mirror of
https://github.com/tuyoogame/YooAsset.git
synced 2026-05-28 03:28:47 +00:00
refactor : 代码重构
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6f2f046660639e54cb2c40610189a91c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,523 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 内置文件系统,管理内置(StreamingAssets)目录下的资源文件访问。
|
||||
/// </summary>
|
||||
internal class BuiltinFileSystem : IFileSystem
|
||||
{
|
||||
/// <summary>
|
||||
/// 内置资源文件路径映射表
|
||||
/// </summary>
|
||||
protected readonly Dictionary<string, string> _builtinFilePathMapping = new Dictionary<string, string>(10000);
|
||||
|
||||
/// <summary>
|
||||
/// 临时文件路径映射表
|
||||
/// </summary>
|
||||
protected readonly Dictionary<string, string> _tempFilePathMapping = new Dictionary<string, string>(10000);
|
||||
|
||||
/// <summary>
|
||||
/// 包裹根目录路径
|
||||
/// </summary>
|
||||
protected string _packageRoot;
|
||||
|
||||
/// <summary>
|
||||
/// 临时文件根目录路径
|
||||
/// </summary>
|
||||
protected string _tempFilesRoot;
|
||||
|
||||
/// <summary>
|
||||
/// 解压清单文件根目录路径
|
||||
/// </summary>
|
||||
protected string _unpackManifestFilesRoot;
|
||||
|
||||
/// <summary>
|
||||
/// 解压资源包文件根目录路径
|
||||
/// </summary>
|
||||
protected string _unpackBundleFilesRoot;
|
||||
|
||||
/// <summary>
|
||||
/// 内置 Bundle 缓存系统
|
||||
/// </summary>
|
||||
public IBundleCache BuiltinBundleCache { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 解压 Bundle 缓存系统
|
||||
/// </summary>
|
||||
public IBundleCache UnpackBundleCache { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 解压调度器
|
||||
/// </summary>
|
||||
public DownloadSchedulerOperation UnpackScheduler { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// 下载后台接口
|
||||
/// </summary>
|
||||
public IDownloadBackend DownloadBackend { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 包裹名称
|
||||
/// </summary>
|
||||
public string PackageName { get; private set; }
|
||||
|
||||
#region 自定义参数
|
||||
/// <summary>
|
||||
/// 自定义参数:UnityWebRequest 创建委托
|
||||
/// </summary>
|
||||
public UnityWebRequestCreator WebRequestCreator { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 自定义参数:覆盖安装缓存清理模式
|
||||
/// </summary>
|
||||
public EInstallCleanupMode InstallCleanupMode { get; private set; } = EInstallCleanupMode.None;
|
||||
|
||||
/// <summary>
|
||||
/// 自定义参数:初始化的时候缓存文件校验级别
|
||||
/// </summary>
|
||||
public EFileVerifyLevel FileVerifyLevel { get; private set; } = EFileVerifyLevel.Low;
|
||||
|
||||
/// <summary>
|
||||
/// 自定义参数:初始化的时候缓存文件校验最大并发数
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 默认值:8(推荐值为处理器数两倍)。过大的值可能导致线程池任务过多,影响系统稳定性。
|
||||
/// </remarks>
|
||||
public int FileVerifyMaxConcurrency { get; private set; } = 8;
|
||||
|
||||
/// <summary>
|
||||
/// 自定义参数:拷贝内置清单
|
||||
/// </summary>
|
||||
public bool CopyBuiltinPackageManifest { get; private set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 自定义参数:拷贝内置清单的目标目录
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 注意:该参数为空的时候,会获取默认的沙盒目录。
|
||||
/// </remarks>
|
||||
public string CopyBuiltinPackageManifestDestRoot { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 自定义参数:解压文件系统的根目录
|
||||
/// </summary>
|
||||
public string UnpackFileSystemRoot { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 自定义参数:最大并发连接数
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 默认值:8(推荐范围 1-32)
|
||||
/// </remarks>
|
||||
public int UnpackMaxConcurrency { get; private set; } = 8;
|
||||
|
||||
/// <summary>
|
||||
/// 自定义参数:每帧发起的最大请求数
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 默认值:8(推荐范围 1-32)。避免单帧发起过多请求导致卡顿。
|
||||
/// </remarks>
|
||||
public int UnpackMaxRequestsPerFrame { get; private set; } = 8;
|
||||
|
||||
/// <summary>
|
||||
/// 自定义参数:AssetBundle 解密器
|
||||
/// </summary>
|
||||
public IBundleDecryptor AssetBundleDecryptor { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 自定义参数:RawBundle 解密器
|
||||
/// </summary>
|
||||
public IBundleDecryptor RawBundleDecryptor { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 自定义参数:AssetBundle 备用解密器
|
||||
/// </summary>
|
||||
public IBundleMemoryDecryptor AssetBundleFallbackDecryptor { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 自定义参数:资源清单解密器
|
||||
/// </summary>
|
||||
public IManifestDecryptor ManifestDecryptor { get; private set; }
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// 创建实例
|
||||
/// </summary>
|
||||
public BuiltinFileSystem()
|
||||
{
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public FSInitializeOperation InitializeAsync()
|
||||
{
|
||||
var operation = new BFSInitializeOperation(this);
|
||||
return operation;
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public FSRequestPackageVersionOperation RequestPackageVersionAsync(FSRequestPackageVersionOptions options)
|
||||
{
|
||||
var operation = new BFSRequestPackageVersionOperation(this);
|
||||
return operation;
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public FSLoadPackageManifestOperation LoadPackageManifestAsync(FSLoadPackageManifestOptions options)
|
||||
{
|
||||
var operation = new BFSLoadPackageManifestOperation(this, options.PackageVersion);
|
||||
return operation;
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public FSLoadPackageBundleOperation LoadPackageBundleAsync(FSLoadPackageBundleOptions options)
|
||||
{
|
||||
var operation = new BFSLoadPackageBundleOperation(this, options);
|
||||
return operation;
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public FSDownloadBundleOperation DownloadBundleAsync(FSDownloadBundleOptions options)
|
||||
{
|
||||
var operation = new BFSDownloadBundleOperation(this, options);
|
||||
return operation;
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public FSClearCacheOperation ClearCacheAsync(FSClearCacheOptions options)
|
||||
{
|
||||
if (options.ClearMethod == ClearCacheMethods.ClearAllManifestFiles)
|
||||
{
|
||||
var operation = new FSClearCacheCompleteOperation();
|
||||
return operation;
|
||||
}
|
||||
else if (options.ClearMethod == ClearCacheMethods.ClearUnusedManifestFiles)
|
||||
{
|
||||
var operation = new FSClearCacheCompleteOperation();
|
||||
return operation;
|
||||
}
|
||||
else
|
||||
{
|
||||
var operation = new BFSClearCacheOperation(this, options);
|
||||
return operation;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void SetParameter(string paramName, object value)
|
||||
{
|
||||
if (paramName == nameof(EFileSystemParameter.DownloadBackend))
|
||||
{
|
||||
DownloadBackend = FileSystemHelper.CastParameter<IDownloadBackend>(paramName, value);
|
||||
}
|
||||
else if (paramName == nameof(EFileSystemParameter.UnityWebRequestCreator))
|
||||
{
|
||||
WebRequestCreator = FileSystemHelper.CastParameter<UnityWebRequestCreator>(paramName, value);
|
||||
}
|
||||
else if (paramName == nameof(EFileSystemParameter.InstallCleanupMode))
|
||||
{
|
||||
InstallCleanupMode = FileSystemHelper.CastParameter<EInstallCleanupMode>(paramName, value);
|
||||
}
|
||||
else if (paramName == nameof(EFileSystemParameter.FileVerifyLevel))
|
||||
{
|
||||
FileVerifyLevel = FileSystemHelper.CastParameter<EFileVerifyLevel>(paramName, value);
|
||||
}
|
||||
else if (paramName == nameof(EFileSystemParameter.FileVerifyMaxConcurrency))
|
||||
{
|
||||
int convertValue = FileSystemHelper.CastParameter<int>(paramName, value);
|
||||
if (convertValue > 32)
|
||||
{
|
||||
YooLogger.LogWarning($"FILE_VERIFY_MAX_CONCURRENCY value {convertValue} is too large, clamped to 32. Recommended range: 1 - 32.");
|
||||
}
|
||||
|
||||
// 限制在合理范围内:1-32
|
||||
FileVerifyMaxConcurrency = Mathf.Clamp(convertValue, 1, 32);
|
||||
}
|
||||
else if (paramName == nameof(EFileSystemParameter.CopyBuiltinPackageManifest))
|
||||
{
|
||||
CopyBuiltinPackageManifest = FileSystemHelper.CastParameter<bool>(paramName, value);
|
||||
}
|
||||
else if (paramName == nameof(EFileSystemParameter.CopyBuiltinPackageManifestDestRoot))
|
||||
{
|
||||
CopyBuiltinPackageManifestDestRoot = FileSystemHelper.CastParameter<string>(paramName, value);
|
||||
}
|
||||
else if (paramName == nameof(EFileSystemParameter.UnpackFileSystemRoot))
|
||||
{
|
||||
UnpackFileSystemRoot = FileSystemHelper.CastParameter<string>(paramName, value);
|
||||
}
|
||||
else if (paramName == nameof(EFileSystemParameter.DownloadMaxConcurrency))
|
||||
{
|
||||
int convertValue = FileSystemHelper.CastParameter<int>(paramName, value);
|
||||
if (convertValue > 32)
|
||||
{
|
||||
YooLogger.LogWarning($"DOWNLOAD_MAX_CONCURRENCY value {convertValue} is too large, clamped to 32. Recommended range: 1 - 32.");
|
||||
}
|
||||
|
||||
// 限制在合理范围内:1-32
|
||||
UnpackMaxConcurrency = Mathf.Clamp(convertValue, 1, 32);
|
||||
}
|
||||
else if (paramName == nameof(EFileSystemParameter.DownloadMaxRequestPerFrame))
|
||||
{
|
||||
int convertValue = FileSystemHelper.CastParameter<int>(paramName, value);
|
||||
if (convertValue > 32)
|
||||
{
|
||||
YooLogger.LogWarning($"DOWNLOAD_MAX_REQUEST_PER_FRAME value {convertValue} is too large, clamped to 32. Recommended range: 1 - 32.");
|
||||
}
|
||||
|
||||
// 限制在合理范围内:1-32
|
||||
UnpackMaxRequestsPerFrame = Mathf.Clamp(convertValue, 1, 32);
|
||||
}
|
||||
else if (paramName == nameof(EFileSystemParameter.AssetbundleDecryptor))
|
||||
{
|
||||
AssetBundleDecryptor = FileSystemHelper.CastParameter<IBundleDecryptor>(paramName, value);
|
||||
}
|
||||
else if (paramName == nameof(EFileSystemParameter.RawbundleDecryptor))
|
||||
{
|
||||
RawBundleDecryptor = FileSystemHelper.CastParameter<IBundleDecryptor>(paramName, value);
|
||||
}
|
||||
else if (paramName == nameof(EFileSystemParameter.AssetbundleFallbackDecryptor))
|
||||
{
|
||||
AssetBundleFallbackDecryptor = FileSystemHelper.CastParameter<IBundleMemoryDecryptor>(paramName, value);
|
||||
}
|
||||
else if (paramName == nameof(EFileSystemParameter.ManifestDecryptor))
|
||||
{
|
||||
ManifestDecryptor = FileSystemHelper.CastParameter<IManifestDecryptor>(paramName, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException($"Unrecognized parameter name: '{paramName}'.", nameof(paramName));
|
||||
}
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public void OnCreate(string packageName, string packageRoot)
|
||||
{
|
||||
PackageName = packageName;
|
||||
|
||||
if (string.IsNullOrEmpty(packageRoot))
|
||||
_packageRoot = GetDefaultBuiltinPackageRoot(packageName);
|
||||
else
|
||||
_packageRoot = packageRoot;
|
||||
|
||||
// 设置根目录
|
||||
string unpackRoot;
|
||||
if (string.IsNullOrEmpty(UnpackFileSystemRoot))
|
||||
unpackRoot = GetDefaultUnpackPackageRoot(packageName);
|
||||
else
|
||||
unpackRoot = UnpackFileSystemRoot;
|
||||
_unpackManifestFilesRoot = PathUtility.Combine(unpackRoot, BuiltinFileSystemConsts.UnpackManifestFilesFolderName);
|
||||
_unpackBundleFilesRoot = PathUtility.Combine(unpackRoot, BuiltinFileSystemConsts.UnpackBundleFilesFolderName);
|
||||
_tempFilesRoot = PathUtility.Combine(unpackRoot, BuiltinFileSystemConsts.UnpackTempFilesFolderName);
|
||||
|
||||
// 创建默认的下载后台接口
|
||||
if (DownloadBackend == null)
|
||||
DownloadBackend = new UnityWebRequestBackend(WebRequestCreator);
|
||||
|
||||
// 创建内置文件缓存系统
|
||||
{
|
||||
var cacheConfig = new BuiltinBundleCache.Configuration(
|
||||
assetBundleDecryptor: AssetBundleDecryptor,
|
||||
rawBundleDecryptor: RawBundleDecryptor,
|
||||
downloadBackend: DownloadBackend);
|
||||
BuiltinBundleCache = new BuiltinBundleCache(packageName, _packageRoot, cacheConfig);
|
||||
}
|
||||
|
||||
// 创建沙盒文件缓存系统
|
||||
{
|
||||
var cacheConfig = new SandboxBundleCache.Configuration(
|
||||
fileVerifyMaxConcurrency: FileVerifyMaxConcurrency,
|
||||
fileVerifyLevel: FileVerifyLevel,
|
||||
assetBundleDecryptor: AssetBundleDecryptor,
|
||||
rawBundleDecryptor: RawBundleDecryptor,
|
||||
assetBundleFallbackDecryptor: AssetBundleFallbackDecryptor);
|
||||
UnpackBundleCache = new SandboxBundleCache(packageName, _unpackBundleFilesRoot, cacheConfig);
|
||||
}
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public void OnDestroy()
|
||||
{
|
||||
if (BuiltinBundleCache != null)
|
||||
{
|
||||
BuiltinBundleCache.Dispose();
|
||||
BuiltinBundleCache = null;
|
||||
}
|
||||
|
||||
if (UnpackBundleCache != null)
|
||||
{
|
||||
UnpackBundleCache.Dispose();
|
||||
UnpackBundleCache = null;
|
||||
}
|
||||
|
||||
if (UnpackScheduler != null)
|
||||
{
|
||||
UnpackScheduler.AbortOperation();
|
||||
UnpackScheduler = null;
|
||||
}
|
||||
|
||||
if (DownloadBackend != null)
|
||||
{
|
||||
DownloadBackend.Dispose();
|
||||
DownloadBackend = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool CanAcceptBundle(PackageBundle bundle)
|
||||
{
|
||||
return BuiltinBundleCache.IsCached(bundle.BundleGuid);
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public bool IsDownloadRequired(PackageBundle bundle)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public bool IsUnpackRequired(PackageBundle bundle)
|
||||
{
|
||||
if (IsUnpackBundleFile(bundle))
|
||||
{
|
||||
return UnpackBundleCache.IsCached(bundle.BundleGuid) == false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public bool IsImportRequired(PackageBundle bundle)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否属于解压资源包文件
|
||||
/// </summary>
|
||||
public bool IsUnpackBundleFile(PackageBundle bundle)
|
||||
{
|
||||
if (CanAcceptBundle(bundle) == false)
|
||||
return false;
|
||||
|
||||
#if UNITY_ANDROID || UNITY_OPENHARMONY
|
||||
if (bundle.IsEncrypted)
|
||||
return true;
|
||||
|
||||
if (bundle.GetBundleType() == (int)EBundleType.RawBundle)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
#region 内部方法
|
||||
/// <summary>
|
||||
/// 获取默认的内置包裹根目录
|
||||
/// </summary>
|
||||
public string GetDefaultBuiltinPackageRoot(string packageName)
|
||||
{
|
||||
string rootDirectory = YooAssetConfiguration.GetDefaultBuiltinRoot();
|
||||
return PathUtility.Combine(rootDirectory, packageName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取内置文件路径
|
||||
/// </summary>
|
||||
public string GetBuiltinBundleFilePath(PackageBundle bundle)
|
||||
{
|
||||
if (_builtinFilePathMapping.TryGetValue(bundle.BundleGuid, out string filePath) == false)
|
||||
{
|
||||
filePath = PathUtility.Combine(_packageRoot, bundle.GetFileName());
|
||||
_builtinFilePathMapping.Add(bundle.BundleGuid, filePath);
|
||||
}
|
||||
return filePath;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取内置包裹版本文件路径
|
||||
/// </summary>
|
||||
public string GetBuiltinPackageVersionFilePath()
|
||||
{
|
||||
string fileName = YooAssetConfiguration.GetPackageVersionFileName(PackageName);
|
||||
return PathUtility.Combine(_packageRoot, fileName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取内置包裹哈希文件路径
|
||||
/// </summary>
|
||||
public string GetBuiltinPackageHashFilePath(string packageVersion)
|
||||
{
|
||||
string fileName = YooAssetConfiguration.GetPackageHashFileName(PackageName, packageVersion);
|
||||
return PathUtility.Combine(_packageRoot, fileName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取内置包裹清单文件路径
|
||||
/// </summary>
|
||||
public string GetBuiltinPackageManifestFilePath(string packageVersion)
|
||||
{
|
||||
string fileName = YooAssetConfiguration.GetManifestBinaryFileName(PackageName, packageVersion);
|
||||
return PathUtility.Combine(_packageRoot, fileName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取沙盒应用程序水印文件路径
|
||||
/// </summary>
|
||||
public string GetSandboxAppFootprintFilePath()
|
||||
{
|
||||
return PathUtility.Combine(_unpackManifestFilesRoot, SandboxFileSystemConsts.AppFootprintFileName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除所有缓存的资源文件
|
||||
/// </summary>
|
||||
public void DeleteAllBundleFiles()
|
||||
{
|
||||
if (Directory.Exists(_unpackBundleFilesRoot))
|
||||
{
|
||||
Directory.Delete(_unpackBundleFilesRoot, true);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除所有缓存的清单文件
|
||||
/// </summary>
|
||||
public void DeleteAllManifestFiles()
|
||||
{
|
||||
if (Directory.Exists(_unpackManifestFilesRoot))
|
||||
{
|
||||
Directory.Delete(_unpackManifestFilesRoot, true);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除所有缓存的临时文件
|
||||
/// </summary>
|
||||
public void DeleteAllTempFiles()
|
||||
{
|
||||
if (Directory.Exists(_tempFilesRoot))
|
||||
{
|
||||
Directory.Delete(_tempFilesRoot, true);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取默认的解压根目录
|
||||
/// </summary>
|
||||
public string GetDefaultUnpackPackageRoot(string packageName)
|
||||
{
|
||||
string rootDirectory = YooAssetConfiguration.GetDefaultCacheRoot();
|
||||
return PathUtility.Combine(rootDirectory, packageName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取解压的临时文件路径
|
||||
/// </summary>
|
||||
public string GetUnpackTempFilePath(PackageBundle bundle)
|
||||
{
|
||||
if (_tempFilePathMapping.TryGetValue(bundle.BundleGuid, out string filePath) == false)
|
||||
{
|
||||
filePath = PathUtility.Combine(_tempFilesRoot, bundle.BundleGuid);
|
||||
_tempFilePathMapping.Add(bundle.BundleGuid, filePath);
|
||||
}
|
||||
return filePath;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 98465b987635afc479022ec358477491
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,24 @@
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 内置文件系统常量定义
|
||||
/// </summary>
|
||||
internal static class BuiltinFileSystemConsts
|
||||
{
|
||||
/// <summary>
|
||||
/// 解压清单文件的文件夹名称
|
||||
/// </summary>
|
||||
public const string UnpackManifestFilesFolderName = "UnpackManifestFiles";
|
||||
|
||||
/// <summary>
|
||||
/// 解压资源文件的文件夹名称
|
||||
/// </summary>
|
||||
public const string UnpackBundleFilesFolderName = "UnpackBundleFiles";
|
||||
|
||||
/// <summary>
|
||||
/// 解压临时文件的文件夹名称
|
||||
/// </summary>
|
||||
public const string UnpackTempFilesFolderName = "UnpackTempFiles";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4aa038f71ffd2394abc5daee917fbc66
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 06f6a75331ed07a4a9e5e8f46dcf157e
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,74 @@
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 内置文件系统的清理缓存操作
|
||||
/// </summary>
|
||||
internal sealed class BFSClearCacheOperation : FSClearCacheOperation
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
CheckReadOnly,
|
||||
ClearCache,
|
||||
Done,
|
||||
}
|
||||
|
||||
private readonly BuiltinFileSystem _fileSystem;
|
||||
private readonly FSClearCacheOptions _options;
|
||||
private BCClearCacheOperation _clearCacheOp;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
internal BFSClearCacheOperation(BuiltinFileSystem fileSystem, FSClearCacheOptions options)
|
||||
{
|
||||
_fileSystem = fileSystem;
|
||||
_options = options;
|
||||
}
|
||||
protected override void InternalStart()
|
||||
{
|
||||
_steps = ESteps.CheckReadOnly;
|
||||
}
|
||||
protected override void InternalUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
if (_steps == ESteps.CheckReadOnly)
|
||||
{
|
||||
if (_fileSystem.UnpackBundleCache.IsReadOnly)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetResult();
|
||||
return;
|
||||
}
|
||||
|
||||
_steps = ESteps.ClearCache;
|
||||
}
|
||||
|
||||
if (_steps == ESteps.ClearCache)
|
||||
{
|
||||
if (_clearCacheOp == null)
|
||||
{
|
||||
_clearCacheOp = _fileSystem.UnpackBundleCache.ClearCacheAsync(_options.ConvertTo());
|
||||
_clearCacheOp.StartOperation();
|
||||
AddChildOperation(_clearCacheOp);
|
||||
}
|
||||
|
||||
_clearCacheOp.UpdateOperation();
|
||||
if (_clearCacheOp.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_clearCacheOp.Status == EOperationStatus.Succeeded)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetResult();
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError(_clearCacheOp.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3852e5e9188e72d488f02467606a39e6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,108 @@
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 内置文件系统的解压文件操作
|
||||
/// </summary>
|
||||
internal sealed class BFSDownloadBundleOperation : FSDownloadBundleOperation
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
CheckExists,
|
||||
CreateUnpack,
|
||||
CheckUnpack,
|
||||
Done,
|
||||
}
|
||||
|
||||
private readonly BuiltinFileSystem _fileSystem;
|
||||
private readonly FSDownloadBundleOptions _options;
|
||||
private DownloadFileBaseOperation _downloadFileOp;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
internal BFSDownloadBundleOperation(BuiltinFileSystem fileSystem, FSDownloadBundleOptions options) : base(options.Bundle)
|
||||
{
|
||||
_fileSystem = fileSystem;
|
||||
_options = options;
|
||||
}
|
||||
protected override void InternalStart()
|
||||
{
|
||||
_steps = ESteps.CheckExists;
|
||||
}
|
||||
protected override void InternalUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
// 检测文件是否存在
|
||||
if (_steps == ESteps.CheckExists)
|
||||
{
|
||||
if (_fileSystem.UnpackBundleCache.IsCached(Bundle.BundleGuid))
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetResult();
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.CreateUnpack;
|
||||
}
|
||||
}
|
||||
|
||||
// 创建解压器
|
||||
if (_steps == ESteps.CreateUnpack)
|
||||
{
|
||||
_downloadFileOp = _fileSystem.UnpackScheduler.TryGetDownloadOperation(Bundle);
|
||||
if (_downloadFileOp == null)
|
||||
{
|
||||
string builtinFilePath = _fileSystem.GetBuiltinBundleFilePath(Bundle);
|
||||
_downloadFileOp = new UnpackAndCacheFileOperation(_fileSystem, Bundle, builtinFilePath);
|
||||
_fileSystem.UnpackScheduler.RegisterDownloadOperation(_downloadFileOp);
|
||||
}
|
||||
|
||||
_steps = ESteps.CheckUnpack;
|
||||
}
|
||||
|
||||
// 检测结果
|
||||
if (_steps == ESteps.CheckUnpack)
|
||||
{
|
||||
if (IsWaitForCompletion)
|
||||
_downloadFileOp.WaitForCompletion();
|
||||
|
||||
// 注意:不主动调用 _downloadFileOp.UpdateOperation()
|
||||
// 说明:解压任务由 UnpackScheduler 统一驱动,此处仅读取状态。
|
||||
// 说明:同步等待由 WaitForCompletion() 内部的 ExecuteBatch() 保证。
|
||||
Progress = _downloadFileOp.Progress;
|
||||
Report = _downloadFileOp.LatestReport;
|
||||
if (_downloadFileOp.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_downloadFileOp.Status == EOperationStatus.Succeeded)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetResult();
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError(_downloadFileOp.Error);
|
||||
YooLogger.LogError(Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
protected override void InternalWaitForCompletion()
|
||||
{
|
||||
ExecuteBatch();
|
||||
}
|
||||
protected override void InternalAbort()
|
||||
{
|
||||
// 注意:取消下载任务的时候引用计数减一
|
||||
if (_steps != ESteps.Done)
|
||||
{
|
||||
if (_downloadFileOp != null)
|
||||
{
|
||||
_downloadFileOp.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 899d85c6278629e40a36bc616b53bd95
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,192 @@
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 内置文件系统的初始化操作
|
||||
/// </summary>
|
||||
internal sealed class BFSInitializeOperation : FSInitializeOperation
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
CheckPlatform,
|
||||
CheckAppFootprint,
|
||||
CopyPackageManifest,
|
||||
InitializeBuiltinBundleCache,
|
||||
InitializeUnpackBundleCache,
|
||||
CreateScheduler,
|
||||
Done,
|
||||
}
|
||||
|
||||
private readonly BuiltinFileSystem _fileSystem;
|
||||
private BCInitializeOperation _initializeBuiltinBundleCacheOp;
|
||||
private BCInitializeOperation _initializeUnpackBundleCacheOp;
|
||||
private CopyBuiltinPackageManifestOperation _copyBuiltinPackageManifestOp;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
internal BFSInitializeOperation(BuiltinFileSystem fileSystem)
|
||||
{
|
||||
_fileSystem = fileSystem;
|
||||
}
|
||||
protected override void InternalStart()
|
||||
{
|
||||
_steps = ESteps.CheckPlatform;
|
||||
}
|
||||
protected override void InternalUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
if (_steps == ESteps.CheckPlatform)
|
||||
{
|
||||
#if UNITY_WEBGL
|
||||
_steps = ESteps.Done;
|
||||
SetError($"{nameof(BuiltinFileSystem)} does not support the WebGL platform.");
|
||||
#else
|
||||
_steps = ESteps.CheckAppFootprint;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (_steps == ESteps.CheckAppFootprint)
|
||||
{
|
||||
string footprintFilePath = _fileSystem.GetSandboxAppFootprintFilePath();
|
||||
var appFootprint = new ApplicationFootprint(footprintFilePath);
|
||||
appFootprint.Load(_fileSystem.PackageName);
|
||||
|
||||
// 如果水印发生变化,则说明覆盖安装后首次打开游戏
|
||||
if (appFootprint.IsDirty())
|
||||
{
|
||||
if (_fileSystem.InstallCleanupMode == EInstallCleanupMode.None)
|
||||
{
|
||||
YooLogger.LogWarning("No action required on overwrite installation.");
|
||||
}
|
||||
else if (_fileSystem.InstallCleanupMode == EInstallCleanupMode.ClearAllCacheFiles)
|
||||
{
|
||||
_fileSystem.DeleteAllBundleFiles();
|
||||
_fileSystem.DeleteAllManifestFiles();
|
||||
_fileSystem.DeleteAllTempFiles();
|
||||
YooLogger.LogWarning("Deleted all cache files on overwrite installation.");
|
||||
}
|
||||
else if (_fileSystem.InstallCleanupMode == EInstallCleanupMode.ClearAllBundleFiles)
|
||||
{
|
||||
_fileSystem.DeleteAllBundleFiles();
|
||||
YooLogger.LogWarning("Deleted all bundle files on overwrite installation.");
|
||||
}
|
||||
else if (_fileSystem.InstallCleanupMode == EInstallCleanupMode.ClearAllManifestFiles)
|
||||
{
|
||||
_fileSystem.DeleteAllManifestFiles();
|
||||
YooLogger.LogWarning("Deleted all manifest files on overwrite installation.");
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new YooInternalException($"Unhandled {nameof(EInstallCleanupMode)} value: {_fileSystem.InstallCleanupMode}.");
|
||||
}
|
||||
|
||||
appFootprint.Overwrite(_fileSystem.PackageName);
|
||||
}
|
||||
|
||||
_steps = ESteps.CopyPackageManifest;
|
||||
}
|
||||
|
||||
if (_steps == ESteps.CopyPackageManifest)
|
||||
{
|
||||
if (_fileSystem.CopyBuiltinPackageManifest)
|
||||
{
|
||||
if (_copyBuiltinPackageManifestOp == null)
|
||||
{
|
||||
_copyBuiltinPackageManifestOp = new CopyBuiltinPackageManifestOperation(_fileSystem);
|
||||
_copyBuiltinPackageManifestOp.StartOperation();
|
||||
AddChildOperation(_copyBuiltinPackageManifestOp);
|
||||
}
|
||||
|
||||
_copyBuiltinPackageManifestOp.UpdateOperation();
|
||||
if (_copyBuiltinPackageManifestOp.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_copyBuiltinPackageManifestOp.Status == EOperationStatus.Succeeded)
|
||||
{
|
||||
_steps = ESteps.InitializeBuiltinBundleCache;
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError(_copyBuiltinPackageManifestOp.Error);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.InitializeBuiltinBundleCache;
|
||||
}
|
||||
}
|
||||
|
||||
if (_steps == ESteps.InitializeBuiltinBundleCache)
|
||||
{
|
||||
if (_initializeBuiltinBundleCacheOp == null)
|
||||
{
|
||||
_initializeBuiltinBundleCacheOp = _fileSystem.BuiltinBundleCache.InitializeAsync();
|
||||
_initializeBuiltinBundleCacheOp.StartOperation();
|
||||
AddChildOperation(_initializeBuiltinBundleCacheOp);
|
||||
}
|
||||
|
||||
_initializeBuiltinBundleCacheOp.UpdateOperation();
|
||||
Progress = _initializeBuiltinBundleCacheOp.Progress;
|
||||
if (_initializeBuiltinBundleCacheOp.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_initializeBuiltinBundleCacheOp.Status == EOperationStatus.Succeeded)
|
||||
{
|
||||
_steps = ESteps.InitializeUnpackBundleCache;
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError(_initializeBuiltinBundleCacheOp.Error);
|
||||
}
|
||||
}
|
||||
|
||||
if (_steps == ESteps.InitializeUnpackBundleCache)
|
||||
{
|
||||
if (_initializeUnpackBundleCacheOp == null)
|
||||
{
|
||||
_initializeUnpackBundleCacheOp = _fileSystem.UnpackBundleCache.InitializeAsync();
|
||||
_initializeUnpackBundleCacheOp.StartOperation();
|
||||
AddChildOperation(_initializeUnpackBundleCacheOp);
|
||||
}
|
||||
|
||||
_initializeUnpackBundleCacheOp.UpdateOperation();
|
||||
Progress = _initializeUnpackBundleCacheOp.Progress;
|
||||
if (_initializeUnpackBundleCacheOp.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_initializeUnpackBundleCacheOp.Status == EOperationStatus.Succeeded)
|
||||
{
|
||||
_steps = ESteps.CreateScheduler;
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError(_initializeUnpackBundleCacheOp.Error);
|
||||
}
|
||||
}
|
||||
|
||||
if (_steps == ESteps.CreateScheduler)
|
||||
{
|
||||
// 注意: 下载调度中心在最后一步创建,防止初始化失败后残留任务。
|
||||
// 注意: 下载调度中心作为独立任务运行!
|
||||
if (_fileSystem.UnpackScheduler == null)
|
||||
{
|
||||
var schedulerConfig = new DownloadSchedulerOperation.Configuration(
|
||||
schedulerName: _fileSystem.GetType().Name,
|
||||
downloadBackend: _fileSystem.DownloadBackend,
|
||||
maxConcurrency: _fileSystem.UnpackMaxConcurrency,
|
||||
maxRequestsPerFrame: _fileSystem.UnpackMaxRequestsPerFrame);
|
||||
_fileSystem.UnpackScheduler = new DownloadSchedulerOperation(schedulerConfig);
|
||||
AsyncOperationSystem.StartOperation(_fileSystem.PackageName, _fileSystem.UnpackScheduler);
|
||||
}
|
||||
|
||||
_steps = ESteps.Done;
|
||||
SetResult();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a15804d2ba6172a4b91f6c17245495a6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,165 @@
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 内置文件系统的加载资源包操作
|
||||
/// </summary>
|
||||
internal sealed class BFSLoadPackageBundleOperation : FSLoadPackageBundleOperation
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
Prepare,
|
||||
UnpackFile,
|
||||
AbortUnpack,
|
||||
LoadUnpackBundle,
|
||||
LoadBundle,
|
||||
CheckResult,
|
||||
Done,
|
||||
}
|
||||
|
||||
private readonly BuiltinFileSystem _fileSystem;
|
||||
private readonly FSLoadPackageBundleOptions _options;
|
||||
private FSDownloadBundleOperation _unpackFileOp;
|
||||
private BCLoadBundleOperation _loadBundleOp;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
internal BFSLoadPackageBundleOperation(BuiltinFileSystem fileSystem, FSLoadPackageBundleOptions options)
|
||||
{
|
||||
_fileSystem = fileSystem;
|
||||
_options = options;
|
||||
}
|
||||
protected override void InternalStart()
|
||||
{
|
||||
_steps = ESteps.Prepare;
|
||||
}
|
||||
protected override void InternalUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
if (_steps == ESteps.Prepare)
|
||||
{
|
||||
if (_fileSystem.IsUnpackBundleFile(_options.Bundle))
|
||||
{
|
||||
if (_fileSystem.UnpackBundleCache.IsCached(_options.Bundle.BundleGuid))
|
||||
_steps = ESteps.LoadUnpackBundle;
|
||||
else
|
||||
_steps = ESteps.UnpackFile;
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.LoadBundle;
|
||||
}
|
||||
}
|
||||
|
||||
if (_steps == ESteps.UnpackFile)
|
||||
{
|
||||
// 中断解压
|
||||
if (ShouldAbortDownload)
|
||||
{
|
||||
if (_unpackFileOp != null)
|
||||
_unpackFileOp.AbortOperation();
|
||||
_steps = ESteps.AbortUnpack;
|
||||
}
|
||||
}
|
||||
|
||||
if (_steps == ESteps.UnpackFile)
|
||||
{
|
||||
if (_unpackFileOp == null)
|
||||
{
|
||||
// 注意:内置文件解压不做失败尝试
|
||||
var options = new FSDownloadBundleOptions(_options.Bundle, 0);
|
||||
_unpackFileOp = _fileSystem.DownloadBundleAsync(options);
|
||||
_unpackFileOp.StartOperation();
|
||||
AddChildOperation(_unpackFileOp);
|
||||
}
|
||||
|
||||
if (IsWaitForCompletion)
|
||||
_unpackFileOp.WaitForCompletion();
|
||||
|
||||
_unpackFileOp.UpdateOperation();
|
||||
if (_unpackFileOp.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_unpackFileOp.Status == EOperationStatus.Succeeded)
|
||||
{
|
||||
_steps = ESteps.LoadUnpackBundle;
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError(_unpackFileOp.Error);
|
||||
}
|
||||
}
|
||||
|
||||
if (_steps == ESteps.AbortUnpack)
|
||||
{
|
||||
if (_unpackFileOp != null)
|
||||
{
|
||||
if (IsWaitForCompletion)
|
||||
_unpackFileOp.WaitForCompletion();
|
||||
|
||||
_unpackFileOp.UpdateOperation();
|
||||
if (_unpackFileOp.IsDone == false)
|
||||
return;
|
||||
}
|
||||
|
||||
_steps = ESteps.Done;
|
||||
SetError("Bundle download aborted.");
|
||||
}
|
||||
|
||||
if (_steps == ESteps.LoadUnpackBundle)
|
||||
{
|
||||
_loadBundleOp = _fileSystem.UnpackBundleCache.LoadBundleAsync(_options.ConvertTo());
|
||||
_loadBundleOp.StartOperation();
|
||||
AddChildOperation(_loadBundleOp);
|
||||
_steps = ESteps.CheckResult;
|
||||
}
|
||||
|
||||
if (_steps == ESteps.LoadBundle)
|
||||
{
|
||||
_loadBundleOp = _fileSystem.BuiltinBundleCache.LoadBundleAsync(_options.ConvertTo());
|
||||
_loadBundleOp.StartOperation();
|
||||
AddChildOperation(_loadBundleOp);
|
||||
_steps = ESteps.CheckResult;
|
||||
}
|
||||
|
||||
if (_steps == ESteps.CheckResult)
|
||||
{
|
||||
if (IsWaitForCompletion)
|
||||
_loadBundleOp.WaitForCompletion();
|
||||
|
||||
_loadBundleOp.UpdateOperation();
|
||||
if (_loadBundleOp.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_loadBundleOp.Status == EOperationStatus.Succeeded)
|
||||
{
|
||||
if (_loadBundleOp.BundleHandle == null)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError("Fatal error: loaded bundle handle is null.");
|
||||
YooLogger.LogError(Error);
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetResult();
|
||||
BundleHandle = _loadBundleOp.BundleHandle;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError(_loadBundleOp.Error);
|
||||
YooLogger.LogError(Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
protected override void InternalWaitForCompletion()
|
||||
{
|
||||
ExecuteBatch();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 99fc95c784d960c45ba9373f31fbc7fe
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,90 @@
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 内置文件系统的加载包裹清单操作
|
||||
/// </summary>
|
||||
internal sealed class BFSLoadPackageManifestOperation : FSLoadPackageManifestOperation
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
RequestPackageHash,
|
||||
LoadPackageManifest,
|
||||
Done,
|
||||
}
|
||||
|
||||
private readonly BuiltinFileSystem _fileSystem;
|
||||
private readonly string _packageVersion;
|
||||
private RequestBuiltinPackageHashOperation _requestBuiltinPackageHashOp;
|
||||
private LoadBuiltinPackageManifestOperation _loadBuiltinPackageManifestOp;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
|
||||
internal BFSLoadPackageManifestOperation(BuiltinFileSystem fileSystem, string packageVersion)
|
||||
{
|
||||
_fileSystem = fileSystem;
|
||||
_packageVersion = packageVersion;
|
||||
}
|
||||
protected override void InternalStart()
|
||||
{
|
||||
_steps = ESteps.RequestPackageHash;
|
||||
}
|
||||
protected override void InternalUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
if (_steps == ESteps.RequestPackageHash)
|
||||
{
|
||||
if (_requestBuiltinPackageHashOp == null)
|
||||
{
|
||||
_requestBuiltinPackageHashOp = new RequestBuiltinPackageHashOperation(_fileSystem, _packageVersion);
|
||||
_requestBuiltinPackageHashOp.StartOperation();
|
||||
AddChildOperation(_requestBuiltinPackageHashOp);
|
||||
}
|
||||
|
||||
_requestBuiltinPackageHashOp.UpdateOperation();
|
||||
if (_requestBuiltinPackageHashOp.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_requestBuiltinPackageHashOp.Status == EOperationStatus.Succeeded)
|
||||
{
|
||||
_steps = ESteps.LoadPackageManifest;
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError(_requestBuiltinPackageHashOp.Error);
|
||||
}
|
||||
}
|
||||
|
||||
if (_steps == ESteps.LoadPackageManifest)
|
||||
{
|
||||
if (_loadBuiltinPackageManifestOp == null)
|
||||
{
|
||||
string packageHash = _requestBuiltinPackageHashOp.PackageHash;
|
||||
_loadBuiltinPackageManifestOp = new LoadBuiltinPackageManifestOperation(_fileSystem, _packageVersion, packageHash);
|
||||
_loadBuiltinPackageManifestOp.StartOperation();
|
||||
AddChildOperation(_loadBuiltinPackageManifestOp);
|
||||
}
|
||||
|
||||
_loadBuiltinPackageManifestOp.UpdateOperation();
|
||||
if (_loadBuiltinPackageManifestOp.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_loadBuiltinPackageManifestOp.Status == EOperationStatus.Succeeded)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetResult();
|
||||
Manifest = _loadBuiltinPackageManifestOp.Manifest;
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError(_loadBuiltinPackageManifestOp.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b55b3624add2db6489954d999b13a9ec
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,61 @@
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 内置文件系统的查询包裹版本操作
|
||||
/// </summary>
|
||||
internal sealed class BFSRequestPackageVersionOperation : FSRequestPackageVersionOperation
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
RequestPackageVersion,
|
||||
Done,
|
||||
}
|
||||
|
||||
private readonly BuiltinFileSystem _fileSystem;
|
||||
private RequestBuiltinPackageVersionOperation _requestBuiltinPackageVersionOp;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
|
||||
internal BFSRequestPackageVersionOperation(BuiltinFileSystem fileSystem)
|
||||
{
|
||||
_fileSystem = fileSystem;
|
||||
}
|
||||
protected override void InternalStart()
|
||||
{
|
||||
_steps = ESteps.RequestPackageVersion;
|
||||
}
|
||||
protected override void InternalUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
if (_steps == ESteps.RequestPackageVersion)
|
||||
{
|
||||
if (_requestBuiltinPackageVersionOp == null)
|
||||
{
|
||||
_requestBuiltinPackageVersionOp = new RequestBuiltinPackageVersionOperation(_fileSystem);
|
||||
_requestBuiltinPackageVersionOp.StartOperation();
|
||||
AddChildOperation(_requestBuiltinPackageVersionOp);
|
||||
}
|
||||
|
||||
_requestBuiltinPackageVersionOp.UpdateOperation();
|
||||
if (_requestBuiltinPackageVersionOp.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_requestBuiltinPackageVersionOp.Status == EOperationStatus.Succeeded)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
PackageVersion = _requestBuiltinPackageVersionOp.PackageVersion;
|
||||
SetResult();
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError(_requestBuiltinPackageVersionOp.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f0b6ec24639af3741847a6a7ef09986a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,142 @@
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 拷贝内置包裹清单到沙盒操作
|
||||
/// </summary>
|
||||
internal sealed class CopyBuiltinPackageManifestOperation : AsyncOperationBase
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
LoadBuiltinPackageVersion,
|
||||
CopyBuiltinPackageHash,
|
||||
CopyBuiltinPackageManifest,
|
||||
Done,
|
||||
}
|
||||
|
||||
private readonly BuiltinFileSystem _fileSystem;
|
||||
private RequestBuiltinPackageVersionOperation _requestBuiltinPackageVersionOp;
|
||||
private CopyBuiltinFileOperation _copyBuiltinHashFileOp;
|
||||
private CopyBuiltinFileOperation _copyBuiltinManifestFileOp;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
public CopyBuiltinPackageManifestOperation(BuiltinFileSystem fileSystem)
|
||||
{
|
||||
_fileSystem = fileSystem;
|
||||
}
|
||||
protected override void InternalStart()
|
||||
{
|
||||
_steps = ESteps.LoadBuiltinPackageVersion;
|
||||
}
|
||||
protected override void InternalUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
if (_steps == ESteps.LoadBuiltinPackageVersion)
|
||||
{
|
||||
if (_requestBuiltinPackageVersionOp == null)
|
||||
{
|
||||
_requestBuiltinPackageVersionOp = new RequestBuiltinPackageVersionOperation(_fileSystem);
|
||||
_requestBuiltinPackageVersionOp.StartOperation();
|
||||
AddChildOperation(_requestBuiltinPackageVersionOp);
|
||||
}
|
||||
|
||||
_requestBuiltinPackageVersionOp.UpdateOperation();
|
||||
if (_requestBuiltinPackageVersionOp.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_requestBuiltinPackageVersionOp.Status == EOperationStatus.Succeeded)
|
||||
{
|
||||
_steps = ESteps.CopyBuiltinPackageHash;
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError(_requestBuiltinPackageVersionOp.Error);
|
||||
}
|
||||
}
|
||||
|
||||
if (_steps == ESteps.CopyBuiltinPackageHash)
|
||||
{
|
||||
if (_copyBuiltinHashFileOp == null)
|
||||
{
|
||||
// 注意:只负责拷贝文件,不负责校验文件。
|
||||
string packageVersion = _requestBuiltinPackageVersionOp.PackageVersion;
|
||||
string destFilePath = GetCopyPackageHashDestPath(packageVersion);
|
||||
string sourceFilePath = _fileSystem.GetBuiltinPackageHashFilePath(packageVersion);
|
||||
_copyBuiltinHashFileOp = new CopyBuiltinFileOperation(_fileSystem, sourceFilePath, destFilePath);
|
||||
_copyBuiltinHashFileOp.StartOperation();
|
||||
AddChildOperation(_copyBuiltinHashFileOp);
|
||||
}
|
||||
|
||||
_copyBuiltinHashFileOp.UpdateOperation();
|
||||
if (_copyBuiltinHashFileOp.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_copyBuiltinHashFileOp.Status == EOperationStatus.Succeeded)
|
||||
{
|
||||
_steps = ESteps.CopyBuiltinPackageManifest;
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError(_copyBuiltinHashFileOp.Error);
|
||||
}
|
||||
}
|
||||
|
||||
if (_steps == ESteps.CopyBuiltinPackageManifest)
|
||||
{
|
||||
if (_copyBuiltinManifestFileOp == null)
|
||||
{
|
||||
// 注意:只负责拷贝文件,不负责校验文件。
|
||||
string packageVersion = _requestBuiltinPackageVersionOp.PackageVersion;
|
||||
string destFilePath = GetCopyPackageManifestDestPath(packageVersion);
|
||||
string sourceFilePath = _fileSystem.GetBuiltinPackageManifestFilePath(packageVersion);
|
||||
_copyBuiltinManifestFileOp = new CopyBuiltinFileOperation(_fileSystem, sourceFilePath, destFilePath);
|
||||
_copyBuiltinManifestFileOp.StartOperation();
|
||||
AddChildOperation(_copyBuiltinManifestFileOp);
|
||||
}
|
||||
|
||||
_copyBuiltinManifestFileOp.UpdateOperation();
|
||||
if (_copyBuiltinManifestFileOp.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_copyBuiltinManifestFileOp.Status == EOperationStatus.Succeeded)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetResult();
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError(_copyBuiltinManifestFileOp.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string GetCopyManifestFileRoot()
|
||||
{
|
||||
string destRoot = _fileSystem.CopyBuiltinPackageManifestDestRoot;
|
||||
if (string.IsNullOrEmpty(destRoot))
|
||||
{
|
||||
string defaultCacheRoot = YooAssetConfiguration.GetDefaultCacheRoot();
|
||||
destRoot = PathUtility.Combine(defaultCacheRoot, _fileSystem.PackageName, SandboxFileSystemConsts.ManifestFilesFolderName);
|
||||
}
|
||||
return destRoot;
|
||||
}
|
||||
private string GetCopyPackageHashDestPath(string packageVersion)
|
||||
{
|
||||
string fileRoot = GetCopyManifestFileRoot();
|
||||
string fileName = YooAssetConfiguration.GetPackageHashFileName(_fileSystem.PackageName, packageVersion);
|
||||
return PathUtility.Combine(fileRoot, fileName);
|
||||
}
|
||||
private string GetCopyPackageManifestDestPath(string packageVersion)
|
||||
{
|
||||
string fileRoot = GetCopyManifestFileRoot();
|
||||
string fileName = YooAssetConfiguration.GetManifestBinaryFileName(_fileSystem.PackageName, packageVersion);
|
||||
return PathUtility.Combine(fileRoot, fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9cbc466f7e0e94d4fb7ab6ba63c89497
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: be1c19353672bb34ca3e4ddcb462402f
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,123 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 拷贝内置文件操作
|
||||
/// </summary>
|
||||
internal sealed class CopyBuiltinFileOperation : AsyncOperationBase
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
CheckFileExist,
|
||||
TryCopyFile,
|
||||
UnpackFile,
|
||||
Done,
|
||||
}
|
||||
|
||||
private readonly BuiltinFileSystem _fileSystem;
|
||||
private readonly string _sourceFilePath;
|
||||
private readonly string _destFilePath;
|
||||
private IDownloadFileRequest _downloadFileRequest;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
internal CopyBuiltinFileOperation(BuiltinFileSystem fileSystem, string sourceFilePath, string destFilePath)
|
||||
{
|
||||
_fileSystem = fileSystem;
|
||||
_sourceFilePath = sourceFilePath;
|
||||
_destFilePath = destFilePath;
|
||||
}
|
||||
protected override void InternalStart()
|
||||
{
|
||||
_steps = ESteps.CheckFileExist;
|
||||
}
|
||||
protected override void InternalUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
if (_steps == ESteps.CheckFileExist)
|
||||
{
|
||||
// 注意:只检查目标文件是否存在,不校验完整性。
|
||||
// 说明:文件校验由后续的缓存写入流程负责。
|
||||
if (File.Exists(_destFilePath))
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetResult();
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.TryCopyFile;
|
||||
}
|
||||
}
|
||||
|
||||
if (_steps == ESteps.TryCopyFile)
|
||||
{
|
||||
if (File.Exists(_sourceFilePath))
|
||||
{
|
||||
try
|
||||
{
|
||||
FileUtility.EnsureParentDirectoryExists(_destFilePath);
|
||||
File.Copy(_sourceFilePath, _destFilePath, true);
|
||||
_steps = ESteps.Done;
|
||||
SetResult();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
YooLogger.LogWarning($"Failed to copy builtin file: {ex.Message}.");
|
||||
_steps = ESteps.UnpackFile;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.UnpackFile;
|
||||
}
|
||||
}
|
||||
|
||||
if (_steps == ESteps.UnpackFile)
|
||||
{
|
||||
if (_downloadFileRequest == null)
|
||||
{
|
||||
// TODO: 团结引擎,在某些安卓机型(红米),通过UnityWebRequest拷贝包内文件会小概率失败!需要借助其它方式来拷贝包内文件。
|
||||
string url = DownloadUrlHelper.ToLocalFileUrl(_sourceFilePath);
|
||||
var args = new DownloadFileRequestArgs(
|
||||
url: url,
|
||||
timeout: 60,
|
||||
watchdogTimeout: 0,
|
||||
savePath: _destFilePath);
|
||||
_downloadFileRequest = _fileSystem.DownloadBackend.CreateFileRequest(args);
|
||||
_downloadFileRequest.SendRequest();
|
||||
}
|
||||
|
||||
if (_downloadFileRequest.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_downloadFileRequest.Status == EDownloadRequestStatus.Succeeded)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetResult();
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError(_downloadFileRequest.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
protected override void InternalDispose()
|
||||
{
|
||||
if (_downloadFileRequest != null)
|
||||
{
|
||||
_downloadFileRequest.Dispose();
|
||||
_downloadFileRequest = null;
|
||||
}
|
||||
}
|
||||
protected override void InternalWaitForCompletion()
|
||||
{
|
||||
//注意:等待解压本地文件完毕,该操作会挂起主线程!
|
||||
ExecuteUntilComplete();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bf44368bc5c2bf1479c36d82e931c295
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,153 @@
|
||||
using System.IO;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 加载内置包裹清单文件操作
|
||||
/// </summary>
|
||||
internal sealed class LoadBuiltinPackageManifestOperation : AsyncOperationBase
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
TryLoadFileData,
|
||||
RequestFileData,
|
||||
VerifyFileData,
|
||||
LoadManifest,
|
||||
Done,
|
||||
}
|
||||
|
||||
private readonly BuiltinFileSystem _fileSystem;
|
||||
private readonly string _packageVersion;
|
||||
private readonly string _packageHash;
|
||||
private IDownloadBytesRequest _downloadBytesRequest;
|
||||
private DeserializeManifestOperation _deserializeManifestOp;
|
||||
private byte[] _fileData;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
/// <summary>
|
||||
/// 包裹清单
|
||||
/// </summary>
|
||||
public PackageManifest Manifest { get; private set; }
|
||||
|
||||
|
||||
internal LoadBuiltinPackageManifestOperation(BuiltinFileSystem fileSystem, string packageVersion, string packageHash)
|
||||
{
|
||||
_fileSystem = fileSystem;
|
||||
_packageVersion = packageVersion;
|
||||
_packageHash = packageHash;
|
||||
}
|
||||
protected override void InternalStart()
|
||||
{
|
||||
_steps = ESteps.TryLoadFileData;
|
||||
}
|
||||
protected override void InternalUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
if (_steps == ESteps.TryLoadFileData)
|
||||
{
|
||||
string filePath = _fileSystem.GetBuiltinPackageManifestFilePath(_packageVersion);
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
try
|
||||
{
|
||||
_fileData = File.ReadAllBytes(filePath);
|
||||
_steps = ESteps.VerifyFileData;
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError($"Failed to read builtin package manifest file: {ex.Message}.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.RequestFileData;
|
||||
}
|
||||
}
|
||||
|
||||
if (_steps == ESteps.RequestFileData)
|
||||
{
|
||||
if (_downloadBytesRequest == null)
|
||||
{
|
||||
string filePath = _fileSystem.GetBuiltinPackageManifestFilePath(_packageVersion);
|
||||
string url = DownloadUrlHelper.ToLocalFileUrl(filePath);
|
||||
var args = new DownloadDataRequestArgs(
|
||||
url: url,
|
||||
timeout: 60,
|
||||
watchdogTimeout: 0);
|
||||
_downloadBytesRequest = _fileSystem.DownloadBackend.CreateBytesRequest(args);
|
||||
_downloadBytesRequest.SendRequest();
|
||||
}
|
||||
|
||||
if (_downloadBytesRequest.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_downloadBytesRequest.Status == EDownloadRequestStatus.Succeeded)
|
||||
{
|
||||
_fileData = _downloadBytesRequest.Result;
|
||||
_steps = ESteps.VerifyFileData;
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError(_downloadBytesRequest.Error);
|
||||
}
|
||||
}
|
||||
|
||||
if (_steps == ESteps.VerifyFileData)
|
||||
{
|
||||
if (PackageManifestHelper.VerifyManifestData(_fileData, _packageHash))
|
||||
{
|
||||
_steps = ESteps.LoadManifest;
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError("Failed to verify builtin package manifest file.");
|
||||
}
|
||||
}
|
||||
|
||||
if (_steps == ESteps.LoadManifest)
|
||||
{
|
||||
if (_deserializeManifestOp == null)
|
||||
{
|
||||
_deserializeManifestOp = new DeserializeManifestOperation(_fileSystem.ManifestDecryptor, _fileData);
|
||||
_deserializeManifestOp.StartOperation();
|
||||
AddChildOperation(_deserializeManifestOp);
|
||||
}
|
||||
|
||||
_deserializeManifestOp.UpdateOperation();
|
||||
Progress = _deserializeManifestOp.Progress;
|
||||
if (_deserializeManifestOp.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_deserializeManifestOp.Status == EOperationStatus.Succeeded)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Manifest = _deserializeManifestOp.Manifest;
|
||||
SetResult();
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError(_deserializeManifestOp.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
protected override void InternalDispose()
|
||||
{
|
||||
if (_downloadBytesRequest != null)
|
||||
{
|
||||
_downloadBytesRequest.Dispose();
|
||||
_downloadBytesRequest = null;
|
||||
}
|
||||
}
|
||||
protected override string InternalGetDescription()
|
||||
{
|
||||
return $"PackageVersion: {_packageVersion} PackageHash: {_packageHash}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8af9b72837c6a01428ee627011f4341b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,118 @@
|
||||
using System.IO;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 请求内置包裹哈希操作
|
||||
/// </summary>
|
||||
internal sealed class RequestBuiltinPackageHashOperation : AsyncOperationBase
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
TryLoadPackageHash,
|
||||
RequestPackageHash,
|
||||
CheckResult,
|
||||
Done,
|
||||
}
|
||||
|
||||
private readonly BuiltinFileSystem _fileSystem;
|
||||
private readonly string _packageVersion;
|
||||
private IDownloadTextRequest _downloadTextRequest;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
/// <summary>
|
||||
/// 包裹哈希值
|
||||
/// </summary>
|
||||
public string PackageHash { get; private set; }
|
||||
|
||||
|
||||
internal RequestBuiltinPackageHashOperation(BuiltinFileSystem fileSystem, string packageVersion)
|
||||
{
|
||||
_fileSystem = fileSystem;
|
||||
_packageVersion = packageVersion;
|
||||
}
|
||||
protected override void InternalStart()
|
||||
{
|
||||
_steps = ESteps.TryLoadPackageHash;
|
||||
}
|
||||
protected override void InternalUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
if (_steps == ESteps.TryLoadPackageHash)
|
||||
{
|
||||
string filePath = _fileSystem.GetBuiltinPackageHashFilePath(_packageVersion);
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
try
|
||||
{
|
||||
PackageHash = File.ReadAllText(filePath);
|
||||
_steps = ESteps.CheckResult;
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError($"Failed to read builtin package hash file: {ex.Message}.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.RequestPackageHash;
|
||||
}
|
||||
}
|
||||
|
||||
if (_steps == ESteps.RequestPackageHash)
|
||||
{
|
||||
if (_downloadTextRequest == null)
|
||||
{
|
||||
string filePath = _fileSystem.GetBuiltinPackageHashFilePath(_packageVersion);
|
||||
string url = DownloadUrlHelper.ToLocalFileUrl(filePath);
|
||||
var args = new DownloadDataRequestArgs(
|
||||
url: url,
|
||||
timeout: 60,
|
||||
watchdogTimeout: 0);
|
||||
_downloadTextRequest = _fileSystem.DownloadBackend.CreateTextRequest(args);
|
||||
_downloadTextRequest.SendRequest();
|
||||
}
|
||||
|
||||
if (_downloadTextRequest.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_downloadTextRequest.Status == EDownloadRequestStatus.Succeeded)
|
||||
{
|
||||
PackageHash = _downloadTextRequest.Result;
|
||||
_steps = ESteps.CheckResult;
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError(_downloadTextRequest.Error);
|
||||
}
|
||||
}
|
||||
|
||||
if (_steps == ESteps.CheckResult)
|
||||
{
|
||||
if (TextUtility.ValidateContent(PackageHash, out string validateError) == false)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError($"Builtin package hash file validation failed: {validateError}.");
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetResult();
|
||||
}
|
||||
}
|
||||
}
|
||||
protected override void InternalDispose()
|
||||
{
|
||||
if (_downloadTextRequest != null)
|
||||
{
|
||||
_downloadTextRequest.Dispose();
|
||||
_downloadTextRequest = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b2084625d8253164aa71ef934e0690fd
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,116 @@
|
||||
using System.IO;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 请求内置包裹版本操作
|
||||
/// </summary>
|
||||
internal sealed class RequestBuiltinPackageVersionOperation : AsyncOperationBase
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
TryLoadPackageVersion,
|
||||
RequestPackageVersion,
|
||||
CheckResult,
|
||||
Done,
|
||||
}
|
||||
|
||||
private readonly BuiltinFileSystem _fileSystem;
|
||||
private IDownloadTextRequest _downloadTextRequest;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
/// <summary>
|
||||
/// 包裹版本
|
||||
/// </summary>
|
||||
public string PackageVersion { get; private set; }
|
||||
|
||||
|
||||
internal RequestBuiltinPackageVersionOperation(BuiltinFileSystem fileSystem)
|
||||
{
|
||||
_fileSystem = fileSystem;
|
||||
}
|
||||
protected override void InternalStart()
|
||||
{
|
||||
_steps = ESteps.TryLoadPackageVersion;
|
||||
}
|
||||
protected override void InternalUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
if (_steps == ESteps.TryLoadPackageVersion)
|
||||
{
|
||||
string filePath = _fileSystem.GetBuiltinPackageVersionFilePath();
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
try
|
||||
{
|
||||
PackageVersion = File.ReadAllText(filePath);
|
||||
_steps = ESteps.CheckResult;
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError($"Failed to read builtin package version file: {ex.Message}.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.RequestPackageVersion;
|
||||
}
|
||||
}
|
||||
|
||||
if (_steps == ESteps.RequestPackageVersion)
|
||||
{
|
||||
if (_downloadTextRequest == null)
|
||||
{
|
||||
string filePath = _fileSystem.GetBuiltinPackageVersionFilePath();
|
||||
string url = DownloadUrlHelper.ToLocalFileUrl(filePath);
|
||||
var args = new DownloadDataRequestArgs(
|
||||
url: url,
|
||||
timeout: 60,
|
||||
watchdogTimeout: 0);
|
||||
_downloadTextRequest = _fileSystem.DownloadBackend.CreateTextRequest(args);
|
||||
_downloadTextRequest.SendRequest();
|
||||
}
|
||||
|
||||
if (_downloadTextRequest.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_downloadTextRequest.Status == EDownloadRequestStatus.Succeeded)
|
||||
{
|
||||
PackageVersion = _downloadTextRequest.Result;
|
||||
_steps = ESteps.CheckResult;
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError(_downloadTextRequest.Error);
|
||||
}
|
||||
}
|
||||
|
||||
if (_steps == ESteps.CheckResult)
|
||||
{
|
||||
if (TextUtility.ValidateContent(PackageVersion, out string validateError) == false)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError($"Builtin package version file validation failed: {validateError}.");
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetResult();
|
||||
}
|
||||
}
|
||||
}
|
||||
protected override void InternalDispose()
|
||||
{
|
||||
if (_downloadTextRequest != null)
|
||||
{
|
||||
_downloadTextRequest.Dispose();
|
||||
_downloadTextRequest = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6bddb076e377b66488ec28c9dbdd18cd
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,126 @@
|
||||
using System.IO;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 解压并缓存文件操作
|
||||
/// </summary>
|
||||
internal sealed class UnpackAndCacheFileOperation : DownloadFileBaseOperation
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
CheckCopy,
|
||||
CopyLocalFile,
|
||||
CacheFile,
|
||||
Done,
|
||||
}
|
||||
|
||||
private readonly BuiltinFileSystem _fileSystem;
|
||||
private readonly string _builtinFilePath;
|
||||
private readonly string _tempFilePath;
|
||||
private CopyBuiltinFileOperation _copyBuiltinFileOp;
|
||||
private BCWriteCacheOperation _writeCacheOp;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
internal UnpackAndCacheFileOperation(BuiltinFileSystem fileSystem, PackageBundle bundle, string builtinFilePath) : base(bundle, builtinFilePath)
|
||||
{
|
||||
_fileSystem = fileSystem;
|
||||
_builtinFilePath = builtinFilePath;
|
||||
_tempFilePath = _fileSystem.GetUnpackTempFilePath(bundle);
|
||||
}
|
||||
protected override void InternalStart()
|
||||
{
|
||||
_steps = ESteps.CheckCopy;
|
||||
}
|
||||
protected override void InternalUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
// 检测文件拷贝
|
||||
if (_steps == ESteps.CheckCopy)
|
||||
{
|
||||
// 删除历史缓存文件
|
||||
FileUtility.EnsureParentDirectoryExists(_tempFilePath);
|
||||
if (File.Exists(_tempFilePath))
|
||||
File.Delete(_tempFilePath);
|
||||
|
||||
_steps = ESteps.CopyLocalFile;
|
||||
}
|
||||
|
||||
// 拷贝本地文件
|
||||
if (_steps == ESteps.CopyLocalFile)
|
||||
{
|
||||
if (_copyBuiltinFileOp == null)
|
||||
{
|
||||
_copyBuiltinFileOp = new CopyBuiltinFileOperation(_fileSystem, _builtinFilePath, _tempFilePath);
|
||||
_copyBuiltinFileOp.StartOperation();
|
||||
AddChildOperation(_copyBuiltinFileOp);
|
||||
}
|
||||
|
||||
if (IsWaitForCompletion)
|
||||
_copyBuiltinFileOp.WaitForCompletion();
|
||||
|
||||
_copyBuiltinFileOp.UpdateOperation();
|
||||
if (_copyBuiltinFileOp.IsDone == false)
|
||||
return;
|
||||
|
||||
// 更新下载报告
|
||||
LatestReport = DownloadReport.CreateProgress(Bundle.FileSize, 1f);
|
||||
|
||||
if (_copyBuiltinFileOp.Status == EOperationStatus.Succeeded)
|
||||
{
|
||||
_steps = ESteps.CacheFile;
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError(_copyBuiltinFileOp.Error);
|
||||
|
||||
// 注意:拷贝失败后直接删除临时文件
|
||||
if (File.Exists(_tempFilePath))
|
||||
File.Delete(_tempFilePath);
|
||||
}
|
||||
}
|
||||
|
||||
// 缓存文件
|
||||
if (_steps == ESteps.CacheFile)
|
||||
{
|
||||
if (_writeCacheOp == null)
|
||||
{
|
||||
var options = new BCWriteCacheOptions(Bundle, _tempFilePath);
|
||||
_writeCacheOp = _fileSystem.UnpackBundleCache.WriteCacheAsync(options);
|
||||
_writeCacheOp.StartOperation();
|
||||
AddChildOperation(_writeCacheOp);
|
||||
}
|
||||
|
||||
if (IsWaitForCompletion)
|
||||
_writeCacheOp.WaitForCompletion();
|
||||
|
||||
_writeCacheOp.UpdateOperation();
|
||||
if (_writeCacheOp.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_writeCacheOp.Status == EOperationStatus.Succeeded)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetResult();
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError(_writeCacheOp.Error);
|
||||
}
|
||||
|
||||
// 注意:缓存完成后直接删除临时文件
|
||||
if (File.Exists(_tempFilePath))
|
||||
File.Delete(_tempFilePath);
|
||||
}
|
||||
}
|
||||
protected override void InternalWaitForCompletion()
|
||||
{
|
||||
ExecuteBatch();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: daa3aa418d6979b469437c30b7bbc05d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ca2dc2186da7a2847b300c398600e472
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,304 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 模拟文件系统,管理编辑器模式下的模拟文件系统。
|
||||
/// </summary>
|
||||
internal class EditorFileSystem : IFileSystem
|
||||
{
|
||||
/// <summary>
|
||||
/// 包裹根目录路径
|
||||
/// </summary>
|
||||
protected string _packageRoot;
|
||||
|
||||
/// <summary>
|
||||
/// 虚拟文件缓存系统
|
||||
/// </summary>
|
||||
public IBundleCache BundleCache { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 下载调度器
|
||||
/// </summary>
|
||||
public DownloadSchedulerOperation DownloadScheduler { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// 下载后台接口
|
||||
/// </summary>
|
||||
public IDownloadBackend DownloadBackend { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 包裹名称
|
||||
/// </summary>
|
||||
public string PackageName { get; private set; }
|
||||
|
||||
#region 自定义参数
|
||||
/// <summary>
|
||||
/// 自定义参数:UnityWebRequest 创建委托
|
||||
/// </summary>
|
||||
public UnityWebRequestCreator WebRequestCreator { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 自定义参数:模拟WebGL平台模式
|
||||
/// </summary>
|
||||
public bool VirtualWebGLMode { get; private set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 自定义参数:模拟虚拟下载模式
|
||||
/// </summary>
|
||||
public bool VirtualDownloadMode { get; private set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 自定义参数:模拟虚拟下载的网速(单位:字节)
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 默认值:1024
|
||||
/// </remarks>
|
||||
public int VirtualDownloadSpeed { get; private set; } = 1024;
|
||||
|
||||
/// <summary>
|
||||
/// 自定义参数:最大并发连接数
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 默认值:8(推荐范围 1-32)。过大的并发数可能被服务器限流,也会增加本地资源消耗。
|
||||
/// </remarks>
|
||||
public int DownloadMaxConcurrency { get; private set; } = 8;
|
||||
|
||||
/// <summary>
|
||||
/// 自定义参数:每帧发起的最大请求数
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 默认值:8(推荐范围 1-32)。避免单帧发起过多请求导致卡顿。
|
||||
/// </remarks>
|
||||
public int DownloadMaxRequestsPerFrame { get; private set; } = 8;
|
||||
|
||||
/// <summary>
|
||||
/// 自定义参数:异步模拟加载最小帧数
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 默认值:1
|
||||
/// </remarks>
|
||||
public int AsyncSimulateMinFrame { get; private set; } = 1;
|
||||
|
||||
/// <summary>
|
||||
/// 自定义参数:异步模拟加载最大帧数
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 默认值:1
|
||||
/// </remarks>
|
||||
public int AsyncSimulateMaxFrame { get; private set; } = 1;
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// 创建实例
|
||||
/// </summary>
|
||||
public EditorFileSystem()
|
||||
{
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public FSInitializeOperation InitializeAsync()
|
||||
{
|
||||
var operation = new EFSInitializeOperation(this);
|
||||
return operation;
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public FSRequestPackageVersionOperation RequestPackageVersionAsync(FSRequestPackageVersionOptions options)
|
||||
{
|
||||
var operation = new EFSRequestPackageVersionOperation(this);
|
||||
return operation;
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public FSLoadPackageManifestOperation LoadPackageManifestAsync(FSLoadPackageManifestOptions options)
|
||||
{
|
||||
var operation = new EFSLoadPackageManifestOperation(this, options.PackageVersion);
|
||||
return operation;
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public FSLoadPackageBundleOperation LoadPackageBundleAsync(FSLoadPackageBundleOptions options)
|
||||
{
|
||||
var operation = new EFSLoadPackageBundleOperation(this, options);
|
||||
return operation;
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public FSDownloadBundleOperation DownloadBundleAsync(FSDownloadBundleOptions options)
|
||||
{
|
||||
var downloader = new EFSDownloadBundleOperation(this, options);
|
||||
return downloader;
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public FSClearCacheOperation ClearCacheAsync(FSClearCacheOptions options)
|
||||
{
|
||||
if (options.ClearMethod == ClearCacheMethods.ClearAllManifestFiles)
|
||||
{
|
||||
var operation = new FSClearCacheCompleteOperation();
|
||||
return operation;
|
||||
}
|
||||
else if (options.ClearMethod == ClearCacheMethods.ClearUnusedManifestFiles)
|
||||
{
|
||||
var operation = new FSClearCacheCompleteOperation();
|
||||
return operation;
|
||||
}
|
||||
else
|
||||
{
|
||||
var operation = new EFSClearCacheOperation(this, options);
|
||||
return operation;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void SetParameter(string paramName, object value)
|
||||
{
|
||||
if (paramName == nameof(EFileSystemParameter.DownloadBackend))
|
||||
{
|
||||
DownloadBackend = FileSystemHelper.CastParameter<IDownloadBackend>(paramName, value);
|
||||
}
|
||||
else if (paramName == nameof(EFileSystemParameter.UnityWebRequestCreator))
|
||||
{
|
||||
WebRequestCreator = FileSystemHelper.CastParameter<UnityWebRequestCreator>(paramName, value);
|
||||
}
|
||||
else if (paramName == nameof(EFileSystemParameter.VirtualWebglMode))
|
||||
{
|
||||
VirtualWebGLMode = FileSystemHelper.CastParameter<bool>(paramName, value);
|
||||
}
|
||||
else if (paramName == nameof(EFileSystemParameter.VirtualDownloadMode))
|
||||
{
|
||||
VirtualDownloadMode = FileSystemHelper.CastParameter<bool>(paramName, value);
|
||||
}
|
||||
else if (paramName == nameof(EFileSystemParameter.VirtualDownloadSpeed))
|
||||
{
|
||||
int convertValue = FileSystemHelper.CastParameter<int>(paramName, value);
|
||||
VirtualDownloadSpeed = Mathf.Clamp(convertValue, 1, int.MaxValue);
|
||||
}
|
||||
else if (paramName == nameof(EFileSystemParameter.DownloadMaxConcurrency))
|
||||
{
|
||||
int convertValue = FileSystemHelper.CastParameter<int>(paramName, value);
|
||||
if (convertValue > 32)
|
||||
{
|
||||
YooLogger.LogWarning($"DOWNLOAD_MAX_CONCURRENCY value {convertValue} is too large, clamped to 32. Recommended range: 1 - 32.");
|
||||
}
|
||||
|
||||
// 限制在合理范围内:1-32
|
||||
DownloadMaxConcurrency = Mathf.Clamp(convertValue, 1, 32);
|
||||
}
|
||||
else if (paramName == nameof(EFileSystemParameter.DownloadMaxRequestPerFrame))
|
||||
{
|
||||
int convertValue = FileSystemHelper.CastParameter<int>(paramName, value);
|
||||
if (convertValue > 32)
|
||||
{
|
||||
YooLogger.LogWarning($"DOWNLOAD_MAX_REQUEST_PER_FRAME value {convertValue} is too large, clamped to 32. Recommended range: 1 - 32.");
|
||||
}
|
||||
|
||||
// 限制在合理范围内:1-32
|
||||
DownloadMaxRequestsPerFrame = Mathf.Clamp(convertValue, 1, 32);
|
||||
}
|
||||
else if (paramName == nameof(EFileSystemParameter.AsyncSimulateMinFrame))
|
||||
{
|
||||
AsyncSimulateMinFrame = FileSystemHelper.CastParameter<int>(paramName, value);
|
||||
}
|
||||
else if (paramName == nameof(EFileSystemParameter.AsyncSimulateMaxFrame))
|
||||
{
|
||||
AsyncSimulateMaxFrame = FileSystemHelper.CastParameter<int>(paramName, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException($"Unrecognized parameter name: '{paramName}'.", nameof(paramName));
|
||||
}
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public void OnCreate(string packageName, string packageRoot)
|
||||
{
|
||||
PackageName = packageName;
|
||||
|
||||
if (string.IsNullOrEmpty(packageRoot))
|
||||
throw new System.ArgumentException($"{nameof(EditorFileSystem)} package root is null or empty.");
|
||||
|
||||
_packageRoot = packageRoot;
|
||||
|
||||
// 创建默认的下载后台接口
|
||||
if (DownloadBackend == null)
|
||||
DownloadBackend = new UnityWebRequestBackend(WebRequestCreator);
|
||||
|
||||
// 创建编辑器文件缓存系统
|
||||
if (AsyncSimulateMinFrame > AsyncSimulateMaxFrame)
|
||||
AsyncSimulateMinFrame = AsyncSimulateMaxFrame;
|
||||
var cacheConfig = new EditorBundleCache.Configuration(
|
||||
virtualDownloadMode: VirtualDownloadMode,
|
||||
virtualWebGLMode: VirtualWebGLMode,
|
||||
asyncSimulateMinFrame: AsyncSimulateMinFrame,
|
||||
asyncSimulateMaxFrame: AsyncSimulateMaxFrame);
|
||||
BundleCache = new EditorBundleCache(packageName, _packageRoot, cacheConfig);
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public void OnDestroy()
|
||||
{
|
||||
if (BundleCache != null)
|
||||
{
|
||||
BundleCache.Dispose();
|
||||
BundleCache = null;
|
||||
}
|
||||
|
||||
if (DownloadScheduler != null)
|
||||
{
|
||||
DownloadScheduler.AbortOperation();
|
||||
DownloadScheduler = null;
|
||||
}
|
||||
|
||||
if (DownloadBackend != null)
|
||||
{
|
||||
DownloadBackend.Dispose();
|
||||
DownloadBackend = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool CanAcceptBundle(PackageBundle bundle)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public bool IsDownloadRequired(PackageBundle bundle)
|
||||
{
|
||||
return BundleCache.IsCached(bundle.BundleGuid) == false;
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public bool IsUnpackRequired(PackageBundle bundle)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public bool IsImportRequired(PackageBundle bundle)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#region 内部方法
|
||||
/// <summary>
|
||||
/// 获取编辑器包裹版本文件路径
|
||||
/// </summary>
|
||||
public string GetEditorPackageVersionFilePath()
|
||||
{
|
||||
string fileName = YooAssetConfiguration.GetPackageVersionFileName(PackageName);
|
||||
return PathUtility.Combine(_packageRoot, fileName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取编辑器包裹哈希文件路径
|
||||
/// </summary>
|
||||
public string GetEditorPackageHashFilePath(string packageVersion)
|
||||
{
|
||||
string fileName = YooAssetConfiguration.GetPackageHashFileName(PackageName, packageVersion);
|
||||
return PathUtility.Combine(_packageRoot, fileName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取编辑器包裹清单文件路径
|
||||
/// </summary>
|
||||
public string GetEditorPackageManifestFilePath(string packageVersion)
|
||||
{
|
||||
string fileName = YooAssetConfiguration.GetManifestBinaryFileName(PackageName, packageVersion);
|
||||
return PathUtility.Combine(_packageRoot, fileName);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 53f40d241c7bcf340841a33459678568
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,21 @@
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 编辑器文件系统工具类
|
||||
/// </summary>
|
||||
internal static class EditorFileSystemHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取编辑器环境下资源包对应的源文件路径
|
||||
/// </summary>
|
||||
public static string GetEditorFilePath(PackageBundle bundle)
|
||||
{
|
||||
if (bundle.MainAssets.Count == 0)
|
||||
return string.Empty;
|
||||
|
||||
var packageAsset = bundle.MainAssets[0];
|
||||
return packageAsset.AssetPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3c1e490fd2f44974b92bb10d556b28d4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3779423aa03ffb6499efda626280c72a
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,74 @@
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 编辑器文件系统的清理缓存操作
|
||||
/// </summary>
|
||||
internal sealed class EFSClearCacheOperation : FSClearCacheOperation
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
CheckReadOnly,
|
||||
ClearCache,
|
||||
Done,
|
||||
}
|
||||
|
||||
private readonly EditorFileSystem _fileSystem;
|
||||
private readonly FSClearCacheOptions _options;
|
||||
private BCClearCacheOperation _clearCacheOp;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
internal EFSClearCacheOperation(EditorFileSystem fileSystem, FSClearCacheOptions options)
|
||||
{
|
||||
_fileSystem = fileSystem;
|
||||
_options = options;
|
||||
}
|
||||
protected override void InternalStart()
|
||||
{
|
||||
_steps = ESteps.CheckReadOnly;
|
||||
}
|
||||
protected override void InternalUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
if (_steps == ESteps.CheckReadOnly)
|
||||
{
|
||||
if (_fileSystem.BundleCache.IsReadOnly)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetResult();
|
||||
return;
|
||||
}
|
||||
|
||||
_steps = ESteps.ClearCache;
|
||||
}
|
||||
|
||||
if (_steps == ESteps.ClearCache)
|
||||
{
|
||||
if (_clearCacheOp == null)
|
||||
{
|
||||
_clearCacheOp = _fileSystem.BundleCache.ClearCacheAsync(_options.ConvertTo());
|
||||
_clearCacheOp.StartOperation();
|
||||
AddChildOperation(_clearCacheOp);
|
||||
}
|
||||
|
||||
_clearCacheOp.UpdateOperation();
|
||||
if (_clearCacheOp.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_clearCacheOp.Status == EOperationStatus.Succeeded)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetResult();
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError(_clearCacheOp.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7c7447804168ec04c8c4690db6074f2f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,123 @@
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 编辑器文件系统的下载文件操作
|
||||
/// </summary>
|
||||
internal sealed class EFSDownloadBundleOperation : FSDownloadBundleOperation
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
CheckExists,
|
||||
CreateDownload,
|
||||
CheckDownload,
|
||||
Done,
|
||||
}
|
||||
|
||||
private readonly EditorFileSystem _fileSystem;
|
||||
private readonly FSDownloadBundleOptions _options;
|
||||
private DownloadFileBaseOperation _downloadFileOp;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
internal EFSDownloadBundleOperation(EditorFileSystem fileSystem, FSDownloadBundleOptions options) : base(options.Bundle)
|
||||
{
|
||||
_fileSystem = fileSystem;
|
||||
_options = options;
|
||||
}
|
||||
protected override void InternalStart()
|
||||
{
|
||||
_steps = ESteps.CheckExists;
|
||||
}
|
||||
protected override void InternalUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
// 检测文件是否存在
|
||||
if (_steps == ESteps.CheckExists)
|
||||
{
|
||||
if (_fileSystem.BundleCache.IsCached(_options.Bundle.BundleGuid))
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetResult();
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.CreateDownload;
|
||||
}
|
||||
}
|
||||
|
||||
// 创建下载器
|
||||
if (_steps == ESteps.CreateDownload)
|
||||
{
|
||||
_downloadFileOp = _fileSystem.DownloadScheduler.TryGetDownloadOperation(Bundle);
|
||||
if (_downloadFileOp == null)
|
||||
{
|
||||
string editorFilePath = EditorFileSystemHelper.GetEditorFilePath(Bundle);
|
||||
if (string.IsNullOrEmpty(editorFilePath))
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError($"Editor file path is empty for bundle '{Bundle.BundleName}'.");
|
||||
return;
|
||||
}
|
||||
|
||||
_downloadFileOp = new SimulateAndCacheFileOperation(_fileSystem, Bundle, editorFilePath);
|
||||
_fileSystem.DownloadScheduler.RegisterDownloadOperation(_downloadFileOp);
|
||||
}
|
||||
|
||||
_steps = ESteps.CheckDownload;
|
||||
}
|
||||
|
||||
// 检测结果
|
||||
if (_steps == ESteps.CheckDownload)
|
||||
{
|
||||
if (IsWaitForCompletion)
|
||||
{
|
||||
if (_downloadFileOp is SimulateAndCacheFileOperation)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError($"Attempting to load bundle '{Bundle.BundleName}' from simulate: '{_downloadFileOp.Url}'.");
|
||||
return;
|
||||
}
|
||||
_downloadFileOp.WaitForCompletion();
|
||||
}
|
||||
|
||||
// 注意:不主动调用 _downloadFileOp.UpdateOperation()
|
||||
// 说明:下载任务由 DownloadSchedulerOperation 统一驱动,此处仅读取状态。
|
||||
// 说明:同步等待由 WaitForCompletion() 内部的 ExecuteBatch() 保证。
|
||||
Progress = _downloadFileOp.Progress;
|
||||
Report = _downloadFileOp.LatestReport;
|
||||
if (_downloadFileOp.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_downloadFileOp.Status == EOperationStatus.Succeeded)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetResult();
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError(_downloadFileOp.Error);
|
||||
YooLogger.LogError(Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
protected override void InternalWaitForCompletion()
|
||||
{
|
||||
ExecuteBatch();
|
||||
}
|
||||
protected override void InternalAbort()
|
||||
{
|
||||
// 注意:取消下载任务的时候引用计数减一
|
||||
if (_steps != ESteps.Done)
|
||||
{
|
||||
if (_downloadFileOp != null)
|
||||
{
|
||||
_downloadFileOp.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f043dc0e0f147334380cfd0720636544
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,90 @@
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 编辑器文件系统的初始化操作
|
||||
/// </summary>
|
||||
internal sealed class EFSInitializeOperation : FSInitializeOperation
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
CheckPlatform,
|
||||
InitializeBundleCache,
|
||||
CreateScheduler,
|
||||
Done,
|
||||
}
|
||||
|
||||
private readonly EditorFileSystem _fileSystem;
|
||||
private BCInitializeOperation _initializeBundleCacheOp;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
internal EFSInitializeOperation(EditorFileSystem fileSystem)
|
||||
{
|
||||
_fileSystem = fileSystem;
|
||||
}
|
||||
protected override void InternalStart()
|
||||
{
|
||||
_steps = ESteps.CheckPlatform;
|
||||
}
|
||||
protected override void InternalUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
if (_steps == ESteps.CheckPlatform)
|
||||
{
|
||||
#if !UNITY_EDITOR
|
||||
_steps = ESteps.Done;
|
||||
SetError($"{nameof(EditorFileSystem)} only supports the Unity Editor.");
|
||||
#else
|
||||
_steps = ESteps.InitializeBundleCache;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (_steps == ESteps.InitializeBundleCache)
|
||||
{
|
||||
if (_initializeBundleCacheOp == null)
|
||||
{
|
||||
_initializeBundleCacheOp = _fileSystem.BundleCache.InitializeAsync();
|
||||
_initializeBundleCacheOp.StartOperation();
|
||||
AddChildOperation(_initializeBundleCacheOp);
|
||||
}
|
||||
|
||||
_initializeBundleCacheOp.UpdateOperation();
|
||||
Progress = _initializeBundleCacheOp.Progress;
|
||||
if (_initializeBundleCacheOp.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_initializeBundleCacheOp.Status == EOperationStatus.Succeeded)
|
||||
{
|
||||
_steps = ESteps.CreateScheduler;
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError(_initializeBundleCacheOp.Error);
|
||||
}
|
||||
}
|
||||
|
||||
if (_steps == ESteps.CreateScheduler)
|
||||
{
|
||||
// 注意: 下载调度中心在最后一步创建,防止初始化失败后残留任务。
|
||||
// 注意: 下载调度中心作为独立任务运行!
|
||||
if (_fileSystem.DownloadScheduler == null)
|
||||
{
|
||||
var schedulerConfig = new DownloadSchedulerOperation.Configuration(
|
||||
schedulerName: _fileSystem.GetType().Name,
|
||||
downloadBackend: _fileSystem.DownloadBackend,
|
||||
maxConcurrency: _fileSystem.DownloadMaxConcurrency,
|
||||
maxRequestsPerFrame: _fileSystem.DownloadMaxRequestsPerFrame);
|
||||
_fileSystem.DownloadScheduler = new DownloadSchedulerOperation(schedulerConfig);
|
||||
AsyncOperationSystem.StartOperation(_fileSystem.PackageName, _fileSystem.DownloadScheduler);
|
||||
}
|
||||
|
||||
_steps = ESteps.Done;
|
||||
SetResult();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 99cfeba8095613442992a0e21a248b73
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,149 @@
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 编辑器文件系统的加载资源包操作
|
||||
/// </summary>
|
||||
internal sealed class EFSLoadPackageBundleOperation : FSLoadPackageBundleOperation
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
Prepare,
|
||||
DownloadFile,
|
||||
AbortDownload,
|
||||
LoadBundle,
|
||||
CheckResult,
|
||||
Done,
|
||||
}
|
||||
|
||||
private readonly EditorFileSystem _fileSystem;
|
||||
private readonly FSLoadPackageBundleOptions _options;
|
||||
private FSDownloadBundleOperation _downloadFileOp;
|
||||
private BCLoadBundleOperation _loadBundleOp;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
internal EFSLoadPackageBundleOperation(EditorFileSystem fileSystem, FSLoadPackageBundleOptions options)
|
||||
{
|
||||
_fileSystem = fileSystem;
|
||||
_options = options;
|
||||
}
|
||||
protected override void InternalStart()
|
||||
{
|
||||
_steps = ESteps.Prepare;
|
||||
}
|
||||
protected override void InternalUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
if (_steps == ESteps.Prepare)
|
||||
{
|
||||
if (_fileSystem.BundleCache.IsCached(_options.Bundle.BundleGuid))
|
||||
_steps = ESteps.LoadBundle;
|
||||
else
|
||||
_steps = ESteps.DownloadFile;
|
||||
}
|
||||
|
||||
if (_steps == ESteps.DownloadFile)
|
||||
{
|
||||
// 中断下载
|
||||
if (ShouldAbortDownload)
|
||||
{
|
||||
if (_downloadFileOp != null)
|
||||
_downloadFileOp.AbortOperation();
|
||||
_steps = ESteps.AbortDownload;
|
||||
}
|
||||
}
|
||||
|
||||
if (_steps == ESteps.DownloadFile)
|
||||
{
|
||||
if (_downloadFileOp == null)
|
||||
{
|
||||
// 注意:模拟文件下载不做失败尝试
|
||||
var options = new FSDownloadBundleOptions(_options.Bundle, 0);
|
||||
_downloadFileOp = _fileSystem.DownloadBundleAsync(options);
|
||||
_downloadFileOp.StartOperation();
|
||||
AddChildOperation(_downloadFileOp);
|
||||
}
|
||||
|
||||
if (IsWaitForCompletion)
|
||||
_downloadFileOp.WaitForCompletion();
|
||||
|
||||
_downloadFileOp.UpdateOperation();
|
||||
if (_downloadFileOp.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_downloadFileOp.Status == EOperationStatus.Succeeded)
|
||||
{
|
||||
_steps = ESteps.LoadBundle;
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError(_downloadFileOp.Error);
|
||||
}
|
||||
}
|
||||
|
||||
if (_steps == ESteps.AbortDownload)
|
||||
{
|
||||
if (_downloadFileOp != null)
|
||||
{
|
||||
if (IsWaitForCompletion)
|
||||
_downloadFileOp.WaitForCompletion();
|
||||
|
||||
_downloadFileOp.UpdateOperation();
|
||||
if (_downloadFileOp.IsDone == false)
|
||||
return;
|
||||
}
|
||||
|
||||
_steps = ESteps.Done;
|
||||
SetError("Bundle download aborted.");
|
||||
}
|
||||
|
||||
if (_steps == ESteps.LoadBundle)
|
||||
{
|
||||
_loadBundleOp = _fileSystem.BundleCache.LoadBundleAsync(_options.ConvertTo());
|
||||
_loadBundleOp.StartOperation();
|
||||
AddChildOperation(_loadBundleOp);
|
||||
_steps = ESteps.CheckResult;
|
||||
}
|
||||
|
||||
if (_steps == ESteps.CheckResult)
|
||||
{
|
||||
if (IsWaitForCompletion)
|
||||
_loadBundleOp.WaitForCompletion();
|
||||
|
||||
_loadBundleOp.UpdateOperation();
|
||||
if (_loadBundleOp.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_loadBundleOp.Status == EOperationStatus.Succeeded)
|
||||
{
|
||||
if (_loadBundleOp.BundleHandle == null)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError("Fatal error: loaded bundle handle is null.");
|
||||
YooLogger.LogError(Error);
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetResult();
|
||||
BundleHandle = _loadBundleOp.BundleHandle;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError(_loadBundleOp.Error);
|
||||
YooLogger.LogError(Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
protected override void InternalWaitForCompletion()
|
||||
{
|
||||
ExecuteBatch();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 47b871368218c7c49920927c10c6955e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,91 @@
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 编辑器文件系统的加载包裹清单操作
|
||||
/// </summary>
|
||||
internal sealed class EFSLoadPackageManifestOperation : FSLoadPackageManifestOperation
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
LoadPackageHash,
|
||||
LoadPackageManifest,
|
||||
Done,
|
||||
}
|
||||
|
||||
private readonly EditorFileSystem _fileSystem;
|
||||
private readonly string _packageVersion;
|
||||
private LoadEditorPackageHashOperation _loadEditorPackageHashOp;
|
||||
private LoadEditorPackageManifestOperation _loadEditorPackageManifestOp;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
|
||||
internal EFSLoadPackageManifestOperation(EditorFileSystem fileSystem, string packageVersion)
|
||||
{
|
||||
_fileSystem = fileSystem;
|
||||
_packageVersion = packageVersion;
|
||||
}
|
||||
protected override void InternalStart()
|
||||
{
|
||||
_steps = ESteps.LoadPackageHash;
|
||||
}
|
||||
protected override void InternalUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
if (_steps == ESteps.LoadPackageHash)
|
||||
{
|
||||
if (_loadEditorPackageHashOp == null)
|
||||
{
|
||||
_loadEditorPackageHashOp = new LoadEditorPackageHashOperation(_fileSystem, _packageVersion);
|
||||
_loadEditorPackageHashOp.StartOperation();
|
||||
AddChildOperation(_loadEditorPackageHashOp);
|
||||
}
|
||||
|
||||
_loadEditorPackageHashOp.UpdateOperation();
|
||||
if (_loadEditorPackageHashOp.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_loadEditorPackageHashOp.Status == EOperationStatus.Succeeded)
|
||||
{
|
||||
_steps = ESteps.LoadPackageManifest;
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError(_loadEditorPackageHashOp.Error);
|
||||
}
|
||||
}
|
||||
|
||||
if (_steps == ESteps.LoadPackageManifest)
|
||||
{
|
||||
if (_loadEditorPackageManifestOp == null)
|
||||
{
|
||||
string packageHash = _loadEditorPackageHashOp.PackageHash;
|
||||
_loadEditorPackageManifestOp = new LoadEditorPackageManifestOperation(_fileSystem, _packageVersion, packageHash);
|
||||
_loadEditorPackageManifestOp.StartOperation();
|
||||
AddChildOperation(_loadEditorPackageManifestOp);
|
||||
}
|
||||
|
||||
_loadEditorPackageManifestOp.UpdateOperation();
|
||||
Progress = _loadEditorPackageManifestOp.Progress;
|
||||
if (_loadEditorPackageManifestOp.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_loadEditorPackageManifestOp.Status == EOperationStatus.Succeeded)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetResult();
|
||||
Manifest = _loadEditorPackageManifestOp.Manifest;
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError(_loadEditorPackageManifestOp.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f3abaff43b56f62489688162296203cd
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,61 @@
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 编辑器文件系统的查询包裹版本操作
|
||||
/// </summary>
|
||||
internal sealed class EFSRequestPackageVersionOperation : FSRequestPackageVersionOperation
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
LoadPackageVersion,
|
||||
Done,
|
||||
}
|
||||
|
||||
private readonly EditorFileSystem _fileSystem;
|
||||
private LoadEditorPackageVersionOperation _loadEditorPackageVersionOp;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
|
||||
internal EFSRequestPackageVersionOperation(EditorFileSystem fileSystem)
|
||||
{
|
||||
_fileSystem = fileSystem;
|
||||
}
|
||||
protected override void InternalStart()
|
||||
{
|
||||
_steps = ESteps.LoadPackageVersion;
|
||||
}
|
||||
protected override void InternalUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
if (_steps == ESteps.LoadPackageVersion)
|
||||
{
|
||||
if (_loadEditorPackageVersionOp == null)
|
||||
{
|
||||
_loadEditorPackageVersionOp = new LoadEditorPackageVersionOperation(_fileSystem);
|
||||
_loadEditorPackageVersionOp.StartOperation();
|
||||
AddChildOperation(_loadEditorPackageVersionOp);
|
||||
}
|
||||
|
||||
_loadEditorPackageVersionOp.UpdateOperation();
|
||||
if (_loadEditorPackageVersionOp.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_loadEditorPackageVersionOp.Status == EOperationStatus.Succeeded)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
PackageVersion = _loadEditorPackageVersionOp.PackageVersion;
|
||||
SetResult();
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError(_loadEditorPackageVersionOp.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 47293048f9cde3f46a1b297f1c2e3373
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cf9de625784f5fe41a8d4fc53bf71ff0
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,66 @@
|
||||
using System.IO;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 加载编辑器包裹哈希文件操作
|
||||
/// </summary>
|
||||
internal sealed class LoadEditorPackageHashOperation : AsyncOperationBase
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
LoadHash,
|
||||
Done,
|
||||
}
|
||||
|
||||
private readonly EditorFileSystem _fileSystem;
|
||||
private readonly string _packageVersion;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
/// <summary>
|
||||
/// 包裹哈希值
|
||||
/// </summary>
|
||||
public string PackageHash { get; private set; }
|
||||
|
||||
|
||||
internal LoadEditorPackageHashOperation(EditorFileSystem fileSystem, string packageVersion)
|
||||
{
|
||||
_fileSystem = fileSystem;
|
||||
_packageVersion = packageVersion;
|
||||
}
|
||||
protected override void InternalStart()
|
||||
{
|
||||
_steps = ESteps.LoadHash;
|
||||
}
|
||||
protected override void InternalUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
if (_steps == ESteps.LoadHash)
|
||||
{
|
||||
string hashFilePath = _fileSystem.GetEditorPackageHashFilePath(_packageVersion);
|
||||
if (File.Exists(hashFilePath))
|
||||
{
|
||||
PackageHash = FileUtility.ReadAllText(hashFilePath);
|
||||
if (TextUtility.ValidateContent(PackageHash, out string validateError) == false)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError($"Simulation package hash file validation failed: {validateError}.");
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetResult();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError($"Could not find simulation package hash file: '{hashFilePath}'.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 137c898b6a637c74d8d5e281e6124a72
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,115 @@
|
||||
using System.IO;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 加载编辑器包裹清单文件操作
|
||||
/// </summary>
|
||||
internal sealed class LoadEditorPackageManifestOperation : AsyncOperationBase
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
LoadFileData,
|
||||
VerifyFileData,
|
||||
LoadManifest,
|
||||
Done,
|
||||
}
|
||||
|
||||
private readonly EditorFileSystem _fileSystem;
|
||||
private readonly string _packageVersion;
|
||||
private readonly string _packageHash;
|
||||
private DeserializeManifestOperation _deserializeManifestOp;
|
||||
private byte[] _fileData;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
/// <summary>
|
||||
/// 包裹清单
|
||||
/// </summary>
|
||||
public PackageManifest Manifest { get; private set; }
|
||||
|
||||
|
||||
internal LoadEditorPackageManifestOperation(EditorFileSystem fileSystem, string packageVersion, string packageHash)
|
||||
{
|
||||
_fileSystem = fileSystem;
|
||||
_packageVersion = packageVersion;
|
||||
_packageHash = packageHash;
|
||||
}
|
||||
protected override void InternalStart()
|
||||
{
|
||||
_steps = ESteps.LoadFileData;
|
||||
}
|
||||
protected override void InternalUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
if (_steps == ESteps.LoadFileData)
|
||||
{
|
||||
string manifestFilePath = _fileSystem.GetEditorPackageManifestFilePath(_packageVersion);
|
||||
if (File.Exists(manifestFilePath))
|
||||
{
|
||||
try
|
||||
{
|
||||
_fileData = FileUtility.ReadAllBytes(manifestFilePath);
|
||||
_steps = ESteps.VerifyFileData;
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError($"Failed to read editor package manifest file: {ex.Message}.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError($"Could not find simulation package manifest file: '{manifestFilePath}'.");
|
||||
}
|
||||
}
|
||||
|
||||
if (_steps == ESteps.VerifyFileData)
|
||||
{
|
||||
if (PackageManifestHelper.VerifyManifestData(_fileData, _packageHash))
|
||||
{
|
||||
_steps = ESteps.LoadManifest;
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError("Failed to verify simulation package manifest file.");
|
||||
}
|
||||
}
|
||||
|
||||
if (_steps == ESteps.LoadManifest)
|
||||
{
|
||||
if (_deserializeManifestOp == null)
|
||||
{
|
||||
_deserializeManifestOp = new DeserializeManifestOperation(null, _fileData);
|
||||
_deserializeManifestOp.StartOperation();
|
||||
AddChildOperation(_deserializeManifestOp);
|
||||
}
|
||||
|
||||
_deserializeManifestOp.UpdateOperation();
|
||||
Progress = _deserializeManifestOp.Progress;
|
||||
if (_deserializeManifestOp.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_deserializeManifestOp.Status == EOperationStatus.Succeeded)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Manifest = _deserializeManifestOp.Manifest;
|
||||
SetResult();
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError(_deserializeManifestOp.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
protected override string InternalGetDescription()
|
||||
{
|
||||
return $"PackageVersion: {_packageVersion} PackageHash: {_packageHash}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b6504949dca3fbf4fbb8c61c3ab9c51f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,64 @@
|
||||
using System.IO;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 加载编辑器包裹版本文件操作
|
||||
/// </summary>
|
||||
internal sealed class LoadEditorPackageVersionOperation : AsyncOperationBase
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
LoadVersion,
|
||||
Done,
|
||||
}
|
||||
|
||||
private readonly EditorFileSystem _fileSystem;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
/// <summary>
|
||||
/// 包裹版本
|
||||
/// </summary>
|
||||
public string PackageVersion { get; private set; }
|
||||
|
||||
|
||||
internal LoadEditorPackageVersionOperation(EditorFileSystem fileSystem)
|
||||
{
|
||||
_fileSystem = fileSystem;
|
||||
}
|
||||
protected override void InternalStart()
|
||||
{
|
||||
_steps = ESteps.LoadVersion;
|
||||
}
|
||||
protected override void InternalUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
if (_steps == ESteps.LoadVersion)
|
||||
{
|
||||
string versionFilePath = _fileSystem.GetEditorPackageVersionFilePath();
|
||||
if (File.Exists(versionFilePath))
|
||||
{
|
||||
PackageVersion = FileUtility.ReadAllText(versionFilePath);
|
||||
if (TextUtility.ValidateContent(PackageVersion, out string validateError) == false)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError($"Simulation package version file validation failed: {validateError}.");
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetResult();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError($"Could not find simulation package version file: '{versionFilePath}'.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a4278d490ca87354ab63b0bece1fdab7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,113 @@
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 模拟下载并缓存文件操作
|
||||
/// </summary>
|
||||
internal sealed class SimulateAndCacheFileOperation : DownloadFileBaseOperation
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
CreateRequest,
|
||||
CheckRequest,
|
||||
CacheFile,
|
||||
Done,
|
||||
}
|
||||
|
||||
private readonly EditorFileSystem _fileSystem;
|
||||
private IDownloadRequest _downloadRequest;
|
||||
private BCWriteCacheOperation _writeCacheOp;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
internal SimulateAndCacheFileOperation(EditorFileSystem fileSystem, PackageBundle bundle, string filePath) : base(bundle, filePath)
|
||||
{
|
||||
_fileSystem = fileSystem;
|
||||
}
|
||||
protected override void InternalStart()
|
||||
{
|
||||
_steps = ESteps.CreateRequest;
|
||||
}
|
||||
protected override void InternalUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
// 创建下载请求
|
||||
if (_steps == ESteps.CreateRequest)
|
||||
{
|
||||
int speed = _fileSystem.VirtualDownloadSpeed;
|
||||
var args = new SimulatedDownloadRequestArgs(
|
||||
url: Url,
|
||||
fileSize: Bundle.FileSize,
|
||||
downloadSpeed: speed);
|
||||
_downloadRequest = _fileSystem.DownloadBackend.CreateSimulateRequest(args);
|
||||
_downloadRequest.SendRequest();
|
||||
_steps = ESteps.CheckRequest;
|
||||
}
|
||||
|
||||
// 检测下载结果
|
||||
if (_steps == ESteps.CheckRequest)
|
||||
{
|
||||
LatestReport = DownloadReport.CreateProgress(_downloadRequest.DownloadedBytes, _downloadRequest.DownloadProgress);
|
||||
Progress = _downloadRequest.DownloadProgress;
|
||||
if (_downloadRequest.IsDone == false)
|
||||
return;
|
||||
|
||||
// 更新下载报告
|
||||
LatestReport = DownloadReport.CreateFinished(_downloadRequest.HttpCode, _downloadRequest.HttpError,
|
||||
_downloadRequest.DownloadedBytes, _downloadRequest.DownloadProgress);
|
||||
|
||||
// 检查网络错误
|
||||
if (_downloadRequest.Status == EDownloadRequestStatus.Succeeded)
|
||||
{
|
||||
_steps = ESteps.CacheFile;
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError(_downloadRequest.Error);
|
||||
}
|
||||
}
|
||||
|
||||
// 缓存文件
|
||||
if (_steps == ESteps.CacheFile)
|
||||
{
|
||||
if (_writeCacheOp == null)
|
||||
{
|
||||
var options = new BCWriteCacheOptions(Bundle, Url);
|
||||
_writeCacheOp = _fileSystem.BundleCache.WriteCacheAsync(options);
|
||||
_writeCacheOp.StartOperation();
|
||||
AddChildOperation(_writeCacheOp);
|
||||
}
|
||||
|
||||
_writeCacheOp.UpdateOperation();
|
||||
if (_writeCacheOp.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_writeCacheOp.Status == EOperationStatus.Succeeded)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetResult();
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError(_writeCacheOp.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
protected override void InternalDispose()
|
||||
{
|
||||
if (_downloadRequest != null)
|
||||
{
|
||||
_downloadRequest.Dispose();
|
||||
_downloadRequest = null;
|
||||
}
|
||||
}
|
||||
protected override void InternalWaitForCompletion()
|
||||
{
|
||||
throw new YooInternalException($"{nameof(SimulateAndCacheFileOperation)} does not support synchronous waiting. Bundle: '{Bundle.BundleName}', Url: '{Url}'.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fcd5dd2d445745b4189568a255b85609
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b03f54c14ce3f6041870eaa9317d2e64
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,80 @@
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 应用程序水印
|
||||
/// </summary>
|
||||
internal class ApplicationFootprint
|
||||
{
|
||||
private readonly string _filePath;
|
||||
private string _footprint;
|
||||
|
||||
/// <summary>
|
||||
/// 创建实例
|
||||
/// </summary>
|
||||
/// <param name="filePath">足迹文件路径</param>
|
||||
public ApplicationFootprint(string filePath)
|
||||
{
|
||||
_filePath = filePath;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取应用程序水印
|
||||
/// </summary>
|
||||
public void Load(string packageName)
|
||||
{
|
||||
if (File.Exists(_filePath))
|
||||
{
|
||||
try
|
||||
{
|
||||
_footprint = FileUtility.ReadAllText(_filePath);
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
_footprint = string.Empty;
|
||||
YooLogger.LogError($"Failed to read application footprint file: {ex.Message}.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Overwrite(packageName);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检测水印是否发生变化
|
||||
/// </summary>
|
||||
public bool IsDirty()
|
||||
{
|
||||
return _footprint != GetApplicationIdentifier();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 覆盖掉水印
|
||||
/// </summary>
|
||||
public void Overwrite(string packageName)
|
||||
{
|
||||
_footprint = GetApplicationIdentifier();
|
||||
try
|
||||
{
|
||||
FileUtility.WriteAllText(_filePath, _footprint);
|
||||
YooLogger.Log($"Saved application footprint: '{_footprint}'.");
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
YooLogger.LogWarning($"Failed to save application footprint file: {ex.Message}.");
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetApplicationIdentifier()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
return Application.version;
|
||||
#else
|
||||
return Application.buildGUID;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c9d96ea955bc07149a08471e33915556
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,29 @@
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 覆盖安装清理模式
|
||||
/// </summary>
|
||||
public enum EInstallCleanupMode
|
||||
{
|
||||
/// <summary>
|
||||
/// 不做任何处理
|
||||
/// </summary>
|
||||
None = 0,
|
||||
|
||||
/// <summary>
|
||||
/// 清理所有缓存文件(包含资源文件和清单文件)
|
||||
/// </summary>
|
||||
ClearAllCacheFiles = 1,
|
||||
|
||||
/// <summary>
|
||||
/// 清理所有缓存的资源文件
|
||||
/// </summary>
|
||||
ClearAllBundleFiles = 2,
|
||||
|
||||
/// <summary>
|
||||
/// 清理所有缓存的清单文件
|
||||
/// </summary>
|
||||
ClearAllManifestFiles = 3,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c61fdc079dca97548a0158b8100ec258
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 09e4cebb2073ab945ac09e9099b327ad
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3414bfb159816a74f917270b7d48c25f
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,202 @@
|
||||
using System.IO;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 下载远端资源并缓存到本地的操作
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// TODO: 下载和缓存不能拆分,因为FSDownloadBundleOperation下载任务并不唯一,会造成写入缓存冲突。
|
||||
/// </remarks>
|
||||
internal sealed class DownloadAndCacheFileOperation : DownloadFileBaseOperation
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
CreateRequest,
|
||||
CheckRequest,
|
||||
CacheFile,
|
||||
Done,
|
||||
}
|
||||
|
||||
private readonly SandboxFileSystem _fileSystem;
|
||||
private readonly string _tempFilePath;
|
||||
private IDownloadFileRequest _downloadFileRequest;
|
||||
private BCWriteCacheOperation _writeCacheOp;
|
||||
private bool _enableResume;
|
||||
private long _fileOriginLength = 0;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
internal DownloadAndCacheFileOperation(SandboxFileSystem fileSystem, PackageBundle bundle, string url) : base(bundle, url)
|
||||
{
|
||||
_fileSystem = fileSystem;
|
||||
_tempFilePath = _fileSystem.GetTempFilePath(bundle);
|
||||
}
|
||||
protected override void InternalStart()
|
||||
{
|
||||
_steps = ESteps.CreateRequest;
|
||||
}
|
||||
protected override void InternalUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
// 创建下载请求
|
||||
if (_steps == ESteps.CreateRequest)
|
||||
{
|
||||
FileUtility.EnsureParentDirectoryExists(_tempFilePath);
|
||||
_enableResume = Bundle.FileSize >= _fileSystem.ResumeDownloadMinimumSize;
|
||||
if (_enableResume)
|
||||
{
|
||||
_downloadFileRequest = CreateResumeRequest();
|
||||
_downloadFileRequest.SendRequest();
|
||||
_steps = ESteps.CheckRequest;
|
||||
}
|
||||
else
|
||||
{
|
||||
_downloadFileRequest = CreateNormalRequest();
|
||||
_downloadFileRequest.SendRequest();
|
||||
_steps = ESteps.CheckRequest;
|
||||
}
|
||||
}
|
||||
|
||||
// 检测下载结果
|
||||
if (_steps == ESteps.CheckRequest)
|
||||
{
|
||||
bool isDone = _downloadFileRequest.IsDone;
|
||||
if (_enableResume)
|
||||
{
|
||||
long downloadedBytes = _fileOriginLength + _downloadFileRequest.DownloadedBytes;
|
||||
float downloadProgress = (float)((double)downloadedBytes / Bundle.FileSize);
|
||||
LatestReport = DownloadReport.CreateProgress(downloadedBytes, downloadProgress);
|
||||
Progress = downloadProgress;
|
||||
}
|
||||
else
|
||||
{
|
||||
LatestReport = DownloadReport.CreateProgress(_downloadFileRequest.DownloadedBytes, _downloadFileRequest.DownloadProgress);
|
||||
Progress = _downloadFileRequest.DownloadProgress;
|
||||
}
|
||||
if (isDone == false)
|
||||
return;
|
||||
|
||||
// 更新下载报告
|
||||
LatestReport = DownloadReport.CreateFinished(_downloadFileRequest.HttpCode, _downloadFileRequest.HttpError,
|
||||
LatestReport.DownloadedBytes, LatestReport.DownloadProgress);
|
||||
|
||||
// 检查网络错误
|
||||
if (_downloadFileRequest.Status == EDownloadRequestStatus.Succeeded)
|
||||
{
|
||||
_steps = ESteps.CacheFile;
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError(_downloadFileRequest.Error);
|
||||
|
||||
if (_enableResume)
|
||||
{
|
||||
// 注意: HTTP 416 Range Not Satisfiable 表示服务器无法满足客户端在 Range 请求头中指定的字节范围请求。
|
||||
if (_downloadFileRequest.HttpCode == 416)
|
||||
DeleteTempFile();
|
||||
}
|
||||
else
|
||||
{
|
||||
DeleteTempFile();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 缓存文件
|
||||
if (_steps == ESteps.CacheFile)
|
||||
{
|
||||
if (_writeCacheOp == null)
|
||||
{
|
||||
var options = new BCWriteCacheOptions(Bundle, _tempFilePath);
|
||||
_writeCacheOp = _fileSystem.BundleCache.WriteCacheAsync(options);
|
||||
_writeCacheOp.StartOperation();
|
||||
AddChildOperation(_writeCacheOp);
|
||||
}
|
||||
|
||||
_writeCacheOp.UpdateOperation();
|
||||
if (_writeCacheOp.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_writeCacheOp.Status == EOperationStatus.Succeeded)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetResult();
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError(_writeCacheOp.Error);
|
||||
}
|
||||
|
||||
// 注意:缓存完成后直接删除临时文件
|
||||
DeleteTempFile();
|
||||
}
|
||||
}
|
||||
protected override void InternalDispose()
|
||||
{
|
||||
if (_downloadFileRequest != null)
|
||||
{
|
||||
_downloadFileRequest.Dispose();
|
||||
_downloadFileRequest = null;
|
||||
}
|
||||
}
|
||||
protected override void InternalWaitForCompletion()
|
||||
{
|
||||
throw new YooInternalException($"{nameof(DownloadAndCacheFileOperation)} does not support synchronous waiting. Bundle: '{Bundle.BundleName}', Url: '{Url}'.");
|
||||
}
|
||||
|
||||
private IDownloadFileRequest CreateResumeRequest()
|
||||
{
|
||||
// 获取下载起始位置
|
||||
if (File.Exists(_tempFilePath))
|
||||
{
|
||||
FileInfo fileInfo = new FileInfo(_tempFilePath);
|
||||
if (fileInfo.Length >= Bundle.FileSize)
|
||||
{
|
||||
DeleteTempFile();
|
||||
}
|
||||
else
|
||||
{
|
||||
_fileOriginLength = fileInfo.Length;
|
||||
}
|
||||
}
|
||||
|
||||
int watchdogTime = _fileSystem.DownloadWatchdogTimeout;
|
||||
int timeout = 0; //注意:文件下载不做超时检测
|
||||
bool appendToFile = true;
|
||||
bool removeFileOnAbort = false;
|
||||
long resumeOffset = _fileOriginLength;
|
||||
var args = new DownloadFileRequestArgs(
|
||||
url: Url,
|
||||
timeout: timeout,
|
||||
watchdogTimeout: watchdogTime,
|
||||
savePath: _tempFilePath,
|
||||
appendToFile: appendToFile,
|
||||
removeFileOnAbort: removeFileOnAbort,
|
||||
resumeOffset: resumeOffset);
|
||||
return _fileSystem.DownloadBackend.CreateFileRequest(args);
|
||||
}
|
||||
private IDownloadFileRequest CreateNormalRequest()
|
||||
{
|
||||
DeleteTempFile();
|
||||
|
||||
int watchdogTime = _fileSystem.DownloadWatchdogTimeout;
|
||||
int timeout = 0; //注意:文件下载不做超时检测
|
||||
var args = new DownloadFileRequestArgs(
|
||||
url: Url,
|
||||
timeout: timeout,
|
||||
watchdogTimeout: watchdogTime,
|
||||
savePath: _tempFilePath);
|
||||
return _fileSystem.DownloadBackend.CreateFileRequest(args);
|
||||
}
|
||||
private void DeleteTempFile()
|
||||
{
|
||||
if (File.Exists(_tempFilePath))
|
||||
File.Delete(_tempFilePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ad910a81855976e44b4f1f09051910b0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,155 @@
|
||||
using System.IO;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 下载包裹哈希文件操作
|
||||
/// </summary>
|
||||
internal sealed class DownloadPackageHashOperation : AsyncOperationBase
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
CheckExists,
|
||||
DownloadFile,
|
||||
VerifyFile,
|
||||
Done,
|
||||
}
|
||||
|
||||
private readonly SandboxFileSystem _fileSystem;
|
||||
private readonly string _packageVersion;
|
||||
private readonly int _timeout;
|
||||
private IDownloadFileRequest _downloadFileRequest;
|
||||
private string _savePath;
|
||||
private string _tempPath;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
|
||||
internal DownloadPackageHashOperation(SandboxFileSystem fileSystem, string packageVersion, int timeout)
|
||||
{
|
||||
_fileSystem = fileSystem;
|
||||
_packageVersion = packageVersion;
|
||||
_timeout = timeout;
|
||||
}
|
||||
protected override void InternalStart()
|
||||
{
|
||||
_savePath = _fileSystem.GetCachePackageHashFilePath(_packageVersion);
|
||||
_tempPath = _savePath + ".tmp";
|
||||
_steps = ESteps.CheckExists;
|
||||
}
|
||||
protected override void InternalUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
if (_steps == ESteps.CheckExists)
|
||||
{
|
||||
if (File.Exists(_savePath))
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetResult();
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.DownloadFile;
|
||||
}
|
||||
}
|
||||
|
||||
if (_steps == ESteps.DownloadFile)
|
||||
{
|
||||
if (_downloadFileRequest == null)
|
||||
{
|
||||
FileUtility.EnsureParentDirectoryExists(_tempPath);
|
||||
|
||||
// 删除历史临时文件
|
||||
if (File.Exists(_tempPath))
|
||||
File.Delete(_tempPath);
|
||||
|
||||
string fileName = YooAssetConfiguration.GetPackageHashFileName(_fileSystem.PackageName, _packageVersion);
|
||||
string webURL = GetWebRequestUrl(fileName);
|
||||
int watchdogTime = _fileSystem.DownloadWatchdogTimeout;
|
||||
var args = new DownloadFileRequestArgs(
|
||||
url: webURL,
|
||||
timeout: _timeout,
|
||||
watchdogTimeout: watchdogTime,
|
||||
savePath: _tempPath);
|
||||
_downloadFileRequest = _fileSystem.DownloadBackend.CreateFileRequest(args);
|
||||
_downloadFileRequest.SendRequest();
|
||||
}
|
||||
|
||||
if (_downloadFileRequest.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_downloadFileRequest.Status == EDownloadRequestStatus.Succeeded)
|
||||
{
|
||||
_steps = ESteps.VerifyFile;
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError(_downloadFileRequest.Error);
|
||||
_fileSystem.DownloadUrlPolicy.OnRequestFailed(_downloadFileRequest.Url, _downloadFileRequest.HttpCode, _downloadFileRequest.HttpError);
|
||||
DeleteTempFile();
|
||||
}
|
||||
}
|
||||
|
||||
if (_steps == ESteps.VerifyFile)
|
||||
{
|
||||
// 验证临时文件存在且大小有效
|
||||
FileInfo fileInfo = new FileInfo(_tempPath);
|
||||
if (fileInfo.Exists == false || fileInfo.Length == 0)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError("Downloaded package hash temp file is invalid.");
|
||||
DeleteTempFile();
|
||||
return;
|
||||
}
|
||||
|
||||
// 严格校验临时文件内容
|
||||
string content = FileUtility.ReadAllText(_tempPath);
|
||||
if (TextUtility.ValidateContent(content, out string validateError) == false)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError($"Downloaded package hash file validation failed: {validateError}.");
|
||||
DeleteTempFile();
|
||||
return;
|
||||
}
|
||||
|
||||
// 原子移动到最终缓存路径
|
||||
try
|
||||
{
|
||||
if (File.Exists(_savePath))
|
||||
File.Delete(_savePath);
|
||||
File.Move(_tempPath, _savePath);
|
||||
_steps = ESteps.Done;
|
||||
SetResult();
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError($"Failed to move hash temp file to cache path: {ex.Message}.");
|
||||
DeleteTempFile();
|
||||
}
|
||||
}
|
||||
}
|
||||
protected override void InternalDispose()
|
||||
{
|
||||
if (_downloadFileRequest != null)
|
||||
{
|
||||
_downloadFileRequest.Dispose();
|
||||
_downloadFileRequest = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void DeleteTempFile()
|
||||
{
|
||||
if (File.Exists(_tempPath))
|
||||
File.Delete(_tempPath);
|
||||
}
|
||||
private string GetWebRequestUrl(string fileName)
|
||||
{
|
||||
var urls = _fileSystem.RemoteService.GetRemoteUrls(fileName);
|
||||
return _fileSystem.DownloadUrlPolicy.SelectUrl(urls);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8604af2bf2c8a1d4684cb59d81ab9445
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,152 @@
|
||||
using System.IO;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 下载包裹清单文件操作
|
||||
/// </summary>
|
||||
internal sealed class DownloadPackageManifestOperation : AsyncOperationBase
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
CheckExists,
|
||||
DownloadFile,
|
||||
VerifyFile,
|
||||
Done,
|
||||
}
|
||||
|
||||
private readonly SandboxFileSystem _fileSystem;
|
||||
private readonly string _packageVersion;
|
||||
private readonly int _timeout;
|
||||
private IDownloadFileRequest _downloadFileRequest;
|
||||
private string _savePath;
|
||||
private string _tempPath;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
|
||||
internal DownloadPackageManifestOperation(SandboxFileSystem fileSystem, string packageVersion, int timeout)
|
||||
{
|
||||
_fileSystem = fileSystem;
|
||||
_packageVersion = packageVersion;
|
||||
_timeout = timeout;
|
||||
}
|
||||
protected override void InternalStart()
|
||||
{
|
||||
_savePath = _fileSystem.GetCachePackageManifestFilePath(_packageVersion);
|
||||
_tempPath = _savePath + ".tmp";
|
||||
_steps = ESteps.CheckExists;
|
||||
}
|
||||
protected override void InternalUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
if (_steps == ESteps.CheckExists)
|
||||
{
|
||||
if (File.Exists(_savePath))
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetResult();
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.DownloadFile;
|
||||
}
|
||||
}
|
||||
|
||||
if (_steps == ESteps.DownloadFile)
|
||||
{
|
||||
if (_downloadFileRequest == null)
|
||||
{
|
||||
FileUtility.EnsureParentDirectoryExists(_tempPath);
|
||||
|
||||
// 删除历史临时文件
|
||||
if (File.Exists(_tempPath))
|
||||
File.Delete(_tempPath);
|
||||
|
||||
string fileName = YooAssetConfiguration.GetManifestBinaryFileName(_fileSystem.PackageName, _packageVersion);
|
||||
string webURL = GetDownloadRequestUrl(fileName);
|
||||
int watchdogTime = _fileSystem.DownloadWatchdogTimeout;
|
||||
var args = new DownloadFileRequestArgs(
|
||||
url: webURL,
|
||||
timeout: _timeout,
|
||||
watchdogTimeout: watchdogTime,
|
||||
savePath: _tempPath);
|
||||
_downloadFileRequest = _fileSystem.DownloadBackend.CreateFileRequest(args);
|
||||
_downloadFileRequest.SendRequest();
|
||||
}
|
||||
|
||||
if (_downloadFileRequest.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_downloadFileRequest.Status == EDownloadRequestStatus.Succeeded)
|
||||
{
|
||||
_steps = ESteps.VerifyFile;
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError(_downloadFileRequest.Error);
|
||||
_fileSystem.DownloadUrlPolicy.OnRequestFailed(_downloadFileRequest.Url, _downloadFileRequest.HttpCode, _downloadFileRequest.HttpError);
|
||||
DeleteTempFile();
|
||||
}
|
||||
}
|
||||
|
||||
if (_steps == ESteps.VerifyFile)
|
||||
{
|
||||
// 验证临时文件存在且大小有效
|
||||
FileInfo fileInfo = new FileInfo(_tempPath);
|
||||
if (fileInfo.Exists == false)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError("Downloaded package manifest temp file does not exist.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (fileInfo.Length < PackageManifestConsts.MinFileSize)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError($"Downloaded manifest file is too small ({fileInfo.Length} bytes), possibly corrupted.");
|
||||
DeleteTempFile();
|
||||
return;
|
||||
}
|
||||
|
||||
// 原子移动到最终缓存路径
|
||||
try
|
||||
{
|
||||
if (File.Exists(_savePath))
|
||||
File.Delete(_savePath);
|
||||
File.Move(_tempPath, _savePath);
|
||||
_steps = ESteps.Done;
|
||||
SetResult();
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError($"Failed to move manifest temp file to cache path: {ex.Message}.");
|
||||
DeleteTempFile();
|
||||
}
|
||||
}
|
||||
}
|
||||
protected override void InternalDispose()
|
||||
{
|
||||
if (_downloadFileRequest != null)
|
||||
{
|
||||
_downloadFileRequest.Dispose();
|
||||
_downloadFileRequest = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void DeleteTempFile()
|
||||
{
|
||||
if (File.Exists(_tempPath))
|
||||
File.Delete(_tempPath);
|
||||
}
|
||||
private string GetDownloadRequestUrl(string fileName)
|
||||
{
|
||||
var urls = _fileSystem.RemoteService.GetRemoteUrls(fileName);
|
||||
return _fileSystem.DownloadUrlPolicy.SelectUrl(urls);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9d5983f1b32b2e14c8b4c5b539bee8fa
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,124 @@
|
||||
using System.IO;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 导入并缓存文件操作
|
||||
/// </summary>
|
||||
internal sealed class ImportAndCacheFileOperation : DownloadFileBaseOperation
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
CheckTempFile,
|
||||
CopyLocalFile,
|
||||
CacheFile,
|
||||
Done,
|
||||
}
|
||||
|
||||
private readonly SandboxFileSystem _fileSystem;
|
||||
private readonly string _sourceFilePath;
|
||||
private readonly string _tempFilePath;
|
||||
private BCWriteCacheOperation _bundleCacheOp;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
internal ImportAndCacheFileOperation(SandboxFileSystem fileSystem, PackageBundle bundle, string sourceFilePath) : base(bundle, sourceFilePath)
|
||||
{
|
||||
_fileSystem = fileSystem;
|
||||
_sourceFilePath = sourceFilePath;
|
||||
_tempFilePath = _fileSystem.GetTempFilePath(bundle);
|
||||
}
|
||||
protected override void InternalStart()
|
||||
{
|
||||
_steps = ESteps.CheckTempFile;
|
||||
}
|
||||
protected override void InternalUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
// 检测临时文件
|
||||
if (_steps == ESteps.CheckTempFile)
|
||||
{
|
||||
// 删除历史临时文件
|
||||
FileUtility.EnsureParentDirectoryExists(_tempFilePath);
|
||||
if (File.Exists(_tempFilePath))
|
||||
File.Delete(_tempFilePath);
|
||||
|
||||
_steps = ESteps.CopyLocalFile;
|
||||
}
|
||||
|
||||
// 拷贝本地文件
|
||||
if (_steps == ESteps.CopyLocalFile)
|
||||
{
|
||||
try
|
||||
{
|
||||
File.Copy(_sourceFilePath, _tempFilePath, true);
|
||||
|
||||
// 更新下载报告
|
||||
LatestReport = DownloadReport.CreateProgress(Bundle.FileSize, 1f);
|
||||
_steps = ESteps.CacheFile;
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
LatestReport = DownloadReport.CreateFinished(-1, ex.Message, 0, 0f);
|
||||
SetError($"Failed to copy local file: {ex.Message}.");
|
||||
|
||||
// 注意:拷贝失败后直接删除临时文件
|
||||
DeleteTempFile();
|
||||
}
|
||||
}
|
||||
|
||||
// 缓存文件
|
||||
if (_steps == ESteps.CacheFile)
|
||||
{
|
||||
if (_bundleCacheOp == null)
|
||||
{
|
||||
var options = new BCWriteCacheOptions(Bundle, _tempFilePath);
|
||||
_bundleCacheOp = _fileSystem.BundleCache.WriteCacheAsync(options);
|
||||
_bundleCacheOp.StartOperation();
|
||||
AddChildOperation(_bundleCacheOp);
|
||||
}
|
||||
|
||||
if (IsWaitForCompletion)
|
||||
_bundleCacheOp.WaitForCompletion();
|
||||
|
||||
_bundleCacheOp.UpdateOperation();
|
||||
if (_bundleCacheOp.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_bundleCacheOp.Status == EOperationStatus.Succeeded)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetResult();
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError(_bundleCacheOp.Error);
|
||||
}
|
||||
|
||||
// 注意:缓存完成后直接删除临时文件
|
||||
DeleteTempFile();
|
||||
}
|
||||
}
|
||||
protected override void InternalWaitForCompletion()
|
||||
{
|
||||
ExecuteBatch();
|
||||
}
|
||||
|
||||
private void DeleteTempFile()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (File.Exists(_tempFilePath))
|
||||
File.Delete(_tempFilePath);
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
YooLogger.LogWarning($"Failed to delete temp file '{_tempFilePath}': {ex.Message}.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 47700ac672942834f8d5a7c59783d88e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,65 @@
|
||||
using System.IO;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 加载缓存包裹哈希文件操作
|
||||
/// </summary>
|
||||
internal sealed class LoadCachePackageHashOperation : AsyncOperationBase
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
LoadPackageHash,
|
||||
Done,
|
||||
}
|
||||
|
||||
private readonly SandboxFileSystem _fileSystem;
|
||||
private readonly string _packageVersion;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
/// <summary>
|
||||
/// 包裹哈希值
|
||||
/// </summary>
|
||||
public string PackageHash { get; private set; }
|
||||
|
||||
|
||||
internal LoadCachePackageHashOperation(SandboxFileSystem fileSystem, string packageVersion)
|
||||
{
|
||||
_fileSystem = fileSystem;
|
||||
_packageVersion = packageVersion;
|
||||
}
|
||||
protected override void InternalStart()
|
||||
{
|
||||
_steps = ESteps.LoadPackageHash;
|
||||
}
|
||||
protected override void InternalUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
if (_steps == ESteps.LoadPackageHash)
|
||||
{
|
||||
string filePath = _fileSystem.GetCachePackageHashFilePath(_packageVersion);
|
||||
if (File.Exists(filePath) == false)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError($"Could not find cache package hash file: '{filePath}'.");
|
||||
return;
|
||||
}
|
||||
|
||||
PackageHash = FileUtility.ReadAllText(filePath);
|
||||
if (TextUtility.ValidateContent(PackageHash, out string validateError) == false)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError($"Cache package hash file validation failed: {validateError}.");
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetResult();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: db66f75d31bfeca4e897e9ee0946b1de
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,115 @@
|
||||
using System.IO;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 加载缓存包裹清单文件操作
|
||||
/// </summary>
|
||||
internal sealed class LoadCachePackageManifestOperation : AsyncOperationBase
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
LoadFileData,
|
||||
VerifyFileData,
|
||||
LoadManifest,
|
||||
Done,
|
||||
}
|
||||
|
||||
private readonly SandboxFileSystem _fileSystem;
|
||||
private readonly string _packageVersion;
|
||||
private readonly string _packageHash;
|
||||
private DeserializeManifestOperation _deserializeManifestOp;
|
||||
private byte[] _fileData;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
/// <summary>
|
||||
/// 包裹清单
|
||||
/// </summary>
|
||||
public PackageManifest Manifest { get; private set; }
|
||||
|
||||
|
||||
internal LoadCachePackageManifestOperation(SandboxFileSystem fileSystem, string packageVersion, string packageHash)
|
||||
{
|
||||
_fileSystem = fileSystem;
|
||||
_packageVersion = packageVersion;
|
||||
_packageHash = packageHash;
|
||||
}
|
||||
protected override void InternalStart()
|
||||
{
|
||||
_steps = ESteps.LoadFileData;
|
||||
}
|
||||
protected override void InternalUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
if (_steps == ESteps.LoadFileData)
|
||||
{
|
||||
string manifestFilePath = _fileSystem.GetCachePackageManifestFilePath(_packageVersion);
|
||||
if (File.Exists(manifestFilePath))
|
||||
{
|
||||
try
|
||||
{
|
||||
_fileData = File.ReadAllBytes(manifestFilePath);
|
||||
_steps = ESteps.VerifyFileData;
|
||||
}
|
||||
catch (System.Exception ex)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError($"Failed to read cache package manifest file: {ex.Message}.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError($"Could not find cache manifest file: '{manifestFilePath}'.");
|
||||
}
|
||||
}
|
||||
|
||||
if (_steps == ESteps.VerifyFileData)
|
||||
{
|
||||
if (PackageManifestHelper.VerifyManifestData(_fileData, _packageHash))
|
||||
{
|
||||
_steps = ESteps.LoadManifest;
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError("Failed to verify cache package manifest file.");
|
||||
}
|
||||
}
|
||||
|
||||
if (_steps == ESteps.LoadManifest)
|
||||
{
|
||||
if (_deserializeManifestOp == null)
|
||||
{
|
||||
_deserializeManifestOp = new DeserializeManifestOperation(_fileSystem.ManifestDecryptor, _fileData);
|
||||
_deserializeManifestOp.StartOperation();
|
||||
AddChildOperation(_deserializeManifestOp);
|
||||
}
|
||||
|
||||
_deserializeManifestOp.UpdateOperation();
|
||||
Progress = _deserializeManifestOp.Progress;
|
||||
if (_deserializeManifestOp.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_deserializeManifestOp.Status == EOperationStatus.Succeeded)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Manifest = _deserializeManifestOp.Manifest;
|
||||
SetResult();
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError(_deserializeManifestOp.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
protected override string InternalGetDescription()
|
||||
{
|
||||
return $"PackageVersion: {_packageVersion} PackageHash: {_packageHash}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: acd84795f7cc3e348ab2b6cde03c8a22
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,105 @@
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 请求远端包裹版本操作
|
||||
/// </summary>
|
||||
internal sealed class RequestRemotePackageVersionOperation : AsyncOperationBase
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
RequestPackageVersion,
|
||||
Done,
|
||||
}
|
||||
|
||||
private readonly SandboxFileSystem _fileSystem;
|
||||
private readonly bool _appendTimeTicks;
|
||||
private readonly int _timeout;
|
||||
private IDownloadTextRequest _downloadTextRequest;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
/// <summary>
|
||||
/// 包裹版本
|
||||
/// </summary>
|
||||
internal string PackageVersion { get; set; }
|
||||
|
||||
|
||||
internal RequestRemotePackageVersionOperation(SandboxFileSystem fileSystem, bool appendTimeTicks, int timeout)
|
||||
{
|
||||
_fileSystem = fileSystem;
|
||||
_appendTimeTicks = appendTimeTicks;
|
||||
_timeout = timeout;
|
||||
}
|
||||
protected override void InternalStart()
|
||||
{
|
||||
_steps = ESteps.RequestPackageVersion;
|
||||
}
|
||||
protected override void InternalUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
if (_steps == ESteps.RequestPackageVersion)
|
||||
{
|
||||
if (_downloadTextRequest == null)
|
||||
{
|
||||
string fileName = YooAssetConfiguration.GetPackageVersionFileName(_fileSystem.PackageName);
|
||||
string url = GetWebRequestUrl(fileName);
|
||||
int watchDogTime = _fileSystem.DownloadWatchdogTimeout;
|
||||
var args = new DownloadDataRequestArgs(
|
||||
url: url,
|
||||
timeout: _timeout,
|
||||
watchdogTimeout: watchDogTime);
|
||||
_downloadTextRequest = _fileSystem.DownloadBackend.CreateTextRequest(args);
|
||||
_downloadTextRequest.SendRequest();
|
||||
}
|
||||
|
||||
Progress = _downloadTextRequest.DownloadProgress;
|
||||
if (_downloadTextRequest.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_downloadTextRequest.Status == EDownloadRequestStatus.Succeeded)
|
||||
{
|
||||
PackageVersion = _downloadTextRequest.Result;
|
||||
if (TextUtility.ValidateContent(PackageVersion, out string validateError) == false)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError($"Remote package version file validation failed: {validateError}.");
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetResult();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError(_downloadTextRequest.Error);
|
||||
_fileSystem.DownloadUrlPolicy.OnRequestFailed(_downloadTextRequest.Url, _downloadTextRequest.HttpCode, _downloadTextRequest.HttpError);
|
||||
}
|
||||
}
|
||||
}
|
||||
protected override void InternalDispose()
|
||||
{
|
||||
if (_downloadTextRequest != null)
|
||||
{
|
||||
_downloadTextRequest.Dispose();
|
||||
_downloadTextRequest = null;
|
||||
}
|
||||
}
|
||||
|
||||
private string GetWebRequestUrl(string fileName)
|
||||
{
|
||||
var urls = _fileSystem.RemoteService.GetRemoteUrls(fileName);
|
||||
string url = _fileSystem.DownloadUrlPolicy.SelectUrl(urls);
|
||||
|
||||
// 在URL末尾添加时间戳
|
||||
if (_appendTimeTicks)
|
||||
return $"{url}?{System.DateTime.UtcNow.Ticks}";
|
||||
else
|
||||
return url;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1b078a220cc4f7d4392d77ccc77c001e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,215 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 沙盒文件系统的清理缓存操作
|
||||
/// </summary>
|
||||
internal sealed class SFSClearCacheOperation : FSClearCacheOperation
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
CheckReadOnly,
|
||||
ClearCache,
|
||||
Done,
|
||||
}
|
||||
|
||||
private readonly SandboxFileSystem _fileSystem;
|
||||
private readonly FSClearCacheOptions _options;
|
||||
private BCClearCacheOperation _clearCacheOp;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
internal SFSClearCacheOperation(SandboxFileSystem fileSystem, FSClearCacheOptions options)
|
||||
{
|
||||
_fileSystem = fileSystem;
|
||||
_options = options;
|
||||
}
|
||||
protected override void InternalStart()
|
||||
{
|
||||
_steps = ESteps.CheckReadOnly;
|
||||
}
|
||||
protected override void InternalUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
if (_steps == ESteps.CheckReadOnly)
|
||||
{
|
||||
if (_fileSystem.BundleCache.IsReadOnly)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetResult();
|
||||
return;
|
||||
}
|
||||
|
||||
_steps = ESteps.ClearCache;
|
||||
}
|
||||
|
||||
if (_steps == ESteps.ClearCache)
|
||||
{
|
||||
if (_clearCacheOp == null)
|
||||
{
|
||||
_clearCacheOp = _fileSystem.BundleCache.ClearCacheAsync(_options.ConvertTo());
|
||||
_clearCacheOp.StartOperation();
|
||||
AddChildOperation(_clearCacheOp);
|
||||
}
|
||||
|
||||
_clearCacheOp.UpdateOperation();
|
||||
if (_clearCacheOp.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_clearCacheOp.Status == EOperationStatus.Succeeded)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetResult();
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError(_clearCacheOp.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 沙盒文件系统的清理所有缓存清单操作
|
||||
/// </summary>
|
||||
internal sealed class SFSClearAllCacheManifestOperation : FSClearCacheOperation
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
ClearAllCacheFiles,
|
||||
Done,
|
||||
}
|
||||
|
||||
private readonly SandboxFileSystem _fileSystem;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
internal SFSClearAllCacheManifestOperation(SandboxFileSystem fileSystem)
|
||||
{
|
||||
_fileSystem = fileSystem;
|
||||
}
|
||||
protected override void InternalStart()
|
||||
{
|
||||
_steps = ESteps.ClearAllCacheFiles;
|
||||
}
|
||||
protected override void InternalUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
if (_steps == ESteps.ClearAllCacheFiles)
|
||||
{
|
||||
try
|
||||
{
|
||||
// TODO: 如果正在下载资源清单,会有几率触发异常!
|
||||
string directoryRoot = _fileSystem.GetCacheManifestFilesRoot();
|
||||
DirectoryInfo directoryInfo = new DirectoryInfo(directoryRoot);
|
||||
if (directoryInfo.Exists)
|
||||
{
|
||||
foreach (FileInfo fileInfo in directoryInfo.GetFiles())
|
||||
{
|
||||
string fileName = fileInfo.Name;
|
||||
if (fileName == SandboxFileSystemConsts.AppFootprintFileName)
|
||||
continue;
|
||||
|
||||
fileInfo.Delete();
|
||||
}
|
||||
}
|
||||
|
||||
_steps = ESteps.Done;
|
||||
SetResult();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError(ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 沙盒文件系统的清理未使用缓存清单操作
|
||||
/// </summary>
|
||||
internal sealed class SFSClearUnusedCacheManifestOperation : FSClearCacheOperation
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
CheckManifest,
|
||||
ClearUnusedCacheFiles,
|
||||
Done,
|
||||
}
|
||||
|
||||
private readonly SandboxFileSystem _fileSystem;
|
||||
private readonly PackageManifest _manifest;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
internal SFSClearUnusedCacheManifestOperation(SandboxFileSystem fileSystem, PackageManifest manifest)
|
||||
{
|
||||
_fileSystem = fileSystem;
|
||||
_manifest = manifest;
|
||||
}
|
||||
protected override void InternalStart()
|
||||
{
|
||||
_steps = ESteps.CheckManifest;
|
||||
}
|
||||
protected override void InternalUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
if (_steps == ESteps.CheckManifest)
|
||||
{
|
||||
if (_manifest == null)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError("Could not find active package manifest.");
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.ClearUnusedCacheFiles;
|
||||
}
|
||||
}
|
||||
|
||||
if (_steps == ESteps.ClearUnusedCacheFiles)
|
||||
{
|
||||
try
|
||||
{
|
||||
string activeManifestFileName = YooAssetConfiguration.GetManifestBinaryFileName(_manifest.PackageName, _manifest.PackageVersion);
|
||||
string activeHashFileName = YooAssetConfiguration.GetPackageHashFileName(_manifest.PackageName, _manifest.PackageVersion);
|
||||
|
||||
// TODO: 如果正在下载资源清单,会有几率触发异常!
|
||||
string directoryRoot = _fileSystem.GetCacheManifestFilesRoot();
|
||||
DirectoryInfo directoryInfo = new DirectoryInfo(directoryRoot);
|
||||
if (directoryInfo.Exists)
|
||||
{
|
||||
foreach (FileInfo fileInfo in directoryInfo.GetFiles())
|
||||
{
|
||||
string fileName = fileInfo.Name;
|
||||
if (fileName == SandboxFileSystemConsts.AppFootprintFileName)
|
||||
continue;
|
||||
if (fileName == activeManifestFileName || fileName == activeHashFileName)
|
||||
continue;
|
||||
|
||||
fileInfo.Delete();
|
||||
}
|
||||
}
|
||||
|
||||
_steps = ESteps.Done;
|
||||
SetResult();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError(ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5643382e7031ba14cbb4ab0f4a9acd94
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,179 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 沙盒文件系统的下载文件操作
|
||||
/// </summary>
|
||||
internal sealed class SFSDownloadBundleOperation : FSDownloadBundleOperation
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
CheckExists,
|
||||
CreateDownload,
|
||||
CheckDownload,
|
||||
TryAgain,
|
||||
Done,
|
||||
}
|
||||
|
||||
private readonly SandboxFileSystem _fileSystem;
|
||||
private readonly FSDownloadBundleOptions _options;
|
||||
private readonly DownloadRetryController _downloadRetryController;
|
||||
private DownloadFileBaseOperation _downloadFileOp;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
internal SFSDownloadBundleOperation(SandboxFileSystem fileSystem, FSDownloadBundleOptions options) : base(options.Bundle)
|
||||
{
|
||||
_fileSystem = fileSystem;
|
||||
_options = options;
|
||||
_downloadRetryController = new DownloadRetryController(options.RetryCount, _fileSystem.DownloadRetryPolicy);
|
||||
}
|
||||
protected override void InternalStart()
|
||||
{
|
||||
_steps = ESteps.CheckExists;
|
||||
}
|
||||
protected override void InternalUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
// 检测文件是否存在
|
||||
if (_steps == ESteps.CheckExists)
|
||||
{
|
||||
if (_fileSystem.BundleCache.IsCached(Bundle.BundleGuid))
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetResult();
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.CreateDownload;
|
||||
}
|
||||
}
|
||||
|
||||
// 创建下载器
|
||||
if (_steps == ESteps.CreateDownload)
|
||||
{
|
||||
_downloadFileOp = _fileSystem.DownloadScheduler.TryGetDownloadOperation(Bundle);
|
||||
if (_downloadFileOp == null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(_options.ImportFilePath))
|
||||
{
|
||||
// 下载远端文件
|
||||
string url = GetRequestUrl(Bundle.GetFileName());
|
||||
_downloadFileOp = new DownloadAndCacheFileOperation(_fileSystem, Bundle, url);
|
||||
_fileSystem.DownloadScheduler.RegisterDownloadOperation(_downloadFileOp);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 导入本地文件
|
||||
_downloadFileOp = new ImportAndCacheFileOperation(_fileSystem, Bundle, _options.ImportFilePath);
|
||||
_fileSystem.DownloadScheduler.RegisterDownloadOperation(_downloadFileOp);
|
||||
}
|
||||
}
|
||||
|
||||
_steps = ESteps.CheckDownload;
|
||||
}
|
||||
|
||||
// 检测结果
|
||||
if (_steps == ESteps.CheckDownload)
|
||||
{
|
||||
if (IsWaitForCompletion)
|
||||
{
|
||||
if (_downloadFileOp is DownloadAndCacheFileOperation)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError($"Attempting to load bundle '{Bundle.BundleName}' from remote: '{_downloadFileOp.Url}'.");
|
||||
return;
|
||||
}
|
||||
_downloadFileOp.WaitForCompletion();
|
||||
}
|
||||
|
||||
// 注意:不主动调用 _downloadFileOp.UpdateOperation()
|
||||
// 说明:下载任务由 DownloadSchedulerOperation 统一驱动,此处仅读取状态。
|
||||
// 说明:同步等待由 WaitForCompletion() 内部的 ExecuteBatch() 保证。
|
||||
Progress = _downloadFileOp.Progress;
|
||||
Report = _downloadFileOp.LatestReport;
|
||||
if (_downloadFileOp.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_downloadFileOp.Status == EOperationStatus.Succeeded)
|
||||
{
|
||||
_fileSystem.DownloadUrlPolicy.OnRequestSucceeded(_downloadFileOp.Url);
|
||||
_steps = ESteps.Done;
|
||||
SetResult();
|
||||
}
|
||||
else
|
||||
{
|
||||
// 注意:本地导入失败时跳过重试策略
|
||||
if (string.IsNullOrEmpty(_options.ImportFilePath) == false)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError(_downloadFileOp.Error);
|
||||
YooLogger.LogError(Error);
|
||||
}
|
||||
else
|
||||
{
|
||||
string url = _downloadFileOp.Url;
|
||||
long httpCode = _downloadFileOp.LatestReport.HttpCode;
|
||||
string httpError = _downloadFileOp.LatestReport.HttpError;
|
||||
_fileSystem.DownloadUrlPolicy.OnRequestFailed(url, httpCode, httpError);
|
||||
if (IsWaitForCompletion == false && _downloadRetryController.CanRetryRequest(url, httpCode, httpError))
|
||||
{
|
||||
_downloadRetryController.StartRetryDelay();
|
||||
_steps = ESteps.TryAgain;
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError(_downloadFileOp.Error);
|
||||
YooLogger.LogError(Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 重新尝试下载
|
||||
if (_steps == ESteps.TryAgain)
|
||||
{
|
||||
if (_downloadRetryController.TickRetryDelay())
|
||||
{
|
||||
if (_downloadFileOp != null)
|
||||
{
|
||||
_downloadFileOp.Release();
|
||||
_downloadFileOp = null;
|
||||
}
|
||||
|
||||
Progress = 0f;
|
||||
Report = DownloadReport.Empty;
|
||||
_steps = ESteps.CreateDownload;
|
||||
}
|
||||
}
|
||||
}
|
||||
protected override void InternalWaitForCompletion()
|
||||
{
|
||||
ExecuteBatch();
|
||||
}
|
||||
protected override void InternalAbort()
|
||||
{
|
||||
// 注意:取消下载任务的时候引用计数减一
|
||||
if (_steps != ESteps.Done)
|
||||
{
|
||||
if (_downloadFileOp != null)
|
||||
{
|
||||
_downloadFileOp.Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取网络请求地址
|
||||
/// </summary>
|
||||
private string GetRequestUrl(string fileName)
|
||||
{
|
||||
var urls = _fileSystem.RemoteService.GetRemoteUrls(fileName);
|
||||
return _fileSystem.DownloadUrlPolicy.SelectUrl(urls);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: af07b7cdf729e944dbb6d60204c71235
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,146 @@
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 沙盒文件系统的初始化操作
|
||||
/// </summary>
|
||||
internal sealed class SFSInitializeOperation : FSInitializeOperation
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
CheckPlatform,
|
||||
CheckParameter,
|
||||
CheckAppFootprint,
|
||||
InitializeBundleCache,
|
||||
CreateScheduler,
|
||||
Done,
|
||||
}
|
||||
|
||||
private readonly SandboxFileSystem _fileSystem;
|
||||
private BCInitializeOperation _initializeBundleCacheOp;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
|
||||
internal SFSInitializeOperation(SandboxFileSystem fileSystem)
|
||||
{
|
||||
_fileSystem = fileSystem;
|
||||
}
|
||||
protected override void InternalStart()
|
||||
{
|
||||
_steps = ESteps.CheckPlatform;
|
||||
}
|
||||
protected override void InternalUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
if (_steps == ESteps.CheckPlatform)
|
||||
{
|
||||
#if UNITY_WEBGL
|
||||
_steps = ESteps.Done;
|
||||
SetError($"{nameof(SandboxFileSystem)} does not support the WebGL platform.");
|
||||
#else
|
||||
_steps = ESteps.CheckParameter;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (_steps == ESteps.CheckParameter)
|
||||
{
|
||||
if (_fileSystem.RemoteService == null)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError($"{nameof(IRemoteService)} is null.");
|
||||
return;
|
||||
}
|
||||
|
||||
_steps = ESteps.CheckAppFootprint;
|
||||
}
|
||||
|
||||
if (_steps == ESteps.CheckAppFootprint)
|
||||
{
|
||||
string footprintFilePath = _fileSystem.GetSandboxAppFootprintFilePath();
|
||||
var appFootprint = new ApplicationFootprint(footprintFilePath);
|
||||
appFootprint.Load(_fileSystem.PackageName);
|
||||
|
||||
// 如果水印发生变化,则说明覆盖安装后首次打开游戏
|
||||
if (appFootprint.IsDirty())
|
||||
{
|
||||
if (_fileSystem.InstallCleanupMode == EInstallCleanupMode.None)
|
||||
{
|
||||
YooLogger.LogWarning("No action required on overwrite installation.");
|
||||
}
|
||||
else if (_fileSystem.InstallCleanupMode == EInstallCleanupMode.ClearAllCacheFiles)
|
||||
{
|
||||
_fileSystem.DeleteAllBundleFiles();
|
||||
_fileSystem.DeleteAllManifestFiles();
|
||||
_fileSystem.DeleteAllTempFiles();
|
||||
YooLogger.LogWarning("Deleted all cache files on overwrite installation.");
|
||||
}
|
||||
else if (_fileSystem.InstallCleanupMode == EInstallCleanupMode.ClearAllBundleFiles)
|
||||
{
|
||||
_fileSystem.DeleteAllBundleFiles();
|
||||
YooLogger.LogWarning("Deleted all bundle files on overwrite installation.");
|
||||
}
|
||||
else if (_fileSystem.InstallCleanupMode == EInstallCleanupMode.ClearAllManifestFiles)
|
||||
{
|
||||
_fileSystem.DeleteAllManifestFiles();
|
||||
YooLogger.LogWarning("Deleted all manifest files on overwrite installation.");
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new YooInternalException($"Unhandled {nameof(EInstallCleanupMode)} value: {_fileSystem.InstallCleanupMode}.");
|
||||
}
|
||||
|
||||
appFootprint.Overwrite(_fileSystem.PackageName);
|
||||
}
|
||||
|
||||
_steps = ESteps.InitializeBundleCache;
|
||||
}
|
||||
|
||||
if (_steps == ESteps.InitializeBundleCache)
|
||||
{
|
||||
if (_initializeBundleCacheOp == null)
|
||||
{
|
||||
_initializeBundleCacheOp = _fileSystem.BundleCache.InitializeAsync();
|
||||
_initializeBundleCacheOp.StartOperation();
|
||||
AddChildOperation(_initializeBundleCacheOp);
|
||||
}
|
||||
|
||||
_initializeBundleCacheOp.UpdateOperation();
|
||||
Progress = _initializeBundleCacheOp.Progress;
|
||||
if (_initializeBundleCacheOp.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_initializeBundleCacheOp.Status == EOperationStatus.Succeeded)
|
||||
{
|
||||
_steps = ESteps.CreateScheduler;
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError(_initializeBundleCacheOp.Error);
|
||||
}
|
||||
}
|
||||
|
||||
if (_steps == ESteps.CreateScheduler)
|
||||
{
|
||||
// 注意: 下载调度中心在最后一步创建,防止初始化失败后残留任务。
|
||||
// 注意: 下载调度中心作为独立任务运行!
|
||||
if (_fileSystem.DownloadScheduler == null)
|
||||
{
|
||||
var schedulerConfig = new DownloadSchedulerOperation.Configuration(
|
||||
schedulerName: _fileSystem.GetType().Name,
|
||||
downloadBackend: _fileSystem.DownloadBackend,
|
||||
maxConcurrency: _fileSystem.DownloadMaxConcurrency,
|
||||
maxRequestsPerFrame: _fileSystem.DownloadMaxRequestsPerFrame);
|
||||
_fileSystem.DownloadScheduler = new DownloadSchedulerOperation(schedulerConfig);
|
||||
AsyncOperationSystem.StartOperation(_fileSystem.PackageName, _fileSystem.DownloadScheduler);
|
||||
}
|
||||
|
||||
_steps = ESteps.Done;
|
||||
SetResult();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 443aa31f081edfd458a90e3385a75203
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,161 @@
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 沙盒文件系统的加载资源包操作
|
||||
/// </summary>
|
||||
internal sealed class SFSLoadPackageBundleOperation : FSLoadPackageBundleOperation
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
Prepare,
|
||||
DownloadFile,
|
||||
AbortDownload,
|
||||
LoadBundle,
|
||||
CheckResult,
|
||||
Done,
|
||||
}
|
||||
|
||||
private readonly SandboxFileSystem _fileSystem;
|
||||
private readonly FSLoadPackageBundleOptions _options;
|
||||
private FSDownloadBundleOperation _downloadFileOp;
|
||||
private BCLoadBundleOperation _loadBundleOp;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
internal SFSLoadPackageBundleOperation(SandboxFileSystem fileSystem, FSLoadPackageBundleOptions options)
|
||||
{
|
||||
_fileSystem = fileSystem;
|
||||
_options = options;
|
||||
}
|
||||
protected override void InternalStart()
|
||||
{
|
||||
_steps = ESteps.Prepare;
|
||||
}
|
||||
protected override void InternalUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
if (_steps == ESteps.Prepare)
|
||||
{
|
||||
if (_fileSystem.BundleCache.IsCached(_options.Bundle.BundleGuid))
|
||||
{
|
||||
_steps = ESteps.LoadBundle;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_fileSystem.DisableOnDemandDownload)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError($"Bundle is not cached: '{_options.Bundle.BundleName}'.");
|
||||
YooLogger.LogWarning(Error);
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.DownloadFile;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_steps == ESteps.DownloadFile)
|
||||
{
|
||||
// 中断下载
|
||||
if (ShouldAbortDownload)
|
||||
{
|
||||
if (_downloadFileOp != null)
|
||||
_downloadFileOp.AbortOperation();
|
||||
_steps = ESteps.AbortDownload;
|
||||
}
|
||||
}
|
||||
|
||||
if (_steps == ESteps.DownloadFile)
|
||||
{
|
||||
if (_downloadFileOp == null)
|
||||
{
|
||||
var options = new FSDownloadBundleOptions(_options.Bundle, int.MaxValue);
|
||||
_downloadFileOp = _fileSystem.DownloadBundleAsync(options);
|
||||
_downloadFileOp.StartOperation();
|
||||
AddChildOperation(_downloadFileOp);
|
||||
}
|
||||
|
||||
if (IsWaitForCompletion)
|
||||
_downloadFileOp.WaitForCompletion();
|
||||
|
||||
_downloadFileOp.UpdateOperation();
|
||||
if (_downloadFileOp.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_downloadFileOp.Status == EOperationStatus.Succeeded)
|
||||
{
|
||||
_steps = ESteps.LoadBundle;
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError(_downloadFileOp.Error);
|
||||
}
|
||||
}
|
||||
|
||||
if (_steps == ESteps.AbortDownload)
|
||||
{
|
||||
if (_downloadFileOp != null)
|
||||
{
|
||||
if (IsWaitForCompletion)
|
||||
_downloadFileOp.WaitForCompletion();
|
||||
|
||||
_downloadFileOp.UpdateOperation();
|
||||
if (_downloadFileOp.IsDone == false)
|
||||
return;
|
||||
}
|
||||
|
||||
_steps = ESteps.Done;
|
||||
SetError("Bundle download aborted.");
|
||||
}
|
||||
|
||||
if (_steps == ESteps.LoadBundle)
|
||||
{
|
||||
_loadBundleOp = _fileSystem.BundleCache.LoadBundleAsync(_options.ConvertTo());
|
||||
_loadBundleOp.StartOperation();
|
||||
AddChildOperation(_loadBundleOp);
|
||||
_steps = ESteps.CheckResult;
|
||||
}
|
||||
|
||||
if (_steps == ESteps.CheckResult)
|
||||
{
|
||||
if (IsWaitForCompletion)
|
||||
_loadBundleOp.WaitForCompletion();
|
||||
|
||||
_loadBundleOp.UpdateOperation();
|
||||
if (_loadBundleOp.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_loadBundleOp.Status == EOperationStatus.Succeeded)
|
||||
{
|
||||
if (_loadBundleOp.BundleHandle == null)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError("Fatal error: loaded bundle handle is null.");
|
||||
YooLogger.LogError(Error);
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetResult();
|
||||
BundleHandle = _loadBundleOp.BundleHandle;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError(_loadBundleOp.Error);
|
||||
YooLogger.LogError(Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
protected override void InternalWaitForCompletion()
|
||||
{
|
||||
ExecuteBatch();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a653cabf995909d48935a0486db6116f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,166 @@
|
||||
using System.IO;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 沙盒文件系统的加载包裹清单操作
|
||||
/// </summary>
|
||||
internal sealed class SFSLoadPackageManifestOperation : FSLoadPackageManifestOperation
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
DownloadPackageHash,
|
||||
DownloadPackageManifest,
|
||||
LoadPackageHash,
|
||||
LoadPackageManifest,
|
||||
Done,
|
||||
}
|
||||
|
||||
private readonly SandboxFileSystem _fileSystem;
|
||||
private readonly string _packageVersion;
|
||||
private readonly int _timeout;
|
||||
private DownloadPackageHashOperation _downloadPackageHashOp;
|
||||
private DownloadPackageManifestOperation _downloadPackageManifestOp;
|
||||
private LoadCachePackageHashOperation _loadCachePackageHashOp;
|
||||
private LoadCachePackageManifestOperation _loadCachePackageManifestOp;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
|
||||
internal SFSLoadPackageManifestOperation(SandboxFileSystem fileSystem, string packageVersion, int timeout)
|
||||
{
|
||||
_fileSystem = fileSystem;
|
||||
_packageVersion = packageVersion;
|
||||
_timeout = timeout;
|
||||
}
|
||||
protected override void InternalStart()
|
||||
{
|
||||
_steps = ESteps.DownloadPackageHash;
|
||||
}
|
||||
protected override void InternalUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
if (_steps == ESteps.DownloadPackageHash)
|
||||
{
|
||||
if (_downloadPackageHashOp == null)
|
||||
{
|
||||
_downloadPackageHashOp = new DownloadPackageHashOperation(_fileSystem, _packageVersion, _timeout);
|
||||
_downloadPackageHashOp.StartOperation();
|
||||
AddChildOperation(_downloadPackageHashOp);
|
||||
}
|
||||
|
||||
_downloadPackageHashOp.UpdateOperation();
|
||||
if (_downloadPackageHashOp.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_downloadPackageHashOp.Status == EOperationStatus.Succeeded)
|
||||
{
|
||||
_steps = ESteps.DownloadPackageManifest;
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError(_downloadPackageHashOp.Error);
|
||||
}
|
||||
}
|
||||
|
||||
if (_steps == ESteps.DownloadPackageManifest)
|
||||
{
|
||||
if (_downloadPackageManifestOp == null)
|
||||
{
|
||||
_downloadPackageManifestOp = new DownloadPackageManifestOperation(_fileSystem, _packageVersion, _timeout);
|
||||
_downloadPackageManifestOp.StartOperation();
|
||||
AddChildOperation(_downloadPackageManifestOp);
|
||||
}
|
||||
|
||||
_downloadPackageManifestOp.UpdateOperation();
|
||||
if (_downloadPackageManifestOp.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_downloadPackageManifestOp.Status == EOperationStatus.Succeeded)
|
||||
{
|
||||
_steps = ESteps.LoadPackageHash;
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError(_downloadPackageManifestOp.Error);
|
||||
}
|
||||
}
|
||||
|
||||
if (_steps == ESteps.LoadPackageHash)
|
||||
{
|
||||
if (_loadCachePackageHashOp == null)
|
||||
{
|
||||
_loadCachePackageHashOp = new LoadCachePackageHashOperation(_fileSystem, _packageVersion);
|
||||
_loadCachePackageHashOp.StartOperation();
|
||||
AddChildOperation(_loadCachePackageHashOp);
|
||||
}
|
||||
|
||||
_loadCachePackageHashOp.UpdateOperation();
|
||||
if (_loadCachePackageHashOp.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_loadCachePackageHashOp.Status == EOperationStatus.Succeeded)
|
||||
{
|
||||
_steps = ESteps.LoadPackageManifest;
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError(_loadCachePackageHashOp.Error);
|
||||
ClearCacheFatalFile();
|
||||
}
|
||||
}
|
||||
|
||||
if (_steps == ESteps.LoadPackageManifest)
|
||||
{
|
||||
if (_loadCachePackageManifestOp == null)
|
||||
{
|
||||
string packageHash = _loadCachePackageHashOp.PackageHash;
|
||||
_loadCachePackageManifestOp = new LoadCachePackageManifestOperation(_fileSystem, _packageVersion, packageHash);
|
||||
_loadCachePackageManifestOp.StartOperation();
|
||||
AddChildOperation(_loadCachePackageManifestOp);
|
||||
}
|
||||
|
||||
_loadCachePackageManifestOp.UpdateOperation();
|
||||
Progress = _loadCachePackageManifestOp.Progress;
|
||||
if (_loadCachePackageManifestOp.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_loadCachePackageManifestOp.Status == EOperationStatus.Succeeded)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetResult();
|
||||
Manifest = _loadCachePackageManifestOp.Manifest;
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError(_loadCachePackageManifestOp.Error);
|
||||
ClearCacheFatalFile();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearCacheFatalFile()
|
||||
{
|
||||
// 注意:如果加载沙盒内的清单报错,为了避免流程被卡住,主动把损坏的文件删除。
|
||||
string manifestFilePath = _fileSystem.GetCachePackageManifestFilePath(_packageVersion);
|
||||
if (File.Exists(manifestFilePath))
|
||||
{
|
||||
YooLogger.LogWarning($"Invalid package manifest file has been removed: '{manifestFilePath}'.");
|
||||
File.Delete(manifestFilePath);
|
||||
}
|
||||
|
||||
string hashFilePath = _fileSystem.GetCachePackageHashFilePath(_packageVersion);
|
||||
if (File.Exists(hashFilePath))
|
||||
{
|
||||
YooLogger.LogWarning($"Invalid package hash file has been removed: '{hashFilePath}'.");
|
||||
File.Delete(hashFilePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2447826454481704ab785153ae89be3a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,66 @@
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 沙盒文件系统的查询包裹版本操作
|
||||
/// </summary>
|
||||
internal sealed class SFSRequestPackageVersionOperation : FSRequestPackageVersionOperation
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
GetPackageVersion,
|
||||
Done,
|
||||
}
|
||||
|
||||
private readonly SandboxFileSystem _fileSystem;
|
||||
private readonly bool _appendTimeTicks;
|
||||
private readonly int _timeout;
|
||||
private RequestRemotePackageVersionOperation _requestRemotePackageVersionOp;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
|
||||
internal SFSRequestPackageVersionOperation(SandboxFileSystem fileSystem, bool appendTimeTicks, int timeout)
|
||||
{
|
||||
_fileSystem = fileSystem;
|
||||
_appendTimeTicks = appendTimeTicks;
|
||||
_timeout = timeout;
|
||||
}
|
||||
protected override void InternalStart()
|
||||
{
|
||||
_steps = ESteps.GetPackageVersion;
|
||||
}
|
||||
protected override void InternalUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
if (_steps == ESteps.GetPackageVersion)
|
||||
{
|
||||
if (_requestRemotePackageVersionOp == null)
|
||||
{
|
||||
_requestRemotePackageVersionOp = new RequestRemotePackageVersionOperation(_fileSystem, _appendTimeTicks, _timeout);
|
||||
_requestRemotePackageVersionOp.StartOperation();
|
||||
AddChildOperation(_requestRemotePackageVersionOp);
|
||||
}
|
||||
|
||||
_requestRemotePackageVersionOp.UpdateOperation();
|
||||
Progress = _requestRemotePackageVersionOp.Progress;
|
||||
if (_requestRemotePackageVersionOp.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_requestRemotePackageVersionOp.Status == EOperationStatus.Succeeded)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
PackageVersion = _requestRemotePackageVersionOp.PackageVersion;
|
||||
SetResult();
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError(_requestRemotePackageVersionOp.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 856b1334d67ed4d41b31a583f713c449
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,476 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 沙盒文件系统,管理沙盒目录下的资源文件存储与访问。
|
||||
/// </summary>
|
||||
internal class SandboxFileSystem : IFileSystem
|
||||
{
|
||||
/// <summary>
|
||||
/// 临时文件路径映射表
|
||||
/// </summary>
|
||||
protected readonly Dictionary<string, string> _tempFilePathMapping = new Dictionary<string, string>(10000);
|
||||
|
||||
/// <summary>
|
||||
/// 包裹根目录路径
|
||||
/// </summary>
|
||||
protected string _packageRoot;
|
||||
|
||||
/// <summary>
|
||||
/// 临时文件根目录路径
|
||||
/// </summary>
|
||||
protected string _tempFilesRoot;
|
||||
|
||||
/// <summary>
|
||||
/// 缓存清单文件根目录路径
|
||||
/// </summary>
|
||||
protected string _cacheManifestFilesRoot;
|
||||
|
||||
/// <summary>
|
||||
/// 缓存资源包文件根目录路径
|
||||
/// </summary>
|
||||
protected string _cacheBundleFilesRoot;
|
||||
|
||||
/// <summary>
|
||||
/// 沙盒 Bundle 缓存系统
|
||||
/// </summary>
|
||||
public IBundleCache BundleCache { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 下载调度器
|
||||
/// </summary>
|
||||
public DownloadSchedulerOperation DownloadScheduler { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// 下载后台接口
|
||||
/// </summary>
|
||||
public IDownloadBackend DownloadBackend { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 包裹名称
|
||||
/// </summary>
|
||||
public string PackageName { get; private set; }
|
||||
|
||||
#region 自定义参数
|
||||
/// <summary>
|
||||
/// 自定义参数:UnityWebRequest 创建委托
|
||||
/// </summary>
|
||||
public UnityWebRequestCreator WebRequestCreator { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 自定义参数:覆盖安装缓存清理模式
|
||||
/// </summary>
|
||||
public EInstallCleanupMode InstallCleanupMode { get; private set; } = EInstallCleanupMode.None;
|
||||
|
||||
/// <summary>
|
||||
/// 自定义参数:初始化的时候缓存文件校验级别
|
||||
/// </summary>
|
||||
public EFileVerifyLevel FileVerifyLevel { get; private set; } = EFileVerifyLevel.Low;
|
||||
|
||||
/// <summary>
|
||||
/// 自定义参数:初始化时缓存文件校验的最大并发数
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 默认值:8(推荐值为处理器数两倍)。过大的值可能导致线程池任务过多,影响系统稳定性。
|
||||
/// </remarks>
|
||||
public int FileVerifyMaxConcurrency { get; private set; } = 8;
|
||||
|
||||
/// <summary>
|
||||
/// 自定义参数:禁用边玩边下机制
|
||||
/// </summary>
|
||||
public bool DisableOnDemandDownload { get; private set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 自定义参数:最大并发连接数
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 默认值:8(推荐范围 1-32)。过大的并发数可能被服务器限流,也会增加本地资源消耗。
|
||||
/// </remarks>
|
||||
public int DownloadMaxConcurrency { get; private set; } = 8;
|
||||
|
||||
/// <summary>
|
||||
/// 自定义参数:每帧发起的最大请求数
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// 默认值:8(推荐范围 1-32)。避免单帧发起过多请求导致卡顿。
|
||||
/// </remarks>
|
||||
public int DownloadMaxRequestsPerFrame { get; private set; } = 8;
|
||||
|
||||
/// <summary>
|
||||
/// 自定义参数:下载任务的看门狗机制超时时间
|
||||
/// </summary>
|
||||
public int DownloadWatchdogTimeout { get; private set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// 自定义参数:启用断点续传的最小尺寸
|
||||
/// </summary>
|
||||
public long ResumeDownloadMinimumSize { get; private set; } = long.MaxValue;
|
||||
|
||||
/// <summary>
|
||||
/// 自定义参数:远程服务接口的实例类
|
||||
/// </summary>
|
||||
public IRemoteService RemoteService { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 自定义参数:AssetBundle 解密器
|
||||
/// </summary>
|
||||
public IBundleDecryptor AssetBundleDecryptor { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 自定义参数:RawBundle 解密器
|
||||
/// </summary>
|
||||
public IBundleDecryptor RawBundleDecryptor { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 自定义参数:AssetBundle 备用解密器
|
||||
/// </summary>
|
||||
public IBundleMemoryDecryptor AssetBundleFallbackDecryptor { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 自定义参数:资源清单解密器
|
||||
/// </summary>
|
||||
public IManifestDecryptor ManifestDecryptor { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 自定义参数:下载重试判定策略
|
||||
/// </summary>
|
||||
public IDownloadRetryPolicy DownloadRetryPolicy { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// 自定义参数:URL 选择策略
|
||||
/// </summary>
|
||||
public IDownloadUrlPolicy DownloadUrlPolicy { get; private set; }
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// 创建实例
|
||||
/// </summary>
|
||||
public SandboxFileSystem()
|
||||
{
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public FSInitializeOperation InitializeAsync()
|
||||
{
|
||||
var operation = new SFSInitializeOperation(this);
|
||||
return operation;
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public FSRequestPackageVersionOperation RequestPackageVersionAsync(FSRequestPackageVersionOptions options)
|
||||
{
|
||||
var operation = new SFSRequestPackageVersionOperation(this, options.AppendTimeTicks, options.Timeout);
|
||||
return operation;
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public FSLoadPackageManifestOperation LoadPackageManifestAsync(FSLoadPackageManifestOptions options)
|
||||
{
|
||||
var operation = new SFSLoadPackageManifestOperation(this, options.PackageVersion, options.Timeout);
|
||||
return operation;
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public FSLoadPackageBundleOperation LoadPackageBundleAsync(FSLoadPackageBundleOptions options)
|
||||
{
|
||||
var operation = new SFSLoadPackageBundleOperation(this, options);
|
||||
return operation;
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public FSDownloadBundleOperation DownloadBundleAsync(FSDownloadBundleOptions options)
|
||||
{
|
||||
var downloader = new SFSDownloadBundleOperation(this, options);
|
||||
return downloader;
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public FSClearCacheOperation ClearCacheAsync(FSClearCacheOptions options)
|
||||
{
|
||||
if (options.ClearMethod == ClearCacheMethods.ClearAllManifestFiles)
|
||||
{
|
||||
var operation = new SFSClearAllCacheManifestOperation(this);
|
||||
return operation;
|
||||
}
|
||||
else if (options.ClearMethod == ClearCacheMethods.ClearUnusedManifestFiles)
|
||||
{
|
||||
var operation = new SFSClearUnusedCacheManifestOperation(this, options.Manifest);
|
||||
return operation;
|
||||
}
|
||||
else
|
||||
{
|
||||
var operation = new SFSClearCacheOperation(this, options);
|
||||
return operation;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void SetParameter(string paramName, object value)
|
||||
{
|
||||
if (paramName == nameof(EFileSystemParameter.DownloadBackend))
|
||||
{
|
||||
DownloadBackend = FileSystemHelper.CastParameter<IDownloadBackend>(paramName, value);
|
||||
}
|
||||
else if (paramName == nameof(EFileSystemParameter.UnityWebRequestCreator))
|
||||
{
|
||||
WebRequestCreator = FileSystemHelper.CastParameter<UnityWebRequestCreator>(paramName, value);
|
||||
}
|
||||
else if (paramName == nameof(EFileSystemParameter.InstallCleanupMode))
|
||||
{
|
||||
InstallCleanupMode = FileSystemHelper.CastParameter<EInstallCleanupMode>(paramName, value);
|
||||
}
|
||||
else if (paramName == nameof(EFileSystemParameter.FileVerifyLevel))
|
||||
{
|
||||
FileVerifyLevel = FileSystemHelper.CastParameter<EFileVerifyLevel>(paramName, value);
|
||||
}
|
||||
else if (paramName == nameof(EFileSystemParameter.FileVerifyMaxConcurrency))
|
||||
{
|
||||
int convertValue = FileSystemHelper.CastParameter<int>(paramName, value);
|
||||
if (convertValue > 32)
|
||||
{
|
||||
YooLogger.LogWarning($"FILE_VERIFY_MAX_CONCURRENCY value {convertValue} is too large, clamped to 32. Recommended range: 1 - 32.");
|
||||
}
|
||||
|
||||
// 限制在合理范围内:1-32
|
||||
FileVerifyMaxConcurrency = Mathf.Clamp(convertValue, 1, 32);
|
||||
}
|
||||
else if (paramName == nameof(EFileSystemParameter.DownloadDisableOndemand))
|
||||
{
|
||||
DisableOnDemandDownload = FileSystemHelper.CastParameter<bool>(paramName, value);
|
||||
}
|
||||
else if (paramName == nameof(EFileSystemParameter.DownloadMaxConcurrency))
|
||||
{
|
||||
int convertValue = FileSystemHelper.CastParameter<int>(paramName, value);
|
||||
if (convertValue > 32)
|
||||
{
|
||||
YooLogger.LogWarning($"DOWNLOAD_MAX_CONCURRENCY value {convertValue} is too large, clamped to 32. Recommended range: 1 - 32.");
|
||||
}
|
||||
|
||||
// 限制在合理范围内:1-32
|
||||
DownloadMaxConcurrency = Mathf.Clamp(convertValue, 1, 32);
|
||||
}
|
||||
else if (paramName == nameof(EFileSystemParameter.DownloadMaxRequestPerFrame))
|
||||
{
|
||||
int convertValue = FileSystemHelper.CastParameter<int>(paramName, value);
|
||||
if (convertValue > 32)
|
||||
{
|
||||
YooLogger.LogWarning($"DOWNLOAD_MAX_REQUEST_PER_FRAME value {convertValue} is too large, clamped to 32. Recommended range: 1 - 32.");
|
||||
}
|
||||
|
||||
// 限制在合理范围内:1-32
|
||||
DownloadMaxRequestsPerFrame = Mathf.Clamp(convertValue, 1, 32);
|
||||
}
|
||||
else if (paramName == nameof(EFileSystemParameter.DownloadWatchdogTimeout))
|
||||
{
|
||||
int convertValue = FileSystemHelper.CastParameter<int>(paramName, value);
|
||||
DownloadWatchdogTimeout = Mathf.Max(convertValue, 0);
|
||||
}
|
||||
else if (paramName == nameof(EFileSystemParameter.DownloadResumeMinimumSize))
|
||||
{
|
||||
ResumeDownloadMinimumSize = FileSystemHelper.CastParameter<long>(paramName, value);
|
||||
}
|
||||
else if (paramName == nameof(EFileSystemParameter.RemoteService))
|
||||
{
|
||||
RemoteService = FileSystemHelper.CastParameter<IRemoteService>(paramName, value);
|
||||
}
|
||||
else if (paramName == nameof(EFileSystemParameter.AssetbundleDecryptor))
|
||||
{
|
||||
AssetBundleDecryptor = FileSystemHelper.CastParameter<IBundleDecryptor>(paramName, value);
|
||||
}
|
||||
else if (paramName == nameof(EFileSystemParameter.RawbundleDecryptor))
|
||||
{
|
||||
RawBundleDecryptor = FileSystemHelper.CastParameter<IBundleDecryptor>(paramName, value);
|
||||
}
|
||||
else if (paramName == nameof(EFileSystemParameter.AssetbundleFallbackDecryptor))
|
||||
{
|
||||
AssetBundleFallbackDecryptor = FileSystemHelper.CastParameter<IBundleMemoryDecryptor>(paramName, value);
|
||||
}
|
||||
else if (paramName == nameof(EFileSystemParameter.ManifestDecryptor))
|
||||
{
|
||||
ManifestDecryptor = FileSystemHelper.CastParameter<IManifestDecryptor>(paramName, value);
|
||||
}
|
||||
else if (paramName == nameof(EFileSystemParameter.DownloadRetryPolicy))
|
||||
{
|
||||
DownloadRetryPolicy = FileSystemHelper.CastParameter<IDownloadRetryPolicy>(paramName, value);
|
||||
}
|
||||
else if (paramName == nameof(EFileSystemParameter.DownloadUrlPolicy))
|
||||
{
|
||||
DownloadUrlPolicy = FileSystemHelper.CastParameter<IDownloadUrlPolicy>(paramName, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException($"Unrecognized parameter name: '{paramName}'.", nameof(paramName));
|
||||
}
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public void OnCreate(string packageName, string packageRoot)
|
||||
{
|
||||
PackageName = packageName;
|
||||
|
||||
if (string.IsNullOrEmpty(packageRoot))
|
||||
_packageRoot = GetDefaultCachePackageRoot(packageName);
|
||||
else
|
||||
_packageRoot = packageRoot;
|
||||
|
||||
_cacheBundleFilesRoot = PathUtility.Combine(_packageRoot, SandboxFileSystemConsts.BundleFilesFolderName);
|
||||
_cacheManifestFilesRoot = PathUtility.Combine(_packageRoot, SandboxFileSystemConsts.ManifestFilesFolderName);
|
||||
_tempFilesRoot = PathUtility.Combine(_packageRoot, SandboxFileSystemConsts.TempFilesFolderName);
|
||||
|
||||
// 创建默认的下载后台接口
|
||||
if (DownloadBackend == null)
|
||||
DownloadBackend = new UnityWebRequestBackend(WebRequestCreator);
|
||||
|
||||
// 创建默认的下载重试策略
|
||||
if (DownloadRetryPolicy == null)
|
||||
DownloadRetryPolicy = new DefaultDownloadRetryPolicy();
|
||||
|
||||
// 创建默认的 URL 选择策略
|
||||
if (DownloadUrlPolicy == null)
|
||||
DownloadUrlPolicy = new DefaultDownloadUrlPolicy();
|
||||
|
||||
// 创建文件缓存系统
|
||||
{
|
||||
var cacheConfig = new SandboxBundleCache.Configuration(
|
||||
fileVerifyMaxConcurrency: FileVerifyMaxConcurrency,
|
||||
fileVerifyLevel: FileVerifyLevel,
|
||||
assetBundleDecryptor: AssetBundleDecryptor,
|
||||
rawBundleDecryptor: RawBundleDecryptor,
|
||||
assetBundleFallbackDecryptor: AssetBundleFallbackDecryptor);
|
||||
BundleCache = new SandboxBundleCache(PackageName, _cacheBundleFilesRoot, cacheConfig);
|
||||
}
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public void OnDestroy()
|
||||
{
|
||||
if (BundleCache != null)
|
||||
{
|
||||
BundleCache.Dispose();
|
||||
BundleCache = null;
|
||||
}
|
||||
|
||||
if (DownloadScheduler != null)
|
||||
{
|
||||
DownloadScheduler.AbortOperation();
|
||||
DownloadScheduler = null;
|
||||
}
|
||||
|
||||
if (DownloadBackend != null)
|
||||
{
|
||||
DownloadBackend.Dispose();
|
||||
DownloadBackend = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool CanAcceptBundle(PackageBundle bundle)
|
||||
{
|
||||
// 注意:保底加载!
|
||||
return true;
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public bool IsDownloadRequired(PackageBundle bundle)
|
||||
{
|
||||
return BundleCache.IsCached(bundle.BundleGuid) == false;
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public bool IsUnpackRequired(PackageBundle bundle)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
/// <inheritdoc />
|
||||
public bool IsImportRequired(PackageBundle bundle)
|
||||
{
|
||||
return BundleCache.IsCached(bundle.BundleGuid) == false;
|
||||
}
|
||||
|
||||
#region 内部方法
|
||||
/// <summary>
|
||||
/// 获取默认的缓存包裹根目录
|
||||
/// </summary>
|
||||
public string GetDefaultCachePackageRoot(string packageName)
|
||||
{
|
||||
string rootDirectory = YooAssetConfiguration.GetDefaultCacheRoot();
|
||||
return PathUtility.Combine(rootDirectory, packageName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取缓存清单文件的根目录
|
||||
/// </summary>
|
||||
public string GetCacheManifestFilesRoot()
|
||||
{
|
||||
return _cacheManifestFilesRoot;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取缓存包裹哈希文件路径
|
||||
/// </summary>
|
||||
public string GetCachePackageHashFilePath(string packageVersion)
|
||||
{
|
||||
string fileName = YooAssetConfiguration.GetPackageHashFileName(PackageName, packageVersion);
|
||||
return PathUtility.Combine(_cacheManifestFilesRoot, fileName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取缓存包裹清单文件路径
|
||||
/// </summary>
|
||||
public string GetCachePackageManifestFilePath(string packageVersion)
|
||||
{
|
||||
string fileName = YooAssetConfiguration.GetManifestBinaryFileName(PackageName, packageVersion);
|
||||
return PathUtility.Combine(_cacheManifestFilesRoot, fileName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取沙盒应用程序水印文件路径
|
||||
/// </summary>
|
||||
public string GetSandboxAppFootprintFilePath()
|
||||
{
|
||||
return PathUtility.Combine(_cacheManifestFilesRoot, SandboxFileSystemConsts.AppFootprintFileName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取临时文件路径
|
||||
/// </summary>
|
||||
public string GetTempFilePath(PackageBundle bundle)
|
||||
{
|
||||
if (_tempFilePathMapping.TryGetValue(bundle.BundleGuid, out string filePath) == false)
|
||||
{
|
||||
filePath = PathUtility.Combine(_tempFilesRoot, bundle.BundleGuid);
|
||||
_tempFilePathMapping.Add(bundle.BundleGuid, filePath);
|
||||
}
|
||||
return filePath;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除所有缓存的资源文件
|
||||
/// </summary>
|
||||
public void DeleteAllBundleFiles()
|
||||
{
|
||||
if (Directory.Exists(_cacheBundleFilesRoot))
|
||||
{
|
||||
Directory.Delete(_cacheBundleFilesRoot, true);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除所有缓存的清单文件
|
||||
/// </summary>
|
||||
public void DeleteAllManifestFiles()
|
||||
{
|
||||
if (Directory.Exists(_cacheManifestFilesRoot))
|
||||
{
|
||||
Directory.Delete(_cacheManifestFilesRoot, true);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除所有缓存的临时文件
|
||||
/// </summary>
|
||||
public void DeleteAllTempFiles()
|
||||
{
|
||||
if (Directory.Exists(_tempFilesRoot))
|
||||
{
|
||||
Directory.Delete(_tempFilesRoot, true);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4989ddcb6c99102429eeefffc3675ae5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,29 @@
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 沙盒文件系统常量定义
|
||||
/// </summary>
|
||||
internal static class SandboxFileSystemConsts
|
||||
{
|
||||
/// <summary>
|
||||
/// 记录应用程序版本的文件名称
|
||||
/// </summary>
|
||||
public const string AppFootprintFileName = "ApplicationFootprint.bytes";
|
||||
|
||||
/// <summary>
|
||||
/// 清单文件的文件夹名称
|
||||
/// </summary>
|
||||
public const string ManifestFilesFolderName = "ManifestFiles";
|
||||
|
||||
/// <summary>
|
||||
/// 资源文件的文件夹名称
|
||||
/// </summary>
|
||||
public const string BundleFilesFolderName = "BundleFiles";
|
||||
|
||||
/// <summary>
|
||||
/// 临时文件的文件夹名称
|
||||
/// </summary>
|
||||
public const string TempFilesFolderName = "TempFiles";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 610912866fe58794a904b43c2e24d84d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ecc61a05185e16f4082069f3d4976a16
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6f59bbfac9d9e6f4987496e16bae8b22
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,96 @@
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// WebGL 游戏平台文件系统初始化操作
|
||||
/// </summary>
|
||||
internal sealed class WGFSInitializeOperation : FSInitializeOperation
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
CheckPlatform,
|
||||
CheckParameter,
|
||||
InitializeBundleCache,
|
||||
Done,
|
||||
}
|
||||
|
||||
private readonly WebGameFileSystem _fileSystem;
|
||||
private BCInitializeOperation _initializeBundleCacheOp;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
internal WGFSInitializeOperation(WebGameFileSystem fileSystem)
|
||||
{
|
||||
_fileSystem = fileSystem;
|
||||
}
|
||||
protected override void InternalStart()
|
||||
{
|
||||
_steps = ESteps.CheckPlatform;
|
||||
}
|
||||
protected override void InternalUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
if (_steps == ESteps.CheckPlatform)
|
||||
{
|
||||
#if !UNITY_WEBGL
|
||||
_steps = ESteps.Done;
|
||||
SetError($"{nameof(WebGameFileSystem)} only supports the WebGL platform.");
|
||||
#else
|
||||
_steps = ESteps.CheckParameter;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (_steps == ESteps.CheckParameter)
|
||||
{
|
||||
if (_fileSystem.RemoteService == null)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError($"{nameof(IRemoteService)} is null.");
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查URL双斜杠
|
||||
// 注意:双斜杠会导致某小游戏平台加载文件失败,但网络请求又不返回失败!
|
||||
var testUrls = _fileSystem.RemoteService.GetRemoteUrls("test.bundle");
|
||||
foreach (var url in testUrls)
|
||||
{
|
||||
if (PathUtility.ContainsDoubleSlashes(url))
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError($"{nameof(IRemoteService)} returned URL contains double slashes: '{url}'.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
_steps = ESteps.InitializeBundleCache;
|
||||
}
|
||||
|
||||
if (_steps == ESteps.InitializeBundleCache)
|
||||
{
|
||||
if (_initializeBundleCacheOp == null)
|
||||
{
|
||||
_initializeBundleCacheOp = _fileSystem.BundleCache.InitializeAsync();
|
||||
_initializeBundleCacheOp.StartOperation();
|
||||
AddChildOperation(_initializeBundleCacheOp);
|
||||
}
|
||||
|
||||
_initializeBundleCacheOp.UpdateOperation();
|
||||
Progress = _initializeBundleCacheOp.Progress;
|
||||
if (_initializeBundleCacheOp.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_initializeBundleCacheOp.Status == EOperationStatus.Succeeded)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetResult();
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError(_initializeBundleCacheOp.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4c67db74d2670a84abf48b4b3dad3227
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,79 @@
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// WebGL 游戏平台加载资源包操作
|
||||
/// </summary>
|
||||
internal sealed class WGFSLoadPackageBundleOperation : FSLoadPackageBundleOperation
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
LoadBundle,
|
||||
Done,
|
||||
}
|
||||
|
||||
private readonly WebGameFileSystem _fileSystem;
|
||||
private readonly FSLoadPackageBundleOptions _options;
|
||||
private BCLoadBundleOperation _loadBundleOp;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
internal WGFSLoadPackageBundleOperation(WebGameFileSystem fileSystem, FSLoadPackageBundleOptions options)
|
||||
{
|
||||
_fileSystem = fileSystem;
|
||||
_options = options;
|
||||
}
|
||||
protected override void InternalStart()
|
||||
{
|
||||
_steps = ESteps.LoadBundle;
|
||||
}
|
||||
protected override void InternalUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
if (_steps == ESteps.LoadBundle)
|
||||
{
|
||||
if (_loadBundleOp == null)
|
||||
{
|
||||
_loadBundleOp = _fileSystem.BundleCache.LoadBundleAsync(_options.ConvertTo());
|
||||
_loadBundleOp.StartOperation();
|
||||
AddChildOperation(_loadBundleOp);
|
||||
}
|
||||
|
||||
_loadBundleOp.UpdateOperation();
|
||||
Progress = _loadBundleOp.Progress;
|
||||
if (_loadBundleOp.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_loadBundleOp.Status == EOperationStatus.Succeeded)
|
||||
{
|
||||
if (_loadBundleOp.BundleHandle == null)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError("Fatal error: loaded bundle handle is null.");
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetResult();
|
||||
BundleHandle = _loadBundleOp.BundleHandle;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError(_loadBundleOp.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
protected override void InternalWaitForCompletion()
|
||||
{
|
||||
if (_steps != ESteps.Done)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
SetError("WebGL platform does not support synchronous loading.");
|
||||
YooLogger.LogError(Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user