some minor refactoring

This commit is contained in:
Jesse Boyd
2019-08-18 02:09:09 +01:00
parent d1af07b6ae
commit d434dfcfdd
64 changed files with 1892 additions and 812 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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);
}
/**

View File

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

View File

@ -0,0 +1,77 @@
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;
public class ChunkCache<T extends Trimable> implements IChunkCache<T> {
protected final Long2ObjectLinkedOpenHashMap<WeakReference<T>> getCache;
private final IChunkCache<T> delegate;
protected ChunkCache(IChunkCache<T> delegate) {
this.getCache = new Long2ObjectLinkedOpenHashMap<>();
this.delegate = delegate;
}
/**
* Get or create the IGetBlocks
*
* @param index chunk index {@link com.boydti.fawe.util.MathMan#pairInt(int, int)}
* @param provider used to create if it isn't already cached
* @return cached IGetBlocks
*/
@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 T blocks = ref.get();
if (blocks != null) {
return 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<T>>> iter = getCache
.long2ObjectEntrySet().fastIterator();
while (iter.hasNext()) {
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 false;
}
synchronized (igb) {
igb.trim(true);
}
}
}
}
return result;
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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]),

View File

@ -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)",

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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