The bug
The game saves natural enchantments as shorts, yet using integer values (eg 32768 (max short + 1)) makes the game load them fine as integers numbers.
Note that the enchantment saving and loading logic exists in multiple methods which all behave differently.
20w07a Mojang names:
ItemStack.enchant(Enchantment, int)
: Casts theint
enchantment level tobyte
(-128 to 127) and then stores it asshort
EnchantmentHelper.setEnchantments(...)
: Casts theint
enchantment level toshort
(-32768 to 32767) and then stores it asshort
EnchantmentHelper.getItemEnchantmentLevel(Enchantment, ItemStack)
: Reads asint
and then clamps it to 0 to 255EnchantmentHelper.deserializeEnchantments(ListTag)
: Reads asint
EnchantmentHelper.runIterationOnItem(EnchantmentVisitor, ItemStack)
: Reads asint
EnchantedBookItem.addEnchantment(ItemStack, EnchantmentInstance)
: Reads asint
, then writes asshort
ItemStack.appendEnchantmentNames(List<Component>, ListTag)
: Reads asint
How to reproduce
/give @s stick{Enchantments:[{id:"sharpness",lvl:32768}]}
Close and reopen the game
:info: Note that the enchantment level was loaded just finePut the stick in an anvil and rename it
❌ The level overflows and becomes -32768
Linked issues
relates to 2
Comments 11
@@unknown, it looks like this method is (at least in 1.12.2) only used for cases where the level is restricted to maximum values of the enchantments anyways (enchantment table, loot tables, /enchant
...), so it is not such a big problem.
1. /give @p diamond_sword
2. /enchant @p sharpness
3. /data get entity @p SelectedItem.tag.Enchantments[0].lvl
→ 1s
instead of 1
Can reproduce that.
Makes me believe I may have also come to the wrong conclusions for the related ticket MC-135506, can you check that one?
Okay, the code that is responsible for adding an enchantment is very weird.
This code is from 1.12 using mcp 940
net.minecraft.item.ItemStack.addEnchantment(Enchantment, int)
The method accepts an int as parameter, then when adding it casts it to a byte, and then stores it as a short. Only thing that's missing here is a long.
Edit
The code in 1.13-pre1 looks very similar. This code was decompiled using the CFR decompiler.
awr.a(azq, int)
the
o()
method seems to initialize thestackTagCompound
field (g
) if it is null. That's what has been there before, just in its own method. Other than that, there where some changes to the tag itself: It was renamed toEnchantments
and is now using a String-ID.