Commit graph Aetheria/Assets/Scripts/ServerShared/LoadoutGenerator.cs
Author SHA1 Message Date
Meta Vens
2c065937ee Merge origin/eureka/aetheria-release-pirates-record (8e51016f) into master
AetherDb Program.cs: both sides appended a command (pd-gear/mine-launcher, pirates-faction);
kept all, one usage line. GameData/Aetheria.cc: master's blob kept here, pirates-faction
apply replayed on it in the next commit (follow-up catalog-blob-merge-order).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-08 21:37:22 +02:00
Meta Vens
2403a5f393 Merge origin/master (594d3477) into eureka/aetheria-release-gear-without-presence
Brings gear-without-presence up to master ahead of landing it, with
eureka/aetheria-release-retire-longinusx following.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 18:33:40 +02:00
Meta Vens
e16288bfcf Pirates record: the demo tests read the shipped faction; tests pin its eight emoji-named products
Deletes the AddPirates stand-in and its 21 calls. DemoTerminus_missing_cast_refused removes the shipped record from its scratch
copy first. LoadoutGenerator.HasHome is public so the catalog test asks production's own home rule. These tests are red on
a catalog without the Pirates: the catalog commit (pirates-faction apply) follows separately.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-08 14:50:48 +02:00
Meta Vens
04d2947a80 Gear without presence: IsAvailable reaches by allegiance alone
Presence in the galaxy no longer gates gear (ruling gear-without-presence).
Delete the IsPrelude exception, Galaxy.ContainsFaction with its cache, and
the AetherDb loadout exclude-sellers mode that existed to exercise the
presence gate. An absent maker weighs as one jump beyond the farthest zone
the generator's zone reaches. Not yet verified; may not build.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-08 14:10:58 +02:00
Meta Vens
db4617d832 Boss gate: a boss zone spawns its faction's boss, and RunGoal derives whether the exit gate is open
EntityPack.Boss (key 21) carries Entity.IsBoss through save and Continue. GenerateZone adds one boss
per BossZones entry before the ambient return, flying the faction's BossHull or, with the gap logged,
its most expensive available ship hull. RunGoal (ServerShared) is the one owner of boss life and exit
state, derived from Zone.Entities.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 01:13:08 +02:00
Meta Vens
d50fd1b973 A faction reaches its own gear; allegiance names only other factions
Operator ruling, 2026-09-30: "removing the 11 self-entries was my intention".
IsAvailable, the one reach rule, now says a faction always reaches its own
manufacturer's gear, and a transient `AetherDb allegiance-self [apply]` drops
the self-entries from the eleven factions that had one (Rossum & Douglas never
did, which is why its stations could not carry its own gear).

Tests: in a main-sector galaxy every faction is offered all it makes and no
allegiance map names its own faction; and, through a fixture faction outside
the galaxy with no self-entry, its own product is on offer to it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 23:13:34 +02:00
Meta Vens
072a56f0b4 One loose fit rule for hardpoint gear
Operator ruling, 2026-09-30: "Hardpoint fit is loose: nobody's gonna stop you
from putting a small reactor in a large reactor's hardpoint." There is one rule,
HardpointData.Takes: gear of the hardpoint's type fits when its shape, at the
hardpoint's rotation, lies within the hardpoint's cells. TakesAt is the same
rule at one offset, and Entity.ItemFits (equipping, save load, presets) now
asks it instead of repeating the containment test. Generation's hardpoint
picks, HasHome (so station stock and loadouts), product reuse and `AetherDb
hardpoint-fit` all read Takes.

Generation keeps its own placement preference, named IsFilledBy and not a fit
rule: it offers gear that fills the hardpoint when any is on offer and falls
back to anything that fits only when none is, so loadouts change only where a
hardpoint used to stay empty. RestoredHullsTests pick fillers through
IsFilledBy.

Consequence: the Autocannon, Vulcan, scorched void policy, Notorious, pretty
pretty bang bang, Manhattan, plight, DeathCluster, Small Drive and pswarm now
have a home and are offered. Still homeless: CShot RainbowLite Lazer,
ChargeBlast SG, ChargeBlast+-, OK Disperser.

Tests: generation offers exactly the sold hardpoint gear some hull fits; a 7x7
design no hull fits is offered only once a hull that takes it exists; a 5x5
Reactor hardpoint nothing fills still gets a reactor; equipping and the rule
agree for every hull, hardpoint and design; the homeless list is stated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 20:46:28 +02:00
Meta Vens
d91ab8daf9 Generation never offers gear no hull can mount
Operator ruling, 2026-09-30, on the Autocannon: "Leave the autocannon unsold,
we'll need to author a bunch more hulls before all the gear variety in the game
has a home." The fit rule gets one owner, HardpointData.Takes (the gear's type,
laid in at the hardpoint's rotation, filling every cell); LoadoutGenerator's
hardpoint picks, its reuse of a previous product and `AetherDb hardpoint-fit`
all read it. RandomProducts, which both station stock and NPC loadouts draw
through, offers only gear with a home: Tool gear, hulls, or hardpoint gear some
hull in the catalog takes. The Autocannon keeps its product and price.

Test: the Autocannon is never drawn in 2000 draws of its hardpoint type; after
a scratch hull whose hardpoint takes it is authored, it is.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 18:01:35 +02:00
Meta Vens
89ef80d298 Stations: every generated station carries a heater
Operator ruling, 2026-09-30: an idle station has no heat source and cools
toward freezing and invisibility, so station generation (LoadoutGenerator, the
one owner of station loadouts) equips one heater after the docking bay, from
the products whose design is Tool gear with a low-pass Thermotoggle and Heat,
the cockpit's thermostat composition. It is required, like the docking bay.

Not yet warm: generated stations have no reactor (no reactor product fits
Zenith's 16-cell Reactor hardpoint), so the heater's EnergyDraw gets no supply
and the station still cools (280 K to ~247 K over ten idle minutes). The test
that an idle station stays above freezing waits on that.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 15:45:32 +02:00
Meta Vens
85ebe036e1 Scenarios Cut 1: RunStart stages a new run; the Scenario catalog type
RunStart (ServerShared, no Unity type) owns what a new run starts with
(docs/scenarios-cut.md, 2.2):
- GenerateArena: the galaxy's entrance pack, generated under the scenario's
  Ambient rule. ZoneGenerator.GenerateZone gains `ambient`; false keeps
  planets, orbits and stations and generates no ship, turret or wanderer.
- Check: every failure staging a scenario would hit, found with no zone,
  touching no store.
- Stage: all-or-nothing. With no scenario, the generated starting-hull ship
  at the origin, as StartGame built it. With one, the player preset and the
  entities at their authored place and heading with cargo, stance set both
  ways through SetIff, a Minion for each piloted one; all through Zone.Admit.

Scenario (aetheria.scenario v1) joins AetheriaStores.CatalogTypes.
RunStartTests stage into a real prelude arena from the shipped catalog and
authored settings.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 12:35:18 +02:00
Meta Vens
29fcc3ee9e Fire control Cut 6c.1/6c.2: Resolution becomes reciprocal, targeting degrades instead of throwing
6c.1 (operator ruling 2026-09-19): Resolution stays a benefit -- higher is
better -- so HitProbability derives its sensor ceiling as the reciprocal of
Resolution instead of reading Resolution as the ceiling directly. The
authored 1-cell/2-cell targeting systems' Resolution values move to the new
scale in the next (data) commit.

6c.2: LoadoutGenerator.FillInterior no longer throws InvalidLoadoutException
when no targeting-system product is available to a galaxy -- it degrades to
no targeting system and logs the gap, safe only because Cut 5.1 already gave
unaided fire a floor (GameplaySettings.UnaidedTracking).

Adds FireControlCut6cTests.cs pinning both: HigherResolutionYieldsHigherOrEqualHitProbability
(dies if Resolution is read as the ceiling directly) and
NoSellerDegradesToUnaidedInsteadOfThrowing (dies if the throw is restored).

dotnet test tests/Aetheria.Shared.Tests: 210 passed, 0 failed.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-19 18:31:46 +02:00
Meta Vens
52a18efcdc Require a targeting system on every armed loadout; AI aims through reveal
LoadoutGenerator.FillInterior equips a targeting-system product,
required: true, on any entity EquipHardpoints already gave a weapon --
Q4's "not an upgrade" ruling made structural. CombatState now selects
the target's most dangerous revealed weapon item each tick through the
same IsRevealed predicate and TrySelectTargetItem writer the player path
uses, instead of never touching TargetItem at all.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-19 13:02:37 +02:00
Meta Vens
415f8e1152 Add the lot ledger and mint every crafted instance through it
Quality, Ingredients and Product leave CraftedItemInstance; a unit now
carries only a LotId into the run-scoped ProvenanceLedger. ItemManager
gains the one lot-minting path (CreateLot/CreateInstance(int)), GetLot,
and Brand(), which derives a maker and product from provenance instead
of a stored field. RunSave persists the ledger pruned to what the saved
zones' entities still reach; the live ledger is never pruned, so a
floor pickup collected after a save still resolves. CopyBuild is gone:
matching hardpoints now share the same lot instead of copying values.
PropertiesPanel shows the derived brand where the design's manufacturer
used to be. AetherDb's census flags duplicate (maker, design) products
and its save command checks every crafted instance's lot against a real
run store.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-17 04:16:23 +02:00
Meta Vens
d90a65a908 Stop describing a preset materializer that does not exist
LoadoutGenerator.IsAvailable's comment claimed a caller passes it to
Loadouts.Materialize. No game path materializes a preset yet. The comment now
says a spawner is to pass it, and that none does yet.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 23:32:53 +02:00
Meta Vens
db83cd290d Make loadouts authored catalog presets with an editor capture command
Loadouts are ship presets (variants) for spawners, not a player feature.

- Route Loadout to the catalog; the player store no longer holds it.
- Materialize takes no credits: affordability, the charge and Loadouts.Price
  are deleted, since only the player menu priced loadouts. Availability,
  key-order product choice, all-or-nothing failures and the weapon-group
  rules stay.
- Delete the InventoryPanel Save Loadout and Restore Loadout entries and
  RestoreLoadout, which also removes its docking-bay overwrite.
- The editor opens the catalog writable in the one process cache, and the
  editor-only console command capturepreset "<name>" [replace] captures the
  piloted ship. Loadouts.Commit keys a preset by name, refuses a same-name
  replace unless asked, and commits conditionally on that key. The single-file
  store then lands only that record onto the file as it is on disk. An
  unconditional commit would re-serialize every live catalog instance,
  including any that play has mutated.
- Tests: capture -> commit -> fresh reopen round-trip, explicit replace with
  no duplicate, and a preset commit that does not persist a mutated live
  Faction. The money-only tests are removed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 23:09:43 +02:00
Meta Vens
5e5c304e37 Make loadout availability a port and move the charge into Materialize (Cut 10 fix)
Materialize takes isAvailable as a Predicate<FactionProductData>; the restore
menu passes LoadoutGenerator.IsAvailable for the docked station, so generation
and loadouts still share one availability rule. Candidate products are ordered
by record key, so "first available product" no longer depends on dictionary
order. Materialize charges Price through ref credits only when it returns a
ship; RestoreLoadout no longer subtracts on its own.

Tests: a slot that resolves but does not fit builds nothing, charges nothing and
is listed; Price is the sum of design prices and is charged on success; the
first available product in key order builds a slot, a later one is used when
the first is unavailable, and none available fails the slot.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 22:27:03 +02:00
Meta Vens
00f62acc34 Make loadouts player-store design documents built all-or-nothing (Cut 10)
Loadout.cs owns loadouts: the document, capture, save and materialization.

- Loadout ("aetheria.loadout", player store) holds a hull design ref, and
  per slot a hull cell, a rotation and an EquippableItemData design ref,
  plus weapon groups as slot indices. It names no product, manufacturer,
  unit roll, cargo, faction, position or behaviour state.
- Loadouts.Capture records the hull design and one slot per equipped item
  (gear, cargo bays, docking bays). Entity.Equipment also holds the hull's
  own unit (MapEntity adds EquippedHull); that is Loadout.Hull, not a slot.
- Loadouts.Save is the only writer: one Commit to the player store, reusing
  the existing key for the name.
- Loadouts.Materialize is the only builder of a ship from a loadout. For
  the hull and each slot in order it resolves the design and takes the
  first product in catalog order that LoadoutGenerator.IsAvailable (now
  public) accepts, with no any-manufacturer fallback. Every failing slot is
  listed; units are built only after everything resolved, and any resolve
  or fit failure returns null with no ship, no charge and no write.
- Loadouts.Price is the hull design's price plus each slot design's price.
- InventoryPanel: Save Loadout asks for a name (default: the ship's name)
  and saves the capture. Restore Loadout, shown when docked with saved
  loadouts, lists each with its price, debits credits only after
  Materialize succeeds, then docks the ship as before; a failure opens
  "Loadout cannot be built here" with one line per failing slot.

Tests: new LoadoutTests (3): LoadoutRoundTripsThroughAFreshCache,
LoadoutHoldsNoRunOrGalaxyRefs, MissingDesignReports. Each fails with its
rule mutated out. The fixture hull is 3x3, not the spec's 2x2:
HullData.InteriorCells is Shape.Shrink(), so a 2x2 hull has no interior
cell a cargo bay can occupy.

Builds: headless, 14 tests pass, Unity batchmode compile reports no error CS.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 22:06:06 +02:00
Meta Vens
a2b54889b4 Move the ServerShared data model onto CultLib's CultCache
Cut 8b. Aetheria.Shared builds headless against GameCult.Caching and
GameCult.Caching.MessagePack at the pinned CultLib; the pin guard also
checks the Caching project exists.

Documents: [CultDocument("aetheria.<type>", "1")] with [MessagePackObject]
and integer [Key]s on the Q7 concrete types (the eight ItemData leaves,
Faction, FactionProductData, PersonalityAttribute, NameFile, OrbitData, the
four BodyData leaves, SavedZone, SavedGame, PlayerSettings, InputLayout).
SavedGame and PlayerSettings are [CultGlobal]; Name members are [CultName].
ItemData, CraftedItemData, EquippableItemData, BodyData and AgentTask lose
[MessagePackObject]; BodyData and AgentTask lose their [Union]s. InputLayout
moves into ServerShared so AetheriaStores can route it.

References: Guid and DatabaseLink<T> members become CultRecordRef<T>;
Guid-keyed maps become ref-keyed with [CultReference(..., many: true)];
ZonePack holds refs to orbit and body records. Runtime maps (Zone orbits,
bodies and belts, cargo ItemsOfType, agent targets) key by CultRecordKey.
Identity is the record key: ID comparisons become reference or key
comparisons. StatModifierData.RequireBehavior is a simple type name.

AetheriaStores.Open composes the catalog (read-only unless writable), run
and player stores, one home per type. CultRecordRefs carries IsSet, a
null-safe Get(ref), RefOf (key from TryGetHandle) and Upsert.
ItemManager.GetData is the one item resolution path. MathResolver is
declared by [assembly: CultCacheFormatterResolver].

Inspector attributes: text, range and asset path map onto CultLib's
CultInspector attributes (asset path only on string members); every
replaced Aetheria attribute keeps [Inspectable] for the runtime panel.

Builds: Aetheria.Shared. Does not build: AetherDb and the Unity project,
which follow.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 19:00:42 +02:00
Meta Vens
6140a06a0a Swap Unity.Mathematics usings for CultMath
Every Unity.Mathematics using, alias and qualified name under Assets\Scripts
and tools now names CultMath. The nine `using static ...noise;` lines are
gone: snoise lives on CultMath's math. UnityExtensions loses float4.ToColor
and Color.ToFloat4, which duplicate the bridge's ToColor and ToCultMath; the
float3 colour pair stays because the bridge has none.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 17:39:12 +02:00
Meta Vens
6bd3e17690 Fix station docking bays, save-safe instance keys, and zero-weight draws
One rule now governs interior space: an empty hardpoint cell is usable, in
both UnoccupiedSpace and ItemFits. ItemFits used to refuse hardpoint cells
that UnoccupiedSpace offered, so stations failed to equip a docking bay.

CraftedItemInstance.Ingredients and Product move from keys 3 and 4 to 9 and
10, past every key the derived instances use. At 3 and 4 an older save reads
nil into a non-nullable Guid and fails to load.

WeightedRandomElements returns an empty array when every weight is zero,
instead of an array of nulls. LoadoutGenerator treats a missing Galaxy as
"every product available", the seam a fixture needs to generate loadouts
without a galaxy. ZoneGenerator skips a story station that fails to generate
and logs it, instead of throwing.

Verified: Aetheria.Shared and tools/AetherDb build headless; Unity 6000.3.24f1
batchmode compile succeeds; AetherDb doctor, station-fit and loadout pass.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-12 23:22:36 +02:00
Meta Vens
8d93b937bc Author manufacturer variation as faction products
A design lists role names; a faction product is a manufacturer's branded
build of one, carrying its name, its flavor text, and a pseudo-gaussian
quality distribution per role whose mean is the technology put in and
whose deviation is their quality control. A PerformanceStat may name the
role whose quality it reads, unset reading the item own workmanship as
before, so old saves behave unchanged. Generation selects products rather
than designs, which makes what a faction makes the availability rule.

This is Njordr shape at one dimension: role names, per-role derivation
and per-product distributions carry over when quality widens into
dimensions. No parts exist yet; the product authors the role quality.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-12 01:12:12 +02:00
Meta Vens
25ecb46fcd Generate stations that respect empty hardpoints and required items
UnoccupiedSpace now counts empty hardpoint cells as free, matching
ItemFits: general gear may use a hardpoint until hardpoint gear claims
it. LoadoutGenerator equips hardpoint gear before the docking bay, so the
bay cannot take the reactor's slot. Hulls, docking bays, controllers,
cargo bays and capacitors are required: if no manufacturer present in the
galaxy and known to the faction makes one, any manufacturer is used and
the database gap is logged, so a galaxy without AU still gets stations.
Manufacturer preference is allegiance / (1 + hops to headquarters); the
distance term previously never applied due to operator precedence, and
would have divided by zero in the headquarters zone.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-11 23:23:19 +02:00
Meta Vens
3dcfaf9783 Delete commented-out code blocks
Git keeps the history. SimpleCommodityData records its retired
MessagePack keys so they are not reused against old data.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-11 22:14:58 +02:00
Meta Vens
7006a6b0dd Restore the stable legacy Unity project 2026-08-10 14:57:50 +01:00
Meta Vens
7772d9eb36 Model station sensors through hardpoint scale 2026-07-13 16:53:25 +01:00
Meta Vens
2e622ead78 Guard daemon playable run generation 2026-07-06 22:06:33 +01:00
Meta Vens
2381b407ec Split entity blueprint materialization names 2026-06-28 15:23:42 +01:00
Meta Vens
be1207c585 Move runtime API namespace to Verse 2026-06-21 09:54:15 +01:00
Meta Vens
39a0dc8737 Sync daemon authority migration 2026-06-21 09:37:54 +01:00
Meta Vens
33f289dcac Move orbital runtime seam onto typed orbit keys 2026-06-16 16:07:20 +01:00
Meta Vens
7f87373886 Use typed catalog keys for faction lookups 2026-06-15 17:25:40 +01:00
Meta Vens
c245538793 Use typed item keys in server item decisions 2026-06-15 01:12:22 +01:00
Meta Vens
32187038eb Demote behavior construction configs 2026-06-14 21:48:43 +01:00
Meta Vens
7b605f049c Demote entity blueprints to construction 2026-06-14 20:40:13 +01:00
Meta Vens
d163b3064c Expose item identity on runtime instances 2026-06-14 11:12:48 +01:00
Meta Vens
301b1251b1 Use typed runtime item category tokens 2026-06-14 09:38:55 +01:00
Meta Vens
2a871e4cfb Use typed loadout candidate selectors 2026-06-14 09:31:17 +01:00
Meta Vens
a786da0e24 Instantiate loadout items from typed rows 2026-06-14 07:27:23 +01:00
Meta Vens
ce8adfbaf2 Use typed rows for loadout selection 2026-06-14 05:25:56 +01:00
Meta Vens
05c3e88b10 Prefilter loadout hull roles with typed catalog 2026-06-13 23:26:50 +01:00
Meta Vens
1806ba221e Prefilter loadouts with typed catalog rows 2026-06-13 23:20:16 +01:00
Meta Vens
b9377a112a Name item catalog bridge as projection 2026-06-13 23:10:48 +01:00
Meta Vens
9d8636f419 Demote loadout item projection bridge 2026-06-13 19:41:09 +01:00
Meta Vens
a9abfe0c68 Rename runtime entity blueprint projector 2026-06-13 19:12:56 +01:00
Meta Vens
ade6845e1d Demote runtime save packs to blueprints 2026-06-13 18:06:59 +01:00
Meta Vens
06f32937b6 Remove legacy catalog enumeration bridges 2026-06-13 13:49:16 +01:00
Meta Vens
8e77e67dba Use typed catalog for loadout item candidates 2026-06-13 13:35:00 +01:00
Meta Vens
c43d7b8f67 Resolve runtime factions through typed galaxy projection 2026-06-13 13:24:36 +01:00
Meta Vens
fabbd088e2 Hide legacy catalog reader behind ItemManager 2026-06-13 10:49:29 +01:00
Reinier Vens
47e500e1ce Playability
Fixed loadout generator tutorial edge cases
Recreated missing items
Created field shader & test scene
2022-08-08 22:43:55 +01:00