104 lines
4 KiB
Markdown
104 lines
4 KiB
Markdown
# Issue #269 — slope-stop capture and retail correction
|
||
|
||
**Date:** 2026-07-31
|
||
**Status:** implemented; user live gate passed
|
||
**Scope:** landing-bounce follow-up, `CTransition::validate_transition`
|
||
|
||
## Symptom
|
||
|
||
After the retail 5%-elasticity landing reflection was restored for #265,
|
||
the character could retain too much downhill speed after landing on a
|
||
walkable slope. The user described the residual as “slides too far on
|
||
landing.”
|
||
|
||
## ACDream live capture
|
||
|
||
`ACDREAM_CAPTURE_PLAYER_QUANTA=<jsonl-path>` records the local player's
|
||
complete admitted object quantum without changing simulation order:
|
||
|
||
1. quantum start;
|
||
2. root/PositionManager composition;
|
||
3. pre- and post-`UpdatePhysicsInternal`;
|
||
4. transition result;
|
||
5. final collision-response commit.
|
||
|
||
The accepted repro contained 2,184 quanta. The clearest landing was:
|
||
|
||
| Quantum | Event | Velocity |
|
||
|---|---|---|
|
||
| 1740 | final airborne quantum | `(-12.316, 8.187, -26.266)` |
|
||
| 1741 | slope collision, normal `(-0.236, 0.236, 0.943)` | |
|
||
| 1741 post-response | correct 5% reflect | `(-17.391, 13.262, -6.576)` |
|
||
| 1742–1758 | still Contact + OnWalkable, no new collision normal | velocity unchanged |
|
||
| 1759+ | contact relationship changes | friction finally begins decaying |
|
||
|
||
The reflected velocity had `dot(v, normal) = +1.0252`: it pointed away
|
||
from the slope. Retail `calc_friction` correctly skips while this value is
|
||
at least `0.25`, so friction was not the defect. ACDream was repeatedly
|
||
restoring the remembered slope plane and re-grounding the body without
|
||
performing retail's accompanying velocity stop.
|
||
|
||
## Retail oracle
|
||
|
||
Named-retail:
|
||
|
||
- `CPhysicsObj::check_contact` `0x0050F5B0`
|
||
- `CPhysicsObj::get_object_info` `0x00511CC0`
|
||
- `CTransition::validate_transition` `0x0050AA70`
|
||
- `OBJECTINFO::kill_velocity` `0x0050CFE0`
|
||
|
||
The exact `validate_transition` order at
|
||
`0x0050AAED–0x0050AB42` is:
|
||
|
||
1. enter only for a non-OK collision/adjusted/slid result;
|
||
2. if `last_known_contact_plane_valid`, call
|
||
`OBJECTINFO::kill_velocity`;
|
||
3. test the current sphere center against the remembered plane using
|
||
`radius + 0.0002`;
|
||
4. restore the contact plane only when still within that distance;
|
||
5. later, at `0x0050ACFF`, overwrite last-known validity with final
|
||
contact-plane validity.
|
||
|
||
`OBJECTINFO::kill_velocity` calls
|
||
`CPhysicsObj::set_velocity({0,0,0}, 0)`. ACDream had ported the proximity
|
||
test and plane restore but omitted this call. It also allowed the
|
||
last-known plane to re-ground clean accepted moves, although retail only
|
||
consumes it in the non-OK recovery branch.
|
||
|
||
## Correction
|
||
|
||
`Transition.ValidateTransition` now:
|
||
|
||
- calls `ObjectInfo.StopVelocity()` before the remembered-plane
|
||
proximity/restore test on a non-OK recovery;
|
||
- performs that restore only in the retail branch;
|
||
- overwrites last-known validity from final contact validity, so a clean
|
||
move away cannot be re-grounded from stale memory.
|
||
|
||
The existing `PhysicsEngine.ResolveWithTransition` consumption of
|
||
`VelocityKilled` applies the zero to the canonical `PhysicsBody` before
|
||
the collision-response tail. The initial 5% landing reflection remains;
|
||
only a following collision recovery performs the retail stop.
|
||
|
||
## Gates
|
||
|
||
- New focused pins:
|
||
- collision recovery with a remembered plane kills velocity;
|
||
- clean advance with a remembered plane neither kills nor re-grounds.
|
||
- Full `AcDream.Core.Tests`: 4,107 passed / 2 skipped.
|
||
- Full `AcDream.Runtime.Tests`: 439 passed.
|
||
- `AcDream.App` Release build: 0 warnings / 0 errors.
|
||
- Complete Release suite: 10,061 passed / 5 skipped / 0 failed.
|
||
- User live gate: **PASS** — repeated slope jumps now settle correctly
|
||
(“Perfect! Works great!”).
|
||
|
||
## Diagnostic tools retained
|
||
|
||
- `tools/analyze_269_slope_stop_capture.py`
|
||
- `tools/cdb/run-issue269-slope-stop.ps1`
|
||
- `tools/cdb/issue269-slope-stop.cdb`
|
||
|
||
The cdb runner refuses to attach unless the live retail executable matches
|
||
the Sept 2013 named PDB. The locally installed 2015 retail executable does
|
||
not match; the static named-retail decode above is therefore the retail
|
||
oracle used for this correction.
|