From ab6face8e201fb03dd88d7a93726dc3d3a2fb97a Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Mon, 20 Jul 2026 05:22:39 +0100 Subject: [PATCH] Let daemon gameplay state close the main menu --- Aetheria.State.Daemon.Smoke/Program.cs | 4 ++++ Aetheria.State.Daemon/Program.cs | 7 ++++++- Aetheria.State/AetheriaEveCommandBridge.cs | 1 + .../Runtime/AetheriaRuntimeDaemonGameSurfaceBuilder.cs | 7 +++++-- 4 files changed, 16 insertions(+), 3 deletions(-) diff --git a/Aetheria.State.Daemon.Smoke/Program.cs b/Aetheria.State.Daemon.Smoke/Program.cs index 7d8b6d8af..64c2d2442 100644 --- a/Aetheria.State.Daemon.Smoke/Program.cs +++ b/Aetheria.State.Daemon.Smoke/Program.cs @@ -3791,6 +3791,10 @@ internal sealed class AetheriaDaemonYmirSmokeChecks node.Id is "aetheria.daemon.game.frame" or "aetheria.daemon.game.player" or "aetheria.daemon.game.commands") .All(node => node.Layout.TryGetValue("display", out var display) && display == "none"), "operator diagnostics must remain published state without becoming pilot-camera UI"); + var mainMenu = Flatten(surface.Surface.Root).Single(node => node.Id == "aetheria.daemon.game.main_menu"); + Require(mainMenu.Layout.TryGetValue("display", out var menuDisplay) && menuDisplay == "none" && + mainMenu.EmbeddedDocuments.Count == 0, + "an active pilot surface must not embed or display the main menu until daemon menu state opens it"); } private static void ChargedWeaponCannotBypassChargeLifecycle() diff --git a/Aetheria.State.Daemon/Program.cs b/Aetheria.State.Daemon/Program.cs index d1be07e51..15ca92486 100644 --- a/Aetheria.State.Daemon/Program.cs +++ b/Aetheria.State.Daemon/Program.cs @@ -1935,8 +1935,13 @@ static async Task PublishClientGameplayDocumentsAsync( var mainMenuState = await node.MutableDocument(AetheriaStateNode.MainMenuStateKey) .ReadAsync() .ConfigureAwait(false); + var hasActivePilot = !string.IsNullOrWhiteSpace(result.Frame.Run?.CurrentEntityKey) && + result.Frame.Run.Zones?.Any(zone => + zone != null && + zone.ZoneIndex == result.Frame.Run.CurrentZoneIndex && + (zone.Entities?.Count ?? 0) > 0) == true; var activeMainMenuSurfaceId = string.IsNullOrWhiteSpace(mainMenuState?.ActiveSurfaceId) - ? AetheriaRuntimeMainMenuCommands.RootSurfaceId + ? (hasActivePilot ? "" : AetheriaRuntimeMainMenuCommands.RootSurfaceId) : mainMenuState.ActiveSurfaceId; var reactiveGameSurface = AetheriaRuntimeSurfaceDocuments.ToPortableSurface( AetheriaRuntimeDaemonGameSurfaceBuilder.BuildReactiveGameplay( diff --git a/Aetheria.State/AetheriaEveCommandBridge.cs b/Aetheria.State/AetheriaEveCommandBridge.cs index 519c2d87b..5d3fa26fb 100644 --- a/Aetheria.State/AetheriaEveCommandBridge.cs +++ b/Aetheria.State/AetheriaEveCommandBridge.cs @@ -405,6 +405,7 @@ public static class AetheriaEveCommandBridge case AetheriaRuntimeEveCommandKind.MainMenuBackToMain: case AetheriaRuntimeEveCommandKind.MainMenuContinueRun: case AetheriaRuntimeEveCommandKind.MainMenuNewGame: + return ""; case AetheriaRuntimeEveCommandKind.MainMenuQuit: return AetheriaRuntimeMainMenuCommands.RootSurfaceId; default: diff --git a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeDaemonGameSurfaceBuilder.cs b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeDaemonGameSurfaceBuilder.cs index 12f848a73..f702b4794 100644 --- a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeDaemonGameSurfaceBuilder.cs +++ b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeDaemonGameSurfaceBuilder.cs @@ -19,7 +19,7 @@ namespace GameCult.Aetheria.State.Verse AetheriaRuntimeDaemonFrameDocument frame, AetheriaRuntimeDaemonHealthDocument health, AetheriaRuntimeDaemonCommandBoundaryDocument commandBoundary, - string activeMainMenuSurfaceId = AetheriaRuntimeMainMenuCommands.RootSurfaceId, + string activeMainMenuSurfaceId = "", AetheriaRuntimeCatalogSnapshot? catalog = null) { frame ??= new AetheriaRuntimeDaemonFrameDocument(); @@ -30,7 +30,8 @@ namespace GameCult.Aetheria.State.Verse var entity = FindCurrentEntity(run, zone); var target = FindTargetEntity(zone, entity); var entityName = string.IsNullOrWhiteSpace(entity?.Name) ? "(no current entity)" : entity!.Name; - activeMainMenuSurfaceId = NormalizeMainMenuSurfaceId(activeMainMenuSurfaceId); + if (!string.IsNullOrWhiteSpace(activeMainMenuSurfaceId)) + activeMainMenuSurfaceId = NormalizeMainMenuSurfaceId(activeMainMenuSurfaceId); var surfaceChildren = new List { PlayableWorldSurface( @@ -1761,6 +1762,8 @@ namespace GameCult.Aetheria.State.Verse string id, string activeSurfaceId) { + if (string.IsNullOrWhiteSpace(activeSurfaceId)) + return Hidden(Node(id, "surface.slot", Array.Empty<(string Key, string Value)>())); activeSurfaceId = NormalizeMainMenuSurfaceId(activeSurfaceId); var activeSurfaceRecordRef = $"eve:surface:{activeSurfaceId}"; return new AetheriaRuntimeSurfaceComponent(