acdream/docs/research/2026-06-24-teleport-out-issues-handoff.md
Erik 57e79dc679 docs: handoff — two teleport-OUT issues (no-collision-after-death, char-missing)
Both observed 2026-06-24 after the FPS work; both are the known #135/#138 placed-
but-unstreamed streaming gap (NOT FPS-work regressions — those commits are render-
only). Handoff maps the symptoms to ISSUES, flags the delicate-area lessons (no
guess-patches, the reverted hold, fix-the-foundation, capture-first), and points
at the physics digest + streaming refs + capture apparatus.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-24 07:57:16 +02:00

5.7 KiB

Handoff — two teleport-OUT issues (no-collision-after-death, char-missing-after-portal) — 2026-06-24

Branch/worktree: observed on claude/thirsty-goldberg-51bb9b (C:\Users\erikn\source\repos\acdream\.claude\worktrees\thirsty-goldberg-51bb9b). References / named-retail live in the MAIN repo C:\Users\erikn\source\repos\acdream\.

These are NOT regressions from the dense-town FPS work. That work (commits 290e731 cell-object batching, 9f51a4d cell-particle consolidation, a9d06a6 apparatus strip, 02578dd docs) is finalized + committed and touched render files ONLY — zero physics / collision / streaming / movement / membership code (verified: git show --name-only 290e731 9f51a4d a9d06a6). Do NOT suspect those commits. The only indirect link: higher FPS makes the same few-tick transient render across more frames, so it's more noticeable; the underlying bug predates the FPS work (and collision is FPS-independent — physics ticks at a fixed rate).


The two issues (user-observed, 2026-06-24)

Both are on the teleport-OUT-to-outdoor path and are almost certainly the same known placed-but-unstreamed streaming gap (#135/#138 family). ISSUES §51 says a streaming-gap fix "would fix both symptoms." They're split into two prompts only so they can be tackled independently — whoever picks one should read both.

Issue A — no collision after death → portaled to Holtburg

  • Symptom: after dying and being teleported to Holtburg, the player has no collision (falls through / clips).
  • Root (known, NOT this session's work): the placed-but-unstreamed gap — on a teleport the player is placed immediately, but the destination landblock streams in a few ticks later; during that gap the physics resolve runs against an empty world (no terrain/collision meshes loaded), so collision finds nothing.
  • ISSUES refs: docs/ISSUES.md:51 (the far-town runaway/march + Z free-fall, "same root as #135/#138 placed-but-unstreamed gap"), and docs/ISSUES.md:138 (acceptance: "the outdoor world fully streamed, collision working"). Whether the death lands in a dungeon-exit (#138 proper) or an outdoor respawn-to-lifestone, the placement→stream→resolve timing is the same.

Issue B — char missing sometimes after portal to outside

  • Symptom: after portaling outside, the character (and other entities) are missing for a moment, then pop in.
  • Root (known = #138): teleport-OUT re-hydrates world entities with fresh monotonic Ids a few ticks after arrival (GameWindow ~:3251, Id = _liveEntityIdCounter++); during that gap they aren't in the draw set, so they appear late ("objects come back"). The player is one of them.
  • ISSUES refs: docs/ISSUES.md:265 (#138 — "Teleport OUT of a dungeon loads the outdoor world incompletely + position desync"), docs/ISSUES.md:299 (the fresh-Id re-hydration detail + the cache-invalidation side-finding).

⚠ This is the DELICATE area — read before touching

  1. DO NOT guess-patch. The teleport/streaming runaway burned ~5 failed attempts (#145). Build the apparatus FIRST (capture → replay), per memory/feedback_apparatus_for_physics_bugs.md.
  2. A "streaming HOLD" was tried and REVERTED. Freezing the per-tick resolve until the landblock loads produced a ~10 s freeze; the user called it "shaky and bandaid" (feedback_no_holds_for_slow_foundation in memory). The real fix is fix the foundation — make the destination stream with placement (the async equivalent of retail's synchronous load), not a gate that masks a slow stream.
  3. Capture first. Reproduce a real teleport and capture the placement→stream→resolve sequence before proposing anything.

Where to start reading (in order)

  • claude-memory/project_physics_collision_digest.md — physics / collision / cell-membership SSOT + the DO-NOT-RETRY table. START HERE.
  • docs/ISSUES.md #135, #138, #107, #145 (the teleport/streaming family).
  • memory/reference_two_tier_streaming.md — the A.5 streaming architecture (Region → Controller → LandblockStreamer → GpuWorldState; near/far radii).
  • The teleport/placement + streaming code: grep GameWindow for the snap/placement path ([snap], EXIT-expand, _liveEntityIdCounter), the streaming dungeon EXIT-expand → (x,y) logs, and PlayerMovementController / PhysicsEngine arrival resolve.

Capture apparatus (already in the tree)

  • ACDREAM_CAPTURE_RESOLVE=<path> — JSON-Lines of every player-side PhysicsEngine.ResolveWithTransition (inputs + body before/after + result). Run it across a death→Holtburg teleport to see the resolve running against the empty world during the gap.
  • ACDREAM_PROBE_CELL=1 — one [cell-transit] line per player cell change (old→new, reason). Low volume; shows the post-teleport cell march.
  • ACDREAM_PROBE_RESOLVE=1 — per-resolve line (input/target/output, grounded, contact-plane, responsible entity). Heavy.
  • Launch (PowerShell): user notan / MittSnus81!, local ACE 127.0.0.1:9000. See CLAUDE.md "Running the client against the live server".

Likely fix shape (hypothesis, NOT confirmed — capture first)

Make the teleport destination's near landblocks stream synchronously (or placement waits on the first stream tick) so the arrival resolve never runs against an empty world, AND the entity re-hydration completes before/with the first drawn frame — rather than a per-tick HOLD. Both symptoms (no-collision, char-missing) collapse to "the world isn't there yet when we place + resolve + draw." Confirm the exact gap timing from a capture before committing to a shape.