From 4cccf944aa1355e9c246cd7e36b055a1324bd3f8 Mon Sep 17 00:00:00 2001 From: haykam821 <24855774+haykam821@users.noreply.github.com> Date: Sat, 26 Mar 2022 07:24:57 -0400 Subject: [PATCH] Add the block trample event (#14) --- .../event/block/BlockTrampleEvent.java | 37 +++++++++++++++++ .../mixin/block/FarmlandBlockMixin.java | 19 +++++++-- .../mixin/block/TurtleEggBlockMixin.java | 40 +++++++++++++++++++ src/main/resources/stimuli.mixins.json | 1 + 4 files changed, 93 insertions(+), 4 deletions(-) create mode 100644 src/main/java/xyz/nucleoid/stimuli/event/block/BlockTrampleEvent.java create mode 100644 src/main/java/xyz/nucleoid/stimuli/mixin/block/TurtleEggBlockMixin.java diff --git a/src/main/java/xyz/nucleoid/stimuli/event/block/BlockTrampleEvent.java b/src/main/java/xyz/nucleoid/stimuli/event/block/BlockTrampleEvent.java new file mode 100644 index 0000000..dfe594d --- /dev/null +++ b/src/main/java/xyz/nucleoid/stimuli/event/block/BlockTrampleEvent.java @@ -0,0 +1,37 @@ +package xyz.nucleoid.stimuli.event.block; + +import net.minecraft.block.BlockState; +import net.minecraft.entity.LivingEntity; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.ActionResult; +import net.minecraft.util.math.BlockPos; +import xyz.nucleoid.stimuli.event.StimulusEvent; + +/** + * Called when any {@link LivingEntity} attempts to trample a block, such as farmland or turtle eggs. + * + *

Upon return: + *

+ *

+ * If all listeners return {@link ActionResult#PASS}, the trample succeeds. + */ +public interface BlockTrampleEvent { + StimulusEvent EVENT = StimulusEvent.create(BlockTrampleEvent.class, ctx -> (entity, world, pos, from, to) -> { + try { + for (var listener : ctx.getListeners()) { + var result = listener.onTrample(entity, world, pos, from, to); + if (result != ActionResult.PASS) { + return result; + } + } + } catch (Throwable t) { + ctx.handleException(t); + } + return ActionResult.PASS; + }); + + ActionResult onTrample(LivingEntity entity, ServerWorld world, BlockPos pos, BlockState from, BlockState to); +} diff --git a/src/main/java/xyz/nucleoid/stimuli/mixin/block/FarmlandBlockMixin.java b/src/main/java/xyz/nucleoid/stimuli/mixin/block/FarmlandBlockMixin.java index e65cf05..3579098 100644 --- a/src/main/java/xyz/nucleoid/stimuli/mixin/block/FarmlandBlockMixin.java +++ b/src/main/java/xyz/nucleoid/stimuli/mixin/block/FarmlandBlockMixin.java @@ -1,8 +1,10 @@ package xyz.nucleoid.stimuli.mixin.block; import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; import net.minecraft.block.FarmlandBlock; import net.minecraft.entity.Entity; +import net.minecraft.entity.LivingEntity; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.world.ServerWorld; import net.minecraft.util.ActionResult; @@ -14,16 +16,25 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import xyz.nucleoid.stimuli.Stimuli; import xyz.nucleoid.stimuli.event.block.BlockBreakEvent; +import xyz.nucleoid.stimuli.event.block.BlockTrampleEvent; @Mixin(FarmlandBlock.class) public class FarmlandBlockMixin { @Inject(method = "onLandedUpon", at = @At(value = "INVOKE", target = "Lnet/minecraft/block/FarmlandBlock;setToDirt(Lnet/minecraft/block/BlockState;Lnet/minecraft/world/World;Lnet/minecraft/util/math/BlockPos;)V", shift = At.Shift.BEFORE), cancellable = true) private void breakFarmland(World world, BlockState state, BlockPos pos, Entity entity, float fallDistance, CallbackInfo ci) { - if (world instanceof ServerWorld serverWorld && entity instanceof ServerPlayerEntity player) { - try (var invokers = Stimuli.select().forEntityAt(player, pos)) { - var result = invokers.get(BlockBreakEvent.EVENT).onBreak(player, serverWorld, pos); - if (result == ActionResult.FAIL) { + if (world instanceof ServerWorld serverWorld && entity instanceof LivingEntity livingEntity) { + try (var invokers = Stimuli.select().forEntityAt(entity, pos)) { + var trampleResult = invokers.get(BlockTrampleEvent.EVENT).onTrample(livingEntity, serverWorld, pos, state, Blocks.DIRT.getDefaultState()); + if (trampleResult == ActionResult.FAIL) { ci.cancel(); + return; + } + + if (livingEntity instanceof ServerPlayerEntity player) { + var breakResult = invokers.get(BlockBreakEvent.EVENT).onBreak(player, serverWorld, pos); + if (breakResult == ActionResult.FAIL) { + ci.cancel(); + } } } } diff --git a/src/main/java/xyz/nucleoid/stimuli/mixin/block/TurtleEggBlockMixin.java b/src/main/java/xyz/nucleoid/stimuli/mixin/block/TurtleEggBlockMixin.java new file mode 100644 index 0000000..500f75b --- /dev/null +++ b/src/main/java/xyz/nucleoid/stimuli/mixin/block/TurtleEggBlockMixin.java @@ -0,0 +1,40 @@ +package xyz.nucleoid.stimuli.mixin.block; + +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.block.TurtleEggBlock; +import net.minecraft.entity.Entity; +import net.minecraft.entity.LivingEntity; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.ActionResult; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import xyz.nucleoid.stimuli.Stimuli; +import xyz.nucleoid.stimuli.event.block.BlockTrampleEvent; + +@Mixin(TurtleEggBlock.class) +public class TurtleEggBlockMixin { + @Inject(method = "tryBreakEgg", at = @At(value = "INVOKE", target = "Lnet/minecraft/block/TurtleEggBlock;breakEgg(Lnet/minecraft/world/World;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/BlockState;)V", shift = At.Shift.BEFORE), cancellable = true) + private void trampleTurtleEgg(World world, BlockState from, BlockPos pos, Entity entity, int inverseChance, CallbackInfo ci) { + if (world instanceof ServerWorld serverWorld && entity instanceof LivingEntity livingEntity) { + BlockState to = Blocks.AIR.getDefaultState(); + if (from.contains(TurtleEggBlock.EGGS)) { + int eggs = from.get(TurtleEggBlock.EGGS); + if (eggs > 1) { + to = from.with(TurtleEggBlock.EGGS, eggs - 1); + } + } + + try (var invokers = Stimuli.select().forEntityAt(entity, pos)) { + var trampleResult = invokers.get(BlockTrampleEvent.EVENT).onTrample(livingEntity, serverWorld, pos, from, to); + if (trampleResult == ActionResult.FAIL) { + ci.cancel(); + } + } + } + } +} diff --git a/src/main/resources/stimuli.mixins.json b/src/main/resources/stimuli.mixins.json index b299829..8bb5a5e 100644 --- a/src/main/resources/stimuli.mixins.json +++ b/src/main/resources/stimuli.mixins.json @@ -8,6 +8,7 @@ "block.BlockMixin", "block.BucketItemMixin", "block.FarmlandBlockMixin", + "block.TurtleEggBlockMixin", "entity.LivingEntityMixin", "player.ClientConnectionMixin", "player.CraftingResultInventoryMixin",