diff --git a/.voidbot/state/aetheria.cc b/.voidbot/state/aetheria.cc index 25f64bdbe..c2f628ab8 100644 Binary files a/.voidbot/state/aetheria.cc and b/.voidbot/state/aetheria.cc differ diff --git a/Assets/Scripts/ServerShared/Behaviors/StatModifier.cs b/Assets/Scripts/ServerShared/Behaviors/StatModifier.cs index 0a0f86a7a..8462303ae 100644 --- a/Assets/Scripts/ServerShared/Behaviors/StatModifier.cs +++ b/Assets/Scripts/ServerShared/Behaviors/StatModifier.cs @@ -67,15 +67,15 @@ public class StatModifier : Behavior, IInitializableBehavior, IDisposable, IAlwa if (typeof(EquippableItemData).IsAssignableFrom(targetType)) _stats = Entity.Equipment .Select(hp => hp.EquippableItem) - .Where(gear => _data.RequireBehavior == null || ItemManager.GetData(gear).Behaviors.Any(behavior => behavior.GetType() == _data.RequireBehavior)) + .Where(HasRequiredBehavior) .Where(gear => ItemManager.GetData(gear).GetType() == targetType) .Select(gear => statField.GetValue(ItemManager.GetData(gear)) as PerformanceStat) .ToArray(); else _stats = Entity.Equipment .Select(hp => hp.EquippableItem) - .Where(gear => _data.RequireBehavior == null || ItemManager.GetData(gear).Behaviors.Any(behavior => behavior.GetType() == _data.RequireBehavior)) - .SelectMany(gear => ItemManager.GetData(gear).Behaviors) + .Where(HasRequiredBehavior) + .SelectMany(gear => ItemManager.GetRuntimeBehaviorProjections(gear)) .Where(behaviorData => behaviorData.GetType() == targetType) .Select(behaviorData => statField.GetValue(behaviorData) as PerformanceStat) .ToArray(); @@ -83,6 +83,13 @@ public class StatModifier : Behavior, IInitializableBehavior, IDisposable, IAlwa } } + private bool HasRequiredBehavior(EquippableItem gear) + { + return _data.RequireBehavior == null || + ItemManager.GetRuntimeBehaviorProjections(gear) + .Any(behavior => behavior.GetType() == _data.RequireBehavior); + } + private void ApplyModifier() { _applied = true; @@ -135,4 +142,4 @@ public class StatReference [Inspectable, LegacyPayloadKey(2)] public string Stat; -} \ No newline at end of file +} diff --git a/docs/aetheria-perfect-machine-map.md b/docs/aetheria-perfect-machine-map.md index 6bafb18ea..42e219800 100644 --- a/docs/aetheria-perfect-machine-map.md +++ b/docs/aetheria-perfect-machine-map.md @@ -199,7 +199,10 @@ legacy catalog cache, and legacy UI paths should be migration-only or deleted. through the runtime behavior projection bridge before instantiating the current `BehaviorData`-backed behavior classes. `BehaviorData` remains the temporary behavior-class config bridge, not the runtime behavior payload - owner. + owner. `StatModifier` behavior requirements and behavior-stat targets also + read that typed behavior projection bridge instead of hydrating + `EquippableItemData.Behaviors`; item performance stat fields are still a + legacy DTO bridge until those stats move to typed runtime rows. Ship drag, combat/turret shot prediction height, and thruster torque geometry now consume typed hull facets and typed shape masks. The item properties panel also reads typed catalog title names, descriptions, @@ -717,6 +720,10 @@ First Aetheria surfaces to publish: - Done: move `EquippedItem` and `ConsumableItemEffect` behavior construction off `Data.Behaviors` and onto typed runtime behavior payload projection; `BehaviorData` remains only the temporary behavior-class config bridge. + - Done: move `StatModifier` behavior requirements and behavior-stat targets + off `EquippableItemData.Behaviors` and onto typed runtime behavior + projections; equippable item performance stat fields remain a separate DTO + bridge. - Done: move runtime blueprint price aggregation and conductivity restore geometry onto typed runtime item price and hull shape rows; legacy `ItemData.Price` and `HullData.Shape` no longer own those blueprint paths.