From f002c034fb8731ac232f677a7dfad12824d5dc1d Mon Sep 17 00:00:00 2001 From: wizjany Date: Mon, 27 Jan 2025 09:48:29 -0500 Subject: [PATCH] Fix tree generators working on the unbuffered underlying world. (#2705) Adds two methods to EditSession to allow getting blocks which are buffered by the EditSession, not yet set in the world. This allows the proxies used by tree generators to know the eventual state of the world, rather than the "real" state. --- .../PaperweightServerLevelDelegateProxy.java | 21 ++++++++++------ .../impl/v1_21_3/StaticRefraction.java | 1 + .../PaperweightServerLevelDelegateProxy.java | 15 ++++++++++-- .../impl/v1_21_4/StaticRefraction.java | 1 + .../java/com/sk89q/worldedit/EditSession.java | 24 +++++++++++++++++++ .../FabricServerLevelDelegateProxy.java | 10 +++++++- .../NeoForgeServerLevelDelegateProxy.java | 10 +++++++- 7 files changed, 71 insertions(+), 11 deletions(-) diff --git a/worldedit-bukkit/adapters/adapter-1.21.3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_3/PaperweightServerLevelDelegateProxy.java b/worldedit-bukkit/adapters/adapter-1.21.3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_3/PaperweightServerLevelDelegateProxy.java index 37f04531bf..c223e812c6 100644 --- a/worldedit-bukkit/adapters/adapter-1.21.3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_3/PaperweightServerLevelDelegateProxy.java +++ b/worldedit-bukkit/adapters/adapter-1.21.3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_3/PaperweightServerLevelDelegateProxy.java @@ -28,7 +28,6 @@ import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.util.Location; import com.sk89q.worldedit.util.concurrency.LazyReference; -import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.entity.EntityTypes; import net.minecraft.core.BlockPos; import net.minecraft.core.registries.Registries; @@ -37,6 +36,7 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.world.entity.Entity; import net.minecraft.world.level.WorldGenLevel; +import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.Vec3; @@ -50,6 +50,7 @@ import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; +import java.util.function.Predicate; public class PaperweightServerLevelDelegateProxy implements InvocationHandler { @@ -86,7 +87,11 @@ private BlockEntity getBlockEntity(BlockPos blockPos) { } private BlockState getBlockState(BlockPos blockPos) { - return adapter.adapt(this.editSession.getBlock(BlockVector3.at(blockPos.getX(), blockPos.getY(), blockPos.getZ()))); + return adapter.adapt(this.editSession.getBlockWithBuffer(BlockVector3.at(blockPos.getX(), blockPos.getY(), blockPos.getZ()))); + } + + private boolean isStateAtPosition(BlockPos blockPos, Predicate predicate) { + return predicate.test(getBlockState(blockPos)); } private boolean setBlock(BlockPos blockPos, BlockState blockState) { @@ -98,11 +103,7 @@ private boolean setBlock(BlockPos blockPos, BlockState blockState) { } private boolean removeBlock(BlockPos blockPos) { - try { - return editSession.setBlock(BlockVector3.at(blockPos.getX(), blockPos.getY(), blockPos.getZ()), BlockTypes.AIR.getDefaultState()); - } catch (MaxChangedBlocksException e) { - throw new RuntimeException(e); - } + return setBlock(blockPos, Blocks.AIR.defaultBlockState()); } private boolean addEntity(Entity entity) { @@ -144,6 +145,12 @@ private static void addMethodHandleToTable( lookup.unreflect(PaperweightServerLevelDelegateProxy.class.getDeclaredMethod("getBlockState", BlockPos.class)) ); + addMethodHandleToTable( + builder, + StaticRefraction.IS_STATE_AT_POSITION, + lookup.unreflect(PaperweightServerLevelDelegateProxy.class.getDeclaredMethod("isStateAtPosition", BlockPos.class, Predicate.class)) + ); + MethodHandle addEntity = lookup.unreflect(PaperweightServerLevelDelegateProxy.class.getDeclaredMethod("addEntity", Entity.class)); addMethodHandleToTable( builder, diff --git a/worldedit-bukkit/adapters/adapter-1.21.3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_3/StaticRefraction.java b/worldedit-bukkit/adapters/adapter-1.21.3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_3/StaticRefraction.java index c098c9efd9..56b11e71ba 100644 --- a/worldedit-bukkit/adapters/adapter-1.21.3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_3/StaticRefraction.java +++ b/worldedit-bukkit/adapters/adapter-1.21.3/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_3/StaticRefraction.java @@ -37,6 +37,7 @@ public final class StaticRefraction { ); public static final String NEXT_TICK_TIME = Refraction.pickName("nextTickTime", "e"); public static final String GET_BLOCK_STATE = Refraction.pickName("getBlockState", "a_"); + public static final String IS_STATE_AT_POSITION = Refraction.pickName("isStateAtPosition", "a"); /** * {@code addFreshEntityWithPassengers(Entity entity)}. */ diff --git a/worldedit-bukkit/adapters/adapter-1.21.4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_4/PaperweightServerLevelDelegateProxy.java b/worldedit-bukkit/adapters/adapter-1.21.4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_4/PaperweightServerLevelDelegateProxy.java index e3dc39b3f5..3c72784170 100644 --- a/worldedit-bukkit/adapters/adapter-1.21.4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_4/PaperweightServerLevelDelegateProxy.java +++ b/worldedit-bukkit/adapters/adapter-1.21.4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_4/PaperweightServerLevelDelegateProxy.java @@ -53,6 +53,7 @@ import java.lang.reflect.Proxy; import java.util.HashMap; import java.util.Map; +import java.util.function.Predicate; public class PaperweightServerLevelDelegateProxy implements InvocationHandler, AutoCloseable { @@ -99,7 +100,11 @@ private BlockEntity getBlockEntity(BlockPos blockPos) { } private BlockState getBlockState(BlockPos blockPos) { - return adapter.adapt(this.editSession.getBlock(adapt(blockPos))); + return adapter.adapt(this.editSession.getBlockWithBuffer(adapt(blockPos))); + } + + private boolean isStateAtPosition(BlockPos blockPos, Predicate predicate) { + return predicate.test(getBlockState(blockPos)); } private boolean setBlock(BlockPos blockPos, BlockState blockState) { @@ -134,7 +139,7 @@ private void handleBlockEntity(BlockPos blockPos, BlockState blockState) { createdBlockEntities.remove(pos); } - private boolean removeBlock(BlockPos blockPos, boolean bl) { + private boolean removeBlock(BlockPos blockPos) { return setBlock(blockPos, Blocks.AIR.defaultBlockState()); } @@ -191,6 +196,12 @@ private static void addMethodHandleToTable( lookup.unreflect(PaperweightServerLevelDelegateProxy.class.getDeclaredMethod("getBlockState", BlockPos.class)) ); + addMethodHandleToTable( + builder, + StaticRefraction.IS_STATE_AT_POSITION, + lookup.unreflect(PaperweightServerLevelDelegateProxy.class.getDeclaredMethod("isStateAtPosition", BlockPos.class, Predicate.class)) + ); + MethodHandle addEntity = lookup.unreflect(PaperweightServerLevelDelegateProxy.class.getDeclaredMethod("addEntity", Entity.class)); addMethodHandleToTable( builder, diff --git a/worldedit-bukkit/adapters/adapter-1.21.4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_4/StaticRefraction.java b/worldedit-bukkit/adapters/adapter-1.21.4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_4/StaticRefraction.java index 61471ad115..9e5272571e 100644 --- a/worldedit-bukkit/adapters/adapter-1.21.4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_4/StaticRefraction.java +++ b/worldedit-bukkit/adapters/adapter-1.21.4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/v1_21_4/StaticRefraction.java @@ -37,6 +37,7 @@ public final class StaticRefraction { ); public static final String NEXT_TICK_TIME = Refraction.pickName("nextTickTime", "e"); public static final String GET_BLOCK_STATE = Refraction.pickName("getBlockState", "a_"); + public static final String IS_STATE_AT_POSITION = Refraction.pickName("isStateAtPosition", "a"); /** * {@code addFreshEntityWithPassengers(Entity entity)}. */ diff --git a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java index 26c357fc20..3cf2a79a55 100644 --- a/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java +++ b/worldedit-core/src/main/java/com/sk89q/worldedit/EditSession.java @@ -714,6 +714,30 @@ public BaseBlock getFullBlock(BlockVector3 position) { return world.getFullBlock(position); } + /** + * As with {@link #getBlock(BlockVector3)}, gets the block at the given position. + * However, this may return blocks not yet set to the world (i.e., buffered) by + * the current EditSession. + * + * @param position position of the block + * @return the block + */ + public BlockState getBlockWithBuffer(BlockVector3 position) { + return this.bypassNone.getBlock(position); + } + + /** + * As with {@link #getFullBlock(BlockVector3)}, gets the block at the given position, + * but as with {@link #getBlockWithBuffer(BlockVector3)}, this may return a block in + * the current EditSession's buffer rather than from the world. + * + * @param position position of the block + * @return the block + */ + public BaseBlock getFullBlockWithBuffer(BlockVector3 position) { + return this.bypassNone.getFullBlock(position); + } + /** * Returns the highest solid 'terrain' block. * diff --git a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/internal/FabricServerLevelDelegateProxy.java b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/internal/FabricServerLevelDelegateProxy.java index e3bdb96309..ba3d8d9c13 100644 --- a/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/internal/FabricServerLevelDelegateProxy.java +++ b/worldedit-fabric/src/main/java/com/sk89q/worldedit/fabric/internal/FabricServerLevelDelegateProxy.java @@ -41,6 +41,7 @@ import java.lang.reflect.Proxy; import java.util.HashMap; import java.util.Map; +import java.util.function.Predicate; public class FabricServerLevelDelegateProxy implements InvocationHandler, AutoCloseable { @@ -81,7 +82,7 @@ private BlockEntity getBlockEntity(BlockPos blockPos) { } private BlockState getBlockState(BlockPos blockPos) { - return FabricAdapter.adapt(this.editSession.getBlock(FabricAdapter.adapt(blockPos))); + return FabricAdapter.adapt(this.editSession.getBlockWithBuffer(FabricAdapter.adapt(blockPos))); } private boolean setBlock(BlockPos blockPos, BlockState blockState) { @@ -147,6 +148,13 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl return getBlockState(blockPos); } } + case "isStateAtPosition", "method_16358" -> { + if (args.length == 2 && args[0] instanceof BlockPos blockPos && args[1] instanceof Predicate) { + @SuppressWarnings("unchecked") + Predicate predicate = (Predicate) args[1]; + return predicate.test(getBlockState(blockPos)); + } + } case "getBlockEntity", "method_8321" -> { if (args.length == 1 && args[0] instanceof BlockPos blockPos) { return getBlockEntity(blockPos); diff --git a/worldedit-neoforge/src/main/java/com/sk89q/worldedit/neoforge/internal/NeoForgeServerLevelDelegateProxy.java b/worldedit-neoforge/src/main/java/com/sk89q/worldedit/neoforge/internal/NeoForgeServerLevelDelegateProxy.java index b6abff1fed..becb44030e 100644 --- a/worldedit-neoforge/src/main/java/com/sk89q/worldedit/neoforge/internal/NeoForgeServerLevelDelegateProxy.java +++ b/worldedit-neoforge/src/main/java/com/sk89q/worldedit/neoforge/internal/NeoForgeServerLevelDelegateProxy.java @@ -42,6 +42,7 @@ import java.lang.reflect.Proxy; import java.util.HashMap; import java.util.Map; +import java.util.function.Predicate; public class NeoForgeServerLevelDelegateProxy implements InvocationHandler, AutoCloseable { @@ -82,7 +83,7 @@ private BlockEntity getBlockEntity(BlockPos blockPos) { } private BlockState getBlockState(BlockPos blockPos) { - return NeoForgeAdapter.adapt(this.editSession.getBlock(NeoForgeAdapter.adapt(blockPos))); + return NeoForgeAdapter.adapt(this.editSession.getBlockWithBuffer(NeoForgeAdapter.adapt(blockPos))); } private boolean setBlock(BlockPos blockPos, BlockState blockState) { @@ -150,6 +151,13 @@ public Object invoke(Object proxy, Method method, Object[] args) throws Throwabl return getBlockState(blockPos); } } + case "isStateAtPosition", "m_7433_" -> { + if (args.length == 2 && args[0] instanceof BlockPos blockPos && args[1] instanceof Predicate) { + @SuppressWarnings("unchecked") + Predicate predicate = (Predicate) args[1]; + return predicate.test(getBlockState(blockPos)); + } + } case "getBlockEntity", "m_7702_" -> { if (args.length == 1 && args[0] instanceof BlockPos blockPos) { return getBlockEntity(blockPos);