Add Unity playable world runtime host

This commit is contained in:
Meta Vens 2026-07-09 19:09:26 +01:00
commit be503940fa
11 changed files with 332 additions and 12 deletions

View file

@ -627,6 +627,10 @@ Recently cut:
command receipts through `IEveUnitySceneCommandReceiptSource`: pending
receipts remain status only, while accepted or reconciled receipts refresh
from the provider surface source instead of moving entities locally.
`EveUnityPlayableWorldRuntime` now owns the generic Unity playable-world
composition point: provider surface documents, provider asset manifest
documents, command sink, optional receipt source, asset manifest cache,
presenter, and scene sink are wired without Aetheria imports.
`EveUnityPlayableWorldPresenter` now maps provider-authored entity rows and
asset refs into scene sink operations, including removal of entities absent
from later provider snapshots, without importing Aetheria entity/prefab
@ -643,7 +647,9 @@ Recently cut:
`gamecult.eve.unity_playable_world_asset_manifest.v1` and
`EveUnityPlayableWorldAssetManifestDocumentSource` now define the typed
manifest document loading boundary and feed that cache without importing
Aetheria asset classes. The Unity client boundary is generic before it learns
Aetheria asset classes. `EveUnityLivePlayableWorldAssetProvider` connects
that cache to the active world pointer for GameObject scenes. The Unity
client boundary is generic before it learns
live transport. The next blocker is the live generic Unity player loop:
implement the CultMesh/CultNet adapter, implement concrete CultMesh/CultCache
readers for provider surface and asset manifest documents, and prove

View file

@ -495,6 +495,12 @@ now also declares
provider connection with `EveUnityPlayableWorldPresenter`, applies every live
snapshot to the scene sink, and delegates player intent back to the advertised
provider command boundary. The runtime now also declares
`playableWorldRuntimeHost`: `EveUnityPlayableWorldRuntime` composes provider
surface documents, provider asset manifest documents, command sink, optional
receipt source, asset manifest cache, presenter, and scene sink into one generic
Unity playable-world client. `EveUnityLivePlayableWorldAssetProvider` lets a
GameObject scene resolve prefabs through the active world's provider manifest
without importing provider prefab classes. The runtime now also declares
`providerCommandReceipts`: `IEveUnitySceneCommandReceiptSource` and
`EveUnitySceneCommandReceipt` keep provider-owned pending/accepted/denied/
reconciled command status distinct from scene state; accepted or reconciled

View file

@ -177,6 +177,10 @@ local world truth, and `IEveUnitySceneCommandReceiptSource` reports provider
receipts as derived command status. Pending receipts do not move the scene;
accepted or reconciled receipts only trigger a refresh from the provider surface
source, so the next presentation still comes from daemon-authored state.
`EveUnityPlayableWorldRuntime` is the generic runtime composition entry point:
it wires provider surface documents, provider asset manifest documents, command
sink, optional receipt source, asset manifest cache, presenter, and scene sink
into one Unity playable-world client without importing provider code.
`EveUnityPlayableWorldPresenter` maps the provider-authored entity rows and
asset refs into scene operations through `IEveUnityPlayableWorldSceneSink` and
`IEveUnityPlayableWorldAssetResolver`, including removal of entities that
@ -193,16 +197,17 @@ through data rather than Aetheria code. `gamecult.eve.unity_playable_world_asset
loading boundary for those Unity load keys. `IEveUnityPlayableWorldAssetManifestSource`
and `EveUnityPlayableWorldAssetManifestCache` key live manifest updates by the
`playableWorld.AssetManifest` pointer, so a CultMesh/CultCache source can update
Unity asset bindings without changing the lowerer. Aetheria-specific names
appear only as provider-authored data and command ids; the Unity client code
does not import Aetheria runtime types, prefab classes, or apply movement
Unity asset bindings without changing the lowerer. `EveUnityLivePlayableWorldAssetProvider`
connects that cache to the active world pointer for GameObject scenes. Aetheria-specific
names appear only as provider-authored data and command ids; the Unity client
code does not import Aetheria runtime types, prefab classes, or apply movement
locally.
This is not yet the final playable client. The remaining cut is a live
CultMesh/CultNet provider subscription adapter implementing those document and
command ports, concrete CultMesh/CultCache readers for provider snapshots and
command ports, concrete CultMesh/CultCache readers for provider surface and
asset manifest documents, and proof that daemon receipts plus provider
snapshots drive the next rendered Unity frame rather than renderer-local state.
documents drive the next rendered Unity frame rather than renderer-local state.
## Non-Goals

View file

@ -0,0 +1,197 @@
using System;
using GameCult.Eve.Surface;
using UnityEngine;
#nullable enable
namespace GameCult.Eve.UnityScene
{
public sealed class EveUnityPlayableWorldRuntime : IDisposable
{
private readonly EveUnitySceneProviderSurfaceDocumentSource _surfaceSource;
private readonly EveUnitySceneProviderConnection _connection;
private readonly EveUnityPlayableWorldLiveClient _client;
private readonly EveUnityPlayableWorldAssetManifestDocumentSource? _assetManifestSource;
private bool _assetManifestConnected;
public EveUnityPlayableWorldRuntime(
IEveUnitySceneProviderSurfaceDocumentSource surfaceDocuments,
IEveUnitySceneCommandSink commandSink,
IEveUnityPlayableWorldSceneSink sceneSink,
IEveUnityPlayableWorldAssetManifestDocumentSource? assetManifestDocuments = null,
IEveUnitySceneCommandReceiptSource? receiptSource = null,
IEveUnityPlayableWorldAssetResolver? assetResolver = null,
EveUnityPlayableWorldAssetManifestCache? assetManifests = null)
{
if (surfaceDocuments == null) throw new ArgumentNullException(nameof(surfaceDocuments));
if (commandSink == null) throw new ArgumentNullException(nameof(commandSink));
if (sceneSink == null) throw new ArgumentNullException(nameof(sceneSink));
AssetManifests = assetManifests ?? new EveUnityPlayableWorldAssetManifestCache();
_surfaceSource = new EveUnitySceneProviderSurfaceDocumentSource(surfaceDocuments);
_connection = new EveUnitySceneProviderConnection(_surfaceSource, commandSink);
_client = new EveUnityPlayableWorldLiveClient(
_connection,
new EveUnityPlayableWorldPresenter(sceneSink, assetResolver ?? new EveUnityAssetRefResolver()),
receiptSource);
if (assetManifestDocuments != null)
_assetManifestSource = new EveUnityPlayableWorldAssetManifestDocumentSource(assetManifestDocuments);
}
public EveUnityPlayableWorldAssetManifestCache AssetManifests { get; }
public EveUnityPlayableWorldProjection? ActiveWorld => _client.ActiveWorld;
public EveUnitySceneProjection? ActiveProjection => _client.ActiveProjection;
public EveUnityPlayableWorldPresentation? LastPresentation => _client.LastPresentation;
public EveUnitySceneCommandReceipt? LastReceipt => _client.LastReceipt;
public long ActiveVersion => _client.ActiveVersion;
public string SourcePointer => _client.SourcePointer;
public event Action<EveUnitySceneCommandReceipt>? ReceiptAvailable
{
add { _client.ReceiptAvailable += value; }
remove { _client.ReceiptAvailable -= value; }
}
public static EveUnityPlayableWorldRuntime CreateForGameObjectScene(
Transform root,
IEveUnitySceneProviderSurfaceDocumentSource surfaceDocuments,
IEveUnitySceneCommandSink commandSink,
IEveUnityPlayableWorldAssetManifestDocumentSource? assetManifestDocuments = null,
IEveUnitySceneCommandReceiptSource? receiptSource = null,
IEveUnityGameObjectAssetProvider? fallbackAssetProvider = null)
{
EveUnityPlayableWorldRuntime? runtime = null;
var assetManifests = new EveUnityPlayableWorldAssetManifestCache();
var liveAssetProvider = new EveUnityLivePlayableWorldAssetProvider(
assetManifests,
() => runtime?.ActiveWorld,
fallbackAssetProvider ?? new EveUnityResourcesAssetProvider());
var sceneSink = new EveUnityGameObjectPlayableWorldSceneSink(root, liveAssetProvider);
runtime = new EveUnityPlayableWorldRuntime(
surfaceDocuments,
commandSink,
sceneSink,
assetManifestDocuments,
receiptSource,
new EveUnityAssetRefResolver(),
assetManifests);
return runtime;
}
public EveUnityPlayableWorldPresentation Connect()
{
EnsureAssetManifestConnected();
return _client.Connect();
}
public EveUnityPlayableWorldPresentation Refresh()
{
EnsureAssetManifestConnected();
return _client.Refresh();
}
public EveSurfaceCommandRequest SubmitMoveIntent(
string entityId,
float targetX,
float targetY,
float targetZ,
DateTimeOffset? issuedAt = null)
{
return _client.SubmitMoveIntent(entityId, targetX, targetY, targetZ, issuedAt);
}
public EveSurfaceCommandRequest SubmitFocusIntent(
string entityId,
DateTimeOffset? issuedAt = null)
{
return _client.SubmitFocusIntent(entityId, issuedAt);
}
public EveSurfaceCommandRequest SubmitTargetIntent(
string sourceEntityId,
string targetEntityId,
DateTimeOffset? issuedAt = null)
{
return _client.SubmitTargetIntent(sourceEntityId, targetEntityId, issuedAt);
}
public EveSurfaceCommandRequest SubmitActionIntent(
string entityId,
string actionId,
DateTimeOffset? issuedAt = null)
{
return _client.SubmitActionIntent(entityId, actionId, issuedAt);
}
public void Disconnect()
{
_client.Disconnect();
if (_assetManifestConnected && _assetManifestSource != null)
{
AssetManifests.Disconnect(_assetManifestSource);
_assetManifestSource.Disconnect();
_assetManifestConnected = false;
}
}
public void Dispose()
{
Disconnect();
_client.Dispose();
_assetManifestSource?.Dispose();
}
private void EnsureAssetManifestConnected()
{
if (_assetManifestConnected || _assetManifestSource == null)
return;
_assetManifestSource.Connect();
AssetManifests.Connect(_assetManifestSource);
_assetManifestConnected = true;
}
}
public sealed class EveUnityLivePlayableWorldAssetProvider : IEveUnityGameObjectAssetProvider
{
private readonly EveUnityPlayableWorldAssetManifestCache _assetManifests;
private readonly Func<EveUnityPlayableWorldProjection?> _activeWorld;
private readonly IEveUnityGameObjectAssetProvider _fallback;
public EveUnityLivePlayableWorldAssetProvider(
EveUnityPlayableWorldAssetManifestCache assetManifests,
Func<EveUnityPlayableWorldProjection?> activeWorld,
IEveUnityGameObjectAssetProvider fallback)
{
_assetManifests = assetManifests ?? throw new ArgumentNullException(nameof(assetManifests));
_activeWorld = activeWorld ?? throw new ArgumentNullException(nameof(activeWorld));
_fallback = fallback ?? throw new ArgumentNullException(nameof(fallback));
}
public GameObject? ResolvePrefab(EveUnityPlayableWorldAssetBinding asset)
{
if (asset == null) throw new ArgumentNullException(nameof(asset));
var world = _activeWorld();
var manifest = world == null ? null : _assetManifests.GetForWorld(world);
if (manifest != null)
{
var provider = new EveUnityManifestGameObjectAssetProvider(manifest, _fallback);
var prefab = provider.ResolvePrefab(asset);
if (prefab != null)
return prefab;
}
return _fallback.ResolvePrefab(asset);
}
}
}

View file

@ -248,6 +248,90 @@ namespace GameCult.Eve.UnityScene.Tests
Assert.That(moveIntent.ReceiptSchema, Is.EqualTo("aetheria.eve_command_acceptance_status.v1"));
}
[Test]
public void PlayableWorldRuntimeComposesProviderDocumentsAssetsReceiptsAndSceneSink()
{
var surfaceDocuments = new FakeProviderSurfaceDocumentSource(new EveUnitySceneProviderSurfaceDocument(
PlayableArpgDocument(),
Advertisement("aetheria.daemon.game"),
"cultmesh://aetheria/eve/surfaces/aetheria.daemon.game",
1));
var assetDocuments = new FakeAssetManifestDocumentSource(new EveUnityPlayableWorldAssetManifestDocument(
"cultmesh://aetheria/assets/manifest",
new[]
{
new EveUnityPlayableWorldAssetManifestDocumentEntry(
"cultmesh://aetheria/assets/map/entity/player",
"player",
"Resources/Aetheria/Entities/Vanguard.prefab",
"aetheria.vanguard"),
new EveUnityPlayableWorldAssetManifestDocumentEntry(
"cultmesh://aetheria/assets/map/entity/ship",
"enemy",
"Resources/Aetheria/Entities/Raider.prefab",
"aetheria.raider")
},
"aetheria"));
var commandSink = new FakeCommandSink("cultmesh-command-sink");
var receiptSource = new FakeCommandReceiptSource();
var sceneSink = new FakePlayableWorldSceneSink();
using var runtime = new EveUnityPlayableWorldRuntime(
surfaceDocuments,
commandSink,
sceneSink,
assetDocuments,
receiptSource);
var initialPresentation = runtime.Connect();
Assert.That(initialPresentation.ActiveEntities, Is.EqualTo(3));
Assert.That(runtime.ActiveWorld, Is.Not.Null);
Assert.That(runtime.ActiveWorld!.AssetManifest, Is.EqualTo("cultmesh://aetheria/assets/manifest"));
Assert.That(runtime.AssetManifests.GetForWorld(runtime.ActiveWorld), Is.Not.Null);
Assert.That(sceneSink.Upserts.Count, Is.EqualTo(3));
var moveIntent = runtime.SubmitMoveIntent(
"player-vanguard",
14f,
0f,
9f,
DateTimeOffset.Parse("2026-07-09T00:00:00Z"));
Assert.That(commandSink.Submitted.Count, Is.EqualTo(1));
Assert.That(commandSink.Submitted[0], Is.SameAs(moveIntent));
Assert.That(moveIntent.ProviderId, Is.EqualTo("aetheria"));
Assert.That(moveIntent.Command, Is.EqualTo("aetheria.daemon.commands"));
Assert.That(moveIntent.CommandBoundary, Is.EqualTo("aetheria.daemon.commands"));
Assert.That(moveIntent.ReceiptSchema, Is.EqualTo("aetheria.eve_command_acceptance_status.v1"));
surfaceDocuments.Publish(new EveUnitySceneProviderSurfaceDocument(
PlayableArpgDocument(includeRaider: false, playerPosition: "14,0,9"),
Advertisement("aetheria.daemon.game"),
"cultmesh://aetheria/eve/surfaces/aetheria.daemon.game",
2));
Assert.That(runtime.ActiveVersion, Is.EqualTo(2));
Assert.That(runtime.LastPresentation, Is.Not.Null);
Assert.That(runtime.LastPresentation!.ActiveEntities, Is.EqualTo(2));
Assert.That(sceneSink.RemovedEntityIds, Does.Contain("raider-scout"));
Assert.That(sceneSink.Upserts[3].entity.EntityId, Is.EqualTo("player-vanguard"));
Assert.That(sceneSink.Upserts[3].entity.PositionX, Is.EqualTo(14f));
Assert.That(sceneSink.Upserts[3].entity.PositionZ, Is.EqualTo(9f));
receiptSource.Publish(new EveUnitySceneCommandReceipt(
"aetheria.daemon.move_intent.accepted",
"aetheria.daemon.move_intent",
"aetheria.daemon.move_intent",
"accepted",
"Aetheria",
"provider-owned-daemon"));
Assert.That(runtime.LastReceipt, Is.Not.Null);
Assert.That(runtime.LastReceipt!.IsProviderOwned, Is.True);
Assert.That(runtime.LastReceipt.ShouldRefreshProviderSurface, Is.True);
}
[Test]
public void PlayableWorldPresenterInstantiatesUpdatesAndDespawnsProviderEntities()
{

View file

@ -24,6 +24,7 @@
"providerAssetManifestDocumentSource",
"sceneGraphProjection",
"playableWorldProjection",
"playableWorldRuntimeHost",
"playableWorldScenePresentation",
"unityGameObjectSceneSink",
"providerAssetManifestResolution",
@ -72,6 +73,7 @@
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneClientSession.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneProviderConnection.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldLiveClient.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldRuntime.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldPresenter.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnityGameObjectPlayableWorldSceneSink.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldAssetManifest.cs",
@ -124,6 +126,7 @@
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneClientSession.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneProviderConnection.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldLiveClient.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldRuntime.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldPresenter.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnityGameObjectPlayableWorldSceneSink.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldAssetManifest.cs",
@ -165,6 +168,7 @@
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneClientSession.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneProviderConnection.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldLiveClient.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldRuntime.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldPresenter.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnityGameObjectPlayableWorldSceneSink.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldAssetManifest.cs",

View file

@ -19,6 +19,7 @@
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneClientSession.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneProviderConnection.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldLiveClient.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldRuntime.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldPresenter.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnityGameObjectPlayableWorldSceneSink.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldAssetManifest.cs",
@ -41,6 +42,7 @@
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneClientSession.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneProviderConnection.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldLiveClient.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldRuntime.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldPresenter.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnityGameObjectPlayableWorldSceneSink.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldAssetManifest.cs",
@ -63,6 +65,7 @@
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneClientSession.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneProviderConnection.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldLiveClient.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldRuntime.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldPresenter.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnityGameObjectPlayableWorldSceneSink.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldAssetManifest.cs",
@ -73,7 +76,7 @@
"runtimes/incubating/eve-unity-scene/eve-runtime-capability.json"
],
"destinationOwner": "EveUnity",
"replacementProof": "EveUnity claims the provider-advertised unity-scene lowering target with provider-agnostic playable-world projection, scene graph projection, typed provider surface document loading, provider snapshot session, live playable-world client composition, provider command receipt observation, playable-world scene presentation, Unity GameObject scene sink, typed provider asset manifest document loading, provider asset manifest resolution, provider asset manifest source/cache, and command boundary evidence; live transport and capture remain separate lifecycle proofs."
"replacementProof": "EveUnity claims the provider-advertised unity-scene lowering target with provider-agnostic playable-world projection, scene graph projection, typed provider surface document loading, provider snapshot session, a playable-world runtime host, live playable-world client composition, provider command receipt observation, playable-world scene presentation, Unity GameObject scene sink, typed provider asset manifest document loading, provider asset manifest resolution, provider asset manifest source/cache, and command boundary evidence; live transport and capture remain separate lifecycle proofs."
},
{
"id": "unity-scene-sai-plugin-projection",

View file

@ -39,7 +39,7 @@ if ($manifest.incubation.splitHandoff.manifestPath -ne "runtimes/incubating/eve-
throw "EveUnity scene manifest missing split handoff path"
}
foreach ($feature in @("providerAdvertisements", "commandTransport", "providerSurfaceSession", "providerSurfaceSource", "providerSurfaceDocumentSource", "livePlayableWorldClient", "providerCommandReceipts", "providerAssetManifestDocumentSource", "sceneGraphProjection", "playableWorldProjection", "playableWorldScenePresentation", "unityGameObjectSceneSink", "providerAssetManifestResolution", "providerAssetManifestSource", "embeddedDocuments")) {
foreach ($feature in @("providerAdvertisements", "commandTransport", "providerSurfaceSession", "providerSurfaceSource", "providerSurfaceDocumentSource", "livePlayableWorldClient", "providerCommandReceipts", "providerAssetManifestDocumentSource", "sceneGraphProjection", "playableWorldProjection", "playableWorldRuntimeHost", "playableWorldScenePresentation", "unityGameObjectSceneSink", "providerAssetManifestResolution", "providerAssetManifestSource", "embeddedDocuments")) {
if (-not (@($manifest.supportedFeatures) -contains $feature)) {
throw "EveUnity scene manifest missing provider-shell feature: $feature"
}

View file

@ -54,7 +54,7 @@ foreach ($evidencePath in @($worldSurfaceLoweringClaim.evidencePaths)) {
}
}
foreach ($feature in @("providerAdvertisements", "commandTransport", "providerSurfaceSession", "providerSurfaceSource", "providerSurfaceDocumentSource", "livePlayableWorldClient", "providerCommandReceipts", "providerAssetManifestDocumentSource", "sceneGraphProjection", "playableWorldProjection", "playableWorldScenePresentation", "unityGameObjectSceneSink", "providerAssetManifestResolution", "providerAssetManifestSource")) {
foreach ($feature in @("providerAdvertisements", "commandTransport", "providerSurfaceSession", "providerSurfaceSource", "providerSurfaceDocumentSource", "livePlayableWorldClient", "providerCommandReceipts", "providerAssetManifestDocumentSource", "sceneGraphProjection", "playableWorldProjection", "playableWorldRuntimeHost", "playableWorldScenePresentation", "unityGameObjectSceneSink", "providerAssetManifestResolution", "providerAssetManifestSource")) {
if (-not (@($manifest.supportedFeatures) -contains $feature)) {
throw "EveUnity scene provider shell missing supported feature: $feature"
}
@ -67,6 +67,7 @@ $expectedFiles = @(
"runtimes\incubating\eve-unity-scene\Runtime\EveUnitySceneClientSession.cs",
"runtimes\incubating\eve-unity-scene\Runtime\EveUnitySceneProviderConnection.cs",
"runtimes\incubating\eve-unity-scene\Runtime\EveUnityPlayableWorldLiveClient.cs",
"runtimes\incubating\eve-unity-scene\Runtime\EveUnityPlayableWorldRuntime.cs",
"runtimes\incubating\eve-unity-scene\Runtime\EveUnityPlayableWorldPresenter.cs",
"runtimes\incubating\eve-unity-scene\Runtime\EveUnityGameObjectPlayableWorldSceneSink.cs",
"runtimes\incubating\eve-unity-scene\Runtime\EveUnityPlayableWorldAssetManifest.cs",
@ -112,6 +113,13 @@ foreach ($symbol in @("EveUnityPlayableWorldLiveClient", "IEveUnitySceneCommandR
}
}
$runtimeHostSource = Get-Content -LiteralPath (Join-Path $projectRoot "runtimes\incubating\eve-unity-scene\Runtime\EveUnityPlayableWorldRuntime.cs") -Raw
foreach ($symbol in @("EveUnityPlayableWorldRuntime", "CreateForGameObjectScene", "EveUnityLivePlayableWorldAssetProvider", "IEveUnitySceneProviderSurfaceDocumentSource", "IEveUnitySceneCommandSink", "IEveUnityPlayableWorldAssetManifestDocumentSource", "IEveUnitySceneCommandReceiptSource", "EveUnityPlayableWorldAssetManifestCache", "AssetManifests", "ActiveWorld", "SubmitMoveIntent", "SubmitFocusIntent", "SubmitTargetIntent", "SubmitActionIntent", "Connect", "Refresh", "Disconnect")) {
if (-not $runtimeHostSource.Contains($symbol)) {
throw "EveUnity playable world runtime host missing symbol: $symbol"
}
}
$playableWorldPresenterSource = Get-Content -LiteralPath (Join-Path $projectRoot "runtimes\incubating\eve-unity-scene\Runtime\EveUnityPlayableWorldPresenter.cs") -Raw
foreach ($symbol in @("IEveUnityPlayableWorldSceneSink", "IEveUnityPlayableWorldAssetResolver", "EveUnityPlayableWorldPresenter", "EveUnityPlayableWorldAssetBinding", "EveUnityPlayableWorldPresentation", "EveUnityAssetRefResolver", "ConfigureWorld", "UpsertEntity", "RemoveEntity", "provider-asset-ref", "unity-generated-placeholder")) {
if (-not $playableWorldPresenterSource.Contains($symbol)) {
@ -155,7 +163,7 @@ foreach ($symbol in @("TeXMathUnitySceneProjectionAdapter", "tex.math", "embed.t
}
$testSource = Get-Content -LiteralPath (Join-Path $projectRoot "runtimes\incubating\eve-unity-scene\Tests\Editor\EveUnitySceneSurfaceLowererTests.cs") -Raw
foreach ($symbol in @("LowerCarriesProviderAdvertisedWorldBoundary", "LowerBuildsProviderAgnosticSceneGraphFromSurfaceTree", "LowerExtractsPlayableArpgWorldFromGenericScene3dSurface", "GenericClientSessionConsumesAetheriaPlayableWorldSnapshotWithoutAetheriaTypes", "GenericProviderConnectionAppliesLiveSnapshotsAndSubmitsCommandsThroughSink", "ProviderSurfaceDocumentSourceFeedsPlayableClientWithoutAetheriaTypes", "PlayableWorldPresenterInstantiatesUpdatesAndDespawnsProviderEntities", "LivePlayableWorldClientPresentsProviderSnapshotsAndKeepsCommandsProviderOwned", "LivePlayableWorldClientRefreshesFromProviderSnapshotAfterReceiptWithoutOwningMovement", "AssetManifestMapsProviderAssetRefsToUnityLoadKeysWithoutAetheriaTypes", "AssetManifestCacheTracksPlayableWorldManifestPointerAndLiveUpdates", "AssetManifestDocumentSourceFeedsCacheWithoutChangingSceneLowering", "FakeProviderSurfaceSource", "FakeProviderSurfaceDocumentSource", "FakeCommandReceiptSource", "FakeAssetManifestSource", "FakeAssetManifestDocumentSource", "FakeCommandSink", "FakePlayableWorldSceneSink", "SaiVisualNovelLowersThroughRuntimeProjectionAdapterWithoutOwningStoryState", "CommandIntentCarriesAdvertisedBoundaryWithoutOwningReceipts", "pending", "reconciled", "world-projection-node", "playable-world-root", "playable-world-entity", "world-field-3d", "arpg-third-person", "cultmesh://aetheria/assets/manifest", "cultmesh://aetheria/eve/surfaces/aetheria.daemon.game", "aetheria.daemon.move_intent", "sai-vn-scene-stage", "norn-graph-scene-projection", "tex-math-scene-projection", "sai.vn", "norn.graph", "tex.math", "sidecar-advertised-plugin-abi", "aetheria.daemon.commands", "aetheria.eve_command_acceptance_status.v1")) {
foreach ($symbol in @("LowerCarriesProviderAdvertisedWorldBoundary", "LowerBuildsProviderAgnosticSceneGraphFromSurfaceTree", "LowerExtractsPlayableArpgWorldFromGenericScene3dSurface", "GenericClientSessionConsumesAetheriaPlayableWorldSnapshotWithoutAetheriaTypes", "GenericProviderConnectionAppliesLiveSnapshotsAndSubmitsCommandsThroughSink", "ProviderSurfaceDocumentSourceFeedsPlayableClientWithoutAetheriaTypes", "PlayableWorldRuntimeComposesProviderDocumentsAssetsReceiptsAndSceneSink", "PlayableWorldPresenterInstantiatesUpdatesAndDespawnsProviderEntities", "LivePlayableWorldClientPresentsProviderSnapshotsAndKeepsCommandsProviderOwned", "LivePlayableWorldClientRefreshesFromProviderSnapshotAfterReceiptWithoutOwningMovement", "AssetManifestMapsProviderAssetRefsToUnityLoadKeysWithoutAetheriaTypes", "AssetManifestCacheTracksPlayableWorldManifestPointerAndLiveUpdates", "AssetManifestDocumentSourceFeedsCacheWithoutChangingSceneLowering", "FakeProviderSurfaceSource", "FakeProviderSurfaceDocumentSource", "FakeCommandReceiptSource", "FakeAssetManifestSource", "FakeAssetManifestDocumentSource", "FakeCommandSink", "FakePlayableWorldSceneSink", "SaiVisualNovelLowersThroughRuntimeProjectionAdapterWithoutOwningStoryState", "CommandIntentCarriesAdvertisedBoundaryWithoutOwningReceipts", "pending", "reconciled", "world-projection-node", "playable-world-root", "playable-world-entity", "world-field-3d", "arpg-third-person", "cultmesh://aetheria/assets/manifest", "cultmesh://aetheria/eve/surfaces/aetheria.daemon.game", "aetheria.daemon.move_intent", "sai-vn-scene-stage", "norn-graph-scene-projection", "tex-math-scene-projection", "sai.vn", "norn.graph", "tex.math", "sidecar-advertised-plugin-abi", "aetheria.daemon.commands", "aetheria.eve_command_acceptance_status.v1")) {
if (-not $testSource.Contains($symbol)) {
throw "EveUnity scene provider shell tests missing symbol: $symbol"
}

View file

@ -73,6 +73,7 @@ node $consumerScript $consumerExport `
--expect-runtime-feature unity-scene:providerAssetManifestDocumentSource `
--expect-runtime-feature unity-scene:sceneGraphProjection `
--expect-runtime-feature unity-scene:playableWorldProjection `
--expect-runtime-feature unity-scene:playableWorldRuntimeHost `
--expect-runtime-feature unity-scene:playableWorldScenePresentation `
--expect-runtime-feature unity-scene:unityGameObjectSceneSink `
--expect-runtime-feature unity-scene:providerAssetManifestResolution `

View file

@ -1041,7 +1041,7 @@
"splitHandoffPath": "runtimes/incubating/eve-unity-scene/eveunity-scene-split-handoff.json",
"requiredFixtures": ["aetheria-world", "eve-world-smoke"],
"pluginFixtures": ["sai-vn"],
"supportedFeatures": ["providerAdvertisements", "commandTransport", "providerSurfaceSession", "providerSurfaceSource", "providerSurfaceDocumentSource", "livePlayableWorldClient", "providerCommandReceipts", "providerAssetManifestDocumentSource", "providerAssetManifestSource", "sceneGraphProjection", "playableWorldProjection", "playableWorldScenePresentation", "unityGameObjectSceneSink", "providerAssetManifestResolution", "embeddedDocuments"],
"supportedFeatures": ["providerAdvertisements", "commandTransport", "providerSurfaceSession", "providerSurfaceSource", "providerSurfaceDocumentSource", "livePlayableWorldClient", "providerCommandReceipts", "providerAssetManifestDocumentSource", "providerAssetManifestSource", "sceneGraphProjection", "playableWorldProjection", "playableWorldRuntimeHost", "playableWorldScenePresentation", "unityGameObjectSceneSink", "providerAssetManifestResolution", "embeddedDocuments"],
"supportedPlugins": [
{
"pluginId": "sai.vn",
@ -1072,6 +1072,7 @@
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneClientSession.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneProviderConnection.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldLiveClient.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldRuntime.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldPresenter.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnityGameObjectPlayableWorldSceneSink.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldAssetManifest.cs",
@ -1091,6 +1092,7 @@
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneClientSession.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneProviderConnection.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldLiveClient.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldRuntime.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldPresenter.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnityGameObjectPlayableWorldSceneSink.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldAssetManifest.cs",
@ -1133,6 +1135,10 @@
"path": "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldLiveClient.cs",
"contains": ["EveUnityPlayableWorldLiveClient", "IEveUnitySceneCommandReceiptSource", "EveUnitySceneCommandReceipt", "EveUnitySceneProviderConnection", "EveUnityPlayableWorldPresenter", "ActiveWorld", "LastPresentation", "LastReceipt", "ReceiptAvailable", "Connect", "Refresh", "SubmitMoveIntent", "SubmitFocusIntent", "SubmitTargetIntent", "SubmitActionIntent", "ProjectionUpdated", "ShouldRefreshProviderSurface", "IsProviderOwned", "Disconnect"]
},
{
"path": "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldRuntime.cs",
"contains": ["EveUnityPlayableWorldRuntime", "CreateForGameObjectScene", "EveUnityLivePlayableWorldAssetProvider", "IEveUnitySceneProviderSurfaceDocumentSource", "IEveUnitySceneCommandSink", "IEveUnityPlayableWorldAssetManifestDocumentSource", "IEveUnitySceneCommandReceiptSource", "EveUnityPlayableWorldAssetManifestCache", "AssetManifests", "ActiveWorld", "SubmitMoveIntent", "SubmitFocusIntent", "SubmitTargetIntent", "SubmitActionIntent", "Connect", "Refresh", "Disconnect"]
},
{
"path": "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldPresenter.cs",
"contains": ["IEveUnityPlayableWorldSceneSink", "IEveUnityPlayableWorldAssetResolver", "EveUnityPlayableWorldPresenter", "EveUnityPlayableWorldAssetBinding", "EveUnityPlayableWorldPresentation", "EveUnityAssetRefResolver", "ConfigureWorld", "UpsertEntity", "RemoveEntity", "provider-asset-ref", "unity-generated-placeholder"]
@ -1159,7 +1165,7 @@
},
{
"path": "runtimes/incubating/eve-unity-scene/Tests/Editor/EveUnitySceneSurfaceLowererTests.cs",
"contains": ["LowerCarriesProviderAdvertisedWorldBoundary", "LowerBuildsProviderAgnosticSceneGraphFromSurfaceTree", "LowerExtractsPlayableArpgWorldFromGenericScene3dSurface", "GenericClientSessionConsumesAetheriaPlayableWorldSnapshotWithoutAetheriaTypes", "GenericProviderConnectionAppliesLiveSnapshotsAndSubmitsCommandsThroughSink", "ProviderSurfaceDocumentSourceFeedsPlayableClientWithoutAetheriaTypes", "PlayableWorldPresenterInstantiatesUpdatesAndDespawnsProviderEntities", "LivePlayableWorldClientPresentsProviderSnapshotsAndKeepsCommandsProviderOwned", "LivePlayableWorldClientRefreshesFromProviderSnapshotAfterReceiptWithoutOwningMovement", "AssetManifestMapsProviderAssetRefsToUnityLoadKeysWithoutAetheriaTypes", "AssetManifestCacheTracksPlayableWorldManifestPointerAndLiveUpdates", "AssetManifestDocumentSourceFeedsCacheWithoutChangingSceneLowering", "FakeProviderSurfaceSource", "FakeProviderSurfaceDocumentSource", "FakeCommandReceiptSource", "FakeAssetManifestSource", "FakeAssetManifestDocumentSource", "FakeCommandSink", "FakePlayableWorldSceneSink", "SaiVisualNovelLowersThroughRuntimeProjectionAdapterWithoutOwningStoryState", "CommandIntentCarriesAdvertisedBoundaryWithoutOwningReceipts", "pending", "reconciled", "world-projection-node", "playable-world-root", "playable-world-entity", "world-field-3d", "arpg-third-person", "cultmesh://aetheria/assets/manifest", "cultmesh://aetheria/eve/surfaces/aetheria.daemon.game", "aetheria.daemon.move_intent", "sai-vn-scene-stage", "norn-graph-scene-projection", "tex-math-scene-projection", "norn.map", "cultmesh://aetheria/norn/map", "sai.vn", "norn.graph", "tex.math", "sidecar-advertised-plugin-abi", "aetheria.daemon.commands", "aetheria.eve_command_acceptance_status.v1"]
"contains": ["LowerCarriesProviderAdvertisedWorldBoundary", "LowerBuildsProviderAgnosticSceneGraphFromSurfaceTree", "LowerExtractsPlayableArpgWorldFromGenericScene3dSurface", "GenericClientSessionConsumesAetheriaPlayableWorldSnapshotWithoutAetheriaTypes", "GenericProviderConnectionAppliesLiveSnapshotsAndSubmitsCommandsThroughSink", "ProviderSurfaceDocumentSourceFeedsPlayableClientWithoutAetheriaTypes", "PlayableWorldRuntimeComposesProviderDocumentsAssetsReceiptsAndSceneSink", "PlayableWorldPresenterInstantiatesUpdatesAndDespawnsProviderEntities", "LivePlayableWorldClientPresentsProviderSnapshotsAndKeepsCommandsProviderOwned", "LivePlayableWorldClientRefreshesFromProviderSnapshotAfterReceiptWithoutOwningMovement", "AssetManifestMapsProviderAssetRefsToUnityLoadKeysWithoutAetheriaTypes", "AssetManifestCacheTracksPlayableWorldManifestPointerAndLiveUpdates", "AssetManifestDocumentSourceFeedsCacheWithoutChangingSceneLowering", "FakeProviderSurfaceSource", "FakeProviderSurfaceDocumentSource", "FakeCommandReceiptSource", "FakeAssetManifestSource", "FakeAssetManifestDocumentSource", "FakeCommandSink", "FakePlayableWorldSceneSink", "SaiVisualNovelLowersThroughRuntimeProjectionAdapterWithoutOwningStoryState", "CommandIntentCarriesAdvertisedBoundaryWithoutOwningReceipts", "pending", "reconciled", "world-projection-node", "playable-world-root", "playable-world-entity", "world-field-3d", "arpg-third-person", "cultmesh://aetheria/assets/manifest", "cultmesh://aetheria/eve/surfaces/aetheria.daemon.game", "aetheria.daemon.move_intent", "sai-vn-scene-stage", "norn-graph-scene-projection", "tex-math-scene-projection", "norn.map", "cultmesh://aetheria/norn/map", "sai.vn", "norn.graph", "tex.math", "sidecar-advertised-plugin-abi", "aetheria.daemon.commands", "aetheria.eve_command_acceptance_status.v1"]
},
{
"path": "tools/eveunity/eveunity-capture-contract.test.mjs",