Pin and prove lazy provider asset delivery

This commit is contained in:
Meta Vens 2026-07-19 21:51:30 +01:00
commit 6e19396f7f
5 changed files with 52 additions and 37 deletions

View file

@ -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<EveUnityPlayableWorldClientHost>();
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<Transform>(includeInactive: true).Length,

View file

@ -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": [

View file

@ -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",

View file

@ -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<EveUnityPlayableWorldClientHost>();
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<Transform>(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,

View file

@ -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"
}
}
}