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 fe0bfb075b Merge phase-2b/atlas-neighbors-cameras-events: Phase 2b
Phase 2b MVP complete. 9 commits implementing:
- Vertex struct gains TerrainLayer (uint, location 3 VertexAttribIPointer)
  and LandblockMesh.Build takes a TerrainTextureType → atlas layer map
- TerrainAtlas builds GL_TEXTURE_2D_ARRAY from Region.TerrainInfo.
  LandSurfaces.TexMerge.TerrainDesc, one layer per referenced TerrainTextureType
- Terrain shader rewritten to sample sampler2DArray with flat uint layer
  and per-landblock uModel translation
- TerrainRenderer grows AddLandblock(mesh, worldOrigin) for multi-landblock
  drawing, drops the ctor mesh param in favor of the new add pattern
- GameWindow replaces single-landblock load with WorldView.Load 3x3 grid;
  entity positions are translated by their source landblock's world offset
- ICamera interface extracted, OrbitCamera refactored to implement
- FlyCamera with WASD + raw cursor mouse look, pitch clamp, horizontal-plane
  movement independent of pitch
- CameraController with F toggle, Escape contextual (fly→orbit releases
  cursor; orbit→Escape closes window), cursor capture via CursorMode.Raw
- IGameState + IEvents + WorldEntitySnapshot added to Plugin.Abstractions
- WorldEvents implements replay-on-subscribe so plugins that subscribe
  after the world is loaded see every already-spawned entity exactly once
  before returning from +=
- WorldGameState exposes the entity snapshot list; AppPluginHost
  constructor gains state + events parameters
- Program.cs and GameWindow thread worldGameState + worldEvents through
  the startup; OnLoad calls FireEntitySpawned for each hydrated entity
- SmokePlugin subscribes in Enable, logs replay count at subscribe time
  (0 because it subscribes before world load) and the total seen count
  at Disable time (via live events during hydration)

6 new xUnit tests (43 → 48): 1 terrain layer mapping regression +
5 WorldEvents replay/live/unsubscribe/exception-safety tests.

Smoke verified against real dats: 33 terrain atlas layers at 512x512,
9 landblocks loaded in 3x3 grid, 239 entities hydrated across all
landblocks, build clean, no exceptions, all plugin lifecycle logs
visible including the new `sees 0 entities (replay count at subscribe)`
line.

Phase 2 (both 2a and 2b) is done. Next phase is visual verification
by the user and then Phase 3 planning (animated entities, doors,
terrain texture blending at cell boundaries, proper lighting, etc).
2026-04-10 20:32:46 +02:00
docs/plans docs: phase 2b implementation plan (9 tasks) 2026-04-10 20:13:03 +02:00
src feat(app): wire IGameState+IEvents into Program and SmokePlugin 2026-04-10 20:31:50 +02:00
tests feat(core): add IGameState, IEvents, WorldEvents with replay-on-subscribe 2026-04-10 20:29:29 +02:00
.gitignore chore: phase 0 — skeleton + dat asset inventory 2026-04-10 09:02:56 +02:00
AcDream.slnx feat(app): wire plugin host, ship smoke plugin, log lifecycle 2026-04-10 16:46:25 +02:00
README.md chore: phase 0 — skeleton + dat asset inventory 2026-04-10 09:02:56 +02:00

acdream

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

Status: pre-alpha, not playable. Phase 0 only — dat file asset inventory.

Stack: .NET 10, Chorizite.DatReaderWriter for dat parsing. Silk.NET + Avalonia planned for rendering/UI (not yet wired up).

Requires: A retail Asheron's Call install (Turbine/Microsoft property — supply your own). Set ACDREAM_DAT_DIR environment variable to the directory containing client_portal.dat, client_cell_1.dat, client_highres.dat, and client_local_English.dat, or pass it as the first CLI argument.

Layout

  • src/AcDream.Cli/ — console app that dumps asset counts from a dat directory
  • references/ — local read-only reference material (ACE, ACViewer, WorldBuilder, DatReaderWriter, holtburger, retail AC install). Gitignored.

Run

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

Or set ACDREAM_DAT_DIR and run without args.