108 lines
3.8 KiB
Markdown
108 lines
3.8 KiB
Markdown
# #271 — Stair-side uphill reversal capture
|
||
|
||
**Date:** 2026-07-31
|
||
|
||
**Status:** closed; retail control flow restored and user live gate passed
|
||
|
||
## Symptom
|
||
|
||
When the local player ran diagonally uphill while pressing into the side of
|
||
an outdoor staircase, the character could suddenly move backward and rapidly
|
||
slide to the bottom. The symptom was intermittent because it required the
|
||
forward candidate to hit the side wall while the step-down recovery crossed a
|
||
tread edge.
|
||
|
||
This is not an RDP, render-rate, animation, or gravity symptom. It reproduced
|
||
inside the pure Core collision resolver from one captured input frame.
|
||
|
||
## Live evidence
|
||
|
||
The bounded capture is under the ignored local artifact pointer:
|
||
|
||
`artifacts/issue271-stair-side/LATEST.txt`
|
||
|
||
It contains 677 local-player physics quanta plus the matching resolver stream.
|
||
The first decisive frame is quantum 310:
|
||
|
||
```text
|
||
current = (133.03775, 75.53931, 59.608147)
|
||
target = (133.33783, 76.42308, 59.608147)
|
||
input = forward + run
|
||
result = (133.18779, 75.19872, 59.316677)
|
||
normal = (-1, approximately 0, approximately 0)
|
||
```
|
||
|
||
The X side-wall collision was valid, but the tangential Y component reversed:
|
||
an uphill request of `+0.88377` produced `-0.34059`. Three frames later,
|
||
quantum 313 snapped from Z `59.52598` to terrain Z `58.005`. A second attempt
|
||
reproduced the same family at quanta 479–482, falling from Z `60.96376` to
|
||
`58.005`.
|
||
|
||
## Retail oracle
|
||
|
||
Named retail:
|
||
|
||
- `CTransition::edge_slide` at `0x0050B3D0`
|
||
- current-walkable branch at `0x0050B44A`
|
||
- no-walkable back-probe at `0x0050B458–0x0050B50F`
|
||
- `SPHEREPATH::precipice_slide` at `0x0050CC80`
|
||
|
||
Retail tests only the current `SPHEREPATH::walkable` pointer. If it is null,
|
||
retail:
|
||
|
||
1. offsets the failed candidate back to the current sphere center;
|
||
2. runs `step_down` there to rediscover the surface actually under the mover;
|
||
3. restores the failed candidate;
|
||
4. runs `precipice_slide` against the newly discovered polygon; or
|
||
5. returns `COLLIDED_TS` when the back-probe found no walkable polygon.
|
||
|
||
Retail has no substitution of an older saved walkable polygon in either null
|
||
case.
|
||
|
||
## ACDream divergence and root cause
|
||
|
||
`EdgeSlideAfterStepDownFailed` previously called
|
||
`SpherePath.RestoreLastWalkable()`:
|
||
|
||
- before deciding whether to enter the retail back-probe; and
|
||
- again when the back-probe found no current walkable polygon.
|
||
|
||
`LastWalkable` is a separate ACDream history used by the still-open
|
||
CliffSlide compatibility path. At a staircase side wall it could describe the
|
||
preceding tread rather than the surface below the current player position.
|
||
Promoting it into the current slot bypassed retail's back-probe.
|
||
`PrecipiceSlide` then projected the failed forward candidate along the stale
|
||
tread edge, producing the backward/downhill displacement seen in the capture.
|
||
|
||
The fix removes both stale-history promotions from the edge-slide dispatch.
|
||
Current walkable state still takes retail's direct precipice path; absent
|
||
state now always takes retail's current-position back-probe.
|
||
|
||
## Deterministic regression
|
||
|
||
`Issue185OutdoorStairsSeamReplayTests` reuses the captured
|
||
`0x01000AC5` staircase collision fixture and the exact quantum-310 position,
|
||
contact plane, movement delta, player flags, and 1.5 m Setup step-down height.
|
||
|
||
Pre-fix:
|
||
|
||
```text
|
||
out = (133.187790, 75.346481, 59.430882)
|
||
```
|
||
|
||
Fixed:
|
||
|
||
```text
|
||
out = (133.187790, 76.078186, 60.016247)
|
||
```
|
||
|
||
The regression requires meaningful positive uphill progress and forbids a
|
||
downhill Z displacement. The complete Core Release suite passes 4,108 tests /
|
||
2 skips; the complete Release solution passes 10,062 tests / 5 skips.
|
||
|
||
## Live acceptance
|
||
|
||
The user repeatedly ran uphill while pressing into both sides of the affected
|
||
staircase. Movement remained stable and the former rapid downhill reversal did
|
||
not recur. The client then closed through the normal logout path, with ACE
|
||
confirming graceful logout.
|