From 86fabfd2ec28a2e909207c0914294668534dee8f Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Sun, 28 Jun 2026 09:48:19 +0100 Subject: [PATCH] Use reactive inventory validation documents --- Aetheria.State.Verify/Program.cs | 22 ++++--- Assets/Scripts/UI/Menu/InventoryMenu.cs | 80 ++++++++++++++++++++++-- Assets/Scripts/UI/Menu/InventoryPanel.cs | 80 ++++++++++++++++++++++-- 3 files changed, 166 insertions(+), 16 deletions(-) diff --git a/Aetheria.State.Verify/Program.cs b/Aetheria.State.Verify/Program.cs index d025eb829..0fac1d98f 100644 --- a/Aetheria.State.Verify/Program.cs +++ b/Aetheria.State.Verify/Program.cs @@ -6852,11 +6852,11 @@ static void RequireInventoryValidationUsesManagedTypedDocuments(string root) } var clientState = File.ReadAllText(clientStatePath); - if (!clientState.Contains("public Task LatestInventoryAsync(int entityIndex)", StringComparison.Ordinal) || - !clientState.Contains("public AetheriaRuntimeInventoryDocument LatestInventory(int entityIndex)", StringComparison.Ordinal)) + if (!clientState.Contains("public Task> ReactiveInventoryAsync(", StringComparison.Ordinal) || + !clientState.Contains("public CultMeshReactiveDocument ReactiveInventory(", StringComparison.Ordinal)) { throw new InvalidOperationException( - "AetheriaClientDetailState must expose managed typed latest access for indexed inventory documents."); + "AetheriaClientDetailState must expose managed reactive typed access for indexed inventory documents."); } var sources = new Dictionary @@ -6869,10 +6869,13 @@ static void RequireInventoryValidationUsesManagedTypedDocuments(string root) var compact = CompactSource(source); var requiredSymbols = new[] { - "var state = ResolveClient().Aetheria();", - "state.Latest()", - "state.Latest()", - "state.Details.LatestInventory(entityIndex)" + "ResolveCurrentEntity()", + ".ReactiveEntity()", + "ResolveReactiveStationRefit()", + ".ReactiveStationRefit()", + "ResolveInventory(entityIndex)", + ".ReactiveInventory(entityIndex)", + "_inventory?.Current" }; var missingSymbols = requiredSymbols .Where(symbol => !source.Contains(symbol, StringComparison.Ordinal)) @@ -6886,6 +6889,9 @@ static void RequireInventoryValidationUsesManagedTypedDocuments(string root) var forbiddenCompactedSymbols = new[] { + ".Latest()", + ".Latest()", + ".Details.LatestInventory(entityIndex)", ".Aetheria().Current.Entity.LatestAsync()", ".Aetheria().StationRefit.LatestAsync()", ".Details.Inventory(entityIndex).LatestAsync()" @@ -15724,7 +15730,7 @@ static void RequireInventoryDoubleClickTransferRequestAuthority(string root) "TryValidateTypedCargoSlot(", "TryValidateTypedEquipmentSlot(", ".Details", - ".LatestInventory(entityIndex)", + ".ReactiveInventory(entityIndex)", "origin.Cargo.TryGetValue(item, out var originPosition)", "SourceIndex == cargoIndex", "SourceIndex == equipmentIndex", diff --git a/Assets/Scripts/UI/Menu/InventoryMenu.cs b/Assets/Scripts/UI/Menu/InventoryMenu.cs index 3b6997563..69ba6a75d 100644 --- a/Assets/Scripts/UI/Menu/InventoryMenu.cs +++ b/Assets/Scripts/UI/Menu/InventoryMenu.cs @@ -34,6 +34,10 @@ public class InventoryMenu : MonoBehaviour private string _clientStatePath = ""; private CultMeshReactiveDocument _catalog; private CultMeshReactiveDocument _playerSettings; + private CultMeshReactiveDocument _currentEntity; + private CultMeshReactiveDocument _stationRefit; + private int _inventoryEntityIndex = -1; + private CultMeshReactiveDocument _inventory; private AetheriaUnityActionBarPresentation _actionBarPresentation; private AetheriaUnityObservedEntityIndex _observedEntityIndex; private readonly AetheriaEveUnitySurfaceChrome _shipSettingsSurfaceChrome = PanelChrome(360f, 420f); @@ -824,8 +828,7 @@ public class InventoryMenu : MonoBehaviour try { - var state = ResolveClient().Aetheria(); - var current = state.Latest(); + var current = ResolveCurrentEntity(); if (current != null && string.Equals(current.EntityKey, entityKey, StringComparison.Ordinal)) { equipment = current.Equipment ?? Array.Empty(); @@ -833,7 +836,7 @@ public class InventoryMenu : MonoBehaviour return true; } - var refit = state.Latest(); + var refit = ResolveReactiveStationRefit(); var entityIndex = -1; if (refit != null) { @@ -848,7 +851,7 @@ public class InventoryMenu : MonoBehaviour if (entityIndex < 0) return false; - var inventory = state.Details.LatestInventory(entityIndex); + var inventory = ResolveInventory(entityIndex); if (inventory == null || !string.Equals(inventory.EntityKey, entityKey, StringComparison.Ordinal)) return false; @@ -939,8 +942,77 @@ public class InventoryMenu : MonoBehaviour { _catalog?.Dispose(); _playerSettings?.Dispose(); + _currentEntity?.Dispose(); + _stationRefit?.Dispose(); + _inventory?.Dispose(); _catalog = null; _playerSettings = null; + _currentEntity = null; + _stationRefit = null; + _inventory = null; + _inventoryEntityIndex = -1; + } + + private AetheriaRuntimeCurrentEntityDocument ResolveCurrentEntity() + { + if (_currentEntity != null) + return _currentEntity.Current; + + try + { + _currentEntity = ResolveClient() + .Aetheria() + .Current + .ReactiveEntity(); + } + catch (Exception ex) + { + Debug.LogWarning($"Failed to bind Aetheria current entity for inventory menu: {ex.Message}"); + } + + return _currentEntity?.Current; + } + + private AetheriaRuntimeStationRefitDocument ResolveReactiveStationRefit() + { + if (_stationRefit != null) + return _stationRefit.Current; + + try + { + _stationRefit = ResolveClient() + .Aetheria() + .ReactiveStationRefit(); + } + catch (Exception ex) + { + Debug.LogWarning($"Failed to bind Aetheria station refit for inventory menu: {ex.Message}"); + } + + return _stationRefit?.Current; + } + + private AetheriaRuntimeInventoryDocument ResolveInventory(int entityIndex) + { + if (_inventory != null && _inventoryEntityIndex == entityIndex) + return _inventory.Current; + + try + { + var nextInventory = ResolveClient() + .Aetheria() + .Details + .ReactiveInventory(entityIndex); + _inventory?.Dispose(); + _inventoryEntityIndex = entityIndex; + _inventory = nextInventory; + } + catch (Exception ex) + { + Debug.LogWarning($"Failed to bind Aetheria inventory projection for entity {entityIndex}: {ex.Message}"); + } + + return _inventory?.Current; } void Update() diff --git a/Assets/Scripts/UI/Menu/InventoryPanel.cs b/Assets/Scripts/UI/Menu/InventoryPanel.cs index 83ff8447c..3fbec144d 100644 --- a/Assets/Scripts/UI/Menu/InventoryPanel.cs +++ b/Assets/Scripts/UI/Menu/InventoryPanel.cs @@ -104,6 +104,10 @@ public class InventoryPanel : MonoBehaviour, IPointerClickHandler private string _clientStatePath = ""; private CultMeshReactiveDocument _catalog; private CultMeshReactiveDocument _playerSettings; + private CultMeshReactiveDocument _currentEntity; + private CultMeshReactiveDocument _stationRefit; + private int _inventoryEntityIndex = -1; + private CultMeshReactiveDocument _inventory; private AetheriaRuntimeStationRefitEntityOption[] _dropdownStationRefitEntities = Array.Empty(); private AetheriaRuntimeStationLoadoutRestoreOption[] _dropdownStationRefitLoadouts = @@ -1249,8 +1253,7 @@ private void Update() try { - var state = ResolveClient().Aetheria(); - var current = state.Latest(); + var current = ResolveCurrentEntity(); if (current != null && string.Equals(current.EntityKey, entityKey, StringComparison.Ordinal)) { equipment = current.Equipment ?? Array.Empty(); @@ -1258,7 +1261,7 @@ private void Update() return true; } - var refit = state.Latest(); + var refit = ResolveReactiveStationRefit(); var entityIndex = -1; if (refit != null) { @@ -1273,7 +1276,7 @@ private void Update() if (entityIndex < 0) return false; - var inventory = state.Details.LatestInventory(entityIndex); + var inventory = ResolveInventory(entityIndex); if (inventory == null || !string.Equals(inventory.EntityKey, entityKey, StringComparison.Ordinal)) return false; @@ -1488,8 +1491,77 @@ private void Update() { _catalog?.Dispose(); _playerSettings?.Dispose(); + _currentEntity?.Dispose(); + _stationRefit?.Dispose(); + _inventory?.Dispose(); _catalog = null; _playerSettings = null; + _currentEntity = null; + _stationRefit = null; + _inventory = null; + _inventoryEntityIndex = -1; + } + + private AetheriaRuntimeCurrentEntityDocument ResolveCurrentEntity() + { + if (_currentEntity != null) + return _currentEntity.Current; + + try + { + _currentEntity = ResolveClient() + .Aetheria() + .Current + .ReactiveEntity(); + } + catch (Exception ex) + { + Debug.LogWarning($"Failed to bind Aetheria current entity for inventory panel: {ex.Message}"); + } + + return _currentEntity?.Current; + } + + private AetheriaRuntimeStationRefitDocument ResolveReactiveStationRefit() + { + if (_stationRefit != null) + return _stationRefit.Current; + + try + { + _stationRefit = ResolveClient() + .Aetheria() + .ReactiveStationRefit(); + } + catch (Exception ex) + { + Debug.LogWarning($"Failed to bind Aetheria station refit for inventory panel: {ex.Message}"); + } + + return _stationRefit?.Current; + } + + private AetheriaRuntimeInventoryDocument ResolveInventory(int entityIndex) + { + if (_inventory != null && _inventoryEntityIndex == entityIndex) + return _inventory.Current; + + try + { + var nextInventory = ResolveClient() + .Aetheria() + .Details + .ReactiveInventory(entityIndex); + _inventory?.Dispose(); + _inventoryEntityIndex = entityIndex; + _inventory = nextInventory; + } + catch (Exception ex) + { + Debug.LogWarning($"Failed to bind Aetheria inventory projection for entity {entityIndex}: {ex.Message}"); + } + + return _inventory?.Current; } private AetheriaRuntimeCatalogSnapshot ResolveCatalog()