refactor : 代码重构

This commit is contained in:
何冠峰
2026-02-05 16:14:50 +08:00
parent 0ec07033f7
commit d839146bd5
152 changed files with 2095 additions and 1877 deletions

1
.gitignore vendored
View File

@@ -70,6 +70,7 @@ sysinfo.txt
# Builds
*.apk
*.unitypackage
*.zip
# Crashlytics generated file
crashlytics-build.properties

View File

@@ -10,7 +10,7 @@ namespace YooAsset.Editor
/// <summary>
/// 文件签名(自动填写)
/// </summary>
public string FileSign;
public string FileSignature;
/// <summary>
/// 文件版本(自动填写)

View File

@@ -20,7 +20,7 @@ namespace YooAsset.Editor
ScanReport report = JsonUtility.FromJson<ScanReport>(jsonData);
// 检测配置文件的签名
if (report.FileSign != ScannerDefine.ReportFileSign)
if (report.FileSignature != ScannerDefine.ReportFileSign)
throw new Exception($"导入的报告文件无法识别 : {filePath}");
// 检测报告文件的版本

View File

@@ -122,7 +122,7 @@ namespace YooAsset.Editor
throw new Exception($"Failed to load schema : {ScannerSchema}");
var report = schema.RunScanner(this);
report.FileSign = ScannerDefine.ReportFileSign;
report.FileSignature = ScannerDefine.ReportFileSign;
report.FileVersion = ScannerDefine.ReportFileVersion;
report.SchemaType = schema.GetType().FullName;
report.ScannerGUID = ScannerGUID;

View File

@@ -15,7 +15,7 @@ namespace YooAsset.Editor
/// <summary>
/// 文件签名
/// </summary>
public string FileSign;
public string FileSignature;
/// <summary>
/// 文件版本
@@ -40,7 +40,7 @@ namespace YooAsset.Editor
ConfigWrapper setting = JsonUtility.FromJson<ConfigWrapper>(json);
// 检测配置文件的签名
if (setting.FileSign != ScannerDefine.SettingFileSign)
if (setting.FileSignature != ScannerDefine.SettingFileSign)
throw new Exception($"导入的配置文件无法识别 : {filePath}");
// 检测配置文件的版本
@@ -74,7 +74,7 @@ namespace YooAsset.Editor
File.Delete(savePath);
ConfigWrapper wrapper = new ConfigWrapper();
wrapper.FileSign = ScannerDefine.SettingFileSign;
wrapper.FileSignature = ScannerDefine.SettingFileSign;
wrapper.FileVersion = ScannerDefine.SettingFileVersion;
wrapper.Scanners = AssetArtScannerSettingData.Setting.Scanners;

View File

@@ -15,7 +15,7 @@ namespace YooAsset.Editor
string buildinRootDirectory = buildParametersContext.GetBuildinRootDirectory();
string buildPackageName = buildParametersContext.Parameters.PackageName;
var manifestServices = buildParametersContext.Parameters.ManifestDecryptor;
BuiltinFileCatalogTools.CreateFile(manifestServices, buildPackageName, buildinRootDirectory);
BuiltinCatalogTools.CreateFile(manifestServices, buildPackageName, buildinRootDirectory);
// 刷新目录
AssetDatabase.Refresh();

View File

@@ -157,12 +157,10 @@ namespace YooAsset
}
/// <summary>
/// 内部同步等待方法(子类可选实现)
/// 默认抛出异常,如果异步操作需要支持,子类应重写以支持同步等待
/// 内部释放方法(子类可选实现)
/// </summary>
internal virtual void InternalWaitForCompletion()
internal virtual void InternalDispose()
{
throw new YooInternalException($"InternalWaitForCompletion() is not implemented: {this.GetType().Name}");
}
/// <summary>
@@ -173,6 +171,15 @@ namespace YooAsset
return string.Empty;
}
/// <summary>
/// 内部同步等待方法(子类可选实现)
/// 默认抛出异常,如果异步操作需要支持,子类应重写以支持同步等待
/// </summary>
internal virtual void InternalWaitForCompletion()
{
throw new YooInternalException($"InternalWaitForCompletion() is not implemented: {this.GetType().Name}");
}
/// <summary>
/// 添加子任务
/// </summary>
@@ -321,27 +328,40 @@ namespace YooAsset
// 结束记录
DebugEndRecording();
if (_onCompleted != null)
try
{
var invocationList = _onCompleted.GetInvocationList();
foreach (var handler in invocationList)
{
try
{
((Action<AsyncOperationBase>)handler).Invoke(this);
}
catch (Exception ex)
{
YooLogger.Error($"Exception in completion callback: {ex}");
}
}
InternalDispose();
}
catch (Exception ex)
{
YooLogger.Error($"Exception in {this.GetType().Name}.InternalDispose: {ex}");
}
if (_onCompleted != null)
{
var invocations = _onCompleted.GetInvocationList();
InvokeSafely(invocations);
_onCompleted = null;
}
_onCompleted = null;
if (_taskCompletionSource != null)
_taskCompletionSource.TrySetResult(null);
}
}
private void InvokeSafely(Delegate[] invocations)
{
foreach (var handler in invocations)
{
try
{
((Action<AsyncOperationBase>)handler).Invoke(this);
}
catch (Exception ex)
{
YooLogger.Error($"Exception in inoke callback: {ex}");
}
}
}
/// <summary>
/// 执行一次更新逻辑

View File

@@ -3,7 +3,7 @@ using System;
namespace YooAsset
{
/// <summary>
/// 可轮询的下载请求接口
/// 下载请求接口
/// </summary>
internal interface IDownloadRequest : IDisposable
{

View File

@@ -2,7 +2,7 @@
namespace YooAsset
{
/// <summary>
/// 缓存记录接口
/// 缓存条目接口
/// </summary>
internal interface ICacheEntry
{

View File

@@ -42,7 +42,7 @@ namespace YooAsset
/// <summary>
/// 写入缓存文件
/// </summary>
FCWriteCacheOperation WriteCacheAsync(WriteCacheOptions options);
FCWriteCacheOperation WriteCacheAsync(FCWriteCacheOptions options);
/// <summary>
/// 清理缓存文件
@@ -52,12 +52,12 @@ namespace YooAsset
/// <summary>
/// 验证缓存文件
/// </summary>
FCVerifyCacheOperation VerifyCacheAsync(VerifyCacheOptions options);
FCVerifyCacheOperation VerifyCacheAsync(FCVerifyCacheOptions options);
/// <summary>
/// 加载资源包
/// </summary>
FCLoadBundleOperation LoadBundleAsync(LoadBundleOptions options);
FCLoadBundleOperation LoadBundleAsync(FCLoadBundleOptions options);
/// <summary>
/// 是否已缓存指定 Bundle

View File

@@ -0,0 +1,133 @@
using System;
using System.IO;
namespace YooAsset
{
/// <summary>
/// 加载内置资源目录操作
/// </summary>
internal sealed class LoadBuiltinCatalogOperation : AsyncOperationBase
{
private enum ESteps
{
None,
TryLoadFileData,
RequestFileData,
LoadCatalog,
CheckResult,
Done,
}
private readonly LoadBuiltinCatalogOptions _options;
private IDownloadBytesRequest _downloadBytesRequest;
private byte[] _fileData;
private ESteps _steps = ESteps.None;
/// <summary>
/// 加载完成的内置资源目录
/// </summary>
public BuiltinCatalog Catalog;
internal LoadBuiltinCatalogOperation(LoadBuiltinCatalogOptions options)
{
_options = options;
}
internal override void InternalStart()
{
_steps = ESteps.TryLoadFileData;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.TryLoadFileData)
{
if (File.Exists(_options.FilePath))
{
try
{
_fileData = File.ReadAllBytes(_options.FilePath);
_steps = ESteps.LoadCatalog;
}
catch (Exception ex)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Failed to read file: {ex.Message}";
}
}
else
{
_steps = ESteps.RequestFileData;
}
}
if (_steps == ESteps.RequestFileData)
{
// 注意:从安装包体里解压数据
// 注意从Web服务器下载数据
if (_downloadBytesRequest == null)
{
string url = DownloadSystemTools.ToLocalUrl(_options.FilePath);
var args = new DownloadDataRequestArgs(url, 60, 0);
_downloadBytesRequest = _options.DownloadBackend.CreateBytesRequest(args);
_downloadBytesRequest.SendRequest();
}
if (_downloadBytesRequest.IsDone == false)
return;
if (_downloadBytesRequest.Status == EDownloadRequestStatus.Succeeded)
{
_fileData = _downloadBytesRequest.Result;
_steps = ESteps.LoadCatalog;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _downloadBytesRequest.Error;
}
}
if (_steps == ESteps.LoadCatalog)
{
try
{
Catalog = BuiltinCatalogTools.DeserializeFromBinary(_fileData);
_steps = ESteps.CheckResult;
}
catch (Exception ex)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Failed to load catalog: {ex.Message}";
}
}
if (_steps == ESteps.CheckResult)
{
if (Catalog.PackageName == _options.PackageName)
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Catalog package name {Catalog.PackageName} cannot match the file cache package name {_options.PackageName}";
}
}
}
internal override void InternalDispose()
{
if (_downloadBytesRequest != null)
{
_downloadBytesRequest.Dispose();
_downloadBytesRequest = null;
}
}
}
}

View File

@@ -0,0 +1,24 @@
namespace YooAsset
{
/// <summary>
/// 加载内置资源目录操作选项
/// </summary>
internal struct LoadBuiltinCatalogOptions
{
/// <summary>
/// 包裹名称
/// </summary>
public string PackageName { get; set; }
/// <summary>
/// 文件路径
/// </summary>
public string FilePath { get; set; }
/// <summary>
/// 下载后台
/// </summary>
public IDownloadBackend DownloadBackend { get; set; }
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 236fcfdca8d96624087432269508ccee
guid: 23227e3feab43ab4693cc17ad519f364
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@@ -1,8 +1,11 @@
using System.IO;
using System.IO;
using UnityEngine;
namespace YooAsset
{
/// <summary>
/// 从本地文件加载 AssetBundle 操作
/// </summary>
internal class LoadLocalAssetBundleOperation : FCLoadBundleOperation
{
private enum ESteps
@@ -13,14 +16,16 @@ namespace YooAsset
Done,
}
private readonly PackageBundle _bundle;
private readonly LoadLocalAssetBundleOptions _options;
private AssetBundleCreateRequest _createRequest;
private AssetBundle _assetBundle;
private Stream _loadStream;
private ESteps _steps = ESteps.None;
public bool UnityEngineLoadFailed = false;
/// <summary>
/// Unity引擎加载是否失败
/// </summary>
public bool UnityEngineLoadFailed { get; private set; } = false;
public LoadLocalAssetBundleOperation(LoadLocalAssetBundleOptions options)
{
@@ -37,13 +42,13 @@ namespace YooAsset
if (_steps == ESteps.LoadBundle)
{
if (_bundle.IsEncrypted == false)
if (_options.Bundle.IsEncrypted == false)
{
LoadFromFile();
}
else
{
var decryptor = _options.Decryptor;
var decryptor = _options.AssetBundleDecryptor;
if (decryptor == null)
{
_steps = ESteps.Done;
@@ -52,17 +57,18 @@ namespace YooAsset
return;
}
LoadResult result;
if (decryptor is IBundleOffsetDecryptor offsetDecryptor)
{
LoadFromFileWithOffset(offsetDecryptor);
result = LoadFromFileWithOffset(offsetDecryptor);
}
else if (decryptor is IBundleMemoryDecryptor memoryDecryptor)
{
LoadFromMemory(memoryDecryptor);
result = LoadFromMemory(memoryDecryptor);
}
else if (decryptor is IBundleStreamDecryptor streamDecryptor)
{
LoadFromStream(streamDecryptor);
result = LoadFromStream(streamDecryptor);
}
else
{
@@ -71,6 +77,14 @@ namespace YooAsset
Error = $"{_options.CacheName} not support {decryptor.GetType().Name}";
return;
}
if (result.Succeeded == false)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = result.Error;
return;
}
}
_steps = ESteps.CheckResult;
@@ -82,8 +96,8 @@ namespace YooAsset
{
if (IsWaitForCompletion)
{
// 强制挂起主线程(注意:该操作会很耗时)
YooLogger.Warning("Suspend the main thread to load unity bundle.");
// 强制挂起主线程(注意:该操作会很耗时)
YooLogger.Warning("Suspending the main thread to load Unity bundle.");
_assetBundle = _createRequest.assetBundle;
}
else
@@ -100,6 +114,7 @@ namespace YooAsset
Status = EOperationStatus.Failed;
Error = "Unity engine load failed.";
UnityEngineLoadFailed = true;
CleanupStream();
}
else
{
@@ -121,10 +136,10 @@ namespace YooAsset
else
_createRequest = AssetBundle.LoadFromFileAsync(_options.FilePath);
}
private void LoadFromFileWithOffset(IBundleOffsetDecryptor decryptor)
private LoadResult LoadFromFileWithOffset(IBundleOffsetDecryptor decryptor)
{
var args = new BundleDecryptArgs();
args.Bundle = _bundle;
args.Bundle = _options.Bundle;
args.FilePath = _options.FilePath;
uint offset = decryptor.GetFileOffset(args);
@@ -132,31 +147,51 @@ namespace YooAsset
_assetBundle = AssetBundle.LoadFromFile(_options.FilePath, 0, offset);
else
_createRequest = AssetBundle.LoadFromFileAsync(_options.FilePath, 0, offset);
return LoadResult.Default();
}
private void LoadFromMemory(IBundleMemoryDecryptor decryptor)
private LoadResult LoadFromMemory(IBundleMemoryDecryptor decryptor)
{
var args = new BundleDecryptArgs();
args.Bundle = _bundle;
args.Bundle = _options.Bundle;
args.FilePath = _options.FilePath;
var binaryData = decryptor.GetDecryptData(args);
if (binaryData == null)
return LoadResult.Failure($"{_options.CacheName} decryptor returned null data.");
if (IsWaitForCompletion)
_assetBundle = AssetBundle.LoadFromMemory(binaryData);
else
_createRequest = AssetBundle.LoadFromMemoryAsync(binaryData);
return LoadResult.Default();
}
private void LoadFromStream(IBundleStreamDecryptor decryptor)
private LoadResult LoadFromStream(IBundleStreamDecryptor decryptor)
{
var args = new BundleDecryptArgs();
args.Bundle = _bundle;
args.Bundle = _options.Bundle;
args.FilePath = _options.FilePath;
uint bufferSize = decryptor.GetReadBufferSize(args);
_loadStream = decryptor.GetDecryptStream(args);
if (_loadStream == null)
return LoadResult.Failure($"{_options.CacheName} decryptor returned null stream.");
uint unityCRC = 0;
if (IsWaitForCompletion)
_assetBundle = AssetBundle.LoadFromStream(_loadStream, 0, bufferSize);
_assetBundle = AssetBundle.LoadFromStream(_loadStream, unityCRC, bufferSize);
else
_createRequest = AssetBundle.LoadFromStreamAsync(_loadStream, 0, bufferSize);
_createRequest = AssetBundle.LoadFromStreamAsync(_loadStream, unityCRC, bufferSize);
return LoadResult.Default();
}
private void CleanupStream()
{
if (_loadStream != null)
{
_loadStream.Close();
_loadStream.Dispose();
_loadStream = null;
}
}
}
}

View File

@@ -22,9 +22,9 @@ namespace YooAsset
public string FilePath { get; set; }
/// <summary>
/// 解密接口
/// AssetBundle 解密器
/// </summary>
public IBundleDecryptor Decryptor { get; set; }
public IBundleDecryptor AssetBundleDecryptor { get; set; }
}
}

View File

@@ -3,6 +3,9 @@ using System.IO;
namespace YooAsset
{
/// <summary>
/// 从本地加载 RawBundle 操作
/// </summary>
internal class LoadLocalRawBundleOperation : FCLoadBundleOperation
{
private enum ESteps
@@ -34,7 +37,7 @@ namespace YooAsset
{
if (_options.Bundle.IsEncrypted == false)
{
if (IsSupportFileIO(_options.FilePath) == false)
if (SupportsFileIO(_options.FilePath) == false)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
@@ -46,7 +49,7 @@ namespace YooAsset
}
else
{
var decryptor = _options.Decryptor;
var decryptor = _options.RawBundleDecryptor;
if (decryptor == null)
{
_steps = ESteps.Done;
@@ -55,9 +58,10 @@ namespace YooAsset
return;
}
LoadResult result;
if (decryptor is IBundleMemoryDecryptor memoryDecryptor)
{
LoadFromMemory(memoryDecryptor);
result = LoadFromMemory(memoryDecryptor);
}
else
{
@@ -66,6 +70,14 @@ namespace YooAsset
Error = $"{_options.CacheName} not support {decryptor.GetType().Name}";
return;
}
if (result.Succeeded == false)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = result.Error;
return;
}
}
_steps = ESteps.CheckResult;
@@ -95,17 +107,19 @@ namespace YooAsset
private void LoadFromFile()
{
byte[] data = File.ReadAllBytes(_options.FilePath);
if (data != null)
_rawBundle = new RawBundle(data);
_rawBundle = new RawBundle(data);
}
private void LoadFromMemory(IBundleMemoryDecryptor decryptor)
private LoadResult LoadFromMemory(IBundleMemoryDecryptor decryptor)
{
var args = new BundleDecryptArgs();
args.Bundle = _options.Bundle;
args.FilePath = _options.FilePath;
var binaryData = decryptor.GetDecryptData(args);
if (binaryData != null)
_rawBundle = new RawBundle(binaryData);
if (binaryData == null)
return LoadResult.Failure($"{_options.CacheName} decryptor returned null data.");
_rawBundle = new RawBundle(binaryData);
return LoadResult.Default();
}
}
}

View File

@@ -22,8 +22,8 @@ namespace YooAsset
public string FilePath { get; set; }
/// <summary>
/// 解密接口
/// RawBundle 解密器
/// </summary>
public IBundleDecryptor Decryptor { get; set; }
public IBundleDecryptor RawBundleDecryptor { get; set; }
}
}

View File

@@ -1,18 +1,24 @@
using UnityEngine;
using UnityEngine;
namespace YooAsset
{
/// <summary>
/// 从网络加载 AssetBundle 操作的抽象基类
/// </summary>
internal abstract class LoadWebAssetBundleOperation : FCLoadBundleOperation
{
}
/// <summary>
/// 从网络加载未加密 AssetBundle 操作
/// </summary>
internal class LoadWebNormalAssetBundleOperation : LoadWebAssetBundleOperation
{
private enum ESteps
{
None,
DownloadBundle,
CheckResult,
BundleRequest,
CheckRequest,
TryAgain,
Done,
}
@@ -21,7 +27,7 @@ namespace YooAsset
private IDownloadAssetBundleRequest _downloadAssetBundleRequest;
private ESteps _steps = ESteps.None;
// 失败重试
// 失败重试
private int _requestCount = 0;
private float _tryAgainTimer = 0;
private int _failedTryAgain;
@@ -29,27 +35,27 @@ namespace YooAsset
public LoadWebNormalAssetBundleOperation(LoadWebAssetBundleOptions options)
{
_options = options;
_failedTryAgain = int.MaxValue; //注意:网络原因失败后,重新尝试直到成功
_failedTryAgain = int.MaxValue; //注意:网络原因失败后,重新尝试直到成功
}
internal override void InternalStart()
{
_steps = ESteps.DownloadBundle;
_steps = ESteps.BundleRequest;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.DownloadBundle)
if (_steps == ESteps.BundleRequest)
{
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.CheckResult;
_steps = ESteps.CheckRequest;
}
if (_steps == ESteps.CheckResult)
if (_steps == ESteps.CheckRequest)
{
Progress = _downloadAssetBundleRequest.DownloadProgress;
if (_downloadAssetBundleRequest.IsDone == false)
@@ -62,7 +68,7 @@ namespace YooAsset
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Fatal error: dwonload asset bundle is null.";
Error = $"Fatal error: downloaded asset bundle is null.";
}
else
{
@@ -73,7 +79,7 @@ namespace YooAsset
}
else
{
if (_failedTryAgain > 0)
if (_failedTryAgain > 0 && IsRetryableError(_downloadAssetBundleRequest.HttpCode))
{
_steps = ESteps.TryAgain;
}
@@ -84,27 +90,39 @@ namespace YooAsset
Error = _downloadAssetBundleRequest.Error;
}
}
// 最终释放请求器
_downloadAssetBundleRequest.Dispose();
}
if (_steps == ESteps.TryAgain)
{
// 注意:失败后释放网络请求
if (_downloadAssetBundleRequest != null)
{
_downloadAssetBundleRequest.Dispose();
_downloadAssetBundleRequest = null;
}
_tryAgainTimer += UnityEngine.Time.unscaledDeltaTime;
if (_tryAgainTimer > 1f)
{
_tryAgainTimer = 0f;
_failedTryAgain--;
Progress = 0f;
_steps = ESteps.DownloadBundle;
_steps = ESteps.BundleRequest;
}
}
}
internal override void InternalDispose()
{
if (_downloadAssetBundleRequest != null)
{
_downloadAssetBundleRequest.Dispose();
_downloadAssetBundleRequest = null;
}
}
private string GetRequestURL()
{
// 轮流返回请求地址
// 轮流返回请求地址
_requestCount++;
if (_requestCount % 2 == 0)
return _options.FallbackURL;
@@ -113,12 +131,18 @@ namespace YooAsset
}
}
/// <summary>
/// 从网络加载加密的 AssetBundle 操作
/// </summary>
internal class LoadWebEncryptedAssetBundleOperation : LoadWebAssetBundleOperation
{
private enum ESteps
{
None,
DownloadData,
DataRequest,
CheckRequest,
VerifyData,
LoadBundle,
CheckResult,
TryAgain,
Done,
@@ -127,9 +151,10 @@ namespace YooAsset
protected readonly LoadWebAssetBundleOptions _options;
private IDownloadBytesRequest _downloadBytesRequest;
private IBundleMemoryDecryptor _decryptor;
private AssetBundleCreateRequest _createRequest;
private ESteps _steps = ESteps.None;
// 失败重试
// 失败重试
private int _requestCount = 0;
private float _tryAgainTimer = 0;
private int _failedTryAgain;
@@ -137,20 +162,20 @@ namespace YooAsset
public LoadWebEncryptedAssetBundleOperation(LoadWebAssetBundleOptions options)
{
_options = options;
_failedTryAgain = int.MaxValue; //注意:网络原因失败后,重新尝试直到成功
_failedTryAgain = int.MaxValue; //注意:网络原因失败后,重新尝试直到成功
}
internal override void InternalStart()
{
_steps = ESteps.DownloadData;
_steps = ESteps.DataRequest;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.DownloadData)
if (_steps == ESteps.DataRequest)
{
var decryptor = _options.Decryptor;
var decryptor = _options.AssetBundleDecryptor;
if (decryptor == null)
{
_steps = ESteps.Done;
@@ -161,12 +186,12 @@ namespace YooAsset
if (decryptor is IBundleMemoryDecryptor)
{
string url = GetRequestURL();
_decryptor = decryptor as IBundleMemoryDecryptor;
string url = GetRequestURL();
var args = new DownloadDataRequestArgs(url, 0, _options.WatchdogTimeout);
_downloadBytesRequest = _options.DownloadBackend.CreateBytesRequest(args);
_downloadBytesRequest.SendRequest();
_steps = ESteps.CheckResult;
_steps = ESteps.CheckRequest;
}
else
{
@@ -177,32 +202,19 @@ namespace YooAsset
}
}
if (_steps == ESteps.CheckResult)
if (_steps == ESteps.CheckRequest)
{
Progress = _downloadBytesRequest.DownloadProgress;
if (_downloadBytesRequest.IsDone == false)
return;
// 检查网络错误
if (_downloadBytesRequest.Status == EDownloadRequestStatus.Succeeded)
{
var assetBundle = LoadFromMemory(_decryptor, _downloadBytesRequest.Result);
if (assetBundle == null)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = "Unity engine load failed.";
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
BundleResult = new AssetBundleResult(_downloadBytesRequest.Url, _options.Bundle, assetBundle, null);
}
_steps = ESteps.VerifyData;
}
else
{
if (_failedTryAgain > 0)
if (_failedTryAgain > 0 && IsRetryableError(_downloadBytesRequest.HttpCode))
{
_steps = ESteps.TryAgain;
}
@@ -213,35 +225,118 @@ namespace YooAsset
Error = _downloadBytesRequest.Error;
}
}
}
// 最终释放请求器
_downloadBytesRequest.Dispose();
if (_steps == ESteps.VerifyData)
{
// 注意:网络/代理/服务器异常导致内容不完整但请求仍成功
EFileVerifyResult verifyResult;
if (_options.DownloadVerifyLevel == EFileVerifyLevel.Low || _options.DownloadVerifyLevel == EFileVerifyLevel.Middle)
verifyResult = FileVerifyTools.FileVerify(_downloadBytesRequest.Result, _options.Bundle.FileSize, 0);
else if (_options.DownloadVerifyLevel == EFileVerifyLevel.High)
verifyResult = FileVerifyTools.FileVerify(_downloadBytesRequest.Result, _options.Bundle.FileSize, _options.Bundle.FileCRC);
else
throw new System.NotImplementedException(_options.DownloadVerifyLevel.ToString());
if (verifyResult == EFileVerifyResult.Succeed)
{
_steps = ESteps.LoadBundle;
}
else
{
string error = $"[WebBundleVerify] Verify failed. Url:{_downloadBytesRequest.Url} Level: {_options.DownloadVerifyLevel} Result: {verifyResult}";
YooLogger.Warning(error);
if (_failedTryAgain > 0)
{
_steps = ESteps.TryAgain;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = error;
}
}
}
if (_steps == ESteps.LoadBundle)
{
LoadResult result = LoadFromMemory(_decryptor, _downloadBytesRequest.Result);
if (result.Succeeded == false)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = result.Error;
return;
}
_steps = ESteps.CheckResult;
}
if (_steps == ESteps.CheckResult)
{
if (_createRequest.isDone == false)
return;
var assetBundle = _createRequest.assetBundle;
if (assetBundle == null)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = "Unity engine load failed.";
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
BundleResult = new AssetBundleResult(_downloadBytesRequest.Url, _options.Bundle, assetBundle, null);
}
}
if (_steps == ESteps.TryAgain)
{
// 注意:失败后释放网络请求
if (_downloadBytesRequest != null)
{
_downloadBytesRequest.Dispose();
_downloadBytesRequest = null;
}
_tryAgainTimer += Time.unscaledDeltaTime;
if (_tryAgainTimer > 1f)
{
_tryAgainTimer = 0f;
_failedTryAgain--;
Progress = 0f;
_steps = ESteps.DownloadData;
_steps = ESteps.DataRequest;
}
}
}
internal override void InternalDispose()
{
if (_downloadBytesRequest != null)
{
_downloadBytesRequest.Dispose();
_downloadBytesRequest = null;
}
}
private AssetBundle LoadFromMemory(IBundleMemoryDecryptor decryptor, byte[] fileData)
private LoadResult LoadFromMemory(IBundleMemoryDecryptor decryptor, byte[] fileData)
{
var args = new BundleDecryptArgs();
args.Bundle = _options.Bundle;
args.FileData = fileData;
var binaryData = decryptor.GetDecryptData(args);
return AssetBundle.LoadFromMemory(binaryData);
if (binaryData == null)
return LoadResult.Failure($"{_options.CacheName} decryptor returned null data.");
_createRequest = AssetBundle.LoadFromMemoryAsync(binaryData);
return LoadResult.Default();
}
private string GetRequestURL()
{
// 轮流返回请求地址
// 轮流返回请求地址
_requestCount++;
if (_requestCount % 2 == 0)
return _options.FallbackURL;

View File

@@ -22,20 +22,25 @@ namespace YooAsset
public string MainURL { get; set; }
/// <summary>
/// 请求地址
/// 备用请求地址
/// </summary>
public string FallbackURL { get; set; }
/// <summary>
/// 解密接口
/// AssetBundle 解密器
/// </summary>
public IBundleDecryptor Decryptor { get; set; }
public IBundleDecryptor AssetBundleDecryptor { get; set; }
/// <summary>
/// 下载后台接口
/// </summary>
public IDownloadBackend DownloadBackend { get; set; }
/// <summary>
/// 下载数据校验级别
/// </summary>
public EFileVerifyLevel DownloadVerifyLevel { get; set; }
/// <summary>
/// 看门狗超时时间
/// </summary>

View File

@@ -1,10 +1,16 @@
namespace YooAsset
{
/// <summary>
/// 清理缓存操作基类
/// </summary>
internal abstract class FCClearCacheOperation : AsyncOperationBase
{
}
/// <summary>
/// 清理缓存完成操作
/// </summary>
internal class FCClearCacheCompleteOperation : FCClearCacheOperation
{
private readonly string _error;

View File

@@ -1,6 +1,9 @@
namespace YooAsset
{
/// <summary>
/// 文件缓存初始化操作基类
/// </summary>
internal abstract class FCInitializeOperation : AsyncOperationBase
{
}

View File

@@ -1,27 +1,91 @@

namespace YooAsset
{
/// <summary>
/// 加载资源包操作基类
/// </summary>
internal abstract class FCLoadBundleOperation : AsyncOperationBase
{
protected struct LoadResult
{
/// <summary>
/// 错误信息
/// </summary>
public readonly string Error;
/// <summary>
/// 加载成功
/// </summary>
public bool Succeeded
{
get { return Error == null; }
}
public LoadResult(string error)
{
Error = error;
}
public static LoadResult Default()
{
return new LoadResult(null);
}
public static LoadResult Failure(string error)
{
return new LoadResult(error);
}
}
/// <summary>
/// 资源包加载结果
/// </summary>
public IBundleResult BundleResult { get; protected set; }
/// <summary>
/// 检查文件路径是否支持 FileIO 读取
/// </summary>
protected bool IsSupportFileIO(string filePath)
protected bool SupportsFileIO(string filePath)
{
if (string.IsNullOrEmpty(filePath))
return true;
return false;
if (filePath.StartsWith("jar:") || filePath.StartsWith("content:"))
return false;
return true;
}
/// <summary>
/// 判断是否为可重试的错误
/// </summary>
protected bool IsRetryableError(long httpCode)
{
// HTTP 状态码
// 1xx 信息响应
// 2xx 成功响应
// 3xx 重定向消息
// 4xx 客户端错误响应
// 5xx 服务器错误响应
if (httpCode == 0)
return true;
// 4xx 客户端错误不可重试
// 说明408 Request Timeout
// 说明429 Too Many Requests
if (httpCode >= 400 && httpCode < 500)
return httpCode == 408 || httpCode == 429;
// 其它情况可重试
return true;
}
}
/// <summary>
/// 加载资源包失败操作
/// </summary>
internal sealed class FCLoadBundleErrorOperation : FCLoadBundleOperation
{
private readonly string _error;
internal FCLoadBundleErrorOperation(string error)
{
_error = error;

View File

@@ -1,14 +1,17 @@

namespace YooAsset
{
internal struct LoadBundleOptions
/// <summary>
/// 加载资源包操作选项
/// </summary>
internal readonly struct FCLoadBundleOptions
{
/// <summary>
/// 资源包
/// </summary>
public readonly PackageBundle Bundle;
public LoadBundleOptions(PackageBundle bundle)
public FCLoadBundleOptions(PackageBundle bundle)
{
Bundle = bundle;
}

View File

@@ -1,10 +1,16 @@
namespace YooAsset
{
/// <summary>
/// 验证缓存操作基类
/// </summary>
internal abstract class FCVerifyCacheOperation : AsyncOperationBase
{
}
/// <summary>
/// 验证缓存完成操作
/// </summary>
internal class FCVerifyCacheCompleteOperation : FCVerifyCacheOperation
{
private readonly string _error;

View File

@@ -1,7 +1,10 @@
namespace YooAsset
{
internal struct VerifyCacheOptions
/// <summary>
/// 验证缓存操作选项
/// </summary>
internal struct FCVerifyCacheOptions
{
/// <summary>
/// 要验证的资源包
@@ -9,8 +12,8 @@ namespace YooAsset
public PackageBundle Bundle { get; set; }
/// <summary>
/// 失败后直接移除缓存
/// 失败后直接移除缓存条目
/// </summary>
public bool FailedDeleteCache { get; set; }
public bool DeleteCacheEntryOnFailure { get; set; }
}
}

View File

@@ -1,10 +1,16 @@
namespace YooAsset
{
/// <summary>
/// 写入缓存操作基类
/// </summary>
internal abstract class FCWriteCacheOperation : AsyncOperationBase
{
}
/// <summary>
/// 写入缓存完成操作
/// </summary>
internal class FCWriteCacheCompleteOperation : FCWriteCacheOperation
{
private readonly string _error;

View File

@@ -1,7 +1,10 @@
namespace YooAsset
{
internal struct WriteCacheOptions
/// <summary>
/// 写入缓存操作选项
/// </summary>
internal struct FCWriteCacheOptions
{
/// <summary>
/// 要缓存的资源包

View File

@@ -1,19 +1,29 @@
using System;
using System;
using System.IO;
using System.Collections.Generic;
namespace YooAsset
{
/// <summary>
/// 内置资源清单目录
/// 内置资源目录
/// </summary>
[Serializable]
internal class BuiltinFileCatalog
internal class BuiltinCatalog
{
/// <summary>
/// 内置资源文件条目
/// </summary>
[Serializable]
public class FileWrapper
public class FileEntry
{
/// <summary>
/// 资源包唯一标识
/// </summary>
public string BundleGUID;
/// <summary>
/// 资源包文件名
/// </summary>
public string FileName;
}
@@ -33,8 +43,8 @@ namespace YooAsset
public string PackageVersion;
/// <summary>
/// 文件列表
/// 文件条目列表
/// </summary>
public List<FileWrapper> Wrappers = new List<FileWrapper>();
public List<FileEntry> FileEntries = new List<FileEntry>();
}
}

View File

@@ -1,17 +1,20 @@

namespace YooAsset
{
internal class BuiltinFileCatalogDefine
/// <summary>
/// 内置资源目录常量定义
/// </summary>
internal class BuiltinCatalogDefine
{
/// <summary>
/// 文件极限大小100MB
/// </summary>
public const int FileMaxSize = 104857600;
public const int MaxFileSize = 104857600;
/// <summary>
/// 文件头标记
/// </summary>
public const uint FileSign = 0x133C5EE;
public const uint FileHeader = 0x133C5EE;
/// <summary>
/// 文件格式版本

View File

@@ -1,11 +1,14 @@
using System;
using System;
using System.IO;
using System.Collections.Generic;
using UnityEngine;
namespace YooAsset
{
internal static class BuiltinFileCatalogTools
/// <summary>
/// 内置资源目录工具类
/// </summary>
internal static class BuiltinCatalogTools
{
#if UNITY_EDITOR
/// <summary>
@@ -21,7 +24,7 @@ namespace YooAsset
string versionFilePath = $"{packageDirectory}/{versionFileName}";
if (File.Exists(versionFilePath) == false)
{
Debug.LogError($"Can not found package version file : {versionFilePath}");
Debug.LogError($"Package version file not found: {versionFilePath}");
return false;
}
@@ -35,7 +38,7 @@ namespace YooAsset
string manifestFilePath = $"{packageDirectory}/{manifestFileName}";
if (File.Exists(manifestFilePath) == false)
{
Debug.LogError($"Can not found package manifest file : {manifestFilePath}");
Debug.LogError($"Package manifest file not found: {manifestFilePath}");
return false;
}
@@ -53,29 +56,29 @@ namespace YooAsset
}
// 创建内置清单实例
var buildinFileCatalog = new BuiltinFileCatalog();
buildinFileCatalog.FileVersion = BuiltinFileCatalogDefine.FileVersion;
buildinFileCatalog.PackageName = packageName;
buildinFileCatalog.PackageVersion = packageVersion;
var buildinCatalog = new BuiltinCatalog();
buildinCatalog.FileVersion = BuiltinCatalogDefine.FileVersion;
buildinCatalog.PackageName = packageName;
buildinCatalog.PackageVersion = packageVersion;
// 创建白名单查询集合
HashSet<string> whiteFileList = new HashSet<string>
HashSet<string> whiteFileNameList = new HashSet<string>
{
"link.xml",
"buildlogtep.json",
BuiltinFileCatalogDefine.JsonFileName,
BuiltinFileCatalogDefine.BinaryFileName
BuiltinCatalogDefine.JsonFileName,
BuiltinCatalogDefine.BinaryFileName
};
string packageVersionFileName = YooAssetSettingsData.GetPackageVersionFileName(packageName);
string packageHashFileName = YooAssetSettingsData.GetPackageHashFileName(packageName, packageVersion);
string manifestBinaryFIleName = YooAssetSettingsData.GetManifestBinaryFileName(packageName, packageVersion);
string manifestJsonFIleName = YooAssetSettingsData.GetManifestJsonFileName(packageName, packageVersion);
string manifestBinaryFileName = YooAssetSettingsData.GetManifestBinaryFileName(packageName, packageVersion);
string manifestJsonFileName = YooAssetSettingsData.GetManifestJsonFileName(packageName, packageVersion);
string reportFileName = YooAssetSettingsData.GetBuildReportFileName(packageName, packageVersion);
whiteFileList.Add(packageVersionFileName);
whiteFileList.Add(packageHashFileName);
whiteFileList.Add(manifestBinaryFIleName);
whiteFileList.Add(manifestJsonFIleName);
whiteFileList.Add(reportFileName);
whiteFileNameList.Add(packageVersionFileName);
whiteFileNameList.Add(packageHashFileName);
whiteFileNameList.Add(manifestBinaryFileName);
whiteFileNameList.Add(manifestJsonFileName);
whiteFileNameList.Add(reportFileName);
// 记录所有内置资源文件
DirectoryInfo rootDirectory = new DirectoryInfo(packageDirectory);
@@ -85,37 +88,37 @@ namespace YooAsset
if (fileInfo.Extension == ".meta")
continue;
if (whiteFileList.Contains(fileInfo.Name))
if (whiteFileNameList.Contains(fileInfo.Name))
continue;
string fileName = fileInfo.Name;
if (fileMapping.TryGetValue(fileName, out string bundleGUID))
{
var wrapper = new BuiltinFileCatalog.FileWrapper();
wrapper.BundleGUID = bundleGUID;
wrapper.FileName = fileName;
buildinFileCatalog.Wrappers.Add(wrapper);
var fileEntry = new BuiltinCatalog.FileEntry();
fileEntry.BundleGUID = bundleGUID;
fileEntry.FileName = fileName;
buildinCatalog.FileEntries.Add(fileEntry);
}
else
{
Debug.LogWarning($"Failed mapping file : {fileName}");
Debug.LogWarning($"Failed to map file: {fileName}");
}
}
// 创建输出文件
string jsonFilePath = $"{packageDirectory}/{BuiltinFileCatalogDefine.JsonFileName}";
string jsonFilePath = $"{packageDirectory}/{BuiltinCatalogDefine.JsonFileName}";
if (File.Exists(jsonFilePath))
File.Delete(jsonFilePath);
SerializeToJson(jsonFilePath, buildinFileCatalog);
SerializeToJson(jsonFilePath, buildinCatalog);
// 创建输出文件
string binaryFilePath = $"{packageDirectory}/{BuiltinFileCatalogDefine.BinaryFileName}";
string binaryFilePath = $"{packageDirectory}/{BuiltinCatalogDefine.BinaryFileName}";
if (File.Exists(binaryFilePath))
File.Delete(binaryFilePath);
SerializeToBinary(binaryFilePath, buildinFileCatalog);
SerializeToBinary(binaryFilePath, buildinCatalog);
UnityEditor.AssetDatabase.Refresh();
Debug.Log($"Succeed to save catalog file : {binaryFilePath}");
Debug.Log($"Successfully saved catalog file: {binaryFilePath}");
return true;
}
@@ -125,71 +128,62 @@ namespace YooAsset
public static bool CreateEmptyFile(string packageName, string packageVersion, string outputPath)
{
// 创建内置清单实例
var buildinFileCatalog = new BuiltinFileCatalog();
buildinFileCatalog.FileVersion = BuiltinFileCatalogDefine.FileVersion;
var buildinFileCatalog = new BuiltinCatalog();
buildinFileCatalog.FileVersion = BuiltinCatalogDefine.FileVersion;
buildinFileCatalog.PackageName = packageName;
buildinFileCatalog.PackageVersion = packageVersion;
// 创建输出文件
string jsonFilePath = $"{outputPath}/{BuiltinFileCatalogDefine.JsonFileName}";
string jsonFilePath = $"{outputPath}/{BuiltinCatalogDefine.JsonFileName}";
if (File.Exists(jsonFilePath))
File.Delete(jsonFilePath);
SerializeToJson(jsonFilePath, buildinFileCatalog);
// 创建输出文件
string binaryFilePath = $"{outputPath}/{BuiltinFileCatalogDefine.BinaryFileName}";
string binaryFilePath = $"{outputPath}/{BuiltinCatalogDefine.BinaryFileName}";
if (File.Exists(binaryFilePath))
File.Delete(binaryFilePath);
SerializeToBinary(binaryFilePath, buildinFileCatalog);
UnityEditor.AssetDatabase.Refresh();
Debug.Log($"Succeed to save catalog file : {binaryFilePath}");
Debug.Log($"Successfully saved catalog file: {binaryFilePath}");
return true;
}
#endif
/// <summary>
/// 序列化JSON文件
/// </summary>
public static void SerializeToJson(string savePath, BuiltinFileCatalog catalog)
public static void SerializeToJson(string savePath, BuiltinCatalog catalog)
{
string json = JsonUtility.ToJson(catalog, true);
FileUtility.WriteAllText(savePath, json);
}
/// <summary>
/// 反序列化JSON文件
/// </summary>
public static BuiltinFileCatalog DeserializeFromJson(string jsonContent)
{
return JsonUtility.FromJson<BuiltinFileCatalog>(jsonContent);
}
/// <summary>
/// 序列化(二进制文件)
/// </summary>
public static void SerializeToBinary(string savePath, BuiltinFileCatalog catalog)
public static void SerializeToBinary(string savePath, BuiltinCatalog catalog)
{
using (FileStream fs = new FileStream(savePath, FileMode.Create))
{
// 创建缓存器
BufferWriter buffer = new BufferWriter(BuiltinFileCatalogDefine.FileMaxSize);
BufferWriter buffer = new BufferWriter(BuiltinCatalogDefine.MaxFileSize);
// 写入文件标记
buffer.WriteUInt32(BuiltinFileCatalogDefine.FileSign);
buffer.WriteUInt32(BuiltinCatalogDefine.FileHeader);
// 写入文件版本
buffer.WriteUTF8(BuiltinFileCatalogDefine.FileVersion);
buffer.WriteUTF8(BuiltinCatalogDefine.FileVersion);
// 写入文件头信息
buffer.WriteUTF8(catalog.PackageName);
buffer.WriteUTF8(catalog.PackageVersion);
// 写入资源包列表
buffer.WriteInt32(catalog.Wrappers.Count);
for (int i = 0; i < catalog.Wrappers.Count; i++)
buffer.WriteInt32(catalog.FileEntries.Count);
for (int i = 0; i < catalog.FileEntries.Count; i++)
{
var fileWrapper = catalog.Wrappers[i];
var fileWrapper = catalog.FileEntries[i];
buffer.WriteUTF8(fileWrapper.BundleGUID);
buffer.WriteUTF8(fileWrapper.FileName);
}
@@ -199,11 +193,20 @@ namespace YooAsset
fs.Flush();
}
}
#endif
/// <summary>
/// 反序列化JSON文件
/// </summary>
public static BuiltinCatalog DeserializeFromJson(string jsonContent)
{
return JsonUtility.FromJson<BuiltinCatalog>(jsonContent);
}
/// <summary>
/// 反序列化(二进制文件)
/// </summary>
public static BuiltinFileCatalog DeserializeFromBinary(byte[] binaryData)
public static BuiltinCatalog DeserializeFromBinary(byte[] binaryData)
{
if (binaryData == null || binaryData.Length == 0)
throw new Exception("Catalog file data is null or empty.");
@@ -212,31 +215,31 @@ namespace YooAsset
BufferReader buffer = new BufferReader(binaryData);
// 读取文件标记
uint fileSign = buffer.ReadUInt32();
if (fileSign != BuiltinFileCatalogDefine.FileSign)
uint fileHeader = buffer.ReadUInt32();
if (fileHeader != BuiltinCatalogDefine.FileHeader)
throw new Exception("Invalid catalog file.");
// 读取文件版本
string fileVersion = buffer.ReadUTF8();
if (fileVersion != BuiltinFileCatalogDefine.FileVersion)
throw new Exception($"The catalog file version are not compatible : {fileVersion} != {BuiltinFileCatalogDefine.FileVersion}");
if (fileVersion != BuiltinCatalogDefine.FileVersion)
throw new Exception($"The catalog file version is not compatible: {fileVersion} != {BuiltinCatalogDefine.FileVersion}");
BuiltinFileCatalog catalog = new BuiltinFileCatalog();
BuiltinCatalog catalog = new BuiltinCatalog();
{
// 读取文件头信息
catalog.FileVersion = fileVersion;
catalog.PackageName = buffer.ReadUTF8();
catalog.PackageVersion = buffer.ReadUTF8();
// 读取资源包列表
// 读取文件条目列表
int fileCount = buffer.ReadInt32();
catalog.Wrappers = new List<BuiltinFileCatalog.FileWrapper>(fileCount);
catalog.FileEntries = new List<BuiltinCatalog.FileEntry>(fileCount);
for (int i = 0; i < fileCount; i++)
{
var fileWrapper = new BuiltinFileCatalog.FileWrapper();
fileWrapper.BundleGUID = buffer.ReadUTF8();
fileWrapper.FileName = buffer.ReadUTF8();
catalog.Wrappers.Add(fileWrapper);
var fileEntry = new BuiltinCatalog.FileEntry();
fileEntry.BundleGUID = buffer.ReadUTF8();
fileEntry.FileName = buffer.ReadUTF8();
catalog.FileEntries.Add(fileEntry);
}
}

View File

@@ -1,10 +1,16 @@
using System;
using System;
using System.Collections.Generic;
namespace YooAsset
{
/// <summary>
/// 内置文件缓存系统,用于管理 StreamingAssets 中的资源包
/// </summary>
internal class BuiltinFileCache : IFileCache
{
/// <summary>
/// 内置文件缓存配置
/// </summary>
internal struct CacheConfig
{
/// <summary>
@@ -18,14 +24,16 @@ namespace YooAsset
public IBundleDecryptor RawBundleDecryptor { get; set; }
/// <summary>
/// 下载后台接口
/// 下载后台
/// </summary>
public IDownloadBackend DownloadBackend { get; set; }
}
private readonly Dictionary<string, BuiltinFileCacheEntry> _caches = new Dictionary<string, BuiltinFileCacheEntry>(10000);
private readonly Dictionary<string, BuiltinFileCacheEntry> _cacheEntries = new Dictionary<string, BuiltinFileCacheEntry>(10000);
// 缓存配置
/// <summary>
/// 缓存配置
/// </summary>
internal readonly CacheConfig Config;
#region
@@ -51,7 +59,7 @@ namespace YooAsset
{
get
{
return _caches.Count;
return _cacheEntries.Count;
}
}
@@ -62,6 +70,12 @@ namespace YooAsset
public long SpaceOccupied { get; private set; }
#endregion
/// <summary>
/// 创建内置文件缓存系统实例
/// </summary>
/// <param name="packageName">包裹名称</param>
/// <param name="rootPath">缓存根目录</param>
/// <param name="config">缓存配置</param>
public BuiltinFileCache(string packageName, string rootPath, CacheConfig config)
{
PackageName = packageName;
@@ -77,7 +91,7 @@ namespace YooAsset
var operation = new BFCInitializeOperation(this);
return operation;
}
public virtual FCWriteCacheOperation WriteCacheAsync(WriteCacheOptions options)
public virtual FCWriteCacheOperation WriteCacheAsync(FCWriteCacheOptions options)
{
var operation = new FCWriteCacheCompleteOperation($"{nameof(BuiltinFileCache)} is readonly.");
return operation;
@@ -87,12 +101,12 @@ namespace YooAsset
var operation = new FCClearCacheCompleteOperation($"{nameof(BuiltinFileCache)} is readonly.");
return operation;
}
public virtual FCVerifyCacheOperation VerifyCacheAsync(VerifyCacheOptions options)
public virtual FCVerifyCacheOperation VerifyCacheAsync(FCVerifyCacheOptions options)
{
var operation = new FCVerifyCacheCompleteOperation();
return operation;
}
public virtual FCLoadBundleOperation LoadBundleAsync(LoadBundleOptions options)
public virtual FCLoadBundleOperation LoadBundleAsync(FCLoadBundleOptions options)
{
if (options.Bundle.BundleType == (int)EBundleType.AssetBundle)
{
@@ -113,16 +127,16 @@ namespace YooAsset
}
public virtual bool IsCached(string bundleGUID)
{
return _caches.ContainsKey(bundleGUID);
return _cacheEntries.ContainsKey(bundleGUID);
}
#region
/// <summary>
/// 获取指定缓存
/// </summary>
public BuiltinFileCacheEntry GetEntry(string bundleGUID)
internal BuiltinFileCacheEntry GetEntry(string bundleGUID)
{
if (_caches.TryGetValue(bundleGUID, out BuiltinFileCacheEntry entry))
if (_cacheEntries.TryGetValue(bundleGUID, out BuiltinFileCacheEntry entry))
return entry;
else
return null;
@@ -131,12 +145,12 @@ namespace YooAsset
/// <summary>
/// 添加指定缓存
/// </summary>
internal void AddEntry(string bundleGUID, BuiltinFileCacheEntry entry)
internal void AddEntry(string bundleGUID, BuiltinFileCacheEntry cacheEntry)
{
if (_caches.ContainsKey(bundleGUID))
throw new YooInternalException($"Cache entry already existed: {bundleGUID}");
if (_cacheEntries.ContainsKey(bundleGUID))
throw new YooInternalException($"Cache entry already exists: {bundleGUID}");
_caches.Add(bundleGUID, entry);
_cacheEntries.Add(bundleGUID, cacheEntry);
}
/// <summary>
@@ -144,7 +158,7 @@ namespace YooAsset
/// </summary>
internal string GetCatalogBinaryFileLoadPath()
{
return PathUtility.Combine(RootPath, BuiltinFileCatalogDefine.BinaryFileName);
return PathUtility.Combine(RootPath, BuiltinCatalogDefine.BinaryFileName);
}
#endregion
}

View File

@@ -1,11 +1,26 @@

namespace YooAsset
{
/// <summary>
/// 内置文件缓存条目
/// </summary>
internal class BuiltinFileCacheEntry : ICacheEntry
{
/// <summary>
/// 资源包唯一标识
/// </summary>
public string BundleGUID { get; private set; }
/// <summary>
/// 资源包文件路径
/// </summary>
public string FilePath { get; private set; }
/// <summary>
/// 创建内置文件缓存条目
/// </summary>
/// <param name="bundleGUID">资源包唯一标识</param>
/// <param name="filePath">资源包文件路径</param>
public BuiltinFileCacheEntry(string bundleGUID, string filePath)
{
BundleGUID = bundleGUID;

View File

@@ -1,67 +1,77 @@

namespace YooAsset
{
/// <summary>
/// 内置文件缓存初始化操作
/// </summary>
internal class BFCInitializeOperation : FCInitializeOperation
{
private enum ESteps
{
None,
LoadCatalogFile,
RecordFiles,
LoadCatalog,
RecordEntry,
Done,
}
private readonly BuiltinFileCache _fileCache;
private LoadBuiltinCatalogFileOperation _loadBuiltinCatalogFileOp;
private LoadBuiltinCatalogOperation _loadBuiltinCatalogOp;
private ESteps _steps = ESteps.None;
public BFCInitializeOperation(BuiltinFileCache cache)
public BFCInitializeOperation(BuiltinFileCache fileCache)
{
_fileCache = cache;
_fileCache = fileCache;
}
internal override void InternalStart()
{
_steps = ESteps.LoadCatalogFile;
_steps = ESteps.LoadCatalog;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.LoadCatalogFile)
if (_steps == ESteps.LoadCatalog)
{
if (_loadBuiltinCatalogFileOp == null)
if (_loadBuiltinCatalogOp == null)
{
_loadBuiltinCatalogFileOp = new LoadBuiltinCatalogFileOperation(_fileCache);
_loadBuiltinCatalogFileOp.StartOperation();
AddChildOperation(_loadBuiltinCatalogFileOp);
var options = new LoadBuiltinCatalogOptions();
options.PackageName = _fileCache.PackageName;
options.FilePath = _fileCache.GetCatalogBinaryFileLoadPath();
options.DownloadBackend = _fileCache.Config.DownloadBackend;
_loadBuiltinCatalogOp = new LoadBuiltinCatalogOperation(options);
_loadBuiltinCatalogOp.StartOperation();
AddChildOperation(_loadBuiltinCatalogOp);
}
_loadBuiltinCatalogFileOp.UpdateOperation();
if (_loadBuiltinCatalogFileOp.IsDone == false)
_loadBuiltinCatalogOp.UpdateOperation();
if (_loadBuiltinCatalogOp.IsDone == false)
return;
if (_loadBuiltinCatalogFileOp.Status == EOperationStatus.Succeeded)
if (_loadBuiltinCatalogOp.Status == EOperationStatus.Succeeded)
{
_steps = ESteps.RecordFiles;
_steps = ESteps.RecordEntry;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _loadBuiltinCatalogFileOp.Error;
Error = _loadBuiltinCatalogOp.Error;
}
}
if (_steps == ESteps.RecordFiles)
if (_steps == ESteps.RecordEntry)
{
var catalog = _loadBuiltinCatalogFileOp.Catalog;
foreach (var wrapper in catalog.Wrappers)
var catalog = _loadBuiltinCatalogOp.Catalog;
foreach (var fileEntry in catalog.FileEntries)
{
string filePath = PathUtility.Combine(_fileCache.RootPath, wrapper.FileName);
var entry = new BuiltinFileCacheEntry(wrapper.BundleGUID, filePath);
_fileCache.AddEntry(wrapper.BundleGUID, entry);
string filePath = PathUtility.Combine(_fileCache.RootPath, fileEntry.FileName);
var cacheEntry = new BuiltinFileCacheEntry(fileEntry.BundleGUID, filePath);
_fileCache.AddEntry(fileEntry.BundleGUID, cacheEntry);
}
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
}
}
}

View File

@@ -1,6 +1,9 @@

namespace YooAsset
{
/// <summary>
/// 内置文件缓存加载 AssetBundle 操作
/// </summary>
internal class BFCLoadAssetBundleOperation : FCLoadBundleOperation
{
private enum ESteps
@@ -38,7 +41,7 @@ namespace YooAsset
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Not found file cache entry: {_bundle.BundleGUID}";
Error = $"File cache entry not found: {_bundle.BundleGUID}";
}
else
{
@@ -54,7 +57,7 @@ namespace YooAsset
options.CacheName = _fileCache.GetType().Name;
options.Bundle = _bundle;
options.FilePath = _cacheEntry.FilePath;
options.Decryptor = _fileCache.Config.AssetBundleDecryptor;
options.AssetBundleDecryptor = _fileCache.Config.AssetBundleDecryptor;
_loadLocalAssetBundleOp = new LoadLocalAssetBundleOperation(options);
_loadLocalAssetBundleOp.StartOperation();
AddChildOperation(_loadLocalAssetBundleOp);
@@ -70,7 +73,7 @@ namespace YooAsset
if (_loadLocalAssetBundleOp.Status == EOperationStatus.Succeeded)
{
if (_loadLocalAssetBundleOp.BundleResult == null)
throw new YooInternalException("Loaded asset bundle result is null.");
throw new YooInternalException("Loaded bundle result is null.");
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
@@ -90,6 +93,9 @@ namespace YooAsset
}
}
/// <summary>
/// 内置文件缓存加载 RawBundle 操作
/// </summary>
internal class BFCLoadRawBundleOperation : FCLoadBundleOperation
{
private enum ESteps
@@ -127,7 +133,7 @@ namespace YooAsset
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Not found file cache entry: {_bundle.BundleGUID}";
Error = $"File cache entry not found: {_bundle.BundleGUID}";
}
else
{
@@ -143,7 +149,7 @@ namespace YooAsset
options.CacheName = _fileCache.GetType().Name;
options.Bundle = _bundle;
options.FilePath = _cacheEntry.FilePath;
options.Decryptor = _fileCache.Config.AssetBundleDecryptor;
options.RawBundleDecryptor = _fileCache.Config.RawBundleDecryptor;
_loadLocalRawBundleOp = new LoadLocalRawBundleOperation(options);
_loadLocalRawBundleOp.StartOperation();
AddChildOperation(_loadLocalRawBundleOp);
@@ -159,8 +165,10 @@ namespace YooAsset
if(_loadLocalRawBundleOp.Status == EOperationStatus.Succeeded)
{
if (_loadLocalRawBundleOp.BundleResult == null)
throw new YooInternalException("Loaded raw bundle result is null.");
throw new YooInternalException("Loaded bundle result is null.");
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
BundleResult = _loadLocalRawBundleOp.BundleResult;
}
else

View File

@@ -1,112 +0,0 @@
using System;
using System.IO;
namespace YooAsset
{
internal sealed class LoadBuiltinCatalogFileOperation : AsyncOperationBase
{
private enum ESteps
{
None,
TryLoadFileData,
RequestFileData,
LoadCatalog,
CheckResut,
Done,
}
private readonly BuiltinFileCache _fileCache;
private IDownloadBytesRequest _webDataRequestOp;
private byte[] _fileData;
private ESteps _steps = ESteps.None;
/// <summary>
/// 内置资源目录
/// </summary>
public BuiltinFileCatalog Catalog;
internal LoadBuiltinCatalogFileOperation(BuiltinFileCache fileCache)
{
_fileCache = fileCache;
}
internal override void InternalStart()
{
_steps = ESteps.TryLoadFileData;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.TryLoadFileData)
{
string filePath = _fileCache.GetCatalogBinaryFileLoadPath();
if (File.Exists(filePath))
{
_fileData = File.ReadAllBytes(filePath);
_steps = ESteps.LoadCatalog;
}
else
{
_steps = ESteps.RequestFileData;
}
}
if (_steps == ESteps.RequestFileData)
{
if (_webDataRequestOp == null)
{
string filePath = _fileCache.GetCatalogBinaryFileLoadPath();
string url = DownloadSystemTools.ToLocalUrl(filePath);
var args = new DownloadDataRequestArgs(url, 60, 0);
_webDataRequestOp = _fileCache.Config.DownloadBackend.CreateBytesRequest(args);
_webDataRequestOp.SendRequest();
}
if (_webDataRequestOp.IsDone == false)
return;
if (_webDataRequestOp.Status == EDownloadRequestStatus.Succeeded)
{
_fileData = _webDataRequestOp.Result;
_steps = ESteps.LoadCatalog;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _webDataRequestOp.Error;
}
}
if (_steps == ESteps.LoadCatalog)
{
try
{
Catalog = BuiltinFileCatalogTools.DeserializeFromBinary(_fileData);
_steps = ESteps.CheckResut;
}
catch (Exception ex)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Failed to load catalog file : {ex.Message}";
}
}
if (_steps == ESteps.CheckResut)
{
if (Catalog.PackageName != _fileCache.PackageName)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Catalog file package name {Catalog.PackageName} cannot match the file cache package name {_fileCache.PackageName}";
return;
}
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
}
}
}
}

View File

@@ -1,21 +1,44 @@
using System;
using System;
using System.Collections.Generic;
namespace YooAsset
{
/// <summary>
/// 编辑器文件缓存系统,用于编辑器模式下的资源模拟加载
/// </summary>
internal class EditorFileCache : IFileCache
{
/// <summary>
/// 编辑器文件缓存配置
/// </summary>
internal struct CacheConfig
{
/// <summary>
/// 虚拟下载模式,模拟资源下载流程
/// </summary>
public bool VirtualDownloadMode { get; set; }
/// <summary>
/// 虚拟WebGL模式
/// </summary>
public bool VirtualWebGLMode { get; set; }
/// <summary>
/// 异步模拟最小帧数
/// </summary>
public int AsyncSimulateMinFrame { get; set; }
/// <summary>
/// 异步模拟最大帧数
/// </summary>
public int AsyncSimulateMaxFrame { get; set; }
}
private readonly Dictionary<string, EditorFileCacheEntry> _caches = new Dictionary<string, EditorFileCacheEntry>(10000);
private readonly Dictionary<string, EditorFileCacheEntry> _cacheEntries = new Dictionary<string, EditorFileCacheEntry>(10000);
// 缓存配置
/// <summary>
/// 缓存配置
/// </summary>
internal readonly CacheConfig Config;
#region
@@ -41,7 +64,7 @@ namespace YooAsset
{
get
{
return _caches.Count;
return _cacheEntries.Count;
}
}
@@ -52,6 +75,12 @@ namespace YooAsset
public long SpaceOccupied { get; private set; }
#endregion
/// <summary>
/// 创建编辑器文件缓存系统实例
/// </summary>
/// <param name="packageName">包裹名称</param>
/// <param name="rootPath">缓存根目录</param>
/// <param name="config">缓存配置</param>
public EditorFileCache(string packageName, string rootPath, CacheConfig config)
{
PackageName = packageName;
@@ -67,7 +96,7 @@ namespace YooAsset
var operation = new EFCInitializeOperation(this);
return operation;
}
public virtual FCWriteCacheOperation WriteCacheAsync(WriteCacheOptions options)
public virtual FCWriteCacheOperation WriteCacheAsync(FCWriteCacheOptions options)
{
var operation = new EFCWriteCacheOperation(this, options);
return operation;
@@ -77,16 +106,16 @@ namespace YooAsset
var operation = new FCClearCacheCompleteOperation();
return operation;
}
public virtual FCVerifyCacheOperation VerifyCacheAsync(VerifyCacheOptions options)
public virtual FCVerifyCacheOperation VerifyCacheAsync(FCVerifyCacheOptions options)
{
var operation = new FCVerifyCacheCompleteOperation();
return operation;
}
public virtual FCLoadBundleOperation LoadBundleAsync(LoadBundleOptions options)
public virtual FCLoadBundleOperation LoadBundleAsync(FCLoadBundleOptions options)
{
if (options.Bundle.BundleType == (int)EBundleType.VirtualBundle)
{
var operation = new EFCLoadVirtualBundleOperation(this, options.Bundle);
var operation = new EFCLoadBundleOperation(this, options.Bundle);
return operation;
}
else
@@ -99,32 +128,21 @@ namespace YooAsset
public virtual bool IsCached(string bundleGUID)
{
if (Config.VirtualDownloadMode)
return _caches.ContainsKey(bundleGUID);
return _cacheEntries.ContainsKey(bundleGUID);
else
return true;
}
#region
/// <summary>
/// 获取指定缓存
/// </summary>
public EditorFileCacheEntry GetEntry(string bundleGUID)
{
if (_caches.TryGetValue(bundleGUID, out EditorFileCacheEntry entry))
return entry;
else
return null;
}
/// <summary>
/// 添加指定缓存
/// </summary>
internal void AddEntry(string bundleGUID, EditorFileCacheEntry entry)
internal void AddEntry(string bundleGUID, EditorFileCacheEntry cacheEntry)
{
if (_caches.ContainsKey(bundleGUID))
throw new YooInternalException($"Cache entry already existed: {bundleGUID}");
if (_cacheEntries.ContainsKey(bundleGUID))
throw new YooInternalException($"Cache entry already exists: {bundleGUID}");
_caches.Add(bundleGUID, entry);
_cacheEntries.Add(bundleGUID, cacheEntry);
}
#endregion
}

View File

@@ -1,11 +1,26 @@

namespace YooAsset
{
/// <summary>
/// 编辑器文件缓存条目
/// </summary>
internal class EditorFileCacheEntry : ICacheEntry
{
/// <summary>
/// 资源包唯一标识
/// </summary>
public string BundleGUID { get; private set; }
/// <summary>
/// 资源包文件路径
/// </summary>
public string FilePath { get; private set; }
/// <summary>
/// 创建编辑器文件缓存条目
/// </summary>
/// <param name="bundleGUID">资源包唯一标识</param>
/// <param name="filePath">资源包文件路径</param>
public EditorFileCacheEntry(string bundleGUID, string filePath)
{
BundleGUID = bundleGUID;

View File

@@ -1,6 +1,9 @@

namespace YooAsset
{
/// <summary>
/// 编辑器文件缓存初始化操作
/// </summary>
internal class EFCInitializeOperation : FCInitializeOperation
{
private readonly EditorFileCache _fileCache;

View File

@@ -1,13 +1,16 @@

namespace YooAsset
{
internal class EFCLoadVirtualBundleOperation : FCLoadBundleOperation
/// <summary>
/// 编辑器文件缓存加载资源包操作
/// </summary>
internal class EFCLoadBundleOperation : FCLoadBundleOperation
{
private enum ESteps
{
None,
LoadVirtualBundle,
CheckResult,
CheckCache,
LoadBundle,
Done,
}
@@ -16,14 +19,14 @@ namespace YooAsset
private int _asyncSimulateFrame;
private ESteps _steps = ESteps.None;
public EFCLoadVirtualBundleOperation(EditorFileCache fileCache, PackageBundle bundle)
public EFCLoadBundleOperation(EditorFileCache fileCache, PackageBundle bundle)
{
_fileCache = fileCache;
_bundle = bundle;
}
internal override void InternalStart()
{
_steps = ESteps.LoadVirtualBundle;
_steps = ESteps.CheckCache;
_asyncSimulateFrame = GetAsyncSimulateFrame();
}
internal override void InternalUpdate()
@@ -31,21 +34,20 @@ namespace YooAsset
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.LoadVirtualBundle)
if (_steps == ESteps.CheckCache)
{
var entry = _fileCache.GetEntry(_bundle.BundleGUID);
if (entry == null)
if (_fileCache.IsCached(_bundle.BundleGUID) == false)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Not found file cache entry: {_bundle.BundleGUID}";
Error = $"File cache entry not found: {_bundle.BundleGUID}";
return;
}
_steps = ESteps.CheckResult;
_steps = ESteps.LoadBundle;
}
if (_steps == ESteps.CheckResult)
if (_steps == ESteps.LoadBundle)
{
if (IsWaitForCompletion)
{
@@ -53,12 +55,15 @@ namespace YooAsset
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = "WebGL mode only support asyn load method.";
Error = "WebGL mode only supports async load method.";
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
string editorFilePath = EditorFileSystemTools.GetEditorFilePath(_bundle);
BundleResult = new VirtualBundleResult(editorFilePath, _bundle);
}
}
else
@@ -68,6 +73,9 @@ namespace YooAsset
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
string editorFilePath = EditorFileSystemTools.GetEditorFilePath(_bundle);
BundleResult = new VirtualBundleResult(editorFilePath, _bundle);
}
}
}

View File

@@ -1,43 +1,44 @@
using System;
using System.IO;
namespace YooAsset
{
/// <summary>
/// 编辑器文件缓存写入操作
/// </summary>
internal class EFCWriteCacheOperation : FCWriteCacheOperation
{
private enum ESteps
{
None,
Check,
CheckCache,
CacheFile,
Done,
}
private readonly EditorFileCache _cache;
private readonly WriteCacheOptions _options;
private readonly EditorFileCache _fileCache;
private readonly FCWriteCacheOptions _options;
private ESteps _steps = ESteps.None;
public EFCWriteCacheOperation(EditorFileCache cache, WriteCacheOptions options)
public EFCWriteCacheOperation(EditorFileCache cache, FCWriteCacheOptions options)
{
_cache = cache;
_fileCache = cache;
_options = options;
}
internal override void InternalStart()
{
_steps = ESteps.Check;
_steps = ESteps.CheckCache;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.Check)
if (_steps == ESteps.CheckCache)
{
if (_cache.IsCached(_options.Bundle.BundleGUID))
if (_fileCache.IsCached(_options.Bundle.BundleGUID))
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = "The bundle is cached.";
Error = "The bundle is already cached.";
}
else
{
@@ -48,7 +49,7 @@ namespace YooAsset
if (_steps == ESteps.CacheFile)
{
var cacheEntry = new EditorFileCacheEntry(_options.Bundle.BundleGUID, _options.FilePath);
_cache.AddEntry(_options.Bundle.BundleGUID, cacheEntry);
_fileCache.AddEntry(_options.Bundle.BundleGUID, cacheEntry);
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
}

View File

@@ -9,8 +9,13 @@ namespace YooAsset
/// <summary>
/// 验证异常
/// </summary>
Exception = -7,
Exception = -8,
/// <summary>
/// 数据无效
/// </summary>
BytesDataInvalid = -7,
/// <summary>
/// 未找到缓存信息
/// </summary>

View File

@@ -1,13 +1,20 @@
using System;
using System;
using System.IO;
namespace YooAsset
{
/// <summary>
/// 文件校验工具类
/// </summary>
internal class FileVerifyTools
{
/// <summary>
/// 文件校验
/// 校验文件完整性
/// </summary>
/// <param name="filePath">文件路径</param>
/// <param name="fileSize">期望的文件大小</param>
/// <param name="fileCRC">期望的文件CRC值</param>
/// <returns>校验结果</returns>
public static EFileVerifyResult FileVerify(string filePath, long fileSize, uint fileCRC)
{
try
@@ -15,7 +22,7 @@ namespace YooAsset
if (File.Exists(filePath) == false)
return EFileVerifyResult.DataFileNotExisted;
// 验证文件大小
// 可选条件:验证文件大小
if (fileSize > 0)
{
long size = FileUtility.GetFileSize(filePath);
@@ -25,7 +32,7 @@ namespace YooAsset
return EFileVerifyResult.FileOverflow;
}
// 验证文件CRC
// 可选条件:验证文件CRC
if (fileCRC > 0)
{
uint crc = HashUtility.ComputeFileCRC32AsUInt(filePath);
@@ -41,7 +48,52 @@ namespace YooAsset
}
catch (Exception ex)
{
YooLogger.Error($"File verify exception : {ex.Message}");
YooLogger.Error($"File verification exception: {ex.Message}");
return EFileVerifyResult.Exception;
}
}
/// <summary>
/// 校验文件完整性
/// </summary>
/// <param name="fileData">文件数据</param>
/// <param name="fileSize">期望的文件大小</param>
/// <param name="fileCRC">期望的文件CRC值</param>
/// <returns>校验结果</returns>
public static EFileVerifyResult FileVerify(byte[] fileData, long fileSize, uint fileCRC)
{
try
{
if (fileData == null || fileData.Length == 0)
return EFileVerifyResult.BytesDataInvalid;
// 可选条件:验证文件大小
if (fileSize > 0)
{
long size = fileData.Length;
if (size < fileSize)
return EFileVerifyResult.FileNotComplete;
else if (size > fileSize)
return EFileVerifyResult.FileOverflow;
}
// 可选条件验证文件CRC
if (fileCRC > 0)
{
uint crc = HashUtility.ComputeBytesCRC32AsUInt(fileData);
if (crc == fileCRC)
return EFileVerifyResult.Succeed;
else
return EFileVerifyResult.FileCrcError;
}
else
{
return EFileVerifyResult.Succeed;
}
}
catch (Exception ex)
{
YooLogger.Error($"File verification exception: {ex.Message}");
return EFileVerifyResult.Exception;
}
}

View File

@@ -1,9 +1,11 @@
using System.Collections.Generic;
using System.Linq;
using System.Collections.Generic;
namespace YooAsset
{
internal class ClearCacheFilesOperation : FCClearCacheOperation
/// <summary>
/// 清理缓存文件操作
/// </summary>
internal class ClearCacheFilesOperation : AsyncOperationBase
{
private enum ESteps
{
@@ -13,14 +15,14 @@ namespace YooAsset
Done,
}
private readonly SandboxFileCache _cache;
private readonly SandboxFileCache _fileCache;
private readonly List<string> _bundleGUIDs;
private int _clearFileTotalCount;
private int _fileTotalCount;
private ESteps _steps = ESteps.None;
public ClearCacheFilesOperation(SandboxFileCache cache, List<string> bundleGUIDs)
public ClearCacheFilesOperation(SandboxFileCache fileCache, List<string> bundleGUIDs)
{
_cache = cache;
_fileCache = fileCache;
_bundleGUIDs = bundleGUIDs;
}
internal override void InternalStart()
@@ -41,7 +43,7 @@ namespace YooAsset
return;
}
_clearFileTotalCount = _bundleGUIDs.Count;
_fileTotalCount = _bundleGUIDs.Count;
_steps = ESteps.ClearCache;
}
@@ -50,16 +52,16 @@ namespace YooAsset
for (int i = _bundleGUIDs.Count - 1; i >= 0; i--)
{
string bundleGUID = _bundleGUIDs[i];
_cache.RemoveEntry(bundleGUID);
_fileCache.RemoveEntry(bundleGUID);
_bundleGUIDs.RemoveAt(i);
if (IsBusy)
break;
}
if (_clearFileTotalCount == 0)
if (_fileTotalCount == 0)
Progress = 1.0f;
else
Progress = 1.0f - ((float)_bundleGUIDs.Count / _clearFileTotalCount);
Progress = 1.0f - ((float)_bundleGUIDs.Count / _fileTotalCount);
if (_bundleGUIDs.Count == 0)
{

View File

@@ -1,11 +1,13 @@
using System;
using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace YooAsset
{
/// <summary>
/// 搜索缓存文件操作,扫描缓存目录中的文件
/// </summary>
internal sealed class SearchCacheFilesOperation : AsyncOperationBase
{
private enum ESteps
@@ -16,7 +18,7 @@ namespace YooAsset
Done,
}
private readonly SandboxFileCache _cache;
private readonly SandboxFileCache _fileCache;
private IEnumerator<string> _filesEnumerator = null;
private double _verifyStartTime;
private ESteps _steps = ESteps.None;
@@ -24,12 +26,12 @@ namespace YooAsset
/// <summary>
/// 需要验证的元素
/// </summary>
public readonly List<VerifyFileInfo> Result = new List<VerifyFileInfo>(5000);
public readonly List<SearchFileInfo> Result = new List<SearchFileInfo>(5000);
internal SearchCacheFilesOperation(SandboxFileCache cache)
internal SearchCacheFilesOperation(SandboxFileCache fileCache)
{
_cache = cache;
_fileCache = fileCache;
}
internal override void InternalStart()
{
@@ -42,9 +44,9 @@ namespace YooAsset
if (_steps == ESteps.Prepare)
{
if (Directory.Exists(_cache.RootPath))
if (Directory.Exists(_fileCache.RootPath))
{
var directories = Directory.EnumerateDirectories(_cache.RootPath);
var directories = Directory.EnumerateDirectories(_fileCache.RootPath);
_filesEnumerator = directories.GetEnumerator();
_verifyStartTime = TimeUtility.RealtimeSinceStartup;
_steps = ESteps.SearchFiles;
@@ -80,19 +82,19 @@ namespace YooAsset
if (isFindItem == false)
break;
var rootFoder = _filesEnumerator.Current;
var childDirectories = Directory.EnumerateDirectories(rootFoder);
foreach (var chidDirectory in childDirectories)
var rootFolder = _filesEnumerator.Current;
var childDirectories = Directory.EnumerateDirectories(rootFolder);
foreach (var childDirectory in childDirectories)
{
string bundleGUID = Path.GetFileName(chidDirectory);
if (_cache.IsCached(bundleGUID))
string bundleGUID = Path.GetFileName(childDirectory);
if (_fileCache.IsCached(bundleGUID))
continue;
// 创建验证元素类
string fileRootPath = chidDirectory;
string fileRootPath = childDirectory;
string dataFilePath = PathUtility.Combine(fileRootPath, SandboxFileCacheDefine.BundleDataFileName);
string infoFilePath = PathUtility.Combine(fileRootPath, SandboxFileCacheDefine.BundleInfoFileName);
var element = new VerifyFileInfo(bundleGUID, fileRootPath, dataFilePath, infoFilePath);
var element = new SearchFileInfo(bundleGUID, fileRootPath, dataFilePath, infoFilePath);
Result.Add(element);
}

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
@@ -7,7 +7,7 @@ using System.Threading;
namespace YooAsset
{
/// <summary>
/// 缓存文件验证(线程版)
/// 缓存文件验证(线程版),验证缓存目录中的文件
/// </summary>
internal sealed class VerifyCacheFilesOperation : AsyncOperationBase
{
@@ -19,25 +19,25 @@ namespace YooAsset
Done,
}
private readonly SandboxFileCache _cache;
private readonly SandboxFileCache _fileCache;
private readonly EFileVerifyLevel _verifyLevel;
private readonly int _fileVerifyMaxConcurrency;
private readonly List<VerifyFileInfo> _waitingList;
private List<VerifyFileInfo> _verifyingList;
private int _verifyMaxNum;
private readonly List<SearchFileInfo> _pendingVerifyList;
private List<SearchFileInfo> _activeVerifyList;
private int _maxConcurrentVerifyCount;
private int _verifyTotalCount;
private double _verifyStartTime;
private int _succeedCount;
private int _successCount;
private int _failedCount;
private ESteps _steps = ESteps.None;
internal VerifyCacheFilesOperation(SandboxFileCache cache, EFileVerifyLevel verifyLevel, int fileVerifyMaxConcurrency, List<VerifyFileInfo> elements)
internal VerifyCacheFilesOperation(SandboxFileCache fileCache, EFileVerifyLevel verifyLevel, int fileVerifyMaxConcurrency, List<SearchFileInfo> elements)
{
_cache = cache;
_fileCache = fileCache;
_verifyLevel = verifyLevel;
_fileVerifyMaxConcurrency = fileVerifyMaxConcurrency;
_waitingList = elements;
_pendingVerifyList = elements;
}
internal override void InternalStart()
{
@@ -52,44 +52,44 @@ namespace YooAsset
{
// 设置同时验证的最大数
int processorCount = Environment.ProcessorCount * 2 + 1;
_verifyMaxNum = Math.Min(processorCount, _fileVerifyMaxConcurrency);
if (_verifyMaxNum < 1)
_verifyMaxNum = 1;
_maxConcurrentVerifyCount = Math.Min(processorCount, _fileVerifyMaxConcurrency);
if (_maxConcurrentVerifyCount < 1)
_maxConcurrentVerifyCount = 1;
YooLogger.Log($"Verify max concurrency : {_verifyMaxNum}");
_verifyingList = new List<VerifyFileInfo>(_verifyMaxNum);
YooLogger.Log($"Verify max concurrency : {_maxConcurrentVerifyCount}");
_activeVerifyList = new List<SearchFileInfo>(_maxConcurrentVerifyCount);
_verifyStartTime = TimeUtility.RealtimeSinceStartup;
_verifyTotalCount = _waitingList.Count;
_verifyTotalCount = _pendingVerifyList.Count;
_steps = ESteps.UpdateVerify;
}
if (_steps == ESteps.UpdateVerify)
{
// 检测校验结果
for (int i = _verifyingList.Count - 1; i >= 0; i--)
for (int i = _activeVerifyList.Count - 1; i >= 0; i--)
{
var verifyElement = _verifyingList[i];
int result = verifyElement.Result;
if (result != 0)
var verifyElement = _activeVerifyList[i];
int resultCode = verifyElement.VerifyResultCode; //注意: 一次命令取值
if (resultCode != 0)
{
_verifyingList.RemoveAt(i);
if (verifyElement.Result == (int)EFileVerifyResult.Succeed)
_activeVerifyList.RemoveAt(i);
if (resultCode == (int)EFileVerifyResult.Succeed)
{
_succeedCount++;
_successCount++;
var cacheEntry = new SandboxFileCacheEntry(verifyElement.BundleGUID, verifyElement.InfoFilePath, verifyElement.DataFilePath);
_cache.AddEntry(verifyElement.BundleGUID, cacheEntry);
_fileCache.AddEntry(verifyElement.BundleGUID, cacheEntry);
}
else
{
_failedCount++;
YooLogger.Warning($"Failed to verify file {verifyElement.Result} and delete files : {verifyElement.FolderPath}");
verifyElement.DeleteFiles();
YooLogger.Warning($"File verification failed (code: {verifyElement.VerifyResultCode}). Deleting files: {verifyElement.FolderPath}");
verifyElement.DeleteCacheFolder();
}
}
}
Progress = GetProgress();
if (_waitingList.Count == 0 && _verifyingList.Count == 0)
if (_pendingVerifyList.Count == 0 && _activeVerifyList.Count == 0)
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
@@ -97,21 +97,21 @@ namespace YooAsset
YooLogger.Log($"Verify cache files elapsed time {costTime:f1} seconds");
}
for (int i = _waitingList.Count - 1; i >= 0; i--)
for (int i = _pendingVerifyList.Count - 1; i >= 0; i--)
{
if (IsBusy)
break;
if (_verifyingList.Count >= _verifyMaxNum)
if (_activeVerifyList.Count >= _maxConcurrentVerifyCount)
break;
var element = _waitingList[i];
var element = _pendingVerifyList[i];
bool succeed = ThreadPool.QueueUserWorkItem(new WaitCallback(VerifyFileInThread), element);
if (succeed == false)
VerifyFileInThread(element);
_waitingList.RemoveAt(i);
_verifyingList.Add(element);
_pendingVerifyList.RemoveAt(i);
_activeVerifyList.Add(element);
}
}
}
@@ -119,17 +119,17 @@ namespace YooAsset
{
if (_verifyTotalCount == 0)
return 1f;
return (float)(_succeedCount + _failedCount) / _verifyTotalCount;
return (float)(_successCount + _failedCount) / _verifyTotalCount;
}
// 验证缓存文件(子线程内操作)
private void VerifyFileInThread(object obj)
{
VerifyFileInfo element = (VerifyFileInfo)obj;
int verifyResult = (int)VerifyFile(element, _verifyLevel);
element.Result = verifyResult;
SearchFileInfo element = (SearchFileInfo)obj;
int verifyResultCode = (int)VerifyFile(element, _verifyLevel);
element.VerifyResultCode = verifyResultCode; //注意: 一次命令赋值
}
private EFileVerifyResult VerifyFile(VerifyFileInfo element, EFileVerifyLevel verifyLevel)
private EFileVerifyResult VerifyFile(SearchFileInfo element, EFileVerifyLevel verifyLevel)
{
try
{
@@ -145,7 +145,6 @@ namespace YooAsset
else
{
// 解析信息文件填充验证数据
// 注意:验证数据在后续流程会被使用。
byte[] binaryData = FileUtility.ReadAllBytes(element.InfoFilePath);
BufferReader buffer = new BufferReader(binaryData);
uint dataFileCRC = buffer.ReadUInt32();
@@ -161,7 +160,7 @@ namespace YooAsset
}
catch (Exception ex)
{
YooLogger.Error($"File verify exception : {ex.Message}");
YooLogger.Error($"File verification exception: {ex.Message}");
return EFileVerifyResult.Exception;
}
}

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.Threading;
namespace YooAsset
@@ -49,11 +49,11 @@ namespace YooAsset
if (_steps == ESteps.Waiting)
{
int result = _element.Result;
if (result == 0)
int resultCode = _element.VerifyResultCode; //注意: 一次命令取值
if (resultCode == 0)
return;
VerifyResult = (EFileVerifyResult)result;
VerifyResult = (EFileVerifyResult)resultCode;
if (VerifyResult == EFileVerifyResult.Succeed)
{
_steps = ESteps.Done;
@@ -63,21 +63,21 @@ namespace YooAsset
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Failed to verify file : {_element.TempFilePath} ErrorCode : {VerifyResult}";
Error = $"Failed to verify file: {_element.FilePath} ErrorCode: {VerifyResult}";
}
}
}
internal override void InternalWaitForCompletion()
{
//TODO 等待子线程验证文件完毕,该操作会挂起主线程!
//注意: 等待子线程验证文件完毕,该操作会挂起主线程!
ExecuteUntilComplete();
}
private void VerifyFileInThread(object obj)
{
TempFileInfo element = (TempFileInfo)obj;
int result = (int)FileVerifyTools.FileVerify(element.TempFilePath, element.TempFileSize, element.TempFileCRC);
element.Result = result;
int resultCode = (int)FileVerifyTools.FileVerify(element.FilePath, element.FileSize, element.FileCRC);
element.VerifyResultCode = resultCode; //注意: 一次命令赋值
}
}
}

View File

@@ -77,6 +77,9 @@ namespace YooAsset
protected abstract bool ParseOptionsStep();
}
/// <summary>
/// 清理所有沙盒缓存操作
/// </summary>
internal sealed class SFCClearAllCacheOperation : SFCClearCacheOperation
{
internal SFCClearAllCacheOperation(SandboxFileCache fileCache, ClearCacheOptions options)
@@ -84,15 +87,18 @@ namespace YooAsset
protected override bool ParseOptionsStep()
{
var allEntrys = _fileCache.GetAllEntries();
_bundleGUIDs = new List<string>(allEntrys.Count);
foreach (var entry in allEntrys)
var allEntries = _fileCache.GetAllEntries();
_bundleGUIDs = new List<string>(allEntries.Count);
foreach (var entry in allEntries)
{
_bundleGUIDs.Add(entry.BundleGUID);
}
return true;
}
}
/// <summary>
/// 清理未使用的沙盒缓存操作
/// </summary>
internal sealed class SFCClearUnusedCacheOperation : SFCClearCacheOperation
{
internal SFCClearUnusedCacheOperation(SandboxFileCache fileCache, ClearCacheOptions options)
@@ -104,13 +110,13 @@ namespace YooAsset
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = "Can not found active package manifest.";
Error = "Active package manifest not found.";
return false;
}
var allEntrys = _fileCache.GetAllEntries();
_bundleGUIDs = new List<string>(allEntrys.Count);
foreach (var entry in allEntrys)
var allEntries = _fileCache.GetAllEntries();
_bundleGUIDs = new List<string>(allEntries.Count);
foreach (var entry in allEntries)
{
if (_options.Manifest.IsIncludeBundleFile(entry.BundleGUID) == false)
{
@@ -120,6 +126,9 @@ namespace YooAsset
return true;
}
}
/// <summary>
/// 按资源地址清理沙盒缓存操作
/// </summary>
internal sealed class SFCClearCacheByLocationsOperation : SFCClearCacheOperation
{
internal SFCClearCacheByLocationsOperation(SandboxFileCache fileCache, ClearCacheOptions options)
@@ -131,7 +140,7 @@ namespace YooAsset
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = "Can not found active package manifest.";
Error = "Active package manifest not found.";
return false;
}
@@ -154,7 +163,7 @@ namespace YooAsset
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Invalid clear param : {_options.ClearParam.GetType().FullName}";
Error = $"Invalid clear param: {_options.ClearParam.GetType().FullName}";
return false;
}
@@ -171,6 +180,9 @@ namespace YooAsset
return true;
}
}
/// <summary>
/// 按标签清理沙盒缓存操作
/// </summary>
internal sealed class SFCClearCacheByTagsOperation : SFCClearCacheOperation
{
internal SFCClearCacheByTagsOperation(SandboxFileCache fileCache, ClearCacheOptions options)
@@ -182,7 +194,7 @@ namespace YooAsset
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = "Can not found active package manifest.";
Error = "Active package manifest not found.";
return false;
}
@@ -205,13 +217,13 @@ namespace YooAsset
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Invalid clear param : {_options.ClearParam.GetType().FullName}";
Error = $"Invalid clear param: {_options.ClearParam.GetType().FullName}";
return false;
}
var allEntrys = _fileCache.GetAllEntries();
_bundleGUIDs = new List<string>(allEntrys.Count);
foreach (var entry in allEntrys)
var allEntries = _fileCache.GetAllEntries();
_bundleGUIDs = new List<string>(allEntries.Count);
foreach (var entry in allEntries)
{
if (_options.Manifest.TryGetPackageBundleByBundleGUID(entry.BundleGUID, out PackageBundle bundle))
{

View File

@@ -1,6 +1,9 @@

namespace YooAsset
{
/// <summary>
/// 沙盒文件缓存初始化操作
/// </summary>
internal class SFCInitializeOperation : FCInitializeOperation
{
private enum ESteps
@@ -11,14 +14,14 @@ namespace YooAsset
Done,
}
private readonly SandboxFileCache _cache;
private readonly SandboxFileCache _fileCache;
private SearchCacheFilesOperation _searchCacheFilesOp;
private VerifyCacheFilesOperation _verifyCacheFilesOp;
private ESteps _steps = ESteps.None;
public SFCInitializeOperation(SandboxFileCache cache)
public SFCInitializeOperation(SandboxFileCache fileCache)
{
_cache = cache;
_fileCache = fileCache;
}
internal override void InternalStart()
{
@@ -33,7 +36,7 @@ namespace YooAsset
{
if (_searchCacheFilesOp == null)
{
_searchCacheFilesOp = new SearchCacheFilesOperation(_cache);
_searchCacheFilesOp = new SearchCacheFilesOperation(_fileCache);
_searchCacheFilesOp.StartOperation();
AddChildOperation(_searchCacheFilesOp);
}
@@ -43,14 +46,23 @@ namespace YooAsset
if (_searchCacheFilesOp.IsDone == false)
return;
_steps = ESteps.VerifyCacheFiles;
if (_searchCacheFilesOp.Status == EOperationStatus.Succeeded)
{
_steps = ESteps.VerifyCacheFiles;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _searchCacheFilesOp.Error;
}
}
if (_steps == ESteps.VerifyCacheFiles)
{
if (_verifyCacheFilesOp == null)
{
_verifyCacheFilesOp = new VerifyCacheFilesOperation(_cache, _cache.Config.FileVerifyLevel, _cache.Config.FileVerifyMaxConcurrency, _searchCacheFilesOp.Result);
_verifyCacheFilesOp = new VerifyCacheFilesOperation(_fileCache, _fileCache.Config.FileVerifyLevel, _fileCache.Config.FileVerifyMaxConcurrency, _searchCacheFilesOp.Result);
_verifyCacheFilesOp.StartOperation();
AddChildOperation(_verifyCacheFilesOp);
}

View File

@@ -1,9 +1,12 @@
using System;
using System;
using System.IO;
using UnityEngine;
namespace YooAsset
{
/// <summary>
/// 沙盒文件缓存加载 AssetBundle 操作
/// </summary>
internal class SFCLoadAssetBundleOperation : FCLoadBundleOperation
{
private enum ESteps
@@ -44,7 +47,7 @@ namespace YooAsset
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Not found file cache entry: {_bundle.BundleGUID}";
Error = $"File cache entry not found: {_bundle.BundleGUID}";
}
else
{
@@ -60,7 +63,7 @@ namespace YooAsset
options.CacheName = _fileCache.GetType().Name;
options.Bundle = _bundle;
options.FilePath = _cacheEntry.DataFilePath;
options.Decryptor = _fileCache.Config.AssetBundleDecryptor;
options.AssetBundleDecryptor = _fileCache.Config.AssetBundleDecryptor;
_loadLocalAssetBundleOp = new LoadLocalAssetBundleOperation(options);
_loadLocalAssetBundleOp.StartOperation();
AddChildOperation(_loadLocalAssetBundleOp);
@@ -104,9 +107,9 @@ namespace YooAsset
// 说明在AssetBundle文件加载失败的情况下我们需要重新验证文件的完整性
if (_verifyCacheOp == null)
{
var options = new VerifyCacheOptions();
var options = new FCVerifyCacheOptions();
options.Bundle = _bundle;
options.FailedDeleteCache = true;
options.DeleteCacheEntryOnFailure = true;
_verifyCacheOp = _fileCache.VerifyCacheAsync(options);
_verifyCacheOp.StartOperation();
AddChildOperation(_verifyCacheOp);
@@ -147,7 +150,7 @@ namespace YooAsset
return;
}
assetBundle = FallbackLoadDecryptAssetBundle(_fileCache.Config.AssetBundleFallbackDecryptor);
assetBundle = FallbackLoadEncryptedAssetBundle(_fileCache.Config.AssetBundleFallbackDecryptor);
if (assetBundle == null)
{
_steps = ESteps.Done;
@@ -182,20 +185,21 @@ namespace YooAsset
private AssetBundle FallbackLoadAssetBundle()
{
byte[] fileData = FileUtility.ReadAllBytes(_cacheEntry.DataFilePath);
if (fileData == null || fileData.Length == 0)
return null;
return AssetBundle.LoadFromMemory(fileData);
}
private AssetBundle FallbackLoadDecryptAssetBundle(IBundleMemoryDecryptor decryptor)
private AssetBundle FallbackLoadEncryptedAssetBundle(IBundleMemoryDecryptor decryptor)
{
var args = new BundleDecryptArgs();
args.Bundle = _bundle;
args.FilePath = _cacheEntry.DataFilePath;
var binaryData = decryptor.GetDecryptData(args);
return AssetBundle.LoadFromMemory(binaryData);
var fileData = decryptor.GetDecryptData(args);
return AssetBundle.LoadFromMemory(fileData);
}
}
/// <summary>
/// 沙盒文件缓存加载 RawBundle 操作
/// </summary>
internal class SFCLoadRawBundleOperation : FCLoadBundleOperation
{
private enum ESteps
@@ -234,7 +238,7 @@ namespace YooAsset
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Not found file cache entry: {_bundle.BundleGUID}";
Error = $"File cache entry not found: {_bundle.BundleGUID}";
}
else
{
@@ -250,7 +254,7 @@ namespace YooAsset
options.CacheName = _fileCache.GetType().Name;
options.Bundle = _bundle;
options.FilePath = _cacheEntry.DataFilePath;
options.Decryptor = _fileCache.Config.AssetBundleDecryptor;
options.RawBundleDecryptor = _fileCache.Config.RawBundleDecryptor;
_loadLocalRawBundleOp = new LoadLocalRawBundleOperation(options);
_loadLocalRawBundleOp.StartOperation();
AddChildOperation(_loadLocalRawBundleOp);
@@ -268,6 +272,8 @@ namespace YooAsset
if (_loadLocalRawBundleOp.BundleResult == null)
throw new YooInternalException("Loaded raw bundle result is null.");
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
BundleResult = _loadLocalRawBundleOp.BundleResult;
}
else

View File

@@ -1,6 +1,9 @@

namespace YooAsset
{
/// <summary>
/// 沙盒文件缓存验证操作
/// </summary>
internal class SFCVerifyCacheOperation : FCVerifyCacheOperation
{
private enum ESteps
@@ -12,11 +15,11 @@ namespace YooAsset
}
private readonly SandboxFileCache _fileCache;
private readonly VerifyCacheOptions _options;
private VerifyTempFileOperation _verifyOperation;
private readonly FCVerifyCacheOptions _options;
private VerifyTempFileOperation _verifyTempFileOp;
private ESteps _steps = ESteps.None;
public SFCVerifyCacheOperation(SandboxFileCache cache, VerifyCacheOptions options)
public SFCVerifyCacheOperation(SandboxFileCache cache, FCVerifyCacheOptions options)
{
_fileCache = cache;
_options = options;
@@ -36,7 +39,7 @@ namespace YooAsset
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = "Not found cached bundle.";
Error = "Cached bundle not found.";
}
else
{
@@ -46,23 +49,23 @@ namespace YooAsset
if (_steps == ESteps.VerifyFile)
{
if (_verifyOperation == null)
if (_verifyTempFileOp == null)
{
var entry = _fileCache.GetEntry(_options.Bundle.BundleGUID);
var element = new TempFileInfo(entry.DataFilePath, _options.Bundle.FileCRC, _options.Bundle.FileSize);
_verifyOperation = new VerifyTempFileOperation(element);
_verifyOperation.StartOperation();
AddChildOperation(_verifyOperation);
_verifyTempFileOp = new VerifyTempFileOperation(element);
_verifyTempFileOp.StartOperation();
AddChildOperation(_verifyTempFileOp);
}
if (IsWaitForCompletion)
_verifyOperation.WaitForCompletion();
_verifyTempFileOp.WaitForCompletion();
_verifyOperation.UpdateOperation();
if (_verifyOperation.IsDone == false)
_verifyTempFileOp.UpdateOperation();
if (_verifyTempFileOp.IsDone == false)
return;
if (_verifyOperation.Status == EOperationStatus.Succeeded)
if (_verifyTempFileOp.Status == EOperationStatus.Succeeded)
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
@@ -71,11 +74,11 @@ namespace YooAsset
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _verifyOperation.Error;
Error = _verifyTempFileOp.Error;
if (_options.FailedDeleteCache)
if (_options.DeleteCacheEntryOnFailure)
{
YooLogger.Error($"Find corrupted bundle file and remove cache entry : {_options.Bundle.BundleGUID}");
YooLogger.Error($"Found corrupted bundle file. Removing cache entry: {_options.Bundle.BundleGUID}");
_fileCache.RemoveEntry(_options.Bundle.BundleGUID);
}
}

View File

@@ -3,6 +3,9 @@ using System.IO;
namespace YooAsset
{
/// <summary>
/// 沙盒文件缓存写入操作
/// </summary>
internal class SFCWriteCacheOperation : FCWriteCacheOperation
{
private enum ESteps
@@ -14,14 +17,14 @@ namespace YooAsset
Done,
}
private readonly SandboxFileCache _cache;
private readonly WriteCacheOptions _options;
private VerifyTempFileOperation _verifyOperation;
private readonly SandboxFileCache _fileCache;
private readonly FCWriteCacheOptions _options;
private VerifyTempFileOperation _verifyTempFileOp;
private ESteps _steps = ESteps.None;
public SFCWriteCacheOperation(SandboxFileCache cache, WriteCacheOptions options)
public SFCWriteCacheOperation(SandboxFileCache fileCache, FCWriteCacheOptions options)
{
_cache = cache;
_fileCache = fileCache;
_options = options;
}
internal override void InternalStart()
@@ -35,11 +38,11 @@ namespace YooAsset
if (_steps == ESteps.Check)
{
if (_cache.IsCached(_options.Bundle.BundleGUID))
if (_fileCache.IsCached(_options.Bundle.BundleGUID))
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = "The bundle is cached.";
Error = "The bundle is already cached.";
}
else
{
@@ -49,22 +52,22 @@ namespace YooAsset
if (_steps == ESteps.VerifyFile)
{
if (_verifyOperation == null)
if (_verifyTempFileOp == null)
{
var element = new TempFileInfo(_options.FilePath, _options.Bundle.FileCRC, _options.Bundle.FileSize);
_verifyOperation = new VerifyTempFileOperation(element);
_verifyOperation.StartOperation();
AddChildOperation(_verifyOperation);
_verifyTempFileOp = new VerifyTempFileOperation(element);
_verifyTempFileOp.StartOperation();
AddChildOperation(_verifyTempFileOp);
}
if (IsWaitForCompletion)
_verifyOperation.WaitForCompletion();
_verifyTempFileOp.WaitForCompletion();
_verifyOperation.UpdateOperation();
if (_verifyOperation.IsDone == false)
_verifyTempFileOp.UpdateOperation();
if (_verifyTempFileOp.IsDone == false)
return;
if (_verifyOperation.Status == EOperationStatus.Succeeded)
if (_verifyTempFileOp.Status == EOperationStatus.Succeeded)
{
_steps = ESteps.CacheFile;
}
@@ -72,37 +75,45 @@ namespace YooAsset
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _verifyOperation.Error;
Error = _verifyTempFileOp.Error;
}
}
if (_steps == ESteps.CacheFile)
{
string infoFilePath = _cache.GetInfoFilePath(_options.Bundle);
string dataFilePath = _cache.GetDataFilePath(_options.Bundle);
string dataFilePath = _fileCache.GetDataFilePath(_options.Bundle);
string infoFilePath = _fileCache.GetInfoFilePath(_options.Bundle);
string dataTempPath = _fileCache.GetDataTempFilePath(_options.Bundle);
string infoTempPath = _fileCache.GetInfoTempFilePath(_options.Bundle);
try
{
if (File.Exists(infoFilePath))
File.Delete(infoFilePath);
if (File.Exists(dataFilePath))
File.Delete(dataFilePath);
// 拷贝数据文件
// 阶段A准备目标目录清理可能存在的残留文件
FileUtility.EnsureFileDirectory(dataFilePath);
FileInfo fileInfo = new FileInfo(_options.FilePath);
fileInfo.CopyTo(dataFilePath, true);
DeleteFileSafely(dataTempPath);
DeleteFileSafely(infoTempPath);
// 写入信息文件
FileUtility.EnsureFileDirectory(infoFilePath);
using (FileStream fs = new FileStream(infoFilePath, FileMode.Create, FileAccess.Write, FileShare.Read))
// 阶段B写入临时文件
FileInfo fileInfo = new FileInfo(_options.FilePath);
fileInfo.CopyTo(dataTempPath, true);
using (FileStream fs = new FileStream(infoTempPath, FileMode.Create, FileAccess.Write, FileShare.Read))
{
_cache.SharedBuffer.Clear();
_cache.SharedBuffer.WriteUInt32(_options.Bundle.FileCRC);
_cache.SharedBuffer.WriteInt64(_options.Bundle.FileSize);
_cache.SharedBuffer.WriteToStream(fs);
var buffer = new BufferWriter(128);
buffer.WriteUInt32(_options.Bundle.FileCRC);
buffer.WriteInt64(_options.Bundle.FileSize);
buffer.WriteToStream(fs);
fs.Flush();
}
// 阶段C原子提交
if (File.Exists(dataFilePath))
File.Delete(dataFilePath);
File.Move(dataTempPath, dataFilePath);
if (File.Exists(infoFilePath))
File.Delete(infoFilePath);
File.Move(infoTempPath, infoFilePath);
}
catch (Exception ex)
{
@@ -110,11 +121,16 @@ namespace YooAsset
Status = EOperationStatus.Failed;
Error = $"Failed to write cache file. Error: {ex.Message}";
YooLogger.Error(Error);
return; //失败后直接返回
// 回滚:清理临时文件,正式文件不受影响
DeleteFileSafely(dataTempPath);
DeleteFileSafely(infoTempPath);
return;
}
// 阶段D注册内存缓存条目
var cacheEntry = new SandboxFileCacheEntry(_options.Bundle.BundleGUID, infoFilePath, dataFilePath);
_cache.AddEntry(_options.Bundle.BundleGUID, cacheEntry);
_fileCache.AddEntry(_options.Bundle.BundleGUID, cacheEntry);
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
}
@@ -123,5 +139,18 @@ namespace YooAsset
{
ExecuteBatch();
}
private static void DeleteFileSafely(string filePath)
{
try
{
if (File.Exists(filePath))
File.Delete(filePath);
}
catch (Exception ex)
{
YooLogger.Warning($"Failed to delete file: {filePath} Error: {ex.Message}");
}
}
}
}

View File

@@ -3,8 +3,14 @@ using System.Collections.Generic;
namespace YooAsset
{
/// <summary>
/// 沙盒文件缓存系统,用于管理下载到本地的资源包缓存
/// </summary>
internal class SandboxFileCache : IFileCache
{
/// <summary>
/// 沙盒文件缓存配置
/// </summary>
internal struct CacheConfig
{
/// <summary>
@@ -33,17 +39,16 @@ namespace YooAsset
public IBundleMemoryDecryptor AssetBundleFallbackDecryptor { get; set; }
}
private const int HashFolderLength = 2;
private readonly Dictionary<string, SandboxFileCacheEntry> _caches = new Dictionary<string, SandboxFileCacheEntry>(10000);
private const int HashFolderNameLength = 2;
private readonly Dictionary<string, SandboxFileCacheEntry> _cacheEntries = new Dictionary<string, SandboxFileCacheEntry>(10000);
private readonly Dictionary<string, string> _dataFilePathMapping = new Dictionary<string, string>(10000);
private readonly Dictionary<string, string> _infoFilePathMapping = new Dictionary<string, string>(10000);
// 缓存配置
/// <summary>
/// 缓存配置
/// </summary>
internal readonly CacheConfig Config;
// 共享缓冲区
internal readonly BufferWriter SharedBuffer = new BufferWriter(1024);
#region
/// <summary>
/// 包裹名称
@@ -67,7 +72,7 @@ namespace YooAsset
{
get
{
return _caches.Count;
return _cacheEntries.Count;
}
}
@@ -78,6 +83,12 @@ namespace YooAsset
public long SpaceOccupied { get; private set; }
#endregion
/// <summary>
/// 创建沙盒文件缓存系统实例
/// </summary>
/// <param name="packageName">包裹名称</param>
/// <param name="rootPath">缓存根目录</param>
/// <param name="config">缓存配置</param>
public SandboxFileCache(string packageName, string rootPath, CacheConfig config)
{
PackageName = packageName;
@@ -93,7 +104,7 @@ namespace YooAsset
var operation = new SFCInitializeOperation(this);
return operation;
}
public virtual FCWriteCacheOperation WriteCacheAsync(WriteCacheOptions options)
public virtual FCWriteCacheOperation WriteCacheAsync(FCWriteCacheOptions options)
{
var operation = new SFCWriteCacheOperation(this, options);
return operation;
@@ -127,12 +138,12 @@ namespace YooAsset
return operation;
}
}
public virtual FCVerifyCacheOperation VerifyCacheAsync(VerifyCacheOptions options)
public virtual FCVerifyCacheOperation VerifyCacheAsync(FCVerifyCacheOptions options)
{
var operation = new SFCVerifyCacheOperation(this, options);
return operation;
}
public virtual FCLoadBundleOperation LoadBundleAsync(LoadBundleOptions options)
public virtual FCLoadBundleOperation LoadBundleAsync(FCLoadBundleOptions options)
{
if (options.Bundle.BundleType == (int)EBundleType.AssetBundle)
{
@@ -153,7 +164,7 @@ namespace YooAsset
}
public virtual bool IsCached(string bundleGUID)
{
return _caches.ContainsKey(bundleGUID);
return _cacheEntries.ContainsKey(bundleGUID);
}
#region
@@ -185,12 +196,30 @@ namespace YooAsset
return filePath;
}
/// <summary>
/// 获取 Bundle 数据临时文件路径
/// </summary>
internal string GetDataTempFilePath(PackageBundle bundle)
{
string folderName = GetHashFolderName(bundle.FileHash);
return PathUtility.Combine(RootPath, folderName, bundle.BundleGUID, SandboxFileCacheDefine.BundleDataTempFileName);
}
/// <summary>
/// 获取 Bundle 信息临时文件路径
/// </summary>
internal string GetInfoTempFilePath(PackageBundle bundle)
{
string folderName = GetHashFolderName(bundle.FileHash);
return PathUtility.Combine(RootPath, folderName, bundle.BundleGUID, SandboxFileCacheDefine.BundleInfoTempFileName);
}
/// <summary>
/// 获取指定缓存
/// </summary>
internal SandboxFileCacheEntry GetEntry(string bundleGUID)
{
if (_caches.TryGetValue(bundleGUID, out SandboxFileCacheEntry entry))
if (_cacheEntries.TryGetValue(bundleGUID, out SandboxFileCacheEntry entry))
return entry;
else
return null;
@@ -201,19 +230,19 @@ namespace YooAsset
/// </summary>
internal IReadOnlyCollection<SandboxFileCacheEntry> GetAllEntries()
{
return _caches.Values;
return _cacheEntries.Values;
}
/// <summary>
/// 添加指定缓存
/// </summary>
internal void AddEntry(string bundleGUID, SandboxFileCacheEntry entry)
internal void AddEntry(string bundleGUID, SandboxFileCacheEntry cacheEntry)
{
if (_caches.ContainsKey(bundleGUID))
throw new YooInternalException($"Cache entry already existed: {bundleGUID}");
if (_cacheEntries.ContainsKey(bundleGUID))
throw new YooInternalException($"Cache entry already exists: {bundleGUID}");
_caches.Add(bundleGUID, entry);
SpaceOccupied += entry.GetFileSize();
_cacheEntries.Add(bundleGUID, cacheEntry);
SpaceOccupied += cacheEntry.GetFileSize();
}
/// <summary>
@@ -221,9 +250,9 @@ namespace YooAsset
/// </summary>
internal void RemoveEntry(string bundleGUID)
{
if (_caches.TryGetValue(bundleGUID, out SandboxFileCacheEntry entry))
if (_cacheEntries.TryGetValue(bundleGUID, out SandboxFileCacheEntry entry))
{
_caches.Remove(bundleGUID);
_cacheEntries.Remove(bundleGUID);
_dataFilePathMapping.Remove(bundleGUID);
_infoFilePathMapping.Remove(bundleGUID);
SpaceOccupied -= entry.GetFileSize();
@@ -236,9 +265,9 @@ namespace YooAsset
if (string.IsNullOrEmpty(fileHash))
throw new YooInternalException();
if (fileHash.Length <= HashFolderLength)
if (fileHash.Length <= HashFolderNameLength)
return fileHash;
return fileHash.Substring(0, HashFolderLength);
return fileHash.Substring(0, HashFolderNameLength);
}
#endregion
}

View File

@@ -1,6 +1,9 @@

namespace YooAsset
{
/// <summary>
/// 沙盒文件缓存常量定义
/// </summary>
internal class SandboxFileCacheDefine
{
/// <summary>
@@ -12,5 +15,15 @@ namespace YooAsset
/// 信息文件名称
/// </summary>
public const string BundleInfoFileName = "__info";
/// <summary>
/// 数据临时文件名称
/// </summary>
public const string BundleDataTempFileName = "__data.tmp";
/// <summary>
/// 信息临时文件名称
/// </summary>
public const string BundleInfoTempFileName = "__info.tmp";
}
}

View File

@@ -3,13 +3,35 @@ using System.IO;
namespace YooAsset
{
/// <summary>
/// 沙盒文件缓存条目
/// </summary>
internal class SandboxFileCacheEntry : ICacheEntry
{
public string BundleGUID { get; private set; }
public string InfoFilePath { get; private set; }
public string DataFilePath { get; private set; }
private long _fileSize = 0;
private long _fileSize = -1;
/// <summary>
/// 资源包唯一标识
/// </summary>
public string BundleGUID { get; private set; }
/// <summary>
/// 信息文件路径
/// </summary>
public string InfoFilePath { get; private set; }
/// <summary>
/// 数据文件路径
/// </summary>
public string DataFilePath { get; private set; }
/// <summary>
/// 创建沙盒文件缓存条目
/// </summary>
/// <param name="bundleGUID">资源包唯一标识</param>
/// <param name="infoFilePath">信息文件路径</param>
/// <param name="dataFilePath">数据文件路径</param>
public SandboxFileCacheEntry(string bundleGUID, string infoFilePath, string dataFilePath)
{
BundleGUID = bundleGUID;
@@ -18,8 +40,9 @@ namespace YooAsset
}
/// <summary>
/// 删除记录文件
/// 删除缓存文件夹及其所有内容
/// </summary>
/// <returns>删除是否成功</returns>
public bool Delete()
{
try
@@ -43,13 +66,14 @@ namespace YooAsset
}
}
/// <summary>
/// 获取缓存文件总大小
/// </summary>
/// <returns>文件总大小(字节)</returns>
public long GetFileSize()
{
if (_fileSize == 0)
{
_fileSize = FileUtility.GetFileSize(InfoFilePath);
_fileSize += FileUtility.GetFileSize(DataFilePath);
}
if (_fileSize < 0)
_fileSize = FileUtility.GetFileSize(DataFilePath);
return _fileSize;
}
}

View File

@@ -0,0 +1,65 @@
using System.IO;
namespace YooAsset
{
/// <summary>
/// 搜索的文件信息,用于缓存文件校验流程
/// </summary>
internal class SearchFileInfo
{
/// <summary>
/// 资源包唯一标识
/// </summary>
public string BundleGUID { get; private set; }
/// <summary>
/// 缓存文件夹路径
/// </summary>
public string FolderPath { get; private set; }
/// <summary>
/// 数据文件路径
/// </summary>
public string DataFilePath { get; private set; }
/// <summary>
/// 信息文件路径
/// </summary>
public string InfoFilePath { get; private set; }
/// <summary>
/// 验证结果码(原子操作对象,用于线程安全)
/// </summary>
public volatile int VerifyResultCode = 0;
/// <summary>
/// 创建验证文件信息
/// </summary>
/// <param name="bundleGUID">资源包唯一标识</param>
/// <param name="folderPath">缓存文件夹路径</param>
/// <param name="dataFilePath">数据文件路径</param>
/// <param name="infoFilePath">信息文件路径</param>
public SearchFileInfo(string bundleGUID, string folderPath, string dataFilePath, string infoFilePath)
{
BundleGUID = bundleGUID;
FolderPath = folderPath;
DataFilePath = dataFilePath;
InfoFilePath = infoFilePath;
}
/// <summary>
/// 删除缓存文件夹及其内容
/// </summary>
public void DeleteCacheFolder()
{
try
{
Directory.Delete(FolderPath, true);
}
catch (System.Exception ex)
{
YooLogger.Warning($"Failed to delete cache bundle folder: {ex}");
}
}
}
}

View File

@@ -1,22 +1,42 @@

namespace YooAsset
{
/// <summary>
/// 临时的文件信息,用于存储待验证的下载文件
/// </summary>
internal class TempFileInfo
{
public string TempFilePath { private set; get; }
public uint TempFileCRC { private set; get; }
public long TempFileSize { private set; get; }
/// <summary>
/// 临时文件路径
/// </summary>
public string FilePath { private set; get; }
/// <summary>
/// 注意:原子操作对象
/// 文件CRC校验值
/// </summary>
public volatile int Result = 0;
public uint FileCRC { private set; get; }
/// <summary>
/// 文件大小(字节)
/// </summary>
public long FileSize { private set; get; }
/// <summary>
/// 验证结果码(原子操作对象,用于线程安全)
/// </summary>
public volatile int VerifyResultCode = 0;
/// <summary>
/// 创建临时文件信息
/// </summary>
/// <param name="filePath">临时文件路径</param>
/// <param name="fileCRC">文件CRC校验值</param>
/// <param name="fileSize">文件大小(字节)</param>
public TempFileInfo(string filePath, uint fileCRC, long fileSize)
{
TempFilePath = filePath;
TempFileCRC = fileCRC;
TempFileSize = fileSize;
FilePath = filePath;
FileCRC = fileCRC;
FileSize = fileSize;
}
}
}

View File

@@ -1,37 +0,0 @@
using System.IO;
namespace YooAsset
{
internal class VerifyFileInfo
{
public string BundleGUID { get; private set; }
public string FolderPath { get; private set; }
public string DataFilePath { get; private set; }
public string InfoFilePath { get; private set; }
/// <summary>
/// 注意:原子操作对象
/// </summary>
public volatile int Result = 0;
public VerifyFileInfo(string bundleGUID, string folderPath, string dataFilePath, string infoFilePath)
{
BundleGUID = bundleGUID;
FolderPath = folderPath;
DataFilePath = dataFilePath;
InfoFilePath = infoFilePath;
}
public void DeleteFiles()
{
try
{
Directory.Delete(FolderPath, true);
}
catch (System.Exception ex)
{
YooLogger.Warning($"Failed to delete cache bundle folder : {ex}");
}
}
}
}

View File

@@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: 0a0a41496ce76334a958424c79db1016
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: 65bba40cd16af3a47bddda520ab51d6b
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,6 +1,9 @@

namespace YooAsset
{
/// <summary>
/// Web远端文件缓存初始化操作
/// </summary>
internal class WRFCInitializeOperation : FCInitializeOperation
{
private readonly WebRemoteFileCache _fileCache;

View File

@@ -1,6 +1,9 @@

namespace YooAsset
{
/// <summary>
/// Web远端文件缓存加载 AssetBundle 操作
/// </summary>
internal class WRFCLoadAssetBundleOperation : FCLoadBundleOperation
{
private enum ESteps
@@ -12,12 +15,12 @@ namespace YooAsset
}
private readonly WebRemoteFileCache _fileCache;
private readonly LoadBundleOptions _options;
private readonly FCLoadBundleOptions _options;
private LoadWebAssetBundleOperation _loadWebAssetBundleOp;
private WebRemoteFileCacheEntry _cacheEntry;
private ESteps _steps = ESteps.None;
public WRFCLoadAssetBundleOperation(WebRemoteFileCache fileCache, LoadBundleOptions options)
public WRFCLoadAssetBundleOperation(WebRemoteFileCache fileCache, FCLoadBundleOptions options)
{
_fileCache = fileCache;
_options = options;
@@ -38,7 +41,7 @@ namespace YooAsset
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Not found file cache entry: {_options.Bundle.BundleGUID}";
Error = $"File cache entry not found: {_options.Bundle.BundleGUID}";
}
else
{
@@ -55,8 +58,9 @@ namespace YooAsset
options.Bundle = _options.Bundle;
options.MainURL = _cacheEntry.MainURL;
options.FallbackURL = _cacheEntry.FallbackURL;
options.Decryptor = _fileCache.Config.AssetBundleDecryptor;
options.AssetBundleDecryptor = _fileCache.Config.AssetBundleDecryptor;
options.DownloadBackend = _fileCache.Config.DownloadBackend;
options.DownloadVerifyLevel = _fileCache.Config.DownloadVerifyLevel;
options.WatchdogTimeout = _fileCache.Config.WatchdogTimeout;
options.DisableUnityWebCache = _fileCache.Config.DisableUnityWebCache;
@@ -76,7 +80,7 @@ namespace YooAsset
if (_loadWebAssetBundleOp.Status == EOperationStatus.Succeeded)
{
if (_loadWebAssetBundleOp.BundleResult == null)
throw new YooInternalException("Loaded asset bundle result is null.");
throw new YooInternalException("Loaded bundle result is null.");
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
@@ -90,5 +94,15 @@ namespace YooAsset
}
}
}
internal override void InternalWaitForCompletion()
{
if (_steps != ESteps.Done)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"{nameof(WebRemoteFileCache)} not support sync load asset bundle.";
YooLogger.Error(Error);
}
}
}
}

View File

@@ -1,10 +1,16 @@
using System;
using System;
using System.Collections.Generic;
namespace YooAsset
{
/// <summary>
/// Web远端文件缓存系统用于从远程服务器加载资源
/// </summary>
internal class WebRemoteFileCache : IFileCache
{
/// <summary>
/// Web远端文件缓存配置
/// </summary>
internal struct CacheConfig
{
/// <summary>
@@ -17,6 +23,11 @@ namespace YooAsset
/// </summary>
public bool DisableUnityWebCache { get; set; }
/// <summary>
/// 下载数据校验级别
/// </summary>
public EFileVerifyLevel DownloadVerifyLevel { get; set; }
/// <summary>
/// AssetBundle 解密器
/// </summary>
@@ -33,9 +44,11 @@ namespace YooAsset
public IDownloadBackend DownloadBackend { get; set; }
}
private readonly Dictionary<string, WebRemoteFileCacheEntry> _caches = new Dictionary<string, WebRemoteFileCacheEntry>(10000);
private readonly Dictionary<string, WebRemoteFileCacheEntry> _cacheEntries = new Dictionary<string, WebRemoteFileCacheEntry>(10000);
// 缓存配置
/// <summary>
/// 缓存配置
/// </summary>
internal readonly CacheConfig Config;
#region
@@ -61,7 +74,7 @@ namespace YooAsset
{
get
{
return 0;
return _cacheEntries.Count;
}
}
@@ -72,6 +85,12 @@ namespace YooAsset
public long SpaceOccupied { get; private set; }
#endregion
/// <summary>
/// 创建Web远端文件缓存系统实例
/// </summary>
/// <param name="packageName">包裹名称</param>
/// <param name="rootPath">缓存根目录</param>
/// <param name="config">缓存配置</param>
public WebRemoteFileCache(string packageName, string rootPath, CacheConfig config)
{
PackageName = packageName;
@@ -87,7 +106,7 @@ namespace YooAsset
var operation = new WRFCInitializeOperation(this);
return operation;
}
public virtual FCWriteCacheOperation WriteCacheAsync(WriteCacheOptions options)
public virtual FCWriteCacheOperation WriteCacheAsync(FCWriteCacheOptions options)
{
var operation = new FCWriteCacheCompleteOperation($"{nameof(WebRemoteFileCache)} is readonly.");
return operation;
@@ -97,12 +116,12 @@ namespace YooAsset
var operation = new FCClearCacheCompleteOperation($"{nameof(WebRemoteFileCache)} is readonly.");
return operation;
}
public virtual FCVerifyCacheOperation VerifyCacheAsync(VerifyCacheOptions options)
public virtual FCVerifyCacheOperation VerifyCacheAsync(FCVerifyCacheOptions options)
{
var operation = new FCVerifyCacheCompleteOperation();
return operation;
}
public virtual FCLoadBundleOperation LoadBundleAsync(LoadBundleOptions options)
public virtual FCLoadBundleOperation LoadBundleAsync(FCLoadBundleOptions options)
{
if (options.Bundle.BundleType == (int)EBundleType.AssetBundle)
{
@@ -111,7 +130,7 @@ namespace YooAsset
}
else
{
string error = $"{nameof(WebServerFileCache)} not support load bundle type : {options.Bundle.BundleType}";
string error = $"{nameof(WebRemoteFileCache)} not support load bundle type : {options.Bundle.BundleType}";
var operation = new FCLoadBundleErrorOperation(error);
return operation;
}
@@ -122,9 +141,12 @@ namespace YooAsset
}
#region
public WebRemoteFileCacheEntry GetEntry(PackageBundle bundle)
/// <summary>
/// 获取或创建指定资源包的缓存条目
/// </summary>
internal WebRemoteFileCacheEntry GetEntry(PackageBundle bundle)
{
if (_caches.TryGetValue(bundle.BundleGUID, out WebRemoteFileCacheEntry entry))
if (_cacheEntries.TryGetValue(bundle.BundleGUID, out WebRemoteFileCacheEntry entry))
{
return entry;
}
@@ -133,7 +155,7 @@ namespace YooAsset
string mainURL = Config.RemoteServices.GetRemoteMainURL(bundle.FileName);
string fallbackURL = Config.RemoteServices.GetRemoteFallbackURL(bundle.FileName);
var newEntry = new WebRemoteFileCacheEntry(bundle.BundleGUID, mainURL, fallbackURL);
_caches.Add(bundle.BundleGUID, newEntry);
_cacheEntries.Add(bundle.BundleGUID, newEntry);
return newEntry;
}
}

View File

@@ -1,12 +1,32 @@

namespace YooAsset
{
/// <summary>
/// Web远端文件缓存条目
/// </summary>
internal class WebRemoteFileCacheEntry : ICacheEntry
{
/// <summary>
/// 资源包唯一标识
/// </summary>
public string BundleGUID { get; private set; }
/// <summary>
/// 主下载地址
/// </summary>
public string MainURL { get; private set; }
/// <summary>
/// 备用下载地址
/// </summary>
public string FallbackURL { get; private set; }
/// <summary>
/// 创建Web远端文件缓存条目
/// </summary>
/// <param name="bundleGUID">资源包唯一标识</param>
/// <param name="mainURL">主下载地址</param>
/// <param name="fallbackURL">备用下载地址</param>
public WebRemoteFileCacheEntry(string bundleGUID, string mainURL, string fallbackURL)
{
BundleGUID = bundleGUID;

View File

@@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: a72d34ce1de343d4291428371af736a5
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1,96 +0,0 @@
using System;
namespace YooAsset
{
internal sealed class LoadWebServerCatalogOperation : AsyncOperationBase
{
private enum ESteps
{
None,
RequestFileData,
LoadCatalog,
CheckResut,
Done,
}
private readonly WebServerFileCache _fileCache;
private IDownloadBytesRequest _webDataRequestOp;
private byte[] _fileData;
private ESteps _steps = ESteps.None;
/// <summary>
/// 内置资源目录
/// </summary>
public BuiltinFileCatalog Catalog;
internal LoadWebServerCatalogOperation(WebServerFileCache fileCache)
{
_fileCache = fileCache;
}
internal override void InternalStart()
{
_steps = ESteps.RequestFileData;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.RequestFileData)
{
if (_webDataRequestOp == null)
{
string filePath = _fileCache.GetCatalogBinaryFileLoadPath();
string url = DownloadSystemTools.ToLocalUrl(filePath);
var args = new DownloadDataRequestArgs(url, 60, 0);
_webDataRequestOp = _fileCache.Config.DownloadBackend.CreateBytesRequest(args);
_webDataRequestOp.SendRequest();
}
if (_webDataRequestOp.IsDone == false)
return;
if (_webDataRequestOp.Status == EDownloadRequestStatus.Succeeded)
{
_fileData = _webDataRequestOp.Result;
_steps = ESteps.LoadCatalog;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _webDataRequestOp.Error;
}
}
if (_steps == ESteps.LoadCatalog)
{
try
{
Catalog = BuiltinFileCatalogTools.DeserializeFromBinary(_fileData);
_steps = ESteps.CheckResut;
}
catch (Exception ex)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Failed to load catalog file : {ex.Message}";
}
}
if (_steps == ESteps.CheckResut)
{
if (Catalog.PackageName != _fileCache.PackageName)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Catalog file package name {Catalog.PackageName} cannot match the file cache package name {_fileCache.PackageName}";
return;
}
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
}
}
}
}

View File

@@ -1,18 +1,21 @@

namespace YooAsset
{
/// <summary>
/// Web服务器文件缓存初始化操作
/// </summary>
internal class WSFCInitializeOperation : FCInitializeOperation
{
private enum ESteps
{
None,
LoadCatalogFile,
RecordFiles,
LoadCatalog,
RecordEntry,
Done,
}
private readonly WebServerFileCache _fileCache;
private LoadWebServerCatalogOperation _loadWebCatalogFileOp;
private LoadBuiltinCatalogOperation _loadBuiltinCatalogOp;
private ESteps _steps = ESteps.None;
public WSFCInitializeOperation(WebServerFileCache cache)
@@ -21,47 +24,54 @@ namespace YooAsset
}
internal override void InternalStart()
{
_steps = ESteps.LoadCatalogFile;
_steps = ESteps.LoadCatalog;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.LoadCatalogFile)
if (_steps == ESteps.LoadCatalog)
{
if (_loadWebCatalogFileOp == null)
if (_loadBuiltinCatalogOp == null)
{
_loadWebCatalogFileOp = new LoadWebServerCatalogOperation(_fileCache);
_loadWebCatalogFileOp.StartOperation();
AddChildOperation(_loadWebCatalogFileOp);
var options = new LoadBuiltinCatalogOptions();
options.PackageName = _fileCache.PackageName;
options.FilePath = _fileCache.GetCatalogBinaryFileLoadPath();
options.DownloadBackend = _fileCache.Config.DownloadBackend;
_loadBuiltinCatalogOp = new LoadBuiltinCatalogOperation(options);
_loadBuiltinCatalogOp.StartOperation();
AddChildOperation(_loadBuiltinCatalogOp);
}
_loadWebCatalogFileOp.UpdateOperation();
if (_loadWebCatalogFileOp.IsDone == false)
_loadBuiltinCatalogOp.UpdateOperation();
if (_loadBuiltinCatalogOp.IsDone == false)
return;
if (_loadWebCatalogFileOp.Status == EOperationStatus.Succeeded)
if (_loadBuiltinCatalogOp.Status == EOperationStatus.Succeeded)
{
_steps = ESteps.RecordFiles;
_steps = ESteps.RecordEntry;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _loadWebCatalogFileOp.Error;
Error = _loadBuiltinCatalogOp.Error;
}
}
if (_steps == ESteps.RecordFiles)
if (_steps == ESteps.RecordEntry)
{
var catalog = _loadWebCatalogFileOp.Catalog;
foreach (var wrapper in catalog.Wrappers)
var catalog = _loadBuiltinCatalogOp.Catalog;
foreach (var fileEntry in catalog.FileEntries)
{
string filePath = PathUtility.Combine(_fileCache.RootPath, wrapper.FileName);
var entry = new WebServerFileCacheEntry(wrapper.BundleGUID, filePath);
_fileCache.AddEntry(wrapper.BundleGUID, entry);
string filePath = PathUtility.Combine(_fileCache.RootPath, fileEntry.FileName);
var cacheEntry = new WebServerFileCacheEntry(fileEntry.BundleGUID, filePath);
_fileCache.AddEntry(fileEntry.BundleGUID, cacheEntry);
}
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
}
}
}

View File

@@ -1,6 +1,9 @@

namespace YooAsset
{
/// <summary>
/// Web服务器文件缓存加载 AssetBundle 操作
/// </summary>
internal class WSFCLoadAssetBundleOperation : FCLoadBundleOperation
{
private enum ESteps
@@ -12,12 +15,12 @@ namespace YooAsset
}
private readonly WebServerFileCache _fileCache;
private readonly LoadBundleOptions _options;
private readonly FCLoadBundleOptions _options;
private LoadWebAssetBundleOperation _loadWebAssetBundleOp;
private WebServerFileCacheEntry _cacheEntry;
private ESteps _steps = ESteps.None;
public WSFCLoadAssetBundleOperation(WebServerFileCache fileCache, LoadBundleOptions options)
public WSFCLoadAssetBundleOperation(WebServerFileCache fileCache, FCLoadBundleOptions options)
{
_fileCache = fileCache;
_options = options;
@@ -38,7 +41,7 @@ namespace YooAsset
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Not found file cache entry: {_options.Bundle.BundleGUID}";
Error = $"File cache entry not found: {_options.Bundle.BundleGUID}";
}
else
{
@@ -56,8 +59,9 @@ namespace YooAsset
options.Bundle = _options.Bundle;
options.MainURL = url;
options.FallbackURL = url;
options.Decryptor = _fileCache.Config.AssetBundleDecryptor;
options.AssetBundleDecryptor = _fileCache.Config.AssetBundleDecryptor;
options.DownloadBackend = _fileCache.Config.DownloadBackend;
options.DownloadVerifyLevel = _fileCache.Config.DownloadVerifyLevel;
options.WatchdogTimeout = _fileCache.Config.WatchdogTimeout;
options.DisableUnityWebCache = _fileCache.Config.DisableUnityWebCache;
@@ -77,7 +81,7 @@ namespace YooAsset
if (_loadWebAssetBundleOp.Status == EOperationStatus.Succeeded)
{
if (_loadWebAssetBundleOp.BundleResult == null)
throw new YooInternalException("Loaded asset bundle result is null.");
throw new YooInternalException("Loaded bundle result is null.");
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
@@ -91,5 +95,15 @@ namespace YooAsset
}
}
}
internal override void InternalWaitForCompletion()
{
if (_steps != ESteps.Done)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"{nameof(WebServerFileCache)} not support sync load asset bundle.";
YooLogger.Error(Error);
}
}
}
}

View File

@@ -1,10 +1,16 @@
using System;
using System;
using System.Collections.Generic;
namespace YooAsset
{
/// <summary>
/// Web服务器文件缓存系统用于WebGL平台从服务器加载资源
/// </summary>
internal class WebServerFileCache : IFileCache
{
/// <summary>
/// Web服务器文件缓存配置
/// </summary>
internal struct CacheConfig
{
/// <summary>
@@ -17,20 +23,27 @@ namespace YooAsset
/// </summary>
public bool DisableUnityWebCache { get; set; }
/// <summary>
/// 下载数据校验级别
/// </summary>
public EFileVerifyLevel DownloadVerifyLevel { get; set; }
/// <summary>
/// AssetBundle 解密器
/// </summary>
public IBundleDecryptor AssetBundleDecryptor { get; set; }
/// <summary>
/// 下载后台接口
/// 下载后台
/// </summary>
public IDownloadBackend DownloadBackend { get; set; }
}
private readonly Dictionary<string, WebServerFileCacheEntry> _caches = new Dictionary<string, WebServerFileCacheEntry>(10000);
private readonly Dictionary<string, WebServerFileCacheEntry> _cacheEntries = new Dictionary<string, WebServerFileCacheEntry>(10000);
// 缓存配置
/// <summary>
/// 缓存配置
/// </summary>
internal readonly CacheConfig Config;
#region
@@ -56,7 +69,7 @@ namespace YooAsset
{
get
{
return _caches.Count;
return _cacheEntries.Count;
}
}
@@ -67,6 +80,12 @@ namespace YooAsset
public long SpaceOccupied { get; private set; }
#endregion
/// <summary>
/// 创建Web服务器文件缓存系统实例
/// </summary>
/// <param name="packageName">包裹名称</param>
/// <param name="rootPath">缓存根目录</param>
/// <param name="config">缓存配置</param>
public WebServerFileCache(string packageName, string rootPath, CacheConfig config)
{
PackageName = packageName;
@@ -82,7 +101,7 @@ namespace YooAsset
var operation = new WSFCInitializeOperation(this);
return operation;
}
public virtual FCWriteCacheOperation WriteCacheAsync(WriteCacheOptions options)
public virtual FCWriteCacheOperation WriteCacheAsync(FCWriteCacheOptions options)
{
var operation = new FCWriteCacheCompleteOperation($"{nameof(WebServerFileCache)} is readonly.");
return operation;
@@ -92,12 +111,12 @@ namespace YooAsset
var operation = new FCClearCacheCompleteOperation($"{nameof(WebServerFileCache)} is readonly.");
return operation;
}
public virtual FCVerifyCacheOperation VerifyCacheAsync(VerifyCacheOptions options)
public virtual FCVerifyCacheOperation VerifyCacheAsync(FCVerifyCacheOptions options)
{
var operation = new FCVerifyCacheCompleteOperation();
return operation;
}
public virtual FCLoadBundleOperation LoadBundleAsync(LoadBundleOptions options)
public virtual FCLoadBundleOperation LoadBundleAsync(FCLoadBundleOptions options)
{
if (options.Bundle.BundleType == (int)EBundleType.AssetBundle)
{
@@ -113,13 +132,16 @@ namespace YooAsset
}
public virtual bool IsCached(string bundleGUID)
{
return _caches.ContainsKey(bundleGUID);
return _cacheEntries.ContainsKey(bundleGUID);
}
#region
public WebServerFileCacheEntry GetEntry(string bundleGUID)
/// <summary>
/// 获取指定缓存条目
/// </summary>
internal WebServerFileCacheEntry GetEntry(string bundleGUID)
{
if (_caches.TryGetValue(bundleGUID, out WebServerFileCacheEntry entry))
if (_cacheEntries.TryGetValue(bundleGUID, out WebServerFileCacheEntry entry))
return entry;
else
return null;
@@ -128,12 +150,12 @@ namespace YooAsset
/// <summary>
/// 添加指定缓存
/// </summary>
internal void AddEntry(string bundleGUID, WebServerFileCacheEntry entry)
internal void AddEntry(string bundleGUID, WebServerFileCacheEntry cacheEntry)
{
if (_caches.ContainsKey(bundleGUID))
throw new YooInternalException($"Cache entry already existed: {bundleGUID}");
if (_cacheEntries.ContainsKey(bundleGUID))
throw new YooInternalException($"Cache entry already exists: {bundleGUID}");
_caches.Add(bundleGUID, entry);
_cacheEntries.Add(bundleGUID, cacheEntry);
}
/// <summary>
@@ -141,7 +163,7 @@ namespace YooAsset
/// </summary>
internal string GetCatalogBinaryFileLoadPath()
{
return PathUtility.Combine(RootPath, BuiltinFileCatalogDefine.BinaryFileName);
return PathUtility.Combine(RootPath, BuiltinCatalogDefine.BinaryFileName);
}
#endregion
}

View File

@@ -1,11 +1,26 @@

namespace YooAsset
{
/// <summary>
/// Web服务器文件缓存条目
/// </summary>
internal class WebServerFileCacheEntry : ICacheEntry
{
/// <summary>
/// 资源包唯一标识
/// </summary>
public string BundleGUID { get; private set; }
/// <summary>
/// 资源包文件路径
/// </summary>
public string FilePath { get; private set; }
/// <summary>
/// 创建Web服务器文件缓存条目
/// </summary>
/// <param name="bundleGUID">资源包唯一标识</param>
/// <param name="filePath">资源包文件路径</param>
public WebServerFileCacheEntry(string bundleGUID, string filePath)
{
BundleGUID = bundleGUID;

View File

@@ -1,254 +0,0 @@
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 (IsWaitForCompletion)
Result = AssetBundle.LoadFromFile(_options.FileLoadPath);
else
_createRequest = AssetBundle.LoadFromFileAsync(_options.FileLoadPath);
_steps = ESteps.CheckResult;
}
if (_steps == ESteps.CheckResult)
{
if (_createRequest != null)
{
if (IsWaitForCompletion)
{
// 强制挂起主线程(注意:该操作会很耗时)
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.Succeeded;
}
}
}
internal override void InternalWaitForCompletion()
{
ExecuteBatch();
}
public override AssetBundle LoadFromMemory()
{
if (IsSupportFileIO(_options.FileLoadPath) == false)
return null;
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
{
protected DefaultLoadAssetBundleFromOffsetOperation(LoadAssetBundleOptions options) : base(options)
{
}
/// <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,
CheckFilePath,
LoadAssetBundle,
CheckResult,
Done,
}
private AssetBundleCreateRequest _createRequest;
private ESteps _steps = ESteps.None;
public DefaultLoadAssetBundleFromMemoryOperation(LoadAssetBundleOptions options) : base(options) { }
internal override void InternalStart()
{
_steps = ESteps.CheckFilePath;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.CheckFilePath)
{
string filePath = _options.FileLoadPath;
if (IsSupportFileIO(filePath) == false)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"FileIO not supported for builtin path : {filePath}";
}
else
{
_steps = ESteps.LoadAssetBundle;
}
}
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 (IsWaitForCompletion)
Result = AssetBundle.LoadFromMemory(rawData);
else
_createRequest = AssetBundle.LoadFromMemoryAsync(rawData);
_steps = ESteps.CheckResult;
}
}
/// <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,
CheckFilePath,
LoadAssetBundle,
CheckResult,
Done,
}
private ESteps _steps = ESteps.None;
protected DefaultLoadAssetBundleFromStreamOperation(LoadAssetBundleOptions options) : base(options)
{
}
internal override void InternalUpdate()
{
if (_steps == ESteps.CheckFilePath)
{
string filePath = _options.FileLoadPath;
if (IsSupportFileIO(filePath) == false)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"FileIO not supported for builtin path : {filePath}";
}
else
{
_steps = ESteps.LoadAssetBundle;
}
}
}
/// <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,107 +0,0 @@
using System.IO;
/*
namespace YooAsset
{
/// <summary>
/// 默认的 RawBundle 加载操作(非加密)
/// 通用实现,适用于 BuiltinFileSystem 和 CacheFileSystem
/// </summary>
public class DefaultLoadRawBundleOperation : LoadRawBundleOperation
{
private enum ESteps
{
None,
CheckFilePath,
LoadRawBundle,
Done
}
private ESteps _steps = ESteps.None;
public DefaultLoadRawBundleOperation(LoadRawBundleOptions options) : base(options) { }
internal override void InternalStart()
{
_steps = ESteps.CheckFilePath;
}
internal override void InternalUpdate()
{
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.Succeeded;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Can not found raw bundle file : {filePath}";
}
}
}
}
/// <summary>
/// 默认的 RawBundle 加载操作(加密)
/// 通用实现,适用于 CacheFileSystem
/// </summary>
public abstract class DefaultLoadRawBundleFromMemoryOperation : LoadRawBundleOperation
{
private enum ESteps
{
None,
CheckFilePath,
LoadRawBundle,
Done
}
private ESteps _steps = ESteps.None;
public DefaultLoadRawBundleFromMemoryOperation(LoadRawBundleOptions options) : base(options) { }
internal override void InternalStart()
{
_steps = ESteps.CheckFilePath;
}
internal override void InternalUpdate()
{
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.Succeeded;
}
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Can not found raw bundle file : {filePath}";
}
}
}
/// <summary>
/// 文件数据解密
/// </summary>
protected abstract byte[] DecryptData(byte[] data);
}
}
*/

View File

@@ -1,251 +0,0 @@
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.RetryCount;
}
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.Succeeded)
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
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.RetryCount;
}
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.Succeeded)
{
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.Succeeded;
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

@@ -31,12 +31,12 @@ namespace YooAsset
/// <summary>
/// 下载Bundle文件
/// </summary>
FSDownloadFileOperation DownloadFileAsync(DownloadFileOptions options);
FSDownloadFileOperation DownloadFileAsync(FSDownloadFileOptions options);
/// <summary>
/// 加载Bundle文件
/// </summary>
FSLoadBundleOperation LoadBundleAsync(LoadBundleOptions options);
FSLoadBundleOperation LoadBundleAsync(FCLoadBundleOptions options);
/// <summary>

View File

@@ -0,0 +1,132 @@
namespace YooAsset
{
internal class LoadWebPackageManifestOperation : AsyncOperationBase
{
private enum ESteps
{
None,
RequestFileData,
VerifyFileData,
LoadManifest,
Done,
}
private readonly LoadWebPackageManifestOptions _options;
private IDownloadBytesRequest _webDataRequestOp;
private DeserializeManifestOperation _deserializer;
private int _requestCount = 0;
private ESteps _steps = ESteps.None;
/// <summary>
/// 包裹清单
/// </summary>
public PackageManifest Manifest { private set; get; }
internal LoadWebPackageManifestOperation(LoadWebPackageManifestOptions options)
{
_options = options;
}
internal override void InternalStart()
{
_requestCount = DownloadFailureCounter.GetFailureCount(_options.PackageName, nameof(LoadWebPackageManifestOperation));
_steps = ESteps.RequestFileData;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.RequestFileData)
{
if (_webDataRequestOp == null)
{
string fileName = YooAssetSettingsData.GetManifestBinaryFileName(_options.PackageName, _options.PackageVersion);
string url = GetRequestURL(fileName);
var args = new DownloadDataRequestArgs(url, _options.Timeout, 0);
_webDataRequestOp = _options.DownloadBackend.CreateBytesRequest(args);
_webDataRequestOp.SendRequest();
}
Progress = _webDataRequestOp.DownloadProgress;
if (_webDataRequestOp.IsDone == false)
return;
if (_webDataRequestOp.Status == EDownloadRequestStatus.Succeeded)
{
_steps = ESteps.VerifyFileData;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _webDataRequestOp.Error;
DownloadFailureCounter.RecordFailure(_options.PackageName, nameof(LoadWebPackageManifestOperation));
}
}
if (_steps == ESteps.VerifyFileData)
{
if (PackageManifestTools.VerifyManifestData(_webDataRequestOp.Result, _options.PackageHash))
{
_steps = ESteps.LoadManifest;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = "Failed to verify web package manifest file.";
}
}
if (_steps == ESteps.LoadManifest)
{
if (_deserializer == null)
{
_deserializer = new DeserializeManifestOperation(_options.ManifestDecryptor, _webDataRequestOp.Result);
_deserializer.StartOperation();
AddChildOperation(_deserializer);
}
_deserializer.UpdateOperation();
Progress = _deserializer.Progress;
if (_deserializer.IsDone == false)
return;
if (_deserializer.Status == EOperationStatus.Succeeded)
{
_steps = ESteps.Done;
Manifest = _deserializer.Manifest;
Status = EOperationStatus.Succeeded;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _deserializer.Error;
}
}
}
internal override void InternalDispose()
{
if (_webDataRequestOp != null)
{
_webDataRequestOp.Dispose();
_webDataRequestOp = null;
}
}
internal override string InternalGetDescription()
{
return $"PackageVersion : {_options.PackageVersion} PackageHash : {_options.PackageHash}";
}
private string GetRequestURL(string fileName)
{
// 轮流返回请求地址
if (_requestCount % 2 == 0)
return _options.RemoteServices.GetRemoteMainURL(fileName);
else
return _options.RemoteServices.GetRemoteFallbackURL(fileName);
}
}
}

View File

@@ -0,0 +1,14 @@
namespace YooAsset
{
internal struct LoadWebPackageManifestOptions
{
public string PackageName { get; set; }
public string PackageVersion { get; set; }
public string PackageHash { get; set; }
public int Timeout { get; set; }
public IRemoteServices RemoteServices { get; set; }
public IManifestDecryptor ManifestDecryptor { get; set; }
public IDownloadBackend DownloadBackend { get; set; }
}
}

View File

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

View File

@@ -0,0 +1,94 @@
namespace YooAsset
{
internal class RequestWebPackageHashOperation : AsyncOperationBase
{
private enum ESteps
{
None,
RequestPackageHash,
Done,
}
private readonly RequestWebPackageHashOptions _options;
private IDownloadTextRequest _webTextRequestOp;
private int _requestCount = 0;
private ESteps _steps = ESteps.None;
/// <summary>
/// 包裹哈希值
/// </summary>
public string PackageHash { private set; get; }
public RequestWebPackageHashOperation(RequestWebPackageHashOptions options)
{
_options = options;
}
internal override void InternalStart()
{
_requestCount = DownloadFailureCounter.GetFailureCount(_options.PackageName, nameof(RequestWebPackageHashOperation));
_steps = ESteps.RequestPackageHash;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.RequestPackageHash)
{
if (_webTextRequestOp == null)
{
string fileName = YooAssetSettingsData.GetPackageHashFileName(_options.PackageName, _options.PackageVersion);
string url = GetRequestURL(fileName);
var args = new DownloadDataRequestArgs(url, _options.Timeout, 0);
_webTextRequestOp = _options.DownloadBackend.CreateTextRequest(args);
_webTextRequestOp.SendRequest();
}
Progress = _webTextRequestOp.DownloadProgress;
if (_webTextRequestOp.IsDone == false)
return;
if (_webTextRequestOp.Status == EDownloadRequestStatus.Succeeded)
{
PackageHash = _webTextRequestOp.Result;
if (string.IsNullOrEmpty(PackageHash))
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Web package hash file content is empty.";
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
}
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _webTextRequestOp.Error;
DownloadFailureCounter.RecordFailure(_options.PackageName, nameof(RequestWebPackageHashOperation));
}
}
}
internal override void InternalDispose()
{
if (_webTextRequestOp != null)
{
_webTextRequestOp.Dispose();
_webTextRequestOp = null;
}
}
private string GetRequestURL(string fileName)
{
// 轮流返回请求地址
if (_requestCount % 2 == 0)
return _options.RemoteServices.GetRemoteMainURL(fileName);
else
return _options.RemoteServices.GetRemoteFallbackURL(fileName);
}
}
}

View File

@@ -0,0 +1,12 @@
namespace YooAsset
{
internal struct RequestWebPackageHashOptions
{
public string PackageName { get; set; }
public string PackageVersion { get; set; }
public int Timeout { get; set; }
public IRemoteServices RemoteServices { get; set; }
public IDownloadBackend DownloadBackend { get; set; }
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: cc25b8eb3bf83474f942e36bf7b3210d
guid: 4ba57dfeb7916fd46bb58b673fc08ef4
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@@ -0,0 +1,102 @@
namespace YooAsset
{
internal class RequestWebPackageVersionOperation : AsyncOperationBase
{
private enum ESteps
{
None,
RequestPackageVersion,
Done,
}
private readonly RequestWebPackageVersionOptions _options;
private IDownloadTextRequest _webTextRequestOp;
private int _requestCount = 0;
private ESteps _steps = ESteps.None;
/// <summary>
/// 包裹版本
/// </summary>
public string PackageVersion { private set; get; }
public RequestWebPackageVersionOperation(RequestWebPackageVersionOptions options)
{
_options = options;
}
internal override void InternalStart()
{
_requestCount = DownloadFailureCounter.GetFailureCount(_options.PackageName, nameof(RequestWebPackageVersionOperation));
_steps = ESteps.RequestPackageVersion;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.RequestPackageVersion)
{
if (_webTextRequestOp == null)
{
string fileName = YooAssetSettingsData.GetPackageVersionFileName(_options.PackageName);
string url = GetRequestURL(fileName);
var args = new DownloadDataRequestArgs(url, _options.Timeout, 0);
_webTextRequestOp = _options.DownloadBackend.CreateTextRequest(args);
_webTextRequestOp.SendRequest();
}
Progress = _webTextRequestOp.DownloadProgress;
if (_webTextRequestOp.IsDone == false)
return;
if (_webTextRequestOp.Status == EDownloadRequestStatus.Succeeded)
{
PackageVersion = _webTextRequestOp.Result;
if (string.IsNullOrEmpty(PackageVersion))
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Web package version file content is empty.";
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
}
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _webTextRequestOp.Error;
DownloadFailureCounter.RecordFailure(_options.PackageName, nameof(RequestWebPackageVersionOperation));
}
}
}
internal override void InternalDispose()
{
if (_webTextRequestOp != null)
{
_webTextRequestOp.Dispose();
_webTextRequestOp = null;
}
}
private string GetRequestURL(string fileName)
{
string url;
// 轮流返回请求地址
if (_requestCount % 2 == 0)
url = _options.RemoteServices.GetRemoteMainURL(fileName);
else
url = _options.RemoteServices.GetRemoteFallbackURL(fileName);
// 在URL末尾添加时间戳
if (_options.AppendTimeTicks)
return $"{url}?{System.DateTime.UtcNow.Ticks}";
else
return url;
}
}
}

View File

@@ -0,0 +1,12 @@
namespace YooAsset
{
internal struct RequestWebPackageVersionOptions
{
public string PackageName { get; set; }
public bool AppendTimeTicks { get; set; }
public int Timeout { get; set; }
public IRemoteServices RemoteServices { get; set; }
public IDownloadBackend DownloadBackend { get; set; }
}
}

View File

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

View File

@@ -1,7 +1,7 @@

namespace YooAsset
{
internal readonly struct DownloadFileOptions
internal readonly struct FSDownloadFileOptions
{
/// <summary>
/// 资源包对象
@@ -18,13 +18,13 @@ namespace YooAsset
/// </summary>
public readonly string ImportFilePath;
public DownloadFileOptions(PackageBundle bundle, int retryCount)
public FSDownloadFileOptions(PackageBundle bundle, int retryCount)
{
Bundle = bundle;
RetryCount = retryCount;
ImportFilePath = null;
}
public DownloadFileOptions(PackageBundle bundle, int retryCount, string importFilePath)
public FSDownloadFileOptions(PackageBundle bundle, int retryCount, string importFilePath)
{
Bundle = bundle;
RetryCount = retryCount;

View File

@@ -137,12 +137,12 @@ namespace YooAsset
var operation = new BFSClearCacheOperation(this, options);
return operation;
}
public virtual FSDownloadFileOperation DownloadFileAsync(DownloadFileOptions options)
public virtual FSDownloadFileOperation DownloadFileAsync(FSDownloadFileOptions options)
{
var operation = new BFSDownloadFileOperation(this, options);
return operation;
}
public virtual FSLoadBundleOperation LoadBundleAsync(LoadBundleOptions options)
public virtual FSLoadBundleOperation LoadBundleAsync(FCLoadBundleOptions options)
{
var operation = new BFSLoadBundleOperation(this, options);
return operation;
@@ -235,21 +235,21 @@ namespace YooAsset
else
_packageRoot = packageRoot;
// 创建默认的下载后台接口
if (DownloadBackend == null)
DownloadBackend = new UnityWebRequestBackend(WebRequestCreator);
// 创建解压缓存系统
// 设置根目录
string unpackRoot;
if (string.IsNullOrEmpty(UnpackFileSystemRoot))
unpackRoot = GetDefaultUnpackCacheRoot(packageName);
unpackRoot = GetDefaultUnpackPathRoot(packageName);
else
unpackRoot = UnpackFileSystemRoot;
_unpackManifestFilesRoot = PathUtility.Combine(unpackRoot, BuiltinFileSystemDefine.UnpackManifestFilesFolderName);
_unpackBundleFilesRoot = PathUtility.Combine(unpackRoot, BuiltinFileSystemDefine.UnpackBundleFilesFolderName);
_unpackTempFilesRoot = PathUtility.Combine(unpackRoot, BuiltinFileSystemDefine.UnpackTempFilesFolderName);
// 创建内置缓存对象
// 创建默认的下载后台接口
if (DownloadBackend == null)
DownloadBackend = new UnityWebRequestBackend(WebRequestCreator);
// 创建内置文件缓存系统
{
var cacheConfig = new BuiltinFileCache.CacheConfig();
cacheConfig.AssetBundleDecryptor = AssetBundleDecryptor;
@@ -258,7 +258,7 @@ namespace YooAsset
BuiltinFileCache = new BuiltinFileCache(packageName, _packageRoot, cacheConfig);
}
// 创建沙盒缓存对象
// 创建沙盒文件缓存系统
{
var cacheConfig = new SandboxFileCache.CacheConfig();
cacheConfig.FileVerifyMaxConcurrency = FileVerifyMaxConcurrency;
@@ -377,7 +377,7 @@ namespace YooAsset
}
/// <summary>
/// 删除所有缓存的资源文件
/// 删除所有解压的资源文件
/// </summary>
public void DeleteAllBundleFiles()
{
@@ -388,9 +388,9 @@ namespace YooAsset
}
/// <summary>
/// 获取默认的解压缓存根目录
/// 获取默认的解压根目录
/// </summary>
public string GetDefaultUnpackCacheRoot(string packageName)
public string GetDefaultUnpackPathRoot(string packageName)
{
string rootDirectory = YooAssetSettingsData.GetYooDefaultCacheRoot();
return PathUtility.Combine(rootDirectory, packageName);

Some files were not shown because too many files have changed in this diff Show More