Final allowed fix round for S4-c2 on cc8e5677a. This lands every item in the campaign packet section 12 without adding a flush site, shader, distance, overflow recovery draw, or graphical-client run. R2-1 particle row 5: ParticleRenderer now constructs and owns the actual particle-mesh-opaque pipeline using the existing particle_mesh shaders and layout, Blend=None, depth test/write enabled with WorldCompare, dynamic per-batch cull, clockwise front face, and no alpha-to-coverage. The production dispatch selects it for an opaque-classified mesh particle whose clamped material alpha is 1.0. Nonopaque mesh pipelines remain depth-write-off. The production route keeps cached reserve/immediate delegates and the warmed append/immediate paths allocate 0 B. R2-2 EnvCell exact per-subset routing: ObjectMeshManager carries Content's TextureBatchData.RetailSurfaceMask onto ObjectRenderBatch at the real upload boundary. EnvCellRenderer scans the active prepared cell snapshot and feeds each real transparent batch's exact mask through RetailAlphaMeshRouter. Pure 0x08 Base1ClipMap reaches CLIP, 0x02 alpha-family reaches ALPHA, and table Immediate subsets draw at the cell turn. Separate fixed-route draw sources coalesce to at most one token per (cell,list) and filtered replay draws only that list's subsets; a mixed cell contributes to both lists without duplicate replay. Detail-on routes eligible subsets immediately with the detail pass. The warmed dispatch/source allocation pins measure 0 B; the production scan/filter is covered behaviorally and uses only retained scratch/enumerators (static allocation audit). R2-3 capacity cleanup: RetailAlphaQueue registers a source before the 3,000 entry capacity return. A source whose first append is rejected is therefore reset by flush, EndFrame, or abort, but its rejected payload is never prepared or drawn. R2-4 production proof and prose: both actual Wb submit sites are exercised; the particle tests call the production dispatcher and inspect the constructed owner's production pipeline/selector; EnvCell tests upload real Content batch masks through ObjectMeshManager and drain real filtered MDI calls. The A1 positive proof executes WorldSceneRenderer's real outdoor frame owner through RetailPViewRenderer.DrawInside and RetailAlphaQueue.EndFrame and observes [DrawBuilding x N, RenderNormalMode] with no LandscapeFlush. The packet and register now state the varying retail first-for-list truth and the exact per-subset EnvCell/AP-238, visible AP-239 compositing, and AP-240 feeder scope. Physical active register counts remain AP=159 and AD=92. Final clean-state gates (actual output): - Release solution build: Build succeeded; 0 Warning(s); 0 Error(s). - Hermetic solution filter: every project green, 16,728 passed / 0 failed / 0 skipped total; AcDream.App.Tests 6,875/6,875. - InstalledDat: 255 passed / 10 failed / 1 skipped / 266 total, exactly the allowed identities: TowerAscent_StaircaseStaysConeVisible_EveryStep; MainGameUiAndChatInput_MediaBearingChildrenNowBuildAsRealWidgets (#383); EveryAuthoredInvisibleWidget_StartsHiddenAcrossAllLayouts (#383); Oh_doorway_still_first_frame_diff (#458); and the six AlphaFlushCounts_{CathedralArrival,CathedralLeak,CathedralStairArch, FoundryDeep,HoltburgDoorwayStill,TerraceEdge}_MatchesRetailFrame2. All six AlphaFlushSites_* pass in the same lane. - VulkanShaderDescriptorContractTests + VulkanShaderManifestTests + RenderPackSpirvValidatorTests: 32 passed / 0 failed / 0 skipped. - Corrected queue/router/walk/driver/particle/Wb/EnvCell/PView production filter: 211 passed / 0 failed / 0 skipped. - Explicit warmed production allocation pins: 2 passed; both measure 0 B. - Register: physical AP-238/AP-239/AP-240/AD-120/~~AP-34~~ rows each count exactly 1; active physical rows AP=159 and AD=92. - git diff --check: PASS. Production mutation checks (each applied, run to the named first failure, and exactly reversed before the final gates): 1. Restoring the particle row-5 throw fails OpaqueClassifiedMeshBatch_WithNoMaterialAlpha_DrawsImmediateOnOpaqueDepthState first with InvalidOperationException: mutation: row 5 unreachable. 2. Deleting row 5's immediate callback fails that same production-dispatch test's first collection assertion: expected [(Mesh, 11, True)], actual []. 3. Constructing the actual owner pipeline with depthWrite:false fails ImmediateOpaqueMesh_UsesProductionParticleMeshOpaquePipelineDescription first at Assert.True(description.Depth.Write): expected true, actual false. 4. Mapping the production selector back to _meshAlphaPipeline fails that same test first at Assert.Same: expected particle-mesh-opaque, actual particle-mesh-alpha. 5. Dropping RetailSurfaceMask at the real ObjectMeshManager upload boundary fails the mixed-cell production scan first: expected Clip | Alpha, actual Immediate. 6. Hardcoding the uploaded EnvCell scan to MaskAlphaFamily fails the mixed-cell production scan first: expected Clip | Alpha, actual Alpha; the pure-mask pin also reports expected Clip, actual Alpha. 7. Inverting the production detail predicate fails the detail-on production pin first: expected Immediate, actual Clip. 8. Removing both EnvCell replay filters fails the mixed production drain's real MDI assertions: each call expected DrawCount 1, actual DrawCount 2. 9. Moving RegisterSource below the full-capacity return fails every RejectedFirstUseSource_IsCleanedWithoutPrepareOrDraw row (flush, EndFrame, abort) at the first ResetCount assertion: expected 1, actual 0. 10. Hardcoding detailSurfaceActive=false at the real Wb dispatch fails both production submit-site tests at their first queue-count assertion: expected 0, actual 1. 11. Restoring RetailPViewRenderer's removed outdoor LandscapeFlush call fails OutdoorProductionPView_DrainsBuildingThenRenderNormalModeWithoutLandscapeFlush first at the real drain sequence: expected [DrawBuilding, RenderNormalMode], actual [DrawBuilding, LandscapeFlush, RenderNormalMode]. 12. Deleting WorldSceneRenderer's final EndFrame owner drain fails that same full-path A1 test first: expected [DrawBuilding, RenderNormalMode], actual [DrawBuilding]. Not done/deferred: none. No retail conflict or infeasible contract item was found. No graphical client was launched. Co-Authored-By: Codex <noreply@openai.com> |
||
|---|---|---|
| .gitea/workflows | ||
| .github | ||
| .vscode | ||
| assets/icons | ||
| docs | ||
| memory | ||
| references | ||
| samples | ||
| src | ||
| tests | ||
| tools | ||
| .gitattributes | ||
| .gitignore | ||
| .gitmodules | ||
| AcDream.slnx | ||
| AGENTS.md | ||
| analyze_flap_live.py | ||
| CLAUDE.md | ||
| Directory.Build.props | ||
| Directory.Packages.props | ||
| find_burst.py | ||
| global.json | ||
| launch-a6-issue98-capture.ps1 | ||
| launch-a6-issue98-cottage-gfxobj-dump.ps1 | ||
| launch-a6-issue98-polydump.ps1 | ||
| launch-flap-capture.ps1 | ||
| launch-flap-churn.ps1 | ||
| launch-flap-verify.ps1 | ||
| NOTICE.md | ||
| NuGet.Config | ||
| README.md | ||
acdream
A modern open-source C# / .NET 10 Asheron's Call client.
acdream ports the observable behaviour of the September 2013 retail client to Silk.NET and a modern, plugin-friendly architecture. The code is modern; the behaviour is retail.
Status: playable pre-alpha. M3, “Cast a spell,” landed on 2026-07-21 and
M4, “Live in the world,” is active. The graphical client supports the connected
combat, magic, movement, portal, inventory, loot, and retained-UI loops used by
the current test characters. The presentation-independent GameRuntime and
the Linux/Windows multi-session headless host are complete. Native Linux
graphics are intentionally parked at the L1 capability checkpoint; Windows is
the currently validated graphical platform.
The documentation map is the entry point for current milestones, roadmap state, architecture, issues, retail divergences, research, and durable project memory.
Technology
- Runtime: C# and .NET 10
- Graphics: Silk.NET, OpenGL 4.3 core, bindless textures, shader draw parameters, SSBOs, and multi-draw indirect
- Audio: OpenAL through Silk.NET
- Content: retail DAT files plus a machine-local, memory-mapped
acdream.pakproduced byAcDream.Bake - Networking: custom UDP, ISAAC cipher, and game-message layers compatible with ACEmulator
- UI: retained retail gameplay UI plus opt-in ImGui developer tools
- Automation: the same presentation-independent
GameRuntimeis hosted by both the graphical client andAcDream.Headless
The modern renderer is mandatory. There is no legacy renderer fallback. Startup reports an actionable error if the required OpenGL capabilities are missing.
What works
- ACE login, character selection, world entry, chat, client commands, reconnect, and graceful logout.
- Outdoor, building, cellar, and dungeon streaming with prepared terrain, scenery, buildings, EnvCells, collision, portal visibility, sky, fog, lighting, audio, and day/night presentation.
- Local and observed movement, animation, jumping, selection, radar, combat stances, melee, bows, crossbows, spell projectiles, death, corpses, chests, and looting.
- Inventory bags, stable server ordering, stack splitting, ground drops, paperdoll equipment, weapon switching, quick bars, item use, cooldowns, and giving items to NPCs.
- Retail-style retained UI for vitals, chat, toolbar, inventory, character, attributes, skills, spellbook, components, effects, combat/spell/jump bars, radar/compass, dialogs, external containers, and assessment.
- Complete end-of-retail spell catalog, learned and favorite spells, component preflight, connected casts, enchantments, DAT-driven projectiles and effects, recall, portal-space travel, Hidden/UnHide, and remote materialization.
- One presentation-independent runtime owner for session, entities, objects, inventory, character state, selection, interactions, combat, magic, movement, physics, projectiles, world environment, and portal transit.
- A no-window Windows/Linux host with deterministic bot commands/events, shared immutable content, multi-session scheduling, isolation, reconnect, resource telemetry, and tested 1/5/10/30-session ownership.
- Plugin loading, shared command/input abstractions, retained markup panels,
and permanent ImGui developer tools behind
ACDREAM_DEVTOOLS=1.
Current boundaries
- The active M4 prelude is world interaction completion. Slices 1–3, including assessment and its final formula/icon/layout correction, are user-accepted. Equipped-child picking and vendor browse/buy/sell are the next uncompleted slices.
- Issue
#225retains the lifestone/particle shared-alpha visual comparison. Its connected lifetime and performance routes already pass. - Narrow carried behaviour debt includes issue
#153(an unstreamed far-teleport edge), issue#116(slide feel), issue#235(30 Hz capped/RDP jump presentation), and the live temporary-stopgap rows in the retail divergence register. - Native Linux graphics are deferred. L0 portability and L1 backend/capability
reporting are implemented; WSLg reaches the GPU through Mesa D3D12 but does
not expose mandatory
GL_ARB_bindless_texture. Resume with a supported physical Linux AMD/NVIDIA driver before beginning later Slice L work. - Advanced vendor/trade/crafting/social surfaces and larger M4 quest, character-creation, and emote bodies remain roadmap work.
Prerequisites
- .NET 10 SDK
- Your own retail Asheron's Call DAT directory containing:
client_portal.datclient_cell_1.datclient_highres.datclient_local_English.dat
- A machine-local
acdream.pakbuilt from those DATs - A running ACE server for connected play; the examples use
127.0.0.1:9000 - For the graphical client, a driver exposing the mandatory Vulkan capabilities validated at startup
The project does not distribute Microsoft/Turbine DAT files or derived prepared packages.
Build and test
dotnet restore AcDream.slnx
dotnet build AcDream.slnx -c Release
dotnet test AcDream.slnx -c Release --no-build
The current CI-filtered Windows baseline is a successful Release build with 16,151 passing tests and zero failures; opt-in live, installed-DAT, prepared-package, manual, timing, and platform-specific lanes run separately.
Prepare content
Production rendering and collision use the validated prepared package rather than decoding world meshes on the frame path:
dotnet run --project src\AcDream.Bake\AcDream.Bake.csproj -c Release -- `
--dat-dir "C:\Games\Asheron's Call" `
--out "C:\Games\Asheron's Call\acdream.pak"
A complete format-2 package from the standard installed DAT set is about
570 MiB (the former format-1 package was about 30 GB). It is machine-local and
must not be committed. ACDREAM_PAK_PATH overrides the default
<DAT directory>\acdream.pak.
Run the graphical client
$env:ACDREAM_DAT_DIR = "C:\Games\Asheron's Call"
$env:ACDREAM_PAK_PATH = "C:\Games\Asheron's Call\acdream.pak"
$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 Release
The DAT directory can instead be supplied as the first positional argument:
dotnet run --project src\AcDream.App\AcDream.App.csproj -c Release -- `
"C:\Games\Asheron's Call"
Run a headless session
AcDream.Headless loads no App, UI, OpenGL, native-window, or audio assembly.
Create a version-1 configuration such as bot.json:
{
"version": 1,
"process": {
"content": {
"datDirectory": "/opt/ac",
"preparedAssetPath": "/opt/ac/acdream.pak"
}
},
"sessions": [
{
"id": "bot-1",
"endpoint": { "host": "127.0.0.1", "port": 9000 },
"account": "testaccount",
"character": { "index": 0 },
"policy": { "id": "idle" },
"credential": {
"provider": "environment",
"reference": "ACDREAM_BOT_PASSWORD"
}
}
]
}
Then validate and run it:
export ACDREAM_BOT_PASSWORD='testpassword'
dotnet run --project src/AcDream.Headless/AcDream.Headless.csproj -c Release -- \
validate --config bot.json
dotnet run --project src/AcDream.Headless/AcDream.Headless.csproj -c Release -- \
run --config bot.json
For a single local session, run also accepts
--user <account> --password <password>. Add uniquely identified session
entries and credential references for a multi-session process. Available
built-in policies are idle, lifecycle-smoke, observer-movement, and
portal-route-smoke.
Useful startup options
| Variable | Effect |
|---|---|
ACDREAM_DAT_DIR |
Retail DAT directory |
ACDREAM_PAK_PATH |
Prepared package path; defaults to <DAT dir>/acdream.pak |
ACDREAM_LIVE=1 |
Enable connected mode |
ACDREAM_TEST_HOST / ACDREAM_TEST_PORT |
ACE endpoint |
ACDREAM_TEST_USER / ACDREAM_TEST_PASS |
Graphical-client credentials |
ACDREAM_RETAIL_UI=0 |
Disable the retained retail gameplay UI for diagnostics; it is enabled by default |
ACDREAM_DEVTOOLS=1 |
Enable ImGui developer tools |
ACDREAM_NO_AUDIO=1 |
Suppress OpenAL initialization |
ACDREAM_UNCAPPED_RENDER=1 |
Disable normal frame pacing for diagnostics |
ACDREAM_DISPLAY_PROTOCOL=auto|x11|wayland |
Select the Linux GLFW backend |
ACDREAM_DAY_GROUP=N |
Force a day-group index for weather/lighting comparisons |
ACDREAM_STREAM_RADIUS=N |
Legacy override over configured streaming radii |
ACDREAM_DUMP_SKY=1 |
Dump sky interpolation and draw diagnostics |
ACDREAM_DUMP_MOTION=1 |
Dump inbound movement and motion-cycle decisions |
Additional diagnostic and budget controls are documented beside their typed owners and in the linked research plans; they are not stable user settings.
Repository layout
src/
AcDream.Runtime/ presentation-independent GameRuntime
AcDream.App/ graphical host, retained UI, renderer, audio
AcDream.Headless/ Windows/Linux no-window multi-session host
AcDream.Core/ retail gameplay, movement, physics, world logic
AcDream.Core.Net/ UDP, ISAAC, protocol and message routing
AcDream.Content/ GL-free DAT and prepared-package content
AcDream.Bake/ offline acdream.pak builder
AcDream.Cli/ offline DAT inspector
AcDream.UI.Abstractions/ shared UI/input models and contracts
AcDream.UI.ImGui/ developer-tool presentation
AcDream.Plugin.Abstractions/ BCL-only plugin contracts
AcDream.Plugins.Smoke/ example plugin
tests/
AcDream.*.Tests/ layer-matched xUnit projects
docs/
README.md documentation authority and current map
architecture/ ownership, structure, divergence, WB inventory
plans/ milestone, roadmap, and execution plans
research/ retail pseudocode, traces, fixtures, evidence
audit/ completion and conformance audits
memory/ durable engineering references
references/ gitignored external reference repositories
Development workflow
All AC-specific behaviour starts from the named retail oracle in
docs/research/named-retail/:
- Search the named retail pseudo-C and headers by
class::method. - Use the older Ghidra chunks only when the named oracle is insufficient.
- Cross-reference ACE and the relevant client/viewer implementation.
- Record readable pseudocode and exact constants/order.
- Port the retail mechanism into the correct modern owner.
- Add conformance, lifecycle, and failure-boundary tests.
- Run the automated gate and the appropriate connected or visual gate.
- Update architecture, roadmap, divergences, and durable memory with the same change.
Guessing at AC-specific algorithms is forbidden. See AGENTS.md, CLAUDE.md, and the architecture guide for the full rules.
Reference projects
- ACE / ACEmulator: authoritative server and protocol behaviour
- ACViewer: character appearance and DAT presentation cross-check
- WorldBuilder: extracted Silk.NET DAT/rendering foundation
- Chorizite.ACProtocol: clean-room protocol reference
- holtburger: broad non-retail client behaviour reference
- AC2D: terrain and movement-packet cross-checks
The retail binary/decomp remains the behavioural oracle when references disagree.
Licence and game assets
The acdream source has not yet been assigned a top-level licence and is not ready for public redistribution. External reference code retains its own licence.
Asheron's Call DAT files, art, names, and other game assets remain the property of Microsoft/Turbine. This repository does not distribute them; users must supply their own retail installation.