This commit is contained in:
陈思海 2025-11-05 19:31:37 +08:00
parent 9172d11d84
commit ad913aceb4
4 changed files with 175 additions and 22 deletions

View File

@ -19,5 +19,11 @@ namespace AlicizaX.Resource.Runtime
/// 是否可以回收。 /// 是否可以回收。
/// </summary> /// </summary>
bool IsCanRelease(); bool IsCanRelease();
/// <summary>
/// Unity资源对象。
/// </summary>
public UnityEngine.Object TargetObject { get; set; }
} }
} }

View File

@ -39,6 +39,8 @@ namespace AlicizaX.Resource.Runtime
#endif #endif
private Sprite _sprite; private Sprite _sprite;
public Object TargetObject { get; set; }
public string Location { get; private set; } public string Location { get; private set; }
private bool _setNativeSize = false; private bool _setNativeSize = false;
@ -90,6 +92,7 @@ namespace AlicizaX.Resource.Runtime
_sprite = null; _sprite = null;
_setType = SetType.None; _setType = SetType.None;
_setNativeSize = false; _setNativeSize = false;
TargetObject = null;
} }
public static SetSpriteObject Create(Image image, string location, bool setNativeSize = false, CancellationToken cancellationToken = default) public static SetSpriteObject Create(Image image, string location, bool setNativeSize = false, CancellationToken cancellationToken = default)
@ -100,6 +103,7 @@ namespace AlicizaX.Resource.Runtime
item.Location = location; item.Location = location;
item._cancellationToken = cancellationToken; item._cancellationToken = cancellationToken;
item._setType = SetType.Image; item._setType = SetType.Image;
item.TargetObject = image;
return item; return item;
} }
@ -110,6 +114,7 @@ namespace AlicizaX.Resource.Runtime
item.Location = location; item.Location = location;
item._cancellationToken = cancellationToken; item._cancellationToken = cancellationToken;
item._setType = SetType.SpriteRender; item._setType = SetType.SpriteRender;
item.TargetObject = spriteRenderer;
return item; return item;
} }
} }

View File

@ -1,26 +1,52 @@
using AlicizaX; using System;
using System.Collections.Generic;
using System.Threading;
using Cysharp.Threading.Tasks; using Cysharp.Threading.Tasks;
namespace AlicizaX.Resource.Runtime namespace AlicizaX.Resource.Runtime
{ {
public partial class ResourceExtComponent public partial class ResourceExtComponent
{ {
/// <summary> private static IResourceModule _resourceModule;
/// 资源组件。 private LoadAssetCallbacks _loadAssetCallbacks;
/// </summary>
private IResourceModule m_ResourceModule;
private LoadAssetCallbacks m_LoadAssetCallbacks; public static IResourceModule ResourceModule => _resourceModule;
private class LoadingState : IMemory
{
public CancellationTokenSource Cts { get; set; }
public string Location { get; set; }
public void Clear()
{
if (Cts != null)
{
Cts.Cancel();
Cts.Dispose();
Cts = null;
}
Location = String.Empty;
}
}
private static readonly Dictionary<UnityEngine.Object, LoadingState> _loadingStates = new Dictionary<UnityEngine.Object, LoadingState>();
private void InitializedResources() private void InitializedResources()
{ {
m_ResourceModule = ModuleSystem.GetModule<IResourceModule>(); _resourceModule = ModuleSystem.GetModule<IResourceModule>();
m_LoadAssetCallbacks = new LoadAssetCallbacks(OnLoadAssetSuccess, OnLoadAssetFailure); _loadAssetCallbacks = new LoadAssetCallbacks(OnLoadAssetSuccess, OnLoadAssetFailure);
} }
private void OnLoadAssetFailure(string assetName, LoadResourceStatus status, string errormessage, object userdata) private void OnLoadAssetFailure(string assetName, LoadResourceStatus status, string errormessage, object userdata)
{ {
_assetLoadingList.Remove(assetName); _assetLoadingList.Remove(assetName);
ISetAssetObject setAssetObject = (ISetAssetObject)userdata;
if (setAssetObject != null)
{
ClearLoadingState(setAssetObject.TargetObject);
}
Log.Error("Can not load asset from '{0}' with error message '{1}'.", assetName, errormessage); Log.Error("Can not load asset from '{0}' with error message '{1}'.", assetName, errormessage);
} }
@ -29,10 +55,22 @@ namespace AlicizaX.Resource.Runtime
_assetLoadingList.Remove(assetName); _assetLoadingList.Remove(assetName);
ISetAssetObject setAssetObject = (ISetAssetObject)userdata; ISetAssetObject setAssetObject = (ISetAssetObject)userdata;
UnityEngine.Object assetObject = asset as UnityEngine.Object; UnityEngine.Object assetObject = asset as UnityEngine.Object;
if (assetObject != null) if (assetObject != null)
{ {
m_AssetItemPool.Register(AssetItemObject.Create(setAssetObject.Location, assetObject), true); // 检查资源是否仍然是当前需要的。
SetAsset(setAssetObject, assetObject); if (IsCurrentLocation(setAssetObject.TargetObject, setAssetObject.Location))
{
ClearLoadingState(setAssetObject.TargetObject);
_assetItemPool.Register(AssetItemObject.Create(setAssetObject.Location, assetObject), true);
SetAsset(setAssetObject, assetObject);
}
else
{
// 资源已经过期,卸载。
_resourceModule.UnloadAsset(assetObject);
}
} }
else else
{ {
@ -41,23 +79,127 @@ namespace AlicizaX.Resource.Runtime
} }
/// <summary> /// <summary>
/// 通过资源系统设置资源。 /// 通过Unity对象加载资源。
/// </summary> /// </summary>
/// <param name="setAssetObject">需要设置的对象。</param> /// <param name="setAssetObject">ISetAssetObject。</param>
/// <typeparam name="T">Unity对象类型。</typeparam>
public async UniTaskVoid SetAssetByResources<T>(ISetAssetObject setAssetObject) where T : UnityEngine.Object public async UniTaskVoid SetAssetByResources<T>(ISetAssetObject setAssetObject) where T : UnityEngine.Object
{ {
await TryWaitingLoading(setAssetObject.Location); var target = setAssetObject.TargetObject;
var location = setAssetObject.Location;
if (m_AssetItemPool.CanSpawn(setAssetObject.Location)) if (target == null)
{ {
var assetObject = (T)m_AssetItemPool.Spawn(setAssetObject.Location).Target; return;
SetAsset(setAssetObject, assetObject);
} }
else
// 取消并清理旧的加载请求。
CancelAndCleanupOldRequest(target);
// 创建新的加载状态
var cts = new CancellationTokenSource();
var loadingState = MemoryPool.Acquire<LoadingState>();
loadingState.Cts = cts;
loadingState.Location = location;
_loadingStates[target] = loadingState;
try
{ {
_assetLoadingList.Add(setAssetObject.Location); // 等待其他可能正在进行的加载。
m_ResourceModule.LoadAssetAsync(setAssetObject.Location, typeof(T), 0, m_LoadAssetCallbacks, setAssetObject); await TryWaitingLoading(location).AttachExternalCancellation(cts.Token);
// 再次检查是否被新请求替换。
if (!IsCurrentLocation(target, location))
{
return;
}
// 检查缓存。
if (_assetItemPool.CanSpawn(location))
{
ClearLoadingState(target);
var assetObject = (T)_assetItemPool.Spawn(location).Target;
SetAsset(setAssetObject, assetObject);
}
else
{
// 最后一次检查是否被替换。
if (!IsCurrentLocation(target, location))
{
return;
}
// 防止重复加载同一资源。
if (!_assetLoadingList.Add(location))
{
// 已经在加载中,等待回调处理。
return;
}
_resourceModule.LoadAssetAsync(location, typeof(T), 0, _loadAssetCallbacks, setAssetObject);
}
} }
catch (OperationCanceledException)
{
// 请求被取消,正常情况,无需处理。
}
catch (Exception ex)
{
Log.Error($"Failed to load asset '{location}': {ex}");
ClearLoadingState(target);
}
}
/// <summary>
/// 取消并清理旧的加载请求。
/// <param name="target">Unity对象。</param>
/// </summary>
private void CancelAndCleanupOldRequest(UnityEngine.Object target)
{
if (_loadingStates.TryGetValue(target, out var oldState))
{
MemoryPool.Release(oldState);
_loadingStates.Remove(target);
}
}
/// <summary>
/// 清理加载状态。
/// <param name="target">Unity对象。</param>
/// </summary>
private void ClearLoadingState(UnityEngine.Object target)
{
if (_loadingStates.TryGetValue(target, out var state))
{
MemoryPool.Release(state);
_loadingStates.Remove(target);
}
}
/// <summary>
/// 检查指定位置是否仍是该目标的当前加载位置。
/// </summary>
private bool IsCurrentLocation(UnityEngine.Object target, string location)
{
if (target == null)
{
return false;
}
return _loadingStates.TryGetValue(target, out var state) && state.Location == location;
}
/// <summary>
/// 组件销毁时清理所有资源。
/// </summary>
private void OnDestroy()
{
foreach (var state in _loadingStates.Values)
{
MemoryPool.Release(state);
}
_loadingStates.Clear();
} }
} }
} }

View File

@ -47,7 +47,7 @@ namespace AlicizaX.Resource.Runtime
/// <summary> /// <summary>
/// 散图集合对象池 /// 散图集合对象池
/// </summary> /// </summary>
private IObjectPool<AssetItemObject> m_AssetItemPool; private IObjectPool<AssetItemObject> _assetItemPool;
#if UNITY_EDITOR #if UNITY_EDITOR
@ -66,7 +66,7 @@ namespace AlicizaX.Resource.Runtime
{ {
yield return new WaitForEndOfFrame(); yield return new WaitForEndOfFrame();
IObjectPoolModule objectPoolComponent = ModuleSystem.GetModule<IObjectPoolModule>(); IObjectPoolModule objectPoolComponent = ModuleSystem.GetModule<IObjectPoolModule>();
m_AssetItemPool = objectPoolComponent.CreateMultiSpawnObjectPool<AssetItemObject>( _assetItemPool = objectPoolComponent.CreateMultiSpawnObjectPool<AssetItemObject>(
"SetAssetPool", "SetAssetPool",
m_AutoReleaseInterval, 16, 60, 0); m_AutoReleaseInterval, 16, 60, 0);
m_LoadAssetObjectsLinkedList = new LinkedList<LoadAssetObject>(); m_LoadAssetObjectsLinkedList = new LinkedList<LoadAssetObject>();
@ -105,7 +105,7 @@ namespace AlicizaX.Resource.Runtime
var next = current.Next; var next = current.Next;
if (current.Value.AssetObject.IsCanRelease()) if (current.Value.AssetObject.IsCanRelease())
{ {
m_AssetItemPool.Unspawn(current.Value.AssetTarget); _assetItemPool.Unspawn(current.Value.AssetTarget);
MemoryPool.Release(current.Value.AssetObject); MemoryPool.Release(current.Value.AssetObject);
m_LoadAssetObjectsLinkedList.Remove(current); m_LoadAssetObjectsLinkedList.Remove(current);
} }