Use generic Verse mutable documents

This commit is contained in:
Meta Vens 2026-06-29 00:55:14 +01:00
commit 4a3e5ef457
5 changed files with 71 additions and 103 deletions

View file

@ -11596,11 +11596,7 @@ static void RequireAetheriaRuntimeVerseClientContract(string root)
"AetheriaRuntimeVerseContractRegistry.CreateCultNetRegistry(registry)",
"public Observable<CultNetDatabaseChange<TDocument>> WatchRecord<TDocument>(",
"WatchRecord<AetheriaRuntimeDaemonFrameDocument>",
"CultMeshMutableStatePointer<AetheriaRuntimeDaemonFrameDocument>",
"CultMeshMutableStatePointer<AetheriaRuntimeVerseAuthorityPolicyDocument>",
"CultMeshMutableStatePointer<AetheriaRuntimeStarbridgeScenarioDocument>",
"CultMeshMutableStatePointer<AetheriaRuntimeStarbridgeSessionDocument>",
"CultMeshMutableStatePointer<AetheriaRuntimeStarbridgePlayerSeatDocument>",
"public CultMeshMutableStatePointer<TDocument> MutableDocument<TDocument>(",
"CultMesh.MutableStatePointer(",
"CultMesh.CreateCultCacheDocumentRegistry(RuntimeDocumentTypes)",
"CultMesh.CreateCultNetDocumentRegistry(RuntimeDocumentTypes, registry)",
@ -11612,7 +11608,6 @@ static void RequireAetheriaRuntimeVerseClientContract(string root)
"new CultRecordKey(\"daemon:aetheria.starbridge.session.latest.v1\")",
"Document<AetheriaRuntimeVerseAuthorityPolicyDocument>(",
"typeof(EveSurfaceState)",
"CultMeshMutableStatePointer<EveSurfaceState>",
"private AetheriaClientState? _aetheriaState",
"private AetheriaRuntimeManagedClientInputs? _managedClientInputs",
"_managedClientInputs?.Dispose()",
@ -11676,6 +11671,37 @@ static void RequireAetheriaRuntimeVerseClientContract(string root)
string.Join(", ", survivingNamedWatchHelpers));
}
var forbiddenNamedMutablePointers = new[]
{
"ProviderAdvertisement(",
"Health(",
"CommandBoundary(",
"VerseAuthorityPolicy(",
"LatestFrame(",
"LatestSoaView(",
"StarbridgeScenario(",
"StarbridgeSession(",
"StarbridgePlayerSeat(",
"DaemonGameSurface(",
"DaemonGameTuiSurface(",
"DaemonEditorSurface(",
"DaemonEditorTuiSurface("
};
var runtimeClientInstanceApi = client.Split(
"public AetheriaClientState Aetheria()",
StringSplitOptions.None).Last().Split(
"public CultMeshDocumentHandle<TDocument> Document<TDocument>(",
StringSplitOptions.None)[0];
var survivingNamedMutablePointers = forbiddenNamedMutablePointers
.Where(symbol => runtimeClientInstanceApi.Contains(symbol, StringComparison.Ordinal))
.ToArray();
if (survivingNamedMutablePointers.Length > 0)
{
throw new InvalidOperationException(
"AetheriaRuntimeVerseClient must expose generic MutableDocument<TDocument>(CultRecordKey) instead of named mutable pointer wrappers: " +
string.Join(", ", survivingNamedMutablePointers));
}
var requiredManagedInputSymbols = new[]
{
"internal sealed class AetheriaRuntimeManagedClientInputs : IDisposable",
@ -12016,7 +12042,7 @@ static void RequireAetheriaRuntimeVerseClientContract(string root)
{
"AetheriaRuntimeVerseClient",
"WatchRecord<T>(CultRecordKey)",
"CultMeshMutableStatePointer<T>",
"MutableDocument<T>(CultRecordKey)",
"Unity",
"Verse records",
"EveSurfaceState",

View file

@ -121,7 +121,9 @@ public class DaemonRuntimeDocumentTests
.OpenAsync(statePath, "daemon-frame-read-test", startServer: false, pullOnOpen: true)
.GetAwaiter()
.GetResult();
var published = client.LatestFrame()
var published = client
.MutableDocument<AetheriaRuntimeDaemonFrameDocument>(
AetheriaRuntimeVerseRecordKeys.DaemonFrameLatest)
.ReadAsync()
.GetAwaiter()
.GetResult();
@ -2041,7 +2043,9 @@ public class DaemonRuntimeDocumentTests
.OpenAsync(statePath, "daemon-soa-store-read-test", startServer: false, pullOnOpen: true)
.GetAwaiter()
.GetResult();
var published = client.LatestSoaView()
var published = client
.MutableDocument<AetheriaRuntimeDaemonSoaViewDocument>(
AetheriaRuntimeVerseRecordKeys.DaemonSoaViewLatest)
.ReadAsync()
.GetAwaiter()
.GetResult();
@ -4300,7 +4304,9 @@ public class DaemonRuntimeDocumentTests
.OpenAsync(statePath, "daemon-surface-command-test", startServer: false, pullOnOpen: true)
.GetAwaiter()
.GetResult();
client.LatestFrame()
client
.MutableDocument<AetheriaRuntimeDaemonFrameDocument>(
AetheriaRuntimeVerseRecordKeys.DaemonFrameLatest)
.ReplaceAsync(frame)
.GetAwaiter()
.GetResult();
@ -4317,7 +4323,9 @@ public class DaemonRuntimeDocumentTests
.OpenAsync(statePath, "daemon-soa-view-test", startServer: false, pullOnOpen: true)
.GetAwaiter()
.GetResult();
client.LatestSoaView()
client
.MutableDocument<AetheriaRuntimeDaemonSoaViewDocument>(
AetheriaRuntimeVerseRecordKeys.DaemonSoaViewLatest)
.ReplaceAsync(soaView)
.GetAwaiter()
.GetResult();
@ -4334,19 +4342,27 @@ public class DaemonRuntimeDocumentTests
.OpenAsync(statePath, "daemon-surfaces-test", startServer: false, pullOnOpen: true)
.GetAwaiter()
.GetResult();
client.DaemonGameSurface()
client
.MutableDocument<Aetheria.State.Documents.EveSurfaceState>(
AetheriaRuntimeVerseRecordKeys.DaemonGameSurface)
.ReplaceAsync(ToEveSurfaceState(result.GameSurface))
.GetAwaiter()
.GetResult();
client.DaemonGameTuiSurface()
client
.MutableDocument<Aetheria.State.Documents.EveSurfaceState>(
AetheriaRuntimeVerseRecordKeys.DaemonGameTuiSurface)
.ReplaceAsync(ToEveSurfaceState(result.GameTuiSurface))
.GetAwaiter()
.GetResult();
client.DaemonEditorSurface()
client
.MutableDocument<Aetheria.State.Documents.EveSurfaceState>(
AetheriaRuntimeVerseRecordKeys.DaemonEditorSurface)
.ReplaceAsync(ToEveSurfaceState(result.EditorSurface))
.GetAwaiter()
.GetResult();
client.DaemonEditorTuiSurface()
client
.MutableDocument<Aetheria.State.Documents.EveSurfaceState>(
AetheriaRuntimeVerseRecordKeys.DaemonEditorTuiSurface)
.ReplaceAsync(ToEveSurfaceState(result.EditorTuiSurface))
.GetAwaiter()
.GetResult();
@ -4438,7 +4454,9 @@ public class DaemonRuntimeDocumentTests
.OpenAsync(statePath, "daemon-authority-policy-test", startServer: false, pullOnOpen: true)
.GetAwaiter()
.GetResult();
client.VerseAuthorityPolicy()
client
.MutableDocument<AetheriaRuntimeVerseAuthorityPolicyDocument>(
AetheriaRuntimeVerseRecordKeys.VerseAuthorityPolicy)
.ReplaceAsync(policy)
.GetAwaiter()
.GetResult();

View file

@ -72,7 +72,9 @@ public class StarbridgePlayerSeatDocumentTests
.GetAwaiter()
.GetResult();
client.StarbridgePlayerSeat(seat.SeatId)
client
.MutableDocument<AetheriaRuntimeStarbridgePlayerSeatDocument>(
AetheriaRuntimeVerseRecordKeys.StarbridgePlayerSeat(seat.SeatId))
.ReplaceAsync(seat)
.GetAwaiter()
.GetResult();

View file

@ -206,92 +206,14 @@ namespace GameCult.Aetheria.State.Verse
return _aetheriaState ??= CreateAetheriaState();
}
public CultMeshMutableStatePointer<AetheriaRuntimeDaemonProviderAdvertisementDocument> ProviderAdvertisement()
public CultMeshMutableStatePointer<TDocument> MutableDocument<TDocument>(
CultRecordKey key)
where TDocument : class
{
ThrowIfDisposed();
return MutableDocumentPointer<AetheriaRuntimeDaemonProviderAdvertisementDocument>(
AetheriaRuntimeVerseRecordKeys.DaemonProviderAdvertisement);
}
public CultMeshMutableStatePointer<AetheriaRuntimeDaemonHealthDocument> Health()
{
ThrowIfDisposed();
return MutableDocumentPointer<AetheriaRuntimeDaemonHealthDocument>(
AetheriaRuntimeVerseRecordKeys.DaemonHealth);
}
public CultMeshMutableStatePointer<AetheriaRuntimeDaemonCommandBoundaryDocument> CommandBoundary()
{
ThrowIfDisposed();
return MutableDocumentPointer<AetheriaRuntimeDaemonCommandBoundaryDocument>(
AetheriaRuntimeVerseRecordKeys.DaemonCommandBoundary);
}
public CultMeshMutableStatePointer<AetheriaRuntimeVerseAuthorityPolicyDocument> VerseAuthorityPolicy()
{
ThrowIfDisposed();
return MutableDocumentPointer<AetheriaRuntimeVerseAuthorityPolicyDocument>(
AetheriaRuntimeVerseRecordKeys.VerseAuthorityPolicy);
}
public CultMeshMutableStatePointer<AetheriaRuntimeDaemonFrameDocument> LatestFrame()
{
ThrowIfDisposed();
return MutableDocumentPointer<AetheriaRuntimeDaemonFrameDocument>(
AetheriaRuntimeVerseRecordKeys.DaemonFrameLatest);
}
public CultMeshMutableStatePointer<AetheriaRuntimeDaemonSoaViewDocument> LatestSoaView()
{
ThrowIfDisposed();
return MutableDocumentPointer<AetheriaRuntimeDaemonSoaViewDocument>(
AetheriaRuntimeVerseRecordKeys.DaemonSoaViewLatest);
}
public CultMeshMutableStatePointer<AetheriaRuntimeStarbridgeScenarioDocument> StarbridgeScenario()
{
ThrowIfDisposed();
return MutableDocumentPointer<AetheriaRuntimeStarbridgeScenarioDocument>(
AetheriaRuntimeVerseRecordKeys.StarbridgeScenarioLatest);
}
public CultMeshMutableStatePointer<AetheriaRuntimeStarbridgeSessionDocument> StarbridgeSession()
{
ThrowIfDisposed();
return MutableDocumentPointer<AetheriaRuntimeStarbridgeSessionDocument>(
AetheriaRuntimeVerseRecordKeys.StarbridgeSessionLatest);
}
public CultMeshMutableStatePointer<AetheriaRuntimeStarbridgePlayerSeatDocument> StarbridgePlayerSeat(
string seatId)
{
ThrowIfDisposed();
return MutableDocumentPointer<AetheriaRuntimeStarbridgePlayerSeatDocument>(
AetheriaRuntimeVerseRecordKeys.StarbridgePlayerSeat(seatId));
}
public CultMeshMutableStatePointer<EveSurfaceState> DaemonGameSurface()
{
ThrowIfDisposed();
return MutableDocumentPointer<EveSurfaceState>(AetheriaRuntimeVerseRecordKeys.DaemonGameSurface);
}
public CultMeshMutableStatePointer<EveSurfaceState> DaemonGameTuiSurface()
{
ThrowIfDisposed();
return MutableDocumentPointer<EveSurfaceState>(AetheriaRuntimeVerseRecordKeys.DaemonGameTuiSurface);
}
public CultMeshMutableStatePointer<EveSurfaceState> DaemonEditorSurface()
{
ThrowIfDisposed();
return MutableDocumentPointer<EveSurfaceState>(AetheriaRuntimeVerseRecordKeys.DaemonEditorSurface);
}
public CultMeshMutableStatePointer<EveSurfaceState> DaemonEditorTuiSurface()
{
ThrowIfDisposed();
return MutableDocumentPointer<EveSurfaceState>(AetheriaRuntimeVerseRecordKeys.DaemonEditorTuiSurface);
if (string.IsNullOrWhiteSpace(key.Value))
throw new ArgumentException("Value must be non-empty.", nameof(key));
return MutableDocumentPointer<TDocument>(key);
}
public CultMeshDocumentHandle<TDocument> Document<TDocument>(

View file

@ -31,9 +31,9 @@ registry and exposes:
latest daemon frame, latest SoA view, and daemon game/editor Eve surfaces;
- reactive watches via `WatchRecord<T>(CultRecordKey)`, with record identity
passed as data instead of one watch helper per document lane;
- `CultMeshMutableStatePointer<T>` handles for transparent reactive POCO
- `MutableDocument<T>(CultRecordKey)` handles for transparent reactive POCO
presentation, including read, watch, and replace through shared CultMesh
Verse context semantics;
Verse context semantics, with record identity passed as data;
- typed daemon and Eve command submission through the same command record keys
used by the daemon.