Saves the comprehensive inventory of what WorldBuilder provides
(terrain, scenery, static objects, EnvCells, portals, sky, particles,
texture decode, mesh extraction, visibility) vs what acdream still
ports from retail decomp (network, physics, animation, movement, UI,
plugin, audio, chat).
This is the load-bearing reference for the strategic shift from
"port retail algorithms ourselves" to "rely on WorldBuilder for
rendering + dat-handling, port only what WB doesn't cover."
Updates CLAUDE.md:
- Adds top-level instruction: read the inventory FIRST before
re-porting anything in the 🟢 list
- Reframes references/WorldBuilder/ as acdream's rendering BASE,
not just a reference repo
- Updates the "Reference hierarchy by domain" table to point
rendering/dat questions at WorldBuilder, with retail decomp as
cross-check
Subsequent commits will fork WorldBuilder and replace our terrain/
scenery/object rendering with calls into the fork.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
11 KiB
WorldBuilder Inventory — what we take, adapt, or leave
Status: load-bearing reference. As of 2026-05-08 acdream's strategy is to rely heavily on WorldBuilder for rendering and dat-handling rather than re-port retail algorithms ourselves. WorldBuilder is MIT-licensed, is 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 already target.
Integration model: fork upstream WorldBuilder at
github.com/Chorizite/WorldBuilder, depend on our fork, delete editor-only
code, expose hooks for our network state to feed scene data in. Sync with
upstream via merge so we inherit fixes. This document tells you, before
you write code, whether the thing you're about to port already exists in
WorldBuilder.
Workflow change: Before re-implementing any AC-specific rendering or dat-handling algorithm, check this inventory first. If WorldBuilder has it, port from WorldBuilder (or call into our fork once it's wired up), not from retail decomp. Retail decomp remains the oracle for things WorldBuilder lacks — animation, motion, physics collision, networking.
Repo layout (as of cloned snapshot under references/WorldBuilder/)
Chorizite.OpenGLSDLBackend/— full OpenGL renderer (Silk.NET).WorldBuilder.Shared/— data models, dat parsers, landscape module.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).
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,ITexturePaintingToolModules/Landscape/Commands/*— undo/redo command pattern for editor (Add/Delete/Move/Rename/Reorder/etc.)LandscapeDocument+LandscapeLayer+LandscapeLayerGroup+LandscapeChunk+LandscapeLayerChunk+LandscapeLayerBase— editor document modelModules/Landscape/Models/TerrainPatch*+LandblockChangedEventArgs— editor mutation eventsModules/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 helpersHubs/*— collaborative editing via SignalRStaticObject(editor model) — replace with our own scene-state data model fed from networkBackendGizmoDrawer+GizmoRenderer— editor gizmosProjectStructures, IProject, Project— editor project filesKeyBinding— editor input bindingViewportInputEvent[Extensions]— editor viewport inputEditorState— 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
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 🟢, the new rule is: check this inventory FIRST. If WB has it, port from WB. Re-porting from retail decomp when WB already has a tested port is no longer appropriate — that's how we got the scenery edge-vertex bug.
When the inventory says "take wholesale or adapt" and we discover a behavior mismatch with retail (rare — WB is verified), the resolution is: reconcile WB ↔ retail decomp ↔ holtburger ↔ ACE ↔ ACViewer (the existing reference hierarchy in CLAUDE.md). WorldBuilder ranks at the top of that hierarchy for anything 🟢.