diff --git a/docs/eve-migration-roadmap.md b/docs/eve-migration-roadmap.md index ddbe563..a5736a4 100644 --- a/docs/eve-migration-roadmap.md +++ b/docs/eve-migration-roadmap.md @@ -285,18 +285,25 @@ Exit criteria: ## Active Work Queue -1. Repoint Eve conformance and handoff evidence at the graduated `EveUnity` - owner repo, then delete the duplicate - `runtimes/incubating/eve-unity-scene` body and Eve-local Unity lifecycle - scripts. Keep only Eve contracts and cross-repo conformance policy here. -2. Add a real Unity PlayMode PNG/frame capture in EveUnity for Aetheria's +1. Add a real Unity PlayMode PNG/frame capture in EveUnity for Aetheria's daemon-published game surface and the generic world-smoke provider. -3. Replace Aetheria's local state-file polling adapter with a generic live +2. Replace Aetheria's local state-file polling adapter with a generic live CultMesh/CultNet provider transport when that transport contract is ready; Aetheria should then supply only provider advertisement and credentials. Recently cut: +- Eve no longer contains `runtimes/incubating/eve-unity-scene`. Runtime + capability, source-symbol, lifecycle, and package evidence now resolve from + `../EveUnity` through the parity runtime's `sourceRoot`. Eve-local scene + release, capture, lifecycle, split-handoff, and EditMode runner scripts were + deleted. `unity-scene` is active in parity; its real frame capture remains a + visible lifecycle gap rather than a JSON projection standing in for pixels. +- EveUnity now owns typed release and capture request builders alongside its + UPM pack and consumer-test scripts. The release builder describes a package + request; the capture builder consumes a provider advertisement and describes + the requested frame. Neither claims a release tag or PNG exists before the + corresponding owner-repo artifact is produced. - `GameCult/EveUnity` now exists as the runtime owner repo. It owns `packages/org.gamecult.eve.unity-scene`, the generic GameObject playable-world host, camera/input components, plugin projection shells, package tests, UPM @@ -310,11 +317,6 @@ Recently cut: from the provider repo or Eve core. A consumer run through the owner path passed all 21 `GameCult.Eve.UnityScene.Tests` tests, with results under `E:\Projects\EveUnity\artifacts\aetheria-consumer\20260710T022930`. -- The runtime split is not yet structurally complete because Eve's parity - manifest, handoff ledger, and Unity smokes still inspect the incubating copy. - Those references must move to owner-repo evidence before the duplicate body - is deleted. Until that deletion, EveUnity is the active package owner and - Eve's copy is migration residue, not a second runtime authority. - The web reference now has a schema-backed layout probe for the `embedded-surface` and `sai-vn` fixtures. `scripts/run-web-reference-layout-probe-smoke.ps1` builds the browser lowerer, diff --git a/docs/parity-testing-harness.md b/docs/parity-testing-harness.md index 340de80..f6df9c4 100644 --- a/docs/parity-testing-harness.md +++ b/docs/parity-testing-harness.md @@ -481,15 +481,11 @@ lowers the Aetheria world surface through `EveElectronShell` into `artifacts/eveelectron-capture/latest/electron-shell-projection.json`. The remaining blocker is packaged Electron window capture. -Unity scene semantic capture evidence follows the same rule without pretending -it is a rendered Unity frame. `tools/eveunity/eveunity-scene-capture-artifact.mjs` -lowers the Aetheria world surface into `gamecult.eve.unity_scene_projection.v1` -and writes `artifacts/eveunity-scene-capture/latest/unity-scene-projection.json`. -It records scene graph projection, embedded slots, sidecar plugin projection -metadata, and a `playableWorld` extraction for generic `world.scene3d` / -`world.entity3d` ARPG data: state pointer, asset manifest, camera/input profile, -entity transforms, asset refs, and daemon command affordances. The Unity scene -runtime also declares `providerSurfaceSession` and carries +Unity scene runtime evidence is now consumed from the `EveUnity` owner repo +through the parity runtime's `sourceRoot`. Eve does not generate a substitute +JSON scene capture. Until EveUnity attaches a real PlayMode PNG or frame, the +capture contract reports `contract-artifact-missing` and remains visibly +pending. The owner runtime declares `providerSurfaceSession` and carries `EveUnitySceneClientSession`, a provider-snapshot boundary that lowers the active surface and emits `gamecult.eve.command.v1` intents without Aetheria types. It also declares `providerSurfaceSource` through diff --git a/runtimes/incubating/eve-unity-scene/Runtime.meta b/runtimes/incubating/eve-unity-scene/Runtime.meta deleted file mode 100644 index f5f6f4b..0000000 --- a/runtimes/incubating/eve-unity-scene/Runtime.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 1ed3bb976c01b68498f8da912b8ddf2d -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/runtimes/incubating/eve-unity-scene/Runtime/EveUnityGameObjectPlayableWorldSceneSink.cs b/runtimes/incubating/eve-unity-scene/Runtime/EveUnityGameObjectPlayableWorldSceneSink.cs deleted file mode 100644 index 9256609..0000000 --- a/runtimes/incubating/eve-unity-scene/Runtime/EveUnityGameObjectPlayableWorldSceneSink.cs +++ /dev/null @@ -1,160 +0,0 @@ -using System; -using System.Collections.Generic; -using UnityEngine; - -#nullable enable - -namespace GameCult.Eve.UnityScene -{ - public interface IEveUnityGameObjectAssetProvider - { - GameObject? ResolvePrefab(EveUnityPlayableWorldAssetBinding asset); - } - - public sealed class EveUnityGameObjectPlayableWorldSceneSink : IEveUnityPlayableWorldSceneSink - { - private readonly Transform _root; - private readonly IEveUnityGameObjectAssetProvider _assetProvider; - private readonly Dictionary _instances = new Dictionary(StringComparer.Ordinal); - - public EveUnityGameObjectPlayableWorldSceneSink( - Transform root, - IEveUnityGameObjectAssetProvider assetProvider) - { - _root = root != null ? root : throw new ArgumentNullException(nameof(root)); - _assetProvider = assetProvider ?? throw new ArgumentNullException(nameof(assetProvider)); - } - - public int ActiveEntityCount => _instances.Count; - - public void ConfigureWorld(EveUnityPlayableWorldProjection world) - { - if (world == null) throw new ArgumentNullException(nameof(world)); - if (!string.IsNullOrWhiteSpace(world.WorldRootId)) - _root.name = world.WorldRootId; - } - - public void UpsertEntity(EveUnityPlayableWorldEntity entity, EveUnityPlayableWorldAssetBinding asset) - { - if (entity == null) throw new ArgumentNullException(nameof(entity)); - if (asset == null) throw new ArgumentNullException(nameof(asset)); - if (string.IsNullOrWhiteSpace(entity.EntityId)) - return; - - GameObject instance; - if (!_instances.TryGetValue(entity.EntityId, out instance) || instance == null) - { - instance = InstantiateEntity(entity, asset); - _instances[entity.EntityId] = instance; - } - else - { - var marker = instance.GetComponent(); - if (marker != null && !string.Equals(marker.AssetRef, asset.AssetRef, StringComparison.Ordinal)) - { - DestroyInstance(instance); - instance = InstantiateEntity(entity, asset); - _instances[entity.EntityId] = instance; - } - } - - ApplyEntity(instance, entity, asset); - } - - public void RemoveEntity(string entityId) - { - if (string.IsNullOrWhiteSpace(entityId)) - return; - - GameObject instance; - if (!_instances.TryGetValue(entityId, out instance)) - return; - - _instances.Remove(entityId); - if (instance != null) - DestroyInstance(instance); - } - - private GameObject InstantiateEntity(EveUnityPlayableWorldEntity entity, EveUnityPlayableWorldAssetBinding asset) - { - var prefab = _assetProvider.ResolvePrefab(asset); - var instance = prefab != null - ? UnityEngine.Object.Instantiate(prefab, _root) - : GameObject.CreatePrimitive(PrimitiveType.Capsule); - - if (instance.transform.parent != _root) - instance.transform.SetParent(_root, false); - - return instance; - } - - private static void ApplyEntity( - GameObject instance, - EveUnityPlayableWorldEntity entity, - EveUnityPlayableWorldAssetBinding asset) - { - instance.name = string.IsNullOrWhiteSpace(entity.Label) - ? entity.EntityId - : $"{entity.EntityId} ({entity.Label})"; - instance.transform.localPosition = new Vector3(entity.PositionX, entity.PositionY, entity.PositionZ); - instance.transform.localRotation = Quaternion.Euler(0f, entity.RotationY, 0f); - if (entity.Radius > 0f) - instance.transform.localScale = Vector3.one * entity.Radius; - - var marker = instance.GetComponent(); - if (marker == null) - marker = instance.AddComponent(); - - marker.Apply(entity, asset); - } - - private static void DestroyInstance(GameObject instance) - { - if (Application.isPlaying) - UnityEngine.Object.Destroy(instance); - else - UnityEngine.Object.DestroyImmediate(instance); - } - } - - public sealed class EveUnityResourcesAssetProvider : IEveUnityGameObjectAssetProvider - { - public GameObject? ResolvePrefab(EveUnityPlayableWorldAssetBinding asset) - { - if (asset == null) throw new ArgumentNullException(nameof(asset)); - var resourcesPath = EveUnityPlayableWorldAssetManifestEntry.NormalizeResourcesPath(asset.AssetRef); - return string.IsNullOrWhiteSpace(resourcesPath) - ? null - : Resources.Load(resourcesPath); - } - } - - public sealed class EveUnityPlayableWorldEntityMarker : MonoBehaviour - { - public string EntityId = ""; - public string NodeId = ""; - public string EntityKind = ""; - public string Label = ""; - public string Faction = ""; - public string AssetRef = ""; - public string PresentationKind = ""; - public bool Selectable; - public bool Controllable; - - public void Apply(EveUnityPlayableWorldEntity entity, EveUnityPlayableWorldAssetBinding asset) - { - if (entity == null) throw new ArgumentNullException(nameof(entity)); - if (asset == null) throw new ArgumentNullException(nameof(asset)); - - EntityId = entity.EntityId; - NodeId = entity.NodeId; - EntityKind = entity.EntityKind; - Label = entity.Label; - Faction = entity.Faction; - AssetRef = asset.AssetRef; - PresentationKind = asset.PresentationKind; - Selectable = entity.Selectable; - Controllable = entity.Controllable; - } - } -} diff --git a/runtimes/incubating/eve-unity-scene/Runtime/EveUnityGameObjectPlayableWorldSceneSink.cs.meta b/runtimes/incubating/eve-unity-scene/Runtime/EveUnityGameObjectPlayableWorldSceneSink.cs.meta deleted file mode 100644 index 493007b..0000000 --- a/runtimes/incubating/eve-unity-scene/Runtime/EveUnityGameObjectPlayableWorldSceneSink.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: e924fe3501e6e584392cb405f916c9c9 \ No newline at end of file diff --git a/runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldAssetManifest.cs b/runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldAssetManifest.cs deleted file mode 100644 index d6dd81a..0000000 --- a/runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldAssetManifest.cs +++ /dev/null @@ -1,341 +0,0 @@ -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 static EveUnityPlayableWorldAssetManifest FromDocument(EveUnityPlayableWorldAssetManifestDocument document) - { - if (document == null) throw new ArgumentNullException(nameof(document)); - - var entries = new List(); - foreach (var entry in document.Entries) - { - if (entry == null) - continue; - - entries.Add(new EveUnityPlayableWorldAssetManifestEntry( - entry.AssetRef, - entry.EntityKind, - entry.ResourcesPath, - entry.PrefabKey, - entry.PresentationKind)); - } - - return new EveUnityPlayableWorldAssetManifest(document.ManifestRef, entries); - } - - 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 interface IEveUnityPlayableWorldAssetManifestSource - { - string ManifestRef { get; } - - EveUnityPlayableWorldAssetManifest CurrentManifest { get; } - - event Action ManifestAvailable; - } - - public sealed class EveUnityPlayableWorldAssetManifestCache - { - private readonly Dictionary _manifests = - new Dictionary(StringComparer.Ordinal); - private readonly Dictionary> _subscriptions = - new Dictionary>(); - - public int Count => _manifests.Count; - - public void Add(EveUnityPlayableWorldAssetManifest manifest) - { - if (manifest == null) throw new ArgumentNullException(nameof(manifest)); - if (string.IsNullOrWhiteSpace(manifest.ManifestRef)) - throw new ArgumentException("Asset manifest ref is required.", nameof(manifest)); - - _manifests[manifest.ManifestRef] = manifest; - } - - public void Connect(IEveUnityPlayableWorldAssetManifestSource source) - { - if (source == null) throw new ArgumentNullException(nameof(source)); - if (_subscriptions.ContainsKey(source)) - return; - - Add(source.CurrentManifest); - Action handler = Add; - source.ManifestAvailable += handler; - _subscriptions[source] = handler; - } - - public void Disconnect(IEveUnityPlayableWorldAssetManifestSource source) - { - if (source == null) throw new ArgumentNullException(nameof(source)); - Action handler; - if (!_subscriptions.TryGetValue(source, out handler)) - return; - - source.ManifestAvailable -= handler; - _subscriptions.Remove(source); - } - - public bool TryGet(string manifestRef, out EveUnityPlayableWorldAssetManifest? manifest) - { - if (string.IsNullOrWhiteSpace(manifestRef)) - { - manifest = null; - return false; - } - - return _manifests.TryGetValue(manifestRef, out manifest); - } - - public EveUnityPlayableWorldAssetManifest? GetForWorld(EveUnityPlayableWorldProjection world) - { - if (world == null) throw new ArgumentNullException(nameof(world)); - EveUnityPlayableWorldAssetManifest? manifest; - return TryGet(world.AssetManifest, out manifest) ? manifest : null; - } - - public IEveUnityGameObjectAssetProvider CreateGameObjectAssetProvider( - EveUnityPlayableWorldProjection world, - IEveUnityGameObjectAssetProvider fallback) - { - if (world == null) throw new ArgumentNullException(nameof(world)); - if (fallback == null) throw new ArgumentNullException(nameof(fallback)); - - var manifest = GetForWorld(world); - return manifest == null - ? fallback - : new EveUnityManifestGameObjectAssetProvider(manifest, fallback); - } - } - - public interface IEveUnityPlayableWorldAssetManifestDocumentSource - { - string ManifestRef { get; } - - EveUnityPlayableWorldAssetManifestDocument CurrentDocument { get; } - - event Action DocumentAvailable; - } - - public sealed class EveUnityPlayableWorldAssetManifestDocumentSource : IEveUnityPlayableWorldAssetManifestSource, IDisposable - { - private readonly IEveUnityPlayableWorldAssetManifestDocumentSource _documentSource; - private bool _connected; - - public EveUnityPlayableWorldAssetManifestDocumentSource( - IEveUnityPlayableWorldAssetManifestDocumentSource documentSource) - { - _documentSource = documentSource ?? throw new ArgumentNullException(nameof(documentSource)); - CurrentManifest = EveUnityPlayableWorldAssetManifest.FromDocument(_documentSource.CurrentDocument); - } - - public string ManifestRef => CurrentManifest.ManifestRef; - - public EveUnityPlayableWorldAssetManifest CurrentManifest { get; private set; } - - public event Action? ManifestAvailable; - - public void Connect() - { - if (_connected) - return; - - _documentSource.DocumentAvailable += OnDocumentAvailable; - _connected = true; - } - - public void Disconnect() - { - if (!_connected) - return; - - _documentSource.DocumentAvailable -= OnDocumentAvailable; - _connected = false; - } - - public void Dispose() - { - Disconnect(); - } - - private void OnDocumentAvailable(EveUnityPlayableWorldAssetManifestDocument document) - { - CurrentManifest = EveUnityPlayableWorldAssetManifest.FromDocument(document); - ManifestAvailable?.Invoke(CurrentManifest); - } - } - - public sealed class EveUnityPlayableWorldAssetManifestDocument - { - public const string SchemaId = "gamecult.eve.unity_playable_world_asset_manifest.v1"; - - public EveUnityPlayableWorldAssetManifestDocument( - string manifestRef, - IReadOnlyList entries, - string providerId = "", - string schema = SchemaId) - { - ManifestRef = manifestRef ?? ""; - Entries = entries ?? Array.Empty(); - ProviderId = providerId ?? ""; - Schema = string.IsNullOrWhiteSpace(schema) ? SchemaId : schema; - } - - public string Schema { get; } - - public string ManifestRef { get; } - - public string ProviderId { get; } - - public IReadOnlyList Entries { get; } - } - - public sealed class EveUnityPlayableWorldAssetManifestDocumentEntry - { - public EveUnityPlayableWorldAssetManifestDocumentEntry( - string assetRef, - string entityKind, - string resourcesPath, - string prefabKey, - string presentationKind = "provider-asset-ref") - { - AssetRef = assetRef ?? ""; - EntityKind = entityKind ?? ""; - ResourcesPath = 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 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/Runtime/EveUnityPlayableWorldAssetManifest.cs.meta b/runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldAssetManifest.cs.meta deleted file mode 100644 index 43c845c..0000000 --- a/runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldAssetManifest.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 0a1f1e9cabc1b044dbf58bc878a6d09a \ No newline at end of file diff --git a/runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldCameraRig.cs b/runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldCameraRig.cs deleted file mode 100644 index 9dc3ce7..0000000 --- a/runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldCameraRig.cs +++ /dev/null @@ -1,92 +0,0 @@ -using UnityEngine; - -#nullable enable - -namespace GameCult.Eve.UnityScene -{ - public sealed class EveUnityPlayableWorldCameraRig : MonoBehaviour - { - [SerializeField] private EveUnityPlayableWorldClientHost? host; - [SerializeField] private Transform? cameraTransform; - [SerializeField] private bool driveInLateUpdate = true; - [SerializeField] private float distance = 10f; - [SerializeField] private float height = 6f; - [SerializeField] private float yawDegrees = 35f; - [SerializeField] private float followDamping = 12f; - - public EveUnityPlayableWorldClientHost? Host - { - get => host; - set => host = value; - } - - public Transform? CameraTransform - { - get => cameraTransform; - set => cameraTransform = value; - } - - public bool ApplyRig(float deltaTime) - { - var resolvedHost = ResolveHost(); - var activeWorld = resolvedHost?.ActiveWorld; - if (resolvedHost == null || activeWorld == null) - return false; - - if (!string.IsNullOrWhiteSpace(activeWorld.CameraRig) && - activeWorld.CameraRig != "arpg.orbital-follow.v1" && - activeWorld.CameraRig != "third-person-orbit") - { - return false; - } - - var camera = cameraTransform != null ? cameraTransform : transform; - var player = FindPlayerMarker(resolvedHost, activeWorld.PlayerEntityId); - if (player == null) - return false; - - var target = player.transform.position; - var orbit = Quaternion.Euler(0f, yawDegrees, 0f) * (Vector3.back * Mathf.Max(0.1f, distance)); - var desiredPosition = target + orbit + (Vector3.up * Mathf.Max(0f, height)); - var t = deltaTime <= 0f - ? 1f - : 1f - Mathf.Exp(-Mathf.Max(0.01f, followDamping) * deltaTime); - - camera.position = Vector3.Lerp(camera.position, desiredPosition, t); - camera.LookAt(target); - return true; - } - - private void LateUpdate() - { - if (driveInLateUpdate) - ApplyRig(Time.deltaTime); - } - - private EveUnityPlayableWorldClientHost? ResolveHost() - { - if (host != null) - return host; - - host = GetComponent(); - return host; - } - - private static EveUnityPlayableWorldEntityMarker? FindPlayerMarker( - EveUnityPlayableWorldClientHost host, - string playerEntityId) - { - if (string.IsNullOrWhiteSpace(playerEntityId)) - return null; - - var markers = host.SceneRoot.GetComponentsInChildren(); - foreach (var marker in markers) - { - if (marker != null && marker.EntityId == playerEntityId) - return marker; - } - - return null; - } - } -} diff --git a/runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldCameraRig.cs.meta b/runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldCameraRig.cs.meta deleted file mode 100644 index de23c49..0000000 --- a/runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldCameraRig.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 3e68cf66c50b4951a9d7f7de68f0ad0e diff --git a/runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldClientBootstrap.cs b/runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldClientBootstrap.cs deleted file mode 100644 index a78caf9..0000000 --- a/runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldClientBootstrap.cs +++ /dev/null @@ -1,193 +0,0 @@ -using System; -using UnityEngine; - -#nullable enable - -namespace GameCult.Eve.UnityScene -{ - public sealed class EveUnityPlayableWorldClientBootstrap : MonoBehaviour - { - [SerializeField] private EveUnityPlayableWorldClientHost? host; - [SerializeField] private MonoBehaviour? provider; - [SerializeField] private MonoBehaviour? providerSurfaceDocuments; - [SerializeField] private MonoBehaviour? commandSink; - [SerializeField] private MonoBehaviour? assetManifestDocuments; - [SerializeField] private MonoBehaviour? receiptSource; - [SerializeField] private MonoBehaviour? fallbackAssetProvider; - [SerializeField] private Transform? sceneRoot; - [SerializeField] private Transform? cameraTransform; - [SerializeField] private bool createSceneRootIfMissing = true; - [SerializeField] private bool attachInputDriver = true; - [SerializeField] private bool attachCameraRig = true; - [SerializeField] private bool connectOnEnable = true; - - public EveUnityPlayableWorldClientHost? Host => host; - - public Transform? SceneRoot => sceneRoot; - - public Transform? CameraTransform => cameraTransform; - - public EveUnityPlayableWorldPresentation? LastPresentation { get; private set; } - - public void ConfigureProvider(MonoBehaviour providerComponent) - { - provider = providerComponent != null ? providerComponent : throw new ArgumentNullException(nameof(providerComponent)); - providerSurfaceDocuments = provider; - commandSink = provider; - assetManifestDocuments = provider; - receiptSource = provider; - } - - public EveUnityPlayableWorldPresentation Mount() - { - var resolvedHost = ResolveHost(); - var resolvedProvider = provider; - var surfaceDocuments = ResolveBehaviour( - providerSurfaceDocuments, - resolvedProvider, - nameof(providerSurfaceDocuments)); - var resolvedCommandSink = ResolveBehaviour( - commandSink, - resolvedProvider, - nameof(commandSink)); - var resolvedAssetDocuments = ResolveOptionalBehaviour( - assetManifestDocuments, - resolvedProvider); - var resolvedReceiptSource = ResolveOptionalBehaviour( - receiptSource, - resolvedProvider); - var resolvedFallbackAssetProvider = ResolveOptionalBehaviour( - fallbackAssetProvider, - null); - - sceneRoot = ResolveSceneRoot(); - resolvedHost.ConnectOnEnable = false; - resolvedHost.Configure( - sceneRoot, - surfaceDocuments, - resolvedCommandSink, - resolvedAssetDocuments, - resolvedReceiptSource, - resolvedFallbackAssetProvider); - - if (attachInputDriver) - ConfigureInputDriver(resolvedHost); - - if (attachCameraRig) - ConfigureCameraRig(resolvedHost); - - LastPresentation = resolvedHost.Connect(); - return LastPresentation; - } - - private void Awake() - { - if (host != null && provider != null) - host.ConnectOnEnable = false; - } - - private void OnEnable() - { - if (connectOnEnable) - Mount(); - } - - private EveUnityPlayableWorldClientHost ResolveHost() - { - if (host != null) - return host; - - host = GetComponent(); - if (host == null) - host = gameObject.AddComponent(); - - return host; - } - - private Transform ResolveSceneRoot() - { - if (sceneRoot != null) - return sceneRoot; - - if (!createSceneRootIfMissing) - return transform; - - var root = new GameObject("Eve Unity Playable World Root"); - root.transform.SetParent(transform, false); - sceneRoot = root.transform; - return sceneRoot; - } - - private Transform ResolveCameraTransform() - { - if (cameraTransform != null) - return cameraTransform; - - var mainCamera = Camera.main; - if (mainCamera != null) - { - cameraTransform = mainCamera.transform; - return cameraTransform; - } - - var cameraObject = new GameObject("Eve Unity Playable World Camera"); - cameraObject.transform.SetParent(transform, false); - cameraObject.AddComponent(); - cameraTransform = cameraObject.transform; - return cameraTransform; - } - - private void ConfigureInputDriver(EveUnityPlayableWorldClientHost resolvedHost) - { - var driver = GetComponent(); - if (driver == null) - driver = gameObject.AddComponent(); - - driver.Host = resolvedHost; - driver.CameraTransform = ResolveCameraTransform(); - } - - private void ConfigureCameraRig(EveUnityPlayableWorldClientHost resolvedHost) - { - var rig = GetComponent(); - if (rig == null) - rig = gameObject.AddComponent(); - - rig.Host = resolvedHost; - rig.CameraTransform = ResolveCameraTransform(); - } - - private MonoBehaviour ResolveBehaviour( - MonoBehaviour? explicitComponent, - MonoBehaviour? providerComponent, - string fieldName) where T : class - { - var resolved = ResolveOptionalBehaviour(explicitComponent, providerComponent); - if (resolved != null) - return resolved; - - throw new InvalidOperationException( - $"Eve Unity playable world bootstrap requires '{fieldName}' or provider to implement {typeof(T).Name}."); - } - - private MonoBehaviour? ResolveOptionalBehaviour( - MonoBehaviour? explicitComponent, - MonoBehaviour? providerComponent) where T : class - { - if (explicitComponent is T) - return explicitComponent; - - if (providerComponent is T) - return providerComponent; - - var components = GetComponents(); - foreach (var component in components) - { - if (component is T) - return component; - } - - return null; - } - } -} diff --git a/runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldClientBootstrap.cs.meta b/runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldClientBootstrap.cs.meta deleted file mode 100644 index 845b68c..0000000 --- a/runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldClientBootstrap.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: 1d5e4b8e1e104bb99522dc2b75d7f4c9 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldClientHost.cs b/runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldClientHost.cs deleted file mode 100644 index 30da84a..0000000 --- a/runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldClientHost.cs +++ /dev/null @@ -1,204 +0,0 @@ -using System; -using System.Collections.Generic; -using GameCult.Eve.Surface; -using UnityEngine; - -#nullable enable - -namespace GameCult.Eve.UnityScene -{ - public sealed class EveUnityPlayableWorldClientHost : MonoBehaviour - { - [SerializeField] private Transform? sceneRoot; - [SerializeField] private MonoBehaviour? providerSurfaceDocuments; - [SerializeField] private MonoBehaviour? commandSink; - [SerializeField] private MonoBehaviour? assetManifestDocuments; - [SerializeField] private MonoBehaviour? receiptSource; - [SerializeField] private MonoBehaviour? fallbackAssetProvider; - [SerializeField] private bool connectOnEnable; - [SerializeField] private bool refreshInUpdate = true; - [SerializeField] private float refreshIntervalSeconds = 0.1f; - - private float _nextRefreshAt; - - public EveUnityPlayableWorldRuntime? Runtime { get; private set; } - - public EveUnityPlayableWorldProjection? ActiveWorld => Runtime?.ActiveWorld; - - public EveUnitySceneProjection? ActiveProjection => Runtime?.ActiveProjection; - - public EveUnityPlayableWorldPresentation? LastPresentation => Runtime?.LastPresentation; - - public EveUnitySceneCommandReceipt? LastReceipt => Runtime?.LastReceipt; - - public long ActiveVersion => Runtime?.ActiveVersion ?? 0; - - public Transform SceneRoot => sceneRoot == null ? transform : sceneRoot; - - public bool ConnectOnEnable - { - get => connectOnEnable; - set => connectOnEnable = value; - } - - public void Configure( - Transform? sceneRoot, - MonoBehaviour providerSurfaceDocuments, - MonoBehaviour commandSink, - MonoBehaviour? assetManifestDocuments = null, - MonoBehaviour? receiptSource = null, - MonoBehaviour? fallbackAssetProvider = null) - { - this.sceneRoot = sceneRoot; - this.providerSurfaceDocuments = providerSurfaceDocuments; - this.commandSink = commandSink; - this.assetManifestDocuments = assetManifestDocuments; - this.receiptSource = receiptSource; - this.fallbackAssetProvider = fallbackAssetProvider; - } - - public EveUnityPlayableWorldPresentation Connect() - { - Disconnect(); - RefreshProviderSources(); - - Runtime = EveUnityPlayableWorldRuntime.CreateForGameObjectScene( - SceneRoot, - Required( - providerSurfaceDocuments, - nameof(providerSurfaceDocuments)), - Required( - commandSink, - nameof(commandSink)), - Optional(assetManifestDocuments), - Optional(receiptSource), - Optional(fallbackAssetProvider)); - - return Runtime.Connect(); - } - - public EveUnityPlayableWorldPresentation Refresh() - { - RefreshProviderSources(); - if (Runtime == null) - return Connect(); - - return Runtime.Refresh(); - } - - public EveSurfaceCommandRequest SubmitMoveIntent( - string entityId, - float targetX, - float targetY, - float targetZ, - DateTimeOffset? issuedAt = null) - { - return RequireRuntime().SubmitMoveIntent(entityId, targetX, targetY, targetZ, issuedAt); - } - - public EveSurfaceCommandRequest SubmitMoveVectorIntent( - string entityId, - float directionX, - float directionY, - float scalarValue = 1f, - DateTimeOffset? issuedAt = null) - { - return RequireRuntime().SubmitMoveVectorIntent(entityId, directionX, directionY, scalarValue, issuedAt); - } - - public EveSurfaceCommandRequest SubmitFocusIntent( - string entityId, - DateTimeOffset? issuedAt = null) - { - return RequireRuntime().SubmitFocusIntent(entityId, issuedAt); - } - - public EveSurfaceCommandRequest SubmitTargetIntent( - string sourceEntityId, - string targetEntityId, - DateTimeOffset? issuedAt = null) - { - return RequireRuntime().SubmitTargetIntent(sourceEntityId, targetEntityId, issuedAt); - } - - public EveSurfaceCommandRequest SubmitActionIntent( - string entityId, - string actionId, - DateTimeOffset? issuedAt = null) - { - return RequireRuntime().SubmitActionIntent(entityId, actionId, issuedAt); - } - - public void Disconnect() - { - Runtime?.Dispose(); - Runtime = null; - } - - private void OnEnable() - { - if (connectOnEnable) - Connect(); - } - - private void Update() - { - if (!refreshInUpdate || Runtime == null) - return; - - if (Time.unscaledTime < _nextRefreshAt) - return; - - _nextRefreshAt = Time.unscaledTime + Math.Max(0.01f, refreshIntervalSeconds); - Refresh(); - } - - private void OnDisable() - { - Disconnect(); - } - - private void OnDestroy() - { - Disconnect(); - } - - private EveUnityPlayableWorldRuntime RequireRuntime() - { - if (Runtime == null) - throw new InvalidOperationException("Eve Unity playable world client host is not connected."); - - return Runtime; - } - - private void RefreshProviderSources() - { - var refreshed = new HashSet(); - RefreshProvider(providerSurfaceDocuments, refreshed); - RefreshProvider(assetManifestDocuments, refreshed); - RefreshProvider(receiptSource, refreshed); - RefreshProvider(commandSink, refreshed); - } - - private static void RefreshProvider(MonoBehaviour? behaviour, ISet refreshed) - { - if (behaviour is IEveUnityProviderRefreshSource refreshSource && refreshed.Add(behaviour)) - refreshSource.Refresh(); - } - - private static T Required(MonoBehaviour? behaviour, string fieldName) where T : class - { - var resolved = behaviour as T; - if (resolved == null) - throw new InvalidOperationException( - $"Eve Unity playable world client host requires '{fieldName}' to implement {typeof(T).Name}."); - - return resolved; - } - - private static T? Optional(MonoBehaviour? behaviour) where T : class - { - return behaviour as T; - } - } -} diff --git a/runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldClientHost.cs.meta b/runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldClientHost.cs.meta deleted file mode 100644 index 83701ad..0000000 --- a/runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldClientHost.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: df3f3a1abd3f14541bf6d7ec59343661 \ No newline at end of file diff --git a/runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldInputDriver.cs b/runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldInputDriver.cs deleted file mode 100644 index 03850e1..0000000 --- a/runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldInputDriver.cs +++ /dev/null @@ -1,173 +0,0 @@ -using System; -using GameCult.Eve.Surface; -using UnityEngine; - -#nullable enable - -namespace GameCult.Eve.UnityScene -{ - public sealed class EveUnityPlayableWorldInputDriver : MonoBehaviour - { - [SerializeField] private EveUnityPlayableWorldClientHost? host; - [SerializeField] private Transform? cameraTransform; - [SerializeField] private bool driveInUpdate = true; - [SerializeField] private string horizontalAxis = "Horizontal"; - [SerializeField] private string verticalAxis = "Vertical"; - [SerializeField] private string actionButton = "Fire1"; - [SerializeField] private float deadZone = 0.01f; - [SerializeField] private float commandIntervalSeconds = 0.05f; - [SerializeField] private bool submitZeroOnRelease = true; - - private float _nextCommandAt; - private bool _wasMoving; - - public EveUnityPlayableWorldClientHost? Host - { - get => host; - set => host = value; - } - - public Transform? CameraTransform - { - get => cameraTransform; - set => cameraTransform = value; - } - - public EveSurfaceCommandRequest? SubmitMoveVectorInput( - float horizontal, - float vertical, - DateTimeOffset? issuedAt = null) - { - var resolvedHost = ResolveHost(); - if (resolvedHost == null || resolvedHost.ActiveWorld == null) - return null; - - var movement = EveUnityPlayableWorldMoveVector.FromCameraRelativeInput( - horizontal, - vertical, - cameraTransform, - deadZone); - - if (!movement.HasInput) - { - if (!submitZeroOnRelease || !_wasMoving) - return null; - - _wasMoving = false; - return resolvedHost.SubmitMoveVectorIntent( - resolvedHost.ActiveWorld.PlayerEntityId, - 0f, - 0f, - 0f, - issuedAt); - } - - _wasMoving = true; - return resolvedHost.SubmitMoveVectorIntent( - resolvedHost.ActiveWorld.PlayerEntityId, - movement.DirectionX, - movement.DirectionY, - movement.ScalarValue, - issuedAt); - } - - public EveSurfaceCommandRequest? SubmitPrimaryAction(string actionId = "primary") - { - var resolvedHost = ResolveHost(); - if (resolvedHost?.ActiveWorld == null) - return null; - - return resolvedHost.SubmitActionIntent( - resolvedHost.ActiveWorld.PlayerEntityId, - string.IsNullOrWhiteSpace(actionId) ? "primary" : actionId); - } - - private void Update() - { - if (!driveInUpdate || Time.unscaledTime < _nextCommandAt) - return; - - _nextCommandAt = Time.unscaledTime + Math.Max(0.01f, commandIntervalSeconds); - SubmitMoveVectorInput(Input.GetAxisRaw(horizontalAxis), Input.GetAxisRaw(verticalAxis)); - - if (!string.IsNullOrWhiteSpace(actionButton) && Input.GetButtonDown(actionButton)) - SubmitPrimaryAction(actionButton); - } - - private EveUnityPlayableWorldClientHost? ResolveHost() - { - if (host != null) - return host; - - host = GetComponent(); - return host; - } - } - - public readonly struct EveUnityPlayableWorldMoveVector - { - public EveUnityPlayableWorldMoveVector( - float directionX, - float directionY, - float scalarValue, - bool hasInput) - { - DirectionX = directionX; - DirectionY = directionY; - ScalarValue = scalarValue; - HasInput = hasInput; - } - - public float DirectionX { get; } - - public float DirectionY { get; } - - public float ScalarValue { get; } - - public bool HasInput { get; } - - public static EveUnityPlayableWorldMoveVector FromCameraRelativeInput( - float horizontal, - float vertical, - Transform? cameraTransform, - float deadZone = 0.01f) - { - var input = new Vector2(horizontal, vertical); - var magnitude = Mathf.Clamp01(input.magnitude); - if (magnitude <= Mathf.Max(0f, deadZone)) - return new EveUnityPlayableWorldMoveVector(0f, 0f, 0f, false); - - Vector3 direction; - if (cameraTransform == null) - { - direction = new Vector3(horizontal, 0f, vertical); - } - else - { - var forward = cameraTransform.forward; - forward.y = 0f; - if (forward.sqrMagnitude <= 0.0001f) - forward = Vector3.forward; - forward.Normalize(); - - var right = cameraTransform.right; - right.y = 0f; - if (right.sqrMagnitude <= 0.0001f) - right = Vector3.right; - right.Normalize(); - - direction = (right * horizontal) + (forward * vertical); - } - - if (direction.sqrMagnitude <= 0.0001f) - return new EveUnityPlayableWorldMoveVector(0f, 0f, 0f, false); - - direction.Normalize(); - return new EveUnityPlayableWorldMoveVector( - direction.x, - direction.z, - magnitude, - true); - } - } -} diff --git a/runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldInputDriver.cs.meta b/runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldInputDriver.cs.meta deleted file mode 100644 index 0110ff1..0000000 --- a/runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldInputDriver.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 7ad1be678e6e4d6d9c72769358e0a233 diff --git a/runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldLiveClient.cs b/runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldLiveClient.cs deleted file mode 100644 index 6a50694..0000000 --- a/runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldLiveClient.cs +++ /dev/null @@ -1,225 +0,0 @@ -using System; -using GameCult.Eve.Surface; - -#nullable enable - -namespace GameCult.Eve.UnityScene -{ - public sealed class EveUnityPlayableWorldLiveClient : IDisposable - { - 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, - 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; - - public EveUnityPlayableWorldProjection? ActiveWorld => ActiveProjection?.PlayableWorld; - - 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? ReceiptAvailable; - - public EveUnityPlayableWorldPresentation Connect() - { - EnsureSubscribed(); - EnsureReceiptSubscribed(); - _connection.Connect(); - return RequirePresentation(); - } - - public EveUnityPlayableWorldPresentation Refresh() - { - EnsureSubscribed(); - _connection.Refresh(); - return RequirePresentation(); - } - - public EveSurfaceCommandRequest SubmitMoveIntent( - string entityId, - float targetX, - float targetY, - float targetZ, - DateTimeOffset? issuedAt = null) - { - return _connection.SubmitMoveIntent(entityId, targetX, targetY, targetZ, issuedAt); - } - - public EveSurfaceCommandRequest SubmitMoveVectorIntent( - string entityId, - float directionX, - float directionY, - float scalarValue = 1f, - DateTimeOffset? issuedAt = null) - { - return _connection.SubmitMoveVectorIntent(entityId, directionX, directionY, scalarValue, issuedAt); - } - - public EveSurfaceCommandRequest SubmitFocusIntent( - string entityId, - DateTimeOffset? issuedAt = null) - { - return _connection.SubmitFocusIntent(entityId, issuedAt); - } - - public EveSurfaceCommandRequest SubmitTargetIntent( - string sourceEntityId, - string targetEntityId, - DateTimeOffset? issuedAt = null) - { - return _connection.SubmitTargetIntent(sourceEntityId, targetEntityId, issuedAt); - } - - public EveSurfaceCommandRequest SubmitActionIntent( - string entityId, - string actionId, - DateTimeOffset? issuedAt = null) - { - return _connection.SubmitActionIntent(entityId, actionId, issuedAt); - } - - public void Disconnect() - { - if (_connected) - { - _connection.ProjectionUpdated -= OnProjectionUpdated; - _connected = false; - } - - if (_receiptConnected && _receiptSource != null) - { - _receiptSource.ReceiptAvailable -= OnReceiptAvailable; - _receiptConnected = false; - } - - _connection.Disconnect(); - } - - public void Dispose() - { - Disconnect(); - _connection.Dispose(); - } - - private void EnsureSubscribed() - { - if (_connected) - return; - - _connection.ProjectionUpdated += OnProjectionUpdated; - _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) - throw new InvalidOperationException("The active Unity scene surface has not produced a playable world presentation."); - return LastPresentation; - } - } - - public interface IEveUnitySceneCommandReceiptSource - { - event Action 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); - } -} diff --git a/runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldLiveClient.cs.meta b/runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldLiveClient.cs.meta deleted file mode 100644 index ef9f199..0000000 --- a/runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldLiveClient.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 3b46f9972e945ca4daa29473de0bfb9b \ No newline at end of file diff --git a/runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldPresenter.cs b/runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldPresenter.cs deleted file mode 100644 index b77695b..0000000 --- a/runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldPresenter.cs +++ /dev/null @@ -1,154 +0,0 @@ -using System; -using System.Collections.Generic; - -#nullable enable - -namespace GameCult.Eve.UnityScene -{ - public interface IEveUnityPlayableWorldSceneSink - { - void ConfigureWorld(EveUnityPlayableWorldProjection world); - - void UpsertEntity(EveUnityPlayableWorldEntity entity, EveUnityPlayableWorldAssetBinding asset); - - void RemoveEntity(string entityId); - } - - public interface IEveUnityPlayableWorldAssetResolver - { - EveUnityPlayableWorldAssetBinding Resolve(EveUnityPlayableWorldEntity entity); - } - - public sealed class EveUnityPlayableWorldPresenter - { - private readonly IEveUnityPlayableWorldSceneSink _sceneSink; - private readonly IEveUnityPlayableWorldAssetResolver _assetResolver; - private readonly HashSet _knownEntityIds = new HashSet(StringComparer.Ordinal); - - public EveUnityPlayableWorldPresenter( - IEveUnityPlayableWorldSceneSink sceneSink, - IEveUnityPlayableWorldAssetResolver assetResolver) - { - _sceneSink = sceneSink ?? throw new ArgumentNullException(nameof(sceneSink)); - _assetResolver = assetResolver ?? throw new ArgumentNullException(nameof(assetResolver)); - } - - public EveUnityPlayableWorldPresentation Apply(EveUnitySceneProjection projection) - { - if (projection == null) throw new ArgumentNullException(nameof(projection)); - if (projection.PlayableWorld == null) - throw new InvalidOperationException("Unity playable world presentation requires a playableWorld projection."); - - return Apply(projection.PlayableWorld); - } - - public EveUnityPlayableWorldPresentation Apply(EveUnityPlayableWorldProjection world) - { - if (world == null) throw new ArgumentNullException(nameof(world)); - - var nextEntityIds = new HashSet(StringComparer.Ordinal); - _sceneSink.ConfigureWorld(world); - - var upserted = 0; - foreach (var entity in world.Entities) - { - if (string.IsNullOrWhiteSpace(entity.EntityId)) - continue; - - nextEntityIds.Add(entity.EntityId); - _sceneSink.UpsertEntity(entity, _assetResolver.Resolve(entity)); - upserted++; - } - - var removed = 0; - var previousEntityIds = new List(_knownEntityIds); - foreach (var entityId in previousEntityIds) - { - if (nextEntityIds.Contains(entityId)) - continue; - - _sceneSink.RemoveEntity(entityId); - _knownEntityIds.Remove(entityId); - removed++; - } - - foreach (var entityId in nextEntityIds) - _knownEntityIds.Add(entityId); - - return new EveUnityPlayableWorldPresentation( - world.WorldRootId, - world.PlayerEntityId, - world.InputProfile, - world.CameraRig, - upserted, - removed, - _knownEntityIds.Count); - } - } - - public sealed class EveUnityPlayableWorldAssetBinding - { - public EveUnityPlayableWorldAssetBinding( - string assetRef, - string entityKind, - string presentationKind) - { - AssetRef = assetRef ?? ""; - EntityKind = entityKind ?? ""; - PresentationKind = presentationKind ?? ""; - } - - public string AssetRef { get; } - - public string EntityKind { get; } - - public string PresentationKind { get; } - } - - public sealed class EveUnityPlayableWorldPresentation - { - public EveUnityPlayableWorldPresentation( - string worldRootId, - string playerEntityId, - string inputProfile, - string cameraRig, - int upsertedEntities, - int removedEntities, - int activeEntities) - { - WorldRootId = worldRootId ?? ""; - PlayerEntityId = playerEntityId ?? ""; - InputProfile = inputProfile ?? ""; - CameraRig = cameraRig ?? ""; - UpsertedEntities = upsertedEntities; - RemovedEntities = removedEntities; - ActiveEntities = activeEntities; - } - - public string WorldRootId { get; } - - public string PlayerEntityId { get; } - - public string InputProfile { get; } - - public string CameraRig { get; } - - public int UpsertedEntities { get; } - - public int RemovedEntities { get; } - - public int ActiveEntities { get; } - } - - public sealed class EveUnityAssetRefResolver : IEveUnityPlayableWorldAssetResolver - { - public EveUnityPlayableWorldAssetBinding Resolve(EveUnityPlayableWorldEntity entity) - { - if (entity == null) throw new ArgumentNullException(nameof(entity)); - return new EveUnityPlayableWorldAssetBinding( - entity.AssetRef, - entity.EntityKind, - string.IsNullOrWhiteSpace(entity.AssetRef) ? "unity-generated-placeholder" : "provider-asset-ref"); - } - } -} diff --git a/runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldPresenter.cs.meta b/runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldPresenter.cs.meta deleted file mode 100644 index 97b6682..0000000 --- a/runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldPresenter.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 1df1c82e51d1ee04c96247cdff61101a \ No newline at end of file diff --git a/runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldRuntime.cs b/runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldRuntime.cs deleted file mode 100644 index 3dd56e4..0000000 --- a/runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldRuntime.cs +++ /dev/null @@ -1,207 +0,0 @@ -using System; -using GameCult.Eve.Surface; -using UnityEngine; - -#nullable enable - -namespace GameCult.Eve.UnityScene -{ - public sealed class EveUnityPlayableWorldRuntime : IDisposable - { - private readonly EveUnitySceneProviderSurfaceDocumentSource _surfaceSource; - private readonly EveUnitySceneProviderConnection _connection; - private readonly EveUnityPlayableWorldLiveClient _client; - private readonly EveUnityPlayableWorldAssetManifestDocumentSource? _assetManifestSource; - private bool _assetManifestConnected; - - public EveUnityPlayableWorldRuntime( - IEveUnitySceneProviderSurfaceDocumentSource surfaceDocuments, - IEveUnitySceneCommandSink commandSink, - IEveUnityPlayableWorldSceneSink sceneSink, - IEveUnityPlayableWorldAssetManifestDocumentSource? assetManifestDocuments = null, - IEveUnitySceneCommandReceiptSource? receiptSource = null, - IEveUnityPlayableWorldAssetResolver? assetResolver = null, - EveUnityPlayableWorldAssetManifestCache? assetManifests = null) - { - if (surfaceDocuments == null) throw new ArgumentNullException(nameof(surfaceDocuments)); - if (commandSink == null) throw new ArgumentNullException(nameof(commandSink)); - if (sceneSink == null) throw new ArgumentNullException(nameof(sceneSink)); - - AssetManifests = assetManifests ?? new EveUnityPlayableWorldAssetManifestCache(); - _surfaceSource = new EveUnitySceneProviderSurfaceDocumentSource(surfaceDocuments); - _connection = new EveUnitySceneProviderConnection(_surfaceSource, commandSink); - _client = new EveUnityPlayableWorldLiveClient( - _connection, - new EveUnityPlayableWorldPresenter(sceneSink, assetResolver ?? new EveUnityAssetRefResolver()), - receiptSource); - - if (assetManifestDocuments != null) - _assetManifestSource = new EveUnityPlayableWorldAssetManifestDocumentSource(assetManifestDocuments); - } - - public EveUnityPlayableWorldAssetManifestCache AssetManifests { get; } - - public EveUnityPlayableWorldProjection? ActiveWorld => _client.ActiveWorld; - - public EveUnitySceneProjection? ActiveProjection => _client.ActiveProjection; - - public EveUnityPlayableWorldPresentation? LastPresentation => _client.LastPresentation; - - public EveUnitySceneCommandReceipt? LastReceipt => _client.LastReceipt; - - public long ActiveVersion => _client.ActiveVersion; - - public string SourcePointer => _client.SourcePointer; - - public event Action? ReceiptAvailable - { - add { _client.ReceiptAvailable += value; } - remove { _client.ReceiptAvailable -= value; } - } - - public static EveUnityPlayableWorldRuntime CreateForGameObjectScene( - Transform root, - IEveUnitySceneProviderSurfaceDocumentSource surfaceDocuments, - IEveUnitySceneCommandSink commandSink, - IEveUnityPlayableWorldAssetManifestDocumentSource? assetManifestDocuments = null, - IEveUnitySceneCommandReceiptSource? receiptSource = null, - IEveUnityGameObjectAssetProvider? fallbackAssetProvider = null) - { - EveUnityPlayableWorldRuntime? runtime = null; - var assetManifests = new EveUnityPlayableWorldAssetManifestCache(); - var liveAssetProvider = new EveUnityLivePlayableWorldAssetProvider( - assetManifests, - () => runtime?.ActiveWorld, - fallbackAssetProvider ?? new EveUnityResourcesAssetProvider()); - var sceneSink = new EveUnityGameObjectPlayableWorldSceneSink(root, liveAssetProvider); - - runtime = new EveUnityPlayableWorldRuntime( - surfaceDocuments, - commandSink, - sceneSink, - assetManifestDocuments, - receiptSource, - new EveUnityAssetRefResolver(), - assetManifests); - return runtime; - } - - public EveUnityPlayableWorldPresentation Connect() - { - EnsureAssetManifestConnected(); - return _client.Connect(); - } - - public EveUnityPlayableWorldPresentation Refresh() - { - EnsureAssetManifestConnected(); - return _client.Refresh(); - } - - public EveSurfaceCommandRequest SubmitMoveIntent( - string entityId, - float targetX, - float targetY, - float targetZ, - DateTimeOffset? issuedAt = null) - { - return _client.SubmitMoveIntent(entityId, targetX, targetY, targetZ, issuedAt); - } - - public EveSurfaceCommandRequest SubmitMoveVectorIntent( - string entityId, - float directionX, - float directionY, - float scalarValue = 1f, - DateTimeOffset? issuedAt = null) - { - return _client.SubmitMoveVectorIntent(entityId, directionX, directionY, scalarValue, issuedAt); - } - - public EveSurfaceCommandRequest SubmitFocusIntent( - string entityId, - DateTimeOffset? issuedAt = null) - { - return _client.SubmitFocusIntent(entityId, issuedAt); - } - - public EveSurfaceCommandRequest SubmitTargetIntent( - string sourceEntityId, - string targetEntityId, - DateTimeOffset? issuedAt = null) - { - return _client.SubmitTargetIntent(sourceEntityId, targetEntityId, issuedAt); - } - - public EveSurfaceCommandRequest SubmitActionIntent( - string entityId, - string actionId, - DateTimeOffset? issuedAt = null) - { - return _client.SubmitActionIntent(entityId, actionId, issuedAt); - } - - public void Disconnect() - { - _client.Disconnect(); - - if (_assetManifestConnected && _assetManifestSource != null) - { - AssetManifests.Disconnect(_assetManifestSource); - _assetManifestSource.Disconnect(); - _assetManifestConnected = false; - } - } - - public void Dispose() - { - Disconnect(); - _client.Dispose(); - _assetManifestSource?.Dispose(); - } - - private void EnsureAssetManifestConnected() - { - if (_assetManifestConnected || _assetManifestSource == null) - return; - - _assetManifestSource.Connect(); - AssetManifests.Connect(_assetManifestSource); - _assetManifestConnected = true; - } - } - - public sealed class EveUnityLivePlayableWorldAssetProvider : IEveUnityGameObjectAssetProvider - { - private readonly EveUnityPlayableWorldAssetManifestCache _assetManifests; - private readonly Func _activeWorld; - private readonly IEveUnityGameObjectAssetProvider _fallback; - - public EveUnityLivePlayableWorldAssetProvider( - EveUnityPlayableWorldAssetManifestCache assetManifests, - Func activeWorld, - IEveUnityGameObjectAssetProvider fallback) - { - _assetManifests = assetManifests ?? throw new ArgumentNullException(nameof(assetManifests)); - _activeWorld = activeWorld ?? throw new ArgumentNullException(nameof(activeWorld)); - _fallback = fallback ?? throw new ArgumentNullException(nameof(fallback)); - } - - public GameObject? ResolvePrefab(EveUnityPlayableWorldAssetBinding asset) - { - if (asset == null) throw new ArgumentNullException(nameof(asset)); - - var world = _activeWorld(); - var manifest = world == null ? null : _assetManifests.GetForWorld(world); - if (manifest != null) - { - var provider = new EveUnityManifestGameObjectAssetProvider(manifest, _fallback); - var prefab = provider.ResolvePrefab(asset); - if (prefab != null) - return prefab; - } - - return _fallback.ResolvePrefab(asset); - } - } -} diff --git a/runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldRuntime.cs.meta b/runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldRuntime.cs.meta deleted file mode 100644 index 57fd452..0000000 --- a/runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldRuntime.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 9323e6fa0b61837499fa84b30e597e92 \ No newline at end of file diff --git a/runtimes/incubating/eve-unity-scene/Runtime/EveUnityProviderRefreshSource.cs b/runtimes/incubating/eve-unity-scene/Runtime/EveUnityProviderRefreshSource.cs deleted file mode 100644 index 06f8937..0000000 --- a/runtimes/incubating/eve-unity-scene/Runtime/EveUnityProviderRefreshSource.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace GameCult.Eve.UnityScene -{ - public interface IEveUnityProviderRefreshSource - { - void Refresh(); - } -} diff --git a/runtimes/incubating/eve-unity-scene/Runtime/EveUnityProviderRefreshSource.cs.meta b/runtimes/incubating/eve-unity-scene/Runtime/EveUnityProviderRefreshSource.cs.meta deleted file mode 100644 index 29cdeb8..0000000 --- a/runtimes/incubating/eve-unity-scene/Runtime/EveUnityProviderRefreshSource.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: babddb726f9747e43a7789eb6b584fad \ No newline at end of file diff --git a/runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneClientSession.cs b/runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneClientSession.cs deleted file mode 100644 index e82cf56..0000000 --- a/runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneClientSession.cs +++ /dev/null @@ -1,220 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using GameCult.Eve.Surface; - -#nullable enable - -namespace GameCult.Eve.UnityScene -{ - public sealed class EveUnitySceneClientSession - { - public const string RuntimeClientId = "unity-scene"; - - private readonly EveUnitySceneSurfaceLowerer _lowerer; - private EveUnitySceneProviderSurfaceSnapshot? _activeSnapshot; - - public EveUnitySceneClientSession() - : this(new EveUnitySceneSurfaceLowerer()) - { - } - - public EveUnitySceneClientSession(EveUnitySceneSurfaceLowerer lowerer) - { - _lowerer = lowerer ?? throw new ArgumentNullException(nameof(lowerer)); - } - - public EveUnitySceneProjection? ActiveProjection { get; private set; } - - public string ActiveSourcePointer => _activeSnapshot?.SourcePointer ?? ""; - - public long ActiveVersion => _activeSnapshot?.Version ?? 0; - - public EveUnitySceneProjection Connect(EveUnitySceneProviderSurfaceSnapshot snapshot) - { - if (snapshot == null) throw new ArgumentNullException(nameof(snapshot)); - - var projection = _lowerer.Lower(snapshot.Document, snapshot.AdvertisedSurface); - _activeSnapshot = snapshot; - ActiveProjection = projection; - return projection; - } - - public EveUnitySceneProjection ApplySnapshot(EveUnitySceneProviderSurfaceSnapshot snapshot) - { - return Connect(snapshot); - } - - public EveSurfaceCommandRequest CreateMoveIntent( - string entityId, - float targetX, - float targetY, - float targetZ, - DateTimeOffset? issuedAt = null) - { - var playableWorld = RequirePlayableWorld(); - return CreatePlayableWorldIntent( - playableWorld.MovementCommand, - new Dictionary(StringComparer.Ordinal) - { - ["entityId"] = entityId ?? "", - ["targetPosition"] = FormatVector3(targetX, targetY, targetZ) - }, - issuedAt); - } - - public EveSurfaceCommandRequest CreateMoveVectorIntent( - string entityId, - float directionX, - float directionY, - float scalarValue = 1f, - DateTimeOffset? issuedAt = null) - { - var playableWorld = RequirePlayableWorld(); - return CreatePlayableWorldIntent( - playableWorld.MovementCommand, - new Dictionary(StringComparer.Ordinal) - { - ["entityId"] = entityId ?? "", - ["directionX"] = FormatFloat(directionX), - ["directionY"] = FormatFloat(directionY), - ["scalarValue"] = FormatFloat(scalarValue) - }, - issuedAt); - } - - public EveSurfaceCommandRequest CreateFocusIntent( - string entityId, - DateTimeOffset? issuedAt = null) - { - var playableWorld = RequirePlayableWorld(); - return CreatePlayableWorldIntent( - playableWorld.FocusCommand, - new Dictionary(StringComparer.Ordinal) - { - ["entityId"] = entityId ?? "" - }, - issuedAt); - } - - public EveSurfaceCommandRequest CreateTargetIntent( - string sourceEntityId, - string targetEntityId, - DateTimeOffset? issuedAt = null) - { - var playableWorld = RequirePlayableWorld(); - return CreatePlayableWorldIntent( - playableWorld.TargetCommand, - new Dictionary(StringComparer.Ordinal) - { - ["sourceEntityId"] = sourceEntityId ?? "", - ["targetEntityId"] = targetEntityId ?? "" - }, - issuedAt); - } - - public EveSurfaceCommandRequest CreateActionIntent( - string entityId, - string actionId, - DateTimeOffset? issuedAt = null) - { - var playableWorld = RequirePlayableWorld(); - return CreatePlayableWorldIntent( - playableWorld.ActionCommand, - new Dictionary(StringComparer.Ordinal) - { - ["entityId"] = entityId ?? "", - ["actionId"] = actionId ?? "" - }, - issuedAt); - } - - public EveSurfaceCommandRequest CreatePlayableWorldIntent( - string commandId, - IReadOnlyDictionary? payload = null, - DateTimeOffset? issuedAt = null) - { - if (string.IsNullOrWhiteSpace(commandId)) - throw new InvalidOperationException("Playable world command id is missing from the active surface."); - - var snapshot = RequireSnapshot(); - var projection = RequireProjection(); - var envelopePayload = new Dictionary(StringComparer.Ordinal) - { - ["commandId"] = commandId - }; - - if (payload != null) - { - foreach (var entry in payload) - envelopePayload[entry.Key] = entry.Value; - } - - return _lowerer.CreateCommandIntent( - snapshot.Document, - snapshot.AdvertisedSurface, - projection.CommandBoundary, - envelopePayload, - issuedAt); - } - - private EveUnityPlayableWorldProjection RequirePlayableWorld() - { - var projection = RequireProjection(); - if (projection.PlayableWorld == null) - throw new InvalidOperationException("The active Unity scene surface does not expose a playable world projection."); - return projection.PlayableWorld; - } - - private EveUnitySceneProjection RequireProjection() - { - if (ActiveProjection == null) - throw new InvalidOperationException("No provider surface snapshot has been connected to the Unity scene client session."); - return ActiveProjection; - } - - private EveUnitySceneProviderSurfaceSnapshot RequireSnapshot() - { - if (_activeSnapshot == null) - throw new InvalidOperationException("No provider surface snapshot has been connected to the Unity scene client session."); - return _activeSnapshot; - } - - private static string FormatVector3(float x, float y, float z) - { - return string.Join( - ",", - x.ToString("R", CultureInfo.InvariantCulture), - y.ToString("R", CultureInfo.InvariantCulture), - z.ToString("R", CultureInfo.InvariantCulture)); - } - - private static string FormatFloat(float value) - { - return value.ToString("R", CultureInfo.InvariantCulture); - } - } - - public sealed class EveUnitySceneProviderSurfaceSnapshot - { - public EveUnitySceneProviderSurfaceSnapshot( - EveSurfaceDocument document, - EveUnitySceneProviderSurfaceAdvertisement advertisedSurface, - string sourcePointer, - long version = 0) - { - Document = document ?? throw new ArgumentNullException(nameof(document)); - AdvertisedSurface = advertisedSurface ?? throw new ArgumentNullException(nameof(advertisedSurface)); - SourcePointer = sourcePointer ?? ""; - Version = version; - } - - public EveSurfaceDocument Document { get; } - - public EveUnitySceneProviderSurfaceAdvertisement AdvertisedSurface { get; } - - public string SourcePointer { get; } - - public long Version { get; } - } -} diff --git a/runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneClientSession.cs.meta b/runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneClientSession.cs.meta deleted file mode 100644 index 5919fc3..0000000 --- a/runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneClientSession.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: d2b8fac8eb072f8419afa594928840ef \ No newline at end of file diff --git a/runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneLiveProviderBridge.cs b/runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneLiveProviderBridge.cs deleted file mode 100644 index 44afc89..0000000 --- a/runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneLiveProviderBridge.cs +++ /dev/null @@ -1,290 +0,0 @@ -using System; -using GameCult.Eve.Surface; -using UnityEngine; - -#nullable enable - -namespace GameCult.Eve.UnityScene -{ - public interface IEveUnitySceneLiveProviderTransport - { - string TransportKind { get; } - - string SurfacePointer { get; } - - string AssetManifestPointer { get; } - - EveUnitySceneProviderSurfaceDocument CurrentSurfaceDocument { get; } - - EveUnityPlayableWorldAssetManifestDocument CurrentAssetManifestDocument { get; } - - event Action SurfaceDocumentAvailable; - - event Action AssetManifestDocumentAvailable; - - event Action CommandReceiptAvailable; - - void Connect(); - - void Disconnect(); - - void Refresh(); - - void SubmitCommand(EveSurfaceCommandRequest request); - } - - public abstract class EveUnitySceneLiveProviderTransportBehaviour : - MonoBehaviour, - IEveUnitySceneLiveProviderTransport - { - public abstract string TransportKind { get; } - - public abstract string SurfacePointer { get; } - - public abstract string AssetManifestPointer { get; } - - public abstract EveUnitySceneProviderSurfaceDocument CurrentSurfaceDocument { get; } - - public abstract EveUnityPlayableWorldAssetManifestDocument CurrentAssetManifestDocument { get; } - - public abstract event Action SurfaceDocumentAvailable; - - public abstract event Action AssetManifestDocumentAvailable; - - public abstract event Action CommandReceiptAvailable; - - public abstract void Connect(); - - public abstract void Disconnect(); - - public abstract void Refresh(); - - public abstract void SubmitCommand(EveSurfaceCommandRequest request); - } - - public sealed class EveUnitySceneLiveProviderBridgeComponent : - MonoBehaviour, - IEveUnitySceneProviderSurfaceDocumentSource, - IEveUnitySceneProviderSurfaceDocumentConnection, - IEveUnityPlayableWorldAssetManifestDocumentSource, - IEveUnitySceneCommandSink, - IEveUnitySceneCommandReceiptSource, - IEveUnityProviderRefreshSource - { - [SerializeField] private MonoBehaviour? transportBehaviour; - - private EveUnitySceneLiveProviderBridge? _bridge; - private IEveUnitySceneLiveProviderTransport? _configuredTransport; - - public string TransportKind => Bridge.TransportKind; - - public string SurfacePointer => Bridge.SurfacePointer; - - public string AssetManifestPointer => Bridge.AssetManifestPointer; - - public string SinkKind => Bridge.SinkKind; - - public string ManifestRef => Bridge.ManifestRef; - - public EveUnitySceneProviderSurfaceDocument CurrentSurfaceDocument => Bridge.CurrentSurfaceDocument; - - public EveUnityPlayableWorldAssetManifestDocument CurrentAssetManifestDocument => Bridge.CurrentAssetManifestDocument; - - EveUnitySceneProviderSurfaceDocument IEveUnitySceneProviderSurfaceDocumentSource.CurrentDocument => - Bridge.CurrentSurfaceDocument; - - EveUnityPlayableWorldAssetManifestDocument IEveUnityPlayableWorldAssetManifestDocumentSource.CurrentDocument => - Bridge.CurrentAssetManifestDocument; - - public event Action? DocumentAvailable - { - add { Bridge.DocumentAvailable += value; } - remove { Bridge.DocumentAvailable -= value; } - } - - public event Action? AssetManifestDocumentAvailable - { - add { Bridge.AssetManifestDocumentAvailable += value; } - remove { Bridge.AssetManifestDocumentAvailable -= value; } - } - - event Action IEveUnityPlayableWorldAssetManifestDocumentSource.DocumentAvailable - { - add { Bridge.AssetManifestDocumentAvailable += value; } - remove { Bridge.AssetManifestDocumentAvailable -= value; } - } - - public event Action? ReceiptAvailable - { - add { Bridge.ReceiptAvailable += value; } - remove { Bridge.ReceiptAvailable -= value; } - } - - public void Configure(IEveUnitySceneLiveProviderTransport transport) - { - if (transport == null) throw new ArgumentNullException(nameof(transport)); - _bridge?.Dispose(); - _configuredTransport = transport; - _bridge = new EveUnitySceneLiveProviderBridge(transport); - } - - public void Connect() - { - Bridge.Connect(); - } - - public void Disconnect() - { - _bridge?.Disconnect(); - } - - public void Refresh() - { - Bridge.Connect(); - Bridge.Refresh(); - } - - public void Submit(EveSurfaceCommandRequest request) - { - Bridge.Submit(request); - } - - private void OnDisable() - { - Disconnect(); - } - - private void OnDestroy() - { - _bridge?.Dispose(); - _bridge = null; - } - - private EveUnitySceneLiveProviderBridge Bridge - { - get - { - if (_bridge != null) - return _bridge; - - var transport = _configuredTransport ?? transportBehaviour as IEveUnitySceneLiveProviderTransport; - if (transport == null) - throw new InvalidOperationException( - "Eve Unity scene live provider bridge requires a transport implementing IEveUnitySceneLiveProviderTransport."); - - _bridge = new EveUnitySceneLiveProviderBridge(transport); - return _bridge; - } - } - } - - public sealed class EveUnitySceneLiveProviderBridge : - IEveUnitySceneProviderSurfaceDocumentSource, - IEveUnitySceneProviderSurfaceDocumentConnection, - IEveUnityPlayableWorldAssetManifestDocumentSource, - IEveUnitySceneCommandSink, - IEveUnitySceneCommandReceiptSource, - IEveUnityProviderRefreshSource, - IDisposable - { - private readonly IEveUnitySceneLiveProviderTransport _transport; - private bool _connected; - - public EveUnitySceneLiveProviderBridge(IEveUnitySceneLiveProviderTransport transport) - { - _transport = transport ?? throw new ArgumentNullException(nameof(transport)); - CurrentSurfaceDocument = _transport.CurrentSurfaceDocument; - CurrentAssetManifestDocument = _transport.CurrentAssetManifestDocument; - } - - public string TransportKind => _transport.TransportKind; - - public string SurfacePointer => _transport.SurfacePointer; - - public string AssetManifestPointer => _transport.AssetManifestPointer; - - public string SinkKind => _transport.TransportKind; - - public string ManifestRef => CurrentAssetManifestDocument.ManifestRef; - - public EveUnitySceneProviderSurfaceDocument CurrentSurfaceDocument { get; private set; } - - public EveUnityPlayableWorldAssetManifestDocument CurrentAssetManifestDocument { get; private set; } - - EveUnitySceneProviderSurfaceDocument IEveUnitySceneProviderSurfaceDocumentSource.CurrentDocument => - CurrentSurfaceDocument; - - EveUnityPlayableWorldAssetManifestDocument IEveUnityPlayableWorldAssetManifestDocumentSource.CurrentDocument => - CurrentAssetManifestDocument; - - public event Action? DocumentAvailable; - - public event Action? AssetManifestDocumentAvailable; - - event Action IEveUnityPlayableWorldAssetManifestDocumentSource.DocumentAvailable - { - add { AssetManifestDocumentAvailable += value; } - remove { AssetManifestDocumentAvailable -= value; } - } - - public event Action? ReceiptAvailable; - - public void Connect() - { - if (_connected) - return; - - _transport.SurfaceDocumentAvailable += OnSurfaceDocumentAvailable; - _transport.AssetManifestDocumentAvailable += OnAssetManifestDocumentAvailable; - _transport.CommandReceiptAvailable += OnCommandReceiptAvailable; - _transport.Connect(); - _connected = true; - } - - public void Disconnect() - { - if (!_connected) - return; - - _transport.SurfaceDocumentAvailable -= OnSurfaceDocumentAvailable; - _transport.AssetManifestDocumentAvailable -= OnAssetManifestDocumentAvailable; - _transport.CommandReceiptAvailable -= OnCommandReceiptAvailable; - _transport.Disconnect(); - _connected = false; - } - - public void Refresh() - { - _transport.Refresh(); - } - - public void Submit(EveSurfaceCommandRequest request) - { - if (request == null) throw new ArgumentNullException(nameof(request)); - _transport.SubmitCommand(request); - } - - public void Dispose() - { - Disconnect(); - } - - private void OnSurfaceDocumentAvailable(EveUnitySceneProviderSurfaceDocument document) - { - CurrentSurfaceDocument = document ?? throw new ArgumentNullException(nameof(document)); - DocumentAvailable?.Invoke(CurrentSurfaceDocument); - } - - private void OnAssetManifestDocumentAvailable(EveUnityPlayableWorldAssetManifestDocument document) - { - CurrentAssetManifestDocument = document ?? throw new ArgumentNullException(nameof(document)); - AssetManifestDocumentAvailable?.Invoke(CurrentAssetManifestDocument); - } - - private void OnCommandReceiptAvailable(EveUnitySceneCommandReceipt receipt) - { - if (receipt == null) throw new ArgumentNullException(nameof(receipt)); - ReceiptAvailable?.Invoke(receipt); - } - } -} diff --git a/runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneLiveProviderBridge.cs.meta b/runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneLiveProviderBridge.cs.meta deleted file mode 100644 index d7a6df6..0000000 --- a/runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneLiveProviderBridge.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 7e11af135f8f48c48a2e0d88f8f9d04c diff --git a/runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneProviderConnection.cs b/runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneProviderConnection.cs deleted file mode 100644 index e21292c..0000000 --- a/runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneProviderConnection.cs +++ /dev/null @@ -1,291 +0,0 @@ -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 SnapshotAvailable; - - void Connect(); - - void Refresh(); - - void Disconnect(); - } - - public interface IEveUnitySceneCommandSink - { - string SinkKind { get; } - - void Submit(EveSurfaceCommandRequest request); - } - - public interface IEveUnitySceneProviderSurfaceDocumentSource - { - EveUnitySceneProviderSurfaceDocument CurrentDocument { get; } - - event Action DocumentAvailable; - } - - public interface IEveUnitySceneProviderSurfaceDocumentConnection - { - void Connect(); - - void Disconnect(); - } - - public sealed class EveUnitySceneProviderSurfaceDocument - { - public EveUnitySceneProviderSurfaceDocument( - EveSurfaceDocument surfaceDocument, - EveUnitySceneProviderSurfaceAdvertisement advertisedSurface, - string sourcePointer, - long version = 0) - { - SurfaceDocument = surfaceDocument ?? throw new ArgumentNullException(nameof(surfaceDocument)); - AdvertisedSurface = advertisedSurface ?? throw new ArgumentNullException(nameof(advertisedSurface)); - SourcePointer = sourcePointer ?? ""; - Version = version == 0 ? surfaceDocument.Version : version; - } - - public EveSurfaceDocument SurfaceDocument { get; } - - public EveUnitySceneProviderSurfaceAdvertisement AdvertisedSurface { get; } - - public string SourcePointer { get; } - - public long Version { get; } - - public EveUnitySceneProviderSurfaceSnapshot ToSnapshot() - { - return new EveUnitySceneProviderSurfaceSnapshot( - SurfaceDocument, - AdvertisedSurface, - SourcePointer, - Version); - } - } - - public sealed class EveUnitySceneProviderSurfaceDocumentSource : IEveUnitySceneProviderSurfaceSource, IDisposable - { - private readonly IEveUnitySceneProviderSurfaceDocumentSource _documentSource; - private readonly IEveUnitySceneProviderSurfaceDocumentConnection? _documentConnection; - private readonly IEveUnityProviderRefreshSource? _refreshSource; - private bool _connected; - - public EveUnitySceneProviderSurfaceDocumentSource( - IEveUnitySceneProviderSurfaceDocumentSource documentSource) - { - _documentSource = documentSource ?? throw new ArgumentNullException(nameof(documentSource)); - _documentConnection = documentSource as IEveUnitySceneProviderSurfaceDocumentConnection; - _refreshSource = documentSource as IEveUnityProviderRefreshSource; - CurrentSnapshot = _documentSource.CurrentDocument.ToSnapshot(); - } - - public string ProviderId => CurrentSnapshot.Document.ProviderId; - - public string SurfaceId => CurrentSnapshot.AdvertisedSurface.SurfaceId; - - public string SourcePointer => CurrentSnapshot.SourcePointer; - - public EveUnitySceneProviderSurfaceSnapshot CurrentSnapshot { get; private set; } - - public event Action? SnapshotAvailable; - - public void Connect() - { - if (_connected) - return; - - _documentSource.DocumentAvailable += OnDocumentAvailable; - _documentConnection?.Connect(); - _connected = true; - } - - public void Refresh() - { - _refreshSource?.Refresh(); - } - - public void Disconnect() - { - if (!_connected) - return; - - _documentConnection?.Disconnect(); - _documentSource.DocumentAvailable -= OnDocumentAvailable; - _connected = false; - } - - public void Dispose() - { - Disconnect(); - } - - private void OnDocumentAvailable(EveUnitySceneProviderSurfaceDocument document) - { - if (document == null) throw new ArgumentNullException(nameof(document)); - CurrentSnapshot = document.ToSnapshot(); - SnapshotAvailable?.Invoke(CurrentSnapshot); - } - } - - 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? ProjectionUpdated; - - public EveUnitySceneProjection Connect() - { - if (!_connected) - { - _surfaceSource.SnapshotAvailable += OnSnapshotAvailable; - _surfaceSource.Connect(); - _connected = true; - } - - if (HasAppliedCurrentSnapshot()) - return _session.ActiveProjection!; - - return ApplySnapshot(_surfaceSource.CurrentSnapshot); - } - - public EveUnitySceneProjection Refresh() - { - _surfaceSource.Refresh(); - if (HasAppliedCurrentSnapshot()) - return _session.ActiveProjection!; - - 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 SubmitMoveVectorIntent( - string entityId, - float directionX, - float directionY, - float scalarValue = 1f, - DateTimeOffset? issuedAt = null) - { - return Submit(_session.CreateMoveVectorIntent(entityId, directionX, directionY, scalarValue, 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; - _surfaceSource.Disconnect(); - _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 bool HasAppliedCurrentSnapshot() - { - var projection = _session.ActiveProjection; - if (projection == null) - return false; - - var snapshot = _surfaceSource.CurrentSnapshot; - return _session.ActiveVersion == snapshot.Version && - string.Equals(_session.ActiveSourcePointer, snapshot.SourcePointer, StringComparison.Ordinal); - } - - private void OnSnapshotAvailable(EveUnitySceneProviderSurfaceSnapshot snapshot) - { - ApplySnapshot(snapshot); - } - } -} diff --git a/runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneProviderConnection.cs.meta b/runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneProviderConnection.cs.meta deleted file mode 100644 index d594d36..0000000 --- a/runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneProviderConnection.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 9e93e937d561d4941b5080a454091f7a \ No newline at end of file diff --git a/runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs b/runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs deleted file mode 100644 index 6c02fef..0000000 --- a/runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs +++ /dev/null @@ -1,578 +0,0 @@ -using System; -using System.Collections.Generic; -using GameCult.Eve.Surface; -using GameCult.Mesh; - -#nullable enable - -namespace GameCult.Eve.UnityScene -{ - public sealed class EveUnitySceneSurfaceLowerer - { - private static readonly SaiVisualNovelUnitySceneProjectionAdapter SaiVisualNovelAdapter = new SaiVisualNovelUnitySceneProjectionAdapter(); - private static readonly NornGraphUnitySceneProjectionAdapter NornGraphAdapter = new NornGraphUnitySceneProjectionAdapter(); - private static readonly TeXMathUnitySceneProjectionAdapter TeXMathAdapter = new TeXMathUnitySceneProjectionAdapter(); - - public EveUnitySceneProjection Lower( - EveSurfaceDocument document, - EveUnitySceneProviderSurfaceAdvertisement advertisedSurface) - { - if (document == null) throw new ArgumentNullException(nameof(document)); - if (advertisedSurface == null) throw new ArgumentNullException(nameof(advertisedSurface)); - if (!string.Equals(document.Surface.Id, advertisedSurface.SurfaceId, StringComparison.Ordinal)) - { - throw new InvalidOperationException( - $"Active surface '{document.Surface.Id}' does not match advertised Unity scene surface '{advertisedSurface.SurfaceId}'."); - } - - return new EveUnitySceneProjection( - document.ProviderId, - document.Surface.Id, - advertisedSurface.WorldInteraction.ProjectionKind, - advertisedSurface.WorldInteraction.CommandBoundary, - advertisedSurface.WorldInteraction.ReceiptSchema, - advertisedSurface.WorldInteraction.Ownership, - BuildPlayableWorld(document.Surface.Root), - BuildSceneGraph(document.Surface.Root)); - } - - public EveSurfaceCommandRequest CreateCommandIntent( - EveSurfaceDocument document, - EveUnitySceneProviderSurfaceAdvertisement advertisedSurface, - string command, - IReadOnlyDictionary? payload = null, - DateTimeOffset? issuedAt = null) - { - if (document == null) throw new ArgumentNullException(nameof(document)); - if (advertisedSurface == null) throw new ArgumentNullException(nameof(advertisedSurface)); - if (string.IsNullOrWhiteSpace(command)) throw new ArgumentException("Command is required.", nameof(command)); - - var projection = Lower(document, advertisedSurface); - return new EveSurfaceCommandRequest( - projection.ProviderId, - projection.SurfaceId, - ResolveOperation(document, command), - CultMesh.OperationPayload(payload ?? new Dictionary(StringComparer.Ordinal)), - issuedAt ?? DateTimeOffset.UtcNow, - "unity-scene", - projection.CommandBoundary, - projection.ReceiptSchema); - } - - private static CultMeshOperationInvocationDescriptor ResolveOperation( - EveSurfaceDocument document, - string command) - { - foreach (var template in document.Commands) - { - if (string.Equals(template.Command, command, StringComparison.Ordinal)) - return CultMesh.OperationInvocation(template.Operation); - } - - return CultMesh.OperationInvocation(command); - } - - private static EveUnitySceneNode BuildSceneGraph(EveSurfaceComponent component) - { - var children = new List(component.Children.Count); - foreach (var child in component.Children) - { - children.Add(BuildSceneGraph(child)); - } - - return new EveUnitySceneNode( - component.Id, - component.Kind, - SceneObjectKind(component.Kind), - component.Props, - component.Layout, - component.Style, - component.StateBindings.Count, - component.EmbeddedDocuments.Count, - BuildEmbeddedDocumentSlots(component.EmbeddedDocuments), - BuildPluginProjection(component), - children); - } - - private static EveUnityPlayableWorldProjection? BuildPlayableWorld(EveSurfaceComponent root) - { - var worldRoot = FindFirst(root, component => string.Equals(component.Kind, "world.scene3d", StringComparison.Ordinal)); - if (worldRoot == null) - return null; - - var entities = new List(); - foreach (var component in Flatten(worldRoot)) - { - if (string.Equals(component.Kind, "world.entity3d", StringComparison.Ordinal)) - entities.Add(BuildPlayableEntity(component)); - } - - return new EveUnityPlayableWorldProjection( - worldRoot.Id, - worldRoot.GetProp("statePointerId", worldRoot.GetProp("worldStatePointerId")), - worldRoot.GetProp("assetManifest", worldRoot.GetProp("assetManifestUri")), - worldRoot.GetProp("inputProfile"), - worldRoot.GetProp("cameraRig"), - worldRoot.GetProp("playerEntityId"), - worldRoot.GetProp("movementCommand"), - worldRoot.GetProp("focusCommand"), - worldRoot.GetProp("targetCommand"), - worldRoot.GetProp("actionCommand"), - entities); - } - - private static EveUnityPlayableWorldEntity BuildPlayableEntity(EveSurfaceComponent component) - { - var position = ParseVector3(component.GetProp("position")); - return new EveUnityPlayableWorldEntity( - component.Id, - component.GetProp("entityId", component.Id), - component.GetProp("entityKind", component.GetProp("kind")), - component.GetProp("label", component.GetProp("name")), - component.GetProp("faction"), - component.GetProp("assetRef", component.GetProp("meshRef", component.GetProp("prefabRef"))), - position.x, - position.y, - position.z, - ParseFloat(component.GetProp("rotationY", component.GetProp("yaw")), 0f), - ParseFloat(component.GetProp("radius"), 0f), - ParseBoolean(component.GetProp("selectable")), - ParseBoolean(component.GetProp("controllable")), - component.GetProp("focusCommand"), - component.GetProp("moveCommand"), - component.GetProp("targetCommand"), - component.GetProp("actionCommand")); - } - - private static EveSurfaceComponent? FindFirst( - EveSurfaceComponent component, - Predicate predicate) - { - if (predicate(component)) - return component; - foreach (var child in component.Children) - { - var found = FindFirst(child, predicate); - if (found != null) - return found; - } - return null; - } - - private static IEnumerable Flatten(EveSurfaceComponent component) - { - yield return component; - foreach (var child in component.Children) - { - foreach (var nested in Flatten(child)) - yield return nested; - } - } - - private static (float x, float y, float z) ParseVector3(string value) - { - var parts = (value ?? "").Split(','); - return ( - parts.Length > 0 ? ParseFloat(parts[0], 0f) : 0f, - parts.Length > 1 ? ParseFloat(parts[1], 0f) : 0f, - parts.Length > 2 ? ParseFloat(parts[2], 0f) : 0f); - } - - private static float ParseFloat(string value, float fallback) - { - return float.TryParse(value, System.Globalization.NumberStyles.Float, System.Globalization.CultureInfo.InvariantCulture, out var parsed) - ? parsed - : fallback; - } - - private static bool ParseBoolean(string value) - { - return string.Equals(value, "true", StringComparison.OrdinalIgnoreCase) || - string.Equals(value, "1", StringComparison.Ordinal); - } - - private static EveUnityScenePluginProjection? BuildPluginProjection(EveSurfaceComponent component) - { - if (SaiVisualNovelAdapter.CanProject(component)) - return SaiVisualNovelAdapter.Project(component); - if (NornGraphAdapter.CanProject(component)) - return NornGraphAdapter.Project(component); - if (TeXMathAdapter.CanProject(component)) - return TeXMathAdapter.Project(component); - return null; - } - - private static IReadOnlyList BuildEmbeddedDocumentSlots( - IReadOnlyList embeddedDocuments) - { - var slots = new List(embeddedDocuments.Count); - foreach (var slot in embeddedDocuments) - { - slots.Add(new EveUnitySceneEmbeddedDocumentSlot( - slot.SlotId, - slot.DocumentId, - slot.SchemaId, - slot.PresentationKind)); - } - return slots; - } - - private static string SceneObjectKind(string componentKind) - { - if (string.IsNullOrWhiteSpace(componentKind)) - return "empty"; - if (string.Equals(componentKind, "world.scene3d", StringComparison.Ordinal)) - return "playable-world-root"; - if (string.Equals(componentKind, "world.entity3d", StringComparison.Ordinal)) - return "playable-world-entity"; - if (string.Equals(componentKind, "field.vector3d", StringComparison.Ordinal) || - string.Equals(componentKind, "field.scalar3d", StringComparison.Ordinal)) - return "world-field-3d"; - if (string.Equals(componentKind, "vn.stage", StringComparison.Ordinal)) - return "sai-vn-scene-stage"; - if (string.Equals(componentKind, "panel.dialogue", StringComparison.Ordinal) || - string.Equals(componentKind, "text.dialogue", StringComparison.Ordinal)) - return "sai-vn-scene-dialogue"; - if (string.Equals(componentKind, "rail.actions", StringComparison.Ordinal)) - return "sai-vn-scene-action-rail"; - if (componentKind.StartsWith("control.", StringComparison.Ordinal)) - return "command-control"; - if (string.Equals(componentKind, "embed.norn", StringComparison.Ordinal)) - return "norn-graph-scene-projection"; - if (string.Equals(componentKind, "embed.tex", StringComparison.Ordinal)) - return "tex-math-scene-projection"; - if (componentKind.StartsWith("embed.", StringComparison.Ordinal)) - return "plugin-placeholder"; - if (string.Equals(componentKind, "surface.slot", StringComparison.Ordinal)) - return "embedded-surface-slot"; - if (componentKind.StartsWith("world.", StringComparison.Ordinal) || - componentKind.StartsWith("field.", StringComparison.Ordinal)) - return "world-projection-node"; - if (componentKind.StartsWith("text.", StringComparison.Ordinal) || string.Equals(componentKind, "label", StringComparison.Ordinal)) - return "scene-label"; - return "scene-node"; - } - } - - public sealed class EveUnitySceneProjection - { - public EveUnitySceneProjection( - string providerId, - string surfaceId, - string projectionKind, - string commandBoundary, - string receiptSchema, - string ownership, - EveUnityPlayableWorldProjection? playableWorld, - EveUnitySceneNode root) - { - ProviderId = providerId ?? ""; - SurfaceId = surfaceId ?? ""; - ProjectionKind = projectionKind ?? ""; - CommandBoundary = commandBoundary ?? ""; - ReceiptSchema = receiptSchema ?? ""; - Ownership = ownership ?? ""; - PlayableWorld = playableWorld; - Root = root ?? throw new ArgumentNullException(nameof(root)); - } - - public string ProviderId { get; } - - public string SurfaceId { get; } - - public string ProjectionKind { get; } - - public string CommandBoundary { get; } - - public string ReceiptSchema { get; } - - public string Ownership { get; } - - public EveUnityPlayableWorldProjection? PlayableWorld { get; } - - public EveUnitySceneNode Root { get; } - } - - public sealed class EveUnityPlayableWorldProjection - { - public EveUnityPlayableWorldProjection( - string worldRootId, - string statePointerId, - string assetManifest, - string inputProfile, - string cameraRig, - string playerEntityId, - string movementCommand, - string focusCommand, - string targetCommand, - string actionCommand, - IReadOnlyList entities) - { - WorldRootId = worldRootId ?? ""; - StatePointerId = statePointerId ?? ""; - AssetManifest = assetManifest ?? ""; - InputProfile = inputProfile ?? ""; - CameraRig = cameraRig ?? ""; - PlayerEntityId = playerEntityId ?? ""; - MovementCommand = movementCommand ?? ""; - FocusCommand = focusCommand ?? ""; - TargetCommand = targetCommand ?? ""; - ActionCommand = actionCommand ?? ""; - Entities = entities ?? Array.Empty(); - } - - public string WorldRootId { get; } - - public string StatePointerId { get; } - - public string AssetManifest { get; } - - public string InputProfile { get; } - - public string CameraRig { get; } - - public string PlayerEntityId { get; } - - public string MovementCommand { get; } - - public string FocusCommand { get; } - - public string TargetCommand { get; } - - public string ActionCommand { get; } - - public int EntityCount => Entities.Count; - - public IReadOnlyList Entities { get; } - } - - public sealed class EveUnityPlayableWorldEntity - { - public EveUnityPlayableWorldEntity( - string nodeId, - string entityId, - string entityKind, - string label, - string faction, - string assetRef, - float positionX, - float positionY, - float positionZ, - float rotationY, - float radius, - bool selectable, - bool controllable, - string focusCommand, - string moveCommand, - string targetCommand, - string actionCommand) - { - NodeId = nodeId ?? ""; - EntityId = entityId ?? ""; - EntityKind = entityKind ?? ""; - Label = label ?? ""; - Faction = faction ?? ""; - AssetRef = assetRef ?? ""; - PositionX = positionX; - PositionY = positionY; - PositionZ = positionZ; - RotationY = rotationY; - Radius = radius; - Selectable = selectable; - Controllable = controllable; - FocusCommand = focusCommand ?? ""; - MoveCommand = moveCommand ?? ""; - TargetCommand = targetCommand ?? ""; - ActionCommand = actionCommand ?? ""; - } - - public string NodeId { get; } - - public string EntityId { get; } - - public string EntityKind { get; } - - public string Label { get; } - - public string Faction { get; } - - public string AssetRef { get; } - - public float PositionX { get; } - - public float PositionY { get; } - - public float PositionZ { get; } - - public float RotationY { get; } - - public float Radius { get; } - - public bool Selectable { get; } - - public bool Controllable { get; } - - public string FocusCommand { get; } - - public string MoveCommand { get; } - - public string TargetCommand { get; } - - public string ActionCommand { get; } - } - - public sealed class EveUnitySceneNode - { - public EveUnitySceneNode( - string id, - string componentKind, - string sceneObjectKind, - IReadOnlyDictionary props, - IReadOnlyDictionary layout, - IReadOnlyDictionary style, - int stateBindingCount, - int embeddedDocumentCount, - IReadOnlyList embeddedDocuments, - EveUnityScenePluginProjection? pluginProjection, - IReadOnlyList children) - { - Id = id ?? ""; - ComponentKind = componentKind ?? ""; - SceneObjectKind = sceneObjectKind ?? ""; - Props = props ?? new Dictionary(StringComparer.Ordinal); - Layout = layout ?? new Dictionary(StringComparer.Ordinal); - Style = style ?? new Dictionary(StringComparer.Ordinal); - StateBindingCount = stateBindingCount; - EmbeddedDocumentCount = embeddedDocumentCount; - EmbeddedDocuments = embeddedDocuments ?? Array.Empty(); - PluginProjection = pluginProjection; - Children = children ?? Array.Empty(); - } - - public string Id { get; } - - public string ComponentKind { get; } - - public string SceneObjectKind { get; } - - public IReadOnlyDictionary Props { get; } - - public IReadOnlyDictionary Layout { get; } - - public IReadOnlyDictionary Style { get; } - - public int StateBindingCount { get; } - - public int EmbeddedDocumentCount { get; } - - public IReadOnlyList EmbeddedDocuments { get; } - - public EveUnityScenePluginProjection? PluginProjection { get; } - - public IReadOnlyList Children { get; } - } - - public sealed class EveUnityScenePluginProjection - { - public EveUnityScenePluginProjection( - string pluginId, - string projectionKind, - string abiSchema, - string commandBoundary, - IReadOnlyList capabilities, - string command, - string documentId, - string semanticOwner) - { - PluginId = pluginId ?? ""; - ProjectionKind = projectionKind ?? ""; - AbiSchema = abiSchema ?? ""; - CommandBoundary = commandBoundary ?? ""; - Capabilities = capabilities ?? Array.Empty(); - Command = command ?? ""; - DocumentId = documentId ?? ""; - SemanticOwner = semanticOwner ?? ""; - } - - public string PluginId { get; } - - public string ProjectionKind { get; } - - public string AbiSchema { get; } - - public string CommandBoundary { get; } - - public IReadOnlyList Capabilities { get; } - - public string Command { get; } - - public string DocumentId { get; } - - public string SemanticOwner { get; } - } - - public sealed class EveUnitySceneEmbeddedDocumentSlot - { - public EveUnitySceneEmbeddedDocumentSlot( - string slotId, - string documentId, - string schemaId, - string presentationKind) - { - SlotId = slotId ?? ""; - DocumentId = documentId ?? ""; - SchemaId = schemaId ?? ""; - PresentationKind = presentationKind ?? ""; - } - - public string SlotId { get; } - - public string DocumentId { get; } - - public string SchemaId { get; } - - public string PresentationKind { get; } - } - - public sealed class EveUnitySceneProviderSurfaceAdvertisement - { - public EveUnitySceneProviderSurfaceAdvertisement( - string surfaceId, - string surfaceKind, - EveUnitySceneWorldInteraction worldInteraction) - { - SurfaceId = surfaceId ?? ""; - SurfaceKind = surfaceKind ?? ""; - WorldInteraction = worldInteraction ?? throw new ArgumentNullException(nameof(worldInteraction)); - } - - public string SurfaceId { get; } - - public string SurfaceKind { get; } - - public EveUnitySceneWorldInteraction WorldInteraction { get; } - } - - public sealed class EveUnitySceneWorldInteraction - { - public EveUnitySceneWorldInteraction( - string projectionKind, - string commandBoundary, - string receiptSchema, - string ownership) - { - ProjectionKind = projectionKind ?? ""; - CommandBoundary = commandBoundary ?? ""; - ReceiptSchema = receiptSchema ?? ""; - Ownership = ownership ?? ""; - } - - public string ProjectionKind { get; } - - public string CommandBoundary { get; } - - public string ReceiptSchema { get; } - - public string Ownership { get; } - } -} diff --git a/runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs.meta b/runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs.meta deleted file mode 100644 index 0b26f1f..0000000 --- a/runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 32422132e752b9a4f8a45b2a5cb01217 \ No newline at end of file diff --git a/runtimes/incubating/eve-unity-scene/Runtime/GameCult.Eve.UnityScene.asmdef b/runtimes/incubating/eve-unity-scene/Runtime/GameCult.Eve.UnityScene.asmdef deleted file mode 100644 index 395e095..0000000 --- a/runtimes/incubating/eve-unity-scene/Runtime/GameCult.Eve.UnityScene.asmdef +++ /dev/null @@ -1,16 +0,0 @@ -{ - "name": "GameCult.Eve.UnityScene", - "rootNamespace": "GameCult.Eve.UnityScene", - "references": [ - "GameCult.Eve.Surface" - ], - "includePlatforms": [], - "excludePlatforms": [], - "allowUnsafeCode": false, - "overrideReferences": false, - "precompiledReferences": [], - "autoReferenced": true, - "defineConstraints": [], - "versionDefines": [], - "noEngineReferences": false -} diff --git a/runtimes/incubating/eve-unity-scene/Runtime/GameCult.Eve.UnityScene.asmdef.meta b/runtimes/incubating/eve-unity-scene/Runtime/GameCult.Eve.UnityScene.asmdef.meta deleted file mode 100644 index dcd39b3..0000000 --- a/runtimes/incubating/eve-unity-scene/Runtime/GameCult.Eve.UnityScene.asmdef.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: a5b5eeaa1ac2b24409cf4718616ebbe3 -AssemblyDefinitionImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/runtimes/incubating/eve-unity-scene/Runtime/NornGraphUnitySceneProjectionAdapter.cs b/runtimes/incubating/eve-unity-scene/Runtime/NornGraphUnitySceneProjectionAdapter.cs deleted file mode 100644 index 4c6f4c8..0000000 --- a/runtimes/incubating/eve-unity-scene/Runtime/NornGraphUnitySceneProjectionAdapter.cs +++ /dev/null @@ -1,45 +0,0 @@ -using System; -using System.Collections.Generic; -using GameCult.Eve.Surface; - -#nullable enable - -namespace GameCult.Eve.UnityScene -{ - public sealed class NornGraphUnitySceneProjectionAdapter - { - public string PluginId => "norn.graph"; - - public IReadOnlyList Capabilities { get; } = new[] - { - "embed.norn" - }; - - public bool CanProject(EveSurfaceComponent component) - { - return component != null && string.Equals(component.Kind, "embed.norn", StringComparison.Ordinal); - } - - public EveUnityScenePluginProjection Project(EveSurfaceComponent component) - { - if (component == null) throw new ArgumentNullException(nameof(component)); - if (!CanProject(component)) - { - throw new InvalidOperationException( - $"Norn scene projection adapter cannot project component kind '{component.Kind}'."); - } - - return new EveUnityScenePluginProjection( - PluginId, - "norn-scene-embedded-graph-shell", - "gamecult.eve.plugin_abi.v1", - "sidecar-advertised-plugin-abi", - Capabilities, - component.GetProp( - "interaction.nodeAction", - component.GetProp("focusCommand", component.GetProp("command", "graph.focus"))), - component.GetProp("graph.document", component.GetProp("documentId", "")), - "Norn"); - } - } -} diff --git a/runtimes/incubating/eve-unity-scene/Runtime/NornGraphUnitySceneProjectionAdapter.cs.meta b/runtimes/incubating/eve-unity-scene/Runtime/NornGraphUnitySceneProjectionAdapter.cs.meta deleted file mode 100644 index 15f16c2..0000000 --- a/runtimes/incubating/eve-unity-scene/Runtime/NornGraphUnitySceneProjectionAdapter.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: bbe1659cc5c50ff4e9ab6f2ef0ed82c3 \ No newline at end of file diff --git a/runtimes/incubating/eve-unity-scene/Runtime/SaiVisualNovelUnitySceneProjectionAdapter.cs b/runtimes/incubating/eve-unity-scene/Runtime/SaiVisualNovelUnitySceneProjectionAdapter.cs deleted file mode 100644 index 4d4d654..0000000 --- a/runtimes/incubating/eve-unity-scene/Runtime/SaiVisualNovelUnitySceneProjectionAdapter.cs +++ /dev/null @@ -1,87 +0,0 @@ -using System; -using System.Collections.Generic; -using GameCult.Eve.Surface; - -#nullable enable - -namespace GameCult.Eve.UnityScene -{ - public sealed class SaiVisualNovelUnitySceneProjectionAdapter - { - public string PluginId => "sai.vn"; - - public IReadOnlyList Capabilities { get; } = new[] - { - "vn.stage", - "story.choose", - "story.continue", - "story.jump" - }; - - public bool CanProject(EveSurfaceComponent component) - { - if (component == null) - return false; - - switch (component.Kind) - { - case "vn.stage": - case "panel.dialogue": - case "text.dialogue": - case "rail.actions": - return true; - case "control.button": - return StoryCommand(component).StartsWith("story.", StringComparison.Ordinal); - default: - return false; - } - } - - public EveUnityScenePluginProjection Project(EveSurfaceComponent component) - { - if (component == null) throw new ArgumentNullException(nameof(component)); - if (!CanProject(component)) - { - throw new InvalidOperationException( - $"Sai scene projection adapter cannot project component kind '{component.Kind}'."); - } - - return new EveUnityScenePluginProjection( - PluginId, - ProjectionKind(component), - "gamecult.eve.plugin_abi.v1", - "sidecar-advertised-plugin-abi", - Capabilities, - StoryCommand(component), - component.GetProp("storyId", component.GetProp("currentPath", "")), - "Sai"); - } - - private static string ProjectionKind(EveSurfaceComponent component) - { - switch (component.Kind) - { - case "vn.stage": - return "sai-vn-scene-stage-shell"; - case "panel.dialogue": - case "text.dialogue": - return "sai-vn-scene-dialogue-shell"; - case "rail.actions": - return "sai-vn-scene-action-rail-shell"; - case "control.button": - return "sai-vn-scene-story-command-shell"; - default: - return "sai-vn-scene-projection-shell"; - } - } - - private static string StoryCommand(EveSurfaceComponent component) - { - return component.GetProp( - "command", - component.GetProp( - "action.command", - component.GetProp("action", component.GetProp("type", "")))); - } - } -} diff --git a/runtimes/incubating/eve-unity-scene/Runtime/SaiVisualNovelUnitySceneProjectionAdapter.cs.meta b/runtimes/incubating/eve-unity-scene/Runtime/SaiVisualNovelUnitySceneProjectionAdapter.cs.meta deleted file mode 100644 index 989da6e..0000000 --- a/runtimes/incubating/eve-unity-scene/Runtime/SaiVisualNovelUnitySceneProjectionAdapter.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: fc79e8d0b375f3d41ad7809e2129ca6c \ No newline at end of file diff --git a/runtimes/incubating/eve-unity-scene/Runtime/TeXMathUnitySceneProjectionAdapter.cs b/runtimes/incubating/eve-unity-scene/Runtime/TeXMathUnitySceneProjectionAdapter.cs deleted file mode 100644 index c1632b4..0000000 --- a/runtimes/incubating/eve-unity-scene/Runtime/TeXMathUnitySceneProjectionAdapter.cs +++ /dev/null @@ -1,56 +0,0 @@ -using System; -using System.Collections.Generic; -using GameCult.Eve.Surface; - -#nullable enable - -namespace GameCult.Eve.UnityScene -{ - public sealed class TeXMathUnitySceneProjectionAdapter - { - public string PluginId => "tex.math"; - - public IReadOnlyList Capabilities { get; } = new[] - { - "embed.tex", - "tex.inline", - "tex.block", - "tex.scene-placement" - }; - - public bool CanProject(EveSurfaceComponent component) - { - return component != null && string.Equals(component.Kind, "embed.tex", StringComparison.Ordinal); - } - - public EveUnityScenePluginProjection Project(EveSurfaceComponent component) - { - if (component == null) throw new ArgumentNullException(nameof(component)); - if (!CanProject(component)) - { - throw new InvalidOperationException( - $"TeX scene projection adapter cannot project component kind '{component.Kind}'."); - } - - return new EveUnityScenePluginProjection( - PluginId, - ProjectionKind(component), - "gamecult.eve.plugin_abi.v1", - "sidecar-advertised-plugin-abi", - Capabilities, - "", - component.GetProp("sourceUri", component.GetProp("source", "")), - "EvePlugins"); - } - - private static string ProjectionKind(EveSurfaceComponent component) - { - var display = component.GetProp("display", "inline"); - if (string.Equals(display, "block", StringComparison.Ordinal)) - return "tex-math-scene-block-fallback-shell"; - if (string.Equals(display, "page", StringComparison.Ordinal)) - return "tex-math-scene-page-fallback-shell"; - return "tex-math-scene-inline-fallback-shell"; - } - } -} diff --git a/runtimes/incubating/eve-unity-scene/Runtime/TeXMathUnitySceneProjectionAdapter.cs.meta b/runtimes/incubating/eve-unity-scene/Runtime/TeXMathUnitySceneProjectionAdapter.cs.meta deleted file mode 100644 index dd5310c..0000000 --- a/runtimes/incubating/eve-unity-scene/Runtime/TeXMathUnitySceneProjectionAdapter.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: 0184a5155baa9774f9ed133ad871b735 \ No newline at end of file diff --git a/runtimes/incubating/eve-unity-scene/Tests.meta b/runtimes/incubating/eve-unity-scene/Tests.meta deleted file mode 100644 index cffd388..0000000 --- a/runtimes/incubating/eve-unity-scene/Tests.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: b37c64ab7abc96a468018e86c041d431 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/runtimes/incubating/eve-unity-scene/Tests/Editor.meta b/runtimes/incubating/eve-unity-scene/Tests/Editor.meta deleted file mode 100644 index 532aea7..0000000 --- a/runtimes/incubating/eve-unity-scene/Tests/Editor.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: ac7339c6ff81f6f48864df2308ebeed2 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/runtimes/incubating/eve-unity-scene/Tests/Editor/EveUnitySceneSurfaceLowererTests.cs b/runtimes/incubating/eve-unity-scene/Tests/Editor/EveUnitySceneSurfaceLowererTests.cs deleted file mode 100644 index 65b01d3..0000000 --- a/runtimes/incubating/eve-unity-scene/Tests/Editor/EveUnitySceneSurfaceLowererTests.cs +++ /dev/null @@ -1,1681 +0,0 @@ -using System; -using System.Collections.Generic; -using GameCult.Eve.Surface; -using GameCult.Mesh; -using NUnit.Framework; -using UnityEngine; - -#nullable enable - -namespace GameCult.Eve.UnityScene.Tests -{ - public sealed class EveUnitySceneSurfaceLowererTests - { - [Test] - public void LowerCarriesProviderAdvertisedWorldBoundary() - { - var lowerer = new EveUnitySceneSurfaceLowerer(); - var projection = lowerer.Lower(Document("aetheria.daemon.game"), Advertisement("aetheria.daemon.game")); - - Assert.That(projection.ProviderId, Is.EqualTo("aetheria")); - Assert.That(projection.SurfaceId, Is.EqualTo("aetheria.daemon.game")); - Assert.That(projection.ProjectionKind, Is.EqualTo("provider-authored-world-surface")); - Assert.That(projection.CommandBoundary, Is.EqualTo("aetheria.daemon.commands")); - Assert.That(projection.ReceiptSchema, Is.EqualTo("aetheria.eve_command_acceptance_status.v1")); - Assert.That(projection.Ownership, Is.EqualTo("provider-owns-world-state-assets-command-acceptance-and-receipts")); - Assert.That(projection.Root.Id, Is.EqualTo("aetheria.daemon.game.root")); - Assert.That(projection.Root.SceneObjectKind, Is.EqualTo("scene-node")); - } - - [Test] - public void LowerBuildsProviderAgnosticSceneGraphFromSurfaceTree() - { - var lowerer = new EveUnitySceneSurfaceLowerer(); - var projection = lowerer.Lower(Document("aetheria.daemon.game"), Advertisement("aetheria.daemon.game")); - - Assert.That(projection.Root.Children.Count, Is.EqualTo(3)); - Assert.That(projection.Root.Children[0].SceneObjectKind, Is.EqualTo("world-projection-node")); - Assert.That(projection.Root.Children[0].Props["binding"], Is.EqualTo("cultmesh://aetheria/world/entities")); - Assert.That(projection.Root.Children[0].StateBindingCount, Is.EqualTo(1)); - Assert.That(projection.Root.Children[1].SceneObjectKind, Is.EqualTo("command-control")); - Assert.That(projection.Root.Children[1].Props["command"], Is.EqualTo("aetheria.daemon.focus")); - var nornNode = projection.Root.Children[2]; - Assert.That(nornNode.SceneObjectKind, Is.EqualTo("norn-graph-scene-projection")); - Assert.That(nornNode.EmbeddedDocumentCount, Is.EqualTo(1)); - Assert.That(nornNode.EmbeddedDocuments.Count, Is.EqualTo(1)); - Assert.That(nornNode.EmbeddedDocuments[0].SlotId, Is.EqualTo("norn.map")); - Assert.That(nornNode.EmbeddedDocuments[0].DocumentId, Is.EqualTo("cultmesh://aetheria/norn/map")); - Assert.That(nornNode.EmbeddedDocuments[0].SchemaId, Is.EqualTo("gamecult.eve.surface.v1")); - Assert.That(nornNode.EmbeddedDocuments[0].PresentationKind, Is.EqualTo("scene-overlay")); - Assert.That(nornNode.PluginProjection, Is.Not.Null); - Assert.That(nornNode.PluginProjection!.PluginId, Is.EqualTo("norn.graph")); - Assert.That(nornNode.PluginProjection.ProjectionKind, Is.EqualTo("norn-scene-embedded-graph-shell")); - Assert.That(nornNode.PluginProjection.AbiSchema, Is.EqualTo("gamecult.eve.plugin_abi.v1")); - Assert.That(nornNode.PluginProjection.CommandBoundary, Is.EqualTo("sidecar-advertised-plugin-abi")); - Assert.That(nornNode.PluginProjection.Capabilities, Does.Contain("embed.norn")); - Assert.That(nornNode.PluginProjection.Command, Is.EqualTo("graph.focus")); - Assert.That(nornNode.PluginProjection.DocumentId, Is.EqualTo("cultmesh://aetheria/norn/map")); - Assert.That(nornNode.PluginProjection.SemanticOwner, Is.EqualTo("Norn")); - } - - [Test] - public void LowerExtractsPlayableArpgWorldFromGenericScene3dSurface() - { - var lowerer = new EveUnitySceneSurfaceLowerer(); - var projection = lowerer.Lower(PlayableArpgDocument(), Advertisement("aetheria.daemon.game")); - - Assert.That(projection.Root.Children[0].SceneObjectKind, Is.EqualTo("playable-world-root")); - Assert.That(projection.Root.Children[0].Children[0].SceneObjectKind, Is.EqualTo("playable-world-entity")); - Assert.That(projection.Root.Children[0].Children[3].SceneObjectKind, Is.EqualTo("world-field-3d")); - Assert.That(projection.PlayableWorld, Is.Not.Null); - Assert.That(projection.PlayableWorld!.WorldRootId, Is.EqualTo("aetheria.daemon.game.playable")); - Assert.That(projection.PlayableWorld.StatePointerId, Is.EqualTo("cultmesh://aetheria/run/current")); - Assert.That(projection.PlayableWorld.AssetManifest, Is.EqualTo("cultmesh://aetheria/assets/manifest")); - Assert.That(projection.PlayableWorld.InputProfile, Is.EqualTo("arpg-third-person")); - Assert.That(projection.PlayableWorld.CameraRig, Is.EqualTo("third-person-orbit")); - Assert.That(projection.PlayableWorld.PlayerEntityId, Is.EqualTo("player-vanguard")); - Assert.That(projection.PlayableWorld.MovementCommand, Is.EqualTo("aetheria.daemon.move_intent")); - Assert.That(projection.PlayableWorld.FocusCommand, Is.EqualTo("aetheria.daemon.focus")); - Assert.That(projection.PlayableWorld.TargetCommand, Is.EqualTo("aetheria.daemon.target")); - Assert.That(projection.PlayableWorld.EntityCount, Is.EqualTo(3)); - - var player = FindEntity(projection.PlayableWorld, "player-vanguard"); - Assert.That(player.EntityKind, Is.EqualTo("player")); - Assert.That(player.AssetRef, Is.EqualTo("cultmesh://aetheria/assets/map/entity/player")); - Assert.That(player.PositionX, Is.EqualTo(0f)); - Assert.That(player.PositionY, Is.EqualTo(0f)); - Assert.That(player.PositionZ, Is.EqualTo(0f)); - Assert.That(player.Controllable, Is.True); - Assert.That(player.MoveCommand, Is.EqualTo("aetheria.daemon.move_intent")); - - var raider = FindEntity(projection.PlayableWorld, "raider-scout"); - Assert.That(raider.EntityKind, Is.EqualTo("enemy")); - Assert.That(raider.PositionX, Is.EqualTo(9f)); - Assert.That(raider.PositionZ, Is.EqualTo(14f)); - Assert.That(raider.TargetCommand, Is.EqualTo("aetheria.daemon.target")); - } - - [Test] - public void GenericClientSessionConsumesAetheriaPlayableWorldSnapshotWithoutAetheriaTypes() - { - var session = new EveUnitySceneClientSession(); - var projection = session.Connect(new EveUnitySceneProviderSurfaceSnapshot( - PlayableArpgDocument(), - Advertisement("aetheria.daemon.game"), - "cultmesh://aetheria/eve/surfaces/aetheria.daemon.game", - 42)); - - Assert.That(session.ActiveSourcePointer, Is.EqualTo("cultmesh://aetheria/eve/surfaces/aetheria.daemon.game")); - Assert.That(session.ActiveProjection, Is.SameAs(projection)); - Assert.That(projection.ProviderId, Is.EqualTo("aetheria")); - Assert.That(projection.PlayableWorld, Is.Not.Null); - Assert.That(projection.PlayableWorld!.InputProfile, Is.EqualTo("arpg-third-person")); - Assert.That(projection.PlayableWorld.EntityCount, Is.EqualTo(3)); - - var moveIntent = session.CreateMoveIntent( - "player-vanguard", - 12f, - 0f, - 8f, - DateTimeOffset.Parse("2026-07-09T00:00:00Z")); - - 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.ClientId, Is.EqualTo("unity-scene")); - 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")); - - var focusIntent = session.CreateFocusIntent("anchor-station"); - Assert.That(focusIntent.Command, Is.EqualTo("aetheria.daemon.commands")); - Assert.That(focusIntent.CommandBoundary, Is.EqualTo("aetheria.daemon.commands")); - - var moveVectorIntent = session.CreateMoveVectorIntent( - "player-vanguard", - 0.25f, - 0.75f, - 0.8f, - DateTimeOffset.Parse("2026-07-09T00:00:01Z")); - - Assert.That(moveVectorIntent.ProviderId, Is.EqualTo("aetheria")); - Assert.That(moveVectorIntent.SurfaceId, Is.EqualTo("aetheria.daemon.game")); - Assert.That(moveVectorIntent.Command, Is.EqualTo("aetheria.daemon.commands")); - Assert.That(moveVectorIntent.Payload.GetString("commandId"), Is.EqualTo("aetheria.daemon.move_intent")); - Assert.That(moveVectorIntent.Payload.GetString("entityId"), Is.EqualTo("player-vanguard")); - Assert.That(moveVectorIntent.Payload.GetString("directionX"), Is.EqualTo("0.25")); - Assert.That(moveVectorIntent.Payload.GetString("directionY"), Is.EqualTo("0.75")); - Assert.That(moveVectorIntent.Payload.GetString("scalarValue"), Is.EqualTo("0.8")); - } - - [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 ProviderSurfaceDocumentSourceFeedsPlayableClientWithoutAetheriaTypes() - { - var documentSource = new FakeProviderSurfaceDocumentSource(new EveUnitySceneProviderSurfaceDocument( - PlayableArpgDocument(), - Advertisement("aetheria.daemon.game"), - "cultmesh://aetheria/eve/surfaces/aetheria.daemon.game", - 1)); - using var surfaceSource = new EveUnitySceneProviderSurfaceDocumentSource(documentSource); - var commandSink = new FakeCommandSink("cultmesh-command-sink"); - var sceneSink = new FakePlayableWorldSceneSink(); - using var connection = new EveUnitySceneProviderConnection(surfaceSource, commandSink); - using var client = new EveUnityPlayableWorldLiveClient( - connection, - new EveUnityPlayableWorldPresenter(sceneSink, new EveUnityAssetRefResolver())); - - var initialPresentation = client.Connect(); - - Assert.That(surfaceSource.ProviderId, Is.EqualTo("aetheria")); - Assert.That(surfaceSource.SurfaceId, Is.EqualTo("aetheria.daemon.game")); - Assert.That(surfaceSource.SourcePointer, Is.EqualTo("cultmesh://aetheria/eve/surfaces/aetheria.daemon.game")); - Assert.That(initialPresentation.ActiveEntities, Is.EqualTo(3)); - Assert.That(client.ActiveWorld, Is.Not.Null); - Assert.That(client.ActiveWorld!.StatePointerId, Is.EqualTo("cultmesh://aetheria/run/current")); - Assert.That(client.ActiveWorld.AssetManifest, Is.EqualTo("cultmesh://aetheria/assets/manifest")); - - documentSource.Publish(new EveUnitySceneProviderSurfaceDocument( - PlayableArpgDocument(includeRaider: false, playerPosition: "11,0,5"), - Advertisement("aetheria.daemon.game"), - "cultmesh://aetheria/eve/surfaces/aetheria.daemon.game", - 2)); - - 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.RemovedEntityIds, Does.Contain("raider-scout")); - Assert.That(sceneSink.Upserts[3].entity.EntityId, Is.EqualTo("player-vanguard")); - Assert.That(sceneSink.Upserts[3].entity.PositionX, Is.EqualTo(11f)); - Assert.That(sceneSink.Upserts[3].entity.PositionZ, Is.EqualTo(5f)); - - var moveIntent = client.SubmitMoveIntent("player-vanguard", 12f, 0f, 8f); - - Assert.That(commandSink.Submitted.Count, Is.EqualTo(1)); - Assert.That(commandSink.Submitted[0], Is.SameAs(moveIntent)); - Assert.That(moveIntent.ProviderId, Is.EqualTo("aetheria")); - Assert.That(moveIntent.SurfaceId, Is.EqualTo("aetheria.daemon.game")); - Assert.That(moveIntent.CommandBoundary, Is.EqualTo("aetheria.daemon.commands")); - Assert.That(moveIntent.ReceiptSchema, Is.EqualTo("aetheria.eve_command_acceptance_status.v1")); - } - - [Test] - public void PlayableWorldRuntimeComposesProviderDocumentsAssetsReceiptsAndSceneSink() - { - var surfaceDocuments = new FakeProviderSurfaceDocumentSource(new EveUnitySceneProviderSurfaceDocument( - PlayableArpgDocument(), - Advertisement("aetheria.daemon.game"), - "cultmesh://aetheria/eve/surfaces/aetheria.daemon.game", - 1)); - var assetDocuments = new FakeAssetManifestDocumentSource(new EveUnityPlayableWorldAssetManifestDocument( - "cultmesh://aetheria/assets/manifest", - new[] - { - new EveUnityPlayableWorldAssetManifestDocumentEntry( - "cultmesh://aetheria/assets/map/entity/player", - "player", - "Resources/Aetheria/Entities/Vanguard.prefab", - "aetheria.vanguard"), - new EveUnityPlayableWorldAssetManifestDocumentEntry( - "cultmesh://aetheria/assets/map/entity/ship", - "enemy", - "Resources/Aetheria/Entities/Raider.prefab", - "aetheria.raider") - }, - "aetheria")); - var commandSink = new FakeCommandSink("cultmesh-command-sink"); - var receiptSource = new FakeCommandReceiptSource(); - var sceneSink = new FakePlayableWorldSceneSink(); - - using var runtime = new EveUnityPlayableWorldRuntime( - surfaceDocuments, - commandSink, - sceneSink, - assetDocuments, - receiptSource); - - var initialPresentation = runtime.Connect(); - - Assert.That(initialPresentation.ActiveEntities, Is.EqualTo(3)); - Assert.That(runtime.ActiveWorld, Is.Not.Null); - Assert.That(runtime.ActiveWorld!.AssetManifest, Is.EqualTo("cultmesh://aetheria/assets/manifest")); - Assert.That(runtime.AssetManifests.GetForWorld(runtime.ActiveWorld), Is.Not.Null); - Assert.That(sceneSink.Upserts.Count, Is.EqualTo(3)); - - var moveIntent = runtime.SubmitMoveIntent( - "player-vanguard", - 14f, - 0f, - 9f, - DateTimeOffset.Parse("2026-07-09T00:00:00Z")); - - Assert.That(commandSink.Submitted.Count, Is.EqualTo(1)); - Assert.That(commandSink.Submitted[0], Is.SameAs(moveIntent)); - Assert.That(moveIntent.ProviderId, Is.EqualTo("aetheria")); - Assert.That(moveIntent.Command, Is.EqualTo("aetheria.daemon.commands")); - Assert.That(moveIntent.CommandBoundary, Is.EqualTo("aetheria.daemon.commands")); - Assert.That(moveIntent.ReceiptSchema, Is.EqualTo("aetheria.eve_command_acceptance_status.v1")); - - surfaceDocuments.Publish(new EveUnitySceneProviderSurfaceDocument( - PlayableArpgDocument(includeRaider: false, playerPosition: "14,0,9"), - Advertisement("aetheria.daemon.game"), - "cultmesh://aetheria/eve/surfaces/aetheria.daemon.game", - 2)); - - Assert.That(runtime.ActiveVersion, Is.EqualTo(2)); - Assert.That(runtime.LastPresentation, Is.Not.Null); - Assert.That(runtime.LastPresentation!.ActiveEntities, Is.EqualTo(2)); - Assert.That(sceneSink.RemovedEntityIds, Does.Contain("raider-scout")); - Assert.That(sceneSink.Upserts[3].entity.EntityId, Is.EqualTo("player-vanguard")); - Assert.That(sceneSink.Upserts[3].entity.PositionX, Is.EqualTo(14f)); - Assert.That(sceneSink.Upserts[3].entity.PositionZ, Is.EqualTo(9f)); - - receiptSource.Publish(new EveUnitySceneCommandReceipt( - "aetheria.daemon.move_intent.accepted", - "aetheria.daemon.move_intent", - "aetheria.daemon.move_intent", - "accepted", - "Aetheria", - "provider-owned-daemon")); - - Assert.That(runtime.LastReceipt, Is.Not.Null); - Assert.That(runtime.LastReceipt!.IsProviderOwned, Is.True); - Assert.That(runtime.LastReceipt.ShouldRefreshProviderSurface, Is.True); - } - - [Test] - public void LiveProviderBridgeFeedsPlayableWorldRuntimeThroughTransportPorts() - { - var transport = new FakeLiveProviderTransport( - new EveUnitySceneProviderSurfaceDocument( - PlayableArpgDocument(), - Advertisement("aetheria.daemon.game"), - "cultmesh://aetheria/eve/surfaces/aetheria.daemon.game", - 1), - new EveUnityPlayableWorldAssetManifestDocument( - "cultmesh://aetheria/assets/manifest", - new[] - { - new EveUnityPlayableWorldAssetManifestDocumentEntry( - "cultmesh://aetheria/assets/map/entity/player", - "player", - "Resources/Aetheria/Entities/Vanguard.prefab", - "aetheria.vanguard") - }, - "aetheria")); - using var bridge = new EveUnitySceneLiveProviderBridge(transport); - var sceneSink = new FakePlayableWorldSceneSink(); - - using var runtime = new EveUnityPlayableWorldRuntime( - bridge, - bridge, - sceneSink, - bridge, - bridge); - - var initialPresentation = runtime.Connect(); - - Assert.That(transport.ConnectCount, Is.EqualTo(1)); - Assert.That(bridge.TransportKind, Is.EqualTo("cultmesh-cultnet-provider-transport")); - Assert.That(bridge.SurfacePointer, Is.EqualTo("cultmesh://aetheria/eve/surfaces/aetheria.daemon.game")); - Assert.That(bridge.AssetManifestPointer, Is.EqualTo("cultmesh://aetheria/assets/manifest")); - Assert.That(initialPresentation.ActiveEntities, Is.EqualTo(3)); - Assert.That(runtime.ActiveWorld, Is.Not.Null); - Assert.That(runtime.AssetManifests.GetForWorld(runtime.ActiveWorld!), Is.Not.Null); - - var moveIntent = runtime.SubmitMoveVectorIntent( - "player-vanguard", - 0.5f, - 1f, - 0.75f, - DateTimeOffset.Parse("2026-07-09T00:00:00Z")); - - Assert.That(transport.Submitted.Count, Is.EqualTo(1)); - Assert.That(transport.Submitted[0], Is.SameAs(moveIntent)); - Assert.That(moveIntent.CommandBoundary, Is.EqualTo("aetheria.daemon.commands")); - - transport.PublishSurface(new EveUnitySceneProviderSurfaceDocument( - PlayableArpgDocument(includeRaider: false, playerPosition: "6,0,2"), - Advertisement("aetheria.daemon.game"), - "cultmesh://aetheria/eve/surfaces/aetheria.daemon.game", - 2)); - - Assert.That(runtime.ActiveVersion, Is.EqualTo(2)); - Assert.That(runtime.LastPresentation, Is.Not.Null); - Assert.That(runtime.LastPresentation!.ActiveEntities, Is.EqualTo(2)); - Assert.That(sceneSink.RemovedEntityIds, Does.Contain("raider-scout")); - - transport.PublishReceipt(new EveUnitySceneCommandReceipt( - "aetheria.daemon.move_intent.accepted", - "aetheria.daemon.commands", - "aetheria.daemon.move_intent", - "accepted", - "Aetheria", - "provider-owned-daemon")); - - Assert.That(runtime.LastReceipt, Is.Not.Null); - Assert.That(runtime.LastReceipt!.IsProviderOwned, Is.True); - Assert.That(transport.RefreshCount, Is.EqualTo(1)); - } - - [Test] - public void PlayableWorldClientHostMountsInterfaceProviderWithoutProviderTypes() - { - var rootObject = new GameObject("generic-eve-world-root"); - var hostObject = new GameObject("generic-eve-client"); - hostObject.SetActive(false); - - try - { - var provider = hostObject.AddComponent(); - provider.Set( - new EveUnitySceneProviderSurfaceDocument( - PlayableArpgDocument(), - Advertisement("aetheria.daemon.game"), - "cultmesh://aetheria/eve/surfaces/aetheria.daemon.game", - 1), - new EveUnityPlayableWorldAssetManifestDocument( - "cultmesh://aetheria/assets/manifest", - new[] - { - new EveUnityPlayableWorldAssetManifestDocumentEntry( - "cultmesh://aetheria/assets/map/entity/player", - "player", - "", - "aetheria.vanguard") - }, - "aetheria")); - - var host = hostObject.AddComponent(); - host.Configure(rootObject.transform, provider, provider, provider, provider); - - var presentation = host.Connect(); - var moveIntent = host.SubmitMoveIntent("player-vanguard", 3f, 0f, 4f); - - Assert.That(presentation.ActiveEntities, Is.EqualTo(3)); - Assert.That(host.ActiveWorld, Is.Not.Null); - Assert.That(host.ActiveWorld!.PlayerEntityId, Is.EqualTo("player-vanguard")); - Assert.That(host.ActiveWorld.AssetManifest, Is.EqualTo("cultmesh://aetheria/assets/manifest")); - Assert.That(rootObject.transform.childCount, Is.EqualTo(3)); - Assert.That(provider.RefreshCount, Is.EqualTo(1)); - Assert.That(provider.Submitted.Count, Is.EqualTo(1)); - Assert.That(provider.Submitted[0], Is.SameAs(moveIntent)); - Assert.That(moveIntent.CommandBoundary, Is.EqualTo("aetheria.daemon.commands")); - } - finally - { - UnityEngine.Object.DestroyImmediate(hostObject); - UnityEngine.Object.DestroyImmediate(rootObject); - } - } - - [Test] - public void PlayableWorldClientBootstrapWiresGenericUnityClientFromProviderInterfaces() - { - var hostObject = new GameObject("generic-eve-client"); - hostObject.SetActive(false); - - try - { - var provider = hostObject.AddComponent(); - provider.Set( - new EveUnitySceneProviderSurfaceDocument( - PlayableArpgDocument(), - Advertisement("aetheria.daemon.game"), - "cultmesh://aetheria/eve/surfaces/aetheria.daemon.game", - 1), - new EveUnityPlayableWorldAssetManifestDocument( - "cultmesh://aetheria/assets/manifest", - Array.Empty(), - "aetheria")); - - var bootstrap = hostObject.AddComponent(); - bootstrap.ConfigureProvider(provider); - - bootstrap.Mount(); - - Assert.That(bootstrap.Host, Is.Not.Null); - Assert.That(bootstrap.Host!.ActiveWorld, Is.Not.Null); - Assert.That(bootstrap.Host.ActiveWorld!.PlayerEntityId, Is.EqualTo("player-vanguard")); - Assert.That(bootstrap.LastPresentation, Is.Not.Null); - Assert.That(bootstrap.LastPresentation!.ActiveEntities, Is.EqualTo(3)); - Assert.That(bootstrap.SceneRoot, Is.Not.Null); - Assert.That(bootstrap.SceneRoot!.childCount, Is.EqualTo(3)); - Assert.That(hostObject.GetComponent(), Is.Not.Null); - Assert.That(hostObject.GetComponent(), Is.Not.Null); - Assert.That(bootstrap.CameraTransform, Is.Not.Null); - Assert.That(provider.RefreshCount, Is.EqualTo(1)); - - var input = hostObject.GetComponent(); - var moveVector = input.SubmitMoveVectorInput(0f, 1f); - - Assert.That(moveVector, Is.Not.Null); - Assert.That(provider.Submitted.Count, Is.EqualTo(1)); - Assert.That(provider.Submitted[0], Is.SameAs(moveVector)); - Assert.That(moveVector!.ProviderId, Is.EqualTo("aetheria")); - Assert.That(moveVector.SurfaceId, Is.EqualTo("aetheria.daemon.game")); - Assert.That(moveVector.CommandBoundary, Is.EqualTo("aetheria.daemon.commands")); - Assert.That(moveVector.Payload.GetString("commandId"), Is.EqualTo("aetheria.daemon.move_intent")); - Assert.That(moveVector.Payload.GetString("entityId"), Is.EqualTo("player-vanguard")); - } - finally - { - UnityEngine.Object.DestroyImmediate(hostObject); - } - } - - [Test] - public void PlayableWorldClientHostSubmitsProviderOwnedMoveVector() - { - var rootObject = new GameObject("generic-eve-world-root"); - var hostObject = new GameObject("generic-eve-client"); - hostObject.SetActive(false); - - try - { - var provider = hostObject.AddComponent(); - provider.Set( - new EveUnitySceneProviderSurfaceDocument( - PlayableArpgDocument(), - Advertisement("aetheria.daemon.game"), - "cultmesh://aetheria/eve/surfaces/aetheria.daemon.game", - 1), - new EveUnityPlayableWorldAssetManifestDocument( - "cultmesh://aetheria/assets/manifest", - Array.Empty(), - "aetheria")); - - var host = hostObject.AddComponent(); - host.Configure(rootObject.transform, provider, provider, provider, provider); - host.Connect(); - - var moveVector = host.SubmitMoveVectorIntent("player-vanguard", 0.6f, -0.8f, 1f); - - Assert.That(provider.Submitted.Count, Is.EqualTo(1)); - Assert.That(provider.Submitted[0], Is.SameAs(moveVector)); - Assert.That(moveVector.CommandBoundary, Is.EqualTo("aetheria.daemon.commands")); - Assert.That(moveVector.Payload.GetString("commandId"), Is.EqualTo("aetheria.daemon.move_intent")); - Assert.That(moveVector.Payload.GetString("entityId"), Is.EqualTo("player-vanguard")); - Assert.That(moveVector.Payload.GetString("directionX"), Is.EqualTo("0.6")); - Assert.That(moveVector.Payload.GetString("directionY"), Is.EqualTo("-0.8")); - Assert.That(moveVector.Payload.GetString("scalarValue"), Is.EqualTo("1")); - } - finally - { - UnityEngine.Object.DestroyImmediate(hostObject); - UnityEngine.Object.DestroyImmediate(rootObject); - } - } - - [Test] - public void PlayableWorldInputDriverBuildsCameraRelativeMoveVectorWithoutProviderTypes() - { - var rootObject = new GameObject("generic-eve-world-root"); - var hostObject = new GameObject("generic-eve-client"); - var cameraObject = new GameObject("generic-eve-camera"); - hostObject.SetActive(false); - - try - { - cameraObject.transform.rotation = Quaternion.Euler(0f, 90f, 0f); - var provider = hostObject.AddComponent(); - provider.Set( - new EveUnitySceneProviderSurfaceDocument( - PlayableArpgDocument(), - Advertisement("aetheria.daemon.game"), - "cultmesh://aetheria/eve/surfaces/aetheria.daemon.game", - 1), - new EveUnityPlayableWorldAssetManifestDocument( - "cultmesh://aetheria/assets/manifest", - Array.Empty(), - "aetheria")); - - var host = hostObject.AddComponent(); - host.Configure(rootObject.transform, provider, provider, provider, provider); - host.Connect(); - - var driver = hostObject.AddComponent(); - driver.Host = host; - driver.CameraTransform = cameraObject.transform; - var request = driver.SubmitMoveVectorInput(0f, 1f); - - Assert.That(request, Is.Not.Null); - Assert.That(provider.Submitted.Count, Is.EqualTo(1)); - Assert.That(request!.Payload.GetString("commandId"), Is.EqualTo("aetheria.daemon.move_intent")); - Assert.That(request.Payload.GetDouble("directionX", 0), Is.EqualTo(1f).Within(0.0001f)); - Assert.That(request.Payload.GetDouble("directionY", 0), Is.EqualTo(0f).Within(0.0001f)); - Assert.That(request.Payload.GetDouble("scalarValue", 0), Is.EqualTo(1f).Within(0.0001f)); - - var movement = EveUnityPlayableWorldMoveVector.FromCameraRelativeInput(1f, 1f, null); - Assert.That(movement.HasInput, Is.True); - Assert.That(movement.ScalarValue, Is.EqualTo(1f).Within(0.0001f)); - } - finally - { - UnityEngine.Object.DestroyImmediate(cameraObject); - UnityEngine.Object.DestroyImmediate(hostObject); - UnityEngine.Object.DestroyImmediate(rootObject); - } - } - - [Test] - public void PlayableWorldCameraRigFollowsAdvertisedPlayerEntityWithoutProviderTypes() - { - var rootObject = new GameObject("generic-eve-world-root"); - var hostObject = new GameObject("generic-eve-client"); - var cameraObject = new GameObject("generic-eve-camera"); - hostObject.SetActive(false); - - try - { - var provider = hostObject.AddComponent(); - provider.Set( - new EveUnitySceneProviderSurfaceDocument( - PlayableArpgDocument(), - Advertisement("aetheria.daemon.game"), - "cultmesh://aetheria/eve/surfaces/aetheria.daemon.game", - 1), - new EveUnityPlayableWorldAssetManifestDocument( - "cultmesh://aetheria/assets/manifest", - Array.Empty(), - "aetheria")); - - var host = hostObject.AddComponent(); - host.Configure(rootObject.transform, provider, provider, provider, provider); - host.Connect(); - - var rig = hostObject.AddComponent(); - rig.Host = host; - rig.CameraTransform = cameraObject.transform; - - Assert.That(rig.ApplyRig(0f), Is.True); - Assert.That(cameraObject.transform.position.y, Is.GreaterThan(0f)); - Assert.That(Vector3.Distance(cameraObject.transform.position, Vector3.zero), Is.GreaterThan(1f)); - } - finally - { - UnityEngine.Object.DestroyImmediate(cameraObject); - UnityEngine.Object.DestroyImmediate(hostObject); - UnityEngine.Object.DestroyImmediate(rootObject); - } - } - - [Test] - public void PlayableWorldPresenterInstantiatesUpdatesAndDespawnsProviderEntities() - { - var lowerer = new EveUnitySceneSurfaceLowerer(); - var sink = new FakePlayableWorldSceneSink(); - var presenter = new EveUnityPlayableWorldPresenter(sink, new EveUnityAssetRefResolver()); - - var firstProjection = lowerer.Lower(PlayableArpgDocument(), Advertisement("aetheria.daemon.game")); - var firstPresentation = presenter.Apply(firstProjection); - - Assert.That(firstPresentation.WorldRootId, Is.EqualTo("aetheria.daemon.game.playable")); - Assert.That(firstPresentation.PlayerEntityId, Is.EqualTo("player-vanguard")); - Assert.That(firstPresentation.InputProfile, Is.EqualTo("arpg-third-person")); - Assert.That(firstPresentation.CameraRig, Is.EqualTo("third-person-orbit")); - Assert.That(firstPresentation.UpsertedEntities, Is.EqualTo(3)); - Assert.That(firstPresentation.RemovedEntities, Is.EqualTo(0)); - Assert.That(firstPresentation.ActiveEntities, Is.EqualTo(3)); - Assert.That(sink.ConfiguredWorlds.Count, Is.EqualTo(1)); - Assert.That(sink.Upserts.Count, Is.EqualTo(3)); - Assert.That(sink.Upserts[0].entity.EntityId, Is.EqualTo("player-vanguard")); - Assert.That(sink.Upserts[0].entity.PositionX, Is.EqualTo(0f)); - Assert.That(sink.Upserts[0].asset.AssetRef, Is.EqualTo("cultmesh://aetheria/assets/map/entity/player")); - Assert.That(sink.Upserts[0].asset.PresentationKind, Is.EqualTo("provider-asset-ref")); - - var secondProjection = lowerer.Lower( - PlayableArpgDocument(includeRaider: false, playerPosition: "5,0,2"), - Advertisement("aetheria.daemon.game")); - var secondPresentation = presenter.Apply(secondProjection); - - Assert.That(secondPresentation.UpsertedEntities, Is.EqualTo(2)); - Assert.That(secondPresentation.RemovedEntities, Is.EqualTo(1)); - Assert.That(secondPresentation.ActiveEntities, Is.EqualTo(2)); - Assert.That(sink.ConfiguredWorlds.Count, Is.EqualTo(2)); - Assert.That(sink.RemovedEntityIds.Count, Is.EqualTo(1)); - Assert.That(sink.RemovedEntityIds[0], Is.EqualTo("raider-scout")); - Assert.That(sink.Upserts[3].entity.EntityId, Is.EqualTo("player-vanguard")); - Assert.That(sink.Upserts[3].entity.PositionX, Is.EqualTo(5f)); - Assert.That(sink.Upserts[3].entity.PositionZ, Is.EqualTo(2f)); - } - - [Test] - public void LivePlayableWorldClientPresentsProviderSnapshotsAndKeepsCommandsProviderOwned() - { - 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 sceneSink = new FakePlayableWorldSceneSink(); - using var connection = new EveUnitySceneProviderConnection(source, commandSink); - using var client = new EveUnityPlayableWorldLiveClient( - connection, - new EveUnityPlayableWorldPresenter(sceneSink, new EveUnityAssetRefResolver())); - - var initialPresentation = client.Connect(); - - Assert.That(initialPresentation.ActiveEntities, Is.EqualTo(3)); - Assert.That(initialPresentation.PlayerEntityId, Is.EqualTo("player-vanguard")); - Assert.That(client.ActiveWorld, Is.Not.Null); - Assert.That(client.ActiveWorld!.AssetManifest, Is.EqualTo("cultmesh://aetheria/assets/manifest")); - Assert.That(sceneSink.ConfiguredWorlds.Count, Is.EqualTo(1)); - Assert.That(sceneSink.Upserts.Count, Is.EqualTo(3)); - - source.Publish(new EveUnitySceneProviderSurfaceSnapshot( - PlayableArpgDocument(includeRaider: false, playerPosition: "7,0,4"), - Advertisement("aetheria.daemon.game"), - "cultmesh://aetheria/eve/surfaces/aetheria.daemon.game", - 2)); - - Assert.That(client.ActiveVersion, Is.EqualTo(2)); - Assert.That(client.LastPresentation, Is.Not.Null); - Assert.That(client.LastPresentation!.ActiveEntities, Is.EqualTo(2)); - Assert.That(client.LastPresentation.RemovedEntities, Is.EqualTo(1)); - Assert.That(sceneSink.ConfiguredWorlds.Count, Is.EqualTo(2)); - Assert.That(sceneSink.RemovedEntityIds[0], Is.EqualTo("raider-scout")); - Assert.That(sceneSink.Upserts[3].entity.EntityId, Is.EqualTo("player-vanguard")); - Assert.That(sceneSink.Upserts[3].entity.PositionX, Is.EqualTo(7f)); - Assert.That(sceneSink.Upserts[3].entity.PositionZ, Is.EqualTo(4f)); - - var moveIntent = client.SubmitMoveIntent( - "player-vanguard", - 12f, - 0f, - 8f, - DateTimeOffset.Parse("2026-07-09T00:00:00Z")); - - Assert.That(commandSink.Submitted.Count, Is.EqualTo(1)); - Assert.That(commandSink.Submitted[0], Is.SameAs(moveIntent)); - Assert.That(moveIntent.ProviderId, Is.EqualTo("aetheria")); - Assert.That(moveIntent.SurfaceId, Is.EqualTo("aetheria.daemon.game")); - Assert.That(moveIntent.CommandBoundary, Is.EqualTo("aetheria.daemon.commands")); - Assert.That(moveIntent.ReceiptSchema, Is.EqualTo("aetheria.eve_command_acceptance_status.v1")); - - client.Disconnect(); - source.Publish(new EveUnitySceneProviderSurfaceSnapshot( - PlayableArpgDocument(playerPosition: "99,0,99"), - Advertisement("aetheria.daemon.game"), - "cultmesh://aetheria/eve/surfaces/aetheria.daemon.game", - 3)); - - Assert.That(client.ActiveVersion, Is.EqualTo(2)); - 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() - { - 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 AssetManifestCacheTracksPlayableWorldManifestPointerAndLiveUpdates() - { - var lowerer = new EveUnitySceneSurfaceLowerer(); - var projection = lowerer.Lower(PlayableArpgDocument(), Advertisement("aetheria.daemon.game")); - Assert.That(projection.PlayableWorld, Is.Not.Null); - - var source = new FakeAssetManifestSource(new EveUnityPlayableWorldAssetManifest( - "cultmesh://aetheria/assets/manifest", - new[] - { - new EveUnityPlayableWorldAssetManifestEntry( - "cultmesh://aetheria/assets/map/entity/player", - "player", - "resources://Aetheria/Entities/Vanguard.prefab", - "aetheria.vanguard") - })); - var cache = new EveUnityPlayableWorldAssetManifestCache(); - cache.Connect(source); - - var manifest = cache.GetForWorld(projection.PlayableWorld!); - Assert.That(manifest, Is.Not.Null); - Assert.That(manifest!.ManifestRef, Is.EqualTo("cultmesh://aetheria/assets/manifest")); - Assert.That(cache.Count, Is.EqualTo(1)); - 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")); - - source.Publish(new EveUnityPlayableWorldAssetManifest( - "cultmesh://aetheria/assets/manifest", - new[] - { - new EveUnityPlayableWorldAssetManifestEntry( - "cultmesh://aetheria/assets/map/entity/player", - "player", - "resources://Aetheria/Entities/VanguardMk2.prefab", - "aetheria.vanguard.mk2") - })); - - var updated = cache.GetForWorld(projection.PlayableWorld); - Assert.That(updated, Is.Not.Null); - var updatedPlayer = updated!.Find(new EveUnityPlayableWorldAssetBinding( - "cultmesh://aetheria/assets/map/entity/player", - "player", - "provider-asset-ref")); - Assert.That(updatedPlayer, Is.Not.Null); - Assert.That(updatedPlayer!.ResourcesPath, Is.EqualTo("Aetheria/Entities/VanguardMk2")); - - cache.Disconnect(source); - source.Publish(new EveUnityPlayableWorldAssetManifest( - "cultmesh://aetheria/assets/manifest", - new[] - { - new EveUnityPlayableWorldAssetManifestEntry( - "cultmesh://aetheria/assets/map/entity/player", - "player", - "resources://Aetheria/Entities/VanguardIgnored.prefab", - "aetheria.vanguard.ignored") - })); - - var afterDisconnect = cache.GetForWorld(projection.PlayableWorld); - var afterDisconnectPlayer = afterDisconnect!.Find(new EveUnityPlayableWorldAssetBinding( - "cultmesh://aetheria/assets/map/entity/player", - "player", - "provider-asset-ref")); - Assert.That(afterDisconnectPlayer!.ResourcesPath, Is.EqualTo("Aetheria/Entities/VanguardMk2")); - } - - [Test] - public void AssetManifestDocumentSourceFeedsCacheWithoutChangingSceneLowering() - { - var lowerer = new EveUnitySceneSurfaceLowerer(); - var projection = lowerer.Lower(PlayableArpgDocument(), Advertisement("aetheria.daemon.game")); - Assert.That(projection.PlayableWorld, Is.Not.Null); - - var documentSource = new FakeAssetManifestDocumentSource(new EveUnityPlayableWorldAssetManifestDocument( - "cultmesh://aetheria/assets/manifest", - new[] - { - new EveUnityPlayableWorldAssetManifestDocumentEntry( - "cultmesh://aetheria/assets/map/entity/player", - "player", - "resources://Aetheria/Entities/Vanguard.prefab", - "aetheria.vanguard") - }, - "aetheria")); - using var manifestSource = new EveUnityPlayableWorldAssetManifestDocumentSource(documentSource); - var cache = new EveUnityPlayableWorldAssetManifestCache(); - manifestSource.Connect(); - cache.Connect(manifestSource); - - var manifest = cache.GetForWorld(projection.PlayableWorld!); - Assert.That(manifest, Is.Not.Null); - Assert.That(manifest!.ManifestRef, Is.EqualTo("cultmesh://aetheria/assets/manifest")); - 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")); - - documentSource.Publish(new EveUnityPlayableWorldAssetManifestDocument( - "cultmesh://aetheria/assets/manifest", - new[] - { - new EveUnityPlayableWorldAssetManifestDocumentEntry( - "cultmesh://aetheria/assets/map/entity/player", - "player", - "Resources/Aetheria/Entities/VanguardAuthority.prefab", - "aetheria.vanguard.authority") - }, - "aetheria")); - - var updated = cache.GetForWorld(projection.PlayableWorld); - var updatedPlayer = updated!.Find(new EveUnityPlayableWorldAssetBinding( - "cultmesh://aetheria/assets/map/entity/player", - "player", - "provider-asset-ref")); - Assert.That(updatedPlayer, Is.Not.Null); - Assert.That(updatedPlayer!.ResourcesPath, Is.EqualTo("Aetheria/Entities/VanguardAuthority")); - Assert.That(updatedPlayer.PrefabKey, Is.EqualTo("aetheria.vanguard.authority")); - } - - [Test] - public void SaiVisualNovelLowersThroughRuntimeProjectionAdapterWithoutOwningStoryState() - { - var lowerer = new EveUnitySceneSurfaceLowerer(); - var projection = lowerer.Lower(SaiDocument(), Advertisement("sai.visual_novel.surface")); - - Assert.That(projection.ProviderId, Is.EqualTo("gamecult.home.vn")); - Assert.That(projection.SurfaceId, Is.EqualTo("sai.visual_novel.surface")); - Assert.That(projection.Root.SceneObjectKind, Is.EqualTo("sai-vn-scene-stage")); - Assert.That(projection.Root.PluginProjection, Is.Not.Null); - Assert.That(projection.Root.PluginProjection!.PluginId, Is.EqualTo("sai.vn")); - Assert.That(projection.Root.PluginProjection.ProjectionKind, Is.EqualTo("sai-vn-scene-stage-shell")); - Assert.That(projection.Root.PluginProjection.AbiSchema, Is.EqualTo("gamecult.eve.plugin_abi.v1")); - Assert.That(projection.Root.PluginProjection.CommandBoundary, Is.EqualTo("sidecar-advertised-plugin-abi")); - Assert.That(projection.Root.PluginProjection.Capabilities, Does.Contain("vn.stage")); - Assert.That(projection.Root.PluginProjection.Capabilities, Does.Contain("story.choose")); - Assert.That(projection.Root.PluginProjection.DocumentId, Is.EqualTo("gamecult-compound")); - Assert.That(projection.Root.PluginProjection.SemanticOwner, Is.EqualTo("Sai")); - - var dialogue = projection.Root.Children[0]; - Assert.That(dialogue.SceneObjectKind, Is.EqualTo("sai-vn-scene-dialogue")); - Assert.That(dialogue.PluginProjection!.ProjectionKind, Is.EqualTo("sai-vn-scene-dialogue-shell")); - Assert.That(dialogue.PluginProjection.SemanticOwner, Is.EqualTo("Sai")); - - var choice = projection.Root.Children[1].Children[0]; - Assert.That(choice.SceneObjectKind, Is.EqualTo("command-control")); - Assert.That(choice.PluginProjection, Is.Not.Null); - Assert.That(choice.PluginProjection!.PluginId, Is.EqualTo("sai.vn")); - Assert.That(choice.PluginProjection.ProjectionKind, Is.EqualTo("sai-vn-scene-story-command-shell")); - Assert.That(choice.PluginProjection.Command, Is.EqualTo("story.choose")); - Assert.That(choice.PluginProjection.SemanticOwner, Is.EqualTo("Sai")); - - var tex = projection.Root.Children[2]; - Assert.That(tex.SceneObjectKind, Is.EqualTo("tex-math-scene-projection")); - Assert.That(tex.PluginProjection, Is.Not.Null); - Assert.That(tex.PluginProjection!.PluginId, Is.EqualTo("tex.math")); - Assert.That(tex.PluginProjection.ProjectionKind, Is.EqualTo("tex-math-scene-block-fallback-shell")); - Assert.That(tex.PluginProjection.Capabilities, Does.Contain("embed.tex")); - Assert.That(tex.PluginProjection.Capabilities, Does.Contain("tex.scene-placement")); - Assert.That(tex.PluginProjection.DocumentId, Is.EqualTo("\\\\mathrm{votes}(p)=1+\\\\lfloor\\\\log_b(1+p)\\\\rfloor")); - Assert.That(tex.PluginProjection.SemanticOwner, Is.EqualTo("EvePlugins")); - } - - [Test] - public void CommandIntentCarriesAdvertisedBoundaryWithoutOwningReceipts() - { - var lowerer = new EveUnitySceneSurfaceLowerer(); - var intent = lowerer.CreateCommandIntent( - Document("aetheria.daemon.game"), - Advertisement("aetheria.daemon.game"), - "aetheria.daemon.commands", - new Dictionary(StringComparer.Ordinal) - { - ["commandId"] = "aetheria.daemon.focus" - }, - DateTimeOffset.Parse("2026-07-09T00:00:00Z")); - - Assert.That(intent.Schema, Is.EqualTo(EveSurfaceCommandRequest.SchemaId)); - Assert.That(intent.ProviderId, Is.EqualTo("aetheria")); - Assert.That(intent.SurfaceId, Is.EqualTo("aetheria.daemon.game")); - Assert.That(intent.Command, Is.EqualTo("aetheria.daemon.commands")); - Assert.That(intent.ClientId, Is.EqualTo("unity-scene")); - Assert.That(intent.CommandBoundary, Is.EqualTo("aetheria.daemon.commands")); - Assert.That(intent.ReceiptSchema, Is.EqualTo("aetheria.eve_command_acceptance_status.v1")); - } - - private static EveSurfaceDocument Document(string surfaceId) - { - return new EveSurfaceDocument( - "aetheria", - "game.provider", - "Aetheria world", - 1, - "2026-07-09T00:00:00Z", - new EveSurfaceTree( - surfaceId, - new EveSurfaceComponent( - $"{surfaceId}.root", - "surface", - new Dictionary(StringComparer.Ordinal), - new[] - { - new EveSurfaceComponent( - $"{surfaceId}.entities", - "world.entities", - new Dictionary(StringComparer.Ordinal) - { - ["binding"] = "cultmesh://aetheria/world/entities" - }, - Array.Empty(), - new[] - { - new CultMeshStateBindingDescriptor("entities", "cultmesh://aetheria/world/entities") - }), - new EveSurfaceComponent( - $"{surfaceId}.focus", - "control.button", - new Dictionary(StringComparer.Ordinal) - { - ["command"] = "aetheria.daemon.focus" - }, - Array.Empty()), - new EveSurfaceComponent( - $"{surfaceId}.norn", - "embed.norn", - new Dictionary(StringComparer.Ordinal) - { - ["graph.document"] = "cultmesh://aetheria/norn/map", - ["interaction.nodeAction"] = "graph.focus" - }, - Array.Empty(), - Array.Empty(), - new[] - { - new EveEmbeddedDocumentSlot( - "norn.map", - "cultmesh://aetheria/norn/map", - "gamecult.eve.surface.v1", - "scene-overlay") - }) - }), - Array.Empty()), - Array.Empty()); - } - - private static EveSurfaceDocument PlayableArpgDocument( - bool includeRaider = true, - string playerPosition = "0,0,0") - { - var playableChildren = new List - { - PlayableEntity( - "aetheria.daemon.game.entity.player", - "player-vanguard", - "player", - "Vanguard", - "player", - "cultmesh://aetheria/assets/map/entity/player", - playerPosition, - "35", - "1.15", - true, - true, - "aetheria.daemon.focus", - "aetheria.daemon.move_intent", - "", - "") - }; - - if (includeRaider) - { - playableChildren.Add(PlayableEntity( - "aetheria.daemon.game.entity.raider", - "raider-scout", - "enemy", - "Raider Scout", - "raider", - "cultmesh://aetheria/assets/map/entity/ship", - "9,0,14", - "220", - "0.9", - true, - false, - "", - "", - "aetheria.daemon.target", - "")); - } - - playableChildren.Add(PlayableEntity( - "aetheria.daemon.game.entity.station", - "anchor-station", - "station", - "Anchor Station", - "neutral", - "cultmesh://aetheria/assets/map/entity/station", - "-18,0,6", - "0", - "3.4", - true, - false, - "aetheria.daemon.focus", - "", - "", - "")); - - playableChildren.Add(new EveSurfaceComponent( - "aetheria.daemon.game.flow", - "field.vector3d", - new Dictionary(StringComparer.Ordinal) - { - ["fieldId"] = "aetheria.zone.flow", - ["bind"] = "aetheria.daemon.soaView.flowField3d", - ["visualizer"] = "particles", - ["bounds"] = "-32,0,-32,32,24,32" - }, - Array.Empty())); - - return new EveSurfaceDocument( - "aetheria", - "game.runtime", - "Aetheria daemon game", - 1, - "2026-07-09T00:00:00Z", - new EveSurfaceTree( - "aetheria.daemon.game", - new EveSurfaceComponent( - "aetheria.daemon.game.root", - "surface", - new Dictionary(StringComparer.Ordinal), - new[] - { - new EveSurfaceComponent( - "aetheria.daemon.game.playable", - "world.scene3d", - new Dictionary(StringComparer.Ordinal) - { - ["statePointerId"] = "cultmesh://aetheria/run/current", - ["assetManifest"] = "cultmesh://aetheria/assets/manifest", - ["inputProfile"] = "arpg-third-person", - ["cameraRig"] = "third-person-orbit", - ["playerEntityId"] = "player-vanguard", - ["movementCommand"] = "aetheria.daemon.move_intent", - ["focusCommand"] = "aetheria.daemon.focus", - ["targetCommand"] = "aetheria.daemon.target", - ["actionCommand"] = "aetheria.daemon.use_equipment" - }, - playableChildren, - new[] - { - new CultMeshStateBindingDescriptor("run", "cultmesh://aetheria/run/current"), - new CultMeshStateBindingDescriptor("assets", "cultmesh://aetheria/assets/manifest") - }) - }), - Array.Empty()), - new[] - { - new EveCommandTemplate(CultMesh.OperationBinding("aetheria.daemon.commands", "Aetheria daemon commands")) - }); - } - - private static EveSurfaceComponent PlayableEntity( - string nodeId, - string entityId, - string entityKind, - string label, - string faction, - string assetRef, - string position, - string rotationY, - string radius, - bool selectable, - bool controllable, - string focusCommand, - string moveCommand, - string targetCommand, - string actionCommand) - { - return new EveSurfaceComponent( - nodeId, - "world.entity3d", - new Dictionary(StringComparer.Ordinal) - { - ["entityId"] = entityId, - ["entityKind"] = entityKind, - ["label"] = label, - ["faction"] = faction, - ["assetRef"] = assetRef, - ["position"] = position, - ["rotationY"] = rotationY, - ["radius"] = radius, - ["selectable"] = selectable ? "true" : "false", - ["controllable"] = controllable ? "true" : "false", - ["focusCommand"] = focusCommand, - ["moveCommand"] = moveCommand, - ["targetCommand"] = targetCommand, - ["actionCommand"] = actionCommand - }, - Array.Empty()); - } - - private static EveUnityPlayableWorldEntity FindEntity( - EveUnityPlayableWorldProjection playableWorld, - string entityId) - { - foreach (var entity in playableWorld.Entities) - { - if (string.Equals(entity.EntityId, entityId, StringComparison.Ordinal)) - return entity; - } - throw new AssertionException($"Playable entity not found: {entityId}"); - } - - private static EveSurfaceDocument SaiDocument() - { - return new EveSurfaceDocument( - "gamecult.home.vn", - "sai.visual_novel", - "GameCult Compound VN", - 1, - "2026-07-09T00:00:00Z", - new EveSurfaceTree( - "sai.visual_novel.surface", - new EveSurfaceComponent( - "sai.root", - "vn.stage", - new Dictionary(StringComparer.Ordinal) - { - ["storyId"] = "gamecult-compound", - ["currentPath"] = "hub" - }, - new[] - { - new EveSurfaceComponent( - "sai.dialogue", - "panel.dialogue", - new Dictionary(StringComparer.Ordinal) - { - ["speaker"] = "Void", - ["text"] = "Pick a door." - }, - Array.Empty()), - new EveSurfaceComponent( - "sai.choices", - "rail.actions", - new Dictionary(StringComparer.Ordinal), - new[] - { - new EveSurfaceComponent( - "sai.choice.eve", - "control.button", - new Dictionary(StringComparer.Ordinal) - { - ["label"] = "What is Eve?", - ["action.command"] = "story.choose", - ["targetPath"] = "eve" - }, - Array.Empty()) - }), - new EveSurfaceComponent( - "sai.tex.log-power", - "embed.tex", - new Dictionary(StringComparer.Ordinal) - { - ["label"] = "Bifrost voting weight", - ["source"] = "\\\\mathrm{votes}(p)=1+\\\\lfloor\\\\log_b(1+p)\\\\rfloor", - ["format"] = "latex", - ["display"] = "block" - }, - Array.Empty()) - }), - Array.Empty()), - new[] - { - new EveCommandTemplate(CultMesh.OperationBinding("story.choose", "Choose")) - }); - } - - private static EveUnitySceneProviderSurfaceAdvertisement Advertisement(string surfaceId) - { - return new EveUnitySceneProviderSurfaceAdvertisement( - surfaceId, - "interactive-world", - new EveUnitySceneWorldInteraction( - "provider-authored-world-surface", - "aetheria.daemon.commands", - "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? SnapshotAvailable; - - public void Connect() - { - } - - public void Refresh() - { - } - - public void Disconnect() - { - } - - public void Stage(EveUnitySceneProviderSurfaceSnapshot snapshot) - { - CurrentSnapshot = snapshot; - } - - public void Publish(EveUnitySceneProviderSurfaceSnapshot snapshot) - { - CurrentSnapshot = snapshot; - SnapshotAvailable?.Invoke(snapshot); - } - } - - private sealed class FakeProviderSurfaceDocumentSource : IEveUnitySceneProviderSurfaceDocumentSource - { - public FakeProviderSurfaceDocumentSource(EveUnitySceneProviderSurfaceDocument currentDocument) - { - CurrentDocument = currentDocument; - } - - public EveUnitySceneProviderSurfaceDocument CurrentDocument { get; private set; } - - public event Action? DocumentAvailable; - - public void Publish(EveUnitySceneProviderSurfaceDocument document) - { - CurrentDocument = document; - DocumentAvailable?.Invoke(document); - } - } - - private sealed class FakeCommandReceiptSource : IEveUnitySceneCommandReceiptSource - { - public event Action? ReceiptAvailable; - - public void Publish(EveUnitySceneCommandReceipt receipt) - { - ReceiptAvailable?.Invoke(receipt); - } - } - - private sealed class FakeCommandSink : IEveUnitySceneCommandSink - { - public FakeCommandSink(string sinkKind) - { - SinkKind = sinkKind; - } - - public string SinkKind { get; } - - public List Submitted { get; } = new List(); - - public void Submit(EveSurfaceCommandRequest request) - { - Submitted.Add(request); - } - } - - private sealed class FakePlayableWorldSceneSink : IEveUnityPlayableWorldSceneSink - { - public List ConfiguredWorlds { get; } = new List(); - - public List<(EveUnityPlayableWorldEntity entity, EveUnityPlayableWorldAssetBinding asset)> Upserts { get; } = - new List<(EveUnityPlayableWorldEntity entity, EveUnityPlayableWorldAssetBinding asset)>(); - - public List RemovedEntityIds { get; } = new List(); - - public void ConfigureWorld(EveUnityPlayableWorldProjection world) - { - ConfiguredWorlds.Add(world); - } - - public void UpsertEntity(EveUnityPlayableWorldEntity entity, EveUnityPlayableWorldAssetBinding asset) - { - Upserts.Add((entity, asset)); - } - - public void RemoveEntity(string entityId) - { - RemovedEntityIds.Add(entityId); - } - } - - private sealed class FakeAssetManifestSource : IEveUnityPlayableWorldAssetManifestSource - { - public FakeAssetManifestSource(EveUnityPlayableWorldAssetManifest currentManifest) - { - CurrentManifest = currentManifest; - } - - public string ManifestRef => CurrentManifest.ManifestRef; - - public EveUnityPlayableWorldAssetManifest CurrentManifest { get; private set; } - - public event Action? ManifestAvailable; - - public void Publish(EveUnityPlayableWorldAssetManifest manifest) - { - CurrentManifest = manifest; - ManifestAvailable?.Invoke(manifest); - } - } - - private sealed class FakeAssetManifestDocumentSource : IEveUnityPlayableWorldAssetManifestDocumentSource - { - public FakeAssetManifestDocumentSource(EveUnityPlayableWorldAssetManifestDocument currentDocument) - { - CurrentDocument = currentDocument; - } - - public string ManifestRef => CurrentDocument.ManifestRef; - - public EveUnityPlayableWorldAssetManifestDocument CurrentDocument { get; private set; } - - public event Action? DocumentAvailable; - - public void Publish(EveUnityPlayableWorldAssetManifestDocument document) - { - CurrentDocument = document; - DocumentAvailable?.Invoke(document); - } - } - - private sealed class FakeLiveProviderTransport : IEveUnitySceneLiveProviderTransport - { - public FakeLiveProviderTransport( - EveUnitySceneProviderSurfaceDocument surfaceDocument, - EveUnityPlayableWorldAssetManifestDocument assetManifestDocument) - { - CurrentSurfaceDocument = surfaceDocument; - CurrentAssetManifestDocument = assetManifestDocument; - } - - public string TransportKind => "cultmesh-cultnet-provider-transport"; - - public string SurfacePointer => CurrentSurfaceDocument.SourcePointer; - - public string AssetManifestPointer => CurrentAssetManifestDocument.ManifestRef; - - public EveUnitySceneProviderSurfaceDocument CurrentSurfaceDocument { get; private set; } - - public EveUnityPlayableWorldAssetManifestDocument CurrentAssetManifestDocument { get; private set; } - - public List Submitted { get; } = new List(); - - public int ConnectCount { get; private set; } - - public int DisconnectCount { get; private set; } - - public int RefreshCount { get; private set; } - - public event Action? SurfaceDocumentAvailable; - - public event Action? AssetManifestDocumentAvailable; - - public event Action? CommandReceiptAvailable; - - public void Connect() - { - ConnectCount++; - } - - public void Disconnect() - { - DisconnectCount++; - } - - public void Refresh() - { - RefreshCount++; - } - - public void SubmitCommand(EveSurfaceCommandRequest request) - { - Submitted.Add(request); - } - - public void PublishSurface(EveUnitySceneProviderSurfaceDocument document) - { - CurrentSurfaceDocument = document; - SurfaceDocumentAvailable?.Invoke(document); - } - - public void PublishAssetManifest(EveUnityPlayableWorldAssetManifestDocument document) - { - CurrentAssetManifestDocument = document; - AssetManifestDocumentAvailable?.Invoke(document); - } - - public void PublishReceipt(EveUnitySceneCommandReceipt receipt) - { - CommandReceiptAvailable?.Invoke(receipt); - } - } - - private sealed class FakePlayableWorldProviderComponent : - MonoBehaviour, - IEveUnitySceneProviderSurfaceDocumentSource, - IEveUnityPlayableWorldAssetManifestDocumentSource, - IEveUnitySceneCommandSink, - IEveUnitySceneCommandReceiptSource, - IEveUnityProviderRefreshSource - { - public List Submitted { get; } = new List(); - - public int RefreshCount { get; private set; } - - public string SinkKind => "fake-provider-command-sink"; - - public string ManifestRef => CurrentDocument.ManifestRef; - - public EveUnitySceneProviderSurfaceDocument CurrentSurfaceDocument { get; private set; } = - new EveUnitySceneProviderSurfaceDocument( - PlayableArpgDocument(), - Advertisement("aetheria.daemon.game"), - "cultmesh://aetheria/eve/surfaces/aetheria.daemon.game", - 1); - - public EveUnityPlayableWorldAssetManifestDocument CurrentDocument { get; private set; } = - new EveUnityPlayableWorldAssetManifestDocument( - "cultmesh://aetheria/assets/manifest", - Array.Empty(), - "aetheria"); - - EveUnitySceneProviderSurfaceDocument IEveUnitySceneProviderSurfaceDocumentSource.CurrentDocument => - CurrentSurfaceDocument; - - public event Action? DocumentAvailable; - - public event Action? AssetManifestDocumentAvailable; - - event Action IEveUnityPlayableWorldAssetManifestDocumentSource.DocumentAvailable - { - add => AssetManifestDocumentAvailable += value; - remove => AssetManifestDocumentAvailable -= value; - } - - public event Action? ReceiptAvailable; - - public void Set( - EveUnitySceneProviderSurfaceDocument surfaceDocument, - EveUnityPlayableWorldAssetManifestDocument assetManifest) - { - CurrentSurfaceDocument = surfaceDocument; - CurrentDocument = assetManifest; - } - - public void Refresh() - { - RefreshCount++; - DocumentAvailable?.Invoke(CurrentSurfaceDocument); - AssetManifestDocumentAvailable?.Invoke(CurrentDocument); - } - - public void Submit(EveSurfaceCommandRequest request) - { - Submitted.Add(request); - } - - public void PublishReceipt(EveUnitySceneCommandReceipt receipt) - { - ReceiptAvailable?.Invoke(receipt); - } - } - } -} diff --git a/runtimes/incubating/eve-unity-scene/Tests/Editor/EveUnitySceneSurfaceLowererTests.cs.meta b/runtimes/incubating/eve-unity-scene/Tests/Editor/EveUnitySceneSurfaceLowererTests.cs.meta deleted file mode 100644 index ef6d6e2..0000000 --- a/runtimes/incubating/eve-unity-scene/Tests/Editor/EveUnitySceneSurfaceLowererTests.cs.meta +++ /dev/null @@ -1,2 +0,0 @@ -fileFormatVersion: 2 -guid: d2b3006d5699924498750dbf5f087435 \ No newline at end of file diff --git a/runtimes/incubating/eve-unity-scene/Tests/Editor/GameCult.Eve.UnityScene.Tests.asmdef b/runtimes/incubating/eve-unity-scene/Tests/Editor/GameCult.Eve.UnityScene.Tests.asmdef deleted file mode 100644 index 392a1b5..0000000 --- a/runtimes/incubating/eve-unity-scene/Tests/Editor/GameCult.Eve.UnityScene.Tests.asmdef +++ /dev/null @@ -1,19 +0,0 @@ -{ - "name": "GameCult.Eve.UnityScene.Tests", - "rootNamespace": "GameCult.Eve.UnityScene.Tests", - "references": [ - "GameCult.Eve.Surface", - "GameCult.Eve.UnityScene" - ], - "includePlatforms": [ - "Editor" - ], - "excludePlatforms": [], - "allowUnsafeCode": false, - "overrideReferences": false, - "precompiledReferences": [], - "autoReferenced": false, - "defineConstraints": [], - "versionDefines": [], - "noEngineReferences": false -} diff --git a/runtimes/incubating/eve-unity-scene/Tests/Editor/GameCult.Eve.UnityScene.Tests.asmdef.meta b/runtimes/incubating/eve-unity-scene/Tests/Editor/GameCult.Eve.UnityScene.Tests.asmdef.meta deleted file mode 100644 index d045f6a..0000000 --- a/runtimes/incubating/eve-unity-scene/Tests/Editor/GameCult.Eve.UnityScene.Tests.asmdef.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 10e7994adb919944aadc88f960300bc4 -AssemblyDefinitionImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/runtimes/incubating/eve-unity-scene/eve-runtime-capability.json b/runtimes/incubating/eve-unity-scene/eve-runtime-capability.json deleted file mode 100644 index 1e6b22a..0000000 --- a/runtimes/incubating/eve-unity-scene/eve-runtime-capability.json +++ /dev/null @@ -1,269 +0,0 @@ -{ - "schema": "gamecult.eve.runtime_capability.v1", - "runtimeId": "unity-scene", - "title": "Unity / Scene", - "owner": "EveUnity", - "incubation": { - "ownerRepo": "EveUnity", - "currentHostRepo": "Eve", - "splitTarget": "EveUnity", - "graduationTrigger": "Split with EveUnity when a provider-agnostic Unity scene lowerer consumes provider world surfaces, emits command intents, and attaches scene capture evidence without importing Aetheria product code.", - "splitHandoff": { - "manifestPath": "runtimes/incubating/eve-unity-scene/eveunity-scene-split-handoff.json", - "smokeCommand": "powershell -ExecutionPolicy Bypass -File .\\scripts\\run-eveunity-scene-split-handoff-smoke.ps1" - } - }, - "supportedFeatures": [ - "providerAdvertisements", - "commandTransport", - "providerSurfaceSession", - "providerSurfaceSource", - "providerSurfaceDocumentSource", - "liveProviderTransportBridge", - "livePlayableWorldClient", - "providerCommandReceipts", - "providerAssetManifestDocumentSource", - "playableWorldClientHost", - "playableWorldClientBootstrap", - "playableWorldInputDriver", - "playableWorldCameraRig", - "sceneGraphProjection", - "playableWorldProjection", - "playableWorldRuntimeHost", - "playableWorldScenePresentation", - "unityGameObjectSceneSink", - "providerAssetManifestResolution", - "providerAssetManifestSource", - "embeddedDocuments" - ], - "supportedPlugins": [ - { - "pluginId": "sai.vn", - "capabilities": [ - "vn.stage", - "story.choose", - "story.continue", - "story.jump" - ], - "projectionAdapter": "SaiVisualNovelUnitySceneProjectionAdapter" - }, - { - "pluginId": "norn.graph", - "capabilities": [ - "embed.norn" - ], - "projectionAdapter": "NornGraphUnitySceneProjectionAdapter" - }, - { - "pluginId": "tex.math", - "capabilities": [ - "embed.tex", - "tex.inline", - "tex.block", - "tex.scene-placement" - ], - "projectionAdapter": "TeXMathUnitySceneProjectionAdapter" - } - ], - "unsupportedPlugins": [], - "worldSurfaceLowering": [ - { - "targetId": "unity-scene", - "surfaceKinds": ["interactive-world"], - "projectionKinds": ["provider-authored-world-surface"], - "supportLevel": "unity-playable-world-scene-command-surface", - "ownership": "runtime-lowers-provider-world-surface-without-owning-world-state", - "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/EveUnitySceneLiveProviderBridge.cs", - "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldLiveClient.cs", - "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldRuntime.cs", - "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldClientHost.cs", - "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldClientBootstrap.cs", - "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldInputDriver.cs", - "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldCameraRig.cs", - "runtimes/incubating/eve-unity-scene/Runtime/EveUnityProviderRefreshSource.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", - "runtimes/incubating/eve-unity-scene/Tests/Editor/EveUnitySceneSurfaceLowererTests.cs", - "web/fixtures/aetheria.provider-advertisement.json", - "web/fixtures/eve-world-smoke.provider-advertisement.json" - ] - } - ], - "commandTransport": { - "schema": "gamecult.eve.command.v1", - "status": "provider-shell-contract-skeleton", - "emitter": "EveUnitySceneSurfaceLowerer.CreateCommandIntent", - "clientId": "unity-scene", - "authority": "Unity scene input emits command intents through provider-advertised command boundaries; providers accept, deny, and publish receipts." - }, - "lifecycle": { - "release": { - "ownerRepo": "EveUnity", - "status": "unity-scene-upm-artifact-smoke", - "releaseContract": { - "ownerRepo": "EveUnity", - "packageName": "org.gamecult.eve.unity-scene", - "packageRoot": "runtimes/incubating/eve-unity-scene", - "versionSource": "runtimes/incubating/eve-unity-scene/package.json", - "tagPattern": "eveunity-scene-v{version}", - "artifactKind": "upm-package", - "requestSchema": "gamecult.eve.runtime_release_request.v1", - "requestBuilder": "tools/eveunity/eveunity-release-contract.mjs", - "artifactBuilder": "tools/eveunity/eveunity-release-artifact.mjs", - "artifactPattern": "artifacts/eveunity-scene-release/{version}/org.gamecult.eve.unity-scene-{version}.tgz", - "publishProof": "Tagged Unity scene package release is created from the EveUnity repo and references the provider-agnostic scene package root.", - "requiredPackageDependencies": [ - { - "packageName": "org.gamecult.eve.surface", - "version": "0.1.0", - "packageManager": "upm", - "ownerRepo": "Eve", - "purpose": "Shared Unity DTOs for gamecult.eve.surface.v1 documents." - } - ] - }, - "evidencePaths": [ - "runtimes/incubating/eve-unity-scene/package.json", - "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/EveUnitySceneLiveProviderBridge.cs", - "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldLiveClient.cs", - "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldRuntime.cs", - "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldClientHost.cs", - "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldClientBootstrap.cs", - "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldInputDriver.cs", - "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldCameraRig.cs", - "runtimes/incubating/eve-unity-scene/Runtime/EveUnityProviderRefreshSource.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", - "runtimes/incubating/eve-unity-scene/eveunity-scene-split-handoff.json", - "scripts/run-eveunity-scene-split-handoff-smoke.ps1", - "scripts/run-eveunity-scene-release-contract-smoke.ps1", - "scripts/run-eveunity-scene-release-artifact-smoke.ps1", - "tools/eveunity/eveunity-release-contract.mjs", - "tools/eveunity/eveunity-release-contract.test.mjs", - "tools/eveunity/eveunity-release-artifact.mjs", - "tools/eveunity/eveunity-release-artifact.test.mjs" - ], - "pendingProofs": [ - "Unity scene package release is cut from EveUnity rather than Eve incubation." - ] - }, - "test": { - "ownerRepo": "EveUnity", - "status": "unity-scene-editmode-batchmode", - "testContract": { - "ownerRepo": "EveUnity", - "runnerKind": "unity-editmode-batchmode", - "runnerScript": "scripts/run-aetheria-unity-scene-editmode-tests.ps1", - "consumerProject": "E:\\Projects\\Aetheria", - "packageName": "org.gamecult.eve.unity-scene", - "testAssembly": "GameCult.Eve.UnityScene.Tests", - "testPlatform": "EditMode", - "resultsArtifact": "artifacts/aetheria-unity-scene-editmode/{stamp}/unity-editmode-results.xml", - "logArtifact": "artifacts/aetheria-unity-scene-editmode/{stamp}/unity-editmode.log", - "manifestMutation": "Temporarily adds org.gamecult.eve.unity-scene to Aetheria Unity testables, runs GameCult.Eve.UnityScene.Tests, and restores Packages/manifest.json." - }, - "evidencePaths": [ - "runtimes/incubating/eve-unity-scene/package.json", - "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/EveUnitySceneLiveProviderBridge.cs", - "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldLiveClient.cs", - "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldRuntime.cs", - "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldClientHost.cs", - "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldClientBootstrap.cs", - "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldInputDriver.cs", - "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldCameraRig.cs", - "runtimes/incubating/eve-unity-scene/Runtime/EveUnityProviderRefreshSource.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", - "runtimes/incubating/eve-unity-scene/Tests/Editor/GameCult.Eve.UnityScene.Tests.asmdef", - "runtimes/incubating/eve-unity-scene/Tests/Editor/EveUnitySceneSurfaceLowererTests.cs", - "runtimes/incubating/eve-unity-scene/eveunity-scene-split-handoff.json", - "scripts/run-eveunity-scene-split-handoff-smoke.ps1", - "scripts/run-eveunity-scene-provider-shell-smoke.ps1", - "scripts/run-aetheria-unity-editmode-tests.ps1", - "scripts/run-aetheria-unity-scene-editmode-tests.ps1" - ], - "pendingProofs": [ - "Unity scene EditMode runner is owned by EveUnity rather than Eve incubation.", - "Live CultMesh/CultNet provider subscription adapter implements IEveUnitySceneLiveProviderTransport and feeds EveUnitySceneLiveProviderBridge from provider-owned documents, manifests, commands, and receipts instead of Eve-local fixture documents." - ] - }, - "capture": { - "ownerRepo": "EveUnity", - "status": "pending-unity-scene-capture", - "captureContract": { - "ownerRepo": "EveUnity", - "runtimeId": "unity-scene", - "targetId": "unity-scene", - "requestSchema": "gamecult.eve.runtime_capture_request.v1", - "requestBuilder": "tools/eveunity/eveunity-capture-contract.mjs", - "advertisementPath": "web/fixtures/aetheria.provider-advertisement.json", - "captureKind": "unity-scene-frame-png", - "artifactKind": "png", - "artifactPattern": "artifacts/eveunity-scene-capture/{stamp}/unity-scene.png", - "conformanceAttachment": "runtime.captureArtifacts[]", - "requiredProvider": "aetheria", - "requiredSurface": "aetheria.daemon.game", - "additionalProviderSurfaces": [ - { - "providerId": "eve.world-smoke", - "surfaceId": "eve.world-smoke.surface", - "purpose": "Generic non-product interactive-world capture control." - } - ], - "authority": "Capture observes Unity scene projection only; provider state, command acceptance, and receipts stay provider-owned.", - "publishProof": "Unity scene screenshot or frame-capture PNG artifact is attached to the runtime conformance report from EveUnity." - }, - "evidencePaths": [ - "tools/eveunity/eveunity-capture-contract.mjs", - "tools/eveunity/eveunity-capture-contract.test.mjs", - "tools/eveunity/eveunity-scene-capture-artifact.mjs", - "tools/eveunity/eveunity-scene-capture-artifact.test.mjs", - "scripts/run-eveunity-scene-capture-contract-smoke.ps1", - "scripts/run-eveunity-scene-capture-smoke.ps1" - ], - "pendingProofs": [ - "Unity scene screenshot or frame-capture PNG artifact is attached to the runtime conformance report." - ] - } - }, - "capture": { - "status": "json-projection", - "note": "Unity scene attaches a provider-advertisement-backed gamecult.eve.unity_scene_projection.v1 JSON projection artifact; Unity screenshot or frame-capture PNG remains an EveUnity split blocker.", - "artifacts": [ - { - "kind": "json-projection", - "schema": "gamecult.eve.unity_scene_projection.v1", - "path": "artifacts/eveunity-scene-capture/latest/unity-scene-projection.json", - "runtimeId": "unity-scene", - "providerId": "aetheria", - "surfaceId": "aetheria.daemon.game", - "sourceSurfacePath": "web/fixtures/aetheria-world-surface.json", - "requestPath": "artifacts/eveunity-scene-capture/latest/capture-request.json" - } - ] - } -} diff --git a/runtimes/incubating/eve-unity-scene/eve-runtime-capability.json.meta b/runtimes/incubating/eve-unity-scene/eve-runtime-capability.json.meta deleted file mode 100644 index b672c6f..0000000 --- a/runtimes/incubating/eve-unity-scene/eve-runtime-capability.json.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 16a73a75d0939424bad58c752f0f8a3e -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/runtimes/incubating/eve-unity-scene/eveunity-scene-split-handoff.json b/runtimes/incubating/eve-unity-scene/eveunity-scene-split-handoff.json deleted file mode 100644 index 196ad56..0000000 --- a/runtimes/incubating/eve-unity-scene/eveunity-scene-split-handoff.json +++ /dev/null @@ -1,218 +0,0 @@ -{ - "schema": "gamecult.eve.runtime_split_handoff.v1", - "splitTarget": "EveUnity", - "ownerRepo": "EveUnity", - "currentHostRepo": "Eve", - "runtimeId": "unity-scene", - "packageName": "org.gamecult.eve.unity-scene", - "sourcePackageRoot": "runtimes/incubating/eve-unity-scene", - "destinationPackageRoot": "packages/org.gamecult.eve.unity-scene", - "authorityBoundary": "EveUnity owns generic Unity scene projection for provider-authored world surfaces: scene graph construction, camera/input binding, Unity package lifecycle, scene capture, and command intent emission through advertised provider command boundaries. Providers such as Aetheria own world state, assets, simulation, command authorization, receipts, and authored scenario flows. Eve keeps only the surface, command, provider advertisement, runtime capability, and conformance export contracts.", - "moveSets": [ - { - "id": "unity-scene-runtime-body", - "stage": "runtime-body", - "currentPaths": [ - "runtimes/incubating/eve-unity-scene/package.json", - "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/EveUnitySceneLiveProviderBridge.cs", - "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldLiveClient.cs", - "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldRuntime.cs", - "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldClientHost.cs", - "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldClientBootstrap.cs", - "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldInputDriver.cs", - "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldCameraRig.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", - "runtimes/incubating/eve-unity-scene/Tests/Editor/GameCult.Eve.UnityScene.Tests.asmdef", - "runtimes/incubating/eve-unity-scene/Tests/Editor/EveUnitySceneSurfaceLowererTests.cs" - ], - "destinationOwner": "EveUnity", - "replacementProof": "EveUnity hosts a provider-agnostic Unity scene lowerer that consumes provider advertisements and world surfaces without importing Aetheria runtime internals." - }, - { - "id": "unity-scene-upm-package", - "stage": "release", - "currentPaths": [ - "runtimes/incubating/eve-unity-scene/package.json", - "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/EveUnitySceneLiveProviderBridge.cs", - "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldLiveClient.cs", - "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldRuntime.cs", - "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldClientHost.cs", - "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldClientBootstrap.cs", - "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldInputDriver.cs", - "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldCameraRig.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", - "tools/eveunity/eveunity-release-artifact.mjs", - "tools/eveunity/eveunity-release-artifact.test.mjs", - "scripts/run-eveunity-scene-release-contract-smoke.ps1", - "scripts/run-eveunity-scene-release-artifact-smoke.ps1" - ], - "destinationOwner": "EveUnity", - "replacementProof": "EveUnity builds the provider-agnostic Unity scene UPM package artifact now; the split is not complete until the tagged Unity scene release is cut from EveUnity." - }, - { - "id": "unity-scene-world-surface-lowering", - "stage": "world-surface-lowering", - "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/EveUnitySceneLiveProviderBridge.cs", - "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldLiveClient.cs", - "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldRuntime.cs", - "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldClientHost.cs", - "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldClientBootstrap.cs", - "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldInputDriver.cs", - "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldCameraRig.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", - "runtimes/incubating/eve-unity-scene/Tests/Editor/EveUnitySceneSurfaceLowererTests.cs", - "runtimes/incubating/eve-unity-scene/eve-runtime-capability.json" - ], - "destinationOwner": "EveUnity", - "replacementProof": "EveUnity claims the provider-advertised unity-scene lowering target with provider-agnostic playable-world projection, scene graph projection, typed provider surface document loading, provider snapshot session, live provider transport bridge, a playable-world runtime host, generic client bootstrap, movement input driver, camera rig, live playable-world client composition, provider command receipt observation, playable-world scene presentation, Unity GameObject scene sink, typed provider asset manifest document loading, provider asset manifest resolution, provider asset manifest source/cache, and command boundary evidence; concrete CultMesh/CultNet transport and capture remain separate lifecycle proofs." - }, - { - "id": "unity-scene-sai-plugin-projection", - "stage": "plugin-projection", - "currentPaths": [ - "runtimes/incubating/eve-unity-scene/Runtime/SaiVisualNovelUnitySceneProjectionAdapter.cs", - "runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs", - "runtimes/incubating/eve-unity-scene/Tests/Editor/EveUnitySceneSurfaceLowererTests.cs", - "runtimes/incubating/eve-unity-scene/eve-runtime-capability.json" - ], - "destinationOwner": "EveUnity", - "replacementProof": "EveUnity owns only the Unity scene projection adapter for Sai's sidecar-advertised VN capabilities; Sai keeps story state, VN/Ink semantics, and story command interpretation." - }, - { - "id": "unity-scene-norn-plugin-projection", - "stage": "plugin-projection", - "currentPaths": [ - "runtimes/incubating/eve-unity-scene/Runtime/NornGraphUnitySceneProjectionAdapter.cs", - "runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs", - "runtimes/incubating/eve-unity-scene/Tests/Editor/EveUnitySceneSurfaceLowererTests.cs", - "runtimes/incubating/eve-unity-scene/eve-runtime-capability.json" - ], - "destinationOwner": "EveUnity", - "replacementProof": "EveUnity owns only the Unity scene projection adapter for Norn's sidecar-advertised embed.norn capability; Norn keeps graph layout, graph state, and graph command semantics." - }, - { - "id": "unity-scene-tex-plugin-projection", - "stage": "plugin-projection", - "currentPaths": [ - "runtimes/incubating/eve-unity-scene/Runtime/TeXMathUnitySceneProjectionAdapter.cs", - "runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs", - "runtimes/incubating/eve-unity-scene/Tests/Editor/EveUnitySceneSurfaceLowererTests.cs", - "runtimes/incubating/eve-unity-scene/eve-runtime-capability.json" - ], - "destinationOwner": "EveUnity", - "replacementProof": "EveUnity owns only the Unity scene projection shell for TeX's sidecar-advertised embed.tex capability; EvePlugins keeps TeX parsing, typesetting, baseline metrics, and render-cache semantics." - }, - { - "id": "unity-scene-command-transport", - "stage": "command", - "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/EveUnitySceneLiveProviderBridge.cs", - "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldClientHost.cs", - "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldClientBootstrap.cs", - "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldInputDriver.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 typed provider surface documents, a provider-snapshot client session, IEveUnitySceneLiveProviderTransport, IEveUnitySceneCommandSink, IEveUnitySceneCommandReceiptSource, and advertised command boundaries, then observes provider receipts and refreshes from provider documents/snapshots instead of mutating local world truth." - }, - { - "id": "aetheria-playable-world-consumer-proof", - "stage": "observed-provider-proof", - "observedProviderPaths": [ - "E:\\Projects\\Aetheria\\Assets\\Scripts\\Tests\\DaemonRuntimeDocumentTests.cs", - "E:\\Projects\\Aetheria\\Packages\\org.gamecult.aetheria.eve-runtime\\Runtime\\AetheriaEveUnitySceneProviderBridge.cs", - "E:\\Projects\\Aetheria\\Packages\\org.gamecult.aetheria.state\\Runtime\\AetheriaRuntimeDaemonGameSurfaceBuilder.cs", - "E:\\Projects\\Aetheria\\Packages\\org.gamecult.aetheria.state\\Runtime\\AetheriaRuntimeDaemonOperationsClient.cs" - ], - "destinationOwner": "Aetheria", - "replacementProof": "Aetheria proves a generic EveUnity playable-world runtime can lower the daemon-published 3D ARPG surface, resolve provider-owned asset refs, submit movement through the advertised command boundary, observe provider receipts, and refresh from provider-owned daemon snapshots without making EveUnity import Aetheria product code." - }, - { - "id": "unity-scene-capture-lifecycle", - "stage": "capture", - "currentPaths": [ - "tools/eveunity/eveunity-capture-contract.mjs", - "tools/eveunity/eveunity-capture-contract.test.mjs", - "tools/eveunity/eveunity-scene-capture-artifact.mjs", - "tools/eveunity/eveunity-scene-capture-artifact.test.mjs", - "scripts/run-eveunity-scene-capture-contract-smoke.ps1", - "scripts/run-eveunity-scene-capture-smoke.ps1" - ], - "destinationOwner": "EveUnity", - "replacementProof": "EveUnity builds a provider-advertisement-backed Unity scene capture request and deterministic gamecult.eve.unity_scene_projection.v1 JSON projection artifact with playableWorld evidence now; the split is not complete until EveUnity attaches Unity scene screenshot or frame-capture PNG artifacts to conformance output for at least one provider-authored world surface." - } - ], - "contractInputs": [ - "gamecult.eve.surface.v1", - "gamecult.eve.command.v1", - "gamecult.eve.provider_advertisement.v1", - "gamecult.eve.runtime_capability.v1", - "gamecult.eve.conformance_export.v1" - ], - "forbiddenImports": [ - "Aetheria daemon state as Unity scene runtime authority", - "Aetheria gameplay scripts as EveUnity scene lowerer truth", - "provider-specific scene components that bypass gamecult.eve.command.v1", - "renderer-local world simulation as provider truth", - "product assets bundled as Eve runtime contract", - "Sai story state, VN/Ink semantics, or story command interpretation as Unity scene runtime authority", - "Norn graph layout, graph state, or command semantics as Unity scene runtime authority", - "TeX parsing, typesetting, baseline metrics, or render-cache semantics as Unity scene runtime authority" - ], - "requiredExternalProofs": [ - "EveUnity publishes a Unity scene runtime capability manifest.", - "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 typed provider surface document, provider surface source, and command sink ports that a live CultMesh/CultNet adapter can implement without changing scene lowering.", - "EveUnity owns a live provider transport bridge that adapts CultMesh/CultNet provider documents, asset manifests, command submission, receipts, and refresh requests into the runtime ports without importing provider internals.", - "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 generic Unity client bootstrap that wires provider surface documents, command sink, asset manifest, input driver, camera rig, and scene root without importing provider internals.", - "EveUnity owns generic playable-world movement input and camera rig components that emit provider-owned command intents and follow provider-advertised player entities without importing provider internals.", - "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 gamecult.eve.unity_playable_world_asset_manifest.v1 document loading into its asset manifest cache without importing Aetheria asset 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 a provider asset manifest source/cache boundary keyed by playableWorld assetManifest pointers so live CultMesh/CultCache loading can update Unity asset bindings 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.", - "EveUnity owns the Unity scene TeX projection adapter outside Eve incubation without importing TeX implementation state.", - "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, observes provider receipts, and refreshes rendered state from provider surface documents/snapshots.", - "Unity scene screenshot or frame-capture PNG artifacts are attached to conformance output." - ] -} diff --git a/runtimes/incubating/eve-unity-scene/eveunity-scene-split-handoff.json.meta b/runtimes/incubating/eve-unity-scene/eveunity-scene-split-handoff.json.meta deleted file mode 100644 index a253ee8..0000000 --- a/runtimes/incubating/eve-unity-scene/eveunity-scene-split-handoff.json.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 0a5262acca13bee44bb5cac30a93f8dd -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/runtimes/incubating/eve-unity-scene/package.json b/runtimes/incubating/eve-unity-scene/package.json deleted file mode 100644 index bdd7c4f..0000000 --- a/runtimes/incubating/eve-unity-scene/package.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name": "org.gamecult.eve.unity-scene", - "displayName": "Eve Unity Scene Lowering", - "version": "0.1.0", - "unity": "2021.3", - "description": "Provider-agnostic Unity scene shell for gamecult.eve.surface.v1 interactive world surfaces.", - "dependencies": { - "org.gamecult.eve.surface": "0.1.0" - }, - "keywords": [ - "Eve", - "Unity", - "Scene", - "Interactive World" - ], - "license": "MPL-2.0", - "category": "Scripting" -} diff --git a/runtimes/incubating/eve-unity-scene/package.json.meta b/runtimes/incubating/eve-unity-scene/package.json.meta deleted file mode 100644 index f41eec4..0000000 --- a/runtimes/incubating/eve-unity-scene/package.json.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 8eaedcd0b70a6574c8ddb12c84b444a5 -PackageManifestImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/scripts/run-aetheria-conformance-consumer-smoke.ps1 b/scripts/run-aetheria-conformance-consumer-smoke.ps1 index 4bdc8b7..546a658 100644 --- a/scripts/run-aetheria-conformance-consumer-smoke.ps1 +++ b/scripts/run-aetheria-conformance-consumer-smoke.ps1 @@ -82,26 +82,14 @@ try { --expect-command-boundary-coverage aetheria:aetheria.daemon.editor:tui:covered:EveTui:tui ` --expect-split-target-proof "EveUnity:Aetheria daemon 3D ARPG world lowers through a generic EveUnity playable-world client" ` --expect-runtime-capture-artifact unity-uitoolkit:json-projection:gamecult.eve.unity_uitoolkit_projection.v1:aetheria:aetheria.daemon.game ` - --expect-runtime-capture-artifact unity-scene:json-projection:gamecult.eve.unity_scene_projection.v1:aetheria:aetheria.daemon.game ` --expect-runtime-capture-artifact electron-shell:json-projection:gamecult.eve.electron_shell_projection.v1:aetheria:aetheria.daemon.game ` --expect-runtime-capture-artifact tui:json-grid:gamecult.eve.tui_grid.v1:aetheria:aetheria.daemon.game ` --expect-split-handoff-move EveTui:tui:tui-runtime-body:current:exists:eve-tui-shell.mjs ` --expect-split-handoff-move EveTui:tui:tui-world-surface-lowering:current:exists:eve-tui-shell.mjs ` --expect-split-handoff-move EveTui:tui:tui-command-transport:current:exists:eve-tui-shell.mjs ` - --expect-split-target-blocker "EveUnity:Unity scene runtime body graduates to EveUnity outside Aetheria product code" ` --expect-split-target-blocker "EveElectron:Electron shell runtime body graduates to EveElectron outside Aetheria product code" ` --expect-split-target-blocker "EveTui:TUI package release is cut from EveTui rather than Eve incubation" ` --expect-split-target-blocker "EveTui:TUI capture path is owned by EveTui rather than Eve incubation" ` - --expect-split-handoff-move EveUnity:unity-scene:unity-scene-runtime-body:current:exists:EveUnitySceneSurfaceLowerer.cs ` - --expect-split-handoff-move EveUnity:unity-scene:unity-scene-runtime-body:current:exists:EveUnitySceneLiveProviderBridge.cs ` - --expect-split-handoff-move EveUnity:unity-scene:unity-scene-world-surface-lowering:current:exists:EveUnitySceneSurfaceLowerer.cs ` - --expect-split-handoff-move EveUnity:unity-scene:unity-scene-world-surface-lowering:current:exists:EveUnitySceneLiveProviderBridge.cs ` - --expect-split-handoff-move EveUnity:unity-scene:unity-scene-command-transport:current:exists:EveUnitySceneSurfaceLowerer.cs ` - --expect-split-handoff-move EveUnity:unity-scene:unity-scene-command-transport:current:exists:EveUnitySceneLiveProviderBridge.cs ` - --expect-split-handoff-move EveUnity:unity-scene:aetheria-playable-world-consumer-proof:observed-provider:exists:Assets/Scripts/Tests/DaemonRuntimeDocumentTests.cs ` - --expect-split-handoff-move EveUnity:unity-scene:aetheria-playable-world-consumer-proof:observed-provider:exists:Packages/org.gamecult.aetheria.eve-runtime/Runtime/AetheriaEveUnitySceneProviderBridge.cs ` - --expect-split-handoff-move EveUnity:unity-scene:aetheria-playable-world-consumer-proof:observed-provider:exists:AetheriaRuntimeDaemonGameSurfaceBuilder.cs ` - --expect-split-handoff-move EveUnity:unity-scene:aetheria-playable-world-consumer-proof:observed-provider:exists:AetheriaRuntimeDaemonOperationsClient.cs ` --expect-split-handoff-move EveUnity:unity-uitoolkit:aetheria-unity-consumer-boundary:observed-provider:exists:Packages/manifest.json ` --expect-split-handoff-move EveUnity:unity-uitoolkit:aetheria-unity-consumer-boundary:observed-provider:exists:GameCult.Eve.UnityUIToolkit.csproj ` --expect-split-handoff-move EveUnity:unity-uitoolkit:aetheria-unity-consumer-boundary:observed-provider:exists:Aetheria.State.Unity/AetheriaRuntimeCatalogClient.cs ` diff --git a/scripts/run-aetheria-unity-package-smoke.ps1 b/scripts/run-aetheria-unity-package-smoke.ps1 index 26cfe19..16f374c 100644 --- a/scripts/run-aetheria-unity-package-smoke.ps1 +++ b/scripts/run-aetheria-unity-package-smoke.ps1 @@ -1,5 +1,6 @@ param( - [string] $AetheriaRoot = "E:\Projects\Aetheria" + [string] $AetheriaRoot = "E:\Projects\Aetheria", + [string] $EveUnityRoot = "E:\Projects\EveUnity" ) $ErrorActionPreference = "Stop" @@ -8,6 +9,9 @@ $eveRoot = Split-Path -Parent $PSScriptRoot if (-not (Test-Path $AetheriaRoot)) { throw "Aetheria repo not found: $AetheriaRoot" } +if (-not (Test-Path $EveUnityRoot)) { + throw "EveUnity repo not found: $EveUnityRoot" +} $manifestPath = Join-Path $AetheriaRoot "Packages\manifest.json" $unityToolkitProject = Join-Path $AetheriaRoot "GameCult.Eve.UnityUIToolkit.csproj" @@ -24,8 +28,9 @@ $aetheriaGameSurfaceBuilder = Join-Path $AetheriaRoot "Packages\org.gamecult.aet $aetheriaDaemonOperationsClient = Join-Path $AetheriaRoot "Packages\org.gamecult.aetheria.state\Runtime\AetheriaRuntimeDaemonOperationsClient.cs" $aetheriaDaemonDocuments = Join-Path $AetheriaRoot "Packages\org.gamecult.aetheria.state\Runtime\AetheriaRuntimeDaemonDocuments.cs" $aetheriaRuntimeVerseClient = Join-Path $AetheriaRoot "Packages\org.gamecult.aetheria.state\Runtime\AetheriaRuntimeVerseClient.cs" -$eveUnitySceneProviderConnection = Join-Path $eveRoot "runtimes\incubating\eve-unity-scene\Runtime\EveUnitySceneProviderConnection.cs" -$eveUnitySceneLiveProviderBridge = Join-Path $eveRoot "runtimes\incubating\eve-unity-scene\Runtime\EveUnitySceneLiveProviderBridge.cs" +$eveUnityScenePackage = Join-Path $EveUnityRoot "packages\org.gamecult.eve.unity-scene" +$eveUnitySceneProviderConnection = Join-Path $eveUnityScenePackage "Runtime\EveUnitySceneProviderConnection.cs" +$eveUnitySceneLiveProviderBridge = Join-Path $eveUnityScenePackage "Runtime\EveUnitySceneLiveProviderBridge.cs" if (-not (Test-Path $manifestPath)) { throw "Aetheria Unity package manifest not found: $manifestPath" } @@ -81,7 +86,7 @@ if (-not (Test-Path $eveUnitySceneLiveProviderBridge)) { $manifest = Get-Content -Raw -LiteralPath $manifestPath | ConvertFrom-Json $requiredDependencies = @{ "org.gamecult.eve.surface" = "file:../../Eve/packages/org.gamecult.eve.surface" - "org.gamecult.eve.unity-scene" = "file:../../Eve/runtimes/incubating/eve-unity-scene" + "org.gamecult.eve.unity-scene" = "file:../EveUnity/packages/org.gamecult.eve.unity-scene" "org.gamecult.eve.unity-uitoolkit" = "file:../../Eve/packages/org.gamecult.eve.unity-uitoolkit" } foreach ($dependencyName in $requiredDependencies.Keys) { @@ -122,7 +127,7 @@ $requiredSceneCompileItems = @( "Runtime\EveUnityPlayableWorldAssetManifest.cs" ) foreach ($compileItem in $requiredSceneCompileItems) { - $expected = Join-Path $eveRoot "runtimes\incubating\eve-unity-scene\$compileItem" + $expected = Join-Path $eveUnityScenePackage $compileItem if (-not $sceneProject.Contains($expected)) { throw "Aetheria GameCult.Eve.UnityScene.csproj missing compile item: $expected" } diff --git a/scripts/run-aetheria-unity-scene-editmode-tests.ps1 b/scripts/run-aetheria-unity-scene-editmode-tests.ps1 deleted file mode 100644 index 86d8c28..0000000 --- a/scripts/run-aetheria-unity-scene-editmode-tests.ps1 +++ /dev/null @@ -1,19 +0,0 @@ -param( - [string] $AetheriaRoot = "E:\Projects\Aetheria", - [string] $UnityExe = "C:\Program Files\Unity\Hub\Editor\6000.4.2f1\Editor\Unity.exe", - [string] $OutputRoot = "" -) - -$ErrorActionPreference = "Stop" - -$eveRoot = Split-Path -Parent $PSScriptRoot -if ([string]::IsNullOrWhiteSpace($OutputRoot)) { - $OutputRoot = Join-Path $eveRoot "artifacts\aetheria-unity-scene-editmode" -} - -& (Join-Path $PSScriptRoot "run-aetheria-unity-editmode-tests.ps1") ` - -AetheriaRoot $AetheriaRoot ` - -UnityExe $UnityExe ` - -OutputRoot $OutputRoot ` - -PackageName "org.gamecult.eve.unity-scene" ` - -TestAssembly "GameCult.Eve.UnityScene.Tests" diff --git a/scripts/run-conformance-consumer-smoke.ps1 b/scripts/run-conformance-consumer-smoke.ps1 index 430bc1e..7a9b125 100644 --- a/scripts/run-conformance-consumer-smoke.ps1 +++ b/scripts/run-conformance-consumer-smoke.ps1 @@ -101,7 +101,7 @@ try { --expect-screenshot-metric web:eve-world-smoke:bounding-boxes:pass ` --expect-screenshot-metric electron-shell:aetheria-world:bounding-boxes:pending-capture ` --expect-runtime-capture-probe unity-uitoolkit:semantic-artifact-present-capture-pending:png:EveUnity ` - --expect-runtime-capture-probe unity-scene:semantic-artifact-present-capture-pending:png:EveUnity ` + --expect-runtime-capture-probe unity-scene:contract-artifact-missing:png:EveUnity ` --expect-runtime-capture-probe electron-shell:semantic-artifact-present-capture-pending:png:EveElectron ` --expect-runtime-capture-probe tui:contract-artifact-present:json-grid:EveTui ` --expect-capability-gap "split-target:EveUnity:EveUnity:proof:Tagged UPM release" ` diff --git a/scripts/run-eveunity-scene-capture-contract-smoke.ps1 b/scripts/run-eveunity-scene-capture-contract-smoke.ps1 deleted file mode 100644 index 19417b0..0000000 --- a/scripts/run-eveunity-scene-capture-contract-smoke.ps1 +++ /dev/null @@ -1,99 +0,0 @@ -param( - [string] $CapabilityManifestPath = "runtimes\incubating\eve-unity-scene\eve-runtime-capability.json", - [string] $AdvertisementPath = "web\fixtures\aetheria.provider-advertisement.json", - [string] $OutputPath = "artifacts\eveunity-scene-capture-contract\latest\capture-request.json", - [string] $Stamp = "smoke" -) - -$ErrorActionPreference = "Stop" - -$projectRoot = Split-Path -Parent $PSScriptRoot -$absoluteCapabilityPath = if ([System.IO.Path]::IsPathRooted($CapabilityManifestPath)) { - $CapabilityManifestPath -} else { - Join-Path $projectRoot $CapabilityManifestPath -} -$absoluteAdvertisementPath = if ([System.IO.Path]::IsPathRooted($AdvertisementPath)) { - $AdvertisementPath -} else { - Join-Path $projectRoot $AdvertisementPath -} -$absoluteOutputPath = if ([System.IO.Path]::IsPathRooted($OutputPath)) { - $OutputPath -} else { - Join-Path $projectRoot $OutputPath -} - -foreach ($path in @($absoluteCapabilityPath, $absoluteAdvertisementPath)) { - if (-not (Test-Path -LiteralPath $path)) { - throw "EveUnity scene capture contract input not found: $path" - } -} - -$manifest = Get-Content -LiteralPath $absoluteCapabilityPath -Raw | ConvertFrom-Json -$captureContract = $manifest.lifecycle.capture.captureContract -if ($null -eq $captureContract) { - throw "EveUnity scene capture contract missing lifecycle.capture.captureContract" -} -foreach ($field in @("ownerRepo", "runtimeId", "targetId", "requestSchema", "requestBuilder", "advertisementPath", "captureKind", "artifactKind", "artifactPattern", "conformanceAttachment", "requiredProvider", "requiredSurface", "authority", "publishProof")) { - if (-not $captureContract.$field) { - throw "EveUnity scene capture contract missing $field" - } -} -if ($captureContract.ownerRepo -ne "EveUnity") { - throw "Unexpected EveUnity scene capture owner: $($captureContract.ownerRepo)" -} -if ($captureContract.runtimeId -ne "unity-scene") { - throw "Unexpected EveUnity scene capture runtime: $($captureContract.runtimeId)" -} -if ($captureContract.targetId -ne "unity-scene") { - throw "Unexpected EveUnity scene capture target: $($captureContract.targetId)" -} -if ($captureContract.requestSchema -ne "gamecult.eve.runtime_capture_request.v1") { - throw "Unexpected EveUnity scene capture request schema: $($captureContract.requestSchema)" -} - -$builderPath = Join-Path $projectRoot $captureContract.requestBuilder -if (-not (Test-Path -LiteralPath $builderPath)) { - throw "EveUnity scene capture request builder not found: $($captureContract.requestBuilder)" -} -if ((Join-Path $projectRoot $captureContract.advertisementPath) -ne $absoluteAdvertisementPath) { - throw "EveUnity scene capture advertisement path mismatch: $($captureContract.advertisementPath) vs $AdvertisementPath" -} - -node --test (Join-Path $projectRoot "tools\eveunity\eveunity-capture-contract.test.mjs") -if ($LASTEXITCODE -ne 0) { - throw "EveUnity capture contract tests failed with exit code $LASTEXITCODE" -} - -node $builderPath --capability $absoluteCapabilityPath --advertisement $absoluteAdvertisementPath --output $absoluteOutputPath --stamp $Stamp -if ($LASTEXITCODE -ne 0) { - throw "EveUnity scene capture request builder failed with exit code $LASTEXITCODE" -} -if (-not (Test-Path -LiteralPath $absoluteOutputPath)) { - throw "EveUnity scene capture request was not written: $absoluteOutputPath" -} - -$request = Get-Content -LiteralPath $absoluteOutputPath -Raw | ConvertFrom-Json -foreach ($expectation in @( - @{ field = "schema"; value = "gamecult.eve.runtime_capture_request.v1" }, - @{ field = "runtimeId"; value = "unity-scene" }, - @{ field = "ownerRepo"; value = "EveUnity" }, - @{ field = "providerId"; value = "aetheria" }, - @{ field = "surfaceId"; value = "aetheria.daemon.game" }, - @{ field = "targetId"; value = "unity-scene" }, - @{ field = "commandBoundary"; value = "aetheria.daemon.commands" }, - @{ field = "receiptSchema"; value = "aetheria.eve_command_acceptance_status.v1" }, - @{ field = "captureKind"; value = "unity-scene-frame-png" }, - @{ field = "artifactKind"; value = "png" }, - @{ field = "conformanceAttachment"; value = "runtime.captureArtifacts[]" } -)) { - if ($request.($expectation.field) -ne $expectation.value) { - throw "EveUnity scene capture request $($expectation.field) expected $($expectation.value) got $($request.($expectation.field))" - } -} -if ($request.artifactPath -ne "artifacts/eveunity-scene-capture/$Stamp/unity-scene.png") { - throw "Unexpected EveUnity scene capture artifact path: $($request.artifactPath)" -} - -Write-Host "EveUnity scene capture contract smoke passed: $absoluteOutputPath" diff --git a/scripts/run-eveunity-scene-capture-smoke.ps1 b/scripts/run-eveunity-scene-capture-smoke.ps1 deleted file mode 100644 index 67879fb..0000000 --- a/scripts/run-eveunity-scene-capture-smoke.ps1 +++ /dev/null @@ -1,77 +0,0 @@ -param( - [string] $CapabilityManifestPath = "runtimes\incubating\eve-unity-scene\eve-runtime-capability.json", - [string] $AdvertisementPath = "web\fixtures\aetheria.provider-advertisement.json", - [string] $SurfacePath = "web\fixtures\aetheria-world-surface.json", - [string] $OutputPath = "artifacts\eveunity-scene-capture\latest\unity-scene-projection.json", - [string] $RequestOutputPath = "artifacts\eveunity-scene-capture\latest\capture-request.json", - [string] $Stamp = "latest", - [string] $ExpectedProviderId = "aetheria", - [string] $ExpectedSurfaceId = "aetheria.daemon.game", - [string] $ExpectedCommandBoundary = "aetheria.daemon.commands", - [string] $ExpectedReceiptSchema = "aetheria.eve_command_acceptance_status.v1" -) - -$ErrorActionPreference = "Stop" - -$projectRoot = Split-Path -Parent $PSScriptRoot -function Resolve-RepoPath([string] $candidate) { - if ([System.IO.Path]::IsPathRooted($candidate)) { - return $candidate - } - return Join-Path $projectRoot $candidate -} - -$absoluteCapabilityPath = Resolve-RepoPath $CapabilityManifestPath -$absoluteAdvertisementPath = Resolve-RepoPath $AdvertisementPath -$absoluteSurfacePath = Resolve-RepoPath $SurfacePath -$absoluteOutputPath = Resolve-RepoPath $OutputPath -$absoluteRequestOutputPath = Resolve-RepoPath $RequestOutputPath - -foreach ($path in @($absoluteCapabilityPath, $absoluteAdvertisementPath, $absoluteSurfacePath)) { - if (-not (Test-Path -LiteralPath $path)) { - throw "EveUnity scene capture input not found: $path" - } -} - -node --test (Join-Path $projectRoot "tools\eveunity\eveunity-scene-capture-artifact.test.mjs") -if ($LASTEXITCODE -ne 0) { - throw "EveUnity scene capture artifact tests failed with exit code $LASTEXITCODE" -} - -node (Join-Path $projectRoot "tools\eveunity\eveunity-scene-capture-artifact.mjs") ` - --capability $absoluteCapabilityPath ` - --advertisement $absoluteAdvertisementPath ` - --surface $absoluteSurfacePath ` - --output $absoluteOutputPath ` - --request-output $absoluteRequestOutputPath ` - --stamp $Stamp -if ($LASTEXITCODE -ne 0) { - throw "EveUnity scene capture artifact builder failed with exit code $LASTEXITCODE" -} - -foreach ($path in @($absoluteOutputPath, $absoluteRequestOutputPath)) { - if (-not (Test-Path -LiteralPath $path)) { - throw "EveUnity scene capture artifact output missing: $path" - } -} - -$projection = Get-Content -LiteralPath $absoluteOutputPath -Raw | ConvertFrom-Json -foreach ($expectation in @( - @{ field = "schema"; value = "gamecult.eve.unity_scene_projection.v1" }, - @{ field = "runtimeId"; value = "unity-scene" }, - @{ field = "providerId"; value = $ExpectedProviderId }, - @{ field = "surfaceId"; value = $ExpectedSurfaceId }, - @{ field = "commandBoundary"; value = $ExpectedCommandBoundary }, - @{ field = "receiptSchema"; value = $ExpectedReceiptSchema }, - @{ field = "artifactKind"; value = "json-projection" }, - @{ field = "captureKind"; value = "unity-scene-projection-json" } -)) { - if ($projection.($expectation.field) -ne $expectation.value) { - throw "EveUnity scene projection $($expectation.field) expected $($expectation.value) got $($projection.($expectation.field))" - } -} -if (-not $projection.root.id) { - throw "EveUnity scene projection capture must contain a root scene node" -} - -Write-Host "EveUnity scene capture smoke passed: $absoluteOutputPath" diff --git a/scripts/run-eveunity-scene-lifecycle-smoke.ps1 b/scripts/run-eveunity-scene-lifecycle-smoke.ps1 deleted file mode 100644 index 84ae613..0000000 --- a/scripts/run-eveunity-scene-lifecycle-smoke.ps1 +++ /dev/null @@ -1,256 +0,0 @@ -param( - [string] $CapabilityManifestPath = "runtimes\incubating\eve-unity-scene\eve-runtime-capability.json", - [switch] $RunUnityEditMode -) - -$ErrorActionPreference = "Stop" - -$projectRoot = Split-Path -Parent $PSScriptRoot -$absoluteManifestPath = if ([System.IO.Path]::IsPathRooted($CapabilityManifestPath)) { - $CapabilityManifestPath -} else { - Join-Path $projectRoot $CapabilityManifestPath -} - -if (-not (Test-Path -LiteralPath $absoluteManifestPath)) { - throw "EveUnity scene runtime capability manifest not found: $absoluteManifestPath" -} - -$manifest = Get-Content -LiteralPath $absoluteManifestPath -Raw | ConvertFrom-Json - -if ($manifest.schema -ne "gamecult.eve.runtime_capability.v1") { - throw "Unexpected EveUnity scene manifest schema: $($manifest.schema)" -} -if ($manifest.runtimeId -ne "unity-scene") { - throw "Unexpected EveUnity scene runtime id: $($manifest.runtimeId)" -} -if ($manifest.owner -ne "EveUnity") { - throw "Unexpected EveUnity scene owner: $($manifest.owner)" -} -if ($manifest.incubation.ownerRepo -ne "EveUnity") { - throw "Unexpected EveUnity scene incubation owner: $($manifest.incubation.ownerRepo)" -} -if ($manifest.incubation.currentHostRepo -ne "Eve") { - throw "Unexpected EveUnity scene current host repo: $($manifest.incubation.currentHostRepo)" -} -if ($manifest.incubation.splitTarget -ne "EveUnity") { - throw "Unexpected EveUnity scene split target: $($manifest.incubation.splitTarget)" -} -if ($manifest.incubation.splitHandoff.manifestPath -ne "runtimes/incubating/eve-unity-scene/eveunity-scene-split-handoff.json") { - throw "EveUnity scene manifest missing split handoff path" -} - -foreach ($feature in @("providerAdvertisements", "commandTransport", "providerSurfaceSession", "providerSurfaceSource", "providerSurfaceDocumentSource", "liveProviderTransportBridge", "livePlayableWorldClient", "providerCommandReceipts", "providerAssetManifestDocumentSource", "playableWorldClientHost", "playableWorldClientBootstrap", "playableWorldInputDriver", "playableWorldCameraRig", "sceneGraphProjection", "playableWorldProjection", "playableWorldRuntimeHost", "playableWorldScenePresentation", "unityGameObjectSceneSink", "providerAssetManifestResolution", "providerAssetManifestSource", "embeddedDocuments")) { - if (-not (@($manifest.supportedFeatures) -contains $feature)) { - throw "EveUnity scene manifest missing provider-shell feature: $feature" - } -} -if (@($manifest.supportedPlugins).Count -ne 3) { - throw "EveUnity scene must claim exactly three plugin projection adapters" -} -$saiProjection = @($manifest.supportedPlugins) | Where-Object { $_.pluginId -eq "sai.vn" } | Select-Object -First 1 -if (-not $saiProjection) { - throw "EveUnity scene manifest missing supported Sai projection adapter" -} -if ($saiProjection.projectionAdapter -ne "SaiVisualNovelUnitySceneProjectionAdapter") { - throw "Unexpected EveUnity scene Sai projection adapter: $($saiProjection.projectionAdapter)" -} -foreach ($capability in @("vn.stage", "story.choose", "story.continue", "story.jump")) { - if (-not (@($saiProjection.capabilities) -contains $capability)) { - throw "EveUnity scene Sai projection adapter must claim $capability" - } -} -$nornProjection = @($manifest.supportedPlugins) | Where-Object { $_.pluginId -eq "norn.graph" } | Select-Object -First 1 -if (-not $nornProjection) { - throw "EveUnity scene manifest missing supported Norn projection adapter" -} -if ($nornProjection.projectionAdapter -ne "NornGraphUnitySceneProjectionAdapter") { - throw "Unexpected EveUnity scene Norn projection adapter: $($nornProjection.projectionAdapter)" -} -if (-not (@($nornProjection.capabilities) -contains "embed.norn")) { - throw "EveUnity scene Norn projection adapter must claim embed.norn" -} -$texProjection = @($manifest.supportedPlugins) | Where-Object { $_.pluginId -eq "tex.math" } | Select-Object -First 1 -if (-not $texProjection) { - throw "EveUnity scene manifest missing supported TeX projection adapter" -} -if ($texProjection.projectionAdapter -ne "TeXMathUnitySceneProjectionAdapter") { - throw "Unexpected EveUnity scene TeX projection adapter: $($texProjection.projectionAdapter)" -} -foreach ($capability in @("embed.tex", "tex.inline", "tex.block", "tex.scene-placement")) { - if (-not (@($texProjection.capabilities) -contains $capability)) { - throw "EveUnity scene TeX projection adapter must claim $capability" - } -} -$worldSurfaceLoweringClaims = @() -if ($null -ne $manifest.worldSurfaceLowering) { - $worldSurfaceLoweringClaims = @($manifest.worldSurfaceLowering) -} -if ($worldSurfaceLoweringClaims.Count -ne 1) { - throw "EveUnity scene must claim exactly one world-surface lowering target" -} -$worldSurfaceLoweringClaim = $worldSurfaceLoweringClaims | Where-Object { $_.targetId -eq "unity-scene" } | Select-Object -First 1 -if (-not $worldSurfaceLoweringClaim) { - throw "EveUnity scene manifest missing unity-scene world-surface lowering claim" -} -if ($worldSurfaceLoweringClaim.supportLevel -ne "unity-playable-world-scene-command-surface") { - throw "Unexpected EveUnity scene world-surface support level: $($worldSurfaceLoweringClaim.supportLevel)" -} -if ($worldSurfaceLoweringClaim.ownership -ne "runtime-lowers-provider-world-surface-without-owning-world-state") { - throw "Unexpected EveUnity scene world-surface ownership: $($worldSurfaceLoweringClaim.ownership)" -} -foreach ($evidencePath in @($worldSurfaceLoweringClaim.evidencePaths)) { - $absoluteEvidencePath = Join-Path $projectRoot $evidencePath - if (-not (Test-Path -LiteralPath $absoluteEvidencePath)) { - throw "EveUnity scene world-surface claim missing evidence path: $evidencePath" - } -} - -if (@($manifest.unsupportedPlugins) | Where-Object { $_.pluginId -eq "sai.vn" } | Select-Object -First 1) { - throw "EveUnity scene must not report sai.vn unsupported while the projection adapter is declared" -} -if (@($manifest.unsupportedPlugins) | Where-Object { $_.pluginId -eq "norn.graph" } | Select-Object -First 1) { - throw "EveUnity scene must not report norn.graph unsupported while the projection adapter is declared" -} -if (@($manifest.unsupportedPlugins) | Where-Object { $_.pluginId -eq "tex.math" } | Select-Object -First 1) { - throw "EveUnity scene must not report tex.math unsupported while the projection adapter is declared" -} - -if ($manifest.commandTransport.schema -ne "gamecult.eve.command.v1") { - throw "Unexpected EveUnity scene command schema: $($manifest.commandTransport.schema)" -} -if ($manifest.commandTransport.status -ne "provider-shell-contract-skeleton") { - throw "Unexpected EveUnity scene command transport status: $($manifest.commandTransport.status)" -} - -foreach ($stage in @("release", "test", "capture")) { - $stageDocument = $manifest.lifecycle.$stage - if ($null -eq $stageDocument) { - throw "EveUnity scene lifecycle missing stage: $stage" - } - if ($stageDocument.ownerRepo -ne "EveUnity") { - throw "EveUnity scene lifecycle stage $stage has unexpected owner: $($stageDocument.ownerRepo)" - } - if (-not $stageDocument.status) { - throw "EveUnity scene lifecycle stage $stage missing status" - } - foreach ($evidencePath in @($stageDocument.evidencePaths)) { - $absoluteEvidencePath = Join-Path $projectRoot $evidencePath - if (-not (Test-Path -LiteralPath $absoluteEvidencePath)) { - throw "EveUnity scene lifecycle stage $stage missing evidence path: $evidencePath" - } - } -} - -$releaseContract = $manifest.lifecycle.release.releaseContract -foreach ($field in @("ownerRepo", "packageName", "packageRoot", "versionSource", "tagPattern", "artifactKind", "requestSchema", "requestBuilder", "artifactBuilder", "artifactPattern", "publishProof")) { - if (-not $releaseContract.$field) { - throw "EveUnity scene release contract missing $field" - } -} -if ($releaseContract.requestSchema -ne "gamecult.eve.runtime_release_request.v1") { - throw "EveUnity scene release contract has unexpected request schema: $($releaseContract.requestSchema)" -} -foreach ($pathProperty in @("packageRoot", "versionSource")) { - $relativePath = $releaseContract.$pathProperty - $absolutePath = Join-Path $projectRoot $relativePath - if (-not (Test-Path -LiteralPath $absolutePath)) { - throw "EveUnity scene release contract $pathProperty does not exist: $relativePath" - } -} -foreach ($pathProperty in @("requestBuilder", "artifactBuilder")) { - $relativePath = $releaseContract.$pathProperty - $absolutePath = Join-Path $projectRoot $relativePath - if (-not (Test-Path -LiteralPath $absolutePath)) { - throw "EveUnity scene release contract $pathProperty does not exist: $relativePath" - } -} -$packageManifest = Get-Content -LiteralPath (Join-Path $projectRoot $releaseContract.versionSource) -Raw | ConvertFrom-Json -$surfaceDependency = @($releaseContract.requiredPackageDependencies) | Where-Object { $_.packageName -eq "org.gamecult.eve.surface" } | Select-Object -First 1 -if (-not $surfaceDependency) { - throw "EveUnity scene release contract missing required org.gamecult.eve.surface dependency contract" -} -if ($surfaceDependency.ownerRepo -ne "Eve" -or $surfaceDependency.packageManager -ne "upm") { - throw "EveUnity scene release contract has unexpected surface dependency owner/package manager: $($surfaceDependency.ownerRepo)/$($surfaceDependency.packageManager)" -} -if ($surfaceDependency.version -ne $packageManifest.dependencies."org.gamecult.eve.surface") { - throw "EveUnity scene release contract surface dependency version mismatch: $($surfaceDependency.version)" -} - -$testContract = $manifest.lifecycle.test.testContract -foreach ($field in @("ownerRepo", "runnerKind", "runnerScript", "consumerProject", "packageName", "testAssembly", "testPlatform", "resultsArtifact", "logArtifact", "manifestMutation")) { - if (-not $testContract.$field) { - throw "EveUnity scene test contract missing $field" - } -} -if ($testContract.runnerKind -ne "unity-editmode-batchmode") { - throw "EveUnity scene test contract has unexpected runner kind: $($testContract.runnerKind)" -} -if ($testContract.packageName -ne "org.gamecult.eve.unity-scene") { - throw "EveUnity scene test contract has unexpected package name: $($testContract.packageName)" -} -if ($testContract.testAssembly -ne "GameCult.Eve.UnityScene.Tests") { - throw "EveUnity scene test contract has unexpected test assembly: $($testContract.testAssembly)" -} -if ($testContract.testPlatform -ne "EditMode") { - throw "EveUnity scene test contract has unexpected test platform: $($testContract.testPlatform)" -} -foreach ($pathProperty in @("runnerScript", "consumerProject")) { - $candidate = $testContract.$pathProperty - $absolutePath = if ([System.IO.Path]::IsPathRooted($candidate)) { - $candidate - } else { - Join-Path $projectRoot $candidate - } - if (-not (Test-Path -LiteralPath $absolutePath)) { - throw "EveUnity scene test contract $pathProperty does not exist: $candidate" - } -} -$runnerSource = Get-Content -LiteralPath (Join-Path $projectRoot $testContract.runnerScript) -Raw -foreach ($expectedText in @($testContract.packageName, $testContract.testAssembly, "run-aetheria-unity-editmode-tests.ps1")) { - if (-not $runnerSource.Contains($expectedText)) { - throw "EveUnity scene test runner script missing expected text: $expectedText" - } -} - -$captureContract = $manifest.lifecycle.capture.captureContract -foreach ($field in @("ownerRepo", "runtimeId", "targetId", "requestSchema", "requestBuilder", "advertisementPath", "captureKind", "artifactKind", "artifactPattern", "conformanceAttachment", "requiredProvider", "requiredSurface", "authority", "publishProof")) { - if (-not $captureContract.$field) { - throw "EveUnity scene capture contract missing $field" - } -} -if ($captureContract.runtimeId -ne "unity-scene") { - throw "EveUnity scene capture contract has unexpected runtime: $($captureContract.runtimeId)" -} -if ($captureContract.targetId -ne "unity-scene") { - throw "EveUnity scene capture contract has unexpected target: $($captureContract.targetId)" -} -if ($captureContract.requestSchema -ne "gamecult.eve.runtime_capture_request.v1") { - throw "EveUnity scene capture contract has unexpected request schema: $($captureContract.requestSchema)" -} -if ($captureContract.captureKind -ne "unity-scene-frame-png") { - throw "EveUnity scene capture contract has unexpected capture kind: $($captureContract.captureKind)" -} -foreach ($pathProperty in @("requestBuilder", "advertisementPath")) { - $relativePath = $captureContract.$pathProperty - $absolutePath = Join-Path $projectRoot $relativePath - if (-not (Test-Path -LiteralPath $absolutePath)) { - throw "EveUnity scene capture contract $pathProperty does not exist: $relativePath" - } -} - -& (Join-Path $projectRoot "scripts\run-eveunity-scene-split-handoff-smoke.ps1") -& (Join-Path $projectRoot "scripts\run-eveunity-scene-provider-shell-smoke.ps1") -& (Join-Path $projectRoot "scripts\run-eveunity-scene-release-contract-smoke.ps1") -& (Join-Path $projectRoot "scripts\run-eveunity-scene-release-artifact-smoke.ps1") -& (Join-Path $projectRoot "scripts\run-eveunity-scene-capture-contract-smoke.ps1") -& (Join-Path $projectRoot "scripts\run-eveunity-scene-capture-smoke.ps1") - -if ($RunUnityEditMode) { - & (Join-Path $projectRoot "scripts\run-aetheria-unity-scene-editmode-tests.ps1") - if ($LASTEXITCODE -ne 0) { - throw "Aetheria Unity scene EditMode smoke failed with exit code $LASTEXITCODE" - } -} - -Write-Host "EveUnity scene lifecycle smoke passed: $absoluteManifestPath" diff --git a/scripts/run-eveunity-scene-provider-shell-smoke.ps1 b/scripts/run-eveunity-scene-provider-shell-smoke.ps1 deleted file mode 100644 index a81d034..0000000 --- a/scripts/run-eveunity-scene-provider-shell-smoke.ps1 +++ /dev/null @@ -1,238 +0,0 @@ -param( - [string] $CapabilityManifestPath = "runtimes\incubating\eve-unity-scene\eve-runtime-capability.json" -) - -$ErrorActionPreference = "Stop" - -$projectRoot = Split-Path -Parent $PSScriptRoot -$absoluteManifestPath = if ([System.IO.Path]::IsPathRooted($CapabilityManifestPath)) { - $CapabilityManifestPath -} else { - Join-Path $projectRoot $CapabilityManifestPath -} - -if (-not (Test-Path -LiteralPath $absoluteManifestPath)) { - throw "EveUnity scene runtime capability manifest not found: $absoluteManifestPath" -} - -$manifest = Get-Content -LiteralPath $absoluteManifestPath -Raw | ConvertFrom-Json - -if ($manifest.runtimeId -ne "unity-scene") { - throw "Unexpected EveUnity scene runtime id: $($manifest.runtimeId)" -} -if ($manifest.lifecycle.test.status -ne "unity-scene-editmode-batchmode") { - throw "Unexpected EveUnity scene provider shell status: $($manifest.lifecycle.test.status)" -} - -$worldSurfaceLoweringClaims = @() -if ($null -ne $manifest.worldSurfaceLowering) { - $worldSurfaceLoweringClaims = @($manifest.worldSurfaceLowering) -} -if ($worldSurfaceLoweringClaims.Count -ne 1) { - throw "EveUnity scene must claim exactly one provider world-surface lowering target" -} -$worldSurfaceLoweringClaim = $worldSurfaceLoweringClaims | Where-Object { $_.targetId -eq "unity-scene" } | Select-Object -First 1 -if (-not $worldSurfaceLoweringClaim) { - throw "EveUnity scene missing unity-scene world-surface lowering claim" -} -if (-not (@($worldSurfaceLoweringClaim.surfaceKinds) -contains "interactive-world")) { - throw "EveUnity scene world-surface claim must support interactive-world surfaces" -} -if (-not (@($worldSurfaceLoweringClaim.projectionKinds) -contains "provider-authored-world-surface")) { - throw "EveUnity scene world-surface claim must support provider-authored-world-surface projections" -} -if ($worldSurfaceLoweringClaim.supportLevel -ne "unity-playable-world-scene-command-surface") { - throw "Unexpected EveUnity scene support level: $($worldSurfaceLoweringClaim.supportLevel)" -} -if ($worldSurfaceLoweringClaim.ownership -ne "runtime-lowers-provider-world-surface-without-owning-world-state") { - throw "Unexpected EveUnity scene ownership: $($worldSurfaceLoweringClaim.ownership)" -} -foreach ($evidencePath in @($worldSurfaceLoweringClaim.evidencePaths)) { - $absoluteEvidencePath = Join-Path $projectRoot $evidencePath - if (-not (Test-Path -LiteralPath $absoluteEvidencePath)) { - throw "EveUnity scene world-surface claim missing evidence path: $evidencePath" - } -} - -foreach ($feature in @("providerAdvertisements", "commandTransport", "providerSurfaceSession", "providerSurfaceSource", "providerSurfaceDocumentSource", "liveProviderTransportBridge", "livePlayableWorldClient", "providerCommandReceipts", "providerAssetManifestDocumentSource", "playableWorldClientHost", "playableWorldClientBootstrap", "playableWorldInputDriver", "playableWorldCameraRig", "sceneGraphProjection", "playableWorldProjection", "playableWorldRuntimeHost", "playableWorldScenePresentation", "unityGameObjectSceneSink", "providerAssetManifestResolution", "providerAssetManifestSource")) { - if (-not (@($manifest.supportedFeatures) -contains $feature)) { - throw "EveUnity scene provider shell missing supported feature: $feature" - } -} - -$expectedFiles = @( - "runtimes\incubating\eve-unity-scene\package.json", - "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\EveUnitySceneLiveProviderBridge.cs", - "runtimes\incubating\eve-unity-scene\Runtime\EveUnityPlayableWorldLiveClient.cs", - "runtimes\incubating\eve-unity-scene\Runtime\EveUnityPlayableWorldRuntime.cs", - "runtimes\incubating\eve-unity-scene\Runtime\EveUnityPlayableWorldClientHost.cs", - "runtimes\incubating\eve-unity-scene\Runtime\EveUnityPlayableWorldClientBootstrap.cs", - "runtimes\incubating\eve-unity-scene\Runtime\EveUnityPlayableWorldInputDriver.cs", - "runtimes\incubating\eve-unity-scene\Runtime\EveUnityPlayableWorldCameraRig.cs", - "runtimes\incubating\eve-unity-scene\Runtime\EveUnityProviderRefreshSource.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", - "runtimes\incubating\eve-unity-scene\Tests\Editor\GameCult.Eve.UnityScene.Tests.asmdef", - "runtimes\incubating\eve-unity-scene\Tests\Editor\EveUnitySceneSurfaceLowererTests.cs" -) - -foreach ($relativePath in $expectedFiles) { - $absolutePath = Join-Path $projectRoot $relativePath - if (-not (Test-Path -LiteralPath $absolutePath)) { - throw "EveUnity scene provider shell missing file: $relativePath" - } -} - -$lowererSource = Get-Content -LiteralPath (Join-Path $projectRoot "runtimes\incubating\eve-unity-scene\Runtime\EveUnitySceneSurfaceLowerer.cs") -Raw -foreach ($symbol in @("EveUnitySceneSurfaceLowerer", "EveUnitySceneProviderSurfaceAdvertisement", "WorldInteraction", "CommandBoundary", "ReceiptSchema", "EveSurfaceCommandRequest", "BuildSceneGraph", "BuildPlayableWorld", "EveUnityPlayableWorldProjection", "EveUnityPlayableWorldEntity", "BuildPluginProjection", "SaiVisualNovelUnitySceneProjectionAdapter", "TeXMathUnitySceneProjectionAdapter", "EveUnityScenePluginProjection", "EveUnitySceneNode", "SceneObjectKind", "playable-world-root", "unity-scene")) { - if (-not $lowererSource.Contains($symbol)) { - throw "EveUnity scene provider shell lowerer missing symbol: $symbol" - } -} - -$clientSessionSource = Get-Content -LiteralPath (Join-Path $projectRoot "runtimes\incubating\eve-unity-scene\Runtime\EveUnitySceneClientSession.cs") -Raw -foreach ($symbol in @("EveUnitySceneClientSession", "EveUnitySceneProviderSurfaceSnapshot", "ActiveVersion", "Connect", "ApplySnapshot", "CreateMoveIntent", "CreateMoveVectorIntent", "CreateFocusIntent", "CreateTargetIntent", "CreateActionIntent", "CreatePlayableWorldIntent", "commandId", "targetPosition", "directionX", "directionY", "scalarValue", "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", "IEveUnitySceneProviderSurfaceDocumentSource", "IEveUnitySceneProviderSurfaceDocumentConnection", "IEveUnityProviderRefreshSource", "EveUnitySceneProviderSurfaceDocument", "EveUnitySceneProviderSurfaceDocumentSource", "ToSnapshot", "DocumentAvailable", "EveUnitySceneProviderConnection", "SnapshotAvailable", "CurrentSnapshot", "Connect", "Refresh", "_refreshSource?.Refresh();", "SubmitMoveIntent", "SubmitMoveVectorIntent", "SubmitFocusIntent", "SubmitTargetIntent", "SubmitActionIntent", "Disconnect", "HasAppliedCurrentSnapshot")) { - if (-not $providerConnectionSource.Contains($symbol)) { - throw "EveUnity scene provider connection missing symbol: $symbol" - } -} - -$liveProviderBridgeSource = Get-Content -LiteralPath (Join-Path $projectRoot "runtimes\incubating\eve-unity-scene\Runtime\EveUnitySceneLiveProviderBridge.cs") -Raw -foreach ($symbol in @("IEveUnitySceneLiveProviderTransport", "EveUnitySceneLiveProviderTransportBehaviour", "EveUnitySceneLiveProviderBridgeComponent", "EveUnitySceneLiveProviderBridge", "IEveUnitySceneProviderSurfaceDocumentSource", "IEveUnitySceneProviderSurfaceDocumentConnection", "IEveUnityPlayableWorldAssetManifestDocumentSource", "IEveUnitySceneCommandSink", "IEveUnitySceneCommandReceiptSource", "IEveUnityProviderRefreshSource", "SubmitCommand", "CommandReceiptAvailable", "ReceiptAvailable?.Invoke(receipt);", "transportBehaviour")) { - if (-not $liveProviderBridgeSource.Contains($symbol)) { - throw "EveUnity scene live provider bridge missing symbol: $symbol" - } -} -if ($liveProviderBridgeSource.Contains("Aetheria")) { - throw "EveUnity scene live provider bridge must remain provider-agnostic and cannot reference Aetheria" -} -if ($liveProviderBridgeSource.Contains("if (receipt.ShouldRefreshProviderSurface)")) { - throw "EveUnity scene live provider bridge must forward receipts; playable-world live client owns refresh policy" -} - -$liveClientSource = Get-Content -LiteralPath (Join-Path $projectRoot "runtimes\incubating\eve-unity-scene\Runtime\EveUnityPlayableWorldLiveClient.cs") -Raw -foreach ($symbol in @("EveUnityPlayableWorldLiveClient", "IEveUnitySceneCommandReceiptSource", "EveUnitySceneCommandReceipt", "EveUnitySceneProviderConnection", "EveUnityPlayableWorldPresenter", "ActiveWorld", "LastPresentation", "LastReceipt", "ReceiptAvailable", "Connect", "Refresh", "SubmitMoveIntent", "SubmitMoveVectorIntent", "SubmitFocusIntent", "SubmitTargetIntent", "SubmitActionIntent", "ProjectionUpdated", "ShouldRefreshProviderSurface", "IsProviderOwned", "Disconnect")) { - if (-not $liveClientSource.Contains($symbol)) { - throw "EveUnity playable world live client missing symbol: $symbol" - } -} - -$runtimeHostSource = Get-Content -LiteralPath (Join-Path $projectRoot "runtimes\incubating\eve-unity-scene\Runtime\EveUnityPlayableWorldRuntime.cs") -Raw -foreach ($symbol in @("EveUnityPlayableWorldRuntime", "CreateForGameObjectScene", "EveUnityLivePlayableWorldAssetProvider", "IEveUnitySceneProviderSurfaceDocumentSource", "IEveUnitySceneCommandSink", "IEveUnityPlayableWorldAssetManifestDocumentSource", "IEveUnitySceneCommandReceiptSource", "EveUnityPlayableWorldAssetManifestCache", "AssetManifests", "ActiveWorld", "SubmitMoveIntent", "SubmitMoveVectorIntent", "SubmitFocusIntent", "SubmitTargetIntent", "SubmitActionIntent", "Connect", "Refresh", "Disconnect")) { - if (-not $runtimeHostSource.Contains($symbol)) { - throw "EveUnity playable world runtime host missing symbol: $symbol" - } -} - -$clientHostSource = Get-Content -LiteralPath (Join-Path $projectRoot "runtimes\incubating\eve-unity-scene\Runtime\EveUnityPlayableWorldClientHost.cs") -Raw -foreach ($symbol in @("EveUnityPlayableWorldClientHost", "MonoBehaviour", "providerSurfaceDocuments", "IEveUnitySceneProviderSurfaceDocumentSource", "IEveUnitySceneCommandSink", "IEveUnityPlayableWorldAssetManifestDocumentSource", "IEveUnitySceneCommandReceiptSource", "IEveUnityGameObjectAssetProvider", "IEveUnityProviderRefreshSource", "Configure", "CreateForGameObjectScene", "Connect", "Refresh", "SceneRoot", "SubmitMoveIntent", "SubmitMoveVectorIntent", "SubmitFocusIntent", "SubmitTargetIntent", "SubmitActionIntent", "Disconnect")) { - if (-not $clientHostSource.Contains($symbol)) { - throw "EveUnity playable world client host missing symbol: $symbol" - } -} -if ($clientHostSource.Contains("Aetheria")) { - throw "EveUnity playable world client host must remain provider-agnostic and cannot reference Aetheria" -} - -$clientBootstrapSource = Get-Content -LiteralPath (Join-Path $projectRoot "runtimes\incubating\eve-unity-scene\Runtime\EveUnityPlayableWorldClientBootstrap.cs") -Raw -foreach ($symbol in @("EveUnityPlayableWorldClientBootstrap", "ConfigureProvider", "Mount", "ResolveHost", "ResolveSceneRoot", "ResolveCameraTransform", "EveUnityPlayableWorldClientHost", "EveUnityPlayableWorldInputDriver", "EveUnityPlayableWorldCameraRig", "IEveUnitySceneProviderSurfaceDocumentSource", "IEveUnitySceneCommandSink", "IEveUnityPlayableWorldAssetManifestDocumentSource", "IEveUnitySceneCommandReceiptSource", "IEveUnityGameObjectAssetProvider")) { - if (-not $clientBootstrapSource.Contains($symbol)) { - throw "EveUnity playable world client bootstrap missing symbol: $symbol" - } -} -if ($clientBootstrapSource.Contains("Aetheria")) { - throw "EveUnity playable world client bootstrap must remain provider-agnostic and cannot reference Aetheria" -} - -$refreshSource = Get-Content -LiteralPath (Join-Path $projectRoot "runtimes\incubating\eve-unity-scene\Runtime\EveUnityProviderRefreshSource.cs") -Raw -foreach ($symbol in @("IEveUnityProviderRefreshSource", "Refresh")) { - if (-not $refreshSource.Contains($symbol)) { - throw "EveUnity provider refresh source missing symbol: $symbol" - } -} - -$inputDriverSource = Get-Content -LiteralPath (Join-Path $projectRoot "runtimes\incubating\eve-unity-scene\Runtime\EveUnityPlayableWorldInputDriver.cs") -Raw -foreach ($symbol in @("EveUnityPlayableWorldInputDriver", "EveUnityPlayableWorldMoveVector", "FromCameraRelativeInput", "SubmitMoveVectorInput", "SubmitPrimaryAction", "Input.GetAxisRaw", "Input.GetButtonDown", "directionX", "directionY", "scalarValue", "SubmitMoveVectorIntent")) { - if (-not $inputDriverSource.Contains($symbol)) { - throw "EveUnity playable world input driver missing symbol: $symbol" - } -} -if ($inputDriverSource.Contains("Aetheria")) { - throw "EveUnity playable world input driver must remain provider-agnostic and cannot reference Aetheria" -} - -$cameraRigSource = Get-Content -LiteralPath (Join-Path $projectRoot "runtimes\incubating\eve-unity-scene\Runtime\EveUnityPlayableWorldCameraRig.cs") -Raw -foreach ($symbol in @("EveUnityPlayableWorldCameraRig", "ApplyRig", "arpg.orbital-follow.v1", "EveUnityPlayableWorldEntityMarker", "SceneRoot", "LookAt")) { - if (-not $cameraRigSource.Contains($symbol)) { - throw "EveUnity playable world camera rig missing symbol: $symbol" - } -} -if ($cameraRigSource.Contains("Aetheria")) { - throw "EveUnity playable world camera rig must remain provider-agnostic and cannot reference Aetheria" -} - -$playableWorldPresenterSource = Get-Content -LiteralPath (Join-Path $projectRoot "runtimes\incubating\eve-unity-scene\Runtime\EveUnityPlayableWorldPresenter.cs") -Raw -foreach ($symbol in @("IEveUnityPlayableWorldSceneSink", "IEveUnityPlayableWorldAssetResolver", "EveUnityPlayableWorldPresenter", "EveUnityPlayableWorldAssetBinding", "EveUnityPlayableWorldPresentation", "EveUnityAssetRefResolver", "ConfigureWorld", "UpsertEntity", "RemoveEntity", "provider-asset-ref", "unity-generated-placeholder")) { - if (-not $playableWorldPresenterSource.Contains($symbol)) { - throw "EveUnity playable world presenter missing symbol: $symbol" - } -} - -$gameObjectSceneSinkSource = Get-Content -LiteralPath (Join-Path $projectRoot "runtimes\incubating\eve-unity-scene\Runtime\EveUnityGameObjectPlayableWorldSceneSink.cs") -Raw -foreach ($symbol in @("EveUnityGameObjectPlayableWorldSceneSink", "IEveUnityGameObjectAssetProvider", "EveUnityResourcesAssetProvider", "EveUnityPlayableWorldEntityMarker", "GameObject", "Transform", "Resources.Load", "PrimitiveType.Capsule", "DestroyImmediate", "localPosition", "localRotation")) { - if (-not $gameObjectSceneSinkSource.Contains($symbol)) { - throw "EveUnity GameObject playable world scene sink missing symbol: $symbol" - } -} - -$assetManifestSource = Get-Content -LiteralPath (Join-Path $projectRoot "runtimes\incubating\eve-unity-scene\Runtime\EveUnityPlayableWorldAssetManifest.cs") -Raw -foreach ($symbol in @("EveUnityPlayableWorldAssetManifest", "IEveUnityPlayableWorldAssetManifestSource", "IEveUnityPlayableWorldAssetManifestDocumentSource", "EveUnityPlayableWorldAssetManifestDocumentSource", "EveUnityPlayableWorldAssetManifestDocument", "EveUnityPlayableWorldAssetManifestDocumentEntry", "FromDocument", "DocumentAvailable", "gamecult.eve.unity_playable_world_asset_manifest.v1", "EveUnityPlayableWorldAssetManifestCache", "EveUnityPlayableWorldAssetManifestEntry", "EveUnityManifestGameObjectAssetProvider", "ManifestAvailable", "GetForWorld", "CreateGameObjectAssetProvider", "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)) { - throw "EveUnity scene Sai projection adapter missing symbol: $symbol" - } -} - -$nornAdapterSource = Get-Content -LiteralPath (Join-Path $projectRoot "runtimes\incubating\eve-unity-scene\Runtime\NornGraphUnitySceneProjectionAdapter.cs") -Raw -foreach ($symbol in @("NornGraphUnitySceneProjectionAdapter", "norn.graph", "embed.norn", "gamecult.eve.plugin_abi.v1", "sidecar-advertised-plugin-abi", "Norn")) { - if (-not $nornAdapterSource.Contains($symbol)) { - throw "EveUnity scene Norn projection adapter missing symbol: $symbol" - } -} - -$texAdapterSource = Get-Content -LiteralPath (Join-Path $projectRoot "runtimes\incubating\eve-unity-scene\Runtime\TeXMathUnitySceneProjectionAdapter.cs") -Raw -foreach ($symbol in @("TeXMathUnitySceneProjectionAdapter", "tex.math", "embed.tex", "tex.scene-placement", "gamecult.eve.plugin_abi.v1", "sidecar-advertised-plugin-abi", "EvePlugins")) { - if (-not $texAdapterSource.Contains($symbol)) { - throw "EveUnity scene TeX projection adapter missing symbol: $symbol" - } -} - -$testSource = Get-Content -LiteralPath (Join-Path $projectRoot "runtimes\incubating\eve-unity-scene\Tests\Editor\EveUnitySceneSurfaceLowererTests.cs") -Raw -foreach ($symbol in @("LowerCarriesProviderAdvertisedWorldBoundary", "LowerBuildsProviderAgnosticSceneGraphFromSurfaceTree", "LowerExtractsPlayableArpgWorldFromGenericScene3dSurface", "GenericClientSessionConsumesAetheriaPlayableWorldSnapshotWithoutAetheriaTypes", "GenericProviderConnectionAppliesLiveSnapshotsAndSubmitsCommandsThroughSink", "ProviderSurfaceDocumentSourceFeedsPlayableClientWithoutAetheriaTypes", "PlayableWorldRuntimeComposesProviderDocumentsAssetsReceiptsAndSceneSink", "LiveProviderBridgeFeedsPlayableWorldRuntimeThroughTransportPorts", "PlayableWorldClientHostMountsInterfaceProviderWithoutProviderTypes", "PlayableWorldClientBootstrapWiresGenericUnityClientFromProviderInterfaces", "PlayableWorldClientHostSubmitsProviderOwnedMoveVector", "PlayableWorldInputDriverBuildsCameraRelativeMoveVectorWithoutProviderTypes", "PlayableWorldCameraRigFollowsAdvertisedPlayerEntityWithoutProviderTypes", "PlayableWorldPresenterInstantiatesUpdatesAndDespawnsProviderEntities", "LivePlayableWorldClientPresentsProviderSnapshotsAndKeepsCommandsProviderOwned", "LivePlayableWorldClientRefreshesFromProviderSnapshotAfterReceiptWithoutOwningMovement", "AssetManifestMapsProviderAssetRefsToUnityLoadKeysWithoutAetheriaTypes", "AssetManifestCacheTracksPlayableWorldManifestPointerAndLiveUpdates", "AssetManifestDocumentSourceFeedsCacheWithoutChangingSceneLowering", "FakeProviderSurfaceSource", "FakeProviderSurfaceDocumentSource", "FakeCommandReceiptSource", "FakeAssetManifestSource", "FakeAssetManifestDocumentSource", "FakeLiveProviderTransport", "FakeCommandSink", "FakePlayableWorldSceneSink", "FakePlayableWorldProviderComponent", "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" - } -} - -Write-Host "EveUnity scene provider shell smoke passed: $absoluteManifestPath" diff --git a/scripts/run-eveunity-scene-release-artifact-smoke.ps1 b/scripts/run-eveunity-scene-release-artifact-smoke.ps1 deleted file mode 100644 index b76bee3..0000000 --- a/scripts/run-eveunity-scene-release-artifact-smoke.ps1 +++ /dev/null @@ -1,18 +0,0 @@ -param( - [string] $CapabilityManifestPath = "runtimes\incubating\eve-unity-scene\eve-runtime-capability.json", - [string] $RequestOutputPath = "artifacts\eveunity-scene-release-contract\latest\release-request.json", - [string] $ProofOutputPath = "artifacts\eveunity-scene-release\latest\release-artifact.json" -) - -$ErrorActionPreference = "Stop" - -$projectRoot = Split-Path -Parent $PSScriptRoot -& (Join-Path $projectRoot "scripts\run-eveunity-release-artifact-smoke.ps1") ` - -CapabilityManifestPath $CapabilityManifestPath ` - -RequestOutputPath $RequestOutputPath ` - -ProofOutputPath $ProofOutputPath ` - -ReleaseContractSmokePath "scripts\run-eveunity-scene-release-contract-smoke.ps1" - -if ($LASTEXITCODE -ne 0) { - throw "EveUnity scene release artifact smoke failed with exit code $LASTEXITCODE" -} diff --git a/scripts/run-eveunity-scene-release-contract-smoke.ps1 b/scripts/run-eveunity-scene-release-contract-smoke.ps1 deleted file mode 100644 index 38e7e0f..0000000 --- a/scripts/run-eveunity-scene-release-contract-smoke.ps1 +++ /dev/null @@ -1,109 +0,0 @@ -param( - [string] $CapabilityManifestPath = "runtimes\incubating\eve-unity-scene\eve-runtime-capability.json", - [string] $OutputPath = "artifacts\eveunity-scene-release-contract\latest\release-request.json" -) - -$ErrorActionPreference = "Stop" - -$projectRoot = Split-Path -Parent $PSScriptRoot -$absoluteCapabilityPath = if ([System.IO.Path]::IsPathRooted($CapabilityManifestPath)) { - $CapabilityManifestPath -} else { - Join-Path $projectRoot $CapabilityManifestPath -} -$absoluteOutputPath = if ([System.IO.Path]::IsPathRooted($OutputPath)) { - $OutputPath -} else { - Join-Path $projectRoot $OutputPath -} - -if (-not (Test-Path -LiteralPath $absoluteCapabilityPath)) { - throw "EveUnity scene release contract input not found: $absoluteCapabilityPath" -} - -$manifest = Get-Content -LiteralPath $absoluteCapabilityPath -Raw | ConvertFrom-Json -$releaseContract = $manifest.lifecycle.release.releaseContract -if ($null -eq $releaseContract) { - throw "EveUnity scene release contract missing lifecycle.release.releaseContract" -} -foreach ($field in @("ownerRepo", "packageName", "packageRoot", "versionSource", "tagPattern", "artifactKind", "requestSchema", "requestBuilder", "artifactBuilder", "artifactPattern", "publishProof")) { - if (-not $releaseContract.$field) { - throw "EveUnity scene release contract missing $field" - } -} -if ($releaseContract.ownerRepo -ne "EveUnity") { - throw "Unexpected EveUnity scene release owner: $($releaseContract.ownerRepo)" -} -if ($releaseContract.packageName -ne "org.gamecult.eve.unity-scene") { - throw "Unexpected EveUnity scene package name: $($releaseContract.packageName)" -} -if ($releaseContract.requestSchema -ne "gamecult.eve.runtime_release_request.v1") { - throw "Unexpected EveUnity scene release request schema: $($releaseContract.requestSchema)" -} -if ($releaseContract.artifactKind -ne "upm-package") { - throw "Unexpected EveUnity scene release artifact kind: $($releaseContract.artifactKind)" -} - -$builderPath = Join-Path $projectRoot $releaseContract.requestBuilder -$artifactBuilderPath = Join-Path $projectRoot $releaseContract.artifactBuilder -$packagePath = Join-Path $projectRoot $releaseContract.versionSource -$packageRoot = Join-Path $projectRoot $releaseContract.packageRoot -foreach ($path in @($builderPath, $artifactBuilderPath, $packagePath, $packageRoot)) { - if (-not (Test-Path -LiteralPath $path)) { - throw "EveUnity scene release contract path not found: $path" - } -} - -node --test (Join-Path $projectRoot "tools\eveunity\eveunity-release-contract.test.mjs") -if ($LASTEXITCODE -ne 0) { - throw "EveUnity release contract tests failed with exit code $LASTEXITCODE" -} - -node $builderPath --capability $absoluteCapabilityPath --package $packagePath --output $absoluteOutputPath -if ($LASTEXITCODE -ne 0) { - throw "EveUnity scene release request builder failed with exit code $LASTEXITCODE" -} -if (-not (Test-Path -LiteralPath $absoluteOutputPath)) { - throw "EveUnity scene release request was not written: $absoluteOutputPath" -} - -$request = Get-Content -LiteralPath $absoluteOutputPath -Raw | ConvertFrom-Json -$packageManifest = Get-Content -LiteralPath $packagePath -Raw | ConvertFrom-Json -foreach ($expectation in @( - @{ field = "schema"; value = "gamecult.eve.runtime_release_request.v1" }, - @{ field = "ownerRepo"; value = "EveUnity" }, - @{ field = "repository"; value = "GameCult/EveUnity" }, - @{ field = "packageName"; value = "org.gamecult.eve.unity-scene" }, - @{ field = "version"; value = $packageManifest.version }, - @{ field = "packageRoot"; value = "runtimes/incubating/eve-unity-scene" }, - @{ field = "versionSource"; value = "runtimes/incubating/eve-unity-scene/package.json" }, - @{ field = "artifactKind"; value = "upm-package" } -)) { - if ($request.($expectation.field) -ne $expectation.value) { - throw "EveUnity scene release request $($expectation.field) expected $($expectation.value) got $($request.($expectation.field))" - } -} - -$expectedTagName = $releaseContract.tagPattern.Replace("{version}", $packageManifest.version) -if ($request.tagName -ne $expectedTagName) { - throw "Unexpected EveUnity scene release tag: $($request.tagName)" -} -$expectedArtifactPath = $releaseContract.artifactPattern.Replace("{version}", $packageManifest.version) -if ($request.artifactPath -ne $expectedArtifactPath) { - throw "Unexpected EveUnity scene release artifact path: $($request.artifactPath)" -} -if ($request.dependencies."org.gamecult.eve.surface" -ne $packageManifest.dependencies."org.gamecult.eve.surface") { - throw "EveUnity scene release request lost org.gamecult.eve.surface dependency" -} -$surfaceDependency = @($request.requiredPackageDependencies) | Where-Object { $_.packageName -eq "org.gamecult.eve.surface" } | Select-Object -First 1 -if (-not $surfaceDependency) { - throw "EveUnity scene release request missing required org.gamecult.eve.surface dependency contract" -} -if ($surfaceDependency.ownerRepo -ne "Eve" -or $surfaceDependency.packageManager -ne "upm") { - throw "EveUnity scene release request has unexpected surface dependency owner/package manager: $($surfaceDependency.ownerRepo)/$($surfaceDependency.packageManager)" -} -if ($surfaceDependency.version -ne $packageManifest.dependencies."org.gamecult.eve.surface") { - throw "EveUnity scene release request surface dependency version mismatch: $($surfaceDependency.version)" -} - -Write-Host "EveUnity scene release contract smoke passed: $absoluteOutputPath" diff --git a/scripts/run-eveunity-scene-split-handoff-smoke.ps1 b/scripts/run-eveunity-scene-split-handoff-smoke.ps1 deleted file mode 100644 index db019d3..0000000 --- a/scripts/run-eveunity-scene-split-handoff-smoke.ps1 +++ /dev/null @@ -1,160 +0,0 @@ -param( - [string] $HandoffPath = "runtimes\incubating\eve-unity-scene\eveunity-scene-split-handoff.json" -) - -$ErrorActionPreference = "Stop" - -$projectRoot = Split-Path -Parent $PSScriptRoot -$absoluteHandoffPath = if ([System.IO.Path]::IsPathRooted($HandoffPath)) { - $HandoffPath -} else { - Join-Path $projectRoot $HandoffPath -} - -if (-not (Test-Path -LiteralPath $absoluteHandoffPath)) { - throw "EveUnity scene split handoff manifest not found: $absoluteHandoffPath" -} - -$handoff = Get-Content -LiteralPath $absoluteHandoffPath -Raw | ConvertFrom-Json - -if ($handoff.schema -ne "gamecult.eve.runtime_split_handoff.v1") { - throw "Unexpected EveUnity scene split handoff schema: $($handoff.schema)" -} -if ($handoff.splitTarget -ne "EveUnity") { - throw "Unexpected EveUnity scene split handoff target: $($handoff.splitTarget)" -} -if ($handoff.ownerRepo -ne "EveUnity") { - throw "Unexpected EveUnity scene split handoff owner: $($handoff.ownerRepo)" -} -if ($handoff.currentHostRepo -ne "Eve") { - throw "Unexpected EveUnity scene split handoff host: $($handoff.currentHostRepo)" -} -if ($handoff.runtimeId -ne "unity-scene") { - throw "Unexpected EveUnity scene split handoff runtime: $($handoff.runtimeId)" -} -if ($handoff.packageName -ne "org.gamecult.eve.unity-scene") { - throw "Unexpected EveUnity scene package name: $($handoff.packageName)" -} - -$sourcePackageRoot = Join-Path $projectRoot $handoff.sourcePackageRoot -if (-not (Test-Path -LiteralPath $sourcePackageRoot)) { - throw "EveUnity scene source package root missing: $($handoff.sourcePackageRoot)" -} - -$moveSets = @($handoff.moveSets) -$expectedMoveSets = @{ - "unity-scene-runtime-body" = "runtime-body" - "unity-scene-upm-package" = "release" - "unity-scene-world-surface-lowering" = "world-surface-lowering" - "unity-scene-sai-plugin-projection" = "plugin-projection" - "unity-scene-norn-plugin-projection" = "plugin-projection" - "unity-scene-tex-plugin-projection" = "plugin-projection" - "unity-scene-command-transport" = "command" - "aetheria-playable-world-consumer-proof" = "observed-provider-proof" - "unity-scene-capture-lifecycle" = "capture" -} - -foreach ($id in $expectedMoveSets.Keys) { - $moveSet = $moveSets | Where-Object { $_.id -eq $id } | Select-Object -First 1 - if (-not $moveSet) { - throw "EveUnity scene split handoff missing move set: $id" - } - if ($moveSet.stage -ne $expectedMoveSets[$id]) { - throw "EveUnity scene split handoff move set $id has unexpected stage: $($moveSet.stage)" - } - $expectedDestinationOwner = if ($id -eq "aetheria-playable-world-consumer-proof") { "Aetheria" } else { "EveUnity" } - if ($moveSet.destinationOwner -ne $expectedDestinationOwner) { - throw "EveUnity scene split handoff move set $id has unexpected destination owner: $($moveSet.destinationOwner)" - } - if (-not $moveSet.replacementProof) { - throw "EveUnity scene split handoff move set $id missing replacement proof" - } - $currentPaths = if ($null -eq $moveSet.currentPaths) { @() } else { @($moveSet.currentPaths) } - $observedProviderPaths = if ($null -eq $moveSet.observedProviderPaths) { @() } else { @($moveSet.observedProviderPaths) } - if ($id -in @("unity-scene-runtime-body", "unity-scene-upm-package", "unity-scene-world-surface-lowering", "unity-scene-sai-plugin-projection", "unity-scene-norn-plugin-projection", "unity-scene-tex-plugin-projection", "unity-scene-command-transport", "unity-scene-capture-lifecycle")) { - if ($currentPaths.Count -eq 0) { - throw "EveUnity scene split handoff move set $id must name current Eve incubation paths" - } - foreach ($relativePath in $currentPaths) { - $absolutePath = Join-Path $projectRoot $relativePath - if (-not (Test-Path -LiteralPath $absolutePath)) { - throw "EveUnity scene split handoff move set $id path missing: $relativePath" - } - } - } - if ($observedProviderPaths.Count -ne 0) { - if ($id -ne "aetheria-playable-world-consumer-proof") { - throw "EveUnity scene split handoff move set $id must not treat provider product paths as generic scene runtime source" - } - foreach ($providerPath in $observedProviderPaths) { - if (-not [System.IO.Path]::IsPathRooted($providerPath)) { - throw "Aetheria playable-world consumer proof path must be absolute: $providerPath" - } - if (-not (Test-Path -LiteralPath $providerPath)) { - throw "Aetheria playable-world consumer proof path is missing: $providerPath" - } - } - } -} - -$aetheriaConsumerProof = $moveSets | Where-Object { $_.id -eq "aetheria-playable-world-consumer-proof" } | Select-Object -First 1 -foreach ($requiredObservedPath in @( - "E:\Projects\Aetheria\Assets\Scripts\Tests\DaemonRuntimeDocumentTests.cs", - "E:\Projects\Aetheria\Packages\org.gamecult.aetheria.eve-runtime\Runtime\AetheriaEveUnitySceneProviderBridge.cs", - "E:\Projects\Aetheria\Packages\org.gamecult.aetheria.state\Runtime\AetheriaRuntimeDaemonGameSurfaceBuilder.cs", - "E:\Projects\Aetheria\Packages\org.gamecult.aetheria.state\Runtime\AetheriaRuntimeDaemonOperationsClient.cs" -)) { - if (-not (@($aetheriaConsumerProof.observedProviderPaths) -contains $requiredObservedPath)) { - throw "Aetheria playable-world consumer proof missing required observed provider path: $requiredObservedPath" - } -} - -foreach ($contract in @( - "gamecult.eve.surface.v1", - "gamecult.eve.command.v1", - "gamecult.eve.provider_advertisement.v1", - "gamecult.eve.runtime_capability.v1", - "gamecult.eve.conformance_export.v1" -)) { - if (-not (@($handoff.contractInputs) -contains $contract)) { - throw "EveUnity scene split handoff missing contract input: $contract" - } -} - -foreach ($forbiddenImport in @( - "Aetheria daemon state as Unity scene runtime authority", - "Aetheria gameplay scripts as EveUnity scene lowerer truth", - "provider-specific scene components that bypass gamecult.eve.command.v1", - "renderer-local world simulation as provider truth", - "product assets bundled as Eve runtime contract", - "Sai story state, VN/Ink semantics, or story command interpretation as Unity scene runtime authority", - "Norn graph layout, graph state, or command semantics as Unity scene runtime authority", - "TeX parsing, typesetting, baseline metrics, or render-cache semantics as Unity scene runtime authority" -)) { - if (-not (@($handoff.forbiddenImports) -contains $forbiddenImport)) { - throw "EveUnity scene split handoff missing forbidden import: $forbiddenImport" - } -} - -$saiProjectionMoveSet = $moveSets | Where-Object { $_.id -eq "unity-scene-sai-plugin-projection" } | Select-Object -First 1 -if (-not (@($saiProjectionMoveSet.currentPaths) -contains "runtimes/incubating/eve-unity-scene/Runtime/SaiVisualNovelUnitySceneProjectionAdapter.cs")) { - throw "EveUnity scene split handoff Sai projection move set must include the scene adapter path" -} - -$nornProjectionMoveSet = $moveSets | Where-Object { $_.id -eq "unity-scene-norn-plugin-projection" } | Select-Object -First 1 -if (-not (@($nornProjectionMoveSet.currentPaths) -contains "runtimes/incubating/eve-unity-scene/Runtime/NornGraphUnitySceneProjectionAdapter.cs")) { - throw "EveUnity scene split handoff Norn projection move set must include the scene adapter path" -} - -$texProjectionMoveSet = $moveSets | Where-Object { $_.id -eq "unity-scene-tex-plugin-projection" } | Select-Object -First 1 -if (-not (@($texProjectionMoveSet.currentPaths) -contains "runtimes/incubating/eve-unity-scene/Runtime/TeXMathUnitySceneProjectionAdapter.cs")) { - throw "EveUnity scene split handoff TeX projection move set must include the scene adapter path" -} - -foreach ($proof in @($handoff.requiredExternalProofs)) { - if (-not $proof) { - throw "EveUnity scene split handoff contains an empty required external proof" - } -} - -Write-Host "EveUnity scene split handoff smoke passed: $absoluteHandoffPath" diff --git a/scripts/run-parity-harness.ps1 b/scripts/run-parity-harness.ps1 index 964dd7a..a46900e 100644 --- a/scripts/run-parity-harness.ps1 +++ b/scripts/run-parity-harness.ps1 @@ -36,15 +36,6 @@ try { -ExpectedSurfaceId "eve.world-smoke.surface" ` -ExpectedCommandBoundary "eve.world-smoke.commands" ` -ExpectedReceiptSchema "eve.world_smoke.command_receipt.v1" - & (Join-Path $PSScriptRoot "run-eveunity-scene-capture-smoke.ps1") ` - -AdvertisementPath "web\fixtures\eve-world-smoke.provider-advertisement.json" ` - -SurfacePath "web\fixtures\eve-world-smoke-surface.json" ` - -OutputPath "artifacts\eveunity-scene-capture\latest\eve-world-smoke-unity-scene-projection.json" ` - -RequestOutputPath "artifacts\eveunity-scene-capture\latest\eve-world-smoke-capture-request.json" ` - -ExpectedProviderId "eve.world-smoke" ` - -ExpectedSurfaceId "eve.world-smoke.surface" ` - -ExpectedCommandBoundary "eve.world-smoke.commands" ` - -ExpectedReceiptSchema "eve.world_smoke.command_receipt.v1" & (Join-Path $PSScriptRoot "run-eveelectron-capture-smoke.ps1") ` -AdvertisementPath "web\fixtures\eve-world-smoke.provider-advertisement.json" ` -SurfacePath "web\fixtures\eve-world-smoke-surface.json" ` @@ -70,9 +61,6 @@ try { & (Join-Path $PSScriptRoot "run-aetheria-provider-handoff-smoke.ps1") & (Join-Path $PSScriptRoot "run-eveunity-split-handoff-smoke.ps1") & (Join-Path $PSScriptRoot "run-eveunity-release-artifact-smoke.ps1") - & (Join-Path $PSScriptRoot "run-eveunity-scene-split-handoff-smoke.ps1") - & (Join-Path $PSScriptRoot "run-eveunity-scene-release-artifact-smoke.ps1") - & (Join-Path $PSScriptRoot "run-eveunity-scene-lifecycle-smoke.ps1") & (Join-Path $PSScriptRoot "run-eveelectron-split-handoff-smoke.ps1") & (Join-Path $PSScriptRoot "run-eveelectron-lifecycle-smoke.ps1") & (Join-Path $PSScriptRoot "run-evetui-split-handoff-smoke.ps1") diff --git a/scripts/run-runtime-owner-conformance-consumer-smoke.ps1 b/scripts/run-runtime-owner-conformance-consumer-smoke.ps1 index abab980..c928377 100644 --- a/scripts/run-runtime-owner-conformance-consumer-smoke.ps1 +++ b/scripts/run-runtime-owner-conformance-consumer-smoke.ps1 @@ -56,7 +56,7 @@ node $consumerScript $consumerExport ` --expect-runtime-status linux-flutter:active ` --expect-runtime-status android-flutter:active ` --expect-runtime-status unity-uitoolkit:active ` - --expect-runtime-status unity-scene:pending ` + --expect-runtime-status unity-scene:active ` --expect-runtime-status electron-shell:pending ` --expect-runtime-status tui:active ` --expect-runtime-status direct2d:external-adapter-spike ` @@ -164,9 +164,7 @@ node $consumerScript $consumerExport ` --expect-runtime-capture-status unity-uitoolkit:json-projection ` --expect-runtime-capture-artifact unity-uitoolkit:json-projection:gamecult.eve.unity_uitoolkit_projection.v1:aetheria:aetheria.daemon.game ` --expect-runtime-capture-artifact unity-uitoolkit:json-projection:gamecult.eve.unity_uitoolkit_projection.v1:eve.world-smoke:eve.world-smoke.surface ` - --expect-runtime-capture-status unity-scene:json-projection ` - --expect-runtime-capture-artifact unity-scene:json-projection:gamecult.eve.unity_scene_projection.v1:aetheria:aetheria.daemon.game ` - --expect-runtime-capture-artifact unity-scene:json-projection:gamecult.eve.unity_scene_projection.v1:eve.world-smoke:eve.world-smoke.surface ` + --expect-runtime-capture-status unity-scene:pending-unity-frame-capture ` --expect-runtime-capture-status electron-shell:json-projection ` --expect-runtime-capture-artifact electron-shell:json-projection:gamecult.eve.electron_shell_projection.v1:aetheria:aetheria.daemon.game ` --expect-runtime-capture-artifact electron-shell:json-projection:gamecult.eve.electron_shell_projection.v1:eve.world-smoke:eve.world-smoke.surface ` @@ -175,7 +173,7 @@ node $consumerScript $consumerExport ` --expect-runtime-capture-artifact tui:json-grid:gamecult.eve.tui_grid.v1:eve.world-smoke:eve.world-smoke.surface ` --expect-runtime-capture-status direct2d:missing ` --expect-runtime-capture-probe unity-uitoolkit:semantic-artifact-present-capture-pending:png:EveUnity ` - --expect-runtime-capture-probe unity-scene:semantic-artifact-present-capture-pending:png:EveUnity ` + --expect-runtime-capture-probe unity-scene:contract-artifact-missing:png:EveUnity ` --expect-runtime-capture-probe electron-shell:semantic-artifact-present-capture-pending:png:EveElectron ` --expect-runtime-capture-probe tui:contract-artifact-present:json-grid:EveTui ` --expect-screenshot-metric web:embedded-surface:structure:pass ` @@ -236,32 +234,32 @@ node $consumerScript $consumerExport ` --expect-runtime-lifecycle-field "unity-uitoolkit:capture:captureContract.additionalProviderSurfaces.0.surfaceId:eve.world-smoke.surface" ` --expect-runtime-lifecycle-field "unity-uitoolkit:capture:captureContract.additionalProviderSurfaces.1.providerId:aetheria" ` --expect-runtime-lifecycle-field "unity-uitoolkit:capture:captureContract.additionalProviderSurfaces.1.surfaceId:aetheria.daemon.editor" ` - --expect-runtime-lifecycle-status unity-scene:release:unity-scene-upm-artifact-smoke ` + --expect-runtime-lifecycle-status unity-scene:release:owner-repo-upm-artifact ` --expect-runtime-lifecycle-status unity-scene:test:unity-scene-editmode-batchmode ` - --expect-runtime-lifecycle-status unity-scene:capture:pending-unity-scene-capture ` - --expect-runtime-lifecycle-pending "unity-scene:release:Unity scene package release" ` - --expect-runtime-lifecycle-pending "unity-scene:test:Unity scene EditMode runner" ` + --expect-runtime-lifecycle-status unity-scene:capture:pending-unity-frame-capture ` + --expect-runtime-lifecycle-pending "unity-scene:release:Cut and publish the first tagged EveUnity package release" ` + --expect-runtime-lifecycle-pending "unity-scene:test:Move the Aetheria consumer scenario into a provider-owned conformance pack" ` --expect-runtime-lifecycle-pending "unity-scene:capture:Unity scene screenshot or frame-capture PNG artifact" ` --expect-runtime-lifecycle-field "unity-scene:release:releaseContract.packageName:org.gamecult.eve.unity-scene" ` --expect-runtime-lifecycle-field "unity-scene:release:releaseContract.artifactKind:upm-package" ` --expect-runtime-lifecycle-field "unity-scene:release:releaseContract.tagPattern:eveunity-scene-v{version}" ` - --expect-runtime-lifecycle-field "unity-scene:release:releaseContract.versionSource:runtimes/incubating/eve-unity-scene/package.json" ` + --expect-runtime-lifecycle-field "unity-scene:release:releaseContract.versionSource:packages/org.gamecult.eve.unity-scene/package.json" ` --expect-runtime-lifecycle-field "unity-scene:release:releaseContract.requestSchema:gamecult.eve.runtime_release_request.v1" ` - --expect-runtime-lifecycle-field "unity-scene:release:releaseContract.requestBuilder:tools/eveunity/eveunity-release-contract.mjs" ` - --expect-runtime-lifecycle-field "unity-scene:release:releaseContract.artifactBuilder:tools/eveunity/eveunity-release-artifact.mjs" ` + --expect-runtime-lifecycle-field "unity-scene:release:releaseContract.requestBuilder:scripts/build-release-request.ps1" ` + --expect-runtime-lifecycle-field "unity-scene:release:releaseContract.artifactBuilder:scripts/pack.ps1" ` --expect-runtime-lifecycle-field "unity-scene:release:releaseContract.artifactPattern:artifacts/eveunity-scene-release/{version}/org.gamecult.eve.unity-scene-{version}.tgz" ` --expect-runtime-lifecycle-field "unity-scene:release:releaseContract.requiredPackageDependencies.0.packageName:org.gamecult.eve.surface" ` --expect-runtime-lifecycle-field "unity-scene:release:releaseContract.requiredPackageDependencies.0.ownerRepo:Eve" ` --expect-runtime-lifecycle-field "unity-scene:release:releaseContract.requiredPackageDependencies.0.packageManager:upm" ` --expect-runtime-lifecycle-field "unity-scene:test:testContract.runnerKind:unity-editmode-batchmode" ` - --expect-runtime-lifecycle-field "unity-scene:test:testContract.runnerScript:scripts/run-aetheria-unity-scene-editmode-tests.ps1" ` + --expect-runtime-lifecycle-field "unity-scene:test:testContract.runnerScript:scripts/run-package-tests.ps1" ` --expect-runtime-lifecycle-field "unity-scene:test:testContract.testPlatform:EditMode" ` --expect-runtime-lifecycle-field "unity-scene:test:testContract.testAssembly:GameCult.Eve.UnityScene.Tests" ` --expect-runtime-lifecycle-field "unity-scene:capture:captureContract.captureKind:unity-scene-frame-png" ` --expect-runtime-lifecycle-field "unity-scene:capture:captureContract.targetId:unity-scene" ` --expect-runtime-lifecycle-field "unity-scene:capture:captureContract.requestSchema:gamecult.eve.runtime_capture_request.v1" ` - --expect-runtime-lifecycle-field "unity-scene:capture:captureContract.requestBuilder:tools/eveunity/eveunity-capture-contract.mjs" ` - --expect-runtime-lifecycle-field "unity-scene:capture:captureContract.advertisementPath:web/fixtures/aetheria.provider-advertisement.json" ` + --expect-runtime-lifecycle-field "unity-scene:capture:captureContract.requestBuilder:scripts/build-capture-request.ps1" ` + --expect-runtime-lifecycle-field "unity-scene:capture:captureContract.advertisementPath:GameCult/Aetheria:web/fixtures/aetheria.provider-advertisement.json" ` --expect-runtime-lifecycle-field "unity-scene:capture:captureContract.requiredSurface:aetheria.daemon.game" ` --expect-runtime-lifecycle-field "unity-scene:capture:captureContract.additionalProviderSurfaces.0.providerId:eve.world-smoke" ` --expect-runtime-lifecycle-field "unity-scene:capture:captureContract.additionalProviderSurfaces.0.surfaceId:eve.world-smoke.surface" ` diff --git a/scripts/run-split-target-conformance-consumer-smoke.ps1 b/scripts/run-split-target-conformance-consumer-smoke.ps1 index 5b7a28f..ec00eb2 100644 --- a/scripts/run-split-target-conformance-consumer-smoke.ps1 +++ b/scripts/run-split-target-conformance-consumer-smoke.ps1 @@ -41,40 +41,15 @@ try { --expect-split-target-status EveUnity:incubating ` --expect-split-target-proof "EveUnity:Unity lifecycle evidence is declared" ` --expect-split-target-proof "EveUnity:EveUnity split handoff is machine-readable" ` - --expect-split-target-proof "EveUnity:Unity scene split handoff is machine-readable" ` - --expect-split-target-proof "EveUnity:Unity scene lifecycle contract is machine-readable" ` + --expect-split-target-proof "EveUnity:Unity scene runtime is owned by EveUnity" ` + --expect-split-target-proof "EveUnity:Unity scene lifecycle is owned and tested from EveUnity" ` --expect-split-target-proof "EveUnity:Aetheria daemon 3D ARPG world lowers through a generic EveUnity playable-world client" ` --expect-runtime-capture-artifact unity-uitoolkit:json-projection:gamecult.eve.unity_uitoolkit_projection.v1:aetheria:aetheria.daemon.game ` --expect-runtime-capture-artifact unity-uitoolkit:json-projection:gamecult.eve.unity_uitoolkit_projection.v1:eve.world-smoke:eve.world-smoke.surface ` - --expect-runtime-capture-artifact unity-scene:json-projection:gamecult.eve.unity_scene_projection.v1:aetheria:aetheria.daemon.game ` - --expect-runtime-capture-artifact unity-scene:json-projection:gamecult.eve.unity_scene_projection.v1:eve.world-smoke:eve.world-smoke.surface ` - --expect-split-target-blocker "EveUnity:runtime:unity-scene:status:pending" ` - --expect-split-target-blocker-record EveUnity:runtime-status:unity-scene ` - --expect-split-target-blocker-record "EveUnity:pending-proof:Unity scene runtime body graduates to EveUnity outside Aetheria product code." ` - --expect-split-handoff-move EveUnity:unity-scene:unity-scene-runtime-body:current:exists:EveUnitySceneSurfaceLowerer.cs ` - --expect-split-handoff-move EveUnity:unity-scene:unity-scene-runtime-body:current:exists:EveUnitySceneLiveProviderBridge.cs ` - --expect-split-handoff-move EveUnity:unity-scene:unity-scene-runtime-body:current:exists:EveUnityPlayableWorldClientBootstrap.cs ` - --expect-split-handoff-move EveUnity:unity-scene:unity-scene-upm-package:current:exists:eveunity-release-artifact.mjs ` - --expect-split-handoff-move EveUnity:unity-scene:unity-scene-world-surface-lowering:current:exists:EveUnitySceneSurfaceLowerer.cs ` - --expect-split-handoff-move EveUnity:unity-scene:unity-scene-world-surface-lowering:current:exists:EveUnitySceneLiveProviderBridge.cs ` - --expect-split-handoff-move EveUnity:unity-scene:unity-scene-world-surface-lowering:current:exists:EveUnityPlayableWorldClientBootstrap.cs ` - --expect-split-handoff-move EveUnity:unity-scene:unity-scene-sai-plugin-projection:current:exists:SaiVisualNovelUnitySceneProjectionAdapter.cs ` - --expect-split-handoff-move EveUnity:unity-scene:unity-scene-norn-plugin-projection:current:exists:NornGraphUnitySceneProjectionAdapter.cs ` - --expect-split-handoff-move EveUnity:unity-scene:unity-scene-tex-plugin-projection:current:exists:TeXMathUnitySceneProjectionAdapter.cs ` - --expect-split-handoff-move EveUnity:unity-scene:unity-scene-command-transport:current:exists:EveUnitySceneSurfaceLowerer.cs ` - --expect-split-handoff-move EveUnity:unity-scene:unity-scene-command-transport:current:exists:EveUnitySceneLiveProviderBridge.cs ` - --expect-split-handoff-move EveUnity:unity-scene:aetheria-playable-world-consumer-proof:observed-provider:exists:Assets/Scripts/Tests/DaemonRuntimeDocumentTests.cs ` - --expect-split-handoff-move EveUnity:unity-scene:aetheria-playable-world-consumer-proof:observed-provider:exists:Packages/org.gamecult.aetheria.eve-runtime/Runtime/AetheriaEveUnitySceneProviderBridge.cs ` - --expect-split-handoff-move EveUnity:unity-scene:aetheria-playable-world-consumer-proof:observed-provider:exists:AetheriaRuntimeDaemonGameSurfaceBuilder.cs ` - --expect-split-handoff-move EveUnity:unity-scene:aetheria-playable-world-consumer-proof:observed-provider:exists:AetheriaRuntimeDaemonOperationsClient.cs ` - --expect-split-handoff-move EveUnity:unity-scene:unity-scene-capture-lifecycle:current:exists:eveunity-capture-contract.mjs ` --expect-split-handoff-move EveUnity:unity-uitoolkit:aetheria-unity-consumer-boundary:observed-provider:exists:Packages/manifest.json ` --expect-split-handoff-move EveUnity:unity-uitoolkit:aetheria-unity-consumer-boundary:observed-provider:exists:GameCult.Eve.UnityUIToolkit.csproj ` --expect-split-handoff-move EveUnity:unity-uitoolkit:aetheria-unity-consumer-boundary:observed-provider:exists:Aetheria.State.Unity/AetheriaRuntimeCatalogClient.cs ` --expect-split-target-blocker "EveUnity:Tagged UPM release" ` - --expect-split-target-blocker "EveUnity:Unity batchmode EditMode runner" ` - --expect-split-target-blocker "EveUnity:Unity batchmode or editor capture artifact" ` - --expect-split-target-blocker "EveUnity:Unity scene runtime body graduates to EveUnity outside Aetheria product code" ` --expect-split-target EveElectron ` --expect-split-target-status EveElectron:incubating ` --expect-split-target-proof "EveElectron:EveElectron split handoff is machine-readable" ` diff --git a/tools/eveunity/eveunity-capture-contract.test.mjs b/tools/eveunity/eveunity-capture-contract.test.mjs index e27cbe2..816c0f0 100644 --- a/tools/eveunity/eveunity-capture-contract.test.mjs +++ b/tools/eveunity/eveunity-capture-contract.test.mjs @@ -6,7 +6,6 @@ import { buildUnityCaptureRequest } from "./eveunity-capture-contract.mjs"; const advertisement = JSON.parse(readFileSync(new URL("../../web/fixtures/aetheria.provider-advertisement.json", import.meta.url), "utf8")); const worldSmokeAdvertisement = JSON.parse(readFileSync(new URL("../../web/fixtures/eve-world-smoke.provider-advertisement.json", import.meta.url), "utf8")); const capabilityManifest = JSON.parse(readFileSync(new URL("../../packages/org.gamecult.eve.unity-uitoolkit/eve-runtime-capability.json", import.meta.url), "utf8")); -const sceneCapabilityManifest = JSON.parse(readFileSync(new URL("../../runtimes/incubating/eve-unity-scene/eve-runtime-capability.json", import.meta.url), "utf8")); test("builds Unity UI Toolkit capture request from provider advertisement", () => { const request = buildUnityCaptureRequest({ @@ -75,53 +74,3 @@ test("rejects a capture request when the surface does not advertise the runtime /does not advertise lowering target unity-uitoolkit/, ); }); - -test("builds Unity scene capture request from provider advertisement", () => { - const request = buildUnityCaptureRequest({ - advertisement, - capabilityManifest: sceneCapabilityManifest, - advertisementPath: "web/fixtures/aetheria.provider-advertisement.json", - capabilityManifestPath: "runtimes/incubating/eve-unity-scene/eve-runtime-capability.json", - stamp: "smoke", - }); - - assert.equal(request.schema, "gamecult.eve.runtime_capture_request.v1"); - assert.equal(request.runtimeId, "unity-scene"); - assert.equal(request.ownerRepo, "EveUnity"); - assert.equal(request.providerId, "aetheria"); - assert.equal(request.surfaceId, "aetheria.daemon.game"); - assert.equal(request.targetId, "unity-scene"); - assert.equal(request.projectionKind, "provider-authored-world-surface"); - assert.equal(request.commandBoundary, "aetheria.daemon.commands"); - assert.equal(request.receiptSchema, "aetheria.eve_command_acceptance_status.v1"); - assert.equal(request.artifactPath, "artifacts/eveunity-scene-capture/smoke/unity-scene.png"); - assert.match(request.authority, /provider state/); -}); - -test("builds Unity scene capture request from a declared generic world provider", () => { - const request = buildUnityCaptureRequest({ - advertisement: worldSmokeAdvertisement, - capabilityManifest: sceneCapabilityManifest, - advertisementPath: "web/fixtures/eve-world-smoke.provider-advertisement.json", - capabilityManifestPath: "runtimes/incubating/eve-unity-scene/eve-runtime-capability.json", - stamp: "smoke", - }); - - assert.equal(request.runtimeId, "unity-scene"); - assert.equal(request.providerId, "eve.world-smoke"); - assert.equal(request.surfaceId, "eve.world-smoke.surface"); - assert.equal(request.commandBoundary, "eve.world-smoke.commands"); - assert.equal(request.receiptSchema, "eve.world_smoke.command_receipt.v1"); -}); - -test("rejects Unity scene capture request for Aetheria editor surface", () => { - assert.throws( - () => buildUnityCaptureRequest({ - advertisement, - capabilityManifest: sceneCapabilityManifest, - captureSurfaceId: "aetheria.daemon.editor", - stamp: "smoke", - }), - /capture surface mismatch/, - ); -}); diff --git a/tools/eveunity/eveunity-release-artifact.test.mjs b/tools/eveunity/eveunity-release-artifact.test.mjs index c2561b6..300dc70 100644 --- a/tools/eveunity/eveunity-release-artifact.test.mjs +++ b/tools/eveunity/eveunity-release-artifact.test.mjs @@ -6,8 +6,6 @@ import { buildUnityReleaseArtifactPlan } from "./eveunity-release-artifact.mjs"; const capabilityManifest = JSON.parse(readFileSync(new URL("../../packages/org.gamecult.eve.unity-uitoolkit/eve-runtime-capability.json", import.meta.url), "utf8")); const packageManifest = JSON.parse(readFileSync(new URL("../../packages/org.gamecult.eve.unity-uitoolkit/package.json", import.meta.url), "utf8")); -const sceneCapabilityManifest = JSON.parse(readFileSync(new URL("../../runtimes/incubating/eve-unity-scene/eve-runtime-capability.json", import.meta.url), "utf8")); -const scenePackageManifest = JSON.parse(readFileSync(new URL("../../runtimes/incubating/eve-unity-scene/package.json", import.meta.url), "utf8")); test("plans npm pack for the EveUnity UI Toolkit UPM artifact", () => { const request = buildUnityReleaseRequest({ @@ -30,26 +28,6 @@ test("plans npm pack for the EveUnity UI Toolkit UPM artifact", () => { ]); }); -test("plans npm pack for the EveUnity scene UPM artifact", () => { - const request = buildUnityReleaseRequest({ - capabilityManifest: sceneCapabilityManifest, - packageManifest: scenePackageManifest, - capabilityManifestPath: "runtimes/incubating/eve-unity-scene/eve-runtime-capability.json", - packageManifestPath: "runtimes/incubating/eve-unity-scene/package.json", - }); - const plan = buildUnityReleaseArtifactPlan({ request, packageManifest: scenePackageManifest }); - - assert.equal(plan.packageRoot, "runtimes/incubating/eve-unity-scene"); - assert.equal(plan.artifactPath, "artifacts/eveunity-scene-release/0.1.0/org.gamecult.eve.unity-scene-0.1.0.tgz"); - assert.equal(plan.artifactDirectory, "artifacts/eveunity-scene-release/0.1.0"); - assert.equal(plan.expectedFileName, "org.gamecult.eve.unity-scene-0.1.0.tgz"); - assert.deepEqual(plan.npmPackArguments, [ - "pack", - "runtimes/incubating/eve-unity-scene", - "--pack-destination", - "artifacts/eveunity-scene-release/0.1.0", - ]); -}); test("rejects release artifact plans for mismatched package identity", () => { const request = buildUnityReleaseRequest({ capabilityManifest, packageManifest }); diff --git a/tools/eveunity/eveunity-release-contract.test.mjs b/tools/eveunity/eveunity-release-contract.test.mjs index 151ee0b..3ee5570 100644 --- a/tools/eveunity/eveunity-release-contract.test.mjs +++ b/tools/eveunity/eveunity-release-contract.test.mjs @@ -5,8 +5,6 @@ import { buildUnityReleaseRequest } from "./eveunity-release-contract.mjs"; const capabilityManifest = JSON.parse(readFileSync(new URL("../../packages/org.gamecult.eve.unity-uitoolkit/eve-runtime-capability.json", import.meta.url), "utf8")); const packageManifest = JSON.parse(readFileSync(new URL("../../packages/org.gamecult.eve.unity-uitoolkit/package.json", import.meta.url), "utf8")); -const sceneCapabilityManifest = JSON.parse(readFileSync(new URL("../../runtimes/incubating/eve-unity-scene/eve-runtime-capability.json", import.meta.url), "utf8")); -const scenePackageManifest = JSON.parse(readFileSync(new URL("../../runtimes/incubating/eve-unity-scene/package.json", import.meta.url), "utf8")); test("builds EveUnity UPM release request from package manifest", () => { const request = buildUnityReleaseRequest({ @@ -55,25 +53,3 @@ test("rejects package manifests missing required UPM dependencies", () => { /must depend on org\.gamecult\.eve\.surface/, ); }); - -test("builds EveUnity scene UPM release request from package manifest", () => { - const request = buildUnityReleaseRequest({ - capabilityManifest: sceneCapabilityManifest, - packageManifest: scenePackageManifest, - capabilityManifestPath: "runtimes/incubating/eve-unity-scene/eve-runtime-capability.json", - packageManifestPath: "runtimes/incubating/eve-unity-scene/package.json", - }); - - assert.equal(request.schema, "gamecult.eve.runtime_release_request.v1"); - assert.equal(request.ownerRepo, "EveUnity"); - assert.equal(request.repository, "GameCult/EveUnity"); - assert.equal(request.packageName, "org.gamecult.eve.unity-scene"); - assert.equal(request.version, "0.1.0"); - assert.equal(request.packageRoot, "runtimes/incubating/eve-unity-scene"); - assert.equal(request.versionSource, "runtimes/incubating/eve-unity-scene/package.json"); - assert.equal(request.tagName, "eveunity-scene-v0.1.0"); - assert.equal(request.artifactKind, "upm-package"); - assert.equal(request.artifactPath, "artifacts/eveunity-scene-release/0.1.0/org.gamecult.eve.unity-scene-0.1.0.tgz"); - assert.equal(request.dependencies["org.gamecult.eve.surface"], "0.1.0"); - assert.equal(request.requiredPackageDependencies[0].ownerRepo, "Eve"); -}); diff --git a/tools/eveunity/eveunity-scene-capture-artifact.mjs b/tools/eveunity/eveunity-scene-capture-artifact.mjs deleted file mode 100644 index 8e18e29..0000000 --- a/tools/eveunity/eveunity-scene-capture-artifact.mjs +++ /dev/null @@ -1,397 +0,0 @@ -import { mkdirSync, writeFileSync } from "node:fs"; -import path from "node:path"; -import { fileURLToPath } from "node:url"; -import { buildUnityCaptureRequest, loadJsonFile, writeCaptureRequest } from "./eveunity-capture-contract.mjs"; - -export function buildUnitySceneCaptureArtifact({ - advertisement, - capabilityManifest, - surfaceDocument, - advertisementPath = "", - capabilityManifestPath = "", - captureSurfaceId = "", - stamp = "latest", -} = {}) { - const request = buildUnityCaptureRequest({ - advertisement, - capabilityManifest, - advertisementPath, - capabilityManifestPath, - captureSurfaceId, - stamp, - }); - const projection = buildUnitySceneProjection(surfaceDocument, advertisement, request.surfaceId); - validateProjectionArtifact(projection, request); - - return { - request, - projection: { - ...projection, - artifactKind: "json-projection", - captureKind: "unity-scene-projection-json", - sourceAdvertisementPath: request.sourceAdvertisementPath, - sourceCapabilityManifestPath: request.sourceCapabilityManifestPath, - issuedAtUtc: request.issuedAtUtc, - }, - }; -} - -export function buildUnitySceneProjection(surfaceDocument, providerAdvertisement, requestedSurfaceId = "") { - const selected = selectSurface(providerAdvertisement, requestedSurfaceId); - const document = normalizeSurfaceDocument(surfaceDocument); - if (document.surfaceId !== selected.surfaceId) { - throw new Error(`Surface document ${document.surfaceId} does not match advertised Unity scene surface ${selected.surfaceId}.`); - } - const playableWorld = buildPlayableWorld(document.root); - - return { - type: "unity-scene-projection", - schema: "gamecult.eve.unity_scene_projection.v1", - runtimeId: "unity-scene", - providerId: selected.providerId, - surfaceId: selected.surfaceId, - projectionKind: selected.worldInteraction.projectionKind, - commandBoundary: selected.worldInteraction.commandBoundary, - receiptSchema: selected.worldInteraction.receiptSchema, - ownership: selected.worldInteraction.ownership, - ...(playableWorld ? { playableWorld } : {}), - root: buildSceneNode(document.root), - }; -} - -export function writeUnitySceneCaptureArtifact({ request, projection }, { outputPath, requestOutputPath = "" } = {}) { - if (!outputPath) throw new Error("outputPath is required"); - mkdirSync(path.dirname(outputPath), { recursive: true }); - writeFileSync(outputPath, `${JSON.stringify(projection, null, 2)}\n`, "utf8"); - if (requestOutputPath) { - writeCaptureRequest(request, requestOutputPath); - } -} - -function selectSurface(providerAdvertisement, requestedSurfaceId = "") { - const provider = normalizeProviderAdvertisement(providerAdvertisement); - const surface = requestedSurfaceId - ? provider.surfaces.find(candidate => candidate.surfaceId === requestedSurfaceId) - : provider.surfaces[0]; - - if (!surface) { - throw new Error(`Provider ${provider.providerId} does not advertise surface ${requestedSurfaceId || "(first)"}`); - } - - return { - providerId: provider.providerId, - surfaceId: surface.surfaceId, - worldInteraction: normalizeWorldInteraction(surface.worldInteraction), - }; -} - -function normalizeProviderAdvertisement(providerAdvertisement) { - if (!providerAdvertisement || typeof providerAdvertisement !== "object") { - throw new Error("Provider advertisement is required."); - } - const providerId = String(providerAdvertisement.providerId || ""); - if (!providerId) throw new Error("Provider advertisement missing providerId."); - const surfaces = Array.isArray(providerAdvertisement.surfaces) - ? providerAdvertisement.surfaces - .filter(surface => surface && typeof surface === "object" && surface.surfaceId) - .map(surface => ({ - ...surface, - surfaceId: String(surface.surfaceId), - })) - : []; - if (!surfaces.length) throw new Error(`Provider ${providerId} advertises no surfaces.`); - return { ...providerAdvertisement, providerId, surfaces }; -} - -function normalizeSurfaceDocument(surfaceDocument) { - if (!surfaceDocument || typeof surfaceDocument !== "object") { - throw new Error("Surface document is required."); - } - if (surfaceDocument.schema !== "gamecult.eve.surface.v1") { - throw new Error(`Unexpected surface schema: ${surfaceDocument.schema || ""}`); - } - const surface = objectValue(surfaceDocument.surface); - const surfaceId = firstString(surface.id); - if (!surfaceId) throw new Error("Surface document missing surface.id."); - const root = objectValue(surface.root); - if (!root.id) throw new Error(`Surface document ${surfaceId} missing surface.root.`); - return { ...surfaceDocument, surfaceId, root }; -} - -function buildSceneNode(component) { - const source = objectValue(component); - const children = Array.isArray(source.children) ? source.children.map(buildSceneNode) : []; - const embeddedDocuments = normalizeEmbeddedDocuments(source.embeddedDocuments); - const componentKind = firstString(source.kind); - const pluginProjection = buildPluginProjection(componentKind, source); - return { - id: firstString(source.id), - componentKind, - sceneObjectKind: sceneObjectKind(componentKind), - props: objectValue(source.props), - layout: objectValue(source.layout), - style: objectValue(source.style), - stateBindingCount: Array.isArray(source.stateBindings) ? source.stateBindings.length : 0, - embeddedDocumentCount: embeddedDocuments.length, - embeddedDocuments, - ...(pluginProjection ? { pluginProjection } : {}), - children, - }; -} - -function normalizeEmbeddedDocuments(value) { - return Array.isArray(value) - ? value - .filter(document => document && typeof document === "object") - .map(document => ({ - slotId: firstString(document.slotId, document.id), - documentId: firstString(document.documentId, document.href, document.url), - schemaId: firstString(document.schemaId, document.schema), - presentationKind: firstString(document.presentationKind, document.kind), - })) - .filter(document => document.slotId || document.documentId) - : []; -} - -function sceneObjectKind(componentKind) { - if (!componentKind) return "empty"; - if (componentKind === "world.scene3d") return "playable-world-root"; - if (componentKind === "world.entity3d") return "playable-world-entity"; - if (componentKind === "field.vector3d" || componentKind === "field.scalar3d") return "world-field-3d"; - if (componentKind === "vn.stage") return "sai-vn-scene-stage"; - if (componentKind === "panel.dialogue" || componentKind === "text.dialogue") return "sai-vn-scene-dialogue"; - if (componentKind === "rail.actions") return "sai-vn-scene-action-rail"; - if (componentKind.startsWith("control.")) return "command-control"; - if (componentKind === "embed.norn") return "norn-graph-scene-projection"; - if (componentKind === "embed.tex") return "tex-math-scene-projection"; - if (componentKind.startsWith("embed.")) return "plugin-placeholder"; - if (componentKind === "surface.slot") return "embedded-surface-slot"; - if (componentKind.startsWith("field.") || componentKind.startsWith("world.")) return "world-projection-node"; - if (componentKind.startsWith("text.") || componentKind === "text" || componentKind === "label") return "scene-label"; - return "scene-node"; -} - -function buildPlayableWorld(root) { - const world = findComponent(root, component => firstString(component?.kind) === "world.scene3d"); - if (!world) return null; - const props = objectValue(world.props); - const entities = flattenComponents(world) - .filter(component => firstString(component.kind) === "world.entity3d") - .map(component => buildPlayableEntity(component)); - return { - worldRootId: firstString(world.id), - statePointerId: firstString(props.statePointerId, props.worldStatePointerId), - assetManifest: firstString(props.assetManifest, props.assetManifestUri), - inputProfile: firstString(props.inputProfile), - cameraRig: firstString(props.cameraRig), - playerEntityId: firstString(props.playerEntityId), - movementCommand: firstString(props.movementCommand), - focusCommand: firstString(props.focusCommand), - targetCommand: firstString(props.targetCommand), - actionCommand: firstString(props.actionCommand), - entityCount: entities.length, - entities, - }; -} - -function buildPlayableEntity(component) { - const props = objectValue(component.props); - const [x, y, z] = parseVector3(firstString(props.position)); - return { - nodeId: firstString(component.id), - entityId: firstString(props.entityId, component.id), - entityKind: firstString(props.entityKind, props.kind), - label: firstString(props.label, props.name), - faction: firstString(props.faction), - assetRef: firstString(props.assetRef, props.meshRef, props.prefabRef), - position: { x, y, z }, - rotationY: parseNumber(firstString(props.rotationY, props.yaw), 0), - radius: parseNumber(firstString(props.radius), 0), - selectable: parseBoolean(props.selectable), - controllable: parseBoolean(props.controllable), - focusCommand: firstString(props.focusCommand), - moveCommand: firstString(props.moveCommand), - targetCommand: firstString(props.targetCommand), - actionCommand: firstString(props.actionCommand), - }; -} - -function findComponent(component, predicate) { - const source = objectValue(component); - if (predicate(source)) return source; - for (const child of Array.isArray(source.children) ? source.children : []) { - const found = findComponent(child, predicate); - if (found) return found; - } - return null; -} - -function flattenComponents(component) { - const source = objectValue(component); - return [ - source, - ...((Array.isArray(source.children) ? source.children : []).flatMap(flattenComponents)), - ]; -} - -function parseVector3(value) { - const values = String(value || "") - .split(",") - .map(part => parseNumber(part.trim(), 0)); - return [values[0] || 0, values[1] || 0, values[2] || 0]; -} - -function parseNumber(value, fallback) { - const parsed = Number(value); - return Number.isFinite(parsed) ? parsed : fallback; -} - -function parseBoolean(value) { - if (typeof value === "boolean") return value; - if (typeof value === "number") return value !== 0; - return String(value || "").toLowerCase() === "true"; -} - -function buildPluginProjection(componentKind, component) { - const props = objectValue(component.props); - if (componentKind === "vn.stage") { - return { - pluginId: "sai.vn", - projectionKind: "sai-vn-scene-stage", - abiSchema: "gamecult.eve.plugin_abi.v1", - commandBoundary: "sidecar-advertised-plugin-abi", - capabilities: ["vn.stage", "story.choose", "story.continue", "story.jump"], - command: "story.choose", - documentId: firstString(props.storyId, component.id), - semanticOwner: "Sai", - availability: "required", - }; - } - - if (componentKind === "embed.norn") { - return { - pluginId: "norn.graph", - projectionKind: "norn-graph-scene-projection", - abiSchema: "gamecult.eve.plugin_abi.v1", - commandBoundary: "sidecar-advertised-plugin-abi", - capabilities: ["embed.norn"], - command: "graph.node.activate", - documentId: firstString(props.sourceUri, props.documentId, component.id), - semanticOwner: "Norn", - availability: "optional-nested", - }; - } - - if (componentKind === "embed.tex") { - return { - pluginId: "tex.math", - projectionKind: texProjectionKind(props), - abiSchema: "gamecult.eve.plugin_abi.v1", - commandBoundary: "sidecar-advertised-plugin-abi", - capabilities: ["embed.tex", "tex.inline", "tex.block", "tex.scene-placement"], - command: "", - documentId: firstString(props.sourceUri, props.source, component.id), - semanticOwner: "EvePlugins", - availability: "optional-nested", - }; - } - - return null; -} - -function texProjectionKind(props) { - const display = firstString(props.display, "inline"); - if (display === "block") return "tex-math-scene-projection"; - if (display === "page") return "tex-math-scene-page-projection"; - return "tex-math-scene-inline-projection"; -} - -function normalizeWorldInteraction(value) { - const source = objectValue(value); - return { - projectionKind: firstString(source.projectionKind), - commandBoundary: firstString(source.commandBoundary), - receiptSchema: firstString(source.receiptSchema), - ownership: firstString(source.ownership), - }; -} - -function validateProjectionArtifact(projection, request) { - if (projection.schema !== "gamecult.eve.unity_scene_projection.v1") { - throw new Error(`Unexpected Unity scene projection schema: ${projection.schema || ""}`); - } - for (const [field, expected] of [ - ["runtimeId", request.runtimeId], - ["providerId", request.providerId], - ["surfaceId", request.surfaceId], - ["projectionKind", request.projectionKind], - ["commandBoundary", request.commandBoundary], - ["receiptSchema", request.receiptSchema], - ]) { - if ((projection[field] || "") !== (expected || "")) { - throw new Error(`Unity scene projection ${field} expected ${expected || ""} got ${projection[field] || ""}`); - } - } - if (!projection.root || !projection.root.id) { - throw new Error("Unity scene projection artifact must contain a root scene node"); - } -} - -function objectValue(value) { - return value && typeof value === "object" && !Array.isArray(value) ? value : {}; -} - -function firstString(...values) { - for (const value of values) { - if (typeof value === "string" && value.trim()) return value; - if (typeof value === "number" && Number.isFinite(value)) return String(value); - } - return ""; -} - -function parseArgs(argv) { - const args = {}; - for (let index = 0; index < argv.length; index += 1) { - const value = argv[index]; - if (!value.startsWith("--")) continue; - const key = value.slice(2); - const next = argv[index + 1]; - if (!next || next.startsWith("--")) { - args[key] = true; - } else { - args[key] = next; - index += 1; - } - } - return args; -} - -function runCli() { - const args = parseArgs(process.argv.slice(2)); - for (const required of ["advertisement", "capability", "surface", "output"]) { - if (!args[required]) { - throw new Error(`missing required --${required}`); - } - } - const stamp = args.stamp || "latest"; - const artifact = buildUnitySceneCaptureArtifact({ - advertisement: loadJsonFile(args.advertisement), - capabilityManifest: loadJsonFile(args.capability), - surfaceDocument: loadJsonFile(args.surface), - advertisementPath: args.advertisement, - capabilityManifestPath: args.capability, - captureSurfaceId: args["surface-id"] || "", - stamp, - }); - writeUnitySceneCaptureArtifact(artifact, { - outputPath: args.output, - requestOutputPath: args["request-output"] || "", - }); - process.stdout.write(`${args.output}\n`); -} - -const invokedPath = process.argv[1] ? path.resolve(process.argv[1]) : ""; -const modulePath = fileURLToPath(import.meta.url); -if (invokedPath === modulePath) { - runCli(); -} diff --git a/tools/eveunity/eveunity-scene-capture-artifact.test.mjs b/tools/eveunity/eveunity-scene-capture-artifact.test.mjs deleted file mode 100644 index 1a7f254..0000000 --- a/tools/eveunity/eveunity-scene-capture-artifact.test.mjs +++ /dev/null @@ -1,96 +0,0 @@ -import assert from "node:assert/strict"; -import { readFileSync } from "node:fs"; -import test from "node:test"; -import { validateSchemaSubset } from "../../runtimes/incubating/test-support/schema-subset.mjs"; -import { buildUnitySceneCaptureArtifact, buildUnitySceneProjection } from "./eveunity-scene-capture-artifact.mjs"; - -const unitySceneProjectionSchema = JSON.parse(readFileSync(new URL("../../schemas/gamecult.eve.unity_scene_projection.v1.schema.json", import.meta.url), "utf8")); -const aetheriaAdvertisement = JSON.parse(readFileSync(new URL("../../web/fixtures/aetheria.provider-advertisement.json", import.meta.url), "utf8")); -const capabilityManifest = JSON.parse(readFileSync(new URL("../../runtimes/incubating/eve-unity-scene/eve-runtime-capability.json", import.meta.url), "utf8")); -const aetheriaSurfaceDocument = JSON.parse(readFileSync(new URL("../../web/fixtures/aetheria-world-surface.json", import.meta.url), "utf8")); -const worldSmokeAdvertisement = JSON.parse(readFileSync(new URL("../../web/fixtures/eve-world-smoke.provider-advertisement.json", import.meta.url), "utf8")); -const worldSmokeSurfaceDocument = JSON.parse(readFileSync(new URL("../../web/fixtures/eve-world-smoke-surface.json", import.meta.url), "utf8")); -const saiAdvertisement = JSON.parse(readFileSync(new URL("../../web/fixtures/sai-vn.provider-advertisement.json", import.meta.url), "utf8")); -const saiSurfaceDocument = JSON.parse(readFileSync(new URL("../../web/fixtures/sai-vn-surface.json", import.meta.url), "utf8")); - -test("builds Unity scene projection capture artifact from provider advertisement and surface", () => { - const { request, projection } = buildUnitySceneCaptureArtifact({ - advertisement: aetheriaAdvertisement, - capabilityManifest, - surfaceDocument: aetheriaSurfaceDocument, - advertisementPath: "web/fixtures/aetheria.provider-advertisement.json", - capabilityManifestPath: "runtimes/incubating/eve-unity-scene/eve-runtime-capability.json", - stamp: "smoke", - }); - - assert.equal(request.artifactPath, "artifacts/eveunity-scene-capture/smoke/unity-scene.png"); - assert.deepEqual(validateSchemaSubset(unitySceneProjectionSchema, projection), []); - assert.equal(projection.schema, "gamecult.eve.unity_scene_projection.v1"); - assert.equal(projection.runtimeId, "unity-scene"); - assert.equal(projection.providerId, "aetheria"); - assert.equal(projection.surfaceId, "aetheria.daemon.game"); - assert.equal(projection.commandBoundary, "aetheria.daemon.commands"); - assert.equal(projection.receiptSchema, "aetheria.eve_command_acceptance_status.v1"); - assert.equal(projection.artifactKind, "json-projection"); - assert.equal(projection.captureKind, "unity-scene-projection-json"); - assert.equal(projection.root.id, "aetheria.daemon.game.root"); - assert.equal(projection.playableWorld.worldRootId, "aetheria.daemon.game.playable"); - assert.equal(projection.playableWorld.statePointerId, "cultmesh://aetheria/run/current"); - assert.equal(projection.playableWorld.assetManifest, "cultmesh://aetheria/assets/manifest"); - assert.equal(projection.playableWorld.inputProfile, "arpg-third-person"); - assert.equal(projection.playableWorld.cameraRig, "third-person-orbit"); - assert.equal(projection.playableWorld.playerEntityId, "player-vanguard"); - assert.equal(projection.playableWorld.movementCommand, "aetheria.daemon.move_intent"); - assert.equal(projection.playableWorld.entityCount, 3); - const player = projection.playableWorld.entities.find(entity => entity.entityId === "player-vanguard"); - assert.equal(player.assetRef, "cultmesh://aetheria/assets/map/entity/player"); - assert.deepEqual(player.position, { x: 0, y: 0, z: 0 }); - assert.equal(player.controllable, true); - assert.equal(projection.root.children[1].children[0].sceneObjectKind, "playable-world-root"); -}); - -test("builds Unity scene capture artifact for a generic world provider", () => { - const { projection } = buildUnitySceneCaptureArtifact({ - advertisement: worldSmokeAdvertisement, - capabilityManifest, - surfaceDocument: worldSmokeSurfaceDocument, - advertisementPath: "web/fixtures/eve-world-smoke.provider-advertisement.json", - capabilityManifestPath: "runtimes/incubating/eve-unity-scene/eve-runtime-capability.json", - stamp: "smoke", - }); - - assert.deepEqual(validateSchemaSubset(unitySceneProjectionSchema, projection), []); - assert.equal(projection.providerId, "eve.world-smoke"); - assert.equal(projection.surfaceId, "eve.world-smoke.surface"); - assert.equal(projection.commandBoundary, "eve.world-smoke.commands"); - assert.equal(projection.receiptSchema, "eve.world_smoke.command_receipt.v1"); - assert.equal(projection.root.id, "eve.world-smoke.root"); - assert.equal(projection.root.children[1].sceneObjectKind, "world-projection-node"); -}); - -test("marks Sai required and Norn TeX optional sidecar plugin projections", () => { - const advertisement = structuredClone(saiAdvertisement); - advertisement.surfaces[0].worldInteraction = { - projectionKind: "provider-authored-visual-novel-surface", - commandBoundary: "sai.vn.plugin.commands", - receiptSchema: "gamecult.eve.command_receipt.v1", - loweringTargets: ["unity-scene"], - ownership: "provider-owns-story-state-independent-plugin-sidecars-own-semantics", - }; - - const projection = buildUnitySceneProjection(saiSurfaceDocument, advertisement, "sai.visual_novel.surface"); - assert.deepEqual(validateSchemaSubset(unitySceneProjectionSchema, projection), []); - const graphNode = projection.root.children.find(child => child.id === "sai.graph"); - const texLayer = projection.root.children.find(child => child.id === "sai.embeds"); - const texNode = texLayer.children.find(child => child.id === "sai.tex.log-power"); - - assert.equal(projection.root.pluginProjection.pluginId, "sai.vn"); - assert.equal(projection.root.pluginProjection.semanticOwner, "Sai"); - assert.equal(projection.root.pluginProjection.availability, "required"); - assert.equal(graphNode.pluginProjection.pluginId, "norn.graph"); - assert.equal(graphNode.pluginProjection.semanticOwner, "Norn"); - assert.equal(graphNode.pluginProjection.availability, "optional-nested"); - assert.equal(texNode.pluginProjection.pluginId, "tex.math"); - assert.equal(texNode.pluginProjection.semanticOwner, "EvePlugins"); - assert.equal(texNode.pluginProjection.availability, "optional-nested"); -}); diff --git a/tools/parity/parity-manifest.json b/tools/parity/parity-manifest.json index f720e7c..d718440 100644 --- a/tools/parity/parity-manifest.json +++ b/tools/parity/parity-manifest.json @@ -625,71 +625,35 @@ { "description": "Unity lifecycle evidence is declared and smoke-checked for EveUnity incubation.", "status": "passed", - "evidencePaths": [ - "packages/org.gamecult.eve.unity-uitoolkit/eve-runtime-capability.json", - "scripts/run-eveunity-lifecycle-smoke.ps1", - "scripts/run-aetheria-unity-package-smoke.ps1", - "scripts/run-aetheria-unity-editmode-tests.ps1" - ] + "evidencePaths": ["packages/org.gamecult.eve.unity-uitoolkit/eve-runtime-capability.json", "scripts/run-eveunity-lifecycle-smoke.ps1", "scripts/run-aetheria-unity-package-smoke.ps1", "scripts/run-aetheria-unity-editmode-tests.ps1"] }, { "description": "EveUnity split handoff is machine-readable and smoke-checked.", "status": "passed", - "evidencePaths": [ - "packages/org.gamecult.eve.unity-uitoolkit/eveunity-split-handoff.json", - "scripts/run-eveunity-split-handoff-smoke.ps1", - "packages/org.gamecult.eve.unity-uitoolkit/eve-runtime-capability.json" - ] + "evidencePaths": ["packages/org.gamecult.eve.unity-uitoolkit/eveunity-split-handoff.json", "scripts/run-eveunity-split-handoff-smoke.ps1", "packages/org.gamecult.eve.unity-uitoolkit/eve-runtime-capability.json"] }, { - "description": "Unity scene split handoff is machine-readable and smoke-checked.", + "description": "Unity scene runtime is owned by EveUnity and its owner-repo sources are present.", "status": "passed", - "evidencePaths": [ - "runtimes/incubating/eve-unity-scene/eveunity-scene-split-handoff.json", - "scripts/run-eveunity-scene-split-handoff-smoke.ps1" - ] + "evidencePaths": ["../EveUnity/packages/org.gamecult.eve.unity-scene/eve-runtime-capability.json", "../EveUnity/packages/org.gamecult.eve.unity-scene/package.json"] }, { - "description": "Unity scene lifecycle contract is machine-readable and smoke-checked.", + "description": "Unity scene lifecycle is owned and tested from EveUnity.", "status": "passed", - "evidencePaths": [ - "runtimes/incubating/eve-unity-scene/eve-runtime-capability.json", - "scripts/run-eveunity-scene-lifecycle-smoke.ps1", - "scripts/run-eveunity-scene-release-artifact-smoke.ps1", - "scripts/run-eveunity-scene-provider-shell-smoke.ps1", - "scripts/run-aetheria-unity-scene-editmode-tests.ps1" - ] + "evidencePaths": ["../EveUnity/packages/org.gamecult.eve.unity-scene/eve-runtime-capability.json", "../EveUnity/scripts/pack.ps1", "../EveUnity/scripts/run-package-tests.ps1"] }, { "description": "Aetheria daemon 3D ARPG world lowers through a generic EveUnity playable-world client without Aetheria runtime authority.", "status": "passed", - "evidencePaths": [ - "runtimes/incubating/eve-unity-scene/eveunity-scene-split-handoff.json", - "scripts/run-eveunity-scene-split-handoff-smoke.ps1", - "scripts/run-aetheria-unity-scene-editmode-tests.ps1" - ] + "evidencePaths": ["../EveUnity/packages/org.gamecult.eve.unity-scene/eve-runtime-capability.json", "../Aetheria/Packages/org.gamecult.aetheria.eve-runtime/Runtime/AetheriaEveUnitySceneProviderBridge.cs", "../Aetheria/Assets/Scripts/Tests/DaemonRuntimeDocumentTests.cs"] }, { "description": "Unity scene graph projection lowerer plus Sai, Norn, and TeX projection adapters exist without claiming provider simulation, plugin semantics, or capture ownership.", "status": "passed", - "evidencePaths": [ - "runtimes/incubating/eve-unity-scene/package.json", - "runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneSurfaceLowerer.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", - "runtimes/incubating/eve-unity-scene/Tests/Editor/EveUnitySceneSurfaceLowererTests.cs", - "scripts/run-eveunity-scene-provider-shell-smoke.ps1" - ] + "evidencePaths": ["../EveUnity/packages/org.gamecult.eve.unity-scene/package.json", "../EveUnity/packages/org.gamecult.eve.unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs", "../EveUnity/packages/org.gamecult.eve.unity-scene/Runtime/SaiVisualNovelUnitySceneProjectionAdapter.cs", "../EveUnity/packages/org.gamecult.eve.unity-scene/Runtime/NornGraphUnitySceneProjectionAdapter.cs", "../EveUnity/packages/org.gamecult.eve.unity-scene/Runtime/TeXMathUnitySceneProjectionAdapter.cs", "../EveUnity/packages/org.gamecult.eve.unity-scene/Tests/Editor/EveUnitySceneSurfaceLowererTests.cs"] } ], - "pendingProofs": [ - "Tagged UPM release is cut from EveUnity rather than Eve incubation.", - "Unity batchmode EditMode runners are owned by EveUnity rather than Eve incubation.", - "Unity batchmode or editor capture artifact is attached to the runtime conformance report.", - "Unity scene runtime body graduates to EveUnity outside Aetheria product code.", - "Unity scene screenshot or frame-capture PNG artifact is attached to the runtime conformance report." - ] + "pendingProofs": ["Tagged UPM release is cut from EveUnity.", "Unity PlayMode frame capture is attached to conformance for Aetheria and the generic world-smoke provider.", "Generic live CultMesh/CultNet provider transport replaces Aetheria local state-file polling."] }, { "id": "EveElectron", @@ -1039,19 +1003,18 @@ { "id": "unity-scene", "title": "Unity / Scene", - "kind": "pending", + "kind": "active", "ownerRepo": "EveUnity", "repoRole": "runtime-target", "splitTarget": "EveUnity", - "graduationTrigger": "Split with EveUnity when a provider-agnostic Unity scene lowerer consumes provider world surfaces, emits command intents, and attaches scene capture evidence without importing Aetheria product code.", + "graduationTrigger": "Graduated: EveUnity owns the provider-agnostic Unity scene package, release lifecycle, and runtime tests. Real Unity frame capture and live CultMesh transport remain active lifecycle work.", "capabilityManifest": { "schemaPath": "schemas/gamecult.eve.runtime_capability.v1.schema.json", - "manifestPath": "runtimes/incubating/eve-unity-scene/eve-runtime-capability.json" + "manifestPath": "packages/org.gamecult.eve.unity-scene/eve-runtime-capability.json" }, - "splitHandoffPath": "runtimes/incubating/eve-unity-scene/eveunity-scene-split-handoff.json", "requiredFixtures": ["aetheria-world", "eve-world-smoke"], "pluginFixtures": ["sai-vn"], - "supportedFeatures": ["providerAdvertisements", "commandTransport", "providerSurfaceSession", "providerSurfaceSource", "providerSurfaceDocumentSource", "liveProviderTransportBridge", "livePlayableWorldClient", "providerCommandReceipts", "providerAssetManifestDocumentSource", "playableWorldClientHost", "playableWorldClientBootstrap", "playableWorldInputDriver", "playableWorldCameraRig", "providerAssetManifestSource", "sceneGraphProjection", "playableWorldProjection", "playableWorldRuntimeHost", "playableWorldScenePresentation", "unityGameObjectSceneSink", "providerAssetManifestResolution", "embeddedDocuments"], + "supportedFeatures": ["providerAdvertisements", "commandTransport", "providerSurfaceSession", "providerSurfaceSource", "providerSurfaceDocumentSource", "liveProviderTransportBridge", "livePlayableWorldClient", "providerCommandReceipts", "providerAssetManifestDocumentSource", "playableWorldClientHost", "playableWorldClientBootstrap", "playableWorldInputDriver", "playableWorldCameraRig", "sceneGraphProjection", "playableWorldProjection", "playableWorldRuntimeHost", "playableWorldScenePresentation", "unityGameObjectSceneSink", "providerAssetManifestResolution", "providerAssetManifestSource", "embeddedDocuments"], "supportedPlugins": [ { "pluginId": "sai.vn", @@ -1077,182 +1040,163 @@ "projectionKinds": ["provider-authored-world-surface"], "supportLevel": "unity-playable-world-scene-command-surface", "ownership": "runtime-lowers-provider-world-surface-without-owning-world-state", - "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/EveUnitySceneLiveProviderBridge.cs", - "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldLiveClient.cs", - "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldRuntime.cs", - "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldClientHost.cs", - "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldClientBootstrap.cs", - "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldInputDriver.cs", - "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldCameraRig.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", - "runtimes/incubating/eve-unity-scene/Tests/Editor/EveUnitySceneSurfaceLowererTests.cs", - "web/fixtures/aetheria.provider-advertisement.json", - "web/fixtures/eve-world-smoke.provider-advertisement.json" - ] + "evidencePaths": ["packages/org.gamecult.eve.unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs", "packages/org.gamecult.eve.unity-scene/Runtime/EveUnitySceneClientSession.cs", "packages/org.gamecult.eve.unity-scene/Runtime/EveUnitySceneProviderConnection.cs", "packages/org.gamecult.eve.unity-scene/Runtime/EveUnitySceneLiveProviderBridge.cs", "packages/org.gamecult.eve.unity-scene/Runtime/EveUnityPlayableWorldLiveClient.cs", "packages/org.gamecult.eve.unity-scene/Runtime/EveUnityPlayableWorldRuntime.cs", "packages/org.gamecult.eve.unity-scene/Runtime/EveUnityPlayableWorldClientHost.cs", "packages/org.gamecult.eve.unity-scene/Runtime/EveUnityPlayableWorldClientBootstrap.cs", "packages/org.gamecult.eve.unity-scene/Runtime/EveUnityPlayableWorldInputDriver.cs", "packages/org.gamecult.eve.unity-scene/Runtime/EveUnityPlayableWorldCameraRig.cs", "packages/org.gamecult.eve.unity-scene/Runtime/EveUnityProviderRefreshSource.cs", "packages/org.gamecult.eve.unity-scene/Runtime/EveUnityPlayableWorldPresenter.cs", "packages/org.gamecult.eve.unity-scene/Runtime/EveUnityGameObjectPlayableWorldSceneSink.cs", "packages/org.gamecult.eve.unity-scene/Runtime/EveUnityPlayableWorldAssetManifest.cs", "packages/org.gamecult.eve.unity-scene/Runtime/SaiVisualNovelUnitySceneProjectionAdapter.cs", "packages/org.gamecult.eve.unity-scene/Runtime/NornGraphUnitySceneProjectionAdapter.cs", "packages/org.gamecult.eve.unity-scene/Runtime/TeXMathUnitySceneProjectionAdapter.cs", "packages/org.gamecult.eve.unity-scene/Tests/Editor/EveUnitySceneSurfaceLowererTests.cs"] } ], - "expectedPaths": [ - "runtimes/incubating/eve-unity-scene/package.json", - "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/EveUnitySceneLiveProviderBridge.cs", - "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldLiveClient.cs", - "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldRuntime.cs", - "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldClientHost.cs", - "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldClientBootstrap.cs", - "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldInputDriver.cs", - "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldCameraRig.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", - "runtimes/incubating/eve-unity-scene/Tests/Editor/GameCult.Eve.UnityScene.Tests.asmdef", - "runtimes/incubating/eve-unity-scene/Tests/Editor/EveUnitySceneSurfaceLowererTests.cs", - "runtimes/incubating/eve-unity-scene/eve-runtime-capability.json", - "runtimes/incubating/eve-unity-scene/eveunity-scene-split-handoff.json", - "scripts/run-eveunity-scene-lifecycle-smoke.ps1", - "scripts/run-eveunity-scene-release-contract-smoke.ps1", - "scripts/run-eveunity-scene-release-artifact-smoke.ps1", - "scripts/run-eveunity-scene-provider-shell-smoke.ps1", - "scripts/run-eveunity-scene-capture-contract-smoke.ps1", - "scripts/run-eveunity-scene-capture-smoke.ps1", - "tools/eveunity/eveunity-release-contract.mjs", - "tools/eveunity/eveunity-release-contract.test.mjs", - "tools/eveunity/eveunity-release-artifact.mjs", - "tools/eveunity/eveunity-release-artifact.test.mjs", - "tools/eveunity/eveunity-capture-contract.mjs", - "tools/eveunity/eveunity-capture-contract.test.mjs", - "tools/eveunity/eveunity-scene-capture-artifact.mjs", - "tools/eveunity/eveunity-scene-capture-artifact.test.mjs" - ], + "expectedPaths": ["packages/org.gamecult.eve.unity-scene/package.json", "packages/org.gamecult.eve.unity-scene/eve-runtime-capability.json", "packages/org.gamecult.eve.unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs", "packages/org.gamecult.eve.unity-scene/Runtime/EveUnitySceneClientSession.cs", "packages/org.gamecult.eve.unity-scene/Runtime/EveUnitySceneProviderConnection.cs", "packages/org.gamecult.eve.unity-scene/Runtime/EveUnitySceneLiveProviderBridge.cs", "packages/org.gamecult.eve.unity-scene/Runtime/EveUnityPlayableWorldLiveClient.cs", "packages/org.gamecult.eve.unity-scene/Runtime/EveUnityPlayableWorldRuntime.cs", "packages/org.gamecult.eve.unity-scene/Runtime/EveUnityPlayableWorldClientHost.cs", "packages/org.gamecult.eve.unity-scene/Runtime/EveUnityPlayableWorldClientBootstrap.cs", "packages/org.gamecult.eve.unity-scene/Runtime/EveUnityPlayableWorldInputDriver.cs", "packages/org.gamecult.eve.unity-scene/Runtime/EveUnityPlayableWorldCameraRig.cs", "packages/org.gamecult.eve.unity-scene/Runtime/EveUnityProviderRefreshSource.cs", "packages/org.gamecult.eve.unity-scene/Runtime/EveUnityPlayableWorldPresenter.cs", "packages/org.gamecult.eve.unity-scene/Runtime/EveUnityGameObjectPlayableWorldSceneSink.cs", "packages/org.gamecult.eve.unity-scene/Runtime/EveUnityPlayableWorldAssetManifest.cs", "packages/org.gamecult.eve.unity-scene/Runtime/SaiVisualNovelUnitySceneProjectionAdapter.cs", "packages/org.gamecult.eve.unity-scene/Runtime/NornGraphUnitySceneProjectionAdapter.cs", "packages/org.gamecult.eve.unity-scene/Runtime/TeXMathUnitySceneProjectionAdapter.cs", "packages/org.gamecult.eve.unity-scene/Tests/Editor/EveUnitySceneSurfaceLowererTests.cs", "packages/org.gamecult.eve.unity-scene/Runtime/GameCult.Eve.UnityScene.asmdef", "scripts/pack.ps1", "scripts/build-release-request.ps1", "packages/org.gamecult.eve.unity-scene/Tests/Editor/GameCult.Eve.UnityScene.Tests.asmdef", "scripts/run-package-tests.ps1", "scripts/build-capture-request.ps1"], "expectedSourceSymbols": [ { - "path": "runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs", + "path": "packages/org.gamecult.eve.unity-scene/Runtime/EveUnitySceneSurfaceLowerer.cs", "contains": ["EveUnitySceneSurfaceLowerer", "EveUnitySceneProviderSurfaceAdvertisement", "WorldInteraction", "CommandBoundary", "ReceiptSchema", "EveSurfaceCommandRequest", "BuildSceneGraph", "BuildPlayableWorld", "EveUnityPlayableWorldProjection", "EveUnityPlayableWorldEntity", "BuildEmbeddedDocumentSlots", "BuildPluginProjection", "SaiVisualNovelUnitySceneProjectionAdapter", "TeXMathUnitySceneProjectionAdapter", "EveUnitySceneEmbeddedDocumentSlot", "EveUnityScenePluginProjection", "EveUnitySceneNode", "SceneObjectKind", "playable-world-root", "unity-scene"] }, { - "path": "runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneClientSession.cs", + "path": "packages/org.gamecult.eve.unity-scene/Runtime/EveUnitySceneClientSession.cs", "contains": ["EveUnitySceneClientSession", "EveUnitySceneProviderSurfaceSnapshot", "ActiveVersion", "Connect", "ApplySnapshot", "CreateMoveIntent", "CreateFocusIntent", "CreateTargetIntent", "CreateActionIntent", "CreatePlayableWorldIntent", "commandId", "targetPosition", "unity-scene"] }, { - "path": "runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneProviderConnection.cs", + "path": "packages/org.gamecult.eve.unity-scene/Runtime/EveUnitySceneProviderConnection.cs", "contains": ["IEveUnitySceneProviderSurfaceSource", "IEveUnitySceneCommandSink", "IEveUnitySceneProviderSurfaceDocumentSource", "EveUnitySceneProviderSurfaceDocument", "EveUnitySceneProviderSurfaceDocumentSource", "ToSnapshot", "DocumentAvailable", "EveUnitySceneProviderConnection", "SnapshotAvailable", "CurrentSnapshot", "Connect", "Refresh", "SubmitMoveIntent", "SubmitFocusIntent", "SubmitTargetIntent", "SubmitActionIntent", "Disconnect"] }, { - "path": "runtimes/incubating/eve-unity-scene/Runtime/EveUnitySceneLiveProviderBridge.cs", - "contains": ["IEveUnitySceneLiveProviderTransport", "EveUnitySceneLiveProviderTransportBehaviour", "EveUnitySceneLiveProviderBridgeComponent", "EveUnitySceneLiveProviderBridge", "IEveUnitySceneProviderSurfaceDocumentSource", "IEveUnityPlayableWorldAssetManifestDocumentSource", "IEveUnitySceneCommandSink", "IEveUnitySceneCommandReceiptSource", "IEveUnityProviderRefreshSource", "SubmitCommand", "CommandReceiptAvailable", "ShouldRefreshProviderSurface", "transportBehaviour"] + "path": "packages/org.gamecult.eve.unity-scene/Runtime/EveUnitySceneLiveProviderBridge.cs", + "contains": ["IEveUnitySceneLiveProviderTransport", "EveUnitySceneLiveProviderTransportBehaviour", "EveUnitySceneLiveProviderBridgeComponent", "EveUnitySceneLiveProviderBridge", "IEveUnitySceneProviderSurfaceDocumentSource", "IEveUnityPlayableWorldAssetManifestDocumentSource", "IEveUnitySceneCommandSink", "IEveUnitySceneCommandReceiptSource", "IEveUnityProviderRefreshSource", "SubmitCommand", "CommandReceiptAvailable", "transportBehaviour"] }, { - "path": "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldLiveClient.cs", - "contains": ["EveUnityPlayableWorldLiveClient", "IEveUnitySceneCommandReceiptSource", "EveUnitySceneCommandReceipt", "EveUnitySceneProviderConnection", "EveUnityPlayableWorldPresenter", "ActiveWorld", "LastPresentation", "LastReceipt", "ReceiptAvailable", "Connect", "Refresh", "SubmitMoveIntent", "SubmitFocusIntent", "SubmitTargetIntent", "SubmitActionIntent", "ProjectionUpdated", "ShouldRefreshProviderSurface", "IsProviderOwned", "Disconnect"] + "path": "packages/org.gamecult.eve.unity-scene/Runtime/EveUnityPlayableWorldLiveClient.cs", + "contains": ["EveUnityPlayableWorldLiveClient", "IEveUnitySceneCommandReceiptSource", "EveUnitySceneCommandReceipt", "EveUnitySceneProviderConnection", "EveUnityPlayableWorldPresenter", "ActiveWorld", "LastPresentation", "LastReceipt", "ReceiptAvailable", "Connect", "Refresh", "SubmitMoveIntent", "SubmitFocusIntent", "SubmitTargetIntent", "SubmitActionIntent", "ProjectionUpdated", "IsProviderOwned", "Disconnect"] }, { - "path": "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldRuntime.cs", + "path": "packages/org.gamecult.eve.unity-scene/Runtime/EveUnityPlayableWorldRuntime.cs", "contains": ["EveUnityPlayableWorldRuntime", "CreateForGameObjectScene", "EveUnityLivePlayableWorldAssetProvider", "IEveUnitySceneProviderSurfaceDocumentSource", "IEveUnitySceneCommandSink", "IEveUnityPlayableWorldAssetManifestDocumentSource", "IEveUnitySceneCommandReceiptSource", "EveUnityPlayableWorldAssetManifestCache", "AssetManifests", "ActiveWorld", "SubmitMoveIntent", "SubmitMoveVectorIntent", "SubmitFocusIntent", "SubmitTargetIntent", "SubmitActionIntent", "Connect", "Refresh", "Disconnect"] }, { - "path": "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldClientHost.cs", + "path": "packages/org.gamecult.eve.unity-scene/Runtime/EveUnityPlayableWorldClientHost.cs", "contains": ["EveUnityPlayableWorldClientHost", "MonoBehaviour", "providerSurfaceDocuments", "IEveUnitySceneProviderSurfaceDocumentSource", "IEveUnitySceneCommandSink", "IEveUnityPlayableWorldAssetManifestDocumentSource", "IEveUnitySceneCommandReceiptSource", "IEveUnityGameObjectAssetProvider", "IEveUnityProviderRefreshSource", "Configure", "ConnectOnEnable", "CreateForGameObjectScene", "Connect", "Refresh", "SceneRoot", "SubmitMoveIntent", "SubmitMoveVectorIntent", "SubmitFocusIntent", "SubmitTargetIntent", "SubmitActionIntent", "Disconnect"] }, { - "path": "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldClientBootstrap.cs", + "path": "packages/org.gamecult.eve.unity-scene/Runtime/EveUnityPlayableWorldClientBootstrap.cs", "contains": ["EveUnityPlayableWorldClientBootstrap", "ConfigureProvider", "Mount", "ResolveHost", "ResolveSceneRoot", "ResolveCameraTransform", "EveUnityPlayableWorldClientHost", "EveUnityPlayableWorldInputDriver", "EveUnityPlayableWorldCameraRig", "IEveUnitySceneProviderSurfaceDocumentSource", "IEveUnitySceneCommandSink", "IEveUnityPlayableWorldAssetManifestDocumentSource", "IEveUnitySceneCommandReceiptSource", "IEveUnityGameObjectAssetProvider"] }, { - "path": "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldInputDriver.cs", + "path": "packages/org.gamecult.eve.unity-scene/Runtime/EveUnityPlayableWorldInputDriver.cs", "contains": ["EveUnityPlayableWorldInputDriver", "EveUnityPlayableWorldMoveVector", "FromCameraRelativeInput", "SubmitMoveVectorInput", "SubmitPrimaryAction", "Input.GetAxisRaw", "Input.GetButtonDown", "directionX", "directionY", "scalarValue", "SubmitMoveVectorIntent"] }, { - "path": "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldCameraRig.cs", + "path": "packages/org.gamecult.eve.unity-scene/Runtime/EveUnityPlayableWorldCameraRig.cs", "contains": ["EveUnityPlayableWorldCameraRig", "ApplyRig", "arpg.orbital-follow.v1", "EveUnityPlayableWorldEntityMarker", "SceneRoot", "LookAt"] }, { - "path": "runtimes/incubating/eve-unity-scene/Runtime/EveUnityPlayableWorldPresenter.cs", + "path": "packages/org.gamecult.eve.unity-scene/Runtime/EveUnityPlayableWorldPresenter.cs", "contains": ["IEveUnityPlayableWorldSceneSink", "IEveUnityPlayableWorldAssetResolver", "EveUnityPlayableWorldPresenter", "EveUnityPlayableWorldAssetBinding", "EveUnityPlayableWorldPresentation", "EveUnityAssetRefResolver", "ConfigureWorld", "UpsertEntity", "RemoveEntity", "provider-asset-ref", "unity-generated-placeholder"] }, { - "path": "runtimes/incubating/eve-unity-scene/Runtime/EveUnityGameObjectPlayableWorldSceneSink.cs", + "path": "packages/org.gamecult.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", + "path": "packages/org.gamecult.eve.unity-scene/Runtime/EveUnityPlayableWorldAssetManifest.cs", "contains": ["EveUnityPlayableWorldAssetManifest", "IEveUnityPlayableWorldAssetManifestSource", "IEveUnityPlayableWorldAssetManifestDocumentSource", "EveUnityPlayableWorldAssetManifestDocumentSource", "EveUnityPlayableWorldAssetManifestDocument", "EveUnityPlayableWorldAssetManifestDocumentEntry", "FromDocument", "DocumentAvailable", "gamecult.eve.unity_playable_world_asset_manifest.v1", "EveUnityPlayableWorldAssetManifestCache", "EveUnityPlayableWorldAssetManifestEntry", "EveUnityManifestGameObjectAssetProvider", "ManifestAvailable", "GetForWorld", "CreateGameObjectAssetProvider", "ManifestRef", "ResourcesPath", "PrefabKey", "NormalizeResourcesPath", "ResolvePrefab", "Resources.Load"] }, { - "path": "runtimes/incubating/eve-unity-scene/Runtime/SaiVisualNovelUnitySceneProjectionAdapter.cs", + "path": "packages/org.gamecult.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"] }, { - "path": "runtimes/incubating/eve-unity-scene/Runtime/NornGraphUnitySceneProjectionAdapter.cs", + "path": "packages/org.gamecult.eve.unity-scene/Runtime/NornGraphUnitySceneProjectionAdapter.cs", "contains": ["NornGraphUnitySceneProjectionAdapter", "norn.graph", "embed.norn", "gamecult.eve.plugin_abi.v1", "sidecar-advertised-plugin-abi", "Norn"] }, { - "path": "runtimes/incubating/eve-unity-scene/Runtime/TeXMathUnitySceneProjectionAdapter.cs", + "path": "packages/org.gamecult.eve.unity-scene/Runtime/TeXMathUnitySceneProjectionAdapter.cs", "contains": ["TeXMathUnitySceneProjectionAdapter", "tex.math", "embed.tex", "tex.scene-placement", "gamecult.eve.plugin_abi.v1", "sidecar-advertised-plugin-abi", "EvePlugins"] }, { - "path": "runtimes/incubating/eve-unity-scene/Tests/Editor/EveUnitySceneSurfaceLowererTests.cs", + "path": "packages/org.gamecult.eve.unity-scene/Tests/Editor/EveUnitySceneSurfaceLowererTests.cs", "contains": ["LowerCarriesProviderAdvertisedWorldBoundary", "LowerBuildsProviderAgnosticSceneGraphFromSurfaceTree", "LowerExtractsPlayableArpgWorldFromGenericScene3dSurface", "GenericClientSessionConsumesAetheriaPlayableWorldSnapshotWithoutAetheriaTypes", "GenericProviderConnectionAppliesLiveSnapshotsAndSubmitsCommandsThroughSink", "ProviderSurfaceDocumentSourceFeedsPlayableClientWithoutAetheriaTypes", "PlayableWorldRuntimeComposesProviderDocumentsAssetsReceiptsAndSceneSink", "LiveProviderBridgeFeedsPlayableWorldRuntimeThroughTransportPorts", "PlayableWorldClientHostMountsInterfaceProviderWithoutProviderTypes", "PlayableWorldClientBootstrapWiresGenericUnityClientFromProviderInterfaces", "PlayableWorldClientHostSubmitsProviderOwnedMoveVector", "PlayableWorldInputDriverBuildsCameraRelativeMoveVectorWithoutProviderTypes", "PlayableWorldCameraRigFollowsAdvertisedPlayerEntityWithoutProviderTypes", "PlayableWorldPresenterInstantiatesUpdatesAndDespawnsProviderEntities", "LivePlayableWorldClientPresentsProviderSnapshotsAndKeepsCommandsProviderOwned", "LivePlayableWorldClientRefreshesFromProviderSnapshotAfterReceiptWithoutOwningMovement", "AssetManifestMapsProviderAssetRefsToUnityLoadKeysWithoutAetheriaTypes", "AssetManifestCacheTracksPlayableWorldManifestPointerAndLiveUpdates", "AssetManifestDocumentSourceFeedsCacheWithoutChangingSceneLowering", "FakeProviderSurfaceSource", "FakeProviderSurfaceDocumentSource", "FakeCommandReceiptSource", "FakeAssetManifestSource", "FakeAssetManifestDocumentSource", "FakeLiveProviderTransport", "FakeCommandSink", "FakePlayableWorldSceneSink", "FakePlayableWorldProviderComponent", "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", - "contains": ["builds Unity scene capture request from provider advertisement", "builds Unity UI Toolkit capture request from a declared generic world provider", "builds Unity scene capture request from a declared generic world provider", "unity-scene", "artifacts/eveunity-scene-capture/smoke/unity-scene.png", "eve.world-smoke.commands"] - }, - { - "path": "tools/eveunity/eveunity-scene-capture-artifact.mjs", - "contains": ["buildUnitySceneCaptureArtifact", "buildUnitySceneProjection", "buildPlayableWorld", "gamecult.eve.unity_scene_projection.v1", "unity-scene-projection-json", "writeUnitySceneCaptureArtifact", "request-output"] - }, - { - "path": "tools/eveunity/eveunity-scene-capture-artifact.test.mjs", - "contains": ["builds Unity scene projection capture artifact", "builds Unity scene capture artifact for a generic world provider", "marks Sai required and Norn TeX optional sidecar plugin projections", "playableWorld", "arpg-third-person", "aetheria.daemon.move_intent", "gamecult.eve.unity_scene_projection.v1", "unity-scene-projection-json", "optional-nested", "eve.world-smoke.commands"] - }, - { - "path": "tools/eveunity/eveunity-release-contract.test.mjs", - "contains": ["builds EveUnity scene UPM release request from package manifest", "eveunity-scene-v0.1.0", "artifacts/eveunity-scene-release/0.1.0/org.gamecult.eve.unity-scene-0.1.0.tgz"] - }, - { - "path": "tools/eveunity/eveunity-release-artifact.test.mjs", - "contains": ["plans npm pack for the EveUnity scene UPM artifact", "runtimes/incubating/eve-unity-scene", "org.gamecult.eve.unity-scene-0.1.0.tgz"] } ], "capture": { - "status": "json-projection", - "note": "Unity scene attaches a provider-advertisement-backed gamecult.eve.unity_scene_projection.v1 JSON projection artifact; Unity screenshot or frame-capture PNG remains an EveUnity split blocker.", - "artifacts": [ - { - "kind": "json-projection", - "schema": "gamecult.eve.unity_scene_projection.v1", - "path": "artifacts/eveunity-scene-capture/latest/unity-scene-projection.json", - "runtimeId": "unity-scene", - "providerId": "aetheria", - "surfaceId": "aetheria.daemon.game", - "sourceSurfacePath": "web/fixtures/aetheria-world-surface.json", - "requestPath": "artifacts/eveunity-scene-capture/latest/capture-request.json" + "status": "pending-unity-frame-capture", + "note": "A real Unity PNG/frame capture driven by a provider surface remains active lifecycle work.", + "artifacts": [] + }, + "sourceRoot": "../EveUnity", + "currentHostRepo": "EveUnity", + "lifecycle": { + "release": { + "ownerRepo": "EveUnity", + "status": "owner-repo-upm-artifact", + "releaseContract": { + "ownerRepo": "EveUnity", + "packageName": "org.gamecult.eve.unity-scene", + "packageRoot": "packages/org.gamecult.eve.unity-scene", + "versionSource": "packages/org.gamecult.eve.unity-scene/package.json", + "tagPattern": "eveunity-scene-v{version}", + "artifactKind": "upm-package", + "requestSchema": "gamecult.eve.runtime_release_request.v1", + "requestBuilder": "scripts/build-release-request.ps1", + "artifactBuilder": "scripts/pack.ps1", + "artifactPattern": "artifacts/eveunity-scene-release/{version}/org.gamecult.eve.unity-scene-{version}.tgz", + "publishProof": "Tagged Unity scene package release is created from the EveUnity repository.", + "requiredPackageDependencies": [ + { + "packageName": "org.gamecult.eve.surface", + "version": "0.1.0", + "packageManager": "upm", + "ownerRepo": "Eve", + "purpose": "Shared Unity DTOs for gamecult.eve.surface.v1 documents." + } + ] }, - { - "kind": "json-projection", - "schema": "gamecult.eve.unity_scene_projection.v1", - "path": "artifacts/eveunity-scene-capture/latest/eve-world-smoke-unity-scene-projection.json", + "evidencePaths": ["packages/org.gamecult.eve.unity-scene/package.json", "packages/org.gamecult.eve.unity-scene/Runtime/GameCult.Eve.UnityScene.asmdef", "scripts/pack.ps1", "scripts/build-release-request.ps1"], + "pendingProofs": ["Cut and publish the first tagged EveUnity package release."] + }, + "test": { + "ownerRepo": "EveUnity", + "status": "unity-scene-editmode-batchmode", + "testContract": { + "ownerRepo": "EveUnity", + "runnerKind": "unity-editmode-batchmode", + "runnerScript": "scripts/run-package-tests.ps1", + "consumerProject": "E:\\Projects\\Aetheria", + "packageName": "org.gamecult.eve.unity-scene", + "testAssembly": "GameCult.Eve.UnityScene.Tests", + "testPlatform": "EditMode", + "resultsArtifact": "artifacts/aetheria-unity-scene-editmode/{stamp}/unity-editmode-results.xml", + "logArtifact": "artifacts/aetheria-unity-scene-editmode/{stamp}/unity-editmode.log", + "manifestMutation": "Temporarily adds org.gamecult.eve.unity-scene to Aetheria Unity testables, runs GameCult.Eve.UnityScene.Tests, and restores Packages/manifest.json." + }, + "evidencePaths": ["packages/org.gamecult.eve.unity-scene/Tests/Editor/GameCult.Eve.UnityScene.Tests.asmdef", "packages/org.gamecult.eve.unity-scene/Tests/Editor/EveUnitySceneSurfaceLowererTests.cs", "scripts/run-package-tests.ps1"], + "pendingProofs": ["Move the Aetheria consumer scenario into a provider-owned conformance pack that installs EveUnity from its owner repository."] + }, + "capture": { + "ownerRepo": "EveUnity", + "status": "pending-unity-frame-capture", + "captureContract": { + "ownerRepo": "EveUnity", "runtimeId": "unity-scene", - "providerId": "eve.world-smoke", - "surfaceId": "eve.world-smoke.surface", - "sourceSurfacePath": "web/fixtures/eve-world-smoke-surface.json", - "requestPath": "artifacts/eveunity-scene-capture/latest/eve-world-smoke-capture-request.json" - } - ] + "targetId": "unity-scene", + "requestSchema": "gamecult.eve.runtime_capture_request.v1", + "requestBuilder": "scripts/build-capture-request.ps1", + "advertisementPath": "GameCult/Aetheria:web/fixtures/aetheria.provider-advertisement.json", + "captureKind": "unity-scene-frame-png", + "artifactKind": "png", + "artifactPattern": "artifacts/eveunity-scene-capture/{stamp}/unity-scene.png", + "conformanceAttachment": "runtime.captureArtifacts[]", + "requiredProvider": "aetheria", + "requiredSurface": "aetheria.daemon.game", + "additionalProviderSurfaces": [ + { + "providerId": "eve.world-smoke", + "surfaceId": "eve.world-smoke.surface", + "purpose": "Generic non-product interactive-world capture control." + } + ], + "authority": "Capture observes Unity scene projection only; provider state, command acceptance, and receipts stay provider-owned.", + "publishProof": "Unity scene screenshot or frame-capture PNG artifact is attached to the runtime conformance report from EveUnity." + }, + "evidencePaths": ["scripts/build-capture-request.ps1"], + "pendingProofs": ["Unity scene screenshot or frame-capture PNG artifact is attached to the runtime conformance report."] + } } }, { diff --git a/tools/parity/run-parity.mjs b/tools/parity/run-parity.mjs index 1d96187..9a35646 100644 --- a/tools/parity/run-parity.mjs +++ b/tools/parity/run-parity.mjs @@ -274,14 +274,14 @@ async function loadSurface(surface) { async function evaluateRuntime(runtime, fixtureResults) { const expectedPaths = runtime.expectedPaths || []; - const missingPaths = expectedPaths.filter(candidate => !existsSync(path.join(repoRoot, candidate))); + const missingPaths = expectedPaths.filter(candidate => !existsSync(resolveRuntimeOwnedPath(runtime, candidate))); const expectedExternalPaths = runtime.expectedExternalPaths || []; const missingExternalPaths = expectedExternalPaths.filter(candidate => !existsSync(candidate)); const expectedSourceSymbols = runtime.expectedSourceSymbols || []; const missingSourceSymbols = []; for (const expectation of expectedSourceSymbols) { const sourcePath = expectation.path || ""; - const absolutePath = path.join(repoRoot, sourcePath); + const absolutePath = resolveRuntimeOwnedPath(runtime, sourcePath); if (!existsSync(absolutePath)) { missingSourceSymbols.push(`${sourcePath}:missing`); continue; @@ -404,7 +404,7 @@ async function readRuntimeCapabilityManifestDocument(runtime) { const manifestPath = runtime.capabilityManifest?.manifestPath; if (!manifestPath) return null; try { - return await readJsonDocument(manifestPath); + return JSON.parse(await readFile(resolveRuntimeOwnedPath(runtime, manifestPath), "utf8")); } catch { return null; } @@ -477,7 +477,7 @@ async function validateRuntimeLifecycle(runtime, lifecycle, lifecycleDocument) { for (const stage of ["release", "test", "capture"]) { const stageDocument = lifecycle[stage]; for (const evidencePath of stageDocument?.evidencePaths || []) { - if (!existsSync(path.join(repoRoot, evidencePath))) { + if (!existsSync(resolveRuntimeOwnedPath(runtime, evidencePath))) { errors.push(`lifecycle.${stage}.evidence:${evidencePath}:missing`); } } @@ -1419,13 +1419,14 @@ async function validateRuntimeCapabilityManifest(runtime) { const capabilityManifest = runtime.capabilityManifest; if (!capabilityManifest) return []; - const errors = await validateJsonDocument(capabilityManifest.schemaPath, capabilityManifest.manifestPath, { + const manifestDocumentPath = path.relative(repoRoot, resolveRuntimeOwnedPath(runtime, capabilityManifest.manifestPath)); + const errors = await validateJsonDocument(capabilityManifest.schemaPath, manifestDocumentPath, { schema: "gamecult.eve.runtime_capability.v1", runtimeId: runtime.id, }); if (errors.length) return errors; - const documentPath = path.join(repoRoot, capabilityManifest.manifestPath); + const documentPath = resolveRuntimeOwnedPath(runtime, capabilityManifest.manifestPath); const document = JSON.parse(await readFile(documentPath, "utf8")); const supportedFeatures = document.supportedFeatures || []; const supportedPlugins = document.supportedPlugins || []; @@ -1449,6 +1450,7 @@ async function validateRuntimeCapabilityManifest(runtime) { runtime.worldSurfaceLowering || [], worldSurfaceLowering, `${capabilityManifest.manifestPath}:worldSurfaceLowering`, + runtime, )); const expectedCommandSchema = runtimeCommandTransportSchema(runtime); @@ -1472,12 +1474,13 @@ async function validateRuntimeCapabilityManifest(runtime) { runtime.lifecycle || {}, lifecycle, capabilityManifest.manifestPath, + runtime, )); return errors; } -function compareWorldSurfaceLoweringClaims(expectedClaims, actualClaims, label) { +function compareWorldSurfaceLoweringClaims(expectedClaims, actualClaims, label, runtime) { const errors = []; const actualByTarget = new Map((actualClaims || []).map(claim => [claim.targetId, claim])); for (const expected of expectedClaims || []) { @@ -1495,7 +1498,7 @@ function compareWorldSurfaceLoweringClaims(expectedClaims, actualClaims, label) errors.push(...missingMembers(expected.projectionKinds || [], actual.projectionKinds || [], `${label}:${expected.targetId}.projectionKinds`)); errors.push(...missingMembers(expected.evidencePaths || [], actual.evidencePaths || [], `${label}:${expected.targetId}.evidencePaths`)); for (const evidencePath of actual.evidencePaths || []) { - if (!existsSync(path.join(repoRoot, evidencePath))) { + if (!existsSync(resolveRuntimeOwnedPath(runtime, evidencePath))) { errors.push(`${label}:${expected.targetId}.evidencePath:${evidencePath}:missing`); } } @@ -1503,7 +1506,7 @@ function compareWorldSurfaceLoweringClaims(expectedClaims, actualClaims, label) return errors; } -function compareRuntimeLifecycleClaims(expectedLifecycle, actualLifecycle, manifestPath) { +function compareRuntimeLifecycleClaims(expectedLifecycle, actualLifecycle, manifestPath, runtime) { const errors = []; for (const stage of ["release", "test", "capture"]) { const expected = expectedLifecycle[stage]; @@ -1523,12 +1526,12 @@ function compareRuntimeLifecycleClaims(expectedLifecycle, actualLifecycle, manif errors.push(...missingMembers(expected.evidencePaths || [], actual.evidencePaths || [], `${label}.evidencePaths`)); errors.push(...missingMembers(expected.pendingProofs || [], actual.pendingProofs || [], `${label}.pendingProofs`)); - errors.push(...compareReleaseContract(expected.releaseContract, actual.releaseContract, `${label}.releaseContract`)); - errors.push(...compareTestContract(expected.testContract, actual.testContract, `${label}.testContract`)); + errors.push(...compareReleaseContract(expected.releaseContract, actual.releaseContract, `${label}.releaseContract`, runtime)); + errors.push(...compareTestContract(expected.testContract, actual.testContract, `${label}.testContract`, runtime)); errors.push(...compareCaptureContract(expected.captureContract, actual.captureContract, `${label}.captureContract`)); for (const evidencePath of actual.evidencePaths || []) { - if (!existsSync(path.join(repoRoot, evidencePath))) { + if (!existsSync(resolveRuntimeOwnedPath(runtime, evidencePath))) { errors.push(`${label}.evidencePaths:${evidencePath}:missing`); } } @@ -1576,7 +1579,7 @@ function captureSurfaceClaimKeys(claims) { .filter(claim => claim !== ":"); } -function compareTestContract(expected, actual, label) { +function compareTestContract(expected, actual, label, runtime) { const errors = []; if (!expected) return errors; if (!actual) return [`${label}:missing`]; @@ -1597,7 +1600,7 @@ function compareTestContract(expected, actual, label) { errors.push(`${label}.${key}:expected ${expected[key] || ""} got ${actual[key] || ""}`); } } - if (actual.runnerScript && !existsSync(path.join(repoRoot, actual.runnerScript))) { + if (actual.runnerScript && !existsSync(resolveRuntimeOwnedPath(runtime, actual.runnerScript))) { errors.push(`${label}.runnerScript:${actual.runnerScript}:missing`); } if (actual.consumerProject && !existsSync(actual.consumerProject)) { @@ -1625,7 +1628,7 @@ function compareTestContract(expected, actual, label) { return errors; } -function compareReleaseContract(expected, actual, label) { +function compareReleaseContract(expected, actual, label, runtime) { const errors = []; if (!expected) return errors; if (!actual) return [`${label}:missing`]; @@ -1638,7 +1641,7 @@ function compareReleaseContract(expected, actual, label) { errors.push(`${label}.requestSchema:${actual.requestSchema}:missing-schema-catalog-entry`); } for (const key of ["packageRoot", "versionSource", "requestBuilder", "artifactBuilder"]) { - if (actual[key] && !existsSync(path.join(repoRoot, actual[key]))) { + if (actual[key] && !existsSync(resolveRuntimeOwnedPath(runtime, actual[key]))) { errors.push(`${label}.${key}:${actual[key]}:missing`); } } @@ -1651,6 +1654,13 @@ function compareReleaseContract(expected, actual, label) { return errors; } +function resolveRuntimeOwnedPath(runtime, candidate) { + if (!candidate) return repoRoot; + if (path.isAbsolute(candidate)) return candidate; + const sourceRoot = runtime?.sourceRoot || "."; + return path.resolve(repoRoot, sourceRoot, candidate); +} + function compareDependencyRecords(expectedRecords, actualRecords, label, keys) { const errors = []; for (const expected of expectedRecords) {