Add Unity command receipt boundary

This commit is contained in:
Meta Vens 2026-07-09 18:43:48 +01:00
commit ccbaba2a05
11 changed files with 218 additions and 22 deletions

View file

@ -617,7 +617,10 @@ Recently cut:
`EveUnityPlayableWorldLiveClient` now composes the provider connection with
the playable-world presenter, so provider snapshots immediately drive scene
presentation and Unity input still exits through the provider command sink
rather than local simulation.
rather than local simulation. The same live client now observes provider
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.
`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
@ -634,8 +637,8 @@ Recently cut:
Unity client boundary is generic before it learns live transport. The next
blocker is the live generic Unity player loop: implement that CultMesh/CultNet
adapter, implement the concrete CultMesh/CultCache asset-manifest source, and
route provider receipts/next frames through the live client rather than
renderer-local simulation.
prove provider receipts plus daemon snapshots drive rendered Unity frames
rather than renderer-local simulation.
- EveElectron capture lifecycle now carries the same kind of structured pending
capture contract. `captureContract` names the Electron shell runtime, capture
kind, PNG artifact pattern, conformance attachment point, required Aetheria

View file

@ -489,6 +489,11 @@ runtime-owned port to implement. The runtime 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
`providerCommandReceipts`: `IEveUnitySceneCommandReceiptSource` and
`EveUnitySceneCommandReceipt` keep provider-owned pending/accepted/denied/
reconciled command status distinct from scene state; accepted or reconciled
receipts can refresh the provider snapshot, but receipts do not mutate world
entities. The runtime now also declares
`playableWorldScenePresentation`: `EveUnityPlayableWorldPresenter` maps
provider-authored entity rows and asset refs into scene sink operations while
removing entities absent from later provider snapshots. The runtime now also
@ -504,8 +509,8 @@ and `EveUnityPlayableWorldAssetManifestCache` key live manifest updates by the
`playableWorld.AssetManifest` pointer, giving the future CultMesh/CultCache
reader a narrow slot that does not change scene lowering. The remaining blocker
is the live CultMesh/CultNet adapter, a concrete CultMesh/CultCache provider
asset-manifest source, receipt-aware refresh through the live client, and Unity
screenshot or frame-capture PNG production from EveUnity.
asset-manifest source, and Unity screenshot or frame-capture PNG production from
EveUnity.
Runtime capture probe coverage is exported as `runtimeCaptureProbeCoverage[]`.
Each record joins runtime status, capture owner, lifecycle capture contract,

View file

@ -166,8 +166,11 @@ radii, asset refs, controllability, and command affordances. The generic
while `IEveUnitySceneCommandSink` receives command envelopes.
`EveUnityPlayableWorldLiveClient` composes that connection with the playable
world presenter: every provider snapshot is lowered into a presentation pass,
and Unity input still emits provider-owned command intents rather than mutating
local world truth.
Unity input still emits provider-owned command intents rather than mutating
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.
`EveUnityPlayableWorldPresenter` maps the provider-authored entity rows and
asset refs into scene operations through `IEveUnityPlayableWorldSceneSink` and
`IEveUnityPlayableWorldAssetResolver`, including removal of entities that
@ -188,9 +191,9 @@ locally.
This is not yet the final playable client. The remaining cut is a live
CultMesh/CultNet provider subscription adapter implementing those source/sink
ports, a concrete CultMesh/CultCache asset-manifest source implementation,
receipt-aware refresh over the same live client, and proof that daemon receipts
drive the next rendered Unity frame rather than renderer-local state.
ports, a concrete CultMesh/CultCache asset-manifest source implementation, and
proof that daemon receipts plus provider snapshots drive the next rendered
Unity frame rather than renderer-local state.
## Non-Goals

View file

@ -9,14 +9,21 @@ namespace GameCult.Eve.UnityScene
{
private readonly EveUnitySceneProviderConnection _connection;
private readonly EveUnityPlayableWorldPresenter _presenter;
private readonly IEveUnitySceneCommandReceiptSource? _receiptSource;
private readonly bool _refreshOnTerminalReceipt;
private bool _connected;
private bool _receiptConnected;
public EveUnityPlayableWorldLiveClient(
EveUnitySceneProviderConnection connection,
EveUnityPlayableWorldPresenter presenter)
EveUnityPlayableWorldPresenter presenter,
IEveUnitySceneCommandReceiptSource? receiptSource = null,
bool refreshOnTerminalReceipt = true)
{
_connection = connection ?? throw new ArgumentNullException(nameof(connection));
_presenter = presenter ?? throw new ArgumentNullException(nameof(presenter));
_receiptSource = receiptSource;
_refreshOnTerminalReceipt = refreshOnTerminalReceipt;
}
public EveUnitySceneProjection? ActiveProjection => _connection.ActiveProjection;
@ -25,13 +32,18 @@ namespace GameCult.Eve.UnityScene
public EveUnityPlayableWorldPresentation? LastPresentation { get; private set; }
public EveUnitySceneCommandReceipt? LastReceipt { get; private set; }
public long ActiveVersion => _connection.ActiveVersion;
public string SourcePointer => _connection.SourcePointer;
public event Action<EveUnitySceneCommandReceipt>? ReceiptAvailable;
public EveUnityPlayableWorldPresentation Connect()
{
EnsureSubscribed();
EnsureReceiptSubscribed();
_connection.Connect();
return RequirePresentation();
}
@ -84,6 +96,12 @@ namespace GameCult.Eve.UnityScene
_connected = false;
}
if (_receiptConnected && _receiptSource != null)
{
_receiptSource.ReceiptAvailable -= OnReceiptAvailable;
_receiptConnected = false;
}
_connection.Disconnect();
}
@ -102,11 +120,29 @@ namespace GameCult.Eve.UnityScene
_connected = true;
}
private void EnsureReceiptSubscribed()
{
if (_receiptSource == null || _receiptConnected)
return;
_receiptSource.ReceiptAvailable += OnReceiptAvailable;
_receiptConnected = true;
}
private void OnProjectionUpdated(EveUnitySceneProjection projection)
{
LastPresentation = _presenter.Apply(projection);
}
private void OnReceiptAvailable(EveUnitySceneCommandReceipt receipt)
{
LastReceipt = receipt ?? throw new ArgumentNullException(nameof(receipt));
ReceiptAvailable?.Invoke(receipt);
if (_refreshOnTerminalReceipt && receipt.ShouldRefreshProviderSurface)
Refresh();
}
private EveUnityPlayableWorldPresentation RequirePresentation()
{
if (LastPresentation == null)
@ -114,4 +150,66 @@ namespace GameCult.Eve.UnityScene
return LastPresentation;
}
}
public interface IEveUnitySceneCommandReceiptSource
{
event Action<EveUnitySceneCommandReceipt> ReceiptAvailable;
}
public sealed class EveUnitySceneCommandReceipt
{
public EveUnitySceneCommandReceipt(
string receiptId,
string command,
string commandId,
string state,
string ownerRepo,
string authority,
string schema = "gamecult.eve.command_receipt.v1",
string providerId = "",
string surfaceId = "",
string message = "",
DateTimeOffset? issuedAtUtc = null)
{
ReceiptId = receiptId ?? "";
Command = command ?? "";
CommandId = commandId ?? "";
State = state ?? "";
OwnerRepo = ownerRepo ?? "";
Authority = authority ?? "";
Schema = string.IsNullOrWhiteSpace(schema) ? "gamecult.eve.command_receipt.v1" : schema;
ProviderId = providerId ?? "";
SurfaceId = surfaceId ?? "";
Message = message ?? "";
IssuedAtUtc = issuedAtUtc;
}
public string Schema { get; }
public string ReceiptId { get; }
public string Command { get; }
public string CommandId { get; }
public string State { get; }
public string OwnerRepo { get; }
public string Authority { get; }
public string ProviderId { get; }
public string SurfaceId { get; }
public string Message { get; }
public DateTimeOffset? IssuedAtUtc { get; }
public bool IsProviderOwned => !string.IsNullOrWhiteSpace(OwnerRepo) && !string.Equals(OwnerRepo, "EveUnity", StringComparison.Ordinal);
public bool ShouldRefreshProviderSurface =>
string.Equals(State, "accepted", StringComparison.OrdinalIgnoreCase) ||
string.Equals(State, "reconciled", StringComparison.OrdinalIgnoreCase);
}
}

View file

@ -307,6 +307,76 @@ namespace GameCult.Eve.UnityScene.Tests
Assert.That(sceneSink.ConfiguredWorlds.Count, Is.EqualTo(2));
}
[Test]
public void LivePlayableWorldClientRefreshesFromProviderSnapshotAfterReceiptWithoutOwningMovement()
{
var source = new FakeProviderSurfaceSource(
"aetheria",
"aetheria.daemon.game",
"cultmesh://aetheria/eve/surfaces/aetheria.daemon.game",
new EveUnitySceneProviderSurfaceSnapshot(
PlayableArpgDocument(),
Advertisement("aetheria.daemon.game"),
"cultmesh://aetheria/eve/surfaces/aetheria.daemon.game",
1));
var commandSink = new FakeCommandSink("cultmesh-command-sink");
var receiptSource = new FakeCommandReceiptSource();
var sceneSink = new FakePlayableWorldSceneSink();
using var connection = new EveUnitySceneProviderConnection(source, commandSink);
using var client = new EveUnityPlayableWorldLiveClient(
connection,
new EveUnityPlayableWorldPresenter(sceneSink, new EveUnityAssetRefResolver()),
receiptSource);
client.Connect();
client.SubmitMoveIntent("player-vanguard", 30f, 0f, 30f);
Assert.That(sceneSink.Upserts[0].entity.PositionX, Is.EqualTo(0f));
Assert.That(sceneSink.ConfiguredWorlds.Count, Is.EqualTo(1));
receiptSource.Publish(new EveUnitySceneCommandReceipt(
"aetheria.daemon.move_intent.pending",
"aetheria.daemon.commands",
"aetheria.daemon.move_intent",
"pending",
"Aetheria",
"AetheriaRuntimeDaemonCommandBoundaryDocument",
"aetheria.eve_command_acceptance_status.v1",
"aetheria",
"aetheria.daemon.game"));
Assert.That(client.LastReceipt, Is.Not.Null);
Assert.That(client.LastReceipt!.State, Is.EqualTo("pending"));
Assert.That(client.LastReceipt.IsProviderOwned, Is.True);
Assert.That(sceneSink.ConfiguredWorlds.Count, Is.EqualTo(1));
source.Stage(new EveUnitySceneProviderSurfaceSnapshot(
PlayableArpgDocument(includeRaider: false, playerPosition: "30,0,30"),
Advertisement("aetheria.daemon.game"),
"cultmesh://aetheria/eve/surfaces/aetheria.daemon.game",
2));
receiptSource.Publish(new EveUnitySceneCommandReceipt(
"aetheria.daemon.move_intent.reconciled",
"aetheria.daemon.commands",
"aetheria.daemon.move_intent",
"reconciled",
"Aetheria",
"AetheriaRuntimeDaemonCommandBoundaryDocument",
"aetheria.eve_command_acceptance_status.v1",
"aetheria",
"aetheria.daemon.game"));
Assert.That(client.LastReceipt.State, Is.EqualTo("reconciled"));
Assert.That(client.ActiveVersion, Is.EqualTo(2));
Assert.That(client.LastPresentation, Is.Not.Null);
Assert.That(client.LastPresentation!.ActiveEntities, Is.EqualTo(2));
Assert.That(sceneSink.ConfiguredWorlds.Count, Is.EqualTo(2));
Assert.That(sceneSink.Upserts[3].entity.EntityId, Is.EqualTo("player-vanguard"));
Assert.That(sceneSink.Upserts[3].entity.PositionX, Is.EqualTo(30f));
Assert.That(sceneSink.Upserts[3].entity.PositionZ, Is.EqualTo(30f));
}
[Test]
public void AssetManifestMapsProviderAssetRefsToUnityLoadKeysWithoutAetheriaTypes()
{
@ -808,6 +878,11 @@ namespace GameCult.Eve.UnityScene.Tests
public event Action<EveUnitySceneProviderSurfaceSnapshot>? SnapshotAvailable;
public void Stage(EveUnitySceneProviderSurfaceSnapshot snapshot)
{
CurrentSnapshot = snapshot;
}
public void Publish(EveUnitySceneProviderSurfaceSnapshot snapshot)
{
CurrentSnapshot = snapshot;
@ -815,6 +890,16 @@ namespace GameCult.Eve.UnityScene.Tests
}
}
private sealed class FakeCommandReceiptSource : IEveUnitySceneCommandReceiptSource
{
public event Action<EveUnitySceneCommandReceipt>? ReceiptAvailable;
public void Publish(EveUnitySceneCommandReceipt receipt)
{
ReceiptAvailable?.Invoke(receipt);
}
}
private sealed class FakeCommandSink : IEveUnitySceneCommandSink
{
public FakeCommandSink(string sinkKind)

View file

@ -19,6 +19,7 @@
"providerSurfaceSession",
"providerSurfaceSource",
"livePlayableWorldClient",
"providerCommandReceipts",
"sceneGraphProjection",
"playableWorldProjection",
"playableWorldScenePresentation",

View file

@ -73,7 +73,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, provider snapshot session, live playable-world client composition, playable-world scene presentation, Unity GameObject scene sink, 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, provider snapshot session, live playable-world client composition, provider command receipt observation, playable-world scene presentation, Unity GameObject scene sink, 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",
@ -122,7 +122,7 @@
"runtimes/incubating/eve-unity-scene/eve-runtime-capability.json"
],
"destinationOwner": "EveUnity",
"replacementProof": "Unity scene input emits gamecult.eve.command.v1 intents through a provider-snapshot client session, IEveUnitySceneProviderSurfaceSource, IEveUnitySceneCommandSink, and advertised command boundaries, then renders provider receipts instead of mutating local world truth."
"replacementProof": "Unity scene input emits gamecult.eve.command.v1 intents through a provider-snapshot client session, IEveUnitySceneProviderSurfaceSource, IEveUnitySceneCommandSink, IEveUnitySceneCommandReceiptSource, and advertised command boundaries, then observes provider receipts and refreshes from provider snapshots instead of mutating local world truth."
},
{
"id": "unity-scene-capture-lifecycle",
@ -162,7 +162,7 @@
"EveUnity owns a provider-agnostic scene graph lowerer that consumes advertised worldInteraction boundaries without importing Aetheria internals.",
"EveUnity owns a provider-snapshot Unity scene client session that lowers Aetheria's surface and emits command intents without importing Aetheria project code.",
"EveUnity owns provider surface source and command sink ports that a live CultMesh/CultNet adapter can implement without changing scene lowering.",
"EveUnity owns a live playable-world client coordinator that applies provider snapshots through the presenter and emits command intents through the advertised provider command sink without local simulation.",
"EveUnity owns a live playable-world client coordinator that applies provider snapshots through the presenter, observes provider command receipts, and emits command intents through the advertised provider command sink without local simulation.",
"EveUnity owns a playable-world presenter that maps provider-authored entity rows and asset refs into Unity scene operations without importing Aetheria entity or prefab classes.",
"EveUnity owns a generic Unity GameObject scene sink and asset-provider hook for playable-world rows without importing Aetheria entity or prefab classes.",
"EveUnity owns a provider asset manifest resolver that maps provider-authored asset refs and entity kinds to Unity load keys without importing Aetheria asset classes.",
@ -174,7 +174,7 @@
"EveUnity lowers at least one non-Aetheria provider-authored world surface into Unity scene objects.",
"EveUnity lowers Aetheria's game world surface into generic playableWorld projection data through provider advertisements without importing Aetheria internals.",
"A generic EveUnity scene client subscribes to the live Aetheria daemon surface over CultMesh/CultNet without Aetheria project code.",
"Unity scene input emits gamecult.eve.command.v1 intents and renders provider receipts.",
"Unity scene input emits gamecult.eve.command.v1 intents, observes provider receipts, and refreshes rendered state from provider snapshots.",
"Unity scene screenshot or frame-capture PNG artifacts are attached to conformance output."
]
}

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", "livePlayableWorldClient", "sceneGraphProjection", "playableWorldProjection", "playableWorldScenePresentation", "unityGameObjectSceneSink", "providerAssetManifestResolution", "providerAssetManifestSource", "embeddedDocuments")) {
foreach ($feature in @("providerAdvertisements", "commandTransport", "providerSurfaceSession", "providerSurfaceSource", "livePlayableWorldClient", "providerCommandReceipts", "sceneGraphProjection", "playableWorldProjection", "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", "livePlayableWorldClient", "sceneGraphProjection", "playableWorldProjection", "playableWorldScenePresentation", "unityGameObjectSceneSink", "providerAssetManifestResolution", "providerAssetManifestSource")) {
foreach ($feature in @("providerAdvertisements", "commandTransport", "providerSurfaceSession", "providerSurfaceSource", "livePlayableWorldClient", "providerCommandReceipts", "sceneGraphProjection", "playableWorldProjection", "playableWorldScenePresentation", "unityGameObjectSceneSink", "providerAssetManifestResolution", "providerAssetManifestSource")) {
if (-not (@($manifest.supportedFeatures) -contains $feature)) {
throw "EveUnity scene provider shell missing supported feature: $feature"
}
@ -106,7 +106,7 @@ foreach ($symbol in @("IEveUnitySceneProviderSurfaceSource", "IEveUnitySceneComm
}
$liveClientSource = Get-Content -LiteralPath (Join-Path $projectRoot "runtimes\incubating\eve-unity-scene\Runtime\EveUnityPlayableWorldLiveClient.cs") -Raw
foreach ($symbol in @("EveUnityPlayableWorldLiveClient", "EveUnitySceneProviderConnection", "EveUnityPlayableWorldPresenter", "ActiveWorld", "LastPresentation", "Connect", "Refresh", "SubmitMoveIntent", "SubmitFocusIntent", "SubmitTargetIntent", "SubmitActionIntent", "ProjectionUpdated", "Disconnect")) {
foreach ($symbol in @("EveUnityPlayableWorldLiveClient", "IEveUnitySceneCommandReceiptSource", "EveUnitySceneCommandReceipt", "EveUnitySceneProviderConnection", "EveUnityPlayableWorldPresenter", "ActiveWorld", "LastPresentation", "LastReceipt", "ReceiptAvailable", "Connect", "Refresh", "SubmitMoveIntent", "SubmitFocusIntent", "SubmitTargetIntent", "SubmitActionIntent", "ProjectionUpdated", "ShouldRefreshProviderSurface", "IsProviderOwned", "Disconnect")) {
if (-not $liveClientSource.Contains($symbol)) {
throw "EveUnity playable world live client missing symbol: $symbol"
}
@ -155,7 +155,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", "PlayableWorldPresenterInstantiatesUpdatesAndDespawnsProviderEntities", "LivePlayableWorldClientPresentsProviderSnapshotsAndKeepsCommandsProviderOwned", "AssetManifestMapsProviderAssetRefsToUnityLoadKeysWithoutAetheriaTypes", "AssetManifestCacheTracksPlayableWorldManifestPointerAndLiveUpdates", "FakeProviderSurfaceSource", "FakeAssetManifestSource", "FakeCommandSink", "FakePlayableWorldSceneSink", "SaiVisualNovelLowersThroughRuntimeProjectionAdapterWithoutOwningStoryState", "CommandIntentCarriesAdvertisedBoundaryWithoutOwningReceipts", "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", "PlayableWorldPresenterInstantiatesUpdatesAndDespawnsProviderEntities", "LivePlayableWorldClientPresentsProviderSnapshotsAndKeepsCommandsProviderOwned", "LivePlayableWorldClientRefreshesFromProviderSnapshotAfterReceiptWithoutOwningMovement", "AssetManifestMapsProviderAssetRefsToUnityLoadKeysWithoutAetheriaTypes", "AssetManifestCacheTracksPlayableWorldManifestPointerAndLiveUpdates", "FakeProviderSurfaceSource", "FakeCommandReceiptSource", "FakeAssetManifestSource", "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

@ -67,6 +67,7 @@ node $consumerScript $consumerExport `
--expect-runtime-feature unity-scene:providerSurfaceSession `
--expect-runtime-feature unity-scene:providerSurfaceSource `
--expect-runtime-feature unity-scene:livePlayableWorldClient `
--expect-runtime-feature unity-scene:providerCommandReceipts `
--expect-runtime-feature unity-scene:sceneGraphProjection `
--expect-runtime-feature unity-scene:playableWorldProjection `
--expect-runtime-feature unity-scene:playableWorldScenePresentation `

View file

@ -1040,7 +1040,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", "livePlayableWorldClient", "providerAssetManifestSource", "sceneGraphProjection", "playableWorldProjection", "playableWorldScenePresentation", "unityGameObjectSceneSink", "providerAssetManifestResolution", "embeddedDocuments"],
"supportedFeatures": ["providerAdvertisements", "commandTransport", "providerSurfaceSession", "providerSurfaceSource", "livePlayableWorldClient", "providerCommandReceipts", "providerAssetManifestSource", "sceneGraphProjection", "playableWorldProjection", "playableWorldScenePresentation", "unityGameObjectSceneSink", "providerAssetManifestResolution", "embeddedDocuments"],
"supportedPlugins": [
{
"pluginId": "sai.vn",
@ -1130,7 +1130,7 @@
},
{
"path": "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldLiveClient.cs",
"contains": ["EveUnityPlayableWorldLiveClient", "EveUnitySceneProviderConnection", "EveUnityPlayableWorldPresenter", "ActiveWorld", "LastPresentation", "Connect", "Refresh", "SubmitMoveIntent", "SubmitFocusIntent", "SubmitTargetIntent", "SubmitActionIntent", "ProjectionUpdated", "Disconnect"]
"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/EveUnityPlayableWorldPresenter.cs",
@ -1158,7 +1158,7 @@
},
{
"path": "runtimes/incubating/eve-unity-scene/Tests/Editor/EveUnitySceneSurfaceLowererTests.cs",
"contains": ["LowerCarriesProviderAdvertisedWorldBoundary", "LowerBuildsProviderAgnosticSceneGraphFromSurfaceTree", "LowerExtractsPlayableArpgWorldFromGenericScene3dSurface", "GenericClientSessionConsumesAetheriaPlayableWorldSnapshotWithoutAetheriaTypes", "GenericProviderConnectionAppliesLiveSnapshotsAndSubmitsCommandsThroughSink", "PlayableWorldPresenterInstantiatesUpdatesAndDespawnsProviderEntities", "LivePlayableWorldClientPresentsProviderSnapshotsAndKeepsCommandsProviderOwned", "AssetManifestMapsProviderAssetRefsToUnityLoadKeysWithoutAetheriaTypes", "AssetManifestCacheTracksPlayableWorldManifestPointerAndLiveUpdates", "FakeProviderSurfaceSource", "FakeAssetManifestSource", "FakeCommandSink", "FakePlayableWorldSceneSink", "SaiVisualNovelLowersThroughRuntimeProjectionAdapterWithoutOwningStoryState", "CommandIntentCarriesAdvertisedBoundaryWithoutOwningReceipts", "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", "PlayableWorldPresenterInstantiatesUpdatesAndDespawnsProviderEntities", "LivePlayableWorldClientPresentsProviderSnapshotsAndKeepsCommandsProviderOwned", "LivePlayableWorldClientRefreshesFromProviderSnapshotAfterReceiptWithoutOwningMovement", "AssetManifestMapsProviderAssetRefsToUnityLoadKeysWithoutAetheriaTypes", "AssetManifestCacheTracksPlayableWorldManifestPointerAndLiveUpdates", "FakeProviderSurfaceSource", "FakeCommandReceiptSource", "FakeAssetManifestSource", "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",