From 06d87a84cc18f68a9c557315bf31fd781c13c46a Mon Sep 17 00:00:00 2001 From: sk89q Date: Tue, 16 Nov 2010 14:07:52 -0800 Subject: [PATCH] Added pattern support to //replace and //fill. --- src/EditSession.java | 146 +++++++++++++++++++++++++++++++++++++ src/WorldEditListener.java | 42 +++++++---- 2 files changed, 174 insertions(+), 14 deletions(-) diff --git a/src/EditSession.java b/src/EditSession.java index 19b8afa8f..f99280fb7 100644 --- a/src/EditSession.java +++ b/src/EditSession.java @@ -414,6 +414,94 @@ public class EditSession { return affected; } + /** + * Fills an area recursively in the X/Z directions. + * + * @param x + * @param z + * @param origin + * @param pattern + * @param radius + * @param depth + * @return number of blocks affected + */ + public int fillXZ(int x, int z, Vector origin, Pattern pattern, + int radius, int depth) + throws MaxChangedBlocksException { + + int affected = 0; + int originX = origin.getBlockX(); + int originY = origin.getBlockY(); + int originZ = origin.getBlockZ(); + + HashSet visited = new HashSet(); + Stack queue = new Stack(); + + queue.push(new BlockVector(x, 0, z)); + + while (!queue.empty()) { + BlockVector pt = queue.pop(); + int cx = pt.getBlockX(); + int cz = pt.getBlockZ(); + + if (visited.contains(pt)) { + continue; + } + + visited.add(pt); + + double dist = Math.sqrt(Math.pow(originX - cx, 2) + + Math.pow(originZ - cz, 2)); + int minY = originY - depth + 1; + + if (dist > radius) { + continue; + } + + if (getBlock(new Vector(cx, originY, cz)).isAir()) { + affected += fillY(cx, originY, cz, pattern, minY); + } else { + continue; + } + + queue.push(new BlockVector(cx + 1, 0, cz)); + queue.push(new BlockVector(cx - 1, 0, cz)); + queue.push(new BlockVector(cx, 0, cz + 1)); + queue.push(new BlockVector(cx, 0, cz - 1)); + } + + return affected; + } + + /** + * Recursively fills a block and below until it hits another block. + * + * @param x + * @param cy + * @param z + * @param pattern + * @param minY + * @throws MaxChangedBlocksException + * @return + */ + private int fillY(int x, int cy, int z, Pattern pattern, int minY) + throws MaxChangedBlocksException { + int affected = 0; + + for (int y = cy; y >= minY; y--) { + Vector pt = new Vector(x, y, z); + + if (getBlock(pt).isAir()) { + setBlock(pt, pattern.next(pt)); + affected++; + } else { + break; + } + } + + return affected; + } + /** * Remove blocks above. * @@ -661,6 +749,64 @@ public class EditSession { 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 pattern + * @return number of blocks affected + * @throws MaxChangedBlocksException + */ + public int replaceBlocks(Region region, Set fromBlockTypes, + Pattern pattern) + throws MaxChangedBlocksException { + int affected = 0; + + if (region instanceof CuboidRegion) { + // Doing this for speed + Vector min = region.getMinimumPoint(); + Vector max = region.getMaximumPoint(); + + int minX = min.getBlockX(); + int minY = min.getBlockY(); + int minZ = min.getBlockZ(); + int maxX = max.getBlockX(); + int maxY = max.getBlockY(); + int maxZ = max.getBlockZ(); + + for (int x = minX; x <= maxX; x++) { + for (int y = minY; y <= maxY; y++) { + for (int z = minZ; z <= maxZ; z++) { + Vector pt = new Vector(x, y, z); + int curBlockType = getBlock(pt).getID(); + + if ((fromBlockTypes == null && curBlockType != 0) || + (fromBlockTypes != null && + fromBlockTypes.contains(curBlockType))) { + if (setBlock(pt, pattern.next(pt))) { + affected++; + } + } + } + } + } + } else { + for (Vector pt : region) { + int curBlockType = getBlock(pt).getID(); + + if (fromBlockTypes == null && curBlockType != 0 || + fromBlockTypes.contains(curBlockType)) { + if (setBlock(pt, pattern.next(pt))) { + affected++; + } + } + } + } + + return affected; + } + /** * Make faces of the region (as if it was a cuboid if it's not). * diff --git a/src/WorldEditListener.java b/src/WorldEditListener.java index b74a9ca41..b1cdc6e7d 100644 --- a/src/WorldEditListener.java +++ b/src/WorldEditListener.java @@ -308,14 +308,15 @@ public class WorldEditListener extends PluginListener { * Get a list of blocks as a set. * * @param list + * @params allBlocksAllowed * @return set */ - public Set getBlockIDs(String list) throws UnknownItemException, - DisallowedItemException { + public Set getBlockIDs(String list, boolean allBlocksAllowed) + throws UnknownItemException, DisallowedItemException { String[] items = list.split(","); Set blocks = new HashSet(); for (String s : items) { - blocks.add(getBlock(s).getID()); + blocks.add(getBlock(s, allBlocksAllowed).getID()); } return blocks; } @@ -725,14 +726,20 @@ public class WorldEditListener extends PluginListener { // Fill a hole } else if (split[0].equalsIgnoreCase("//fill")) { checkArgs(split, 2, 3, split[0]); - BaseBlock block = getBlock(split[1]); + Pattern pattern = getBlockPattern(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 = editSession.fillXZ((int)pos.getX(), (int)pos.getZ(), - pos, block, radius, depth); + int affected = 0; + if (pattern instanceof SingleBlockPattern) { + affected = editSession.fillXZ((int)pos.getX(), (int)pos.getZ(), + pos, ((SingleBlockPattern)pattern).getBlock(), radius, depth); + } else { + affected = editSession.fillXZ((int)pos.getX(), (int)pos.getZ(), + pos, pattern, radius, depth); + } player.print(affected + " block(s) have been created."); return true; @@ -936,17 +943,24 @@ public class WorldEditListener extends PluginListener { // Replace all blocks in the region } else if(split[0].equalsIgnoreCase("//replace")) { checkArgs(split, 1, 2, split[0]); + Set from; - BaseBlock to; + Pattern to; if (split.length == 2) { from = null; - to = getBlock(split[1], true); + to = getBlockPattern(split[1]); } else { - from = getBlockIDs(split[1]); - to = getBlock(split[2]); + from = getBlockIDs(split[1], true); + to = getBlockPattern(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); } - - int affected = editSession.replaceBlocks(session.getRegion(), from, to); player.print(affected + " block(s) have been replaced."); return true; @@ -959,9 +973,9 @@ public class WorldEditListener extends PluginListener { BaseBlock to; if (split.length == 3) { from = null; - to = getBlock(split[2], true); + to = getBlock(split[2]); } else { - from = getBlockIDs(split[2]); + from = getBlockIDs(split[2], true); to = getBlock(split[3]); }