diff --git a/Runtime/Resource/Resource/Extension/ISetAssetObject.cs b/Runtime/Resource/Resource/Extension/ISetAssetObject.cs
index 6ab7267..ff5f271 100644
--- a/Runtime/Resource/Resource/Extension/ISetAssetObject.cs
+++ b/Runtime/Resource/Resource/Extension/ISetAssetObject.cs
@@ -19,5 +19,11 @@ namespace AlicizaX.Resource.Runtime
/// 是否可以回收。
///
bool IsCanRelease();
+
+
+ ///
+ /// Unity资源对象。
+ ///
+ public UnityEngine.Object TargetObject { get; set; }
}
}
diff --git a/Runtime/Resource/Resource/Extension/Implement/SetSpriteObject.cs b/Runtime/Resource/Resource/Extension/Implement/SetSpriteObject.cs
index f9aea6b..9d5810a 100644
--- a/Runtime/Resource/Resource/Extension/Implement/SetSpriteObject.cs
+++ b/Runtime/Resource/Resource/Extension/Implement/SetSpriteObject.cs
@@ -39,6 +39,8 @@ namespace AlicizaX.Resource.Runtime
#endif
private Sprite _sprite;
+ public Object TargetObject { get; set; }
+
public string Location { get; private set; }
private bool _setNativeSize = false;
@@ -90,6 +92,7 @@ namespace AlicizaX.Resource.Runtime
_sprite = null;
_setType = SetType.None;
_setNativeSize = false;
+ TargetObject = null;
}
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._cancellationToken = cancellationToken;
item._setType = SetType.Image;
+ item.TargetObject = image;
return item;
}
@@ -110,6 +114,7 @@ namespace AlicizaX.Resource.Runtime
item.Location = location;
item._cancellationToken = cancellationToken;
item._setType = SetType.SpriteRender;
+ item.TargetObject = spriteRenderer;
return item;
}
}
diff --git a/Runtime/Resource/Resource/Extension/ResourceExtComponent.Resource.cs b/Runtime/Resource/Resource/Extension/ResourceExtComponent.Resource.cs
index 3fb4d4e..1aa4cc1 100644
--- a/Runtime/Resource/Resource/Extension/ResourceExtComponent.Resource.cs
+++ b/Runtime/Resource/Resource/Extension/ResourceExtComponent.Resource.cs
@@ -1,26 +1,52 @@
-using AlicizaX;
+using System;
+using System.Collections.Generic;
+using System.Threading;
using Cysharp.Threading.Tasks;
namespace AlicizaX.Resource.Runtime
{
public partial class ResourceExtComponent
{
- ///
- /// 资源组件。
- ///
- private IResourceModule m_ResourceModule;
+ private static IResourceModule _resourceModule;
+ private LoadAssetCallbacks _loadAssetCallbacks;
- 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 _loadingStates = new Dictionary();
private void InitializedResources()
{
- m_ResourceModule = ModuleSystem.GetModule();
- m_LoadAssetCallbacks = new LoadAssetCallbacks(OnLoadAssetSuccess, OnLoadAssetFailure);
+ _resourceModule = ModuleSystem.GetModule();
+ _loadAssetCallbacks = new LoadAssetCallbacks(OnLoadAssetSuccess, OnLoadAssetFailure);
}
private void OnLoadAssetFailure(string assetName, LoadResourceStatus status, string errormessage, object userdata)
{
_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);
}
@@ -29,10 +55,22 @@ namespace AlicizaX.Resource.Runtime
_assetLoadingList.Remove(assetName);
ISetAssetObject setAssetObject = (ISetAssetObject)userdata;
UnityEngine.Object assetObject = asset as UnityEngine.Object;
+
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
{
@@ -41,23 +79,127 @@ namespace AlicizaX.Resource.Runtime
}
///
- /// 通过资源系统设置资源。
+ /// 通过Unity对象加载资源。
///
- /// 需要设置的对象。
+ /// ISetAssetObject。
+ /// Unity对象类型。
public async UniTaskVoid SetAssetByResources(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;
- SetAsset(setAssetObject, assetObject);
+ return;
}
- else
+
+ // 取消并清理旧的加载请求。
+ CancelAndCleanupOldRequest(target);
+
+ // 创建新的加载状态
+ var cts = new CancellationTokenSource();
+ var loadingState = MemoryPool.Acquire();
+ 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);
+ }
+ }
+
+ ///
+ /// 取消并清理旧的加载请求。
+ /// Unity对象。
+ ///
+ private void CancelAndCleanupOldRequest(UnityEngine.Object target)
+ {
+ if (_loadingStates.TryGetValue(target, out var oldState))
+ {
+ MemoryPool.Release(oldState);
+ _loadingStates.Remove(target);
+ }
+ }
+
+ ///
+ /// 清理加载状态。
+ /// Unity对象。
+ ///
+ private void ClearLoadingState(UnityEngine.Object target)
+ {
+ if (_loadingStates.TryGetValue(target, out var state))
+ {
+ MemoryPool.Release(state);
+ _loadingStates.Remove(target);
+ }
+ }
+
+ ///
+ /// 检查指定位置是否仍是该目标的当前加载位置。
+ ///
+ private bool IsCurrentLocation(UnityEngine.Object target, string location)
+ {
+ if (target == null)
+ {
+ return false;
+ }
+ return _loadingStates.TryGetValue(target, out var state) && state.Location == location;
+ }
+
+ ///
+ /// 组件销毁时清理所有资源。
+ ///
+ private void OnDestroy()
+ {
+ foreach (var state in _loadingStates.Values)
+ {
+ MemoryPool.Release(state);
+ }
+
+ _loadingStates.Clear();
}
}
}
diff --git a/Runtime/Resource/Resource/Extension/ResourceExtComponent.cs b/Runtime/Resource/Resource/Extension/ResourceExtComponent.cs
index dcab63a..8f8dc72 100644
--- a/Runtime/Resource/Resource/Extension/ResourceExtComponent.cs
+++ b/Runtime/Resource/Resource/Extension/ResourceExtComponent.cs
@@ -47,7 +47,7 @@ namespace AlicizaX.Resource.Runtime
///
/// 散图集合对象池
///
- private IObjectPool m_AssetItemPool;
+ private IObjectPool _assetItemPool;
#if UNITY_EDITOR
@@ -66,7 +66,7 @@ namespace AlicizaX.Resource.Runtime
{
yield return new WaitForEndOfFrame();
IObjectPoolModule objectPoolComponent = ModuleSystem.GetModule();
- m_AssetItemPool = objectPoolComponent.CreateMultiSpawnObjectPool(
+ _assetItemPool = objectPoolComponent.CreateMultiSpawnObjectPool(
"SetAssetPool",
m_AutoReleaseInterval, 16, 60, 0);
m_LoadAssetObjectsLinkedList = new LinkedList();
@@ -105,7 +105,7 @@ namespace AlicizaX.Resource.Runtime
var next = current.Next;
if (current.Value.AssetObject.IsCanRelease())
{
- m_AssetItemPool.Unspawn(current.Value.AssetTarget);
+ _assetItemPool.Unspawn(current.Value.AssetTarget);
MemoryPool.Release(current.Value.AssetObject);
m_LoadAssetObjectsLinkedList.Remove(current);
}