Add Unity scene provider source boundary

This commit is contained in:
Meta Vens 2026-07-09 18:08:34 +01:00
commit 5f29e2defc
12 changed files with 314 additions and 21 deletions

View file

@ -612,10 +612,12 @@ Recently cut:
`playableWorld` shape under `gamecult.eve.unity_scene_projection.v1`.
`EveUnitySceneClientSession` now consumes provider surface snapshots and emits
movement/focus/target/action intents through the advertised command boundary,
so the Unity client boundary is generic before it learns live transport. The
next blocker is the live generic Unity player loop: feed that session from
CultMesh/CultNet, instantiate the projected world in Unity, and wait for
provider receipts/next frames rather than renderer-local simulation.
while `EveUnitySceneProviderConnection` defines the generic surface source
and command sink ports that a CultMesh/CultNet adapter must implement. The
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, instantiate the projected world in Unity, and wait for provider
receipts/next 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

@ -481,9 +481,12 @@ entity transforms, asset refs, and daemon command affordances. The Unity scene
runtime also declares `providerSurfaceSession` and carries
`EveUnitySceneClientSession`, a provider-snapshot boundary that lowers the
active surface and emits `gamecult.eve.command.v1` intents without Aetheria
types. The remaining blocker is the live CultMesh/CultNet subscription adapter,
Unity player instantiation, and Unity screenshot or frame-capture PNG
production from EveUnity.
types. It also declares `providerSurfaceSource` through
`EveUnitySceneProviderConnection`, `IEveUnitySceneProviderSurfaceSource`, and
`IEveUnitySceneCommandSink`, so the live CultMesh/CultNet adapter has a narrow
runtime-owned port to implement. The remaining blocker is that live adapter,
Unity player instantiation, 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

@ -161,13 +161,15 @@ movement/focus/target command names, `world.entity3d` rows, and a
radii, asset refs, controllability, and command affordances. The generic
`EveUnitySceneClientSession` consumes provider surface snapshots and emits
`gamecult.eve.command.v1` intents through the advertised command boundary.
Aetheria-specific names appear only as provider-authored data and command ids;
the Unity client code does not import Aetheria runtime types or apply movement
locally.
`EveUnitySceneProviderConnection` adds the live-source port shape:
`IEveUnitySceneProviderSurfaceSource` supplies current and updated snapshots,
while `IEveUnitySceneCommandSink` receives command envelopes. Aetheria-specific
names appear only as provider-authored data and command ids; the Unity client
code does not import Aetheria runtime types or apply movement locally.
This is not yet the final playable client. The remaining cut is a live
CultMesh/CultNet provider subscription adapter feeding `EveUnitySceneClientSession`,
Unity player instantiation of the projected world, and proof that daemon
CultMesh/CultNet provider subscription adapter implementing those source/sink
ports, Unity player instantiation of the projected world, and proof that daemon
receipts drive the next frame rather than renderer-local state.
## Non-Goals

View file

@ -28,6 +28,8 @@ namespace GameCult.Eve.UnityScene
public string ActiveSourcePointer => _activeSnapshot?.SourcePointer ?? "";
public long ActiveVersion => _activeSnapshot?.Version ?? 0;
public EveUnitySceneProjection Connect(EveUnitySceneProviderSurfaceSnapshot snapshot)
{
if (snapshot == null) throw new ArgumentNullException(nameof(snapshot));

View file

@ -0,0 +1,145 @@
using System;
using GameCult.Eve.Surface;
#nullable enable
namespace GameCult.Eve.UnityScene
{
public interface IEveUnitySceneProviderSurfaceSource
{
string ProviderId { get; }
string SurfaceId { get; }
string SourcePointer { get; }
EveUnitySceneProviderSurfaceSnapshot CurrentSnapshot { get; }
event Action<EveUnitySceneProviderSurfaceSnapshot> SnapshotAvailable;
}
public interface IEveUnitySceneCommandSink
{
string SinkKind { get; }
void Submit(EveSurfaceCommandRequest request);
}
public sealed class EveUnitySceneProviderConnection : IDisposable
{
private readonly IEveUnitySceneProviderSurfaceSource _surfaceSource;
private readonly IEveUnitySceneCommandSink _commandSink;
private readonly EveUnitySceneClientSession _session;
private bool _connected;
public EveUnitySceneProviderConnection(
IEveUnitySceneProviderSurfaceSource surfaceSource,
IEveUnitySceneCommandSink commandSink)
: this(surfaceSource, commandSink, new EveUnitySceneClientSession())
{
}
public EveUnitySceneProviderConnection(
IEveUnitySceneProviderSurfaceSource surfaceSource,
IEveUnitySceneCommandSink commandSink,
EveUnitySceneClientSession session)
{
_surfaceSource = surfaceSource ?? throw new ArgumentNullException(nameof(surfaceSource));
_commandSink = commandSink ?? throw new ArgumentNullException(nameof(commandSink));
_session = session ?? throw new ArgumentNullException(nameof(session));
}
public string ProviderId => _surfaceSource.ProviderId;
public string SurfaceId => _surfaceSource.SurfaceId;
public string SourcePointer => _surfaceSource.SourcePointer;
public EveUnitySceneProjection? ActiveProjection => _session.ActiveProjection;
public long ActiveVersion => _session.ActiveVersion;
public event Action<EveUnitySceneProjection>? ProjectionUpdated;
public EveUnitySceneProjection Connect()
{
if (!_connected)
{
_surfaceSource.SnapshotAvailable += OnSnapshotAvailable;
_connected = true;
}
return ApplySnapshot(_surfaceSource.CurrentSnapshot);
}
public EveUnitySceneProjection Refresh()
{
return ApplySnapshot(_surfaceSource.CurrentSnapshot);
}
public EveSurfaceCommandRequest SubmitMoveIntent(
string entityId,
float targetX,
float targetY,
float targetZ,
DateTimeOffset? issuedAt = null)
{
return Submit(_session.CreateMoveIntent(entityId, targetX, targetY, targetZ, issuedAt));
}
public EveSurfaceCommandRequest SubmitFocusIntent(
string entityId,
DateTimeOffset? issuedAt = null)
{
return Submit(_session.CreateFocusIntent(entityId, issuedAt));
}
public EveSurfaceCommandRequest SubmitTargetIntent(
string sourceEntityId,
string targetEntityId,
DateTimeOffset? issuedAt = null)
{
return Submit(_session.CreateTargetIntent(sourceEntityId, targetEntityId, issuedAt));
}
public EveSurfaceCommandRequest SubmitActionIntent(
string entityId,
string actionId,
DateTimeOffset? issuedAt = null)
{
return Submit(_session.CreateActionIntent(entityId, actionId, issuedAt));
}
public void Disconnect()
{
if (!_connected)
return;
_surfaceSource.SnapshotAvailable -= OnSnapshotAvailable;
_connected = false;
}
public void Dispose()
{
Disconnect();
}
private EveSurfaceCommandRequest Submit(EveSurfaceCommandRequest request)
{
_commandSink.Submit(request);
return request;
}
private EveUnitySceneProjection ApplySnapshot(EveUnitySceneProviderSurfaceSnapshot snapshot)
{
var projection = _session.ApplySnapshot(snapshot);
ProjectionUpdated?.Invoke(projection);
return projection;
}
private void OnSnapshotAvailable(EveUnitySceneProviderSurfaceSnapshot snapshot)
{
ApplySnapshot(snapshot);
}
}
}

View file

@ -131,6 +131,73 @@ namespace GameCult.Eve.UnityScene.Tests
Assert.That(focusIntent.CommandBoundary, Is.EqualTo("aetheria.daemon.commands"));
}
[Test]
public void GenericProviderConnectionAppliesLiveSnapshotsAndSubmitsCommandsThroughSink()
{
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 sink = new FakeCommandSink("cultmesh-command-sink");
using var connection = new EveUnitySceneProviderConnection(source, sink);
var projectionUpdates = 0;
connection.ProjectionUpdated += _ => projectionUpdates++;
var initialProjection = connection.Connect();
Assert.That(initialProjection.ProviderId, Is.EqualTo("aetheria"));
Assert.That(connection.ProviderId, Is.EqualTo("aetheria"));
Assert.That(connection.SurfaceId, Is.EqualTo("aetheria.daemon.game"));
Assert.That(connection.SourcePointer, Is.EqualTo("cultmesh://aetheria/eve/surfaces/aetheria.daemon.game"));
Assert.That(connection.ActiveVersion, Is.EqualTo(1));
Assert.That(projectionUpdates, Is.EqualTo(1));
source.Publish(new EveUnitySceneProviderSurfaceSnapshot(
PlayableArpgDocument(),
Advertisement("aetheria.daemon.game"),
"cultmesh://aetheria/eve/surfaces/aetheria.daemon.game",
2));
Assert.That(connection.ActiveVersion, Is.EqualTo(2));
Assert.That(connection.ActiveProjection, Is.Not.Null);
Assert.That(connection.ActiveProjection!.PlayableWorld, Is.Not.Null);
Assert.That(connection.ActiveProjection.PlayableWorld!.PlayerEntityId, Is.EqualTo("player-vanguard"));
Assert.That(projectionUpdates, Is.EqualTo(2));
var moveIntent = connection.SubmitMoveIntent(
"player-vanguard",
20f,
0f,
15f,
DateTimeOffset.Parse("2026-07-09T00:00:00Z"));
Assert.That(sink.SinkKind, Is.EqualTo("cultmesh-command-sink"));
Assert.That(sink.Submitted.Count, Is.EqualTo(1));
Assert.That(sink.Submitted[0], Is.SameAs(moveIntent));
Assert.That(moveIntent.Schema, Is.EqualTo(EveSurfaceCommandRequest.SchemaId));
Assert.That(moveIntent.ProviderId, Is.EqualTo("aetheria"));
Assert.That(moveIntent.SurfaceId, Is.EqualTo("aetheria.daemon.game"));
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"));
connection.Disconnect();
source.Publish(new EveUnitySceneProviderSurfaceSnapshot(
PlayableArpgDocument(),
Advertisement("aetheria.daemon.game"),
"cultmesh://aetheria/eve/surfaces/aetheria.daemon.game",
3));
Assert.That(connection.ActiveVersion, Is.EqualTo(2));
Assert.That(projectionUpdates, Is.EqualTo(2));
}
[Test]
public void SaiVisualNovelLowersThroughRuntimeProjectionAdapterWithoutOwningStoryState()
{
@ -490,5 +557,53 @@ namespace GameCult.Eve.UnityScene.Tests
"aetheria.eve_command_acceptance_status.v1",
"provider-owns-world-state-assets-command-acceptance-and-receipts"));
}
private sealed class FakeProviderSurfaceSource : IEveUnitySceneProviderSurfaceSource
{
public FakeProviderSurfaceSource(
string providerId,
string surfaceId,
string sourcePointer,
EveUnitySceneProviderSurfaceSnapshot currentSnapshot)
{
ProviderId = providerId;
SurfaceId = surfaceId;
SourcePointer = sourcePointer;
CurrentSnapshot = currentSnapshot;
}
public string ProviderId { get; }
public string SurfaceId { get; }
public string SourcePointer { get; }
public EveUnitySceneProviderSurfaceSnapshot CurrentSnapshot { get; private set; }
public event Action<EveUnitySceneProviderSurfaceSnapshot>? SnapshotAvailable;
public void Publish(EveUnitySceneProviderSurfaceSnapshot snapshot)
{
CurrentSnapshot = snapshot;
SnapshotAvailable?.Invoke(snapshot);
}
}
private sealed class FakeCommandSink : IEveUnitySceneCommandSink
{
public FakeCommandSink(string sinkKind)
{
SinkKind = sinkKind;
}
public string SinkKind { get; }
public List<EveSurfaceCommandRequest> Submitted { get; } = new List<EveSurfaceCommandRequest>();
public void Submit(EveSurfaceCommandRequest request)
{
Submitted.Add(request);
}
}
}
}

View file

@ -17,6 +17,7 @@
"providerAdvertisements",
"commandTransport",
"providerSurfaceSession",
"providerSurfaceSource",
"sceneGraphProjection",
"playableWorldProjection",
"embeddedDocuments"
@ -61,6 +62,7 @@
"evidencePaths": [
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneClientSession.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneProviderConnection.cs",
"runtimes/incubating/eve-unity-scene/Runtime/SaiVisualNovelUnitySceneProjectionAdapter.cs",
"runtimes/incubating/eve-unity-scene/Runtime/NornGraphUnitySceneProjectionAdapter.cs",
"runtimes/incubating/eve-unity-scene/Runtime/TeXMathUnitySceneProjectionAdapter.cs",
@ -108,6 +110,7 @@
"runtimes/incubating/eve-unity-scene/Runtime/GameCult.Eve.UnityScene.asmdef",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneClientSession.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneProviderConnection.cs",
"runtimes/incubating/eve-unity-scene/Runtime/SaiVisualNovelUnitySceneProjectionAdapter.cs",
"runtimes/incubating/eve-unity-scene/Runtime/NornGraphUnitySceneProjectionAdapter.cs",
"runtimes/incubating/eve-unity-scene/Runtime/TeXMathUnitySceneProjectionAdapter.cs",
@ -144,6 +147,7 @@
"runtimes/incubating/eve-unity-scene/Runtime/GameCult.Eve.UnityScene.asmdef",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneClientSession.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneProviderConnection.cs",
"runtimes/incubating/eve-unity-scene/Runtime/SaiVisualNovelUnitySceneProjectionAdapter.cs",
"runtimes/incubating/eve-unity-scene/Runtime/NornGraphUnitySceneProjectionAdapter.cs",
"runtimes/incubating/eve-unity-scene/Runtime/TeXMathUnitySceneProjectionAdapter.cs",
@ -155,7 +159,7 @@
],
"pendingProofs": [
"Unity scene provider-advertisement smoke runs from EveUnity with real Unity scene/frame objects and no Aetheria imports.",
"Live CultMesh/CultNet provider subscription adapter feeds EveUnitySceneClientSession snapshots instead of Eve-local fixture documents."
"Live CultMesh/CultNet provider subscription adapter implements IEveUnitySceneProviderSurfaceSource and feeds EveUnitySceneClientSession snapshots instead of Eve-local fixture documents."
]
},
"capture": {

View file

@ -17,6 +17,7 @@
"runtimes/incubating/eve-unity-scene/Runtime/GameCult.Eve.UnityScene.asmdef",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneClientSession.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneProviderConnection.cs",
"runtimes/incubating/eve-unity-scene/Runtime/SaiVisualNovelUnitySceneProjectionAdapter.cs",
"runtimes/incubating/eve-unity-scene/Runtime/NornGraphUnitySceneProjectionAdapter.cs",
"runtimes/incubating/eve-unity-scene/Runtime/TeXMathUnitySceneProjectionAdapter.cs",
@ -34,6 +35,7 @@
"runtimes/incubating/eve-unity-scene/Runtime/GameCult.Eve.UnityScene.asmdef",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneClientSession.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneProviderConnection.cs",
"runtimes/incubating/eve-unity-scene/Tests/Editor/GameCult.Eve.UnityScene.Tests.asmdef",
"tools/eveunity/eveunity-release-contract.mjs",
"tools/eveunity/eveunity-release-contract.test.mjs",
@ -51,6 +53,7 @@
"currentPaths": [
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneClientSession.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneProviderConnection.cs",
"runtimes/incubating/eve-unity-scene/Runtime/SaiVisualNovelUnitySceneProjectionAdapter.cs",
"runtimes/incubating/eve-unity-scene/Runtime/NornGraphUnitySceneProjectionAdapter.cs",
"runtimes/incubating/eve-unity-scene/Runtime/TeXMathUnitySceneProjectionAdapter.cs",
@ -102,11 +105,12 @@
"currentPaths": [
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneClientSession.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneProviderConnection.cs",
"runtimes/incubating/eve-unity-scene/Tests/Editor/EveUnitySceneSurfaceLowererTests.cs",
"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 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, and advertised command boundaries, then renders provider receipts instead of mutating local world truth."
},
{
"id": "unity-scene-capture-lifecycle",
@ -145,6 +149,7 @@
"EveUnity builds the provider-agnostic Unity scene UPM package artifact.",
"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 the provider-agnostic playable-world scene lowerer outside Eve incubation.",
"EveUnity owns the Unity scene Sai projection adapter outside Eve incubation without importing Sai story state or VN/Ink internals.",
"EveUnity owns the Unity scene Norn projection adapter outside Eve incubation without importing Norn implementation state.",

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", "sceneGraphProjection", "playableWorldProjection", "embeddedDocuments")) {
foreach ($feature in @("providerAdvertisements", "commandTransport", "providerSurfaceSession", "providerSurfaceSource", "sceneGraphProjection", "playableWorldProjection", "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", "sceneGraphProjection", "playableWorldProjection")) {
foreach ($feature in @("providerAdvertisements", "commandTransport", "providerSurfaceSession", "providerSurfaceSource", "sceneGraphProjection", "playableWorldProjection")) {
if (-not (@($manifest.supportedFeatures) -contains $feature)) {
throw "EveUnity scene provider shell missing supported feature: $feature"
}
@ -65,6 +65,7 @@ $expectedFiles = @(
"runtimes\incubating\eve-unity-scene\Runtime\GameCult.Eve.UnityScene.asmdef",
"runtimes\incubating\eve-unity-scene\Runtime\EveUnitySceneSurfaceLowerer.cs",
"runtimes\incubating\eve-unity-scene\Runtime\EveUnitySceneClientSession.cs",
"runtimes\incubating\eve-unity-scene\Runtime\EveUnitySceneProviderConnection.cs",
"runtimes\incubating\eve-unity-scene\Runtime\SaiVisualNovelUnitySceneProjectionAdapter.cs",
"runtimes\incubating\eve-unity-scene\Runtime\NornGraphUnitySceneProjectionAdapter.cs",
"runtimes\incubating\eve-unity-scene\Runtime\TeXMathUnitySceneProjectionAdapter.cs",
@ -87,12 +88,19 @@ foreach ($symbol in @("EveUnitySceneSurfaceLowerer", "EveUnitySceneProviderSurfa
}
$clientSessionSource = Get-Content -LiteralPath (Join-Path $projectRoot "runtimes\incubating\eve-unity-scene\Runtime\EveUnitySceneClientSession.cs") -Raw
foreach ($symbol in @("EveUnitySceneClientSession", "EveUnitySceneProviderSurfaceSnapshot", "Connect", "ApplySnapshot", "CreateMoveIntent", "CreateFocusIntent", "CreateTargetIntent", "CreateActionIntent", "CreatePlayableWorldIntent", "commandId", "targetPosition", "unity-scene")) {
foreach ($symbol in @("EveUnitySceneClientSession", "EveUnitySceneProviderSurfaceSnapshot", "ActiveVersion", "Connect", "ApplySnapshot", "CreateMoveIntent", "CreateFocusIntent", "CreateTargetIntent", "CreateActionIntent", "CreatePlayableWorldIntent", "commandId", "targetPosition", "unity-scene")) {
if (-not $clientSessionSource.Contains($symbol)) {
throw "EveUnity scene client session missing symbol: $symbol"
}
}
$providerConnectionSource = Get-Content -LiteralPath (Join-Path $projectRoot "runtimes\incubating\eve-unity-scene\Runtime\EveUnitySceneProviderConnection.cs") -Raw
foreach ($symbol in @("IEveUnitySceneProviderSurfaceSource", "IEveUnitySceneCommandSink", "EveUnitySceneProviderConnection", "SnapshotAvailable", "CurrentSnapshot", "Connect", "Refresh", "SubmitMoveIntent", "SubmitFocusIntent", "SubmitTargetIntent", "SubmitActionIntent", "Disconnect")) {
if (-not $providerConnectionSource.Contains($symbol)) {
throw "EveUnity scene provider connection missing symbol: $symbol"
}
}
$saiAdapterSource = Get-Content -LiteralPath (Join-Path $projectRoot "runtimes\incubating\eve-unity-scene\Runtime\SaiVisualNovelUnitySceneProjectionAdapter.cs") -Raw
foreach ($symbol in @("SaiVisualNovelUnitySceneProjectionAdapter", "sai.vn", "vn.stage", "story.choose", "story.continue", "story.jump", "gamecult.eve.plugin_abi.v1", "sidecar-advertised-plugin-abi", "Sai")) {
if (-not $saiAdapterSource.Contains($symbol)) {
@ -115,7 +123,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", "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", "FakeProviderSurfaceSource", "FakeCommandSink", "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")) {
if (-not $testSource.Contains($symbol)) {
throw "EveUnity scene provider shell tests missing symbol: $symbol"
}

View file

@ -65,6 +65,7 @@ node $consumerScript $consumerExport `
--expect-runtime-feature unity-scene:providerAdvertisements `
--expect-runtime-feature unity-scene:commandTransport `
--expect-runtime-feature unity-scene:providerSurfaceSession `
--expect-runtime-feature unity-scene:providerSurfaceSource `
--expect-runtime-feature unity-scene:sceneGraphProjection `
--expect-runtime-feature unity-scene:playableWorldProjection `
--expect-runtime-feature electron-shell:providerAdvertisements `

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", "sceneGraphProjection", "playableWorldProjection", "embeddedDocuments"],
"supportedFeatures": ["providerAdvertisements", "commandTransport", "providerSurfaceSession", "providerSurfaceSource", "sceneGraphProjection", "playableWorldProjection", "embeddedDocuments"],
"supportedPlugins": [
{
"pluginId": "sai.vn",
@ -1069,6 +1069,7 @@
"evidencePaths": [
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneClientSession.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneProviderConnection.cs",
"runtimes/incubating/eve-unity-scene/Runtime/SaiVisualNovelUnitySceneProjectionAdapter.cs",
"runtimes/incubating/eve-unity-scene/Runtime/NornGraphUnitySceneProjectionAdapter.cs",
"runtimes/incubating/eve-unity-scene/Runtime/TeXMathUnitySceneProjectionAdapter.cs",
@ -1083,6 +1084,7 @@
"runtimes/incubating/eve-unity-scene/Runtime/GameCult.Eve.UnityScene.asmdef",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneClientSession.cs",
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneProviderConnection.cs",
"runtimes/incubating/eve-unity-scene/Runtime/SaiVisualNovelUnitySceneProjectionAdapter.cs",
"runtimes/incubating/eve-unity-scene/Runtime/NornGraphUnitySceneProjectionAdapter.cs",
"runtimes/incubating/eve-unity-scene/Runtime/TeXMathUnitySceneProjectionAdapter.cs",
@ -1112,7 +1114,11 @@
},
{
"path": "runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneClientSession.cs",
"contains": ["EveUnitySceneClientSession", "EveUnitySceneProviderSurfaceSnapshot", "Connect", "ApplySnapshot", "CreateMoveIntent", "CreateFocusIntent", "CreateTargetIntent", "CreateActionIntent", "CreatePlayableWorldIntent", "commandId", "targetPosition", "unity-scene"]
"contains": ["EveUnitySceneClientSession", "EveUnitySceneProviderSurfaceSnapshot", "ActiveVersion", "Connect", "ApplySnapshot", "CreateMoveIntent", "CreateFocusIntent", "CreateTargetIntent", "CreateActionIntent", "CreatePlayableWorldIntent", "commandId", "targetPosition", "unity-scene"]
},
{
"path": "runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneProviderConnection.cs",
"contains": ["IEveUnitySceneProviderSurfaceSource", "IEveUnitySceneCommandSink", "EveUnitySceneProviderConnection", "SnapshotAvailable", "CurrentSnapshot", "Connect", "Refresh", "SubmitMoveIntent", "SubmitFocusIntent", "SubmitTargetIntent", "SubmitActionIntent", "Disconnect"]
},
{
"path": "runtimes/incubating/eve-unity-scene/Runtime/SaiVisualNovelUnitySceneProjectionAdapter.cs",
@ -1128,7 +1134,7 @@
},
{
"path": "runtimes/incubating/eve-unity-scene/Tests/Editor/EveUnitySceneSurfaceLowererTests.cs",
"contains": ["LowerCarriesProviderAdvertisedWorldBoundary", "LowerBuildsProviderAgnosticSceneGraphFromSurfaceTree", "LowerExtractsPlayableArpgWorldFromGenericScene3dSurface", "GenericClientSessionConsumesAetheriaPlayableWorldSnapshotWithoutAetheriaTypes", "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", "FakeProviderSurfaceSource", "FakeCommandSink", "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"]
},
{
"path": "tools/eveunity/eveunity-capture-contract.test.mjs",