diff --git a/README.md b/README.md index 9c786a69a..dfd73d6c5 100644 --- a/README.md +++ b/README.md @@ -60,6 +60,13 @@ As a result of lessons learned, we then focused on the economy system, and built At the moment we are focused on implementing and polishing the ARPG gameplay as a standalone title, first as a rogue-lite combat demo and then adding a story-driven campaign mode. +## Developer Navigation + +The repo is currently in a major typed-state migration. Before making runtime +changes, read [docs/developer-navigation.md](docs/developer-navigation.md) for +the current project map, command list, migration rules, and where the new +Unity/daemon/Electron boundaries live. + ## Architecture ### Project Structure diff --git a/docs/developer-navigation.md b/docs/developer-navigation.md new file mode 100644 index 000000000..771dfcf58 --- /dev/null +++ b/docs/developer-navigation.md @@ -0,0 +1,503 @@ +# Aetheria Developer Navigation + +Date: 2026-06-25 + +This is the handoff map for working in the post-migration Aetheria tree. It is +written for someone who already knows original Aetheria and needs to understand +what changed, where the new seams are, and how to keep moving without being +ambushed by half-finished architecture. + +The short version: Unity is being reduced to a renderer, input surface, and +editor environment. Durable game state and portable gameplay facts now live in +typed CultCache/CultNet/CultMesh records under `Aetheria.State`. The daemon is +the simulation owner. Unity and the Electron RTS client are clients of the same +typed Verse state. + +## Start Here + +Read these in this order: + +1. `docs/developer-navigation.md` + You are here. This is the repo map and daily working guide. +2. `docs/aetheria-current-codebase-model.md` + Control-flow model of the codebase before the latest Stage 7 work. Some + names have moved, but it is still the best broad map. +3. `Aetheria.State/docs/stage-7-thin-client-staged-implementation-plan.md` + The staged migration plan. Use this when deciding what to build next. +4. `Aetheria.State/docs/stage-7-client-surface-inventory.md` + Surface inventory and edit queue for Unity/Electron/client boundaries. +5. `docs/aetheria-verse-client-contract.md` + Intended client contract: use typed Verse state, not daemon internals. +6. `Aetheria.State/docs/verse-authority-implementation-plan.md` + Authority and Starbridge staged implementation map. + +Longer background/reference docs: + +- `docs/aetheria-perfect-machine-map.md` +- `Aetheria.State/docs/verse-daemon-shape.md` +- `Aetheria.State/docs/verse-authority-policy.md` +- `Aetheria.State/docs/cultmesh-cross-runtime-primitives.md` +- `Aetheria.State/docs/cultmesh-ergonomics-staged-migration-plan.md` +- `Aetheria.State/docs/daemon-code-map-for-rust-port.md` +- `Aetheria.State/docs/rust-rebuild-freeze-checklist.md` + +## What Changed + +Original Aetheria had a lot of live gameplay state flowing through Unity object +graphs: `ActionGameManager`, `Zone`, `Entity`, behavior instances, Unity UI +panels, save files, catalog DTOs, and renderer caches all knew more than they +should. + +The current migration is moving toward this shape: + +```text +client input + -> typed client facade + -> typed command document + -> local Verse node + -> daemon command gate + -> simulation + -> typed daemon frame/fact documents + -> local Verse replica + -> typed projection or native SoA view + -> Unity/Electron rendering and UI +``` + +The important shift is not "Unity talks to a daemon over a side channel." The +important shift is "every runtime is a CultMesh participant reading and writing +typed Verse state." + +## Main Projects + +`Aetheria.State` + +Durable typed state and shared runtime contract. This is the center of the new +world. It owns document types, schema registration, state mapping, Eve command +bridges, provider advertisement, player settings, loadout templates, trade +policy, Verse target state, and several projection helpers. + +`Aetheria.State.Daemon` + +The local daemon process. It opens the state node, starts CultMesh, accepts Eve +and daemon command documents, ticks the authoritative run state, and republishes +daemon frame/SoA/health/provider/surface records. + +`Packages/org.gamecult.aetheria.state/Runtime` + +The Unity-embeddable runtime state package. Unity, tests, daemon, and Electron +binding generation all depend on this contract. This package contains the +shared C# client facade (`AetheriaClient`, `AetheriaControl`, `AetheriaUi`), +daemon command documents, RTS/current-entity projections, Starbridge documents, +authority policy, SoA documents, Eve surface builders, and runtime catalog +snapshots. + +`Assets/Scripts` + +Unity client, legacy simulation shell, UI, renderer, and migration adapters. +This is no longer supposed to be the source of portable gameplay truth. Much of +it still exists as a presentation adapter over old object shapes while the +daemon contract fills in. + +`Aetheria.Rts.Web` + +Electron RTS client. It is intentionally thin: browser UI plus Electron +CultMesh/Verse access, local projection reads, and typed operation helpers. +Generated TypeScript bindings live in +`Aetheria.Rts.Web/Electron/aetheria-rts-generated-bindings.ts` and are derived +from C# `[Key]` declarations. + +`Aetheria.State.Verify` + +The fence. If a migration rule matters, this project should enforce it. +Whenever you delete a bad path or promote a new typed surface, add a verifier +assertion so the old path does not grow back. + +`Aetheria.State.AuthoritySmoke` + +Smoke coverage for authority/session behavior. This is a good "does the +co-op/authority spine still breathe?" check. + +`Aetheria.State.Freeze` + +Documentation/freeze support for the C# API/Rust-port discussion. The Rust +rebuild is shelved for MVP purposes, but the mapping is useful context. + +## Daily Commands + +Run these from repo root unless noted. + +Core verifier: + +```powershell +dotnet run --project .\Aetheria.State.Verify\Aetheria.State.Verify.csproj +``` + +Unity/runtime compile: + +```powershell +dotnet build .\GameCult.Aetheria.State.Unity.csproj --no-restore -v:minimal +``` + +Replica compile: + +```powershell +dotnet build .\Aetheria.State.Replica\Aetheria.State.Replica.csproj --no-restore -v:minimal +``` + +Authority smoke: + +```powershell +dotnet run --project .\Aetheria.State.AuthoritySmoke\Aetheria.State.AuthoritySmoke.csproj +``` + +Stage 7 Unity parity: + +```powershell +.\Aetheria.State\scripts\verify-stage7d-unity-parity.ps1 +``` + +RTS/Electron contract checks: + +```powershell +cd .\Aetheria.Rts.Web +npm run check:rts-bindings +npm run verify:stage7c:electron +``` + +Regenerate RTS bindings after changing C# `[MessagePackObject]` or `[Key]` +contracts consumed by Electron: + +```powershell +cd .\Aetheria.Rts.Web +npm run generate:rts-bindings +``` + +Expected recurring warnings: + +- `System.Numerics.Vectors` version conflict from Unity/Brokkr reference + overlap. This is noisy but currently non-fatal. +- Nullable warnings in some runtime surface builders. They are not new proof of + failure unless they become errors or touch code you are actively changing. + +## Current Mental Model + +### State Owner + +Typed CultCache/CultNet/CultMesh documents are the state owner. The primary +world file is: + +```text +GameData/aetheria-world.cc +``` + +Local client target state also exists so Unity can resolve which Verse to open. +Do not resurrect ad-hoc local files for gameplay state, loadouts, player +settings, command ports, or viewport payload passing. + +### Daemon Owner + +`Aetheria.State.Daemon/Program.cs` is the process entry. The important runtime +tick boundary is in: + +```text +Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeDaemonTickRunner.cs +``` + +Command application is in: + +```text +Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeDaemonOperations.cs +``` + +### Client Facade + +Use `AetheriaClient` first: + +```text +Packages/org.gamecult.aetheria.state/Runtime/AetheriaClient.cs +``` + +It exposes named reads such as current entity, current docking, station/refit, +sector map, viewport, Starbridge summary, health, authority policy, and SoA +views. It also exposes typed controls through `AetheriaControl` and typed UI +surface helpers through `AetheriaUi`. + +If a Unity panel or Electron surface needs a fact, prefer adding or extending a +named facade read. Avoid handing callers raw daemon frames unless the caller is +a transitional projection layer. + +### Unity Shell + +Unity should do: + +- input capture; +- camera and presentation; +- UI lowering; +- local view caches; +- Burst/DOTS/native rendering eventually; +- editor affordances. + +Unity should not do: + +- portable gameplay authority; +- server-authoritative simulation ticks; +- trade pricing truth; +- persistent loadout/player settings truth; +- stringly public command APIs; +- ad-hoc queues or buses as gameplay boundaries; +- Unity physics authority. + +`ActionGameManager` is now a shell and compatibility adapter. It is still big, +but it is no longer the place to add new portable gameplay state. + +### Electron RTS Client + +The RTS client should have the same shape as Unity: + +- local typed Verse/CultMesh access; +- typed viewport/object/gravity/current selection reads; +- typed command operations; +- no bespoke gameplay rules except UI presentation and input behavior. + +Do not add gameplay-only truth to `Aetheria.Rts.Web/Client/app.ts`. If it looks +like a simulation rule, it belongs in the daemon/state layer. + +## Important Files By Task + +Add or inspect a typed runtime document: + +- `Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeDaemonDocuments.cs` +- `Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeSnapshotDocuments.cs` +- `Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeRtsViewportDocuments.cs` +- `Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeStarbridgeDocuments.cs` +- `Aetheria.State/AetheriaDocumentRegistry.cs` +- `Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeVerseClient.cs` + +Add or inspect a daemon command: + +- `Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeDaemonDocuments.cs` +- `Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeDaemonOperationClient.cs` +- `Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeDaemonOperationsClient.cs` +- `Packages/org.gamecult.aetheria.state/Runtime/AetheriaControl.cs` +- `Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeDaemonOperations.cs` +- `Aetheria.State.Verify/Program.cs` + +Add a client projection: + +- `Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeRtsProjection.cs` +- `Packages/org.gamecult.aetheria.state/Runtime/AetheriaClient.cs` +- `Aetheria.Rts.Web/Electron/aetheria-rts-local-projection.ts` +- `Aetheria.Rts.Web/Electron/aetheria-rts-generated-bindings.ts` +- `Aetheria.State.Verify/Program.cs` + +Work on Unity thin-client migration: + +- `Assets/Scripts/Gameplay/AetheriaDaemonObserver.cs` +- `Assets/Scripts/Gameplay/AetheriaUnityGameplayBootShell.cs` +- `Assets/Scripts/Gameplay/AetheriaUnityGameplayInputShell.cs` +- `Assets/Scripts/Gameplay/AetheriaUnityObservedFrameApplier.cs` +- `Assets/Scripts/Gameplay/AetheriaUnityObservedFacadeProjector.cs` +- `Assets/Scripts/Gameplay/AetheriaUnityCurrentEntityBinder.cs` +- `Assets/Scripts/Gameplay/AetheriaUnityTargetPresentation.cs` +- `Assets/Scripts/UI/Menu/*.cs` +- `Assets/Scripts/UI/HUD/SchematicDisplay.cs` +- `Assets/Scripts/Zone Display/ZoneRenderer.cs` + +Work on Eve/CultUI surfaces: + +- `Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeEveSurfaceState.cs` +- `Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeEveSurfaceAdapter.cs` +- `Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeEveCommandClient.cs` +- `Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntime*SurfaceBuilder.cs` +- `Packages/org.gamecult.aetheria.eve-runtime/Runtime/AetheriaEveSurfacePresenter.cs` +- `Packages/org.gamecult.aetheria.eve-runtime/Runtime/AetheriaEveUnitySurfaceHost.cs` + +Work on RTS/Electron: + +- `Aetheria.Rts.Web/Client/app.ts` +- `Aetheria.Rts.Web/Client/aetheria-rts-contract.ts` +- `Aetheria.Rts.Web/Electron/main.ts` +- `Aetheria.Rts.Web/Electron/preload.cjs` +- `Aetheria.Rts.Web/Electron/aetheria-cultmesh.ts` +- `Aetheria.Rts.Web/Electron/aetheria-rts-bindings.ts` +- `Aetheria.Rts.Web/Electron/aetheria-rts-local-projection.ts` +- `Aetheria.Rts.Web/scripts/generate-rts-bindings.mjs` + +Work on native/SoA render path: + +- `Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeDaemonSoaDocuments.cs` +- `Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeDaemonSoaFramePublisher.cs` +- `Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeDaemonSoaViewIndex.cs` +- `Assets/Scripts/Gameplay/AetheriaDaemonRenderNativeView.cs` +- `Assets/Scripts/Gameplay/AetheriaDaemonRenderBuffer.cs` +- `Assets/Scripts/Gameplay/AetheriaDaemonRenderMatrixJob.cs` +- `Assets/Scripts/Gameplay/AetheriaDaemonRenderGroupMatrixJob.cs` + +Work on Ymir/physics: + +- `Assets/Scripts/Gameplay/Physics/AetheriaYmirPhysicsBridge.cs` +- `Assets/Scripts/Gameplay/Weapons/*Manager.cs` +- `Assets/Scripts/Gameplay/Weapons/*Projectile*.cs` +- CultMath/Ymir code may live outside this repo; verify paths before editing. + +## Migration Rules + +1. Public client APIs must be typed. + No public `Apply(command, payload)`, string command names, or raw payload + dictionaries. + +2. If Unity needs a gameplay fact, ask whether Electron/RTS would need the same + fact. + If yes, promote it into `Aetheria.State` and read it through `AetheriaClient`. + +3. If a fact is needed every frame, prefer a typed projection or SoA/native view. + Do not make Unity crawl a whole daemon frame in a hot path unless the code is + explicitly transitional and fenced by the verifier. + +4. Add verifier coverage when deleting or replacing authority paths. + `Aetheria.State.Verify` and `verify-stage7d-unity-parity.ps1` are not busy + work; they are the migration memory. + +5. Keep Electron thin. + RTS UI may select, display, and submit typed operations. It should not invent + enemy AI, movement rules, trade rules, station rules, or combat rules. + +6. Keep Unity honest. + Unity may adapt old facade objects for presentation until Stage 8 finishes, + but new state truth belongs in typed documents. + +7. Do not preserve legacy shape for its own sake. + Git preserves history. The migration should delete dead shims when the typed + replacement exists and tests prove it. + +## Known Transitional Debt + +These are not surprises; they are known pressure points. + +- `ActionGameManager` still exists and is still too large. It has been reduced, + but it remains a compatibility shell around input, scene wiring, and legacy + presentation. +- Unity `Entity`, `Zone`, and behavior objects still exist as presentation and + compatibility adapters. Do not treat them as the final state authority. +- `ZoneRenderer` still has persistent presentation caches. Stage 8 should keep + crushing it down toward per-frame query/native rendering. +- Some command bodies are still a broad typed union document selected by + `AetheriaRuntimeDaemonCommandKinds`. This is typed at the document boundary, + but not as elegant as distinct operation bodies. +- Some TypeScript generated binding metadata covers document slots better than + nested ergonomic decode helpers. After C# contract changes, regenerate and + check bindings. +- The C# daemon is still the MVP path. The Rust rebuild notes are context, not + the current target. +- Physics is supposed to move to Ymir. Unity physics authority is forbidden, but + some Unity-side presentation/bridge code still exists. + +## How To Add A New Gameplay Surface + +Use this checklist before writing code: + +1. Name the owner. + Is this daemon state, client presentation, local input configuration, or + editor-only tooling? + +2. Define the typed shape. + Add or extend a MessagePack/CultNet document in the runtime package. Use + explicit `[Key]` slots and stable names. + +3. Add a facade read or operation. + Prefer `AetheriaClient`, `AetheriaControl`, or `AetheriaUi` over direct + low-level Verse calls in client code. + +4. Lower Unity and Electron through the same semantics. + Unity and RTS do not need identical UI, but they should observe the same + facts and submit the same operation when policy allows it. + +5. Add or update generated TS bindings. + Run `npm run generate:rts-bindings` from `Aetheria.Rts.Web` when contract + slots change. + +6. Fence the old path. + Add checks to `Aetheria.State.Verify/Program.cs` or the Stage 7 parity + script. + +7. Run the relevant gates. + At minimum: state verifier, Unity compile, parity script, and RTS binding + check when TS-visible contracts changed. + +## How To Find Things Fast + +Search for a typed schema: + +```powershell +rg -n "gamecult\.aetheria\..*\.v1|CultDocument|MessagePackObject" Aetheria.State Packages/org.gamecult.aetheria.state/Runtime +``` + +Search for Unity still touching manager/global state: + +```powershell +rg -n "ActionGameManager\.|RuntimeCatalog|RuntimePlayerSettings|TryGetObserved" Assets/Scripts -g "*.cs" +``` + +Search for stringly command smells: + +```powershell +rg -n "Apply\(command|payload|Dictionary facade -> client presentation +command document -> daemon apply -> projected result +``` + +If a path does not fit that shape, it is probably transitional debt or a bug. +