Skip to content

Expand the step-up probe by the requested movement - #140

Open
aibengineering wants to merge 1 commit into
PrismarineJS:masterfrom
aibengineering:codex/step-up-probe-requested-movement
Open

Expand the step-up probe by the requested movement#140
aibengineering wants to merge 1 commit into
PrismarineJS:masterfrom
aibengineering:codex/step-up-probe-requested-movement

Conversation

@aibengineering

@aibengineering aibengineering commented Sep 4, 2026

Copy link
Copy Markdown

The box that decides how far a step may rise is expanded along the movement that collision already clamped, rather than the movement that was requested.

That box exists to reach into the cell being entered, so a ceiling over the destination limits the rise. Built from the clamped movement it collapses to the player's own box whenever the player is flush against the obstacle, because the clamped movement is then exactly zero. The rise is limited by whatever stands over the player instead, so with open space overhead it takes the whole stepHeight and strikes the ceiling over the destination.

How we hit it

A bot walking a two-block-high passage on 1.21.4 stopped dead against a moss carpet and could never enter that cell, however long it pushed. Placing a block above the bot's own head made the identical move succeed, which isolated the probe box: a block over your head cannot help you walk forward.

Why this is the right logic

Vanilla expands by the requested movement. Checked against the 1.21.4 server jar, disassembled with javap and read against Mojang's official server mappings for that version (server.txt, sha1 0b1e60cc509cfb0172573ae56b436c29febbc187), which map Entity to bum, Entity.collide(Vec3) to bum.a(fbb), AABB.expandTowards(double,double,double) to faw.b(DDD) and Vec3.x/y/z to fbb.d/e/f.

In bum.a(fbb) the parameter in local 1 is the requested movement and local 4 holds the result of collideBoundingBox; the two are compared per axis at offsets 45 to 91 to decide whether a step is worth trying. The step probe is then built at offsets 179 to 197 as

aABB2.expandTowards(vec3.x, maxUpStep(), vec3.z)

reading local 1, the requested movement, at offsets 181 and 190. The collided vector is used only for those comparisons and for the aabb.move(0, vec32.y, 0) at offset 170.

queryBB a few lines above this hunk already expands by oldVel for the same reason, so the two were inconsistent with each other as well as with vanilla.

Notes

test/step.test.js covers a one-sixteenth block in a two-high passage entered from a standstill, and asserts the move does not depend on what stands over the player. It fails before the change and passes after. The change can only lower the permitted rise, never raise it, so a candidate it now rejects was one stepping into a space the probe reports as occupied.

@aibengineering
aibengineering force-pushed the codex/step-up-probe-requested-movement branch from 019770b to 23003a6 Compare September 4, 2026 05:48
The box that decides how far a step may rise was expanded along the movement
collision had already clamped, rather than the movement that was asked for.

That box exists to reach into the cell being entered, so that a ceiling over
the destination limits the rise. Built from the clamped movement it collapses
to the player's own box whenever the player is flush against the obstacle,
because the clamped movement is then exactly zero. The rise is limited by
whatever stands over the player instead, so with open space overhead it takes
the whole 0.6 step height and strikes the ceiling over the destination. In a
two-high passage a player touching a carpet can never step on to it, and never
will, since standing still does not change any of the inputs.

Vanilla expands by the requested movement. Checked against the 1.21.4 server
jar, disassembled with javap and read against Mojang's official server
mappings for that version (piston-data server.txt,
sha1 0b1e60cc509cfb0172573ae56b436c29febbc187), which map
net.minecraft.world.entity.Entity to bum, Entity.collide(Vec3) to bum.a(fbb),
AABB.expandTowards(double,double,double) to faw.b(DDD) and Vec3.x/y/z to
fbb.d/e/f. In bum.a(fbb) the parameter in local 1 is the requested movement
and local 4 holds the result of collideBoundingBox; the two are compared per
axis at offsets 45 to 91 to decide whether a step is worth trying. The step
probe is then built at offsets 179 to 197 as

    aABB2.expandTowards(vec3.x, maxUpStep(), vec3.z)

reading local 1, the requested movement, at offsets 181 and 190. The collided
vector in local 4 is used only for those comparisons and for the
aabb.move(0, vec32.y, 0) at offset 170. `queryBB` a few lines above this hunk
already expands by `oldVel` for the same reason, so the two were inconsistent
with each other as well as with vanilla.

Observed against a 1.21.4 server: a bot flush against a moss carpet under a
two-high ceiling could not move at all, for as long as it kept trying. Placing
a block above its own head made the same move succeed, which is what isolated
the probe box, since a block over your head cannot help you walk forward.

The change can only lower the permitted rise, never raise it, so a candidate it
now rejects was one stepping into a space the probe reports as occupied.
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