Skip to content

Add clientTickEndPacket feature flag (1.21.3+) - #1304

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

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

Conversation

@DallasCarraher

Copy link
Copy Markdown

Summary

  • Adds a clientTickEndPacket feature flag (versions 1.21.3 - latest) for the serverbound tick_end packet that's been present in the wire protocol since 1.21.3 but has no client anywhere in the prismarine ecosystem sending it.

Why

Found live-testing mineflayer against a local 26.3 vanilla server while chasing a post-spawn multiplayer.disconnect.invalid_player_movement kick. Decompiled ServerGamePacketListenerImpl (26.3 server jar) and traced it:

  • handleMovePlayer disconnects with invalid_player_movement if a position-bearing move packet arrives while receivedPositionThisTick is already true.
  • receivedPositionThisTick (and receivedMovementThisTick) are only ever cleared in handleClientTickEnd, which fires on receipt of the serverbound tick_end packet (id present since 1.21.3, confirmed via protocol.json for 1.21.3 through 26.3).
  • A client that never sends tick_end sets that flag on its very first position-bearing move packet and it is never cleared again — so the second position/position-and-look packet sent over the whole connection, no matter how much later, gets the client kicked.

This flag lets client implementations (mineflayer, etc.) gate sending an empty tick_end packet once per client tick to keep the server's bookkeeping in sync, mirroring real client behavior. See companion PR on mineflayer for the consumer side.

Test plan

  • Verified locally against a real 26.3 server jar: without sending tick_end, bot is kicked ~1-2s after spawn with invalid_player_movement; with mineflayer sending it every physics tick (gated on this flag), the bot stays connected, moves, and chats without being kicked.

extremeheat and others added 13 commits September 14, 2026 09:10
Co-authored-by: extremeheat <13713600+extremeheat@users.noreply.github.com>
Registers protocol 776 (26.2) with real generated data: blocks, items,
entities, recipes, language, commands, protocol.json (regenerated from
proto.yml), loot tables, and the rest of the per-version files. Also
adds a 1.20.3 windows.json with the crafter menu (missing since 1.20.3)
so 26.2's windows entry is accurate.

Extracted from the 26.2 portion of PrismarineJS#1287,
which additionally carries unrelated fixes for 1.13.1, 1.14.2, 1.9.1
and a broader commands.json refresh across older versions. This commit
isolates just the 26.2 data so it can be reviewed and merged
independently of that larger changeset.

effects/enchantments/instruments are borrowed from 26.1 since those
registries are unchanged in 26.2.

Full mocha suite passes (1887 passing, 1 pending, 0 failing).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Addresses review feedback on this PR:

- sulfur_cube_content duplicated ItemStackTemplate's shape inline
  instead of referencing it. Verified against the real 26.2 server jar:
  net.minecraft.world.item.component.SulfurCubeContent is a record with
  a single field of type net.minecraft.world.item.ItemStackTemplate (no
  array wrapper) — Mojang's own internal type has the same name and
  shape minecraft-data already used. Now just `if sulfur_cube_content:
  ItemStackTemplate`.

- packet_spectator_action: verified this is a genuine rename, not a
  new packet alongside the old one. Decompiled the real 26.2 server
  jar: net/minecraft/network/protocol/game/ServerboundSpectatorActionPacket
  exists (a Record with one field, `OptionalInt spectateEntityId`,
  handled via `handleSpectatorAction`); no ServerboundSpectateEntityPacket
  class exists anywhere in the jar. Matches this PR's existing encoding
  (`entityId?: varint`) exactly — no data change needed for this one.

- Separately: rebasing this branch onto pc_26_2 silently regressed
  PrismarineJS#1267's ItemStackTemplate fix throughout data/pc/latest/proto.yml —
  git's merge applied both sides' overlapping edits to this file in a
  way that dropped PrismarineJS#1267's hunks without flagging a conflict. Restored
  all of it (intangible_projectile NBT, and ItemStackTemplate at
  use_remainder/charged_projectiles/bundle_contents/container/particle
  item/SlotDisplay item_stack/advancement icon) and regenerated
  data/pc/26.2/protocol.json from the corrected proto.yml.

Full test suite still green: 1887 passing, 1 pending, 0 failing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ng, cubemob metadata, bee size, knockback_resistance min

All five verified by decompiling the real 26.2 server jar
(versions/26.2/server-26.2.jar) with CFR, cross-referenced against
extremeheat/extracted_minecraft_data where cited in review.

- packet_entity_teleport: the pc_26_2 rebase also silently dropped
  PrismarineJS#1273's 1.21.2+ layout fix (dx/dy/dz, f32 yaw/pitch,
  PositionUpdateRelatives flags) the same way it dropped PrismarineJS#1267's
  ItemStackTemplate fix. Restored — ClientboundTeleportEntityPacket
  still uses PositionMoveRotation in 26.2, confirmed against the real
  class.

- packet_spectator_action: entityId?: varint (protodef presence-byte
  optional) doesn't match vanilla's wire format. Decompiled
  ByteBufCodecs.OPTIONAL_VAR_INT: it maps a single raw VarInt directly
  (no separate presence byte) — 0 = absent, n = entity id (n - 1).
  Changed to `entityId: optvarint`, the same sentinel-varint alias
  already used for entity metadata's optional_block_state/
  optional_unsigned_int.

- data/pc/26.2/entities.json: slime/magma_cube/sulfur_cube were
  missing the `baby`/`age_locked` metadata keys AgeableMob defines
  (confirmed via SynchedEntityData.defineId call order in
  AgeableMob/AbstractCubeMob/SulfurCube bytecode), and sulfur_cube had
  max_fuse/from_bucket swapped. Fixed all three to
  mob_flags, baby, age_locked, size, max_fuse, from_bucket.

- bee width/height: EntityTypes.BEE registers .sized(0.55f, 0.5f) in
  26.2; entities.json still had 26.1's 0.7/0.6. Fixed.

- data/pc/26.2/attributes.json: knockbackResistance's min was 0.0;
  Attributes.KNOCKBACK_RESISTANCE registers RangedAttribute(default
  0.0, min -2.0, max 1.0). Fixed.

Full test suite still green: 1887 passing, 1 pending, 0 failing.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
# Conflicts:
#	data/dataPaths.json
#	data/pc/common/versions.json
#	data/pc/latest/proto.yml
Two independent gaps found live-testing 26.3 against a real Realm with
mineflayer:

- packet_success (login, toClient) was missing the sessionId: UUID
  field that 26.2 (protocol 776) already added. Client-side parsing
  under-read every login success packet by 16 bytes.

- configuration.toClient's packet ID table was missing
  CLIENTBOUND_POST_EFFECTS at 0x0a, shifting every packet from
  store_cookie (0x0b) through code_of_conduct (0x14) down by one slot
  versus the real server. Confirmed by decompiling
  net.minecraft.network.protocol.configuration.ConfigurationProtocols
  from the official 26.3 server jar and reading addPacket() call order
  (same technique as PrismarineJS#1298/26.1.2's packet ID fixes). Concretely, ID
  0x0f was mapped to custom_report_details but is actually
  select_known_packs — since mineflayer's client.once('select_known_packs')
  listener never fired under the wrong name, the client never sent the
  required response, and the server silently stalled in the
  configuration state forever (steady keep_alive, nothing else).

Added packet_post_effects (a single postEffects: List<Identifier>
field, confirmed via javap on ClientboundPostEffectsPacket's
STREAM_CODEC) and resequenced 0x0a-0x14 to match.

With both fixes, a real client now completes the full configuration
handshake (select_known_packs -> registry_data -> tags ->
finish_configuration) and enters the play state.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Live-testing against a real 26.3 Realm (with the configuration-state fix
from 12aa21b already applied) got the bot into the play state, but it
immediately misread the join-game packet as low_disk_space_warning and
crashed decoding a player_chat-shaped packet. Same root cause as the
configuration-state bug: Mojang inserted new packets between 26.1.2 and
26.3 (net.minecraft.network.protocol.game.GameProtocols), shifting every
later packet ID by one or more slots versus what protocol.json had.

Decompiled the official 26.3 server jar's GameProtocols class (deobfuscated,
per PrismarineJS/mineflayer#3888's proven method for the same bug class at
protocol 775) to get the true addPacket() registration order for both
play.toClient (144 packets) and play.toServer (69 packets), then
programmatically realigned the existing packet name tables against that
ground truth, preserving names for unchanged packets and identifying
genuinely new ones with no prior schema:

- clientbound: add_transient_block, swing_animation, and post_effects
  (the same new packet from the configuration-state fix, now also sent
  in play state and copied into play.toClient.types)
- serverbound: punch (replaces the old arm_animation/swing packet) and
  spectator_action (new OptionalInt entity id, distinct from the existing
  teleport_to_entity packet, which keeps the old "spectate" semantics)

Field layouts for the new packets were read directly from each class's
STREAM_CODEC via javap rather than guessed from wire bytes.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ortation schema

Found live-testing against a 26.3 Realm right after the play-state packet
ID drift fix (previous commit): the bot entered play, correctly parsed the
join-game and a wide range of world/entity packets, then got kicked with
"Failed to decode packet 'serverbound/minecraft:accept_teleportation'" the
first time it echoed a teleport confirmation back.

Decompiling ServerboundAcceptTeleportationPacket from the 26.3 server jar
shows Mojang widened this packet beyond the old single teleportId varint -
it now also carries the x/y/z/yRot/xRot being confirmed. protocol.json
still only declared teleportId, so the fields minecraft-protocol's compiler
had never seen in this schema were of course not on the wire the server
required, and it rejected the payload as malformed rather than an unknown
extra field.

Companion fix in mineflayer's physics.js populates the new fields; sending
them is a no-op on older protocol versions since protodef only serializes
fields declared for the running schema.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Found live-testing against a 26.3 Realm: after the play-state ID and
teleport_confirm fixes (previous two commits), the bot got much further -
correctly parsed login and dozens of packet types, including block entities
with legible NBT (sign text decoded perfectly) - but crashed in
prismarine-chunk's loadParsedLight with a light-section array coming up
far short of what the corresponding mask claimed.

Decompiled ByteBufCodecs.BIT_SET from the official 26.3 server jar (the
codec used for skyLightMask/blockLightMask/emptySkyLightMask/
emptyBlockLightMask in ClientboundLightUpdatePacketData): it now calls
FriendlyByteBuf.readByteArray()/writeByteArray() + BitSet.valueOf(byte[]),
not the varint-count-of-longs encoding every other supported version uses
(confirmed against the still-correct 1.21.9/773 schema, which uses
readLongArray()/BitSet.valueOf(long[]) for the same codec). Manually
decoding a captured chunk packet byte-for-byte confirmed it: reading the
masks as longs produced impossible bit positions (up to 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.

Companion prismarine-chunk fix (BitArray.fromByteArray, version-gated to
26.3+) is in the pc-26.3 branch there.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Found live-testing mineflayer against a local 26.3 server: decompiling
ServerGamePacketListenerImpl showed the server only clears its per-tick
receivedPositionThisTick/receivedMovementThisTick bookkeeping when it
receives a serverbound tick_end packet (handleClientTickEnd). A client
that never sends tick_end gets that flag stuck true after its first
position-bearing move packet, so the *second* one ever sent -- no
matter how much later -- gets it kicked with
multiplayer.disconnect.invalid_player_movement.

The tick_end packet (empty container, protocol name "tick_end") has
existed in the wire protocol since 1.21.3, but nothing in prismarine
land currently sends it. Add a feature flag so client implementations
can gate sending it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
DallasCarraher and others added 14 commits September 18, 2026 10:38
… fields

Per review on PrismarineJS#1301 (@maebahesioru, verified against a live Paper
26.3-8-dev / protocol 777 server and by decompiling paper-26.3.jar):

- packet_login (play/toClient) was missing onlineMode: bool, added by
  26.3 between worldState and enforcesSecureChat. Every login packet
  was under-reading by exactly 1 byte without it.

- packet_advancements (play/toClient) advancementMapping entries are
  now PositionedAdvancement records: appended x: f32 and y: f32 after
  sendsTelemtryData. Without them the packet over-read badly.
rel_entity_move / entity_move_look / sync_entity_position all crashed with
"Chunk size is N but only M was read" / PartialReadError once more than one
entity was nearby, because 26.3 replaced the old flat delta encodings with
new ones (decompiled from the real 26.3 server jar):

- ClientboundMoveEntityPacket (rel_entity_move / entity_move_look): the old
  3x-i16 dX/dY/dZ is gone. It's now a packed `properties` varint (bit 0 =
  onGround, remaining bits = stepCount via VecDelta's packProperties/
  unpackStepCount) followed by either the old flat 3x-i16 format when
  stepCount <= 0, or `stepCount` chained {ticks: varint, dX, dY, dZ: i16}
  DeltaStep entries when an entity's position wasn't sent every tick. A
  lone, regularly-ticked entity almost always hits the stepCount<=0 path,
  which is why this needed several nearby mobs/players to reproduce.
  Handled via a new custom protodef type (`entityDelta`, registered in
  node-minecraft-protocol) since the sub-count depends on a runtime-derived
  value (properties >>> 1), which plain declarative container/switch can't
  express.

- ClientboundEntityPositionSyncPacket (sync_entity_position): the old flat
  x/y/z/dx/dy/dz fields are gone. `position` is now a PositionPath: a
  varint type discriminator (0 = Linear, an absolute x/y/z f64) or (1 =
  Stepped, a varint-counted list of {x, y, z: f64, tickOffset: varint}
  absolute-position steps). Unlike VecDelta this carries full double
  positions per step, not fixed-point shorts, so it's expressed with plain
  declarative mapper+switch+array, no custom type needed.

Confirmed via `javap -c -p` on VecDelta, VecDelta$Stepped$DeltaStep,
ClientboundMoveEntityPacket(.Pos/.PosRot), PositionPath(.Linear/.Stepped),
PositionStep and their STREAM_CODECs in the real 26.3 server jar.
protodef's container SizeOf compiler can only inline an `anon: true` field
when its type is a literal inline ["container", ...] or ["switch", ...]
array (see containerInlining() in protodef's compiler-structures.js) --
not a bare string reference to a registered native type, even a
container-shaped one. Referencing the custom `entityDelta` type as an anon
field blew up the compiled protocol with "Cannot inline anonymous type:
entityDelta" as soon as a client actually connected (caught by testing
against a local 26.3 server with multiple moving entities, not just
unit-testing the type's read/write/sizeOf in isolation).

Give it a real field name ("move") instead: packet_rel_entity_move /
packet_entity_move_look now have `move: { onGround, steps }` rather than
flattened onGround/steps fields at the packet root. Paired with the
mineflayer change reading packet.move.steps instead of packet.steps.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Follow-up to 2fc2152 (fix packet_login onlineMode and packet_advancements
position fields). That commit correctly identified that advancement entries
now carry an x/y position pair, but placed it wrong: it added x/y *inside*
the Advancement container (after sendsTelemtryData) while *also* leaving the
pre-26.3 xCord/yCord fields inside displayData. That duplicate/misplaced
pair caused catastrophic misalignment on the next advancements packet
(PartialReadError: string field expecting a size >1MB), since every
Advancement carried two extra floats that aren't actually on the wire there.

Root cause, decompiled from the real 26.3 server jar
(ClientboundUpdateAdvancementsPacket, $PositionedAdvancement,
AdvancementHolder, Advancement, DisplayInfo, AdvancementRequirements,
AdvancementProgress, CriterionProgress STREAM_CODECs):

- ClientboundUpdateAdvancementsPacket.added is a
  List<PositionedAdvancement>, not a map keyed by id directly.
- PositionedAdvancement.STREAM_CODEC = composite(AdvancementHolder, x: f32,
  y: f32) -- x/y are siblings of the advancement itself, not fields inside
  it.
- AdvancementHolder.STREAM_CODEC = composite(id: Identifier, value:
  Advancement) -- matches the existing key/value entry shape.
- Advancement.STREAM_CODEC only sends 4 fields: parent (optional
  Identifier), display (optional DisplayInfo), requirements
  (AdvancementRequirements), sendsTelemetryEvent (bool). rewards/criteria/
  name are server-only and never hit the wire.
- DisplayInfo.STREAM_CODEC has no x/y at all anymore (title, description,
  icon, type, flags int, optional background identifier) -- the xCord/yCord
  fields inside displayData are stale leftovers from an older MC version's
  layout and don't exist on 26.3's wire format.
- AdvancementRequirements (array<array<string>>), AdvancementProgress
  (map<string, CriterionProgress>), and CriterionProgress (option<Instant>)
  were also checked against their STREAM_CODECs and match the existing
  requirements/progressMapping/criterionProgress schema, so those were left
  alone.

Fix: remove xCord/yCord from inside displayData, and move x/y out of the
advancementMapping entry's `value` container to be siblings of `key`/
`value` at the entry level, matching PositionedAdvancement{advancement:
{id, value}, x, y}.

Note: this commit only touches the packet_advancements region. The working
tree also has unrelated in-progress changes to the metadata_entry switch
table (recipe_book_add/entity_metadata work, a separate concurrent task) --
staged and committed this fix as an isolated blob built from HEAD plus only
this change, to avoid stepping on that work.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ale dataPaths row

dataPaths.json's pc["26.3"].entities pointed at pc/26.1 — two versions stale, not
even pc/26.2. Since 26.1->26.2 already shifted 28 entity internalIds (including
player 155->156) from newly inserted entity types, and 26.3 sits two versions past
that, the stale pointer meant mineflayer's entityDataByInternalId table looked up
the wrong internalId for every spawn_entity packet: player entities were never
recognized as type 'player', so bot.players[username].entity never linked up.
Symptom: "Can't see player X nearby" even standing right next to them.

Root cause confirmed by decompiling the 26.3 server jar's
net.minecraft.world.entity.EntityTypes static initializer (the actual entity
registration order, not the alphabetical EntityTypeIds constants) via javap
bytecode. Diffing that 161-entry registration order against pc/26.2's 158-entry
entities.json shows a clean insertion-only diff: 3 new entities (cushion,
poplar_boat, poplar_chest_boat), zero removals, zero reordering elsewhere. player
moves from internalId 156 (26.2) to 159 (26.3). New entities' dimensions/category/
metadata were read from their EntityType.Builder registration calls and
defineSynchedData bytecode in the same decompile.

Also audited the rest of the pc["26.3"] dataPaths row: it was a verbatim copy of
the pc["26.1"] row with only protocol/version bumped, missing the wave of updates
pc["26.2"]'s row already picked up from 26.1 (attributes, blocks, items, biomes,
blockCollisionShapes, blockLoot, commands, entityLoot, foods, language,
loginPacket, materials, particles, recipes, sounds, tints, windows). Repointed all
of those to pc/26.2 as a strict improvement (1-version-stale using already-known-
good data, vs. 2-versions-stale) without decompile-regenerating each one; left
effects/enchantments/instruments/mapIcons alone since pc/26.2's row also keeps
those at their older pointers, suggesting they're legitimately unchanged.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…icle registry IDs, and world_particles layout

Four related protodef bugs found live against a real 26.3 Realm and a local
offline-mode 26.3 test server (DEBUG=minecraft-protocol), all traced to the
same root cause: several enum/registry orderings drifted in 26.3 and the
schema still used their pre-26.3 numbering.

1. entityMetadataEntry's `type` mapper (byte/int/.../particles/...) was the
   pre-26.3 EntityDataSerializers order. Decompiling
   net.minecraft.network.syncher.EntityDataSerializers's static initializer
   (registerSerializer() call order) shows optional_uuid was removed entirely
   in 26.3 and replaced by optional_living_entity_reference (still wire-
   compatible, still a plain UUID), and boolean/rotations/block_pos/
   optional_block_pos/direction/block_state/optional_block_state/particle/
   particles were all reshuffled around it. Renumbered all 44 entries and
   added the two new ones (optional_living_entity_reference, dye_color).
   This was the direct cause of the reported
   "Chunk size is 18 but only 14 was read" on a sonic_boom particles entry.

2. SlotDisplay's "tag" variant (used inside RecipeDisplay ingredients and
   packet_recipe_book_add's craftingRequirements) was typed as a plain
   "string", but TagSlotDisplay.STREAM_CODEC decompiles to
   ByteBufCodecs.holderSet(Registries.ITEM) -- the same registryEntryHolderSet
   (IDSet) encoding used everywhere else, not a bare tag-name string. Fixed
   to "IDSet". This was the actual cause of the reported
   "PartialReadError ... reading VarInt" on packet_recipe_book_add: a
   0x00 discriminator byte (IDSet's "named tag" case) was being misread as a
   zero-length string, shifting every subsequent SlotDisplay's type byte by
   one field.

3. The "Particle" container's own `type` mapper (angry_villager/block/.../
   sonic_boom/...) was also pre-26.3: decompiling
   net.minecraft.core.particles.ParticleTypes's static initializer
   (registerXxx() call order against BuiltInRegistries.PARTICLE_TYPE) gives a
   completely different, longer ordering -- 128 entries vs the old ~117, with
   new geyser/geyser_base/geyser_poof/geyser_plume/sulfur_bubbles/
   noxious_gas(_cloud)/red_poplar_leaves/orange_poplar_leaves/
   yellow_poplar_leaves/sulfur_cube_goo types inserted and
   trial_spawner_detected_player(_ominous) renamed to
   trial_spawner_detection(_ominous). sonic_boom moved 28->35, note moved
   58->68 (a byte that used to mean "note" now means "vibration"), etc.
   Rebuilt the full 128-entry mapper from the decompiled order and added
   data-switch cases for the four new geyser variants (GeyserParticleOptions/
   GeyserBaseParticleOptions STREAM_CODECs: waterBlocks:i32, plus
   burstImpulseBase:f32 for the non-plain geyser variants). This mapper is
   shared by entity_metadata's particle/particles fields and by
   packet_world_particles, so it was silently corrupting both.

4. packet_world_particles (ClientboundLevelParticlesPacket) itself had a
   stale pre-26.x field layout: `particle` used to be the last field with
   flat offsetX/Y/Z + a single velocityOffset float + an i32 amount. The
   26.3 STREAM_CODEC (decompiled composite(...)) puts `particle` FIRST, has
   six float fields (xDist/yDist/zDist/xMaxSpeed/yMaxSpeed/zMaxSpeed, not
   four), amount is a varint not i32, and there's a new trailing
   randomizationType enum (default/alternative/alternative_with_speed) that
   didn't exist before. Found live once particle mapper fix PrismarineJS#3 above stopped
   masking it (was reading a real "vibration" particle's sub-payload as if
   it were the void "note" particle, corrupting everything after it).

All four confirmed against the real 26.3 server jar
(net.minecraft.network.syncher.EntityDataSerializers,
net.minecraft.core.particles.ParticleTypes/ParticleType/GeyserParticleOptions/
GeyserBaseParticleOptions, net.minecraft.world.item.crafting.display.
SlotDisplay$TagSlotDisplay, net.minecraft.network.protocol.game.
ClientboundLevelParticlesPacket/$RandomizationType via javap) and re-verified
live: a bot connected to a local offline-mode 26.3 test server now parses
packet_recipe_book_add (crafting table recipe with a #minecraft:planks IDSet
ingredient), and packet_world_particles for note/sonic_boom/item/vibration
particles (the last carrying a live entity-tracking vibration source), with
zero PartialReadError/chunk-size-mismatch console spam across a multi-minute
session with several mobs (warden, sniffer, breeze, copper_golem, villager)
alive.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…n/max

StatePropertiesPredicate$RangedMatcher.minValue/maxValue are each
Optional<String> (ByteBufCodecs.optional(STRING_UTF8): a presence bool
then the string), confirmed by decompiling the real 26.3 server jar.
The schema had them as bare strings, so any block-property range
matcher missing a min or max (very common - e.g. a single-sided
"waterlogged" check) desynced the byte stream one bit early, cascading
into the following nbt field as a bogus huge array-length read
("array size is abnormally large") - same failure class as the
earlier packet_advancements bug in this PR.

Reproduced live against a running 26.3 server: a dropped/held item
carrying can_place_on with an open-ended waterlogged range (minValue
present, maxValue absent) now decodes cleanly in both entity_metadata
and set_slot, with zero PartialReadError and a stable connection
afterward. Verified independently with a schema-level round trip
(createPacketBuffer/parsePacketBuffer) covering minValue-only,
maxValue-only, and neither-present cases.
…or the 121 new items and 90 new blocks

26.3's dataPaths row pointed these at pc/26.2, but 26.3 inserted poplar wood,
concrete/wool slabs and stairs, cushions, maps, etc. mid-registry, shifting IDs.
IDs/states come from the server jar's registry report; attributes for new
entries are approximated from analogues.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…mponentType/pot_decorations

Two more wire-ID bugs, both found live via PACKET_DEBUG capture of dropped
packets against a real 26.3 Realm and local-test-server-26.3, and both
confirmed by javap on server-26.3.jar.

1. entityMetadataEntry `type` mapper: the previous fix numbered the serializers
   by *declaration* order in EntityDataSerializers (which includes helper
   fields and puts BLOCK_STATE/PARTICLE early). Wire IDs follow the
   registerSerializer(...) *call* order instead: boolean=8, rotations=9,
   block_pos=10 ... optional_living_entity_reference=13, block_state=14,
   optional_block_state=15, particle=16, particles=17, villager_data=18,
   optional_unsigned_int=19, pose=20, ..., optional_global_pos=33. Symptom was
   PartialReadError on every entity_metadata packet for villagers/players
   (type 18 read as optional_global_pos), dropping names/health/pose.

2. SlotComponentType: 26.3 registers 122 data components, the schema had 110,
   so every ID from 40 on was shifted. Reordered to the DataComponents
   register() call order. Added codecs for the new components whose
   STREAM_CODEC is fully readable from bytecode (attack_animation and
   interact_animation reuse SwingAnimation, cushion/color, waxed, villager_food,
   mob_visibility, sign_text_front/back, sulfur_cube_content) and dropped
   map_color, which 26.3 no longer registers. pot_decorations is now four
   Optional<ItemStackTemplate> fields (was an array of item ids); this was the
   direct cause of the PartialReadError on the 72 KB advancements packet, whose
   decorated-pot icon carries that component.

   Still read as void (no codec yet; they use nested loot-number providers /
   larger schemas): block_transformer, compostable, cooking_fuel, brewing_fuel,
   provides_pottery_pattern.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ort features.json

data/pc/26.3 was pointing its protocol source at the shared pc/latest/proto.yml,
which had never been updated for any of the 26.3-era fixes (SlotComponentType,
entity_metadata ordering/naming, ItemBlockPredicate, particle registry, the
stepped entity-move/position-sync encoding, packet_teams/packet_advancements/
packet_map_chunk layout, and the play/configuration packet ID insertions) —
every one of those had only ever been hand-patched into protocol.json, so
'npm run build' regenerated a completely different (stale) file and CI's
"protocol.json is desynced from yaml" check failed.

Froze data/pc/26.3/proto.yml from a copy of pc/26.2's (last known-good, in-sync)
proto.yml and applied each documented 26.3 fix to it directly, repointed
dataPaths.json's pc/26.3 "proto" entry at pc/26.3 instead of pc/latest, and left
pc/latest untouched. protocol.json is now the direct 'npm run build' output of
this frozen yaml.

Also fixed the protodef-validator failure on packet_rel_entity_move/
packet_entity_move_look's new entityDelta type (needs a `types` entry so the
validator's protocol-schema pass registers it, even though it has no compiled
body of its own — the real reader lives in node-minecraft-protocol), and
resorted features.json (clientTickEndPacket was appended out of alphabetical
order).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WSuum5hJoePw4kJdMjxdKx
The earlier light-mask fix (count-of-longs -> count-of-bytes) only retyped
the four mask fields on packet_map_chunk. packet_update_light still read
skyLightMask/blockLightMask/emptySkyLightMask/emptyBlockLightMask as
array<i64>, so every standalone light update was misparsed: either a
PartialReadError ("Chunk size is N but only M was read"), or, when the
misread happened to fit, i64 elements (protodef SignedBigInt, whose
valueOf() is a BigInt) reached prismarine-chunk's fromByteArray and threw
"Cannot mix BigInt and other types". Both are connection-fatal in practice:
the client stops servicing traffic and the keepalive times out.

javap on server-26.3.jar: ClientboundLightUpdatePacket and
ClientboundLevelChunkWithLightPacket both embed
ClientboundLightUpdatePacketData.STREAM_CODEC, whose four masks are all
ByteBufCodecs.BIT_SET (ByteBufCodecs$15: FriendlyByteBuf.readByteArray ->
BitSet.valueOf(byte[])). It is the only BIT_SET user in the protocol
package, so no other packet needs the same change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CI on this PR (which tests the merge with master) failed "26.1 / protocol.json
is desynced from yaml". The 26.2 commits on this branch froze
data/pc/26.1/proto.yml from pc/latest and repointed 26.1 at it, but master
has since changed 26.1's protocol.json by editing pc/latest/proto.yml
(PrismarineJS#1278 InteractionHand main_hand/off_hand mappers, PrismarineJS#1295 entity_action
enum names). The merge took master's newer JSON alongside this branch's
older frozen yaml.

Applied master's pc/latest/proto.yml diff since the merge base to
pc/26.1/proto.yml (it was an identical copy) and regenerated. 26.1's
protocol.json is now byte-identical to master's.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Brings the frozen 26.2 and 26.3 proto.yml in line with what master did to
pc/latest (and what the previous commit ported to 26.1):

- PrismarineJS#1278: `hand` on open_book, arm_animation, block_place and use_item is
  now a main_hand/off_hand mapper instead of a bare varint.
- PrismarineJS#1295: entity_action actionId names follow Mojang's
  ServerboundPlayerCommandPacket.Action (leave_bed -> stop_sleeping,
  start/stop_horse_jump -> start/stop_riding_jump, open_vehicle_inventory ->
  open_inventory, start_elytra_flying -> start_fall_flying).

Wire format is unchanged: numeric writes still pass through the mappers,
and the start/stop_sprinting names are the same. The resulting packet
definitions are identical to 26.1's. mineflayer's elytraFly still sends
'start_elytra_flying' under entityActionUsesStringMapper, which is the
same break master already has on 26.1 and is handled by
PrismarineJS/mineflayer#4120.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
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.

4 participants