diff --git a/docs/plans/2026-04-11-roadmap.md b/docs/plans/2026-04-11-roadmap.md index 9cd290e..ab41b7d 100644 --- a/docs/plans/2026-04-11-roadmap.md +++ b/docs/plans/2026-04-11-roadmap.md @@ -28,6 +28,7 @@ | 7.1 | EnvCell room geometry — walls/floors/ceilings via CellStruct + Environment dats | Visual ✓ | | 9.1 | Translucent render pass (AlphaBlend / Additive / InvAlpha + per-kind blend funcs) | Visual ✓ | | 9.2 | Back-face culling in translucent pass (fixes lifestone crystal) | Visual ✓ | +| A.1 | Streaming landblock loader — runtime-configurable visible window (default 5×5, `ACDREAM_STREAM_RADIUS`), camera-centered offline / player-centered live, hysteresis-based unloads, pending-spawn list for late CreateObject events | Live ✓ | Plus polish that doesn't get its own phase number: - FlyCamera default speed lowered + Shift-to-boost @@ -39,12 +40,12 @@ Plus polish that doesn't get its own phase number: ## Phases ahead — agreed order -### Phase A — Foundation (next) +### Phase A — Foundation (in progress) **Goal:** walk across 10+ landblocks without crashes, without hitches at landblock boundaries, and without framerate cratering. **Sub-pieces:** -- **A.1 — Streaming landblock loader.** Runtime-configurable visible window (default 5×5, `ACDREAM_STREAM_RADIUS` env var override). Center follows the camera offline and the player in live mode. Background worker thread loads landblocks CPU-side (dats, scenery, interior, entities); the render thread drains a completion outbox and performs GPU upload. Unloads happen at `radius + 1` distance to avoid churn. +- **✓ SHIPPED — A.1 — Streaming landblock loader.** Runtime-configurable visible window (default 5×5, `ACDREAM_STREAM_RADIUS` env var override). Center follows the fly camera offline and the server-sent player position in live mode. Currently runs **synchronously** on the render thread — the original async-worker design hit DatCollection's lack of thread safety and was reverted for correctness. The Channel-based outbox API is preserved so async loading can return cleanly when `Phase A.3` introduces a thread-safe dat wrapper. Pending-spawn list in `GpuWorldState` parks live `CreateObject` events whose target landblock hasn't been streamed in yet and back-fills them when it arrives, so spawn-vs-streaming races are no longer racy at all. `MaxCompletionsPerFrame=4` spreads the 5×5 first-frame load over ~7 frames (~116ms) to avoid GPU OOM. - **A.2 — Frustum culling + LOD.** Per-landblock AABB test against the view frustum in `StaticMeshRenderer.Draw`, skipping drawn entities in culled landblocks. Per-entity culling deferred. No LOD mesh levels yet — that's Phase C or later. - **A.3 — Background net I/O thread.** `WorldSession` runs its receive loop on a dedicated thread; parsed game messages are posted to a concurrent queue the render thread drains from `OnUpdate`. Event invocations still happen on the render thread (preserves existing handler assumptions). Removes packet drops under frame stalls. - **A.4 — Async dat decoding.** Folded into the streaming worker — it's the worker's read path, not a separate subsystem. Called out here because regressions in dat caching could land on this surface. @@ -156,8 +157,8 @@ Not detailed here; each gets its own brainstorm when it becomes relevant. | Character clothing missing / wrong | **5 FIXED** ✓ | | Statue wrong color / wrong scale | **5 FIXED** ✓ | | Holtburg sign half-buried | **5 FIXED** ✓ | -| Can't walk past the loaded 3×3 window | **Phase A (Foundation)** | -| Frame hitch crossing landblock boundary | **Phase A** | +| Can't walk past the loaded 3×3 window | **A.1 FIXED** ✓ (5×5 default, `ACDREAM_STREAM_RADIUS` to tune) | +| Frame hitch crossing landblock boundary | **Phase A.3** (synchronous loader for now; async returns when DatCollection is thread-safe) | | Walking around doesn't move me on the server | **Phase B (Gameplay)** | | Can't talk to NPCs | **Phase B** | | Can't open a door | **Phase B** |