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>
bool IsCanRelease();
/// <summary>
/// Unity资源对象。
/// </summary>
public UnityEngine.Object TargetObject { get; set; }
}
}

View File

@ -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;
}
}

View File

@ -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
{
/// <summary>
/// 资源组件。
/// </summary>
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<UnityEngine.Object, LoadingState> _loadingStates = new Dictionary<UnityEngine.Object, LoadingState>();
private void InitializedResources()
{
m_ResourceModule = ModuleSystem.GetModule<IResourceModule>();
m_LoadAssetCallbacks = new LoadAssetCallbacks(OnLoadAssetSuccess, OnLoadAssetFailure);
_resourceModule = ModuleSystem.GetModule<IResourceModule>();
_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,35 +55,151 @@ 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);
// 检查资源是否仍然是当前需要的。
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
{
Log.Error($"Load failure asset type is {asset.GetType()}.");
}
}
/// <summary>
/// 通过资源系统设置资源。
/// 通过Unity对象加载资源。
/// </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
{
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;
}
// 取消并清理旧的加载请求。
CancelAndCleanupOldRequest(target);
// 创建新的加载状态
var cts = new CancellationTokenSource();
var loadingState = MemoryPool.Acquire<LoadingState>();
loadingState.Cts = cts;
loadingState.Location = location;
_loadingStates[target] = loadingState;
try
{
// 等待其他可能正在进行的加载。
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
{
_assetLoadingList.Add(setAssetObject.Location);
m_ResourceModule.LoadAssetAsync(setAssetObject.Location, typeof(T), 0, m_LoadAssetCallbacks, setAssetObject);
// 最后一次检查是否被替换。
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>
private IObjectPool<AssetItemObject> m_AssetItemPool;
private IObjectPool<AssetItemObject> _assetItemPool;
#if UNITY_EDITOR
@ -66,7 +66,7 @@ namespace AlicizaX.Resource.Runtime
{
yield return new WaitForEndOfFrame();
IObjectPoolModule objectPoolComponent = ModuleSystem.GetModule<IObjectPoolModule>();
m_AssetItemPool = objectPoolComponent.CreateMultiSpawnObjectPool<AssetItemObject>(
_assetItemPool = objectPoolComponent.CreateMultiSpawnObjectPool<AssetItemObject>(
"SetAssetPool",
m_AutoReleaseInterval, 16, 60, 0);
m_LoadAssetObjectsLinkedList = new LinkedList<LoadAssetObject>();
@ -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);
}