refactor(modes): share pilot surface across game modes

This commit is contained in:
Meta Vens 2026-07-11 00:56:19 +01:00
commit 97f86d5365
9 changed files with 16 additions and 33 deletions

View file

@ -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
{

View file

@ -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<EveSurfaceDocument>(AetheriaRuntimeVerseRecordKeys.DaemonGameSurface)
.ReplaceAsync(AetheriaRuntimeSurfaceDocuments.ToPortableSurface(gameSurface))

View file

@ -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",

View file

@ -225,8 +225,7 @@ namespace GameCult.Aetheria.State.Verse
var gameSurface = AetheriaRuntimeDaemonGameSurfaceBuilder.Build(
frame,
health,
commandBoundary,
starbridgeSummary);
commandBoundary);
var designerSurfaces = new[]
{
AetheriaRuntimeStatRecipeSurfaceBuilder.BuildFromCatalog(catalog),

View file

@ -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")),

View file

@ -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",

View file

@ -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",

View file

@ -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",

View file

@ -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) {