Skip to content

Conversation

@HaHaWTH
Copy link
Contributor

@HaHaWTH HaHaWTH commented Jan 4, 2026

This pull request fixes MC-17876, attribute modifiers of equipment are applied after the entity health is set, leading to health value loss on entity reload/player rejoin.

This PR fixed the issue by loading equipment attributes before the max health is determined to prevent the health from being clamped to the base value. Treats Player separately, as the inventory is not loaded yet.

To reproduce

Type command /item replace entity @s armor.head with iron_helmet[minecraft:attribute_modifiers=[ {id:"test",type:"max_health",amount:6,operation:"add_value"}]], quit the server after health regen, the extra health will be lost upon rejoin without this fix.

API Changes

Shouldn't introduce any API behavior change with EntityEquipmentChangedEvent.

The added method loadEquipmentAttributeChanges logic was extracted from collectEquipmentChanges with only attribute modifiers application kept

@HaHaWTH HaHaWTH requested a review from a team as a code owner January 4, 2026 14:29
@github-project-automation github-project-automation bot moved this to Awaiting review in Paper PR Queue Jan 4, 2026
@lynxplay
Copy link
Contributor

lynxplay commented Jan 4, 2026

I am not a fan of copying half the method out, nor really of moving the health call.
The fact that players are handled differently because their main and offhand items are in the inventory block makes this pretty ugly imo.

Beyond that, we now also double loading/changing the attributes, once during the readAdditional and once in the first tick when the equipment changes are detected.

Lastly, and probably my suggestion for this.
This should already be a problem when comparing this to the absorption hearts. They suffer the same issue as health as their max amount is managed by an attribute modifier. The "solution" mojang takes here is to have the loading ignore clamping and then clamp after the first tick in-world when the attribute updater does its thing.
While not perfect (this leaves the entity in a state of technically invalid absorption amounts) it avoids the above double loading of attributes.

We can (not have to, probably a separate PR) still fix the fact that the entity health and absorption are faulty during the first tick of the entity, but that would probably be placed in some post processing in Entity.load, similar to how reapplyPosition is already called there too, instead of manually moving it to the end of every readAddtiional call, hoping none was missed that might modify item state.

@HaHaWTH
Copy link
Contributor Author

HaHaWTH commented Jan 4, 2026

Thanks for the feedback. I have refactored the fix as suggested:

Removed the duplicated equipment attribute loading logic, avoiding double-loading of attributes.
Adopted a strategy similar to absorption: Add a overload method of setHealth to bypass clamp to maxHealth logic while keeping the necessary safety checks, setting to private to prevent some plugins with reflections from scanning overloaded setHealth(float, boolean).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Awaiting review

Development

Successfully merging this pull request may close these issues.

2 participants