diff --git a/docs/aetheria-release-map.md b/docs/aetheria-release-map.md new file mode 100644 index 000000000..6169f882f --- /dev/null +++ b/docs/aetheria-release-map.md @@ -0,0 +1,216 @@ +# Aetheria Release: Map + +Date: 2026-10-03 + +This map holds body facts, the model page and rationale for campaign +`aetheria-release`. It has no progress section, no per-cut sections, no rulings +and no ledger: those are typed documents in the Eureka mind. Ends live in +`docs/aetheria-release-target.md`. The Eyes inventory this pass started from is +`F:\Projects\aetheria-release-inventory.md`, which is outside the repo. + +Every anchor below is against `origin/master` `f1dee184` and was read in a sparse +scratch worktree on 2026-10-03, unless the line says otherwise. + +## Body facts + +**B1. No impact event carries a world point.** +- `Entity.IncomingHit` (`ServerShared/Entity.cs:138`) carries only the source. +- `ArmorDamage` (`:139`) carries a schematic cell. `ItemDamage` (`:140`) carries the + item. `HullDamage` (`:143`) carries the amount. +- `Zone.ShotCommitted` and `ShotResolved` (`Zone.cs:41-42`) carry a `ShotOutcome` + (`FireControl.cs:1902-1930`), which holds a schematic cell, bearing and lateral + offset but no world point. +- The world point of a direct hit is never computed. `ApplyDirectHit` + (`FireControl.cs:944-998`) walks lanes in the schematic frame. A + contact or delayed blast computes it at `:1030` and `:1043` and passes it to + `Detonate`. `Detonate` (`:1341-1414`) has the world point and the share each entity + took, and publishes neither. +- So nothing can show a hit at the place it landed without recomputing + `FireControl`'s geometry. + +**B2. Weapon hits on a shield show nothing.** `ShieldManager.ShowHit` +(`Gameplay/ShieldManager.cs:88`) has one caller, ship-on-ship collision (`:80`). +`FireControl` calls `Shield.TakeHit` and `Break` (`FireControl.cs:952-956`, +`:1378-1385`) with no presentation hook. The inventory's "shield impact: present" +refers to the shield-panel rig, which `FieldTester` drives in `FieldShieldTest.unity`. +It does not run in the game. + +**B3. A capability event contract already exists for this.** `CapabilityEvents` +(`ServerShared/CapabilityEvents.cs`) defines `AbsorbEvent` (position, direction, +magnitude, damage type) and one `Subject` per event kind. +`CapabilityPresentationBinder` (`Gameplay/CapabilityPresentationBinder.cs`) wires +`IAbsorbPresenter` components on an object and its children. The contract's own +comment says the simulation will own and publish these events, and presentations +will subscribe and decide nothing (ruling fork L, 2026-09-17). Today its only +publisher is `FieldTester`. `AbsorbEvent` has no way to tell a shield absorb from a +hull absorb. + +**B4. The weapons already announce what they do.** +- `InstantWeapon.OnFire(shotId)` (`Behaviors/InstantWeapon.cs:272`) fires only for a + round that was not refused. +- `ChargedWeapon` has `OnStartCharging`, `OnStopCharging`, `OnCharged` and + `OnFailed` (`ChargedWeapon.cs:87-90`). +- `ConstantWeapon` has `OnStartFiring` and `OnStopFiring`. +- `EntityInstance.SetEntity` subscribes the effect managers to all of these + (`Gameplay/EntityInstance.cs:209-240`). + +**B5. The Wwise-shaped audio path is dead at its source.** +- `EquippedItem.SoundBank` (`Entity.cs:1353`) is never assigned outside two tests + (`FireControlPerWeaponTests.cs:424`, `:672`). +- So every `FireAudioEvent` and `SetAudioParameter` call returns at its null check. + The calls sit in `InstantWeapon.cs:275`, `ChargedWeapon.cs:137,154,169,185`, + `Reactor.cs:97`, `Thruster.cs:96` and `AetherDrive.cs:170-172`. +- No production code subscribes to `EquippedItem.AudioEvents` (`:1375`). +- `WwiseSoundBinding` and `WwiseLoopingSoundBinding` (`WwiseSoundBinding.cs`) have + zero use sites. +- `GameData/SoundbanksInfo.json` (2,648 lines) is read by no code. Only + `docs/build-delivery-cut.md:231` mentions copying it. +- `EntityInstance.cs:243-251` reads `item.Data.SoundBank` and does nothing with it. +- Catalog fields that hold Wwise ids: + - `EquippableItemData.SoundBank` (`ItemData.cs:403`); + - `AetherDriveData.RpmAudioParameter` and `TorqueRatioAudioParameter` + (`AetherDrive.cs:44-48`, keys 11 and 12); + - `Faction.OverworldMusic`, `CombatMusic` and `BossMusic` (`Corporations.cs:52-59`, + keys 13 to 15). + +**B6. Unity audio is switched off and has no listener.** +`ProjectSettings/AudioManager.asset` has `m_DisableAudio: 1`. A YAML grep found +`AudioListener:` count 0 in `ARPG.unity` and in `Main Menu.unity`; the two test +scenes have one each. The editor is Unity 6000.3.24f1 +(`ProjectSettings/ProjectVersion.txt`). + +**B7. The 2021 sound library is on disk and usable.** +- The Wwise project is `Aetheria-Economy_WwiseProject.wproj`, `WwiseVersion="v2021.1.1"` + and `SchemaVersion="103"`. +- Its 225 `.wav` are in LFS and present in the operator's checkout: + `Originals/SFX` holds 731 MB. +- The SFX include fire, hit and miss for cannon, ioncannon, lightingGun, machinegun + and railgun. They also include charge and charge-fail, ship destroyed (two), and + shield up, down and active. Overheat alarm, docking, undocking, wormhole, reactor + states and sensor ping are there too. +- Interface sounds are `blip`, `equip`, `mouseover`, `pickup`, `putdown`, and trade + buy and sell. +- Music: menu, Gen overworld and combat, Metal overworld, combat and boss, Daya + overworld, Kawaii Future Bass. There are also 30 ambience layers. +- The 20 `Originals/Plugins/SoundSeed Grain` sources feed a Wwise plugin, and + their procedural behaviour does not carry over outside Wwise. +- `*.wav` is an LFS pattern in `.gitattributes`. + +**B8. The camera has the tooling for shake; nothing uses it.** +`com.unity.cinemachine` 2.10.7 is in `Packages/manifest.json`. It ships +`CinemachineImpulseSource` and `CinemachineImpulseListener`. A grep found no +`Impulse` and no `shake` in `Assets/Scripts`. The follow camera is +`ActionGameManager.FollowCamera` (`ActionGameManager.cs:122`). + +**B9. Graphics settings are not saved.** +- `MainMenu.ShowGraphicsSettings`'s Back button (`UI/MainMenu.cs:258-263`) never calls + `ActionGameManager.SavePlayerSettings()`. +- Gameplay's Back button does call it (`:236-241`). +- `PlayerGraphicsSettings` (`ServerShared/PlayerSettings.cs:63-67`) holds keys 0 and 1. +- `PropertiesPanel.AddField(name, float read, write, min, max)` exists + (`UI/Properties Panel/PropertiesPanel.cs:290`). + +**B10. The lanes overlap the feedback files in these hunks** (`git diff +origin/master...origin/` hunk headers): +- **mining** (`83d8371e`): + - `FireControl.cs` at `:72` and `:522`; + - `Entity.cs` at `:43`, `:198-240`, `:295-395` and `:1075`; + - `EntityInstance.cs` at `:236` and `:410`; + - `ActionGameManager.cs` across `:362-1432`, including `:1076-1100`; + - `ZoneRenderer.cs` and `Zone.cs`. +- **scenarios** (`aa3baf12`): + - `Entity.cs` at `:204`, `:601` and `:786-1003`; + - `ActionGameManager.cs` at `:583`, `:732` and `:801`. +- **moddable-ships** (`a93625c2`): + - `ActionGameManager.cs` at `:42-70`; + - `ZoneRenderer.cs`; + - `Packages/manifest.json`, which adds glTFast. + +`feedback-1`'s edits are disjoint from these: `FireControl.cs:944-1045` and +`:1375-1412`, `Entity.cs:138-150`, and `EntityInstance.cs:159-170`. + +**B11. The headless tests compile only `ServerShared`.** That covers +`Aetheria.Shared/Aetheria.Shared.csproj:20` and `tests/Aetheria.Shared.Tests`. A rule +that must be pinned headless must live in `ServerShared`. + +## Model page + +| Kind | Identity | Lifecycle | Authority | +|---|---|---|---| +| Impact (`AbsorbEvent` with a layer) | Transient. The receiving entity's `Capabilities` stream, plus the shot. It is not stored. | Published once per landed hit, before the hull damage is applied. It is never replayed or persisted. | `FireControl` alone, in `ApplyDirectHit` and `Detonate`. Presenters only read it. | +| Impact cue | Derived from one impact and the receiver. | Computed at presentation time and discarded. | `Feedback` (engine-free, `ServerShared`). Visual and audio presenters render it and do not re-derive it. | +| Player feedback preferences (shake, volumes) | `PlayerSettings` global, player store, keys under `GraphicsSettings` (shake) and a new `AudioSettings` (volumes). | Edited in the settings menu and saved on Back. A new key defaults on load. | The player, through the menu. No runtime writer. | +| Presentation tuning (effect prefab, intensity scale, impulse shape, sound bank) | A Unity component or asset in `Assets/Content`. | Authored in the editor and versioned with the scene. | The operator. It stays Unity-serialized by fork M (a). | +| Sound assets | The file under `Assets/Audio`, copied from the Wwise `Originals`. Provenance is recorded per file. | Added per cut. The Wwise project stays as the source archive until `audio-route` and `audio-source-rights` are ruled. | The operator, on rights (`audio-source-rights`). | +| Ship content (`ShipAuthoring` with GLB) | `aetheria.ship_authoring` id. GLB nodes carry an `aetheria.id` extra. | Owned by the moddable-ships lane until it merges. | The moddable-ships rulings (MQ1-MQ5). This campaign adds no owner. | + +No cell is empty for the two mapped cuts. The content rows defer to a lane this +campaign does not own until question `content-lane-owner` is ruled. + +## Rationale + +**Why the impact is published by `FireControl` and not derived in Unity.** B1 shows +that the world point exists only inside `FireControl`'s lane walk and blast +resolution. If a presenter derived it, it would have to recompute lanes from the +`ShotOutcome`. That rebuilds the second hit authority that fire control Cuts 3 to +12.4(b) deleted. So the owner of where a round landed publishes where it landed. + +**Why reuse `CapabilityEvents` rather than a new subject.** The contract was ruled +for exactly this (B3): the simulation publishes absorbs and presenters subscribe. +Its binder already exists. Reusing it adds one field (the layer) instead of a +second event family. It also brings the shield-panel presenters within reach of real +hits later, with no new wiring. + +**Why the cue derivation lives in `ServerShared`.** Intensity and shake are rules +("in proportion to the damage", "zero at zero preference"). B11 says only +`ServerShared` is under headless test and Stryker.NET. Keeping the function +engine-free puts the rules where mutation testing reaches them. Audio then renders +the same cue (target: one cue, two channels). + +**Why native Unity audio is recommended** (question `audio-route`): +- The simulation already announces fire, charge, impact and death (B4 and + `feedback-1`). +- The Wwise path is dead at its source (B5). +- Unity audio is only switched off (B6). +- Of the Wwise project, what carries over is the wav files (B7). The + 2021.1 project, its events, banks and SoundSeed plugin sources would need + migrating to a Wwise release that supports Unity 6. +- Wwise adds three costs: + - a native plugin per platform; + - a second authoring application; + - a sound-bank build step. Its authoring console runs on Windows and macOS, not + on Yggdrasil's Linux. + + Agents cannot easily author Wwise work units, and the operator's AquaSynth renders + would have to pass through it. +- Licensing is not the obstacle. Wwise is free under a $250K development budget, + with no asset limit (Audiokinetic pricing page and indie-license blog). FMOD is + free under $200K yearly revenue and a $500K budget. +- What the middleware would buy is interactive music and parameter-driven + mixing, authored by a sound designer. The release bar asks for neither yet. +- Unity's limits are known: 32 real voices by default (`AudioManager.asset` + `m_RealVoiceCount`), no authored containers or RTPC graph, and mixer assets that + cannot be created from script. +- Unity 6's `AudioRandomContainer` has no public scripting API for its clip list. + The first cut therefore uses a small `ScriptableObject` sound bank with random + pick and jitter. + +Confidence: medium-high. It falls to medium if the operator expects a contracted +sound designer working in Wwise, or adaptive music with transitions and stingers +before release. + +**Why content runs in parallel.** The release quota is met at the operator's pace, +one hull a day, and that clock starts only when the first Tripo mesh flies. The steps +in front of it are the operator's owed S2 play checks, the moddable-ships merge, and +the add-on's package action. Each is cheap and none depends on feedback or audio. +Serializing them behind audio would idle the slowest resource in the project. + +**Sources consulted for the audio fork:** +- https://www.audiokinetic.com/en/wwise/pricing/ +- https://www.audiokinetic.com/en/community/blog/free-wwise-for-indie-developers/ +- https://www.gamedeveloper.com/audio/small-developers-and-creators-can-now-use-fmod-studio-for-free +- https://gamefromscratch.com/fmod-studio-now-free-for-indie-game-developers/ + +Two claims were not verified from primary sources on 2026-10-03: which Wwise +release first supports Unity 6000.x, and the scripting surface of +`AudioRandomContainer`. diff --git a/docs/aetheria-release-target.md b/docs/aetheria-release-target.md new file mode 100644 index 000000000..f2377a2d4 --- /dev/null +++ b/docs/aetheria-release-target.md @@ -0,0 +1,194 @@ +# Aetheria Release Target + +Date: 2026-10-03 + +Status: target. This document owns the ends. The typed `target` in the Eureka mind +(campaign `aetheria-release`) owns the labelled invariants and the not-in-scope list; +this file gives their reasons. Cut specs, questions and rulings are typed documents in +the mind and are not restated here. Body facts, the model page and the rationale for +the cut order are in `docs/aetheria-release-map.md`. + +## Why + +The game has enough systems to ship: fire control, stats and power, heat, item +provenance, locomotion, and the mining and scenario lanes in flight. What keeps it +unreleasable is presentation and breadth. It plays no sound at all. A hit on a hull +shows nothing where it lands, and the camera never reacts. Three hulls on two models +and one station are all a player can fly or dock at. + +## Operator direction (2026-10-02 and 2026-10-03) + +- "we already have plenty of game here, especially once we merge everything in flight + (and maybe another campaign or two geared at making the world feel more alive). The + only thing making it unreleasable to me is the lack of polish, content and feedback. + We need audio, we need ships, stations and gear for the player to covet and collect, + and we need our mechanics to be visible and visceral." +- "If we get the moddable ships pipeline usable and a Tripo3D subscription I can pump + one of these out every day, game ready." The pipeline is GPT Image 2.5, then + Tripo3D, then minor cleanup. +- "I don't think Asura is the way to go for content." +- The announcement bar (2026-10-02): a wider selection of ships and gear, a UX polish + pass, and audio feedback throughout. + +## What "release" means + +The release is the public announcement to players and Patreon, with a build they +can download. It is done when every line below holds on one build made from +`master`, and the operator has played that build and called it. The operator's call +is part of the definition: a ticked list without it is not a release. + +1. **The lanes in flight have landed.** `codex/mining`, `codex/scenarios` and + `codex/moddable-ships` are merged into `master` or explicitly parked by the + operator. A release does not ship around half-merged work. +2. **Every player action that changes the world makes a sound.** That covers weapon + fire and charging, impacts on shield and hull, ship destruction, docking and + undocking, the wormhole, thrusters and the drive, inventory and trade actions, menu + clicks, the overheat alarm, and music in the menu, overworld and combat. The + player can set master, music, effects and interface volume, and the settings + persist. +3. **Every hit is seen where it lands and felt by the one who takes it.** An impact + on a shield shows on the shield at the side it came from. An impact on a hull + shows at the struck point. A hit on the player's own ship moves the camera in + proportion to the damage. The player can turn shake down to zero, and the hit is + still shown. +4. **Damage, heat and exposure are visible before they are fatal.** Lost armour, + a destroyed item and a critical hull each look different on the ship and in the + HUD. Overheat and hull-critical warnings use two channels, sound plus a visual, + and the more urgent one wins. The player can see how visible they are, how close + that is to being detected, and the largest source of it. +5. **There is enough to covet.** The content quota is set by the operator's ruling + on question `release-content-bar`. Every hull and station in the quota is + flyable or dockable and enters through the moddable-ships package path. Rarity + tiers show their colours, and every weapon type sounds and looks distinct. +6. **A new player can play for thirty minutes on the Windows build without hitting + a blocking defect.** The build is published through the build-delivery path. + +## Ends + +- **The simulation states what happened, and presentation shows it.** Fire control, + shields, damage, heat and detection publish typed facts. Visual and audio + presenters subscribe to them, derive a cue from each, and render it. They decide + no rule and recompute no geometry. +- **One cue, two channels.** Each fact becomes a cue in one engine-free function. + The visual and the audio presenter render that same cue, so the two channels + cannot disagree about what happened or how hard. +- **New content is data.** A new hull, station or piece of gear arrives as a catalog + record or a mod package. Nobody hand-wires a prefab array. The operator's daily + ship goes through the image model, Tripo, cleanup and the Blender add-on, and + comes out as a `ShipAuthoring` package with its GLB. +- **The player controls intensity without losing the signal.** Shake, flashes, + particle density and each audio channel have settings. Turning any of them down + never removes the tactical information it carried. + +## Invariants that must survive + +The typed target carries these as labelled statements. The reasons: + +- **Legacy first** (operator, 2026-09-11). All work lands in the restored Unity tree. + There is no daemon, CultMesh or Eve re-architecture here. Shared infrastructure + is adopted, not invented. +- **The simulation owns the facts.** Fire control was rebuilt (Cuts 3 to 12.4(b)) so + that no Unity collider or effect decides a hit. Feedback must not reopen that + path. It reads `FireControl`'s facts and never re-derives them. +- **The simulation names no sound.** Today the simulation calls `FireAudioEvent` + with Wwise ids, against a sound bank that is never assigned. Audio becomes a + presenter of the same semantic events that visual effects use (`OnFire`, + `OnStartCharging`, impacts and deaths). +- **State is CultCache.** Player preferences such as shake and volumes go in the + player store (`PlayerSettings`), and authored data goes in the catalog. Engine + asset references are Addressables GUIDs (ruling of 2026-09-17). Presentation + tuning stays on its Unity component (fork M (a) of `docs/settings-globals-cut.md`). +- **Instruments bound what is shown** (`Visual and Sensory Direction`). A cue + never shows the player more than their sensors know. +- **The lanes are respected.** This campaign never commits to a `codex/*` branch or + to the operator's checkout. It branches from `origin/master` and rebases after + each lane merges. +- **Rules are tested headless.** Every rule decided in `ServerShared` has a + behavioural test in `tests/Aetheria.Shared.Tests`. A presentation-only behaviour + is an operator check, reachable through ordinary play or a scenario. +- **The operator judges whether the bar is met.** + +## Not in scope + +- Asura and procedural planet content. The operator ruled it out for content. +- New mechanics. Contact tiers beyond the current threshold, fused tracks, thermal + capture, probes and new weapon classes are not added here. This campaign makes + the existing mechanics visible. +- Faction mechanics beyond what `Faction Play.md` and its rulings name. +- "World feels alive" work such as ambient traffic and events. The operator named + it as a possible separate campaign. +- Build publishing machinery. `docs/build-delivery-target.md` owns it. This + campaign needs it done before release, but does not build it. +- Platforms other than Windows 64-bit, multiplayer, narrative and Ink work. +- Finishing other lanes' cuts: mining, scenarios, moddable-ships S2 and S5, thermal + balance, and the settings-globals tier-colour fix. This campaign depends on them + and does not do them. + +## Strands + +- **Feedback.** Impacts, damage states, warnings and detection, made visible and + felt. The first cut is mapped (`feedback-1`). It gives impacts a world point and a + layer, then shows them on the shield or hull and in the camera. +- **Audio.** The route is open as question `audio-route`. The first cut is mapped + for the recommended route (`audio-1`) and is blocked until the ruling. Its sketched + sequel covers interface, inventory, trade, docking and wormhole sounds, then + music, then continuous loops (thrusters, reactor, drive) and the overheat alarm, + then AquaSynth renders for whatever the 2021 library lacks. +- **Content pipeline.** This strand is a sketch until `codex/moddable-ships` merges. + 1. The Blender add-on gains a collection-to-package action. It places anchors + with `aetheria.id` extras for weapon, radiator and thruster mounts, the collider, + map icon, shield and tractor, then exports the GLB with the `ship.cc`. This is + proof gate 2 of `docs/moddable-ship-authoring.md`. + 2. Moddable-ships S3. The first playable mod ship is a Tripo mesh of a concept + whose image already worked (the Headliner or the Quiet Sense), taken through + the whole path. + 3. Repeatability. A convex collider from the render mesh, and one material-slot + convention that leaves room for a later livery slot. + 4. Throughput. One hull a day from the operator, plus stations, then gear. +- **Faction Play.** The design is `Game Design/Faction Play.md` in AetheriaLore, + at `5c45e27` plus `f3e0e6d`. It covers behaviour, relations, loadouts, resources, + visuals and hooks. On 2026-10-03 the operator accepted every proposal in it, and + the acceptance is recorded as three rulings: + - `faction-relations-field`: relations are their own authored field, not derived + from allegiance; + - `faction-lore-changes`: the five lore changes; + - `lucent-duel-bait`: Lucent's need for glory lets the player bait it into a + duel. + + The strand's first cut, when mapped, is the note's smallest proof: Zhestokost, + Lucent and AU in one run, with implementation steps 1 to 3. Those steps are + `Personality`-driven engagement range and fire discipline, the four shared agent + states, and hail barks. The feedback and content strands leave room for faction + colour and livery, and decide nothing about them. + +## Sequencing + +Self proposed feedback, then audio, then content. Feedback goes first because it is +the cheapest per unit of perceived quality and it makes later content read. This +target keeps that order for agent-paced work, with one change: **content is the +calendar-critical path, so its unblocking runs in parallel rather than last.** The +quota is met one hull a day of operator time, and that clock cannot start until a +mesh flies. The steps that start it cost the agents little: + +- the operator's owed S2 play checks on `codex/moddable-ships`; +- the merge; +- the add-on's package action. + +Agent order: `feedback-1`. Then `audio-1`, once `audio-route` is ruled; it consumes +`feedback-1`'s impact cue. Then the content strand's add-on action as soon as +moddable-ships merges. After that, the remaining feedback and audio cuts alternate. + +## Lanes and collisions + +| Lane | Owner | This campaign | +|---|---|---| +| `codex/fire-control-12` (operator checkout, modified `.blend`) | Codex / operator | Never touched. Reads use `git show` or a scratch worktree. | +| `codex/mining` | Codex | Waits for its merge. `feedback-1` edits `FireControl.Apply`, `ApplyDirectHit` and `Detonate`, which mining does not change (it edits `FireControl.cs:72-100` and `:522-535`). Mining Cut 4 (shots at chunks) should publish impacts through the same contract (follow-up). | +| `codex/scenarios` | Codex, blocked on a fix batch | Waits. Operator checks in this campaign are reachable through ordinary play. Where one is not, it waits for scenarios Cut 4. | +| `codex/moddable-ships` | Codex, S2 owing operator checks | Waits for the merge. Ownership of anchor authoring and S3 after the merge is question `content-lane-owner`. | +| `eureka/aetheria-release-*` | This campaign | One branch per cut, from `origin/master`, each in its own worktree. | + +The hot files are shared with the lanes: `Entity.cs`, `FireControl.cs`, +`ActionGameManager.cs`, `EntityInstance.cs` and `ZoneRenderer.cs`. Each cut keeps +its hunks out of the regions the open lanes change, which are listed per spec. New +behaviour goes in new files wherever an existing owner allows it.