mirror of
https://github.com/plexusorg/Plex-FAWE.git
synced 2025-06-11 20:13:55 +00:00
Merge branch 'commanding' of https://github.com/IntellectualSites/FastAsyncWorldEdit-1.13 into commanding
This commit is contained in:
@ -4,6 +4,7 @@ import com.boydti.fawe.beta.Trimable;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.object.collection.BitArray4096;
|
||||
import com.boydti.fawe.object.collection.IterableThreadLocal;
|
||||
import com.boydti.fawe.util.IOUtil;
|
||||
import com.boydti.fawe.util.MathMan;
|
||||
import com.sk89q.jnbt.ByteArrayTag;
|
||||
import com.sk89q.jnbt.ByteTag;
|
||||
@ -29,92 +30,182 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public final class FaweCache implements Trimable {
|
||||
public final static int BLOCKS_PER_LAYER = 4096;
|
||||
public final static int CHUNK_LAYERS = 16;
|
||||
public final static int WORLD_HEIGHT = CHUNK_LAYERS << 4;
|
||||
public final static int WORLD_MAX_Y = WORLD_HEIGHT - 1;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
public enum FaweCache implements Trimable {
|
||||
IMP
|
||||
; // singleton
|
||||
|
||||
public static final char[] EMPTY_CHAR_4096 = new char[4096];
|
||||
public final int BLOCKS_PER_LAYER = 4096;
|
||||
public final int CHUNK_LAYERS = 16;
|
||||
public final int WORLD_HEIGHT = CHUNK_LAYERS << 4;
|
||||
public final int WORLD_MAX_Y = WORLD_HEIGHT - 1;
|
||||
|
||||
public final char[] EMPTY_CHAR_4096 = new char[4096];
|
||||
|
||||
private final IdentityHashMap<Class, IterableThreadLocal> REGISTERED_SINGLETONS = new IdentityHashMap<>();
|
||||
private final IdentityHashMap<Class, Pool> REGISTERED_POOLS = new IdentityHashMap<>();
|
||||
|
||||
public interface Pool<T> {
|
||||
T poll();
|
||||
default boolean offer(T recycle) {
|
||||
return false;
|
||||
}
|
||||
default void clear() {}
|
||||
}
|
||||
|
||||
public class QueuePool<T> extends ConcurrentLinkedQueue<T> implements Pool<T> {
|
||||
private final Supplier<T> supplier;
|
||||
|
||||
public QueuePool(Supplier<T> supplier) {
|
||||
this.supplier = supplier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean offer(T t) {
|
||||
return super.offer(t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T poll() {
|
||||
T result = super.poll();
|
||||
if (result == null) {
|
||||
return supplier.get();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
if (!isEmpty()) super.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Palette buffers / cache
|
||||
*/
|
||||
|
||||
@Override
|
||||
public boolean trim(boolean aggressive) {
|
||||
public synchronized boolean trim(boolean aggressive) {
|
||||
BLOCK_TO_PALETTE.clean();
|
||||
PALETTE_TO_BLOCK.clean();
|
||||
BLOCK_STATES.clean();
|
||||
SECTION_BLOCKS.clean();
|
||||
PALETTE_CACHE.clean();
|
||||
PALETTE_TO_BLOCK_CHAR.clean();
|
||||
INDEX_STORE.clean();
|
||||
|
||||
MUTABLE_VECTOR3.clean();
|
||||
MUTABLE_BLOCKVECTOR3.clean();
|
||||
SECTION_BITS_TO_CHAR.clean();
|
||||
for (Map.Entry<Class, IterableThreadLocal> entry : REGISTERED_SINGLETONS.entrySet()) {
|
||||
entry.getValue().clean();
|
||||
}
|
||||
for (Map.Entry<Class, Pool> entry : REGISTERED_POOLS.entrySet()) {
|
||||
Pool pool = entry.getValue();
|
||||
pool.clear();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static final IterableThreadLocal<int[]> BLOCK_TO_PALETTE = new IterableThreadLocal<int[]>() {
|
||||
@Override
|
||||
public int[] init() {
|
||||
int[] result = new int[BlockTypes.states.length];
|
||||
Arrays.fill(result, Integer.MAX_VALUE);
|
||||
return result;
|
||||
public final <T> Pool<T> getPool(Class<T> clazz) {
|
||||
Pool<T> pool = REGISTERED_POOLS.get(clazz);
|
||||
if (pool == null) {
|
||||
synchronized (this) {
|
||||
pool = REGISTERED_POOLS.get(clazz);
|
||||
if (pool == null) {
|
||||
Fawe.debug("Not registered " + clazz);
|
||||
Supplier<T> supplier = IOUtil.supplier(clazz::newInstance);
|
||||
pool = supplier::get;
|
||||
REGISTERED_POOLS.put(clazz, pool);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
return pool;
|
||||
}
|
||||
|
||||
public static final IterableThreadLocal<char[]> SECTION_BITS_TO_CHAR = new IterableThreadLocal<char[]>() {
|
||||
@Override
|
||||
public char[] init() {
|
||||
char[] result = new char[4096];
|
||||
return result;
|
||||
}
|
||||
};
|
||||
public final <T> T getFromPool(Class<T> clazz) {
|
||||
Pool<T> pool = getPool(clazz);
|
||||
return pool.poll();
|
||||
}
|
||||
|
||||
public static final IterableThreadLocal<int[]> PALETTE_TO_BLOCK = new IterableThreadLocal<int[]>() {
|
||||
@Override
|
||||
public int[] init() {
|
||||
return new int[Character.MAX_VALUE + 1];
|
||||
public final <T> T getSingleton(Class<T> clazz) {
|
||||
IterableThreadLocal<T> cache = REGISTERED_SINGLETONS.get(clazz);
|
||||
if (cache == null) {
|
||||
synchronized (this) {
|
||||
cache = REGISTERED_SINGLETONS.get(clazz);
|
||||
if (cache == null) {
|
||||
Fawe.debug("Not registered " + clazz);
|
||||
cache = new IterableThreadLocal<>(IOUtil.supplier(clazz::newInstance));
|
||||
REGISTERED_SINGLETONS.put(clazz, cache);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
return cache.get();
|
||||
}
|
||||
|
||||
public static final IterableThreadLocal<char[]> PALETTE_TO_BLOCK_CHAR = new IterableThreadLocal<char[]>() {
|
||||
@Override
|
||||
public char[] init() {
|
||||
char[] result = new char[Character.MAX_VALUE + 1];
|
||||
Arrays.fill(result, Character.MAX_VALUE);
|
||||
return result;
|
||||
public synchronized <T> IterableThreadLocal<T> registerSingleton(Class<T> clazz, Supplier<T> cache) {
|
||||
checkNotNull(cache);
|
||||
IterableThreadLocal<T> local = new IterableThreadLocal<>(cache);
|
||||
IterableThreadLocal previous = REGISTERED_SINGLETONS.putIfAbsent(clazz, local);
|
||||
if (previous != null) {
|
||||
throw new IllegalStateException("Previous key");
|
||||
}
|
||||
};
|
||||
return local;
|
||||
}
|
||||
|
||||
public static final IterableThreadLocal<long[]> BLOCK_STATES = new IterableThreadLocal<long[]>() {
|
||||
@Override
|
||||
public long[] init() {
|
||||
return new long[2048];
|
||||
public synchronized <T> Pool<T> registerPool(Class<T> clazz, Supplier<T> cache, boolean buffer) {
|
||||
checkNotNull(cache);
|
||||
Pool<T> pool;
|
||||
if (buffer) {
|
||||
pool = new QueuePool<>(cache);
|
||||
} else {
|
||||
pool = cache::get;
|
||||
}
|
||||
};
|
||||
Pool previous = REGISTERED_POOLS.putIfAbsent(clazz, pool);
|
||||
if (previous != null) {
|
||||
throw new IllegalStateException("Previous key");
|
||||
}
|
||||
return pool;
|
||||
}
|
||||
|
||||
public static final IterableThreadLocal<int[]> SECTION_BLOCKS = new IterableThreadLocal<int[]>() {
|
||||
@Override
|
||||
public int[] init() {
|
||||
return new int[4096];
|
||||
public final IterableThreadLocal<int[]> BLOCK_TO_PALETTE = new IterableThreadLocal<>(() -> {
|
||||
int[] result = new int[BlockTypes.states.length];
|
||||
Arrays.fill(result, Integer.MAX_VALUE);
|
||||
return result;
|
||||
});
|
||||
|
||||
public final IterableThreadLocal<char[]> SECTION_BITS_TO_CHAR = new IterableThreadLocal<>(() -> new char[4096]);
|
||||
|
||||
public final IterableThreadLocal<int[]> PALETTE_TO_BLOCK = new IterableThreadLocal<>(() -> new int[Character.MAX_VALUE + 1]);
|
||||
|
||||
public final IterableThreadLocal<char[]> PALETTE_TO_BLOCK_CHAR = new IterableThreadLocal<>(
|
||||
() -> new char[Character.MAX_VALUE + 1], a -> {
|
||||
Arrays.fill(a, Character.MAX_VALUE);
|
||||
}
|
||||
};
|
||||
);
|
||||
|
||||
public final IterableThreadLocal<long[]> BLOCK_STATES = new IterableThreadLocal<>(() -> new long[2048]);
|
||||
|
||||
public final IterableThreadLocal<int[]> SECTION_BLOCKS = new IterableThreadLocal<>(() -> new int[4096]);
|
||||
|
||||
public final IterableThreadLocal<int[]> INDEX_STORE = new IterableThreadLocal<>(() -> new int[256]);
|
||||
|
||||
/**
|
||||
* Holds data for a palette used in a chunk section
|
||||
*/
|
||||
public static final class Palette {
|
||||
public final class Palette {
|
||||
public int paletteToBlockLength;
|
||||
/**
|
||||
* Reusable buffer array, MUST check paletteToBlockLength for actual length
|
||||
@ -128,12 +219,7 @@ public final class FaweCache implements Trimable {
|
||||
public long[] blockStates;
|
||||
}
|
||||
|
||||
private static final IterableThreadLocal<Palette> PALETTE_CACHE = new IterableThreadLocal<Palette>() {
|
||||
@Override
|
||||
public Palette init() {
|
||||
return new Palette();
|
||||
}
|
||||
};
|
||||
private final IterableThreadLocal<Palette> PALETTE_CACHE = new IterableThreadLocal<>(Palette::new);
|
||||
|
||||
/**
|
||||
* Convert raw char array to palette
|
||||
@ -141,7 +227,7 @@ public final class FaweCache implements Trimable {
|
||||
* @param blocks
|
||||
* @return palette
|
||||
*/
|
||||
public static Palette toPalette(int layerOffset, char[] blocks) {
|
||||
public Palette toPalette(int layerOffset, char[] blocks) {
|
||||
return toPalette(layerOffset, null, blocks);
|
||||
}
|
||||
|
||||
@ -151,11 +237,11 @@ public final class FaweCache implements Trimable {
|
||||
* @param blocks
|
||||
* @return palette
|
||||
*/
|
||||
public static Palette toPalette(int layerOffset, int[] blocks) {
|
||||
public Palette toPalette(int layerOffset, int[] blocks) {
|
||||
return toPalette(layerOffset, blocks, null);
|
||||
}
|
||||
|
||||
private static Palette toPalette(int layerOffset, int[] blocksInts, char[] blocksChars) {
|
||||
private Palette toPalette(int layerOffset, int[] blocksInts, char[] blocksChars) {
|
||||
int[] blockToPalette = BLOCK_TO_PALETTE.get();
|
||||
int[] paletteToBlock = PALETTE_TO_BLOCK.get();
|
||||
long[] blockStates = BLOCK_STATES.get();
|
||||
@ -229,14 +315,9 @@ public final class FaweCache implements Trimable {
|
||||
* Vector cache
|
||||
*/
|
||||
|
||||
public static IterableThreadLocal<MutableBlockVector3> MUTABLE_BLOCKVECTOR3 = new IterableThreadLocal<MutableBlockVector3>() {
|
||||
@Override
|
||||
public MutableBlockVector3 init() {
|
||||
return new MutableBlockVector3();
|
||||
}
|
||||
};
|
||||
public IterableThreadLocal<MutableBlockVector3> MUTABLE_BLOCKVECTOR3 = new IterableThreadLocal<>(MutableBlockVector3::new);
|
||||
|
||||
public static IterableThreadLocal<MutableVector3> MUTABLE_VECTOR3 = new IterableThreadLocal<MutableVector3>() {
|
||||
public IterableThreadLocal<MutableVector3> MUTABLE_VECTOR3 = new IterableThreadLocal<MutableVector3>(MutableVector3::new) {
|
||||
@Override
|
||||
public MutableVector3 init() {
|
||||
return new MutableVector3();
|
||||
@ -246,7 +327,7 @@ public final class FaweCache implements Trimable {
|
||||
/*
|
||||
Conversion methods between JNBT tags and raw values
|
||||
*/
|
||||
public static Map<String, Object> asMap(Object... pairs) {
|
||||
public Map<String, Object> asMap(Object... pairs) {
|
||||
HashMap<String, Object> map = new HashMap<>(pairs.length >> 1);
|
||||
for (int i = 0; i < pairs.length; i += 2) {
|
||||
String key = (String) pairs[i];
|
||||
@ -256,47 +337,47 @@ public final class FaweCache implements Trimable {
|
||||
return map;
|
||||
}
|
||||
|
||||
public static ShortTag asTag(short value) {
|
||||
public ShortTag asTag(short value) {
|
||||
return new ShortTag(value);
|
||||
}
|
||||
|
||||
public static IntTag asTag(int value) {
|
||||
public IntTag asTag(int value) {
|
||||
return new IntTag(value);
|
||||
}
|
||||
|
||||
public static DoubleTag asTag(double value) {
|
||||
public DoubleTag asTag(double value) {
|
||||
return new DoubleTag(value);
|
||||
}
|
||||
|
||||
public static ByteTag asTag(byte value) {
|
||||
public ByteTag asTag(byte value) {
|
||||
return new ByteTag(value);
|
||||
}
|
||||
|
||||
public static FloatTag asTag(float value) {
|
||||
public FloatTag asTag(float value) {
|
||||
return new FloatTag(value);
|
||||
}
|
||||
|
||||
public static LongTag asTag(long value) {
|
||||
public LongTag asTag(long value) {
|
||||
return new LongTag(value);
|
||||
}
|
||||
|
||||
public static ByteArrayTag asTag(byte[] value) {
|
||||
public ByteArrayTag asTag(byte[] value) {
|
||||
return new ByteArrayTag(value);
|
||||
}
|
||||
|
||||
public static IntArrayTag asTag(int[] value) {
|
||||
public IntArrayTag asTag(int[] value) {
|
||||
return new IntArrayTag(value);
|
||||
}
|
||||
|
||||
public static LongArrayTag asTag(long[] value) {
|
||||
public LongArrayTag asTag(long[] value) {
|
||||
return new LongArrayTag(value);
|
||||
}
|
||||
|
||||
public static StringTag asTag(String value) {
|
||||
public StringTag asTag(String value) {
|
||||
return new StringTag(value);
|
||||
}
|
||||
|
||||
public static CompoundTag asTag(Map<String, Object> value) {
|
||||
public CompoundTag asTag(Map<String, Object> value) {
|
||||
HashMap<String, Tag> map = new HashMap<>();
|
||||
for (Map.Entry<String, Object> entry : value.entrySet()) {
|
||||
Object child = entry.getValue();
|
||||
@ -306,7 +387,7 @@ public final class FaweCache implements Trimable {
|
||||
return new CompoundTag(map);
|
||||
}
|
||||
|
||||
public static Tag asTag(Object value) {
|
||||
public Tag asTag(Object value) {
|
||||
if (value instanceof Integer) {
|
||||
return asTag((int) value);
|
||||
} else if (value instanceof Short) {
|
||||
@ -359,7 +440,7 @@ public final class FaweCache implements Trimable {
|
||||
}
|
||||
}
|
||||
|
||||
public static ListTag asTag(Object... values) {
|
||||
public ListTag asTag(Object... values) {
|
||||
Class<? extends Tag> clazz = null;
|
||||
List<Tag> list = new ArrayList<>(values.length);
|
||||
for (Object value : values) {
|
||||
@ -373,7 +454,7 @@ public final class FaweCache implements Trimable {
|
||||
return new ListTag(clazz, list);
|
||||
}
|
||||
|
||||
public static ListTag asTag(Collection values) {
|
||||
public ListTag asTag(Collection values) {
|
||||
Class<? extends Tag> clazz = null;
|
||||
List<Tag> list = new ArrayList<>(values.size());
|
||||
for (Object value : values) {
|
||||
@ -390,7 +471,7 @@ public final class FaweCache implements Trimable {
|
||||
/*
|
||||
Thread stuff
|
||||
*/
|
||||
public static ThreadPoolExecutor newBlockingExecutor() {
|
||||
public ThreadPoolExecutor newBlockingExecutor() {
|
||||
int nThreads = Settings.IMP.QUEUE.PARALLEL_THREADS;
|
||||
ArrayBlockingQueue<Runnable> queue = new ArrayBlockingQueue<>(nThreads);
|
||||
return new ThreadPoolExecutor(nThreads, nThreads,
|
||||
|
@ -106,6 +106,8 @@ public interface IChunk<T extends Future<T>> extends Trimable, Callable<T>, IChu
|
||||
/* set - queues a change */
|
||||
boolean setBiome(int x, int y, int z, BiomeType biome);
|
||||
|
||||
boolean setTile(int x, int y, int z, CompoundTag tag);
|
||||
|
||||
boolean setBlock(int x, int y, int z, BlockStateHolder block);
|
||||
|
||||
@Override
|
||||
@ -126,7 +128,7 @@ public interface IChunk<T extends Future<T>> extends Trimable, Callable<T>, IChu
|
||||
*/
|
||||
@Override
|
||||
default IBlocks reset() {
|
||||
init(getQueue(), getX(), getZ());
|
||||
init(null, getX(), getZ());
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,8 @@ import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
/**
|
||||
* An interface for getting blocks.
|
||||
*/
|
||||
@ -28,4 +30,8 @@ public interface IChunkGet extends IBlocks, Trimable, InputExtent {
|
||||
default void optimize() {
|
||||
|
||||
}
|
||||
|
||||
<T extends Future<T>> T call(IChunkSet set, Runnable finalize);
|
||||
|
||||
char[] load(int layer);
|
||||
}
|
||||
|
@ -28,6 +28,10 @@ public interface IDelegateChunk<U extends IChunk> extends IChunk {
|
||||
return root;
|
||||
}
|
||||
|
||||
@Override
|
||||
default <T extends Future<T>> T call(IChunkSet set, Runnable finalize) {
|
||||
return getParent().call(set, finalize);
|
||||
}
|
||||
|
||||
@Override
|
||||
default IQueueExtent getQueue() {
|
||||
@ -49,6 +53,11 @@ public interface IDelegateChunk<U extends IChunk> extends IChunk {
|
||||
getParent().flood(flood, mask, block);
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean setTile(int x, int y, int z, CompoundTag tag) {
|
||||
return getParent().setTile(x, y, z, tag);
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean setBiome(int x, int y, int z, BiomeType biome) {
|
||||
return getParent().setBiome(x, y, z, biome);
|
||||
@ -74,6 +83,11 @@ public interface IDelegateChunk<U extends IChunk> extends IChunk {
|
||||
return getParent().getFullBlock(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
default char[] load(int layer) {
|
||||
return getParent().load(layer);
|
||||
}
|
||||
|
||||
@Override
|
||||
default void init(IQueueExtent extent, int chunkX, int chunkZ) {
|
||||
getParent().init(extent, chunkX, chunkZ);
|
||||
|
@ -1,6 +1,35 @@
|
||||
package com.boydti.fawe.beta;
|
||||
|
||||
import com.boydti.fawe.beta.implementation.WorldChunkCache;
|
||||
import com.boydti.fawe.beta.implementation.IChunkCache;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.MaxChangedBlocksException;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.entity.BaseEntity;
|
||||
import com.sk89q.worldedit.entity.Entity;
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard;
|
||||
import com.sk89q.worldedit.function.generator.GenBase;
|
||||
import com.sk89q.worldedit.function.generator.Resource;
|
||||
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.regions.Region;
|
||||
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;
|
||||
import com.sk89q.worldedit.world.block.BlockType;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
/**
|
||||
@ -11,8 +40,43 @@ public interface IDelegateQueueExtent extends IQueueExtent {
|
||||
IQueueExtent getParent();
|
||||
|
||||
@Override
|
||||
default void init(WorldChunkCache cache) {
|
||||
getParent().init(cache);
|
||||
default boolean isQueueEnabled() {
|
||||
return getParent().isQueueEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
default void clearBlockUpdates(Player... players) {
|
||||
getParent().clearBlockUpdates(players);
|
||||
}
|
||||
|
||||
@Override
|
||||
default void sendBlockUpdates(Player... players) {
|
||||
getParent().sendBlockUpdates(players);
|
||||
}
|
||||
|
||||
@Override
|
||||
default void enableQueue() {
|
||||
getParent().enableQueue();
|
||||
}
|
||||
|
||||
@Override
|
||||
default void disableQueue() {
|
||||
getParent().disableQueue();
|
||||
}
|
||||
|
||||
@Override
|
||||
default void init(Extent extent, IChunkCache<IChunkGet> get, IChunkCache<IChunkSet> set) {
|
||||
getParent().init(extent, get, set);
|
||||
}
|
||||
|
||||
@Override
|
||||
default IChunkGet getCachedGet(int x, int z) {
|
||||
return getParent().getCachedGet(x, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
default IChunkSet getCachedSet(int x, int z) {
|
||||
return getParent().getCachedSet(x, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -21,10 +85,50 @@ public interface IDelegateQueueExtent extends IQueueExtent {
|
||||
}
|
||||
|
||||
@Override
|
||||
default Future<?> submit(IChunk chunk) {
|
||||
default <T extends Future<T>> T submit(IChunk<T> chunk) {
|
||||
return getParent().submit(chunk);
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean setBlock(int x, int y, int z, BlockStateHolder state) {
|
||||
return getParent().setBlock(x, y, z, state);
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean setTile(int x, int y, int z, CompoundTag tile) throws WorldEditException {
|
||||
return getParent().setTile(x, y, z, tile);
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean setBiome(int x, int y, int z, BiomeType biome) {
|
||||
return getParent().setBiome(x, y, z, biome);
|
||||
}
|
||||
|
||||
@Override
|
||||
default BlockState getBlock(int x, int y, int z) {
|
||||
return getParent().getBlock(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
default BaseBlock getFullBlock(int x, int y, int z) {
|
||||
return getParent().getFullBlock(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
default BiomeType getBiome(int x, int z) {
|
||||
return getParent().getBiome(x, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
default BlockVector3 getMinimumPoint() {
|
||||
return getParent().getMinimumPoint();
|
||||
}
|
||||
|
||||
@Override
|
||||
default BlockVector3 getMaximumPoint() {
|
||||
return getParent().getMaximumPoint();
|
||||
}
|
||||
|
||||
@Override
|
||||
default IChunk create(boolean isFull) {
|
||||
return getParent().create(isFull);
|
||||
@ -40,8 +144,247 @@ public interface IDelegateQueueExtent extends IQueueExtent {
|
||||
getParent().flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
default ChunkFilterBlock initFilterBlock() {
|
||||
return getParent().initFilterBlock();
|
||||
}
|
||||
|
||||
@Override
|
||||
default int size() {
|
||||
return getParent().size();
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean isEmpty() {
|
||||
return getParent().isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
default void sendChunk(int chunkX, int chunkZ, int bitMask) {
|
||||
getParent().sendChunk(chunkX, chunkZ, bitMask);
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean trim(boolean aggressive) {
|
||||
return getParent().trim(aggressive);
|
||||
}
|
||||
|
||||
@Override
|
||||
default void recycle() {
|
||||
getParent().recycle();
|
||||
}
|
||||
|
||||
@Override
|
||||
default List<? extends Entity> getEntities(Region region) {
|
||||
return getParent().getEntities(region);
|
||||
}
|
||||
|
||||
@Override
|
||||
default List<? extends Entity> getEntities() {
|
||||
return getParent().getEntities();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
default Entity createEntity(Location location, BaseEntity entity) {
|
||||
return getParent().createEntity(location, entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
default void removeEntity(int x, int y, int z, UUID uuid) {
|
||||
getParent().removeEntity(x, y, z, uuid);
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean isWorld() {
|
||||
return getParent().isWorld();
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean regenerateChunk(int x, int z, @Nullable BiomeType type, @Nullable Long seed) {
|
||||
return getParent().regenerateChunk(x, z, type, seed);
|
||||
}
|
||||
|
||||
@Override
|
||||
default int getHighestTerrainBlock(int x, int z, int minY, int maxY) {
|
||||
return getParent().getHighestTerrainBlock(x, z, minY, maxY);
|
||||
}
|
||||
|
||||
@Override
|
||||
default int getHighestTerrainBlock(int x, int z, int minY, int maxY, Mask filter) {
|
||||
return getParent().getHighestTerrainBlock(x, z, minY, maxY, filter);
|
||||
}
|
||||
|
||||
@Override
|
||||
default int getNearestSurfaceLayer(int x, int z, int y, int minY, int maxY) {
|
||||
return getParent().getNearestSurfaceLayer(x, z, y, minY, maxY);
|
||||
}
|
||||
|
||||
@Override
|
||||
default int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, boolean ignoreAir) {
|
||||
return getParent().getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, ignoreAir);
|
||||
}
|
||||
|
||||
@Override
|
||||
default int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY) {
|
||||
return getParent().getNearestSurfaceTerrainBlock(x, z, y, minY, maxY);
|
||||
}
|
||||
|
||||
@Override
|
||||
default int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax) {
|
||||
return getParent().getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax);
|
||||
}
|
||||
|
||||
@Override
|
||||
default int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax, Mask mask) {
|
||||
return getParent().getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax, mask);
|
||||
}
|
||||
|
||||
@Override
|
||||
default int getNearestSurfaceTerrainBlock(int x, int z, int y, int minY, int maxY, int failedMin, int failedMax, boolean ignoreAir) {
|
||||
return getParent().getNearestSurfaceTerrainBlock(x, z, y, minY, maxY, failedMin, failedMax, ignoreAir);
|
||||
}
|
||||
|
||||
@Override
|
||||
default void addCaves(Region region) throws WorldEditException {
|
||||
getParent().addCaves(region);
|
||||
}
|
||||
|
||||
@Override
|
||||
default void generate(Region region, GenBase gen) throws WorldEditException {
|
||||
getParent().generate(region, gen);
|
||||
}
|
||||
|
||||
@Override
|
||||
default void addSchems(Region region, Mask mask, List<ClipboardHolder> clipboards, int rarity, boolean rotate) throws WorldEditException {
|
||||
getParent().addSchems(region, mask, clipboards, rarity, rotate);
|
||||
}
|
||||
|
||||
@Override
|
||||
default void spawnResource(Region region, Resource gen, int rarity, int frequency) throws WorldEditException {
|
||||
getParent().spawnResource(region, gen, rarity, frequency);
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean contains(BlockVector3 pt) {
|
||||
return getParent().contains(pt);
|
||||
}
|
||||
|
||||
@Override
|
||||
default void addOre(Region region, Mask mask, Pattern material, int size, int frequency, int rarity, int minY, int maxY) throws WorldEditException {
|
||||
getParent().addOre(region, mask, material, size, frequency, rarity, minY, maxY);
|
||||
}
|
||||
|
||||
@Override
|
||||
default void addOres(Region region, Mask mask) throws WorldEditException {
|
||||
getParent().addOres(region, mask);
|
||||
}
|
||||
|
||||
@Override
|
||||
default List<Countable<BlockType>> getBlockDistribution(Region region) {
|
||||
return getParent().getBlockDistribution(region);
|
||||
}
|
||||
|
||||
@Override
|
||||
default List<Countable<BlockState>> getBlockDistributionWithData(Region region) {
|
||||
return getParent().getBlockDistributionWithData(region);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
default Operation commit() {
|
||||
return getParent().commit();
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean cancel() {
|
||||
return getParent().cancel();
|
||||
}
|
||||
|
||||
@Override
|
||||
default int getMaxY() {
|
||||
return getParent().getMaxY();
|
||||
}
|
||||
|
||||
@Override
|
||||
default BlockArrayClipboard lazyCopy(Region region) {
|
||||
return getParent().lazyCopy(region);
|
||||
}
|
||||
|
||||
@Override
|
||||
default int countBlocks(Region region, Set<BaseBlock> searchBlocks) {
|
||||
return getParent().countBlocks(region, searchBlocks);
|
||||
}
|
||||
|
||||
@Override
|
||||
default int countBlocks(Region region, Mask searchMask) {
|
||||
return getParent().countBlocks(region, searchMask);
|
||||
}
|
||||
|
||||
@Override
|
||||
default <B extends BlockStateHolder<B>> int setBlocks(Region region, B block) throws MaxChangedBlocksException {
|
||||
return getParent().setBlocks(region, block);
|
||||
}
|
||||
|
||||
@Override
|
||||
default int setBlocks(Region region, Pattern pattern) throws MaxChangedBlocksException {
|
||||
return getParent().setBlocks(region, pattern);
|
||||
}
|
||||
|
||||
@Override
|
||||
default <B extends BlockStateHolder<B>> int replaceBlocks(Region region, Set<BaseBlock> filter, B replacement) throws MaxChangedBlocksException {
|
||||
return getParent().replaceBlocks(region, filter, replacement);
|
||||
}
|
||||
|
||||
@Override
|
||||
default int replaceBlocks(Region region, Set<BaseBlock> filter, Pattern pattern) throws MaxChangedBlocksException {
|
||||
return getParent().replaceBlocks(region, filter, pattern);
|
||||
}
|
||||
|
||||
@Override
|
||||
default int replaceBlocks(Region region, Mask mask, Pattern pattern) throws MaxChangedBlocksException {
|
||||
return getParent().replaceBlocks(region, mask, pattern);
|
||||
}
|
||||
|
||||
@Override
|
||||
default int center(Region region, Pattern pattern) throws MaxChangedBlocksException {
|
||||
return getParent().center(region, pattern);
|
||||
}
|
||||
|
||||
@Override
|
||||
default int setBlocks(Set<BlockVector3> vset, Pattern pattern) {
|
||||
return getParent().setBlocks(vset, pattern);
|
||||
}
|
||||
|
||||
@Override
|
||||
default BlockState getBlock(BlockVector3 position) {
|
||||
return getParent().getBlock(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
default BaseBlock getFullBlock(BlockVector3 position) {
|
||||
return getParent().getFullBlock(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
default BiomeType getBiome(BlockVector2 position) {
|
||||
return getParent().getBiome(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
default BiomeType getBiomeType(int x, int z) {
|
||||
return getParent().getBiomeType(x, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
default <T extends BlockStateHolder<T>> boolean setBlock(BlockVector3 position, T block) throws WorldEditException {
|
||||
return getParent().setBlock(position, block);
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean setBiome(BlockVector2 position, BiomeType biome) {
|
||||
return getParent().setBiome(position, biome);
|
||||
}
|
||||
}
|
||||
|
@ -1,24 +1,24 @@
|
||||
package com.boydti.fawe.beta;
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.beta.implementation.WorldChunkCache;
|
||||
import com.boydti.fawe.beta.implementation.IChunkCache;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.WorldEditException;
|
||||
import com.sk89q.worldedit.entity.Player;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.math.BlockVector3;
|
||||
import com.sk89q.worldedit.registry.Keyed;
|
||||
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;
|
||||
import java.io.Flushable;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* TODO: implement Extent (need to refactor Extent first) Interface for a queue based extent which
|
||||
* uses chunks
|
||||
*/
|
||||
public interface IQueueExtent extends Flushable, Trimable, Extent, Keyed {
|
||||
public interface IQueueExtent extends Flushable, Trimable, Extent {
|
||||
|
||||
@Override
|
||||
default boolean isQueueEnabled() {
|
||||
@ -54,7 +54,7 @@ public interface IQueueExtent extends Flushable, Trimable, Extent, Keyed {
|
||||
void disableQueue();
|
||||
|
||||
|
||||
void init(WorldChunkCache world); // TODO NOT IMPLEMENTED replace with supplier
|
||||
void init(Extent extent, IChunkCache<IChunkGet> get, IChunkCache<IChunkSet> set);
|
||||
|
||||
/**
|
||||
* Get the cached get object
|
||||
@ -64,7 +64,7 @@ public interface IQueueExtent extends Flushable, Trimable, Extent, Keyed {
|
||||
* @param supplier
|
||||
* @return
|
||||
*/
|
||||
IChunkGet getCachedGet(int x, int z, Supplier<IChunkGet> supplier);
|
||||
IChunkGet getCachedGet(int x, int z);
|
||||
|
||||
/**
|
||||
* Get the cached chunk set object
|
||||
@ -73,7 +73,7 @@ public interface IQueueExtent extends Flushable, Trimable, Extent, Keyed {
|
||||
* @param supplier
|
||||
* @return
|
||||
*/
|
||||
IChunkSet getCachedSet(int x, int z, Supplier<IChunkSet> supplier);
|
||||
IChunkSet getCachedSet(int x, int z);
|
||||
|
||||
/**
|
||||
* Get the IChunk at a position (and cache it if it's not already)
|
||||
@ -100,6 +100,12 @@ public interface IQueueExtent extends Flushable, Trimable, Extent, Keyed {
|
||||
return chunk.setBlock(x & 15, y, z & 15, state);
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean setTile(int x, int y, int z, CompoundTag tile) throws WorldEditException {
|
||||
final IChunk chunk = getCachedChunk(x >> 4, z >> 4);
|
||||
return chunk.setTile(x & 15, y, z & 15, tile);
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean setBiome(int x, int y, int z, BiomeType biome) {
|
||||
final IChunk chunk = getCachedChunk(x >> 4, z >> 4);
|
||||
@ -130,7 +136,7 @@ public interface IQueueExtent extends Flushable, Trimable, Extent, Keyed {
|
||||
|
||||
@Override
|
||||
default BlockVector3 getMaximumPoint() {
|
||||
return BlockVector3.at(30000000, FaweCache.WORLD_MAX_Y, 30000000);
|
||||
return BlockVector3.at(30000000, FaweCache.IMP.WORLD_MAX_Y, 30000000);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -14,4 +14,6 @@ public interface Trimable {
|
||||
* @return if this object is empty at the end of the trim, and can therefore be deleted
|
||||
*/
|
||||
boolean trim(boolean aggressive);
|
||||
|
||||
default void recycle() {}
|
||||
}
|
||||
|
@ -2,33 +2,22 @@ package com.boydti.fawe.beta.implementation;
|
||||
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.beta.Trimable;
|
||||
import com.boydti.fawe.util.MathMan;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectIterator;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* IGetBlocks may be cached by the WorldChunkCache so that it can be used between multiple
|
||||
* IQueueExtents - avoids conversion between palette and raw data on every block get
|
||||
*/
|
||||
public class WorldChunkCache implements Trimable {
|
||||
public class ChunkCache<T extends Trimable> implements IChunkCache<T> {
|
||||
|
||||
protected final Long2ObjectLinkedOpenHashMap<WeakReference<IChunkGet>> getCache;
|
||||
private final World world;
|
||||
protected final Long2ObjectLinkedOpenHashMap<WeakReference<T>> getCache;
|
||||
private final IChunkCache<T> delegate;
|
||||
|
||||
protected WorldChunkCache(World world) {
|
||||
this.world = world;
|
||||
protected ChunkCache(IChunkCache<T> delegate) {
|
||||
this.getCache = new Long2ObjectLinkedOpenHashMap<>();
|
||||
}
|
||||
|
||||
public World getWorld() {
|
||||
return world;
|
||||
}
|
||||
|
||||
public synchronized int size() {
|
||||
return getCache.size();
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -38,38 +27,47 @@ public class WorldChunkCache implements Trimable {
|
||||
* @param provider used to create if it isn't already cached
|
||||
* @return cached IGetBlocks
|
||||
*/
|
||||
public synchronized IChunkGet get(long index, Supplier<IChunkGet> provider) {
|
||||
final WeakReference<IChunkGet> ref = getCache.get(index);
|
||||
@Override
|
||||
public synchronized T get(int x, int z) {
|
||||
long pair = MathMan.pairInt(x, z);
|
||||
final WeakReference<T> ref = getCache.get(pair);
|
||||
if (ref != null) {
|
||||
final IChunkGet blocks = ref.get();
|
||||
final T blocks = ref.get();
|
||||
if (blocks != null) {
|
||||
return blocks;
|
||||
}
|
||||
}
|
||||
final IChunkGet blocks = provider.get();
|
||||
getCache.put(index, new WeakReference<>(blocks));
|
||||
final T blocks = newChunk(x, z);
|
||||
getCache.put(pair, new WeakReference<>(blocks));
|
||||
return blocks;
|
||||
}
|
||||
|
||||
public T newChunk(int chunkX, int chunkZ) {
|
||||
return delegate.get(chunkX, chunkZ);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean trim(boolean aggressive) {
|
||||
if (getCache.size() == 0) {
|
||||
return true;
|
||||
}
|
||||
boolean result = true;
|
||||
if (!getCache.isEmpty()) {
|
||||
final ObjectIterator<Long2ObjectMap.Entry<WeakReference<IChunkGet>>> iter = getCache
|
||||
.long2ObjectEntrySet().fastIterator();
|
||||
final ObjectIterator<Long2ObjectMap.Entry<WeakReference<T>>> iter = getCache
|
||||
.long2ObjectEntrySet().fastIterator();
|
||||
while (iter.hasNext()) {
|
||||
final Long2ObjectMap.Entry<WeakReference<IChunkGet>> entry = iter.next();
|
||||
final WeakReference<IChunkGet> value = entry.getValue();
|
||||
final IChunkGet igb = value.get();
|
||||
final Long2ObjectMap.Entry<WeakReference<T>> entry = iter.next();
|
||||
final WeakReference<T> value = entry.getValue();
|
||||
final T igb = value.get();
|
||||
if (igb == null) {
|
||||
iter.remove();
|
||||
} else {
|
||||
result = false;
|
||||
if (!aggressive) {
|
||||
return result;
|
||||
return false;
|
||||
}
|
||||
synchronized (igb) {
|
||||
igb.trim(aggressive);
|
||||
igb.trim(true);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,135 @@
|
||||
package com.boydti.fawe.beta.implementation;
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.beta.IBlocks;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.beta.IChunkSet;
|
||||
import com.boydti.fawe.util.MathMan;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.entity.BaseEntity;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
public class FallbackChunkGet implements IChunkGet {
|
||||
private final int bx, bz;
|
||||
private final Extent extent;
|
||||
|
||||
public FallbackChunkGet(Extent extent, int chunkX, int chunkZ) {
|
||||
this.extent = extent;
|
||||
this.bx = chunkX << 4;
|
||||
this.bz = chunkZ << 4;
|
||||
}
|
||||
@Override
|
||||
public BaseBlock getFullBlock(int x, int y, int z) {
|
||||
return extent.getFullBlock(bx + x, y, bz + z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeType getBiomeType(int x, int z) {
|
||||
return extent.getBiomeType(bx + x, bz + z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState getBlock(int x, int y, int z) {
|
||||
return extent.getBlock(bx + x, y, bz + z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag getTag(int x, int y, int z) {
|
||||
return extent.getFullBlock(bx + x, y, bz + z).getNbtData();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean trim(boolean aggressive) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Future<T>> T call(IChunkSet set, Runnable finalize) {
|
||||
for (int layer = 0; layer < 16; layer++) {
|
||||
if (set.hasSection(layer)) {
|
||||
char[] arr = set.getArray(layer);
|
||||
int by = layer << 4;
|
||||
for (int y = 0, i = 0; y < 16; y++) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
for (int x = 0; x < 16; x++, i++) {
|
||||
char ordinal = arr[i];
|
||||
if (ordinal != 0) {
|
||||
BlockState block = BlockState.getFromOrdinal(ordinal);
|
||||
extent.setBlock(bx + x, by + y, bz + z, block);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
Map<Short, CompoundTag> tiles = set.getTiles();
|
||||
if (!tiles.isEmpty()) {
|
||||
for (Map.Entry<Short, CompoundTag> entry : tiles.entrySet()) {
|
||||
short blockHash = entry.getKey();
|
||||
final int x = (blockHash >> 12 & 0xF) + bx;
|
||||
final int y = (blockHash & 0xFF);
|
||||
final int z = (blockHash >> 8 & 0xF) + bz;
|
||||
extent.setTile(bx + x, y, bz + z, entry.getValue());
|
||||
}
|
||||
|
||||
}
|
||||
Set<CompoundTag> spawns = set.getEntities();
|
||||
if (!spawns.isEmpty()) {
|
||||
for (CompoundTag spawn : spawns) {
|
||||
BaseEntity ent = new BaseEntity(spawn);
|
||||
extent.createEntity(ent.getLocation(extent), ent);
|
||||
}
|
||||
}
|
||||
Set<UUID> kills = set.getEntityRemoves();
|
||||
if (!kills.isEmpty()) {
|
||||
for (UUID kill : kills) {
|
||||
extent.removeEntity(0, 0, 0, kill);
|
||||
}
|
||||
}
|
||||
BiomeType[] biomes = set.getBiomes();
|
||||
if (biomes != null) {
|
||||
for (int z = 0, i = 0; z < 16; z++) {
|
||||
for (int x = 0; x < 16; x++, i++) {
|
||||
BiomeType biome = biomes[i];
|
||||
if (biome != null) {
|
||||
extent.setBiome(bx + x, 0, bz + z, biome);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char[] load(int layer) {
|
||||
char[] arr = FaweCache.IMP.SECTION_BITS_TO_CHAR.get();
|
||||
int by = layer << 4;
|
||||
for (int y = 0, i = 0; y < 16; y++) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
for (int x = 0; x < 16; x++, i++) {
|
||||
arr[i] = getBlock(bx + x, by + y, bz + z).getOrdinalChar();
|
||||
}
|
||||
}
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSection(int layer) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBlocks reset() {
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package com.boydti.fawe.beta.implementation;
|
||||
|
||||
import com.boydti.fawe.beta.Trimable;
|
||||
|
||||
/**
|
||||
* IGetBlocks may be cached by the WorldChunkCache so that it can be used between multiple
|
||||
* IQueueExtents - avoids conversion between palette and raw data on every block get
|
||||
*/
|
||||
public interface IChunkCache<T> extends Trimable {
|
||||
T get(int chunkX, int chunkZ);
|
||||
|
||||
@Override
|
||||
default boolean trim(boolean aggressive) {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
package com.boydti.fawe.beta.implementation;
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.beta.IBlocks;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.beta.IChunkSet;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.biome.BiomeTypes;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
public enum NullChunkGet implements IChunkGet {
|
||||
INSTANCE
|
||||
;
|
||||
@Override
|
||||
public BaseBlock getFullBlock(int x, int y, int z) {
|
||||
return BlockTypes.AIR.getDefaultState().toBaseBlock();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BiomeType getBiomeType(int x, int z) {
|
||||
return BiomeTypes.FOREST;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState getBlock(int x, int y, int z) {
|
||||
return BlockTypes.AIR.getDefaultState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag getTag(int x, int y, int z) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean trim(boolean aggressive) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends Future<T>> T call(IChunkSet set, Runnable finalize) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char[] load(int layer) {
|
||||
return FaweCache.IMP.EMPTY_CHAR_4096;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSection(int layer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBlocks reset() {
|
||||
return null;
|
||||
}
|
||||
}
|
@ -3,6 +3,8 @@ package com.boydti.fawe.beta.implementation;
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.beta.IChunk;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.beta.IChunkSet;
|
||||
import com.boydti.fawe.beta.IQueueExtent;
|
||||
import com.boydti.fawe.beta.Trimable;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
@ -11,6 +13,7 @@ import com.boydti.fawe.util.MemUtil;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
import com.boydti.fawe.wrappers.WorldWrapper;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.world.World;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.HashMap;
|
||||
@ -33,16 +36,11 @@ public abstract class QueueHandler implements Trimable, Runnable {
|
||||
|
||||
private ForkJoinPool forkJoinPoolPrimary = new ForkJoinPool();
|
||||
private ForkJoinPool forkJoinPoolSecondary = new ForkJoinPool();
|
||||
private ThreadPoolExecutor blockingExecutor = FaweCache.newBlockingExecutor();
|
||||
private ThreadPoolExecutor blockingExecutor = FaweCache.IMP.newBlockingExecutor();
|
||||
private ConcurrentLinkedQueue<FutureTask> syncTasks = new ConcurrentLinkedQueue<>();
|
||||
|
||||
private Map<World, WeakReference<WorldChunkCache>> chunkCache = new HashMap<>();
|
||||
private IterableThreadLocal<IQueueExtent> queuePool = new IterableThreadLocal<IQueueExtent>() {
|
||||
@Override
|
||||
public IQueueExtent init() {
|
||||
return create();
|
||||
}
|
||||
};
|
||||
private Map<World, WeakReference<IChunkCache<IChunkGet>>> chunkCache = new HashMap<>();
|
||||
private IterableThreadLocal<IQueueExtent> queuePool = new IterableThreadLocal<>(QueueHandler.this::create);
|
||||
/**
|
||||
* Used to calculate elapsed time in milliseconds and ensure block placement doesn't lag the
|
||||
* server
|
||||
@ -50,6 +48,7 @@ public abstract class QueueHandler implements Trimable, Runnable {
|
||||
private long last;
|
||||
private long allocate = 50;
|
||||
private double targetTPS = 18;
|
||||
|
||||
public QueueHandler() {
|
||||
TaskManager.IMP.repeat(this, 1);
|
||||
}
|
||||
@ -197,18 +196,18 @@ public abstract class QueueHandler implements Trimable, Runnable {
|
||||
* @param world
|
||||
* @return
|
||||
*/
|
||||
public WorldChunkCache getOrCreate(World world) {
|
||||
public IChunkCache<IChunkGet> getOrCreateWorldCache(World world) {
|
||||
world = WorldWrapper.unwrap(world);
|
||||
|
||||
synchronized (chunkCache) {
|
||||
final WeakReference<WorldChunkCache> ref = chunkCache.get(world);
|
||||
final WeakReference<IChunkCache<IChunkGet>> ref = chunkCache.get(world);
|
||||
if (ref != null) {
|
||||
final WorldChunkCache cached = ref.get();
|
||||
final IChunkCache<IChunkGet> cached = ref.get();
|
||||
if (cached != null) {
|
||||
return cached;
|
||||
}
|
||||
}
|
||||
final WorldChunkCache created = new WorldChunkCache(world);
|
||||
final IChunkCache<IChunkGet> created = new ChunkCache<>(world);
|
||||
chunkCache.put(world, new WeakReference<>(created));
|
||||
return created;
|
||||
}
|
||||
@ -222,7 +221,9 @@ public abstract class QueueHandler implements Trimable, Runnable {
|
||||
|
||||
public IQueueExtent getQueue(World world) {
|
||||
final IQueueExtent queue = queuePool.get();
|
||||
queue.init(getOrCreate(world));
|
||||
IChunkCache<IChunkGet> cacheGet = getOrCreateWorldCache(world);
|
||||
IChunkCache<IChunkSet> set = null; // TODO cache?
|
||||
queue.init(world, cacheGet, set);
|
||||
return queue;
|
||||
}
|
||||
|
||||
@ -230,13 +231,13 @@ public abstract class QueueHandler implements Trimable, Runnable {
|
||||
public boolean trim(boolean aggressive) {
|
||||
boolean result = true;
|
||||
synchronized (chunkCache) {
|
||||
final Iterator<Map.Entry<World, WeakReference<WorldChunkCache>>> iter = chunkCache
|
||||
final Iterator<Map.Entry<World, WeakReference<IChunkCache<IChunkGet>>>> iter = chunkCache
|
||||
.entrySet().iterator();
|
||||
while (iter.hasNext()) {
|
||||
final Map.Entry<World, WeakReference<WorldChunkCache>> entry = iter.next();
|
||||
final WeakReference<WorldChunkCache> value = entry.getValue();
|
||||
final WorldChunkCache cache = value.get();
|
||||
if (cache == null || cache.size() == 0 || cache.trim(aggressive)) {
|
||||
final Map.Entry<World, WeakReference<IChunkCache<IChunkGet>>> entry = iter.next();
|
||||
final WeakReference<IChunkCache<IChunkGet>> value = entry.getValue();
|
||||
final IChunkCache<IChunkGet> cache = value.get();
|
||||
if (cache.trim(aggressive)) {
|
||||
iter.remove();
|
||||
continue;
|
||||
}
|
||||
|
@ -1,41 +1,49 @@
|
||||
package com.boydti.fawe.beta.implementation;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.beta.IChunk;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.beta.IChunkSet;
|
||||
import com.boydti.fawe.beta.IQueueExtent;
|
||||
import com.boydti.fawe.beta.implementation.blocks.CharSetBlocks;
|
||||
import com.boydti.fawe.beta.implementation.holder.ChunkHolder;
|
||||
import com.boydti.fawe.beta.implementation.holder.ReferenceChunk;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.util.MathMan;
|
||||
import com.boydti.fawe.util.MemUtil;
|
||||
import com.google.common.util.concurrent.Futures;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Single threaded implementation for IQueueExtent (still abstract) - Does not implement creation of
|
||||
* chunks (that has to implemented by the platform e.g. Bukkit)
|
||||
* <p>
|
||||
* This queue is reusable {@link #init(WorldChunkCache)}
|
||||
* This queue is reusable {@link #init(IChunkCache)}
|
||||
*/
|
||||
public abstract class SingleThreadQueueExtent implements IQueueExtent {
|
||||
|
||||
// Pool discarded chunks for reuse (can safely be cleared by another thread)
|
||||
private static final ConcurrentLinkedQueue<IChunk> CHUNK_POOL = new ConcurrentLinkedQueue<>();
|
||||
// // Pool discarded chunks for reuse (can safely be cleared by another thread)
|
||||
// private static final ConcurrentLinkedQueue<IChunk> CHUNK_POOL = new ConcurrentLinkedQueue<>();
|
||||
// Chunks currently being queued / worked on
|
||||
private final Long2ObjectLinkedOpenHashMap<IChunk> chunks = new Long2ObjectLinkedOpenHashMap<>();
|
||||
private WorldChunkCache cache;
|
||||
|
||||
private IChunkCache<IChunkGet> cacheGet;
|
||||
private IChunkCache<IChunkSet> cacheSet;
|
||||
private boolean initialized;
|
||||
|
||||
private Thread currentThread;
|
||||
private ConcurrentLinkedQueue<Future> submissions = new ConcurrentLinkedQueue<>();
|
||||
// Last access pointers
|
||||
private IChunk lastChunk;
|
||||
private long lastPair = Long.MAX_VALUE;
|
||||
|
||||
private boolean enabledQueue = true;
|
||||
|
||||
/**
|
||||
* Safety check to ensure that the thread being used matches the one being initialized on. - Can
|
||||
* be removed later
|
||||
@ -48,23 +56,42 @@ public abstract class SingleThreadQueueExtent implements IQueueExtent {
|
||||
}
|
||||
|
||||
@Override
|
||||
public IChunkGet getCachedGet(int x, int z, Supplier<IChunkGet> supplier) {
|
||||
return cache.get(MathMan.pairInt(x, z), supplier);
|
||||
public void enableQueue() {
|
||||
enabledQueue = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disableQueue() {
|
||||
enabledQueue = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IChunkGet getCachedGet(int x, int z) {
|
||||
return cacheGet.get(x, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IChunkSet getCachedSet(int x, int z) {
|
||||
return cacheSet.get(x, z);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the queue.
|
||||
*/
|
||||
protected synchronized void reset() {
|
||||
if (!initialized) return;
|
||||
checkThread();
|
||||
cache = null;
|
||||
if (!chunks.isEmpty()) {
|
||||
CHUNK_POOL.addAll(chunks.values());
|
||||
for (IChunk chunk : chunks.values()) {
|
||||
chunk.recycle();
|
||||
}
|
||||
chunks.clear();
|
||||
}
|
||||
enabledQueue = true;
|
||||
lastChunk = null;
|
||||
lastPair = Long.MAX_VALUE;
|
||||
currentThread = null;
|
||||
initialized = false;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -73,17 +100,18 @@ public abstract class SingleThreadQueueExtent implements IQueueExtent {
|
||||
* @param cache
|
||||
*/
|
||||
@Override
|
||||
public synchronized void init(WorldChunkCache cache) {
|
||||
if (this.cache != null) {
|
||||
reset();
|
||||
}
|
||||
public synchronized void init(Extent extent, IChunkCache<IChunkGet> get, IChunkCache<IChunkSet> set) {
|
||||
reset();
|
||||
currentThread = Thread.currentThread();
|
||||
checkNotNull(cache);
|
||||
this.cache = cache;
|
||||
}
|
||||
|
||||
public void returnToPool(IChunk chunk) {
|
||||
CHUNK_POOL.add(chunk);
|
||||
if (get == null) {
|
||||
get = (x, z) -> { throw new UnsupportedOperationException(); };
|
||||
}
|
||||
if (set == null) {
|
||||
set = (x, z) -> CharSetBlocks.newInstance();
|
||||
}
|
||||
this.cacheGet = get;
|
||||
this.cacheSet = set;
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -116,8 +144,9 @@ public abstract class SingleThreadQueueExtent implements IQueueExtent {
|
||||
*/
|
||||
private <T extends Future<T>> T submitUnchecked(IChunk<T> chunk) {
|
||||
if (chunk.isEmpty()) {
|
||||
CHUNK_POOL.add(chunk);
|
||||
return (T) (Future) Futures.immediateFuture(null);
|
||||
chunk.recycle();
|
||||
Future result = Futures.immediateFuture(null);
|
||||
return (T) result;
|
||||
}
|
||||
|
||||
if (Fawe.isMainThread()) {
|
||||
@ -130,7 +159,8 @@ public abstract class SingleThreadQueueExtent implements IQueueExtent {
|
||||
@Override
|
||||
public synchronized boolean trim(boolean aggressive) {
|
||||
// TODO trim individial chunk sections
|
||||
CHUNK_POOL.clear();
|
||||
cacheGet.trim(aggressive);
|
||||
cacheSet.trim(aggressive);
|
||||
if (Thread.currentThread() == currentThread) {
|
||||
lastChunk = null;
|
||||
lastPair = Long.MAX_VALUE;
|
||||
@ -157,10 +187,7 @@ public abstract class SingleThreadQueueExtent implements IQueueExtent {
|
||||
* @return IChunk
|
||||
*/
|
||||
private IChunk poolOrCreate(int X, int Z) {
|
||||
IChunk next = CHUNK_POOL.poll();
|
||||
if (next == null) {
|
||||
next = create(false);
|
||||
}
|
||||
IChunk next = create(false);
|
||||
next.init(this, X, Z);
|
||||
return next;
|
||||
}
|
||||
@ -187,7 +214,7 @@ public abstract class SingleThreadQueueExtent implements IQueueExtent {
|
||||
checkThread();
|
||||
final int size = chunks.size();
|
||||
final boolean lowMem = MemUtil.isMemoryLimited();
|
||||
if (lowMem || size > Settings.IMP.QUEUE.TARGET_SIZE) {
|
||||
if (enabledQueue && (lowMem || size > Settings.IMP.QUEUE.TARGET_SIZE)) {
|
||||
chunk = chunks.removeFirst();
|
||||
final Future future = submitUnchecked(chunk);
|
||||
if (future != null && !future.isDone()) {
|
||||
@ -211,6 +238,11 @@ public abstract class SingleThreadQueueExtent implements IQueueExtent {
|
||||
return chunk;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IChunk create(boolean isFull) {
|
||||
return ChunkHolder.newInstance();
|
||||
}
|
||||
|
||||
private void pollSubmissions(int targetSize, boolean aggressive) {
|
||||
final int overflow = submissions.size() - targetSize;
|
||||
if (aggressive) {
|
||||
|
@ -63,7 +63,7 @@ public class BitSetBlocks implements IChunkSet {
|
||||
|
||||
@Override
|
||||
public char[] getArray(int layer) {
|
||||
char[] arr = FaweCache.SECTION_BITS_TO_CHAR.get();
|
||||
char[] arr = FaweCache.IMP.SECTION_BITS_TO_CHAR.get();
|
||||
MemBlockSet.IRow nullRowY = row.getRow(layer);
|
||||
if (nullRowY instanceof MemBlockSet.RowY) {
|
||||
char value = blockState.getOrdinalChar();
|
||||
|
@ -6,6 +6,8 @@ import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockTypes;
|
||||
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
public abstract class CharGetBlocks extends CharBlocks implements IChunkGet {
|
||||
|
||||
@Override
|
||||
|
@ -1,6 +1,8 @@
|
||||
package com.boydti.fawe.beta.implementation.blocks;
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.beta.IChunkSet;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.boydti.fawe.util.MathMan;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
@ -14,21 +16,21 @@ import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
public class CharSetBlocks extends CharBlocks implements IChunkSet {
|
||||
private static FaweCache.Pool<CharSetBlocks> POOL = FaweCache.IMP.registerPool(CharSetBlocks.class, CharSetBlocks::new, Settings.IMP.QUEUE.POOL);
|
||||
public static CharSetBlocks newInstance() {
|
||||
return POOL.poll();
|
||||
}
|
||||
|
||||
public BiomeType[] biomes;
|
||||
public HashMap<Short, CompoundTag> tiles;
|
||||
public HashSet<CompoundTag> entities;
|
||||
public HashSet<UUID> entityRemoves;
|
||||
|
||||
public CharSetBlocks(CharBlocks other) {
|
||||
super(other);
|
||||
if (other instanceof CharSetBlocks) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public CharSetBlocks() {
|
||||
private CharSetBlocks() {}
|
||||
|
||||
@Override
|
||||
public void recycle() {
|
||||
POOL.offer(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.boydti.fawe.beta.implementation.holder;
|
||||
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.beta.ChunkFilterBlock;
|
||||
import com.boydti.fawe.beta.Filter;
|
||||
import com.boydti.fawe.beta.FilterBlockMask;
|
||||
@ -10,19 +11,67 @@ import com.boydti.fawe.beta.IChunkSet;
|
||||
import com.boydti.fawe.beta.IQueueExtent;
|
||||
import com.boydti.fawe.beta.implementation.SingleThreadQueueExtent;
|
||||
import com.boydti.fawe.beta.implementation.blocks.CharSetBlocks;
|
||||
import com.boydti.fawe.config.Settings;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.regions.Region;
|
||||
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;
|
||||
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.function.Supplier;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* An abstract {@link IChunk} class that implements basic get/set blocks
|
||||
*/
|
||||
public abstract class ChunkHolder implements IChunk {
|
||||
public class ChunkHolder<T extends Future<T>> implements IChunk {
|
||||
|
||||
private static FaweCache.Pool<ChunkHolder> POOL = FaweCache.IMP.registerPool(ChunkHolder.class, ChunkHolder::new, Settings.IMP.QUEUE.POOL);
|
||||
|
||||
public static ChunkHolder newInstance() {
|
||||
return POOL.poll();
|
||||
}
|
||||
|
||||
private IChunkGet get;
|
||||
private IChunkSet set;
|
||||
private IBlockDelegate delegate;
|
||||
private IQueueExtent extent;
|
||||
private int chunkX;
|
||||
private int chunkZ;
|
||||
|
||||
public ChunkHolder() {
|
||||
this.delegate = NULL;
|
||||
}
|
||||
|
||||
public void init(IBlockDelegate delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void recycle() {
|
||||
delegate = NULL;
|
||||
}
|
||||
|
||||
public IBlockDelegate getDelegate() {
|
||||
return delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IQueueExtent getQueue() {
|
||||
return extent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setTile(int x, int y, int z, CompoundTag tag) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char[] load(int layer) {
|
||||
return getOrCreateGet().load(layer);
|
||||
}
|
||||
|
||||
public static final IBlockDelegate BOTH = new IBlockDelegate() {
|
||||
@Override
|
||||
@ -160,20 +209,6 @@ public abstract class ChunkHolder implements IChunk {
|
||||
return chunk.getFullBlock(x, y, z);
|
||||
}
|
||||
};
|
||||
private IChunkGet get;
|
||||
private IChunkSet set;
|
||||
private IBlockDelegate delegate;
|
||||
private IQueueExtent extent;
|
||||
private int chunkX;
|
||||
private int chunkZ;
|
||||
|
||||
public ChunkHolder() {
|
||||
this.delegate = NULL;
|
||||
}
|
||||
|
||||
public ChunkHolder(IBlockDelegate delegate) {
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flood(Flood flood, FilterBlockMask mask, ChunkFilterBlock block) {
|
||||
@ -264,14 +299,6 @@ public abstract class ChunkHolder implements IChunk {
|
||||
return set;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the settable part of this chunk (defaults to a char array)
|
||||
* @return
|
||||
*/
|
||||
public IChunkSet createSet() {
|
||||
return new CharSetBlocks();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a wrapped set object
|
||||
* - The purpose of wrapping is to allow different extents to intercept / alter behavior
|
||||
@ -279,13 +306,7 @@ public abstract class ChunkHolder implements IChunk {
|
||||
* @return
|
||||
*/
|
||||
private IChunkSet newWrappedSet() {
|
||||
if (extent instanceof SingleThreadQueueExtent) {
|
||||
IChunkSet newSet = extent.getCachedSet(chunkX, chunkZ, this::createSet);
|
||||
if (newSet != null) {
|
||||
return newSet;
|
||||
}
|
||||
}
|
||||
return createSet();
|
||||
return extent.getCachedSet(chunkX, chunkZ);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -295,17 +316,9 @@ public abstract class ChunkHolder implements IChunk {
|
||||
* @return
|
||||
*/
|
||||
private IChunkGet newWrappedGet() {
|
||||
if (extent instanceof SingleThreadQueueExtent) {
|
||||
IChunkGet newGet = extent.getCachedGet(chunkX, chunkZ, this::get);
|
||||
if (newGet != null) {
|
||||
return newGet;
|
||||
}
|
||||
}
|
||||
return get();
|
||||
return extent.getCachedGet(chunkX, chunkZ);
|
||||
}
|
||||
|
||||
public abstract IChunkGet get();
|
||||
|
||||
@Override
|
||||
public void init(IQueueExtent extent, int chunkX, int chunkZ) {
|
||||
this.extent = extent;
|
||||
@ -320,6 +333,22 @@ public abstract class ChunkHolder implements IChunk {
|
||||
get = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized T call() {
|
||||
if (get != null && set != null) {
|
||||
return getOrCreateGet().call(getOrCreateSet(), this::recycle);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T call(IChunkSet set, Runnable finalize) {
|
||||
if (get != null && set != null) {
|
||||
return getOrCreateGet().call(set, finalize);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public IQueueExtent getExtent() {
|
||||
return extent;
|
||||
}
|
||||
|
@ -1,27 +1,29 @@
|
||||
package com.boydti.fawe.beta.implementation.holder;
|
||||
|
||||
import com.boydti.fawe.beta.IChunk;
|
||||
import com.boydti.fawe.beta.IChunkSet;
|
||||
import com.boydti.fawe.beta.IDelegateChunk;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
/**
|
||||
* Implementation of IDelegateChunk
|
||||
*
|
||||
* @param <T>
|
||||
*/
|
||||
public class DelegateChunk<T extends IChunk> implements IDelegateChunk {
|
||||
public class DelegateChunk<U extends IChunk> implements IDelegateChunk<U> {
|
||||
|
||||
private T parent;
|
||||
private U parent;
|
||||
|
||||
public DelegateChunk(T parent) {
|
||||
public DelegateChunk(U parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final T getParent() {
|
||||
public final U getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
public final void setParent(T parent) {
|
||||
public final void setParent(U parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
}
|
||||
|
@ -475,7 +475,7 @@ public class AnvilCommands {
|
||||
// });
|
||||
// if (useData) {
|
||||
// for (long[] c : map) {
|
||||
// BaseBlock block = FaweCache.CACHE_BLOCK[(int) c[0]];
|
||||
// BaseBlock block = FaweCache.IMP.CACHE_BLOCK[(int) c[0]];
|
||||
// String name = BlockType.fromID(block.getId()).getName();
|
||||
// String str = String.format("%-7s (%.3f%%) %s #%d:%d",
|
||||
// String.valueOf(c[1]),
|
||||
|
@ -293,7 +293,13 @@ public class Settings extends Config {
|
||||
" - Low values may result in FAWE waiting on requests to the main thread",
|
||||
" - Higher values use more memory and isn't noticeably faster",
|
||||
})
|
||||
public int PRELOAD_CHUNKS = 32;
|
||||
public int PRELOAD_CHUNKS = 100000;
|
||||
|
||||
@Comment({
|
||||
"If pooling is enabled (reduces GC, higher memory usage)",
|
||||
" - Enable to improve performance at the expense of memory",
|
||||
})
|
||||
public boolean POOL = true;
|
||||
|
||||
@Comment({
|
||||
"Discard edits which have been idle for a certain amount of time (ms)",
|
||||
|
@ -58,10 +58,10 @@ public class LoggingChangeSet extends AbstractDelegateChangeSet {
|
||||
// loc.x = x;
|
||||
// loc.y = y;
|
||||
// loc.z = z;
|
||||
// oldBlock.id = FaweCache.getId(combinedId4DataFrom);
|
||||
// oldBlock.data = FaweCache.getData(combinedId4DataFrom);
|
||||
// newBlock.id = FaweCache.getId(combinedId4DataTo);
|
||||
// newBlock.data = FaweCache.getData(combinedId4DataTo);
|
||||
// oldBlock.id = FaweCache.IMP.getId(combinedId4DataFrom);
|
||||
// oldBlock.data = FaweCache.IMP.getData(combinedId4DataFrom);
|
||||
// newBlock.id = FaweCache.IMP.getId(combinedId4DataTo);
|
||||
// newBlock.data = FaweCache.IMP.getData(combinedId4DataTo);
|
||||
// // Log to BlocksHub and parent
|
||||
// api.logBlock(loc, player, world, oldBlock, newBlock);
|
||||
parent.add(x, y, z, combinedId4DataFrom, combinedId4DataTo);
|
||||
|
@ -1,7 +1,12 @@
|
||||
package com.boydti.fawe.object.brush.visualization.cfi;
|
||||
|
||||
import com.boydti.fawe.Fawe;
|
||||
import com.boydti.fawe.FaweCache;
|
||||
import com.boydti.fawe.beta.IBlocks;
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.beta.IChunkSet;
|
||||
import com.boydti.fawe.beta.IQueueExtent;
|
||||
import com.boydti.fawe.beta.implementation.FallbackChunkGet;
|
||||
import com.boydti.fawe.object.FaweInputStream;
|
||||
import com.boydti.fawe.object.FaweOutputStream;
|
||||
import com.boydti.fawe.object.FawePlayer;
|
||||
@ -44,6 +49,7 @@ import com.sk89q.worldedit.session.ClipboardHolder;
|
||||
import com.sk89q.worldedit.util.Location;
|
||||
import com.sk89q.worldedit.world.biome.BiomeType;
|
||||
import com.sk89q.worldedit.world.biome.BiomeTypes;
|
||||
import com.sk89q.worldedit.world.block.BaseBlock;
|
||||
import com.sk89q.worldedit.world.block.BlockID;
|
||||
import com.sk89q.worldedit.world.block.BlockState;
|
||||
import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
@ -58,6 +64,7 @@ import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@ -65,13 +72,6 @@ import javax.annotation.Nullable;
|
||||
public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Drawable, VirtualWorld {
|
||||
private final MutableBlockVector3 mutable = new MutableBlockVector3();
|
||||
|
||||
private final ThreadLocal<int[]> indexStore = new ThreadLocal<int[]>() {
|
||||
@Override
|
||||
protected int[] initialValue() {
|
||||
return new int[256];
|
||||
}
|
||||
};
|
||||
|
||||
private final DifferentialBlockBuffer blocks;
|
||||
protected final DifferentialArray<byte[]> heights;
|
||||
protected final DifferentialArray<byte[]> biomes;
|
||||
@ -1571,7 +1571,7 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
|
||||
int[] floor = this.floor.get();
|
||||
int[] overlay = this.overlay != null ? this.overlay.get() : null;
|
||||
try {
|
||||
int[] indexes = indexStore.get();
|
||||
int[] indexes = FaweCache.IMP.INDEX_STORE.get();
|
||||
|
||||
int index;
|
||||
int maxY = 0;
|
||||
@ -1902,12 +1902,6 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
|
||||
}));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
IterableThreadLocal.clean(indexStore);
|
||||
super.finalize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxY() {
|
||||
return 255;
|
||||
@ -1973,4 +1967,10 @@ public class HeightMapMCAGenerator extends MCAWriter implements StreamChange, Dr
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IChunkGet get(int x, int z) {
|
||||
Fawe.debug("Should not be using buffering with HMMG");
|
||||
return new FallbackChunkGet(this, x, z);
|
||||
}
|
||||
}
|
||||
|
@ -79,10 +79,10 @@ public class WritableMCAChunk {
|
||||
}
|
||||
|
||||
public void write(NBTOutputStream nbtOut) throws IOException {
|
||||
int[] blockToPalette = FaweCache.BLOCK_TO_PALETTE.get();
|
||||
int[] paletteToBlock = FaweCache.PALETTE_TO_BLOCK.get();
|
||||
long[] blockstates = FaweCache.BLOCK_STATES.get();
|
||||
int[] blocksCopy = FaweCache.SECTION_BLOCKS.get();
|
||||
int[] blockToPalette = FaweCache.IMP.BLOCK_TO_PALETTE.get();
|
||||
int[] paletteToBlock = FaweCache.IMP.PALETTE_TO_BLOCK.get();
|
||||
long[] blockstates = FaweCache.IMP.BLOCK_STATES.get();
|
||||
int[] blocksCopy = FaweCache.IMP.SECTION_BLOCKS.get();
|
||||
|
||||
nbtOut.writeNamedTagName("", NBTConstants.TYPE_COMPOUND);
|
||||
nbtOut.writeNamedTag("DataVersion", 1631);
|
||||
|
@ -52,7 +52,7 @@ public abstract class FaweChangeSet implements ChangeSet {
|
||||
public FaweChangeSet(String world) {
|
||||
this.worldName = world;
|
||||
this.mainThread = Fawe.get() == null || Fawe.isMainThread();
|
||||
this.layers = FaweCache.CHUNK_LAYERS;
|
||||
this.layers = FaweCache.IMP.CHUNK_LAYERS;
|
||||
}
|
||||
|
||||
public FaweChangeSet(World world) {
|
||||
|
@ -223,7 +223,7 @@ public class ClipboardRemapper {
|
||||
// String name = entry.getKey();
|
||||
// int id = value.get("id").getAsInt();
|
||||
// int data = value.get("data").getAsInt();
|
||||
// int combined = FaweCache.getCombined(id, data);
|
||||
// int combined = FaweCache.IMP.getCombined(id, data);
|
||||
// map.putIfAbsent(name, new ArrayList<>());
|
||||
// map.get(name).add(combined);
|
||||
// }
|
||||
@ -496,7 +496,7 @@ public class ClipboardRemapper {
|
||||
// int combined = block.getCombined();
|
||||
// if (remap[combined]) {
|
||||
// char value = remapCombined[combined];
|
||||
// BaseBlock newBlock = FaweCache.CACHE_BLOCK[value];
|
||||
// BaseBlock newBlock = FaweCache.IMP.CACHE_BLOCK[value];
|
||||
// newBlock.setNbtData(block.getNbtData());
|
||||
// return newBlock;
|
||||
// }
|
||||
|
@ -1,14 +0,0 @@
|
||||
package com.boydti.fawe.object.collection;
|
||||
|
||||
public class ByteStore extends IterableThreadLocal<byte[]> {
|
||||
private final int size;
|
||||
|
||||
public ByteStore(int size) {
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] init() {
|
||||
return new byte[size];
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
package com.boydti.fawe.object.collection;
|
||||
|
||||
import com.boydti.fawe.util.IOUtil;
|
||||
import com.boydti.fawe.util.MainUtil;
|
||||
import java.lang.ref.Reference;
|
||||
import java.lang.reflect.Array;
|
||||
@ -8,12 +9,27 @@ import java.lang.reflect.Method;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ConcurrentLinkedDeque;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.IntFunction;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public abstract class IterableThreadLocal<T> extends ThreadLocal<T> implements Iterable<T> {
|
||||
public class IterableThreadLocal<T> extends ThreadLocal<T> implements Iterable<T> {
|
||||
private final ConcurrentLinkedDeque<T> allValues = new ConcurrentLinkedDeque<>();
|
||||
private final Supplier<T> supplier;
|
||||
|
||||
public IterableThreadLocal() {
|
||||
public IterableThreadLocal(Supplier<T> supplier) {
|
||||
this.supplier = supplier;
|
||||
}
|
||||
|
||||
public IterableThreadLocal(Supplier<T> supplier, Function<T, T> modifier) {
|
||||
this.supplier = supplier;
|
||||
}
|
||||
|
||||
public IterableThreadLocal(Supplier<T> supplier, Consumer<T> modifier) {
|
||||
this.supplier = supplier;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -33,7 +49,7 @@ public abstract class IterableThreadLocal<T> extends ThreadLocal<T> implements I
|
||||
}
|
||||
|
||||
public T init() {
|
||||
return null;
|
||||
return supplier.get();
|
||||
}
|
||||
|
||||
public void clean() {
|
||||
|
@ -20,7 +20,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
*/
|
||||
public final class MemBlockSet extends BlockSet {
|
||||
public final static int BITS_PER_WORD = 6;
|
||||
public final static int WORDS = FaweCache.BLOCKS_PER_LAYER >> BITS_PER_WORD;
|
||||
public final static int WORDS = FaweCache.IMP.BLOCKS_PER_LAYER >> BITS_PER_WORD;
|
||||
public final static IRow NULL_ROW_X = new NullRowX();
|
||||
public final static IRow NULL_ROW_Z = new NullRowZ();
|
||||
public final static IRow NULL_ROW_Y = new NullRowY();
|
||||
@ -354,7 +354,7 @@ public final class MemBlockSet extends BlockSet {
|
||||
maxy = y + 1;
|
||||
}
|
||||
by = (Y << 4) + y;
|
||||
if (by == FaweCache.WORLD_MAX_Y) return FaweCache.WORLD_MAX_Y;
|
||||
if (by == FaweCache.IMP.WORLD_MAX_Y) return FaweCache.IMP.WORLD_MAX_Y;
|
||||
break outer;
|
||||
}
|
||||
}
|
||||
@ -823,7 +823,7 @@ public final class MemBlockSet extends BlockSet {
|
||||
private final IRow[] rows;
|
||||
|
||||
public RowZ() {
|
||||
this.rows = new IRow[FaweCache.CHUNK_LAYERS];
|
||||
this.rows = new IRow[FaweCache.IMP.CHUNK_LAYERS];
|
||||
reset();
|
||||
}
|
||||
|
||||
@ -866,7 +866,7 @@ public final class MemBlockSet extends BlockSet {
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
for (int i = 0; i < FaweCache.CHUNK_LAYERS; i++) rows[i] = NULL_ROW_Y;
|
||||
for (int i = 0; i < FaweCache.IMP.CHUNK_LAYERS; i++) rows[i] = NULL_ROW_Y;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -31,10 +31,10 @@ public abstract class FaweBlockMatcher {
|
||||
// public boolean apply(BaseBlock oldBlock) {
|
||||
// int currentId = oldBlock.getId();
|
||||
// oldBlock.setId(id);
|
||||
// if (FaweCache.hasData(currentId)) {
|
||||
// if (FaweCache.IMP.hasData(currentId)) {
|
||||
// oldBlock.setData(0);
|
||||
// }
|
||||
// if (FaweCache.hasNBT(currentId)) {
|
||||
// if (FaweCache.IMP.hasNBT(currentId)) {
|
||||
// oldBlock.setNbtData(null);
|
||||
// }
|
||||
// return true;
|
||||
@ -47,7 +47,7 @@ public abstract class FaweBlockMatcher {
|
||||
// int currentId = oldBlock.getId();
|
||||
// oldBlock.setId(id);
|
||||
// oldBlock.setData(data);
|
||||
// if (FaweCache.hasNBT(currentId)) {
|
||||
// if (FaweCache.IMP.hasNBT(currentId)) {
|
||||
// oldBlock.setNbtData(null);
|
||||
// }
|
||||
// return true;
|
||||
@ -67,10 +67,10 @@ public abstract class FaweBlockMatcher {
|
||||
// BaseBlock replace = array[random.random(size)];
|
||||
// int currentId = block.getId();
|
||||
// block.setId(replace.getId());
|
||||
// if (FaweCache.hasNBT(currentId)) {
|
||||
// if (FaweCache.IMP.hasNBT(currentId)) {
|
||||
// block.setNbtData(null);
|
||||
// }
|
||||
// if (FaweCache.hasData(currentId) || replace.getData() != 0) {
|
||||
// if (FaweCache.IMP.hasData(currentId) || replace.getData() != 0) {
|
||||
// block.setData(replace.getData());
|
||||
// }
|
||||
// return true;
|
||||
@ -82,7 +82,7 @@ public abstract class FaweBlockMatcher {
|
||||
public static FaweBlockMatcher fromBlock(BaseBlock block, boolean checkData) {
|
||||
// final int id = block.getId();
|
||||
// final int data = block.getData();
|
||||
// if (checkData && FaweCache.hasData(id)) {
|
||||
// if (checkData && FaweCache.IMP.hasData(id)) {
|
||||
// return new FaweBlockMatcher() {
|
||||
// @Override
|
||||
// public boolean apply(BaseBlock block) {
|
||||
@ -104,13 +104,13 @@ public abstract class FaweBlockMatcher {
|
||||
// if (searchBlocks.size() == 1) {
|
||||
// return fromBlock(searchBlocks.iterator().next(), checkData);
|
||||
// }
|
||||
// final boolean[] allowedId = new boolean[FaweCache.getId(Character.MAX_VALUE)];
|
||||
// final boolean[] allowedId = new boolean[FaweCache.IMP.getId(Character.MAX_VALUE)];
|
||||
// for (BaseBlock block : searchBlocks) {
|
||||
// allowedId[block.getId()] = true;
|
||||
// }
|
||||
// final boolean[] allowed = new boolean[Character.MAX_VALUE];
|
||||
// for (BaseBlock block : searchBlocks) {
|
||||
// allowed[FaweCache.getCombined(block)] = true;
|
||||
// allowed[FaweCache.IMP.getCombined(block)] = true;
|
||||
// }
|
||||
// if (checkData) {
|
||||
// return new FaweBlockMatcher() {
|
||||
@ -118,7 +118,7 @@ public abstract class FaweBlockMatcher {
|
||||
// public boolean apply(BaseBlock block) {
|
||||
// int id = block.getId();
|
||||
// if (allowedId[id]) {
|
||||
// if (FaweCache.hasData(id)) {
|
||||
// if (FaweCache.IMP.hasData(id)) {
|
||||
// return allowed[(id << 4) + block.getData()];
|
||||
// }
|
||||
// return true;
|
||||
|
@ -36,7 +36,7 @@ public class FuzzyRegionSelector extends PassthroughExtent implements RegionSele
|
||||
.player(FawePlayer.wrap(player))
|
||||
.changeSetNull()
|
||||
.checkMemory(false)
|
||||
.autoQueue(true)
|
||||
.autoQueue(false)
|
||||
.build());
|
||||
this.player = player;
|
||||
this.region = new FuzzyRegion(world, getExtent(), mask);
|
||||
|
@ -161,7 +161,7 @@ public class MinecraftStructure implements ClipboardReader, ClipboardWriter {
|
||||
if (width > WARN_SIZE || height > WARN_SIZE || length > WARN_SIZE) {
|
||||
Fawe.debug("A structure longer than 32 is unsupported by minecraft (but probably still works)");
|
||||
}
|
||||
Map<String, Object> structure = FaweCache.asMap("version", 1, "author", owner);
|
||||
Map<String, Object> structure = FaweCache.IMP.asMap("version", 1, "author", owner);
|
||||
// ignored: version / owner
|
||||
MutableBlockVector3 mutable = new MutableBlockVector3(0, 0, 0);
|
||||
Int2ObjectArrayMap<Integer> indexes = new Int2ObjectArrayMap<>();
|
||||
@ -211,10 +211,10 @@ public class MinecraftStructure implements ClipboardReader, ClipboardWriter {
|
||||
List<Integer> pos = Arrays.asList(point.getX() - min.getX(),
|
||||
point.getY() - min.getY(), point.getZ() - min.getZ());
|
||||
if (!block.hasNbtData()) {
|
||||
blocks.add(FaweCache.asMap("state", index, "pos", pos));
|
||||
blocks.add(FaweCache.IMP.asMap("state", index, "pos", pos));
|
||||
} else {
|
||||
blocks.add(
|
||||
FaweCache.asMap("state", index, "pos", pos, "nbt", block.getNbtData()));
|
||||
FaweCache.IMP.asMap("state", index, "pos", pos, "nbt", block.getNbtData()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -234,14 +234,14 @@ public class MinecraftStructure implements ClipboardReader, ClipboardWriter {
|
||||
// Replace rotation data
|
||||
nbtMap.put("Rotation", writeRotation(entity.getLocation()));
|
||||
nbtMap.put("id", new StringTag(state.getType().getId()));
|
||||
Map<String, Object> entityMap = FaweCache.asMap("pos", pos, "blockPos", blockPos, "nbt", nbt);
|
||||
Map<String, Object> entityMap = FaweCache.IMP.asMap("pos", pos, "blockPos", blockPos, "nbt", nbt);
|
||||
entities.add(entityMap);
|
||||
}
|
||||
}
|
||||
if (!entities.isEmpty()) {
|
||||
structure.put("entities", entities);
|
||||
}
|
||||
out.writeNamedTag("", FaweCache.asTag(structure));
|
||||
out.writeNamedTag("", FaweCache.IMP.asTag(structure));
|
||||
close();
|
||||
}
|
||||
|
||||
|
@ -25,10 +25,11 @@ public class FaweLocalBlockQueue extends LocalBlockQueue {
|
||||
|
||||
public final IQueueExtent IMP;
|
||||
private final LegacyMapper legacyMapper;
|
||||
private final World world;
|
||||
|
||||
public FaweLocalBlockQueue(String worldName) {
|
||||
super(worldName);
|
||||
World world = FaweAPI.getWorld(worldName);
|
||||
this.world = FaweAPI.getWorld(worldName);
|
||||
IMP = Fawe.get().getQueueHandler().getQueue(world);
|
||||
legacyMapper = LegacyMapper.getInstance();
|
||||
}
|
||||
@ -104,7 +105,7 @@ public class FaweLocalBlockQueue extends LocalBlockQueue {
|
||||
|
||||
@Override
|
||||
public String getWorld() {
|
||||
return IMP.getId();
|
||||
return world.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -134,7 +135,7 @@ public class FaweLocalBlockQueue extends LocalBlockQueue {
|
||||
|
||||
@Override
|
||||
public boolean setTile(int x, int y, int z, CompoundTag tag) {
|
||||
IMP.setTile(x, y, z, (com.sk89q.jnbt.CompoundTag) FaweCache.asTag(tag));
|
||||
IMP.setTile(x, y, z, (com.sk89q.jnbt.CompoundTag) FaweCache.IMP.asTag(tag));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -116,7 +116,7 @@ public class FaweSchematicHandler extends SchematicHandler {
|
||||
public void run(OutputStream output) {
|
||||
try {
|
||||
try (PGZIPOutputStream gzip = new PGZIPOutputStream(output)) {
|
||||
CompoundTag weTag = (CompoundTag) FaweCache.asTag(tag);
|
||||
CompoundTag weTag = (CompoundTag) FaweCache.IMP.asTag(tag);
|
||||
try (NBTOutputStream nos = new NBTOutputStream(gzip)) {
|
||||
Map<String, Tag> map = weTag.getValue();
|
||||
nos.writeNamedTag("Schematic", map.getOrDefault("Schematic", weTag));
|
||||
|
@ -93,7 +93,7 @@ public final class BrushCache {
|
||||
} else {
|
||||
displayMap = ReflectionUtils.getMap(display.getValue());
|
||||
}
|
||||
displayMap.put("Lore", FaweCache.asTag(json.split("\\r?\\n")));
|
||||
displayMap.put("Lore", FaweCache.IMP.asTag(json.split("\\r?\\n")));
|
||||
String primary = (String) tool.getPrimary().getSettings().get(BrushSettings.SettingType.BRUSH);
|
||||
String secondary = (String) tool.getSecondary().getSettings().get(BrushSettings.SettingType.BRUSH);
|
||||
if (primary == null) primary = secondary;
|
||||
|
@ -5,6 +5,11 @@ import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.IntFunction;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public final class IOUtil {
|
||||
|
||||
@ -79,4 +84,30 @@ public final class IOUtil {
|
||||
out.write(buf, 0, r);
|
||||
}
|
||||
}
|
||||
|
||||
public static <T> Supplier<T> supplier(IntFunction<T> funx, int size) {
|
||||
return () -> funx.apply(size);
|
||||
}
|
||||
|
||||
public static <T> Supplier<T> supplier(Supplier<T> supplier, Function<T, T> modifier) {
|
||||
return () -> modifier.apply(supplier.get());
|
||||
}
|
||||
|
||||
public static <T> Supplier<T> supplier(Supplier<T> supplier, Consumer<T> modifier) {
|
||||
return () -> {
|
||||
T instance = supplier.get();
|
||||
modifier.accept(instance);
|
||||
return instance;
|
||||
};
|
||||
}
|
||||
|
||||
public static <T> Supplier<T> supplier(Callable<T> callable) {
|
||||
return () -> {
|
||||
try {
|
||||
return callable.call();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
package com.boydti.fawe.wrappers;
|
||||
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.object.RunnableVal;
|
||||
import com.boydti.fawe.util.ExtentTraverser;
|
||||
import com.boydti.fawe.util.TaskManager;
|
||||
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
@ -12,6 +14,8 @@ import com.sk89q.worldedit.blocks.BaseItemStack;
|
||||
import com.sk89q.worldedit.entity.BaseEntity;
|
||||
import com.sk89q.worldedit.entity.Entity;
|
||||
import com.sk89q.worldedit.extension.platform.Platform;
|
||||
import com.sk89q.worldedit.extent.AbstractDelegateExtent;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.function.mask.Mask;
|
||||
import com.sk89q.worldedit.function.operation.Operation;
|
||||
import com.sk89q.worldedit.math.BlockVector2;
|
||||
@ -57,6 +61,18 @@ public class WorldWrapper extends AbstractWorld {
|
||||
return world;
|
||||
}
|
||||
|
||||
public static World unwrap(Extent extent) {
|
||||
if (extent.isWorld()) {
|
||||
if (extent instanceof World) {
|
||||
return unwrap((World) extent);
|
||||
}
|
||||
if (extent instanceof AbstractDelegateExtent) {
|
||||
return unwrap(new ExtentTraverser<>(extent).find(World.class).get());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private WorldWrapper(World parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
@ -267,4 +283,9 @@ public class WorldWrapper extends AbstractWorld {
|
||||
public BlockVector3 getSpawnPosition() {
|
||||
return parent.getSpawnPosition();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IChunkGet get(int x, int z) {
|
||||
return parent.get(x, z);
|
||||
}
|
||||
}
|
||||
|
@ -164,7 +164,7 @@ import org.slf4j.LoggerFactory;
|
||||
* using the {@link ChangeSetExtent}.</p>
|
||||
*/
|
||||
@SuppressWarnings({"FieldCanBeLocal"})
|
||||
public class EditSession extends PassthroughExtent implements SimpleWorld, AutoCloseable {
|
||||
public class EditSession extends PassthroughExtent implements AutoCloseable {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(EditSession.class);
|
||||
|
||||
@ -3023,33 +3023,10 @@ public class EditSession extends PassthroughExtent implements SimpleWorld, AutoC
|
||||
Direction.DOWN.toBlockVector(),
|
||||
};
|
||||
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return worldName;
|
||||
}
|
||||
|
||||
@Override public @org.jetbrains.annotations.Nullable Path getStoragePath() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean clearContainerBlockContents(BlockVector3 pos) {
|
||||
BaseBlock block = getFullBlock(pos);
|
||||
CompoundTag nbt = block.getNbtData();
|
||||
if (nbt != null) {
|
||||
if (nbt.containsKey("items")) {
|
||||
return setBlock(pos.getBlockX(), pos.getBlockY(), pos.getBlockZ(), block.toBlockState().toBaseBlock());
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean regenerate(final Region region) {
|
||||
return regenerate(region, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean regenerate(final Region region, final EditSession session) {
|
||||
return session.regenerate(region, null, null);
|
||||
}
|
||||
@ -3164,69 +3141,4 @@ public class EditSession extends PassthroughExtent implements SimpleWorld, AutoC
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void simulateBlockMine(BlockVector3 position) {
|
||||
TaskManager.IMP.sync((Supplier<Object>) () -> {
|
||||
world.simulateBlockMine(position);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
public boolean generateTree(TreeGenerator.TreeType type, BlockVector3 position) {
|
||||
return generateTree(type, this, position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean generateTree(TreeGenerator.TreeType type, EditSession editSession, BlockVector3 position) {
|
||||
if (getWorld() != null) {
|
||||
try {
|
||||
return getWorld().generateTree(type, editSession, position);
|
||||
} catch (MaxChangedBlocksException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WeatherType getWeather() {
|
||||
return world.getWeather();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getRemainingWeatherDuration() {
|
||||
return world.getRemainingWeatherDuration();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWeather(WeatherType weatherType) {
|
||||
world.setWeather(weatherType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWeather(WeatherType weatherType, long duration) {
|
||||
world.setWeather(weatherType, duration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dropItem(Vector3 position, BaseItemStack item) {
|
||||
world.dropItem(position, item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean playEffect(Vector3 position, int type, int data) {
|
||||
return world.playEffect(position, type, data);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean notifyAndLightBlock(BlockVector3 position, BlockState previousType) throws WorldEditException {
|
||||
return world.notifyAndLightBlock(position, previousType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockVector3 getSpawnPosition() {
|
||||
return world.getSpawnPosition();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -618,7 +618,7 @@ public class SelectionCommands {
|
||||
maskOpt = new IdMask(world);
|
||||
}
|
||||
//TODO Make FuzzyRegionSelector accept actors
|
||||
newSelector = new FuzzyRegionSelector((Player) actor, editSession, maskOpt);
|
||||
newSelector = new FuzzyRegionSelector((Player) actor, world, maskOpt);
|
||||
actor.print(BBC.SEL_FUZZY.s());
|
||||
actor.print(BBC.SEL_LIST.s());
|
||||
break;
|
||||
|
@ -22,8 +22,12 @@ package com.sk89q.worldedit.entity;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.jnbt.ListTag;
|
||||
import com.sk89q.worldedit.extent.Extent;
|
||||
import com.sk89q.worldedit.util.Location;
|
||||
import com.sk89q.worldedit.world.NbtValued;
|
||||
import com.sk89q.worldedit.world.entity.EntityType;
|
||||
import com.sk89q.worldedit.world.entity.EntityTypes;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@ -56,6 +60,10 @@ public class BaseEntity implements NbtValued {
|
||||
setNbtData(nbtData);
|
||||
}
|
||||
|
||||
public BaseEntity(CompoundTag tag) {
|
||||
this(EntityTypes.parse(tag.getString("Id")), tag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new base entity with no NBT data.
|
||||
*
|
||||
@ -76,6 +84,17 @@ public class BaseEntity implements NbtValued {
|
||||
setNbtData(other.getNbtData());
|
||||
}
|
||||
|
||||
public Location getLocation(Extent extent) {
|
||||
ListTag posTag = nbtData.getListTag("Pos");
|
||||
ListTag rotTag = nbtData.getListTag("Rotation");
|
||||
double x = posTag.getDouble(0);
|
||||
double y = posTag.getDouble(1);
|
||||
double z = posTag.getDouble(2);
|
||||
float yaw = rotTag.getFloat(0);
|
||||
float pitch = rotTag.getFloat(1);
|
||||
return new Location(extent, x, y, z, yaw, pitch);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNbtData() {
|
||||
return true;
|
||||
|
@ -13,7 +13,7 @@ public class MutableBlockVector3 extends BlockVector3 {
|
||||
}
|
||||
|
||||
public static MutableBlockVector3 get(int x, int y, int z) {
|
||||
return FaweCache.MUTABLE_BLOCKVECTOR3.get().setComponents(x, y, z);
|
||||
return FaweCache.IMP.MUTABLE_BLOCKVECTOR3.get().setComponents(x, y, z);
|
||||
}
|
||||
|
||||
public MutableBlockVector3() {}
|
||||
|
@ -10,11 +10,11 @@ public class MutableVector3 extends Vector3 {
|
||||
}
|
||||
|
||||
public static MutableVector3 get(int x, int y, int z) {
|
||||
return FaweCache.MUTABLE_VECTOR3.get().setComponents(x, y, z);
|
||||
return FaweCache.IMP.MUTABLE_VECTOR3.get().setComponents(x, y, z);
|
||||
}
|
||||
|
||||
public static MutableVector3 get(double x, double y, double z) {
|
||||
return FaweCache.MUTABLE_VECTOR3.get().setComponents(x, y, z);
|
||||
return FaweCache.IMP.MUTABLE_VECTOR3.get().setComponents(x, y, z);
|
||||
}
|
||||
|
||||
public MutableVector3(double x, double y, double z) {
|
||||
|
@ -43,12 +43,10 @@ public class LinkedFuture<T extends Future<T>> implements Future<T> {
|
||||
@Override
|
||||
public synchronized T get(long timeout, @NotNull TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
|
||||
if (task != null) {
|
||||
T result = task.get(timeout, unit);
|
||||
if (task != null || !task.isDone()) {
|
||||
task = task.get(timeout, unit);
|
||||
if (task != null) {
|
||||
return (T) this;
|
||||
}
|
||||
task = null;
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -19,6 +19,8 @@
|
||||
|
||||
package com.sk89q.worldedit.world;
|
||||
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.beta.implementation.NullChunkGet;
|
||||
import com.sk89q.jnbt.CompoundTag;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.MaxChangedBlocksException;
|
||||
@ -132,6 +134,11 @@ public class NullWorld extends AbstractWorld {
|
||||
return BlockVector3.ZERO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IChunkGet get(int x, int z) {
|
||||
return NullChunkGet.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState getBlock(int x, int y, int z) {
|
||||
return BlockTypes.AIR.getDefaultState();
|
||||
|
@ -19,6 +19,8 @@
|
||||
|
||||
package com.sk89q.worldedit.world;
|
||||
|
||||
import com.boydti.fawe.beta.IChunkGet;
|
||||
import com.boydti.fawe.beta.implementation.IChunkCache;
|
||||
import com.boydti.fawe.object.extent.LightingExtent;
|
||||
import com.sk89q.worldedit.EditSession;
|
||||
import com.sk89q.worldedit.MaxChangedBlocksException;
|
||||
@ -47,7 +49,7 @@ import java.util.Locale;
|
||||
/**
|
||||
* Represents a world (dimension).
|
||||
*/
|
||||
public interface World extends Extent, Keyed {
|
||||
public interface World extends Extent, Keyed, IChunkCache<IChunkGet> {
|
||||
|
||||
/**
|
||||
* Get the name of the world.
|
||||
@ -290,4 +292,7 @@ public interface World extends Extent, Keyed {
|
||||
default String getId() {
|
||||
return getName().replace(" ", "_").toLowerCase(Locale.ROOT);
|
||||
}
|
||||
|
||||
@Override
|
||||
IChunkGet get(int x, int z);
|
||||
}
|
||||
|
Reference in New Issue
Block a user