docs(A.5 T27): roadmap + ISSUES + CLAUDE.md updates for A.5 ship

Roadmap (2026-04-11-roadmap.md):
- Status header updated to 2026-05-10 / A.5 as the shipped phase.
- A.5 row added to shipped table (after A.3): two-tier streaming,
  QualityPreset, Bug A/B fixes, deferred items, plan archive link.
- A.5 sub-piece in Phase A section marked SHIPPED with archive link
  (replaces the old "not yet brainstormed" entry).
- N.6 bullet changed from "Currently in flight" to "Planned
  (post-A.5 polish takes priority)"; A.5's landing means the
  "direct higher-radius comparison once A.5 lands" item is now
  available.

ISSUES.md:
- #52 (A.5/lifestone-missing): Holtburg lifestone not rendering since
  A.5 dev; two root-cause candidates; investigation approach.
- #53 (A.5/tier1-redo): classification cache reverted at 9b49009;
  animation-mutation audit required before retry; 1-week estimate.
- #54 (A.5/jobkind-plumbing): Bug A's post-load strip wastes worker
  CPU; proper fix plumbs JobKind through BuildLandblockForStreaming;
  30 min–1 hour estimate.

CLAUDE.md:
- "Currently in flight" paragraph updated from N.6 to Post-A.5 polish
  (issues #52/#53/#54) with note that N.6 follows.
- A.5 shipped paragraph added (mirrors N.5b/N.5/N.4 format).
- WB integration cribs: new bullet documenting the two-tier streaming
  architecture (StreamingRegion / StreamingController / LandblockStreamer
  / GpuWorldState, N₁/N₂ defaults, QualitySettings, spec pointer).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Erik 2026-05-10 10:06:40 +02:00
parent a28a5b7583
commit d93d823539
3 changed files with 102 additions and 18 deletions

View file

@ -46,6 +46,74 @@ Copy this block when adding a new issue:
# Active issues
## #54 — A.5/jobkind-plumbing: far-tier worker loads full entity layer then strips
**Status:** OPEN
**Severity:** LOW (correctness/perf; worker wastes CPU on far-tier LandBlockInfo + scenery generation that is immediately discarded)
**Filed:** 2026-05-10
**Component:** streaming / LandblockStreamer
**Description:** Bug A's fix (commit `9217fd9`) patches at the worker output — after a far-tier job completes the full `LoadNear` path, the result's entity list is stripped before posting to the completion queue. This means far-tier LBs still load `LandBlockInfo` + run `SceneryGenerator` + call `LandblockLoader.BuildEntitiesFromInfo` even though those results are thrown away. At N₂=12, that is ~544 far-tier LBs × unnecessary dat reads + scenery math on promotion sequences.
**Proper fix:** plumb `LandblockStreamJobKind` through `BuildLandblockForStreaming` so far-tier jobs call only `LandBlock` heightmap read + `LandblockMesh.Build`, skipping `LandBlockInfo` + `SceneryGenerator` entirely. The function signature change is ~5 lines; wiring is ~10 lines. Estimated 30 min1 hour total.
**Files:**
- `src/AcDream.App/Streaming/LandblockStreamer.cs``HandleJob` + `BuildLandblockForStreaming`
**Acceptance:** Far-tier LB worker path reads only the `LandBlock` dat file (no `LandBlockInfo`, no `SceneryGenerator` call). Verified by adding a counter diagnostic or via dotnet-trace showing the dat-read call count per job kind.
---
## #53 — A.5/tier1-redo: entity-classification cache broke animation (reverted)
**Status:** OPEN
**Severity:** MEDIUM (perf gap; the classification cache would save ~1-2ms/frame but cannot land until animation-mutation audit is done)
**Filed:** 2026-05-10
**Component:** rendering / WbDrawDispatcher / AnimationSequencer
**Description:** Tier 1 entity-classification cache (commit `3639a6f`) was reverted at `9b49009` due to an animation regression. The cache stored `meshRef.PartTransform` at first-classify time. For static entities this is stable. For animated entities, `AnimationSequencer` mutates `meshRef.PartTransform` every frame to apply the current skeletal pose. The cache froze the pose, causing NPCs and some animated entities to stop animating (some buildings also showed at wrong positions, likely entities incorrectly flagged as animated).
**Root cause:** the "trust MeshRefs as the source of truth" comment in the dispatcher gave false confidence — MeshRefs IS the source of truth, but it is mutated EVERY frame for animated entities.
**Next attempt needs:**
1. Audit `AnimationSequencer` + `AnimationHookRouter` to identify ALL per-frame mutations of `MeshRef` state (not just `PartTransform` — are any other fields mutated?).
2. Redesign cache to: (a) bypass animated entities entirely (classify them each frame, cache only static entities), OR (b) cache only the animation-invariant subset of the classification key (group key, texture handle, blend mode) while reading the per-frame pose from the live `MeshRef`.
3. Test specifically with a moving animated NPC visible on screen before shipping.
**Estimated:** 1 week including audit + redesign + retest.
**Files:**
- `src/AcDream.App/Rendering/Wb/WbDrawDispatcher.cs` — dispatcher classification logic
- `src/AcDream.Core/Animation/AnimationSequencer.cs` — mutation source
- `src/AcDream.Core/Animation/AnimationHookRouter.cs` — secondary mutation source
---
## #52 — A.5/lifestone-missing: Holtburg lifestone not rendering
**Status:** OPEN
**Severity:** MEDIUM (visible missing landmark; lifestone is the player's respawn anchor and should always be visible)
**Filed:** 2026-05-10
**Component:** streaming / rendering
**Description:** The Holtburg lifestone (spinning blue crystal) has not rendered since earlier in A.5 development. Reproduce: launch live client, walk to Holtburg town center, look toward the lifestone position. Should see the spinning blue crystal; instead see nothing.
**Root cause (suspected, two candidates):**
1. Bug A's far-tier strip (commit `9217fd9`) may be incorrectly stripping a near-tier entity. The lifestone's server GUID is `0x5000000A`; its dat object may be registering via the `LandBlockInfo` path but getting stripped as if it were a far-tier entity due to a tier-classification race or incorrect LB-tier tracking.
2. Separate regression from earlier in the A.5 development chain — possibly introduced when entity registration was restructured during T13/T16 streaming controller wiring.
**Investigation approach:**
1. Add a `[STREAMING-DIAG]` log line when far-tier stripping drops an entity — log the entity's GfxObj ID and LB address so the lifestone's GfxObj ID appears in the log if it is being stripped.
2. If not in the strip log, check whether the lifestone's LB is registering as near-tier at all during first-tick bootstrap.
3. Bisect to find the commit that broke it if the above two checks don't isolate the cause.
**Acceptance:** Launch live, walk to Holtburg center, spinning blue crystal visible at the lifestone position. No regression on other static entities in the area.
---
## #50 — Road-edge tree at 0xA9B1 visible in acdream but not retail
**Status:** OPEN

View file

@ -1,6 +1,6 @@
# acdream — strategic roadmap
**Status:** Living document. Updated 2026-05-09 for Phase N.5b shipping (terrain on the modern rendering path via Path C — mirror WB's `TerrainRenderManager` pattern, consume `LandblockMesh.Build` for retail formula compliance; closes ISSUE #51). N.6 (perf polish) remains the in-flight phase.
**Status:** Living document. Updated 2026-05-10 for Phase A.5 shipping (two-tier streaming N₁=4/N₂=12 + QualityPreset system + Bug A/B fixes; closes the two-tier streaming spec). Post-A.5 polish (Tier 1 retry + lifestone fix + JobKind plumbing) is now the in-flight work.
**Purpose:** One source of truth for where the project is and where it's going. Every observed defect or missing feature has a named phase that owns it; when something looks wrong in-game, look here to find the phase that'll address it. Implementation details live in per-phase specs under `docs/superpowers/specs/`, not in this file.
---
@ -31,6 +31,7 @@
| 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 ✓ |
| A.2 | Frustum culling — per-landblock AABB test (Gribb-Hartmann), terrain + static-mesh renderers skip culled landblocks, perf overlay in window title | Visual ✓ |
| A.3 | Background net receive thread — dedicated daemon thread buffers UDP into Channel, render thread drains | Visual ✓ |
| A.5 | Two-tier streaming + horizon LOD — N₁=4 (full detail, 81 LBs) + N₂=12 (terrain only, 544 LBs); fog blend at N₁; per-LB entity dispatcher walk tightened (Change #1 animated-walk fix + Change #2 cached AABB); single-worker off-thread mesh build; mipmaps + 16x anisotropic on TerrainAtlas; A2C with MSAA 4x on foliage; depth-write audit + lock-in test; **NEW T22.5: QualityPreset system** (Low/Medium/High/Ultra) with per-preset radii + MSAA + anisotropic + A2C + completions; env-var overrides per field; F11 mid-session re-apply. **Bug fixes post-T26 ship-prep**: (Bug A) far-tier worker now strips entities from far-tier loads — without this fix, far-tier LBs were loading their full entity layer (~71K entities) defeating the two-tier optimization; (Bug B) WalkEntities switched from per-frame fresh-list allocation to caller-provided scratch list (eliminated ~480 KB/frame GC pressure). **Deferred to post-A.5**: Tier 1 entity-classification cache (first attempt broke animation; revert + redo with animation-mutation audit), lifestone visual (missing in render), JobKind plumbing through BuildLandblockForStreaming (proper Bug A fix), Tier 2/3 perf optimizations (roadmap at docs/plans/2026-05-10-perf-tiers-2-3-roadmap.md). Plan archived at docs/superpowers/plans/2026-05-09-phase-a5-two-tier-streaming.md. | Live ✓ |
| B.3 | Physics MVP resolver foundation — terrain contact, CellSurface prototype, streaming-populated collision inputs, and first `PhysicsEngine` resolver path. Not the complete retail collision system. | Tests ✓ |
| B.2 | Player movement mode — Tab-toggled WASD ground walking, walk/run/idle animations, third-person chase camera, MoveToState + AutonomousPosition outbound, portal entry. Outdoor-only MVP. | Live ✓ |
| D.1 | 2D ortho overlay + font rendering (StbTrueTypeSharp atlas + TextRenderer + DebugOverlay) | Visual ✓ |
@ -82,7 +83,7 @@ Plus polish that doesn't get its own phase number:
- **✓ SHIPPED — A.2 — Frustum culling.** Per-landblock AABB test (Gribb-Hartmann plane extraction + positive-vertex AABB test) in both `TerrainRenderer.Draw` and `StaticMeshRenderer.Draw`. Per-entity culling deferred. LOD deferred to Phase C. Performance overlay in window title shows FPS, frame time, visible/total landblock ratio, entity count, animated count. ~160fps uncapped at 5×5 radius.
- **✓ SHIPPED — A.3 — Background net receive thread.** Dedicated daemon thread continuously pulls raw UDP datagrams from the kernel buffer into a `Channel<byte[]>`. Render thread's `Tick()` drains the channel. All decode, fragment assembly, ISAAC crypto, event dispatch, and ack-sending remain on the render thread — minimal change that prevents packet drops during frame stalls. Thread starts after `EnterWorld()` completes; `PumpOnce()` during handshake still reads the socket directly.
- **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.
- **A.5 — Two-tier streaming + terrain horizon LOD.** Split `ACDREAM_STREAM_RADIUS` into two: `ACDREAM_TERRAIN_RADIUS` (large, 8-12 cells = 1.5-2.3km) for terrain mesh + `ACDREAM_ENTITY_RADIUS` (small, 2-3 cells, current default) for entities + scenery. Distant landblocks render terrain only — no NPCs, no procedural scenery, no static objects. Tune `SceneLightingUbo`'s `uFogParams` so the far edge fades into sky color (eliminates the hard streaming boundary visible at higher radii). Optional: terrain LOD via mesh decimation for very distant chunks (combine 2×2 landblocks into one decimated mesh; cribs from `references/WorldBuilder/Chorizite.OpenGLSDLBackend/Lib/TerrainRenderManager.cs`). Motivation: at radius=5 today, perf scales from ~810 fps → ~200-300 fps because everything stays full-detail; both retail and WorldBuilder render terrain way out and strip entities/scenery at distance. Enables WB-style horizon visibility. **Estimate: 3-5 days for the radius split + fog tuning; +1 week if terrain LOD is included.** Not yet brainstormed.
- **✓ SHIPPED — A.5 — Two-tier streaming + horizon LOD.** Shipped 2026-05-10. See shipped table above for full description. Plan archived at `docs/superpowers/plans/2026-05-09-phase-a5-two-tier-streaming.md`.
**Acceptance:**
- Walk across 10+ landblocks in any direction, no crashes, no empty voids.
@ -664,7 +665,7 @@ for our deletions/additions; merge upstream `master` periodically.
manifest at higher radius. Spec acceptance criterion #5 was wrong;
amended via `docs/plans/2026-05-09-phase-n5b-perf-baseline.md`. Plan
archived at `docs/superpowers/plans/2026-05-09-phase-n5b-terrain-modern.md`.
- **N.6 — Perf polish.** **Currently in flight.**
- **N.6 — Perf polish.** **Planned (post-A.5 polish takes priority).**
Builds on N.5 + N.5b. Legacy renderer retirement was pulled forward
into N.5 ship amendment — `InstancedMeshRenderer`, `StaticMeshRenderer`,
`WbFoundationFlag` are gone — and the terrain legacy renderer
@ -675,8 +676,8 @@ for our deletions/additions; merge upstream `master` periodically.
is a candidate), GPU-side culling via compute pre-pass (eliminates
the per-frame slot walk + DEIC build entirely), GL_TIME_ELAPSED query
double-buffering (deferred from N.5 — diagnostic shows `gpu_us=0/0`
under `ACDREAM_WB_DIAG=1`), direct higher-radius perf comparison once
A.5 lands (where modern's architectural wins manifest), retire the
under `ACDREAM_WB_DIAG=1`), direct higher-radius perf comparison (A.5
has now landed — modern's architectural wins are measurable), retire the
legacy `Texture2D`/`sampler2D` path in `TextureCache` (currently kept
for Sky + Debug + particle paths now that Terrain has migrated).
Plan + spec written when work begins. **Estimate: 1-2 weeks.**