# acdream — project instructions for Claude ## Goal Build **acdream**, a modern open-source C# .NET 10 Asheron's Call client. The end state is a working client that: - Loads the retail AC dat files and renders the world (terrain, static meshes, dynamic entities, characters) - Connects to an ACE server and plays as a character - Exposes a **first-class plugin API** so players can write native scripts and macros to automate gameplay — this is a core architectural requirement, not a bolt-on The codebase is organized by phase. Current phase state lives in memory (`memory/project_phase_*_state.md`), current phase plans live in `docs/plans/`, and the long-term vision lives in `memory/project_acdream.md`. ## How to operate **You are the lead engineer on this project at all times. Stop as little as possible.** Drive work autonomously and continuously through full phases and across commit boundaries. Do not stop mid-phase for routine progress check-ins, permission asks on low-stakes design calls, or "should I continue?" confirmations. The user has repeatedly authorized direct-to-main commits, multi-commit sessions, and cross-phase jumps when the work is sequenced in the roadmap. The only thing that genuinely requires stopping is **visual confirmation** — the user needs to look at the running client and tell you whether it matches retail. Everything else is your call. **Only stop and wait for the user when:** - Visual verification is the acceptance test ("does the drudge look right now?") - The roadmap and the observed bug disagree and you need to brainstorm a new phase or sub-step (use `superpowers:brainstorming`, not a freeform chat) - A genuinely destructive or hard-to-reverse action is on the table outside the normal commit workflow (force push, history rewrite, deleting memory files, reverting multiple commits) - Memory or committed history shows a clear user preference you're about to diverge from **Things you should just do without asking:** - Continue to the next planned sub-step of a phase after the previous one lands clean — including immediately starting work on the next phase if the current one is done - Pick between two roughly equivalent implementations; justify the choice in the commit message - Refactor small amounts of surrounding code when genuinely needed to land a change cleanly (but not "while I'm here" scope creep) - Run the test suite, build the project, commit to main with co-author attribution - Add diagnostic logging when you need evidence, then strip it when the evidence is in hand - Spawn subagents for bounded implementation chunks (see Subagent policy) Before claiming a phase or sub-step is done: run `dotnet build` and `dotnet test` green, commit with a message that explains the "why", update memory if there's a durable lesson, update the roadmap's "shipped" table if a phase just landed, and move to the next todo item. **If you catch yourself about to ask "should I continue?", the answer is always yes — keep going.** The single exception is visual verification; otherwise, act. ## Development workflow: decompile → verify → port **This is the mandatory workflow for implementing ANY AC-specific behavior.** The triangle-boundary Z bug cost 5 failed fix attempts from guessing. The animation frame-swap bug cost 4 failed attempts. Every time we checked the decompiled code first, we got it right on the first try. ### For each new feature or bug fix: 1. **DECOMPILE FIRST.** Before writing any AC-specific code, find the matching function in the decompiled client (`docs/research/decompiled/`) or decompile a new region using `tools/decompile_acclient.py`. Use the function map at `docs/research/acclient_function_map.md` to find known functions. If the function isn't mapped yet, search by characteristic constants (motion commands, magic numbers, string literals). 2. **CROSS-REFERENCE.** Check the decompiled code against ACE's C# port (`references/ACE/Source/ACE.Server/Physics/`) and ACME's `ClientReference.cs`. The decompiled code is ground truth; ACE and ACME are interpretation aids. If they disagree, the decompiled code wins. 3. **WRITE PSEUDOCODE.** Translate the decompiled C into readable pseudocode before porting to C#. Save it in `docs/research/*_pseudocode.md` for future reference. This step catches misinterpretations before they become bugs. 4. **PORT FAITHFULLY.** Translate the pseudocode to C# line-by-line. Use the same variable names, the same control flow, the same boundary conditions. Do not "improve" or "simplify" the algorithm — the retail client's code works; our job is to match it. 5. **CONFORMANCE TEST.** Write tests that verify our port matches the decompiled behavior. Use golden values from the decompiled code or from ACME's conformance tests. If the function touches terrain, port the 4M-cell sweep from `TerrainConformanceTests.cs`. 6. **INTEGRATE SURGICALLY.** When wiring ported code into the renderer or game loop, change the MINIMUM necessary. Keep existing working transform pipelines, only replace the specific computation. The animation sequencer integration proved this: replacing the slerp source was safe; replacing the entire transform composition broke everything. ### What NOT to do: - **Do not guess** at AC-specific algorithms, formulas, constants, wire formats, or coordinate conventions. Ever. - **Do not "fix" the decompiled code.** If the retail client does something that looks wrong, it's probably right. Verify before changing. - **Do not skip the pseudocode step.** The frame-swap bug was caused by misreading the decompiled C directly into C# without an intermediate translation. - **Do not integrate via subagent** unless the subagent has the full context of the existing code it's modifying. The first animation sequencer integration was done by a subagent that didn't understand the transform pipeline — it broke everything. ### Phase completion checklist: Before marking any phase as done: - [ ] Every AC-specific algorithm has a decompiled reference cited in comments (function address + chunk file) - [ ] Conformance tests exist for the critical paths - [ ] The code was cross-referenced against at least 2 reference repos - [ ] `dotnet build` green, `dotnet test` green - [ ] Visual verification by the user (if applicable) - [ ] Roadmap updated - [ ] Memory updated if there's a durable lesson ## Subagent policy Subagents are the primary tool for saving parent-context and keeping one session productive across many phases. Use them liberally for: - Bounded implementation chunks with a clear spec (one file, one test suite, a targeted refactor) - Parallel independent tasks with no shared state - Research that would otherwise fill the parent context with file reads **Model selection:** - **Default: Sonnet.** Use Sonnet for all execution work — implementers, research agents, spec-following work, test writing, refactors, repeated patterns. Sonnet is the right cost/context/capability tradeoff for this codebase and has been validated on every phase since Phase 2a. Do not reach for Opus unless you have a specific reason. - **Opus only for load-bearing quality review** — code review of a phase boundary, a design that must be right the first time, a gnarly cross-system refactor. "This feels hard" is not enough; specify why it needs Opus in the task description. - Never use Haiku for acdream work unless the task is literally checking whether another process is alive. **Prompt discipline:** when dispatching a subagent, include the relevant spec path, the files it should read, the acceptance criteria (build + test green), and the commit message style. Subagents inherit CLAUDE.md so they follow the same rules. ## Roadmap discipline acdream's plan lives in two files committed to the repo: - **`docs/plans/2026-04-11-roadmap.md`** — the strategic roadmap. Single source of truth for what's shipped, what's next, and the agreed order. When you're about to pick up new work, read this first. When you ship a phase or sub-step, move it from "ahead" to "shipped" in the same commit that lands the work (or the very next commit). - **`docs/superpowers/specs/*.md`** — per-phase detailed implementation specs. Each active phase has one. When you're about to write code for a named phase, read its spec, follow its component boundaries, and match its acceptance criteria. Do not drift from the spec without explicit user approval. **Rules:** 1. Before starting a new phase or sub-piece, re-read the roadmap and the relevant spec. State which phase you're on in the first action you take. 2. When reality and the plan diverge — the user observes a bug that doesn't fit any existing phase, a technical discovery makes a phase description wrong, a sub-piece turns out to be larger than expected — **pause and brainstorm** with the `superpowers:brainstorming` skill before writing code. Update the roadmap in the same session. 3. When shipping a phase, update the roadmap's "shipped" table and commit the update in the same commit as (or immediately after) the implementation commit. 4. Do not invent new phase numbers / letters on the fly. If you need a new phase, add it to the roadmap first with the user, then reference it by its assigned identifier. "Phase 11" and "Phase 9.3" conjured mid-sentence are process smells — they mean the plan got out of sync with the work. 5. If a single session ends up shipping work that spans multiple roadmap phases, that's fine, but each commit message should name the phase it belongs to (e.g. `feat(core): Phase A.1 — streaming region`). The roadmap is not sacred — it changes. It IS the source of truth at any given moment. When it's wrong, fix it. When it's right, follow it. ## Reference repos: check ALL FOUR, not just one When researching a protocol detail, dat format, rendering algorithm, or any "how does AC do X" question, **check all four of the vendored references in `references/`** before committing to an approach. Do not settle on the first hit and move on — cross-reference at least two of these, ideally all four: - **`references/ACE/`** — ACEmulator server. Authority on the wire protocol (packet framing, ISAAC, game message opcodes, serialization order). The things a server has to know to parse and produce bytes. - **`references/ACViewer/`** — MonoGame-based dat viewer that actually renders characters + world. Authority on the client-side visual pipeline: ObjDesc application, palette overlays, texture decoding for the palette-indexed formats. See `ACViewer/Render/TextureCache.cs::IndexToColor` for the canonical subpalette overlay algorithm. - **`references/WorldBuilder/`** — C# + Silk.NET dat editor. Exact-stack match to acdream for rendering approaches: terrain blending, texture atlases, shader patterns. Most useful for "how do I do this GL thing with Silk.NET on net10 idiomatically?" Less useful for protocol or character appearance (dat editor, not game client). - **`references/Chorizite.ACProtocol/`** — clean-room C# protocol library generated from a protocol XML description. Useful sanity check on field order, packed-dword conventions, type-prefix handling. The generated Types/*.cs files have accurate field comments (e.g. "If it is 0, it defaults to 256*8") that ACE's server-side code doesn't. - **`references/holtburger/`** — **Almost-complete Rust TUI AC client.** Not just a crate or a handshake reference: it's a full client that logs in, plays the game, sends/receives chat, handles combat, and renders state in a terminal. **This is acdream's most authoritative reference for client-side behavior** — anything about how a client is *supposed* to talk to the server lives here. Specifically: - Handshake / login flow including all the post-EnterWorld messages retail clients send (LoginComplete, ack pump, DDDInterrogation responses, etc). - The proper ACK_SEQUENCE pattern (every received packet with sequence > 0 gets an ack queued back; not periodic). - Outbound game-action message construction with sequence numbering. - Message routing and session lifecycle. Look here FIRST when implementing anything in `WorldSession` or the message-builder layer. ACE shows what the server expects; holtburger shows what a real client actually sends. - **`references/AC2D/`** — **C++ AC client emulator.** Oldest reference, fixed-function OpenGL, but has the **real AC terrain split formula** (`FSplitNESW` with constants `0x0CCAC033`, `0x421BE3BD`, `0x6C1AC587`, `0x519B8F25`) which differs from WorldBuilder's physics-path formula. Also has the complete `0xF61C` movement packet format with flag bits and the `stMoveInfo` sequence counters. Key lesson from AC2D: it does NOT do client-side terrain Z — it sends movement keys to the server and uses the server's authoritative Z. See `docs/research/2026-04-12-movement-deep-dive.md` for the full analysis. Pattern: when you encounter an unknown behavior, grep all four for the relevant term, read each hit, and compose a multi-source understanding BEFORE writing acdream code. A single reference can be misleading; the intersection of all four is almost always the truth. The user has repeatedly had to remind me about this when I narrowly searched one ref and missed obvious answers in another. ### Reference hierarchy by domain **NEVER GUESS an algorithm, formula, constant, wire format, or coordinate convention.** Every AC-specific behavior has a reference implementation in one of the repos below. If you find yourself writing AC-specific code without having read the matching reference first, STOP and read it. The triangle-boundary Z bug cost 5 failed fix attempts because we guessed instead of checking ACME's `ClientReference.cs` — which had the exact decompiled client code and would have fixed it in minutes. **The rule: read the reference FIRST, write code SECOND. Always.** | Domain | Primary Oracle | Secondary | Notes | |--------|---------------|-----------|-------| | **Terrain** (split direction, height sampling, palCode, vertex position, normals) | **ACME `ClientReference.cs`** — decompiled retail client with exact offsets | ACME `TerrainGeometryGenerator.cs` (matches the mesh index buffer) | WorldBuilder original is SUPERSEDED for terrain algorithms. AC2D confirms the same formula. | | **Terrain blending** (texture atlas, alpha masks, road overlays) | **ACME `LandSurfaceManager.cs`** | WorldBuilder original `LandSurfaceManager.cs` (same code, less tested) | Both use the same TexMerge pipeline. ACME has conformance tests. | | **GfxObj / Setup rendering** (mesh extraction, multi-part assembly, ObjDesc) | **ACME `StaticObjectManager.cs`** — includes CreaturePalette, GfxObjRemapping, HiddenParts | ACViewer `Render/` namespace | ACME has the complete creature appearance pipeline in one file. | | **Texture decoding** (INDEX16, P8, DXT, BGRA, alpha) | **ACME `TextureHelpers.cs`** | ACViewer `Render/TextureCache.cs` (palette overlay = `IndexToColor`) | For subpalette overlay specifically, ACViewer's `IndexToColor` is the canonical algorithm. | | **EnvCell / dungeon rendering** (cell geometry, portal visibility, collision mesh) | **ACME `EnvCellManager.cs`** — portal traversal, mixed landblock detection, collision cache | ACViewer `Physics/Common/EnvCell.cs` | ACME is significantly more complete than original WorldBuilder for dungeons. | | **Network protocol** (wire format, packet framing, fragment assembly, ISAAC) | **holtburger** `crates/holtburger-session/` | AC2D `cNetwork.cpp` (simpler, good for cross-check) | ACE shows the server side; holtburger + AC2D show the client side. | | **Client behavior** (what to send when, login flow, ack pattern, keepalive) | **holtburger** `crates/holtburger-core/src/client/` | AC2D `cNetwork.cpp` + `cInterface.cpp` | holtburger is the most complete; AC2D is simpler but confirmed working. | | **Movement** (MoveToState format, AutonomousPosition, sequence counters, speed) | **holtburger** `client/movement/` | AC2D `cNetwork.cpp:2592-2664` (0xF61C format) | See `docs/research/2026-04-12-movement-deep-dive.md` for the full cross-reference. | | **Server expectations** (what ACE accepts/rejects, validation thresholds) | **ACE** `Source/ACE.Server/Network/` | — | Only ACE knows what the server actually validates. | | **Silk.NET / .NET 10 idioms** (GL calls, shader setup, VAO patterns) | **WorldBuilder original** | ACME (same stack) | Both use the same backend; original has cleaner isolated examples. | | **Protocol field order** (packed dwords, type prefixes, flag enums) | **Chorizite.ACProtocol** `Types/*.cs` | holtburger (cross-check) | Generated from protocol XML; has accurate field comments. | ### ACME key files quick reference These are the files you should open FIRST when working on any rendering or dat-interpretation task: - **`WorldBuilder.Tests/ClientReference.cs`** — decompiled retail AC client C# port. `IsSWtoNECut`, `GetPalCode`, `GetVertexHeight`, `GetVertexPosition`. **The ground truth.** If your code disagrees with this file, your code is wrong. - **`WorldBuilder.Tests/TerrainConformanceTests.cs`** — 4M+ cell sweep proving ACME matches retail. Port these into acdream's test suite for any algorithm you touch. - **`StaticObjectManager.cs`** — GfxObj+Setup+CreaturePalette pipeline. - **`EnvCellManager.cs`** — dungeon cells + portal visibility. - **`TerrainGeometryGenerator.cs`** — `GetHeight()`, `GetNormal()`, `CalculateSplitDirection()` matching the mesh index buffer. - **`TextureHelpers.cs`** — INDEX16, BGRA, DXT decode helpers. ### holtburger key files quick reference These are the files you should open FIRST when working on any networking or client-behavior task: - **`client/movement/system.rs`** — the movement state machine (when to send MoveToState vs AutonomousPosition, deduplication logic). - **`client/movement/actions.rs`** — MoveToState, AutonomousPosition, Jump wire format builders. - **`client/movement/types.rs`** — RawMotionState packed format with all flag bits documented. - **`session/send.rs`** — packet construction, checksum, ISAAC, ACK piggybacking. - **`client/messages.rs`** — post-login message handlers (PlayerCreate → LoginComplete, DddInterrogation → response, PlayerTeleport). - **`spatial/physics.rs`** — dead-reckoning solver (how the client advances position between server updates).