From 2e31c2aaf0b5a1d2e41b43c448897d47fef01a10 Mon Sep 17 00:00:00 2001 From: sk89q Date: Wed, 29 Sep 2010 23:41:05 -0700 Subject: [PATCH] Updated WorldEdit for build 100; made regions no longer shared and fixed the missing authorization check. --- nbproject/project.properties | 5 +- src/IncompleteRegionException.java | 27 ++ src/InsufficientArgumentsException.java | 28 ++ src/UnknownItemException.java | 27 ++ src/WorldEdit.java | 342 ++++++++++++++---------- src/WorldEditSession.java | 103 +++++++ 6 files changed, 394 insertions(+), 138 deletions(-) create mode 100644 src/IncompleteRegionException.java create mode 100644 src/InsufficientArgumentsException.java create mode 100644 src/UnknownItemException.java create mode 100644 src/WorldEditSession.java diff --git a/nbproject/project.properties b/nbproject/project.properties index 70856562b..a68e37a09 100644 --- a/nbproject/project.properties +++ b/nbproject/project.properties @@ -19,13 +19,12 @@ dist.dir=dist dist.jar=${dist.dir}/WorldEdit.jar dist.javadoc.dir=${dist.dir}/javadoc excludes= -file.reference.Minecraft_Mod.jar=lib\\Minecraft_Mod.jar file.reference.minecraft_server.jar=lib\\minecraft_server.jar includes=** jar.compress=false javac.classpath=\ - ${file.reference.Minecraft_Mod.jar}:\ - ${file.reference.minecraft_server.jar} + ${file.reference.minecraft_server.jar}:\ + ${libs.Minecraft_Mod.classpath} # Space-separated list of extra javac options javac.compilerargs= javac.deprecation=false diff --git a/src/IncompleteRegionException.java b/src/IncompleteRegionException.java new file mode 100644 index 000000000..5e4aca8e1 --- /dev/null +++ b/src/IncompleteRegionException.java @@ -0,0 +1,27 @@ +// $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 . +*/ + +/** + * Raised when a region is not fully defined. + * + * @author Albert + */ +public class IncompleteRegionException extends Exception { + +} diff --git a/src/InsufficientArgumentsException.java b/src/InsufficientArgumentsException.java new file mode 100644 index 000000000..5ac3f330a --- /dev/null +++ b/src/InsufficientArgumentsException.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 . +*/ + +/** + * + * @author sk89q + */ +public class InsufficientArgumentsException extends Exception { + public InsufficientArgumentsException(String error) { + super(error); + } +} diff --git a/src/UnknownItemException.java b/src/UnknownItemException.java new file mode 100644 index 000000000..542aa8d78 --- /dev/null +++ b/src/UnknownItemException.java @@ -0,0 +1,27 @@ +// $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 . +*/ + +/** + * Thrown when no item exist by the ID. + * + * @author sk89q + */ +public class UnknownItemException extends Exception { + +} diff --git a/src/WorldEdit.java b/src/WorldEdit.java index 644895589..eb06089e1 100644 --- a/src/WorldEdit.java +++ b/src/WorldEdit.java @@ -17,26 +17,23 @@ * along with this program. If not, see . */ -import java.util.LinkedHashMap; +import java.util.HashMap; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.Map; -public class WorldEdit implements Plugin { - private int[] editPos1 = new int[3]; - private int[] editPos2 = new int[3]; - private String editPos1Owner = ""; - private String editPos2Owner = ""; - private net.minecraft.server.MinecraftServer server; +/** + * + * @author sk89q + */ +public class WorldEdit extends Plugin { + private static Logger logger = Logger.getLogger("Minecraft"); + private HashMap sessions = new HashMap(); + private HashMap commands = new HashMap(); - private boolean setBlock(int x, int y, int z, int blockType) { - return server.e.d(x, y, z, blockType); - } + public WorldEdit() { + super(); - private int getBlock(int x, int y, int z) { - return server.e.a(x, y, z); - } - - public void enable() { - server = etc.getMCServer(); - LinkedHashMap commands = etc.getInstance().commands; commands.put("/editpos1", "Set editing position #1"); commands.put("/editpos2", "Set editing position #2"); commands.put("/editsize", "Get size of selected region"); @@ -47,82 +44,226 @@ public class WorldEdit implements Plugin { commands.put("/editfill", " - Fill a hole"); } + /** + * Enables the plugin. + */ + public void enable() { + etc controller = etc.getInstance(); + + for (Map.Entry entry : commands.entrySet()) { + controller.addCommand(entry.getKey(), entry.getValue()); + } + } + + /** + * Disables the plugin. + */ public void disable() { + etc controller = etc.getInstance(); + + for (String key : commands.keySet()) { + controller.removeCommand(key); + } + + sessions.clear(); } - public boolean onLoginChecks(String user) { - throw new UnsupportedOperationException("Not implemented."); + /** + * Gets the WorldEdit session for a player. + * + * @param player + * @return + */ + private WorldEditSession getSession(Player player) { + if (sessions.containsKey(player.getName())) { + return sessions.get(player.getName()); + } else { + WorldEditSession session = new WorldEditSession(); + sessions.put(player.getName(), session); + return session; + } } - public void onLogin(Player player) { - throw new UnsupportedOperationException("Not implemented."); + /** + * Get an item ID from an item name or an item ID number. + * + * @param id + * @return + * @throws UnknownItemException + */ + private int getItem(String id) throws UnknownItemException { + try { + return Integer.parseInt(id); + } catch (NumberFormatException e) { + try { + return etc.getInstance().getDataSource().getItem(id); + } catch (NumberFormatException e2) { + throw new UnknownItemException(); + } + } } - public void onChat(Player player, String message) { - throw new UnsupportedOperationException("Not implemented."); + /** + * Sets the block at position x, y, z with a block type. + * + * @param x + * @param y + * @param z + * @param blockType + * @return + */ + private boolean setBlock(int x, int y, int z, int blockType) { + return etc.getMCServer().e.d(x, y, z, blockType); } + /** + * Gets the block type at a position x, y, z. + * + * @param x + * @param y + * @param z + * @return + */ + private int getBlock(int x, int y, int z) { + return etc.getMCServer().e.a(x, y, z); + } + + /** + * + * @override + * @param player + */ + public void onDisconnect(Player player) { + sessions.remove(player.getName()); + } + + /** + * + * @override + * @param player + * @param split + * @return + */ public boolean onCommand(Player player, String[] split) { try { - return handleEditCommand(player, split); + if (commands.containsKey(split[0])) { + if (etc.getInstance().canUseCommand(player.getName(), split[0])) { + return handleEditCommand(player, split); + } + } + + return false; } catch (NumberFormatException e) { player.sendMessage(Colors.Rose + "Number expected; string given."); return true; - } - } - - private boolean canDoEdit(Player player) { - if (!player.getName().equals(editPos1Owner)) { - player.sendMessage(Colors.Rose + "You don't own edit position #1. (Is someone else editing?)"); - } else if (!player.getName().equals(editPos2Owner)) { - player.sendMessage(Colors.Rose + "You don't own edit position #2. (Is someone else editing?)"); - } else { + } catch (IncompleteRegionException e2) { + player.sendMessage(Colors.Rose + "The edit region has not been fully defined."); + return true; + } catch (UnknownItemException e3) { + player.sendMessage(Colors.Rose + "Unknown item."); + return true; + } catch (InsufficientArgumentsException e4) { + player.sendMessage(Colors.Rose + e4.getMessage()); return true; } - return false; } - private boolean handleEditCommand(Player player, String[] split) { - int lowerX = Math.min(editPos1[0], editPos2[0]); - int upperX = Math.max(editPos1[0], editPos2[0]); - int lowerY = Math.min(editPos1[1], editPos2[1]); - int upperY = Math.max(editPos1[1], editPos2[1]); - int lowerZ = Math.min(editPos1[2], editPos2[2]); - int upperZ = Math.max(editPos1[2], editPos2[2]); + /** + * Checks to make sure that there are enough arguments. + * + * @param args + * @param min + * @throws InsufficientArgumentsException + */ + private void checkArgs(String[] args, int min) throws InsufficientArgumentsException { + if (args.length <= min) { + throw new InsufficientArgumentsException(String.format("Min. %d arguments required", min)); + } + } + + private boolean handleEditCommand(Player player, String[] split) + throws UnknownItemException, IncompleteRegionException, + InsufficientArgumentsException + { + WorldEditSession session = getSession(player); // Set edit position #1 if (split[0].equalsIgnoreCase("/editpos1")) { - editPos1Owner = player.getName(); - editPos1[0] = (int)Math.floor(player.getX()); - editPos1[1] = (int)Math.floor(player.getY()); - editPos1[2] = (int)Math.floor(player.getZ()); + session.setPos1((int)Math.floor(player.getX()), + (int)Math.floor(player.getY()), + (int)Math.floor(player.getZ())); player.sendMessage(Colors.LightPurple + "First edit position set."); return true; // Set edit position #2 } else if (split[0].equalsIgnoreCase("/editpos2")) { - editPos2Owner = player.getName(); - editPos2[0] = (int)Math.floor(player.getX()); - editPos2[1] = (int)Math.floor(player.getY()); - editPos2[2] = (int)Math.floor(player.getZ()); + session.setPos2((int)Math.floor(player.getX()), + (int)Math.floor(player.getY()), + (int)Math.floor(player.getZ())); player.sendMessage(Colors.LightPurple + "Second edit position set."); return true; + + // Fill a hole + } else if (split[0].equalsIgnoreCase("/editfill")) { + checkArgs(split, 1); + int blockType = getItem(split[1]); + int radius = split.length > 2 ? Integer.parseInt(split[2]) : 50; + int depth = split.length > 3 ? Integer.parseInt(split[3]) : 1; + + int cx = (int)Math.floor(player.getX()); + int cy = (int)Math.floor(player.getY()); + int cz = (int)Math.floor(player.getZ()); + int minY = Math.max(-128, cy - depth); + + int affected = fill(cx, cz, cx, cy, cz, blockType, radius, minY); + + logger.log(Level.INFO, player.getName() + " used /editfill"); + player.sendMessage(Colors.LightPurple + affected + " block(s) have been created."); + + return true; + + // Remove blocks above current position + } else if (split[0].equalsIgnoreCase("/removeabove")) { + int size = split.length > 1 ? Integer.parseInt(split[1]) - 1 : 0; + + int affected = 0; + int cx = (int)Math.floor(player.getX()); + int cy = (int)Math.floor(player.getY()); + int cz = (int)Math.floor(player.getZ()); + + for (int x = cx - size; x <= cx + size; x++) { + for (int z = cz - size; z <= cz + size; z++) { + for (int y = cy; y <= 127; y++) { + if (getBlock(x, y, z) != 0) { + setBlock(x, y, z, 0); + affected++; + } + } + } + } + + logger.log(Level.INFO, player.getName() + " used /removeabove"); + player.sendMessage(Colors.LightPurple + affected + " block(s) have been removed."); + + return true; + } + + int lowerX = session.getLowerX(); + int upperX = session.getUpperX(); + int lowerY = session.getLowerY(); + int upperY = session.getUpperY(); + int lowerZ = session.getLowerZ(); + int upperZ = session.getUpperZ(); // Get size of area - } else if (split[0].equalsIgnoreCase("/editsize")) { - if (!canDoEdit(player)) return true; - int size = (upperX - lowerX + 1) * (upperY - lowerY + 1) * (upperZ - lowerZ + 1); - player.sendMessage(Colors.LightPurple + "# of blocks: " + size); + if (split[0].equalsIgnoreCase("/editsize")) { + player.sendMessage(Colors.LightPurple + "# of blocks: " + getSession(player).getSize()); return true; // Replace all blocks in the region } else if(split[0].equalsIgnoreCase("/editset")) { - if (!canDoEdit(player)) return true; - int blockType = 0; - if (split.length > 1) { - blockType = Integer.parseInt(split[1]); - } - + checkArgs(split, 1); + int blockType = getItem(split[1]); int affected = 0; for (int x = lowerX; x <= upperX; x++) { @@ -134,17 +275,15 @@ public class WorldEdit implements Plugin { } } + logger.log(Level.INFO, player.getName() + " used /editset"); player.sendMessage(Colors.LightPurple + affected + " block(s) have been set."); return true; // Replace all blocks in the region } else if(split[0].equalsIgnoreCase("/editreplace")) { - if (!canDoEdit(player)) return true; - int blockType = 0; - if (split.length > 1) { - blockType = Integer.parseInt(split[1]); - } + checkArgs(split, 1); + int blockType = getItem(split[1]); int affected = 0; @@ -159,17 +298,15 @@ public class WorldEdit implements Plugin { } } + logger.log(Level.INFO, player.getName() + " used /editreplace"); player.sendMessage(Colors.LightPurple + affected + " block(s) have been replaced."); return true; // Lay blocks over an area } else if (split[0].equalsIgnoreCase("/editoverlay")) { - if (!canDoEdit(player)) return true; - int blockType = 1; - if (split.length > 1) { - blockType = Integer.parseInt(split[1]); - } + checkArgs(split, 1); + int blockType = getItem(split[1]); // We don't want to pass beyond boundaries upperY = Math.min(127, upperY + 1); @@ -189,62 +326,9 @@ public class WorldEdit implements Plugin { } } + logger.log(Level.INFO, player.getName() + " used /editoverlay"); player.sendMessage(Colors.LightPurple + affected + " block(s) have been overlayed."); - return true; - - // Fill a hole - } else if (split[0].equalsIgnoreCase("/editfill")) { - int blockType = 1; - int radius = 10; - int depth = 1; - - if (split.length > 1) { - blockType = Integer.parseInt(split[1]); - } - if (split.length > 2) { - radius = Integer.parseInt(split[2]); - } - if (split.length > 3) { - depth = Integer.parseInt(split[3]); - } - - int cx = (int)Math.floor(player.getX()); - int cy = (int)Math.floor(player.getY()); - int cz = (int)Math.floor(player.getZ()); - int minY = Math.max(-128, cy - depth); - - int affected = fill(cx, cz, cx, cy, cz, blockType, radius, minY); - - player.sendMessage(Colors.LightPurple + affected + " block(s) have been set."); - - return true; - - // Remove blocks above current position - } else if (split[0].equalsIgnoreCase("/removeabove")) { - int size = 0; - if (split.length > 1) { - size = Integer.parseInt(split[1]) - 1; - } - - int affected = 0; - int cx = (int)Math.floor(player.getX()); - int cy = (int)Math.floor(player.getY()); - int cz = (int)Math.floor(player.getZ()); - - for (int x = cx - size; x <= cx + size; x++) { - for (int z = cz - size; z <= cz + size; z++) { - for (int y = cy; y <= 127; y++) { - if (getBlock(x, y, z) != 0) { - setBlock(x, y, z, 0); - affected++; - } - } - } - } - - player.sendMessage(Colors.LightPurple + affected + " block(s) have been removed."); - return true; } @@ -287,16 +371,4 @@ public class WorldEdit implements Plugin { return affected; } - - public void onBan(Player player, String reason) { - throw new UnsupportedOperationException("Not implemented."); - } - - public void onIpBan(Player player, String reason) { - throw new UnsupportedOperationException("Not implemented."); - } - - public void onKick(Player player, String reason) { - throw new UnsupportedOperationException("Not implemented."); - } } diff --git a/src/WorldEditSession.java b/src/WorldEditSession.java new file mode 100644 index 000000000..c04570992 --- /dev/null +++ b/src/WorldEditSession.java @@ -0,0 +1,103 @@ +// $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 . +*/ + +/** + * + * @author sk89q + */ +public class WorldEditSession { + private int[] pos1 = new int[3]; + private int[] pos2 = new int[3]; + private boolean hasSetPos1 = false; + private boolean hasSetPos2 = false; + + private void checkPos1() throws IncompleteRegionException { + if (!hasSetPos1) { + throw new IncompleteRegionException(); + } + } + + private void checkPos2() throws IncompleteRegionException { + if (!hasSetPos2) { + throw new IncompleteRegionException(); + } + } + + public int[] getPos1() throws IncompleteRegionException { + checkPos1(); + return pos1; + } + + public void setPos1(int x, int y, int z) { + hasSetPos1 = true; + pos1 = new int[]{x, y, z}; + } + + public int[] getPos2() throws IncompleteRegionException { + checkPos2(); + return pos2; + } + + public void setPos2(int x, int y, int z) { + hasSetPos2 = true; + pos2 = new int[]{x, y, z}; + } + + public int getLowerX() throws IncompleteRegionException { + checkPos1(); + checkPos2(); + return Math.min(pos1[0], pos2[0]); + } + + public int getUpperX() throws IncompleteRegionException { + checkPos1(); + checkPos2(); + return Math.max(pos1[0], pos2[0]); + } + + public int getLowerY() throws IncompleteRegionException { + checkPos1(); + checkPos2(); + return Math.min(pos1[1], pos2[1]); + } + + public int getUpperY() throws IncompleteRegionException { + checkPos1(); + checkPos2(); + return Math.max(pos1[1], pos2[1]); + } + + public int getLowerZ() throws IncompleteRegionException { + checkPos1(); + checkPos2(); + return Math.min(pos1[2], pos2[2]); + } + + public int getUpperZ() throws IncompleteRegionException { + checkPos1(); + checkPos2(); + return Math.max(pos1[2], pos2[2]); + } + + public int getSize() throws IncompleteRegionException { + return (getUpperX() - getLowerX() + 1) * + (getUpperY() - getLowerY() + 1) * + (getUpperZ() - getLowerZ() + 1); + } +}