diff --git a/.voidbot/state/aetheria.cc b/.voidbot/state/aetheria.cc
index a5b2da9e7..a1d39d0e2 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 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