Route SoA latest view through managed state

This commit is contained in:
Meta Vens 2026-06-28 07:16:21 +01:00
commit 783ea271cc
8 changed files with 69 additions and 62 deletions

View file

@ -83,25 +83,31 @@ static async Task ExportFixtureSetAsync(
if (commands.Count > 0)
WriteArtifact(outputDirectory, manifest, "commands.seeded", AetheriaRuntimeDaemonSchemas.Command + "[]", commands);
var frame = AetheriaRuntimeDaemonFrameStore.ReadFrame(statePath);
await using var node = await AetheriaStateNode
.OpenAsync(statePath, runtimeId: "aetheria-freeze", startServer: false)
.ConfigureAwait(false);
var frame = await node.LatestFrame().ReadAsync().ConfigureAwait(false);
if (frame == null)
throw new InvalidOperationException("Freeze export cannot continue because the daemon latest frame is missing.");
WriteArtifact(outputDirectory, manifest, "daemon-frame.latest", AetheriaRuntimeDaemonSchemas.Frame, frame);
if (AetheriaRuntimeDaemonPublicationStore.TryReadHealth(statePath, out var health))
if (await TryReadAsync<AetheriaRuntimeDaemonHealthDocument>(() => node.Health().ReadAsync()).ConfigureAwait(false) is { } health)
WriteArtifact(outputDirectory, manifest, "daemon-health.latest", AetheriaRuntimeDaemonSchemas.Health, health);
if (AetheriaRuntimeDaemonPublicationStore.TryReadProviderAdvertisement(statePath, out var provider))
if (await TryReadAsync<AetheriaRuntimeDaemonProviderAdvertisementDocument>(() => node.ProviderAdvertisement().ReadAsync()).ConfigureAwait(false) is { } provider)
WriteArtifact(outputDirectory, manifest, "daemon-provider.latest", AetheriaRuntimeDaemonSchemas.ProviderAdvertisement, provider);
if (AetheriaRuntimeDaemonPublicationStore.TryReadCommandBoundary(statePath, out var commandBoundary))
if (await TryReadAsync<AetheriaRuntimeDaemonCommandBoundaryDocument>(() => node.CommandBoundary().ReadAsync()).ConfigureAwait(false) is { } commandBoundary)
WriteArtifact(outputDirectory, manifest, "daemon-command-boundary.latest", AetheriaRuntimeDaemonSchemas.CommandBoundary, commandBoundary);
if (AetheriaRuntimeDaemonPublicationStore.TryReadVerseAuthorityPolicy(statePath, out var authorityPolicy))
if (await TryReadAsync<AetheriaRuntimeVerseAuthorityPolicyDocument>(() => node.VerseAuthorityPolicy().ReadAsync()).ConfigureAwait(false) is { } authorityPolicy)
WriteArtifact(outputDirectory, manifest, "verse-authority-policy.latest", AetheriaRuntimeVerseAuthoritySchemas.Policy, authorityPolicy);
if (AetheriaRuntimeDaemonPublicationStore.TryReadStarbridgeSessionSummary(statePath, out var starbridgeSummary))
if (await TryReadAsync<AetheriaRuntimeStarbridgeSessionSummaryDocument>(() => node.StarbridgeSessionSummary().ReadAsync()).ConfigureAwait(false) is { } starbridgeSummary)
WriteArtifact(outputDirectory, manifest, "starbridge-session-summary.latest", AetheriaRuntimeDaemonSchemas.StarbridgeSessionSummary, starbridgeSummary);
if (AetheriaRuntimeDaemonSoaViewStore.TryReadView(statePath, out var soaView))
if (await TryReadAsync<AetheriaRuntimeDaemonSoaViewDocument>(() => node.LatestSoaView().ReadAsync()).ConfigureAwait(false) is { } soaView)
WriteArtifact(outputDirectory, manifest, "daemon-soa-view.latest", AetheriaRuntimeDaemonSchemas.SoaView, soaView);
var viewport = new AetheriaRuntimeRtsViewportBounds
@ -142,6 +148,19 @@ static void ExportAuthorityDecisionFixtures(string outputDirectory)
WriteJson(Path.Combine(outputDirectory, "manifest.json"), manifest);
}
static async Task<T?> TryReadAsync<T>(Func<Task<T?>> read)
where T : class
{
try
{
return await read().ConfigureAwait(false);
}
catch (KeyNotFoundException)
{
return null;
}
}
static void ExportYmirQueryFixtures(string outputDirectory)
{
Directory.CreateDirectory(outputDirectory);

View file

@ -8675,7 +8675,6 @@ static void RequireDaemonVersePublication(string root)
var daemonFrameStorePath = Path.Combine(root, "Packages", "org.gamecult.aetheria.state", "Runtime", "AetheriaRuntimeDaemonFrameStore.cs");
var daemonPublicationStorePath = Path.Combine(root, "Packages", "org.gamecult.aetheria.state", "Runtime", "AetheriaRuntimeDaemonPublicationStore.cs");
var daemonSoaDocumentsPath = Path.Combine(root, "Packages", "org.gamecult.aetheria.state", "Runtime", "AetheriaRuntimeDaemonSoaDocuments.cs");
var daemonSoaViewStorePath = Path.Combine(root, "Packages", "org.gamecult.aetheria.state", "Runtime", "AetheriaRuntimeDaemonSoaViewStore.cs");
var daemonSoaFramePublisherPath = Path.Combine(root, "Packages", "org.gamecult.aetheria.state", "Runtime", "AetheriaRuntimeDaemonSoaFramePublisher.cs");
var daemonStateRefsPath = Path.Combine(root, "Packages", "org.gamecult.aetheria.state", "Runtime", "AetheriaRuntimeDaemonStateRefs.cs");
var daemonGameSurfaceBuilderPath = Path.Combine(root, "Packages", "org.gamecult.aetheria.state", "Runtime", "AetheriaRuntimeDaemonGameSurfaceBuilder.cs");
@ -8701,7 +8700,6 @@ static void RequireDaemonVersePublication(string root)
daemonFrameStorePath,
daemonPublicationStorePath,
daemonSoaDocumentsPath,
daemonSoaViewStorePath,
daemonSoaFramePublisherPath,
daemonStateRefsPath,
daemonGameSurfaceBuilderPath,
@ -8736,7 +8734,6 @@ static void RequireDaemonVersePublication(string root)
var daemonFrameStore = File.ReadAllText(daemonFrameStorePath);
var daemonPublicationStore = File.ReadAllText(daemonPublicationStorePath);
var daemonSoaDocuments = File.ReadAllText(daemonSoaDocumentsPath);
var daemonSoaViewStore = File.ReadAllText(daemonSoaViewStorePath);
var daemonSoaFramePublisher = File.ReadAllText(daemonSoaFramePublisherPath);
var daemonStateRefs = File.ReadAllText(daemonStateRefsPath);
var daemonGameSurfaceBuilder = File.ReadAllText(daemonGameSurfaceBuilderPath);
@ -8822,7 +8819,7 @@ static void RequireDaemonVersePublication(string root)
var requiredSoaFramePublisherSymbols = new[]
{
"public static class AetheriaRuntimeDaemonSoaFramePublisher",
"PublishCurrentZoneEntities(",
"BuildCurrentZoneEntities(",
"AetheriaRuntimeDaemonSoaBackends.MemoryMappedFile",
"MemoryMappedFile.CreateOrOpen(",
"ObserverWritable = false",
@ -8831,8 +8828,7 @@ static void RequireDaemonVersePublication(string root)
"AetheriaRuntimeDaemonSoaColumnKinds.Velocity",
"AetheriaRuntimeDaemonSoaColumnKinds.PhysicsBodyRadius",
"AetheriaRuntimeDaemonSoaColumnKinds.RenderVisibility",
"AetheriaRuntimeDaemonSoaColumnKinds.RenderGroupId",
"AetheriaRuntimeDaemonSoaViewStore.PublishView(stateFilePath, view)"
"AetheriaRuntimeDaemonSoaColumnKinds.RenderGroupId"
};
var missingSoaFramePublisherSymbols = requiredSoaFramePublisherSymbols
.Where(symbol => !daemonSoaFramePublisher.Contains(symbol, StringComparison.Ordinal))
@ -8930,13 +8926,18 @@ static void RequireDaemonVersePublication(string root)
string.Join(", ", publicationStoreReaderHits));
}
if (daemonFrameStore.Contains("TryReadFrame(", StringComparison.Ordinal) ||
daemonFrameStore.Contains("ReadFrame(", StringComparison.Ordinal) ||
daemonSoaViewStore.Contains("TryReadView(", StringComparison.Ordinal) ||
daemonSoaViewStore.Contains("ReadView(", StringComparison.Ordinal))
var daemonSoaViewStorePath = Path.Combine(root, "Packages", "org.gamecult.aetheria.state", "Runtime", "AetheriaRuntimeDaemonSoaViewStore.cs");
if (File.Exists(daemonSoaViewStorePath))
{
throw new InvalidOperationException(
"Daemon frame/SoA stores still expose file-backed readers; use tick-result documents or AetheriaClient managed observation.");
"Daemon SoA latest-view publication must stay on managed CultMesh pointers; delete AetheriaRuntimeDaemonSoaViewStore.cs instead of reviving sidecar path writes.");
}
if (daemonFrameStore.Contains("TryReadFrame(", StringComparison.Ordinal) ||
daemonFrameStore.Contains("ReadFrame(", StringComparison.Ordinal))
{
throw new InvalidOperationException(
"Daemon frame store still exposes file-backed readers; use tick-result documents or AetheriaClient managed observation.");
}
var requiredDaemonRegistrySymbols = new[]
@ -9111,7 +9112,7 @@ static void RequireDaemonVersePublication(string root)
"VerseId",
"CultMeshAddress",
"AetheriaRuntimeDaemonCommandBoundaryDocument.Create",
"AetheriaRuntimeDaemonSoaFramePublisher.PublishCurrentZoneEntities(stateFilePath, frame)",
"AetheriaRuntimeDaemonSoaFramePublisher.BuildCurrentZoneEntities(stateFilePath, frame)",
"AetheriaRuntimeDaemonProviderAdvertisementDocument.Create",
"AetheriaRuntimeDaemonPublicationStore.PublishCommandBoundary",
"AetheriaRuntimeDaemonPublicationStore.PublishProviderAdvertisement",
@ -9227,7 +9228,7 @@ static void RequireDaemonVersePublication(string root)
? daemonHostSource.Substring(apiPublicationStart, apiPublicationEnd - apiPublicationStart)
: "";
if (apiPublicationBlock.Contains("AetheriaRuntimeDaemonPublicationStore.TryRead", StringComparison.Ordinal) ||
apiPublicationBlock.Contains("AetheriaRuntimeDaemonSoaViewStore.TryRead", StringComparison.Ordinal))
apiPublicationBlock.Contains("SoaViewStore.TryRead", StringComparison.Ordinal))
{
throw new InvalidOperationException(
"Daemon API document publication must use typed tick result documents instead of reopening witness files.");
@ -13857,7 +13858,7 @@ static void RequireRuntimeStateReaderOwnsUnityStateAcquisition(string root)
"FramePath",
"SoaViewPath",
"AetheriaRuntimeDaemonFrameStore.GetFramePath",
"AetheriaRuntimeDaemonSoaViewStore.GetViewPath"
"SoaViewStore.GetViewPath"
};
var observedDaemonStateBypassHits = forbiddenObservedDaemonStateSymbols
.Where(symbol => observedDaemonState.Contains(symbol, StringComparison.Ordinal))

View file

@ -1941,11 +1941,11 @@ public class DaemonRuntimeDocumentTests
}
[Test]
public void SoaViewStorePublishesLatestDaemonView()
public void ManagedLatestSoaViewPublishesLatestDaemonView()
{
var statePath = Path.Combine(
Path.GetTempPath(),
"aetheria-daemon-soa-view-store-tests",
"aetheria-managed-soa-view-tests",
Path.GetRandomFileName(),
"state.cc");
var view = AetheriaRuntimeDaemonSoaViewDocument.Create(
@ -1991,22 +1991,32 @@ public class DaemonRuntimeDocumentTests
}
});
var viewPath = AetheriaRuntimeDaemonSoaViewStore.PublishView(statePath, view);
PublishLatestSoaViewThroughVerseClient(statePath, view);
Assert.AreEqual(AetheriaRuntimeStateBoundary.GetDaemonSoaViewPath(statePath), viewPath);
using var client = AetheriaRuntimeVerseClient
.OpenAsync(statePath, "daemon-soa-store-read-test", startServer: false, pullOnOpen: true)
.GetAwaiter()
.GetResult();
var published = client.LatestSoaView()
.ReadAsync()
.GetAwaiter()
.GetResult();
Assert.IsNotNull(published);
Assert.AreEqual(AetheriaRuntimeDaemonSchemas.SoaView, view.Schema);
Assert.AreEqual("aetheria-daemon", view.DaemonId);
Assert.AreEqual("session-soa-store", view.SessionId);
Assert.AreEqual(123, view.FrameId);
Assert.AreEqual(456, view.Generation);
Assert.IsTrue(view.IsAuthoritative);
Assert.AreEqual(1, view.Buffers.Count);
Assert.AreEqual("entity-hot-0", view.Buffers[0].BufferId);
Assert.IsFalse(view.Buffers[0].ObserverWritable);
Assert.AreEqual(1, view.Columns.Count);
Assert.AreEqual(AetheriaRuntimeDaemonSoaColumnKinds.Heat, view.Columns[0].Kind);
Assert.AreEqual(1, view.DirtyRanges.Count);
Assert.AreEqual(256, view.DirtyRanges[0].Count);
Assert.AreEqual(AetheriaRuntimeDaemonSchemas.SoaView, published.Schema);
Assert.AreEqual("aetheria-daemon", published.DaemonId);
Assert.AreEqual("session-soa-store", published.SessionId);
Assert.AreEqual(123, published.FrameId);
Assert.AreEqual(456, published.Generation);
Assert.IsTrue(published.IsAuthoritative);
Assert.AreEqual(1, published.Buffers.Count);
Assert.AreEqual("entity-hot-0", published.Buffers[0].BufferId);
Assert.IsFalse(published.Buffers[0].ObserverWritable);
Assert.AreEqual(1, published.Columns.Count);
Assert.AreEqual(AetheriaRuntimeDaemonSoaColumnKinds.Heat, published.Columns[0].Kind);
Assert.AreEqual(1, published.DirtyRanges.Count);
Assert.AreEqual(256, published.DirtyRanges[0].Count);
}
[Test]
@ -2072,7 +2082,7 @@ public class DaemonRuntimeDocumentTests
1.0,
0.02);
var view = AetheriaRuntimeDaemonSoaFramePublisher.PublishCurrentZoneEntities(statePath, frame);
var view = AetheriaRuntimeDaemonSoaFramePublisher.BuildCurrentZoneEntities(statePath, frame);
Assert.AreEqual(AetheriaRuntimeDaemonSoaBackends.MemoryMappedFile, view.Backend);
Assert.AreEqual(1, view.Buffers.Count);
Assert.IsFalse(view.Buffers[0].ObserverWritable);

View file

@ -71,7 +71,6 @@
<Compile Include="Packages\org.gamecult.aetheria.state\Runtime\AetheriaRuntimeStateBoot.cs" />
<Compile Include="Packages\org.gamecult.aetheria.state\Runtime\AetheriaRuntimeVerseHostCommands.cs" />
<Compile Include="Packages\org.gamecult.aetheria.state\Runtime\AetheriaRuntimeDaemonSurfaceCommands.cs" />
<Compile Include="Packages\org.gamecult.aetheria.state\Runtime\AetheriaRuntimeDaemonSoaViewStore.cs" />
<Compile Include="Packages\org.gamecult.aetheria.state\Runtime\AetheriaRuntimePlayerSettingsCommands.cs" />
<Compile Include="Packages\org.gamecult.aetheria.state\Runtime\AetheriaControl.cs" />
<Compile Include="Packages\org.gamecult.aetheria.state\Runtime\AetheriaRuntimeDaemonStateRefs.cs" />

View file

@ -24,7 +24,7 @@ namespace GameCult.Aetheria.State.Verse
new Dictionary<string, RetainedMappedBuffer>(StringComparer.Ordinal);
private static long RetainedBufferUseSequence;
public static AetheriaRuntimeDaemonSoaViewDocument PublishCurrentZoneEntities(
public static AetheriaRuntimeDaemonSoaViewDocument BuildCurrentZoneEntities(
string stateFilePath,
AetheriaRuntimeDaemonFrameDocument frame)
{
@ -74,7 +74,6 @@ namespace GameCult.Aetheria.State.Verse
synchronizationMode: AetheriaRuntimeDaemonSoaSynchronizationModes.ImmutableFrame,
renderGroups: CreateRenderGroups(entities));
AetheriaRuntimeDaemonSoaViewStore.PublishView(stateFilePath, view);
return view;
}

View file

@ -1,19 +0,0 @@
#nullable enable
namespace GameCult.Aetheria.State.Verse
{
public static class AetheriaRuntimeDaemonSoaViewStore
{
public static string GetViewPath(string stateFilePath)
{
return AetheriaRuntimeStateBoundary.GetDaemonSoaViewPath(stateFilePath);
}
public static string PublishView(string stateFilePath, AetheriaRuntimeDaemonSoaViewDocument view)
{
var path = GetViewPath(stateFilePath);
AetheriaRuntimeCultCacheDocumentStore.WriteDaemonSoaView(path, view);
return path;
}
}
}

View file

@ -1,2 +0,0 @@
fileFormatVersion: 2
guid: e7b9b2f5fbcc6fd44b0a7984041a6330

View file

@ -210,7 +210,7 @@ namespace GameCult.Aetheria.State.Verse
}
var framePath = AetheriaRuntimeDaemonFrameStore.PublishFrame(stateFilePath, frame);
var soaView = AetheriaRuntimeDaemonSoaFramePublisher.PublishCurrentZoneEntities(stateFilePath, frame);
var soaView = AetheriaRuntimeDaemonSoaFramePublisher.BuildCurrentZoneEntities(stateFilePath, frame);
var commandBoundary = AetheriaRuntimeDaemonCommandBoundaryDocument.Create(options.DaemonId);
var commandBoundaryPath = AetheriaRuntimeDaemonPublicationStore.PublishCommandBoundary(
stateFilePath,