From f14df0b63d46dfdc2a764a9760d52a3296a95bdf Mon Sep 17 00:00:00 2001 From: dordsor21 Date: Mon, 27 May 2024 17:54:36 +0100 Subject: [PATCH] Add (untested) processing capability and second passes where appropriate --- .../ext/fawe/v1_20_R2/PaperweightAdapter.java | 12 +- .../FaweMutableBlockPlaceContext.java | 6 +- .../fawe/v1_20_R2/PaperweightFaweAdapter.java | 19 +- .../fawe/v1_20_R2/PaperweightGetBlocks.java | 5 +- .../fawe/v1_20_R2/PaperweightLevelProxy.java | 54 +- .../PaperweightPlacementStateProcessor.java | 61 +-- .../ext.fawe/v1_20_R3/PaperweightAdapter.java | 12 +- .../FaweMutableBlockPlaceContext.java | 6 +- .../fawe/v1_20_R3/PaperweightFaweAdapter.java | 21 +- .../fawe/v1_20_R3/PaperweightGetBlocks.java | 5 +- .../fawe/v1_20_R3/PaperweightLevelProxy.java | 54 +- .../PaperweightPlacementStateProcessor.java | 69 +-- .../ext.fawe/v1_20_R4/PaperweightAdapter.java | 12 +- .../FaweMutableBlockPlaceContext.java | 6 +- .../fawe/v1_20_R4/PaperweightFaweAdapter.java | 19 +- .../fawe/v1_20_R4/PaperweightGetBlocks.java | 5 +- .../fawe/v1_20_R4/PaperweightLevelProxy.java | 55 +-- .../PaperweightPlacementStateProcessor.java | 65 ++- .../ext/fawe/v1_21_R1/PaperweightAdapter.java | 12 +- .../FaweMutableBlockPlaceContext.java | 6 +- .../fawe/v1_21_R1/PaperweightFaweAdapter.java | 19 +- .../fawe/v1_21_R1/PaperweightGetBlocks.java | 5 +- .../fawe/v1_21_R1/PaperweightLevelProxy.java | 55 +-- .../PaperweightPlacementStateProcessor.java | 61 ++- .../bukkit/BukkitServerInterface.java | 7 +- .../bukkit/adapter/BukkitImplAdapter.java | 4 +- .../com/fastasyncworldedit/core/FaweAPI.java | 10 +- .../parser/mask/Adjacent2DMaskParser.java | 51 ++ .../core/extent/PassthroughExtent.java | 7 - .../core/extent/PlacementStateProcessor.java | 462 ++++++++++++++++++ .../processor/PlacementStateProcessor.java | 268 ---------- .../core/function/mask/Adjacent2DMask.java | 53 ++ .../core/function/mask/AdjacentAny2DMask.java | 66 +++ .../core/function/mask/AdjacentAnyMask.java | 2 +- .../changeset/FaweStreamChangeSet.java | 1 - .../fastasyncworldedit/core/queue/Filter.java | 9 + .../core/queue/IChunkSet.java | 16 + .../core/queue/IDelegateFilter.java | 5 + .../core/queue/IQueueExtent.java | 15 + .../implementation/ParallelQueueExtent.java | 41 +- .../SingleThreadQueueExtent.java | 24 +- .../implementation/blocks/BitSetBlocks.java | 11 + .../implementation/blocks/CharSetBlocks.java | 15 +- .../blocks/ThreadUnsafeCharBlocks.java | 19 +- .../implementation/chunk/ChunkHolder.java | 24 +- .../queue/implementation/chunk/NullChunk.java | 11 + .../core/util/ExtentTraverser.java | 24 + .../sk89q/worldedit/EditSessionBuilder.java | 55 ++- .../com/sk89q/worldedit/LocalSession.java | 1 + .../worldedit/command/RegionCommands.java | 100 ++-- .../extension/platform/Platform.java | 10 +- .../function/mask/BlockTypeMask.java | 7 +- .../com/sk89q/worldedit/util/SideEffect.java | 17 +- 53 files changed, 1306 insertions(+), 673 deletions(-) create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/Adjacent2DMaskParser.java create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/PlacementStateProcessor.java delete mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/PlacementStateProcessor.java create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/Adjacent2DMask.java create mode 100644 worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/AdjacentAny2DMask.java diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightAdapter.java index 9aaeb7bc2..e429fede3 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_20_R2/PaperweightAdapter.java @@ -857,12 +857,12 @@ public final class PaperweightAdapter implements BukkitImplAdapter SUPPORTED_SIDE_EFFECTS = Sets.immutableEnumSet( - SideEffect.NEIGHBORS, - SideEffect.LIGHTING, - SideEffect.VALIDATION, - SideEffect.ENTITY_AI, - SideEffect.EVENTS, - SideEffect.UPDATE + //FAWE start - FAWE-supported side effects + SideEffect.HISTORY, + SideEffect.HEIGHTMAPS, + SideEffect.LIGHTING, + SideEffect.NEIGHBORS + //FAWE end ); @Override diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/FaweMutableBlockPlaceContext.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/FaweMutableBlockPlaceContext.java index 4f6828429..a05be1dbe 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/FaweMutableBlockPlaceContext.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/FaweMutableBlockPlaceContext.java @@ -16,7 +16,11 @@ import javax.annotation.Nullable; public class FaweMutableBlockPlaceContext extends BlockPlaceContext { - private static final BlockHitResult DEFAULT_BLOCK_HIT = new BlockHitResult(Vec3.ZERO, Direction.NORTH, BlockPos.ZERO, false); + private static final BlockHitResult DEFAULT_BLOCK_HIT = new BlockHitResult(new Vec3( + Integer.MAX_VALUE, + Integer.MAX_VALUE, + Integer.MAX_VALUE + ), Direction.NORTH, BlockPos.ZERO, false); private final ServerLevel level; private BlockHitResult hitResult = null; private Direction direction = null; diff --git a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightFaweAdapter.java index f59ad4bc6..08b7cda1b 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightFaweAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R2/PaperweightFaweAdapter.java @@ -4,7 +4,7 @@ import com.fastasyncworldedit.bukkit.adapter.FaweAdapter; import com.fastasyncworldedit.bukkit.adapter.NMSRelighterFactory; import com.fastasyncworldedit.core.FaweCache; import com.fastasyncworldedit.core.entity.LazyBaseEntity; -import com.fastasyncworldedit.core.extent.processor.PlacementStateProcessor; +import com.fastasyncworldedit.core.extent.PlacementStateProcessor; import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory; import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.fastasyncworldedit.core.queue.IBatchProcessor; @@ -14,6 +14,7 @@ import com.fastasyncworldedit.core.util.NbtUtils; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Sets; import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.bukkit.BukkitAdapter; @@ -35,7 +36,6 @@ import com.sk89q.worldedit.registry.state.IntegerProperty; import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.util.SideEffect; -import com.sk89q.worldedit.util.SideEffectSet; import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.world.RegenOptions; import com.sk89q.worldedit.world.biome.BiomeType; @@ -294,9 +294,16 @@ public final class PaperweightFaweAdapter extends FaweAdapter SUPPORTED_SIDE_EFFECTS = Sets.immutableEnumSet( + SideEffect.HISTORY, + SideEffect.HEIGHTMAPS, + SideEffect.LIGHTING, + SideEffect.NEIGHBORS + ); + @Override public Set getSupportedSideEffects() { - return SideEffectSet.defaults().getSideEffectsToApply(); + return SUPPORTED_SIDE_EFFECTS; } @Override @@ -445,7 +452,7 @@ public final class PaperweightFaweAdapter extends FaweAdapter crossChunkSecondPasses, + ThreadLocal threadProcessors, + Region region, + AtomicBoolean finished ) { - super(extent, mask, includeUnedited); - World world; - if (extent.isWorld()) { - world = (World) extent; - } else if (extent instanceof EditSession session) { - world = session.getWorld(); - } else if ((world = new ExtentTraverser<>(extent).findAndGet(BukkitWorld.class)) == null) { - throw new UnsupportedOperationException("Cannot find world of extent."); - } - BukkitWorld bukkitWorld; - if (world instanceof WorldWrapper wrapper) { - bukkitWorld = (BukkitWorld) wrapper.getParent(); - } else { - bukkitWorld = (BukkitWorld) world; - } - PaperweightLevelProxy proxyLevel = PaperweightLevelProxy.getInstance( - ((CraftWorld) bukkitWorld.getWorld()).getHandle(), - extent - ); - mutableBlockPlaceContext = new FaweMutableBlockPlaceContext(proxyLevel); - proxyLevel.setEnabled(true); + super(extent, mask, crossChunkSecondPasses, threadProcessors, region, finished); + this.proxyLevel = PaperweightLevelProxy.getInstance(this); + this.mutableBlockPlaceContext = new FaweMutableBlockPlaceContext(proxyLevel); } @Override @@ -75,8 +64,8 @@ public class PaperweightPlacementStateProcessor extends PlacementStateProcessor new BlockHitResult(pos, side, blockPos, false), side.getOpposite() )); - return newState == null ? BlockTypesCache.ReservedIDs.AIR : - adapter.ibdIDToOrdinal(Block.BLOCK_STATE_REGISTRY.getId(newState)); + return newState == null ? BlockTypesCache.ReservedIDs.AIR : adapter.ibdIDToOrdinal(Block.BLOCK_STATE_REGISTRY.getId( + newState)); } @Override @@ -85,12 +74,12 @@ public class PaperweightPlacementStateProcessor extends PlacementStateProcessor if (child == getExtent()) { return this; } - return new PaperweightPlacementStateProcessor(child, mask, includeUnedited); + return new PaperweightPlacementStateProcessor(child, mask, region); } @Override public PlacementStateProcessor fork() { - return new PaperweightPlacementStateProcessor(extent, mask, includeUnedited); + return new PaperweightPlacementStateProcessor(extent, mask, postCompleteSecondPasses, threadProcessors, region, finished); } } diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightAdapter.java index ded4bcfdd..ebf1ada46 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R3/PaperweightAdapter.java @@ -856,12 +856,12 @@ public final class PaperweightAdapter implements BukkitImplAdapter SUPPORTED_SIDE_EFFECTS = Sets.immutableEnumSet( - SideEffect.NEIGHBORS, - SideEffect.LIGHTING, - SideEffect.VALIDATION, - SideEffect.ENTITY_AI, - SideEffect.EVENTS, - SideEffect.UPDATE + //FAWE start - FAWE-supported side effects + SideEffect.HISTORY, + SideEffect.HEIGHTMAPS, + SideEffect.LIGHTING, + SideEffect.NEIGHBORS + //FAWE end ); @Override diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/FaweMutableBlockPlaceContext.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/FaweMutableBlockPlaceContext.java index 36aab0805..13034892c 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/FaweMutableBlockPlaceContext.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/FaweMutableBlockPlaceContext.java @@ -16,7 +16,11 @@ import javax.annotation.Nullable; public class FaweMutableBlockPlaceContext extends BlockPlaceContext { - private static final BlockHitResult DEFAULT_BLOCK_HIT = new BlockHitResult(Vec3.ZERO, Direction.NORTH, BlockPos.ZERO, false); + private static final BlockHitResult DEFAULT_BLOCK_HIT = new BlockHitResult(new Vec3( + Integer.MAX_VALUE, + Integer.MAX_VALUE, + Integer.MAX_VALUE + ), Direction.NORTH, BlockPos.ZERO, false); private final ServerLevel level; private BlockHitResult hitResult = null; private Direction direction = null; diff --git a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightFaweAdapter.java index 20766fbe0..0b781a40d 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightFaweAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R3/PaperweightFaweAdapter.java @@ -4,7 +4,7 @@ import com.fastasyncworldedit.bukkit.adapter.FaweAdapter; import com.fastasyncworldedit.bukkit.adapter.NMSRelighterFactory; import com.fastasyncworldedit.core.FaweCache; import com.fastasyncworldedit.core.entity.LazyBaseEntity; -import com.fastasyncworldedit.core.extent.processor.PlacementStateProcessor; +import com.fastasyncworldedit.core.extent.PlacementStateProcessor; import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory; import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.fastasyncworldedit.core.queue.IBatchProcessor; @@ -14,6 +14,7 @@ import com.fastasyncworldedit.core.util.NbtUtils; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Sets; import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.blocks.BaseItemStack; import com.sk89q.worldedit.bukkit.BukkitAdapter; @@ -34,7 +35,6 @@ import com.sk89q.worldedit.registry.state.IntegerProperty; import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.util.SideEffect; -import com.sk89q.worldedit.util.SideEffectSet; import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.world.RegenOptions; import com.sk89q.worldedit.world.biome.BiomeType; @@ -293,9 +293,16 @@ public final class PaperweightFaweAdapter extends FaweAdapter SUPPORTED_SIDE_EFFECTS = Sets.immutableEnumSet( + SideEffect.HISTORY, + SideEffect.HEIGHTMAPS, + SideEffect.LIGHTING, + SideEffect.NEIGHBORS + ); + @Override public Set getSupportedSideEffects() { - return SideEffectSet.defaults().getSideEffectsToApply(); + return SUPPORTED_SIDE_EFFECTS; } @Override @@ -444,7 +451,7 @@ public final class PaperweightFaweAdapter extends FaweAdapter crossChunkSecondPasses, + ThreadLocal threadProcessors, + Region region, + AtomicBoolean finished ) { - super(extent, mask, includeUnedited); - World world; - if (extent.isWorld()) { - world = (World) extent; - } else if (extent instanceof EditSession session) { - world = session.getWorld(); - } else if ((world = new ExtentTraverser<>(extent).findAndGet(BukkitWorld.class)) == null) { - throw new UnsupportedOperationException("Cannot find world of extent."); - } - BukkitWorld bukkitWorld; - if (world instanceof WorldWrapper wrapper) { - bukkitWorld = (BukkitWorld) wrapper.getParent(); - } else { - bukkitWorld = (BukkitWorld) world; - } - PaperweightLevelProxy proxyLevel = PaperweightLevelProxy.getInstance( - ((CraftWorld) bukkitWorld.getWorld()).getHandle(), - extent - ); - mutableBlockPlaceContext = new FaweMutableBlockPlaceContext(proxyLevel); - proxyLevel.setEnabled(true); + super(extent, mask, crossChunkSecondPasses, threadProcessors, region, finished); + this.proxyLevel = PaperweightLevelProxy.getInstance(this); + this.mutableBlockPlaceContext = new FaweMutableBlockPlaceContext(proxyLevel); } @Override protected char getStateAtFor( - int x, - int y, - int z, - BlockState state, - Vector3 clickPos, - Direction clickedFaceDirection, - BlockVector3 clickedBlock + int x, int y, int z, BlockState state, Vector3 clickPos, Direction clickedFaceDirection, BlockVector3 clickedBlock ) { Block block = ((PaperweightBlockMaterial) state.getMaterial()).getBlock(); Vec3 pos = new Vec3(clickPos.x(), clickPos.y(), clickPos.z()); @@ -75,8 +58,8 @@ public class PaperweightPlacementStateProcessor extends PlacementStateProcessor new BlockHitResult(pos, side, blockPos, false), side.getOpposite() )); - return newState == null ? BlockTypesCache.ReservedIDs.AIR : - adapter.ibdIDToOrdinal(Block.BLOCK_STATE_REGISTRY.getId(newState)); + return newState == null ? BlockTypesCache.ReservedIDs.AIR : adapter.ibdIDToOrdinal(Block.BLOCK_STATE_REGISTRY.getId( + newState)); } @Override @@ -85,12 +68,12 @@ public class PaperweightPlacementStateProcessor extends PlacementStateProcessor if (child == getExtent()) { return this; } - return new PaperweightPlacementStateProcessor(child, mask, includeUnedited); + return new PaperweightPlacementStateProcessor(child, mask, region); } @Override public PlacementStateProcessor fork() { - return new PaperweightPlacementStateProcessor(extent, mask, includeUnedited); + return new PaperweightPlacementStateProcessor(extent, mask, postCompleteSecondPasses, threadProcessors, region, finished); } } diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightAdapter.java index 206ade66a..f45104c14 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext.fawe/v1_20_R4/PaperweightAdapter.java @@ -880,12 +880,12 @@ public final class PaperweightAdapter implements BukkitImplAdapter SUPPORTED_SIDE_EFFECTS = Sets.immutableEnumSet( - SideEffect.NEIGHBORS, - SideEffect.LIGHTING, - SideEffect.VALIDATION, - SideEffect.ENTITY_AI, - SideEffect.EVENTS, - SideEffect.UPDATE + //FAWE start - FAWE-supported side effects + SideEffect.HISTORY, + SideEffect.HEIGHTMAPS, + SideEffect.LIGHTING, + SideEffect.NEIGHBORS + //FAWE end ); @Override diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/FaweMutableBlockPlaceContext.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/FaweMutableBlockPlaceContext.java index 609ad796d..b4d4802dc 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/FaweMutableBlockPlaceContext.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/FaweMutableBlockPlaceContext.java @@ -16,7 +16,11 @@ import javax.annotation.Nullable; public class FaweMutableBlockPlaceContext extends BlockPlaceContext { - private static final BlockHitResult DEFAULT_BLOCK_HIT = new BlockHitResult(Vec3.ZERO, Direction.NORTH, BlockPos.ZERO, false); + private static final BlockHitResult DEFAULT_BLOCK_HIT = new BlockHitResult(new Vec3( + Integer.MAX_VALUE, + Integer.MAX_VALUE, + Integer.MAX_VALUE + ), Direction.NORTH, BlockPos.ZERO, false); private final ServerLevel level; private BlockHitResult hitResult = null; private Direction direction = null; diff --git a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightFaweAdapter.java index 95e80d1f2..a4496ed5a 100644 --- a/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightFaweAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20_5/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R4/PaperweightFaweAdapter.java @@ -4,7 +4,7 @@ import com.fastasyncworldedit.bukkit.adapter.FaweAdapter; import com.fastasyncworldedit.bukkit.adapter.NMSRelighterFactory; import com.fastasyncworldedit.core.FaweCache; import com.fastasyncworldedit.core.entity.LazyBaseEntity; -import com.fastasyncworldedit.core.extent.processor.PlacementStateProcessor; +import com.fastasyncworldedit.core.extent.PlacementStateProcessor; import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory; import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.fastasyncworldedit.core.queue.IBatchProcessor; @@ -14,6 +14,7 @@ import com.fastasyncworldedit.core.util.NbtUtils; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Sets; import com.mojang.serialization.Codec; import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.blocks.BaseItemStack; @@ -36,7 +37,6 @@ import com.sk89q.worldedit.registry.state.IntegerProperty; import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.util.SideEffect; -import com.sk89q.worldedit.util.SideEffectSet; import com.sk89q.worldedit.util.concurrency.LazyReference; import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.world.RegenOptions; @@ -303,9 +303,16 @@ public final class PaperweightFaweAdapter extends FaweAdapter SUPPORTED_SIDE_EFFECTS = Sets.immutableEnumSet( + SideEffect.HISTORY, + SideEffect.HEIGHTMAPS, + SideEffect.LIGHTING, + SideEffect.NEIGHBORS + ); + @Override public Set getSupportedSideEffects() { - return SideEffectSet.defaults().getSideEffectsToApply(); + return SUPPORTED_SIDE_EFFECTS; } @Override @@ -454,7 +461,7 @@ public final class PaperweightFaweAdapter extends FaweAdapter(extent).findAndGet(BukkitWorld.class)) == null) { - throw new UnsupportedOperationException("Cannot find world of extent."); + public PaperweightPlacementStateProcessor(Extent extent, BlockTypeMask mask, Region region) { + super(extent, mask, region); + World world = ExtentTraverser.getWorldFromExtent(extent); + if (world == null) { + throw new UnsupportedOperationException( + "World is required for PlacementStateProcessor but none found in given extent."); } BukkitWorld bukkitWorld; if (world instanceof WorldWrapper wrapper) { @@ -49,12 +46,22 @@ public class PaperweightPlacementStateProcessor extends PlacementStateProcessor } else { bukkitWorld = (BukkitWorld) world; } - PaperweightLevelProxy proxyLevel = PaperweightLevelProxy.getInstance( - ((CraftWorld) bukkitWorld.getWorld()).getHandle(), - extent - ); - mutableBlockPlaceContext = new FaweMutableBlockPlaceContext(proxyLevel); - proxyLevel.setEnabled(true); + this.proxyLevel = PaperweightLevelProxy.getInstance(((CraftWorld) bukkitWorld.getWorld()).getHandle(), this); + this.mutableBlockPlaceContext = new FaweMutableBlockPlaceContext(proxyLevel); + } + + private PaperweightPlacementStateProcessor( + Extent extent, + BlockTypeMask mask, + Map crossChunkSecondPasses, + ServerLevel serverLevel, + ThreadLocal threadProcessors, + Region region, + AtomicBoolean finished + ) { + super(extent, mask, crossChunkSecondPasses, threadProcessors, region, finished); + this.proxyLevel = PaperweightLevelProxy.getInstance(serverLevel, this); + this.mutableBlockPlaceContext = new FaweMutableBlockPlaceContext(proxyLevel); } @Override @@ -75,8 +82,8 @@ public class PaperweightPlacementStateProcessor extends PlacementStateProcessor new BlockHitResult(pos, side, blockPos, false), side.getOpposite() )); - return newState == null ? BlockTypesCache.ReservedIDs.AIR : - adapter.ibdIDToOrdinal(Block.BLOCK_STATE_REGISTRY.getId(newState)); + return newState == null ? BlockTypesCache.ReservedIDs.AIR : adapter.ibdIDToOrdinal(Block.BLOCK_STATE_REGISTRY.getId( + newState)); } @Override @@ -85,12 +92,20 @@ public class PaperweightPlacementStateProcessor extends PlacementStateProcessor if (child == getExtent()) { return this; } - return new PaperweightPlacementStateProcessor(child, mask, includeUnedited); + return new PaperweightPlacementStateProcessor(child, mask, region); } @Override public PlacementStateProcessor fork() { - return new PaperweightPlacementStateProcessor(extent, mask, includeUnedited); + return new PaperweightPlacementStateProcessor( + extent, + mask, + postCompleteSecondPasses, + proxyLevel.serverLevel, + threadProcessors, + region, + finished + ); } } diff --git a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightAdapter.java b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightAdapter.java index b958c8ba7..59be29173 100644 --- a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/ext/fawe/v1_21_R1/PaperweightAdapter.java @@ -886,12 +886,12 @@ public final class PaperweightAdapter implements BukkitImplAdapter SUPPORTED_SIDE_EFFECTS = Sets.immutableEnumSet( - SideEffect.NEIGHBORS, - SideEffect.LIGHTING, - SideEffect.VALIDATION, - SideEffect.ENTITY_AI, - SideEffect.EVENTS, - SideEffect.UPDATE + //FAWE start - FAWE-supported side effects + SideEffect.HISTORY, + SideEffect.HEIGHTMAPS, + SideEffect.LIGHTING, + SideEffect.NEIGHBORS + //FAWE end ); @Override diff --git a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/FaweMutableBlockPlaceContext.java b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/FaweMutableBlockPlaceContext.java index c7a879220..d5db5e210 100644 --- a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/FaweMutableBlockPlaceContext.java +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/FaweMutableBlockPlaceContext.java @@ -16,7 +16,11 @@ import javax.annotation.Nullable; public class FaweMutableBlockPlaceContext extends BlockPlaceContext { - private static final BlockHitResult DEFAULT_BLOCK_HIT = new BlockHitResult(Vec3.ZERO, Direction.NORTH, BlockPos.ZERO, false); + private static final BlockHitResult DEFAULT_BLOCK_HIT = new BlockHitResult(new Vec3( + Integer.MAX_VALUE, + Integer.MAX_VALUE, + Integer.MAX_VALUE + ), Direction.NORTH, BlockPos.ZERO, false); private final ServerLevel level; private BlockHitResult hitResult = null; private Direction direction = null; diff --git a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweAdapter.java b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweAdapter.java index 458428b49..5465d9c5c 100644 --- a/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_21/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_21_R1/PaperweightFaweAdapter.java @@ -4,7 +4,7 @@ import com.fastasyncworldedit.bukkit.adapter.FaweAdapter; import com.fastasyncworldedit.bukkit.adapter.NMSRelighterFactory; import com.fastasyncworldedit.core.FaweCache; import com.fastasyncworldedit.core.entity.LazyBaseEntity; -import com.fastasyncworldedit.core.extent.processor.PlacementStateProcessor; +import com.fastasyncworldedit.core.extent.PlacementStateProcessor; import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory; import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.fastasyncworldedit.core.queue.IBatchProcessor; @@ -14,6 +14,7 @@ import com.fastasyncworldedit.core.util.NbtUtils; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Sets; import com.mojang.serialization.Codec; import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.blocks.BaseItemStack; @@ -36,7 +37,6 @@ import com.sk89q.worldedit.registry.state.IntegerProperty; import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.util.Direction; import com.sk89q.worldedit.util.SideEffect; -import com.sk89q.worldedit.util.SideEffectSet; import com.sk89q.worldedit.util.concurrency.LazyReference; import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.world.RegenOptions; @@ -303,9 +303,16 @@ public final class PaperweightFaweAdapter extends FaweAdapter SUPPORTED_SIDE_EFFECTS = Sets.immutableEnumSet( + SideEffect.HISTORY, + SideEffect.HEIGHTMAPS, + SideEffect.LIGHTING, + SideEffect.NEIGHBORS + ); + @Override public Set getSupportedSideEffects() { - return SideEffectSet.defaults().getSideEffectsToApply(); + return SUPPORTED_SIDE_EFFECTS; } @Override @@ -454,7 +461,7 @@ public final class PaperweightFaweAdapter extends FaweAdapter(extent).findAndGet(BukkitWorld.class)) == null) { - throw new UnsupportedOperationException("Cannot find world of extent."); + public PaperweightPlacementStateProcessor(Extent extent, BlockTypeMask mask, Region region) { + super(extent, mask, region); + World world = ExtentTraverser.getWorldFromExtent(extent); + if (world == null) { + throw new UnsupportedOperationException( + "World is required for PlacementStateProcessor but none found in given extent."); } BukkitWorld bukkitWorld; if (world instanceof WorldWrapper wrapper) { @@ -49,12 +46,22 @@ public class PaperweightPlacementStateProcessor extends PlacementStateProcessor } else { bukkitWorld = (BukkitWorld) world; } - PaperweightLevelProxy proxyLevel = PaperweightLevelProxy.getInstance( - ((CraftWorld) bukkitWorld.getWorld()).getHandle(), - extent - ); - mutableBlockPlaceContext = new FaweMutableBlockPlaceContext(proxyLevel); - proxyLevel.setEnabled(true); + this.proxyLevel = PaperweightLevelProxy.getInstance(((CraftWorld) bukkitWorld.getWorld()).getHandle(), this); + this.mutableBlockPlaceContext = new FaweMutableBlockPlaceContext(proxyLevel); + } + + private PaperweightPlacementStateProcessor( + Extent extent, + BlockTypeMask mask, + Map crossChunkSecondPasses, + ServerLevel serverLevel, + ThreadLocal threadProcessors, + Region region, + AtomicBoolean finished + ) { + super(extent, mask, crossChunkSecondPasses, threadProcessors, region, finished); + this.proxyLevel = PaperweightLevelProxy.getInstance(serverLevel, this); + this.mutableBlockPlaceContext = new FaweMutableBlockPlaceContext(proxyLevel); } @Override @@ -85,12 +92,20 @@ public class PaperweightPlacementStateProcessor extends PlacementStateProcessor if (child == getExtent()) { return this; } - return new PaperweightPlacementStateProcessor(child, mask, includeUnedited); + return new PaperweightPlacementStateProcessor(child, mask, region); } @Override public PlacementStateProcessor fork() { - return new PaperweightPlacementStateProcessor(extent, mask, includeUnedited); + return new PaperweightPlacementStateProcessor( + extent, + mask, + postCompleteSecondPasses, + proxyLevel.serverLevel, + threadProcessors, + region, + finished + ); } } diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java index 4e04368f7..b22578bae 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/BukkitServerInterface.java @@ -21,7 +21,7 @@ package com.sk89q.worldedit.bukkit; import com.fastasyncworldedit.bukkit.util.MinecraftVersion; import com.fastasyncworldedit.core.configuration.Settings; -import com.fastasyncworldedit.core.extent.processor.PlacementStateProcessor; +import com.fastasyncworldedit.core.extent.PlacementStateProcessor; import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory; import com.fastasyncworldedit.core.queue.IBatchProcessor; import com.google.common.collect.Sets; @@ -41,6 +41,7 @@ import com.sk89q.worldedit.extension.platform.Watchdog; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.function.mask.BlockTypeMask; import com.sk89q.worldedit.internal.util.LogManagerCompat; +import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.SideEffect; import com.sk89q.worldedit.util.lifecycle.Lifecycled; import com.sk89q.worldedit.world.DataFixer; @@ -314,8 +315,8 @@ public class BukkitServerInterface extends AbstractPlatform implements MultiUser } @Override - public PlacementStateProcessor getPlatformPlacementProcessor(Extent extent, BlockTypeMask mask, boolean includeUnedited) { - return this.plugin.getBukkitImplAdapter().getPlatformPlacementProcessor(extent, mask, includeUnedited); + public PlacementStateProcessor getPlatformPlacementProcessor(Extent extent, BlockTypeMask mask, Region region) { + return this.plugin.getBukkitImplAdapter().getPlatformPlacementProcessor(extent, mask, region); } //FAWE end } diff --git a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java index bd29c1b40..02514a54b 100644 --- a/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java +++ b/worldedit-bukkit/src/main/java/com/sk89q/worldedit/bukkit/adapter/BukkitImplAdapter.java @@ -23,7 +23,7 @@ import com.fastasyncworldedit.bukkit.FaweBukkit; import com.fastasyncworldedit.bukkit.adapter.IBukkitAdapter; import com.fastasyncworldedit.bukkit.adapter.NMSRelighterFactory; import com.fastasyncworldedit.core.Fawe; -import com.fastasyncworldedit.core.extent.processor.PlacementStateProcessor; +import com.fastasyncworldedit.core.extent.PlacementStateProcessor; import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory; import com.fastasyncworldedit.core.queue.IBatchProcessor; import com.fastasyncworldedit.core.queue.IChunkGet; @@ -409,7 +409,7 @@ public interface BukkitImplAdapter extends IBukkitAdapter { * Returns an {@link PlacementStateProcessor} instance for processing placed blocks to "fix" them. * @since TODO */ - default PlacementStateProcessor getPlatformPlacementProcessor(Extent extent, BlockTypeMask mask, boolean includeUnedited) { + default PlacementStateProcessor getPlatformPlacementProcessor(Extent extent, BlockTypeMask mask, Region region) { return null; } //FAWE end diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweAPI.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweAPI.java index 28367a949..de3e1a278 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweAPI.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/FaweAPI.java @@ -32,6 +32,8 @@ import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.Location; +import com.sk89q.worldedit.util.SideEffect; +import com.sk89q.worldedit.util.SideEffectSet; import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.world.World; import org.apache.logging.log4j.Logger; @@ -355,8 +357,12 @@ public class FaweAPI { if (unwrapped instanceof IQueueExtent) { queue = (IQueueExtent) unwrapped; } else if (Settings.settings().QUEUE.PARALLEL_THREADS > 1) { - ParallelQueueExtent parallel = - new ParallelQueueExtent(Fawe.instance().getQueueHandler(), world, true); + ParallelQueueExtent parallel = new ParallelQueueExtent( + Fawe.instance().getQueueHandler(), + world, + true, + SideEffectSet.none().with(SideEffect.LIGHTING, SideEffect.State.ON) + ); queue = parallel.getExtent(); } else { queue = Fawe.instance().getQueueHandler().getQueue(world); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/Adjacent2DMaskParser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/Adjacent2DMaskParser.java new file mode 100644 index 000000000..116d3634a --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extension/factory/parser/mask/Adjacent2DMaskParser.java @@ -0,0 +1,51 @@ +package com.fastasyncworldedit.core.extension.factory.parser.mask; + +import com.fastasyncworldedit.core.extension.factory.parser.RichParser; +import com.fastasyncworldedit.core.function.mask.Adjacent2DMask; +import com.fastasyncworldedit.core.function.mask.AdjacentAny2DMask; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.command.util.SuggestionHelper; +import com.sk89q.worldedit.extension.input.InputParseException; +import com.sk89q.worldedit.extension.input.ParserContext; +import com.sk89q.worldedit.function.mask.Mask; + +import javax.annotation.Nonnull; +import java.util.stream.Stream; + +public class Adjacent2DMaskParser extends RichParser { + + public Adjacent2DMaskParser(WorldEdit worldEdit) { + super(worldEdit, "~2d", "adjacent2d"); + } + + @Override + protected Stream getSuggestions(String argumentInput, int index) { + if (index == 0) { + return worldEdit.getMaskFactory().getSuggestions(argumentInput).stream(); + } else if (index == 1 || index == 2) { + return SuggestionHelper.suggestPositiveDoubles(argumentInput); + } + return Stream.empty(); + } + + @Override + protected Mask parseFromInput(@Nonnull String[] arguments, ParserContext context) throws InputParseException { + if (arguments.length == 0) { + return null; + } + Mask subMask = worldEdit.getMaskFactory().parseFromInput(arguments[0], context); + int min = arguments.length > 1 ? Integer.parseInt(arguments[1]) : -1; + int max = arguments.length > 2 ? Integer.parseInt(arguments[2]) : -1; + if (min == -1 && max == -1) { + min = 1; + max = 4; + } else if (max == -1) { + max = min; + } + if (max >= 4 && min == 1) { + return new AdjacentAny2DMask(subMask); + } + return new Adjacent2DMask(subMask, min, max); + } + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/PassthroughExtent.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/PassthroughExtent.java index 5ac2f9d7b..e1e0975d5 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/PassthroughExtent.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/PassthroughExtent.java @@ -10,7 +10,6 @@ import com.sk89q.worldedit.extent.AbstractDelegateExtent; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.function.mask.Mask; -import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.Region; @@ -215,12 +214,6 @@ public class PassthroughExtent extends AbstractDelegateExtent { return getExtent().setBiome(position, biome); } - @Override - @Nullable - public Operation commit() { - return getExtent().commit(); - } - @Override public boolean cancel() { return getExtent().cancel(); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/PlacementStateProcessor.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/PlacementStateProcessor.java new file mode 100644 index 000000000..1ed94a53e --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/PlacementStateProcessor.java @@ -0,0 +1,462 @@ +package com.fastasyncworldedit.core.extent; + +import com.fastasyncworldedit.core.extent.filter.block.FilterBlock; +import com.fastasyncworldedit.core.extent.processor.ProcessorScope; +import com.fastasyncworldedit.core.function.mask.AdjacentAny2DMask; +import com.fastasyncworldedit.core.math.BlockVector3ChunkMap; +import com.fastasyncworldedit.core.math.MutableBlockVector3; +import com.fastasyncworldedit.core.math.MutableVector3; +import com.fastasyncworldedit.core.queue.IBatchProcessor; +import com.fastasyncworldedit.core.queue.IChunk; +import com.fastasyncworldedit.core.queue.IChunkGet; +import com.fastasyncworldedit.core.queue.IChunkSet; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.extent.AbstractDelegateExtent; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.extent.NullExtent; +import com.sk89q.worldedit.function.mask.BlockTypeMask; +import com.sk89q.worldedit.function.pattern.Pattern; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.math.Vector3; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.registry.state.Property; +import com.sk89q.worldedit.util.Direction; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockCategories; +import com.sk89q.worldedit.world.block.BlockCategory; +import com.sk89q.worldedit.world.block.BlockState; +import com.sk89q.worldedit.world.block.BlockTypes; +import com.sk89q.worldedit.world.block.BlockTypesCache; +import org.enginehub.linbus.tree.LinCompoundTag; + +import java.util.EnumSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.stream.Collectors; + +public abstract class PlacementStateProcessor extends AbstractDelegateExtent implements IBatchProcessor, Pattern { + + private static final Direction[] NESW = new Direction[]{Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST}; + private static final int CHUNK_BLOCK_POS_MASK = -1 << 4; + + private static volatile boolean SETUP = false; + private static BlockTypeMask DEFAULT_MASK = null; + private static BlockTypeMask REQUIRES_SECOND_PASS = null; + private static AdjacentAny2DMask ADJACENT_STAIR_MASK = null; + + protected final Extent extent; + protected final BlockTypeMask mask; + protected final Region region; + protected final Map postCompleteSecondPasses; + protected final ThreadLocal threadProcessors; + protected final AtomicBoolean finished; + private final MutableVector3 clickPos = new MutableVector3(); + private final MutableBlockVector3 clickedBlock = new MutableBlockVector3(); + + private IChunkGet processChunkGet = null; + private IChunkSet processChunkSet = null; + private int processChunkX; + private int processChunkZ; + + /** + * Process/extent/pattern for performing block updates, e.g. stair shape and glass pane connections + * + * @param extent Extent to use + * @param mask Mask of blocks to perform updates on + * @since TODO + */ + public PlacementStateProcessor(Extent extent, BlockTypeMask mask, Region region) { + super(extent); + // Required here as child classes are located within adapters and will therefore be statically accessed on startup, + // meaning we attempt to access BlockTypes class before it is correctly initialised. + if (!SETUP) { + synchronized (PlacementStateProcessor.class) { + if (!SETUP) { + setup(); + } + } + } + this.extent = extent; + this.mask = mask == null ? DEFAULT_MASK : mask; + this.region = region; + this.postCompleteSecondPasses = new ConcurrentHashMap<>(); + this.threadProcessors = ThreadLocal.withInitial(this::fork); + this.finished = new AtomicBoolean(); + } + + protected PlacementStateProcessor( + Extent extent, + BlockTypeMask mask, + Map crossChunkSecondPasses, + ThreadLocal threadProcessors, + Region region, + AtomicBoolean finished + ) { + super(extent); + this.extent = extent; + this.mask = mask; + this.region = region; + this.postCompleteSecondPasses = crossChunkSecondPasses; + this.threadProcessors = threadProcessors; + this.finished = finished; + } + + private static void setup() { + REQUIRES_SECOND_PASS = new BlockTypeMask(new NullExtent()); + REQUIRES_SECOND_PASS.add( + BlockTypes.IRON_BARS, + BlockTypes.GLASS_PANE, + BlockTypes.BLACK_STAINED_GLASS_PANE, + BlockTypes.BLUE_STAINED_GLASS_PANE, + BlockTypes.BROWN_STAINED_GLASS_PANE, + BlockTypes.LIGHT_BLUE_STAINED_GLASS_PANE, + BlockTypes.PINK_STAINED_GLASS_PANE, + BlockTypes.LIGHT_GRAY_STAINED_GLASS_PANE, + BlockTypes.GRAY_STAINED_GLASS_PANE, + BlockTypes.CYAN_STAINED_GLASS_PANE, + BlockTypes.PURPLE_STAINED_GLASS_PANE, + BlockTypes.GREEN_STAINED_GLASS_PANE, + BlockTypes.LIME_STAINED_GLASS_PANE, + BlockTypes.MAGENTA_STAINED_GLASS_PANE, + BlockTypes.YELLOW_STAINED_GLASS_PANE, + BlockTypes.ORANGE_STAINED_GLASS_PANE, + BlockTypes.RED_STAINED_GLASS_PANE, + BlockTypes.WHITE_STAINED_GLASS_PANE, + BlockTypes.TRIPWIRE, + BlockTypes.TWISTING_VINES_PLANT, + BlockTypes.CAVE_VINES_PLANT, + BlockTypes.WEEPING_VINES_PLANT, + BlockTypes.VINE, + BlockTypes.REDSTONE_WIRE + ); + BlockCategory[] categories = new BlockCategory[]{BlockCategories.FENCES, BlockCategories.FENCE_GATES, BlockCategories.WALLS, BlockCategories.CAVE_VINES}; + for (BlockCategory category : categories) { + if (category != null) { + REQUIRES_SECOND_PASS.add(category.getAll()); + } + } + + DEFAULT_MASK = REQUIRES_SECOND_PASS.copy(); + DEFAULT_MASK.add( + BlockTypes.CHORUS_PLANT, + BlockTypes.DRIPSTONE_BLOCK, + BlockTypes.POINTED_DRIPSTONE, + BlockTypes.BIG_DRIPLEAF, + BlockTypes.BIG_DRIPLEAF_STEM, + BlockTypes.CAMPFIRE, + BlockTypes.CHEST, + BlockTypes.TRAPPED_CHEST, + BlockTypes.CRAFTER, + BlockTypes.MUSHROOM_STEM, + BlockTypes.BROWN_MUSHROOM_BLOCK, + BlockTypes.RED_MUSHROOM_BLOCK + ); + categories = new BlockCategory[]{BlockCategories.STAIRS, BlockCategories.BAMBOO_BLOCKS, BlockCategories.TALL_FLOWERS}; + for (BlockCategory category : categories) { + if (category != null) { + DEFAULT_MASK.add(category.getAll()); + } + } + BlockTypeMask stairs = new BlockTypeMask(new NullExtent(), BlockCategories.STAIRS.getAll()); + ADJACENT_STAIR_MASK = new AdjacentAny2DMask(stairs, false); + SETUP = true; + } + + @Override + public IChunkSet processSet(IChunk iChunk, IChunkGet chunkGet, IChunkSet chunkSet) { + if (finished.get()) { + return chunkSet; + } + PlacementStateProcessor threadProcessor = threadProcessors.get(); + try { + threadProcessor.initProcess(iChunk, chunkGet, chunkSet); + return threadProcessor.process(); + } finally { + threadProcessor.uninit(); + } + } + + private void initProcess(IChunk iChunk, IChunkGet chunkGet, IChunkSet chunkSet) { + this.processChunkX = iChunk.getX() << 4; + this.processChunkZ = iChunk.getZ() << 4; + this.processChunkGet = chunkGet; + this.processChunkSet = chunkSet; + } + + private void uninit() { + this.processChunkGet = null; + this.processChunkSet = null; + } + + private IChunkSet process() { + Map setTiles = processChunkSet.getTiles(); + for (int layer = processChunkGet.getMinSectionPosition(); layer <= processChunkGet.getMaxSectionPosition(); layer++) { + int layerY = layer << 4; + char[] set = processChunkSet.loadIfPresent(layer); + if (set == null) { + continue; + } + for (int y = 0, i = 0; y < 16; y++, i += 256) { + int blockY = layerY + y; + checkAndPerformUpdate(setTiles, set, i, blockY, true); + checkAndPerformUpdate(setTiles, set, i, blockY, false); + } + } + return processChunkSet; + } + + private void checkAndPerformUpdate(Map setTiles, char[] set, int index, int blockY, boolean firstPass) { + for (int z = 0; z < 16; z++) { + int blockZ = processChunkZ + z; + for (int x = 0; x < 16; x++, index++) { + int blockX = processChunkX + x; + char ordinal = set[index]; + BlockState state = BlockTypesCache.states[ordinal]; + if (firstPass && !BlockCategories.STAIRS.contains(state)) { + continue; + } + if (!mask.test(state)) { + continue; + } + if (!firstPass && REQUIRES_SECOND_PASS.test(state)) { + postCompleteSecondPasses.put(new SecondPass( + blockX, + blockY, + blockZ, + setTiles.isEmpty() ? null : ((BlockVector3ChunkMap) setTiles).remove(x, blockY, z) + ), ordinal); + set[index] = BlockTypesCache.ReservedIDs.__RESERVED__; + continue; + } + char newOrdinal = getBlockOrdinal(blockX, blockY, blockZ, state); + if (newOrdinal == ordinal) { + continue; + } + set[index] = newOrdinal; + } + } + } + + @Override + public ProcessorScope getScope() { + return ProcessorScope.CHANGING_BLOCKS; + } + + @Override + public void finish() { + flush(); + } + + @Override + public void flush() { + finished.set(true); + for (Map.Entry entry : postCompleteSecondPasses.entrySet()) { + BlockState state; + char ordinal = entry.getValue(); + SecondPass secondPass = entry.getKey(); + if (ordinal != 0) { + state = BlockTypesCache.states[ordinal]; + } else { + state = extent.getBlock(secondPass.x, secondPass.y, secondPass.z); + } + char newOrdinal = getBlockOrdinal(secondPass.x, secondPass.y, secondPass.z, state); + if (newOrdinal == state.getOrdinalChar() && ordinal == 0) { + continue; + } + if (secondPass.tile != null) { + extent.setTile(secondPass.x, secondPass.y, secondPass.z, secondPass.tile); + } + extent.setBlock(secondPass.x, secondPass.y, secondPass.z, BlockTypesCache.states[newOrdinal]); + } + postCompleteSecondPasses.clear(); + } + + @Override + public abstract PlacementStateProcessor fork(); + + protected abstract char getStateAtFor( + int x, + int y, + int z, + BlockState state, + Vector3 clickPos, + Direction clickedFaceDirection, + BlockVector3 clickedBlock + ); + + public BlockState getBlockStateAt(int x, int y, int z) { + Character ord = postCompleteSecondPasses.get(new SecondPass(x, y, z, null)); + if (ord != null && ord != 0) { + return BlockTypesCache.states[ord]; + } + if (processChunkSet == null || (x & CHUNK_BLOCK_POS_MASK) != processChunkX || (z & CHUNK_BLOCK_POS_MASK) != processChunkZ) { + return extent.getBlock(x, y, z); + } + char[] set = processChunkSet.loadIfPresent(y >> 4); + if (set == null) { + return processChunkGet.getBlock(x & 15, y, z & 15); + } + char ordinal = set[(y & 15) << 8 | (z & 15) << 4 | (x & 15)]; + if (ordinal == BlockTypesCache.ReservedIDs.__RESERVED__) { + return processChunkGet.getBlock(x & 15, y, z & 15); + } + return BlockTypesCache.states[ordinal]; + } + + public CompoundTag getTileAt(int x, int y, int z) { + SecondPass secondPass = new SecondPass(x, y, z, null); + Character ord = postCompleteSecondPasses.get(secondPass); + if (ord != null && ord != 0) { + // This should be rare enough... + for (SecondPass pass : postCompleteSecondPasses.keySet()) { + if (pass.hashCode() == secondPass.hashCode()) { + return pass.tile != null ? pass.tile : BlockTypesCache.states[ord].getNbtData(); + } + } + return BlockTypesCache.states[ord].getNbtData(); + } + if (processChunkSet == null || (x & CHUNK_BLOCK_POS_MASK) != processChunkX || (z & CHUNK_BLOCK_POS_MASK) != processChunkZ) { + return extent.getFullBlock(x, y, z).getNbtData(); + } + CompoundTag tile = processChunkSet.getTile(x & 15, y, z & 15); + if (tile != null) { + return tile; + } + char[] set = processChunkSet.loadIfPresent(y >> 4); + if (set == null) { + return processChunkGet.getFullBlock(x & 15, y, z & 15).getNbtData(); + } + char ordinal = set[(y & 15) << 8 | (z & 15) << 4 | (x & 15)]; + if (ordinal == BlockTypesCache.ReservedIDs.__RESERVED__) { + return processChunkGet.getFullBlock(x & 15, y, z & 15).getNbtData(); + } + return BlockTypesCache.states[ordinal].getNbtData(); + } + + private char getBlockOrdinal(final int blockX, final int blockY, final int blockZ, final BlockState state) { + EnumSet dirs = Direction.getDirections(state); + Direction clickedFaceDirection = null; // This should be always be set by the below. + Set states = state.getStates().keySet().stream().map(Property::getName).collect(Collectors.toSet()); + if (dirs.isEmpty() || states.contains("NORTH") && states.contains("EAST")) { + clickPos.setComponents(blockX + 0.5d, blockY, blockZ + 0.5d); + clickedFaceDirection = Direction.UP; + clickedBlock.setComponents(blockX, blockY - 1, blockZ); + } else { + boolean hadNesw = false; + for (Direction dir : NESW) { + if (dirs.contains(dir)) { + clickedFaceDirection = dir.getLeft().getLeft(); // opposite + clickPos.setComponents( + (double) blockX + 0.5 * (1 + dir.getBlockX()), + (double) blockY + 0.2, + (double) blockZ + 0.5 * (1 + dir.getBlockZ()) + ); + clickedBlock.setComponents(blockX, blockY, blockZ).add(dir.toBlockVector()); + hadNesw = true; + break; + } + } + if (hadNesw) { + if (dirs.contains(Direction.UP)) { + clickPos.mutY(blockY + 0.5); + } + } else if (dirs.contains(Direction.UP)) { + clickedFaceDirection = Direction.DOWN; + clickPos.setComponents(blockX + 0.5d, blockY + 1d, blockZ + 0.5d); + clickedBlock.setComponents(blockX, blockY + 1, blockZ); + } else if (dirs.contains(Direction.DOWN)) { + clickedFaceDirection = Direction.UP; + clickPos.setComponents(blockX + 0.5d, blockY - 1d, blockZ + 0.5d); + clickedBlock.setComponents(blockX, blockY - 1, blockZ); + } + } + return getStateAtFor(blockX, blockY, blockZ, state, clickPos, clickedFaceDirection, clickedBlock); + } + + @Override + public void applyBlock(FilterBlock block) { + if (finished.get()) { + return; + } + BlockState state = BlockTypesCache.states[block.getOrdinal()]; + if (!mask.test(state)) { + return; + } + if (REQUIRES_SECOND_PASS.test(block.getBlock()) && ADJACENT_STAIR_MASK.test(extent, block)) { + postCompleteSecondPasses.put(new SecondPass(block), (char) 0); + } + char ordinal = (char) block.getOrdinal(); + char newOrdinal = getBlockOrdinal(block.x(), block.y(), block.z(), block.getBlock()); + if (ordinal != newOrdinal) { + block.setBlock(BlockTypesCache.states[newOrdinal]); + } + } + + @Override + public boolean apply(Extent orDefault, BlockVector3 get, BlockVector3 set) throws WorldEditException { + if (orDefault == null) { + orDefault = extent; + } + BaseBlock block = orDefault.getFullBlock(get); + if (!mask.test(block)) { + return false; + } + if (REQUIRES_SECOND_PASS.test(block) && ADJACENT_STAIR_MASK.test(extent, set)) { + postCompleteSecondPasses.put(new SecondPass(set), (char) 0); + return false; + } + char newOrdinal = getBlockOrdinal(set.x(), set.y(), set.z(), block.toBlockState()); + if (block.getOrdinalChar() != newOrdinal) { + BlockState newState = BlockTypesCache.states[newOrdinal]; + orDefault.setBlock(set.x(), set.y(), set.z(), newState); + LinCompoundTag nbt = block.getNbt(); + if (nbt != null && newState.getBlockType() == block.getBlockType()) { + orDefault.setTile(set.x(), set.y(), set.z(), new CompoundTag(nbt)); + } + return true; + } + return false; + } + + @Override + public BaseBlock applyBlock(BlockVector3 position) { + if (finished.get()) { + return null; + } + BaseBlock block = extent.getFullBlock(position); + if (!mask.test(block)) { + return null; + } + if (REQUIRES_SECOND_PASS.test(block) && ADJACENT_STAIR_MASK.test(extent, position)) { + postCompleteSecondPasses.put(new SecondPass(position), (char) 0); + return null; + } + char newOrdinal = getBlockOrdinal(position.x(), position.y(), position.z(), block.toBlockState()); + if (block.getOrdinalChar() != newOrdinal) { + BlockState state = BlockTypesCache.states[newOrdinal]; + LinCompoundTag nbt = block.getNbt(); + if (nbt != null && state.getBlockType() == block.getBlockType()) { + state.toBaseBlock(nbt); + } + return state.toBaseBlock(); + } + return null; + } + + protected record SecondPass(int x, int y, int z, CompoundTag tile) { + + private SecondPass(BlockVector3 pos) { + this(pos.x(), pos.y(), pos.z(), null); + } + + @Override + public int hashCode() { + return (x ^ (z << 12)) ^ (y << 24); + } + + } + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/PlacementStateProcessor.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/PlacementStateProcessor.java deleted file mode 100644 index aa857c65e..000000000 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/extent/processor/PlacementStateProcessor.java +++ /dev/null @@ -1,268 +0,0 @@ -package com.fastasyncworldedit.core.extent.processor; - -import com.fastasyncworldedit.core.extent.filter.block.FilterBlock; -import com.fastasyncworldedit.core.math.MutableBlockVector3; -import com.fastasyncworldedit.core.math.MutableVector3; -import com.fastasyncworldedit.core.queue.Filter; -import com.fastasyncworldedit.core.queue.IBatchProcessor; -import com.fastasyncworldedit.core.queue.IChunk; -import com.fastasyncworldedit.core.queue.IChunkGet; -import com.fastasyncworldedit.core.queue.IChunkSet; -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.jnbt.NBTUtils; -import com.sk89q.worldedit.WorldEditException; -import com.sk89q.worldedit.extent.AbstractDelegateExtent; -import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.extent.NullExtent; -import com.sk89q.worldedit.function.mask.BlockTypeMask; -import com.sk89q.worldedit.function.pattern.Pattern; -import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.math.Vector3; -import com.sk89q.worldedit.registry.state.Property; -import com.sk89q.worldedit.util.Direction; -import com.sk89q.worldedit.world.block.BaseBlock; -import com.sk89q.worldedit.world.block.BlockCategories; -import com.sk89q.worldedit.world.block.BlockCategory; -import com.sk89q.worldedit.world.block.BlockState; -import com.sk89q.worldedit.world.block.BlockTypes; -import com.sk89q.worldedit.world.block.BlockTypesCache; -import org.enginehub.linbus.tree.LinCompoundTag; - -import java.util.EnumSet; -import java.util.Set; -import java.util.stream.Collectors; - -public abstract class PlacementStateProcessor extends AbstractDelegateExtent implements IBatchProcessor, Filter, Pattern { - - private static final Direction[] NESW = new Direction[]{Direction.NORTH, Direction.EAST, Direction.SOUTH, Direction.WEST}; - private static volatile boolean SETUP = false; - private static BlockTypeMask DEFAULT_MASK = null; - - protected final Extent extent; - protected final BlockTypeMask mask; - protected final boolean includeUnedited; - private final MutableVector3 clickPos = new MutableVector3(); - private final MutableBlockVector3 clickedBlock = new MutableBlockVector3(); - - public PlacementStateProcessor(Extent extent, BlockTypeMask mask, boolean includeUnedited) { - super(extent); - // Required here as child classes are located within adapters and will therefore be statically accessed on startup, - // meaning we attempt to access BlockTypes class before it is correctly initialised. - if (!SETUP) { - synchronized (PlacementStateProcessor.class) { - if (!SETUP) { - setup(); - } - } - } - this.extent = extent; - this.mask = mask == null ? DEFAULT_MASK : mask; - this.includeUnedited = includeUnedited; - } - - private static void setup() { - DEFAULT_MASK = new BlockTypeMask(new NullExtent()); - DEFAULT_MASK.add( - BlockTypes.IRON_BARS, - BlockTypes.GLASS_PANE, - BlockTypes.BLACK_STAINED_GLASS_PANE, - BlockTypes.BLUE_STAINED_GLASS_PANE, - BlockTypes.BROWN_STAINED_GLASS_PANE, - BlockTypes.LIGHT_BLUE_STAINED_GLASS_PANE, - BlockTypes.PINK_STAINED_GLASS_PANE, - BlockTypes.LIGHT_GRAY_STAINED_GLASS_PANE, - BlockTypes.GRAY_STAINED_GLASS_PANE, - BlockTypes.CYAN_STAINED_GLASS_PANE, - BlockTypes.PURPLE_STAINED_GLASS_PANE, - BlockTypes.GREEN_STAINED_GLASS_PANE, - BlockTypes.LIME_STAINED_GLASS_PANE, - BlockTypes.MAGENTA_STAINED_GLASS_PANE, - BlockTypes.YELLOW_STAINED_GLASS_PANE, - BlockTypes.ORANGE_STAINED_GLASS_PANE, - BlockTypes.RED_STAINED_GLASS_PANE, - BlockTypes.WHITE_STAINED_GLASS_PANE, - BlockTypes.CHORUS_PLANT, - BlockTypes.DRIPSTONE_BLOCK, - BlockTypes.POINTED_DRIPSTONE, - BlockTypes.BIG_DRIPLEAF, - BlockTypes.BIG_DRIPLEAF_STEM, - BlockTypes.CAMPFIRE, - BlockTypes.CHEST, - BlockTypes.TRAPPED_CHEST, - BlockTypes.CRAFTER, - BlockTypes.MUSHROOM_STEM, - BlockTypes.BROWN_MUSHROOM_BLOCK, - BlockTypes.RED_MUSHROOM_BLOCK, - BlockTypes.TRIPWIRE, - BlockTypes.TWISTING_VINES_PLANT, - BlockTypes.CAVE_VINES_PLANT, - BlockTypes.WEEPING_VINES_PLANT, - BlockTypes.VINE, - BlockTypes.REDSTONE_WIRE - ); - BlockCategory[] categories = new BlockCategory[]{BlockCategories.FENCES, BlockCategories.FENCE_GATES, BlockCategories.STAIRS, BlockCategories.WALLS, BlockCategories.BAMBOO_BLOCKS, BlockCategories.CAVE_VINES, BlockCategories.TALL_FLOWERS}; - for (BlockCategory category : categories) { - if (category != null) { - DEFAULT_MASK.add(category.getAll()); - } - } - SETUP = true; - } - - @Override - public IChunkSet processSet(IChunk iChunk, IChunkGet iChunkGet, IChunkSet iChunkSet) { - int chunkX = iChunk.getX() << 4; - int chunkZ = iChunk.getZ() << 4; - for (int layer = iChunkGet.getMinSectionPosition(); layer <= iChunkGet.getMaxSectionPosition(); layer++) { - int layerY = layer << 4; - char[] set = iChunkSet.loadIfPresent(layer); - char[] get = null; - if (set == null) { - if (!includeUnedited) { - continue; - } - } - for (int y = 0, i = 0; y < 16; y++) { - int blockY = layerY + y; - for (int z = 0; z < 16; z++) { - int blockZ = chunkZ + z; - for (int x = 0; x < 16; x++, i++) { - int blockX = chunkX + x; - char ordinal = set == null ? BlockTypesCache.ReservedIDs.__RESERVED__ : set[i]; - if (ordinal == BlockTypesCache.ReservedIDs.__RESERVED__) { - if (!includeUnedited) { - continue; - } - if (get == null) { - get = iChunkGet.load(layer); - } - ordinal = get[i]; - } - BlockState state = BlockTypesCache.states[ordinal]; - if (!mask.test(state.getBlockType())) { - continue; - } - char newOrdinal = getBlockOrdinal(blockX, blockY, blockZ, state); - if (set == null) { - set = iChunkSet.load(layer); - } - set[i] = newOrdinal; - } - } - } - } - return iChunkSet; - } - - @Override - public ProcessorScope getScope() { - return ProcessorScope.CHANGING_BLOCKS; - } - - @Override - public abstract PlacementStateProcessor fork(); - - // Require block type to avoid duplicate lookup - protected abstract char getStateAtFor( - int x, int y, int z, BlockState state, Vector3 clickPos, Direction clickedFaceDirection, BlockVector3 clickedBlock - ); - - private char getBlockOrdinal( - final int blockX, - final int blockY, - final int blockZ, - final BlockState state - ) { - EnumSet dirs = Direction.getDirections(state); - Direction clickedFaceDirection = null; // This should be always be set by the below. - Set states = state.getStates().keySet().stream().map(Property::getName).collect(Collectors.toSet()); - if (dirs.isEmpty() || states.contains("NORTH") && states.contains("EAST")) { - clickPos.setComponents(blockX + 0.5d, blockY, blockZ + 0.5d); - clickedFaceDirection = Direction.UP; - clickedBlock.setComponents(blockX, blockY - 1, blockZ); - } else { - boolean hadNesw = false; - for (Direction dir : NESW) { - if (dirs.contains(dir)) { - clickedFaceDirection = dir.getLeft().getLeft(); // opposite - clickPos.setComponents( - (double) blockX + 0.5 * (1 + dir.getBlockX()), - (double) blockY + 0.2, - (double) blockZ + 0.5 * (1 + dir.getBlockZ()) - ); - clickedBlock.setComponents(blockX, blockY, blockZ).add(dir.toBlockVector()); - hadNesw = true; - break; - } - } - if (hadNesw) { - if (dirs.contains(Direction.UP)) { - clickPos.mutY(blockY + 0.5); - } - } else if (dirs.contains(Direction.UP)) { - clickedFaceDirection = Direction.DOWN; - clickPos.setComponents(blockX + 0.5d, blockY + 1d, blockZ + 0.5d); - clickedBlock.setComponents(blockX, blockY + 1, blockZ); - } else if (dirs.contains(Direction.DOWN)) { - clickedFaceDirection = Direction.UP; - clickPos.setComponents(blockX + 0.5d, blockY - 1d, blockZ + 0.5d); - clickedBlock.setComponents(blockX, blockY - 1, blockZ); - } - } - return getStateAtFor(blockX, blockY, blockZ, state, clickPos, clickedFaceDirection, clickedBlock); - } - - @Override - public void applyBlock(FilterBlock block) { - BlockState state = BlockTypesCache.states[block.getOrdinal()]; - if (!mask.test(state.getBlockType())) { - return; - } - char ordinal = (char) block.getOrdinal(); - char newOrdinal = getBlockOrdinal(block.x(), block.y(), block.z(), block.getBlock()); - if (ordinal != newOrdinal) { - block.setBlock(BlockTypesCache.states[newOrdinal]); - } - } - - @Override - public boolean apply(Extent orDefault, BlockVector3 get, BlockVector3 set) throws WorldEditException { - if (orDefault == null) { - orDefault = extent; - } - BaseBlock block = orDefault.getFullBlock(get); - if (!mask.test(block.getBlockType())) { - return false; - } - char newOrdinal = getBlockOrdinal(set.x(), set.y(), set.z(), block.toBlockState()); - if (block.getOrdinalChar() != newOrdinal) { - BlockState newState = BlockTypesCache.states[newOrdinal]; - orDefault.setBlock(set, newState); - LinCompoundTag nbt = block.getNbt(); - if (nbt != null && newState.getBlockType() == block.getBlockType()) { - orDefault.setTile(set.x(), set.y(), set.z(), new CompoundTag(nbt)); - } - return true; - } - return false; - } - - @Override - public BaseBlock applyBlock(final BlockVector3 position) { - BaseBlock block = extent.getFullBlock(position); - if (!mask.test(block.getBlockType())) { - return null; - } - char newOrdinal = getBlockOrdinal(position.x(), position.y(), position.z(), block.toBlockState()); - if (block.getOrdinalChar() != newOrdinal) { - BlockState state = BlockTypesCache.states[newOrdinal]; - LinCompoundTag nbt = block.getNbt(); - if (nbt != null && state.getBlockType() == block.getBlockType()) { - return state.toBaseBlock(nbt); - } - return state.toBaseBlock(); - } - return null; - } - -} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/Adjacent2DMask.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/Adjacent2DMask.java new file mode 100644 index 000000000..853362f7a --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/Adjacent2DMask.java @@ -0,0 +1,53 @@ +package com.fastasyncworldedit.core.function.mask; + +import com.fastasyncworldedit.core.math.MutableBlockVector3; +import com.sk89q.worldedit.function.mask.AbstractMask; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.math.BlockVector3; + +public class Adjacent2DMask extends AbstractMask { + + private final int min; + private final int max; + private final Mask mask; + private final MutableBlockVector3 vector; + + public Adjacent2DMask(Mask mask, int requiredMin, int requiredMax) { + this.mask = mask; + this.min = requiredMin; + this.max = requiredMax; + this.vector = new MutableBlockVector3(); + } + + @Override + public boolean test(BlockVector3 bv) { + vector.setComponents(bv); + double x = bv.x(); + double z = bv.z(); + vector.mutX(x + 1); + int count = 0; + if (mask.test(vector) && ++count == min && max >= 4) { + return true; + } + vector.mutX(x - 1); + if (mask.test(vector) && ++count == min && max >= 4) { + return true; + } + vector.mutX(x); + vector.mutZ(z + 1); + if (mask.test(vector) && ++count == min && max >= 4) { + return true; + } + vector.mutZ(z - 1); + if (mask.test(vector) && ++count == min && max >= 4) { + return true; + } + return count >= min && count <= max; + } + + @Override + public Mask copy() { + return new Adjacent2DMask(mask.copy(), min, max); + } + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/AdjacentAny2DMask.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/AdjacentAny2DMask.java new file mode 100644 index 000000000..d40b413c7 --- /dev/null +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/AdjacentAny2DMask.java @@ -0,0 +1,66 @@ +package com.fastasyncworldedit.core.function.mask; + +import com.fastasyncworldedit.core.math.MutableBlockVector3; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.function.mask.AbstractExtentMask; +import com.sk89q.worldedit.function.mask.AbstractMask; +import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.math.BlockVector3; + +/** + * Just an optimized version of the Adjacent Mask for single adjacency. + */ +public class AdjacentAny2DMask extends AbstractMask { + + private final Mask mask; + private final MutableBlockVector3 mutable; + + public AdjacentAny2DMask(Mask mask) { + this(mask, true); + } + + public AdjacentAny2DMask(Mask mask, boolean cache) { + this.mask = cache ? CachedMask.cache(mask) : mask; + mutable = new MutableBlockVector3(); + } + + @Override + public boolean test(BlockVector3 v) { + int x = v.x(); + int y = v.y(); + int z = v.z(); + if (mask.test(mutable.setComponents(x + 1, y, z))) { + return true; + } + if (mask.test(mutable.setComponents(x - 1, y, z))) { + return true; + } + if (mask.test(mutable.setComponents(x, y, z + 1))) { + return true; + } + return mask.test(mutable.setComponents(x, y, z - 1)); + } + + public boolean test(Extent extent, BlockVector3 v) { + AbstractExtentMask extentMask = (AbstractExtentMask) mask; + int x = v.x(); + int y = v.y(); + int z = v.z(); + if (extentMask.test(extent, mutable.setComponents(x + 1, y, z))) { + return true; + } + if (extentMask.test(extent, mutable.setComponents(x - 1, y, z))) { + return true; + } + if (extentMask.test(extent, mutable.setComponents(x, y, z + 1))) { + return true; + } + return extentMask.test(extent, mutable.setComponents(x, y, z - 1)); + } + + @Override + public Mask copy() { + return new AdjacentAny2DMask(mask.copy(), false); + } + +} diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/AdjacentAnyMask.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/AdjacentAnyMask.java index 956daf67d..cc57be2bb 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/AdjacentAnyMask.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/function/mask/AdjacentAnyMask.java @@ -23,7 +23,7 @@ public class AdjacentAnyMask extends AbstractMask implements ResettableMask { } AdjacentAnyMask(CachedMask mask, int minY, int maxY) { - this.mask = CachedMask.cache(mask); + this.mask = mask; mutable = new MutableBlockVector3(); this.minY = minY; this.maxY = maxY; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/FaweStreamChangeSet.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/FaweStreamChangeSet.java index e50030d21..388844c24 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/FaweStreamChangeSet.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/history/changeset/FaweStreamChangeSet.java @@ -461,7 +461,6 @@ public abstract class FaweStreamChangeSet extends AbstractChangeSet { } catch (EOFException ignored) { } catch (Exception e) { e.printStackTrace(); - e.printStackTrace(); } try { is.close(); 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 f308d4806..ab277ded4 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 @@ -62,4 +62,13 @@ public interface Filter { } + /** + * Signals to the filter the edit has concluded + * + * @since TODO + */ + default void finish() { + + } + } diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkSet.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkSet.java index fc1482d6e..da6ea03e5 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkSet.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/IChunkSet.java @@ -7,6 +7,7 @@ import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extent.OutputExtent; import com.sk89q.worldedit.function.operation.Operation; import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.util.SideEffectSet; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BlockStateHolder; @@ -139,4 +140,19 @@ public interface IChunkSet extends IBlocks, OutputExtent { return this; } + /** + * Set the side effects to be used when settings these blocks + * + * @since TODO + */ + void setSideEffectSet(@Nonnull SideEffectSet sideEffectSet); + + /** + * Get the side effects to be used when settings these blocks + * + * @since TODO + */ + @Nonnull + SideEffectSet getSideEffectSet(); + } 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 1e172dd19..8d309ed58 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 @@ -38,6 +38,11 @@ public interface IDelegateFilter extends Filter { return this; } + @Override + default void finish() { + getParent().finish(); + } + Filter newInstance(Filter other); } 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 d09b7f04b..e1714f039 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 @@ -10,6 +10,7 @@ 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 javax.annotation.Nullable; import java.io.Flushable; @@ -81,6 +82,20 @@ public interface IQueueExtent extends Flushable, Trimable, ICh boolean isFastMode(); + /** + * Set the side effects to be used with this extent + * + * @since TODO + */ + void setSideEffectSet(SideEffectSet sideEffectSet); + + /** + * Get the side effects to be used with this extent + * + * @since TODO + */ + SideEffectSet getSideEffectSet(); + /** * Create a new root IChunk object. Full chunks will be reused, so a more optimized chunk can be * returned in that case. 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 56a238166..e166ca235 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 @@ -20,11 +20,14 @@ import com.fastasyncworldedit.core.queue.Filter; import com.fastasyncworldedit.core.queue.IQueueChunk; import com.fastasyncworldedit.core.queue.IQueueExtent; import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.function.mask.BlockMask; import com.sk89q.worldedit.function.mask.ExistingBlockMask; import com.sk89q.worldedit.function.mask.Mask; +import com.sk89q.worldedit.function.operation.Operation; +import com.sk89q.worldedit.function.operation.RunContext; import com.sk89q.worldedit.function.pattern.BlockPattern; import com.sk89q.worldedit.function.pattern.Pattern; import com.sk89q.worldedit.internal.util.LogManagerCompat; @@ -32,6 +35,7 @@ import com.sk89q.worldedit.math.BlockVector2; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.util.Countable; +import com.sk89q.worldedit.util.SideEffectSet; import com.sk89q.worldedit.world.World; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockState; @@ -39,6 +43,7 @@ import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; import org.apache.logging.log4j.Logger; +import javax.annotation.Nullable; import java.util.Iterator; import java.util.List; import java.util.Set; @@ -58,11 +63,12 @@ public class ParallelQueueExtent extends PassthroughExtent { // not very important) private final boolean[] faweExceptionReasonsUsed = new boolean[FaweException.Type.values().length]; private final boolean fastmode; + private final SideEffectSet sideEffectSet; private int changes; private int lastException = Integer.MIN_VALUE; private int exceptionCount = 0; - public ParallelQueueExtent(QueueHandler handler, World world, boolean fastmode) { + public ParallelQueueExtent(QueueHandler handler, World world, boolean fastmode, @Nullable SideEffectSet sideEffectSet) { super(handler.getQueue(world, new BatchProcessorHolder(), new BatchProcessorHolder())); this.world = world; this.handler = handler; @@ -75,6 +81,7 @@ public class ParallelQueueExtent extends PassthroughExtent { ((MultiBatchProcessor) this.postProcessor.getProcessor()).setFaweExceptionArray(faweExceptionReasonsUsed); } this.fastmode = fastmode; + this.sideEffectSet = sideEffectSet == null ? SideEffectSet.defaults() : sideEffectSet; } /** @@ -121,7 +128,12 @@ public class ParallelQueueExtent extends PassthroughExtent { @SuppressWarnings("rawtypes") private IQueueExtent getNewQueue() { - return handler.getQueue(world, this.processor, this.postProcessor); + SingleThreadQueueExtent queue = (SingleThreadQueueExtent) handler.getQueue(world, this.processor, this.postProcessor); + queue.setFastMode(fastmode); + queue.setSideEffectSet(sideEffectSet); + queue.setFaweExceptionArray(faweExceptionReasonsUsed); + enter(queue); + return queue; } @Override @@ -140,6 +152,8 @@ public class ParallelQueueExtent extends PassthroughExtent { BlockVector2 pos = chunksIter.next(); block = getExtent().apply(block, filter, region, pos.x(), pos.z(), full); } + getExtent().flush(); + filter.finish(); } else { final ForkJoinTask[] tasks = IntStream.range(0, size).mapToObj(i -> handler.submit(() -> { try { @@ -147,13 +161,9 @@ public class ParallelQueueExtent extends PassthroughExtent { final Region newRegion = region.clone(); // Create a chunk that we will reuse/reset for each operation final SingleThreadQueueExtent queue = (SingleThreadQueueExtent) getNewQueue(); - queue.setFastMode(fastmode); - queue.setFaweExceptionArray(faweExceptionReasonsUsed); - enter(queue); synchronized (queue) { try { ChunkFilterBlock block = null; - while (true) { // Get the next chunk posWeakChunk final int chunkX; @@ -169,6 +179,7 @@ public class ParallelQueueExtent extends PassthroughExtent { block = queue.apply(block, newFilter, newRegion, chunkX, chunkZ, full); } queue.flush(); + filter.finish(); } catch (Throwable t) { if (t instanceof FaweException) { Fawe.handleFaweException(faweExceptionReasonsUsed, (FaweException) t, LOGGER); @@ -205,6 +216,24 @@ public class ParallelQueueExtent extends PassthroughExtent { return filter; } + @Override + protected Operation commitBefore() { + return new Operation() { + @Override + public Operation resume(final RunContext run) throws WorldEditException { + getExtent().commit(); + processor.flush(); + getExtent().flush(); + return null; + } + + @Override + public void cancel() { + + } + }; + } + @Override public int countBlocks(Region region, Mask searchMask) { return 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 b0239a5a3..389f0d66e 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 @@ -27,6 +27,7 @@ import com.sk89q.worldedit.internal.util.LogManagerCompat; 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.World; import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap; import org.apache.logging.log4j.Logger; @@ -68,6 +69,7 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen private boolean[] faweExceptionReasonsUsed = new boolean[FaweException.Type.values().length]; private int lastException = Integer.MIN_VALUE; private int exceptionCount = 0; + private SideEffectSet sideEffectSet = SideEffectSet.defaults(); public SingleThreadQueueExtent() { } @@ -110,6 +112,16 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen this.fastmode = fastmode; } + @Override + public void setSideEffectSet(SideEffectSet sideEffectSet) { + this.sideEffectSet = sideEffectSet; + } + + @Override + public SideEffectSet getSideEffectSet() { + return sideEffectSet; + } + @Override public int getMinY() { return minY; @@ -120,6 +132,10 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen return maxY; } + public World getWorld() { + return world; + } + /** * Sets the cached boolean array of length {@code FaweException.Type.values().length} that determines if a thrown * {@link FaweException} of type {@link FaweException.Type} should be output to console, rethrown to attempt to be visible @@ -278,10 +294,16 @@ public class SingleThreadQueueExtent extends ExtentBatchProcessorHolder implemen private ChunkHolder poolOrCreate(int chunkX, int chunkZ) { ChunkHolder next = create(false); next.init(this, chunkX, chunkZ); - next.setFastMode(isFastMode()); return next; } + @Override + public IQueueChunk wrap(IQueueChunk chunk) { + chunk.setFastMode(isFastMode()); + chunk.setSideEffectSet(getSideEffectSet()); + return chunk; + } + @Override public final IQueueChunk getOrCreateChunk(int x, int z) { getChunkLock.lock(); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/BitSetBlocks.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/BitSetBlocks.java index 76f2191ed..0ace5150a 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/BitSetBlocks.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/BitSetBlocks.java @@ -6,6 +6,7 @@ import com.fastasyncworldedit.core.nbt.FaweCompoundTag; import com.fastasyncworldedit.core.queue.IChunkSet; import com.fastasyncworldedit.core.util.collection.MemBlockSet; import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.util.SideEffectSet; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; @@ -212,6 +213,16 @@ public class BitSetBlocks implements IChunkSet { return false; } + @Override + public void setSideEffectSet(SideEffectSet sideEffectSet) { + + } + + @Override + public SideEffectSet getSideEffectSet() { + return SideEffectSet.none(); + } + @Override public int getSectionCount() { return layers; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/CharSetBlocks.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/CharSetBlocks.java index 8d7c059ed..c08271d97 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/CharSetBlocks.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/CharSetBlocks.java @@ -9,6 +9,7 @@ import com.fastasyncworldedit.core.queue.IChunkSet; import com.fastasyncworldedit.core.queue.Pool; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.util.SideEffectSet; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockTypesCache; @@ -44,6 +45,7 @@ public class CharSetBlocks extends CharBlocks implements IChunkSet { public EnumMap heightMaps; private boolean fastMode = false; private int bitMask = -1; + private SideEffectSet sideEffectSet = SideEffectSet.defaults(); private CharSetBlocks() { // Expand as we go @@ -374,10 +376,21 @@ public class CharSetBlocks extends CharBlocks implements IChunkSet { heightMaps != null ? new EnumMap<>(heightMaps) : null, defaultOrdinal(), fastMode, - bitMask + bitMask, + sideEffectSet ); } + @Override + public void setSideEffectSet(SideEffectSet sideEffectSet) { + this.sideEffectSet = sideEffectSet; + } + + @Override + public SideEffectSet getSideEffectSet() { + return sideEffectSet; + } + static char[][] createLightCopy(char[][] lightArr, int sectionCount) { if (lightArr == null) { return null; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/ThreadUnsafeCharBlocks.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/ThreadUnsafeCharBlocks.java index c21e932a9..c36dcbeef 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/ThreadUnsafeCharBlocks.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/queue/implementation/blocks/ThreadUnsafeCharBlocks.java @@ -9,6 +9,7 @@ import com.fastasyncworldedit.core.queue.IBlocks; import com.fastasyncworldedit.core.queue.IChunkSet; import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.util.SideEffectSet; import com.sk89q.worldedit.world.biome.BiomeType; import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; @@ -51,6 +52,7 @@ public class ThreadUnsafeCharBlocks implements IChunkSet, IBlocks { private Map heightMaps; private boolean fastMode; private int bitMask; + private SideEffectSet sideEffectSet; /** * New instance given the data stored in a {@link CharSetBlocks} instance. @@ -71,7 +73,8 @@ public class ThreadUnsafeCharBlocks implements IChunkSet, IBlocks { Map heightMaps, char defaultOrdinal, boolean fastMode, - int bitMask + int bitMask, + SideEffectSet sideEffectSet ) { this.blocks = blocks; this.minSectionPosition = minSectionPosition; @@ -87,6 +90,7 @@ public class ThreadUnsafeCharBlocks implements IChunkSet, IBlocks { this.defaultOrdinal = defaultOrdinal; this.fastMode = fastMode; this.bitMask = bitMask; + this.sideEffectSet = sideEffectSet; } @Override @@ -480,10 +484,21 @@ public class ThreadUnsafeCharBlocks implements IChunkSet, IBlocks { heightMaps != null ? new HashMap<>(heightMaps) : null, defaultOrdinal, fastMode, - bitMask + bitMask, + sideEffectSet ); } + @Override + public void setSideEffectSet(SideEffectSet sideEffectSet) { + this.sideEffectSet = sideEffectSet; + } + + @Override + public SideEffectSet getSideEffectSet() { + return sideEffectSet; + } + @Override public boolean trim(boolean aggressive) { return false; 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 7c36eb94c..1ec0e26a0 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 @@ -15,6 +15,7 @@ import com.fastasyncworldedit.core.util.MemUtil; import com.sk89q.worldedit.internal.util.LogManagerCompat; 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; @@ -51,6 +52,7 @@ public class ChunkHolder> implements IQueueChunk { private boolean isInit = false; // Lighting handles queue differently. It relies on the chunk cache and not doing init. private boolean createCopy = false; private long initTime = -1L; + private SideEffectSet sideEffectSet; private ChunkHolder() { this.delegate = NULL; @@ -150,6 +152,16 @@ public class ChunkHolder> implements IQueueChunk { return chunkSet != null && chunkSet.hasBiomes(layer); } + @Override + public void setSideEffectSet(SideEffectSet sideEffectSet) { + this.sideEffectSet = sideEffectSet; + } + + @Override + public SideEffectSet getSideEffectSet() { + return sideEffectSet; + } + public boolean isInit() { return isInit; } @@ -874,7 +886,6 @@ public class ChunkHolder> implements IQueueChunk { public synchronized void filterBlocks(Filter filter, ChunkFilterBlock block, @Nullable Region region, boolean full) { final IChunkGet get = getOrCreateGet(); final IChunkSet set = getOrCreateSet(); - set.setFastMode(fastmode); try { block.filter(this, get, set, filter, region, full); } finally { @@ -948,13 +959,21 @@ public class ChunkHolder> implements IQueueChunk { return chunkSet; } + public final IChunkSet getChunkSet() { + return chunkSet; + } + /** * Create a wrapped set object * - The purpose of wrapping is to allow different extents to intercept / alter behavior * - e.g., caching, optimizations, filtering */ private IChunkSet newWrappedSet() { - return extent.getCachedSet(chunkX, chunkZ); + IChunkSet set = extent.getCachedSet(chunkX, chunkZ); + set.setFastMode(fastmode); + set.setSideEffectSet(sideEffectSet); + set.setBitMask(bitMask); + return set; } /** @@ -985,7 +1004,6 @@ public class ChunkHolder> implements IQueueChunk { @Override public synchronized T call() { if (chunkSet != null && !chunkSet.isEmpty()) { - chunkSet.setBitMask(bitMask); IChunkSet copy = chunkSet.createCopy(); return this.call(copy, () -> { // Do nothing 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 14107e83a..770a878a9 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 @@ -8,6 +8,7 @@ import com.fastasyncworldedit.core.queue.IChunkSet; import com.fastasyncworldedit.core.queue.IQueueChunk; 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; @@ -86,6 +87,16 @@ public final class NullChunk implements IQueueChunk { return false; } + @Override + public void setSideEffectSet(SideEffectSet sideEffectSet) { + + } + + @Override + public SideEffectSet getSideEffectSet() { + return SideEffectSet.none(); + } + @Nonnull public int[] getHeightMap(@Nullable HeightMapType type) { return new int[256]; diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/ExtentTraverser.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/ExtentTraverser.java index 6ae147765..e1a106979 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/ExtentTraverser.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/ExtentTraverser.java @@ -1,7 +1,11 @@ package com.fastasyncworldedit.core.util; +import com.fastasyncworldedit.core.queue.implementation.ParallelQueueExtent; +import com.fastasyncworldedit.core.queue.implementation.SingleThreadQueueExtent; +import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.extent.AbstractDelegateExtent; import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.world.World; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -21,6 +25,26 @@ public class ExtentTraverser { this.parent = parent; } + /** + * Get the world backing the given extent, if present, else null. + * + * @since TODO + */ + @Nullable + public static World getWorldFromExtent(Extent extent) { + if (extent.isWorld()) { + return (World) extent; + } else if (extent instanceof EditSession session) { + return session.getWorld(); + } else if (extent instanceof SingleThreadQueueExtent stqe) { + return stqe.getWorld(); + } else if (extent instanceof ParallelQueueExtent pqe) { + return ((SingleThreadQueueExtent) pqe.getExtent()).getWorld(); + } else { + return new ExtentTraverser<>(extent).findAndGet(World.class); + } + } + public boolean exists() { return root != null; } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSessionBuilder.java b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSessionBuilder.java index 26650bf9c..4efb73ab8 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSessionBuilder.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSessionBuilder.java @@ -64,7 +64,10 @@ import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.inventory.BlockBag; import com.sk89q.worldedit.internal.util.LogManagerCompat; import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.regions.RegionIntersection; import com.sk89q.worldedit.util.Identifiable; +import com.sk89q.worldedit.util.SideEffect; +import com.sk89q.worldedit.util.SideEffectSet; import com.sk89q.worldedit.util.eventbus.EventBus; import com.sk89q.worldedit.util.formatting.text.Component; import com.sk89q.worldedit.util.formatting.text.TextComponent; @@ -104,6 +107,7 @@ public final class EditSessionBuilder { private Extent extent; private boolean compiled; private boolean wrapped; + private SideEffectSet sideEffectSet = SideEffectSet.defaults(); private @Nullable World world; @@ -415,6 +419,14 @@ public final class EditSessionBuilder { return setDirty(); } + /** + * Set the side effects to be used with this edit + */ + public EditSessionBuilder setSideEffectSet(@Nullable SideEffectSet sideEffectSet) { + this.sideEffectSet = sideEffectSet; + return setDirty(); + } + /** * Compile the builder to the settings given. Prepares history, limits, lighting, etc. */ @@ -445,6 +457,9 @@ public final class EditSessionBuilder { fastMode = actor.getSession().hasFastMode(); } } + if (fastMode) { + sideEffectSet = SideEffectSet.none(); + } if (checkMemory == null) { checkMemory = actor != null && !this.fastMode; } @@ -470,7 +485,12 @@ public final class EditSessionBuilder { if (unwrapped instanceof IQueueExtent) { extent = queue = (IQueueExtent) unwrapped; } else if (Settings.settings().QUEUE.PARALLEL_THREADS > 1 && !Fawe.isMainThread()) { - ParallelQueueExtent parallel = new ParallelQueueExtent(Fawe.instance().getQueueHandler(), world, fastMode); + ParallelQueueExtent parallel = new ParallelQueueExtent( + Fawe.instance().getQueueHandler(), + world, + fastMode, + sideEffectSet + ); queue = parallel.getExtent(); extent = parallel; } else { @@ -491,7 +511,7 @@ public final class EditSessionBuilder { } extent = this.bypassAll = wrapExtent(extent, eventBus, event, EditSession.Stage.BEFORE_CHANGE); this.bypassHistory = this.extent = wrapExtent(bypassAll, eventBus, event, EditSession.Stage.BEFORE_REORDER); - if (!this.fastMode || changeSet != null) { + if (!this.fastMode || this.sideEffectSet.shouldApply(SideEffect.HISTORY) || changeSet != null) { if (changeSet == null) { if (Settings.settings().HISTORY.USE_DISK) { UUID uuid = actor == null ? Identifiable.CONSOLE : actor.getUniqueId(); @@ -546,13 +566,29 @@ public final class EditSessionBuilder { } // There's no need to do the below (and it'll also just be a pain to implement) if we're not placing chunks if (placeChunks) { - if (((relightMode != null && relightMode != RelightMode.NONE) || (relightMode == null && Settings.settings().LIGHTING.MODE > 0))) { - relighter = WorldEdit.getInstance().getPlatformManager() + if (this.sideEffectSet.shouldApply(SideEffect.LIGHTING) || (relightMode != null && relightMode != RelightMode.NONE)) { + relighter = WorldEdit + .getInstance() + .getPlatformManager() .queryCapability(Capability.WORLD_EDITING) - .getRelighterFactory().createRelighter(relightMode, world, queue); + .getRelighterFactory() + .createRelighter(relightMode, world, queue); queue.addProcessor(new RelightProcessor(relighter)); } - queue.addProcessor(new HeightmapProcessor(world.getMinY(), world.getMaxY())); + if (this.sideEffectSet.shouldApply(SideEffect.HEIGHTMAPS)) { + queue.addProcessor(new HeightmapProcessor(world.getMinY(), world.getMaxY())); + } + if (this.sideEffectSet.shouldApply(SideEffect.UPDATE) || this.sideEffectSet.shouldApply(SideEffect.NEIGHBORS) || this.sideEffectSet.shouldApply( + SideEffect.VALIDATION)) { + Region region = allowedRegions == null || allowedRegions.length == 0 + ? null + : allowedRegions.length == 1 ? allowedRegions[0] : new RegionIntersection(allowedRegions); + queue.addProcessor(WorldEdit + .getInstance() + .getPlatformManager() + .queryCapability(Capability.WORLD_EDITING) + .getPlatformPlacementProcessor(extent, null, region)); + } if (!Settings.settings().EXPERIMENTAL.KEEP_ENTITIES_IN_BLOCKS) { queue.addProcessor(new EntityInBlockRemovingProcessor()); @@ -714,6 +750,13 @@ public final class EditSessionBuilder { return changeSet; } + /** + * Get the SideEffectSet that will be used + */ + public SideEffectSet getSideEffectSet() { + return sideEffectSet; + } + /** * Get the ultimate resultant extent */ diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java index 51a03119f..438d726c4 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/LocalSession.java @@ -1749,6 +1749,7 @@ public class LocalSession implements TextureHolder { } builder.command(command); builder.fastMode(!this.sideEffectSet.doesApplyAny()); + builder.setSideEffectSet(this.sideEffectSet); editSession = builder.build(); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java b/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java index d371ee6a0..2aaca8fe3 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/command/RegionCommands.java @@ -118,7 +118,7 @@ public class RegionCommands { Actor actor, EditSession editSession, @Selection Region region, @Arg(desc = "The pattern of blocks to set") - Pattern pattern + Pattern pattern ) { int affected = editSession.setBlocks(region, pattern); if (affected != 0) { @@ -233,11 +233,11 @@ public class RegionCommands { Actor actor, EditSession editSession, @Selection Region region, @Arg(desc = "The pattern of blocks to place") - Pattern pattern, + Pattern pattern, @Arg(desc = "The thickness of the line", def = "0") - int thickness, + int thickness, @Switch(name = 'h', desc = "Generate only a shell") - boolean shell + boolean shell ) throws WorldEditException { if (!(region instanceof CuboidRegion cuboidregion)) { actor.print(Caption.of("worldedit.line.cuboid-only")); @@ -266,11 +266,11 @@ public class RegionCommands { Actor actor, EditSession editSession, @Selection Region region, @Arg(desc = "The pattern of blocks to place") - Pattern pattern, + Pattern pattern, @Arg(desc = "The thickness of the curve", def = "0") - int thickness, + int thickness, @Switch(name = 'h', desc = "Generate only a shell") - boolean shell + boolean shell ) throws WorldEditException { if (!(region instanceof ConvexPolyhedralRegion cpregion)) { actor.print(Caption.of("worldedit.curve.invalid-type")); @@ -298,9 +298,9 @@ public class RegionCommands { public int replace( Actor actor, EditSession editSession, @Selection Region region, @Arg(desc = "The mask representing blocks to replace", def = "") - Mask from, + Mask from, @Arg(desc = "The pattern of blocks to replace with") - Pattern to + Pattern to ) throws WorldEditException { if (from == null) { from = new ExistingBlockMask(editSession); @@ -324,7 +324,7 @@ public class RegionCommands { public int overlay( Actor actor, EditSession editSession, @Selection Region region, @Arg(desc = "The pattern of blocks to overlay") - Pattern pattern + Pattern pattern ) throws WorldEditException { int affected = editSession.overlayCuboidBlocks(region, pattern); actor.print(Caption.of("worldedit.overlay.overlaid", TextComponent.of(affected))); @@ -380,7 +380,7 @@ public class RegionCommands { public int center( Actor actor, EditSession editSession, @Selection Region region, @Arg(desc = "The pattern of blocks to set") - Pattern pattern + Pattern pattern ) throws WorldEditException { int affected = editSession.center(region, pattern); actor.print(Caption.of("worldedit.center.changed", TextComponent.of(affected))); @@ -412,7 +412,7 @@ public class RegionCommands { public int walls( Actor actor, EditSession editSession, @Selection Region region, @Arg(desc = "The pattern of blocks to set") - Pattern pattern + Pattern pattern ) throws WorldEditException { int affected = editSession.makeWalls(region, pattern); actor.print(Caption.of("worldedit.walls.changed", TextComponent.of(affected))); @@ -431,7 +431,7 @@ public class RegionCommands { public int faces( Actor actor, EditSession editSession, @Selection Region region, @Arg(desc = "The pattern of blocks to set") - Pattern pattern + Pattern pattern ) throws WorldEditException { int affected = editSession.makeFaces(region, pattern); actor.print(Caption.of("worldedit.faces.changed", TextComponent.of(affected))); @@ -451,9 +451,9 @@ public class RegionCommands { public int smooth( Actor actor, EditSession editSession, @Selection Region region, @Arg(desc = "# of iterations to perform", def = "1") - int iterations, + int iterations, @Arg(desc = "The mask of blocks to use as the height map", def = "") - Mask mask + Mask mask ) throws WorldEditException { //FAWE start > the mask will have been initialised with a WorldWrapper extent (very bad/slow) new MaskTraverser(mask).setNewExtent(editSession); @@ -526,11 +526,11 @@ public class RegionCommands { public int snowSmooth( Actor actor, EditSession editSession, @Selection Region region, @Arg(desc = "# of iterations to perform", def = "1") - int iterations, + int iterations, @ArgFlag(name = 'l', desc = "Set the amount of snow blocks under the snow", def = "1") - int snowBlockCount, + int snowBlockCount, @ArgFlag(name = 'm', desc = "The mask of blocks to use as the height map") - Mask mask + Mask mask ) throws WorldEditException { SnowHeightMap heightMap = new SnowHeightMap(editSession, region, mask); HeightMapFilter filter = new HeightMapFilter(new GaussianKernel(5, 1.0)); @@ -554,22 +554,22 @@ public class RegionCommands { Actor actor, World world, EditSession editSession, LocalSession session, @Selection Region region, @Arg(desc = "# of blocks to move", def = "1") - int count, + int count, @Arg(desc = "The direction to move", def = Direction.AIM) @Direction(includeDiagonals = true) - BlockVector3 direction, + BlockVector3 direction, @Arg(desc = "The pattern of blocks to leave", def = "air") - Pattern replace, + Pattern replace, @Switch(name = 's', desc = "Shift the selection to the target location") - boolean moveSelection, + boolean moveSelection, @Switch(name = 'a', desc = "Ignore air blocks") - boolean ignoreAirBlocks, + boolean ignoreAirBlocks, @Switch(name = 'e', desc = "Also copy entities") - boolean copyEntities, + boolean copyEntities, @Switch(name = 'b', desc = "Also copy biomes") - boolean copyBiomes, + boolean copyBiomes, @ArgFlag(name = 'm', desc = "Set the include mask, non-matching blocks become air") - Mask mask + Mask mask ) throws WorldEditException { checkCommandArgument(count >= 1, "Multiplier must be >= 1"); @@ -618,9 +618,9 @@ public class RegionCommands { Actor actor, EditSession editSession, @Selection Region region, @Arg(desc = "BlockStateHolder", def = "air") - BlockStateHolder replace, + BlockStateHolder replace, @Switch(name = 'm', desc = "Only fall within the vertical selection") - boolean notFullHeight + boolean notFullHeight ) throws WorldEditException { int affected = editSession.fall(region, !notFullHeight, replace); actor.print(Caption.of("fawe.worldedit.visitor.visitor.block", affected)); @@ -639,20 +639,20 @@ public class RegionCommands { @Selection Region region, @Arg(desc = "# of copies to stack", def = "1") @Confirm(Confirm.Processor.REGION) - int count, + int count, @Arg(desc = "How far to move the contents each stack", def = Offset.FORWARD) @Offset - BlockVector3 direction, + BlockVector3 direction, @Switch(name = 's', desc = "Shift the selection to the last stacked copy") - boolean moveSelection, + boolean moveSelection, @Switch(name = 'a', desc = "Ignore air blocks") - boolean ignoreAirBlocks, + boolean ignoreAirBlocks, @Switch(name = 'e', desc = "Also copy entities") - boolean copyEntities, + boolean copyEntities, @Switch(name = 'b', desc = "Also copy biomes") - boolean copyBiomes, + boolean copyBiomes, @ArgFlag(name = 'm', desc = "Set the include mask, non-matching blocks become air") - Mask mask + Mask mask ) throws WorldEditException { checkCommandArgument(count >= 1, "Count must be >= 1"); @@ -704,13 +704,13 @@ public class RegionCommands { Actor actor, World world, LocalSession session, EditSession editSession, @Selection Region region, @Arg(desc = "The seed to regenerate with, otherwise uses world seed", def = "") - Long seed, + Long seed, @Switch(name = 'b', desc = "Regenerate biomes as well") - boolean regenBiomes, + boolean regenBiomes, @Switch(name = 'r', desc = "If the seed should be randomized") - boolean randomSeed, + boolean randomSeed, @Arg(desc = "Biome to apply for this regeneration (only works in overworld)", def = "") - BiomeType biomeType + BiomeType biomeType ) throws WorldEditException { Mask mask = session.getMask(); boolean success; @@ -759,13 +759,13 @@ public class RegionCommands { Actor actor, LocalSession session, EditSession editSession, @Selection Region region, @Arg(desc = "The expression to use", variable = true) - List expression, + List expression, @Switch(name = 'r', desc = "Use the game's coordinate origin") - boolean useRawCoords, + boolean useRawCoords, @Switch(name = 'o', desc = "Use the placement's coordinate origin") - boolean offset, + boolean offset, @Switch(name = 'c', desc = "Use the selection's center as origin") - boolean offsetCenter + boolean offsetCenter ) throws WorldEditException { final Vector3 zero; Vector3 unit; @@ -837,11 +837,11 @@ public class RegionCommands { Actor actor, EditSession editSession, @Selection Region region, @Arg(desc = "Thickness of the shell to leave", def = "0") - int thickness, + int thickness, @Arg(desc = "The pattern of blocks to replace the hollowed area with", def = "air") - Pattern pattern, + Pattern pattern, @ArgFlag(name = 'm', desc = "Mask to hollow with") - Mask mask + Mask mask ) throws WorldEditException { checkCommandArgument(thickness >= 0, "Thickness must be >= 0"); //FAWE start > the mask will have been initialised with a WorldWrapper extent (very bad/slow) @@ -871,9 +871,9 @@ public class RegionCommands { public int forest( Actor actor, EditSession editSession, @Selection Region region, @Arg(desc = "The type of tree to place", def = "tree") - TreeType type, + TreeType type, @Arg(desc = "The density of the forest", def = "5") - double density + double density ) throws WorldEditException { checkCommandArgument(0 <= density && density <= 100, "Density must be in [0, 100]"); int affected = editSession.makeForest(region, density / 100, type); @@ -893,7 +893,7 @@ public class RegionCommands { public int flora( Actor actor, EditSession editSession, @Selection Region region, @Arg(desc = "The density of the forest", def = "5") - double density + double density ) throws WorldEditException { checkCommandArgument(0 <= density && density <= 100, "Density must be in [0, 100]"); density = density / 100; @@ -929,7 +929,7 @@ public class RegionCommands { .getInstance() .getPlatformManager() .queryCapability(Capability.WORLD_EDITING) - .getPlatformPlacementProcessor(editSession, null, true) + .getPlatformPlacementProcessor(editSession, null, region) ); if (affected != 0) { actor.print(Caption.of("worldedit.set.done", TextComponent.of(affected))); diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Platform.java b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Platform.java index 25130a90c..0f0c358b1 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Platform.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/extension/platform/Platform.java @@ -19,16 +19,16 @@ package com.sk89q.worldedit.extension.platform; -import com.fastasyncworldedit.core.extent.processor.PlacementStateProcessor; +import com.fastasyncworldedit.core.extent.PlacementStateProcessor; import com.fastasyncworldedit.core.extent.processor.lighting.Relighter; import com.fastasyncworldedit.core.extent.processor.lighting.RelighterFactory; import com.fastasyncworldedit.core.queue.IBatchProcessor; import com.sk89q.worldedit.LocalConfiguration; -import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.entity.Player; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.function.mask.BlockTypeMask; import com.sk89q.worldedit.internal.util.NonAbstractForCompatibility; +import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.registry.Keyed; import com.sk89q.worldedit.util.SideEffect; import com.sk89q.worldedit.util.io.ResourceLoader; @@ -281,10 +281,12 @@ public interface Platform extends Keyed { } /** - * Returns an {@link PlacementStateProcessor} instance for processing placed blocks to "fix" them. + * Returns an {@link PlacementStateProcessor} instance for processing placed blocks to "fix" them. Optional region to + * prevent any changes outside of, as sometimes block neighbours will also be updated otherwise. + * * @since TODO */ - default PlacementStateProcessor getPlatformPlacementProcessor(Extent extent, BlockTypeMask mask, boolean includeUnedited) { + default PlacementStateProcessor getPlatformPlacementProcessor(Extent extent, BlockTypeMask mask, @Nullable Region region) { return null; } //FAWE end diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockTypeMask.java b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockTypeMask.java index c3567b6d5..7004d347a 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockTypeMask.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/function/mask/BlockTypeMask.java @@ -21,6 +21,7 @@ package com.sk89q.worldedit.function.mask; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.block.BlockStateHolder; import com.sk89q.worldedit.world.block.BlockType; import com.sk89q.worldedit.world.block.BlockTypes; @@ -140,6 +141,10 @@ public class BlockTypeMask extends AbstractExtentMask { public boolean test(BlockType block) { return types[block.getInternalId()]; } + + public > boolean test(B blockStateHolder) { + return types[blockStateHolder.getBlockType().getInternalId()]; + } //FAWE end @Nullable @@ -149,7 +154,7 @@ public class BlockTypeMask extends AbstractExtentMask { } @Override - public Mask copy() { + public BlockTypeMask copy() { return new BlockTypeMask(getExtent(), types.clone(), hasAir); } diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/util/SideEffect.java b/worldedit-core/src/main/java/com/sk89q/worldedit/util/SideEffect.java index 3c3910be7..49d8bc26d 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/util/SideEffect.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/util/SideEffect.java @@ -19,23 +19,30 @@ package com.sk89q.worldedit.util; +import com.fastasyncworldedit.core.configuration.Settings; + import java.util.Locale; public enum SideEffect { - LIGHTING(State.ON, true), - NEIGHBORS(State.ON, true), - UPDATE(State.ON, true), + //FAWE start - adjust defaults, add history and heightmaps + HISTORY(State.ON, true), + HEIGHTMAPS(State.ON, true), + LIGHTING(Settings.settings().LIGHTING.MODE == 0 ? State.OFF : State.ON, true), + NEIGHBORS(State.OFF, true), + UPDATE(State.OFF, true), + //FAWE end VALIDATION(State.OFF, true), ENTITY_AI(State.OFF, true), EVENTS(State.OFF, true), /** * Internal use only. */ - POI_UPDATE(State.ON, false), + POI_UPDATE(State.OFF, false), /** * Internal use only. */ - NETWORK(State.ON, false); + NETWORK(State.OFF, false); + //FAWE end private final String displayName; private final String description;