Skip to content

pc 26.3: read/write light-section masks as byte arrays, not long arrays - #334

Open
DallasCarraher wants to merge 3 commits into
PrismarineJS:masterfrom
DallasCarraher:pc-26.3
Open

DallasCarraher wants to merge 3 commits into
PrismarineJS:masterfrom
DallasCarraher:pc-26.3

Conversation

@DallasCarraher

Copy link
Copy Markdown

Summary

Live-testing a mineflayer bot against a real Minecraft 26.3 Realm, chunk
loading crashed in loadParsedLight/readSection with:

TypeError: The first argument must be of type string or an instance of
Buffer, ArrayBuffer, or Array or an Array-like Object. Received undefined

The light-section byte-array data (skyLight/blockLight) was coming up
short versus what the corresponding mask (skyLightMask/blockLightMask/
emptySkyLightMask/emptyBlockLightMask) claimed.

Root cause is on the wire, not in this parsing logic: decompiling the
official 26.3 server jar's ByteBufCodecs.BIT_SET (the codec Mojang uses for
these four mask fields in ClientboundLightUpdatePacketData) shows it now
calls FriendlyByteBuf.readByteArray()/writeByteArray() +
BitSet.valueOf(byte[]) - a varint-count-of-raw-bytes encoding - instead
of the varint-count-of-longs encoding every other currently-supported
version uses (cross-checked against the still-long-array-based 1.21.9/773
schema, which calls readLongArray()/BitSet.valueOf(long[]) for the same
codec).

Manually decoding a captured map_chunk packet byte-for-byte confirmed it:
reading the masks as longs produced impossible bit positions (e.g. bit 120,
for a chunk with far fewer than 120 sections), while reading them as raw
bytes lines up exactly with the real per-section light data that follows -
and with legible block-entity NBT (sign text) decoding correctly on either
side of the masks, pinning the drift specifically to these four fields.

Changes

  • src/pc/common/BitArrayNoSpan.js: add BitArray.fromByteArray/
    toByteArray, matching java.util.BitSet's little-endian-within-byte
    convention (bit i is bit i % 8 of bytes[i / 8]).
  • src/pc/1.18/ChunkColumn.js: use them instead of fromLongArray/
    toLongArray when mcData.version['>=']('26.3'), in both
    loadParsedLight (read, client-side) and dumpLight (write, server-side).
    Gated so nothing changes for older, already-working protocol versions.

A companion minecraft-data schema fix (the four mask fields now typed
ByteArray for 26.3, instead of an array of i64) is in
PrismarineJS/minecraft-data#1301.

This builds on the not-yet-merged 26.1-26.3 chunk-format scaffolding from
#328/#329 (26.1, merged) and #333/#331 (26.2, open) - the actual fix here is
isolated to the two files above; everything else in the diff is that
existing scaffolding.

Test plan

  • Live-tested against a real 26.3 Realm: chunk light data now loads
    without throwing, and the bot reliably reaches mineflayer's spawn
    event (previously crashed hard during the very first chunk load)
  • CI / existing test suite

DallasCarraher and others added 3 commits September 14, 2026 01:00
Minecraft 26.2 (protocol 776) uses the same chunk section format as
26.1, so it maps to the existing 1.18-family implementation rather
than needing a new one. Without this, prismarine-chunk throws "No
chunk implementation for pc 26.2 found" for any consumer (mineflayer,
etc.) as soon as minecraft-data has data for 26.2.

Tested against PrismarineJS/minecraft-data#1298 (26.2 support, not
yet merged): full test suite passes (328/328), standard lint clean.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Found live-testing against a 26.3 Realm: loadParsedLight threw "The first
argument must be of type string or an instance of Buffer, ArrayBuffer, or
Array or an Array-like Object. Received undefined" from readSection, because
the light-section byte-array data (skyLight/blockLight) came up short versus
what the corresponding mask (skyLightMask/etc.) claimed.

Root cause is on the wire, not in this parsing logic: Mojang's BIT_SET codec
for these four mask fields switched from a varint-count-of-longs encoding to
a varint-count-of-raw-bytes encoding starting at 26.3 (protocol 777) -
confirmed by decompiling ByteBufCodecs.BIT_SET from the official server jar,
and cross-checked against the still-long-array-based 1.21.9/773 schema.
Companion minecraft-data fix (skyLightMask etc. now typed ByteArray for
26.3) is in the pc-26.3-support branch there.

Feeding the new byte arrays through the existing BitArray.fromLongArray
silently produced impossible bit positions (up to 120, for a chunk with far
fewer than 120 sections), which is what caused the eventual short-array
crash a few fields downstream. Added BitArray.fromByteArray/toByteArray
(matching java.util.BitSet's little-endian-within-byte convention) and
gated their use to 26.3+ so nothing changes for older, already-working
protocol versions.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
mc-zuri pushed a commit to mc-zuri/mineflayer-bedrock-public that referenced this pull request Oct 1, 2026
…om local 26.3 branches

Until the upstream PRs are released:
- ../node-minecraft-protocol: PrismarineJS/node-minecraft-protocol#1539 (vecDelta,
  lpVec3 fix) merged with PrismarineJS#1532 (26.3 in supportedVersions)
- ../prismarine-chunk: PrismarineJS/prismarine-chunk#334 (+PrismarineJS#333), 26.2/26.3 chunks and
  byte-array light masks
- ../prismarine-physics: PrismarineJS/prismarine-physics#145 plus climbUsingJump for 26.2/26.3

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H7iHmAk5ADbghn7SLqHBGw

@rom1504 rom1504 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Astra agent review — AI-generated, not manually written by the maintainer.

Rechecked 7382b4f and the existing discussion.

The byte-array mask conversion is internally consistent, but this is not ready as a complete 26.3 integration yet. Earlier today boundary probes through the actual changed BitArray code passed at bits 0, 7, 8, 31, 32, 63 and 64, including empty masks and trailing-zero trimming. The paired minecraft-data #1301 head uses byte-array masks in both map_chunk and update_light.

Please coordinate that data release and rerun the failing chunk CI, then exercise the packet-to-column path. #1301 itself still has version-integration work pending. These focused mask checks are not a new captured 26.3 server fixture or evidence that every new-version packet is ready.

Skills used: prismarine-protocol-data-review checked version selection and candidate-versus-release readiness; prismarine-world-render-review checked world/renderer ownership and integration paths; prismarine-review checked current scope and existing feedback to avoid duplicate threads.

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.

2 participants