From fa82f6490e5a23965e16f33be3439d00ec03a4c4 Mon Sep 17 00:00:00 2001 From: Timon Seidel Date: Tue, 8 Apr 2025 13:44:22 +0200 Subject: [PATCH 1/3] chore: refactor block vector handling in loops --- .../worldedit/command/SelectionCommands.java | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) 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..0bba824796 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 @@ -22,6 +22,7 @@ import com.fastasyncworldedit.core.configuration.Caption; import com.fastasyncworldedit.core.extent.clipboard.URIClipboardHolder; import com.fastasyncworldedit.core.function.mask.IdMask; +import com.fastasyncworldedit.core.math.MutableBlockVector3; import com.fastasyncworldedit.core.regions.selector.FuzzyRegionSelector; import com.fastasyncworldedit.core.regions.selector.PolyhedralRegionSelector; import com.fastasyncworldedit.core.util.MaskTraverser; @@ -536,12 +537,13 @@ public void trim(Actor actor, World world, LocalSession session, int minY = 0; boolean found = false; + MutableBlockVector3 mutable = new MutableBlockVector3(); 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); + mutable.setComponents(x, y, z); - if (mask.test(vec)) { + if (mask.test(mutable)) { found = true; minY = y; @@ -561,9 +563,9 @@ public void trim(Actor actor, World world, LocalSession session, 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); + mutable.setComponents(x, y, z); - if (mask.test(vec)) { + if (mask.test(mutable)) { maxY = y; break outer; } @@ -576,9 +578,9 @@ public void trim(Actor actor, World world, LocalSession session, 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); + mutable.setComponents(x, y, z); - if (mask.test(vec)) { + if (mask.test(mutable)) { minX = x; break outer; } @@ -591,9 +593,9 @@ public void trim(Actor actor, World world, LocalSession session, 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); + mutable.setComponents(x, y, z); - if (mask.test(vec)) { + if (mask.test(mutable)) { maxX = x; break outer; } @@ -606,9 +608,9 @@ public void trim(Actor actor, World world, LocalSession session, 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); + mutable.setComponents(x, y, z); - if (mask.test(vec)) { + if (mask.test(mutable)) { minZ = z; break outer; } @@ -621,9 +623,9 @@ public void trim(Actor actor, World world, LocalSession session, 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); + mutable.setComponents(x, y, z); - if (mask.test(vec)) { + if (mask.test(mutable)) { maxZ = z; break outer; } From 79e2fcbb38974a64c80d9e8fa399e93598b3c519 Mon Sep 17 00:00:00 2001 From: Timon Seidel Date: Wed, 9 Apr 2025 18:03:28 +0200 Subject: [PATCH 2/3] impl suggestions from @SirYwell Co-authored-by: Hannes Greule --- .../worldedit/command/SelectionCommands.java | 148 +++++------------- 1 file changed, 40 insertions(+), 108 deletions(-) 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 0bba824796..54c0e5686f 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,8 +21,10 @@ import com.fastasyncworldedit.core.configuration.Caption; import com.fastasyncworldedit.core.extent.clipboard.URIClipboardHolder; +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.math.MutableBlockVector3; +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; @@ -49,7 +51,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; @@ -519,7 +520,7 @@ 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 { // Avoid checking blocks outside the original region but within the cuboid region @@ -527,118 +528,49 @@ public void trim(Actor actor, World world, LocalSession session, if (!(originalRegion instanceof CuboidRegion)) { mask = new MaskIntersection(new RegionMask(originalRegion), mask); } + //FAWE start + 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; - - MutableBlockVector3 mutable = new MutableBlockVector3(); - 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++) { - mutable.setComponents(x, y, z); - - if (mask.test(mutable)) { - found = true; - minY = y; - - break outer; - } - } - } - } - - // 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++) { - mutable.setComponents(x, y, z); - - if (mask.test(mutable)) { - maxY = y; - break outer; - } - } - } - } - - 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++) { - mutable.setComponents(x, y, z); - - if (mask.test(mutable)) { - minX = x; - break outer; - } - } - } - } - - 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++) { - mutable.setComponents(x, y, z); - - if (mask.test(mutable)) { - maxX = x; - break outer; - } - } - } - } - - 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++) { - mutable.setComponents(x, y, z); - - if (mask.test(mutable)) { - minZ = z; - break outer; - } - } - } - } - - 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++) { - mutable.setComponents(x, y, z); - - if (mask.test(mutable)) { - maxZ = z; - break outer; - } - } - } - } + final CuboidRegion region = originalRegion.getBoundingBox(); + + final BlockVector3 min = region.getMinimumPoint(); + final BlockVector3 max = region.getMaximumPoint(); + + final int[] values = new int[]{ + min.x(), + max.x(), + min.y(), + max.y(), + min.z(), + max.z() + }; + + editSession.apply( + region, new MaskFilter<>( + new Filter() { + @Override + public void applyBlock(final FilterBlock block) { + values[0] = Math.min(values[0], block.x()); + values[1] = Math.max(values[1], block.x()); + values[2] = Math.min(values[2], block.y()); + values[3] = Math.max(values[3], block.y()); + values[4] = Math.min(values[4], block.z()); + values[5] = Math.max(values[5], block.z()); + } + }, mask + ), true + ); final CuboidRegionSelector selector; if (session.getRegionSelector(world) instanceof ExtendingCuboidRegionSelector) { - selector = new ExtendingCuboidRegionSelector(world, BlockVector3.at(minX, minY, minZ), BlockVector3.at(maxX, maxY, maxZ)); + selector = new ExtendingCuboidRegionSelector(world, BlockVector3.at(values[0], values[2], values[4]), + BlockVector3.at(values[1], values[3], values[5])); } else { - selector = new CuboidRegionSelector(world, BlockVector3.at(minX, minY, minZ), BlockVector3.at(maxX, maxY, maxZ)); + selector = new CuboidRegionSelector(world, BlockVector3.at(values[0], values[2], values[4]), + BlockVector3.at(values[1], values[3], values[5])); } + //FAWE end session.setRegionSelector(world, selector); session.getRegionSelector(world).learnChanges(); From 895ed4309a10b1e6087c3a06ff70c563b0d433bc Mon Sep 17 00:00:00 2001 From: SirYwell Date: Thu, 10 Apr 2025 12:07:12 +0200 Subject: [PATCH 3/3] rework filtering, re-add no match check --- .../worldedit/command/SelectionCommands.java | 109 ++++++++++++------ 1 file changed, 76 insertions(+), 33 deletions(-) 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 54c0e5686f..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,6 +21,7 @@ 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; @@ -523,52 +524,94 @@ private BlockVector3[] getChangesForEachDir(int amount, boolean onlyHorizontal, 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); - } - //FAWE start new MaskTraverser(mask).setNewExtent(editSession); // Result region will be cuboid final CuboidRegion region = originalRegion.getBoundingBox(); - final BlockVector3 min = region.getMinimumPoint(); + // subtract offset to determine if there was any change later + final BlockVector3 min = region.getMinimumPoint().subtract(BlockVector3.ONE); final BlockVector3 max = region.getMaximumPoint(); - final int[] values = new int[]{ - min.x(), - max.x(), - min.y(), - max.y(), - min.z(), - max.z() - }; - - editSession.apply( - region, new MaskFilter<>( - new Filter() { - @Override - public void applyBlock(final FilterBlock block) { - values[0] = Math.min(values[0], block.x()); - values[1] = Math.max(values[1], block.x()); - values[2] = Math.min(values[2], block.y()); - values[3] = Math.max(values[3], block.y()); - values[4] = Math.min(values[4], block.z()); - values[5] = Math.max(values[5], block.z()); - } - }, mask - ), true - ); + 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(); + } + + 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; + } + + @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()); + } + + @Override + public TrimFilter init() { + return new TrimFilter(this, this.minX, this.minY, this.minZ, this.maxX, this.maxY, this.maxZ); + } + + @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); + } + + } + 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(values[0], values[2], values[4]), - BlockVector3.at(values[1], values[3], values[5])); + selector = new ExtendingCuboidRegionSelector(world, newMin, newMax); } else { - selector = new CuboidRegionSelector(world, BlockVector3.at(values[0], values[2], values[4]), - BlockVector3.at(values[1], values[3], values[5])); + selector = new CuboidRegionSelector(world, newMin, newMax); } //FAWE end session.setRegionSelector(world, selector);