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 }