From ebb1e6613ce9dbf93ad7283dd7641d1ecdbcd3d2 Mon Sep 17 00:00:00 2001 From: SirYwell Date: Fri, 2 Jan 2026 11:37:11 +0100 Subject: [PATCH 1/2] Improve BlendBall performance using custom Filter --- .../core/command/tool/brush/BlendBall.java | 167 ++++++++++-------- 1 file changed, 94 insertions(+), 73 deletions(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/BlendBall.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/BlendBall.java index ec3e0766ec..669b0d0e10 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/BlendBall.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/BlendBall.java @@ -1,12 +1,16 @@ package com.fastasyncworldedit.core.command.tool.brush; +import com.fastasyncworldedit.core.extent.filter.block.FilterBlock; import com.fastasyncworldedit.core.function.mask.CachedMask; import com.fastasyncworldedit.core.math.MutableBlockVector3; +import com.fastasyncworldedit.core.queue.Filter; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.command.tool.brush.Brush; +import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockTypes; @@ -54,89 +58,106 @@ public void build(EditSession editSession, BlockVector3 position, Pattern patter int ty = position.y(); int tz = position.z(); - int[] frequency = new int[BlockTypes.size()]; + final CuboidRegion region = new CuboidRegion( + BlockVector3.at(tx - outsetSize, ty - outsetSize, tz - outsetSize), + BlockVector3.at(tx + outsetSize, ty + outsetSize, tz + outsetSize) + ); - int maxY = editSession.getMaxY(); - int minY = editSession.getMinY(); + editSession.apply(region, new BlendBallFilter((int) brushSizeSquared, tx, ty, tz), true); + } - MutableBlockVector3 mutable = new MutableBlockVector3(); - for (int x = -outsetSize; x <= outsetSize; x++) { - int x0 = x + tx; - int xx = x * x; - for (int y = -outsetSize; y <= outsetSize; y++) { - int y0 = y + ty; - if (y0 + 1 < minY || y0 - 1 > maxY) { - continue; - } - int yy = y * y; - int xxyy = xx + yy; - if (xxyy >= brushSizeSquared) { - continue; - } - for (int z = -outsetSize; z <= outsetSize; z++) { - int z0 = z + tz; - if (xxyy + z * z >= brushSizeSquared || maskFails(editSession, mutable.setComponents(x0, y0, z0))) { - continue; - } - int highest = 1, currentBlockFrequency = 1; - BlockState currentState = editSession.getBlock(x0, y0, z0); - BlockState highestState = currentState; - int currentStateID = currentState.getInternalBlockTypeId(); - Arrays.fill(frequency, 0); - int air = 0; - int total = 26; - boolean tie = false; - for (int ox = -1; ox <= 1; ox++) { - for (int oz = -1; oz <= 1; oz++) { - for (int oy = -1; oy <= 1; oy++) { - if (ox == 0 && oy == 0 && oz == 0) { - continue; - } else if (oy + y0 < minY || oy + y0 > maxY) { - total--; - continue; - } - boolean masked = maskFails(editSession, mutable.setComponents(x0 + ox, y0 + oy, z0 + oz)); - BlockState state = masked ? AIR : editSession.getBlock(x0 + ox, y0 + oy, z0 + oz); - if (state.getBlockType().getMaterial().isAir()) { - air++; - } - int internalID = state.getInternalBlockTypeId(); - int count = frequency[internalID]; - if (internalID == currentStateID) { - currentBlockFrequency++; - } - count++; - if (count - highest >= minFreqDiff) { - highest = count; - highestState = state; - tie = false; - } else if (count == highest) { - tie = true; - } - frequency[internalID] = count; - } + private boolean maskFails(Extent extent, BlockVector3 pos) { + return mask != null && !mask.test(extent, pos); + } + + private class BlendBallFilter implements Filter { + private final int[] frequency = new int[BlockTypes.size()]; + private final MutableBlockVector3 mutable = new MutableBlockVector3(); + private final int brushSizeSquared; + private final int xo; + private final int yo; + private final int zo; + + private BlendBallFilter(final int brushSizeSquared, final int xo, final int yo, final int zo) { + this.brushSizeSquared = brushSizeSquared; + this.xo = xo; + this.yo = yo; + this.zo = zo; + } + + @Override + public void applyBlock(final FilterBlock block) { + final Extent extent = block.getExtent(); + final int xr = block.x(); + final int yr = block.y(); + final int zr = block.z(); + int x = xr - this.xo; + int y = yr - this.yo; + int z = zr - this.zo; + if (x * x + y * y + z * z >= brushSizeSquared || maskFails(extent, block)) { + return; + } + int maxY = extent.getMaxY(); + int minY = extent.getMinY(); + int highest = 1, currentBlockFrequency = 1; + BlockState currentState = block.getBlock(); + BlockState highestState = currentState; + int currentStateID = currentState.getInternalBlockTypeId(); + Arrays.fill(frequency, 0); + int air = 0; + int total = 26; + boolean tie = false; + for (int ox = -1; ox <= 1; ox++) { + for (int oz = -1; oz <= 1; oz++) { + for (int oy = -1; oy <= 1; oy++) { + if (ox == 0 && oy == 0 && oz == 0) { + continue; + } else if (oy + yr < minY || oy + yr > maxY) { + total--; + continue; } - } - if (onlyAir) { - if (air * 2 - total >= minFreqDiff) { - if (!currentState.isAir()) { - editSession.setBlock(x0, y0, z0, AIR); - } - } else if (currentState.isAir() && total - 2 * air >= minFreqDiff) { - editSession.setBlock(x0, y0, z0, highestState); + boolean masked = maskFails(extent, mutable.setComponents(xr + ox, yr + oy, zr + oz)); + BlockState state = masked ? AIR : block.getBlock(xr + ox, yr + oy, zr + oz); + if (state.getBlockType().getMaterial().isAir()) { + air++; + } + int internalID = state.getInternalBlockTypeId(); + int count = frequency[internalID]; + if (internalID == currentStateID) { + currentBlockFrequency++; + } + count++; + if (count - highest >= minFreqDiff) { + highest = count; + highestState = state; + tie = false; + } else if (count == highest) { + tie = true; } - continue; + frequency[internalID] = count; } - if (highest - currentBlockFrequency >= minFreqDiff && !tie && currentState != highestState) { - editSession.setBlock(x0, y0, z0, highestState); + } + } + if (onlyAir) { + if (air * 2 - total >= minFreqDiff) { + if (!currentState.isAir()) { + block.setBlock(AIR); } + } else if (currentState.isAir() && total - 2 * air >= minFreqDiff) { + block.setBlock(highestState); } + return; + } + if (highest - currentBlockFrequency >= minFreqDiff && !tie && currentState != highestState) { + block.setBlock(highestState); } } - } - private boolean maskFails(EditSession editSession, MutableBlockVector3 mutable) { - return mask != null && !mask.test(editSession, mutable); + @Override + public Filter fork() { + return new BlendBallFilter(brushSizeSquared, xo, yo, zo); + } + } } From 9e8f43432212a290f3826fa7138a00764c04e1e0 Mon Sep 17 00:00:00 2001 From: SirYwell Date: Fri, 2 Jan 2026 11:46:58 +0100 Subject: [PATCH 2/2] better variable names --- .../core/command/tool/brush/BlendBall.java | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/BlendBall.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/BlendBall.java index 669b0d0e10..bae4e2badc 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/BlendBall.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/command/tool/brush/BlendBall.java @@ -74,27 +74,27 @@ private class BlendBallFilter implements Filter { private final int[] frequency = new int[BlockTypes.size()]; private final MutableBlockVector3 mutable = new MutableBlockVector3(); private final int brushSizeSquared; - private final int xo; - private final int yo; - private final int zo; + private final int centerX; + private final int centerY; + private final int centerZ; - private BlendBallFilter(final int brushSizeSquared, final int xo, final int yo, final int zo) { + private BlendBallFilter(final int brushSizeSquared, final int centerX, final int centerY, final int centerZ) { this.brushSizeSquared = brushSizeSquared; - this.xo = xo; - this.yo = yo; - this.zo = zo; + this.centerX = centerX; + this.centerY = centerY; + this.centerZ = centerZ; } @Override public void applyBlock(final FilterBlock block) { final Extent extent = block.getExtent(); - final int xr = block.x(); - final int yr = block.y(); - final int zr = block.z(); - int x = xr - this.xo; - int y = yr - this.yo; - int z = zr - this.zo; - if (x * x + y * y + z * z >= brushSizeSquared || maskFails(extent, block)) { + final int gx = block.x(); + final int gy = block.y(); + final int gz = block.z(); + int dx = gx - this.centerX; + int dy = gy - this.centerY; + int dz = gz - this.centerZ; + if (dx * dx + dy * dy + dz * dz >= brushSizeSquared || maskFails(extent, block)) { return; } int maxY = extent.getMaxY(); @@ -112,12 +112,12 @@ public void applyBlock(final FilterBlock block) { for (int oy = -1; oy <= 1; oy++) { if (ox == 0 && oy == 0 && oz == 0) { continue; - } else if (oy + yr < minY || oy + yr > maxY) { + } else if (oy + gy < minY || oy + gy > maxY) { total--; continue; } - boolean masked = maskFails(extent, mutable.setComponents(xr + ox, yr + oy, zr + oz)); - BlockState state = masked ? AIR : block.getBlock(xr + ox, yr + oy, zr + oz); + boolean masked = maskFails(extent, mutable.setComponents(gx + ox, gy + oy, gz + oz)); + BlockState state = masked ? AIR : block.getBlock(gx + ox, gy + oy, gz + oz); if (state.getBlockType().getMaterial().isAir()) { air++; } @@ -155,7 +155,7 @@ public void applyBlock(final FilterBlock block) { @Override public Filter fork() { - return new BlendBallFilter(brushSizeSquared, xo, yo, zo); + return new BlendBallFilter(brushSizeSquared, centerX, centerY, centerZ); } }