fix(physics): port retail stair edge backprobe
This commit is contained in:
parent
5a0f9868a6
commit
2dcb4f1d94
6 changed files with 218 additions and 6 deletions
108
docs/research/2026-07-31-271-stair-side-slide-capture.md
Normal file
108
docs/research/2026-07-31-271-stair-side-slide-capture.md
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
# #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.
|
||||
Loading…
Add table
Add a link
Reference in a new issue