diff --git a/docs/cultcache-migration-cut.md b/docs/cultcache-migration-cut.md index 967f4b6b7..f27bde97d 100644 --- a/docs/cultcache-migration-cut.md +++ b/docs/cultcache-migration-cut.md @@ -95,7 +95,7 @@ recorded, none blocking: `WeaponData.AmmoType` refs. - One cache holds all three stores for the process. - `RunSave` commits a save atomically with stable zone keys and clears the run - on New Game or death. + on death or victory (`RunSave.Replace` drops the old run once a new one has staged). - `SavedRun`, the msgpack settings and layout I/O, `.loadout`, `SaveState`, `SaveZone` and the importer are deleted. - **Loadouts are authored ship presets in the catalog.** This was reworked @@ -138,9 +138,6 @@ The first Soul pass found untested all-or-nothing, availability and price rules, weapon-group corruption, dictionary-ordered product choice, and a premature "done". All are fixed. -Recorded, not fixed: New Game clears the previous run before generation, as the -spec says, so a generation fault loses that run. - `GameData/PlayerSettings.msgpack` entered history through `5c5c3d5e`. It holds defaults and the username, and about 65 earlier versions are already in LFS history, so history is left alone. @@ -651,7 +648,9 @@ After Cut 10, every runtime write is a single-store `Commit` on one cache that holds catalog, run and player stores from first access: - `RunSave.Commit` saves the run at wormhole arrival and quit, with stable `SavedZone` keys. -- `RunSave.Clear` deletes every run record at New Game and at death. +- `RunSave.Clear` deletes every run record at death and victory (`ActionGameManager.EndRun`). +- `RunSave.Replace` swaps the saved run for a new one only after the new run has + staged; a start that fails leaves the saved run in place. - The settings getter creates `PlayerSettings` on first launch, and `SavePlayerSettings` commits it. - `Loadouts.Save` writes loadouts to the player store, and @@ -849,7 +848,7 @@ reads a global back (Q4). | Global | Store | Read by | Existence owned by | Missing at main menu | Missing at resume | Missing at new game | |---|---|---|---|---|---|---| | `PlayerSettings` | Player | `MainMenu` (name, tutorial flag), `ActionGameManager` (credits) | boot: `ActionGameManager.Awake` after `AetheriaStores.Open`, when `GetGlobal()` is null, upserts one and flushes (Cut 10) | cannot happen after boot | same | same | -| `SavedGame` | Run | `MainMenu` (resume), `Galaxy(CultCache, SavedGame, ...)` | new game: `ActionGameManager.BeginRun()` creates the run store and writes it; `Die()` deletes the run store (Cut 10) | no run file: Resume hidden; run file without `SavedGame`: refuse to resume, log the key, New Game only | as main menu | new game deletes any run store first | +| `SavedGame` | Run | `MainMenu` (resume), `Galaxy(CultCache, SavedGame, ...)` | new run: `RunSave.Replace` writes the new run's records and removes the old run's once the scenario has staged; `EndRun` calls `RunSave.Clear` at death and victory | no run file: Continue disabled; run file without `SavedGame`: Continue disabled, log the key | as main menu | a new run keeps the saved run until it has staged | | catalog globals | Catalog | none exist | authored data; catalog is read-only | `AetheriaStores.Open` throws naming every `[CultGlobal]` type routed to the catalog with no record | same | same | **CultLib's role.** `[CultGlobal]` means exactly: at most one record of the @@ -1772,8 +1771,8 @@ Probes behind 8a (scratch copies; nothing committed): Math audit: - **Not used:** `float4x4`, `transpose`, `determinant`, `_11` names. The - `determinant` hits (`AetheriaMath.cs:98-112`, `NIH\MIConvexHull`) are locals - and comments; the `half` hits are locals. `float2x2`/`float3x3`, `int3`/`int4`, + `determinant` hits were locals and comments (in `AetheriaMath.cs` and the + vendored `NIH\MIConvexHull`, both since deleted); the `half` hits are locals. `float2x2`/`float3x3`, `int3`/`int4`, `double2`/`double3`, `quaternion.LookRotation`, `Random` and `snoise` all compile against CultMath. - **Accepted by Cut 6b:** `hash`, `normalize`, `Random`, `snoise` and NaN @@ -2596,28 +2595,31 @@ AetherDb and test edits made by Cut 9 (landed `70fbaca1`, recorded `e3af23fa`). - `SavedGame` global and `savedzone-{i}` records in `run.cc`. - `PlayerSettings` global in `player.cc`. - Orbit and body records in `run.cc`, written by zone generation and landed by the next save. - - **Run begins:** New Game calls `RunSave.Clear(CultCache)` as its first - statement (the `MainMenu.cs:110` handler), before the `Task.Run` at `:127` - or `:154`. - - Galaxy generation writes nothing. - - Zone generation (`PopulateLevel` `:615`, then `ZoneGenerator.cs:99, 108, - 200-201, 239, 253`) upserts orbits and bodies into the attached run store. - They stay staged until the next `RunSave.Commit`. + - **Run begins:** a scenario launch (`MainMenu.Launch`) generates the galaxy on a + background task and writes nothing to the run store. `StartGame` then calls + `StartScenario`, which runs arena generation, `PopulateLevel` and staging + inside `RunSave.Replace(CultCache, ...)`. The saved run's records are removed + only when staging succeeds; on failure the records the start wrote are removed + and the saved run stays. + - Zone generation (`PopulateLevel`, then `ZoneGenerator`) upserts orbits and + bodies into the attached run store. They stay staged until the next + `RunSave.Commit`, or are removed by `Replace` on a failed start. - **Run saves:** `ActionGameManager.SaveRun()`: - - It is `if (CurrentGalaxy != null) { var (game, zones) = RunSave.Capture(CultCache, CurrentGalaxy, Zone, DockedEntity ?? CurrentEntity, IsTutorial, _actionBarSlots.Select(s => s.Save()).ToArray()); RunSave.Commit(CultCache, game, zones); }`. + - It captures the live run (`RunSave.Capture`, which writes `SavedGame.IsTutorial` from `galaxy.IsPrelude`) and commits it with `RunSave.Commit` (`ActionGameManager.SaveRun`, `:284`). - Callers: wormhole arrival (`:605`) and `OnApplicationQuit() { SaveRun(); SavePlayerSettings(); }`. - - **Run ends:** `Die` replaces `SavePlayerSettings()` at `:1059` with - `RunSave.Clear(CultCache); SavePlayerSettings();`. - - `CurrentGalaxy` is already null (`:1058`), so a quit afterwards does not save a run. + - **Run ends:** `EndRun` (death and victory) nulls `CurrentGalaxy`, then calls + `RunSave.Clear(CultCache); SavePlayerSettings();` (`ActionGameManager.cs:1224-1232`). + - `CurrentGalaxy` is already null, so a quit afterwards does not save a run. - **Run exists:** derived only as `CultCache.GetGlobal() != null`. - `MainMenu.ShowMain` enables Continue from it. Continue sets - `IsTutorial = saved.IsTutorial` and - `CurrentGalaxy = new Galaxy(CultCache, saved, Debug.Log)`. - - `StartGame` (`:695-741`) reads it once at the top: `null` takes the - new-run branch; otherwise it resumes from `CurrentZone`, - `CurrentZoneEntity` and `ActionBarBindings` (`:722, 723, 737`). + `CurrentGalaxy = new Galaxy(CultCache, saved, Debug.Log)`, whose `IsPrelude` + comes from `saved.IsTutorial`. + - `StartGame` (`ActionGameManager.cs:820`) branches on `PendingScenario`: set + means a new run (`StartScenario`); otherwise it resumes from `CurrentZone`, + `CurrentZoneEntity` and `ActionBarBindings` of the saved run. - A run store that holds records but no `SavedGame` logs - `run store has no SavedGame; Continue disabled`. New Game clears it. + `run store has no SavedGame; Continue disabled`. The next scenario launch + replaces those records once it has staged. - **Player settings:** - The `ActionGameManager.PlayerSettings` getter returns `CultCache.GetGlobal()`. - When that is absent (first launch), the getter commits @@ -2651,7 +2653,7 @@ AetherDb and test edits made by Cut 9 (landed `70fbaca1`, recorded `e3af23fa`). - The cache never creates either. `AetheriaStores.Open` keeps its missing-global check catalog-only (`AetheriaStores.cs:24-29`). - **Derived state:** - "Run exists" is derived from the `SavedGame` global. - - `IsTutorial` is set from it on Continue and written back by `Capture`. + - `Galaxy.IsPrelude` is set from `SavedGame.IsTutorial` on Continue; `Capture` writes it back from `galaxy.IsPrelude`. No static copy exists. - `PlayerSettings.SavedRun` is deleted, not demoted. - **Forbidden writers:** - `File.*` I/O for game state anywhere in `Assets\Scripts`. @@ -2660,10 +2662,10 @@ AetherDb and test edits made by Cut 9 (landed `70fbaca1`, recorded `e3af23fa`). - A second `AetheriaStores.Open` in `Assets\Scripts`. - Any upsert of `SavedGame` or `SavedZone` outside `RunSave.Commit`. - **Shared paths:** - - Normal and tutorial New Game both call `Clear`. + - Every scenario launch goes through `RunSave.Replace`. - Continue and a new run's `StartGame` read the same global. - Wormhole and quit call `SaveRun`. - - Death calls `Clear`. + - Death and victory call `Clear` through `EndRun`. - **Deletion line:** `SavedRun`, `SaveState`, the msgpack settings and layout I/O, `SaveLoadout`, `SaveZone` and the `SavedGame` constructor go before `RunSave` lands. diff --git a/docs/headless-playground-cut.md b/docs/headless-playground-cut.md index bea30aa46..51c3f1bb5 100644 --- a/docs/headless-playground-cut.md +++ b/docs/headless-playground-cut.md @@ -10,6 +10,13 @@ probe was built with `--artifacts-path` in scratch, so this tree got no `bin`/`o writes. CultLib was a temporary detached worktree at `a0813c6`, since removed. The probe source is not kept; §2.8 records what it did. +Since this map, the new-run path moved: `MainMenu.Launch` starts a `Scenario` and +`ActionGameManager.StartScenario` replaces the saved run through `RunSave.Replace` +after `RunStart` stages it (`docs/scenarios-cut.md` R.9); the `IsTutorial` static is +gone (`Galaxy.IsPrelude` is the one owner) and `ItemManager` takes its seed in its +constructor. Passages below that name the old `MainMenu` new-game anchors or those +statics are rewritten to that path; the `Run` owner itself is still unbuilt. + ## 0. Target Operator, 2026-09-17: player inputs "map directly to the same entity inputs the AI @@ -107,11 +114,11 @@ All of this is Unity code: | Concern | Anchor | Unity dependencies | |---|---|---| | Store composition | `ActionGameManager.cs:43-63` (static, `Application.dataPath`) | path only | -| Handoff across scene load | statics `CurrentGalaxy`, `IsTutorial` (`:96-97`), written by `MainMenu.cs:104-105,126,138,152,166`, read by `SectorMap.cs:114-310` | `SceneManager.LoadScene` (`MainMenu.cs:106,139,167`) | -| New game: clear | `MainMenu.cs:112` | none | -| New game: galaxy | `MainMenu.cs:125,148` (`UnityEngine.Random.value` background noise), `:127-141,153-169` (`Task.Run`, then `Observable.NextFrame`) | Random, UniRx main-thread scheduler | -| ItemManager | `ActionGameManager.cs:264`; RNG clock-seeded at `ItemManager.cs:20` | `Debug.Log` | -| Start / Continue | `StartGame` `:725-770`: spawn player ship `:733-744`; Continue resolves the docked child `:751-762`; action bar restore `:764-767` | renderer binding, `SectorMap` reveal | +| Handoff across scene load | statics `CurrentGalaxy` and `PendingScenario` (`ActionGameManager.cs:108,113`), written by `MainMenu.Launch` and Continue, read by `SectorMap` | `SceneManager.LoadScene` (`MainMenu.EnterGame`, `MainMenu.cs:287`) | +| New game: replace | `ActionGameManager.StartScenario` (`:855-876`): `RunSave.Replace` drops the saved run only after the scenario stages; `MainMenu` clears nothing | none | +| New game: galaxy | `MainMenu.Launch` builds a `GalaxyStage` and runs `Task.Run(() => RunStart.Generate(scenario, stage))`, then `Observable.NextFrame`; background noise and galaxy draw from `GalaxyStage.Seed`, not `UnityEngine.Random` | UniRx main-thread scheduler | +| ItemManager | `ActionGameManager.cs:309`; seed is a constructor argument, `RunStart.ItemSeed(galaxy, step)` (`RunStart.cs:99`), reseeded by `RunStart.SeedItems` | `Debug.Log` | +| Start / Continue | `StartGame` (`:820`): `PendingScenario` set runs `StartScenario` (new run, player staged by `RunStart.Stage`); otherwise Continue resolves the saved zone and docked child and restores the action bar | renderer binding, `SectorMap` reveal | | Zone entry | `PopulateLevel` `:639-675`: generate/unpack `:643-654`; move pilot `:659-666` | `ZoneRenderer.LoadZone`, `Debug.Log` | | Wormhole placement (a game rule) | `ZoneRenderer.cs:222-231` (`dir * Pack.Radius * GameSettings.WormholeDistanceRatio`) | lives in a MonoBehaviour | | Warp | detect `ActionGameManager.cs:312-316`; `EnterWormhole` `:615-637`, which saves on arrival (`:635`) | `ZoneRenderer.WormholeInstances` as the wormhole list | @@ -146,7 +153,7 @@ All of this is Unity code: (`GameSettings.cs:17`, authored `LonginusX`) and `WormholeDistanceRatio` (`:23`, authored 0.75). - Randomness: - - `ItemManager.Random` is clock-seeded (`ItemManager.cs:20`). + - `ItemManager.Random` is seeded by the constructor argument (`ItemManager.cs:35`); a new run's seed is `RunStart.ItemSeed(galaxy, step)`, from `Galaxy.Seed`. - `Galaxy` is clock-seeded only when `seed == 0` (`Galaxy.cs:108,158`). - `Zone` seeds from the zone name (`Zone.cs:54`). - `Zone.Update` runs belt updates on `Task.Run` (`Zone.cs:144`). It is still @@ -243,7 +250,7 @@ Continue and death. There is one instance per run. It holds no Unity type. - `GameplaySettings`, `ZoneGenerationSettings`, `PlanetSettings`; - a `uint seed` for `ItemManager`; - `Action log`; - - for a new run, a caller-built `Galaxy` and `isTutorial`; + - for a new run, a caller-built `Galaxy` (`Galaxy.IsPrelude` says whether it is the prelude) and the staged start (`RunStart.Stage`); - `dt` per step; - commands from either lowering; - `SavedActionBarBinding[]` at save, owned by the Unity action bar (the playground @@ -305,10 +312,8 @@ Continue and death. There is one instance per run. It holds no Unity type. - `ActionGameManager`: bodies of `SaveRun`, `EnterWormhole`, `PopulateLevel`'s simulation half, `StartGame`, `Dock`, `DoDock`'s state half, `Undock`'s checks, `TowShip`, `Die`'s clear, and `IntroCutscene` (entirely); - - statics `CurrentGalaxy` and `IsTutorial`; - - `MainMenu.cs:104-105,112`; - - `ZoneRenderer.cs:222-231`'s wormhole construction; - - `ItemManager.cs:20`'s clock seed. + - statics `CurrentGalaxy` and `PendingScenario`; + - `ZoneRenderer.cs:222-231`'s wormhole construction. All of these go in the same cut that adds `Run`. None survives as a fallback. @@ -318,12 +323,12 @@ Unity dependencies, each injected or cut: |---|---|---| | `Time.deltaTime` | `:1218` | injected: `Run.Step(float dt)` | | `Time.time` | `IntroCutscene`, `Die` post-fx | cutscene deleted; post-fx stays in Unity, on `Died` | -| `UnityEngine.Random` | `MainMenu.cs:125,148` (background noise), `EntityInstance.cs:413-428` (loot) | noise stays in the menu as a galaxy-generation input; loot roll moves to `Zone` on `ItemManager.Random` (Cut 2); effect spread jitter (`ProjectileManager.cs:20-26`) stays visual | -| Clock RNG | `ItemManager.cs:20` | cut; the seed is a constructor argument, and Unity passes a clock-derived one | +| `UnityEngine.Random` | `EntityInstance.cs:413-428` (loot) | galaxy noise already draws from `GalaxyStage.Seed`; loot roll moves to `Zone` on `ItemManager.Random` (Cut 2); effect spread jitter (`ProjectileManager.cs:20-26`) stays visual | +| Clock RNG | `Scenario.Seed` of 0 (`GalaxyStage.SeedFrom`) | the clock seeds only the galaxy seed; every item stream derives from it through `RunStart.ItemSeed` | | Coroutines | `IntroCutscene` | deleted (dead) | | UniRx | `Observable.NextFrame` in the menu, `EveryUpdate` in `Die` | stay in Unity; `Run` uses C# events, and `Entity.Death` (UniRx, headless-compiled) is what `Run` subscribes to | | `Debug.Log` | `:264`, `:657`, `MainMenu` | injected `Action` | -| Scene load | `MainMenu` | stays; the handoff static becomes `ActionGameManager.NewRun : (Galaxy, bool)?`, command-only, consumed once in `Start`; null means Continue | +| Scene load | `MainMenu` | stays; the handoff static is `ActionGameManager.PendingScenario`, command-only, consumed once by `StartGame`; null means Continue | | MonoBehaviour state | `_currentEntity`, `DockedEntity`, `DockingBay`, `TowingStation`, `Zone`, `ItemManager` | projections of `Run` | | Barrel transforms | `EntityInstance.cs:516` -> `HardpointTransforms` | `HardpointTransforms` deleted (Cut 2); the arc is item rotation plus `FiringArc` (fork A); barrels and `ArticulationPoint` are presentation only, `GetBarrel` | | `Physics.*` hit queries | `Projectile`, `GuidedProjectile`, `Laser`, `Lightning`, `HullCollider` subjects | deleted from damage paths; `FireControl` rolls (Cut 2) | @@ -374,7 +379,7 @@ This is subtraction first, then one new file. - Deletes and moves: - `ActionGameManager.cs`: - `IntroCutscene` `:772-799` (dead). - - Statics `CurrentGalaxy` and `IsTutorial` (`:96-97`). + - Statics `CurrentGalaxy` and `PendingScenario` (`:108,113`). - `SaveRun` body `:243-248` becomes `Run?.Save(actionBar)`. Quit (`:236`) calls it. - `EnterWormhole` `:615-637` and the detect loop `:312-316` become `Run.TryEnterWormhole()`. `WarpArrived` drives `SectorMap.QueueZoneReveal`. @@ -393,14 +398,13 @@ This is subtraction first, then one new file. `Run.Died`. - `:264` constructs no `ItemManager`. - `Update` `:1218` becomes `Run.Step(Time.deltaTime)`. - - `MainMenu.cs`: - - Continue (`:102-107`) sets `ActionGameManager.NewRun = null` and loads the scene. - - New Game drops `:112` and sets `NewRun = (sector, tutorial)` at `:138,166`. + - `MainMenu`: already built. Continue (`ShowMain`) loads the scene with no + `PendingScenario`; `MainMenu.Launch` sets `PendingScenario` and clears nothing. - `SectorMap.cs:114-310` reads `ActionGameManager.Instance.Run.Galaxy`. - `InventoryPanel.cs:117-118` becomes `GameManager.Run.Board(ship)`. - `ZoneRenderer.cs:222-231` iterates `zone.Wormholes`. - - `ItemManager.cs:20`: the seed becomes a constructor argument. Call sites: 11 in - tests, 1 in `AetherDb`, and `Run`. + - `ItemManager`: the seed is already a constructor argument (`ItemManager.cs:35`); + `Run` supplies `RunStart.ItemSeed(galaxy, step)`. - Settings (fork S (a)): - `StartingHullName` and `WormholeDistanceRatio` move from `GameSettings.cs:17,23` to `GameplaySettings` (`Settings.cs:155`). @@ -412,8 +416,8 @@ This is subtraction first, then one new file. `GalaxyZone.AdjacentZones` with the rule from `ZoneRenderer.cs:226-230`. Null galaxy zone gives an empty array. - New `Run.cs`: types and rules, no bodies here. - - `static Run New(CultCache, GameplaySettings, ZoneGenerationSettings, PlanetSettings, Galaxy, bool isTutorial, uint seed, Action log)` - 1. `RunSave.Clear`. + - `static Run New(CultCache, GameplaySettings, ZoneGenerationSettings, PlanetSettings, Galaxy, Scenario, Action log)` + 1. `RunSave.Replace` around steps 2-5 (the saved run goes only once the scenario has staged). 2. `ItemManager` over `RunSave.Lots`, seeded. 3. `EnterZone(Entrance)`. 4. Spawn the player ship per `:734-743`. @@ -446,7 +450,7 @@ This is subtraction first, then one new file. child; updates `Bay.DockedShip`. - `void Tow()`: the rule from `:891-911`. - `void Save(SavedActionBarBinding[] actionBar)` - - `RunSave.Capture(cache, Galaxy, Zone, Station ?? Pilot, isTutorial, actionBar)`, + - `RunSave.Capture(cache, Galaxy, Zone, Station ?? Pilot, actionBar, credits)`, then `Commit(…, ItemManager.Lots)`. - No-op when `Ended`. - Remembers `actionBar` for warp saves. @@ -461,7 +465,7 @@ This is subtraction first, then one new file. | Test | Asserts | Mutation that must kill it | |---|---|---| -| `NewRunSpawnsPilotInEntrance` | pilot is a `Ship` with `IsPlayerShip`, in `Zone.Entities`, `Zone.GalaxyZone == Galaxy.Entrance`; the run store is cleared of a prior `SavedGame` | `New` skips `RunSave.Clear`; spawn omits `Zones.Entities.Add` | +| `NewRunSpawnsPilotInEntrance` | pilot is a `Ship` with `IsPlayerShip`, in `Zone.Entities`, `Zone.GalaxyZone == Galaxy.Entrance`; the run store holds no prior `SavedGame` once the run has staged | `New` skips `RunSave.Replace`; spawn omits `Zones.Entities.Add` | | `WarpMovesPilotAndSaves` | stepping after `TryEnterWormhole` lands the pilot in the target zone, out of the old zone's entities, with `SavedGame.CurrentZone` equal to the target index after reopen | arrival skips `Save`; `EnterZone` leaves the pilot in the old zone | | `ContinueLandsDocked` | save while docked, reopen, `Continue`: `Station` is the saved orbital, `Pilot` is its player child | `Land` binds to the orbital itself | | `DeathEndsAndClears` | hull death clears every run record; `Step` throws; `Save` writes nothing | `Died` handler omits `Clear`; `Ended` not set | @@ -473,7 +477,7 @@ This is subtraction first, then one new file. - Unity batchmode has no `error CS`. - Negative greps: - `rg -n "RunSave\.(Clear|Commit|Capture)" Assets/Scripts --glob '!ServerShared/**'` is empty. - - `rg -n "CurrentGalaxy|IsTutorial\s*=" Assets/Scripts` is empty. + - `rg -n "CurrentGalaxy|PendingScenario" Assets/Scripts` matches only the `Run` lowering in `ActionGameManager` and `MainMenu`. - `rg -n "new Wormhole" Assets/Scripts` matches only `Zone.cs`. - `rg -n "new ItemManager\(" Assets/Scripts` matches only `Run.cs`. - `rg -n "ZoneGenerator\.GenerateZone|new Zone\(" Assets/Scripts --glob '!ServerShared/**'` is empty. @@ -1161,7 +1165,7 @@ Options as mapped before the ruling: - **Recommend (a).** **N. Is the scene handoff static acceptable?** Low-blocking. -- (a) `ActionGameManager.NewRun : (Galaxy, bool)?`, consumed once by `Start`. +- (a) `ActionGameManager.PendingScenario : Scenario`, consumed once by `StartGame` (built this way). - (b) `MainMenu` builds the whole `Run` on its generation thread. That moves zone generation's run-store upserts off the main thread, and the `CultCache` threading contract is not checked here. diff --git a/docs/item-provenance-cut.md b/docs/item-provenance-cut.md index 473ec76c2..a0ccd947f 100644 --- a/docs/item-provenance-cut.md +++ b/docs/item-provenance-cut.md @@ -166,9 +166,9 @@ Contradictions and corrections found in the Body: `LoadoutTests` fixture is not: `FirstAvailableProductInKeyOrderBuildsTheSlot` (`LoadoutTests.cs:289-312`) adds two same-maker Lamp products and reads `.Product`. 6. **`ItemManager` lives one scene load, and every run starts with a scene load.** It is - constructed in `ActionGameManager.Start` (`:264`). There is one scene, `ARPG`. New Game - and Continue both end in `SceneManager.LoadScene("ARPG")` (`MainMenu.cs:106,139,167`), and - no `DontDestroyOnLoad` exists. So a ledger held by `ItemManager` spans exactly one run. + constructed in `ActionGameManager.Start` (`:309`). There is one scene, `ARPG`. A scenario + launch and Continue both end in `SceneManager.LoadScene("ARPG")` (`MainMenu.EnterGame`, + `:287`), and no `DontDestroyOnLoad` guards the `ItemManager`. So a ledger held by `ItemManager` spans exactly one run. 7. **Aside, not this cut:** `CreateInstance(CraftedItemData, float)` mints a `CompoundCommodity` for a `ConsumableItemData` design (`ItemManager.cs:136-141`), while `TryActivateConsumable` casts to `ConsumableItem` (`Entity.cs:336`). This map keeps @@ -252,9 +252,11 @@ Not probed: CultCache Studio's rendering of the ledger (operator check); Unity c `ZoneGenerator`'s staged-upsert pattern (`ZoneGenerator.cs:99-108`) is not used for lots: the ledger is live simulation state, captured at commit like entities. - Lifecycle: the run begins with a scene load (§1.6), whose `Start` reads - `RunSave.Lots(CultCache)`. New Game has already cleared the run store (`MainMenu.cs:112`), - so it gets an empty ledger. Continue gets the stored one. Death clears the run store - (`ActionGameManager.cs:1090`); the next run reloads the scene. + `RunSave.Lots(CultCache)`. A scenario launch has `PendingScenario` set, so `Start` builds an + empty `ProvenanceLedger` instead (`ActionGameManager.cs:312`); the saved run's records stay + in the store until `RunSave.Replace` drops them once the new run has staged + (`SavedGame.cs:247`). Continue reads the stored ledger. Death and victory end in `EndRun`, + which calls `RunSave.Clear` (`ActionGameManager.cs:1224-1231`); the next run reloads the scene. **Branding.** - Owner: `ItemManager.Brand(CraftedItemInstance)` -> `(Faction Maker, FactionProductData Product)`. @@ -526,7 +528,7 @@ Subtraction, plus a data rewrite. worktrees. Operator-only checks after Cut C: -- New Game and fly through one zone. The starting ship's items show tier colour, and the +- New Game, pick a scenario, and fly through one zone. The starting ship's items show tier colour, and the properties panel shows Manufacturer, product name and flavour text for branded gear. - Dock and buy an item: its brand still shows in your cargo. - Kill an NPC and pick up loot: brand shown. diff --git a/docs/item-provenance-substrate.md b/docs/item-provenance-substrate.md index 0bc310942..956d79138 100644 --- a/docs/item-provenance-substrate.md +++ b/docs/item-provenance-substrate.md @@ -68,8 +68,7 @@ catalog, built a 196-zone sector galaxy from the authored `Settings.asset`, and `47189c8a`). The commented `HaulingControllerData` union (`Behaviors.cs:179`) is the same kind of residue. - **No recipe, blueprint or ingredient model exists.** "Factory", "fabricat", - "assembler", "blueprint", "recipe" and "refiner" appear in no live C# outside - `NIH/MIConvexHull`. + "assembler", "blueprint", "recipe" and "refiner" appear in no live C#. `ItemData.Manufacturer` readers: `PropertiesPanel.cs:371-372` (shows "Manufacturer", falling back to "GameCult"), `tools/AetherDb/Program.cs:54` (census), and the @@ -83,7 +82,7 @@ All crafted instances come from three `ItemManager` overloads: - `CreateInstance(CraftedItemData, float quality)` (`ItemManager.cs:126-142`) sets Quality and Durability, with no product and no ingredients. - `CreateInstance(CraftedItemData)` (`:144-160`) rolls a rarity tier with the - **time-seeded** `ItemManager.Random` (`:20`) and stores the tier's *discrete* + `ItemManager.Random` (`:22`; seeded per run from the galaxy seed by `RunStart.ItemSeed`) and stores the tier's *discrete* Quality. - `CreateInstance(FactionProductData)` (`:164-187`) calls the previous overload, sets `Product`, and draws a gaussian `RoleFill` per design role. Since no role is @@ -130,9 +129,12 @@ unexecuted stubs. `TradeMenu.Inventory = entity.CargoBays.First()` (`ActionGameManager.cs:827-829`). - **Zones generate lazily on first entry** (`ActionGameManager.cs:643-652`, `PackedContents ??=`) from a deterministic zone seed - (`ZoneGenerator.cs:47`: name hash xor position hash). Item *selection* follows that - seed, but item *quality* comes from the time-seeded `ItemManager.Random`. A zone is - never regenerated within a run. New Game clears the run store (`MainMenu.cs:111`). + (`ZoneGenerator.cs:52`: name hash xor position hash). Item *selection* follows that + seed, but item *quality* comes from `ItemManager.Random`, a stream seeded per run from + the galaxy seed (`RunStart.SeedItems`, steps `ArenaStep`, `StageStep`, `ContinueStep`) + and drawn in the order zones are entered. A zone is never regenerated within a run. A + new run does not clear the run store up front: `RunSave.Replace` drops the old run's + records once the new run has staged (`SavedGame.cs:247`). - Each station carries hull, hardpoint gear, one docking bay, cargo bay, capacitor and stock, all embedded by value. No station equips a factory; none can, because factory designs have no product (§1). @@ -150,8 +152,9 @@ unexecuted stubs. `FactionProductData`, `PersonalityAttribute`, `NameFile`, `InputLayout`, `Loadout`. - Run (`:10`): `OrbitData`, `BodyData`, `SavedZone`, `SavedGame`. Written only by `RunSave.Commit`, which does one commit, keys zones `savedzone-{i}` and removes stale - zones (`SavedGame.cs:96-111`). `RunSave.Clear` removes every run-typed record - (`:114-124`). The single-file store writes its whole view on commit. + zones (`SavedGame.cs:216`). `RunSave.Clear` removes every run-typed + record (`:242`); `RunSave.Replace` (`:247`) does the same for a new run, but only once + the new run has staged. The single-file store writes its whole view on commit. - Player (`:11`): `PlayerSettings`. - **Every item instance is a value** embedded in `EntityPack` (hull, equipment, bays, cargo contents; `EntitySerializer.cs:179-196`), inside `SavedZone.Contents`. No @@ -237,7 +240,7 @@ Every stat and wear reader goes through the instance: "F" marks a fork (§9). "D" marks a recorded default. -| Kind | Named by | Mint | Transfer / loot / sell | Consume | Zone unload / save | New Game / death | Decides | +| Kind | Named by | Mint | Transfer / loot / sell | Consume | Zone unload / save | New run / death | Decides | |---|---|---|---|---|---|---|---| | **Lot** (provenance node) | run-scoped `LotId` (F1) | synthesis, at the mint site's call (F3) | never moves; instances point at it (D) | synthesized inputs are consumed at synthesis and have no instance (D) | kept while reachable from any instance, route or station; GC on `RunSave.Commit` (D, from the orphan-SavedZone scar) | cleared with the run store (D) | the synthesizer, one function in `ServerShared` | | **Lot properties** (mocked quality per role) | on the lot (F4) | rolled once at synthesis from factory quality and input qualities, seeded by lot id (F4) | immutable | n/a | with the lot | with the lot | synthesizer; stat readers only read | @@ -301,7 +304,7 @@ synthesized?** Blocks station identity, routes, stock and loot provenance. pirated freighter's cargo should come from a station the player can fly to. The skeleton is about 200 stations, small next to 16k instances. It demotes `ZoneGenerator`'s station count and faction choice to reading the roster. It also - moves item quality from the time-seeded `ItemManager.Random` to seeded synthesis, + moves item quality from the per-run `ItemManager.Random` stream, which depends on the order zones are entered, to lot-seeded synthesis, which makes the chain regenerable. - Sub-default: stations keep no identity outside a run. Zones never regenerate within one. diff --git a/docs/merge-to-master-checklist.md b/docs/merge-to-master-checklist.md index d5d70e17b..270b5625b 100644 --- a/docs/merge-to-master-checklist.md +++ b/docs/merge-to-master-checklist.md @@ -33,7 +33,7 @@ Compiled 2026-09-29 by Eyes from the maps on the branch. Pointers are `doc:line` ### 2b. Fresh launch (no `run.cc`, no `player.cc`) 3. **Launch to main menu.** Expect no Addressables errors, and the Groups window shows `Assets/Content` under `Default Local Group` (`addressables-cut.md:301`). `player.cc` appears and Continue is disabled (`cultcache-migration-cut.md:2746`). Proves: Addressables Cut 1, CultCache cutover. The 09-17 smoke covered the last two on the old tree; this is a cheap recheck on the new schema. -4. **New Game (tutorial).** Expect the galaxy generates and the start ship is the Longinus (`settings-globals-cut.md:498`, an expectation, not a recorded check for this stack). Expect a Zenith station with a docking bay in the entrance zone every time (`locomotion-cut.md:375`). Proves: locomotion Cut 1 station rule. +4. **New Game, then a scenario.** New Game opens the scenario picker (`MainMenu.ShowScenarios`); a development build lists modes (Terminus (Demo)), development (Tutorial Galaxy, Main Galaxy) and test arenas, a release build lists only the modes. Pick Tutorial Galaxy or Terminus (Demo). Expect the galaxy generates and the start ship is the Longinus (`settings-globals-cut.md:498`, an expectation, not a recorded check for this stack). Expect a Zenith station with a docking bay in the entrance zone every time (`locomotion-cut.md:375`). Proves: locomotion Cut 1 station rule. 5. **Addressables, "Use Asset Database".** Ships, turret and Zenith spawn; thruster and aether-drive particles show; fire an instant weapon (Autocannon) and a charged one (ChargeBlast SG); action bar icons show (`addressables-cut.md:362-366`). Proves: Addressables Cut 2. ### 2c. Flight, power and economy diff --git a/docs/tutorial-script-sketch.md b/docs/tutorial-script-sketch.md index 7e9233988..3fcbbebb6 100644 --- a/docs/tutorial-script-sketch.md +++ b/docs/tutorial-script-sketch.md @@ -16,7 +16,7 @@ Status: sketch for the operator to react to. Nothing here is built or canon. ## Shape -One contained tutorial run in a small prelude galaxy (`IsTutorial`, +One contained tutorial run in a small prelude galaxy (`Galaxy.IsPrelude`, `TutorialGenerationSettings`). The player is a newly incorporated subsidiary of the protagonist faction. Threefra, a debt-born assessor with opinions, walks them through a "qualification module" whose checklist is theatre. The real test is how the player