plan(G.3a): core teleport-into-dungeon implementation plan (#133)
TDD plan for the gated G.3a core: a pure TeleportArrivalController state machine (hold-until-hydration + force-snap on impossible/timeout) + its GameWindow wiring (replace the unconditional arrival snap with recenter + deferred BeginArrival; per-frame Tick; readiness predicate reusing the #107 login triplet) + the EnvCell physics/visibility hydration decouple + the visual acceptance gate. G.3b/c/d get their own plans after the gate. Also syncs the spec: the readiness predicate reuses SampleTerrainZ + IsSpawnCellReady + IsSpawnClaimUnhydratable (the validated #107 login gate) rather than a new IsLandblockApplied query — strictly more faithful, less new surface. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
6680fd42b2
commit
c9650bd3bd
2 changed files with 653 additions and 11 deletions
|
|
@ -130,9 +130,12 @@ All five verified against current code this session (high confidence).
|
|||
a 5×5 near window; physics ready +1-2 frames.
|
||||
- Recenter keeps the old neighborhood until hysteresis unload (NearRadius+2
|
||||
demote, FarRadius+2 unload), so the player isn't instantly stranded.
|
||||
- **New code needed:** a "destination landblock applied" query + dest-coord
|
||||
validation (reject out-of-world coords — a malformed portal dest would otherwise
|
||||
leave the player in an invisible, unloadable landblock).
|
||||
- **New code needed:** reuse the #107 login-gate **terrain-ready signal**
|
||||
`_physicsEngine.SampleTerrainZ(x,y) is not null` (non-null once the destination
|
||||
terrain landblock has applied) — no separate "landblock applied" query is
|
||||
required. Plus dest-coord validation (reject out-of-world coords — a malformed
|
||||
portal dest would otherwise leave the player in an invisible, unloadable
|
||||
landblock).
|
||||
|
||||
### 2.4 EnvCell hydration coupling (latent landmine — decouple)
|
||||
- In `BuildInteriorEntitiesForStreaming` (`GameWindow.cs:5564-5651`), both
|
||||
|
|
@ -203,17 +206,22 @@ the dungeon cell, on the floor, with walls blocking — no ocean, no ACE
|
|||
via the safety-net demote (loud log), exit PortalSpace.
|
||||
- `now > deadline` (timeout, ~10 s) → force-snap via safety-net demote + loud
|
||||
log, exit PortalSpace. (See §5 — failure-surfacing, not symptom-masking.)
|
||||
- `IsLandblockApplied(destLb) && IsSpawnCellReady(destCell)` → ready: go to 3.
|
||||
- `SampleTerrainZ(destPos) != null && (outdoor || IsSpawnCellReady(destCell))`
|
||||
→ ready: go to 3.
|
||||
- else stay frozen, retry next frame.
|
||||
3. `Placing`: call the **existing** `Resolve(destPos, destCell, Vector3.Zero, …)`.
|
||||
Because the cell is now hydrated, Resolve takes the #111 validated-claim branch
|
||||
→ `WalkableFloorZNearest` grounds the player on the EnvCell floor. Snap entity
|
||||
+ controller (existing `:4935-4939` code), exit PortalSpace, resume input.
|
||||
|
||||
**New streaming query — `IsLandblockApplied(uint landblockId)`** (on
|
||||
`StreamingController` / `GpuWorldState`): true once the landblock's terrain has
|
||||
been applied (AABB set in `ApplyLoadedTerrainLocked`) **and** `AddLandblock` has
|
||||
run into physics. Gate the hold on this, not on the GPU mesh alone.
|
||||
**Readiness predicate — reuse the #107 login triplet (no new query).** The
|
||||
hold gates on exactly the three checks the login auto-entry gate already uses
|
||||
(`GameWindow.cs:1010-1024`), evaluated against the teleport's `(destPos,
|
||||
destCell)` instead of the spawn claim: `SampleTerrainZ(destPos.X, destPos.Y) is
|
||||
not null` (destination terrain applied) ∧ (outdoor cell OR
|
||||
`IsSpawnCellReady(destCell)`); `IsSpawnClaimUnhydratable(destCell)` short-circuits
|
||||
an impossible claim to immediate placement. This reuses proven, validated code
|
||||
rather than introducing a parallel "landblock applied" query.
|
||||
|
||||
**Dest-coord validation:** in `OnLivePositionUpdated`, reject a destination whose
|
||||
`(lbX, lbY)` is out of the world grid before recenter; log + abort the teleport
|
||||
|
|
@ -288,7 +296,7 @@ command bus.
|
|||
2. fake UpdatePosition(destCell) → validate dest coords → recenter streaming to dest lb
|
||||
→ prioritize-load dest lb → re-send LoginComplete
|
||||
3. HOLD (TeleportArrivalController.Tick, each frame in PortalSpace):
|
||||
ready = IsLandblockApplied(destLb) && IsSpawnCellReady(destCell)
|
||||
ready = SampleTerrainZ(destPos) != null && (outdoor || IsSpawnCellReady(destCell))
|
||||
- not ready → stay frozen, retry [G.3c: tunnel holds in TAS_TUNNEL/_CONTINUE]
|
||||
- impossible → IsSpawnClaimUnhydratable → safety-net demote + loud log
|
||||
- timeout → force-snap + loud log + leave PortalSpace
|
||||
|
|
@ -374,7 +382,7 @@ visual gate.
|
|||
| Unit | Location | Does | Depends on |
|
||||
|---|---|---|---|
|
||||
| `TeleportArrivalController` | `AcDream.App/World/` | Owns the `Idle/Holding/Placing` phase + `_pendingArrival`; decides hold-vs-place each frame | readiness predicate (injected), `Resolve` (injected), PortalSpace state |
|
||||
| readiness predicate | `StreamingController` + `PhysicsEngine` | `IsLandblockApplied(lb)` ∧ `IsSpawnCellReady(cell)`; `IsSpawnClaimUnhydratable(cell)` | dat `LandBlockInfo`, `DataCache` |
|
||||
| readiness predicate | `PhysicsEngine` (reused #107 triplet) | `SampleTerrainZ(pos)` ∧ (outdoor ∨ `IsSpawnCellReady(cell)`); `IsSpawnClaimUnhydratable(cell)` | `DataCache`, dat `LandBlockInfo` |
|
||||
| hydration decouple | `GameWindow.BuildInteriorEntitiesForStreaming` | `BuildLoadedCell` + `CacheCellStruct` gated on cellStruct/BSP, not render mesh | `cellStruct`, `PhysicsBSP` |
|
||||
| `TeleportAnimState` FSM (G.3c) | `AcDream.App` UI/render | Portal-tunnel fade FSM; hold-exit gated on the readiness predicate | `m_pPortalSpace` viewport, the readiness predicate |
|
||||
| recall builders (G.3d) | `AcDream.Core/Network/Actions` | Zero-payload outbound game actions | command bus |
|
||||
|
|
@ -419,7 +427,8 @@ visual gate.
|
|||
(`IsSpawnClaimUnhydratable`); hold plausible-but-slow with a ~10 s ceiling;
|
||||
on timeout force-snap + loud log (fail visibly, never freeze).
|
||||
3. **Big-jump streaming?** Verified to work (Chebyshev recenter). Add only
|
||||
`IsLandblockApplied` + dest-coord validation.
|
||||
dest-coord validation; the readiness gate reuses `SampleTerrainZ` (no new
|
||||
streaming query).
|
||||
4. **EnvCell placement vs flat terrain?** The #111 `WalkableFloorZNearest` EnvCell
|
||||
path (identical to the cellar path that already works); the flat terrain
|
||||
renders below. The gate guarantees the cell is hydrated before Resolve runs.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue