Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Damage Pipeline Update #792

Merged
merged 55 commits into from
Jun 24, 2024
Merged

Damage Pipeline Update #792

merged 55 commits into from
Jun 24, 2024

Conversation

Caltinor
Copy link
Contributor

@Caltinor Caltinor commented Apr 10, 2024

This PR aims to create a more cohesive chain of events when entities are dealt damage.

For an in depth explanation of the need for this PR, please see This writeup by Tslat.

Overview

this PR adds two (2) new events, renames four (4), an override method for damage, and adds a protected field (damageContainer) to LivingEntity to track damage throughout the damage sequence.

DamageContainer Interface

This new field in LivingEntity tracks everything that happens during the sequence and is passed to each event. This means that for a single attack, no detail about the sequence from a prior step is obscured or inaccessible. For example, in later events, the modified and original damage are referenceable. Additionally values such as shield blocked damage, armor reduction, enchant reduction, absorption reduction, and mob effect reduction are all accessible (provided they are set at that point in the sequence). Since this container is provided to each event, it is also where modifications take place so that they persist between events.

When the sequence is complete, the damage container is discarded until a new attack is received. This is also a protected method to prevent access from the outside, since its sole purpose is to be a transient container for event-driven modifications happening internally.

The Sequence at a High Level

The "damage sequence" starts when the entity's hurt method is invoked and ends when damage is applied to the entity health. the sequence is as follows

  1. invocation of hurt
  2. invulnerability check. sequence ends if invulnerable <= EntityInvulnerabilityCheckEvent (new)
  3. cancel if on client, dead or dying, or damage is fire and entity is fire resistant
  4. first NeoForge hook to cancel or modify damage. <= LivingIncomingDamageEvent (formerly LivingAttackEvent)
  5. shield/blocking check and damage to shield <= LivingShieldBlockEvent (formerly ShieldBlockEvent)
  6. freezing check
  7. invocation of actuallyHurt
  8. apply armor reduction <= ArmorHurtEvent (new)
  9. apply magic reduction
  10. apply absorption
  11. NeoForge hook to alter damage and cancel if zero <= LivingDamageEvent.Pre (formerly LivingDamageEvent)
  12. entity health reduced by damage
  13. after-changes event to capture final state <= LivingDamageEvent.Post (formerly LivingHurtEvent)

Invulnerability Check

Currently the vanilla invulnerability check prevents modders from having any decision power on the receiving end of damage if vanilla decides the entity is invulnerable. The new event provides the following benefits:

  1. Modders always have a way to listen to an entity being attacked, even if the damage is nothing
  2. they can now override invulnerability
  3. There is now an earlier point to cancel damage.

LivingIncomingDamageEvent (formerly LivingAttackEvent)

Renamed to indicate this is the first stage in the damage sequence. This event is where most of the change should happen. Through DamageContainer#addModifier armor, enchant, mob effect, and absorption values are changed through the provided callbacks. Changing the damage in this event will have the most downstream effects.

Shield changes and the new LivingShieldBlockEvent (formerly ShieldBlockEvent)

The current ShieldBlockEvent is nested inside vanilla checks as to whether the entity is blocking. Like the invulnerability check, this was decision power taken from modders. The new event is now part of the condition, so the damage blocked, the damage to the shield, and whether the player is considered blocking are all handled by the event.

ArmorHurtEvent (new) and Reductions from Armor, Magic, and Absorption

There is currently no way to modify damage to armor durabililty except to modify the damage to the entity through two different events. This event gives explicit control over the armor durability damage portion. Furthermore, the modifiers for damage reduction from armor, enchantments, mob effects, and absorption are applied in the DamageContainer instance.

LivingDamageEvent.Pre (formerly LivingDamageEvent)

Renamed to indicate this is damage incoming to the entity and cannot be interrupted. The event is no longer cancellable for this reason. However, setting the damage to zero does still terminate the damage sequence. At this stage, all reductions have taken place and have been applied to the newDamage value. This is the last chance for users to change the final damage to the entity, but it will not revert and armor or shield durability losses.

LivingDamageEvent.Post (formerly LivingHurtEvent)

Renamed to indicate this shows changes already applied to the entity. This event is not cancellable, and receives an immutable version of the DamageContainer. This event works more as a trigger for events that need to fire when an entity takes damage AND needs to know the amount of damage received.

added ILivingEntityExtension#onDamageTaken

a default noop method that executes after the damage sequence has finished and allows custom entities a means to apply custom behavior during actuallyHurt without having to override the method.

@neoforged-pr-publishing
Copy link

  • Publish PR to GitHub Packages

@Caltinor
Copy link
Contributor Author

Updated with input from discussions on discord. Original post has been updated to reflect these changes as well.

@Shadows-of-Fire Shadows-of-Fire added enhancement New (or improvement to existing) feature or request breaking change Breaks binary compatibility 1.21 Targeted at Minecraft 1.21 labels Apr 15, 2024
@Shadows-of-Fire
Copy link
Contributor

Going to tentatively set this as targeting 1.21, due to the scope of other changes that are currently slated for 1.20.5. If we find ourselves in an accelerated timeline before the 20.5 stable release, we can revisit this decision.

@Shadows-of-Fire Shadows-of-Fire added this to the 1.21 Stable Release milestone Apr 15, 2024
@Shadows-of-Fire Shadows-of-Fire added 1.20.5 Targeted at Minecraft 1.20.5 and removed 1.21 Targeted at Minecraft 1.21 labels Apr 30, 2024
@Shadows-of-Fire Shadows-of-Fire removed this from the 1.21 Stable Release milestone Apr 30, 2024
@Shadows-of-Fire Shadows-of-Fire added 1.20.6 Targeted at Minecraft 1.20.6 and removed 1.20.5 Targeted at Minecraft 1.20.5 labels Apr 30, 2024
@Technici4n Technici4n added this to the 20.6 Stable Release milestone May 15, 2024
Copy link
Contributor

@Shadows-of-Fire Shadows-of-Fire left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have time to finish all the files atm (I got about halfway through) but I'll submit this review set thus far. Lots of little changes that need to be made for sanity.

One thing I think needs to be looked at on a broad level is the event naming. The sequence doesn't have a coherent name set, and we have two clashing names that (at a glance) would appear to be the "initiating" event - EntityPreDamageEvent and IncomingDamageEvent. That might be better discussed on discord though.

@Matyrobbrt Matyrobbrt added the 1.21 Targeted at Minecraft 1.21 label Jun 15, 2024
@Matyrobbrt Matyrobbrt added the last call Planned to be resolved by the end of the week, awaiting any last-minute comments label Jun 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
1.21 Targeted at Minecraft 1.21 breaking change Breaks binary compatibility enhancement New (or improvement to existing) feature or request last call Planned to be resolved by the end of the week, awaiting any last-minute comments
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants