scanchunk

This commit is contained in:
Jesse Boyd 2019-05-06 15:57:12 +10:00
parent d603f45063
commit 459629a2f2
No known key found for this signature in database
GPG Key ID: 59F1DE6293AF6E1F
9 changed files with 231 additions and 101 deletions

View File

@ -181,13 +181,12 @@ public abstract class QueueHandler implements Trimable, Runnable {
// Initialize
chunk.init(queue, X, Z);
chunk = newFilter.applyChunk(chunk, region);
if (chunk == null) continue;
if (block == null) block = queue.initFilterBlock();
chunk.filter(newFilter, block, region, mbv1, mbv2);
IChunk newChunk = newFilter.applyChunk(chunk, region);
if (newChunk != null) {
chunk = newChunk;
if (block == null) block = queue.initFilterBlock();
chunk.filter(newFilter, block, region, mbv1, mbv2);
}
queue.submit(chunk);
}
queue.flush();

View File

@ -19,10 +19,8 @@ public class FuzzyRegion extends AbstractRegion {
private final Mask mask;
private BlockVectorSet set = new BlockVectorSet();
private boolean populated;
private int minX, minY, minZ, maxX, maxY, maxZ;
private Extent extent;
private int count = 0;
{
minX = minY = minZ = Integer.MAX_VALUE;
@ -59,7 +57,7 @@ public class FuzzyRegion extends AbstractRegion {
@Override
public Iterator<BlockVector3> iterator() {
return (Iterator) set.iterator();
return set.iterator();
}
private final void setMinMax(int x, int y, int z) {

View File

@ -6,6 +6,7 @@ import com.sk89q.worldedit.function.mask.Mask;
import com.sk89q.worldedit.function.visitor.RecursiveVisitor;
import com.sk89q.worldedit.math.BlockVector3;
import java.util.Arrays;
import java.util.Collection;
@ -39,14 +40,14 @@ public class AboveVisitor extends RecursiveVisitor {
this.baseY = baseY;
Collection<BlockVector3> directions = getDirections();
directions.clear();
directions.add(BlockVector3.at(1, 0, 0));
directions.add(BlockVector3.at(-1, 0, 0));
directions.add(BlockVector3.at(0, 0, 1));
directions.add(BlockVector3.at(0, 0, -1));
directions.add(BlockVector3.at(0, 1, 0));
directions.add(BlockVector3.at(0, -1, 0));
setDirections(
BlockVector3.at(1, 0, 0),
BlockVector3.at(-1, 0, 0),
BlockVector3.at(0, 0, 1),
BlockVector3.at(0, 0, -1),
BlockVector3.at(0, 1, 0),
BlockVector3.at(0, -1, 0)
);
}
@Override

View File

@ -23,6 +23,7 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Queue;
import java.util.Set;
@ -73,7 +74,7 @@ public abstract class BreadthFirstSearch implements Operation {
}
private final RegionFunction function;
private List<BlockVector3> directions = new ArrayList<>();
private BlockVector3[] directions;
private BlockVectorSet visited;
private final MappedFaweQueue mFaweQueue;
private BlockVectorSet queue;
@ -96,21 +97,16 @@ public abstract class BreadthFirstSearch implements Operation {
this.queue = new BlockVectorSet();
this.visited = new BlockVectorSet();
this.function = function;
this.directions.addAll(Arrays.asList(DEFAULT_DIRECTIONS));
this.directions = DEFAULT_DIRECTIONS;
this.maxDepth = maxDepth;
}
public void setDirections(List<BlockVector3> directions) {
public void setDirections(BlockVector3... directions) {
this.directions = directions;
}
private IntegerTrio[] getIntDirections() {
IntegerTrio[] array = new IntegerTrio[directions.size()];
for (int i = 0; i < array.length; i++) {
BlockVector3 dir = directions.get(i);
array[i] = new IntegerTrio(dir.getBlockX(), dir.getBlockY(), dir.getBlockZ());
}
return array;
public void setDirections(Collection<BlockVector3> directions) {
setDirections(directions.toArray(new BlockVector3[0]));
}
/**
@ -121,34 +117,36 @@ public abstract class BreadthFirstSearch implements Operation {
* unit vectors. An example of a valid direction is
* {@code BlockVector3.at(1, 0, 1)}.</p>
*
* <p>The list of directions can be cleared.</p>
*
* @return the list of directions
*/
protected Collection<BlockVector3> getDirections() {
return directions;
public Collection<BlockVector3> getDirections() {
return Arrays.asList(directions);
}
/**
* Add the directions along the axes as directions to visit.
*/
protected void addAxes() {
directions.add(BlockVector3.at(0, -1, 0));
directions.add(BlockVector3.at(0, 1, 0));
directions.add(BlockVector3.at(-1, 0, 0));
directions.add(BlockVector3.at(1, 0, 0));
directions.add(BlockVector3.at(0, 0, -1));
directions.add(BlockVector3.at(0, 0, 1));
public void addAxes() {
HashSet<BlockVector3> set = new HashSet<>(Arrays.asList(directions));
set.add(BlockVector3.at(0, -1, 0));
set.add(BlockVector3.at(0, 1, 0));
set.add(BlockVector3.at(-1, 0, 0));
set.add(BlockVector3.at(1, 0, 0));
set.add(BlockVector3.at(0, 0, -1));
set.add(BlockVector3.at(0, 0, 1));
setDirections(set);
}
/**
* Add the diagonal directions as directions to visit.
*/
protected void addDiagonal() {
directions.add(BlockVector3.at(1, 0, 1));
directions.add(BlockVector3.at(-1, 0, -1));
directions.add(BlockVector3.at(1, 0, -1));
directions.add(BlockVector3.at(-1, 0, 1));
public void addDiagonal() {
HashSet<BlockVector3> set = new HashSet<>(Arrays.asList(directions));
set.add(BlockVector3.at(1, 0, 1));
set.add(BlockVector3.at(-1, 0, -1));
set.add(BlockVector3.at(1, 0, -1));
set.add(BlockVector3.at(-1, 0, 1));
setDirections(set);
}
public void visit(final BlockVector3 pos) {
@ -159,12 +157,6 @@ public abstract class BreadthFirstSearch implements Operation {
}
}
public void resetVisited() {
queue.clear();
visited.clear();
affected = 0;
}
public void setVisited(BlockVectorSet set) {
this.visited = set;
}
@ -180,21 +172,6 @@ public abstract class BreadthFirstSearch implements Operation {
public void setMaxBranch(int maxBranch) {
this.maxBranch = maxBranch;
}
/**
* Try to visit the given 'to' location.
*
* @param from the origin block
* @param to the block under question
*/
private void visit(BlockVector3 from, BlockVector3 to) {
BlockVector3 blockVector = to;
if (!visited.contains(blockVector)) {
visited.add(blockVector);
if (isVisitable(from, to)) {
queue.add(blockVector);
}
}
}
/**
* Return whether the given 'to' block should be visited, starting from the
@ -220,7 +197,7 @@ public abstract class BreadthFirstSearch implements Operation {
MutableBlockVector3 mutable = new MutableBlockVector3();
// MutableBlockVector3 mutable2 = new MutableBlockVector3();
boolean shouldTrim = false;
IntegerTrio[] dirs = getIntDirections();
BlockVector3[] dirs = directions;
BlockVectorSet tempQueue = new BlockVectorSet();
BlockVectorSet chunkLoadSet = new BlockVectorSet();
for (currentDepth = 0; !queue.isEmpty() && currentDepth <= maxDepth; currentDepth++) {
@ -228,11 +205,11 @@ public abstract class BreadthFirstSearch implements Operation {
int cx = Integer.MIN_VALUE;
int cz = Integer.MIN_VALUE;
for (BlockVector3 from : queue) {
for (IntegerTrio direction : dirs) {
int x = from.getBlockX() + direction.x;
int z = from.getBlockZ() + direction.z;
for (BlockVector3 direction : dirs) {
int x = from.getBlockX() + direction.getX();
int z = from.getBlockZ() + direction.getZ();
if (cx != (cx = x >> 4) || cz != (cz = z >> 4)) {
int y = from.getBlockY() + direction.y;
int y = from.getBlockY() + direction.getY();
if (y < 0 || y >= 256) {
continue;
}
@ -249,13 +226,13 @@ public abstract class BreadthFirstSearch implements Operation {
for (BlockVector3 from : queue) {
if (function.apply(from)) affected++;
for (int i = 0, j = 0; i < dirs.length && j < maxBranch; i++) {
IntegerTrio direction = dirs[i];
int y = from.getBlockY() + direction.y;
BlockVector3 direction = dirs[i];
int y = from.getBlockY() + direction.getY();
if (y < 0 || y >= 256) {
continue;
}
int x = from.getBlockX() + direction.x;
int z = from.getBlockZ() + direction.z;
int x = from.getBlockX() + direction.getX();
int z = from.getBlockZ() + direction.getZ();
if (!visited.contains(x, y, z)) {
if (isVisitable(from, BlockVector3.at(x, y, z))) {
j++;

View File

@ -51,14 +51,15 @@ public class DirectionalVisitor extends RecursiveVisitor {
checkNotNull(mask);
this.origin = origin;
this.dirVec = direction;
final Collection<BlockVector3> directions = this.getDirections();
directions.clear();
directions.add(BlockVector3.at(1, 0, 0));
directions.add(BlockVector3.at(-1, 0, 0));
directions.add(BlockVector3.at(0, 0, 1));
directions.add(BlockVector3.at(0, 0, -1));
directions.add(BlockVector3.at(0, -1, 0));
directions.add(BlockVector3.at(0, 1, 0));
setDirections(
BlockVector3.at(1, 0, 0),
BlockVector3.at(-1, 0, 0),
BlockVector3.at(0, 0, 1),
BlockVector3.at(0, 0, -1),
BlockVector3.at(0, -1, 0),
BlockVector3.at(0, 1, 0)
);
}
@Override

View File

@ -60,13 +60,13 @@ public class DownwardVisitor extends RecursiveVisitor {
checkNotNull(mask);
this.baseY = baseY;
Collection<BlockVector3> directions = getDirections();
directions.clear();
directions.add(BlockVector3.at(1, 0, 0));
directions.add(BlockVector3.at(-1, 0, 0));
directions.add(BlockVector3.at(0, 0, 1));
directions.add(BlockVector3.at(0, 0, -1));
directions.add(BlockVector3.at(0, -1, 0));
setDirections(
BlockVector3.at(1, 0, 0),
BlockVector3.at(-1, 0, 0),
BlockVector3.at(0, 0, 1),
BlockVector3.at(0, 0, -1),
BlockVector3.at(0, -1, 0)
);
}
@Override

View File

@ -46,13 +46,14 @@ public class NonRisingVisitor extends RecursiveVisitor {
public NonRisingVisitor(Mask mask, RegionFunction function, int depth, HasFaweQueue hasFaweQueue) {
super(mask, function, depth, hasFaweQueue);
Collection<BlockVector3> directions = getDirections();
directions.clear();
directions.add(BlockVector3.at(1, 0, 0));
directions.add(BlockVector3.at(-1, 0, 0));
directions.add(BlockVector3.at(0, 0, 1));
directions.add(BlockVector3.at(0, 0, -1));
directions.add(BlockVector3.at(0, -1, 0));
setDirections(
BlockVector3.at(1, 0, 0),
BlockVector3.at(-1, 0, 0),
BlockVector3.at(0, 0, 1),
BlockVector3.at(0, 0, -1),
BlockVector3.at(0, -1, 0)
);
}

View File

@ -0,0 +1,151 @@
package com.sk89q.worldedit.function.visitor;
import com.boydti.fawe.example.MappedFaweQueue;
import com.boydti.fawe.object.FaweQueue;
import com.boydti.fawe.object.HasFaweQueue;
import com.boydti.fawe.object.collection.BlockVectorSet;
import com.boydti.fawe.util.MathMan;
import com.sk89q.worldedit.function.RegionFunction;
import com.sk89q.worldedit.math.BlockVector3;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.longs.LongArraySet;
import it.unimi.dsi.fastutil.longs.LongSet;
import it.unimi.dsi.fastutil.objects.ObjectIterator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
/**
* A chunk based search algorithm
*/
public class ScanChunk {
private static final int MAX_QUEUE = 34816;
public static final BlockVector3[] DEFAULT_DIRECTIONS = new BlockVector3[6];
public static final BlockVector3[] DIAGONAL_DIRECTIONS;
static {
DEFAULT_DIRECTIONS[0] = (BlockVector3.at(0, -1, 0));
DEFAULT_DIRECTIONS[1] = (BlockVector3.at(0, 1, 0));
DEFAULT_DIRECTIONS[2] = (BlockVector3.at(-1, 0, 0));
DEFAULT_DIRECTIONS[3] = (BlockVector3.at(1, 0, 0));
DEFAULT_DIRECTIONS[4] = (BlockVector3.at(0, 0, -1));
DEFAULT_DIRECTIONS[5] = (BlockVector3.at(0, 0, 1));
List<BlockVector3> list = new ArrayList<>();
for (int x = -1; x <= 1; x++) {
for (int y = -1; y <= 1; y++) {
for (int z = -1; z <= 1; z++) {
if (x != 0 || y != 0 || z != 0) {
BlockVector3 pos = BlockVector3.at(x, y, z);
if (!list.contains(pos)) {
list.add(pos);
}
}
}
}
}
Collections.sort(list, new Comparator<BlockVector3>() {
@Override
public int compare(BlockVector3 o1, BlockVector3 o2) {
return (int) Math.signum(o1.lengthSq() - o2.lengthSq());
}
});
DIAGONAL_DIRECTIONS = list.toArray(new BlockVector3[list.size()]);
}
private final RegionFunction function;
private final BlockVector3[] directions;
private final Long2ObjectOpenHashMap<long[][]> visited;
private final Long2ObjectOpenHashMap<char[]> queues;
public ScanChunk(final RegionFunction function) {
this.function = function;
this.directions = DEFAULT_DIRECTIONS;
this.queues = new Long2ObjectOpenHashMap<>();
this.visited = new Long2ObjectOpenHashMap<>();
}
public static final long pairInt(int x, int y) {
return (((long) x) << 32) | (y & 0xffffffffL);
}
public boolean isVisited(int x, int y, int z) {
int X = x >> 4;
int Z = z >> 4;
long pair = pairInt(X, Z);
long[][] chunk = visited.get(pair);
if (chunk == null) return false;
int layer = y >> 4;
long[] section = chunk[layer];
if (section == null) return false;
return get(section, getLocalIndex(x & 15, y & 15, z & 15));
}
public void start(int x, int y, int z) {
if (!isVisited(x, y, z)) {
queue(x, y, z);
visit(x, y, z);
}
}
public void visit(int x, int y, int z) {
int X = x >> 4;
int Z = z >> 4;
long pair = pairInt(X, Z);
long[][] chunk = visited.get(pair);
if (chunk == null) {
visited.put(pair, chunk = new long[16][]);
}
int layer = y >> 4;
long[] section = chunk[layer];
if (section == null) {
chunk[layer] = section = new long[64];
}
set(section, getLocalIndex(x & 15, y & 15, z & 15));
}
public void queue(int x, int y, int z) {
int X = x >> 4;
int Z = z >> 4;
long pair = pairInt(X, Z);
char[] queue = queues.get(pair);
if (queue == null) {
queue = queues.put(pair, queue = new char[MAX_QUEUE + 2]);
queue[0] = 2;
queue[1] = 2;
}
if (queue[1] >= queue.length) {
queue[1] = 2;
}
queue[queue[1]++] = getLocalIndex(x & 15, y, z & 15);
}
public void process() {
LongArraySet set = new LongArraySet();
while (!queues.isEmpty()) {
ObjectIterator<Long2ObjectMap.Entry<char[]>> iter = queues.long2ObjectEntrySet().fastIterator();
Long2ObjectMap.Entry<char[]> entry = iter.next();
long index = entry.getLongKey();
int X = MathMan.unpairIntX(index);
int Z = MathMan.unpairIntY(index);
}
}
public void set(long[] bits, int i) {
bits[i >> 6] |= (1L << (i & 0x3F));
}
public boolean get(long[] bits, final int i) {
return (bits[i >> 6] & (1L << (i & 0x3F))) != 0;
}
public char getLocalIndex(int x, int y, int z) {
return (char) (y + (x << 8) + (z << 12));
}
}

View File

@ -44,6 +44,7 @@ public class EllipsoidRegion extends AbstractRegion {
*/
private Vector3 radius;
private Vector3 radiusSqr;
private Vector3 inverseRadius;
private int radiusLengthSqr;
private boolean sphere;
@ -136,7 +137,7 @@ public class EllipsoidRegion extends AbstractRegion {
public void contract(BlockVector3... changes) throws RegionOperationException {
center = center.subtract(calculateDiff(changes));
Vector3 newRadius = radius.subtract(calculateChanges(changes));
radius = Vector3.at(1.5, 1.5, 1.5).getMaximum(newRadius);
setRadius(Vector3.at(1.5, 1.5, 1.5).getMaximum(newRadius));
}
@Override
@ -187,6 +188,7 @@ public class EllipsoidRegion extends AbstractRegion {
} else {
this.sphere = false;
}
inverseRadius = Vector3.ONE.divide(radius);
}
@Override
@ -233,9 +235,9 @@ public class EllipsoidRegion extends AbstractRegion {
if (sphere) {
return cx2 + cy2 + cz2 <= radiusLengthSqr;
}
double cxd = (double) cx / radius.getBlockX();
double cyd = (double) cy / radius.getBlockY();
double czd = (double) cz / radius.getBlockZ();
double cxd = cx * inverseRadius.getX();
double cyd = cy * inverseRadius.getY();
double czd = cz * inverseRadius.getZ();
return cxd * cxd + cyd * cyd + czd * czd <= 1;
}