From 1c7643bb581a1291e74ae62cfd2c896bfb4dec1e Mon Sep 17 00:00:00 2001
From: Jordan
Date: Wed, 11 May 2022 13:22:10 +0100
Subject: [PATCH] Allow use of BlockVectorSet for large //line selections
instead of LocalBlockVectorSet (#1713)
---
.../pattern/BufferedPattern2DParser.java | 4 +-
.../parser/pattern/BufferedPatternParser.java | 4 +-
.../core/function/mask/CachedMask.java | 10 +-
.../function/pattern/BufferedPattern.java | 20 +++-
.../function/pattern/BufferedPattern2D.java | 17 +++-
.../core/math/BlockVectorSet.java | 53 ++++++-----
.../core/math/LocalBlockVectorSet.java | 92 ++++++++++++-------
.../core/util/collection/BlockVector3Set.java | 37 ++++++++
.../java/com/sk89q/worldedit/EditSession.java | 16 ++--
.../extension/input/ParserContext.java | 26 ++++++
10 files changed, 205 insertions(+), 74 deletions(-)
create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/util/collection/BlockVector3Set.java
diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/BufferedPattern2DParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/BufferedPattern2DParser.java
index bd9f2a28c..246e024c6 100644
--- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/BufferedPattern2DParser.java
+++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/BufferedPattern2DParser.java
@@ -3,10 +3,12 @@ package com.fastasyncworldedit.core.extension.factory.parser.pattern;
import com.fastasyncworldedit.core.configuration.Caption;
import com.fastasyncworldedit.core.extension.factory.parser.RichParser;
import com.fastasyncworldedit.core.function.pattern.BufferedPattern2D;
+import com.sk89q.worldedit.IncompleteRegionException;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.extension.input.InputParseException;
import com.sk89q.worldedit.extension.input.ParserContext;
import com.sk89q.worldedit.function.pattern.Pattern;
+import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import javax.annotation.Nonnull;
@@ -40,7 +42,7 @@ public class BufferedPattern2DParser extends RichParser {
));
}
Pattern inner = this.worldEdit.getPatternFactory().parseFromInput(input[0], context);
- return new BufferedPattern2D(context.requireActor(), inner);
+ return new BufferedPattern2D(context.requireActor(), inner, context.getSelection());
}
}
diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/BufferedPatternParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/BufferedPatternParser.java
index fe62b5d67..49fd27495 100644
--- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/BufferedPatternParser.java
+++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/pattern/BufferedPatternParser.java
@@ -3,10 +3,12 @@ package com.fastasyncworldedit.core.extension.factory.parser.pattern;
import com.fastasyncworldedit.core.configuration.Caption;
import com.fastasyncworldedit.core.extension.factory.parser.RichParser;
import com.fastasyncworldedit.core.function.pattern.BufferedPattern;
+import com.sk89q.worldedit.IncompleteRegionException;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.extension.input.InputParseException;
import com.sk89q.worldedit.extension.input.ParserContext;
import com.sk89q.worldedit.function.pattern.Pattern;
+import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.formatting.text.TextComponent;
import javax.annotation.Nonnull;
@@ -40,7 +42,7 @@ public class BufferedPatternParser extends RichParser {
));
}
Pattern inner = this.worldEdit.getPatternFactory().parseFromInput(arguments[0], context);
- return new BufferedPattern(context.requireActor(), inner);
+ return new BufferedPattern(context.requireActor(), inner, context.getSelection());
}
}
diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/CachedMask.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/CachedMask.java
index be926b2fb..f0b0df48c 100644
--- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/CachedMask.java
+++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/CachedMask.java
@@ -1,6 +1,6 @@
package com.fastasyncworldedit.core.function.mask;
-import com.fastasyncworldedit.core.math.LocalBlockVectorSet;
+import com.fastasyncworldedit.core.math.BlockVectorSet;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.mask.AbstractExtentMask;
import com.sk89q.worldedit.function.mask.Mask;
@@ -11,8 +11,8 @@ import javax.annotation.Nullable;
public class CachedMask extends AbstractDelegateMask implements ResettableMask {
private final boolean hasExtent;
- private transient LocalBlockVectorSet cache_checked = new LocalBlockVectorSet();
- private transient LocalBlockVectorSet cache_results = new LocalBlockVectorSet();
+ private transient BlockVectorSet cache_checked = new BlockVectorSet();
+ private transient BlockVectorSet cache_results = new BlockVectorSet();
public CachedMask(Mask mask) {
super(mask);
@@ -28,8 +28,8 @@ public class CachedMask extends AbstractDelegateMask implements ResettableMask {
@Override
public void reset() {
- cache_checked = new LocalBlockVectorSet();
- cache_results = new LocalBlockVectorSet();
+ cache_checked = new BlockVectorSet();
+ cache_results = new BlockVectorSet();
resetCache();
}
diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/BufferedPattern.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/BufferedPattern.java
index 399d96663..cd7d4eced 100644
--- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/BufferedPattern.java
+++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/BufferedPattern.java
@@ -3,17 +3,21 @@ package com.fastasyncworldedit.core.function.pattern;
import com.fastasyncworldedit.core.Fawe;
import com.fastasyncworldedit.core.math.LocalBlockVectorSet;
import com.fastasyncworldedit.core.util.FaweTimer;
+import com.fastasyncworldedit.core.util.collection.BlockVector3Set;
import com.sk89q.worldedit.WorldEditException;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.pattern.AbstractPattern;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.math.BlockVector3;
+import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.world.block.BaseBlock;
+import javax.annotation.Nullable;
+
public class BufferedPattern extends AbstractPattern implements ResettablePattern {
- protected final LocalBlockVectorSet set = new LocalBlockVectorSet();
+ protected final BlockVector3Set set;
protected final FaweTimer timer;
protected final long[] actionTime;
@@ -26,6 +30,18 @@ public class BufferedPattern extends AbstractPattern implements ResettablePatter
* @param parent pattern to set
*/
public BufferedPattern(Actor actor, Pattern parent) {
+ this(actor, parent, null);
+ }
+
+ /**
+ * Create a new {@link Pattern} instance
+ *
+ * @param actor actor associated with the pattern
+ * @param parent pattern to set
+ * @param region anticipated area of the edit
+ * @since TODO
+ */
+ public BufferedPattern(Actor actor, Pattern parent, @Nullable Region region) {
long[] tmp = actor.getMeta("lastActionTime");
if (tmp == null) {
actor.setMeta("lastActionTime", tmp = new long[2]);
@@ -33,6 +49,8 @@ public class BufferedPattern extends AbstractPattern implements ResettablePatter
actionTime = tmp;
this.pattern = parent;
this.timer = Fawe.instance().getTimer();
+ // Assume brush is used if no region provided, i.e. unlikely to required BlockVectorSet
+ set = region == null ? new LocalBlockVectorSet() : BlockVector3Set.getAppropriateVectorSet(region);
}
@Override
diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/BufferedPattern2D.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/BufferedPattern2D.java
index 379c263c7..b08c635cb 100644
--- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/BufferedPattern2D.java
+++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/pattern/BufferedPattern2D.java
@@ -3,6 +3,9 @@ package com.fastasyncworldedit.core.function.pattern;
import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.math.BlockVector3;
+import com.sk89q.worldedit.regions.Region;
+
+import javax.annotation.Nullable;
public class BufferedPattern2D extends BufferedPattern {
@@ -13,7 +16,19 @@ public class BufferedPattern2D extends BufferedPattern {
* @param parent pattern to set
*/
public BufferedPattern2D(Actor actor, Pattern parent) {
- super(actor, parent);
+ super(actor, parent, null);
+ }
+
+ /**
+ * Create a new {@link Pattern} instance
+ *
+ * @param actor actor associated with the pattern
+ * @param parent pattern to set
+ * @param region anticipated area of the edit
+ * @since TODO
+ */
+ public BufferedPattern2D(Actor actor, Pattern parent, @Nullable Region region) {
+ super(actor, parent, region);
}
@Override
diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/BlockVectorSet.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/BlockVectorSet.java
index 98078b123..e904244de 100644
--- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/BlockVectorSet.java
+++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/BlockVectorSet.java
@@ -1,9 +1,10 @@
package com.fastasyncworldedit.core.math;
import com.fastasyncworldedit.core.util.MathMan;
+import com.fastasyncworldedit.core.util.collection.BlockVector3Set;
import com.sk89q.worldedit.math.BlockVector3;
-import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
-import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
+import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap;
+import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import it.unimi.dsi.fastutil.objects.ObjectIterator;
import javax.annotation.Nonnull;
@@ -13,7 +14,6 @@ import java.util.Collections;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Objects;
-import java.util.Set;
/**
* The BlockVectorSet is a memory optimized Set for storing {@link BlockVector3}'s.
@@ -23,14 +23,14 @@ import java.util.Set;
* {@code HashSet}.
*
*/
-public class BlockVectorSet extends AbstractCollection implements Set {
+public class BlockVectorSet extends AbstractCollection implements BlockVector3Set {
- private final Int2ObjectMap localSets = new Int2ObjectOpenHashMap<>();
+ private final Long2ObjectLinkedOpenHashMap localSets = new Long2ObjectLinkedOpenHashMap<>(4);
@Override
public int size() {
int size = 0;
- for (Int2ObjectMap.Entry entry : localSets.int2ObjectEntrySet()) {
+ for (Long2ObjectMap.Entry entry : localSets.long2ObjectEntrySet()) {
size += entry.getValue().size();
}
return size;
@@ -38,7 +38,7 @@ public class BlockVectorSet extends AbstractCollection implements
public BlockVector3 get(int index) {
int count = 0;
- for (Int2ObjectMap.Entry entry : localSets.int2ObjectEntrySet()) {
+ for (Long2ObjectMap.Entry entry : localSets.long2ObjectEntrySet()) {
LocalBlockVectorSet set = entry.getValue();
int size = set.size();
int newSize = count + size;
@@ -46,10 +46,12 @@ public class BlockVectorSet extends AbstractCollection implements
int localIndex = index - count;
MutableBlockVector3 pos = set.getIndex(localIndex);
if (pos != null) {
- int pair = entry.getIntKey();
- int cx = MathMan.unpairX(pair);
- int cz = MathMan.unpairY(pair);
+ long triple = entry.getLongKey();
+ int cx = (int) MathMan.untripleWorldCoordX(triple);
+ int cy = (int) MathMan.untripleWorldCoordY(triple);
+ int cz = (int) MathMan.untripleWorldCoordZ(triple);
pos.mutX((cx << 11) + pos.getBlockX());
+ pos.mutY((cy << 9) + pos.getBlockY());
pos.mutZ((cz << 11) + pos.getBlockZ());
return pos.toImmutable();
}
@@ -61,7 +63,7 @@ public class BlockVectorSet extends AbstractCollection implements
@Override
public boolean isEmpty() {
- for (Int2ObjectMap.Entry entry : localSets.int2ObjectEntrySet()) {
+ for (Long2ObjectMap.Entry entry : localSets.long2ObjectEntrySet()) {
if (!entry.getValue().isEmpty()) {
return false;
}
@@ -70,9 +72,10 @@ public class BlockVectorSet extends AbstractCollection implements
}
public boolean contains(int x, int y, int z) {
- int pair = MathMan.pair((short) (x >> 11), (short) (z >> 11));
- LocalBlockVectorSet localMap = localSets.get(pair);
- return localMap != null && localMap.contains(x & 2047, y, z & 2047);
+ int indexedY = (y + 128) >> 9;
+ long triple = MathMan.tripleWorldCoord((x >> 11), indexedY, (z >> 11));
+ LocalBlockVectorSet localMap = localSets.get(triple);
+ return localMap != null && localMap.contains(x & 2047, ((y + 128) & 511) - 128, z & 2047);
}
@Override
@@ -86,12 +89,12 @@ public class BlockVectorSet extends AbstractCollection implements
@Nonnull
@Override
public Iterator iterator() {
- final ObjectIterator> entries = localSets.int2ObjectEntrySet().iterator();
+ final ObjectIterator> entries = localSets.long2ObjectEntrySet().iterator();
if (!entries.hasNext()) {
return Collections.emptyIterator();
}
return new Iterator<>() {
- Int2ObjectMap.Entry entry = entries.next();
+ Long2ObjectMap.Entry entry = entries.next();
Iterator entryIter = entry.getValue().iterator();
final MutableBlockVector3 mutable = new MutableBlockVector3();
@@ -115,12 +118,13 @@ public class BlockVectorSet extends AbstractCollection implements
entryIter = entry.getValue().iterator();
}
BlockVector3 localPos = entryIter.next();
- int pair = entry.getIntKey();
- int cx = MathMan.unpairX(pair);
- int cz = MathMan.unpairY(pair);
+ long triple = entry.getLongKey();
+ int cx = (int) MathMan.untripleWorldCoordX(triple);
+ int cy = (int) MathMan.untripleWorldCoordY(triple);
+ int cz = (int) MathMan.untripleWorldCoordZ(triple);
return mutable.setComponents(
(cx << 11) + localPos.getBlockX(),
- localPos.getBlockY(),
+ (cy << 9) + localPos.getBlockY(),
(cz << 11) + localPos.getBlockZ()
);
}
@@ -133,14 +137,15 @@ public class BlockVectorSet extends AbstractCollection implements
}
public boolean add(int x, int y, int z) {
- int pair = MathMan.pair((short) (x >> 11), (short) (z >> 11));
- LocalBlockVectorSet localMap = localSets.get(pair);
+ int indexedY = (y + 128) >> 9;
+ long triple = MathMan.tripleWorldCoord((x >> 11), indexedY, (z >> 11));
+ LocalBlockVectorSet localMap = localSets.get(triple);
if (localMap == null) {
localMap = new LocalBlockVectorSet();
localMap.setOffset(1024, 1024);
- localSets.put(pair, localMap);
+ localSets.put(triple, localMap);
}
- return localMap.add(x & 2047, y, z & 2047);
+ return localMap.add(x & 2047, ((y + 128) & 511) - 128, z & 2047);
}
public boolean remove(int x, int y, int z) {
diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/LocalBlockVectorSet.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/LocalBlockVectorSet.java
index 882c4ee43..789248a08 100644
--- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/LocalBlockVectorSet.java
+++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/math/LocalBlockVectorSet.java
@@ -1,27 +1,29 @@
package com.fastasyncworldedit.core.math;
import com.fastasyncworldedit.core.util.MathMan;
+import com.fastasyncworldedit.core.util.collection.BlockVector3Set;
import com.sk89q.worldedit.math.BlockVector3;
import com.zaxxer.sparsebits.SparseBitSet;
import javax.annotation.Nonnull;
import java.util.Collection;
import java.util.Iterator;
-import java.util.Set;
/**
* The LocalBlockVectorSet is a Memory and CPU optimized Set for storing BlockVectors which are all in a local region
* - All vectors must be in a 2048 * 512 * 2048 area centered around the first entry
* - This will use 8 bytes for every 64 BlockVectors (about 800x less than a HashSet)
*/
-public class LocalBlockVectorSet implements Set {
+public class LocalBlockVectorSet implements BlockVector3Set {
private final SparseBitSet set;
private int offsetX;
private int offsetZ;
+ private int offsetY = 128;
/**
- * New LocalBlockVectorSet that will set the offset x and z to the first value given
+ * New LocalBlockVectorSet that will set the offset x and z to the first value given. The y offset will default to 128 to
+ * allow -64 -> 320 world height.
*/
public LocalBlockVectorSet() {
offsetX = offsetZ = Integer.MAX_VALUE;
@@ -29,7 +31,7 @@ public class LocalBlockVectorSet implements Set {
}
/**
- * New LocalBlockVectorSet with a given offset
+ * New LocalBlockVectorSet with a given offset. Defaults y offset to 128.
*
* @param x x offset
* @param z z offset
@@ -40,8 +42,24 @@ public class LocalBlockVectorSet implements Set {
this.set = new SparseBitSet();
}
- private LocalBlockVectorSet(int x, int z, SparseBitSet set) {
+ /**
+ * New LocalBlockVectorSet with a given offset
+ *
+ * @param x x offset
+ * @param y y offset
+ * @param z z offset
+ * @since TODO
+ */
+ public LocalBlockVectorSet(int x, int y, int z) {
this.offsetX = x;
+ this.offsetY = y;
+ this.offsetZ = z;
+ this.set = new SparseBitSet();
+ }
+
+ private LocalBlockVectorSet(int x, int y, int z, SparseBitSet set) {
+ this.offsetX = x;
+ this.offsetY = y;
this.offsetZ = z;
this.set = set;
}
@@ -65,8 +83,7 @@ public class LocalBlockVectorSet implements Set {
* @return if the set contains the position
*/
public boolean contains(int x, int y, int z) {
- // take 128 to fit -256 {
@Override
public LocalBlockVectorSet clone() {
- return new LocalBlockVectorSet(offsetX, offsetZ, set.clone());
+ return new LocalBlockVectorSet(offsetX, offsetY, offsetZ, set.clone());
}
/**
@@ -103,8 +120,7 @@ public class LocalBlockVectorSet implements Set {
int b3 = (index >> 15) & 0xFF;
int b4 = (index >> 23) & 0xFF;
int ix = offsetX + (((b3 + (((b2 & 0x7)) << 8)) << 21) >> 21);
- // Add 128 as we shift y by 128 to fit -256> 6) & 0x1) == 0 ? 1 : -1);
+ int iy = offsetY + b1 * (((b2 >> 6) & 0x1) == 0 ? 1 : -1);
int iz = offsetZ + (((b4 + (((b2 >> 3) & 0x7) << 8)) << 21) >> 21);
if (Math.abs(ix - x) <= radius && Math.abs(iz - z) <= radius && Math.abs(iy - y) <= radius) {
return true;
@@ -125,7 +141,8 @@ public class LocalBlockVectorSet implements Set {
}
/**
- * Set the offset applied to values when storing and reading to keep the values within -1024 to 1023
+ * Set the offset applied to values when storing and reading to keep the values within -1024 to 1023. Uses default y offset
+ * of 128 to allow -64 -> 320 world height use.
*
* @param x x offset
* @param z z offset
@@ -135,6 +152,21 @@ public class LocalBlockVectorSet implements Set {
this.offsetZ = z;
}
+ /**
+ * Set the offset applied to values when storing and reading to keep the x and z values within -1024 to 1023. Y values
+ * require keeping withing -256 and 255.
+ *
+ * @param x x offset
+ * @param y y offset
+ * @param z z offset
+ * @since TODO
+ */
+ public void setOffset(int x, int y, int z) {
+ this.offsetX = x;
+ this.offsetY = y;
+ this.offsetZ = z;
+ }
+
protected MutableBlockVector3 getIndex(int getIndex) {
int size = size();
if (getIndex > size) {
@@ -150,8 +182,7 @@ public class LocalBlockVectorSet implements Set {
int b3 = (index >> 15) & 0xFF;
int b4 = (index >> 23) & 0xFF;
int x = offsetX + (((b3 + (((b2 & 0x7)) << 8)) << 21) >> 21);
- // Add 128 as we shift y by 128 to fit -256> 6) & 0x1) == 0 ? 1 : -1);
+ int y = offsetY + b1 * (((b2 >> 6) & 0x1) == 0 ? 1 : -1);
int z = offsetZ + (((b4 + (((b2 >> 3) & 0x7) << 8)) << 21) >> 21);
return MutableBlockVector3.get(x, y, z);
}
@@ -184,8 +215,7 @@ public class LocalBlockVectorSet implements Set {
int b3 = (index >> 15) & 0xFF;
int b4 = (index >> 23) & 0xFF;
int x = offsetX + (((b3 + (((b2 & 0x7)) << 8)) << 21) >> 21);
- // Add 128 as we shift y by 128 to fit -256> 6) & 0x1) == 0 ? 1 : -1);
+ int y = offsetY + b1 * (((b2 >> 6) & 0x1) == 0 ? 1 : -1);
int z = offsetZ + (((b4 + (((b2 >> 3) & 0x7) << 8)) << 21) >> 21);
mutable.mutX(x);
mutable.mutY(y);
@@ -220,8 +250,7 @@ public class LocalBlockVectorSet implements Set {
int b3 = (index >> 15) & 0xFF;
int b4 = (index >> 23) & 0xFF;
int x = offsetX + (((b3 + (((b2 & 0x7)) << 8)) << 21) >> 21);
- // Add 128 as we shift y by 128 to fit -256> 6) & 0x1) == 0 ? 1 : -1);
+ int y = offsetY + b1 * (((b2 >> 6) & 0x1) == 0 ? 1 : -1);
int z = offsetZ + (((b4 + (((b2 >> 3) & 0x7) << 8)) << 21) >> 21);
array[i] = (T) BlockVector3.at(x, y, z);
index++;
@@ -246,7 +275,8 @@ public class LocalBlockVectorSet implements Set {
if (relX > 1023 || relX < -1024 || relZ > 1023 || relZ < -1024) {
return false;
}
- return y >= -128 && y <= 383;
+ int relY = y - offsetY;
+ return relY >= -256 && relY <= 255;
}
/**
@@ -264,13 +294,11 @@ public class LocalBlockVectorSet implements Set {
}
int relX = x - offsetX;
int relZ = z - offsetZ;
- if (relX > 1023 || relX < -1024 || relZ > 1023 || relZ < -1024) {
+ int relY = y - offsetY;
+ if (relX > 1023 || relX < -1024 || relZ > 1023 || relZ < -1024 || relY < -256 || relY > 255) {
throw new UnsupportedOperationException(
"LocalVectorSet can only contain vectors within 1024 blocks (cuboid) of the first entry. Attempted to set " +
- "block at " + x + ", " + y + ", " + z + ". With origin " + offsetX + " " + offsetZ);
- }
- if (y < -128 || y > 383) {
- throw new UnsupportedOperationException("LocalVectorSet can only contain vectors from y elem:[-128,383]");
+ "block at " + x + ", " + y + ", " + z + ". With origin " + offsetX + " " + offsetY + " " + offsetZ);
}
int index = getIndex(x, y, z);
if (set.get(index)) {
@@ -293,17 +321,15 @@ public class LocalBlockVectorSet implements Set {
}
private int getIndex(BlockVector3 vector) {
- // take 128 to fit -256 {
public boolean remove(int x, int y, int z) {
int relX = x - offsetX;
int relZ = z - offsetZ;
- if (relX > 1023 || relX < -1024 || relZ > 1023 || relZ < -1024) {
+ int relY = y - offsetY;
+ if (relX > 1023 || relX < -1024 || relZ > 1023 || relZ < -1024 || relY < -256 || relY > 255) {
return false;
}
- // take 128 to fit -256 {
int b3 = (index >> 15) & 0xFF;
int b4 = (index >> 23) & 0xFF;
int x = offsetX + (((b3 + (((b2 & 0x7)) << 8)) << 21) >> 21);
- // Add 128 as we shift y by 128 to fit -256> 6) & 0x1) == 0 ? 1 : -1);
+ int y = offsetY + b1 * (((b2 >> 6) & 0x1) == 0 ? 1 : -1);
int z = offsetZ + (((b4 + (((b2 >> 3) & 0x7) << 8)) << 21) >> 21);
mVec.mutX(x);
mVec.mutY(y);
@@ -406,8 +431,7 @@ public class LocalBlockVectorSet implements Set {
int b3 = (index >> 15) & 0xFF;
int b4 = (index >> 23) & 0xFF;
int x = offsetX + (((b3 + (((b2 & 0x7)) << 8)) << 21) >> 21);
- // Add 128 as we shift y by 128 to fit -256> 6) & 0x1) == 0 ? 1 : -1);
+ int y = offsetY + b1 * (((b2 >> 6) & 0x1) == 0 ? 1 : -1);
int z = offsetZ + (((b4 + (((b2 >> 3) & 0x7) << 8)) << 21) >> 21);
visitor.run(x, y, z, index);
}
diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/collection/BlockVector3Set.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/collection/BlockVector3Set.java
new file mode 100644
index 000000000..881aaf9f3
--- /dev/null
+++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/collection/BlockVector3Set.java
@@ -0,0 +1,37 @@
+package com.fastasyncworldedit.core.util.collection;
+
+import com.fastasyncworldedit.core.math.BlockVectorSet;
+import com.fastasyncworldedit.core.math.LocalBlockVectorSet;
+import com.sk89q.worldedit.math.BlockVector3;
+import com.sk89q.worldedit.regions.Region;
+
+import java.util.Set;
+
+public interface BlockVector3Set extends Set {
+
+ static BlockVector3Set getAppropriateVectorSet(Region region) {
+ BlockVector3 max = region.getMaximumPoint();
+ BlockVector3 min = region.getMinimumPoint();
+ BlockVector3 size = region.getDimensions();
+ if (size.getBlockX() > 2048 || size.getBlockZ() > 2048 || size.getBlockY() > 512) {
+ return new BlockVectorSet();
+ } else {
+ // Set default offset as many operations utilising a region are likely to start in a corner, this initialising the
+ // LocalBlockVectorSet poorly
+ // This needs to be ceiling as LocalBlockVector extends 1 block further "negative"
+ int offsetX = (int) Math.ceil((min.getX() + max.getX()) / 2d);
+ int offsetZ = (int) Math.ceil((min.getZ() + max.getZ()) / 2d);
+ int offsetY;
+ if (region.getMinimumY() < -128 || region.getMaximumY() > 320) {
+ offsetY = (min.getY() + max.getY()) / 2;
+ } else {
+ offsetY = 128;
+ }
+ return new LocalBlockVectorSet(offsetX, offsetY, offsetZ);
+ }
+ }
+ boolean add(int x, int y, int z);
+
+ boolean contains(int x, int y, int z);
+
+}
diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java
index 5bd31cb83..55c5ab21f 100644
--- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java
+++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java
@@ -56,6 +56,7 @@ import com.fastasyncworldedit.core.util.ExtentTraverser;
import com.fastasyncworldedit.core.util.MaskTraverser;
import com.fastasyncworldedit.core.util.MathMan;
import com.fastasyncworldedit.core.util.TaskManager;
+import com.fastasyncworldedit.core.util.collection.BlockVector3Set;
import com.fastasyncworldedit.core.util.task.RunnableVal;
import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.entity.Entity;
@@ -3052,7 +3053,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
*/
public int hollowOutRegion(Region region, int thickness, Pattern pattern, Mask mask) {
try {
- final Set outside = new LocalBlockVectorSet();
+ final Set outside = BlockVector3Set.getAppropriateVectorSet(region);
final BlockVector3 min = region.getMinimumPoint();
final BlockVector3 max = region.getMaximumPoint();
@@ -3096,7 +3097,7 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
}
for (int i = 1; i < thickness; ++i) {
- final Set newOutside = new LocalBlockVectorSet();
+ final Set newOutside = BlockVector3Set.getAppropriateVectorSet(region);
outer:
for (BlockVector3 position : region) {
for (BlockVector3 recurseDirection : recurseDirections) {
@@ -3151,11 +3152,6 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
public int drawLine(Pattern pattern, BlockVector3 pos1, BlockVector3 pos2, double radius, boolean filled, boolean flat)
throws MaxChangedBlocksException {
- //FAWE start - LocalBlockVectorSet
- LocalBlockVectorSet vset = new LocalBlockVectorSet();
- boolean notdrawn = true;
- //FAWE end
-
int x1 = pos1.getBlockX();
int y1 = pos1.getBlockY();
int z1 = pos1.getBlockZ();
@@ -3169,6 +3165,12 @@ public class EditSession extends PassthroughExtent implements AutoCloseable {
int dy = Math.abs(y2 - y1);
int dz = Math.abs(z2 - z1);
+ //FAWE start - LocalBlockVectorSet
+ BlockVector3Set vset = BlockVector3Set.getAppropriateVectorSet(new CuboidRegion(pos1, pos2));
+
+ boolean notdrawn = true;
+ //FAWE end
+
if (dx + dy + dz == 0) {
//FAWE start - LocalBlockVectorSet
vset.add(tipx, tipy, tipz);
diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/input/ParserContext.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/input/ParserContext.java
index cf3f7d753..617fa4fda 100644
--- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/input/ParserContext.java
+++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/input/ParserContext.java
@@ -20,6 +20,7 @@
package com.sk89q.worldedit.extension.input;
import com.fastasyncworldedit.core.configuration.Caption;
+import com.sk89q.worldedit.IncompleteRegionException;
import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.WorldEdit;
import com.sk89q.worldedit.extension.factory.MaskFactory;
@@ -27,6 +28,7 @@ import com.sk89q.worldedit.extension.platform.Actor;
import com.sk89q.worldedit.extension.platform.Capability;
import com.sk89q.worldedit.extension.platform.Locatable;
import com.sk89q.worldedit.extent.Extent;
+import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.world.World;
import org.enginehub.piston.inject.InjectedValueAccess;
@@ -343,5 +345,29 @@ public class ParserContext {
return maxY;
}
+
+ /**
+ * Attempts to retrieve the selection associated with this context. Requires an {@link Actor} or {@link LocalSession} be
+ * supplied.
+ *
+ * @return Region representing the selection for this context or null if it cannot be retrieved.
+ * @since TODO
+ */
+ public Region getSelection() {
+ if (session != null) {
+ try {
+ return session.getSelection();
+ } catch (IncompleteRegionException ignored) {
+ }
+ }
+ if (actor != null) {
+ try {
+ return actor.getSession().getSelection();
+ } catch (IncompleteRegionException ignored) {
+ }
+ }
+ return null;
+ }
+
//FAWE end
}