Modern open-source C# .NET 10 Asheron's Call client. Faithful port of retail client behaviour to Silk.NET with a plugin API.
Ports WorldBuilder's full BuildTexture / FillCellData pipeline as
pure CPU functions in TerrainBlending.cs, along with the SurfaceInfo
recipe record and a TerrainBlendingContext input struct that carries
the atlas index lists the algorithm needs.
This is still pure algorithm work — no GL, no shaders, no mesh gen
changes. Visual Phase 3c.4 next commit wires it into LandblockMesh
and rewrites the terrain shaders to consume Data0..3.
Added (all ports of WorldBuilder LandSurfaceManager methods):
- ExtractTerrainCodes: inverse of GetPalCode terrain bits
- PseudoRandomIndex: deterministic hash over palette code for alpha
variant selection; overflow-dependent int math matches WorldBuilder
byte-for-byte
- RotateTerrainCode: *2 with wrap (1→2→4→8→1, multi-corner patterns
handled in tests)
- GetRoadCodes: decodes the 8-bit road mask into up to two canonical
road patterns + allRoad flag; magic 0xE/0xD/0xB/0x7 switch kept verbatim
- FindTerrainAlpha: picks corner vs side alpha map, walks the 4
rotations looking for a TCode match, returns (alphaLayer, rotation)
or (255, 0) for "not found"
- FindRoadAlpha: same idea for road maps, iterates all maps from a
pseudo-random offset
- BuildSurface: composes the above into a SurfaceInfo, handling the
all-road, all-duplicate-terrain, and distinct-terrain cases via
BuildOverlayLayers + BuildWithDuplicates (ports GetTerrainTextures +
BuildTerrainCodesWithDuplicates)
- FillCellData: packs a SurfaceInfo + CellSplitDirection into the 4
uint32 vertex attributes Data0..Data3. Byte layout documented in
XML comment and matches WorldBuilder's Landscape.vert uvec4 byte
unpacking exactly.
SurfaceInfo record carries resolved atlas byte layers directly (base +
3 terrain overlays + 2 road overlays, each with optional alpha layer
and 0-3 rotation). Sentinel 255 = "slot unused".
Tests (14 new, 75/75 total):
- ExtractTerrainCodes round-trip with GetPalCode
- RotateTerrainCode single-corner cycle + multi-corner patterns
- GetRoadCodes: no-road, all-road, single-corner road
- PseudoRandomIndex: range, count=0 guard, determinism
- BuildSurface: all-grass → base only; all-road → road as base;
two-grass-two-dirt → base + overlay
- FillCellData: full round-trip bit layout with recognizable
byte values in every slot, plus a no-road1 case that verifies
the texRd1 slot collapses to 255 when road1 alpha is absent
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
||
|---|---|---|
| docs/plans | ||
| src | ||
| tests | ||
| .gitignore | ||
| AcDream.slnx | ||
| CLAUDE.md | ||
| README.md | ||
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 directoryreferences/— 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.