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 theintenchantment level tobyte(-128 to 127) and then stores it asshortEnchantmentHelper.setEnchantments(...): Casts theintenchantment level toshort(-32768 to 32767) and then stores it asshortEnchantmentHelper.getItemEnchantmentLevel(Enchantment, ItemStack): Reads asintand then clamps it to 0 to 255EnchantmentHelper.deserializeEnchantments(ListTag): Reads asintEnchantmentHelper.runIterationOnItem(EnchantmentVisitor, ItemStack): Reads asintEnchantedBookItem.addEnchantment(ItemStack, EnchantmentInstance): Reads asint, then writes asshortItemStack.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 thestackTagCompoundfield (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 toEnchantmentsand is now using a String-ID.