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());