diff --git a/Aetheria.State.Verify/Program.cs b/Aetheria.State.Verify/Program.cs index bbb670b13..8cb0a08f7 100644 --- a/Aetheria.State.Verify/Program.cs +++ b/Aetheria.State.Verify/Program.cs @@ -7594,7 +7594,9 @@ static void RequireAetheriaManagedStateAccessorsCoverDomainDocuments(string root var requiredClientSymbols = new[] { "public AetheriaRuntimeDaemonFrameDocument LatestDaemonFrame()", + "public CultMeshReactiveDocument ReactiveDaemonFrame(", "public AetheriaRuntimeDaemonSoaViewDocument LatestDaemonSoaView()", + "public CultMeshReactiveDocument ReactiveDaemonSoaView(", "public AetheriaClientDockingSnapshot LatestDockingState()", "public AetheriaClientReactiveDockingState ReactiveDockingState(", "public AetheriaRuntimeObservedDaemonState? LatestObservedDaemon()", @@ -7654,6 +7656,13 @@ static void RequireAetheriaManagedStateAccessorsCoverDomainDocuments(string root string.Join(", ", missingObservedSymbols)); } + if (observedDaemonState.Contains("state.LatestFrame.ReactiveAsync", StringComparison.Ordinal) || + observedDaemonState.Contains("state.LatestSoaView.ReactiveAsync", StringComparison.Ordinal)) + { + throw new InvalidOperationException( + "Observed daemon reactive state must delegate through named AetheriaClientState reactive accessors instead of walking raw CultMesh handles."); + } + if (observedDaemonState.Contains("state.LatestDaemonFrameAsync()", StringComparison.Ordinal) || observedDaemonState.Contains("state.LatestDaemonSoaViewAsync()", StringComparison.Ordinal) || observedDaemonState.Contains("state.ReactiveObservedDaemonAsync()", StringComparison.Ordinal) || @@ -14871,8 +14880,8 @@ static void RequireRuntimeStateReaderOwnsUnityStateAcquisition(string root) "AetheriaRuntimeDaemonSoaViewIndex.Build(soaView)", "public sealed class AetheriaRuntimeReactiveObservedDaemonState", "public static async Task CreateAsync(", - "state.LatestFrame.ReactiveAsync(options)", - "state.LatestSoaView.ReactiveAsync(options)", + "state.ReactiveDaemonFrameAsync(options)", + "state.ReactiveDaemonSoaViewAsync(options)", "public bool TryCurrent(out AetheriaRuntimeObservedDaemonState? observed)" }; var missingObservedDaemonStateSymbols = requiredObservedDaemonStateSymbols @@ -14891,7 +14900,9 @@ static void RequireRuntimeStateReaderOwnsUnityStateAcquisition(string root) "FramePath", "SoaViewPath", "AetheriaRuntimeDaemonFrameStore.GetFramePath", - "SoaViewStore.GetViewPath" + "SoaViewStore.GetViewPath", + "state.LatestFrame.ReactiveAsync", + "state.LatestSoaView.ReactiveAsync" }; var observedDaemonStateBypassHits = forbiddenObservedDaemonStateSymbols .Where(symbol => observedDaemonState.Contains(symbol, StringComparison.Ordinal)) @@ -16472,7 +16483,7 @@ static void RequireInventoryLoadoutSaveRequestAuthority(string root) "ProjectLoadoutTemplateAsync(", "AetheriaClientState state", "public sealed class AetheriaRuntimeReactiveLoadoutSnapshotProjector", - "state.Daemon.LatestFrame.ReactiveAsync(options)", + "state.ReactiveDaemonFrameAsync(options)", "public AetheriaRuntimeLoadoutTemplateCommit ProjectLoadoutTemplate(string entityKey)", "ProjectLoadoutTemplate(", "frame.Run ?? new AetheriaRuntimeRunCheckpointCommit()", @@ -16494,6 +16505,13 @@ static void RequireInventoryLoadoutSaveRequestAuthority(string root) "Loadout template save payloads still perform one-shot daemon frame reads instead of using a reactive typed frame document."); } + if (loadoutSnapshotProjector.Contains("state.Daemon.LatestFrame.ReactiveAsync", StringComparison.Ordinal) || + loadoutSnapshotProjector.Contains("state.LatestFrame.ReactiveAsync", StringComparison.Ordinal)) + { + throw new InvalidOperationException( + "Loadout template save payloads must use named AetheriaClientState reactive daemon frame access instead of walking raw CultMesh handles."); + } + var forbiddenActionSymbols = new[] { "AetheriaRuntimeStateCommitLog.QueueLoadoutTemplate", diff --git a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaClientState.cs b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaClientState.cs index b349409f0..aa61dc660 100644 --- a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaClientState.cs +++ b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaClientState.cs @@ -211,6 +211,18 @@ namespace GameCult.Aetheria.State.Verse return LatestDaemonFrameAsync().ConfigureAwait(false).GetAwaiter().GetResult(); } + public Task> ReactiveDaemonFrameAsync( + CultMeshReactiveDocumentOptions? options = null) + { + return LatestFrame.ReactiveAsync(options); + } + + public CultMeshReactiveDocument ReactiveDaemonFrame( + CultMeshReactiveDocumentOptions? options = null) + { + return LatestFrame.Reactive(options); + } + public Task LatestDaemonSoaViewAsync() { return LatestSoaView.LatestAsync(); @@ -221,6 +233,18 @@ namespace GameCult.Aetheria.State.Verse return LatestDaemonSoaViewAsync().ConfigureAwait(false).GetAwaiter().GetResult(); } + public Task> ReactiveDaemonSoaViewAsync( + CultMeshReactiveDocumentOptions? options = null) + { + return LatestSoaView.ReactiveAsync(options); + } + + public CultMeshReactiveDocument ReactiveDaemonSoaView( + CultMeshReactiveDocumentOptions? options = null) + { + return LatestSoaView.Reactive(options); + } + public Task LatestDockingStateAsync() { return DockingState.LatestAsync(); diff --git a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeLoadoutSnapshotProjector.cs b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeLoadoutSnapshotProjector.cs index c50715438..ae180fce8 100644 --- a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeLoadoutSnapshotProjector.cs +++ b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeLoadoutSnapshotProjector.cs @@ -267,7 +267,7 @@ namespace GameCult.Aetheria.State.Verse { if (state == null) throw new ArgumentNullException(nameof(state)); - var frame = await state.Daemon.LatestFrame.ReactiveAsync(options).ConfigureAwait(false); + var frame = await state.ReactiveDaemonFrameAsync(options).ConfigureAwait(false); return new AetheriaRuntimeReactiveLoadoutSnapshotProjector(frame); } diff --git a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeObservedDaemonState.cs b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeObservedDaemonState.cs index 71182d4f9..5872f4e70 100644 --- a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeObservedDaemonState.cs +++ b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeObservedDaemonState.cs @@ -56,7 +56,7 @@ namespace GameCult.Aetheria.State.Verse { if (state == null) throw new ArgumentNullException(nameof(state)); - var frame = await state.LatestFrame.ReactiveAsync(options).ConfigureAwait(false); + var frame = await state.ReactiveDaemonFrameAsync(options).ConfigureAwait(false); var soaView = await TryCreateSoaViewAsync(state, options).ConfigureAwait(false); return new AetheriaRuntimeReactiveObservedDaemonState(frame, soaView); } @@ -106,7 +106,7 @@ namespace GameCult.Aetheria.State.Verse { try { - return await state.LatestSoaView.ReactiveAsync(options).ConfigureAwait(false); + return await state.ReactiveDaemonSoaViewAsync(options).ConfigureAwait(false); } catch (KeyNotFoundException) {