refactor the runtime code

重构了运行时代码,支持全新的文件系统。
This commit is contained in:
何冠峰
2024-07-04 20:36:26 +08:00
parent 2987d356b6
commit ff02da5c54
313 changed files with 9889 additions and 7234 deletions
@@ -1,319 +0,0 @@
using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace YooAsset
{
internal sealed class AssetBundleFileLoader : BundleLoaderBase
{
private enum ESteps
{
None = 0,
Download,
CheckDownload,
Unpack,
CheckUnpack,
LoadBundleFile,
LoadDeliveryFile,
CheckLoadFile,
Done,
}
private ESteps _steps = ESteps.None;
private bool _isWaitForAsyncComplete = false;
private bool _isShowWaitForAsyncError = false;
private DownloaderBase _unpacker;
private DownloaderBase _downloader;
private AssetBundleCreateRequest _createRequest;
private Stream _managedStream;
public AssetBundleFileLoader(ResourceManager impl, BundleInfo bundleInfo) : base(impl, bundleInfo)
{
}
/// <summary>
/// 轮询更新
/// </summary>
public override void Update()
{
if (_steps == ESteps.Done)
return;
if (_steps == ESteps.None)
{
if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromRemote)
{
_steps = ESteps.Download;
FileLoadPath = MainBundleInfo.CachedDataFilePath;
}
else if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromStreaming)
{
#if UNITY_ANDROID
if (MainBundleInfo.Bundle.Encrypted)
{
_steps = ESteps.Unpack;
FileLoadPath = MainBundleInfo.CachedDataFilePath;
}
else
{
_steps = ESteps.LoadBundleFile;
FileLoadPath = MainBundleInfo.BuildinFilePath;
}
#else
_steps = ESteps.LoadBundleFile;
FileLoadPath = MainBundleInfo.BuildinFilePath;
#endif
}
else if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromCache)
{
_steps = ESteps.LoadBundleFile;
FileLoadPath = MainBundleInfo.CachedDataFilePath;
}
else if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromDelivery)
{
_steps = ESteps.LoadDeliveryFile;
FileLoadPath = MainBundleInfo.DeliveryFilePath;
}
else
{
throw new System.NotImplementedException(MainBundleInfo.LoadMode.ToString());
}
}
// 1. 从服务器下载
if (_steps == ESteps.Download)
{
_downloader = MainBundleInfo.CreateDownloader(int.MaxValue);
_downloader.SendRequest();
_steps = ESteps.CheckDownload;
}
// 2. 检测服务器下载结果
if (_steps == ESteps.CheckDownload)
{
DownloadProgress = _downloader.DownloadProgress;
DownloadedBytes = _downloader.DownloadedBytes;
if (_downloader.IsDone() == false)
return;
if (_downloader.HasError())
{
_steps = ESteps.Done;
Status = EStatus.Failed;
LastError = _downloader.GetLastError();
}
else
{
_steps = ESteps.LoadBundleFile;
return; //下载完毕等待一帧再去加载!
}
}
// 3. 内置文件解压
if (_steps == ESteps.Unpack)
{
int failedTryAgain = 1;
_unpacker = MainBundleInfo.CreateUnpacker(failedTryAgain);
_unpacker.SendRequest();
_steps = ESteps.CheckUnpack;
}
// 4.检测内置文件解压结果
if (_steps == ESteps.CheckUnpack)
{
DownloadProgress = _unpacker.DownloadProgress;
DownloadedBytes = _unpacker.DownloadedBytes;
if (_unpacker.IsDone() == false)
return;
if (_unpacker.HasError())
{
_steps = ESteps.Done;
Status = EStatus.Failed;
LastError = _unpacker.GetLastError();
}
else
{
_steps = ESteps.LoadBundleFile;
}
}
// 5. 加载AssetBundle
if (_steps == ESteps.LoadBundleFile)
{
#if UNITY_EDITOR
// 注意:Unity2017.4编辑器模式下,如果AssetBundle文件不存在会导致编辑器崩溃,这里做了预判。
if (System.IO.File.Exists(FileLoadPath) == false)
{
_steps = ESteps.Done;
Status = EStatus.Failed;
LastError = $"Not found assetBundle file : {FileLoadPath}";
YooLogger.Error(LastError);
return;
}
#endif
// 设置下载进度
DownloadProgress = 1f;
DownloadedBytes = (ulong)MainBundleInfo.Bundle.FileSize;
// 加载AssetBundle资源对象
// 注意:解密服务类可能会返回空的对象。
if (_isWaitForAsyncComplete)
CacheBundle = MainBundleInfo.LoadAssetBundle(FileLoadPath, out _managedStream);
else
_createRequest = MainBundleInfo.LoadAssetBundleAsync(FileLoadPath, out _managedStream);
_steps = ESteps.CheckLoadFile;
}
// 6. 加载AssetBundle
if (_steps == ESteps.LoadDeliveryFile)
{
// 设置下载进度
DownloadProgress = 1f;
DownloadedBytes = (ulong)MainBundleInfo.Bundle.FileSize;
// Load assetBundle file
if (_isWaitForAsyncComplete)
CacheBundle = MainBundleInfo.LoadDeliveryAssetBundle(FileLoadPath);
else
_createRequest = MainBundleInfo.LoadDeliveryAssetBundleAsync(FileLoadPath);
_steps = ESteps.CheckLoadFile;
}
// 7. 检测AssetBundle加载结果
if (_steps == ESteps.CheckLoadFile)
{
if (_createRequest != null)
{
if (_isWaitForAsyncComplete || IsForceDestroyComplete)
{
// 强制挂起主线程(注意:该操作会很耗时)
YooLogger.Warning("Suspend the main thread to load unity bundle.");
CacheBundle = _createRequest.assetBundle;
}
else
{
if (_createRequest.isDone == false)
return;
CacheBundle = _createRequest.assetBundle;
}
}
// Check error
if (CacheBundle == null)
{
// 注意:当缓存文件的校验等级为Low的时候,并不能保证缓存文件的完整性。
// 在AssetBundle文件加载失败的情况下,我们需要重新验证文件的完整性!
if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromCache)
{
var result = MainBundleInfo.VerifySelf();
if (result == EVerifyResult.Succeed)
{
// 说明:在安卓移动平台,华为和三星真机上有极小概率加载资源包失败。
// 大多数情况在首次安装下载资源到沙盒内,游戏过程中切换到后台再回到游戏内有很大概率触发!
byte[] fileData = FileUtility.ReadAllBytes(FileLoadPath);
if (fileData != null && fileData.Length > 0)
CacheBundle = AssetBundle.LoadFromMemory(fileData);
if (CacheBundle == null)
{
_steps = ESteps.Done;
Status = EStatus.Failed;
LastError = $"Failed to load assetBundle from memory : {MainBundleInfo.Bundle.BundleName}";
YooLogger.Error(LastError);
}
else
{
_steps = ESteps.Done;
Status = EStatus.Succeed;
}
}
else
{
_steps = ESteps.Done;
Status = EStatus.Failed;
LastError = $"Found possibly corrupt file ! {MainBundleInfo.Bundle.CacheGUID} Verify result : {result}";
YooLogger.Error(LastError);
MainBundleInfo.CacheDiscard();
}
}
else
{
_steps = ESteps.Done;
Status = EStatus.Failed;
LastError = $"Failed to load assetBundle : {MainBundleInfo.Bundle.BundleName}";
YooLogger.Error(LastError);
}
}
else
{
_steps = ESteps.Done;
Status = EStatus.Succeed;
}
}
}
/// <summary>
/// 销毁
/// </summary>
public override void Destroy()
{
base.Destroy();
if (_managedStream != null)
{
_managedStream.Close();
_managedStream.Dispose();
_managedStream = null;
}
}
/// <summary>
/// 主线程等待异步操作完毕
/// </summary>
public override void WaitForAsyncComplete()
{
_isWaitForAsyncComplete = true;
int frame = 1000;
while (true)
{
// 文件解压
if (_unpacker != null)
{
if (_unpacker.IsDone() == false)
{
_unpacker.WaitForAsyncComplete = true;
_unpacker.Update();
continue;
}
}
// 保险机制
// 注意:如果需要从WEB端下载资源,可能会触发保险机制!
frame--;
if (frame == 0)
{
if (_isShowWaitForAsyncError == false)
{
_isShowWaitForAsyncError = true;
YooLogger.Error($"{nameof(WaitForAsyncComplete)} failed ! Try load bundle : {MainBundleInfo.Bundle.BundleName} from remote with sync load method !");
}
break;
}
// 驱动流程
Update();
// 完成后退出
if (IsDone())
break;
}
}
}
}
@@ -1,111 +0,0 @@
using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
namespace YooAsset
{
/// <summary>
/// WebGL平台加载器
/// </summary>
internal sealed class AssetBundleWebLoader : BundleLoaderBase
{
private enum ESteps
{
None = 0,
LoadWebSiteFile,
LoadRemoteFile,
CheckLoadFile,
Done,
}
private ESteps _steps = ESteps.None;
private DownloaderBase _downloader;
public AssetBundleWebLoader(ResourceManager impl, BundleInfo bundleInfo) : base(impl, bundleInfo)
{
}
/// <summary>
/// 轮询更新
/// </summary>
public override void Update()
{
if (_steps == ESteps.Done)
return;
if (_steps == ESteps.None)
{
if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromRemote)
{
_steps = ESteps.LoadRemoteFile;
FileLoadPath = string.Empty;
}
else if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromStreaming)
{
_steps = ESteps.LoadWebSiteFile;
FileLoadPath = string.Empty;
}
else
{
throw new System.NotImplementedException(MainBundleInfo.LoadMode.ToString());
}
}
// 1. 跨域获取资源包
if (_steps == ESteps.LoadRemoteFile)
{
_downloader = MainBundleInfo.CreateDownloader(int.MaxValue);
_downloader.SendRequest(true);
_steps = ESteps.CheckLoadFile;
}
// 2. 从站点获取资源包
if (_steps == ESteps.LoadWebSiteFile)
{
_downloader = MainBundleInfo.CreateUnpacker(int.MaxValue);
_downloader.SendRequest(true);
_steps = ESteps.CheckLoadFile;
}
// 3. 检测加载结果
if (_steps == ESteps.CheckLoadFile)
{
DownloadProgress = _downloader.DownloadProgress;
DownloadedBytes = _downloader.DownloadedBytes;
if (_downloader.IsDone() == false)
return;
CacheBundle = _downloader.GetAssetBundle();
if (CacheBundle == null)
{
_steps = ESteps.Done;
Status = EStatus.Failed;
LastError = $"AssetBundle file is invalid : {MainBundleInfo.Bundle.BundleName}";
YooLogger.Error(LastError);
}
else
{
_steps = ESteps.Done;
Status = EStatus.Succeed;
}
}
}
/// <summary>
/// 主线程等待异步操作完毕
/// </summary>
public override void WaitForAsyncComplete()
{
if (IsDone() == false)
{
Status = EStatus.Failed;
LastError = $"{nameof(WaitForAsyncComplete)} failed ! WebGL platform not support sync load method !";
YooLogger.Error(LastError);
}
}
}
}
@@ -5,7 +5,7 @@ using UnityEngine;
namespace YooAsset
{
internal abstract class BundleLoaderBase
internal class BundleFileLoader
{
public enum EStatus
{
@@ -14,21 +14,17 @@ namespace YooAsset
Failed
}
/// <summary>
/// 所属资源系统
/// </summary>
public ResourceManager Impl { private set; get; }
private readonly ResourceManager _resourceManager;
private readonly List<ProviderBase> _providers = new List<ProviderBase>(100);
private readonly List<ProviderBase> _removeList = new List<ProviderBase>(100);
private FSLoadBundleOperation _loadBundleOp;
private bool _isDone = false;
/// <summary>
/// 资源包文件信息
/// </summary>
public BundleInfo MainBundleInfo { private set; get; }
/// <summary>
/// 引用计数
/// </summary>
public int RefCount { private set; get; }
/// <summary>
/// 加载状态
/// </summary>
@@ -37,30 +33,87 @@ namespace YooAsset
/// <summary>
/// 最近的错误信息
/// </summary>
public string LastError { protected set; get; }
public string LastError { protected set; get; } = string.Empty;
/// <summary>
/// 是否已经销毁
/// </summary>
public bool IsDestroyed { private set; get; } = false;
private readonly List<ProviderBase> _providers = new List<ProviderBase>(100);
private readonly List<ProviderBase> _removeList = new List<ProviderBase>(100);
protected bool IsForceDestroyComplete { private set; get; } = false;
internal AssetBundle CacheBundle { set; get; }
internal string FileLoadPath { set; get; }
internal float DownloadProgress { set; get; }
internal ulong DownloadedBytes { set; get; }
/// <summary>
/// 引用计数
/// </summary>
public int RefCount { private set; get; } = 0;
/// <summary>
/// 下载进度
/// </summary>
public float DownloadProgress { set; get; } = 0;
/// <summary>
/// 下载大小
/// </summary>
public long DownloadedBytes { set; get; } = 0;
/// <summary>
/// 下载结果
/// </summary>
public object Result { set; get; }
public BundleLoaderBase(ResourceManager impl, BundleInfo bundleInfo)
public BundleFileLoader(ResourceManager resourceManager, BundleInfo bundleInfo)
{
Impl = impl;
_resourceManager = resourceManager;
MainBundleInfo = bundleInfo;
RefCount = 0;
Status = EStatus.None;
}
/// <summary>
/// 轮询更新
/// </summary>
public void Update()
{
if (_isDone)
return;
if (_loadBundleOp == null)
_loadBundleOp = MainBundleInfo.LoadBundleFile();
DownloadProgress = _loadBundleOp.DownloadProgress;
DownloadedBytes = _loadBundleOp.DownloadedBytes;
if (_loadBundleOp.IsDone == false)
return;
if (_loadBundleOp.Status == EOperationStatus.Succeed)
{
_isDone = true;
Status = EStatus.Succeed;
Result = _loadBundleOp.Result;
}
else
{
_isDone = true;
Status = EStatus.Failed;
LastError = _loadBundleOp.Error;
}
}
/// <summary>
/// 销毁
/// </summary>
public void Destroy()
{
IsDestroyed = true;
// Check fatal
if (RefCount > 0)
throw new Exception($"Bundle file loader ref is not zero : {MainBundleInfo.Bundle.BundleName}");
if (IsDone() == false)
throw new Exception($"Bundle file loader is not done : {MainBundleInfo.Bundle.BundleName}");
MainBundleInfo.UnloadBundleFile(Result);
}
/// <summary>
/// 引用(引用计数递加)
/// </summary>
@@ -130,52 +183,40 @@ namespace YooAsset
// 移除资源提供者
if (_removeList.Count > 0)
{
Impl.RemoveBundleProviders(_removeList);
_resourceManager.RemoveBundleProviders(_removeList);
_removeList.Clear();
}
}
/// <summary>
/// 轮询更新
/// </summary>
public abstract void Update();
/// <summary>
/// 销毁
/// </summary>
public virtual void Destroy()
{
IsDestroyed = true;
// Check fatal
if (RefCount > 0)
throw new Exception($"Bundle file loader ref is not zero : {MainBundleInfo.Bundle.BundleName}");
if (IsDone() == false)
throw new Exception($"Bundle file loader is not done : {MainBundleInfo.Bundle.BundleName}");
if (CacheBundle != null)
{
CacheBundle.Unload(true);
CacheBundle = null;
}
}
/// <summary>
/// 强制销毁资源提供者
/// </summary>
public void ForceDestroyComplete()
{
IsForceDestroyComplete = true;
// 注意:主动轮询更新完成同步加载
// 说明:如果正在下载或解压也可以放心销毁。
Update();
}
/// <summary>
/// 主线程等待异步操作完毕
/// </summary>
public abstract void WaitForAsyncComplete();
public void WaitForAsyncComplete()
{
while (true)
{
if (_loadBundleOp != null)
{
if (_loadBundleOp.IsDone == false)
_loadBundleOp.WaitForAsyncComplete();
}
// 驱动流程
Update();
// 完成后退出
if (IsDone())
break;
}
}
/// <summary>
/// 终止下载任务
/// </summary>
public void AbortDownloadOperation()
{
if (_loadBundleOp != null)
_loadBundleOp.AbortDownloadOperation();
}
}
}
@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: b8aaabc43e74af14d8eb3c7c85e19cda
guid: 031287bf937f83e4fa18a0db797abb42
MonoImporter:
externalObjects: {}
serializedVersion: 2
@@ -4,15 +4,15 @@ using System.Collections.Generic;
namespace YooAsset
{
internal class DependAssetBundles
internal class DependFileLoaders
{
/// <summary>
/// 依赖的资源包加载器列表
/// </summary>
internal readonly List<BundleLoaderBase> DependList;
internal readonly List<BundleFileLoader> DependList;
public DependAssetBundles(List<BundleLoaderBase> dpendList)
public DependFileLoaders(List<BundleFileLoader> dpendList)
{
DependList = dpendList;
}
@@ -37,7 +37,7 @@ namespace YooAsset
{
foreach (var loader in DependList)
{
if (loader.Status != BundleLoaderBase.EStatus.Succeed)
if (loader.Status != BundleFileLoader.EStatus.Succeed)
{
return false;
}
@@ -52,7 +52,7 @@ namespace YooAsset
{
foreach (var loader in DependList)
{
if (loader.Status != BundleLoaderBase.EStatus.Succeed)
if (loader.Status != BundleFileLoader.EStatus.Succeed)
{
return loader.LastError;
}
@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 64d0a51f59c2a964eaf97b87db47428f
guid: 3834f832061fdd74fbfb1eba381b1b3e
MonoImporter:
externalObjects: {}
serializedVersion: 2
@@ -0,0 +1,32 @@
namespace YooAsset
{
public struct DownloadStatus
{
/// <summary>
/// 下载是否已经完成
/// </summary>
public bool IsDone;
/// <summary>
/// 下载进度(0-1f)
/// </summary>
public float Progress;
/// <summary>
/// 下载文件的总大小
/// </summary>
public long TotalBytes;
/// <summary>
/// 已经下载的文件大小
/// </summary>
public long DownloadedBytes;
public static DownloadStatus CreateDefaultStatus()
{
DownloadStatus status = new DownloadStatus();
return status;
}
}
}
@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: b7eeccc96e4c31c45bd105b0dbc3fd6e
guid: 26dbf3c6610209e40bcf31c9c66739bc
MonoImporter:
externalObjects: {}
serializedVersion: 2
@@ -1,188 +0,0 @@
using System.IO;
namespace YooAsset
{
internal class RawBundleFileLoader : BundleLoaderBase
{
private enum ESteps
{
None,
Download,
CheckDownload,
Unpack,
CheckUnpack,
CheckFile,
Done,
}
private ESteps _steps = ESteps.None;
private DownloaderBase _unpacker;
private DownloaderBase _downloader;
public RawBundleFileLoader(ResourceManager impl, BundleInfo bundleInfo) : base(impl, bundleInfo)
{
}
/// <summary>
/// 轮询更新
/// </summary>
public override void Update()
{
if (_steps == ESteps.Done)
return;
if (_steps == ESteps.None)
{
if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromRemote)
{
_steps = ESteps.Download;
FileLoadPath = MainBundleInfo.CachedDataFilePath;
}
else if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromStreaming)
{
#if UNITY_ANDROID
_steps = ESteps.Unpack;
FileLoadPath = MainBundleInfo.CachedDataFilePath;
#else
_steps = ESteps.CheckFile;
FileLoadPath = MainBundleInfo.BuildinFilePath;
#endif
}
else if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromCache)
{
_steps = ESteps.CheckFile;
FileLoadPath = MainBundleInfo.CachedDataFilePath;
}
else if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromDelivery)
{
_steps = ESteps.CheckFile;
FileLoadPath = MainBundleInfo.DeliveryFilePath;
}
else
{
throw new System.NotImplementedException(MainBundleInfo.LoadMode.ToString());
}
}
// 1. 下载远端文件
if (_steps == ESteps.Download)
{
_downloader = MainBundleInfo.CreateDownloader(int.MaxValue);
_downloader.SendRequest();
_steps = ESteps.CheckDownload;
}
// 2. 检测下载结果
if (_steps == ESteps.CheckDownload)
{
DownloadProgress = _downloader.DownloadProgress;
DownloadedBytes = _downloader.DownloadedBytes;
if (_downloader.IsDone() == false)
return;
if (_downloader.HasError())
{
_steps = ESteps.Done;
Status = EStatus.Failed;
LastError = _downloader.GetLastError();
}
else
{
_steps = ESteps.CheckFile;
}
}
// 3. 解压内置文件
if (_steps == ESteps.Unpack)
{
int failedTryAgain = 1;
_unpacker = MainBundleInfo.CreateUnpacker(failedTryAgain);
_unpacker.SendRequest();
_steps = ESteps.CheckUnpack;
}
// 4. 检测解压结果
if (_steps == ESteps.CheckUnpack)
{
DownloadProgress = _unpacker.DownloadProgress;
DownloadedBytes = _unpacker.DownloadedBytes;
if (_unpacker.IsDone() == false)
return;
if (_unpacker.HasError())
{
_steps = ESteps.Done;
Status = EStatus.Failed;
LastError = _unpacker.GetLastError();
}
else
{
_steps = ESteps.CheckFile;
}
}
// 5. 检测结果
if (_steps == ESteps.CheckFile)
{
// 设置下载进度
DownloadProgress = 1f;
DownloadedBytes = (ulong)MainBundleInfo.Bundle.FileSize;
if (File.Exists(FileLoadPath))
{
_steps = ESteps.Done;
Status = EStatus.Succeed;
}
else
{
_steps = ESteps.Done;
Status = EStatus.Failed;
LastError = $"Raw file not found : {FileLoadPath}";
}
}
}
/// <summary>
/// 主线程等待异步操作完毕
/// </summary>
public override void WaitForAsyncComplete()
{
int frame = 1000;
while (true)
{
// 文件解压
if (_unpacker != null)
{
if (_unpacker.IsDone() == false)
{
_unpacker.WaitForAsyncComplete = true;
_unpacker.Update();
continue;
}
}
// 保险机制
// 注意:如果需要从远端下载资源,可能会触发保险机制!
frame--;
if (frame == 0)
{
if (IsDone() == false)
{
Status = EStatus.Failed;
LastError = $"WaitForAsyncComplete failed ! Try load bundle : {MainBundleInfo.Bundle.BundleName} from remote with sync load method !";
YooLogger.Error(LastError);
}
break;
}
// 驱动流程
Update();
// 完成后退出
if (IsDone())
break;
}
}
}
}
@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: fa39f24727abe514093f18787c0c7e27
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -1,145 +0,0 @@
using System.IO;
namespace YooAsset
{
/// <summary>
/// WebGL平台加载器
/// </summary>
internal class RawBundleWebLoader : BundleLoaderBase
{
private enum ESteps
{
None,
Download,
CheckDownload,
Website,
CheckWebsite,
CheckFile,
Done,
}
private ESteps _steps = ESteps.None;
private DownloaderBase _website;
private DownloaderBase _downloader;
public RawBundleWebLoader(ResourceManager impl, BundleInfo bundleInfo) : base(impl, bundleInfo)
{
}
/// <summary>
/// 轮询更新
/// </summary>
public override void Update()
{
if (_steps == ESteps.Done)
return;
if (_steps == ESteps.None)
{
if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromRemote)
{
_steps = ESteps.Download;
FileLoadPath = MainBundleInfo.CachedDataFilePath;
}
else if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromStreaming)
{
_steps = ESteps.Website;
FileLoadPath = MainBundleInfo.CachedDataFilePath;
}
else
{
throw new System.NotImplementedException(MainBundleInfo.LoadMode.ToString());
}
}
// 1. 下载远端文件
if (_steps == ESteps.Download)
{
_downloader = MainBundleInfo.CreateDownloader(int.MaxValue);
_downloader.SendRequest();
_steps = ESteps.CheckDownload;
}
// 2. 检测下载结果
if (_steps == ESteps.CheckDownload)
{
DownloadProgress = _downloader.DownloadProgress;
DownloadedBytes = _downloader.DownloadedBytes;
if (_downloader.IsDone() == false)
return;
if (_downloader.HasError())
{
_steps = ESteps.Done;
Status = EStatus.Failed;
LastError = _downloader.GetLastError();
}
else
{
_steps = ESteps.CheckFile;
}
}
// 3. 从站点下载
if (_steps == ESteps.Website)
{
_website = MainBundleInfo.CreateUnpacker(int.MaxValue);
_website.SendRequest();
_steps = ESteps.CheckWebsite;
}
// 4. 检测站点下载
if (_steps == ESteps.CheckWebsite)
{
DownloadProgress = _website.DownloadProgress;
DownloadedBytes = _website.DownloadedBytes;
if (_website.IsDone() == false)
return;
if (_website.HasError())
{
_steps = ESteps.Done;
Status = EStatus.Failed;
LastError = _website.GetLastError();
}
else
{
_steps = ESteps.CheckFile;
}
}
// 5. 检测结果
if (_steps == ESteps.CheckFile)
{
// 设置下载进度
DownloadProgress = 1f;
DownloadedBytes = (ulong)MainBundleInfo.Bundle.FileSize;
_steps = ESteps.Done;
if (File.Exists(FileLoadPath))
{
Status = EStatus.Succeed;
}
else
{
Status = EStatus.Failed;
LastError = $"Raw file not found : {FileLoadPath}";
}
}
}
/// <summary>
/// 主线程等待异步操作完毕
/// </summary>
public override void WaitForAsyncComplete()
{
if (IsDone() == false)
{
Status = EStatus.Failed;
LastError = $"{nameof(WaitForAsyncComplete)} failed ! WebGL platform not support sync load method !";
YooLogger.Error(LastError);
}
}
}
}
@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 1d16b689f73611e44bd01a4cc429a6ac
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -1,82 +0,0 @@
namespace YooAsset
{
internal class VirtualBundleFileLoader : BundleLoaderBase
{
private enum ESteps
{
None,
CheckFile,
Done,
}
private ESteps _steps = ESteps.None;
public VirtualBundleFileLoader(ResourceManager impl, BundleInfo bundleInfo) : base(impl, bundleInfo)
{
}
/// <summary>
/// 轮询更新
/// </summary>
public override void Update()
{
if (_steps == ESteps.Done)
return;
if (_steps == ESteps.None)
{
if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromEditor)
{
_steps = ESteps.CheckFile;
}
else
{
throw new System.NotImplementedException(MainBundleInfo.LoadMode.ToString());
}
}
// 1. 检测结果
if (_steps == ESteps.CheckFile)
{
// 设置下载进度
DownloadProgress = 1f;
DownloadedBytes = (ulong)MainBundleInfo.Bundle.FileSize;
_steps = ESteps.Done;
Status = EStatus.Succeed;
}
}
/// <summary>
/// 主线程等待异步操作完毕
/// </summary>
public override void WaitForAsyncComplete()
{
int frame = 1000;
while (true)
{
// 保险机制
// 注意:如果需要从远端下载资源,可能会触发保险机制!
frame--;
if (frame == 0)
{
if (IsDone() == false)
{
Status = EStatus.Failed;
LastError = $"WaitForAsyncComplete failed ! Try load bundle : {MainBundleInfo.Bundle.BundleName} from remote with sync load method !";
YooLogger.Error(LastError);
}
break;
}
// 驱动流程
Update();
// 完成后退出
if (IsDone())
break;
}
}
}
}
@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 7b9023a940b496549894d9d8872219fb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -72,23 +72,10 @@ namespace YooAsset
}
}
/// <summary>
/// 取消实例化对象操作
/// </summary>
public void Cancel()
{
if (IsDone == false)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"User cancelled !";
}
}
/// <summary>
/// 等待异步实例化结束
/// </summary>
public void WaitForAsyncComplete()
public override void WaitForAsyncComplete()
{
if (_steps == ESteps.Done)
return;
@@ -96,6 +83,14 @@ namespace YooAsset
InternalOnUpdate();
}
/// <summary>
/// 取消实例化对象操作
/// </summary>
public void Cancel()
{
SetAbort();
}
internal static GameObject InstantiateInternal(UnityEngine.Object assetObject, bool setPositionAndRotation, Vector3 position, Quaternion rotation, Transform parent, bool worldPositionStays)
{
if (assetObject == null)
@@ -0,0 +1,94 @@
using System;
using UnityEngine;
namespace YooAsset
{
public sealed class UnloadAllAssetsOperation : AsyncOperationBase
{
private enum ESteps
{
None,
AbortDownload,
CheckLoading,
UnloadAll,
Done,
}
private readonly ResourceManager _resManager;
private ESteps _steps = ESteps.None;
internal UnloadAllAssetsOperation(ResourceManager resourceManager)
{
_resManager = resourceManager;
}
internal override void InternalOnStart()
{
_steps = ESteps.AbortDownload;
}
internal override void InternalOnUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.AbortDownload)
{
// 注意:终止所有下载任务
var loaderList = _resManager._loaderList;
foreach (var loader in loaderList)
{
loader.AbortDownloadOperation();
}
_steps = ESteps.CheckLoading;
}
if (_steps == ESteps.CheckLoading)
{
// 注意:等待所有任务完成
var providerDic = _resManager._providerDic;
foreach (var provider in providerDic.Values)
{
if (provider.IsDone == false)
return;
}
_steps = ESteps.UnloadAll;
}
if (_steps == ESteps.UnloadAll)
{
var loaderList = _resManager._loaderList;
var loaderDic = _resManager._loaderDic;
var providerDic = _resManager._providerDic;
// 释放所有资源句柄
foreach (var provider in providerDic.Values)
{
provider.ReleaseAllHandles();
}
// 强制销毁资源提供者
foreach (var provider in providerDic.Values)
{
provider.Destroy();
}
// 强制销毁文件加载器
foreach (var loader in loaderList)
{
loader.Destroy();
}
// 清空数据
providerDic.Clear();
loaderList.Clear();
loaderDic.Clear();
_resManager.ClearSceneHandle();
// 注意:调用底层接口释放所有资源
Resources.UnloadUnusedAssets();
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}
}
}
}
@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: bd1ad395c62c5804589ec9b267ea0484
guid: 97b5f55d30137a4438d3cbed93819c6b
MonoImporter:
externalObjects: {}
serializedVersion: 2
@@ -0,0 +1,62 @@
using System;
using UnityEngine;
namespace YooAsset
{
public sealed class UnloadUnusedAssetsOperation : AsyncOperationBase
{
private enum ESteps
{
None,
UnloadUnused,
Done,
}
private readonly ResourceManager _resManager;
private ESteps _steps = ESteps.None;
internal UnloadUnusedAssetsOperation(ResourceManager resourceManager)
{
_resManager = resourceManager;
}
internal override void InternalOnStart()
{
_steps = ESteps.UnloadUnused;
}
internal override void InternalOnUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.UnloadUnused)
{
var loaderList = _resManager._loaderList;
var loaderDic = _resManager._loaderDic;
for (int i = loaderList.Count - 1; i >= 0; i--)
{
BundleFileLoader loader = loaderList[i];
loader.TryDestroyProviders();
}
for (int i = loaderList.Count - 1; i >= 0; i--)
{
BundleFileLoader loader = loaderList[i];
if (loader.CanDestroy())
{
string bundleName = loader.MainBundleInfo.Bundle.BundleName;
loader.Destroy();
loaderList.RemoveAt(i);
loaderDic.Remove(bundleName);
}
}
// 注意:调用底层接口释放所有资源
Resources.UnloadUnusedAssets();
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 90a7cd6101e04ac48ae6aa383572d2c4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -6,6 +6,7 @@ namespace YooAsset
{
internal sealed class BundledAllAssetsProvider : ProviderBase
{
private AssetBundle _assetBundle;
private AssetBundleRequest _cacheRequest;
public BundledAllAssetsProvider(ResourceManager manager, string providerGUID, AssetInfo assetInfo) : base(manager, providerGUID, assetInfo)
@@ -30,54 +31,62 @@ namespace YooAsset
{
if (IsWaitForAsyncComplete)
{
DependBundles.WaitForAsyncComplete();
OwnerBundle.WaitForAsyncComplete();
DependLoaders.WaitForAsyncComplete();
FileLoader.WaitForAsyncComplete();
}
if (DependBundles.IsDone() == false)
if (DependLoaders.IsDone() == false)
return;
if (OwnerBundle.IsDone() == false)
if (FileLoader.IsDone() == false)
return;
if (DependBundles.IsSucceed() == false)
if (DependLoaders.IsSucceed() == false)
{
string error = DependBundles.GetLastError();
string error = DependLoaders.GetLastError();
InvokeCompletion(error, EOperationStatus.Failed);
return;
}
if (OwnerBundle.Status != BundleLoaderBase.EStatus.Succeed)
if (FileLoader.Status != BundleFileLoader.EStatus.Succeed)
{
string error = OwnerBundle.LastError;
string error = FileLoader.LastError;
InvokeCompletion(error, EOperationStatus.Failed);
return;
}
if (OwnerBundle.CacheBundle == null)
if (FileLoader.Result == null)
{
ProcessCacheBundleException();
ProcessFatalEvent();
return;
}
if (FileLoader.Result is AssetBundle == false)
{
string error = "Try load raw file using load assetbundle method !";
InvokeCompletion(error, EOperationStatus.Failed);
return;
}
_assetBundle = FileLoader.Result as AssetBundle;
_steps = ESteps.Loading;
}
// 2. 加载资源对象
if (_steps == ESteps.Loading)
{
if (IsWaitForAsyncComplete || IsForceDestroyComplete)
if (IsWaitForAsyncComplete)
{
if (MainAssetInfo.AssetType == null)
AllAssetObjects = OwnerBundle.CacheBundle.LoadAllAssets();
AllAssetObjects = _assetBundle.LoadAllAssets();
else
AllAssetObjects = OwnerBundle.CacheBundle.LoadAllAssets(MainAssetInfo.AssetType);
AllAssetObjects = _assetBundle.LoadAllAssets(MainAssetInfo.AssetType);
}
else
{
if (MainAssetInfo.AssetType == null)
_cacheRequest = OwnerBundle.CacheBundle.LoadAllAssetsAsync();
_cacheRequest = _assetBundle.LoadAllAssetsAsync();
else
_cacheRequest = OwnerBundle.CacheBundle.LoadAllAssetsAsync(MainAssetInfo.AssetType);
_cacheRequest = _assetBundle.LoadAllAssetsAsync(MainAssetInfo.AssetType);
}
_steps = ESteps.Checking;
}
@@ -87,7 +96,7 @@ namespace YooAsset
{
if (_cacheRequest != null)
{
if (IsWaitForAsyncComplete || IsForceDestroyComplete)
if (IsWaitForAsyncComplete)
{
// 强制挂起主线程(注意:该操作会很耗时)
YooLogger.Warning("Suspend the main thread to load unity asset.");
@@ -106,9 +115,9 @@ namespace YooAsset
{
string error;
if (MainAssetInfo.AssetType == null)
error = $"Failed to load all assets : {MainAssetInfo.AssetPath} AssetType : null AssetBundle : {OwnerBundle.MainBundleInfo.Bundle.BundleName}";
error = $"Failed to load all assets : {MainAssetInfo.AssetPath} AssetType : null AssetBundle : {FileLoader.MainBundleInfo.Bundle.BundleName}";
else
error = $"Failed to load all assets : {MainAssetInfo.AssetPath} AssetType : {MainAssetInfo.AssetType} AssetBundle : {OwnerBundle.MainBundleInfo.Bundle.BundleName}";
error = $"Failed to load all assets : {MainAssetInfo.AssetPath} AssetType : {MainAssetInfo.AssetType} AssetBundle : {FileLoader.MainBundleInfo.Bundle.BundleName}";
YooLogger.Error(error);
InvokeCompletion(error, EOperationStatus.Failed);
}
@@ -6,6 +6,7 @@ namespace YooAsset
{
internal sealed class BundledAssetProvider : ProviderBase
{
private AssetBundle _assetBundle;
private AssetBundleRequest _cacheRequest;
public BundledAssetProvider(ResourceManager manager, string providerGUID, AssetInfo assetInfo) : base(manager, providerGUID, assetInfo)
@@ -30,54 +31,62 @@ namespace YooAsset
{
if (IsWaitForAsyncComplete)
{
DependBundles.WaitForAsyncComplete();
OwnerBundle.WaitForAsyncComplete();
DependLoaders.WaitForAsyncComplete();
FileLoader.WaitForAsyncComplete();
}
if (DependBundles.IsDone() == false)
if (DependLoaders.IsDone() == false)
return;
if (OwnerBundle.IsDone() == false)
if (FileLoader.IsDone() == false)
return;
if (DependBundles.IsSucceed() == false)
if (DependLoaders.IsSucceed() == false)
{
string error = DependBundles.GetLastError();
string error = DependLoaders.GetLastError();
InvokeCompletion(error, EOperationStatus.Failed);
return;
}
if (OwnerBundle.Status != BundleLoaderBase.EStatus.Succeed)
if (FileLoader.Status != BundleFileLoader.EStatus.Succeed)
{
string error = OwnerBundle.LastError;
string error = FileLoader.LastError;
InvokeCompletion(error, EOperationStatus.Failed);
return;
}
if (OwnerBundle.CacheBundle == null)
if (FileLoader.Result == null)
{
ProcessCacheBundleException();
ProcessFatalEvent();
return;
}
if (FileLoader.Result is AssetBundle == false)
{
string error = "Try load raw file using load assetbundle method !";
InvokeCompletion(error, EOperationStatus.Failed);
return;
}
_assetBundle = FileLoader.Result as AssetBundle;
_steps = ESteps.Loading;
}
// 2. 加载资源对象
if (_steps == ESteps.Loading)
{
if (IsWaitForAsyncComplete || IsForceDestroyComplete)
if (IsWaitForAsyncComplete)
{
if (MainAssetInfo.AssetType == null)
AssetObject = OwnerBundle.CacheBundle.LoadAsset(MainAssetInfo.AssetPath);
AssetObject = _assetBundle.LoadAsset(MainAssetInfo.AssetPath);
else
AssetObject = OwnerBundle.CacheBundle.LoadAsset(MainAssetInfo.AssetPath, MainAssetInfo.AssetType);
AssetObject = _assetBundle.LoadAsset(MainAssetInfo.AssetPath, MainAssetInfo.AssetType);
}
else
{
if (MainAssetInfo.AssetType == null)
_cacheRequest = OwnerBundle.CacheBundle.LoadAssetAsync(MainAssetInfo.AssetPath);
_cacheRequest = _assetBundle.LoadAssetAsync(MainAssetInfo.AssetPath);
else
_cacheRequest = OwnerBundle.CacheBundle.LoadAssetAsync(MainAssetInfo.AssetPath, MainAssetInfo.AssetType);
_cacheRequest = _assetBundle.LoadAssetAsync(MainAssetInfo.AssetPath, MainAssetInfo.AssetType);
}
_steps = ESteps.Checking;
}
@@ -87,7 +96,7 @@ namespace YooAsset
{
if (_cacheRequest != null)
{
if (IsWaitForAsyncComplete || IsForceDestroyComplete)
if (IsWaitForAsyncComplete)
{
// 强制挂起主线程(注意:该操作会很耗时)
YooLogger.Warning("Suspend the main thread to load unity asset.");
@@ -106,9 +115,9 @@ namespace YooAsset
{
string error;
if (MainAssetInfo.AssetType == null)
error = $"Failed to load asset : {MainAssetInfo.AssetPath} AssetType : null AssetBundle : {OwnerBundle.MainBundleInfo.Bundle.BundleName}";
error = $"Failed to load asset : {MainAssetInfo.AssetPath} AssetType : null AssetBundle : {FileLoader.MainBundleInfo.Bundle.BundleName}";
else
error = $"Failed to load asset : {MainAssetInfo.AssetPath} AssetType : {MainAssetInfo.AssetType} AssetBundle : {OwnerBundle.MainBundleInfo.Bundle.BundleName}";
error = $"Failed to load asset : {MainAssetInfo.AssetPath} AssetType : {MainAssetInfo.AssetType} AssetBundle : {FileLoader.MainBundleInfo.Bundle.BundleName}";
YooLogger.Error(error);
InvokeCompletion(error, EOperationStatus.Failed);
}
@@ -24,16 +24,21 @@ namespace YooAsset
if (_steps == ESteps.CheckBundle)
{
if (IsWaitForAsyncComplete)
{
OwnerBundle.WaitForAsyncComplete();
}
FileLoader.WaitForAsyncComplete();
if (OwnerBundle.IsDone() == false)
if (FileLoader.IsDone() == false)
return;
if (OwnerBundle.Status != BundleLoaderBase.EStatus.Succeed)
if (FileLoader.Status != BundleFileLoader.EStatus.Succeed)
{
string error = OwnerBundle.LastError;
string error = FileLoader.LastError;
InvokeCompletion(error, EOperationStatus.Failed);
return;
}
if (FileLoader.Result is string == false)
{
string error = "Try load AssetBundle file using load raw file method !";
InvokeCompletion(error, EOperationStatus.Failed);
return;
}
@@ -44,7 +49,7 @@ namespace YooAsset
// 2. 检测加载结果
if (_steps == ESteps.Checking)
{
RawFilePath = OwnerBundle.FileLoadPath;
RawFilePath = FileLoader.Result as string;
InvokeCompletion(string.Empty, EOperationStatus.Succeed);
}
}
@@ -37,25 +37,25 @@ namespace YooAsset
{
if (IsWaitForAsyncComplete)
{
DependBundles.WaitForAsyncComplete();
OwnerBundle.WaitForAsyncComplete();
DependLoaders.WaitForAsyncComplete();
FileLoader.WaitForAsyncComplete();
}
if (DependBundles.IsDone() == false)
if (DependLoaders.IsDone() == false)
return;
if (OwnerBundle.IsDone() == false)
if (FileLoader.IsDone() == false)
return;
if (DependBundles.IsSucceed() == false)
if (DependLoaders.IsSucceed() == false)
{
string error = DependBundles.GetLastError();
string error = DependLoaders.GetLastError();
InvokeCompletion(error, EOperationStatus.Failed);
return;
}
if (OwnerBundle.Status != BundleLoaderBase.EStatus.Succeed)
if (FileLoader.Status != BundleFileLoader.EStatus.Succeed)
{
string error = OwnerBundle.LastError;
string error = FileLoader.LastError;
InvokeCompletion(error, EOperationStatus.Failed);
return;
}
@@ -66,7 +66,7 @@ namespace YooAsset
// 2. 加载场景
if (_steps == ESteps.Loading)
{
if (IsWaitForAsyncComplete || IsForceDestroyComplete)
if (IsWaitForAsyncComplete)
{
// 注意:场景同步加载方法不会立即加载场景,而是在下一帧加载。
LoadSceneParameters parameters = new LoadSceneParameters(SceneMode);
@@ -99,7 +99,7 @@ namespace YooAsset
{
if (_asyncOperation != null)
{
if (IsWaitForAsyncComplete || IsForceDestroyComplete)
if (IsWaitForAsyncComplete)
{
// 场景加载无法强制异步转同步
YooLogger.Error("The scene is loading asyn !");
@@ -6,6 +6,7 @@ namespace YooAsset
{
internal sealed class BundledSubAssetsProvider : ProviderBase
{
private AssetBundle _assetBundle;
private AssetBundleRequest _cacheRequest;
public BundledSubAssetsProvider(ResourceManager manager, string providerGUID, AssetInfo assetInfo) : base(manager, providerGUID, assetInfo)
@@ -30,54 +31,62 @@ namespace YooAsset
{
if (IsWaitForAsyncComplete)
{
DependBundles.WaitForAsyncComplete();
OwnerBundle.WaitForAsyncComplete();
DependLoaders.WaitForAsyncComplete();
FileLoader.WaitForAsyncComplete();
}
if (DependBundles.IsDone() == false)
if (DependLoaders.IsDone() == false)
return;
if (OwnerBundle.IsDone() == false)
if (FileLoader.IsDone() == false)
return;
if (DependBundles.IsSucceed() == false)
if (DependLoaders.IsSucceed() == false)
{
string error = DependBundles.GetLastError();
string error = DependLoaders.GetLastError();
InvokeCompletion(error, EOperationStatus.Failed);
return;
}
if (OwnerBundle.Status != BundleLoaderBase.EStatus.Succeed)
if (FileLoader.Status != BundleFileLoader.EStatus.Succeed)
{
string error = OwnerBundle.LastError;
string error = FileLoader.LastError;
InvokeCompletion(error, EOperationStatus.Failed);
return;
}
if (OwnerBundle.CacheBundle == null)
if (FileLoader.Result == null)
{
ProcessCacheBundleException();
ProcessFatalEvent();
return;
}
if (FileLoader.Result is AssetBundle == false)
{
string error = "Try load raw file using load assetbundle method !";
InvokeCompletion(error, EOperationStatus.Failed);
return;
}
_assetBundle = FileLoader.Result as AssetBundle;
_steps = ESteps.Loading;
}
// 2. 加载资源对象
if (_steps == ESteps.Loading)
{
if (IsWaitForAsyncComplete || IsForceDestroyComplete)
if (IsWaitForAsyncComplete)
{
if (MainAssetInfo.AssetType == null)
AllAssetObjects = OwnerBundle.CacheBundle.LoadAssetWithSubAssets(MainAssetInfo.AssetPath);
AllAssetObjects = _assetBundle.LoadAssetWithSubAssets(MainAssetInfo.AssetPath);
else
AllAssetObjects = OwnerBundle.CacheBundle.LoadAssetWithSubAssets(MainAssetInfo.AssetPath, MainAssetInfo.AssetType);
AllAssetObjects = _assetBundle.LoadAssetWithSubAssets(MainAssetInfo.AssetPath, MainAssetInfo.AssetType);
}
else
{
if (MainAssetInfo.AssetType == null)
_cacheRequest = OwnerBundle.CacheBundle.LoadAssetWithSubAssetsAsync(MainAssetInfo.AssetPath);
_cacheRequest = _assetBundle.LoadAssetWithSubAssetsAsync(MainAssetInfo.AssetPath);
else
_cacheRequest = OwnerBundle.CacheBundle.LoadAssetWithSubAssetsAsync(MainAssetInfo.AssetPath, MainAssetInfo.AssetType);
_cacheRequest = _assetBundle.LoadAssetWithSubAssetsAsync(MainAssetInfo.AssetPath, MainAssetInfo.AssetType);
}
_steps = ESteps.Checking;
}
@@ -87,7 +96,7 @@ namespace YooAsset
{
if (_cacheRequest != null)
{
if (IsWaitForAsyncComplete || IsForceDestroyComplete)
if (IsWaitForAsyncComplete)
{
// 强制挂起主线程(注意:该操作会很耗时)
YooLogger.Warning("Suspend the main thread to load unity asset.");
@@ -106,9 +115,9 @@ namespace YooAsset
{
string error;
if (MainAssetInfo.AssetType == null)
error = $"Failed to load sub assets : {MainAssetInfo.AssetPath} AssetType : null AssetBundle : {OwnerBundle.MainBundleInfo.Bundle.BundleName}";
error = $"Failed to load sub assets : {MainAssetInfo.AssetPath} AssetType : null AssetBundle : {FileLoader.MainBundleInfo.Bundle.BundleName}";
else
error = $"Failed to load sub assets : {MainAssetInfo.AssetPath} AssetType : {MainAssetInfo.AssetType} AssetBundle : {OwnerBundle.MainBundleInfo.Bundle.BundleName}";
error = $"Failed to load sub assets : {MainAssetInfo.AssetPath} AssetType : {MainAssetInfo.AssetType} AssetBundle : {FileLoader.MainBundleInfo.Bundle.BundleName}";
YooLogger.Error(error);
InvokeCompletion(error, EOperationStatus.Failed);
}
@@ -43,15 +43,15 @@ namespace YooAsset
{
if (IsWaitForAsyncComplete)
{
OwnerBundle.WaitForAsyncComplete();
FileLoader.WaitForAsyncComplete();
}
if (OwnerBundle.IsDone() == false)
if (FileLoader.IsDone() == false)
return;
if (OwnerBundle.Status != BundleLoaderBase.EStatus.Succeed)
if (FileLoader.Status != BundleFileLoader.EStatus.Succeed)
{
string error = OwnerBundle.LastError;
string error = FileLoader.LastError;
InvokeCompletion(error, EOperationStatus.Failed);
return;
}
@@ -65,7 +65,7 @@ namespace YooAsset
if (MainAssetInfo.AssetType == null)
{
List<UnityEngine.Object> result = new List<Object>();
foreach (var assetPath in OwnerBundle.MainBundleInfo.IncludeAssetsInEditor)
foreach (var assetPath in FileLoader.MainBundleInfo.IncludeAssetsInEditor)
{
UnityEngine.Object mainAsset = UnityEditor.AssetDatabase.LoadMainAssetAtPath(assetPath);
if (mainAsset != null)
@@ -76,7 +76,7 @@ namespace YooAsset
else
{
List<UnityEngine.Object> result = new List<Object>();
foreach (var assetPath in OwnerBundle.MainBundleInfo.IncludeAssetsInEditor)
foreach (var assetPath in FileLoader.MainBundleInfo.IncludeAssetsInEditor)
{
UnityEngine.Object mainAsset = UnityEditor.AssetDatabase.LoadAssetAtPath(assetPath, MainAssetInfo.AssetType);
if (mainAsset != null)
@@ -43,15 +43,15 @@ namespace YooAsset
{
if (IsWaitForAsyncComplete)
{
OwnerBundle.WaitForAsyncComplete();
FileLoader.WaitForAsyncComplete();
}
if (OwnerBundle.IsDone() == false)
if (FileLoader.IsDone() == false)
return;
if (OwnerBundle.Status != BundleLoaderBase.EStatus.Succeed)
if (FileLoader.Status != BundleFileLoader.EStatus.Succeed)
{
string error = OwnerBundle.LastError;
string error = FileLoader.LastError;
InvokeCompletion(error, EOperationStatus.Failed);
return;
}
@@ -40,15 +40,15 @@ namespace YooAsset
{
if (IsWaitForAsyncComplete)
{
OwnerBundle.WaitForAsyncComplete();
FileLoader.WaitForAsyncComplete();
}
if (OwnerBundle.IsDone() == false)
if (FileLoader.IsDone() == false)
return;
if (OwnerBundle.Status != BundleLoaderBase.EStatus.Succeed)
if (FileLoader.Status != BundleFileLoader.EStatus.Succeed)
{
string error = OwnerBundle.LastError;
string error = FileLoader.LastError;
InvokeCompletion(error, EOperationStatus.Failed);
return;
}
@@ -38,15 +38,15 @@ namespace YooAsset
{
if (IsWaitForAsyncComplete)
{
OwnerBundle.WaitForAsyncComplete();
FileLoader.WaitForAsyncComplete();
}
if (OwnerBundle.IsDone() == false)
if (FileLoader.IsDone() == false)
return;
if (OwnerBundle.Status != BundleLoaderBase.EStatus.Succeed)
if (FileLoader.Status != BundleFileLoader.EStatus.Succeed)
{
string error = OwnerBundle.LastError;
string error = FileLoader.LastError;
InvokeCompletion(error, EOperationStatus.Failed);
return;
}
@@ -57,7 +57,7 @@ namespace YooAsset
// 2. 加载资源对象
if (_steps == ESteps.Loading)
{
if (IsWaitForAsyncComplete || IsForceDestroyComplete)
if (IsWaitForAsyncComplete)
{
LoadSceneParameters loadSceneParameters = new LoadSceneParameters(SceneMode);
SceneObject = UnityEditor.SceneManagement.EditorSceneManager.LoadSceneInPlayMode(MainAssetInfo.AssetPath, loadSceneParameters);
@@ -88,7 +88,7 @@ namespace YooAsset
{
if (_asyncOperation != null)
{
if (IsWaitForAsyncComplete || IsForceDestroyComplete)
if (IsWaitForAsyncComplete)
{
// 场景加载无法强制异步转同步
YooLogger.Error("The scene is loading asyn !");
@@ -43,15 +43,15 @@ namespace YooAsset
{
if (IsWaitForAsyncComplete)
{
OwnerBundle.WaitForAsyncComplete();
FileLoader.WaitForAsyncComplete();
}
if (OwnerBundle.IsDone() == false)
if (FileLoader.IsDone() == false)
return;
if (OwnerBundle.Status != BundleLoaderBase.EStatus.Succeed)
if (FileLoader.Status != BundleFileLoader.EStatus.Succeed)
{
string error = OwnerBundle.LastError;
string error = FileLoader.LastError;
InvokeCompletion(error, EOperationStatus.Failed);
return;
}
@@ -1,7 +1,6 @@
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;
using System;
namespace YooAsset
@@ -69,10 +68,9 @@ namespace YooAsset
protected ESteps _steps = ESteps.None;
protected BundleLoaderBase OwnerBundle { private set; get; }
protected DependAssetBundles DependBundles { private set; get; }
protected BundleFileLoader FileLoader { private set; get; }
protected DependFileLoaders DependLoaders { private set; get; }
protected bool IsWaitForAsyncComplete { private set; get; } = false;
protected bool IsForceDestroyComplete { private set; get; } = false;
private readonly List<HandleBase> _handles = new List<HandleBase>();
@@ -85,13 +83,30 @@ namespace YooAsset
// 创建资源包加载器
if (manager != null)
{
OwnerBundle = manager.CreateOwnerAssetBundleLoader(assetInfo);
OwnerBundle.Reference();
OwnerBundle.AddProvider(this);
FileLoader = manager.CreateOwnerFileLoader(assetInfo);
FileLoader.Reference();
FileLoader.AddProvider(this);
var dependList = manager.CreateDependAssetBundleLoaders(assetInfo);
DependBundles = new DependAssetBundles(dependList);
DependBundles.Reference();
var dependList = manager.CreateDependFileLoaders(assetInfo);
DependLoaders = new DependFileLoaders(dependList);
DependLoaders.Reference();
}
}
/// <summary>
/// 等待异步执行完毕
/// </summary>
public override void WaitForAsyncComplete()
{
IsWaitForAsyncComplete = true;
// 注意:主动轮询更新完成同步加载
InternalOnUpdate();
// 验证结果
if (IsDone == false)
{
YooLogger.Warning($"{nameof(WaitForAsyncComplete)} failed to loading : {MainAssetInfo.AssetPath}");
}
}
@@ -110,15 +125,15 @@ namespace YooAsset
}
// 释放资源包加载器
if (OwnerBundle != null)
if (FileLoader != null)
{
OwnerBundle.Release();
OwnerBundle = null;
FileLoader.Release();
FileLoader = null;
}
if (DependBundles != null)
if (DependLoaders != null)
{
DependBundles.Release();
DependBundles = null;
DependLoaders.Release();
DependLoaders = null;
}
}
@@ -188,43 +203,14 @@ namespace YooAsset
}
/// <summary>
/// 等待异步执行完毕
/// 处理致命问题
/// </summary>
public void WaitForAsyncComplete()
protected void ProcessFatalEvent()
{
IsWaitForAsyncComplete = true;
// 注意:主动轮询更新完成同步加载
InternalOnUpdate();
// 验证结果
if (IsDone == false)
{
YooLogger.Warning($"{nameof(WaitForAsyncComplete)} failed to loading : {MainAssetInfo.AssetPath}");
}
}
/// <summary>
/// 强制销毁资源提供者
/// </summary>
public void ForceDestroyComplete()
{
IsForceDestroyComplete = true;
// 注意:主动轮询更新完成同步加载
// 说明:如果资源包未准备完毕也可以放心销毁。
InternalOnUpdate();
}
/// <summary>
/// 处理特殊异常
/// </summary>
protected void ProcessCacheBundleException()
{
if (OwnerBundle.IsDestroyed)
if (FileLoader.IsDestroyed)
throw new System.Exception("Should never get here !");
string error = $"The bundle {OwnerBundle.MainBundleInfo.Bundle.BundleName} has been destroyed by unity bugs !";
string error = $"The bundle {FileLoader.MainBundleInfo.Bundle.BundleName} has been destroyed by unity bugs !";
YooLogger.Error(error);
InvokeCompletion(Error, EOperationStatus.Failed);
}
@@ -252,6 +238,28 @@ namespace YooAsset
}
}
/// <summary>
/// 获取下载报告
/// </summary>
public DownloadStatus GetDownloadStatus()
{
DownloadStatus status = new DownloadStatus();
status.TotalBytes = FileLoader.MainBundleInfo.Bundle.FileSize;
status.DownloadedBytes = FileLoader.DownloadedBytes;
foreach (var dependBundle in DependLoaders.DependList)
{
status.TotalBytes += dependBundle.MainBundleInfo.Bundle.FileSize;
status.DownloadedBytes += dependBundle.DownloadedBytes;
}
if (status.TotalBytes == 0)
throw new System.Exception("Should never get here !");
status.IsDone = status.DownloadedBytes == status.TotalBytes;
status.Progress = (float)status.DownloadedBytes / status.TotalBytes;
return status;
}
#region 调试信息相关
/// <summary>
/// 出生的场景
@@ -304,40 +312,18 @@ namespace YooAsset
}
}
/// <summary>
/// 获取下载报告
/// </summary>
internal DownloadStatus GetDownloadStatus()
{
DownloadStatus status = new DownloadStatus();
status.TotalBytes = (ulong)OwnerBundle.MainBundleInfo.Bundle.FileSize;
status.DownloadedBytes = OwnerBundle.DownloadedBytes;
foreach (var dependBundle in DependBundles.DependList)
{
status.TotalBytes += (ulong)dependBundle.MainBundleInfo.Bundle.FileSize;
status.DownloadedBytes += dependBundle.DownloadedBytes;
}
if (status.TotalBytes == 0)
throw new System.Exception("Should never get here !");
status.IsDone = status.DownloadedBytes == status.TotalBytes;
status.Progress = (float)status.DownloadedBytes / status.TotalBytes;
return status;
}
/// <summary>
/// 获取资源包的调试信息列表
/// </summary>
internal void GetBundleDebugInfos(List<DebugBundleInfo> output)
{
var bundleInfo = new DebugBundleInfo();
bundleInfo.BundleName = OwnerBundle.MainBundleInfo.Bundle.BundleName;
bundleInfo.RefCount = OwnerBundle.RefCount;
bundleInfo.Status = OwnerBundle.Status.ToString();
bundleInfo.BundleName = FileLoader.MainBundleInfo.Bundle.BundleName;
bundleInfo.RefCount = FileLoader.RefCount;
bundleInfo.Status = FileLoader.Status.ToString();
output.Add(bundleInfo);
DependBundles.GetBundleDebugInfos(output);
DependLoaders.GetBundleDebugInfos(output);
}
#endregion
}
@@ -1,103 +0,0 @@
using System.IO;
using UnityEngine;
namespace YooAsset
{
internal class ResourceLoader
{
private IDecryptionServices _decryption;
private IDeliveryLoadServices _delivery;
public void Init(IDecryptionServices decryption, IDeliveryLoadServices delivery)
{
_decryption = decryption;
_delivery = delivery;
}
/// <summary>
/// 同步加载资源包对象
/// </summary>
public AssetBundle LoadAssetBundle(BundleInfo bundleInfo, string fileLoadPath, out Stream managedStream)
{
managedStream = null;
if (bundleInfo.Bundle.Encrypted)
{
if (_decryption == null)
{
YooLogger.Error($"{nameof(IDecryptionServices)} is null ! when load asset bundle {bundleInfo.Bundle.BundleName}!");
return null;
}
DecryptFileInfo fileInfo = new DecryptFileInfo();
fileInfo.BundleName = bundleInfo.Bundle.BundleName;
fileInfo.FileLoadPath = fileLoadPath;
fileInfo.ConentCRC = bundleInfo.Bundle.UnityCRC;
return _decryption.LoadAssetBundle(fileInfo, out managedStream);
}
else
{
return AssetBundle.LoadFromFile(fileLoadPath);
}
}
/// <summary>
/// 异步加载资源包对象
/// </summary>
public AssetBundleCreateRequest LoadAssetBundleAsync(BundleInfo bundleInfo, string fileLoadPath, out Stream managedStream)
{
managedStream = null;
if (bundleInfo.Bundle.Encrypted)
{
if (_decryption == null)
{
YooLogger.Error($"{nameof(IDecryptionServices)} is null ! when load asset bundle {bundleInfo.Bundle.BundleName}!");
return null;
}
DecryptFileInfo fileInfo = new DecryptFileInfo();
fileInfo.BundleName = bundleInfo.Bundle.BundleName;
fileInfo.FileLoadPath = fileLoadPath;
fileInfo.ConentCRC = bundleInfo.Bundle.UnityCRC;
return _decryption.LoadAssetBundleAsync(fileInfo, out managedStream);
}
else
{
return AssetBundle.LoadFromFileAsync(fileLoadPath);
}
}
/// <summary>
/// 同步加载分发的资源包对象
/// </summary>
public AssetBundle LoadDeliveryAssetBundle(BundleInfo bundleInfo, string fileLoadPath)
{
if (_delivery == null)
throw new System.Exception("Should never get here !");
// 注意:对于已经加密的资源包,需要开发者自行解密。
DeliveryFileInfo fileInfo = new DeliveryFileInfo();
fileInfo.BundleName = bundleInfo.Bundle.BundleName;
fileInfo.FileLoadPath = fileLoadPath;
fileInfo.ConentCRC = bundleInfo.Bundle.UnityCRC;
fileInfo.Encrypted = bundleInfo.Bundle.Encrypted;
return _delivery.LoadAssetBundle(fileInfo);
}
/// <summary>
/// 异步加载分发的资源包对象
/// </summary>
public AssetBundleCreateRequest LoadDeliveryAssetBundleAsync(BundleInfo bundleInfo, string fileLoadPath)
{
if (_delivery == null)
throw new System.Exception("Should never get here !");
// 注意:对于已经加密的资源包,需要开发者自行解密。
DeliveryFileInfo fileInfo = new DeliveryFileInfo();
fileInfo.BundleName = bundleInfo.Bundle.BundleName;
fileInfo.FileLoadPath = fileLoadPath;
fileInfo.ConentCRC = bundleInfo.Bundle.UnityCRC;
fileInfo.Encrypted = bundleInfo.Bundle.Encrypted;
return _delivery.LoadAssetBundleAsync(fileInfo);
}
}
}
@@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 3818e5adef4eaea4a85b112f953c4f7b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -13,9 +13,9 @@ namespace YooAsset
private readonly static Dictionary<string, SceneHandle> _sceneHandles = new Dictionary<string, SceneHandle>(100);
private static long _sceneCreateCount = 0;
private readonly Dictionary<string, ProviderBase> _providerDic = new Dictionary<string, ProviderBase>(5000);
private readonly Dictionary<string, BundleLoaderBase> _loaderDic = new Dictionary<string, BundleLoaderBase>(5000);
private readonly List<BundleLoaderBase> _loaderList = new List<BundleLoaderBase>(5000);
internal readonly Dictionary<string, ProviderBase> _providerDic = new Dictionary<string, ProviderBase>(5000);
internal readonly Dictionary<string, BundleFileLoader> _loaderDic = new Dictionary<string, BundleFileLoader>(5000);
internal readonly List<BundleFileLoader> _loaderList = new List<BundleFileLoader>(5000);
private bool _simulationOnEditor;
private bool _autoDestroyAssetProvider;
@@ -35,10 +35,10 @@ namespace YooAsset
/// <summary>
/// 初始化
/// </summary>
public void Initialize(bool simulationOnEditor, bool autoDestroyAssetProvider, IBundleQuery bundleServices)
public void Initialize(InitializeParameters initializeParameters, IBundleQuery bundleServices)
{
_simulationOnEditor = simulationOnEditor;
_autoDestroyAssetProvider = autoDestroyAssetProvider;
_simulationOnEditor = initializeParameters is EditorSimulateModeParameters;
_autoDestroyAssetProvider = initializeParameters.AutoDestroyAssetProvider;
_bundleQuery = bundleServices;
}
@@ -56,30 +56,6 @@ namespace YooAsset
}
}
/// <summary>
/// 资源回收(卸载引用计数为零的资源)
/// </summary>
public void UnloadUnusedAssets()
{
for (int i = _loaderList.Count - 1; i >= 0; i--)
{
BundleLoaderBase loader = _loaderList[i];
loader.TryDestroyProviders();
}
for (int i = _loaderList.Count - 1; i >= 0; i--)
{
BundleLoaderBase loader = _loaderList[i];
if (loader.CanDestroy())
{
string bundleName = loader.MainBundleInfo.Bundle.BundleName;
loader.Destroy();
_loaderList.RemoveAt(i);
_loaderDic.Remove(bundleName);
}
}
}
/// <summary>
/// 尝试卸载指定资源的资源包(包括依赖资源)
/// </summary>
@@ -92,8 +68,8 @@ namespace YooAsset
}
// 卸载主资源包加载器
string manBundleName = _bundleQuery.GetMainBundleName(assetInfo);
var mainLoader = TryGetAssetBundleLoader(manBundleName);
string mainBundleName = _bundleQuery.GetMainBundleName(assetInfo);
var mainLoader = TryGetFileLoader(mainBundleName);
if (mainLoader != null)
{
mainLoader.TryDestroyProviders();
@@ -110,7 +86,7 @@ namespace YooAsset
string[] dependBundleNames = _bundleQuery.GetDependBundleNames(assetInfo);
foreach (var dependBundleName in dependBundleNames)
{
var dependLoader = TryGetAssetBundleLoader(dependBundleName);
var dependLoader = TryGetFileLoader(dependBundleName);
if (dependLoader != null)
{
if (dependLoader.CanDestroy())
@@ -124,57 +100,6 @@ namespace YooAsset
}
}
/// <summary>
/// 强制回收所有资源
/// 注意:加载器在销毁后关联的下载器还会继续下载!
/// </summary>
public void ForceUnloadAllAssets()
{
#if UNITY_WEBGL
throw new Exception($"WebGL not support invoke {nameof(ForceUnloadAllAssets)}");
#else
// 注意:因为场景无法异步转同步,需要等待所有场景加载完毕!
foreach (var sceneHandlePair in _sceneHandles)
{
var sceneHandle = sceneHandlePair.Value;
if (sceneHandle.PackageName == PackageName)
{
if (sceneHandle.IsDone == false)
throw new Exception($"{nameof(ForceUnloadAllAssets)} cannot be called when loading the scene !");
}
}
// 释放所有资源句柄
foreach (var provider in _providerDic.Values)
{
provider.ReleaseAllHandles();
}
// 强制销毁资源提供者
foreach (var provider in _providerDic.Values)
{
provider.ForceDestroyComplete();
provider.Destroy();
}
// 强制销毁资源加载器
foreach (var loader in _loaderList)
{
loader.ForceDestroyComplete();
loader.Destroy();
}
// 清空数据
_providerDic.Clear();
_loaderList.Clear();
_loaderDic.Clear();
ClearSceneHandle();
// 注意:调用底层接口释放所有资源
Resources.UnloadUnusedAssets();
#endif
}
/// <summary>
/// 加载场景对象
/// 注意:返回的场景句柄是唯一的,每个场景句柄对应自己的场景提供者对象。
@@ -336,6 +261,7 @@ namespace YooAsset
return provider.CreateHandle<RawFileHandle>();
}
internal void UnloadSubScene(string sceneName)
{
List<string> removeKeys = new List<string>();
@@ -355,7 +281,7 @@ namespace YooAsset
_sceneHandles.Remove(key);
}
}
private void UnloadAllScene()
internal void UnloadAllScene()
{
// 释放所有场景句柄
foreach (var valuePair in _sceneHandles)
@@ -364,7 +290,7 @@ namespace YooAsset
}
_sceneHandles.Clear();
}
private void ClearSceneHandle()
internal void ClearSceneHandle()
{
// 释放资源包下的所有场景
if (_bundleQuery.ManifestValid())
@@ -385,18 +311,18 @@ namespace YooAsset
}
}
internal BundleLoaderBase CreateOwnerAssetBundleLoader(AssetInfo assetInfo)
internal BundleFileLoader CreateOwnerFileLoader(AssetInfo assetInfo)
{
BundleInfo bundleInfo = _bundleQuery.GetMainBundleInfo(assetInfo);
return CreateAssetBundleLoaderInternal(bundleInfo);
return CreateFileLoaderInternal(bundleInfo);
}
internal List<BundleLoaderBase> CreateDependAssetBundleLoaders(AssetInfo assetInfo)
internal List<BundleFileLoader> CreateDependFileLoaders(AssetInfo assetInfo)
{
BundleInfo[] depends = _bundleQuery.GetDependBundleInfos(assetInfo);
List<BundleLoaderBase> result = new List<BundleLoaderBase>(depends.Length);
List<BundleFileLoader> result = new List<BundleFileLoader>(depends.Length);
foreach (var bundleInfo in depends)
{
BundleLoaderBase dependLoader = CreateAssetBundleLoaderInternal(bundleInfo);
BundleFileLoader dependLoader = CreateFileLoaderInternal(bundleInfo);
result.Add(dependLoader);
}
return result;
@@ -413,41 +339,23 @@ namespace YooAsset
return _loaderList.Count > 0;
}
private BundleLoaderBase CreateAssetBundleLoaderInternal(BundleInfo bundleInfo)
private BundleFileLoader CreateFileLoaderInternal(BundleInfo bundleInfo)
{
// 如果加载器已经存在
string bundleName = bundleInfo.Bundle.BundleName;
BundleLoaderBase loader = TryGetAssetBundleLoader(bundleName);
BundleFileLoader loader = TryGetFileLoader(bundleName);
if (loader != null)
return loader;
// 新增下载需求
if (_simulationOnEditor)
{
loader = new VirtualBundleFileLoader(this, bundleInfo);
}
else
{
#if UNITY_WEBGL
if (bundleInfo.Bundle.Buildpipeline== EDefaultBuildPipeline.RawFileBuildPipeline.ToString())
loader = new RawBundleWebLoader(this, bundleInfo);
else
loader = new AssetBundleWebLoader(this, bundleInfo);
#else
if (bundleInfo.Bundle.Buildpipeline == EDefaultBuildPipeline.RawFileBuildPipeline.ToString())
loader = new RawBundleFileLoader(this, bundleInfo);
else
loader = new AssetBundleFileLoader(this, bundleInfo);
#endif
}
loader = new BundleFileLoader(this, bundleInfo);
_loaderList.Add(loader);
_loaderDic.Add(bundleName, loader);
return loader;
}
private BundleLoaderBase TryGetAssetBundleLoader(string bundleName)
private BundleFileLoader TryGetFileLoader(string bundleName)
{
if (_loaderDic.TryGetValue(bundleName, out BundleLoaderBase value))
if (_loaderDic.TryGetValue(bundleName, out BundleFileLoader value))
return value;
else
return null;