diff --git a/ReleaseConsumerProject/Assets/Tests/PlayMode/GenericWorldCaptureTests.cs b/ReleaseConsumerProject/Assets/Tests/PlayMode/GenericWorldCaptureTests.cs index 307e961..91c7643 100644 --- a/ReleaseConsumerProject/Assets/Tests/PlayMode/GenericWorldCaptureTests.cs +++ b/ReleaseConsumerProject/Assets/Tests/PlayMode/GenericWorldCaptureTests.cs @@ -305,9 +305,8 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests Assert.That(provider.Selection.VerseId, Is.Not.Empty); Assert.That(provider.Selection.ProviderId, Is.Not.Empty); Assert.That(provider.Selection.SurfaceId, Is.Not.Empty); - Assert.That(provider.CurrentAssetBodyTransportKind, - Is.EqualTo(CultMeshBodyTransportKind.SharedFileMapping), - "The generic client did not negotiate its verified provider bundle as a mapped body."); + Assert.That(provider.CurrentAssetBodyTransportKind, Is.Null, + "Publishing the provider catalog eagerly transferred an asset bundle."); host = root.AddComponent(); host.Configure( root.transform, @@ -376,6 +375,9 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests "provider-asset-ref")); Assert.That(playerPrefab, Is.Not.Null, $"Provider asset catalog did not resolve player AssetRef '{playerFact.AssetRef}'."); + Assert.That(provider.CurrentAssetBodyTransportKind, + Is.EqualTo(CultMeshBodyTransportKind.SharedFileMapping), + "The first requested provider bundle was not negotiated as a mapped body."); var marker = FindMarker(root, playerId); Assert.That( marker.GetComponentsInChildren(includeInactive: true).Length, diff --git a/ReleaseConsumerProject/Packages/manifest.json b/ReleaseConsumerProject/Packages/manifest.json index 1a69088..37567c8 100644 --- a/ReleaseConsumerProject/Packages/manifest.json +++ b/ReleaseConsumerProject/Packages/manifest.json @@ -6,10 +6,10 @@ "com.unity.modules.physics": "1.0.0", "com.unity.modules.uielements": "1.0.0", "com.unity.render-pipelines.universal": "17.4.0", - "org.gamecult.cultlib": "https://github.com/GameCult/CultLib.git?path=/unity/org.gamecult.cultlib#cultlib-unity-v1.0.34", + "org.gamecult.cultlib": "https://github.com/GameCult/CultLib.git?path=/unity/org.gamecult.cultlib#cultlib-unity-v1.0.35", "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.2.3", "org.gamecult.eve.surface": "https://github.com/GameCult/EveUnity.git?path=/packages/org.gamecult.eve.surface#eveunity-surface-v0.2.4", - "org.gamecult.eve.unity-scene": "https://github.com/GameCult/EveUnity.git?path=/packages/org.gamecult.eve.unity-scene#eveunity-scene-v0.3.94", + "org.gamecult.eve.unity-scene": "https://github.com/GameCult/EveUnity.git?path=/packages/org.gamecult.eve.unity-scene#eveunity-scene-v0.3.96", "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 b02e97b..5086900 100644 --- a/ReleaseConsumerProject/Packages/packages-lock.json +++ b/ReleaseConsumerProject/Packages/packages-lock.json @@ -119,11 +119,11 @@ } }, "org.gamecult.cultlib": { - "version": "https://github.com/GameCult/CultLib.git?path=/unity/org.gamecult.cultlib#cultlib-unity-v1.0.34", + "version": "https://github.com/GameCult/CultLib.git?path=/unity/org.gamecult.cultlib#cultlib-unity-v1.0.35", "depth": 0, "source": "git", "dependencies": {}, - "hash": "c148d891c1d8713285ae15b2f17b59c106fb9426" + "hash": "36a822d91416d7fecd4f3e67259186e45cf7cdaa" }, "org.gamecult.eve.plugin-fields": { "version": "https://github.com/GameCult/EvePlugins.git?path=/plugins/eve-plugin-fields/unity/org.gamecult.eve.plugin-fields#eve-plugin-fields-unity-v0.2.3", @@ -144,18 +144,18 @@ "hash": "e08fa08335f99e9edddeb706912eecfad07cb281" }, "org.gamecult.eve.unity-scene": { - "version": "https://github.com/GameCult/EveUnity.git?path=/packages/org.gamecult.eve.unity-scene#eveunity-scene-v0.3.94", + "version": "https://github.com/GameCult/EveUnity.git?path=/packages/org.gamecult.eve.unity-scene#eveunity-scene-v0.3.96", "depth": 0, "source": "git", "dependencies": { - "org.gamecult.cultlib": "1.0.34", + "org.gamecult.cultlib": "1.0.35", "org.gamecult.eve.plugin-fields": "0.2.3", "org.gamecult.eve.surface": "0.2.4", "com.unity.mathematics": "1.3.2", "com.unity.render-pipelines.universal": "17.4.0", "com.unity.modules.particlesystem": "1.0.0" }, - "hash": "0463ddff4e39c9cca14e632b7e46b6b0081c67cc" + "hash": "3da246aba8ee24af1c2528fe1c81b41a51a41c64" }, "org.gamecult.eve.unity-uitoolkit": { "version": "https://github.com/GameCult/EveUnity.git?path=/packages/org.gamecult.eve.unity-uitoolkit#eveunity-uitoolkit-v0.1.1", diff --git a/TestProject/Assets/Tests/PlayMode/GenericWorldCaptureTests.cs b/TestProject/Assets/Tests/PlayMode/GenericWorldCaptureTests.cs index 3bc6852..91c7643 100644 --- a/TestProject/Assets/Tests/PlayMode/GenericWorldCaptureTests.cs +++ b/TestProject/Assets/Tests/PlayMode/GenericWorldCaptureTests.cs @@ -16,6 +16,7 @@ using UnityEngine.Rendering; using UnityEngine.Rendering.Universal; using UnityEngine.TestTools; using UnityEngine.UIElements; +using Stopwatch = System.Diagnostics.Stopwatch; namespace GameCult.EveUnity.GenericClient.PlayModeTests { @@ -304,9 +305,8 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests Assert.That(provider.Selection.VerseId, Is.Not.Empty); Assert.That(provider.Selection.ProviderId, Is.Not.Empty); Assert.That(provider.Selection.SurfaceId, Is.Not.Empty); - Assert.That(provider.CurrentAssetBodyTransportKind, - Is.EqualTo(CultMeshBodyTransportKind.SharedFileMapping), - "The generic client did not negotiate its verified provider bundle as a mapped body."); + Assert.That(provider.CurrentAssetBodyTransportKind, Is.Null, + "Publishing the provider catalog eagerly transferred an asset bundle."); host = root.AddComponent(); host.Configure( root.transform, @@ -375,6 +375,9 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests "provider-asset-ref")); Assert.That(playerPrefab, Is.Not.Null, $"Provider asset catalog did not resolve player AssetRef '{playerFact.AssetRef}'."); + Assert.That(provider.CurrentAssetBodyTransportKind, + Is.EqualTo(CultMeshBodyTransportKind.SharedFileMapping), + "The first requested provider bundle was not negotiated as a mapped body."); var marker = FindMarker(root, playerId); Assert.That( marker.GetComponentsInChildren(includeInactive: true).Length, @@ -912,6 +915,7 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests Assert.That(captureFieldVolume, Is.Not.Null, "The generic client did not install its Fields volume lowerer before temporal settling."); const int temporalSettlingFrames = 128; + var temporalSettlingElapsed = Stopwatch.StartNew(); var initialCompositeCount = captureFieldVolume.CompositeCount; var temporalSettlingDeadline = Time.realtimeSinceStartup + 20f; while (captureFieldVolume.CompositeCount - initialCompositeCount < temporalSettlingFrames && @@ -923,6 +927,8 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests Assert.That(captureFieldVolume.CompositeCount - initialCompositeCount, Is.GreaterThanOrEqualTo(temporalSettlingFrames), "The pilot capture ran before the advertised temporal reconstruction had settled."); + Debug.Log($"EveUnity witness phase temporal-settling-128-frames took {temporalSettlingElapsed.Elapsed.TotalMilliseconds:0.###}ms."); + var pilotCaptureElapsed = Stopwatch.StartNew(); yield return null; RenderTexture.active = target; pixels = new Texture2D(captureWidth, captureHeight, TextureFormat.RGB24, false); @@ -950,7 +956,9 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests "The provider-authored player prefab has no renderer on its advertised map channel."); Assert.That(playerMapRendererFacts.Sum(fact => fact.renderedPixelCount), Is.Zero, "A provider-prefab map-channel renderer leaked into the pilot camera."); + Debug.Log($"EveUnity witness phase pilot-capture-and-renderer-probes took {pilotCaptureElapsed.Elapsed.TotalMilliseconds:0.###}ms."); + var mapCaptureElapsed = Stopwatch.StartNew(); mapRenderers = mapRenderers.Where(renderer => renderer != null).ToList(); Assert.That(mapRenderers, Is.Not.Empty, "All advertised map-channel renderers were destroyed before map capture."); @@ -981,6 +989,7 @@ namespace GameCult.EveUnity.GenericClient.PlayModeTests Directory.CreateDirectory(Path.GetDirectoryName(Path.GetFullPath(mapCapturePath))); File.WriteAllBytes(mapCapturePath, pixels.EncodeToPNG()); Assert.That(new FileInfo(mapCapturePath).Length, Is.GreaterThan(1024)); + Debug.Log($"EveUnity witness phase map-capture took {mapCaptureElapsed.Elapsed.TotalMilliseconds:0.###}ms."); var tractorReleaseVersion = runtime.ActiveVersion; var tractorRelease = host.SubmitAdvertisedActionValueIntent( playerId, diff --git a/scripts/run-aetheria-daemon-world-witness.ps1 b/scripts/run-aetheria-daemon-world-witness.ps1 index b9bb925..cf1038c 100644 --- a/scripts/run-aetheria-daemon-world-witness.ps1 +++ b/scripts/run-aetheria-daemon-world-witness.ps1 @@ -17,10 +17,10 @@ param( ) $ErrorActionPreference = "Stop" -$expectedEveUnityCommit = "0463ddff4e39c9cca14e632b7e46b6b0081c67cc" +$expectedEveUnityCommit = "3da246aba8ee24af1c2528fe1c81b41a51a41c64" $expectedEveFieldsCommit = "c5a4a75c1b727499b16c2dae1895f29e2a9f72f0" $expectedEveUnityUiToolkitCommit = "4d0cbe0185bdc4fc65eb63503a7c5cb578539669" -$expectedCultLibCommit = "c148d891c1d8713285ae15b2f17b59c106fb9426" +$expectedCultLibCommit = "36a822d91416d7fecd4f3e67259186e45cf7cdaa" $repoRoot = Split-Path -Parent $PSScriptRoot $projectRoot = $ClientProject $outputRoot = if ([IO.Path]::IsPathRooted($OutputDirectory)) { $OutputDirectory } else { Join-Path $repoRoot $OutputDirectory } @@ -42,7 +42,7 @@ $providerReadyPath = Join-Path $outputRoot "provider-ready.txt" $witnessPath = Join-Path $outputRoot "runtime-witness.json" $replicaPath = Join-Path $outputRoot "eve-unity-replica.cc" $statePath = Join-Path $outputRoot "aetheria-witness-state.cc" -$providerBundlePath = Join-Path $AetheriaRoot "Build\EveAssets\StandaloneWindows64\aetheria-world" +$providerBundleDirectory = Join-Path $AetheriaRoot "Build\EveAssets\StandaloneWindows64" $daemonProject = Join-Path $AetheriaRoot "Aetheria.State.Daemon\Aetheria.State.Daemon.csproj" $importProject = Join-Path $AetheriaRoot "Aetheria.State.Import\Aetheria.State.Import.csproj" @@ -144,32 +144,36 @@ if ($PrimeWarmCacheFromProviderBundle) { if ($CacheState -ne "warm") { throw "Local provider-bundle priming is only valid for an explicitly warm witness." } - if (-not (Test-Path -LiteralPath $providerBundlePath)) { - throw "Provider-owned Aetheria bundle is missing: $providerBundlePath" - } + $providerBundlePaths = @(Get-ChildItem -LiteralPath $providerBundleDirectory -Filter "aetheria-*" -File -ErrorAction SilentlyContinue | + Where-Object { $_.Extension -ne ".manifest" } | Select-Object -ExpandProperty FullName) + if ($providerBundlePaths.Count -eq 0) { throw "Provider-owned Aetheria bundles are missing: $providerBundleDirectory" } New-Item -ItemType Directory -Force -Path $assetCachePath | Out-Null - $primeHash = (Get-FileHash -LiteralPath $providerBundlePath -Algorithm SHA256).Hash.ToLowerInvariant() - $primeTarget = Join-Path $assetCachePath "$primeHash.body" - if (-not (Test-Path -LiteralPath $primeTarget)) { - $primePartial = Join-Path $assetCachePath "$primeHash.partial.local-prime" - Copy-Item -LiteralPath $providerBundlePath -Destination $primePartial -Force - if ((Get-FileHash -LiteralPath $primePartial -Algorithm SHA256).Hash.ToLowerInvariant() -ne $primeHash) { - Remove-Item -LiteralPath $primePartial -Force -ErrorAction SilentlyContinue - throw "Locally primed provider bundle failed its content-hash check." + foreach ($providerBundlePath in $providerBundlePaths) { + $primeHash = (Get-FileHash -LiteralPath $providerBundlePath -Algorithm SHA256).Hash.ToLowerInvariant() + $primeTarget = Join-Path $assetCachePath "$primeHash.body" + if (-not (Test-Path -LiteralPath $primeTarget)) { + $primePartial = Join-Path $assetCachePath "$primeHash.partial.local-prime" + Copy-Item -LiteralPath $providerBundlePath -Destination $primePartial -Force + if ((Get-FileHash -LiteralPath $primePartial -Algorithm SHA256).Hash.ToLowerInvariant() -ne $primeHash) { + Remove-Item -LiteralPath $primePartial -Force -ErrorAction SilentlyContinue + throw "Locally primed provider bundle failed its content-hash check." + } + Move-Item -LiteralPath $primePartial -Destination $primeTarget -Force } - Move-Item -LiteralPath $primePartial -Destination $primeTarget -Force } - Write-Host "Warm cache primed locally from the provider bundle; this is not CDN-transfer evidence: $primeTarget" + Write-Host "Warm cache primed locally from $($providerBundlePaths.Count) provider bundles; this is not CDN-transfer evidence: $assetCachePath" } if ($CacheState -eq "warm") { - if (-not (Test-Path -LiteralPath $providerBundlePath)) { - throw "Provider-owned Aetheria bundle is missing: $providerBundlePath" - } - $currentBundleHash = (Get-FileHash -LiteralPath $providerBundlePath -Algorithm SHA256).Hash.ToLowerInvariant() - $currentWarmBody = Get-ChildItem -LiteralPath $assetCachePath -Filter "$currentBundleHash.body" -File -Recurse -ErrorAction SilentlyContinue | - Select-Object -First 1 - if ($null -eq $currentWarmBody) { - throw "Warm witness cache does not contain the current provider bundle. expected=$currentBundleHash cache=$assetCachePath" + $providerBundlePaths = @(Get-ChildItem -LiteralPath $providerBundleDirectory -Filter "aetheria-*" -File -ErrorAction SilentlyContinue | + Where-Object { $_.Extension -ne ".manifest" } | Select-Object -ExpandProperty FullName) + if ($providerBundlePaths.Count -eq 0) { throw "Provider-owned Aetheria bundles are missing: $providerBundleDirectory" } + foreach ($providerBundlePath in $providerBundlePaths) { + $currentBundleHash = (Get-FileHash -LiteralPath $providerBundlePath -Algorithm SHA256).Hash.ToLowerInvariant() + $currentWarmBody = Get-ChildItem -LiteralPath $assetCachePath -Filter "$currentBundleHash.body" -File -Recurse -ErrorAction SilentlyContinue | + Select-Object -First 1 + if ($null -eq $currentWarmBody) { + throw "Warm witness cache does not contain current provider bundle '$providerBundlePath'. expected=$currentBundleHash cache=$assetCachePath" + } } }