Bypass configs for simple behaviors

This commit is contained in:
Meta Vens 2026-06-15 19:06:13 +01:00
commit b97bf31b50
14 changed files with 152 additions and 256 deletions

Binary file not shown.

View file

@ -201,6 +201,10 @@ after construction.
Cockpit, HeatStorage, Switch, Trigger, and TurretController no longer have
`RuntimeBehaviorConfig` subclasses at all; `ItemManager` constructs them
directly from typed runtime behavior definitions.
Heat, EnergyDraw, Cooldown, Wear, Visibility, Reflector, VelocityLimit,
VelocityConversion, and ItemUsage also bypass the temporary config bridge and
read typed behavior fields through `RuntimeBehaviorDefinition`, registering
runtime performance stats explicitly for `StatModifier`.
`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

View file

@ -95,6 +95,14 @@ public abstract class Behavior
return false;
}
protected void RegisterPerformanceStat(string statName, PerformanceStat stat)
{
if (!string.IsNullOrWhiteSpace(statName) && stat != null)
{
_performanceStats[statName] = stat;
}
}
private static Dictionary<string, PerformanceStat> CapturePerformanceStats(RuntimeBehaviorConfig config)
{
return config == null
@ -186,6 +194,8 @@ public interface IPopulationAssignment
public sealed class RuntimeBehaviorDefinition
{
private readonly IReadOnlyDictionary<int, AetheriaRuntimeBehaviorValue> _fields;
public string Kind { get; }
public int Group { get; }
@ -193,6 +203,55 @@ public sealed class RuntimeBehaviorDefinition
{
Kind = payload?.Kind ?? "";
Group = payload?.Group ?? 0;
var fields = new Dictionary<int, AetheriaRuntimeBehaviorValue>();
if (payload != null)
{
foreach (var field in payload.Fields)
{
if (!fields.ContainsKey(field.Key))
{
fields.Add(field.Key, field.Value);
}
}
}
_fields = fields;
}
public bool Bool(int key, bool fallback = false)
{
return _fields.TryGetValue(key, out var value) ? value.BoolValue : fallback;
}
public string ItemKey(int key, string fallback = "")
{
return _fields.TryGetValue(key, out var value) &&
!string.IsNullOrWhiteSpace(value.ItemKeyValue)
? value.ItemKeyValue
: fallback;
}
public PerformanceStat PerformanceStat(int key, PerformanceStat fallback)
{
return _fields.TryGetValue(key, out var value) ? ToPerformanceStat(value) : fallback;
}
private static PerformanceStat ToPerformanceStat(AetheriaRuntimeBehaviorValue value)
{
return new PerformanceStat
{
Min = ChildFloat(value, 0),
Max = ChildFloat(value, 1),
HeatExponentMultiplier = ChildFloat(value, 2),
DurabilityExponentMultiplier = ChildFloat(value, 3),
QualityExponent = ChildFloat(value, 4)
};
}
private static float ChildFloat(AetheriaRuntimeBehaviorValue value, int index)
{
return value.Children.Count > index ? (float)value.Children[index].NumberValue : 0;
}
}

View file

@ -7,23 +7,6 @@ using System.Linq;
using Unity.Mathematics;
using static Unity.Mathematics.math;
[Inspectable, Order(-10)]
public class CooldownConfig : RuntimeBehaviorConfig
{
[Inspectable]
public PerformanceStat Cooldown = new PerformanceStat();
public override Behavior CreateInstance(EquippedItem item)
{
return new Cooldown(this, item);
}
public override Behavior CreateInstance(ConsumableItemEffect item)
{
return new Cooldown(this, item);
}
}
public class Cooldown : Behavior, IAlwaysUpdatedBehavior, IProgressBehavior
{
private readonly PerformanceStat _cooldownDuration;
@ -32,14 +15,16 @@ public class Cooldown : Behavior, IAlwaysUpdatedBehavior, IProgressBehavior
public float Progress => saturate(_cooldown);
public Cooldown(CooldownConfig data, EquippedItem item) : base(data, item)
public Cooldown(RuntimeBehaviorDefinition definition, EquippedItem item) : base(definition, item)
{
_cooldownDuration = data.Cooldown;
_cooldownDuration = definition.PerformanceStat(1, new PerformanceStat());
RegisterPerformanceStat(nameof(Cooldown), _cooldownDuration);
}
public Cooldown(CooldownConfig data, ConsumableItemEffect item) : base(data, item)
public Cooldown(RuntimeBehaviorDefinition definition, ConsumableItemEffect item) : base(definition, item)
{
_cooldownDuration = data.Cooldown;
_cooldownDuration = definition.PerformanceStat(1, new PerformanceStat());
RegisterPerformanceStat(nameof(Cooldown), _cooldownDuration);
}
public override bool Execute(float dt)

View file

@ -4,41 +4,23 @@
using System;
using System.Linq;
[Inspectable, Order(-20)]
public class EnergyDrawConfig : RuntimeBehaviorConfig
{
[Inspectable]
public PerformanceStat EnergyDraw = new PerformanceStat();
[Inspectable]
public bool PerSecond;
public override Behavior CreateInstance(EquippedItem item)
{
return new EnergyDraw(this, item);
}
public override Behavior CreateInstance(ConsumableItemEffect item)
{
return new EnergyDraw(this, item);
}
}
public class EnergyDraw : Behavior
{
private readonly PerformanceStat _energyDraw;
private readonly bool _perSecond;
public EnergyDraw(EnergyDrawConfig data, EquippedItem item) : base(data, item)
public EnergyDraw(RuntimeBehaviorDefinition definition, EquippedItem item) : base(definition, item)
{
_energyDraw = data.EnergyDraw;
_perSecond = data.PerSecond;
_energyDraw = definition.PerformanceStat(1, new PerformanceStat());
_perSecond = definition.Bool(2);
RegisterPerformanceStat(nameof(EnergyDraw), _energyDraw);
}
public EnergyDraw(EnergyDrawConfig data, ConsumableItemEffect item) : base(data, item)
public EnergyDraw(RuntimeBehaviorDefinition definition, ConsumableItemEffect item) : base(definition, item)
{
_energyDraw = data.EnergyDraw;
_perSecond = data.PerSecond;
_energyDraw = definition.PerformanceStat(1, new PerformanceStat());
_perSecond = definition.Bool(2);
RegisterPerformanceStat(nameof(EnergyDraw), _energyDraw);
}
public override bool Execute(float dt)

View file

@ -4,40 +4,23 @@
using System;
using System.Linq;
[Inspectable, Order(10)]
public class HeatConfig : RuntimeBehaviorConfig
{
[Inspectable]
public PerformanceStat Heat = new PerformanceStat();
[Inspectable]
public bool PerSecond;
public override Behavior CreateInstance(EquippedItem item)
{
return new Heat(this, item);
}
public override Behavior CreateInstance(ConsumableItemEffect item)
{
return new Heat(this, item);
}
}
public class Heat : Behavior
{
private readonly PerformanceStat _heat;
private readonly bool _perSecond;
public Heat(HeatConfig data, EquippedItem item) : base(data, item)
public Heat(RuntimeBehaviorDefinition definition, EquippedItem item) : base(definition, item)
{
_heat = data.Heat;
_perSecond = data.PerSecond;
_heat = definition.PerformanceStat(1, new PerformanceStat());
_perSecond = definition.Bool(2);
RegisterPerformanceStat(nameof(Heat), _heat);
}
public Heat(HeatConfig data, ConsumableItemEffect item) : base(data, item)
public Heat(RuntimeBehaviorDefinition definition, ConsumableItemEffect item) : base(definition, item)
{
_heat = data.Heat;
_perSecond = data.PerSecond;
_heat = definition.PerformanceStat(1, new PerformanceStat());
_perSecond = definition.Bool(2);
RegisterPerformanceStat(nameof(Heat), _heat);
}
public override bool Execute(float dt)

View file

@ -3,34 +3,18 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
using System.Linq;
[Inspectable, Order(-5)]
public class ItemUsageConfig : RuntimeBehaviorConfig
{
public string ItemKey;
public override Behavior CreateInstance(EquippedItem item)
{
return new ItemUsage(this, item);
}
public override Behavior CreateInstance(ConsumableItemEffect item)
{
return new ItemUsage(this, item);
}
}
public class ItemUsage : Behavior
{
private readonly string _itemKey;
public ItemUsage(ItemUsageConfig data, EquippedItem item) : base(data, item)
public ItemUsage(RuntimeBehaviorDefinition definition, EquippedItem item) : base(definition, item)
{
_itemKey = data.ItemKey;
_itemKey = definition.ItemKey(1);
}
public ItemUsage(ItemUsageConfig data, ConsumableItemEffect item) : base(data, item)
public ItemUsage(RuntimeBehaviorDefinition definition, ConsumableItemEffect item) : base(definition, item)
{
_itemKey = data.ItemKey;
_itemKey = definition.ItemKey(1);
}
public override bool Execute(float dt)

View file

@ -5,38 +5,20 @@
using Unity.Mathematics;
using static Unity.Mathematics.math;
[Inspectable]
public class ReflectorConfig : RuntimeBehaviorConfig
{
[Inspectable]
public PerformanceStat CrossSection = new PerformanceStat();
// [InspectableAnimationCurve]
// public float4[] VisibilityCurve;
public override Behavior CreateInstance(EquippedItem item)
{
return new Reflector(this, item);
}
public override Behavior CreateInstance(ConsumableItemEffect item)
{
return new Reflector(this, item);
}
}
public class Reflector : Behavior
{
private readonly PerformanceStat _crossSection;
public Reflector(ReflectorConfig data, EquippedItem item) : base(data, item)
public Reflector(RuntimeBehaviorDefinition definition, EquippedItem item) : base(definition, item)
{
_crossSection = data.CrossSection;
_crossSection = definition.PerformanceStat(1, new PerformanceStat());
RegisterPerformanceStat("CrossSection", _crossSection);
}
public Reflector(ReflectorConfig data, ConsumableItemEffect item) : base(data, item)
public Reflector(RuntimeBehaviorDefinition definition, ConsumableItemEffect item) : base(definition, item)
{
_crossSection = data.CrossSection;
_crossSection = definition.PerformanceStat(1, new PerformanceStat());
RegisterPerformanceStat("CrossSection", _crossSection);
}
public override bool Execute(float dt)

View file

@ -4,32 +4,20 @@
using Unity.Mathematics;
using static Unity.Mathematics.math;
public class VelocityConversionConfig : RuntimeBehaviorConfig
{
[Inspectable]
public PerformanceStat Lambda = new PerformanceStat();
public override Behavior CreateInstance(EquippedItem item)
{
return new VelocityConversion(this, item);
}
public override Behavior CreateInstance(ConsumableItemEffect item)
{
return new VelocityConversion(this, item);
}
}
public class VelocityConversion : Behavior
{
private readonly PerformanceStat _lambda;
public VelocityConversion(VelocityConversionConfig data, EquippedItem item) : base(data, item)
public VelocityConversion(RuntimeBehaviorDefinition definition, EquippedItem item) : base(definition, item)
{
_lambda = data.Lambda;
_lambda = definition.PerformanceStat(1, new PerformanceStat());
RegisterPerformanceStat("Lambda", _lambda);
}
public VelocityConversion(VelocityConversionConfig data, ConsumableItemEffect item) : base(data, item)
public VelocityConversion(RuntimeBehaviorDefinition definition, ConsumableItemEffect item) : base(definition, item)
{
_lambda = data.Lambda;
_lambda = definition.PerformanceStat(1, new PerformanceStat());
RegisterPerformanceStat("Lambda", _lambda);
}
public override bool Execute(float dt)

View file

@ -5,22 +5,6 @@
using Unity.Mathematics;
using static Unity.Mathematics.math;
[Inspectable]
public class VelocityLimitConfig : RuntimeBehaviorConfig
{
[Inspectable]
public PerformanceStat TopSpeed = new PerformanceStat();
public override Behavior CreateInstance(EquippedItem item)
{
return new VelocityLimit(this, item);
}
public override Behavior CreateInstance(ConsumableItemEffect item)
{
return new VelocityLimit(this, item);
}
}
[Order(100)]
public class VelocityLimit : Behavior
{
@ -28,15 +12,17 @@ public class VelocityLimit : Behavior
private readonly PerformanceStat _topSpeed;
public VelocityLimit(VelocityLimitConfig data, EquippedItem item) : base(data, item)
public VelocityLimit(RuntimeBehaviorDefinition definition, EquippedItem item) : base(definition, item)
{
_topSpeed = data.TopSpeed;
_topSpeed = definition.PerformanceStat(1, new PerformanceStat());
RegisterPerformanceStat("TopSpeed", _topSpeed);
Limit = Evaluate(_topSpeed);
}
public VelocityLimit(VelocityLimitConfig data, ConsumableItemEffect item) : base(data, item)
public VelocityLimit(RuntimeBehaviorDefinition definition, ConsumableItemEffect item) : base(definition, item)
{
_topSpeed = data.TopSpeed;
_topSpeed = definition.PerformanceStat(1, new PerformanceStat());
RegisterPerformanceStat("TopSpeed", _topSpeed);
Limit = Evaluate(_topSpeed);
}

View file

@ -4,36 +4,22 @@
using System;
using System.Linq;
[Inspectable]
public class VisibilityConfig : RuntimeBehaviorConfig
{
[Inspectable]
public PerformanceStat Visibility = new PerformanceStat();
[Inspectable]
public PerformanceStat VisibilityDecay = new PerformanceStat();
public override Behavior CreateInstance(EquippedItem item)
{
return new Visibility(this, item);
}
public override Behavior CreateInstance(ConsumableItemEffect item)
{
return new Visibility(this, item);
}
}
public class Visibility : Behavior
{
private readonly PerformanceStat _visibility;
public Visibility(VisibilityConfig data, EquippedItem item) : base(data, item)
public Visibility(RuntimeBehaviorDefinition definition, EquippedItem item) : base(definition, item)
{
_visibility = data.Visibility;
_visibility = definition.PerformanceStat(1, new PerformanceStat());
RegisterPerformanceStat(nameof(Visibility), _visibility);
RegisterPerformanceStat("VisibilityDecay", definition.PerformanceStat(2, new PerformanceStat()));
}
public Visibility(VisibilityConfig data, ConsumableItemEffect item) : base(data, item)
public Visibility(RuntimeBehaviorDefinition definition, ConsumableItemEffect item) : base(definition, item)
{
_visibility = data.Visibility;
_visibility = definition.PerformanceStat(1, new PerformanceStat());
RegisterPerformanceStat(nameof(Visibility), _visibility);
RegisterPerformanceStat("VisibilityDecay", definition.PerformanceStat(2, new PerformanceStat()));
}
public override bool Execute(float dt)

View file

@ -6,33 +6,18 @@ using System.Collections.Generic;
using Unity.Mathematics;
using static Unity.Mathematics.math;
[Inspectable, Order(1000)]
public class WearConfig : RuntimeBehaviorConfig
{
[InspectableTemperature]
public bool PerSecond = true;
public override Behavior CreateInstance(EquippedItem item)
{
return new Wear(this, item);
}
public override Behavior CreateInstance(ConsumableItemEffect item)
{
return new Wear(this, item);
}
}
public class Wear : Behavior
{
private readonly bool _perSecond;
public Wear(WearConfig data, EquippedItem item) : base(data, item)
public Wear(RuntimeBehaviorDefinition definition, EquippedItem item) : base(definition, item)
{
_perSecond = data.PerSecond;
_perSecond = definition.Bool(1, true);
}
public Wear(WearConfig data, ConsumableItemEffect item) : base(data, item)
public Wear(RuntimeBehaviorDefinition definition, ConsumableItemEffect item) : base(definition, item)
{
_perSecond = data.PerSecond;
_perSecond = definition.Bool(1, true);
}
public override bool Execute(float dt)

View file

@ -93,10 +93,19 @@ public class ItemManager
switch (payload.Kind)
{
case "Cockpit": return new Cockpit(definition, item);
case "Cooldown": return new Cooldown(definition, item);
case "EnergyDraw": return new EnergyDraw(definition, item);
case "Heat": return new Heat(definition, item);
case "HeatStorage": return new HeatStorage(definition, item);
case "ItemUsage": return new ItemUsage(definition, item);
case "Reflector": return new Reflector(definition, item);
case "Switch": return new Switch(definition, item);
case "Trigger": return new Trigger(definition, item);
case "TurretController": return new TurretController(definition, item);
case "VelocityConversion": return new VelocityConversion(definition, item);
case "VelocityLimit": return new VelocityLimit(definition, item);
case "Visibility": return new Visibility(definition, item);
case "Wear": return new Wear(definition, item);
default: return null;
}
}
@ -107,10 +116,19 @@ public class ItemManager
switch (payload.Kind)
{
case "Cockpit": return new Cockpit(definition, effect);
case "Cooldown": return new Cooldown(definition, effect);
case "EnergyDraw": return new EnergyDraw(definition, effect);
case "Heat": return new Heat(definition, effect);
case "HeatStorage": return new HeatStorage(definition, effect);
case "ItemUsage": return new ItemUsage(definition, effect);
case "Reflector": return new Reflector(definition, effect);
case "Switch": return new Switch(definition, effect);
case "Trigger": return new Trigger(definition, effect);
case "TurretController": return new TurretController(definition, effect);
case "VelocityConversion": return new VelocityConversion(definition, effect);
case "VelocityLimit": return new VelocityLimit(definition, effect);
case "Visibility": return new Visibility(definition, effect);
case "Wear": return new Wear(definition, effect);
default: return null;
}
}
@ -124,27 +142,18 @@ public class ItemManager
case "Capacitor": return Configure(new CapacitorConfig(), payload, ApplyCapacitorConfig);
case "ChargedWeapon": return Configure(new ChargedWeaponConfig(), payload, ApplyChargedWeaponConfig);
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 "InstantWeapon": return Configure(new InstantWeaponConfig(), payload, ApplyInstantWeaponConfig);
case "ItemUsage": return Configure(new ItemUsageConfig(), payload, ApplyItemUsageConfig);
case "Launcher": return Configure(new LauncherConfig(), payload, ApplyLauncherConfig);
case "MiningTool": return Configure(new MiningToolConfig(), payload, ApplyMiningToolConfig);
case "Radiator": return Configure(new RadiatorConfig(), payload, ApplyRadiatorConfig);
case "Reactor": return Configure(new ReactorConfig(), payload, ApplyReactorConfig);
case "Reflector": return Configure(new ReflectorConfig(), payload, ApplyReflectorConfig);
case "ResourceScanner": return Configure(new ResourceScannerConfig(), payload, ApplyResourceScannerConfig);
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 "Thermotoggle": return Configure(new ThermotoggleConfig(), payload, ApplyThermotoggleConfig);
case "Thruster": return Configure(new ThrusterConfig(), payload, ApplyThrusterConfig);
case "VelocityConversion": return Configure(new VelocityConversionConfig(), payload, ApplyVelocityConversionConfig);
case "VelocityLimit": return Configure(new VelocityLimitConfig(), payload, ApplyVelocityLimitConfig);
case "Visibility": return Configure(new VisibilityConfig(), payload, ApplyVisibilityConfig);
case "Wear": return Configure(new WearConfig(), payload, ApplyWearConfig);
default: return null;
}
}
@ -182,28 +191,6 @@ public class ItemManager
config.Efficiency = reader.PerformanceStat(2, config.Efficiency);
}
private static void ApplyCooldownConfig(CooldownConfig config, BehaviorPayloadReader reader)
{
config.Cooldown = reader.PerformanceStat(1, config.Cooldown);
}
private static void ApplyEnergyDrawConfig(EnergyDrawConfig config, BehaviorPayloadReader reader)
{
config.EnergyDraw = reader.PerformanceStat(1, config.EnergyDraw);
config.PerSecond = reader.Bool(2, config.PerSecond);
}
private static void ApplyHeatConfig(HeatConfig config, BehaviorPayloadReader reader)
{
config.Heat = reader.PerformanceStat(1, config.Heat);
config.PerSecond = reader.Bool(2, config.PerSecond);
}
private static void ApplyItemUsageConfig(ItemUsageConfig config, BehaviorPayloadReader reader)
{
config.ItemKey = reader.ItemKey(1, config.ItemKey);
}
private static void ApplyMiningToolConfig(MiningToolConfig config, BehaviorPayloadReader reader)
{
config.DamagePerSecond = reader.PerformanceStat(1, config.DamagePerSecond);
@ -230,11 +217,6 @@ public class ItemManager
config.ThrottlingFactor = reader.PerformanceStat(4, config.ThrottlingFactor);
}
private static void ApplyReflectorConfig(ReflectorConfig config, BehaviorPayloadReader reader)
{
config.CrossSection = reader.PerformanceStat(1, config.CrossSection);
}
private static void ApplyResourceScannerConfig(ResourceScannerConfig config, BehaviorPayloadReader reader)
{
config.Range = reader.PerformanceStat(1, config.Range);
@ -285,27 +267,6 @@ public class ItemManager
config.ParticlesPrefab = reader.String(5, config.ParticlesPrefab);
}
private static void ApplyVelocityConversionConfig(VelocityConversionConfig config, BehaviorPayloadReader reader)
{
config.Lambda = reader.PerformanceStat(1, config.Lambda);
}
private static void ApplyVelocityLimitConfig(VelocityLimitConfig config, BehaviorPayloadReader reader)
{
config.TopSpeed = reader.PerformanceStat(1, config.TopSpeed);
}
private static void ApplyVisibilityConfig(VisibilityConfig config, BehaviorPayloadReader reader)
{
config.Visibility = reader.PerformanceStat(1, config.Visibility);
config.VisibilityDecay = reader.PerformanceStat(2, config.VisibilityDecay);
}
private static void ApplyWearConfig(WearConfig config, BehaviorPayloadReader reader)
{
config.PerSecond = reader.Bool(1, config.PerSecond);
}
private static void ApplyWeaponConfig(WeaponConfig config, BehaviorPayloadReader reader)
{
config.DamageType = reader.Enum(1, config.DamageType);

View file

@ -325,6 +325,11 @@ legacy catalog cache, and legacy UI paths should be migration-only or deleted.
Cockpit, HeatStorage, Switch, Trigger, and TurretController now bypass
`RuntimeBehaviorConfig` entirely; `ItemManager` constructs those no-payload
behavior classes directly from typed runtime behavior definitions.
Heat, EnergyDraw, Cooldown, Wear, Visibility, Reflector, VelocityLimit,
VelocityConversion, and ItemUsage also bypass the temporary config bridge and
read typed behavior fields through `RuntimeBehaviorDefinition`; stat-bearing
behaviors register their runtime performance stats explicitly for
`StatModifier` rather than relying on config reflection.
`StatModifier` behavior requirements and behavior-stat targets compare typed
behavior kinds on the live equipped behavior instances through
`AetheriaRuntimeBehaviorMetadataCatalog` instead of scanning config
@ -1458,6 +1463,12 @@ First Aetheria surfaces to publish:
`ItemManager` now constructs those behavior kinds directly from typed
runtime behavior definitions rather than routing them through the
temporary config bridge.
- Done: delete the simple field-bearing `HeatConfig`, `EnergyDrawConfig`,
`CooldownConfig`, `WearConfig`, `VisibilityConfig`, `ReflectorConfig`,
`VelocityLimitConfig`, `VelocityConversionConfig`, and `ItemUsageConfig`
classes. `RuntimeBehaviorDefinition` now owns the typed field reads for
those behavior kinds, and the live behaviors explicitly register their
performance stats for `StatModifier`.
- Done: delete `LegacyPayloadKeyAttribute` from live Unity source after
importer constants and explicit typed mappers became the only migrated
field-key authorities.