From 64d7052d5fe7694baaab3be9d5e99897abce04e9 Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Tue, 13 Dec 2016 15:01:43 +1100 Subject: [PATCH] Some tweaks to fuzzy region select --- .../fawe/object/extent/ProcessedWEExtent.java | 5 +- .../fawe/object/regions/FuzzyRegion.java | 71 +++--------- .../regions/selector/FuzzyRegionSelector.java | 12 +- .../fawe/object/visitor/FuzzySearch.java | 106 ++++++++++++++++++ .../java/com/boydti/fawe/util/MathMan.java | 18 ++- .../wrappers/LocationMaskedPlayerWrapper.java | 8 ++ 6 files changed, 153 insertions(+), 67 deletions(-) create mode 100644 core/src/main/java/com/boydti/fawe/object/visitor/FuzzySearch.java diff --git a/core/src/main/java/com/boydti/fawe/object/extent/ProcessedWEExtent.java b/core/src/main/java/com/boydti/fawe/object/extent/ProcessedWEExtent.java index 13dd5fb8..8d1717ba 100644 --- a/core/src/main/java/com/boydti/fawe/object/extent/ProcessedWEExtent.java +++ b/core/src/main/java/com/boydti/fawe/object/extent/ProcessedWEExtent.java @@ -4,7 +4,6 @@ import com.boydti.fawe.FaweCache; import com.boydti.fawe.config.BBC; import com.boydti.fawe.object.FaweLimit; import com.boydti.fawe.object.RegionWrapper; -import com.boydti.fawe.util.MainUtil; import com.boydti.fawe.util.WEManager; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.Vector; @@ -32,6 +31,10 @@ public class ProcessedWEExtent extends FaweRegionExtent { this.extent = (AbstractDelegateExtent) parent; } + public void setLimit(FaweLimit other) { + this.limit.set(other); + } + @Override public Entity createEntity(final Location location, final BaseEntity entity) { if (entity == null) { diff --git a/core/src/main/java/com/boydti/fawe/object/regions/FuzzyRegion.java b/core/src/main/java/com/boydti/fawe/object/regions/FuzzyRegion.java index b2037023..d46cc443 100644 --- a/core/src/main/java/com/boydti/fawe/object/regions/FuzzyRegion.java +++ b/core/src/main/java/com/boydti/fawe/object/regions/FuzzyRegion.java @@ -1,15 +1,13 @@ package com.boydti.fawe.object.regions; +import com.boydti.fawe.object.visitor.FuzzySearch; import com.boydti.fawe.util.MathMan; import com.sk89q.worldedit.BlockVector; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.function.RegionFunction; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.operation.Operations; -import com.sk89q.worldedit.function.visitor.RecursiveVisitor; import com.sk89q.worldedit.regions.AbstractRegion; import com.sk89q.worldedit.regions.RegionOperationException; import com.sk89q.worldedit.world.World; @@ -41,53 +39,14 @@ public class FuzzyRegion extends AbstractRegion { return mask; } - private static int pair(int x, int y, int z) { - byte b1 = (byte) y; - byte b2 = (byte) (x); - byte b3 = (byte) (z); - int x16 = (x >> 8) & 0x7; - int z16 = (z >> 8) & 0x7; - byte b4 = MathMan.pair8(x16, z16); - return ((b1 & 0xFF) - + ((b2 & 0xFF) << 8) - + ((b3 & 0xFF) << 16) - + ((b4 & 0x7F) << 24)) - ; - } - @Override public int getArea() { return set.cardinality(); } public void select(int x, int y, int z) { - RecursiveVisitor visitor = new RecursiveVisitor(mask, new RegionFunction() { - @Override - public boolean apply(Vector position) throws WorldEditException { - return true; - } - }) { - @Override - public boolean isVisited(Node node) { - return contains(node.getX(), node.getY(), node.getZ()); - } - - @Override - public void addVisited(Node node, int depth) { - try { - set(node.getX(), node.getY(), node.getZ()); - } catch (RegionOperationException e) { - throw new RuntimeException(e); - } - } - - @Override - public void cleanVisited(int layer) { - // Do nothing - } - }; - visitor.visit(new Vector(x, y, z)); - Operations.completeBlindly(visitor); + FuzzySearch search = new FuzzySearch(this, extent, new Vector(x, y, z)); + Operations.completeBlindly(search); } @Override @@ -105,13 +64,13 @@ public class FuzzyRegion extends AbstractRegion { @Override public BlockVector next() { - int b1 = ((byte) index) & 0xFF; - int b2 = ((byte) (index >> 8)) & 0xFF; - int b3 = ((byte)(index >> 16)) & 0xFF; - byte b4 = (byte) (index >> 24); - pos.x = offsetX + (((b2 + ((MathMan.unpair8x(b4)) << 8)) << 21) >> 21); + int b1 = (index & 0xFF); + int b2 = ((byte) (index >> 8)) & 0x7F; + int b3 = ((byte)(index >> 15)) & 0xFF; + int b4 = ((byte) (index >> 23)) & 0xFF; + pos.x = offsetX + (((b3 + ((MathMan.unpair8x(b2)) << 8)) << 21) >> 21); pos.y = offsetY + b1; - pos.z = offsetZ + (((b3 + ((MathMan.unpair8y(b4)) << 8)) << 21) >> 21); + pos.z = offsetZ + (((b4 + ((MathMan.unpair8y(b2)) << 8)) << 21) >> 21); return pos; } @@ -124,8 +83,8 @@ public class FuzzyRegion extends AbstractRegion { public void set(int x, int y, int z) throws RegionOperationException{ if (populated) { - if (++count > 1048576) { - throw new RegionOperationException("Selection is too large! (1048576 blocks)"); + if (++count > 16777216) { + throw new RegionOperationException("Selection is too large! (16777216 blocks)"); } x -= offsetX; y -= offsetY; @@ -137,7 +96,7 @@ public class FuzzyRegion extends AbstractRegion { z = 0; populated = true; } - set.set(pair(x, y, z), true); + set.set(MathMan.tripleSearchCoords(x, y, z), true); if (x >= 1024 || x <= -1024 || z >= 1024 || z <= -1024) { throw new RegionOperationException("Selection is too large! (1024 blocks wide)"); } @@ -163,7 +122,7 @@ public class FuzzyRegion extends AbstractRegion { public boolean contains(int x, int y, int z) { try { - return set.get(pair(x - offsetX, y - offsetY, z - offsetZ)); + return set.get(MathMan.tripleSearchCoords(x - offsetX, y - offsetY, z - offsetZ)); } catch (IndexOutOfBoundsException e) { throw new RuntimeException(e); } @@ -171,12 +130,12 @@ public class FuzzyRegion extends AbstractRegion { @Override public Vector getMinimumPoint() { - return new Vector(minX, minY, minZ); + return new Vector(minX + offsetX, minY + offsetY, minZ + offsetZ); } @Override public Vector getMaximumPoint() { - return new Vector(maxX, maxY, maxZ); + return new Vector(maxX + offsetX, maxY + offsetY, maxZ + offsetZ); } @Override diff --git a/core/src/main/java/com/boydti/fawe/object/regions/selector/FuzzyRegionSelector.java b/core/src/main/java/com/boydti/fawe/object/regions/selector/FuzzyRegionSelector.java index 4db634a7..6fed8565 100644 --- a/core/src/main/java/com/boydti/fawe/object/regions/selector/FuzzyRegionSelector.java +++ b/core/src/main/java/com/boydti/fawe/object/regions/selector/FuzzyRegionSelector.java @@ -14,7 +14,6 @@ import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extent.AbstractDelegateExtent; -import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.RegionSelector; @@ -35,7 +34,7 @@ public class FuzzyRegionSelector extends AbstractDelegateExtent implements Regio .player(FawePlayer.wrap(player)) .changeSetNull() .checkMemory(false) - .autoQueue(false) + .autoQueue(true) .build()); this.player = player; this.region = new FuzzyRegion(world, getExtent(), mask); @@ -55,7 +54,7 @@ public class FuzzyRegionSelector extends AbstractDelegateExtent implements Regio .player(FawePlayer.wrap(player)) .changeSetNull() .checkMemory(false) - .autoQueue(false) + .autoQueue(true) .build(); new ExtentTraverser(this).setNext(extent); this.region.setWorld(world); @@ -69,13 +68,10 @@ public class FuzzyRegionSelector extends AbstractDelegateExtent implements Regio @Override public boolean selectPrimary(Vector position, SelectorLimits limits) { + setWorld(getWorld()); + new MaskTraverser(getMask()).reset(getExtent()); positions.clear(); positions.add(position); - Extent extent = getExtent(); - if (extent instanceof EditSession) { - ((EditSession) extent).resetLimit(); - } - new MaskTraverser(getMask()).reset(extent); this.region = new FuzzyRegion(getWorld(), getExtent(), getMask()); this.region.select((int) position.x, (int) position.y, (int) position.z); return true; diff --git a/core/src/main/java/com/boydti/fawe/object/visitor/FuzzySearch.java b/core/src/main/java/com/boydti/fawe/object/visitor/FuzzySearch.java new file mode 100644 index 00000000..3b34b11d --- /dev/null +++ b/core/src/main/java/com/boydti/fawe/object/visitor/FuzzySearch.java @@ -0,0 +1,106 @@ +package com.boydti.fawe.object.visitor; + +import com.boydti.fawe.config.BBC; +import com.boydti.fawe.object.collection.SparseBitSet; +import com.boydti.fawe.object.regions.FuzzyRegion; +import com.boydti.fawe.util.MathMan; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.operation.Operation; +import com.sk89q.worldedit.function.operation.RunContext; +import com.sk89q.worldedit.regions.RegionOperationException; +import java.util.List; + +public class FuzzySearch implements Operation { + + private final FuzzyRegion region; + private final SparseBitSet visited; + private final SparseBitSet queue; + private final int offsetZ; + private final int offsetX; + private final Extent extent; + private final int maxY; + private int affected; + + public FuzzySearch(FuzzyRegion region, Extent extent, Vector origin) { + this.region = region; + this.queue = new SparseBitSet(); + this.visited = new SparseBitSet(); + this.offsetX = origin.getBlockX(); + this.offsetZ = origin.getBlockZ(); + this.queue.set(MathMan.tripleSearchCoords(0, origin.getBlockY(), 0)); + this.extent = extent; + this.maxY = extent.getMaximumPoint().getBlockY(); + } + + private boolean hasVisited(int x, int y, int z) { + return visited.get(MathMan.tripleSearchCoords(x - offsetX, y, z - offsetZ)); + } + + private void queueVisit(int x, int y, int z) throws RegionOperationException { + if (y < 0 || y > maxY) { + return; + } + int ox = x - offsetX; + if (ox >= 1024 || ox < -1024) { + throw new RegionOperationException("Selection is too large! (1024 blocks wide)"); + } + int oz = z - offsetZ; + if (oz >= 1024 || oz < -1024) { + throw new RegionOperationException("Selection is too large! (1024 blocks wide)"); + } + int index = MathMan.tripleSearchCoords(ox, y, oz); + if (!visited.get(index)) { + visited.set(index); + queue.set(index); + } + } + + @Override + public Operation resume(RunContext run) throws WorldEditException { + Vector pos = new Vector(); + Mask mask = region.getMask(); + int index = 0; + while ((index = queue.nextSetBit(index)) != -1 || (index = queue.nextSetBit(0)) != -1) { + queue.clear(index); + int b1 = (index & 0xFF); + int b2 = ((byte) (index >> 8)) & 0x7F; + int b3 = ((byte)(index >> 15)) & 0xFF; + int b4 = ((byte) (index >> 23)) & 0xFF; + int x = offsetX + (((b3 + ((MathMan.unpair8x(b2)) << 8)) << 21) >> 21); + int y = b1; + int z = offsetZ + (((b4 + ((MathMan.unpair8y(b2)) << 8)) << 21) >> 21); + pos.x = x; + pos.y = y; + pos.z = z; + if (mask.test(pos)) { + affected++; + region.set(x, y, z); + queueVisit(x + 1, y, z); + queueVisit(x - 1, y, z); + queueVisit(x, y + 1, z); + queueVisit(x, y - 1, z); + queueVisit(x, y, z + 1); + queueVisit(x, y, z - 1); + } + } + return null; + } + + @Override + public void cancel() { + + } + + public int getAffected() { + return affected; + } + + @Override + public void addStatusMessages(List messages) { + messages.add(BBC.VISITOR_BLOCK.format(getAffected())); + } + +} \ No newline at end of file diff --git a/core/src/main/java/com/boydti/fawe/util/MathMan.java b/core/src/main/java/com/boydti/fawe/util/MathMan.java index 9b96bd20..e8a15b94 100644 --- a/core/src/main/java/com/boydti/fawe/util/MathMan.java +++ b/core/src/main/java/com/boydti/fawe/util/MathMan.java @@ -68,6 +68,20 @@ public class MathMan { return (short) ((x & 15) << 12 | (z & 15) << 8 | y); } + public static int tripleSearchCoords(int x, int y, int z) { + byte b1 = (byte) y; + byte b3 = (byte) (x); + byte b4 = (byte) (z); + int x16 = (x >> 8) & 0x7; + int z16 = (z >> 8) & 0x7; + byte b2 = MathMan.pair8(x16, z16); + return ((b1 & 0xFF) + + ((b2 & 0x7F) << 8) + + ((b3 & 0xFF) << 15) + + ((b4 & 0xFF) << 23)) + ; + } + public static final long chunkXZ2Int(int x, int z) { return (long)x & 4294967295L | ((long)z & 4294967295L) << 32; } @@ -96,11 +110,11 @@ public class MathMan { return (byte) (x + (y << 3)); } - public static byte unpair8x(byte value) { + public static byte unpair8x(int value) { return (byte) (value & 0x7); } - public static byte unpair8y(byte value) { + public static byte unpair8y(int value) { return (byte) ((value >> 3) & 0x7F); } diff --git a/core/src/main/java/com/boydti/fawe/wrappers/LocationMaskedPlayerWrapper.java b/core/src/main/java/com/boydti/fawe/wrappers/LocationMaskedPlayerWrapper.java index fcbd4d89..038dabbe 100644 --- a/core/src/main/java/com/boydti/fawe/wrappers/LocationMaskedPlayerWrapper.java +++ b/core/src/main/java/com/boydti/fawe/wrappers/LocationMaskedPlayerWrapper.java @@ -20,6 +20,14 @@ public class LocationMaskedPlayerWrapper extends PlayerWrapper { this.allowTeleport = allowTeleport; } + public static Player unwrap(Player object) { + if (object instanceof LocationMaskedPlayerWrapper) { + return ((LocationMaskedPlayerWrapper) object).getParent(); + } else { + return object; + } + } + @Override public double getYaw() { return position.getYaw();