some refactoring to pipeline classes (WIP)

This commit is contained in:
Jesse Boyd 2019-07-17 05:10:39 +10:00
parent 14d5275e05
commit cfbde956f4
No known key found for this signature in database
GPG Key ID: 59F1DE6293AF6E1F
21 changed files with 1388 additions and 439 deletions

View File

@ -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<T extends Future<T>> 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));

View File

@ -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<IChunkGet> 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<br>

View File

@ -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<BlockVector3> vset, Pattern pattern) {
TODO
if (vset instanceof Region) {
setBlocks((Region) vset, pattern);
}
for (BlockVector3 blockVector3 : vset) {
pattern.apply(this, blockVector3, blockVector3);
}
return getChanges();
}

View File

@ -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<IChunkGet> supplier) {
return cache.get(MathMan.pairInt(X, Z), supplier);
}
/**

View File

@ -110,8 +110,10 @@ public abstract class ChunkHolder implements IChunk, Supplier<IChunkGet> {
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();
}

View File

@ -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);

View File

@ -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;

View File

@ -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 <T>
*/
public class AdaptedSetCollection<T, V> implements Set<V> {
private final Function<T, V> adapter;
private final Collection<V> adapted;
private final Collection<T> original;
public AdaptedSetCollection(Collection<T> collection, Function<T, V> adapter) {
this.original = collection;
this.adapted = Collections2.transform(collection, adapter);
this.adapter = adapter;
}
public Collection<T> 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<V> iterator() {
return adapted.iterator();
}
@NotNull
@Override
public Object[] toArray() {
return adapted.toArray();
}
@NotNull
@Override
public <V> 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<? extends V> c) {
return adapted.addAll(c);
}
@Override
public boolean removeAll(@NotNull Collection<?> c) {
return adapted.removeAll(c);
}
public boolean removeIf(Predicate<? super V> 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<V> spliterator() {
return adapted.spliterator();
}
@Override
public Stream<V> stream() {
return adapted.stream();
}
@Override
public Stream<V> parallelStream() {
return adapted.parallelStream();
}
public void forEach(Consumer<? super V> action) {
adapted.forEach(action);
}
}

View File

@ -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<BlockVector3> iterator();
public abstract Set<BlockVector2> getChunks();
public abstract Set<BlockVector3> 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 {
}
}

View File

@ -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<BlockVector3> {
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<BlockVector3> iterator() {
return null;
}
@NotNull
@Override
public Object[] toArray() {
return new Object[0];
}
@NotNull
@Override
public <T> 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<? extends BlockVector3> 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() {
}
}

View File

@ -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;
}
}

View File

@ -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<BlockVector3> iterator() {
//
// }
//
// @Override
// public Set<BlockVector2> getChunks() {
// // next 65536
// }
//
// @Override
// public Set<BlockVector3> 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);
// }
//}

View File

@ -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<BlockVector2> getChunks() {
return new AbstractSet<BlockVector2>() {
@NotNull
@Override
public Iterator<BlockVector2> iterator() {
return new Iterator<BlockVector2>() {
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<BlockVector3> getChunkCubes() {
return new AbstractSet<BlockVector3>() {
@Override
public Iterator<BlockVector3> iterator() {
return new Iterator<BlockVector3>() {
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<BlockVector3> iterator() {
return new Iterator<BlockVector3>() {
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;
}
}

View File

@ -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);

View File

@ -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<Object>) () -> {

View File

@ -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() {

View File

@ -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++) {

View File

@ -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;

View File

@ -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;
}

View File

@ -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<BlockVector3> 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.
*

View File

@ -62,14 +62,23 @@ public interface Region extends Iterable<BlockVector3>, 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.