# Phase N — WorldBuilder Rendering Migration: Design **Date:** 2026-05-08 **Status:** Design complete, awaiting plan generation for N.1. ## Goal Stop re-porting AC-specific rendering and dat-handling algorithms from retail decomp. Instead, depend on a fork of WorldBuilder (`github.com/Chorizite/WorldBuilder`, MIT) for terrain, scenery, static objects, EnvCells, portals, sky, particles, texture decoding, mesh extraction, and visibility / culling. Acdream keeps its own network, physics, animation, motion, UI, plugin, audio, and chat layers — those are not in WorldBuilder. ## Why acdream has accumulated a recurring pattern of subtle porting bugs in its own rendering algorithms (the latest: a tree near the road at landblock `0xA9B1` that retail and WorldBuilder do not show but our re-port did, despite the algorithm code looking byte-identical to WorldBuilder's). The triangle-Z bug, the hover-over-terrain bug, and the edge-vertex spawn bug are all in the same family: small porting errors that survive surface-level review. WorldBuilder is verified by visual inspection to render the AC world correctly. It uses the same Silk.NET + .NET stack we already target. It is MIT-licensed. It has fewer subtle bugs because its developers have run it against the entire client_cell + client_portal dat content and fixed everything users have reported. The cost of "we re-port retail algorithms ourselves" is now higher than the cost of "we depend on someone else's tested port and inherit their fixes." Migrating the rendering+dat layer to WorldBuilder is the right call. ## Inventory reference The full taxonomy of "what WorldBuilder has, what we keep porting ourselves" lives at [`docs/architecture/worldbuilder-inventory.md`](../../architecture/worldbuilder-inventory.md). Before re-implementing any rendering or dat-handling algorithm, **check the inventory first**. CLAUDE.md is updated to enforce this. ## Architecture ### Integration model **Fork upstream WorldBuilder, depend on the fork via git submodule.** - Fork: `https://github.com/eriknihlen/WorldBuilder` (already created; upstream: `Chorizite/WorldBuilder`). - Long-lived branch in fork: `acdream`. Upstream `master` merges into `acdream` periodically; our acdream-specific changes (delete editor files, expose hooks for our scene state) live on `acdream`. - The current read-only snapshot at `references/WorldBuilder/` is **replaced** by a git submodule pointing at the fork's `acdream` branch. Existing CLAUDE.md path references and research docs that cite `references/WorldBuilder/...` keep working. - Our solution adds two ``s: - `references/WorldBuilder/Chorizite.OpenGLSDLBackend/Chorizite.OpenGLSDLBackend.csproj` - `references/WorldBuilder/WorldBuilder.Shared/WorldBuilder.Shared.csproj` - Transitive NuGet dependencies (`Chorizite.Core`, `Chorizite.DatReaderWriter.Extensions`, `BCnEncoder.Net`, `SixLabors.ImageSharp`, `Silk.NET.SDL`, `MP3Sharp`) flow through. - Editor-only files in WorldBuilder (Modules/Landscape/{Tools, Commands, Services, Migrations, Hubs}, LandscapeDocument, etc.) stay in the fork's source tree but are simply not referenced by acdream. They impose no runtime cost. We can prune later if upstream stays well-organized. ### Phasing — strangler fig, subsystem by subsystem Each sub-phase is independently shippable behind a feature flag (`ACDREAM_USE_WB_=1`). After visual verification the flag becomes default-on, then is removed and the old code is deleted. This gives us a one-line revert if a phase regresses. | # | Sub-phase | Effort | Risk | |---|---|---|---| | **N.0** | Submodule + project references + build green | 1-2 hrs | Low | | **N.1** | Scenery algorithm calls | 1-2 days | Low | | **N.2** | Terrain math helpers | 1-2 days | Low | | **N.3** | Texture decoding | 2-3 days | Medium | | **N.4** | Object meshing (Setup/GfxObj) | 1 week | Medium | | **N.5** | Terrain rendering (full pipeline) | 2 weeks | High | | **N.6** | Static objects rendering | 2 weeks | High | | **N.7** | EnvCells / dungeons | 2 weeks | High | | **N.8** | Sky + particles | 1 week | Medium | | **N.9** | Visibility / culling | 3-5 days | Medium | | **N.10** | GL infrastructure consolidation (optional) | 1 week | Medium | Total estimated calendar: 2-3 months. Engineering effort: 6-8 weeks. ### What WorldBuilder does NOT cover (keep porting from retail decomp) - Network protocol (UDP, ISAAC, ACE messages) — keep ours - Physics: collision, BSP queries, sphere sweeps, walkable validation — keep ours (partial), continue porting from retail decomp - Animation: motion sequencer, cycle/non-cycle parts — keep ours - Movement: WASD → MoveToState wire, remote-entity motion via UpdateMotion + dead-reckoning — keep ours - Game UI: chat, vitals, inventory, spell book — keep ours (ImGui today, custom-toolkit later) - Plugin API: IGameState, IEvents, IActions, IPacketPipeline, IOverlay — keep ours (acdream-unique) - Game events: combat, allegiance, spell casting — keep ours - Audio (OpenAL pipeline) — keep ours - TurbineChat + slash commands — keep ours - Login + character selection flow — keep ours Per CLAUDE.md update, these still follow the "grep named → decompile → verify → port" workflow against retail decomp at `docs/research/named-retail/`. ### Network reference posture `references/Chorizite.ACProtocol/` (separate Chorizite repo) remains the Primary Oracle for protocol field order and packed-dword conventions per CLAUDE.md's reference table. No fork needed there. We will lean on it harder during future network-conformance phases (Phase M is already on the roadmap for that). ## Components ### N.0 — Setup (must land before N.1) **Files / actions:** - Remove `references/WorldBuilder/` from working tree (it's currently a checked-in snapshot). Add it back as a submodule pointing at `git@github.com:eriknihlen/WorldBuilder.git` tracking the `acdream` branch (created off `master`). - Add `` entries in `src/AcDream.Core/AcDream.Core.csproj` and `src/AcDream.App/AcDream.App.csproj` for the two WB projects. - Update `.gitmodules` to reflect the new submodule. - Verify `dotnet build` and `dotnet test` are green. - Commit. **Done criteria:** - `git submodule status` shows `references/WorldBuilder` at the fork's `acdream` HEAD. - Solution builds clean with no new warnings. - Existing 870+ tests still pass. ### N.1 — Scenery algorithm calls See companion design doc: [`2026-05-08-phase-n1-scenery-via-wb-helpers-design.md`](2026-05-08-phase-n1-scenery-via-wb-helpers-design.md). Brief: replace the algorithm guts inside `SceneryGenerator.Generate()` with calls to WB's `SceneryHelpers` (Displace, RotateObj, ScaleObj, ObjAlign, CheckSlope) and `TerrainUtils` (OnRoad, GetNormal). Keep our data flow, our `ScenerySpawn` shape, our renderer integration. Add a small adapter `LandBlock → TerrainEntry[]`. ### N.2-N.10 — separately brainstormed when we get there Each sub-phase will get its own brainstorm + spec when we reach it. Estimating ahead is unreliable for the bigger phases (N.5, N.6, N.7); we'll know more after N.1 ships and we have hands-on experience with the WB integration. ## Risks 1. **Chorizite.Core dependency footprint.** Each render manager we take pulls in `Chorizite.Core.Lib` and `Chorizite.Core.Render`. Mitigation: take the NuGet dep, don't try to strip it. Risk is mostly cosmetic (an extra package). 2. **WB's data-flow is editor-shaped.** `LandscapeDocument`, `LandscapeChunk`, etc. are editor concepts. Mitigation: write small adapters that produce the editor-shaped data from our dat reads. Phase N.1 is intentionally chosen to avoid this — we use only the stateless helpers, not the full `SceneryRenderManager`. Larger phases (N.5+) will need real adapter layers. 3. **Upstream divergence.** WB's `master` will keep moving. Mitigation: merge upstream `master` into our `acdream` branch periodically (at minimum, before each new phase starts). Our acdream-specific changes are isolated to deletions and additions on the `acdream` branch, which merges cleanly with upstream most of the time. 4. **Behaviors WB doesn't have.** WB is a dat editor; some in-game-only behaviors (creature appearance via CreaturePalette / GfxObjRemapping / HiddenParts) aren't in WB and we'll still need to handle them ourselves at the integration boundary. Mitigation: ACME's `StaticObjectManager.cs` covers these and is documented in CLAUDE.md as the secondary oracle for character appearance. 5. **Visual regression during migration.** Mitigation: feature flag per phase. Visual verification at known-good locations (Holtburg, Foundry statue, dungeon entrances) before flag becomes default-on. ## Testing - **N.0:** existing 870+ tests stay green; `dotnet build` clean. - **N.1:** new conformance test that runs both our `SceneryGenerator` and a parallel call into WB's helpers against the same fixture data, asserts identical spawn list. Visual verification at landblock `0xA9B1` — the offending tree should be gone, Issue #49's missing scenery should still be visible. - **N.2-N.10:** each phase will define its own conformance and visual verification criteria when brainstormed. ## Documentation impact - [x] `docs/architecture/worldbuilder-inventory.md` — created. - [x] `CLAUDE.md` — updated with new posture (top-level rule + reference table + per-domain oracle hierarchy). - [ ] `docs/plans/2026-04-11-roadmap.md` — add Phase N entry alongside L, M, etc. (this happens in the same commit as the spec). - [ ] `docs/architecture/acdream-architecture.md` — needs an acknowledging note that the rendering layer is now WB-backed; can follow in a later commit, not blocking. ## Out of scope for this design - Phase N.2-N.10 detailed scope (each gets own brainstorm). - Network conformance work (separate Phase M). - Animation, physics, motion ports (continue against retail decomp, not WB). - UI, plugin, chat work (separate phases, not affected).