From 02de4c8200835f156936fb048065a600e3f30907 Mon Sep 17 00:00:00 2001 From: sk89q Date: Sat, 29 Jan 2011 02:05:22 -0800 Subject: [PATCH] Moved commands into their own classes. --- src/com/sk89q/util/commands/Command.java | 31 + .../sk89q/util/commands/CommandContext.java | 80 + src/com/sk89q/worldedit/LocalPlayer.java | 2 +- src/com/sk89q/worldedit/WorldEdit.java | 1612 +---------------- .../sk89q/worldedit/bukkit/BukkitPlayer.java | 2 +- .../worldedit/commands/ChunkCommands.java | 161 ++ .../worldedit/commands/ClipboardCommands.java | 282 +++ .../commands/CommandPermissions.java | 28 + .../worldedit/commands/CommandsManager.java | 166 ++ .../worldedit/commands/GeneralCommands.java | 77 + .../commands/GenerationCommands.java | 190 ++ .../worldedit/commands/HistoryCommands.java | 89 + .../InsufficientArgumentsException.java | 4 +- .../commands/NavigationCommands.java | 168 ++ .../worldedit/commands/RegionCommands.java | 225 +++ .../worldedit/commands/ScriptingCommands.java | 78 + .../worldedit/commands/SelectionCommands.java | 407 +++++ .../worldedit/commands/SnapshotCommands.java | 199 ++ .../commands/SuperPickaxeCommands.java | 280 +++ .../worldedit/commands/UtilityCommands.java | 325 ++++ .../scripting/CraftScriptContext.java | 2 +- 21 files changed, 2875 insertions(+), 1533 deletions(-) create mode 100644 src/com/sk89q/util/commands/Command.java create mode 100644 src/com/sk89q/util/commands/CommandContext.java create mode 100644 src/com/sk89q/worldedit/commands/ChunkCommands.java create mode 100644 src/com/sk89q/worldedit/commands/ClipboardCommands.java create mode 100644 src/com/sk89q/worldedit/commands/CommandPermissions.java create mode 100644 src/com/sk89q/worldedit/commands/CommandsManager.java create mode 100644 src/com/sk89q/worldedit/commands/GeneralCommands.java create mode 100644 src/com/sk89q/worldedit/commands/GenerationCommands.java create mode 100644 src/com/sk89q/worldedit/commands/HistoryCommands.java rename src/com/sk89q/worldedit/{ => commands}/InsufficientArgumentsException.java (91%) create mode 100644 src/com/sk89q/worldedit/commands/NavigationCommands.java create mode 100644 src/com/sk89q/worldedit/commands/RegionCommands.java create mode 100644 src/com/sk89q/worldedit/commands/ScriptingCommands.java create mode 100644 src/com/sk89q/worldedit/commands/SelectionCommands.java create mode 100644 src/com/sk89q/worldedit/commands/SnapshotCommands.java create mode 100644 src/com/sk89q/worldedit/commands/SuperPickaxeCommands.java create mode 100644 src/com/sk89q/worldedit/commands/UtilityCommands.java diff --git a/src/com/sk89q/util/commands/Command.java b/src/com/sk89q/util/commands/Command.java new file mode 100644 index 000000000..175e5cda1 --- /dev/null +++ b/src/com/sk89q/util/commands/Command.java @@ -0,0 +1,31 @@ +// $Id$ +/* + * 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.util.commands; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) +public @interface Command { + String[] aliases(); + String usage(); + String desc(); + int min(); + int max(); +} diff --git a/src/com/sk89q/util/commands/CommandContext.java b/src/com/sk89q/util/commands/CommandContext.java new file mode 100644 index 000000000..758b5b6eb --- /dev/null +++ b/src/com/sk89q/util/commands/CommandContext.java @@ -0,0 +1,80 @@ +// $Id$ +/* + * 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.util.commands; + +public class CommandContext { + protected String[] args; + + public CommandContext(String args) { + this.args = args.split(" "); + } + + public CommandContext(String[] args) { + this.args = args; + } + + public String getCommand() { + return args[0]; + } + + public boolean matches(String command) { + return args[0].equalsIgnoreCase(command); + } + + public String getString(int index) { + return args[index + 1]; + } + + public String getJoinedStrings(int initialIndex) { + initialIndex = initialIndex + 1; + StringBuilder buffer = new StringBuilder(args[initialIndex]); + for (int i = initialIndex + 1; i < args.length; i++) { + buffer.append(" ").append(args[i]); + } + return buffer.toString(); + } + + public int getInteger(int index) throws NumberFormatException { + return Integer.parseInt(args[index + 1]); + } + + public double getDouble(int index) throws NumberFormatException { + return Double.parseDouble(args[index + 1]); + } + + public String[] getSlice(int index) { + String[] slice = new String[args.length - index]; + System.arraycopy(args, index, slice, 0, args.length - index); + return slice; + } + + public String[] getPaddedSlice(int index, int padding) { + String[] slice = new String[args.length - index + padding]; + System.arraycopy(args, index, slice, padding, args.length - index + padding); + return slice; + } + + public int length() { + return args.length; + } + + public int argsLength() { + return args.length - 1; + } +} diff --git a/src/com/sk89q/worldedit/LocalPlayer.java b/src/com/sk89q/worldedit/LocalPlayer.java index 2d3b96ba5..c809954de 100644 --- a/src/com/sk89q/worldedit/LocalPlayer.java +++ b/src/com/sk89q/worldedit/LocalPlayer.java @@ -542,7 +542,7 @@ public abstract class LocalPlayer { * @return */ public boolean canDestroyBedrock() { - return hasPermission("worldeditbedrock"); + return hasPermission("worldedit.bedrock"); } /** diff --git a/src/com/sk89q/worldedit/WorldEdit.java b/src/com/sk89q/worldedit/WorldEdit.java index dc486381d..8e29e4756 100644 --- a/src/com/sk89q/worldedit/WorldEdit.java +++ b/src/com/sk89q/worldedit/WorldEdit.java @@ -30,15 +30,12 @@ import java.util.logging.Logger; import java.io.*; import javax.script.ScriptException; import com.sk89q.util.StringUtil; +import com.sk89q.util.commands.CommandContext; import com.sk89q.worldedit.LocalSession.CompassMode; 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.commands.*; import com.sk89q.worldedit.scripting.*; -import com.sk89q.worldedit.snapshots.*; -import com.sk89q.worldedit.superpickaxe.*; -import com.sk89q.worldedit.regions.*; import com.sk89q.worldedit.patterns.*; /** @@ -50,11 +47,23 @@ import com.sk89q.worldedit.patterns.*; * @author sk89q */ public class WorldEdit { - private static final Logger logger = Logger.getLogger("Minecraft.WorldEdit"); + public static final Logger logger = Logger.getLogger("Minecraft.WorldEdit"); + /** + * Interface to the server. + */ private ServerInterface server; + + /** + * Configuration. This is a subclass. + */ private LocalConfiguration config; + /** + * List of commands. + */ + private CommandsManager commands; + /** * Stores a list of WorldEdit sessions, keyed by players' names. Sessions * persist only for the user's session. On disconnect, the session will be @@ -65,12 +74,6 @@ public class WorldEdit { private HashMap sessions = new HashMap(); - /** - * List of commands. These are checked when the command event is called, so - * the list must know about every command. - */ - private HashMap commands = new HashMap(); - /** * Construct an instance of the plugin * @@ -81,105 +84,20 @@ public class WorldEdit { this.server = server; this.config = config; - populateCommands(); - } - - /** - * Builds the list of commands. - */ - private void populateCommands() { - commands.put("//limit", "[Num] - See documentation"); - commands.put("/toggleplace", "Toggle placing at pos #1"); + commands = new CommandsManager(); - commands.put("//undo", "Undo"); - commands.put("//redo", "Redo"); - commands.put("/clearhistory", "Clear history"); - - commands.put("//pos1", "Set editing position #1"); - commands.put("//pos2", "Set editing position #2"); - commands.put("//hpos1", "Trace editing position #1"); - commands.put("//hpos2", "Trace editing position #2"); - commands.put("//chunk", "Select the chunk that you are in"); - commands.put("//wand", "Gives you the \"edit wand\""); - commands.put("/toggleeditwand", "Toggles edit wand selection"); - commands.put("//expand", "[Num] - Expands the selection"); - commands.put("//contract", "[Num] - Contracts the selection"); - commands.put("//shift", "[Num] - Shift the selection"); - commands.put("//size", "Get size of selected region"); - commands.put("//count", "[BlockIDs] - Count the number of blocks in the region"); - commands.put("//distr", "Get the top block distribution"); - - commands.put("//set", "[ID] - Set all blocks inside region"); - commands.put("//replace", " [ToID] - Replace all existing blocks inside region"); - commands.put("//overlay", "[ID] - Overlay the area one layer"); - commands.put("//walls", "[ID] - Build walls"); - commands.put("//outline", "[ID] - Outline the region with blocks"); - commands.put("//move", " - Move the selection"); - commands.put("//stack", " - Stacks the selection"); - commands.put("//smooth", " - Smooth an area's heightmap"); - - commands.put("//copy", "Copies the currently selected region"); - commands.put("//cut", "Cuts the currently selected region"); - commands.put("//paste", " - Pastes the clipboard"); - commands.put("//rotate", "[Angle] - Rotate the clipboard"); - commands.put("//flip", " - Flip the clipboard"); - commands.put("//load", "[Filename] - Load .schematic into clipboard"); - commands.put("//save", "[Filename] - Save clipboard to .schematic"); - commands.put("/clearclipboard", "Clear clipboard"); - - commands.put("//hcyl", "[ID] [Radius] - Create a vertical hollow cylinder"); - commands.put("//cyl", "[ID] [Radius] - Create a vertical cylinder"); - commands.put("//sphere", "[ID] [Radius] - Create a sphere"); - commands.put("//hsphere", "[ID] [Radius] - Create a hollow sphere"); - commands.put("/forestgen", " - Make Notch tree forest"); - commands.put("/pinegen", " - Make an ugly pine tree forest"); - commands.put("/pumpkins", " - Make a pumpkin forest"); - - commands.put("//fill", "[ID] [Radius] - Fill a hole"); - commands.put("//fillr", "[ID] [Radius] - Fill a hole fully recursively"); - commands.put("/fixwater", "[Radius] - Level nearby pools of water"); - commands.put("/fixlava", "[Radius] - Level nearby pools of lava"); - commands.put("//drain", "[Radius] - Drain nearby water/lava pools"); - commands.put("/removeabove", " - Remove blocks above head"); - commands.put("/removebelow", " - Remove blocks below position"); - commands.put("/removenear", " - Remove blocks near you"); - commands.put("/replacenear", " [ToID] - Replace all existing blocks nearby"); - commands.put("/snow", " - Simulate snow cover"); - commands.put("/thaw", " - Unthaw/remove snow"); - commands.put("/butcher", " - Kill nearby mobs"); - commands.put("/ex", "[Size] - Extinguish fires"); - - commands.put("/chunkinfo", "Get the filename of the chunk that you are in"); - commands.put("/listchunks", "Print a list of used chunks"); - commands.put("/delchunks", "Generate a shell script to delete chunks"); - - commands.put("/unstuck", "Go up to the first free spot"); - commands.put("/ascend", "Go up one level"); - commands.put("/descend", "Go down one level"); - commands.put("/jumpto", "Jump to the block that you are looking at"); - commands.put("/thru", "Go through the wall that you are looking at"); - commands.put("/ceil", " - Get to the ceiling"); - commands.put("/up", " - Go up some distance"); - - commands.put("/listsnapshots", " - List the 5 newest snapshots"); - commands.put("//use", "[SnapshotID] - Use a particular snapshot"); - commands.put("//restore", " - Restore a particular snapshot"); - - commands.put("//", "Toggles super pick axe."); - commands.put("/single", "Switch to single block super pickaxe mode"); - commands.put("/area", "[Range] - Switch to area super pickaxe mode"); - commands.put("/recur", "[Range] - Switch to recursive super pickaxe mode"); - commands.put("/none", "Switch to no tool"); - commands.put("/info", "Switch to the info tool"); - commands.put("/tree", "Switch to the tree tool"); - commands.put("/pinetree", "Switch to the pine tree tool"); - commands.put("/bigtree", "Switch to the big tree tool"); - 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"); - commands.put("/.s", " - Re-execute last CraftScript"); + commands.register(ChunkCommands.class); + commands.register(ClipboardCommands.class); + commands.register(GeneralCommands.class); + commands.register(GenerationCommands.class); + commands.register(HistoryCommands.class); + commands.register(NavigationCommands.class); + commands.register(RegionCommands.class); + commands.register(ScriptingCommands.class); + commands.register(SelectionCommands.class); + commands.register(SnapshotCommands.class); + commands.register(SuperPickaxeCommands.class); + commands.register(UtilityCommands.class); } /** @@ -198,7 +116,7 @@ public class WorldEdit { // Set the limit on the number of blocks that an operation can // change at once, or don't if the player has an override or there // is no limit. There is also a default limit - if (!player.hasPermission("worldeditnomax") + if (!player.hasPermission("worldedit.limit.unrestricted") && config.maxChangeLimit > -1) { // If the default limit is infinite but there is a maximum @@ -220,7 +138,7 @@ public class WorldEdit { // doesn't have an override session.setUseInventory(config.useInventory && (!config.useInventoryOverride - || !player.hasPermission("worldeditunlimited"))); + || !player.hasPermission("worldedit.inventory.unrestricted"))); // Remember the session sessions.put(player.getName(), session); @@ -298,7 +216,7 @@ public class WorldEdit { } // Check if the item is allowed - if (allAllowed || player.hasPermission("worldeditanyblock") + if (allAllowed || player.hasPermission("worldedit.anyblock") || !config.disallowedBlocks.contains(blockType.getID())) { // Allow special sign text syntax @@ -413,1361 +331,18 @@ public class WorldEdit { return blocks; } - /** - * Checks to make sure that there are enough but not too many arguments. - * - * @param args - * @param min - * @param max -1 for no maximum - * @param cmd command name - * @throws InsufficientArgumentsException - */ - private void checkArgs(String[] args, int min, int max, String cmd) - throws InsufficientArgumentsException { - if (args.length <= min || (max != -1 && args.length - 1 > max)) { - if (commands.containsKey(cmd)) { - throw new InsufficientArgumentsException(cmd + " usage: " + - commands.get(cmd)); - } else { - throw new InsufficientArgumentsException("Invalid number of arguments"); - } - } - } - /** * Checks to see if the specified radius is within bounds. * * @param radius * @throws MaxRadiusException */ - private void checkMaxRadius(int radius) throws MaxRadiusException { + public void checkMaxRadius(int radius) throws MaxRadiusException { if (config.maxRadius > 0 && radius > config.maxRadius) { throw new MaxRadiusException(); } } - /** - * The main meat of command processing. - * - * @param player - * @param editPlayer - * @param session - * @param editSession - * @param split - * @return - * @throws UnknownItemException - * @throws IncompleteRegionException - * @throws InsufficientArgumentsException - * @throws DisallowedItemException - */ - private boolean performCommand(LocalPlayer player, - LocalSession session, EditSession editSession, String[] split) - throws WorldEditException - { - if (config.logCommands) { - logger.log(Level.INFO, "WorldEdit: " + player.getName() + ": " - + StringUtil.joinString(split, " ")); - } - - LocalWorld world = player.getPosition().getWorld(); - - // Jump to the first free position - if (split[0].equalsIgnoreCase("/unstuck")) { - checkArgs(split, 0, 0, split[0]); - player.print("There you go!"); - player.findFreePosition(); - return true; - - // Ascend a level - } else if(split[0].equalsIgnoreCase("/ascend")) { - checkArgs(split, 0, 0, split[0]); - if (player.ascendLevel()) { - player.print("Ascended a level."); - } else { - player.printError("No free spot above you found."); - } - return true; - - // Descend a level - } else if(split[0].equalsIgnoreCase("/descend")) { - checkArgs(split, 0, 0, split[0]); - if (player.descendLevel()) { - player.print("Descended a level."); - } else { - player.printError("No free spot below you found."); - } - return true; - - // Jump to the block in sight - } else if (split[0].equalsIgnoreCase("/jumpto")) { - checkArgs(split, 0, 0, split[0]); - WorldVector pos = player.getSolidBlockTrace(300); - if (pos != null) { - player.findFreePosition(pos); - player.print("Poof!"); - } else { - player.printError("No block in sight!"); - } - return true; - - // Go through a wall - } else if (split[0].equalsIgnoreCase("/thru")) { - checkArgs(split, 0, 0, split[0]); - if (player.passThroughForwardWall(6)) { - player.print("Whoosh!"); - } else { - player.printError("No free spot ahead of you found."); - } - return true; - - // Go to the ceiling - } else if (split[0].equalsIgnoreCase("/ceil")) { - checkArgs(split, 0, 1, split[0]); - int clearence = split.length > 1 ? - Math.max(0, Integer.parseInt(split[1])) : 0; - - if (player.ascendToCeiling(clearence)) { - player.print("Whoosh!"); - } else { - player.printError("No free spot above you found."); - } - return true; - - // Go up - } else if (split[0].equalsIgnoreCase("/up")) { - checkArgs(split, 1, 1, split[0]); - int distance = Integer.parseInt(split[1]); - - if (player.ascendUpwards(distance)) { - player.print("Whoosh!"); - } else { - player.printError("You would hit something above you."); - } - return true; - - // Set edit position #1 - } else if (split[0].equalsIgnoreCase("//pos1")) { - checkArgs(split, 0, 0, split[0]); - session.setPos1(player.getBlockIn()); - if (session.isRegionDefined()) { - player.print("First position set to " + player.getBlockIn() - + " (" + session.getRegion().getSize() + ")."); - } else { - player.print("First position set to " + player.getBlockIn() + "."); - } - return true; - - // Set edit position #2 - } else if (split[0].equalsIgnoreCase("//pos2")) { - checkArgs(split, 0, 0, split[0]); - session.setPos2(player.getBlockIn()); - if (session.isRegionDefined()) { - player.print("Second position set to " + player.getBlockIn() - + " (" + session.getRegion().getSize() + ")."); - } else { - player.print("Second position set to " + player.getBlockIn() + "."); - } - return true; - - // Trace edit position #1 - } else if (split[0].equalsIgnoreCase("//hpos1")) { - checkArgs(split, 0, 0, split[0]); - Vector pos = player.getBlockTrace(300); - if (pos != null) { - session.setPos1(pos); - if (session.isRegionDefined()) { - player.print("First position set to " + pos - + " (" + session.getRegion().getSize() + ")."); - } else { - player.print("First position set to " + pos.toString() + " ."); - } - } else { - player.printError("No block in sight!"); - } - return true; - - // Trace edit position #2 - } else if (split[0].equalsIgnoreCase("//hpos2")) { - checkArgs(split, 0, 0, split[0]); - Vector pos = player.getBlockTrace(300); - if (pos != null) { - session.setPos2(pos); - if (session.isRegionDefined()) { - player.print("Second position set to " + pos - + " (" + session.getRegion().getSize() + ")."); - } else { - player.print("Second position set to " + pos.toString() + " ."); - } - } else { - player.printError("No block in sight!"); - } - return true; - - // Select the chunk - } else if(split[0].equalsIgnoreCase("//chunk")) { - checkArgs(split, 0, 0, split[0]); - - Vector2D min2D = ChunkStore.toChunk(player.getBlockIn()); - Vector min = new Vector(min2D.getBlockX() * 16, 0, min2D.getBlockZ() * 16); - Vector max = min.add(15, 127, 15); - - session.setPos1(min); - session.setPos2(max); - - player.print("Chunk selected: " - + min2D.getBlockX() + ", " + min2D.getBlockZ()); - - return true; - - // Edit wand - } else if (split[0].equalsIgnoreCase("//wand")) { - checkArgs(split, 0, 0, split[0]); - player.giveItem(config.wandItem, 1); - player.print("Left click: select pos #1; Right click: select pos #2"); - return true; - - // Toggle placing at pos #1 - } else if (split[0].equalsIgnoreCase("/toggleplace")) { - checkArgs(split, 0, 0, split[0]); - if (session.togglePlacementPosition()) { - player.print("Now placing at pos #1."); - } else { - player.print("Now placing at the block you stand in."); - } - return true; - - // Toggle edit wand - } else if (split[0].equalsIgnoreCase("/toggleeditwand")) { - checkArgs(split, 0, 0, split[0]); - session.setToolControl(!session.isToolControlEnabled()); - if (session.isToolControlEnabled()) { - player.print("Edit wand enabled."); - } else { - player.print("Edit wand disabled."); - } - return true; - - // Toggle super pick axe - } else if (split[0].equalsIgnoreCase("//")) { - checkArgs(split, 0, 0, split[0]); - if (session.toggleSuperPickAxe()) { - player.print("Super pick axe enabled."); - } else { - player.print("Super pick axe disabled."); - } - return true; - - // Set max number of blocks to change at a time - } else if (split[0].equalsIgnoreCase("//limit")) { - checkArgs(split, 1, 1, split[0]); - int limit = Math.max(-1, Integer.parseInt(split[1])); - if (!player.hasPermission("worldeditnomax") - && config.maxChangeLimit > -1) { - if (limit > config.maxChangeLimit) { - player.printError("Your maximum allowable limit is " - + config.maxChangeLimit + "."); - return true; - } - } - - session.setBlockChangeLimit(limit); - player.print("Block change limit set to " + limit + "."); - - return true; - - // Single super pickaxe mode - } else if (split[0].equalsIgnoreCase("/single")) { - if (!canUseCommand(player, "/")) { - player.printError("You don't have permission for super pickaxe usage."); - return true; - } - - checkArgs(split, 0, 0, split[0]); - session.setLeftClickMode(new SinglePickaxe()); - session.enableSuperPickAxe(); - player.print("Mode changed. Left click with a pickaxe. // to disable."); - return true; - - // Area/recursive super pickaxe mode - } else if (split[0].equalsIgnoreCase("/area") - || split[0].equalsIgnoreCase("/recur")) { - - if (!canUseCommand(player, "/")) { - player.printError("You don't have permission for super pickaxe usage."); - return true; - } - - checkArgs(split, 1, 1, split[0]); - - boolean recur = split[0].equalsIgnoreCase("/recur"); - int range = Integer.parseInt(split[1]); - - if (range > config.maxSuperPickaxeSize) { - player.printError("Maximum range: " + config.maxSuperPickaxeSize); - return true; - } - - session.setLeftClickMode( - recur ? new RecursivePickaxe(range) : new AreaPickaxe(range)); - session.enableSuperPickAxe(); - player.print("Mode changed. Left click with a pickaxe. // to disable."); - return true; - - // Tree tool - } else if (split[0].equalsIgnoreCase("/tree")) { - checkArgs(split, 0, 0, split[0]); - session.setArmSwingMode(null); - session.setRightClickMode(new TreePlanter()); - player.print("Tree tool equipped. Right click with a pickaxe."); - return true; - - // Big tree tool - } else if (split[0].equalsIgnoreCase("/bigtree")) { - checkArgs(split, 0, 0, split[0]); - session.setArmSwingMode(null); - session.setRightClickMode(new BigTreePlanter()); - player.print("Big tree tool equipped. Right click with a pickaxe."); - return true; - - // Pine tree tool - } else if (split[0].equalsIgnoreCase("/pinetree")) { - checkArgs(split, 0, 0, split[0]); - session.setArmSwingMode(null); - session.setRightClickMode(new PineTreePlanter()); - player.print("Pine tree tree tool equipped. Right click with a pickaxe."); - return true; - - // Info tool - } else if (split[0].equalsIgnoreCase("/info")) { - checkArgs(split, 0, 0, split[0]); - session.setArmSwingMode(null); - session.setRightClickMode(new QueryTool()); - player.print("Info tool equipped. Right click with a pickaxe."); - return true; - - // Replace block tool - } else if (split[0].equalsIgnoreCase("/repl")) { - checkArgs(split, 1, 1, split[0]); - BaseBlock targetBlock = getBlock(player, split[1]); - session.setArmSwingMode(null); - session.setRightClickMode(new BlockReplacer(targetBlock)); - player.print("Block replacer tool equipped. Right click with a pickaxe."); - return true; - - // Sphere brush tool - } else if (split[0].equalsIgnoreCase("/brush")) { - checkArgs(split, 1, 3, split[0]); - int radius = split.length > 2 ? Integer.parseInt(split[2]) : 2; - boolean nonReplacing = split.length > 3 - ? (split[3].equalsIgnoreCase("true") - || split[3].equalsIgnoreCase("yes")) : false; - if (radius > config.maxBrushRadius) { - player.printError("Maximum allowed brush radius: " - + config.maxBrushRadius); - return true; - } - BaseBlock targetBlock = getBlock(player, split[1]); - session.setRightClickMode(null); - session.setArmSwingMode(new SphereBrush(targetBlock, radius, nonReplacing)); - if (nonReplacing) { - player.print("Non-replacing sphere brush tool equipped."); - } else { - player.print("Sphere brush tool equipped. Swing with a pickaxe."); - } - return true; - - // Sphere brush tool - } else if (split[0].equalsIgnoreCase("/rbrush")) { - checkArgs(split, 1, 3, split[0]); - int radius = split.length > 2 ? Integer.parseInt(split[2]) : 2; - if (radius > config.maxBrushRadius) { - player.printError("Maximum allowed brush radius: " - + config.maxBrushRadius); - return true; - } - BaseBlock targetBlock = getBlock(player, split[1]); - session.setRightClickMode(null); - session.setArmSwingMode(new ReplacingSphereBrush(targetBlock, radius)); - player.print("Replacing sphere brush tool equipped. Swing with a pickaxe."); - return true; - - // No tool - } else if (split[0].equalsIgnoreCase("/none")) { - checkArgs(split, 0, 0, split[0]); - session.setArmSwingMode(null); - session.setRightClickMode(null); - player.print("Now no longer equipping a tool."); - return true; - - // Undo - } else if (split[0].equalsIgnoreCase("//undo")) { - checkArgs(split, 0, 0, split[0]); - EditSession undone = session.undo(session.getBlockBag(player)); - if (undone != null) { - player.print("Undo successful."); - flushBlockBag(player, undone); - } else { - player.printError("Nothing to undo."); - } - return true; - - // Redo - } else if (split[0].equalsIgnoreCase("//redo")) { - checkArgs(split, 0, 0, split[0]); - EditSession redone = session.redo(session.getBlockBag(player)); - if (redone != null) { - player.print("Redo successful."); - flushBlockBag(player, redone); - } else { - player.printError("Nothing to redo."); - } - return true; - - // Clear undo history - } else if (split[0].equalsIgnoreCase("/clearhistory")) { - checkArgs(split, 0, 0, split[0]); - session.clearHistory(); - player.print("History cleared."); - return true; - - // Clear clipboard - } else if (split[0].equalsIgnoreCase("/clearclipboard")) { - checkArgs(split, 0, 0, split[0]); - session.setClipboard(null); - player.print("Clipboard cleared."); - return true; - - // Paste - } else if (split[0].equalsIgnoreCase("//paste")) { - checkArgs(split, 0, 1, split[0]); - boolean atOrigin = split.length > 1 - ? (split[1].equalsIgnoreCase("true") - || split[1].equalsIgnoreCase("yes")) - : false; - if (atOrigin) { - Vector pos = session.getClipboard().getOrigin(); - session.getClipboard().place(editSession, pos, false); - player.findFreePosition(); - player.print("Pasted to copy origin. Undo with //undo"); - } else { - Vector pos = session.getPlacementPosition(player); - session.getClipboard().paste(editSession, pos, false); - player.findFreePosition(); - player.print("Pasted relative to you. Undo with //undo"); - } - - return true; - - // Draw a hollow cylinder - } else if (split[0].equalsIgnoreCase("//hcyl") - || split[0].equalsIgnoreCase("//cyl")) { - checkArgs(split, 2, 3, split[0]); - BaseBlock block = getBlock(player, split[1]); - int radius = Math.max(1, Integer.parseInt(split[2])); - int height = split.length > 3 ? Integer.parseInt(split[3]) : 1; - boolean filled = split[0].equalsIgnoreCase("//cyl"); - - Vector pos = session.getPlacementPosition(player); - int affected; - if (filled) { - affected = editSession.makeCylinder(pos, block, radius, height); - } else { - affected = editSession.makeHollowCylinder(pos, block, radius, height); - } - player.print(affected + " block(s) have been created."); - - return true; - - // Draw a sphere - } else if (split[0].equalsIgnoreCase("//sphere") - || split[0].equalsIgnoreCase("//hsphere")) { - checkArgs(split, 2, 3, split[0]); - BaseBlock block = getBlock(player, split[1]); - int radius = Math.max(1, Integer.parseInt(split[2])); - boolean raised = split.length > 3 - ? (split[3].equalsIgnoreCase("true") - || split[3].equalsIgnoreCase("yes")) - : false; - boolean filled = split[0].equalsIgnoreCase("//sphere"); - - Vector pos = session.getPlacementPosition(player); - if (raised) { - pos = pos.add(0, radius, 0); - } - - int affected = editSession.makeSphere(pos, block, radius, filled); - player.findFreePosition(); - player.print(affected + " block(s) have been created."); - - return true; - - // Fill a hole - } else if (split[0].equalsIgnoreCase("//fill") - || split[0].equalsIgnoreCase("//fillr")) { - boolean recursive = split[0].equalsIgnoreCase("//fillr"); - checkArgs(split, 2, recursive ? 2 : 3, split[0]); - Pattern pattern = getBlockPattern(player, split[1]); - int radius = Math.max(1, Integer.parseInt(split[2])); - checkMaxRadius(radius); - int depth = split.length > 3 ? Math.max(1, Integer.parseInt(split[3])) : 1; - - Vector pos = session.getPlacementPosition(player); - int affected = 0; - if (pattern instanceof SingleBlockPattern) { - affected = editSession.fillXZ(pos, - ((SingleBlockPattern)pattern).getBlock(), - radius, depth, recursive); - } else { - affected = editSession.fillXZ(pos, pattern, radius, depth, recursive); - } - player.print(affected + " block(s) have been created."); - - return true; - - // Remove blocks above current position - } else if (split[0].equalsIgnoreCase("/removeabove")) { - checkArgs(split, 0, 2, split[0]); - int size = split.length > 1 ? Math.max(1, Integer.parseInt(split[1])) : 1; - checkMaxRadius(size); - int height = split.length > 2 ? Math.min(128, Integer.parseInt(split[2]) + 2) : 128; - - int affected = editSession.removeAbove( - session.getPlacementPosition(player), size, height); - player.print(affected + " block(s) have been removed."); - - return true; - - // Remove blocks below current position - } else if (split[0].equalsIgnoreCase("/removebelow")) { - checkArgs(split, 0, 2, split[0]); - int size = split.length > 1 ? Math.max(1, Integer.parseInt(split[1])) : 1; - checkMaxRadius(size); - int height = split.length > 2 ? Math.max(1, Integer.parseInt(split[2])) : 128; - - int affected = editSession.removeBelow( - session.getPlacementPosition(player), size, height); - player.print(affected + " block(s) have been removed."); - - return true; - - // Remove blocks near - } else if (split[0].equalsIgnoreCase("/removenear")) { - checkArgs(split, 2, 2, split[0]); - BaseBlock block = getBlock(player, split[1], true); - int size = Math.max(1, Integer.parseInt(split[2])); - checkMaxRadius(size); - - int affected = editSession.removeNear( - session.getPlacementPosition(player), block.getType(), size); - player.print(affected + " block(s) have been removed."); - - return true; - - // Extinguish - } else if (split[0].equalsIgnoreCase("/ex")) { - checkArgs(split, 0, 1, split[0]); - int defaultRadius = config.maxRadius != -1 ? Math.min(40, config.maxRadius) : 40; - int size = split.length > 1 ? Math.max(1, Integer.parseInt(split[1])) - : defaultRadius; - checkMaxRadius(size); - - int affected = editSession.removeNear( - session.getPlacementPosition(player), 51, size); - player.print(affected + " block(s) have been removed."); - - return true; - - // Load .schematic to clipboard - } else if (split[0].equalsIgnoreCase("//load")) { - checkArgs(split, 1, 1, split[0]); - String filename = split[1].replace("\0", "") + ".schematic"; - File dir = new File(config.getWorkingDirectory(), "schematics"); - File f = new File(new File(config.getWorkingDirectory(), "schematics"), filename); - - if (!filename.matches("^[A-Za-z0-9_\\- \\./\\\\'\\$@~!%\\^\\*\\(\\)\\[\\]\\+\\{\\},\\?]+$")) { - player.printError("Valid characters: A-Z, a-z, 0-9, spaces, " - + "./\'$@~!%^*()[]+{},?"); - return true; - } - - try { - String filePath = f.getCanonicalPath(); - String dirPath = dir.getCanonicalPath(); - - if (!filePath.substring(0, dirPath.length()).equals(dirPath)) { - player.printError("Schematic could not read or it does not exist."); - } else { - session.setClipboard(CuboidClipboard.loadSchematic(f)); - logger.log(Level.INFO, player.getName() + " loaded " + filePath); - player.print(filename + " loaded. Paste it with //paste"); - } - } catch (DataException e) { - player.printError("Load error: " + e.getMessage()); - } catch (IOException e) { - player.printError("Schematic could not read or it does not exist: " + e.getMessage()); - } - - return true; - - // Save clipboard to .schematic - } else if (split[0].equalsIgnoreCase("//save")) { - checkArgs(split, 1, 1, split[0]); - String filename = split[1].replace("\0", "") + ".schematic"; - - if (!filename.matches("^[A-Za-z0-9_\\- \\./\\\\'\\$@~!%\\^\\*\\(\\)\\[\\]\\+\\{\\},\\?]+$")) { - player.printError("Valid characters: A-Z, a-z, 0-9, spaces, " - + "./\'$@~!%^*()[]+{},?"); - return true; - } - - File dir = new File(config.getWorkingDirectory(), "schematics"); - File f = new File(new File(config.getWorkingDirectory(), "schematics"), filename); - - if (!dir.exists()) { - if (!dir.mkdir()) { - player.printError("A schematics/ folder could not be created."); - return true; - } - } - - try { - String filePath = f.getCanonicalPath(); - String dirPath = dir.getCanonicalPath(); - - if (!filePath.substring(0, dirPath.length()).equals(dirPath)) { - player.printError("Invalid path for Schematic."); - } else { - // Create parent directories - File parent = f.getParentFile(); - if (parent != null && !parent.exists()) { - parent.mkdirs(); - } - - session.getClipboard().saveSchematic(f); - logger.log(Level.INFO, player.getName() + " saved " + filePath); - player.print(filename + " saved."); - } - } catch (DataException se) { - player.printError("Save error: " + se.getMessage()); - } catch (IOException e) { - player.printError("Schematic could not written: " + e.getMessage()); - } - - return true; - - // Get size - } else if (split[0].equalsIgnoreCase("//size")) { - Region region = session.getRegion(); - Vector size = region.getMaximumPoint() - .subtract(region.getMinimumPoint()) - .add(1, 1, 1); - player.print("First position: " + session.getPos1()); - player.print("Second position: " + session.getPos2()); - player.print("Size: " + size); - player.print("# of blocks: " + region.getSize()); - return true; - - // Get count - } else if (split[0].equalsIgnoreCase("//count")) { - checkArgs(split, 1, 1, split[0]); - Set searchIDs = getBlockIDs(player, split[1], true); - player.print("Counted: " + - editSession.countBlocks(session.getRegion(), searchIDs)); - return true; - - // Get block distribution - } else if (split[0].equalsIgnoreCase("//distr")) { - checkArgs(split, 0, 0, split[0]); - List> distribution = - editSession.getBlockDistribution(session.getRegion()); - if (distribution.size() > 0) { // *Should* always be true - int size = session.getRegion().getSize(); - - player.print("# total blocks: " + size); - - for (Countable c : distribution) { - player.print(String.format("%-7s (%.3f%%) %s #%d", - String.valueOf(c.getAmount()), - c.getAmount() / (double)size * 100, - BlockType.fromID(c.getID()).getName(), c.getID())); - } - } else { - player.printError("No blocks counted."); - } - return true; - - // Replace all blocks in the region - } else if(split[0].equalsIgnoreCase("//set")) { - checkArgs(split, 1, 1, split[0]); - Pattern pattern = getBlockPattern(player, split[1]); - int affected; - if (pattern instanceof SingleBlockPattern) { - affected = editSession.setBlocks(session.getRegion(), - ((SingleBlockPattern)pattern).getBlock()); - } else { - affected = editSession.setBlocks(session.getRegion(), pattern); - } - player.print(affected + " block(s) have been changed."); - - return true; - - // Smooth the heightmap of a region - } else if (split[0].equalsIgnoreCase("//smooth")) { - checkArgs(split, 0, 1, split[0]); - - int iterations = 1; - if (split.length >= 2) - iterations = Integer.parseInt(split[1]); - - HeightMap heightMap = new HeightMap(editSession, session.getRegion()); - HeightMapFilter filter = new HeightMapFilter(new GaussianKernel(5, 1.0)); - int affected = heightMap.applyFilter(filter, iterations); - player.print("Terrain's height map smoothed. " + affected + " block(s) changed."); - - return true; - - // Set the outline of a region - } else if(split[0].equalsIgnoreCase("//outline")) { - checkArgs(split, 1, 1, split[0]); - BaseBlock block = getBlock(player, split[1]); - int affected = editSession.makeCuboidFaces(session.getRegion(), block); - player.print(affected + " block(s) have been changed."); - - return true; - - // Set the walls of a region - } else if(split[0].equalsIgnoreCase("//walls")) { - checkArgs(split, 1, 1, split[0]); - BaseBlock block = getBlock(player, split[1]); - int affected = editSession.makeCuboidWalls(session.getRegion(), block); - player.print(affected + " block(s) have been changed."); - - return true; - - // Drain pools - } else if(split[0].equalsIgnoreCase("//drain")) { - checkArgs(split, 1, 1, split[0]); - int radius = Math.max(0, Integer.parseInt(split[1])); - checkMaxRadius(radius); - int affected = editSession.drainArea( - session.getPlacementPosition(player), radius); - player.print(affected + " block(s) have been changed."); - - return true; - - // Fix water - } else if(split[0].equalsIgnoreCase("/fixwater")) { - checkArgs(split, 1, 1, split[0]); - int radius = Math.max(0, Integer.parseInt(split[1])); - checkMaxRadius(radius); - int affected = editSession.fixLiquid( - session.getPlacementPosition(player), radius, 8, 9); - player.print(affected + " block(s) have been changed."); - - return true; - - // Fix lava - } else if(split[0].equalsIgnoreCase("/fixlava")) { - checkArgs(split, 1, 1, split[0]); - int radius = Math.max(0, Integer.parseInt(split[1])); - checkMaxRadius(radius); - int affected = editSession.fixLiquid( - session.getPlacementPosition(player), radius, 10, 11); - player.print(affected + " block(s) have been changed."); - - return true; - - // Replace all blocks in the region - } else if(split[0].equalsIgnoreCase("//replace")) { - checkArgs(split, 1, 2, split[0]); - - Set from; - Pattern to; - if (split.length == 2) { - from = null; - to = getBlockPattern(player, split[1]); - } else { - from = getBlockIDs(player, split[1], true); - to = getBlockPattern(player, split[2]); - } - - int affected = 0; - if (to instanceof SingleBlockPattern) { - affected = editSession.replaceBlocks(session.getRegion(), from, - ((SingleBlockPattern)to).getBlock()); - } else { - affected = editSession.replaceBlocks(session.getRegion(), from, to); - } - player.print(affected + " block(s) have been replaced."); - - return true; - - // Replace all blocks in the region - } else if(split[0].equalsIgnoreCase("/replacenear")) { - checkArgs(split, 2, 3, split[0]); - int size = Math.max(1, Integer.parseInt(split[1])); - Set from; - BaseBlock to; - if (split.length == 3) { - from = null; - to = getBlock(player, split[2]); - } else { - from = getBlockIDs(player, split[2], true); - to = getBlock(player, split[3]); - } - - Vector min = player.getBlockIn().subtract(size, size, size); - Vector max = player.getBlockIn().add(size, size, size); - Region region = new CuboidRegion(min, max); - - int affected = editSession.replaceBlocks(region, from, to); - player.print(affected + " block(s) have been replaced."); - - return true; - - // Lay blocks over an area - } else if (split[0].equalsIgnoreCase("//overlay")) { - checkArgs(split, 1, 1, split[0]); - BaseBlock block = getBlock(player, split[1]); - - Region region = session.getRegion(); - int affected = editSession.overlayCuboidBlocks(region, block); - player.print(affected + " block(s) have been overlayed."); - - return true; - - // Copy - } else if (split[0].equalsIgnoreCase("//copy") - || split[0].equalsIgnoreCase("//cut")) { - boolean cut = split[0].equalsIgnoreCase("//cut"); - BaseBlock block = new BaseBlock(0); - - if (cut) { - checkArgs(split, 0, 1, split[0]); - if (split.length > 1) { - getBlock(player, split[1]); - } - } else { - checkArgs(split, 0, 0, split[0]); - } - - Region region = session.getRegion(); - Vector min = region.getMinimumPoint(); - Vector max = region.getMaximumPoint(); - Vector pos = player.getBlockIn(); - - CuboidClipboard clipboard = new CuboidClipboard( - max.subtract(min).add(new Vector(1, 1, 1)), - min, min.subtract(pos)); - clipboard.copy(editSession); - session.setClipboard(clipboard); - - if (cut) { - editSession.setBlocks(session.getRegion(), block); - player.print("Block(s) cut."); - } else { - player.print("Block(s) copied."); - } - - return true; - - // Make tree forest - } else if (split[0].equalsIgnoreCase("/forestgen")) { - checkArgs(split, 0, 2, split[0]); - int size = split.length > 1 ? Math.max(1, Integer.parseInt(split[1])) : 10; - double density = split.length > 2 ? Double.parseDouble(split[2]) / 100 : 0.05; - - int affected = editSession.makeForest(player.getPosition(), - size, density, false); - player.print(affected + " trees created."); - - return true; - - // Make pine tree forest - } else if (split[0].equalsIgnoreCase("/pinegen")) { - checkArgs(split, 0, 1, split[0]); - int size = split.length > 1 ? Math.max(1, Integer.parseInt(split[1])) : 10; - double density = split.length > 2 ? Double.parseDouble(split[2]) / 100 : 0.05; - - int affected = editSession.makeForest(player.getPosition(), - size, density, true); - player.print(affected + " pine trees created."); - - return true; - - // Let it snow~ - } else if (split[0].equalsIgnoreCase("/snow")) { - checkArgs(split, 0, 1, split[0]); - int size = split.length > 1 ? Math.max(1, Integer.parseInt(split[1])) : 10; - - int affected = editSession.simulateSnow(player.getBlockIn(), size); - player.print(affected + " surfaces covered. Let it snow~"); - - return true; - - // Thaw - } else if (split[0].equalsIgnoreCase("/thaw")) { - checkArgs(split, 0, 1, split[0]); - int size = split.length > 1 ? Math.max(1, Integer.parseInt(split[1])) : 10; - - int affected = editSession.thaw(player.getBlockIn(), size); - player.print(affected + " surfaces thawed."); - - return true; - - // Make pumpkin patches - } else if (split[0].equalsIgnoreCase("/pumpkins")) { - checkArgs(split, 0, 1, split[0]); - int size = split.length > 1 ? Math.max(1, Integer.parseInt(split[1])) : 10; - - int affected = editSession.makePumpkinPatches(player.getPosition(), size); - player.print(affected + " pumpkin patches created."); - - return true; - - // Move - } else if (split[0].equalsIgnoreCase("//move")) { - checkArgs(split, 0, 3, split[0]); - int count = split.length > 1 ? Math.max(1, Integer.parseInt(split[1])) : 1; - Vector dir = getDirection(player, - split.length > 2 ? split[2].toLowerCase() : "me"); - BaseBlock replace; - - // Replacement block argument - if (split.length > 3) { - replace = getBlock(player, split[3]); - } else { - replace = new BaseBlock(0); - } - - int affected = editSession.moveCuboidRegion(session.getRegion(), - dir, count, true, replace); - player.print(affected + " blocks moved."); - - return true; - - // Stack - } else if (split[0].equalsIgnoreCase("//stack")) { - checkArgs(split, 0, 2, split[0]); - int count = split.length > 1 ? Math.max(1, Integer.parseInt(split[1])) : 1; - Vector dir = getDirection(player, - split.length > 2 ? split[2].toLowerCase() : "me"); - - int affected = editSession.stackCuboidRegion(session.getRegion(), - dir, count, true); - player.print(affected + " blocks changed. Undo with //undo"); - - return true; - - // Expand - } else if (split[0].equalsIgnoreCase("//expand")) { - checkArgs(split, 1, 3, split[0]); - Vector dir; - - if (split[1].equals("vert") || split[1].equals("vertical")) { - Region region = session.getRegion(); - int oldSize = region.getSize(); - region.expand(new Vector(0, 128, 0)); - region.expand(new Vector(0, -128, 0)); - session.learnRegionChanges(); - int newSize = region.getSize(); - player.print("Region expanded " + (newSize - oldSize) + " blocks [top-to-bottom]."); - return true; - } - - int change = Integer.parseInt(split[1]); - int reverseChange = 0; - - if (split.length == 3) { - try { - reverseChange = Integer.parseInt(split[2]) * -1; - dir = getDirection(player, "me"); - } catch (NumberFormatException e) { - dir = getDirection(player, split[2].toLowerCase()); - } - } else if (split.length == 4) { - reverseChange = Integer.parseInt(split[2]) * -1; - dir = getDirection(player, split[3].toLowerCase()); - } else { - dir = getDirection(player, "me"); - } - - Region region = session.getRegion(); - int oldSize = region.getSize(); - region.expand(dir.multiply(change)); - if (reverseChange != 0) { - region.expand(dir.multiply(reverseChange)); - } - session.learnRegionChanges(); - int newSize = region.getSize(); - player.print("Region expanded " + (newSize - oldSize) + " blocks."); - - return true; - - // Contract - } else if (split[0].equalsIgnoreCase("//contract")) { - checkArgs(split, 1, 3, split[0]); - Vector dir; - int change = Integer.parseInt(split[1]); - int reverseChange = 0; - if (split.length == 3) { - try { - reverseChange = Integer.parseInt(split[2]) * -1; - dir = getDirection(player, "me"); - } catch (NumberFormatException e) { - dir = getDirection(player, split[2].toLowerCase()); - } - } else if (split.length == 4) { - reverseChange = Integer.parseInt(split[2]) * -1; - dir = getDirection(player, split[3].toLowerCase()); - } else { - dir = getDirection(player, "me"); - } - - Region region = session.getRegion(); - int oldSize = region.getSize(); - region.contract(dir.multiply(change)); - if (reverseChange != 0) { - region.contract(dir.multiply(reverseChange)); - } - session.learnRegionChanges(); - int newSize = region.getSize(); - player.print("Region contracted " + (oldSize - newSize) + " blocks."); - - return true; - - // Shift - } else if (split[0].equalsIgnoreCase("//shift")) { - checkArgs(split, 1, 2, split[0]); - Vector dir; - int change = Integer.parseInt(split[1]); - if (split.length == 3) { - dir = getDirection(player, split[2].toLowerCase()); - } else { - dir = getDirection(player, "me"); - } - - Region region = session.getRegion(); - region.expand(dir.multiply(change)); - region.contract(dir.multiply(change)); - session.learnRegionChanges(); - player.print("Region shifted."); - - return true; - - // Rotate - } else if (split[0].equalsIgnoreCase("//rotate")) { - checkArgs(split, 1, 1, split[0]); - int angle = Integer.parseInt(split[1]); - if (angle % 90 == 0) { - CuboidClipboard clipboard = session.getClipboard(); - clipboard.rotate2D(angle); - player.print("Clipboard rotated by " + angle + " degrees."); - } else { - player.printError("Angles must be divisible by 90 degrees."); - } - - return true; - - // Flip - } else if (split[0].equalsIgnoreCase("//flip")) { - checkArgs(split, 0, 1, split[0]); - CuboidClipboard.FlipDirection dir = getFlipDirection(player, - split.length > 1 ? split[1].toLowerCase() : "me"); - - CuboidClipboard clipboard = session.getClipboard(); - clipboard.flip(dir); - player.print("Clipboard flipped."); - - return true; - - // Kill mobs - } else if (split[0].equalsIgnoreCase("/butcher")) { - checkArgs(split, 0, 1, split[0]); - - int radius = split.length > 1 ? - Math.max(1, Integer.parseInt(split[1])) : -1; - - Vector origin = session.getPlacementPosition(player); - int killed = world.killMobs(origin, radius); - player.print("Killed " + killed + " mobs."); - - return true; - - // Get chunk filename - } else if (split[0].equalsIgnoreCase("/chunkinfo")) { - checkArgs(split, 0, 0, split[0]); - - Vector pos = player.getBlockIn(); - int chunkX = (int)Math.floor(pos.getBlockX() / 16.0); - int chunkZ = (int)Math.floor(pos.getBlockZ() / 16.0); - - String folder1 = Integer.toString(divisorMod(chunkX, 64), 36); - String folder2 = Integer.toString(divisorMod(chunkZ, 64), 36); - String filename = "c." + Integer.toString(chunkX, 36) - + "." + Integer.toString(chunkZ, 36) + ".dat"; - - player.print("Chunk: " + chunkX + ", " + chunkZ); - player.print(folder1 + "/" + folder2 + "/" + filename); - - return true; - - // Dump a list of involved chunks - } else if (split[0].equalsIgnoreCase("/listchunks")) { - checkArgs(split, 0, 0, split[0]); - - Set chunks = session.getRegion().getChunks(); - - for (Vector2D chunk : chunks) { - player.print(NestedFileChunkStore.getFilename(chunk)); - } - - return true; - - // Dump a list of involved chunks - } else if (split[0].equalsIgnoreCase("/delchunks")) { - checkArgs(split, 0, 0, split[0]); - - Set chunks = session.getRegion().getChunks(); - FileOutputStream out = null; - - if (config.shellSaveType == null) { - player.printError("Shell script type must be configured: 'bat' or 'bash' expected."); - } else if (config.shellSaveType.equalsIgnoreCase("bat")) { - try { - out = new FileOutputStream("worldedit-delchunks.bat"); - OutputStreamWriter writer = new OutputStreamWriter(out, "UTF-8"); - writer.write("@ECHO off\r\n"); - writer.write("ECHO This batch file was generated by WorldEdit.\r\n"); - writer.write("ECHO It contains a list of chunks that were in the selected region\r\n"); - writer.write("ECHO at the time that the /delchunks command was used. Run this file\r\n"); - writer.write("ECHO in order to delete the chunk files listed in this file.\r\n"); - writer.write("ECHO.\r\n"); - writer.write("PAUSE\r\n"); - - for (Vector2D chunk : chunks) { - String filename = NestedFileChunkStore.getFilename(chunk); - writer.write("ECHO " + filename + "\r\n"); - writer.write("DEL \"world/" + filename + "\"\r\n"); - } - - writer.write("ECHO Complete.\r\n"); - writer.write("PAUSE\r\n"); - writer.close(); - player.print("worldedit-delchunks.bat written. Run it when no one is near the region."); - } catch (IOException e) { - player.printError("Error occurred: " + e.getMessage()); - } finally { - if (out != null) { - try { out.close(); } catch (IOException ie) {} - } - } - } else if (config.shellSaveType.equalsIgnoreCase("bash")) { - try { - out = new FileOutputStream("worldedit-delchunks.sh"); - OutputStreamWriter writer = new OutputStreamWriter(out, "UTF-8"); - writer.write("#!/bin/bash\n"); - writer.write("echo This shell file was generated by WorldEdit.\n"); - writer.write("echo It contains a list of chunks that were in the selected region\n"); - writer.write("echo at the time that the /delchunks command was used. Run this file\n"); - writer.write("echo in order to delete the chunk files listed in this file.\n"); - writer.write("echo\n"); - writer.write("read -p \"Press any key to continue...\"\n"); - - for (Vector2D chunk : chunks) { - String filename = NestedFileChunkStore.getFilename(chunk); - writer.write("echo " + filename + "\n"); - writer.write("rm \"world/" + filename + "\"\n"); - } - - writer.write("echo Complete.\n"); - writer.write("read -p \"Press any key to continue...\"\n"); - writer.close(); - player.print("worldedit-delchunks.sh written. Run it when no one is near the region."); - player.print("You will have to chmod it to be executable."); - } catch (IOException e) { - player.printError("Error occurred: " + e.getMessage()); - } finally { - if (out != null) { - try { out.close(); } catch (IOException ie) {} - } - } - } else { - player.printError("Shell script type must be configured: 'bat' or 'bash' expected."); - } - - return true; - - // List snapshots - } else if (split[0].equalsIgnoreCase("/listsnapshots")) { - checkArgs(split, 0, 1, split[0]); - - int num = split.length > 1 ? - Math.min(40, Math.max(5, Integer.parseInt(split[1]))) : 5; - - if (config.snapshotRepo != null) { - Snapshot[] snapshots = config.snapshotRepo.getSnapshots(); - - if (snapshots.length > 0) { - for (byte i = 0; i < Math.min(num, snapshots.length); i++) { - player.print((i + 1) + ". " + snapshots[i].getName()); - } - - player.print("Use //use [snapshot] or //use latest to set the snapshot."); - } else { - player.printError("No snapshots are available."); - } - } else { - player.printError("Snapshot/backup restore is not configured."); - } - - return true; - - // Use a certain snapshot - } else if (split[0].equalsIgnoreCase("//use")) { - checkArgs(split, 1, 1, split[0]); - - if (config.snapshotRepo == null) { - player.printError("Snapshot/backup restore is not configured."); - return true; - } - - String name = split[1]; - - // Want the latest snapshot? - if (name.equalsIgnoreCase("latest")) { - Snapshot snapshot = config.snapshotRepo.getDefaultSnapshot(); - - if (snapshot != null) { - session.setSnapshot(null); - player.print("Now using newest snapshot."); - } else { - player.printError("No snapshots were found."); - } - } else { - try { - session.setSnapshot(config.snapshotRepo.getSnapshot(name)); - player.print("Snapshot set to: " + name); - } catch (InvalidSnapshotException e) { - player.printError("That snapshot does not exist or is not available."); - } - } - - return true; - - // Restore - } else if (split[0].equalsIgnoreCase("//restore")) { - checkArgs(split, 0, 1, split[0]); - - if (config.snapshotRepo == null) { - player.printError("Snapshot/backup restore is not configured."); - return true; - } - - Region region = session.getRegion(); - Snapshot snapshot; - - if (split.length > 1) { - try { - snapshot = config.snapshotRepo.getSnapshot(split[1]); - } catch (InvalidSnapshotException e) { - player.printError("That snapshot does not exist or is not available."); - return true; - } - } else { - snapshot = session.getSnapshot(); - } - - ChunkStore chunkStore = null; - - // No snapshot set? - if (snapshot == null) { - snapshot = config.snapshotRepo.getDefaultSnapshot(); - - if (snapshot == null) { - player.printError("No snapshots were found."); - return true; - } - } - - // Load chunk store - try { - chunkStore = snapshot.getChunkStore(); - player.print("Snapshot '" + snapshot.getName() + "' loaded; now restoring..."); - } catch (DataException e) { - player.printError("Failed to load snapshot: " + e.getMessage()); - return true; - } catch (IOException e) { - player.printError("Failed to load snapshot: " + e.getMessage()); - return true; - } - - try { - // Restore snapshot - SnapshotRestore restore = new SnapshotRestore(chunkStore, region); - //player.print(restore.getChunksAffected() + " chunk(s) will be loaded."); - - restore.restore(editSession); - - if (restore.hadTotalFailure()) { - String error = restore.getLastErrorMessage(); - if (error != null) { - player.printError("Errors prevented any blocks from being restored."); - player.printError("Last error: " + error); - } else { - player.printError("No chunks could be loaded. (Bad archive?)"); - } - } else { - player.print(String.format("Restored; %d " - + "missing chunks and %d other errors.", - restore.getMissingChunks().size(), - restore.getErrorChunks().size())); - } - } finally { - try { - chunkStore.close(); - } catch (IOException e) { - } - } - - 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); - - session.setLastScript(split[1]); - - runScript(player, split[1], args); - - return true; - - // CraftScript - } else if (split[0].equalsIgnoreCase("/.s")) { - checkArgs(split, 1, -1, split[0]); - - String lastScript = session.getLastScript(); - - if (lastScript == null) { - player.printError("Use /cs with a script name first."); - return true; - } - - String[] args = new String[split.length]; - System.arraycopy(split, 0, args, 0, split.length); - args[0] = lastScript; - - runScript(player, lastScript, args); - - return true; - } - - return false; - } - /** * Modulus, divisor-style. * @@ -1775,7 +350,7 @@ public class WorldEdit { * @param n * @return */ - private static int divisorMod(int a, int n) { + public static int divisorMod(int a, int n) { return (int)(a - n * Math.floor(Math.floor(a) / (double)n)); } @@ -1883,7 +458,7 @@ public class WorldEdit { * @param blockBag * @param editSession */ - private static void flushBlockBag(LocalPlayer player, + public void flushBlockBag(LocalPlayer player, EditSession editSession) { BlockBag blockBag = editSession.getBlockBag(); @@ -1918,38 +493,11 @@ public class WorldEdit { } } - /** - * Checks to see if the player can use a command or /worldedit. - * - * @param player - * @param command - * @return - */ - private boolean canUseCommand(LocalPlayer player, String command) { - // Allow the /worldeditselect permission - if (command.equalsIgnoreCase("/pos1") - || command.equalsIgnoreCase("/pos2") - || command.equalsIgnoreCase("/hpos1") - || command.equalsIgnoreCase("/hpos2") - || command.equalsIgnoreCase("/chunk") - || command.equalsIgnoreCase("/expand") - || command.equalsIgnoreCase("/contract") - || command.equalsIgnoreCase("/shift") - || command.equalsIgnoreCase("toggleeditwand")) { - return player.hasPermission(command) - || player.hasPermission("worldeditselect") - || player.hasPermission("worldedit"); - } - - return player.hasPermission(command) - || player.hasPermission("worldedit"); - } - /** * @return the commands */ - public HashMap getCommands() { - return commands; + public Map getCommands() { + return commands.getCommands(); } /** @@ -1979,7 +527,7 @@ public class WorldEdit { && config.navigationWandMaxDistance > 0) { CompassMode mode = session.getCompassMode(); - if (player.hasPermission("jumpto") && mode == CompassMode.JUMPTO) { + if (player.hasPermission("worldedit.navigation.jumpto") && mode == CompassMode.JUMPTO) { WorldVector pos = player.getSolidBlockTrace(config.navigationWandMaxDistance); if (pos != null) { player.findFreePosition(pos); @@ -2009,14 +557,14 @@ public class WorldEdit { CompassMode mode = session.getCompassMode(); if (mode == CompassMode.JUMPTO) { - if (player.hasPermission("thru")) { + if (player.hasPermission("worldedit.navigation.thru")) { session.setCompassMode(CompassMode.THRU); player.print("Switched to /thru mode."); } else { player.printError("You don't have permission for /thru."); } } else { - if (player.hasPermission("jumpto")) { + if (player.hasPermission("worldedit.navigation.jumpto")) { session.setCompassMode(CompassMode.JUMPTO); player.print("Switched to /jumpto mode."); } else { @@ -2043,7 +591,7 @@ public class WorldEdit { LocalSession session = getSession(player); if (itemInHand == config.wandItem && session.isToolControlEnabled() - && canUseCommand(player, "/pos2")) { + && player.hasPermission("worldedit.selection.pos")) { session.setPos2(clicked); try { player.print("Second position set to " + clicked @@ -2068,13 +616,11 @@ public class WorldEdit { * @return false if you want the action to go through */ public boolean handleBlockLeftClick(LocalPlayer player, WorldVector clicked) { - if (!canUseCommand(player, "/pos1") - && !canUseCommand(player, "/")) { return false; } - LocalSession session = getSession(player); if (player.getItemInHand() == config.wandItem) { - if (session.isToolControlEnabled()) { + if (session.isToolControlEnabled() + && player.hasPermission("worldedit.selection.pos")) { // Bug workaround if (clicked.getBlockX() == 0 && clicked.getBlockY() == 0 && clicked.getBlockZ() == 0) { @@ -2116,56 +662,55 @@ public class WorldEdit { */ public boolean handleCommand(LocalPlayer player, String[] split) { try { - // Legacy /, command - if (split[0].equals("/,")) { - split[0] = "//"; + // Quick script shortcut - } else if (split[0].matches("^/[^/].*\\.js$")) { + if (split[0].matches("^/[^/].*\\.js$")) { String[] newSplit = new String[split.length + 1]; System.arraycopy(split, 0, newSplit, 1, split.length); newSplit[0] = "/cs"; newSplit[1] = newSplit[1].substring(1); split = newSplit; } - String searchCmd = split[0].toLowerCase(); - if (commands.containsKey(searchCmd) - || (config.noDoubleSlash && commands.containsKey("/" + searchCmd)) + if (commands.hasCommand(searchCmd) + || (config.noDoubleSlash && commands.hasCommand("/" + searchCmd)) || ((searchCmd.length() < 3 || searchCmd.charAt(2) != '/') - && commands.containsKey(searchCmd.substring(1)))) { - if (config.noDoubleSlash && commands.containsKey("/" + searchCmd)) { + && commands.hasCommand(searchCmd.substring(1)))) { + if (config.noDoubleSlash && commands.hasCommand("/" + searchCmd)) { split[0] = "/" + split[0]; - } else if (commands.containsKey(searchCmd.substring(1))) { + } else if (commands.hasCommand(searchCmd.substring(1))) { split[0] = split[0].substring(1); } + + LocalSession session = getSession(player); + BlockBag blockBag = session.getBlockBag(player); - if (canUseCommand(player, split[0].substring(1))) { - LocalSession session = getSession(player); - BlockBag blockBag = session.getBlockBag(player); - - EditSession editSession = - new EditSession(server, player.getWorld(), - session.getBlockChangeLimit(), blockBag); - editSession.enableQueue(); + EditSession editSession = + new EditSession(server, player.getWorld(), + session.getBlockChangeLimit(), blockBag); + editSession.enableQueue(); - long start = System.currentTimeMillis(); + long start = System.currentTimeMillis(); - try { - return performCommand(player, session, editSession, split); - } finally { - session.remember(editSession); - editSession.flushQueue(); - - if (config.profile) { - long time = System.currentTimeMillis() - start; - player.print((time / 1000.0) + "s elapsed"); - } - - flushBlockBag(player, editSession); + try { + if (config.logCommands) { + logger.log(Level.INFO, "WorldEdit: " + player.getName() + ": " + + StringUtil.joinString(split, " ")); } - } else { - player.printError("You don't have permission for this command."); + + return commands.execute(new CommandContext(split), this, + session, player, editSession); + } finally { + session.remember(editSession); + editSession.flushQueue(); + + if (config.profile) { + long time = System.currentTimeMillis() - start; + player.print((time / 1000.0) + "s elapsed"); + } + + flushBlockBag(player, editSession); } } @@ -2312,4 +857,13 @@ public class WorldEdit { } } } + + /** + * Get Worldedit's configuration. + * + * @return + */ + public LocalConfiguration getConfiguration() { + return config; + } } diff --git a/src/com/sk89q/worldedit/bukkit/BukkitPlayer.java b/src/com/sk89q/worldedit/bukkit/BukkitPlayer.java index d7815bfff..22b5d57f1 100644 --- a/src/com/sk89q/worldedit/bukkit/BukkitPlayer.java +++ b/src/com/sk89q/worldedit/bukkit/BukkitPlayer.java @@ -102,7 +102,7 @@ public class BukkitPlayer extends LocalPlayer { @Override public boolean hasPermission(String perm) { - return plugin.hasPermission(player, "/" + perm); + return plugin.hasPermission(player, perm); } @Override diff --git a/src/com/sk89q/worldedit/commands/ChunkCommands.java b/src/com/sk89q/worldedit/commands/ChunkCommands.java new file mode 100644 index 000000000..b27815ece --- /dev/null +++ b/src/com/sk89q/worldedit/commands/ChunkCommands.java @@ -0,0 +1,161 @@ +// $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.commands; + +import java.io.*; +import java.util.Set; +import com.sk89q.util.commands.Command; +import com.sk89q.util.commands.CommandContext; +import com.sk89q.worldedit.*; +import com.sk89q.worldedit.data.NestedFileChunkStore; + +/** + * Chunk tools. + * + * @author sk89q + */ +public class ChunkCommands { + @Command( + aliases = {"/chunkinfo"}, + usage = "", + desc = "Get information about the chunk that you are inside", + min = 0, + max = 0 + ) + @CommandPermissions({"worldedit.chunkinfo"}) + public static void chunkInfo(CommandContext args, WorldEdit we, + LocalSession session, LocalPlayer player, EditSession editSession) + throws WorldEditException { + + Vector pos = player.getBlockIn(); + int chunkX = (int)Math.floor(pos.getBlockX() / 16.0); + int chunkZ = (int)Math.floor(pos.getBlockZ() / 16.0); + + String folder1 = Integer.toString(WorldEdit.divisorMod(chunkX, 64), 36); + String folder2 = Integer.toString(WorldEdit.divisorMod(chunkZ, 64), 36); + String filename = "c." + Integer.toString(chunkX, 36) + + "." + Integer.toString(chunkZ, 36) + ".dat"; + + player.print("Chunk: " + chunkX + ", " + chunkZ); + player.print(folder1 + "/" + folder2 + "/" + filename); + } + + @Command( + aliases = {"/listchunks"}, + usage = "", + desc = "List chunks that your selection includes", + min = 0, + max = 0 + ) + @CommandPermissions({"worldedit.listchunks"}) + public static void listChunks(CommandContext args, WorldEdit we, + LocalSession session, LocalPlayer player, EditSession editSession) + throws WorldEditException { + + Set chunks = session.getRegion().getChunks(); + + for (Vector2D chunk : chunks) { + player.print(NestedFileChunkStore.getFilename(chunk)); + } + } + + @Command( + aliases = {"/delchunks"}, + usage = "", + desc = "Delete chunks that your selection includes", + min = 0, + max = 0 + ) + @CommandPermissions({"delchunks"}) + public static void deleteChunks(CommandContext args, WorldEdit we, + LocalSession session, LocalPlayer player, EditSession editSession) + throws WorldEditException { + + LocalConfiguration config = we.getConfiguration(); + + Set chunks = session.getRegion().getChunks(); + FileOutputStream out = null; + + if (config.shellSaveType == null) { + player.printError("Shell script type must be configured: 'bat' or 'bash' expected."); + } else if (config.shellSaveType.equalsIgnoreCase("bat")) { + try { + out = new FileOutputStream("worldedit-delchunks.bat"); + OutputStreamWriter writer = new OutputStreamWriter(out, "UTF-8"); + writer.write("@ECHO off\r\n"); + writer.write("ECHO This batch file was generated by WorldEdit.\r\n"); + writer.write("ECHO It contains a list of chunks that were in the selected region\r\n"); + writer.write("ECHO at the time that the /delchunks command was used. Run this file\r\n"); + writer.write("ECHO in order to delete the chunk files listed in this file.\r\n"); + writer.write("ECHO.\r\n"); + writer.write("PAUSE\r\n"); + + for (Vector2D chunk : chunks) { + String filename = NestedFileChunkStore.getFilename(chunk); + writer.write("ECHO " + filename + "\r\n"); + writer.write("DEL \"world/" + filename + "\"\r\n"); + } + + writer.write("ECHO Complete.\r\n"); + writer.write("PAUSE\r\n"); + writer.close(); + player.print("worldedit-delchunks.bat written. Run it when no one is near the region."); + } catch (IOException e) { + player.printError("Error occurred: " + e.getMessage()); + } finally { + if (out != null) { + try { out.close(); } catch (IOException ie) {} + } + } + } else if (config.shellSaveType.equalsIgnoreCase("bash")) { + try { + out = new FileOutputStream("worldedit-delchunks.sh"); + OutputStreamWriter writer = new OutputStreamWriter(out, "UTF-8"); + writer.write("#!/bin/bash\n"); + writer.write("echo This shell file was generated by WorldEdit.\n"); + writer.write("echo It contains a list of chunks that were in the selected region\n"); + writer.write("echo at the time that the /delchunks command was used. Run this file\n"); + writer.write("echo in order to delete the chunk files listed in this file.\n"); + writer.write("echo\n"); + writer.write("read -p \"Press any key to continue...\"\n"); + + for (Vector2D chunk : chunks) { + String filename = NestedFileChunkStore.getFilename(chunk); + writer.write("echo " + filename + "\n"); + writer.write("rm \"world/" + filename + "\"\n"); + } + + writer.write("echo Complete.\n"); + writer.write("read -p \"Press any key to continue...\"\n"); + writer.close(); + player.print("worldedit-delchunks.sh written. Run it when no one is near the region."); + player.print("You will have to chmod it to be executable."); + } catch (IOException e) { + player.printError("Error occurred: " + e.getMessage()); + } finally { + if (out != null) { + try { out.close(); } catch (IOException ie) {} + } + } + } else { + player.printError("Shell script type must be configured: 'bat' or 'bash' expected."); + } + } +} diff --git a/src/com/sk89q/worldedit/commands/ClipboardCommands.java b/src/com/sk89q/worldedit/commands/ClipboardCommands.java new file mode 100644 index 000000000..ed8bbb810 --- /dev/null +++ b/src/com/sk89q/worldedit/commands/ClipboardCommands.java @@ -0,0 +1,282 @@ +// $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.commands; + +import java.io.File; +import java.io.IOException; +import com.sk89q.util.commands.Command; +import com.sk89q.util.commands.CommandContext; +import com.sk89q.worldedit.*; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.data.DataException; +import com.sk89q.worldedit.regions.Region; + +/** + * Clipboard commands. + * + * @author sk89q + */ +public class ClipboardCommands { + @Command( + aliases = {"//copy"}, + usage = "", + desc = "Copy the selection to the clipboard", + min = 0, + max = 0 + ) + @CommandPermissions({"worldedit.clipboard.copy"}) + public static void copy(CommandContext args, WorldEdit we, + LocalSession session, LocalPlayer player, EditSession editSession) + throws WorldEditException { + + Region region = session.getRegion(); + Vector min = region.getMinimumPoint(); + Vector max = region.getMaximumPoint(); + Vector pos = player.getBlockIn(); + + CuboidClipboard clipboard = new CuboidClipboard( + max.subtract(min).add(new Vector(1, 1, 1)), + min, min.subtract(pos)); + clipboard.copy(editSession); + session.setClipboard(clipboard); + + player.print("Block(s) copied."); + } + + @Command( + aliases = {"//cut"}, + usage = "[leave-id]", + desc = "Cut the selection to the clipboard", + min = 0, + max = 1 + ) + @CommandPermissions({"worldedit.clipboard.cut"}) + public static void cut(CommandContext args, WorldEdit we, + LocalSession session, LocalPlayer player, EditSession editSession) + throws WorldEditException { + + BaseBlock block = new BaseBlock(0); + + if (args.argsLength() > 0) { + block = we.getBlock(player, args.getString(0)); + } + + Region region = session.getRegion(); + Vector min = region.getMinimumPoint(); + Vector max = region.getMaximumPoint(); + Vector pos = player.getBlockIn(); + + CuboidClipboard clipboard = new CuboidClipboard( + max.subtract(min).add(new Vector(1, 1, 1)), + min, min.subtract(pos)); + clipboard.copy(editSession); + session.setClipboard(clipboard); + + editSession.setBlocks(session.getRegion(), block); + player.print("Block(s) cut."); + } + + @Command( + aliases = {"//paste"}, + usage = "[at-origin?]", + desc = "Paste the clipboard's contents", + min = 0, + max = 1 + ) + @CommandPermissions({"worldedit.clipboard.paste"}) + public static void paste(CommandContext args, WorldEdit we, + LocalSession session, LocalPlayer player, EditSession editSession) + throws WorldEditException { + + boolean atOrigin = args.argsLength() > 0 + ? (args.getString(1).equalsIgnoreCase("true") + || args.getString(0).equalsIgnoreCase("yes")) + : false; + + if (atOrigin) { + Vector pos = session.getClipboard().getOrigin(); + session.getClipboard().place(editSession, pos, false); + player.findFreePosition(); + player.print("Pasted to copy origin. Undo with //undo"); + } else { + Vector pos = session.getPlacementPosition(player); + session.getClipboard().paste(editSession, pos, false); + player.findFreePosition(); + player.print("Pasted relative to you. Undo with //undo"); + } + } + + @Command( + aliases = {"//rotate"}, + usage = "", + desc = "Rotate the contents of the clipboard", + min = 1, + max = 1 + ) + @CommandPermissions({"worldedit.clipboard.rotate"}) + public static void rotate(CommandContext args, WorldEdit we, + LocalSession session, LocalPlayer player, EditSession editSession) + throws WorldEditException { + + int angle = args.getInteger(0); + + if (angle % 90 == 0) { + CuboidClipboard clipboard = session.getClipboard(); + clipboard.rotate2D(angle); + player.print("Clipboard rotated by " + angle + " degrees."); + } else { + player.printError("Angles must be divisible by 90 degrees."); + } + } + + @Command( + aliases = {"//flip"}, + usage = "[dir]", + desc = "Flip the contents of the clipboard", + min = 0, + max = 1 + ) + @CommandPermissions({"worldedit.clipboard.flip"}) + public static void flip(CommandContext args, WorldEdit we, + LocalSession session, LocalPlayer player, EditSession editSession) + throws WorldEditException { + + CuboidClipboard.FlipDirection dir = we.getFlipDirection(player, + args.argsLength() > 0 ? args.getString(0).toLowerCase() : "me"); + + CuboidClipboard clipboard = session.getClipboard(); + clipboard.flip(dir); + player.print("Clipboard flipped."); + } + + @Command( + aliases = {"//load"}, + usage = "", + desc = "Load a schematic into your clipboard", + min = 1, + max = 1 + ) + @CommandPermissions({"worldedit.clipboard.load"}) + public static void load(CommandContext args, WorldEdit we, + LocalSession session, LocalPlayer player, EditSession editSession) + throws WorldEditException { + + LocalConfiguration config = we.getConfiguration(); + + String filename = args.getString(0).replace("\0", "") + ".schematic"; + File dir = new File(config.getWorkingDirectory(), "schematics"); + File f = new File(new File(config.getWorkingDirectory(), "schematics"), filename); + + if (!filename.matches("^[A-Za-z0-9_\\- \\./\\\\'\\$@~!%\\^\\*\\(\\)\\[\\]\\+\\{\\},\\?]+$")) { + player.printError("Valid characters: A-Z, a-z, 0-9, spaces, " + + "./\'$@~!%^*()[]+{},?"); + return; + } + + try { + String filePath = f.getCanonicalPath(); + String dirPath = dir.getCanonicalPath(); + + if (!filePath.substring(0, dirPath.length()).equals(dirPath)) { + player.printError("Schematic could not read or it does not exist."); + } else { + session.setClipboard(CuboidClipboard.loadSchematic(f)); + WorldEdit.logger.info(player.getName() + " loaded " + filePath); + player.print(filename + " loaded. Paste it with //paste"); + } + } catch (DataException e) { + player.printError("Load error: " + e.getMessage()); + } catch (IOException e) { + player.printError("Schematic could not read or it does not exist: " + e.getMessage()); + } + } + + @Command( + aliases = {"//save"}, + usage = "", + desc = "Save a schematic into your clipboard", + min = 1, + max = 1 + ) + @CommandPermissions({"worldedit.clipboard.save"}) + public static void save(CommandContext args, WorldEdit we, + LocalSession session, LocalPlayer player, EditSession editSession) + throws WorldEditException { + + LocalConfiguration config = we.getConfiguration(); + + String filename = args.getString(0).replace("\0", "") + ".schematic"; + + if (!filename.matches("^[A-Za-z0-9_\\- \\./\\\\'\\$@~!%\\^\\*\\(\\)\\[\\]\\+\\{\\},\\?]+$")) { + player.printError("Valid characters: A-Z, a-z, 0-9, spaces, " + + "./\'$@~!%^*()[]+{},?"); + return; + } + + File dir = new File(config.getWorkingDirectory(), "schematics"); + File f = new File(new File(config.getWorkingDirectory(), "schematics"), filename); + + if (!dir.exists()) { + if (!dir.mkdir()) { + player.printError("A schematics/ folder could not be created."); + return; + } + } + + try { + String filePath = f.getCanonicalPath(); + String dirPath = dir.getCanonicalPath(); + + if (!filePath.substring(0, dirPath.length()).equals(dirPath)) { + player.printError("Invalid path for Schematic."); + } else { + // Create parent directories + File parent = f.getParentFile(); + if (parent != null && !parent.exists()) { + parent.mkdirs(); + } + + session.getClipboard().saveSchematic(f); + WorldEdit.logger.info(player.getName() + " saved " + filePath); + player.print(filename + " saved."); + } + } catch (DataException se) { + player.printError("Save error: " + se.getMessage()); + } catch (IOException e) { + player.printError("Schematic could not written: " + e.getMessage()); + } + } + + @Command( + aliases = {"/clearclipboard"}, + usage = "", + desc = "Clear your clipboard", + min = 0, + max = 0 + ) + @CommandPermissions({"worldedit.clipboard.clear"}) + public static void clearClipboard(CommandContext args, WorldEdit we, + LocalSession session, LocalPlayer player, EditSession editSession) + throws WorldEditException { + + session.setClipboard(null); + player.print("Clipboard cleared."); + } +} diff --git a/src/com/sk89q/worldedit/commands/CommandPermissions.java b/src/com/sk89q/worldedit/commands/CommandPermissions.java new file mode 100644 index 000000000..392cd0913 --- /dev/null +++ b/src/com/sk89q/worldedit/commands/CommandPermissions.java @@ -0,0 +1,28 @@ +// $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.commands; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +@Retention(RetentionPolicy.RUNTIME) +public @interface CommandPermissions { + String[] value(); +} diff --git a/src/com/sk89q/worldedit/commands/CommandsManager.java b/src/com/sk89q/worldedit/commands/CommandsManager.java new file mode 100644 index 000000000..31d83b36e --- /dev/null +++ b/src/com/sk89q/worldedit/commands/CommandsManager.java @@ -0,0 +1,166 @@ +// $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.commands; + +import java.lang.annotation.Annotation; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Map; +import com.sk89q.util.commands.Command; +import com.sk89q.util.commands.CommandContext; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.LocalPlayer; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.WorldEditException; + +/** + * Manager for handling commands. + * + * @author sk89q + */ +public class CommandsManager { + /** + * Mapping of commands (including aliases) with their method. + */ + public Map commands = new HashMap(); + /** + * Mapping of commands (not including aliases) with a description. + */ + public Map descs = new HashMap(); + + /** + * Register an object that contains commands (denoted by the + * com.sk89q.util.commands.Command annotation. The methods are + * cached into a map for later usage and it reduces the overhead of + * reflection (method lookup via reflection is relatively slow). + * + * @param cls + */ + public void register(Class cls) { + for (Method method : cls.getMethods()) { + if (!method.isAnnotationPresent(Command.class)) { + continue; + } + + Command cmd = method.getAnnotation(Command.class); + + // Cache the commands + for (String alias : cmd.aliases()) { + commands.put(alias, method); + } + + // Build a list of commands and their usage details + if (cmd.usage().length() == 0) { + descs.put(cmd.aliases()[0], cmd.desc()); + } else { + descs.put(cmd.aliases()[0], cmd.usage() + " - " + cmd.desc()); + } + } + } + + /** + * Checks to see whether there is a command. + * + * @param command + * @return + */ + public boolean hasCommand(String command) { + return commands.containsKey(command.toLowerCase()); + } + + /** + * Get a list of command descriptions. + * + * @return + */ + public Map getCommands() { + return descs; + } + + /** + * Attempt to execute a command. + * + * @param args + * @param we + * @param session + * @param player + * @param editSession + * @return + */ + public boolean execute(CommandContext args, WorldEdit we, + LocalSession session, LocalPlayer player, EditSession editSession) + throws WorldEditException { + Method method = commands.get(args.getCommand().toLowerCase()); + + if (method == null) { + return false; // No command + } + + if (!checkPermissions(method, player)) { + return true; + } + + Command cmd = method.getAnnotation(Command.class); + + if (args.argsLength() < cmd.min()) { + player.printError(args.getCommand() + " " + cmd.usage()); + return true; + } + + if (cmd.max() != -1 && args.argsLength() > cmd.max()) { + player.printError(args.getCommand() + " " + cmd.usage()); + return true; + } + + try { + method.invoke(null, args, we, session, player, editSession); + } catch (IllegalArgumentException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } catch (InvocationTargetException e) { + if (e.getCause() instanceof WorldEditException) { + throw (WorldEditException)e.getCause(); + } else { + e.printStackTrace(); + } + } + + return true; + } + + private boolean checkPermissions(Method method, LocalPlayer player) { + CommandPermissions perms = method.getAnnotation(CommandPermissions.class); + if (perms == null) { + return true; + } + + for (String perm : perms.value()) { + if (player.hasPermission(perm)) { + return true; + } + } + + player.printError("You don't have permission for this command."); + return false; + } +} diff --git a/src/com/sk89q/worldedit/commands/GeneralCommands.java b/src/com/sk89q/worldedit/commands/GeneralCommands.java new file mode 100644 index 000000000..34e604a5a --- /dev/null +++ b/src/com/sk89q/worldedit/commands/GeneralCommands.java @@ -0,0 +1,77 @@ +// $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.commands; + +import com.sk89q.util.commands.Command; +import com.sk89q.util.commands.CommandContext; +import com.sk89q.worldedit.*; + +/** + * General WorldEdit commands. + * + * @author sk89q + */ +public class GeneralCommands { + @Command( + aliases = {"//limit"}, + usage = "", + desc = "Modify block change limit", + min = 1, + max = 1 + ) + @CommandPermissions({"worldedit.limit"}) + public static void limit(CommandContext args, WorldEdit we, + LocalSession session, LocalPlayer player, EditSession editSession) + throws WorldEditException { + + LocalConfiguration config = we.getConfiguration(); + + int limit = Math.max(-1, args.getInteger(0)); + if (!player.hasPermission("worldedit.limit.unrestricted") + && config.maxChangeLimit > -1) { + if (limit > config.maxChangeLimit) { + player.printError("Your maximum allowable limit is " + + config.maxChangeLimit + "."); + return; + } + } + + session.setBlockChangeLimit(limit); + player.print("Block change limit set to " + limit + "."); + } + + @Command( + aliases = {"/toggleplace"}, + usage = "", + desc = "", + min = 0, + max = 0 + ) + public static void togglePlace(CommandContext args, WorldEdit we, + LocalSession session, LocalPlayer player, EditSession editSession) + throws WorldEditException { + + if (session.togglePlacementPosition()) { + player.print("Now placing at pos #1."); + } else { + player.print("Now placing at the block you stand in."); + } + } +} diff --git a/src/com/sk89q/worldedit/commands/GenerationCommands.java b/src/com/sk89q/worldedit/commands/GenerationCommands.java new file mode 100644 index 000000000..0b5610333 --- /dev/null +++ b/src/com/sk89q/worldedit/commands/GenerationCommands.java @@ -0,0 +1,190 @@ +// $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.commands; + +import com.sk89q.util.commands.Command; +import com.sk89q.util.commands.CommandContext; +import com.sk89q.worldedit.*; +import com.sk89q.worldedit.blocks.BaseBlock; + +/** + * Generation commands. + * + * @author sk89q + */ +public class GenerationCommands { + @Command( + aliases = {"//hcyl"}, + usage = " [height] ", + desc = "Generate a hollow cylinder", + min = 2, + max = 3 + ) + @CommandPermissions({"worldedit.generation.cylinder"}) + public static void hcyl(CommandContext args, WorldEdit we, + LocalSession session, LocalPlayer player, EditSession editSession) + throws WorldEditException { + + BaseBlock block = we.getBlock(player, args.getString(0)); + int radius = Math.max(1, args.getInteger(1)); + int height = args.argsLength() > 2 ? args.getInteger(2) : 1; + + Vector pos = session.getPlacementPosition(player); + int affected = editSession.makeHollowCylinder(pos, block, radius, height); + player.print(affected + " block(s) have been created."); + } + + @Command( + aliases = {"//cyl"}, + usage = " [height] ", + desc = "Generate a cylinder", + min = 2, + max = 3 + ) + @CommandPermissions({"worldedit.generation.cylinder"}) + public static void cyl(CommandContext args, WorldEdit we, + LocalSession session, LocalPlayer player, EditSession editSession) + throws WorldEditException { + + BaseBlock block = we.getBlock(player, args.getString(0)); + int radius = Math.max(1, args.getInteger(1)); + int height = args.argsLength() > 2 ? args.getInteger(2) : 1; + + Vector pos = session.getPlacementPosition(player); + int affected = editSession.makeCylinder(pos, block, radius, height); + player.print(affected + " block(s) have been created."); + } + + @Command( + aliases = {"//hsphere"}, + usage = " [raised?] ", + desc = "Generate a hollow sphere", + min = 2, + max = 3 + ) + @CommandPermissions({"worldedit.generation.sphere"}) + public static void hsphere(CommandContext args, WorldEdit we, + LocalSession session, LocalPlayer player, EditSession editSession) + throws WorldEditException { + + BaseBlock block = we.getBlock(player, args.getString(0)); + int radius = Math.max(1, args.getInteger(1)); + boolean raised = args.argsLength() > 2 + ? (args.getString(2).equalsIgnoreCase("true") + || args.getString(2).equalsIgnoreCase("yes")) + : false; + + Vector pos = session.getPlacementPosition(player); + if (raised) { + pos = pos.add(0, radius, 0); + } + + int affected = editSession.makeSphere(pos, block, radius, false); + player.findFreePosition(); + player.print(affected + " block(s) have been created."); + } + + @Command( + aliases = {"//sphere"}, + usage = " [raised?] ", + desc = "Generate a filled sphere", + min = 2, + max = 3 + ) + @CommandPermissions({"worldedit.generation.sphere"}) + public static void sphere(CommandContext args, WorldEdit we, + LocalSession session, LocalPlayer player, EditSession editSession) + throws WorldEditException { + + BaseBlock block = we.getBlock(player, args.getString(0)); + int radius = Math.max(1, args.getInteger(1)); + boolean raised = args.argsLength() > 2 + ? (args.getString(2).equalsIgnoreCase("true") + || args.getString(2).equalsIgnoreCase("yes")) + : false; + + Vector pos = session.getPlacementPosition(player); + if (raised) { + pos = pos.add(0, radius, 0); + } + + int affected = editSession.makeSphere(pos, block, radius, true); + player.findFreePosition(); + player.print(affected + " block(s) have been created."); + } + + @Command( + aliases = {"/forestgen"}, + usage = "[size] [density] ", + desc = "Generate a forest", + min = 0, + max = 2 + ) + @CommandPermissions({"worldedit.generation.forest"}) + public static void forestGen(CommandContext args, WorldEdit we, + LocalSession session, LocalPlayer player, EditSession editSession) + throws WorldEditException { + + int size = args.argsLength() > 0 ? Math.max(1, args.getInteger(0)) : 10; + double density = args.argsLength() > 1 ? Double.parseDouble(args.getString(1)) / 100 : 0.05; + + int affected = editSession.makeForest(player.getPosition(), + size, density, false); + player.print(affected + " trees created."); + } + + @Command( + aliases = {"/pinegen"}, + usage = "[size] [density]", + desc = "Generate a pine forest", + min = 0, + max = 2 + ) + @CommandPermissions({"worldedit.generation.forest"}) + public static void pineGen(CommandContext args, WorldEdit we, + LocalSession session, LocalPlayer player, EditSession editSession) + throws WorldEditException { + + int size = args.argsLength() > 0 ? Math.max(1, args.getInteger(0)) : 10; + double density = args.argsLength() > 1 ? Double.parseDouble(args.getString(1)) / 100 : 0.05; + + int affected = editSession.makeForest(player.getPosition(), + size, density, true); + player.print(affected + " pine trees created."); + } + + @Command( + aliases = {"/pumpkins"}, + usage = "[size]", + desc = "Generate pumpkin patches", + min = 0, + max = 1 + ) + @CommandPermissions({"worldedit.generation.pumpkins"}) + public static void pumpkins(CommandContext args, WorldEdit we, + LocalSession session, LocalPlayer player, EditSession editSession) + throws WorldEditException { + + int size = args.argsLength() > 0 ? Math.max(1, args.getInteger(0)) : 10; + + int affected = editSession.makePumpkinPatches(player.getPosition(), size); + player.print(affected + " pumpkin patches created."); + } +} diff --git a/src/com/sk89q/worldedit/commands/HistoryCommands.java b/src/com/sk89q/worldedit/commands/HistoryCommands.java new file mode 100644 index 000000000..5db794827 --- /dev/null +++ b/src/com/sk89q/worldedit/commands/HistoryCommands.java @@ -0,0 +1,89 @@ +// $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.commands; + +import com.sk89q.util.commands.Command; +import com.sk89q.util.commands.CommandContext; +import com.sk89q.worldedit.*; + +/** + * History little commands. + * + * @author sk89q + */ +public class HistoryCommands { + @Command( + aliases = {"//undo"}, + usage = "", + desc = "Undoes the last action", + min = 0, + max = 0 + ) + @CommandPermissions({"worldedit.history.undo"}) + public static void undo(CommandContext args, WorldEdit we, + LocalSession session, LocalPlayer player, EditSession editSession) + throws WorldEditException { + + EditSession undone = session.undo(session.getBlockBag(player)); + if (undone != null) { + player.print("Undo successful."); + we.flushBlockBag(player, undone); + } else { + player.printError("Nothing to undo."); + } + } + + @Command( + aliases = {"//redo"}, + usage = "", + desc = "Redoes the last action (from history)", + min = 0, + max = 0 + ) + @CommandPermissions({"worldedit.history.redo"}) + public static void redo(CommandContext args, WorldEdit we, + LocalSession session, LocalPlayer player, EditSession editSession) + throws WorldEditException { + + EditSession redone = session.redo(session.getBlockBag(player)); + if (redone != null) { + player.print("Redo successful."); + we.flushBlockBag(player, redone); + } else { + player.printError("Nothing to redo."); + } + } + + @Command( + aliases = {"/clearhistory"}, + usage = "", + desc = "Clear your history", + min = 0, + max = 0 + ) + @CommandPermissions({"worldedit.history.clear"}) + public static void clearHistory(CommandContext args, WorldEdit we, + LocalSession session, LocalPlayer player, EditSession editSession) + throws WorldEditException { + + session.clearHistory(); + player.print("History cleared."); + } +} diff --git a/src/com/sk89q/worldedit/InsufficientArgumentsException.java b/src/com/sk89q/worldedit/commands/InsufficientArgumentsException.java similarity index 91% rename from src/com/sk89q/worldedit/InsufficientArgumentsException.java rename to src/com/sk89q/worldedit/commands/InsufficientArgumentsException.java index 49f1bbb22..741f5721e 100644 --- a/src/com/sk89q/worldedit/InsufficientArgumentsException.java +++ b/src/com/sk89q/worldedit/commands/InsufficientArgumentsException.java @@ -17,7 +17,9 @@ * along with this program. If not, see . */ -package com.sk89q.worldedit; +package com.sk89q.worldedit.commands; + +import com.sk89q.worldedit.WorldEditException; /** * diff --git a/src/com/sk89q/worldedit/commands/NavigationCommands.java b/src/com/sk89q/worldedit/commands/NavigationCommands.java new file mode 100644 index 000000000..545dd6c32 --- /dev/null +++ b/src/com/sk89q/worldedit/commands/NavigationCommands.java @@ -0,0 +1,168 @@ +// $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.commands; + +import com.sk89q.util.commands.Command; +import com.sk89q.util.commands.CommandContext; +import com.sk89q.worldedit.*; + +/** + * Navigation commands. + * + * @author sk89q + */ +public class NavigationCommands { + @Command( + aliases = {"/unstuck"}, + usage = "", + desc = "Escape from being stuck inside a block", + min = 0, + max = 0 + ) + @CommandPermissions({"worldedit.navigation.unstuck"}) + public static void unstuck(CommandContext args, WorldEdit we, + LocalSession session, LocalPlayer player, EditSession editSession) + throws WorldEditException { + + player.print("There you go!"); + player.findFreePosition(); + } + + @Command( + aliases = {"/ascend"}, + usage = "", + desc = "Go up a floor", + min = 0, + max = 0 + ) + @CommandPermissions({"worldedit.navigation.ascend"}) + public static void ascend(CommandContext args, WorldEdit we, + LocalSession session, LocalPlayer player, EditSession editSession) + throws WorldEditException { + + if (player.ascendLevel()) { + player.print("Ascended a level."); + } else { + player.printError("No free spot above you found."); + } + } + + @Command( + aliases = {"/descend"}, + usage = "", + desc = "Go down a floor", + min = 0, + max = 0 + ) + @CommandPermissions({"worldedit.navigation.descend"}) + public static void descend(CommandContext args, WorldEdit we, + LocalSession session, LocalPlayer player, EditSession editSession) + throws WorldEditException { + + if (player.descendLevel()) { + player.print("Descended a level."); + } else { + player.printError("No free spot below you found."); + } + } + + @Command( + aliases = {"/ceil"}, + usage = "[clearance]", + desc = "Go to the celing", + min = 0, + max = 1 + ) + @CommandPermissions({"worldedit.navigation.ceiling"}) + public static void ceiling(CommandContext args, WorldEdit we, + LocalSession session, LocalPlayer player, EditSession editSession) + throws WorldEditException { + + int clearence = args.argsLength() > 0 ? + Math.max(0, args.getInteger(0)) : 0; + + if (player.ascendToCeiling(clearence)) { + player.print("Whoosh!"); + } else { + player.printError("No free spot above you found."); + } + } + + @Command( + aliases = {"/thru"}, + usage = "", + desc = "Passthrough walls", + min = 0, + max = 0 + ) + @CommandPermissions({"worldedit.navigation.thru"}) + public static void thru(CommandContext args, WorldEdit we, + LocalSession session, LocalPlayer player, EditSession editSession) + throws WorldEditException { + + if (player.passThroughForwardWall(6)) { + player.print("Whoosh!"); + } else { + player.printError("No free spot ahead of you found."); + } + } + + @Command( + aliases = {"/jumpto"}, + usage = "", + desc = "Teleport to a location", + min = 0, + max = 0 + ) + @CommandPermissions({"worldedit.navigation.jumpto"}) + public static void jumpTo(CommandContext args, WorldEdit we, + LocalSession session, LocalPlayer player, EditSession editSession) + throws WorldEditException { + + WorldVector pos = player.getSolidBlockTrace(300); + if (pos != null) { + player.findFreePosition(pos); + player.print("Poof!"); + } else { + player.printError("No block in sight!"); + } + } + + @Command( + aliases = {"/up"}, + usage = "", + desc = "Go upwards some distance", + min = 1, + max = 1 + ) + @CommandPermissions({"worldedit.navigation.up"}) + public static void up(CommandContext args, WorldEdit we, + LocalSession session, LocalPlayer player, EditSession editSession) + throws WorldEditException { + + int distance = args.getInteger(0); + + if (player.ascendUpwards(distance)) { + player.print("Whoosh!"); + } else { + player.printError("You would hit something above you."); + } + } +} diff --git a/src/com/sk89q/worldedit/commands/RegionCommands.java b/src/com/sk89q/worldedit/commands/RegionCommands.java new file mode 100644 index 000000000..4fa5a26a6 --- /dev/null +++ b/src/com/sk89q/worldedit/commands/RegionCommands.java @@ -0,0 +1,225 @@ +// $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.commands; + +import java.util.Set; +import com.sk89q.util.commands.Command; +import com.sk89q.util.commands.CommandContext; +import com.sk89q.worldedit.*; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.filters.GaussianKernel; +import com.sk89q.worldedit.filters.HeightMapFilter; +import com.sk89q.worldedit.patterns.*; +import com.sk89q.worldedit.regions.Region; + +/** + * Region related commands. + * + * @author sk89q + */ +public class RegionCommands { + @Command( + aliases = {"//set"}, + usage = "", + desc = "Set all the blocks inside the selection to a block", + min = 1, + max = 1 + ) + @CommandPermissions({"worldedit.region.set"}) + public static void set(CommandContext args, WorldEdit we, + LocalSession session, LocalPlayer player, EditSession editSession) + throws WorldEditException { + + Pattern pattern = we.getBlockPattern(player, args.getString(0)); + + int affected; + + if (pattern instanceof SingleBlockPattern) { + affected = editSession.setBlocks(session.getRegion(), + ((SingleBlockPattern)pattern).getBlock()); + } else { + affected = editSession.setBlocks(session.getRegion(), pattern); + } + + player.print(affected + " block(s) have been changed."); + } + + @Command( + aliases = {"//replace"}, + usage = "[from-block] ", + desc = "Replace all blocks in the selection with another", + min = 1, + max = 2 + ) + @CommandPermissions({"worldedit.region.replace"}) + public static void replace(CommandContext args, WorldEdit we, + LocalSession session, LocalPlayer player, EditSession editSession) + throws WorldEditException { + + Set from; + Pattern to; + if (args.argsLength() == 1) { + from = null; + to = we.getBlockPattern(player, args.getString(0)); + } else { + from = we.getBlockIDs(player, args.getString(0), true); + to = we.getBlockPattern(player, args.getString(1)); + } + + int affected = 0; + if (to instanceof SingleBlockPattern) { + affected = editSession.replaceBlocks(session.getRegion(), from, + ((SingleBlockPattern)to).getBlock()); + } else { + affected = editSession.replaceBlocks(session.getRegion(), from, to); + } + + player.print(affected + " block(s) have been replaced."); + } + + @Command( + aliases = {"//overlay"}, + usage = "", + desc = "Set a block on top of blocks in the region", + min = 1, + max = 1 + ) + @CommandPermissions({"worldedit.region.overlay"}) + public static void overlay(CommandContext args, WorldEdit we, + LocalSession session, LocalPlayer player, EditSession editSession) + throws WorldEditException { + + BaseBlock block = we.getBlock(player, args.getString(0)); + + Region region = session.getRegion(); + int affected = editSession.overlayCuboidBlocks(region, block); + player.print(affected + " block(s) have been overlayed."); + } + + @Command( + aliases = {"//walls"}, + usage = "", + desc = "Build the four sides of the selection", + min = 1, + max = 1 + ) + @CommandPermissions({"worldedit.region.walls"}) + public static void walls(CommandContext args, WorldEdit we, + LocalSession session, LocalPlayer player, EditSession editSession) + throws WorldEditException { + + BaseBlock block = we.getBlock(player, args.getString(0)); + int affected = editSession.makeCuboidWalls(session.getRegion(), block); + + player.print(affected + " block(s) have been changed."); + } + + @Command( + aliases = {"//faces", "//outline"}, + usage = "", + desc = "Build the walls, ceiling, and roof of a selection", + min = 1, + max = 1 + ) + @CommandPermissions({"worldedit.region.faces"}) + public static void faces(CommandContext args, WorldEdit we, + LocalSession session, LocalPlayer player, EditSession editSession) + throws WorldEditException { + + BaseBlock block = we.getBlock(player, args.getString(0)); + int affected = editSession.makeCuboidFaces(session.getRegion(), block); + player.print(affected + " block(s) have been changed."); + } + + @Command( + aliases = {"//smooth"}, + usage = "[iterations]", + desc = "Smooth the elevation in the selection", + min = 0, + max = 1 + ) + @CommandPermissions({"worldedit.region.smooth"}) + public static void smooth(CommandContext args, WorldEdit we, + LocalSession session, LocalPlayer player, EditSession editSession) + throws WorldEditException { + + int iterations = 1; + if (args.argsLength() > 0) { + iterations = args.getInteger(0); + } + + HeightMap heightMap = new HeightMap(editSession, session.getRegion()); + HeightMapFilter filter = new HeightMapFilter(new GaussianKernel(5, 1.0)); + int affected = heightMap.applyFilter(filter, iterations); + player.print("Terrain's height map smoothed. " + affected + " block(s) changed."); + + } + + @Command( + aliases = {"//move"}, + usage = "[count] [direction] [leave-id] ", + desc = "Move the contents of the selection", + min = 0, + max = 3 + ) + @CommandPermissions({"worldedit.region.move"}) + public static void move(CommandContext args, WorldEdit we, + LocalSession session, LocalPlayer player, EditSession editSession) + throws WorldEditException { + + int count = args.argsLength() > 0 ? Math.max(1, args.getInteger(0)) : 1; + Vector dir = we.getDirection(player, + args.argsLength() > 1 ? args.getString(1).toLowerCase() : "me"); + BaseBlock replace; + + // Replacement block argument + if (args.argsLength() > 2) { + replace = we.getBlock(player, args.getString(2)); + } else { + replace = new BaseBlock(0); + } + + int affected = editSession.moveCuboidRegion(session.getRegion(), + dir, count, true, replace); + player.print(affected + " blocks moved."); + } + + + @Command( + aliases = {"//stack"}, + usage = "[count] [direction] ", + desc = "Repeat the contents of the selection", + min = 0, + max = 2 + ) + @CommandPermissions({"worldedit.region.stack"}) + public static void stack(CommandContext args, WorldEdit we, + LocalSession session, LocalPlayer player, EditSession editSession) + throws WorldEditException { + + int count = args.argsLength() > 0 ? Math.max(1, args.getInteger(0)) : 1; + Vector dir = we.getDirection(player, + args.argsLength() > 1 ? args.getString(1).toLowerCase() : "me"); + + int affected = editSession.stackCuboidRegion(session.getRegion(), + dir, count, true); + player.print(affected + " blocks changed. Undo with //undo"); + } +} diff --git a/src/com/sk89q/worldedit/commands/ScriptingCommands.java b/src/com/sk89q/worldedit/commands/ScriptingCommands.java new file mode 100644 index 000000000..7f1b6ef0c --- /dev/null +++ b/src/com/sk89q/worldedit/commands/ScriptingCommands.java @@ -0,0 +1,78 @@ +// $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.commands; + +import com.sk89q.util.commands.Command; +import com.sk89q.util.commands.CommandContext; +import com.sk89q.worldedit.*; + +/** + * Scripting commands. + * + * @author sk89q + */ +public class ScriptingCommands { + @Command( + aliases = {"/cs"}, + usage = " [args...]", + desc = "Execute a CraftScript", + min = 1, + max = -1 + ) + @CommandPermissions({"worldedit.scripting.execute"}) + public static void execute(CommandContext args, WorldEdit we, + LocalSession session, LocalPlayer player, EditSession editSession) + throws WorldEditException { + // @TODO: Check for worldedit.scripting.execute.