Repository navigation
feat(wasm-mesher): parse 1.21.5 – 26.3 map_chunk packets, fix 1.18+ light order - #101
Merged
Merged
Conversation
The light arrays in a 1.18+ map_chunk are vanilla DataLayer bytes: byte i holds blocks 2i (low nibble) and 2i + 1 (high nibble). parse_map_chunk_v18plus decoded them as long-encoded BitArray dumps, which reverse the bytes of every 8-byte run, so each 16-block row came out mirrored along X. Smooth lighting then showed dark bands and shadows in the wrong place wherever light changed along a row. The 1.16 and 1.17 update_light paths already read the natural order. The parity references for 1.18.2, 1.19.4, 1.20.4 and 1.21 had been generated through a prismarine-chunk that also reads the mirrored order, so they agreed with the bug. In open air, sky light never differs by more than 1 between neighbouring blocks. As stored, those references broke that rule 25 to 623 times per chunk. With their sky and block light un-mirrored, which is what this commit stores, they break it 0 times. Blocks and biomes are unchanged. A synthetic one-section packet checks the nibble order directly. runtime-build is rebuilt with wasm-pack 0.15; the bindings only list their exports in a different order.
parse_map_chunk_v18plus only knew the 1.18 to 1.21.4 layout, so from
1.21.5 on it failed and every chunk fell back to the slower JS
conversion. It now follows the format changes, chosen by protocol:
- 1.21.5 (770): heightmaps are an array of { type, long[] } instead
of NBT, and palette containers no longer send the data array length
(or the single value container's empty array). The long count
follows from the capacity, 4096 blocks or 64 biomes, and the bits
per value.
- 26.1 (775): each section has a fluid count after its block count.
- 26.3 (777): the four light masks are byte arrays
(java.util.BitSet.valueOf(byte[])) instead of long arrays.
New parity fixtures hold three map_chunk packets each for 1.21.5,
1.21.11, 26.1 and 26.3, taken from vanilla client recordings. Their
references come from prismarine-chunk with 26.x support, loaded the
way mineflayer loads a map_chunk. Blocks, biomes and both light
arrays match byte for byte. Unit tests cover the cases the fixture
world doesn't: palette data without a length, the single value
container and the byte array BitSet.
PalettedContainer.read does not use the bits byte on the wire as is. It picks a Strategy configuration from it, and that configuration's bits in memory decode the data array (and, from 1.21.5 on, size it: SimpleBitStorage holds ceil(capacity / (64 / bits)) longs): - block palettes of 1 to 4 bits are stored with 4 (FOUR_BITS_LINEAR); biome palettes keep 1 to 3 bits; - direct containers are stored with the global palette bits, ceillog2 of the registry size, whatever the wire byte says. parse_wire_container now follows that for map_chunk sections, and parse_container goes back to reading prismarine-chunk dumps only. The global palette bits also have to be right: the worker passed 8 for blocks and 3 for biomes, so every direct container, a section with more than 256 distinct block states, decoded as noise. They now come from minecraft-data for the version: 15 bits for blocks up to 26.2, 16 for 26.3, and 6 or 7 for biomes. Vanilla servers send the wire byte equal to the bits in memory, so all 12,098 recorded chunks of 19 versions from 1.18.2 to 26.3 still parse identically to prismarine-chunk. New tests cover a direct container with the global bits, a direct container whose wire byte differs from them, its prefixed form, and a 2-bit block palette stored with 4.
zardoy
marked this pull request as ready for review
October 16, 2026 11:28
Owner
|
I trust you, all good |
Owner
|
@mc-zuri TYSM your changes are finally released! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
parseMapChunkV18Plus(and the fusedgenerateGeometryFromMapChunkV18Plus*paths) only understood the 1.18–1.21.4map_chunklayout. From 1.21.5 on it failed, so every chunk fell back to the slower JSconvertChunkToWasmpath, and on 26.x it couldn't be used at all. This PR adds the newer layouts and fixes a long-standing light-order bug in the 1.18+ path.1. Parse 1.21.5 – 26.3
map_chunkpacketsThe layout is chosen by protocol in
McVersionFlags::for_protocol:{ type, long[] }instead of NBTBitSet.valueOf(byte[])) instead of long arrays2. Read 1.18+
map_chunklight in vanilla nibble orderThe light arrays in a
map_chunkare vanillaDataLayerbytes: byteiholds blocks2i(low nibble) and2i + 1. The parser decoded them as long-encoded BitArray dumps, which reverses each 8-byte run, so every 16-block row came out mirrored along X. With smooth lighting this showed up as dark bands or shadows in the wrong place wherever light changed along a row. The 1.16/1.17update_lightpaths already used the natural order.The existing 1.18.2 – 1.21 parity references had been generated through a prismarine-chunk that reads the same mirrored order, so they agreed with the bug.
3. Size and decode containers like vanilla
PalettedContainer.readmaps the bits byte on the wire through aStrategyconfiguration. That configuration's bits in memory decode the data array, and from 1.21.5 on they also size it:FOUR_BITS_LINEAR); biome palettes keep 1–3 bits;parse_wire_containerfollows this formap_chunksections, andparse_containeronce again only reads prismarine-chunk dumps. The worker used to pass 8 and 3 as the global bits, so any direct container (a section with more than 256 distinct block states) decoded as noise. It now computes them from minecraft-data per version: 15 bits for blocks up to 26.2, 16 for 26.3, and 6 or 7 for biomes.Testing
map_chunkpackets each for 1.21.5, 1.21.11, 26.1 and 26.3, taken from vanilla client recordings. References come from prismarine-chunk with 26.x support (loaded like mineflayer loads amap_chunk). Blocks, biomes, sky and block light match byte for byte.cargo test: 51 passed.vitest: 451 passed. Thebuild.sh websnapshot test andtest-section-boundarypass.map_chunkpackets from vanilla recordings of 19 versions (1.18.2 – 26.3) with no failures. Blocks, biomes, sky and block light match prismarine-chunk at every position.Notes
runtime-buildis rebuilt with wasm-pack 0.15. The generated.d.tsonly lists the exports in a different order; signatures are unchanged.🤖 Generated with Claude Code