From 459629a2f2e8e6c7f566dda5834ac7c3081580d2 Mon Sep 17 00:00:00 2001
From: Jesse Boyd
Date: Mon, 6 May 2019 15:57:12 +1000
Subject: [PATCH] scanchunk
---
.../beta/implementation/QueueHandler.java | 13 +-
.../fawe/object/regions/FuzzyRegion.java | 4 +-
.../fawe/object/visitor/AboveVisitor.java | 17 +-
.../function/visitor/BreadthFirstSearch.java | 91 ++++-------
.../function/visitor/DirectionalVisitor.java | 17 +-
.../function/visitor/DownwardVisitor.java | 14 +-
.../function/visitor/NonRisingVisitor.java | 15 +-
.../worldedit/function/visitor/ScanChunk.java | 151 ++++++++++++++++++
.../worldedit/regions/EllipsoidRegion.java | 10 +-
9 files changed, 231 insertions(+), 101 deletions(-)
create mode 100644 worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/ScanChunk.java
diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java
index a7ebe3676..a3fbf1c04 100644
--- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java
+++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/QueueHandler.java
@@ -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();
diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/regions/FuzzyRegion.java b/worldedit-core/src/main/java/com/boydti/fawe/object/regions/FuzzyRegion.java
index 3abaa65cf..f7ecfa2b4 100644
--- a/worldedit-core/src/main/java/com/boydti/fawe/object/regions/FuzzyRegion.java
+++ b/worldedit-core/src/main/java/com/boydti/fawe/object/regions/FuzzyRegion.java
@@ -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 iterator() {
- return (Iterator) set.iterator();
+ return set.iterator();
}
private final void setMinMax(int x, int y, int z) {
diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/visitor/AboveVisitor.java b/worldedit-core/src/main/java/com/boydti/fawe/object/visitor/AboveVisitor.java
index 71de953b1..373e71f5d 100644
--- a/worldedit-core/src/main/java/com/boydti/fawe/object/visitor/AboveVisitor.java
+++ b/worldedit-core/src/main/java/com/boydti/fawe/object/visitor/AboveVisitor.java
@@ -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 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
diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/BreadthFirstSearch.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/BreadthFirstSearch.java
index 859110b77..bbc420a76 100644
--- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/BreadthFirstSearch.java
+++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/BreadthFirstSearch.java
@@ -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 directions = new ArrayList<>();
+ private BlockVector3[] directions;
private BlockVectorSet visited;
private final MappedFaweQueue mFaweQueue;
private BlockVectorSet queue;
@@ -96,23 +97,18 @@ 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 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 directions) {
+ setDirections(directions.toArray(new BlockVector3[0]));
}
-
+
/**
* Get the list of directions will be visited.
*
@@ -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)}.
*
- * The list of directions can be cleared.
- *
* @return the list of directions
*/
- protected Collection getDirections() {
- return directions;
+ public Collection 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 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 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++;
diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/DirectionalVisitor.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/DirectionalVisitor.java
index 8a9542e32..9a0b8c912 100644
--- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/DirectionalVisitor.java
+++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/DirectionalVisitor.java
@@ -51,14 +51,15 @@ public class DirectionalVisitor extends RecursiveVisitor {
checkNotNull(mask);
this.origin = origin;
this.dirVec = direction;
- final Collection 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
diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/DownwardVisitor.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/DownwardVisitor.java
index a3a8dac66..e2c4f667a 100644
--- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/DownwardVisitor.java
+++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/DownwardVisitor.java
@@ -60,13 +60,13 @@ public class DownwardVisitor extends RecursiveVisitor {
checkNotNull(mask);
this.baseY = baseY;
- Collection 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
diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/NonRisingVisitor.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/NonRisingVisitor.java
index 7e79e57a7..5a67fa950 100644
--- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/NonRisingVisitor.java
+++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/NonRisingVisitor.java
@@ -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 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)
+ );
}
diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/ScanChunk.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/ScanChunk.java
new file mode 100644
index 000000000..cfef60a74
--- /dev/null
+++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/ScanChunk.java
@@ -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 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() {
+ @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 visited;
+ private final Long2ObjectOpenHashMap 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> iter = queues.long2ObjectEntrySet().fastIterator();
+ Long2ObjectMap.Entry 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));
+ }
+
+
+}
diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/EllipsoidRegion.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/EllipsoidRegion.java
index 9cef04a0e..0c0be6781 100644
--- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/EllipsoidRegion.java
+++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/EllipsoidRegion.java
@@ -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;
}