Prefer typed item keys in runtime commits

This commit is contained in:
Meta Vens 2026-06-15 00:06:17 +01:00
commit d2996bc072
8 changed files with 90 additions and 33 deletions

Binary file not shown.

View file

@ -171,7 +171,8 @@ try
CorporationLegacyId = "smoke:faction",
Hull = new AetheriaRuntimeLoadoutItemCommit
{
ItemDefinitionLegacyId = "smoke:hull",
ItemDefinitionLegacyId = "stale:hull",
ItemKey = "aetheria.item_definition:legacy:smoke:hull",
Quality = 0.7,
Durability = 0.6
},
@ -183,7 +184,8 @@ try
Y = 2,
Item = new AetheriaRuntimeLoadoutItemCommit
{
ItemDefinitionLegacyId = "smoke:weapon",
ItemDefinitionLegacyId = "stale:weapon",
ItemKey = "aetheria.item_definition:legacy:smoke:weapon",
Quality = 0.9,
Durability = 0.8,
Enabled = false
@ -202,7 +204,8 @@ try
Y = 4,
Item = new AetheriaRuntimeLoadoutItemCommit
{
ItemDefinitionLegacyId = "smoke:ore",
ItemDefinitionLegacyId = "stale:ore",
ItemKey = "aetheria.item_definition:legacy:smoke:ore",
Quantity = 5
}
}
@ -234,7 +237,8 @@ try
{
ControlPath = "<Keyboard>/2",
Kind = "gear",
ItemDefinitionLegacyId = "smoke:weapon",
ItemDefinitionLegacyId = "stale:weapon",
ItemKey = "aetheria.item_definition:legacy:smoke:weapon",
EquipmentIndex = 0,
BehaviorIndex = 1
}
@ -283,7 +287,8 @@ try
{
new AetheriaRuntimeBodyResourceCommit
{
ItemDefinitionLegacyId = "smoke:ore",
ItemDefinitionLegacyId = "stale:ore",
ItemKey = "aetheria.item_definition:legacy:smoke:ore",
Amount = 3.5
}
},
@ -334,7 +339,8 @@ try
TractorPower = 12.5,
Heatstroke = 0.25,
Hypothermia = 0.125,
HullItemDefinitionLegacyId = "smoke:hull",
HullItemDefinitionLegacyId = "stale:hull",
HullItemKey = "aetheria.item_definition:legacy:smoke:hull",
Equipment = new[]
{
new AetheriaRuntimeLoadoutItemSlotCommit
@ -343,7 +349,8 @@ try
Y = 0,
Item = new AetheriaRuntimeLoadoutItemCommit
{
ItemDefinitionLegacyId = "smoke:weapon",
ItemDefinitionLegacyId = "stale:weapon",
ItemKey = "aetheria.item_definition:legacy:smoke:weapon",
Quality = 0.9,
Durability = 0.8,
Enabled = false
@ -362,7 +369,8 @@ try
Y = 3,
Item = new AetheriaRuntimeLoadoutItemCommit
{
ItemDefinitionLegacyId = "smoke:ore",
ItemDefinitionLegacyId = "stale:ore",
ItemKey = "aetheria.item_definition:legacy:smoke:ore",
Quantity = 7
}
}
@ -387,7 +395,8 @@ try
{
new AetheriaRuntimeActiveConsumableCommit
{
ItemDefinitionLegacyId = "smoke:consumable",
ItemDefinitionLegacyId = "stale:consumable",
ItemKey = "aetheria.item_definition:legacy:smoke:consumable",
Quality = 0.75,
RemainingDuration = 3.0,
Duration = 5.0

View file

@ -164,7 +164,7 @@ public static class AetheriaRuntimeCommitLogApplier
item ??= new AetheriaRuntimeLoadoutItemCommit();
return new AetheriaLoadoutItem
{
ItemKey = ReferenceKey("aetheria.item_definition", item.ItemDefinitionLegacyId ?? ""),
ItemKey = ReferenceKey(item.ItemKey, "aetheria.item_definition", item.ItemDefinitionLegacyId ?? ""),
Quality = item.Quality,
Durability = item.Durability,
Quantity = item.Quantity,
@ -332,7 +332,7 @@ public static class AetheriaRuntimeCommitLogApplier
return (resources ?? Array.Empty<AetheriaRuntimeBodyResourceCommit>())
.Select(resource => new AetheriaBodyResource
{
ItemKey = ReferenceKey("aetheria.item_definition", resource.ItemDefinitionLegacyId ?? ""),
ItemKey = ReferenceKey(resource.ItemKey, "aetheria.item_definition", resource.ItemDefinitionLegacyId ?? ""),
Amount = resource.Amount
})
.ToArray();
@ -464,7 +464,7 @@ public static class AetheriaRuntimeCommitLogApplier
Heatstroke = entity.Heatstroke,
Hypothermia = entity.Hypothermia,
FactionKey = ReferenceKey("aetheria.corporation", entity.CorporationLegacyId ?? ""),
HullItemKey = ReferenceKey("aetheria.item_definition", entity.HullItemDefinitionLegacyId ?? ""),
HullItemKey = ReferenceKey(entity.HullItemKey, "aetheria.item_definition", entity.HullItemDefinitionLegacyId ?? ""),
Equipment = ToEntityItemSlots(entity.Equipment),
CargoBays = ToEntityItemSlots(entity.CargoBays),
DockingBays = ToEntityItemSlots(entity.DockingBays),
@ -624,7 +624,7 @@ public static class AetheriaRuntimeCommitLogApplier
return (consumables ?? Array.Empty<AetheriaRuntimeActiveConsumableCommit>())
.Select(consumable => new AetheriaActiveConsumableSnapshot
{
ItemKey = ReferenceKey("aetheria.item_definition", consumable.ItemDefinitionLegacyId ?? ""),
ItemKey = ReferenceKey(consumable.ItemKey, "aetheria.item_definition", consumable.ItemDefinitionLegacyId ?? ""),
Quality = consumable.Quality,
RemainingDuration = consumable.RemainingDuration,
Duration = consumable.Duration
@ -666,7 +666,7 @@ public static class AetheriaRuntimeCommitLogApplier
{
ControlPath = binding.ControlPath ?? "",
Kind = binding.Kind ?? "",
TargetKey = ReferenceKey("aetheria.item_definition", binding.ItemDefinitionLegacyId ?? ""),
TargetKey = ReferenceKey(binding.ItemKey, "aetheria.item_definition", binding.ItemDefinitionLegacyId ?? ""),
EquipmentIndex = binding.EquipmentIndex,
BehaviorIndex = binding.BehaviorIndex,
WeaponGroup = binding.WeaponGroup
@ -712,6 +712,13 @@ public static class AetheriaRuntimeCommitLogApplier
return string.IsNullOrWhiteSpace(legacyId) ? "" : $"{documentName}:legacy:{legacyId}";
}
private static string ReferenceKey(string typedKey, string documentName, string legacyId)
{
return !string.IsNullOrWhiteSpace(typedKey)
? typedKey
: ReferenceKey(documentName, legacyId);
}
private static string StableToken(string value)
{
var chars = (string.IsNullOrWhiteSpace(value) ? "unnamed" : value.Trim().ToLowerInvariant())

View file

@ -87,6 +87,10 @@ derived legacy-GUID compatibility projection for broader simulation paths.
Cargo inventory indexes, consumable activation lookup, action-bar consumable
quantity/fill, transfer lookup, trade owned counts, weapon ammo references, and
item-use behavior references now use item keys.
Unity runtime commit DTOs also carry typed `ItemKey`/`HullItemKey` fields for
loadout items, action-bar targets, body resources, entity hulls, and active
consumables. Their old `*LegacyId` fields remain import/export compatibility
only; the commit applier prefers typed keys whenever present.
The old generic `RuntimeCatalogLink<T>` abstraction, `ItemManager.GetData`
hydration path, vague `ItemInstance.Data` identity field, and old
`RuntimeItemReference.Projection` cache have been deleted; runtime item facts

View file

@ -94,8 +94,8 @@ public class ActionBarConsumableBinding : ActionBarBinding
else Slot.Fill.fillAmount = instance.RemainingDuration / instance.Duration;
}
private string TargetItemKey =>
Guid.TryParse(Target.LegacyId, out var legacyId) ? AetheriaRuntimeItemReference.FromLegacyId(legacyId) : "";
public string TargetItemKey =>
Guid.TryParse(Target?.LegacyId, out var legacyId) ? AetheriaRuntimeItemReference.FromLegacyId(legacyId) : "";
public string TargetItemDefinitionLegacyId => Target?.LegacyId ?? "";
@ -116,14 +116,14 @@ public class ActionBarGearBinding : ActionBarBinding
{
get
{
var itemKey = Item?.EquippableItem?.ItemKey ?? "";
const string legacyPrefix = "aetheria.item_definition:legacy:";
return itemKey.StartsWith(legacyPrefix, StringComparison.OrdinalIgnoreCase)
? itemKey.Substring(legacyPrefix.Length)
return AetheriaRuntimeItemReference.ToLegacyId(TargetItemKey) is var legacyId && legacyId != Guid.Empty
? legacyId.ToString("D")
: "";
}
}
public string TargetItemKey => Item?.EquippableItem?.ItemKey ?? "";
public ActionBarGearBinding(Entity entity, ActionBarSlot slot, EquippedItem item, IActivatedBehavior behavior) : base(entity, slot)
{
Item = item;

View file

@ -523,6 +523,7 @@ public class ActionGameManager : MonoBehaviour
return new AetheriaRuntimeLoadoutItemCommit
{
ItemDefinitionLegacyId = item.ItemId == Guid.Empty ? "" : item.ItemId.ToString("D"),
ItemKey = item.ItemKey,
Quality = item is CraftedItemInstance crafted ? crafted.Quality : 1.0,
Durability = item is EquippableItem equippable ? equippable.Durability : 1.0,
Quantity = item is SimpleCommodity commodity ? commodity.Quantity : 1,
@ -569,7 +570,8 @@ public class ActionGameManager : MonoBehaviour
{
ControlPath = slot.ControlPath ?? "",
Kind = "consumable",
ItemDefinitionLegacyId = consumable.TargetItemDefinitionLegacyId
ItemDefinitionLegacyId = consumable.TargetItemDefinitionLegacyId,
ItemKey = consumable.TargetItemKey
};
case ActionBarGearBinding gear:
return new AetheriaRuntimeActionBarBindingCommit
@ -577,6 +579,7 @@ public class ActionGameManager : MonoBehaviour
ControlPath = slot.ControlPath ?? "",
Kind = "gear",
ItemDefinitionLegacyId = gear.TargetItemDefinitionLegacyId,
ItemKey = gear.TargetItemKey,
EquipmentIndex = gear.EquipmentIndex,
BehaviorIndex = gear.BehaviorIndex
};
@ -676,6 +679,7 @@ public class ActionGameManager : MonoBehaviour
.Select(pair => new AetheriaRuntimeBodyResourceCommit
{
ItemDefinitionLegacyId = LegacyId(pair.Key),
ItemKey = AetheriaRuntimeItemReference.FromLegacyId(pair.Key),
Amount = pair.Value
})
.ToArray() ?? Array.Empty<AetheriaRuntimeBodyResourceCommit>(),
@ -707,6 +711,7 @@ public class ActionGameManager : MonoBehaviour
.Select(pair => new AetheriaRuntimeBodyResourceCommit
{
ItemDefinitionLegacyId = LegacyId(pair.Key),
ItemKey = AetheriaRuntimeItemReference.FromLegacyId(pair.Key),
Amount = pair.Value
})
.ToArray() ?? Array.Empty<AetheriaRuntimeBodyResourceCommit>(),
@ -821,6 +826,7 @@ public class ActionGameManager : MonoBehaviour
Hypothermia = entity.Hypothermia,
CorporationLegacyId = entity.Faction?.ID.ToString("D") ?? "",
HullItemDefinitionLegacyId = entity.Hull?.ItemId == Guid.Empty ? "" : entity.Hull.ItemId.ToString("D"),
HullItemKey = entity.Hull?.ItemKey ?? "",
Equipment = ProjectEquippedSlots(entity.Equipment),
CargoBays = ProjectEquippedSlots(entity.CargoBays),
DockingBays = ProjectEquippedSlots(entity.DockingBays),
@ -1183,6 +1189,7 @@ public class ActionGameManager : MonoBehaviour
.Select(effect => new AetheriaRuntimeActiveConsumableCommit
{
ItemDefinitionLegacyId = effect.Item?.ItemId == Guid.Empty ? "" : effect.Item.ItemId.ToString("D"),
ItemKey = effect.Item?.ItemKey ?? "",
Quality = effect.Item?.Quality ?? 1.0,
RemainingDuration = effect.RemainingDuration,
Duration = effect.Duration
@ -1334,7 +1341,7 @@ public class ActionGameManager : MonoBehaviour
{
item ??= new AetheriaRuntimeLoadoutItemCommit();
return new AetheriaRuntimeLoadoutItemSnapshot(
ReferenceKey("aetheria.item_definition", item.ItemDefinitionLegacyId ?? ""),
ReferenceKey(item.ItemKey, "aetheria.item_definition", item.ItemDefinitionLegacyId ?? ""),
item.Quality,
item.Durability,
item.Quantity,
@ -1366,6 +1373,13 @@ public class ActionGameManager : MonoBehaviour
return string.IsNullOrWhiteSpace(legacyId) ? "" : $"{prefix}:{legacyId}";
}
private static string ReferenceKey(string typedKey, string prefix, string legacyId)
{
return !string.IsNullOrWhiteSpace(typedKey)
? typedKey
: ReferenceKey(prefix, legacyId);
}
private void OnApplicationQuit() => QueueRunCheckpoint("application-quit");
private void QueueRunCheckpoint(string reason)

View file

@ -187,6 +187,9 @@ namespace GameCult.Aetheria.State.Unity
[Key(4)]
public bool Enabled { get; set; } = true;
[Key(5)]
public string ItemKey { get; set; } = "";
}
[MessagePackObject]
@ -266,6 +269,9 @@ namespace GameCult.Aetheria.State.Unity
[Key(5)]
public int WeaponGroup { get; set; } = -1;
[Key(6)]
public string ItemKey { get; set; } = "";
}
[MessagePackObject]
@ -388,6 +394,9 @@ namespace GameCult.Aetheria.State.Unity
[Key(1)]
public double Amount { get; set; }
[Key(2)]
public string ItemKey { get; set; } = "";
}
[MessagePackObject]
@ -610,6 +619,9 @@ namespace GameCult.Aetheria.State.Unity
[Key(34)]
public IReadOnlyList<AetheriaRuntimeEntityContactCommit> Contacts { get; set; } = Array.Empty<AetheriaRuntimeEntityContactCommit>();
[Key(35)]
public string HullItemKey { get; set; } = "";
}
[MessagePackObject]
@ -658,6 +670,9 @@ namespace GameCult.Aetheria.State.Unity
[Key(3)]
public double Duration { get; set; }
[Key(4)]
public string ItemKey { get; set; } = "";
}
[MessagePackObject]

View file

@ -496,10 +496,13 @@ legacy catalog cache, and legacy UI paths should be migration-only or deleted.
- The dead Unity `NameFile` projection class has been deleted. Runtime name
generation reads `AetheriaRuntimeNameFile` records from the typed catalog
facade; legacy `GameData/NameFile/*.msgpack` remains migration input only.
- Pending Unity runtime commit envelopes now name their source catalog IDs as
`CorporationLegacyId`, `ItemDefinitionLegacyId`, and
`HullItemDefinitionLegacyId`; the applier has always projected those fields
into typed corporation and item-definition record keys.
- Pending Unity runtime commit envelopes now carry typed item keys for loadout
items, action-bar targets, body resources, entity hulls, and active
consumables. The older `ItemDefinitionLegacyId` and
`HullItemDefinitionLegacyId` fields remain compatibility import/export
fields; the applier prefers `ItemKey`/`HullItemKey` whenever present.
Corporation legacy IDs still translate to typed corporation record keys at
the commit boundary.
- Entity restore and loadout manufacturer-distance weighting no longer read
legacy `Faction` entries through `ItemManager`; they use `Galaxy.ResolveFaction`
over the typed corporation projection.
@ -626,7 +629,9 @@ legacy catalog cache, and legacy UI paths should be migration-only or deleted.
transfer lookup, and trade owned-count rows now use item keys rather than
GUID-owned cargo indexes. Weapon ammo and item-use behavior config item
references are also typed-key-first (`AmmoItemKey`/`ItemKey`), with
`AmmoType`/`Item` only derived GUID compatibility;
`AmmoType`/`Item` only derived GUID compatibility. Runtime commit DTOs now
publish item and hull identity through `ItemKey`/`HullItemKey`, with legacy
ID fields demoted to compatibility;
there is no remaining `ItemInstance.Data` identity/backing field. The reader interface for this
bridge is named `IRuntimeItemCatalogReader` and exposes only typed catalog
row lookup. Behavior
@ -1206,9 +1211,9 @@ First Aetheria surfaces to publish:
in the typed state package's `.cc` reader.
- In progress: convert domain references from GUID/base-class patterns to
typed record refs. Item instances, cargo inventory indexes, weapon ammo
references, and item-use behavior references now carry typed item keys;
remaining broader simulation paths still derive legacy GUIDs until those
structures move to typed keys.
references, item-use behavior references, and runtime commit item/hull
surfaces now carry typed item keys; remaining broader simulation paths
still derive legacy GUIDs until those structures move to typed keys.
- Remove runtime dependency on `ItemData` DTOs as item instance owners.
5. Mesh host
@ -1327,13 +1332,16 @@ First Aetheria surfaces to publish:
derived legacy compatibility for unfinished cargo and simulation paths.
- Done: move `EquippedCargoBay.ItemsOfType`, consumable activation lookup,
action-bar consumable quantity/fill, item transfer lookup, and trade owned
counts from derived `Guid ItemId` keys to typed `ItemKey` strings. GUID
behavior-config fields still translate at the cargo boundary until
behavior config construction moves to typed item references.
counts from derived `Guid ItemId` keys to typed `ItemKey` strings.
- Done: move weapon ammo and `ItemUsage` config references from GUID fields
to typed item-key fields. `AmmoType` and `Item` remain derived compatibility
properties, but runtime ammo consumption, item use, and HUD ammo counts use
`AmmoItemKey`/`ItemKey`.
- Done: add typed `ItemKey`/`HullItemKey` fields to runtime commit item
surfaces and make the applier prefer them over stale legacy-ID fields.
Loadout items, action-bar targets, body resources, entity hulls, cargo
contents, and active consumables now prove typed-key ownership in the
Unity smoke by carrying intentionally stale legacy IDs.
- Done: delete the dead `ItemManager.GetRuntimeItemProjection<T>` bridge
after loadout generation stopped hydrating selected typed rows into
`EquippableItemData` merely to instantiate equipment.