reset() {
return this;
}
+ /**
+ * Set a new {@link WrapperChunk} that allows prevention of a {@link ChunkHolder} instance being cached "locally" whilst it
+ * has been called/submitted, causing issues with processing/postprocessing, etc.
+ * If a wrapper has already been set, throws {@link IllegalStateException} as there should be no circumstance for us to set
+ * a new wrapper (does nothing if attempting to set the same wrapper).
+ *
+ * @param parentWrapper wrapper wrapping this {@link ChunkHolder instance}
+ * @throws IllegalStateException if there is already a wrapper set and a new wrapper instance is attempted to be se
+ * @since TODO
+ */
+ void setWrapper(WrapperChunk> parentWrapper);
+
+ /**
+ * Invalidate the {@link WrapperChunk} if present.
+ *
+ * @since TODO
+ */
+ void invalidateWrapper();
+
/**
* Apply the queued changes to the world containing this chunk.
* The future returned may return another future. To ensure completion keep calling {@link
diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IQueueExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IQueueExtent.java
index 70f4bd7ea8..679e80eb5b 100644
--- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IQueueExtent.java
+++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IQueueExtent.java
@@ -5,6 +5,8 @@
import com.fastasyncworldedit.core.internal.simd.SimdSupport;
import com.fastasyncworldedit.core.internal.simd.VectorizedCharFilterBlock;
import com.fastasyncworldedit.core.internal.simd.VectorizedFilter;
+import com.fastasyncworldedit.core.queue.implementation.chunk.ChunkHolder;
+import com.fastasyncworldedit.core.queue.implementation.chunk.WrapperChunk;
import com.sk89q.worldedit.extent.Extent;
import com.sk89q.worldedit.function.operation.Operation;
import com.sk89q.worldedit.math.BlockVector2;
@@ -166,11 +168,24 @@ default ChunkFilterBlock apply(
// if (!filter.appliesChunk(chunkX, chunkZ)) {
// return block;
// }
- T chunk = this.getOrCreateChunk(chunkX, chunkZ);
+ T initial = this.getOrCreateChunk(chunkX, chunkZ);
+ WrapperChunk chunk = new WrapperChunk<>(initial, () -> this.getOrCreateChunk(chunkX, chunkZ));
+ if (initial instanceof ChunkHolder> holder) {
+ holder.setWrapper(chunk);
+ }
- T newChunk = filter.applyChunk(chunk, region);
+ IChunk newChunk = filter.applyChunk(chunk, region);
+ if (newChunk == chunk) {
+ newChunk = chunk.get();
+ } else {
+ T c = (T) newChunk;
+ chunk.setWrapped(c);
+ // The IDE lies, it is possible for it to be a ChunkHolder because we're a little loose with our generic types...
+ if (c instanceof ChunkHolder> holder) {
+ holder.setWrapper(chunk);
+ }
+ }
if (newChunk != null) {
- chunk = newChunk;
if (block == null) {
if (SimdSupport.useVectorApi() && filter instanceof VectorizedFilter) {
block = new VectorizedCharFilterBlock(this);
@@ -181,12 +196,16 @@ default ChunkFilterBlock apply(
block.initChunk(chunkX, chunkZ);
chunk.filterBlocks(filter, block, region, full);
}
- this.submit(chunk);
+ // If null, then assume it has already been submitted and the WrapperChunk has therefore been invalidated
+ T toSubmit = chunk.get();
+ if (toSubmit != null) {
+ this.submit(toSubmit);
+ }
return block;
}
@Override
- default T apply(Region region, T filter, boolean full) {
+ default U apply(Region region, U filter, boolean full) {
final Set chunks = region.getChunks();
ChunkFilterBlock block = null;
for (BlockVector2 chunk : chunks) {
diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/SingleThreadQueueExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/SingleThreadQueueExtent.java
index caf14a96ff..6aafff7a03 100644
--- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/SingleThreadQueueExtent.java
+++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/SingleThreadQueueExtent.java
@@ -36,6 +36,7 @@
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
+import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.ReentrantLock;
/**
@@ -53,6 +54,7 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen
private final Long2ObjectLinkedOpenHashMap> chunks = new Long2ObjectLinkedOpenHashMap<>();
private final ConcurrentLinkedQueue> submissions = new ConcurrentLinkedQueue<>();
private final ReentrantLock getChunkLock = new ReentrantLock();
+ private final AtomicReference lastChunk = new AtomicReference<>();
private World world = null;
private int minY = 0;
private int maxY = 255;
@@ -61,7 +63,6 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen
private boolean initialized;
private Thread currentThread;
// Last access pointers
- private volatile IQueueChunk lastChunk;
private boolean enabledQueue = true;
private boolean fastmode = false;
// Array for lazy avoidance of concurrent modification exceptions and needless overcomplication of code (synchronisation is
@@ -161,13 +162,13 @@ protected synchronized void reset() {
return;
}
getChunkLock.lock();
+ this.lastChunk.set(null);
try {
this.chunks.clear();
} finally {
getChunkLock.unlock();
}
this.enabledQueue = true;
- this.lastChunk = null;
this.currentThread = null;
this.initialized = false;
this.setProcessor(EmptyBatchProcessor.getInstance());
@@ -221,9 +222,7 @@ public boolean isEmpty() {
@Override
public > V submit(IQueueChunk chunk) {
- if (lastChunk == chunk) {
- lastChunk = null;
- }
+ this.lastChunk.compareAndExchange(chunk, null);
final long index = MathMan.pairInt(chunk.getX(), chunk.getZ());
getChunkLock.lock();
chunks.remove(index, chunk);
@@ -254,6 +253,8 @@ private > V submitUnchecked(IQueueChunk chunk) {
}
}
+ chunk.invalidateWrapper();
+
if (Fawe.isMainThread()) {
V result = (V) chunk.call();
if (result == null) {
@@ -277,8 +278,9 @@ public > V submitTaskUnchecked(Callable callable) {
public synchronized boolean trim(boolean aggressive) {
cacheGet.trim(aggressive);
cacheSet.trim(aggressive);
+ LOGGER.info("trim");
if (Thread.currentThread() == currentThread) {
- lastChunk = null;
+ lastChunk.set(null);
return chunks.isEmpty();
}
if (!submissions.isEmpty()) {
@@ -316,7 +318,7 @@ public IQueueChunk wrap(IQueueChunk chunk) {
@Override
public final IQueueChunk getOrCreateChunk(int x, int z) {
- final IQueueChunk lastChunk = this.lastChunk;
+ final IQueueChunk lastChunk = this.lastChunk.get();
if (lastChunk != null && lastChunk.getX() == x && lastChunk.getZ() == z) {
return lastChunk;
}
@@ -330,7 +332,7 @@ public final IQueueChunk getOrCreateChunk(int x, int z) {
try {
IQueueChunk chunk = chunks.get(pair);
if (chunk != null) {
- this.lastChunk = chunk;
+ this.lastChunk.set(chunk);
return chunk;
}
final int size = chunks.size();
@@ -340,8 +342,9 @@ public final IQueueChunk getOrCreateChunk(int x, int z) {
// - queue size > target size and primary queue has less than num threads submissions
int targetSize = lowMem ? Settings.settings().QUEUE.PARALLEL_THREADS + 8 : this.targetSize;
if (enabledQueue && size > targetSize && (lowMem || Fawe.instance().getQueueHandler().isUnderutilized())) {
- chunk = chunks.removeFirst();
- final Future future = submitUnchecked(chunk);
+ IQueueChunk toSubmit = chunks.removeFirst();
+ this.lastChunk.compareAndExchange(toSubmit, null);
+ final Future future = submitUnchecked(toSubmit);
if (future != null && !future.isDone()) {
pollSubmissions(targetSize, lowMem);
submissions.add(future);
@@ -351,7 +354,7 @@ public final IQueueChunk getOrCreateChunk(int x, int z) {
chunk = wrap(chunk);
chunks.put(pair, chunk);
- this.lastChunk = chunk;
+ this.lastChunk.set(chunk);
return chunk;
} finally {
@@ -481,6 +484,7 @@ public synchronized void flush() {
if (MemUtil.isMemoryLimited()) {
while (!chunks.isEmpty()) {
IQueueChunk chunk = chunks.removeFirst();
+ this.lastChunk.compareAndExchange(chunk, null);
final Future future = submitUnchecked(chunk);
if (future != null && !future.isDone()) {
pollSubmissions(Settings.settings().QUEUE.PARALLEL_THREADS, true);
@@ -490,6 +494,7 @@ public synchronized void flush() {
} else {
while (!chunks.isEmpty()) {
IQueueChunk chunk = chunks.removeFirst();
+ this.lastChunk.compareAndExchange(chunk, null);
final Future future = submitUnchecked(chunk);
if (future != null && !future.isDone()) {
submissions.add(future);
diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/ChunkHolder.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/ChunkHolder.java
index cbe1c3c052..2251ca0096 100644
--- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/ChunkHolder.java
+++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/ChunkHolder.java
@@ -36,6 +36,7 @@
*/
@SuppressWarnings("rawtypes")
public class ChunkHolder> implements IQueueChunk {
+
private static final Logger LOGGER = LogManagerCompat.getLogger();
public static ChunkHolder newInstance() {
@@ -45,7 +46,7 @@ public static ChunkHolder newInstance() {
private volatile IChunkGet chunkExisting; // The existing chunk (e.g. a clipboard, or the world, before changes)
private volatile IChunkSet chunkSet; // The blocks to be set to the chunkExisting
private IBlockDelegate delegate; // delegate handles the abstraction of the chunk layers
- private IQueueExtent extends IChunk> extent; // the parent queue extent which has this chunk
+ private IQueueExtent> extent; // the parent queue extent which has this chunk
private int chunkX;
private int chunkZ;
private boolean fastmode;
@@ -54,6 +55,7 @@ public static ChunkHolder newInstance() {
private boolean createCopy = false;
private long initTime = -1L;
private SideEffectSet sideEffectSet;
+ private WrapperChunk> parentWrapper = null;
private ChunkHolder() {
this.delegate = NULL;
@@ -63,7 +65,28 @@ public void init(IBlockDelegate delegate) {
this.delegate = delegate;
}
+ @Override
+ public void setWrapper(WrapperChunk> parentWrapper) {
+ if (parentWrapper == this.parentWrapper) {
+ return;
+ }
+ if (this.parentWrapper != null) {
+ throw new IllegalStateException("Wrapper already set");
+ }
+ this.parentWrapper = parentWrapper;
+ }
+
+ @Override
+ public void invalidateWrapper() {
+ if (this.parentWrapper != null) {
+ if (!this.parentWrapper.invalidate(this)) {
+ throw new IllegalStateException("Existing chunk not equal to expected");
+ }
+ }
+ }
+
private static final AtomicBoolean recycleWarning = new AtomicBoolean(false);
+
@Override
public void recycle() {
if (!recycleWarning.getAndSet(true)) {
@@ -346,10 +369,12 @@ public int[] getHeightMap(ChunkHolder chunk, HeightMapType type) {
@Override
public void flushLightToGet(ChunkHolder chunk) {
- chunk.chunkExisting.setLightingToGet(chunk.chunkSet.getLight(), chunk.chunkSet.getMinSectionPosition(),
+ chunk.chunkExisting.setLightingToGet(
+ chunk.chunkSet.getLight(), chunk.chunkSet.getMinSectionPosition(),
chunk.chunkSet.getMaxSectionPosition()
);
- chunk.chunkExisting.setSkyLightingToGet(chunk.chunkSet.getSkyLight(), chunk.chunkSet.getMinSectionPosition(),
+ chunk.chunkExisting.setSkyLightingToGet(
+ chunk.chunkSet.getSkyLight(), chunk.chunkSet.getMinSectionPosition(),
chunk.chunkSet.getMaxSectionPosition()
);
}
@@ -892,10 +917,15 @@ public boolean hasNonEmptySection(final int layer) {
public synchronized void filterBlocks(Filter filter, ChunkFilterBlock block, @Nullable Region region, boolean full) {
final IChunkGet get = getOrCreateGet();
final IChunkSet set = getOrCreateSet();
+ if (parentWrapper == null) {
+ parentWrapper = new WrapperChunk<>(this, () -> this.extent.getOrCreateChunk(getX(), getZ()));
+ } else if (parentWrapper.get() != this) {
+ throw new IllegalStateException("Parent WrapperChunk is not storing this chunk!?");
+ }
try {
- block.filter(this, get, set, filter, region, full);
+ block.filter(parentWrapper, get, set, filter, region, full);
} finally {
- filter.finishChunk(this);
+ filter.finishChunk(parentWrapper);
}
}
@@ -998,6 +1028,12 @@ public synchronized void init(IQueueExtent extent, int chu
this.extent = extent;
this.chunkX = chunkX;
this.chunkZ = chunkZ;
+ if (this.parentWrapper != null) {
+ if (!this.parentWrapper.invalidate(this)) {
+ throw new IllegalStateException("Existing chunk not equal to expected");
+ }
+ this.parentWrapper = null;
+ }
if (chunkSet != null) {
chunkSet.reset();
delegate = SET;
@@ -1013,9 +1049,11 @@ public synchronized T call() {
if (chunkSet != null && !chunkSet.isEmpty()) {
IChunkSet copy = chunkSet.createCopy();
- return this.call(extent, copy, () -> {
- // Do nothing
- });
+ return this.call(
+ extent, copy, () -> {
+ // Do nothing
+ }
+ );
}
return null;
}
@@ -1025,14 +1063,20 @@ public synchronized T call() {
*/
@Override
- public > U call(IQueueExtent extends IChunk> owner, IChunkSet set, Runnable finalize) {
+ public > U call(IQueueExtent> owner, IChunkSet set, Runnable finalize) {
if (set != null) {
+ if (parentWrapper != null) {
+ if (!parentWrapper.invalidate(this)) {
+ throw new IllegalStateException("Existing chunk not equal to expected");
+ }
+ }
IChunkGet get = getOrCreateGet();
try {
get.lockCall();
trackExtent();
boolean postProcess = !(getExtent().getPostProcessor() instanceof EmptyBatchProcessor);
final int copyKey = get.setCreateCopy(postProcess);
+ // We should always be performing processing/postprocessing with this instance (i.e. not with this.parentWrapper)
final IChunkSet iChunkSet = getExtent().processSet(this, get, set);
Runnable finalizer;
if (postProcess) {
@@ -1067,7 +1111,7 @@ private void untrackExtent() {
/**
* Get the extent this chunk is in.
*/
- public IQueueExtent extends IChunk> getExtent() {
+ public IQueueExtent> getExtent() {
return extent;
}
diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/NullChunk.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/NullChunk.java
index 7394b0c28a..f0966493c1 100644
--- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/NullChunk.java
+++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/NullChunk.java
@@ -47,6 +47,14 @@ public boolean isEmpty() {
return true;
}
+ @Override
+ public void setWrapper(final WrapperChunk parentWrapper) {
+ }
+
+ @Override
+ public void invalidateWrapper() {
+ }
+
public Future call() {
return null;
}
diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/WrapperChunk.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/WrapperChunk.java
new file mode 100644
index 0000000000..92032e6aa4
--- /dev/null
+++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/WrapperChunk.java
@@ -0,0 +1,596 @@
+package com.fastasyncworldedit.core.queue.implementation.chunk;
+
+import com.fastasyncworldedit.core.extent.filter.block.ChunkFilterBlock;
+import com.fastasyncworldedit.core.extent.processor.heightmap.HeightMapType;
+import com.fastasyncworldedit.core.math.MutableBlockVector3;
+import com.fastasyncworldedit.core.nbt.FaweCompoundTag;
+import com.fastasyncworldedit.core.queue.Filter;
+import com.fastasyncworldedit.core.queue.IChunk;
+import com.fastasyncworldedit.core.queue.IChunkGet;
+import com.fastasyncworldedit.core.queue.IChunkSet;
+import com.fastasyncworldedit.core.queue.IQueueExtent;
+import com.sk89q.jnbt.CompoundTag;
+import com.sk89q.worldedit.WorldEditException;
+import com.sk89q.worldedit.entity.Entity;
+import com.sk89q.worldedit.function.operation.Operation;
+import com.sk89q.worldedit.math.BlockVector2;
+import com.sk89q.worldedit.math.BlockVector3;
+import com.sk89q.worldedit.regions.Region;
+import com.sk89q.worldedit.util.SideEffectSet;
+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 org.jetbrains.annotations.ApiStatus;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.Future;
+import java.util.function.Supplier;
+
+/**
+ * NOT public API. Allows prevention of a {@link ChunkHolder} instance being cached "locally" whilst it has been
+ * called/submitted, causing issues with processing/postprocessing, etc.
+ * The function {@link WrapperChunk#invalidate(ChunkHolder)} is called in
+ * {@link ChunkHolder#call(IQueueExtent, IChunkSet, Runnable)} which means the next access to the wrapped chunk will call the
+ * supplier given on instantiation.
+ *
+ * @param type of wrapped chunk
+ * @since TODO
+ */
+@SuppressWarnings("removal")
+@ApiStatus.Internal
+public class WrapperChunk implements IChunk {
+
+ private final Supplier supplier;
+ private volatile T chunk;
+
+ /**
+ * New instance.
+ *
+ * @param initialValue Initial chunk to be wrapped
+ * @param supplier Supplier to provide "replacement" chunk if this {@link WrapperChunk} is invalidated
+ */
+ public WrapperChunk(T initialValue, Supplier supplier) {
+ this.chunk = initialValue;
+ this.supplier = supplier;
+ }
+
+ private T getWrapped() {
+ T c = this.chunk;
+ if (c != null) {
+ return c;
+ }
+ synchronized (this) {
+ if (this.chunk == null) {
+ this.chunk = supplier.get();
+ }
+ return this.chunk;
+ }
+ }
+
+ /**
+ * Get the chunk currently cached.
+ *
+ * @return cached chunk
+ */
+ public T get() {
+ return chunk;
+ }
+
+ /**
+ * Invalidate the currently stored chunk (set to null) if the existing {@link ChunkHolder} matches the expected.
+ *
+ * @param expected The {@link ChunkHolder} instance we expect.
+ * @return true if the expected {@link ChunkHolder} is the currently wrapped chunk, false otherwise (and does not invalidate).
+ */
+ boolean invalidate(ChunkHolder> expected) {
+ T c = this.chunk;
+ if (c != null && expected != c) {
+ return false;
+ }
+ synchronized (this) {
+ this.chunk = null;
+ }
+ return true;
+ }
+
+ /**
+ * Set a new chunk that this instance should wrap. Calls {@link ChunkHolder#setWrapper(WrapperChunk)} if the chunk to wrap
+ * is of type {@link ChunkHolder}.
+ *
+ * @param chunk chunk to wrap
+ */
+ public void setWrapped(T chunk) {
+ synchronized (this) {
+ this.chunk = Objects.requireNonNull(chunk);
+ }
+ }
+
+ @Override
+ public void init(final IQueueExtent extent, final int x, final int z) {
+ getWrapped().init(extent, x, z);
+ }
+
+ @Override
+ public int getX() {
+ return getWrapped().getX();
+ }
+
+ @Override
+ public int getZ() {
+ return getWrapped().getZ();
+ }
+
+ @Override
+ public byte[] toByteArray(final boolean full, final boolean stretched) {
+ return getWrapped().toByteArray(full, stretched);
+ }
+
+ @Override
+ public byte[] toByteArray(final byte[] buffer, final int bitMask, final boolean full, final boolean stretched) {
+ return getWrapped().toByteArray(buffer, bitMask, full, stretched);
+ }
+
+ @Override
+ public BlockVector3 getChunkBlockCoord() {
+ return getWrapped().getChunkBlockCoord();
+ }
+
+ @Override
+ public IChunk getRoot() {
+ return getWrapped().getRoot();
+ }
+
+ @Override
+ public void filterBlocks(
+ final Filter filter,
+ final ChunkFilterBlock block,
+ @Nullable final Region region,
+ final boolean full
+ ) {
+ getWrapped().filterBlocks(filter, block, region, full);
+ }
+
+ @Override
+ public boolean setBiome(final int x, final int y, final int z, final BiomeType biome) {
+ return getWrapped().setBiome(x, y, z, biome);
+ }
+
+ @Override
+ public boolean setBiome(final BlockVector3 position, final BiomeType biome) {
+ return getWrapped().setBiome(position, biome);
+ }
+
+ @Override
+ public void setBlockLight(final BlockVector3 position, final int value) {
+ getWrapped().setBlockLight(position, value);
+ }
+
+ @Override
+ public > boolean setBlock(final BlockVector3 position, final T block) throws
+ WorldEditException {
+ return getWrapped().setBlock(position, block);
+ }
+
+ @Override
+ public > boolean setBlock(final int x, final int y, final int z, final T holder) {
+ return getWrapped().setBlock(x, y, z, holder);
+ }
+
+ @Override
+ public void setBlocks(final int layer, final char[] data) {
+ getWrapped().setBlocks(layer, data);
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return getWrapped().isEmpty();
+ }
+
+ @Override
+ public boolean setTile(final int x, final int y, final int z, final CompoundTag tile) throws WorldEditException {
+ return getWrapped().setTile(x, y, z, tile);
+ }
+
+ @Override
+ public boolean tile(final int x, final int y, final int z, final FaweCompoundTag tag) {
+ return getWrapped().tile(x, y, z, tag);
+ }
+
+ @Override
+ public boolean fullySupports3DBiomes() {
+ return getWrapped().fullySupports3DBiomes();
+ }
+
+ @Override
+ public boolean setBiome(final BlockVector2 position, final BiomeType biome) {
+ return getWrapped().setBiome(position, biome);
+ }
+
+ @Override
+ public void setBlockLight(final int x, final int y, final int z, final int value) {
+ getWrapped().setBlockLight(x, y, z, value);
+ }
+
+ @Override
+ public void setSkyLight(final BlockVector3 position, final int value) {
+ getWrapped().setSkyLight(position, value);
+ }
+
+ @Override
+ public void setSkyLight(final int x, final int y, final int z, final int value) {
+ getWrapped().setSkyLight(x, y, z, value);
+ }
+
+ @Override
+ public void setHeightMap(final HeightMapType type, final int[] heightMap) {
+ getWrapped().setHeightMap(type, heightMap);
+ }
+
+ @Override
+ public void setLightLayer(final int layer, final char[] toSet) {
+ getWrapped().setLightLayer(layer, toSet);
+ }
+
+ @Override
+ public void setSkyLightLayer(final int layer, final char[] toSet) {
+ getWrapped().setSkyLightLayer(layer, toSet);
+ }
+
+ @Override
+ public void setFullBright(final int layer) {
+ getWrapped().setFullBright(layer);
+ }
+
+ @Override
+ public void setEntity(final CompoundTag tag) {
+ getWrapped().setEntity(tag);
+ }
+
+ @Override
+ public void entity(final FaweCompoundTag tag) {
+ getWrapped().entity(tag);
+ }
+
+ @Override
+ public void removeEntity(final UUID uuid) {
+ getWrapped().removeEntity(uuid);
+ }
+
+ @Override
+ public Set getEntityRemoves() {
+ return getWrapped().getEntityRemoves();
+ }
+
+ @Override
+ public BiomeType[][] getBiomes() {
+ return getWrapped().getBiomes();
+ }
+
+ @Override
+ public boolean hasBiomes() {
+ return getWrapped().hasBiomes();
+ }
+
+ @Override
+ public char[][] getLight() {
+ return getWrapped().getLight();
+ }
+
+ @Override
+ public char[][] getSkyLight() {
+ return getWrapped().getSkyLight();
+ }
+
+ @Override
+ public boolean hasLight() {
+ return getWrapped().hasLight();
+ }
+
+ @Override
+ public void setFastMode(final boolean fastMode) {
+ getWrapped().setFastMode(fastMode);
+ }
+
+ @Override
+ public boolean isFastMode() {
+ return getWrapped().isFastMode();
+ }
+
+ @Override
+ public void setBitMask(final int bitMask) {
+ getWrapped().setBitMask(bitMask);
+ }
+
+ @Override
+ public int getBitMask() {
+ return getWrapped().getBitMask();
+ }
+
+ @Override
+ public void removeSectionLighting(final int layer, final boolean sky) {
+ getWrapped().removeSectionLighting(layer, sky);
+ }
+
+ @Override
+ public boolean trim(final boolean aggressive, final int layer) {
+ return getWrapped().trim(aggressive, layer);
+ }
+
+ @Override
+ public Map getHeightMaps() {
+ return getWrapped().getHeightMaps();
+ }
+
+ @Override
+ public IChunk reset() {
+ return getWrapped().reset();
+ }
+
+ @Override
+ public int getSectionCount() {
+ return getWrapped().getSectionCount();
+ }
+
+ @Override
+ public int getMaxSectionPosition() {
+ return getWrapped().getMaxSectionPosition();
+ }
+
+ @Override
+ public int getMinSectionPosition() {
+ return getWrapped().getMinSectionPosition();
+ }
+
+ @Override
+ public @Nullable Operation commit() {
+ return getWrapped().commit();
+ }
+
+ @Override
+ public boolean hasBiomes(final int layer) {
+ return getWrapped().hasBiomes(layer);
+ }
+
+ @Override
+ public @NotNull IChunkSet createCopy() {
+ return getWrapped().createCopy();
+ }
+
+ @Override
+ public void setSideEffectSet(@NotNull final SideEffectSet sideEffectSet) {
+ getWrapped().setSideEffectSet(sideEffectSet);
+ }
+
+ @Override
+ public @NotNull SideEffectSet getSideEffectSet() {
+ return getWrapped().getSideEffectSet();
+ }
+
+ @Override
+ public BaseBlock getFullBlock(final int x, final int y, final int z) {
+ return getWrapped().getFullBlock(x, y, z);
+ }
+
+ @Override
+ public BiomeType getBiome(final BlockVector2 position) {
+ return getWrapped().getBiome(position);
+ }
+
+ @Override
+ public BiomeType getBiomeType(final int x, final int y, final int z) {
+ return getWrapped().getBiomeType(x, y, z);
+ }
+
+ @Override
+ public BiomeType getBiome(final BlockVector3 position) {
+ return getWrapped().getBiome(position);
+ }
+
+ @Override
+ public int getEmittedLight(final BlockVector3 position) {
+ return getWrapped().getEmittedLight(position);
+ }
+
+ @Override
+ public boolean hasSection(final int layer) {
+ return getWrapped().hasSection(layer);
+ }
+
+ @Override
+ public boolean hasNonEmptySection(final int layer) {
+ return getWrapped().hasNonEmptySection(layer);
+ }
+
+ @Override
+ public char[] load(final int layer) {
+ return getWrapped().load(layer);
+ }
+
+ @Override
+ public @Nullable char[] loadIfPresent(final int layer) {
+ return getWrapped().loadIfPresent(layer);
+ }
+
+ @Override
+ public BlockState getBlock(final BlockVector3 position) {
+ return getWrapped().getBlock(position);
+ }
+
+ @Override
+ public BlockState getBlock(final int x, final int y, final int z) {
+ return getWrapped().getBlock(x, y, z);
+ }
+
+ @Override
+ public BaseBlock getFullBlock(final BlockVector3 position) {
+ return getWrapped().getFullBlock(position);
+ }
+
+ @Override
+ public Map getTiles() {
+ return getWrapped().getTiles();
+ }
+
+ @Override
+ public Map tiles() {
+ return getWrapped().tiles();
+ }
+
+ @Override
+ public int getSkyLight(final int x, final int y, final int z) {
+ return getWrapped().getSkyLight(x, y, z);
+ }
+
+ @Override
+ public int getBrightness(final MutableBlockVector3 position) {
+ return getWrapped().getBrightness(position);
+ }
+
+ @Override
+ public int getBrightness(final int x, final int y, final int z) {
+ return getWrapped().getBrightness(x, y, z);
+ }
+
+ @Override
+ public int getOpacity(final MutableBlockVector3 position) {
+ return getWrapped().getOpacity(position);
+ }
+
+ @Override
+ public int getOpacity(final int x, final int y, final int z) {
+ return getWrapped().getOpacity(x, y, z);
+ }
+
+ @Override
+ public int getEmittedLight(final int x, final int y, final int z) {
+ return getWrapped().getEmittedLight(x, y, z);
+ }
+
+ @Override
+ public int getSkyLight(final MutableBlockVector3 position) {
+ return getWrapped().getSkyLight(position);
+ }
+
+ @Override
+ public int[] getHeightMap(final HeightMapType type) {
+ return getWrapped().getHeightMap(type);
+ }
+
+ @Override
+ public void optimize() {
+ getWrapped().optimize();
+ }
+
+ @Override
+ public > T call(
+ final IQueueExtent> owner,
+ final IChunkSet set,
+ final Runnable finalize
+ ) {
+ return getWrapped().call(owner, set, finalize);
+ }
+
+ @Override
+ public CompoundTag getEntity(final UUID uuid) {
+ return getWrapped().getEntity(uuid);
+ }
+
+ @Override
+ public @Nullable FaweCompoundTag entity(final UUID uuid) {
+ return getWrapped().entity(uuid);
+ }
+
+ @Override
+ public CompoundTag getTile(final int x, final int y, final int z) {
+ return getWrapped().getTile(x, y, z);
+ }
+
+ @Override
+ public @Nullable FaweCompoundTag tile(final int x, final int y, final int z) {
+ return getWrapped().tile(x, y, z);
+ }
+
+ @Override
+ public Set getEntities() {
+ return getWrapped().getEntities();
+ }
+
+ @Override
+ public Collection entities() {
+ return getWrapped().entities();
+ }
+
+ @Override
+ public Set getFullEntities() {
+ return getWrapped().getFullEntities();
+ }
+
+ @Override
+ public boolean isCreateCopy() {
+ return getWrapped().isCreateCopy();
+ }
+
+ @Override
+ public int setCreateCopy(final boolean createCopy) {
+ return getWrapped().setCreateCopy(createCopy);
+ }
+
+ @Override
+ public @Nullable IChunkGet getCopy(final int key) {
+ return getWrapped().getCopy(key);
+ }
+
+ @Override
+ public void lockCall() {
+ getWrapped().lockCall();
+ }
+
+ @Override
+ public void unlockCall() {
+ getWrapped().unlockCall();
+ }
+
+ @Override
+ public void setLightingToGet(final char[][] lighting, final int startSectionIndex, final int endSectionIndex) {
+ getWrapped().setLightingToGet(lighting, startSectionIndex, endSectionIndex);
+ }
+
+ @Override
+ public void setSkyLightingToGet(final char[][] lighting, final int startSectionIndex, final int endSectionIndex) {
+ getWrapped().setSkyLightingToGet(lighting, startSectionIndex, endSectionIndex);
+ }
+
+ @Override
+ public void setHeightmapToGet(final HeightMapType type, final int[] data) {
+ getWrapped().setHeightmapToGet(type, data);
+ }
+
+ @Override
+ public int getMaxY() {
+ return getWrapped().getMaxY();
+ }
+
+ @Override
+ public int getMinY() {
+ return getWrapped().getMinY();
+ }
+
+ @Override
+ public boolean trim(final boolean aggressive) {
+ return getWrapped().trim(aggressive);
+ }
+
+ @Override
+ public void recycle() {
+ getWrapped().recycle();
+ }
+
+
+}