Some tweaks to fuzzy region select

This commit is contained in:
Jesse Boyd 2016-12-13 15:01:43 +11:00
parent f16ebf4f77
commit 64d7052d5f
No known key found for this signature in database
GPG Key ID: 59F1DE6293AF6E1F
6 changed files with 153 additions and 67 deletions

View File

@ -4,7 +4,6 @@ import com.boydti.fawe.FaweCache;
import com.boydti.fawe.config.BBC; import com.boydti.fawe.config.BBC;
import com.boydti.fawe.object.FaweLimit; import com.boydti.fawe.object.FaweLimit;
import com.boydti.fawe.object.RegionWrapper; import com.boydti.fawe.object.RegionWrapper;
import com.boydti.fawe.util.MainUtil;
import com.boydti.fawe.util.WEManager; import com.boydti.fawe.util.WEManager;
import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.Vector;
@ -32,6 +31,10 @@ public class ProcessedWEExtent extends FaweRegionExtent {
this.extent = (AbstractDelegateExtent) parent; this.extent = (AbstractDelegateExtent) parent;
} }
public void setLimit(FaweLimit other) {
this.limit.set(other);
}
@Override @Override
public Entity createEntity(final Location location, final BaseEntity entity) { public Entity createEntity(final Location location, final BaseEntity entity) {
if (entity == null) { if (entity == null) {

View File

@ -1,15 +1,13 @@
package com.boydti.fawe.object.regions; package com.boydti.fawe.object.regions;
import com.boydti.fawe.object.visitor.FuzzySearch;
import com.boydti.fawe.util.MathMan; import com.boydti.fawe.util.MathMan;
import com.sk89q.worldedit.BlockVector; import com.sk89q.worldedit.BlockVector;
import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.EditSession;
import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.RegionFunction;
import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.operation.Operations; 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.AbstractRegion;
import com.sk89q.worldedit.regions.RegionOperationException; import com.sk89q.worldedit.regions.RegionOperationException;
import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.World;
@ -41,53 +39,14 @@ public class FuzzyRegion extends AbstractRegion {
return mask; 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 @Override
public int getArea() { public int getArea() {
return set.cardinality(); return set.cardinality();
} }
public void select(int x, int y, int z) { public void select(int x, int y, int z) {
RecursiveVisitor visitor = new RecursiveVisitor(mask, new RegionFunction() { FuzzySearch search = new FuzzySearch(this, extent, new Vector(x, y, z));
@Override Operations.completeBlindly(search);
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);
} }
@Override @Override
@ -105,13 +64,13 @@ public class FuzzyRegion extends AbstractRegion {
@Override @Override
public BlockVector next() { public BlockVector next() {
int b1 = ((byte) index) & 0xFF; int b1 = (index & 0xFF);
int b2 = ((byte) (index >> 8)) & 0xFF; int b2 = ((byte) (index >> 8)) & 0x7F;
int b3 = ((byte)(index >> 16)) & 0xFF; int b3 = ((byte)(index >> 15)) & 0xFF;
byte b4 = (byte) (index >> 24); int b4 = ((byte) (index >> 23)) & 0xFF;
pos.x = offsetX + (((b2 + ((MathMan.unpair8x(b4)) << 8)) << 21) >> 21); pos.x = offsetX + (((b3 + ((MathMan.unpair8x(b2)) << 8)) << 21) >> 21);
pos.y = offsetY + b1; 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; return pos;
} }
@ -124,8 +83,8 @@ public class FuzzyRegion extends AbstractRegion {
public void set(int x, int y, int z) throws RegionOperationException{ public void set(int x, int y, int z) throws RegionOperationException{
if (populated) { if (populated) {
if (++count > 1048576) { if (++count > 16777216) {
throw new RegionOperationException("Selection is too large! (1048576 blocks)"); throw new RegionOperationException("Selection is too large! (16777216 blocks)");
} }
x -= offsetX; x -= offsetX;
y -= offsetY; y -= offsetY;
@ -137,7 +96,7 @@ public class FuzzyRegion extends AbstractRegion {
z = 0; z = 0;
populated = true; 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) { if (x >= 1024 || x <= -1024 || z >= 1024 || z <= -1024) {
throw new RegionOperationException("Selection is too large! (1024 blocks wide)"); 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) { public boolean contains(int x, int y, int z) {
try { 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) { } catch (IndexOutOfBoundsException e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
@ -171,12 +130,12 @@ public class FuzzyRegion extends AbstractRegion {
@Override @Override
public Vector getMinimumPoint() { public Vector getMinimumPoint() {
return new Vector(minX, minY, minZ); return new Vector(minX + offsetX, minY + offsetY, minZ + offsetZ);
} }
@Override @Override
public Vector getMaximumPoint() { public Vector getMaximumPoint() {
return new Vector(maxX, maxY, maxZ); return new Vector(maxX + offsetX, maxY + offsetY, maxZ + offsetZ);
} }
@Override @Override

View File

@ -14,7 +14,6 @@ import com.sk89q.worldedit.Vector;
import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.entity.Player;
import com.sk89q.worldedit.extension.platform.Actor; import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extent.AbstractDelegateExtent; import com.sk89q.worldedit.extent.AbstractDelegateExtent;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.regions.RegionSelector; import com.sk89q.worldedit.regions.RegionSelector;
@ -35,7 +34,7 @@ public class FuzzyRegionSelector extends AbstractDelegateExtent implements Regio
.player(FawePlayer.wrap(player)) .player(FawePlayer.wrap(player))
.changeSetNull() .changeSetNull()
.checkMemory(false) .checkMemory(false)
.autoQueue(false) .autoQueue(true)
.build()); .build());
this.player = player; this.player = player;
this.region = new FuzzyRegion(world, getExtent(), mask); this.region = new FuzzyRegion(world, getExtent(), mask);
@ -55,7 +54,7 @@ public class FuzzyRegionSelector extends AbstractDelegateExtent implements Regio
.player(FawePlayer.wrap(player)) .player(FawePlayer.wrap(player))
.changeSetNull() .changeSetNull()
.checkMemory(false) .checkMemory(false)
.autoQueue(false) .autoQueue(true)
.build(); .build();
new ExtentTraverser(this).setNext(extent); new ExtentTraverser(this).setNext(extent);
this.region.setWorld(world); this.region.setWorld(world);
@ -69,13 +68,10 @@ public class FuzzyRegionSelector extends AbstractDelegateExtent implements Regio
@Override @Override
public boolean selectPrimary(Vector position, SelectorLimits limits) { public boolean selectPrimary(Vector position, SelectorLimits limits) {
setWorld(getWorld());
new MaskTraverser(getMask()).reset(getExtent());
positions.clear(); positions.clear();
positions.add(position); 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 = new FuzzyRegion(getWorld(), getExtent(), getMask());
this.region.select((int) position.x, (int) position.y, (int) position.z); this.region.select((int) position.x, (int) position.y, (int) position.z);
return true; return true;

View File

@ -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<String> messages) {
messages.add(BBC.VISITOR_BLOCK.format(getAffected()));
}
}

View File

@ -68,6 +68,20 @@ public class MathMan {
return (short) ((x & 15) << 12 | (z & 15) << 8 | y); 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) { public static final long chunkXZ2Int(int x, int z) {
return (long)x & 4294967295L | ((long)z & 4294967295L) << 32; return (long)x & 4294967295L | ((long)z & 4294967295L) << 32;
} }
@ -96,11 +110,11 @@ public class MathMan {
return (byte) (x + (y << 3)); return (byte) (x + (y << 3));
} }
public static byte unpair8x(byte value) { public static byte unpair8x(int value) {
return (byte) (value & 0x7); return (byte) (value & 0x7);
} }
public static byte unpair8y(byte value) { public static byte unpair8y(int value) {
return (byte) ((value >> 3) & 0x7F); return (byte) ((value >> 3) & 0x7F);
} }

View File

@ -20,6 +20,14 @@ public class LocationMaskedPlayerWrapper extends PlayerWrapper {
this.allowTeleport = allowTeleport; this.allowTeleport = allowTeleport;
} }
public static Player unwrap(Player object) {
if (object instanceof LocationMaskedPlayerWrapper) {
return ((LocationMaskedPlayerWrapper) object).getParent();
} else {
return object;
}
}
@Override @Override
public double getYaw() { public double getYaw() {
return position.getYaw(); return position.getYaw();