Expected behaviour:
As the item component "attribute_modifiers" supports doubles, the "set_attribute_modifiers" loot table function should also support doubles.
Observed behaviour:
When modifying an item's data with /data or directly putting an attribute in the /give command, you have the full 'double' range of values. But when using an item modifier with "set_attribute_modifiers", the value gets converted to a float with less precision.
How to reproduce:
Install the attached Datapack (1.20.5)
/reload
Run "/function report:run", it will give you a stone and a grass block.
Use "/data get entity @s SelectedItem" on both items and notice how the attribute values don't match, despite being the same in the datapack function.
Attachments
Comments 4
Response to Maxime Lebrot:
For example, we store tiny increments of the luck attribute as an "ID" for the item, so we can detect item swapping efficiently. But with float accuracy we can't properly convert that attribute back to a score for comparison checks. If it's a double (Like what's supported on the item through /give or direct NBT editing), we can convert a value of 32 to 3.2000000000000006E-11 by using a scale factor of 0.0000000000010000000000000001 and convert that attribute back to a score value of 32. This works for the entire range of integers without any gaps where a mismatch would occur. But with only float accuracy, we'd either need to increase the scale factor (Meaning at higher score values it would skip numbers, creating a mismatch and bugs) or avoid item modifiers which were made for that purpose, because instead of 3.2000000000000006E-11 we'd have for example 3.199999987213431E-11, which translates to a 31.
I can imagine there being other cases where comparison checks would fail because of the small difference. Other than in this scenario where it breaks something, in general it's not good if we have to worry about whether using the set_attribute modifier is worth it in exchange for the potential rounding errors when working with small numbers.
As long as this bug remains, we'll have to copy the item to a data storage, then modify the value there, then copy that data into a container and retrieve it from there, so we don't have those rounding errors.
I found another place where it impacts us: Loot tables for items.
Let's say you have a loot table for an item and you set the luck attribute to a "default" state. And at some point, you want to check if the attribute still has the default value. But because you used a loot table (with the loot table function "set_attributes"), the values don't match, so it thinks it doesn't have the default value and breaks the datapack.
The reason is that the
ItemAttributeModifiers
component usesCodec.DOUBLE
for amount, while theSetAttributesFunction
usesNumberProviders.CODEC
and then usesamount.getFloat(context)
.