acdream/docs/research/2026-06-21-teleport-issues-handoff.md
Erik 59b4868408 docs: handoff — teleport issues cluster (#145 residual + retail teleport flow + FPS leak)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-21 18:11:37 +02:00

104 lines
6.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Handoff — teleport issues cluster (2026-06-21)
**Branch:** `claude/thirsty-goldberg-51bb9b` — committed, NOT merged ("merge later").
**Account:** `notan` / `MittSnus81!``+Je`. Portal via the Town Network hub (`0x0007`) to far towns.
---
## What shipped this session (context)
#145 **cell-relative physics frame (Option B)**, Slices 13 + 7 (`438bb68`→`403a338`). The carried-anchor
fix closes the far-town cascade **for a STREAMED-terrain arrival** — live-verified across ~10 far-town
landblocks over 2 sessions, zero march. Design + plan:
`docs/superpowers/specs/2026-06-21-145-cell-relative-physics-frame-design.md` + the matching plan.
Adversarial review passed (2 flagged issues were verified false positives). Slices **46** (contact-plane /
walkable cell-relative + `_liveCenter` fully render-only — invisible architectural completeness) remain.
---
## Work item A — #145 RESIDUAL (reopened): unstreamed-arrival-near-edge cascade
**Trigger:** a teleport that arrives onto a **NOT-YET-STREAMED** landblock **near an edge** → the cascade
recurs (+ a Z free-fall). **Evidence** (`launch5.log`):
- `[snap] claim=0xC98C0028 pos=(113.666,190.259,22.010) branch=NO-LANDBLOCK (lbs=0) -> verbatim` — arrival
local Y=190.3, **1.7 m from the 192 edge**, destination not streamed → cell marches `0xC98C → 0xC9FE`
(+2 lbY/tick), Z free-falls 22→19; outbound wire sends the marched cell `C9FE0031` + compensating garbage
`localY=21684` → ACE `MOVEMENT SPEED` / `failed transition`**player stuck**.
- Same session, **mid-block** unstreamed arrival `0x977B000C` (Y=73.8) → Z free-fall only, **no march**.
- Hub `0x00070133` **VALIDATED** (cells resident) → fine.
**Root (HYPOTHESIS — not apparatus-confirmed):** outdoor teleport places immediately but the destination
streams a few ticks later (`streaming: dungeon EXIT-expand -> (201,140)` logs just after placement). During
the gap the resolve runs against an empty world; at an edge the player crosses into the **unstreamed
neighbour**, where the carried anchor (which computes to `(0,0,0)` at the recentered center) gives no
protection. **Same root as the Z free-fall** (`#135`/`#138` placed-before-streamed gap).
**⚠️ DO NOT guess-patch** (original #145 burned 5 attempts). **Apparatus first:** add a diagnostic that logs
the **anchor value + the engagement-guard state** in `PhysicsEngine.ResolveWithTransition` at the crossing
tick (behind a probe flag), reproduce a `0xC98C`-style arrival once, and confirm whether the anchor
**disengages** (CellId/CellPosition landblock divergence) or the **body is repositioned into a marched frame
first**. *Then* the fix is a known quantity.
**Likely fix:** a **streaming-gap HOLD** — freeze the per-tick resolve (no integration/gravity, no membership
march) while the player's landblock is unloaded, until it streams in (a few ticks). The async-streaming
equivalent of retail's synchronous load; would fix **both** the cascade and the Z plunge.
**Note:** this may be **subsumed by Work item B** — the retail teleport flow holds until the world loads, so
there's no unstreamed gap to begin with. Decide A-vs-B ordering at brainstorm.
---
## Work item B — KEYSTONE FEATURE: the retail teleport flow
**Symptoms (user-reported; all ONE root):**
1. Camera **floats** to the destination on teleport (disliked).
2. Teleport **takes too long** / feels off vs retail.
3. Player **input is not locked** during teleport.
**Retail behaviour (user = oracle, treat as axiom):** teleport plays an **animation** (portal effect), holds
input + camera, **waits for the world to load**, then exits/places the player. Used for **ALL** teleportation:
**login, logout, death, portal.**
**Insight:** acdream places **immediately** (raw placement → the floating camera + the unstreamed gap). A
faithful retail teleport flow (anim + input/camera lock + **hold-until-loaded** + single exit point) fixes the
float, the timing, the input-lock, **and very likely Work item A.** This is the keystone.
**This is a FEATURE → start with `superpowers:brainstorming`** (the user is the retail oracle on look/feel).
**Research first:** grep `docs/research/named-retail/acclient_2013_pseudo_c.txt` for the portal/teleport flow
— the teleport animation, the loading hold, the PortalSpace exit condition, and the unified path for
login/logout/death/portal. **Extend, don't rebuild:** acdream already has `PlayerState.PortalSpace`,
`TeleportArrivalController`, and `TeleportArrivalRules.Decide` (`src/AcDream.App/World/` + `GameWindow`); the
flow should slot the anim + hold-until-loaded into that machinery.
---
## Work item C — FPS leak after teleports (perf bug, SEPARATE)
**Symptom:** FPS drops low after a couple of teleports (cumulative).
**Hypothesis:** a streaming/entity **leak** — landblocks or render/physics entities not freed on teleport,
accumulating across round-trips (candidates: dungeon collapse/expand not cleaning up; `RehydrateServerEntities`
/ `_lastSpawnByGuid` accumulating; `GpuWorldState` entities not pruned). **NEXT:** capture FPS + landblock /
entity counts across N teleports (`ACDREAM_DUMP_LIVE_SPAWNS=1` + streaming logs + the DebugPanel counts), find
what grows unbounded. Independent of A and B.
---
## Pointers / apparatus
- **Logs (worktree root):** `launch5.log` (#145 residual capture — the `0xC98C` stuck-at-`21684` run),
`launch4.log` (Z free-fall + a 3-far-town round-trip), `launch3`/`launch2` (clean streamed-arrival runs).
- **#145 record:** `docs/ISSUES.md` #145 (reopened, with the trigger table) + the physics digest banner
(`claude-memory/project_physics_collision_digest.md`).
- **Probes (no rebuild):** `ACDREAM_PROBE_CELL=1` (`[cell-transit]`), `ACDREAM_PROBE_RESOLVE=1`,
`ACDREAM_CAPTURE_RESOLVE=<path>`, `ACDREAM_DUMP_LIVE_SPAWNS=1`.
- **Decomp oracle:** `docs/research/named-retail/` (grep `class::method`); for the teleport flow, look at the
portal/teleport + DDD-loading + animation paths.
- **Wire cross-check:** `references/holtburger` (client teleport flow) + `references/ACE` (server teleport /
`MOVEMENT SPEED` validation — the `failed transition` rejects).
## Suggested order (brainstorm to confirm)
1. **B first** (retail teleport flow) — it's the keystone and likely subsumes **A**. Brainstorm → spec → build.
2. Re-test **A**: if the hold-until-loaded flow eliminates the unstreamed gap, the #145 residual is gone; if a
narrow edge case survives, apply the diagnostic + targeted hold.
3. **C** (FPS leak) — independent; can run in parallel as its own investigation.
4. (Background) Slices **46** — the invisible Option-B completeness, unrelated to this cluster.