From cfbde956f4f4581e546cf9e30dee3d8d47de7f69 Mon Sep 17 00:00:00 2001 From: Jesse Boyd Date: Wed, 17 Jul 2019 05:10:39 +1000 Subject: [PATCH] some refactoring to pipeline classes (WIP) --- .../fawe/bukkit/beta/BukkitChunkHolder.java | 7 +- .../com/boydti/fawe/beta/IQueueExtent.java | 7 +- .../implementation/MultiThreadedQueue.java | 14 +- .../SingleThreadQueueExtent.java | 6 +- .../implementation/holder/ChunkHolder.java | 6 +- .../jnbt/anvil/HeightMapMCAGenerator.java | 64 +- .../com/boydti/fawe/jnbt/anvil/MCAWriter.java | 3 +- .../collection/AdaptedSetCollection.java | 135 +++ .../fawe/object/collection/BlockSet.java | 112 +++ .../fawe/object/collection/ChunkBVecSet.java | 109 --- .../fawe/object/collection/ChunkBitSet.java | 183 ---- .../fawe/object/collection/CpuBlockSet.java | 137 +++ .../fawe/object/collection/MemBlockSet.java | 917 ++++++++++++++++++ .../fawe/object/regions/FuzzyRegion.java | 3 +- .../java/com/sk89q/worldedit/EditSession.java | 22 +- .../com/sk89q/worldedit/extent/Extent.java | 6 +- .../function/visitor/BreadthFirstSearch.java | 42 +- .../function/visitor/DirectionalVisitor.java | 11 +- .../function/visitor/RecursiveVisitor.java | 7 +- .../worldedit/regions/AbstractRegion.java | 23 +- .../com/sk89q/worldedit/regions/Region.java | 13 +- 21 files changed, 1388 insertions(+), 439 deletions(-) create mode 100644 worldedit-core/src/main/java/com/boydti/fawe/object/collection/AdaptedSetCollection.java create mode 100644 worldedit-core/src/main/java/com/boydti/fawe/object/collection/BlockSet.java delete mode 100644 worldedit-core/src/main/java/com/boydti/fawe/object/collection/ChunkBVecSet.java delete mode 100644 worldedit-core/src/main/java/com/boydti/fawe/object/collection/ChunkBitSet.java create mode 100644 worldedit-core/src/main/java/com/boydti/fawe/object/collection/CpuBlockSet.java create mode 100644 worldedit-core/src/main/java/com/boydti/fawe/object/collection/MemBlockSet.java diff --git a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java index 919da1b05..b9767bbef 100644 --- a/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java +++ b/worldedit-bukkit/src/main/java/com/boydti/fawe/bukkit/beta/BukkitChunkHolder.java @@ -6,8 +6,6 @@ import com.boydti.fawe.beta.IQueueExtent; import com.boydti.fawe.beta.IChunkSet; import com.boydti.fawe.beta.implementation.QueueHandler; import com.boydti.fawe.beta.implementation.holder.ChunkHolder; -import com.boydti.fawe.bukkit.v0.BukkitQueue_0; -import com.boydti.fawe.bukkit.v1_14.BukkitQueue_1_14; import com.boydti.fawe.util.MemUtil; import com.boydti.fawe.util.ReflectionUtils; import com.sk89q.jnbt.CompoundTag; @@ -24,7 +22,6 @@ import net.minecraft.server.v1_14_R1.Chunk; import net.minecraft.server.v1_14_R1.ChunkSection; import net.minecraft.server.v1_14_R1.Entity; import net.minecraft.server.v1_14_R1.EntityTypes; -import net.minecraft.server.v1_14_R1.MinecraftKey; import net.minecraft.server.v1_14_R1.NBTTagCompound; import net.minecraft.server.v1_14_R1.NBTTagInt; import net.minecraft.server.v1_14_R1.TileEntity; @@ -283,14 +280,14 @@ public class BukkitChunkHolder> extends ChunkHolder { final int y = (blockHash & 0xFF); final int z = (blockHash >> 8 & 0xF) + bz; final BlockPosition pos = new BlockPosition(x, y, z); - synchronized (BukkitQueue_0.class) { + synchronized (nmsWorld) { TileEntity tileEntity = nmsWorld.getTileEntity(pos); if (tileEntity == null || tileEntity.isRemoved()) { nmsWorld.removeTileEntity(pos); tileEntity = nmsWorld.getTileEntity(pos); } if (tileEntity != null) { - final NBTTagCompound tag = (NBTTagCompound) BukkitQueue_1_14.fromNative(nativeTag); + final NBTTagCompound tag = (NBTTagCompound) fromNative(nativeTag); tag.set("x", new NBTTagInt(x)); tag.set("y", new NBTTagInt(y)); tag.set("z", new NBTTagInt(z)); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/IQueueExtent.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/IQueueExtent.java index 633dad3a8..5e9bfffbe 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/IQueueExtent.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/IQueueExtent.java @@ -10,6 +10,7 @@ import com.sk89q.worldedit.world.block.BlockStateHolder; import java.io.Flushable; import java.util.concurrent.Future; +import java.util.function.Supplier; /** * TODO: implement Extent (need to refactor Extent first) @@ -22,7 +23,7 @@ public interface IQueueExtent extends Flushable, Trimable, Extent { * Get the {@link WorldChunkCache} * @return */ - WorldChunkCache getCache(); + IChunkGet getCachedGet(int X, int Z, Supplier supplier); /** * Get the IChunk at a position (and cache it if it's not already) @@ -67,12 +68,12 @@ public interface IQueueExtent extends Flushable, Trimable, Extent { @Override default BlockVector3 getMinimumPoint() { - return getCache().getWorld().getMinimumPoint(); + return getWorld().getMinimumPoint(); } @Override default BlockVector3 getMaximumPoint() { - return getCache().getWorld().getMaximumPoint(); + return getWorld().getMaximumPoint(); } /** * Create a new root IChunk object
diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/MultiThreadedQueue.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/MultiThreadedQueue.java index badabc0d2..e571306ac 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/MultiThreadedQueue.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/MultiThreadedQueue.java @@ -9,23 +9,16 @@ import com.boydti.fawe.beta.filters.DistrFilter; import com.boydti.fawe.config.Settings; import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.extent.AbstractDelegateExtent; -import com.sk89q.worldedit.function.mask.BlockMask; -import com.sk89q.worldedit.function.mask.BlockMaskBuilder; import com.sk89q.worldedit.function.mask.Mask; -import com.sk89q.worldedit.function.mask.SingleBlockStateMask; -import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.function.pattern.Pattern; -import com.sk89q.worldedit.function.visitor.RegionVisitor; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.Countable; import com.sk89q.worldedit.world.World; -import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; -import com.sk89q.worldedit.world.block.BlockTypes; import java.util.Iterator; import java.util.List; @@ -132,7 +125,12 @@ public class MultiThreadedQueue extends AbstractDelegateExtent implements IQueue @Override public int setBlocks(Set vset, Pattern pattern) { - TODO + if (vset instanceof Region) { + setBlocks((Region) vset, pattern); + } + for (BlockVector3 blockVector3 : vset) { + pattern.apply(this, blockVector3, blockVector3); + } return getChanges(); } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/SingleThreadQueueExtent.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/SingleThreadQueueExtent.java index 661868e8f..522987383 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/SingleThreadQueueExtent.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/SingleThreadQueueExtent.java @@ -2,6 +2,7 @@ package com.boydti.fawe.beta.implementation; import com.boydti.fawe.Fawe; import com.boydti.fawe.beta.IChunk; +import com.boydti.fawe.beta.IChunkGet; import com.boydti.fawe.beta.IQueueExtent; import com.boydti.fawe.beta.implementation.holder.ReferenceChunk; import com.boydti.fawe.config.Settings; @@ -13,6 +14,7 @@ import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; +import java.util.function.Supplier; import static com.google.common.base.Preconditions.checkNotNull; @@ -38,8 +40,8 @@ public abstract class SingleThreadQueueExtent implements IQueueExtent { } @Override - public WorldChunkCache getCache() { - return cache; + public IChunkGet getCachedGet(int X, int Z, Supplier supplier) { + return cache.get(MathMan.pairInt(X, Z), supplier); } /** diff --git a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java index d0a192063..794065f2a 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/beta/implementation/holder/ChunkHolder.java @@ -110,8 +110,10 @@ public abstract class ChunkHolder implements IChunk, Supplier { private IChunkGet newGet() { if (extent instanceof SingleThreadQueueExtent) { - final WorldChunkCache cache = ((SingleThreadQueueExtent) extent).getCache(); - return cache.get(MathMan.pairInt(X, Z), this); + IChunkGet newGet = extent.getCachedGet(X, Z, this); + if (newGet != null) { + return newGet; + } } return get(); } diff --git a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/HeightMapMCAGenerator.java b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/HeightMapMCAGenerator.java index 77b8d2048..e3273cd16 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/HeightMapMCAGenerator.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/HeightMapMCAGenerator.java @@ -1,65 +1,73 @@ package com.boydti.fawe.jnbt.anvil; import com.boydti.fawe.Fawe; -import com.boydti.fawe.FaweCache; -import com.boydti.fawe.beta.ArrayFilterBlock; -import com.boydti.fawe.beta.DelegateFilter; -import com.boydti.fawe.beta.Filter; -import com.boydti.fawe.beta.FilterBlock; -import com.boydti.fawe.beta.SimpleFilterBlock; -import com.boydti.fawe.beta.filters.ArrayImageMask; -import com.boydti.fawe.example.SimpleIntFaweChunk; -import com.boydti.fawe.jnbt.anvil.HeightMapMCADrawer; -import com.boydti.fawe.jnbt.anvil.MCAChunk; -import com.boydti.fawe.jnbt.anvil.MCAWriter; -import com.boydti.fawe.object.*; +import com.boydti.fawe.object.FaweInputStream; +import com.boydti.fawe.object.FaweOutputStream; +import com.boydti.fawe.object.FawePlayer; +import com.boydti.fawe.object.Metadatable; +import com.boydti.fawe.object.RunnableVal2; import com.boydti.fawe.object.brush.visualization.VirtualWorld; import com.boydti.fawe.object.change.StreamChange; import com.boydti.fawe.object.changeset.CFIChangeSet; -import com.boydti.fawe.object.collection.*; +import com.boydti.fawe.object.collection.DifferentialArray; +import com.boydti.fawe.object.collection.DifferentialBlockBuffer; +import com.boydti.fawe.object.collection.IterableThreadLocal; +import com.boydti.fawe.object.collection.LocalBlockVector2DSet; +import com.boydti.fawe.object.collection.SummedAreaTable; import com.boydti.fawe.object.exception.FaweException; import com.boydti.fawe.object.queue.LazyFaweChunk; import com.boydti.fawe.object.schematic.Schematic; -import com.boydti.fawe.util.*; +import com.boydti.fawe.util.CachedTextureUtil; +import com.boydti.fawe.util.RandomTextureUtil; +import com.boydti.fawe.util.ReflectionUtils; +import com.boydti.fawe.util.TaskManager; +import com.boydti.fawe.util.TextureUtil; import com.boydti.fawe.util.image.Drawable; import com.boydti.fawe.util.image.ImageViewer; import com.sk89q.jnbt.CompoundTag; -import com.sk89q.worldedit.*; -import com.sk89q.worldedit.math.MutableBlockVector3; -import com.sk89q.worldedit.registry.state.PropertyKey; -import com.sk89q.worldedit.util.Location; -import com.sk89q.worldedit.world.biome.BiomeTypes; -import com.sk89q.worldedit.world.block.BlockID; -import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseItemStack; +import com.sk89q.worldedit.extension.platform.Capability; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.MutableBlockVector3; import com.sk89q.worldedit.math.Vector3; import com.sk89q.worldedit.math.transform.AffineTransform; import com.sk89q.worldedit.math.transform.Transform; import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.registry.state.PropertyKey; import com.sk89q.worldedit.session.ClipboardHolder; +import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.TreeGenerator; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.biome.BiomeType; +import com.sk89q.worldedit.world.biome.BiomeTypes; +import com.sk89q.worldedit.world.block.BlockID; +import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; +import javax.annotation.Nullable; import java.awt.image.BufferedImage; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.lang.reflect.Field; -import java.util.*; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; import java.util.List; +import java.util.UUID; import java.util.concurrent.ThreadLocalRandom; -import javax.annotation.Nullable; // TODO FIXME public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Drawable, VirtualWorld { @@ -200,11 +208,6 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr this.editSession = session; } - @Override - public boolean supports(Capability capability) { - return false; - } - // Used for visualizing the world on a map private ImageViewer viewer; // Used for visualizing the world by sending chunk packets @@ -239,11 +242,6 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr return metaData; } - @Override - public FaweQueue getQueue() { - throw new UnsupportedOperationException("Not supported: Queue is not backed by a real world"); - } - @Override public Vector3 getOrigin() { return Vector3.at(chunkOffset.getBlockX() << 4, 0, chunkOffset.getBlockZ() << 4); diff --git a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAWriter.java b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAWriter.java index 19f34b0ab..b05318592 100644 --- a/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAWriter.java +++ b/worldedit-core/src/main/java/com/boydti/fawe/jnbt/anvil/MCAWriter.java @@ -3,6 +3,7 @@ package com.boydti.fawe.jnbt.anvil; import com.boydti.fawe.object.collection.IterableThreadLocal; import com.boydti.fawe.object.io.BufferedRandomAccessFile; import com.boydti.fawe.util.MainUtil; +import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.world.block.BlockID; import java.io.File; @@ -12,7 +13,7 @@ import java.util.concurrent.ForkJoinPool; import java.util.concurrent.TimeUnit; import java.util.zip.Deflater; -public abstract class MCAWriter { +public abstract class MCAWriter implements Extent { private File folder; private final int length; private final int width; diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/collection/AdaptedSetCollection.java b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/AdaptedSetCollection.java new file mode 100644 index 000000000..0f0b33b7b --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/AdaptedSetCollection.java @@ -0,0 +1,135 @@ +package com.boydti.fawe.object.collection; + +import com.google.common.base.Function; +import com.google.common.collect.Collections2; +import org.jetbrains.annotations.NotNull; + +import javax.annotation.Nullable; +import java.util.Collection; +import java.util.Iterator; +import java.util.Set; +import java.util.Spliterator; +import java.util.function.Consumer; +import java.util.function.Predicate; +import java.util.stream.Stream; + +/** + * Adapt a collection to a set + * (It's assumed that the collection is set like, otherwise behavior will be weird) + * + * @param + */ +public class AdaptedSetCollection implements Set { + private final Function adapter; + private final Collection adapted; + private final Collection original; + + public AdaptedSetCollection(Collection collection, Function adapter) { + this.original = collection; + this.adapted = Collections2.transform(collection, adapter); + this.adapter = adapter; + } + + public Collection getOriginal() { + return original; + } + + @Override + public int size() { + return adapted.size(); + } + + @Override + public boolean isEmpty() { + return adapted.isEmpty(); + } + + @Override + public boolean contains(Object o) { + return adapted.contains(o); + } + + @NotNull + @Override + public Iterator iterator() { + return adapted.iterator(); + } + + @NotNull + @Override + public Object[] toArray() { + return adapted.toArray(); + } + + @NotNull + @Override + public V[] toArray(@NotNull V[] a) { + return adapted.toArray(a); + } + + public boolean add(V v) { + return adapted.add(v); + } + + @Override + public boolean remove(Object o) { + return adapted.remove(o); + } + + @Override + public boolean containsAll(@NotNull Collection c) { + return adapted.containsAll(c); + } + + public boolean addAll(@NotNull Collection c) { + return adapted.addAll(c); + } + + @Override + public boolean removeAll(@NotNull Collection c) { + return adapted.removeAll(c); + } + + public boolean removeIf(Predicate filter) { + return adapted.removeIf(filter); + } + + @Override + public boolean retainAll(@NotNull Collection c) { + return adapted.retainAll(c); + } + + @Override + public void clear() { + adapted.clear(); + } + + @Override + public boolean equals(Object o) { + return adapted.equals(o); + } + + @Override + public int hashCode() { + return adapted.hashCode(); + } + + @Override + public Spliterator spliterator() { + return adapted.spliterator(); + } + + @Override + public Stream stream() { + return adapted.stream(); + } + + @Override + public Stream parallelStream() { + return adapted.parallelStream(); + } + + public void forEach(Consumer action) { + adapted.forEach(action); + } +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/collection/BlockSet.java b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/BlockSet.java new file mode 100644 index 000000000..a96a8f340 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/BlockSet.java @@ -0,0 +1,112 @@ +package com.boydti.fawe.object.collection; + +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.AbstractRegion; +import com.sk89q.worldedit.regions.RegionOperationException; +import com.sk89q.worldedit.world.World; + +import java.util.AbstractSet; +import java.util.Iterator; +import java.util.Set; + +public abstract class BlockSet extends AbstractRegion { + private final int chunkOffsetX; + private final int chunkOffsetZ; + private final int blockOffsetX; + private final int blockOffsetZ; + + public BlockSet(int offsetX, int offsetZ) { + super(null); + this.chunkOffsetX = offsetX; + this.chunkOffsetZ = offsetZ; + this.blockOffsetX = offsetX << 4; + this.blockOffsetZ = offsetZ << 4; + } + + @Override + public boolean contains(Object o) { + try { + return contains((BlockVector3) o); + } catch (ClassCastException e) { + e.printStackTrace(); + return false; + } + } + + public boolean contains(BlockVector3 obj) { + return contains(obj.getX(), obj.getY(), obj.getZ()); + } + + protected final int lowestBit(long bitBuffer) { + final long lowBit = Long.lowestOneBit(bitBuffer); + return Long.bitCount(lowBit - 1); + } + + protected final int highestBit(long bitBuffer) { + final long lowBit = Long.highestOneBit(bitBuffer); + return Long.bitCount(lowBit - 1); + } + + @Override + public boolean isGlobal() { + return false; + } + + public final int getBlockOffsetX() { + return blockOffsetX; + } + + public int getBlockOffsetZ() { + return blockOffsetZ; + } + + public int getChunkOffsetX() { + return chunkOffsetX; + } + + public int getChunkOffsetZ() { + return chunkOffsetZ; + } + + @Override + public boolean add(BlockVector3 p) { + return add(p.getX(), p.getY(), p.getZ()); + } + + public boolean remove(BlockVector3 p) { + return remove(p.getX(), p.getY(), p.getZ()); + } + + @Override + public boolean remove(Object o) { + try { + return remove((BlockVector3) o); + } catch (ClassCastException e) { + e.printStackTrace(); + return false; + } + } + + @Override + public abstract boolean contains(int x, int y, int z); + public abstract boolean add(int x, int y, int z); + public abstract void set(int x, int y, int z); + public abstract void clear(int x, int y, int z); + public abstract boolean remove(int x, int y, int z); + public abstract Iterator iterator(); + public abstract Set getChunks(); + public abstract Set getChunkCubes(); + public abstract BlockVector3 getMaximumPoint(); + public abstract BlockVector3 getMinimumPoint(); + + @Override + public void expand(BlockVector3... changes) throws RegionOperationException { + + } + + @Override + public void contract(BlockVector3... changes) throws RegionOperationException { + + } +} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/collection/ChunkBVecSet.java b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/ChunkBVecSet.java deleted file mode 100644 index 0dddf8bdc..000000000 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/collection/ChunkBVecSet.java +++ /dev/null @@ -1,109 +0,0 @@ -package com.boydti.fawe.object.collection; - -import com.sk89q.worldedit.math.BlockVector3; -import org.jetbrains.annotations.NotNull; - -import java.util.Collection; -import java.util.Iterator; -import java.util.Set; - -public class ChunkBVecSet implements Set { - private final int offsetX, offsetZ; - private final ChunkBitSet set; - private int size = 0; - - public ChunkBVecSet(int size) { - this(Integer.MAX_VALUE, Integer.MAX_VALUE, new ChunkBitSet(size)); - } - - public ChunkBVecSet(ChunkBitSet set, int offsetX, int offsetZ) { - this.offsetX = offsetX; - this.offsetZ = offsetZ; - this.set = set; - } - - public ChunkBitSet getBitSet() { - return set; - } - - @Override - public int size() { - return size; - } - - @Override - public boolean isEmpty() { - return size() == 0; - } - - @Override - public boolean contains(Object o) { - try { - return contain((BlockVector3) o); - } catch (ClassCastException e) { - e.printStackTrace(); - return false; - } - } - - public boolean contain(BlockVector3 obj) { - return contain(obj.getX(), obj.getY(), obj.getZ()); - } - - public boolean contain(int x, int y, int z) { - return set.get(x - offsetX, y, z - offsetZ); - } - - @NotNull - @Override - public Iterator iterator() { - return null; - } - - @NotNull - @Override - public Object[] toArray() { - return new Object[0]; - } - - @NotNull - @Override - public T[] toArray(@NotNull T[] a) { - return null; - } - - @Override - public boolean add(BlockVector3 blockVector3) { - return false; - } - - @Override - public boolean remove(Object o) { - return false; - } - - @Override - public boolean containsAll(@NotNull Collection c) { - return false; - } - - @Override - public boolean addAll(@NotNull Collection c) { - return false; - } - - @Override - public boolean retainAll(@NotNull Collection c) { - return false; - } - - @Override - public boolean removeAll(@NotNull Collection c) { - return false; - } - - @Override - public void clear() { - - } -} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/collection/ChunkBitSet.java b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/ChunkBitSet.java deleted file mode 100644 index eac383c64..000000000 --- a/worldedit-core/src/main/java/com/boydti/fawe/object/collection/ChunkBitSet.java +++ /dev/null @@ -1,183 +0,0 @@ -package com.boydti.fawe.object.collection; - -import java.util.Arrays; - -public class ChunkBitSet { - private final static int CHUNK_LAYERS = 16; - private final static int BITS_PER_LAYER = 4096; - private final static int BITS_PER_WORD = 6; - private final static int WORDS = BITS_PER_LAYER >> BITS_PER_WORD; - private final static IRow NULL_ROW_X = new NullRowX(); - private final static IRow NULL_ROW_Z = new NullRowZ(); - private final static IRow NULL_ROW_Y = new NullRowY(); - - private final IRow[] rows; - - public ChunkBitSet() { - this(16); - } - - public ChunkBitSet(int size) { - this.rows = new IRow[size]; - for (int i = 0; i < size; i++) rows[i] = NULL_ROW_X; - } - - public boolean get(int x, int y, int z) { - return rows[x >> 4].get(this.rows, x, y, z); - } - - public void add(int x, int y, int z) { - rows[x >> 4].add(this.rows, x, y, z); - } - - public void set(int x, int y, int z) { - rows[x >> 4].set(this.rows, x, y, z); - } - - public void clear(int x, int y, int z) { - rows[x >> 4].clear(this.rows, x, y, z); - } - - private interface IRow { - default boolean get(IRow[] rows, int x, int y, int z) { return false; } - void set(IRow[] rows, int x, int y, int z); - default boolean add(IRow[] rows, int x, int y, int z) { - set(rows, x, y, z); - return true; - } - default void clear(IRow[] rows, int x, int y, int z) { return; } - } - - private static class NullRowX implements IRow { - @Override - public void set(IRow[] parent, int x, int y, int z) { - IRow row = new RowX(parent.length); - parent[x >> 4] = row; - row.set(parent, x, y, z); - } - } - - private static class NullRowZ implements IRow { - @Override - public void set(IRow[] parent, int x, int y, int z) { - IRow row = new RowZ(); - parent[z >> 4] = row; - row.set(parent, x, y, z); - } - } - - private static class NullRowY implements IRow { - @Override - public void set(IRow[] parent, int x, int y, int z) { - IRow row = new RowY(); - parent[y >> 4] = row; - row.set(parent, x, y, z); - } - } - - private static class RowX implements IRow { - private final IRow[] rows; - - public RowX(int size) { - this.rows = new IRow[size]; - for (int i = 0; i < size; i++) rows[i] = NULL_ROW_Z; - } - - @Override - public boolean get(IRow[] parent, int x, int y, int z) { - return rows[z >> 4].get(this.rows, x, y, z); - } - - @Override - public void set(IRow[] parent, int x, int y, int z) { - this.rows[z >> 4].set(this.rows, x, y, z); - } - - @Override - public boolean add(IRow[] parent, int x, int y, int z) { - return this.rows[z >> 4].add(this.rows, x, y, z); - } - - @Override - public void clear(IRow[] parent, int x, int y, int z) { - this.rows[z >> 4].clear(this.rows, x, y, z); - } - } - - private static class RowZ implements IRow { - private final IRow[] rows; - - public RowZ() { - this.rows = new IRow[CHUNK_LAYERS]; - for (int i = 0; i < CHUNK_LAYERS; i++) rows[i] = NULL_ROW_Y; - } - - @Override - public boolean get(IRow[] parent, int x, int y, int z) { - return rows[y >> 4].get(this.rows, x, y, z); - } - - @Override - public void set(IRow[] parent, int x, int y, int z) { - this.rows[y >> 4].set(this.rows, x, y, z); - } - - @Override - public boolean add(IRow[] parent, int x, int y, int z) { - return this.rows[y >> 4].add(this.rows, x, y, z); - } - - @Override - public void clear(IRow[] parent, int x, int y, int z) { - this.rows[y >> 4].set(this.rows, x, y, z); - } - } - - private static class RowY implements IRow { - private final long[] bits; - - public RowY() { - this.bits = new long[WORDS]; - } - - @Override - public boolean get(IRow[] parent, int x, int y, int z) { - int i = ((y & 15) << 8) | ((z & 15) << 4) | (x & 15); - return (bits[i >> 6] & (1L << (i & 0x3F))) != 0; - } - - @Override - public void set(IRow[] parent, int x, int y, int z) { - int i = ((y & 15) << 8) | ((z & 15) << 4) | (x & 15); - bits[i >> 6] |= (1L << (i & 0x3F)); - } - - @Override - public boolean add(IRow[] parent, int x, int y, int z) { - int i = ((y & 15) << 8) | ((z & 15) << 4) | (x & 15); - int offset = i >> 6; - long value = bits[offset]; - long mask = (1L << (i & 0x3F)); - if ((value & mask) != 0) { - bits[offset] = value | mask; - return true; - } - return false; - } - - @Override - public void clear(IRow[] parent, int x, int y, int z) { - int i = ((y & 15) << 8) | ((z & 15) << 4) | (x & 15); - bits[i >> 6] &= ~(1L << (i & 0x3F)); - } - } - - private static IRow[] resize(IRow[] arr, IRow def) { - int len = arr.length; - int newLen = len == 1 ? 1 : Integer.highestOneBit(len - 1) * 2; - IRow[] copy = Arrays.copyOf(arr, newLen, IRow[].class); - for (int i = len; i < newLen; i++) copy[i] = def; - return copy; - } -} - diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/collection/CpuBlockSet.java b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/CpuBlockSet.java new file mode 100644 index 000000000..974e16e53 --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/CpuBlockSet.java @@ -0,0 +1,137 @@ +//package com.boydti.fawe.object.collection; +// +//import com.sk89q.worldedit.math.BlockVector2; +//import com.sk89q.worldedit.math.BlockVector3; +// +//import java.util.Iterator; +//import java.util.Set; +// +//public final class CpuBlockSet extends BlockSet { +// private static final int DIRTY_SET = 0x1; +// private static final int DIRTY_CLEAR = 0x10; +// +// public static int WORLD_HEIGHT = 256; +// private final long[] bits; +// private final byte[] dirty; +// private final int chunkShift; +// private final int chunkShift2; +// +// public CpuBlockSet(int size, int offsetX, int offsetZ) { +// super(offsetX, offsetZ); +// size = size == 1 ? 1 : Integer.highestOneBit(size - 1) * 2; +// int arrayLen = (size * size * WORLD_HEIGHT) >> 6; +// int bitShift = Integer.bitCount(Integer.highestOneBit(size) - 1); +// this.chunkShift = 12 + bitShift; +// this.chunkShift2 = 12 + bitShift * 2; +// this.bits = new long[arrayLen]; +// this.dirty = new byte[arrayLen >> 12]; +// } +// +// @Override +// public BlockVector3 getMinimumPoint() { +// +// } +// +// @Override +// public BlockVector3 getMaximumPoint() { +// // visited set +// // queue (longs) +// } +// +// @Override +// public Iterator iterator() { +// +// } +// +// @Override +// public Set getChunks() { +// // next 65536 +// } +// +// @Override +// public Set getChunkCubes() { +// // next 4096 +// } +// +// private final boolean contains(final int i) { +// return (bits[i >> 6] & (1L << (i & 0x3F))) != 0; +// } +// +// private final boolean add(final int i) { +// int offset = i >> 6; +// long value = bits[offset]; +// long mask = (1L << (i & 0x3F)); +// if ((value & mask) == 0) { +// dirty[i >> 16] |= DIRTY_SET; +// bits[offset] = value | mask; +// return true; +// } +// return false; +// } +// +// private final boolean remove(final int i) { +// int offset = i >> 6; +// long value = bits[offset]; +// long mask = (1L << (i & 0x3F)); +// if ((value & mask) != 0) { +// bits[offset] = value & ~mask; +// dirty[i >> 16] |= DIRTY_CLEAR; +// return true; +// } +// return false; +// } +// +// private final void set(final int i) { +// bits[i >> 6] |= (1L << (i & 0x3F)); +// dirty[i >> 12] |= DIRTY_SET; +// } +// +// private final void clear(final int i) { +// bits[i >> 6] &= ~(1L << (i & 0x3F)); +// dirty[i >> 12] |= DIRTY_CLEAR; +// } +// +// @Override +// public boolean contains(int x, int y, int z) { +// return contains(index(x, y, z)); +// } +// +// @Override +// public boolean add(int x, int y, int z) { +// return add(index(x, y, z)); +// } +// +// @Override +// public void set(int x, int y, int z) { +// set(index(x, y, z)); +// } +// +// @Override +// public void clear(int x, int y, int z) { +// clear(index(x, y, z)); +// } +// +// @Override +// public boolean remove(int x, int y, int z) { +// return remove(index(x, y, z)); +// } +// +// @Override +// public void clear() { +// for (int i = 0; i < dirty.length; i++) { +// boolean isDirty = dirty[i] != 0; +// if (isDirty) { +// dirty[i] = 0; +// int start = i << 10; +// int end = Math.min(bits.length, (i + 1) << 10); +// for (int j = start; j < end; j++) { +// bits[j] = 0; +// } +// } +// } +// } +// +// private final int index(int x, int y, int z) { +// return (((y & 15) << 8) | ((z & 15) << 4) | (x & 15)) | ((y >> 4) << chunkShift2) | ((z >> 4) << chunkShift) | ((x >> 4) << 12); +// } +//} diff --git a/worldedit-core/src/main/java/com/boydti/fawe/object/collection/MemBlockSet.java b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/MemBlockSet.java new file mode 100644 index 000000000..a1b43639c --- /dev/null +++ b/worldedit-core/src/main/java/com/boydti/fawe/object/collection/MemBlockSet.java @@ -0,0 +1,917 @@ +package com.boydti.fawe.object.collection; + +import com.sk89q.worldedit.math.BlockVector2; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.MutableBlockVector2; +import com.sk89q.worldedit.math.MutableBlockVector3; +import org.jetbrains.annotations.NotNull; + +import java.util.AbstractSet; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +/** + * Memory optimized BlockVector3 Set using a sparsely populated bitset and grouped by chunk section + * Note on spaghetti code / duplication + * - Uses a minimum of 1 bit per entry + * - 99.9% of the time there are no if checks on get/clear + * - Grouping / iteration is by chunk section, and the y>z>x order + */ +public final class MemBlockSet extends BlockSet { + private final static int CHUNK_LAYERS = 16; + private final static int BITS_PER_LAYER = 4096; + private final static int BITS_PER_WORD = 6; + private final static int WORDS = BITS_PER_LAYER >> BITS_PER_WORD; + private final static IRow NULL_ROW_X = new NullRowX(); + private final static IRow NULL_ROW_Z = new NullRowZ(); + private final static IRow NULL_ROW_Y = new NullRowY(); + private final IRow[] rows; + private final MutableBlockVector3 mutable; + + public MemBlockSet() { + this(16, 0, 0); + } + + public MemBlockSet(int size, int offsetX, int offsetZ) { + super(offsetX, offsetZ); + this.rows = new IRow[size]; + for (int i = 0; i < size; i++) rows[i] = NULL_ROW_X; + this.mutable = new MutableBlockVector3(); + } + + @Override + public boolean contains(int x, int y, int z) { + x -= getBlockOffsetX(); + z -= getBlockOffsetZ(); + return rows[x >> 4].get(this.rows, x, y, z - getBlockOffsetZ()); + } + + @Override + public boolean add(int x, int y, int z) { + x -= getBlockOffsetX(); + z -= getBlockOffsetZ(); + return rows[x >> 4].add(this.rows, x, y, z - getBlockOffsetZ()); + } + + @Override + public void set(int x, int y, int z) { + x -= getBlockOffsetX(); + z -= getBlockOffsetZ(); + rows[x >> 4].set(this.rows, x, y, z - getBlockOffsetZ()); + } + + @Override + public void clear(int x, int y, int z) { + x -= getBlockOffsetX(); + z -= getBlockOffsetZ(); + rows[x >> 4].clear(this.rows, x, y, z - getBlockOffsetZ()); + } + + @Override + public boolean remove(int x, int y, int z) { + x -= getBlockOffsetX(); + z -= getBlockOffsetZ(); + return rows[x >> 4].remove(this.rows, x, y, z - getBlockOffsetZ()); + } + + public BlockVector3 getMinimumPoint() { + return BlockVector3.at(getMinX(), getMinY(), getMinZ()); + } + + public BlockVector3 getMaximumPoint() { + return BlockVector3.at(getMaxX(), getMaxY(), getMaxZ()); + } + + @Override + public Set getChunks() { + return new AbstractSet() { + @NotNull + @Override + public Iterator iterator() { + return new Iterator() { + private MutableBlockVector2 mutable = new MutableBlockVector2(); + private boolean hasNext; + private int X,Z; + private int setX, setZ; + + { + init(); + } + + private void init() { + for (;X < rows.length; X++) { + IRow nullRowX = rows[X]; + if (nullRowX instanceof RowX) { + RowX rowx = (RowX) nullRowX; + for (;Z < rowx.rows.length; Z++) { + IRow nullRowZ = rowx.rows[Z]; + if (nullRowZ instanceof RowZ) { + setX = X; + setZ = Z; + Z++; + hasNext = true; + return; + } + } + Z = 0; + } + } + hasNext = false; + } + + @Override + public boolean hasNext() { + return hasNext; + } + + @Override + public BlockVector2 next() { + mutable.setComponents(setX + getBlockOffsetX(), setZ + getBlockOffsetZ()); + init(); + return mutable; + } + + @Override + public void remove() { + throw new UnsupportedOperationException("This set is immutable."); + } + }; + } + + @Override + public int size() { + int size = 0; + for (int X = 0;X < rows.length; X++) { + IRow nullRowX = rows[X]; + if (nullRowX instanceof RowX) { + RowX rowx = (RowX) nullRowX; + for (int Z = 0; Z < rowx.rows.length; Z++) { + IRow nullRowZ = rowx.rows[Z]; + if (nullRowZ instanceof RowZ) { + size++; + } + } + } + } + return size; + } + + @Override + public boolean isEmpty() { + return MemBlockSet.this.isEmpty(); + } + + @Override + public boolean contains(Object o) { + if (o instanceof BlockVector2) { + BlockVector2 other = (BlockVector2) o; + IRow rowx = rows[other.getX() - getChunkOffsetX()]; + if (rowx instanceof RowX) { + return ((RowX) rowx).rows[other.getZ() - getChunkOffsetZ()] instanceof RowZ; + } + } + return false; + } + }; + } + + public Set getChunkCubes() { + return new AbstractSet() { + @Override + public Iterator iterator() { + return new Iterator() { + private MutableBlockVector3 mutable = new MutableBlockVector3(); + private boolean hasNext; + private int X, Z, Y; + private int setX, setY, setZ; + + { + init(); + } + + private void init() { + for (;X < rows.length; X++) { + IRow nullRowX = rows[X]; + if (nullRowX instanceof RowX) { + RowX rowx = (RowX) nullRowX; + for (;Z < rowx.rows.length; Z++) { + IRow nullRowZ = rowx.rows[Z]; + if (nullRowZ instanceof RowZ) { + RowZ rowz = (RowZ) nullRowZ; + for (;Y < rowz.rows.length;Y++) { + IRow nullRowY = rowz.rows[Y]; + if (nullRowY instanceof RowY) { + setX = X; + setY = Y; + setZ = Z; + Z++; + hasNext = true; + } + } + Y = 0; + } + } + Z = 0; + } + } + hasNext = false; + } + + @Override + public boolean hasNext() { + return hasNext; + } + + @Override + public BlockVector3 next() { + mutable.setComponents(setX + getBlockOffsetX(), setY, setZ + getBlockOffsetX()); + init(); + return mutable; + } + + @Override + public void remove() { + throw new UnsupportedOperationException("This set is immutable."); + } + }; + } + + @Override + public int size() { + int size = 0; + for (int X = 0;X < rows.length; X++) { + IRow nullRowX = rows[X]; + if (nullRowX instanceof RowX) { + RowX rowx = (RowX) nullRowX; + for (int Z = 0; Z < rowx.rows.length; Z++) { + IRow nullRowZ = rowx.rows[Z]; + if (nullRowZ instanceof RowZ) { + RowZ rowz = (RowZ) nullRowZ; + for (int Y = 0; Y < rowz.rows.length; Y++) { + IRow nullRowY = rowz.rows[Y]; + if (nullRowY instanceof RowY) { + size++; + } + } + } + } + } + } + return size; + } + + @Override + public boolean isEmpty() { + return MemBlockSet.this.isEmpty(); + } + + @Override + public boolean contains(Object o) { + if (o instanceof BlockVector3) { + BlockVector3 other = (BlockVector3) o; + IRow rowx = rows[other.getX() - getChunkOffsetX()]; + if (rowx instanceof RowX) { + IRow rowz = ((RowX) rowx).rows[other.getZ()]; + if (rowz instanceof RowZ) { + return ((RowZ) rowz).rows[other.getY() - getChunkOffsetZ()] instanceof RowY; + } + } + } + return false; + } + }; + } + + @Override + public int getMinY() { + int maxY = 15; + int maxy = 16; + int by = Integer.MAX_VALUE; + for (int X = 0; X < rows.length; X++) { + IRow nullRowX = rows[X]; + if (!(nullRowX instanceof RowX)) continue; + RowX rowx = (RowX) nullRowX; + for (int Z = 0; Z < rowx.rows.length; Z++) { + IRow nullRowZ = rowx.rows[Z]; + if (!(nullRowZ instanceof RowZ)) continue; + RowZ rowz = (RowZ) nullRowZ; + outer: + for (int Y = 0; Y <= maxY; Y++) { + IRow nullRowY = rowz.rows[Y]; + if (!(nullRowY instanceof RowY)) continue; + RowY rowY = (RowY) nullRowY; + int localMaxy = Y == maxY ? maxy : 15; + for (int y = 0, i = 0; y < localMaxy; y++) { + for (int xz = 0; xz < 4; xz++, i++) { + long val = rowY.bits[i]; + if (val != 0) { + if (y == 0) { + maxY = Y - 1; + maxy = 16; + } else { + maxY = Y; + maxy = y; + } + by = (Y << 4) + y; + if (by == 0) return 0; + break outer; + } + } + } + } + } + } + return by; + } + + @Override + public int getMaxY() { + int maxY = 0; + int maxy = 0; + int by = Integer.MIN_VALUE; + for (int X = 0; X < rows.length; X++) { + IRow nullRowX = rows[X]; + if (!(nullRowX instanceof RowX)) continue; + RowX rowx = (RowX) nullRowX; + for (int Z = 0; Z < rowx.rows.length; Z++) { + IRow nullRowZ = rowx.rows[Z]; + if (!(nullRowZ instanceof RowZ)) continue; + RowZ rowz = (RowZ) nullRowZ; + outer: + for (int Y = 15; Y >= maxY; Y--) { + IRow nullRowY = rowz.rows[Y]; + if (!(nullRowY instanceof RowY)) continue; + RowY rowY = (RowY) nullRowY; + int localMaxy = Y == maxY ? maxy : 0; + for (int y = 15, i = 63; y >= localMaxy; y--) { + for (int xz = 3; xz >= 0; xz--, i--) { + long val = rowY.bits[i]; + if (val != 0) { + if (y == 15) { + maxY = Y + 1; + maxy = 0; + } else { + maxY = Y; + maxy = y + 1; + } + by = (Y << 4) + y; + if (by == 255) return 255; + break outer; + } + } + } + } + } + } + return by; + } + + public int getMaxZ() { + int maxChunkZ = 0; + int maxz = -1; + int tz = Integer.MIN_VALUE; + for (int X = rows.length - 1; X >= 0; X--) { + IRow nullRowX = rows[X]; + if (!(nullRowX instanceof RowX)) continue; + RowX rowx = (RowX) nullRowX; + outer: + for (int Z = rowx.rows.length - 1; Z >= maxChunkZ ; Z--) { + IRow nullRowZ = rowx.rows[Z]; + if (!(nullRowZ instanceof RowZ)) continue; + RowZ rowz = (RowZ) nullRowZ; + if (Z != maxChunkZ) { + maxChunkZ = Z; + maxz = -1; + } + for (int Y = rowz.rows.length - 1; Y >= 0; Y--) { + IRow nullRowY = rowz.rows[Y]; + if (!(nullRowY instanceof RowY)) continue; + RowY rowY = (RowY) nullRowY; + for (int y = 15, i1 = 63; y >= 0; y--, i1 -= 4) { + for (int z = 12, i = i1; z > maxz - 3; z -= 4, i--) { + long bitBuffer = rowY.bits[i]; + if (bitBuffer != 0) { + int highest = highestBit(bitBuffer); + maxz = z + (highest >> 4); + if (maxz == 15) { + tz = (maxChunkZ << 4) + 15; + maxChunkZ++; + break outer; + } else { + tz = Math.max(tz, (maxChunkZ << 4) + maxz); + break; + } + } + } + } + } + break; + } + } + return tz + getBlockOffsetZ(); + } + + public int getMaxX() { + for (int X = rows.length - 1; X >= 0; X--) { + IRow nullRowX = rows[X]; + if (!(nullRowX instanceof RowX)) continue; + int tx = (X << 4); + RowX rowx = (RowX) nullRowX; + long or = 0; + for (int Z = rowx.rows.length - 1; Z >= 0 ; Z--) { + IRow nullRowZ = rowx.rows[Z]; + if (!(nullRowZ instanceof RowZ)) continue; + RowZ rowz = (RowZ) nullRowZ; + for (int Y = rowz.rows.length - 1; Y >= 0; Y--) { + IRow nullRowY = rowz.rows[Y]; + if (!(nullRowY instanceof RowY)) continue; + RowY rowY = (RowY) nullRowY; + for (long value : rowY.bits) { + or |= value; + } + or = (or & 0xFFFF) | ((or >> 16) & 0xFFFF) | ((or >> 32) & 0xFFFF) | ((or >> 48) & 0xFFFF); + if (highestBit(or) == 15) return tx + 15; + } + } + int highest = highestBit(or); + if (highest != 64) { + return tx + highest + getBlockOffsetX(); + } + } + return Integer.MAX_VALUE; + } + + public int getMinZ() { + int maxChunkZ = rows.length - 1; + int maxz = 16; + int bz = Integer.MAX_VALUE; + for (int X = 0; X < rows.length; X++) { + IRow nullRowX = rows[X]; + if (!(nullRowX instanceof RowX)) continue; + RowX rowx = (RowX) nullRowX; + outer: + for (int Z = 0; Z <= maxChunkZ; Z++) { + IRow nullRowZ = rowx.rows[Z]; + if (!(nullRowZ instanceof RowZ)) continue; + RowZ rowz = (RowZ) nullRowZ; + if (Z != maxChunkZ) { + maxChunkZ = Z; + maxz = 16; + } + for (int Y = 0; Y < rowz.rows.length; Y++) { + IRow nullRowY = rowz.rows[Y]; + if (!(nullRowY instanceof RowY)) continue; + RowY rowY = (RowY) nullRowY; + for (int y = 0, i1 = 0; y < 16; y++, i1 += 4) { + for (int z = 0, i = i1; z < maxz; z += 4, i++) { + long bitBuffer = rowY.bits[i]; + if (bitBuffer != 0) { + int lowest = lowestBit(bitBuffer); + maxz = z + (lowest >> 4); + if (maxz == 0) { + bz = (maxChunkZ << 4); + maxChunkZ--; + break outer; + } else { + bz = Math.min(bz, (maxChunkZ << 4) + maxz); + break; + } + } + } + } + } + break; + } + } + return bz + getBlockOffsetZ(); + } + + public int getMinX() { + for (int X = 0; X < rows.length; X++) { + IRow nullRowX = rows[X]; + if (!(nullRowX instanceof RowX)) continue; + int bx = X << 4; + RowX rowx = (RowX) nullRowX; + long or = 0; + for (int Z = 0; Z < rowx.rows.length; Z++) { + IRow nullRowZ = rowx.rows[Z]; + if (!(nullRowZ instanceof RowZ)) continue; + RowZ rowz = (RowZ) nullRowZ; + for (int Y = 0; Y < rowz.rows.length; Y++) { + IRow nullRowY = rowz.rows[Y]; + if (!(nullRowY instanceof RowY)) continue; + RowY rowY = (RowY) nullRowY; + for (long value : rowY.bits) { + or |= value; + } + or = (or & 0xFFFF) | ((or >> 16) & 0xFFFF) | ((or >> 32) & 0xFFFF) | ((or >> 48) & 0xFFFF); + if (lowestBit(or) == 0) return bx; + } + } + int lowest = lowestBit(or); + if (lowest != 64) { + return bx + lowest + getBlockOffsetX(); + } + } + return Integer.MAX_VALUE; + } + + public void iterate(BlockIterator iterator) { + for (int X = 0; X < rows.length; X++) { + IRow nullRowX = rows[X]; + if (!(nullRowX instanceof RowX)) continue; + int bx = getBlockOffsetX() + (X << 4); + RowX rowx = (RowX) nullRowX; + for (int Z = 0; Z < rowx.rows.length; Z++) { + IRow nullRowZ = rowx.rows[Z]; + if (!(nullRowZ instanceof RowZ)) continue; + int bz = getBlockOffsetZ() + (Z << 4); + RowZ rowz = (RowZ) nullRowZ; + for (int Y = 0; Y < rowz.rows.length; Y++) { + IRow nullRowY = rowz.rows[Y]; + if (!(nullRowY instanceof RowY)) continue; + int by = Y << 4; + RowY rowY = (RowY) nullRowY; + for (int y = 0, i = 0; y < 16; y++) { + for (int z = 0; z < 16; z += 4, i++) { + long bitBuffer = rowY.bits[i]; + if (bitBuffer != 0) { + if (bitBuffer == -1L) { + for (int zz = z; zz < z + 4; zz++) { + for (int x = 0; x < 16; x++) { + iterator.apply(bx + x, by + y, bz + zz); + } + } + continue; + } + do { + final long lowBit = Long.lowestOneBit(bitBuffer); + final int bitIndex = Long.bitCount(lowBit - 1); + int x = bitIndex & 15; + int zz = z + (bitIndex >> 4); + iterator.apply(bx + x, by + y, bz + zz); + bitBuffer = bitBuffer ^ lowBit; + } while (bitBuffer != 0); + } + + } + } + } + } + } + } + + @Override + public Iterator iterator() { + return new Iterator() { + private int bx, by, bz, zz, yy; + private RowX rowX; + private RowZ rowZ; + private RowY rowY; + private long[] bits; + private int bitsIndex = 0; + private int yIndex = 0; + private int zIndex = 0; + private int xIndex = 0; + private long bitBuffer = 0; + private boolean next; + + { + if (nextRowX()) { + if (nextRowZ()) { + if (nextRowY()) { + next = nextLong(); + } + } + } + } + + private boolean nextRowX() { + while (xIndex < rows.length) { + bx = getBlockOffsetX() + (xIndex << 4); + IRow nullRowX = rows[xIndex++]; + if (nullRowX instanceof RowX) { + rowX = (RowX) nullRowX; + return true; + } + } + return false; + } + + private boolean nextRowZ() { + while (zIndex < rowX.rows.length) { + bz = getBlockOffsetZ() + (zIndex << 4); + IRow nullRowZ = rowX.rows[zIndex++]; + if (nullRowZ instanceof RowZ) { + rowZ = (RowZ) nullRowZ; + return true; + } + } + if (nextRowX()) { + zIndex = 0; + return nextRowZ(); + } + return false; + } + + private boolean nextRowY() { + while (yIndex < rowZ.rows.length) { + by = yIndex << 4; + IRow nullRowY = rowZ.rows[yIndex++]; + if (nullRowY instanceof RowY) { + rowY = (RowY) nullRowY; + bits = rowY.bits; + return true; + } + } + if (nextRowZ()) { + yIndex = 0; + return nextRowY(); + } + return false; + } + + private boolean nextLong() { + if (bitBuffer == 0) { + do { + bitBuffer = bits[bitsIndex++]; + if (bitsIndex == bits.length) { + bitsIndex = 0; + if (!nextRowY()) { + return next = false; + } + } + } while (bitBuffer == 0); + zz = bz + (((bitsIndex - 1) << 2) & 15); + yy = by + ((bitsIndex - 1) >> 2); + } + return true; + } + + @Override + public boolean hasNext() { + return next; + } + + @Override + public BlockVector3 next() { + final long lowBit = Long.lowestOneBit(bitBuffer); + final int bitIndex = Long.bitCount(lowBit-1); + { + mutable.setComponents((bx) + (bitIndex & 15), yy, (zz) + (bitIndex)); + } + bitBuffer = bitBuffer ^ lowBit; + nextLong(); + return mutable; + } + + @Override + public void remove() { + // TODO optimize + MemBlockSet.this.remove(mutable); + } + }; + } + + @Override + public boolean isEmpty() { + for (int X = 0; X < rows.length; X++) { + IRow nullRowX = rows[X]; + if (!(nullRowX instanceof RowX)) continue; + RowX rowx = (RowX) nullRowX; + for (int Z = 0; Z < rowx.rows.length; Z++) { + IRow nullRowZ = rowx.rows[Z]; + if (!(nullRowZ instanceof RowZ)) continue; + RowZ rowz = (RowZ) nullRowZ; + for (int Y = 0; Y < 16; Y++) { + IRow nullRowY = rowz.rows[Y]; + if (!(nullRowY instanceof RowY)) continue; + RowY rowY = (RowY) nullRowY; + for (long bit : rowY.bits) { + if (bit != 0) return true; + } + } + } + } + return false; + } + + @Override + public int size() { + return (int) sizeLong(); + } + + public long sizeLong() { + long total = 0; + long lastBit = 0; + int lastCount = 0; + for (int X = 0; X < rows.length; X++) { + IRow nullRowX = rows[X]; + if (!(nullRowX instanceof RowX)) continue; + RowX rowx = (RowX) nullRowX; + for (int Z = 0; Z < rowx.rows.length; Z++) { + IRow nullRowZ = rowx.rows[Z]; + if (!(nullRowZ instanceof RowZ)) continue; + RowZ rowz = (RowZ) nullRowZ; + outer: + for (int Y = 0; Y < 16; Y++) { + IRow nullRowY = rowz.rows[Y]; + if (!(nullRowY instanceof RowY)) continue; + RowY rowY = (RowY) nullRowY; + for (long bit : rowY.bits) { + if (bit == 0) continue; + else if (bit == -1L) { + total += 64; + } + else if (bit == lastBit) { + total += lastCount; + } else { + lastBit = bit; + total += lastCount = Long.bitCount(bit); + } + } + } + } + } + return total; + } + + public void clear() { + Arrays.fill(rows, NULL_ROW_X); + } + + public interface BlockIterator { + void apply(int x, int y, int z); + } + + private interface IRow { + default boolean get(IRow[] rows, int x, int y, int z) { return false; } + void set(IRow[] rows, int x, int y, int z); + default boolean add(IRow[] rows, int x, int y, int z) { + set(rows, x, y, z); + return true; + } + default boolean remove(IRow[] rows, int x, int y, int z) { + remove(rows, x, y, z); + return false; + } + default void clear(IRow[] rows, int x, int y, int z) { return; } + } + + private static final class NullRowX implements IRow { + @Override + public void set(IRow[] parent, int x, int y, int z) { + IRow row = new RowX(parent.length); + parent[x >> 4] = row; + row.set(parent, x, y, z); + } + } + + private static final class NullRowZ implements IRow { + @Override + public void set(IRow[] parent, int x, int y, int z) { + IRow row = new RowZ(); + parent[z >> 4] = row; + row.set(parent, x, y, z); + } + } + + private static final class NullRowY implements IRow { + @Override + public void set(IRow[] parent, int x, int y, int z) { + IRow row = new RowY(); + parent[y >> 4] = row; + row.set(parent, x, y, z); + } + } + + private static final class RowX implements IRow { + private final IRow[] rows; + + public RowX(int size) { + this.rows = new IRow[size]; + for (int i = 0; i < size; i++) rows[i] = NULL_ROW_Z; + } + + @Override + public boolean get(IRow[] parent, int x, int y, int z) { + return rows[z >> 4].get(this.rows, x, y, z); + } + + @Override + public void set(IRow[] parent, int x, int y, int z) { + this.rows[z >> 4].set(this.rows, x, y, z); + } + + @Override + public boolean add(IRow[] parent, int x, int y, int z) { + return this.rows[z >> 4].add(this.rows, x, y, z); + } + + @Override + public void clear(IRow[] parent, int x, int y, int z) { + this.rows[z >> 4].clear(this.rows, x, y, z); + } + + @Override + public boolean remove(IRow[] parent, int x, int y, int z) { + return this.rows[z >> 4].remove(this.rows, x, y, z); + } + } + + private static final class RowZ implements IRow { + private final IRow[] rows; + + public RowZ() { + this.rows = new IRow[CHUNK_LAYERS]; + for (int i = 0; i < CHUNK_LAYERS; i++) rows[i] = NULL_ROW_Y; + } + + @Override + public boolean get(IRow[] parent, int x, int y, int z) { + return rows[y >> 4].get(this.rows, x, y, z); + } + + @Override + public void set(IRow[] parent, int x, int y, int z) { + this.rows[y >> 4].set(this.rows, x, y, z); + } + + @Override + public boolean add(IRow[] parent, int x, int y, int z) { + return this.rows[y >> 4].add(this.rows, x, y, z); + } + + @Override + public void clear(IRow[] parent, int x, int y, int z) { + this.rows[y >> 4].set(this.rows, x, y, z); + } + + @Override + public boolean remove(IRow[] parent, int x, int y, int z) { + return this.rows[y >> 4].remove(this.rows, x, y, z); + } + } + + private static final class RowY implements IRow { + private final long[] bits; + + public RowY() { + this.bits = new long[WORDS]; + } + + @Override + public boolean get(IRow[] parent, int x, int y, int z) { + int i = ((y & 15) << 8) | ((z & 15) << 4) | (x & 15); + return (bits[i >> 6] & (1L << (i & 0x3F))) != 0; + } + + @Override + public void set(IRow[] parent, int x, int y, int z) { + int i = ((y & 15) << 8) | ((z & 15) << 4) | (x & 15); + bits[i >> 6] |= (1L << (i & 0x3F)); + } + + @Override + public boolean add(IRow[] parent, int x, int y, int z) { + int i = ((y & 15) << 8) | ((z & 15) << 4) | (x & 15); + int offset = i >> 6; + long value = bits[offset]; + long mask = (1L << (i & 0x3F)); + if ((value & mask) == 0) { + bits[offset] = value | mask; + return true; + } + return false; + } + + @Override + public void clear(IRow[] parent, int x, int y, int z) { + int i = ((y & 15) << 8) | ((z & 15) << 4) | (x & 15); + bits[i >> 6] &= ~(1L << (i & 0x3F)); + } + + @Override + public boolean remove(IRow[] rows, int x, int y, int z) { + int i = ((y & 15) << 8) | ((z & 15) << 4) | (x & 15); + int offset = i >> 6; + long value = bits[offset]; + long mask = (1L << (i & 0x3F)); + if ((value & mask) != 0) { + bits[offset] = value & ~mask; + return true; + } + return false; + } + } + + private static IRow[] resize(IRow[] arr, IRow def) { + int len = arr.length; + int newLen = len == 1 ? 1 : Integer.highestOneBit(len - 1) * 2; + IRow[] copy = Arrays.copyOf(arr, newLen, IRow[].class); + for (int i = len; i < newLen; i++) copy[i] = def; + return copy; + } +} \ No newline at end of file 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 f7ecfa2b4..5517f7be6 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 @@ -1,6 +1,5 @@ package com.boydti.fawe.object.regions; -import com.boydti.fawe.object.HasFaweQueue; import com.boydti.fawe.object.collection.BlockVectorSet; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.WorldEditException; @@ -49,7 +48,7 @@ public class FuzzyRegion extends AbstractRegion { setMinMax(p.getBlockX(), p.getBlockY(), p.getBlockZ()); return true; } - }, 256, extent instanceof HasFaweQueue ? (HasFaweQueue) extent : null); + }, 256); search.setVisited(set); search.visit(BlockVector3.at(x, y, z)); Operations.completeBlindly(search); 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 2ecc31871..11e6a2538 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -1125,8 +1125,8 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, final int startCheckY = fullHeight ? 0 : startPerformY; final int endY = region.getMaximumPoint().getBlockY(); RegionVisitor visitor = new RegionVisitor(flat, pos -> { - int x = pos.getBlockX(); - int z = pos.getBlockZ(); + int x = pos.getX(); + int z = pos.getZ(); int freeSpot = startCheckY; for (int y = startCheckY; y <= endY; y++) { if (y < startPerformY) { @@ -1175,7 +1175,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, final BlockReplace replace = new BlockReplace(EditSession.this, pattern); // Pick how we're going to visit blocks - RecursiveVisitor visitor = new DirectionalVisitor(mask, replace, origin, direction, (int) (radius * 2 + 1), this); + RecursiveVisitor visitor = new DirectionalVisitor(mask, replace, origin, direction, (int) (radius * 2 + 1)); // Start at the origin visitor.visit(origin); @@ -1230,9 +1230,9 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, // Pick how we're going to visit blocks RecursiveVisitor visitor; if (recursive) { - visitor = new RecursiveVisitor(mask, replace, (int) (radius * 2 + 1), this); + visitor = new RecursiveVisitor(mask, replace, (int) (radius * 2 + 1)); } else { - visitor = new DownwardVisitor(mask, replace, origin.getBlockY(), (int) (radius * 2 + 1), this); + visitor = new DownwardVisitor(mask, replace, origin.getBlockY(), (int) (radius * 2 + 1)); } // Start at the origin @@ -1510,7 +1510,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, int minY = region.getMinimumPoint().getBlockY(); int maxY = Math.min(getMaximumPoint().getBlockY(), region.getMaximumPoint().getBlockY() + 1); SurfaceRegionFunction surface = new SurfaceRegionFunction(this, offset, minY, maxY); - FlatRegionVisitor visitor = new FlatRegionVisitor(asFlatRegion(region), surface, this); + FlatRegionVisitor visitor = new FlatRegionVisitor(asFlatRegion(region), surface); Operations.completeBlindly(visitor); return this.changes = visitor.getAffected(); } @@ -1674,7 +1674,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, } else { replace = new BlockReplace(this, (BlockTypes.AIR.getDefaultState())); } - RecursiveVisitor visitor = new RecursiveVisitor(mask, replace, (int) (radius * 2 + 1), this); + RecursiveVisitor visitor = new RecursiveVisitor(mask, replace, (int) (radius * 2 + 1)); // Around the origin in a 3x3 block for (BlockVector3 position : CuboidRegion.fromCenter(origin, 1)) { @@ -2556,7 +2556,7 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, throw new RuntimeException(e); } } - }, this); + }); Operations.completeBlindly(visitor); changes += visitor.getAffected(); return changes; @@ -3061,12 +3061,6 @@ public class EditSession extends AbstractDelegateExtent implements HasFaweQueue, return false; } -// public void dropItem(BlockVector3 position, BaseItemStack item) { -// if (getWorld() != null) { -// getWorld().dropItem(position, item); -// } -// } - @Override public void simulateBlockMine(BlockVector3 position) { TaskManager.IMP.sync((Supplier) () -> { diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/Extent.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/Extent.java index 08f75d223..20949aa8b 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extent/Extent.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extent/Extent.java @@ -19,13 +19,11 @@ package com.sk89q.worldedit.extent; -import com.boydti.fawe.example.MappedFaweQueue; import com.boydti.fawe.jnbt.anvil.generator.CavesGen; import com.boydti.fawe.jnbt.anvil.generator.GenBase; import com.boydti.fawe.jnbt.anvil.generator.OreGen; import com.boydti.fawe.jnbt.anvil.generator.Resource; import com.boydti.fawe.jnbt.anvil.generator.SchemGen; - import com.boydti.fawe.object.clipboard.WorldCopyClipboard; import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.WorldEditException; @@ -35,7 +33,6 @@ import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.function.RegionMaskingFilter; import com.sk89q.worldedit.function.block.BlockReplace; import com.sk89q.worldedit.function.mask.BlockMask; -import com.sk89q.worldedit.function.mask.BlockMaskBuilder; import com.sk89q.worldedit.function.mask.ExistingBlockMask; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.function.operation.Operation; @@ -54,7 +51,6 @@ import com.sk89q.worldedit.registry.state.PropertyGroup; import com.sk89q.worldedit.session.ClipboardHolder; import com.sk89q.worldedit.util.Countable; import com.sk89q.worldedit.util.Location; -import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; @@ -403,7 +399,7 @@ public interface Extent extends InputExtent, OutputExtent { } default boolean cancel() { - + return true; } default int getMaxY() { 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 eb037d381..d428c7e83 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 @@ -20,14 +20,7 @@ package com.sk89q.worldedit.function.visitor; import com.boydti.fawe.config.BBC; -import com.boydti.fawe.config.Settings; -import com.boydti.fawe.example.MappedFaweQueue; -import com.boydti.fawe.object.FaweQueue; -import com.boydti.fawe.object.HasFaweQueue; -import com.boydti.fawe.object.IntegerTrio; import com.boydti.fawe.object.collection.BlockVectorSet; - -import static com.google.common.base.Preconditions.checkNotNull; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.function.RegionFunction; import com.sk89q.worldedit.function.operation.Operation; @@ -39,11 +32,11 @@ import com.sk89q.worldedit.util.Direction; import java.util.ArrayList; 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 static com.google.common.base.Preconditions.checkNotNull; + /** * Performs a breadth-first search starting from points added with * {@link #visit(BlockVector3)}. The search continues @@ -87,7 +80,6 @@ public abstract class BreadthFirstSearch implements Operation { private final RegionFunction function; private BlockVector3[] directions; private BlockVectorSet visited; - private final MappedFaweQueue mFaweQueue; private BlockVectorSet queue; private int currentDepth = 0; private final int maxDepth; @@ -105,15 +97,7 @@ public abstract class BreadthFirstSearch implements Operation { } public BreadthFirstSearch(RegionFunction function, int maxDepth) { - this(function, maxDepth, null); checkNotNull(function); - - } - - public BreadthFirstSearch(RegionFunction function, int maxDepth, HasFaweQueue faweQueue) { - checkNotNull(function); - FaweQueue fq = faweQueue != null ? faweQueue.getQueue() : null; - this.mFaweQueue = fq instanceof MappedFaweQueue ? (MappedFaweQueue) fq : null; this.queue = new BlockVectorSet(); this.visited = new BlockVectorSet(); this.function = function; @@ -236,28 +220,6 @@ public abstract class BreadthFirstSearch implements Operation { BlockVectorSet tempQueue = new BlockVectorSet(); BlockVectorSet chunkLoadSet = new BlockVectorSet(); for (currentDepth = 0; !queue.isEmpty() && currentDepth <= maxDepth; currentDepth++) { - if (mFaweQueue != null && Settings.IMP.QUEUE.PRELOAD_CHUNKS > 1) { - int cx = Integer.MIN_VALUE; - int cz = Integer.MIN_VALUE; - for (BlockVector3 from : queue) { - 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.getY(); - if (y < 0 || y >= 256) { - continue; - } - if (!visited.contains(x, y, z)) { - chunkLoadSet.add(cx, 0, cz); - } - } - } - } - for (BlockVector3 chunk : chunkLoadSet) { - mFaweQueue.queueChunkLoad(chunk.getBlockX(), chunk.getBlockZ()); - } - } for (BlockVector3 from : queue) { if (function.apply(from)) affected++; for (int i = 0, j = 0; i < dirs.length && j < maxBranch; i++) { 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 9a0b8c912..27aa99562 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 @@ -19,15 +19,10 @@ package com.sk89q.worldedit.function.visitor; -import com.boydti.fawe.object.HasFaweQueue; -import com.sk89q.worldedit.math.MutableBlockVector3; import com.sk89q.worldedit.function.RegionFunction; import com.sk89q.worldedit.function.mask.Mask; import com.sk89q.worldedit.math.BlockVector3; -import java.util.Collection; - - import static com.google.common.base.Preconditions.checkNotNull; /** @@ -43,11 +38,11 @@ public class DirectionalVisitor extends RecursiveVisitor { private final BlockVector3 dirVec; public DirectionalVisitor(Mask mask, RegionFunction function, BlockVector3 origin, BlockVector3 direction) { - this(mask, function, origin, direction, Integer.MAX_VALUE, null); + this(mask, function, origin, direction, Integer.MAX_VALUE); } - public DirectionalVisitor(Mask mask, RegionFunction function, BlockVector3 origin, BlockVector3 direction, int distance, HasFaweQueue hasFaweQueue) { - super(mask, function, distance, hasFaweQueue); + public DirectionalVisitor(Mask mask, RegionFunction function, BlockVector3 origin, BlockVector3 direction, int distance) { + super(mask, function, distance); checkNotNull(mask); this.origin = origin; this.dirVec = direction; diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/RecursiveVisitor.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/RecursiveVisitor.java index 6564ff54f..0ce97d0c8 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/RecursiveVisitor.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/visitor/RecursiveVisitor.java @@ -19,7 +19,6 @@ package com.sk89q.worldedit.function.visitor; -import com.boydti.fawe.object.HasFaweQueue; import static com.google.common.base.Preconditions.checkNotNull; import com.sk89q.worldedit.function.RegionFunction; @@ -45,11 +44,7 @@ public class RecursiveVisitor extends BreadthFirstSearch { * @param function the function */ public RecursiveVisitor(Mask mask, RegionFunction function, int maxDepth) { - this(mask, function, maxDepth, null); - } - - public RecursiveVisitor(Mask mask, RegionFunction function, int maxDepth, HasFaweQueue faweQueue) { - super(function, maxDepth, faweQueue); + super(function, maxDepth); checkNotNull(mask); this.mask = mask; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/AbstractRegion.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/AbstractRegion.java index d1a8e0d3e..a58cb450f 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/AbstractRegion.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/AbstractRegion.java @@ -27,13 +27,14 @@ import com.sk89q.worldedit.regions.iterator.RegionIterator; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.storage.ChunkStore; +import java.util.AbstractSet; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; -public abstract class AbstractRegion implements Region { +public abstract class AbstractRegion extends AbstractSet implements Region { protected World world; @@ -41,6 +42,11 @@ public abstract class AbstractRegion implements Region { this.world = world; } + @Override + public int size() { + return getArea(); + } + @Override public Vector3 getCenter() { return getMinimumPoint().add(getMaximumPoint()).toVector3().divide(2); @@ -100,21 +106,6 @@ public abstract class AbstractRegion implements Region { return points; } - /** - * Get the number of blocks in the region. - * - * @return number of blocks - */ - @Override - public int getArea() { - BlockVector3 min = getMinimumPoint(); - BlockVector3 max = getMaximumPoint(); - - return (max.getX() - min.getX() + 1) * - (max.getY() - min.getY() + 1) * - (max.getZ() - min.getZ() + 1); - } - /** * Get X-size. * diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/Region.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/Region.java index c3dc4d55a..89f2c3522 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/Region.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/Region.java @@ -62,14 +62,23 @@ public interface Region extends Iterable, Cloneable { * * @return center point */ - Vector3 getCenter(); + default Vector3 getCenter() { + return getMinimumPoint().add(getMaximumPoint()).toVector3().divide(2); + } /** * Get the number of blocks in the region. * * @return number of blocks */ - int getArea(); + default int getArea() { + BlockVector3 min = getMinimumPoint(); + BlockVector3 max = getMaximumPoint(); + + return (max.getX() - min.getX() + 1) * + (max.getY() - min.getY() + 1) * + (max.getZ() - min.getZ() + 1); + } /** * Get X-size.