From 9570bfc11d0603a3f5228a92ff9855b969ff91f2 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Mon, 29 Jun 2026 02:08:46 +0100 Subject: [PATCH] Simplify menu docking state access --- Aetheria.State.Verify/Program.cs | 53 +++++++++++++++++-- Assets/Scripts/UI/Menu/MenuPanel.cs | 8 ++- Assets/Scripts/UI/Menu/TradeMenu.cs | 25 ++++----- .../Runtime/AetheriaRuntimeVerseClient.cs | 9 ---- 4 files changed, 70 insertions(+), 25 deletions(-) diff --git a/Aetheria.State.Verify/Program.cs b/Aetheria.State.Verify/Program.cs index 69e8f89b7..8e11d303b 100644 --- a/Aetheria.State.Verify/Program.cs +++ b/Aetheria.State.Verify/Program.cs @@ -4769,7 +4769,9 @@ static void RequireRuntimeMenuTabsUseEveSurface(string root) "ResolveVisibleTabs(", "SetObservedEntityIndex(AetheriaUnityObservedEntityIndex observedEntityIndex)", "AetheriaRuntimeCurrentDockingDocument", - "ResolveClient().State.Latest()", + "CultMeshReactiveDocument _currentDocking", + "_currentDocking ??= ResolveClient().State.Reactive()", + "docking = _currentDocking.Current", "docking.IsDocked", "AetheriaClient", "AetheriaUnityRuntimeClientProvider.ResolveClient(", @@ -5731,8 +5733,12 @@ static void RequireTradeCargoSelectorUseEveSurface(string root) "AetheriaRuntimeTradeCargoSelectorCommandKind.Select", "SetObservedEntityIndex(AetheriaUnityObservedEntityIndex observedEntityIndex)", "AetheriaRuntimeCurrentDockingDocument", - "ResolveClient().State.Latest()", - "ResolveClient().State.Latest()", + "CultMeshReactiveDocument _currentDocking", + "_currentDocking ??= ResolveClient().State.Reactive()", + "docking = _currentDocking.Current", + "CultMeshReactiveDocument _stationRefit", + "_stationRefit = ResolveClient().State.Reactive()", + "return _stationRefit?.Current", "SetTargetCargo(", "selection.EntityKey", "OwnedQuantity", @@ -7222,11 +7228,46 @@ static void RequireMenuDockingUsesManagedTypedSnapshot(string root) string.Join(", ", offenders)); } + var menuPanel = File.ReadAllText(Path.Combine(root, "Assets", "Scripts", "UI", "Menu", "MenuPanel.cs")); + var tradeMenu = File.ReadAllText(Path.Combine(root, "Assets", "Scripts", "UI", "Menu", "TradeMenu.cs")); + var directDockingOffenders = new List(); + if (!menuPanel.Contains("CultMeshReactiveDocument _currentDocking", StringComparison.Ordinal) || + !menuPanel.Contains("_currentDocking ??= ResolveClient().State.Reactive()", StringComparison.Ordinal) || + !menuPanel.Contains("docking = _currentDocking.Current", StringComparison.Ordinal) || + menuPanel.Contains("ResolveClient().State.Latest()", StringComparison.Ordinal)) + { + directDockingOffenders.Add("Assets/Scripts/UI/Menu/MenuPanel.cs"); + } + + if (!tradeMenu.Contains("CultMeshReactiveDocument _currentDocking", StringComparison.Ordinal) || + !tradeMenu.Contains("_currentDocking ??= ResolveClient().State.Reactive()", StringComparison.Ordinal) || + !tradeMenu.Contains("docking = _currentDocking.Current", StringComparison.Ordinal) || + tradeMenu.Contains("ResolveClient().State.Latest()", StringComparison.Ordinal)) + { + directDockingOffenders.Add("Assets/Scripts/UI/Menu/TradeMenu.cs"); + } + + if (directDockingOffenders.Count > 0) + { + throw new InvalidOperationException( + "Unity menu docking reads must hold the managed reactive typed docking document and sample Current directly: " + + string.Join(", ", directDockingOffenders)); + } + Console.WriteLine("Menu docking state: Unity menus read managed reactive typed docking snapshots"); } static bool HasManagedDockingSnapshotAccess(string source) { + if (source.Contains("AetheriaRuntimeCurrentDockingDocument", StringComparison.Ordinal) && + source.Contains("CultMeshReactiveDocument _currentDocking", StringComparison.Ordinal) && + source.Contains("State.Reactive()", StringComparison.Ordinal) && + source.Contains("_currentDocking.Current", StringComparison.Ordinal) && + !source.Contains("ResolveClient().State.Latest()", StringComparison.Ordinal)) + { + return true; + } + if (source.Contains("AetheriaRuntimeCurrentDockingDocument", StringComparison.Ordinal) && source.Contains("ResolveClient().State.Latest()", StringComparison.Ordinal) && !source.Contains("ResolveClient().State.CurrentDocking()", StringComparison.Ordinal) && @@ -11854,6 +11895,12 @@ static void RequireAetheriaRuntimeVerseClientContract(string root) string.Join(", ", survivingNamedMutablePointers)); } + if (client.Contains("ReactiveDocumentAsync", StringComparison.Ordinal)) + { + throw new InvalidOperationException( + "AetheriaRuntimeVerseClient must not expose a second reactive-document alias; callers should use Document(key).ReactiveAsync()."); + } + if (File.Exists(Path.Combine(root, "Packages", "org.gamecult.aetheria.state", "Runtime", "AetheriaRuntimeManagedClientInputs.cs")) || client.Contains("AetheriaRuntimeManagedClientInputs", StringComparison.Ordinal) || client.Contains("AetheriaRuntimeDaemonFrameSession _daemonFrame", StringComparison.Ordinal) || diff --git a/Assets/Scripts/UI/Menu/MenuPanel.cs b/Assets/Scripts/UI/Menu/MenuPanel.cs index 059ab57b3..4684e7a6b 100644 --- a/Assets/Scripts/UI/Menu/MenuPanel.cs +++ b/Assets/Scripts/UI/Menu/MenuPanel.cs @@ -8,6 +8,7 @@ using System.Linq; using GameCult.Aetheria.EveRuntime; using GameCult.Aetheria.State.Verse; using GameCult.Eve.Surface; +using GameCult.Mesh; using UnityEngine; using UnityEngine.UIElements; @@ -32,6 +33,7 @@ public class MenuPanel : MonoBehaviour private UIDocument _tabSurfaceDocument; private readonly AetheriaEveUnitySurfaceChrome _tabSurfaceChrome = new AetheriaEveUnitySurfaceChrome(); private string _clientStatePath = ""; + private CultMeshReactiveDocument _currentDocking; public MenuTab CurrentTab { get; private set; } @@ -98,6 +100,9 @@ public class MenuPanel : MonoBehaviour AetheriaEveUnitySurfaceHost.DestroyDocument(_tabSurfaceDocument); _tabSurfaceDocument = null; } + + _currentDocking?.Dispose(); + _currentDocking = null; } private void RenderTabSurface() @@ -175,7 +180,8 @@ public class MenuPanel : MonoBehaviour docking = null; try { - docking = ResolveClient().State.Latest(); + _currentDocking ??= ResolveClient().State.Reactive(); + docking = _currentDocking.Current; return docking != null; } catch (Exception ex) diff --git a/Assets/Scripts/UI/Menu/TradeMenu.cs b/Assets/Scripts/UI/Menu/TradeMenu.cs index 275492736..9a9cb1631 100644 --- a/Assets/Scripts/UI/Menu/TradeMenu.cs +++ b/Assets/Scripts/UI/Menu/TradeMenu.cs @@ -40,6 +40,8 @@ public class TradeMenu : MonoBehaviour private string _clientStatePath = ""; private CultMeshReactiveDocument _catalog; private CultMeshReactiveDocument _playerSettings; + private CultMeshReactiveDocument _currentDocking; + private CultMeshReactiveDocument _stationRefit; private readonly AetheriaEveUnitySurfaceChrome _cargoSelectorSurfaceChrome = PanelChrome(360f, 420f, Align.FlexEnd); private readonly AetheriaEveUnitySurfaceChrome _filterSurfaceChrome = PanelChrome(420f, 520f, Align.FlexStart); private readonly AetheriaEveUnitySurfaceChrome _rowActionSurfaceChrome = PanelChrome(320f, 360f, Align.FlexStart); @@ -47,7 +49,6 @@ public class TradeMenu : MonoBehaviour private AetheriaRuntimeTradeCargoSelectorSurfaceModel _cargoSelectorSurfaceModel; private AetheriaRuntimeStationCargoTargetRow[] _cargoSelectorStationRefitTargets = Array.Empty(); - private AetheriaRuntimeStationRefitDocument _stationRefit; private AetheriaRuntimeTradeFilterSurfaceModel _filterSurfaceModel; private Action[] _rowActionCallbacks = Array.Empty(); private AetheriaRuntimeTradeRowActionSurfaceModel _rowActionSurfaceModel; @@ -513,23 +514,18 @@ public class TradeMenu : MonoBehaviour private AetheriaRuntimeStationRefitDocument ResolveStationRefit() { if (_stationRefit != null) - return _stationRefit; + return _stationRefit.Current; - _stationRefit = TryResolveStationRefit(); - return _stationRefit; - } - - private AetheriaRuntimeStationRefitDocument TryResolveStationRefit() - { try { - return ResolveClient().State.Latest(); + _stationRefit = ResolveClient().State.Reactive(); } catch (Exception ex) { - Debug.LogWarning($"Failed to read Aetheria station refit state for trade menu: {ex.Message}"); - return null; + Debug.LogWarning($"Failed to bind Aetheria station refit state for trade menu: {ex.Message}"); } + + return _stationRefit?.Current; } private bool TryResolveCurrentDocking(out AetheriaRuntimeCurrentDockingDocument docking) @@ -537,7 +533,8 @@ public class TradeMenu : MonoBehaviour docking = null; try { - docking = ResolveClient().State.Latest(); + _currentDocking ??= ResolveClient().State.Reactive(); + docking = _currentDocking.Current; return docking != null; } catch (Exception ex) @@ -549,6 +546,7 @@ public class TradeMenu : MonoBehaviour private void InvalidateStationRefit() { + _stationRefit?.Dispose(); _stationRefit = null; } @@ -614,8 +612,11 @@ public class TradeMenu : MonoBehaviour { _catalog?.Dispose(); _playerSettings?.Dispose(); + _currentDocking?.Dispose(); + _stationRefit?.Dispose(); _catalog = null; _playerSettings = null; + _currentDocking = null; _stationRefit = null; } diff --git a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeVerseClient.cs b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeVerseClient.cs index fe60285ea..3977ecca9 100644 --- a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeVerseClient.cs +++ b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeVerseClient.cs @@ -241,15 +241,6 @@ namespace GameCult.Aetheria.State.Verse new CultMeshRouteHint(CultMeshLocalityKind.SharedMemory, "Aetheria Verse database")); } - public Task> ReactiveDocumentAsync( - CultRecordKey key, - CultMeshReactiveDocumentOptions? options = null, - string? documentId = null) - where TDocument : class - { - return Document(key, documentId).ReactiveAsync(options); - } - public Observable> WatchRecord( CultRecordKey key) where TDocument : class