refactor the runtime code
重构了运行时代码,支持全新的文件系统。
This commit is contained in:
@@ -0,0 +1,537 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 缓存文件系统
|
||||
/// 说明:正在进行的下载器会在ResourcePackage销毁的时候执行Abort操作!
|
||||
/// </summary>
|
||||
internal class DefaultCacheFileSystem : IFileSystem
|
||||
{
|
||||
public class FileWrapper
|
||||
{
|
||||
public string InfoFilePath { private set; get; }
|
||||
public string DataFilePath { private set; get; }
|
||||
public string DataFileCRC { private set; get; }
|
||||
public long DataFileSize { private set; get; }
|
||||
|
||||
public FileWrapper(string infoFilePath, string dataFilePath, string dataFileCRC, long dataFileSize)
|
||||
{
|
||||
InfoFilePath = infoFilePath;
|
||||
DataFilePath = dataFilePath;
|
||||
DataFileCRC = dataFileCRC;
|
||||
DataFileSize = dataFileSize;
|
||||
}
|
||||
}
|
||||
|
||||
protected readonly Dictionary<string, DefaultDownloadFileOperation> _downloaders = new Dictionary<string, DefaultDownloadFileOperation>(1000);
|
||||
protected readonly Dictionary<string, FileWrapper> _wrappers = new Dictionary<string, FileWrapper>(10000);
|
||||
protected readonly Dictionary<string, Stream> _loadedStream = new Dictionary<string, Stream>(10000);
|
||||
protected readonly Dictionary<string, string> _dataFilePaths = new Dictionary<string, string>(10000);
|
||||
protected readonly Dictionary<string, string> _infoFilePaths = new Dictionary<string, string>(10000);
|
||||
protected readonly Dictionary<string, string> _tempFilePaths = new Dictionary<string, string>(10000);
|
||||
protected readonly List<string> _removeList = new List<string>(1000);
|
||||
protected string _packageRoot;
|
||||
protected string _saveFileRoot;
|
||||
protected string _tempFileRoot;
|
||||
protected string _manifestFileRoot;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 包裹名称
|
||||
/// </summary>
|
||||
public string PackageName { private set; get; }
|
||||
|
||||
/// <summary>
|
||||
/// 文件访问权限
|
||||
/// </summary>
|
||||
public EFileAccess FileSystemAccess
|
||||
{
|
||||
get
|
||||
{
|
||||
return EFileAccess.ReadWrite;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 文件根目录
|
||||
/// </summary>
|
||||
public string FileRoot
|
||||
{
|
||||
get
|
||||
{
|
||||
return _packageRoot;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 文件数量
|
||||
/// </summary>
|
||||
public int FileCount
|
||||
{
|
||||
get
|
||||
{
|
||||
return _wrappers.Count;
|
||||
}
|
||||
}
|
||||
|
||||
#region 自定义参数
|
||||
/// <summary>
|
||||
/// 自定义参数:远程服务接口
|
||||
/// </summary>
|
||||
public IRemoteServices RemoteServices { private set; get; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// 自定义参数:初始化的时候缓存文件校验级别
|
||||
/// </summary>
|
||||
public EFileVerifyLevel FileVerifyLevel { private set; get; } = EFileVerifyLevel.Middle;
|
||||
|
||||
/// <summary>
|
||||
/// 自定义参数:数据文件追加文件格式
|
||||
/// </summary>
|
||||
public bool AppendFileExtension { private set; get; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 自定义参数:原生文件构建管线
|
||||
/// </summary>
|
||||
public bool RawFileBuildPipeline { private set; get; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// 自定义参数:启用断点续传的最小尺寸
|
||||
/// </summary>
|
||||
public long ResumeDownloadMinimumSize { private set; get; } = long.MaxValue;
|
||||
|
||||
/// <summary>
|
||||
/// 自定义参数:断点续传下载器关注的错误码
|
||||
/// </summary>
|
||||
public List<long> ResumeDownloadResponseCodes { private set; get; } = null;
|
||||
#endregion
|
||||
|
||||
|
||||
public DefaultCacheFileSystem()
|
||||
{
|
||||
}
|
||||
public virtual FSInitializeFileSystemOperation InitializeFileSystemAsync()
|
||||
{
|
||||
var operation = new DCFSInitializeOperation(this);
|
||||
OperationSystem.StartOperation(PackageName, operation);
|
||||
return operation;
|
||||
}
|
||||
public virtual FSLoadPackageManifestOperation LoadPackageManifestAsync(params object[] args)
|
||||
{
|
||||
string packageVersion = args[0] as string;
|
||||
int timeout = (int)args[1];
|
||||
var operation = new DCFSLoadPackageManifestOperation(this, packageVersion, timeout);
|
||||
OperationSystem.StartOperation(PackageName, operation);
|
||||
return operation;
|
||||
}
|
||||
public virtual FSRequestPackageVersionOperation RequestPackageVersionAsync(params object[] args)
|
||||
{
|
||||
bool appendTimeTicks = (bool)args[0];
|
||||
int timeout = (int)args[1];
|
||||
var operation = new DCFSRequestPackageVersionOperation(this, appendTimeTicks, timeout);
|
||||
OperationSystem.StartOperation(PackageName, operation);
|
||||
return operation;
|
||||
}
|
||||
public virtual FSClearAllBundleFilesOperation ClearAllBundleFilesAsync(params object[] args)
|
||||
{
|
||||
var operation = new DCFSClearAllBundleFilesOperation(this);
|
||||
OperationSystem.StartOperation(PackageName, operation);
|
||||
return operation;
|
||||
}
|
||||
public virtual FSClearUnusedBundleFilesOperation ClearUnusedBundleFilesAsync(params object[] args)
|
||||
{
|
||||
PackageManifest manifest = args[0] as PackageManifest;
|
||||
var operation = new DCFSClearUnusedBundleFilesOperation(this, manifest);
|
||||
OperationSystem.StartOperation(PackageName, operation);
|
||||
return operation;
|
||||
}
|
||||
public virtual FSDownloadFileOperation DownloadFileAsync(params object[] args)
|
||||
{
|
||||
PackageBundle bundle = args[0] as PackageBundle;
|
||||
string localCopyFilePath = (string)args[1];
|
||||
int failedTryAgain = (int)args[2];
|
||||
int timeout = (int)args[3];
|
||||
|
||||
// 查询旧的下载器
|
||||
if (_downloaders.TryGetValue(bundle.BundleGUID, out var oldDownloader))
|
||||
{
|
||||
oldDownloader.Reference();
|
||||
return oldDownloader;
|
||||
}
|
||||
|
||||
// 创建新的下载器
|
||||
{
|
||||
string mainURL;
|
||||
string fallbackURL;
|
||||
if (string.IsNullOrEmpty(localCopyFilePath))
|
||||
{
|
||||
mainURL = RemoteServices.GetRemoteMainURL(bundle.FileName);
|
||||
fallbackURL = RemoteServices.GetRemoteFallbackURL(bundle.FileName);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 注意:把本地文件路径指定为远端下载地址
|
||||
mainURL = DownloadSystemHelper.ConvertToWWWPath(localCopyFilePath);
|
||||
fallbackURL = mainURL;
|
||||
}
|
||||
|
||||
if (bundle.FileSize >= ResumeDownloadMinimumSize)
|
||||
{
|
||||
var newDownloader = new DCFSDownloadResumeFileOperation(this, bundle, mainURL, fallbackURL, failedTryAgain, timeout);
|
||||
newDownloader.Reference();
|
||||
_downloaders.Add(bundle.BundleGUID, newDownloader);
|
||||
OperationSystem.StartOperation(PackageName, newDownloader);
|
||||
return newDownloader;
|
||||
}
|
||||
else
|
||||
{
|
||||
var newDownloader = new DCFSDownloadNormalFileOperation(this, bundle, mainURL, fallbackURL, failedTryAgain, timeout);
|
||||
newDownloader.Reference();
|
||||
_downloaders.Add(bundle.BundleGUID, newDownloader);
|
||||
OperationSystem.StartOperation(PackageName, newDownloader);
|
||||
return newDownloader;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void SetParameter(string name, object value)
|
||||
{
|
||||
if (name == "REMOTE_SERVICES")
|
||||
{
|
||||
RemoteServices = (IRemoteServices)value;
|
||||
}
|
||||
else if (name == "FILE_VERIFY_LEVEL")
|
||||
{
|
||||
FileVerifyLevel = (EFileVerifyLevel)value;
|
||||
}
|
||||
else if (name == "APPEND_FILE_EXTENSION")
|
||||
{
|
||||
AppendFileExtension = (bool)value;
|
||||
}
|
||||
else if (name == "RAW_FILE_BUILD_PIPELINE")
|
||||
{
|
||||
RawFileBuildPipeline = (bool)value;
|
||||
}
|
||||
else if (name == "RESUME_DOWNLOAD_MINMUM_SIZE")
|
||||
{
|
||||
ResumeDownloadMinimumSize = (long)value;
|
||||
}
|
||||
else if (name == "RESUME_DOWNLOAD_RESPONSE_CODES")
|
||||
{
|
||||
ResumeDownloadResponseCodes = (List<long>)value;
|
||||
}
|
||||
else
|
||||
{
|
||||
YooLogger.Warning($"Invalid parameter : {name}");
|
||||
}
|
||||
}
|
||||
public virtual void OnCreate(string packageName, string rootDirectory)
|
||||
{
|
||||
PackageName = packageName;
|
||||
|
||||
if (string.IsNullOrEmpty(rootDirectory))
|
||||
rootDirectory = GetDefaultRoot();
|
||||
|
||||
_packageRoot = PathUtility.Combine(rootDirectory, packageName);
|
||||
_saveFileRoot = PathUtility.Combine(_packageRoot, DefaultCacheFileSystemDefine.SaveFilesFolderName);
|
||||
_tempFileRoot = PathUtility.Combine(_packageRoot, DefaultCacheFileSystemDefine.TempFilesFolderName);
|
||||
_manifestFileRoot = PathUtility.Combine(_packageRoot, DefaultCacheFileSystemDefine.ManifestFilesFolderName);
|
||||
}
|
||||
public virtual void OnUpdate()
|
||||
{
|
||||
_removeList.Clear();
|
||||
|
||||
foreach (var valuePair in _downloaders)
|
||||
{
|
||||
var downloader = valuePair.Value;
|
||||
|
||||
// 注意:主动终止引用计数为零的下载任务
|
||||
if (downloader.RefCount <= 0)
|
||||
{
|
||||
_removeList.Add(valuePair.Key);
|
||||
downloader.SetAbort();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (downloader.IsDone)
|
||||
_removeList.Add(valuePair.Key);
|
||||
}
|
||||
|
||||
foreach (var key in _removeList)
|
||||
{
|
||||
_downloaders.Remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual bool Belong(PackageBundle bundle)
|
||||
{
|
||||
// 注意:缓存文件系统保底加载!
|
||||
return true;
|
||||
}
|
||||
public virtual bool Belong(string bundleGUID)
|
||||
{
|
||||
// 注意:缓存文件系统保底加载!
|
||||
return true;
|
||||
}
|
||||
public virtual bool Exists(PackageBundle packageBundle)
|
||||
{
|
||||
return _wrappers.ContainsKey(packageBundle.BundleGUID);
|
||||
}
|
||||
public virtual bool Exists(string bundleGUID)
|
||||
{
|
||||
return _wrappers.ContainsKey(bundleGUID);
|
||||
}
|
||||
|
||||
public virtual bool CheckNeedDownload(PackageBundle bundle)
|
||||
{
|
||||
if (Belong(bundle) == false)
|
||||
return false;
|
||||
|
||||
return Exists(bundle) == false;
|
||||
}
|
||||
public virtual bool CheckNeedUnpack(PackageBundle bundle)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
public virtual bool CheckNeedImport(PackageBundle bundle)
|
||||
{
|
||||
if (Belong(bundle) == false)
|
||||
return false;
|
||||
|
||||
return Exists(bundle) == false;
|
||||
}
|
||||
|
||||
public virtual bool WriteFile(PackageBundle bundle, string copyPath)
|
||||
{
|
||||
if (_wrappers.ContainsKey(bundle.BundleGUID))
|
||||
{
|
||||
throw new Exception("Should never get here !");
|
||||
}
|
||||
|
||||
string infoFilePath = GetInfoFilePath(bundle);
|
||||
string dataFilePath = GetDataFilePath(bundle);
|
||||
|
||||
try
|
||||
{
|
||||
if (File.Exists(infoFilePath))
|
||||
File.Delete(infoFilePath);
|
||||
if (File.Exists(dataFilePath))
|
||||
File.Delete(dataFilePath);
|
||||
|
||||
FileUtility.CreateFileDirectory(dataFilePath);
|
||||
|
||||
// 拷贝数据文件
|
||||
FileInfo fileInfo = new FileInfo(copyPath);
|
||||
fileInfo.CopyTo(dataFilePath);
|
||||
|
||||
// 写入文件信息
|
||||
WriteInfoFile(infoFilePath, bundle.FileCRC, bundle.FileSize);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
YooLogger.Error($"Failed to write cache file ! {e.Message}");
|
||||
return false;
|
||||
}
|
||||
|
||||
FileWrapper wrapper = new FileWrapper(infoFilePath, dataFilePath, bundle.FileCRC, bundle.FileSize);
|
||||
return Record(bundle.BundleGUID, wrapper);
|
||||
}
|
||||
public virtual bool DeleteFile(PackageBundle bundle)
|
||||
{
|
||||
return DeleteFile(bundle.BundleGUID);
|
||||
}
|
||||
public virtual bool DeleteFile(string bundleGUID)
|
||||
{
|
||||
if (_wrappers.TryGetValue(bundleGUID, out FileWrapper wrapper))
|
||||
{
|
||||
try
|
||||
{
|
||||
string dataFilePath = wrapper.DataFilePath;
|
||||
FileInfo fileInfo = new FileInfo(dataFilePath);
|
||||
if (fileInfo.Exists)
|
||||
fileInfo.Directory.Delete(true);
|
||||
_wrappers.Remove(bundleGUID);
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
YooLogger.Error($"Failed to delete cache file ! {e.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public virtual EFileVerifyResult VerifyFile(PackageBundle bundle)
|
||||
{
|
||||
if (_wrappers.TryGetValue(bundle.BundleGUID, out FileWrapper wrapper) == false)
|
||||
return EFileVerifyResult.CacheNotFound;
|
||||
|
||||
EFileVerifyResult result = FileSystemHelper.FileVerify(wrapper.DataFilePath, wrapper.DataFileSize, wrapper.DataFileCRC, EFileVerifyLevel.High);
|
||||
return result;
|
||||
}
|
||||
|
||||
public virtual byte[] ReadFileBytes(PackageBundle bundle)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
public virtual string ReadFileText(PackageBundle bundle)
|
||||
{
|
||||
throw new System.NotImplementedException();
|
||||
}
|
||||
|
||||
public virtual FSLoadBundleOperation LoadBundleFile(PackageBundle bundle)
|
||||
{
|
||||
if (RawFileBuildPipeline)
|
||||
{
|
||||
var operation = new DCFSLoadRawBundleOperation(this, bundle);
|
||||
OperationSystem.StartOperation(PackageName, operation);
|
||||
return operation;
|
||||
}
|
||||
else
|
||||
{
|
||||
var operation = new DCFSLoadAssetBundleOperation(this, bundle);
|
||||
OperationSystem.StartOperation(PackageName, operation);
|
||||
return operation;
|
||||
}
|
||||
}
|
||||
public virtual void UnloadBundleFile(PackageBundle bundle, object result)
|
||||
{
|
||||
AssetBundle assetBundle = result as AssetBundle;
|
||||
if (assetBundle == null)
|
||||
return;
|
||||
|
||||
if (assetBundle != null)
|
||||
assetBundle.Unload(true);
|
||||
|
||||
if (_loadedStream.TryGetValue(bundle.BundleGUID, out Stream managedStream))
|
||||
{
|
||||
managedStream.Close();
|
||||
managedStream.Dispose();
|
||||
_loadedStream.Remove(bundle.BundleGUID);
|
||||
}
|
||||
}
|
||||
|
||||
#region 内部方法
|
||||
private readonly BufferWriter _sharedBuffer = new BufferWriter(1024);
|
||||
public void WriteInfoFile(string filePath, string dataFileCRC, long dataFileSize)
|
||||
{
|
||||
using (FileStream fs = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.Read))
|
||||
{
|
||||
_sharedBuffer.Clear();
|
||||
_sharedBuffer.WriteUTF8(dataFileCRC);
|
||||
_sharedBuffer.WriteInt64(dataFileSize);
|
||||
_sharedBuffer.WriteToStream(fs);
|
||||
fs.Flush();
|
||||
}
|
||||
}
|
||||
public void ReadInfoFile(string filePath, out string dataFileCRC, out long dataFileSize)
|
||||
{
|
||||
byte[] binaryData = FileUtility.ReadAllBytes(filePath);
|
||||
BufferReader buffer = new BufferReader(binaryData);
|
||||
dataFileCRC = buffer.ReadUTF8();
|
||||
dataFileSize = buffer.ReadInt64();
|
||||
}
|
||||
|
||||
protected string GetDefaultRoot()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
// 注意:为了方便调试查看,编辑器下把存储目录放到项目里。
|
||||
string projectPath = Path.GetDirectoryName(UnityEngine.Application.dataPath);
|
||||
projectPath = PathUtility.RegularPath(projectPath);
|
||||
return PathUtility.Combine(projectPath, YooAssetSettingsData.Setting.DefaultYooFolderName);
|
||||
#elif UNITY_STANDALONE
|
||||
return PathUtility.Combine(UnityEngine.Application.dataPath, YooAssetSettingsData.Setting.DefaultYooFolderName);
|
||||
#else
|
||||
return PathUtility.Combine(UnityEngine.Application.persistentDataPath, YooAssetSettingsData.Setting.DefaultYooFolderName);
|
||||
#endif
|
||||
}
|
||||
protected string GetDataFilePath(PackageBundle bundle)
|
||||
{
|
||||
if (_dataFilePaths.TryGetValue(bundle.BundleGUID, out string filePath) == false)
|
||||
{
|
||||
string folderName = bundle.FileHash.Substring(0, 2);
|
||||
filePath = PathUtility.Combine(_saveFileRoot, folderName, bundle.BundleGUID, DefaultCacheFileSystemDefine.SaveBundleDataFileName);
|
||||
if (AppendFileExtension)
|
||||
filePath += bundle.FileExtension;
|
||||
_dataFilePaths.Add(bundle.BundleGUID, filePath);
|
||||
}
|
||||
return filePath;
|
||||
}
|
||||
protected string GetInfoFilePath(PackageBundle bundle)
|
||||
{
|
||||
if (_infoFilePaths.TryGetValue(bundle.BundleGUID, out string filePath) == false)
|
||||
{
|
||||
string folderName = bundle.FileHash.Substring(0, 2);
|
||||
filePath = PathUtility.Combine(_saveFileRoot, folderName, bundle.BundleGUID, DefaultCacheFileSystemDefine.SaveBundleInfoFileName);
|
||||
_infoFilePaths.Add(bundle.BundleGUID, filePath);
|
||||
}
|
||||
return filePath;
|
||||
}
|
||||
public string GetTempFilePath(PackageBundle bundle)
|
||||
{
|
||||
if (_tempFilePaths.TryGetValue(bundle.BundleGUID, out string filePath) == false)
|
||||
{
|
||||
filePath = PathUtility.Combine(_tempFileRoot, bundle.BundleGUID);
|
||||
_tempFilePaths.Add(bundle.BundleGUID, filePath);
|
||||
}
|
||||
return filePath;
|
||||
}
|
||||
public string GetFileLoadPath(PackageBundle bundle)
|
||||
{
|
||||
return GetDataFilePath(bundle);
|
||||
}
|
||||
public string GetCacheFilesRoot()
|
||||
{
|
||||
return _saveFileRoot;
|
||||
}
|
||||
public string GetCachePackageHashFilePath(string packageVersion)
|
||||
{
|
||||
string fileName = YooAssetSettingsData.GetPackageHashFileName(PackageName, packageVersion);
|
||||
return PathUtility.Combine(_manifestFileRoot, fileName);
|
||||
}
|
||||
public string GetCachePackageManifestFilePath(string packageVersion)
|
||||
{
|
||||
string fileName = YooAssetSettingsData.GetManifestBinaryFileName(PackageName, packageVersion);
|
||||
return PathUtility.Combine(_manifestFileRoot, fileName);
|
||||
}
|
||||
public string GetSandboxAppFootPrintFilePath()
|
||||
{
|
||||
return PathUtility.Combine(_manifestFileRoot, DefaultCacheFileSystemDefine.AppFootPrintFileName);
|
||||
}
|
||||
public void DeleteAllManifestFiles()
|
||||
{
|
||||
if (Directory.Exists(_manifestFileRoot))
|
||||
{
|
||||
Directory.Delete(_manifestFileRoot, true);
|
||||
}
|
||||
}
|
||||
public List<string> GetAllCachedBundleGUIDs()
|
||||
{
|
||||
return _wrappers.Keys.ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 记录缓存信息
|
||||
/// </summary>
|
||||
public bool Record(string bundleGUID, FileWrapper wrapper)
|
||||
{
|
||||
if (Exists(bundleGUID))
|
||||
{
|
||||
YooLogger.Error($"{nameof(DefaultCacheFileSystem)} has element : {bundleGUID}");
|
||||
return false;
|
||||
}
|
||||
|
||||
_wrappers.Add(bundleGUID, wrapper);
|
||||
return true;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4989ddcb6c99102429eeefffc3675ae5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
internal class DefaultCacheFileSystemDefine
|
||||
{
|
||||
/// <summary>
|
||||
/// 保存的数据文件名称
|
||||
/// </summary>
|
||||
public const string SaveBundleDataFileName = "__data";
|
||||
|
||||
/// <summary>
|
||||
/// 保存的信息文件名称
|
||||
/// </summary>
|
||||
public const string SaveBundleInfoFileName = "__info";
|
||||
|
||||
/// <summary>
|
||||
/// 保存的资源文件的文件夹名称
|
||||
/// </summary>
|
||||
public const string SaveFilesFolderName = "CacheFiles";
|
||||
|
||||
/// <summary>
|
||||
/// 下载的临时文件的文件夹名称
|
||||
/// </summary>
|
||||
public const string TempFilesFolderName = "CacheTempFiles";
|
||||
|
||||
/// <summary>
|
||||
/// 保存的清单文件的文件夹名称
|
||||
/// </summary>
|
||||
public const string ManifestFilesFolderName = "ManifestFiles";
|
||||
|
||||
/// <summary>
|
||||
/// 记录应用程序版本的文件名称
|
||||
/// </summary>
|
||||
public const string AppFootPrintFileName = "ApplicationFootPrint.bytes";
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 610912866fe58794a904b43c2e24d84d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 09e4cebb2073ab945ac09e9099b327ad
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
internal sealed class DCFSClearAllBundleFilesOperation : FSClearAllBundleFilesOperation
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
GetAllCacheFiles,
|
||||
ClearAllCacheFiles,
|
||||
Done,
|
||||
}
|
||||
|
||||
private readonly DefaultCacheFileSystem _fileSystem;
|
||||
private List<string> _allBundleGUIDs;
|
||||
private int _fileTotalCount = 0;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
|
||||
internal DCFSClearAllBundleFilesOperation(DefaultCacheFileSystem fileSystem)
|
||||
{
|
||||
_fileSystem = fileSystem;
|
||||
}
|
||||
internal override void InternalOnStart()
|
||||
{
|
||||
_steps = ESteps.GetAllCacheFiles;
|
||||
}
|
||||
internal override void InternalOnUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
if (_steps == ESteps.GetAllCacheFiles)
|
||||
{
|
||||
_allBundleGUIDs = _fileSystem.GetAllCachedBundleGUIDs();
|
||||
_fileTotalCount = _allBundleGUIDs.Count;
|
||||
YooLogger.Log($"Found all cache file count : {_fileTotalCount}");
|
||||
_steps = ESteps.ClearAllCacheFiles;
|
||||
}
|
||||
|
||||
if (_steps == ESteps.ClearAllCacheFiles)
|
||||
{
|
||||
for (int i = _allBundleGUIDs.Count - 1; i >= 0; i--)
|
||||
{
|
||||
string bundleGUID = _allBundleGUIDs[i];
|
||||
_fileSystem.DeleteFile(bundleGUID);
|
||||
_allBundleGUIDs.RemoveAt(i);
|
||||
if (OperationSystem.IsBusy)
|
||||
break;
|
||||
}
|
||||
|
||||
if (_fileTotalCount == 0)
|
||||
Progress = 1.0f;
|
||||
else
|
||||
Progress = 1.0f - (_allBundleGUIDs.Count / _fileTotalCount);
|
||||
|
||||
if (_allBundleGUIDs.Count == 0)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Succeed;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: daed187502431d347bf11bddcf8d77de
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
internal sealed class DCFSClearUnusedBundleFilesOperation : FSClearUnusedBundleFilesOperation
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
GetUnusedCacheFiles,
|
||||
ClearUnusedCacheFiles,
|
||||
Done,
|
||||
}
|
||||
|
||||
private readonly DefaultCacheFileSystem _fileSystem;
|
||||
private readonly PackageManifest _manifest;
|
||||
private List<string> _unusedBundleGUIDs;
|
||||
private int _unusedFileTotalCount = 0;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
|
||||
internal DCFSClearUnusedBundleFilesOperation(DefaultCacheFileSystem fileSystem, PackageManifest manifest)
|
||||
{
|
||||
_fileSystem = fileSystem;
|
||||
_manifest = manifest;
|
||||
}
|
||||
internal override void InternalOnStart()
|
||||
{
|
||||
_steps = ESteps.GetUnusedCacheFiles;
|
||||
}
|
||||
internal override void InternalOnUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
if (_steps == ESteps.GetUnusedCacheFiles)
|
||||
{
|
||||
_steps = ESteps.ClearUnusedCacheFiles;
|
||||
_unusedBundleGUIDs = GetUnusedBundleGUIDs();
|
||||
_unusedFileTotalCount = _unusedBundleGUIDs.Count;
|
||||
YooLogger.Log($"Found unused cache file count : {_unusedFileTotalCount}");
|
||||
}
|
||||
|
||||
if (_steps == ESteps.ClearUnusedCacheFiles)
|
||||
{
|
||||
for (int i = _unusedBundleGUIDs.Count - 1; i >= 0; i--)
|
||||
{
|
||||
string bundleGUID = _unusedBundleGUIDs[i];
|
||||
_fileSystem.DeleteFile(bundleGUID);
|
||||
_unusedBundleGUIDs.RemoveAt(i);
|
||||
if (OperationSystem.IsBusy)
|
||||
break;
|
||||
}
|
||||
|
||||
if (_unusedFileTotalCount == 0)
|
||||
Progress = 1.0f;
|
||||
else
|
||||
Progress = 1.0f - (_unusedBundleGUIDs.Count / _unusedFileTotalCount);
|
||||
|
||||
if (_unusedBundleGUIDs.Count == 0)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Succeed;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<string> GetUnusedBundleGUIDs()
|
||||
{
|
||||
var allBundleGUIDs = _fileSystem.GetAllCachedBundleGUIDs();
|
||||
List<string> result = new List<string>(allBundleGUIDs.Count);
|
||||
foreach (var bundleGUID in allBundleGUIDs)
|
||||
{
|
||||
if (_manifest.IsIncludeBundleFile(bundleGUID) == false)
|
||||
{
|
||||
result.Add(bundleGUID);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: be7b242f10abf524fa59e9ca0d12b052
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+432
@@ -0,0 +1,432 @@
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Networking;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
internal sealed class DCFSDownloadNormalFileOperation : DefaultDownloadFileOperation
|
||||
{
|
||||
private readonly DefaultCacheFileSystem _fileSystem;
|
||||
private VerifyTempFileOperation _verifyOperation;
|
||||
private string _fileSavePath;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
internal DCFSDownloadNormalFileOperation(DefaultCacheFileSystem fileSystem, PackageBundle bundle, string mainURL, string fallbackURL, int failedTryAgain, int timeout)
|
||||
: base(bundle, mainURL, fallbackURL, failedTryAgain, timeout)
|
||||
{
|
||||
_fileSystem = fileSystem;
|
||||
}
|
||||
internal override void InternalOnStart()
|
||||
{
|
||||
_fileSavePath = _fileSystem.GetTempFilePath(Bundle);
|
||||
|
||||
// 注意:检测文件是否存在
|
||||
if (_fileSystem.Exists(Bundle))
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Succeed;
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.CreateRequest;
|
||||
}
|
||||
}
|
||||
internal override void InternalOnUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
// 创建下载器
|
||||
if (_steps == ESteps.CreateRequest)
|
||||
{
|
||||
FileUtility.CreateFileDirectory(_fileSavePath);
|
||||
|
||||
// 获取请求地址
|
||||
_requestURL = GetRequestURL();
|
||||
|
||||
// 重置变量
|
||||
_isAbort = false;
|
||||
_latestDownloadBytes = 0;
|
||||
_latestDownloadRealtime = Time.realtimeSinceStartup;
|
||||
DownloadProgress = 0f;
|
||||
DownloadedBytes = 0;
|
||||
|
||||
// 重置计时器
|
||||
if (_tryAgainTimer > 0f)
|
||||
YooLogger.Warning($"Try again download : {_requestURL}");
|
||||
_tryAgainTimer = 0f;
|
||||
|
||||
// 删除临时文件
|
||||
if (File.Exists(_fileSavePath))
|
||||
File.Delete(_fileSavePath);
|
||||
|
||||
// 创建下载器
|
||||
CreateWebRequest();
|
||||
|
||||
_steps = ESteps.CheckRequest;
|
||||
}
|
||||
|
||||
// 检测下载结果
|
||||
if (_steps == ESteps.CheckRequest)
|
||||
{
|
||||
DownloadProgress = _webRequest.downloadProgress;
|
||||
DownloadedBytes = (long)_webRequest.downloadedBytes;
|
||||
Progress = DownloadProgress;
|
||||
if (_webRequest.isDone == false)
|
||||
{
|
||||
CheckRequestTimeout();
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查网络错误
|
||||
if (CheckRequestResult())
|
||||
_steps = ESteps.VerifyTempFile;
|
||||
else
|
||||
_steps = ESteps.TryAgain;
|
||||
|
||||
// 注意:最终释放请求器
|
||||
DisposeWebRequest();
|
||||
}
|
||||
|
||||
// 验证下载文件
|
||||
if (_steps == ESteps.VerifyTempFile)
|
||||
{
|
||||
var element = new TempFileElement(_fileSavePath, Bundle.FileCRC, Bundle.FileSize);
|
||||
_verifyOperation = new VerifyTempFileOperation(element);
|
||||
OperationSystem.StartOperation(_fileSystem.PackageName, _verifyOperation);
|
||||
_steps = ESteps.CheckVerifyTempFile;
|
||||
}
|
||||
|
||||
// 等待验证完成
|
||||
if (_steps == ESteps.CheckVerifyTempFile)
|
||||
{
|
||||
// 注意:同步解压文件更新
|
||||
_verifyOperation.InternalOnUpdate();
|
||||
if (_verifyOperation.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_verifyOperation.Status == EOperationStatus.Succeed)
|
||||
{
|
||||
if (_fileSystem.WriteFile(Bundle, _fileSavePath))
|
||||
{
|
||||
Status = EOperationStatus.Succeed;
|
||||
_steps = ESteps.Done;
|
||||
}
|
||||
else
|
||||
{
|
||||
Error = $"{_fileSystem.GetType().FullName} write file failed !";
|
||||
Status = EOperationStatus.Failed;
|
||||
_steps = ESteps.Done;
|
||||
YooLogger.Error(Error);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Error = _verifyOperation.Error;
|
||||
_steps = ESteps.TryAgain;
|
||||
}
|
||||
|
||||
// 注意:验证完成后直接删除文件
|
||||
if (File.Exists(_fileSavePath))
|
||||
File.Delete(_fileSavePath);
|
||||
}
|
||||
|
||||
// 重新尝试下载
|
||||
if (_steps == ESteps.TryAgain)
|
||||
{
|
||||
if (FailedTryAgain <= 0)
|
||||
{
|
||||
Status = EOperationStatus.Failed;
|
||||
_steps = ESteps.Done;
|
||||
YooLogger.Error(Error);
|
||||
return;
|
||||
}
|
||||
|
||||
_tryAgainTimer += Time.unscaledDeltaTime;
|
||||
if (_tryAgainTimer > 1f)
|
||||
{
|
||||
FailedTryAgain--;
|
||||
_steps = ESteps.CreateRequest;
|
||||
YooLogger.Warning(Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
internal override void InternalOnAbort()
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
DisposeWebRequest();
|
||||
}
|
||||
public override void WaitForAsyncComplete()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
// 文件验证
|
||||
if (_verifyOperation != null)
|
||||
{
|
||||
if (_verifyOperation.IsDone == false)
|
||||
_verifyOperation.WaitForAsyncComplete();
|
||||
}
|
||||
|
||||
// 驱动流程
|
||||
InternalOnUpdate();
|
||||
|
||||
// 完成后退出
|
||||
if (IsDone)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateWebRequest()
|
||||
{
|
||||
_webRequest = DownloadSystemHelper.NewUnityWebRequestGet(_requestURL);
|
||||
DownloadHandlerFile handler = new DownloadHandlerFile(_fileSavePath);
|
||||
handler.removeFileOnAbort = true;
|
||||
_webRequest.downloadHandler = handler;
|
||||
_webRequest.disposeDownloadHandlerOnDispose = true;
|
||||
_webRequest.SendWebRequest();
|
||||
}
|
||||
private void DisposeWebRequest()
|
||||
{
|
||||
if (_webRequest != null)
|
||||
{
|
||||
//注意:引擎底层会自动调用Abort方法
|
||||
_webRequest.Dispose();
|
||||
_webRequest = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class DCFSDownloadResumeFileOperation : DefaultDownloadFileOperation
|
||||
{
|
||||
private readonly DefaultCacheFileSystem _fileSystem;
|
||||
private DownloadHandlerFileRange _downloadHandle;
|
||||
private VerifyTempFileOperation _verifyOperation;
|
||||
private long _fileOriginLength = 0;
|
||||
private string _fileSavePath;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
|
||||
internal DCFSDownloadResumeFileOperation(DefaultCacheFileSystem fileSystem, PackageBundle bundle, string mainURL, string fallbackURL, int failedTryAgain, int timeout)
|
||||
: base(bundle, mainURL, fallbackURL, failedTryAgain, timeout)
|
||||
{
|
||||
_fileSystem = fileSystem;
|
||||
}
|
||||
internal override void InternalOnStart()
|
||||
{
|
||||
_fileSavePath = _fileSystem.GetTempFilePath(Bundle);
|
||||
|
||||
// 注意:检测文件是否存在
|
||||
if (_fileSystem.Exists(Bundle))
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Succeed;
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.CreateRequest;
|
||||
}
|
||||
}
|
||||
internal override void InternalOnUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
// 创建下载器
|
||||
if (_steps == ESteps.CreateRequest)
|
||||
{
|
||||
FileUtility.CreateFileDirectory(_fileSavePath);
|
||||
|
||||
// 获取请求地址
|
||||
_requestURL = GetRequestURL();
|
||||
|
||||
// 重置变量
|
||||
_isAbort = false;
|
||||
_latestDownloadBytes = 0;
|
||||
_latestDownloadRealtime = Time.realtimeSinceStartup;
|
||||
_fileOriginLength = 0;
|
||||
DownloadProgress = 0f;
|
||||
DownloadedBytes = 0;
|
||||
|
||||
// 重置计时器
|
||||
if (_tryAgainTimer > 0f)
|
||||
YooLogger.Warning($"Try again download : {_requestURL}");
|
||||
_tryAgainTimer = 0f;
|
||||
|
||||
// 获取下载起始位置
|
||||
long fileBeginLength = -1;
|
||||
if (File.Exists(_fileSavePath))
|
||||
{
|
||||
FileInfo fileInfo = new FileInfo(_fileSavePath);
|
||||
fileBeginLength = fileInfo.Length;
|
||||
_fileOriginLength = fileBeginLength;
|
||||
DownloadedBytes = _fileOriginLength;
|
||||
}
|
||||
|
||||
// 检测下载起始位置
|
||||
if (fileBeginLength >= Bundle.FileSize)
|
||||
{
|
||||
// 删除临时文件
|
||||
if (File.Exists(_fileSavePath))
|
||||
File.Delete(_fileSavePath);
|
||||
}
|
||||
|
||||
// 创建下载器
|
||||
CreateWebRequest(fileBeginLength);
|
||||
|
||||
_steps = ESteps.CheckRequest;
|
||||
}
|
||||
|
||||
// 检测下载结果
|
||||
if (_steps == ESteps.CheckRequest)
|
||||
{
|
||||
DownloadProgress = _webRequest.downloadProgress;
|
||||
DownloadedBytes = _fileOriginLength + (long)_webRequest.downloadedBytes;
|
||||
if (_webRequest.isDone == false)
|
||||
{
|
||||
CheckRequestTimeout();
|
||||
return;
|
||||
}
|
||||
|
||||
// 检查网络错误
|
||||
if (CheckRequestResult())
|
||||
_steps = ESteps.VerifyTempFile;
|
||||
else
|
||||
_steps = ESteps.TryAgain;
|
||||
|
||||
// 在遇到特殊错误的时候删除文件
|
||||
ClearTempFileWhenError();
|
||||
|
||||
// 注意:最终释放请求器
|
||||
DisposeWebRequest();
|
||||
}
|
||||
|
||||
// 验证下载文件
|
||||
if (_steps == ESteps.VerifyTempFile)
|
||||
{
|
||||
var element = new TempFileElement(_fileSavePath, Bundle.FileCRC, Bundle.FileSize);
|
||||
_verifyOperation = new VerifyTempFileOperation(element);
|
||||
OperationSystem.StartOperation(_fileSystem.PackageName, _verifyOperation);
|
||||
_steps = ESteps.CheckVerifyTempFile;
|
||||
}
|
||||
|
||||
// 等待验证完成
|
||||
if (_steps == ESteps.CheckVerifyTempFile)
|
||||
{
|
||||
if (_verifyOperation.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_verifyOperation.Status == EOperationStatus.Succeed)
|
||||
{
|
||||
if (_fileSystem.WriteFile(Bundle, _fileSavePath))
|
||||
{
|
||||
Status = EOperationStatus.Succeed;
|
||||
_steps = ESteps.Done;
|
||||
}
|
||||
else
|
||||
{
|
||||
Error = $"{_fileSystem.GetType().FullName} write file failed : {_fileSavePath}";
|
||||
Status = EOperationStatus.Failed;
|
||||
_steps = ESteps.Done;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Error = _verifyOperation.Error;
|
||||
_steps = ESteps.TryAgain;
|
||||
}
|
||||
|
||||
// 注意:验证完成后直接删除文件
|
||||
if (File.Exists(_fileSavePath))
|
||||
File.Delete(_fileSavePath);
|
||||
}
|
||||
|
||||
// 重新尝试下载
|
||||
if (_steps == ESteps.TryAgain)
|
||||
{
|
||||
if (FailedTryAgain <= 0)
|
||||
{
|
||||
Status = EOperationStatus.Failed;
|
||||
_steps = ESteps.Done;
|
||||
YooLogger.Error(Error);
|
||||
return;
|
||||
}
|
||||
|
||||
_tryAgainTimer += Time.unscaledDeltaTime;
|
||||
if (_tryAgainTimer > 1f)
|
||||
{
|
||||
FailedTryAgain--;
|
||||
_steps = ESteps.CreateRequest;
|
||||
YooLogger.Warning(Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
internal override void InternalOnAbort()
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
DisposeWebRequest();
|
||||
}
|
||||
public override void WaitForAsyncComplete()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
// 文件验证
|
||||
if (_verifyOperation != null)
|
||||
{
|
||||
if (_verifyOperation.IsDone == false)
|
||||
_verifyOperation.WaitForAsyncComplete();
|
||||
}
|
||||
|
||||
// 驱动流程
|
||||
InternalOnUpdate();
|
||||
|
||||
// 完成后退出
|
||||
if (IsDone)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateWebRequest(long beginLength)
|
||||
{
|
||||
_webRequest = DownloadSystemHelper.NewUnityWebRequestGet(_requestURL);
|
||||
#if UNITY_2019_4_OR_NEWER
|
||||
var handler = new DownloadHandlerFile(_fileSavePath, true);
|
||||
handler.removeFileOnAbort = false;
|
||||
#else
|
||||
var handler = new DownloadHandlerFileRange(FileSavePath, Bundle.FileSize, _webRequest);
|
||||
_downloadHandle = handler;
|
||||
#endif
|
||||
_webRequest.downloadHandler = handler;
|
||||
_webRequest.disposeDownloadHandlerOnDispose = true;
|
||||
if (beginLength > 0)
|
||||
_webRequest.SetRequestHeader("Range", $"bytes={beginLength}-");
|
||||
_webRequest.SendWebRequest();
|
||||
}
|
||||
private void DisposeWebRequest()
|
||||
{
|
||||
if (_downloadHandle != null)
|
||||
{
|
||||
_downloadHandle.Cleanup();
|
||||
_downloadHandle = null;
|
||||
}
|
||||
|
||||
if (_webRequest != null)
|
||||
{
|
||||
//注意:引擎底层会自动调用Abort方法
|
||||
_webRequest.Dispose();
|
||||
_webRequest = null;
|
||||
}
|
||||
}
|
||||
private void ClearTempFileWhenError()
|
||||
{
|
||||
if (_fileSystem.ResumeDownloadResponseCodes == null)
|
||||
return;
|
||||
|
||||
//说明:如果遇到以下错误返回码,验证失败直接删除文件
|
||||
if (_fileSystem.ResumeDownloadResponseCodes.Contains(HttpCode))
|
||||
{
|
||||
if (File.Exists(_fileSavePath))
|
||||
File.Delete(_fileSavePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d6f813e2460f55e4ba3f54527e6999e3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
internal class DCFSInitializeOperation : FSInitializeFileSystemOperation
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
CheckAppFootPrint,
|
||||
SearchCacheFiles,
|
||||
VerifyCacheFiles,
|
||||
Done,
|
||||
}
|
||||
|
||||
private readonly DefaultCacheFileSystem _fileSytem;
|
||||
private SearchCacheFilesOperation _searchCacheFilesOp;
|
||||
private VerifyCacheFilesOperation _verifyCacheFilesOp;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
|
||||
internal DCFSInitializeOperation(DefaultCacheFileSystem fileSystem)
|
||||
{
|
||||
_fileSytem = fileSystem;
|
||||
}
|
||||
internal override void InternalOnStart()
|
||||
{
|
||||
_steps = ESteps.CheckAppFootPrint;
|
||||
}
|
||||
internal override void InternalOnUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
if (_steps == ESteps.CheckAppFootPrint)
|
||||
{
|
||||
var appFootPrint = new ApplicationFootPrint(_fileSytem);
|
||||
appFootPrint.Load(_fileSytem.PackageName);
|
||||
|
||||
// 如果水印发生变化,则说明覆盖安装后首次打开游戏
|
||||
if (appFootPrint.IsDirty())
|
||||
{
|
||||
_fileSytem.DeleteAllManifestFiles();
|
||||
appFootPrint.Coverage(_fileSytem.PackageName);
|
||||
YooLogger.Log("Delete manifest files when application foot print dirty !");
|
||||
}
|
||||
|
||||
_steps = ESteps.SearchCacheFiles;
|
||||
}
|
||||
|
||||
if (_steps == ESteps.SearchCacheFiles)
|
||||
{
|
||||
if (_searchCacheFilesOp == null)
|
||||
{
|
||||
_searchCacheFilesOp = new SearchCacheFilesOperation(_fileSytem);
|
||||
OperationSystem.StartOperation(_fileSytem.PackageName, _searchCacheFilesOp);
|
||||
}
|
||||
|
||||
Progress = _searchCacheFilesOp.Progress;
|
||||
if (_searchCacheFilesOp.IsDone == false)
|
||||
return;
|
||||
|
||||
_steps = ESteps.VerifyCacheFiles;
|
||||
}
|
||||
|
||||
if (_steps == ESteps.VerifyCacheFiles)
|
||||
{
|
||||
if (_verifyCacheFilesOp == null)
|
||||
{
|
||||
_verifyCacheFilesOp = new VerifyCacheFilesOperation(_fileSytem, _searchCacheFilesOp.Result);
|
||||
OperationSystem.StartOperation(_fileSytem.PackageName, _verifyCacheFilesOp);
|
||||
}
|
||||
|
||||
Progress = _verifyCacheFilesOp.Progress;
|
||||
if (_verifyCacheFilesOp.IsDone == false)
|
||||
return;
|
||||
|
||||
// 注意:总是返回成功
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Succeed;
|
||||
|
||||
YooLogger.Log($"Package '{_fileSytem.PackageName}' cached files count : {_fileSytem.FileCount}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 443aa31f081edfd458a90e3385a75203
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+330
@@ -0,0 +1,330 @@
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
internal class DCFSLoadAssetBundleOperation : FSLoadBundleOperation
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
DownloadFile,
|
||||
LoadAssetBundle,
|
||||
CheckResult,
|
||||
Done,
|
||||
}
|
||||
|
||||
private readonly DefaultCacheFileSystem _fileSystem;
|
||||
private readonly PackageBundle _bundle;
|
||||
private FSDownloadFileOperation _downloadFileOp;
|
||||
private AssetBundleCreateRequest _createRequest;
|
||||
private bool _isWaitForAsyncComplete = false;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
|
||||
internal DCFSLoadAssetBundleOperation(DefaultCacheFileSystem fileSystem, PackageBundle bundle)
|
||||
{
|
||||
_fileSystem = fileSystem;
|
||||
_bundle = bundle;
|
||||
}
|
||||
internal override void InternalOnStart()
|
||||
{
|
||||
if (_fileSystem.CheckNeedDownload(_bundle))
|
||||
{
|
||||
DownloadProgress = 0f;
|
||||
DownloadedBytes = 0;
|
||||
_steps = ESteps.DownloadFile;
|
||||
}
|
||||
else
|
||||
{
|
||||
DownloadProgress = 1f;
|
||||
DownloadedBytes = _bundle.FileSize;
|
||||
_steps = ESteps.LoadAssetBundle;
|
||||
}
|
||||
}
|
||||
internal override void InternalOnUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
if (_steps == ESteps.DownloadFile)
|
||||
{
|
||||
if (_downloadFileOp == null)
|
||||
{
|
||||
int failedTryAgain = int.MaxValue;
|
||||
int timeout = 60;
|
||||
_downloadFileOp = _fileSystem.DownloadFileAsync(_bundle, null, failedTryAgain, timeout);
|
||||
}
|
||||
|
||||
DownloadProgress = _downloadFileOp.DownloadProgress;
|
||||
DownloadedBytes = _downloadFileOp.DownloadedBytes;
|
||||
if (_downloadFileOp.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_downloadFileOp.Status == EOperationStatus.Succeed)
|
||||
{
|
||||
_steps = ESteps.LoadAssetBundle;
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Failed;
|
||||
Error = _downloadFileOp.Error;
|
||||
}
|
||||
}
|
||||
|
||||
if (_steps == ESteps.LoadAssetBundle)
|
||||
{
|
||||
string filePath = _fileSystem.GetFileLoadPath(_bundle);
|
||||
if (_isWaitForAsyncComplete)
|
||||
{
|
||||
Result = AssetBundle.LoadFromFile(filePath);
|
||||
}
|
||||
else
|
||||
{
|
||||
_createRequest = AssetBundle.LoadFromFileAsync(filePath);
|
||||
}
|
||||
_steps = ESteps.CheckResult;
|
||||
}
|
||||
|
||||
if (_steps == ESteps.CheckResult)
|
||||
{
|
||||
if (_createRequest != null)
|
||||
{
|
||||
if (_isWaitForAsyncComplete)
|
||||
{
|
||||
// 强制挂起主线程(注意:该操作会很耗时)
|
||||
YooLogger.Warning("Suspend the main thread to load unity bundle.");
|
||||
Result = _createRequest.assetBundle;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_createRequest.isDone == false)
|
||||
return;
|
||||
Result = _createRequest.assetBundle;
|
||||
}
|
||||
}
|
||||
|
||||
if (Result != null)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Succeed;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 注意:当缓存文件的校验等级为Low的时候,并不能保证缓存文件的完整性。
|
||||
// 说明:在AssetBundle文件加载失败的情况下,我们需要重新验证文件的完整性!
|
||||
EFileVerifyResult result = _fileSystem.VerifyFile(_bundle);
|
||||
if (result == EFileVerifyResult.Succeed)
|
||||
{
|
||||
// 注意:在安卓移动平台,华为和三星真机上有极小概率加载资源包失败。
|
||||
// 说明:大多数情况在首次安装下载资源到沙盒内,游戏过程中切换到后台再回到游戏内有很大概率触发!
|
||||
string filePath = _fileSystem.GetFileLoadPath(_bundle);
|
||||
byte[] fileData = FileUtility.ReadAllBytes(filePath);
|
||||
if (fileData != null && fileData.Length > 0)
|
||||
{
|
||||
Result = AssetBundle.LoadFromMemory(fileData);
|
||||
if (Result == null)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Failed;
|
||||
Error = $"Failed to load assetBundle from memory : {_bundle.BundleName}";
|
||||
YooLogger.Error(Error);
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Succeed;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Failed;
|
||||
Error = $"Failed to read assetBundle file bytes : {_bundle.BundleName}";
|
||||
YooLogger.Error(Error);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
_fileSystem.DeleteFile(_bundle);
|
||||
Status = EOperationStatus.Failed;
|
||||
Error = $"Find corrupted file and delete the file : {_bundle.BundleName}";
|
||||
YooLogger.Error(Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void WaitForAsyncComplete()
|
||||
{
|
||||
_isWaitForAsyncComplete = true;
|
||||
|
||||
int frame = 1000;
|
||||
while (true)
|
||||
{
|
||||
// 保险机制
|
||||
// 注意:如果需要从远端下载资源,可能会触发保险机制!
|
||||
frame--;
|
||||
if (frame == 0)
|
||||
{
|
||||
Status = EOperationStatus.Failed;
|
||||
Error = $"{nameof(WaitForAsyncComplete)} failed ! Try load bundle {_bundle.BundleName} from remote with sync load method !";
|
||||
_steps = ESteps.Done;
|
||||
YooLogger.Error(Error);
|
||||
}
|
||||
|
||||
// 驱动流程
|
||||
InternalOnUpdate();
|
||||
|
||||
// 完成后退出
|
||||
if (IsDone)
|
||||
break;
|
||||
}
|
||||
}
|
||||
public override void AbortDownloadOperation()
|
||||
{
|
||||
if (_steps == ESteps.DownloadFile)
|
||||
{
|
||||
if (_downloadFileOp != null)
|
||||
_downloadFileOp.SetAbort();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class DCFSLoadRawBundleOperation : FSLoadBundleOperation
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
DownloadFile,
|
||||
LoadRawBundle,
|
||||
CheckResult,
|
||||
Done,
|
||||
}
|
||||
|
||||
private readonly DefaultCacheFileSystem _fileSystem;
|
||||
private readonly PackageBundle _bundle;
|
||||
private FSDownloadFileOperation _downloadFileOp;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
|
||||
internal DCFSLoadRawBundleOperation(DefaultCacheFileSystem fileSystem, PackageBundle bundle)
|
||||
{
|
||||
_fileSystem = fileSystem;
|
||||
_bundle = bundle;
|
||||
}
|
||||
internal override void InternalOnStart()
|
||||
{
|
||||
if (_fileSystem.CheckNeedDownload(_bundle))
|
||||
{
|
||||
DownloadProgress = 0f;
|
||||
DownloadedBytes = 0;
|
||||
_steps = ESteps.DownloadFile;
|
||||
}
|
||||
else
|
||||
{
|
||||
DownloadProgress = 1f;
|
||||
DownloadedBytes = _bundle.FileSize;
|
||||
_steps = ESteps.LoadRawBundle;
|
||||
}
|
||||
}
|
||||
internal override void InternalOnUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
if (_steps == ESteps.DownloadFile)
|
||||
{
|
||||
if (_downloadFileOp == null)
|
||||
{
|
||||
int failedTryAgain = int.MaxValue;
|
||||
int timeout = 60;
|
||||
_downloadFileOp = _fileSystem.DownloadFileAsync(_bundle, null, failedTryAgain, timeout);
|
||||
}
|
||||
|
||||
DownloadProgress = _downloadFileOp.DownloadProgress;
|
||||
DownloadedBytes = _downloadFileOp.DownloadedBytes;
|
||||
if (_downloadFileOp.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_downloadFileOp.Status == EOperationStatus.Succeed)
|
||||
{
|
||||
_steps = ESteps.LoadRawBundle;
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Failed;
|
||||
Error = _downloadFileOp.Error;
|
||||
}
|
||||
}
|
||||
|
||||
if (_steps == ESteps.LoadRawBundle)
|
||||
{
|
||||
string filePath = _fileSystem.GetFileLoadPath(_bundle);
|
||||
Result = filePath;
|
||||
_steps = ESteps.CheckResult;
|
||||
}
|
||||
|
||||
if (_steps == ESteps.CheckResult)
|
||||
{
|
||||
if (Result != null)
|
||||
{
|
||||
string filePath = Result as string;
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Succeed;
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Failed;
|
||||
Error = $"Can not found raw bundle file : {filePath}";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Failed;
|
||||
Error = $"Failed load raw bundle file : {_bundle.BundleName}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void WaitForAsyncComplete()
|
||||
{
|
||||
int frame = 1000;
|
||||
while (true)
|
||||
{
|
||||
// 保险机制
|
||||
// 注意:如果需要从远端下载资源,可能会触发保险机制!
|
||||
frame--;
|
||||
if (frame == 0)
|
||||
{
|
||||
Status = EOperationStatus.Failed;
|
||||
Error = $"{nameof(WaitForAsyncComplete)} failed ! Try load bundle {_bundle.BundleName} from remote with sync load method !";
|
||||
_steps = ESteps.Done;
|
||||
YooLogger.Error(Error);
|
||||
}
|
||||
|
||||
// 驱动流程
|
||||
InternalOnUpdate();
|
||||
|
||||
// 完成后退出
|
||||
if (IsDone)
|
||||
break;
|
||||
}
|
||||
}
|
||||
public override void AbortDownloadOperation()
|
||||
{
|
||||
if (_steps == ESteps.DownloadFile)
|
||||
{
|
||||
if (_downloadFileOp != null)
|
||||
_downloadFileOp.SetAbort();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a653cabf995909d48935a0486db6116f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+159
@@ -0,0 +1,159 @@
|
||||
using System.IO;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
internal class DCFSLoadPackageManifestOperation : FSLoadPackageManifestOperation
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
DownloadPackageHash,
|
||||
DownloadPackageManifest,
|
||||
LoadCachePackageHash,
|
||||
LoadCachePackageManifest,
|
||||
Done,
|
||||
}
|
||||
|
||||
private readonly DefaultCacheFileSystem _fileSystem;
|
||||
private readonly string _packageVersion;
|
||||
private readonly int _timeout;
|
||||
private DownloadPackageHashOperation _downloadPackageHashOp;
|
||||
private DownloadPackageManifestOperation _downloadPackageManifestOp;
|
||||
private LoadCachePackageHashOperation _loadCachePackageHashOp;
|
||||
private LoadCachePackageManifestOperation _loadCachePackageManifestOp;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
|
||||
internal DCFSLoadPackageManifestOperation(DefaultCacheFileSystem fileSystem, string packageVersion, int timeout)
|
||||
{
|
||||
_fileSystem = fileSystem;
|
||||
_packageVersion = packageVersion;
|
||||
_timeout = timeout;
|
||||
}
|
||||
internal override void InternalOnStart()
|
||||
{
|
||||
_steps = ESteps.DownloadPackageHash;
|
||||
}
|
||||
internal override void InternalOnUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
if (_steps == ESteps.DownloadPackageHash)
|
||||
{
|
||||
if (_downloadPackageHashOp == null)
|
||||
{
|
||||
_downloadPackageHashOp = new DownloadPackageHashOperation(_fileSystem, _packageVersion, _timeout);
|
||||
OperationSystem.StartOperation(_fileSystem.PackageName, _downloadPackageHashOp);
|
||||
}
|
||||
|
||||
if (_downloadPackageHashOp.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_downloadPackageHashOp.Status == EOperationStatus.Succeed)
|
||||
{
|
||||
_steps = ESteps.DownloadPackageManifest;
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Failed;
|
||||
Error = _downloadPackageHashOp.Error;
|
||||
}
|
||||
}
|
||||
|
||||
if (_steps == ESteps.DownloadPackageManifest)
|
||||
{
|
||||
if (_downloadPackageManifestOp == null)
|
||||
{
|
||||
_downloadPackageManifestOp = new DownloadPackageManifestOperation(_fileSystem, _packageVersion, _timeout);
|
||||
OperationSystem.StartOperation(_fileSystem.PackageName, _downloadPackageManifestOp);
|
||||
}
|
||||
|
||||
if (_downloadPackageManifestOp.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_downloadPackageManifestOp.Status == EOperationStatus.Succeed)
|
||||
{
|
||||
_steps = ESteps.LoadCachePackageHash;
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Failed;
|
||||
Error = _downloadPackageManifestOp.Error;
|
||||
}
|
||||
}
|
||||
|
||||
if (_steps == ESteps.LoadCachePackageHash)
|
||||
{
|
||||
if (_loadCachePackageHashOp == null)
|
||||
{
|
||||
_loadCachePackageHashOp = new LoadCachePackageHashOperation(_fileSystem, _packageVersion);
|
||||
OperationSystem.StartOperation(_fileSystem.PackageName, _loadCachePackageHashOp);
|
||||
}
|
||||
|
||||
if (_loadCachePackageHashOp.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_loadCachePackageHashOp.Status == EOperationStatus.Succeed)
|
||||
{
|
||||
_steps = ESteps.LoadCachePackageManifest;
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Failed;
|
||||
Error = _loadCachePackageHashOp.Error;
|
||||
ClearCacheFatalFile();
|
||||
}
|
||||
}
|
||||
|
||||
if (_steps == ESteps.LoadCachePackageManifest)
|
||||
{
|
||||
if (_loadCachePackageManifestOp == null)
|
||||
{
|
||||
string packageHash = _loadCachePackageHashOp.PackageHash;
|
||||
_loadCachePackageManifestOp = new LoadCachePackageManifestOperation(_fileSystem, _packageVersion, packageHash);
|
||||
OperationSystem.StartOperation(_fileSystem.PackageName, _loadCachePackageManifestOp);
|
||||
}
|
||||
|
||||
Progress = _loadCachePackageManifestOp.Progress;
|
||||
if (_loadCachePackageManifestOp.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_loadCachePackageManifestOp.Status == EOperationStatus.Succeed)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Result = _loadCachePackageManifestOp.Manifest;
|
||||
Status = EOperationStatus.Succeed;
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Failed;
|
||||
Error = _loadCachePackageManifestOp.Error;
|
||||
ClearCacheFatalFile();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearCacheFatalFile()
|
||||
{
|
||||
// 注意:如果加载沙盒内的清单报错,为了避免流程被卡住,主动把损坏的文件删除。
|
||||
string manifestFilePath = _fileSystem.GetCachePackageManifestFilePath(_packageVersion);
|
||||
if (File.Exists(manifestFilePath))
|
||||
{
|
||||
YooLogger.Warning($"Failed to load cache manifest file : {Error}");
|
||||
YooLogger.Warning($"Invalid cache manifest file have been removed : {manifestFilePath}");
|
||||
File.Delete(manifestFilePath);
|
||||
}
|
||||
|
||||
string hashFilePath = _fileSystem.GetCachePackageHashFilePath(_packageVersion);
|
||||
if (File.Exists(hashFilePath))
|
||||
{
|
||||
File.Delete(hashFilePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2447826454481704ab785153ae89be3a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
internal class DCFSRequestPackageVersionOperation : FSRequestPackageVersionOperation
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
GetPackageVersion,
|
||||
Done,
|
||||
}
|
||||
|
||||
private readonly DefaultCacheFileSystem _fileSystem;
|
||||
private readonly bool _appendTimeTicks;
|
||||
private readonly int _timeout;
|
||||
private DefaultGetRemotePackageVersionOperation _getRemotePackageVersionOp;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
|
||||
internal DCFSRequestPackageVersionOperation(DefaultCacheFileSystem fileSystem, bool appendTimeTicks, int timeout)
|
||||
{
|
||||
_fileSystem = fileSystem;
|
||||
_appendTimeTicks = appendTimeTicks;
|
||||
_timeout = timeout;
|
||||
}
|
||||
internal override void InternalOnStart()
|
||||
{
|
||||
_steps = ESteps.GetPackageVersion;
|
||||
}
|
||||
internal override void InternalOnUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
if (_steps == ESteps.GetPackageVersion)
|
||||
{
|
||||
if (_getRemotePackageVersionOp == null)
|
||||
{
|
||||
string packageName = _fileSystem.PackageName;
|
||||
string fileName = YooAssetSettingsData.GetPackageVersionFileName(packageName);
|
||||
string mainURL = _fileSystem.RemoteServices.GetRemoteMainURL(fileName);
|
||||
string fallbackURL = _fileSystem.RemoteServices.GetRemoteFallbackURL(fileName);
|
||||
_getRemotePackageVersionOp = new DefaultGetRemotePackageVersionOperation(packageName, mainURL, fallbackURL, _appendTimeTicks, _timeout);
|
||||
OperationSystem.StartOperation(packageName, _getRemotePackageVersionOp);
|
||||
}
|
||||
|
||||
Progress = _getRemotePackageVersionOp.Progress;
|
||||
if (_getRemotePackageVersionOp.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_getRemotePackageVersionOp.Status == EOperationStatus.Succeed)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
PackageVersion = _getRemotePackageVersionOp.PackageVersion;
|
||||
Status = EOperationStatus.Succeed;
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Failed;
|
||||
Error = _getRemotePackageVersionOp.Error;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 856b1334d67ed4d41b31a583f713c449
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3414bfb159816a74f917270b7d48c25f
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 应用程序水印
|
||||
/// </summary>
|
||||
internal class ApplicationFootPrint
|
||||
{
|
||||
private readonly DefaultCacheFileSystem _fileSystem;
|
||||
private string _footPrint;
|
||||
|
||||
|
||||
public ApplicationFootPrint(DefaultCacheFileSystem fileSystem)
|
||||
{
|
||||
_fileSystem = fileSystem;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取应用程序水印
|
||||
/// </summary>
|
||||
public void Load(string packageName)
|
||||
{
|
||||
string footPrintFilePath = _fileSystem.GetSandboxAppFootPrintFilePath();
|
||||
if (File.Exists(footPrintFilePath))
|
||||
{
|
||||
_footPrint = FileUtility.ReadAllText(footPrintFilePath);
|
||||
}
|
||||
else
|
||||
{
|
||||
Coverage(packageName);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检测水印是否发生变化
|
||||
/// </summary>
|
||||
public bool IsDirty()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
return _footPrint != Application.version;
|
||||
#else
|
||||
return _footPrint != Application.buildGUID;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 覆盖掉水印
|
||||
/// </summary>
|
||||
public void Coverage(string packageName)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
_footPrint = Application.version;
|
||||
#else
|
||||
_footPrint = Application.buildGUID;
|
||||
#endif
|
||||
string footPrintFilePath = _fileSystem.GetSandboxAppFootPrintFilePath();
|
||||
FileUtility.WriteAllText(footPrintFilePath, _footPrint);
|
||||
YooLogger.Log($"Save application foot print : {_footPrint}");
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c9d96ea955bc07149a08471e33915556
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+87
@@ -0,0 +1,87 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Networking;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 支持Unity2018版本的断点续传下载器
|
||||
/// </summary>
|
||||
internal class DownloadHandlerFileRange : DownloadHandlerScript
|
||||
{
|
||||
private string _fileSavePath;
|
||||
private long _fileTotalSize;
|
||||
private UnityWebRequest _webRequest;
|
||||
private FileStream _fileStream;
|
||||
|
||||
private long _localFileSize = 0;
|
||||
private long _curFileSize = 0;
|
||||
|
||||
|
||||
public DownloadHandlerFileRange(string fileSavePath, long fileTotalSize, UnityWebRequest webRequest) : base(new byte[1024 * 1024])
|
||||
{
|
||||
_fileSavePath = fileSavePath;
|
||||
_fileTotalSize = fileTotalSize;
|
||||
_webRequest = webRequest;
|
||||
|
||||
if (File.Exists(fileSavePath))
|
||||
{
|
||||
FileInfo fileInfo = new FileInfo(fileSavePath);
|
||||
_localFileSize = fileInfo.Length;
|
||||
}
|
||||
|
||||
_fileStream = new FileStream(_fileSavePath, FileMode.Append, FileAccess.Write);
|
||||
_curFileSize = _localFileSize;
|
||||
}
|
||||
protected override bool ReceiveData(byte[] data, int dataLength)
|
||||
{
|
||||
if (data == null || dataLength == 0 || _webRequest.responseCode >= 400)
|
||||
return false;
|
||||
|
||||
if (_fileStream == null)
|
||||
return false;
|
||||
|
||||
_fileStream.Write(data, 0, dataLength);
|
||||
_curFileSize += dataLength;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// UnityWebRequest.downloadHandler.data
|
||||
/// </summary>
|
||||
protected override byte[] GetData()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// UnityWebRequest.downloadHandler.text
|
||||
/// </summary>
|
||||
protected override string GetText()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// UnityWebRequest.downloadProgress
|
||||
/// </summary>
|
||||
protected override float GetProgress()
|
||||
{
|
||||
return _fileTotalSize == 0 ? 0 : ((float)_curFileSize) / _fileTotalSize;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 释放下载句柄
|
||||
/// </summary>
|
||||
public void Cleanup()
|
||||
{
|
||||
if (_fileStream != null)
|
||||
{
|
||||
_fileStream.Flush();
|
||||
_fileStream.Dispose();
|
||||
_fileStream = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 94254ab8e4496214884c11a891c131c6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
using System.IO;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
internal class DownloadPackageHashOperation : AsyncOperationBase
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
CheckExist,
|
||||
DownloadFile,
|
||||
Done,
|
||||
}
|
||||
|
||||
private readonly DefaultCacheFileSystem _fileSystem;
|
||||
private readonly string _packageVersion;
|
||||
private readonly int _timeout;
|
||||
private UnityWebFileRequestOperation _webFileRequestOp;
|
||||
private int _requestCount = 0;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
|
||||
internal DownloadPackageHashOperation(DefaultCacheFileSystem fileSystem, string packageVersion, int timeout)
|
||||
{
|
||||
_fileSystem = fileSystem;
|
||||
_packageVersion = packageVersion;
|
||||
_timeout = timeout;
|
||||
}
|
||||
internal override void InternalOnStart()
|
||||
{
|
||||
_requestCount = WebRequestCounter.GetRequestFailedCount(_fileSystem.PackageName, nameof(DownloadPackageHashOperation));
|
||||
_steps = ESteps.CheckExist;
|
||||
}
|
||||
internal override void InternalOnUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
if (_steps == ESteps.CheckExist)
|
||||
{
|
||||
string filePath = _fileSystem.GetCachePackageHashFilePath(_packageVersion);
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Succeed;
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.DownloadFile;
|
||||
}
|
||||
}
|
||||
|
||||
if (_steps == ESteps.DownloadFile)
|
||||
{
|
||||
if (_webFileRequestOp == null)
|
||||
{
|
||||
string savePath = _fileSystem.GetCachePackageHashFilePath(_packageVersion);
|
||||
string fileName = YooAssetSettingsData.GetPackageHashFileName(_fileSystem.PackageName, _packageVersion);
|
||||
string webURL = GetWebRequestURL(fileName);
|
||||
YooLogger.Log($"Beginning to download package hash file : {webURL}");
|
||||
_webFileRequestOp = new UnityWebFileRequestOperation(webURL, savePath, _timeout);
|
||||
OperationSystem.StartOperation(_fileSystem.PackageName, _webFileRequestOp);
|
||||
}
|
||||
|
||||
if (_webFileRequestOp.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_webFileRequestOp.Status == EOperationStatus.Succeed)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Succeed;
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Failed;
|
||||
Error = _webFileRequestOp.Error;
|
||||
WebRequestCounter.RecordRequestFailed(_fileSystem.PackageName, nameof(DownloadPackageHashOperation));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string GetWebRequestURL(string fileName)
|
||||
{
|
||||
// 轮流返回请求地址
|
||||
if (_requestCount % 2 == 0)
|
||||
return _fileSystem.RemoteServices.GetRemoteMainURL(fileName);
|
||||
else
|
||||
return _fileSystem.RemoteServices.GetRemoteFallbackURL(fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8604af2bf2c8a1d4684cb59d81ab9445
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
using System.IO;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
internal class DownloadPackageManifestOperation : AsyncOperationBase
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
CheckExist,
|
||||
DownloadFile,
|
||||
Done,
|
||||
}
|
||||
|
||||
private readonly DefaultCacheFileSystem _fileSystem;
|
||||
private readonly string _packageVersion;
|
||||
private readonly int _timeout;
|
||||
private UnityWebFileRequestOperation _webFileRequestOp;
|
||||
private int _requestCount = 0;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
|
||||
internal DownloadPackageManifestOperation(DefaultCacheFileSystem fileSystem, string packageVersion, int timeout)
|
||||
{
|
||||
_fileSystem = fileSystem;
|
||||
_packageVersion = packageVersion;
|
||||
_timeout = timeout;
|
||||
}
|
||||
internal override void InternalOnStart()
|
||||
{
|
||||
_requestCount = WebRequestCounter.GetRequestFailedCount(_fileSystem.PackageName, nameof(DownloadPackageManifestOperation));
|
||||
_steps = ESteps.DownloadFile;
|
||||
}
|
||||
internal override void InternalOnUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
if (_steps == ESteps.CheckExist)
|
||||
{
|
||||
string filePath = _fileSystem.GetCachePackageManifestFilePath(_packageVersion);
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Succeed;
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.DownloadFile;
|
||||
}
|
||||
}
|
||||
|
||||
if (_steps == ESteps.DownloadFile)
|
||||
{
|
||||
if (_webFileRequestOp == null)
|
||||
{
|
||||
string savePath = _fileSystem.GetCachePackageManifestFilePath(_packageVersion);
|
||||
string fileName = YooAssetSettingsData.GetManifestBinaryFileName(_fileSystem.PackageName, _packageVersion);
|
||||
string webURL = GetDownloadRequestURL(fileName);
|
||||
YooLogger.Log($"Beginning to download package manifest file : {webURL}");
|
||||
_webFileRequestOp = new UnityWebFileRequestOperation(webURL, savePath, _timeout);
|
||||
OperationSystem.StartOperation(_fileSystem.PackageName, _webFileRequestOp);
|
||||
}
|
||||
|
||||
if (_webFileRequestOp.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_webFileRequestOp.Status == EOperationStatus.Succeed)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Succeed;
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Failed;
|
||||
Error = _webFileRequestOp.Error;
|
||||
WebRequestCounter.RecordRequestFailed(_fileSystem.PackageName, nameof(DownloadPackageManifestOperation));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string GetDownloadRequestURL(string fileName)
|
||||
{
|
||||
// 轮流返回请求地址
|
||||
if (_requestCount % 2 == 0)
|
||||
return _fileSystem.RemoteServices.GetRemoteMainURL(fileName);
|
||||
else
|
||||
return _fileSystem.RemoteServices.GetRemoteFallbackURL(fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9d5983f1b32b2e14c8b4c5b539bee8fa
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
using System.IO;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
internal class LoadCachePackageHashOperation : AsyncOperationBase
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
LoadPackageHash,
|
||||
Done,
|
||||
}
|
||||
|
||||
private readonly DefaultCacheFileSystem _fileSystem;
|
||||
private readonly string _packageVersion;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
/// <summary>
|
||||
/// 包裹哈希值
|
||||
/// </summary>
|
||||
public string PackageHash { private set; get; }
|
||||
|
||||
|
||||
internal LoadCachePackageHashOperation(DefaultCacheFileSystem fileSystem, string packageVersion)
|
||||
{
|
||||
_fileSystem = fileSystem;
|
||||
_packageVersion = packageVersion;
|
||||
}
|
||||
internal override void InternalOnStart()
|
||||
{
|
||||
_steps = ESteps.LoadPackageHash;
|
||||
}
|
||||
internal override void InternalOnUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
if (_steps == ESteps.LoadPackageHash)
|
||||
{
|
||||
string filePath = _fileSystem.GetCachePackageHashFilePath(_packageVersion);
|
||||
if (File.Exists(filePath) == false)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Failed;
|
||||
Error = $"Cache package hash file not found : {filePath}";
|
||||
return;
|
||||
}
|
||||
|
||||
PackageHash = FileUtility.ReadAllText(filePath);
|
||||
if (string.IsNullOrEmpty(PackageHash))
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Failed;
|
||||
Error = $"Cache package hash file content is empty !";
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Succeed;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: db66f75d31bfeca4e897e9ee0946b1de
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+102
@@ -0,0 +1,102 @@
|
||||
using System.IO;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
internal class LoadCachePackageManifestOperation : AsyncOperationBase
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
LoadFileData,
|
||||
VerifyFileData,
|
||||
LoadManifest,
|
||||
Done,
|
||||
}
|
||||
|
||||
private readonly DefaultCacheFileSystem _fileSystem;
|
||||
private readonly string _packageVersion;
|
||||
private readonly string _packageHash;
|
||||
private DeserializeManifestOperation _deserializer;
|
||||
private byte[] _fileData;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
/// <summary>
|
||||
/// 加载的清单实例
|
||||
/// </summary>
|
||||
public PackageManifest Manifest { private set; get; }
|
||||
|
||||
|
||||
internal LoadCachePackageManifestOperation(DefaultCacheFileSystem fileSystem, string packageVersion, string packageHash)
|
||||
{
|
||||
_fileSystem = fileSystem;
|
||||
_packageVersion = packageVersion;
|
||||
_packageHash = packageHash;
|
||||
}
|
||||
internal override void InternalOnStart()
|
||||
{
|
||||
_steps = ESteps.LoadFileData;
|
||||
}
|
||||
internal override void InternalOnUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
if (_steps == ESteps.LoadFileData)
|
||||
{
|
||||
string manifestFilePath = _fileSystem.GetCachePackageManifestFilePath(_packageVersion);
|
||||
if (File.Exists(manifestFilePath))
|
||||
{
|
||||
_steps = ESteps.VerifyFileData;
|
||||
_fileData = File.ReadAllBytes(manifestFilePath);
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Failed;
|
||||
Error = $"Cache manifest file not found : {manifestFilePath}";
|
||||
}
|
||||
}
|
||||
|
||||
if (_steps == ESteps.VerifyFileData)
|
||||
{
|
||||
string fileHash = HashUtility.BytesMD5(_fileData);
|
||||
if (fileHash == _packageHash)
|
||||
{
|
||||
_steps = ESteps.LoadManifest;
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Failed;
|
||||
Error = "Failed to verify cache package manifest file!";
|
||||
}
|
||||
}
|
||||
|
||||
if (_steps == ESteps.LoadManifest)
|
||||
{
|
||||
if (_deserializer == null)
|
||||
{
|
||||
_deserializer = new DeserializeManifestOperation(_fileData);
|
||||
OperationSystem.StartOperation(_fileSystem.PackageName, _deserializer);
|
||||
}
|
||||
|
||||
Progress = _deserializer.Progress;
|
||||
if (_deserializer.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_deserializer.Status == EOperationStatus.Succeed)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Manifest = _deserializer.Manifest;
|
||||
Status = EOperationStatus.Succeed;
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Failed;
|
||||
Error = _deserializer.Error;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: acd84795f7cc3e348ab2b6cde03c8a22
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+125
@@ -0,0 +1,125 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
internal sealed class SearchCacheFilesOperation : AsyncOperationBase
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
Prepare,
|
||||
SearchFiles,
|
||||
Done,
|
||||
}
|
||||
|
||||
private readonly DefaultCacheFileSystem _fileSystem;
|
||||
private IEnumerator<DirectoryInfo> _filesEnumerator = null;
|
||||
private float _verifyStartTime;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
/// <summary>
|
||||
/// 需要验证的元素
|
||||
/// </summary>
|
||||
public readonly List<CacheFileElement> Result = new List<CacheFileElement>(5000);
|
||||
|
||||
|
||||
internal SearchCacheFilesOperation(DefaultCacheFileSystem fileSystem)
|
||||
{
|
||||
_fileSystem = fileSystem;
|
||||
}
|
||||
internal override void InternalOnStart()
|
||||
{
|
||||
_steps = ESteps.Prepare;
|
||||
_verifyStartTime = UnityEngine.Time.realtimeSinceStartup;
|
||||
}
|
||||
internal override void InternalOnUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
if (_steps == ESteps.Prepare)
|
||||
{
|
||||
DirectoryInfo rootDirectory = new DirectoryInfo(_fileSystem.GetCacheFilesRoot());
|
||||
if (rootDirectory.Exists)
|
||||
{
|
||||
var directorieInfos = rootDirectory.EnumerateDirectories();
|
||||
_filesEnumerator = directorieInfos.GetEnumerator();
|
||||
}
|
||||
_steps = ESteps.SearchFiles;
|
||||
}
|
||||
|
||||
if (_steps == ESteps.SearchFiles)
|
||||
{
|
||||
if (SearchFiles())
|
||||
return;
|
||||
|
||||
// 注意:总是返回成功
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Succeed;
|
||||
float costTime = UnityEngine.Time.realtimeSinceStartup - _verifyStartTime;
|
||||
YooLogger.Log($"Search cache files elapsed time {costTime:f1} seconds");
|
||||
}
|
||||
}
|
||||
|
||||
private bool SearchFiles()
|
||||
{
|
||||
if (_filesEnumerator == null)
|
||||
return false;
|
||||
|
||||
bool isFindItem;
|
||||
while (true)
|
||||
{
|
||||
isFindItem = _filesEnumerator.MoveNext();
|
||||
if (isFindItem == false)
|
||||
break;
|
||||
|
||||
var rootFoder = _filesEnumerator.Current;
|
||||
var childDirectories = rootFoder.GetDirectories();
|
||||
foreach (var chidDirectory in childDirectories)
|
||||
{
|
||||
string bundleGUID = chidDirectory.Name;
|
||||
if (_fileSystem.Exists(bundleGUID))
|
||||
continue;
|
||||
|
||||
// 创建验证元素类
|
||||
string fileRootPath = chidDirectory.FullName;
|
||||
string dataFilePath = $"{fileRootPath}/{ DefaultCacheFileSystemDefine.SaveBundleDataFileName}";
|
||||
string infoFilePath = $"{fileRootPath}/{ DefaultCacheFileSystemDefine.SaveBundleInfoFileName}";
|
||||
|
||||
// 存储的数据文件追加文件格式
|
||||
if (_fileSystem.AppendFileExtension)
|
||||
{
|
||||
string dataFileExtension = FindDataFileExtension(chidDirectory);
|
||||
if (string.IsNullOrEmpty(dataFileExtension) == false)
|
||||
dataFilePath += dataFileExtension;
|
||||
}
|
||||
|
||||
var element = new CacheFileElement(_fileSystem.PackageName, bundleGUID, fileRootPath, dataFilePath, infoFilePath);
|
||||
Result.Add(element);
|
||||
}
|
||||
|
||||
if (OperationSystem.IsBusy)
|
||||
break;
|
||||
}
|
||||
|
||||
return isFindItem;
|
||||
}
|
||||
private string FindDataFileExtension(DirectoryInfo directoryInfo)
|
||||
{
|
||||
string dataFileExtension = string.Empty;
|
||||
var fileInfos = directoryInfo.GetFiles();
|
||||
foreach (var fileInfo in fileInfos)
|
||||
{
|
||||
if (fileInfo.Name.StartsWith(DefaultCacheFileSystemDefine.SaveBundleDataFileName))
|
||||
{
|
||||
dataFileExtension = fileInfo.Extension;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return dataFileExtension;
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8adb017a806563548b1d4c47f7b343e2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+205
@@ -0,0 +1,205 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
internal class CacheFileElement
|
||||
{
|
||||
public string PackageName { private set; get; }
|
||||
public string BundleGUID { private set; get; }
|
||||
public string FileRootPath { private set; get; }
|
||||
public string DataFilePath { private set; get; }
|
||||
public string InfoFilePath { private set; get; }
|
||||
|
||||
public EFileVerifyResult Result;
|
||||
public string DataFileCRC;
|
||||
public long DataFileSize;
|
||||
|
||||
public CacheFileElement(string packageName, string bundleGUID, string fileRootPath, string dataFilePath, string infoFilePath)
|
||||
{
|
||||
PackageName = packageName;
|
||||
BundleGUID = bundleGUID;
|
||||
FileRootPath = fileRootPath;
|
||||
DataFilePath = dataFilePath;
|
||||
InfoFilePath = infoFilePath;
|
||||
}
|
||||
|
||||
public void DeleteFiles()
|
||||
{
|
||||
try
|
||||
{
|
||||
Directory.Delete(FileRootPath, true);
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
YooLogger.Warning($"Failed delete cache bundle folder : {e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 缓存文件验证(线程版)
|
||||
/// </summary>
|
||||
internal class VerifyCacheFilesOperation : AsyncOperationBase
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
InitVerify,
|
||||
UpdateVerify,
|
||||
Done,
|
||||
}
|
||||
|
||||
private readonly ThreadSyncContext _syncContext = new ThreadSyncContext();
|
||||
private readonly DefaultCacheFileSystem _fileSystem;
|
||||
private List<CacheFileElement> _waitingList;
|
||||
private List<CacheFileElement> _verifyingList;
|
||||
private EFileVerifyLevel _verifyLevel = EFileVerifyLevel.Middle;
|
||||
private int _verifyMaxNum;
|
||||
private int _verifyTotalCount;
|
||||
private float _verifyStartTime;
|
||||
private int _succeedCount;
|
||||
private int _failedCount;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
|
||||
internal VerifyCacheFilesOperation(DefaultCacheFileSystem fileSystem, List<CacheFileElement> elements)
|
||||
{
|
||||
_fileSystem = fileSystem;
|
||||
_waitingList = elements;
|
||||
_verifyLevel = _fileSystem.FileVerifyLevel;
|
||||
}
|
||||
internal override void InternalOnStart()
|
||||
{
|
||||
_steps = ESteps.InitVerify;
|
||||
_verifyStartTime = UnityEngine.Time.realtimeSinceStartup;
|
||||
}
|
||||
internal override void InternalOnUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
if (_steps == ESteps.InitVerify)
|
||||
{
|
||||
int fileCount = _waitingList.Count;
|
||||
|
||||
// 设置同时验证的最大数
|
||||
ThreadPool.GetMaxThreads(out int workerThreads, out int ioThreads);
|
||||
YooLogger.Log($"Work threads : {workerThreads}, IO threads : {ioThreads}");
|
||||
_verifyMaxNum = Math.Min(workerThreads, ioThreads);
|
||||
_verifyTotalCount = fileCount;
|
||||
if (_verifyMaxNum < 1)
|
||||
_verifyMaxNum = 1;
|
||||
|
||||
_verifyingList = new List<CacheFileElement>(_verifyMaxNum);
|
||||
_steps = ESteps.UpdateVerify;
|
||||
}
|
||||
|
||||
if (_steps == ESteps.UpdateVerify)
|
||||
{
|
||||
_syncContext.Update();
|
||||
|
||||
Progress = GetProgress();
|
||||
if (_waitingList.Count == 0 && _verifyingList.Count == 0)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Succeed;
|
||||
float costTime = UnityEngine.Time.realtimeSinceStartup - _verifyStartTime;
|
||||
YooLogger.Log($"Verify cache files elapsed time {costTime:f1} seconds");
|
||||
}
|
||||
|
||||
for (int i = _waitingList.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (OperationSystem.IsBusy)
|
||||
break;
|
||||
|
||||
if (_verifyingList.Count >= _verifyMaxNum)
|
||||
break;
|
||||
|
||||
var element = _waitingList[i];
|
||||
if (BeginVerifyFileWithThread(element))
|
||||
{
|
||||
_waitingList.RemoveAt(i);
|
||||
_verifyingList.Add(element);
|
||||
}
|
||||
else
|
||||
{
|
||||
YooLogger.Warning("The thread pool is failed queued.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private float GetProgress()
|
||||
{
|
||||
if (_verifyTotalCount == 0)
|
||||
return 1f;
|
||||
return (float)(_succeedCount + _failedCount) / _verifyTotalCount;
|
||||
}
|
||||
private bool BeginVerifyFileWithThread(CacheFileElement element)
|
||||
{
|
||||
return ThreadPool.QueueUserWorkItem(new WaitCallback(VerifyInThread), element);
|
||||
}
|
||||
private void VerifyInThread(object obj)
|
||||
{
|
||||
CacheFileElement element = (CacheFileElement)obj;
|
||||
element.Result = VerifyingCacheFile(element, _verifyLevel);
|
||||
_syncContext.Post(VerifyCallback, element);
|
||||
}
|
||||
private void VerifyCallback(object obj)
|
||||
{
|
||||
CacheFileElement element = (CacheFileElement)obj;
|
||||
_verifyingList.Remove(element);
|
||||
|
||||
if (element.Result == EFileVerifyResult.Succeed)
|
||||
{
|
||||
_succeedCount++;
|
||||
var fileWrapper = new DefaultCacheFileSystem.FileWrapper(element.InfoFilePath, element.DataFilePath, element.DataFileCRC, element.DataFileSize);
|
||||
_fileSystem.Record(element.BundleGUID, fileWrapper);
|
||||
}
|
||||
else
|
||||
{
|
||||
_failedCount++;
|
||||
|
||||
YooLogger.Warning($"Failed verify file {element.Result} and delete files : {element.FileRootPath}");
|
||||
element.DeleteFiles();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 验证缓存文件(子线程内操作)
|
||||
/// </summary>
|
||||
private EFileVerifyResult VerifyingCacheFile(CacheFileElement element, EFileVerifyLevel verifyLevel)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (verifyLevel == EFileVerifyLevel.Low)
|
||||
{
|
||||
if (File.Exists(element.InfoFilePath) == false)
|
||||
return EFileVerifyResult.InfoFileNotExisted;
|
||||
if (File.Exists(element.DataFilePath) == false)
|
||||
return EFileVerifyResult.DataFileNotExisted;
|
||||
return EFileVerifyResult.Succeed;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (File.Exists(element.InfoFilePath) == false)
|
||||
return EFileVerifyResult.InfoFileNotExisted;
|
||||
|
||||
// 解析信息文件获取验证数据
|
||||
_fileSystem.ReadInfoFile(element.InfoFilePath, out element.DataFileCRC, out element.DataFileSize);
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return EFileVerifyResult.Exception;
|
||||
}
|
||||
|
||||
return FileSystemHelper.FileVerify(element.DataFilePath, element.DataFileSize, element.DataFileCRC, verifyLevel);
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5e9325baa24ae234ea0208d70dd3347e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+112
@@ -0,0 +1,112 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
internal class TempFileElement
|
||||
{
|
||||
public string TempFilePath { private set; get; }
|
||||
public string TempFileCRC { private set; get; }
|
||||
public long TempFileSize { private set; get; }
|
||||
|
||||
/// <summary>
|
||||
/// 注意:原子操作对象
|
||||
/// </summary>
|
||||
public int Result = 0;
|
||||
|
||||
public TempFileElement(string filePath, string fileCRC, long fileSize)
|
||||
{
|
||||
TempFilePath = filePath;
|
||||
TempFileCRC = fileCRC;
|
||||
TempFileSize = fileSize;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 下载文件验证(线程版)
|
||||
/// </summary>
|
||||
internal class VerifyTempFileOperation : AsyncOperationBase
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
VerifyFile,
|
||||
Waiting,
|
||||
Done,
|
||||
}
|
||||
|
||||
private readonly TempFileElement _element;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
/// <summary>
|
||||
/// 验证结果
|
||||
/// </summary>
|
||||
public EFileVerifyResult VerifyResult { protected set; get; }
|
||||
|
||||
|
||||
internal VerifyTempFileOperation(TempFileElement element)
|
||||
{
|
||||
_element = element;
|
||||
}
|
||||
internal override void InternalOnStart()
|
||||
{
|
||||
_steps = ESteps.VerifyFile;
|
||||
}
|
||||
internal override void InternalOnUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
if (_steps == ESteps.VerifyFile)
|
||||
{
|
||||
if (BeginVerifyFileWithThread(_element))
|
||||
{
|
||||
_steps = ESteps.Waiting;
|
||||
}
|
||||
}
|
||||
|
||||
if (_steps == ESteps.Waiting)
|
||||
{
|
||||
int result = _element.Result;
|
||||
if (result == 0)
|
||||
return;
|
||||
|
||||
VerifyResult = (EFileVerifyResult)result;
|
||||
if (VerifyResult == EFileVerifyResult.Succeed)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Succeed;
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Failed;
|
||||
Error = $"Failed verify file : {_element.TempFilePath} ! ErrorCode : {VerifyResult}";
|
||||
}
|
||||
}
|
||||
}
|
||||
public override void WaitForAsyncComplete()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
// 驱动流程
|
||||
InternalOnUpdate();
|
||||
|
||||
// 完成后退出
|
||||
if (IsDone)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private bool BeginVerifyFileWithThread(TempFileElement element)
|
||||
{
|
||||
return ThreadPool.QueueUserWorkItem(new WaitCallback(VerifyInThread), element);
|
||||
}
|
||||
private void VerifyInThread(object obj)
|
||||
{
|
||||
TempFileElement element = (TempFileElement)obj;
|
||||
int result = (int)FileSystemHelper.FileVerify(element.TempFilePath, element.TempFileSize, element.TempFileCRC, EFileVerifyLevel.High);
|
||||
element.Result = result;
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 764ac4f47afd3be4a8d583578f51126d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user