From f6fb8a5b1788bbc9456a0127c6c350bceaed7375 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 15 Jul 2026 11:04:11 +0100 Subject: [PATCH] Record released tractor beam witness --- .../PlayMode/GenericWorldCaptureTests.cs | 57 ++++++++++++++++++- ReleaseConsumerProject/Packages/manifest.json | 2 +- .../Packages/packages-lock.json | 13 ++++- .../PlayMode/GenericWorldCaptureTests.cs | 57 ++++++++++++++++++- docs/aetheria-released-package-witness.md | 32 +++++++---- scripts/run-aetheria-daemon-world-witness.ps1 | 2 +- 6 files changed, 144 insertions(+), 19 deletions(-) diff --git a/ReleaseConsumerProject/Assets/Tests/PlayMode/GenericWorldCaptureTests.cs b/ReleaseConsumerProject/Assets/Tests/PlayMode/GenericWorldCaptureTests.cs index addc5a0..050ab02 100644 --- a/ReleaseConsumerProject/Assets/Tests/PlayMode/GenericWorldCaptureTests.cs +++ b/ReleaseConsumerProject/Assets/Tests/PlayMode/GenericWorldCaptureTests.cs @@ -191,6 +191,7 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests WitnessReceipt movementReceipt = null; WitnessReceipt lookReceipt = null; WitnessReceipt focusReceipt = null; + WitnessReceipt tractorReceipt = null; WitnessReceipt actionReceipt = null; EveUnityShotReceipt observedShot = null; EveUnityCombatPresentation observedCombat = null; @@ -200,6 +201,8 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests float movementDistance = 0f; float aimDotDistance = 0f; int cockpitProgressCount = 0; + float tractorBeamPower = 0f; + int tractorBeamParticleSystemCount = 0; try { @@ -245,7 +248,7 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests var cockpit = loweredSurface.Q("aetheria.daemon.game.cockpit"); Assert.That(cockpit, Is.Not.Null, "The provider did not publish a generic cockpit overlay."); cockpitProgressCount = cockpit.Query().ToList().Count; - Assert.That(cockpitProgressCount, Is.GreaterThanOrEqualTo(6)); + Assert.That(cockpitProgressCount, Is.GreaterThanOrEqualTo(7)); Assert.That(loweredSurface.Q("aetheria.daemon.game.frame").style.display.value, Is.EqualTo(DisplayStyle.None), "Daemon diagnostics leaked into the pilot UI."); host.ShotAvailable += shot => observedShot = shot; @@ -376,6 +379,44 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests var aimRenderer = root.GetComponent(); Assert.That(aimRenderer, Is.Not.Null); + var beamPresentation = EveUnityBeamPresentation.FindAll(runtime.ActiveProjection).SingleOrDefault(); + Assert.That(beamPresentation, Is.Not.Null, + "The provider did not advertise its continuous beam presentation."); + Assert.That(beamPresentation.ActivationActionId, Is.Not.Empty, + "The beam presentation does not name an advertised generic action."); + var tractorVersion = runtime.ActiveVersion; + var tractor = host.SubmitAdvertisedActionIntent(playerId, beamPresentation.ActivationActionId); + var tractorDeadline = Time.realtimeSinceStartup + 12f; + while (Time.realtimeSinceStartup < tractorDeadline && + (runtime.LastReceipt == null || runtime.LastReceipt.CommandId != tractor.CommandId || + !string.Equals(runtime.LastReceipt.State, "reconciled", StringComparison.OrdinalIgnoreCase) || + runtime.ActiveVersion < runtime.LastReceipt.SourceVersion || + EveUnityBeamPresentation.FindAll(runtime.ActiveProjection).Single().Power <= + beamPresentation.ActivationThreshold)) + { + yield return new WaitForSecondsRealtime(0.1f); + runtime.Refresh(); + } + AssertReconciledProviderReceipt(runtime.LastReceipt, tractor.CommandId, + provider.Selection.ProviderId, provider.Selection.SurfaceId, tractorVersion); + tractorReceipt = WitnessReceipt.From("beam", runtime.LastReceipt); + Assert.That(beamPresentation.SourceEntityId, Is.EqualTo(playerId), + "The daemon beam source does not identify the presented player entity."); + Assert.That(host.PresentedEntities.TryGetByEntityId(beamPresentation.SourceEntityId, out _), Is.True, + "The generic beam lowerer cannot resolve the advertised source entity."); + Assert.That(provider.ResolvePrefab(new EveUnityPlayableWorldAssetBinding( + beamPresentation.AssetRole, beamPresentation.AssetRole, "provider-asset-ref")), Is.Not.Null, + $"The provider asset catalog did not resolve beam role '{beamPresentation.AssetRole}'."); + var beamRenderer = root.GetComponent(); + Assert.That(beamRenderer, Is.Not.Null); + beamRenderer.RefreshNow(); + Assert.That(beamRenderer.ActiveBeamCount, Is.EqualTo(1)); + Assert.That(beamRenderer.TryGetPower(beamPresentation.Id, out tractorBeamPower), Is.True); + Assert.That(tractorBeamPower, Is.GreaterThan(beamPresentation.ActivationThreshold)); + tractorBeamParticleSystemCount = beamRenderer.ActiveParticleSystemCount; + Assert.That(tractorBeamParticleSystemCount, Is.GreaterThan(0), + "The generic beam lowerer did not instantiate the provider-owned effect prefab."); + var focusVersion = runtime.ActiveVersion; var inputDriver = root.GetComponent() ?? root.AddComponent(); @@ -573,6 +614,7 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests movementReceipt, lookReceipt, focusReceipt, + tractorReceipt, actionReceipt, observedShot, shieldRatioBefore, @@ -588,6 +630,8 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests pilotAverageLuminance, pilotBrightPixelCount, cockpitProgressCount, + tractorBeamPower, + tractorBeamParticleSystemCount, playerRendererFacts); } finally @@ -620,6 +664,7 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests WitnessReceipt movement, WitnessReceipt look, WitnessReceipt targeting, + WitnessReceipt tractor, WitnessReceipt action, EveUnityShotReceipt shot, float shieldRatioBefore, @@ -635,6 +680,8 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests float pilotAverageLuminance, int pilotBrightPixelCount, int cockpitProgressCount, + float tractorBeamPower, + int tractorBeamParticleSystemCount, RendererFact[] playerRendererFacts) { var path = Environment.GetEnvironmentVariable("EVEUNITY_WITNESS_FACTS_PATH"); @@ -647,6 +694,7 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests movement = movement != null, aimPresentation = look != null && aimDotDistance >= 49.9f, targeting = targeting != null, + beamPresentation = tractor != null && tractorBeamPower > 0.01f && tractorBeamParticleSystemCount > 0, action = action != null, combatPresentation = shot != null, shotId = shot?.ShotId ?? "", @@ -672,12 +720,14 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests pilotAverageLuminance = pilotAverageLuminance, pilotBrightPixelCount = pilotBrightPixelCount, cockpitProgressCount = cockpitProgressCount, + tractorBeamPower = tractorBeamPower, + tractorBeamParticleSystemCount = tractorBeamParticleSystemCount, playerRenderers = playerRendererFacts, mapChannelRendererCount = mapChannelRendererCount, mapChangedPixels = mapChangedPixels, pilotCameraExcludesMapChannel = pilotCameraExcludesMapChannel, mapCameraIncludesMapChannel = mapCameraIncludesMapChannel, - receipts = new[] { movement, look, targeting, action } + receipts = new[] { movement, look, targeting, tractor, action } }; Directory.CreateDirectory(Path.GetDirectoryName(Path.GetFullPath(path))); File.WriteAllText(path, JsonUtility.ToJson(document, true)); @@ -692,6 +742,7 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests public bool movement; public bool aimPresentation; public bool targeting; + public bool beamPresentation; public bool action; public bool combatPresentation; public string shotId; @@ -717,6 +768,8 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests public float pilotAverageLuminance; public int pilotBrightPixelCount; public int cockpitProgressCount; + public float tractorBeamPower; + public int tractorBeamParticleSystemCount; public RendererFact[] playerRenderers; public int mapChannelRendererCount; public int mapChangedPixels; diff --git a/ReleaseConsumerProject/Packages/manifest.json b/ReleaseConsumerProject/Packages/manifest.json index cdbd57c..1dfc17c 100644 --- a/ReleaseConsumerProject/Packages/manifest.json +++ b/ReleaseConsumerProject/Packages/manifest.json @@ -9,7 +9,7 @@ "org.gamecult.cultlib": "https://github.com/GameCult/CultLib.git?path=/unity/org.gamecult.cultlib#cultlib-unity-v1.0.13", "org.gamecult.eve.plugin-fields": "https://github.com/GameCult/EvePlugins.git?path=/plugins/eve-plugin-fields/unity/org.gamecult.eve.plugin-fields#eve-plugin-fields-unity-v0.1.1", "org.gamecult.eve.surface": "https://github.com/GameCult/EveUnity.git?path=/packages/org.gamecult.eve.surface#eveunity-surface-v0.2.1", - "org.gamecult.eve.unity-scene": "https://github.com/GameCult/EveUnity.git?path=/packages/org.gamecult.eve.unity-scene#eveunity-scene-v0.3.27", + "org.gamecult.eve.unity-scene": "https://github.com/GameCult/EveUnity.git?path=/packages/org.gamecult.eve.unity-scene#eveunity-scene-v0.3.30", "org.gamecult.eve.unity-uitoolkit": "https://github.com/GameCult/EveUnity.git?path=/packages/org.gamecult.eve.unity-uitoolkit#eveunity-uitoolkit-v0.1.1" }, "testables": [ diff --git a/ReleaseConsumerProject/Packages/packages-lock.json b/ReleaseConsumerProject/Packages/packages-lock.json index 5979111..269434a 100644 --- a/ReleaseConsumerProject/Packages/packages-lock.json +++ b/ReleaseConsumerProject/Packages/packages-lock.json @@ -142,16 +142,17 @@ "hash": "d0aa50d31f3b6da96bffc194fdc3aa358f37e332" }, "org.gamecult.eve.unity-scene": { - "version": "https://github.com/GameCult/EveUnity.git?path=/packages/org.gamecult.eve.unity-scene#eveunity-scene-v0.3.27", + "version": "https://github.com/GameCult/EveUnity.git?path=/packages/org.gamecult.eve.unity-scene#eveunity-scene-v0.3.30", "depth": 0, "source": "git", "dependencies": { "org.gamecult.cultlib": "1.0.13", "org.gamecult.eve.plugin-fields": "0.1.1", "org.gamecult.eve.surface": "0.2.1", - "com.unity.mathematics": "1.3.2" + "com.unity.mathematics": "1.3.2", + "com.unity.modules.particlesystem": "1.0.0" }, - "hash": "63a41712c5a68ce835bc1820980fc4786c34eb7b" + "hash": "f979cd425a9f8f951736c56051e8368b6d6ac2f3" }, "org.gamecult.eve.unity-uitoolkit": { "version": "https://github.com/GameCult/EveUnity.git?path=/packages/org.gamecult.eve.unity-uitoolkit#eveunity-uitoolkit-v0.1.1", @@ -192,6 +193,12 @@ "source": "builtin", "dependencies": {} }, + "com.unity.modules.particlesystem": { + "version": "1.0.0", + "depth": 1, + "source": "builtin", + "dependencies": {} + }, "com.unity.modules.physics": { "version": "1.0.0", "depth": 0, diff --git a/TestProject/Assets/Tests/PlayMode/GenericWorldCaptureTests.cs b/TestProject/Assets/Tests/PlayMode/GenericWorldCaptureTests.cs index addc5a0..050ab02 100644 --- a/TestProject/Assets/Tests/PlayMode/GenericWorldCaptureTests.cs +++ b/TestProject/Assets/Tests/PlayMode/GenericWorldCaptureTests.cs @@ -191,6 +191,7 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests WitnessReceipt movementReceipt = null; WitnessReceipt lookReceipt = null; WitnessReceipt focusReceipt = null; + WitnessReceipt tractorReceipt = null; WitnessReceipt actionReceipt = null; EveUnityShotReceipt observedShot = null; EveUnityCombatPresentation observedCombat = null; @@ -200,6 +201,8 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests float movementDistance = 0f; float aimDotDistance = 0f; int cockpitProgressCount = 0; + float tractorBeamPower = 0f; + int tractorBeamParticleSystemCount = 0; try { @@ -245,7 +248,7 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests var cockpit = loweredSurface.Q("aetheria.daemon.game.cockpit"); Assert.That(cockpit, Is.Not.Null, "The provider did not publish a generic cockpit overlay."); cockpitProgressCount = cockpit.Query().ToList().Count; - Assert.That(cockpitProgressCount, Is.GreaterThanOrEqualTo(6)); + Assert.That(cockpitProgressCount, Is.GreaterThanOrEqualTo(7)); Assert.That(loweredSurface.Q("aetheria.daemon.game.frame").style.display.value, Is.EqualTo(DisplayStyle.None), "Daemon diagnostics leaked into the pilot UI."); host.ShotAvailable += shot => observedShot = shot; @@ -376,6 +379,44 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests var aimRenderer = root.GetComponent(); Assert.That(aimRenderer, Is.Not.Null); + var beamPresentation = EveUnityBeamPresentation.FindAll(runtime.ActiveProjection).SingleOrDefault(); + Assert.That(beamPresentation, Is.Not.Null, + "The provider did not advertise its continuous beam presentation."); + Assert.That(beamPresentation.ActivationActionId, Is.Not.Empty, + "The beam presentation does not name an advertised generic action."); + var tractorVersion = runtime.ActiveVersion; + var tractor = host.SubmitAdvertisedActionIntent(playerId, beamPresentation.ActivationActionId); + var tractorDeadline = Time.realtimeSinceStartup + 12f; + while (Time.realtimeSinceStartup < tractorDeadline && + (runtime.LastReceipt == null || runtime.LastReceipt.CommandId != tractor.CommandId || + !string.Equals(runtime.LastReceipt.State, "reconciled", StringComparison.OrdinalIgnoreCase) || + runtime.ActiveVersion < runtime.LastReceipt.SourceVersion || + EveUnityBeamPresentation.FindAll(runtime.ActiveProjection).Single().Power <= + beamPresentation.ActivationThreshold)) + { + yield return new WaitForSecondsRealtime(0.1f); + runtime.Refresh(); + } + AssertReconciledProviderReceipt(runtime.LastReceipt, tractor.CommandId, + provider.Selection.ProviderId, provider.Selection.SurfaceId, tractorVersion); + tractorReceipt = WitnessReceipt.From("beam", runtime.LastReceipt); + Assert.That(beamPresentation.SourceEntityId, Is.EqualTo(playerId), + "The daemon beam source does not identify the presented player entity."); + Assert.That(host.PresentedEntities.TryGetByEntityId(beamPresentation.SourceEntityId, out _), Is.True, + "The generic beam lowerer cannot resolve the advertised source entity."); + Assert.That(provider.ResolvePrefab(new EveUnityPlayableWorldAssetBinding( + beamPresentation.AssetRole, beamPresentation.AssetRole, "provider-asset-ref")), Is.Not.Null, + $"The provider asset catalog did not resolve beam role '{beamPresentation.AssetRole}'."); + var beamRenderer = root.GetComponent(); + Assert.That(beamRenderer, Is.Not.Null); + beamRenderer.RefreshNow(); + Assert.That(beamRenderer.ActiveBeamCount, Is.EqualTo(1)); + Assert.That(beamRenderer.TryGetPower(beamPresentation.Id, out tractorBeamPower), Is.True); + Assert.That(tractorBeamPower, Is.GreaterThan(beamPresentation.ActivationThreshold)); + tractorBeamParticleSystemCount = beamRenderer.ActiveParticleSystemCount; + Assert.That(tractorBeamParticleSystemCount, Is.GreaterThan(0), + "The generic beam lowerer did not instantiate the provider-owned effect prefab."); + var focusVersion = runtime.ActiveVersion; var inputDriver = root.GetComponent() ?? root.AddComponent(); @@ -573,6 +614,7 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests movementReceipt, lookReceipt, focusReceipt, + tractorReceipt, actionReceipt, observedShot, shieldRatioBefore, @@ -588,6 +630,8 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests pilotAverageLuminance, pilotBrightPixelCount, cockpitProgressCount, + tractorBeamPower, + tractorBeamParticleSystemCount, playerRendererFacts); } finally @@ -620,6 +664,7 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests WitnessReceipt movement, WitnessReceipt look, WitnessReceipt targeting, + WitnessReceipt tractor, WitnessReceipt action, EveUnityShotReceipt shot, float shieldRatioBefore, @@ -635,6 +680,8 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests float pilotAverageLuminance, int pilotBrightPixelCount, int cockpitProgressCount, + float tractorBeamPower, + int tractorBeamParticleSystemCount, RendererFact[] playerRendererFacts) { var path = Environment.GetEnvironmentVariable("EVEUNITY_WITNESS_FACTS_PATH"); @@ -647,6 +694,7 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests movement = movement != null, aimPresentation = look != null && aimDotDistance >= 49.9f, targeting = targeting != null, + beamPresentation = tractor != null && tractorBeamPower > 0.01f && tractorBeamParticleSystemCount > 0, action = action != null, combatPresentation = shot != null, shotId = shot?.ShotId ?? "", @@ -672,12 +720,14 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests pilotAverageLuminance = pilotAverageLuminance, pilotBrightPixelCount = pilotBrightPixelCount, cockpitProgressCount = cockpitProgressCount, + tractorBeamPower = tractorBeamPower, + tractorBeamParticleSystemCount = tractorBeamParticleSystemCount, playerRenderers = playerRendererFacts, mapChannelRendererCount = mapChannelRendererCount, mapChangedPixels = mapChangedPixels, pilotCameraExcludesMapChannel = pilotCameraExcludesMapChannel, mapCameraIncludesMapChannel = mapCameraIncludesMapChannel, - receipts = new[] { movement, look, targeting, action } + receipts = new[] { movement, look, targeting, tractor, action } }; Directory.CreateDirectory(Path.GetDirectoryName(Path.GetFullPath(path))); File.WriteAllText(path, JsonUtility.ToJson(document, true)); @@ -692,6 +742,7 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests public bool movement; public bool aimPresentation; public bool targeting; + public bool beamPresentation; public bool action; public bool combatPresentation; public string shotId; @@ -717,6 +768,8 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests public float pilotAverageLuminance; public int pilotBrightPixelCount; public int cockpitProgressCount; + public float tractorBeamPower; + public int tractorBeamParticleSystemCount; public RendererFact[] playerRenderers; public int mapChannelRendererCount; public int mapChangedPixels; diff --git a/docs/aetheria-released-package-witness.md b/docs/aetheria-released-package-witness.md index d84581a..0bb254b 100644 --- a/docs/aetheria-released-package-witness.md +++ b/docs/aetheria-released-package-witness.md @@ -4,8 +4,8 @@ The warm-cache released-package witness passes with: -- `org.gamecult.eve.unity-scene` `0.3.27`, commit - `63a41712c5a68ce835bc1820980fc4786c34eb7b`; +- `org.gamecult.eve.unity-scene` `0.3.30`, commit + `f979cd425a9f8f951736c56051e8368b6d6ac2f3`; - `org.gamecult.eve.unity-uitoolkit` `0.1.1`, commit `4d0cbe0185bdc4fc65eb63503a7c5cb578539669`; - `org.gamecult.cultlib` `1.0.13`, commit @@ -14,8 +14,8 @@ The warm-cache released-package witness passes with: Aetheria daemon. Evidence is in `artifacts/aetheria-daemon-native-0326-warm`. The PlayMode test -passed and recorded provider-owned reconciled movement, look, targeting, and -action receipts. The daemon-owned look direction reached the SoA body rotation, +passed and recorded provider-owned reconciled movement, look, targeting, +tractor, and action receipts. The daemon-owned look direction reached the SoA body rotation, and the generic aim presentation rendered at the advertised 50-unit minimum convergence distance. The advertised skybox material and reflection cubemap resolved from the provider bundle as their required native types and became the @@ -43,13 +43,15 @@ daemon lock progress `1.0`; Unity does not manufacture or smooth that value. Camera-channel facts: -- provider-authored player renderers: `12`; -- pilot changed pixels: `230,189`; -- pilot average luminance: `0.003343`; -- pilot bright pixels: `1,227`; +- provider-authored player renderers: `14`, including the lowered tractor effect; +- pilot changed pixels: `230,255`; +- pilot average luminance: `0.004634`; +- pilot bright pixels: `1,542`; - map-channel renderers: `11`; -- map changed pixels: `6,246`; +- map changed pixels: `8,510`; - native cockpit progress bars: `7`; +- daemon tractor power at capture: `0.24`; +- provider tractor particle systems: `1`; - the pilot camera excludes the advertised map layer; - the player prefab's embedded layer-14 map icon contributes exactly `0` pilot pixels; @@ -71,6 +73,14 @@ resolves textured native URP materials in `9` distinct player-material slots, up from `3`, without adding another texture payload. This is temporary provider art with recorded provenance, not a replacement texture pipeline. +The tractor proof is structural, not yet a native-look victory lap. The daemon +publishes `beam.presentation`, the generic client routes `pilot.scoop` through +the advertised `SetTractorPower` operation and payload, and the provider-owned +prefab is attached to the SoA-presented ship with nonzero daemon power. Its +particle renderer contributes only one measured pilot pixel in this capture. +Effect tuning remains provider art work; the runtime must not compensate with +an Aetheria-specific beam. + Primary artifacts: - `results.xml`: one passing PlayMode witness; @@ -81,7 +91,9 @@ Primary artifacts: ## Cold delivery is not currently proven -The current 46.1 MB Unity bundle times out from an empty cache. Its bytes are +The current `46,133,487` byte Unity bundle (SHA-256 +`ff07aa7f71aa2da0e8e6fe2f4ed68900931d6e67c153b586777467316d4fb80f`) +times out from an empty cache. Its bytes are still transported through batched snapshot records rather than the intended mapped/network body transport. Increasing the Unity timeout would hide the transport fault and is not an accepted fix. diff --git a/scripts/run-aetheria-daemon-world-witness.ps1 b/scripts/run-aetheria-daemon-world-witness.ps1 index 4512bbe..3069618 100644 --- a/scripts/run-aetheria-daemon-world-witness.ps1 +++ b/scripts/run-aetheria-daemon-world-witness.ps1 @@ -13,7 +13,7 @@ param( ) $ErrorActionPreference = "Stop" -$expectedEveUnityCommit = "63a41712c5a68ce835bc1820980fc4786c34eb7b" +$expectedEveUnityCommit = "f979cd425a9f8f951736c56051e8368b6d6ac2f3" $expectedEveUnityUiToolkitCommit = "4d0cbe0185bdc4fc65eb63503a7c5cb578539669" $expectedCultLibCommit = "feb5c71513e71d681699f462fe3682b3168c6f73" $repoRoot = Split-Path -Parent $PSScriptRoot