From ae2f95ceae47c13b1d001cc8ffad3708f3d10e6b Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 17 Jun 2026 06:10:41 +0100 Subject: [PATCH] Delegate menu input settings to live remap screen --- Aetheria.State.Verify/Program.cs | 84 +++++++++++++++- Assets/Scripts/Gameplay/ActionGameManager.cs | 60 ++++++++--- Assets/Scripts/UI/MainMenu.cs | 100 +++++++++++++++---- docs/aetheria-perfect-machine-map.md | 7 +- 4 files changed, 212 insertions(+), 39 deletions(-) diff --git a/Aetheria.State.Verify/Program.cs b/Aetheria.State.Verify/Program.cs index f6e488f61..075589794 100644 --- a/Aetheria.State.Verify/Program.cs +++ b/Aetheria.State.Verify/Program.cs @@ -35,6 +35,8 @@ RequireMainMenuSettingsCommit(root); RequireMainMenuRootUsesEveSurface(root); RequireMainMenuSettingsShellUsesEveSurface(root); RequireConfirmationDialogOwnsMinimalPromptShell(root); +RequireMainMenuInputSettingsDelegateToRuntimeScreen(root); +RequireActionGameManagerInputScreenUsesSharedFullscreenPrimitive(root); RequireSectorMapZoneDetailsUseEveSurface(root); RequireRuntimeMenuTabsUseEveSurface(root); RequireInventoryShipSettingsUseEveSurface(root); @@ -512,6 +514,8 @@ Console.WriteLine("Main-menu settings authority: player name, gameplay, and grap Console.WriteLine("Main-menu root shell: root navigation lowers through an Eve UI Toolkit surface instead of the legacy PropertiesPanel/fade shell"); Console.WriteLine("Main-menu settings shell: settings/input/audio subpages lower through Eve UI Toolkit surfaces instead of PropertiesPanel buttons"); Console.WriteLine("Confirmation dialog shell: runtime prompts no longer inherit the generic PropertiesPanel machinery"); +Console.WriteLine("Main-menu input shell: the Eve input page delegates to the live runtime remap screen when that owner exists"); +Console.WriteLine("Runtime input-screen authority: hotkey and menu handoff share the same fullscreen-menu primitive"); Console.WriteLine("Sector-map zone details shell: zone inspection lowers through an Eve UI Toolkit surface instead of PropertiesPanel rows"); Console.WriteLine("Runtime menu tab shell: MenuPanel owns tab metadata and lowers navigation through an Eve UI Toolkit surface"); Console.WriteLine("Inventory ship-settings shell: background ship tuning lowers through an Eve UI Toolkit surface instead of PropertiesPanel.AddField"); @@ -2449,7 +2453,7 @@ static void RequireMainMenuSettingsShellUsesEveSurface(string root) { "RenderMenuSurface(", "BuildSettingsSurfaceDefinition()", - "BuildInputSettingsSurfaceDefinition()", + "BuildInputSettingsSurfaceDefinition(", "BuildAudioSettingsSurfaceDefinition()", "HandleSettingsSurfaceCommand(", "HandleInputSettingsSurfaceCommand(", @@ -2730,6 +2734,84 @@ static string ReadSerializedMonoBehaviourBlock(string path, string scriptGuid) $"Cannot inspect serialized MonoBehaviour block for script guid {scriptGuid} in {path}."); } +static void RequireMainMenuInputSettingsDelegateToRuntimeScreen(string root) +{ + var mainMenuPath = Path.Combine(root, "Assets", "Scripts", "UI", "MainMenu.cs"); + if (!File.Exists(mainMenuPath)) + { + throw new InvalidOperationException("Cannot verify main-menu input delegation; MainMenu.cs is missing."); + } + + var source = File.ReadAllText(mainMenuPath); + var requiredSymbols = new[] + { + "OpenRuntimeInputScreenCommand", + "CanOpenRuntimeInputScreen()", + "TryOpenRuntimeInputScreen()", + "BuildInputSettingsSurfaceDefinition(CanOpenRuntimeInputScreen(), InGame)", + "ActionGameManager.Instance.ShowInputScreenFromMenu();" + }; + + var missingSymbols = requiredSymbols + .Where(symbol => !source.Contains(symbol, StringComparison.Ordinal)) + .ToArray(); + + if (missingSymbols.Length > 0) + { + throw new InvalidOperationException( + "MainMenu input page no longer delegates to the live runtime remap screen: " + + string.Join(", ", missingSymbols)); + } + + var forbiddenSymbols = new[] + { + "Typed input rebinding controls are not lowered through Eve yet.", + "The live remapping screen still owns drag/drop rebinding and low-level InputSystem edits." + }; + + var hits = forbiddenSymbols + .Where(symbol => source.Contains(symbol, StringComparison.Ordinal)) + .ToArray(); + + if (hits.Length > 0) + { + throw new InvalidOperationException( + "MainMenu input page still reports the live remap owner as future work instead of delegating to it: " + + string.Join(", ", hits)); + } +} + +static void RequireActionGameManagerInputScreenUsesSharedFullscreenPrimitive(string root) +{ + var managerPath = Path.Combine(root, "Assets", "Scripts", "Gameplay", "ActionGameManager.cs"); + if (!File.Exists(managerPath)) + { + throw new InvalidOperationException("Cannot verify ActionGameManager input-screen delegation; ActionGameManager.cs is missing."); + } + + var source = File.ReadAllText(managerPath); + var requiredSymbols = new[] + { + "public bool CanShowInputScreenFromMenu()", + "public void ShowInputScreenFromMenu()", + "ShowFullscreenMenu(HelpScreen);", + "private void ShowFullscreenMenu(GameObject menu)", + "private void HideFullscreenMenu(GameObject menu)", + "Input.Global.InputScreen.performed += context => ToggleFullscreenMenu(HelpScreen);" + }; + + var missingSymbols = requiredSymbols + .Where(symbol => !source.Contains(symbol, StringComparison.Ordinal)) + .ToArray(); + + if (missingSymbols.Length > 0) + { + throw new InvalidOperationException( + "ActionGameManager no longer exposes the shared fullscreen primitive for the live input-screen owner: " + + string.Join(", ", missingSymbols)); + } +} + static void RequireSectorMapZoneDetailsUseEveSurface(string root) { var sectorRendererPath = Path.Combine(root, "Assets", "Scripts", "UI", "Menu", "SectorRenderer.cs"); diff --git a/Assets/Scripts/Gameplay/ActionGameManager.cs b/Assets/Scripts/Gameplay/ActionGameManager.cs index 8e04bb6aa..08e5cacbf 100644 --- a/Assets/Scripts/Gameplay/ActionGameManager.cs +++ b/Assets/Scripts/Gameplay/ActionGameManager.cs @@ -2654,29 +2654,59 @@ public class ActionGameManager : MonoBehaviour } } + public bool CanShowInputScreenFromMenu() + { + return CurrentEntity != null && HelpScreen != null; + } + + public void ShowInputScreenFromMenu() + { + ShowFullscreenMenu(HelpScreen); + } + private void ToggleFullscreenMenu(GameObject menu) { if (EventSystem.current != null && EventSystem.current.currentSelectedGameObject != null && EventSystem.current.currentSelectedGameObject.GetComponent() != null) return; - if (CurrentEntity == null) return; + if (menu == null || CurrentEntity == null) return; if (menu.activeSelf) { - _paused = false; - menu.SetActive(false); - UiRoot.SetActive(true); - if (!_menuShown) - { - EnablePlayerInput(); - UpdatePlayerPanel(); - UpdateTargetPanel(CurrentEntity.Target.Value); - } + HideFullscreenMenu(menu); } else { - _paused = true; - menu.SetActive(true); - UiRoot.SetActive(false); - _menuShown = Menu.gameObject.activeSelf; - if (!_menuShown) DisablePlayerInput(); + ShowFullscreenMenu(menu); + } + } + + private void ShowFullscreenMenu(GameObject menu) + { + if (EventSystem.current != null && EventSystem.current.currentSelectedGameObject != null && EventSystem.current.currentSelectedGameObject.GetComponent() != null) return; + if (menu == null || CurrentEntity == null) return; + + if (MainMenu != null && MainMenu.gameObject != menu) + MainMenu.gameObject.SetActive(false); + if (HelpScreen != null && HelpScreen != menu) + HelpScreen.SetActive(false); + + _paused = true; + menu.SetActive(true); + UiRoot.SetActive(false); + _menuShown = Menu.gameObject.activeSelf; + if (!_menuShown) DisablePlayerInput(); + } + + private void HideFullscreenMenu(GameObject menu) + { + if (menu == null || CurrentEntity == null) return; + + _paused = false; + menu.SetActive(false); + UiRoot.SetActive(true); + if (!_menuShown) + { + EnablePlayerInput(); + UpdatePlayerPanel(); + UpdateTargetPanel(CurrentEntity.Target.Value); } } diff --git a/Assets/Scripts/UI/MainMenu.cs b/Assets/Scripts/UI/MainMenu.cs index f55f5ed73..597f2041b 100644 --- a/Assets/Scripts/UI/MainMenu.cs +++ b/Assets/Scripts/UI/MainMenu.cs @@ -33,6 +33,7 @@ public class MainMenu : MonoBehaviour private const string NewGameCommand = "aetheria.main_menu.root.new_game"; private const string ShowSettingsCommand = "aetheria.main_menu.root.show_settings"; private const string QuitCommand = "aetheria.main_menu.root.quit"; + private const string OpenRuntimeInputScreenCommand = "aetheria.main_menu.input_settings.open_runtime_screen"; private const string ShowPlayerSettingsCommand = "aetheria.main_menu.settings.show_player_settings"; private const string ShowInputSettingsCommand = "aetheria.main_menu.settings.show_input_settings"; private const string ShowAudioSettingsCommand = "aetheria.main_menu.settings.show_audio_settings"; @@ -231,7 +232,7 @@ public class MainMenu : MonoBehaviour private void ShowInputSettings() { - RenderMenuSurface(BuildInputSettingsSurfaceDefinition(), HandleInputSettingsSurfaceCommand); + RenderMenuSurface(BuildInputSettingsSurfaceDefinition(CanOpenRuntimeInputScreen(), InGame), HandleInputSettingsSurfaceCommand); } private void ShowAudioSettings() @@ -313,6 +314,16 @@ public class MainMenu : MonoBehaviour return; } + if (string.Equals(request.Command, OpenRuntimeInputScreenCommand, StringComparison.Ordinal)) + { + if (!TryOpenRuntimeInputScreen()) + { + ShowInputSettings(); + } + + return; + } + Debug.LogWarning($"Unknown input settings command: {request.Command}"); } @@ -458,32 +469,81 @@ public class MainMenu : MonoBehaviour Button("aetheria.mainMenu.settings.back", "Back", BackToMainCommand)))); } - private static EveSurfaceDocument BuildInputSettingsSurfaceDefinition() + private bool CanOpenRuntimeInputScreen() { + return InGame && + ActionGameManager.Instance != null && + ActionGameManager.Instance.CanShowInputScreenFromMenu() && + ActionGameManager.Instance.InputDisplayLayout != null; + } + + private bool TryOpenRuntimeInputScreen() + { + if (!CanOpenRuntimeInputScreen()) + return false; + + HideMenuSurface(); + gameObject.SetActive(false); + ActionGameManager.Instance.ShowInputScreenFromMenu(); + return true; + } + + private static EveSurfaceDocument BuildInputSettingsSurfaceDefinition(bool canOpenRuntimeInputScreen, bool inGame) + { + var commands = new List + { + new EveCommandTemplate(BackToSettingsCommand, "Back", "unity-uitoolkit") + }; + + var cardChildren = new List + { + Metric( + "aetheria.mainMenu.input.bindingOverrides", + "Binding Overrides", + ActionGameManager.RuntimePlayerSettings.InputSettings.InputActionMap.Count.ToString()), + Metric( + "aetheria.mainMenu.input.actionBarInputs", + "Action-Bar Inputs", + ActionGameManager.RuntimePlayerSettings.InputSettings.ActionBarInputs.Count.ToString()) + }; + + if (canOpenRuntimeInputScreen) + { + commands.Insert(0, new EveCommandTemplate(OpenRuntimeInputScreenCommand, "Open Remap Screen", "unity-uitoolkit")); + cardChildren.Add(Text( + "aetheria.mainMenu.input.note", + "The live remap screen owns drag/drop rebinding and low-level InputSystem edits. This surface reports the typed player-settings state and hands off to that owner.")); + } + else if (inGame) + { + cardChildren.Add(Text( + "aetheria.mainMenu.input.note", + "The live remap screen should own drag/drop rebinding here, but this scene has no active remap surface to hand off to.")); + } + else + { + cardChildren.Add(Text( + "aetheria.mainMenu.input.note", + "This title shell reports the typed player-settings state. Launch a run to open the live remap screen that owns drag/drop rebinding and low-level InputSystem edits.")); + } + + var buttons = new List(); + if (canOpenRuntimeInputScreen) + { + buttons.Add(Button("aetheria.mainMenu.input.openRuntimeScreen", "Open Remap Screen", OpenRuntimeInputScreenCommand)); + } + + buttons.Add(Button("aetheria.mainMenu.input.back", "Back", BackToSettingsCommand)); + cardChildren.Add(ButtonRow("aetheria.mainMenu.input.actions", buttons.ToArray())); + return BuildMenuSurfaceDocument( InputSettingsSurfaceId, "Aetheria Input Settings", - new[] - { - new EveCommandTemplate(BackToSettingsCommand, "Back", "unity-uitoolkit") - }, + commands, Card( "aetheria.mainMenu.input.card", "Input Settings", - Metric( - "aetheria.mainMenu.input.bindingOverrides", - "Binding Overrides", - ActionGameManager.RuntimePlayerSettings.InputSettings.InputActionMap.Count.ToString()), - Metric( - "aetheria.mainMenu.input.actionBarInputs", - "Action-Bar Inputs", - ActionGameManager.RuntimePlayerSettings.InputSettings.ActionBarInputs.Count.ToString()), - Text( - "aetheria.mainMenu.input.note", - "Typed input rebinding controls are not lowered through Eve yet. The live remapping screen still owns drag/drop rebinding and low-level InputSystem edits."), - ButtonRow( - "aetheria.mainMenu.input.actions", - Button("aetheria.mainMenu.input.back", "Back", BackToSettingsCommand)))); + cardChildren.ToArray())); } private static EveSurfaceDocument BuildAudioSettingsSurfaceDefinition() diff --git a/docs/aetheria-perfect-machine-map.md b/docs/aetheria-perfect-machine-map.md index 24e14d78f..2447be8ae 100644 --- a/docs/aetheria-perfect-machine-map.md +++ b/docs/aetheria-perfect-machine-map.md @@ -1566,9 +1566,10 @@ First Aetheria surfaces to publish: surfaces. Root navigation, settings, input, and audio now lower through a single Eve host instead of the old `PropertiesPanel`/fade shell. The menu remains a client-side projection: the Aetheria daemon owns Verse state and - Unity renders and submits commands. Input rebinding itself remains on the - runtime-owned remap screen until Eve grows typed rebinding controls, and - audio still lacks a typed state surface. + Unity renders and submits commands. The input page now reports typed state + and delegates to the live runtime remap screen in the in-game overlay + instead of pretending that owner is still future work; typed Eve rebinding + controls are still future work. Audio still lacks a typed state surface. - Done: replace the sector-map zone details panel with an Eve-owned UI Toolkit surface. `SectorRenderer` still owns reveal/camera behavior, but zone inspection no longer rebuilds `PropertiesPanel` rows when the player