Skip to content

Fix double-applied +1 offset in sound IDs (SoundsDataGenerator)#76

Open
arielvino wants to merge 1 commit into
PrismarineJS:mainfrom
arielvino:fix-sound-id-offset
Open

Fix double-applied +1 offset in sound IDs (SoundsDataGenerator)#76
arielvino wants to merge 1 commit into
PrismarineJS:mainfrom
arielvino:fix-sound-id-offset

Conversation

@arielvino

@arielvino arielvino commented Jul 12, 2026

Copy link
Copy Markdown

Problem

SoundsDataGenerator emits registry.getId(sound) + 1 for 1.19.2+, with a comment:

the plus 1 is required for 1.19.2+ due to Mojang using 0 in the packet to say that you should read a string id instead.

That protocol fact is real, but the offset is in the wrong layer. On the wire the sound_effect packet encodes the sound as an IdOr<SoundEvent> = VarInt(rawId + 1), where 0 signals an inline SoundEvent. That +1 belongs to the packet codec, not the registry dump.

Consumers already handle the wire offset. In minecraft-protocol, the registryEntryHolder type decodes it:

const { value: n } = varint
if (n !== 0) return { value: { soundId: n - 1 } }   // subtracts 1 here
else /* read inline SoundEvent */

So baking +1 into sounds.json double-counts: the codec subtracts 1 to get the raw id, then the lookup hits a table shifted +1 — every sound resolves to the next entry in registry order. In practice entity.player.hurt reads as entity.player.death, entity.player.small_fall as entity.player.levelup, etc., surfacing to downstream users (mineflayer) as phantom events.

Fix

Emit the raw 0-indexed registry id (drop the + 1) across all affected versions: 1.19.2, 1.20, 1.21, 1.21.3, 1.21.5, 1.21.6, 1.21.7, 1.21.8, 1.21.9, 1.21.10, 1.21.11. Versions ≤1.18, 1.19 and 1.20.4 were already correct.

Verification

This change makes the generator emit exactly registry.getId(sound) - the raw sound_event registry id. I validated that value against the game's own authoritative registry: for each affected version I ran the vanilla server's built-in report generator (java -jar server.jar --reports), which dumps minecraft:sound_event with each entry's protocol_id, and compared it id-for-id against the corresponding 0-indexed sounds.json:

11 versions, 17,944 sound ids, 0 mismatches1.19.2, 1.20.1, 1.20.2, 1.21.1, 1.21.3, 1.21.4, 1.21.5, 1.21.6, 1.21.8, 1.21.9, 1.21.11.

The name-set of each file was also cross-checked against the vanilla registry via misode/mcmeta.

SoundsDataGenerator added +1 to every sound's registry id for 1.19.2+, with a
comment reasoning that "Mojang uses 0 in the packet to say read a string id
instead." That is true of the *wire encoding*: the sound_effect packet writes
the sound as an IdOr<SoundEvent> = VarInt(rawId + 1), where 0 signals an inline
SoundEvent. But that offset belongs to the packet codec, not the registry dump.
prismarine-protocol's registryEntryHolder already does `n - 1` when decoding, so
baking +1 into sounds.json double-counts and shifts every consumer's sound
lookup by one (e.g. entity.player.hurt resolves as entity.player.death).

Emit the raw 0-indexed registry id instead. Verified against a vanilla 1.21.11
server's own --reports registry dump: raw ids match server[N] exactly. Affects
1.19.2, 1.20, 1.21, 1.21.3, 1.21.5, 1.21.6, 1.21.7, 1.21.8, 1.21.9, 1.21.10, 1.21.11.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@arielvino
arielvino marked this pull request as ready for review July 13, 2026 14:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant