From eded42b91185eef3263f8d79c48d4f8ae782b455 Mon Sep 17 00:00:00 2001 From: Pierre Maurice Schwang Date: Thu, 25 Dec 2025 21:51:15 +0100 Subject: [PATCH 1/3] feat: re-add obfuscation (#3411) --- build-logic/src/main/kotlin/buildlogic.adapter.gradle.kts | 8 +++----- .../adapters/adapter-1_21_11/build.gradle.kts | 2 +- worldedit-bukkit/build.gradle.kts | 3 +-- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/build-logic/src/main/kotlin/buildlogic.adapter.gradle.kts b/build-logic/src/main/kotlin/buildlogic.adapter.gradle.kts index 41086ee059..4fe0aa6b45 100644 --- a/build-logic/src/main/kotlin/buildlogic.adapter.gradle.kts +++ b/build-logic/src/main/kotlin/buildlogic.adapter.gradle.kts @@ -10,8 +10,7 @@ plugins { paperweight { injectPaperRepository = false - // TODO: switch back to REOBF when paper releases mappings - reobfArtifactConfiguration = io.papermc.paperweight.userdev.ReobfArtifactConfiguration.MOJANG_PRODUCTION + reobfArtifactConfiguration = io.papermc.paperweight.userdev.ReobfArtifactConfiguration.REOBF_PRODUCTION } repositories { @@ -53,10 +52,9 @@ dependencies { } } -// TODO: re-enable when paper releases mappings -/* tasks.named("assemble") { +tasks.named("assemble") { dependsOn("reobfJar") -} */ +} tasks.named("javadoc") { enabled = false diff --git a/worldedit-bukkit/adapters/adapter-1_21_11/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_21_11/build.gradle.kts index 4826b0f7d4..1a9765af08 100644 --- a/worldedit-bukkit/adapters/adapter-1_21_11/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_21_11/build.gradle.kts @@ -18,6 +18,6 @@ configurations { dependencies { // https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/ - the().paperDevBundle("1.21.11-R0.1-20251209.225848-3") + the().paperDevBundle("1.21.11-R0.1-20251223.192256-16") compileOnly(libs.paperLib) } diff --git a/worldedit-bukkit/build.gradle.kts b/worldedit-bukkit/build.gradle.kts index cbc0d2346a..78ac0e4a2c 100644 --- a/worldedit-bukkit/build.gradle.kts +++ b/worldedit-bukkit/build.gradle.kts @@ -244,8 +244,7 @@ tasks.withType().configureEach { tasks.named("assemble").configure { dependsOn("shadowJar") - // TODO: re-enable when paper releases mappings - // dependsOn("reobfShadowJar") + dependsOn("reobfShadowJar") } publishMods { From f9e66dbbb61b2e5947813bde824ecf09c8fcd0ca Mon Sep 17 00:00:00 2001 From: Jordan Date: Thu, 25 Dec 2025 20:52:35 +0000 Subject: [PATCH 2/3] fix: add a WrapperChunk to allow "Invalidating" a ChunkHolder on submission (#3354) --- .../fastasyncworldedit/core/queue/Filter.java | 2 +- .../core/queue/IQueueChunk.java | 24 + .../core/queue/IQueueExtent.java | 29 +- .../SingleThreadQueueExtent.java | 27 +- .../implementation/chunk/ChunkHolder.java | 64 +- .../queue/implementation/chunk/NullChunk.java | 8 + .../implementation/chunk/WrapperChunk.java | 596 ++++++++++++++++++ 7 files changed, 723 insertions(+), 27 deletions(-) create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/chunk/WrapperChunk.java diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/Filter.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/Filter.java index 0351e17879..60bae43c78 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/Filter.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/Filter.java @@ -24,7 +24,7 @@ public interface Filter { /** * Do something with the IChunk
*/ - default @Nonnull T applyChunk(T chunk, @Nullable Region region) { + default @Nonnull U applyChunk(U chunk, @Nullable Region region) { return chunk; } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IQueueChunk.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IQueueChunk.java index 9dda1d006a..6163fb4a4f 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IQueueChunk.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IQueueChunk.java @@ -1,9 +1,14 @@ package com.fastasyncworldedit.core.queue; +import com.fastasyncworldedit.core.queue.implementation.chunk.ChunkHolder; +import com.fastasyncworldedit.core.queue.implementation.chunk.WrapperChunk; +import org.jetbrains.annotations.ApiStatus; + import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; +@ApiStatus.Internal public interface IQueueChunk> extends IChunk, Callable { /** @@ -15,6 +20,25 @@ default IQueueChunk 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 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 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 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(); + } + + +} From 8357164b4bfb57ec8e39fa211d719378ff7ecc3d Mon Sep 17 00:00:00 2001 From: Alexander Brandes Date: Thu, 25 Dec 2025 22:18:43 +0100 Subject: [PATCH 3/3] Update lz4 to 1.10.2 (#3413) --- gradle/libs.versions.toml | 4 ++-- .../adapters/adapter-1_21_11/build.gradle.kts | 12 ------------ worldedit-bukkit/build.gradle.kts | 14 ++++++++++++++ 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 9309d7d81a..a9e5ed3301 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -32,7 +32,7 @@ antlr4 = "4.13.2" json-simple = "1.1.1" jlibnoise = "1.0.0" jchronic = "0.2.4a" -lz4-java = "1.8.0" +lz4-java = "1.10.2" lz4-stream = "1.0.0" commons-cli = "1.11.0" paperLib = "1.0.8" @@ -108,7 +108,7 @@ antlr4-runtime = { group = "org.antlr", name = "antlr4-runtime", version.ref = " json-simple = { group = "com.googlecode.json-simple", name = "json-simple", version.ref = "json-simple" } jlibnoise = { group = "com.sk89q.lib", name = "jlibnoise", version.ref = "jlibnoise" } jchronic = { group = "com.sk89q", name = "jchronic", version.ref = "jchronic" } -lz4Java = { group = "org.lz4", name = "lz4-java", version.ref = "lz4-java" } +lz4Java = { group = "at.yawk.lz4", name = "lz4-java", version.ref = "lz4-java" } lz4JavaStream = { group = "net.jpountz", name = "lz4-java-stream", version.ref = "lz4-stream" } commonsCli = { group = "commons-cli", name = "commons-cli", version.ref = "commons-cli" } paperLib = { group = "io.papermc", name = "paperlib", version.ref = "paperLib" } diff --git a/worldedit-bukkit/adapters/adapter-1_21_11/build.gradle.kts b/worldedit-bukkit/adapters/adapter-1_21_11/build.gradle.kts index 1a9765af08..d61b503251 100644 --- a/worldedit-bukkit/adapters/adapter-1_21_11/build.gradle.kts +++ b/worldedit-bukkit/adapters/adapter-1_21_11/build.gradle.kts @@ -4,18 +4,6 @@ plugins { id("buildlogic.adapter") } -configurations { - all { - resolutionStrategy { - capabilitiesResolution { - withCapability("org.lz4:lz4-java") { - selectHighestVersion() - } - } - } - } -} - dependencies { // https://repo.papermc.io/service/rest/repository/browse/maven-public/io/papermc/paper/dev-bundle/ the().paperDevBundle("1.21.11-R0.1-20251223.192256-16") diff --git a/worldedit-bukkit/build.gradle.kts b/worldedit-bukkit/build.gradle.kts index 78ac0e4a2c..b22c6f15b4 100644 --- a/worldedit-bukkit/build.gradle.kts +++ b/worldedit-bukkit/build.gradle.kts @@ -79,6 +79,20 @@ val adaptersReobf = configurations.create("adaptersReobf") { extendsFrom(adapters) } +allprojects { + configurations.configureEach { + resolutionStrategy { + capabilitiesResolution { + withCapability("org.lz4:lz4-java") { + select(candidates.first { + (it.id as org.gradle.api.artifacts.component.ModuleComponentIdentifier).group == "at.yawk.lz4" + }) + } + } + } + } +} + dependencies { api(project(":worldedit-core")) api(project(":worldedit-libs:bukkit"))