diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/PressurePlateBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/PressurePlateBlockBehavior.java index 51ad4edb3..999fe0da3 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/PressurePlateBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/PressurePlateBlockBehavior.java @@ -182,6 +182,21 @@ public class PressurePlateBlockBehavior extends BukkitBlockBehavior { } } + @Override + public void onRemove(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + Object state = args[0]; + Object level = args[1]; + Object pos = args[2]; + Object newState = args[3]; + boolean movedByPiston = (boolean) args[4]; + if (!movedByPiston && !FastNMS.INSTANCE.method$BlockStateBase$is(state, FastNMS.INSTANCE.method$BlockState$getBlock(newState))) { + if (this.getSignalForState(state) > 0) { + this.updateNeighbours(level, pos, thisBlock); + } + superMethod.call(); + } + } + private void updateNeighbours(Object level, Object pos, Object thisBlock) { FastNMS.INSTANCE.method$Level$updateNeighborsAt(level, pos, thisBlock); FastNMS.INSTANCE.method$Level$updateNeighborsAt(level, LocationUtils.below(pos), thisBlock); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/UnsafeCompositeBlockBehavior.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/UnsafeCompositeBlockBehavior.java index e70881894..4542f71d2 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/UnsafeCompositeBlockBehavior.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/behavior/UnsafeCompositeBlockBehavior.java @@ -225,6 +225,13 @@ public class UnsafeCompositeBlockBehavior extends BukkitBlockBehavior { } } + @Override + public void onRemove(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + for (AbstractBlockBehavior behavior : this.behaviors) { + behavior.onRemove(thisBlock, args, superMethod); + } + } + @Override public int getSignal(Object thisBlock, Object[] args, Callable superMethod) { for (AbstractBlockBehavior behavior : this.behaviors) { @@ -268,4 +275,11 @@ public class UnsafeCompositeBlockBehavior extends BukkitBlockBehavior { } return previous; } + + @Override + public void spawnAfterBreak(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + for (AbstractBlockBehavior behavior : this.behaviors) { + behavior.spawnAfterBreak(thisBlock, args, superMethod); + } + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BlockGenerator.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BlockGenerator.java index e92214714..1db5d52dc 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BlockGenerator.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/injector/BlockGenerator.java @@ -180,11 +180,18 @@ public final class BlockGenerator { .intercept(MethodDelegation.to(IsSignalSourceInterceptor.INSTANCE)) // playerWillDestroy .method(ElementMatchers.is(CoreReflections.method$Block$playerWillDestroy)) - .intercept(MethodDelegation.to(PlayerWillDestroyInterceptor.INSTANCE)); + .intercept(MethodDelegation.to(PlayerWillDestroyInterceptor.INSTANCE)) + // spawnAfterBreak + .method(ElementMatchers.is(CoreReflections.method$BlockBehaviour$spawnAfterBreak)) + .intercept(MethodDelegation.to(SpawnAfterBreakInterceptor.INSTANCE)); if (CoreReflections.method$BlockBehaviour$affectNeighborsAfterRemoval != null) { builder.method(ElementMatchers.is(CoreReflections.method$BlockBehaviour$affectNeighborsAfterRemoval)) .intercept(MethodDelegation.to(AffectNeighborsAfterRemovalInterceptor.INSTANCE)); } + if (CoreReflections.method$BlockBehaviour$onRemove != null) { + builder.method(ElementMatchers.is(CoreReflections.method$BlockBehaviour$onRemove)) + .intercept(MethodDelegation.to(OnRemoveInterceptor.INSTANCE)); + } Class clazz$CraftEngineBlock = builder.make().load(BlockGenerator.class.getClassLoader()).getLoaded(); constructor$CraftEngineBlock = MethodHandles.publicLookup().in(clazz$CraftEngineBlock) @@ -615,6 +622,20 @@ public final class BlockGenerator { } } + public static class OnRemoveInterceptor { + public static final OnRemoveInterceptor INSTANCE = new OnRemoveInterceptor(); + + @RuntimeType + public void intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable superMethod) { + ObjectHolder holder = ((DelegatingBlock) thisObj).behaviorDelegate(); + try { + holder.value().onRemove(thisObj, args, superMethod); + } catch (Exception e) { + CraftEngine.instance().logger().severe("Failed to run onRemove", e); + } + } + } + public static class EntityInsideInterceptor { public static final EntityInsideInterceptor INSTANCE = new EntityInsideInterceptor(); @@ -643,4 +664,18 @@ public final class BlockGenerator { } } } + + public static class SpawnAfterBreakInterceptor { + public static final SpawnAfterBreakInterceptor INSTANCE = new SpawnAfterBreakInterceptor(); + + @RuntimeType + public void intercept(@This Object thisObj, @AllArguments Object[] args, @SuperCall Callable superMethod) { + ObjectHolder holder = ((DelegatingBlock) thisObj).behaviorDelegate(); + try { + holder.value().spawnAfterBreak(thisObj, args, superMethod); + } catch (Exception e) { + CraftEngine.instance().logger().severe("Failed to run spawnAfterBreak", e); + } + } + } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java index 927ff1e16..0bd7981a8 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/reflection/minecraft/CoreReflections.java @@ -3816,4 +3816,18 @@ public final class CoreReflections { VersionHelper.isOrAbove1_20_2() ? ReflectionUtils.getStaticMethod(clazz$ArmorTrim, Optional.class, clazz$RegistryAccess, clazz$ItemStack, boolean.class) : ReflectionUtils.getStaticMethod(clazz$ArmorTrim, Optional.class, clazz$RegistryAccess, clazz$ItemStack); + + public static final Method method$BlockBehaviour$spawnAfterBreak = requireNonNull( + ReflectionUtils.getDeclaredMethod( + clazz$BlockBehaviour, void.class, clazz$BlockState, clazz$ServerLevel, clazz$BlockPos, clazz$ItemStack, boolean.class + ) + ); + + // 1.20~1.21.4 + public static final Method method$BlockBehaviour$onRemove = MiscUtils.requireNonNullIf( + ReflectionUtils.getDeclaredMethod( + clazz$BlockBehaviour, void.class, clazz$BlockState, clazz$Level, clazz$BlockPos, clazz$BlockState, boolean.class + ), + !VersionHelper.isOrAbove1_21_5() + ); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/block/BlockBehavior.java b/core/src/main/java/net/momirealms/craftengine/core/block/BlockBehavior.java index 0cca29faf..01c6cc04b 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/block/BlockBehavior.java +++ b/core/src/main/java/net/momirealms/craftengine/core/block/BlockBehavior.java @@ -123,6 +123,10 @@ public abstract class BlockBehavior { public void affectNeighborsAfterRemoval(Object thisBlock, Object[] args, Callable superMethod) throws Exception { } + // 1.20~1.21.4 BlockState state, Level level, BlockPos pos, BlockState newState, boolean movedByPiston + public void onRemove(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + } + // BlockState blockState, BlockGetter blockAccess, BlockPos pos, Direction side public int getSignal(Object thisBlock, Object[] args, Callable superMethod) { return 0; @@ -143,6 +147,10 @@ public abstract class BlockBehavior { return superMethod.call(); } + // BlockState state, ServerLevel level, BlockPos pos, ItemStack stack, boolean dropExperience + public void spawnAfterBreak(Object thisBlock, Object[] args, Callable superMethod) throws Exception { + } + public ImmutableBlockState updateStateForPlacement(BlockPlaceContext context, ImmutableBlockState state) { return state; }