From c0d0fbf656a3d4d48307ed660fa1c57d95543f20 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Sun, 14 Jun 2026 07:52:18 +0100 Subject: [PATCH] Delete runtime item DTO hydration --- .voidbot/state/aetheria.cc | Bin 75317 -> 75888 bytes .../AetheriaRuntimeItemCatalog.cs | 195 ------------------ Assets/Scripts/ServerShared/Entity.cs | 28 +-- Assets/Scripts/ServerShared/ItemManager.cs | 38 ---- .../RuntimeItemProjectionEntry.cs | 12 -- .../UI/Properties Panel/PropertiesPanel.cs | 23 --- docs/aetheria-perfect-machine-map.md | 80 ++++--- 7 files changed, 49 insertions(+), 327 deletions(-) diff --git a/.voidbot/state/aetheria.cc b/.voidbot/state/aetheria.cc index 5d42001327f0b9822d8b84b0fff45a4839a6a67c..a04a991ce420de14513377da8af2885cdc356898 100644 GIT binary patch delta 1238 zcmZWp&ud&&6y_#VX``i;%yc?!v`3J%fxKrXnkH=)q6Rexwg!nVH+Xxp%zx zzK*l9q04TRE4-~DDij1=ly2&e2yTi>yKL}ZP};o<&wW40fV;;#=brC7-}%nD{d?`v z{o426OdWn{?cz#1Jiq21PdD9fQ#X&4KQ1h1aGK4zblT2TzgD(CV-0t>c4q42i#HZ( zcNS{wr{nW09Bm)9;6aQDS`2h5tr%b+EDnO$s-QoPb@ulm#^dd+A_hJN8}D8MALCXi z3Bo{8AYL!R8oQ`bMrc5)5ky?;F({dg!H$O*7fB*ULbK!W>nP!3u+Nm+4Q8Kw;my1* zF2bg}zTbFi3wew>d;{$wxCc9@o;zz`)K^Kt5;lp>2Dh9*qCP$1GR~ep!A`U;YjqW) zoZpDZfX0EkhH(hlp(dMuHd4}9okmt^PZAO(d#KB%&^`Ebb`F$=*C;I=@J@mi&^nN2 zWB1NRJ^P};W?m*hNDYF-)M}oP5?!7q)v7_CO6i5sG$sgw}-LT9k(VJp9ME zbPS9YNdm)yvdNCmvgRiSgtQ7?#Xi3#l+K$JM4IQib}-@|mdHSqYEs)mr%VMB)EE+< zQ{ObIfST=!UaFA>q;Z(=$dj^tPH(h`dk7<8`{i)TDxvmdNghFkXu=*y;>QOl0Z(n8 z!gfpqto!J8o$Y1ck+$=`^U_MisC^+5!Ygq+VSw!4CWB|j)a5WGxqNFhYEWIGXgsd$ z<&!)*F-fJ}^`L$>d~+iF`VcGv>K7v6NuF)3DGQ)y=-CG z1GoAGI$&i=z_;Av_vW13-(U;wm%EKwzc^n0e0975H)HoDKJUUSPq^U6lk8IN<#YeD z@4=FGd6IN^v;#4b&pvFi`P$mW<)v&`XJ?A9AC9qR_D74IZTO`pds)0CWR!OD-TpM& zn_;c$w5*+X_orLsRasqH^;adka*F+2CakuX{O!3}Wwi6VlifSbcFS|M+VzVCZKk2CvUGkfp4 z`X;7lCa0Zpsl57<3?*N>UbK7_!iV9%JfG+$yR_xQX%z# z`%uwk3sh04H9SETMQgtN%NOSvL4cEV9v}{+^DlS zwt(iX#{{bZFb_2c)hPPZMI{|rSXnAmsno6J1yXe%n><|{pKm_Vo-c3v+M>TTcPzE} z7PE%YArCQCH3?fN%%CCPM9+DzFp^rDlh^6v^JFxXiUmPSF*F0yATVY0D5NS>#Q zSu&c}?sE|Tc-^x322jsyDwXbJ35;p2Et`-@E261G@bs9@M;f^`E|$@kuadRHTXQoj zCS}don0z$N*6(+`G&bk}hT218exScl(=s{RZw2}%H=?)$&sTDRBCP9nRM$S;T_nnX4*4Cp0%MVd--5@gnaJpV5QYR_%2uz diff --git a/Assets/Scripts/ServerShared/AetheriaRuntimeItemCatalog.cs b/Assets/Scripts/ServerShared/AetheriaRuntimeItemCatalog.cs index 59bb25c00..1131b373a 100644 --- a/Assets/Scripts/ServerShared/AetheriaRuntimeItemCatalog.cs +++ b/Assets/Scripts/ServerShared/AetheriaRuntimeItemCatalog.cs @@ -10,13 +10,11 @@ public interface IRuntimeItemProjectionReader { AetheriaRuntimeCatalogItem GetRuntimeItem(Guid guid); IReadOnlyList GetBehaviorProjections(Guid guid); - ItemData Get(Guid guid); } public sealed class AetheriaRuntimeItemCatalog : IRuntimeItemProjectionReader { private readonly Dictionary _typedItems; - private readonly Dictionary _items; private static readonly IReadOnlyDictionary BehaviorTypesByUnionKey = new Dictionary { { 0, typeof(GuidedWeaponData) }, @@ -59,11 +57,6 @@ public sealed class AetheriaRuntimeItemCatalog : IRuntimeItemProjectionReader _typedItems = catalog.Items .Where(item => Guid.TryParse(item.LegacyId, out _)) .ToDictionary(item => Guid.Parse(item.LegacyId), item => item); - - _items = catalog.Items - .Select(ProjectItem) - .Where(item => item != null) - .ToDictionary(item => item.ID, item => item); } public AetheriaRuntimeCatalogItem GetRuntimeItem(Guid guid) @@ -80,95 +73,6 @@ public sealed class AetheriaRuntimeItemCatalog : IRuntimeItemProjectionReader : ProjectBehaviors(item); } - public ItemData Get(Guid guid) - { - ItemData item; - _items.TryGetValue(guid, out item); - return item; - } - - private static ItemData ProjectItem(AetheriaRuntimeCatalogItem item) - { - if (!Guid.TryParse(item.LegacyId, out var id)) - { - return null; - } - - var projected = CreateItemData(item); - if (projected == null) - { - return null; - } - - projected.ID = id; - projected.Name = item.Name; - projected.Description = item.Description; - projected.Manufacturer = ParseGuid(item.ManufacturerLegacyId); - projected.Mass = (float)item.Mass; - projected.SpecificHeat = (float)item.SpecificHeat; - projected.Conductivity = (float)item.Conductivity; - projected.Shape = ProjectShape(item.ShapeWidth, item.ShapeHeight, item.ShapeCells); - projected.Price = item.Price; - - if (projected is SimpleCommodityData simple) - { - simple.MaxStack = item.MaxStack; - } - - if (projected is ConsumableItemData consumable) - { - consumable.Stackable = item.Stackable; - consumable.Duration = (float)item.Duration; - consumable.Effectiveness = ProjectCurve(item.EffectivenessCurveKeys); - consumable.Behaviors = ProjectBehaviors(item).ToList(); - } - - if (projected is EquippableItemData equippable) - { - equippable.Durability = (float)item.Durability; - equippable.ActionBarIcon = item.ActionBarIcon; - equippable.ThermalResilience = (float)item.ThermalResilience; - equippable.AudioStats = ProjectAudioStats(item).ToList(); - equippable.Behaviors = ProjectBehaviors(item).ToList(); - } - - if (projected is GearData gear) - { - gear.Hardpoint = ParseEnum(item.HardpointType, HardpointType.Tool); - } - - if (projected is CargoBayData cargoBay) - { - cargoBay.InteriorShape = ProjectShape(item.InteriorShapeWidth, item.InteriorShapeHeight, item.InteriorShapeCells); - } - - if (projected is DockingBayData dockingBay) - { - dockingBay.MaxSize = new int2(item.DockingMaxSizeX, item.DockingMaxSizeY); - } - - if (projected is WeaponItemData weapon) - { - weapon.WeaponRange = ParseEnum(item.WeaponRange, WeaponRange.Short); - weapon.WeaponCaliber = ParseEnum(item.WeaponCaliber, WeaponCaliber.Small); - weapon.WeaponType = ParseEnum(item.WeaponType, WeaponType.Laser); - weapon.WeaponFireTypes = ParseFlags(item.WeaponFireTypes, WeaponFireType.None); - weapon.WeaponModifiers = ParseFlags(item.WeaponModifiers, WeaponModifiers.None); - } - - if (projected is HullData hull) - { - hull.HullType = ParseEnum(item.HullType, HullType.Ship); - hull.Hardpoints = item.Hardpoints.Select(ProjectHardpoint).ToList(); - hull.GridOffset = (float)item.HullGridOffset; - hull.Armor = (float)item.HullArmor; - hull.Drag = (float)item.HullDrag; - hull.CanTow = item.HullCanTow; - } - - return projected; - } - private static BehaviorData[] ProjectBehaviors(AetheriaRuntimeCatalogItem item) { return item.BehaviorPayloads @@ -177,29 +81,6 @@ public sealed class AetheriaRuntimeItemCatalog : IRuntimeItemProjectionReader .ToArray(); } - private static BezierCurve ProjectCurve(IReadOnlyList keys) - { - return new BezierCurve - { - Keys = keys == null || keys.Count == 0 - ? new[] { new float4(0, 1, 0, 0), new float4(1, 1, 0, 0) } - : keys.Select(key => new float4( - (float)key.Time, - (float)key.Value, - (float)key.InTangent, - (float)key.OutTangent)).ToArray() - }; - } - - private static IEnumerable ProjectAudioStats(AetheriaRuntimeCatalogItem item) - { - return item.AudioStats.Select(audioStat => new AudioStat - { - Parameter = audioStat.Parameter, - Stat = ProjectPerformanceStat(audioStat.Stat) - }); - } - private static PerformanceStat ProjectPerformanceStat(AetheriaRuntimePerformanceStat stat) { return new PerformanceStat @@ -212,60 +93,6 @@ public sealed class AetheriaRuntimeItemCatalog : IRuntimeItemProjectionReader }; } - private static ItemData CreateItemData(AetheriaRuntimeCatalogItem item) - { - switch (item.Category) - { - case "SimpleCommodityData": - return new SimpleCommodityData(); - case "CompoundCommodityData": - return new CompoundCommodityData(); - case "ConsumableItemData": - return new ConsumableItemData(); - case "GearData": - return new GearData(); - case "CargoBayData": - return new CargoBayData(); - case "DockingBayData": - return new DockingBayData(); - case "WeaponItemData": - return new WeaponItemData(); - case "HullData": - return new HullData(); - default: - return !string.IsNullOrWhiteSpace(item.HardpointType) ? new GearData() : null; - } - } - - private static Shape ProjectShape(int width, int height, IReadOnlyList cells) - { - var shape = new Shape(Math.Max(width, 1), Math.Max(height, 1)); - foreach (var coordinate in shape.AllCoordinates) - { - shape[coordinate] = false; - } - - foreach (var cell in cells) - { - shape[new int2(cell.X, cell.Y)] = true; - } - - return shape; - } - - private static HardpointData ProjectHardpoint(AetheriaRuntimeHardpoint hardpoint) - { - return new HardpointData - { - Type = ParseEnum(hardpoint.Type, HardpointType.Hull), - Position = new int2(hardpoint.PositionX, hardpoint.PositionY), - Shape = ProjectShape(hardpoint.ShapeWidth, hardpoint.ShapeHeight, hardpoint.ShapeCells), - Transform = hardpoint.Transform, - Rotation = ParseEnum(hardpoint.Rotation, ItemRotation.None), - Armor = (float)hardpoint.Armor - }; - } - private static BehaviorData ProjectBehavior(AetheriaRuntimeBehaviorPayload payload) { if (!BehaviorTypesByUnionKey.TryGetValue(payload.UnionKey, out var behaviorType)) @@ -390,28 +217,6 @@ public sealed class AetheriaRuntimeItemCatalog : IRuntimeItemProjectionReader return Guid.TryParse(value, out var result) ? result : Guid.Empty; } - private static T ParseEnum(string value, T fallback) where T : struct - { - return Enum.TryParse(value, true, out T parsed) ? parsed : fallback; - } - - private static T ParseFlags(string value, T fallback) where T : struct - { - if (string.IsNullOrWhiteSpace(value)) - { - return fallback; - } - - return value - .Split('|') - .Select(part => part.Trim()) - .Where(part => part.Length > 0) - .Aggregate(fallback, (current, part) => - Enum.TryParse(part, true, out T parsed) - ? (T)Enum.ToObject(typeof(T), Convert.ToInt32(current) | Convert.ToInt32(parsed)) - : current); - } - private static float2 ConvertFloat2(AetheriaRuntimeBehaviorValue value) { return new float2( diff --git a/Assets/Scripts/ServerShared/Entity.cs b/Assets/Scripts/ServerShared/Entity.cs index 842d1e5a8..30474a5f0 100644 --- a/Assets/Scripts/ServerShared/Entity.cs +++ b/Assets/Scripts/ServerShared/Entity.cs @@ -1247,7 +1247,6 @@ public class ConsumableItemEffect public float RemainingDuration { get; private set; } public Entity Entity { get; } public ConsumableItem Item { get; } - public ConsumableItemData Data { get; } public Behavior[] Behaviors { get; } public AetheriaRuntimeCatalogItem RuntimeItem { get; } public float Duration => Math.Max(_duration, float.Epsilon); @@ -1260,9 +1259,8 @@ public class ConsumableItemEffect Item = item; Entity = entity; RuntimeItem = entity.ItemManager.GetRuntimeItem(item); - Data = entity.ItemManager.GetData(item) as ConsumableItemData; - _duration = RuntimeItem?.Duration > 0 ? (float)RuntimeItem.Duration : Data?.Duration ?? 0; - _effectiveness = CreateEffectivenessCurve(RuntimeItem, Data); + _duration = RuntimeItem?.Duration > 0 ? (float)RuntimeItem.Duration : 0; + _effectiveness = CreateEffectivenessCurve(RuntimeItem); RemainingDuration = _duration; Behaviors = entity.ItemManager.GetRuntimeBehaviorProjections(item) @@ -1297,7 +1295,7 @@ public class ConsumableItemEffect return result; } - private static BezierCurve CreateEffectivenessCurve(AetheriaRuntimeCatalogItem item, ConsumableItemData fallback) + private static BezierCurve CreateEffectivenessCurve(AetheriaRuntimeCatalogItem item) { if (item?.EffectivenessCurveKeys != null && item.EffectivenessCurveKeys.Count > 0) { @@ -1313,7 +1311,7 @@ public class ConsumableItemEffect }; } - return fallback?.Effectiveness ?? new BezierCurve + return new BezierCurve { Keys = new[] { new float4(0, 1, 0, 0), new float4(1, 1, 0, 0) } }; @@ -1342,7 +1340,6 @@ public class EquippedItem public float Wear { get; private set; } public Shape InsetShape { get; } public Entity Entity { get; } - public EquippableItemData Data { get; } public AetheriaRuntimeCatalogItem RuntimeItem { get; } public ReactiveProperty ThermalOnline { get; } = new ReactiveProperty(false); @@ -1443,16 +1440,15 @@ public class EquippedItem public EquippedItem(ItemManager itemManager, EquippableItem item, int2 position, Entity entity) { ItemManager = itemManager; - Data = ItemManager.GetData(item); Entity = entity; EquippableItem = item; Position = position; RuntimeItem = ItemManager.GetRuntimeItem(item); - Conductivity = RuntimeItem != null ? (float)RuntimeItem.Conductivity : Data.Conductivity; + Conductivity = RuntimeItem != null ? (float)RuntimeItem.Conductivity : 0; MaxDurability = RuntimeItem?.Durability > 0 ? (float)RuntimeItem.Durability : Math.Max(item.Durability, 1f); - ThermalResilience = RuntimeItem?.ThermalResilience > 0 ? (float)RuntimeItem.ThermalResilience : Data.ThermalResilience; + ThermalResilience = RuntimeItem?.ThermalResilience > 0 ? (float)RuntimeItem.ThermalResilience : 1; _thermalPerformanceCurve = CreateThermalPerformanceCurve(RuntimeItem); - _audioStats = CreateAudioStatBindings(RuntimeItem, Data); + _audioStats = CreateAudioStatBindings(RuntimeItem); ThermalExponent = lerp( ItemManager.GameplaySettings.ThermalQualityMin, ItemManager.GameplaySettings.ThermalQualityMax, @@ -1541,7 +1537,7 @@ public class EquippedItem RuntimeItem == null || RuntimeItem.MaximumTemperature <= RuntimeItem.MinimumTemperature) { - return Data.Performance(temperature); + return 1; } var t = unlerp((float)RuntimeItem.MinimumTemperature, (float)RuntimeItem.MaximumTemperature, temperature); @@ -1594,9 +1590,7 @@ public class EquippedItem return null; } - private static EquippedItemAudioStatBinding[] CreateAudioStatBindings( - AetheriaRuntimeCatalogItem item, - EquippableItemData fallback) + private static EquippedItemAudioStatBinding[] CreateAudioStatBindings(AetheriaRuntimeCatalogItem item) { if (item?.AudioStats != null) { @@ -1607,9 +1601,7 @@ public class EquippedItem .ToArray(); } - return fallback.AudioStats - .Select(audioStat => new EquippedItemAudioStatBinding(audioStat.Parameter, audioStat.Stat)) - .ToArray(); + return Array.Empty(); } private static PerformanceStat CreatePerformanceStat(AetheriaRuntimePerformanceStat stat) diff --git a/Assets/Scripts/ServerShared/ItemManager.cs b/Assets/Scripts/ServerShared/ItemManager.cs index d75eb6bbe..13b8aa750 100644 --- a/Assets/Scripts/ServerShared/ItemManager.cs +++ b/Assets/Scripts/ServerShared/ItemManager.cs @@ -94,49 +94,11 @@ public class ItemManager return new RuntimeItemReference(itemId); } - public ItemData GetData(ItemInstance item) - { - Hydrate(item); - return item?.Data?.Projection; - } - - public void Hydrate(ItemInstance item) - { - if (item?.Data == null || item.Data.Projection != null) - { - return; - } - - var data = _itemProjections.Get(item.Data.ItemId); - if (data == null) - { - _logger($"Attempted to hydrate missing item id {item.Data.ItemId}"); - return; - } - - item.Data.SetProjection(data); - } - public void Log(string s) { _logger(s); } - public SimpleCommodityData GetData(SimpleCommodity item) - { - return GetData((ItemInstance)item) as SimpleCommodityData; - } - - public CraftedItemData GetData(CraftedItemInstance item) - { - return GetData((ItemInstance)item) as CraftedItemData; - } - - public EquippableItemData GetData(EquippableItem item) - { - return GetData((ItemInstance)item) as EquippableItemData; - } - public float GetMass(ItemInstance item) { var typedItem = GetRuntimeItem(item); diff --git a/Assets/Scripts/ServerShared/RuntimeProjection/RuntimeItemProjectionEntry.cs b/Assets/Scripts/ServerShared/RuntimeProjection/RuntimeItemProjectionEntry.cs index 763076497..09d9a0253 100644 --- a/Assets/Scripts/ServerShared/RuntimeProjection/RuntimeItemProjectionEntry.cs +++ b/Assets/Scripts/ServerShared/RuntimeProjection/RuntimeItemProjectionEntry.cs @@ -28,7 +28,6 @@ public abstract class RuntimeItemProjectionEntry public class RuntimeItemReference { - public ItemData Projection { get; private set; } public Guid ItemId; public RuntimeItemReference() @@ -39,17 +38,6 @@ public class RuntimeItemReference { ItemId = itemId; } - - public RuntimeItemReference(ItemData value) - { - SetProjection(value); - } - - public void SetProjection(ItemData value) - { - Projection = value; - ItemId = value?.ID ?? Guid.Empty; - } } public interface ITintInspector diff --git a/Assets/Scripts/UI/Properties Panel/PropertiesPanel.cs b/Assets/Scripts/UI/Properties Panel/PropertiesPanel.cs index c2af52a33..f3b348eb7 100644 --- a/Assets/Scripts/UI/Properties Panel/PropertiesPanel.cs +++ b/Assets/Scripts/UI/Properties Panel/PropertiesPanel.cs @@ -346,29 +346,6 @@ public class PropertiesPanel : MonoBehaviour OnPropertyAdded?.Invoke(field.gameObject); } - // public void Inspect(Entity entity) - // { - // Clear(); - // Title.text = entity.Name; - // var hullData = Context.GetData(entity.Hull) as HullData; - // AddSection( - // hullData.HullType == HullType.Ship ? "Ship" : - // hullData.HullType == HullType.Station ? "Station" : - // "Platform"); - // //AddList(hullData.Name).Inspect(hull, entity); - // //PropertiesPanel.AddProperty("Hull", () => $"{hullData.Name}"); - // AddEntityProperties(entity); - // //cargoList.SetExpanded(false,true); - // - // RefreshValues(); - // } - - // private void AddEntityProperties(Entity entity) - // { - // AddField("Name", () => entity.Name, name => entity.Name = name); - // AddProperty("Mass", () => $"{entity.Mass.SignificantDigits(Context.GameplaySettings.SignificantDigits)}"); - // } - private void AddItemProperties(ItemInstance item) { var typedItem = FindTypedPropertyItem(item); diff --git a/docs/aetheria-perfect-machine-map.md b/docs/aetheria-perfect-machine-map.md index 527e03540..e940dd676 100644 --- a/docs/aetheria-perfect-machine-map.md +++ b/docs/aetheria-perfect-machine-map.md @@ -80,11 +80,10 @@ legacy catalog cache, and legacy UI paths should be migration-only or deleted. same typed player-settings commit after mutating the runtime projection. The action bar also uses typed runtime catalog category rows to reject non-consumable inventory drops and creates consumable bindings around typed - catalog rows before hydrating any legacy DTO. Missing typed rows are rejected - for consumable binding instead of falling through to legacy DTO classification. - Consumable activation and active-duration fill still resolve legacy - `ConsumableItemData` lazily because runtime effects and duration are not typed - execution surfaces yet. Gear action-bar bindings read custom icon resource + catalog rows. Missing typed rows are rejected for consumable binding instead + of falling through to legacy DTO classification. Consumable activation, + active-duration fill, runtime duration, and effectiveness curves now use typed + item rows with neutral defaults for missing optional facets. Gear action-bar bindings read custom icon resource paths from typed item rows, then use typed weapon and hardpoint facets for fallback icon selection, and finally fall back to a generic tool icon when typed facets are incomplete. The current legacy catalog has zero populated @@ -134,20 +133,19 @@ legacy catalog cache, and legacy UI paths should be migration-only or deleted. - `ActionGameManager` opens `AetheriaRuntimeCatalogStore` over `aetheria-world.cc`, projects it through `AetheriaRuntimeItemCatalog`, and gives `ItemManager` explicit item lookup authority. Item instances carry - `RuntimeItemReference`, an item-definition id plus optional hydrated - projection cache, not a process-global catalog resolver or durable item-data - owner. The old `LegacyItemCatalogBoundary`, + `RuntimeItemReference`, an item-definition id, not a process-global catalog + resolver, hydrated projection cache, or durable item-data owner. The old + `LegacyItemCatalogBoundary`, `LegacyItemCatalogCache`, and runtime MessagePack deserializer path have been deleted. The old `DatabaseEntry`/`RuntimeCatalogEntry` base has been demoted to `RuntimeItemProjectionEntry` for surviving item DTOs, and the old generic `DatabaseLink`/`RuntimeCatalogLink` path has collapsed into the item-specific runtime reference. - `ItemManager` no longer exposes the raw runtime item catalog reader as public - gameplay/UI API. Temporary item projection hydration now goes through - `ItemManager.GetData` over `RuntimeItemReference.ItemId`. `ItemManager` no - longer exposes a legacy catalog enumeration API or a catalog-entry-shaped - single-item API. This prevents catalog authority from leaking into every - caller that only needs a projection lookup. The item properties UI no longer uses + gameplay/UI API, and its old `GetData`/`Hydrate` item DTO projection path has + been deleted. `AetheriaRuntimeItemCatalog` no longer materializes whole + `ItemData` DTOs as a runtime cache; it exposes typed item rows plus the + temporary behavior payload projection bridge. The item properties UI no longer uses `ItemManager` for manufacturer display; it resolves the manufacturer through the package-owned `ActionGameManager.RuntimeCatalog` typed snapshot. Entity restore and loadout manufacturer-distance weighting no longer use `ItemManager` @@ -241,13 +239,13 @@ legacy catalog cache, and legacy UI paths should be migration-only or deleted. conduction, durability performance, thermal performance, and wear scaling. Thermal resilience is also typed and feeds wear scaling. Audio parameter stat bindings are typed item rows and feed equipped-item Wwise parameter updates; - the legacy equippable DTO is now only an incomplete-row projection fallback - for equipped-item simulation. Consumable stackability, duration, and + missing optional thermal/audio facets now degrade to neutral runtime defaults + instead of hydrating legacy equippable DTOs. Consumable stackability, duration, and effectiveness curve slots are part of typed item rows, and action-bar consumable activation/fill now command typed item IDs. The current mapped - legacy catalog has no consumable item rows, so `ConsumableItemData` remains a - compatibility fallback for any future/unmapped consumable instance until - consumable behavior execution is fully typed. + legacy catalog has no consumable item rows, so consumable runtime behavior + still needs future typed data coverage, but it no longer hydrates + `ConsumableItemData` as a fallback. Inventory drag preview occupancy now projects typed item shape cells only into the local `Shape` grid, and final fit/equip acceptance shares the typed runtime catalog geometry path in `Entity.ItemFits` and `TryEquip`. @@ -772,6 +770,10 @@ First Aetheria surfaces to publish: typed runtime item rows; `ItemManager.Instantiate` now clones simple commodities, crafted items, consumables, and equippables from `AetheriaRuntimeCatalogItem` identity and facets. + - Done: delete the runtime item DTO hydration bridge; `ItemManager.GetData`, + `ItemManager.Hydrate`, `IRuntimeItemProjectionReader.Get`, the + `AetheriaRuntimeItemCatalog` whole-item DTO cache, and + `RuntimeItemReference.Projection` are gone. - Done: move final `Entity.ItemFits`, `TryFindSpace`, `TryEquip`, and `TryUnequip` gear occupancy/mass deltas onto typed catalog rows for item shape, hull shape/interior, hardpoint masks, cargo/docking category, and @@ -790,24 +792,23 @@ First Aetheria surfaces to publish: typed runtime item rows; legacy `EquippableItemData.Durability` no longer owns that stat-evaluation path. - Done: move new equippable instance durability initialization onto typed - runtime item rows; legacy `EquippableItemData.Durability` remains only as - an incomplete-row fallback in the instantiation bridge. + runtime item rows. - Done: move `EquippedItem` conductivity and max-durability performance/wear - inputs onto typed runtime item rows; legacy thermal resilience and audio - stats remain explicit DTO residues. + inputs onto typed runtime item rows. - Done: move `EquippedItem` thermal performance evaluation onto typed - runtime item thermal bounds and curve keys; legacy `Data.Performance` - remains only as an incomplete-row fallback. + runtime item thermal bounds and curve keys; missing typed curve/range data + uses a neutral runtime default. - Done: import typed thermal resilience and move equipped-item wear scaling - off `EquippableItemData.ThermalResilience`; it remains only as an - incomplete-row fallback. + off `EquippableItemData.ThermalResilience`; missing typed resilience uses + a neutral runtime default. - Done: import typed audio parameter stat bindings and move equipped-item - Wwise parameter updates off `EquippableItemData.AudioStats`; it remains - only as an incomplete-row fallback. + Wwise parameter updates off `EquippableItemData.AudioStats`; missing + typed audio stat bindings produce no parameter updates. - Done: add typed consumable stackability, duration, and effectiveness curve - fields and route action-bar consumable activation through typed item rows; - verifier records that the current mapped catalog has `0` consumable item - rows, so the old DTO path cannot be fully deleted yet. + fields and route action-bar consumable activation/runtime evaluation + through typed item rows; verifier records that the current mapped catalog + has `0` consumable item rows, so future consumable content still needs + typed coverage. - Done: import action-bar icon resource paths into typed item definitions and move `ActionBarSlot` custom gear icon lookup onto typed runtime item rows. - Done: move `Ship` drag, combat/turret predicted shot height, and thruster @@ -946,10 +947,9 @@ First Aetheria surfaces to publish: - Done: collapse the old generic `RuntimeCatalogLink` abstraction into `RuntimeItemReference`, an item-specific runtime projection reference owned by `ItemManager`. - - Done: demote `RuntimeItemReference.Value` to - `RuntimeItemReference.Projection`, making the hydrated `ItemData` DTO a - cache/display/behavior bridge derived from `ItemId` instead of the - reference's apparent state value. + - Done: demote `RuntimeItemReference.Value` to an item-definition id, then + delete `RuntimeItemReference.Projection`; item references no longer carry + hydrated `ItemData` DTOs. - Done: delete the dead `ItemManager.GetRuntimeItemProjection` bridge after loadout generation stopped hydrating selected typed rows into `EquippableItemData` merely to instantiate equipment. @@ -1048,11 +1048,9 @@ First Aetheria surfaces to publish: ## Immediate Cut Line -Do not add behavior to `ItemData`, `RuntimeItemProjectionEntry`, or the -temporary `AetheriaRuntimeItemCatalog` DTO materializer. The typed state spine -and migration quarantine exist; the next cuts should replace surviving -projection consumers with typed item facets, typed behavior factories, and Eve -surfaces until the remaining `GetData` hydration users are gone and the old DTO -bridge can be deleted. Any predicate that still needs `ItemData` must earn that +Do not add behavior to `ItemData` or `RuntimeItemProjectionEntry`. The typed +state spine and migration quarantine exist; the next cuts should replace the +surviving behavior DTO projection bridge with typed behavior factories and Eve +surfaces. Any predicate that still needs legacy DTO objects must earn that dependency by using behavior objects or simulation-only methods that typed facets do not yet expose.