Skip to content

fix(registries): emit canonical Int/Float/Byte NBT tags for registry entries - #77

Open
rayanbzd wants to merge 1 commit into
Quozul:masterfrom
rayanbzd:fix/canonical-nbt-registries
Open

fix(registries): emit canonical Int/Float/Byte NBT tags for registry entries#77
rayanbzd wants to merge 1 commit into
Quozul:masterfrom
rayanbzd:fix/canonical-nbt-registries

Conversation

@rayanbzd

Copy link
Copy Markdown
Contributor

PacketEvents 2.12.x logs IllegalStateException: Error while reading registry minecraft:timeline on every connect from a 1.21.11+ client (retrooper/packetevents#1482).

Root cause

json_to_nbt was picking the smallest int type that fits each value (0 → Byte, 1000 → Short, 24000 → Short...) and routing lossy floats to Double to preserve precision. Vanilla doesn't do that. NbtOps.createInt(int) always returns IntTag, createFloat(float) always returns FloatTag, and createBoolean(boolean) stays ByteTag. The vanilla client is lenient w/ wider tags; PE's mirror codec isn't.

Checked the 26.1.2 server jar directly (mojmap is in the clear nowadays, so this is verifiable):

  • NbtOps.createInt(I) -> IntTag.valueOf(I) no downcast
  • NbtOps.createFloat(F) -> FloatTag.valueOf(F) never promoted to Double
  • Timeline.DIRECT_CODEC ties period_ticks to ExtraCodecs.POSITIVE_INT (a Codec<Integer> over Codec.INT) -> emits IntTag(24000), not ShortTag(24000)
  • EasingType$CubicBezierControls is a record w/ four float fields -> Codec.FLOAT -> FloatTag

It's what Mojang's typed Codec API emits when serializing registry classes through NbtOps.INSTANCE.

Fix

New opt-in NbtOptions::numeric_widening flag + a json_to_nbt_with_options entry point. With the flag on:

  • ints stay Int (or Long on i32 overflow) - no Byte/Short downcast
  • floats stay Float, even when the f64 doesn't round-trip exactly
  • homogeneous int arrays become IntArray / LongArray, no ByteArray
  • booleans stay Byte, same as NbtOps.createBoolean

json_to_nbt's default behaviour is untouched. Only pico_registries opts in when loading the generated data reports, so nothing outside the registry loader moves.

Test

An integration test at pico_libraries/pico_registries/tests/registry_widening.rs pins the expected types against the real V26_1/timeline/day.json data report (period_ticks: Int(24000), marker ticks: Int(1000), show_in_commands: Byte(1), cubic_bezier[0]: Float(~0.362) etc), so a future regression on the canonical encoding hits CI.

Scope

The non-canonical encoding affected every registry PicoLimbo emits, not just minecraft:timeline. Timeline just happens to be where PE's stricter codec trips first. Fixing at the converter level covers all registries in one go.

No version gating needed, the change is purely about how data reports get loaded into NBT.

@Quozul

Quozul commented Jun 7, 2026

Copy link
Copy Markdown
Owner

Can you please check if this is still relevant as this should be fixed in Packet Events v2.12.2? Thanks!

@Quozul Quozul added the stale label Jun 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants