From 6010827b21be4f55711e4389ad2e471d6be1097b Mon Sep 17 00:00:00 2001 From: Erik Date: Fri, 8 May 2026 10:49:16 +0200 Subject: [PATCH] docs: roadmap N.0 shipped + realistic N.2-N.9 estimates + N.3 handoff MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Roadmap updates after Phase N.1 ship: - Marks N.0 (submodule + project refs setup) as ✓ SHIPPED with the c8782c9 commit reference - Updates N.2-N.9 effort estimates with realistic post-N.1 numbers (originals were 1-2 days / 1 week / 2 weeks; realistic numbers factor in conformance-test discovery, ACME-vs-Chorizite delta hunts, and the visual-verification-then-revert cycle that ate most of N.1's calendar time) - Adds a "Lessons from N.1" subsection so future N phases benefit from the rotation-bug-conformance-test pattern, the ACME divergence insight, and the "whackamole = stop" rule - Updates total calendar estimate to 3-4 months / 10-12 engineering weeks for N.2-N.9 (was 2-3 months / 6-8 weeks) New handoff doc at docs/research/2026-05-08-phase-n3-handoff.md captures everything a fresh agent picking up N.3 (texture decoding) needs: phase context, what to read first, suggested task decomposition, watchouts (especially the ACME-divergence and conformance-test lessons), and where to start. Co-Authored-By: Claude Opus 4.7 (1M context) --- docs/plans/2026-04-11-roadmap.md | 71 ++++++++-- docs/research/2026-05-08-phase-n3-handoff.md | 132 +++++++++++++++++++ 2 files changed, 192 insertions(+), 11 deletions(-) create mode 100644 docs/research/2026-05-08-phase-n3-handoff.md diff --git a/docs/plans/2026-04-11-roadmap.md b/docs/plans/2026-04-11-roadmap.md index 6ccac3e..ee78dc5 100644 --- a/docs/plans/2026-04-11-roadmap.md +++ b/docs/plans/2026-04-11-roadmap.md @@ -530,9 +530,39 @@ submodule replacing `references/WorldBuilder/` snapshot, project references in our solution. Long-lived `acdream` branch in the fork for our deletions/additions; merge upstream `master` periodically. +**Lessons from N.1 (apply to N.2-N.10):** + +1. **Per-helper conformance tests work.** The N.1 conformance test caught a + ~180° rotation bug in our retail port that had been silently wrong + forever. Write the conformance test BEFORE the substitution in each + sub-phase. + +2. **ACME ≠ Chorizite/WorldBuilder.** ACME is a downstream fork of WB with + additional retail-faithful filters that upstream WB (our submodule) + doesn't have. When a visual discrepancy appears, check ACME's source + (`references/WorldBuilder-ACME-Edition/`) for delta filters BEFORE + investigating retail decomp directly. ACME's deltas tend to come as + coherent units — porting one filter without its companions can + over-suppress. + +3. **"Whackamole" is the warning sign.** If a phase generates 3+ visual + regressions on default-on, stop, accept the cosmetic deltas as + ISSUES.md entries, ship the migration. Bugs we leave behind are + debuggable; bugs we never ship are forgotten. + +4. **Subagent-driven execution holds up at this scope.** Fresh subagent + per task with the full task text inline keeps quality high without + polluting the controller's context. Each task should be self-contained + enough that a subagent without session history can complete it. + **Sub-phases (strangler-fig with feature flags):** -- **N.0 — Setup.** Submodule + project references + build green. ~1-2 hrs. +- **✓ SHIPPED — N.0 — Setup.** Shipped 2026-05-08 (commit `c8782c9`). + WorldBuilder fork at `github.com/eriknihlen/WorldBuilder.git` registered + as git submodule at `references/WorldBuilder/` tracking the `acdream` + branch. `AcDream.Core.csproj` references `WorldBuilder.Shared` + + `Chorizite.OpenGLSDLBackend`. Build green, all 28 scenery/terrain tests + passing. - **✓ SHIPPED — N.1 — Scenery algorithm calls.** Shipped 2026-05-08. Replaced `IsOnRoad` / `DisplaceObject` / slope-normal calc / rotation / scale inside `SceneryGenerator.Generate()` with calls to WB's @@ -545,31 +575,50 @@ for our deletions/additions; merge upstream `master` periodically. (road-edge tree at landblock 0xA9B1). - **N.2 — Terrain math helpers.** Refactor `TerrainSurface.SampleZ` / `SampleNormal` / `SampleSurface` to call WB's `TerrainUtils.GetHeight` - / `GetNormal` internally. ~1-2 days. -- **N.3 — Texture decoding.** Replace `TextureCache` decode pipeline - with WB's `TextureHelpers`. ~2-3 days. + / `GetNormal` internally. ~1-2 days. Smallest remaining N phase, low + risk after N.1's conformance proof on GetNormal. +- **N.3 — Texture decoding.** Replace our `TextureCache` decode + pipeline (`src/AcDream.App/Rendering/TextureCache.cs`) with WB's + `TextureHelpers` (INDEX16, P8, BGRA, DXT, alpha). Touches every + texture path. **Realistic estimate: 3-5 days** (was 2-3) — the GL + upload path needs adapting and we'll need conformance tests per + texture format. Handoff doc: + `docs/research/2026-05-08-phase-n3-handoff.md`. - **N.4 — Object meshing.** Replace `SetupMesh.cs` + `GfxObjMesh.cs` with calls to WB's `ObjectMeshManager`. Character-appearance behaviors (CreaturePalette / GfxObjRemapping / HiddenParts) remain - ours — ACME is the secondary oracle. ~1 week. + ours — ACME is the secondary oracle. **Realistic estimate: 1.5-2 + weeks** (was 1) — character appearance edge cases like N.1's + rotation bug will surface. - **N.5 — Terrain rendering.** Replace `TerrainChunkRenderer` + `TerrainAtlas` + `TerrainBlending` with WB's `TerrainRenderManager` + - `LandSurfaceManager` + `TerrainGeometryGenerator`. ~2 weeks. + `LandSurfaceManager` + `TerrainGeometryGenerator`. **Realistic + estimate: 3-4 weeks** (was 2) — largest single phase, GPU-buffer + ownership shifts, integration with our streaming loader is + non-trivial. - **N.6 — Static objects rendering.** Replace `StaticMeshRenderer` + `InstancedMeshRenderer` with WB's `StaticObjectRenderManager`. - ~2 weeks. + **Realistic estimate: 2-3 weeks** (was 2) — interacts with N.4 + output. - **N.7 — EnvCells / dungeons.** Replace EnvCell rendering with WB's - `EnvCellRenderManager` + `PortalRenderManager`. ~2 weeks. + `EnvCellRenderManager` + `PortalRenderManager`. **Realistic + estimate: 2-3 weeks** (was 2). - **N.8 — Sky + particles.** Replace sky rendering + particle pipeline (#36 / C.1 work) with WB's `SkyboxRenderManager` + - `ParticleEmitterRenderer`. ~1 week. + `ParticleEmitterRenderer`. **Realistic estimate: 1.5-2 weeks** + (was 1) — visual continuity matters; we just shipped C.1 and that + work flows through here. - **N.9 — Visibility / culling.** Replace `CellVisibility` + - `FrustumCuller` with WB's `VisibilityManager`. ~3-5 days. + `FrustumCuller` with WB's `VisibilityManager`. **Realistic + estimate: 1 week** (was 3-5 days) — affects perf and what gets + drawn. - **N.10 — GL infrastructure consolidation (optional).** Replace our `Shader` / `TextureCache` / `SamplerCache` plumbing with WB's `ManagedGL*` wrappers + `OpenGLGraphicsDevice`. ~1 week. -**Estimated calendar:** 2-3 months. Engineering effort: 6-8 weeks. +**Estimated calendar:** **3-4 months / 10-12 engineering weeks for +N.2-N.9 (skipping N.10).** (Was 2-3 months / 6-8 weeks — revised +upward after N.1 landed; realistic per-phase numbers above.) **Each sub-phase:** - Ships behind `ACDREAM_USE_WB_=1` flag. diff --git a/docs/research/2026-05-08-phase-n3-handoff.md b/docs/research/2026-05-08-phase-n3-handoff.md new file mode 100644 index 0000000..7b7e7fa --- /dev/null +++ b/docs/research/2026-05-08-phase-n3-handoff.md @@ -0,0 +1,132 @@ +# Phase N.3 handoff — texture decoding via WorldBuilder + +**Use this whole document as the prompt** when handing off to a fresh +agent. Everything they need to pick up cold is below. + +--- + +## Background you'll need + +You're working in `acdream`, a from-scratch C# .NET 10 reimplementation +of Asheron's Call's retail client. The project's house rule (in +`CLAUDE.md`) is **the code is modern, the behavior is retail**. + +acdream just shipped **Phase N.1** (commits `26cf2b8` through `ad8b931`), +the first sub-phase of a strategic migration to fork WorldBuilder +(`github.com/Chorizite/WorldBuilder`, MIT) and depend on its tested +rendering + dat-handling code instead of porting algorithms from retail +decomp ourselves. + +**Read first:** +- `docs/architecture/worldbuilder-inventory.md` — the full taxonomy of + what WB has and what we keep porting ourselves +- `docs/superpowers/specs/2026-05-08-phase-n-worldbuilder-migration-design.md` + — the parent design doc for Phase N +- `CLAUDE.md` — especially the "Reference repos" section (now points at + WB as the rendering BASE) and the workflow rules + +**Phase N.1 commit history (just shipped):** read +`git log --oneline c8782c9..ad8b931` to see how N.0 + N.1 were +structured. The pattern repeats for N.3. + +## What N.3 is + +Replace acdream's texture decoding pipeline with WorldBuilder's +`Chorizite.OpenGLSDLBackend.Lib.TextureHelpers`. WB handles INDEX16, +P8, BGRA, DXT, and alpha-channel decoding. Our existing implementations +of these are scattered across `src/AcDream.App/Rendering/TextureCache.cs` +and possibly `src/AcDream.Core/Meshing/` — find them with +`grep -rln "INDEX16\|P8 decode\|DXT\|BGRA" src/`. + +## Acceptance criteria + +- Build green (`dotnet build`) +- All existing tests green (the 8 pre-existing `DispatcherToMovementIntegrationTests` + failures don't count — they exist on main) +- New conformance tests added per format that's substituted (one xUnit + Theory per: INDEX16, P8, BGRA, DXT). Each compares a fixed input byte + array decoded by our path vs WB's path; assertions on output pixel array. +- Visual verification at Holtburg (or wherever) shows no texture + regressions: terrain texturing, mesh texturing, particle textures all + look the same. +- ISSUES.md updated with any known cosmetic deltas (the N.1 pattern — + if WB and retail disagree on something subtle, file it, don't try + to fix it inline). + +## Tasks (suggested decomposition) + +Follow the N.1 plan structure (`docs/superpowers/plans/2026-05-08-phase-n1-scenery-via-wb-helpers.md`) +as the template. Concretely: + +1. **Audit our texture decode paths.** Grep, list every file/method that + decodes a texture. Map each to the WB equivalent in + `references/WorldBuilder/Chorizite.OpenGLSDLBackend/Lib/TextureHelpers.cs` + (read it end to end first). +2. **Per-format conformance test.** TDD style: write the test, run it + to fail, then plumb the substitution. Conformance test fixture inputs + should include real-dat byte sequences (read a known-good texture from + a dat, encode the bytes as a hex blob in the test). +3. **Substitution.** Replace each decode site with the WB call. Keep our + GL upload pathways — those are NOT WB's responsibility. +4. **Visual verification.** Launch the client at Holtburg, walk around, + look at a tree (mesh texture), the ground (atlas texture), particles + (the recent C.1 rain/clouds/aurora work), and a building (composite + texture). Compare against retail or against a screenshot before the + change. +5. **Delete legacy decoders** once visual verification passes. +6. **Update roadmap + ISSUES** as the final commit. + +## Watchouts (lessons from N.1) + +- **ACME has a downstream fork with extra filters** (`references/WorldBuilder-ACME-Edition/`). + WB's `TextureHelpers` may have ACME-specific patches not yet in upstream. + Compare both before assuming WB's version is canonical. We forked + upstream WB; ACME is reference-only. +- **Conformance tests are non-negotiable.** Phase N.1's rotation bug was + caught by the conformance test. Don't skip them. If a test fails, it's + a real divergence — investigate before "fixing" the test. +- **Whackamole stops the migration.** If 3+ visual regressions appear on + default-on, stop, file as ISSUES, ship. The migration goal is "use WB's + tested code"; pixel-perfect equivalence with our broken hand-ports is + not the goal. +- **`Setup.SortingSphere` ≠ `Setup.CylSphere`.** The N.1 attempt at + `obj_within_block` over-suppressed because we used the wrong radius + source (sorting sphere too large). For texture decoding this likely + doesn't matter, but the general lesson is: read WB's full source + carefully before adapting; don't assume parallel methods do parallel + things. +- **Per-vertex road check — STOP signal.** If you find yourself reading + ACME for "what's missing" and considering a per-vertex filter, STOP. + N.1 tried this (commit `e279c46`), regressed visually, reverted in + `677a726`. ACME's filter set works as a coherent unit; pick-and-choose + fails. If the N.3 work uncovers a similar ACME-only filter, file it + in ISSUES and move on, don't port it inline. + +## Where to start + +1. `git pull` on main to get the latest (Phase N.1 just merged). +2. Create a new worktree for the work: + `git worktree add .claude/worktrees/ -b claude/`. +3. Read the three "read first" docs above. +4. Run `dotnet build && dotnet test` to confirm clean baseline. +5. Read `references/WorldBuilder/Chorizite.OpenGLSDLBackend/Lib/TextureHelpers.cs` + end to end. Take notes on the public API surface. +6. Run the audit task (#1 in Tasks above). Output should be a markdown + table of "our function / file:line / WB equivalent / format covered." +7. Use `superpowers:writing-plans` to convert the audit into a concrete + per-format plan. Then use `superpowers:subagent-driven-development` + to execute it with fresh subagents per format. + +## Useful greps + +- `grep -rln "INDEX16\|IndexedSurface\|P8\|DXT\|BGRA\|TextureFormat" src/` — find decode paths +- `grep -rln "TextureCache" src/` — find our cache layer +- `grep -n "public static.*Decode\|public static.*Convert" references/WorldBuilder/Chorizite.OpenGLSDLBackend/Lib/TextureHelpers.cs` — WB's public API + +## Open question to resolve early + +Does `Chorizite.OpenGLSDLBackend.Lib.TextureHelpers` cover ALL the +formats we use, or does it have gaps? Audit our texture types against +WB's API in step 1. If WB is missing a format we need, the migration for +that format gets deferred (file in ISSUES; keep our decoder for it; note +in the roadmap).