Modern open-source C# .NET 10 Asheron's Call client. Faithful port of retail client behaviour to Silk.NET with a plugin API.
Find a file
Erik 323f5a334d fix(render): S4 chunk 1 round 2 (LAST) - honest PM/PC gate, seeded portalsDrawnCount, the SOME-vs-SAME-plane pin, sixth pose, comment truth
Round 1 (2bd353234) was three-lens reviewed: retail-faithful PASS,
production PASS, gate-honesty FAIL. Every finding landed on the
terrace-edge KnownFailure row plus one pin gap. This is the last round.

R2-1 - gate honesty. WalkTraceConformanceTests.AlphaDepthTranscript.cs's
own KnownFailure doc comment claimed "the PC sequence matches exactly";
it never did - Assert.Equal(expected.PmEvents, actualPm) threw first, so
the PC Assert.Equal line never ran. RunAlphaDepthTranscriptGate now
computes BOTH diffs (SequenceEqual, not Assert.Equal) before asserting
either, and Assert.Fail's message prints both sequences together
whenever either diverges - a written claim about one sequence is now
only ever one this method actually evaluated. Re-running the OLD
(unseeded, cold PortalsDrawnCount=0) code path through this new combined
assertion shows terrace-edge's real divergence was WORSE than round 1
believed: both PM and PC diverged (PC expected counter=2, actual
counter=0) - round 1's "PC matches" claim was not just untested, it was
false.

R2-2 - the harness fix. Retail's portalsDrawnCount (wo(008719b4)) is a
PERSISTENT session global; each capture's own FIRST PM or PC line
(cathedral-arrival 0, cathedral-leak 0, foundry-deep 1,
holtburg-doorway-still 2, terrace-edge 2, cathedral-stair-arch 8) already
carries the pre-capture value - terrace-edge's own sample sits in the
"F 1" preamble text a cdb session prints before the first parsed frame
marker (line 1209, ahead of "F 1" at line 1298), so no amount of
replaying the CAPTURED frames from a cold start can ever reach it (this
fixture's own turns never touch the counter - every PC line reads
ov=0). New WalkAlphaDepthTrace.LoadInitialCounter(root, fixtureName)
scans a fixture's raw lines, ignoring frame boundaries, for the first
PM/PC match and returns its counter. RunAlphaDepthTranscriptGate seeds
WalkFrameDriver.PortalsDrawnCount (already an internal, test-assembly-
settable field) from this value, runs ONE Collect+Replay pass, and
deletes the two-pass "priming" replay outright. Result: terrace-edge
turns GREEN with no KnownFailure tag; every other pose stays exact
(a fixture with real steady-state seal activity computes the identical
value a priming pass used to converge to, since a steady state is by
definition unchanged by one more pass). No pose diverges after seeding,
so the packet's "write the divergence into section 9" fallback never
triggers - nothing needed there this round.

R2-3 - the SOME-vs-SAME-plane discriminator. T2's existing five cases
never separated retail's real quantifier ("every vertex lies on the SAME
one of the four +/-12 planes") from a weaker "every vertex lies on SOME
plane" (per-vertex OR across the four planes, ANDed across vertices) -
the existing split-plane case's third vertex sits on NO plane at all, so
both readings admit it for the same reason. New case in
WalkVisibilityMathTests.cs
(Boundary_guard_admits_a_polygon_whose_every_vertex_is_on_SOME_plane_but_not_the_SAME_one)
and a fourth sink.OnPunchGeometry call in WalkFrameDriverTests.cs's
OnPunchGeometry_RejectsOnlyWhenEveryVertexSharesOnePlane_ButPunchesAnyOtherShape
pin close the gap: [(12,0,3),(0,12,3),(12,5,3)] - every vertex touches
SOME plane (vertex1/3 on x=+12, vertex2 on y=+12) but no SINGLE plane
holds all three (x=+12 cleared by vertex2's x=0, y=+12 cleared by
vertex1's y=0) - retail's real four-accumulator guard admits it; the
weaker per-vertex-OR form rejects it.

R2-4 - the sixth pose. Cherry-picked 4f12cd06b (walk+alphadepth capture)
and 3a6aa7eef (pmverts capture) from claude/campaign-w-retail-frame-walk
onto 2bd353234 - both applied clean, no conflicts (README.md merged
without a manual row). New
AlphaDepthTranscript_CathedralStairArch_MatchesRetailFrame2 Fact: root
0xF4180114, seven outside views, sixteen mode=1 building punches (all
counterBefore=0008 - far-Z punches never touch the counter) of which
twelve are guard-rejected on local y=12.000, then eight mode=0 exit
seals with counterBefore running 0..7 against the root's own ov=7
read-then-zero, settling this fixture's own steady-state counter at 8 -
exactly the value LoadInitialCounter reads back out of its own preamble.
PASS.

R2-5 - comment truth. (a) RetailPViewPassExecutor.cs:
DrawPortalDepthWrite's and DrawExitPortalMask's summaries corrected -
neither the retired ">=3 vertices" pre-filter nor "always matches what
reached the GPU" describe F2's actual count-before-clip behavior any
more. (b) The F2 pin's doc comment
(RetailPViewPassExecutorTests.DrawExitPortalMask_CountsAnUnclippableTwoVertexPolygon_ButDrawsNothing)
named TWO alternative mutations as if both failed; verified only one
does (see mutations below) - the doc comment now says so explicitly and
keeps only the pre-filter mutation. (c) WalkVisibilityMath.cs's doc
comment stated DAT-scan figures as bare facts; independently re-verified
this round with a freshly-written scan (own code, walking the same
production EnvCell.CellPortals/CellStruct.Polygons shape
WalkCellFactory itself uses, over the full 0x0000-0xFFFF landblock-prefix
range) - every cited figure reproduced bit-exact (3,405 landblocks with
cells; 1,854,237 portal polygons; 2,889 any-vertex; 2,163 all-on-plane,
all exit, 0 interior; 16,939 exit portals total, 1,837,298 interior) -
so the doc comment now states the counting rule (id range, what's
counted, how unresolvable polygons/cells are skipped) alongside every
figure instead of leaving them unqualified; landblocksWithCells=3,405
also independently matches CellStructSurfaceConstructionInstalledDatTests'
own OH2 walk of the identical range (that test's own golden-count
comment). The scratch scan itself is not part of this diff (deleted
after use, same as F1's own datScan). (d) This commit body does not
cite "register tests" as evidence - no test reads the register.
Register truth is the human read: no row changes, AD-119 (the C2
blend-vs-write-mask row) unchanged.

Mutations run this round (all verified against production code, then
reverted):
  - R2-1/R2-2 (disable seeding, driver.PortalsDrawnCount = 0 instead of
    initialCounter): AlphaDepthTranscript_TerraceEdge_MatchesRetailFrame2
    fails - "terrace-edge.alphadepth: PM DIVERGES - expected
    [(mode=1,counterBefore=2), (mode=1,counterBefore=2)], actual
    [(mode=1,counterBefore=0), (mode=1,counterBefore=0)]; PC DIVERGES -
    expected [(ov=0,counter=2,fc=0), (ov=0,counter=2,fc=0)], actual
    [(ov=0,counter=0,fc=0), (ov=0,counter=0,fc=0)]" - proving both the
    seeding fix (R2-2) and the honest dual-sequence message (R2-1) at
    once.
  - R2-3 (replace the four per-plane accumulators with a single
    per-vertex "on ANY plane" test ANDed across vertices):
    Boundary_guard_admits_a_polygon_whose_every_vertex_is_on_SOME_plane_but_not_the_SAME_one
    fails, Assert.False() Expected:False Actual:True;
    OnPunchGeometry_RejectsOnlyWhenEveryVertexSharesOnePlane_ButPunchesAnyOtherShape
    fails, Assert.Equal() Expected:3 Actual:2.
  - R2-5b, mutation ONE (restore the old `localVertices.Length < 3`
    pre-filter ahead of the guard):
    DrawExitPortalMask_CountsAnUnclippableTwoVertexPolygon_ButDrawsNothing
    fails, Assert.Equal() Expected:1 Actual:0 - kept as the pin's cited
    mutation.
  - R2-5b, mutation TWO (move `submitted++` to AFTER
    `_portalDepthMask.DrawDepthFan(...)` instead of before): same test
    STILL PASSES - DrawDepthFan has no effect on the local `submitted`
    counter, so the final returned value is identical regardless of
    which side of that call the increment sits on. Confirmed unobservable
    exactly as R2-5b required; the doc comment no longer names this as a
    failing mutation.

Gates: dotnet build tests/AcDream.App.Tests -c Release -> 0 warnings/0
errors. dotnet build src/AcDream.App -c Release -> 0 warnings/0 errors.
Hermetic lane (Lane!=InstalledDat&Lane!=PreparedPackage&Lane!=Live&
Lane!=Manual&Lane!=Timing&Lane!=Windows&Lane!=Linux&Lane!=SystemFont&
Purpose!=Diagnostic&Status!=KnownFailure): 6830/6830 passed (+1 over
round 1's 6829, the new T2 case). InstalledDat lane
(ACDREAM_RUN_INSTALLED_DAT_TESTS=1, --filter Lane=InstalledDat): 254
total (+1 over round 1's 253, the new sixth Fact), 249 passed, 4 failed -
exactly the pre-existing four (LayoutImporterMediaBearingChildSweepTests
and LayoutImporterInvisibleSweepTests, both #383;
TowerAscentReplayTests' KnownFailure; Oh_doorway_still_first_frame_diff,
#458) plus the pre-existing WalkLookInGateSweepTests skip - terrace-edge
no longer fails, no new divergence anywhere else. All six
AlphaDepthTranscript_*_MatchesRetailFrame2 Facts: 6/6 passed standalone.
Shader classes (VulkanShaderDescriptorContractTests +
VulkanShaderManifestTests + RenderPackSpirvValidatorTests +
SkyVertexLayoutTests): 35/35. RetailPViewPassExecutorTests +
WalkFrameDriverTests (full classes, regression check on the R2-3/R2-5b
edits): 57/57.

Commits: two cherry-picks (4f12cd06b, 3a6aa7eef) from
claude/campaign-w-retail-frame-walk, both clean, plus this one fix
commit on top of 2bd353234.

Register: no new AD row; AD-119 unchanged (human read, not a test -
see R2-5d above).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-03 23:38:52 +02:00
.gitea/workflows ci: put the downloads in the 'latest' release, not just the pointer 2026-08-19 16:25:48 +02:00
.github ci: make GitHub workflows manual only 2026-08-18 17:50:50 +02:00
.vscode ci: add GitHub Agentic Workflows scaffolding + daily hygiene assessment 2026-05-22 23:31:13 +02:00
assets/icons fix(app): apply the window icon from Load, not beside Window.Create 2026-08-20 15:13:29 +02:00
docs feat(render): S4 chunk 1 — retail far-punch bits, the ±12 local-input reject, the depth truth table and cross-frame latch pins 2026-09-03 23:38:52 +02:00
memory fix(platform): Campaign LA LA0 review fixes — CI Linux lanes, arch doc, self-guard 2026-08-14 15:30:04 +02:00
references chore(submodule): advance WB to acdream-fix-floor-rendering 2026-05-19 13:23:19 +02:00
samples feat(render): implement Campaign AR and terrain fidelity 2026-08-22 13:13:29 +02:00
src fix(render): S4 chunk 1 round 2 (LAST) - honest PM/PC gate, seeded portalsDrawnCount, the SOME-vs-SAME-plane pin, sixth pose, comment truth 2026-09-03 23:38:52 +02:00
tests fix(render): S4 chunk 1 round 2 (LAST) - honest PM/PC gate, seeded portalsDrawnCount, the SOME-vs-SAME-plane pin, sixth pose, comment truth 2026-09-03 23:38:52 +02:00
tools tools(selfgate): #464 scripted tilt to the owner's eye height (sixteen mouselook samples) 2026-09-03 22:54:44 +02:00
.gitattributes ci: add GitHub Agentic Workflows scaffolding + daily hygiene assessment 2026-05-22 23:31:13 +02:00
.gitignore research(render) Campaign FW0: retail walk-oracle harness + 10 live trace fixtures 2026-08-30 09:10:07 +02:00
.gitmodules phase(N.0): wire up WorldBuilder fork as submodule + project refs 2026-05-08 08:51:49 +02:00
AcDream.slnx feat(render): implement Campaign AR and terrain fidelity 2026-08-22 13:13:29 +02:00
AGENTS.md fix(render): harden portal exit handoff 2026-08-25 17:39:44 +02:00
analyze_flap_live.py diag(render): flap re-diagnosed as portal-flood re-clip DRIFT; physics + camera REFUTED 2026-06-08 11:21:46 +02:00
CLAUDE.md fix #435 (part 2, closes it): attribute the unowned probes — delete 7, reclassify 8, restore 1 2026-08-24 12:32:42 +02:00
Directory.Build.props build: make release restore reproducible 2026-08-18 10:29:00 +02:00
Directory.Packages.props build: make release restore reproducible 2026-08-18 10:29:00 +02:00
find_burst.py diag(render): flap re-diagnosed as portal-flood re-clip DRIFT; physics + camera REFUTED 2026-06-08 11:21:46 +02:00
global.json ci: add bounded complete release gate 2026-08-18 09:09:38 +02:00
launch-a6-issue98-capture.ps1 docs(research): A6.P3 #98 — comparison harness findings + neighborhood fixtures 2026-05-23 20:12:43 +02:00
launch-a6-issue98-cottage-gfxobj-dump.ps1 test(phys): A6.P3 #98 — comparison harness reproduces cottage-floor cap 2026-05-23 20:44:50 +02:00
launch-a6-issue98-polydump.ps1 docs(research): A6.P3 #98 — comparison harness findings + neighborhood fixtures 2026-05-23 20:12:43 +02:00
launch-flap-capture.ps1 diag(render): flap re-diagnosed as portal-flood re-clip DRIFT; physics + camera REFUTED 2026-06-08 11:21:46 +02:00
launch-flap-churn.ps1 diag(render): launch-flap-churn.ps1 — Phase 1 portal-churn pin capture script 2026-06-08 12:56:44 +02:00
launch-flap-verify.ps1 docs(render): FLAP settled by live-retail measurement — full retail port DECIDED (Option A) + exhaustive handoff 2026-06-08 16:19:34 +02:00
NOTICE.md chore(O-T1): create Core/Rendering/Wb directory + NOTICE.md attribution 2026-05-21 14:59:56 +02:00
NuGet.Config build: make release restore reproducible 2026-08-18 10:29:00 +02:00
README.md fix: complete retail parity stability pass 2026-08-28 20:01:39 +02:00

acdream

A modern open-source C# / .NET 10 Asheron's Call client.

acdream ports the observable behaviour of the September 2013 retail client to Silk.NET and a modern, plugin-friendly architecture. The code is modern; the behaviour is retail.

Status: playable pre-alpha. M3, “Cast a spell,” landed on 2026-07-21 and M4, “Live in the world,” is active. The graphical client supports the connected combat, magic, movement, portal, inventory, loot, and retained-UI loops used by the current test characters. The presentation-independent GameRuntime and the Linux/Windows multi-session headless host are complete. Native Linux graphics are intentionally parked at the L1 capability checkpoint; Windows is the currently validated graphical platform.

The documentation map is the entry point for current milestones, roadmap state, architecture, issues, retail divergences, research, and durable project memory.

Technology

  • Runtime: C# and .NET 10
  • Graphics: Silk.NET, OpenGL 4.3 core, bindless textures, shader draw parameters, SSBOs, and multi-draw indirect
  • Audio: OpenAL through Silk.NET
  • Content: retail DAT files plus a machine-local, memory-mapped acdream.pak produced by AcDream.Bake
  • Networking: custom UDP, ISAAC cipher, and game-message layers compatible with ACEmulator
  • UI: retained retail gameplay UI plus opt-in ImGui developer tools
  • Automation: the same presentation-independent GameRuntime is hosted by both the graphical client and AcDream.Headless

The modern renderer is mandatory. There is no legacy renderer fallback. Startup reports an actionable error if the required OpenGL capabilities are missing.

What works

  • ACE login, character selection, world entry, chat, client commands, reconnect, and graceful logout.
  • Outdoor, building, cellar, and dungeon streaming with prepared terrain, scenery, buildings, EnvCells, collision, portal visibility, sky, fog, lighting, audio, and day/night presentation.
  • Local and observed movement, animation, jumping, selection, radar, combat stances, melee, bows, crossbows, spell projectiles, death, corpses, chests, and looting.
  • Inventory bags, stable server ordering, stack splitting, ground drops, paperdoll equipment, weapon switching, quick bars, item use, cooldowns, and giving items to NPCs.
  • Retail-style retained UI for vitals, chat, toolbar, inventory, character, attributes, skills, spellbook, components, effects, combat/spell/jump bars, radar/compass, dialogs, external containers, and assessment.
  • Complete end-of-retail spell catalog, learned and favorite spells, component preflight, connected casts, enchantments, DAT-driven projectiles and effects, recall, portal-space travel, Hidden/UnHide, and remote materialization.
  • One presentation-independent runtime owner for session, entities, objects, inventory, character state, selection, interactions, combat, magic, movement, physics, projectiles, world environment, and portal transit.
  • A no-window Windows/Linux host with deterministic bot commands/events, shared immutable content, multi-session scheduling, isolation, reconnect, resource telemetry, and tested 1/5/10/30-session ownership.
  • Plugin loading, shared command/input abstractions, retained markup panels, and permanent ImGui developer tools behind ACDREAM_DEVTOOLS=1.

Current boundaries

  • The active M4 prelude is world interaction completion. Slices 13, including assessment and its final formula/icon/layout correction, are user-accepted. Equipped-child picking and vendor browse/buy/sell are the next uncompleted slices.
  • Issue #225 retains the lifestone/particle shared-alpha visual comparison. Its connected lifetime and performance routes already pass.
  • Narrow carried behaviour debt includes issue #153 (an unstreamed far-teleport edge), issue #116 (slide feel), issue #235 (30 Hz capped/RDP jump presentation), and the live temporary-stopgap rows in the retail divergence register.
  • Native Linux graphics are deferred. L0 portability and L1 backend/capability reporting are implemented; WSLg reaches the GPU through Mesa D3D12 but does not expose mandatory GL_ARB_bindless_texture. Resume with a supported physical Linux AMD/NVIDIA driver before beginning later Slice L work.
  • Advanced vendor/trade/crafting/social surfaces and larger M4 quest, character-creation, and emote bodies remain roadmap work.

Prerequisites

  • .NET 10 SDK
  • Your own retail Asheron's Call DAT directory containing:
    • client_portal.dat
    • client_cell_1.dat
    • client_highres.dat
    • client_local_English.dat
  • A machine-local acdream.pak built from those DATs
  • A running ACE server for connected play; the examples use 127.0.0.1:9000
  • For the graphical client, a driver exposing the mandatory Vulkan capabilities validated at startup

The project does not distribute Microsoft/Turbine DAT files or derived prepared packages.

Build and test

dotnet restore AcDream.slnx
dotnet build AcDream.slnx -c Release
dotnet test AcDream.slnx -c Release --no-build

The current CI-filtered Windows baseline is a successful Release build with 16,151 passing tests and zero failures; opt-in live, installed-DAT, prepared-package, manual, timing, and platform-specific lanes run separately.

Prepare content

Production rendering and collision use the validated prepared package rather than decoding world meshes on the frame path:

dotnet run --project src\AcDream.Bake\AcDream.Bake.csproj -c Release -- `
  --dat-dir "C:\Games\Asheron's Call" `
  --out "C:\Games\Asheron's Call\acdream.pak"

A complete format-2 package from the standard installed DAT set is about 570 MiB (the former format-1 package was about 30 GB). It is machine-local and must not be committed. ACDREAM_PAK_PATH overrides the default <DAT directory>\acdream.pak.

Run the graphical client

$env:ACDREAM_DAT_DIR   = "C:\Games\Asheron's Call"
$env:ACDREAM_PAK_PATH  = "C:\Games\Asheron's Call\acdream.pak"
$env:ACDREAM_LIVE      = "1"
$env:ACDREAM_TEST_HOST = "127.0.0.1"
$env:ACDREAM_TEST_PORT = "9000"
$env:ACDREAM_TEST_USER = "testaccount"
$env:ACDREAM_TEST_PASS = "testpassword"

dotnet run --project src\AcDream.App\AcDream.App.csproj -c Release

The DAT directory can instead be supplied as the first positional argument:

dotnet run --project src\AcDream.App\AcDream.App.csproj -c Release -- `
  "C:\Games\Asheron's Call"

Run a headless session

AcDream.Headless loads no App, UI, OpenGL, native-window, or audio assembly. Create a version-1 configuration such as bot.json:

{
  "version": 1,
  "process": {
    "content": {
      "datDirectory": "/opt/ac",
      "preparedAssetPath": "/opt/ac/acdream.pak"
    }
  },
  "sessions": [
    {
      "id": "bot-1",
      "endpoint": { "host": "127.0.0.1", "port": 9000 },
      "account": "testaccount",
      "character": { "index": 0 },
      "policy": { "id": "idle" },
      "credential": {
        "provider": "environment",
        "reference": "ACDREAM_BOT_PASSWORD"
      }
    }
  ]
}

Then validate and run it:

export ACDREAM_BOT_PASSWORD='testpassword'
dotnet run --project src/AcDream.Headless/AcDream.Headless.csproj -c Release -- \
  validate --config bot.json
dotnet run --project src/AcDream.Headless/AcDream.Headless.csproj -c Release -- \
  run --config bot.json

For a single local session, run also accepts --user <account> --password <password>. Add uniquely identified session entries and credential references for a multi-session process. Available built-in policies are idle, lifecycle-smoke, observer-movement, and portal-route-smoke.

Useful startup options

Variable Effect
ACDREAM_DAT_DIR Retail DAT directory
ACDREAM_PAK_PATH Prepared package path; defaults to <DAT dir>/acdream.pak
ACDREAM_LIVE=1 Enable connected mode
ACDREAM_TEST_HOST / ACDREAM_TEST_PORT ACE endpoint
ACDREAM_TEST_USER / ACDREAM_TEST_PASS Graphical-client credentials
ACDREAM_RETAIL_UI=0 Disable the retained retail gameplay UI for diagnostics; it is enabled by default
ACDREAM_DEVTOOLS=1 Enable ImGui developer tools
ACDREAM_NO_AUDIO=1 Suppress OpenAL initialization
ACDREAM_UNCAPPED_RENDER=1 Disable normal frame pacing for diagnostics
ACDREAM_DISPLAY_PROTOCOL=auto|x11|wayland Select the Linux GLFW backend
ACDREAM_DAY_GROUP=N Force a day-group index for weather/lighting comparisons
ACDREAM_STREAM_RADIUS=N Legacy override over configured streaming radii
ACDREAM_DUMP_SKY=1 Dump sky interpolation and draw diagnostics
ACDREAM_DUMP_MOTION=1 Dump inbound movement and motion-cycle decisions

Additional diagnostic and budget controls are documented beside their typed owners and in the linked research plans; they are not stable user settings.

Repository layout

src/
  AcDream.Runtime/              presentation-independent GameRuntime
  AcDream.App/                  graphical host, retained UI, renderer, audio
  AcDream.Headless/             Windows/Linux no-window multi-session host
  AcDream.Core/                 retail gameplay, movement, physics, world logic
  AcDream.Core.Net/             UDP, ISAAC, protocol and message routing
  AcDream.Content/              GL-free DAT and prepared-package content
  AcDream.Bake/                 offline acdream.pak builder
  AcDream.Cli/                  offline DAT inspector
  AcDream.UI.Abstractions/      shared UI/input models and contracts
  AcDream.UI.ImGui/             developer-tool presentation
  AcDream.Plugin.Abstractions/  BCL-only plugin contracts
  AcDream.Plugins.Smoke/        example plugin

tests/
  AcDream.*.Tests/              layer-matched xUnit projects

docs/
  README.md                     documentation authority and current map
  architecture/                ownership, structure, divergence, WB inventory
  plans/                       milestone, roadmap, and execution plans
  research/                    retail pseudocode, traces, fixtures, evidence
  audit/                       completion and conformance audits

memory/                        durable engineering references
references/                    gitignored external reference repositories

Development workflow

All AC-specific behaviour starts from the named retail oracle in docs/research/named-retail/:

  1. Search the named retail pseudo-C and headers by class::method.
  2. Use the older Ghidra chunks only when the named oracle is insufficient.
  3. Cross-reference ACE and the relevant client/viewer implementation.
  4. Record readable pseudocode and exact constants/order.
  5. Port the retail mechanism into the correct modern owner.
  6. Add conformance, lifecycle, and failure-boundary tests.
  7. Run the automated gate and the appropriate connected or visual gate.
  8. Update architecture, roadmap, divergences, and durable memory with the same change.

Guessing at AC-specific algorithms is forbidden. See AGENTS.md, CLAUDE.md, and the architecture guide for the full rules.

Reference projects

  • ACE / ACEmulator: authoritative server and protocol behaviour
  • ACViewer: character appearance and DAT presentation cross-check
  • WorldBuilder: extracted Silk.NET DAT/rendering foundation
  • Chorizite.ACProtocol: clean-room protocol reference
  • holtburger: broad non-retail client behaviour reference
  • AC2D: terrain and movement-packet cross-checks

The retail binary/decomp remains the behavioural oracle when references disagree.

Licence and game assets

The acdream source has not yet been assigned a top-level licence and is not ready for public redistribution. External reference code retains its own licence.

Asheron's Call DAT files, art, names, and other game assets remain the property of Microsoft/Turbine. This repository does not distribute them; users must supply their own retail installation.