docs(research): expand #42 handoff prompt for fresh-session pickup
Replaces the original 96-line note with a detailed self-contained brief targeted at someone picking up #42 cold in a new session. Adds: - Explicit ruled-out list (wire data, Euler error, stale velocity, diagnostic instrumentation) — saves rediscovering dead ends. - The user's "buildings + jumping puzzles" constraint that rules out blanket sweep-disable. - Specific file/line targets in PhysicsEngine.cs (470, 478-491, 493-519, 521-530, 532, 534-558) and TransitionTypes.cs (786-846, 1305-1311) with a brief reading order. - Phase 1 / Phase 2 / Phase 3 investigation plan with concrete diagnostic harness (`ACDREAM_AIRBORNE_DIAG=1` + `[SWEEP]` log) and direction-correlation test. - Per-hypothesis fix paths so the agent doesn't re-derive them from the diagnosis. - Full acceptance criteria including build/test gates and visual test sequence (flat / hillside / running / doorway / puzzle / land). - Hard rules (don't blame ACE, don't disable sweep, don't touch L.3 motion code, don't reduce sphere dims, etc.). - cdb breakpoint recipe for retail-vs-acdream A/B comparison. - Pre-session reading list with line numbers. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
086e65dfe6
commit
ce638eb56f
1 changed files with 369 additions and 74 deletions
|
|
@ -1,96 +1,391 @@
|
||||||
# #42 follow-up — PhysicsEngine.ResolveWithTransition airborne XY drift
|
# Handoff prompt — fix #42 PhysicsEngine airborne XY drift
|
||||||
|
|
||||||
**Context:** L.3 motion port landed in this branch (commits `de129bc`
|
Paste this into a fresh Claude Code session at the acdream repo root.
|
||||||
`40d88b9` `2365c8c` `d57ace0` `c26bbbb` `b37b713`) — player-remote
|
The branch you'll work on is `main` at or after commit `086e65d`
|
||||||
running/walking/strafing/NPCs all visually verified clean. M4 jump
|
("Merge L.3 motion port"). Read `CLAUDE.md` first for project conventions.
|
||||||
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
|
## What you're fixing
|
||||||
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
|
When a retail-controlled toon jumps **in place** (no horizontal input,
|
||||||
|
just press jump) while observed through acdream, the visible jump arc
|
||||||
|
renders with a **~1 m horizontal offset** from the actor's actual XY
|
||||||
|
position. Body lands at the offset. Position snaps back to the actor's
|
||||||
|
real XY when the actor next sends any UM (turn / step / etc.).
|
||||||
|
|
||||||
**Initial-overlap depenetration along non-+Z terrain normal.** At
|
User's exact wording: *"I stand at position X and jump, it looks like
|
||||||
jump start the collision sphere is touching the floor at body Z. Most
|
im jumping slightly to the left of X like 1 m-ish (if I observe
|
||||||
outdoor terrain triangles have non-vertical normals (small horizontal
|
jumping char from behind). It also lands at X + 1 m-ish. Position
|
||||||
component). The sweep's first-frame action is to resolve the
|
resets to X when I issue some other command to the client like turning."*
|
||||||
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
|
This is **filed as `#42` in `docs/ISSUES.md`** with severity MEDIUM.
|
||||||
drift direction varies with terrain slope orientation (not actor
|
Pre-existing PhysicsEngine bug, exposed by L.3 M2 (which removed the
|
||||||
facing), this hypothesis is confirmed.
|
mid-arc UP hard-snap that was masking it) and by L.3 M4 (which
|
||||||
|
re-enabled `ResolveWithTransition` per-tick airborne).
|
||||||
|
|
||||||
Other candidates ranked by probability:
|
## What's been ruled out (already, A/B-tested 2026-05-05)
|
||||||
2. Step-down probe firing despite `isOnGround: false` parameter.
|
|
||||||
3. EdgeSlide on near-vertical motion against near-vertical surface.
|
The drift is **definitively inside `PhysicsEngine.ResolveWithTransition`**.
|
||||||
|
Verified by toggling a single line in `GameWindow.OnLivePositionUpdated`:
|
||||||
|
|
||||||
|
- `rmState.CellId = p.LandblockId;` REMOVED → sweep skipped → jumps
|
||||||
|
render geometrically clean (no XY drift), but body falls through
|
||||||
|
the floor (no terrain catch).
|
||||||
|
- `rmState.CellId = p.LandblockId;` PRESENT → sweep runs → jumps
|
||||||
|
land cleanly on the floor, but arc shows ~1 m horizontal drift.
|
||||||
|
|
||||||
|
That A/B narrows the bug to one place. **Do not waste time** on:
|
||||||
|
- ACE wire `VectorUpdate` velocity components (not the source — drift
|
||||||
|
exists with sweep enabled regardless of wire data)
|
||||||
|
- Local Euler integration error (not the source — drift is geometric,
|
||||||
|
visible immediately on jump start)
|
||||||
|
- Stale `body.Velocity` from before the jump (M3 grounded path
|
||||||
|
zeroes it every tick; verified clean)
|
||||||
|
- Wire diagnostic instrumentation (`[VU.WIRE]`, `[UM_RAW]`, etc.) —
|
||||||
|
irrelevant. The bug is in the sweep, not the inputs.
|
||||||
|
|
||||||
|
The bug is **inside `ResolveWithTransition`** (or one of the helpers
|
||||||
|
it delegates to: `Transition`, `SpherePath`, `CollisionInfo`,
|
||||||
|
`AdjustOffset`).
|
||||||
|
|
||||||
|
## Why the fix can't just disable the sweep
|
||||||
|
|
||||||
|
The user explicitly raised: *"What about jumping in to buildings or
|
||||||
|
on a jumping puzzle?"*
|
||||||
|
|
||||||
|
Right. We need full sphere-vs-geometry resolution mid-arc for:
|
||||||
|
- Building doorways (jumping into a doorway you can stand in)
|
||||||
|
- Jumping puzzles (threading between platforms, around obstacles)
|
||||||
|
- Ceiling clips (hitting an overhang at jump apex)
|
||||||
|
- Edge collision (clipping against the corner of a platform)
|
||||||
|
|
||||||
|
So the fix has to **keep the sweep running, but stop it from pushing
|
||||||
|
horizontally on stationary jumps**. Pure-vertical motion against a
|
||||||
|
roughly-horizontal floor must produce zero XY delta from the sweep.
|
||||||
|
|
||||||
|
## The three ranked hypotheses
|
||||||
|
|
||||||
|
These are the in-sweep mechanisms most likely producing the drift.
|
||||||
|
Listed by probability; (1) is the leading candidate.
|
||||||
|
|
||||||
|
### H1: Initial-overlap depenetration along non-+Z terrain normal
|
||||||
|
|
||||||
|
At jump start the collision sphere is touching the floor: `body.Z` is
|
||||||
|
at ground level, sphere radius extends downward into the terrain
|
||||||
|
triangle. The sweep's first tick has to resolve that overlap by
|
||||||
|
**separating the sphere along the contact normal**.
|
||||||
|
|
||||||
|
Outdoor terrain is rarely perfectly flat. Most terrain triangles tilt
|
||||||
|
0.5–10° from horizontal. Their normals have a small horizontal
|
||||||
|
component. When the sweep separates the sphere along that tilted
|
||||||
|
normal, the separation has horizontal magnitude → body shoves
|
||||||
|
sideways → drift carries through the rest of the arc.
|
||||||
|
|
||||||
|
**Direction-correlation test confirms this hypothesis if true:**
|
||||||
|
jumping at multiple landblock positions, the drift direction should
|
||||||
|
correlate with **local terrain slope orientation**, not the actor's
|
||||||
|
facing. (If drift is always relative to actor's facing, H1 is wrong
|
||||||
|
and H2 or H3 is the source.)
|
||||||
|
|
||||||
|
### H2: Step-down probe firing despite `isOnGround: false`
|
||||||
|
|
||||||
|
`PhysicsEngine.ResolveWithTransition` is called with `isOnGround:
|
||||||
|
!rm.Airborne` → `false` for airborne. But the sweep's internals may
|
||||||
|
still execute step-down logic regardless of that flag. Step-down
|
||||||
|
searches **horizontally** within `stepDownHeight` (0.4 m) for the
|
||||||
|
nearest walkable surface — even a small horizontal probe can shift
|
||||||
|
an airborne body sideways if the search finds a "better" surface.
|
||||||
|
|
||||||
|
Already a known asymmetry exists in this region — see `K-fix7` /
|
||||||
|
`K-fix9` comments in `GameWindow.cs:6611-6620` and the matching
|
||||||
|
contact-plane gating in `PhysicsEngine.cs:493-519`. Step-up/down may
|
||||||
|
have a similar gap.
|
||||||
|
|
||||||
|
### H3: EdgeSlide on near-vertical motion grazing a near-vertical surface
|
||||||
|
|
||||||
|
If the sphere even slightly grazes a wall while ascending or
|
||||||
|
descending, `EdgeSlide` projects the motion vector tangent to the
|
||||||
|
wall surface, redirecting some Z velocity into XY. Less likely for
|
||||||
|
open-ground stationary jumps but cannot be ruled out without testing
|
||||||
|
in different environments.
|
||||||
|
|
||||||
## Files to investigate
|
## Files to investigate
|
||||||
|
|
||||||
- `src/AcDream.Core/Physics/PhysicsEngine.cs` — `ResolveWithTransition`
|
```
|
||||||
+ any internal `CTransition` / `find_valid_position` helpers. The
|
src/AcDream.Core/Physics/PhysicsEngine.cs (658 LOC)
|
||||||
initial-overlap depenetration path is the primary target.
|
Line 470: ResolveWithTransition entry point
|
||||||
- Reference at `docs/research/named-retail/acclient_2013_pseudo_c.txt`:
|
Lines 478-491: Transition / ObjectInfo setup
|
||||||
- `CTransition::find_valid_position` (called from `transition()`)
|
Lines 493-519: K-fix7 contact-plane gating (existing airborne fix)
|
||||||
- `SpherePath` initialization
|
Lines 521-530: SlidingNormal seed
|
||||||
- Verbatim retail depenetration logic for airborne bodies
|
Line 532: SpherePath.InitPath (path setup)
|
||||||
|
Lines 534-558: WalkablePolygon seed (grounded only)
|
||||||
|
|
||||||
If our port differs from retail in this region, that diff is the bug.
|
src/AcDream.Core/Physics/TransitionTypes.cs (2200 LOC)
|
||||||
|
Top-level: Transition, SpherePath, CollisionInfo, ObjectInfo classes
|
||||||
|
Search for: find_valid_position, step_sphere, AdjustOffset,
|
||||||
|
StepUp / StepDown / EdgeSlide branches
|
||||||
|
Lines 786-846: existing step-down + edge-slide branch logic
|
||||||
|
(where H2/H3 might be firing inappropriately for
|
||||||
|
airborne)
|
||||||
|
Lines 1305-1311: another step-down/contact branch worth checking
|
||||||
|
|
||||||
## Fix paths (in order of preference)
|
src/AcDream.Core/Physics/CollisionPrimitives.cs (718 LOC)
|
||||||
|
Sphere-vs-triangle math; depenetration-related primitives if any
|
||||||
|
```
|
||||||
|
|
||||||
**(a) Skip initial-overlap depenetration when airborne.** Gate the
|
The L.4 collision-resolution work added the existing airborne gates
|
||||||
"separate from initial contact plane" step inside
|
(K-fix7 ContactPlane, K-fix9 ContactPlane during VectorUpdate) but
|
||||||
`ResolveWithTransition` on `isOnGround: true`. Trusts the previous
|
didn't touch step-up/down or initial-overlap depenetration paths.
|
||||||
tick's resolve to have left the body in a non-overlapping position.
|
Those are the gaps.
|
||||||
Most likely correct fix.
|
|
||||||
|
|
||||||
**(b) Zero step-up/down for airborne sweeps.** Pass
|
## Reference: retail named-retail decomp
|
||||||
`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
|
Mandatory cross-reference. Located at:
|
||||||
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
|
```
|
||||||
|
docs/research/named-retail/acclient_2013_pseudo_c.txt (1.4 M lines, PDB-named)
|
||||||
|
docs/research/named-retail/acclient.h (verbatim retail headers)
|
||||||
|
docs/research/named-retail/symbols.json (greppable name → address)
|
||||||
|
```
|
||||||
|
|
||||||
1. Launch acdream + retail client side-by-side on local ACE
|
Functions to grep for in the named pseudo-C:
|
||||||
(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
|
- `CTransition::init` @ `0x00509dd0` — explicitly clears
|
||||||
patches with different visible slope orientations; if drift direction
|
`contact_plane_valid = 0` at start of every resolve. Confirms the
|
||||||
changes accordingly, depenetration is confirmed.
|
airborne should not be running on a stale contact plane (we already
|
||||||
|
match this — K-fix7).
|
||||||
|
- `CTransition::find_valid_position` — entry to the actual sweep.
|
||||||
|
Read this carefully for the airborne-vs-grounded branching.
|
||||||
|
- `CSpherePath::InitPath` — path-setup; check whether retail does
|
||||||
|
any initial-overlap separation here.
|
||||||
|
- `CSpherePath::step_sphere` — the per-step inner loop.
|
||||||
|
- `CTransition::ValidateWalkable` — rebuilds contact plane when sphere
|
||||||
|
bottom is within EPSILON of terrain plane (per K-fix7 comment); for
|
||||||
|
airborne this should not establish a plane.
|
||||||
|
- `CCollisionInfo::set_contact_plane` and the depenetration paths
|
||||||
|
that use it.
|
||||||
|
|
||||||
## Acceptance
|
**Compare retail behavior against our port byte-for-byte for the
|
||||||
|
specific airborne-stationary-jump path.** Our port may have
|
||||||
|
inadvertently introduced behavior retail doesn't have (e.g.,
|
||||||
|
unconditional initial separation), or omitted a retail gate (e.g.,
|
||||||
|
"skip depenetration if `transient_state.Contact == 0`").
|
||||||
|
|
||||||
- Stationary jumps render at the actor's actual XY (no perceptible
|
## Investigation plan
|
||||||
drift, no snap-back on next UM).
|
|
||||||
- Wall-collision airborne still works (jumping into doorways, jumping
|
Two phases. Don't skip phase 1.
|
||||||
puzzles where you have to thread between platforms or through arches).
|
|
||||||
|
### Phase 1: Confirm hypothesis (≤ 2 hours)
|
||||||
|
|
||||||
|
1. Verify the M4 `CellId` fix is on `main` by grepping `GameWindow.cs`
|
||||||
|
for `rmState.CellId = p.LandblockId`. It should be present at the
|
||||||
|
top of the M2 player-remote branch in `OnLivePositionUpdated`.
|
||||||
|
|
||||||
|
2. Add lightweight diagnostic logging inside `ResolveWithTransition`:
|
||||||
|
```
|
||||||
|
[SWEEP] guid=<guid> pre=(x,y,z) target=(x,y,z) post=(x,y,z) airborne=<bool>
|
||||||
|
```
|
||||||
|
Gate behind `ACDREAM_AIRBORNE_DIAG=1` so the diagnostic doesn't
|
||||||
|
spam logs in normal use.
|
||||||
|
|
||||||
|
3. Have the user jump in place at 3+ different landblock positions
|
||||||
|
with visibly different terrain orientation:
|
||||||
|
- flat plaza tile
|
||||||
|
- hillside facing east
|
||||||
|
- hillside facing north
|
||||||
|
|
||||||
|
For each, capture the sweep's `pre→target→post` deltas across the
|
||||||
|
first 5 frames of the arc.
|
||||||
|
|
||||||
|
4. **Check direction correlation:**
|
||||||
|
- If drift direction varies with terrain orientation → H1 confirmed.
|
||||||
|
The first frame of the sweep is shifting the body horizontally
|
||||||
|
by an amount proportional to the local terrain slope.
|
||||||
|
- If drift direction is always relative to actor facing → H1 wrong;
|
||||||
|
check H2 (step-down probe) by comparing sweeps with non-zero vs
|
||||||
|
zero `stepDownHeight`.
|
||||||
|
- If no drift in open ground but drift near walls → H3.
|
||||||
|
|
||||||
|
5. Stop at the first confirmed hypothesis. Move to phase 2 with
|
||||||
|
precise knowledge of which mechanism is firing.
|
||||||
|
|
||||||
|
### Phase 2: Fix (1–4 hours depending on hypothesis)
|
||||||
|
|
||||||
|
**If H1 confirmed (most likely):**
|
||||||
|
- Find the depenetration / "separate sphere from initial contact"
|
||||||
|
path in `Transition` / `SpherePath` / `CollisionInfo`.
|
||||||
|
- Gate it on `ObjectInfo.State.HasFlag(ObjectInfoState.Contact)`
|
||||||
|
(i.e., grounded). Trust the previous tick's resolve to have left
|
||||||
|
the body in a non-overlapping position.
|
||||||
|
- Compare against retail's `CTransition::init` and `find_valid_position`
|
||||||
|
— likely retail has this gate and we don't.
|
||||||
|
|
||||||
|
**If H2 confirmed:**
|
||||||
|
- Find the step-up/step-down branches in `TransitionTypes.cs`.
|
||||||
|
- Gate them on `oi.Contact` (already exists at line 787 — verify it
|
||||||
|
fires correctly when airborne).
|
||||||
|
- May need to additionally zero `StepUpHeight` / `StepDownHeight`
|
||||||
|
when airborne at the call site in `GameWindow.cs`.
|
||||||
|
|
||||||
|
**If H3 confirmed:**
|
||||||
|
- Find the EdgeSlide branch in `TransitionTypes.cs`.
|
||||||
|
- Add a gate that EdgeSlide only fires when motion has horizontal
|
||||||
|
velocity component above a threshold (so pure-vertical motion is
|
||||||
|
exempt).
|
||||||
|
- Verify against retail's edge-slide branch behavior.
|
||||||
|
|
||||||
|
### Phase 3: Visual verification
|
||||||
|
|
||||||
|
User will run retail + acdream side-by-side. Test cases:
|
||||||
|
|
||||||
|
- ✅ Jump in place on flat ground — no XY drift
|
||||||
|
- ✅ Jump in place on hillside (different orientations) — no XY drift
|
||||||
|
- ✅ Jump while running forward — arc carries forward momentum (XY
|
||||||
|
delta from initial wire velocity, NOT from sweep)
|
||||||
|
- ✅ Jump into a building doorway — body collides with door frame /
|
||||||
|
threads through doorway correctly
|
||||||
|
- ✅ Jump from a platform onto another (jumping puzzle mechanic) —
|
||||||
|
body lands on the target platform
|
||||||
|
- ✅ Land on slope — sequencer leaves Falling correctly
|
||||||
|
|
||||||
|
If any of these regress, the fix is wrong or incomplete. Iterate.
|
||||||
|
|
||||||
|
## Diagnostic toolchain
|
||||||
|
|
||||||
|
### cdb attach to retail (high-value when comparing retail vs ours)
|
||||||
|
|
||||||
|
Toolchain documented in CLAUDE.md "Retail debugger toolchain" section.
|
||||||
|
The relevant breakpoints for #42:
|
||||||
|
|
||||||
|
```
|
||||||
|
bp acclient!CTransition::init "r $t0 = @$t0 + 1; gc"
|
||||||
|
bp acclient!CTransition::find_valid_position "r $t1 = @$t1 + 1; gc"
|
||||||
|
bp acclient!CSpherePath::step_sphere "r $t2 = @$t2 + 1; gc"
|
||||||
|
```
|
||||||
|
|
||||||
|
Have the user (running retail with cdb attached) jump in place. The
|
||||||
|
hit counts and any printed state from breakpoint actions reveal
|
||||||
|
retail's actual airborne sweep call pattern. Compare against
|
||||||
|
acdream's instrumented `[SWEEP]` log. Differences are bugs.
|
||||||
|
|
||||||
|
**Important warnings from CLAUDE.md:**
|
||||||
|
- `qd` / `q` / `qq` are FORBIDDEN inside breakpoint actions — use
|
||||||
|
`.detach`.
|
||||||
|
- High-frequency breakpoints lag retail to ACE timeout — counter-only
|
||||||
|
actions for hot paths.
|
||||||
|
- `cdb -pd` does NOT survive `Stop-Process -Force`; detach cleanly.
|
||||||
|
|
||||||
|
### Live launch
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
$env:ACDREAM_DAT_DIR = "$env:USERPROFILE\Documents\Asheron's Call"
|
||||||
|
$env:ACDREAM_LIVE = "1"
|
||||||
|
$env:ACDREAM_TEST_HOST = "127.0.0.1"
|
||||||
|
$env:ACDREAM_TEST_PORT = "9000"
|
||||||
|
$env:ACDREAM_TEST_USER = "testaccount"
|
||||||
|
$env:ACDREAM_TEST_PASS = "testpassword"
|
||||||
|
$env:ACDREAM_AIRBORNE_DIAG = "1" # enable sweep diagnostic once added
|
||||||
|
dotnet run --project src\AcDream.App\AcDream.App.csproj --no-build -c Debug *>&1 |
|
||||||
|
Tee-Object -FilePath "launch-42.log"
|
||||||
|
```
|
||||||
|
|
||||||
|
Wait 3–5 s between launches (ACE session cleanup race; CLAUDE.md).
|
||||||
|
|
||||||
|
### Test character
|
||||||
|
|
||||||
|
`+Acdream` at server guid `0x5000000A`. Per CLAUDE.md, this is the
|
||||||
|
GM-marker test toon. The user will control it (or another retail toon)
|
||||||
|
from a parallel retail client and you observe in acdream.
|
||||||
|
|
||||||
|
## Acceptance criteria
|
||||||
|
|
||||||
|
The fix is done when ALL of these hold:
|
||||||
|
|
||||||
|
- [ ] Stationary jump on flat ground: arc + landing render at actor's
|
||||||
|
actual XY (zero perceptible drift, zero snap-back on next UM).
|
||||||
|
- [ ] Stationary jump on hillside: same — drift independent of
|
||||||
|
terrain orientation.
|
||||||
|
- [ ] Forward-running jump: arc carries actor's forward XY velocity
|
||||||
|
(this is server-driven, expected to track).
|
||||||
|
- [ ] Jump into a doorway: collision resolves correctly.
|
||||||
|
- [ ] Jump puzzle: thread between two platforms.
|
||||||
|
- [ ] Build green (`dotnet build`).
|
||||||
|
- [ ] Tests green (`dotnet test`) — modulo the 8 pre-existing
|
||||||
|
`Core.Tests` failures unrelated to this work.
|
||||||
|
- [ ] `[SWEEP]` diagnostic shows zero XY change on a stationary jump's
|
||||||
|
first sweep frame (the H1 confirmation residue).
|
||||||
|
|
||||||
|
## Hard rules
|
||||||
|
|
||||||
|
- **Don't blame ACE.** ACE is fixed; retail clients work against ACE
|
||||||
|
without this drift, so our PhysicsEngine port is the bug.
|
||||||
|
- **Don't disable the sweep wholesale.** The user explicitly needs
|
||||||
|
jumping puzzles + wall collision to keep working.
|
||||||
|
- **Don't change `OnLivePositionUpdated` or `TickAnimations`.** The
|
||||||
|
L.3 motion-port work is correct; this is a `PhysicsEngine` bug.
|
||||||
|
- **Don't touch `MotionInterpreter` or `AnimationSequencer`.** Same
|
||||||
|
reason.
|
||||||
|
- **Don't reduce sphere dims** to "avoid intersection". 0.48 m radius
|
||||||
|
/ 1.2 m height is retail human-scale and matches local-player
|
||||||
|
collision; changing it on remotes only would cause asymmetric
|
||||||
|
behavior between local jumps (working) and remote jumps (different
|
||||||
|
collision profile).
|
||||||
|
- **Don't add diagnostic logging that prints every frame** without
|
||||||
|
an env-var gate — already burned the `[VEL_DIAG]` budget once.
|
||||||
|
- **Don't commit a partial fix that breaks any test in the
|
||||||
|
acceptance criteria.** Trade off completeness for correctness.
|
||||||
|
|
||||||
|
## Pre-session reading list
|
||||||
|
|
||||||
|
In order, before writing any code:
|
||||||
|
|
||||||
|
1. `docs/ISSUES.md` § `#42 — Airborne XY drift` (the spec)
|
||||||
|
2. This handoff prompt (you're here)
|
||||||
|
3. `src/AcDream.Core/Physics/PhysicsEngine.cs:470-560`
|
||||||
|
(`ResolveWithTransition`)
|
||||||
|
4. `src/AcDream.Core/Physics/TransitionTypes.cs:780-870`
|
||||||
|
(existing step-down + edge-slide branches)
|
||||||
|
5. Grep `K-fix7` and `K-fix9` in `GameWindow.cs` and
|
||||||
|
`PhysicsEngine.cs` (these are the prior airborne-related fixes;
|
||||||
|
matching style is helpful)
|
||||||
|
6. The L.3 motion-port research at
|
||||||
|
`docs/research/2026-05-04-l3-port/` —
|
||||||
|
especially `01-per-tick.md` § 5 (`CPhysicsObj::transition`) and
|
||||||
|
`01-per-tick.md` § 6 (`SetPositionInternal`) for retail's
|
||||||
|
per-tick collision-sweep contract.
|
||||||
|
7. Retail's `CTransition::init` at `acclient_2013_pseudo_c.txt` line
|
||||||
|
271954 (cited in K-fix7 comment).
|
||||||
|
|
||||||
## Operating notes
|
## Operating notes
|
||||||
|
|
||||||
- This is a `PhysicsEngine` bug, not a motion-port bug. The L.3 work
|
- **Branch off `main`.** Do not work directly on main; use a feature
|
||||||
is done; this is a separate investigation.
|
branch for the fix. Worktree is fine; CLAUDE.md and prior sessions
|
||||||
- The `[VU.WIRE]` instrumentation idea from #42's earlier draft can
|
use `.claude/worktrees/`.
|
||||||
be skipped — we already proved wire data isn't the source via the
|
- **TDD where it fits.** A unit test that asserts
|
||||||
A/B test.
|
`ResolveWithTransition` returns zero XY delta for a stationary
|
||||||
- cdb attach to retail (`docs/research/2026-05-04-l3-port/`-adjacent
|
vertical sweep on a tilted-normal triangle would lock the fix.
|
||||||
toolchain documented in CLAUDE.md) is available if comparing
|
Existing `tests/AcDream.Core.Tests/Physics/PhysicsEngineTests.cs`
|
||||||
retail's airborne sweep behavior against ours becomes useful.
|
is the right home.
|
||||||
|
- **Visual verification is the acceptance test.** The unit test
|
||||||
|
proves the math but the user's eye proves the bug. Plan time for
|
||||||
|
the user to run the test sequence above.
|
||||||
|
- **One-session estimate: half a day to a day.** Phase 1 should
|
||||||
|
identify the hypothesis in under 2 hours; Phase 2 fix depends on
|
||||||
|
which one. Plan for two iterations if the first fix attempt
|
||||||
|
doesn't fully resolve.
|
||||||
|
|
||||||
|
## Out of scope
|
||||||
|
|
||||||
|
- `#41` (sub-decimeter velocity-synthesis blips) — separate issue.
|
||||||
|
- Refactoring NPC vs player-remote convergence in `TickAnimations`
|
||||||
|
(filed in audit § 6 of `06-acdream-audit.md`) — separate session.
|
||||||
|
- Local-player jump behavior — already works; don't touch.
|
||||||
|
- ACE-side fixes — out of scope.
|
||||||
|
|
||||||
|
## Final advice
|
||||||
|
|
||||||
|
The L.3 motion-port history (commits `de129bc`..`5cc2812`) shows what
|
||||||
|
this codebase rewards: spec-faithful reads of named-retail before
|
||||||
|
writing any code. Apply the same here. The fix is probably small —
|
||||||
|
maybe 5–20 lines — but finding it requires reading retail's
|
||||||
|
`find_valid_position` and our `Transition` carefully and identifying
|
||||||
|
the diff. Don't guess; verify.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue