From 7b15a99d025ca49cdadcabd52905bb77848d8ce6 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Thu, 9 Jul 2026 18:24:27 +0100 Subject: [PATCH] Add Unity playable world asset manifest resolver --- docs/eve-migration-roadmap.md | 11 +- docs/parity-testing-harness.md | 9 +- docs/world-state-lowering.md | 11 +- ...veUnityGameObjectPlayableWorldSceneSink.cs | 23 +--- .../EveUnityPlayableWorldAssetManifest.cs | 129 ++++++++++++++++++ .../EveUnitySceneSurfaceLowererTests.cs | 36 +++++ .../eve-runtime-capability.json | 4 + .../eveunity-scene-split-handoff.json | 6 +- .../run-eveunity-scene-lifecycle-smoke.ps1 | 2 +- ...un-eveunity-scene-provider-shell-smoke.ps1 | 12 +- ...ntime-owner-conformance-consumer-smoke.ps1 | 1 + tools/parity/parity-manifest.json | 10 +- 12 files changed, 215 insertions(+), 39 deletions(-) create mode 100644 runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldAssetManifest.cs diff --git a/docs/eve-migration-roadmap.md b/docs/eve-migration-roadmap.md index 1468542..72468f0 100644 --- a/docs/eve-migration-roadmap.md +++ b/docs/eve-migration-roadmap.md @@ -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 diff --git a/docs/parity-testing-harness.md b/docs/parity-testing-harness.md index 9015a11..8ada721 100644 --- a/docs/parity-testing-harness.md +++ b/docs/parity-testing-harness.md @@ -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, diff --git a/docs/world-state-lowering.md b/docs/world-state-lowering.md index e23b852..9281d89 100644 --- a/docs/world-state-lowering.md +++ b/docs/world-state-lowering.md @@ -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 diff --git a/runtimes/incubating/eve-unity-scene/Runtime/EveUnityGameObjectPlayableWorldSceneSink.cs b/runtimes/incubating/eve-unity-scene/Runtime/EveUnityGameObjectPlayableWorldSceneSink.cs index 8ecdae2..9256609 100644 --- a/runtimes/incubating/eve-unity-scene/Runtime/EveUnityGameObjectPlayableWorldSceneSink.cs +++ b/runtimes/incubating/eve-unity-scene/Runtime/EveUnityGameObjectPlayableWorldSceneSink.cs @@ -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(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 diff --git a/runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldAssetManifest.cs b/runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldAssetManifest.cs new file mode 100644 index 0000000..8a5ba91 --- /dev/null +++ b/runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldAssetManifest.cs @@ -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 _byAssetRef = + new Dictionary(StringComparer.Ordinal); + private readonly Dictionary _byEntityKind = + new Dictionary(StringComparer.Ordinal); + + public EveUnityPlayableWorldAssetManifest( + string manifestRef, + IReadOnlyList entries) + { + ManifestRef = manifestRef ?? ""; + Entries = entries ?? Array.Empty(); + + 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 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(entry.ResourcesPath); + if (prefab != null) + return prefab; + } + + return _fallback?.ResolvePrefab(asset); + } + } +} diff --git a/runtimes/incubating/eve-unity-scene/Tests/Editor/EveUnitySceneSurfaceLowererTests.cs b/runtimes/incubating/eve-unity-scene/Tests/Editor/EveUnitySceneSurfaceLowererTests.cs index 0094c00..72f12ee 100644 --- a/runtimes/incubating/eve-unity-scene/Tests/Editor/EveUnitySceneSurfaceLowererTests.cs +++ b/runtimes/incubating/eve-unity-scene/Tests/Editor/EveUnitySceneSurfaceLowererTests.cs @@ -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() { diff --git a/runtimes/incubating/eve-unity-scene/eve-runtime-capability.json b/runtimes/incubating/eve-unity-scene/eve-runtime-capability.json index 2603a29..81ac3d6 100644 --- a/runtimes/incubating/eve-unity-scene/eve-runtime-capability.json +++ b/runtimes/incubating/eve-unity-scene/eve-runtime-capability.json @@ -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", diff --git a/runtimes/incubating/eve-unity-scene/eveunity-scene-split-handoff.json b/runtimes/incubating/eve-unity-scene/eveunity-scene-split-handoff.json index bbadc2f..6d7b3c6 100644 --- a/runtimes/incubating/eve-unity-scene/eveunity-scene-split-handoff.json +++ b/runtimes/incubating/eve-unity-scene/eveunity-scene-split-handoff.json @@ -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.", diff --git a/scripts/run-eveunity-scene-lifecycle-smoke.ps1 b/scripts/run-eveunity-scene-lifecycle-smoke.ps1 index 910982f..7b60584 100644 --- a/scripts/run-eveunity-scene-lifecycle-smoke.ps1 +++ b/scripts/run-eveunity-scene-lifecycle-smoke.ps1 @@ -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" } diff --git a/scripts/run-eveunity-scene-provider-shell-smoke.ps1 b/scripts/run-eveunity-scene-provider-shell-smoke.ps1 index 9b98359..bd3762f 100644 --- a/scripts/run-eveunity-scene-provider-shell-smoke.ps1 +++ b/scripts/run-eveunity-scene-provider-shell-smoke.ps1 @@ -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" } diff --git a/scripts/run-runtime-owner-conformance-consumer-smoke.ps1 b/scripts/run-runtime-owner-conformance-consumer-smoke.ps1 index 8e38580..c1d30c7 100644 --- a/scripts/run-runtime-owner-conformance-consumer-smoke.ps1 +++ b/scripts/run-runtime-owner-conformance-consumer-smoke.ps1 @@ -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 ` diff --git a/tools/parity/parity-manifest.json b/tools/parity/parity-manifest.json index d2dc132..f114f0f 100644 --- a/tools/parity/parity-manifest.json +++ b/tools/parity/parity-manifest.json @@ -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",