Modern open-source C# .NET 10 Asheron's Call client. Faithful port of retail client behaviour to Silk.NET with a plugin API.
The user reported the lifestone crystal (AlphaBlend part 3 of the 4-part 0x020002EE setup) rendered with one side consistently missing — looked like "a box with one side missing, you can see into it" while the whole thing rotated. Isolated via experiment: routing the crystal through the opaque pass (no blending, depth write on) produced a whole solid shape. Routing it through the Phase 9.1 translucent pass (blending on, depth write off) produced the hole. Mesh build was eliminated as the cause. Root cause: our translucent pass matched WorldBuilder's state (SrcAlpha/OneMinusSrcAlpha, DepthMask(false)) but NOT its culling state. WorldBuilder enables GL_CULL_FACE with per-batch CullMode (references/WorldBuilder/Chorizite.OpenGLSDLBackend/Lib/ BaseObjectRenderManager.cs:361-365). Without face culling, the 58 triangles of the closed crystal shell drew in dict-iteration order; back faces that happened to draw AFTER front faces composited over them because depth-write-off meant nothing recorded depth within the translucent set. One face of the crystal ended up permanently overwritten by its own backside. Fix: in pass 2 (translucent) enable GL_CULL_FACE with GL_BACK and CCW front-face winding. Our mesh builder emits pos-side triangles as (0, i, i+1), which is CCW in standard OpenGL conventions, so GL_BACK correctly drops the inward-facing side. Back-face culling is disabled again after pass 2 so subsequent renderers (terrain etc.) see the default state. Known limitation: neg-side polys on translucent surfaces — which my pos/neg mesh-build fix would have emitted with reversed winding — now get culled in the translucent pass. AC rarely uses double-sided polygons on translucent surfaces so this is acceptable, and the opaque pass still renders them correctly. A future Phase 9.3 can track CullMode per sub-mesh and draw double-sided translucents with GL_NONE if it turns out to matter. Also strips the Portal/Lifestone [DIAG] spawn dump that served as one-shot evidence gathering during the investigation. 194 tests green. 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.