docs(research): handoff prompt for #42 PhysicsEngine investigation
Self-contained next-session brief for the airborne XY drift follow-up. Captures: confirmed root cause (ResolveWithTransition, verified A/B), three ranked hypotheses for the in-sweep mechanism (initial-overlap depenetration on non-+Z terrain normal is leading), three fix paths in preference order, repro steps with terrain-slope direction-correlation test, and the acceptance criteria. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
b37b7137f6
commit
5cc281251a
1 changed files with 96 additions and 0 deletions
96
docs/research/2026-05-05-issue-42-handoff.md
Normal file
96
docs/research/2026-05-05-issue-42-handoff.md
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
# #42 follow-up — PhysicsEngine.ResolveWithTransition airborne XY drift
|
||||
|
||||
**Context:** L.3 motion port landed in this branch (commits `de129bc`
|
||||
`40d88b9` `2365c8c` `d57ace0` `c26bbbb` `b37b713`) — player-remote
|
||||
running/walking/strafing/NPCs all visually verified clean. M4 jump
|
||||
landing was fixed (CellId update). But that fix re-enabled
|
||||
`ResolveWithTransition` per-tick during airborne arcs and exposed a
|
||||
pre-existing PhysicsEngine bug: stationary jumps render with ~1 m
|
||||
horizontal offset from the actor's actual XY, then snap back on the
|
||||
next UM/UP.
|
||||
|
||||
**Confirmed root cause** (A/B-tested 2026-05-05): drift originates
|
||||
inside `ResolveWithTransition`, not from wire data, local Euler error,
|
||||
or stale velocity. With the sweep skipped, jumps render geometrically
|
||||
correct (but body falls through floor). With it enabled, jumps land
|
||||
correctly but show the drift. So the bug lives in the sweep.
|
||||
|
||||
## Most likely mechanism
|
||||
|
||||
**Initial-overlap depenetration along non-+Z terrain normal.** At
|
||||
jump start the collision sphere is touching the floor at body Z. Most
|
||||
outdoor terrain triangles have non-vertical normals (small horizontal
|
||||
component). The sweep's first-frame action is to resolve the
|
||||
penetration by separating the sphere along the contact normal — and
|
||||
on a tilted triangle that separation has horizontal magnitude. The
|
||||
body gets shoved sideways the first frame; the rest of the arc
|
||||
carries the offset.
|
||||
|
||||
Direction-correlation test: jump at multiple landblock positions; if
|
||||
drift direction varies with terrain slope orientation (not actor
|
||||
facing), this hypothesis is confirmed.
|
||||
|
||||
Other candidates ranked by probability:
|
||||
2. Step-down probe firing despite `isOnGround: false` parameter.
|
||||
3. EdgeSlide on near-vertical motion against near-vertical surface.
|
||||
|
||||
## Files to investigate
|
||||
|
||||
- `src/AcDream.Core/Physics/PhysicsEngine.cs` — `ResolveWithTransition`
|
||||
+ any internal `CTransition` / `find_valid_position` helpers. The
|
||||
initial-overlap depenetration path is the primary target.
|
||||
- Reference at `docs/research/named-retail/acclient_2013_pseudo_c.txt`:
|
||||
- `CTransition::find_valid_position` (called from `transition()`)
|
||||
- `SpherePath` initialization
|
||||
- Verbatim retail depenetration logic for airborne bodies
|
||||
|
||||
If our port differs from retail in this region, that diff is the bug.
|
||||
|
||||
## Fix paths (in order of preference)
|
||||
|
||||
**(a) Skip initial-overlap depenetration when airborne.** Gate the
|
||||
"separate from initial contact plane" step inside
|
||||
`ResolveWithTransition` on `isOnGround: true`. Trusts the previous
|
||||
tick's resolve to have left the body in a non-overlapping position.
|
||||
Most likely correct fix.
|
||||
|
||||
**(b) Zero step-up/down for airborne sweeps.** Pass
|
||||
`stepUpHeight: 0f, stepDownHeight: 0f` from
|
||||
`GameWindow.cs:6478+` when `rm.Airborne`. No side effects since
|
||||
airborne bodies don't step.
|
||||
|
||||
**(c) Stripped airborne sweep.** Replace the full sphere sweep with a
|
||||
simpler vertical sphere-vs-terrain intersection + wall-collision
|
||||
stop. Loses retail fidelity but eliminates all three mechanisms.
|
||||
Probably overkill if (a) or (b) suffices.
|
||||
|
||||
## Repro
|
||||
|
||||
1. Launch acdream + retail client side-by-side on local ACE
|
||||
(127.0.0.1:9000).
|
||||
2. Have a retail-controlled toon stand still on outdoor terrain.
|
||||
3. Jump in place.
|
||||
4. Observe acdream window: arc shows ~1 m XY offset, lands offset,
|
||||
snaps back on next inbound UM.
|
||||
|
||||
To verify hypothesis (1) specifically: repeat the jump on terrain
|
||||
patches with different visible slope orientations; if drift direction
|
||||
changes accordingly, depenetration is confirmed.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- Stationary jumps render at the actor's actual XY (no perceptible
|
||||
drift, no snap-back on next UM).
|
||||
- Wall-collision airborne still works (jumping into doorways, jumping
|
||||
puzzles where you have to thread between platforms or through arches).
|
||||
|
||||
## Operating notes
|
||||
|
||||
- This is a `PhysicsEngine` bug, not a motion-port bug. The L.3 work
|
||||
is done; this is a separate investigation.
|
||||
- The `[VU.WIRE]` instrumentation idea from #42's earlier draft can
|
||||
be skipped — we already proved wire data isn't the source via the
|
||||
A/B test.
|
||||
- cdb attach to retail (`docs/research/2026-05-04-l3-port/`-adjacent
|
||||
toolchain documented in CLAUDE.md) is available if comparing
|
||||
retail's airborne sweep behavior against ours becomes useful.
|
||||
Loading…
Add table
Add a link
Reference in a new issue