Files
FlowScope/Packages/com.flowscope.gamecore/Addressables/AddressablesResourceBackend.cs
2026-06-04 14:54:49 +08:00

71 lines
2.2 KiB
C#

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<T> LoadAsync<T>(string key, CancellationToken cancellationToken)
where T : class
{
cancellationToken.ThrowIfCancellationRequested();
var handle = UnityAddressables.LoadAssetAsync<T>(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<T>(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<bool>();
using (cancellationToken.Register(() => cancellation.TrySetResult(true)))
{
if (await Task.WhenAny(task, cancellation.Task) == cancellation.Task)
{
throw new OperationCanceledException(cancellationToken);
}
}
await task;
}
}
}