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
This commit is contained in:
Jordan 2024-09-20 23:10:39 +01:00 committed by GitHub
parent 393f80165c
commit 7daafa97f0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 93 additions and 69 deletions

View File

@ -1,69 +1,92 @@
package com.fastasyncworldedit.core.extent.filter; 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.extent.filter.block.FilterBlock;
import com.fastasyncworldedit.core.internal.simd.VectorizedFilter; import com.fastasyncworldedit.core.internal.simd.VectorizedFilter;
import com.fastasyncworldedit.core.queue.Filter; import com.fastasyncworldedit.core.queue.Filter;
import com.fastasyncworldedit.core.queue.IChunk;
import com.sk89q.worldedit.regions.Region;
import jdk.incubator.vector.ShortVector; 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 <T> Parent which extends Filter * @param <L> Left filter
* @param <S> Child which extends Filter * @param <R> Right filter
*/ */
public sealed class LinkedFilter<T extends Filter, S extends Filter> extends DelegateFilter<T> { public sealed class LinkedFilter<L extends Filter, R extends Filter> 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 @SuppressWarnings({"unchecked", "rawtypes"}) // we defeated the type system
public static <T extends Filter, S extends Filter> LinkedFilter<? extends T, ? extends S> of(T parent, S child) { public static <L extends Filter, R extends Filter> LinkedFilter<? extends L, ? extends R> of(L left, R right) {
if (parent instanceof VectorizedFilter p && child instanceof VectorizedFilter c) { if (left instanceof VectorizedFilter l && right instanceof VectorizedFilter r) {
return new VectorizedLinkedFilter(p, c); return new VectorizedLinkedFilter(l, r);
} }
return new LinkedFilter<>(parent, child); return new LinkedFilter<>(left, right);
} }
public LinkedFilter(T parent, S child) { public L getLeft() {
super(parent); return this.left;
this.child = child;
} }
public S getChild() { public R getRight() {
return this.child; return this.right;
}
@Override
public <T extends IChunk> T applyChunk(T chunk, @Nullable Region region) {
chunk = getLeft().applyChunk(chunk, region);
return getRight().applyChunk(chunk, region);
} }
@Override @Override
public void applyBlock(FilterBlock block) { public void applyBlock(FilterBlock block) {
this.getParent().applyBlock(block); getLeft().applyBlock(block);
this.getChild().applyBlock(block); getRight().applyBlock(block);
} }
@Override @Override
public LinkedFilter<? extends LinkedFilter<T, S>, ? extends Filter> newInstance(Filter other) { public void finishChunk(IChunk chunk) {
return new LinkedFilter<>(this, other); getLeft().finishChunk(chunk);
getRight().finishChunk(chunk);
} }
private final static class VectorizedLinkedFilter<T extends VectorizedFilter, S extends VectorizedFilter> @Override
extends LinkedFilter<T, S> implements VectorizedFilter { public Filter fork() {
return new LinkedFilter<>(getLeft().fork(), getRight().fork());
}
public VectorizedLinkedFilter(final T parent, final S child) { @Override
super(parent, child); public void join() {
getLeft().join();
getRight().join();
}
private final static class VectorizedLinkedFilter<L extends VectorizedFilter, R extends VectorizedFilter>
extends LinkedFilter<L, R> implements VectorizedFilter {
public VectorizedLinkedFilter(final L left, final R right) {
super(left, right);
} }
@Override @Override
public ShortVector applyVector(final ShortVector get, final ShortVector set) { public ShortVector applyVector(final ShortVector get, final ShortVector set) {
ShortVector res = getParent().applyVector(get, set); ShortVector res = getLeft().applyVector(get, set);
return getChild().applyVector(get, res); return getRight().applyVector(get, res);
} }
@Override @Override
public LinkedFilter<? extends LinkedFilter<T, S>, Filter> newInstance(Filter other) { public Filter fork() {
if (other instanceof VectorizedFilter o) { return new VectorizedLinkedFilter<>((L) getLeft().fork(), (R) getRight().fork());
return new VectorizedLinkedFilter(this, o);
}
return new LinkedFilter<>(this, other);
} }
} }
} }

View File

@ -83,12 +83,20 @@ public abstract class ChunkFilterBlock extends AbstractExtentFilterBlock {
/** /**
* Filter a chunk with a region / filter. * 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) { if (region != null) {
region.filter(chunk, filter, this, get, set, full); region.filter(chunk, filter, this, get, set, full);
} else { } else {
for (int layer = get.getMinSectionPosition(); layer <= get.getMaxSectionPosition(); layer++) { 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; continue;
} }
initLayer(get, set, layer); initLayer(get, set, layer);

View File

@ -3,6 +3,7 @@ package com.fastasyncworldedit.core.queue;
import com.fastasyncworldedit.core.extent.filter.block.FilterBlock; import com.fastasyncworldedit.core.extent.filter.block.FilterBlock;
import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.Region;
import javax.annotation.Nonnull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
/** /**
@ -10,30 +11,29 @@ import javax.annotation.Nullable;
*/ */
public interface Filter { public interface Filter {
/** // /**
* Checks whether a chunk should be read. // * Checks whether a chunk should be read.
* // *
* @param chunkX the x coordinate in the chunk // * @param chunkX the x coordinate in the chunk
* @param chunkZ the z coordinate in the chunk // * @param chunkZ the z coordinate in the chunk
*/ // */
default boolean appliesChunk( // default boolean appliesChunk(
int chunkX, // int chunkX,
int chunkZ // int chunkZ
) { // ) {
return true; // return true;
} // }
/** /**
* Do something with the IChunk<br> - Return null if you don't want to filter blocks<br> - * Do something with the IChunk<br>
* Return the chunk if you do want to filter blocks<br>
*/ */
default <T extends IChunk> T applyChunk(T chunk, @Nullable Region region) { default @Nonnull <T extends IChunk> T applyChunk(T chunk, @Nullable Region region) {
return chunk; return chunk;
} }
default boolean appliesLayer(IChunk chunk, int layer) { // default boolean appliesLayer(IChunk chunk, int layer) {
return true; // return true;
} // }
/** /**
* Make changes to the block here<br> - e.g., block.setId(...)<br> - Note: Performance is * Make changes to the block here<br> - e.g., block.setId(...)<br> - Note: Performance is

View File

@ -9,21 +9,11 @@ public interface IDelegateFilter extends Filter {
Filter getParent(); Filter getParent();
@Override
default boolean appliesChunk(int chunkX, int chunkZ) {
return getParent().appliesChunk(chunkX, chunkZ);
}
@Override @Override
default <V extends IChunk> V applyChunk(V chunk, @Nullable Region region) { default <V extends IChunk> V applyChunk(V chunk, @Nullable Region region) {
return getParent().applyChunk(chunk, region); return getParent().applyChunk(chunk, region);
} }
@Override
default boolean appliesLayer(IChunk chunk, int layer) {
return getParent().appliesLayer(chunk, layer);
}
@Override @Override
default void applyBlock(FilterBlock block) { default void applyBlock(FilterBlock block) {
getParent().applyBlock(block); getParent().applyBlock(block);

View File

@ -140,9 +140,9 @@ public interface IQueueExtent<T extends IChunk> extends Flushable, Trimable, ICh
int chunkZ, int chunkZ,
boolean full boolean full
) { ) {
if (!filter.appliesChunk(chunkX, chunkZ)) { // if (!filter.appliesChunk(chunkX, chunkZ)) {
return block; // return block;
} // }
T chunk = this.getOrCreateChunk(chunkX, chunkZ); T chunk = this.getOrCreateChunk(chunkX, chunkZ);
T newChunk = filter.applyChunk(chunk, region); T newChunk = filter.applyChunk(chunk, region);

View File

@ -30,7 +30,6 @@ import com.sk89q.worldedit.function.pattern.Pattern;
import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.internal.util.LogManagerCompat;
import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector2;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.CuboidRegion;
import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.Countable; import com.sk89q.worldedit.util.Countable;
import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.World;
@ -227,7 +226,7 @@ public class ParallelQueueExtent extends PassthroughExtent {
public int setBlocks(Region region, Pattern pattern) throws MaxChangedBlocksException { public int setBlocks(Region region, Pattern pattern) throws MaxChangedBlocksException {
VectorizedFilter vectorizedPattern = SimdSupport.vectorizedPattern(pattern); VectorizedFilter vectorizedPattern = SimdSupport.vectorizedPattern(pattern);
var filter = LinkedFilter.of(vectorizedPattern == null ? pattern : vectorizedPattern, new CountFilter()); 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 @Override

View File

@ -269,7 +269,8 @@ public interface Region extends Iterable<BlockVector3>, Cloneable, IBatchProcess
int minSection = Math.max(get.getMinSectionPosition(), getMinimumY() >> 4); int minSection = Math.max(get.getMinSectionPosition(), getMinimumY() >> 4);
int maxSection = Math.min(get.getMaxSectionPosition(), getMaximumY() >> 4); int maxSection = Math.min(get.getMaxSectionPosition(), getMaximumY() >> 4);
for (int layer = minSection; layer <= maxSection; layer++) { 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; return;
} }
block = block.initLayer(get, set, layer); block = block.initLayer(get, set, layer);
@ -319,7 +320,8 @@ public interface Region extends Iterable<BlockVector3>, Cloneable, IBatchProcess
int layer, int layer,
boolean full 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; return;
} }
block = block.initLayer(get, set, layer); block = block.initLayer(get, set, layer);
@ -341,7 +343,8 @@ public interface Region extends Iterable<BlockVector3>, Cloneable, IBatchProcess
int maxZ, int maxZ,
boolean full 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; return;
} }
block = block.initLayer(get, set, layer); block = block.initLayer(get, set, layer);
@ -359,7 +362,8 @@ public interface Region extends Iterable<BlockVector3>, Cloneable, IBatchProcess
int yEnd, int yEnd,
boolean full 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; return;
} }
block = block.initLayer(get, set, layer); block = block.initLayer(get, set, layer);