Skip to content

Fix LpVec3 entity velocity decoding (big-endian word + notch units)#1494

Open
atiweb wants to merge 1 commit into
PrismarineJS:masterfrom
atiweb:fix/lpvec3-velocity-encoding
Open

Fix LpVec3 entity velocity decoding (big-endian word + notch units)#1494
atiweb wants to merge 1 commit into
PrismarineJS:masterfrom
atiweb:fix/lpvec3-velocity-encoding

Conversation

@atiweb

@atiweb atiweb commented Jun 15, 2026

Copy link
Copy Markdown

Problem

src/datatypes/lpVec3.js (added in #1453 for the 1.21.9+ entity-velocity encoding) decodes every entity velocity incorrectly. Two separate issues:

1. Wrong endianness. The 32-bit word is read with readUInt32LE and written with a little-endian writeUInt32LE/writeUInt16LE layout, but Minecraft's net.minecraft.network.LpVec3 reads/writes it with FriendlyByteBuf.readUnsignedInt / writeInt, which are big-endian. The decoded packet is still the correct length, so no parse error is raised — the velocity is just silently wrong. The existing test only covers the zero vector, which is a single 0 byte and therefore endian-agnostic, so this was never caught.

2. Wrong units. entity_velocity/spawn_entity use lpVec3 on >= 1.21.9 and vec3i16 on older versions, and consumers apply fromNotchVelocity (÷ 8000) to packet.velocity uniformly (e.g. mineflayer lib/plugins/entities.js, PrismarineJS/mineflayer#3839). vec3i16 yields raw 1/8000-block-per-tick units, but lpVec3 yielded raw blocks-per-tick — i.e. 8000× too small.

Together these break entity velocity / knockback on 1.21.9–1.21.11. See PrismarineJS/mineflayer#3887 ("Bot freezes in mid-air after taking knockback on 1.21.11").

Fix

  • Read and write the 32-bit word big-endian, and rewrite the write path so the bytes match the on-wire layout packed = c << 16 | b << 8 | a (byte, byte, int32 big-endian).
  • Scale the decoded vector to 1/8000-block-per-tick units to match vec3i16, so the existing fromNotchVelocity consumers work unchanged across all versions.

Validation

  • New test/lpVec3Test.js decodes and round-trips velocity payloads captured from a real vanilla 1.21.11 server (e.g. f9ff7ffeebed → ≈ (0, -0.078, 0) blocks/tick) plus the zero-vector single-byte case.
  • Verified live against a 1.21.11 server with mineflayer: a piglin brute's knockback now decodes to (0.087, 0.177, -0.258) blocks/tick and the bot takes knockback normally instead of freezing in mid-air.

Reference: net.minecraft.network.LpVec3.read = readUnsignedByte, readUnsignedByte, readUnsignedInt; the resulting Vec3 is the entity's blocks-per-tick movement.

@atiweb atiweb closed this Jun 15, 2026
@atiweb atiweb reopened this Jun 15, 2026
The 32-bit word was read/written little-endian, but Minecraft's LpVec3 uses
FriendlyByteBuf.readUnsignedInt/writeInt (big-endian), so every entity velocity
decoded to a wrong but same-length (hence silent) value. Also scale the decoded
vector to 1/8000-block-per-tick units to match vec3i16, so fromNotchVelocity()
consumers work uniformly across versions.

Fixes broken entity velocity / knockback on 1.21.9-1.21.11 (mineflayer#3887).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@atiweb atiweb force-pushed the fix/lpvec3-velocity-encoding branch from 157649e to 64c8cee Compare June 15, 2026 16:25
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