From 57985666d1928077c06b3b38b398dc1d0b30757e Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Sat, 13 Jun 2026 12:04:11 +0100 Subject: [PATCH] Move runtime catalog contract into Unity package --- .voidbot/state/aetheria.cc | Bin 27683 -> 28271 bytes Aetheria.State.Unity.Smoke/Program.cs | 1 + .../Aetheria.State.Unity.csproj | 1 + .../AetheriaRuntimeCatalogClient.cs | 3 +- .../AetheriaRuntimeCatalogSnapshot.cs | 488 ------------------ .../AetheriaRuntimeCatalogSnapshotMapper.cs | 121 +++++ .../Runtime/AetheriaRuntimeCatalogSnapshot.cs | 379 ++++++++++++++ docs/aetheria-perfect-machine-map.md | 29 +- 8 files changed, 520 insertions(+), 502 deletions(-) delete mode 100644 Aetheria.State.Unity/AetheriaRuntimeCatalogSnapshot.cs create mode 100644 Aetheria.State.Unity/AetheriaRuntimeCatalogSnapshotMapper.cs create mode 100644 Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeCatalogSnapshot.cs diff --git a/.voidbot/state/aetheria.cc b/.voidbot/state/aetheria.cc index a5b2da9e7ec710bbfc8c403672bbc295aba418c8..a1d39d0e29ad0b6b30a87971692345622a58188a 100644 GIT binary patch delta 1226 zcmZvc&ubGw6vs_kthI_#S_A&-cu}Zk-EOs^Kd?jv6{$#Df6#+EnSDvu&dw||vu$$< z;>BwjFCIlj@S>87H*a3N2wtod^e@n>9t7WRH%a|*O7b%E-uHdpcixjvx$hgfS5NbO zBNMJS;d#!;xM$rv2kra({au~d_`+Il(8{jWcFc3f(%6pfL-|{$n#a1?(Cv$}u`odh zgi%AetPus&C!zF#Yy4OSp9I24VitiwSOMS1$Tbm|I?;w2AQ5FtvNU){rJ2o*k-PMtwkujK@A`lu1pyoR+a-kd{fSO2O-CBj;jn&QXTxWCQ{fiFl0N(kR03 zRV71G25eXb)R{}0^d*Z!5Jo%C4G0}bvHlJrG*Suy=SWWoX^0;vUr2#HE3kr{~E$-e{63~1dz@K=#Pp<3f`cz^_`0_1E+ z9Sq?T;rRIP=ERE2fesSHKA=1w1j7r?Ysw5ZbSaE@fF?+K`*sCZP1_MstdeoF*bu!a zW1b8vlFFP^4XA>`G>}qFW`)u_a8sMKi*_`gNRErtUFpSyOg4yrz19MxB`K#u6B092 zVC!lm;Z7Wyus=G@V<2YT*5 zQBYmKVt-9f+3)VL2`>SQMT%%0Or-wvOfq*eDU3ph&Sr`!yEZ*wzqmu)GiWG#b$EYa z3|-r@>K2#TnI4kWb+b#o_R;k2?Mz2X-nG;noSfWpl?P%ev3UE@W!hR#w{IjEULCx{4Er&1Gu2heH71wJ1+VEk^un6I?;AQ}tWeC2EV>8k~?)hXhFKf-5N}pc7920C{)h-a97zP%f%{?CR4q&Em(^ z+n0;4cmAwg{5JxdjrQ2E9vxpVejXfFi@Q&jmzGP%qc01W=2Os|Ou>uJ#}amHIx%{V XZQpQMEf|)trp1bJ@M)<8-faH`z8*!X diff --git a/Aetheria.State.Unity.Smoke/Program.cs b/Aetheria.State.Unity.Smoke/Program.cs index de2cd97b5..c52ad34bb 100644 --- a/Aetheria.State.Unity.Smoke/Program.cs +++ b/Aetheria.State.Unity.Smoke/Program.cs @@ -1,5 +1,6 @@ using Aetheria.State; using Aetheria.State.Unity; +using GameCult.Aetheria.State.Unity; var root = args.Length > 0 ? Path.GetFullPath(args[0]) : Directory.GetCurrentDirectory(); var statePath = args.Length > 1 diff --git a/Aetheria.State.Unity/Aetheria.State.Unity.csproj b/Aetheria.State.Unity/Aetheria.State.Unity.csproj index d0c760e7b..fcf138bea 100644 --- a/Aetheria.State.Unity/Aetheria.State.Unity.csproj +++ b/Aetheria.State.Unity/Aetheria.State.Unity.csproj @@ -8,6 +8,7 @@ + diff --git a/Aetheria.State.Unity/AetheriaRuntimeCatalogClient.cs b/Aetheria.State.Unity/AetheriaRuntimeCatalogClient.cs index 7cc8deec3..9bbabea36 100644 --- a/Aetheria.State.Unity/AetheriaRuntimeCatalogClient.cs +++ b/Aetheria.State.Unity/AetheriaRuntimeCatalogClient.cs @@ -1,4 +1,5 @@ using Aetheria.State.Documents; +using GameCult.Aetheria.State.Unity; namespace Aetheria.State.Unity; @@ -20,7 +21,7 @@ public sealed class AetheriaRuntimeCatalogClient : IAsyncDisposable, IDisposable public AetheriaRuntimeCatalogSnapshot ReadCatalog() { var catalog = _node.ReadCatalogSnapshot(); - return AetheriaRuntimeCatalogSnapshot.FromCatalog(catalog); + return AetheriaRuntimeCatalogSnapshotMapper.FromCatalog(catalog); } public async Task ReadCatalogSurfaceAsync() diff --git a/Aetheria.State.Unity/AetheriaRuntimeCatalogSnapshot.cs b/Aetheria.State.Unity/AetheriaRuntimeCatalogSnapshot.cs deleted file mode 100644 index 1a4de3f4c..000000000 --- a/Aetheria.State.Unity/AetheriaRuntimeCatalogSnapshot.cs +++ /dev/null @@ -1,488 +0,0 @@ -using Aetheria.State.Documents; - -namespace Aetheria.State.Unity; - -public sealed class AetheriaRuntimeCatalogSnapshot -{ - private readonly Dictionary _itemsByLegacyId; - private readonly Dictionary _corporationsByLegacyId; - private readonly Dictionary _nameFilesByLegacyId; - - private AetheriaRuntimeCatalogSnapshot( - AetheriaRuntimeCatalogItem[] items, - AetheriaRuntimeCorporation[] corporations, - AetheriaRuntimeNameFile[] nameFiles) - { - Items = items; - Corporations = corporations; - NameFiles = nameFiles; - TradeItems = items.Where(item => item.Price > 0).ToArray(); - EquipmentItems = items.Where(item => !string.IsNullOrWhiteSpace(item.HardpointType)).ToArray(); - - _itemsByLegacyId = items - .Where(item => !string.IsNullOrWhiteSpace(item.LegacyId)) - .ToDictionary(item => item.LegacyId, StringComparer.OrdinalIgnoreCase); - _corporationsByLegacyId = corporations - .Where(corporation => !string.IsNullOrWhiteSpace(corporation.LegacyId)) - .ToDictionary(corporation => corporation.LegacyId, StringComparer.OrdinalIgnoreCase); - _nameFilesByLegacyId = nameFiles - .Where(nameFile => !string.IsNullOrWhiteSpace(nameFile.LegacyId)) - .ToDictionary(nameFile => nameFile.LegacyId, StringComparer.OrdinalIgnoreCase); - } - - public IReadOnlyList Items { get; } - - public IReadOnlyList TradeItems { get; } - - public IReadOnlyList EquipmentItems { get; } - - public IReadOnlyList Corporations { get; } - - public IReadOnlyList NameFiles { get; } - - public static AetheriaRuntimeCatalogSnapshot FromCatalog(AetheriaCatalogSnapshot catalog) - { - return new AetheriaRuntimeCatalogSnapshot( - catalog.Items.Select(AetheriaRuntimeCatalogItem.FromState).ToArray(), - catalog.Corporations.Select(AetheriaRuntimeCorporation.FromState).ToArray(), - catalog.NameFiles.Select(AetheriaRuntimeNameFile.FromState).ToArray()); - } - - public AetheriaRuntimeCatalogItem? FindItemByLegacyId(string legacyId) - { - return TryGet(_itemsByLegacyId, legacyId); - } - - public AetheriaRuntimeCorporation? FindCorporationByLegacyId(string legacyId) - { - return TryGet(_corporationsByLegacyId, legacyId); - } - - public AetheriaRuntimeNameFile? FindNameFileByLegacyId(string legacyId) - { - return TryGet(_nameFilesByLegacyId, legacyId); - } - - public IEnumerable FindItemsByBehavior(string behaviorKind) - { - return string.IsNullOrWhiteSpace(behaviorKind) - ? [] - : Items.Where(item => item.BehaviorKinds.Contains(behaviorKind, StringComparer.OrdinalIgnoreCase)); - } - - public IEnumerable FindItemsByHardpoint(string hardpointType) - { - return string.IsNullOrWhiteSpace(hardpointType) - ? [] - : Items.Where(item => string.Equals(item.HardpointType, hardpointType, StringComparison.OrdinalIgnoreCase)); - } - - public AetheriaRuntimeCorporation? GetManufacturer(AetheriaRuntimeCatalogItem item) - { - return FindCorporationByLegacyId(item.ManufacturerLegacyId); - } - - public AetheriaRuntimeNameFile? GetNameFile(AetheriaRuntimeCorporation corporation) - { - return FindNameFileByLegacyId(corporation.GeonameFileLegacyId); - } - - private static T? TryGet(IReadOnlyDictionary dictionary, string key) where T : class - { - return string.IsNullOrWhiteSpace(key) ? null : dictionary.TryGetValue(key, out var value) ? value : null; - } -} - -public sealed class AetheriaRuntimeCatalogItem -{ - public AetheriaRuntimeCatalogItem( - string legacyId, - string name, - string category, - string description, - string manufacturerLegacyId, - int price, - double mass, - double volume, - int shapeWidth, - int shapeHeight, - int occupiedCells, - IReadOnlyList shapeCells, - int interiorShapeWidth, - int interiorShapeHeight, - int interiorOccupiedCells, - IReadOnlyList interiorShapeCells, - IReadOnlyList hardpoints, - IReadOnlyList behaviorPayloads, - string hardpointType, - string hullType, - IReadOnlyList behaviorKinds, - int maxStack, - double durability, - string weaponRange, - string weaponCaliber, - string weaponType, - string weaponFireTypes, - string weaponModifiers) - { - LegacyId = legacyId; - Name = name; - Category = category; - Description = description; - ManufacturerLegacyId = manufacturerLegacyId; - Price = price; - Mass = mass; - Volume = volume; - ShapeWidth = shapeWidth; - ShapeHeight = shapeHeight; - OccupiedCells = occupiedCells; - ShapeCells = shapeCells; - InteriorShapeWidth = interiorShapeWidth; - InteriorShapeHeight = interiorShapeHeight; - InteriorOccupiedCells = interiorOccupiedCells; - InteriorShapeCells = interiorShapeCells; - Hardpoints = hardpoints; - BehaviorPayloads = behaviorPayloads; - HardpointType = hardpointType; - HullType = hullType; - BehaviorKinds = behaviorKinds; - MaxStack = maxStack; - Durability = durability; - WeaponRange = weaponRange; - WeaponCaliber = weaponCaliber; - WeaponType = weaponType; - WeaponFireTypes = weaponFireTypes; - WeaponModifiers = weaponModifiers; - } - - public string LegacyId { get; } - public string Name { get; } - public string Category { get; } - public string Description { get; } - public string ManufacturerLegacyId { get; } - public int Price { get; } - public double Mass { get; } - public double Volume { get; } - public int ShapeWidth { get; } - public int ShapeHeight { get; } - public int OccupiedCells { get; } - public IReadOnlyList ShapeCells { get; } - public int InteriorShapeWidth { get; } - public int InteriorShapeHeight { get; } - public int InteriorOccupiedCells { get; } - public IReadOnlyList InteriorShapeCells { get; } - public IReadOnlyList Hardpoints { get; } - public IReadOnlyList BehaviorPayloads { get; } - public string HardpointType { get; } - public string HullType { get; } - public IReadOnlyList BehaviorKinds { get; } - public int MaxStack { get; } - public double Durability { get; } - public string WeaponRange { get; } - public string WeaponCaliber { get; } - public string WeaponType { get; } - public string WeaponFireTypes { get; } - public string WeaponModifiers { get; } - - public static AetheriaRuntimeCatalogItem FromState(AetheriaItemDefinition item) - { - return new AetheriaRuntimeCatalogItem( - item.LegacyId, - item.Name, - item.Category, - item.Description, - item.ManufacturerLegacyId, - item.Price, - item.Mass, - item.Volume, - item.ShapeWidth, - item.ShapeHeight, - item.OccupiedCells, - item.ShapeCells.Select(AetheriaRuntimeShapeCell.FromState).ToArray(), - item.InteriorShapeWidth, - item.InteriorShapeHeight, - item.InteriorOccupiedCells, - item.InteriorShapeCells.Select(AetheriaRuntimeShapeCell.FromState).ToArray(), - item.Hardpoints.Select(AetheriaRuntimeHardpoint.FromState).ToArray(), - item.BehaviorPayloads.Select(AetheriaRuntimeBehaviorPayload.FromState).ToArray(), - item.HardpointType, - item.HullType, - item.BehaviorKinds, - item.MaxStack, - item.Durability, - item.WeaponRange, - item.WeaponCaliber, - item.WeaponType, - item.WeaponFireTypes, - item.WeaponModifiers); - } -} - -public sealed class AetheriaRuntimeShapeCell -{ - public AetheriaRuntimeShapeCell(int x, int y) - { - X = x; - Y = y; - } - - public int X { get; } - - public int Y { get; } - - public static AetheriaRuntimeShapeCell FromState(AetheriaShapeCell cell) - { - return new AetheriaRuntimeShapeCell(cell.X, cell.Y); - } -} - -public sealed class AetheriaRuntimeBehaviorPayload -{ - public AetheriaRuntimeBehaviorPayload( - int unionKey, - string kind, - int group, - IReadOnlyList fields) - { - UnionKey = unionKey; - Kind = kind; - Group = group; - Fields = fields; - } - - public int UnionKey { get; } - - public string Kind { get; } - - public int Group { get; } - - public IReadOnlyList Fields { get; } - - public static AetheriaRuntimeBehaviorPayload FromState(AetheriaBehaviorPayload payload) - { - return new AetheriaRuntimeBehaviorPayload( - payload.UnionKey, - payload.Kind, - payload.Group, - payload.Fields.Select(AetheriaRuntimeBehaviorField.FromState).ToArray()); - } -} - -public sealed class AetheriaRuntimeBehaviorField -{ - public AetheriaRuntimeBehaviorField(int key, AetheriaRuntimeBehaviorValue value) - { - Key = key; - Value = value; - } - - public int Key { get; } - - public AetheriaRuntimeBehaviorValue Value { get; } - - public static AetheriaRuntimeBehaviorField FromState(AetheriaBehaviorField field) - { - return new AetheriaRuntimeBehaviorField(field.Key, AetheriaRuntimeBehaviorValue.FromState(field.Value)); - } -} - -public sealed class AetheriaRuntimeBehaviorMapEntry -{ - public AetheriaRuntimeBehaviorMapEntry(string key, AetheriaRuntimeBehaviorValue value) - { - Key = key; - Value = value; - } - - public string Key { get; } - - public AetheriaRuntimeBehaviorValue Value { get; } - - public static AetheriaRuntimeBehaviorMapEntry FromState(AetheriaBehaviorMapEntry entry) - { - return new AetheriaRuntimeBehaviorMapEntry(entry.Key, AetheriaRuntimeBehaviorValue.FromState(entry.Value)); - } -} - -public sealed class AetheriaRuntimeBehaviorValue -{ - public AetheriaRuntimeBehaviorValue( - string kind, - string stringValue, - double numberValue, - bool boolValue, - string legacyIdValue, - IReadOnlyList children, - IReadOnlyList mapEntries) - { - Kind = kind; - StringValue = stringValue; - NumberValue = numberValue; - BoolValue = boolValue; - LegacyIdValue = legacyIdValue; - Children = children; - MapEntries = mapEntries; - } - - public string Kind { get; } - - public string StringValue { get; } - - public double NumberValue { get; } - - public bool BoolValue { get; } - - public string LegacyIdValue { get; } - - public IReadOnlyList Children { get; } - - public IReadOnlyList MapEntries { get; } - - public static AetheriaRuntimeBehaviorValue FromState(AetheriaBehaviorValue value) - { - return new AetheriaRuntimeBehaviorValue( - value.Kind, - value.StringValue, - value.NumberValue, - value.BoolValue, - value.LegacyIdValue, - value.Children.Select(FromState).ToArray(), - value.MapEntries.Select(AetheriaRuntimeBehaviorMapEntry.FromState).ToArray()); - } -} - -public sealed class AetheriaRuntimeHardpoint -{ - public AetheriaRuntimeHardpoint( - string type, - int positionX, - int positionY, - int shapeWidth, - int shapeHeight, - int occupiedCells, - IReadOnlyList shapeCells, - string transform, - string rotation, - double armor) - { - Type = type; - PositionX = positionX; - PositionY = positionY; - ShapeWidth = shapeWidth; - ShapeHeight = shapeHeight; - OccupiedCells = occupiedCells; - ShapeCells = shapeCells; - Transform = transform; - Rotation = rotation; - Armor = armor; - } - - public string Type { get; } - - public int PositionX { get; } - - public int PositionY { get; } - - public int ShapeWidth { get; } - - public int ShapeHeight { get; } - - public int OccupiedCells { get; } - - public IReadOnlyList ShapeCells { get; } - - public string Transform { get; } - - public string Rotation { get; } - - public double Armor { get; } - - public static AetheriaRuntimeHardpoint FromState(AetheriaItemHardpoint hardpoint) - { - return new AetheriaRuntimeHardpoint( - hardpoint.Type, - hardpoint.PositionX, - hardpoint.PositionY, - hardpoint.ShapeWidth, - hardpoint.ShapeHeight, - hardpoint.OccupiedCells, - hardpoint.ShapeCells.Select(AetheriaRuntimeShapeCell.FromState).ToArray(), - hardpoint.Transform, - hardpoint.Rotation, - hardpoint.Armor); - } -} - -public sealed class AetheriaRuntimeCorporation -{ - public AetheriaRuntimeCorporation( - string legacyId, - string name, - string shortName, - string description, - string geonameFileLegacyId, - string bossHullLegacyId, - int influenceDistance, - int allegianceCount) - { - LegacyId = legacyId; - Name = name; - ShortName = shortName; - Description = description; - GeonameFileLegacyId = geonameFileLegacyId; - BossHullLegacyId = bossHullLegacyId; - InfluenceDistance = influenceDistance; - AllegianceCount = allegianceCount; - } - - public string LegacyId { get; } - public string Name { get; } - public string ShortName { get; } - public string Description { get; } - public string GeonameFileLegacyId { get; } - public string BossHullLegacyId { get; } - public int InfluenceDistance { get; } - public int AllegianceCount { get; } - - public static AetheriaRuntimeCorporation FromState(AetheriaCorporation corporation) - { - return new AetheriaRuntimeCorporation( - corporation.LegacyId, - corporation.Name, - corporation.ShortName, - corporation.Description, - corporation.GeonameFileLegacyId, - corporation.BossHullLegacyId, - corporation.InfluenceDistance, - corporation.AllegianceCount); - } -} - -public sealed class AetheriaRuntimeNameFile -{ - public AetheriaRuntimeNameFile( - string legacyId, - string name, - int nameCount, - IReadOnlyList sampleNames) - { - LegacyId = legacyId; - Name = name; - NameCount = nameCount; - SampleNames = sampleNames; - } - - public string LegacyId { get; } - public string Name { get; } - public int NameCount { get; } - public IReadOnlyList SampleNames { get; } - - public static AetheriaRuntimeNameFile FromState(AetheriaNameFile nameFile) - { - return new AetheriaRuntimeNameFile( - nameFile.LegacyId, - nameFile.Name, - nameFile.NameCount, - nameFile.SampleNames); - } -} diff --git a/Aetheria.State.Unity/AetheriaRuntimeCatalogSnapshotMapper.cs b/Aetheria.State.Unity/AetheriaRuntimeCatalogSnapshotMapper.cs new file mode 100644 index 000000000..75220dab7 --- /dev/null +++ b/Aetheria.State.Unity/AetheriaRuntimeCatalogSnapshotMapper.cs @@ -0,0 +1,121 @@ +using Aetheria.State.Documents; +using GameCult.Aetheria.State.Unity; + +namespace Aetheria.State.Unity; + +internal static class AetheriaRuntimeCatalogSnapshotMapper +{ + public static AetheriaRuntimeCatalogSnapshot FromCatalog(AetheriaCatalogSnapshot catalog) + { + return new AetheriaRuntimeCatalogSnapshot( + catalog.Items.Select(FromState).ToArray(), + catalog.Corporations.Select(FromState).ToArray(), + catalog.NameFiles.Select(FromState).ToArray()); + } + + private static AetheriaRuntimeCatalogItem FromState(AetheriaItemDefinition item) + { + return new AetheriaRuntimeCatalogItem( + item.LegacyId, + item.Name, + item.Category, + item.Description, + item.ManufacturerLegacyId, + item.Price, + item.Mass, + item.Volume, + item.ShapeWidth, + item.ShapeHeight, + item.OccupiedCells, + item.ShapeCells.Select(FromState).ToArray(), + item.InteriorShapeWidth, + item.InteriorShapeHeight, + item.InteriorOccupiedCells, + item.InteriorShapeCells.Select(FromState).ToArray(), + item.Hardpoints.Select(FromState).ToArray(), + item.BehaviorPayloads.Select(FromState).ToArray(), + item.HardpointType, + item.HullType, + item.BehaviorKinds, + item.MaxStack, + item.Durability, + item.WeaponRange, + item.WeaponCaliber, + item.WeaponType, + item.WeaponFireTypes, + item.WeaponModifiers); + } + + private static AetheriaRuntimeShapeCell FromState(AetheriaShapeCell cell) + { + return new AetheriaRuntimeShapeCell(cell.X, cell.Y); + } + + private static AetheriaRuntimeBehaviorPayload FromState(AetheriaBehaviorPayload payload) + { + return new AetheriaRuntimeBehaviorPayload( + payload.UnionKey, + payload.Kind, + payload.Group, + payload.Fields.Select(FromState).ToArray()); + } + + private static AetheriaRuntimeBehaviorField FromState(AetheriaBehaviorField field) + { + return new AetheriaRuntimeBehaviorField(field.Key, FromState(field.Value)); + } + + private static AetheriaRuntimeBehaviorMapEntry FromState(AetheriaBehaviorMapEntry entry) + { + return new AetheriaRuntimeBehaviorMapEntry(entry.Key, FromState(entry.Value)); + } + + private static AetheriaRuntimeBehaviorValue FromState(AetheriaBehaviorValue value) + { + return new AetheriaRuntimeBehaviorValue( + value.Kind, + value.StringValue, + value.NumberValue, + value.BoolValue, + value.LegacyIdValue, + value.Children.Select(FromState).ToArray(), + value.MapEntries.Select(FromState).ToArray()); + } + + private static AetheriaRuntimeHardpoint FromState(AetheriaItemHardpoint hardpoint) + { + return new AetheriaRuntimeHardpoint( + hardpoint.Type, + hardpoint.PositionX, + hardpoint.PositionY, + hardpoint.ShapeWidth, + hardpoint.ShapeHeight, + hardpoint.OccupiedCells, + hardpoint.ShapeCells.Select(FromState).ToArray(), + hardpoint.Transform, + hardpoint.Rotation, + hardpoint.Armor); + } + + private static AetheriaRuntimeCorporation FromState(AetheriaCorporation corporation) + { + return new AetheriaRuntimeCorporation( + corporation.LegacyId, + corporation.Name, + corporation.ShortName, + corporation.Description, + corporation.GeonameFileLegacyId, + corporation.BossHullLegacyId, + corporation.InfluenceDistance, + corporation.AllegianceCount); + } + + private static AetheriaRuntimeNameFile FromState(AetheriaNameFile nameFile) + { + return new AetheriaRuntimeNameFile( + nameFile.LegacyId, + nameFile.Name, + nameFile.NameCount, + nameFile.SampleNames); + } +} diff --git a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeCatalogSnapshot.cs b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeCatalogSnapshot.cs new file mode 100644 index 000000000..4551997e9 --- /dev/null +++ b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeCatalogSnapshot.cs @@ -0,0 +1,379 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +#nullable enable + +namespace GameCult.Aetheria.State.Unity +{ + public sealed class AetheriaRuntimeCatalogSnapshot + { + private readonly Dictionary _itemsByLegacyId; + private readonly Dictionary _corporationsByLegacyId; + private readonly Dictionary _nameFilesByLegacyId; + + public AetheriaRuntimeCatalogSnapshot( + AetheriaRuntimeCatalogItem[] items, + AetheriaRuntimeCorporation[] corporations, + AetheriaRuntimeNameFile[] nameFiles) + { + Items = items; + Corporations = corporations; + NameFiles = nameFiles; + TradeItems = items.Where(item => item.Price > 0).ToArray(); + EquipmentItems = items.Where(item => !string.IsNullOrWhiteSpace(item.HardpointType)).ToArray(); + + _itemsByLegacyId = items + .Where(item => !string.IsNullOrWhiteSpace(item.LegacyId)) + .ToDictionary(item => item.LegacyId, StringComparer.OrdinalIgnoreCase); + _corporationsByLegacyId = corporations + .Where(corporation => !string.IsNullOrWhiteSpace(corporation.LegacyId)) + .ToDictionary(corporation => corporation.LegacyId, StringComparer.OrdinalIgnoreCase); + _nameFilesByLegacyId = nameFiles + .Where(nameFile => !string.IsNullOrWhiteSpace(nameFile.LegacyId)) + .ToDictionary(nameFile => nameFile.LegacyId, StringComparer.OrdinalIgnoreCase); + } + + public IReadOnlyList Items { get; } + + public IReadOnlyList TradeItems { get; } + + public IReadOnlyList EquipmentItems { get; } + + public IReadOnlyList Corporations { get; } + + public IReadOnlyList NameFiles { get; } + + public AetheriaRuntimeCatalogItem? FindItemByLegacyId(string legacyId) + { + return TryGet(_itemsByLegacyId, legacyId); + } + + public AetheriaRuntimeCorporation? FindCorporationByLegacyId(string legacyId) + { + return TryGet(_corporationsByLegacyId, legacyId); + } + + public AetheriaRuntimeNameFile? FindNameFileByLegacyId(string legacyId) + { + return TryGet(_nameFilesByLegacyId, legacyId); + } + + public IEnumerable FindItemsByBehavior(string behaviorKind) + { + return string.IsNullOrWhiteSpace(behaviorKind) + ? Enumerable.Empty() + : Items.Where(item => item.BehaviorKinds.Contains(behaviorKind, StringComparer.OrdinalIgnoreCase)); + } + + public IEnumerable FindItemsByHardpoint(string hardpointType) + { + return string.IsNullOrWhiteSpace(hardpointType) + ? Enumerable.Empty() + : Items.Where(item => string.Equals(item.HardpointType, hardpointType, StringComparison.OrdinalIgnoreCase)); + } + + public AetheriaRuntimeCorporation? GetManufacturer(AetheriaRuntimeCatalogItem item) + { + return FindCorporationByLegacyId(item.ManufacturerLegacyId); + } + + public AetheriaRuntimeNameFile? GetNameFile(AetheriaRuntimeCorporation corporation) + { + return FindNameFileByLegacyId(corporation.GeonameFileLegacyId); + } + + private static T? TryGet(IReadOnlyDictionary dictionary, string key) where T : class + { + return string.IsNullOrWhiteSpace(key) ? null : dictionary.TryGetValue(key, out var value) ? value : null; + } + } + + public sealed class AetheriaRuntimeCatalogItem + { + public AetheriaRuntimeCatalogItem( + string legacyId, + string name, + string category, + string description, + string manufacturerLegacyId, + int price, + double mass, + double volume, + int shapeWidth, + int shapeHeight, + int occupiedCells, + IReadOnlyList shapeCells, + int interiorShapeWidth, + int interiorShapeHeight, + int interiorOccupiedCells, + IReadOnlyList interiorShapeCells, + IReadOnlyList hardpoints, + IReadOnlyList behaviorPayloads, + string hardpointType, + string hullType, + IReadOnlyList behaviorKinds, + int maxStack, + double durability, + string weaponRange, + string weaponCaliber, + string weaponType, + string weaponFireTypes, + string weaponModifiers) + { + LegacyId = legacyId; + Name = name; + Category = category; + Description = description; + ManufacturerLegacyId = manufacturerLegacyId; + Price = price; + Mass = mass; + Volume = volume; + ShapeWidth = shapeWidth; + ShapeHeight = shapeHeight; + OccupiedCells = occupiedCells; + ShapeCells = shapeCells; + InteriorShapeWidth = interiorShapeWidth; + InteriorShapeHeight = interiorShapeHeight; + InteriorOccupiedCells = interiorOccupiedCells; + InteriorShapeCells = interiorShapeCells; + Hardpoints = hardpoints; + BehaviorPayloads = behaviorPayloads; + HardpointType = hardpointType; + HullType = hullType; + BehaviorKinds = behaviorKinds; + MaxStack = maxStack; + Durability = durability; + WeaponRange = weaponRange; + WeaponCaliber = weaponCaliber; + WeaponType = weaponType; + WeaponFireTypes = weaponFireTypes; + WeaponModifiers = weaponModifiers; + } + + public string LegacyId { get; } + public string Name { get; } + public string Category { get; } + public string Description { get; } + public string ManufacturerLegacyId { get; } + public int Price { get; } + public double Mass { get; } + public double Volume { get; } + public int ShapeWidth { get; } + public int ShapeHeight { get; } + public int OccupiedCells { get; } + public IReadOnlyList ShapeCells { get; } + public int InteriorShapeWidth { get; } + public int InteriorShapeHeight { get; } + public int InteriorOccupiedCells { get; } + public IReadOnlyList InteriorShapeCells { get; } + public IReadOnlyList Hardpoints { get; } + public IReadOnlyList BehaviorPayloads { get; } + public string HardpointType { get; } + public string HullType { get; } + public IReadOnlyList BehaviorKinds { get; } + public int MaxStack { get; } + public double Durability { get; } + public string WeaponRange { get; } + public string WeaponCaliber { get; } + public string WeaponType { get; } + public string WeaponFireTypes { get; } + public string WeaponModifiers { get; } + } + + public sealed class AetheriaRuntimeShapeCell + { + public AetheriaRuntimeShapeCell(int x, int y) + { + X = x; + Y = y; + } + + public int X { get; } + + public int Y { get; } + } + + public sealed class AetheriaRuntimeBehaviorPayload + { + public AetheriaRuntimeBehaviorPayload( + int unionKey, + string kind, + int group, + IReadOnlyList fields) + { + UnionKey = unionKey; + Kind = kind; + Group = group; + Fields = fields; + } + + public int UnionKey { get; } + + public string Kind { get; } + + public int Group { get; } + + public IReadOnlyList Fields { get; } + } + + public sealed class AetheriaRuntimeBehaviorField + { + public AetheriaRuntimeBehaviorField(int key, AetheriaRuntimeBehaviorValue value) + { + Key = key; + Value = value; + } + + public int Key { get; } + + public AetheriaRuntimeBehaviorValue Value { get; } + } + + public sealed class AetheriaRuntimeBehaviorMapEntry + { + public AetheriaRuntimeBehaviorMapEntry(string key, AetheriaRuntimeBehaviorValue value) + { + Key = key; + Value = value; + } + + public string Key { get; } + + public AetheriaRuntimeBehaviorValue Value { get; } + } + + public sealed class AetheriaRuntimeBehaviorValue + { + public AetheriaRuntimeBehaviorValue( + string kind, + string stringValue, + double numberValue, + bool boolValue, + string legacyIdValue, + IReadOnlyList children, + IReadOnlyList mapEntries) + { + Kind = kind; + StringValue = stringValue; + NumberValue = numberValue; + BoolValue = boolValue; + LegacyIdValue = legacyIdValue; + Children = children; + MapEntries = mapEntries; + } + + public string Kind { get; } + + public string StringValue { get; } + + public double NumberValue { get; } + + public bool BoolValue { get; } + + public string LegacyIdValue { get; } + + public IReadOnlyList Children { get; } + + public IReadOnlyList MapEntries { get; } + } + + public sealed class AetheriaRuntimeHardpoint + { + public AetheriaRuntimeHardpoint( + string type, + int positionX, + int positionY, + int shapeWidth, + int shapeHeight, + int occupiedCells, + IReadOnlyList shapeCells, + string transform, + string rotation, + double armor) + { + Type = type; + PositionX = positionX; + PositionY = positionY; + ShapeWidth = shapeWidth; + ShapeHeight = shapeHeight; + OccupiedCells = occupiedCells; + ShapeCells = shapeCells; + Transform = transform; + Rotation = rotation; + Armor = armor; + } + + public string Type { get; } + + public int PositionX { get; } + + public int PositionY { get; } + + public int ShapeWidth { get; } + + public int ShapeHeight { get; } + + public int OccupiedCells { get; } + + public IReadOnlyList ShapeCells { get; } + + public string Transform { get; } + + public string Rotation { get; } + + public double Armor { get; } + } + + public sealed class AetheriaRuntimeCorporation + { + public AetheriaRuntimeCorporation( + string legacyId, + string name, + string shortName, + string description, + string geonameFileLegacyId, + string bossHullLegacyId, + int influenceDistance, + int allegianceCount) + { + LegacyId = legacyId; + Name = name; + ShortName = shortName; + Description = description; + GeonameFileLegacyId = geonameFileLegacyId; + BossHullLegacyId = bossHullLegacyId; + InfluenceDistance = influenceDistance; + AllegianceCount = allegianceCount; + } + + public string LegacyId { get; } + public string Name { get; } + public string ShortName { get; } + public string Description { get; } + public string GeonameFileLegacyId { get; } + public string BossHullLegacyId { get; } + public int InfluenceDistance { get; } + public int AllegianceCount { get; } + } + + public sealed class AetheriaRuntimeNameFile + { + public AetheriaRuntimeNameFile( + string legacyId, + string name, + int nameCount, + IReadOnlyList sampleNames) + { + LegacyId = legacyId; + Name = name; + NameCount = nameCount; + SampleNames = sampleNames; + } + + public string LegacyId { get; } + public string Name { get; } + public int NameCount { get; } + public IReadOnlyList SampleNames { get; } + } +} diff --git a/docs/aetheria-perfect-machine-map.md b/docs/aetheria-perfect-machine-map.md index df30e66b2..eed66dd02 100644 --- a/docs/aetheria-perfect-machine-map.md +++ b/docs/aetheria-perfect-machine-map.md @@ -117,15 +117,15 @@ legacy catalog cache, and legacy UI paths should be migration-only or deleted. `.cc` records. It exposes trade-item, manufacturer, corporation prefix, and corporation name-file queries, plus equipment, hardpoint, and behavior queries without touching `DatabaseEntry`. -- `Aetheria.State.Unity` is the Unity-facing runtime read facade over typed - catalog state. It opens `aetheria-world.cc`, emits immutable catalog read - models for trade/equipment/behavior/hardpoint/manufacturer/corporation/name - queries, exposes typed item shape masks for layout/fitting consumers, and - exposes typed interior masks and hardpoints for future equipment/cargo - layout consumers, plus typed behavior payload read models for future - behavior factories. It reads the published Eve surface without deserializing - legacy `DatabaseEntry` objects. It is not a simulation owner and does not - write state. +- The embedded `GameCult.Aetheria.State.Unity` package now owns the + Unity-visible immutable catalog read-model contract for + trade/equipment/behavior/hardpoint/manufacturer/corporation/name queries, + typed item shape masks, typed interior masks, hardpoints, and behavior + payloads. The SDK-style `Aetheria.State.Unity` facade includes that package + source and owns only the `.cc` opener plus mapper from `Aetheria.State` + documents into the package contract. It reads the published Eve surface + without deserializing legacy `DatabaseEntry` objects. It is not a simulation + owner and does not write state. - `AetheriaCatalogSurfaceProjector` now emits the first provider-owned Eve surface from typed catalog state. The importer materializes a `gamecult.eve.surface.v1` catalog operator document at @@ -213,9 +213,11 @@ legacy catalog cache, and legacy UI paths should be migration-only or deleted. where gameplay only needs lookups. `ItemManager` still receives `ILegacyCatalogReader` until typed runtime catalog boot replaces it; `Galaxy` has been moved off the legacy reader and now consumes `ItemManager`. - `Aetheria.State.Unity` owns a read-only typed catalog facade for future Unity - consumers; it does not write state or own simulation. The legacy cache no - longer has a public mutation surface. + The embedded Unity state package owns the read-only runtime catalog model + contract for future Unity consumers; the SDK-style `Aetheria.State.Unity` + facade maps typed `.cc` documents into that contract for current .NET smokes. + Neither writes state or owns simulation. The legacy cache no longer has a + public mutation surface. - Inputs: Unity gameplay code, legacy catalog files, typed state documents, and CultMesh server state. - Outputs: `Aetheria.State` emits `.cc` state and CultMesh documents. Legacy @@ -423,7 +425,8 @@ First Aetheria surfaces to publish: - Migration smoke proves stable old catalog payload fields can be read once and converted without old readers remaining on the live runtime path. - Unity runtime catalog smoke proves read-only catalog consumers can open the - typed `.cc` store through `Aetheria.State.Unity` without `DatabaseEntry` or + typed `.cc` store through the SDK-style `Aetheria.State.Unity` opener and + receive package-owned runtime catalog read models without `DatabaseEntry` or `LegacyCatalogCache`, including typed item masks, interior masks, and hardpoint definitions, plus typed behavior payloads. - Unity play smoke proves runtime UI reads from Eve surfaces and sends commands