You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
It is often desired for a mod to have an item that instead of disappearing simply enters a broken state. To accomplish this, you usually just need to ensure ItemStack#getDamageValue never exceeds ItemStack#getMaxDamage. To accomplish this with maximum vanilla compatibility, you often override IForgeItem#damageItem to return 0 for its damage value, then handle the damaging yourself including calling the callback passed into the consumer.
In this patch, shields were fixed to call LivingEntity#stopUsingItem in LivingEntity#hurtCurrentlyUsedShield when the shield breaks via the callback to fix a vanilla bug that causes the wrong item to be used visually and prevents the forge IItemExtension#stopUsingItem hook from being fired.
The problem is LivingEntity#stopUsingItem causes LivingEntity#useItem to be set to ItemStack#EMPTY, and directly after the callback vanilla has code to delete the mainhand or offhand item if LivingEntity#useItem is empty, which is normally meant to cleanup stack size 0 stack instances that are not ItemStack#EMPTY along with a queue to play the breaking sound. In this case, it overwrites a stack that is "broken" but not empty.
Steps to Reproduce:
Create a shield which in its IItemExtension#damageItem hook calls the consumer without having its damage > max damage.
Observe that breaking it while blocking will cause the item to be deleted.
Create an item with the same logic in IItemExtension#damageItem that is damaged through other means.
Observe that it will play the breaking animation without the stack being lost.
Proposed Fix:
Simplest fix is to cache the use item stack before the hurt callback in LivingEntity#hurtCurrentlyUsedShield in a local variable, and use that cache for the if statement. This has the sideeffect that the shield sound will not play for items that are broken without being made empty.
Alternatively, you could protecting the this.setItemSlot code in LivingEntity#hurtCurrentlyUsedShield below the callback to only set the slot if the instance is the same as the original item stack (by shallow comparison).
Another potential fix would be to no-op the entire if statement and move the sound up to the callback, but this has the side-effect of leaving empty instances that are not the same as ItemStack#EMPTY in the player hand.
Alternatives considered:
I could in my code simply bypass calling the broken callback, but that breaks a lot of other usages of damaging items, and prevents my code from calling the forge event.
I could also reintroduce the vanilla bug on my items by starting to use the item after it stops to prevent the item from being deleted as well, but that leads to undesired behavior when using a shield in the mainhand.
The text was updated successfully, but these errors were encountered:
Minecraft Version: Confirmed on 1.20.x and 1.21.x branches.
NeoForge Version: After commit 52733f5
Description of issue:
It is often desired for a mod to have an item that instead of disappearing simply enters a broken state. To accomplish this, you usually just need to ensure
ItemStack#getDamageValue
never exceedsItemStack#getMaxDamage
. To accomplish this with maximum vanilla compatibility, you often overrideIForgeItem#damageItem
to return0
for its damage value, then handle the damaging yourself including calling the callback passed into the consumer.In this patch, shields were fixed to call
LivingEntity#stopUsingItem
inLivingEntity#hurtCurrentlyUsedShield
when the shield breaks via the callback to fix a vanilla bug that causes the wrong item to be used visually and prevents the forgeIItemExtension#stopUsingItem
hook from being fired.The problem is
LivingEntity#stopUsingItem
causesLivingEntity#useItem
to be set toItemStack#EMPTY
, and directly after the callback vanilla has code to delete the mainhand or offhand item ifLivingEntity#useItem
is empty, which is normally meant to cleanup stack size 0 stack instances that are notItemStack#EMPTY
along with a queue to play the breaking sound. In this case, it overwrites a stack that is "broken" but not empty.Steps to Reproduce:
IItemExtension#damageItem
hook calls the consumer without having its damage > max damage.IItemExtension#damageItem
that is damaged through other means.Proposed Fix:
Simplest fix is to cache the use item stack before the hurt callback in
LivingEntity#hurtCurrentlyUsedShield
in a local variable, and use that cache for the if statement. This has the sideeffect that the shield sound will not play for items that are broken without being made empty.Alternatively, you could protecting the
this.setItemSlot
code inLivingEntity#hurtCurrentlyUsedShield
below the callback to only set the slot if the instance is the same as the original item stack (by shallow comparison).Another potential fix would be to no-op the entire if statement and move the sound up to the callback, but this has the side-effect of leaving empty instances that are not the same as
ItemStack#EMPTY
in the player hand.Alternatives considered:
I could in my code simply bypass calling the broken callback, but that breaks a lot of other usages of damaging items, and prevents my code from calling the forge event.
I could also reintroduce the vanilla bug on my items by starting to use the item after it stops to prevent the item from being deleted as well, but that leads to undesired behavior when using a shield in the mainhand.
The text was updated successfully, but these errors were encountered: