diff --git a/packages/org.gamecult.eve.unity-scene/Runtime/CultMesh/EveUnityCultMeshLiveProviderTransport.cs b/packages/org.gamecult.eve.unity-scene/Runtime/CultMesh/EveUnityCultMeshLiveProviderTransport.cs index 39a18c6..5a403f4 100644 --- a/packages/org.gamecult.eve.unity-scene/Runtime/CultMesh/EveUnityCultMeshLiveProviderTransport.cs +++ b/packages/org.gamecult.eve.unity-scene/Runtime/CultMesh/EveUnityCultMeshLiveProviderTransport.cs @@ -1464,6 +1464,8 @@ namespace GameCult.Eve.UnityScene ConfigureAssetCatalog(candidate, catalog); ReuseCompatibleBundles(_assetGeneration, candidate); await PreloadAssetsAsync(candidate, cancellationToken); + if (source.RequiredCatalogVersion > 0) + return candidate; var latest = await candidate.CatalogLease!.Handle.LatestAsync(); candidate.ObserveCatalog(latest); if (latest.Version != candidate.CatalogVersion) @@ -1504,7 +1506,6 @@ namespace GameCult.Eve.UnityScene long requiredCatalogVersion, CancellationToken cancellationToken) { - var requiredCatalog = new TaskCompletionSource(); var lease = await AssetMeshClient(candidate) .LeaseDocumentAsync( candidate.Source.Target, @@ -1513,22 +1514,24 @@ namespace GameCult.Eve.UnityScene IDisposable? watch = null; try { - watch = lease.Handle.Watch(catalog => + var catalog = await lease.Handle.LatestAsync(); + candidate.ObserveCatalog(catalog); + if (requiredCatalogVersion > 0) { - var pending = candidate.ObserveCatalog(catalog); - if (requiredCatalogVersion > 0 && catalog.Version == requiredCatalogVersion) - requiredCatalog.TrySetResult(catalog); - if (pending != null && requiredCatalogVersion <= 0) + RequireCatalogVersion(catalog, requiredCatalogVersion, candidate.Source.ManifestRecordRef); + candidate.CatalogLease = lease; + return catalog; + } + + watch = lease.Handle.Watch(observedCatalog => + { + var pending = candidate.ObserveCatalog(observedCatalog); + if (pending != null) QueueAssetCatalogUpdate(candidate.SourceIdentity, pending); }); candidate.CatalogWatch = watch; candidate.CatalogLease = lease; - var catalog = await lease.Handle.LatestAsync(); - candidate.ObserveCatalog(catalog); - if (requiredCatalogVersion <= 0 || catalog.Version == requiredCatalogVersion) - return catalog; - using (cancellationToken.Register(() => requiredCatalog.TrySetCanceled())) - return await requiredCatalog.Task; + return catalog; } catch { @@ -1538,6 +1541,19 @@ namespace GameCult.Eve.UnityScene } } + private static void RequireCatalogVersion( + EveAssetCatalogDocument catalog, + long requiredCatalogVersion, + string manifestRecordRef) + { + if (catalog == null) throw new ArgumentNullException(nameof(catalog)); + if (requiredCatalogVersion <= 0 || catalog.Version == requiredCatalogVersion) + return; + throw new InvalidDataException( + $"Asset catalog record '{manifestRecordRef}' contains version {catalog.Version}, " + + $"but the Eve surface requires immutable version {requiredCatalogVersion}."); + } + private void CommitAssetGeneration(AssetGeneration candidate, EveSurfaceDocument? surface = null) { PreparedSurface prepared; diff --git a/packages/org.gamecult.eve.unity-scene/Tests/Editor/EveUnityCultMeshAssetLookupTests.cs b/packages/org.gamecult.eve.unity-scene/Tests/Editor/EveUnityCultMeshAssetLookupTests.cs index adf0549..f1508f1 100644 --- a/packages/org.gamecult.eve.unity-scene/Tests/Editor/EveUnityCultMeshAssetLookupTests.cs +++ b/packages/org.gamecult.eve.unity-scene/Tests/Editor/EveUnityCultMeshAssetLookupTests.cs @@ -742,6 +742,27 @@ namespace GameCult.Eve.UnityScene.Tests Assert.That(pendingField.GetValue(transport), Is.Null); } + [Test] + public void PinnedSurfaceRejectsWrongImmutableCatalogRecordImmediately() + { + var require = typeof(EveUnityCultMeshLiveProviderTransport).GetMethod( + "RequireCatalogVersion", + BindingFlags.Static | BindingFlags.NonPublic)!; + var catalog42 = new EveAssetCatalogDocument( + "provider-a", + "eve:assets:aetheria.daemon:version:42", + 42, + DateTimeOffset.UtcNow.ToString("O"), + Array.Empty()); + + var error = Assert.Throws(() => require.Invoke( + null, + new object[] { catalog42, 41L, "eve:assets:aetheria.daemon:version:41" })); + + Assert.That(error!.InnerException, Is.TypeOf()); + Assert.That(error.InnerException!.Message, Does.Contain("requires immutable version 41")); + } + [Test] public void CrossTargetAssetsUseConfiguredRemoteTrust() { diff --git a/packages/org.gamecult.eve.unity-scene/package.json b/packages/org.gamecult.eve.unity-scene/package.json index 12483e3..f5dcbe0 100644 --- a/packages/org.gamecult.eve.unity-scene/package.json +++ b/packages/org.gamecult.eve.unity-scene/package.json @@ -1,7 +1,7 @@ { "name": "org.gamecult.eve.unity-scene", "displayName": "Eve Unity Scene Lowering", - "version": "0.3.133", + "version": "0.3.134", "unity": "6000.0", "description": "Provider-agnostic Unity scene shell for gamecult.eve.surface.v1 interactive world surfaces.", "dependencies": {