From a96fdc66bc01aa28af39954f03ce16fcbf5fa4b3 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Sun, 28 Jun 2026 14:08:53 +0100 Subject: [PATCH] Centralize viewport render state sessions --- Aetheria.State.Verify/Program.cs | 54 ++++++++++++++----- .../AetheriaUnityRenderSplatViewportSource.cs | 5 +- .../Tests/DaemonRuntimeDocumentTests.cs | 4 ++ Assets/Scripts/UI/Menu/MapRenderer.cs | 13 +++-- .../Runtime/AetheriaClientState.cs | 14 +++++ .../Runtime/AetheriaRuntimeStateSessions.cs | 36 +++++++++++++ 6 files changed, 104 insertions(+), 22 deletions(-) diff --git a/Aetheria.State.Verify/Program.cs b/Aetheria.State.Verify/Program.cs index 2bac1f430..9c365ee6d 100644 --- a/Aetheria.State.Verify/Program.cs +++ b/Aetheria.State.Verify/Program.cs @@ -7381,13 +7381,13 @@ static void RequireUnitySharedDocumentAccessorErgonomics(string root) "MapRenderer.cs")); var requiredMapRendererSharedDocumentSymbols = new[] { - "CultMeshReactiveDocument _objectsViewport", - "CultMeshReactiveDocument _renderSplatsViewport", - "CultMeshReactiveDocument _playerSettings", - ".ReactiveObjects(viewport)", - ".ReactiveRenderSplats(viewport)", + "AetheriaRuntimeObjectsViewportSession _objectsViewport", + "AetheriaRuntimeRenderSplatsViewportSession _renderSplatsViewport", + "AetheriaRuntimePlayerSettingsSession _playerSettings", + ".ObserveObjects(viewport)", + ".ObserveRenderSplats(viewport)", ".Settings", - ".ReactivePlayer()", + ".ObservePlayer()", "ClearViewportCaches()", "_objectsViewport?.Dispose()", "_renderSplatsViewport?.Dispose()", @@ -7407,6 +7407,25 @@ static void RequireUnitySharedDocumentAccessorErgonomics(string root) string.Join(", ", missingMapRendererSharedDocumentSymbols)); } + var forbiddenMapRendererSharedDocumentSymbols = new[] + { + "CultMeshReactiveDocument _objectsViewport", + "CultMeshReactiveDocument _renderSplatsViewport", + "CultMeshReactiveDocument _playerSettings", + ".ReactiveObjects(viewport)", + ".ReactiveRenderSplats(viewport)", + ".ReactivePlayer()" + }; + var mapRendererRawDocumentHits = forbiddenMapRendererSharedDocumentSymbols + .Where(symbol => mapRenderer.Contains(symbol, StringComparison.Ordinal)) + .ToArray(); + if (mapRendererRawDocumentHits.Length > 0) + { + throw new InvalidOperationException( + "MapRenderer still owns raw viewport/settings CultMesh documents instead of managed sessions: " + + string.Join(", ", mapRendererRawDocumentHits)); + } + var mainMenu = File.ReadAllText(Path.Combine( root, "Assets", @@ -7647,8 +7666,10 @@ static void RequireUnityViewportAndMapReadsUseManagedAccessors(string root) "public AetheriaRuntimeCurrentEntityDocument LatestEntity()", "public AetheriaRuntimeObjectsViewportDocument LatestObjects(AetheriaRuntimeRtsViewportBounds viewport)", "public CultMeshReactiveDocument ReactiveObjects(", + "public AetheriaRuntimeObjectsViewportSession ObserveObjects(", "public AetheriaRuntimeRenderSplatsViewportDocument LatestRenderSplats(AetheriaRuntimeRtsViewportBounds viewport)", "public CultMeshReactiveDocument ReactiveRenderSplats(", + "public AetheriaRuntimeRenderSplatsViewportSession ObserveRenderSplats(", "public AetheriaRuntimeZoneDetailsDocument LatestZone(int zoneIndex)" }; var missingClientSymbols = requiredClientSymbols @@ -7717,8 +7738,8 @@ static void RequireUnityViewportAndMapReadsUseManagedAccessors(string root) "AetheriaUnityRenderSplatViewportSource.cs")); var requiredRenderSplatViewportSourceSymbols = new[] { - "CultMeshReactiveDocument _renderSplatsViewport", - ".ReactiveRenderSplats(viewport)", + "AetheriaRuntimeRenderSplatsViewportSession _renderSplatsViewport", + ".ObserveRenderSplats(viewport)", "_renderSplatsViewport?.Current", "ClearViewportDocument()" }; @@ -7733,6 +7754,13 @@ static void RequireUnityViewportAndMapReadsUseManagedAccessors(string root) string.Join(", ", missingRenderSplatViewportSourceSymbols)); } + if (renderSplatViewportSource.Contains("CultMeshReactiveDocument _renderSplatsViewport", StringComparison.Ordinal) || + renderSplatViewportSource.Contains(".ReactiveRenderSplats(viewport)", StringComparison.Ordinal)) + { + throw new InvalidOperationException( + "AetheriaUnityRenderSplatViewportSource still owns a raw render-splats CultMesh document instead of AetheriaRuntimeRenderSplatsViewportSession."); + } + var zoneRenderer = File.ReadAllText(Path.Combine( root, "Assets", @@ -13550,10 +13578,10 @@ static void RequireUnityObserverDoesNotTickLocalSimulation(string root) if (!mapRenderer.Contains("AetheriaUnityRuntimeClientProvider.ResolveClient(", StringComparison.Ordinal) || !mapRenderer.Contains(".Viewports", StringComparison.Ordinal) || - !mapRenderer.Contains(".ReactiveObjects(viewport)", StringComparison.Ordinal) || - !mapRenderer.Contains(".ReactiveRenderSplats(viewport)", StringComparison.Ordinal) || + !mapRenderer.Contains(".ObserveObjects(viewport)", StringComparison.Ordinal) || + !mapRenderer.Contains(".ObserveRenderSplats(viewport)", StringComparison.Ordinal) || !mapRenderer.Contains(".Settings", StringComparison.Ordinal) || - !mapRenderer.Contains(".ReactivePlayer()", StringComparison.Ordinal) || + !mapRenderer.Contains(".ObservePlayer()", StringComparison.Ordinal) || !sectorRenderer.Contains("AetheriaUnityRuntimeClientProvider.ResolveClient(", StringComparison.Ordinal) || !sectorRenderer.Contains(".State", StringComparison.Ordinal) || !sectorRenderer.Contains(".ReactiveSectorMap()", StringComparison.Ordinal) || @@ -15285,7 +15313,9 @@ static void RequireRuntimeStateReaderOwnsUnityStateAcquisition(string root) "public AetheriaRuntimeZoneContactsSession ObserveZoneContacts(", "public AetheriaRuntimePlayerSettingsSession ObservePlayer(", "public AetheriaRuntimeVerseHostSettingsSession ObserveVerseHost(", - "public AetheriaRuntimeSectorMapSession ObserveSectorMap(" + "public AetheriaRuntimeSectorMapSession ObserveSectorMap(", + "public AetheriaRuntimeObjectsViewportSession ObserveObjects(", + "public AetheriaRuntimeRenderSplatsViewportSession ObserveRenderSplats(" }; var missingManagedStateAccessSymbols = requiredManagedStateAccessSymbols .Where(symbol => !aetheriaClientState.Contains(symbol, StringComparison.Ordinal)) diff --git a/Assets/Scripts/Gameplay/AetheriaUnityRenderSplatViewportSource.cs b/Assets/Scripts/Gameplay/AetheriaUnityRenderSplatViewportSource.cs index f8b18c7db..634a7884f 100644 --- a/Assets/Scripts/Gameplay/AetheriaUnityRenderSplatViewportSource.cs +++ b/Assets/Scripts/Gameplay/AetheriaUnityRenderSplatViewportSource.cs @@ -1,5 +1,4 @@ using System; -using GameCult.Mesh; using GameCult.Aetheria.State.Verse; using UnityEngine; @@ -28,7 +27,7 @@ public sealed class AetheriaUnityRenderSplatViewportSource : MonoBehaviour private float _nextRefreshTime; private AetheriaRuntimeRtsViewportBounds _viewport; - private CultMeshReactiveDocument _renderSplatsViewport; + private AetheriaRuntimeRenderSplatsViewportSession _renderSplatsViewport; public RenderTexture TargetTexture { @@ -119,7 +118,7 @@ public sealed class AetheriaUnityRenderSplatViewportSource : MonoBehaviour var nextRenderSplatsViewport = ResolveClient() .State .Viewports - .ReactiveRenderSplats(viewport); + .ObserveRenderSplats(viewport); ClearViewportDocument(); _viewport = viewport; _renderSplatsViewport = nextRenderSplatsViewport; diff --git a/Assets/Scripts/Tests/DaemonRuntimeDocumentTests.cs b/Assets/Scripts/Tests/DaemonRuntimeDocumentTests.cs index ad2132f51..cc69ac200 100644 --- a/Assets/Scripts/Tests/DaemonRuntimeDocumentTests.cs +++ b/Assets/Scripts/Tests/DaemonRuntimeDocumentTests.cs @@ -210,6 +210,8 @@ public class DaemonRuntimeDocumentTests using var playerSettingsSession = client.State.Settings.ObservePlayer(); using var verseHostSettingsSession = client.State.Settings.ObserveVerseHost(); using var zoneContactsSession = client.State.ObserveZoneContacts(); + using var objectsViewportSession = client.State.Viewports.ObserveObjects(viewport); + using var renderSplatsViewportSession = client.State.Viewports.ObserveRenderSplats(viewport); using var playerHud = client.State.ObservePlayerHud(); var gameSurface = client.State.LatestGameSurface(); var gameTuiSurface = client.State.LatestGameTuiSurface(); @@ -291,6 +293,8 @@ public class DaemonRuntimeDocumentTests Assert.AreEqual(AetheriaRuntimeVerseHostSettingsDocument.SchemaId, verseHostSettings.Schema); Assert.AreEqual(AetheriaRuntimeVerseHostSettingsDocument.SchemaId, verseHostSettingsSession.Current.Schema); Assert.AreEqual(AetheriaRuntimeDaemonSchemas.ObjectsViewport, objectsViewport.Schema); + Assert.AreEqual(AetheriaRuntimeDaemonSchemas.ObjectsViewport, objectsViewportSession.Current.Schema); + Assert.AreEqual(AetheriaRuntimeDaemonSchemas.RenderSplatsViewport, renderSplatsViewportSession.Current.Schema); Assert.AreEqual(AetheriaRuntimeDaemonSchemas.ZoneContacts, zoneContactsSession.Current.Schema); Assert.AreEqual("Player", objectsViewport.Objects.FirstOrDefault()?.DisplayName); Assert.AreEqual(AetheriaRuntimeDaemonSchemas.ZoneDetails, zoneDetails.Schema); diff --git a/Assets/Scripts/UI/Menu/MapRenderer.cs b/Assets/Scripts/UI/Menu/MapRenderer.cs index 986441c5c..75b314b2f 100644 --- a/Assets/Scripts/UI/Menu/MapRenderer.cs +++ b/Assets/Scripts/UI/Menu/MapRenderer.cs @@ -6,7 +6,6 @@ using System; using System.Collections; using System.Collections.Generic; using System.Linq; -using GameCult.Mesh; using GameCult.Aetheria.State.Verse; using TMPro; using UnityEngine; @@ -40,12 +39,12 @@ public class MapRenderer : MonoBehaviour private RenderTexture _mapTexture; private int2 _size; private bool _init; - private CultMeshReactiveDocument _objectsViewport; - private CultMeshReactiveDocument _renderSplatsViewport; + private AetheriaRuntimeObjectsViewportSession _objectsViewport; + private AetheriaRuntimeRenderSplatsViewportSession _renderSplatsViewport; private float _nextViewportRefreshTime; private readonly List _rtsIconPool = new List(); private string _clientStatePath = ""; - private CultMeshReactiveDocument _playerSettings; + private AetheriaRuntimePlayerSettingsSession _playerSettings; void Start() { @@ -132,11 +131,11 @@ public class MapRenderer : MonoBehaviour _objectsViewport = client .State .Viewports - .ReactiveObjects(viewport); + .ObserveObjects(viewport); _renderSplatsViewport = client .State .Viewports - .ReactiveRenderSplats(viewport); + .ObserveRenderSplats(viewport); var objectsViewport = _objectsViewport?.Current; var zoneName = string.IsNullOrWhiteSpace(objectsViewport?.ZoneName) @@ -321,7 +320,7 @@ public class MapRenderer : MonoBehaviour _playerSettings ??= ResolveClient() .State .Settings - .ReactivePlayer(); + .ObservePlayer(); return _playerSettings?.Current?.ShowAsteroidsInMinimap ?? false; } catch (Exception ex) diff --git a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaClientState.cs b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaClientState.cs index 6cac43e51..20860c751 100644 --- a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaClientState.cs +++ b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaClientState.cs @@ -1075,6 +1075,13 @@ namespace GameCult.Aetheria.State.Verse return Objects(viewport).Reactive(options); } + public AetheriaRuntimeObjectsViewportSession ObserveObjects( + AetheriaRuntimeRtsViewportBounds viewport, + CultMeshReactiveDocumentOptions? options = null) + { + return new AetheriaRuntimeObjectsViewportSession(ReactiveObjects(viewport, options)); + } + public CultMeshDocumentHandle Gravity(AetheriaRuntimeRtsViewportBounds viewport) { return _gravity(viewport ?? new AetheriaRuntimeRtsViewportBounds()); @@ -1132,6 +1139,13 @@ namespace GameCult.Aetheria.State.Verse { return RenderSplats(viewport).Reactive(options); } + + public AetheriaRuntimeRenderSplatsViewportSession ObserveRenderSplats( + AetheriaRuntimeRtsViewportBounds viewport, + CultMeshReactiveDocumentOptions? options = null) + { + return new AetheriaRuntimeRenderSplatsViewportSession(ReactiveRenderSplats(viewport, options)); + } } public sealed class AetheriaClientDetailState diff --git a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeStateSessions.cs b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeStateSessions.cs index 1e270a4bb..fd9cfa7b5 100644 --- a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeStateSessions.cs +++ b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeStateSessions.cs @@ -94,4 +94,40 @@ namespace GameCult.Aetheria.State.Verse _zoneContacts.Dispose(); } } + + public sealed class AetheriaRuntimeObjectsViewportSession : IDisposable + { + private readonly CultMeshReactiveDocument _objectsViewport; + + public AetheriaRuntimeObjectsViewportSession( + CultMeshReactiveDocument objectsViewport) + { + _objectsViewport = objectsViewport ?? throw new ArgumentNullException(nameof(objectsViewport)); + } + + public AetheriaRuntimeObjectsViewportDocument? Current => _objectsViewport.Current; + + public void Dispose() + { + _objectsViewport.Dispose(); + } + } + + public sealed class AetheriaRuntimeRenderSplatsViewportSession : IDisposable + { + private readonly CultMeshReactiveDocument _renderSplatsViewport; + + public AetheriaRuntimeRenderSplatsViewportSession( + CultMeshReactiveDocument renderSplatsViewport) + { + _renderSplatsViewport = renderSplatsViewport ?? throw new ArgumentNullException(nameof(renderSplatsViewport)); + } + + public AetheriaRuntimeRenderSplatsViewportDocument? Current => _renderSplatsViewport.Current; + + public void Dispose() + { + _renderSplatsViewport.Dispose(); + } + } }