[Opt] MemoryPool & ResourceService
This commit is contained in:
parent
d6f36cc9df
commit
4cf5eb57d2
@ -96,6 +96,7 @@ namespace AlicizaX
|
||||
RunCase("ClearAll Unschedule", RunClearAllUnschedule);
|
||||
RunCase("ClearAll Active Queue Reset", RunClearAllActiveQueueReset);
|
||||
RunCase("Type API Cold Path", RunTypeApiColdPath);
|
||||
RunCase("Cached Handle Hot Path", RunCachedHandleHotPath);
|
||||
RunCase("Info Buffer No Alloc", RunInfoBufferNoAlloc);
|
||||
RunCase("Explicit Compact", RunExplicitCompact);
|
||||
}
|
||||
@ -628,6 +629,28 @@ namespace AlicizaX
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void RunCachedHandleHotPath()
|
||||
{
|
||||
using (s_ExtremeMarker.Auto())
|
||||
{
|
||||
MemoryPool<BenchmarkMemory>.ClearAll();
|
||||
MemoryPool<BenchmarkMemory>.Prewarm(objectCount);
|
||||
MemoryPoolHandle handle = MemoryPool.GetHandle(typeof(BenchmarkMemory));
|
||||
AssertTrue(handle.IsValid, "cached handle is invalid");
|
||||
|
||||
RestartCaseMeasure();
|
||||
for (int i = 0; i < loopCount; i++)
|
||||
{
|
||||
IMemory item = handle.Acquire();
|
||||
handle.Release(item);
|
||||
}
|
||||
StopCaseMeasure();
|
||||
|
||||
MemoryPool<BenchmarkMemory>.ClearAll();
|
||||
}
|
||||
}
|
||||
|
||||
private void RunInfoBufferNoAlloc()
|
||||
{
|
||||
using (s_InfoMarker.Auto())
|
||||
|
||||
@ -53,6 +53,19 @@ namespace AlicizaX
|
||||
return MemoryPool<T>.Acquire();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取动态内存类型的缓存句柄。运行时热路径应提前缓存该句柄,避免反复使用 Type 查找。
|
||||
/// </summary>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static MemoryPoolHandle GetHandle(Type memoryType)
|
||||
{
|
||||
return MemoryPoolRegistry.GetHandle(memoryType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 慢速动态路径。禁止在运行时热路径调用;请提前通过 GetHandle(Type) 缓存 MemoryPoolHandle 后再获取对象。
|
||||
/// </summary>
|
||||
[Obsolete("慢速动态路径,禁止在运行时热路径使用。请缓存 MemoryPoolHandle,或改用 MemoryPool<T>.Acquire / MemoryPool.Acquire<T>。", false)]
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static IMemory Acquire(Type memoryType)
|
||||
{
|
||||
@ -66,6 +79,10 @@ namespace AlicizaX
|
||||
MemoryPool<T>.Release(memory);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 慢速动态路径。禁止在运行时热路径调用;请通过缓存的 MemoryPoolHandle 或 Release<T> 回收对象。
|
||||
/// </summary>
|
||||
[Obsolete("慢速动态路径,禁止在运行时热路径使用。请通过缓存的 MemoryPoolHandle,或改用 MemoryPool<T>.Release / MemoryPool.Release<T>。", false)]
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public static void Release(IMemory memory)
|
||||
{
|
||||
|
||||
32
Runtime/MemoryPool/MemoryPoolHandle.cs
Normal file
32
Runtime/MemoryPool/MemoryPoolHandle.cs
Normal file
@ -0,0 +1,32 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace AlicizaX
|
||||
{
|
||||
public readonly struct MemoryPoolHandle
|
||||
{
|
||||
private readonly MemoryPoolRegistry.MemoryPoolHandle _handle;
|
||||
|
||||
internal MemoryPoolHandle(MemoryPoolRegistry.MemoryPoolHandle handle)
|
||||
{
|
||||
_handle = handle;
|
||||
}
|
||||
|
||||
public bool IsValid
|
||||
{
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get => _handle != null;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public IMemory Acquire()
|
||||
{
|
||||
return _handle.Acquire();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void Release(IMemory memory)
|
||||
{
|
||||
_handle.Release(memory);
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Runtime/MemoryPool/MemoryPoolHandle.cs.meta
Normal file
11
Runtime/MemoryPool/MemoryPoolHandle.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2b7195e879c74d7c9d013fa76df5e37c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -101,6 +101,23 @@ namespace AlicizaX
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static AlicizaX.MemoryPoolHandle GetHandle(Type type)
|
||||
{
|
||||
if (type == null)
|
||||
throw new ArgumentNullException(nameof(type));
|
||||
|
||||
if (s_Handles.TryGetValue(type, out var handle))
|
||||
return new AlicizaX.MemoryPoolHandle(handle);
|
||||
|
||||
EnsureRegistered(type);
|
||||
|
||||
if (s_Handles.TryGetValue(type, out handle))
|
||||
return new AlicizaX.MemoryPoolHandle(handle);
|
||||
|
||||
throw new Exception($"MemoryPool: Type '{type.FullName}' is not a valid IMemory type.");
|
||||
}
|
||||
|
||||
public static IMemory Acquire(Type type)
|
||||
{
|
||||
if (type == null)
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
using AlicizaX;
|
||||
using AlicizaX;
|
||||
|
||||
namespace AlicizaX.Resource.Runtime
|
||||
{
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
using AlicizaX.ObjectPool;
|
||||
using AlicizaX.ObjectPool;
|
||||
using AlicizaX;
|
||||
|
||||
namespace AlicizaX.Resource.Runtime
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
|
||||
|
||||
using AlicizaX;
|
||||
|
||||
namespace AlicizaX.Resource.Runtime
|
||||
|
||||
@ -1,21 +1,31 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
using AlicizaX;
|
||||
|
||||
namespace AlicizaX.Resource.Runtime
|
||||
{
|
||||
[Serializable]
|
||||
public class LoadAssetObject
|
||||
public class LoadAssetObject : IMemory
|
||||
{
|
||||
public ISetAssetObject AssetObject { get; }
|
||||
public UnityEngine.Object AssetTarget { get; }
|
||||
public ISetAssetObject AssetObject { get; private set; }
|
||||
public UnityEngine.Object AssetTarget { get; private set; }
|
||||
#if UNITY_EDITOR
|
||||
public bool IsSelect { get; set; }
|
||||
#endif
|
||||
public LoadAssetObject(ISetAssetObject obj, UnityEngine.Object assetTarget)
|
||||
public static LoadAssetObject Create(ISetAssetObject obj, UnityEngine.Object assetTarget)
|
||||
{
|
||||
AssetObject = obj;
|
||||
AssetTarget = assetTarget;
|
||||
LoadAssetObject item = MemoryPool.Acquire<LoadAssetObject>();
|
||||
item.AssetObject = obj;
|
||||
item.AssetTarget = assetTarget;
|
||||
return item;
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
AssetObject = null;
|
||||
AssetTarget = null;
|
||||
#if UNITY_EDITOR
|
||||
IsSelect = false;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,3 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b25c6b1f257bf3445b8e2651e169e314
|
||||
timeCreated: 1710733596
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using Cysharp.Text;
|
||||
using Cysharp.Threading.Tasks;
|
||||
|
||||
namespace AlicizaX.Resource.Runtime
|
||||
@ -49,9 +49,9 @@ namespace AlicizaX.Resource.Runtime
|
||||
}
|
||||
|
||||
UnityEngine.Object assetObject = asset as UnityEngine.Object;
|
||||
if (assetObject == null)
|
||||
{
|
||||
Log.Error($"Load failure asset type is {asset?.GetType()}.");
|
||||
if (assetObject == null)
|
||||
{
|
||||
Log.Error(ZString.Format("Load failure asset type is {0}.", asset?.GetType()));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -78,61 +78,50 @@ namespace AlicizaX.Resource.Runtime
|
||||
|
||||
CancelAndCleanupOldRequest(target);
|
||||
|
||||
var linkedTokenSource = new CancellationTokenSource();
|
||||
var loadingState = MemoryPool.Acquire<LoadingState>();
|
||||
loadingState.Cts = linkedTokenSource;
|
||||
CancellationToken loadToken = cancellationToken;
|
||||
if (cancellationToken.CanBeCanceled)
|
||||
{
|
||||
var linkedTokenSource = new CancellationTokenSource();
|
||||
loadingState.Cts = linkedTokenSource;
|
||||
loadingState.Registration = cancellationToken.Register(static state =>
|
||||
{
|
||||
((CancellationTokenSource)state).Cancel();
|
||||
}, linkedTokenSource);
|
||||
loadToken = linkedTokenSource.Token;
|
||||
}
|
||||
|
||||
loadingState.Location = location;
|
||||
_loadingStates[target] = loadingState;
|
||||
|
||||
try
|
||||
if (!IsCurrentLocation(target, location))
|
||||
{
|
||||
if (!IsCurrentLocation(target, location))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_assetItemPool.CanSpawn(location))
|
||||
{
|
||||
ClearLoadingState(target);
|
||||
|
||||
var assetObject = (T)_assetItemPool.Spawn(location).Target;
|
||||
SetAsset(setAssetObject, assetObject);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IsCurrentLocation(target, location))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
T resource = await _resourceService.LoadAssetAsync<T>(location, linkedTokenSource.Token);
|
||||
if (resource == null)
|
||||
{
|
||||
ClearLoadingState(target);
|
||||
return;
|
||||
}
|
||||
|
||||
OnLoadAssetSuccess(location, resource, 0f, setAssetObject);
|
||||
return;
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
|
||||
if (_assetItemPool.CanSpawn(location))
|
||||
{
|
||||
ClearLoadingState(target);
|
||||
|
||||
var assetObject = (T)_assetItemPool.Spawn(location).Target;
|
||||
SetAsset(setAssetObject, assetObject);
|
||||
return;
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
if (!IsCurrentLocation(target, location))
|
||||
{
|
||||
Log.Error($"Failed to load asset '{location}': {ex}");
|
||||
ClearLoadingState(target);
|
||||
return;
|
||||
}
|
||||
|
||||
var loadResult = await _resourceService.LoadAssetAsync<T>(location, loadToken).SuppressCancellationThrow();
|
||||
if (loadResult.IsCanceled || loadResult.Result == null)
|
||||
{
|
||||
ClearLoadingState(target);
|
||||
return;
|
||||
}
|
||||
|
||||
OnLoadAssetSuccess(location, loadResult.Result, 0f, setAssetObject);
|
||||
}
|
||||
|
||||
private void CancelAndCleanupOldRequest(UnityEngine.Object target)
|
||||
{
|
||||
if (_loadingStates.TryGetValue(target, out var oldState))
|
||||
@ -179,9 +168,10 @@ namespace AlicizaX.Resource.Runtime
|
||||
UnityEngine.Application.lowMemory -= OnLowMemory;
|
||||
ReleaseTrackedAssets();
|
||||
|
||||
foreach (var state in _loadingStates.Values)
|
||||
var enumerator = _loadingStates.GetEnumerator();
|
||||
while (enumerator.MoveNext())
|
||||
{
|
||||
MemoryPool.Release(state);
|
||||
MemoryPool.Release(enumerator.Current.Value);
|
||||
}
|
||||
|
||||
_loadingStates.Clear();
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using Cysharp.Text;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
@ -15,15 +15,60 @@ namespace AlicizaX.Resource.Runtime
|
||||
{
|
||||
private readonly Dictionary<string, SubAssetsHandle> _subAssetsHandles = new Dictionary<string, SubAssetsHandle>();
|
||||
private readonly Dictionary<string, int> _subSpriteReferences = new Dictionary<string, int>();
|
||||
private readonly Dictionary<string, UniTaskCompletionSource<SubAssetsHandle>> _subAssetLoadingOperations = new Dictionary<string, UniTaskCompletionSource<SubAssetsHandle>>();
|
||||
private readonly Dictionary<string, AutoResetUniTaskCompletionSource<SubAssetsHandle>> _subAssetLoadingOperations = new Dictionary<string, AutoResetUniTaskCompletionSource<SubAssetsHandle>>();
|
||||
private readonly Dictionary<SubSpriteKey, Sprite> _subSpriteCache = new Dictionary<SubSpriteKey, Sprite>(SubSpriteKeyComparer.Instance);
|
||||
|
||||
private readonly struct SubSpriteKey
|
||||
{
|
||||
public readonly string Location;
|
||||
public readonly string SpriteName;
|
||||
|
||||
public SubSpriteKey(string location, string spriteName)
|
||||
{
|
||||
Location = location ?? string.Empty;
|
||||
SpriteName = spriteName ?? string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class SubSpriteKeyComparer : IEqualityComparer<SubSpriteKey>
|
||||
{
|
||||
public static readonly SubSpriteKeyComparer Instance = new SubSpriteKeyComparer();
|
||||
|
||||
private SubSpriteKeyComparer()
|
||||
{
|
||||
}
|
||||
|
||||
public bool Equals(SubSpriteKey x, SubSpriteKey y)
|
||||
{
|
||||
return string.Equals(x.Location, y.Location, System.StringComparison.Ordinal) &&
|
||||
string.Equals(x.SpriteName, y.SpriteName, System.StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
public int GetHashCode(SubSpriteKey obj)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
int hash = 17;
|
||||
hash = hash * 31 + System.StringComparer.Ordinal.GetHashCode(obj.Location ?? string.Empty);
|
||||
hash = hash * 31 + System.StringComparer.Ordinal.GetHashCode(obj.SpriteName ?? string.Empty);
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async UniTask SetSubSprite(Image image, string location, string spriteName, bool setNativeSize = false, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var subSprite = await GetSubSpriteImp(location, spriteName, cancellationToken);
|
||||
|
||||
if (image == null)
|
||||
{
|
||||
Log.Warning($"SetSubAssets Image is null");
|
||||
Log.Warning("SetSubAssets Image is null");
|
||||
return;
|
||||
}
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
var subSprite = await GetSubSpriteImp(location, spriteName, cancellationToken);
|
||||
|
||||
if (image == null || cancellationToken.IsCancellationRequested || subSprite == null)
|
||||
{
|
||||
ReleaseSubAssetsIfUnused(location);
|
||||
return;
|
||||
}
|
||||
@ -39,11 +84,17 @@ namespace AlicizaX.Resource.Runtime
|
||||
|
||||
public async UniTask SetSubSprite(SpriteRenderer spriteRenderer, string location, string spriteName, CancellationToken cancellationToken = default)
|
||||
{
|
||||
var subSprite = await GetSubSpriteImp(location, spriteName, cancellationToken);
|
||||
|
||||
if (spriteRenderer == null)
|
||||
{
|
||||
Log.Warning($"SetSubAssets Image is null");
|
||||
Log.Warning("SetSubAssets Image is null");
|
||||
return;
|
||||
}
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
var subSprite = await GetSubSpriteImp(location, spriteName, cancellationToken);
|
||||
|
||||
if (spriteRenderer == null || cancellationToken.IsCancellationRequested || subSprite == null)
|
||||
{
|
||||
ReleaseSubAssetsIfUnused(location);
|
||||
return;
|
||||
}
|
||||
@ -57,17 +108,28 @@ namespace AlicizaX.Resource.Runtime
|
||||
var assetInfo = YooAssets.GetAssetInfo(location);
|
||||
if (assetInfo.IsInvalid)
|
||||
{
|
||||
throw new GameFrameworkException($"Invalid location: {location}");
|
||||
throw new GameFrameworkException(ZString.Format("Invalid location: {0}", location));
|
||||
}
|
||||
|
||||
SubSpriteKey key = new SubSpriteKey(location, spriteName);
|
||||
if (_subSpriteCache.TryGetValue(key, out Sprite cachedSprite))
|
||||
{
|
||||
return cachedSprite;
|
||||
}
|
||||
|
||||
var subAssetsHandle = await GetOrLoadSubAssetsHandleAsync(location, cancellationToken);
|
||||
if (!subAssetsHandle.IsValid)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var subSprite = subAssetsHandle.GetSubAssetObject<Sprite>(spriteName);
|
||||
if (subSprite == null)
|
||||
{
|
||||
throw new GameFrameworkException($"Invalid sprite name: {spriteName}");
|
||||
throw new GameFrameworkException(ZString.Format("Invalid sprite name: {0}", spriteName));
|
||||
}
|
||||
|
||||
_subSpriteCache[key] = subSprite;
|
||||
return subSprite;
|
||||
}
|
||||
|
||||
@ -104,6 +166,7 @@ namespace AlicizaX.Resource.Runtime
|
||||
{
|
||||
subAssetsHandle.Dispose();
|
||||
_subAssetsHandles.Remove(location);
|
||||
ClearSubSpriteCache(location);
|
||||
}
|
||||
}
|
||||
|
||||
@ -130,31 +193,59 @@ namespace AlicizaX.Resource.Runtime
|
||||
continue;
|
||||
}
|
||||
|
||||
var completionSource = new UniTaskCompletionSource<SubAssetsHandle>();
|
||||
var completionSource = AutoResetUniTaskCompletionSource<SubAssetsHandle>.Create();
|
||||
_subAssetLoadingOperations.Add(location, completionSource);
|
||||
|
||||
SubAssetsHandle subAssetsHandle = default;
|
||||
try
|
||||
SubAssetsHandle subAssetsHandle = YooAssets.LoadSubAssetsAsync<Sprite>(location);
|
||||
while (subAssetsHandle is { IsValid: true, IsDone: false })
|
||||
{
|
||||
subAssetsHandle = YooAssets.LoadSubAssetsAsync<Sprite>(location);
|
||||
await subAssetsHandle.ToUniTask();
|
||||
_subAssetsHandles[location] = subAssetsHandle;
|
||||
completionSource.TrySetResult(subAssetsHandle);
|
||||
return subAssetsHandle;
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
DisposeSubAssetsHandle(subAssetsHandle);
|
||||
CompleteSubAssetLoading(location, completionSource, default);
|
||||
return default;
|
||||
}
|
||||
|
||||
await UniTask.Yield();
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
if (!subAssetsHandle.IsValid || subAssetsHandle.Status == EOperationStatus.Failed)
|
||||
{
|
||||
subAssetsHandle?.Dispose();
|
||||
completionSource.TrySetException(ex);
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_subAssetLoadingOperations.Remove(location);
|
||||
DisposeSubAssetsHandle(subAssetsHandle);
|
||||
CompleteSubAssetLoading(location, completionSource, default);
|
||||
return default;
|
||||
}
|
||||
|
||||
_subAssetsHandles[location] = subAssetsHandle;
|
||||
CompleteSubAssetLoading(location, completionSource, subAssetsHandle);
|
||||
return subAssetsHandle;
|
||||
}
|
||||
}
|
||||
|
||||
private void CompleteSubAssetLoading(string location, AutoResetUniTaskCompletionSource<SubAssetsHandle> completionSource, SubAssetsHandle subAssetsHandle)
|
||||
{
|
||||
_subAssetLoadingOperations.Remove(location);
|
||||
completionSource.TrySetResult(subAssetsHandle);
|
||||
}
|
||||
|
||||
private static void DisposeSubAssetsHandle(SubAssetsHandle subAssetsHandle)
|
||||
{
|
||||
if (subAssetsHandle.IsValid)
|
||||
{
|
||||
subAssetsHandle.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearSubSpriteCache(string location)
|
||||
{
|
||||
if (_subSpriteCache.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_subSpriteCache.Clear();
|
||||
}
|
||||
|
||||
private void ReleaseSubAssetsIfUnused(string location)
|
||||
{
|
||||
if (string.IsNullOrEmpty(location))
|
||||
@ -171,6 +262,7 @@ namespace AlicizaX.Resource.Runtime
|
||||
{
|
||||
subAssetsHandle.Dispose();
|
||||
_subAssetsHandles.Remove(location);
|
||||
ClearSubSpriteCache(location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,10 +1,8 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using AlicizaX.ObjectPool;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace AlicizaX.Resource.Runtime
|
||||
@ -17,54 +15,27 @@ namespace AlicizaX.Resource.Runtime
|
||||
{
|
||||
public static ResourceExtComponent Instance { private set; get; }
|
||||
|
||||
/// <summary>
|
||||
/// 检查是否可以释放间隔。
|
||||
/// </summary>
|
||||
[SerializeField]
|
||||
private float checkCanReleaseInterval = 30f;
|
||||
|
||||
/// <summary>
|
||||
/// 对象池自动释放时间间隔。
|
||||
/// </summary>
|
||||
[SerializeField]
|
||||
private float autoReleaseInterval = 60f;
|
||||
|
||||
/// <summary>
|
||||
/// 每帧最大处理资源数量,用于分帧处理避免卡顿。
|
||||
/// </summary>
|
||||
[SerializeField]
|
||||
private int maxProcessPerFrame = 50;
|
||||
|
||||
[SerializeField]
|
||||
private int releaseCheckThreshold = 16;
|
||||
|
||||
/// <summary>
|
||||
/// 当前正在处理的节点,用于分帧处理。
|
||||
/// </summary>
|
||||
private LinkedListNode<LoadAssetObject> _currentProcessNode;
|
||||
|
||||
/// <summary>
|
||||
/// 保存加载的图片对象。
|
||||
/// </summary>
|
||||
private LinkedList<LoadAssetObject> _loadAssetObjectsLinkedList;
|
||||
|
||||
private Dictionary<Object, LinkedListNode<LoadAssetObject>> _trackedAssetNodes;
|
||||
private LoadAssetObject[] _loadAssetObjects;
|
||||
private int _loadAssetObjectCount;
|
||||
private int _currentProcessIndex;
|
||||
private Dictionary<Object, int> _trackedAssetIndices;
|
||||
private bool _releaseRequested;
|
||||
private float _nextReleaseCheckTime = float.MaxValue;
|
||||
|
||||
/// <summary>
|
||||
/// 散图集合对象池。
|
||||
/// </summary>
|
||||
private IObjectPool<AssetItemObject> _assetItemPool;
|
||||
|
||||
|
||||
#if UNITY_EDITOR
|
||||
public LinkedList<LoadAssetObject> LoadAssetObjectsLinkedList
|
||||
{
|
||||
get => _loadAssetObjectsLinkedList;
|
||||
set => _loadAssetObjectsLinkedList = value;
|
||||
}
|
||||
#endif
|
||||
private IEnumerator Start()
|
||||
{
|
||||
Instance = this;
|
||||
@ -80,8 +51,8 @@ namespace AlicizaX.Resource.Runtime
|
||||
capacity: 16,
|
||||
expireTime: 60,
|
||||
priority: 0));
|
||||
_loadAssetObjectsLinkedList = new LinkedList<LoadAssetObject>();
|
||||
_trackedAssetNodes = new Dictionary<Object, LinkedListNode<LoadAssetObject>>(16);
|
||||
_loadAssetObjects = new LoadAssetObject[16];
|
||||
_trackedAssetIndices = new Dictionary<Object, int>(16);
|
||||
|
||||
InitializedResources();
|
||||
}
|
||||
@ -102,50 +73,36 @@ namespace AlicizaX.Resource.Runtime
|
||||
ReleaseUnused();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 回收无引用的缓存资产。
|
||||
/// 使用分帧处理优化性能,避免一次性处理大量资源导致卡顿。
|
||||
/// </summary>
|
||||
public void ReleaseUnused()
|
||||
{
|
||||
if (_loadAssetObjectsLinkedList == null || _loadAssetObjectsLinkedList.Count == 0)
|
||||
if (_loadAssetObjectCount == 0)
|
||||
{
|
||||
_currentProcessNode = null;
|
||||
_currentProcessIndex = 0;
|
||||
_releaseRequested = false;
|
||||
_nextReleaseCheckTime = float.MaxValue;
|
||||
enabled = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// 如果当前没有正在处理的节点,从头开始
|
||||
if (_currentProcessNode == null)
|
||||
{
|
||||
_currentProcessNode = _loadAssetObjectsLinkedList.First;
|
||||
}
|
||||
|
||||
int processedCount = 0;
|
||||
LinkedListNode<LoadAssetObject> current = _currentProcessNode;
|
||||
|
||||
// 分帧处理:每帧最多处理 maxProcessPerFrame 个资源
|
||||
while (current != null && processedCount < maxProcessPerFrame)
|
||||
while (_currentProcessIndex < _loadAssetObjectCount && processedCount < maxProcessPerFrame)
|
||||
{
|
||||
var next = current.Next;
|
||||
|
||||
if (current.Value.AssetObject.IsCanRelease())
|
||||
LoadAssetObject item = _loadAssetObjects[_currentProcessIndex];
|
||||
if (item.AssetObject.IsCanRelease())
|
||||
{
|
||||
RemoveTrackedNode(current, releaseAsset: true);
|
||||
RemoveTrackedAt(_currentProcessIndex, releaseAsset: true);
|
||||
}
|
||||
else
|
||||
{
|
||||
_currentProcessIndex++;
|
||||
}
|
||||
|
||||
current = next;
|
||||
processedCount++;
|
||||
}
|
||||
|
||||
// 更新当前处理节点
|
||||
_currentProcessNode = current;
|
||||
|
||||
// 如果已经处理完所有节点,重置状态
|
||||
if (_currentProcessNode == null)
|
||||
if (_currentProcessIndex >= _loadAssetObjectCount)
|
||||
{
|
||||
_currentProcessIndex = 0;
|
||||
_releaseRequested = false;
|
||||
_nextReleaseCheckTime = float.MaxValue;
|
||||
enabled = false;
|
||||
@ -159,15 +116,17 @@ namespace AlicizaX.Resource.Runtime
|
||||
private void SetAsset(ISetAssetObject setAssetObject, Object assetObject)
|
||||
{
|
||||
ReplaceTrackedAsset(setAssetObject.TargetObject);
|
||||
EnsureTrackedCapacity(_loadAssetObjectCount + 1);
|
||||
|
||||
var node = _loadAssetObjectsLinkedList.AddLast(new LoadAssetObject(setAssetObject, assetObject));
|
||||
int index = _loadAssetObjectCount++;
|
||||
_loadAssetObjects[index] = LoadAssetObject.Create(setAssetObject, assetObject);
|
||||
if (setAssetObject.TargetObject != null)
|
||||
{
|
||||
_trackedAssetNodes[setAssetObject.TargetObject] = node;
|
||||
_trackedAssetIndices[setAssetObject.TargetObject] = index;
|
||||
}
|
||||
|
||||
setAssetObject.SetAsset(assetObject);
|
||||
if (_loadAssetObjectsLinkedList.Count >= releaseCheckThreshold)
|
||||
if (_loadAssetObjectCount >= releaseCheckThreshold)
|
||||
{
|
||||
ScheduleReleaseSweep();
|
||||
}
|
||||
@ -175,73 +134,105 @@ namespace AlicizaX.Resource.Runtime
|
||||
|
||||
private void ReplaceTrackedAsset(Object target)
|
||||
{
|
||||
if (target == null || _trackedAssetNodes == null)
|
||||
if (target == null || _trackedAssetIndices == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_trackedAssetNodes.TryGetValue(target, out var existingNode))
|
||||
if (_trackedAssetIndices.TryGetValue(target, out int existingIndex))
|
||||
{
|
||||
if (_currentProcessNode == existingNode)
|
||||
{
|
||||
_currentProcessNode = existingNode.Next;
|
||||
}
|
||||
|
||||
RemoveTrackedNode(existingNode, releaseAsset: true);
|
||||
RemoveTrackedAt(existingIndex, releaseAsset: true);
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveTrackedNode(LinkedListNode<LoadAssetObject> node, bool releaseAsset)
|
||||
private void RemoveTrackedAt(int index, bool releaseAsset)
|
||||
{
|
||||
if (node == null)
|
||||
if (index < 0 || index >= _loadAssetObjectCount)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var trackedObject = node.Value.AssetObject?.TargetObject;
|
||||
if (trackedObject != null && _trackedAssetNodes != null)
|
||||
LoadAssetObject item = _loadAssetObjects[index];
|
||||
var trackedObject = item.AssetObject?.TargetObject;
|
||||
if (trackedObject != null && _trackedAssetIndices != null)
|
||||
{
|
||||
_trackedAssetNodes.Remove(trackedObject);
|
||||
_trackedAssetIndices.Remove(trackedObject);
|
||||
}
|
||||
|
||||
if (releaseAsset && node.Value.AssetTarget != null)
|
||||
if (releaseAsset && item.AssetTarget != null)
|
||||
{
|
||||
_resourceService?.UnloadAsset(node.Value.AssetTarget);
|
||||
_assetItemPool?.Unspawn(node.Value.AssetTarget);
|
||||
_resourceService?.UnloadAsset(item.AssetTarget);
|
||||
_assetItemPool?.Unspawn(item.AssetTarget);
|
||||
}
|
||||
|
||||
if (node.Value.AssetObject != null)
|
||||
if (item.AssetObject != null)
|
||||
{
|
||||
MemoryPool.Release(node.Value.AssetObject);
|
||||
ReleaseSetAssetObject(item.AssetObject);
|
||||
}
|
||||
|
||||
_loadAssetObjectsLinkedList?.Remove(node);
|
||||
if (_loadAssetObjectsLinkedList != null && _loadAssetObjectsLinkedList.Count > 0)
|
||||
MemoryPool.Release(item);
|
||||
|
||||
int lastIndex = _loadAssetObjectCount - 1;
|
||||
if (index != lastIndex)
|
||||
{
|
||||
LoadAssetObject lastItem = _loadAssetObjects[lastIndex];
|
||||
_loadAssetObjects[index] = lastItem;
|
||||
Object movedTarget = lastItem.AssetObject?.TargetObject;
|
||||
if (movedTarget != null && _trackedAssetIndices != null)
|
||||
{
|
||||
_trackedAssetIndices[movedTarget] = index;
|
||||
}
|
||||
}
|
||||
|
||||
_loadAssetObjects[lastIndex] = null;
|
||||
_loadAssetObjectCount = lastIndex;
|
||||
if (_currentProcessIndex > index)
|
||||
{
|
||||
_currentProcessIndex--;
|
||||
}
|
||||
|
||||
if (_loadAssetObjectCount > 0)
|
||||
{
|
||||
ScheduleReleaseSweep(checkCanReleaseInterval);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static void ReleaseSetAssetObject(ISetAssetObject assetObject)
|
||||
{
|
||||
if (assetObject is SetSpriteObject setSpriteObject)
|
||||
{
|
||||
MemoryPool.Release(setSpriteObject);
|
||||
}
|
||||
}
|
||||
private void ReleaseTrackedAssets()
|
||||
{
|
||||
if (_loadAssetObjectsLinkedList == null)
|
||||
for (int i = _loadAssetObjectCount - 1; i >= 0; i--)
|
||||
{
|
||||
RemoveTrackedAt(i, releaseAsset: true);
|
||||
}
|
||||
|
||||
_currentProcessIndex = 0;
|
||||
_trackedAssetIndices?.Clear();
|
||||
_releaseRequested = false;
|
||||
_nextReleaseCheckTime = float.MaxValue;
|
||||
enabled = false;
|
||||
}
|
||||
|
||||
private void EnsureTrackedCapacity(int capacity)
|
||||
{
|
||||
if (_loadAssetObjects.Length >= capacity)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var current = _loadAssetObjectsLinkedList.First;
|
||||
while (current != null)
|
||||
int newCapacity = _loadAssetObjects.Length << 1;
|
||||
while (newCapacity < capacity)
|
||||
{
|
||||
var next = current.Next;
|
||||
RemoveTrackedNode(current, releaseAsset: true);
|
||||
current = next;
|
||||
newCapacity <<= 1;
|
||||
}
|
||||
|
||||
_currentProcessNode = null;
|
||||
_trackedAssetNodes?.Clear();
|
||||
_releaseRequested = false;
|
||||
_nextReleaseCheckTime = float.MaxValue;
|
||||
enabled = false;
|
||||
Array.Resize(ref _loadAssetObjects, newCapacity);
|
||||
}
|
||||
|
||||
private void ScheduleReleaseSweep(float delay = 0f)
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
@ -26,10 +25,12 @@ namespace AlicizaX.Resource.Runtime
|
||||
private GameObject sourceGameObject;
|
||||
|
||||
[SerializeField]
|
||||
private List<AssetsRefInfo> refAssetInfoList;
|
||||
private AssetsRefInfo[] refAssetInfoArray;
|
||||
|
||||
[SerializeField]
|
||||
private int refAssetInfoCount;
|
||||
|
||||
private static IResourceService _resourceService;
|
||||
private HashSet<int> _refAssetIds;
|
||||
|
||||
private bool TryEnsureResourceModule()
|
||||
{
|
||||
@ -51,26 +52,19 @@ namespace AlicizaX.Resource.Runtime
|
||||
}
|
||||
}
|
||||
|
||||
private void EnsureReferenceCache()
|
||||
private bool ContainsRefAsset(int instanceId)
|
||||
{
|
||||
if (_refAssetIds != null)
|
||||
for (int i = 0; i < refAssetInfoCount; i++)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_refAssetIds = new HashSet<int>();
|
||||
if (refAssetInfoList == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var refInfo in refAssetInfoList)
|
||||
{
|
||||
if (refInfo.refAsset != null)
|
||||
AssetsRefInfo refInfo = refAssetInfoArray[i];
|
||||
int refInstanceId = refInfo.instanceId != 0 ? refInfo.instanceId : refInfo.refAsset != null ? refInfo.refAsset.GetInstanceID() : 0;
|
||||
if (refInstanceId == instanceId)
|
||||
{
|
||||
_refAssetIds.Add(refInfo.instanceId != 0 ? refInfo.instanceId : refInfo.refAsset.GetInstanceID());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
@ -78,40 +72,60 @@ namespace AlicizaX.Resource.Runtime
|
||||
if (!TryEnsureResourceModule())
|
||||
{
|
||||
sourceGameObject = null;
|
||||
refAssetInfoList?.Clear();
|
||||
_refAssetIds?.Clear();
|
||||
ClearRefAssetInfoArray();
|
||||
return;
|
||||
}
|
||||
|
||||
ReleaseSourceReference();
|
||||
ReleaseRefAssetInfoList();
|
||||
ReleaseRefAssetInfoArray();
|
||||
}
|
||||
|
||||
private void ReleaseRefAssetInfoList()
|
||||
private void ReleaseRefAssetInfoArray()
|
||||
{
|
||||
if (refAssetInfoList != null)
|
||||
for (int i = 0; i < refAssetInfoCount; i++)
|
||||
{
|
||||
foreach (var refInfo in refAssetInfoList)
|
||||
{
|
||||
_resourceService.UnloadAsset(refInfo.refAsset);
|
||||
}
|
||||
|
||||
refAssetInfoList.Clear();
|
||||
_resourceService.UnloadAsset(refAssetInfoArray[i].refAsset);
|
||||
}
|
||||
|
||||
_refAssetIds?.Clear();
|
||||
ClearRefAssetInfoArray();
|
||||
}
|
||||
|
||||
private void ClearRefAssetInfoArray()
|
||||
{
|
||||
for (int i = 0; i < refAssetInfoCount; i++)
|
||||
{
|
||||
refAssetInfoArray[i] = default;
|
||||
}
|
||||
|
||||
refAssetInfoCount = 0;
|
||||
}
|
||||
|
||||
private void EnsureRefAssetCapacity(int capacity)
|
||||
{
|
||||
if (refAssetInfoArray != null && refAssetInfoArray.Length >= capacity)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int newCapacity = refAssetInfoArray == null || refAssetInfoArray.Length == 0 ? 4 : refAssetInfoArray.Length << 1;
|
||||
while (newCapacity < capacity)
|
||||
{
|
||||
newCapacity <<= 1;
|
||||
}
|
||||
|
||||
Array.Resize(ref refAssetInfoArray, newCapacity);
|
||||
}
|
||||
|
||||
public AssetsReference Ref(GameObject source, IResourceService resourceService = null)
|
||||
{
|
||||
if (source == null)
|
||||
{
|
||||
throw new GameFrameworkException($"Source gameObject is null.");
|
||||
throw new GameFrameworkException("Source gameObject is null.");
|
||||
}
|
||||
|
||||
if (source.scene.name != null)
|
||||
{
|
||||
throw new GameFrameworkException($"Source gameObject is in scene.");
|
||||
throw new GameFrameworkException("Source gameObject is in scene.");
|
||||
}
|
||||
|
||||
if (resourceService != null)
|
||||
@ -132,7 +146,7 @@ namespace AlicizaX.Resource.Runtime
|
||||
{
|
||||
if (source == null)
|
||||
{
|
||||
throw new GameFrameworkException($"Source gameObject is null.");
|
||||
throw new GameFrameworkException("Source gameObject is null.");
|
||||
}
|
||||
|
||||
if (resourceService != null)
|
||||
@ -140,19 +154,14 @@ namespace AlicizaX.Resource.Runtime
|
||||
_resourceService = resourceService;
|
||||
}
|
||||
|
||||
EnsureReferenceCache();
|
||||
int instanceId = source.GetInstanceID();
|
||||
if (!_refAssetIds.Add(instanceId))
|
||||
if (ContainsRefAsset(instanceId))
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
if (refAssetInfoList == null)
|
||||
{
|
||||
refAssetInfoList = new List<AssetsRefInfo>();
|
||||
}
|
||||
|
||||
refAssetInfoList.Add(new AssetsRefInfo(source));
|
||||
EnsureRefAssetCapacity(refAssetInfoCount + 1);
|
||||
refAssetInfoArray[refAssetInfoCount++] = new AssetsRefInfo(source);
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -160,12 +169,12 @@ namespace AlicizaX.Resource.Runtime
|
||||
{
|
||||
if (source == null)
|
||||
{
|
||||
throw new GameFrameworkException($"Source gameObject is null.");
|
||||
throw new GameFrameworkException("Source gameObject is null.");
|
||||
}
|
||||
|
||||
if (source.scene.name != null)
|
||||
{
|
||||
throw new GameFrameworkException($"Source gameObject is in scene.");
|
||||
throw new GameFrameworkException("Source gameObject is in scene.");
|
||||
}
|
||||
|
||||
GameObject instance = Object.Instantiate(source, parent);
|
||||
@ -176,12 +185,12 @@ namespace AlicizaX.Resource.Runtime
|
||||
{
|
||||
if (source == null)
|
||||
{
|
||||
throw new GameFrameworkException($"Source gameObject is null.");
|
||||
throw new GameFrameworkException("Source gameObject is null.");
|
||||
}
|
||||
|
||||
if (source.scene.name != null)
|
||||
{
|
||||
throw new GameFrameworkException($"Source gameObject is in scene.");
|
||||
throw new GameFrameworkException("Source gameObject is in scene.");
|
||||
}
|
||||
|
||||
var comp = instance.GetComponent<AssetsReference>();
|
||||
@ -192,7 +201,7 @@ namespace AlicizaX.Resource.Runtime
|
||||
{
|
||||
if (source == null)
|
||||
{
|
||||
throw new GameFrameworkException($"Source gameObject is null.");
|
||||
throw new GameFrameworkException("Source gameObject is null.");
|
||||
}
|
||||
|
||||
var comp = instance.GetComponent<AssetsReference>();
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
using AlicizaX;
|
||||
using AlicizaX;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
@ -6,6 +7,140 @@ namespace AlicizaX.Resource.Runtime
|
||||
{
|
||||
public static class AssetsSetHelper
|
||||
{
|
||||
private enum MaterialTargetType
|
||||
{
|
||||
Image,
|
||||
SpriteRenderer,
|
||||
MeshRenderer,
|
||||
MeshRendererShared,
|
||||
}
|
||||
|
||||
private sealed class MaterialSetRequest : IMemory
|
||||
{
|
||||
public MaterialTargetType TargetType;
|
||||
public Image Image;
|
||||
public SpriteRenderer SpriteRenderer;
|
||||
public MeshRenderer MeshRenderer;
|
||||
public bool NeedInstance;
|
||||
|
||||
public static MaterialSetRequest Create(Image image)
|
||||
{
|
||||
MaterialSetRequest request = MemoryPool.Acquire<MaterialSetRequest>();
|
||||
request.TargetType = MaterialTargetType.Image;
|
||||
request.Image = image;
|
||||
return request;
|
||||
}
|
||||
|
||||
public static MaterialSetRequest Create(SpriteRenderer spriteRenderer)
|
||||
{
|
||||
MaterialSetRequest request = MemoryPool.Acquire<MaterialSetRequest>();
|
||||
request.TargetType = MaterialTargetType.SpriteRenderer;
|
||||
request.SpriteRenderer = spriteRenderer;
|
||||
return request;
|
||||
}
|
||||
|
||||
public static MaterialSetRequest Create(MeshRenderer meshRenderer, bool needInstance, bool sharedMaterial)
|
||||
{
|
||||
MaterialSetRequest request = MemoryPool.Acquire<MaterialSetRequest>();
|
||||
request.TargetType = sharedMaterial ? MaterialTargetType.MeshRendererShared : MaterialTargetType.MeshRenderer;
|
||||
request.MeshRenderer = meshRenderer;
|
||||
request.NeedInstance = needInstance;
|
||||
return request;
|
||||
}
|
||||
|
||||
public void Apply(Material material)
|
||||
{
|
||||
if (material == null)
|
||||
{
|
||||
MemoryPool.Release(this);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (TargetType)
|
||||
{
|
||||
case MaterialTargetType.Image:
|
||||
{
|
||||
if (Image == null || Image.gameObject == null)
|
||||
{
|
||||
_resourceService.UnloadAsset(material);
|
||||
MemoryPool.Release(this);
|
||||
return;
|
||||
}
|
||||
|
||||
Image.material = material;
|
||||
AssetsReference.Ref(material, Image.gameObject);
|
||||
break;
|
||||
}
|
||||
case MaterialTargetType.SpriteRenderer:
|
||||
{
|
||||
if (SpriteRenderer == null || SpriteRenderer.gameObject == null)
|
||||
{
|
||||
_resourceService.UnloadAsset(material);
|
||||
MemoryPool.Release(this);
|
||||
return;
|
||||
}
|
||||
|
||||
SpriteRenderer.material = material;
|
||||
AssetsReference.Ref(material, SpriteRenderer.gameObject);
|
||||
break;
|
||||
}
|
||||
case MaterialTargetType.MeshRenderer:
|
||||
{
|
||||
if (MeshRenderer == null || MeshRenderer.gameObject == null)
|
||||
{
|
||||
_resourceService.UnloadAsset(material);
|
||||
MemoryPool.Release(this);
|
||||
return;
|
||||
}
|
||||
|
||||
SetMeshMaterial(MeshRenderer, material, NeedInstance);
|
||||
break;
|
||||
}
|
||||
case MaterialTargetType.MeshRendererShared:
|
||||
{
|
||||
if (MeshRenderer == null || MeshRenderer.gameObject == null)
|
||||
{
|
||||
_resourceService.UnloadAsset(material);
|
||||
MemoryPool.Release(this);
|
||||
return;
|
||||
}
|
||||
|
||||
MeshRenderer.sharedMaterial = material;
|
||||
AssetsReference.Ref(material, MeshRenderer.gameObject);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
MemoryPool.Release(this);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
TargetType = MaterialTargetType.Image;
|
||||
Image = null;
|
||||
SpriteRenderer = null;
|
||||
MeshRenderer = null;
|
||||
NeedInstance = false;
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class MaterialLoadCallbacks
|
||||
{
|
||||
public static readonly LoadAssetCallbacks Instance = new LoadAssetCallbacks(OnSuccess, OnFailure);
|
||||
|
||||
private static void OnSuccess(string assetName, object asset, float duration, object userData)
|
||||
{
|
||||
MaterialSetRequest request = (MaterialSetRequest)userData;
|
||||
request.Apply(asset as Material);
|
||||
}
|
||||
|
||||
private static void OnFailure(string assetName, LoadResourceStatus status, string errorMessage, object userData)
|
||||
{
|
||||
MaterialSetRequest request = (MaterialSetRequest)userData;
|
||||
MemoryPool.Release(request);
|
||||
}
|
||||
}
|
||||
|
||||
private static IResourceService _resourceService;
|
||||
|
||||
private static void CheckResourceManager()
|
||||
@ -16,13 +151,39 @@ namespace AlicizaX.Resource.Runtime
|
||||
}
|
||||
}
|
||||
|
||||
private static void LoadMaterialAsync(string location, string packageName, MaterialSetRequest request)
|
||||
{
|
||||
_resourceService.LoadAssetAsync(location, typeof(Material), 0, MaterialLoadCallbacks.Instance, request, packageName).Forget();
|
||||
}
|
||||
|
||||
private static void SetMeshMaterial(MeshRenderer meshRenderer, Material material, bool needInstance)
|
||||
{
|
||||
if (!needInstance)
|
||||
{
|
||||
meshRenderer.material = material;
|
||||
AssetsReference.Ref(material, meshRenderer.gameObject);
|
||||
return;
|
||||
}
|
||||
|
||||
Material instance = Object.Instantiate(material);
|
||||
meshRenderer.material = instance;
|
||||
AssetsReference.Ref(material, meshRenderer.gameObject);
|
||||
var reference = meshRenderer.GetComponent<MaterialInstanceReference>();
|
||||
if (reference == null)
|
||||
{
|
||||
reference = meshRenderer.gameObject.AddComponent<MaterialInstanceReference>();
|
||||
}
|
||||
|
||||
reference.Set(instance);
|
||||
}
|
||||
|
||||
#region SetMaterial
|
||||
|
||||
public static void SetMaterial(this Image image, string location, bool isAsync = false, string packageName = "")
|
||||
{
|
||||
if (image == null)
|
||||
{
|
||||
throw new GameFrameworkException($"SetSprite failed. Because image is null.");
|
||||
throw new GameFrameworkException("SetSprite failed. Because image is null.");
|
||||
}
|
||||
|
||||
CheckResourceManager();
|
||||
@ -32,29 +193,17 @@ namespace AlicizaX.Resource.Runtime
|
||||
Material material = _resourceService.LoadAsset<Material>(location, packageName);
|
||||
image.material = material;
|
||||
AssetsReference.Ref(material, image.gameObject);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
_resourceService.LoadAsset<Material>(location, material =>
|
||||
{
|
||||
if (image == null || image.gameObject == null)
|
||||
{
|
||||
_resourceService.UnloadAsset(material);
|
||||
material = null;
|
||||
return;
|
||||
}
|
||||
|
||||
image.material = material;
|
||||
AssetsReference.Ref(material, image.gameObject);
|
||||
}, packageName);
|
||||
}
|
||||
LoadMaterialAsync(location, packageName, MaterialSetRequest.Create(image));
|
||||
}
|
||||
|
||||
public static void SetMaterial(this SpriteRenderer spriteRenderer, string location, bool isAsync = false, string packageName = "")
|
||||
{
|
||||
if (spriteRenderer == null)
|
||||
{
|
||||
throw new GameFrameworkException($"SetSprite failed. Because image is null.");
|
||||
throw new GameFrameworkException("SetSprite failed. Because image is null.");
|
||||
}
|
||||
|
||||
CheckResourceManager();
|
||||
@ -64,29 +213,17 @@ namespace AlicizaX.Resource.Runtime
|
||||
Material material = _resourceService.LoadAsset<Material>(location, packageName);
|
||||
spriteRenderer.material = material;
|
||||
AssetsReference.Ref(material, spriteRenderer.gameObject);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
_resourceService.LoadAsset<Material>(location, material =>
|
||||
{
|
||||
if (spriteRenderer == null || spriteRenderer.gameObject == null)
|
||||
{
|
||||
_resourceService.UnloadAsset(material);
|
||||
material = null;
|
||||
return;
|
||||
}
|
||||
|
||||
spriteRenderer.material = material;
|
||||
AssetsReference.Ref(material, spriteRenderer.gameObject);
|
||||
}, packageName);
|
||||
}
|
||||
LoadMaterialAsync(location, packageName, MaterialSetRequest.Create(spriteRenderer));
|
||||
}
|
||||
|
||||
public static void SetMaterial(this MeshRenderer meshRenderer, string location, bool needInstance = true, bool isAsync = false, string packageName = "")
|
||||
{
|
||||
if (meshRenderer == null)
|
||||
{
|
||||
throw new GameFrameworkException($"SetSprite failed. Because image is null.");
|
||||
throw new GameFrameworkException("SetSprite failed. Because image is null.");
|
||||
}
|
||||
|
||||
CheckResourceManager();
|
||||
@ -94,31 +231,18 @@ namespace AlicizaX.Resource.Runtime
|
||||
if (!isAsync)
|
||||
{
|
||||
Material material = _resourceService.LoadAsset<Material>(location, packageName);
|
||||
meshRenderer.material = needInstance ? Object.Instantiate(material) : material;
|
||||
AssetsReference.Ref(material, meshRenderer.gameObject);
|
||||
SetMeshMaterial(meshRenderer, material, needInstance);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
_resourceService.LoadAsset<Material>(location, material =>
|
||||
{
|
||||
if (meshRenderer == null || meshRenderer.gameObject == null)
|
||||
{
|
||||
_resourceService.UnloadAsset(material);
|
||||
material = null;
|
||||
return;
|
||||
}
|
||||
|
||||
meshRenderer.material = needInstance ? Object.Instantiate(material) : material;
|
||||
AssetsReference.Ref(material, meshRenderer.gameObject);
|
||||
}, packageName);
|
||||
}
|
||||
LoadMaterialAsync(location, packageName, MaterialSetRequest.Create(meshRenderer, needInstance, false));
|
||||
}
|
||||
|
||||
public static void SetSharedMaterial(this MeshRenderer meshRenderer, string location, bool isAsync = false, string packageName = "")
|
||||
{
|
||||
if (meshRenderer == null)
|
||||
{
|
||||
throw new GameFrameworkException($"SetSprite failed. Because image is null.");
|
||||
throw new GameFrameworkException("SetSprite failed. Because image is null.");
|
||||
}
|
||||
|
||||
CheckResourceManager();
|
||||
@ -128,22 +252,10 @@ namespace AlicizaX.Resource.Runtime
|
||||
Material material = _resourceService.LoadAsset<Material>(location, packageName);
|
||||
meshRenderer.sharedMaterial = material;
|
||||
AssetsReference.Ref(material, meshRenderer.gameObject);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
_resourceService.LoadAsset<Material>(location, material =>
|
||||
{
|
||||
if (meshRenderer == null || meshRenderer.gameObject == null)
|
||||
{
|
||||
_resourceService.UnloadAsset(material);
|
||||
material = null;
|
||||
return;
|
||||
}
|
||||
|
||||
meshRenderer.sharedMaterial = material;
|
||||
AssetsReference.Ref(material, meshRenderer.gameObject);
|
||||
}, packageName);
|
||||
}
|
||||
LoadMaterialAsync(location, packageName, MaterialSetRequest.Create(meshRenderer, false, true));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@ -1,3 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 370ab69f738b11b429fbcc1d9e7a2fb1
|
||||
timeCreated: 1708490345
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
||||
@ -0,0 +1,29 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace AlicizaX.Resource.Runtime
|
||||
{
|
||||
[DisallowMultipleComponent]
|
||||
public sealed class MaterialInstanceReference : MonoBehaviour
|
||||
{
|
||||
private Material _material;
|
||||
|
||||
public void Set(Material material)
|
||||
{
|
||||
if (_material != null && _material != material)
|
||||
{
|
||||
Object.Destroy(_material);
|
||||
}
|
||||
|
||||
_material = material;
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
if (_material != null)
|
||||
{
|
||||
Object.Destroy(_material);
|
||||
_material = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: eec0821e60a7c3946b3b434cfdbd999d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System;
|
||||
using Cysharp.Text;
|
||||
using AlicizaX;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
@ -17,6 +18,8 @@ namespace AlicizaX.Resource.Runtime
|
||||
|
||||
private bool _forceUnloadUnusedAssets = false;
|
||||
|
||||
private bool _forceSystemUnloadUnusedAssets = false;
|
||||
|
||||
private bool _preorderUnloadUnusedAssets = false;
|
||||
|
||||
private bool _performGCCollect = false;
|
||||
@ -153,7 +156,9 @@ namespace AlicizaX.Resource.Runtime
|
||||
Application.lowMemory += OnLowMemory;
|
||||
}
|
||||
|
||||
public static string PrefsKey = Application.dataPath.GetHashCode() + "GamePlayMode";
|
||||
#if UNITY_EDITOR
|
||||
public static string PrefsKey = ZString.Concat(Application.dataPath.GetHashCode(), "GamePlayMode");
|
||||
#endif
|
||||
|
||||
private void Start()
|
||||
{
|
||||
@ -173,7 +178,7 @@ namespace AlicizaX.Resource.Runtime
|
||||
_resourceService.AssetExpireTime = assetExpireTime;
|
||||
_resourceService.AssetPriority = assetPriority;
|
||||
_resourceService.SetForceUnloadUnusedAssetsAction(ForceUnloadUnusedAssets);
|
||||
Log.Info($"ResourceModule Run Mode {_playMode}");
|
||||
Log.Info(ZString.Format("ResourceModule Run Mode {0}", _playMode));
|
||||
}
|
||||
|
||||
private void OnApplicationQuit()
|
||||
@ -189,6 +194,7 @@ namespace AlicizaX.Resource.Runtime
|
||||
if (performGCCollect)
|
||||
{
|
||||
_performGCCollect = true;
|
||||
_forceSystemUnloadUnusedAssets = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -200,12 +206,13 @@ namespace AlicizaX.Resource.Runtime
|
||||
if (_asyncOperation == null && (_forceUnloadUnusedAssets || _lastUnloadUnusedAssetsOperationElapseSeconds >= maxUnloadUnusedAssetsInterval ||
|
||||
_preorderUnloadUnusedAssets && _lastUnloadUnusedAssetsOperationElapseSeconds >= minUnloadUnusedAssetsInterval))
|
||||
{
|
||||
Log.Info("Unload unused assets...");
|
||||
bool useSystemUnload = _forceSystemUnloadUnusedAssets && useSystemUnloadUnusedAssets;
|
||||
_forceUnloadUnusedAssets = false;
|
||||
_forceSystemUnloadUnusedAssets = false;
|
||||
_preorderUnloadUnusedAssets = false;
|
||||
_lastUnloadUnusedAssetsOperationElapseSeconds = 0f;
|
||||
_resourceService.UnloadUnusedAssets();
|
||||
_asyncOperation = useSystemUnloadUnusedAssets ? Resources.UnloadUnusedAssets() : null;
|
||||
_asyncOperation = useSystemUnload ? Resources.UnloadUnusedAssets() : null;
|
||||
}
|
||||
|
||||
if (_asyncOperation == null && _performGCCollect)
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
using System.Buffers;
|
||||
using System.Buffers;
|
||||
using System.Collections.Generic;
|
||||
using AlicizaX.ObjectPool;
|
||||
using AlicizaX;
|
||||
@ -47,13 +47,10 @@ namespace AlicizaX.Resource.Runtime
|
||||
|
||||
protected internal override void Release(bool isShutdown)
|
||||
{
|
||||
if (!isShutdown)
|
||||
AssetHandle handle = m_AssetHandle;
|
||||
if (handle is { IsValid: true })
|
||||
{
|
||||
AssetHandle handle = m_AssetHandle;
|
||||
if (handle is { IsValid: true })
|
||||
{
|
||||
handle.Dispose();
|
||||
}
|
||||
handle.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using Cysharp.Text;
|
||||
using UnityEngine;
|
||||
using YooAsset;
|
||||
|
||||
@ -90,7 +91,7 @@ namespace AlicizaX.Resource.Runtime
|
||||
// 小游戏缓存根目录
|
||||
// 注意:此处代码根据微信插件配置来填写!
|
||||
WeChatWASM.WXBase.PreloadConcurrent(10);
|
||||
string packageRoot = $"{WeChatWASM.WX.env.USER_DATA_PATH}/__GAME_FILE_CACHE/yoo";
|
||||
string packageRoot = ZString.Concat(WeChatWASM.WX.env.USER_DATA_PATH, "/__GAME_FILE_CACHE/yoo");
|
||||
webRemoteFileSystemParams = WechatFileSystemCreater.CreateFileSystemParameters(packageRoot, remoteServices, null);
|
||||
#endif
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
using AlicizaX.ObjectPool;
|
||||
using AlicizaX.ObjectPool;
|
||||
using AlicizaX;
|
||||
|
||||
namespace AlicizaX.Resource.Runtime
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
using System.IO;
|
||||
using Cysharp.Text;
|
||||
using UnityEngine;
|
||||
using YooAsset;
|
||||
|
||||
@ -20,12 +21,12 @@ namespace AlicizaX.Resource.Runtime
|
||||
|
||||
string IRemoteServices.GetRemoteMainURL(string fileName)
|
||||
{
|
||||
return $"{_defaultHostServer}/{fileName}";
|
||||
return ZString.Concat(_defaultHostServer, "/", fileName);
|
||||
}
|
||||
|
||||
string IRemoteServices.GetRemoteFallbackURL(string fileName)
|
||||
{
|
||||
return $"{_fallbackHostServer}/{fileName}";
|
||||
return ZString.Concat(_fallbackHostServer, "/", fileName);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using AlicizaX.ObjectPool;
|
||||
using AlicizaX;
|
||||
using Cysharp.Text;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using YooAsset;
|
||||
@ -28,7 +29,7 @@ namespace AlicizaX.Resource.Runtime
|
||||
public string DecryptionServices { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 自动释放资源引用计数为0的资源包
|
||||
/// 自动释放资源引用计数。。的资源包
|
||||
/// </summary>
|
||||
public bool AutoUnloadBundleWhenUnused { get; set; } = false;
|
||||
|
||||
@ -60,7 +61,6 @@ namespace AlicizaX.Resource.Runtime
|
||||
|
||||
public int FailedTryAgain { get; set; }
|
||||
|
||||
|
||||
#region internal
|
||||
|
||||
/// <summary>
|
||||
@ -76,39 +76,89 @@ namespace AlicizaX.Resource.Runtime
|
||||
/// <summary>
|
||||
/// 资源信息列表。
|
||||
/// </summary>
|
||||
private readonly Dictionary<string, AssetInfo> _assetInfoMap = new Dictionary<string, AssetInfo>();
|
||||
private readonly Dictionary<AssetCacheKey, AssetInfo> _assetInfoMap = new Dictionary<AssetCacheKey, AssetInfo>(AssetCacheKeyComparer.Instance);
|
||||
|
||||
/// <summary>
|
||||
/// 正在加载的资源任务。
|
||||
/// </summary>
|
||||
private readonly Dictionary<string, UniTaskCompletionSource<bool>> _assetLoadingOperations = new Dictionary<string, UniTaskCompletionSource<bool>>();
|
||||
private readonly Dictionary<string, AutoResetUniTaskCompletionSource<bool>> _assetLoadingOperations = new Dictionary<string, AutoResetUniTaskCompletionSource<bool>>();
|
||||
|
||||
private readonly Dictionary<AssetCacheKey, string> _assetObjectKeyMap = new Dictionary<AssetCacheKey, string>(AssetCacheKeyComparer.Instance);
|
||||
|
||||
private const float ProgressCallbackThreshold = 0.01f;
|
||||
|
||||
private UnloadUnusedAssetsOperation _unloadUnusedAssetsOperation;
|
||||
|
||||
private UnloadAllAssetsOperation _unloadAllAssetsOperation;
|
||||
|
||||
private readonly struct AssetCacheKey
|
||||
{
|
||||
public readonly string PackageName;
|
||||
|
||||
public readonly string Location;
|
||||
|
||||
public AssetCacheKey(string packageName, string location)
|
||||
{
|
||||
PackageName = packageName ?? string.Empty;
|
||||
Location = location ?? string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class AssetCacheKeyComparer : IEqualityComparer<AssetCacheKey>
|
||||
{
|
||||
public static readonly AssetCacheKeyComparer Instance = new AssetCacheKeyComparer();
|
||||
|
||||
private AssetCacheKeyComparer()
|
||||
{
|
||||
}
|
||||
|
||||
public bool Equals(AssetCacheKey x, AssetCacheKey y)
|
||||
{
|
||||
return string.Equals(x.PackageName, y.PackageName, StringComparison.Ordinal) &&
|
||||
string.Equals(x.Location, y.Location, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
public int GetHashCode(AssetCacheKey obj)
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
int hash = 17;
|
||||
hash = hash * 31 + StringComparer.Ordinal.GetHashCode(obj.PackageName ?? string.Empty);
|
||||
hash = hash * 31 + StringComparer.Ordinal.GetHashCode(obj.Location ?? string.Empty);
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
// 初始化资源系统
|
||||
// 初始化资源系。。
|
||||
YooAssets.Initialize(new ResourceLogger());
|
||||
|
||||
YooAssets.SetOperationSystemMaxTimeSlice(Milliseconds);
|
||||
|
||||
// 创建默认的资源包
|
||||
string packageName = DefaultPackageName;
|
||||
|
||||
var defaultPackage = YooAssets.TryGetPackage(packageName);
|
||||
|
||||
if (defaultPackage == null)
|
||||
|
||||
{
|
||||
defaultPackage = YooAssets.CreatePackage(packageName);
|
||||
|
||||
YooAssets.SetDefaultPackage(defaultPackage);
|
||||
}
|
||||
|
||||
DefaultPackage = defaultPackage;
|
||||
|
||||
PackageMap[packageName] = defaultPackage;
|
||||
|
||||
CreateAssetPool();
|
||||
}
|
||||
|
||||
|
||||
protected override void OnInitialize()
|
||||
{
|
||||
}
|
||||
@ -124,6 +174,7 @@ namespace AlicizaX.Resource.Runtime
|
||||
_assetPool = null;
|
||||
_assetLoadingOperations.Clear();
|
||||
_assetInfoMap.Clear();
|
||||
_assetObjectKeyMap.Clear();
|
||||
}
|
||||
|
||||
public UniTask<bool> InitPackageAsync(string packageName = "", string hostServerURL = "", string fallbackHostServerURL = "")
|
||||
@ -137,7 +188,7 @@ namespace AlicizaX.Resource.Runtime
|
||||
{
|
||||
if (resPackage.InitializeStatus is EOperationStatus.Processing or EOperationStatus.Succeed)
|
||||
{
|
||||
Log.Error($"ResourceSystem has already init package : {packageName}");
|
||||
Log.Error(ZString.Format("ResourceSystem has already init package : {0}", packageName));
|
||||
return new UniTask<bool>(false);
|
||||
}
|
||||
else
|
||||
@ -150,7 +201,6 @@ namespace AlicizaX.Resource.Runtime
|
||||
GameFrameworkGuard.NotNull(packageName, nameof(packageName));
|
||||
GameFrameworkGuard.NotNull(hostServerURL, nameof(hostServerURL));
|
||||
GameFrameworkGuard.NotNull(fallbackHostServerURL, nameof(fallbackHostServerURL));
|
||||
|
||||
// 创建默认的资源包
|
||||
var resourcePackage = YooAssets.TryGetPackage(packageName);
|
||||
if (resourcePackage == null)
|
||||
@ -159,7 +209,6 @@ namespace AlicizaX.Resource.Runtime
|
||||
}
|
||||
|
||||
PackageMap[packageName] = resourcePackage;
|
||||
|
||||
var initializationOperationHandler = CreateInitializationOperationHandler(resourcePackage, hostServerURL, fallbackHostServerURL, DecryptionServices);
|
||||
initializationOperationHandler.Completed += asyncOperationBase =>
|
||||
{
|
||||
@ -172,10 +221,10 @@ namespace AlicizaX.Resource.Runtime
|
||||
taskCompletionSource.TrySetException(new Exception(asyncOperationBase.Error));
|
||||
}
|
||||
};
|
||||
|
||||
return taskCompletionSource.Task;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 获取当前资源包版本。
|
||||
/// </summary>
|
||||
@ -186,6 +235,7 @@ namespace AlicizaX.Resource.Runtime
|
||||
var package = string.IsNullOrEmpty(customPackageName)
|
||||
? YooAssets.GetPackage(DefaultPackageName)
|
||||
: YooAssets.GetPackage(customPackageName);
|
||||
|
||||
if (package == null)
|
||||
{
|
||||
return string.Empty;
|
||||
@ -204,44 +254,29 @@ namespace AlicizaX.Resource.Runtime
|
||||
public RequestPackageVersionOperation RequestPackageVersionAsync(bool appendTimeTicks = false, int timeout = 60,
|
||||
string customPackageName = "")
|
||||
{
|
||||
var package = string.IsNullOrEmpty(customPackageName)
|
||||
? YooAssets.GetPackage(DefaultPackageName)
|
||||
: YooAssets.GetPackage(customPackageName);
|
||||
var package = GetPackageOrThrow(customPackageName);
|
||||
return package.RequestPackageVersionAsync(appendTimeTicks, timeout);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 向网络端请求并更新清单
|
||||
/// 向网络端请求并更新清。。
|
||||
/// </summary>
|
||||
/// <param name="packageVersion">更新的包裹版本</param>
|
||||
/// <param name="packageVersion">更新的包裹版。。</param>
|
||||
/// <param name="timeout">超时时间(默认值:60秒)</param>
|
||||
/// <param name="customPackageName">指定资源包的名称。不传使用默认资源包</param>
|
||||
public UpdatePackageManifestOperation UpdatePackageManifestAsync(string packageVersion, int timeout = 60, string customPackageName = "")
|
||||
{
|
||||
var package = string.IsNullOrEmpty(customPackageName)
|
||||
? YooAssets.GetPackage(this.DefaultPackageName)
|
||||
: YooAssets.GetPackage(customPackageName);
|
||||
var package = GetPackageOrThrow(customPackageName);
|
||||
return package.UpdatePackageManifestAsync(packageVersion, timeout);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 创建资源下载器,用于下载当前资源版本所有的资源包文件。
|
||||
/// </summary>
|
||||
/// <param name="customPackageName">指定资源包的名称。不传使用默认资源包</param>
|
||||
public ResourceDownloaderOperation CreateResourceDownloader(string customPackageName = "")
|
||||
{
|
||||
ResourcePackage package = null;
|
||||
if (string.IsNullOrEmpty(customPackageName))
|
||||
{
|
||||
package = YooAssets.GetPackage(this.DefaultPackageName);
|
||||
}
|
||||
else
|
||||
{
|
||||
package = YooAssets.GetPackage(customPackageName);
|
||||
}
|
||||
|
||||
ResourcePackage package = GetPackageOrThrow(customPackageName);
|
||||
return package.CreateResourceDownloader(DownloadingMaxNum, FailedTryAgain);
|
||||
}
|
||||
|
||||
@ -254,10 +289,8 @@ namespace AlicizaX.Resource.Runtime
|
||||
EFileClearMode clearMode = EFileClearMode.ClearUnusedBundleFiles,
|
||||
string customPackageName = "")
|
||||
{
|
||||
var package = string.IsNullOrEmpty(customPackageName)
|
||||
? YooAssets.GetPackage(DefaultPackageName)
|
||||
: YooAssets.GetPackage(customPackageName);
|
||||
return package.ClearCacheFilesAsync(EFileClearMode.ClearUnusedBundleFiles);
|
||||
var package = GetPackageOrThrow(customPackageName);
|
||||
return package.ClearCacheFilesAsync(clearMode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -266,9 +299,7 @@ namespace AlicizaX.Resource.Runtime
|
||||
/// <param name="customPackageName">指定资源包的名称。不传使用默认资源包</param>
|
||||
public void ClearAllBundleFiles(string customPackageName = "")
|
||||
{
|
||||
var package = string.IsNullOrEmpty(customPackageName)
|
||||
? YooAssets.GetPackage(DefaultPackageName)
|
||||
: YooAssets.GetPackage(customPackageName);
|
||||
var package = GetPackageOrThrow(customPackageName);
|
||||
package.ClearCacheFilesAsync(EFileClearMode.ClearAllBundleFiles);
|
||||
}
|
||||
|
||||
@ -297,11 +328,16 @@ namespace AlicizaX.Resource.Runtime
|
||||
public void UnloadUnusedAssets()
|
||||
{
|
||||
_assetPool.ReleaseAllUnused();
|
||||
if (_unloadUnusedAssetsOperation is { IsDone: false })
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var package in PackageMap.Values)
|
||||
{
|
||||
if (package is { InitializeStatus: EOperationStatus.Succeed })
|
||||
{
|
||||
package.UnloadUnusedAssetsAsync();
|
||||
_unloadUnusedAssetsOperation = package.UnloadUnusedAssetsAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -312,15 +348,19 @@ namespace AlicizaX.Resource.Runtime
|
||||
public void ForceUnloadAllAssets()
|
||||
{
|
||||
#if UNITY_WEBGL
|
||||
Log.Warning($"WebGL not support invoke {nameof(ForceUnloadAllAssets)}");
|
||||
Log.Warning(ZString.Format("WebGL not support invoke {0}", nameof(ForceUnloadAllAssets)));
|
||||
return;
|
||||
#else
|
||||
if (_unloadAllAssetsOperation is { IsDone: false })
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var package in PackageMap.Values)
|
||||
{
|
||||
if (package is { InitializeStatus: EOperationStatus.Succeed })
|
||||
{
|
||||
package.UnloadAllAssetsAsync();
|
||||
_unloadAllAssetsOperation = package.UnloadAllAssetsAsync();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -331,6 +371,19 @@ namespace AlicizaX.Resource.Runtime
|
||||
_forceUnloadUnusedAssetsAction?.Invoke(performGCCollect);
|
||||
}
|
||||
|
||||
private ResourcePackage GetPackageOrThrow(string packageName)
|
||||
{
|
||||
ResourcePackage package = string.IsNullOrEmpty(packageName)
|
||||
? YooAssets.GetPackage(DefaultPackageName)
|
||||
: YooAssets.GetPackage(packageName);
|
||||
if (package == null)
|
||||
{
|
||||
throw new GameFrameworkException(ZString.Format("The package does not exist. Package Name :{0}", string.IsNullOrEmpty(packageName) ? DefaultPackageName : packageName));
|
||||
}
|
||||
|
||||
return package;
|
||||
}
|
||||
|
||||
#region Public Methods
|
||||
|
||||
#region 获取资源信息
|
||||
@ -346,11 +399,9 @@ namespace AlicizaX.Resource.Runtime
|
||||
{
|
||||
return YooAssets.IsNeedDownloadFromRemote(location);
|
||||
}
|
||||
else
|
||||
{
|
||||
var package = YooAssets.GetPackage(packageName);
|
||||
return package.IsNeedDownloadFromRemote(location);
|
||||
}
|
||||
|
||||
var package = YooAssets.GetPackage(packageName);
|
||||
return package.IsNeedDownloadFromRemote(location);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -364,11 +415,9 @@ namespace AlicizaX.Resource.Runtime
|
||||
{
|
||||
return YooAssets.IsNeedDownloadFromRemote(assetInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
var package = YooAssets.GetPackage(packageName);
|
||||
return package.IsNeedDownloadFromRemote(assetInfo);
|
||||
}
|
||||
|
||||
var package = YooAssets.GetPackage(packageName);
|
||||
return package.IsNeedDownloadFromRemote(assetInfo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -383,11 +432,9 @@ namespace AlicizaX.Resource.Runtime
|
||||
{
|
||||
return YooAssets.GetAssetInfos(tag);
|
||||
}
|
||||
else
|
||||
{
|
||||
var package = YooAssets.GetPackage(packageName);
|
||||
return package.GetAssetInfos(tag);
|
||||
}
|
||||
|
||||
var package = YooAssets.GetPackage(packageName);
|
||||
return package.GetAssetInfos(tag);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -402,11 +449,9 @@ namespace AlicizaX.Resource.Runtime
|
||||
{
|
||||
return YooAssets.GetAssetInfos(tags);
|
||||
}
|
||||
else
|
||||
{
|
||||
var package = YooAssets.GetPackage(packageName);
|
||||
return package.GetAssetInfos(tags);
|
||||
}
|
||||
|
||||
var package = YooAssets.GetPackage(packageName);
|
||||
return package.GetAssetInfos(tags);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -424,18 +469,19 @@ namespace AlicizaX.Resource.Runtime
|
||||
|
||||
if (string.IsNullOrEmpty(packageName))
|
||||
{
|
||||
if (_assetInfoMap.TryGetValue(location, out AssetInfo assetInfo))
|
||||
AssetCacheKey key = new AssetCacheKey(DefaultPackageName, location);
|
||||
if (_assetInfoMap.TryGetValue(key, out AssetInfo assetInfo))
|
||||
{
|
||||
return assetInfo;
|
||||
}
|
||||
|
||||
assetInfo = YooAssets.GetAssetInfo(location);
|
||||
_assetInfoMap[location] = assetInfo;
|
||||
_assetInfoMap[key] = assetInfo;
|
||||
return assetInfo;
|
||||
}
|
||||
else
|
||||
{
|
||||
string key = $"{packageName}/{location}";
|
||||
AssetCacheKey key = new AssetCacheKey(packageName, location);
|
||||
if (_assetInfoMap.TryGetValue(key, out AssetInfo assetInfo))
|
||||
{
|
||||
return assetInfo;
|
||||
@ -444,7 +490,7 @@ namespace AlicizaX.Resource.Runtime
|
||||
var package = YooAssets.GetPackage(packageName);
|
||||
if (package == null)
|
||||
{
|
||||
throw new GameFrameworkException($"The package does not exist. Package Name :{packageName}");
|
||||
throw new GameFrameworkException(ZString.Format("The package does not exist. Package Name :{0}", packageName));
|
||||
}
|
||||
|
||||
assetInfo = package.GetAssetInfo(location);
|
||||
@ -467,10 +513,9 @@ namespace AlicizaX.Resource.Runtime
|
||||
}
|
||||
|
||||
AssetInfo assetInfo = GetAssetInfo(location, packageName);
|
||||
|
||||
if (!CheckLocationValid(location, packageName))
|
||||
{
|
||||
return HasAssetResult.Valid;
|
||||
return HasAssetResult.NotExist;
|
||||
}
|
||||
|
||||
if (assetInfo == null)
|
||||
@ -499,7 +544,7 @@ namespace AlicizaX.Resource.Runtime
|
||||
}
|
||||
|
||||
var package = YooAssets.GetPackage(packageName);
|
||||
return package.CheckLocationValid(location);
|
||||
return package != null && package.CheckLocationValid(location);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@ -546,6 +591,7 @@ namespace AlicizaX.Resource.Runtime
|
||||
private AssetHandle GetHandleAsync(string location, Type assetType, string packageName = "", uint priority = 0)
|
||||
{
|
||||
if (string.IsNullOrEmpty(packageName))
|
||||
|
||||
{
|
||||
return YooAssets.LoadAssetAsync(location, assetType, priority);
|
||||
}
|
||||
@ -574,7 +620,16 @@ namespace AlicizaX.Resource.Runtime
|
||||
return location;
|
||||
}
|
||||
|
||||
return $"{packageName}/{location}";
|
||||
AssetCacheKey key = new AssetCacheKey(packageName, location);
|
||||
|
||||
if (_assetObjectKeyMap.TryGetValue(key, out string cacheKey))
|
||||
{
|
||||
return cacheKey;
|
||||
}
|
||||
|
||||
cacheKey = ZString.Concat(packageName, "/", location);
|
||||
_assetObjectKeyMap[key] = cacheKey;
|
||||
return cacheKey;
|
||||
}
|
||||
|
||||
public T LoadAsset<T>(string location, string packageName = "") where T : UnityEngine.Object
|
||||
@ -586,21 +641,20 @@ namespace AlicizaX.Resource.Runtime
|
||||
|
||||
if (!CheckLocationValid(location, packageName))
|
||||
{
|
||||
Log.Error($"Could not found location [{location}].");
|
||||
Log.Error(ZString.Format("Could not found location [{0}].", location));
|
||||
return null;
|
||||
}
|
||||
|
||||
string assetObjectKey = GetCacheKey(location, packageName);
|
||||
AssetObject assetObject = _assetPool.Spawn(assetObjectKey);
|
||||
|
||||
if (assetObject != null)
|
||||
{
|
||||
return assetObject.Target as T;
|
||||
}
|
||||
|
||||
AssetHandle handle = GetHandleSync<T>(location, packageName: packageName);
|
||||
|
||||
T ret = handle.AssetObject as T;
|
||||
|
||||
assetObject = AssetObject.Create(assetObjectKey, handle.AssetObject, handle);
|
||||
_assetPool.Register(assetObject, true);
|
||||
|
||||
@ -616,21 +670,20 @@ namespace AlicizaX.Resource.Runtime
|
||||
|
||||
if (!CheckLocationValid(location, packageName))
|
||||
{
|
||||
Log.Error($"Could not found location [{location}].");
|
||||
Log.Error(ZString.Format("Could not found location [{0}].", location));
|
||||
return null;
|
||||
}
|
||||
|
||||
string assetObjectKey = GetCacheKey(location, packageName);
|
||||
AssetObject assetObject = _assetPool.Spawn(assetObjectKey);
|
||||
|
||||
if (assetObject != null)
|
||||
{
|
||||
return AssetsReference.Instantiate(assetObject.Target as GameObject, parent, this).gameObject;
|
||||
}
|
||||
|
||||
AssetHandle handle = GetHandleSync<GameObject>(location, packageName: packageName);
|
||||
|
||||
GameObject gameObject = AssetsReference.Instantiate(handle.AssetObject as GameObject, parent, this).gameObject;
|
||||
|
||||
assetObject = AssetObject.Create(assetObjectKey, handle.AssetObject, handle);
|
||||
_assetPool.Register(assetObject, true);
|
||||
|
||||
@ -654,22 +707,14 @@ namespace AlicizaX.Resource.Runtime
|
||||
|
||||
if (!CheckLocationValid(location, packageName))
|
||||
{
|
||||
Log.Error($"Could not found location [{location}].");
|
||||
Log.Error(ZString.Format("Could not found location [{0}].", location));
|
||||
callback?.Invoke(null);
|
||||
return;
|
||||
}
|
||||
|
||||
string assetObjectKey = GetCacheKey(location, packageName);
|
||||
try
|
||||
{
|
||||
var asset = await GetOrLoadAssetAsync(location, typeof(T), packageName, assetObjectKey);
|
||||
callback?.Invoke(asset as T);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error($"Can not load asset '{location}'. {ex}");
|
||||
callback?.Invoke(null);
|
||||
}
|
||||
var asset = await GetOrLoadAssetAsync(location, typeof(T), packageName, assetObjectKey);
|
||||
callback?.Invoke(asset as T);
|
||||
}
|
||||
|
||||
public async UniTask<T> LoadAssetAsync<T>(string location, CancellationToken cancellationToken = default, string packageName = "") where T : UnityEngine.Object
|
||||
@ -681,13 +726,11 @@ namespace AlicizaX.Resource.Runtime
|
||||
|
||||
if (!CheckLocationValid(location, packageName))
|
||||
{
|
||||
Log.Error($"Could not found location [{location}].");
|
||||
Log.Error(ZString.Format("Could not found location [{0}].", location));
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
string assetObjectKey = GetCacheKey(location, packageName);
|
||||
|
||||
var asset = await GetOrLoadAssetAsync(location, typeof(T), packageName, assetObjectKey, cancellationToken: cancellationToken);
|
||||
return asset as T;
|
||||
}
|
||||
@ -701,12 +744,11 @@ namespace AlicizaX.Resource.Runtime
|
||||
|
||||
if (!CheckLocationValid(location, packageName))
|
||||
{
|
||||
Log.Error($"Could not found location [{location}].");
|
||||
Log.Error(ZString.Format("Could not found location [{0}].", location));
|
||||
return null;
|
||||
}
|
||||
|
||||
string assetObjectKey = GetCacheKey(location, packageName);
|
||||
|
||||
var asset = await GetOrLoadAssetAsync(location, typeof(GameObject), packageName, assetObjectKey, cancellationToken: cancellationToken);
|
||||
return asset != null ? AssetsReference.Instantiate(asset as GameObject, parent, this).gameObject : null;
|
||||
}
|
||||
@ -736,7 +778,7 @@ namespace AlicizaX.Resource.Runtime
|
||||
|
||||
if (!CheckLocationValid(location, packageName))
|
||||
{
|
||||
string errorMessage = Utility.Text.Format("Could not found location [{0}].", location);
|
||||
string errorMessage = ZString.Format("Could not found location [{0}].", location);
|
||||
Log.Error(errorMessage);
|
||||
if (loadAssetCallbacks.LoadAssetFailureCallback != null)
|
||||
{
|
||||
@ -747,14 +789,11 @@ namespace AlicizaX.Resource.Runtime
|
||||
}
|
||||
|
||||
string assetObjectKey = GetCacheKey(location, packageName);
|
||||
|
||||
float duration = Time.time;
|
||||
|
||||
AssetInfo assetInfo = GetAssetInfo(location, packageName);
|
||||
|
||||
if (!string.IsNullOrEmpty(assetInfo.Error))
|
||||
{
|
||||
string errorMessage = Utility.Text.Format("Can not load asset '{0}' because :'{1}'.", location, assetInfo.Error);
|
||||
string errorMessage = ZString.Format("Can not load asset '{0}' because :'{1}'.", location, assetInfo.Error);
|
||||
if (loadAssetCallbacks.LoadAssetFailureCallback != null)
|
||||
{
|
||||
loadAssetCallbacks.LoadAssetFailureCallback(location, LoadResourceStatus.NotExist, errorMessage, userData);
|
||||
@ -764,24 +803,17 @@ namespace AlicizaX.Resource.Runtime
|
||||
throw new GameFrameworkException(errorMessage);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var asset = await GetOrLoadAssetAsync(location, assetType, packageName, assetObjectKey, NormalizePriority(priority), default,
|
||||
handle => StartProgressTask(location, handle, loadAssetCallbacks.LoadAssetUpdateCallback, userData));
|
||||
loadAssetCallbacks.LoadAssetSuccessCallback?.Invoke(location, asset, Time.time - duration, userData);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string errorMessage = Utility.Text.Format("Can not load asset '{0}'.", location);
|
||||
Log.Error($"{errorMessage} {ex}");
|
||||
if (loadAssetCallbacks.LoadAssetFailureCallback != null)
|
||||
{
|
||||
loadAssetCallbacks.LoadAssetFailureCallback(location, LoadResourceStatus.NotReady, errorMessage, userData);
|
||||
return;
|
||||
}
|
||||
var asset = await GetOrLoadAssetAsync(location, assetType, packageName, assetObjectKey, NormalizePriority(priority), default,
|
||||
loadAssetCallbacks.LoadAssetUpdateCallback, userData);
|
||||
|
||||
throw;
|
||||
if (asset == null)
|
||||
{
|
||||
string errorMessage = ZString.Format("Can not load asset '{0}'.", location);
|
||||
loadAssetCallbacks.LoadAssetFailureCallback?.Invoke(location, LoadResourceStatus.NotReady, errorMessage, userData);
|
||||
return;
|
||||
}
|
||||
|
||||
loadAssetCallbacks.LoadAssetSuccessCallback?.Invoke(location, asset, Time.time - duration, userData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -806,7 +838,7 @@ namespace AlicizaX.Resource.Runtime
|
||||
|
||||
if (!CheckLocationValid(location, packageName))
|
||||
{
|
||||
string errorMessage = Utility.Text.Format("Could not found location [{0}].", location);
|
||||
string errorMessage = ZString.Format("Could not found location [{0}].", location);
|
||||
Log.Error(errorMessage);
|
||||
if (loadAssetCallbacks.LoadAssetFailureCallback != null)
|
||||
{
|
||||
@ -817,14 +849,11 @@ namespace AlicizaX.Resource.Runtime
|
||||
}
|
||||
|
||||
string assetObjectKey = GetCacheKey(location, packageName);
|
||||
|
||||
float duration = Time.time;
|
||||
|
||||
AssetInfo assetInfo = GetAssetInfo(location, packageName);
|
||||
|
||||
if (!string.IsNullOrEmpty(assetInfo.Error))
|
||||
{
|
||||
string errorMessage = Utility.Text.Format("Can not load asset '{0}' because :'{1}'.", location, assetInfo.Error);
|
||||
string errorMessage = ZString.Format("Can not load asset '{0}' because :'{1}'.", location, assetInfo.Error);
|
||||
if (loadAssetCallbacks.LoadAssetFailureCallback != null)
|
||||
{
|
||||
loadAssetCallbacks.LoadAssetFailureCallback(location, LoadResourceStatus.NotExist, errorMessage, userData);
|
||||
@ -834,24 +863,17 @@ namespace AlicizaX.Resource.Runtime
|
||||
throw new GameFrameworkException(errorMessage);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var asset = await GetOrLoadAssetAsync(location, assetInfo.AssetType, packageName, assetObjectKey, NormalizePriority(priority), default,
|
||||
handle => StartProgressTask(location, handle, loadAssetCallbacks.LoadAssetUpdateCallback, userData));
|
||||
loadAssetCallbacks.LoadAssetSuccessCallback?.Invoke(location, asset, Time.time - duration, userData);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
string errorMessage = Utility.Text.Format("Can not load asset '{0}'.", location);
|
||||
Log.Error($"{errorMessage} {ex}");
|
||||
if (loadAssetCallbacks.LoadAssetFailureCallback != null)
|
||||
{
|
||||
loadAssetCallbacks.LoadAssetFailureCallback(location, LoadResourceStatus.NotReady, errorMessage, userData);
|
||||
return;
|
||||
}
|
||||
var asset = await GetOrLoadAssetAsync(location, assetInfo.AssetType, packageName, assetObjectKey, NormalizePriority(priority), default,
|
||||
loadAssetCallbacks.LoadAssetUpdateCallback, userData);
|
||||
|
||||
throw;
|
||||
if (asset == null)
|
||||
{
|
||||
string errorMessage = ZString.Format("Can not load asset '{0}'.", location);
|
||||
loadAssetCallbacks.LoadAssetFailureCallback?.Invoke(location, LoadResourceStatus.NotReady, errorMessage, userData);
|
||||
return;
|
||||
}
|
||||
|
||||
loadAssetCallbacks.LoadAssetSuccessCallback?.Invoke(location, asset, Time.time - duration, userData);
|
||||
}
|
||||
|
||||
private async UniTaskVoid InvokeProgress(string location, AssetHandle assetHandle, LoadAssetUpdateCallback loadAssetUpdateCallback, object userData)
|
||||
@ -921,12 +943,11 @@ namespace AlicizaX.Resource.Runtime
|
||||
#endregion
|
||||
|
||||
private async UniTask<UnityEngine.Object> GetOrLoadAssetAsync(string location, Type assetType, string packageName,
|
||||
string assetObjectKey, uint priority = 0, CancellationToken cancellationToken = default, Action<AssetHandle> onHandleCreated = null)
|
||||
string assetObjectKey, uint priority = 0, CancellationToken cancellationToken = default, LoadAssetUpdateCallback loadAssetUpdateCallback = null, object userData = null)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
|
||||
AssetObject cachedAssetObject = _assetPool.Spawn(assetObjectKey);
|
||||
if (cachedAssetObject != null)
|
||||
{
|
||||
@ -939,40 +960,42 @@ namespace AlicizaX.Resource.Runtime
|
||||
continue;
|
||||
}
|
||||
|
||||
AssetHandle handle = null;
|
||||
try
|
||||
AssetHandle handle = GetHandleAsync(location, assetType, packageName: packageName, priority: priority);
|
||||
StartProgressTask(location, handle, loadAssetUpdateCallback, userData);
|
||||
while (handle is { IsValid: true, IsDone: false })
|
||||
{
|
||||
handle = GetHandleAsync(location, assetType, packageName: packageName, priority: priority);
|
||||
onHandleCreated?.Invoke(handle);
|
||||
await handle.ToUniTask();
|
||||
|
||||
if (handle.AssetObject == null || handle.Status == EOperationStatus.Failed)
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
throw new GameFrameworkException(Utility.Text.Format("Can not load asset '{0}'.", location));
|
||||
DisposeHandle(handle);
|
||||
FailLoading(assetObjectKey, null);
|
||||
return null;
|
||||
}
|
||||
|
||||
var assetObject = AssetObject.Create(assetObjectKey, handle.AssetObject, handle);
|
||||
_assetPool.Register(assetObject, true);
|
||||
CompleteLoading(assetObjectKey);
|
||||
return handle.AssetObject as UnityEngine.Object;
|
||||
await UniTask.Yield();
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
if (handle.AssetObject == null || handle.Status == EOperationStatus.Failed)
|
||||
{
|
||||
DisposeHandle(handle);
|
||||
FailLoading(assetObjectKey, ex);
|
||||
throw;
|
||||
FailLoading(assetObjectKey, null);
|
||||
return null;
|
||||
}
|
||||
|
||||
var assetObject = AssetObject.Create(assetObjectKey, handle.AssetObject, handle);
|
||||
_assetPool.Register(assetObject, true);
|
||||
CompleteLoading(assetObjectKey);
|
||||
return handle.AssetObject as UnityEngine.Object;
|
||||
}
|
||||
}
|
||||
|
||||
private bool TryBeginLoading(string assetObjectKey)
|
||||
{
|
||||
if (_assetLoadingOperations.ContainsKey(assetObjectKey))
|
||||
if (_assetLoadingOperations.TryGetValue(assetObjectKey, out _))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_assetLoadingOperations.Add(assetObjectKey, new UniTaskCompletionSource<bool>());
|
||||
_assetLoadingOperations.Add(assetObjectKey, AutoResetUniTaskCompletionSource<bool>.Create());
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1007,12 +1030,13 @@ namespace AlicizaX.Resource.Runtime
|
||||
private void FailLoading(string assetObjectKey, Exception exception)
|
||||
{
|
||||
if (!_assetLoadingOperations.TryGetValue(assetObjectKey, out var loadingOperation))
|
||||
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_assetLoadingOperations.Remove(assetObjectKey);
|
||||
loadingOperation.TrySetException(exception);
|
||||
loadingOperation.TrySetResult(false);
|
||||
}
|
||||
|
||||
private void DisposeHandle(AssetHandle handle)
|
||||
@ -1038,7 +1062,7 @@ namespace AlicizaX.Resource.Runtime
|
||||
/// <summary>
|
||||
/// 设置下载系统参数,自定义下载请求。
|
||||
/// </summary>
|
||||
/// <param name="downloadSystemUnityWebRequest">自定义下载器的请求委托。<see cref="UnityWebRequestDelegate"/></param>
|
||||
/// <param name="downloadSystemUnityWebRequest">自定义下载器的请求委托,<see cref="UnityWebRequestDelegate"/></param>
|
||||
public void SetDownloadSystemUnityWebRequest(UnityWebRequestDelegate downloadSystemUnityWebRequest)
|
||||
{
|
||||
YooAssets.SetDownloadSystemUnityWebRequest(downloadSystemUnityWebRequest);
|
||||
@ -1054,9 +1078,9 @@ namespace AlicizaX.Resource.Runtime
|
||||
|
||||
private string GetAuthorization(string userName, string password)
|
||||
{
|
||||
string auth = $"{userName}:{password}";
|
||||
string auth = ZString.Concat(userName, ":", password);
|
||||
var bytes = System.Text.Encoding.GetEncoding("ISO-8859-1").GetBytes(auth);
|
||||
return $"Basic {Convert.ToBase64String(bytes)}";
|
||||
return ZString.Concat("Basic ", Convert.ToBase64String(bytes));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
Loading…
Reference in New Issue
Block a user