143 lines
4.9 KiB
C#
143 lines
4.9 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using UnityEngine.AddressableAssets;
|
|
using UnityEngine.ResourceManagement.AsyncOperations;
|
|
using Object = UnityEngine.Object;
|
|
|
|
namespace AibisDream.Framework
|
|
{
|
|
public class SceneResourceLoader : IDisposable
|
|
{
|
|
private readonly bool _isPersistent;
|
|
private readonly Dictionary<string, AsyncOperationHandle> _cache = new();
|
|
private readonly List<AsyncOperationHandle> _uncachedHandles = new();
|
|
|
|
public SceneResourceLoader(bool isPersistent = false)
|
|
{
|
|
_isPersistent = isPersistent;
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
ReleaseAll();
|
|
}
|
|
|
|
public bool IsPersistent => _isPersistent;
|
|
|
|
/// <summary>
|
|
/// 异步加载资源(带缓存,同 Key 不重复加载)。
|
|
/// 返回的 Handle 可在协程中 yield return。
|
|
/// </summary>
|
|
public AsyncOperationHandle<T> LoadAsync<T>(string key) where T : Object
|
|
{
|
|
if (_cache.TryGetValue(key, out var cached) && cached.IsValid())
|
|
return cached.Convert<T>();
|
|
|
|
var handle = Addressables.LoadAssetAsync<T>(key);
|
|
_cache[key] = handle;
|
|
handle.Completed += op =>
|
|
{
|
|
if (op.Status != AsyncOperationStatus.Succeeded)
|
|
Debug.LogError($"[SceneResourceLoader] Failed to load '{key}': {op.OperationException}");
|
|
};
|
|
return handle;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 异步加载资源(回调风格,带缓存)。
|
|
/// </summary>
|
|
public void LoadAsync<T>(string key, Action<T> onComplete, Action<string> onError = null) where T : Object
|
|
{
|
|
var handle = LoadAsync<T>(key);
|
|
handle.Completed += op =>
|
|
{
|
|
if (op.Status == AsyncOperationStatus.Succeeded)
|
|
onComplete?.Invoke(op.Result);
|
|
else
|
|
onError?.Invoke($"Failed to load '{key}': {op.OperationException}");
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
/// 异步加载资源(不走缓存,每次产生独立 Handle)。
|
|
/// 适用于 Timeline 等需要独立生命周期管理的资源。
|
|
/// </summary>
|
|
public AsyncOperationHandle<T> LoadUncachedAsync<T>(string key) where T : Object
|
|
{
|
|
var handle = Addressables.LoadAssetAsync<T>(key);
|
|
_uncachedHandles.Add(handle);
|
|
handle.Completed += op =>
|
|
{
|
|
if (op.Status != AsyncOperationStatus.Succeeded)
|
|
Debug.LogError($"[SceneResourceLoader] Failed to load '{key}': {op.OperationException}");
|
|
};
|
|
return handle;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 按 Label 批量预加载资源。返回的 Handle 可在协程中 yield return。
|
|
/// </summary>
|
|
public AsyncOperationHandle<IList<T>> PreloadByLabel<T>(string label) where T : Object
|
|
{
|
|
var handle = Addressables.LoadAssetsAsync<T>(label, null);
|
|
_uncachedHandles.Add(handle);
|
|
handle.Completed += op =>
|
|
{
|
|
if (op.Status != AsyncOperationStatus.Succeeded)
|
|
Debug.LogError($"[SceneResourceLoader] Failed to preload label '{label}': {op.OperationException}");
|
|
};
|
|
return handle;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 提前释放指定 Key 的缓存资源。
|
|
/// </summary>
|
|
public void EarlyRelease(string key)
|
|
{
|
|
if (_cache.TryGetValue(key, out var handle))
|
|
{
|
|
if (handle.IsValid())
|
|
Addressables.Release(handle);
|
|
_cache.Remove(key);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 提前释放指定的非缓存 Handle。
|
|
/// </summary>
|
|
public void EarlyRelease<T>(AsyncOperationHandle<T> handle)
|
|
{
|
|
if (handle.IsValid())
|
|
{
|
|
Addressables.Release(handle);
|
|
_uncachedHandles.Remove(handle);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 释放所有持有的资源 Handle。由 SceneLoader 在卸载场景前调用,或 OnDestroy 时自动调用。
|
|
/// </summary>
|
|
public void ReleaseAll()
|
|
{
|
|
foreach (var kvp in _cache)
|
|
{
|
|
if (kvp.Value.IsValid())
|
|
Addressables.Release(kvp.Value);
|
|
}
|
|
_cache.Clear();
|
|
|
|
foreach (var handle in _uncachedHandles)
|
|
{
|
|
if (handle.IsValid())
|
|
Addressables.Release(handle);
|
|
}
|
|
_uncachedHandles.Clear();
|
|
}
|
|
|
|
public int CachedCount => _cache.Count;
|
|
public int UncachedCount => _uncachedHandles.Count;
|
|
public int TotalHandleCount => _cache.Count + _uncachedHandles.Count;
|
|
}
|
|
}
|