Adapt Aetheria state documents across schema aliases
This commit is contained in:
parent
fb657bea1d
commit
51ccf071e0
3 changed files with 57 additions and 7 deletions
|
|
@ -277,8 +277,10 @@ of transitional `Current*Async()`, `StationRefitAsync()`, `SectorMapAsync()`,
|
|||
also indexes projected state documents by shared document type so callers can
|
||||
retrieve or watch a known typed document with one call while CultMesh owns the
|
||||
bound live feed. The facade also indexes those handles by `CultDocument`
|
||||
schema name/version, so a caller can resolve the shared schema identity even
|
||||
when exact local CLR type identity is not the public contract.
|
||||
schema name/version and can adapt a handle to a different local CLR document
|
||||
type with the same schema identity, so caller code can start treating shared
|
||||
schema identity as the contract even before CultMesh owns alias conversion
|
||||
directly.
|
||||
|
||||
Goal: every client-facing state access becomes a single CultMesh document, collection, query, or pointer call. The caller names the domain state it wants and gets a typed reactive value. It does not manually inspect daemon frames, current-state projections, station rows, record keys, local facade indexes, or transport route details.
|
||||
|
||||
|
|
@ -338,7 +340,7 @@ const refit = await client.aetheria()
|
|||
|
||||
Work:
|
||||
|
||||
- Keep pushing shared CultMesh typed reactive document and collection handles down until type/schema lookup, including safe conversion for schema-compatible CLR aliases, is owned by CultMesh rather than by the Aetheria facade registry.
|
||||
- Keep pushing shared CultMesh typed reactive document and collection handles down until type/schema lookup, including the current Aetheria facade shim for schema-compatible CLR aliases, is owned by CultMesh rather than by the Aetheria facade registry.
|
||||
- Generate Aetheria current/station/zone/catalog accessors from schema metadata.
|
||||
- Move derived-state joins, such as current docking bay from current docking plus station refit plus entity records, into generated/internal query executors.
|
||||
- Replace remaining Unity menu/HUD/render calls to `TryResolve*` and `_observedFacadeIndex` with typed handles or generated/internal render adapters.
|
||||
|
|
@ -349,7 +351,7 @@ Work:
|
|||
Gates:
|
||||
|
||||
- `InventoryMenu`, `InventoryPanel`, `TradeMenu`, `LocalMenu`, `SchematicDisplay`, `SectorRenderer`, `MapRenderer`, and `ZoneRenderer` do not manually join state projections to obtain domain values.
|
||||
- Shared projected documents are reachable through `client.Aetheria().Document<TDocument>()`, `client.Aetheria().DocumentBySchema(schemaVersion)`, `client.Aetheria().LatestAsync<TDocument>()`, and `client.Watch<TDocument>()` as the C# stepping stone toward CultMesh-native type/schema lookup.
|
||||
- Shared projected documents are reachable through `client.Aetheria().Document<TDocument>()`, including same-schema CLR aliases, `client.Aetheria().DocumentBySchema(schemaVersion)`, `client.Aetheria().LatestAsync<TDocument>()`, and `client.Watch<TDocument>()` as the C# stepping stone toward CultMesh-native type/schema lookup.
|
||||
- Client-facing code contains no `_observedFacadeIndex.TryResolve*` outside Unity render adapter internals.
|
||||
- Client-facing code contains no `ResolveClient().Current*Async().GetAwaiter().GetResult()` or equivalent blocking state reads.
|
||||
- `TryGetTypedCurrentDockingBayFacade` and similar transitional helpers are deleted rather than renamed.
|
||||
|
|
|
|||
|
|
@ -604,6 +604,8 @@ Assert-Contains $clientState "TryGetDocument<TDocument>" "Aetheria state facade
|
|||
Assert-Contains $clientState "TryGetDocumentBySchema" "Aetheria state facade must support safe schema document lookup."
|
||||
Assert-Contains $clientState "Document<TDocument>()" "Aetheria state facade must support direct typed document lookup."
|
||||
Assert-Contains $clientState "DocumentBySchema(string schemaVersion)" "Aetheria state facade must support direct schema document lookup."
|
||||
Assert-Contains $clientState "AsSchemaAlias<TAlias>" "Aetheria state facade must adapt same-schema projected documents across CLR aliases until CultMesh owns alias conversion."
|
||||
Assert-Contains $clientState "CultDocumentMessagePackSerialization" "Aetheria projected document aliasing must use the canonical CultCache document serializer."
|
||||
Assert-Contains $clientState "LatestAsync<TDocument>()" "Aetheria state facade must support one-call typed document reads."
|
||||
Assert-Contains $clientState "Watch<TDocument>()" "Aetheria state facade must support reactive typed document lookup."
|
||||
Assert-Contains $clientState "LatestAsync()" "Aetheria state documents must support one-shot typed reads."
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using GameCult.Caching;
|
||||
using GameCult.Caching.MessagePack;
|
||||
using GameCult.Mesh;
|
||||
using R3;
|
||||
|
||||
|
|
@ -44,6 +45,8 @@ namespace GameCult.Aetheria.State.Verse
|
|||
|
||||
public CultMeshLiveFeed<AetheriaRuntimeStateQueryParameters, TDocument> Feed => _feed.Feed;
|
||||
|
||||
internal CultMeshVerseContext Context => _feed.Context;
|
||||
|
||||
public Task<TDocument> LatestAsync()
|
||||
{
|
||||
return _feed.SnapshotAsync(AetheriaRuntimeStateQueryParameters.Empty);
|
||||
|
|
@ -88,6 +91,42 @@ namespace GameCult.Aetheria.State.Verse
|
|||
var verse = CultMesh.Verse("aetheria.local", runtimeId);
|
||||
return new AetheriaRuntimeProjectedDocument<TDocument>(feed.Bind(verse));
|
||||
}
|
||||
|
||||
public AetheriaRuntimeProjectedDocument<TAlias> AsSchemaAlias<TAlias>()
|
||||
{
|
||||
ValidateSchemaAlias(typeof(TDocument), typeof(TAlias));
|
||||
|
||||
TAlias Convert(TDocument document)
|
||||
{
|
||||
if (document is TAlias alreadyTyped)
|
||||
return alreadyTyped;
|
||||
|
||||
var payload = CultDocumentMessagePackSerialization.SerializeUntyped(document!, typeof(TDocument));
|
||||
return (TAlias)CultDocumentMessagePackSerialization.DeserializeUntyped(typeof(TAlias), payload);
|
||||
}
|
||||
|
||||
var feed = new CultMeshLiveFeed<AetheriaRuntimeStateQueryParameters, TAlias>(
|
||||
DocumentId,
|
||||
async (parameters, _context) => Convert(await _feed.SnapshotAsync(parameters).ConfigureAwait(false)),
|
||||
(parameters, _context) => _feed.Watch(parameters).Select(Convert),
|
||||
sources: Sources,
|
||||
routeHint: RouteHint);
|
||||
|
||||
return new AetheriaRuntimeProjectedDocument<TAlias>(feed.Bind(Context));
|
||||
}
|
||||
|
||||
private static void ValidateSchemaAlias(Type sourceType, Type aliasType)
|
||||
{
|
||||
var source = sourceType.GetCustomAttribute<CultDocumentAttribute>();
|
||||
var alias = aliasType.GetCustomAttribute<CultDocumentAttribute>();
|
||||
if (source == null || alias == null ||
|
||||
!string.Equals(source.SchemaName, alias.SchemaName, StringComparison.Ordinal) ||
|
||||
!string.Equals(source.SchemaVersion, alias.SchemaVersion, StringComparison.Ordinal))
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"{aliasType.FullName} cannot alias {sourceType.FullName}; CultDocument schema name/version must match exactly.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public interface IAetheriaRuntimeProjectedDocument
|
||||
|
|
@ -103,6 +142,8 @@ namespace GameCult.Aetheria.State.Verse
|
|||
CultMeshRouteHint RouteHint { get; }
|
||||
|
||||
System.Collections.Generic.IReadOnlyList<CultMeshProjectionSource> Sources { get; }
|
||||
|
||||
AetheriaRuntimeProjectedDocument<TAlias> AsSchemaAlias<TAlias>();
|
||||
}
|
||||
|
||||
public sealed class AetheriaClientState
|
||||
|
|
@ -182,10 +223,15 @@ namespace GameCult.Aetheria.State.Verse
|
|||
|
||||
var schemaVersion = SchemaVersionFor(typeof(TDocument));
|
||||
if (!string.IsNullOrWhiteSpace(schemaVersion) &&
|
||||
_documentsBySchema.TryGetValue(schemaVersion, out var schemaDocument) &&
|
||||
schemaDocument is AetheriaRuntimeProjectedDocument<TDocument> schemaTypedDocument)
|
||||
_documentsBySchema.TryGetValue(schemaVersion, out var schemaDocument))
|
||||
{
|
||||
document = schemaTypedDocument;
|
||||
if (schemaDocument is AetheriaRuntimeProjectedDocument<TDocument> schemaTypedDocument)
|
||||
{
|
||||
document = schemaTypedDocument;
|
||||
return true;
|
||||
}
|
||||
|
||||
document = schemaDocument.AsSchemaAlias<TDocument>();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue