diff --git a/Aetheria.State.Verify/Program.cs b/Aetheria.State.Verify/Program.cs index 1829d473c..63608b90b 100644 --- a/Aetheria.State.Verify/Program.cs +++ b/Aetheria.State.Verify/Program.cs @@ -16283,6 +16283,10 @@ static void RequireRuntimeStateReaderOwnsUnityStateAcquisition(string root) var unityDaemonRenderDocuments = File.Exists(unityDaemonRenderDocumentsPath) ? File.ReadAllText(unityDaemonRenderDocumentsPath) : throw new InvalidOperationException("Cannot verify daemon state acquisition; AetheriaUnityDaemonRenderDocuments.cs is missing."); + var unityRtsViewportDocumentsPath = Path.Combine(root, "Assets", "Scripts", "Gameplay", "AetheriaUnityRtsViewportDocuments.cs"); + var unityRtsViewportDocuments = File.Exists(unityRtsViewportDocumentsPath) + ? File.ReadAllText(unityRtsViewportDocumentsPath) + : throw new InvalidOperationException("Cannot verify daemon state acquisition; AetheriaUnityRtsViewportDocuments.cs is missing."); var zoneRendererPath = Path.Combine(root, "Assets", "Scripts", "Zone Display", "ZoneRenderer.cs"); var zoneRenderer = File.Exists(zoneRendererPath) ? File.ReadAllText(zoneRendererPath) @@ -16543,9 +16547,9 @@ static void RequireRuntimeStateReaderOwnsUnityStateAcquisition(string root) !observedDaemonState.Contains("var currentZoneRender = zoneRender?.Current;", StringComparison.Ordinal) || !observedDaemonState.Contains("new AetheriaRuntimeDaemonRenderView(currentFrame, currentSoaView, currentZoneRender)", 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("private readonly CultMeshReactiveDocument _frame;", StringComparison.Ordinal) || + !unityDaemonRenderDocuments.Contains("private readonly CultMeshReactiveDocument _soaView;", StringComparison.Ordinal) || + !unityDaemonRenderDocuments.Contains("private readonly CultMeshReactiveDocument _zoneRender;", StringComparison.Ordinal) || !unityDaemonRenderDocuments.Contains("public AetheriaRuntimeDaemonRenderView Current", StringComparison.Ordinal) || !unityDaemonRenderDocuments.Contains("AetheriaRuntimeDaemonRenderView.TryCreateCurrent(", StringComparison.Ordinal) || !daemonObserver.Contains("private AetheriaUnityDaemonRenderDocuments _renderDocuments;", StringComparison.Ordinal) || @@ -16556,6 +16560,13 @@ static void RequireRuntimeStateReaderOwnsUnityStateAcquisition(string root) "Observed zone-render state acquisition must sample managed typed zone-render documents directly."); } + if (unityDaemonRenderDocuments.Contains("public CultMeshReactiveDocument<", StringComparison.Ordinal) || + unityRtsViewportDocuments.Contains("public CultMeshReactiveDocument<", StringComparison.Ordinal)) + { + throw new InvalidOperationException( + "Unity managed document holders must not leak raw CultMesh reactive documents through their public surface."); + } + var requiredDaemonStateFacadeSymbols = new[] { "public CultMeshDocumentHandle ProviderAdvertisement { get; }", @@ -16914,9 +16925,9 @@ static void RequireRuntimeStateReaderOwnsUnityStateAcquisition(string root) !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) || + !unityDaemonRenderDocuments.Contains("private readonly CultMeshReactiveDocument _frame;", StringComparison.Ordinal) || + !unityDaemonRenderDocuments.Contains("private readonly CultMeshReactiveDocument _soaView;", StringComparison.Ordinal) || + !unityDaemonRenderDocuments.Contains("private readonly CultMeshReactiveDocument _zoneRender;", StringComparison.Ordinal) || !daemonObserver.Contains("DisposeRenderViewDocuments()", StringComparison.Ordinal)) { throw new InvalidOperationException( diff --git a/Assets/Scripts/Gameplay/AetheriaUnityDaemonRenderDocuments.cs b/Assets/Scripts/Gameplay/AetheriaUnityDaemonRenderDocuments.cs index 4e68122ef..a51d48767 100644 --- a/Assets/Scripts/Gameplay/AetheriaUnityDaemonRenderDocuments.cs +++ b/Assets/Scripts/Gameplay/AetheriaUnityDaemonRenderDocuments.cs @@ -4,20 +4,20 @@ using GameCult.Mesh; public sealed class AetheriaUnityDaemonRenderDocuments : IDisposable { + private readonly CultMeshReactiveDocument _frame; + private readonly CultMeshReactiveDocument _soaView; + private readonly CultMeshReactiveDocument _zoneRender; + private AetheriaUnityDaemonRenderDocuments(AetheriaClientState state) { if (state == null) throw new ArgumentNullException(nameof(state)); - Frame = state.ReactiveDaemonFrame(); - SoaView = state.ReactiveDaemonSoaView(); - ZoneRender = state.ReactiveZoneRender(); + _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; @@ -29,16 +29,16 @@ public sealed class AetheriaUnityDaemonRenderDocuments : IDisposable public bool TryRead(out AetheriaRuntimeDaemonRenderView observed) { return AetheriaRuntimeDaemonRenderView.TryCreateCurrent( - Frame, - SoaView, - ZoneRender, + _frame, + _soaView, + _zoneRender, out observed); } public void Dispose() { - Frame?.Dispose(); - SoaView?.Dispose(); - ZoneRender?.Dispose(); + _frame?.Dispose(); + _soaView?.Dispose(); + _zoneRender?.Dispose(); } } diff --git a/Assets/Scripts/Gameplay/AetheriaUnityRtsViewportDocuments.cs b/Assets/Scripts/Gameplay/AetheriaUnityRtsViewportDocuments.cs index 3d1202a78..67ae88d37 100644 --- a/Assets/Scripts/Gameplay/AetheriaUnityRtsViewportDocuments.cs +++ b/Assets/Scripts/Gameplay/AetheriaUnityRtsViewportDocuments.cs @@ -4,6 +4,10 @@ using GameCult.Mesh; public sealed class AetheriaUnityRtsViewportDocuments : IDisposable { + private readonly CultMeshReactiveDocument _contacts; + private readonly CultMeshReactiveDocument _objectsViewport; + private readonly CultMeshReactiveDocument _renderSplatsViewport; + private AetheriaUnityRtsViewportDocuments( AetheriaClientState state, AetheriaRuntimeRtsViewportBounds viewport, @@ -17,19 +21,16 @@ public sealed class AetheriaUnityRtsViewportDocuments : IDisposable throw new ArgumentNullException(nameof(viewport)); Viewport = viewport; - Contacts = bindContacts ? state.ReactiveZoneContacts() : null; - ObjectsViewport = bindObjects ? state.ReactiveObjectsViewport(viewport) : null; - RenderSplatsViewport = bindRenderSplats ? state.ReactiveRenderSplatsViewport(viewport) : null; + _contacts = bindContacts ? state.ReactiveZoneContacts() : null; + _objectsViewport = bindObjects ? state.ReactiveObjectsViewport(viewport) : null; + _renderSplatsViewport = bindRenderSplats ? state.ReactiveRenderSplatsViewport(viewport) : null; } public AetheriaRuntimeRtsViewportBounds Viewport { get; } - public CultMeshReactiveDocument Contacts { get; } - public CultMeshReactiveDocument ObjectsViewport { get; } - public CultMeshReactiveDocument RenderSplatsViewport { get; } - public AetheriaRuntimeZoneContactsDocument CurrentContacts => Contacts?.Current; - public AetheriaRuntimeObjectsViewportDocument CurrentObjectsViewport => ObjectsViewport?.Current; - public AetheriaRuntimeRenderSplatsViewportDocument CurrentRenderSplatsViewport => RenderSplatsViewport?.Current; + public AetheriaRuntimeZoneContactsDocument CurrentContacts => _contacts?.Current; + public AetheriaRuntimeObjectsViewportDocument CurrentObjectsViewport => _objectsViewport?.Current; + public AetheriaRuntimeRenderSplatsViewportDocument CurrentRenderSplatsViewport => _renderSplatsViewport?.Current; public static AetheriaUnityRtsViewportDocuments OpenMap( AetheriaClientState state, @@ -74,9 +75,9 @@ public sealed class AetheriaUnityRtsViewportDocuments : IDisposable public void Dispose() { - Contacts?.Dispose(); - ObjectsViewport?.Dispose(); - RenderSplatsViewport?.Dispose(); + _contacts?.Dispose(); + _objectsViewport?.Dispose(); + _renderSplatsViewport?.Dispose(); } public static bool SameViewport(