using System; using System.Threading; using System.Threading.Tasks; using FlowScope.Resources; using UnityEngine.ResourceManagement.AsyncOperations; using UnityAddressables = UnityEngine.AddressableAssets.Addressables; namespace FlowScope.Addressables { public sealed class AddressablesResourceBackend : IResourceBackend { public string Name => "Addressables"; public async Task LoadAsync(string key, CancellationToken cancellationToken) where T : class { cancellationToken.ThrowIfCancellationRequested(); var handle = UnityAddressables.LoadAssetAsync(key); try { await WaitWithCancellation(handle.Task, cancellationToken); } catch (OperationCanceledException) { UnityAddressables.Release(handle); throw; } if (handle.OperationException != null || handle.Status != AsyncOperationStatus.Succeeded || handle.Result == null) { var exception = new InvalidOperationException( $"Failed to load Addressables resource '{key}' as {typeof(T).Name} from backend '{Name}'.", handle.OperationException); UnityAddressables.Release(handle); throw exception; } return handle.Result; } public void Release(string key, T asset) where T : class { UnityAddressables.Release(asset); } private static async Task WaitWithCancellation(Task task, CancellationToken cancellationToken) { if (!cancellationToken.CanBeCanceled) { await task; return; } var cancellation = new TaskCompletionSource(); using (cancellationToken.Register(() => cancellation.TrySetResult(true))) { if (await Task.WhenAny(task, cancellation.Task) == cancellation.Task) { throw new OperationCanceledException(cancellationToken); } } await task; } } }