The new lock
field on container block entities stores an item predicate, but when placed as a block, the block entity decoding fails when the item predicate contains any registry/holder information.
How to reproduce:
Give yourself a chest with the lock component
/give @s chest[lock={items:"minecraft:anvil"}]
Inspect the given item
/data get entity @s SelectedItem
✔ Notice that the command was valid and that the full lock component is present on the item
Place the chest down
✔ Notice that at this point you can only open the chest when holding an anvil, as expected
Inspect the chest's block entity data
/data get block <coords>
❌ Notice that the lock field is not present on the block entity
Re-enter singleplayer for the block entity to lose its lock data during deserialization
❌ Notice that you can open the chest even when not holding an anvil
Repeat the same experiment with a lock predicate that isn't using registry access
/give @s chest[lock={count:4}]
✔ Notice that after placing this chest, even after relogging, you can only open it when holding an item stack with count 4
Code analysis:
The reason that decoding the lock field fails is that LockCode#fromTag
uses CODEC.decode(NbtOps.INSTANCE, ..)
, specifically it uses the default NbtOps
instance. In contrast, the vault block entity for example constructs a DynamicOps
using holderLookupProvider.createSerializationContext(NbtOps.INSTANCE)
.
Attachments
Comments 3
Added half a step for re-entering singleplayer to actually go through the broken deserialization. An alternative that'll already go through serialization before a world save is
/data merge block ~ ~ ~1 {lock:{items:"minecraft:anvil"}}
Yep, I have this too.