Fix EitherHolder item data components (damage_type, chicken/variant, zombie_nautilus/variant) for 1.21.11 - #1195
Conversation
damage_type, chicken/variant and zombie_nautilus/variant are encoded on the wire with EitherHolder.streamCodec (net.minecraft.world.item.EitherHolder): a boolean, then either a plain holder id (ByteBufCodecs.holderRegistry, a VarInt with no inline case and no +1) or a resource-key string. They were defined as registryEntryHolder, which reads the holder as VarInt(n) and returns n-1, treating n==0 as an inline value -- off by one for every referenced holder, and a desync for holder id 0. Verified against a real 1.21.11 server: stone_sword[minecraft:damage_type= "minecraft:player_attack"] is sent as 08 01 22 (component 8, hasHolder=true, holder 0x22=34). 34 is minecraft:player_attack; the old registryEntryHolder decoded it as 33 (minecraft:outside_border). The other variant components (pig/cow/frog/ horse use holderRegistry; wolf/cat/painting use their own variant codecs) are not EitherHolder and are left unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
chicken/variant (item data component) has been an EitherHolder since chicken variants were added, not only in 1.21.11. Verified against each official server jar: Chicken references EitherHolder in 1.21.6, 1.21.8 and 1.21.9 (1.21.10 shares 1.21.9 via dataPaths). Apply the same registryEntryHolder -> hasHolder+switch transform there so all versions match. painting/variant is a plain Holder (not EitherHolder), so it is correctly left as registryEntryHolder.
|
Extended this to 1.21.6, 1.21.8 and 1.21.9 — While at it I checked the other
So this should cover every |
Chicken variants were added in 1.21.5, so chicken/variant is already an EitherHolder there (verified: Chicken references EitherHolder in the 1.21.5 server jar). The earlier extension covered 1.21.6/8/9 but missed 1.21.5. Same registryEntryHolder -> hasHolder transform; chicken/variant is now identical across 1.21.5-1.21.11.
|
Conflicts, please merge in latest master and update PR after |
Master moved 1.21.11 to its own data/pc/1.21.11/proto.yml and repointed pc/latest at 26.1, which conflicted in pc/latest/proto.yml. Resolved by moving the fix to 1.21.11's own yaml and keeping master's definitions for 26.1, because the three components are no longer EitherHolder there: 1.21.11: DataComponentType<EitherHolder<DamageType>> DAMAGE_TYPE = ... EitherHolder.streamCodec(...) 26.1: DataComponentType<Holder<DamageType>> DAMAGE_TYPE = ... DamageType.STREAM_CODEC net.minecraft.world.item.EitherHolder is gone from the 26.1 jar entirely (0 references, class removed), and chicken/variant and zombie_nautilus/variant were likewise reverted to plain holders, so pc/latest correctly keeps registryEntryHolder.
|
This doesn't apply to 26.1 ? |
|
Merged master and reran One note on how I resolved the conflict in // 1.21.11
DataComponentType<EitherHolder<DamageType>> DAMAGE_TYPE = register("damage_type", b -> b.persistent(EitherHolder.codec(...)).networkSynchronized(EitherHolder.streamCodec(...)));
// 26.1
DataComponentType<Holder<DamageType>> DAMAGE_TYPE = register("damage_type", b -> b.persistent(DamageType.CODEC).networkSynchronized(DamageType.STREAM_CODEC));
Unrelated heads-up while I was in there: 26.1's |
Problem
Three 1.21.11 item data components are encoded on the wire with
EitherHolder.streamCodec(net.minecraft.world.item.EitherHolder):minecraft:damage_type—EitherHolder<DamageType>minecraft:chicken/variant—EitherHolder<ChickenVariant>minecraft:zombie_nautilus/variant—EitherHolder<ZombieNautilusVariant>EitherHolder.streamCodecisByteBufCodecs.either(holderCodec, ResourceKey.streamCodec): a boolean, then either the holder or a resource-key string. For all three, the holder codec isByteBufCodecs.holderRegistry(...), which writes a plainVarIntregistry id (reference only — no inline value and noid + 1).They were defined as
registryEntryHolder, which reads the holder asVarInt(n)and returnsn - 1, and treatsn == 0as an inline value. That is off by one for every referenced holder, and desyncs on holder id0.Evidence (real 1.21.11 server)
A
stone_sword[minecraft:damage_type="minecraft:player_attack"]is sent incontainer_set_contentas the component bytes08 01 22:08=SlotComponentTypedamage_type01=hasHolder = true22= holder id34The server's
damage_typeregistry hasminecraft:player_attackat id 34. The oldregistryEntryHolderdecoded it as34 - 1 = 33=minecraft:outside_border(wrong). The fixed structure decodesdamageType = 34=minecraft:player_attack.Fix
Define the holder branch as a plain
varint(matchingholderRegistry), keeping the leadinghasHolderboolean and thefalse → string(resource key) branch:Applied to
damage_type,chicken/variantandzombie_nautilus/variantindata/pc/latest/proto.yml(used by 1.21.11) and rebuiltdata/pc/1.21.11/protocol.json. The now-unusedDamageTypeDatatype is removed.The other variant components are intentionally left unchanged:
pig/cow/frog/horse/variantuseholderRegistry(already a plainvarint);wolf/cat/painting/variantuse their own variant stream codecs and are notEitherHolder.