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 6ab269894a fix #172: port the retail CCylSphere collision family (platform step-up)
The Holtburg town-network portal platform (stab 0xC0A9B465, Setup
0x020019E3, CylSphere r=2.597m h=0.256m) blocked the player with an
endless rim slide instead of retail's step-up-onto-top — gating the
whole #137 dungeon repro. Surfaced when #149 started registering
BSP-less stab CylSpheres: the collision SHAPE became right while the
RESPONSE was still the hand-rolled AP-6 approximation (step-up gate +
radial wall-slide only).

Root cause: no cylinder-TOP support anywhere. DoStepUp's internal
step-down probe needs retail's step_sphere_down (0x0053a9b0) to land on
the flat top — a cylinder has no polygons for the walkable search — so
every step-up onto a wide cylinder failed into StepUpSlide and the
player orbited the rim (probe-confirmed: [cyl-test] result=Slid with
horizontal rim normals, launch-137-repro.log).

Port the full family verbatim: dispatcher intersects_sphere 0x0053b440
(placement/ethereal detection, step-down cap landing, walkable probe,
grounded step_sphere_up 0x0053b310, PathClipped collide_with_point
0x0053acb0, airborne land_on_cylinder 0x0053b3d0, Collide-flag
exact-TOI cap rest) + collides_with_sphere 0x0053a880 +
normal_of_collision 0x0053ab50 + slide_sphere 0x0053b2a0. Pseudocode +
settled BN x87 ambiguities (via ACE cross-ref) + two ACE bugs found and
NOT copied (head-slide foot-disp; see doc §8):
docs/research/2026-07-05-ccylsphere-collision-family-pseudocode.md

Ethereal cylinders now flow through retail's Layer-2 override
(pc:276961) instead of the early-OK consume — same net #150 behavior,
plus retail placement-blocked-by-cylinder semantics. SlideSphere gains
a sphereNum param (retail slides the head sphere by its own
displacement, 0x0053b843).

Register: AP-6 retired; AP-83 added (PerfectClip TOI tail decoded per
ACE, dead code until missiles). Tests: CylSphereFamilyTests (grounded
step-up onto the exact platform shape, tall-cylinder block, airborne
top landing, ethereal guard); the #42 self-shadow control assertion
updated to the retail observable (denied movement — the old ~1m radial
self-push was the approximation's artifact, not retail). Suites: Core
2533 / App 713 / UI 425 / Net 385 green.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 14:52:28 +02:00
.github ci(hygiene): allow dotnet ecosystem (nuget+telemetry) so build/test can run 2026-05-23 08:48:37 +02:00
.vscode ci: add GitHub Agentic Workflows scaffolding + daily hygiene assessment 2026-05-22 23:31:13 +02:00
docs fix #172: port the retail CCylSphere collision family (platform step-up) 2026-07-05 14:52:28 +02:00
memory fix(physics): L.4 — steep airborne hits slide-tangent (interim, deviates from retail) 2026-04-30 13:22:07 +02:00
references chore(submodule): advance WB to acdream-fix-floor-rendering 2026-05-19 13:23:19 +02:00
src fix #172: port the retail CCylSphere collision family (platform step-up) 2026-07-05 14:52:28 +02:00
tests fix #172: port the retail CCylSphere collision family (platform step-up) 2026-07-05 14:52:28 +02:00
tools docs(L.2g-S2): verbatim inbound-funnel pseudocode + observer cdb trace script 2026-07-02 18:33:23 +02:00
.gitattributes ci: add GitHub Agentic Workflows scaffolding + daily hygiene assessment 2026-05-22 23:31:13 +02:00
.gitignore docs(studio): dump-panel render sweep — all 26 windows verified 2026-06-25 16:50:39 +02:00
.gitmodules phase(N.0): wire up WorldBuilder fork as submodule + project refs 2026-05-08 08:51:49 +02:00
AcDream.slnx refactor(app): extract typed RuntimeOptions for startup env vars (Step 1) 2026-05-17 09:16:55 +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 docs: R5 arc close-out — V5 facade shipped, arc DONE; M1.5 critical path next 2026-07-05 11:12:37 +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
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
README.md docs: add docs/ISSUES.md tactical issue tracker + CLAUDE.md rules 2026-04-25 00:08:15 +02:00

acdream

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

Faithful port of the retail client's behaviour to Silk.NET with a modern, plugin-friendly architecture. The code is modern; the behaviour is retail.

Status: playable pre-alpha. You can log in to an ACE server, walk and run through Dereth, see other players animate correctly, watch the day-night cycle, hear ambient audio, and take weapons out. Many systems are still stubbed or in-progress — see roadmap.

Stack

  • Language: C# .NET 10
  • Graphics: Silk.NET (OpenGL 4.3)
  • Audio: OpenAL via Silk.NET
  • Dat parsing: Chorizite.DatReaderWriter
  • Networking: Custom UDP + ISAAC cipher + game-message layer, wire-compatible with ACEmulator server

What works

  • Connecting to a local ACEmulator (ACE) server on 127.0.0.1:9000
  • Character selection and login
  • Rendering Dereth terrain with retail-correct texture blending, per-vertex lighting, and road overlays
  • Static scenery (buildings, trees, scenery objects) via EnvCell walker
  • Animated characters (own + remote) with walk / run / strafe / jump / turn / attack motions sourced from the retail motion tables
  • Network sync with remote players — you can watch other characters animate correctly, including speeds and directional motion
  • Day-night cycle driven from the retail Region dat (0x13000000) — correct DayGroup picking via the retail LCG, correct keyframe interpolation, correct per-keyframe sky-object replace
  • Weather (rain/snow particles synced from the server via the retail DayGroup name)
  • Sky dome, stars, moon, clouds, sun — each rendered from the retail Region's SkyObjects with texture scrolling and alpha fade
  • Plugin host with live event replay-on-subscribe

What's stubbed or in-progress

  • Indoor transitions (building interiors) — disabled, Phase B.3 pending
  • Combat — animation works, damage math not wired
  • Lightning visual — the retail PhysicsScript-driven flash is researched but not wired (see docs/research/2026-04-23-lightning-real.md)
  • TimeSync drift — we only sync calendar on login, not periodically, so acdream's in-game clock gradually drifts from retail's
  • Landscape draw distance — currently ACDREAM_STREAM_RADIUS=2 (~400m) vs retail's several kilometres

See docs/plans/2026-04-11-roadmap.md for the ordered phase list. See docs/ISSUES.md for the rolling list of known bugs + small deferred features (tactical, bug-level; the roadmap is strategic, phase-level).

Building + running

Requires:

  • .NET 10 SDK
  • A retail Asheron's Call dat directory (Turbine/Microsoft property — supply your own). Contains client_portal.dat, client_cell_1.dat, client_highres.dat, client_local_English.dat.
  • A running ACE (ACEmulator) server on 127.0.0.1:9000 (or override via env var)

Launch (PowerShell on Windows — bash has trouble with the apostrophe in "Asheron's Call"):

$env:ACDREAM_DAT_DIR   = "$env:USERPROFILE\Documents\Asheron's Call"
$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 Debug

Offline CLI dat inspector (no server needed):

dotnet run --project src/AcDream.Cli -- "C:\path\to\Asheron's Call"

Diagnostic env vars

Variable Effect
ACDREAM_DUMP_SKY=1 Per-second dump of the interpolated SkyKeyframe values + per-SkyObject draw info + texture alpha histograms
ACDREAM_DUMP_MOTION=1 Dump every inbound UpdateMotion + resulting SetCycle
ACDREAM_STREAM_RADIUS=N Tune landblock visible-window radius (default 2 = 5×5)
ACDREAM_NO_AUDIO=1 Suppress OpenAL init
ACDREAM_DAY_GROUP=N Force a specific DayGroup index for A/B-testing weather presets
ACDREAM_RUN_SKILL=N / ACDREAM_JUMP_SKILL=N Client-side run/jump skill (default 200)

Layout

src/
  AcDream.App/                   rendering + audio + main loop (Silk.NET)
  AcDream.Core/                  game state, meshing, physics, sky, weather, lighting
  AcDream.Core.Net/              UDP + ISAAC + game-message layer
  AcDream.Cli/                   offline dat-inspector console app
  AcDream.Plugin.Abstractions/   plugin host interfaces
  AcDream.Plugins.Smoke/         example plugin

tests/
  AcDream.Core.Tests/            xUnit tests (742 passing)
  AcDream.Core.Net.Tests/        network-layer tests

tools/
  RetailTimeProbe/               Win32 P/Invoke ReadProcessMemory probe of
                                 the live retail acclient.exe — dumps
                                 TimeOfDay + sky-lighting globals so we
                                 can compare against acdream's state
  SkyObjectInspect/              dat-inspector for Region sky objects

references/                      vendored read-only reference code — ACE,
                                 ACViewer, WorldBuilder, holtburger,
                                 AC2D, Chorizite, DatReaderWriter.
                                 Gitignored.

docs/
  architecture/                  single-source-of-truth architecture doc
  plans/                         phase roadmaps + per-phase specs
  research/                      decompile-derived research, per-phase
                                 findings, deep-dive agent reports
  audit/                         phase-completion audits

Development workflow

All AC-specific behaviour is ported from the decompiled retail client (docs/research/decompiled/). The workflow is:

  1. Decompile first. Find the matching function in the decompiled client.
  2. Cross-reference. Check against ACE's C# port and ACViewer / WorldBuilder.
  3. Write pseudocode. Translate C to readable pseudocode first.
  4. Port faithfully. Translate line-by-line, preserving variable names and control flow.
  5. Conformance test. Add tests using golden values from retail.
  6. Integrate surgically. Minimise churn in the surrounding pipeline.

Guessing at AC-specific algorithms is explicitly forbidden — see CLAUDE.md for the full workflow rationale and the list of failure modes we've paid for in the past.

Reference repos

We cross-reference five external projects for every retail behaviour:

  • ACE (ACEmulator) — authoritative server-side protocol
  • ACViewer — MonoGame dat viewer; good for character appearance
  • WorldBuilder — Silk.NET dat editor; matches our stack
  • Chorizite.ACProtocol — clean-room C# protocol library
  • holtburger — most complete non-retail client; Rust TUI, full client-side behaviour
  • AC2D — C++ AC-client emulator; has the real terrain split formula and 0xF61C movement packet format

See CLAUDE.md for which reference is authoritative for which domain.

Licence

Not yet chosen. All external reference code is vendored under its own licence; see references/*/LICENSE. The acdream source code itself is unreleased — not yet distributed to the public. Once the licence choice is made it will go in a top-level LICENSE file.

The AC dat files and the game's intellectual property remain the property of Microsoft / Turbine. This project does not distribute any of those files or assets — you must supply your own retail install.