Enchantments are saved as shorts, but are loaded as and function with integer values
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 the int enchantment level to byte (-128 to 127) and then stores it as short
- EnchantmentHelper.setEnchantments(...): Casts the int enchantment level to short (-32768 to 32767) and then stores it as short
- EnchantmentHelper.getItemEnchantmentLevel(Enchantment, ItemStack): Reads as int and then clamps it to 0 to 255
- EnchantmentHelper.deserializeEnchantments(ListTag): Reads as int
- EnchantmentHelper.runIterationOnItem(EnchantmentVisitor, ItemStack): Reads as int
- EnchantedBookItem.addEnchantment(ItemStack, EnchantmentInstance): Reads as int, then writes as short
- ItemStack.appendEnchantmentNames(List<Component>, ListTag): Reads as int
How to reproduce
/give @s stick{Enchantments:[{id:"sharpness",lvl:32768}]}- Close and reopen the game
Note that the enchantment level was loaded just fine - Put the stick in an anvil and rename it
The level overflows and becomes -32768
Created Issue:
Enchantments are saved as shorts, but are loaded as and function with integers values
See title.
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.example command:
/give @s stick{Enchantments:[{id:"sharpness",lvl:32768}]}
See title.
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.example command:
/give @s stick{Enchantments:[{id:"sharpness",lvl:32768}]}See title.
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.How to reproduce
/give @s stick{Enchantments:[{id:"sharpness",lvl:32768}]}- Close and reopen the game
Note that the enchantment level was loaded just fine
- Put the stick in an anvil and rename it
The level overflows and becomes -32768
See title.
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.How to reproduce
/give @s stick{Enchantments:[{id:"sharpness",lvl:32768}]}- Close and reopen the game
Note that the enchantment level was loaded just fine
- Put the stick in an anvil and rename it
The level overflows and becomes -32768
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 the int enchantment level to byte (-128 to 127) and then stores it as short
- EnchantmentHelper.setEnchantments(...): Casts the int enchantment level to short (-32768 to 32767) and then stores it as short
- EnchantmentHelper.getItemEnchantmentLevel(Enchantment, ItemStack): Reads as int and then clamps it to 0 to 255
- EnchantmentHelper.deserializeEnchantments(ListTag): Reads as int
- EnchantmentHelper.runIterationOnItem(EnchantmentVisitor, ItemStack): Reads as int
- EnchantedBookItem.addEnchantment(ItemStack, EnchantmentInstance): Reads as int, then writes as short
- ItemStack.appendEnchantmentNames(List<Component>, ListTag): Reads as int
How to reproduce
/give @s stick{Enchantments:[{id:"sharpness",lvl:32768}]}- Close and reopen the game
Note that the enchantment level was loaded just fine
- Put the stick in an anvil and rename it
The level overflows and becomes -32768
relates to
Enchantments are saved as shorts, but are loaded as and function with integersvalues
I disagree with this being resolved, since it breaks a lot of things made with high enchantment values
relates to
This is intentional, and was changed in 1.17.1 Pre-release 1 (MC-131290).
The reason you were able to have unsupported things like Sharpness 10000 in versions before 1.17.1 was due to a bug which got fixed in 1.17.1 Pre-release 1. See MC-131290.
How so? It literally causes a changing of behavior of effects on logging out and back in when the amplifier is over 127. While yes, it's an unsupported amplifier, this does make them extremely unreliable to use.
A highly similar issue with enchantment levels was deemed valid and fixed: MC-131290.
Okay, the code that is responsible for adding an enchantment is very weird.
This code is from 1.12 using mcp 940
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.
the o() method seems to initialize the stackTagCompound 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 to Enchantments and is now using a String-ID.
@[Mod] NeunEinser, 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.
Still in 18w50a.
Tested in 20w07a, stick stays at level 32768 even after relogging.
Why was this marked as affecting 20w07a?
That's the same behavior as before
Where's the issue then? How am I supposed to reproduce it?
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?Can confirm in 21w03a.
So is it means that 32767 will no longer happens?