diff --git a/plugin.yml b/plugin.yml index 1b29d6e1d..45102f9e4 100644 --- a/plugin.yml +++ b/plugin.yml @@ -246,9 +246,10 @@ commands: brush: description: Switch to the sphere brush tool usage: / [radius] [no-replace?] - reloadwe: - description: Switch to the replacing sphere brush tool - usage: / [radius] + + cs: + description: Execute a CraftScript + usage: / [arg1 [args2 [arg3 [...]]]] reloadwe: description: Reload WorldEdit's configuration diff --git a/src/com/sk89q/worldedit/WorldEditController.java b/src/com/sk89q/worldedit/WorldEditController.java index 96441fce3..1217921f1 100644 --- a/src/com/sk89q/worldedit/WorldEditController.java +++ b/src/com/sk89q/worldedit/WorldEditController.java @@ -27,11 +27,15 @@ import java.util.HashSet; import java.util.logging.Level; import java.util.logging.Logger; import java.io.*; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineManager; +import javax.script.ScriptException; import com.sk89q.util.StringUtil; import com.sk89q.worldedit.bags.BlockBag; import com.sk89q.worldedit.blocks.*; import com.sk89q.worldedit.data.*; import com.sk89q.worldedit.filters.*; +import com.sk89q.worldedit.scripting.ScriptContext; import com.sk89q.worldedit.snapshots.*; import com.sk89q.worldedit.superpickaxe.*; import com.sk89q.worldedit.regions.*; @@ -173,6 +177,8 @@ public class WorldEditController { commands.put("/repl", "[ID] - Switch to the block replacer tool"); commands.put("/brush", "[ID] - Switch to the sphere brush tool"); commands.put("/rbrush", "[ID] - Switch to the replacing sphere brush tool"); + + commands.put("/cs", "[Filename] - Execute a CraftScript"); } /** @@ -1700,6 +1706,17 @@ public class WorldEditController { } } + return true; + + // CraftScript + } else if (split[0].equalsIgnoreCase("/cs")) { + checkArgs(split, 1, -1, split[0]); + + String[] args = new String[split.length - 1]; + System.arraycopy(split, 1, args, 0, split.length - 1); + + runScript(player, split[1], args); + return true; } @@ -2091,4 +2108,86 @@ public class WorldEditController { return true; } + + /** + * Executes a WorldEdit script. + * + * @param player + * @param filename + * @param args + */ + public void runScript(LocalPlayer player, String filename, String[] args) { + File dir = new File("craftscripts"); + File f = new File(dir, filename); + + if (!filename.matches("^[A-Za-z0-9_\\- \\./\\\\'\\$@~!%\\^\\*\\(\\)\\[\\]\\+\\{\\},\\?]+\\.[A-Za-z0-9]+$")) { + player.printError("Invalid filename. Don't forget the extension."); + return; + } + + int index = filename.lastIndexOf("."); + String ext = filename.substring(index + 1, filename.length()); + + if (!ext.equalsIgnoreCase("js")) { + player.printError("Only .js scripts are currently supported"); + return; + } + + try { + String filePath = f.getCanonicalPath(); + String dirPath = dir.getCanonicalPath(); + + if (!filePath.substring(0, dirPath.length()).equals(dirPath)) { + player.printError("Script could not read or it does not exist."); + return; + } + } catch (IOException e) { + player.printError("Script could not read or it does not exist: " + e.getMessage()); + return; + } + + String script; + + try { + FileInputStream file = new FileInputStream(f); + DataInputStream in = new DataInputStream (file); + byte[] data = new byte[in.available()]; + in.readFully(data); + in.close (); + script = new String(data, 0, data.length, "utf-8"); + } catch (FileNotFoundException e) { + player.printError("Script does not exist: " + filename); + return; + } catch (IOException e) { + player.printError("Script read error: " + e.getMessage()); + return; + } + + ScriptEngineManager manager = new ScriptEngineManager(); + ScriptEngine engine = manager.getEngineByExtension(ext); + + if (engine == null) { + player.printError("Failed to load the scripting engine."); + return; + } + + LocalSession session = getSession(player); + ScriptContext context = new ScriptContext(this, server, config, session, player); + + engine.put("argv", args); + engine.put("ctx", context); + engine.put("player", player); + + try { + engine.eval(script); + } catch (ScriptException e) { + e.printStackTrace(); + player.printError("Script encountered an error: " + e.getMessage()); + return; + } finally { + for (EditSession editSession : context._getEditSessions()) { + session.remember(editSession); + } + } + } } diff --git a/src/com/sk89q/worldedit/scripting/ScriptContext.java b/src/com/sk89q/worldedit/scripting/ScriptContext.java new file mode 100644 index 000000000..82ccc070c --- /dev/null +++ b/src/com/sk89q/worldedit/scripting/ScriptContext.java @@ -0,0 +1,90 @@ +// $Id$ +/* + * WorldEdit + * Copyright (C) 2010 sk89q + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . +*/ + +package com.sk89q.worldedit.scripting; + +import java.util.ArrayList; +import java.util.List; +import com.sk89q.worldedit.DisallowedItemException; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.LocalConfiguration; +import com.sk89q.worldedit.LocalPlayer; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.ServerInterface; +import com.sk89q.worldedit.UnknownItemException; +import com.sk89q.worldedit.WorldEditController; +import com.sk89q.worldedit.blocks.BaseBlock; + +public class ScriptContext { + private WorldEditController controller; + private LocalPlayer player; + private LocalConfiguration config; + private LocalSession session; + private ServerInterface server; + private List editSessions = new ArrayList(); + + public ScriptContext(WorldEditController controller, ServerInterface server, + LocalConfiguration config, LocalSession session, LocalPlayer player) { + this.controller = controller; + this.player = player; + this.config = config; + this.server = server; + this.session = session; + } + + public EditSession startEditSession() { + EditSession editSession = + new EditSession(server, player.getWorld(), + session.getBlockChangeLimit(), session.getBlockBag(player)); + editSessions.add(editSession); + return editSession; + } + + public LocalPlayer getPlayer() { + return player; + } + + public LocalSession getSession() { + return session; + } + + public LocalConfiguration getConfiguration() { + return config; + } + + public List _getEditSessions() { + return editSessions; + } + + public void print(String msg) { + player.print(msg); + } + + public void error(String msg) { + player.printError(msg); + } + + public BaseBlock getBlock(String arg) throws UnknownItemException, DisallowedItemException { + return controller.getBlock(player, arg, false); + } + + public BaseBlock getAnyBlock(String arg) throws UnknownItemException, DisallowedItemException { + return controller.getBlock(player, arg, true); + } +}