From 7daafa97f03e0f79baf1996b1ad9c79f7bcfb686 Mon Sep 17 00:00:00 2001 From: Jordan Date: Fri, 20 Sep 2024 23:10:39 +0100 Subject: [PATCH] fix: adjust linked filter to be left-right and do not link to new forked instances (#2913) * fix: adjust linked filter to be left-right and do not link to new forked instances - Assume that child filters know about their own forks - fixes #1874 * Remove appliesChunk|Layer for now --- .../core/extent/filter/LinkedFilter.java | 83 ++++++++++++------- .../extent/filter/block/ChunkFilterBlock.java | 12 ++- .../fastasyncworldedit/core/queue/Filter.java | 36 ++++---- .../core/queue/IDelegateFilter.java | 10 --- .../core/queue/IQueueExtent.java | 6 +- .../implementation/ParallelQueueExtent.java | 3 +- .../com/sk89q/worldedit/regions/Region.java | 12 ++- 7 files changed, 93 insertions(+), 69 deletions(-) diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/LinkedFilter.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/LinkedFilter.java index a600fc180..26700ccc5 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/LinkedFilter.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/LinkedFilter.java @@ -1,69 +1,92 @@ package com.fastasyncworldedit.core.extent.filter; -import com.fastasyncworldedit.core.extent.filter.block.DelegateFilter; import com.fastasyncworldedit.core.extent.filter.block.FilterBlock; import com.fastasyncworldedit.core.internal.simd.VectorizedFilter; import com.fastasyncworldedit.core.queue.Filter; +import com.fastasyncworldedit.core.queue.IChunk; +import com.sk89q.worldedit.regions.Region; import jdk.incubator.vector.ShortVector; +import org.jetbrains.annotations.Nullable; /** - * Filter which links two Filters together for single-filter-input operations. + * Filter which links two Filters together for single-filter-input operations. Left filter is operated first. * - * @param Parent which extends Filter - * @param Child which extends Filter + * @param Left filter + * @param Right filter */ -public sealed class LinkedFilter extends DelegateFilter { +public sealed class LinkedFilter implements Filter { - private final S child; + private final L left; + private final R right; + + public LinkedFilter(L left, R right) { + this.left = left; + this.right = right; + } @SuppressWarnings({"unchecked", "rawtypes"}) // we defeated the type system - public static LinkedFilter of(T parent, S child) { - if (parent instanceof VectorizedFilter p && child instanceof VectorizedFilter c) { - return new VectorizedLinkedFilter(p, c); + public static LinkedFilter of(L left, R right) { + if (left instanceof VectorizedFilter l && right instanceof VectorizedFilter r) { + return new VectorizedLinkedFilter(l, r); } - return new LinkedFilter<>(parent, child); + return new LinkedFilter<>(left, right); } - public LinkedFilter(T parent, S child) { - super(parent); - this.child = child; + public L getLeft() { + return this.left; } - public S getChild() { - return this.child; + public R getRight() { + return this.right; + } + + @Override + public T applyChunk(T chunk, @Nullable Region region) { + chunk = getLeft().applyChunk(chunk, region); + return getRight().applyChunk(chunk, region); } @Override public void applyBlock(FilterBlock block) { - this.getParent().applyBlock(block); - this.getChild().applyBlock(block); + getLeft().applyBlock(block); + getRight().applyBlock(block); } @Override - public LinkedFilter, ? extends Filter> newInstance(Filter other) { - return new LinkedFilter<>(this, other); + public void finishChunk(IChunk chunk) { + getLeft().finishChunk(chunk); + getRight().finishChunk(chunk); } - private final static class VectorizedLinkedFilter - extends LinkedFilter implements VectorizedFilter { + @Override + public Filter fork() { + return new LinkedFilter<>(getLeft().fork(), getRight().fork()); + } - public VectorizedLinkedFilter(final T parent, final S child) { - super(parent, child); + @Override + public void join() { + getLeft().join(); + getRight().join(); + } + + private final static class VectorizedLinkedFilter + extends LinkedFilter implements VectorizedFilter { + + public VectorizedLinkedFilter(final L left, final R right) { + super(left, right); } @Override public ShortVector applyVector(final ShortVector get, final ShortVector set) { - ShortVector res = getParent().applyVector(get, set); - return getChild().applyVector(get, res); + ShortVector res = getLeft().applyVector(get, set); + return getRight().applyVector(get, res); } @Override - public LinkedFilter, Filter> newInstance(Filter other) { - if (other instanceof VectorizedFilter o) { - return new VectorizedLinkedFilter(this, o); - } - return new LinkedFilter<>(this, other); + public Filter fork() { + return new VectorizedLinkedFilter<>((L) getLeft().fork(), (R) getRight().fork()); } + } } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/ChunkFilterBlock.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/ChunkFilterBlock.java index 9e11021d2..830ff9ab1 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/ChunkFilterBlock.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/filter/block/ChunkFilterBlock.java @@ -83,12 +83,20 @@ public abstract class ChunkFilterBlock extends AbstractExtentFilterBlock { /** * Filter a chunk with a region / filter. */ - public synchronized final IChunkSet filter(IChunk chunk, IChunkGet get, IChunkSet set, Filter filter, Region region, boolean full) { + public synchronized final IChunkSet filter( + IChunk chunk, + IChunkGet get, + IChunkSet set, + Filter filter, + Region region, + boolean full + ) { if (region != null) { region.filter(chunk, filter, this, get, set, full); } else { for (int layer = get.getMinSectionPosition(); layer <= get.getMaxSectionPosition(); layer++) { - if ((!full && !get.hasSection(layer)) || !filter.appliesLayer(chunk, layer)) { + //if ((!full && !get.hasSection(layer)) || !filter.appliesLayer(chunk, layer)) { + if (!full && !get.hasSection(layer)) { continue; } initLayer(get, set, layer); 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 366faa8c5..f308d4806 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 @@ -3,6 +3,7 @@ package com.fastasyncworldedit.core.queue; import com.fastasyncworldedit.core.extent.filter.block.FilterBlock; import com.sk89q.worldedit.regions.Region; +import javax.annotation.Nonnull; import javax.annotation.Nullable; /** @@ -10,30 +11,29 @@ import javax.annotation.Nullable; */ public interface Filter { - /** - * Checks whether a chunk should be read. - * - * @param chunkX the x coordinate in the chunk - * @param chunkZ the z coordinate in the chunk - */ - default boolean appliesChunk( - int chunkX, - int chunkZ - ) { - return true; - } +// /** +// * Checks whether a chunk should be read. +// * +// * @param chunkX the x coordinate in the chunk +// * @param chunkZ the z coordinate in the chunk +// */ +// default boolean appliesChunk( +// int chunkX, +// int chunkZ +// ) { +// return true; +// } /** - * Do something with the IChunk
- Return null if you don't want to filter blocks
- - * Return the chunk if you do want to filter blocks
+ * Do something with the IChunk
*/ - default T applyChunk(T chunk, @Nullable Region region) { + default @Nonnull T applyChunk(T chunk, @Nullable Region region) { return chunk; } - default boolean appliesLayer(IChunk chunk, int layer) { - return true; - } +// default boolean appliesLayer(IChunk chunk, int layer) { +// return true; +// } /** * Make changes to the block here
- e.g., block.setId(...)
- Note: Performance is diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IDelegateFilter.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IDelegateFilter.java index a4bb54017..1e172dd19 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IDelegateFilter.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IDelegateFilter.java @@ -9,21 +9,11 @@ public interface IDelegateFilter extends Filter { Filter getParent(); - @Override - default boolean appliesChunk(int chunkX, int chunkZ) { - return getParent().appliesChunk(chunkX, chunkZ); - } - @Override default V applyChunk(V chunk, @Nullable Region region) { return getParent().applyChunk(chunk, region); } - @Override - default boolean appliesLayer(IChunk chunk, int layer) { - return getParent().appliesLayer(chunk, layer); - } - @Override default void applyBlock(FilterBlock block) { getParent().applyBlock(block); 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 ee3740411..d09b7f04b 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 @@ -140,9 +140,9 @@ public interface IQueueExtent extends Flushable, Trimable, ICh int chunkZ, boolean full ) { - if (!filter.appliesChunk(chunkX, chunkZ)) { - return block; - } +// if (!filter.appliesChunk(chunkX, chunkZ)) { +// return block; +// } T chunk = this.getOrCreateChunk(chunkX, chunkZ); T newChunk = filter.applyChunk(chunk, region); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/ParallelQueueExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/ParallelQueueExtent.java index f197524f3..56a238166 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/ParallelQueueExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/ParallelQueueExtent.java @@ -30,7 +30,6 @@ import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.Countable; import com.sk89q.worldedit.world.World; @@ -227,7 +226,7 @@ public class ParallelQueueExtent extends PassthroughExtent { public int setBlocks(Region region, Pattern pattern) throws MaxChangedBlocksException { VectorizedFilter vectorizedPattern = SimdSupport.vectorizedPattern(pattern); var filter = LinkedFilter.of(vectorizedPattern == null ? pattern : vectorizedPattern, new CountFilter()); - return this.changes = apply(region, filter, true).getChild().getTotal(); + return this.changes = apply(region, filter, true).getRight().getTotal(); } @Override diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/Region.java b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/Region.java index 085274772..c236992cf 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/regions/Region.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/regions/Region.java @@ -269,7 +269,8 @@ public interface Region extends Iterable, Cloneable, IBatchProcess int minSection = Math.max(get.getMinSectionPosition(), getMinimumY() >> 4); int maxSection = Math.min(get.getMaxSectionPosition(), getMaximumY() >> 4); for (int layer = minSection; layer <= maxSection; layer++) { - if ((!full && !get.hasSection(layer)) || !filter.appliesLayer(chunk, layer)) { + //if ((!full && !get.hasSection(layer)) || !filter.appliesLayer(chunk, layer)) { + if (!full && !get.hasSection(layer)) { return; } block = block.initLayer(get, set, layer); @@ -319,7 +320,8 @@ public interface Region extends Iterable, Cloneable, IBatchProcess int layer, boolean full ) { - if ((!full && !get.hasSection(layer)) || !filter.appliesLayer(chunk, layer)) { + //if ((!full && !get.hasSection(layer)) || !filter.appliesLayer(chunk, layer)) { + if (!full && !get.hasSection(layer)) { return; } block = block.initLayer(get, set, layer); @@ -341,7 +343,8 @@ public interface Region extends Iterable, Cloneable, IBatchProcess int maxZ, boolean full ) { - if ((!full && !get.hasSection(layer)) || !filter.appliesLayer(chunk, layer)) { + //if ((!full && !get.hasSection(layer)) || !filter.appliesLayer(chunk, layer)) { + if (!full && !get.hasSection(layer)) { return; } block = block.initLayer(get, set, layer); @@ -359,7 +362,8 @@ public interface Region extends Iterable, Cloneable, IBatchProcess int yEnd, boolean full ) { - if ((!full && !get.hasSection(layer)) || !filter.appliesLayer(chunk, layer)) { + //if ((!full && !get.hasSection(layer)) || !filter.appliesLayer(chunk, layer)) { + if (!full && !get.hasSection(layer)) { return; } block = block.initLayer(get, set, layer);