diff --git a/Aetheria.State.Verify/Program.cs b/Aetheria.State.Verify/Program.cs index cca78cea2..b49943374 100644 --- a/Aetheria.State.Verify/Program.cs +++ b/Aetheria.State.Verify/Program.cs @@ -11235,17 +11235,14 @@ static void RequireAetheriaRuntimeVerseClientContract(string root) "return _aetheriaState ??= CreateAetheriaState();", "AetheriaRuntimeLoadoutTemplatesDocument", "ProjectStarbridgeSummaryAsync", - "new AetheriaRuntimeManagedClientInputs(", - "catalogDocument.Reactive()", - "loadoutTemplatesDocument.Reactive()", - "starbridgeScenarioDocument.Reactive()", - "starbridgeSessionDocument.Reactive()", - "latestFrameDocument.Reactive()", - "managedInputs.RequireFrame()", - "managedInputs.Catalog", - "managedInputs.LoadoutTemplates.Templates", - "managedInputs.StarbridgeScenario", - "managedInputs.StarbridgeSession", + "AetheriaRuntimeManagedClientInputs? managedInputs = null;", + "managedInputs = new AetheriaRuntimeManagedClientInputs(state);", + "AetheriaRuntimeManagedClientInputs RequireManagedInputs()", + "RequireManagedInputs().RequireFrame()", + "inputs.Catalog", + "inputs.LoadoutTemplates.Templates", + "inputs.StarbridgeScenario", + "inputs.StarbridgeSession", "BootstrapCatalogDocument(", "CatalogBootstrapSource(", "BootstrapRuntimeCatalogSnapshot()", @@ -11272,11 +11269,17 @@ static void RequireAetheriaRuntimeVerseClientContract(string root) var requiredManagedInputSymbols = new[] { "internal sealed class AetheriaRuntimeManagedClientInputs : IDisposable", - "CultMeshReactiveDocument", - "CultMeshReactiveDocument", - "CultMeshReactiveDocument", - "CultMeshReactiveDocument", - "CultMeshReactiveDocument", + "private readonly AetheriaRuntimeDaemonFrameSession _daemonFrame;", + "private readonly AetheriaRuntimeCatalogSession _catalog;", + "private readonly AetheriaRuntimeLoadoutTemplatesSession _loadoutTemplates;", + "private readonly AetheriaRuntimeStarbridgeScenarioSession _starbridgeScenario;", + "private readonly AetheriaRuntimeStarbridgeRunSession _starbridgeSession;", + "public AetheriaRuntimeManagedClientInputs(AetheriaClientState state)", + "_daemonFrame = state.ObserveDaemonFrame();", + "_catalog = state.ObserveCatalog();", + "_loadoutTemplates = state.ObserveLoadoutTemplates();", + "_starbridgeScenario = state.Starbridge.ObserveScenario();", + "_starbridgeSession = state.Starbridge.ObserveSession();", "public AetheriaRuntimeCatalogSnapshot Catalog => _catalog.Current", "public AetheriaRuntimeLoadoutTemplatesDocument LoadoutTemplates => _loadoutTemplates.Current", "public AetheriaRuntimeDaemonFrameDocument RequireFrame()", @@ -11294,6 +11297,18 @@ static void RequireAetheriaRuntimeVerseClientContract(string root) string.Join(", ", missingManagedInputSymbols)); } + if (managedClientInputs.Contains("CultMeshReactiveDocument<", StringComparison.Ordinal) || + managedClientInputs.Contains(".Reactive()", StringComparison.Ordinal) || + client.Contains("catalogDocument.Reactive()", StringComparison.Ordinal) || + client.Contains("loadoutTemplatesDocument.Reactive()", StringComparison.Ordinal) || + client.Contains("starbridgeScenarioDocument.Reactive()", StringComparison.Ordinal) || + client.Contains("starbridgeSessionDocument.Reactive()", StringComparison.Ordinal) || + client.Contains("latestFrameDocument.Reactive()", StringComparison.Ordinal)) + { + throw new InvalidOperationException( + "Aetheria managed client inputs must sample named managed state sessions instead of owning raw reactive CultMesh documents."); + } + if (client.Contains("AetheriaRuntimeReactiveProjectionInputs", StringComparison.Ordinal) || client.Contains("private sealed class AetheriaRuntimeManagedClientInputs", StringComparison.Ordinal) || client.Contains("_projectionInputs", StringComparison.Ordinal) || @@ -11436,7 +11451,7 @@ static void RequireAetheriaRuntimeVerseClientContract(string root) var starbridgeSummaryBlock = indexedDocumentStart > starbridgeSummaryStart ? client.Substring(starbridgeSummaryStart, indexedDocumentStart - starbridgeSummaryStart) : client.Substring(starbridgeSummaryStart); - if (!starbridgeSummaryBlock.Contains("managedInputs.Catalog", StringComparison.Ordinal) || + if (!starbridgeSummaryBlock.Contains("inputs.Catalog", StringComparison.Ordinal) || starbridgeSummaryBlock.Contains("catalogDocument.LatestAsync()", StringComparison.Ordinal) || starbridgeSummaryBlock.Contains("BootstrapRuntimeCatalogSnapshot()", StringComparison.Ordinal) || starbridgeSummaryBlock.Contains("AetheriaRuntimeCatalogStore.OpenReadOnly", StringComparison.Ordinal)) @@ -17442,7 +17457,7 @@ static void RequireInventoryLoadoutRestoreRequestAuthority(string root) !rtsProjection.Contains("AetheriaRuntimeDaemonTradeItemQueries.TryProjectLoadoutTemplatePrice(", StringComparison.Ordinal) || !rtsProjection.Contains("credits >= price", StringComparison.Ordinal) || !clientState.Contains("public CultMeshDocumentHandle LoadoutTemplates", StringComparison.Ordinal) || - !verseClient.Contains("managedInputs.LoadoutTemplates.Templates", StringComparison.Ordinal) || + !verseClient.Contains("inputs.LoadoutTemplates.Templates", StringComparison.Ordinal) || !verseClient.Contains("ProjectStationRefit(", StringComparison.Ordinal)) { throw new InvalidOperationException( diff --git a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeManagedClientInputs.cs b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeManagedClientInputs.cs index bc23ff4a4..f63cf9da7 100644 --- a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeManagedClientInputs.cs +++ b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeManagedClientInputs.cs @@ -1,5 +1,4 @@ using System; -using GameCult.Mesh; #nullable enable @@ -7,24 +6,22 @@ namespace GameCult.Aetheria.State.Verse { internal sealed class AetheriaRuntimeManagedClientInputs : IDisposable { - private readonly CultMeshReactiveDocument _daemonFrame; - private readonly CultMeshReactiveDocument _catalog; - private readonly CultMeshReactiveDocument _loadoutTemplates; - private readonly CultMeshReactiveDocument _starbridgeScenario; - private readonly CultMeshReactiveDocument _starbridgeSession; + private readonly AetheriaRuntimeDaemonFrameSession _daemonFrame; + private readonly AetheriaRuntimeCatalogSession _catalog; + private readonly AetheriaRuntimeLoadoutTemplatesSession _loadoutTemplates; + private readonly AetheriaRuntimeStarbridgeScenarioSession _starbridgeScenario; + private readonly AetheriaRuntimeStarbridgeRunSession _starbridgeSession; - public AetheriaRuntimeManagedClientInputs( - CultMeshReactiveDocument daemonFrame, - CultMeshReactiveDocument catalog, - CultMeshReactiveDocument loadoutTemplates, - CultMeshReactiveDocument starbridgeScenario, - CultMeshReactiveDocument starbridgeSession) + public AetheriaRuntimeManagedClientInputs(AetheriaClientState state) { - _daemonFrame = daemonFrame ?? throw new ArgumentNullException(nameof(daemonFrame)); - _catalog = catalog ?? throw new ArgumentNullException(nameof(catalog)); - _loadoutTemplates = loadoutTemplates ?? throw new ArgumentNullException(nameof(loadoutTemplates)); - _starbridgeScenario = starbridgeScenario ?? throw new ArgumentNullException(nameof(starbridgeScenario)); - _starbridgeSession = starbridgeSession ?? throw new ArgumentNullException(nameof(starbridgeSession)); + if (state == null) + throw new ArgumentNullException(nameof(state)); + + _daemonFrame = state.ObserveDaemonFrame(); + _catalog = state.ObserveCatalog(); + _loadoutTemplates = state.ObserveLoadoutTemplates(); + _starbridgeScenario = state.Starbridge.ObserveScenario(); + _starbridgeSession = state.Starbridge.ObserveSession(); } public AetheriaRuntimeCatalogSnapshot Catalog => _catalog.Current diff --git a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeVerseClient.cs b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeVerseClient.cs index f7bec7a43..0f151f8ce 100644 --- a/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeVerseClient.cs +++ b/Packages/org.gamecult.aetheria.state/Runtime/AetheriaRuntimeVerseClient.cs @@ -546,15 +546,9 @@ namespace GameCult.Aetheria.State.Verse AetheriaRuntimeVerseRecordKeys.StarbridgeSessionLatest); var latestFrameDocument = Document( AetheriaRuntimeVerseRecordKeys.DaemonFrameLatest); - var managedInputs = new AetheriaRuntimeManagedClientInputs( - latestFrameDocument.Reactive(), - catalogDocument.Reactive(), - loadoutTemplatesDocument.Reactive(), - starbridgeScenarioDocument.Reactive(), - starbridgeSessionDocument.Reactive()); - _managedClientInputs = managedInputs; + AetheriaRuntimeManagedClientInputs? managedInputs = null; - return new AetheriaClientState( + var state = new AetheriaClientState( Document( AetheriaRuntimeVerseRecordKeys.DaemonProviderAdvertisement), Document( @@ -656,6 +650,10 @@ namespace GameCult.Aetheria.State.Verse seatId => Document( AetheriaRuntimeVerseRecordKeys.StarbridgePlayerSeat(seatId))); + managedInputs = new AetheriaRuntimeManagedClientInputs(state); + _managedClientInputs = managedInputs; + return state; + CultMeshDocumentHandle ProjectedDocument( string documentId, Func> project, @@ -678,7 +676,7 @@ namespace GameCult.Aetheria.State.Verse return CultMesh.Document( documentId, verse, - async _ => await project(managedInputs.RequireFrame()).ConfigureAwait(false), + async _ => await project(RequireManagedInputs().RequireFrame()).ConfigureAwait(false), _ => frameChanges .SelectAwait(async (frame, cancellationToken) => await project(frame).ConfigureAwait(false)), @@ -686,6 +684,12 @@ namespace GameCult.Aetheria.State.Verse routeHint: new CultMeshRouteHint(CultMeshLocalityKind.SharedMemory, "Aetheria typed projected state")); } + AetheriaRuntimeManagedClientInputs RequireManagedInputs() + { + return managedInputs + ?? throw new InvalidOperationException("Aetheria Verse client managed inputs were sampled before client state was initialized."); + } + CultMeshDocumentHandle BootstrapCatalogDocument( string documentId, Func> bootstrap, @@ -712,20 +716,22 @@ namespace GameCult.Aetheria.State.Verse Task ProjectStationRefitAsync( AetheriaRuntimeDaemonFrameDocument frame) { + var inputs = RequireManagedInputs(); return Task.FromResult(AetheriaRuntimeRtsProjection.ProjectStationRefit( frame, - managedInputs.LoadoutTemplates.Templates, - managedInputs.Catalog)); + inputs.LoadoutTemplates.Templates, + inputs.Catalog)); } Task ProjectStarbridgeSummaryAsync( AetheriaRuntimeDaemonFrameDocument frame) { + var inputs = RequireManagedInputs(); return Task.FromResult(AetheriaRuntimeStarbridgeProjection.ProjectSessionSummary( frame, - managedInputs.StarbridgeScenario, - managedInputs.StarbridgeSession, - managedInputs.Catalog)); + inputs.StarbridgeScenario, + inputs.StarbridgeSession, + inputs.Catalog)); } static string IndexedDocumentId(string prefix, int index)