From 09d92e3d90a6c0dfbc66ec3cf604f7e9ece73c7a Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Mon, 29 Jun 2026 12:45:03 +0100 Subject: [PATCH] Expose native daemon render document handle --- Aetheria.State.Verify/Program.cs | 53 +++++++++++++------ .../Gameplay/AetheriaDaemonObserver.cs | 38 +++---------- .../AetheriaUnityDaemonRenderDocuments.cs | 44 +++++++++++++++ ...AetheriaUnityDaemonRenderDocuments.cs.meta | 2 + .../AetheriaUnityRuntimeClientProvider.cs | 30 +++++++++-- 5 files changed, 115 insertions(+), 52 deletions(-) create mode 100644 Assets/Scripts/Gameplay/AetheriaUnityDaemonRenderDocuments.cs create mode 100644 Assets/Scripts/Gameplay/AetheriaUnityDaemonRenderDocuments.cs.meta diff --git a/Aetheria.State.Verify/Program.cs b/Aetheria.State.Verify/Program.cs index 0d373e7af..56e8591c1 100644 --- a/Aetheria.State.Verify/Program.cs +++ b/Aetheria.State.Verify/Program.cs @@ -16319,6 +16319,10 @@ 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 unityDaemonRenderDocumentsPath = Path.Combine(root, "Assets", "Scripts", "Gameplay", "AetheriaUnityDaemonRenderDocuments.cs"); + var unityDaemonRenderDocuments = File.Exists(unityDaemonRenderDocumentsPath) + ? File.ReadAllText(unityDaemonRenderDocumentsPath) + : throw new InvalidOperationException("Cannot verify daemon state acquisition; AetheriaUnityDaemonRenderDocuments.cs is missing."); var zoneRendererPath = Path.Combine(root, "Assets", "Scripts", "Zone Display", "ZoneRenderer.cs"); var zoneRenderer = File.Exists(zoneRendererPath) ? File.ReadAllText(zoneRendererPath) @@ -16466,13 +16470,17 @@ static void RequireRuntimeStateReaderOwnsUnityStateAcquisition(string root) "public static AetheriaRuntimeCurrentEntityDocument CurrentEntityState(string runtimeId = \"\")", "public static AetheriaRuntimeCurrentZoneDocument CurrentZoneState(string runtimeId = \"\")", "public static AetheriaRuntimeZoneContactsDocument CurrentZoneContacts(string runtimeId = \"\")", + "public static CultMeshReactiveDocument ReactiveZoneContacts(", "public static AetheriaRuntimeStationRefitDocument CurrentStationRefit(string runtimeId = \"\")", "public static AetheriaRuntimeSectorMapDocument CurrentSectorMap(string runtimeId = \"\")", "public static AetheriaRuntimeSectorMapDocument CurrentSectorMap(", "public static AetheriaRuntimeZoneDetailsDocument CurrentZoneDetails(int zoneIndex, string runtimeId = \"\")", "public static AetheriaRuntimeInventoryDocument CurrentInventory(int entityIndex, string runtimeId = \"\")", + "public static CultMeshReactiveDocument ReactiveObjectsViewport(", + "public static CultMeshReactiveDocument ReactiveRenderSplatsViewport(", "public static AetheriaRuntimeDaemonFrameDocument CurrentDaemonFrame(string runtimeId = \"\")", "public static AetheriaRuntimeDaemonFrameDocument CurrentDaemonFrame(", + "public static AetheriaUnityDaemonRenderDocuments DaemonRenderDocuments(", "public static AetheriaRuntimeVerseHostSettingsDocument CurrentVerseHostSettings(", "public static AetheriaControl Control(string runtimeId = \"\")", "public static AetheriaUi Ui(string runtimeId = \"\")", @@ -16500,7 +16508,6 @@ static void RequireRuntimeStateReaderOwnsUnityStateAcquisition(string root) } if (runtimeClientProvider.Contains("public static CultMeshReactiveDocument Reactive", StringComparison.Ordinal) || - runtimeClientProvider.Contains("public static CultMeshReactiveDocument ReactiveEveSurface(", StringComparison.Ordinal) || runtimeClientProvider.Contains("private static CultMeshReactiveDocument _playerSettingsDocument", StringComparison.Ordinal) || runtimeClientProvider.Contains("RuntimeState().ReactivePlayerSettingsDocument()", StringComparison.Ordinal) || @@ -16508,7 +16515,7 @@ static void RequireRuntimeStateReaderOwnsUnityStateAcquisition(string root) runtimeClientProvider.Contains("_playerSettingsDocument?.Dispose()", StringComparison.Ordinal)) { throw new InvalidOperationException( - "AetheriaUnityRuntimeClientProvider should expose RuntimeState/Control/Ui and read named current typed state for cached settings; do not rebuild static ReactiveX facade wrappers."); + "AetheriaUnityRuntimeClientProvider should expose named current/reactive typed handles; do not rebuild generic static ReactiveX facade wrappers or cached reactive state."); } if (runtimeClientProvider.Contains("AetheriaRuntimePlayerSettingsSession _playerSettingsDocument", StringComparison.Ordinal) || @@ -16572,10 +16579,15 @@ static void RequireRuntimeStateReaderOwnsUnityStateAcquisition(string root) !observedDaemonState.Contains("CultMeshReactiveDocument zoneRender", StringComparison.Ordinal) || !observedDaemonState.Contains("var currentZoneRender = zoneRender?.Current;", StringComparison.Ordinal) || !observedDaemonState.Contains("new AetheriaRuntimeDaemonRenderView(currentFrame, currentSoaView, currentZoneRender)", StringComparison.Ordinal) || - !daemonObserver.Contains("private CultMeshReactiveDocument _daemonFrame;", StringComparison.Ordinal) || - !daemonObserver.Contains("private CultMeshReactiveDocument _daemonSoaView;", StringComparison.Ordinal) || - !daemonObserver.Contains("private CultMeshReactiveDocument _zoneRender;", StringComparison.Ordinal) || - !daemonObserver.Contains("AetheriaRuntimeDaemonRenderView.TryCreateCurrent(", StringComparison.Ordinal)) + !unityDaemonRenderDocuments.Contains("public sealed class AetheriaUnityDaemonRenderDocuments : IDisposable", StringComparison.Ordinal) || + !unityDaemonRenderDocuments.Contains("public CultMeshReactiveDocument Frame { get; }", StringComparison.Ordinal) || + !unityDaemonRenderDocuments.Contains("public CultMeshReactiveDocument SoaView { get; }", StringComparison.Ordinal) || + !unityDaemonRenderDocuments.Contains("public CultMeshReactiveDocument ZoneRender { get; }", StringComparison.Ordinal) || + !unityDaemonRenderDocuments.Contains("public AetheriaRuntimeDaemonRenderView Current", StringComparison.Ordinal) || + !unityDaemonRenderDocuments.Contains("AetheriaRuntimeDaemonRenderView.TryCreateCurrent(", StringComparison.Ordinal) || + !daemonObserver.Contains("private AetheriaUnityDaemonRenderDocuments _renderDocuments;", StringComparison.Ordinal) || + !daemonObserver.Contains("_renderDocuments?.Current", StringComparison.Ordinal) || + !daemonObserver.Contains("AetheriaUnityRuntimeClientProvider.DaemonRenderDocuments(stateBoot, clientId)", StringComparison.Ordinal)) { throw new InvalidOperationException( "Observed zone-render state acquisition must sample managed typed zone-render documents directly."); @@ -16933,27 +16945,34 @@ static void RequireRuntimeStateReaderOwnsUnityStateAcquisition(string root) string.Join(", ", actionGameManagerReaderHits)); } - if (!daemonObserver.Contains("AetheriaClientState ResolveState()", StringComparison.Ordinal) || - !daemonObserver.Contains("AetheriaUnityRuntimeClientProvider.RuntimeState(stateBoot, clientId)", StringComparison.Ordinal) || - !daemonObserver.Contains("AetheriaRuntimeStateBoot.Inspect(AetheriaUnityRuntimePaths.GameDataDirectory)", StringComparison.Ordinal) || + if (!daemonObserver.Contains("AetheriaRuntimeStateBoot.Inspect(AetheriaUnityRuntimePaths.GameDataDirectory)", StringComparison.Ordinal) || !daemonObserver.Contains("AetheriaRuntimeDaemonRenderView", StringComparison.Ordinal) || - !daemonObserver.Contains("CultMeshReactiveDocument _daemonFrame", StringComparison.Ordinal) || - !daemonObserver.Contains("CultMeshReactiveDocument _daemonSoaView", StringComparison.Ordinal) || - !daemonObserver.Contains("CultMeshReactiveDocument _zoneRender", StringComparison.Ordinal) || - !daemonObserver.Contains("_daemonFrame ??= state.ReactiveDaemonFrame();", StringComparison.Ordinal) || - !daemonObserver.Contains("_daemonSoaView ??= state.ReactiveDaemonSoaView();", StringComparison.Ordinal) || - !daemonObserver.Contains("_zoneRender ??= state.ReactiveZoneRender();", StringComparison.Ordinal) || - !daemonObserver.Contains("AetheriaRuntimeDaemonRenderView.TryCreateCurrent(", StringComparison.Ordinal) || + !daemonObserver.Contains("private AetheriaUnityDaemonRenderDocuments _renderDocuments;", StringComparison.Ordinal) || + !daemonObserver.Contains("_renderDocuments?.Current", StringComparison.Ordinal) || + !daemonObserver.Contains("AetheriaUnityRuntimeClientProvider.DaemonRenderDocuments(stateBoot, clientId)", StringComparison.Ordinal) || + !unityDaemonRenderDocuments.Contains("public AetheriaRuntimeDaemonRenderView Current", StringComparison.Ordinal) || + !unityDaemonRenderDocuments.Contains("public CultMeshReactiveDocument Frame { get; }", StringComparison.Ordinal) || + !unityDaemonRenderDocuments.Contains("public CultMeshReactiveDocument SoaView { get; }", StringComparison.Ordinal) || + !unityDaemonRenderDocuments.Contains("public CultMeshReactiveDocument ZoneRender { get; }", StringComparison.Ordinal) || !daemonObserver.Contains("DisposeRenderViewDocuments()", StringComparison.Ordinal)) { throw new InvalidOperationException( - "AetheriaDaemonObserver must sample daemon render views through direct managed reactive daemon documents."); + "AetheriaDaemonObserver must hold a native managed daemon-render document handle and read its current state."); } if (daemonObserver.Contains("AetheriaRuntimeStateReader.TryReadDaemonRenderView", StringComparison.Ordinal) || daemonObserver.Contains("public AetheriaClient Client", StringComparison.Ordinal) || daemonObserver.Contains("public AetheriaControl Control", StringComparison.Ordinal) || daemonObserver.Contains("AetheriaUnityRuntimeClientProvider.ResolveClient(", StringComparison.Ordinal) || + daemonObserver.Contains("AetheriaClientState ResolveState()", StringComparison.Ordinal) || + daemonObserver.Contains("AetheriaUnityRuntimeClientProvider.RuntimeState(stateBoot, clientId)", StringComparison.Ordinal) || + daemonObserver.Contains("CultMeshReactiveDocument _daemonFrame", StringComparison.Ordinal) || + daemonObserver.Contains("CultMeshReactiveDocument _daemonSoaView", StringComparison.Ordinal) || + daemonObserver.Contains("CultMeshReactiveDocument _zoneRender", StringComparison.Ordinal) || + daemonObserver.Contains("_daemonFrame ??= state.ReactiveDaemonFrame();", StringComparison.Ordinal) || + daemonObserver.Contains("_daemonSoaView ??= state.ReactiveDaemonSoaView();", StringComparison.Ordinal) || + daemonObserver.Contains("_zoneRender ??= state.ReactiveZoneRender();", StringComparison.Ordinal) || + daemonObserver.Contains("AetheriaRuntimeDaemonRenderView.TryCreateCurrent(", StringComparison.Ordinal) || daemonObserver.Contains("ResolveClient()?.State", StringComparison.Ordinal) || daemonObserver.Contains(".ReadAsync(client.State)", StringComparison.Ordinal) || daemonObserver.Contains("AetheriaRuntimeReactiveObservedDaemonState", StringComparison.Ordinal) || diff --git a/Assets/Scripts/Gameplay/AetheriaDaemonObserver.cs b/Assets/Scripts/Gameplay/AetheriaDaemonObserver.cs index 61e0a2488..786bceee9 100644 --- a/Assets/Scripts/Gameplay/AetheriaDaemonObserver.cs +++ b/Assets/Scripts/Gameplay/AetheriaDaemonObserver.cs @@ -1,6 +1,5 @@ using System; using GameCult.Aetheria.State.Verse; -using GameCult.Mesh; using UnityEngine; public sealed class AetheriaDaemonObserver : MonoBehaviour @@ -21,9 +20,7 @@ public sealed class AetheriaDaemonObserver : MonoBehaviour private float _nextPollTime; private AetheriaDaemonSoaMemoryMap _soaMemoryMap; private AetheriaDaemonRenderNativeView _renderNativeView; - private CultMeshReactiveDocument _daemonFrame; - private CultMeshReactiveDocument _daemonSoaView; - private CultMeshReactiveDocument _zoneRender; + private AetheriaUnityDaemonRenderDocuments _renderDocuments; public AetheriaRuntimeDaemonRenderView LastRenderView { get; private set; } public AetheriaRuntimeDaemonObservationResult LastObservation { get; private set; } @@ -102,13 +99,7 @@ public sealed class AetheriaDaemonObserver : MonoBehaviour try { EnsureRenderViewDocuments(); - return AetheriaRuntimeDaemonRenderView.TryCreateCurrent( - _daemonFrame, - _daemonSoaView, - _zoneRender, - out var observed) - ? observed - : null; + return _renderDocuments?.Current; } catch { @@ -118,24 +109,11 @@ public sealed class AetheriaDaemonObserver : MonoBehaviour private void EnsureRenderViewDocuments() { - if (_daemonFrame != null && _daemonSoaView != null && _zoneRender != null) + if (_renderDocuments != null) { return; } - var state = ResolveState(); - if (state == null) - { - return; - } - - _daemonFrame ??= state.ReactiveDaemonFrame(); - _daemonSoaView ??= state.ReactiveDaemonSoaView(); - _zoneRender ??= state.ReactiveZoneRender(); - } - - private AetheriaClientState ResolveState() - { var stateBoot = AetheriaRuntimeStateBoot.Inspect(AetheriaUnityRuntimePaths.GameDataDirectory); if (!stateBoot.SupportsLocalStateFileRead || !stateBoot.StateFileExists) { @@ -143,7 +121,7 @@ public sealed class AetheriaDaemonObserver : MonoBehaviour $"Aetheria daemon observer requires a readable local Verse state file: {stateBoot.FailureMessage}"); } - return AetheriaUnityRuntimeClientProvider.RuntimeState(stateBoot, clientId); + _renderDocuments = AetheriaUnityRuntimeClientProvider.DaemonRenderDocuments(stateBoot, clientId); } private void RemapSoaView(AetheriaRuntimeDaemonRenderView observed) @@ -184,11 +162,7 @@ public sealed class AetheriaDaemonObserver : MonoBehaviour private void DisposeRenderViewDocuments() { - _daemonFrame?.Dispose(); - _daemonFrame = null; - _daemonSoaView?.Dispose(); - _daemonSoaView = null; - _zoneRender?.Dispose(); - _zoneRender = null; + _renderDocuments?.Dispose(); + _renderDocuments = null; } } diff --git a/Assets/Scripts/Gameplay/AetheriaUnityDaemonRenderDocuments.cs b/Assets/Scripts/Gameplay/AetheriaUnityDaemonRenderDocuments.cs new file mode 100644 index 000000000..4e68122ef --- /dev/null +++ b/Assets/Scripts/Gameplay/AetheriaUnityDaemonRenderDocuments.cs @@ -0,0 +1,44 @@ +using System; +using GameCult.Aetheria.State.Verse; +using GameCult.Mesh; + +public sealed class AetheriaUnityDaemonRenderDocuments : IDisposable +{ + private AetheriaUnityDaemonRenderDocuments(AetheriaClientState state) + { + if (state == null) + throw new ArgumentNullException(nameof(state)); + + Frame = state.ReactiveDaemonFrame(); + SoaView = state.ReactiveDaemonSoaView(); + ZoneRender = state.ReactiveZoneRender(); + } + + public CultMeshReactiveDocument Frame { get; } + public CultMeshReactiveDocument SoaView { get; } + public CultMeshReactiveDocument ZoneRender { get; } + + public AetheriaRuntimeDaemonRenderView Current => + TryRead(out var observed) ? observed : null; + + public static AetheriaUnityDaemonRenderDocuments Open(AetheriaClientState state) + { + return new AetheriaUnityDaemonRenderDocuments(state); + } + + public bool TryRead(out AetheriaRuntimeDaemonRenderView observed) + { + return AetheriaRuntimeDaemonRenderView.TryCreateCurrent( + Frame, + SoaView, + ZoneRender, + out observed); + } + + public void Dispose() + { + Frame?.Dispose(); + SoaView?.Dispose(); + ZoneRender?.Dispose(); + } +} diff --git a/Assets/Scripts/Gameplay/AetheriaUnityDaemonRenderDocuments.cs.meta b/Assets/Scripts/Gameplay/AetheriaUnityDaemonRenderDocuments.cs.meta new file mode 100644 index 000000000..2a21af8fa --- /dev/null +++ b/Assets/Scripts/Gameplay/AetheriaUnityDaemonRenderDocuments.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: a5bd499492bebfb439338bc5283f6a23 \ No newline at end of file diff --git a/Assets/Scripts/Gameplay/AetheriaUnityRuntimeClientProvider.cs b/Assets/Scripts/Gameplay/AetheriaUnityRuntimeClientProvider.cs index 2b74d0642..0adb91a34 100644 --- a/Assets/Scripts/Gameplay/AetheriaUnityRuntimeClientProvider.cs +++ b/Assets/Scripts/Gameplay/AetheriaUnityRuntimeClientProvider.cs @@ -48,9 +48,6 @@ public static class AetheriaUnityRuntimeClientProvider private 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); @@ -131,6 +128,12 @@ public static class AetheriaUnityRuntimeClientProvider return RuntimeState(runtimeId).CurrentZoneContacts(); } + public static CultMeshReactiveDocument ReactiveZoneContacts( + string runtimeId = "") + { + return RuntimeState(runtimeId).ReactiveZoneContacts(); + } + public static AetheriaRuntimeStationRefitDocument CurrentStationRefit(string runtimeId = "") { return RuntimeState(runtimeId).CurrentStationRefit(); @@ -158,6 +161,20 @@ public static class AetheriaUnityRuntimeClientProvider return RuntimeState(runtimeId).CurrentInventory(entityIndex); } + public static CultMeshReactiveDocument ReactiveObjectsViewport( + AetheriaRuntimeRtsViewportBounds viewport, + string runtimeId = "") + { + return RuntimeState(runtimeId).ReactiveObjectsViewport(viewport); + } + + public static CultMeshReactiveDocument ReactiveRenderSplatsViewport( + AetheriaRuntimeRtsViewportBounds viewport, + string runtimeId = "") + { + return RuntimeState(runtimeId).ReactiveRenderSplatsViewport(viewport); + } + public static AetheriaRuntimeDaemonFrameDocument CurrentDaemonFrame(string runtimeId = "") { return RuntimeState(runtimeId).CurrentDaemonFrame(); @@ -170,6 +187,13 @@ public static class AetheriaUnityRuntimeClientProvider return RuntimeState(stateBoot, runtimeId).CurrentDaemonFrame(); } + public static AetheriaUnityDaemonRenderDocuments DaemonRenderDocuments( + AetheriaRuntimeStateBootReport stateBoot, + string runtimeId = "") + { + return AetheriaUnityDaemonRenderDocuments.Open(RuntimeState(stateBoot, runtimeId)); + } + public static AetheriaRuntimeVerseHostSettingsDocument CurrentVerseHostSettings( AetheriaRuntimeStateBootReport stateBoot, string runtimeId = "")