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 7b88fde52d fix(sky): drive wrap mode from mesh UV range — fixes Bug B (stars-as-square)
Bug B in docs/research/2026-04-26-sky-investigation-handoff.md: stars
rendered as a small square in one corner of the sky instead of stretching
across the dome.

Root cause: the wrap-mode heuristic at SkyRenderer.cs:234-237 was
"GL_CLAMP_TO_EDGE unless TexVelocity != 0". That heuristic was tuned to
fix a separate symptom (the outer dome 0x010015EE/F0/F1/F2 shows
wall-seam bleed under GL_REPEAT because of bilinear-filter sampling at
texel boundaries). But it misclassified any *static* sky object whose
mesh UVs are deliberately authored outside [0,1] to tile the texture
across the geometry.

The smoking gun: GfxObj 0x010015EF is OI-1 in EVERY DayGroup (always
loaded), has TexVelocity = 0 (no scrolling), and authors UVs in
[0.398, 4.602] (texture tiles ~4× across each face). Under
CLAMP_TO_EDGE the bulk of the inner dome sampled the texture's edge
texels; only the small region where UVs happened to fall in [0,1]
showed actual texture content. Hence "a square in one corner".

Fix:

* GfxObjMesh.Build() now scans the resulting per-vertex UVs and sets
  GfxObjSubMesh.NeedsUvRepeat true when any component lies outside
  [0,1]. Mesh-time scan, not draw-time guess.
* SubMeshGpu carries the flag through to draw time.
* SkyRenderer uses `sub.NeedsUvRepeat || obj.TexVelocity != 0` to
  decide REPEAT vs CLAMP_TO_EDGE. The dome (UVs in [0,1]) keeps
  CLAMP — no seam regression. The inner star/sky layer 0x010015EF
  (UVs outside [0,1]) gets REPEAT — texture tiles across the dome.
  Cloud meshes (UVs outside [0,1] AND non-zero TexVelocity) keep
  REPEAT via either branch.

Probe-driven: tools/StarsProbe (committed in 991fb9a) dumps every
SkyObject's geometry + UVs and flags meshes whose UV range exceeds
[0,1]. Run `dotnet run --project tools/StarsProbe -c Release` to
re-derive.

Verified visually by user against the live ACE server in Holtburg —
stars now stretch across the night sky instead of appearing as a
square in one corner. Build green, dotnet test 1222 pass.

Note: this is functionally retail-equivalent for the reported bug but
not the exact retail mechanism. Retail's GameSky::Draw at 0x00506ff0
relies on D3D's global default D3DTADDRESS_WRAP (i.e. REPEAT
everywhere). True retail-faithfulness would require investigating why
our pipeline shows seams on the dome under REPEAT (likely a bilinear
filter / non-seamless texture detail). The data-driven approach taken
here preserves working dome behavior while fixing the broken star
behavior.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-26 22:55:24 +02:00
docs docs(research): sky/weather investigation handoff + diagnostic tools 2026-04-26 21:40:34 +02:00
memory docs(workflow): align CLAUDE.md + memory + roadmap with named-retail foundation 2026-04-25 17:36:53 +02:00
src fix(sky): drive wrap mode from mesh UV range — fixes Bug B (stars-as-square) 2026-04-26 22:55:24 +02:00
tests fix(input): Phase K live-test fixes pt3 — fly→chase round-trip, Shift coexists, run-speed for backward + strafe 2026-04-26 14:48:45 +02:00
tools tools(probe): add StarsProbe to dump every SkyObject's geometry + UVs 2026-04-26 22:19:28 +02:00
.gitignore chore: ignore .worktrees/ for isolated feature work 2026-04-26 14:58:59 +02:00
AcDream.slnx feat(ui): AcDream.UI.ImGui backend — Hexa.NET.ImGui + Silk.NET input bridge 2026-04-25 00:29:09 +02:00
CLAUDE.md feat(ui): #25 Phase K.3 — Settings panel + click-to-rebind + Phase K shipped 2026-04-26 09:44: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.