diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java index aab358096a..8dba6fe0ce 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/SelectionCommands.java @@ -21,7 +21,11 @@ import com.fastasyncworldedit.core.configuration.Caption; import com.fastasyncworldedit.core.extent.clipboard.URIClipboardHolder; +import com.fastasyncworldedit.core.extent.filter.ForkedFilter; +import com.fastasyncworldedit.core.extent.filter.MaskFilter; +import com.fastasyncworldedit.core.extent.filter.block.FilterBlock; import com.fastasyncworldedit.core.function.mask.IdMask; +import com.fastasyncworldedit.core.queue.Filter; import com.fastasyncworldedit.core.regions.selector.FuzzyRegionSelector; import com.fastasyncworldedit.core.regions.selector.PolyhedralRegionSelector; import com.fastasyncworldedit.core.util.MaskTraverser; @@ -48,7 +52,6 @@ import com.sk89q.worldedit.function.block.BlockDistributionCounter; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.MaskIntersection; -import com.sk89q.worldedit.function.mask.Masks; import com.sk89q.worldedit.function.mask.RegionMask; import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.function.visitor.RegionVisitor; @@ -518,125 +521,99 @@ private BlockVector3[] getChangesForEachDir(int amount, boolean onlyHorizontal, ) @Logging(REGION) @CommandPermissions("worldedit.selection.trim") - public void trim(Actor actor, World world, LocalSession session, + public void trim(Actor actor, World world, LocalSession session, EditSession editSession, @Arg(desc = "Mask of blocks to keep within the selection", def = "#existing") Mask mask) throws WorldEditException { + //FAWE start // Avoid checking blocks outside the original region but within the cuboid region Region originalRegion = session.getSelection(world); - if (!(originalRegion instanceof CuboidRegion)) { - mask = new MaskIntersection(new RegionMask(originalRegion), mask); - } + new MaskTraverser(mask).setNewExtent(editSession); // Result region will be cuboid - CuboidRegion region = originalRegion.getBoundingBox(); - - BlockVector3 min = region.getMinimumPoint(); - BlockVector3 max = region.getMaximumPoint(); - - int minY = 0; - boolean found = false; - - outer: for (int y = min.y(); y <= max.y(); y++) { - for (int x = min.x(); x <= max.x(); x++) { - for (int z = min.z(); z <= max.z(); z++) { - BlockVector3 vec = BlockVector3.at(x, y, z); - - if (mask.test(vec)) { - found = true; - minY = y; - - break outer; - } - } + final CuboidRegion region = originalRegion.getBoundingBox(); + + // subtract offset to determine if there was any change later + final BlockVector3 min = region.getMinimumPoint().subtract(BlockVector3.ONE); + final BlockVector3 max = region.getMaximumPoint(); + + class TrimFilter extends ForkedFilter { + private int minX; + private int minY; + private int minZ; + private int maxX; + private int maxY; + private int maxZ; + + public TrimFilter(final BlockVector3 min, final BlockVector3 max) { + super(null); + this.minX = max.x(); + this.minY = max.y(); + this.minZ = max.z(); + this.maxX = min.x(); + this.maxY = min.y(); + this.maxZ = min.z(); } - } - // If anything was found in the first pass, then the remaining variables are guaranteed to be set - if (!found) { - throw new StopExecutionException(Caption.of("worldedit.trim.no-blocks")); - } - - int maxY = minY; - - outer: for (int y = max.y(); y > minY; y--) { - for (int x = min.x(); x <= max.x(); x++) { - for (int z = min.z(); z <= max.z(); z++) { - BlockVector3 vec = BlockVector3.at(x, y, z); - - if (mask.test(vec)) { - maxY = y; - break outer; - } - } + public TrimFilter( + final TrimFilter root, + final int minX, + final int minY, + final int minZ, + final int maxX, + final int maxY, + final int maxZ + ) { + super(root); + this.minX = minX; + this.minY = minY; + this.minZ = minZ; + this.maxX = maxX; + this.maxY = maxY; + this.maxZ = maxZ; } - } - - int minX = 0; - outer: for (int x = min.x(); x <= max.x(); x++) { - for (int z = min.z(); z <= max.z(); z++) { - for (int y = minY; y <= maxY; y++) { - BlockVector3 vec = BlockVector3.at(x, y, z); - - if (mask.test(vec)) { - minX = x; - break outer; - } - } + @Override + public void applyBlock(final FilterBlock block) { + this.minX = Math.min(this.minX, block.x()); + this.maxX = Math.max(this.maxX, block.x()); + this.minY = Math.min(this.minY, block.y()); + this.maxY = Math.max(this.maxY, block.y()); + this.minZ = Math.min(this.minZ, block.z()); + this.maxZ = Math.max(this.maxZ, block.z()); } - } - - int maxX = minX; - outer: for (int x = max.x(); x > minX; x--) { - for (int z = min.z(); z <= max.z(); z++) { - for (int y = minY; y <= maxY; y++) { - BlockVector3 vec = BlockVector3.at(x, y, z); - - if (mask.test(vec)) { - maxX = x; - break outer; - } - } + @Override + public TrimFilter init() { + return new TrimFilter(this, this.minX, this.minY, this.minZ, this.maxX, this.maxY, this.maxZ); } - } - - int minZ = 0; - - outer: for (int z = min.z(); z <= max.z(); z++) { - for (int x = minX; x <= maxX; x++) { - for (int y = minY; y <= maxY; y++) { - BlockVector3 vec = BlockVector3.at(x, y, z); - if (mask.test(vec)) { - minZ = z; - break outer; - } - } + @Override + public void join(final TrimFilter filter) { + this.minX = Math.min(this.minX, filter.minX); + this.maxX = Math.max(this.maxX, filter.maxX); + this.minY = Math.min(this.minY, filter.minY); + this.maxY = Math.max(this.maxY, filter.maxY); + this.minZ = Math.min(this.minZ, filter.minZ); + this.maxZ = Math.max(this.maxZ, filter.maxZ); } - } - - int maxZ = minZ; - - outer: for (int z = max.z(); z > minZ; z--) { - for (int x = minX; x <= maxX; x++) { - for (int y = minY; y <= maxY; y++) { - BlockVector3 vec = BlockVector3.at(x, y, z); - if (mask.test(vec)) { - maxZ = z; - break outer; - } - } - } } + TrimFilter result = editSession.apply(region, new MaskFilter<>(new TrimFilter(min, max), mask), true).getParent(); final CuboidRegionSelector selector; + final BlockVector3 newMin = BlockVector3.at(result.minX, result.minY, result.minZ); + final BlockVector3 newMax = BlockVector3.at(result.maxX, result.maxY, result.maxZ); + + // If anything was found, then all variables are guaranteed to be set to something inside the region + if (newMax.equals(min)) { + throw new StopExecutionException(Caption.of("worldedit.trim.no-blocks")); + } if (session.getRegionSelector(world) instanceof ExtendingCuboidRegionSelector) { - selector = new ExtendingCuboidRegionSelector(world, BlockVector3.at(minX, minY, minZ), BlockVector3.at(maxX, maxY, maxZ)); + selector = new ExtendingCuboidRegionSelector(world, newMin, newMax); } else { - selector = new CuboidRegionSelector(world, BlockVector3.at(minX, minY, minZ), BlockVector3.at(maxX, maxY, maxZ)); + selector = new CuboidRegionSelector(world, newMin, newMax); } + //FAWE end session.setRegionSelector(world, selector); session.getRegionSelector(world).learnChanges();