From f13f70d92b28069f14a906da140f2e6800486b35 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Thu, 2 Jul 2026 20:36:28 +0100 Subject: [PATCH] Advertise Aetheria Eve surface catalog --- Aetheria.State.Daemon/Program.cs | 1 + Aetheria.State/AetheriaEveSurfaceDocuments.cs | 52 ++----- .../Runtime/AetheriaRuntimeDaemonDocuments.cs | 6 + ...theriaRuntimeDaemonEditorSurfaceBuilder.cs | 28 ++++ .../AetheriaRuntimeEveSurfaceCatalog.cs | 133 ++++++++++++++++++ docs/aetheria-perfect-machine-map.md | 16 ++- 6 files changed, 194 insertions(+), 42 deletions(-) create mode 100644 Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeEveSurfaceCatalog.cs diff --git a/Aetheria.State.Daemon/Program.cs b/Aetheria.State.Daemon/Program.cs index a72f10ca2..aebdad066 100644 --- a/Aetheria.State.Daemon/Program.cs +++ b/Aetheria.State.Daemon/Program.cs @@ -2,6 +2,7 @@ using Aetheria.State; using Aetheria.State.Documents; using GameCult.Aetheria.State.Verse; using GameCult.Caching; +using GameCult.Eve.Surface; using GameCult.Mesh; using GameCult.Networking; using MessagePack; diff --git a/Aetheria.State/AetheriaEveSurfaceDocuments.cs b/Aetheria.State/AetheriaEveSurfaceDocuments.cs index abf468cb9..4a9e42f8f 100644 --- a/Aetheria.State/AetheriaEveSurfaceDocuments.cs +++ b/Aetheria.State/AetheriaEveSurfaceDocuments.cs @@ -323,44 +323,9 @@ public static class AetheriaEveSurfaceDocuments Summary = "Aetheria daemon editor Eve TUI surface record" } ], - Surfaces = - [ - new EveProviderSurfaceRef - { - SurfaceId = CatalogSurfaceId, - Key = CatalogSurfaceKey - }, - new EveProviderSurfaceRef - { - SurfaceId = OperationsSurfaceId, - Key = OperationsSurfaceKey - }, - new EveProviderSurfaceRef - { - SurfaceId = PlayerSettingsSurfaceId, - Key = PlayerSettingsSurfaceKey - }, - new EveProviderSurfaceRef - { - SurfaceId = AetheriaRuntimeDaemonGameSurfaceBuilder.SurfaceId, - Key = DaemonGameSurfaceKey - }, - new EveProviderSurfaceRef - { - SurfaceId = AetheriaRuntimeDaemonGameSurfaceBuilder.TuiSurfaceId, - Key = DaemonGameTuiSurfaceKey - }, - new EveProviderSurfaceRef - { - SurfaceId = AetheriaRuntimeDaemonEditorSurfaceBuilder.SurfaceId, - Key = DaemonEditorSurfaceKey - }, - new EveProviderSurfaceRef - { - SurfaceId = AetheriaRuntimeDaemonEditorSurfaceBuilder.TuiSurfaceId, - Key = DaemonEditorTuiSurfaceKey - } - ], + Surfaces = AetheriaRuntimeEveSurfaceCatalog.All + .Select(ToProviderSurfaceRef) + .ToArray(), Commands = [ new EveProviderCommandRef @@ -413,6 +378,17 @@ public static class AetheriaEveSurfaceDocuments }; } + private static EveProviderSurfaceRef ToProviderSurfaceRef(AetheriaRuntimeEveSurfaceAdvertisement surface) + { + return new EveProviderSurfaceRef + { + SurfaceId = surface.SurfaceId, + Key = surface.RecordRef, + Transport = surface.Transport, + Status = surface.Status + }; + } + private static string LatestTimestamp(params string?[] timestamps) { var latest = ""; diff --git a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeDaemonDocuments.cs b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeDaemonDocuments.cs index a19266fb2..b4242c396 100644 --- a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeDaemonDocuments.cs +++ b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeDaemonDocuments.cs @@ -263,6 +263,10 @@ namespace GameCult.Aetheria.State.Verse [Key(21)] public string AssetManifestRecordRef { get; set; } = ""; + [Key(22)] + public IReadOnlyList EveSurfaces { get; set; } = + Array.Empty(); + public static AetheriaRuntimeDaemonProviderAdvertisementDocument Create( string stateFilePath, string daemonId, @@ -291,6 +295,7 @@ namespace GameCult.Aetheria.State.Verse CultMeshAddress = string.IsNullOrWhiteSpace(cultMeshAddress) ? "cultmesh://aetheria.local/eve/providers/aetheria.daemon" : cultMeshAddress, + EveSurfaces = AetheriaRuntimeEveSurfaceCatalog.All, PublishedSchemas = new[] { AetheriaRuntimeDaemonSchemas.Frame, @@ -313,6 +318,7 @@ namespace GameCult.Aetheria.State.Verse AetheriaRuntimeDaemonSchemas.Inventory, AetheriaRuntimeDaemonSchemas.GameSurface, AetheriaRuntimeDaemonSchemas.EditorSurface, + "gamecult.eve.surface.v1", AetheriaRuntimeDaemonSchemas.Command, AetheriaRuntimeDaemonSchemas.StarbridgeScenario, AetheriaRuntimeDaemonSchemas.StarbridgeSession, diff --git a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeDaemonEditorSurfaceBuilder.cs b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeDaemonEditorSurfaceBuilder.cs index 058659487..66c978352 100644 --- a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeDaemonEditorSurfaceBuilder.cs +++ b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeDaemonEditorSurfaceBuilder.cs @@ -106,6 +106,16 @@ namespace GameCult.Aetheria.State.Verse designerSurfaces .Where(surface => surface != null) .Select((surface, index) => DesignerSurfaceRow(index, surface)) + .ToArray())), + Node( + "aetheria.daemon.editor.eve_surfaces", + "card", + new[] { ("title", "Advertised Eve Surfaces") }, + Row( + "aetheria.daemon.editor.eve_surfaces.rows", + provider.EveSurfaces + .Where(surface => surface != null) + .Select((surface, index) => AdvertisedSurfaceRow(index, surface)) .ToArray()))), Array.Empty()), commands: commandBoundary.Commands @@ -134,6 +144,24 @@ namespace GameCult.Aetheria.State.Verse }); } + private static AetheriaRuntimeSurfaceComponent AdvertisedSurfaceRow( + int index, + AetheriaRuntimeEveSurfaceAdvertisement surface) + { + return Node( + $"aetheria.daemon.editor.eve_surfaces.{index}", + "inspector.kv", + new[] + { + ("title", surface.Title), + ("surfaceId", surface.SurfaceId), + ("record", surface.RecordRef), + ("status", surface.Status), + ("audience", surface.Audience), + ("provider", surface.ProviderId) + }); + } + private static AetheriaRuntimeSurfaceComponent CommandRow( int index, AetheriaRuntimeDaemonCommandBoundaryEntry entry) diff --git a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeEveSurfaceCatalog.cs b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeEveSurfaceCatalog.cs new file mode 100644 index 000000000..48b76e5df --- /dev/null +++ b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeEveSurfaceCatalog.cs @@ -0,0 +1,133 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using MessagePack; + +#nullable enable + +namespace GameCult.Aetheria.State.Verse +{ + [MessagePackObject] + public sealed class AetheriaRuntimeEveSurfaceAdvertisement + { + [Key(0)] + public string SurfaceId { get; set; } = ""; + + [Key(1)] + public string Title { get; set; } = ""; + + [Key(2)] + public string ProviderId { get; set; } = "aetheria"; + + [Key(3)] + public string ProviderKind { get; set; } = "game.runtime"; + + [Key(4)] + public string RecordRef { get; set; } = ""; + + [Key(5)] + public string Transport { get; set; } = "cultmesh-managed"; + + [Key(6)] + public string Status { get; set; } = "available"; + + [Key(7)] + public string Audience { get; set; } = "operator"; + + [Key(8)] + public string Mode { get; set; } = "interactive"; + + [Key(9)] + public string Summary { get; set; } = ""; + + [Key(10)] + public IReadOnlyList Commands { get; set; } = Array.Empty(); + } + + public static class AetheriaRuntimeEveSurfaceCatalog + { + private const string SurfaceSchema = "gamecult.eve.surface.v1"; + + private static readonly AetheriaRuntimeEveSurfaceAdvertisement[] Surfaces = + { + Surface(AetheriaRuntimeCatalogCommands.SurfaceId, "Aetheria Catalog", "eve:surface:aetheria.catalog.operator", "operator", "Aetheria catalog operator surface.", AetheriaRuntimeCatalogCommands.Refresh), + Surface(AetheriaRuntimeOperationsCommands.SurfaceId, "Aetheria Operations", "eve:surface:aetheria.operations", "operator", "Daemon operation and Eve command acceptance surface.", AetheriaRuntimeOperationsCommands.Refresh), + Surface(AetheriaRuntimePlayerSettingsCommands.SurfaceId, "Player Settings", "eve:surface:aetheria.player_settings", "player", "Typed player settings surface.", + AetheriaRuntimePlayerSettingsCommands.Refresh, + AetheriaRuntimePlayerSettingsCommands.CycleTemperatureUnit, + AetheriaRuntimePlayerSettingsCommands.DecrementSignificantDigits, + AetheriaRuntimePlayerSettingsCommands.IncrementSignificantDigits, + AetheriaRuntimePlayerSettingsCommands.CycleNebulaQuality, + AetheriaRuntimePlayerSettingsCommands.ToggleShowAsteroidsInMinimap), + Surface(AetheriaRuntimeDaemonGameSurfaceBuilder.SurfaceId, "Aetheria Daemon", AetheriaRuntimeVerseRecordKeys.DaemonGameSurface.ToString(), "player", "Authoritative daemon game surface.", providerId: "aetheria.daemon", providerKind: "game.daemon", transport: "cultmesh-record"), + Surface(AetheriaRuntimeDaemonGameSurfaceBuilder.TuiSurfaceId, "Aetheria Daemon TUI", AetheriaRuntimeVerseRecordKeys.DaemonGameTuiSurface.ToString(), "agent", "Compact daemon game surface for dense inspection.", providerId: "aetheria.daemon", providerKind: "game.daemon", transport: "cultmesh-record"), + Surface(AetheriaRuntimeDaemonEditorSurfaceBuilder.SurfaceId, "Aetheria Daemon Editor", AetheriaRuntimeVerseRecordKeys.DaemonEditorSurface.ToString(), "operator", "Daemon editor and surface inventory.", providerId: "aetheria.daemon", providerKind: "editor.daemon", transport: "cultmesh-record"), + Surface(AetheriaRuntimeDaemonEditorSurfaceBuilder.TuiSurfaceId, "Aetheria Daemon Editor TUI", AetheriaRuntimeVerseRecordKeys.DaemonEditorTuiSurface.ToString(), "agent", "Compact daemon editor and surface inventory.", providerId: "aetheria.daemon", providerKind: "editor.daemon", transport: "cultmesh-record"), + Surface(AetheriaRuntimeMainMenuCommands.RootSurfaceId, "Main Menu", "", "player", "Runtime main menu root.", status: "client-contextual"), + Surface(AetheriaRuntimeMainMenuCommands.SettingsSurfaceId, "Main Menu Settings", "", "player", "Runtime main menu settings shell.", status: "client-contextual"), + Surface(AetheriaRuntimeMainMenuCommands.InputSettingsSurfaceId, "Main Menu Input Settings", "", "player", "Main menu input settings handoff shell.", status: "client-contextual"), + Surface(AetheriaRuntimeMainMenuCommands.PlayerSettingsShellSurfaceId, "Main Menu Player Settings", "", "player", "Main menu player settings shell.", status: "client-contextual"), + Surface(AetheriaRuntimeMainMenuCommands.VerseSettingsShellSurfaceId, "Main Menu Verse Settings", "", "player", "Main menu Verse settings shell.", status: "client-contextual"), + Surface(AetheriaRuntimeInputSettingsCommands.SurfaceId, "Input Settings", "", "player", "Runtime input binding surface.", status: "client-contextual"), + Surface(AetheriaRuntimeVerseHostCommands.SurfaceId, "Verse Host Settings", "", "operator", "Verse host visibility and discovery surface.", status: "client-contextual"), + Surface(AetheriaRuntimeLoadoutTemplateCommands.SurfaceId, "Loadout Templates", "", "player", "Loadout template save surface.", status: "client-contextual"), + Surface(AetheriaRuntimeClientTargetCommands.SurfaceId, "Client Target", "", "operator", "Local client target and Verse discovery surface.", status: "client-contextual"), + Surface(AetheriaRuntimeLocalStorySurfaceBuilder.SurfaceId, "Local Story", "", "player", "Local runtime story/menu surface.", status: "client-contextual"), + Surface(AetheriaRuntimeZoneDetailsSurfaceBuilder.SurfaceId, "Zone Details", "", "player", "Selected zone details surface.", status: "contextual"), + Surface(AetheriaRuntimeInventoryPanelSurfaceBuilder.SurfaceId, "Inventory Panel", "", "player", "Current inventory panel surface.", status: "contextual"), + Surface(AetheriaRuntimeInventoryDropdownSurfaceBuilder.SurfaceId, "Inventory Dropdown", "", "player", "Inventory navigation dropdown surface.", status: "contextual"), + Surface(AetheriaRuntimeShipSettingsSurfaceBuilder.SurfaceId, "Current Ship Settings", "", "player", "Current ship settings surface.", status: "contextual"), + Surface(AetheriaRuntimeCargoItemDetailsSurfaceBuilder.SurfaceId, "Cargo Item Details", "", "player", "Selected cargo item details surface.", status: "contextual"), + Surface(AetheriaRuntimeEquippedItemDetailsSurfaceBuilder.SurfaceId, "Equipped Item Details", "", "player", "Selected equipped item details surface.", status: "contextual"), + Surface(AetheriaRuntimeTradeCargoSelectorSurfaceBuilder.SurfaceId, "Trade Cargo Selector", "", "player", "Trade cargo target selector surface.", status: "contextual"), + Surface(AetheriaRuntimeTradeInteractionSurfaceBuilder.FilterSurfaceId, "Trade Filter Selector", "", "player", "Trade filter selector surface.", status: "contextual"), + Surface(AetheriaRuntimeTradeInteractionSurfaceBuilder.RowActionSurfaceId, "Trade Row Actions", "", "player", "Trade row action selector surface.", status: "contextual"), + Surface(AetheriaRuntimeTradeItemDetailsSurfaceBuilder.SurfaceId, "Trade Item Details", "", "player", "Selected trade item details surface.", status: "contextual"), + Surface(AetheriaRuntimeStatRecipeCommands.SurfaceId, "Stat Recipes", "", "designer", "Designer stat recipe surface.", status: "designer-preview"), + Surface(AetheriaRuntimeTradeValuePolicySurfaceBuilder.SurfaceId, "Trade Value Policy", "", "designer", "Designer trade value policy surface.", status: "designer-preview") + }; + + public static IReadOnlyList All => Surfaces; + + public static IReadOnlyList SurfaceSchemas { get; } = new[] { SurfaceSchema }; + + private static AetheriaRuntimeEveSurfaceAdvertisement Surface( + string surfaceId, + string title, + string recordRef, + string audience, + string summary, + params string[] commands) + { + return Surface(surfaceId, title, recordRef, audience, summary, "aetheria", "game.runtime", "cultmesh-managed", "available", commands); + } + + private static AetheriaRuntimeEveSurfaceAdvertisement Surface( + string surfaceId, + string title, + string recordRef, + string audience, + string summary, + string providerId = "aetheria", + string providerKind = "game.runtime", + string transport = "cultmesh-managed", + string status = "available", + params string[] commands) + { + return new AetheriaRuntimeEveSurfaceAdvertisement + { + SurfaceId = surfaceId, + Title = title, + ProviderId = providerId, + ProviderKind = providerKind, + RecordRef = recordRef ?? "", + Transport = transport, + Status = status, + Audience = audience, + Mode = "interactive", + Summary = summary, + Commands = commands?.Where(command => !string.IsNullOrWhiteSpace(command)).ToArray() ?? Array.Empty() + }; + } + } +} diff --git a/docs/aetheria-perfect-machine-map.md b/docs/aetheria-perfect-machine-map.md index 339f2c185..6a11c15e3 100644 --- a/docs/aetheria-perfect-machine-map.md +++ b/docs/aetheria-perfect-machine-map.md @@ -527,10 +527,15 @@ legacy catalog cache, and legacy UI paths should be migration-only or deleted. narrow typed command buttons, not renderer-local fields. - `AetheriaProviderAdvertisementProjector` publishes `gamecult.eve.provider_advertisement.v1` for the `aetheria` provider, - advertising the catalog, operations, and player-settings surfaces, command - boundaries, schemas, and `.cc` witness path. Its Verse/service identity now - comes from typed daemon host settings instead of hardcoded projector fields. - This is the discovery map for Odin/Eve, not a health page. + advertising the shared runtime Eve surface catalog, command boundaries, + schemas, and `.cc` witness path. Its Verse/service identity now comes from + typed daemon host settings instead of hardcoded projector fields. This is the + discovery map for Odin/Eve, not a health page. +- `AetheriaRuntimeEveSurfaceCatalog` is the single inventory of known Aetheria + Eve panels. The daemon advertisement and Odin-facing provider advertisement + both derive from it, so daemon GUI/TUI records, operator records, menu shells, + inventory/trade panels, contextual inspectors, and designer previews are + visible without making Unity or Electron the owner. - `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 @@ -1678,6 +1683,9 @@ First Aetheria surfaces to publish: surface and advertise their command boundary through the provider ad. - Done: publish an Eve provider advertisement so Odin/Eve can discover Aetheria surfaces and command boundaries through typed state. + - Done: make the daemon/provider advertisements derive from the shared + `AetheriaRuntimeEveSurfaceCatalog`, so Odin/Eir can index every known + Aetheria Eve panel instead of only the daemon game/editor surfaces. - Done: stop legacy catalog pull/read paths from writing entries back to their source backing store. - Done: delete legacy catalog backing-store write/realtime APIs.