2025-01-23 19:06:48 +08:00
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections;
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.Threading;
|
|
|
|
|
|
using AlicizaX.ObjectPool;
|
|
|
|
|
|
using AlicizaX.Runtime;
|
|
|
|
|
|
using Cysharp.Threading.Tasks;
|
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
|
using UnityEngine.SceneManagement;
|
|
|
|
|
|
using YooAsset;
|
|
|
|
|
|
|
|
|
|
|
|
namespace AlicizaX.Resource.Runtime
|
|
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 资源管理器。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
internal sealed partial class ResourceManager : IResourceManager
|
|
|
|
|
|
{
|
|
|
|
|
|
#region Propreties
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 资源包名称。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public string DefaultPackageName { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 资源系统运行模式。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public EPlayMode PlayMode { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 下载文件校验等级。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public EFileVerifyLevel VerifyLevel { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 设置异步系统参数,每帧执行消耗的最大时间切片(单位:毫秒)
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public long Milliseconds { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 实例化的根节点。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public Transform InstanceRoot { get; set; }
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Propagates notification that operations should be canceled.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public CancellationToken CancellationToken { get; private set; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 默认资源包。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
internal ResourcePackage DefaultPackage { private set; get; }
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 资源包列表。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private Dictionary<string, ResourcePackage> PackageMap { get; } = new Dictionary<string, ResourcePackage>();
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 资源信息列表。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private readonly Dictionary<string, AssetInfo> _assetInfoMap = new Dictionary<string, AssetInfo>();
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 正在加载的资源列表。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private readonly HashSet<string> _assetLoadingList = new HashSet<string>();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取或设置无用资源释放的最小间隔时间,以秒为单位。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private float m_MinUnloadUnusedAssetsInterval = 60f;
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取或设置无用资源释放的最大间隔时间,以秒为单位。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private float m_MaxUnloadUnusedAssetsInterval = 300f;
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 使用系统释放无用资源策略。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private bool m_UseSystemUnloadUnusedAssets = true;
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取无用资源释放的等待时长,以秒为单位。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private float m_LastUnloadUnusedAssetsOperationElapseSeconds = 0f;
|
|
|
|
|
|
|
|
|
|
|
|
private bool m_ForceUnloadUnusedAssets = false;
|
|
|
|
|
|
|
|
|
|
|
|
private bool m_PreorderUnloadUnusedAssets = false;
|
|
|
|
|
|
|
|
|
|
|
|
private bool m_PerformGCCollect = false;
|
|
|
|
|
|
|
|
|
|
|
|
private AsyncOperation m_AsyncOperation = null;
|
|
|
|
|
|
|
|
|
|
|
|
private UnloadUnusedAssetsOperation m_unloadUnusedAssetsOperation = null;
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 初始化资源管理器的新实例。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public ResourceManager()
|
|
|
|
|
|
{
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void Initialize()
|
|
|
|
|
|
{
|
|
|
|
|
|
// 初始化资源系统
|
|
|
|
|
|
YooAssets.Initialize(new ResourceLogger());
|
|
|
|
|
|
YooAssets.SetOperationSystemMaxTimeSlice(Milliseconds);
|
|
|
|
|
|
|
|
|
|
|
|
#if UNITY_WECHAT_GAME && !UNITY_EDITOR
|
|
|
|
|
|
YooAssets.SetCacheSystemDisableCacheOnWebGL();
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
// 创建默认的资源包
|
|
|
|
|
|
string packageName = DefaultPackageName;
|
|
|
|
|
|
var defaultPackage = YooAssets.TryGetPackage(packageName);
|
|
|
|
|
|
if (defaultPackage == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
defaultPackage = YooAssets.CreatePackage(packageName);
|
|
|
|
|
|
YooAssets.SetDefaultPackage(defaultPackage);
|
|
|
|
|
|
DefaultPackage = defaultPackage;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
CancellationToken = InstanceRoot.gameObject.GetCancellationTokenOnDestroy();
|
|
|
|
|
|
|
|
|
|
|
|
IObjectPoolManager objectPoolModule = SysModuleCenter.GetModule<IObjectPoolManager>();
|
|
|
|
|
|
SetObjectPoolManager(objectPoolModule);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void IModuleUpdate.Update(float elapseSeconds, float realElapseSeconds)
|
|
|
|
|
|
{
|
|
|
|
|
|
m_LastUnloadUnusedAssetsOperationElapseSeconds += Time.unscaledDeltaTime;
|
|
|
|
|
|
if (m_AsyncOperation == null && m_unloadUnusedAssetsOperation == null && (m_ForceUnloadUnusedAssets || m_LastUnloadUnusedAssetsOperationElapseSeconds >= m_MaxUnloadUnusedAssetsInterval ||
|
|
|
|
|
|
m_PreorderUnloadUnusedAssets && m_LastUnloadUnusedAssetsOperationElapseSeconds >= m_MinUnloadUnusedAssetsInterval))
|
|
|
|
|
|
{
|
2025-01-26 20:55:39 +08:00
|
|
|
|
Log.Debug("Unload unused assets...");
|
2025-01-23 19:06:48 +08:00
|
|
|
|
m_ForceUnloadUnusedAssets = false;
|
|
|
|
|
|
m_PreorderUnloadUnusedAssets = false;
|
|
|
|
|
|
m_LastUnloadUnusedAssetsOperationElapseSeconds = 0f;
|
|
|
|
|
|
m_AsyncOperation = Resources.UnloadUnusedAssets();
|
|
|
|
|
|
if (m_UseSystemUnloadUnusedAssets)
|
|
|
|
|
|
{
|
|
|
|
|
|
UnloadUnusedAssets();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (m_AsyncOperation is { isDone: true })
|
|
|
|
|
|
{
|
|
|
|
|
|
m_AsyncOperation = null;
|
|
|
|
|
|
if (m_PerformGCCollect)
|
|
|
|
|
|
{
|
2025-01-26 20:55:39 +08:00
|
|
|
|
Log.Debug("GC.Collect...");
|
2025-01-23 19:06:48 +08:00
|
|
|
|
m_PerformGCCollect = false;
|
|
|
|
|
|
GC.Collect();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (m_unloadUnusedAssetsOperation is { IsDone: true })
|
|
|
|
|
|
{
|
|
|
|
|
|
m_unloadUnusedAssetsOperation = null;
|
2025-01-26 20:55:39 +08:00
|
|
|
|
Log.Debug("Unload UnusedAssets Done...");
|
2025-01-23 19:06:48 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-02-06 17:59:35 +08:00
|
|
|
|
public UniTask<bool> InitPackageAsync(string packageName, string hostServerURL, string fallbackHostServerURL,string decryptionServicesName, bool isDefaultPackage = true)
|
2025-01-23 19:06:48 +08:00
|
|
|
|
{
|
|
|
|
|
|
if (PackageMap.ContainsKey(packageName))
|
|
|
|
|
|
{
|
|
|
|
|
|
Log.Error($"ResourceSystem has already init package : {packageName}");
|
|
|
|
|
|
return new UniTask<bool>(false);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var taskCompletionSource = new UniTaskCompletionSource<bool>();
|
|
|
|
|
|
GameFrameworkGuard.NotNull(packageName, nameof(packageName));
|
|
|
|
|
|
GameFrameworkGuard.NotNull(hostServerURL, nameof(hostServerURL));
|
|
|
|
|
|
GameFrameworkGuard.NotNull(fallbackHostServerURL, nameof(fallbackHostServerURL));
|
|
|
|
|
|
|
|
|
|
|
|
// 创建默认的资源包
|
|
|
|
|
|
var resourcePackage = YooAssets.TryGetPackage(packageName);
|
|
|
|
|
|
if (resourcePackage == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
resourcePackage = YooAssets.CreatePackage(packageName);
|
|
|
|
|
|
if (isDefaultPackage)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 设置该资源包为默认的资源包,可以使用YooAssets相关加载接口加载该资源包内容。
|
|
|
|
|
|
YooAssets.SetDefaultPackage(resourcePackage);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
PackageMap[packageName] = resourcePackage;
|
|
|
|
|
|
|
2025-02-06 17:59:35 +08:00
|
|
|
|
var initializationOperationHandler = CreateInitializationOperationHandler(resourcePackage, hostServerURL, fallbackHostServerURL,decryptionServicesName);
|
2025-01-23 19:06:48 +08:00
|
|
|
|
initializationOperationHandler.Completed += asyncOperationBase =>
|
|
|
|
|
|
{
|
|
|
|
|
|
if (asyncOperationBase.Error == null && asyncOperationBase.Status == EOperationStatus.Succeed && asyncOperationBase.IsDone)
|
|
|
|
|
|
{
|
|
|
|
|
|
taskCompletionSource.TrySetResult(true);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
taskCompletionSource.TrySetException(new Exception(asyncOperationBase.Error));
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
return taskCompletionSource.Task;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void IModule.Dispose()
|
|
|
|
|
|
{
|
|
|
|
|
|
PackageMap.Clear();
|
|
|
|
|
|
m_AssetPool = null;
|
|
|
|
|
|
_assetLoadingList.Clear();
|
|
|
|
|
|
_assetInfoMap.Clear();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#region Public Methods
|
|
|
|
|
|
|
|
|
|
|
|
#region 加载场景
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 异步加载场景
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="path">资源路径</param>
|
|
|
|
|
|
/// <param name="sceneMode">场景模式</param>
|
|
|
|
|
|
/// <param name="activateOnLoad">是否加载完成自动激活</param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
public UniTask<SceneHandle> LoadSceneAsync(string path, LoadSceneMode sceneMode, bool activateOnLoad = true)
|
|
|
|
|
|
{
|
|
|
|
|
|
var taskCompletionSource = new UniTaskCompletionSource<SceneHandle>();
|
|
|
|
|
|
var sceneHandle = YooAssets.LoadSceneAsync(path, sceneMode, LocalPhysicsMode.None, !activateOnLoad);
|
|
|
|
|
|
sceneHandle.Completed += handle => { taskCompletionSource.TrySetResult(handle); };
|
|
|
|
|
|
return taskCompletionSource.Task;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 异步加载场景
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="assetInfo">资源路径</param>
|
|
|
|
|
|
/// <param name="sceneMode">场景模式</param>
|
|
|
|
|
|
/// <param name="activateOnLoad">是否加载完成自动激活</param>
|
|
|
|
|
|
/// <returns></returns>
|
|
|
|
|
|
public UniTask<SceneHandle> LoadSceneAsync(AssetInfo assetInfo, LoadSceneMode sceneMode, bool activateOnLoad = true)
|
|
|
|
|
|
{
|
|
|
|
|
|
var taskCompletionSource = new UniTaskCompletionSource<SceneHandle>();
|
|
|
|
|
|
var sceneHandle = YooAssets.LoadSceneAsync(assetInfo, sceneMode, LocalPhysicsMode.None, !activateOnLoad);
|
|
|
|
|
|
sceneHandle.Completed += handle => { taskCompletionSource.TrySetResult(handle); };
|
|
|
|
|
|
return taskCompletionSource.Task;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
2025-01-24 16:21:00 +08:00
|
|
|
|
|
2025-01-23 19:06:48 +08:00
|
|
|
|
#region 获取资源信息
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 是否需要从远端更新下载。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="location">资源的定位地址。</param>
|
|
|
|
|
|
/// <param name="packageName">资源包名称。</param>
|
|
|
|
|
|
public bool IsNeedDownloadFromRemote(string location, string packageName = "")
|
|
|
|
|
|
{
|
|
|
|
|
|
if (string.IsNullOrEmpty(packageName))
|
|
|
|
|
|
{
|
|
|
|
|
|
return YooAssets.IsNeedDownloadFromRemote(location);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
var package = YooAssets.GetPackage(packageName);
|
|
|
|
|
|
return package.IsNeedDownloadFromRemote(location);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 是否需要从远端更新下载。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="assetInfo">资源信息。</param>
|
|
|
|
|
|
/// <param name="packageName">资源包名称。</param>
|
|
|
|
|
|
public bool IsNeedDownloadFromRemote(AssetInfo assetInfo, string packageName = "")
|
|
|
|
|
|
{
|
|
|
|
|
|
if (string.IsNullOrEmpty(packageName))
|
|
|
|
|
|
{
|
|
|
|
|
|
return YooAssets.IsNeedDownloadFromRemote(assetInfo);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
var package = YooAssets.GetPackage(packageName);
|
|
|
|
|
|
return package.IsNeedDownloadFromRemote(assetInfo);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取资源信息列表。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="tag">资源标签。</param>
|
|
|
|
|
|
/// <param name="packageName">资源包名称。</param>
|
|
|
|
|
|
/// <returns>资源信息列表。</returns>
|
|
|
|
|
|
public AssetInfo[] GetAssetInfos(string tag, string packageName = "")
|
|
|
|
|
|
{
|
|
|
|
|
|
if (string.IsNullOrEmpty(packageName))
|
|
|
|
|
|
{
|
|
|
|
|
|
return YooAssets.GetAssetInfos(tag);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
var package = YooAssets.GetPackage(packageName);
|
|
|
|
|
|
return package.GetAssetInfos(tag);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取资源信息列表。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="tags">资源标签列表。</param>
|
|
|
|
|
|
/// <param name="packageName">资源包名称。</param>
|
|
|
|
|
|
/// <returns>资源信息列表。</returns>
|
|
|
|
|
|
public AssetInfo[] GetAssetInfos(string[] tags, string packageName = "")
|
|
|
|
|
|
{
|
|
|
|
|
|
if (string.IsNullOrEmpty(packageName))
|
|
|
|
|
|
{
|
|
|
|
|
|
return YooAssets.GetAssetInfos(tags);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
var package = YooAssets.GetPackage(packageName);
|
|
|
|
|
|
return package.GetAssetInfos(tags);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取资源信息。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="location">资源的定位地址。</param>
|
|
|
|
|
|
/// <param name="packageName">资源包名称。</param>
|
|
|
|
|
|
/// <returns>资源信息。</returns>
|
|
|
|
|
|
public AssetInfo GetAssetInfo(string location, string packageName = "")
|
|
|
|
|
|
{
|
|
|
|
|
|
if (string.IsNullOrEmpty(location))
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new GameFrameworkException("Asset name is invalid.");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (string.IsNullOrEmpty(packageName))
|
|
|
|
|
|
{
|
|
|
|
|
|
if (_assetInfoMap.TryGetValue(location, out AssetInfo assetInfo))
|
|
|
|
|
|
{
|
|
|
|
|
|
return assetInfo;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
assetInfo = YooAssets.GetAssetInfo(location);
|
|
|
|
|
|
_assetInfoMap[location] = assetInfo;
|
|
|
|
|
|
return assetInfo;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
string key = $"{packageName}/{location}";
|
|
|
|
|
|
if (_assetInfoMap.TryGetValue(key, out AssetInfo assetInfo))
|
|
|
|
|
|
{
|
|
|
|
|
|
return assetInfo;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var package = YooAssets.GetPackage(packageName);
|
|
|
|
|
|
if (package == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new GameFrameworkException($"The package does not exist. Package Name :{packageName}");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
assetInfo = package.GetAssetInfo(location);
|
|
|
|
|
|
_assetInfoMap[key] = assetInfo;
|
|
|
|
|
|
return assetInfo;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 检查资源是否存在。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="location">资源定位地址。</param>
|
|
|
|
|
|
/// <param name="packageName">资源包名称。</param>
|
|
|
|
|
|
/// <returns>检查资源是否存在的结果。</returns>
|
|
|
|
|
|
public HasAssetResult HasAsset(string location, string packageName = "")
|
|
|
|
|
|
{
|
|
|
|
|
|
if (string.IsNullOrEmpty(location))
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new GameFrameworkException("Asset name is invalid.");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
AssetInfo assetInfo = GetAssetInfo(location, packageName);
|
|
|
|
|
|
|
|
|
|
|
|
if (!CheckLocationValid(location))
|
|
|
|
|
|
{
|
|
|
|
|
|
return HasAssetResult.Valid;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (assetInfo == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
return HasAssetResult.NotExist;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (IsNeedDownloadFromRemote(assetInfo))
|
|
|
|
|
|
{
|
|
|
|
|
|
return HasAssetResult.AssetOnline;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return HasAssetResult.AssetOnDisk;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 检查资源定位地址是否有效。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="location">资源的定位地址</param>
|
|
|
|
|
|
/// <param name="packageName">资源包名称。</param>
|
|
|
|
|
|
public bool CheckLocationValid(string location, string packageName = "")
|
|
|
|
|
|
{
|
|
|
|
|
|
if (string.IsNullOrEmpty(packageName))
|
|
|
|
|
|
{
|
|
|
|
|
|
return YooAssets.CheckLocationValid(location);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
var package = YooAssets.GetPackage(packageName);
|
|
|
|
|
|
return package.CheckLocationValid(location);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region 资源加载
|
|
|
|
|
|
|
|
|
|
|
|
#region 获取资源句柄
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取同步资源句柄。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="location">资源定位地址。</param>
|
|
|
|
|
|
/// <param name="packageName">指定资源包的名称。不传使用默认资源包</param>
|
|
|
|
|
|
/// <typeparam name="T">资源类型。</typeparam>
|
|
|
|
|
|
/// <returns>资源句柄。</returns>
|
|
|
|
|
|
private AssetHandle GetHandleSync<T>(string location, string packageName = "") where T : UnityEngine.Object
|
|
|
|
|
|
{
|
|
|
|
|
|
return GetHandleSync(location, typeof(T), packageName);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private AssetHandle GetHandleSync(string location, Type assetType, string packageName = "")
|
|
|
|
|
|
{
|
|
|
|
|
|
if (string.IsNullOrEmpty(packageName))
|
|
|
|
|
|
{
|
|
|
|
|
|
return YooAssets.LoadAssetSync(location, assetType);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var package = YooAssets.GetPackage(packageName);
|
|
|
|
|
|
return package.LoadAssetSync(location, assetType);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取异步资源句柄。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="location">资源定位地址。</param>
|
|
|
|
|
|
/// <param name="packageName">指定资源包的名称。不传使用默认资源包</param>
|
|
|
|
|
|
/// <typeparam name="T">资源类型。</typeparam>
|
|
|
|
|
|
/// <returns>资源句柄。</returns>
|
|
|
|
|
|
private AssetHandle GetHandleAsync<T>(string location, string packageName = "") where T : UnityEngine.Object
|
|
|
|
|
|
{
|
|
|
|
|
|
return GetHandleAsync(location, typeof(T), packageName);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private AssetHandle GetHandleAsync(string location, Type assetType, string packageName = "")
|
|
|
|
|
|
{
|
|
|
|
|
|
if (string.IsNullOrEmpty(packageName))
|
|
|
|
|
|
{
|
|
|
|
|
|
return YooAssets.LoadAssetAsync(location, assetType);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var package = YooAssets.GetPackage(packageName);
|
|
|
|
|
|
return package.LoadAssetAsync(location, assetType);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 获取资源定位地址的缓存Key。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="location">资源定位地址。</param>
|
|
|
|
|
|
/// <param name="packageName">资源包名称。</param>
|
|
|
|
|
|
/// <returns>资源定位地址的缓存Key。</returns>
|
|
|
|
|
|
private string GetCacheKey(string location, string packageName = "")
|
|
|
|
|
|
{
|
|
|
|
|
|
if (string.IsNullOrEmpty(packageName) || packageName.Equals(DefaultPackageName))
|
|
|
|
|
|
{
|
|
|
|
|
|
return location;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return $"{packageName}/{location}";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public T LoadAsset<T>(string location, string packageName = "") where T : UnityEngine.Object
|
|
|
|
|
|
{
|
|
|
|
|
|
if (string.IsNullOrEmpty(location))
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new GameFrameworkException("Asset name is invalid.");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
string assetObjectKey = GetCacheKey(location, packageName);
|
|
|
|
|
|
AssetObject assetObject = m_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, this);
|
|
|
|
|
|
m_AssetPool.Register(assetObject, true);
|
|
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public GameObject LoadGameObject(string location, Transform parent = null, string packageName = "")
|
|
|
|
|
|
{
|
|
|
|
|
|
if (string.IsNullOrEmpty(location))
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new GameFrameworkException("Asset name is invalid.");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
string assetObjectKey = GetCacheKey(location, packageName);
|
|
|
|
|
|
AssetObject assetObject = m_AssetPool.Spawn(assetObjectKey);
|
|
|
|
|
|
if (assetObject != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
return AssetsReference.Instantiate(assetObject.Target as GameObject, parent).gameObject;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
AssetHandle handle = GetHandleSync<GameObject>(location, packageName: packageName);
|
|
|
|
|
|
|
|
|
|
|
|
GameObject gameObject = AssetsReference.Instantiate(handle.AssetObject as GameObject, parent).gameObject;
|
|
|
|
|
|
|
|
|
|
|
|
assetObject = AssetObject.Create(assetObjectKey, handle.AssetObject, handle, this);
|
|
|
|
|
|
m_AssetPool.Register(assetObject, true);
|
|
|
|
|
|
|
|
|
|
|
|
return gameObject;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 异步加载资源。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="location">资源的定位地址。</param>
|
|
|
|
|
|
/// <param name="callback">回调函数。</param>
|
|
|
|
|
|
/// <param name="packageName">指定资源包的名称。不传使用默认资源包</param>
|
|
|
|
|
|
/// <typeparam name="T">要加载资源的类型。</typeparam>
|
|
|
|
|
|
public async UniTaskVoid LoadAsset<T>(string location, Action<T> callback, string packageName = "") where T : UnityEngine.Object
|
|
|
|
|
|
{
|
|
|
|
|
|
if (string.IsNullOrEmpty(location))
|
|
|
|
|
|
{
|
|
|
|
|
|
Log.Error("Asset name is invalid.");
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (string.IsNullOrEmpty(location))
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new GameFrameworkException("Asset name is invalid.");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
string assetObjectKey = GetCacheKey(location, packageName);
|
|
|
|
|
|
|
|
|
|
|
|
await TryWaitingLoading(assetObjectKey);
|
|
|
|
|
|
|
|
|
|
|
|
AssetObject assetObject = m_AssetPool.Spawn(assetObjectKey);
|
|
|
|
|
|
if (assetObject != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
await UniTask.Yield();
|
|
|
|
|
|
callback?.Invoke(assetObject.Target as T);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
_assetLoadingList.Add(assetObjectKey);
|
|
|
|
|
|
|
|
|
|
|
|
AssetHandle handle = GetHandleAsync<T>(location, packageName: packageName);
|
|
|
|
|
|
|
|
|
|
|
|
handle.Completed += assetHandle =>
|
|
|
|
|
|
{
|
|
|
|
|
|
_assetLoadingList.Remove(assetObjectKey);
|
|
|
|
|
|
|
|
|
|
|
|
if (assetHandle.AssetObject != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
assetObject = AssetObject.Create(assetObjectKey, handle.AssetObject, handle, this);
|
|
|
|
|
|
m_AssetPool.Register(assetObject, true);
|
|
|
|
|
|
|
|
|
|
|
|
callback?.Invoke(assetObject.Target as T);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
callback?.Invoke(null);
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public TObject[] LoadSubAssetsSync<TObject>(string location, string packageName = "") where TObject : UnityEngine.Object
|
|
|
|
|
|
{
|
|
|
|
|
|
if (string.IsNullOrEmpty(location))
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new GameFrameworkException("Asset name is invalid.");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
throw new NotImplementedException();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public UniTask<TObject[]> LoadSubAssetsAsync<TObject>(string location, string packageName = "") where TObject : UnityEngine.Object
|
|
|
|
|
|
{
|
|
|
|
|
|
if (string.IsNullOrEmpty(location))
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new GameFrameworkException("Asset name is invalid.");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
throw new NotImplementedException();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public async UniTask<T> LoadAssetAsync<T>(string location, CancellationToken cancellationToken = default, string packageName = "") where T : UnityEngine.Object
|
|
|
|
|
|
{
|
|
|
|
|
|
if (string.IsNullOrEmpty(location))
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new GameFrameworkException("Asset name is invalid.");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
string assetObjectKey = GetCacheKey(location, packageName);
|
|
|
|
|
|
|
|
|
|
|
|
await TryWaitingLoading(assetObjectKey);
|
|
|
|
|
|
|
|
|
|
|
|
AssetObject assetObject = m_AssetPool.Spawn(assetObjectKey);
|
|
|
|
|
|
if (assetObject != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
await UniTask.Yield();
|
|
|
|
|
|
return assetObject.Target as T;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
_assetLoadingList.Add(assetObjectKey);
|
|
|
|
|
|
|
|
|
|
|
|
AssetHandle handle = GetHandleAsync<T>(location, packageName: packageName);
|
|
|
|
|
|
|
|
|
|
|
|
bool cancelOrFailed = await handle.ToUniTask().AttachExternalCancellation(cancellationToken).SuppressCancellationThrow();
|
|
|
|
|
|
|
|
|
|
|
|
if (cancelOrFailed)
|
|
|
|
|
|
{
|
|
|
|
|
|
_assetLoadingList.Remove(assetObjectKey);
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
assetObject = AssetObject.Create(assetObjectKey, handle.AssetObject, handle, this);
|
|
|
|
|
|
m_AssetPool.Register(assetObject, true);
|
|
|
|
|
|
|
|
|
|
|
|
_assetLoadingList.Remove(assetObjectKey);
|
|
|
|
|
|
|
|
|
|
|
|
return handle.AssetObject as T;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public async UniTask<GameObject> LoadGameObjectAsync(string location, Transform parent = null, CancellationToken cancellationToken = default, string packageName = "")
|
|
|
|
|
|
{
|
|
|
|
|
|
if (string.IsNullOrEmpty(location))
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new GameFrameworkException("Asset name is invalid.");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
string assetObjectKey = GetCacheKey(location, packageName);
|
|
|
|
|
|
|
|
|
|
|
|
await TryWaitingLoading(assetObjectKey);
|
|
|
|
|
|
|
|
|
|
|
|
AssetObject assetObject = m_AssetPool.Spawn(assetObjectKey);
|
|
|
|
|
|
if (assetObject != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
await UniTask.Yield();
|
|
|
|
|
|
return AssetsReference.Instantiate(assetObject.Target as GameObject, parent).gameObject;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
_assetLoadingList.Add(assetObjectKey);
|
|
|
|
|
|
|
|
|
|
|
|
AssetHandle handle = GetHandleAsync<GameObject>(location, packageName: packageName);
|
|
|
|
|
|
|
|
|
|
|
|
bool cancelOrFailed = await handle.ToUniTask().AttachExternalCancellation(cancellationToken).SuppressCancellationThrow();
|
|
|
|
|
|
|
|
|
|
|
|
if (cancelOrFailed)
|
|
|
|
|
|
{
|
|
|
|
|
|
_assetLoadingList.Remove(assetObjectKey);
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
GameObject gameObject = AssetsReference.Instantiate(handle.AssetObject as GameObject, parent).gameObject;
|
|
|
|
|
|
|
|
|
|
|
|
assetObject = AssetObject.Create(assetObjectKey, handle.AssetObject, handle, this);
|
|
|
|
|
|
m_AssetPool.Register(assetObject, true);
|
|
|
|
|
|
|
|
|
|
|
|
_assetLoadingList.Remove(assetObjectKey);
|
|
|
|
|
|
|
|
|
|
|
|
return gameObject;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 异步加载资源。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="location">资源的定位地址。</param>
|
|
|
|
|
|
/// <param name="assetType">要加载资源的类型。</param>
|
|
|
|
|
|
/// <param name="priority">加载资源的优先级。</param>
|
|
|
|
|
|
/// <param name="loadAssetCallbacks">加载资源回调函数集。</param>
|
|
|
|
|
|
/// <param name="userData">用户自定义数据。</param>
|
|
|
|
|
|
/// <param name="packageName">指定资源包的名称。不传使用默认资源包。</param>
|
|
|
|
|
|
public async void LoadAssetAsync(string location, Type assetType, int priority, LoadAssetCallbacks loadAssetCallbacks, object userData, string packageName = "")
|
|
|
|
|
|
{
|
|
|
|
|
|
if (string.IsNullOrEmpty(location))
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new GameFrameworkException("Asset name is invalid.");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (loadAssetCallbacks == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new GameFrameworkException("Load asset callbacks is invalid.");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
string assetObjectKey = GetCacheKey(location, packageName);
|
|
|
|
|
|
|
|
|
|
|
|
await TryWaitingLoading(assetObjectKey);
|
|
|
|
|
|
|
|
|
|
|
|
float duration = Time.time;
|
|
|
|
|
|
|
|
|
|
|
|
AssetObject assetObject = m_AssetPool.Spawn(assetObjectKey);
|
|
|
|
|
|
if (assetObject != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
await UniTask.Yield();
|
|
|
|
|
|
loadAssetCallbacks.LoadAssetSuccessCallback(location, assetObject.Target, Time.time - duration, userData);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
_assetLoadingList.Add(assetObjectKey);
|
|
|
|
|
|
|
|
|
|
|
|
AssetInfo assetInfo = GetAssetInfo(location, packageName);
|
|
|
|
|
|
|
|
|
|
|
|
if (!string.IsNullOrEmpty(assetInfo.Error))
|
|
|
|
|
|
{
|
|
|
|
|
|
_assetLoadingList.Remove(assetObjectKey);
|
|
|
|
|
|
|
|
|
|
|
|
string errorMessage = Utility.Text.Format("Can not load asset '{0}' because :'{1}'.", location, assetInfo.Error);
|
|
|
|
|
|
if (loadAssetCallbacks.LoadAssetFailureCallback != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
loadAssetCallbacks.LoadAssetFailureCallback(location, LoadResourceStatus.NotExist, errorMessage, userData);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
throw new GameFrameworkException(errorMessage);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
AssetHandle handle = GetHandleAsync(location, assetType, packageName: packageName);
|
|
|
|
|
|
|
|
|
|
|
|
if (loadAssetCallbacks.LoadAssetUpdateCallback != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
InvokeProgress(location, handle, loadAssetCallbacks.LoadAssetUpdateCallback, userData).Forget();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
await handle.ToUniTask();
|
|
|
|
|
|
|
|
|
|
|
|
if (handle.AssetObject == null || handle.Status == EOperationStatus.Failed)
|
|
|
|
|
|
{
|
|
|
|
|
|
_assetLoadingList.Remove(assetObjectKey);
|
|
|
|
|
|
|
|
|
|
|
|
string errorMessage = Utility.Text.Format("Can not load asset '{0}'.", location);
|
|
|
|
|
|
if (loadAssetCallbacks.LoadAssetFailureCallback != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
loadAssetCallbacks.LoadAssetFailureCallback(location, LoadResourceStatus.NotReady, errorMessage, userData);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
throw new GameFrameworkException(errorMessage);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
assetObject = AssetObject.Create(assetObjectKey, handle.AssetObject, handle, this);
|
|
|
|
|
|
m_AssetPool.Register(assetObject, true);
|
|
|
|
|
|
|
|
|
|
|
|
_assetLoadingList.Remove(assetObjectKey);
|
|
|
|
|
|
|
|
|
|
|
|
if (loadAssetCallbacks.LoadAssetSuccessCallback != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
duration = Time.time - duration;
|
|
|
|
|
|
|
|
|
|
|
|
loadAssetCallbacks.LoadAssetSuccessCallback(location, handle.AssetObject, duration, userData);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 异步加载资源。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="location">资源的定位地址。</param>
|
|
|
|
|
|
/// <param name="priority">加载资源的优先级。</param>
|
|
|
|
|
|
/// <param name="loadAssetCallbacks">加载资源回调函数集。</param>
|
|
|
|
|
|
/// <param name="userData">用户自定义数据。</param>
|
|
|
|
|
|
/// <param name="packageName">指定资源包的名称。不传使用默认资源包。</param>
|
|
|
|
|
|
public async void LoadAssetAsync(string location, int priority, LoadAssetCallbacks loadAssetCallbacks, object userData, string packageName = "")
|
|
|
|
|
|
{
|
|
|
|
|
|
if (string.IsNullOrEmpty(location))
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new GameFrameworkException("Asset name is invalid.");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (loadAssetCallbacks == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new GameFrameworkException("Load asset callbacks is invalid.");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
string assetObjectKey = GetCacheKey(location, packageName);
|
|
|
|
|
|
|
|
|
|
|
|
await TryWaitingLoading(assetObjectKey);
|
|
|
|
|
|
|
|
|
|
|
|
float duration = Time.time;
|
|
|
|
|
|
|
|
|
|
|
|
AssetObject assetObject = m_AssetPool.Spawn(assetObjectKey);
|
|
|
|
|
|
if (assetObject != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
await UniTask.Yield();
|
|
|
|
|
|
loadAssetCallbacks.LoadAssetSuccessCallback(location, assetObject.Target, Time.time - duration, userData);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
_assetLoadingList.Add(assetObjectKey);
|
|
|
|
|
|
|
|
|
|
|
|
AssetInfo assetInfo = GetAssetInfo(location, packageName);
|
|
|
|
|
|
|
|
|
|
|
|
if (!string.IsNullOrEmpty(assetInfo.Error))
|
|
|
|
|
|
{
|
|
|
|
|
|
_assetLoadingList.Remove(assetObjectKey);
|
|
|
|
|
|
|
|
|
|
|
|
string errorMessage = Utility.Text.Format("Can not load asset '{0}' because :'{1}'.", location, assetInfo.Error);
|
|
|
|
|
|
if (loadAssetCallbacks.LoadAssetFailureCallback != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
loadAssetCallbacks.LoadAssetFailureCallback(location, LoadResourceStatus.NotExist, errorMessage, userData);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
throw new GameFrameworkException(errorMessage);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
AssetHandle handle = GetHandleAsync(location, assetInfo.AssetType, packageName: packageName);
|
|
|
|
|
|
|
|
|
|
|
|
if (loadAssetCallbacks.LoadAssetUpdateCallback != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
InvokeProgress(location, handle, loadAssetCallbacks.LoadAssetUpdateCallback, userData).Forget();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
await handle.ToUniTask();
|
|
|
|
|
|
|
|
|
|
|
|
if (handle.AssetObject == null || handle.Status == EOperationStatus.Failed)
|
|
|
|
|
|
{
|
|
|
|
|
|
_assetLoadingList.Remove(assetObjectKey);
|
|
|
|
|
|
|
|
|
|
|
|
string errorMessage = Utility.Text.Format("Can not load asset '{0}'.", location);
|
|
|
|
|
|
if (loadAssetCallbacks.LoadAssetFailureCallback != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
loadAssetCallbacks.LoadAssetFailureCallback(location, LoadResourceStatus.NotReady, errorMessage, userData);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
throw new GameFrameworkException(errorMessage);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
assetObject = AssetObject.Create(assetObjectKey, handle.AssetObject, handle, this);
|
|
|
|
|
|
m_AssetPool.Register(assetObject, true);
|
|
|
|
|
|
|
|
|
|
|
|
_assetLoadingList.Remove(assetObjectKey);
|
|
|
|
|
|
|
|
|
|
|
|
if (loadAssetCallbacks.LoadAssetSuccessCallback != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
duration = Time.time - duration;
|
|
|
|
|
|
|
|
|
|
|
|
loadAssetCallbacks.LoadAssetSuccessCallback(location, handle.AssetObject, duration, userData);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private async UniTaskVoid InvokeProgress(string location, AssetHandle assetHandle, LoadAssetUpdateCallback loadAssetUpdateCallback, object userData)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (string.IsNullOrEmpty(location))
|
|
|
|
|
|
{
|
|
|
|
|
|
throw new GameFrameworkException("Asset name is invalid.");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (loadAssetUpdateCallback != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
while (assetHandle is { IsValid: true, IsDone: false })
|
|
|
|
|
|
{
|
|
|
|
|
|
await UniTask.Yield();
|
|
|
|
|
|
|
|
|
|
|
|
loadAssetUpdateCallback.Invoke(location, assetHandle.Progress, userData);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private readonly TimeoutController _timeoutController = new TimeoutController();
|
|
|
|
|
|
|
|
|
|
|
|
private async UniTask TryWaitingLoading(string assetObjectKey)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (_assetLoadingList.Contains(assetObjectKey))
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
await UniTask.WaitUntil(
|
|
|
|
|
|
() => !_assetLoadingList.Contains(assetObjectKey),
|
|
|
|
|
|
cancellationToken: CancellationToken)
|
|
|
|
|
|
#if UNITY_EDITOR
|
|
|
|
|
|
.AttachExternalCancellation(_timeoutController.Timeout(TimeSpan.FromSeconds(60)));
|
|
|
|
|
|
_timeoutController.Reset();
|
|
|
|
|
|
#else
|
|
|
|
|
|
;
|
|
|
|
|
|
#endif
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (OperationCanceledException ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (_timeoutController.IsTimeout())
|
|
|
|
|
|
{
|
|
|
|
|
|
Log.Error($"LoadAssetAsync Waiting {assetObjectKey} timeout. reason:{ex.Message}");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public AssetHandle LoadAssetGetOperation<T>(string location, string packageName = "") where T : UnityEngine.Object
|
|
|
|
|
|
{
|
|
|
|
|
|
if (string.IsNullOrEmpty(packageName))
|
|
|
|
|
|
{
|
|
|
|
|
|
return YooAssets.LoadAssetSync<T>(location);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var package = YooAssets.GetPackage(packageName);
|
|
|
|
|
|
return package.LoadAssetSync<T>(location);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public AssetHandle LoadAssetAsyncHandle<T>(string location, string packageName = "") where T : UnityEngine.Object
|
|
|
|
|
|
{
|
|
|
|
|
|
if (string.IsNullOrEmpty(packageName))
|
|
|
|
|
|
{
|
|
|
|
|
|
return YooAssets.LoadAssetAsync<T>(location);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var package = YooAssets.GetPackage(packageName);
|
|
|
|
|
|
return package.LoadAssetAsync<T>(location);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-01-24 16:21:00 +08:00
|
|
|
|
|
2025-01-23 19:06:48 +08:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region 资源回收
|
|
|
|
|
|
|
|
|
|
|
|
private void UnloadUnusedAssets()
|
|
|
|
|
|
{
|
|
|
|
|
|
m_AssetPool.ReleaseAllUnused();
|
|
|
|
|
|
foreach (var package in PackageMap.Values)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (package is { InitializeStatus: EOperationStatus.Succeed })
|
|
|
|
|
|
{
|
|
|
|
|
|
m_unloadUnusedAssetsOperation = package.UnloadUnusedAssetsAsync();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public void ForceUnloadAllAssets()
|
|
|
|
|
|
{
|
|
|
|
|
|
#if UNITY_WEBGL
|
|
|
|
|
|
Log.Warning($"WebGL not support invoke {nameof(ForceUnloadAllAssets)}");
|
|
|
|
|
|
return;
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var package in PackageMap.Values)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (package is { InitializeStatus: EOperationStatus.Succeed })
|
|
|
|
|
|
{
|
|
|
|
|
|
package.UnloadAllAssetsAsync();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 强制执行释放未被使用的资源。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="performGCCollect">是否使用垃圾回收。</param>
|
|
|
|
|
|
public void ForceUnloadUnusedAssets(bool performGCCollect)
|
|
|
|
|
|
{
|
|
|
|
|
|
m_ForceUnloadUnusedAssets = true;
|
|
|
|
|
|
if (performGCCollect)
|
|
|
|
|
|
{
|
|
|
|
|
|
m_PerformGCCollect = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 预订执行释放未被使用的资源。
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="performGCCollect">是否使用垃圾回收。</param>
|
|
|
|
|
|
public void UnloadUnusedAssets(bool performGCCollect)
|
|
|
|
|
|
{
|
|
|
|
|
|
m_PreorderUnloadUnusedAssets = true;
|
|
|
|
|
|
if (performGCCollect)
|
|
|
|
|
|
{
|
|
|
|
|
|
m_PerformGCCollect = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
public int Priority
|
|
|
|
|
|
{
|
|
|
|
|
|
get => 2;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-01-24 16:21:00 +08:00
|
|
|
|
}
|