docs(render): V11 closeout — register, architecture, code structure, issues
Retires the GL framing from the documents that described a two-backend,
two-UI-stack client, and files what the deletion left behind.
Divergence register:
* AD-46 (anisotropic tap pattern in dense alpha scenery) is REFRAMED rather
than retired. Its substance survives -- distant foliage may read denser
than retail's -- but it was measured GL-vs-Vulkan, and with GL gone it is
a Vulkan-vs-retail question against the D3D oracle it already cited. The
measurement is kept as the evidence that the residual is a driver tap
pattern; the row now records that it is no longer falsifiable by
self-differential, which is a real loss the deletion causes.
* AD-47 and AD-48 are NEW, and the campaign's own risk register scheduled
them here: MSAA sample positions (measured at 8.83% of the frame at 4x,
which is why every strict gate runs MSAA off -- and therefore why a
regression confined to the multisample path would not be caught) and
present pacing (#235 is the live instance).
* AD-17's justification moves from a GL clip-plane citation to Vulkan's
maxClipDistances floor, which is the same 8, so the divergence is
unchanged and only its authority moves.
* AP-92 keeps IUiViewportRenderer.TextureIsBottomUp rather than folding it
flat, because it is what let the origin question be answered by data.
Architecture and code structure: the layer diagram, the frame order, the
residency vocabulary and the reference table all said OpenGL. The UI section
said two stacks. Rule 3's rationale is rewritten around what actually
happened -- ImGui was deleted and not one panel, ViewModel or command had to
change, because none of them had ever imported ImGuiNET. That is the rule
paying for itself, so it is recorded as evidence rather than removed as
obsolete.
Issues: #258 files the dev-panel host as a decision rather than an accident,
and #255 is REOPENED. Its TaskCreationOptions.LongRunning fix asks the
scheduler for a thread but does not promise two callbacks overlap; under nine
concurrent test assemblies it still failed 2 of 5 whole-suite runs. The
earlier evidence tested a narrower pool, not a contended one. The fix it
needs is a rendezvous inside the read stub -- not a weakened assertion.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
5852bdb877
commit
c265b52d4b
5 changed files with 143 additions and 62 deletions
|
|
@ -6,7 +6,7 @@ A modern C# .NET 10 Asheron's Call client that:
|
|||
- **Behaves identically to the retail client** — same physics, same
|
||||
animations, same terrain, same collision, same network protocol
|
||||
- **Looks identical to the retail client** — same meshes, same textures,
|
||||
same lighting, same blending, rendered via modern Silk.NET OpenGL
|
||||
same lighting, same blending, rendered via modern Silk.NET Vulkan
|
||||
- **Adds a plugin API** the retail client never had — native C# plugins
|
||||
+ Lua macro scripting for player automation
|
||||
- **Is NOT a 1:1 C++ port** — uses modern C# patterns (composition over
|
||||
|
|
@ -64,7 +64,7 @@ well-defined interfaces that the retail client never had.
|
|||
│ ► wire-format identical to retail │
|
||||
├──────────────────────────────────────────────────────────────┤
|
||||
│ LAYER 1: Renderer │
|
||||
│ Silk.NET OpenGL 4.3 core profile │
|
||||
│ Silk.NET Vulkan 1.3 (the only backend since Campaign V V11) │
|
||||
│ TerrainModernRenderer, WbDrawDispatcher, EnvCellRenderer │
|
||||
│ Shaders (terrain blending, mesh lighting, translucency) │
|
||||
│ ► completely different from retail (D3D7), same visual │
|
||||
|
|
@ -79,28 +79,35 @@ well-defined interfaces that the retail client never had.
|
|||
### UI Architecture (two coexisting presentation stacks)
|
||||
|
||||
The 2026-04-24 design began with a swappable renderer abstraction. D.2b proved
|
||||
that retail fidelity needs a retained LayoutDesc/DAT tree, while ImGui remains
|
||||
valuable as permanent devtools. The current architecture therefore has two
|
||||
presentation stacks over shared state, ViewModels, events, and commands. Full
|
||||
history and the corrected contract live in
|
||||
that retail fidelity needs a retained LayoutDesc/DAT tree, and for most of the
|
||||
project's life ImGui coexisted beside it as permanent devtools. **Campaign V
|
||||
slice V11 ended that (2026-07-29):** ImGui was a GL-only frontend, the campaign
|
||||
did not port it, and deleting OpenGL deleted it. There is now **one** presentation
|
||||
stack. Full history and the corrected contract live in
|
||||
`docs/plans/2026-04-24-ui-framework.md`.
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ DEVELOPER UI │
|
||||
│ IPanel/IPanelRenderer → permanent ImGui devtools │
|
||||
│ GAMEPLAY UI │
|
||||
│ GAMEPLAY UI (the only stack) │
|
||||
│ LayoutDesc/DAT → UiRoot retained widgets + controllers │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ SHARED CONTRACTS │
|
||||
│ ViewModels, commands, input actions, state/event services │
|
||||
│ ► one model and mutation path, two presentation projections│
|
||||
│ ► one model and mutation path, one presentation projection │
|
||||
├─────────────────────────────────────────────────────────────┤
|
||||
│ Game state + events (unchanged) │
|
||||
│ IGameState / IEvents / WorldSession — UI only reads │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
`AcDream.UI.Abstractions` — the `IPanel`/`IPanelRenderer` contract, the
|
||||
ViewModels and the commands — **survives intact**. It was always
|
||||
backend-agnostic, which is exactly what Code Structure Rule 3 was written to
|
||||
protect, and it is what a future developer-panel host would bind to. Only the
|
||||
ImGui *backend* was deleted. `ACDREAM_DEVTOOLS=1` still selects Vulkan's
|
||||
debug-utils extensions and now logs that the developer UI is gone; replacing it
|
||||
is issue **#258**, deliberately unscheduled.
|
||||
|
||||
`AcDream.UI.Abstractions` owns backend-neutral ViewModels, commands, input,
|
||||
and the `IPanel`/`IPanelRenderer` devtools contract. `AcDream.App/UI` owns the
|
||||
retained gameplay tree, LayoutDesc importer, window runtime, and panel
|
||||
|
|
@ -112,8 +119,8 @@ retail client command (`ExecuteClientCommandCmd`), an ACE-owned command
|
|||
handlers and controllers translate those intents to `WorldSession`; panels
|
||||
never inspect or construct wire messages.
|
||||
Plugins register retained gameplay markup through the BCL-only
|
||||
`AcDream.Plugin.Abstractions.IUiRegistry`; they do not import App or ImGui
|
||||
assemblies. Core `SelectionState` is the sole selected-object owner for world,
|
||||
`AcDream.Plugin.Abstractions.IUiRegistry`; they do not import App or
|
||||
presentation assemblies. Core `SelectionState` is the sole selected-object owner for world,
|
||||
radar, inventory, paperdoll, toolbar, use/examine consumers, and plugins;
|
||||
`IPluginHost.Selection` exposes that same state and retail-style old/new callback.
|
||||
Temporary pointer modes are separate App orchestration in `InteractionState` and
|
||||
|
|
@ -131,11 +138,11 @@ Every retained gameplay window has a typed `RetailWindowHandle` and at most one
|
|||
`IRetainedPanelController` lifecycle owner. Multi-controller windows use
|
||||
`RetainedPanelControllerGroup`; the manager disposes controllers exactly once in
|
||||
reverse ownership order. `UiHost` removes Silk device subscriptions first, then
|
||||
disposes the manager/controllers, then its GL renderer. `GameWindow.OnClosing`
|
||||
disposes the manager/controllers, then its renderer. `GameWindow.OnClosing`
|
||||
tears this runtime down before session and game-state sources.
|
||||
|
||||
`RetailUiRuntime` is the production composition boundary. `GameWindow` creates
|
||||
the GL/DAT resolvers and supplies focused state/action binding records in one
|
||||
the device/DAT resolvers and supplies focused state/action binding records in one
|
||||
mount call; the runtime owns all LayoutDesc imports, controller construction,
|
||||
window registration, plugin mounts, cursor feedback, layout persistence, and the
|
||||
retained tick/draw/restore/dispose paths. Panel-specific construction must not
|
||||
|
|
@ -166,7 +173,7 @@ parallel window-lifecycle map.
|
|||
|
||||
```
|
||||
src/
|
||||
AcDream.Core/ Layer 2-4: no GL, no Silk.NET, pure logic
|
||||
AcDream.Core/ Layer 2-4: no Vulkan, no Silk.NET, pure logic
|
||||
Physics/
|
||||
PhysicsBody.cs -> body state / integration foundation (done)
|
||||
CollisionPrimitives.cs -> retail primitive helpers (partial, active)
|
||||
|
|
@ -247,7 +254,7 @@ src/
|
|||
RuntimeGenerationReset.cs -> one retryable canonical-generation reset
|
||||
-> Slice J complete; graphical and no-window hosts share one GameRuntime
|
||||
-> may reference Core, Core.Net, Content, and Plugin.Abstractions only
|
||||
-> must never reference App, UI, Silk.NET, OpenAL, Arch, or ImGui
|
||||
-> must never reference App, UI, Silk.NET, OpenAL, or Arch
|
||||
|
||||
AcDream.Headless/ Linux/Windows no-window production host
|
||||
Program.cs -> CLI entry only
|
||||
|
|
@ -275,10 +282,10 @@ src/
|
|||
GraphicalWindowBackendSelection.cs -> immutable GLFW 3.4
|
||||
Win32/X11/Wayland selection and
|
||||
packaged-native preference
|
||||
GraphicalCapabilityRecord.cs -> pre-render platform/GL/audio/input
|
||||
capability report and startup guard
|
||||
GraphicalGlFunctionProbe.cs -> active modern-GL shader/MDI/SSBO/
|
||||
timer/FBO/persistent-buffer validation
|
||||
Gpu/Vk/VulkanCapabilityRecord.cs -> pre-render platform/device/audio/
|
||||
input capability report + startup gate
|
||||
Gpu/Vk/VulkanBringUpHost.cs -> active device/descriptor/pipeline/
|
||||
offscreen-readback validation
|
||||
GraphicalLegacyConfigurationMigrator.cs -> no-overwrite Windows
|
||||
LocalAppData migration
|
||||
Physics/
|
||||
|
|
@ -646,7 +653,7 @@ centralizing physical storage. `ResidencyManager` owns generation-safe logical
|
|||
asset identity, owner tokens, leases, immutable budgets, and aggregate
|
||||
accounting. Specialized render/content owners continue to own their mesh
|
||||
ranges, texture arrays, staging payloads, decoded animations/audio, and
|
||||
retained shared-alpha scratch. The manager never sees a GL name: policy runs as
|
||||
retained shared-alpha scratch. The manager never sees a device handle: policy runs as
|
||||
a single writer during update/resource maintenance, while logical eviction and
|
||||
fence-delayed physical release remain render-thread owner operations. Prepared
|
||||
package address space is reported separately from committed CPU bytes, and
|
||||
|
|
@ -732,13 +739,13 @@ every region visited:
|
|||
128 MiB respectively, with an 896 MiB physical ceiling that includes an
|
||||
in-progress migration and its retired predecessor.
|
||||
|
||||
OpenGL deletion and range/slot reuse are not synonymous with logical release.
|
||||
Vulkan object destruction and range/slot reuse are not synonymous with logical release.
|
||||
`GpuFrameFlightController` fences three frames in flight. Mesh-buffer stores,
|
||||
texture handles, atlas layers, terrain slots, and landblock render records enter
|
||||
retirement only after they are no longer publishable, and their physical ids are
|
||||
recycled only after the corresponding fence signals. Shutdown follows the same
|
||||
dependency order and remains retryable: UI/controllers and render registrations
|
||||
withdraw first, then owner leases and caches, then GL backing stores. This keeps
|
||||
withdraw first, then owner leases and caches, then device backing stores. This keeps
|
||||
drivers from reading freed memory without adding a portal-specific purge or a
|
||||
visual-distance reduction.
|
||||
|
||||
|
|
@ -770,9 +777,9 @@ the exact retail `Client::UseTime` order. See the completed Slice 6 ledger and
|
|||
`GameWindow.OnRender` likewise owns only one handoff to the shipped
|
||||
`RenderFrameOrchestrator`. Its frozen graph begins per-resource frames and
|
||||
render-thread uploads; draws world/PView and its two shared-alpha scopes;
|
||||
renders portal and paperdoll private viewports, retained gameplay UI, ImGui
|
||||
renders portal and paperdoll private viewports, retained gameplay UI,
|
||||
devtools, and screenshots; then closes the GPU-flight transaction in
|
||||
`finally`. Both UI stacks coexist in the same frame.
|
||||
`finally`. There is one UI stack: the retained tree.
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -849,7 +856,7 @@ exact reference identity and retry position, rejects stale generations, and
|
|||
executes every class through the same meter. The canonical reveal generation
|
||||
supplies one exact destination cell/radius reservation; the meter protects its
|
||||
configured share across time, completion admissions, retained CPU bytes,
|
||||
entity operations, requested GPU bytes, and GL-retirement admissions. A
|
||||
entity operations, requested GPU bytes, and device-retirement admissions. A
|
||||
completion retains the reveal generation that classified it, so a stale
|
||||
completion or teardown cannot consume or clear a replacement generation's
|
||||
reservation. Priority changes order and reserved share, never the global
|
||||
|
|
@ -866,7 +873,7 @@ readiness continue. Canonical live records remain retained until physical
|
|||
teardown converges, so quiescence neither reconstructs server identity nor
|
||||
invents Hidden/UnHide transitions. A shared-origin recenter atomically removes
|
||||
the complete old spatial generation and captures one exact receipt per
|
||||
landblock before the origin changes. Expensive script, physics, render, and GL
|
||||
landblock before the origin changes. Expensive script, physics, render, and GPU
|
||||
release then advances only from `StreamingController.Tick` through stable
|
||||
per-owner entity/stage cursors on the frame's one meter. Publication remains
|
||||
fenced only by an older receipt for the same canonical landblock; the active
|
||||
|
|
@ -944,7 +951,7 @@ rejects a stable checkpoint while any host acknowledgement remains.
|
|||
`FrameScreenshotController` performs the requested default-framebuffer readback
|
||||
after world and retained UI draw on the render thread. The external connected
|
||||
gate launches normal Release processes and observes these artifacts, but never
|
||||
mutates streaming, physics, GL, or entity state from a worker thread.
|
||||
mutates streaming, physics, GPU, or entity state from a worker thread.
|
||||
|
||||
### Teleport cell identity at the streaming boundary
|
||||
|
||||
|
|
@ -1077,7 +1084,7 @@ Current movement/collision ownership:
|
|||
fallback/transfer. `RuntimeSettingsController` is the sole settings
|
||||
persistence/current-state owner, supplies the immutable pre-window snapshot,
|
||||
applies startup pacing/display/FOV/audio once, and later borrows complete
|
||||
runtime targets without replay. Checked GL construction/state boundaries
|
||||
runtime targets without replay. Checked GPU construction/state boundaries
|
||||
retain exact cleanup obligations across failure. The executable nine-phase
|
||||
production pipeline and terminal session start are complete. Checkpoint J
|
||||
moves the exact shutdown dependency graph into `GameWindowLifetime`, whose
|
||||
|
|
@ -1127,7 +1134,7 @@ For acdream-specific code (renderer, plugin API, streaming):
|
|||
| Physics/collision | `docs/research/named-retail/` | ACE Physics/ + older decompiled chunks |
|
||||
| Animation | `docs/research/named-retail/` + ACE Animation/ | — |
|
||||
| Terrain | ACME ClientReference.cs | named retail / older decompiled chunks |
|
||||
| Rendering | WorldBuilder (Silk.NET) | ACViewer |
|
||||
| Rendering | WorldBuilder (Silk.NET; its GL calls now read as RHI intent) | ACViewer |
|
||||
| Protocol | holtburger | AC2D |
|
||||
| Server behavior | ACE | — |
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue