diff --git a/docs/superpowers/plans/2026-06-21-145-cell-relative-physics-frame.md b/docs/superpowers/plans/2026-06-21-145-cell-relative-physics-frame.md index f5d14ee0..09b2b401 100644 --- a/docs/superpowers/plans/2026-06-21-145-cell-relative-physics-frame.md +++ b/docs/superpowers/plans/2026-06-21-145-cell-relative-physics-frame.md @@ -322,6 +322,11 @@ Co-Authored-By: Claude Opus 4.8 (1M context) " Note: the OTHER `TryGetTerrainOrigin` site (`CellTransit.cs:484`, `BuildShadowCellSet`) is registration-side collision (Slice 4 concern), NOT the player pick — leave it for Slice 4. +**⚠ Edge cases surfaced during design (2026-06-21) — handle these or regress #98–#112:** +- **cellId ↔ anchor must share a landblock.** The carried anchor `body.Position − CellPosition.Frame.Origin` is the origin of `CellPosition`'s landblock; the pick's `AdjustToOutside` starts from the passed `cellId`. If `cellId` is the *lagging/marched* controller `CellId` while `CellPosition` is correct, the pick mixes a marched landblock with a correct local → garbage. **Fix: the controller passes `_body.CellPosition.ObjCellId` as the resolve cell for the OUTDOOR case** (so `cellId == CellPosition.ObjCellId`, consistent with the anchor); indoor keeps the BSP-tracked `CellId`. Selection: `(_body.CellPosition.ObjCellId outdoor & seeded && current is outdoor) ? CellPosition.ObjCellId : CellId`. +- **CellPosition goes stale indoors.** The Slice-2a setter only maintains `CellPosition` for outdoor cells (low word 1..0x40); while the player is inside a building (`CellId` indoor) it is NOT updated. On building EXIT (indoor→outdoor) the carried anchor would be stale. **Fix: re-seed `SnapToCell` from the resolve's outdoor result when membership transitions indoor→outdoor** (the resolve already returns the correct outdoor cell + the world position gives the local via the just-computed anchor). Verify with an indoor↔outdoor round-trip replay (CellarUp / cottage harness) in addition to the far-town test. +- **Sweep threading vehicle:** add `Vector3? CarriedBlockOrigin` to `SpherePath` (alongside `CheckCellId`, ~`:336`); set it in `PhysicsEngine.ResolveWithTransition` right after `InitPath` (`:975`) from `body`; read it at the `FindCellSet` call (`TransitionTypes.cs:2291`) and pass through `FindCellSet`→`FindCellList`→`BuildCellSetAndPickContaining` (default `null` = legacy `TryGetTerrainOrigin`, so every existing caller/test is unaffected). + **Files:** - Modify: `src/AcDream.Core/Physics/CellTransit.cs:732-736` (the discarded-bool fallback), `:242` (`AddAllOutsideCells` block-origin subtraction), `:845-849` (containing pick), `:484` (the other seed) - Modify: `src/AcDream.Core/Physics/PhysicsEngine.cs:603-625` (the resolve loop feeds the pick)