diff --git a/Aetheria.State.Verify/Program.cs b/Aetheria.State.Verify/Program.cs index 58474814f..d025eb829 100644 --- a/Aetheria.State.Verify/Program.cs +++ b/Aetheria.State.Verify/Program.cs @@ -4508,9 +4508,10 @@ static void RequireSectorMapZoneDetailsUseEveSurface(string root) "ProjectZoneDetailsSurfaceState(", "AetheriaUnityRuntimeClientProvider.ResolveClient(", ".Aetheria()", - ".LatestSectorMap()", + ".ReactiveSectorMap()", ".Details", - ".LatestZone(zoneIndex)", + ".ReactiveZone(zoneIndex)", + "_zoneDetails?.Current", ".Settings", ".ReactiveCatalog()", ".ReactivePlayer()", @@ -7003,7 +7004,19 @@ static void RequireUnitySharedDocumentAccessorErgonomics(string root) "public Task> ReactiveStationRefitAsync(", "public CultMeshReactiveDocument ReactiveStationRefit(", "public Task> ReactiveZoneRenderAsync(", - "public CultMeshReactiveDocument ReactiveZoneRender(" + "public CultMeshReactiveDocument ReactiveZoneRender(", + "public Task> ReactiveZoneAsync(", + "public CultMeshReactiveDocument ReactiveZone(", + "public Task> ReactiveEntityAsync(", + "public CultMeshReactiveDocument ReactiveEntity(", + "public Task> ReactiveDockingAsync(", + "public CultMeshReactiveDocument ReactiveDocking(", + "public Task> ReactiveZoneAsync(", + "public CultMeshReactiveDocument ReactiveZone(", + "public Task> ReactiveSelectedObjectAsync(", + "public CultMeshReactiveDocument ReactiveSelectedObject(", + "public Task> ReactiveInventoryAsync(", + "public CultMeshReactiveDocument ReactiveInventory(" }; var missingClientSymbols = requiredClientSymbols .Where(symbol => !clientState.Contains(symbol, StringComparison.Ordinal)) @@ -12987,15 +13000,16 @@ static void RequireUnityObserverDoesNotTickLocalSimulation(string root) !mapRenderer.Contains(".ReactivePlayer()", StringComparison.Ordinal) || !sectorRenderer.Contains("AetheriaUnityRuntimeClientProvider.ResolveClient(", StringComparison.Ordinal) || !sectorRenderer.Contains(".Aetheria()", StringComparison.Ordinal) || - !sectorRenderer.Contains(".LatestSectorMap()", StringComparison.Ordinal) || + !sectorRenderer.Contains(".ReactiveSectorMap()", StringComparison.Ordinal) || !sectorRenderer.Contains(".Details", StringComparison.Ordinal) || - !sectorRenderer.Contains(".LatestZone(zoneIndex)", StringComparison.Ordinal) || + !sectorRenderer.Contains(".ReactiveZone(zoneIndex)", StringComparison.Ordinal) || + !sectorRenderer.Contains(".Current", StringComparison.Ordinal) || !sectorRenderer.Contains(".Settings", StringComparison.Ordinal) || !sectorRenderer.Contains(".ReactiveCatalog()", StringComparison.Ordinal) || !sectorRenderer.Contains(".ReactivePlayer()", StringComparison.Ordinal) || !sectorMap.Contains("AetheriaUnityRuntimeClientProvider.ResolveClient(", StringComparison.Ordinal) || !sectorMap.Contains(".Aetheria()", StringComparison.Ordinal) || - !sectorMap.Contains(".LatestSectorMap()", StringComparison.Ordinal) || + !sectorMap.Contains(".ReactiveSectorMap()", StringComparison.Ordinal) || !sectorRenderer.Contains("AetheriaRuntimeZoneDetailsSurfaceBuilder.ProjectDaemonZone(", StringComparison.Ordinal)) { throw new InvalidOperationException( diff --git a/Assets/Scripts/UI/Menu/SectorMap.cs b/Assets/Scripts/UI/Menu/SectorMap.cs index 4af400b2a..c1ff3d974 100644 --- a/Assets/Scripts/UI/Menu/SectorMap.cs +++ b/Assets/Scripts/UI/Menu/SectorMap.cs @@ -2,6 +2,7 @@ using System; using System.Collections; using System.Collections.Generic; using System.Linq; +using GameCult.Mesh; using GameCult.Aetheria.State.Verse; using TMPro; using UniRx; @@ -52,6 +53,7 @@ public class SectorMap : MonoBehaviour private readonly Queue> _queuedZoneReveals = new Queue>(); private readonly Dictionary _zonesByIndex = new Dictionary(); + private CultMeshReactiveDocument _sectorMapDocument; private AetheriaRuntimeSectorMapDocument _sectorMap; private bool _sectorMapLoaded; @@ -219,9 +221,10 @@ public class SectorMap : MonoBehaviour private void EnsureSectorMapLoaded() { - _sectorMap = ResolveClient() + _sectorMapDocument ??= ResolveClient() .Aetheria() - .LatestSectorMap(); + .ReactiveSectorMap(); + _sectorMap = _sectorMapDocument.Current; if (_sectorMapLoaded) return; @@ -252,6 +255,8 @@ public class SectorMap : MonoBehaviour private void OnDestroy() { + _sectorMapDocument?.Dispose(); + _sectorMapDocument = null; _sectorMapLoaded = false; } diff --git a/Assets/Scripts/UI/Menu/SectorRenderer.cs b/Assets/Scripts/UI/Menu/SectorRenderer.cs index eb969f0bc..8b70df942 100644 --- a/Assets/Scripts/UI/Menu/SectorRenderer.cs +++ b/Assets/Scripts/UI/Menu/SectorRenderer.cs @@ -49,6 +49,10 @@ public class SectorRenderer : MonoBehaviour, IBeginDragHandler, IDragHandler, IS private string _clientStatePath = ""; private CultMeshReactiveDocument _catalog; private CultMeshReactiveDocument _playerSettings; + private CultMeshReactiveDocument _sectorMap; + private CultMeshReactiveDocument _currentZone; + private int _zoneDetailsIndex = -1; + private CultMeshReactiveDocument _zoneDetails; private readonly AetheriaEveUnitySurfaceChrome _zoneDetailsSurfaceChrome = new AetheriaEveUnitySurfaceChrome { RootAlignItems = Align.FlexEnd, @@ -170,9 +174,10 @@ public class SectorRenderer : MonoBehaviour, IBeginDragHandler, IDragHandler, IS try { - var sectorMap = ResolveClient() + _sectorMap ??= ResolveClient() .Aetheria() - .LatestSectorMap(); + .ReactiveSectorMap(); + var sectorMap = _sectorMap.Current; return (sectorMap?.Zones ?? Array.Empty()) .FirstOrDefault(zone => zone.ZoneIndex == zoneIndex); } @@ -193,18 +198,25 @@ public class SectorRenderer : MonoBehaviour, IBeginDragHandler, IDragHandler, IS if (zoneIndex < 0) return null; + if (_zoneDetails != null && _zoneDetailsIndex == zoneIndex) + return _zoneDetails.Current; + try { - return ResolveClient() + var nextZoneDetails = ResolveClient() .Aetheria() .Details - .LatestZone(zoneIndex); + .ReactiveZone(zoneIndex); + _zoneDetails?.Dispose(); + _zoneDetailsIndex = zoneIndex; + _zoneDetails = nextZoneDetails; } catch (Exception ex) { - Debug.LogWarning($"Failed to read Aetheria sector zone details from local Verse state: {ex.Message}"); - return null; + Debug.LogWarning($"Failed to bind Aetheria sector zone details from local Verse state: {ex.Message}"); } + + return _zoneDetails?.Current; } private string ResolveHullType(string hullItemKey) @@ -281,8 +293,15 @@ public class SectorRenderer : MonoBehaviour, IBeginDragHandler, IDragHandler, IS { _catalog?.Dispose(); _playerSettings?.Dispose(); + _sectorMap?.Dispose(); + _currentZone?.Dispose(); + _zoneDetails?.Dispose(); _catalog = null; _playerSettings = null; + _sectorMap = null; + _currentZone = null; + _zoneDetails = null; + _zoneDetailsIndex = -1; } private void OnEnable() { @@ -303,16 +322,17 @@ public class SectorRenderer : MonoBehaviour, IBeginDragHandler, IDragHandler, IS { try { - return ResolveClient() + _currentZone ??= ResolveClient() .Aetheria() .Current - .LatestZone(); + .ReactiveZone(); } catch (Exception ex) { - Debug.LogWarning($"Failed to read Aetheria sector current zone from local Verse state: {ex.Message}"); - return null; + Debug.LogWarning($"Failed to bind Aetheria sector current zone from local Verse state: {ex.Message}"); } + + return _currentZone?.Current; } private void OnDisable() diff --git a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaClientState.cs b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaClientState.cs index 899ed8c1a..fa4d96bb7 100644 --- a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaClientState.cs +++ b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaClientState.cs @@ -558,6 +558,18 @@ namespace GameCult.Aetheria.State.Verse return LatestZoneAsync().ConfigureAwait(false).GetAwaiter().GetResult(); } + public Task> ReactiveZoneAsync( + CultMeshReactiveDocumentOptions? options = null) + { + return Zone.ReactiveAsync(options); + } + + public CultMeshReactiveDocument ReactiveZone( + CultMeshReactiveDocumentOptions? options = null) + { + return Zone.Reactive(options); + } + public Task LatestEntityAsync() { return Entity.LatestAsync(); @@ -567,6 +579,30 @@ namespace GameCult.Aetheria.State.Verse { return LatestEntityAsync().ConfigureAwait(false).GetAwaiter().GetResult(); } + + public Task> ReactiveEntityAsync( + CultMeshReactiveDocumentOptions? options = null) + { + return Entity.ReactiveAsync(options); + } + + public CultMeshReactiveDocument ReactiveEntity( + CultMeshReactiveDocumentOptions? options = null) + { + return Entity.Reactive(options); + } + + public Task> ReactiveDockingAsync( + CultMeshReactiveDocumentOptions? options = null) + { + return Docking.ReactiveAsync(options); + } + + public CultMeshReactiveDocument ReactiveDocking( + CultMeshReactiveDocumentOptions? options = null) + { + return Docking.Reactive(options); + } } public sealed class AetheriaClientSettingsState @@ -883,6 +919,20 @@ namespace GameCult.Aetheria.State.Verse return LatestZoneAsync(zoneIndex).ConfigureAwait(false).GetAwaiter().GetResult(); } + public Task> ReactiveZoneAsync( + int zoneIndex, + CultMeshReactiveDocumentOptions? options = null) + { + return Zone(zoneIndex).ReactiveAsync(options); + } + + public CultMeshReactiveDocument ReactiveZone( + int zoneIndex, + CultMeshReactiveDocumentOptions? options = null) + { + return Zone(zoneIndex).Reactive(options); + } + public CultMeshDocumentHandle SelectedObject(int entityIndex) { return _selectedObject(entityIndex); @@ -898,6 +948,20 @@ namespace GameCult.Aetheria.State.Verse return LatestSelectedObjectAsync(entityIndex).ConfigureAwait(false).GetAwaiter().GetResult(); } + public Task> ReactiveSelectedObjectAsync( + int entityIndex, + CultMeshReactiveDocumentOptions? options = null) + { + return SelectedObject(entityIndex).ReactiveAsync(options); + } + + public CultMeshReactiveDocument ReactiveSelectedObject( + int entityIndex, + CultMeshReactiveDocumentOptions? options = null) + { + return SelectedObject(entityIndex).Reactive(options); + } + public CultMeshDocumentHandle Inventory(int entityIndex) { return _inventory(entityIndex); @@ -912,6 +976,20 @@ namespace GameCult.Aetheria.State.Verse { return LatestInventoryAsync(entityIndex).ConfigureAwait(false).GetAwaiter().GetResult(); } + + public Task> ReactiveInventoryAsync( + int entityIndex, + CultMeshReactiveDocumentOptions? options = null) + { + return Inventory(entityIndex).ReactiveAsync(options); + } + + public CultMeshReactiveDocument ReactiveInventory( + int entityIndex, + CultMeshReactiveDocumentOptions? options = null) + { + return Inventory(entityIndex).Reactive(options); + } } public sealed class AetheriaClientStarbridgeState