From 6bbf37fbb00478aa7ef7a9c1f4133bdd7c08140c Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Tue, 16 Jun 2026 21:35:58 +0100 Subject: [PATCH] Move inventory ship settings onto Eve surfaces --- Aetheria.State.Verify/Program.cs | 55 ++++++ Assets/Scripts/UI/Menu/InventoryMenu.cs | 234 +++++++++++++++++++++++- docs/aetheria-perfect-machine-map.md | 12 +- 3 files changed, 293 insertions(+), 8 deletions(-) diff --git a/Aetheria.State.Verify/Program.cs b/Aetheria.State.Verify/Program.cs index f8d4dabdf..23b4803de 100644 --- a/Aetheria.State.Verify/Program.cs +++ b/Aetheria.State.Verify/Program.cs @@ -35,6 +35,7 @@ RequireMainMenuSettingsCommit(root); RequireMainMenuSettingsShellUsesEveSurface(root); RequireSectorMapZoneDetailsUseEveSurface(root); RequireRuntimeMenuTabsUseEveSurface(root); +RequireInventoryShipSettingsUseEveSurface(root); RequirePlayerSettingsEveSurface(root); RequireMainMenuContinueRunState(root); RequirePropertiesPanelReadOnlyInspector(root); @@ -502,6 +503,7 @@ Console.WriteLine("Main-menu settings authority: player name, gameplay, and grap Console.WriteLine("Main-menu settings shell: settings/input/audio subpages lower through Eve UI Toolkit surfaces instead of PropertiesPanel buttons"); 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: tab navigation lowers through an Eve UI Toolkit surface instead of MenuTabButton click wiring"); +Console.WriteLine("Inventory ship-settings shell: background ship tuning lowers through an Eve UI Toolkit surface instead of PropertiesPanel.AddField"); Console.WriteLine("Main-menu Continue authority: Continue selects typed run state instead of a null button"); Console.WriteLine("PropertiesPanel inspector authority: dead generic reflection inspector path is deleted"); Console.WriteLine("Typed behavior metadata authority: live heat/mining/thermotoggle payload kinds stay owned by package metadata"); @@ -2588,6 +2590,59 @@ static void RequireRuntimeMenuTabsUseEveSurface(string root) } } +static void RequireInventoryShipSettingsUseEveSurface(string root) +{ + var inventoryMenuPath = Path.Combine(root, "Assets", "Scripts", "UI", "Menu", "InventoryMenu.cs"); + if (!File.Exists(inventoryMenuPath)) + { + throw new InvalidOperationException("Cannot verify inventory ship-settings shell; InventoryMenu.cs is missing."); + } + + var source = File.ReadAllText(inventoryMenuPath); + var requiredSymbols = new[] + { + "ShipSettingsSurfaceId", + "RenderCurrentShipSettingsSurface(", + "HandleCurrentShipSettingsSurfaceCommand(", + "ResolveShipSettingsSurfaceDocument(", + "BuildCurrentShipSettingsSurfaceDefinition(", + "DecrementShutdownThresholdCommand", + "IncrementShutdownThresholdCommand", + "ResetShutdownThresholdCommand", + "CloseShipSettingsCommand", + "new EveUiToolkitSurfaceLowerer()" + }; + + var missingSymbols = requiredSymbols + .Where(symbol => !source.Contains(symbol, StringComparison.Ordinal)) + .ToArray(); + + if (missingSymbols.Length > 0) + { + throw new InvalidOperationException( + "InventoryMenu no longer lowers current ship settings through an Eve surface shell: " + + string.Join(", ", missingSymbols)); + } + + var forbiddenSymbols = new[] + { + "PropertiesPanel.AddField(\"Shutdown Threshold\"", + "() => GameManager.CurrentEntity.Settings.ShutdownPerformance", + "f => GameManager.CommitEntityShutdownPerformance(GameManager.CurrentEntity, f)" + }; + + var hits = forbiddenSymbols + .Where(symbol => source.Contains(symbol, StringComparison.Ordinal)) + .ToArray(); + + if (hits.Length > 0) + { + throw new InvalidOperationException( + "InventoryMenu still owns ship settings through the old PropertiesPanel field path: " + + string.Join(", ", hits)); + } +} + static void RequirePlayerSettingsEveSurface(string root) { var projectorPath = Path.Combine(root, "Aetheria.State", "AetheriaPlayerSettingsSurfaceProjector.cs"); diff --git a/Assets/Scripts/UI/Menu/InventoryMenu.cs b/Assets/Scripts/UI/Menu/InventoryMenu.cs index b3055326e..62c2c6414 100644 --- a/Assets/Scripts/UI/Menu/InventoryMenu.cs +++ b/Assets/Scripts/UI/Menu/InventoryMenu.cs @@ -7,15 +7,29 @@ using System.Collections; using System.Collections.Generic; using System.Linq; using GameCult.Aetheria.State.Unity; +using GameCult.Eve.Surface; +using GameCult.Eve.UnityUIToolkit; using UnityEngine; using UniRx; using UniRx.Triggers; using Unity.Mathematics; using UnityEngine.InputSystem; using UnityEngine.UI; +using UnityEngine.UIElements; public class InventoryMenu : MonoBehaviour { + private const string ShipSettingsSurfaceType = "surface-state"; + private const string ShipSettingsSurfaceSchema = "gamecult.eve.surface.v1"; + private const string ShipSettingsSurfaceProviderId = "aetheria"; + private const string ShipSettingsSurfaceProviderKind = "inventory.menu"; + private const string ShipSettingsSurfaceId = "aetheria.inventory.current_ship_settings"; + private const string DecrementShutdownThresholdCommand = "aetheria.inventory.current_ship_settings.shutdown.decrement"; + private const string IncrementShutdownThresholdCommand = "aetheria.inventory.current_ship_settings.shutdown.increment"; + private const string ResetShutdownThresholdCommand = "aetheria.inventory.current_ship_settings.shutdown.reset"; + private const string CloseShipSettingsCommand = "aetheria.inventory.current_ship_settings.close"; + private const float ShutdownThresholdStep = 0.05f; + public InventoryPanel[] InventoryPanels; public PropertiesPanel PropertiesPanel; public ActionGameManager GameManager; @@ -29,6 +43,7 @@ public class InventoryMenu : MonoBehaviour private InventoryPanel _selectedPanel; private ItemInstance _selectedItem; private int2[] _selectedCells; + private UIDocument _shipSettingsSurfaceDocument; // private List _backgroundSubscriptions; // private ItemInstance _dragItem; @@ -70,6 +85,7 @@ public class InventoryMenu : MonoBehaviour private void OnDisable() { + HideCurrentShipSettingsSurface(); // Background.gameObject.SetActive(false); } @@ -99,6 +115,8 @@ public class InventoryMenu : MonoBehaviour } else { + HideCurrentShipSettingsSurface(); + PropertiesPanel.gameObject.SetActive(true); ClearSelectedCellHighlight(); _selectedPanel = panel; _selectedPosition = cargoEvent.Position; @@ -131,6 +149,8 @@ public class InventoryMenu : MonoBehaviour } else { + HideCurrentShipSettingsSurface(); + PropertiesPanel.gameObject.SetActive(true); ClearSelectedCellHighlight(); PropertiesPanel.Inspect(item); @@ -148,17 +168,208 @@ public class InventoryMenu : MonoBehaviour panel.OnBackgroundClick.Subscribe(data => { if (GameManager.CurrentEntity == null) return; // Only show ship settings if there's a ship, duh! - - PropertiesPanel.Clear(); - PropertiesPanel.AddField("Shutdown Threshold", - () => GameManager.CurrentEntity.Settings.ShutdownPerformance, - f => GameManager.CommitEntityShutdownPerformance(GameManager.CurrentEntity, f), - 0, - 1); + + RenderCurrentShipSettingsSurface(GameManager.CurrentEntity); }); } } + private void RenderCurrentShipSettingsSurface(Entity entity) + { + if (entity == null) + return; + + PropertiesPanel.gameObject.SetActive(false); + ClearSelectedCellHighlight(); + + var document = ResolveShipSettingsSurfaceDocument(); + document.gameObject.SetActive(true); + + var root = document.rootVisualElement; + root.Clear(); + root.style.flexGrow = 1; + root.style.position = Position.Absolute; + root.style.left = 0; + root.style.top = 0; + root.style.right = 0; + root.style.bottom = 0; + root.style.alignItems = Align.FlexStart; + root.style.justifyContent = Justify.FlexStart; + root.pickingMode = PickingMode.Ignore; + + var shell = new VisualElement(); + shell.style.width = 360; + shell.style.maxWidth = 420; + shell.style.backgroundColor = new Color(0.08f, 0.1f, 0.14f, 0.94f); + shell.style.borderTopLeftRadius = 8; + shell.style.borderTopRightRadius = 8; + shell.style.borderBottomLeftRadius = 8; + shell.style.borderBottomRightRadius = 8; + shell.style.paddingLeft = 18; + shell.style.paddingRight = 18; + shell.style.paddingTop = 18; + shell.style.paddingBottom = 18; + shell.style.borderLeftWidth = 1; + shell.style.borderRightWidth = 1; + shell.style.borderTopWidth = 1; + shell.style.borderBottomWidth = 1; + shell.style.borderLeftColor = new Color(0.3f, 0.47f, 0.71f, 0.8f); + shell.style.borderRightColor = new Color(0.3f, 0.47f, 0.71f, 0.8f); + shell.style.borderTopColor = new Color(0.3f, 0.47f, 0.71f, 0.8f); + shell.style.borderBottomColor = new Color(0.3f, 0.47f, 0.71f, 0.8f); + shell.pickingMode = PickingMode.Position; + root.Add(shell); + + var lowerer = new EveUiToolkitSurfaceLowerer(); + shell.Add(lowerer.Lower(BuildCurrentShipSettingsSurfaceDefinition(entity), HandleCurrentShipSettingsSurfaceCommand)); + } + + private void HandleCurrentShipSettingsSurfaceCommand(EveSurfaceCommandRequest request) + { + var entity = GameManager.CurrentEntity; + if (entity?.Settings == null) + { + HideCurrentShipSettingsSurface(); + return; + } + + switch (request.Command) + { + case DecrementShutdownThresholdCommand: + GameManager.CommitEntityShutdownPerformance( + entity, + Mathf.Clamp01(entity.Settings.ShutdownPerformance - ShutdownThresholdStep)); + RenderCurrentShipSettingsSurface(entity); + return; + case IncrementShutdownThresholdCommand: + GameManager.CommitEntityShutdownPerformance( + entity, + Mathf.Clamp01(entity.Settings.ShutdownPerformance + ShutdownThresholdStep)); + RenderCurrentShipSettingsSurface(entity); + return; + case ResetShutdownThresholdCommand: + GameManager.CommitEntityShutdownPerformance( + entity, + Mathf.Clamp01(GameManager.Settings.GameplaySettings.DefaultShutdownPerformance)); + RenderCurrentShipSettingsSurface(entity); + return; + case CloseShipSettingsCommand: + HideCurrentShipSettingsSurface(); + return; + default: + Debug.LogWarning($"Unknown inventory ship settings command: {request.Command}"); + return; + } + } + + private void HideCurrentShipSettingsSurface() + { + if (_shipSettingsSurfaceDocument == null) + return; + + _shipSettingsSurfaceDocument.rootVisualElement.Clear(); + _shipSettingsSurfaceDocument.gameObject.SetActive(false); + } + + private UIDocument ResolveShipSettingsSurfaceDocument() + { + if (_shipSettingsSurfaceDocument != null) + return _shipSettingsSurfaceDocument; + + var host = new GameObject("Aetheria Inventory Ship Settings Surface"); + host.transform.SetParent(transform, false); + var document = host.AddComponent(); + document.sortingOrder = 1000; + host.SetActive(false); + _shipSettingsSurfaceDocument = document; + return document; + } + + private EveSurfaceDocument BuildCurrentShipSettingsSurfaceDefinition(Entity entity) + { + return new EveSurfaceDocument( + ShipSettingsSurfaceType, + ShipSettingsSurfaceSchema, + ShipSettingsSurfaceProviderId, + ShipSettingsSurfaceProviderKind, + "Current Ship Settings", + version: 1, + DateTime.UtcNow.ToString("O"), + new EveSurfaceTree( + ShipSettingsSurfaceId, + Node( + $"{ShipSettingsSurfaceId}.root", + "surface", + Array.Empty<(string Key, string Value)>(), + Card( + $"{ShipSettingsSurfaceId}.card", + entity.Name, + Metric( + $"{ShipSettingsSurfaceId}.shutdown.metric", + "Shutdown Threshold", + ActionGameManager.RuntimePlayerSettings.Format(entity.Settings.ShutdownPerformance)), + Text( + $"{ShipSettingsSurfaceId}.note", + "Gameplay still owns the mutation. This surface only lowers the current ship setting."), + ButtonRow( + $"{ShipSettingsSurfaceId}.shutdown.buttons", + Button($"{ShipSettingsSurfaceId}.shutdown.decrement", "Threshold -", DecrementShutdownThresholdCommand), + Button($"{ShipSettingsSurfaceId}.shutdown.increment", "Threshold +", IncrementShutdownThresholdCommand), + Button($"{ShipSettingsSurfaceId}.shutdown.reset", "Default", ResetShutdownThresholdCommand), + Button($"{ShipSettingsSurfaceId}.close", "Close", CloseShipSettingsCommand)))), + Array.Empty()), + new[] + { + new EveCommandTemplate(DecrementShutdownThresholdCommand, "Threshold -", "unity-uitoolkit"), + new EveCommandTemplate(IncrementShutdownThresholdCommand, "Threshold +", "unity-uitoolkit"), + new EveCommandTemplate(ResetShutdownThresholdCommand, "Default", "unity-uitoolkit"), + new EveCommandTemplate(CloseShipSettingsCommand, "Close", "unity-uitoolkit") + }); + } + + private static EveSurfaceComponent Card( + string id, + string title, + params EveSurfaceComponent[] children) + { + return Node(id, "card", new[] { ("title", title) }, children); + } + + private static EveSurfaceComponent Metric(string id, string label, string value) + { + return Node(id, "metric", new[] { ("label", label), ("value", value) }); + } + + private static EveSurfaceComponent Text(string id, string value) + { + return Node(id, "text", new[] { ("value", value) }); + } + + private static EveSurfaceComponent Button(string id, string label, string command) + { + return Node(id, "control.button", new[] { ("label", label), ("command", command) }); + } + + private static EveSurfaceComponent ButtonRow( + string id, + params EveSurfaceComponent[] children) + { + return Node(id, "row", Array.Empty<(string Key, string Value)>(), children); + } + + private static EveSurfaceComponent Node( + string id, + string kind, + IEnumerable<(string Key, string Value)> props, + params EveSurfaceComponent[] children) + { + return new EveSurfaceComponent( + id, + kind, + props.ToDictionary(prop => prop.Key, prop => prop.Value, StringComparer.Ordinal), + children ?? Array.Empty()); + } + private bool CommitCargoItemTransfer(EquippedCargoBay origin, InventoryPanel destination, ItemInstance item) { if (destination.DisplayedEntity != null && item is EquippableItem equippableItem) @@ -243,4 +454,13 @@ public class InventoryMenu : MonoBehaviour _ => new int2(cell.X, cell.Y) }; } + + private void OnDestroy() + { + if (_shipSettingsSurfaceDocument != null) + { + Destroy(_shipSettingsSurfaceDocument.gameObject); + _shipSettingsSurfaceDocument = null; + } + } } diff --git a/docs/aetheria-perfect-machine-map.md b/docs/aetheria-perfect-machine-map.md index b200fcec2..9cad8ed3c 100644 --- a/docs/aetheria-perfect-machine-map.md +++ b/docs/aetheria-perfect-machine-map.md @@ -119,7 +119,9 @@ legacy catalog cache, and legacy UI paths should be migration-only or deleted. lowers through a local Eve/UI Toolkit surface as well instead of rebuilding `PropertiesPanel` rows on each zone click. The runtime in-game menu tab strip now lowers through a local Eve/UI Toolkit surface instead of wiring old - `MenuTabButton` clicks. + `MenuTabButton` clicks. Inventory background ship tuning now lowers through a + local Eve/UI Toolkit surface instead of rebuilding a `PropertiesPanel` + float field. - The combat schematic HUD uses typed runtime catalog weapon facets for its static weapon icon strip; missing typed weapon facets no longer fall back to legacy `WeaponItemData`. Schematic weapon-row selection now uses typed @@ -1557,6 +1559,11 @@ First Aetheria surfaces to publish: - Done: replace the runtime in-game menu tab strip with an Eve-owned UI Toolkit surface. `MenuPanel` still owns tab-content activation, but old `MenuTabButton` click wiring no longer owns tab navigation. + - Done: replace inventory background ship tuning with an Eve-owned UI + Toolkit surface. `InventoryMenu` still owns click routing and the + gameplay commit primitive still owns mutation, but the old + `PropertiesPanel.AddField("Shutdown Threshold", ...)` path no longer owns + that settings shell. - Done: move the shared `org.gamecult.eve.surface` and `org.gamecult.eve.unity-uitoolkit` packages into the Eve repo and retarget Aetheria to import them from there instead of carrying local staged @@ -1921,6 +1928,9 @@ First Aetheria surfaces to publish: - Runtime in-game menu tab navigation now lowers through a shared UI Toolkit `UIDocument` host and a local Eve surface document instead of wiring `MenuTabButton` click handlers. +- Inventory background ship tuning now lowers through a shared UI Toolkit + `UIDocument` host and a local Eve surface document instead of rebuilding a + mutable `PropertiesPanel.AddField(...)` control for shutdown threshold. - Keyboard display layout parsing is no longer JSON-backed: `InputDisplayLayout` builds its static ANSI-104 display projection from typed `InputLayout` rows/columns. The dead commented Ink `ToJson` write path and