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;
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 <T> Parent which extends Filter
* @param <S> Child which extends Filter
* @param <L> Left 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
public static <T extends Filter, S extends Filter> LinkedFilter<? extends T, ? extends S> of(T parent, S child) {
if (parent instanceof VectorizedFilter p && child instanceof VectorizedFilter c) {
return new VectorizedLinkedFilter(p, c);
public static <L extends Filter, R extends Filter> LinkedFilter<? extends L, ? extends R> 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 extends IChunk> 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 LinkedFilter<T, S>, ? 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<T extends VectorizedFilter, S extends VectorizedFilter>
extends LinkedFilter<T, S> 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<L extends VectorizedFilter, R extends VectorizedFilter>
extends LinkedFilter<L, R> 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<? extends LinkedFilter<T, S>, 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());
}
}
}

View File

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

View File

@ -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<br> - Return null if you don't want to filter blocks<br> -
* Return the chunk if you do want to filter blocks<br>
* Do something with the IChunk<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;
}
default boolean appliesLayer(IChunk chunk, int layer) {
return true;
}
// default boolean appliesLayer(IChunk chunk, int layer) {
// return true;
// }
/**
* 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();
@Override
default boolean appliesChunk(int chunkX, int chunkZ) {
return getParent().appliesChunk(chunkX, chunkZ);
}
@Override
default <V extends IChunk> 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);

View File

@ -140,9 +140,9 @@ public interface IQueueExtent<T extends IChunk> 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);

View File

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

View File

@ -269,7 +269,8 @@ public interface Region extends Iterable<BlockVector3>, 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<BlockVector3>, 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<BlockVector3>, 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<BlockVector3>, 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);