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>
281 lines
13 KiB
Markdown
281 lines
13 KiB
Markdown
# 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 🟢.
|