diff --git a/.voidbot/state/aetheria.cc b/.voidbot/state/aetheria.cc index b716d486d..242fb56b0 100644 Binary files a/.voidbot/state/aetheria.cc and b/.voidbot/state/aetheria.cc differ diff --git a/Aetheria.State.Unity.Smoke/Program.cs b/Aetheria.State.Unity.Smoke/Program.cs index 6c14bf3e1..915c426ff 100644 --- a/Aetheria.State.Unity.Smoke/Program.cs +++ b/Aetheria.State.Unity.Smoke/Program.cs @@ -121,7 +121,7 @@ if (!catalog.FindItemsByHardpoint(equipment.HardpointType).Any()) throw new InvalidOperationException($"Runtime catalog hardpoint lookup failed for {equipment.HardpointType}."); } -var manufactured = catalog.Items.FirstOrDefault(item => !string.IsNullOrWhiteSpace(item.ManufacturerLegacyId)) +var manufactured = catalog.Items.FirstOrDefault(item => !string.IsNullOrWhiteSpace(item.ManufacturerKey)) ?? throw new InvalidOperationException("Runtime catalog has no manufactured item."); if (string.IsNullOrWhiteSpace(manufactured.ManufacturerKey) || catalog.FindCorporation(manufactured.ManufacturerKey) == null || @@ -130,7 +130,7 @@ if (string.IsNullOrWhiteSpace(manufactured.ManufacturerKey) || throw new InvalidOperationException($"Runtime catalog typed manufacturer lookup failed for {manufactured.Name}."); } -var packageCorporation = packageCatalog.Corporations.FirstOrDefault(corporation => !string.IsNullOrWhiteSpace(corporation.GeonameFileLegacyId)); +var packageCorporation = packageCatalog.Corporations.FirstOrDefault(corporation => !string.IsNullOrWhiteSpace(corporation.GeonameFileKey)); if (packageCorporation == null) { throw new InvalidOperationException("Package catalog store did not read any corporation name-file links."); diff --git a/Aetheria.State.Unity/AetheriaRuntimeCatalogSnapshotMapper.cs b/Aetheria.State.Unity/AetheriaRuntimeCatalogSnapshotMapper.cs index 358253262..9494221df 100644 --- a/Aetheria.State.Unity/AetheriaRuntimeCatalogSnapshotMapper.cs +++ b/Aetheria.State.Unity/AetheriaRuntimeCatalogSnapshotMapper.cs @@ -16,11 +16,11 @@ internal static class AetheriaRuntimeCatalogSnapshotMapper private static AetheriaRuntimeCatalogItem FromState(AetheriaItemDefinition item) { return new AetheriaRuntimeCatalogItem( - item.LegacyId, + item.ItemKey, item.Name, item.Category, item.Description, - item.ManufacturerLegacyId, + item.ManufacturerKey, item.Price, item.Mass, item.SpecificHeat, @@ -141,23 +141,23 @@ internal static class AetheriaRuntimeCatalogSnapshotMapper private static AetheriaRuntimeCorporation FromState(AetheriaCorporation corporation) { return new AetheriaRuntimeCorporation( - corporation.LegacyId, + corporation.CorporationKey, corporation.Name, corporation.ShortName, corporation.Description, - corporation.GeonameFileLegacyId, - corporation.BossHullLegacyId, + corporation.GeonameFileKey, + corporation.BossHullItemKey, corporation.InfluenceDistance, corporation.AllegianceCount, corporation.Allegiances.Select(allegiance => new AetheriaRuntimeCorporationAllegiance( - allegiance.CorporationLegacyId, + allegiance.CorporationKey, allegiance.Weight)).ToArray()); } private static AetheriaRuntimeNameFile FromState(AetheriaNameFile nameFile) { return new AetheriaRuntimeNameFile( - nameFile.LegacyId, + nameFile.NameFileKey, nameFile.Name, nameFile.NameCount, nameFile.SampleNames, diff --git a/Aetheria.State.Verify/Program.cs b/Aetheria.State.Verify/Program.cs index b86fac070..66457109c 100644 --- a/Aetheria.State.Verify/Program.cs +++ b/Aetheria.State.Verify/Program.cs @@ -718,7 +718,16 @@ static void RequireRuntimeCatalogKeyOnlyLookups(string root) "_nameFilesByLegacyId", "FindItemByLegacyId", "FindCorporationByLegacyId", - "FindNameFileByLegacyId" + "FindNameFileByLegacyId", + "public string LegacyId { get; }", + "public string ManufacturerLegacyId", + "public string GeonameFileLegacyId", + "public string BossHullLegacyId", + "public string CorporationLegacyId", + ".ManufacturerLegacyId", + ".GeonameFileLegacyId", + ".BossHullLegacyId", + ".CorporationLegacyId" }; var hits = checkedFiles diff --git a/Aetheria.State/Documents/AetheriaItemDefinition.cs b/Aetheria.State/Documents/AetheriaItemDefinition.cs index 86836af64..92550d9ab 100644 --- a/Aetheria.State/Documents/AetheriaItemDefinition.cs +++ b/Aetheria.State/Documents/AetheriaItemDefinition.cs @@ -19,6 +19,11 @@ public sealed class AetheriaItemDefinition [CultIndex("legacyId")] public string LegacyId { get; set; } = ""; + [IgnoreMember] + public string ItemKey => string.IsNullOrWhiteSpace(LegacyId) + ? "" + : $"aetheria.item_definition:legacy:{LegacyId}"; + [Key(3)] public string Description { get; set; } = ""; diff --git a/Aetheria.State/README.md b/Aetheria.State/README.md index af0cfcff0..f706efeb1 100644 --- a/Aetheria.State/README.md +++ b/Aetheria.State/README.md @@ -129,8 +129,9 @@ The package runtime catalog snapshot indexes items by canonical item key; Unity gameplay, HUD, inventory, trade, ship, and zone helper lookups use `ItemKey` directly instead of deriving `ItemId` and searching by legacy GUID. The Unity runtime package snapshot also no longer exposes item, corporation, or -name-file lookup by legacy ID. Canonical legacy-ID lookup remains only in -`Aetheria.State` migration/catalog inspection APIs. +name-file lookup by legacy ID, and its item/corporation/name-file DTOs no +longer publish legacy relationship fields. Canonical legacy-ID lookup remains +only in `Aetheria.State` migration/catalog inspection APIs. The shared runtime item catalog reader is also item-key-only now: its GUID index, `GetRuntimeItem(Guid)` entry point, raw GUID string fallback, `AetheriaRuntimeItemReference(Guid)` constructor, `FromLegacyId`, and reverse diff --git a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeCatalogSnapshot.cs b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeCatalogSnapshot.cs index e020dae79..854d59d35 100644 --- a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeCatalogSnapshot.cs +++ b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeCatalogSnapshot.cs @@ -92,11 +92,11 @@ namespace GameCult.Aetheria.State.Unity public sealed class AetheriaRuntimeCatalogItem { public AetheriaRuntimeCatalogItem( - string legacyId, + string itemKey, string name, string category, string description, - string manufacturerLegacyId, + string manufacturerKey, int price, double mass, double specificHeat, @@ -141,15 +141,11 @@ namespace GameCult.Aetheria.State.Unity string simpleCommodityCategory, string compoundCommodityCategory) { - LegacyId = legacyId; - ItemKey = string.IsNullOrWhiteSpace(legacyId) ? "" : $"aetheria.item_definition:legacy:{legacyId}"; + ItemKey = itemKey; Name = name; Category = category; Description = description; - ManufacturerLegacyId = manufacturerLegacyId; - ManufacturerKey = string.IsNullOrWhiteSpace(manufacturerLegacyId) - ? "" - : $"aetheria.corporation:legacy:{manufacturerLegacyId}"; + ManufacturerKey = manufacturerKey; Price = price; Mass = mass; SpecificHeat = specificHeat; @@ -195,12 +191,10 @@ namespace GameCult.Aetheria.State.Unity CompoundCommodityCategory = compoundCommodityCategory; } - public string LegacyId { get; } public string ItemKey { get; } public string Name { get; } public string Category { get; } public string Description { get; } - public string ManufacturerLegacyId { get; } public string ManufacturerKey { get; } public int Price { get; } public double Mass { get; } @@ -449,38 +443,32 @@ namespace GameCult.Aetheria.State.Unity public sealed class AetheriaRuntimeCorporation { public AetheriaRuntimeCorporation( - string legacyId, + string corporationKey, string name, string shortName, string description, - string geonameFileLegacyId, - string bossHullLegacyId, + string geonameFileKey, + string bossHullItemKey, int influenceDistance, int allegianceCount, IReadOnlyList allegiances) { - LegacyId = legacyId; + CorporationKey = corporationKey; Name = name; ShortName = shortName; Description = description; - GeonameFileLegacyId = geonameFileLegacyId; - BossHullLegacyId = bossHullLegacyId; - CorporationKey = string.IsNullOrWhiteSpace(legacyId) ? "" : $"aetheria.corporation:legacy:{legacyId}"; - GeonameFileKey = string.IsNullOrWhiteSpace(geonameFileLegacyId) ? "" : $"aetheria.name_file:legacy:{geonameFileLegacyId}"; - BossHullItemKey = string.IsNullOrWhiteSpace(bossHullLegacyId) ? "" : $"aetheria.item_definition:legacy:{bossHullLegacyId}"; + GeonameFileKey = geonameFileKey; + BossHullItemKey = bossHullItemKey; InfluenceDistance = influenceDistance; AllegianceCount = allegianceCount; Allegiances = allegiances; } - public string LegacyId { get; } public string CorporationKey { get; } public string Name { get; } public string ShortName { get; } public string Description { get; } - public string GeonameFileLegacyId { get; } public string GeonameFileKey { get; } - public string BossHullLegacyId { get; } public string BossHullItemKey { get; } public int InfluenceDistance { get; } public int AllegianceCount { get; } @@ -489,16 +477,12 @@ namespace GameCult.Aetheria.State.Unity public sealed class AetheriaRuntimeCorporationAllegiance { - public AetheriaRuntimeCorporationAllegiance(string corporationLegacyId, double weight) + public AetheriaRuntimeCorporationAllegiance(string corporationKey, double weight) { - CorporationLegacyId = corporationLegacyId; - CorporationKey = string.IsNullOrWhiteSpace(corporationLegacyId) - ? "" - : $"aetheria.corporation:legacy:{corporationLegacyId}"; + CorporationKey = corporationKey; Weight = weight; } - public string CorporationLegacyId { get; } public string CorporationKey { get; } public double Weight { get; } } @@ -506,21 +490,19 @@ namespace GameCult.Aetheria.State.Unity public sealed class AetheriaRuntimeNameFile { public AetheriaRuntimeNameFile( - string legacyId, + string nameFileKey, string name, int nameCount, IReadOnlyList sampleNames, IReadOnlyList names) { - LegacyId = legacyId; - NameFileKey = string.IsNullOrWhiteSpace(legacyId) ? "" : $"aetheria.name_file:legacy:{legacyId}"; + NameFileKey = nameFileKey; Name = name; NameCount = nameCount; SampleNames = sampleNames; Names = names; } - public string LegacyId { get; } public string NameFileKey { get; } public string Name { get; } public int NameCount { get; } diff --git a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeCatalogStore.cs b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeCatalogStore.cs index 97e850b61..5a31ccb27 100644 --- a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeCatalogStore.cs +++ b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeCatalogStore.cs @@ -298,11 +298,11 @@ namespace GameCult.Aetheria.State.Unity SkipRemaining(ref reader, fields, 50); return new AetheriaRuntimeCatalogItem( - legacyId, + ItemDefinitionKey(legacyId), name, category, description, - manufacturerLegacyId, + CorporationKey(manufacturerLegacyId), price, mass, specificHeat, @@ -364,12 +364,12 @@ namespace GameCult.Aetheria.State.Unity var allegiances = ReadFieldCorporationAllegiances(ref reader, fields, 11); SkipRemaining(ref reader, fields, 12); return new AetheriaRuntimeCorporation( - legacyId, + CorporationKey(legacyId), name, shortName, description, - geonameFileLegacyId, - bossHullLegacyId, + NameFileKey(geonameFileLegacyId), + ItemDefinitionKey(bossHullLegacyId), influenceDistance, allegianceCount, allegiances); @@ -385,7 +385,7 @@ namespace GameCult.Aetheria.State.Unity var sampleNames = ReadFieldStringArray(ref reader, fields, 3); var names = ReadFieldStringArray(ref reader, fields, 4); SkipRemaining(ref reader, fields, 5); - return new AetheriaRuntimeNameFile(legacyId, name, nameCount, sampleNames, names); + return new AetheriaRuntimeNameFile(NameFileKey(legacyId), name, nameCount, sampleNames, names); } private static EveSurfaceDocument ReadEveSurface(byte[] payload) @@ -1388,7 +1388,7 @@ namespace GameCult.Aetheria.State.Unity var corporationLegacyId = ReadFieldString(ref reader, allegianceFields, 0); var weight = ReadFieldDouble(ref reader, allegianceFields, 1); SkipRemaining(ref reader, allegianceFields, 2); - allegiances[allegiance] = new AetheriaRuntimeCorporationAllegiance(corporationLegacyId, weight); + allegiances[allegiance] = new AetheriaRuntimeCorporationAllegiance(CorporationKey(corporationLegacyId), weight); } return allegiances; @@ -1636,7 +1636,7 @@ namespace GameCult.Aetheria.State.Unity var itemKeyValue = ReadFieldString(ref reader, valueFields, 7); SkipRemaining(ref reader, valueFields, 8); if (string.IsNullOrWhiteSpace(itemKeyValue)) - itemKeyValue = ProjectLegacyItemKey(legacyIdValue); + itemKeyValue = ItemDefinitionKey(legacyIdValue); return new AetheriaRuntimeBehaviorValue(kind, stringValue, numberValue, boolValue, legacyIdValue, itemKeyValue, children, mapEntries); } @@ -1680,13 +1680,27 @@ namespace GameCult.Aetheria.State.Unity Array.Empty()); } - private static string ProjectLegacyItemKey(string legacyItemId) + private static string ItemDefinitionKey(string legacyItemId) { return string.IsNullOrWhiteSpace(legacyItemId) ? "" : $"aetheria.item_definition:legacy:{legacyItemId.Trim()}"; } + private static string CorporationKey(string legacyCorporationId) + { + return string.IsNullOrWhiteSpace(legacyCorporationId) + ? "" + : $"aetheria.corporation:legacy:{legacyCorporationId.Trim()}"; + } + + private static string NameFileKey(string legacyNameFileId) + { + return string.IsNullOrWhiteSpace(legacyNameFileId) + ? "" + : $"aetheria.name_file:legacy:{legacyNameFileId.Trim()}"; + } + private static string ReadString(ref MessagePackReader reader) { return reader.ReadString() ?? ""; diff --git a/docs/aetheria-perfect-machine-map.md b/docs/aetheria-perfect-machine-map.md index 0c91af3b0..7bc032d62 100644 --- a/docs/aetheria-perfect-machine-map.md +++ b/docs/aetheria-perfect-machine-map.md @@ -694,8 +694,10 @@ legacy catalog cache, and legacy UI paths should be migration-only or deleted. indexes items by canonical item key, and Unity gameplay/UI/zone helper lookups resolve `ItemKey` directly rather than deriving legacy GUIDs for `FindItemByLegacyId`. The package snapshot no longer exposes item, - corporation, or name-file `Find*ByLegacyId` indexes; legacy-ID lookup remains - only on the canonical `Aetheria.State` migration/catalog inspection boundary. + corporation, or name-file `Find*ByLegacyId` indexes, and its runtime + item/corporation/name-file DTOs no longer publish legacy relationship fields; + legacy-ID lookup remains only on the canonical `Aetheria.State` + migration/catalog inspection boundary. The shared runtime item catalog reader no longer has a GUID index or `GetRuntimeItem(Guid)` entry point; item-key strings are the only lookup authority; there is no remaining `ItemInstance.Data` identity/backing field. The reader interface for this @@ -1761,8 +1763,10 @@ First Aetheria surfaces to publish: faction resolver, or `CorporationLegacyId` relationship read may return to the live `Galaxy`/`LoadoutGenerator` path. - `Aetheria.State.Verify` guards Unity runtime catalog lookup authority: - package snapshots may expose typed-key lookup only, while legacy-ID lookup - remains quarantined in canonical migration/catalog inspection APIs. + package snapshots may expose typed-key lookup only, and runtime + item/corporation/name-file DTOs may not publish legacy relationship fields; + legacy-ID lookup remains quarantined in canonical migration/catalog + inspection APIs. - `Aetheria.State.Verify` guards behavior body reference naming: resource-scanner and mining-tool runtime state surfaces use `BodyKey` fields; old `*BodyId` readback names and generic legacy reference parsers may not