Skip to content

Commit

Permalink
Add the block trample event (#14)
Browse files Browse the repository at this point in the history
  • Loading branch information
haykam821 authored Mar 26, 2022
1 parent e84984e commit 4cccf94
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -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.
*
* <p>Upon return:
* <ul>
* <li>{@link ActionResult#SUCCESS} cancels further processing and allows the trample.
* <li>{@link ActionResult#FAIL} cancels further processing and cancels the trample.
* <li>{@link ActionResult#PASS} moves on to the next listener.</ul>
* <p>
* If all listeners return {@link ActionResult#PASS}, the trample succeeds.
*/
public interface BlockTrampleEvent {
StimulusEvent<BlockTrampleEvent> 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);
}
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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();
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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();
}
}
}
}
}
1 change: 1 addition & 0 deletions src/main/resources/stimuli.mixins.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"block.BlockMixin",
"block.BucketItemMixin",
"block.FarmlandBlockMixin",
"block.TurtleEggBlockMixin",
"entity.LivingEntityMixin",
"player.ClientConnectionMixin",
"player.CraftingResultInventoryMixin",
Expand Down

0 comments on commit 4cccf94

Please sign in to comment.