refactor : 重构代码

This commit is contained in:
何冠峰
2026-01-22 21:54:00 +08:00
parent 9f820fcbb3
commit 43fef103ee
67 changed files with 1780 additions and 1286 deletions

View File

@@ -36,14 +36,6 @@ namespace YooAsset
{
return _fileSystem.GetBundleFilePath(_packageBundle);
}
public override byte[] ReadBundleFileData()
{
return _fileSystem.ReadBundleFileData(_packageBundle);
}
public override string ReadBundleFileText()
{
return _fileSystem.ReadBundleFileText(_packageBundle);
}
public override FSLoadAssetOperation LoadAssetAsync(AssetInfo assetInfo)
{

View File

@@ -93,11 +93,11 @@ namespace YooAsset
error = $"Failed to load asset : {_assetInfo.AssetPath} AssetType : null AssetBundle : {_packageBundle.BundleName}";
else
error = $"Failed to load asset : {_assetInfo.AssetPath} AssetType : {_assetInfo.AssetType} AssetBundle : {_packageBundle.BundleName}";
YooLogger.Error(error);
_steps = ESteps.Done;
Error = error;
Status = EOperationStatus.Failed;
Error = error;
YooLogger.Error(Error);
}
else
{

View File

@@ -0,0 +1,408 @@
using System;
using System.IO;
using UnityEngine;
namespace YooAsset
{
/// <summary>
/// 默认的 AssetBundle 加载操作(非加密)
/// 通用实现,适用于 BuiltinFileSystem 和 CacheFileSystem
/// </summary>
public class DefaultLoadAssetBundleOperation : LoadAssetBundleOperation
{
private enum ESteps
{
None,
LoadAssetBundle,
CheckResult,
Done,
}
private AssetBundleCreateRequest _createRequest;
private ESteps _steps = ESteps.None;
public DefaultLoadAssetBundleOperation(LoadAssetBundleOptions opionts) : base(opionts) { }
internal override void InternalStart()
{
_steps = ESteps.LoadAssetBundle;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.LoadAssetBundle)
{
if (IsWaitingForAsyncComplete)
Result = AssetBundle.LoadFromFile(_options.FileLoadPath);
else
_createRequest = AssetBundle.LoadFromFileAsync(_options.FileLoadPath);
_steps = ESteps.CheckResult;
}
if (_steps == ESteps.CheckResult)
{
if (_createRequest != null)
{
if (IsWaitingForAsyncComplete)
{
// 强制挂起主线程(注意:该操作会很耗时)
YooLogger.Warning("Suspend the main thread to load unity bundle.");
Result = _createRequest.assetBundle;
}
else
{
if (_createRequest.isDone == false)
return;
Result = _createRequest.assetBundle;
}
}
if (Result == null)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Failed to load asset bundle file : {_options.Bundle.BundleName}";
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}
}
}
internal override void InternalWaitForAsyncComplete()
{
RunBatchExecution();
}
public override AssetBundle LoadFromMemory()
{
byte[] fileData = FileUtility.ReadAllBytes(_options.FileLoadPath);
if (fileData == null || fileData.Length == 0)
return null;
return AssetBundle.LoadFromMemory(fileData);
}
}
/// <summary>
/// 默认的 AssetBundle 加载操作(加密)
/// 通用实现,适用于 BuiltinFileSystem 和 CacheFileSystem
/// </summary>
public abstract class DefaultLoadAssetBundleFromOffsetOperation : LoadAssetBundleOperation
{
private enum ESteps
{
None,
LoadAssetBundle,
CheckResult,
Done,
}
private AssetBundleCreateRequest _createRequest;
private ESteps _steps = ESteps.None;
public DefaultLoadAssetBundleFromOffsetOperation(LoadAssetBundleOptions options) : base(options) { }
internal override void InternalStart()
{
_steps = ESteps.LoadAssetBundle;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.LoadAssetBundle)
{
ulong offset = GetFileOffset();
if (IsWaitingForAsyncComplete)
Result = AssetBundle.LoadFromFile(_options.FileLoadPath, 0, offset);
else
_createRequest = AssetBundle.LoadFromFileAsync(_options.FileLoadPath, 0, offset);
_steps = ESteps.CheckResult;
}
if (_steps == ESteps.CheckResult)
{
if (_createRequest != null)
{
if (IsWaitingForAsyncComplete)
{
// 强制挂起主线程(注意:该操作会很耗时)
YooLogger.Warning("Suspend the main thread to load unity bundle.");
Result = _createRequest.assetBundle;
}
else
{
if (_createRequest.isDone == false)
return;
Result = _createRequest.assetBundle;
}
}
if (Result == null)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Failed to load asset bundle file : {_options.Bundle.BundleName}";
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}
}
}
internal override void InternalWaitForAsyncComplete()
{
RunBatchExecution();
}
/// <summary>
/// 获取偏移值
/// </summary>
protected abstract uint GetFileOffset();
public override AssetBundle LoadFromMemory()
{
int offset = (int)GetFileOffset();
byte[] fileData = File.ReadAllBytes(_options.FileLoadPath);
if (fileData == null || fileData.Length <= offset)
return null;
// 跳过偏移量
byte[] bundleData = new byte[fileData.Length - offset];
Buffer.BlockCopy(fileData, offset, bundleData, 0, bundleData.Length);
return AssetBundle.LoadFromMemory(bundleData);
}
}
/// <summary>
/// 默认的 AssetBundle 加载操作(加密)
/// 通用实现,适用于 CacheFileSystem
/// </summary>
public abstract class DefaultLoadAssetBundleFromMemoryOperation : LoadAssetBundleOperation
{
private enum ESteps
{
None,
CheckPlatform,
LoadAssetBundle,
CheckResult,
Done,
}
private AssetBundleCreateRequest _createRequest;
private ESteps _steps = ESteps.None;
public DefaultLoadAssetBundleFromMemoryOperation(LoadAssetBundleOptions options) : base(options) { }
internal override void InternalStart()
{
_steps = ESteps.CheckPlatform;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.CheckPlatform)
{
#if UNITY_ANDROID
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Android platform not support read builtin file.";
#else
_steps = ESteps.LoadAssetBundle;
#endif
}
if (_steps == ESteps.LoadAssetBundle)
{
byte[] fileData = File.ReadAllBytes(_options.FileLoadPath);
byte[] rawData = DecryptData(fileData);
if (rawData == null || rawData.Length == 0)
{
_steps = ESteps.None;
Status = EOperationStatus.Failed;
Error = "Decrypted raw data is null or empty.";
return;
}
if (IsWaitingForAsyncComplete)
Result = AssetBundle.LoadFromMemory(rawData);
else
_createRequest = AssetBundle.LoadFromMemoryAsync(rawData);
_steps = ESteps.CheckResult;
}
if (_steps == ESteps.CheckResult)
{
if (_createRequest != null)
{
if (IsWaitingForAsyncComplete)
{
// 强制挂起主线程(注意:该操作会很耗时)
YooLogger.Warning("Suspend the main thread to load unity bundle.");
Result = _createRequest.assetBundle;
}
else
{
if (_createRequest.isDone == false)
return;
Result = _createRequest.assetBundle;
}
}
if (Result == null)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Failed to load asset bundle file : {_options.Bundle.BundleName}";
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}
}
}
internal override void InternalWaitForAsyncComplete()
{
RunBatchExecution();
}
/// <summary>
/// 文件数据解密
/// </summary>
protected abstract byte[] DecryptData(byte[] data);
public override AssetBundle LoadFromMemory()
{
byte[] fileData = File.ReadAllBytes(_options.FileLoadPath);
byte[] rawData = DecryptData(fileData);
if (rawData == null || rawData.Length == 0)
return null;
return AssetBundle.LoadFromMemory(rawData);
}
}
/// <summary>
/// 默认的 AssetBundle 加载操作(加密)
/// 通用实现,适用于 CacheFileSystem
/// </summary>
public abstract class DefaultLoadAssetBundleFromStreamOperation : LoadAssetBundleOperation
{
private enum ESteps
{
None,
CheckPlatform,
LoadAssetBundle,
CheckResult,
Done,
}
private AssetBundleCreateRequest _createRequest;
private ESteps _steps = ESteps.None;
public DefaultLoadAssetBundleFromStreamOperation(LoadAssetBundleOptions options) : base(options) { }
internal override void InternalStart()
{
_steps = ESteps.CheckPlatform;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.CheckPlatform)
{
#if UNITY_ANDROID
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Android platform not support read builtin file.";
#else
_steps = ESteps.LoadAssetBundle;
#endif
}
if (_steps == ESteps.LoadAssetBundle)
{
ManagedStream = CreateManagedFileStream();
uint bufferSize = GetManagedReadBufferSize();
if (IsWaitingForAsyncComplete)
Result = AssetBundle.LoadFromStream(ManagedStream, 0, bufferSize);
else
_createRequest = AssetBundle.LoadFromStreamAsync(ManagedStream, 0, bufferSize);
_steps = ESteps.CheckResult;
}
if (_steps == ESteps.CheckResult)
{
if (_createRequest != null)
{
if (IsWaitingForAsyncComplete)
{
// 强制挂起主线程(注意:该操作会很耗时)
YooLogger.Warning("Suspend the main thread to load unity bundle.");
Result = _createRequest.assetBundle;
}
else
{
if (_createRequest.isDone == false)
return;
Result = _createRequest.assetBundle;
}
}
if (Result == null)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Failed to load asset bundle file : {_options.Bundle.BundleName}";
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}
}
}
internal override void InternalWaitForAsyncComplete()
{
RunBatchExecution();
}
/// <summary>
/// 获取文件流
/// </summary>
protected abstract FileStream CreateManagedFileStream();
/// <summary>
/// 获取缓冲池大小
/// </summary>
protected abstract uint GetManagedReadBufferSize();
/// <summary>
/// 文件数据解密
/// </summary>
protected abstract byte[] DecryptData(byte[] data);
public override AssetBundle LoadFromMemory()
{
byte[] fileData = File.ReadAllBytes(_options.FileLoadPath);
byte[] rawData = DecryptData(fileData);
if (rawData == null || rawData.Length == 0)
return null;
return AssetBundle.LoadFromMemory(rawData);
}
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 3b82b4b846083d34b958320b584d8d9b
guid: 067ac2067f265624bac214127575d7d5
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@@ -0,0 +1,249 @@
using UnityEngine;
namespace YooAsset
{
/// <summary>
/// 默认的 AssetBundle 加载操作(非加密)
/// 通用实现,适用于 WebRemoteFileSystem 和 WebServerFileSystem
/// </summary>
public class DefaultLoadWebAssetBundleOperation : LoadWebAssetBundleOperation
{
private enum ESteps
{
None,
CreateRequest,
CheckRequest,
TryAgain,
Done,
}
private IDownloadAssetBundleRequest _downloadAssetBundleRequest;
private ESteps _steps = ESteps.None;
private int _requestCount = 0;
private float _tryAgainTimer = 0;
private int _failedTryAgain;
public DefaultLoadWebAssetBundleOperation(LoadWebAssetBundleOptions opionts) : base(opionts)
{
_failedTryAgain = opionts.FailedTryAgain;
}
internal override void InternalStart()
{
_steps = ESteps.CreateRequest;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
// 创建下载器
if (_steps == ESteps.CreateRequest)
{
string url = GetRequestURL();
var args = new DownloadAssetBundleRequestArgs(url, 0, _options.WatchdogTimeout, _options.DisableUnityWebCache, _options.Bundle.FileHash, _options.Bundle.UnityCRC);
_downloadAssetBundleRequest = _options.DownloadBackend.CreateAssetBundleRequest(args);
_downloadAssetBundleRequest.SendRequest();
_steps = ESteps.CheckRequest;
}
// 检测下载结果
if (_steps == ESteps.CheckRequest)
{
Progress = _downloadAssetBundleRequest.DownloadProgress;
DownloadedBytes = _downloadAssetBundleRequest.DownloadedBytes;
DownloadProgress = _downloadAssetBundleRequest.DownloadProgress;
if (_downloadAssetBundleRequest.IsDone == false)
return;
if (_downloadAssetBundleRequest.Status == EDownloadRequestStatus.Succeed)
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
Result = _downloadAssetBundleRequest.Result;
}
else
{
if (_failedTryAgain > 0)
{
_steps = ESteps.TryAgain;
YooLogger.Warning($"Failed download : {_downloadAssetBundleRequest.URL} Try again.");
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _downloadAssetBundleRequest.Error;
YooLogger.Error(Error);
}
}
// 最终释放请求器
_downloadAssetBundleRequest.Dispose();
}
// 重新尝试下载
if (_steps == ESteps.TryAgain)
{
_tryAgainTimer += Time.unscaledDeltaTime;
if (_tryAgainTimer > 1f)
{
_tryAgainTimer = 0f;
_failedTryAgain--;
Progress = 0f;
DownloadProgress = 0f;
DownloadedBytes = 0;
_steps = ESteps.CreateRequest;
}
}
}
/// <summary>
/// 获取网络请求地址
/// </summary>
protected string GetRequestURL()
{
// 轮流返回请求地址
_requestCount++;
if (_requestCount % 2 == 0)
return _options.FallbackURL;
else
return _options.MainURL;
}
}
/// <summary>
/// 默认的 AssetBundle 加载操作(加密)
/// 通用实现,适用于 WebRemoteFileSystem 和 WebServerFileSystem
/// </summary>
public abstract class DefaultLoadWebAssetBundleFromMemoryOperation : LoadWebAssetBundleOperation
{
private enum ESteps
{
None,
CreateRequest,
CheckRequest,
TryAgain,
Done,
}
private IDownloadBytesRequest _downloadBytesRequest;
private ESteps _steps = ESteps.None;
private int _requestCount = 0;
private float _tryAgainTimer = 0;
private int _failedTryAgain;
public DefaultLoadWebAssetBundleFromMemoryOperation(LoadWebAssetBundleOptions opionts) : base(opionts)
{
_failedTryAgain = opionts.FailedTryAgain;
}
internal override void InternalStart()
{
_steps = ESteps.CreateRequest;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
// 创建下载器
if (_steps == ESteps.CreateRequest)
{
string url = GetRequestURL();
var args = new DownloadDataRequestArgs(url, 0, _options.WatchdogTimeout);
_downloadBytesRequest = _options.DownloadBackend.CreateBytesRequest(args);
_downloadBytesRequest.SendRequest();
_steps = ESteps.CheckRequest;
}
// 检测下载结果
if (_steps == ESteps.CheckRequest)
{
Progress = _downloadBytesRequest.DownloadProgress;
DownloadProgress = _downloadBytesRequest.DownloadProgress;
DownloadedBytes = _downloadBytesRequest.DownloadedBytes;
if (_downloadBytesRequest.IsDone == false)
return;
// 检查网络错误
if (_downloadBytesRequest.Status == EDownloadRequestStatus.Succeed)
{
var rawData = Decryption(_downloadBytesRequest.Result);
if (rawData == null || rawData.Length == 0)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = "AssetBundle raw data is null or empty.";
}
else
{
AssetBundle assetBundle = AssetBundle.LoadFromMemory(rawData);
if (assetBundle == null)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Failed load encrypted AssetBundle: {_options.Bundle.BundleName}";
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
Result = assetBundle;
}
}
}
else
{
if (_failedTryAgain > 0)
{
_steps = ESteps.TryAgain;
YooLogger.Warning($"Failed download : {_downloadBytesRequest.URL} Try again.");
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _downloadBytesRequest.Error;
YooLogger.Error(Error);
}
}
// 最终释放请求器
_downloadBytesRequest.Dispose();
}
// 重新尝试下载
if (_steps == ESteps.TryAgain)
{
_tryAgainTimer += Time.unscaledDeltaTime;
if (_tryAgainTimer > 1f)
{
_tryAgainTimer = 0f;
_failedTryAgain--;
Progress = 0f;
DownloadProgress = 0f;
DownloadedBytes = 0;
_steps = ESteps.CreateRequest;
}
}
}
/// <summary>
/// 文件数据解密
/// </summary>
protected abstract byte[] Decryption(byte[] data);
/// 获取网络请求地址
/// </summary>
protected string GetRequestURL()
{
// 轮流返回请求地址
_requestCount++;
if (_requestCount % 2 == 0)
return _options.FallbackURL;
else
return _options.MainURL;
}
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 3444518ef1b082a46a9855fef4f69c86
guid: 05b4aa37709184a408090202f98b93d3
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@@ -0,0 +1,68 @@
using System.IO;
using UnityEngine;
namespace YooAsset
{
/// <summary>
/// 加载 AssetBundle 的 Operation 工厂委托
/// </summary>
public delegate LoadAssetBundleOperation LoadAssetBundleOperationFactory(bool bundleEncrypted, LoadAssetBundleOptions options);
/// <summary>
/// 加载 AssetBundle 的抽象基类
/// 用户可继承此类实现自定义加载逻辑(如加密解密)
/// </summary>
public abstract class LoadAssetBundleOperation : AsyncOperationBase
{
protected readonly LoadAssetBundleOptions _options;
/// <summary>
/// 加载结果AssetBundle 对象
/// </summary>
public AssetBundle Result { get; protected set; }
/// <summary>
/// 托管流对象(如果使用流加载)
/// 注意:流对象在资源包对象释放的时候会自动释放
/// </summary>
public Stream ManagedStream { get; protected set; }
public LoadAssetBundleOperation(LoadAssetBundleOptions options)
{
_options = options;
}
/// <summary>
/// 后备加载方法:从内存加载 AssetBundle
/// 当主加载方式失败时FileSystem 会调用此方法作为后备机制
/// </summary>
/// <returns>加载成功返回 AssetBundle 对象,失败返回 null</returns>
public abstract AssetBundle LoadFromMemory();
}
/// <summary>
/// 立即完成(失败)的 AssetBundle 加载操作
/// 用途:当 Factory 判定某种场景不支持(例如默认实现不支持加密包)时,返回该 Operation
/// </summary>
public sealed class LoadAssetBundleCompleteOperation : LoadAssetBundleOperation
{
private readonly string _error;
public LoadAssetBundleCompleteOperation(string error, LoadAssetBundleOptions options) : base(options)
{
_error = error;
}
internal override void InternalStart()
{
Status = EOperationStatus.Failed;
Error = _error;
}
internal override void InternalUpdate()
{
}
public override AssetBundle LoadFromMemory()
{
return null;
}
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 2f88823353464474faf7b020a76f9b2d
guid: 32e01cb4600c49f42b8ec19be8f0fb22
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@@ -0,0 +1,19 @@
namespace YooAsset
{
/// <summary>
/// 加载 AssetBundle 的上下文信息
/// </summary>
public struct LoadAssetBundleOptions
{
/// <summary>
/// 文件加载路径
/// </summary>
internal string FileLoadPath { get; set; }
/// <summary>
/// 资源包信息
/// </summary>
internal PackageBundle Bundle { get; set; }
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 174e56f3a30d7fd4e80bde43ba267631
guid: b866c4ec2f032aa4eb0d4f9094273100
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@@ -0,0 +1,60 @@
using UnityEngine;
namespace YooAsset
{
/// <summary>
/// 加载 AssetBundle 的 Operation 工厂委托
/// </summary>
public delegate LoadWebAssetBundleOperation LoadWebAssetBundleOperationFactory(bool bundleEncrypted, LoadWebAssetBundleOptions options);
/// <summary>
/// 加载 AssetBundle 的抽象基类
/// 用户可继承此类实现自定义加载逻辑(如加密解密)
/// </summary>
public abstract class LoadWebAssetBundleOperation : AsyncOperationBase
{
protected readonly LoadWebAssetBundleOptions _options;
/// <summary>
/// 加载结果AssetBundle 对象
/// </summary>
public AssetBundle Result { get; protected set; }
/// <summary>
/// 下载进度
/// </summary>
public float DownloadProgress { protected set; get; }
/// <summary>
/// 下载大小
/// </summary>
public long DownloadedBytes { protected set; get; }
public LoadWebAssetBundleOperation(LoadWebAssetBundleOptions options)
{
_options = options;
}
}
/// <summary>
/// 立即完成(失败)的 AssetBundle 加载操作
/// 用途:当 Factory 判定某种场景不支持(例如默认实现不支持加密包)时,返回该 Operation
/// </summary>
public sealed class LoadWebAssetBundleCompleteOperation : LoadWebAssetBundleOperation
{
private readonly string _error;
public LoadWebAssetBundleCompleteOperation(string error, LoadWebAssetBundleOptions options) : base(options)
{
_error = error;
}
internal override void InternalStart()
{
Status = EOperationStatus.Failed;
Error = _error;
}
internal override void InternalUpdate()
{
}
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 0f65d2f6038b95246b7a09cec4055b3a
guid: f0fd9af541471154d9fc968abd450d31
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@@ -0,0 +1,44 @@
namespace YooAsset
{
/// <summary>
/// 加载 AssetBundle 的上下文信息
/// </summary>
public struct LoadWebAssetBundleOptions
{
/// <summary>
/// 资源包信息
/// </summary>
internal PackageBundle Bundle { get; set; }
/// <summary>
/// 失败后重试次数
/// </summary>
internal int FailedTryAgain { get; set; }
/// <summary>
/// 看门狗超时时间
/// </summary>
internal int WatchdogTimeout { get; set; }
/// <summary>
/// 下载后台接口
/// </summary>
internal IDownloadBackend DownloadBackend { get; set; }
/// <summary>
/// 禁用Unity的网络缓存
/// </summary>
internal bool DisableUnityWebCache { get; set; }
/// <summary>
/// 主资源地址
/// </summary>
internal string MainURL { get; set; }
/// <summary>
/// 备用资源地址
/// </summary>
internal string FallbackURL { get; set; }
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4c79e03ac8bcbef4aa0e2eede5bf63fb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -10,20 +10,10 @@ namespace YooAsset
public abstract void UnloadBundleFile();
/// <summary>
/// 获取资源包文件的路径
/// 获取资源包文件的本地路径
/// </summary>
public abstract string GetBundleFilePath();
/// <summary>
/// 读取资源包文件的二进制数据
/// </summary>
public abstract byte[] ReadBundleFileData();
/// <summary>
/// 读取资源包文件的文本数据
/// </summary>
public abstract string ReadBundleFileText();
/// <summary>
/// 加载资源包内的资源对象

View File

@@ -0,0 +1,141 @@
using System.IO;
namespace YooAsset
{
/// <summary>
/// 默认的 RawBundle 加载操作(非加密)
/// 通用实现,适用于 BuiltinFileSystem 和 CacheFileSystem
/// </summary>
public class DefaultLoadRawBundleOperation : LoadRawBundleOperation
{
private enum ESteps
{
None,
CheckPlatform,
LoadRawBundle,
Done
}
private ESteps _steps = ESteps.None;
public DefaultLoadRawBundleOperation(LoadRawBundleOptions options) : base(options) { }
internal override void InternalStart()
{
_steps = ESteps.CheckPlatform;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.CheckPlatform)
{
#if UNITY_ANDROID
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Android platform not support read builtin file.";
#else
_steps = ESteps.LoadRawBundle;
#endif
}
if (_steps == ESteps.LoadRawBundle)
{
string filePath = _options.FileLoadPath;
if (File.Exists(filePath))
{
byte[] data = File.ReadAllBytes(filePath);
Result = new RawBundle(data);
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Can not found raw bundle file : {filePath}";
}
}
}
internal override void InternalWaitForAsyncComplete()
{
RunBatchExecution();
}
}
/// <summary>
/// 默认的 RawBundle 加载操作(加密)
/// 通用实现,适用于 CacheFileSystem
/// </summary>
public abstract class DefaultLoadRawBundleFromMemoryOperation : LoadRawBundleOperation
{
private enum ESteps
{
None,
CheckPlatform,
LoadRawBundle,
Done
}
private ESteps _steps = ESteps.None;
public DefaultLoadRawBundleFromMemoryOperation(LoadRawBundleOptions options) : base(options) { }
internal override void InternalStart()
{
_steps = ESteps.CheckPlatform;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.CheckPlatform)
{
#if UNITY_ANDROID
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Android platform not support read builtin file.";
#else
_steps = ESteps.LoadRawBundle;
#endif
}
if (_steps == ESteps.LoadRawBundle)
{
string filePath = _options.FileLoadPath;
if (File.Exists(filePath))
{
byte[] fileData = File.ReadAllBytes(filePath);
byte[] rawData = DecryptData(fileData);
if (rawData == null || rawData.Length == 0)
{
_steps = ESteps.None;
Status = EOperationStatus.Failed;
Error = "Decrypted raw data is null or empty.";
}
else
{
Result = new RawBundle(rawData);
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Can not found raw bundle file : {filePath}";
}
}
}
internal override void InternalWaitForAsyncComplete()
{
RunBatchExecution();
}
/// <summary>
/// 文件数据解密
/// </summary>
protected abstract byte[] DecryptData(byte[] data);
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cc25b8eb3bf83474f942e36bf7b3210d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,50 @@
using System.Text;
namespace YooAsset
{
/// <summary>
/// 加载 RawBundle 的 Operation 工厂委托
/// </summary>
public delegate LoadRawBundleOperation LoadRawBundleOperationFactory(bool bundleEncrypted, LoadRawBundleOptions options);
/// <summary>
/// 加载 RawBundle 的抽象基类
/// 用户可继承此类实现自定义加载逻辑(如加密解密)
/// </summary>
public abstract class LoadRawBundleOperation : AsyncOperationBase
{
protected readonly LoadRawBundleOptions _options;
/// <summary>
/// 加载结果RawBundle 对象
/// </summary>
public RawBundle Result { get; protected set; }
public LoadRawBundleOperation(LoadRawBundleOptions options)
{
_options = options;
}
}
/// <summary>
/// 立即完成(失败)的 RawBundle 加载操作
/// 用途:当 Factory 判定某种场景不支持(例如默认实现不支持加密包)时,返回该 Operation
/// </summary>
public sealed class LoadRawBundleCompleteOperation : LoadRawBundleOperation
{
private readonly string _error;
public LoadRawBundleCompleteOperation(string error, LoadRawBundleOptions options) : base(options)
{
_error = error;
}
internal override void InternalStart()
{
Status = EOperationStatus.Failed;
Error = _error;
}
internal override void InternalUpdate()
{
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 445c03f3efb27eb4c91ce4b387997ac7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,19 @@
namespace YooAsset
{
/// <summary>
/// 加载 RawBundle 的上下文信息
/// </summary>
public struct LoadRawBundleOptions
{
/// <summary>
/// 文件加载路径
/// </summary>
internal string FileLoadPath { get; set; }
/// <summary>
/// 资源包信息
/// </summary>
internal PackageBundle Bundle { get; set; }
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8637bbd2c5bb97d428e45a76466af9c2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -3,13 +3,55 @@ namespace YooAsset
{
internal class RawBundleLoadAssetOperation : FSLoadAssetOperation
{
protected enum ESteps
{
None,
LoadObject,
CheckResult,
Done,
}
private readonly PackageBundle _packageBundle;
private readonly RawBundle _rawBundle;
private readonly AssetInfo _assetInfo;
private ESteps _steps = ESteps.None;
public RawBundleLoadAssetOperation(PackageBundle packageBundle, RawBundle rawBundle, AssetInfo assetInfo)
{
_packageBundle = packageBundle;
_rawBundle = rawBundle;
_assetInfo = assetInfo;
}
internal override void InternalStart()
{
Error = $"{nameof(RawBundleLoadAssetOperation)} not support load asset.";
Status = EOperationStatus.Failed;
_steps = ESteps.LoadObject;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.LoadObject)
{
Result = _rawBundle.LoadRawFileObject();
_steps = ESteps.CheckResult;
}
if (_steps == ESteps.CheckResult)
{
if (Result == null)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Failed to load raw file object : {_assetInfo.AssetPath}";
YooLogger.Error(Error);
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}
}
}
}
}

View File

@@ -0,0 +1,27 @@

namespace YooAsset
{
public class RawBundle
{
private byte[] _data;
public RawBundle(byte[] data)
{
_data = data;
}
/// <summary>
/// 加载原生文件对象
/// </summary>
public RawFileObject LoadRawFileObject()
{
var rawFileObject = new RawFileObject(_data);
return rawFileObject;
}
public void Unload()
{
_data = null;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c5157b3021ed3074192933520404544d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -6,32 +6,30 @@ namespace YooAsset
{
private readonly IFileSystem _fileSystem;
private readonly PackageBundle _packageBundle;
private readonly RawBundle _rawBundle;
public RawBundleResult(IFileSystem fileSystem, PackageBundle packageBundle)
public RawBundleResult(IFileSystem fileSystem, PackageBundle packageBundle, RawBundle rawBundle)
{
_fileSystem = fileSystem;
_packageBundle = packageBundle;
_rawBundle = rawBundle;
}
public override void UnloadBundleFile()
{
if (_rawBundle != null)
{
_rawBundle.Unload();
}
}
public override string GetBundleFilePath()
{
return _fileSystem.GetBundleFilePath(_packageBundle);
}
public override byte[] ReadBundleFileData()
{
return _fileSystem.ReadBundleFileData(_packageBundle);
}
public override string ReadBundleFileText()
{
return _fileSystem.ReadBundleFileText(_packageBundle);
}
public override FSLoadAssetOperation LoadAssetAsync(AssetInfo assetInfo)
{
var operation = new RawBundleLoadAssetOperation();
var operation = new RawBundleLoadAssetOperation(_packageBundle, _rawBundle, assetInfo);
return operation;
}
public override FSLoadAllAssetsOperation LoadAllAssetsAsync(AssetInfo assetInfo)

View File

@@ -0,0 +1,38 @@
using System.Text;
namespace YooAsset
{
/// <summary>
/// 原生文件对象
/// </summary>
public class RawFileObject : UnityEngine.Object
{
private readonly byte[] _fileData;
private string _fileText;
public byte[] Data
{
get
{
return _fileData;
}
}
public string Text
{
get
{
if (Data == null || Data.Length == 0)
return null;
if (string.IsNullOrEmpty(_fileText))
_fileText = Encoding.UTF8.GetString(Data);
return _fileText;
}
}
public RawFileObject(byte[] data)
{
_fileData = data;
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ffa40d12948b6c74e95a1cd42c3c3b7e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -20,14 +20,6 @@ namespace YooAsset
{
return _fileSystem.GetBundleFilePath(_packageBundle);
}
public override byte[] ReadBundleFileData()
{
return _fileSystem.ReadBundleFileData(_packageBundle);
}
public override string ReadBundleFileText()
{
return _fileSystem.ReadBundleFileText(_packageBundle);
}
public override FSLoadAssetOperation LoadAssetAsync(AssetInfo assetInfo)
{

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
namespace YooAsset
@@ -81,13 +81,11 @@ namespace YooAsset
/// <summary>
/// 创建默认的内置文件系统参数
/// </summary>
/// <param name="decryptionServices">加密文件解密服务类</param>
/// <param name="packageRoot">文件系统的根目录</param>
public static FileSystemParameters CreateDefaultBuildinFileSystemParameters(IBundleDecryptionServices decryptionServices = null, string packageRoot = null)
public static FileSystemParameters CreateDefaultBuildinFileSystemParameters(string packageRoot = null)
{
string fileSystemClass = typeof(BuiltinFileSystem).FullName;
var fileSystemParams = new FileSystemParameters(fileSystemClass, packageRoot);
fileSystemParams.AddParameter(FileSystemParametersDefine.BUNDLE_DECRYPTION_SERVICES, decryptionServices);
return fileSystemParams;
}
@@ -95,14 +93,12 @@ namespace YooAsset
/// 创建默认的缓存文件系统参数
/// </summary>
/// <param name="remoteServices">远端资源地址查询服务类</param>
/// <param name="decryptionServices">加密文件解密服务类</param>
/// <param name="packageRoot">文件系统的根目录</param>
public static FileSystemParameters CreateDefaultCacheFileSystemParameters(IRemoteServices remoteServices, IBundleDecryptionServices decryptionServices = null, string packageRoot = null)
public static FileSystemParameters CreateDefaultCacheFileSystemParameters(IRemoteServices remoteServices, string packageRoot = null)
{
string fileSystemClass = typeof(CacheFileSystem).FullName;
var fileSystemParams = new FileSystemParameters(fileSystemClass, packageRoot);
fileSystemParams.AddParameter(FileSystemParametersDefine.REMOTE_SERVICES, remoteServices);
fileSystemParams.AddParameter(FileSystemParametersDefine.BUNDLE_DECRYPTION_SERVICES, decryptionServices);
return fileSystemParams;
}
@@ -111,11 +107,10 @@ namespace YooAsset
/// </summary>
/// <param name="decryptionServices">加密文件解密服务类</param>
/// <param name="disableUnityWebCache">禁用Unity的网络缓存</param>
public static FileSystemParameters CreateDefaultWebServerFileSystemParameters(IWebBundleDecryptionServices decryptionServices = null, bool disableUnityWebCache = false)
public static FileSystemParameters CreateDefaultWebServerFileSystemParameters(bool disableUnityWebCache = false)
{
string fileSystemClass = typeof(WebServerFileSystem).FullName;
var fileSystemParams = new FileSystemParameters(fileSystemClass, null);
fileSystemParams.AddParameter(FileSystemParametersDefine.BUNDLE_DECRYPTION_SERVICES, decryptionServices);
fileSystemParams.AddParameter(FileSystemParametersDefine.DISABLE_UNITY_WEB_CACHE, disableUnityWebCache);
return fileSystemParams;
}
@@ -126,12 +121,11 @@ namespace YooAsset
/// <param name="remoteServices">远端资源地址查询服务类</param>
/// <param name="decryptionServices">加密文件解密服务类</param>
/// <param name="disableUnityWebCache">禁用Unity的网络缓存</param>
public static FileSystemParameters CreateDefaultWebRemoteFileSystemParameters(IRemoteServices remoteServices, IWebBundleDecryptionServices decryptionServices = null, bool disableUnityWebCache = false)
public static FileSystemParameters CreateDefaultWebRemoteFileSystemParameters(IRemoteServices remoteServices, bool disableUnityWebCache = false)
{
string fileSystemClass = typeof(WebRemoteFileSystem).FullName;
var fileSystemParams = new FileSystemParameters(fileSystemClass, null);
fileSystemParams.AddParameter(FileSystemParametersDefine.REMOTE_SERVICES, remoteServices);
fileSystemParams.AddParameter(FileSystemParametersDefine.BUNDLE_DECRYPTION_SERVICES, decryptionServices);
fileSystemParams.AddParameter(FileSystemParametersDefine.DISABLE_UNITY_WEB_CACHE, disableUnityWebCache);
return fileSystemParams;
}

View File

@@ -1,4 +1,4 @@

namespace YooAsset
{
public class FileSystemParametersDefine
@@ -23,10 +23,15 @@ namespace YooAsset
/// </summary>
public const string REMOTE_SERVICES = "REMOTE_SERVICES";
/// <summary>
/// 解密服务接口的实例类 <see cref=IBundleDecryptionServices>
/// <summary>
/// 加载 AssetBundle 的 Operation 工厂委托
/// </summary>
public const string BUNDLE_DECRYPTION_SERVICES = "BUNDLE_DECRYPTION_SERVICES";
public const string LOAD_ASSETBUNDLE_OPERATION_FACTORY = "LOAD_ASSETBUNDLE_OPERATION_FACTORY";
/// <summary>
/// 加载 RawBundle 的 Operation 工厂委托
/// </summary>
public const string LOAD_RAWBUNDLE_OPERATION_FACTORY = "LOAD_RAWBUNDLE_OPERATION_FACTORY";
/// <summary>
/// 资源清单服务类 <see cref=IManifestRestoreServices>
@@ -74,7 +79,7 @@ namespace YooAsset
public const string DOWNLOAD_MAX_REQUEST_PER_FRAME = "DOWNLOAD_MAX_REQUEST_PER_FRAME";
/// <summary>
/// 下载任务的看门狗机制监控时间 <see cref=int>
/// 下载任务的看门狗机制超时时间 <see cref=int>
/// </summary>
public const string DOWNLOAD_WATCH_DOG_TIME = "DOWNLOAD_WATCH_DOG_TIME";

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.IO;
using System.Collections.Generic;
using UnityEngine;
@@ -105,9 +105,14 @@ namespace YooAsset
public string UnpackFileSystemRoot { private set; get; }
/// <summary>
/// 自定义参数:解密服务接口的实例类
/// 自定义参数:加载 AssetBundle 的工厂委托
/// </summary>
public IBundleDecryptionServices BundleDecryptionServices { private set; get; }
public LoadAssetBundleOperationFactory LoadAssetBundleFactory { private set; get; }
/// <summary>
/// 自定义参数:加载 RawBundle 的工厂委托
/// </summary>
public LoadRawBundleOperationFactory LoadRawBundleFactory { private set; get; }
/// <summary>
/// 自定义参数:资源清单服务类
@@ -225,9 +230,13 @@ namespace YooAsset
{
UnpackFileSystemRoot = (string)value;
}
else if (name == FileSystemParametersDefine.BUNDLE_DECRYPTION_SERVICES)
else if (name == FileSystemParametersDefine.LOAD_ASSETBUNDLE_OPERATION_FACTORY)
{
BundleDecryptionServices = (IBundleDecryptionServices)value;
LoadAssetBundleFactory = (LoadAssetBundleOperationFactory)value;
}
else if (name == FileSystemParametersDefine.LOAD_RAWBUNDLE_OPERATION_FACTORY)
{
LoadRawBundleFactory = (LoadRawBundleOperationFactory)value;
}
else if (name == FileSystemParametersDefine.MANIFEST_RESTORE_SERVICES)
{
@@ -255,6 +264,14 @@ namespace YooAsset
if (DownloadBackend == null)
DownloadBackend = new UnityWebRequestBackend(WebRequestCreator);
// 创建默认的 AssetBundle 加载工厂
if (LoadAssetBundleFactory == null)
LoadAssetBundleFactory = DefaultLoadAssetBundleOperationFactory;
// 创建默认的 RawBundle 加载工厂
if (LoadRawBundleFactory == null)
LoadRawBundleFactory = DefaultLoadRawBundleOperationFactory;
// 创建解压文件系统
var remoteServices = new UnpackRemoteService(_packageRoot);
_unpackFileSystem = new UnpackFileSystem();
@@ -265,7 +282,8 @@ namespace YooAsset
_unpackFileSystem.SetParameter(FileSystemParametersDefine.FILE_VERIFY_LEVEL, FileVerifyLevel);
_unpackFileSystem.SetParameter(FileSystemParametersDefine.FILE_VERIFY_MAX_CONCURRENCY, FileVerifyMaxConcurrency);
_unpackFileSystem.SetParameter(FileSystemParametersDefine.APPEND_FILE_EXTENSION, AppendFileExtension);
_unpackFileSystem.SetParameter(FileSystemParametersDefine.BUNDLE_DECRYPTION_SERVICES, BundleDecryptionServices);
_unpackFileSystem.SetParameter(FileSystemParametersDefine.LOAD_ASSETBUNDLE_OPERATION_FACTORY, LoadAssetBundleFactory);
_unpackFileSystem.SetParameter(FileSystemParametersDefine.LOAD_RAWBUNDLE_OPERATION_FACTORY, LoadRawBundleFactory);
_unpackFileSystem.SetParameter(FileSystemParametersDefine.COPY_LOCAL_FILE_SERVICES, CopyLocalFileServices);
_unpackFileSystem.OnCreate(packageName, UnpackFileSystemRoot);
}
@@ -315,88 +333,15 @@ namespace YooAsset
{
return false;
}
public virtual string GetBundleFilePath(PackageBundle bundle)
{
if (IsUnpackBundleFile(bundle))
{
return _unpackFileSystem.GetBundleFilePath(bundle);
}
return GetBuiltinFileLoadPath(bundle);
}
public virtual byte[] ReadBundleFileData(PackageBundle bundle)
{
if (IsUnpackBundleFile(bundle))
return _unpackFileSystem.ReadBundleFileData(bundle);
if (Exists(bundle) == false)
return null;
#if UNITY_ANDROID
//TODO : 安卓平台内置文件属于APK压缩包内的文件。
YooLogger.Error($"Android platform not support read buildin bundle file data.");
return null;
#else
if (bundle.Encrypted)
{
if (DecryptionServices == null)
{
YooLogger.Error($"The {nameof(IDecryptionServices)} is null.");
return null;
}
string filePath = GetBuildinFileLoadPath(bundle);
var fileInfo = new DecryptFileInfo()
{
BundleName = bundle.BundleName,
FileLoadCRC = bundle.UnityCRC,
FileLoadPath = filePath,
};
return DecryptionServices.ReadFileData(fileInfo);
}
else
{
string filePath = GetBuildinFileLoadPath(bundle);
return FileUtility.ReadAllBytes(filePath);
}
#endif
}
public virtual string ReadBundleFileText(PackageBundle bundle)
{
if (IsUnpackBundleFile(bundle))
return _unpackFileSystem.ReadBundleFileText(bundle);
if (Exists(bundle) == false)
return null;
#if UNITY_ANDROID
//TODO : 安卓平台内置文件属于APK压缩包内的文件。
YooLogger.Error($"Android platform not support read buildin bundle file text.");
return null;
#else
if (bundle.Encrypted)
{
if (DecryptionServices == null)
{
YooLogger.Error($"The {nameof(IDecryptionServices)} is null.");
return null;
}
string filePath = GetBuildinFileLoadPath(bundle);
var fileInfo = new DecryptFileInfo()
{
BundleName = bundle.BundleName,
FileLoadCRC = bundle.UnityCRC,
FileLoadPath = filePath,
};
return DecryptionServices.ReadFileText(fileInfo);
}
else
{
string filePath = GetBuildinFileLoadPath(bundle);
return FileUtility.ReadAllText(filePath);
}
#endif
}
/// <summary>
/// 是否属于解压资源包文件
@@ -420,6 +365,30 @@ namespace YooAsset
}
#region
private LoadAssetBundleOperation DefaultLoadAssetBundleOperationFactory(bool bundleEncrypted, LoadAssetBundleOptions options)
{
if (bundleEncrypted)
{
string error = $"{nameof(DefaultLoadAssetBundleOperation)} cannot load encrypted bundle. Please provide a custom {nameof(LoadAssetBundleOperationFactory)}.";
return new LoadAssetBundleCompleteOperation(error, options);
}
else
{
return new DefaultLoadAssetBundleOperation(options);
}
}
private LoadRawBundleOperation DefaultLoadRawBundleOperationFactory(bool bundleEncrypted, LoadRawBundleOptions options)
{
if (bundleEncrypted)
{
string error = $"{nameof(DefaultLoadRawBundleOperation)} cannot load encrypted bundle. Please provide a custom {nameof(LoadRawBundleOperationFactory)}.";
return new LoadRawBundleCompleteOperation(error, options);
}
else
{
return new DefaultLoadRawBundleOperation(options);
}
}
protected string GetDefaultBuiltinPackageRoot(string packageName)
{
string rootDirectory = YooAssetSettingsData.GetYooDefaultBuildinRoot();
@@ -476,36 +445,6 @@ namespace YooAsset
{
return _unpackFileSystem.InitializeAsync();
}
/// <summary>
/// 加载加密的资源文件
/// </summary>
public BundleDecryptionSyncResult LoadEncryptedBundleSync(PackageBundle bundle)
{
string filePath = GetBuiltinFileLoadPath(bundle);
var bundleInfo = new BundleDecryptionContext()
{
BundleName = bundle.BundleName,
FileLoadCRC = bundle.UnityCRC,
FileLoadPath = filePath,
};
return BundleDecryptionServices.LoadAssetBundleSync(bundleInfo);
}
/// <summary>
/// 加载加密的资源文件
/// </summary>
public BundleDecryptionAsyncResult LoadEncryptedBundleAsync(PackageBundle bundle)
{
string filePath = GetBuiltinFileLoadPath(bundle);
var bundleInfo = new BundleDecryptionContext()
{
BundleName = bundle.BundleName,
FileLoadCRC = bundle.UnityCRC,
FileLoadPath = filePath,
};
return BundleDecryptionServices.LoadAssetBundleAsync(bundleInfo);
}
#endregion
}
}

View File

@@ -1,26 +1,24 @@
using System.IO;
using System.IO;
using UnityEngine;
namespace YooAsset
{
/// <summary>
/// 加载AssetBundle文件
/// 加载 AssetBundle 文件
/// </summary>
internal class BFSLoadAssetBundleOperation : FSLoadBundleOperation
{
private enum ESteps
{
None,
LoadAssetBundle,
LoadBuiltinAssetBundle,
CheckResult,
Done,
}
private readonly BuiltinFileSystem _fileSystem;
private readonly PackageBundle _bundle;
private AssetBundleCreateRequest _createRequest;
private AssetBundle _assetBundle;
private Stream _managedStream;
private LoadAssetBundleOperation _loadAssetBundleOp;
private ESteps _steps = ESteps.None;
@@ -33,99 +31,55 @@ namespace YooAsset
{
DownloadProgress = 1f;
DownloadedBytes = _bundle.FileSize;
_steps = ESteps.LoadAssetBundle;
_steps = ESteps.LoadBuiltinAssetBundle;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.LoadAssetBundle)
if (_steps == ESteps.LoadBuiltinAssetBundle)
{
if (_bundle.Encrypted)
{
if (_fileSystem.BundleDecryptionServices == null)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"The {nameof(IBundleDecryptionServices)} is null.";
YooLogger.Error(Error);
return;
}
}
if (IsWaitingForAsyncComplete)
{
if (_bundle.Encrypted)
{
var decryptResult = _fileSystem.LoadEncryptedBundleSync(_bundle);
_assetBundle = decryptResult.Result;
_managedStream = decryptResult.ManagedStream;
}
else
{
string filePath = _fileSystem.GetBuiltinFileLoadPath(_bundle);
_assetBundle = AssetBundle.LoadFromFile(filePath);
}
}
else
{
if (_bundle.Encrypted)
{
var decryptResult = _fileSystem.LoadEncryptedBundleAsync(_bundle);
_createRequest = decryptResult.CreateRequest;
_managedStream = decryptResult.ManagedStream;
}
else
{
string filePath = _fileSystem.GetBuiltinFileLoadPath(_bundle);
_createRequest = AssetBundle.LoadFromFileAsync(filePath);
}
}
var options = new LoadAssetBundleOptions();
options.FileLoadPath = _fileSystem.GetBuiltinFileLoadPath(_bundle);
options.Bundle = _bundle;
_loadAssetBundleOp = _fileSystem.LoadAssetBundleFactory.Invoke(_bundle.Encrypted, options);
_loadAssetBundleOp.StartOperation();
AddChildOperation(_loadAssetBundleOp);
_steps = ESteps.CheckResult;
}
if (_steps == ESteps.CheckResult)
{
if (_createRequest != null)
{
if (IsWaitingForAsyncComplete)
{
// 强制挂起主线程(注意:该操作会很耗时)
YooLogger.Warning("Suspend the main thread to load unity bundle.");
_assetBundle = _createRequest.assetBundle;
}
else
{
if (_createRequest.isDone == false)
return;
_assetBundle = _createRequest.assetBundle;
}
}
if (IsWaitingForAsyncComplete)
_loadAssetBundleOp.WaitForAsyncComplete();
if (_assetBundle == null)
_loadAssetBundleOp.UpdateOperation();
if (_loadAssetBundleOp.IsDone == false)
return;
if (_loadAssetBundleOp.Status == EOperationStatus.Succeed)
{
if (_bundle.Encrypted)
if (_loadAssetBundleOp.Result == null)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Failed to load encrypted buildin asset bundle file : {_bundle.BundleName}";
Error = "Loaded builtin asset bundle is null.";
YooLogger.Error(Error);
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Failed to load buildin asset bundle file : {_bundle.BundleName}";
YooLogger.Error(Error);
Result = new AssetBundleResult(_fileSystem, _bundle, _loadAssetBundleOp.Result, _loadAssetBundleOp.ManagedStream);
Status = EOperationStatus.Succeed;
}
}
else
{
_steps = ESteps.Done;
Result = new AssetBundleResult(_fileSystem, _bundle, _assetBundle, _managedStream);
Status = EOperationStatus.Succeed;
Status = EOperationStatus.Failed;
Error = _loadAssetBundleOp.Error;
YooLogger.Error(Error);
}
}
}
@@ -136,7 +90,7 @@ namespace YooAsset
}
/// <summary>
/// 加载原生文件
/// 加载 RawBundle 文件
/// </summary>
internal class BFSLoadRawBundleOperation : FSLoadBundleOperation
{
@@ -144,11 +98,13 @@ namespace YooAsset
{
None,
LoadBuiltinRawBundle,
CheckResult,
Done,
}
private readonly BuiltinFileSystem _fileSystem;
private readonly PackageBundle _bundle;
private LoadRawBundleOperation _loadRawBundleOp;
private ESteps _steps = ESteps.None;
@@ -170,29 +126,47 @@ namespace YooAsset
if (_steps == ESteps.LoadBuiltinRawBundle)
{
string filePath = _fileSystem.GetBuiltinFileLoadPath(_bundle);
var options = new LoadRawBundleOptions();
options.FileLoadPath = _fileSystem.GetBuiltinFileLoadPath(_bundle);
options.Bundle = _bundle;
_loadRawBundleOp = _fileSystem.LoadRawBundleFactory.Invoke(_bundle.Encrypted, options);
_loadRawBundleOp.StartOperation();
AddChildOperation(_loadRawBundleOp);
_steps = ESteps.CheckResult;
}
#if UNITY_ANDROID
//TODO : 安卓平台内置文件属于APK压缩包内的文件。
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Can not load android buildin raw bundle file : {filePath}";
YooLogger.Error(Error);
#else
if (File.Exists(filePath))
if (_steps == ESteps.CheckResult)
{
if (IsWaitingForAsyncComplete)
_loadRawBundleOp.WaitForAsyncComplete();
_loadRawBundleOp.UpdateOperation();
if (_loadRawBundleOp.IsDone == false)
return;
if (_loadRawBundleOp.Status == EOperationStatus.Succeed)
{
_steps = ESteps.Done;
Result = new RawBundleResult(_fileSystem, _bundle);
Status = EOperationStatus.Succeed;
if (_loadRawBundleOp.Result == null)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = "Loaded builtin raw bundle is null.";
YooLogger.Error(Error);
}
else
{
_steps = ESteps.Done;
Result = new RawBundleResult(_fileSystem, _bundle, _loadRawBundleOp.Result);
Status = EOperationStatus.Succeed;
}
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Can not found buildin raw bundle file : {filePath}";
Error = _loadRawBundleOp.Error;
YooLogger.Error(Error);
}
#endif
}
}
internal override void InternalWaitForAsyncComplete()

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
@@ -112,9 +112,9 @@ namespace YooAsset
public int DownloadMaxRequestPerFrame { private set; get; } = 5;
/// <summary>
/// 自定义参数:下载任务的看门狗机制监控时间
/// 自定义参数:下载任务的看门狗机制超时时间
/// </summary>
public int DownloadWatchDogTime { private set; get; } = 0;
public int DownloadWatchDogTimeout { private set; get; } = 0;
/// <summary>
/// 自定义参数:启用断点续传的最小尺寸
@@ -127,9 +127,14 @@ namespace YooAsset
public List<long> ResumeDownloadResponseCodes { private set; get; } = null;
/// <summary>
/// 自定义参数:解密服务接口的实例类
/// 自定义参数:加载 AssetBundle 的工厂委托
/// </summary>
public IBundleDecryptionServices BundleDecryptionServices { private set; get; }
public LoadAssetBundleOperationFactory LoadAssetBundleFactory { private set; get; }
/// <summary>
/// 自定义参数:加载 RawBundle 的工厂委托
/// </summary>
public LoadRawBundleOperationFactory LoadRawBundleFactory { private set; get; }
/// <summary>
/// 自定义参数:资源清单服务类
@@ -307,7 +312,7 @@ namespace YooAsset
else if (name == FileSystemParametersDefine.DOWNLOAD_WATCH_DOG_TIME)
{
int convertValue = Convert.ToInt32(value);
DownloadWatchDogTime = Mathf.Clamp(convertValue, 0, int.MaxValue);
DownloadWatchDogTimeout = Mathf.Clamp(convertValue, 0, int.MaxValue);
}
else if (name == FileSystemParametersDefine.RESUME_DOWNLOAD_MINMUM_SIZE)
{
@@ -317,9 +322,13 @@ namespace YooAsset
{
ResumeDownloadResponseCodes = (List<long>)value;
}
else if (name == FileSystemParametersDefine.BUNDLE_DECRYPTION_SERVICES)
else if (name == FileSystemParametersDefine.LOAD_ASSETBUNDLE_OPERATION_FACTORY)
{
BundleDecryptionServices = (IBundleDecryptionServices)value;
LoadAssetBundleFactory = (LoadAssetBundleOperationFactory)value;
}
else if (name == FileSystemParametersDefine.LOAD_RAWBUNDLE_OPERATION_FACTORY)
{
LoadRawBundleFactory = (LoadRawBundleOperationFactory)value;
}
else if (name == FileSystemParametersDefine.MANIFEST_RESTORE_SERVICES)
{
@@ -350,6 +359,14 @@ namespace YooAsset
// 创建默认的下载后台接口
if (DownloadBackend == null)
DownloadBackend = new UnityWebRequestBackend(WebRequestCreator);
// 创建默认的 AssetBundle 加载工厂
if (LoadAssetBundleFactory == null)
LoadAssetBundleFactory = DefaultLoadAssetBundleOperationFactory;
// 创建默认的 RawBundle 加载工厂
if (LoadRawBundleFactory == null)
LoadRawBundleFactory = DefaultLoadRawBundleOperationFactory;
}
public virtual void OnDestroy()
{
@@ -393,74 +410,17 @@ namespace YooAsset
return Exists(bundle) == false;
}
public virtual string GetBundleFilePath(PackageBundle bundle)
{
return GetCacheBundleFileLoadPath(bundle);
}
public virtual byte[] ReadBundleFileData(PackageBundle bundle)
{
if (Exists(bundle) == false)
return null;
if (bundle.Encrypted)
{
if (BundleDecryptionServices == null)
{
YooLogger.Error($"The {nameof(IBundleDecryptionServices)} is null.");
return null;
}
string filePath = GetCacheBundleFileLoadPath(bundle);
var bundleInfo = new BundleDecryptionContext()
{
BundleName = bundle.BundleName,
FileLoadCRC = bundle.UnityCRC,
FileLoadPath = filePath,
};
return BundleDecryptionServices.ReadFileData(bundleInfo);
}
else
{
string filePath = GetCacheBundleFileLoadPath(bundle);
return FileUtility.ReadAllBytes(filePath);
}
}
public virtual string ReadBundleFileText(PackageBundle bundle)
{
if (Exists(bundle) == false)
return null;
if (bundle.Encrypted)
{
if (BundleDecryptionServices == null)
{
YooLogger.Error($"The {nameof(IBundleDecryptionServices)} is null.");
return null;
}
string filePath = GetCacheBundleFileLoadPath(bundle);
var bundleInfo = new BundleDecryptionContext()
{
BundleName = bundle.BundleName,
FileLoadCRC = bundle.UnityCRC,
FileLoadPath = filePath,
};
return BundleDecryptionServices.ReadFileText(bundleInfo);
}
else
{
string filePath = GetCacheBundleFileLoadPath(bundle);
return FileUtility.ReadAllText(filePath);
}
}
#region
public List<string> GetAllCachedBundleGUIDs()
{
return _records.Keys.ToList();
}
public FileCacheEntry GetRecordFileElement(PackageBundle bundle)
public FileCacheEntry GetRecordFileEntry(PackageBundle bundle)
{
if (_records.TryGetValue(bundle.BundleGUID, out FileCacheEntry element))
return element;
@@ -504,7 +464,7 @@ namespace YooAsset
{
return _records.ContainsKey(bundleGUID);
}
public bool RecordBundleFile(string bundleGUID, FileCacheEntry element)
public bool RecordBundleFile(string bundleGUID, FileCacheEntry entry)
{
if (_records.ContainsKey(bundleGUID))
{
@@ -512,7 +472,7 @@ namespace YooAsset
return false;
}
_records.Add(bundleGUID, element);
_records.Add(bundleGUID, entry);
return true;
}
@@ -594,6 +554,30 @@ namespace YooAsset
#endregion
#region
private LoadAssetBundleOperation DefaultLoadAssetBundleOperationFactory(bool bundleEncrypted, LoadAssetBundleOptions options)
{
if (bundleEncrypted)
{
string error = $"{nameof(DefaultLoadAssetBundleOperation)} cannot load encrypted bundle. Please provide a custom {nameof(LoadAssetBundleOperationFactory)}.";
return new LoadAssetBundleCompleteOperation(error, options);
}
else
{
return new DefaultLoadAssetBundleOperation(options);
}
}
private LoadRawBundleOperation DefaultLoadRawBundleOperationFactory(bool bundleEncrypted, LoadRawBundleOptions options)
{
if (bundleEncrypted)
{
string error = $"{nameof(DefaultLoadRawBundleOperation)} cannot load encrypted bundle. Please provide a custom {nameof(LoadRawBundleOperationFactory)}.";
return new LoadRawBundleCompleteOperation(error, options);
}
else
{
return new DefaultLoadRawBundleOperation(options);
}
}
public string GetDefaultCachePackageRoot(string packageName)
{
string rootDirectory = YooAssetSettingsData.GetYooDefaultCacheRoot();
@@ -647,51 +631,6 @@ namespace YooAsset
Directory.Delete(_cacheManifestFilesRoot, true);
}
}
/// <summary>
/// 加载加密资源文件
/// </summary>
public BundleDecryptionSyncResult LoadEncryptedBundleSync(PackageBundle bundle)
{
string filePath = GetCacheBundleFileLoadPath(bundle);
var bundleInfo = new BundleDecryptionContext()
{
BundleName = bundle.BundleName,
FileLoadCRC = bundle.UnityCRC,
FileLoadPath = filePath,
};
return BundleDecryptionServices.LoadAssetBundleSync(bundleInfo);
}
/// <summary>
/// 加载加密资源文件
/// </summary>
public BundleDecryptionAsyncResult LoadEncryptedBundleAsync(PackageBundle bundle)
{
string filePath = GetCacheBundleFileLoadPath(bundle);
var bundleInfo = new BundleDecryptionContext()
{
BundleName = bundle.BundleName,
FileLoadCRC = bundle.UnityCRC,
FileLoadPath = filePath,
};
return BundleDecryptionServices.LoadAssetBundleAsync(bundleInfo);
}
/// <summary>
/// 加载加密资源文件
/// </summary>
public BundleDecryptionSyncResult LoadEncryptedBundleFallback(PackageBundle bundle)
{
string filePath = GetCacheBundleFileLoadPath(bundle);
var bundleInfo = new BundleDecryptionContext()
{
BundleName = bundle.BundleName,
FileLoadCRC = bundle.UnityCRC,
FileLoadPath = filePath,
};
return BundleDecryptionServices.LoadAssetBundleFallback(bundleInfo);
}
#endregion
}
}

View File

@@ -18,6 +18,14 @@ namespace YooAsset
DataFileSize = dataFileSize;
}
/// <summary>
/// 修正内容
/// </summary>
public void Modify(string dataFilePath)
{
DataFilePath = dataFilePath;
}
/// <summary>
/// 删除记录文件
/// </summary>

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.IO;
using UnityEngine;
@@ -12,17 +12,16 @@ namespace YooAsset
CheckExist,
DownloadFile,
AbortDownload,
LoadAssetBundle,
LoadCacheAssetBundle,
CheckResult,
TryFallback,
Done,
}
protected readonly CacheFileSystem _fileSystem;
protected readonly PackageBundle _bundle;
protected FSDownloadFileOperation _downloadFileOp;
protected AssetBundleCreateRequest _createRequest;
private AssetBundle _assetBundle;
private Stream _managedStream;
protected LoadAssetBundleOperation _loadAssetBundleOp;
protected ESteps _steps = ESteps.None;
@@ -46,7 +45,7 @@ namespace YooAsset
{
DownloadProgress = 1f;
DownloadedBytes = _bundle.FileSize;
_steps = ESteps.LoadAssetBundle;
_steps = ESteps.LoadCacheAssetBundle;
}
else
{
@@ -96,7 +95,7 @@ namespace YooAsset
if (_downloadFileOp.Status == EOperationStatus.Succeed)
{
_steps = ESteps.LoadAssetBundle;
_steps = ESteps.LoadCacheAssetBundle;
}
else
{
@@ -123,140 +122,92 @@ namespace YooAsset
Error = "Abort download file.";
}
if (_steps == ESteps.LoadAssetBundle)
if (_steps == ESteps.LoadCacheAssetBundle)
{
if (_bundle.Encrypted)
{
if (_fileSystem.BundleDecryptionServices == null)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"The {nameof(IBundleDecryptionServices)} is null.";
YooLogger.Error(Error);
return;
}
}
if (IsWaitingForAsyncComplete)
{
if (_bundle.Encrypted)
{
var decryptResult = _fileSystem.LoadEncryptedBundleSync(_bundle);
_assetBundle = decryptResult.Result;
_managedStream = decryptResult.ManagedStream;
}
else
{
string filePath = _fileSystem.GetCacheBundleFileLoadPath(_bundle);
_assetBundle = AssetBundle.LoadFromFile(filePath);
}
}
else
{
if (_bundle.Encrypted)
{
var decryptResult = _fileSystem.LoadEncryptedBundleAsync(_bundle);
_createRequest = decryptResult.CreateRequest;
_managedStream = decryptResult.ManagedStream;
}
else
{
string filePath = _fileSystem.GetCacheBundleFileLoadPath(_bundle);
_createRequest = AssetBundle.LoadFromFileAsync(filePath);
}
}
var options = new LoadAssetBundleOptions();
options.FileLoadPath = _fileSystem.GetCacheBundleFileLoadPath(_bundle);
options.Bundle = _bundle;
_loadAssetBundleOp = _fileSystem.LoadAssetBundleFactory.Invoke(_bundle.Encrypted, options);
_loadAssetBundleOp.StartOperation();
AddChildOperation(_loadAssetBundleOp);
_steps = ESteps.CheckResult;
}
if (_steps == ESteps.CheckResult)
{
if (_createRequest != null)
if (IsWaitingForAsyncComplete)
_loadAssetBundleOp.WaitForAsyncComplete();
_loadAssetBundleOp.UpdateOperation();
if (_loadAssetBundleOp.IsDone == false)
return;
if (_loadAssetBundleOp.Status == EOperationStatus.Succeed)
{
if (IsWaitingForAsyncComplete)
if (_loadAssetBundleOp.Result == null)
{
// 强制挂起主线程(注意:该操作会很耗时)
YooLogger.Warning("Suspend the main thread to load unity bundle.");
_assetBundle = _createRequest.assetBundle;
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = "Loaded cache asset bundle is null.";
YooLogger.Error(Error);
}
else
{
if (_createRequest.isDone == false)
return;
_assetBundle = _createRequest.assetBundle;
_steps = ESteps.Done;
Result = new AssetBundleResult(_fileSystem, _bundle, _loadAssetBundleOp.Result, _loadAssetBundleOp.ManagedStream);
Status = EOperationStatus.Succeed;
}
}
if (_assetBundle != null)
else
{
_steps = ESteps.Done;
Result = new AssetBundleResult(_fileSystem, _bundle, _assetBundle, _managedStream);
Status = EOperationStatus.Succeed;
return;
if (_loadAssetBundleOp is LoadAssetBundleCompleteOperation)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _loadAssetBundleOp.Error;
YooLogger.Error(Error);
}
else
{
// 加载失败,尝试后备加载
_steps = ESteps.TryFallback;
}
}
}
if (_steps == ESteps.TryFallback)
{
// 注意当缓存文件的校验等级为Low的时候并不能保证缓存文件的完整性。
// 说明在AssetBundle文件加载失败的情况下我们需要重新验证文件的完整性
EFileVerifyResult verifyResult = _fileSystem.VerifyCacheFile(_bundle);
if (verifyResult == EFileVerifyResult.Succeed)
{
if (_bundle.Encrypted)
{
var decryptResult = _fileSystem.LoadEncryptedBundleFallback(_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 = _loadAssetBundleOp.LoadFromMemory();
if (assetBundle != null)
{
_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;
}
_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}";
Error = $"Failed to load asset bundle from memory : {_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);
_fileSystem.DeleteCacheBundleFile(_bundle.BundleGUID);
}
}
}
@@ -275,12 +226,14 @@ namespace YooAsset
DownloadFile,
AbortDownload,
LoadCacheRawBundle,
CheckResult,
Done,
}
protected readonly CacheFileSystem _fileSystem;
protected readonly PackageBundle _bundle;
protected FSDownloadFileOperation _downloadFileOp;
protected LoadRawBundleOperation _loadRawBundleOp;
protected ESteps _steps = ESteps.None;
@@ -309,15 +262,16 @@ namespace YooAsset
{
try
{
var recordFileElement = _fileSystem.GetRecordFileElement(_bundle);
File.Move(recordFileElement.DataFilePath, filePath);
var entry = _fileSystem.GetRecordFileEntry(_bundle);
File.Move(entry.DataFilePath, filePath);
entry.Modify(filePath);
_steps = ESteps.LoadCacheRawBundle;
}
catch (Exception ex)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Faild rename raw data file : {ex.Message}";
Error = $"Faild rename cached data file : {ex.Message}";
}
}
else
@@ -394,18 +348,45 @@ namespace YooAsset
if (_steps == ESteps.LoadCacheRawBundle)
{
string filePath = _fileSystem.GetCacheBundleFileLoadPath(_bundle);
if (File.Exists(filePath))
var options = new LoadRawBundleOptions();
options.FileLoadPath = _fileSystem.GetCacheBundleFileLoadPath(_bundle);
options.Bundle = _bundle;
_loadRawBundleOp = _fileSystem.LoadRawBundleFactory.Invoke(_bundle.Encrypted, options);
_loadRawBundleOp.StartOperation();
AddChildOperation(_loadRawBundleOp);
_steps = ESteps.CheckResult;
}
if (_steps == ESteps.CheckResult)
{
if (IsWaitingForAsyncComplete)
_loadRawBundleOp.WaitForAsyncComplete();
_loadRawBundleOp.UpdateOperation();
if (_loadRawBundleOp.IsDone == false)
return;
if (_loadRawBundleOp.Status == EOperationStatus.Succeed)
{
_steps = ESteps.Done;
Result = new RawBundleResult(_fileSystem, _bundle);
Status = EOperationStatus.Succeed;
if (_loadRawBundleOp.Result == null)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = "Loaded cache raw bundle is null.";
YooLogger.Error(Error);
}
else
{
_steps = ESteps.Done;
Result = new RawBundleResult(_fileSystem, _bundle, _loadRawBundleOp.Result);
Status = EOperationStatus.Succeed;
}
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Can not found cache raw bundle file : {filePath}";
Error = _loadRawBundleOp.Error;
YooLogger.Error(Error);
}
}

View File

@@ -57,7 +57,7 @@ namespace YooAsset
string savePath = _fileSystem.GetCachePackageHashFilePath(_packageVersion);
string fileName = YooAssetSettingsData.GetPackageHashFileName(_fileSystem.PackageName, _packageVersion);
string webURL = GetWebRequestURL(fileName);
int watchdogTime = _fileSystem.DownloadWatchDogTime;
int watchdogTime = _fileSystem.DownloadWatchDogTimeout;
var args = new DownloadFileRequestArgs(webURL, savePath, _timeout, watchdogTime);
_webFileRequestOp = _fileSystem.DownloadBackend.CreateFileRequest(args);
_webFileRequestOp.SendRequest();

View File

@@ -57,7 +57,7 @@ namespace YooAsset
string savePath = _fileSystem.GetCachePackageManifestFilePath(_packageVersion);
string fileName = YooAssetSettingsData.GetManifestBinaryFileName(_fileSystem.PackageName, _packageVersion);
string webURL = GetDownloadRequestURL(fileName);
int watchdogTime = _fileSystem.DownloadWatchDogTime;
int watchdogTime = _fileSystem.DownloadWatchDogTimeout;
var args = new DownloadFileRequestArgs(webURL, savePath, _timeout, watchdogTime);
_webFileRequestOp = _fileSystem.DownloadBackend.CreateFileRequest(args);
_webFileRequestOp.SendRequest();

View File

@@ -45,7 +45,7 @@ namespace YooAsset
{
string fileName = YooAssetSettingsData.GetPackageVersionFileName(_fileSystem.PackageName);
string url = GetWebRequestURL(fileName);
int watchDogTime = _fileSystem.DownloadWatchDogTime;
int watchDogTime = _fileSystem.DownloadWatchDogTimeout;
var args = new DownloadDataRequestArgs(url, _timeout, watchDogTime);
_webTextRequestOp = _fileSystem.DownloadBackend.CreateTextRequest(args);
_webTextRequestOp.SendRequest();

View File

@@ -87,7 +87,7 @@ namespace YooAsset
// 创建下载请求
if (_steps == ESteps.CreateRequest)
{
int watchdogTime = _fileSystem.DownloadWatchDogTime;
int watchdogTime = _fileSystem.DownloadWatchDogTimeout;
int timeout = 0; //注意:文件下载不做超时检测
var args = new DownloadFileRequestArgs(URL, _tempFilePath, timeout, watchdogTime);
_request = _fileSystem.DownloadBackend.CreateFileRequest(args);

View File

@@ -171,7 +171,7 @@ namespace YooAsset
}
}
int watchdogTime = _fileSystem.DownloadWatchDogTime;
int watchdogTime = _fileSystem.DownloadWatchDogTimeout;
int timeout = 0; //注意:文件下载不做超时检测
bool appendToFile = true;
bool removeFileOnAbort = false;
@@ -185,7 +185,7 @@ namespace YooAsset
if (File.Exists(_tempFilePath))
File.Delete(_tempFilePath);
int watchdogTime = _fileSystem.DownloadWatchDogTime;
int watchdogTime = _fileSystem.DownloadWatchDogTimeout;
int timeout = 0; //注意:文件下载不做超时检测
var args = new DownloadFileRequestArgs(URL, _tempFilePath, timeout, watchdogTime);
return _fileSystem.DownloadBackend.CreateFileRequest(args);

View File

@@ -208,7 +208,6 @@ namespace YooAsset
{
return false;
}
public virtual string GetBundleFilePath(PackageBundle bundle)
{
if (bundle.IncludeMainAssets.Count == 0)
@@ -217,22 +216,6 @@ namespace YooAsset
var pacakgeAsset = bundle.IncludeMainAssets[0];
return pacakgeAsset.AssetPath;
}
public virtual byte[] ReadBundleFileData(PackageBundle bundle)
{
if (bundle.IncludeMainAssets.Count == 0)
return null;
var pacakgeAsset = bundle.IncludeMainAssets[0];
return FileUtility.ReadAllBytes(pacakgeAsset.AssetPath);
}
public virtual string ReadBundleFileText(PackageBundle bundle)
{
if (bundle.IncludeMainAssets.Count == 0)
return null;
var pacakgeAsset = bundle.IncludeMainAssets[0];
return FileUtility.ReadAllText(pacakgeAsset.AssetPath);
}
#region
public void RecordDownloadFile(PackageBundle bundle)

View File

@@ -1,22 +0,0 @@
using UnityEngine;
namespace YooAsset
{
internal abstract class LoadWebAssetBundleOperation : AsyncOperationBase
{
/// <summary>
/// AssetBundle对象
/// </summary>
public AssetBundle Result;
/// <summary>
/// 下载进度
/// </summary>
public float DownloadProgress { protected set; get; } = 0;
/// <summary>
/// 下载大小
/// </summary>
public long DownloadedBytes { protected set; get; } = 0;
}
}

View File

@@ -1,146 +0,0 @@
using UnityEngine;
namespace YooAsset
{
internal class LoadWebEncryptAssetBundleOperation : LoadWebAssetBundleOperation
{
protected enum ESteps
{
None,
CreateRequest,
CheckRequest,
TryAgain,
Done,
}
private readonly DownloadFileOptions _options;
private readonly IWebBundleDecryptionServices _decryptionServices;
private readonly IDownloadBackend _downloadBackend;
private IDownloadBytesRequest _unityWebDataRequestOp;
private int _requestCount = 0;
private float _tryAgainTimer = 0;
private int _failedTryAgain;
private ESteps _steps = ESteps.None;
internal LoadWebEncryptAssetBundleOperation(DownloadFileOptions options, IWebBundleDecryptionServices decryptionServices, IDownloadBackend downloadBackend)
{
_options = options;
_failedTryAgain = options.FailedTryAgain;
_decryptionServices = decryptionServices;
_downloadBackend = downloadBackend;
}
internal override void InternalStart()
{
_steps = ESteps.CreateRequest;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
// 创建下载器
if (_steps == ESteps.CreateRequest)
{
if (_decryptionServices == null)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"The {nameof(IWebBundleDecryptionServices)} is null.";
YooLogger.Error(Error);
return;
}
string url = GetRequestURL();
var args = new DownloadDataRequestArgs(url, 0, 0);
_unityWebDataRequestOp = _downloadBackend.CreateBytesRequest(args);
_unityWebDataRequestOp.SendRequest();
_steps = ESteps.CheckRequest;
}
// 检测下载结果
if (_steps == ESteps.CheckRequest)
{
Progress = _unityWebDataRequestOp.DownloadProgress;
DownloadProgress = _unityWebDataRequestOp.DownloadProgress;
DownloadedBytes = _unityWebDataRequestOp.DownloadedBytes;
if (_unityWebDataRequestOp.IsDone == false)
return;
// 检查网络错误
if (_unityWebDataRequestOp.Status == EDownloadRequestStatus.Succeed)
{
AssetBundle assetBundle = LoadEncryptedAssetBundle(_unityWebDataRequestOp.Result);
if (assetBundle == null)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = "Failed load encrypted AssetBundle.";
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
Result = assetBundle;
}
}
else
{
if (_failedTryAgain > 0)
{
_steps = ESteps.TryAgain;
YooLogger.Warning($"Failed download : {_unityWebDataRequestOp.URL} Try again.");
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _unityWebDataRequestOp.Error;
YooLogger.Error(Error);
}
}
}
// 重新尝试下载
if (_steps == ESteps.TryAgain)
{
_tryAgainTimer += Time.unscaledDeltaTime;
if (_tryAgainTimer > 1f)
{
_tryAgainTimer = 0f;
_failedTryAgain--;
Progress = 0f;
DownloadProgress = 0f;
DownloadedBytes = 0;
_steps = ESteps.CreateRequest;
}
}
}
/// <summary>
/// 加载加密资源文件
/// </summary>
private AssetBundle LoadEncryptedAssetBundle(byte[] fileData)
{
var fileInfo = new WebBundleDecryptionContext();
fileInfo.BundleName = _options.Bundle.BundleName;
fileInfo.FileLoadCRC = _options.Bundle.UnityCRC;
fileInfo.FileData = fileData;
var decryptResult = _decryptionServices.LoadAssetBundleSync(fileInfo);
return decryptResult.Result;
}
/// <summary>
/// 获取网络请求地址
/// </summary>
protected string GetRequestURL()
{
// 轮流返回请求地址
_requestCount++;
if (_requestCount % 2 == 0)
return _options.FallbackURL;
else
return _options.MainURL;
}
}
}

View File

@@ -1,114 +0,0 @@
using UnityEngine;
namespace YooAsset
{
internal class LoadWebNormalAssetBundleOperation : LoadWebAssetBundleOperation
{
protected enum ESteps
{
None,
CreateRequest,
CheckRequest,
TryAgain,
Done,
}
private readonly DownloadFileOptions _options;
private readonly bool _disableUnityWebCache;
private readonly IDownloadBackend _downloadBackend;
private IDownloadAssetBundleRequest _unityAssetBundleRequestOp;
private int _requestCount = 0;
private float _tryAgainTimer = 0;
private int _failedTryAgain;
private ESteps _steps = ESteps.None;
internal LoadWebNormalAssetBundleOperation(DownloadFileOptions options, bool disableUnityWebCache, IDownloadBackend downloadBackend)
{
_options = options;
_failedTryAgain = options.FailedTryAgain;
_disableUnityWebCache = disableUnityWebCache;
_downloadBackend = downloadBackend;
}
internal override void InternalStart()
{
_steps = ESteps.CreateRequest;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
// 创建下载器
if (_steps == ESteps.CreateRequest)
{
string url = GetRequestURL();
var args = new DownloadAssetBundleRequestArgs(url, 0, 0, _disableUnityWebCache, _options.Bundle.FileHash, _options.Bundle.UnityCRC);
_unityAssetBundleRequestOp = _downloadBackend.CreateAssetBundleRequest(args);
_unityAssetBundleRequestOp.SendRequest();
_steps = ESteps.CheckRequest;
}
// 检测下载结果
if (_steps == ESteps.CheckRequest)
{
Progress = _unityAssetBundleRequestOp.DownloadProgress;
DownloadedBytes = _unityAssetBundleRequestOp.DownloadedBytes;
DownloadProgress = _unityAssetBundleRequestOp.DownloadProgress;
if (_unityAssetBundleRequestOp.IsDone == false)
return;
if (_unityAssetBundleRequestOp.Status == EDownloadRequestStatus.Succeed)
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
Result = _unityAssetBundleRequestOp.Result;
}
else
{
if (_failedTryAgain > 0)
{
_steps = ESteps.TryAgain;
YooLogger.Warning($"Failed download : {_unityAssetBundleRequestOp.URL} Try again.");
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _unityAssetBundleRequestOp.Error;
YooLogger.Error(Error);
}
}
}
// 重新尝试下载
if (_steps == ESteps.TryAgain)
{
_tryAgainTimer += Time.unscaledDeltaTime;
if (_tryAgainTimer > 1f)
{
_tryAgainTimer = 0f;
_failedTryAgain--;
Progress = 0f;
DownloadProgress = 0f;
DownloadedBytes = 0;
_steps = ESteps.CreateRequest;
}
}
}
/// <summary>
/// 获取网络请求地址
/// </summary>
protected string GetRequestURL()
{
// 轮流返回请求地址
_requestCount++;
if (_requestCount % 2 == 0)
return _options.FallbackURL;
else
return _options.MainURL;
}
}
}

View File

@@ -34,23 +34,17 @@ namespace YooAsset
{
if (_loadWebAssetBundleOp == null)
{
string mainURL = _fileSystem.RemoteServices.GetRemoteMainURL(_bundle.FileName);
string fallbackURL = _fileSystem.RemoteServices.GetRemoteFallbackURL(_bundle.FileName);
DownloadFileOptions options = new DownloadFileOptions(_bundle, int.MaxValue);
options.SetURL(mainURL, fallbackURL);
if (_bundle.Encrypted)
{
_loadWebAssetBundleOp = new LoadWebEncryptAssetBundleOperation(options, _fileSystem.BundleDecryptionServices, _fileSystem.DownloadBackend);
_loadWebAssetBundleOp.StartOperation();
AddChildOperation(_loadWebAssetBundleOp);
}
else
{
_loadWebAssetBundleOp = new LoadWebNormalAssetBundleOperation(options, _fileSystem.DisableUnityWebCache, _fileSystem.DownloadBackend);
_loadWebAssetBundleOp.StartOperation();
AddChildOperation(_loadWebAssetBundleOp);
}
var options = new LoadWebAssetBundleOptions();
options.Bundle = _bundle;
options.FailedTryAgain = int.MaxValue;
options.WatchdogTimeout = _fileSystem.DownloadWatchDogTimeout;
options.DownloadBackend = _fileSystem.DownloadBackend;
options.DisableUnityWebCache = _fileSystem.DisableUnityWebCache;
options.MainURL = _fileSystem.RemoteServices.GetRemoteMainURL(_bundle.FileName);
options.FallbackURL = _fileSystem.RemoteServices.GetRemoteFallbackURL(_bundle.FileName);
_loadWebAssetBundleOp = _fileSystem.LoadAssetBundleFactory.Invoke(_bundle.Encrypted, options);
_loadWebAssetBundleOp.StartOperation();
AddChildOperation(_loadWebAssetBundleOp);
}
_loadWebAssetBundleOp.UpdateOperation();
@@ -62,17 +56,16 @@ namespace YooAsset
if (_loadWebAssetBundleOp.Status == EOperationStatus.Succeed)
{
var assetBundle = _loadWebAssetBundleOp.Result;
if (assetBundle == null)
if (_loadWebAssetBundleOp.Result == null)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"{nameof(WRFSLoadAssetBundleOperation)} loaded asset bundle is null.";
Error = $"Loaded asset bundle object is null.";
}
else
{
_steps = ESteps.Done;
Result = new AssetBundleResult(_fileSystem, _bundle, assetBundle, null);
Result = new AssetBundleResult(_fileSystem, _bundle, _loadWebAssetBundleOp.Result, null);
Status = EOperationStatus.Succeed;
}
}

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.IO;
using System.Collections.Generic;
using UnityEngine;
@@ -53,15 +53,20 @@ namespace YooAsset
/// </summary>
public bool DisableUnityWebCache { private set; get; } = false;
/// <summary>
/// 自定义参数:下载任务的看门狗机制超时时间
/// </summary>
public int DownloadWatchDogTimeout { private set; get; } = 0;
/// <summary>
/// 自定义参数:远程服务接口的实例类(支持跨域下载)
/// </summary>
public IRemoteServices RemoteServices { private set; get; }
/// <summary>
/// 自定义参数:解密服务接口的实例类
/// 自定义参数:加载 AssetBundle 的工厂委托
/// </summary>
public IWebBundleDecryptionServices BundleDecryptionServices { private set; get; }
public LoadWebAssetBundleOperationFactory LoadAssetBundleFactory { private set; get; }
/// <summary>
/// 自定义参数:资源清单服务类
@@ -127,13 +132,18 @@ namespace YooAsset
{
DisableUnityWebCache = Convert.ToBoolean(value);
}
else if (name == FileSystemParametersDefine.DOWNLOAD_WATCH_DOG_TIME)
{
int convertValue = Convert.ToInt32(value);
DownloadWatchDogTimeout = Mathf.Clamp(convertValue, 0, int.MaxValue);
}
else if (name == FileSystemParametersDefine.REMOTE_SERVICES)
{
RemoteServices = (IRemoteServices)value;
}
else if (name == FileSystemParametersDefine.BUNDLE_DECRYPTION_SERVICES)
else if (name == FileSystemParametersDefine.LOAD_ASSETBUNDLE_OPERATION_FACTORY)
{
BundleDecryptionServices = (IWebBundleDecryptionServices)value;
LoadAssetBundleFactory = (LoadWebAssetBundleOperationFactory)value;
}
else if (name == FileSystemParametersDefine.MANIFEST_RESTORE_SERVICES)
{
@@ -151,6 +161,10 @@ namespace YooAsset
// 创建默认的下载后台接口
if (DownloadBackend == null)
DownloadBackend = new UnityWebRequestBackend(WebRequestCreator);
// 创建默认的 AssetBundle 加载工厂
if (LoadAssetBundleFactory == null)
LoadAssetBundleFactory = DefaultLoadAssetBundleOperationFactory;
}
public virtual void OnDestroy()
{
@@ -181,21 +195,24 @@ namespace YooAsset
{
return false;
}
public virtual string GetBundleFilePath(PackageBundle bundle)
{
throw new System.NotImplementedException();
}
public virtual byte[] ReadBundleFileData(PackageBundle bundle)
{
throw new System.NotImplementedException();
}
public virtual string ReadBundleFileText(PackageBundle bundle)
{
throw new System.NotImplementedException();
}
#region
private LoadWebAssetBundleOperation DefaultLoadAssetBundleOperationFactory(bool bundleEncrypted, LoadWebAssetBundleOptions options)
{
if (bundleEncrypted)
{
string error = $"{nameof(DefaultLoadWebAssetBundleOperation)} cannot load encrypted bundle. Please provide a custom {nameof(LoadWebAssetBundleOperationFactory)}.";
return new LoadWebAssetBundleCompleteOperation(error, options);
}
else
{
return new DefaultLoadWebAssetBundleOperation(options);
}
}
#endregion
}
}

View File

@@ -36,21 +36,18 @@ namespace YooAsset
{
string fileLoadPath = _fileSystem.GetWebFileLoadPath(_bundle);
string mainURL = DownloadSystemTools.ToLocalURL(fileLoadPath);
DownloadFileOptions options = new DownloadFileOptions(_bundle, int.MaxValue);
options.SetURL(mainURL, mainURL);
if (_bundle.Encrypted)
{
_loadWebAssetBundleOp = new LoadWebEncryptAssetBundleOperation(options, _fileSystem.BundleDecryptionServices, _fileSystem.DownloadBackend);
_loadWebAssetBundleOp.StartOperation();
AddChildOperation(_loadWebAssetBundleOp);
}
else
{
_loadWebAssetBundleOp = new LoadWebNormalAssetBundleOperation(options, _fileSystem.DisableUnityWebCache, _fileSystem.DownloadBackend);
_loadWebAssetBundleOp.StartOperation();
AddChildOperation(_loadWebAssetBundleOp);
}
var options = new LoadWebAssetBundleOptions();
options.Bundle = _bundle;
options.FailedTryAgain = int.MaxValue;
options.WatchdogTimeout = _fileSystem.DownloadWatchDogTimeout;
options.DownloadBackend = _fileSystem.DownloadBackend;
options.DisableUnityWebCache = _fileSystem.DisableUnityWebCache;
options.MainURL = mainURL;
options.FallbackURL = mainURL;
_loadWebAssetBundleOp = _fileSystem.LoadAssetBundleFactory.Invoke(_bundle.Encrypted, options);
_loadWebAssetBundleOp.StartOperation();
AddChildOperation(_loadWebAssetBundleOp);
}
_loadWebAssetBundleOp.UpdateOperation();
@@ -62,17 +59,16 @@ namespace YooAsset
if (_loadWebAssetBundleOp.Status == EOperationStatus.Succeed)
{
var assetBundle = _loadWebAssetBundleOp.Result;
if (assetBundle == null)
if (_loadWebAssetBundleOp.Result == null)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"{nameof(WSFSLoadAssetBundleOperation)} loaded asset bundle is null.";
Error = $"Loaded asset bundle object is null.";
}
else
{
_steps = ESteps.Done;
Result = new AssetBundleResult(_fileSystem, _bundle, assetBundle, null);
Result = new AssetBundleResult(_fileSystem, _bundle, _loadWebAssetBundleOp.Result, null);
Status = EOperationStatus.Succeed;
}
}

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.IO;
using System.Collections.Generic;
using UnityEngine;
@@ -68,9 +68,14 @@ namespace YooAsset
public bool DisableUnityWebCache { private set; get; } = false;
/// <summary>
/// 自定义参数:解密服务接口的实例类
/// 自定义参数:下载任务的看门狗机制超时时间
/// </summary>
public IWebBundleDecryptionServices BundleDecryptionServices { private set; get; }
public int DownloadWatchDogTimeout { private set; get; } = 0;
/// <summary>
/// 自定义参数:加载 AssetBundle 的工厂委托
/// </summary>
public LoadWebAssetBundleOperationFactory LoadAssetBundleFactory { private set; get; }
/// <summary>
/// 自定义参数:资源清单服务类
@@ -136,9 +141,14 @@ namespace YooAsset
{
DisableUnityWebCache = Convert.ToBoolean(value);
}
else if (name == FileSystemParametersDefine.BUNDLE_DECRYPTION_SERVICES)
else if (name == FileSystemParametersDefine.DOWNLOAD_WATCH_DOG_TIME)
{
BundleDecryptionServices = (IWebBundleDecryptionServices)value;
int convertValue = Convert.ToInt32(value);
DownloadWatchDogTimeout = Mathf.Clamp(convertValue, 0, int.MaxValue);
}
else if (name == FileSystemParametersDefine.LOAD_ASSETBUNDLE_OPERATION_FACTORY)
{
LoadAssetBundleFactory = (LoadWebAssetBundleOperationFactory)value;
}
else if (name == FileSystemParametersDefine.MANIFEST_RESTORE_SERVICES)
{
@@ -161,6 +171,10 @@ namespace YooAsset
// 创建默认的下载后台接口
if (DownloadBackend == null)
DownloadBackend = new UnityWebRequestBackend(WebRequestCreator);
// 创建默认的 AssetBundle 加载工厂
if (LoadAssetBundleFactory == null)
LoadAssetBundleFactory = DefaultLoadAssetBundleOperationFactory;
}
public virtual void OnDestroy()
{
@@ -191,21 +205,24 @@ namespace YooAsset
{
return false;
}
public virtual string GetBundleFilePath(PackageBundle bundle)
{
throw new System.NotImplementedException();
}
public virtual byte[] ReadBundleFileData(PackageBundle bundle)
{
throw new System.NotImplementedException();
}
public virtual string ReadBundleFileText(PackageBundle bundle)
{
throw new System.NotImplementedException();
}
#region
private LoadWebAssetBundleOperation DefaultLoadAssetBundleOperationFactory(bool bundleEncrypted, LoadWebAssetBundleOptions options)
{
if (bundleEncrypted)
{
string error = $"{nameof(DefaultLoadWebAssetBundleOperation)} cannot load encrypted bundle. Please provide a custom {nameof(LoadWebAssetBundleOperationFactory)}.";
return new LoadWebAssetBundleCompleteOperation(error, options);
}
else
{
return new DefaultLoadWebAssetBundleOperation(options);
}
}
protected string GetDefaultWebPackageRoot(string packageName)
{
string rootDirectory = YooAssetSettingsData.GetYooDefaultBuildinRoot();

View File

@@ -91,20 +91,9 @@ namespace YooAsset
/// </summary>
bool NeedImport(PackageBundle bundle);
/// <summary>
/// 获取Bundle文件路径
/// 获取资源包本地路径
/// </summary>
string GetBundleFilePath(PackageBundle bundle);
/// <summary>
/// 读取Bundle文件的二进制数据
/// </summary>
byte[] ReadBundleFileData(PackageBundle bundle);
/// <summary>
/// 读取Bundle文件的文本数据
/// </summary>
string ReadBundleFileText(PackageBundle bundle);
}
}

View File

@@ -11,12 +11,12 @@ namespace YooAsset
/// <summary>
/// 下载进度
/// </summary>
public float DownloadProgress { protected set; get; } = 0;
public float DownloadProgress { protected set; get; }
/// <summary>
/// 下载大小
/// </summary>
public long DownloadedBytes { protected set; get; } = 0;
public long DownloadedBytes { protected set; get; }
/// <summary>
/// 终止下载文件

View File

@@ -45,27 +45,6 @@ namespace YooAsset
Provider.WaitForAsyncComplete();
}
/// <summary>
/// 获取原生文件的二进制数据
/// </summary>
public byte[] GetRawFileData()
{
if (IsValidWithWarning == false)
return null;
return Provider.BundleResultObject.ReadBundleFileData();
}
/// <summary>
/// 获取原生文件的文本数据
/// </summary>
public string GetRawFileText()
{
if (IsValidWithWarning == false)
return null;
return Provider.BundleResultObject.ReadBundleFileText();
}
/// <summary>
/// 获取原生文件的路径
/// </summary>
@@ -73,7 +52,7 @@ namespace YooAsset
{
if (IsValidWithWarning == false)
return string.Empty;
return Provider.BundleResultObject.GetBundleFilePath();
return Provider.LoadedBundleResult.GetBundleFilePath();
}
}
}

View File

@@ -56,7 +56,7 @@ namespace YooAsset
{
if (IsValidWithWarning == false)
return string.Empty;
return Provider.SceneName;
return Provider.LoadedSceneName;
}
}

View File

@@ -112,7 +112,7 @@ namespace YooAsset
}
internal override string InternalGetDescription()
{
return $"SceneName : {_provider.SceneName}";
return $"SceneName : {_provider.LoadedSceneName}";
}
}
}

View File

@@ -12,7 +12,7 @@ namespace YooAsset
{
if (_loadAllAssetsOp == null)
{
_loadAllAssetsOp = BundleResultObject.LoadAllAssetsAsync(MainAssetInfo);
_loadAllAssetsOp = LoadedBundleResult.LoadAllAssetsAsync(MainAssetInfo);
_loadAllAssetsOp.StartOperation();
AddChildOperation(_loadAllAssetsOp);

View File

@@ -12,7 +12,7 @@ namespace YooAsset
{
if (_loadAssetOp == null)
{
_loadAssetOp = BundleResultObject.LoadAssetAsync(MainAssetInfo);
_loadAssetOp = LoadedBundleResult.LoadAssetAsync(MainAssetInfo);
_loadAssetOp.StartOperation();
AddChildOperation(_loadAssetOp);

View File

@@ -48,14 +48,14 @@ namespace YooAsset
public UnityEngine.SceneManagement.Scene SceneObject { protected set; get; }
/// <summary>
/// 获取的资源包对象
/// 加载的资源包结果
/// </summary>
public BundleResult BundleResultObject { protected set; get; }
public BundleResult LoadedBundleResult { protected set; get; }
/// <summary>
/// 加载的场景名称
/// </summary>
public string SceneName { protected set; get; }
public string LoadedSceneName { protected set; get; }
/// <summary>
/// 引用计数
@@ -165,8 +165,8 @@ namespace YooAsset
}
// 检测加载结果
BundleResultObject = _mainBundleLoader.Result;
if (BundleResultObject == null)
LoadedBundleResult = _mainBundleLoader.Result;
if (LoadedBundleResult == null)
{
string error = $"Loaded bundle result is null.";
InvokeCompletion(error, EOperationStatus.Failed);

View File

@@ -16,13 +16,13 @@ namespace YooAsset
{
_loadParams = loadParams;
_suspendLoad = suspendLoad;
SceneName = Path.GetFileNameWithoutExtension(assetInfo.AssetPath);
LoadedSceneName = Path.GetFileNameWithoutExtension(assetInfo.AssetPath);
}
protected override void ProcessBundleResult()
{
if (_loadSceneOp == null)
{
_loadSceneOp = BundleResultObject.LoadSceneOperation(MainAssetInfo, _loadParams, _suspendLoad);
_loadSceneOp = LoadedBundleResult.LoadSceneOperation(MainAssetInfo, _loadParams, _suspendLoad);
_loadSceneOp.StartOperation();
AddChildOperation(_loadSceneOp);
}

View File

@@ -12,7 +12,7 @@ namespace YooAsset
{
if (_loadSubAssetsOp == null)
{
_loadSubAssetsOp = BundleResultObject.LoadSubAssetsAsync(MainAssetInfo);
_loadSubAssetsOp = LoadedBundleResult.LoadSubAssetsAsync(MainAssetInfo);
_loadSubAssetsOp.StartOperation();
AddChildOperation(_loadSubAssetsOp);

View File

@@ -723,7 +723,7 @@ namespace YooAsset
}
#endregion
#region []
#region []
/// <summary>
/// 同步加载资源包内所有资源对象
/// </summary>

View File

@@ -1,108 +0,0 @@
using System.IO;
using UnityEngine;
namespace YooAsset
{
public struct BundleDecryptionContext
{
/// <summary>
/// 资源包名称
/// </summary>
public string BundleName;
/// <summary>
/// 文件加载路径
/// </summary>
public string FileLoadPath;
/// <summary>
/// Unity引擎用于内容校验的CRC
/// </summary>
public uint FileLoadCRC;
}
public struct BundleDecryptionAsyncResult
{
/// <summary>
/// 异步请求句柄
/// </summary>
public AssetBundleCreateRequest CreateRequest;
/// <summary>
/// 托管流对象
/// 注意:流对象在资源包对象释放的时候会自动释放
/// </summary>
public Stream ManagedStream;
}
public struct BundleDecryptionSyncResult
{
/// <summary>
/// 资源包对象
/// </summary>
public AssetBundle Result;
/// <summary>
/// 托管流对象
/// 注意:流对象在资源包对象释放的时候会自动释放
/// </summary>
public Stream ManagedStream;
}
public interface IBundleDecryptionServices
{
/// <summary>
/// 同步方式获取解密的资源包
/// </summary>
BundleDecryptionSyncResult LoadAssetBundleSync(BundleDecryptionContext bundleInfo);
/// <summary>
/// 异步方式获取解密的资源包
/// </summary>
BundleDecryptionAsyncResult LoadAssetBundleAsync(BundleDecryptionContext bundleInfo);
/// <summary>
/// 后备方式获取解密的资源包
/// 注意:当正常解密方法失败后,会触发后备加载!
/// 说明建议通过LoadFromMemory()方法加载资源包作为保底机制。
/// issues : https://github.com/tuyoogame/YooAsset/issues/562
/// </summary>
BundleDecryptionSyncResult LoadAssetBundleFallback(BundleDecryptionContext bundleInfo);
/// <summary>
/// 获取解密的字节数据
/// </summary>
byte[] ReadFileData(BundleDecryptionContext bundleInfo);
/// <summary>
/// 获取解密的文本数据
/// </summary>
string ReadFileText(BundleDecryptionContext bundleInfo);
}
public struct WebBundleDecryptionContext
{
/// <summary>
/// 资源包名称
/// </summary>
public string BundleName;
/// <summary>
/// Unity引擎用于内容校验的CRC
/// </summary>
public uint FileLoadCRC;
/// <summary>
/// 文件字节数据
/// </summary>
public byte[] FileData;
}
public struct WebBundleDecryptionSyncResult
{
/// <summary>
/// 资源包对象
/// </summary>
public AssetBundle Result;
}
public interface IWebBundleDecryptionServices
{
WebBundleDecryptionSyncResult LoadAssetBundleSync(WebBundleDecryptionContext bundleInfo);
}
}

View File

@@ -0,0 +1,136 @@
using System;
using System.IO;
using YooAsset;
public class BundleStream : FileStream
{
public const byte KEY = 64;
public BundleStream(string path, FileMode mode, FileAccess access, FileShare share) : base(path, mode, access, share)
{
}
public BundleStream(string path, FileMode mode) : base(path, mode)
{
}
public override int Read(byte[] array, int offset, int count)
{
var index = base.Read(array, offset, count);
for (int i = 0; i < array.Length; i++)
{
array[i] ^= KEY;
}
return index;
}
}
public class TestFileStreamEncryption : IBundleEncryptionServices
{
public BundleEncryptionResult Encrypt(BundleEncryptionContext fileInfo)
{
// 说明对TestRes3资源目录进行加密
if (fileInfo.BundleName.Contains("_testres3_"))
{
var fileData = File.ReadAllBytes(fileInfo.FileLoadPath);
for (int i = 0; i < fileData.Length; i++)
{
fileData[i] ^= BundleStream.KEY;
}
BundleEncryptionResult result = new BundleEncryptionResult();
result.Encrypted = true;
result.EncryptedData = fileData;
return result;
}
else
{
BundleEncryptionResult result = new BundleEncryptionResult();
result.Encrypted = false;
return result;
}
}
}
public class TestFileOffsetEncryption : IBundleEncryptionServices
{
public BundleEncryptionResult Encrypt(BundleEncryptionContext fileInfo)
{
// 说明对TestRes3资源目录进行加密
if (fileInfo.BundleName.Contains("_testres3_"))
{
int offset = 32;
byte[] fileData = File.ReadAllBytes(fileInfo.FileLoadPath);
var encryptedData = new byte[fileData.Length + offset];
Buffer.BlockCopy(fileData, 0, encryptedData, offset, fileData.Length);
BundleEncryptionResult result = new BundleEncryptionResult();
result.Encrypted = true;
result.EncryptedData = encryptedData;
return result;
}
else
{
BundleEncryptionResult result = new BundleEncryptionResult();
result.Encrypted = false;
return result;
}
}
}
public class TestLoadAssetBundleFromOffsetOperation : DefaultLoadAssetBundleFromOffsetOperation
{
private const uint FILE_OFFSET = 32;
public TestLoadAssetBundleFromOffsetOperation(LoadAssetBundleOptions options) : base(options) { }
protected override uint GetFileOffset()
{
return FILE_OFFSET;
}
}
public class TestLoadAssetBundleFromMemoryOperation : DefaultLoadAssetBundleFromMemoryOperation
{
public TestLoadAssetBundleFromMemoryOperation(LoadAssetBundleOptions options) : base(options) { }
protected override byte[] DecryptData(byte[] data)
{
for (int i = 0; i < data.Length; i++)
{
data[i] ^= BundleStream.KEY;
}
return data;
}
}
public class TestLoadAssetBundleFromStreamOperation : DefaultLoadAssetBundleFromStreamOperation
{
public TestLoadAssetBundleFromStreamOperation(LoadAssetBundleOptions options) : base(options) { }
protected override FileStream CreateManagedFileStream()
{
var fileStream = new BundleStream(_options.FileLoadPath, FileMode.Open, FileAccess.Read, FileShare.Read);
return fileStream;
}
protected override uint GetManagedReadBufferSize()
{
return 1024;
}
protected override byte[] DecryptData(byte[] data)
{
for (int i = 0; i < data.Length; i++)
{
data[i] ^= BundleStream.KEY;
}
return data;
}
}
public class TestWebAssetBundleFromMemoryDecryption : DefaultLoadWebAssetBundleFromMemoryOperation
{
public TestWebAssetBundleFromMemoryDecryption(LoadWebAssetBundleOptions opionts) : base(opionts) { }
protected override byte[] Decryption(byte[] data)
{
for (int i = 0; i < data.Length; i++)
{
data[i] ^= BundleStream.KEY;
}
return data;
}
}

View File

@@ -1,94 +0,0 @@
using System;
using System.IO;
using System.Text;
using System.Collections;
using UnityEngine;
using YooAsset;
/// <summary>
/// 文件偏移加密方式
/// </summary>
public class TestFileOffsetEncryption : IBundleEncryptionServices
{
public BundleEncryptionResult Encrypt(BundleEncryptionContext fileInfo)
{
// 说明对TestRes3资源目录进行加密
if (fileInfo.BundleName.Contains("_testres3_"))
{
int offset = 32;
byte[] fileData = File.ReadAllBytes(fileInfo.FileLoadPath);
var encryptedData = new byte[fileData.Length + offset];
Buffer.BlockCopy(fileData, 0, encryptedData, offset, fileData.Length);
BundleEncryptionResult result = new BundleEncryptionResult();
result.Encrypted = true;
result.EncryptedData = encryptedData;
return result;
}
else
{
BundleEncryptionResult result = new BundleEncryptionResult();
result.Encrypted = false;
return result;
}
}
}
/// <summary>
/// 资源文件偏移解密类
/// </summary>
public class TestFileOffsetDecryption : IBundleDecryptionServices
{
/// <summary>
/// 同步方式获取解密的资源包对象
/// 注意:加载流对象在资源包对象释放的时候会自动释放
/// </summary>
BundleDecryptionSyncResult IBundleDecryptionServices.LoadAssetBundleSync(BundleDecryptionContext fileInfo)
{
var decryptResult = new BundleDecryptionSyncResult();
decryptResult.ManagedStream = null;
decryptResult.Result = AssetBundle.LoadFromFile(fileInfo.FileLoadPath, fileInfo.FileLoadCRC, GetFileOffset());
return decryptResult;
}
/// <summary>
/// 异步方式获取解密的资源包对象
/// 注意:加载流对象在资源包对象释放的时候会自动释放
/// </summary>
BundleDecryptionAsyncResult IBundleDecryptionServices.LoadAssetBundleAsync(BundleDecryptionContext fileInfo)
{
BundleDecryptionAsyncResult decryptResult = new BundleDecryptionAsyncResult();
decryptResult.ManagedStream = null;
decryptResult.CreateRequest = AssetBundle.LoadFromFileAsync(fileInfo.FileLoadPath, fileInfo.FileLoadCRC, GetFileOffset());
return decryptResult;
}
/// <summary>
/// 后备方式获取解密的资源包对象
/// </summary>
BundleDecryptionSyncResult IBundleDecryptionServices.LoadAssetBundleFallback(BundleDecryptionContext fileInfo)
{
return new BundleDecryptionSyncResult();
}
/// <summary>
/// 获取解密的字节数据
/// </summary>
byte[] IBundleDecryptionServices.ReadFileData(BundleDecryptionContext fileInfo)
{
throw new System.NotImplementedException();
}
/// <summary>
/// 获取解密的文本数据
/// </summary>
string IBundleDecryptionServices.ReadFileText(BundleDecryptionContext fileInfo)
{
throw new System.NotImplementedException();
}
private static ulong GetFileOffset()
{
return 32;
}
}

View File

@@ -1,159 +0,0 @@
using System;
using System.IO;
using System.Text;
using System.Collections;
using UnityEngine;
using YooAsset;
/// <summary>
/// 资源文件解密流
/// </summary>
public class BundleStream : FileStream
{
public const byte KEY = 64;
public BundleStream(string path, FileMode mode, FileAccess access, FileShare share) : base(path, mode, access, share)
{
}
public BundleStream(string path, FileMode mode) : base(path, mode)
{
}
public override int Read(byte[] array, int offset, int count)
{
var index = base.Read(array, offset, count);
for (int i = 0; i < array.Length; i++)
{
array[i] ^= KEY;
}
return index;
}
}
/// <summary>
/// 文件流加密方式
/// </summary>
public class TestFileStreamEncryption : IBundleEncryptionServices
{
public BundleEncryptionResult Encrypt(BundleEncryptionContext fileInfo)
{
// 说明对TestRes3资源目录进行加密
if (fileInfo.BundleName.Contains("_testres3_"))
{
var fileData = File.ReadAllBytes(fileInfo.FileLoadPath);
for (int i = 0; i < fileData.Length; i++)
{
fileData[i] ^= BundleStream.KEY;
}
BundleEncryptionResult result = new BundleEncryptionResult();
result.Encrypted = true;
result.EncryptedData = fileData;
return result;
}
else
{
BundleEncryptionResult result = new BundleEncryptionResult();
result.Encrypted = false;
return result;
}
}
}
/// <summary>
/// 资源文件流解密类
/// </summary>
public class TestFileStreamDecryption : IBundleDecryptionServices
{
/// <summary>
/// 同步方式获取解密的资源包对象
/// </summary>
BundleDecryptionSyncResult IBundleDecryptionServices.LoadAssetBundleSync(BundleDecryptionContext fileInfo)
{
BundleStream bundleStream = new BundleStream(fileInfo.FileLoadPath, FileMode.Open, FileAccess.Read, FileShare.Read);
var decryptResult = new BundleDecryptionSyncResult();
decryptResult.ManagedStream = bundleStream;
decryptResult.Result = AssetBundle.LoadFromStream(bundleStream, fileInfo.FileLoadCRC, GetManagedReadBufferSize());
return decryptResult;
}
/// <summary>
/// 异步方式获取解密的资源包对象
/// </summary>
BundleDecryptionAsyncResult IBundleDecryptionServices.LoadAssetBundleAsync(BundleDecryptionContext fileInfo)
{
BundleStream bundleStream = new BundleStream(fileInfo.FileLoadPath, FileMode.Open, FileAccess.Read, FileShare.Read);
var decryptResult = new BundleDecryptionAsyncResult();
decryptResult.ManagedStream = bundleStream;
decryptResult.CreateRequest = AssetBundle.LoadFromStreamAsync(bundleStream, fileInfo.FileLoadCRC, GetManagedReadBufferSize());
return decryptResult;
}
/// <summary>
/// 后备方式获取解密的资源包
/// 注意:当正常解密方法失败后,会触发后备加载!
/// 说明建议通过LoadFromMemory()方法加载资源包作为保底机制。
/// </summary>
BundleDecryptionSyncResult IBundleDecryptionServices.LoadAssetBundleFallback(BundleDecryptionContext fileInfo)
{
byte[] fileData = File.ReadAllBytes(fileInfo.FileLoadPath);
var assetBundle = AssetBundle.LoadFromMemory(fileData);
var decryptResult = new BundleDecryptionSyncResult();
decryptResult.Result = assetBundle;
return decryptResult;
}
/// <summary>
/// 获取解密的字节数据
/// </summary>
byte[] IBundleDecryptionServices.ReadFileData(BundleDecryptionContext fileInfo)
{
throw new System.NotImplementedException();
}
/// <summary>
/// 获取解密的文本数据
/// </summary>
string IBundleDecryptionServices.ReadFileText(BundleDecryptionContext fileInfo)
{
throw new System.NotImplementedException();
}
private static uint GetManagedReadBufferSize()
{
return 1024;
}
}
/// <summary>
/// WebGL平台解密类
/// 注意WebGL平台支持内存解密
/// </summary>
public class TestWebFileMemoryDecryption : IWebBundleDecryptionServices
{
public WebBundleDecryptionSyncResult LoadAssetBundleSync(WebBundleDecryptionContext fileInfo)
{
/*
byte[] copyData = new byte[fileInfo.FileData.Length];
Buffer.BlockCopy(fileInfo.FileData, 0, copyData, 0, fileInfo.FileData.Length);
for (int i = 0; i < copyData.Length; i++)
{
copyData[i] ^= BundleStream.KEY;
}
WebDecryptResult decryptResult = new WebDecryptResult();
decryptResult.Result = AssetBundle.LoadFromMemory(copyData);
return decryptResult;
*/
for (int i = 0; i < fileInfo.FileData.Length; i++)
{
fileInfo.FileData[i] ^= BundleStream.KEY;
}
WebBundleDecryptionSyncResult decryptResult = new WebBundleDecryptionSyncResult();
decryptResult.Result = AssetBundle.LoadFromMemory(fileInfo.FileData);
return decryptResult;
}
}

View File

@@ -60,9 +60,8 @@ public class T2_TestBuldinFileSystem : IPrebuildSetup, IPostBuildCleanup
// 初始化资源包
var initParams = new OfflinePlayModeOptions();
var fileDecryption = new TestFileStreamDecryption();
var manifestServices = new TestRestoreManifest();
initParams.BuildinFileSystemParameters = FileSystemParameters.CreateDefaultBuildinFileSystemParameters(fileDecryption, packageRoot);
initParams.BuildinFileSystemParameters = FileSystemParameters.CreateDefaultBuildinFileSystemParameters(packageRoot);
initParams.BuildinFileSystemParameters.AddParameter(FileSystemParametersDefine.DISABLE_CATALOG_FILE, true);
initParams.BuildinFileSystemParameters.AddParameter(FileSystemParametersDefine.MANIFEST_RESTORE_SERVICES, manifestServices);
var initializeOp = package.InitializePackageAsync(initParams);
@@ -100,7 +99,7 @@ public class T2_TestBuldinFileSystem : IPrebuildSetup, IPostBuildCleanup
// 初始化资源包
var initParams = new OfflinePlayModeOptions();
initParams.BuildinFileSystemParameters = FileSystemParameters.CreateDefaultBuildinFileSystemParameters(null, packageRoot);
initParams.BuildinFileSystemParameters = FileSystemParameters.CreateDefaultBuildinFileSystemParameters(packageRoot);
initParams.BuildinFileSystemParameters.AddParameter(FileSystemParametersDefine.APPEND_FILE_EXTENSION, true);
initParams.BuildinFileSystemParameters.AddParameter(FileSystemParametersDefine.DISABLE_CATALOG_FILE, true);
var initializeOp = package.InitializePackageAsync(initParams);

View File

@@ -45,13 +45,12 @@ public class T3_TestCacheFileSystem : IPrebuildSetup, IPostBuildCleanup
// 初始化资源包
var initParams = new HostPlayModeOptions();
var fileDecryption = new TestFileStreamDecryption();
var manifestServices = new TestRestoreManifest();
string hostServerIP = "http://127.0.0.1/CDN/Android/Test/";
var remoteServices = new TestRemoteServices(hostServerIP);
initParams.BuildinFileSystemParameters = null;
initParams.CacheFileSystemParameters = FileSystemParameters.CreateDefaultCacheFileSystemParameters(remoteServices, fileDecryption);
initParams.CacheFileSystemParameters = FileSystemParameters.CreateDefaultCacheFileSystemParameters(remoteServices);
initParams.CacheFileSystemParameters.AddParameter(FileSystemParametersDefine.MANIFEST_RESTORE_SERVICES, manifestServices);
var initializeOp = package.InitializePackageAsync(initParams);
yield return initializeOp;

View File

@@ -24,13 +24,6 @@ public class TestLoadRawFile
var filePath = rawFileHandle.GetRawFilePath();
Assert.IsNotNull(filePath);
var fileText = rawFileHandle.GetRawFileText();
TestLogger.Log(this, fileText);
Assert.IsNotNull(fileText);
var fileData = rawFileHandle.GetRawFileData();
Assert.IsNotNull(fileData);
}
// 测试同步加载
@@ -40,13 +33,6 @@ public class TestLoadRawFile
var filePath = rawFileHandle.GetRawFilePath();
Assert.IsNotNull(filePath);
var fileText = rawFileHandle.GetRawFileText();
TestLogger.Log(this, fileText);
Assert.IsNotNull(fileText);
var fileData = rawFileHandle.GetRawFileData();
Assert.IsNotNull(fileData);
}
}
}