From 97f86d53656f9ee8efbf1262c47456eae2f1652f Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Sat, 11 Jul 2026 00:56:19 +0100 Subject: [PATCH] refactor(modes): share pilot surface across game modes --- Aetheria.State.AuthoritySmoke/Program.cs | 2 +- Aetheria.State.Daemon/Program.cs | 1 - ...AetheriaRuntimeDaemonGameSurfaceBuilder.cs | 23 ++----------------- .../AetheriaRuntimeDaemonTickRunner.cs | 3 +-- .../AetheriaRuntimeEveSurfaceCatalog.cs | 2 +- conformance/eve/aetheria-world-scenario.json | 4 ++-- conformance/eve/aetheria-world-surface.json | 2 +- .../eve/aetheria.provider-advertisement.json | 6 ++--- scripts/verify-eve-conformance-pack.mjs | 6 ++++- 9 files changed, 16 insertions(+), 33 deletions(-) diff --git a/Aetheria.State.AuthoritySmoke/Program.cs b/Aetheria.State.AuthoritySmoke/Program.cs index 0ff4ec9e2..8527ba6b8 100644 --- a/Aetheria.State.AuthoritySmoke/Program.cs +++ b/Aetheria.State.AuthoritySmoke/Program.cs @@ -537,7 +537,7 @@ internal sealed class AuthoritySmokeChecks Require(summary.WaveForecast.Length == 1 && summary.WaveForecast[0].DisplayName == "Bomber Line", "starbridge wave forecast should start at current wave"); Require(summary.RuntimeRoles.Any(role => role.RuntimeId == "commander-client" && role.Role == "commander"), "starbridge runtime roles should project scenario roles"); - var gameSurface = AetheriaRuntimeDaemonGameSurfaceBuilder.Build( + var gameSurface = AetheriaRuntimeDaemonGameSurfaceBuilder.BuildCommander( frame, new AetheriaRuntimeDaemonHealthDocument { diff --git a/Aetheria.State.Daemon/Program.cs b/Aetheria.State.Daemon/Program.cs index b001fd484..bdf460923 100644 --- a/Aetheria.State.Daemon/Program.cs +++ b/Aetheria.State.Daemon/Program.cs @@ -1343,7 +1343,6 @@ static async Task PublishDaemonApiDocumentsAsync( result.Frame, result.Health ?? new AetheriaRuntimeDaemonHealthDocument(), result.CommandBoundary ?? AetheriaRuntimeDaemonCommandBoundaryDocument.Create(options.DaemonId), - result.StarbridgeSessionSummary, activeMainMenuSurfaceId); await node.MutableDocument(AetheriaRuntimeVerseRecordKeys.DaemonGameSurface) .ReplaceAsync(AetheriaRuntimeSurfaceDocuments.ToPortableSurface(gameSurface)) diff --git a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeDaemonGameSurfaceBuilder.cs b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeDaemonGameSurfaceBuilder.cs index 461e9f2ab..a9473fa21 100644 --- a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeDaemonGameSurfaceBuilder.cs +++ b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeDaemonGameSurfaceBuilder.cs @@ -9,23 +9,20 @@ namespace GameCult.Aetheria.State.Verse { public static class AetheriaRuntimeDaemonGameSurfaceBuilder { - public const string PilotSurfaceId = "aetheria.starbridge.pilot"; + public const string PilotSurfaceId = "aetheria.pilot"; public const string CommanderSurfaceId = "aetheria.starbridge.commander"; public const string SurfaceId = PilotSurfaceId; - public const string TuiSurfaceId = "aetheria.starbridge.pilot.tui"; + public const string TuiSurfaceId = "aetheria.pilot.tui"; public static AetheriaRuntimeSurfaceDocument Build( AetheriaRuntimeDaemonFrameDocument frame, AetheriaRuntimeDaemonHealthDocument health, AetheriaRuntimeDaemonCommandBoundaryDocument commandBoundary, - AetheriaRuntimeStarbridgeSessionSummaryDocument? starbridge = null, string activeMainMenuSurfaceId = AetheriaRuntimeMainMenuCommands.RootSurfaceId) { frame ??= new AetheriaRuntimeDaemonFrameDocument(); health ??= new AetheriaRuntimeDaemonHealthDocument(); commandBoundary ??= AetheriaRuntimeDaemonCommandBoundaryDocument.Create(frame.DaemonId); - starbridge ??= AetheriaRuntimeStarbridgeDocuments.SessionSummary(frame); - var run = frame.Run ?? new AetheriaRuntimeRunCheckpointCommit(); var zone = FindCurrentZone(run); var entity = FindCurrentEntity(run, zone); @@ -49,22 +46,6 @@ namespace GameCult.Aetheria.State.Verse Metric("aetheria.daemon.game.frame.observed_commands", "Observed Commands", health.ObservedCommandCount.ToString(CultureInfo.InvariantCulture), AetheriaRuntimeDaemonStateRefs.FrameObservedCommands), Metric("aetheria.daemon.game.frame.applied", "Applied", health.AppliedCommandCount.ToString(CultureInfo.InvariantCulture), AetheriaRuntimeDaemonStateRefs.FrameAppliedCommands), Metric("aetheria.daemon.game.frame.rejected", "Rejected", health.RejectedCommandCount.ToString(CultureInfo.InvariantCulture), AetheriaRuntimeDaemonStateRefs.FrameRejectedCommands)), - Node( - "aetheria.daemon.game.starbridge", - "card", - new[] { ("title", "Starbridge Session") }, - Metric("aetheria.daemon.game.starbridge.scenario", "Scenario", starbridge.ScenarioName), - Metric("aetheria.daemon.game.starbridge.session", "Session", starbridge.SessionId), - Metric("aetheria.daemon.game.starbridge.phase", "Phase", starbridge.Phase), - Metric("aetheria.daemon.game.starbridge.wave", "Wave", starbridge.CurrentWaveIndex.ToString(CultureInfo.InvariantCulture)), - Metric("aetheria.daemon.game.starbridge.zone", "Zone", starbridge.ZoneName), - Metric("aetheria.daemon.game.starbridge.base", "Base", starbridge.BaseStatus?.DisplayName ?? ""), - Metric("aetheria.daemon.game.starbridge.base_hull", "Base Hull", FormatNumber(starbridge.BaseStatus?.Hull ?? 0)), - Metric("aetheria.daemon.game.starbridge.base_shield", "Base Shield", FormatNumber(starbridge.BaseStatus?.Shield ?? 0)), - Metric("aetheria.daemon.game.starbridge.base_heat", "Base Heat", FormatNumber(starbridge.BaseStatus?.Heat ?? 0))), - BuildStarbridgeStationStockCard(starbridge), - BuildStarbridgeWaveForecastCard(starbridge), - BuildStarbridgeRuntimeRolesCard(starbridge), Node( "aetheria.daemon.game.player", "card", diff --git a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeDaemonTickRunner.cs b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeDaemonTickRunner.cs index d7d8742c9..d1c50eb29 100644 --- a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeDaemonTickRunner.cs +++ b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeDaemonTickRunner.cs @@ -225,8 +225,7 @@ namespace GameCult.Aetheria.State.Verse var gameSurface = AetheriaRuntimeDaemonGameSurfaceBuilder.Build( frame, health, - commandBoundary, - starbridgeSummary); + commandBoundary); var designerSurfaces = new[] { AetheriaRuntimeStatRecipeSurfaceBuilder.BuildFromCatalog(catalog), diff --git a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeEveSurfaceCatalog.cs b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeEveSurfaceCatalog.cs index b5ae4a659..7a0e83eef 100644 --- a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeEveSurfaceCatalog.cs +++ b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeEveSurfaceCatalog.cs @@ -110,7 +110,7 @@ namespace GameCult.Aetheria.State.Verse AetheriaRuntimePlayerSettingsCommands.IncrementSignificantDigits, AetheriaRuntimePlayerSettingsCommands.CycleNebulaQuality, AetheriaRuntimePlayerSettingsCommands.ToggleShowAsteroidsInMinimap), - Surface(AetheriaRuntimeDaemonGameSurfaceBuilder.PilotSurfaceId, "Starbridge Pilot", AetheriaRuntimeVerseRecordKeys.DaemonGameSurface.ToString(), "pilot", "Embodied Starbridge pilot projection.", providerId: "aetheria.daemon", providerKind: "game.daemon", transport: "cultmesh-record", surfaceKind: "interactive-world", worldInteraction: WorldInteraction("provider-authored-world-surface"), requiresPlugins: FieldPluginRequirements()), + Surface(AetheriaRuntimeDaemonGameSurfaceBuilder.PilotSurfaceId, "Aetheria Pilot", AetheriaRuntimeVerseRecordKeys.DaemonGameSurface.ToString(), "pilot", "Embodied pilot projection shared by Terminus and Starbridge.", providerId: "aetheria.daemon", providerKind: "game.daemon", transport: "cultmesh-record", surfaceKind: "interactive-world", worldInteraction: WorldInteraction("provider-authored-world-surface"), requiresPlugins: FieldPluginRequirements()), Surface(AetheriaRuntimeDaemonGameSurfaceBuilder.CommanderSurfaceId, "Starbridge Commander", AetheriaRuntimeVerseRecordKeys.StarbridgeCommanderSurface.ToString(), "commander", "Strategic Starbridge commander projection.", providerId: "aetheria.daemon", providerKind: "game.daemon", transport: "cultmesh-record", surfaceKind: "interactive-world", worldInteraction: WorldInteraction("provider-authored-world-surface"), requiresPlugins: FieldPluginRequirements()), 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", surfaceKind: "interactive-world", worldInteraction: WorldInteraction("provider-authored-world-surface")), Surface(AetheriaRuntimeDaemonEditorSurfaceBuilder.SurfaceId, "Aetheria Daemon Editor", AetheriaRuntimeVerseRecordKeys.DaemonEditorSurface.ToString(), "operator", "Daemon editor and surface inventory.", providerId: "aetheria.daemon", providerKind: "editor.daemon", transport: "cultmesh-record", surfaceKind: "interactive-world-editor", worldInteraction: WorldInteraction("provider-authored-world-editor-surface")), diff --git a/conformance/eve/aetheria-world-scenario.json b/conformance/eve/aetheria-world-scenario.json index 522c81b88..20231db12 100644 --- a/conformance/eve/aetheria-world-scenario.json +++ b/conformance/eve/aetheria-world-scenario.json @@ -8,10 +8,10 @@ "purpose": "Proves Aetheria interactive world clients consume provider advertisements, lower provider-owned game surfaces, issue command intents through the daemon boundary, and receive provider-owned receipts.", "requires": { "fixtures": ["aetheria-world"], - "surfaces": ["aetheria.starbridge.pilot", "aetheria.starbridge.commander", "aetheria.daemon.editor"], + "surfaces": ["aetheria.pilot", "aetheria.starbridge.commander", "aetheria.daemon.editor"], "worldSurfaces": [ { - "surfaceId": "aetheria.starbridge.pilot", + "surfaceId": "aetheria.pilot", "surfaceKind": "interactive-world", "projectionKind": "provider-authored-world-surface", "commandBoundary": "aetheria.daemon.commands", diff --git a/conformance/eve/aetheria-world-surface.json b/conformance/eve/aetheria-world-surface.json index e2c8154fd..54d4cdb4a 100644 --- a/conformance/eve/aetheria-world-surface.json +++ b/conformance/eve/aetheria-world-surface.json @@ -7,7 +7,7 @@ "version": 1, "updatedAtUtc": "2026-07-08T00:00:00Z", "surface": { - "id": "aetheria.starbridge.pilot", + "id": "aetheria.pilot", "root": { "id": "aetheria.daemon.game.root", "kind": "surface", diff --git a/conformance/eve/aetheria.provider-advertisement.json b/conformance/eve/aetheria.provider-advertisement.json index ba98c1e5e..a7b3f1477 100644 --- a/conformance/eve/aetheria.provider-advertisement.json +++ b/conformance/eve/aetheria.provider-advertisement.json @@ -95,7 +95,7 @@ }, { "schema": "gamecult.eve.surface.v1", - "surfaceId": "aetheria.starbridge.pilot", + "surfaceId": "aetheria.pilot", "key": "AetheriaRuntimeVerseRecordKeys.DaemonGameSurface", "transport": "cultmesh-record", "status": "available", @@ -115,7 +115,7 @@ "loweringTargets": ["web-reference", "unity-uitoolkit", "unity-scene", "electron-shell", "tui"], "ownership": "provider-owns-world-state-assets-command-acceptance-and-receipts" }, - "summary": "Embodied Starbridge pilot surface lowered by generic Eve runtimes." + "summary": "Embodied pilot surface shared by Terminus and Starbridge and lowered by generic Eve runtimes." }, { "schema": "gamecult.eve.surface.v1", @@ -143,7 +143,7 @@ }, { "schema": "gamecult.eve.surface.v1", - "surfaceId": "aetheria.starbridge.pilot.tui", + "surfaceId": "aetheria.pilot.tui", "key": "AetheriaRuntimeVerseRecordKeys.DaemonGameTuiSurface", "transport": "cultmesh-record", "status": "available", diff --git a/scripts/verify-eve-conformance-pack.mjs b/scripts/verify-eve-conformance-pack.mjs index 6f53f00a5..c483085a0 100644 --- a/scripts/verify-eve-conformance-pack.mjs +++ b/scripts/verify-eve-conformance-pack.mjs @@ -12,7 +12,7 @@ const advertisement = read(pack.advertisementPath); assert.equal(advertisement.providerId, pack.providerId); const starbridgeSurfaces = advertisement.surfaces.filter((surface) => surface.surfaceId === "aetheria.starbridge.commander" || - surface.surfaceId === "aetheria.starbridge.pilot"); + surface.surfaceId === "aetheria.pilot"); assert.equal(starbridgeSurfaces.length, 2); assert.deepEqual(new Set(starbridgeSurfaces.map((surface) => surface.audience)), new Set(["commander", "pilot"])); for (const surface of starbridgeSurfaces) { @@ -21,6 +21,10 @@ for (const surface of starbridgeSurfaces) { assert.ok(surface.worldInteraction?.loweringTargets.includes("electron-shell")); assert.ok(surface.worldInteraction?.loweringTargets.includes("unity-scene")); } +const pilotSurface = advertisement.surfaces.find((surface) => surface.surfaceId === "aetheria.pilot"); +assert.ok(pilotSurface); +assert.match(pilotSurface.summary, /Terminus and Starbridge/); +assert.doesNotMatch(pilotSurface.surfaceId, /starbridge|terminus/); assert.ok(advertisement.surfaces.some((surface) => surface.surfaceId === "aetheria.daemon.editor" && surface.worldInteraction?.projectionKind === "provider-authored-world-editor-surface")); for (const fixture of pack.fixtures) {