diff --git a/.voidbot/state/aetheria.cc b/.voidbot/state/aetheria.cc index 7b27f0535..5e0aad0cd 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 5ec061f9a..283729998 100644 --- a/Aetheria.State/README.md +++ b/Aetheria.State/README.md @@ -176,7 +176,9 @@ documents exist. Live behavior instances expose typed behavior kind and group through `Behavior.Kind` and `Behavior.Group`; the remaining `RuntimeBehaviorConfig` objects are private construction configs, not runtime identity owners or a public behavior API. Stat modifiers ask live behavior -instances for target stats instead of reading behavior config objects directly. +instances for target stats instead of reading behavior config objects directly; +base `Behavior` captures a runtime stat table at construction and no longer +retains the config object for later reflection. `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/Behaviors/Behaviors.cs b/Assets/Scripts/ServerShared/Behaviors/Behaviors.cs index 6c72328ce..3033ae2f2 100644 --- a/Assets/Scripts/ServerShared/Behaviors/Behaviors.cs +++ b/Assets/Scripts/ServerShared/Behaviors/Behaviors.cs @@ -12,7 +12,7 @@ using static Unity.Mathematics.noise; public abstract class Behavior { - private readonly RuntimeBehaviorConfig _config; + private readonly Dictionary _performanceStats; public string Kind { get; } public int Group { get; } public EquippedItem Item { get; } @@ -46,7 +46,7 @@ public abstract class Behavior protected Behavior(RuntimeBehaviorConfig config, EquippedItem item) { - _config = config; + _performanceStats = CapturePerformanceStats(config); Kind = config?.Kind ?? ""; Group = config?.Group ?? 0; Item = item; @@ -55,7 +55,7 @@ public abstract class Behavior protected Behavior(RuntimeBehaviorConfig config, ConsumableItemEffect consumable) { - _config = config; + _performanceStats = CapturePerformanceStats(config); Kind = config?.Kind ?? ""; Group = config?.Group ?? 0; Consumable = consumable; @@ -66,18 +66,21 @@ public abstract class Behavior public bool TryGetPerformanceStat(string statName, out PerformanceStat stat) { - stat = null; - if (_config == null || string.IsNullOrWhiteSpace(statName)) - { - return false; - } + return !string.IsNullOrWhiteSpace(statName) && + _performanceStats.TryGetValue(statName, out stat); + } - var statField = _config - .GetType() - .GetFields() - .FirstOrDefault(field => field.FieldType == typeof(PerformanceStat) && field.Name == statName); - stat = statField?.GetValue(_config) as PerformanceStat; - return stat != null; + private static Dictionary CapturePerformanceStats(RuntimeBehaviorConfig config) + { + return config == null + ? new Dictionary(StringComparer.Ordinal) + : config + .GetType() + .GetFields() + .Where(field => field.FieldType == typeof(PerformanceStat)) + .Select(field => (field.Name, Stat: field.GetValue(config) as PerformanceStat)) + .Where(entry => entry.Stat != null) + .ToDictionary(entry => entry.Name, entry => entry.Stat, StringComparer.Ordinal); } protected void AddHeat(float heat) => Item?.AddHeat(heat); // TODO: Heat for Consumables diff --git a/docs/aetheria-perfect-machine-map.md b/docs/aetheria-perfect-machine-map.md index b48bed494..255d6d2a5 100644 --- a/docs/aetheria-perfect-machine-map.md +++ b/docs/aetheria-perfect-machine-map.md @@ -302,6 +302,8 @@ legacy catalog cache, and legacy UI paths should be migration-only or deleted. behavior-class construction bridge, not the runtime behavior payload owner; bridge instances carry the typed behavior payload kind so runtime logic does not have to reselect behavior identity from the old class graph. + Base `Behavior` now captures a runtime performance-stat table during + construction and no longer retains the config object for later stat lookup. `StatModifier` behavior requirements and behavior-stat targets compare typed behavior kinds on the live equipped behavior instances through `AetheriaRuntimeBehaviorMetadataCatalog` instead of scanning config