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>
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>
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>
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>
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>
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>
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>
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>
Fixed towing system
Tweaked Nebula Flow (a lot)
Extracted environment appearance settings into ZoneEnvironment data structure
Stardust particles now follow global flow field
Fixed various bugs caused by triggering wormhole animation multiple times
Sector -> Galaxy
Fixed bug in hostility system; deserialized entities' PresencePermitted was silently throwing an exception (due to Faction being null during initialization) and thus never updating in response to security level changes
Worked a bit on story processing
Replaced Unity TAA with PlayDead TAA
Custom keyboard layout test scene
Adjusted Aetheric Drive VFX to be more subtle
Reworked stardust VFX to reduce flickering artifacts
Added Action Bar & weapon groups saving/loading
Implemented security levels and faction safe zone visualization
Improved station placement (now include defensive turrets)
Added Aetheric Drive hardpoint and item behavior
Added Drive RPM UI to HUD
Fixed death not disabling continue option
Disabling global input when dialog is visible
Fixed loadout generator failure when zero price item present
Replaced fixed top speed with drag coefficients
Marking player location on galaxy map
Fixed non-input field focus disabling global key map
Player start ship is now always the same
Loadout generator now demands exact match for item dimensions
Thermal damage now triggers ItemDamaged event = player can die from cockpit wear!
Properties panel now has a much more attractive UI
Implemented curve control for properties UI
Centralized number formatting in player settings
Moved significant digits to player settings
Added temperature unit option in player settings
Changed title font to Montserrat
Added trailer-specific camera transitions
Added key to hide UI
Fixed input listening while console is open
Added animated zone reveal effect in galaxy map
Added Ping action for sensors
Added debug console commands (e.g. give command to get any item in legendary+ quality)
Temporarily disabled wwise
Fixed infinite loop in weapon penetration code
Guided missiles now predict target position
Fixed hitscan weapons
Fixed invisible enemies bug
Fixed various loadout generator issues (can now generate turrets!)
Fixed wormhole crash when enemy is targeted
Saving/loading current zone time when exiting game (planets keep their positions)
Created slime simulation in test scene - WIP
Added ping feature to sensors, pulsing a wave of revealing light into the level
Added IEventBehavior interface, used by sensors and weapons, for behaviors containing event subscriptions which need to be reset when EntityInstance is disposed
Implemented sensor impact for locked weapons (lock speed varies with sensor acquisition)
Added ping cooldown bar to HUD
Added spline curve implementations to AetheriaMath, applied better mapping to wormhole transition animation
Tweaked loadout generator to prefer larger items to a controllable degree (e.g. very important for cargo bays, less for shop inventory), shop inventory bans non-ship hulls and manages internal space more effectively
Added stations to loadout generator
Overhauled Trade menu to sell station inventory contents
Placing stations in ZoneGenerator
Moved weapons to new item type: WeaponItemData
Implemented icon sets for weapon functionality
Renamed MegaCorporation to Faction
Implemented quality-dependent item pricing
Added unoccupied space helper function for entity
Moved sector generation settings to settings file
Adjusted sector generation to improve sample elimination performance and better preserve density map
Added unit tests for item shape rotation and fit functions + fixed those (required for correct loadout generation)!
Fixed faction hostility by marking player ship
Added faction to entity serialization
Generating starting loadout for player ship
Modified zone generator to scale the radius and mass of a zone according to galaxy density
Added loadout generator which procedurally generates ships and turrets
Generating 3 randomized ships in each occupied zone
Fixed DatabaseCache.GetAll for parent types
Fixed wormhole traversal bug for returning to previous zone (ZoneRenderer subscriptions not being properly disposed)