Files
YooAsset/Assets/YooAsset/Runtime/FileSystem/DefaultCacheFileSystem/Operation/DCFSLoadBundleOperation.cs

418 lines
16 KiB
C#
Raw Normal View History

2025-03-14 14:32:39 +08:00
using System;
using System.IO;
using UnityEngine;
namespace YooAsset
{
internal class DCFSLoadAssetBundleOperation : FSLoadBundleOperation
{
2024-07-07 00:52:17 +08:00
protected enum ESteps
{
None,
2024-07-07 00:52:17 +08:00
CheckExist,
DownloadFile,
2025-10-30 18:31:06 +08:00
AbortDownload,
LoadAssetBundle,
CheckResult,
Done,
}
2024-07-07 00:52:17 +08:00
protected readonly DefaultCacheFileSystem _fileSystem;
protected readonly PackageBundle _bundle;
protected FSDownloadFileOperation _downloadFileOp;
protected AssetBundleCreateRequest _createRequest;
private AssetBundle _assetBundle;
private Stream _managedStream;
2024-07-07 00:52:17 +08:00
protected ESteps _steps = ESteps.None;
internal DCFSLoadAssetBundleOperation(DefaultCacheFileSystem fileSystem, PackageBundle bundle)
{
_fileSystem = fileSystem;
_bundle = bundle;
}
2025-02-22 16:29:25 +08:00
internal override void InternalStart()
{
2024-07-07 00:52:17 +08:00
_steps = ESteps.CheckExist;
}
2025-02-22 16:29:25 +08:00
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
2024-07-07 00:52:17 +08:00
if (_steps == ESteps.CheckExist)
{
if (_fileSystem.Exists(_bundle))
{
DownloadProgress = 1f;
DownloadedBytes = _bundle.FileSize;
_steps = ESteps.LoadAssetBundle;
}
else
{
if (_fileSystem.DisableOnDemandDownload)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"The bundle not cached : {_bundle.BundleName}";
YooLogger.Warning(Error);
}
else
{
_steps = ESteps.DownloadFile;
}
2024-07-07 00:52:17 +08:00
}
}
2025-10-30 18:31:06 +08:00
if (_steps == ESteps.DownloadFile)
{
// 中断下载
if (AbortDownloadFile)
{
if (_downloadFileOp != null)
_downloadFileOp.AbortOperation();
_steps = ESteps.AbortDownload;
}
}
if (_steps == ESteps.DownloadFile)
{
if (_downloadFileOp == null)
{
2025-07-17 20:59:15 +08:00
DownloadFileOptions options = new DownloadFileOptions(int.MaxValue);
_downloadFileOp = _fileSystem.DownloadFileAsync(_bundle, options);
2025-02-26 19:31:06 +08:00
_downloadFileOp.StartOperation();
AddChildOperation(_downloadFileOp);
}
2024-12-10 16:48:08 +08:00
if (IsWaitForAsyncComplete)
_downloadFileOp.WaitForAsyncComplete();
2025-02-26 19:31:06 +08:00
_downloadFileOp.UpdateOperation();
DownloadProgress = _downloadFileOp.DownloadProgress;
DownloadedBytes = _downloadFileOp.DownloadedBytes;
if (_downloadFileOp.IsDone == false)
return;
if (_downloadFileOp.Status == EOperationStatus.Succeed)
{
_steps = ESteps.LoadAssetBundle;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
2024-07-07 00:52:17 +08:00
Error = _downloadFileOp.Error;
}
}
2025-10-30 18:31:06 +08:00
if (_steps == ESteps.AbortDownload)
{
if (_downloadFileOp != null)
{
if (IsWaitForAsyncComplete)
_downloadFileOp.WaitForAsyncComplete();
_downloadFileOp.UpdateOperation();
if (_downloadFileOp.IsDone == false)
return;
}
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = "Abort download file !";
}
if (_steps == ESteps.LoadAssetBundle)
{
if (_bundle.Encrypted)
{
if (_fileSystem.DecryptionServices == null)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"The {nameof(IDecryptionServices)} is null !";
YooLogger.Error(Error);
return;
}
}
2024-10-17 10:51:17 +08:00
if (IsWaitForAsyncComplete)
{
if (_bundle.Encrypted)
{
var decryptResult = _fileSystem.LoadEncryptedAssetBundle(_bundle);
_assetBundle = decryptResult.Result;
_managedStream = decryptResult.ManagedStream;
}
else
{
string filePath = _fileSystem.GetCacheBundleFileLoadPath(_bundle);
_assetBundle = AssetBundle.LoadFromFile(filePath);
}
}
else
{
if (_bundle.Encrypted)
{
var decryptResult = _fileSystem.LoadEncryptedAssetBundleAsync(_bundle);
_createRequest = decryptResult.CreateRequest;
_managedStream = decryptResult.ManagedStream;
}
else
{
string filePath = _fileSystem.GetCacheBundleFileLoadPath(_bundle);
_createRequest = AssetBundle.LoadFromFileAsync(filePath);
}
}
2024-07-27 15:25:21 +08:00
_steps = ESteps.CheckResult;
}
if (_steps == ESteps.CheckResult)
{
if (_createRequest != null)
{
2024-10-17 10:51:17 +08:00
if (IsWaitForAsyncComplete)
{
// 强制挂起主线程(注意:该操作会很耗时)
YooLogger.Warning("Suspend the main thread to load unity bundle.");
_assetBundle = _createRequest.assetBundle;
}
else
{
if (_createRequest.isDone == false)
return;
_assetBundle = _createRequest.assetBundle;
}
}
if (_assetBundle != null)
{
_steps = ESteps.Done;
Result = new AssetBundleResult(_fileSystem, _bundle, _assetBundle, _managedStream);
2024-07-07 00:52:17 +08:00
Status = EOperationStatus.Succeed;
return;
}
// 注意当缓存文件的校验等级为Low的时候并不能保证缓存文件的完整性。
// 说明在AssetBundle文件加载失败的情况下我们需要重新验证文件的完整性
EFileVerifyResult verifyResult = _fileSystem.VerifyCacheFile(_bundle);
if (verifyResult == EFileVerifyResult.Succeed)
{
if (_bundle.Encrypted)
{
2025-06-17 17:07:02 +08:00
var decryptResult = _fileSystem.LoadEncryptedAssetBundleFallback(_bundle);
_assetBundle = decryptResult.Result;
if (_assetBundle != null)
{
_steps = ESteps.Done;
Result = new AssetBundleResult(_fileSystem, _bundle, _assetBundle, _managedStream);
Status = EOperationStatus.Succeed;
return;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Failed to load encrypted asset bundle file : {_bundle.BundleName}";
YooLogger.Error(Error);
return;
}
}
// 注意:在安卓移动平台,华为和三星真机上有极小概率加载资源包失败。
// 说明:大多数情况在首次安装下载资源到沙盒内,游戏过程中切换到后台再回到游戏内有很大概率触发!
string filePath = _fileSystem.GetCacheBundleFileLoadPath(_bundle);
byte[] fileData = FileUtility.ReadAllBytes(filePath);
if (fileData != null && fileData.Length > 0)
{
_assetBundle = AssetBundle.LoadFromMemory(fileData);
if (_assetBundle == null)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Failed to load asset bundle from memory : {_bundle.BundleName}";
YooLogger.Error(Error);
}
else
{
_steps = ESteps.Done;
Result = new AssetBundleResult(_fileSystem, _bundle, _assetBundle, null);
Status = EOperationStatus.Succeed;
}
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Failed to read asset bundle file bytes : {_bundle.BundleName}";
YooLogger.Error(Error);
}
}
else
{
_steps = ESteps.Done;
_fileSystem.DeleteCacheBundleFile(_bundle.BundleGUID);
Status = EOperationStatus.Failed;
Error = $"Find corrupted asset bundle file and delete : {_bundle.BundleName}";
YooLogger.Error(Error);
}
}
}
2024-07-07 16:01:55 +08:00
internal override void InternalWaitForAsyncComplete()
{
2026-01-12 11:09:27 +08:00
RunBatchExecution();
}
}
internal class DCFSLoadRawBundleOperation : FSLoadBundleOperation
{
2024-07-07 00:52:17 +08:00
protected enum ESteps
{
None,
2024-07-07 00:52:17 +08:00
CheckExist,
DownloadFile,
2025-10-30 18:31:06 +08:00
AbortDownload,
LoadCacheRawBundle,
Done,
}
2024-07-07 00:52:17 +08:00
protected readonly DefaultCacheFileSystem _fileSystem;
protected readonly PackageBundle _bundle;
protected FSDownloadFileOperation _downloadFileOp;
protected ESteps _steps = ESteps.None;
internal DCFSLoadRawBundleOperation(DefaultCacheFileSystem fileSystem, PackageBundle bundle)
{
_fileSystem = fileSystem;
_bundle = bundle;
}
2025-02-22 16:29:25 +08:00
internal override void InternalStart()
{
2024-07-07 00:52:17 +08:00
_steps = ESteps.CheckExist;
}
2025-02-22 16:29:25 +08:00
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
2024-07-07 00:52:17 +08:00
if (_steps == ESteps.CheckExist)
{
if (_fileSystem.Exists(_bundle))
{
2025-03-14 14:32:39 +08:00
// 注意:缓存的原生文件的格式,可能会在业务端根据需求发生变动!
// 注意:这里需要校验文件格式,如果不一致对本地文件进行修正!
string filePath = _fileSystem.GetCacheBundleFileLoadPath(_bundle);
if (File.Exists(filePath) == false)
{
try
{
var recordFileElement = _fileSystem.GetRecordFileElement(_bundle);
File.Move(recordFileElement.DataFilePath, filePath);
_steps = ESteps.LoadCacheRawBundle;
}
catch (Exception ex)
2025-03-14 14:32:39 +08:00
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Faild rename raw data file : {ex.Message}";
2025-03-14 14:32:39 +08:00
}
}
else
{
DownloadProgress = 1f;
DownloadedBytes = _bundle.FileSize;
_steps = ESteps.LoadCacheRawBundle;
}
2024-07-07 00:52:17 +08:00
}
else
{
_steps = ESteps.DownloadFile;
}
}
2025-10-30 18:31:06 +08:00
if (_steps == ESteps.DownloadFile)
{
// 中断下载
if (AbortDownloadFile)
{
if (_downloadFileOp != null)
_downloadFileOp.AbortOperation();
_steps = ESteps.AbortDownload;
}
}
if (_steps == ESteps.DownloadFile)
{
if (_downloadFileOp == null)
{
2025-07-17 20:59:15 +08:00
DownloadFileOptions options = new DownloadFileOptions(int.MaxValue);
_downloadFileOp = _fileSystem.DownloadFileAsync(_bundle, options);
2025-02-26 19:31:06 +08:00
_downloadFileOp.StartOperation();
AddChildOperation(_downloadFileOp);
}
2024-12-10 16:48:08 +08:00
if (IsWaitForAsyncComplete)
_downloadFileOp.WaitForAsyncComplete();
2025-02-26 19:31:06 +08:00
_downloadFileOp.UpdateOperation();
DownloadProgress = _downloadFileOp.DownloadProgress;
DownloadedBytes = _downloadFileOp.DownloadedBytes;
if (_downloadFileOp.IsDone == false)
return;
if (_downloadFileOp.Status == EOperationStatus.Succeed)
{
_steps = ESteps.LoadCacheRawBundle;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
2024-07-07 00:52:17 +08:00
Error = _downloadFileOp.Error;
}
}
2025-10-30 18:31:06 +08:00
if (_steps == ESteps.AbortDownload)
{
if (_downloadFileOp != null)
{
if (IsWaitForAsyncComplete)
_downloadFileOp.WaitForAsyncComplete();
_downloadFileOp.UpdateOperation();
if (_downloadFileOp.IsDone == false)
return;
}
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = "Abort download file !";
}
if (_steps == ESteps.LoadCacheRawBundle)
{
string filePath = _fileSystem.GetCacheBundleFileLoadPath(_bundle);
if (File.Exists(filePath))
{
_steps = ESteps.Done;
Result = new RawBundleResult(_fileSystem, _bundle);
Status = EOperationStatus.Succeed;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Can not found cache raw bundle file : {filePath}";
YooLogger.Error(Error);
}
}
}
2024-07-07 16:01:55 +08:00
internal override void InternalWaitForAsyncComplete()
{
2026-01-12 11:09:27 +08:00
RunBatchExecution();
}
}
}