refactor : 重构代码

This commit is contained in:
何冠峰
2026-01-26 15:03:33 +08:00
parent 781e5950b1
commit 48a121f961
483 changed files with 2062 additions and 2971 deletions

View File

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

View File

@@ -0,0 +1,40 @@
using System;
using System.IO;
using System.Collections.Generic;
namespace YooAsset
{
/// <summary>
/// 内置资源清单目录
/// </summary>
[Serializable]
internal class BuiltinFileCatalog
{
[Serializable]
public class FileWrapper
{
public string BundleGUID;
public string FileName;
}
/// <summary>
/// 文件版本
/// </summary>
public string FileVersion;
/// <summary>
/// 包裹名称
/// </summary>
public string PackageName;
/// <summary>
/// 包裹版本
/// </summary>
public string PackageVersion;
/// <summary>
/// 文件列表
/// </summary>
public List<FileWrapper> Wrappers = new List<FileWrapper>();
}
}

View File

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

View File

@@ -0,0 +1,450 @@
using System;
using System.IO;
using System.Collections.Generic;
using UnityEngine;
namespace YooAsset
{
/// <summary>
/// 内置文件系统
/// </summary>
internal class BuiltinFileSystem : IFileSystem
{
public class FileWrapper
{
public string FileName { private set; get; }
public FileWrapper(string fileName)
{
FileName = fileName;
}
}
protected readonly Dictionary<string, FileWrapper> _wrappers = new Dictionary<string, FileWrapper>(10000);
protected readonly Dictionary<string, string> _builtinFilePathMapping = new Dictionary<string, string>(10000);
protected IFileSystem _unpackFileSystem;
protected string _packageRoot;
/// <summary>
/// 下载后台接口
/// </summary>
public IDownloadBackend DownloadBackend { private set; get; }
/// <summary>
/// 包裹名称
/// </summary>
public string PackageName { private set; get; }
/// <summary>
/// 文件根目录
/// </summary>
public string FileRoot
{
get
{
return _packageRoot;
}
}
/// <summary>
/// 文件数量
/// </summary>
public int FileCount
{
get
{
return _wrappers.Count;
}
}
#region
/// <summary>
/// 自定义参数UnityWebRequest 创建委托
/// </summary>
public UnityWebRequestCreator WebRequestCreator { private set; get; }
/// <summary>
/// 自定义参数:覆盖安装缓存清理模式
/// </summary>
public EOverwriteInstallClearMode InstallClearMode { private set; get; } = EOverwriteInstallClearMode.ClearAllManifestFiles;
/// <summary>
/// 自定义参数:初始化的时候缓存文件校验级别
/// </summary>
public EFileVerifyLevel FileVerifyLevel { private set; get; } = EFileVerifyLevel.Middle;
/// <summary>
/// 自定义参数:初始化的时候缓存文件校验最大并发数
/// </summary>
public int FileVerifyMaxConcurrency { private set; get; } = 32;
/// <summary>
/// 自定义参数:数据文件追加文件格式
/// </summary>
public bool AppendFileExtension { private set; get; } = false;
/// <summary>
/// 自定义参数禁用Catalog目录查询文件
/// </summary>
public bool DisableCatalogFile { private set; get; } = false;
/// <summary>
/// 自定义参数:拷贝内置清单
/// </summary>
public bool CopyBuildinPackageManifest { private set; get; } = false;
/// <summary>
/// 自定义参数:拷贝内置清单的目标目录
/// 注意:该参数为空的时候,会获取默认的沙盒目录!
/// </summary>
public string CopyBuildinPackageManifestDestRoot { private set; get; }
/// <summary>
/// 自定义参数:解压文件系统的根目录
/// </summary>
public string UnpackFileSystemRoot { private set; get; }
/// <summary>
/// 自定义参数:加载 AssetBundle 的工厂委托
/// </summary>
public LoadAssetBundleOperationFactory LoadAssetBundleFactory { private set; get; }
/// <summary>
/// 自定义参数:加载 RawBundle 的工厂委托
/// </summary>
public LoadRawBundleOperationFactory LoadRawBundleFactory { private set; get; }
/// <summary>
/// 自定义参数:资源清单服务类
/// </summary>
public IManifestRestoreServices ManifestRestoreServices { private set; get; }
/// <summary>
/// 自定义参数:拷贝内置文件接口的实例类
/// </summary>
public ILocalFileCopyServices CopyLocalFileServices { private set; get; }
#endregion
public BuiltinFileSystem()
{
}
public virtual FSInitializeOperation InitializeAsync()
{
var operation = new DBFSInitializeOperation(this);
return operation;
}
public virtual FSRequestVersionOperation RequestVersionAsync(RequestVersionOptions options)
{
var operation = new BFSRequestVersionOperation(this);
return operation;
}
public virtual FSLoadManifestOperation LoadManifestAsync(LoadManifestOptions options)
{
var operation = new BFSLoadManifestOperation(this, options.PackageVersion);
return operation;
}
public virtual FSClearCacheOperation ClearCacheAsync(ClearCacheOptions options)
{
return _unpackFileSystem.ClearCacheAsync(options);
}
public virtual FSDownloadFileOperation DownloadFileAsync(DownloadFileOptions options)
{
// 注意:业务层的解压器会依赖该方法
options.ImportFilePath = GetBuiltinFileLoadPath(options.Bundle);
return _unpackFileSystem.DownloadFileAsync(options);
}
public virtual FSLoadBundleOperation LoadBundleAsync(LoadBundleOptions options)
{
PackageBundle bundle = options.Bundle;
if (IsUnpackBundleFile(bundle))
{
return _unpackFileSystem.LoadBundleAsync(options);
}
if (bundle.BundleType == (int)EBundleType.AssetBundle)
{
var operation = new BFSLoadAssetBundleOperation(this, bundle);
return operation;
}
else if (bundle.BundleType == (int)EBundleType.RawBundle)
{
var operation = new BFSLoadRawBundleOperation(this, bundle);
return operation;
}
#if TUANJIE_1_7_OR_NEWER
else if (bundle.BundleType == (int)EBundleType.InstantBundle)
{
var operation = new BFSLoadInstantBundleOperation(this, bundle);
return operation;
}
#endif
else
{
string error = $"{nameof(BuiltinFileSystem)} not support load bundle type : {bundle.BundleType}";
var operation = new FSLoadBundleCompleteOperation(error);
return operation;
}
}
public virtual void SetParameter(string name, object value)
{
if (name == FileSystemParametersDefine.DOWNLOAD_BACKEND)
{
DownloadBackend = (IDownloadBackend)value;
}
else if (name == FileSystemParametersDefine.UNITY_WEB_REQUEST_CREATOR)
{
WebRequestCreator = (UnityWebRequestCreator)value;
}
else if (name == FileSystemParametersDefine.INSTALL_CLEAR_MODE)
{
InstallClearMode = (EOverwriteInstallClearMode)value;
}
else if (name == FileSystemParametersDefine.FILE_VERIFY_LEVEL)
{
FileVerifyLevel = (EFileVerifyLevel)value;
}
else if (name == FileSystemParametersDefine.FILE_VERIFY_MAX_CONCURRENCY)
{
int convertValue = Convert.ToInt32(value);
FileVerifyMaxConcurrency = Mathf.Clamp(convertValue, 1, int.MaxValue);
}
else if (name == FileSystemParametersDefine.APPEND_FILE_EXTENSION)
{
AppendFileExtension = Convert.ToBoolean(value);
}
else if (name == FileSystemParametersDefine.DISABLE_CATALOG_FILE)
{
DisableCatalogFile = Convert.ToBoolean(value);
}
else if (name == FileSystemParametersDefine.COPY_BUILDIN_PACKAGE_MANIFEST)
{
CopyBuildinPackageManifest = Convert.ToBoolean(value);
}
else if (name == FileSystemParametersDefine.COPY_BUILDIN_PACKAGE_MANIFEST_DEST_ROOT)
{
CopyBuildinPackageManifestDestRoot = (string)value;
}
else if (name == FileSystemParametersDefine.UNPACK_FILE_SYSTEM_ROOT)
{
UnpackFileSystemRoot = (string)value;
}
else if (name == FileSystemParametersDefine.LOAD_ASSETBUNDLE_OPERATION_FACTORY)
{
LoadAssetBundleFactory = (LoadAssetBundleOperationFactory)value;
}
else if (name == FileSystemParametersDefine.LOAD_RAWBUNDLE_OPERATION_FACTORY)
{
LoadRawBundleFactory = (LoadRawBundleOperationFactory)value;
}
else if (name == FileSystemParametersDefine.MANIFEST_RESTORE_SERVICES)
{
ManifestRestoreServices = (IManifestRestoreServices)value;
}
else if (name == FileSystemParametersDefine.COPY_LOCAL_FILE_SERVICES)
{
CopyLocalFileServices = (ILocalFileCopyServices)value;
}
else
{
YooLogger.Warning($"Invalid parameter : {name}");
}
}
public virtual void OnCreate(string packageName, string packageRoot)
{
PackageName = packageName;
if (string.IsNullOrEmpty(packageRoot))
_packageRoot = GetDefaultBuiltinPackageRoot(packageName);
else
_packageRoot = packageRoot;
// 创建默认的下载后台接口
if (DownloadBackend == null)
DownloadBackend = new UnityWebRequestBackend(WebRequestCreator);
// 创建默认的 AssetBundle 加载工厂
if (LoadAssetBundleFactory == null)
LoadAssetBundleFactory = DefaultLoadAssetBundleOperationFactory;
// 创建默认的 RawBundle 加载工厂
if (LoadRawBundleFactory == null)
LoadRawBundleFactory = DefaultLoadRawBundleOperationFactory;
// 创建解压文件系统
var remoteServices = new UnpackRemoteService(_packageRoot);
_unpackFileSystem = new UnpackFileSystem();
_unpackFileSystem.SetParameter(FileSystemParametersDefine.REMOTE_SERVICES, remoteServices);
_unpackFileSystem.SetParameter(FileSystemParametersDefine.DOWNLOAD_BACKEND, DownloadBackend);
_unpackFileSystem.SetParameter(FileSystemParametersDefine.UNITY_WEB_REQUEST_CREATOR, WebRequestCreator);
_unpackFileSystem.SetParameter(FileSystemParametersDefine.INSTALL_CLEAR_MODE, InstallClearMode);
_unpackFileSystem.SetParameter(FileSystemParametersDefine.FILE_VERIFY_LEVEL, FileVerifyLevel);
_unpackFileSystem.SetParameter(FileSystemParametersDefine.FILE_VERIFY_MAX_CONCURRENCY, FileVerifyMaxConcurrency);
_unpackFileSystem.SetParameter(FileSystemParametersDefine.APPEND_FILE_EXTENSION, AppendFileExtension);
_unpackFileSystem.SetParameter(FileSystemParametersDefine.LOAD_ASSETBUNDLE_OPERATION_FACTORY, LoadAssetBundleFactory);
_unpackFileSystem.SetParameter(FileSystemParametersDefine.LOAD_RAWBUNDLE_OPERATION_FACTORY, LoadRawBundleFactory);
_unpackFileSystem.SetParameter(FileSystemParametersDefine.COPY_LOCAL_FILE_SERVICES, CopyLocalFileServices);
_unpackFileSystem.OnCreate(packageName, UnpackFileSystemRoot);
}
public virtual void OnDestroy()
{
if (_unpackFileSystem != null)
{
_unpackFileSystem.OnDestroy();
_unpackFileSystem = null;
}
if (DownloadBackend != null)
{
DownloadBackend.Dispose();
DownloadBackend = null;
}
}
public virtual bool Belong(PackageBundle bundle)
{
if (DisableCatalogFile)
return true;
return _wrappers.ContainsKey(bundle.BundleGUID);
}
public virtual bool Exists(PackageBundle bundle)
{
if (DisableCatalogFile)
return true;
return _wrappers.ContainsKey(bundle.BundleGUID);
}
public virtual bool NeedDownload(PackageBundle bundle)
{
return false;
}
public virtual bool NeedUnpack(PackageBundle bundle)
{
if (IsUnpackBundleFile(bundle))
{
return _unpackFileSystem.Exists(bundle) == false;
}
else
{
return false;
}
}
public virtual bool NeedImport(PackageBundle bundle)
{
return false;
}
public virtual string GetBundleFilePath(PackageBundle bundle)
{
if (IsUnpackBundleFile(bundle))
{
return _unpackFileSystem.GetBundleFilePath(bundle);
}
return GetBuiltinFileLoadPath(bundle);
}
/// <summary>
/// 是否属于解压资源包文件
/// </summary>
protected virtual bool IsUnpackBundleFile(PackageBundle bundle)
{
if (Belong(bundle) == false)
return false;
#if UNITY_ANDROID || UNITY_OPENHARMONY
if (bundle.Encrypted)
return true;
if (bundle.BundleType == (int)EBundleType.RawBundle)
return true;
return false;
#else
return false;
#endif
}
#region
private LoadAssetBundleOperation DefaultLoadAssetBundleOperationFactory(bool bundleEncrypted, LoadAssetBundleOptions options)
{
if (bundleEncrypted)
{
string error = $"{nameof(DefaultLoadAssetBundleOperation)} cannot load encrypted bundle. Please provide a custom {nameof(LoadAssetBundleOperationFactory)}.";
return new LoadAssetBundleCompleteOperation(error, options);
}
else
{
return new DefaultLoadAssetBundleOperation(options);
}
}
private LoadRawBundleOperation DefaultLoadRawBundleOperationFactory(bool bundleEncrypted, LoadRawBundleOptions options)
{
if (bundleEncrypted)
{
string error = $"{nameof(DefaultLoadRawBundleOperation)} cannot load encrypted bundle. Please provide a custom {nameof(LoadRawBundleOperationFactory)}.";
return new LoadRawBundleCompleteOperation(error, options);
}
else
{
return new DefaultLoadRawBundleOperation(options);
}
}
protected string GetDefaultBuiltinPackageRoot(string packageName)
{
string rootDirectory = YooAssetSettingsData.GetYooDefaultBuildinRoot();
return PathUtility.Combine(rootDirectory, packageName);
}
public string GetBuiltinFileLoadPath(PackageBundle bundle)
{
if (_builtinFilePathMapping.TryGetValue(bundle.BundleGUID, out string filePath) == false)
{
filePath = PathUtility.Combine(_packageRoot, bundle.FileName);
_builtinFilePathMapping.Add(bundle.BundleGUID, filePath);
}
return filePath;
}
public string GetBuiltinPackageVersionFilePath()
{
string fileName = YooAssetSettingsData.GetPackageVersionFileName(PackageName);
return PathUtility.Combine(_packageRoot, fileName);
}
public string GetBuiltinPackageHashFilePath(string packageVersion)
{
string fileName = YooAssetSettingsData.GetPackageHashFileName(PackageName, packageVersion);
return PathUtility.Combine(_packageRoot, fileName);
}
public string GetBuiltinPackageManifestFilePath(string packageVersion)
{
string fileName = YooAssetSettingsData.GetManifestBinaryFileName(PackageName, packageVersion);
return PathUtility.Combine(_packageRoot, fileName);
}
public string GetCatalogBinaryFileLoadPath()
{
return PathUtility.Combine(_packageRoot, BuiltinFileSystemConstants.BuiltinCatalogBinaryFileName);
}
/// <summary>
/// 记录文件信息
/// </summary>
public bool RecordCatalogFile(string bundleGUID, FileWrapper wrapper)
{
if (_wrappers.ContainsKey(bundleGUID))
{
YooLogger.Error($"{nameof(BuiltinFileSystem)} has element : {bundleGUID}");
return false;
}
_wrappers.Add(bundleGUID, wrapper);
return true;
}
/// <summary>
/// 初始化解压文件系统
/// </summary>
public FSInitializeOperation InitializeUnpackFileSystem()
{
return _unpackFileSystem.InitializeAsync();
}
#endregion
}
}

View File

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

View File

@@ -0,0 +1,16 @@

namespace YooAsset
{
internal class BuiltinFileSystemConstants
{
/// <summary>
/// 内置清单JSON文件名称
/// </summary>
public const string BuiltinCatalogJsonFileName = "BuiltinCatalog.json";
/// <summary>
/// 内置清单二进制文件名称
/// </summary>
public const string BuiltinCatalogBinaryFileName = "BuiltinCatalog.bytes";
}
}

View File

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

View File

@@ -0,0 +1,21 @@

namespace YooAsset
{
internal class CatalogFileConstants
{
/// <summary>
/// 文件极限大小100MB
/// </summary>
public const int FileMaxSize = 104857600;
/// <summary>
/// 文件头标记
/// </summary>
public const uint FileSign = 0x133C5EE;
/// <summary>
/// 文件格式版本
/// </summary>
public const string FileVersion = "1.0.0";
}
}

View File

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

View File

@@ -0,0 +1,246 @@
using System;
using System.IO;
using System.Collections.Generic;
using UnityEngine;
namespace YooAsset
{
internal static class CatalogFileTools
{
#if UNITY_EDITOR
/// <summary>
/// 生成包裹的内置资源目录文件
/// 说明:根据指定目录下的文件生成清单文件。
/// </summary>
public static bool CreateFile(IManifestRestoreServices services, string packageName, string packageDirectory)
{
// 获取资源清单版本
string packageVersion;
{
string versionFileName = YooAssetSettingsData.GetPackageVersionFileName(packageName);
string versionFilePath = $"{packageDirectory}/{versionFileName}";
if (File.Exists(versionFilePath) == false)
{
Debug.LogError($"Can not found package version file : {versionFilePath}");
return false;
}
packageVersion = FileUtility.ReadAllText(versionFilePath);
}
// 加载资源清单文件
PackageManifest packageManifest;
{
string manifestFileName = YooAssetSettingsData.GetManifestBinaryFileName(packageName, packageVersion);
string manifestFilePath = $"{packageDirectory}/{manifestFileName}";
if (File.Exists(manifestFilePath) == false)
{
Debug.LogError($"Can not found package manifest file : {manifestFilePath}");
return false;
}
var binaryData = FileUtility.ReadAllBytes(manifestFilePath);
packageManifest = PackageManifestTools.DeserializeFromBinary(binaryData, services);
}
// 获取文件名映射关系
Dictionary<string, string> fileMapping = new Dictionary<string, string>();
{
foreach (var packageBundle in packageManifest.BundleList)
{
fileMapping.Add(packageBundle.FileName, packageBundle.BundleGUID);
}
}
// 创建内置清单实例
var buildinFileCatalog = new BuiltinFileCatalog();
buildinFileCatalog.FileVersion = CatalogFileConstants.FileVersion;
buildinFileCatalog.PackageName = packageName;
buildinFileCatalog.PackageVersion = packageVersion;
// 创建白名单查询集合
HashSet<string> whiteFileList = new HashSet<string>
{
"link.xml",
"buildlogtep.json",
BuiltinFileSystemConstants.BuiltinCatalogJsonFileName,
BuiltinFileSystemConstants.BuiltinCatalogBinaryFileName
};
string packageVersionFileName = YooAssetSettingsData.GetPackageVersionFileName(packageName);
string packageHashFileName = YooAssetSettingsData.GetPackageHashFileName(packageName, packageVersion);
string manifestBinaryFIleName = YooAssetSettingsData.GetManifestBinaryFileName(packageName, packageVersion);
string manifestJsonFIleName = YooAssetSettingsData.GetManifestJsonFileName(packageName, packageVersion);
string reportFileName = YooAssetSettingsData.GetBuildReportFileName(packageName, packageVersion);
whiteFileList.Add(packageVersionFileName);
whiteFileList.Add(packageHashFileName);
whiteFileList.Add(manifestBinaryFIleName);
whiteFileList.Add(manifestJsonFIleName);
whiteFileList.Add(reportFileName);
// 记录所有内置资源文件
DirectoryInfo rootDirectory = new DirectoryInfo(packageDirectory);
FileInfo[] fileInfos = rootDirectory.GetFiles();
foreach (var fileInfo in fileInfos)
{
if (fileInfo.Extension == ".meta")
continue;
if (whiteFileList.Contains(fileInfo.Name))
continue;
string fileName = fileInfo.Name;
if (fileMapping.TryGetValue(fileName, out string bundleGUID))
{
var wrapper = new BuiltinFileCatalog.FileWrapper();
wrapper.BundleGUID = bundleGUID;
wrapper.FileName = fileName;
buildinFileCatalog.Wrappers.Add(wrapper);
}
else
{
Debug.LogWarning($"Failed mapping file : {fileName}");
}
}
// 创建输出文件
string jsonFilePath = $"{packageDirectory}/{BuiltinFileSystemConstants.BuiltinCatalogJsonFileName}";
if (File.Exists(jsonFilePath))
File.Delete(jsonFilePath);
SerializeToJson(jsonFilePath, buildinFileCatalog);
// 创建输出文件
string binaryFilePath = $"{packageDirectory}/{BuiltinFileSystemConstants.BuiltinCatalogBinaryFileName}";
if (File.Exists(binaryFilePath))
File.Delete(binaryFilePath);
SerializeToBinary(binaryFilePath, buildinFileCatalog);
UnityEditor.AssetDatabase.Refresh();
Debug.Log($"Succeed to save catalog file : {binaryFilePath}");
return true;
}
/// <summary>
/// 生成空的包裹内置资源目录文件
/// </summary>
public static bool CreateEmptyFile(string packageName, string packageVersion, string outputPath)
{
// 创建内置清单实例
var buildinFileCatalog = new BuiltinFileCatalog();
buildinFileCatalog.FileVersion = CatalogFileConstants.FileVersion;
buildinFileCatalog.PackageName = packageName;
buildinFileCatalog.PackageVersion = packageVersion;
// 创建输出文件
string jsonFilePath = $"{outputPath}/{BuiltinFileSystemConstants.BuiltinCatalogJsonFileName}";
if (File.Exists(jsonFilePath))
File.Delete(jsonFilePath);
SerializeToJson(jsonFilePath, buildinFileCatalog);
// 创建输出文件
string binaryFilePath = $"{outputPath}/{BuiltinFileSystemConstants.BuiltinCatalogBinaryFileName}";
if (File.Exists(binaryFilePath))
File.Delete(binaryFilePath);
SerializeToBinary(binaryFilePath, buildinFileCatalog);
UnityEditor.AssetDatabase.Refresh();
Debug.Log($"Succeed to save catalog file : {binaryFilePath}");
return true;
}
#endif
/// <summary>
/// 序列化JSON文件
/// </summary>
public static void SerializeToJson(string savePath, BuiltinFileCatalog catalog)
{
string json = JsonUtility.ToJson(catalog, true);
FileUtility.WriteAllText(savePath, json);
}
/// <summary>
/// 反序列化JSON文件
/// </summary>
public static BuiltinFileCatalog DeserializeFromJson(string jsonContent)
{
return JsonUtility.FromJson<BuiltinFileCatalog>(jsonContent);
}
/// <summary>
/// 序列化(二进制文件)
/// </summary>
public static void SerializeToBinary(string savePath, BuiltinFileCatalog catalog)
{
using (FileStream fs = new FileStream(savePath, FileMode.Create))
{
// 创建缓存器
BufferWriter buffer = new BufferWriter(CatalogFileConstants.FileMaxSize);
// 写入文件标记
buffer.WriteUInt32(CatalogFileConstants.FileSign);
// 写入文件版本
buffer.WriteUTF8(CatalogFileConstants.FileVersion);
// 写入文件头信息
buffer.WriteUTF8(catalog.PackageName);
buffer.WriteUTF8(catalog.PackageVersion);
// 写入资源包列表
buffer.WriteInt32(catalog.Wrappers.Count);
for (int i = 0; i < catalog.Wrappers.Count; i++)
{
var fileWrapper = catalog.Wrappers[i];
buffer.WriteUTF8(fileWrapper.BundleGUID);
buffer.WriteUTF8(fileWrapper.FileName);
}
// 写入文件流
buffer.WriteToStream(fs);
fs.Flush();
}
}
/// <summary>
/// 反序列化(二进制文件)
/// </summary>
public static BuiltinFileCatalog DeserializeFromBinary(byte[] binaryData)
{
if (binaryData == null || binaryData.Length == 0)
throw new Exception("Catalog file data is null or empty.");
// 创建缓存器
BufferReader buffer = new BufferReader(binaryData);
// 读取文件标记
uint fileSign = buffer.ReadUInt32();
if (fileSign != CatalogFileConstants.FileSign)
throw new Exception("Invalid catalog file.");
// 读取文件版本
string fileVersion = buffer.ReadUTF8();
if (fileVersion != CatalogFileConstants.FileVersion)
throw new Exception($"The catalog file version are not compatible : {fileVersion} != {CatalogFileConstants.FileVersion}");
BuiltinFileCatalog catalog = new BuiltinFileCatalog();
{
// 读取文件头信息
catalog.FileVersion = fileVersion;
catalog.PackageName = buffer.ReadUTF8();
catalog.PackageVersion = buffer.ReadUTF8();
// 读取资源包列表
int fileCount = buffer.ReadInt32();
catalog.Wrappers = new List<BuiltinFileCatalog.FileWrapper>(fileCount);
for (int i = 0; i < fileCount; i++)
{
var fileWrapper = new BuiltinFileCatalog.FileWrapper();
fileWrapper.BundleGUID = buffer.ReadUTF8();
fileWrapper.FileName = buffer.ReadUTF8();
catalog.Wrappers.Add(fileWrapper);
}
}
return catalog;
}
}
}

View File

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

View File

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

View File

@@ -0,0 +1,238 @@
using System;
using System.IO;
namespace YooAsset
{
internal class DBFSInitializeOperation : FSInitializeOperation
{
private enum ESteps
{
None,
LoadBuildinPackageVersion,
CopyBuildinPackageHash,
CopyBuildinPackageManifest,
InitUnpackFileSystem,
LoadCatalogFile,
Done,
}
private readonly BuiltinFileSystem _fileSystem;
private RequestBuiltinPackageVersionOperation _requestBuildinPackageVersionOp;
private CopyBuiltinFileOperation _copyBuildinHashFileOp;
private CopyBuiltinFileOperation _copyBuildinManifestFileOp;
private FSInitializeOperation _initUnpackFIleSystemOp;
private LoadBuiltinCatalogFileOperation _loadBuildinCatalogFileOp;
private ESteps _steps = ESteps.None;
internal DBFSInitializeOperation(BuiltinFileSystem fileSystem)
{
_fileSystem = fileSystem;
}
internal override void InternalStart()
{
#if UNITY_WEBGL
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"{nameof(DefaultBuildinFileSystem)} is not support WEBGL platform.";
#else
if (_fileSystem.CopyBuildinPackageManifest)
_steps = ESteps.LoadBuildinPackageVersion;
else
_steps = ESteps.InitUnpackFileSystem;
#endif
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.LoadBuildinPackageVersion)
{
if (_requestBuildinPackageVersionOp == null)
{
_requestBuildinPackageVersionOp = new RequestBuiltinPackageVersionOperation(_fileSystem);
_requestBuildinPackageVersionOp.StartOperation();
AddChildOperation(_requestBuildinPackageVersionOp);
}
_requestBuildinPackageVersionOp.UpdateOperation();
if (_requestBuildinPackageVersionOp.IsDone == false)
return;
if (_requestBuildinPackageVersionOp.Status == EOperationStatus.Succeeded)
{
_steps = ESteps.CopyBuildinPackageHash;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _requestBuildinPackageVersionOp.Error;
}
}
if (_steps == ESteps.CopyBuildinPackageHash)
{
if (_copyBuildinHashFileOp == null)
{
string packageVersion = _requestBuildinPackageVersionOp.PackageVersion;
string destFilePath = GetCopyPackageHashDestPath(packageVersion);
string sourceFilePath = _fileSystem.GetBuiltinPackageHashFilePath(packageVersion);
_copyBuildinHashFileOp = new CopyBuiltinFileOperation(_fileSystem, sourceFilePath, destFilePath);
_copyBuildinHashFileOp.StartOperation();
AddChildOperation(_copyBuildinHashFileOp);
}
_copyBuildinHashFileOp.UpdateOperation();
if (_copyBuildinHashFileOp.IsDone == false)
return;
if (_copyBuildinHashFileOp.Status == EOperationStatus.Succeeded)
{
_steps = ESteps.CopyBuildinPackageManifest;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _copyBuildinHashFileOp.Error;
}
}
if (_steps == ESteps.CopyBuildinPackageManifest)
{
if (_copyBuildinManifestFileOp == null)
{
string packageVersion = _requestBuildinPackageVersionOp.PackageVersion;
string destFilePath = GetCopyPackageManifestDestPath(packageVersion);
string sourceFilePath = _fileSystem.GetBuiltinPackageManifestFilePath(packageVersion);
_copyBuildinManifestFileOp = new CopyBuiltinFileOperation(_fileSystem, sourceFilePath, destFilePath);
_copyBuildinManifestFileOp.StartOperation();
AddChildOperation(_copyBuildinManifestFileOp);
}
_copyBuildinManifestFileOp.UpdateOperation();
if (_copyBuildinManifestFileOp.IsDone == false)
return;
if (_copyBuildinManifestFileOp.Status == EOperationStatus.Succeeded)
{
_steps = ESteps.InitUnpackFileSystem;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _copyBuildinManifestFileOp.Error;
}
}
if (_steps == ESteps.InitUnpackFileSystem)
{
if (_initUnpackFIleSystemOp == null)
{
_initUnpackFIleSystemOp = _fileSystem.InitializeUnpackFileSystem();
_initUnpackFIleSystemOp.StartOperation();
AddChildOperation(_initUnpackFIleSystemOp);
}
_initUnpackFIleSystemOp.UpdateOperation();
Progress = _initUnpackFIleSystemOp.Progress;
if (_initUnpackFIleSystemOp.IsDone == false)
return;
if (_initUnpackFIleSystemOp.Status == EOperationStatus.Succeeded)
{
if (_fileSystem.DisableCatalogFile)
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
}
else
{
_steps = ESteps.LoadCatalogFile;
}
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _initUnpackFIleSystemOp.Error;
}
}
if (_steps == ESteps.LoadCatalogFile)
{
if (_loadBuildinCatalogFileOp == null)
{
_loadBuildinCatalogFileOp = new LoadBuiltinCatalogFileOperation(_fileSystem);
_loadBuildinCatalogFileOp.StartOperation();
AddChildOperation(_loadBuildinCatalogFileOp);
}
_loadBuildinCatalogFileOp.UpdateOperation();
if (_loadBuildinCatalogFileOp.IsDone == false)
return;
if (_loadBuildinCatalogFileOp.Status == EOperationStatus.Succeeded)
{
var catalog = _loadBuildinCatalogFileOp.Catalog;
if (catalog == null)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = "Fatal error : catalog is null.";
return;
}
if (catalog.PackageName != _fileSystem.PackageName)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Catalog file package name {catalog.PackageName} cannot match the file system package name {_fileSystem.PackageName}";
return;
}
foreach (var wrapper in catalog.Wrappers)
{
var fileWrapper = new BuiltinFileSystem.FileWrapper(wrapper.FileName);
_fileSystem.RecordCatalogFile(wrapper.BundleGUID, fileWrapper);
}
YooLogger.Log($"Package '{_fileSystem.PackageName}' buildin catalog files count : {catalog.Wrappers.Count}");
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _loadBuildinCatalogFileOp.Error;
}
}
}
private string GetCopyManifestFileRoot()
{
string destRoot = _fileSystem.CopyBuildinPackageManifestDestRoot;
if (string.IsNullOrEmpty(destRoot))
{
string defaultCacheRoot = YooAssetSettingsData.GetYooDefaultCacheRoot();
destRoot = PathUtility.Combine(defaultCacheRoot, _fileSystem.PackageName, DefaultCacheFileSystemDefine.ManifestFilesFolderName);
}
return destRoot;
}
private string GetCopyPackageHashDestPath(string packageVersion)
{
string fileRoot = GetCopyManifestFileRoot();
string fileName = YooAssetSettingsData.GetPackageHashFileName(_fileSystem.PackageName, packageVersion);
return PathUtility.Combine(fileRoot, fileName);
}
private string GetCopyPackageManifestDestPath(string packageVersion)
{
string fileRoot = GetCopyManifestFileRoot();
string fileName = YooAssetSettingsData.GetManifestBinaryFileName(_fileSystem.PackageName, packageVersion);
return PathUtility.Combine(fileRoot, fileName);
}
}
}

View File

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

View File

@@ -0,0 +1,311 @@
using System.IO;
using UnityEngine;
namespace YooAsset
{
/// <summary>
/// 加载 AssetBundle 文件
/// </summary>
internal class BFSLoadAssetBundleOperation : FSLoadBundleOperation
{
private enum ESteps
{
None,
LoadBuiltinAssetBundle,
CheckResult,
Done,
}
private readonly BuiltinFileSystem _fileSystem;
private readonly PackageBundle _bundle;
private LoadAssetBundleOperation _loadAssetBundleOp;
private ESteps _steps = ESteps.None;
internal BFSLoadAssetBundleOperation(BuiltinFileSystem fileSystem, PackageBundle bundle)
{
_fileSystem = fileSystem;
_bundle = bundle;
}
internal override void InternalStart()
{
DownloadProgress = 1f;
DownloadedBytes = _bundle.FileSize;
_steps = ESteps.LoadBuiltinAssetBundle;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.LoadBuiltinAssetBundle)
{
var options = new LoadAssetBundleOptions();
options.FileLoadPath = _fileSystem.GetBuiltinFileLoadPath(_bundle);
options.Bundle = _bundle;
_loadAssetBundleOp = _fileSystem.LoadAssetBundleFactory.Invoke(_bundle.Encrypted, options);
_loadAssetBundleOp.StartOperation();
AddChildOperation(_loadAssetBundleOp);
_steps = ESteps.CheckResult;
}
if (_steps == ESteps.CheckResult)
{
if (IsWaitForCompletion)
_loadAssetBundleOp.WaitForCompletion();
_loadAssetBundleOp.UpdateOperation();
if (_loadAssetBundleOp.IsDone == false)
return;
if (_loadAssetBundleOp.Status == EOperationStatus.Succeeded)
{
if (_loadAssetBundleOp.Result == null)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = "Loaded builtin asset bundle is null.";
YooLogger.Error(Error);
}
else
{
_steps = ESteps.Done;
Result = new AssetBundleResult(_fileSystem, _bundle, _loadAssetBundleOp.Result, _loadAssetBundleOp.ManagedStream);
Status = EOperationStatus.Succeeded;
}
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _loadAssetBundleOp.Error;
YooLogger.Error(Error);
}
}
}
internal override void InternalWaitForCompletion()
{
ExecuteBatch();
}
}
/// <summary>
/// 加载 RawBundle 文件
/// </summary>
internal class BFSLoadRawBundleOperation : FSLoadBundleOperation
{
private enum ESteps
{
None,
LoadBuiltinRawBundle,
CheckResult,
Done,
}
private readonly BuiltinFileSystem _fileSystem;
private readonly PackageBundle _bundle;
private LoadRawBundleOperation _loadRawBundleOp;
private ESteps _steps = ESteps.None;
internal BFSLoadRawBundleOperation(BuiltinFileSystem fileSystem, PackageBundle bundle)
{
_fileSystem = fileSystem;
_bundle = bundle;
}
internal override void InternalStart()
{
DownloadProgress = 1f;
DownloadedBytes = _bundle.FileSize;
_steps = ESteps.LoadBuiltinRawBundle;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.LoadBuiltinRawBundle)
{
var options = new LoadRawBundleOptions();
options.FileLoadPath = _fileSystem.GetBuiltinFileLoadPath(_bundle);
options.Bundle = _bundle;
_loadRawBundleOp = _fileSystem.LoadRawBundleFactory.Invoke(_bundle.Encrypted, options);
_loadRawBundleOp.StartOperation();
AddChildOperation(_loadRawBundleOp);
_steps = ESteps.CheckResult;
}
if (_steps == ESteps.CheckResult)
{
if (IsWaitForCompletion)
_loadRawBundleOp.WaitForCompletion();
_loadRawBundleOp.UpdateOperation();
if (_loadRawBundleOp.IsDone == false)
return;
if (_loadRawBundleOp.Status == EOperationStatus.Succeeded)
{
if (_loadRawBundleOp.Result == null)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = "Loaded builtin raw bundle is null.";
YooLogger.Error(Error);
}
else
{
_steps = ESteps.Done;
Result = new RawBundleResult(_fileSystem, _bundle, _loadRawBundleOp.Result);
Status = EOperationStatus.Succeeded;
}
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _loadRawBundleOp.Error;
YooLogger.Error(Error);
}
}
}
internal override void InternalWaitForCompletion()
{
ExecuteBatch();
}
}
#if TUANJIE_1_7_OR_NEWER
/// <summary>
/// 加载团结文件
/// </summary>
internal class BFSLoadInstantBundleOperation : FSLoadBundleOperation
{
private enum ESteps
{
None,
LoadInstantBundle,
CheckResult,
Done,
}
private readonly DefaultBuildinFileSystem _fileSystem;
private readonly PackageBundle _bundle;
private AssetBundleCreateRequest _createRequest;
private AssetBundle _assetBundle;
private Stream _managedStream;
private ESteps _steps = ESteps.None;
internal BFSLoadInstantBundleOperation(DefaultBuildinFileSystem fileSystem, PackageBundle bundle)
{
_fileSystem = fileSystem;
_bundle = bundle;
}
internal override void InternalStart()
{
DownloadProgress = 1f;
DownloadedBytes = _bundle.FileSize;
_steps = ESteps.LoadInstantBundle;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.LoadInstantBundle)
{
if (_bundle.Encrypted)
{
if (_fileSystem.DecryptionServices == null)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"The {nameof(IDecryptionServices)} is null.";
YooLogger.Error(Error);
return;
}
}
if (IsWaitingForAsyncComplete)
{
if (_bundle.Encrypted)
{
var decryptResult = _fileSystem.LoadEncryptedAssetBundle(_bundle);
_assetBundle = decryptResult.Result;
_managedStream = decryptResult.ManagedStream;
}
else
{
string filePath = _fileSystem.GetBuildinFileLoadPath(_bundle);
_assetBundle = AssetBundle.LoadFromFile(filePath);
}
}
else
{
if (_bundle.Encrypted)
{
var decryptResult = _fileSystem.LoadEncryptedAssetBundleAsync(_bundle);
_createRequest = decryptResult.CreateRequest;
_managedStream = decryptResult.ManagedStream;
}
else
{
string filePath = _fileSystem.GetBuildinFileLoadPath(_bundle);
_createRequest = AssetBundle.LoadFromFileAsync(filePath);
}
}
_steps = ESteps.CheckResult;
}
if (_steps == ESteps.CheckResult)
{
if (_createRequest != null)
{
if (IsWaitingForAsyncComplete)
{
// 强制挂起主线程(注意:该操作会很耗时)
YooLogger.Warning("Suspend the main thread to load unity bundle.");
_assetBundle = _createRequest.assetBundle;
}
else
{
if (_createRequest.isDone == false)
return;
_assetBundle = _createRequest.assetBundle;
}
}
if (_assetBundle == null)
{
if (_bundle.Encrypted)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Failed to load encrypted buildin asset bundle file : {_bundle.BundleName}";
YooLogger.Error(Error);
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Failed to load buildin asset bundle file : {_bundle.BundleName}";
YooLogger.Error(Error);
}
}
else
{
_steps = ESteps.Done;
Result = new AssetBundleResult(_fileSystem, _bundle, _assetBundle, _managedStream);
Status = EOperationStatus.Succeed;
}
}
}
internal override void InternalWaitForAsyncComplete()
{
RunBatchExecution();
}
}
#endif
}

View File

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

View File

@@ -0,0 +1,89 @@

namespace YooAsset
{
internal class BFSLoadManifestOperation : FSLoadManifestOperation
{
private enum ESteps
{
None,
RequestBuiltinPackageHash,
LoadBuiltinPackageManifest,
Done,
}
private readonly BuiltinFileSystem _fileSystem;
private readonly string _packageVersion;
private RequestBuiltinPackageHashOperation _requestBuiltinPackageHashOp;
private LoadBuiltinPackageManifestOperation _loadBuiltinPackageManifestOp;
private ESteps _steps = ESteps.None;
public BFSLoadManifestOperation(BuiltinFileSystem fileSystem, string packageVersion)
{
_fileSystem = fileSystem;
_packageVersion = packageVersion;
}
internal override void InternalStart()
{
_steps = ESteps.RequestBuiltinPackageHash;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.RequestBuiltinPackageHash)
{
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.LoadBuiltinPackageManifest;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _requestBuiltinPackageHashOp.Error;
}
}
if (_steps == ESteps.LoadBuiltinPackageManifest)
{
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;
Manifest = _loadBuiltinPackageManifestOp.Manifest;
Status = EOperationStatus.Succeeded;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _loadBuiltinPackageManifestOp.Error;
}
}
}
}
}

View File

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

View File

@@ -0,0 +1,59 @@

namespace YooAsset
{
internal class BFSRequestVersionOperation : FSRequestVersionOperation
{
private enum ESteps
{
None,
RequestPackageVersion,
Done,
}
private readonly BuiltinFileSystem _fileSystem;
private RequestBuiltinPackageVersionOperation _requestBuiltinPackageVersionOp;
private ESteps _steps = ESteps.None;
internal BFSRequestVersionOperation(BuiltinFileSystem fileSystem)
{
_fileSystem = fileSystem;
}
internal override void InternalStart()
{
_steps = ESteps.RequestPackageVersion;
}
internal 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;
Status = EOperationStatus.Succeeded;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _requestBuiltinPackageVersionOp.Error;
}
}
}
}
}

View File

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

View File

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

View File

@@ -0,0 +1,103 @@
using System;
using System.IO;
namespace YooAsset
{
internal 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 _webFileRequestOp;
private ESteps _steps = ESteps.None;
public CopyBuiltinFileOperation(BuiltinFileSystem fileSystem, string sourceFilePath, string destFilePath)
{
_fileSystem = fileSystem;
_sourceFilePath = sourceFilePath;
_destFilePath = destFilePath;
}
internal override void InternalStart()
{
_steps = ESteps.CheckFileExist;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.CheckFileExist)
{
if (File.Exists(_destFilePath))
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
}
else
{
_steps = ESteps.TryCopyFile;
}
}
if (_steps == ESteps.TryCopyFile)
{
if (File.Exists(_sourceFilePath))
{
try
{
var directory = Path.GetDirectoryName(_destFilePath);
if (Directory.Exists(directory) == false)
Directory.CreateDirectory(directory);
File.Copy(_sourceFilePath, _destFilePath, true);
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
}
catch (Exception ex)
{
YooLogger.Warning($"Failed copy buildin file : {ex.Message}");
_steps = ESteps.UnpackFile;
}
}
else
{
_steps = ESteps.UnpackFile;
}
}
if (_steps == ESteps.UnpackFile)
{
if (_webFileRequestOp == null)
{
string url = DownloadSystemTools.ToLocalURL(_sourceFilePath);
var args = new DownloadFileRequestArgs(url, _destFilePath, 60, 0);
_webFileRequestOp = _fileSystem.DownloadBackend.CreateFileRequest(args);
_webFileRequestOp.SendRequest();
}
if (_webFileRequestOp.IsDone == false)
return;
if (_webFileRequestOp.Status == EDownloadRequestStatus.Succeed)
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _webFileRequestOp.Error;
}
}
}
}
}

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,134 @@
using System.IO;
namespace YooAsset
{
internal 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 _webDataRequestOp;
private DeserializeManifestOperation _deserializer;
private byte[] _fileData;
private ESteps _steps = ESteps.None;
/// <summary>
/// 包裹清单
/// </summary>
public PackageManifest Manifest { private set; get; }
internal LoadBuiltinPackageManifestOperation(BuiltinFileSystem fileSystem, string packageVersion, string packageHash)
{
_fileSystem = fileSystem;
_packageVersion = packageVersion;
_packageHash = packageHash;
}
internal override void InternalStart()
{
_steps = ESteps.TryLoadFileData;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.TryLoadFileData)
{
string filePath = _fileSystem.GetBuiltinPackageManifestFilePath(_packageVersion);
if (File.Exists(filePath))
{
_fileData = File.ReadAllBytes(filePath);
_steps = ESteps.VerifyFileData;
}
else
{
_steps = ESteps.RequestFileData;
}
}
if (_steps == ESteps.RequestFileData)
{
if (_webDataRequestOp == null)
{
string filePath = _fileSystem.GetBuiltinPackageManifestFilePath(_packageVersion);
string url = DownloadSystemTools.ToLocalURL(filePath);
var args = new DownloadDataRequestArgs(url, 60, 0);
_webDataRequestOp = _fileSystem.DownloadBackend.CreateBytesRequest(args);
_webDataRequestOp.SendRequest();
}
if (_webDataRequestOp.IsDone == false)
return;
if (_webDataRequestOp.Status == EDownloadRequestStatus.Succeed)
{
_fileData = _webDataRequestOp.Result;
_steps = ESteps.VerifyFileData;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _webDataRequestOp.Error;
}
}
if (_steps == ESteps.VerifyFileData)
{
if (PackageManifestTools.VerifyManifestData(_fileData, _packageHash))
{
_steps = ESteps.LoadManifest;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = "Failed to verify buildin package manifest file.";
}
}
if (_steps == ESteps.LoadManifest)
{
if (_deserializer == null)
{
_deserializer = new DeserializeManifestOperation(_fileSystem.ManifestRestoreServices, _fileData);
_deserializer.StartOperation();
AddChildOperation(_deserializer);
}
_deserializer.UpdateOperation();
Progress = _deserializer.Progress;
if (_deserializer.IsDone == false)
return;
if (_deserializer.Status == EOperationStatus.Succeeded)
{
_steps = ESteps.Done;
Manifest = _deserializer.Manifest;
Status = EOperationStatus.Succeeded;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _deserializer.Error;
}
}
}
internal override string InternalGetDescription()
{
return $"PackageVersion : {_packageVersion} PackageHash : {_packageHash}";
}
}
}

View File

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

View File

@@ -0,0 +1,98 @@
using System.IO;
namespace YooAsset
{
internal class RequestBuiltinPackageHashOperation : AsyncOperationBase
{
private enum ESteps
{
None,
TryLoadPackageHash,
RequestPackageHash,
CheckResult,
Done,
}
private readonly BuiltinFileSystem _fileSystem;
private readonly string _packageVersion;
private IDownloadTextRequest _webTextRequestOp;
private ESteps _steps = ESteps.None;
/// <summary>
/// 包裹哈希值
/// </summary>
public string PackageHash { private set; get; }
internal RequestBuiltinPackageHashOperation(BuiltinFileSystem fileSystem, string packageVersion)
{
_fileSystem = fileSystem;
_packageVersion = packageVersion;
}
internal override void InternalStart()
{
_steps = ESteps.TryLoadPackageHash;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.TryLoadPackageHash)
{
string filePath = _fileSystem.GetBuiltinPackageHashFilePath(_packageVersion);
if (File.Exists(filePath))
{
PackageHash = File.ReadAllText(filePath);
_steps = ESteps.CheckResult;
}
else
{
_steps = ESteps.RequestPackageHash;
}
}
if (_steps == ESteps.RequestPackageHash)
{
if (_webTextRequestOp == null)
{
string filePath = _fileSystem.GetBuiltinPackageHashFilePath(_packageVersion);
string url = DownloadSystemTools.ToLocalURL(filePath);
var args = new DownloadDataRequestArgs(url, 60, 0);
_webTextRequestOp = _fileSystem.DownloadBackend.CreateTextRequest(args);
_webTextRequestOp.SendRequest();
}
if (_webTextRequestOp.IsDone == false)
return;
if (_webTextRequestOp.Status == EDownloadRequestStatus.Succeed)
{
PackageHash = _webTextRequestOp.Result;
_steps = ESteps.CheckResult;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _webTextRequestOp.Error;
}
}
if (_steps == ESteps.CheckResult)
{
if (string.IsNullOrEmpty(PackageHash))
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Builtin package hash file content is empty.";
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
}
}
}
}
}

View File

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

View File

@@ -0,0 +1,96 @@
using System.IO;
namespace YooAsset
{
internal class RequestBuiltinPackageVersionOperation : AsyncOperationBase
{
private enum ESteps
{
None,
TryLoadPackageVersion,
RequestPackageVersion,
CheckResult,
Done,
}
private readonly BuiltinFileSystem _fileSystem;
private IDownloadTextRequest _webTextRequestOp;
private ESteps _steps = ESteps.None;
/// <summary>
/// 包裹版本
/// </summary>
public string PackageVersion { private set; get; }
internal RequestBuiltinPackageVersionOperation(BuiltinFileSystem fileSystem)
{
_fileSystem = fileSystem;
}
internal override void InternalStart()
{
_steps = ESteps.TryLoadPackageVersion;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.TryLoadPackageVersion)
{
string filePath = _fileSystem.GetBuiltinPackageVersionFilePath();
if (File.Exists(filePath))
{
PackageVersion = File.ReadAllText(filePath);
_steps = ESteps.CheckResult;
}
else
{
_steps = ESteps.RequestPackageVersion;
}
}
if (_steps == ESteps.RequestPackageVersion)
{
if (_webTextRequestOp == null)
{
string filePath = _fileSystem.GetBuiltinPackageVersionFilePath();
string url = DownloadSystemTools.ToLocalURL(filePath);
var args = new DownloadDataRequestArgs(url, 60, 0);
_webTextRequestOp = _fileSystem.DownloadBackend.CreateTextRequest(args);
_webTextRequestOp.SendRequest();
}
if (_webTextRequestOp.IsDone == false)
return;
if (_webTextRequestOp.Status == EDownloadRequestStatus.Succeed)
{
PackageVersion = _webTextRequestOp.Result;
_steps = ESteps.CheckResult;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _webTextRequestOp.Error;
}
}
if (_steps == ESteps.CheckResult)
{
if (string.IsNullOrEmpty(PackageVersion))
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Builtin package version file content is empty.";
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
}
}
}
}
}

View File

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

View File

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

View File

@@ -0,0 +1,63 @@
using System.IO;
using UnityEngine;
namespace YooAsset
{
/// <summary>
/// 应用程序水印
/// </summary>
internal class ApplicationFootprint
{
private readonly CacheFileSystem _fileSystem;
private string _footPrint;
public ApplicationFootprint(CacheFileSystem fileSystem)
{
_fileSystem = fileSystem;
}
/// <summary>
/// 读取应用程序水印
/// </summary>
public void Load(string packageName)
{
string footPrintFilePath = _fileSystem.GetSandboxAppFootPrintFilePath();
if (File.Exists(footPrintFilePath))
{
_footPrint = FileUtility.ReadAllText(footPrintFilePath);
}
else
{
Coverage(packageName);
}
}
/// <summary>
/// 检测水印是否发生变化
/// </summary>
public bool IsDirty()
{
#if UNITY_EDITOR
return _footPrint != Application.version;
#else
return _footPrint != Application.buildGUID;
#endif
}
/// <summary>
/// 覆盖掉水印
/// </summary>
public void Coverage(string packageName)
{
#if UNITY_EDITOR
_footPrint = Application.version;
#else
_footPrint = Application.buildGUID;
#endif
string footPrintFilePath = _fileSystem.GetSandboxAppFootPrintFilePath();
FileUtility.WriteAllText(footPrintFilePath, _footPrint);
YooLogger.Log($"Save application foot print : {_footPrint}");
}
}
}

View File

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

View File

@@ -0,0 +1,518 @@
using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace YooAsset
{
/// <summary>
/// 缓存文件系统
/// 说明正在进行的下载器会在ResourcePackage销毁的时候执行Abort操作
/// </summary>
internal class CacheFileSystem : IFileSystem
{
protected readonly Dictionary<string, string> _tempFilePathMapping = new Dictionary<string, string>(10000);
protected string _packageRoot;
protected string _tempFilesRoot;
protected string _cacheBundleFilesRoot;
protected string _cacheManifestFilesRoot;
/// <summary>
/// 文件缓存系统
/// </summary>
public BundleCache Cache { get; private set; }
/// <summary>
/// 下载调度器
/// </summary>
public DownloadSchedulerOperation DownloadScheduler { get; set; }
/// <summary>
/// 下载后台接口
/// </summary>
public IDownloadBackend DownloadBackend { get; private set; }
/// <summary>
/// 包裹名称
/// </summary>
public string PackageName { get; private set; }
/// <summary>
/// 文件根目录
/// </summary>
public string FileRoot
{
get
{
return _packageRoot;
}
}
/// <summary>
/// 文件数量
/// </summary>
public int FileCount
{
get
{
return Cache.FileCount;
}
}
#region
/// <summary>
/// 自定义参数UnityWebRequest 创建委托
/// </summary>
public UnityWebRequestCreator WebRequestCreator { private set; get; }
/// <summary>
/// 自定义参数:远程服务接口的实例类
/// </summary>
public IRemoteServices RemoteServices { private set; get; }
/// <summary>
/// 自定义参数:覆盖安装缓存清理模式
/// </summary>
public EOverwriteInstallClearMode InstallClearMode { private set; get; } = EOverwriteInstallClearMode.ClearAllManifestFiles;
/// <summary>
/// 自定义参数:初始化的时候缓存文件校验级别
/// </summary>
public EFileVerifyLevel FileVerifyLevel { private set; get; } = EFileVerifyLevel.Middle;
/// <summary>
/// 自定义参数:初始化的时候缓存文件校验最大并发数
/// 默认值8推荐范围 1-32
/// 说明:过大的值可能导致线程池任务过多,影响系统稳定性
/// </summary>
public int FileVerifyMaxConcurrency { private set; get; } = 8;
/// <summary>
/// 自定义参数:数据文件追加文件格式
/// </summary>
public bool AppendFileExtension { private set; get; } = false;
/// <summary>
/// 自定义参数:禁用边玩边下机制
/// </summary>
public bool DisableOnDemandDownload { private set; get; } = false;
/// <summary>
/// 自定义参数:最大并发连接数
/// 默认值8推荐范围 1-32
/// 说明:过大的并发数可能被服务器限流,也会增加本地资源消耗
/// </summary>
public int DownloadMaxConcurrency { private set; get; } = 8;
/// <summary>
/// 自定义参数:每帧发起的最大请求数
/// 默认值8推荐范围 1-32
/// 说明:避免单帧发起过多请求导致卡顿
/// </summary>
public int DownloadMaxRequestPerFrame { private set; get; } = 8;
/// <summary>
/// 自定义参数:下载任务的看门狗机制超时时间
/// </summary>
public int DownloadWatchDogTimeout { private set; get; } = 0;
/// <summary>
/// 自定义参数:启用断点续传的最小尺寸
/// </summary>
public long ResumeDownloadMinimumSize { private set; get; } = long.MaxValue;
/// <summary>
/// 自定义参数:断点续传下载器关注的错误码
/// </summary>
public List<long> ResumeDownloadResponseCodes { private set; get; } = null;
/// <summary>
/// 自定义参数:加载 AssetBundle 的工厂委托
/// </summary>
public LoadAssetBundleOperationFactory LoadAssetBundleFactory { private set; get; }
/// <summary>
/// 自定义参数:加载 RawBundle 的工厂委托
/// </summary>
public LoadRawBundleOperationFactory LoadRawBundleFactory { private set; get; }
/// <summary>
/// 自定义参数:资源清单服务类
/// </summary>
public IManifestRestoreServices ManifestRestoreServices { private set; get; }
/// <summary>
/// 自定义参数:拷贝内置文件接口的实例类
/// </summary>
public ILocalFileCopyServices CopyLocalFileServices { private set; get; }
#endregion
public CacheFileSystem()
{
}
public virtual FSInitializeOperation InitializeAsync()
{
var operation = new CFSInitializeOperation(this);
return operation;
}
public virtual FSRequestVersionOperation RequestVersionAsync(RequestVersionOptions options)
{
var operation = new CFSRequestPackageVersionOperation(this, options.AppendTimeTicks, options.Timeout);
return operation;
}
public virtual FSLoadManifestOperation LoadManifestAsync(LoadManifestOptions options)
{
var operation = new CFSLoadPackageManifestOperation(this, options.PackageVersion, options.Timeout);
return operation;
}
public virtual FSClearCacheOperation ClearCacheAsync(ClearCacheOptions options)
{
if (options.ClearMode == EFileClearMode.ClearAllBundleFiles.ToString())
{
var operation = new ClearAllCacheBundleFilesOperation(this);
return operation;
}
else if (options.ClearMode == EFileClearMode.ClearUnusedBundleFiles.ToString())
{
var operation = new ClearUnusedCacheBundleFilesOperation(this, options.Manifest);
return operation;
}
else if (options.ClearMode == EFileClearMode.ClearBundleFilesByLocations.ToString())
{
var operation = new ClearCacheBundleFilesByLocationsOperation(this, options.Manifest, options.ClearParam);
return operation;
}
else if (options.ClearMode == EFileClearMode.ClearBundleFilesByTags.ToString())
{
var operation = new ClearCacheBundleFilesByTagsOperation(this, options.Manifest, options.ClearParam);
return operation;
}
else if (options.ClearMode == EFileClearMode.ClearAllManifestFiles.ToString())
{
var operation = new ClearAllCacheManifestFilesOperation(this);
return operation;
}
else if (options.ClearMode == EFileClearMode.ClearUnusedManifestFiles.ToString())
{
var operation = new ClearUnusedCacheManifestFilesOperation(this, options.Manifest);
return operation;
}
else
{
string error = $"Invalid clear mode : {options.ClearMode}";
var operation = new FSClearCacheCompleteOperation(error);
return operation;
}
}
public virtual FSDownloadFileOperation DownloadFileAsync(DownloadFileOptions options)
{
// 获取下载地址
PackageBundle bundle = options.Bundle;
if (string.IsNullOrEmpty(options.ImportFilePath))
{
// 注意:如果是解压文件系统类,这里会返回本地内置文件的下载路径
string mainURL = RemoteServices.GetRemoteMainURL(bundle.FileName);
string fallbackURL = RemoteServices.GetRemoteFallbackURL(bundle.FileName);
options.SetURL(mainURL, fallbackURL);
}
else
{
// 注意:把本地导入文件路径转换为下载器请求地址
string mainURL = DownloadSystemTools.ToLocalURL(options.ImportFilePath);
options.SetURL(mainURL, mainURL);
}
var downloader = new DownloadPackageBundleOperation(this, options);
return downloader;
}
public virtual FSLoadBundleOperation LoadBundleAsync(LoadBundleOptions options)
{
PackageBundle bundle = options.Bundle;
if (bundle.BundleType == (int)EBundleType.AssetBundle)
{
var operation = new CFSLoadAssetBundleOperation(this, bundle);
return operation;
}
else if (bundle.BundleType == (int)EBundleType.RawBundle)
{
var operation = new CFSLoadRawBundleOperation(this, bundle);
return operation;
}
else
{
string error = $"{nameof(CacheFileSystem)} not support load bundle type : {bundle.BundleType}";
var operation = new FSLoadBundleCompleteOperation(error);
return operation;
}
}
public virtual void SetParameter(string name, object value)
{
if (name == FileSystemParametersDefine.DOWNLOAD_BACKEND)
{
DownloadBackend = (IDownloadBackend)value;
}
else if (name == FileSystemParametersDefine.UNITY_WEB_REQUEST_CREATOR)
{
WebRequestCreator = (UnityWebRequestCreator)value;
}
else if (name == FileSystemParametersDefine.REMOTE_SERVICES)
{
RemoteServices = (IRemoteServices)value;
}
else if (name == FileSystemParametersDefine.INSTALL_CLEAR_MODE)
{
InstallClearMode = (EOverwriteInstallClearMode)value;
}
else if (name == FileSystemParametersDefine.FILE_VERIFY_LEVEL)
{
FileVerifyLevel = (EFileVerifyLevel)value;
}
else if (name == FileSystemParametersDefine.FILE_VERIFY_MAX_CONCURRENCY)
{
int convertValue = Convert.ToInt32(value);
if (convertValue > 32)
{
YooLogger.Warning($"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 (name == FileSystemParametersDefine.APPEND_FILE_EXTENSION)
{
AppendFileExtension = Convert.ToBoolean(value);
}
else if (name == FileSystemParametersDefine.DISABLE_ONDEMAND_DOWNLOAD)
{
DisableOnDemandDownload = Convert.ToBoolean(value);
}
else if (name == FileSystemParametersDefine.DOWNLOAD_MAX_CONCURRENCY)
{
int convertValue = Convert.ToInt32(value);
if (convertValue > 32)
{
YooLogger.Warning($"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 (name == FileSystemParametersDefine.DOWNLOAD_MAX_REQUEST_PER_FRAME)
{
int convertValue = Convert.ToInt32(value);
if (convertValue > 32)
{
YooLogger.Warning($"DOWNLOAD_MAX_REQUEST_PER_FRAME value {convertValue} is too large, clamped to 32. Recommended range: 1 - 32.");
}
// 限制在合理范围内1-32
DownloadMaxRequestPerFrame = Mathf.Clamp(convertValue, 1, 32);
}
else if (name == FileSystemParametersDefine.DOWNLOAD_WATCH_DOG_TIME)
{
int convertValue = Convert.ToInt32(value);
DownloadWatchDogTimeout = Mathf.Clamp(convertValue, 0, int.MaxValue);
}
else if (name == FileSystemParametersDefine.RESUME_DOWNLOAD_MINMUM_SIZE)
{
ResumeDownloadMinimumSize = Convert.ToInt64(value);
}
else if (name == FileSystemParametersDefine.RESUME_DOWNLOAD_RESPONSE_CODES)
{
ResumeDownloadResponseCodes = (List<long>)value;
}
else if (name == FileSystemParametersDefine.LOAD_ASSETBUNDLE_OPERATION_FACTORY)
{
LoadAssetBundleFactory = (LoadAssetBundleOperationFactory)value;
}
else if (name == FileSystemParametersDefine.LOAD_RAWBUNDLE_OPERATION_FACTORY)
{
LoadRawBundleFactory = (LoadRawBundleOperationFactory)value;
}
else if (name == FileSystemParametersDefine.MANIFEST_RESTORE_SERVICES)
{
ManifestRestoreServices = (IManifestRestoreServices)value;
}
else if (name == FileSystemParametersDefine.COPY_LOCAL_FILE_SERVICES)
{
CopyLocalFileServices = (ILocalFileCopyServices)value;
}
else
{
YooLogger.Warning($"Invalid parameter : {name}");
}
}
public virtual void OnCreate(string packageName, string packageRoot)
{
PackageName = packageName;
if (string.IsNullOrEmpty(packageRoot))
_packageRoot = GetDefaultCachePackageRoot(packageName);
else
_packageRoot = packageRoot;
_cacheBundleFilesRoot = PathUtility.Combine(_packageRoot, DefaultCacheFileSystemDefine.BundleFilesFolderName);
_cacheManifestFilesRoot = PathUtility.Combine(_packageRoot, DefaultCacheFileSystemDefine.ManifestFilesFolderName);
_tempFilesRoot = PathUtility.Combine(_packageRoot, DefaultCacheFileSystemDefine.TempFilesFolderName);
// 创建文件缓存系统
Cache = new BundleCache(PackageName, _cacheBundleFilesRoot, AppendFileExtension);
// 创建默认的下载后台接口
if (DownloadBackend == null)
DownloadBackend = new UnityWebRequestBackend(WebRequestCreator);
// 创建默认的 AssetBundle 加载工厂
if (LoadAssetBundleFactory == null)
LoadAssetBundleFactory = DefaultLoadAssetBundleOperationFactory;
// 创建默认的 RawBundle 加载工厂
if (LoadRawBundleFactory == null)
LoadRawBundleFactory = DefaultLoadRawBundleOperationFactory;
}
public virtual void OnDestroy()
{
if (DownloadScheduler != null)
{
DownloadScheduler.Dispose();
DownloadScheduler = null;
}
if (DownloadBackend != null)
{
DownloadBackend.Dispose();
DownloadBackend = null;
}
}
public virtual bool Belong(PackageBundle bundle)
{
// 注意:缓存文件系统保底加载!
return true;
}
public virtual bool Exists(PackageBundle bundle)
{
return Cache.IsCached(bundle.BundleGUID);
}
public virtual bool NeedDownload(PackageBundle bundle)
{
if (Belong(bundle) == false)
return false;
return Exists(bundle) == false;
}
public virtual bool NeedUnpack(PackageBundle bundle)
{
return false;
}
public virtual bool NeedImport(PackageBundle bundle)
{
if (Belong(bundle) == false)
return false;
return Exists(bundle) == false;
}
public virtual string GetBundleFilePath(PackageBundle bundle)
{
return GetCacheBundleFileLoadPath(bundle);
}
#region
private LoadAssetBundleOperation DefaultLoadAssetBundleOperationFactory(bool bundleEncrypted, LoadAssetBundleOptions options)
{
if (bundleEncrypted)
{
string error = $"{nameof(DefaultLoadAssetBundleOperation)} cannot load encrypted bundle. Please provide a custom {nameof(LoadAssetBundleOperationFactory)}.";
return new LoadAssetBundleCompleteOperation(error, options);
}
else
{
return new DefaultLoadAssetBundleOperation(options);
}
}
private LoadRawBundleOperation DefaultLoadRawBundleOperationFactory(bool bundleEncrypted, LoadRawBundleOptions options)
{
if (bundleEncrypted)
{
string error = $"{nameof(DefaultLoadRawBundleOperation)} cannot load encrypted bundle. Please provide a custom {nameof(LoadRawBundleOperationFactory)}.";
return new LoadRawBundleCompleteOperation(error, options);
}
else
{
return new DefaultLoadRawBundleOperation(options);
}
}
public string GetDefaultCachePackageRoot(string packageName)
{
string rootDirectory = YooAssetSettingsData.GetYooDefaultCacheRoot();
return PathUtility.Combine(rootDirectory, packageName);
}
public string GetCacheBundleFileLoadPath(PackageBundle bundle)
{
var entry = Cache.GetEntry(bundle.BundleGUID);
if (entry == null)
throw new YooInternalException();
return entry.DataFilePath;
}
public string GetCachePackageHashFilePath(string packageVersion)
{
string fileName = YooAssetSettingsData.GetPackageHashFileName(PackageName, packageVersion);
return PathUtility.Combine(_cacheManifestFilesRoot, fileName);
}
public string GetCachePackageManifestFilePath(string packageVersion)
{
string fileName = YooAssetSettingsData.GetManifestBinaryFileName(PackageName, packageVersion);
return PathUtility.Combine(_cacheManifestFilesRoot, fileName);
}
public string GetSandboxAppFootPrintFilePath()
{
return PathUtility.Combine(_cacheManifestFilesRoot, DefaultCacheFileSystemDefine.AppFootPrintFileName);
}
public string GetCacheBundleFilesRoot()
{
return _cacheBundleFilesRoot;
}
public string GetCacheManifestFilesRoot()
{
return _cacheManifestFilesRoot;
}
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);
}
}
#endregion
}
}

View File

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

View File

@@ -0,0 +1,26 @@

namespace YooAsset
{
internal class DefaultCacheFileSystemDefine
{
/// <summary>
/// 资源文件的文件夹名称
/// </summary>
public const string BundleFilesFolderName = "BundleFiles";
/// <summary>
/// 临时文件的文件夹名称
/// </summary>
public const string TempFilesFolderName = "TempFiles";
/// <summary>
/// 清单文件的文件夹名称
/// </summary>
public const string ManifestFilesFolderName = "ManifestFiles";
/// <summary>
/// 记录应用程序版本的文件名称
/// </summary>
public const string AppFootPrintFileName = "ApplicationFootPrint.bytes";
}
}

View File

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

View File

@@ -0,0 +1,42 @@

namespace YooAsset
{
/// <summary>
/// 文件清理方式
/// </summary>
public enum EFileClearMode
{
/// <summary>
/// 清理所有文件
/// </summary>
ClearAllBundleFiles,
/// <summary>
/// 清理未在使用的文件
/// </summary>
ClearUnusedBundleFiles,
/// <summary>
/// 清理指定地址的文件
/// 说明需要指定参数可选string, string[], List<string>
/// </summary>
ClearBundleFilesByLocations,
/// <summary>
/// 清理指定标签的文件
/// 说明需要指定参数可选string, string[], List<string>
/// </summary>
ClearBundleFilesByTags,
/// <summary>
/// 清理所有清单
/// </summary>
ClearAllManifestFiles,
/// <summary>
/// 清理未在使用的清单
/// </summary>
ClearUnusedManifestFiles,
}
}

View File

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

View File

@@ -0,0 +1,29 @@

namespace YooAsset
{
/// <summary>
/// 覆盖安装清理模式
/// </summary>
public enum EOverwriteInstallClearMode
{
/// <summary>
/// 不做任何处理
/// </summary>
None = 0,
/// <summary>
/// 清理所有缓存文件(包含资源文件和清单文件)
/// </summary>
ClearAllCacheFiles = 1,
/// <summary>
/// 清理所有缓存的资源文件
/// </summary>
ClearAllBundleFiles = 2,
/// <summary>
/// 清理所有缓存的清单文件
/// </summary>
ClearAllManifestFiles = 3,
}
}

View File

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

View File

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

View File

@@ -0,0 +1,121 @@
namespace YooAsset
{
internal class CFSInitializeOperation : FSInitializeOperation
{
private enum ESteps
{
None,
CheckAppFootPrint,
CacheInitialize,
CreateDownloadScheduler,
Done,
}
private readonly CacheFileSystem _fileSystem;
private FCInitializeOperation _initializeCacheOp;
private ESteps _steps = ESteps.None;
internal CFSInitializeOperation(CacheFileSystem fileSystem)
{
_fileSystem = fileSystem;
}
internal override void InternalStart()
{
#if UNITY_WEBGL
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"{nameof(DefaultCacheFileSystem)} is not support WEBGL platform.";
#else
_steps = ESteps.CheckAppFootPrint;
#endif
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.CheckAppFootPrint)
{
var appFootPrint = new ApplicationFootprint(_fileSystem);
appFootPrint.Load(_fileSystem.PackageName);
// 如果水印发生变化,则说明覆盖安装后首次打开游戏
if (appFootPrint.IsDirty())
{
if (_fileSystem.InstallClearMode == EOverwriteInstallClearMode.None)
{
YooLogger.Warning("Do nothing when overwrite install application.");
}
else if (_fileSystem.InstallClearMode == EOverwriteInstallClearMode.ClearAllCacheFiles)
{
_fileSystem.DeleteAllBundleFiles();
_fileSystem.DeleteAllManifestFiles();
YooLogger.Warning("Delete all cache files when overwrite install application.");
}
else if (_fileSystem.InstallClearMode == EOverwriteInstallClearMode.ClearAllBundleFiles)
{
_fileSystem.DeleteAllBundleFiles();
YooLogger.Warning("Delete all bundle files when overwrite install application.");
}
else if (_fileSystem.InstallClearMode == EOverwriteInstallClearMode.ClearAllManifestFiles)
{
_fileSystem.DeleteAllManifestFiles();
YooLogger.Warning("Delete all manifest files when overwrite install application.");
}
else
{
throw new System.NotImplementedException(_fileSystem.InstallClearMode.ToString());
}
appFootPrint.Coverage(_fileSystem.PackageName);
}
_steps = ESteps.CacheInitialize;
}
if (_steps == ESteps.CacheInitialize)
{
if (_initializeCacheOp == null)
{
var options = new FCInitializeOptions();
options.FileVerifyLevel = _fileSystem.FileVerifyLevel;
options.FileVerifyMaxConcurrency = _fileSystem.FileVerifyMaxConcurrency;
_initializeCacheOp = _fileSystem.Cache.InitializeAsync(options);
_initializeCacheOp.StartOperation();
AddChildOperation(_initializeCacheOp);
}
_initializeCacheOp.UpdateOperation();
Progress = _initializeCacheOp.Progress;
if (_initializeCacheOp.IsDone == false)
return;
if (_initializeCacheOp.Status != EOperationStatus.Succeeded)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _initializeCacheOp.Error;
}
else
{
_steps = ESteps.CreateDownloadScheduler;
}
}
if (_steps == ESteps.CreateDownloadScheduler)
{
// 注意:下载中心作为独立任务运行!
if (_fileSystem.DownloadScheduler == null)
{
_fileSystem.DownloadScheduler = new DownloadSchedulerOperation(_fileSystem);
AsyncOperationSystem.StartOperation(_fileSystem.PackageName, _fileSystem.DownloadScheduler);
}
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
}
}
}
}

View File

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

View File

@@ -0,0 +1,405 @@
using System;
using System.IO;
using UnityEngine;
namespace YooAsset
{
internal class CFSLoadAssetBundleOperation : FSLoadBundleOperation
{
protected enum ESteps
{
None,
CheckExist,
DownloadFile,
AbortDownload,
LoadCacheAssetBundle,
CheckResult,
TryFallback,
Done,
}
protected readonly CacheFileSystem _fileSystem;
protected readonly PackageBundle _bundle;
protected FSDownloadFileOperation _downloadFileOp;
protected LoadAssetBundleOperation _loadAssetBundleOp;
protected ESteps _steps = ESteps.None;
internal CFSLoadAssetBundleOperation(CacheFileSystem fileSystem, PackageBundle bundle)
{
_fileSystem = fileSystem;
_bundle = bundle;
}
internal override void InternalStart()
{
_steps = ESteps.CheckExist;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.CheckExist)
{
if (_fileSystem.Exists(_bundle))
{
DownloadProgress = 1f;
DownloadedBytes = _bundle.FileSize;
_steps = ESteps.LoadCacheAssetBundle;
}
else
{
if (_fileSystem.DisableOnDemandDownload)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"The bundle not cached : {_bundle.BundleName}";
YooLogger.Warning(Error);
}
else
{
_steps = ESteps.DownloadFile;
}
}
}
if (_steps == ESteps.DownloadFile)
{
// 中断下载
if (AbortDownloadFile)
{
if (_downloadFileOp != null)
_downloadFileOp.AbortOperation();
_steps = ESteps.AbortDownload;
}
}
if (_steps == ESteps.DownloadFile)
{
if (_downloadFileOp == null)
{
DownloadFileOptions options = new DownloadFileOptions(_bundle, int.MaxValue);
_downloadFileOp = _fileSystem.DownloadFileAsync(options);
_downloadFileOp.StartOperation();
AddChildOperation(_downloadFileOp);
}
if (IsWaitForCompletion)
_downloadFileOp.WaitForCompletion();
_downloadFileOp.UpdateOperation();
DownloadProgress = _downloadFileOp.DownloadProgress;
DownloadedBytes = _downloadFileOp.DownloadedBytes;
if (_downloadFileOp.IsDone == false)
return;
if (_downloadFileOp.Status == EOperationStatus.Succeeded)
{
_steps = ESteps.LoadCacheAssetBundle;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _downloadFileOp.Error;
}
}
if (_steps == ESteps.AbortDownload)
{
if (_downloadFileOp != null)
{
if (IsWaitForCompletion)
_downloadFileOp.WaitForCompletion();
_downloadFileOp.UpdateOperation();
if (_downloadFileOp.IsDone == false)
return;
}
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = "Abort download file.";
}
if (_steps == ESteps.LoadCacheAssetBundle)
{
var options = new LoadAssetBundleOptions();
options.FileLoadPath = _fileSystem.GetCacheBundleFileLoadPath(_bundle);
options.Bundle = _bundle;
_loadAssetBundleOp = _fileSystem.LoadAssetBundleFactory.Invoke(_bundle.Encrypted, options);
_loadAssetBundleOp.StartOperation();
AddChildOperation(_loadAssetBundleOp);
_steps = ESteps.CheckResult;
}
if (_steps == ESteps.CheckResult)
{
if (IsWaitForCompletion)
_loadAssetBundleOp.WaitForCompletion();
_loadAssetBundleOp.UpdateOperation();
if (_loadAssetBundleOp.IsDone == false)
return;
if (_loadAssetBundleOp.Status == EOperationStatus.Succeeded)
{
if (_loadAssetBundleOp.Result == null)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = "Loaded cache asset bundle is null.";
YooLogger.Error(Error);
}
else
{
_steps = ESteps.Done;
Result = new AssetBundleResult(_fileSystem, _bundle, _loadAssetBundleOp.Result, _loadAssetBundleOp.ManagedStream);
Status = EOperationStatus.Succeeded;
}
}
else
{
if (_loadAssetBundleOp is LoadAssetBundleCompleteOperation)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _loadAssetBundleOp.Error;
YooLogger.Error(Error);
}
else
{
// 加载失败,尝试后备加载
_steps = ESteps.TryFallback;
}
}
}
if (_steps == ESteps.TryFallback)
{
var entry = _fileSystem.Cache.GetEntry(_bundle.BundleGUID);
if (entry == null)
throw new YooInternalException();
// 注意当缓存文件的校验等级为Low的时候并不能保证缓存文件的完整性。
// 说明在AssetBundle文件加载失败的情况下我们需要重新验证文件的完整性
var verifyResult = FileVerifyTools.FileVerify(entry.DataFilePath, _bundle.FileSize, _bundle.FileCRC);
if (verifyResult == EFileVerifyResult.Succeed)
{
// 调用后备加载方法
// 注意:在安卓移动平台,华为和三星真机上有极小概率加载资源包失败。
// 说明:大多数情况在首次安装下载资源到沙盒内,游戏过程中切换到后台再回到游戏内有很大概率触发!
AssetBundle assetBundle = _loadAssetBundleOp.LoadFromMemory();
if (assetBundle != null)
{
_steps = ESteps.Done;
Result = new AssetBundleResult(_fileSystem, _bundle, assetBundle, null);
Status = EOperationStatus.Succeeded;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Failed to load asset bundle from memory : {_bundle.BundleName}";
YooLogger.Error(Error);
}
}
else
{
// 文件损坏,删除缓存
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Find corrupted asset bundle file and delete : {_bundle.BundleName}";
YooLogger.Error(Error);
_fileSystem.Cache.RemoveEntry(_bundle.BundleGUID);
}
}
}
internal override void InternalWaitForCompletion()
{
ExecuteBatch();
}
}
internal class CFSLoadRawBundleOperation : FSLoadBundleOperation
{
protected enum ESteps
{
None,
CheckExist,
DownloadFile,
AbortDownload,
LoadCacheRawBundle,
CheckResult,
Done,
}
protected readonly CacheFileSystem _fileSystem;
protected readonly PackageBundle _bundle;
protected FSDownloadFileOperation _downloadFileOp;
protected LoadRawBundleOperation _loadRawBundleOp;
protected ESteps _steps = ESteps.None;
internal CFSLoadRawBundleOperation(CacheFileSystem fileSystem, PackageBundle bundle)
{
_fileSystem = fileSystem;
_bundle = bundle;
}
internal override void InternalStart()
{
_steps = ESteps.CheckExist;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.CheckExist)
{
if (_fileSystem.Exists(_bundle))
{
// 注意:缓存的原生文件的格式,可能会在业务端根据需求发生变动!
// 注意:这里需要校验文件格式,如果不一致对本地文件进行修正!
var entry = _fileSystem.Cache.GetEntry(_bundle.BundleGUID);
if (entry == null)
throw new YooInternalException();
if (File.Exists(entry.DataFilePath) == false)
{
try
{
string destFilePath = _fileSystem.Cache.GetDataFilePath(_bundle);
entry.MoveFile(destFilePath);
_steps = ESteps.LoadCacheRawBundle;
}
catch (Exception ex)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Faild rename cached data file : {ex.Message}";
}
}
else
{
DownloadProgress = 1f;
DownloadedBytes = _bundle.FileSize;
_steps = ESteps.LoadCacheRawBundle;
}
}
else
{
_steps = ESteps.DownloadFile;
}
}
if (_steps == ESteps.DownloadFile)
{
// 中断下载
if (AbortDownloadFile)
{
if (_downloadFileOp != null)
_downloadFileOp.AbortOperation();
_steps = ESteps.AbortDownload;
}
}
if (_steps == ESteps.DownloadFile)
{
if (_downloadFileOp == null)
{
DownloadFileOptions options = new DownloadFileOptions(_bundle, int.MaxValue);
_downloadFileOp = _fileSystem.DownloadFileAsync(options);
_downloadFileOp.StartOperation();
AddChildOperation(_downloadFileOp);
}
if (IsWaitForCompletion)
_downloadFileOp.WaitForCompletion();
_downloadFileOp.UpdateOperation();
DownloadProgress = _downloadFileOp.DownloadProgress;
DownloadedBytes = _downloadFileOp.DownloadedBytes;
if (_downloadFileOp.IsDone == false)
return;
if (_downloadFileOp.Status == EOperationStatus.Succeeded)
{
_steps = ESteps.LoadCacheRawBundle;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _downloadFileOp.Error;
}
}
if (_steps == ESteps.AbortDownload)
{
if (_downloadFileOp != null)
{
if (IsWaitForCompletion)
_downloadFileOp.WaitForCompletion();
_downloadFileOp.UpdateOperation();
if (_downloadFileOp.IsDone == false)
return;
}
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = "Abort download file.";
}
if (_steps == ESteps.LoadCacheRawBundle)
{
var options = new LoadRawBundleOptions();
options.FileLoadPath = _fileSystem.GetCacheBundleFileLoadPath(_bundle);
options.Bundle = _bundle;
_loadRawBundleOp = _fileSystem.LoadRawBundleFactory.Invoke(_bundle.Encrypted, options);
_loadRawBundleOp.StartOperation();
AddChildOperation(_loadRawBundleOp);
_steps = ESteps.CheckResult;
}
if (_steps == ESteps.CheckResult)
{
if (IsWaitForCompletion)
_loadRawBundleOp.WaitForCompletion();
_loadRawBundleOp.UpdateOperation();
if (_loadRawBundleOp.IsDone == false)
return;
if (_loadRawBundleOp.Status == EOperationStatus.Succeeded)
{
if (_loadRawBundleOp.Result == null)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = "Loaded cache raw bundle is null.";
YooLogger.Error(Error);
}
else
{
_steps = ESteps.Done;
Result = new RawBundleResult(_fileSystem, _bundle, _loadRawBundleOp.Result);
Status = EOperationStatus.Succeeded;
}
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _loadRawBundleOp.Error;
YooLogger.Error(Error);
}
}
}
internal override void InternalWaitForCompletion()
{
ExecuteBatch();
}
}
}

View File

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

View File

@@ -0,0 +1,166 @@
using System.IO;
namespace YooAsset
{
internal class CFSLoadPackageManifestOperation : FSLoadManifestOperation
{
private enum ESteps
{
None,
DownloadPackageHash,
DownloadPackageManifest,
LoadCachePackageHash,
LoadCachePackageManifest,
Done,
}
private readonly CacheFileSystem _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 CFSLoadPackageManifestOperation(CacheFileSystem fileSystem, string packageVersion, int timeout)
{
_fileSystem = fileSystem;
_packageVersion = packageVersion;
_timeout = timeout;
}
internal override void InternalStart()
{
_steps = ESteps.DownloadPackageHash;
}
internal 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;
Status = EOperationStatus.Failed;
Error = _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.LoadCachePackageHash;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _downloadPackageManifestOp.Error;
}
}
if (_steps == ESteps.LoadCachePackageHash)
{
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.LoadCachePackageManifest;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _loadCachePackageHashOp.Error;
ClearCacheFatalFile();
}
}
if (_steps == ESteps.LoadCachePackageManifest)
{
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;
Manifest = _loadCachePackageManifestOp.Manifest;
Status = EOperationStatus.Succeeded;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _loadCachePackageManifestOp.Error;
ClearCacheFatalFile();
}
}
}
private void ClearCacheFatalFile()
{
// 注意:如果加载沙盒内的清单报错,为了避免流程被卡住,主动把损坏的文件删除。
string manifestFilePath = _fileSystem.GetCachePackageManifestFilePath(_packageVersion);
if (File.Exists(manifestFilePath))
{
YooLogger.Warning($"Invalid cache manifest file have been removed : {manifestFilePath}");
File.Delete(manifestFilePath);
}
string hashFilePath = _fileSystem.GetCachePackageHashFilePath(_packageVersion);
if (File.Exists(hashFilePath))
{
File.Delete(hashFilePath);
}
}
}
}

View File

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

View File

@@ -0,0 +1,64 @@

namespace YooAsset
{
internal class CFSRequestPackageVersionOperation : FSRequestVersionOperation
{
private enum ESteps
{
None,
GetPackageVersion,
Done,
}
private readonly CacheFileSystem _fileSystem;
private readonly bool _appendTimeTicks;
private readonly int _timeout;
private RequestRemotePackageVersionOperation _requestRemotePackageVersionOp;
private ESteps _steps = ESteps.None;
internal CFSRequestPackageVersionOperation(CacheFileSystem fileSystem, bool appendTimeTicks, int timeout)
{
_fileSystem = fileSystem;
_appendTimeTicks = appendTimeTicks;
_timeout = timeout;
}
internal override void InternalStart()
{
_steps = ESteps.GetPackageVersion;
}
internal 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;
Status = EOperationStatus.Succeeded;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _requestRemotePackageVersionOp.Error;
}
}
}
}
}

View File

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

View File

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

View File

@@ -0,0 +1,74 @@
using System.Collections;
using System.Collections.Generic;
namespace YooAsset
{
internal sealed class ClearAllCacheBundleFilesOperation : FSClearCacheOperation
{
private enum ESteps
{
None,
ClearCacheFiles,
Done,
}
private readonly CacheFileSystem _fileSystem;
private FCClearCacheOperation _clearCacheFileOp;
private ESteps _steps = ESteps.None;
internal ClearAllCacheBundleFilesOperation(CacheFileSystem fileSystem)
{
_fileSystem = fileSystem;
}
internal override void InternalStart()
{
_steps = ESteps.ClearCacheFiles;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.ClearCacheFiles)
{
if (_clearCacheFileOp == null)
{
var options = new FCClearCacheOptions();
options.BundleGUIDs = GetRemoveFiles();
_clearCacheFileOp = _fileSystem.Cache.ClearCacheAsync(options);
_clearCacheFileOp.StartOperation();
AddChildOperation(_clearCacheFileOp);
}
_clearCacheFileOp.UpdateOperation();
Progress = _clearCacheFileOp.Progress;
if (_clearCacheFileOp.IsDone == false)
return;
if (_clearCacheFileOp.Status == EOperationStatus.Succeeded)
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _clearCacheFileOp.Error;
}
}
}
private List<string> GetRemoveFiles()
{
var allEntrys = _fileSystem.Cache.GetAllEntries();
List<string> result = new List<string>(allEntrys.Count);
foreach (var entry in allEntrys)
{
result.Add(entry.BundleGUID);
}
return result;
}
}
}

View File

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

View File

@@ -0,0 +1,63 @@
using System;
using System.IO;
namespace YooAsset
{
internal sealed class ClearAllCacheManifestFilesOperation : FSClearCacheOperation
{
private enum ESteps
{
None,
ClearAllCacheFiles,
Done,
}
private readonly CacheFileSystem _fileSystem;
private ESteps _steps = ESteps.None;
internal ClearAllCacheManifestFilesOperation(CacheFileSystem fileSystem)
{
_fileSystem = fileSystem;
}
internal override void InternalStart()
{
_steps = ESteps.ClearAllCacheFiles;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.ClearAllCacheFiles)
{
try
{
// 注意:如果正在下载资源清单,会有几率触发异常!
string directoryRoot = _fileSystem.GetCacheManifestFilesRoot();
DirectoryInfo directoryInfo = new DirectoryInfo(directoryRoot);
if (directoryInfo.Exists)
{
foreach (FileInfo fileInfo in directoryInfo.GetFiles())
{
string fileName = fileInfo.Name;
if (fileName == DefaultCacheFileSystemDefine.AppFootPrintFileName)
continue;
fileInfo.Delete();
}
}
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
}
catch (Exception ex)
{
_steps = ESteps.Done;
Error = ex.Message;
Status = EOperationStatus.Failed;
}
}
}
}
}

View File

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

View File

@@ -0,0 +1,136 @@
using System.Collections.Generic;
namespace YooAsset
{
internal class ClearCacheBundleFilesByLocationsOperation : FSClearCacheOperation
{
private enum ESteps
{
None,
CheckManifest,
CheckArgs,
ClearCacheFiles,
Done,
}
private readonly CacheFileSystem _fileSystem;
private readonly PackageManifest _manifest;
private readonly object _clearParam;
private FCClearCacheOperation _clearCacheFileOp;
private string[] _locations;
private ESteps _steps = ESteps.None;
internal ClearCacheBundleFilesByLocationsOperation(CacheFileSystem fileSystem, PackageManifest manifest, object clearParam)
{
_fileSystem = fileSystem;
_manifest = manifest;
_clearParam = clearParam;
}
internal override void InternalStart()
{
_steps = ESteps.CheckManifest;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.CheckManifest)
{
if (_manifest == null)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = "Can not found active package manifest.";
}
else
{
_steps = ESteps.CheckArgs;
}
}
if (_steps == ESteps.CheckArgs)
{
if (_clearParam == null)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = "Clear param is null.";
return;
}
if (_clearParam is string)
{
_locations = new string[] { _clearParam as string };
}
else if (_clearParam is List<string>)
{
var tempList = _clearParam as List<string>;
_locations = tempList.ToArray();
}
else if (_clearParam is string[])
{
_locations = _clearParam as string[];
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Invalid clear param : {_clearParam.GetType().FullName}";
return;
}
_steps = ESteps.ClearCacheFiles;
}
if (_steps == ESteps.ClearCacheFiles)
{
if (_clearCacheFileOp == null)
{
var options = new FCClearCacheOptions();
options.BundleGUIDs = GetRemoveFiles();
_clearCacheFileOp = _fileSystem.Cache.ClearCacheAsync(options);
_clearCacheFileOp.StartOperation();
AddChildOperation(_clearCacheFileOp);
}
_clearCacheFileOp.UpdateOperation();
Progress = _clearCacheFileOp.Progress;
if (_clearCacheFileOp.IsDone == false)
return;
if (_clearCacheFileOp.Status == EOperationStatus.Succeeded)
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _clearCacheFileOp.Error;
}
}
}
private List<string> GetRemoveFiles()
{
List<string> result = new List<string>(_locations.Length);
foreach (var location in _locations)
{
string assetPath = _manifest.TryMappingToAssetPath(location);
if (_manifest.TryGetPackageAsset(assetPath, out PackageAsset packageAsset))
{
PackageBundle bundle = _manifest.GetMainPackageBundle(packageAsset.BundleID);
if (bundle != null)
{
result.Add(bundle.BundleGUID);
}
}
}
return result;
}
}
}

View File

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

View File

@@ -0,0 +1,132 @@
using System.Collections.Generic;
namespace YooAsset
{
internal class ClearCacheBundleFilesByTagsOperation : FSClearCacheOperation
{
private enum ESteps
{
None,
CheckManifest,
CheckArgs,
ClearCacheFiles,
Done,
}
private readonly CacheFileSystem _fileSystem;
private readonly PackageManifest _manifest;
private readonly object _clearParam;
private FCClearCacheOperation _clearCacheFileOp;
private string[] _tags;
private ESteps _steps = ESteps.None;
internal ClearCacheBundleFilesByTagsOperation(CacheFileSystem fileSystem, PackageManifest manifest, object clearParam)
{
_fileSystem = fileSystem;
_manifest = manifest;
_clearParam = clearParam;
}
internal override void InternalStart()
{
_steps = ESteps.CheckManifest;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.CheckManifest)
{
if (_manifest == null)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = "Can not found active package manifest.";
}
else
{
_steps = ESteps.CheckArgs;
}
}
if (_steps == ESteps.CheckArgs)
{
if (_clearParam == null)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = "Clear param is null.";
return;
}
if (_clearParam is string)
{
_tags = new string[] { _clearParam as string };
}
else if (_clearParam is List<string>)
{
var tempList = _clearParam as List<string>;
_tags = tempList.ToArray();
}
else if (_clearParam is string[])
{
_tags = _clearParam as string[];
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Invalid clear param : {_clearParam.GetType().FullName}";
return;
}
_steps = ESteps.ClearCacheFiles;
}
if (_steps == ESteps.ClearCacheFiles)
{
if (_clearCacheFileOp == null)
{
var options = new FCClearCacheOptions();
options.BundleGUIDs = GetRemoveFiles();
_clearCacheFileOp = _fileSystem.Cache.ClearCacheAsync(options);
_clearCacheFileOp.StartOperation();
AddChildOperation(_clearCacheFileOp);
}
_clearCacheFileOp.UpdateOperation();
Progress = _clearCacheFileOp.Progress;
if (_clearCacheFileOp.IsDone == false)
return;
if (_clearCacheFileOp.Status == EOperationStatus.Succeeded)
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _clearCacheFileOp.Error;
}
}
}
private List<string> GetRemoveFiles()
{
var allEntrys = _fileSystem.Cache.GetAllEntries();
List<string> result = new List<string>(allEntrys.Count);
foreach (var entry in allEntrys)
{
if (_manifest.TryGetPackageBundleByBundleGUID(entry.BundleGUID, out PackageBundle bundle))
{
if (bundle.HasTag(_tags))
{
result.Add(bundle.BundleGUID);
}
}
}
return result;
}
}
}

View File

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

View File

@@ -0,0 +1,93 @@
using System.Collections;
using System.Collections.Generic;
namespace YooAsset
{
internal sealed class ClearUnusedCacheBundleFilesOperation : FSClearCacheOperation
{
private enum ESteps
{
None,
CheckManifest,
ClearCacheFiles,
Done,
}
private readonly CacheFileSystem _fileSystem;
private readonly PackageManifest _manifest;
private FCClearCacheOperation _clearCacheFileOp;
private ESteps _steps = ESteps.None;
internal ClearUnusedCacheBundleFilesOperation(CacheFileSystem fileSystem, PackageManifest manifest)
{
_fileSystem = fileSystem;
_manifest = manifest;
}
internal override void InternalStart()
{
_steps = ESteps.CheckManifest;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.CheckManifest)
{
if (_manifest == null)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = "Can not found active package manifest.";
}
else
{
_steps = ESteps.ClearCacheFiles;
}
}
if (_steps == ESteps.ClearCacheFiles)
{
if (_clearCacheFileOp == null)
{
var options = new FCClearCacheOptions();
options.BundleGUIDs = GetRemoveFiles();
_clearCacheFileOp = _fileSystem.Cache.ClearCacheAsync(options);
_clearCacheFileOp.StartOperation();
AddChildOperation(_clearCacheFileOp);
}
_clearCacheFileOp.UpdateOperation();
Progress = _clearCacheFileOp.Progress;
if (_clearCacheFileOp.IsDone == false)
return;
if (_clearCacheFileOp.Status == EOperationStatus.Succeeded)
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _clearCacheFileOp.Error;
}
}
}
private List<string> GetRemoveFiles()
{
var allEntrys = _fileSystem.Cache.GetAllEntries();
List<string> result = new List<string>(allEntrys.Count);
foreach (var entry in allEntrys)
{
if (_manifest.IsIncludeBundleFile(entry.BundleGUID) == false)
{
result.Add(entry.BundleGUID);
}
}
return result;
}
}
}

View File

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

View File

@@ -0,0 +1,85 @@
using System;
using System.IO;
namespace YooAsset
{
internal sealed class ClearUnusedCacheManifestFilesOperation : FSClearCacheOperation
{
private enum ESteps
{
None,
CheckManifest,
ClearUnusedCacheFiles,
Done,
}
private readonly CacheFileSystem _fileSystem;
private readonly PackageManifest _manifest;
private ESteps _steps = ESteps.None;
internal ClearUnusedCacheManifestFilesOperation(CacheFileSystem fileSystem, PackageManifest manifest)
{
_fileSystem = fileSystem;
_manifest = manifest;
}
internal override void InternalStart()
{
_steps = ESteps.CheckManifest;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.CheckManifest)
{
if (_manifest == null)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = "Can not found active package manifest.";
}
else
{
_steps = ESteps.ClearUnusedCacheFiles;
}
}
if (_steps == ESteps.ClearUnusedCacheFiles)
{
try
{
string activeManifestFileName = YooAssetSettingsData.GetManifestBinaryFileName(_manifest.PackageName, _manifest.PackageVersion);
string activeHashFileName = YooAssetSettingsData.GetPackageHashFileName(_manifest.PackageName, _manifest.PackageVersion);
// 注意:如果正在下载资源清单,会有几率触发异常!
string directoryRoot = _fileSystem.GetCacheManifestFilesRoot();
DirectoryInfo directoryInfo = new DirectoryInfo(directoryRoot);
if (directoryInfo.Exists)
{
foreach (FileInfo fileInfo in directoryInfo.GetFiles())
{
string fileName = fileInfo.Name;
if (fileName == DefaultCacheFileSystemDefine.AppFootPrintFileName)
continue;
if (fileName == activeManifestFileName || fileName == activeHashFileName)
continue;
fileInfo.Delete();
}
}
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
}
catch (Exception ex)
{
_steps = ESteps.Done;
Error = ex.Message;
Status = EOperationStatus.Failed;
}
}
}
}
}

View File

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

View File

@@ -0,0 +1,154 @@
using System.IO;
using UnityEngine;
namespace YooAsset
{
internal class DownloadPackageBundleOperation : FSDownloadFileOperation
{
protected enum ESteps
{
None,
CheckExists,
CreateRequest,
CheckRequest,
TryAgain,
Done,
}
// 下载参数
protected readonly CacheFileSystem _fileSystem;
protected readonly DownloadFileOptions _options;
private DownloadAndCacheFileOperation _downloadFileOp;
protected int _requestCount = 0;
protected float _tryAgainTimer = 0;
protected int _failedTryAgain;
private ESteps _steps = ESteps.None;
internal DownloadPackageBundleOperation(CacheFileSystem fileSystem, DownloadFileOptions options) : base(options.Bundle)
{
_fileSystem = fileSystem;
_options = options;
_failedTryAgain = options.FailedTryAgain;
}
internal override void InternalStart()
{
_steps = ESteps.CheckExists;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
// 检测文件是否存在
if (_steps == ESteps.CheckExists)
{
if (_fileSystem.Exists(Bundle))
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
}
else
{
_steps = ESteps.CreateRequest;
}
}
// 创建下载器
if (_steps == ESteps.CreateRequest)
{
if (_options.IsValid() == false)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = "Download file options is invalid.";
Debug.Log(Error);
return;
}
string url = GetRequestURL();
_downloadFileOp = _fileSystem.DownloadScheduler.DownloadAndCacheFileAsync(Bundle, url);
_steps = ESteps.CheckRequest;
}
// 检测下载结果
if (_steps == ESteps.CheckRequest)
{
if (IsWaitForCompletion)
_downloadFileOp.WaitForCompletion();
_downloadFileOp.UpdateOperation();
Progress = _downloadFileOp.Progress;
DownloadedBytes = _downloadFileOp.DownloadedBytes;
DownloadProgress = _downloadFileOp.DownloadProgress;
if (_downloadFileOp.IsDone == false)
return;
if (_downloadFileOp.Status == EOperationStatus.Succeeded)
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
}
else
{
if (IsWaitForCompletion == false && _failedTryAgain > 0)
{
_steps = ESteps.TryAgain;
YooLogger.Warning($"Failed download : {_downloadFileOp.URL} Try again.");
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _downloadFileOp.Error;
YooLogger.Error(Error);
}
}
}
// 重新尝试下载
if (_steps == ESteps.TryAgain)
{
_tryAgainTimer += Time.unscaledDeltaTime;
if (_tryAgainTimer > 1f)
{
_tryAgainTimer = 0f;
_failedTryAgain--;
Progress = 0f;
DownloadProgress = 0f;
DownloadedBytes = 0;
_steps = ESteps.CreateRequest;
}
}
}
internal override void InternalWaitForCompletion()
{
ExecuteBatch();
}
internal override void InternalAbort()
{
// 注意:取消下载任务的时候引用计数减一
if (_steps != ESteps.Done)
{
if (_downloadFileOp != null)
{
_downloadFileOp.Release();
}
}
}
/// <summary>
/// 获取网络请求地址
/// </summary>
protected string GetRequestURL()
{
// 轮流返回请求地址
_requestCount++;
if (_requestCount % 2 == 0)
return _options.FallbackURL;
else
return _options.MainURL;
}
}
}

View File

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

View File

@@ -0,0 +1,93 @@
using System.IO;
namespace YooAsset
{
internal class DownloadPackageHashOperation : AsyncOperationBase
{
private enum ESteps
{
None,
CheckExist,
DownloadFile,
Done,
}
private readonly CacheFileSystem _fileSystem;
private readonly string _packageVersion;
private readonly int _timeout;
private IDownloadFileRequest _webFileRequestOp;
private int _requestCount = 0;
private ESteps _steps = ESteps.None;
internal DownloadPackageHashOperation(CacheFileSystem fileSystem, string packageVersion, int timeout)
{
_fileSystem = fileSystem;
_packageVersion = packageVersion;
_timeout = timeout;
}
internal override void InternalStart()
{
_requestCount = DownloadFailureCounter.GetFailureCount(_fileSystem.PackageName, nameof(DownloadPackageHashOperation));
_steps = ESteps.CheckExist;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.CheckExist)
{
string filePath = _fileSystem.GetCachePackageHashFilePath(_packageVersion);
if (File.Exists(filePath))
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
}
else
{
_steps = ESteps.DownloadFile;
}
}
if (_steps == ESteps.DownloadFile)
{
if (_webFileRequestOp == null)
{
string savePath = _fileSystem.GetCachePackageHashFilePath(_packageVersion);
string fileName = YooAssetSettingsData.GetPackageHashFileName(_fileSystem.PackageName, _packageVersion);
string webURL = GetWebRequestURL(fileName);
int watchdogTime = _fileSystem.DownloadWatchDogTimeout;
var args = new DownloadFileRequestArgs(webURL, savePath, _timeout, watchdogTime);
_webFileRequestOp = _fileSystem.DownloadBackend.CreateFileRequest(args);
_webFileRequestOp.SendRequest();
}
if (_webFileRequestOp.IsDone == false)
return;
if (_webFileRequestOp.Status == EDownloadRequestStatus.Succeed)
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _webFileRequestOp.Error;
DownloadFailureCounter.RecordFailure(_fileSystem.PackageName, nameof(DownloadPackageHashOperation));
}
}
}
private string GetWebRequestURL(string fileName)
{
// 轮流返回请求地址
if (_requestCount % 2 == 0)
return _fileSystem.RemoteServices.GetRemoteMainURL(fileName);
else
return _fileSystem.RemoteServices.GetRemoteFallbackURL(fileName);
}
}
}

View File

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

View File

@@ -0,0 +1,93 @@
using System.IO;
namespace YooAsset
{
internal class DownloadPackageManifestOperation : AsyncOperationBase
{
private enum ESteps
{
None,
CheckExist,
DownloadFile,
Done,
}
private readonly CacheFileSystem _fileSystem;
private readonly string _packageVersion;
private readonly int _timeout;
private IDownloadFileRequest _webFileRequestOp;
private int _requestCount = 0;
private ESteps _steps = ESteps.None;
internal DownloadPackageManifestOperation(CacheFileSystem fileSystem, string packageVersion, int timeout)
{
_fileSystem = fileSystem;
_packageVersion = packageVersion;
_timeout = timeout;
}
internal override void InternalStart()
{
_requestCount = DownloadFailureCounter.GetFailureCount(_fileSystem.PackageName, nameof(DownloadPackageManifestOperation));
_steps = ESteps.CheckExist;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.CheckExist)
{
string filePath = _fileSystem.GetCachePackageManifestFilePath(_packageVersion);
if (File.Exists(filePath))
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
}
else
{
_steps = ESteps.DownloadFile;
}
}
if (_steps == ESteps.DownloadFile)
{
if (_webFileRequestOp == null)
{
string savePath = _fileSystem.GetCachePackageManifestFilePath(_packageVersion);
string fileName = YooAssetSettingsData.GetManifestBinaryFileName(_fileSystem.PackageName, _packageVersion);
string webURL = GetDownloadRequestURL(fileName);
int watchdogTime = _fileSystem.DownloadWatchDogTimeout;
var args = new DownloadFileRequestArgs(webURL, savePath, _timeout, watchdogTime);
_webFileRequestOp = _fileSystem.DownloadBackend.CreateFileRequest(args);
_webFileRequestOp.SendRequest();
}
if (_webFileRequestOp.IsDone == false)
return;
if (_webFileRequestOp.Status == EDownloadRequestStatus.Succeed)
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _webFileRequestOp.Error;
DownloadFailureCounter.RecordFailure(_fileSystem.PackageName, nameof(DownloadPackageManifestOperation));
}
}
}
private string GetDownloadRequestURL(string fileName)
{
// 轮流返回请求地址
if (_requestCount % 2 == 0)
return _fileSystem.RemoteServices.GetRemoteMainURL(fileName);
else
return _fileSystem.RemoteServices.GetRemoteFallbackURL(fileName);
}
}
}

View File

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

View File

@@ -0,0 +1,64 @@
using System.IO;
namespace YooAsset
{
internal class LoadCachePackageHashOperation : AsyncOperationBase
{
private enum ESteps
{
None,
LoadPackageHash,
Done,
}
private readonly CacheFileSystem _fileSystem;
private readonly string _packageVersion;
private ESteps _steps = ESteps.None;
/// <summary>
/// 包裹哈希值
/// </summary>
public string PackageHash { private set; get; }
internal LoadCachePackageHashOperation(CacheFileSystem fileSystem, string packageVersion)
{
_fileSystem = fileSystem;
_packageVersion = packageVersion;
}
internal override void InternalStart()
{
_steps = ESteps.LoadPackageHash;
}
internal 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;
Status = EOperationStatus.Failed;
Error = $"Can not found cache package hash file : {filePath}";
return;
}
PackageHash = FileUtility.ReadAllText(filePath);
if (string.IsNullOrEmpty(PackageHash))
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Cache package hash file content is empty.";
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
}
}
}
}
}

View File

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

View File

@@ -0,0 +1,107 @@
using System.IO;
namespace YooAsset
{
internal class LoadCachePackageManifestOperation : AsyncOperationBase
{
private enum ESteps
{
None,
LoadFileData,
VerifyFileData,
LoadManifest,
Done,
}
private readonly CacheFileSystem _fileSystem;
private readonly string _packageVersion;
private readonly string _packageHash;
private DeserializeManifestOperation _deserializer;
private byte[] _fileData;
private ESteps _steps = ESteps.None;
/// <summary>
/// 包裹清单
/// </summary>
public PackageManifest Manifest { private set; get; }
internal LoadCachePackageManifestOperation(CacheFileSystem fileSystem, string packageVersion, string packageHash)
{
_fileSystem = fileSystem;
_packageVersion = packageVersion;
_packageHash = packageHash;
}
internal override void InternalStart()
{
_steps = ESteps.LoadFileData;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.LoadFileData)
{
string manifestFilePath = _fileSystem.GetCachePackageManifestFilePath(_packageVersion);
if (File.Exists(manifestFilePath))
{
_steps = ESteps.VerifyFileData;
_fileData = File.ReadAllBytes(manifestFilePath);
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Can not found cache manifest file : {manifestFilePath}";
}
}
if (_steps == ESteps.VerifyFileData)
{
if (PackageManifestTools.VerifyManifestData(_fileData, _packageHash))
{
_steps = ESteps.LoadManifest;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = "Failed to verify cache package manifest file.";
}
}
if (_steps == ESteps.LoadManifest)
{
if (_deserializer == null)
{
_deserializer = new DeserializeManifestOperation(_fileSystem.ManifestRestoreServices, _fileData);
_deserializer.StartOperation();
AddChildOperation(_deserializer);
}
_deserializer.UpdateOperation();
Progress = _deserializer.Progress;
if (_deserializer.IsDone == false)
return;
if (_deserializer.Status == EOperationStatus.Succeeded)
{
_steps = ESteps.Done;
Manifest = _deserializer.Manifest;
Status = EOperationStatus.Succeeded;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _deserializer.Error;
}
}
}
internal override string InternalGetDescription()
{
return $"PackageVersion : {_packageVersion} PackageHash : {_packageHash}";
}
}
}

View File

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

View File

@@ -0,0 +1,100 @@

namespace YooAsset
{
internal class RequestRemotePackageVersionOperation : AsyncOperationBase
{
private enum ESteps
{
None,
RequestPackageVersion,
Done,
}
private readonly CacheFileSystem _fileSystem;
private readonly bool _appendTimeTicks;
private readonly int _timeout;
private IDownloadTextRequest _webTextRequestOp;
private int _requestCount = 0;
private ESteps _steps = ESteps.None;
/// <summary>
/// 包裹版本
/// </summary>
internal string PackageVersion { set; get; }
internal RequestRemotePackageVersionOperation(CacheFileSystem fileSystem, bool appendTimeTicks, int timeout)
{
_fileSystem = fileSystem;
_appendTimeTicks = appendTimeTicks;
_timeout = timeout;
}
internal override void InternalStart()
{
_requestCount = DownloadFailureCounter.GetFailureCount(_fileSystem.PackageName, nameof(RequestRemotePackageVersionOperation));
_steps = ESteps.RequestPackageVersion;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.RequestPackageVersion)
{
if (_webTextRequestOp == null)
{
string fileName = YooAssetSettingsData.GetPackageVersionFileName(_fileSystem.PackageName);
string url = GetWebRequestURL(fileName);
int watchDogTime = _fileSystem.DownloadWatchDogTimeout;
var args = new DownloadDataRequestArgs(url, _timeout, watchDogTime);
_webTextRequestOp = _fileSystem.DownloadBackend.CreateTextRequest(args);
_webTextRequestOp.SendRequest();
}
Progress = _webTextRequestOp.DownloadProgress;
if (_webTextRequestOp.IsDone == false)
return;
if (_webTextRequestOp.Status == EDownloadRequestStatus.Succeed)
{
PackageVersion = _webTextRequestOp.Result;
if (string.IsNullOrEmpty(PackageVersion))
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Remote package version file content is empty.";
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
}
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _webTextRequestOp.Error;
DownloadFailureCounter.RecordFailure(_fileSystem.PackageName, nameof(RequestRemotePackageVersionOperation));
}
}
}
private string GetWebRequestURL(string fileName)
{
string url;
// 轮流返回请求地址
if (_requestCount % 2 == 0)
url = _fileSystem.RemoteServices.GetRemoteMainURL(fileName);
else
url = _fileSystem.RemoteServices.GetRemoteFallbackURL(fileName);
// 在URL末尾添加时间戳
if (_appendTimeTicks)
return $"{url}?{System.DateTime.UtcNow.Ticks}";
else
return url;
}
}
}

View File

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

View File

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

View File

@@ -0,0 +1,51 @@

namespace YooAsset
{
internal abstract class DownloadAndCacheFileOperation : AsyncOperationBase
{
/// <summary>
/// 引用计数
/// </summary>
public int RefCount { private set; get; }
/// <summary>
/// 下载地址
/// </summary>
public readonly string URL;
/// <summary>
/// 下载进度
/// </summary>
public float DownloadProgress { get; protected set; }
/// <summary>
/// 下载字节
/// </summary>
public long DownloadedBytes { get; protected set; }
public DownloadAndCacheFileOperation(string url)
{
URL = url;
}
internal override string InternalGetDescription()
{
return $"RefCount : {RefCount}";
}
/// <summary>
/// 减少引用计数
/// </summary>
public void Release()
{
RefCount--;
}
/// <summary>
/// 增加引用计数
/// </summary>
public void Reference()
{
RefCount++;
}
}
}

View File

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

View File

@@ -0,0 +1,174 @@
using System.IO;
namespace YooAsset
{
internal sealed class DownloadAndCacheLocalFileOperation : DownloadAndCacheFileOperation
{
private enum ESteps
{
None,
CheckCopy,
CopyLocalFile,
CreateRequest,
CheckRequest,
CacheFile,
Done,
}
private readonly CacheFileSystem _fileSystem;
private readonly PackageBundle _bundle;
private readonly string _tempFilePath;
private IDownloadRequest _request;
private FCStoreCacheOperation _bundleCacheOp;
private ESteps _steps = ESteps.None;
internal DownloadAndCacheLocalFileOperation(CacheFileSystem fileSystem, PackageBundle bundle, string url) : base(url)
{
_fileSystem = fileSystem;
_bundle = bundle;
_tempFilePath = _fileSystem.GetTempFilePath(_bundle);
}
internal override void InternalStart()
{
_steps = ESteps.CheckCopy;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
// 检测文件拷贝
if (_steps == ESteps.CheckCopy)
{
// 删除历史缓存文件
FileUtility.CreateFileDirectory(_tempFilePath);
if (File.Exists(_tempFilePath))
File.Delete(_tempFilePath);
if (_fileSystem.CopyLocalFileServices != null)
_steps = ESteps.CopyLocalFile;
else
_steps = ESteps.CreateRequest;
}
// 拷贝本地文件
if (_steps == ESteps.CopyLocalFile)
{
try
{
//TODO 团结引擎,在某些机型(红米),拷贝包内文件会小概率失败!需要借助其它方式来拷贝包内文件。
var localFileInfo = new LocalFileInfo();
localFileInfo.PackageName = _fileSystem.PackageName;
localFileInfo.BundleName = _bundle.BundleName;
localFileInfo.SourceFileURL = URL;
_fileSystem.CopyLocalFileServices.CopyFile(localFileInfo, _tempFilePath);
if (File.Exists(_tempFilePath))
{
DownloadProgress = 1f;
DownloadedBytes = _bundle.FileSize;
_steps = ESteps.CacheFile;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Failed copy local file : {URL}";
}
}
catch (System.Exception ex)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Failed copy local file : {ex.Message}";
}
}
// 创建下载请求
if (_steps == ESteps.CreateRequest)
{
int watchdogTime = _fileSystem.DownloadWatchDogTimeout;
int timeout = 0; //注意:文件下载不做超时检测
var args = new DownloadFileRequestArgs(URL, _tempFilePath, timeout, watchdogTime);
_request = _fileSystem.DownloadBackend.CreateFileRequest(args);
_request.SendRequest();
_steps = ESteps.CheckRequest;
}
// 检测下载结果
if (_steps == ESteps.CheckRequest)
{
//TODO 更新下载后台,防止无限挂起
if (IsWaitForCompletion)
_fileSystem.DownloadBackend.Update();
DownloadProgress = _request.DownloadProgress;
DownloadedBytes = _request.DownloadedBytes;
Progress = DownloadProgress;
if (_request.IsDone == false)
return;
// 检查网络错误
if (_request.Status == EDownloadRequestStatus.Succeed)
{
_steps = ESteps.CacheFile;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _request.Error;
}
// 最终释放请求器
_request.Dispose();
}
// 缓存文件
if (_steps == ESteps.CacheFile)
{
if (_bundleCacheOp == null)
{
var options = new FCStoreCacheOptions();
options.Bundle = _bundle;
options.FilePath = _tempFilePath;
_bundleCacheOp = _fileSystem.Cache.StoreCacheAsync(options);
_bundleCacheOp.StartOperation();
AddChildOperation(_bundleCacheOp);
}
if (IsWaitForCompletion)
_bundleCacheOp.WaitForCompletion();
_bundleCacheOp.UpdateOperation();
if (_bundleCacheOp.IsDone == false)
return;
if (_bundleCacheOp.Status == EOperationStatus.Succeeded)
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _bundleCacheOp.Error;
}
// 注意:缓存完成后直接删除临时文件
if (File.Exists(_tempFilePath))
File.Delete(_tempFilePath);
}
}
internal override void InternalAbort()
{
if (_request != null)
_request.Dispose();
}
internal override void InternalWaitForCompletion()
{
//TODO 等待导入或解压本地文件完毕,该操作会挂起主线程!
ExecuteUntilComplete();
}
}
}

View File

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

View File

@@ -0,0 +1,185 @@
using System.IO;
namespace YooAsset
{
internal sealed class DownloadAndCacheRemoteFileOperation : DownloadAndCacheFileOperation
{
private enum ESteps
{
None,
CreateRequest,
CheckRequest,
CacheFile,
Done,
}
private readonly CacheFileSystem _fileSystem;
private readonly PackageBundle _bundle;
private readonly string _tempFilePath;
private bool _enableResume = false;
private long _fileOriginLength = 0;
private IDownloadRequest _request;
private FCStoreCacheOperation _bundleCacheOp;
private ESteps _steps = ESteps.None;
internal DownloadAndCacheRemoteFileOperation(CacheFileSystem fileSystem, PackageBundle bundle, string url) : base(url)
{
_fileSystem = fileSystem;
_bundle = bundle;
_tempFilePath = _fileSystem.GetTempFilePath(_bundle);
}
internal override void InternalStart()
{
_steps = ESteps.CreateRequest;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
// 创建下载请求
if (_steps == ESteps.CreateRequest)
{
FileUtility.CreateFileDirectory(_tempFilePath);
_enableResume = _bundle.FileSize >= _fileSystem.ResumeDownloadMinimumSize;
if (_enableResume)
{
_request = CreateResumeRequest();
_request.SendRequest();
_steps = ESteps.CheckRequest;
}
else
{
_request = CreateNormalRequest();
_request.SendRequest();
_steps = ESteps.CheckRequest;
}
}
// 检测下载结果
if (_steps == ESteps.CheckRequest)
{
DownloadProgress = _request.DownloadProgress;
DownloadedBytes = _fileOriginLength + _request.DownloadedBytes;
Progress = DownloadProgress;
if (_request.IsDone == false)
return;
// 检查网络错误
if (_request.Status == EDownloadRequestStatus.Succeed)
{
_steps = ESteps.CacheFile;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _request.Error;
}
// 在遇到特殊错误的时候删除文件
if (_enableResume)
ClearTempFileWhenError(_request.HttpCode);
// 最终释放请求器
_request.Dispose();
}
// 缓存文件
if (_steps == ESteps.CacheFile)
{
if (_bundleCacheOp == null)
{
var options = new FCStoreCacheOptions();
options.Bundle = _bundle;
options.FilePath = _tempFilePath;
_bundleCacheOp = _fileSystem.Cache.StoreCacheAsync(options);
_bundleCacheOp.StartOperation();
AddChildOperation(_bundleCacheOp);
}
_bundleCacheOp.UpdateOperation();
if (_bundleCacheOp.IsDone == false)
return;
if (_bundleCacheOp.Status == EOperationStatus.Succeeded)
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _bundleCacheOp.Error;
}
// 注意:缓存完成后直接删除临时文件
if (File.Exists(_tempFilePath))
File.Delete(_tempFilePath);
}
}
internal override void InternalAbort()
{
if (_request != null)
_request.Dispose();
}
internal override void InternalWaitForCompletion()
{
if (_steps != ESteps.Done)
{
// 注意:不中断下载任务,保持后台继续下载
YooLogger.Error($"Try load bundle {_bundle.BundleName} from remote : {URL}");
}
}
private IDownloadRequest CreateResumeRequest()
{
// 获取下载起始位置
if (File.Exists(_tempFilePath))
{
FileInfo fileInfo = new FileInfo(_tempFilePath);
if (fileInfo.Length >= _bundle.FileSize)
{
File.Delete(_tempFilePath);
}
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, _tempFilePath, timeout, watchdogTime, appendToFile, removeFileOnAbort, resumeOffset);
return _fileSystem.DownloadBackend.CreateFileRequest(args);
}
private IDownloadRequest CreateNormalRequest()
{
// 删除历史缓存文件
if (File.Exists(_tempFilePath))
File.Delete(_tempFilePath);
int watchdogTime = _fileSystem.DownloadWatchDogTimeout;
int timeout = 0; //注意:文件下载不做超时检测
var args = new DownloadFileRequestArgs(URL, _tempFilePath, timeout, watchdogTime);
return _fileSystem.DownloadBackend.CreateFileRequest(args);
}
private void ClearTempFileWhenError(long httpCode)
{
if (_fileSystem.ResumeDownloadResponseCodes == null)
return;
//说明:如果遇到以下错误返回码,验证失败直接删除文件
if (_fileSystem.ResumeDownloadResponseCodes.Contains(httpCode))
{
if (File.Exists(_tempFilePath))
File.Delete(_tempFilePath);
}
}
}
}

View File

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

View File

@@ -0,0 +1,182 @@
using System;
using System.Collections.Generic;
namespace YooAsset
{
/// <summary>
/// 下载调度器
/// </summary>
/// <remarks>
/// 管理所有活跃的下载任务,控制并发数量。
/// </remarks>
internal class DownloadSchedulerOperation : AsyncOperationBase, IDisposable
{
private readonly CacheFileSystem _fileSystem;
private readonly Dictionary<string, DownloadAndCacheFileOperation> _downloaders = new Dictionary<string, DownloadAndCacheFileOperation>(1000);
private readonly List<string> _removeList = new List<string>(1000);
/// <summary>
/// 是否已暂停
/// </summary>
public bool Paused { get; private set; } = false;
/// <summary>
/// 当前活跃的下载任务数
/// </summary>
public int ActiveDownloadCount { get; private set; }
/// <summary>
/// 当前等待中的下载任务数
/// </summary>
public int PendingDownloadCount
{
get
{
return _downloaders.Count - ActiveDownloadCount;
}
}
/// <summary>
/// 构造下载中心
/// </summary>
public DownloadSchedulerOperation(CacheFileSystem fileSystem)
{
_fileSystem = fileSystem;
}
internal override void InternalStart()
{
}
internal override void InternalUpdate()
{
// 驱动下载后台
_fileSystem.DownloadBackend.Update();
// 获取可移除的下载器集合
_removeList.Clear();
foreach (var valuePair in _downloaders)
{
var downloader = valuePair.Value;
downloader.UpdateOperation();
if (downloader.IsDone)
{
_removeList.Add(valuePair.Key);
continue;
}
// 注意:主动终止引用计数为零的下载任务
if (downloader.RefCount <= 0)
{
_removeList.Add(valuePair.Key);
downloader.AbortOperation();
continue;
}
}
// 移除下载器
foreach (var key in _removeList)
{
if (_downloaders.TryGetValue(key, out var downloader))
{
RemoveChildOperation(downloader);
_downloaders.Remove(key);
}
}
// 暂停时不启动新任务
if (Paused)
return;
// 最大并发数检测
ActiveDownloadCount = GetProcessingOperationCount();
if (ActiveDownloadCount != _downloaders.Count)
{
int maxConcurrency = _fileSystem.DownloadMaxConcurrency;
int maxRequestPerFrame = _fileSystem.DownloadMaxRequestPerFrame;
if (ActiveDownloadCount < maxConcurrency)
{
int startCount = maxConcurrency - ActiveDownloadCount;
if (startCount > maxRequestPerFrame)
startCount = maxRequestPerFrame;
foreach (var operationPair in _downloaders)
{
var operation = operationPair.Value;
if (operation.Status == EOperationStatus.None)
{
operation.StartOperation();
startCount--;
if (startCount <= 0)
break;
}
}
}
}
}
internal override string InternalGetDescription()
{
return $"{_fileSystem.GetType().FullName}";
}
/// <summary>
/// 释放下载资源
/// </summary>
public void Dispose()
{
foreach (var valuePair in _downloaders)
{
var operation = valuePair.Value;
operation.AbortOperation();
}
_downloaders.Clear();
}
/// <summary>
/// 创建下载任务
/// </summary>
/// <param name="bundle">资源包信息</param>
/// <param name="url">下载地址</param>
/// <returns>下载操作</returns>
public DownloadAndCacheFileOperation DownloadAndCacheFileAsync(PackageBundle bundle, string url)
{
// 查询旧的下载器
if (_downloaders.TryGetValue(bundle.BundleGUID, out var oldDownloader))
{
oldDownloader.Reference();
return oldDownloader;
}
// 创建新的下载器
DownloadAndCacheFileOperation newDownloader;
bool isRequestLocalFile = DownloadSystemTools.IsLocalFileURL(url);
if (isRequestLocalFile)
{
newDownloader = new DownloadAndCacheLocalFileOperation(_fileSystem, bundle, url);
}
else
{
newDownloader = new DownloadAndCacheRemoteFileOperation(_fileSystem, bundle, url);
}
AddChildOperation(newDownloader);
_downloaders.Add(bundle.BundleGUID, newDownloader);
newDownloader.Reference();
return newDownloader;
}
/// <summary>
/// 获取正在进行中的下载器总数
/// </summary>
private int GetProcessingOperationCount()
{
int count = 0;
foreach (var operationPair in _downloaders)
{
var operation = operationPair.Value;
if (operation.Status != EOperationStatus.None)
count++;
}
return count;
}
}
}

View File

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

View File

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

View File

@@ -0,0 +1,252 @@
using System;
using System.Collections.Generic;
namespace YooAsset
{
/// <summary>
/// 模拟文件系统
/// </summary>
internal class EditorFileSystem : IFileSystem
{
protected readonly Dictionary<string, string> _records = new Dictionary<string, string>(10000);
protected string _packageRoot;
/// <summary>
/// 下载后台接口
/// </summary>
public IDownloadBackend DownloadBackend { private set; get; }
/// <summary>
/// 包裹名称
/// </summary>
public string PackageName { private set; get; }
/// <summary>
/// 文件根目录
/// </summary>
public string FileRoot
{
get
{
return _packageRoot;
}
}
/// <summary>
/// 文件数量
/// </summary>
public int FileCount
{
get
{
return 0;
}
}
#region
/// <summary>
/// 自定义参数UnityWebRequest 创建委托
/// </summary>
public UnityWebRequestCreator WebRequestCreator { private set; get; }
/// <summary>
/// 模拟WebGL平台模式
/// </summary>
public bool VirtualWebGLMode { private set; get; } = false;
/// <summary>
/// 模拟虚拟下载模式
/// </summary>
public bool VirtualDownloadMode { private set; get; } = false;
/// <summary>
/// 模拟虚拟下载的网速(单位:字节)
/// </summary>
public int VirtualDownloadSpeed { private set; get; } = 1024;
/// <summary>
/// 异步模拟加载最小帧数
/// </summary>
public int AsyncSimulateMinFrame { private set; get; } = 1;
/// <summary>
/// 异步模拟加载最大帧数
/// </summary>
public int AsyncSimulateMaxFrame { private set; get; } = 1;
#endregion
public EditorFileSystem()
{
}
public virtual FSInitializeOperation InitializeAsync()
{
var operation = new EFSInitializeOperation(this);
return operation;
}
public virtual FSRequestVersionOperation RequestVersionAsync(RequestVersionOptions options)
{
var operation = new EFSRequestVersionOperation(this);
return operation;
}
public virtual FSLoadManifestOperation LoadManifestAsync(LoadManifestOptions options)
{
var operation = new EFSLoadManifestOperation(this, options.PackageVersion);
return operation;
}
public virtual FSClearCacheOperation ClearCacheAsync(ClearCacheOptions options)
{
var operation = new FSClearCacheCompleteOperation();
return operation;
}
public virtual FSDownloadFileOperation DownloadFileAsync(DownloadFileOptions options)
{
string mainURL = options.Bundle.BundleName;
options.SetURL(mainURL, mainURL);
var downloader = new DownloadVirtualBundleOperation(this, options);
return downloader;
}
public virtual FSLoadBundleOperation LoadBundleAsync(LoadBundleOptions options)
{
PackageBundle bundle = options.Bundle;
if (bundle.BundleType == (int)EBundleType.VirtualBundle)
{
var operation = new EFSLoadBundleOperation(this, bundle);
return operation;
}
else
{
string error = $"{nameof(EditorFileSystem)} not support load bundle type : {bundle.BundleType}";
var operation = new FSLoadBundleCompleteOperation(error);
return operation;
}
}
public virtual void SetParameter(string name, object value)
{
if (name == FileSystemParametersDefine.DOWNLOAD_BACKEND)
{
DownloadBackend = (IDownloadBackend)value;
}
else if (name == FileSystemParametersDefine.UNITY_WEB_REQUEST_CREATOR)
{
WebRequestCreator = (UnityWebRequestCreator)value;
}
else if (name == FileSystemParametersDefine.VIRTUAL_WEBGL_MODE)
{
VirtualWebGLMode = Convert.ToBoolean(value);
}
else if (name == FileSystemParametersDefine.VIRTUAL_DOWNLOAD_MODE)
{
VirtualDownloadMode = Convert.ToBoolean(value);
}
else if (name == FileSystemParametersDefine.VIRTUAL_DOWNLOAD_SPEED)
{
VirtualDownloadSpeed = Convert.ToInt32(value);
}
else if (name == FileSystemParametersDefine.ASYNC_SIMULATE_MIN_FRAME)
{
AsyncSimulateMinFrame = Convert.ToInt32(value);
}
else if (name == FileSystemParametersDefine.ASYNC_SIMULATE_MAX_FRAME)
{
AsyncSimulateMaxFrame = Convert.ToInt32(value);
}
else
{
YooLogger.Warning($"Invalid parameter : {name}");
}
}
public virtual void OnCreate(string packageName, string packageRoot)
{
PackageName = packageName;
if (string.IsNullOrEmpty(packageRoot))
throw new YooFileSystemException($"{nameof(EditorFileSystem)} package root is null or empty.");
_packageRoot = packageRoot;
// 创建默认的下载后台接口
if (DownloadBackend == null)
DownloadBackend = new UnityWebRequestBackend(WebRequestCreator);
}
public virtual void OnDestroy()
{
if (DownloadBackend != null)
{
DownloadBackend.Dispose();
DownloadBackend = null;
}
}
public virtual bool Belong(PackageBundle bundle)
{
return true;
}
public virtual bool Exists(PackageBundle bundle)
{
if (VirtualDownloadMode)
{
return _records.ContainsKey(bundle.BundleGUID);
}
else
{
return true;
}
}
public virtual bool NeedDownload(PackageBundle bundle)
{
if (Belong(bundle) == false)
return false;
return Exists(bundle) == false;
}
public virtual bool NeedUnpack(PackageBundle bundle)
{
return false;
}
public virtual bool NeedImport(PackageBundle bundle)
{
return false;
}
public virtual string GetBundleFilePath(PackageBundle bundle)
{
if (bundle.IncludeMainAssets.Count == 0)
return string.Empty;
var pacakgeAsset = bundle.IncludeMainAssets[0];
return pacakgeAsset.AssetPath;
}
#region
public void RecordDownloadFile(PackageBundle bundle)
{
if (_records.ContainsKey(bundle.BundleGUID) == false)
_records.Add(bundle.BundleGUID, bundle.BundleName);
}
public string GetEditorPackageVersionFilePath()
{
string fileName = YooAssetSettingsData.GetPackageVersionFileName(PackageName);
return PathUtility.Combine(_packageRoot, fileName);
}
public string GetEditorPackageHashFilePath(string packageVersion)
{
string fileName = YooAssetSettingsData.GetPackageHashFileName(PackageName, packageVersion);
return PathUtility.Combine(_packageRoot, fileName);
}
public string GetEditorPackageManifestFilePath(string packageVersion)
{
string fileName = YooAssetSettingsData.GetManifestBinaryFileName(PackageName, packageVersion);
return PathUtility.Combine(_packageRoot, fileName);
}
public int GetAsyncSimulateFrame()
{
if (AsyncSimulateMinFrame > AsyncSimulateMaxFrame)
{
AsyncSimulateMinFrame = AsyncSimulateMaxFrame;
}
return UnityEngine.Random.Range(AsyncSimulateMinFrame, AsyncSimulateMaxFrame + 1);
}
#endregion
}
}

View File

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

View File

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

View File

@@ -0,0 +1,20 @@

namespace YooAsset
{
internal class EFSInitializeOperation : FSInitializeOperation
{
private readonly EditorFileSystem _fileSytem;
internal EFSInitializeOperation(EditorFileSystem fileSystem)
{
_fileSytem = fileSystem;
}
internal override void InternalStart()
{
Status = EOperationStatus.Succeeded;
}
internal override void InternalUpdate()
{
}
}
}

View File

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

View File

@@ -0,0 +1,148 @@

namespace YooAsset
{
internal class EFSLoadBundleOperation : FSLoadBundleOperation
{
protected enum ESteps
{
None,
CheckExist,
DownloadFile,
AbortDownload,
LoadAssetBundle,
CheckResult,
Done,
}
private readonly EditorFileSystem _fileSystem;
private readonly PackageBundle _bundle;
protected FSDownloadFileOperation _downloadFileOp;
private int _asyncSimulateFrame;
private ESteps _steps = ESteps.None;
internal EFSLoadBundleOperation(EditorFileSystem fileSystem, PackageBundle bundle)
{
_fileSystem = fileSystem;
_bundle = bundle;
}
internal override void InternalStart()
{
_steps = ESteps.CheckExist;
_asyncSimulateFrame = _fileSystem.GetAsyncSimulateFrame();
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.CheckExist)
{
if (_fileSystem.Exists(_bundle))
{
DownloadProgress = 1f;
DownloadedBytes = _bundle.FileSize;
_steps = ESteps.LoadAssetBundle;
}
else
{
_steps = ESteps.DownloadFile;
}
}
if (_steps == ESteps.DownloadFile)
{
// 中断下载
if (AbortDownloadFile)
{
if (_downloadFileOp != null)
_downloadFileOp.AbortOperation();
_steps = ESteps.AbortDownload;
}
}
if (_steps == ESteps.DownloadFile)
{
if (_downloadFileOp == null)
{
DownloadFileOptions options = new DownloadFileOptions(_bundle, int.MaxValue);
_downloadFileOp = _fileSystem.DownloadFileAsync(options);
_downloadFileOp.StartOperation();
AddChildOperation(_downloadFileOp);
}
if (IsWaitForCompletion)
_downloadFileOp.WaitForCompletion();
_downloadFileOp.UpdateOperation();
DownloadProgress = _downloadFileOp.DownloadProgress;
DownloadedBytes = _downloadFileOp.DownloadedBytes;
if (_downloadFileOp.IsDone == false)
return;
if (_downloadFileOp.Status == EOperationStatus.Succeeded)
{
_steps = ESteps.LoadAssetBundle;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _downloadFileOp.Error;
}
}
if (_steps == ESteps.AbortDownload)
{
if (_downloadFileOp != null)
{
if (IsWaitForCompletion)
_downloadFileOp.WaitForCompletion();
_downloadFileOp.UpdateOperation();
if (_downloadFileOp.IsDone == false)
return;
}
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = "Abort download file.";
}
if (_steps == ESteps.LoadAssetBundle)
{
if (IsWaitForCompletion)
{
if (_fileSystem.VirtualWebGLMode)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = "Virtual WebGL Mode only support asyn load method.";
YooLogger.Error(Error);
}
else
{
_steps = ESteps.CheckResult;
}
}
else
{
if (_asyncSimulateFrame <= 0)
_steps = ESteps.CheckResult;
else
_asyncSimulateFrame--;
}
}
if (_steps == ESteps.CheckResult)
{
_steps = ESteps.Done;
Result = new VirtualBundleResult(_fileSystem, _bundle);
Status = EOperationStatus.Succeeded;
}
}
internal override void InternalWaitForCompletion()
{
ExecuteBatch();
}
}
}

View File

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

View File

@@ -0,0 +1,90 @@

namespace YooAsset
{
internal class EFSLoadManifestOperation : FSLoadManifestOperation
{
private enum ESteps
{
None,
LoadEditorPackageHash,
LoadEditorPackageManifest,
Done,
}
private readonly EditorFileSystem _fileSystem;
private readonly string _packageVersion;
private LoadEditorPackageHashOperation _loadEditorPackageHashOpe;
private LoadEditorPackageManifestOperation _loadEditorPackageManifestOp;
private ESteps _steps = ESteps.None;
internal EFSLoadManifestOperation(EditorFileSystem fileSystem, string packageVersion)
{
_fileSystem = fileSystem;
_packageVersion = packageVersion;
}
internal override void InternalStart()
{
_steps = ESteps.LoadEditorPackageHash;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.LoadEditorPackageHash)
{
if (_loadEditorPackageHashOpe == null)
{
_loadEditorPackageHashOpe = new LoadEditorPackageHashOperation(_fileSystem, _packageVersion);
_loadEditorPackageHashOpe.StartOperation();
AddChildOperation(_loadEditorPackageHashOpe);
}
_loadEditorPackageHashOpe.UpdateOperation();
if (_loadEditorPackageHashOpe.IsDone == false)
return;
if (_loadEditorPackageHashOpe.Status == EOperationStatus.Succeeded)
{
_steps = ESteps.LoadEditorPackageManifest;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _loadEditorPackageHashOpe.Error;
}
}
if (_steps == ESteps.LoadEditorPackageManifest)
{
if (_loadEditorPackageManifestOp == null)
{
string packageHash = _loadEditorPackageHashOpe.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;
Manifest = _loadEditorPackageManifestOp.Manifest;
Status = EOperationStatus.Succeeded;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _loadEditorPackageManifestOp.Error;
}
}
}
}
}

View File

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

View File

@@ -0,0 +1,59 @@

namespace YooAsset
{
internal class EFSRequestVersionOperation : FSRequestVersionOperation
{
private enum ESteps
{
None,
LoadPackageVersion,
Done,
}
private readonly EditorFileSystem _fileSystem;
private LoadEditorPackageVersionOperation _loadEditorPackageVersionOp;
private ESteps _steps = ESteps.None;
internal EFSRequestVersionOperation(EditorFileSystem fileSystem)
{
_fileSystem = fileSystem;
}
internal override void InternalStart()
{
_steps = ESteps.LoadPackageVersion;
}
internal 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;
Status = EOperationStatus.Succeeded;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _loadEditorPackageVersionOp.Error;
}
}
}
}
}

View File

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

View File

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

View File

@@ -0,0 +1,148 @@
using UnityEngine;
namespace YooAsset
{
internal class DownloadVirtualBundleOperation : FSDownloadFileOperation
{
protected enum ESteps
{
None,
CheckExists,
CreateRequest,
CheckRequest,
TryAgain,
Done,
}
// 下载参数
protected readonly EditorFileSystem _fileSystem;
protected readonly DownloadFileOptions _options;
protected IDownloadFileRequest _downloadFileOp;
protected int _requestCount = 0;
protected float _tryAgainTimer = 0;
protected int _failedTryAgain;
private ESteps _steps = ESteps.None;
internal DownloadVirtualBundleOperation(EditorFileSystem fileSystem, DownloadFileOptions options) : base(options.Bundle)
{
_fileSystem = fileSystem;
_options = options;
_failedTryAgain = options.FailedTryAgain;
}
internal override void InternalStart()
{
_steps = ESteps.CheckExists;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
// 检测文件是否存在
if (_steps == ESteps.CheckExists)
{
if (_fileSystem.Exists(Bundle))
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
}
else
{
_steps = ESteps.CreateRequest;
}
}
// 创建下载器
if (_steps == ESteps.CreateRequest)
{
if (_options.IsValid() == false)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = "Download file options is invalid.";
Debug.Log(Error);
return;
}
string url = GetRequestURL();
int speed = _fileSystem.VirtualDownloadSpeed;
var args = new DownloadSimulateRequestArgs(url, Bundle.FileSize, speed);
_downloadFileOp = _fileSystem.DownloadBackend.CreateSimulateRequest(args);
_downloadFileOp.SendRequest();
_steps = ESteps.CheckRequest;
}
// 检测下载结果
if (_steps == ESteps.CheckRequest)
{
Progress = _downloadFileOp.DownloadProgress;
DownloadedBytes = _downloadFileOp.DownloadedBytes;
DownloadProgress = _downloadFileOp.DownloadProgress;
if (_downloadFileOp.IsDone == false)
return;
if (_downloadFileOp.Status == EDownloadRequestStatus.Succeed)
{
_fileSystem.RecordDownloadFile(Bundle);
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
}
else
{
if (IsWaitForCompletion == false && _failedTryAgain > 0)
{
_steps = ESteps.TryAgain;
YooLogger.Warning($"Failed download : {_downloadFileOp.URL} Try again.");
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _downloadFileOp.Error;
YooLogger.Error(Error);
}
}
}
// 重新尝试下载
if (_steps == ESteps.TryAgain)
{
_tryAgainTimer += Time.unscaledDeltaTime;
if (_tryAgainTimer > 1f)
{
_tryAgainTimer = 0f;
_failedTryAgain--;
Progress = 0f;
DownloadProgress = 0f;
DownloadedBytes = 0;
_steps = ESteps.CreateRequest;
}
}
}
internal override void InternalWaitForCompletion()
{
if (_steps != ESteps.Done)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Try load bundle {Bundle.BundleName} from remote.";
YooLogger.Error(Error);
}
}
/// <summary>
/// 获取网络请求地址
/// </summary>
protected string GetRequestURL()
{
// 轮流返回请求地址
_requestCount++;
if (_requestCount % 2 == 0)
return _options.FallbackURL;
else
return _options.MainURL;
}
}
}

View File

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

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