From a1fa5f1425dd1d0fa6849e6568d2be0e83a43be1 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Sun, 28 Jun 2026 02:32:13 +0100 Subject: [PATCH] Share managed runtime client access --- Aetheria.State.Verify/Program.cs | 51 +++++++++++++++++-- .../AetheriaUnityRenderSplatViewportSource.cs | 33 ++---------- .../AetheriaUnityRuntimeClientProvider.cs | 10 ++++ .../Zone Display/VolumeCloudRenderer.cs | 32 ++---------- Assets/Scripts/Zone Display/ZoneRenderer.cs | 32 ++---------- .../Runtime/AetheriaEveSurfacePresenter.cs | 25 ++------- 6 files changed, 71 insertions(+), 112 deletions(-) diff --git a/Aetheria.State.Verify/Program.cs b/Aetheria.State.Verify/Program.cs index f7597d4e5..6dd61abb6 100644 --- a/Aetheria.State.Verify/Program.cs +++ b/Aetheria.State.Verify/Program.cs @@ -3191,10 +3191,9 @@ static void RequireEveRuntimeBootstrap(string root) var requiredPresenterSymbols = new[] { "private string surfaceId = AetheriaRuntimeDaemonGameSurfaceBuilder.SurfaceId", - "private AetheriaClient? _client", "ReadDaemonSurface(statePath)", "ReadDaemonSurface(stateBoot.StateFilePath)", - "AetheriaClient.OpenAsync(", + "AetheriaUnityRuntimeClientProvider.ResolveClient(", "DaemonGameSurfaceAsync()", "DaemonGameTuiSurfaceAsync()", "DaemonEditorSurfaceAsync()", @@ -9472,7 +9471,7 @@ static void RequireTypedEveCommandBodies(string root) "internal static class AetheriaRuntimeEveCommands", "public static class AetheriaRuntimeEveCommandClient", "namespace GameCult.Aetheria.State.Verse", - "AetheriaClient.OpenAsync(", + "AetheriaUnityRuntimeClientProvider.ResolveClient(", "internal async Task SubmitDaemonCommandAsync(", "internal async Task SubmitEveCommandAsync(", "CreatePlayerSettingsCommand(", @@ -12829,6 +12828,18 @@ static void RequireRuntimeStateReaderOwnsUnityStateAcquisition(string root) var runtimeClientProvider = File.Exists(runtimeClientProviderPath) ? File.ReadAllText(runtimeClientProviderPath) : throw new InvalidOperationException("Cannot verify daemon state acquisition; AetheriaUnityRuntimeClientProvider.cs is missing."); + var zoneRendererPath = Path.Combine(root, "Assets", "Scripts", "Zone Display", "ZoneRenderer.cs"); + var zoneRenderer = File.Exists(zoneRendererPath) + ? File.ReadAllText(zoneRendererPath) + : throw new InvalidOperationException("Cannot verify daemon state acquisition; ZoneRenderer.cs is missing."); + var volumeCloudRendererPath = Path.Combine(root, "Assets", "Scripts", "Zone Display", "VolumeCloudRenderer.cs"); + var volumeCloudRenderer = File.Exists(volumeCloudRendererPath) + ? File.ReadAllText(volumeCloudRendererPath) + : throw new InvalidOperationException("Cannot verify daemon state acquisition; VolumeCloudRenderer.cs is missing."); + var renderSplatViewportSourcePath = Path.Combine(root, "Assets", "Scripts", "Gameplay", "AetheriaUnityRenderSplatViewportSource.cs"); + var renderSplatViewportSource = File.Exists(renderSplatViewportSourcePath) + ? File.ReadAllText(renderSplatViewportSourcePath) + : throw new InvalidOperationException("Cannot verify daemon state acquisition; AetheriaUnityRenderSplatViewportSource.cs is missing."); var gameplayBootShellPath = Path.Combine(root, "Assets", "Scripts", "Gameplay", "AetheriaUnityGameplayBootShell.cs"); var gameplayBootShell = File.Exists(gameplayBootShellPath) ? File.ReadAllText(gameplayBootShellPath) @@ -12902,6 +12913,7 @@ static void RequireRuntimeStateReaderOwnsUnityStateAcquisition(string root) "public static class AetheriaUnityRuntimeClientProvider", "public static RuntimePlayerSettings PlayerSettings =>", "public static AetheriaClient ResolveClient(string stateFilePath, string runtimeId = \"\")", + "public static AetheriaClient ResolveClient(AetheriaRuntimeStateBootReport stateBoot, string runtimeId = \"\")", "public static AetheriaClient CurrentClientForStateFile(string stateFilePath)", "AetheriaClient", ".Aetheria()", @@ -12922,6 +12934,37 @@ static void RequireRuntimeStateReaderOwnsUnityStateAcquisition(string root) string.Join(", ", missingRuntimeClientProviderSymbols)); } + var providerOwnedClientAccessSources = new Dictionary + { + ["Packages/org.gamecult.aetheria.eve-runtime/Runtime/AetheriaEveSurfacePresenter.cs"] = eveSurfacePresenter, + ["Assets/Scripts/Zone Display/ZoneRenderer.cs"] = zoneRenderer, + ["Assets/Scripts/Zone Display/VolumeCloudRenderer.cs"] = volumeCloudRenderer, + ["Assets/Scripts/Gameplay/AetheriaUnityRenderSplatViewportSource.cs"] = renderSplatViewportSource + }; + var directClientOpenHits = providerOwnedClientAccessSources + .Where(pair => + pair.Value.Contains("AetheriaClient.OpenAsync(", StringComparison.Ordinal) || + pair.Value.Contains(".OpenLocalAsync(", StringComparison.Ordinal)) + .Select(pair => pair.Key) + .ToArray(); + if (directClientOpenHits.Length > 0) + { + throw new InvalidOperationException( + "Unity runtime readers must acquire managed typed state through AetheriaUnityRuntimeClientProvider instead of opening local clients: " + + string.Join(", ", directClientOpenHits)); + } + + var missingProviderClientAccess = providerOwnedClientAccessSources + .Where(pair => !pair.Value.Contains("AetheriaUnityRuntimeClientProvider.ResolveClient(", StringComparison.Ordinal)) + .Select(pair => pair.Key) + .ToArray(); + if (missingProviderClientAccess.Length > 0) + { + throw new InvalidOperationException( + "Unity runtime readers no longer use the shared managed runtime client provider: " + + string.Join(", ", missingProviderClientAccess)); + } + if (!observedFrameApplier.Contains("private AetheriaRuntimeZoneRenderDocument _lastZoneRender;", StringComparison.Ordinal) || !observedFrameApplier.Contains("ApplyLatestZoneRender()", StringComparison.Ordinal) || !observedFrameApplier.Contains(".Aetheria()", StringComparison.Ordinal) || @@ -13078,7 +13121,7 @@ static void RequireRuntimeStateReaderOwnsUnityStateAcquisition(string root) string.Join(", ", mainMenuReaderHits)); } - if (!eveSurfacePresenter.Contains("AetheriaClient.OpenAsync(", StringComparison.Ordinal) || + if (!eveSurfacePresenter.Contains("AetheriaUnityRuntimeClientProvider.ResolveClient(", StringComparison.Ordinal) || !eveSurfacePresenter.Contains("ReadDaemonSurface(statePath)", StringComparison.Ordinal)) { throw new InvalidOperationException( diff --git a/Assets/Scripts/Gameplay/AetheriaUnityRenderSplatViewportSource.cs b/Assets/Scripts/Gameplay/AetheriaUnityRenderSplatViewportSource.cs index 4d5c0cc77..edf2bd0cf 100644 --- a/Assets/Scripts/Gameplay/AetheriaUnityRenderSplatViewportSource.cs +++ b/Assets/Scripts/Gameplay/AetheriaUnityRenderSplatViewportSource.cs @@ -1,5 +1,4 @@ using System; -using System.IO; using GameCult.Aetheria.State.Verse; using UnityEngine; @@ -26,8 +25,6 @@ public sealed class AetheriaUnityRenderSplatViewportSource : MonoBehaviour [SerializeField] private bool renderInLateUpdate = true; - private AetheriaClient _client; - private string _clientStatePath = ""; private float _nextRefreshTime; private AetheriaRuntimeRenderSplatsViewportDocument _document; @@ -135,33 +132,9 @@ public sealed class AetheriaUnityRenderSplatViewportSource : MonoBehaviour private AetheriaClient ResolveClient() { - var gameDataDirectory = new DirectoryInfo(Path.Combine(Application.dataPath, "..", "GameData")); - var stateBoot = AetheriaRuntimeStateBoot.Inspect(gameDataDirectory); - if (_client != null && string.Equals(_clientStatePath, stateBoot.StateFilePath, StringComparison.Ordinal)) - return _client; - - DisposeClient(); - _client = AetheriaClient - .OpenLocalAsync( - gameDataDirectory, - "unity-render-splat-viewport", - "local", - pullOnOpen: true) - .GetAwaiter() - .GetResult(); - _clientStatePath = stateBoot.StateFilePath; - return _client; + return AetheriaUnityRuntimeClientProvider.ResolveClient( + AetheriaRuntimeStateBoot.Inspect(AetheriaUnityRuntimePaths.GameDataDirectory), + "unity-render-splat-viewport"); } - private void OnDestroy() - { - DisposeClient(); - } - - private void DisposeClient() - { - _client?.Dispose(); - _client = null; - _clientStatePath = ""; - } } diff --git a/Assets/Scripts/Gameplay/AetheriaUnityRuntimeClientProvider.cs b/Assets/Scripts/Gameplay/AetheriaUnityRuntimeClientProvider.cs index ce8462de7..914d50f59 100644 --- a/Assets/Scripts/Gameplay/AetheriaUnityRuntimeClientProvider.cs +++ b/Assets/Scripts/Gameplay/AetheriaUnityRuntimeClientProvider.cs @@ -42,6 +42,16 @@ public static class AetheriaUnityRuntimeClientProvider return _runtimeClient; } + public static AetheriaClient ResolveClient(AetheriaRuntimeStateBootReport stateBoot, string runtimeId = "") + { + if (stateBoot == null) + throw new ArgumentNullException(nameof(stateBoot)); + + return ResolveClient( + stateBoot.StateFilePath, + string.IsNullOrWhiteSpace(runtimeId) ? stateBoot.RuntimeId : runtimeId); + } + public static AetheriaClient CurrentClientForStateFile(string stateFilePath) { return _runtimeClient != null && diff --git a/Assets/Scripts/Zone Display/VolumeCloudRenderer.cs b/Assets/Scripts/Zone Display/VolumeCloudRenderer.cs index dec5b64a7..ee0a72911 100644 --- a/Assets/Scripts/Zone Display/VolumeCloudRenderer.cs +++ b/Assets/Scripts/Zone Display/VolumeCloudRenderer.cs @@ -1,5 +1,4 @@ using System; -using System.IO; using System.Linq; using System.Collections; using System.Collections.Generic; @@ -54,8 +53,6 @@ public class VolumeCloudRenderer : EffectBase // The index of 4x4 pixels. private int frameIndex = 0; private bool firstFrame = true; - private AetheriaClient _client; - private string _clientStatePath = ""; private AetheriaRuntimePlayerSettingsDocument _playerSettings; [SerializeField] @@ -68,7 +65,7 @@ public class VolumeCloudRenderer : EffectBase } private void OnDestroy() { - DisposeClient(); + _playerSettings = null; if (this.fullBuffer != null) { for (int i = 0; i < fullBuffer.Length; i++) { fullBuffer[i].Release(); @@ -118,30 +115,9 @@ public class VolumeCloudRenderer : EffectBase private AetheriaClient ResolveClient() { - var gameDataDirectory = new DirectoryInfo(Path.Combine(Application.dataPath, "..", "GameData")); - var stateBoot = AetheriaRuntimeStateBoot.Inspect(gameDataDirectory); - if (_client != null && string.Equals(_clientStatePath, stateBoot.StateFilePath, StringComparison.Ordinal)) - return _client; - - DisposeClient(); - _client = AetheriaClient - .OpenLocalAsync( - gameDataDirectory, - "unity-volume-cloud-renderer", - "local", - pullOnOpen: true) - .GetAwaiter() - .GetResult(); - _clientStatePath = stateBoot.StateFilePath; - return _client; - } - - private void DisposeClient() - { - _client?.Dispose(); - _client = null; - _clientStatePath = ""; - _playerSettings = null; + return AetheriaUnityRuntimeClientProvider.ResolveClient( + AetheriaRuntimeStateBoot.Inspect(AetheriaUnityRuntimePaths.GameDataDirectory), + "unity-volume-cloud-renderer"); } [ImageEffectOpaque] diff --git a/Assets/Scripts/Zone Display/ZoneRenderer.cs b/Assets/Scripts/Zone Display/ZoneRenderer.cs index 080840c7d..01bb6fa55 100644 --- a/Assets/Scripts/Zone Display/ZoneRenderer.cs +++ b/Assets/Scripts/Zone Display/ZoneRenderer.cs @@ -5,7 +5,6 @@ using System; using System.Collections; using System.Collections.Generic; -using System.IO; using System.Linq; using Cinemachine; using GameCult.Aetheria.State.Verse; @@ -118,8 +117,6 @@ public class ZoneRenderer : MonoBehaviour Array.Empty(); private IReadOnlyList _zoneRenderBodies = Array.Empty(); - private AetheriaClient _client; - private string _clientStatePath = ""; private AetheriaRuntimeCatalogSnapshot _catalog; public Dictionary WormholeInstances = new Dictionary(); @@ -970,7 +967,7 @@ public class ZoneRenderer : MonoBehaviour private void OnDestroy() { - DisposeClient(); + _catalog = null; } private float GetTerrainHeight(float2 position) @@ -1194,30 +1191,9 @@ public class ZoneRenderer : MonoBehaviour private AetheriaClient ResolveClient() { - var gameDataDirectory = new DirectoryInfo(Path.Combine(Application.dataPath, "..", "GameData")); - var stateBoot = AetheriaRuntimeStateBoot.Inspect(gameDataDirectory); - if (_client != null && string.Equals(_clientStatePath, stateBoot.StateFilePath, StringComparison.Ordinal)) - return _client; - - DisposeClient(); - _client = AetheriaClient - .OpenLocalAsync( - gameDataDirectory, - "unity-zone-renderer", - "local", - pullOnOpen: true) - .GetAwaiter() - .GetResult(); - _clientStatePath = stateBoot.StateFilePath; - return _client; - } - - private void DisposeClient() - { - _client?.Dispose(); - _client = null; - _clientStatePath = ""; - _catalog = null; + return AetheriaUnityRuntimeClientProvider.ResolveClient( + AetheriaRuntimeStateBoot.Inspect(AetheriaUnityRuntimePaths.GameDataDirectory), + "unity-zone-renderer"); } } diff --git a/Packages/org.gamecult.aetheria.eve-runtime/Runtime/AetheriaEveSurfacePresenter.cs b/Packages/org.gamecult.aetheria.eve-runtime/Runtime/AetheriaEveSurfacePresenter.cs index 14681a560..33262db0e 100644 --- a/Packages/org.gamecult.aetheria.eve-runtime/Runtime/AetheriaEveSurfacePresenter.cs +++ b/Packages/org.gamecult.aetheria.eve-runtime/Runtime/AetheriaEveSurfacePresenter.cs @@ -29,8 +29,6 @@ namespace GameCult.Aetheria.EveRuntime private float refreshIntervalSeconds = 0.1f; private UIDocument? _document; - private AetheriaClient? _client; - private string _clientStatePath = ""; private float _nextRefreshTime; private string _mountedStatePath = ""; private string _mountedSurfaceId = ""; @@ -151,20 +149,9 @@ namespace GameCult.Aetheria.EveRuntime private AetheriaClient ResolveClient(string statePath) { - if (_client != null && string.Equals(_clientStatePath, statePath, StringComparison.Ordinal)) - return _client; - - _client?.Dispose(); - _clientStatePath = statePath ?? ""; - _client = AetheriaClient.OpenAsync( - _clientStatePath, - "unity-eve-surface-presenter", - "local", - startServer: false, - pullOnOpen: true) - .GetAwaiter() - .GetResult(); - return _client; + return AetheriaUnityRuntimeClientProvider.ResolveClient( + statePath, + "unity-eve-surface-presenter"); } private UIDocument ResolveDocument() @@ -242,11 +229,5 @@ namespace GameCult.Aetheria.EveRuntime } } - private void OnDisable() - { - _client?.Dispose(); - _client = null; - _clientStatePath = ""; - } } }