acdream/docs/architecture/worldbuilder-inventory.md
Erik 2256006cb7 ship(O): Phase O — DatPath Unification — SHIPPED
ONE thing touches the DATs. WB code lives in our repo:
- src/AcDream.Core/Rendering/Wb/ — pure helpers (5 files, ~782 LOC)
- src/AcDream.App/Rendering/Wb/ — GL infra + mesh pipeline (~27 files, ~7K LOC)

Project references to WorldBuilder.Shared + Chorizite.OpenGLSDLBackend
dropped from AcDream.App.csproj and AcDream.Core.csproj.
references/WorldBuilder/ remains in-tree as read-reference only.

DefaultDatReaderWriter eliminated; DatCollection is the only dat reader.
WbMeshAdapter consumes our DatCollection via DatCollectionAdapter
(O-D7 fallback adapter; ObjectMeshManager has 26 _dats.X call sites,
exceeding the 20 refactor threshold).

Visual side-by-side passed: Holtburg town, inn interior, dungeon all
render identically to pre-O.

Doc updates:
- CLAUDE.md: rewrote WB integration cribs to point at extracted code.
  Code Structure Rules rule 2 updated to remove stale seam names.
  "Currently working toward" flipped from Phase O to M1.5 resumption.
- docs/architecture/worldbuilder-inventory.md: Phase O banner added.
  Status/integration model updated to post-O ownership. Workflow
  section updated to reference our extracted tree, not WB project ref.
- docs/plans/2026-04-11-roadmap.md: Phase O moved to shipped table.
  Phase O "ahead" block collapsed to SHIPPED note. M1.5 block updated
  to ACTIVE (Phase O shipped; resuming from 2026-05-20 baseline).
- docs/plans/2026-05-12-milestones.md: M1.5 heading updated to ACTIVE;
  Phase O ship writeup prepended to the M1.5 block.

Phase O ship closes Tasks O-T1..O-T7 shipped across this session.
Specs + audit + plan: docs/superpowers/{specs,plans}/2026-05-21-phase-o-*

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 17:41:15 +02:00

281 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# WorldBuilder Inventory — what we extracted, adapted, or left behind
> **Phase O shipped 2026-05-21.** The ~33 WB files we actually use have
> been extracted into our tree. `references/WorldBuilder/` stays as a
> **read-reference only** — nothing in `src/AcDream.*` references it as a
> project dependency. `DatCollection` is now the only dat reader in process.
>
> Use this document to:
> 1. Know **where our extracted code lives** (look for the "Extracted to"
> column / notes in each section below).
> 2. Know **what WB still has** that we haven't needed yet — grep
> `references/WorldBuilder/` if you ever need to add something.
> 3. Know **what WB never had** (the 🔴 list) — those are always ours.
**Pre-O status (archived for context):** As of Phase N.4 (2026-05-08)
acdream relied heavily on WorldBuilder as a project reference for rendering
and dat-handling. WorldBuilder is MIT-licensed, verified by visual inspection
to render the AC world correctly (terrain, scenery, slabs, dungeons, slopes,
particles), and uses the same Silk.NET + .NET stack we target.
**Post-O integration model:** Extracted WB code lives in two locations in
our tree (see CLAUDE.md for the full breakdown):
- `src/AcDream.Core/Rendering/Wb/` — pure helpers (no GL): `TerrainUtils`,
`TerrainEntry`, `RegionInfo`, `SceneryHelpers`, `TextureHelpers`.
- `src/AcDream.App/Rendering/Wb/` — GL infrastructure + mesh pipeline:
`ObjectMeshManager`, `WbMeshAdapter`, `WbDrawDispatcher`, texture cache,
shader infra, EnvCell/portal/scenery/terrain-blending pipeline classes.
`DatCollectionAdapter` bridges our `IDatCollection` to the `IDatReaderWriter`
interface WB's internals expect (O-D7 fallback; `ObjectMeshManager` has 26
internal `_dats.*` call sites — above the 20-site inline-swap threshold).
**Workflow:** Before re-implementing any AC-specific rendering or dat-handling
algorithm, **check this inventory first**. If we already extracted it (🟢
sections), it's in `src/AcDream.App/Rendering/Wb/` — use our copy. If WB has
it but we haven't extracted it yet, grep `references/WorldBuilder/` and extract
as needed. Retail decomp remains the oracle for things WB never had (🔴 list).
Attribution: WorldBuilder is MIT-licensed. `NOTICE.md` includes WB attribution.
---
## Read-reference layout (under `references/WorldBuilder/`, not project-referenced)
- **`Chorizite.OpenGLSDLBackend/`** — full OpenGL renderer (Silk.NET). The
components we use are extracted into `src/AcDream.App/Rendering/Wb/`.
- **`WorldBuilder.Shared/`** — data models, dat parsers, landscape module.
The helpers we use are extracted into `src/AcDream.Core/Rendering/Wb/`.
- **`WorldBuilder/`** — Avalonia desktop app shell (not taken).
- **`WorldBuilder.{Windows,Linux,Mac}/`** — platform entry points (not taken).
- **`WorldBuilder.Server/`** — collab editing backend (not taken).
- **`Tests/` + `WorldBuilder.Shared.Benchmarks/`** — test harness (study only).
**Upstream NuGet dependencies** (these stay as NuGet packages, we don't
vendor them):
| Package | Version | Purpose |
|---|---|---|
| `Chorizite.Core` | 0.0.18 | Plugin framework — contains `Chorizite.Core.Lib.BoundingBox`, `Chorizite.Core.Render.*` interfaces used by every render manager |
| `Chorizite.DatReaderWriter` | 2.1.x | dat parsing (we already use 2.1.7) |
| `Chorizite.DatReaderWriter.Extensions` | 1.1.x | extra dat helpers |
| `BCnEncoder.Net` | 2.2.x | DXT decode (we already use) |
| `SixLabors.ImageSharp` | 3.1.x | image loading |
| `Silk.NET.OpenGL` + `Silk.NET.SDL` | 2.23.x | GL + windowing (we use Silk's own windowing, they use SDL) |
| `MP3Sharp` | 1.0.5 | MP3 decode |
---
## 🟢 RENDERING — take wholesale or adapt
These are what makes WB "perfect". Anything in this section, we should
use from WB rather than re-implement.
### Terrain
| Component | What it does |
|---|---|
| `TerrainRenderManager` | Full pipeline (per-chunk GPU buffers, draw orchestration) |
| `LandSurfaceManager` | Texture blending atlas (palCode, alpha masks, road overlays) |
| `TerrainGeometryGenerator` | Heightmap → mesh, normals, OnRoad, GetHeight, GetNormal |
| `TerrainChunk` | 16×16 landblock chunk geometry |
| `TextureAtlasManager` | Texture atlas builder |
| `VertexLandscape` | Terrain vertex format |
### Scenery (procedural placement: trees, bushes, rocks, fences)
| Component | What it does |
|---|---|
| `SceneryRenderManager` | Generate + render per-vertex scenery |
| `SceneryHelpers` | Displace / RotateObj / ScaleObj / ObjAlign / CheckSlope |
| `SceneryInstance` | Per-spawn instance data |
### Static objects (buildings, slabs, props — Setup + GfxObj + ObjDesc)
| Component | What it does |
|---|---|
| `StaticObjectRenderManager` | Master pipeline for static objects |
| `ObjectRenderManagerBase` + `BaseObjectRenderManager` | Common render base |
| `ObjectMeshManager` | Mesh extraction from Setup/GfxObj, ObjDesc application |
### Dungeons / interiors
| Component | What it does |
|---|---|
| `EnvCellRenderManager` | Dungeon interior cell geometry |
| `PortalRenderManager` | Portal traversal / visibility |
### Sky + atmosphere
| Component | What it does |
|---|---|
| `SkyboxRenderManager` | Skybox rendering |
| `ParticleEmitterRenderer` + `ParticleBatcher` + `ActiveParticleEmitter` | Particle systems (sky particles, weather, magic) |
### Visibility / culling
| Component | What it does |
|---|---|
| `VisibilityManager` + `VisibilitySnapshot` | Frustum + cell visibility |
| `Frustum` | Frustum-cull math |
### Other rendering helpers
| Component | What it does |
|---|---|
| `MinimapRenderer` | Top-down minimap |
| `GlobalMeshBuffer` | Shared GPU mesh buffer |
| `GpuResourceManager` | GPU resource lifecycle |
| `InstanceData` | Instanced draw data |
| `TextureHelpers` | INDEX16, P8, BGRA, DXT decode + alpha (canonical port) |
| `DebugRenderer` + `DebugRendererLineDrawer` + `EdgeLineBuilder` | Debug primitives |
### Shaders (22 total)
Located at `Chorizite.OpenGLSDLBackend/Shaders/`:
`Landscape.{vert,frag}` · `StaticObject.{vert,frag}` · `StaticObjectModern.{vert,frag}` · `Particle.{vert,frag}` · `PortalStencil.{vert,frag}` · `Outline.{vert,frag}` · `Simple3D.{vert,frag}` · `InstancedLine.{vert,frag}` · `Text.{vert,frag}` · `UI.{vert,frag}` · `Gizmo.{vert,frag}` (editor-only)
---
## 🟢 LOW-LEVEL GL / FRAMEWORK — take or replace with our own
Either take WB's wrappers wholesale, or keep our own and adapt the
render managers to use ours. These wrappers are stateless or
near-stateless and are the easiest to swap.
| Component | What it does |
|---|---|
| `OpenGLGraphicsDevice` | Silk.NET.OpenGL wrapper |
| `OpenGLRenderer` | Render orchestration |
| `GLSLShader` | Shader compile/link/uniforms |
| `GLHelpers` + `GLStateScope` | GL state utility |
| `ManagedGLFrameBuffer` / `ManagedGLIndexBuffer` / `ManagedGLTexture` / `ManagedGLTextureArray` / `ManagedGLUniformBuffer` / `ManagedGLVertexArray` / `ManagedGLVertexBuffer` | GL resource wrappers |
| `TextureParameters` | Sampler config |
| `GpuMemoryTracker` | Memory tracking |
| `Camera2D` / `Camera3D` / `CameraBase` / `ICamera` / `CameraController` | Camera primitives |
| `GameScene` + `SingleObjectScene` + `SceneData` + `ModernRenderData` + `RenderPass` | Scene / pass structures |
---
## 🟢 GEOMETRY / MATH UTILS — take wholesale
| Component | File |
|---|---|
| `TerrainUtils` (OnRoad, GetNormal, GetHeight, GetRoad, palCode) | `WorldBuilder.Shared/Modules/Landscape/Lib/TerrainUtils.cs` |
| `TerrainCacheManager` | `…/Lib/TerrainCacheManager.cs` |
| `TerrainRaycast` | `…/Lib/TerrainRaycast.cs` |
| `GeometryUtils` | `WorldBuilder.Shared/Lib/GeometryUtils.cs` |
| `RaycastingUtils` (ray-vs-sphere/AABB/triangle) | `WorldBuilder.Shared/Lib/RaycastingUtils.cs` |
| `DoubleNumerics` (double-precision Vector/Matrix) | `WorldBuilder.Shared/Lib/DoubleNumerics.cs` |
| `DatUtils` | `WorldBuilder.Shared/Lib/DatUtils.cs` |
| `BoundingBoxExtensions` | `Chorizite.OpenGLSDLBackend/Lib/BoundingBoxExtensions.cs` |
---
## 🟢 DATA MODELS — take selectively
| Component | What it does |
|---|---|
| `RegionInfo` | Landblock metadata wrapper (LandblockSizeInUnits, CellSizeInUnits, etc.) |
| `TerrainEntry` | Per-vertex terrain (Type/Scenery/Road/Height) |
| `MergedLandblock` | Merged dat data |
| `CellSplitDirection` | SW-NE vs NE-SW |
| `Cell` | Generic cell wrapper |
| `ObjectId` | Object identifier |
| `Position` | World position |
| `ACEnums` | AC-specific enums |
| `WbBuildingPortal` / `WbCellPortal` | Portal structures |
| `BuildingObject` | Building data |
---
## 🟡 EDITOR-ONLY — leave behind / delete in fork
These exist for the editor experience and have no place in a game
client. Delete in fork.
- **`Modules/Landscape/Tools/*`** — `BrushTool`, `BucketFillTool`,
`RoadLineTool`, `RoadVertexTool`, `InspectorTool`,
`ObjectManipulationTool`, `Gizmo*` (DragHandler, HitTester, Renderer,
State), `TexturePainting*`, `SceneRaycaster`,
`LandscapeBrush`, `LandscapeToolBase`, `LandscapeToolContext`,
`IToolSettingsProvider`, `ILandscapeBrush`, `ILandscapeEditorService`,
`ILandscapeRaycastService`, `ILandscapeTool`, `ITexturePaintingTool`
- **`Modules/Landscape/Commands/*`** — undo/redo command pattern for
editor (Add/Delete/Move/Rename/Reorder/etc.)
- **`LandscapeDocument` + `LandscapeLayer` + `LandscapeLayerGroup` + `LandscapeChunk` + `LandscapeLayerChunk` + `LandscapeLayerBase`** — editor document model
- **`Modules/Landscape/Models/TerrainPatch*` + `LandblockChangedEventArgs`** — editor mutation events
- **`Modules/Landscape/Services/ILandscapeCacheService` + `ILandscapeDataProvider` + `ILandscapeObjectService` + impls** — editor data flow
- **All `Migrations/*`** — SQLite schema migrations (project file format)
- **`Repositories/*`** + **`Services/*`** — project storage, dat repository, AceDb, SignalR sync, document manager, undo stack, world coordinates, keyword DB, project migration, semantic kernel AI helpers
- **`Hubs/*`** — collaborative editing via SignalR
- **`StaticObject` (editor model)** — replace with our own scene-state data model fed from network
- **`BackendGizmoDrawer` + `GizmoRenderer`** — editor gizmos
- **`ProjectStructures, IProject, Project`** — editor project files
- **`KeyBinding`** — editor input binding
- **`ViewportInputEvent[Extensions]`** — editor viewport input
- **`EditorState`** — editor state container
---
## 🟡 AUDIO / FONT — we already have alternatives
Keep ours; don't take theirs.
- **`AudioPlaybackEngine`** — uses MP3Sharp. We have OpenAL.
- **`FontRenderer`** — uses ImageSharp. We have BitmapFont/StbTrueTypeSharp + ImGui.
---
## 🔴 NOT IN WORLDBUILDER — port from retail decomp ourselves
WorldBuilder is a dat editor; it does not have:
- **Network protocol** — UDP framing, ISAAC, packet codec, ACE message
layer (we have this; oracle is `references/holtburger`)
- **Physics** — collision (CPhysicsObj transitions, BSP queries, sphere
sweeps), step-up, walkable validation (we have partial; oracle is the
retail decomp at `docs/research/named-retail/`)
- **Animation** — motion sequencer, cycle/non-cycle parts, animation
frame interpolation (we have this; oracle is retail decomp)
- **Movement** — local player WASD → MoveToState wire, remote-entity
motion via UpdateMotion + dead-reckoning (we have this; oracle is
`references/holtburger` + retail decomp)
- **Game UI** — chat, vitals, inventory, spell book, allegiance, options
(we have this; ImGui-based today, custom-toolkit later)
- **Plugin API** — `IGameState`, `IEvents`, `IActions`, `IPacketPipeline`,
`IOverlay` (we have this — acdream-unique)
- **Game events** — combat, allegiance, spell casting, quest events
(we have this; oracle is ACE for opcodes + retail for client behavior)
- **Audio** — OpenAL pipeline, sound triggers (we have this)
- **TurbineChat** + **slash commands** (we have this)
- **Login + character selection flow** (we have this)
---
## What this means for the workflow (post-Phase O)
The CLAUDE.md "grep named → decompile → verify → port" workflow stays
the rule for everything in the 🔴 list (network, physics, animation,
movement, UI, plugin, audio, chat).
For anything in 🟢 that we've already extracted: **the code is in our
tree at `src/AcDream.{Core,App}/Rendering/Wb/`**. Read it there — don't
grep `references/WorldBuilder/` unless you want to compare against the
original. Re-porting from retail decomp when we already have a tested
port is still how we'd get the scenery edge-vertex bug back.
For anything in 🟢 that we have NOT yet extracted: grep
`references/WorldBuilder/` to find the source, then extract it using the
Phase O pattern (verbatim copy → adapt constructor to accept
`IDatCollection` via `DatCollectionAdapter` where needed → add to
`src/AcDream.App/Rendering/Wb/`). Do NOT add a new project reference back
to `WorldBuilder.Shared` or `Chorizite.OpenGLSDLBackend` — Phase O
permanently removed those.
When we discover a behavior mismatch with retail (rare — the extracted
code is the same as the original), the resolution is: reconcile extracted
code ↔ retail decomp ↔ holtburger ↔ ACE ↔ ACViewer (the existing
reference hierarchy in CLAUDE.md). Our extracted code ranks at the top
of that hierarchy for anything 🟢.