refactor : 重构代码

This commit is contained in:
何冠峰
2026-01-27 17:32:20 +08:00
parent 48a121f961
commit c2d8b8efcb
393 changed files with 7239 additions and 4598 deletions

View File

@@ -1,40 +0,0 @@
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

@@ -10,20 +10,27 @@ namespace YooAsset
/// </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 readonly Dictionary<string, string> _tempFilePathMapping = new Dictionary<string, string>(10000);
protected string _packageRoot;
protected string _unpackTempFilesRoot;
protected string _unpackManifestFilesRoot;
protected string _unpackBundleFilesRoot;
/// <summary>
/// 内置文件缓存系统
/// </summary>
public IFileCache BuiltinFileCache { private set; get; }
/// <summary>
/// 沙盒文件缓存系统
/// </summary>
public IFileCache UnpackFileCache { private set; get; }
/// <summary>
/// 解压调度器
/// </summary>
public DownloadSchedulerOperation UnpackScheduler { get; set; }
/// <summary>
/// 下载后台接口
@@ -35,28 +42,6 @@ namespace YooAsset
/// </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 创建委托
@@ -66,7 +51,7 @@ namespace YooAsset
/// <summary>
/// 自定义参数:覆盖安装缓存清理模式
/// </summary>
public EOverwriteInstallClearMode InstallClearMode { private set; get; } = EOverwriteInstallClearMode.ClearAllManifestFiles;
public EInstallCleanupMode InstallClearMode { private set; get; } = EInstallCleanupMode.ClearAllManifestFiles;
/// <summary>
/// 自定义参数:初始化的时候缓存文件校验级别
@@ -78,16 +63,6 @@ namespace YooAsset
/// </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>
@@ -105,24 +80,22 @@ namespace YooAsset
public string UnpackFileSystemRoot { private set; get; }
/// <summary>
/// 自定义参数:加载 AssetBundle 的工厂委托
/// 自定义参数:最大并发连接数
/// 默认值8推荐范围 1-32
/// </summary>
public LoadAssetBundleOperationFactory LoadAssetBundleFactory { private set; get; }
public int UnpackMaxConcurrency { private set; get; }
/// <summary>
/// 自定义参数:加载 RawBundle 的工厂委托
/// 自定义参数:每帧发起的最大请求数
/// 默认值8推荐范围 1-32
/// 说明:避免单帧发起过多请求导致卡顿
/// </summary>
public LoadRawBundleOperationFactory LoadRawBundleFactory { private set; get; }
public int UnpackMaxRequestPerFrame { private set; get; }
/// <summary>
/// 自定义参数:资源清单服务类
/// </summary>
public IManifestRestoreServices ManifestRestoreServices { private set; get; }
/// <summary>
/// 自定义参数:拷贝内置文件接口的实例类
/// </summary>
public ILocalFileCopyServices CopyLocalFileServices { private set; get; }
#endregion
@@ -131,7 +104,7 @@ namespace YooAsset
}
public virtual FSInitializeOperation InitializeAsync()
{
var operation = new DBFSInitializeOperation(this);
var operation = new BFSInitializeOperation(this);
return operation;
}
public virtual FSRequestVersionOperation RequestVersionAsync(RequestVersionOptions options)
@@ -146,45 +119,18 @@ namespace YooAsset
}
public virtual FSClearCacheOperation ClearCacheAsync(ClearCacheOptions options)
{
return _unpackFileSystem.ClearCacheAsync(options);
var operation = new BFSClearCacheOperation(this, options);
return operation;
}
public virtual FSDownloadFileOperation DownloadFileAsync(DownloadFileOptions options)
{
// 注意:业务层的解压器会依赖该方法
options.ImportFilePath = GetBuiltinFileLoadPath(options.Bundle);
return _unpackFileSystem.DownloadFileAsync(options);
var operation = new BFSDownloadFileOperation(this, options);
return operation;
}
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;
}
var operation = new BFSLoadBundleOperation(this, options);
return operation;
}
public virtual void SetParameter(string name, object value)
@@ -199,7 +145,7 @@ namespace YooAsset
}
else if (name == FileSystemParametersDefine.INSTALL_CLEAR_MODE)
{
InstallClearMode = (EOverwriteInstallClearMode)value;
InstallClearMode = (EInstallCleanupMode)value;
}
else if (name == FileSystemParametersDefine.FILE_VERIFY_LEVEL)
{
@@ -210,14 +156,6 @@ namespace YooAsset
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);
@@ -230,22 +168,32 @@ namespace YooAsset
{
UnpackFileSystemRoot = (string)value;
}
else if (name == FileSystemParametersDefine.LOAD_ASSETBUNDLE_OPERATION_FACTORY)
else if (name == FileSystemParametersDefine.DOWNLOAD_MAX_CONCURRENCY)
{
LoadAssetBundleFactory = (LoadAssetBundleOperationFactory)value;
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
UnpackMaxConcurrency = Mathf.Clamp(convertValue, 1, 32);
}
else if (name == FileSystemParametersDefine.LOAD_RAWBUNDLE_OPERATION_FACTORY)
else if (name == FileSystemParametersDefine.DOWNLOAD_MAX_REQUEST_PER_FRAME)
{
LoadRawBundleFactory = (LoadRawBundleOperationFactory)value;
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
UnpackMaxRequestPerFrame = Mathf.Clamp(convertValue, 1, 32);
}
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}");
@@ -264,35 +212,49 @@ namespace YooAsset
if (DownloadBackend == null)
DownloadBackend = new UnityWebRequestBackend(WebRequestCreator);
// 创建默认的 AssetBundle 加载工厂
if (LoadAssetBundleFactory == null)
LoadAssetBundleFactory = DefaultLoadAssetBundleOperationFactory;
// 创建解压缓存系统
string unpackRoot;
if (string.IsNullOrEmpty(UnpackFileSystemRoot))
unpackRoot = GetDefaultUnpackCacheRoot(packageName);
else
unpackRoot = UnpackFileSystemRoot;
_unpackManifestFilesRoot = PathUtility.Combine(unpackRoot, BuiltinFileSystemConstants.UnpackManifestFilesFolderName);
_unpackBundleFilesRoot = PathUtility.Combine(unpackRoot, BuiltinFileSystemConstants.UnpackBundleFilesFolderName);
_unpackTempFilesRoot = PathUtility.Combine(unpackRoot, BuiltinFileSystemConstants.UnpackTempFilesFolderName);
// 创建默认的 RawBundle 加载工厂
if (LoadRawBundleFactory == null)
LoadRawBundleFactory = DefaultLoadRawBundleOperationFactory;
// 创建内置缓存对象
{
var cacheConfig = new BuiltinFileCache.CacheConfig();
cacheConfig.DownloadBackend = DownloadBackend;
BuiltinFileCache = new BuiltinFileCache(packageName, _packageRoot, cacheConfig);
}
// 创建解压文件系统
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);
// 创建沙盒缓存对象
{
var cacheConfig = new SandboxFileCache.CacheConfig();
cacheConfig.FileVerifyLevel = FileVerifyLevel;
cacheConfig.FileVerifyMaxConcurrency = FileVerifyMaxConcurrency;
UnpackFileCache = new SandboxFileCache(packageName, _unpackBundleFilesRoot, cacheConfig);
}
}
public virtual void OnDestroy()
{
if (_unpackFileSystem != null)
if (BuiltinFileCache != null)
{
_unpackFileSystem.OnDestroy();
_unpackFileSystem = null;
BuiltinFileCache.Dispose();
BuiltinFileCache = null;
}
if (UnpackFileCache != null)
{
UnpackFileCache.Dispose();
UnpackFileCache = null;
}
if (UnpackScheduler != null)
{
UnpackScheduler.Dispose();
UnpackScheduler = null;
}
if (DownloadBackend != null)
@@ -304,15 +266,7 @@ namespace YooAsset
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);
return BuiltinFileCache.IsCached(bundle.BundleGUID);
}
public virtual bool NeedDownload(PackageBundle bundle)
{
@@ -322,7 +276,7 @@ namespace YooAsset
{
if (IsUnpackBundleFile(bundle))
{
return _unpackFileSystem.Exists(bundle) == false;
return UnpackFileCache.IsCached(bundle.BundleGUID) == false;
}
else
{
@@ -333,26 +287,17 @@ namespace YooAsset
{
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)
public virtual bool IsUnpackBundleFile(PackageBundle bundle)
{
if (Belong(bundle) == false)
return false;
#if UNITY_ANDROID || UNITY_OPENHARMONY
if (bundle.Encrypted)
if (bundle.IsEncrypted)
return true;
if (bundle.BundleType == (int)EBundleType.RawBundle)
@@ -365,31 +310,7 @@ namespace YooAsset
}
#region
private LoadAssetBundleOperation DefaultLoadAssetBundleOperationFactory(bool bundleEncrypted, LoadAssetBundleOptions options)
{
if (bundleEncrypted)
{
string error = $"{nameof(DefaultLoadAssetBundleOperation)} cannot load encrypted bundle. Please provide a custom {nameof(LoadAssetBundleOperationFactory)}.";
return new LoadAssetBundleCompleteOperation(error, options);
}
else
{
return new DefaultLoadAssetBundleOperation(options);
}
}
private LoadRawBundleOperation DefaultLoadRawBundleOperationFactory(bool bundleEncrypted, LoadRawBundleOptions options)
{
if (bundleEncrypted)
{
string error = $"{nameof(DefaultLoadRawBundleOperation)} cannot load encrypted bundle. Please provide a custom {nameof(LoadRawBundleOperationFactory)}.";
return new LoadRawBundleCompleteOperation(error, options);
}
else
{
return new DefaultLoadRawBundleOperation(options);
}
}
protected string GetDefaultBuiltinPackageRoot(string packageName)
public string GetDefaultBuiltinPackageRoot(string packageName)
{
string rootDirectory = YooAssetSettingsData.GetYooDefaultBuildinRoot();
return PathUtility.Combine(rootDirectory, packageName);
@@ -418,32 +339,42 @@ namespace YooAsset
string fileName = YooAssetSettingsData.GetManifestBinaryFileName(PackageName, packageVersion);
return PathUtility.Combine(_packageRoot, fileName);
}
public string GetCatalogBinaryFileLoadPath()
public string GetSandboxAppFootPrintFilePath()
{
return PathUtility.Combine(_packageRoot, BuiltinFileSystemConstants.BuiltinCatalogBinaryFileName);
return PathUtility.Combine(_unpackManifestFilesRoot, DefaultCacheFileSystemDefine.AppFootPrintFileName);
}
/// <summary>
/// 记录文件信息
/// 删除所有缓存的资源文件
/// </summary>
public bool RecordCatalogFile(string bundleGUID, FileWrapper wrapper)
public void DeleteAllBundleFiles()
{
if (_wrappers.ContainsKey(bundleGUID))
if (Directory.Exists(_unpackBundleFilesRoot))
{
YooLogger.Error($"{nameof(BuiltinFileSystem)} has element : {bundleGUID}");
return false;
Directory.Delete(_unpackBundleFilesRoot, true);
}
_wrappers.Add(bundleGUID, wrapper);
return true;
}
/// <summary>
/// 初始化解压文件系统
/// 获取默认的解压缓存根目录
/// </summary>
public FSInitializeOperation InitializeUnpackFileSystem()
public string GetDefaultUnpackCacheRoot(string packageName)
{
return _unpackFileSystem.InitializeAsync();
string rootDirectory = YooAssetSettingsData.GetYooDefaultCacheRoot();
return PathUtility.Combine(rootDirectory, packageName);
}
/// <summary>
/// 获取解压的临时文件路径
/// </summary>
public string GetUnpackTempFilePath(PackageBundle bundle)
{
if (_tempFilePathMapping.TryGetValue(bundle.BundleGUID, out string filePath) == false)
{
filePath = PathUtility.Combine(_unpackTempFilesRoot, bundle.BundleGUID);
_tempFilePathMapping.Add(bundle.BundleGUID, filePath);
}
return filePath;
}
#endregion
}

View File

@@ -1,16 +1,21 @@

namespace YooAsset
{
internal class BuiltinFileSystemConstants
{
/// <summary>
/// 内置清单JSON文件名称
/// 解压清单文件的文件夹名称
/// </summary>
public const string BuiltinCatalogJsonFileName = "BuiltinCatalog.json";
public const string UnpackManifestFilesFolderName = "UnpackManifestFiles";
/// <summary>
/// 解压资源文件的文件夹名称
/// </summary>
public const string UnpackBundleFilesFolderName = "UnpackBundleFiles";
/// <summary>
/// 内置清单二进制文件名称
/// 解压临时文件的文件名称
/// </summary>
public const string BuiltinCatalogBinaryFileName = "BuiltinCatalog.bytes";
public const string UnpackTempFilesFolderName = "UnpackTempFiles";
}
}

View File

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

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

@@ -1,246 +0,0 @@
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,59 @@

namespace YooAsset
{
internal class BFSClearCacheOperation : FSClearCacheOperation
{
private enum ESteps
{
None,
ClearCache,
Done,
}
private readonly BuiltinFileSystem _fileSystem;
private readonly ClearCacheOptions _options;
private FCClearCacheOperation _clearCacheOp;
private ESteps _steps = ESteps.None;
internal BFSClearCacheOperation(BuiltinFileSystem fileSystem, ClearCacheOptions options)
{
_fileSystem = fileSystem;
_options = options;
}
internal override void InternalStart()
{
_steps = ESteps.ClearCache;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.ClearCache)
{
if (_clearCacheOp == null)
{
_clearCacheOp = _fileSystem.UnpackFileCache.ClearCacheAsync(_options);
_clearCacheOp.StartOperation();
AddChildOperation(_clearCacheOp);
}
_clearCacheOp.UpdateOperation();
if (_clearCacheOp.IsDone == false)
return;
if (_clearCacheOp.Status == EOperationStatus.Succeeded)
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _clearCacheOp.Error;
}
}
}
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: cf87ffe3b3de69942ac16640a330dd37
guid: 3852e5e9188e72d488f02467606a39e6
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@@ -0,0 +1,131 @@
using UnityEngine;
namespace YooAsset
{
internal class BFSDownloadFileOperation : FSDownloadFileOperation
{
private enum ESteps
{
None,
CheckExists,
UnpackAndCache,
TryAgain,
Done,
}
private readonly BuiltinFileSystem _fileSystem;
private readonly DownloadFileOptions _options;
private DownloadFileBaseOperation _downloadFileOp;
private ESteps _steps = ESteps.None;
// 失败重试
private float _tryAgainTimer = 0;
private int _failedTryAgain;
internal BFSDownloadFileOperation(BuiltinFileSystem fileSystem, DownloadFileOptions options) : base(options.Bundle)
{
_fileSystem = fileSystem;
_options = options;
_failedTryAgain = options.RetryCount;
}
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.UnpackFileCache.IsCached(Bundle.BundleGUID))
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
}
else
{
_steps = ESteps.UnpackAndCache;
}
}
// 下载并缓存文件
if (_steps == ESteps.UnpackAndCache)
{
if (_downloadFileOp == null)
{
_downloadFileOp = _fileSystem.UnpackScheduler.TryGetDownloadFile(Bundle);
if (_downloadFileOp == null)
{
string builtinFilePath = _fileSystem.GetBuiltinFileLoadPath(Bundle);
_downloadFileOp = new UnpackAndCacheFileOperation(_fileSystem, Bundle, builtinFilePath);
_fileSystem.UnpackScheduler.AddDownloadFile(_downloadFileOp);
}
}
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.UnpackAndCache;
}
}
}
internal override void InternalWaitForCompletion()
{
ExecuteBatch();
}
internal override void InternalAbort()
{
// 注意:取消下载任务的时候引用计数减一
if (_steps != ESteps.Done)
{
if (_downloadFileOp != null)
{
_downloadFileOp.Release();
}
}
}
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: b05c83971e3dca94f9fa460d396385e5
guid: 899d85c6278629e40a36bc616b53bd95
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@@ -1,30 +1,26 @@
using System;
using System.IO;
namespace YooAsset
{
internal class DBFSInitializeOperation : FSInitializeOperation
internal class BFSInitializeOperation : FSInitializeOperation
{
private enum ESteps
{
None,
LoadBuildinPackageVersion,
CopyBuildinPackageHash,
CopyBuildinPackageManifest,
InitUnpackFileSystem,
LoadCatalogFile,
CheckAppFootprint,
CopyPackageManifest,
InitializeBuiltinFileCache,
InitializeUnpackFileCache,
CreateScheduler,
Done,
}
private readonly BuiltinFileSystem _fileSystem;
private RequestBuiltinPackageVersionOperation _requestBuildinPackageVersionOp;
private CopyBuiltinFileOperation _copyBuildinHashFileOp;
private CopyBuiltinFileOperation _copyBuildinManifestFileOp;
private FSInitializeOperation _initUnpackFIleSystemOp;
private LoadBuiltinCatalogFileOperation _loadBuildinCatalogFileOp;
private FCInitializeOperation _initializeBuiltinFileCacheOp;
private FCInitializeOperation _initializeUnpackFileCacheOp;
private CopyBuiltinPackageManifest _copyBuiltinPackageManifestOp;
private ESteps _steps = ESteps.None;
internal DBFSInitializeOperation(BuiltinFileSystem fileSystem)
internal BFSInitializeOperation(BuiltinFileSystem fileSystem)
{
_fileSystem = fileSystem;
}
@@ -35,10 +31,7 @@ namespace YooAsset
Status = EOperationStatus.Failed;
Error = $"{nameof(DefaultBuildinFileSystem)} is not support WEBGL platform.";
#else
if (_fileSystem.CopyBuildinPackageManifest)
_steps = ESteps.LoadBuildinPackageVersion;
else
_steps = ESteps.InitUnpackFileSystem;
_steps = ESteps.CheckAppFootprint;
#endif
}
internal override void InternalUpdate()
@@ -46,193 +39,146 @@ namespace YooAsset
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.LoadBuildinPackageVersion)
if (_steps == ESteps.CheckAppFootprint)
{
if (_requestBuildinPackageVersionOp == null)
{
_requestBuildinPackageVersionOp = new RequestBuiltinPackageVersionOperation(_fileSystem);
_requestBuildinPackageVersionOp.StartOperation();
AddChildOperation(_requestBuildinPackageVersionOp);
}
string footprintFilePath = _fileSystem.GetSandboxAppFootPrintFilePath();
var appFootprint = new ApplicationFootprint(footprintFilePath);
appFootprint.Load(_fileSystem.PackageName);
_requestBuildinPackageVersionOp.UpdateOperation();
if (_requestBuildinPackageVersionOp.IsDone == false)
return;
if (_requestBuildinPackageVersionOp.Status == EOperationStatus.Succeeded)
// <20><><EFBFBD><EFBFBD>ˮӡ<CBAE><D3A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E4BBAF><EFBFBD><EFBFBD>˵<EFBFBD><CBB5><EFBFBD><EFBFBD><EFBFBD>ǰ<EFBFBD>װ<EFBFBD><D7B0><EFBFBD>״δ<D7B4><CEB4><EFBFBD><EFBFBD><EFBFBD>Ϸ
if (appFootprint.IsDirty())
{
_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)
if (_fileSystem.InstallClearMode == EInstallCleanupMode.None)
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
YooLogger.Warning("Do nothing when overwrite install application.");
}
else if (_fileSystem.InstallClearMode == EInstallCleanupMode.ClearAllCacheFiles)
{
_fileSystem.DeleteAllBundleFiles();
YooLogger.Warning("Delete all cache files when overwrite install application.");
}
else if (_fileSystem.InstallClearMode == EInstallCleanupMode.ClearAllBundleFiles)
{
_fileSystem.DeleteAllBundleFiles();
YooLogger.Warning("Delete all bundle files when overwrite install application.");
}
else if (_fileSystem.InstallClearMode == EInstallCleanupMode.ClearAllManifestFiles)
{
YooLogger.Warning("Do nothing when overwrite install application.");
}
else
{
_steps = ESteps.LoadCatalogFile;
throw new System.NotImplementedException(_fileSystem.InstallClearMode.ToString());
}
appFootprint.Coverage(_fileSystem.PackageName);
}
_steps = ESteps.CopyPackageManifest;
}
if (_steps == ESteps.CopyPackageManifest)
{
if (_fileSystem.CopyBuildinPackageManifest)
{
if (_copyBuiltinPackageManifestOp == null)
{
_copyBuiltinPackageManifestOp = new CopyBuiltinPackageManifest(_fileSystem);
_copyBuiltinPackageManifestOp.StartOperation();
AddChildOperation(_copyBuiltinPackageManifestOp);
}
_copyBuiltinPackageManifestOp.UpdateOperation();
if (_copyBuiltinPackageManifestOp.IsDone == false)
return;
if (_copyBuiltinPackageManifestOp.Status == EOperationStatus.Succeeded)
{
_steps = ESteps.InitializeBuiltinFileCache;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _copyBuiltinPackageManifestOp.Error;
}
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _initUnpackFIleSystemOp.Error;
_steps = ESteps.InitializeBuiltinFileCache;
}
}
if (_steps == ESteps.LoadCatalogFile)
if (_steps == ESteps.InitializeBuiltinFileCache)
{
if (_loadBuildinCatalogFileOp == null)
if (_initializeBuiltinFileCacheOp == null)
{
_loadBuildinCatalogFileOp = new LoadBuiltinCatalogFileOperation(_fileSystem);
_loadBuildinCatalogFileOp.StartOperation();
AddChildOperation(_loadBuildinCatalogFileOp);
_initializeBuiltinFileCacheOp = _fileSystem.BuiltinFileCache.InitializeAsync();
_initializeBuiltinFileCacheOp.StartOperation();
AddChildOperation(_initializeBuiltinFileCacheOp);
}
_loadBuildinCatalogFileOp.UpdateOperation();
if (_loadBuildinCatalogFileOp.IsDone == false)
_initializeBuiltinFileCacheOp.UpdateOperation();
Progress = _initializeBuiltinFileCacheOp.Progress;
if (_initializeBuiltinFileCacheOp.IsDone == false)
return;
if (_loadBuildinCatalogFileOp.Status == EOperationStatus.Succeeded)
if (_initializeBuiltinFileCacheOp.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;
_steps = ESteps.InitializeUnpackFileCache;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _loadBuildinCatalogFileOp.Error;
Error = _initializeBuiltinFileCacheOp.Error;
}
}
}
private string GetCopyManifestFileRoot()
{
string destRoot = _fileSystem.CopyBuildinPackageManifestDestRoot;
if (string.IsNullOrEmpty(destRoot))
if (_steps == ESteps.InitializeUnpackFileCache)
{
string defaultCacheRoot = YooAssetSettingsData.GetYooDefaultCacheRoot();
destRoot = PathUtility.Combine(defaultCacheRoot, _fileSystem.PackageName, DefaultCacheFileSystemDefine.ManifestFilesFolderName);
if (_initializeUnpackFileCacheOp == null)
{
_initializeUnpackFileCacheOp = _fileSystem.UnpackFileCache.InitializeAsync();
_initializeUnpackFileCacheOp.StartOperation();
AddChildOperation(_initializeUnpackFileCacheOp);
}
_initializeUnpackFileCacheOp.UpdateOperation();
Progress = _initializeUnpackFileCacheOp.Progress;
if (_initializeUnpackFileCacheOp.IsDone == false)
return;
if (_initializeUnpackFileCacheOp.Status == EOperationStatus.Succeeded)
{
_steps = ESteps.CreateScheduler;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _initializeUnpackFileCacheOp.Error;
}
}
if (_steps == ESteps.CreateScheduler)
{
// ע<><D7A2>: <20><><EFBFBD>ص<EFBFBD><D8B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֹ<EFBFBD><D6B9>ʼ<EFBFBD><CABC>ʧ<EFBFBD>ܺ<EFBFBD><DCBA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
// ע<><D7A2>: <20><><EFBFBD>ص<EFBFBD><D8B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><CEAA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>У<EFBFBD>
if (_fileSystem.UnpackScheduler == null)
{
var schedulerConfig = new DownloadSchedulerOperation.SchedulerConfig();
schedulerConfig.SchedulerName = _fileSystem.GetType().Name;
schedulerConfig.DownloadBackend = _fileSystem.DownloadBackend;
schedulerConfig.MaxConcurrency = _fileSystem.UnpackMaxConcurrency;
schedulerConfig.MaxRequestPerFrame = _fileSystem.UnpackMaxRequestPerFrame;
_fileSystem.UnpackScheduler = new DownloadSchedulerOperation(schedulerConfig);
AsyncOperationSystem.StartOperation(_fileSystem.PackageName, _fileSystem.UnpackScheduler);
}
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
}
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

@@ -1,170 +1,167 @@
using System.IO;
using UnityEngine;
namespace YooAsset
{
/// <summary>
/// 加载 AssetBundle 文件
/// </summary>
internal class BFSLoadAssetBundleOperation : FSLoadBundleOperation
internal class BFSLoadBundleOperation : FSLoadBundleOperation
{
private enum ESteps
{
None,
LoadBuiltinAssetBundle,
Prepare,
UnpackFile,
AbortUnpack,
LoadUnpackBundle,
LoadBuiltinBundle,
CheckResult,
Done,
}
private readonly BuiltinFileSystem _fileSystem;
private readonly PackageBundle _bundle;
private LoadAssetBundleOperation _loadAssetBundleOp;
private readonly LoadBundleOptions _options;
private FSDownloadFileOperation _unpackFileOp;
private FCLoadBundleOperation _loadBundleOp;
private ESteps _steps = ESteps.None;
internal BFSLoadAssetBundleOperation(BuiltinFileSystem fileSystem, PackageBundle bundle)
internal BFSLoadBundleOperation(BuiltinFileSystem fileSystem, LoadBundleOptions options)
{
_fileSystem = fileSystem;
_bundle = bundle;
_options = options;
}
internal override void InternalStart()
{
DownloadProgress = 1f;
DownloadedBytes = _bundle.FileSize;
_steps = ESteps.LoadBuiltinAssetBundle;
_steps = ESteps.Prepare;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.LoadBuiltinAssetBundle)
if (_steps == ESteps.Prepare)
{
var options = new LoadAssetBundleOptions();
options.FileLoadPath = _fileSystem.GetBuiltinFileLoadPath(_bundle);
options.Bundle = _bundle;
_loadAssetBundleOp = _fileSystem.LoadAssetBundleFactory.Invoke(_bundle.Encrypted, options);
_loadAssetBundleOp.StartOperation();
AddChildOperation(_loadAssetBundleOp);
if (_fileSystem.IsUnpackBundleFile(_options.Bundle))
{
if (_fileSystem.UnpackFileCache.IsCached(_options.Bundle.BundleGUID))
{
DownloadProgress = 1f;
DownloadedBytes = _options.Bundle.FileSize;
_steps = ESteps.LoadUnpackBundle;
}
else
{
_steps = ESteps.UnpackFile;
}
}
else
{
DownloadProgress = 1f;
DownloadedBytes = _options.Bundle.FileSize;
_steps = ESteps.LoadBuiltinBundle;
}
}
if (_steps == ESteps.UnpackFile)
{
// 中断解压
if (AbortDownloadFile)
{
if (_unpackFileOp != null)
_unpackFileOp.AbortOperation();
_steps = ESteps.AbortUnpack;
}
}
if (_steps == ESteps.UnpackFile)
{
if (_unpackFileOp == null)
{
var options = new DownloadFileOptions(_options.Bundle, int.MaxValue);
_unpackFileOp = _fileSystem.DownloadFileAsync(options); // 注意:异步任务的开启由调度器统一控制
AddChildOperation(_unpackFileOp);
}
if (IsWaitForCompletion)
_unpackFileOp.WaitForCompletion();
_unpackFileOp.UpdateOperation();
DownloadProgress = _unpackFileOp.DownloadProgress;
DownloadedBytes = _unpackFileOp.DownloadedBytes;
if (_unpackFileOp.IsDone == false)
return;
if (_unpackFileOp.Status == EOperationStatus.Succeeded)
{
_steps = ESteps.LoadUnpackBundle;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _unpackFileOp.Error;
}
}
if (_steps == ESteps.AbortUnpack)
{
if (_unpackFileOp != null)
{
if (IsWaitForCompletion)
_unpackFileOp.WaitForCompletion();
_unpackFileOp.UpdateOperation();
if (_unpackFileOp.IsDone == false)
return;
}
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = "Abort download file.";
}
if (_steps == ESteps.LoadUnpackBundle)
{
_loadBundleOp = _fileSystem.UnpackFileCache.LoadBundleAsync(_options);
_loadBundleOp.StartOperation();
AddChildOperation(_loadBundleOp);
_steps = ESteps.CheckResult;
}
if (_steps == ESteps.LoadBuiltinBundle)
{
_loadBundleOp = _fileSystem.BuiltinFileCache.LoadBundleAsync(_options);
_loadBundleOp.StartOperation();
AddChildOperation(_loadBundleOp);
_steps = ESteps.CheckResult;
}
if (_steps == ESteps.CheckResult)
{
if (IsWaitForCompletion)
_loadAssetBundleOp.WaitForCompletion();
_loadBundleOp.WaitForCompletion();
_loadAssetBundleOp.UpdateOperation();
if (_loadAssetBundleOp.IsDone == false)
_loadBundleOp.UpdateOperation();
if (_loadBundleOp.IsDone == false)
return;
if (_loadAssetBundleOp.Status == EOperationStatus.Succeeded)
if (_loadBundleOp.Status == EOperationStatus.Succeeded)
{
if (_loadAssetBundleOp.Result == null)
if (_loadBundleOp.BundleResult == null)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = "Loaded builtin asset bundle is null.";
Error = "Loaded bundle result is null.";
YooLogger.Error(Error);
}
else
{
_steps = ESteps.Done;
Result = new AssetBundleResult(_fileSystem, _bundle, _loadAssetBundleOp.Result, _loadAssetBundleOp.ManagedStream);
Status = EOperationStatus.Succeeded;
Result = _loadBundleOp.BundleResult;
}
}
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;
Error = _loadBundleOp.Error;
YooLogger.Error(Error);
}
}
@@ -179,7 +176,7 @@ namespace YooAsset
/// <summary>
/// 加载团结文件
/// </summary>
internal class BFSLoadInstantBundleOperation : FSLoadBundleOperation
internal class BFSLoadInstantBundleOperation
{
private enum ESteps
{

View File

@@ -1,4 +1,4 @@
using System;
using System;
using System.IO;
namespace YooAsset
@@ -77,7 +77,8 @@ namespace YooAsset
{
if (_webFileRequestOp == null)
{
string url = DownloadSystemTools.ToLocalURL(_sourceFilePath);
//TODO <20>Ž<EFBFBD><C5BD><EFBFBD><EFBFBD><EFBFBD><E6A3AC>ijЩ<C4B3><D0A9>׿<EFBFBD><D7BF><EFBFBD>ͣ<EFBFBD><CDA3><EFBFBD><EFBFBD>ף<EFBFBD><D7A3><EFBFBD>ͨ<EFBFBD><CDA8>UnityWebRequest<73><74><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><C4BC><EFBFBD>С<EFBFBD><D0A1><EFBFBD><EFBFBD>ʧ<EFBFBD>ܣ<EFBFBD><DCA3><EFBFBD>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʽ<EFBFBD><CABD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><C4BC><EFBFBD>
string url = DownloadSystemTools.ToLocalUrl(_sourceFilePath);
var args = new DownloadFileRequestArgs(url, _destFilePath, 60, 0);
_webFileRequestOp = _fileSystem.DownloadBackend.CreateFileRequest(args);
_webFileRequestOp.SendRequest();
@@ -86,7 +87,7 @@ namespace YooAsset
if (_webFileRequestOp.IsDone == false)
return;
if (_webFileRequestOp.Status == EDownloadRequestStatus.Succeed)
if (_webFileRequestOp.Status == EDownloadRequestStatus.Succeeded)
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
@@ -99,5 +100,10 @@ namespace YooAsset
}
}
}
internal override void InternalWaitForCompletion()
{
//TODO <20>ȴ<EFBFBD><C8B4><EFBFBD>ѹ<EFBFBD><D1B9><EFBFBD><EFBFBD><EFBFBD>ļ<EFBFBD><C4BC><EFBFBD><EFBFBD>ϣ<EFBFBD><CFA3>ò<EFBFBD><C3B2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̣߳<DFB3>
ExecuteUntilComplete();
}
}
}

View File

@@ -0,0 +1,140 @@
namespace YooAsset
{
internal class CopyBuiltinPackageManifest : AsyncOperationBase
{
private enum ESteps
{
None,
LoadBuiltinPackageVersion,
CopyBuiltinPackageHash,
CopyBuiltinPackageManifest,
Done,
}
private readonly BuiltinFileSystem _fileSystem;
private RequestBuiltinPackageVersionOperation _requestBuildinPackageVersionOp;
private CopyBuiltinFileOperation _copyBuiltinHashFileOp;
private CopyBuiltinFileOperation _copyBuiltinManifestFileOp;
private ESteps _steps = ESteps.None;
public CopyBuiltinPackageManifest(BuiltinFileSystem fileSystem)
{
_fileSystem = fileSystem;
}
internal override void InternalStart()
{
_steps = ESteps.LoadBuiltinPackageVersion;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.LoadBuiltinPackageVersion)
{
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.CopyBuiltinPackageHash;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _requestBuildinPackageVersionOp.Error;
}
}
if (_steps == ESteps.CopyBuiltinPackageHash)
{
if (_copyBuiltinHashFileOp == null)
{
string packageVersion = _requestBuildinPackageVersionOp.PackageVersion;
string destFilePath = GetCopyPackageHashDestPath(packageVersion);
string sourceFilePath = _fileSystem.GetBuiltinPackageHashFilePath(packageVersion);
_copyBuiltinHashFileOp = new CopyBuiltinFileOperation(_fileSystem, sourceFilePath, destFilePath);
_copyBuiltinHashFileOp.StartOperation();
AddChildOperation(_copyBuiltinHashFileOp);
}
_copyBuiltinHashFileOp.UpdateOperation();
if (_copyBuiltinHashFileOp.IsDone == false)
return;
if (_copyBuiltinHashFileOp.Status == EOperationStatus.Succeeded)
{
_steps = ESteps.CopyBuiltinPackageManifest;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _copyBuiltinHashFileOp.Error;
}
}
if (_steps == ESteps.CopyBuiltinPackageManifest)
{
if (_copyBuiltinManifestFileOp == null)
{
string packageVersion = _requestBuildinPackageVersionOp.PackageVersion;
string destFilePath = GetCopyPackageManifestDestPath(packageVersion);
string sourceFilePath = _fileSystem.GetBuiltinPackageManifestFilePath(packageVersion);
_copyBuiltinManifestFileOp = new CopyBuiltinFileOperation(_fileSystem, sourceFilePath, destFilePath);
_copyBuiltinManifestFileOp.StartOperation();
AddChildOperation(_copyBuiltinManifestFileOp);
}
_copyBuiltinManifestFileOp.UpdateOperation();
if (_copyBuiltinManifestFileOp.IsDone == false)
return;
if (_copyBuiltinManifestFileOp.Status == EOperationStatus.Succeeded)
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _copyBuiltinManifestFileOp.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

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: a4113df346bbd1b4ead918b52ac46f55
guid: 9cbc466f7e0e94d4fb7ab6ba63c89497
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@@ -1,98 +0,0 @@
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

@@ -1,4 +1,4 @@
using System.IO;
using System.IO;
namespace YooAsset
{
@@ -62,7 +62,7 @@ namespace YooAsset
if (_webDataRequestOp == null)
{
string filePath = _fileSystem.GetBuiltinPackageManifestFilePath(_packageVersion);
string url = DownloadSystemTools.ToLocalURL(filePath);
string url = DownloadSystemTools.ToLocalUrl(filePath);
var args = new DownloadDataRequestArgs(url, 60, 0);
_webDataRequestOp = _fileSystem.DownloadBackend.CreateBytesRequest(args);
_webDataRequestOp.SendRequest();
@@ -71,7 +71,7 @@ namespace YooAsset
if (_webDataRequestOp.IsDone == false)
return;
if (_webDataRequestOp.Status == EDownloadRequestStatus.Succeed)
if (_webDataRequestOp.Status == EDownloadRequestStatus.Succeeded)
{
_fileData = _webDataRequestOp.Result;
_steps = ESteps.VerifyFileData;

View File

@@ -1,4 +1,4 @@
using System.IO;
using System.IO;
namespace YooAsset
{
@@ -57,7 +57,7 @@ namespace YooAsset
if (_webTextRequestOp == null)
{
string filePath = _fileSystem.GetBuiltinPackageHashFilePath(_packageVersion);
string url = DownloadSystemTools.ToLocalURL(filePath);
string url = DownloadSystemTools.ToLocalUrl(filePath);
var args = new DownloadDataRequestArgs(url, 60, 0);
_webTextRequestOp = _fileSystem.DownloadBackend.CreateTextRequest(args);
_webTextRequestOp.SendRequest();
@@ -66,7 +66,7 @@ namespace YooAsset
if (_webTextRequestOp.IsDone == false)
return;
if (_webTextRequestOp.Status == EDownloadRequestStatus.Succeed)
if (_webTextRequestOp.Status == EDownloadRequestStatus.Succeeded)
{
PackageHash = _webTextRequestOp.Result;
_steps = ESteps.CheckResult;

View File

@@ -1,4 +1,4 @@
using System.IO;
using System.IO;
namespace YooAsset
{
@@ -55,7 +55,7 @@ namespace YooAsset
if (_webTextRequestOp == null)
{
string filePath = _fileSystem.GetBuiltinPackageVersionFilePath();
string url = DownloadSystemTools.ToLocalURL(filePath);
string url = DownloadSystemTools.ToLocalUrl(filePath);
var args = new DownloadDataRequestArgs(url, 60, 0);
_webTextRequestOp = _fileSystem.DownloadBackend.CreateTextRequest(args);
_webTextRequestOp.SendRequest();
@@ -64,7 +64,7 @@ namespace YooAsset
if (_webTextRequestOp.IsDone == false)
return;
if (_webTextRequestOp.Status == EDownloadRequestStatus.Succeed)
if (_webTextRequestOp.Status == EDownloadRequestStatus.Succeeded)
{
PackageVersion = _webTextRequestOp.Result;
_steps = ESteps.CheckResult;

View File

@@ -0,0 +1,122 @@
using System.IO;
namespace YooAsset
{
internal sealed class UnpackAndCacheFileOperation : DownloadFileBaseOperation
{
private enum ESteps
{
None,
CheckCopy,
CopyLocalFile,
CreateRequest,
CheckRequest,
CacheFile,
Done,
}
private readonly BuiltinFileSystem _fileSystem;
private readonly string _builtinFilePath;
private readonly string _tempFilePath;
private CopyBuiltinFileOperation _copyBuiltinFileOp;
private FCWriteCacheOperation _bundleCacheOp;
private ESteps _steps = ESteps.None;
internal UnpackAndCacheFileOperation(BuiltinFileSystem fileSystem, PackageBundle bundle, string builtinFilePath) : base(bundle, builtinFilePath)
{
_fileSystem = fileSystem;
_builtinFilePath = builtinFilePath;
_tempFilePath = _fileSystem.GetUnpackTempFilePath(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.EnsureFileDirectory(_tempFilePath);
if (File.Exists(_tempFilePath))
File.Delete(_tempFilePath);
_steps = ESteps.CopyLocalFile;
}
// 拷贝本地文件
if (_steps == ESteps.CopyLocalFile)
{
if (_copyBuiltinFileOp == null)
{
_copyBuiltinFileOp = new CopyBuiltinFileOperation(_fileSystem, _builtinFilePath, _tempFilePath);
_copyBuiltinFileOp.StartOperation();
AddChildOperation(_copyBuiltinFileOp);
}
if (IsWaitForCompletion)
_copyBuiltinFileOp.WaitForCompletion();
_copyBuiltinFileOp.UpdateOperation();
if (_copyBuiltinFileOp.IsDone == false)
return;
if (_copyBuiltinFileOp.Status == EOperationStatus.Succeeded)
{
_steps = ESteps.CacheFile;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _copyBuiltinFileOp.Error;
}
}
// 缓存文件
if (_steps == ESteps.CacheFile)
{
if (_bundleCacheOp == null)
{
var options = new WriteCacheOptions();
options.Bundle = Bundle;
options.FilePath = _tempFilePath;
_bundleCacheOp = _fileSystem.UnpackFileCache.WriteCacheAsync(options);
_bundleCacheOp.StartOperation();
AddChildOperation(_bundleCacheOp);
}
if (IsWaitForCompletion)
_bundleCacheOp.WaitForCompletion();
_bundleCacheOp.UpdateOperation();
if (_bundleCacheOp.IsDone == false)
return;
if (_bundleCacheOp.Status == EOperationStatus.Succeeded)
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _bundleCacheOp.Error;
}
// 注意:缓存完成后直接删除临时文件
if (File.Exists(_tempFilePath))
File.Delete(_tempFilePath);
}
}
internal override void InternalWaitForCompletion()
{
ExecuteBatch();
}
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: c6be7b8be0b51784997c959b370193e9
guid: daa3aa418d6979b469437c30b7bbc05d
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@@ -8,13 +8,12 @@ namespace YooAsset
/// </summary>
internal class ApplicationFootprint
{
private readonly CacheFileSystem _fileSystem;
private string _footPrint;
private readonly string _filePath;
private string _footprint;
public ApplicationFootprint(CacheFileSystem fileSystem)
public ApplicationFootprint(string filePath)
{
_fileSystem = fileSystem;
_filePath = filePath;
}
/// <summary>
@@ -22,10 +21,9 @@ namespace YooAsset
/// </summary>
public void Load(string packageName)
{
string footPrintFilePath = _fileSystem.GetSandboxAppFootPrintFilePath();
if (File.Exists(footPrintFilePath))
if (File.Exists(_filePath))
{
_footPrint = FileUtility.ReadAllText(footPrintFilePath);
_footprint = FileUtility.ReadAllText(_filePath);
}
else
{
@@ -39,9 +37,9 @@ namespace YooAsset
public bool IsDirty()
{
#if UNITY_EDITOR
return _footPrint != Application.version;
return _footprint != Application.version;
#else
return _footPrint != Application.buildGUID;
return _footprint != Application.buildGUID;
#endif
}
@@ -51,13 +49,12 @@ namespace YooAsset
public void Coverage(string packageName)
{
#if UNITY_EDITOR
_footPrint = Application.version;
_footprint = Application.version;
#else
_footPrint = Application.buildGUID;
_footprint = Application.buildGUID;
#endif
string footPrintFilePath = _fileSystem.GetSandboxAppFootPrintFilePath();
FileUtility.WriteAllText(footPrintFilePath, _footPrint);
YooLogger.Log($"Save application foot print : {_footPrint}");
FileUtility.WriteAllText(_filePath, _footprint);
YooLogger.Log($"Save application footprint : {_footprint}");
}
}
}

View File

@@ -13,16 +13,15 @@ namespace YooAsset
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;
protected string _cacheBundleFilesRoot;
/// <summary>
/// 文件缓存系统
/// 沙盒文件缓存系统
/// </summary>
public BundleCache Cache { get; private set; }
public IFileCache FileCache { get; private set; }
/// <summary>
/// 下载调度器
@@ -39,28 +38,6 @@ namespace YooAsset
/// </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 创建委托
@@ -75,7 +52,7 @@ namespace YooAsset
/// <summary>
/// 自定义参数:覆盖安装缓存清理模式
/// </summary>
public EOverwriteInstallClearMode InstallClearMode { private set; get; } = EOverwriteInstallClearMode.ClearAllManifestFiles;
public EInstallCleanupMode InstallClearMode { private set; get; } = EInstallCleanupMode.ClearAllManifestFiles;
/// <summary>
/// 自定义参数:初始化的时候缓存文件校验级别
@@ -89,11 +66,6 @@ namespace YooAsset
/// </summary>
public int FileVerifyMaxConcurrency { private set; get; } = 8;
/// <summary>
/// 自定义参数:数据文件追加文件格式
/// </summary>
public bool AppendFileExtension { private set; get; } = false;
/// <summary>
/// 自定义参数:禁用边玩边下机制
/// </summary>
@@ -128,28 +100,12 @@ namespace YooAsset
/// </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()
{
}
@@ -170,83 +126,31 @@ namespace YooAsset
}
public virtual FSClearCacheOperation ClearCacheAsync(ClearCacheOptions options)
{
if (options.ClearMode == EFileClearMode.ClearAllBundleFiles.ToString())
if (options.ClearMode == EManifestClearMode.ClearAllManifestFiles.ToString())
{
var operation = new ClearAllCacheBundleFilesOperation(this);
var operation = new CFSClearAllCacheManifestOperation(this);
return operation;
}
else if (options.ClearMode == EFileClearMode.ClearUnusedBundleFiles.ToString())
else if (options.ClearMode == EManifestClearMode.ClearUnusedManifestFiles.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);
var operation = new CFSClearUnusedCacheManifestOperation(this, options.Manifest);
return operation;
}
else
{
string error = $"Invalid clear mode : {options.ClearMode}";
var operation = new FSClearCacheCompleteOperation(error);
var operation = new CFSClearCacheOperation(this, options);
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);
var downloader = new CFSDownloadFileOperation(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;
}
var operation = new CFSLoadBundleOperation(this, options);
return operation;
}
public virtual void SetParameter(string name, object value)
@@ -265,7 +169,7 @@ namespace YooAsset
}
else if (name == FileSystemParametersDefine.INSTALL_CLEAR_MODE)
{
InstallClearMode = (EOverwriteInstallClearMode)value;
InstallClearMode = (EInstallCleanupMode)value;
}
else if (name == FileSystemParametersDefine.FILE_VERIFY_LEVEL)
{
@@ -282,10 +186,6 @@ namespace YooAsset
// 限制在合理范围内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);
@@ -325,22 +225,10 @@ namespace YooAsset
{
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}");
@@ -360,22 +248,25 @@ namespace YooAsset
_tempFilesRoot = PathUtility.Combine(_packageRoot, DefaultCacheFileSystemDefine.TempFilesFolderName);
// 创建文件缓存系统
Cache = new BundleCache(PackageName, _cacheBundleFilesRoot, AppendFileExtension);
{
var cacheConfig = new SandboxFileCache.CacheConfig();
cacheConfig.FileVerifyLevel = FileVerifyLevel;
cacheConfig.FileVerifyMaxConcurrency = FileVerifyMaxConcurrency;
FileCache = new SandboxFileCache(PackageName, _cacheBundleFilesRoot, cacheConfig);
}
// 创建默认的下载后台接口
if (DownloadBackend == null)
DownloadBackend = new UnityWebRequestBackend(WebRequestCreator);
// 创建默认的 AssetBundle 加载工厂
if (LoadAssetBundleFactory == null)
LoadAssetBundleFactory = DefaultLoadAssetBundleOperationFactory;
// 创建默认的 RawBundle 加载工厂
if (LoadRawBundleFactory == null)
LoadRawBundleFactory = DefaultLoadRawBundleOperationFactory;
}
public virtual void OnDestroy()
{
if (FileCache != null)
{
FileCache.Dispose();
FileCache = null;
}
if (DownloadScheduler != null)
{
DownloadScheduler.Dispose();
@@ -391,19 +282,15 @@ namespace YooAsset
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;
return FileCache.IsCached(bundle.BundleGUID) == false;
}
public virtual bool NeedUnpack(PackageBundle bundle)
{
@@ -414,50 +301,18 @@ namespace YooAsset
if (Belong(bundle) == false)
return false;
return Exists(bundle) == false;
}
public virtual string GetBundleFilePath(PackageBundle bundle)
{
return GetCacheBundleFileLoadPath(bundle);
return FileCache.IsCached(bundle.BundleGUID) == false;
}
#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)
public string GetCacheManifestFilesRoot()
{
var entry = Cache.GetEntry(bundle.BundleGUID);
if (entry == null)
throw new YooInternalException();
return entry.DataFilePath;
return _cacheManifestFilesRoot;
}
public string GetCachePackageHashFilePath(string packageVersion)
{
@@ -473,14 +328,6 @@ namespace YooAsset
{
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)

View File

@@ -3,6 +3,16 @@ namespace YooAsset
{
internal class DefaultCacheFileSystemDefine
{
/// <summary>
/// 记录应用程序版本的文件名称
/// </summary>
public const string AppFootPrintFileName = "ApplicationFootPrint.bytes";
/// <summary>
/// 清单文件的文件夹名称
/// </summary>
public const string ManifestFilesFolderName = "ManifestFiles";
/// <summary>
/// 资源文件的文件夹名称
/// </summary>
@@ -12,15 +22,5 @@ namespace YooAsset
/// 临时文件的文件夹名称
/// </summary>
public const string TempFilesFolderName = "TempFiles";
/// <summary>
/// 清单文件的文件夹名称
/// </summary>
public const string ManifestFilesFolderName = "ManifestFiles";
/// <summary>
/// 记录应用程序版本的文件名称
/// </summary>
public const string AppFootPrintFileName = "ApplicationFootPrint.bytes";
}
}

View File

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

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

@@ -4,7 +4,7 @@ namespace YooAsset
/// <summary>
/// 覆盖安装清理模式
/// </summary>
public enum EOverwriteInstallClearMode
public enum EInstallCleanupMode
{
/// <summary>
/// 不做任何处理

View File

@@ -0,0 +1,19 @@

namespace YooAsset
{
/// <summary>
/// 清单清理方式
/// </summary>
public enum EManifestClearMode
{
/// <summary>
/// 清理所有清单
/// </summary>
ClearAllManifestFiles,
/// <summary>
/// 清理未在使用的清单
/// </summary>
ClearUnusedManifestFiles,
}
}

View File

@@ -0,0 +1,197 @@
using System;
using System.IO;
namespace YooAsset
{
internal class CFSClearCacheOperation : FSClearCacheOperation
{
private enum ESteps
{
None,
ClearCache,
Done,
}
private readonly CacheFileSystem _fileSystem;
private readonly ClearCacheOptions _options;
private FCClearCacheOperation _clearCacheOp;
private ESteps _steps = ESteps.None;
internal CFSClearCacheOperation(CacheFileSystem fileSystem, ClearCacheOptions options)
{
_fileSystem = fileSystem;
_options = options;
}
internal override void InternalStart()
{
_steps = ESteps.ClearCache;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.ClearCache)
{
if (_clearCacheOp == null)
{
_clearCacheOp = _fileSystem.FileCache.ClearCacheAsync(_options);
_clearCacheOp.StartOperation();
AddChildOperation(_clearCacheOp);
}
_clearCacheOp.UpdateOperation();
if (_clearCacheOp.IsDone == false)
return;
if (_clearCacheOp.Status == EOperationStatus.Succeeded)
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _clearCacheOp.Error;
}
}
}
}
internal class CFSClearAllCacheManifestOperation : FSClearCacheOperation
{
private enum ESteps
{
None,
ClearAllCacheFiles,
Done,
}
private readonly CacheFileSystem _fileSystem;
private ESteps _steps = ESteps.None;
internal CFSClearAllCacheManifestOperation(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;
}
}
}
}
internal class CFSClearUnusedCacheManifestOperation : FSClearCacheOperation
{
private enum ESteps
{
None,
CheckManifest,
ClearUnusedCacheFiles,
Done,
}
private readonly CacheFileSystem _fileSystem;
private readonly PackageManifest _manifest;
private ESteps _steps = ESteps.None;
internal CFSClearUnusedCacheManifestOperation(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,157 @@
using UnityEngine;
namespace YooAsset
{
internal class CFSDownloadFileOperation : FSDownloadFileOperation
{
protected enum ESteps
{
None,
CheckExists,
DownloadAndCache,
TryAgain,
Done,
}
private readonly CacheFileSystem _fileSystem;
private readonly DownloadFileOptions _options;
private DownloadFileBaseOperation _downloadFileOp;
private ESteps _steps = ESteps.None;
// 失败重试
private int _requestCount = 0;
private float _tryAgainTimer = 0;
private int _failedTryAgain;
internal CFSDownloadFileOperation(CacheFileSystem fileSystem, DownloadFileOptions options) : base(options.Bundle)
{
_fileSystem = fileSystem;
_options = options;
_failedTryAgain = options.RetryCount;
}
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.FileCache.IsCached(Bundle.BundleGUID))
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
}
else
{
_steps = ESteps.DownloadAndCache;
}
}
// 下载并缓存文件
if (_steps == ESteps.DownloadAndCache)
{
if (_downloadFileOp == null)
{
_downloadFileOp = _fileSystem.DownloadScheduler.TryGetDownloadFile(Bundle);
if (_downloadFileOp == null)
{
if (string.IsNullOrEmpty(_options.ImportFilePath))
{
// 下载远端文件
string mainURL = _fileSystem.RemoteServices.GetRemoteMainURL(Bundle.FileName);
string fallbackURL = _fileSystem.RemoteServices.GetRemoteFallbackURL(Bundle.FileName);
string url = GetRequestURL(mainURL, fallbackURL);
_downloadFileOp = new DownloadAndCacheFileOperation(_fileSystem, Bundle, url);
_fileSystem.DownloadScheduler.AddDownloadFile(_downloadFileOp);
}
else
{
// 导入本地文件
_downloadFileOp = new ImportAndCacheFileOperation(_fileSystem, Bundle, _options.ImportFilePath);
_fileSystem.DownloadScheduler.AddDownloadFile(_downloadFileOp);
}
}
}
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.DownloadAndCache;
}
}
}
internal override void InternalWaitForCompletion()
{
ExecuteBatch();
}
internal override void InternalAbort()
{
// 注意:取消下载任务的时候引用计数减一
if (_steps != ESteps.Done)
{
if (_downloadFileOp != null)
{
_downloadFileOp.Release();
}
}
}
/// <summary>
/// 获取网络请求地址
/// </summary>
private string GetRequestURL(string mainURL, string fallbackURL)
{
// 轮流返回请求地址
_requestCount++;
if (_requestCount % 2 == 0)
return fallbackURL;
else
return mainURL;
}
}
}

View File

@@ -6,14 +6,14 @@ namespace YooAsset
private enum ESteps
{
None,
CheckAppFootPrint,
CacheInitialize,
CreateDownloadScheduler,
CheckAppFootprint,
InitializeFileCache,
CreateScheduler,
Done,
}
private readonly CacheFileSystem _fileSystem;
private FCInitializeOperation _initializeCacheOp;
private FCInitializeOperation _initializeFileCacheOp;
private ESteps _steps = ESteps.None;
@@ -28,7 +28,7 @@ namespace YooAsset
Status = EOperationStatus.Failed;
Error = $"{nameof(DefaultCacheFileSystem)} is not support WEBGL platform.";
#else
_steps = ESteps.CheckAppFootPrint;
_steps = ESteps.CheckAppFootprint;
#endif
}
internal override void InternalUpdate()
@@ -36,30 +36,31 @@ namespace YooAsset
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.CheckAppFootPrint)
if (_steps == ESteps.CheckAppFootprint)
{
var appFootPrint = new ApplicationFootprint(_fileSystem);
appFootPrint.Load(_fileSystem.PackageName);
string footprintFilePath = _fileSystem.GetSandboxAppFootPrintFilePath();
var appFootprint = new ApplicationFootprint(footprintFilePath);
appFootprint.Load(_fileSystem.PackageName);
// 如果水印发生变化,则说明覆盖安装后首次打开游戏
if (appFootPrint.IsDirty())
if (appFootprint.IsDirty())
{
if (_fileSystem.InstallClearMode == EOverwriteInstallClearMode.None)
if (_fileSystem.InstallClearMode == EInstallCleanupMode.None)
{
YooLogger.Warning("Do nothing when overwrite install application.");
}
else if (_fileSystem.InstallClearMode == EOverwriteInstallClearMode.ClearAllCacheFiles)
else if (_fileSystem.InstallClearMode == EInstallCleanupMode.ClearAllCacheFiles)
{
_fileSystem.DeleteAllBundleFiles();
_fileSystem.DeleteAllManifestFiles();
YooLogger.Warning("Delete all cache files when overwrite install application.");
}
else if (_fileSystem.InstallClearMode == EOverwriteInstallClearMode.ClearAllBundleFiles)
else if (_fileSystem.InstallClearMode == EInstallCleanupMode.ClearAllBundleFiles)
{
_fileSystem.DeleteAllBundleFiles();
YooLogger.Warning("Delete all bundle files when overwrite install application.");
}
else if (_fileSystem.InstallClearMode == EOverwriteInstallClearMode.ClearAllManifestFiles)
else if (_fileSystem.InstallClearMode == EInstallCleanupMode.ClearAllManifestFiles)
{
_fileSystem.DeleteAllManifestFiles();
YooLogger.Warning("Delete all manifest files when overwrite install application.");
@@ -69,47 +70,50 @@ namespace YooAsset
throw new System.NotImplementedException(_fileSystem.InstallClearMode.ToString());
}
appFootPrint.Coverage(_fileSystem.PackageName);
appFootprint.Coverage(_fileSystem.PackageName);
}
_steps = ESteps.CacheInitialize;
_steps = ESteps.InitializeFileCache;
}
if (_steps == ESteps.CacheInitialize)
if (_steps == ESteps.InitializeFileCache)
{
if (_initializeCacheOp == null)
if (_initializeFileCacheOp == null)
{
var options = new FCInitializeOptions();
options.FileVerifyLevel = _fileSystem.FileVerifyLevel;
options.FileVerifyMaxConcurrency = _fileSystem.FileVerifyMaxConcurrency;
_initializeCacheOp = _fileSystem.Cache.InitializeAsync(options);
_initializeCacheOp.StartOperation();
AddChildOperation(_initializeCacheOp);
_initializeFileCacheOp = _fileSystem.FileCache.InitializeAsync();
_initializeFileCacheOp.StartOperation();
AddChildOperation(_initializeFileCacheOp);
}
_initializeCacheOp.UpdateOperation();
Progress = _initializeCacheOp.Progress;
if (_initializeCacheOp.IsDone == false)
_initializeFileCacheOp.UpdateOperation();
Progress = _initializeFileCacheOp.Progress;
if (_initializeFileCacheOp.IsDone == false)
return;
if (_initializeCacheOp.Status != EOperationStatus.Succeeded)
if (_initializeFileCacheOp.Status == EOperationStatus.Succeeded)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _initializeCacheOp.Error;
_steps = ESteps.CreateScheduler;
}
else
{
_steps = ESteps.CreateDownloadScheduler;
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _initializeFileCacheOp.Error;
}
}
if (_steps == ESteps.CreateDownloadScheduler)
if (_steps == ESteps.CreateScheduler)
{
// 注意:下载中心作为独立任务运行!
// 注意: 下载调度中心在最后一步创建,防止初始化失败后残留任务。
// 注意: 下载调度中心作为独立任务运行!
if (_fileSystem.DownloadScheduler == null)
{
_fileSystem.DownloadScheduler = new DownloadSchedulerOperation(_fileSystem);
var schedulerConfig = new DownloadSchedulerOperation.SchedulerConfig();
schedulerConfig.SchedulerName = _fileSystem.GetType().Name;
schedulerConfig.DownloadBackend = _fileSystem.DownloadBackend;
schedulerConfig.MaxConcurrency = _fileSystem.DownloadMaxConcurrency;
schedulerConfig.MaxRequestPerFrame = _fileSystem.DownloadMaxRequestPerFrame;
_fileSystem.DownloadScheduler = new DownloadSchedulerOperation(schedulerConfig);
AsyncOperationSystem.StartOperation(_fileSystem.PackageName, _fileSystem.DownloadScheduler);
}

View File

@@ -1,51 +1,46 @@
using System;
using System.IO;
using UnityEngine;
namespace YooAsset
{
internal class CFSLoadAssetBundleOperation : FSLoadBundleOperation
internal class CFSLoadBundleOperation : FSLoadBundleOperation
{
protected enum ESteps
private enum ESteps
{
None,
CheckExist,
Prepare,
DownloadFile,
AbortDownload,
LoadCacheAssetBundle,
LoadSandboxBundle,
CheckResult,
TryFallback,
Done,
}
protected readonly CacheFileSystem _fileSystem;
protected readonly PackageBundle _bundle;
protected FSDownloadFileOperation _downloadFileOp;
protected LoadAssetBundleOperation _loadAssetBundleOp;
protected ESteps _steps = ESteps.None;
private readonly CacheFileSystem _fileSystem;
private readonly LoadBundleOptions _options;
private FSDownloadFileOperation _downloadFileOp;
private FCLoadBundleOperation _loadBundleOp;
private ESteps _steps = ESteps.None;
internal CFSLoadAssetBundleOperation(CacheFileSystem fileSystem, PackageBundle bundle)
internal CFSLoadBundleOperation(CacheFileSystem fileSystem, LoadBundleOptions options)
{
_fileSystem = fileSystem;
_bundle = bundle;
_options = options;
}
internal override void InternalStart()
{
_steps = ESteps.CheckExist;
_steps = ESteps.Prepare;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.CheckExist)
if (_steps == ESteps.Prepare)
{
if (_fileSystem.Exists(_bundle))
if (_fileSystem.FileCache.IsCached(_options.Bundle.BundleGUID))
{
DownloadProgress = 1f;
DownloadedBytes = _bundle.FileSize;
_steps = ESteps.LoadCacheAssetBundle;
DownloadedBytes = _options.Bundle.FileSize;
_steps = ESteps.LoadSandboxBundle;
}
else
{
@@ -53,7 +48,7 @@ namespace YooAsset
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"The bundle not cached : {_bundle.BundleName}";
Error = $"The bundle not cached : {_options.Bundle.BundleName}";
YooLogger.Warning(Error);
}
else
@@ -78,9 +73,8 @@ namespace YooAsset
{
if (_downloadFileOp == null)
{
DownloadFileOptions options = new DownloadFileOptions(_bundle, int.MaxValue);
_downloadFileOp = _fileSystem.DownloadFileAsync(options);
_downloadFileOp.StartOperation();
DownloadFileOptions options = new DownloadFileOptions(_options.Bundle, int.MaxValue);
_downloadFileOp = _fileSystem.DownloadFileAsync(options); // 注意:异步任务的开启由调度器统一控制
AddChildOperation(_downloadFileOp);
}
@@ -95,7 +89,7 @@ namespace YooAsset
if (_downloadFileOp.Status == EOperationStatus.Succeeded)
{
_steps = ESteps.LoadCacheAssetBundle;
_steps = ESteps.LoadSandboxBundle;
}
else
{
@@ -122,284 +116,47 @@ namespace YooAsset
Error = "Abort download file.";
}
if (_steps == ESteps.LoadCacheAssetBundle)
if (_steps == ESteps.LoadSandboxBundle)
{
var options = new LoadAssetBundleOptions();
options.FileLoadPath = _fileSystem.GetCacheBundleFileLoadPath(_bundle);
options.Bundle = _bundle;
_loadAssetBundleOp = _fileSystem.LoadAssetBundleFactory.Invoke(_bundle.Encrypted, options);
_loadAssetBundleOp.StartOperation();
AddChildOperation(_loadAssetBundleOp);
_loadBundleOp = _fileSystem.FileCache.LoadBundleAsync(_options);
_loadBundleOp.StartOperation();
AddChildOperation(_loadBundleOp);
_steps = ESteps.CheckResult;
}
if (_steps == ESteps.CheckResult)
{
if (IsWaitForCompletion)
_loadAssetBundleOp.WaitForCompletion();
_loadBundleOp.WaitForCompletion();
_loadAssetBundleOp.UpdateOperation();
if (_loadAssetBundleOp.IsDone == false)
_loadBundleOp.UpdateOperation();
if (_loadBundleOp.IsDone == false)
return;
if (_loadAssetBundleOp.Status == EOperationStatus.Succeeded)
if (_loadBundleOp.Status == EOperationStatus.Succeeded)
{
if (_loadAssetBundleOp.Result == null)
if (_loadBundleOp.BundleResult == null)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = "Loaded cache asset bundle is null.";
Error = "Loaded bundle result 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;
Result = _loadBundleOp.BundleResult;
}
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _loadRawBundleOp.Error;
Error = _loadBundleOp.Error;
YooLogger.Error(Error);
}
}
}
internal override void InternalWaitForCompletion()
{
ExecuteBatch();
}
}
}

View File

@@ -1,74 +0,0 @@
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

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

View File

@@ -1,63 +0,0 @@
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

@@ -1,136 +0,0 @@
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

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

View File

@@ -1,132 +0,0 @@
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

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

View File

@@ -1,93 +0,0 @@
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

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

View File

@@ -1,85 +0,0 @@
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

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

View File

@@ -2,7 +2,7 @@ using System.IO;
namespace YooAsset
{
internal sealed class DownloadAndCacheRemoteFileOperation : DownloadAndCacheFileOperation
internal sealed class DownloadAndCacheFileOperation : DownloadFileBaseOperation
{
private enum ESteps
{
@@ -14,19 +14,17 @@ namespace YooAsset
}
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 IDownloadRequest _downloadRequest;
private FCWriteCacheOperation _writeCacheOp;
private ESteps _steps = ESteps.None;
internal DownloadAndCacheRemoteFileOperation(CacheFileSystem fileSystem, PackageBundle bundle, string url) : base(url)
internal DownloadAndCacheFileOperation(CacheFileSystem fileSystem, PackageBundle bundle, string url) : base(bundle, url)
{
_fileSystem = fileSystem;
_bundle = bundle;
_tempFilePath = _fileSystem.GetTempFilePath(_bundle);
_tempFilePath = _fileSystem.GetTempFilePath(bundle);
}
internal override void InternalStart()
{
@@ -40,19 +38,19 @@ namespace YooAsset
// 创建下载请求
if (_steps == ESteps.CreateRequest)
{
FileUtility.CreateFileDirectory(_tempFilePath);
FileUtility.EnsureFileDirectory(_tempFilePath);
_enableResume = _bundle.FileSize >= _fileSystem.ResumeDownloadMinimumSize;
_enableResume = Bundle.FileSize >= _fileSystem.ResumeDownloadMinimumSize;
if (_enableResume)
{
_request = CreateResumeRequest();
_request.SendRequest();
_downloadRequest = CreateResumeRequest();
_downloadRequest.SendRequest();
_steps = ESteps.CheckRequest;
}
else
{
_request = CreateNormalRequest();
_request.SendRequest();
_downloadRequest = CreateNormalRequest();
_downloadRequest.SendRequest();
_steps = ESteps.CheckRequest;
}
}
@@ -60,14 +58,14 @@ namespace YooAsset
// 检测下载结果
if (_steps == ESteps.CheckRequest)
{
DownloadProgress = _request.DownloadProgress;
DownloadedBytes = _fileOriginLength + _request.DownloadedBytes;
DownloadProgress = _downloadRequest.DownloadProgress;
DownloadedBytes = _fileOriginLength + _downloadRequest.DownloadedBytes;
Progress = DownloadProgress;
if (_request.IsDone == false)
if (_downloadRequest.IsDone == false)
return;
// 检查网络错误
if (_request.Status == EDownloadRequestStatus.Succeed)
if (_downloadRequest.Status == EDownloadRequestStatus.Succeeded)
{
_steps = ESteps.CacheFile;
}
@@ -75,35 +73,35 @@ namespace YooAsset
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _request.Error;
Error = _downloadRequest.Error;
}
// 在遇到特殊错误的时候删除文件
if (_enableResume)
ClearTempFileWhenError(_request.HttpCode);
ClearTempFileWhenError(_downloadRequest.HttpCode);
// 最终释放请求器
_request.Dispose();
_downloadRequest.Dispose();
}
// 缓存文件
if (_steps == ESteps.CacheFile)
{
if (_bundleCacheOp == null)
if (_writeCacheOp == null)
{
var options = new FCStoreCacheOptions();
options.Bundle = _bundle;
var options = new WriteCacheOptions();
options.Bundle = Bundle;
options.FilePath = _tempFilePath;
_bundleCacheOp = _fileSystem.Cache.StoreCacheAsync(options);
_bundleCacheOp.StartOperation();
AddChildOperation(_bundleCacheOp);
_writeCacheOp = _fileSystem.FileCache.WriteCacheAsync(options);
_writeCacheOp.StartOperation();
AddChildOperation(_writeCacheOp);
}
_bundleCacheOp.UpdateOperation();
if (_bundleCacheOp.IsDone == false)
_writeCacheOp.UpdateOperation();
if (_writeCacheOp.IsDone == false)
return;
if (_bundleCacheOp.Status == EOperationStatus.Succeeded)
if (_writeCacheOp.Status == EOperationStatus.Succeeded)
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
@@ -112,7 +110,7 @@ namespace YooAsset
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _bundleCacheOp.Error;
Error = _writeCacheOp.Error;
}
// 注意:缓存完成后直接删除临时文件
@@ -122,15 +120,15 @@ namespace YooAsset
}
internal override void InternalAbort()
{
if (_request != null)
_request.Dispose();
if (_downloadRequest != null)
_downloadRequest.Dispose();
}
internal override void InternalWaitForCompletion()
{
if (_steps != ESteps.Done)
{
// 注意:不中断下载任务,保持后台继续下载
YooLogger.Error($"Try load bundle {_bundle.BundleName} from remote : {URL}");
YooLogger.Error($"Try load bundle {Bundle.BundleName} from remote : {Url}");
}
}
@@ -140,7 +138,7 @@ namespace YooAsset
if (File.Exists(_tempFilePath))
{
FileInfo fileInfo = new FileInfo(_tempFilePath);
if (fileInfo.Length >= _bundle.FileSize)
if (fileInfo.Length >= Bundle.FileSize)
{
File.Delete(_tempFilePath);
}
@@ -155,7 +153,7 @@ namespace YooAsset
bool appendToFile = true;
bool removeFileOnAbort = false;
long resumeOffset = _fileOriginLength;
var args = new DownloadFileRequestArgs(URL, _tempFilePath, timeout, watchdogTime, appendToFile, removeFileOnAbort, resumeOffset);
var args = new DownloadFileRequestArgs(Url, _tempFilePath, timeout, watchdogTime, appendToFile, removeFileOnAbort, resumeOffset);
return _fileSystem.DownloadBackend.CreateFileRequest(args);
}
private IDownloadRequest CreateNormalRequest()
@@ -166,7 +164,7 @@ namespace YooAsset
int watchdogTime = _fileSystem.DownloadWatchDogTimeout;
int timeout = 0; //注意:文件下载不做超时检测
var args = new DownloadFileRequestArgs(URL, _tempFilePath, timeout, watchdogTime);
var args = new DownloadFileRequestArgs(Url, _tempFilePath, timeout, watchdogTime);
return _fileSystem.DownloadBackend.CreateFileRequest(args);
}
private void ClearTempFileWhenError(long httpCode)

View File

@@ -1,4 +1,4 @@
using System.IO;
using System.IO;
namespace YooAsset
{
@@ -66,7 +66,7 @@ namespace YooAsset
if (_webFileRequestOp.IsDone == false)
return;
if (_webFileRequestOp.Status == EDownloadRequestStatus.Succeed)
if (_webFileRequestOp.Status == EDownloadRequestStatus.Succeeded)
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;

View File

@@ -1,4 +1,4 @@
using System.IO;
using System.IO;
namespace YooAsset
{
@@ -66,7 +66,7 @@ namespace YooAsset
if (_webFileRequestOp.IsDone == false)
return;
if (_webFileRequestOp.Status == EDownloadRequestStatus.Succeed)
if (_webFileRequestOp.Status == EDownloadRequestStatus.Succeeded)
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;

View File

@@ -0,0 +1,106 @@
using System.IO;
namespace YooAsset
{
internal sealed class ImportAndCacheFileOperation : DownloadFileBaseOperation
{
private enum ESteps
{
None,
CheckTempFile,
CopyLocalFile,
CacheFile,
Done,
}
private readonly CacheFileSystem _fileSystem;
private readonly string _sourceFilePath;
private readonly string _tempFilePath;
private FCWriteCacheOperation _bundleCacheOp;
private ESteps _steps = ESteps.None;
internal ImportAndCacheFileOperation(CacheFileSystem fileSystem, PackageBundle bundle, string sourceFilePath) : base(bundle, sourceFilePath)
{
_fileSystem = fileSystem;
_sourceFilePath = sourceFilePath;
_tempFilePath = _fileSystem.GetTempFilePath(bundle);
}
internal override void InternalStart()
{
_steps = ESteps.CheckTempFile;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
// 检测临时文件
if (_steps == ESteps.CheckTempFile)
{
// 注意:删除历史临时文件
FileUtility.EnsureFileDirectory(_tempFilePath);
if (File.Exists(_tempFilePath))
File.Delete(_tempFilePath);
_steps = ESteps.CopyLocalFile;
}
// 拷贝本地文件
if (_steps == ESteps.CopyLocalFile)
{
try
{
File.Copy(_sourceFilePath, _tempFilePath, true);
_steps = ESteps.CacheFile;
}
catch (System.Exception ex)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Failed copy local file : {ex.Message}";
}
}
// 缓存文件
if (_steps == ESteps.CacheFile)
{
if (_bundleCacheOp == null)
{
var options = new WriteCacheOptions();
options.Bundle = Bundle;
options.FilePath = _tempFilePath;
_bundleCacheOp = _fileSystem.FileCache.WriteCacheAsync(options);
_bundleCacheOp.StartOperation();
AddChildOperation(_bundleCacheOp);
}
if (IsWaitForCompletion)
_bundleCacheOp.WaitForCompletion();
_bundleCacheOp.UpdateOperation();
if (_bundleCacheOp.IsDone == false)
return;
if (_bundleCacheOp.Status == EOperationStatus.Succeeded)
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _bundleCacheOp.Error;
}
// 注意:缓存完成后直接删除临时文件
if (File.Exists(_tempFilePath))
File.Delete(_tempFilePath);
}
}
internal override void InternalWaitForCompletion()
{
ExecuteBatch();
}
}
}

View File

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

namespace YooAsset
{
internal class RequestRemotePackageVersionOperation : AsyncOperationBase
@@ -55,7 +55,7 @@ namespace YooAsset
if (_webTextRequestOp.IsDone == false)
return;
if (_webTextRequestOp.Status == EDownloadRequestStatus.Succeed)
if (_webTextRequestOp.Status == EDownloadRequestStatus.Succeeded)
{
PackageVersion = _webTextRequestOp.Result;
if (string.IsNullOrEmpty(PackageVersion))

View File

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

View File

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

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

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

View File

@@ -1,174 +0,0 @@
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

@@ -1,182 +0,0 @@
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

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

View File

@@ -1,5 +1,5 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace YooAsset
{
@@ -8,9 +8,18 @@ namespace YooAsset
/// </summary>
internal class EditorFileSystem : IFileSystem
{
protected readonly Dictionary<string, string> _records = new Dictionary<string, string>(10000);
protected string _packageRoot;
/// <summary>
/// 虚拟文件缓存系统
/// </summary>
public IFileCache FileCache { private set; get; }
/// <summary>
/// 解压调度器
/// </summary>
public DownloadSchedulerOperation DownloadScheduler { get; set; }
/// <summary>
/// 下载后台接口
/// </summary>
@@ -21,28 +30,6 @@ namespace YooAsset
/// </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 创建委托
@@ -50,27 +37,41 @@ namespace YooAsset
public UnityWebRequestCreator WebRequestCreator { private set; get; }
/// <summary>
/// 模拟WebGL平台模式
/// 自定义参数:模拟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>
/// 异步模拟加载最小帧
/// 自定义参数:最大并发连接
/// 默认值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 AsyncSimulateMinFrame { private set; get; } = 1;
/// <summary>
/// 异步模拟加载最大帧数
/// 自定义参数:异步模拟加载最大帧数
/// </summary>
public int AsyncSimulateMaxFrame { private set; get; } = 1;
#endregion
@@ -100,25 +101,13 @@ namespace YooAsset
}
public virtual FSDownloadFileOperation DownloadFileAsync(DownloadFileOptions options)
{
string mainURL = options.Bundle.BundleName;
options.SetURL(mainURL, mainURL);
var downloader = new DownloadVirtualBundleOperation(this, options);
var downloader = new EFSDownloadFileOperation(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;
}
var operation = new EFSLoadBundleOperation(this, options);
return operation;
}
public virtual void SetParameter(string name, object value)
@@ -143,6 +132,28 @@ namespace YooAsset
{
VirtualDownloadSpeed = Convert.ToInt32(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.ASYNC_SIMULATE_MIN_FRAME)
{
AsyncSimulateMinFrame = Convert.ToInt32(value);
@@ -168,9 +179,31 @@ namespace YooAsset
// 创建默认的下载后台接口
if (DownloadBackend == null)
DownloadBackend = new UnityWebRequestBackend(WebRequestCreator);
// 创建编辑器文件缓存系统
if (AsyncSimulateMinFrame > AsyncSimulateMaxFrame)
AsyncSimulateMinFrame = AsyncSimulateMaxFrame;
var cacheConfig = new EditorFileCache.CacheConfig();
cacheConfig.VirtualDownloadMode = VirtualDownloadMode;
cacheConfig.VirtualWebGLMode = VirtualWebGLMode;
cacheConfig.AsyncSimulateMinFrame = AsyncSimulateMinFrame;
cacheConfig.AsyncSimulateMaxFrame = AsyncSimulateMaxFrame;
FileCache = new EditorFileCache(packageName, _packageRoot, cacheConfig);
}
public virtual void OnDestroy()
{
if (FileCache != null)
{
FileCache.Dispose();
FileCache = null;
}
if (DownloadScheduler != null)
{
DownloadScheduler.Dispose();
DownloadScheduler = null;
}
if (DownloadBackend != null)
{
DownloadBackend.Dispose();
@@ -182,23 +215,12 @@ namespace YooAsset
{
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;
return FileCache.IsCached(bundle.BundleGUID) == false;
}
public virtual bool NeedUnpack(PackageBundle bundle)
{
@@ -208,7 +230,9 @@ namespace YooAsset
{
return false;
}
public virtual string GetBundleFilePath(PackageBundle bundle)
#region
public string GetBundleFilePath(PackageBundle bundle)
{
if (bundle.IncludeMainAssets.Count == 0)
return string.Empty;
@@ -216,13 +240,6 @@ namespace YooAsset
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);
@@ -238,15 +255,6 @@ namespace YooAsset
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

@@ -1,36 +1,32 @@
using System.IO;
using UnityEngine;
namespace YooAsset
{
internal class DownloadPackageBundleOperation : FSDownloadFileOperation
internal class EFSDownloadFileOperation : FSDownloadFileOperation
{
protected enum ESteps
{
None,
CheckExists,
CreateRequest,
CheckRequest,
DownloadAndCache,
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 readonly EditorFileSystem _fileSystem;
private readonly DownloadFileOptions _options;
private DownloadFileBaseOperation _downloadFileOp;
private ESteps _steps = ESteps.None;
// 失败重试
private float _tryAgainTimer = 0;
private int _failedTryAgain;
internal DownloadPackageBundleOperation(CacheFileSystem fileSystem, DownloadFileOptions options) : base(options.Bundle)
internal EFSDownloadFileOperation(EditorFileSystem fileSystem, DownloadFileOptions options) : base(options.Bundle)
{
_fileSystem = fileSystem;
_options = options;
_failedTryAgain = options.FailedTryAgain;
_failedTryAgain = options.RetryCount;
}
internal override void InternalStart()
{
@@ -44,37 +40,31 @@ namespace YooAsset
// 检测文件是否存在
if (_steps == ESteps.CheckExists)
{
if (_fileSystem.Exists(Bundle))
if (_fileSystem.FileCache.IsCached(_options.Bundle.BundleGUID))
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
}
else
{
_steps = ESteps.CreateRequest;
_steps = ESteps.DownloadAndCache;
}
}
// 创建下载器
if (_steps == ESteps.CreateRequest)
// 下载并缓存文件
if (_steps == ESteps.DownloadAndCache)
{
if (_options.IsValid() == false)
if (_downloadFileOp == null)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = "Download file options is invalid.";
Debug.Log(Error);
return;
_downloadFileOp = _fileSystem.DownloadScheduler.TryGetDownloadFile(Bundle);
if (_downloadFileOp == null)
{
string editorFilePath = _fileSystem.GetBundleFilePath(Bundle);
_downloadFileOp = new SimulateAndCacheFileOperation(_fileSystem, Bundle, editorFilePath);
_fileSystem.DownloadScheduler.AddDownloadFile(_downloadFileOp);
}
}
string url = GetRequestURL();
_downloadFileOp = _fileSystem.DownloadScheduler.DownloadAndCacheFileAsync(Bundle, url);
_steps = ESteps.CheckRequest;
}
// 检测下载结果
if (_steps == ESteps.CheckRequest)
{
if (IsWaitForCompletion)
_downloadFileOp.WaitForCompletion();
@@ -95,7 +85,7 @@ namespace YooAsset
if (IsWaitForCompletion == false && _failedTryAgain > 0)
{
_steps = ESteps.TryAgain;
YooLogger.Warning($"Failed download : {_downloadFileOp.URL} Try again.");
YooLogger.Warning($"Failed download : {_downloadFileOp.Url} Try again.");
}
else
{
@@ -118,7 +108,7 @@ namespace YooAsset
Progress = 0f;
DownloadProgress = 0f;
DownloadedBytes = 0;
_steps = ESteps.CreateRequest;
_steps = ESteps.DownloadAndCache;
}
}
}
@@ -137,18 +127,5 @@ namespace YooAsset
}
}
}
/// <summary>
/// 获取网络请求地址
/// </summary>
protected string GetRequestURL()
{
// 轮流返回请求地址
_requestCount++;
if (_requestCount % 2 == 0)
return _options.FallbackURL;
else
return _options.MainURL;
}
}
}

View File

@@ -3,18 +3,73 @@ namespace YooAsset
{
internal class EFSInitializeOperation : FSInitializeOperation
{
private readonly EditorFileSystem _fileSytem;
private enum ESteps
{
None,
InitializeFileCache,
CreateScheduler,
Done,
}
private readonly EditorFileSystem _fileSystem;
private FCInitializeOperation _initializeFileCacheOp;
private ESteps _steps = ESteps.None;
internal EFSInitializeOperation(EditorFileSystem fileSystem)
{
_fileSytem = fileSystem;
_fileSystem = fileSystem;
}
internal override void InternalStart()
{
Status = EOperationStatus.Succeeded;
_steps = ESteps.InitializeFileCache;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.InitializeFileCache)
{
if (_initializeFileCacheOp == null)
{
_initializeFileCacheOp = _fileSystem.FileCache.InitializeAsync();
_initializeFileCacheOp.StartOperation();
AddChildOperation(_initializeFileCacheOp);
}
_initializeFileCacheOp.UpdateOperation();
Progress = _initializeFileCacheOp.Progress;
if (_initializeFileCacheOp.IsDone == false)
return;
if (_initializeFileCacheOp.Status == EOperationStatus.Succeeded)
{
_steps = ESteps.CreateScheduler;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _initializeFileCacheOp.Error;
}
}
if (_steps == ESteps.CreateScheduler)
{
// 注意: 下载调度中心在最后一步创建,防止初始化失败后残留任务。
// 注意: 下载调度中心作为独立任务运行!
if (_fileSystem.DownloadScheduler == null)
{
var schedulerConfig = new DownloadSchedulerOperation.SchedulerConfig();
schedulerConfig.SchedulerName = _fileSystem.GetType().Name;
schedulerConfig.DownloadBackend = _fileSystem.DownloadBackend;
schedulerConfig.MaxConcurrency = _fileSystem.DownloadMaxConcurrency;
schedulerConfig.MaxRequestPerFrame = _fileSystem.DownloadMaxRequestPerFrame;
_fileSystem.DownloadScheduler = new DownloadSchedulerOperation(schedulerConfig);
AsyncOperationSystem.StartOperation(_fileSystem.PackageName, _fileSystem.DownloadScheduler);
}
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
}
}
}
}

View File

@@ -3,45 +3,44 @@ namespace YooAsset
{
internal class EFSLoadBundleOperation : FSLoadBundleOperation
{
protected enum ESteps
private enum ESteps
{
None,
CheckExist,
Prepare,
DownloadFile,
AbortDownload,
LoadAssetBundle,
LoadVirtualBundle,
CheckResult,
Done,
}
private readonly EditorFileSystem _fileSystem;
private readonly PackageBundle _bundle;
protected FSDownloadFileOperation _downloadFileOp;
private int _asyncSimulateFrame;
private readonly LoadBundleOptions _options;
private FSDownloadFileOperation _downloadFileOp;
private FCLoadBundleOperation _loadBundleOp;
private ESteps _steps = ESteps.None;
internal EFSLoadBundleOperation(EditorFileSystem fileSystem, PackageBundle bundle)
internal EFSLoadBundleOperation(EditorFileSystem fileSystem, LoadBundleOptions options)
{
_fileSystem = fileSystem;
_bundle = bundle;
_options = options;
}
internal override void InternalStart()
{
_steps = ESteps.CheckExist;
_asyncSimulateFrame = _fileSystem.GetAsyncSimulateFrame();
_steps = ESteps.Prepare;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.CheckExist)
if (_steps == ESteps.Prepare)
{
if (_fileSystem.Exists(_bundle))
if (_fileSystem.FileCache.IsCached(_options.Bundle.BundleGUID))
{
DownloadProgress = 1f;
DownloadedBytes = _bundle.FileSize;
_steps = ESteps.LoadAssetBundle;
DownloadedBytes = _options.Bundle.FileSize;
_steps = ESteps.LoadVirtualBundle;
}
else
{
@@ -64,7 +63,7 @@ namespace YooAsset
{
if (_downloadFileOp == null)
{
DownloadFileOptions options = new DownloadFileOptions(_bundle, int.MaxValue);
DownloadFileOptions options = new DownloadFileOptions(_options.Bundle, int.MaxValue);
_downloadFileOp = _fileSystem.DownloadFileAsync(options);
_downloadFileOp.StartOperation();
AddChildOperation(_downloadFileOp);
@@ -81,7 +80,7 @@ namespace YooAsset
if (_downloadFileOp.Status == EOperationStatus.Succeeded)
{
_steps = ESteps.LoadAssetBundle;
_steps = ESteps.LoadVirtualBundle;
}
else
{
@@ -108,36 +107,46 @@ namespace YooAsset
Error = "Abort download file.";
}
if (_steps == ESteps.LoadAssetBundle)
if (_steps == ESteps.LoadVirtualBundle)
{
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--;
}
_loadBundleOp = _fileSystem.FileCache.LoadBundleAsync(_options);
_loadBundleOp.StartOperation();
AddChildOperation(_loadBundleOp);
_steps = ESteps.CheckResult;
}
if (_steps == ESteps.CheckResult)
{
_steps = ESteps.Done;
Result = new VirtualBundleResult(_fileSystem, _bundle);
Status = EOperationStatus.Succeeded;
if (IsWaitForCompletion)
_loadBundleOp.WaitForCompletion();
_loadBundleOp.UpdateOperation();
if (_loadBundleOp.IsDone == false)
return;
if (_loadBundleOp.Status == EOperationStatus.Succeeded)
{
if (_loadBundleOp.BundleResult == null)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = "Loaded bundle result is null.";
YooLogger.Error(Error);
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
Result = _loadBundleOp.BundleResult;
}
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _loadBundleOp.Error;
YooLogger.Error(Error);
}
}
}
internal override void InternalWaitForCompletion()

View File

@@ -1,148 +0,0 @@
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,112 @@
namespace YooAsset
{
internal class SimulateAndCacheFileOperation : DownloadFileBaseOperation
{
protected enum ESteps
{
None,
CreateRequest,
CheckRequest,
CacheFile,
Done,
}
protected readonly EditorFileSystem _fileSystem;
protected IDownloadRequest _downloadRequest;
private FCWriteCacheOperation _writeCacheOp;
private ESteps _steps = ESteps.None;
internal SimulateAndCacheFileOperation(EditorFileSystem fileSystem, PackageBundle bundle, string filePath) : base(bundle, filePath)
{
_fileSystem = fileSystem;
}
internal override void InternalStart()
{
_steps = ESteps.CreateRequest;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
// 创建下载请求
if (_steps == ESteps.CreateRequest)
{
int speed = _fileSystem.VirtualDownloadSpeed;
var args = new SimulateDownloadRequestArgs(Url, Bundle.FileSize, speed);
_downloadRequest = _fileSystem.DownloadBackend.CreateSimulateRequest(args);
_downloadRequest.SendRequest();
_steps = ESteps.CheckRequest;
}
// 检测下载结果
if (_steps == ESteps.CheckRequest)
{
DownloadedBytes = _downloadRequest.DownloadedBytes;
DownloadProgress = _downloadRequest.DownloadProgress;
Progress = DownloadProgress;
if (_downloadRequest.IsDone == false)
return;
// 检查网络错误
if (_downloadRequest.Status == EDownloadRequestStatus.Succeeded)
{
_steps = ESteps.CacheFile;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _downloadRequest.Error;
}
// 最终释放请求器
_downloadRequest.Dispose();
}
// 缓存文件
if (_steps == ESteps.CacheFile)
{
if (_writeCacheOp == null)
{
var options = new WriteCacheOptions();
options.Bundle = Bundle;
options.FilePath = Url;
_writeCacheOp = _fileSystem.FileCache.WriteCacheAsync(options);
_writeCacheOp.StartOperation();
AddChildOperation(_writeCacheOp);
}
_writeCacheOp.UpdateOperation();
if (_writeCacheOp.IsDone == false)
return;
if (_writeCacheOp.Status == EOperationStatus.Succeeded)
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _writeCacheOp.Error;
}
}
}
internal override void InternalAbort()
{
if (_downloadRequest != null)
_downloadRequest.Dispose();
}
internal override void InternalWaitForCompletion()
{
if (_steps != ESteps.Done)
{
// 注意:不中断下载任务,保持后台继续下载
YooLogger.Error($"Try load bundle {Bundle.BundleName} from remote : {Url}");
}
}
}
}

View File

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

View File

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

View File

@@ -1,22 +0,0 @@

namespace YooAsset
{
/// <summary>
/// 解压文件系统
/// </summary>
internal class UnpackFileSystem : CacheFileSystem
{
public UnpackFileSystem()
{
}
public override void OnCreate(string packageName, string rootDirectory)
{
base.OnCreate(packageName, rootDirectory);
// 注意:重写保存根目录和临时目录
_cacheBundleFilesRoot = PathUtility.Combine(_packageRoot, UnpackFileSystemConstants.SaveBundleFilesFolderName);
_cacheManifestFilesRoot = PathUtility.Combine(_packageRoot, UnpackFileSystemConstants.SaveManifestFilesFolderName);
_tempFilesRoot = PathUtility.Combine(_packageRoot, UnpackFileSystemConstants.TempFilesFolderName);
}
}
}

View File

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

View File

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

namespace YooAsset
{
internal class UnpackFileSystemConstants
{
/// <summary>
/// 保存的资源文件的文件夹名称
/// </summary>
public const string SaveBundleFilesFolderName = "UnpackBundleFiles";
/// <summary>
/// 保存的清单文件的文件夹名称
/// </summary>
public const string SaveManifestFilesFolderName = "UnpackManifestFiles";
/// <summary>
/// 下载的临时文件的文件夹名称
/// </summary>
public const string TempFilesFolderName = "UnpackTempFiles";
}
}

View File

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

View File

@@ -1,34 +0,0 @@
using System.Collections.Generic;
namespace YooAsset
{
internal class UnpackRemoteService : IRemoteServices
{
private readonly string _buildinPackageRoot;
protected readonly Dictionary<string, string> _mapping = new Dictionary<string, string>(10000);
public UnpackRemoteService(string buildinPackRoot)
{
_buildinPackageRoot = buildinPackRoot;
}
string IRemoteServices.GetRemoteMainURL(string fileName)
{
return GetFileLoadURL(fileName);
}
string IRemoteServices.GetRemoteFallbackURL(string fileName)
{
return GetFileLoadURL(fileName);
}
private string GetFileLoadURL(string fileName)
{
if (_mapping.TryGetValue(fileName, out string url) == false)
{
string filePath = PathUtility.Combine(_buildinPackageRoot, fileName);
url = DownloadSystemTools.ToLocalURL(filePath);
_mapping.Add(fileName, url);
}
return url;
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,4 +1,4 @@
using YooAsset;
using YooAsset;
internal class LoadWebPackageManifestOperation : AsyncOperationBase
{
@@ -65,7 +65,7 @@ internal class LoadWebPackageManifestOperation : AsyncOperationBase
if (_webDataRequestOp.IsDone == false)
return;
if (_webDataRequestOp.Status == EDownloadRequestStatus.Succeed)
if (_webDataRequestOp.Status == EDownloadRequestStatus.Succeeded)
{
_steps = ESteps.VerifyFileData;
}

View File

@@ -1,4 +1,4 @@
using YooAsset;
using YooAsset;
internal class RequestWebPackageHashOperation : AsyncOperationBase
{
@@ -57,7 +57,7 @@ internal class RequestWebPackageHashOperation : AsyncOperationBase
if (_webTextRequestOp.IsDone == false)
return;
if (_webTextRequestOp.Status == EDownloadRequestStatus.Succeed)
if (_webTextRequestOp.Status == EDownloadRequestStatus.Succeeded)
{
PackageHash = _webTextRequestOp.Result;
if (string.IsNullOrEmpty(PackageHash))

View File

@@ -1,4 +1,4 @@
using YooAsset;
using YooAsset;
internal class RequestWebPackageVersionOperation : AsyncOperationBase
{
@@ -57,7 +57,7 @@ internal class RequestWebPackageVersionOperation : AsyncOperationBase
if (_webTextRequestOp.IsDone == false)
return;
if (_webTextRequestOp.Status == EDownloadRequestStatus.Succeed)
if (_webTextRequestOp.Status == EDownloadRequestStatus.Succeeded)
{
PackageVersion = _webTextRequestOp.Result;
if (string.IsNullOrEmpty(PackageVersion))

View File

@@ -3,7 +3,16 @@ namespace YooAsset
{
internal class WRFSInitializeOperation : FSInitializeOperation
{
private enum ESteps
{
None,
InitializeFileCache,
Done,
}
private readonly WebRemoteFileSystem _fileSystem;
private FCInitializeOperation _initializeFileCacheOp;
private ESteps _steps = ESteps.None;
public WRFSInitializeOperation(WebRemoteFileSystem fileSystem)
{
@@ -11,10 +20,39 @@ namespace YooAsset
}
internal override void InternalStart()
{
Status = EOperationStatus.Succeeded;
_steps = ESteps.InitializeFileCache;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.InitializeFileCache)
{
if (_initializeFileCacheOp == null)
{
_initializeFileCacheOp = _fileSystem.FileCache.InitializeAsync();
_initializeFileCacheOp.StartOperation();
AddChildOperation(_initializeFileCacheOp);
}
_initializeFileCacheOp.UpdateOperation();
Progress = _initializeFileCacheOp.Progress;
if (_initializeFileCacheOp.IsDone == false)
return;
if (_initializeFileCacheOp.Status == EOperationStatus.Succeeded)
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _initializeFileCacheOp.Error;
}
}
}
}
}

View File

@@ -1,79 +1,71 @@

namespace YooAsset
{
internal class WRFSLoadAssetBundleOperation : FSLoadBundleOperation
internal class WRFSLoadBundleOperation : FSLoadBundleOperation
{
private enum ESteps
{
None,
LoadWebAssetBundle,
LoadWebBundle,
Done,
}
private readonly WebRemoteFileSystem _fileSystem;
private readonly PackageBundle _bundle;
private LoadWebAssetBundleOperation _loadWebAssetBundleOp;
private readonly LoadBundleOptions _options;
private FCLoadBundleOperation _loadBundleOp;
private ESteps _steps = ESteps.None;
internal WRFSLoadAssetBundleOperation(WebRemoteFileSystem fileSystem, PackageBundle bundle)
internal WRFSLoadBundleOperation(WebRemoteFileSystem fileSystem, LoadBundleOptions options)
{
_fileSystem = fileSystem;
_bundle = bundle;
_options = options;
}
internal override void InternalStart()
{
_steps = ESteps.LoadWebAssetBundle;
_steps = ESteps.LoadWebBundle;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.LoadWebAssetBundle)
if (_steps == ESteps.LoadWebBundle)
{
if (_loadWebAssetBundleOp == null)
if (_loadBundleOp == null)
{
var options = new LoadWebAssetBundleOptions();
options.Bundle = _bundle;
options.FailedTryAgain = int.MaxValue;
options.WatchdogTimeout = _fileSystem.DownloadWatchDogTimeout;
options.DownloadBackend = _fileSystem.DownloadBackend;
options.DisableUnityWebCache = _fileSystem.DisableUnityWebCache;
options.MainURL = _fileSystem.RemoteServices.GetRemoteMainURL(_bundle.FileName);
options.FallbackURL = _fileSystem.RemoteServices.GetRemoteFallbackURL(_bundle.FileName);
_loadWebAssetBundleOp = _fileSystem.LoadAssetBundleFactory.Invoke(_bundle.Encrypted, options);
_loadWebAssetBundleOp.StartOperation();
AddChildOperation(_loadWebAssetBundleOp);
_loadBundleOp = _fileSystem.FileCache.LoadBundleAsync(_options);
_loadBundleOp.StartOperation();
AddChildOperation(_loadBundleOp);
}
_loadWebAssetBundleOp.UpdateOperation();
DownloadProgress = _loadWebAssetBundleOp.DownloadProgress;
DownloadedBytes = _loadWebAssetBundleOp.DownloadedBytes;
Progress = _loadWebAssetBundleOp.Progress;
if (_loadWebAssetBundleOp.IsDone == false)
_loadBundleOp.UpdateOperation();
Progress = _loadBundleOp.Progress;
DownloadProgress = Progress;
DownloadedBytes = 0;
if (_loadBundleOp.IsDone == false)
return;
if (_loadWebAssetBundleOp.Status == EOperationStatus.Succeeded)
if (_loadBundleOp.Status == EOperationStatus.Succeeded)
{
if (_loadWebAssetBundleOp.Result == null)
if (_loadBundleOp.BundleResult == null)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Loaded asset bundle object is null.";
Error = $"Loaded bundle result is null.";
}
else
{
_steps = ESteps.Done;
Result = new AssetBundleResult(_fileSystem, _bundle, _loadWebAssetBundleOp.Result, null);
Status = EOperationStatus.Succeeded;
Result = _loadBundleOp.BundleResult;
}
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _loadWebAssetBundleOp.Error;
Error = _loadBundleOp.Error;
}
}
}

View File

@@ -10,37 +10,20 @@ namespace YooAsset
/// </summary>
internal class WebRemoteFileSystem : IFileSystem
{
/// <summary>
/// Web文件缓存系统
/// </summary>
public IFileCache FileCache { get; private set; }
/// <summary>
/// 下载后台接口
/// </summary>
public IDownloadBackend DownloadBackend { private set; get; }
public IDownloadBackend DownloadBackend { get; private set; }
/// <summary>
/// 包裹名称
/// </summary>
public string PackageName { private set; get; }
/// <summary>
/// 文件根目录
/// </summary>
public string FileRoot
{
get
{
return string.Empty;
}
}
/// <summary>
/// 文件数量
/// </summary>
public int FileCount
{
get
{
return 0;
}
}
public string PackageName { get; private set; }
#region
/// <summary>
@@ -63,11 +46,6 @@ namespace YooAsset
/// </summary>
public IRemoteServices RemoteServices { private set; get; }
/// <summary>
/// 自定义参数:加载 AssetBundle 的工厂委托
/// </summary>
public LoadWebAssetBundleOperationFactory LoadAssetBundleFactory { private set; get; }
/// <summary>
/// 自定义参数:资源清单服务类
/// </summary>
@@ -104,18 +82,8 @@ namespace YooAsset
}
public virtual FSLoadBundleOperation LoadBundleAsync(LoadBundleOptions options)
{
PackageBundle bundle = options.Bundle;
if (bundle.BundleType == (int)EBundleType.AssetBundle)
{
var operation = new WRFSLoadAssetBundleOperation(this, bundle);
return operation;
}
else
{
string error = $"{nameof(WebRemoteFileSystem)} not support load bundle type : {bundle.BundleType}";
var operation = new FSLoadBundleCompleteOperation(error);
return operation;
}
var operation = new WRFSLoadBundleOperation(this, options);
return operation;
}
public virtual void SetParameter(string name, object value)
@@ -141,10 +109,6 @@ namespace YooAsset
{
RemoteServices = (IRemoteServices)value;
}
else if (name == FileSystemParametersDefine.LOAD_ASSETBUNDLE_OPERATION_FACTORY)
{
LoadAssetBundleFactory = (LoadWebAssetBundleOperationFactory)value;
}
else if (name == FileSystemParametersDefine.MANIFEST_RESTORE_SERVICES)
{
ManifestRestoreServices = (IManifestRestoreServices)value;
@@ -162,12 +126,23 @@ namespace YooAsset
if (DownloadBackend == null)
DownloadBackend = new UnityWebRequestBackend(WebRequestCreator);
// 创建默认的 AssetBundle 加载工厂
if (LoadAssetBundleFactory == null)
LoadAssetBundleFactory = DefaultLoadAssetBundleOperationFactory;
// 创建Web文件缓存系统
var cacheConfig = new WebRemoteFileCache.CacheConfig();
cacheConfig.DisableUnityWebCache = DisableUnityWebCache;
cacheConfig.RemoteServices = RemoteServices;
cacheConfig.DownloadBackend = DownloadBackend;
cacheConfig.WatchdogTimeout = DownloadWatchDogTimeout;
cacheConfig.RetryCount = int.MaxValue;
FileCache = new WebRemoteFileCache(packageName, packageRoot, cacheConfig);
}
public virtual void OnDestroy()
{
if (FileCache != null)
{
FileCache.Dispose();
FileCache = null;
}
if (DownloadBackend != null)
{
DownloadBackend.Dispose();
@@ -177,11 +152,7 @@ namespace YooAsset
public virtual bool Belong(PackageBundle bundle)
{
return true;
}
public virtual bool Exists(PackageBundle bundle)
{
return true;
return FileCache.IsCached(bundle.BundleGUID);
}
public virtual bool NeedDownload(PackageBundle bundle)
{
@@ -195,24 +166,5 @@ namespace YooAsset
{
return false;
}
public virtual string GetBundleFilePath(PackageBundle bundle)
{
throw new System.NotImplementedException();
}
#region
private LoadWebAssetBundleOperation DefaultLoadAssetBundleOperationFactory(bool bundleEncrypted, LoadWebAssetBundleOptions options)
{
if (bundleEncrypted)
{
string error = $"{nameof(DefaultLoadWebAssetBundleOperation)} cannot load encrypted bundle. Please provide a custom {nameof(LoadWebAssetBundleOperationFactory)}.";
return new LoadWebAssetBundleCompleteOperation(error, options);
}
else
{
return new DefaultLoadWebAssetBundleOperation(options);
}
}
#endregion
}
}

View File

@@ -6,12 +6,12 @@ namespace YooAsset
private enum ESteps
{
None,
LoadCatalogFile,
InitializeFileCache,
Done,
}
private readonly WebServerFileSystem _fileSystem;
private LoadWebServerCatalogFileOperation _loadCatalogFileOp;
private FCInitializeOperation _initializeFileCacheOp;
private ESteps _steps = ESteps.None;
@@ -21,27 +21,28 @@ namespace YooAsset
}
internal override void InternalStart()
{
_steps = ESteps.LoadCatalogFile;
_steps = ESteps.InitializeFileCache;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.LoadCatalogFile)
if (_steps == ESteps.InitializeFileCache)
{
if (_loadCatalogFileOp == null)
if (_initializeFileCacheOp == null)
{
_loadCatalogFileOp = new LoadWebServerCatalogFileOperation(_fileSystem, 60);
_loadCatalogFileOp.StartOperation();
AddChildOperation(_loadCatalogFileOp);
_initializeFileCacheOp = _fileSystem.FileCache.InitializeAsync();
_initializeFileCacheOp.StartOperation();
AddChildOperation(_initializeFileCacheOp);
}
_loadCatalogFileOp.UpdateOperation();
if (_loadCatalogFileOp.IsDone == false)
_initializeFileCacheOp.UpdateOperation();
Progress = _initializeFileCacheOp.Progress;
if (_initializeFileCacheOp.IsDone == false)
return;
if (_loadCatalogFileOp.Status == EOperationStatus.Succeeded)
if (_initializeFileCacheOp.Status == EOperationStatus.Succeeded)
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeeded;
@@ -50,7 +51,7 @@ namespace YooAsset
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _loadCatalogFileOp.Error;
Error = _initializeFileCacheOp.Error;
}
}
}

View File

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

namespace YooAsset
{
internal class WSFSLoadAssetBundleOperation : FSLoadBundleOperation
@@ -6,77 +6,66 @@ namespace YooAsset
private enum ESteps
{
None,
LoadWebAssetBundle,
LoadWebBundle,
Done,
}
private readonly WebServerFileSystem _fileSystem;
private readonly PackageBundle _bundle;
private LoadWebAssetBundleOperation _loadWebAssetBundleOp;
private readonly LoadBundleOptions _options;
private FCLoadBundleOperation _loadBundleOp;
private ESteps _steps = ESteps.None;
internal WSFSLoadAssetBundleOperation(WebServerFileSystem fileSystem, PackageBundle bundle)
internal WSFSLoadAssetBundleOperation(WebServerFileSystem fileSystem, LoadBundleOptions options)
{
_fileSystem = fileSystem;
_bundle = bundle;
_options = options;
}
internal override void InternalStart()
{
_steps = ESteps.LoadWebAssetBundle;
_steps = ESteps.LoadWebBundle;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.LoadWebAssetBundle)
if (_steps == ESteps.LoadWebBundle)
{
if (_loadWebAssetBundleOp == null)
if (_loadBundleOp == null)
{
string fileLoadPath = _fileSystem.GetWebFileLoadPath(_bundle);
string mainURL = DownloadSystemTools.ToLocalURL(fileLoadPath);
var options = new LoadWebAssetBundleOptions();
options.Bundle = _bundle;
options.FailedTryAgain = int.MaxValue;
options.WatchdogTimeout = _fileSystem.DownloadWatchDogTimeout;
options.DownloadBackend = _fileSystem.DownloadBackend;
options.DisableUnityWebCache = _fileSystem.DisableUnityWebCache;
options.MainURL = mainURL;
options.FallbackURL = mainURL;
_loadWebAssetBundleOp = _fileSystem.LoadAssetBundleFactory.Invoke(_bundle.Encrypted, options);
_loadWebAssetBundleOp.StartOperation();
AddChildOperation(_loadWebAssetBundleOp);
_loadBundleOp = _fileSystem.FileCache.LoadBundleAsync(_options);
_loadBundleOp.StartOperation();
AddChildOperation(_loadBundleOp);
}
_loadWebAssetBundleOp.UpdateOperation();
DownloadProgress = _loadWebAssetBundleOp.DownloadProgress;
DownloadedBytes = _loadWebAssetBundleOp.DownloadedBytes;
Progress = _loadWebAssetBundleOp.Progress;
if (_loadWebAssetBundleOp.IsDone == false)
_loadBundleOp.UpdateOperation();
Progress = _loadBundleOp.Progress;
DownloadProgress = Progress;
DownloadedBytes = 0;
if (_loadBundleOp.IsDone == false)
return;
if (_loadWebAssetBundleOp.Status == EOperationStatus.Succeeded)
if (_loadBundleOp.Status == EOperationStatus.Succeeded)
{
if (_loadWebAssetBundleOp.Result == null)
if (_loadBundleOp.BundleResult == null)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Loaded asset bundle object is null.";
Error = $"Loaded bundle result is null.";
}
else
{
_steps = ESteps.Done;
Result = new AssetBundleResult(_fileSystem, _bundle, _loadWebAssetBundleOp.Result, null);
Status = EOperationStatus.Succeeded;
Result = _loadBundleOp.BundleResult;
}
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _loadWebAssetBundleOp.Error;
Error = _loadBundleOp.Error;
}
}
}

View File

@@ -1,92 +0,0 @@
using System;
namespace YooAsset
{
internal sealed class LoadWebServerCatalogFileOperation : AsyncOperationBase
{
private enum ESteps
{
None,
RequestData,
LoadCatalog,
Done,
}
private readonly WebServerFileSystem _fileSystem;
private readonly int _timeout;
private IDownloadBytesRequest _webDataRequestOp;
private ESteps _steps = ESteps.None;
internal LoadWebServerCatalogFileOperation(WebServerFileSystem fileSystem, int timeout)
{
_fileSystem = fileSystem;
_timeout = timeout;
}
internal override void InternalStart()
{
_steps = ESteps.RequestData;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.RequestData)
{
if (_webDataRequestOp == null)
{
string filePath = _fileSystem.GetCatalogBinaryFileLoadPath();
string url = DownloadSystemTools.ToLocalURL(filePath);
var args = new DownloadDataRequestArgs(url, _timeout, 0);
_webDataRequestOp = _fileSystem.DownloadBackend.CreateBytesRequest(args);
_webDataRequestOp.SendRequest();
}
if (_webDataRequestOp.IsDone == false)
return;
if (_webDataRequestOp.Status == EDownloadRequestStatus.Succeed)
{
_steps = ESteps.LoadCatalog;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _webDataRequestOp.Error;
}
}
if (_steps == ESteps.LoadCatalog)
{
try
{
var catalog = CatalogFileTools.DeserializeFromBinary(_webDataRequestOp.Result);
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 WebServerFileSystem.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;
}
catch (Exception ex)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Failed to load catalog file : {ex.Message}";
}
}
}
}
}

View File

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

View File

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

namespace YooAsset
{
internal class LoadWebServerPackageManifestOperation : AsyncOperationBase
@@ -47,7 +47,7 @@ namespace YooAsset
if (_webDataRequestOp == null)
{
string filePath = _fileSystem.GetWebPackageManifestFilePath(_packageVersion);
string url = DownloadSystemTools.ToLocalURL(filePath);
string url = DownloadSystemTools.ToLocalUrl(filePath);
var args = new DownloadDataRequestArgs(url, _timeout, 0);
_webDataRequestOp = _fileSystem.DownloadBackend.CreateBytesRequest(args);
_webDataRequestOp.SendRequest();
@@ -56,7 +56,7 @@ namespace YooAsset
if (_webDataRequestOp.IsDone == false)
return;
if (_webDataRequestOp.Status == EDownloadRequestStatus.Succeed)
if (_webDataRequestOp.Status == EDownloadRequestStatus.Succeeded)
{
_steps = ESteps.VerifyFileData;
}

View File

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

namespace YooAsset
{
internal class RequestWebServerPackageHashOperation : AsyncOperationBase
@@ -42,7 +42,7 @@ namespace YooAsset
if (_webTextRequestOp == null)
{
string filePath = _fileSystem.GetWebPackageHashFilePath(_packageVersion);
string url = DownloadSystemTools.ToLocalURL(filePath);
string url = DownloadSystemTools.ToLocalUrl(filePath);
var args = new DownloadDataRequestArgs(url, _timeout, 0);
_webTextRequestOp = _fileSystem.DownloadBackend.CreateTextRequest(args);
_webTextRequestOp.SendRequest();
@@ -52,7 +52,7 @@ namespace YooAsset
if (_webTextRequestOp.IsDone == false)
return;
if (_webTextRequestOp.Status == EDownloadRequestStatus.Succeed)
if (_webTextRequestOp.Status == EDownloadRequestStatus.Succeeded)
{
PackageHash = _webTextRequestOp.Result;
if (string.IsNullOrEmpty(PackageHash))

View File

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

namespace YooAsset
{
internal class RequestWebServerPackageVersionOperation : AsyncOperationBase
@@ -40,7 +40,7 @@ namespace YooAsset
if (_webTextRequestOp == null)
{
string filePath = _fileSystem.GetWebPackageVersionFilePath();
string url = DownloadSystemTools.ToLocalURL(filePath);
string url = DownloadSystemTools.ToLocalUrl(filePath);
var args = new DownloadDataRequestArgs(url, _timeout, 0);
_webTextRequestOp = _fileSystem.DownloadBackend.CreateTextRequest(args);
_webTextRequestOp.SendRequest();
@@ -49,7 +49,7 @@ namespace YooAsset
if (_webTextRequestOp.IsDone == false)
return;
if (_webTextRequestOp.Status == EDownloadRequestStatus.Succeed)
if (_webTextRequestOp.Status == EDownloadRequestStatus.Succeeded)
{
PackageVersion = _webTextRequestOp.Result;
if (string.IsNullOrEmpty(PackageVersion))

View File

@@ -10,51 +10,23 @@ namespace YooAsset
/// </summary>
internal class WebServerFileSystem : 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> _webFilePathMapping = new Dictionary<string, string>(10000);
protected string _webPackageRoot = string.Empty;
protected string _packageRoot = string.Empty;
/// <summary>
/// Web文件缓存系统
/// </summary>
public IFileCache FileCache { get; private set; }
/// <summary>
/// 下载后台接口
/// </summary>
public IDownloadBackend DownloadBackend { private set; get; }
public IDownloadBackend DownloadBackend { get; private set; }
/// <summary>
/// 包裹名称
/// </summary>
public string PackageName { private set; get; }
/// <summary>
/// 文件根目录
/// </summary>
public string FileRoot
{
get
{
return _webPackageRoot;
}
}
/// <summary>
/// 文件数量
/// </summary>
public int FileCount
{
get
{
return 0;
}
}
public string PackageName { get; private set; }
#region
/// <summary>
@@ -72,11 +44,6 @@ namespace YooAsset
/// </summary>
public int DownloadWatchDogTimeout { private set; get; } = 0;
/// <summary>
/// 自定义参数:加载 AssetBundle 的工厂委托
/// </summary>
public LoadWebAssetBundleOperationFactory LoadAssetBundleFactory { private set; get; }
/// <summary>
/// 自定义参数:资源清单服务类
/// </summary>
@@ -113,18 +80,8 @@ namespace YooAsset
}
public virtual FSLoadBundleOperation LoadBundleAsync(LoadBundleOptions options)
{
PackageBundle bundle = options.Bundle;
if (bundle.BundleType == (int)EBundleType.AssetBundle)
{
var operation = new WSFSLoadAssetBundleOperation(this, bundle);
return operation;
}
else
{
string error = $"{nameof(WebServerFileSystem)} not support load bundle type : {bundle.BundleType}";
var operation = new FSLoadBundleCompleteOperation(error);
return operation;
}
var operation = new WSFSLoadAssetBundleOperation(this, options);
return operation;
}
public virtual void SetParameter(string name, object value)
@@ -146,10 +103,6 @@ namespace YooAsset
int convertValue = Convert.ToInt32(value);
DownloadWatchDogTimeout = Mathf.Clamp(convertValue, 0, int.MaxValue);
}
else if (name == FileSystemParametersDefine.LOAD_ASSETBUNDLE_OPERATION_FACTORY)
{
LoadAssetBundleFactory = (LoadWebAssetBundleOperationFactory)value;
}
else if (name == FileSystemParametersDefine.MANIFEST_RESTORE_SERVICES)
{
ManifestRestoreServices = (IManifestRestoreServices)value;
@@ -164,20 +117,30 @@ namespace YooAsset
PackageName = packageName;
if (string.IsNullOrEmpty(packageRoot))
_webPackageRoot = GetDefaultWebPackageRoot(packageName);
_packageRoot = GetDefaultWebPackageRoot(packageName);
else
_webPackageRoot = packageRoot;
_packageRoot = packageRoot;
// 创建默认的下载后台接口
if (DownloadBackend == null)
DownloadBackend = new UnityWebRequestBackend(WebRequestCreator);
// 创建默认的 AssetBundle 加载工厂
if (LoadAssetBundleFactory == null)
LoadAssetBundleFactory = DefaultLoadAssetBundleOperationFactory;
// 创建Web文件缓存系统
var cacheConfig = new WebServerFileCache.CacheConfig();
cacheConfig.DisableUnityWebCache = DisableUnityWebCache;
cacheConfig.DownloadBackend = DownloadBackend;
cacheConfig.WatchdogTimeout = DownloadWatchDogTimeout;
cacheConfig.RetryCount = int.MaxValue;
FileCache = new WebServerFileCache(packageName, _packageRoot, cacheConfig);
}
public virtual void OnDestroy()
{
if (FileCache != null)
{
FileCache.Dispose();
FileCache = null;
}
if (DownloadBackend != null)
{
DownloadBackend.Dispose();
@@ -187,11 +150,7 @@ namespace YooAsset
public virtual bool Belong(PackageBundle bundle)
{
return _wrappers.ContainsKey(bundle.BundleGUID);
}
public virtual bool Exists(PackageBundle bundle)
{
return _wrappers.ContainsKey(bundle.BundleGUID);
return FileCache.IsCached(bundle.BundleGUID);
}
public virtual bool NeedDownload(PackageBundle bundle)
{
@@ -205,71 +164,27 @@ namespace YooAsset
{
return false;
}
public virtual string GetBundleFilePath(PackageBundle bundle)
{
throw new System.NotImplementedException();
}
#region
private LoadWebAssetBundleOperation DefaultLoadAssetBundleOperationFactory(bool bundleEncrypted, LoadWebAssetBundleOptions options)
{
if (bundleEncrypted)
{
string error = $"{nameof(DefaultLoadWebAssetBundleOperation)} cannot load encrypted bundle. Please provide a custom {nameof(LoadWebAssetBundleOperationFactory)}.";
return new LoadWebAssetBundleCompleteOperation(error, options);
}
else
{
return new DefaultLoadWebAssetBundleOperation(options);
}
}
protected string GetDefaultWebPackageRoot(string packageName)
{
string rootDirectory = YooAssetSettingsData.GetYooDefaultBuildinRoot();
return PathUtility.Combine(rootDirectory, packageName);
}
public string GetWebFileLoadPath(PackageBundle bundle)
{
if (_webFilePathMapping.TryGetValue(bundle.BundleGUID, out string filePath) == false)
{
filePath = PathUtility.Combine(_webPackageRoot, bundle.FileName);
_webFilePathMapping.Add(bundle.BundleGUID, filePath);
}
return filePath;
}
public string GetWebPackageVersionFilePath()
{
string fileName = YooAssetSettingsData.GetPackageVersionFileName(PackageName);
return PathUtility.Combine(FileRoot, fileName);
return PathUtility.Combine(_packageRoot, fileName);
}
public string GetWebPackageHashFilePath(string packageVersion)
{
string fileName = YooAssetSettingsData.GetPackageHashFileName(PackageName, packageVersion);
return PathUtility.Combine(FileRoot, fileName);
return PathUtility.Combine(_packageRoot, fileName);
}
public string GetWebPackageManifestFilePath(string packageVersion)
{
string fileName = YooAssetSettingsData.GetManifestBinaryFileName(PackageName, packageVersion);
return PathUtility.Combine(FileRoot, fileName);
}
public string GetCatalogBinaryFileLoadPath()
{
return PathUtility.Combine(_webPackageRoot, BuiltinFileSystemConstants.BuiltinCatalogBinaryFileName);
}
/// <summary>
/// 记录内置文件信息
/// </summary>
public bool RecordCatalogFile(string bundleGUID, FileWrapper wrapper)
{
if (_wrappers.ContainsKey(bundleGUID))
{
YooLogger.Error($"{nameof(WebServerFileSystem)} has element : {bundleGUID}");
return false;
}
_wrappers.Add(bundleGUID, wrapper);
return true;
return PathUtility.Combine(_packageRoot, fileName);
}
#endregion
}