Route daemon reads through managed documents
This commit is contained in:
parent
8a755b9ae3
commit
635bf6bbf0
5 changed files with 156 additions and 9 deletions
|
|
@ -12833,6 +12833,14 @@ static void RequireRuntimeStateReaderOwnsUnityStateAcquisition(string root)
|
|||
var gameplayBootShell = File.Exists(gameplayBootShellPath)
|
||||
? File.ReadAllText(gameplayBootShellPath)
|
||||
: throw new InvalidOperationException("Cannot verify daemon state acquisition; AetheriaUnityGameplayBootShell.cs is missing.");
|
||||
var aetheriaClientPath = Path.Combine(root, "Packages", "org.gamecult.aetheria.state", "Runtime", "AetheriaClient.cs");
|
||||
var aetheriaClient = File.Exists(aetheriaClientPath)
|
||||
? File.ReadAllText(aetheriaClientPath)
|
||||
: throw new InvalidOperationException("Cannot verify daemon state acquisition; AetheriaClient.cs is missing.");
|
||||
var aetheriaClientStatePath = Path.Combine(root, "Packages", "org.gamecult.aetheria.state", "Runtime", "AetheriaClientState.cs");
|
||||
var aetheriaClientState = File.Exists(aetheriaClientStatePath)
|
||||
? File.ReadAllText(aetheriaClientStatePath)
|
||||
: throw new InvalidOperationException("Cannot verify daemon state acquisition; AetheriaClientState.cs is missing.");
|
||||
|
||||
var requiredActionGameManagerSymbols = new[]
|
||||
{
|
||||
|
|
@ -12924,6 +12932,60 @@ static void RequireRuntimeStateReaderOwnsUnityStateAcquisition(string root)
|
|||
"Observed zone-render state acquisition must live behind AetheriaUnityObservedFrameApplier.");
|
||||
}
|
||||
|
||||
var requiredDaemonStateFacadeSymbols = new[]
|
||||
{
|
||||
"public AetheriaClientDaemonState Daemon { get; }",
|
||||
"public sealed class AetheriaClientDaemonState",
|
||||
"CultMeshDocumentHandle<AetheriaRuntimeDaemonProviderAdvertisementDocument> ProviderAdvertisement",
|
||||
"CultMeshDocumentHandle<AetheriaRuntimeDaemonHealthDocument> Health",
|
||||
"CultMeshDocumentHandle<AetheriaRuntimeDaemonCommandBoundaryDocument> CommandBoundary",
|
||||
"CultMeshDocumentHandle<AetheriaRuntimeDaemonFrameDocument> LatestFrame",
|
||||
"CultMeshDocumentHandle<AetheriaRuntimeDaemonSoaViewDocument> LatestSoaView"
|
||||
};
|
||||
var missingDaemonStateFacadeSymbols = requiredDaemonStateFacadeSymbols
|
||||
.Where(symbol => !aetheriaClientState.Contains(symbol, StringComparison.Ordinal))
|
||||
.ToArray();
|
||||
if (missingDaemonStateFacadeSymbols.Length > 0)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"AetheriaClientState must expose daemon service state as managed typed document handles: " +
|
||||
string.Join(", ", missingDaemonStateFacadeSymbols));
|
||||
}
|
||||
|
||||
var requiredDaemonClientFacadeSymbols = new[]
|
||||
{
|
||||
"State.Daemon.LatestFrame.LatestAsync()",
|
||||
"State.Daemon.LatestSoaView.LatestAsync()",
|
||||
"State.Daemon.Health.LatestAsync()"
|
||||
};
|
||||
var missingDaemonClientFacadeSymbols = requiredDaemonClientFacadeSymbols
|
||||
.Where(symbol => !aetheriaClient.Contains(symbol, StringComparison.Ordinal))
|
||||
.ToArray();
|
||||
if (missingDaemonClientFacadeSymbols.Length > 0)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"AetheriaClient daemon compatibility methods must read managed typed state documents: " +
|
||||
string.Join(", ", missingDaemonClientFacadeSymbols));
|
||||
}
|
||||
|
||||
var forbiddenDaemonClientBypassSymbols = new[]
|
||||
{
|
||||
"return _verse.GetObservedDaemonStateAsync();",
|
||||
"return _verse.GetLatestAuthoritativeRunFrameAsync();",
|
||||
"return _verse.GetHealthAsync();",
|
||||
"return _verse.GetLatestSoaViewAsync();",
|
||||
"var frame = await _verse.GetLatestFrameAsync()"
|
||||
};
|
||||
var daemonClientBypassHits = forbiddenDaemonClientBypassSymbols
|
||||
.Where(symbol => aetheriaClient.Contains(symbol, StringComparison.Ordinal))
|
||||
.ToArray();
|
||||
if (daemonClientBypassHits.Length > 0)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"AetheriaClient still bypasses managed daemon documents for compatibility reads: " +
|
||||
string.Join(", ", daemonClientBypassHits));
|
||||
}
|
||||
|
||||
var forbiddenActionGameManagerReaderSymbols = new[]
|
||||
{
|
||||
"AetheriaRuntimeStateReader.ReadPlayerSettings",
|
||||
|
|
|
|||
|
|
@ -215,6 +215,8 @@ public class DaemonRuntimeDocumentTests
|
|||
using var zoneRenderReactive = client.State
|
||||
.Reactive<AetheriaRuntimeZoneRenderDocument>();
|
||||
var legacyCurrentEntity = client.CurrentEntityAsync().GetAwaiter().GetResult();
|
||||
var legacyObserved = client.ObserveAsync().GetAwaiter().GetResult();
|
||||
var legacyAuthoritativeFrame = client.LatestAuthoritativeRunFrameAsync().GetAwaiter().GetResult();
|
||||
var dockingState = client.Aetheria()
|
||||
.DockingState
|
||||
.LatestAsync()
|
||||
|
|
@ -226,6 +228,15 @@ public class DaemonRuntimeDocumentTests
|
|||
Assert.AreSame(client.State.Catalog, client.Document<AetheriaRuntimeCatalogSnapshot>());
|
||||
Assert.AreSame(client.State.ZoneRender, client.Document<AetheriaRuntimeZoneRenderDocument>());
|
||||
Assert.AreSame(client.State.LatestFrame, client.Document<AetheriaRuntimeDaemonFrameDocument>());
|
||||
Assert.AreSame(client.State.Daemon.LatestFrame, client.State.LatestFrame);
|
||||
Assert.AreSame(client.State.Daemon.LatestSoaView, client.State.LatestSoaView);
|
||||
Assert.AreSame(
|
||||
client.State.Daemon.ProviderAdvertisement,
|
||||
client.Document<AetheriaRuntimeDaemonProviderAdvertisementDocument>());
|
||||
Assert.AreSame(client.State.Daemon.Health, client.Document<AetheriaRuntimeDaemonHealthDocument>());
|
||||
Assert.AreSame(
|
||||
client.State.Daemon.CommandBoundary,
|
||||
client.Document<AetheriaRuntimeDaemonCommandBoundaryDocument>());
|
||||
Assert.AreSame(client.State.Settings.Player, client.Document<AetheriaRuntimePlayerSettingsDocument>());
|
||||
Assert.AreSame(client.State.Settings.VerseHost, client.Document<AetheriaRuntimeVerseHostSettingsDocument>());
|
||||
Assert.AreSame(
|
||||
|
|
@ -247,6 +258,8 @@ public class DaemonRuntimeDocumentTests
|
|||
Assert.AreEqual(AetheriaRuntimeDaemonSchemas.Frame, latestFrame.Schema);
|
||||
Assert.AreEqual(frame.FrameId, latestFrame.FrameId);
|
||||
Assert.AreEqual(frame.FrameId, latestFrameByType.FrameId);
|
||||
Assert.AreEqual(frame.FrameId, legacyObserved.Frame.FrameId);
|
||||
Assert.AreEqual(frame.FrameId, legacyAuthoritativeFrame.FrameId);
|
||||
Assert.AreEqual(AetheriaRuntimeCatalogSnapshot.SchemaId, client.State.Catalog.Sources.Last().SchemaId);
|
||||
Assert.GreaterOrEqual(catalog.Items.Count, 0);
|
||||
Assert.AreEqual(AetheriaRuntimePlayerSettingsDocument.SchemaId, playerSettings.Schema);
|
||||
|
|
|
|||
|
|
@ -128,10 +128,25 @@ namespace GameCult.Aetheria.State.Verse
|
|||
pullOnOpen: pullOnOpen);
|
||||
}
|
||||
|
||||
public Task<AetheriaRuntimeObservedDaemonState?> ObserveAsync()
|
||||
public async Task<AetheriaRuntimeObservedDaemonState?> ObserveAsync()
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
return _verse.GetObservedDaemonStateAsync();
|
||||
var frame = await State.Daemon.LatestFrame.LatestAsync().ConfigureAwait(false);
|
||||
if (frame == null)
|
||||
return null;
|
||||
|
||||
var soaView = await State.Daemon.LatestSoaView.LatestAsync().ConfigureAwait(false);
|
||||
if (soaView == null ||
|
||||
!string.Equals(soaView.Schema, AetheriaRuntimeDaemonSchemas.SoaView, StringComparison.Ordinal))
|
||||
{
|
||||
soaView = null;
|
||||
}
|
||||
|
||||
return new AetheriaRuntimeObservedDaemonState(
|
||||
frame,
|
||||
soaView,
|
||||
AetheriaRuntimeDaemonFrameStore.GetFramePath(StatePath),
|
||||
AetheriaRuntimeDaemonSoaViewStore.GetViewPath(StatePath));
|
||||
}
|
||||
|
||||
public AetheriaRuntimeCatalogSnapshot OpenRuntimeCatalog()
|
||||
|
|
@ -170,10 +185,20 @@ namespace GameCult.Aetheria.State.Verse
|
|||
entityKey ?? "");
|
||||
}
|
||||
|
||||
public Task<AetheriaRuntimeDaemonFrameDocument?> LatestAuthoritativeRunFrameAsync()
|
||||
public async Task<AetheriaRuntimeDaemonFrameDocument?> LatestAuthoritativeRunFrameAsync()
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
return _verse.GetLatestAuthoritativeRunFrameAsync();
|
||||
var frame = await State.Daemon.LatestFrame.LatestAsync().ConfigureAwait(false);
|
||||
if (frame == null ||
|
||||
!frame.IsAuthoritative ||
|
||||
frame.Run == null ||
|
||||
frame.Run.Zones == null ||
|
||||
frame.Run.Zones.Count == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
public async Task<AetheriaRuntimeRtsViewportDocument> MapViewportAsync(
|
||||
|
|
@ -291,10 +316,10 @@ namespace GameCult.Aetheria.State.Verse
|
|||
return await State.Details.Inventory(entityIndex).LatestAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public Task<AetheriaRuntimeDaemonHealthDocument?> DaemonHealthAsync()
|
||||
public async Task<AetheriaRuntimeDaemonHealthDocument?> DaemonHealthAsync()
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
return _verse.GetHealthAsync();
|
||||
return await State.Daemon.Health.LatestAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public Task<AetheriaRuntimeVerseAuthorityPolicyDocument?> AuthorityStatusAsync()
|
||||
|
|
@ -308,10 +333,10 @@ namespace GameCult.Aetheria.State.Verse
|
|||
: null);
|
||||
}
|
||||
|
||||
public Task<AetheriaRuntimeDaemonSoaViewDocument?> SoaViewAsync()
|
||||
public async Task<AetheriaRuntimeDaemonSoaViewDocument?> SoaViewAsync()
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
return _verse.GetLatestSoaViewAsync();
|
||||
return await State.Daemon.LatestSoaView.LatestAsync().ConfigureAwait(false);
|
||||
}
|
||||
|
||||
public Task<global::Aetheria.State.Documents.EveSurfaceState?> DaemonGameSurfaceAsync()
|
||||
|
|
@ -451,7 +476,7 @@ namespace GameCult.Aetheria.State.Verse
|
|||
|
||||
private async Task<AetheriaRuntimeDaemonFrameDocument> RequireFrameAsync()
|
||||
{
|
||||
var frame = await _verse.GetLatestFrameAsync().ConfigureAwait(false);
|
||||
var frame = await State.Daemon.LatestFrame.LatestAsync().ConfigureAwait(false);
|
||||
if (frame == null)
|
||||
throw new InvalidOperationException("Aetheria local client has no daemon frame yet.");
|
||||
return frame;
|
||||
|
|
|
|||
|
|
@ -13,6 +13,9 @@ namespace GameCult.Aetheria.State.Verse
|
|||
private readonly CultMeshDocumentCatalog _documents;
|
||||
|
||||
internal AetheriaClientState(
|
||||
CultMeshDocumentHandle<AetheriaRuntimeDaemonProviderAdvertisementDocument> providerAdvertisement,
|
||||
CultMeshDocumentHandle<AetheriaRuntimeDaemonHealthDocument> health,
|
||||
CultMeshDocumentHandle<AetheriaRuntimeDaemonCommandBoundaryDocument> commandBoundary,
|
||||
CultMeshDocumentHandle<AetheriaRuntimeDaemonFrameDocument> latestFrame,
|
||||
CultMeshDocumentHandle<AetheriaRuntimeDaemonSoaViewDocument> latestSoaView,
|
||||
CultMeshDocumentHandle<AetheriaRuntimeCatalogSnapshot> catalog,
|
||||
|
|
@ -38,6 +41,12 @@ namespace GameCult.Aetheria.State.Verse
|
|||
CultMeshDocumentHandle<AetheriaRuntimeStarbridgeSessionSummaryDocument> starbridgeSummary,
|
||||
Func<string, CultMeshDocumentHandle<AetheriaRuntimeStarbridgePlayerSeatDocument>> starbridgePlayerSeat)
|
||||
{
|
||||
Daemon = new AetheriaClientDaemonState(
|
||||
providerAdvertisement,
|
||||
health,
|
||||
commandBoundary,
|
||||
latestFrame,
|
||||
latestSoaView);
|
||||
LatestFrame = latestFrame ?? throw new ArgumentNullException(nameof(latestFrame));
|
||||
LatestSoaView = latestSoaView ?? throw new ArgumentNullException(nameof(latestSoaView));
|
||||
Catalog = catalog ?? throw new ArgumentNullException(nameof(catalog));
|
||||
|
|
@ -64,6 +73,9 @@ namespace GameCult.Aetheria.State.Verse
|
|||
starbridgeSummary,
|
||||
starbridgePlayerSeat);
|
||||
_documents = CultMesh.Documents(
|
||||
Daemon.ProviderAdvertisement,
|
||||
Daemon.Health,
|
||||
Daemon.CommandBoundary,
|
||||
LatestFrame,
|
||||
LatestSoaView,
|
||||
Catalog,
|
||||
|
|
@ -81,6 +93,8 @@ namespace GameCult.Aetheria.State.Verse
|
|||
Starbridge.Session);
|
||||
}
|
||||
|
||||
public AetheriaClientDaemonState Daemon { get; }
|
||||
|
||||
public CultMeshDocumentHandle<AetheriaRuntimeDaemonFrameDocument> LatestFrame { get; }
|
||||
|
||||
public CultMeshDocumentHandle<AetheriaRuntimeDaemonSoaViewDocument> LatestSoaView { get; }
|
||||
|
|
@ -182,6 +196,33 @@ namespace GameCult.Aetheria.State.Verse
|
|||
}
|
||||
}
|
||||
|
||||
public sealed class AetheriaClientDaemonState
|
||||
{
|
||||
internal AetheriaClientDaemonState(
|
||||
CultMeshDocumentHandle<AetheriaRuntimeDaemonProviderAdvertisementDocument> providerAdvertisement,
|
||||
CultMeshDocumentHandle<AetheriaRuntimeDaemonHealthDocument> health,
|
||||
CultMeshDocumentHandle<AetheriaRuntimeDaemonCommandBoundaryDocument> commandBoundary,
|
||||
CultMeshDocumentHandle<AetheriaRuntimeDaemonFrameDocument> latestFrame,
|
||||
CultMeshDocumentHandle<AetheriaRuntimeDaemonSoaViewDocument> latestSoaView)
|
||||
{
|
||||
ProviderAdvertisement = providerAdvertisement ?? throw new ArgumentNullException(nameof(providerAdvertisement));
|
||||
Health = health ?? throw new ArgumentNullException(nameof(health));
|
||||
CommandBoundary = commandBoundary ?? throw new ArgumentNullException(nameof(commandBoundary));
|
||||
LatestFrame = latestFrame ?? throw new ArgumentNullException(nameof(latestFrame));
|
||||
LatestSoaView = latestSoaView ?? throw new ArgumentNullException(nameof(latestSoaView));
|
||||
}
|
||||
|
||||
public CultMeshDocumentHandle<AetheriaRuntimeDaemonProviderAdvertisementDocument> ProviderAdvertisement { get; }
|
||||
|
||||
public CultMeshDocumentHandle<AetheriaRuntimeDaemonHealthDocument> Health { get; }
|
||||
|
||||
public CultMeshDocumentHandle<AetheriaRuntimeDaemonCommandBoundaryDocument> CommandBoundary { get; }
|
||||
|
||||
public CultMeshDocumentHandle<AetheriaRuntimeDaemonFrameDocument> LatestFrame { get; }
|
||||
|
||||
public CultMeshDocumentHandle<AetheriaRuntimeDaemonSoaViewDocument> LatestSoaView { get; }
|
||||
}
|
||||
|
||||
public sealed class AetheriaClientCurrentState
|
||||
{
|
||||
internal AetheriaClientCurrentState(
|
||||
|
|
|
|||
|
|
@ -735,6 +735,12 @@ namespace GameCult.Aetheria.State.Verse
|
|||
CultMesh.ProjectionSource("catalog:aetheria.loadout_templates"));
|
||||
|
||||
return new AetheriaClientState(
|
||||
Document<AetheriaRuntimeDaemonProviderAdvertisementDocument>(
|
||||
AetheriaRuntimeVerseRecordKeys.DaemonProviderAdvertisement),
|
||||
Document<AetheriaRuntimeDaemonHealthDocument>(
|
||||
AetheriaRuntimeVerseRecordKeys.DaemonHealth),
|
||||
Document<AetheriaRuntimeDaemonCommandBoundaryDocument>(
|
||||
AetheriaRuntimeVerseRecordKeys.DaemonCommandBoundary),
|
||||
Document<AetheriaRuntimeDaemonFrameDocument>(
|
||||
AetheriaRuntimeVerseRecordKeys.DaemonFrameLatest),
|
||||
Document<AetheriaRuntimeDaemonSoaViewDocument>(
|
||||
|
|
|
|||
Loading…
Reference in a new issue