From 6cca2bef6571416ad8e983217b4dc5fab3a6105f Mon Sep 17 00:00:00 2001 From: TheDeathlyCow <53499406+TheDeathlyCow@users.noreply.github.com> Date: Mon, 26 Aug 2024 23:02:20 +1200 Subject: [PATCH] After Damage Event (#4051) * after damage event * add after damage event to testmod * remove amount > 0 check to capture shield blocking * add javadoc * dont fire event if killed * clarify javadoc a bit more * fix checkstyle issue * fix other checkstyle issues lol * rename damageDealt to baseDamageTaken (cherry picked from commit 2122d828f09a27d22ab75367ba769708cd3830ea) --- .../event/v1/ServerLivingEntityEvents.java | 31 +++++++++++++++++++ .../mixin/entity/event/LivingEntityMixin.java | 8 +++++ .../test/entity/event/EntityEventTests.java | 4 +++ 3 files changed, 43 insertions(+) diff --git a/fabric-entity-events-v1/src/main/java/net/fabricmc/fabric/api/entity/event/v1/ServerLivingEntityEvents.java b/fabric-entity-events-v1/src/main/java/net/fabricmc/fabric/api/entity/event/v1/ServerLivingEntityEvents.java index 68a1505bf6..82f5b481ba 100644 --- a/fabric-entity-events-v1/src/main/java/net/fabricmc/fabric/api/entity/event/v1/ServerLivingEntityEvents.java +++ b/fabric-entity-events-v1/src/main/java/net/fabricmc/fabric/api/entity/event/v1/ServerLivingEntityEvents.java @@ -42,6 +42,22 @@ public final class ServerLivingEntityEvents { return true; }); + /** + * An event that is called after an entity is damaged. This is fired from {@link LivingEntity#damage} after damage + * is applied, or after that damage was blocked by a shield. + * + *

The base damage taken is the damage initially applied to the entity. Damage taken is the amount of damage the + * entity actually took, after effects such as shields and extra freezing damage are applied. Damage taken does NOT + * include damage reduction from armor and enchantments. + * + *

This event is not fired if the entity was killed by the damage. + */ + public static final Event AFTER_DAMAGE = EventFactory.createArrayBacked(AfterDamage.class, callbacks -> (entity, source, baseDamageTaken, damageTaken, blocked) -> { + for (AfterDamage callback : callbacks) { + callback.afterDamage(entity, source, baseDamageTaken, damageTaken, blocked); + } + }); + /** * An event that is called when an entity takes fatal damage. * @@ -104,6 +120,21 @@ public interface AllowDamage { boolean allowDamage(LivingEntity entity, DamageSource source, float amount); } + @FunctionalInterface + public interface AfterDamage { + /** + * Called after a living entity took damage, unless they were killed. The base damage taken is given as damage + * taken before armor or enchantments are applied, but after other effects like shields are applied. + * + * @param entity the entity that was damaged + * @param source the source of the damage + * @param baseDamageTaken the amount of damage initially dealt + * @param damageTaken the amount of damage actually taken by the entity, before armor and enchantment effects + * @param blocked whether the damage was blocked by a shield + */ + void afterDamage(LivingEntity entity, DamageSource source, float baseDamageTaken, float damageTaken, boolean blocked); + } + @FunctionalInterface public interface AllowDeath { /** diff --git a/fabric-entity-events-v1/src/main/java/net/fabricmc/fabric/mixin/entity/event/LivingEntityMixin.java b/fabric-entity-events-v1/src/main/java/net/fabricmc/fabric/mixin/entity/event/LivingEntityMixin.java index aed0256226..6b88b4a0e5 100644 --- a/fabric-entity-events-v1/src/main/java/net/fabricmc/fabric/mixin/entity/event/LivingEntityMixin.java +++ b/fabric-entity-events-v1/src/main/java/net/fabricmc/fabric/mixin/entity/event/LivingEntityMixin.java @@ -30,6 +30,7 @@ import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; import net.minecraft.block.BedBlock; import net.minecraft.block.BlockState; @@ -83,6 +84,13 @@ private void beforeDamage(DamageSource source, float amount, CallbackInfoReturna } } + @Inject(method = "damage", at = @At("TAIL"), locals = LocalCapture.CAPTURE_FAILHARD) + private void afterDamage(DamageSource source, float amount, CallbackInfoReturnable cir, float dealt, boolean blocked) { + if (!isDead()) { + ServerLivingEntityEvents.AFTER_DAMAGE.invoker().afterDamage((LivingEntity) (Object) this, source, dealt, amount, blocked); + } + } + @Inject(method = "sleep", at = @At("RETURN")) private void onSleep(BlockPos pos, CallbackInfo info) { EntitySleepEvents.START_SLEEPING.invoker().onStartSleeping((LivingEntity) (Object) this, pos); diff --git a/fabric-entity-events-v1/src/testmod/java/net/fabricmc/fabric/test/entity/event/EntityEventTests.java b/fabric-entity-events-v1/src/testmod/java/net/fabricmc/fabric/test/entity/event/EntityEventTests.java index 2b987a55cc..f6e1779ed5 100644 --- a/fabric-entity-events-v1/src/testmod/java/net/fabricmc/fabric/test/entity/event/EntityEventTests.java +++ b/fabric-entity-events-v1/src/testmod/java/net/fabricmc/fabric/test/entity/event/EntityEventTests.java @@ -90,6 +90,10 @@ public void onInitialize() { return true; }); + ServerLivingEntityEvents.AFTER_DAMAGE.register((entity, source, baseDamageTaken, damageTaken, blocked) -> { + LOGGER.info("Entity {} received {} damage from {} (initially dealt {}, blocked {})", entity.getName().getString(), damageTaken, source.getName(), baseDamageTaken, blocked); + }); + ServerLivingEntityEvents.ALLOW_DEATH.register((entity, source, amount) -> { LOGGER.info("{} is going to die to {} damage from {} damage source", entity.getName().getString(), amount, source.getName());