Bug Description
There is a precision issue causing the wrong amount of damage to be applied when using /item modify
modifier set_damage
. That also breaks future relative-mode set_damage calls from working at all, where they just report success but do not alter the damage of the item anymore (unless the damage is hard-set to a value again, thus eliminating the floating-point imprecision).
Bug Reproduction Steps
My test where I encountered it:
1. Gave myself an item with the max_damage component and damage component both set to 100:
/give @s minecraft:clock[minecraft:max_damage=100,minecraft:damage=100,minecraft:max_stack_size=1]
2. Set up two repeating command blocks, requiring redstone, with similar commands to add and remove 0.01 damage – which should be 1 damage per tick:
item modify entity @p hotbar.0 {function: "set_damage", damage: 0.01, add: true}
item modify entity @p hotbar.0 {function: "set_damage", damage: -0.01, add: true}
3. Use a stone button for repeated 1-second runs of each. It works at first, going from 100 damage to 80, then 60... but then the precision error happens and it drops to 39 instead of 40. After that point, the command to subtract damage no longer works on it.
Seems like a precision error to me, but it breaks the intended use cases of that item modifier function, and should be fixed.
Code Analysis
I think the code at fault is in the SetItemDamageFunction class's "run" method:
public ItemStack run(ItemStack p_81048_, LootContext p_81049_) {
if (p_81048_.isDamageableItem()) {
int i = p_81048_.getMaxDamage();
float f = this.add ? 1.0F - (float)p_81048_.getDamageValue() / (float)i : 0.0F;
float f1 = 1.0F - Mth.clamp(this.damage.getFloat(p_81049_) + f, 0.0F, 1.0F);
p_81048_.setDamageValue(Mth.floor(f1 * (float)i));
} else {
LOGGER.warn("Couldn't set damage of loot item {}", (Object)p_81048_);
}
return p_81048_;
}
There's a lot of floating point math happening there, including in intermediate values, especially when "add" is true and includes an extra floating-point division. Perhaps this should be changed to doubles, or maybe the modifier function should accept an absolute amount of damage rather than a percentage (and then the damage points can be calculated with only int math, dividing only in the last step).
Whatever the fix... this bug is datapack-breaking and needs a fix.
Comments 0
No comments.