diff --git a/src/RegionClipboard.java b/src/CuboidClipboard.java similarity index 83% rename from src/RegionClipboard.java rename to src/CuboidClipboard.java index da85eb60b..df9c3c24d 100644 --- a/src/RegionClipboard.java +++ b/src/CuboidClipboard.java @@ -28,11 +28,11 @@ import com.sk89q.worldedit.*; * * @author Albert */ -public class RegionClipboard { +public class CuboidClipboard { private int[][][] data; - private Point min; - private Point max; - private Point origin; + private Point min; + private Point max; + private Point origin; /** * Constructs the region instance. The minimum and maximum points must be @@ -42,13 +42,13 @@ public class RegionClipboard { * @param max * @param origin */ - public RegionClipboard(Point min, Point max, Point origin) { + public CuboidClipboard(Point min, Point max, Point origin) { this.min = min; this.max = max; this.origin = origin; - data = new int[(max.getX()) - min.getX() + 1] - [max.getY() - min.getY() + 1] - [max.getZ() - min.getZ() + 1]; + data = new int[(int)((max.getX()) - min.getX() + 1)] + [(int)(max.getY() - min.getY() + 1)] + [(int)(max.getZ() - min.getZ() + 1)]; } /** @@ -57,7 +57,7 @@ public class RegionClipboard { * @return */ public int getWidth() { - return max.getX() - min.getX() + 1; + return (int)(max.getX() - min.getX() + 1); } /** @@ -66,7 +66,7 @@ public class RegionClipboard { * @return */ public int getLength() { - return max.getZ() - min.getZ() + 1; + return (int)(max.getZ() - min.getZ() + 1); } /** @@ -75,7 +75,7 @@ public class RegionClipboard { * @return */ public int getHeight() { - return max.getY() - min.getY() + 1; + return (int)(max.getY() - min.getY() + 1); } /** @@ -84,10 +84,10 @@ public class RegionClipboard { * @param editSession */ public void copy(EditSession editSession) { - for (int x = min.getX(); x <= max.getX(); x++) { - for (int y = min.getY(); y <= max.getY(); y++) { - for (int z = min.getZ(); z <= max.getZ(); z++) { - data[x - min.getX()][y - min.getY()][z - min.getZ()] = + for (int x = (int)min.getX(); x <= (int)max.getX(); x++) { + for (int y = (int)min.getY(); y <= (int)max.getY(); y++) { + for (int z = (int)min.getZ(); z <= (int)max.getZ(); z++) { + data[x - (int)min.getX()][y - (int)min.getY()][z - (int)min.getZ()] = editSession.getBlock(x, y, z); } } @@ -102,11 +102,11 @@ public class RegionClipboard { * @param noAir True to not paste air * @throws MaxChangedBlocksException */ - public void paste(EditSession editSession, Point newOrigin, boolean noAir) + public void paste(EditSession editSession, Point newOrigin, boolean noAir) throws MaxChangedBlocksException { - int offsetX = min.getX() - origin.getX() + newOrigin.getX(); - int offsetY = min.getY() - origin.getY() + newOrigin.getY(); - int offsetZ = min.getZ() - origin.getZ() + newOrigin.getZ(); + int offsetX = (int)(min.getX() - origin.getX() + newOrigin.getX()); + int offsetY = (int)(min.getY() - origin.getY() + newOrigin.getY()); + int offsetZ = (int)(min.getZ() - origin.getZ() + newOrigin.getZ()); place(editSession, offsetX, offsetY, offsetZ, noAir); } @@ -158,9 +158,9 @@ public class RegionClipboard { int xs = getWidth(); int ys = getHeight(); int zs = getLength(); - int offsetX = min.getX(); - int offsetY = min.getY(); - int offsetZ = min.getZ(); + int offsetX = (int)min.getX(); + int offsetY = (int)min.getY(); + int offsetZ = (int)min.getZ(); for (short i = 1; i <= count; i++) { place(editSession, offsetX + xm * xs, offsetY + ym * ys, @@ -168,9 +168,9 @@ public class RegionClipboard { } if (moveOrigin) { - min = new Point(offsetX + xm * count, - offsetY + ym * count, - offsetZ + zm * count); + min = new Point((int)offsetX + xm * count, + (int)offsetY + ym * count, + (int)offsetZ + zm * count); } } @@ -238,7 +238,7 @@ public class RegionClipboard { * @throws SchematicException * @throws IOException */ - public static RegionClipboard loadSchematic(String path, Point origin) + public static CuboidClipboard loadSchematic(String path, Point origin) throws SchematicException, IOException { FileInputStream stream = new FileInputStream(path); NBTInputStream nbtStream = new NBTInputStream(stream); @@ -259,17 +259,13 @@ public class RegionClipboard { } byte[] blocks = (byte[])getChildTag(schematic, "Blocks", ByteArrayTag.class).getValue(); - Point min = new Point( - origin.getX(), - origin.getY(), - origin.getZ() - ); - Point max = new Point( + Point min = origin; + Point max = new Point( origin.getX() + xs - 1, origin.getY() + ys - 1, origin.getZ() + zs - 1 ); - RegionClipboard clipboard = new RegionClipboard(min, max, origin); + CuboidClipboard clipboard = new CuboidClipboard(min, max, origin); for (int x = 0; x < xs; x++) { for (int y = 0; y < ys; y++) { diff --git a/src/EditSession.java b/src/EditSession.java index bf6d56b0c..6d11c4ddf 100644 --- a/src/EditSession.java +++ b/src/EditSession.java @@ -36,15 +36,15 @@ public class EditSession { /** * Stores the original blocks before modification. */ - private HashMap,Integer> original = new HashMap,Integer>(); + private HashMap original = new HashMap(); /** * Stores the current blocks. */ - private HashMap,Integer> current = new HashMap,Integer>(); + private HashMap current = new HashMap(); /** * Queue. */ - private HashMap,Integer> queue = new HashMap,Integer>(); + private HashMap queue = new HashMap(); /** * The maximum number of blocks to change at a time. If this number is * exceeded, a MaxChangedBlocksException exception will be @@ -59,7 +59,7 @@ public class EditSession { /** * List of object types to queue. */ - private static HashSet queuedBlocks = new HashSet(); + private static final HashSet queuedBlocks = new HashSet(); static { queuedBlocks.add(50); // Torch @@ -93,14 +93,13 @@ public class EditSession { /** * Sets a block without changing history. * - * @param x - * @param y - * @param z + * @param pt * @param blockType * @return Whether the block changed */ - private boolean rawSetBlock(int x, int y, int z, int blockType) { - return etc.getMCServer().e.d(x, y, z, blockType); + private boolean rawSetBlock(Point pt, int blockType) { + return etc.getMCServer().e.d(pt.getBlockX(), pt.getBlockY(), + pt.getBlockZ(), blockType); } /** @@ -116,45 +115,70 @@ public class EditSession { */ public boolean setBlock(int x, int y, int z, int blockType) throws MaxChangedBlocksException { - Point pt = new Point(x, y, z); - + return setBlock(new Point(x, y, z), blockType); + } + + /** + * Sets the block at position x, y, z with a block type. If queue mode is + * enabled, blocks may not be actually set in world until flushQueue() + * is called. + * + * @param pt + * @param blockType + * @return Whether the block changed -- not entirely dependable + */ + public boolean setBlock(Point pt, int blockType) + throws MaxChangedBlocksException { if (!original.containsKey(pt)) { - original.put(pt, getBlock(x, y, z)); + original.put(pt, getBlock(pt)); if (maxBlocks != -1 && original.size() > maxBlocks) { throw new MaxChangedBlocksException(maxBlocks); } } - + current.put(pt, blockType); - - return smartSetBlock(x, y, z, blockType); + + return smartSetBlock(pt, blockType); } /** * Actually set the block. Will use queue. * - * @param x - * @param y - * @param z + * @param pt * @param blockType * @return */ - private boolean smartSetBlock(int x, int y, int z, int blockType) { - Point pt = new Point(x, y, z); - + private boolean smartSetBlock(Point pt, int blockType) { if (queued) { if (blockType != 0 && queuedBlocks.contains(blockType) - && rawGetBlock(x, y - 1, z) == 0) { + && rawGetBlock(pt.add(0, -1, 0)) == 0) { queue.put(pt, blockType); - return getBlock(x, y, z) != blockType; + return getBlock(pt) != blockType; } else if (blockType == 0 - && queuedBlocks.contains(rawGetBlock(x, y + 1, z))) { - rawSetBlock(x, y + 1, z, 0); // Prevent items from being dropped + && queuedBlocks.contains(rawGetBlock(pt.add(0, 1, 0)))) { + rawSetBlock(pt.add(0, 1, 0), 0); // Prevent items from being dropped } } - return rawSetBlock(x, y, z, blockType); + return rawSetBlock(pt, blockType); + } + + /** + * Gets the block type at a position x, y, z. + * + * @param pt + * @return Block type + */ + public int getBlock(Point pt) { + // In the case of the queue, the block may have not actually been + // changed yet + if (queued) { + if (current.containsKey(pt)) { + return current.get(pt); + } + } + return etc.getMCServer().e.a(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); } /** @@ -166,37 +190,26 @@ public class EditSession { * @return Block type */ public int getBlock(int x, int y, int z) { - // In the case of the queue, the block may have not actually been - // changed yet - if (queued) { - Point pt = new Point(x, y, z); - if (current.containsKey(pt)) { - return current.get(pt); - } - } - return etc.getMCServer().e.a(x, y, z); + return getBlock(new Point(x, y, z)); } /** * Gets the block type at a position x, y, z. * - * @param x - * @param y - * @param z + * @param pt * @return Block type */ - public int rawGetBlock(int x, int y, int z) { - return etc.getMCServer().e.a(x, y, z); + public int rawGetBlock(Point pt) { + return etc.getMCServer().e.a(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); } /** * Restores all blocks to their initial state. */ public void undo() { - for (Map.Entry,Integer> entry : original.entrySet()) { + for (Map.Entry entry : original.entrySet()) { Point pt = (Point)entry.getKey(); - smartSetBlock((Integer)pt.getX(), (Integer)pt.getY(),(Integer)pt.getZ(), - (int)entry.getValue()); + smartSetBlock(pt, (int)entry.getValue()); } flushQueue(); } @@ -205,10 +218,9 @@ public class EditSession { * Sets to new state. */ public void redo() { - for (Map.Entry,Integer> entry : current.entrySet()) { + for (Map.Entry entry : current.entrySet()) { Point pt = (Point)entry.getKey(); - smartSetBlock((Integer)pt.getX(), (Integer)pt.getY(),(Integer)pt.getZ(), - (int)entry.getValue()); + smartSetBlock(pt, (int)entry.getValue()); } flushQueue(); } @@ -275,10 +287,328 @@ public class EditSession { public void flushQueue() { if (!queued) { return; } - for (Map.Entry,Integer> entry : queue.entrySet()) { + for (Map.Entry entry : queue.entrySet()) { Point pt = (Point)entry.getKey(); - rawSetBlock((Integer)pt.getX(), (Integer)pt.getY(),(Integer)pt.getZ(), - (int)entry.getValue()); + rawSetBlock(pt, (int)entry.getValue()); } } + + /** + * Fills an area recursively in the X/Z directions. + * + * @param x + * @param z + * @param origin + * @param blockType + * @param radius + * @param depth + * @return + */ + public int fillXZ(int x, int z, Point origin, int blockType, int radius, int depth) + throws MaxChangedBlocksException { + double dist = Math.sqrt(Math.pow(origin.getX() - x, 2) + Math.pow(origin.getZ() - z, 2)); + int minY = origin.getBlockY() - depth + 1; + int affected = 0; + + if (dist > radius) { + return 0; + } + + if (getBlock(new Point(x, origin.getY(), z)) == 0) { + affected = fillY(x, (int)origin.getY(), z, blockType, minY); + } else { + return 0; + } + + affected += fillXZ(x + 1, z, origin, blockType, radius, depth); + affected += fillXZ(x - 1, z, origin, blockType, radius, depth); + affected += fillXZ(x, z + 1, origin, blockType, radius, depth); + affected += fillXZ(x, z - 1, origin, blockType, radius, depth); + + return affected; + } + + /** + * Recursively fills a block and below until it hits another block. + * + * @param x + * @param cy + * @param z + * @param blockType + * @param minY + * @throws MaxChangedBlocksException + * @return + */ + private int fillY(int x, int cy, int z, int blockType, int minY) + throws MaxChangedBlocksException { + int affected = 0; + + for (int y = cy; y >= minY; y--) { + Point pt = new Point(x, y, z); + + if (getBlock(pt) == 0) { + setBlock(pt, blockType); + affected++; + } else { + break; + } + } + + return affected; + } + + /** + * Remove blocks above. + * + * @param pos + * @param size, + * @param height + * @return + */ + public int removeAbove(Point pos, int size, int height) throws + MaxChangedBlocksException { + int maxY = Math.min(127, pos.getBlockY() + height - 1); + size--; + int affected = 0; + + for (int x = (int)pos.getX() - size; x <= (int)pos.getX() + size; x++) { + for (int z = (int)pos.getZ() - size; z <= (int)pos.getZ() + size; z++) { + for (int y = (int)pos.getY(); y <= maxY; y++) { + Point pt = new Point(x, y, z); + + if (getBlock(pt) != 0) { + setBlock(pt, 0); + affected++; + } + } + } + } + + return affected; + } + + /** + * Remove blocks below. + * + * @param pos + * @param size, + * @param height + * @return + */ + public int removeBelow(Point pos, int size, int height) throws + MaxChangedBlocksException { + int minY = Math.max(0, pos.getBlockY() - height); + size--; + int affected = 0; + + for (int x = (int)pos.getX() - size; x <= (int)pos.getX() + size; x++) { + for (int z = (int)pos.getZ() - size; z <= (int)pos.getZ() + size; z++) { + for (int y = (int)pos.getY(); y >= minY; y--) { + Point pt = new Point(x, y, z); + + if (getBlock(pt) != 0) { + setBlock(pt, 0); + affected++; + } + } + } + } + + return affected; + } + + /** + * Sets all the blocks inside a region to a certain block type. + * + * @param region + * @param blockType + * @return + * @throws MaxChangedBlocksException + */ + public int setBlocks(Region region, int blockType) + throws MaxChangedBlocksException { + int affected = 0; + + if (region instanceof CuboidRegion) { + // Doing this for speed + Point min = region.getMinimumPoint(); + Point max = region.getMaximumPoint(); + + for (int x = min.getBlockX(); x <= max.getBlockX(); x++) { + for (int y = min.getBlockY(); y <= max.getBlockY(); y++) { + for (int z = min.getBlockZ(); z <= max.getBlockZ(); z++) { + Point pt = new Point(x, y, z); + + if (setBlock(pt, blockType)) { + affected++; + } + } + } + } + } else { + for (Point pt : region) { + if (setBlock(pt, blockType)) { + affected++; + } + } + } + + return affected; + } + + /** + * Replaces all the blocks of a type inside a region to another block type. + * + * @param region + * @param fromBlockType -1 for non-air + * @param toBlockType + * @return + * @throws MaxChangedBlocksException + */ + public int replaceBlocks(Region region, int fromBlockType, int toBlockType) + throws MaxChangedBlocksException { + int affected = 0; + + if (region instanceof CuboidRegion) { + // Doing this for speed + Point min = region.getMinimumPoint(); + Point max = region.getMaximumPoint(); + + for (int x = min.getBlockX(); x <= max.getBlockX(); x++) { + for (int y = min.getBlockY(); y <= max.getBlockY(); y++) { + for (int z = min.getBlockZ(); z <= max.getBlockZ(); z++) { + Point pt = new Point(x, y, z); + int curBlockType = getBlock(pt); + + if (fromBlockType == -1 && curBlockType != 0 || + curBlockType == fromBlockType) { + if (setBlock(pt, toBlockType)) { + affected++; + } + } + } + } + } + } else { + for (Point pt : region) { + int curBlockType = getBlock(pt); + + if (fromBlockType == -1 && curBlockType != 0 || + curBlockType == fromBlockType) { + if (setBlock(pt, toBlockType)) { + affected++; + } + } + } + } + + return affected; + } + + /** + * Make faces of the region (as if it was a cuboid if it's not). + * + * @param region + * @param blockType + * @return + * @throws MaxChangedBlocksException + */ + public int makeCuboidFaces(Region region, int blockType) + throws MaxChangedBlocksException { + int affected = 0; + + Point min = region.getMinimumPoint(); + Point max = region.getMaximumPoint(); + + for (int x = min.getBlockX(); x <= max.getBlockX(); x++) { + for (int y = min.getBlockY(); y <= max.getBlockY(); y++) { + if (setBlock(x, y, min.getBlockZ(), blockType)) { affected++; } + if (setBlock(x, y, max.getBlockZ(), blockType)) { affected++; } + affected++; + } + } + + for (int y = min.getBlockY(); y <= max.getBlockY(); y++) { + for (int z = min.getBlockZ(); z <= max.getBlockZ(); z++) { + if (setBlock(min.getBlockX(), y, z, blockType)) { affected++; } + if (setBlock(max.getBlockX(), y, z, blockType)) { affected++; } + } + } + + for (int z = min.getBlockZ(); z <= max.getBlockZ(); z++) { + for (int x = min.getBlockX(); x <= max.getBlockX(); x++) { + if (setBlock(x, min.getBlockY(), z, blockType)) { affected++; } + if (setBlock(x, max.getBlockY(), z, blockType)) { affected++; } + } + } + + return affected; + } + + /** + * Overlays a layer of blocks over a cuboid area. + * + * @param region + * @param upperY + * @param lowerY + * @param blockType + * @return + * @throws MaxChangedBlocksException + */ + public int overlayCuboidBlocks(Region region, int blockType) + throws MaxChangedBlocksException { + Point min = region.getMinimumPoint(); + Point max = region.getMaximumPoint(); + + int upperY = Math.min(127, max.getBlockY() + 1); + int lowerY = Math.max(0, min.getBlockY()- 1); + + int affected = 0; + + for (int x = min.getBlockX(); x <= max.getBlockX(); x++) { + for (int z = min.getBlockZ(); z <= max.getBlockZ(); z++) { + for (int y = upperY; y >= lowerY; y--) { + if (y + 1 <= 127 && getBlock(x, y, z) != 0 && getBlock(x, y + 1, z) == 0) { + if (setBlock(x, y + 1, z, blockType)) { + affected++; + } + break; + } + } + } + } + + return affected; + } + + public int stackCuboidRegion(Region region, int xm, int ym, int zm, + int count, boolean copyAir) + throws MaxChangedBlocksException { + int affected = 0; + + Point min = region.getMinimumPoint(); + Point max = region.getMaximumPoint(); + int xs = region.getWidth(); + int ys = region.getHeight(); + int zs = region.getLength(); + + for (int x = min.getBlockX(); x <= max.getBlockX(); x++) { + for (int z = min.getBlockZ(); z <= max.getBlockZ(); z++) { + for (int y = min.getBlockY(); y <= max.getBlockY(); y++) { + int blockType = getBlock(new Point(x, y, z)); + + if (blockType != 0 || copyAir) { + for (int i = 1; i <= count; i++) { + if (setBlock(x + xs * xm * i, y + ys * ym * i, + z + zs * zm * i, blockType)) { + affected++; + } + } + } + } + } + } + + return affected; + } } diff --git a/src/ScriptPlayer.java b/src/ScriptPlayer.java index 67c67b600..2937a5142 100644 --- a/src/ScriptPlayer.java +++ b/src/ScriptPlayer.java @@ -17,12 +17,14 @@ * along with this program. If not, see . */ +import com.sk89q.worldedit.Point; + /** * - * @author Albert + * @author sk89q */ public class ScriptPlayer { - private Player player; + private WorldEditPlayer player; public String name; public double pitch; @@ -39,17 +41,18 @@ public class ScriptPlayer { * * @param player */ - public ScriptPlayer(Player player) { + public ScriptPlayer(WorldEditPlayer player) { this.player = player; name = player.getName(); pitch = player.getPitch(); - yaw = player.getRotation(); - x = player.getX(); - y = player.getY(); - z = player.getZ(); - blockX = (int)Math.floor(player.getX()); - blockY = (int)Math.floor(player.getY()); - blockZ = (int)Math.floor(player.getZ()); + yaw = player.getYaw(); + Point pos = player.getPosition(); + x = pos.getX(); + y = pos.getY(); + z = pos.getZ(); + blockX = pos.getBlockX(); + blockY = pos.getBlockY(); + blockZ = pos.getBlockZ(); } /** @@ -58,7 +61,7 @@ public class ScriptPlayer { * @param msg */ public void print(String msg) { - player.sendMessage(msg); + player.print(msg); } /** @@ -67,42 +70,6 @@ public class ScriptPlayer { * @param msg */ public void error(String msg) { - player.sendMessage(Colors.Rose + msg); - } - - /** - * Teleport the player to a position. - * - * @param x - * @param y - * @param z - */ - public void teleporTo(double x, double y, double z) { - Location loc = new Location(); - loc.x = x; - loc.y = y; - loc.z = z; - loc.rotX = player.getRotation(); - loc.rotY = player.getPitch(); - player.teleportTo(loc); - } - - /** - * Teleport the player to a position with a certain rotation. - * - * @param x - * @param y - * @param z - * @param pitch - * @param yaw - */ - public void teleporTo(double x, double y, double z, float pitch, float yaw) { - Location loc = new Location(); - loc.x = x; - loc.y = y; - loc.z = z; - loc.rotX = yaw; - loc.rotY = pitch; - player.teleportTo(loc); + player.printError(msg); } } diff --git a/src/WorldEdit.java b/src/WorldEdit.java index b1b3afee0..c03c7a7f1 100644 --- a/src/WorldEdit.java +++ b/src/WorldEdit.java @@ -36,7 +36,8 @@ public class WorldEdit extends Plugin { "44,45,47,48,49,52,53,54,56,57,58,60,61,62,67,73,78,79,80,81,82,85"; private static final Logger logger = Logger.getLogger("Minecraft"); - private HashMap sessions = new HashMap(); + private HashMap sessions = + new HashMap(); private HashMap commands = new HashMap(); private PropertiesFile properties; @@ -74,7 +75,7 @@ public class WorldEdit extends Plugin { commands.put("/editfill", "[ID] [Radius] - Fill a hole"); commands.put("/editscript", "[Filename] - Run a WorldEdit script"); commands.put("/editlimit", "[Num] - See documentation"); - commands.put("/lift", "Go up to the first free spot"); + commands.put("/unstuck", "Go up to the first free spot"); } /** @@ -83,13 +84,13 @@ public class WorldEdit extends Plugin { * @param player * @return */ - private WorldEditSession getSession(Player player) { - if (sessions.containsKey(player.getName())) { - return sessions.get(player.getName()); + private WorldEditSession getSession(WorldEditPlayer player) { + if (sessions.containsKey(player)) { + return sessions.get(player); } else { WorldEditSession session = new WorldEditSession(); session.setBlockChangeLimit(defaultMaxBlocksChanged); - sessions.put(player.getName(), session); + sessions.put(player, session); return session; } } @@ -218,29 +219,28 @@ public class WorldEdit extends Plugin { * @return false if you want the action to go through */ @Override - public boolean onBlockCreate(Player player, Block blockPlaced, + public boolean onBlockCreate(Player modPlayer, Block blockPlaced, Block blockClicked, int itemInHand) { if (itemInHand == 271) { // Wooden axe - if (!player.canUseCommand("/editpos1") - || !player.canUseCommand("/editpos2")) { + if (!modPlayer.canUseCommand("/editpos1") + || !modPlayer.canUseCommand("/editpos2")) { return false; } - + + WorldEditPlayer player = new WorldEditPlayer(modPlayer); WorldEditSession session = getSession(player); - int x = (int)Math.floor(blockClicked.getX()); - int y = (int)Math.floor(blockClicked.getY()); - int z = (int)Math.floor(blockClicked.getZ()); - if (session.isToolControlEnabled()) { + Point cur = Point.toBlockPoint(blockClicked.getX(), + blockClicked.getY(), + blockClicked.getZ()); + try { if (session.hasToolBeenDoubleClicked() - && x == session.getPos1()[0] - && y == session.getPos1()[1] - && z == session.getPos1()[2]) { // Pos 2 - session.setPos2(x, y, z); + && cur.equals(session.getPos1())) { // Pos 2 + session.setPos2(cur); session.setPos1(session.getLastToolPos1()); - player.sendMessage(Colors.LightPurple + "Second edit position set; first one restored."); + player.print("Second edit position set; first one restored."); } else { // Have to remember the original position because on // double click, we are going to restore it @@ -248,8 +248,8 @@ public class WorldEdit extends Plugin { session.setLastToolPos1(session.getPos1()); } catch (IncompleteRegionException e) {} - session.setPos1(x, y, z); - player.sendMessage(Colors.LightPurple + "First edit position set."); + session.setPos1(cur); + player.print("First edit position set."); } } catch (IncompleteRegionException e) {} @@ -269,10 +269,11 @@ public class WorldEdit extends Plugin { * @return */ @Override - public boolean onCommand(Player player, String[] split) { - try { + public boolean onCommand(Player modPlayer, String[] split) { + try { if (commands.containsKey(split[0])) { - if (player.canUseCommand(split[0])) { + if (modPlayer.canUseCommand(split[0])) { + WorldEditPlayer player = new WorldEditPlayer(modPlayer); WorldEditSession session = getSession(player); EditSession editSession = new EditSession(session.getBlockChangeLimit()); @@ -287,7 +288,8 @@ public class WorldEdit extends Plugin { } } else { // See if there is a script by the same name - if (mapScriptCommands && player.canUseCommand("/editscript")) { + if (mapScriptCommands && modPlayer.canUseCommand("/editscript")) { + WorldEditPlayer player = new WorldEditPlayer(modPlayer); WorldEditSession session = getSession(player); EditSession editSession = new EditSession(session.getBlockChangeLimit()); @@ -310,20 +312,20 @@ public class WorldEdit extends Plugin { return false; } catch (NumberFormatException e) { - player.sendMessage(Colors.Rose + "Number expected; string given."); + modPlayer.sendMessage(Colors.Rose + "Number expected; string given."); } catch (IncompleteRegionException e2) { - player.sendMessage(Colors.Rose + "The edit region has not been fully defined."); + modPlayer.sendMessage(Colors.Rose + "The edit region has not been fully defined."); } catch (UnknownItemException e3) { - player.sendMessage(Colors.Rose + "Unknown item."); + modPlayer.sendMessage(Colors.Rose + "Unknown item."); } catch (DisallowedItemException e4) { - player.sendMessage(Colors.Rose + "Disallowed item."); + modPlayer.sendMessage(Colors.Rose + "Disallowed item."); } catch (MaxChangedBlocksException e5) { - player.sendMessage(Colors.Rose + "The maximum number of blocks changed (" + modPlayer.sendMessage(Colors.Rose + "The maximum number of blocks changed (" + e5.getBlockLimit() + ") in an instance was reached."); } catch (InsufficientArgumentsException e6) { - player.sendMessage(Colors.Rose + e6.getMessage()); + modPlayer.sendMessage(Colors.Rose + e6.getMessage()); } catch (WorldEditException e7) { - player.sendMessage(Colors.Rose + e7.getMessage()); + modPlayer.sendMessage(Colors.Rose + e7.getMessage()); } return true; @@ -333,6 +335,7 @@ public class WorldEdit extends Plugin { * The main meat of command processing. * * @param player + * @param editPlayer * @param session * @param editSession * @param split @@ -342,204 +345,132 @@ public class WorldEdit extends Plugin { * @throws InsufficientArgumentsException * @throws DisallowedItemException */ - private boolean performCommand(Player player, WorldEditSession session, - EditSession editSession, String[] split) + private boolean performCommand(WorldEditPlayer player, + WorldEditSession session, EditSession editSession, String[] split) throws WorldEditException { // Jump to the first free position - if (split[0].equalsIgnoreCase("/lift")) { - player.sendMessage(Colors.LightPurple + "There you go!"); - teleportToStandPosition(player); + if (split[0].equalsIgnoreCase("/unstuck")) { + checkArgs(split, 0, 0, split[0]); + player.print("There you go!"); + player.findFreePosition(); return true; // Set edit position #1 } else if (split[0].equalsIgnoreCase("/editpos1")) { - 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."); + checkArgs(split, 0, 0, split[0]); + session.setPos1(player.getBlockIn()); + player.print("First edit position set."); return true; // Set edit position #2 } else if (split[0].equalsIgnoreCase("/editpos2")) { - 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."); + checkArgs(split, 0, 0, split[0]); + session.setPos2(player.getBlockIn()); + player.print("Second edit position set."); return true; // Edit wand } else if (split[0].equalsIgnoreCase("/editwand")) { + checkArgs(split, 0, 0, split[0]); player.giveItem(271, 1); - player.sendMessage(Colors.LightPurple + "Right click = sel. pos 1; double right click = sel. pos 2"); + player.print("Right click = sel. pos 1; double right click = sel. pos 2"); return true; // Set max number of blocks to change at a time } else if (split[0].equalsIgnoreCase("/editlimit")) { - checkArgs(split, 1, 1, "/editlimit"); + checkArgs(split, 1, 1, split[0]); int limit = Math.max(-1, Integer.parseInt(split[1])); session.setBlockChangeLimit(limit); - player.sendMessage(Colors.LightPurple + "Block change limit set to " - + limit + "."); + player.print("Block change limit set to " + limit + "."); return true; // Undo } else if (split[0].equalsIgnoreCase("/editundo")) { + checkArgs(split, 0, 0, split[0]); if (session.undo()) { - player.sendMessage(Colors.LightPurple + "Undo successful."); + player.print("Undo successful."); } else { - player.sendMessage(Colors.Rose + "Nothing to undo."); + player.printError("Nothing to undo."); } return true; // Redo } else if (split[0].equalsIgnoreCase("/editredo")) { + checkArgs(split, 0, 0, split[0]); if (session.redo()) { - player.sendMessage(Colors.LightPurple + "Redo successful."); + player.print("Redo successful."); } else { - player.sendMessage(Colors.Rose + "Nothing to redo."); + 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.sendMessage(Colors.LightPurple + "History cleared."); + player.print("History cleared."); return true; // Clear clipboard } else if (split[0].equalsIgnoreCase("/clearclipboard")) { + checkArgs(split, 0, 0, split[0]); session.setClipboard(null); - player.sendMessage(Colors.LightPurple + "Clipboard cleared."); + player.print("Clipboard cleared."); return true; // Paste } else if (split[0].equalsIgnoreCase("/editpasteair") || split[0].equalsIgnoreCase("/editpaste")) { if (session.getClipboard() == null) { - player.sendMessage(Colors.Rose + "Nothing is in your clipboard."); + player.printError("Nothing is in your clipboard."); } else { - Point pos = new Point((int)Math.floor(player.getX()), - (int)Math.floor(player.getY()), - (int)Math.floor(player.getZ())); + Point pos = player.getBlockIn(); session.getClipboard().paste(editSession, pos, split[0].equalsIgnoreCase("/editpaste")); - teleportToStandPosition(player); - logger.log(Level.INFO, player.getName() + " used " + split[0]); - player.sendMessage(Colors.LightPurple + "Pasted. Undo with /editundo"); + player.findFreePosition(); + player.print("Pasted. Undo with /editundo"); } return true; // Fill a hole } else if (split[0].equalsIgnoreCase("/editfill")) { - checkArgs(split, 2, 3, "/editfill"); + checkArgs(split, 2, 3, split[0]); int blockType = getItem(split[1]); int radius = Math.max(1, Integer.parseInt(split[2])); int depth = split.length > 3 ? Math.max(1, 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(editSession, cx, cz, cx, cy, cz, - blockType, radius, minY); - - logger.log(Level.INFO, player.getName() + " used " + split[0]); - player.sendMessage(Colors.LightPurple + affected + " block(s) have been created."); + Point pos = player.getBlockIn(); + int affected = editSession.fillXZ((int)pos.getX(), (int)pos.getZ(), + pos, blockType, radius, depth); + player.print(affected + " block(s) have been created."); return true; // Remove blocks above current position } else if (split[0].equalsIgnoreCase("/removeabove")) { - int size = split.length > 1 ? Math.max(0, Integer.parseInt(split[1]) - 1) : 0; - int height = split.length > 2 ? Math.max(1, Integer.parseInt(split[2])) : 127; + int size = split.length > 1 ? Math.max(1, Integer.parseInt(split[1])) : 1; + int height = split.length > 2 ? Math.min(128, Integer.parseInt(split[2]) + 2) : 128; - int affected = 0; - int cx = (int)Math.floor(player.getX()); - int cy = (int)Math.floor(player.getY()); - int cz = (int)Math.floor(player.getZ()); - int maxY = Math.min(127, cy + height - 1); - - for (int x = cx - size; x <= cx + size; x++) { - for (int z = cz - size; z <= cz + size; z++) { - for (int y = cy; y <= maxY; y++) { - if (editSession.getBlock(x, y, z) != 0) { - editSession.setBlock(x, y, z, 0); - affected++; - } - } - } - } - - logger.log(Level.INFO, player.getName() + " used " + split[0]); - player.sendMessage(Colors.LightPurple + affected + " block(s) have been removed."); + int affected = editSession.removeAbove(player.getBlockIn(), size, height); + player.print(affected + " block(s) have been removed."); return true; // Remove blocks below current position } else if (split[0].equalsIgnoreCase("/removebelow")) { - int size = split.length > 1 ? Math.max(0, Integer.parseInt(split[1]) - 1) : 0; - int height = split.length > 2 ? Math.max(1, Integer.parseInt(split[2])) : 127; + int size = split.length > 1 ? Math.max(1, Integer.parseInt(split[1])) : 1; + int height = split.length > 2 ? Math.max(1, Integer.parseInt(split[2])) : 128; - int affected = 0; - 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(0, cy - height); - - for (int x = cx - size; x <= cx + size; x++) { - for (int z = cz - size; z <= cz + size; z++) { - for (int y = cy; y >= minY; y--) { - if (editSession.getBlock(x, y, z) != 0) { - editSession.setBlock(x, y, z, 0); - affected++; - } - } - } - } - - logger.log(Level.INFO, player.getName() + " used " + split[0]); - player.sendMessage(Colors.LightPurple + affected + " block(s) have been removed."); - - return true; - - // Make a cylinder - } else if (split[0].equalsIgnoreCase("/editcyl")) { - checkArgs(split, 2, 3, "/editcyl"); - int blockType = getItem(split[1]); - int radius = Math.abs(Integer.parseInt(split[2])); - int height = split.length > 3 ? getItem(split[3], true) : 1; - - // We don't want to pass beyond boundaries - int cx = (int)Math.floor(player.getX()); - int cy = (int)Math.floor(player.getY()); - int cz = (int)Math.floor(player.getZ()); - int maxY = Math.min(127, cy + height); - - int affected = 0; - - for (int x = -radius; x <= radius; x++) { - int z = (int)(Math.sqrt(radius - x * x) + 0.5); - for (int y = cy; y <= maxY; y++) { - for (int z2 = cz - z; z2 <= cz + z; z2++) { - editSession.setBlock(x + cx, y, z2, blockType); - affected++; - } - } - } - - teleportToStandPosition(player); - - logger.log(Level.INFO, player.getName() + " used " + split[0]); - player.sendMessage(Colors.LightPurple + affected + " block(s) have been set."); + int affected = editSession.removeBelow(player.getBlockIn(), size, height); + player.print(affected + " block(s) have been removed."); return true; // Load .schematic to clipboard } else if (split[0].equalsIgnoreCase("/editload")) { - checkArgs(split, 1, 1, "/editload"); + checkArgs(split, 1, 1, split[0]); String filename = split[1].replace("\0", "") + ".schematic"; File dir = new File("schematics"); File f = new File("schematics", filename); @@ -549,20 +480,17 @@ public class WorldEdit extends Plugin { String dirPath = dir.getCanonicalPath(); if (!filePath.substring(0, dirPath.length()).equals(dirPath)) { - player.sendMessage(Colors.Rose + "Schematic could not read or it does not exist."); + player.printError("Schematic could not read or it does not exist."); } else { - int cx = (int)Math.floor(player.getX()); - int cy = (int)Math.floor(player.getY()); - int cz = (int)Math.floor(player.getZ()); - Point origin = new Point(cx, cy, cz); - session.setClipboard(RegionClipboard.loadSchematic(filePath, origin)); + Point origin = player.getBlockIn(); + session.setClipboard(CuboidClipboard.loadSchematic(filePath, origin)); logger.log(Level.INFO, player.getName() + " loaded " + filePath); - player.sendMessage(Colors.LightPurple + filename + " loaded."); + player.print(filename + " loaded."); } - } catch (SchematicException e) { - player.sendMessage(Colors.Rose + "Load error: " + e.getMessage()); + /*} catch (SchematicException e) { + player.printError("Load error: " + e.getMessage());*/ } catch (IOException e) { - player.sendMessage(Colors.Rose + "Schematic could not read or it does not exist."); + player.printError("Schematic could not read or it does not exist."); } return true; @@ -570,18 +498,18 @@ public class WorldEdit extends Plugin { // Save clipboard to .schematic } else if (split[0].equalsIgnoreCase("/editsave")) { if (session.getClipboard() == null) { - player.sendMessage(Colors.Rose + "Nothing is in your clipboard."); + player.printError("Nothing is in your clipboard."); return true; } - checkArgs(split, 1, 1, "/editsave"); + checkArgs(split, 1, 1, split[0]); String filename = split[1].replace("\0", "") + ".schematic"; File dir = new File("schematics"); File f = new File("schematics", filename); if (!dir.exists()) { if (!dir.mkdir()) { - player.sendMessage(Colors.Rose + "A schematics/ folder could not be created."); + player.printError("A schematics/ folder could not be created."); return true; } } @@ -591,7 +519,7 @@ public class WorldEdit extends Plugin { String dirPath = dir.getCanonicalPath(); if (!filePath.substring(0, dirPath.length()).equals(dirPath)) { - player.sendMessage(Colors.Rose + "Invalid path for Schematic."); + player.printError("Invalid path for Schematic."); } else { // Create parent directories File parent = f.getParentFile(); @@ -601,164 +529,91 @@ public class WorldEdit extends Plugin { session.getClipboard().saveSchematic(filePath); logger.log(Level.INFO, player.getName() + " saved " + filePath); - player.sendMessage(Colors.LightPurple + filename + " saved."); + player.print(filename + " saved."); } } catch (SchematicException se) { - player.sendMessage(Colors.Rose + "Save error: " + se.getMessage()); + player.printError("Save error: " + se.getMessage()); } catch (IOException e) { - player.sendMessage(Colors.Rose + "Schematic could not written."); + player.printError("Schematic could not written."); } return true; // Run a script } else if (split[0].equalsIgnoreCase("/editscript")) { - checkArgs(split, 1, -1, "/editscript"); + checkArgs(split, 1, -1, split[0]); String filename = split[1].replace("\0", "") + ".js"; String[] args = new String[split.length - 2]; System.arraycopy(split, 2, args, 0, split.length - 2); try { runScript(player, session, editSession, filename, args); } catch (NoSuchScriptException e) { - player.sendMessage(Colors.Rose + "Script file does not exist."); + player.printError("Script file does not exist."); } 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 - if (split[0].equalsIgnoreCase("/editsize")) { - player.sendMessage(Colors.LightPurple + "# of blocks: " + getSession(player).getSize()); + } else if (split[0].equalsIgnoreCase("/editsize")) { + player.print("# of blocks: " + session.getRegion().getSize()); return true; // Replace all blocks in the region } else if(split[0].equalsIgnoreCase("/editset")) { - checkArgs(split, 1, 1, "/editset"); + checkArgs(split, 1, 1, split[0]); int blockType = getItem(split[1]); - int affected = 0; - - for (int x = lowerX; x <= upperX; x++) { - for (int y = lowerY; y <= upperY; y++) { - for (int z = lowerZ; z <= upperZ; z++) { - editSession.setBlock(x, y, z, blockType); - affected++; - } - } - } - - logger.log(Level.INFO, player.getName() + " used " + split[0]); - player.sendMessage(Colors.LightPurple + affected + " block(s) have been set."); + int affected = editSession.setBlocks(session.getRegion(), blockType); + player.print(affected + " block(s) have been changed."); return true; // Set the outline of a region } else if(split[0].equalsIgnoreCase("/editoutline")) { - checkArgs(split, 1, 1, "/editoutline"); + checkArgs(split, 1, 1, split[0]); int blockType = getItem(split[1]); - int affected = 0; - - for (int x = lowerX; x <= upperX; x++) { - for (int y = lowerY; y <= upperY; y++) { - editSession.setBlock(x, y, lowerZ, blockType); - editSession.setBlock(x, y, upperZ, blockType); - affected++; - } - } - - for (int y = lowerY; y <= upperY; y++) { - for (int z = lowerZ; z <= upperZ; z++) { - editSession.setBlock(lowerX, y, z, blockType); - editSession.setBlock(upperX, y, z, blockType); - affected++; - } - } - - for (int z = lowerZ; z <= upperZ; z++) { - for (int x = lowerX; x <= upperX; x++) { - editSession.setBlock(x, lowerY, z, blockType); - editSession.setBlock(x, upperY, z, blockType); - affected++; - } - } - - logger.log(Level.INFO, player.getName() + " used " + split[0]); - player.sendMessage(Colors.LightPurple + affected + " block(s) have been set."); + int affected = editSession.makeCuboidFaces(session.getRegion(), blockType); + player.print(affected + " block(s) have been changed."); return true; // Replace all blocks in the region } else if(split[0].equalsIgnoreCase("/editreplace")) { - checkArgs(split, 1, 2, "/editreplace"); - int blockType = getItem(split[1]); - int replaceType = split.length > 2 ? getItem(split[2], true) : -1; - - int affected = 0; - - for (int x = lowerX; x <= upperX; x++) { - for (int y = lowerY; y <= upperY; y++) { - for (int z = lowerZ; z <= upperZ; z++) { - if ((replaceType == -1 && editSession.getBlock(x, y, z) != 0) || - (editSession.getBlock(x, y, z) == replaceType)) { - editSession.setBlock(x, y, z, blockType); - affected++; - } - } - } + checkArgs(split, 1, 2, split[0]); + int from, to; + if (split.length == 2) { + from = -1; + to = getItem(split[1]); + } else { + from = getItem(split[1]); + to = getItem(split[2]); } - - logger.log(Level.INFO, player.getName() + " used " + split[0]); - player.sendMessage(Colors.LightPurple + affected + " block(s) have been replaced."); + + int affected = editSession.replaceBlocks(session.getRegion(), from, to); + player.print(affected + " block(s) have been replaced."); return true; // Lay blocks over an area } else if (split[0].equalsIgnoreCase("/editoverlay")) { - checkArgs(split, 1, 1, "/editoverlay"); + checkArgs(split, 1, 1, split[0]); int blockType = getItem(split[1]); - // We don't want to pass beyond boundaries - upperY = Math.min(127, upperY + 1); - lowerY = Math.max(-128, lowerY - 1); - - int affected = 0; - - for (int x = lowerX; x <= upperX; x++) { - for (int z = lowerZ; z <= upperZ; z++) { - for (int y = upperY; y >= lowerY; y--) { - if (y + 1 <= 127 && editSession.getBlock(x, y, z) != 0 && editSession.getBlock(x, y + 1, z) == 0) { - editSession.setBlock(x, y + 1, z, blockType); - affected++; - break; - } - } - } - } - - logger.log(Level.INFO, player.getName() + " used " + split[0]); - player.sendMessage(Colors.LightPurple + affected + " block(s) have been overlayed."); + Region region = session.getRegion(); + int affected = editSession.overlayCuboidBlocks(region, blockType); + player.print(affected + " block(s) have been overlayed."); return true; // Copy } else if (split[0].equalsIgnoreCase("/editcopy")) { - Point min = new Point(lowerX, lowerY, lowerZ); - Point max = new Point(upperX, upperY, upperZ); - Point pos = new Point((int)Math.floor(player.getX()), - (int)Math.floor(player.getY()), - (int)Math.floor(player.getZ())); + checkArgs(split, 0, 0, split[0]); + Region region = session.getRegion(); + Point min = region.getMinimumPoint(); + Point max = region.getMaximumPoint(); + Point pos = player.getBlockIn(); - RegionClipboard clipboard = new RegionClipboard(min, max, pos); + CuboidClipboard clipboard = new CuboidClipboard(min, max, pos); clipboard.copy(editSession); session.setClipboard(clipboard); - - logger.log(Level.INFO, player.getName() + " used " + split[0]); - player.sendMessage(Colors.LightPurple + "Block(s) copied."); + + player.print("Block(s) copied."); return true; @@ -766,72 +621,43 @@ public class WorldEdit extends Plugin { } else if (split[0].equalsIgnoreCase("/editstackair") || split[0].equalsIgnoreCase("/editstack")) { checkArgs(split, 0, 2, split[0]); - String dir = split.length > 1 ? split[1] : "me"; - int count = split.length > 2 ? Math.max(1, Integer.parseInt(split[2])) : 1; + int count = split.length > 1 ? Math.max(1, Integer.parseInt(split[1])) : 1; + String dir = split.length > 2 ? split[2].toLowerCase() : "me"; int xm = 0; int ym = 0; int zm = 0; boolean copyAir = split[0].equalsIgnoreCase("/editstackair"); - if (dir.equalsIgnoreCase("me")) { + if (dir.equals("me")) { // From hey0's code - double rot = (player.getRotation() - 90) % 360; + double rot = (player.getYaw() - 90) % 360; if (rot < 0) { rot += 360.0; } - dir = etc.getCompassPointForDirection(rot); + + dir = etc.getCompassPointForDirection(rot).toLowerCase(); } - if (dir.equalsIgnoreCase("w")) { + if (dir.charAt(0) == 'w') { zm += 1; - } else if (dir.equalsIgnoreCase("e")) { + } else if (dir.charAt(0) == 'e') { zm -= 1; - } else if (dir.equalsIgnoreCase("s")) { + } else if (dir.charAt(0) == 's') { xm += 1; - } else if (dir.equalsIgnoreCase("n")) { + } else if (dir.charAt(0) == 'n') { xm -= 1; - } else if (dir.equalsIgnoreCase("u")) { + } else if (dir.charAt(0) == 'u') { ym += 1; - } else if (dir.equalsIgnoreCase("d")) { + } else if (dir.charAt(0) == 'd') { ym -= 1; } else { - player.sendMessage(Colors.Rose + "Unknown direction: " + dir); + player.printError("Unknown direction: " + dir); return true; } - int xs = session.getWidth(); - int ys = session.getHeight(); - int zs = session.getLength(); - - int affected = 0; - - for (int x = lowerX; x <= upperX; x++) { - for (int z = lowerZ; z <= upperZ; z++) { - for (int y = lowerY; y <= upperY; y++) { - int blockType = editSession.getBlock(x, y, z); - - if (blockType != 0 || copyAir) { - for (int i = 1; i <= count; i++) { - editSession.setBlock(x + xs * xm * i, y + ys * ym * i, - z + zs * zm * i, blockType); - affected++; - } - } - } - } - } - - /*int shiftX = xs * xm * count; - int shiftY = ys * ym * count; - int shiftZ = zs * zm * count; - - int[] pos1 = session.getPos1(); - int[] pos2 = session.getPos2(); - session.setPos1(pos1[0] + shiftX, pos1[1] + shiftY, pos1[2] + shiftZ); - session.setPos2(pos2[0] + shiftX, pos2[1] + shiftY, pos2[2] + shiftZ);*/ - - logger.log(Level.INFO, player.getName() + " used " + split[0]); - player.sendMessage(Colors.LightPurple + "Stacked. Undo with /editundo"); + int affected = editSession.stackCuboidRegion(session.getRegion(), + xm, ym, zm, count, copyAir); + player.print(affected + " blocks changed. Undo with /editundo"); return true; } @@ -839,113 +665,6 @@ public class WorldEdit extends Plugin { return false; } - /** - * Fills an area recursively in the X/Z directions. - * - * @param editSession - * @param x - * @param z - * @param cx - * @param cy - * @param cz - * @param blockType - * @param radius - * @param minY - * @return - */ - private int fill(EditSession editSession, int x, int z, int cx, int cy, - int cz, int blockType, int radius, int minY) - throws MaxChangedBlocksException { - double dist = Math.sqrt(Math.pow(cx - x, 2) + Math.pow(cz - z, 2)); - int affected = 0; - - if (dist > radius) { - return 0; - } - - if (editSession.getBlock(x, cy, z) == 0) { - affected = fillY(editSession, x, cy, z, blockType, minY); - } else { - return 0; - } - - affected += fill(editSession, x + 1, z, cx, cy, cz, blockType, radius, minY); - affected += fill(editSession, x - 1, z, cx, cy, cz, blockType, radius, minY); - affected += fill(editSession, x, z + 1, cx, cy, cz, blockType, radius, minY); - affected += fill(editSession, x, z - 1, cx, cy, cz, blockType, radius, minY); - - return affected; - } - - /** - * Recursively fills a block and below until it hits another block. - * - * @param editSession - * @param x - * @param cy - * @param z - * @param blockType - * @param minY - * @throws MaxChangedBlocksException - * @return - */ - private int fillY(EditSession editSession, int x, int cy, - int z, int blockType, int minY) - throws MaxChangedBlocksException { - int affected = 0; - - for (int y = cy; y > minY; y--) { - if (editSession.getBlock(x, y, z) == 0) { - editSession.setBlock(x, y, z, blockType); - affected++; - } else { - break; - } - } - - return affected; - } - - /** - * Find a position for the player to stand that is not inside a block. - * Blocks above the player will be iteratively tested until there is - * a series of two free blocks. The player will be teleported to - * that free position. - * - * @param player - */ - private void teleportToStandPosition(Player player) { - int x = (int)Math.floor(player.getX()); - int y = (int)Math.floor(player.getY()); - int origY = y; - int z = (int)Math.floor(player.getZ()); - - byte free = 0; - - while (y <= 129) { - if (getBlock(x, y, z) == 0) { - free++; - } else { - free = 0; - } - - if (free == 2) { - if (y - 1 != origY) { - Location loc = new Location(); - loc.x = x + 0.5; - loc.y = y - 1; - loc.z = z + 0.5; - loc.rotX = player.getRotation(); - loc.rotY = player.getPitch(); - player.teleportTo(loc); - return; - } - } - - y++; - } - } - /** * Execute a script. * @@ -954,7 +673,7 @@ public class WorldEdit extends Plugin { * @param args * @return Whether the file was attempted execution */ - private boolean runScript(Player player, WorldEditSession session, + private boolean runScript(WorldEditPlayer player, WorldEditSession session, EditSession editSession, String filename, String[] args) throws NoSuchScriptException { File dir = new File("editscripts"); @@ -1008,12 +727,12 @@ public class WorldEdit extends Plugin { logger.log(Level.INFO, player.getName() + ": executing " + filename + "..."); cx.evaluateString(scope, code, filename, 1, null); logger.log(Level.INFO, player.getName() + ": script " + filename + " executed successfully."); - player.sendMessage(Colors.LightPurple + filename + " executed successfully."); + player.print(filename + " executed successfully."); } catch (RhinoException re) { - player.sendMessage(Colors.Rose + filename + ": JS error: " + re.getMessage()); + player.printError(filename + ": JS error: " + re.getMessage()); re.printStackTrace(); } catch (Error err) { - player.sendMessage(Colors.Rose + filename + ": execution error: " + err.getMessage()); + player.printError(filename + ": execution error: " + err.getMessage()); } finally { Context.exit(); } @@ -1021,7 +740,7 @@ public class WorldEdit extends Plugin { return true; } catch (IOException e) { - player.sendMessage(Colors.Rose + "Script could not read or it does not exist."); + player.printError("Script could not read or it does not exist."); } return false; diff --git a/src/WorldEditPlayer.java b/src/WorldEditPlayer.java new file mode 100644 index 000000000..29458c907 --- /dev/null +++ b/src/WorldEditPlayer.java @@ -0,0 +1,199 @@ +// $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 . +*/ + +import com.sk89q.worldedit.Point; + +/** + * + * @author sk89q + */ +public class WorldEditPlayer { + private Player player; + + /** + * Construct a WorldEditPlayer. + * + * @param player + */ + public WorldEditPlayer(Player player) { + this.player = player; + } + + /** + * Get the name of the player. + * + * @return String + */ + public String getName() { + return player.getName(); + } + + /** + * Get the point of the block that is being stood upon. + * + * @return + */ + public Point getBlockOn() { + return Point.toBlockPoint(player.getX(), player.getY() - 1, player.getZ()); + } + + /** + * Get the point of the block that is being stood in. + * + * @return + */ + public Point getBlockIn() { + return Point.toBlockPoint(player.getX(), player.getY(), player.getZ()); + } + + /** + * Get the player's position. + * + * @return + */ + public Point getPosition() { + return new Point(player.getX(), player.getY(), player.getZ()); + } + + /** + * Get the player's view pitch. + * + * @return + */ + public double getPitch() { + return player.getPitch(); + } + + /** + * Get the player's view yaw. + * + * @return + */ + public double getYaw() { + return player.getRotation(); + } + + /** + * Print a WorldEdit message. + * + * @param msg + */ + public void print(String msg) { + player.sendMessage(Colors.LightPurple + msg); + } + + /** + * Print a WorldEdit error. + * + * @param msg + */ + public void printError(String msg) { + player.sendMessage(Colors.Rose + msg); + } + + /** + * Move the player. + * + * @param pos + * @param pitch + * @param yaw + */ + public void setPosition(Point pos, float pitch, float yaw) { + Location loc = new Location(); + loc.x = pos.getX(); + loc.y = pos.getY(); + loc.z = pos.getZ(); + loc.rotX = (float)yaw; + loc.rotY = (float)pitch; + player.teleportTo(loc); + } + + /** + * Find a position for the player to stand that is not inside a block. + * Blocks above the player will be iteratively tested until there is + * a series of two free blocks. The player will be teleported to + * that free position. + */ + public void findFreePosition() { + int x = (int)Math.floor(player.getX()); + int y = (int)Math.floor(player.getY()); + int origY = y; + int z = (int)Math.floor(player.getZ()); + + byte free = 0; + + while (y <= 129) { + if (etc.getServer().getBlockIdAt(x, y, z) == 0) { + free++; + } else { + free = 0; + } + + if (free == 2) { + if (y - 1 != origY) { + Location loc = new Location(); + loc.x = x + 0.5; + loc.y = y - 1; + loc.z = z + 0.5; + loc.rotX = player.getRotation(); + loc.rotY = player.getPitch(); + player.teleportTo(loc); + return; + } + } + + y++; + } + } + + /** + * Gives the player an item. + * + * @param type + * @param amt + */ + public void giveItem(int type, int amt) { + player.giveItem(type, amt); + } + + /** + * Returns true if equal. + * + * @param other + * @return + */ + @Override + public boolean equals(Object other) { + if (!(other instanceof WorldEditPlayer)) { + return false; + } + WorldEditPlayer other2 = (WorldEditPlayer)other; + return other2.getName().equals(player.getName()); + } + + /** + * Gets the hash code. + * + * @return + */ + @Override + public int hashCode() { + return getName().hashCode(); + } +} diff --git a/src/WorldEditSession.java b/src/WorldEditSession.java index 73a226589..e69b3ac85 100644 --- a/src/WorldEditSession.java +++ b/src/WorldEditSession.java @@ -26,15 +26,12 @@ import java.util.LinkedList; */ public class WorldEditSession { public static final int MAX_HISTORY_SIZE = 15; - private int[] pos1 = new int[3]; - private int[] pos2 = new int[3]; - private boolean hasSetPos1 = false; - private boolean hasSetPos2 = false; + private Point pos1, pos2; private LinkedList history = new LinkedList(); private int historyPointer = 0; - private RegionClipboard clipboard; + private CuboidClipboard clipboard; private boolean toolControl = true; - private int[] lastToolPos1 = new int[3]; + private Point lastToolPos1; private long lastToolClick = 0; private int maxBlocksChanged = -1; @@ -69,7 +66,7 @@ public class WorldEditSession { /** * Undo. * - * @return whether anything was undoed + * @return whether anything was undone */ public boolean undo() { historyPointer--; @@ -85,7 +82,7 @@ public class WorldEditSession { /** * Redo. * - * @return whether anything was redoed + * @return whether anything was redone */ public boolean redo() { if (historyPointer < history.size()) { @@ -103,7 +100,7 @@ public class WorldEditSession { * @throws IncompleteRegionException */ private void checkPos1() throws IncompleteRegionException { - if (!hasSetPos1) { + if (pos1 == null) { throw new IncompleteRegionException(); } } @@ -114,7 +111,7 @@ public class WorldEditSession { * @throws IncompleteRegionException */ private void checkPos2() throws IncompleteRegionException { - if (!hasSetPos2) { + if (pos2 == null) { throw new IncompleteRegionException(); } } @@ -125,7 +122,7 @@ public class WorldEditSession { * @return * @throws IncompleteRegionException */ - public int[] getPos1() throws IncompleteRegionException { + public Point getPos1() throws IncompleteRegionException { checkPos1(); return pos1; } @@ -133,25 +130,10 @@ public class WorldEditSession { /** * Sets position 1. * - * @param x - * @param y - * @param z + * @param pt */ - public void setPos1(int x, int y, int z) { - hasSetPos1 = true; - pos1 = new int[]{x, y, z}; - } - - /** - * Sets position 1. - * - * @param x - * @param y - * @param z - */ - public void setPos1(int[] pos) { - hasSetPos1 = true; - pos1 = pos; + public void setPos1(Point pt) { + pos1 = pt; } /** @@ -160,7 +142,7 @@ public class WorldEditSession { * @return * @throws IncompleteRegionException */ - public int[] getPos2() throws IncompleteRegionException { + public Point getPos2() throws IncompleteRegionException { checkPos2(); return pos2; } @@ -168,139 +150,23 @@ public class WorldEditSession { /** * Sets position 2. * - * @param x - * @param y - * @param z + * @param pt */ - public void setPos2(int x, int y, int z) { - hasSetPos2 = true; - pos2 = new int[]{x, y, z}; + public void setPos2(Point pt) { + pos2 = pt; } /** - * Sets position 2. - * - * @param x - * @param y - * @param z - */ - public void setPos2(int[] pos) { - hasSetPos2 = true; - pos2 = pos; - } - - /** - * Get lower X bound. + * Get the region. * * @return * @throws IncompleteRegionException */ - public int getLowerX() throws IncompleteRegionException { + public Region getRegion() throws IncompleteRegionException { checkPos1(); checkPos2(); - return Math.min(pos1[0], pos2[0]); - } - /** - * Get upper X bound. - * - * @return - * @throws IncompleteRegionException - */ - public int getUpperX() throws IncompleteRegionException { - checkPos1(); - checkPos2(); - return Math.max(pos1[0], pos2[0]); - } - - /** - * Get lower Y bound. - * - * @return - * @throws IncompleteRegionException - */ - public int getLowerY() throws IncompleteRegionException { - checkPos1(); - checkPos2(); - return Math.min(pos1[1], pos2[1]); - } - - /** - * Get upper Y bound. - * - * @return - * @throws IncompleteRegionException - */ - public int getUpperY() throws IncompleteRegionException { - checkPos1(); - checkPos2(); - return Math.max(pos1[1], pos2[1]); - } - - /** - * Get lower Z bound. - * - * @return - * @throws IncompleteRegionException - */ - public int getLowerZ() throws IncompleteRegionException { - checkPos1(); - checkPos2(); - return Math.min(pos1[2], pos2[2]); - } - - /** - * Get upper Z bound. - * - * @return - * @throws IncompleteRegionException - */ - public int getUpperZ() throws IncompleteRegionException { - checkPos1(); - checkPos2(); - return Math.max(pos1[2], pos2[2]); - } - - /** - * Gets the size of the region as the number of blocks. - * - * @return - * @throws IncompleteRegionException - */ - public int getSize() throws IncompleteRegionException { - return (getUpperX() - getLowerX() + 1) * - (getUpperY() - getLowerY() + 1) * - (getUpperZ() - getLowerZ() + 1); - } - - /** - * Get the width (X-direction) of the selected region. - * - * @return - * @throws IncompleteRegionException - */ - public int getWidth() throws IncompleteRegionException { - return getUpperX() - getLowerX() + 1; - } - - /** - * Get the length (Z-direction) of the selected region. - * - * @return - * @throws IncompleteRegionException - */ - public int getLength() throws IncompleteRegionException { - return getUpperZ() - getLowerZ() + 1; - } - - /** - * Get the height (Y-direction) of the selected region. - * - * @return - * @throws IncompleteRegionException - */ - public int getHeight() throws IncompleteRegionException { - return getUpperY() - getLowerY() + 1; + return new CuboidRegion(pos1, pos2); } /** @@ -308,7 +174,7 @@ public class WorldEditSession { * * @return */ - public RegionClipboard getClipboard() { + public CuboidClipboard getClipboard() { return clipboard; } @@ -317,7 +183,7 @@ public class WorldEditSession { * * @param clipboard */ - public void setClipboard(RegionClipboard clipboard) { + public void setClipboard(CuboidClipboard clipboard) { this.clipboard = clipboard; } @@ -342,14 +208,14 @@ public class WorldEditSession { /** * @return the lastToolPos1 */ - public int[] getLastToolPos1() { + public Point getLastToolPos1() { return lastToolPos1; } /** * @param lastToolPos1 the lastToolPos1 to set */ - public void setLastToolPos1(int[] lastToolPos1) { + public void setLastToolPos1(Point lastToolPos1) { this.lastToolPos1 = lastToolPos1; } diff --git a/src/com/sk89q/worldedit/CuboidRegion.java b/src/com/sk89q/worldedit/CuboidRegion.java new file mode 100644 index 000000000..921bcb314 --- /dev/null +++ b/src/com/sk89q/worldedit/CuboidRegion.java @@ -0,0 +1,131 @@ +// $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; + +import java.util.Iterator; + +/** + * + * @author Albert + */ +public class CuboidRegion implements Region { + /** + * Store the first point. + */ + private Point pos1; + /** + * Store the second point. + */ + private Point pos2; + + /** + * Construct a new instance of this cuboid region. + * + * @param pos1 + * @param pos2 + */ + public CuboidRegion(Point pos1, Point pos2) { + this.pos1 = pos1; + this.pos2 = pos2; + } + + /** + * Get the lower point of the cuboid. + * + * @return + */ + @Override + public Point getMinimumPoint() { + return new Point(Math.min(pos1.getX(), pos2.getX()), + Math.min(pos1.getY(), pos2.getY()), + Math.min(pos1.getZ(), pos2.getZ())); + } + + /** + * Get the upper point of the cuboid. + * + * @return + */ + @Override + public Point getMaximumPoint() { + return new Point(Math.max(pos1.getX(), pos2.getX()), + Math.max(pos1.getY(), pos2.getY()), + Math.max(pos1.getZ(), pos2.getZ())); + } + + /** + * Get the number of blocks in the region. + * + * @return + */ + public int getSize() { + Point min = getMinimumPoint(); + Point max = getMaximumPoint(); + + return (int)((max.getX() - min.getX() + 1) * + (max.getY() - min.getY() + 1) * + (max.getZ() - min.getZ() + 1)); + } + + /** + * Get X-size. + * + * @return + */ + public int getWidth() { + Point min = getMinimumPoint(); + Point max = getMaximumPoint(); + + return (int)(max.getX() - min.getX() + 1); + } + + /** + * Get Y-size. + * + * @return + */ + public int getHeight() { + Point min = getMinimumPoint(); + Point max = getMaximumPoint(); + + return (int)(max.getY() - min.getY() + 1); + } + + /** + * Get Z-size. + * + * @return + */ + public int getLength() { + Point min = getMinimumPoint(); + Point max = getMaximumPoint(); + + return (int)(max.getZ() - min.getZ() + 1); + } + + /** + * Get the iterator. + * + * @return + */ + public Iterator iterator() { + throw new UnsupportedOperationException("Not implemented"); + } +} diff --git a/src/com/sk89q/worldedit/Point.java b/src/com/sk89q/worldedit/Point.java index 13a2c8580..4e0a4e5db 100644 --- a/src/com/sk89q/worldedit/Point.java +++ b/src/com/sk89q/worldedit/Point.java @@ -20,50 +20,289 @@ package com.sk89q.worldedit; import org.apache.commons.lang3.builder.HashCodeBuilder; -import org.apache.commons.lang3.builder.EqualsBuilder; /** * * @author Albert */ -public final class Point { - private final T x, y, z; +public final class Point { + private final double x, y, z; /** * Construct the Point object. - * + * * @param x * @param y * @param z */ - public Point(T x, T y, T z) { + public Point(double x, double y, double z) { this.x = x; this.y = y; this.z = z; } + /** + * Construct the Point object. + * + * @param x + * @param y + * @param z + */ + public Point(int x, int y, int z) { + this.x = (double)x; + this.y = (double)y; + this.z = (double)z; + } + + /** + * Construct the Point object. + * + * @param x + * @param y + * @param z + */ + public Point(float x, float y, float z) { + this.x = (double)x; + this.y = (double)y; + this.z = (double)z; + } + + /** + * Construct the Point object. + */ + public Point() { + this.x = 0; + this.y = 0; + this.z = 0; + } + /** * @return the x */ - public T getX() { + public double getX() { return x; } + /** + * @return the x + */ + public int getBlockX() { + return (int)x; + } /** * @return the y */ - public T getY() { + public double getY() { return y; } + /** + * @return the y + */ + public int getBlockY() { + return (int)y; + } + /** * @return the z */ - public T getZ() { + public double getZ() { return z; } + /** + * @return the z + */ + public int getBlockZ() { + return (int)z; + } + + /** + * Adds two points. + * + * @param other + * @return New point + */ + public Point add(Point other) { + return new Point(x + other.x, y + other.y, z + other.z); + } + + /** + * Adds two points. + * + * @param other + * @return New point + */ + public Point add(double x, double y, double z) { + return new Point(this.x + x, this.y + y, this.z + z); + } + + /** + * Adds two points. + * + * @param other + * @return New point + */ + public Point add(int x, int y, int z) { + return new Point(this.x + x, this.y + y, this.z + z); + } + + /** + * Adds points. + * + * @param other + * @return New point + */ + public Point add(Point ... others) { + double newX = x, newY = y, newZ = z; + + for (int i = 0; i < others.length; i++) { + newX += others[i].x; + newY += others[i].y; + newZ += others[i].z; + } + return new Point(newX, newY, newZ); + } + + /** + * Subtracts two points. + * + * @param other + * @return New point + */ + public Point subtract(Point other) { + return new Point(x - other.x, y - other.y, z - other.z); + } + + /** + * Subtract two points. + * + * @param other + * @return New point + */ + public Point subtract(double x, double y, double z) { + return new Point(this.x - x, this.y - y, this.z - z); + } + + /** + * Subtract two points. + * + * @param other + * @return New point + */ + public Point subtract(int x, int y, int z) { + return new Point(this.x - x, this.y - y, this.z - z); + } + + /** + * Subtract points. + * + * @param other + * @return New point + */ + public Point subtract(Point ... others) { + double newX = x, newY = y, newZ = z; + + for (int i = 0; i < others.length; i++) { + newX -= others[i].x; + newY -= others[i].y; + newZ -= others[i].z; + } + return new Point(newX, newY, newZ); + } + + /** + * Multiplies two points. + * + * @param other + * @return New point + */ + public Point multiply(Point other) { + return new Point(x * other.x, y * other.y, z * other.z); + } + + /** + * Multiply two points. + * + * @param other + * @return New point + */ + public Point multiply(double x, double y, double z) { + return new Point(this.x * x, this.y * y, this.z * z); + } + + /** + * Multiply two points. + * + * @param other + * @return New point + */ + public Point multiply(int x, int y, int z) { + return new Point(this.x * x, this.y * y, this.z * z); + } + + /** + * Multiply points. + * + * @param other + * @return New point + */ + public Point multiply(Point ... others) { + double newX = x, newY = y, newZ = z; + + for (int i = 0; i < others.length; i++) { + newX *= others[i].x; + newY *= others[i].y; + newZ *= others[i].z; + } + return new Point(newX, newY, newZ); + } + + /** + * Divide two points. + * + * @param other + * @return New point + */ + public Point divide(Point other) { + return new Point(x / other.x, y / other.y, z / other.z); + } + + /** + * Divide two points. + * + * @param other + * @return New point + */ + public Point divide(double x, double y, double z) { + return new Point(this.x / x, this.y / y, this.z / z); + } + + /** + * Divide two points. + * + * @param other + * @return New point + */ + public Point divide(int x, int y, int z) { + return new Point(this.x / x, this.y / y, this.z / z); + } + + /** + * Get a block point from a point. + * + * @param x + * @param y + * @param z + * @return + */ + public static Point toBlockPoint(double x, double y, double z) { + return new Point((int)Math.floor(x), + (int)Math.floor(y), + (int)Math.floor(z)); + } + /** * Checks if another object is equivalent. * @@ -76,11 +315,7 @@ public final class Point { return false; } Point other = (Point)obj; - return new EqualsBuilder() - .append(x, other.x) - .append(y, other.y) - .append(z, other.z) - .isEquals(); + return other.x == this.x && other.y == this.y && other.z == this.z; } @@ -97,5 +332,4 @@ public final class Point { append(z). toHashCode(); } - } diff --git a/src/com/sk89q/worldedit/Region.java b/src/com/sk89q/worldedit/Region.java new file mode 100644 index 000000000..0eabd7d63 --- /dev/null +++ b/src/com/sk89q/worldedit/Region.java @@ -0,0 +1,63 @@ +// $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; + +/** + * + * @author Albert + */ +public interface Region extends Iterable { + /** + * Get the lower point of a region. + * + * @return + */ + public Point getMinimumPoint(); + /** + * Get the upper point of a region. + * + * @return + */ + public Point getMaximumPoint(); + /** + * Get the number of blocks in the region. + * + * @return + */ + public int getSize(); + /** + * Get X-size. + * + * @return + */ + public int getWidth(); + /** + * Get Y-size. + * + * @return + */ + public int getHeight(); + /** + * Get Z-size. + * + * @return + */ + public int getLength(); +}