docs(#145): verified root cause + decision to port cell-relative physics frame (Option B) + handoff
Workflow wf_87607d15-c43 (4 research streams + synthesis + 3 adversarial verifiers, HIGH confidence) confirmed the far-town runaway is a cell-membership label cascade from a discarded TryGetTerrainOrigin bool (CellTransit.cs:736 -> (0,0) origin for unstreamed neighbors), not a free-fall; 17410 is a wire artifact. User chose the architectural fix: port retail's cell-relative Position + retire _liveCenter from physics. Handoff doc carries the verified mechanism, the retail port table (decomp addresses), acdream divergence sites, apparatus (desync-capture.jsonl + probes + harness template), and the brainstorming-gate requirement. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
a4f0b51894
commit
67f98e8e72
2 changed files with 244 additions and 5 deletions
|
|
@ -71,11 +71,52 @@ Holtburg↔dungeon works because Holtburg is the startup center; the far town ex
|
||||||
412/498/710); it did NOT fire for the far town during the runaway (746+) — and it only adds RENDER
|
412/498/710); it did NOT fire for the far town during the runaway (746+) — and it only adds RENDER
|
||||||
entities, never the physics `_landblocks` the resolver iterates.
|
entities, never the physics `_landblocks` the resolver iterates.
|
||||||
**Apparatus:** `[cell-transit]` trail (`ACDREAM_PROBE_CELL=1`) + `desync-capture.jsonl` (72,401
|
**Apparatus:** `[cell-transit]` trail (`ACDREAM_PROBE_CELL=1`) + `desync-capture.jsonl` (72,401
|
||||||
`ResolveWithTransition` frames, `ACDREAM_CAPTURE_RESOLVE`). Suspected: the per-frame outdoor resolve
|
`ResolveWithTransition` frames, `ACDREAM_CAPTURE_RESOLVE`). **ROOT CAUSE — VERIFIED 2026-06-21 (multi-agent workflow + adversarial verification, decomp-confirmed against live Ghidra):**
|
||||||
(`PhysicsEngine.Resolve` / `AdjustPosition` iterating `_landblocks`) does not normalize the local
|
It is a **cell-membership cascade**, NOT a real free-fall. The physics body stays small + correct
|
||||||
position across a landblock crossing the way retail's `set_position`/`change_cell`/`AdjustPosition`
|
(capture: max|Y|≈86 m, settles at the true rest `(-6.1,-30.2,12.0)`); only the **cell id** marches
|
||||||
does — port that. Research workflow running (acdream resolver code + retail named-decomp/Ghidra
|
one landblock south per physics quantum (~33 ms) until the landblock-Y byte underflows to 0x00. The
|
||||||
oracle + capture characterization → synthesis → adversarial verify).
|
`17410` is a **wire-conversion artifact** (the outbound `localY = Position.Y − (lbY−_liveCenterY)·192`
|
||||||
|
adds back 91×192 once `lbY` marched to 0), never a physics value.
|
||||||
|
**The bug (single source line):** `CellTransit.cs:736` —
|
||||||
|
`cache.CellGraph.TryGetTerrainOrigin(currentCellId, out var blockOrigin)` **discards the bool**.
|
||||||
|
For a far town, the player is placed at the southern landblock edge (world-Y≈0.3) with **stale
|
||||||
|
southward running velocity** (teleport doesn't idle the motion state); the first tick crosses Y=0
|
||||||
|
into landblock `0xC95A`, which **has not streamed in yet** → `TryGetTerrainOrigin` returns `false`
|
||||||
|
with `origin=Vector3.Zero` (the comment at `CellTransit.cs:732-735` self-documents this "legacy
|
||||||
|
anchor-frame" fallback). `(0,0)` is handed to `AddAllOutsideCells` (`:758`) → `GetOutsideLcoord`
|
||||||
|
(`LandDefs.cs:110-111`) does `ly += floor(worldY/24)` = `floor(-0.088/24) = -1` → cell marches one
|
||||||
|
block south. The correct origin `(0,-192)` would give `floor(191.9/24)=+7` (right region) — the
|
||||||
|
missing −192 rebase IS the bug. Every subsequent neighbor is also unstreamed → the cascade
|
||||||
|
self-perpetuates 91 times. **Far-town-only** because Holtburg (the streaming startup center) has all
|
||||||
|
neighbors permanently registered, so the fallback never fires + spawns are mid-block (no Y=0 cross).
|
||||||
|
**Retail contrast (decomp-confirmed, addresses re-verified in Ghidra patchmem):** retail stores
|
||||||
|
position CELL-RELATIVE (`Position{ uint objcell_id; Frame{ m_fOrigin ∈ [0,192) } }`, `acclient.h:30659`)
|
||||||
|
and rebases the ACTUAL stored origin in place on every placement via `Position::adjust_to_outside`
|
||||||
|
(0x00504A40) → `LandDefs::adjust_to_outside` (0x005A9BC0, wraps origin into [0,192) + recomputes the
|
||||||
|
cell id) called from `AdjustPosition` (0x00511D80) / `SetPositionInternal` (0x00515BD0); cross-cell
|
||||||
|
offsets come only from `get_block_offset` (0x0043E630, delta of two cell ids, zero within a
|
||||||
|
landblock). An inconsistent (cell, local) pair is structurally impossible in retail. acdream's
|
||||||
|
streaming-relative physics frame (`worldXY=(lb−_liveCenter)·192+local`, per-landblock baked
|
||||||
|
WorldOffset) is the deeper divergence; the proximate bug is the discarded-bool `(0,0)` fallback.
|
||||||
|
|
||||||
|
**FIX DIRECTION (report-only — awaiting user approval):**
|
||||||
|
- **4a (targeted, faithful, this-session):** honor `TryGetTerrainOrigin`'s `false` at `CellTransit.cs:736`
|
||||||
|
— when the current landblock's terrain isn't resident, the outdoor pick has no trustworthy
|
||||||
|
block-local frame, so HOLD the current (cell, position) verbatim (no march), the same
|
||||||
|
"frame-not-yet-authoritative ⇒ return input" contract the NO-LANDBLOCK Resolve branch already uses.
|
||||||
|
PAIR with **idle the motion state on teleport arrival** (stop re-applying the dungeon running
|
||||||
|
velocity the same frame as `SetPosition`) so the body never attempts the first crossing before
|
||||||
|
terrain streams. Adaptation (not a direct retail port — retail gets it free via cell-relative
|
||||||
|
storage) ⇒ needs a divergence-register row. Deterministic replay test from the capture
|
||||||
|
(`TeleportFarTownRunawayTests`: with `0xC95A` unregistered, resolve returns `currentCellId`
|
||||||
|
unchanged). Consumer sites to cover via the early-return: `:758/242` (seed), `:845` (pick), `:484`.
|
||||||
|
- **4b (architectural, file as a phase, brainstorm-gated):** port retail's cell-relative physics
|
||||||
|
`Position` + make `_liveCenter` render-only + `get_block_offset` as the only cross-cell translation.
|
||||||
|
Removes the whole class structurally. Multi-commit.
|
||||||
|
**Open items:** map-edge wedge (verbatim-hold could hover the player at a boundary if the needed
|
||||||
|
neighbor never streams — likely mitigated by the motion-idle + the destination center always
|
||||||
|
streaming; verify). **Confidence: HIGH** (all 3 adversarial lenses holdsUp=true; capture- and
|
||||||
|
decomp-verified). Full report: workflow `wf_87607d15-c43`.
|
||||||
|
|
||||||
**[ORIGINAL #145 — source-frame overlap, FIXED 2026-06-20; history below]**
|
**[ORIGINAL #145 — source-frame overlap, FIXED 2026-06-20; history below]**
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,198 @@
|
||||||
|
# Handoff — #145-residual: port the physics frame to CELL-RELATIVE (retail-faithful), retire the streaming center from physics
|
||||||
|
|
||||||
|
**Date:** 2026-06-21
|
||||||
|
**Branch:** `claude/thirsty-goldberg-51bb9b` — committed, **NOT merged to main** (user's call: "we can merge later")
|
||||||
|
**Milestone:** M1.5 "Indoor world feels right" (this is the last blocker for far-town/dungeon round-trips)
|
||||||
|
**HEAD at handoff:** `a4f0b51` (the #145 reopen) + an uncommitted ISSUES.md #145 root-cause update (committed alongside this doc).
|
||||||
|
**DECISION (user, 2026-06-21):** Go with **Option B — the architectural fix.** Make the physics position
|
||||||
|
**cell-relative like retail** and retire the streaming `_liveCenterX/_liveCenterY` from the physics path
|
||||||
|
(render-only). The user explicitly rejected the targeted patch (Option A) in favor of "done right, never
|
||||||
|
again." Quote: *"It should be agnostic."* **Start with a brainstorming gate** (this is a multi-commit
|
||||||
|
physics-frame phase touching the physics↔streaming seam broadly).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## What shipped this session (context — already committed)
|
||||||
|
|
||||||
|
| Commit | What |
|
||||||
|
|---|---|
|
||||||
|
| `bf66fb4` | **#138 FIXED + user-verified** — server objects re-hydrate from the retained spawn table (`_lastSpawnByGuid`) on landblock reload; ACE won't re-send known objects, so we re-project. Register AP-48. |
|
||||||
|
| `0a5f91b` | #138 secondary — rescue persistent entities from the pending bucket on unload (player-vanish candidate). |
|
||||||
|
| `aa4a04d`/`b07825c` | #138 docs + handoff correction (the prior handoff's `ClientObjectTable` advice was WRONG — it's inventory-only; `_lastSpawnByGuid` is the world-object table). |
|
||||||
|
| `a4f0b51` | **#145 REOPENED** — far-town teleport resolver runaway (residual of the 2026-06-20 source-drop fix). |
|
||||||
|
|
||||||
|
**#138 is DONE and independent of this work** — the re-hydrate (objects come back) is user-confirmed and
|
||||||
|
the capture proved it is NOT involved in the runaway. It's mergeable as-is.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## THE BUG (verified — multi-agent workflow `wf_87607d15-c43` + 3 adversarial verifiers, all `holdsUp=true`, confidence HIGH)
|
||||||
|
|
||||||
|
**Full report:** `…/tasks/w8wm5fln4.output` (synthesis + 3 verdicts) and the workflow transcript dir.
|
||||||
|
Distilled:
|
||||||
|
|
||||||
|
**It is a cell-membership LABEL cascade, NOT a real free-fall.** Teleport to a FAR town (e.g.
|
||||||
|
(201,91)=`0xC95B`) places the player CORRECTLY at `0xC95B0001` local `(14.8, 0.3, 12)` (the #145 verbatim
|
||||||
|
path). Then the per-frame resolve **marches the cell id one landblock south per physics quantum (~33 ms)**
|
||||||
|
while the **physics body barely moves** (capture: max|Y|≈86 m, Z falls to ≈−135 then walk-back; settles at
|
||||||
|
the TRUE rest `(-6.124, -30.186, 12.000)`, og=True). The cell-id `lbY` byte counts `0x5B`(91)→`0x00`. The
|
||||||
|
**`17410`** ACE rejects is a **wire-conversion artifact** — once `lbY` marched to 0, the outbound
|
||||||
|
`localY = Position.Y − (lbY − _liveCenterY)·192` back-adds 91×192 = 17472. The body never went there.
|
||||||
|
|
||||||
|
**Proximate cause (single source line):** `src/AcDream.Core/Physics/CellTransit.cs:736`
|
||||||
|
```csharp
|
||||||
|
cache.CellGraph.TryGetTerrainOrigin(currentCellId, out var blockOrigin); // bool DISCARDED
|
||||||
|
```
|
||||||
|
For a far town the player is placed at the southern landblock edge (world-Y≈0.3) with **stale southward
|
||||||
|
running velocity** (the teleport never idled the motion state). The first tick crosses Y=0 into landblock
|
||||||
|
`0xC95A`, which **has not streamed in yet** → `TryGetTerrainOrigin` returns **`false` with
|
||||||
|
`origin=Vector3.Zero`** (`CellGraph.cs:47-56`; the comment at `CellTransit.cs:732-735` literally
|
||||||
|
self-documents this "legacy anchor-frame assumption (world frame == block-local frame)"). `(0,0)` flows into
|
||||||
|
`AddAllOutsideCells` (`:758`) → `GetOutsideLcoord` (`LandDefs.cs:110-111`) does
|
||||||
|
`ly += floor(worldY/24)` = `floor(-0.088/24) = -1` → cell marches one block south. The CORRECT origin for
|
||||||
|
`0xC95A` is `(0,-192)`, which would give `floor(191.9/24)=+7` (right region). **The missing −192 rebase is
|
||||||
|
the bug.** Every next neighbor is also unstreamed → the `(0,0)` cascade self-perpetuates 91×.
|
||||||
|
|
||||||
|
**Why FAR-TOWN only:** Holtburg is the streaming startup center *only because +Je spawns there* (the center
|
||||||
|
recenters to the login landblock at `GameWindow ~:2879` and on every teleport at `~:5447` — it is NOT
|
||||||
|
hardcoded to Holtburg). Holtburg works because its neighbors are already streamed (registered), so the
|
||||||
|
`(0,0)` fallback never fires, and its spawns are mid-block (no Y=0 crossing to arm the cascade). The bug
|
||||||
|
fires at the EDGE of the streamed region for ANY fresh teleport. **This is the non-agnostic assumption the
|
||||||
|
user flagged: `(0,0)` = "this landblock is home" — only true at the center.**
|
||||||
|
|
||||||
|
**#138 re-hydrate EXONERATED:** it fired only for Holtburg + the dungeon (log lines 412/498/710), never for
|
||||||
|
the far town during the runaway (746+); it adds only RENDER entities, never the physics `_landblocks` the
|
||||||
|
resolver iterates.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## THE FIX — Option B: cell-relative physics `Position` (port retail)
|
||||||
|
|
||||||
|
**The retail design (decomp-verified, addresses re-confirmed against live Ghidra patchmem :8081):**
|
||||||
|
retail stores EVERY physics position **cell-relative** and re-bases the stored origin **in place** on every
|
||||||
|
placement and every boundary crossing, so the (cell, local) pair can never drift apart. There is **no
|
||||||
|
streaming "center" anywhere in retail's physics.** Make acdream's physics match this; `_liveCenterX/Y`
|
||||||
|
becomes a **render-only** concern (the `(lb − _liveCenter)·192` math is correct for placing meshes around
|
||||||
|
the camera, but must NOT be the physics authority).
|
||||||
|
|
||||||
|
### Retail functions to port (named decomp + Ghidra — verified addresses)
|
||||||
|
|
||||||
|
| Retail symbol | Address | Role |
|
||||||
|
|---|---|---|
|
||||||
|
| `struct Position { uint objcell_id; Frame frame }` | `acclient.h:30659` | The position IS the (cell, local) pair. `Frame.m_fOrigin` (`acclient.h:30654`) is LOCAL to the cell, bounded `[0,192)` for outdoor. **No global/world position field exists.** |
|
||||||
|
| `Position::adjust_to_outside` | `0x00504A40` | Rebases the ACTUAL `this->frame.m_fOrigin` + `this->objcell_id` in place (not a temp). |
|
||||||
|
| `LandDefs::adjust_to_outside` | `0x005A9BC0` | Recomputes global landcell via `get_outside_lcoord`, rebuilds cell id via `lcoord_to_gid`, **wraps origin into [0,192)** (`origin -= floor(origin/192)*192`). The canonicalizer. |
|
||||||
|
| `LandDefs::get_outside_lcoord` | `0x005A9B00` | `gX = blockLcoordX + floor(localX/24)`. (acdream `LandDefs.cs:105-112` is a faithful port — but the per-frame pick feeds it a RAW world-frame Y via the `(0,0)` fallback instead of a wrapped local.) |
|
||||||
|
| `LandDefs::get_block_offset` | `0x0043E630` | The ONLY cross-cell translation: `(dX−sX)·24, (dY−sY)·24` from the two cell ids' landblock bytes; **returns ZeroVector when both cells share a landblock**. A delta of two NAMED cells — never an accumulation vs a moving center. |
|
||||||
|
| `LandDefs::blockid_to_lcoord` / `lcoord_to_gid` | `0x0043D680` / `0x004A19A0` | Absolute global landcell grid (lcoord 0..0x7f8). No `_liveCenter` subtraction anywhere — the grid origin is the world origin, fixed. |
|
||||||
|
| `CTransition::validate_transition` | `0x0050AA70` | On each accepted step adopts `curr_pos.objcell_id = check_pos.objcell_id` AND `curr_pos.frame = check_pos.frame` **together** (lockstep), then `cache_global_curr_center`. The local frame is re-expressed into the destination cell during the sweep. |
|
||||||
|
| `CPhysicsObj::AdjustPosition` / `SetPositionInternal` | `0x00511D80` / `0x00515BD0` | Every placement/teleport runs `adjust_to_outside` → an inconsistent (lbY=0, localY=17410) pair cannot persist. |
|
||||||
|
| `SPHEREPATH::cache_global_curr_center` | `0x0050C740` | Builds the transient working "global" sphere center from `frame.m_fl2gv·local + frame.m_fOrigin` — cell-local only, NO landblock-world offset, rebuilt from `curr_pos` each step. |
|
||||||
|
|
||||||
|
acdream **already ports** `AdjustToOutside`/`GetOutsideLcoord`/`LcoordToGid`/`BlockidToLcoord` in
|
||||||
|
`src/AcDream.Core/Physics/LandDefs.cs` (from the #106 work) — WITH the [0,192) wrap (`LandDefs.cs:130-145`).
|
||||||
|
The gap is that the per-frame outdoor resolve (`CellTransit.BuildCellSetAndPickContaining`) does NOT run the
|
||||||
|
wrap+rebase; it re-derives `lbPrefix` from a world-XY scan against a `(0,0)`-or-baked-offset origin.
|
||||||
|
|
||||||
|
### acdream divergence sites (the streaming-relative physics frame — what to change)
|
||||||
|
|
||||||
|
- **The frame itself:** physics position is a streaming-relative world `Vector3`
|
||||||
|
(`worldXY = (lb − _liveCenter)·192 + local`). Sites: `PhysicsEngine.cs:603-614` (the `foreach(_landblocks)`
|
||||||
|
outdoor membership scan), `:624`, `:858-860` (returns `lbPrefix | (targetCellId & 0xFFFF)`).
|
||||||
|
- **Baked per-landblock WorldOffset** computed against the MOVING center at load: `GameWindow.cs` origin
|
||||||
|
computation `~:4992` (and the WorldOffset inverse used outbound at `~:2930-2931` / `~:4992-4993` — note the
|
||||||
|
synthesis cited `:7763-7765` for the outbound `localY` conversion but a verifier could not locate that
|
||||||
|
exact line; **re-locate the outbound (cell, local) builder** — it's where `localY = Position.Y − (lbY −
|
||||||
|
_liveCenterY)·192` happens).
|
||||||
|
- **The `(0,0)` fallback** (proximate trigger): `CellTransit.cs:736` (discarded bool) → consumed at the seed
|
||||||
|
`AddAllOutsideCells` (`:758` → `:242`), the containing-pick (`:845`), and the other seed (`:484`).
|
||||||
|
`CellGraph.cs:47-56` (`TryGetTerrainOrigin` returns `(Zero,false)` for unregistered terrain).
|
||||||
|
- **The teleport that leaves running velocity live:** `src/AcDream.App/Input/PlayerMovementController.cs`
|
||||||
|
(NOTE: App/Input, not Core/Physics) — `SetPosition` zeros velocity `~:803` but the same-frame motion path
|
||||||
|
re-applies the running vector `~:943-980`. A teleport arrival should call the motion-idle path.
|
||||||
|
- `TransitionTypes.cs ~:2315` (`SetCheckPos` commits the marched cell id without moving position).
|
||||||
|
- **The recenter:** `GameWindow.OnLivePositionUpdated ~:5447` (drop-source + `_liveCenterX/Y=lbX/lbY`) and the
|
||||||
|
login recenter `~:2879-2909`. These STAY (render frame), but physics must stop depending on them.
|
||||||
|
|
||||||
|
### Shape of the port (brainstorm this — do not just start coding)
|
||||||
|
|
||||||
|
The end state: a physics `Position { uint ObjCellId; Frame{ Vector3 LocalOrigin∈[0,192) for outdoor; Quaternion } }`,
|
||||||
|
carried by the player/physics body instead of a streaming-relative world `Vector3`. Cross-cell offsets come
|
||||||
|
ONLY from `get_block_offset(cellA, cellB)` (port `0x0043E630`). Every `SetPosition`/teleport/cross-landblock
|
||||||
|
move runs `AdjustToOutside` to re-wrap. `_liveCenterX/Y` is used by the RENDERER (and the outbound wire
|
||||||
|
conversion derives the wire (cell, local) directly from the cell-relative Position — no center math needed,
|
||||||
|
which kills the 17410 leak at the source). The streaming `WorldOffset` baked per-landblock can stay for the
|
||||||
|
RENDER mesh placement but the physics resolve must not read it.
|
||||||
|
|
||||||
|
**This is a large, seam-crossing change.** It touches `PhysicsEngine`, `CellTransit`, `TransitionTypes`,
|
||||||
|
`CellGraph`, the player controller, the outbound wire builder, and every test that constructs a physics
|
||||||
|
position. Scope it via `superpowers:brainstorming` FIRST, then write a plan, then execute in reviewable
|
||||||
|
slices (likely: (1) introduce cell-relative `Position` alongside the world frame; (2) port `get_block_offset`
|
||||||
|
+ route the resolve through it; (3) make `AdjustToOutside` run on the per-frame path; (4) flip the player
|
||||||
|
body to cell-relative; (5) make the outbound wire derive from it; (6) make `_liveCenter` render-only; (7)
|
||||||
|
delete the baked-WorldOffset physics reads). Conformance: replay the captured runaway + the existing
|
||||||
|
`CellarUp`/`DoorBug`/membership harnesses must stay green.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Apparatus (use this — do NOT rebuild)
|
||||||
|
|
||||||
|
- **The captured runaway:** `desync-capture.jsonl` (worktree root, 72,401 `ResolveWithTransition` records:
|
||||||
|
`input{currentPos,targetPos,cellId,sphere*,stepUp/Down,isOnGround,moverFlags,movingEntityId}`,
|
||||||
|
`bodyBefore/After{position,orientation,velocity}`, `result`). Runaway records: cellId `0xC95B0001`→`0xC9000008`
|
||||||
|
(decimal 3372220424). Velocity at first far-town record = `(3.637,−11.276,0)` (the stale run).
|
||||||
|
- **Probes (env vars, no rebuild):** `ACDREAM_PROBE_CELL=1` → `[cell-transit] old->new pos=(x,y,z) reason=`;
|
||||||
|
`ACDREAM_CAPTURE_RESOLVE=<path>` → the JSON capture; `ACDREAM_PROBE_RESOLVE=1` → per-resolve `[resolve]`
|
||||||
|
lines; `ACDREAM_DUMP_LIVE_SPAWNS=1` → spawn + re-hydrate + recenter lines.
|
||||||
|
- **The session log of the repro:** `…/tasks/bu932mwj3.output` (cell-transit trail + `[snap]` + teleport
|
||||||
|
arrivals + the healthy Holtburg cell-transits for comparison).
|
||||||
|
- **Test harness template:** build `tests/AcDream.Core.Tests/Physics/TeleportFarTownRunawayTests.cs` from the
|
||||||
|
capture (apparatus = `PhysicsResolveCapture` + the `CellarUpTrajectoryReplayTests` `LiveCompare_*` pattern).
|
||||||
|
Assert: with `0xC95A` unregistered, the cell-relative resolve keeps cell+local consistent (no march). Include
|
||||||
|
a non-south case (east-edge spawn) — the cascade is direction-agnostic.
|
||||||
|
|
||||||
|
## Open items / risks / DO-NOT-RETRY
|
||||||
|
|
||||||
|
- **Verifier corrections to the synthesis prose (use the corrected facts):** march rate is ~1 landblock per
|
||||||
|
physics QUANTUM (~33 ms), not per render frame (~40 capture records per crossing); `max|Position.Y|≈85.67`
|
||||||
|
(not 61.9); the true settle is `(-6.124,-30.186,12.000)` og=True (not `(21.87,-21.62,-6.50)` — that's a
|
||||||
|
mid-fall entry); `PlayerMovementController.cs` is under `src/AcDream.App/Input/`. The MECHANISM is unchanged.
|
||||||
|
- **DO-NOT-RETRY:** the physics digest DO-NOT-RETRY table has NO conflict (it covers cellar-up/door/lip
|
||||||
|
wedges — different code path). But **do NOT attempt a membership "stickiness"/hysteresis fix** — the table
|
||||||
|
explicitly disproves stickiness for the lip path; the correct shape is cell-relative storage, not hysteresis.
|
||||||
|
Also the digest already names this seam: `TryGetTerrainOrigin` "Zero fallback = legacy anchor-frame" + the
|
||||||
|
[[feedback_latent_bug_masked_by_fallback]] lesson ("a fallback masked a production bug") — this is that
|
||||||
|
pattern recurring. Read the physics digest first.
|
||||||
|
- **Map-edge towns:** confirm a destination at the world edge (a needed neighbor landblock genuinely doesn't
|
||||||
|
exist) resolves sanely under the cell-relative frame (retail handles this via the absolute lcoord grid —
|
||||||
|
`get_outside_lcoord` clamps; verify the acdream port matches).
|
||||||
|
- **Outbound wire:** after the port, the wire (cell, local) must derive from the cell-relative Position
|
||||||
|
directly. Re-locate the current outbound builder (the synthesis's `:7763-7765` was unverified).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Launch / probes / accounts (unchanged)
|
||||||
|
|
||||||
|
```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 = "notan"; $env:ACDREAM_TEST_PASS = 'MittSnus81!' # single-quote the '!'
|
||||||
|
$env:ACDREAM_PROBE_CELL = "1"
|
||||||
|
$env:ACDREAM_CAPTURE_RESOLVE = "<worktree>\desync-capture2.jsonl"
|
||||||
|
dotnet run --project src\AcDream.App\AcDream.App.csproj --no-build -c Debug 2>&1 | Tee-Object launch.log
|
||||||
|
```
|
||||||
|
Account `notan`/`MittSnus81!` → `+Je` (guid `0x50000001`), spawns Holtburg, reaches the 0x0007 Town Network
|
||||||
|
hub → portals to far towns (the repro: hub → any far town → the runaway arms when you arrive still running).
|
||||||
|
**The user drives the client lifecycle** — do NOT kill/close clients; `dotnet run` when asked, read logs.
|
||||||
|
**Visual confirmation requires the user** (the one genuine stop point).
|
||||||
|
|
||||||
|
## Pointers
|
||||||
|
- ISSUES `#145` (reopened — full verified root cause + the A-vs-B decision), `#138` (DONE).
|
||||||
|
- Physics digest (SSOT + DO-NOT-RETRY): `claude-memory/project_physics_collision_digest.md` — read FIRST.
|
||||||
|
- Workflow output (full synthesis + 3 verdicts): `…/tasks/w8wm5fln4.output`; transcripts under
|
||||||
|
`…/subagents/workflows/wf_87607d15-c43/` (the retail-oracle agent's report is the decomp goldmine).
|
||||||
|
- Register: AP-36 (the streaming-center gate) + AP-48 (#138 re-hydrate) — the B port will retire/rewrite the
|
||||||
|
physics half of the streaming-relative-frame divergence; add/update register rows in the porting commits.
|
||||||
|
- References: `named-retail/acclient_2013_pseudo_c.txt` + `acclient.h` + Ghidra patchmem :8081 (the oracle);
|
||||||
|
`references/ACE` + `references/holtburger` (the wire/client frame cross-check).
|
||||||
Loading…
Add table
Add a link
Reference in a new issue