diff --git a/.voidbot/state/aetheria.cc b/.voidbot/state/aetheria.cc index c41f927e1..31b89ddbd 100644 Binary files a/.voidbot/state/aetheria.cc and b/.voidbot/state/aetheria.cc differ diff --git a/Aetheria.State/README.md b/Aetheria.State/README.md index a65d0298b..c0dede01c 100644 --- a/Aetheria.State/README.md +++ b/Aetheria.State/README.md @@ -198,6 +198,9 @@ curves, ammo/reload fields, guided projectile profile fields, burst/cooldown fields, charge multipliers, and lock parameters into runtime-owned fields. Behavior instances no longer retain their `RuntimeBehaviorConfig` subclasses after construction. +Cockpit, HeatStorage, Switch, Trigger, and TurretController no longer have +`RuntimeBehaviorConfig` subclasses at all; `ItemManager` constructs them +directly from typed runtime behavior definitions. `ItemManager` currently owns the explicit typed-payload-to-config bridge. Typed name-file documents are `aetheria.name_file.v2` records. They carry the legacy ID, display name, count, compact sample names for surfaces, and the full diff --git a/Assets/Scripts/ServerShared/AetheriaRuntimeItemCatalog.cs b/Assets/Scripts/ServerShared/AetheriaRuntimeItemCatalog.cs index facb6c016..95b7a20ea 100644 --- a/Assets/Scripts/ServerShared/AetheriaRuntimeItemCatalog.cs +++ b/Assets/Scripts/ServerShared/AetheriaRuntimeItemCatalog.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.Linq; using GameCult.Aetheria.State.Unity; diff --git a/Assets/Scripts/ServerShared/Behaviors/Behaviors.cs b/Assets/Scripts/ServerShared/Behaviors/Behaviors.cs index 3033ae2f2..957ba6bd3 100644 --- a/Assets/Scripts/ServerShared/Behaviors/Behaviors.cs +++ b/Assets/Scripts/ServerShared/Behaviors/Behaviors.cs @@ -6,6 +6,7 @@ using System; using System.Collections; using System.Collections.Generic; using System.Linq; +using GameCult.Aetheria.State.Unity; using Unity.Mathematics; using static Unity.Mathematics.math; using static Unity.Mathematics.noise; @@ -62,12 +63,36 @@ public abstract class Behavior ItemManager = consumable.Entity.ItemManager; } + protected Behavior(RuntimeBehaviorDefinition definition, EquippedItem item) + { + _performanceStats = new Dictionary(StringComparer.Ordinal); + Kind = definition?.Kind ?? ""; + Group = definition?.Group ?? 0; + Item = item; + ItemManager = Item.ItemManager; + } + + protected Behavior(RuntimeBehaviorDefinition definition, ConsumableItemEffect consumable) + { + _performanceStats = new Dictionary(StringComparer.Ordinal); + Kind = definition?.Kind ?? ""; + Group = definition?.Group ?? 0; + Consumable = consumable; + ItemManager = consumable.Entity.ItemManager; + } + public float Evaluate(PerformanceStat stat) => Item?.Evaluate(stat) ?? Consumable.Evaluate(stat); public bool TryGetPerformanceStat(string statName, out PerformanceStat stat) { - return !string.IsNullOrWhiteSpace(statName) && - _performanceStats.TryGetValue(statName, out stat); + if (!string.IsNullOrWhiteSpace(statName) && + _performanceStats.TryGetValue(statName, out stat)) + { + return true; + } + + stat = null; + return false; } private static Dictionary CapturePerformanceStats(RuntimeBehaviorConfig config) @@ -159,6 +184,18 @@ public interface IPopulationAssignment int AssignedPopulation { get; set; } } +public sealed class RuntimeBehaviorDefinition +{ + public string Kind { get; } + public int Group { get; } + + public RuntimeBehaviorDefinition(AetheriaRuntimeBehaviorPayload payload) + { + Kind = payload?.Kind ?? ""; + Group = payload?.Group ?? 0; + } +} + [Inspectable] public abstract class RuntimeBehaviorConfig { diff --git a/Assets/Scripts/ServerShared/Behaviors/Cockpit.cs b/Assets/Scripts/ServerShared/Behaviors/Cockpit.cs index f35acd664..89bec6210 100644 --- a/Assets/Scripts/ServerShared/Behaviors/Cockpit.cs +++ b/Assets/Scripts/ServerShared/Behaviors/Cockpit.cs @@ -6,26 +6,13 @@ using System.Collections.Generic; using Unity.Mathematics; using static Unity.Mathematics.math; -[Inspectable] -public class CockpitConfig : RuntimeBehaviorConfig -{ - public override Behavior CreateInstance(EquippedItem item) - { - return new Cockpit(this, item); - } - public override Behavior CreateInstance(ConsumableItemEffect item) - { - return new Cockpit(this, item); - } -} - public class Cockpit : Behavior { - public Cockpit(CockpitConfig data, EquippedItem item) : base(data, item) + public Cockpit(RuntimeBehaviorDefinition definition, EquippedItem item) : base(definition, item) { } - public Cockpit(CockpitConfig data, ConsumableItemEffect item) : base(data, item) + public Cockpit(RuntimeBehaviorDefinition definition, ConsumableItemEffect item) : base(definition, item) { } } diff --git a/Assets/Scripts/ServerShared/Behaviors/HeatStorage.cs b/Assets/Scripts/ServerShared/Behaviors/HeatStorage.cs index b8f52df84..aeeea7538 100644 --- a/Assets/Scripts/ServerShared/Behaviors/HeatStorage.cs +++ b/Assets/Scripts/ServerShared/Behaviors/HeatStorage.cs @@ -6,26 +6,13 @@ using System.Collections.Generic; using Unity.Mathematics; using static Unity.Mathematics.math; -[Inspectable] -public class HeatStorageConfig : RuntimeBehaviorConfig -{ - public override Behavior CreateInstance(EquippedItem item) - { - return new HeatStorage(this, item); - } - public override Behavior CreateInstance(ConsumableItemEffect item) - { - return new HeatStorage(this, item); - } -} - public class HeatStorage : Behavior { - public HeatStorage(HeatStorageConfig data, EquippedItem item) : base(data, item) + public HeatStorage(RuntimeBehaviorDefinition definition, EquippedItem item) : base(definition, item) { } - public HeatStorage(HeatStorageConfig data, ConsumableItemEffect item) : base(data, item) + public HeatStorage(RuntimeBehaviorDefinition definition, ConsumableItemEffect item) : base(definition, item) { } } diff --git a/Assets/Scripts/ServerShared/Behaviors/Switch.cs b/Assets/Scripts/ServerShared/Behaviors/Switch.cs index 368911124..ce9ec9e1e 100644 --- a/Assets/Scripts/ServerShared/Behaviors/Switch.cs +++ b/Assets/Scripts/ServerShared/Behaviors/Switch.cs @@ -4,27 +4,14 @@ using System; using System.Linq; -[Inspectable, Order(-25)] -public class SwitchConfig : RuntimeBehaviorConfig -{ - public override Behavior CreateInstance(EquippedItem item) - { - return new Switch(this, item); - } - public override Behavior CreateInstance(ConsumableItemEffect item) - { - return new Switch(this, item); - } -} - public class Switch : Behavior, IActivatedBehavior { public bool Activated { get; set; } - public Switch(SwitchConfig data, EquippedItem item) : base(data, item) + public Switch(RuntimeBehaviorDefinition definition, EquippedItem item) : base(definition, item) { } - public Switch(SwitchConfig data, ConsumableItemEffect item) : base(data, item) + public Switch(RuntimeBehaviorDefinition definition, ConsumableItemEffect item) : base(definition, item) { } diff --git a/Assets/Scripts/ServerShared/Behaviors/Trigger.cs b/Assets/Scripts/ServerShared/Behaviors/Trigger.cs index 3c60f133a..1080fb15f 100644 --- a/Assets/Scripts/ServerShared/Behaviors/Trigger.cs +++ b/Assets/Scripts/ServerShared/Behaviors/Trigger.cs @@ -4,26 +4,13 @@ using System; using System.Linq; -[Inspectable, Order(-20)] -public class TriggerConfig : RuntimeBehaviorConfig -{ - public override Behavior CreateInstance(EquippedItem item) - { - return new Trigger(this, item); - } - public override Behavior CreateInstance(ConsumableItemEffect item) - { - return new Trigger(this, item); - } -} - public class Trigger : Behavior, IActivatedBehavior { public bool _pulled; public bool Pulled => _pulled; - public Trigger(TriggerConfig data, EquippedItem item) : base(data, item) { } - public Trigger(TriggerConfig data, ConsumableItemEffect item) : base(data, item) { } + public Trigger(RuntimeBehaviorDefinition definition, EquippedItem item) : base(definition, item) { } + public Trigger(RuntimeBehaviorDefinition definition, ConsumableItemEffect item) : base(definition, item) { } public override bool Execute(float dt) { diff --git a/Assets/Scripts/ServerShared/Behaviors/TurretController.cs b/Assets/Scripts/ServerShared/Behaviors/TurretController.cs index b374b313a..718212ed3 100644 --- a/Assets/Scripts/ServerShared/Behaviors/TurretController.cs +++ b/Assets/Scripts/ServerShared/Behaviors/TurretController.cs @@ -8,18 +8,6 @@ using UniRx; using Unity.Mathematics; using static Unity.Mathematics.math; using float3 = Unity.Mathematics.float3; -public class TurretControllerConfig : RuntimeBehaviorConfig -{ - public override Behavior CreateInstance(EquippedItem item) - { - return new TurretController(this, item); - } - public override Behavior CreateInstance(ConsumableItemEffect item) - { - return new TurretController(this, item); - } -} - public class TurretController : Behavior, IInitializableBehavior { private List _weapons = new List(); @@ -30,11 +18,11 @@ public class TurretController : Behavior, IInitializableBehavior public float ShotSpeed => _shotSpeed; public bool PredictShots => _predictShots; - public TurretController(TurretControllerConfig data, EquippedItem item) : base(data, item) + public TurretController(RuntimeBehaviorDefinition definition, EquippedItem item) : base(definition, item) { } - public TurretController(TurretControllerConfig data, ConsumableItemEffect item) : base(data, item) + public TurretController(RuntimeBehaviorDefinition definition, ConsumableItemEffect item) : base(definition, item) { } diff --git a/Assets/Scripts/ServerShared/ItemManager.cs b/Assets/Scripts/ServerShared/ItemManager.cs index 4037a18ed..d70b100c9 100644 --- a/Assets/Scripts/ServerShared/ItemManager.cs +++ b/Assets/Scripts/ServerShared/ItemManager.cs @@ -61,32 +61,58 @@ public class ItemManager public Behavior[] CreateRuntimeBehaviors(EquippedItem item) { - return CreateRuntimeBehaviorConfigs(item?.EquippableItem) - .Select(config => config.CreateInstance(item)) - .ToArray(); + return GetRuntimeItem(item?.EquippableItem)?.BehaviorPayloads + .Select(payload => CreateRuntimeBehavior(payload, item)) + .Where(behavior => behavior != null) + .ToArray() ?? Array.Empty(); } public Behavior[] CreateRuntimeBehaviors(ConsumableItemEffect effect) { - return CreateRuntimeBehaviorConfigs(effect?.Item) - .Select(config => config.CreateInstance(effect)) - .ToArray(); - } - - private IReadOnlyList CreateRuntimeBehaviorConfigs(ItemInstance item) - { - var typedItem = GetRuntimeItem(item); - return typedItem == null - ? Array.Empty() - : BuildBehaviorConfigs(typedItem); - } - - private static RuntimeBehaviorConfig[] BuildBehaviorConfigs(AetheriaRuntimeCatalogItem item) - { - return item.BehaviorPayloads - .Select(BuildBehaviorConfig) + return GetRuntimeItem(effect?.Item)?.BehaviorPayloads + .Select(payload => CreateRuntimeBehavior(payload, effect)) .Where(behavior => behavior != null) - .ToArray(); + .ToArray() ?? Array.Empty(); + } + + private static Behavior CreateRuntimeBehavior(AetheriaRuntimeBehaviorPayload payload, EquippedItem item) + { + var directBehavior = CreateDirectRuntimeBehavior(payload, item); + return directBehavior ?? BuildBehaviorConfig(payload)?.CreateInstance(item); + } + + private static Behavior CreateRuntimeBehavior(AetheriaRuntimeBehaviorPayload payload, ConsumableItemEffect effect) + { + var directBehavior = CreateDirectRuntimeBehavior(payload, effect); + return directBehavior ?? BuildBehaviorConfig(payload)?.CreateInstance(effect); + } + + private static Behavior CreateDirectRuntimeBehavior(AetheriaRuntimeBehaviorPayload payload, EquippedItem item) + { + var definition = new RuntimeBehaviorDefinition(payload); + switch (payload.Kind) + { + case "Cockpit": return new Cockpit(definition, item); + case "HeatStorage": return new HeatStorage(definition, item); + case "Switch": return new Switch(definition, item); + case "Trigger": return new Trigger(definition, item); + case "TurretController": return new TurretController(definition, item); + default: return null; + } + } + + private static Behavior CreateDirectRuntimeBehavior(AetheriaRuntimeBehaviorPayload payload, ConsumableItemEffect effect) + { + var definition = new RuntimeBehaviorDefinition(payload); + switch (payload.Kind) + { + case "Cockpit": return new Cockpit(definition, effect); + case "HeatStorage": return new HeatStorage(definition, effect); + case "Switch": return new Switch(definition, effect); + case "Trigger": return new Trigger(definition, effect); + case "TurretController": return new TurretController(definition, effect); + default: return null; + } } private static RuntimeBehaviorConfig BuildBehaviorConfig(AetheriaRuntimeBehaviorPayload payload) @@ -97,13 +123,11 @@ public class ItemManager case "AutoWeapon": return Configure(new AutoWeaponConfig(), payload, ApplyInstantWeaponConfig); case "Capacitor": return Configure(new CapacitorConfig(), payload, ApplyCapacitorConfig); case "ChargedWeapon": return Configure(new ChargedWeaponConfig(), payload, ApplyChargedWeaponConfig); - case "Cockpit": return Configure(new CockpitConfig(), payload, null); case "ConstantWeapon": return Configure(new ConstantWeaponConfig(), payload, ApplyConstantWeaponConfig); case "Cooldown": return Configure(new CooldownConfig(), payload, ApplyCooldownConfig); case "EnergyDraw": return Configure(new EnergyDrawConfig(), payload, ApplyEnergyDrawConfig); case "GuidedWeapon": return Configure(new GuidedWeaponConfig(), payload, ApplyGuidedWeaponConfig); case "Heat": return Configure(new HeatConfig(), payload, ApplyHeatConfig); - case "HeatStorage": return Configure(new HeatStorageConfig(), payload, null); case "InstantWeapon": return Configure(new InstantWeaponConfig(), payload, ApplyInstantWeaponConfig); case "ItemUsage": return Configure(new ItemUsageConfig(), payload, ApplyItemUsageConfig); case "Launcher": return Configure(new LauncherConfig(), payload, ApplyLauncherConfig); @@ -115,11 +139,8 @@ public class ItemManager case "Sensor": return Configure(new SensorConfig(), payload, ApplySensorConfig); case "Shield": return Configure(new ShieldConfig(), payload, ApplyShieldConfig); case "StatModifier": return Configure(new StatModifierConfig(), payload, ApplyStatModifierConfig); - case "Switch": return Configure(new SwitchConfig(), payload, null); case "Thermotoggle": return Configure(new ThermotoggleConfig(), payload, ApplyThermotoggleConfig); case "Thruster": return Configure(new ThrusterConfig(), payload, ApplyThrusterConfig); - case "Trigger": return Configure(new TriggerConfig(), payload, null); - case "TurretController": return Configure(new TurretControllerConfig(), payload, null); case "VelocityConversion": return Configure(new VelocityConversionConfig(), payload, ApplyVelocityConversionConfig); case "VelocityLimit": return Configure(new VelocityLimitConfig(), payload, ApplyVelocityLimitConfig); case "Visibility": return Configure(new VisibilityConfig(), payload, ApplyVisibilityConfig); diff --git a/docs/aetheria-perfect-machine-map.md b/docs/aetheria-perfect-machine-map.md index 436f6b8d1..96011fedc 100644 --- a/docs/aetheria-perfect-machine-map.md +++ b/docs/aetheria-perfect-machine-map.md @@ -322,6 +322,9 @@ legacy catalog cache, and legacy UI paths should be migration-only or deleted. fields, burst/cooldown fields, charge multipliers, and lock parameters into runtime-owned fields. Behavior instances no longer retain their `RuntimeBehaviorConfig` subclasses after construction. + Cockpit, HeatStorage, Switch, Trigger, and TurretController now bypass + `RuntimeBehaviorConfig` entirely; `ItemManager` constructs those no-payload + behavior classes directly from typed runtime behavior definitions. `StatModifier` behavior requirements and behavior-stat targets compare typed behavior kinds on the live equipped behavior instances through `AetheriaRuntimeBehaviorMetadataCatalog` instead of scanning config @@ -1450,6 +1453,11 @@ First Aetheria surfaces to publish: all behavior subclasses now copy constructor config inputs into explicit runtime fields instead of keeping `RuntimeBehaviorConfig` subclass instances alive as state. + - Done: delete the no-payload `CockpitConfig`, `HeatStorageConfig`, + `SwitchConfig`, `TriggerConfig`, and `TurretControllerConfig` classes. + `ItemManager` now constructs those behavior kinds directly from typed + runtime behavior definitions rather than routing them through the + temporary config bridge. - Done: delete `LegacyPayloadKeyAttribute` from live Unity source after importer constants and explicit typed mappers became the only migrated field-key authorities.