Add Unity playable world asset manifest resolver

This commit is contained in:
Meta Vens 2026-07-09 18:24:27 +01:00
commit 7b15a99d02
12 changed files with 215 additions and 39 deletions

View file

@ -620,10 +620,13 @@ Recently cut:
classes. `EveUnityGameObjectPlayableWorldSceneSink` now provides the first
Unity-native sink body: generic `GameObject` creation/update/removal,
transform/radius application, entity markers, and a swappable asset-provider
hook. 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, resolve provider assets through CultMesh/CultCache
manifests, and wait for provider receipts/next frames rather than
hook. `EveUnityPlayableWorldAssetManifest` and
`EveUnityManifestGameObjectAssetProvider` map provider-authored asset refs and
entity kinds to Unity resource/prefab keys through data, not Aetheria code.
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, load provider asset manifests from
CultMesh/CultCache, 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

View file

@ -491,9 +491,12 @@ removing entities absent from later provider snapshots. The runtime now also
declares `unityGameObjectSceneSink`: `EveUnityGameObjectPlayableWorldSceneSink`
creates or updates generic `GameObject` instances, attaches
`EveUnityPlayableWorldEntityMarker`, and resolves prefabs through a swappable
asset-provider hook. The remaining blocker is the live adapter, provider asset
resolution against CultMesh/CultCache manifests, and Unity screenshot or
frame-capture PNG production from EveUnity.
asset-provider hook. The runtime now also declares
`providerAssetManifestResolution`: `EveUnityPlayableWorldAssetManifest` and
`EveUnityManifestGameObjectAssetProvider` map provider-authored asset refs and
entity kinds to Unity resource/prefab keys through data. The remaining blocker
is the live adapter, loading provider asset manifests from CultMesh/CultCache,
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

@ -171,15 +171,18 @@ disappear from later provider snapshots. `EveUnityGameObjectPlayableWorldSceneSi
is the first Unity-native implementation: it creates or updates generic
`GameObject` instances, applies transforms/radii, attaches an
`EveUnityPlayableWorldEntityMarker`, and resolves provider asset refs through an
`IEveUnityGameObjectAssetProvider` hook. Aetheria-specific names appear only as
`IEveUnityGameObjectAssetProvider` hook. `EveUnityPlayableWorldAssetManifest`
and `EveUnityManifestGameObjectAssetProvider` add the provider-manifest mapping
step: provider asset refs and entity kinds become Unity resource/prefab keys
through data rather than Aetheria code. 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 source/sink
ports, provider asset resolution against CultMesh/CultCache manifests, and proof
that daemon receipts drive the next rendered Unity frame rather than
renderer-local state.
ports, loading the provider asset manifest from CultMesh/CultCache instead of a
local constructed manifest object, and proof that daemon receipts drive the next
rendered Unity frame rather than renderer-local state.
## Non-Goals

View file

@ -122,32 +122,11 @@ namespace GameCult.Eve.UnityScene
public GameObject? ResolvePrefab(EveUnityPlayableWorldAssetBinding asset)
{
if (asset == null) throw new ArgumentNullException(nameof(asset));
var resourcesPath = NormalizeResourcesPath(asset.AssetRef);
var resourcesPath = EveUnityPlayableWorldAssetManifestEntry.NormalizeResourcesPath(asset.AssetRef);
return string.IsNullOrWhiteSpace(resourcesPath)
? null
: Resources.Load<GameObject>(resourcesPath);
}
private static string NormalizeResourcesPath(string assetRef)
{
if (string.IsNullOrWhiteSpace(assetRef))
return "";
var path = assetRef.Trim();
foreach (var prefix in new[] { "resources://", "resource://", "Resources/" })
{
if (path.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
{
path = path.Substring(prefix.Length);
break;
}
}
if (path.EndsWith(".prefab", StringComparison.OrdinalIgnoreCase))
path = path.Substring(0, path.Length - ".prefab".Length);
return path;
}
}
public sealed class EveUnityPlayableWorldEntityMarker : MonoBehaviour

View file

@ -0,0 +1,129 @@
using System;
using System.Collections.Generic;
using UnityEngine;
#nullable enable
namespace GameCult.Eve.UnityScene
{
public sealed class EveUnityPlayableWorldAssetManifest
{
private readonly Dictionary<string, EveUnityPlayableWorldAssetManifestEntry> _byAssetRef =
new Dictionary<string, EveUnityPlayableWorldAssetManifestEntry>(StringComparer.Ordinal);
private readonly Dictionary<string, EveUnityPlayableWorldAssetManifestEntry> _byEntityKind =
new Dictionary<string, EveUnityPlayableWorldAssetManifestEntry>(StringComparer.Ordinal);
public EveUnityPlayableWorldAssetManifest(
string manifestRef,
IReadOnlyList<EveUnityPlayableWorldAssetManifestEntry> entries)
{
ManifestRef = manifestRef ?? "";
Entries = entries ?? Array.Empty<EveUnityPlayableWorldAssetManifestEntry>();
foreach (var entry in Entries)
{
if (entry == null)
continue;
if (!string.IsNullOrWhiteSpace(entry.AssetRef))
_byAssetRef[entry.AssetRef] = entry;
if (!string.IsNullOrWhiteSpace(entry.EntityKind))
_byEntityKind[entry.EntityKind] = entry;
}
}
public string ManifestRef { get; }
public IReadOnlyList<EveUnityPlayableWorldAssetManifestEntry> Entries { get; }
public EveUnityPlayableWorldAssetManifestEntry? Find(EveUnityPlayableWorldAssetBinding asset)
{
if (asset == null) throw new ArgumentNullException(nameof(asset));
EveUnityPlayableWorldAssetManifestEntry entry;
if (!string.IsNullOrWhiteSpace(asset.AssetRef) && _byAssetRef.TryGetValue(asset.AssetRef, out entry))
return entry;
if (!string.IsNullOrWhiteSpace(asset.EntityKind) && _byEntityKind.TryGetValue(asset.EntityKind, out entry))
return entry;
return null;
}
}
public sealed class EveUnityPlayableWorldAssetManifestEntry
{
public EveUnityPlayableWorldAssetManifestEntry(
string assetRef,
string entityKind,
string resourcesPath,
string prefabKey,
string presentationKind = "provider-asset-ref")
{
AssetRef = assetRef ?? "";
EntityKind = entityKind ?? "";
ResourcesPath = NormalizeResourcesPath(resourcesPath);
PrefabKey = prefabKey ?? "";
PresentationKind = presentationKind ?? "";
}
public string AssetRef { get; }
public string EntityKind { get; }
public string ResourcesPath { get; }
public string PrefabKey { get; }
public string PresentationKind { get; }
public static string NormalizeResourcesPath(string path)
{
if (string.IsNullOrWhiteSpace(path))
return "";
var normalized = path.Trim();
foreach (var prefix in new[] { "resources://", "resource://", "Resources/" })
{
if (normalized.StartsWith(prefix, StringComparison.OrdinalIgnoreCase))
{
normalized = normalized.Substring(prefix.Length);
break;
}
}
if (normalized.EndsWith(".prefab", StringComparison.OrdinalIgnoreCase))
normalized = normalized.Substring(0, normalized.Length - ".prefab".Length);
return normalized;
}
}
public sealed class EveUnityManifestGameObjectAssetProvider : IEveUnityGameObjectAssetProvider
{
private readonly EveUnityPlayableWorldAssetManifest _manifest;
private readonly IEveUnityGameObjectAssetProvider? _fallback;
public EveUnityManifestGameObjectAssetProvider(
EveUnityPlayableWorldAssetManifest manifest,
IEveUnityGameObjectAssetProvider? fallback = null)
{
_manifest = manifest ?? throw new ArgumentNullException(nameof(manifest));
_fallback = fallback;
}
public string ManifestRef => _manifest.ManifestRef;
public GameObject? ResolvePrefab(EveUnityPlayableWorldAssetBinding asset)
{
if (asset == null) throw new ArgumentNullException(nameof(asset));
var entry = _manifest.Find(asset);
if (entry != null && !string.IsNullOrWhiteSpace(entry.ResourcesPath))
{
var prefab = Resources.Load<GameObject>(entry.ResourcesPath);
if (prefab != null)
return prefab;
}
return _fallback?.ResolvePrefab(asset);
}
}
}

View file

@ -238,6 +238,42 @@ namespace GameCult.Eve.UnityScene.Tests
Assert.That(sink.Upserts[3].entity.PositionZ, Is.EqualTo(2f));
}
[Test]
public void AssetManifestMapsProviderAssetRefsToUnityLoadKeysWithoutAetheriaTypes()
{
var manifest = new EveUnityPlayableWorldAssetManifest(
"cultmesh://aetheria/assets/manifest",
new[]
{
new EveUnityPlayableWorldAssetManifestEntry(
"cultmesh://aetheria/assets/map/entity/player",
"player",
"resources://Aetheria/Entities/Vanguard.prefab",
"aetheria.vanguard"),
new EveUnityPlayableWorldAssetManifestEntry(
"",
"enemy",
"Resources/Aetheria/Entities/Raider.prefab",
"aetheria.raider")
});
var player = manifest.Find(new EveUnityPlayableWorldAssetBinding(
"cultmesh://aetheria/assets/map/entity/player",
"player",
"provider-asset-ref"));
Assert.That(player, Is.Not.Null);
Assert.That(player!.ResourcesPath, Is.EqualTo("Aetheria/Entities/Vanguard"));
Assert.That(player.PrefabKey, Is.EqualTo("aetheria.vanguard"));
var enemy = manifest.Find(new EveUnityPlayableWorldAssetBinding(
"cultmesh://aetheria/assets/map/entity/missing-raider",
"enemy",
"provider-asset-ref"));
Assert.That(enemy, Is.Not.Null);
Assert.That(enemy!.ResourcesPath, Is.EqualTo("Aetheria/Entities/Raider"));
Assert.That(enemy.PrefabKey, Is.EqualTo("aetheria.raider"));
}
[Test]
public void SaiVisualNovelLowersThroughRuntimeProjectionAdapterWithoutOwningStoryState()
{

View file

@ -22,6 +22,7 @@
"playableWorldProjection",
"playableWorldScenePresentation",
"unityGameObjectSceneSink",
"providerAssetManifestResolution",
"embeddedDocuments"
],
"supportedPlugins": [
@ -67,6 +68,7 @@
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneProviderConnection.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",
"runtimes/incubating/eve-unity-scene/Runtime/SaiVisualNovelUnitySceneProjectionAdapter.cs",
"runtimes/incubating/eve-unity-scene/Runtime/NornGraphUnitySceneProjectionAdapter.cs",
"runtimes/incubating/eve-unity-scene/Runtime/TeXMathUnitySceneProjectionAdapter.cs",
@ -117,6 +119,7 @@
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneProviderConnection.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",
"runtimes/incubating/eve-unity-scene/Runtime/SaiVisualNovelUnitySceneProjectionAdapter.cs",
"runtimes/incubating/eve-unity-scene/Runtime/NornGraphUnitySceneProjectionAdapter.cs",
"runtimes/incubating/eve-unity-scene/Runtime/TeXMathUnitySceneProjectionAdapter.cs",
@ -156,6 +159,7 @@
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneProviderConnection.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",
"runtimes/incubating/eve-unity-scene/Runtime/SaiVisualNovelUnitySceneProjectionAdapter.cs",
"runtimes/incubating/eve-unity-scene/Runtime/NornGraphUnitySceneProjectionAdapter.cs",
"runtimes/incubating/eve-unity-scene/Runtime/TeXMathUnitySceneProjectionAdapter.cs",

View file

@ -20,6 +20,7 @@
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneProviderConnection.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",
"runtimes/incubating/eve-unity-scene/Runtime/SaiVisualNovelUnitySceneProjectionAdapter.cs",
"runtimes/incubating/eve-unity-scene/Runtime/NornGraphUnitySceneProjectionAdapter.cs",
"runtimes/incubating/eve-unity-scene/Runtime/TeXMathUnitySceneProjectionAdapter.cs",
@ -40,6 +41,7 @@
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneProviderConnection.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",
"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",
@ -60,6 +62,7 @@
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneProviderConnection.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",
"runtimes/incubating/eve-unity-scene/Runtime/SaiVisualNovelUnitySceneProjectionAdapter.cs",
"runtimes/incubating/eve-unity-scene/Runtime/NornGraphUnitySceneProjectionAdapter.cs",
"runtimes/incubating/eve-unity-scene/Runtime/TeXMathUnitySceneProjectionAdapter.cs",
@ -67,7 +70,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, playable-world scene presentation, Unity GameObject scene sink, 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, playable-world scene presentation, Unity GameObject scene sink, provider asset manifest resolution, and command boundary evidence; live transport and capture remain separate lifecycle proofs."
},
{
"id": "unity-scene-sai-plugin-projection",
@ -158,6 +161,7 @@
"EveUnity owns provider surface source and command sink ports that a live CultMesh/CultNet adapter can implement without changing scene lowering.",
"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.",
"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", "providerSurfaceSource", "sceneGraphProjection", "playableWorldProjection", "playableWorldScenePresentation", "unityGameObjectSceneSink", "embeddedDocuments")) {
foreach ($feature in @("providerAdvertisements", "commandTransport", "providerSurfaceSession", "providerSurfaceSource", "sceneGraphProjection", "playableWorldProjection", "playableWorldScenePresentation", "unityGameObjectSceneSink", "providerAssetManifestResolution", "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", "sceneGraphProjection", "playableWorldProjection", "playableWorldScenePresentation", "unityGameObjectSceneSink")) {
foreach ($feature in @("providerAdvertisements", "commandTransport", "providerSurfaceSession", "providerSurfaceSource", "sceneGraphProjection", "playableWorldProjection", "playableWorldScenePresentation", "unityGameObjectSceneSink", "providerAssetManifestResolution")) {
if (-not (@($manifest.supportedFeatures) -contains $feature)) {
throw "EveUnity scene provider shell missing supported feature: $feature"
}
@ -68,6 +68,7 @@ $expectedFiles = @(
"runtimes\incubating\eve-unity-scene\Runtime\EveUnitySceneProviderConnection.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",
"runtimes\incubating\eve-unity-scene\Runtime\SaiVisualNovelUnitySceneProjectionAdapter.cs",
"runtimes\incubating\eve-unity-scene\Runtime\NornGraphUnitySceneProjectionAdapter.cs",
"runtimes\incubating\eve-unity-scene\Runtime\TeXMathUnitySceneProjectionAdapter.cs",
@ -117,6 +118,13 @@ foreach ($symbol in @("EveUnityGameObjectPlayableWorldSceneSink", "IEveUnityGame
}
}
$assetManifestSource = Get-Content -LiteralPath (Join-Path $projectRoot "runtimes\incubating\eve-unity-scene\Runtime\EveUnityPlayableWorldAssetManifest.cs") -Raw
foreach ($symbol in @("EveUnityPlayableWorldAssetManifest", "EveUnityPlayableWorldAssetManifestEntry", "EveUnityManifestGameObjectAssetProvider", "ManifestRef", "ResourcesPath", "PrefabKey", "NormalizeResourcesPath", "ResolvePrefab", "Resources.Load")) {
if (-not $assetManifestSource.Contains($symbol)) {
throw "EveUnity playable world asset manifest 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)) {
@ -139,7 +147,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", "FakeProviderSurfaceSource", "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", "AssetManifestMapsProviderAssetRefsToUnityLoadKeysWithoutAetheriaTypes", "FakeProviderSurfaceSource", "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")) {
if (-not $testSource.Contains($symbol)) {
throw "EveUnity scene provider shell tests missing symbol: $symbol"
}

View file

@ -70,6 +70,7 @@ node $consumerScript $consumerExport `
--expect-runtime-feature unity-scene:playableWorldProjection `
--expect-runtime-feature unity-scene:playableWorldScenePresentation `
--expect-runtime-feature unity-scene:unityGameObjectSceneSink `
--expect-runtime-feature unity-scene:providerAssetManifestResolution `
--expect-runtime-feature electron-shell:providerAdvertisements `
--expect-runtime-feature electron-shell:commandTransport `
--expect-runtime-feature electron-shell:surfaceTreeProjection `

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", "sceneGraphProjection", "playableWorldProjection", "playableWorldScenePresentation", "unityGameObjectSceneSink", "embeddedDocuments"],
"supportedFeatures": ["providerAdvertisements", "commandTransport", "providerSurfaceSession", "providerSurfaceSource", "sceneGraphProjection", "playableWorldProjection", "playableWorldScenePresentation", "unityGameObjectSceneSink", "providerAssetManifestResolution", "embeddedDocuments"],
"supportedPlugins": [
{
"pluginId": "sai.vn",
@ -1072,6 +1072,7 @@
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneProviderConnection.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",
"runtimes/incubating/eve-unity-scene/Runtime/SaiVisualNovelUnitySceneProjectionAdapter.cs",
"runtimes/incubating/eve-unity-scene/Runtime/NornGraphUnitySceneProjectionAdapter.cs",
"runtimes/incubating/eve-unity-scene/Runtime/TeXMathUnitySceneProjectionAdapter.cs",
@ -1089,6 +1090,7 @@
"runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneProviderConnection.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",
"runtimes/incubating/eve-unity-scene/Runtime/SaiVisualNovelUnitySceneProjectionAdapter.cs",
"runtimes/incubating/eve-unity-scene/Runtime/NornGraphUnitySceneProjectionAdapter.cs",
"runtimes/incubating/eve-unity-scene/Runtime/TeXMathUnitySceneProjectionAdapter.cs",
@ -1132,6 +1134,10 @@
"path": "runtimes/incubating/eve-unity-scene/Runtime/EveUnityGameObjectPlayableWorldSceneSink.cs",
"contains": ["EveUnityGameObjectPlayableWorldSceneSink", "IEveUnityGameObjectAssetProvider", "EveUnityResourcesAssetProvider", "EveUnityPlayableWorldEntityMarker", "GameObject", "Transform", "Resources.Load", "PrimitiveType.Capsule", "DestroyImmediate", "localPosition", "localRotation"]
},
{
"path": "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldAssetManifest.cs",
"contains": ["EveUnityPlayableWorldAssetManifest", "EveUnityPlayableWorldAssetManifestEntry", "EveUnityManifestGameObjectAssetProvider", "ManifestRef", "ResourcesPath", "PrefabKey", "NormalizeResourcesPath", "ResolvePrefab", "Resources.Load"]
},
{
"path": "runtimes/incubating/eve-unity-scene/Runtime/SaiVisualNovelUnitySceneProjectionAdapter.cs",
"contains": ["SaiVisualNovelUnitySceneProjectionAdapter", "sai.vn", "vn.stage", "story.choose", "story.continue", "story.jump", "gamecult.eve.plugin_abi.v1", "sidecar-advertised-plugin-abi", "Sai"]
@ -1146,7 +1152,7 @@
},
{
"path": "runtimes/incubating/eve-unity-scene/Tests/Editor/EveUnitySceneSurfaceLowererTests.cs",
"contains": ["LowerCarriesProviderAdvertisedWorldBoundary", "LowerBuildsProviderAgnosticSceneGraphFromSurfaceTree", "LowerExtractsPlayableArpgWorldFromGenericScene3dSurface", "GenericClientSessionConsumesAetheriaPlayableWorldSnapshotWithoutAetheriaTypes", "GenericProviderConnectionAppliesLiveSnapshotsAndSubmitsCommandsThroughSink", "PlayableWorldPresenterInstantiatesUpdatesAndDespawnsProviderEntities", "FakeProviderSurfaceSource", "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", "AssetManifestMapsProviderAssetRefsToUnityLoadKeysWithoutAetheriaTypes", "FakeProviderSurfaceSource", "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"]
},
{
"path": "tools/eveunity/eveunity-capture-contract.test.mjs",