2026-08-10 14:57:50 +01:00
|
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
2020-12-22 03:13:43 +00:00
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
|
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
|
|
|
|
|
|
|
|
|
|
using System;
|
2020-04-09 10:33:16 +01:00
|
|
|
|
using System.Collections;
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.Linq;
|
2026-08-10 14:57:50 +01:00
|
|
|
|
using MessagePack;
|
|
|
|
|
|
using Newtonsoft.Json;
|
2026-09-14 17:39:12 +02:00
|
|
|
|
using CultMath;
|
|
|
|
|
|
using static CultMath.math;
|
2020-04-09 10:33:16 +01:00
|
|
|
|
|
2021-04-18 05:13:20 +01:00
|
|
|
|
public abstract class Behavior
|
2020-04-09 10:33:16 +01:00
|
|
|
|
{
|
2026-08-10 14:57:50 +01:00
|
|
|
|
public BehaviorData Data { get; }
|
2021-04-18 05:13:20 +01:00
|
|
|
|
public EquippedItem Item { get; }
|
|
|
|
|
|
private ConsumableItemEffect Consumable { get; }
|
|
|
|
|
|
protected ItemManager ItemManager { get; }
|
|
|
|
|
|
|
|
|
|
|
|
protected Entity Entity => Item?.Entity ?? Consumable.Entity;
|
|
|
|
|
|
public float Temperature => Item?.Temperature ?? Consumable.Entity.MaxTemp;
|
|
|
|
|
|
|
2026-08-10 14:57:50 +01:00
|
|
|
|
public float3 Direction
|
2021-04-18 05:13:20 +01:00
|
|
|
|
{
|
|
|
|
|
|
get
|
|
|
|
|
|
{
|
|
|
|
|
|
if(Item != null)
|
|
|
|
|
|
{
|
Delete HardpointTransforms; mount direction and arc become sim data
Entity.HardpointTransforms was written only by Unity (EntityInstance.cs),
so the simulation's notion of where a gun points was a readback from a
renderer that never runs headless -- Combat.cs threw KeyNotFoundException
on the first combat tick outside Unity. Deletes the field, its writer, and
the readback branch in Behavior.Direction, leaving the item-rotation path
(the same convention reaction thrusters use, R6) as the only source of
mount direction.
Adds FireControl (ServerShared), a static class owning whether a weapon
bears on a point: MountDirection (planar, from ItemRotation), ArcFor (the
per-hardpoint HardpointData.FiringArc override, falling back to the new
GameplaySettings.FiringArc default of 120), and InArc (the planar dot-cone
test, R7 -- target height never enters it, and an arc of 360+ passes
unconditionally so a turret hardpoint needs no new type, just a number).
Combat.cs and TurretController.cs now gate AI fire through InArc instead
of the old hardcoded 0.99 dot-product test against a live Unity transform.
Settings.cs drops AgentFiringMinDot, which was declared and read by
nothing.
docs/fire-control-cut.md, Cut 1.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-19 07:37:52 +02:00
|
|
|
|
var itemDirection = Entity.Direction.Rotate(Item.EquippableItem.Rotation);
|
|
|
|
|
|
return float3(itemDirection.x, 0, itemDirection.y);
|
2021-04-18 05:13:20 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-10 14:57:50 +01:00
|
|
|
|
return float3(Entity.Direction.x, 0, Entity.Direction.y);
|
2021-04-18 05:13:20 +01:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-10 14:57:50 +01:00
|
|
|
|
protected Behavior(BehaviorData data, EquippedItem item)
|
2026-06-15 18:51:59 +01:00
|
|
|
|
{
|
2026-08-10 14:57:50 +01:00
|
|
|
|
Data = data;
|
2026-06-15 18:51:59 +01:00
|
|
|
|
Item = item;
|
|
|
|
|
|
ItemManager = Item.ItemManager;
|
|
|
|
|
|
}
|
2026-08-10 14:57:50 +01:00
|
|
|
|
|
|
|
|
|
|
protected Behavior(BehaviorData data, ConsumableItemEffect consumable)
|
2026-06-15 18:51:59 +01:00
|
|
|
|
{
|
2026-08-10 14:57:50 +01:00
|
|
|
|
Data = data;
|
2026-06-15 18:51:59 +01:00
|
|
|
|
Consumable = consumable;
|
|
|
|
|
|
ItemManager = consumable.Entity.ItemManager;
|
|
|
|
|
|
}
|
2026-08-10 14:57:50 +01:00
|
|
|
|
|
2021-04-18 05:13:20 +01:00
|
|
|
|
public float Evaluate(PerformanceStat stat) => Item?.Evaluate(stat) ?? Consumable.Evaluate(stat);
|
2026-09-19 06:58:57 +02:00
|
|
|
|
|
|
|
|
|
|
// Nominal-request ruling (docs/stats-and-power-cut.md, operator ruling 2026-09-19): the read a PowerRequest
|
|
|
|
|
|
// implementation uses for a stat named in StatValidation.PowerRequestFields, in place of Evaluate above. A
|
|
|
|
|
|
// consumable-hosted instance (Item == null) never reaches PowerBus.Step at all (see e.g. EnergyDraw.Execute's
|
|
|
|
|
|
// own comment), and ConsumableItemEffect.PowerSupplyFactor is already the identity (1) unconditionally, so
|
|
|
|
|
|
// Consumable.Evaluate is already nominal with respect to power and needs no separate context.
|
|
|
|
|
|
public float EvaluateNominalPower(PerformanceStat stat) => Item?.EvaluateNominalPower(stat) ?? Consumable.Evaluate(stat);
|
2021-04-18 05:13:20 +01:00
|
|
|
|
protected void AddHeat(float heat) => Item?.AddHeat(heat); // TODO: Heat for Consumables
|
|
|
|
|
|
|
|
|
|
|
|
protected void CauseDamage(float damage)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (Item != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Item.EquippableItem.Durability -= damage;
|
|
|
|
|
|
Entity.ItemDamage.OnNext((Item, damage));
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
Consumable.Entity.Hull.Durability -= damage;
|
|
|
|
|
|
Consumable.Entity.HullDamage.OnNext(damage);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
protected void CauseWearDamage(float multiplier)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (Item != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
CauseDamage(Item.Wear * multiplier);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2026-08-10 14:57:50 +01:00
|
|
|
|
|
2021-04-18 05:13:20 +01:00
|
|
|
|
public virtual bool Execute(float dt)
|
|
|
|
|
|
{
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
2020-04-09 10:33:16 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-04-18 05:13:20 +01:00
|
|
|
|
public interface IActivatedBehavior
|
2021-01-25 05:53:36 +00:00
|
|
|
|
{
|
|
|
|
|
|
void Activate();
|
|
|
|
|
|
void Deactivate();
|
|
|
|
|
|
}
|
2020-04-09 10:33:16 +01:00
|
|
|
|
|
2021-04-18 05:13:20 +01:00
|
|
|
|
public interface IAnalogBehavior
|
2020-04-09 10:33:16 +01:00
|
|
|
|
{
|
2020-06-05 04:16:33 +01:00
|
|
|
|
float Axis { get; set; }
|
2020-04-09 10:33:16 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-03-21 01:55:25 +00:00
|
|
|
|
public interface IEventBehavior
|
|
|
|
|
|
{
|
|
|
|
|
|
void ResetEvents();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-05-12 01:42:13 +01:00
|
|
|
|
public interface IInitializableBehavior
|
|
|
|
|
|
{
|
|
|
|
|
|
void Initialize();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-01-25 05:53:36 +00:00
|
|
|
|
public interface IInteractiveBehavior
|
|
|
|
|
|
{
|
|
|
|
|
|
bool Exposed { get; }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-05-12 01:42:13 +01:00
|
|
|
|
public interface IAlwaysUpdatedBehavior
|
|
|
|
|
|
{
|
2021-01-10 03:59:47 +00:00
|
|
|
|
void Update(float delta);
|
2020-05-12 01:42:13 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2020-12-31 19:53:16 +00:00
|
|
|
|
public interface IProgressBehavior
|
|
|
|
|
|
{
|
|
|
|
|
|
float Progress { get; }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2020-06-08 01:01:33 +01:00
|
|
|
|
public interface IPopulationAssignment
|
|
|
|
|
|
{
|
|
|
|
|
|
int AssignedPopulation { get; set; }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
Cut 3: PowerBus replaces TryConsumeEnergy/CanConsumeEnergy
Deletes Entity.CanConsumeEnergy/TryConsumeEnergy and Reactor's own capacitor
draining/filling (the demand-mechanism halves of Reactor.cs:90-141); adds
PowerBus (one per Entity, stepped once per tick before equipment executes),
IPowerConsumer on the five continuous draw sites (EnergyDraw, Thruster,
AetherDrive, Radiator, ConstantWeapon), and EquippedItem.PowerSupply as the
bus's grant ratio. Reactor keeps only its heat/throttle arithmetic, now driven
by PowerBus.NetDraw instead of an accumulator any behaviour could add into.
The four instant draws (InstantWeapon's burst/shot, Sensor's ping, Shield's hit
taken) are out of scope for the bus this cut per the map; they spend capacitor
charge directly and atomically via the new Entity.TrySpendCapacitorCharge/
CanSpendCapacitorCharge, replacing TryConsumeEnergy's old partial-drain-then-
refuse bug for that path too. Named, temporary exception closed by Cut 4.
docs/stats-and-power-cut.md Cut 3.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-18 21:39:38 +02:00
|
|
|
|
// Cut 3 (docs/stats-and-power-cut.md §1.2): a behaviour that wants to draw from its entity's PowerBus declares a
|
|
|
|
|
|
// request instead of spending energy itself. PowerBus.Step calls this on every consumer once per tick, before
|
|
|
|
|
|
// any behaviour's Execute runs, so PowerRequest must be computable from state that is already current at that
|
|
|
|
|
|
// point -- a resolved stat and, where the map calls for one, a behaviour-supplied scalar such as Thruster's
|
|
|
|
|
|
// throttle axis (set externally before the tick) -- never from work Execute itself would otherwise do. The
|
|
|
|
|
|
// behaviour reads back how much of its own request was granted from Item.PowerSupply during its own Execute.
|
Cut 5: priority tiers replace PowerBus's single shared GrantRatio
PowerTiers.cs names five tiers (Critical/High/Medium/Low/Utility) and their
per-behaviour-kind defaults: Radiator is Critical (the closest thing this game
has to life support -- a starved radiator cascades into wear and shutdown
across the whole hull), Shield is High, Thruster/AetherDrive are Medium,
ConstantWeapon/InstantWeapon are Low, and Sensor/EnergyDraw are Utility.
IPowerConsumer.DefaultPowerTier lets each behaviour own its own default.
EquippableItem.PowerTier (Key 12) is the stored, player-choosable tier on the
unit rather than the design; EquippedItem's constructor seeds a kind default
the first time a unit is equipped, only when the field is still
PowerTiers.Unassigned, and never again -- a tier is a stored choice, not
something the bus re-derives.
PowerBus.AllocateTiers walks tiers lowest-number-first: a tier is granted in
full before the next tier sees anything left, an empty tier passes its whole
share down, and within a tier every consumer rations by the same
grant/demand fraction so unequal requests still divide proportionally. A new
TierGrantRatio[] exposes each tier's own ratio for a future UI (Cut 8) to
read starvation from directly, instead of reconstructing it from every item's
PowerSupply.
Deletes EquippedItem.SortPosition, IOrderedBehavior and Reactor.Order (its
only implementer): the bus already steps before any equipment's Execute, so
equip/behaviour order never decided who got fed even before this cut, and
nothing else needed the interface (subject to the map's O3 operator check).
docs/stats-and-power-cut.md Cut 5 / §1.3.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-19 02:58:38 +02:00
|
|
|
|
//
|
|
|
|
|
|
// Cut 5 (docs/stats-and-power-cut.md §1.3): every kind of consumer also names the priority tier (PowerTiers.cs)
|
|
|
|
|
|
// it defaults to. EquippedItem reads this exactly once, to seed EquippableItem.PowerTier the first time an item
|
|
|
|
|
|
// without a player-chosen tier gets equipped -- after that the stored field is what PowerBus reads, never this.
|
Cut 3: PowerBus replaces TryConsumeEnergy/CanConsumeEnergy
Deletes Entity.CanConsumeEnergy/TryConsumeEnergy and Reactor's own capacitor
draining/filling (the demand-mechanism halves of Reactor.cs:90-141); adds
PowerBus (one per Entity, stepped once per tick before equipment executes),
IPowerConsumer on the five continuous draw sites (EnergyDraw, Thruster,
AetherDrive, Radiator, ConstantWeapon), and EquippedItem.PowerSupply as the
bus's grant ratio. Reactor keeps only its heat/throttle arithmetic, now driven
by PowerBus.NetDraw instead of an accumulator any behaviour could add into.
The four instant draws (InstantWeapon's burst/shot, Sensor's ping, Shield's hit
taken) are out of scope for the bus this cut per the map; they spend capacitor
charge directly and atomically via the new Entity.TrySpendCapacitorCharge/
CanSpendCapacitorCharge, replacing TryConsumeEnergy's old partial-drain-then-
refuse bug for that path too. Named, temporary exception closed by Cut 4.
docs/stats-and-power-cut.md Cut 3.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-18 21:39:38 +02:00
|
|
|
|
public interface IPowerConsumer
|
|
|
|
|
|
{
|
|
|
|
|
|
float PowerRequest(float dt);
|
Cut 5: priority tiers replace PowerBus's single shared GrantRatio
PowerTiers.cs names five tiers (Critical/High/Medium/Low/Utility) and their
per-behaviour-kind defaults: Radiator is Critical (the closest thing this game
has to life support -- a starved radiator cascades into wear and shutdown
across the whole hull), Shield is High, Thruster/AetherDrive are Medium,
ConstantWeapon/InstantWeapon are Low, and Sensor/EnergyDraw are Utility.
IPowerConsumer.DefaultPowerTier lets each behaviour own its own default.
EquippableItem.PowerTier (Key 12) is the stored, player-choosable tier on the
unit rather than the design; EquippedItem's constructor seeds a kind default
the first time a unit is equipped, only when the field is still
PowerTiers.Unassigned, and never again -- a tier is a stored choice, not
something the bus re-derives.
PowerBus.AllocateTiers walks tiers lowest-number-first: a tier is granted in
full before the next tier sees anything left, an empty tier passes its whole
share down, and within a tier every consumer rations by the same
grant/demand fraction so unequal requests still divide proportionally. A new
TierGrantRatio[] exposes each tier's own ratio for a future UI (Cut 8) to
read starvation from directly, instead of reconstructing it from every item's
PowerSupply.
Deletes EquippedItem.SortPosition, IOrderedBehavior and Reactor.Order (its
only implementer): the bus already steps before any equipment's Execute, so
equip/behaviour order never decided who got fed even before this cut, and
nothing else needed the interface (subject to the map's O3 operator check).
docs/stats-and-power-cut.md Cut 5 / §1.3.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-19 02:58:38 +02:00
|
|
|
|
int DefaultPowerTier { get; }
|
Cut 3: PowerBus replaces TryConsumeEnergy/CanConsumeEnergy
Deletes Entity.CanConsumeEnergy/TryConsumeEnergy and Reactor's own capacitor
draining/filling (the demand-mechanism halves of Reactor.cs:90-141); adds
PowerBus (one per Entity, stepped once per tick before equipment executes),
IPowerConsumer on the five continuous draw sites (EnergyDraw, Thruster,
AetherDrive, Radiator, ConstantWeapon), and EquippedItem.PowerSupply as the
bus's grant ratio. Reactor keeps only its heat/throttle arithmetic, now driven
by PowerBus.NetDraw instead of an accumulator any behaviour could add into.
The four instant draws (InstantWeapon's burst/shot, Sensor's ping, Shield's hit
taken) are out of scope for the bus this cut per the map; they spend capacitor
charge directly and atomically via the new Entity.TrySpendCapacitorCharge/
CanSpendCapacitorCharge, replacing TryConsumeEnergy's old partial-drain-then-
refuse bug for that path too. Named, temporary exception closed by Cut 4.
docs/stats-and-power-cut.md Cut 3.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-18 21:39:38 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-10 14:57:50 +01:00
|
|
|
|
[Inspectable,
|
|
|
|
|
|
Union(0, typeof(GuidedWeaponData)),
|
|
|
|
|
|
Union(1, typeof(LauncherData)),
|
|
|
|
|
|
Union(2, typeof(ReactorData)),
|
|
|
|
|
|
Union(3, typeof(RadiatorData)),
|
|
|
|
|
|
Union(4, typeof(StatModifierData)),
|
|
|
|
|
|
Union(5, typeof(SensorData)),
|
|
|
|
|
|
Union(6, typeof(ReflectorData)),
|
|
|
|
|
|
Union(7, typeof(ShieldData)),
|
|
|
|
|
|
Union(8, typeof(ThrusterData)),
|
|
|
|
|
|
Union(9, typeof(WearData)),
|
|
|
|
|
|
Union(10, typeof(VelocityConversionData)),
|
|
|
|
|
|
Union(11, typeof(VelocityLimitData)),
|
Delete the aether drive: behaviour, union 12, hardpoint type, aggregates, settings, presenters, prefab
AetherDriveData and AetherDrive, Union(12) (now a retired-do-not-reuse comment, as 26 is),
HardpointType.AetherDrive (last member, nothing shifts), Ship's drive sets, aggregates and
Axis write, the five request-field rows, GameplaySettings Aether multipliers, ShipInstance's
drive particles, SchematicDisplay's RPM display and AetherDriveUi, the undock refusal's drive
clause, the drive prefab and material, and AetherDb's drive roles and brownout row. The
design is kept at parked/aether-drive.
Adds EveryShippedShipHullHasATopSpeed. ARPG.unity still holds stale serialized references to
the removed SchematicDisplay fields and the RPM Display object; the next commit removes them.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-08 14:04:28 +02:00
|
|
|
|
// Union(12): retired, do not reuse -- was AetherDriveData (retire-longinusx; parked/aether-drive)
|
2026-08-10 14:57:50 +01:00
|
|
|
|
// Union(14, typeof(TowingControllerData)),
|
|
|
|
|
|
Union(15, typeof(CooldownData)),
|
|
|
|
|
|
Union(16, typeof(HeatData)),
|
|
|
|
|
|
// Union(17, typeof(HitscanData)),
|
|
|
|
|
|
Union(18, typeof(ItemUsageData)),
|
|
|
|
|
|
//Union(19, typeof(RadianceData)),
|
|
|
|
|
|
Union(20, typeof(SwitchData)),
|
|
|
|
|
|
Union(21, typeof(TriggerData)),
|
|
|
|
|
|
Union(22, typeof(VisibilityData)),
|
|
|
|
|
|
Union(23, typeof(ThermotoggleData)),
|
|
|
|
|
|
Union(24, typeof(EnergyDrawData)),
|
|
|
|
|
|
// Union(25, typeof(MiningControllerData)),
|
Cut 2: the dead mining path goes, and chunks get one owner
MiningTool (its Execute range-checked against nothing, since no writer ever
set AsteroidBelt/Asteroid) and Zone.MineAsteroid (mints nothing; the
SimpleCommodity drop was commented out) are deleted, per Q1=A: "Bring back
the drill, indeed." Union tag 26 is retired, not reused. ResourceScanner's
dead survey Execute and its scan-target fields go too; its authored Range/
MinimumDensity/ScanDuration stay pending Q2. PlanetSettings.MiningDifficulty
had one reader, now gone.
Chunk wear (damage, broken-until) moves off AsteroidBelt's three per-belt
dictionaries and onto Zone as the one owner (Q3=A): Zone.Wear is the only
writer, ChunkExists/ChunkRadius are the readers, and respawn is a lazy
comparison against zone time, never a per-tick loop. ChunkId is
(CultRecordKey Field, int Index) -- "Field", not "Belt", because chunks are
meant to generalize past asteroid belts to other debris fields later.
Persisted in ZonePack's new key 6 (List<ChunkWearPack>, nullable so an older
record with no key 6 loads with no wear instead of throwing), pruned of
healed, non-broken entries at pack.
The break threshold stays strictly greater-than, matching today's behaviour:
damage exactly equal to hitpoints does not yet break the chunk.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 11:30:44 +02:00
|
|
|
|
// Union(26): retired, do not reuse -- was the "hit it with a tool" behavior deleted in Cut 2 (docs/mining-cut.md, Q1=A).
|
2026-08-10 14:57:50 +01:00
|
|
|
|
// Union(27, typeof(SurveyControllerData)),
|
|
|
|
|
|
Union(28, typeof(ResourceScannerData)),
|
|
|
|
|
|
// Union(29, typeof(WanderControllerData)),
|
|
|
|
|
|
// Union(30, typeof(HaulingControllerData)),
|
|
|
|
|
|
Union(31, typeof(CapacitorData)),
|
|
|
|
|
|
Union(32, typeof(CockpitData)),
|
|
|
|
|
|
Union(33, typeof(HeatStorageData)),
|
|
|
|
|
|
Union(34, typeof(TurretControllerData)),
|
|
|
|
|
|
Union(35, typeof(InstantWeaponData)),
|
|
|
|
|
|
Union(36, typeof(ConstantWeaponData)),
|
|
|
|
|
|
Union(37, typeof(ChargedWeaponData)),
|
|
|
|
|
|
Union(38, typeof(AutoWeaponData)),
|
2026-09-19 13:02:05 +02:00
|
|
|
|
// Cut 2 (docs/fire-control-cut.md): 39 is the next free index against this list, not the 39 the
|
|
|
|
|
|
// superseded draft quoted -- checked directly here rather than trusted from that document.
|
|
|
|
|
|
Union(39, typeof(TargetingSystemData)),
|
2026-10-07 19:47:21 +02:00
|
|
|
|
Union(40, typeof(MineLayerData)),
|
2026-10-10 05:51:04 +02:00
|
|
|
|
Union(41, typeof(ThrottleLockData)),
|
2026-10-09 20:22:00 +02:00
|
|
|
|
Union(42, typeof(VapourDumpData)),
|
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
|
|
|
|
JsonObject(MemberSerialization.OptIn)]
|
2026-08-10 14:57:50 +01:00
|
|
|
|
public abstract class BehaviorData
|
|
|
|
|
|
{
|
|
|
|
|
|
[Inspectable, JsonProperty("group"), Key(0)]
|
|
|
|
|
|
public int Group;
|
|
|
|
|
|
|
|
|
|
|
|
public abstract Behavior CreateInstance(EquippedItem item);
|
|
|
|
|
|
public abstract Behavior CreateInstance(ConsumableItemEffect consumable);
|
2026-06-21 09:37:54 +01:00
|
|
|
|
|
2026-08-10 14:57:50 +01:00
|
|
|
|
public override string ToString()
|
2026-06-21 09:37:54 +01:00
|
|
|
|
{
|
2026-08-10 14:57:50 +01:00
|
|
|
|
return base.ToString().FormatTypeName();
|
2026-06-21 09:37:54 +01:00
|
|
|
|
}
|
2026-08-10 14:57:50 +01:00
|
|
|
|
}
|