mirror of https://github.com/tuyoogame/YooAsset
Merge branch 'tuyoogame:main' into main
commit
a64d485278
|
@ -199,7 +199,7 @@ namespace YooAsset.Editor
|
||||||
{
|
{
|
||||||
if (IsRawAsset)
|
if (IsRawAsset)
|
||||||
{
|
{
|
||||||
string mainBundleName = $"{_mainBundleName}.{YooAssetSettingsData.Setting.RawFileVariant}";
|
string mainBundleName = $"{_mainBundleName}.{YooAssetSettingsData.Setting.RawBundleFileVariant}";
|
||||||
_mainBundleName = mainBundleName.ToLower();
|
_mainBundleName = mainBundleName.ToLower();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -46,7 +46,7 @@ namespace YooAsset
|
||||||
if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromRemote)
|
if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromRemote)
|
||||||
{
|
{
|
||||||
_steps = ESteps.Download;
|
_steps = ESteps.Download;
|
||||||
FileLoadPath = MainBundleInfo.Bundle.CachedFilePath;
|
FileLoadPath = MainBundleInfo.Bundle.CachedDataFilePath;
|
||||||
}
|
}
|
||||||
else if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromStreaming)
|
else if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromStreaming)
|
||||||
{
|
{
|
||||||
|
@ -55,7 +55,7 @@ namespace YooAsset
|
||||||
if (loadMethod == EBundleLoadMethod.LoadFromMemory || loadMethod == EBundleLoadMethod.LoadFromStream)
|
if (loadMethod == EBundleLoadMethod.LoadFromMemory || loadMethod == EBundleLoadMethod.LoadFromStream)
|
||||||
{
|
{
|
||||||
_steps = ESteps.Unpack;
|
_steps = ESteps.Unpack;
|
||||||
FileLoadPath = MainBundleInfo.Bundle.CachedFilePath;
|
FileLoadPath = MainBundleInfo.Bundle.CachedDataFilePath;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -70,7 +70,7 @@ namespace YooAsset
|
||||||
else if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromCache)
|
else if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromCache)
|
||||||
{
|
{
|
||||||
_steps = ESteps.LoadFile;
|
_steps = ESteps.LoadFile;
|
||||||
FileLoadPath = MainBundleInfo.Bundle.CachedFilePath;
|
FileLoadPath = MainBundleInfo.Bundle.CachedDataFilePath;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -242,14 +242,11 @@ namespace YooAsset
|
||||||
// 在AssetBundle文件加载失败的情况下,我们需要重新验证文件的完整性!
|
// 在AssetBundle文件加载失败的情况下,我们需要重新验证文件的完整性!
|
||||||
if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromCache)
|
if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromCache)
|
||||||
{
|
{
|
||||||
string cacheLoadPath = MainBundleInfo.Bundle.CachedFilePath;
|
var result = CacheSystem.VerifyingRecordFile(MainBundleInfo.Bundle.PackageName, MainBundleInfo.Bundle.CacheGUID);
|
||||||
if (CacheSystem.VerifyBundle(MainBundleInfo.Bundle, EVerifyLevel.High) != EVerifyResult.Succeed)
|
if (result != EVerifyResult.Succeed)
|
||||||
{
|
{
|
||||||
if (File.Exists(cacheLoadPath))
|
YooLogger.Error($"Found possibly corrupt file ! {MainBundleInfo.Bundle.CacheGUID}");
|
||||||
{
|
CacheSystem.DiscardFile(MainBundleInfo.Bundle.PackageName, MainBundleInfo.Bundle.CacheGUID);
|
||||||
YooLogger.Error($"Delete the invalid cache file : {cacheLoadPath}");
|
|
||||||
File.Delete(cacheLoadPath);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,7 @@ namespace YooAsset
|
||||||
if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromRemote)
|
if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromRemote)
|
||||||
{
|
{
|
||||||
_steps = ESteps.Download;
|
_steps = ESteps.Download;
|
||||||
FileLoadPath = MainBundleInfo.Bundle.CachedFilePath;
|
FileLoadPath = MainBundleInfo.Bundle.CachedDataFilePath;
|
||||||
}
|
}
|
||||||
else if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromStreaming)
|
else if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromStreaming)
|
||||||
{
|
{
|
||||||
|
@ -57,7 +57,7 @@ namespace YooAsset
|
||||||
else if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromCache)
|
else if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromCache)
|
||||||
{
|
{
|
||||||
_steps = ESteps.LoadCacheFile;
|
_steps = ESteps.LoadCacheFile;
|
||||||
FileLoadPath = MainBundleInfo.Bundle.CachedFilePath;
|
FileLoadPath = MainBundleInfo.Bundle.CachedDataFilePath;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -147,14 +147,11 @@ namespace YooAsset
|
||||||
// 在AssetBundle文件加载失败的情况下,我们需要重新验证文件的完整性!
|
// 在AssetBundle文件加载失败的情况下,我们需要重新验证文件的完整性!
|
||||||
if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromCache)
|
if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromCache)
|
||||||
{
|
{
|
||||||
string cacheLoadPath = MainBundleInfo.Bundle.CachedFilePath;
|
var result = CacheSystem.VerifyingRecordFile(MainBundleInfo.Bundle.PackageName, MainBundleInfo.Bundle.CacheGUID);
|
||||||
if (CacheSystem.VerifyBundle(MainBundleInfo.Bundle, EVerifyLevel.High) != EVerifyResult.Succeed)
|
if (result != EVerifyResult.Succeed)
|
||||||
{
|
{
|
||||||
if (File.Exists(cacheLoadPath))
|
YooLogger.Error($"Found possibly corrupt file ! {MainBundleInfo.Bundle.CacheGUID}");
|
||||||
{
|
CacheSystem.DiscardFile(MainBundleInfo.Bundle.PackageName, MainBundleInfo.Bundle.CacheGUID);
|
||||||
YooLogger.Error($"Delete the invalid cache file : {cacheLoadPath}");
|
|
||||||
File.Delete(cacheLoadPath);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,13 +38,13 @@ namespace YooAsset
|
||||||
if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromRemote)
|
if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromRemote)
|
||||||
{
|
{
|
||||||
_steps = ESteps.Download;
|
_steps = ESteps.Download;
|
||||||
FileLoadPath = MainBundleInfo.Bundle.CachedFilePath;
|
FileLoadPath = MainBundleInfo.Bundle.CachedDataFilePath;
|
||||||
}
|
}
|
||||||
else if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromStreaming)
|
else if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromStreaming)
|
||||||
{
|
{
|
||||||
#if UNITY_ANDROID || UNITY_WEBGL
|
#if UNITY_ANDROID || UNITY_WEBGL
|
||||||
_steps = ESteps.Unpack;
|
_steps = ESteps.Unpack;
|
||||||
FileLoadPath = MainBundleInfo.Bundle.CachedFilePath;
|
FileLoadPath = MainBundleInfo.Bundle.CachedDataFilePath;
|
||||||
#else
|
#else
|
||||||
_steps = ESteps.CheckFile;
|
_steps = ESteps.CheckFile;
|
||||||
FileLoadPath = MainBundleInfo.Bundle.StreamingFilePath;
|
FileLoadPath = MainBundleInfo.Bundle.StreamingFilePath;
|
||||||
|
@ -53,7 +53,7 @@ namespace YooAsset
|
||||||
else if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromCache)
|
else if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromCache)
|
||||||
{
|
{
|
||||||
_steps = ESteps.CheckFile;
|
_steps = ESteps.CheckFile;
|
||||||
FileLoadPath = MainBundleInfo.Bundle.CachedFilePath;
|
FileLoadPath = MainBundleInfo.Bundle.CachedDataFilePath;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -229,15 +229,6 @@ namespace YooAsset
|
||||||
return _playModeServices.PreDownloadPackageAsync(packageVersion, timeout);
|
return _playModeServices.PreDownloadPackageAsync(packageVersion, timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 检查包裹内容的完整性
|
|
||||||
/// </summary>
|
|
||||||
public CheckPackageContentsOperation CheckPackageContentsAsync(string packageVersion)
|
|
||||||
{
|
|
||||||
DebugCheckInitialize();
|
|
||||||
return _playModeServices.CheckPackageContentsOperation(packageVersion);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 清理包裹未使用的缓存文件
|
/// 清理包裹未使用的缓存文件
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -731,12 +722,12 @@ namespace YooAsset
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 是否包含资源文件
|
/// 是否包含资源文件
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal bool IsIncludeBundleFile(string fileName)
|
internal bool IsIncludeBundleFile(string cacheGUID)
|
||||||
{
|
{
|
||||||
// NOTE : 编辑器模拟模式下始终返回TRUE
|
// NOTE : 编辑器模拟模式下始终返回TRUE
|
||||||
if (_playMode == EPlayMode.EditorSimulateMode)
|
if (_playMode == EPlayMode.EditorSimulateMode)
|
||||||
return true;
|
return true;
|
||||||
return _playModeServices.ActiveManifest.IsIncludeBundleFile(fileName);
|
return _playModeServices.ActiveManifest.IsIncludeBundleFile(cacheGUID);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace YooAsset
|
||||||
|
{
|
||||||
|
[Serializable]
|
||||||
|
internal class CacheFileInfo
|
||||||
|
{
|
||||||
|
public string FileCRC;
|
||||||
|
public long FileSize;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: a6296859f09655c4191594304ddf378f
|
guid: e4a97c06e069c1146a881fcb359f9b4b
|
||||||
MonoImporter:
|
MonoImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
|
@ -2,19 +2,19 @@
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
namespace YooAsset
|
namespace YooAsset
|
||||||
{
|
{
|
||||||
internal static class CacheSystem
|
internal static class CacheSystem
|
||||||
{
|
{
|
||||||
private readonly static Dictionary<string, PatchBundle> _cachedDic = new Dictionary<string, PatchBundle>(1000);
|
private readonly static Dictionary<string, PackageCache> _cachedDic = new Dictionary<string, PackageCache>(1000);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 初始化时的验证级别
|
/// 初始化时的验证级别
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static EVerifyLevel InitVerifyLevel { set; get; } = EVerifyLevel.Low;
|
public static EVerifyLevel InitVerifyLevel { set; get; } = EVerifyLevel.Low;
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 清空所有数据
|
/// 清空所有数据
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -25,103 +25,119 @@ namespace YooAsset
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查询是否为验证文件
|
/// 查询是否为验证文件
|
||||||
/// 注意:被收录的文件完整性是绝对有效的
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static bool IsCached(PatchBundle patchBundle)
|
public static bool IsCached(string packageName, string cacheGUID)
|
||||||
{
|
{
|
||||||
string cacheKey = patchBundle.CacheKey;
|
var cache = GetOrCreateCache(packageName);
|
||||||
if (_cachedDic.ContainsKey(cacheKey))
|
return cache.IsCached(cacheGUID);
|
||||||
{
|
|
||||||
string filePath = patchBundle.CachedFilePath;
|
|
||||||
if (File.Exists(filePath))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
/// <summary>
|
||||||
|
/// 录入验证的文件
|
||||||
|
/// </summary>
|
||||||
|
public static void RecordFile(string packageName, string cacheGUID, PackageCache.RecordWrapper wrapper)
|
||||||
{
|
{
|
||||||
_cachedDic.Remove(cacheKey);
|
var cache = GetOrCreateCache(packageName);
|
||||||
YooLogger.Error($"Cache file is missing : {filePath}");
|
cache.Record(cacheGUID, wrapper);
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else
|
/// <summary>
|
||||||
|
/// 丢弃验证的文件(同时删除文件)
|
||||||
|
/// </summary>
|
||||||
|
public static void DiscardFile(string packageName, string cacheGUID)
|
||||||
{
|
{
|
||||||
return false;
|
var cache = GetOrCreateCache(packageName);
|
||||||
|
var wrapper = cache.TryGetWrapper(cacheGUID);
|
||||||
|
if (wrapper == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
cache.Discard(cacheGUID);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string dataFilePath = wrapper.DataFilePath;
|
||||||
|
FileInfo fileInfo = new FileInfo(dataFilePath);
|
||||||
|
if (fileInfo.Exists)
|
||||||
|
fileInfo.Directory.Delete(true);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
YooLogger.Error($"Failed to delete cache file ! {e.Message}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 缓存补丁包文件
|
/// 验证缓存文件(子线程内操作)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static void CacheBundle(PatchBundle patchBundle)
|
public static EVerifyResult VerifyingCacheFile(VerifyElement element, EVerifyLevel verifyLevel)
|
||||||
{
|
|
||||||
string cacheKey = patchBundle.CacheKey;
|
|
||||||
if (_cachedDic.ContainsKey(cacheKey) == false)
|
|
||||||
{
|
|
||||||
string filePath = patchBundle.CachedFilePath;
|
|
||||||
YooLogger.Log($"Cache verify file : {filePath}");
|
|
||||||
_cachedDic.Add(cacheKey, patchBundle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 验证补丁包文件
|
|
||||||
/// </summary>
|
|
||||||
public static EVerifyResult VerifyBundle(PatchBundle patchBundle, EVerifyLevel verifyLevel)
|
|
||||||
{
|
|
||||||
return VerifyContentInternal(patchBundle.CachedFilePath, patchBundle.FileSize, patchBundle.FileCRC, verifyLevel);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 验证并缓存本地文件
|
|
||||||
/// </summary>
|
|
||||||
public static EVerifyResult VerifyAndCacheLocalBundleFile(PatchBundle patchBundle, EVerifyLevel verifyLevel)
|
|
||||||
{
|
|
||||||
var verifyResult = VerifyContentInternal(patchBundle.CachedFilePath, patchBundle.FileSize, patchBundle.FileCRC, verifyLevel);
|
|
||||||
if (verifyResult == EVerifyResult.Succeed)
|
|
||||||
CacheBundle(patchBundle);
|
|
||||||
return verifyResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 验证并缓存下载文件
|
|
||||||
/// </summary>
|
|
||||||
public static EVerifyResult VerifyAndCacheDownloadBundleFile(string tempFilePath, PatchBundle patchBundle, EVerifyLevel verifyLevel)
|
|
||||||
{
|
|
||||||
var verifyResult = VerifyContentInternal(tempFilePath, patchBundle.FileSize, patchBundle.FileCRC, verifyLevel);
|
|
||||||
if (verifyResult == EVerifyResult.Succeed)
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
string destFilePath = patchBundle.CachedFilePath;
|
string infoFilePath = element.InfoFilePath;
|
||||||
if (File.Exists(destFilePath))
|
if (File.Exists(infoFilePath) == false)
|
||||||
File.Delete(destFilePath);
|
return EVerifyResult.InfoFileNotExisted;
|
||||||
|
|
||||||
FileInfo fileInfo = new FileInfo(tempFilePath);
|
// 解析信息文件获取验证数据
|
||||||
fileInfo.MoveTo(destFilePath);
|
string jsonContent = FileUtility.ReadAllText(infoFilePath);
|
||||||
|
CacheFileInfo fileInfo = UnityEngine.JsonUtility.FromJson<CacheFileInfo>(jsonContent);
|
||||||
|
element.DataFileCRC = fileInfo.FileCRC;
|
||||||
|
element.DataFileSize = fileInfo.FileSize;
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception)
|
||||||
{
|
{
|
||||||
verifyResult = EVerifyResult.FileMoveFailed;
|
return EVerifyResult.Exception;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (verifyResult == EVerifyResult.Succeed)
|
return VerifyingInternal(element.DataFilePath, element.DataFileSize, element.DataFileCRC, verifyLevel);
|
||||||
{
|
|
||||||
CacheBundle(patchBundle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return verifyResult;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 验证文件完整性
|
/// 验证下载文件
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private static EVerifyResult VerifyContentInternal(string filePath, long fileSize, string fileCRC, EVerifyLevel verifyLevel)
|
public static EVerifyResult VerifyingTempFile(PatchBundle patchBundle, EVerifyLevel verifyLevel)
|
||||||
|
{
|
||||||
|
return VerifyingInternal(patchBundle.TempDataFilePath, patchBundle.FileSize, patchBundle.FileCRC, verifyLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 验证记录文件
|
||||||
|
/// </summary>
|
||||||
|
public static EVerifyResult VerifyingRecordFile(string packageName, string cacheGUID)
|
||||||
|
{
|
||||||
|
var cache = GetOrCreateCache(packageName);
|
||||||
|
var wrapper = cache.TryGetWrapper(cacheGUID);
|
||||||
|
if (wrapper == null)
|
||||||
|
return EVerifyResult.CacheNotFound;
|
||||||
|
|
||||||
|
EVerifyResult result = VerifyingInternal(wrapper.DataFilePath, wrapper.DataFileSize, wrapper.DataFileCRC, EVerifyLevel.High);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取未被使用的缓存文件
|
||||||
|
/// </summary>
|
||||||
|
public static List<string> GetUnusedCacheGUIDs(AssetsPackage package)
|
||||||
|
{
|
||||||
|
var cache = GetOrCreateCache(package.PackageName);
|
||||||
|
var keys = cache.GetAllKeys();
|
||||||
|
List<string> result = new List<string>(keys.Count);
|
||||||
|
foreach (var cacheGUID in keys)
|
||||||
|
{
|
||||||
|
if (package.IsIncludeBundleFile(cacheGUID) == false)
|
||||||
|
{
|
||||||
|
result.Add(cacheGUID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static EVerifyResult VerifyingInternal(string filePath, long fileSize, string fileCRC, EVerifyLevel verifyLevel)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (File.Exists(filePath) == false)
|
if (File.Exists(filePath) == false)
|
||||||
return EVerifyResult.FileNotExisted;
|
return EVerifyResult.DataFileNotExisted;
|
||||||
|
|
||||||
// 先验证文件大小
|
// 先验证文件大小
|
||||||
long size = FileUtility.GetFileSize(filePath);
|
long size = FileUtility.GetFileSize(filePath);
|
||||||
|
@ -149,5 +165,14 @@ namespace YooAsset
|
||||||
return EVerifyResult.Exception;
|
return EVerifyResult.Exception;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private static PackageCache GetOrCreateCache(string packageName)
|
||||||
|
{
|
||||||
|
if (_cachedDic.TryGetValue(packageName, out PackageCache cache) == false)
|
||||||
|
{
|
||||||
|
cache = new PackageCache(packageName);
|
||||||
|
_cachedDic.Add(packageName, cache);
|
||||||
|
}
|
||||||
|
return cache;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -7,14 +7,19 @@ namespace YooAsset
|
||||||
internal enum EVerifyResult
|
internal enum EVerifyResult
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 文件不存在
|
/// 未找到缓存信息
|
||||||
/// </summary>
|
/// </summary>
|
||||||
FileNotExisted = -5,
|
CacheNotFound = -6,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 文件移动失败(重命名失败)
|
/// 信息文件不存在
|
||||||
/// </summary>
|
/// </summary>
|
||||||
FileMoveFailed = -4,
|
InfoFileNotExisted = -5,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 数据文件不存在
|
||||||
|
/// </summary>
|
||||||
|
DataFileNotExisted = -4,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 文件内容不足(小于正常大小)
|
/// 文件内容不足(小于正常大小)
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: d29a9623b2b346e439b7a7e37fafa781
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
|
@ -0,0 +1,71 @@
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace YooAsset
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 清理本地包裹未使用的缓存文件
|
||||||
|
/// </summary>
|
||||||
|
public sealed class ClearUnusedCacheFilesOperation : AsyncOperationBase
|
||||||
|
{
|
||||||
|
private enum ESteps
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
GetUnusedCacheFiles,
|
||||||
|
ClearUnusedCacheFiles,
|
||||||
|
Done,
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly AssetsPackage _package;
|
||||||
|
private List<string> _unusedCacheGUIDs;
|
||||||
|
private int _unusedFileTotalCount = 0;
|
||||||
|
private ESteps _steps = ESteps.None;
|
||||||
|
|
||||||
|
internal ClearUnusedCacheFilesOperation(AssetsPackage package)
|
||||||
|
{
|
||||||
|
_package = package;
|
||||||
|
}
|
||||||
|
internal override void Start()
|
||||||
|
{
|
||||||
|
_steps = ESteps.GetUnusedCacheFiles;
|
||||||
|
}
|
||||||
|
internal override void Update()
|
||||||
|
{
|
||||||
|
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_steps == ESteps.GetUnusedCacheFiles)
|
||||||
|
{
|
||||||
|
_unusedCacheGUIDs = CacheSystem.GetUnusedCacheGUIDs(_package);
|
||||||
|
_unusedFileTotalCount = _unusedCacheGUIDs.Count;
|
||||||
|
YooLogger.Log($"Found unused cache file count : {_unusedFileTotalCount}");
|
||||||
|
_steps = ESteps.ClearUnusedCacheFiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_steps == ESteps.ClearUnusedCacheFiles)
|
||||||
|
{
|
||||||
|
for (int i = _unusedCacheGUIDs.Count - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
string cacheGUID = _unusedCacheGUIDs[i];
|
||||||
|
CacheSystem.DiscardFile(_package.PackageName, cacheGUID);
|
||||||
|
_unusedCacheGUIDs.RemoveAt(i);
|
||||||
|
|
||||||
|
if (OperationSystem.IsBusy)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_unusedFileTotalCount == 0)
|
||||||
|
Progress = 1.0f;
|
||||||
|
else
|
||||||
|
Progress = 1.0f - (_unusedCacheGUIDs.Count / _unusedFileTotalCount);
|
||||||
|
|
||||||
|
if (_unusedCacheGUIDs.Count == 0)
|
||||||
|
{
|
||||||
|
_steps = ESteps.Done;
|
||||||
|
Status = EOperationStatus.Succeed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,80 @@
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace YooAsset
|
||||||
|
{
|
||||||
|
internal class PackageCachingOperation : AsyncOperationBase
|
||||||
|
{
|
||||||
|
private enum ESteps
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
GetCacheFiles,
|
||||||
|
VerifyCacheFiles,
|
||||||
|
Done,
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly string _packageName;
|
||||||
|
private PackageVerifyOperation _packageVerifyOp;
|
||||||
|
private ESteps _steps = ESteps.None;
|
||||||
|
|
||||||
|
public PackageCachingOperation(string packageName)
|
||||||
|
{
|
||||||
|
_packageName = packageName;
|
||||||
|
}
|
||||||
|
internal override void Start()
|
||||||
|
{
|
||||||
|
_steps = ESteps.GetCacheFiles;
|
||||||
|
}
|
||||||
|
internal override void Update()
|
||||||
|
{
|
||||||
|
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_steps == ESteps.GetCacheFiles)
|
||||||
|
{
|
||||||
|
var elements = GetVerifyElements();
|
||||||
|
_packageVerifyOp = PackageVerifyOperation.CreateOperation(elements);
|
||||||
|
OperationSystem.StartOperation(_packageVerifyOp);
|
||||||
|
_steps = ESteps.VerifyCacheFiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_steps == ESteps.VerifyCacheFiles)
|
||||||
|
{
|
||||||
|
Progress = _packageVerifyOp.Progress;
|
||||||
|
if (_packageVerifyOp.IsDone == false)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// 注意:总是返回成功
|
||||||
|
_steps = ESteps.Done;
|
||||||
|
Status = EOperationStatus.Succeed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<VerifyElement> GetVerifyElements()
|
||||||
|
{
|
||||||
|
string cacheFolderPath = PersistentHelper.GetCacheFolderPath(_packageName);
|
||||||
|
if (Directory.Exists(cacheFolderPath) == false)
|
||||||
|
return new List<VerifyElement>();
|
||||||
|
|
||||||
|
DirectoryInfo rootDirectory = new DirectoryInfo(cacheFolderPath);
|
||||||
|
DirectoryInfo[] fileFolders = rootDirectory.GetDirectories();
|
||||||
|
List<VerifyElement> result = new List<VerifyElement>(fileFolders.Length);
|
||||||
|
foreach (var fileFoder in fileFolders)
|
||||||
|
{
|
||||||
|
string cacheGUID = fileFoder.Name;
|
||||||
|
if (CacheSystem.IsCached(_packageName, cacheGUID))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
string fileRootPath = fileFoder.FullName;
|
||||||
|
string dataFilePath = $"{fileRootPath}/{ YooAssetSettings.CacheBundleDataFileName}";
|
||||||
|
string infoFilePath = $"{fileRootPath}/{ YooAssetSettings.CacheBundleInfoFileName}";
|
||||||
|
VerifyElement element = new VerifyElement(_packageName, cacheGUID, fileRootPath, dataFilePath, infoFilePath);
|
||||||
|
result.Add(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 3d400b2548d79ca42bec7370f5d66b78
|
guid: 4ff95e7516dbfa148b4fe16eaab783fb
|
||||||
MonoImporter:
|
MonoImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
|
@ -0,0 +1,258 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
|
namespace YooAsset
|
||||||
|
{
|
||||||
|
internal abstract class PackageVerifyOperation : AsyncOperationBase
|
||||||
|
{
|
||||||
|
public static PackageVerifyOperation CreateOperation(List<VerifyElement> elements)
|
||||||
|
{
|
||||||
|
#if UNITY_WEBGL
|
||||||
|
var operation = new PackageVerifyWithoutThreadOperation(elements);
|
||||||
|
#else
|
||||||
|
var operation = new PackageVerifyWithThreadOperation(elements);
|
||||||
|
#endif
|
||||||
|
return operation;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 本地缓存文件验证(线程版)
|
||||||
|
/// </summary>
|
||||||
|
internal class PackageVerifyWithThreadOperation : PackageVerifyOperation
|
||||||
|
{
|
||||||
|
private enum ESteps
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
InitVerify,
|
||||||
|
UpdateVerify,
|
||||||
|
Done,
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly ThreadSyncContext _syncContext = new ThreadSyncContext();
|
||||||
|
private List<VerifyElement> _waitingList;
|
||||||
|
private List<VerifyElement> _verifyingList;
|
||||||
|
private int _verifyMaxNum;
|
||||||
|
private int _verifyTotalCount;
|
||||||
|
private float _verifyStartTime;
|
||||||
|
private int _succeedCount;
|
||||||
|
private int _failedCount;
|
||||||
|
private ESteps _steps = ESteps.None;
|
||||||
|
|
||||||
|
public PackageVerifyWithThreadOperation(List<VerifyElement> elements)
|
||||||
|
{
|
||||||
|
_waitingList = elements;
|
||||||
|
}
|
||||||
|
internal override void Start()
|
||||||
|
{
|
||||||
|
_steps = ESteps.InitVerify;
|
||||||
|
_verifyStartTime = UnityEngine.Time.realtimeSinceStartup;
|
||||||
|
}
|
||||||
|
internal override void Update()
|
||||||
|
{
|
||||||
|
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<VerifyElement>(_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($"Package verify 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(VerifyElement element)
|
||||||
|
{
|
||||||
|
return ThreadPool.QueueUserWorkItem(new WaitCallback(VerifyInThread), element);
|
||||||
|
}
|
||||||
|
private void VerifyInThread(object obj)
|
||||||
|
{
|
||||||
|
VerifyElement element = (VerifyElement)obj;
|
||||||
|
element.Result = CacheSystem.VerifyingCacheFile(element, CacheSystem.InitVerifyLevel);
|
||||||
|
_syncContext.Post(VerifyCallback, element);
|
||||||
|
}
|
||||||
|
private void VerifyCallback(object obj)
|
||||||
|
{
|
||||||
|
VerifyElement element = (VerifyElement)obj;
|
||||||
|
_verifyingList.Remove(element);
|
||||||
|
|
||||||
|
if (element.Result == EVerifyResult.Succeed)
|
||||||
|
{
|
||||||
|
_succeedCount++;
|
||||||
|
var wrapper = new PackageCache.RecordWrapper(element.InfoFilePath, element.DataFilePath, element.DataFileCRC, element.DataFileSize);
|
||||||
|
CacheSystem.RecordFile(element.PackageName, element.CacheGUID, wrapper);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_failedCount++;
|
||||||
|
|
||||||
|
// 删除验证失败的缓存文件
|
||||||
|
if (Directory.Exists(element.FileRootPath))
|
||||||
|
{
|
||||||
|
YooLogger.Warning($"Failed verify file and delete files : {element.FileRootPath}");
|
||||||
|
Directory.Delete(element.FileRootPath, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 本地缓存文件验证(非线程版)
|
||||||
|
/// </summary>
|
||||||
|
internal class PackageVerifyWithoutThreadOperation : PackageVerifyOperation
|
||||||
|
{
|
||||||
|
private enum ESteps
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
InitVerify,
|
||||||
|
UpdateVerify,
|
||||||
|
Done,
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<VerifyElement> _waitingList;
|
||||||
|
private List<VerifyElement> _verifyingList;
|
||||||
|
private int _verifyMaxNum;
|
||||||
|
private int _verifyTotalCount;
|
||||||
|
private float _verifyStartTime;
|
||||||
|
private int _succeedCount;
|
||||||
|
private int _failedCount;
|
||||||
|
private ESteps _steps = ESteps.None;
|
||||||
|
|
||||||
|
public PackageVerifyWithoutThreadOperation(List<VerifyElement> elements)
|
||||||
|
{
|
||||||
|
_waitingList = elements;
|
||||||
|
}
|
||||||
|
internal override void Start()
|
||||||
|
{
|
||||||
|
_steps = ESteps.InitVerify;
|
||||||
|
_verifyStartTime = UnityEngine.Time.realtimeSinceStartup;
|
||||||
|
}
|
||||||
|
internal override void Update()
|
||||||
|
{
|
||||||
|
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_steps == ESteps.InitVerify)
|
||||||
|
{
|
||||||
|
int fileCount = _waitingList.Count;
|
||||||
|
|
||||||
|
// 设置同时验证的最大数
|
||||||
|
_verifyMaxNum = fileCount;
|
||||||
|
_verifyTotalCount = fileCount;
|
||||||
|
|
||||||
|
_verifyingList = new List<VerifyElement>(_verifyMaxNum);
|
||||||
|
_steps = ESteps.UpdateVerify;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_steps == ESteps.UpdateVerify)
|
||||||
|
{
|
||||||
|
Progress = GetProgress();
|
||||||
|
if (_waitingList.Count == 0 && _verifyingList.Count == 0)
|
||||||
|
{
|
||||||
|
_steps = ESteps.Done;
|
||||||
|
Status = EOperationStatus.Succeed;
|
||||||
|
float costTime = UnityEngine.Time.realtimeSinceStartup - _verifyStartTime;
|
||||||
|
YooLogger.Log($"Package verify 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];
|
||||||
|
BeginVerifyFileWithoutThread(element);
|
||||||
|
_waitingList.RemoveAt(i);
|
||||||
|
_verifyingList.Add(element);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 主线程内验证,可以清空列表
|
||||||
|
_verifyingList.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private float GetProgress()
|
||||||
|
{
|
||||||
|
if (_verifyTotalCount == 0)
|
||||||
|
return 1f;
|
||||||
|
return (float)(_succeedCount + _failedCount) / _verifyTotalCount;
|
||||||
|
}
|
||||||
|
private void BeginVerifyFileWithoutThread(VerifyElement element)
|
||||||
|
{
|
||||||
|
element.Result = CacheSystem.VerifyingCacheFile(element, CacheSystem.InitVerifyLevel);
|
||||||
|
if (element.Result == EVerifyResult.Succeed)
|
||||||
|
{
|
||||||
|
_succeedCount++;
|
||||||
|
var wrapper = new PackageCache.RecordWrapper(element.InfoFilePath, element.DataFilePath, element.DataFileCRC, element.DataFileSize);
|
||||||
|
CacheSystem.RecordFile(element.PackageName, element.CacheGUID, wrapper);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_failedCount++;
|
||||||
|
|
||||||
|
// 删除验证失败的缓存文件
|
||||||
|
if (Directory.Exists(element.FileRootPath))
|
||||||
|
{
|
||||||
|
YooLogger.Warning($"Failed verify file and delete files : {element.FileRootPath}");
|
||||||
|
Directory.Delete(element.FileRootPath, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,103 @@
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace YooAsset
|
||||||
|
{
|
||||||
|
internal class PackageCache
|
||||||
|
{
|
||||||
|
internal class RecordWrapper
|
||||||
|
{
|
||||||
|
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 RecordWrapper(string infoFilePath, string dataFilePath, string dataFileCRC, long dataFileSize)
|
||||||
|
{
|
||||||
|
InfoFilePath = infoFilePath;
|
||||||
|
DataFilePath = dataFilePath;
|
||||||
|
DataFileCRC = dataFileCRC;
|
||||||
|
DataFileSize = dataFileSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly Dictionary<string, RecordWrapper> _wrappers = new Dictionary<string, RecordWrapper>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 包裹名称
|
||||||
|
/// </summary>
|
||||||
|
public string PackageName { private set; get; }
|
||||||
|
|
||||||
|
|
||||||
|
public PackageCache(string packageName)
|
||||||
|
{
|
||||||
|
PackageName = packageName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 清空所有数据
|
||||||
|
/// </summary>
|
||||||
|
public void ClearAll()
|
||||||
|
{
|
||||||
|
_wrappers.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查询缓存记录
|
||||||
|
/// </summary>
|
||||||
|
public bool IsCached(string cacheGUID)
|
||||||
|
{
|
||||||
|
return _wrappers.ContainsKey(cacheGUID);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 记录验证结果
|
||||||
|
/// </summary>
|
||||||
|
public void Record(string cacheGUID, RecordWrapper wrapper)
|
||||||
|
{
|
||||||
|
if (_wrappers.ContainsKey(cacheGUID) == false)
|
||||||
|
{
|
||||||
|
_wrappers.Add(cacheGUID, wrapper);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new Exception("Should never get here !");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 丢弃验证结果
|
||||||
|
/// </summary>
|
||||||
|
public void Discard(string cacheGUID)
|
||||||
|
{
|
||||||
|
if (_wrappers.ContainsKey(cacheGUID))
|
||||||
|
{
|
||||||
|
_wrappers.Remove(cacheGUID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取记录对象
|
||||||
|
/// </summary>
|
||||||
|
public RecordWrapper TryGetWrapper(string cacheGUID)
|
||||||
|
{
|
||||||
|
if (_wrappers.TryGetValue(cacheGUID, out RecordWrapper value))
|
||||||
|
return value;
|
||||||
|
else
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal List<string> GetAllKeys()
|
||||||
|
{
|
||||||
|
List<string> keys = new List<string>(_wrappers.Keys.Count);
|
||||||
|
var keyCollection = _wrappers.Keys;
|
||||||
|
foreach (var key in keyCollection)
|
||||||
|
{
|
||||||
|
keys.Add(key);
|
||||||
|
}
|
||||||
|
return keys;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 08f3e92fdbd5d56459d8882be1f54f60
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
|
@ -0,0 +1,25 @@
|
||||||
|
|
||||||
|
namespace YooAsset
|
||||||
|
{
|
||||||
|
internal class VerifyElement
|
||||||
|
{
|
||||||
|
public string PackageName { private set; get; }
|
||||||
|
public string CacheGUID { private set; get; }
|
||||||
|
public string FileRootPath { private set; get; }
|
||||||
|
public string DataFilePath { private set; get; }
|
||||||
|
public string InfoFilePath { private set; get; }
|
||||||
|
|
||||||
|
public EVerifyResult Result;
|
||||||
|
public string DataFileCRC;
|
||||||
|
public long DataFileSize;
|
||||||
|
|
||||||
|
public VerifyElement(string packageName, string cacheGUID, string fileRootPath, string dataFilePath, string infoFilePath)
|
||||||
|
{
|
||||||
|
PackageName = packageName;
|
||||||
|
CacheGUID = cacheGUID;
|
||||||
|
FileRootPath = fileRootPath;
|
||||||
|
DataFilePath = dataFilePath;
|
||||||
|
InfoFilePath = infoFilePath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 5a4b96484bd701f4289b2f74c38abaa8
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
|
@ -1,33 +0,0 @@
|
||||||
|
|
||||||
namespace YooAsset
|
|
||||||
{
|
|
||||||
internal class VerifyInfo
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 验证的资源文件是否为内置资源
|
|
||||||
/// </summary>
|
|
||||||
public bool IsBuildinFile { private set; get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 验证的资源包实例
|
|
||||||
/// </summary>
|
|
||||||
public PatchBundle VerifyBundle { private set; get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 验证的文件路径
|
|
||||||
/// </summary>
|
|
||||||
public string VerifyFilePath { private set; get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 验证结果
|
|
||||||
/// </summary>
|
|
||||||
public EVerifyResult Result;
|
|
||||||
|
|
||||||
public VerifyInfo(bool isBuildinFile, PatchBundle verifyBundle)
|
|
||||||
{
|
|
||||||
IsBuildinFile = isBuildinFile;
|
|
||||||
VerifyBundle = verifyBundle;
|
|
||||||
VerifyFilePath = verifyBundle.CachedFilePath;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -77,13 +77,13 @@ namespace YooAsset
|
||||||
public static DownloaderBase BeginDownload(BundleInfo bundleInfo, int failedTryAgain, int timeout = 60)
|
public static DownloaderBase BeginDownload(BundleInfo bundleInfo, int failedTryAgain, int timeout = 60)
|
||||||
{
|
{
|
||||||
// 查询存在的下载器
|
// 查询存在的下载器
|
||||||
if (_downloaderDic.TryGetValue(bundleInfo.Bundle.CachedFilePath, out var downloader))
|
if (_downloaderDic.TryGetValue(bundleInfo.Bundle.CachedDataFilePath, out var downloader))
|
||||||
{
|
{
|
||||||
return downloader;
|
return downloader;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果资源已经缓存
|
// 如果资源已经缓存
|
||||||
if (CacheSystem.IsCached(bundleInfo.Bundle))
|
if (CacheSystem.IsCached(bundleInfo.Bundle.PackageName, bundleInfo.Bundle.CacheGUID))
|
||||||
{
|
{
|
||||||
var tempDownloader = new TempDownloader(bundleInfo);
|
var tempDownloader = new TempDownloader(bundleInfo);
|
||||||
return tempDownloader;
|
return tempDownloader;
|
||||||
|
@ -92,11 +92,11 @@ namespace YooAsset
|
||||||
// 创建新的下载器
|
// 创建新的下载器
|
||||||
{
|
{
|
||||||
YooLogger.Log($"Beginning to download file : {bundleInfo.Bundle.FileName} URL : {bundleInfo.RemoteMainURL}");
|
YooLogger.Log($"Beginning to download file : {bundleInfo.Bundle.FileName} URL : {bundleInfo.RemoteMainURL}");
|
||||||
FileUtility.CreateFileDirectory(bundleInfo.Bundle.CachedFilePath);
|
FileUtility.CreateFileDirectory(bundleInfo.Bundle.CachedDataFilePath);
|
||||||
bool breakDownload = bundleInfo.Bundle.FileSize >= BreakpointResumeFileSize;
|
bool breakDownload = bundleInfo.Bundle.FileSize >= BreakpointResumeFileSize;
|
||||||
DownloaderBase newDownloader = new FileDownloader(bundleInfo, breakDownload);
|
DownloaderBase newDownloader = new FileDownloader(bundleInfo, breakDownload);
|
||||||
newDownloader.SendRequest(failedTryAgain, timeout);
|
newDownloader.SendRequest(failedTryAgain, timeout);
|
||||||
_downloaderDic.Add(bundleInfo.Bundle.CachedFilePath, newDownloader);
|
_downloaderDic.Add(bundleInfo.Bundle.CachedDataFilePath, newDownloader);
|
||||||
return newDownloader;
|
return newDownloader;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,13 +6,13 @@ namespace YooAsset
|
||||||
protected enum ESteps
|
protected enum ESteps
|
||||||
{
|
{
|
||||||
None,
|
None,
|
||||||
CheckLocalFile,
|
|
||||||
CheckTempFile,
|
CheckTempFile,
|
||||||
PrepareDownload,
|
PrepareDownload,
|
||||||
CreateResumeDownloader,
|
CreateResumeDownloader,
|
||||||
CreateGeneralDownloader,
|
CreateGeneralDownloader,
|
||||||
CheckDownload,
|
CheckDownload,
|
||||||
VerifyDownload,
|
VerifyingFile,
|
||||||
|
CachingFile,
|
||||||
TryAgain,
|
TryAgain,
|
||||||
Succeed,
|
Succeed,
|
||||||
Failed,
|
Failed,
|
||||||
|
@ -60,7 +60,7 @@ namespace YooAsset
|
||||||
{
|
{
|
||||||
_failedTryAgain = failedTryAgain;
|
_failedTryAgain = failedTryAgain;
|
||||||
_timeout = timeout;
|
_timeout = timeout;
|
||||||
_steps = ESteps.CheckLocalFile;
|
_steps = ESteps.CheckTempFile;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public abstract void Update();
|
public abstract void Update();
|
||||||
|
|
|
@ -25,7 +25,7 @@ namespace YooAsset
|
||||||
public FileDownloader(BundleInfo bundleInfo, bool breakResume) : base(bundleInfo)
|
public FileDownloader(BundleInfo bundleInfo, bool breakResume) : base(bundleInfo)
|
||||||
{
|
{
|
||||||
_breakResume = breakResume;
|
_breakResume = breakResume;
|
||||||
_tempFilePath = bundleInfo.Bundle.CachedFilePath + ".temp";
|
_tempFilePath = bundleInfo.Bundle.TempDataFilePath;
|
||||||
}
|
}
|
||||||
public override void Update()
|
public override void Update()
|
||||||
{
|
{
|
||||||
|
@ -34,29 +34,13 @@ namespace YooAsset
|
||||||
if (IsDone())
|
if (IsDone())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// 检测本地正式文件
|
|
||||||
if (_steps == ESteps.CheckLocalFile)
|
|
||||||
{
|
|
||||||
var verifyResult = CacheSystem.VerifyAndCacheLocalBundleFile(_bundleInfo.Bundle, CacheSystem.InitVerifyLevel);
|
|
||||||
if (verifyResult == EVerifyResult.Succeed)
|
|
||||||
{
|
|
||||||
_steps = ESteps.Succeed;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (File.Exists(_bundleInfo.Bundle.CachedFilePath))
|
|
||||||
File.Delete(_bundleInfo.Bundle.CachedFilePath);
|
|
||||||
_steps = ESteps.CheckTempFile;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检测本地临时文件
|
// 检测本地临时文件
|
||||||
if (_steps == ESteps.CheckTempFile)
|
if (_steps == ESteps.CheckTempFile)
|
||||||
{
|
{
|
||||||
var verifyResult = CacheSystem.VerifyAndCacheDownloadBundleFile(_tempFilePath, _bundleInfo.Bundle, EVerifyLevel.High);
|
var verifyResult = CacheSystem.VerifyingTempFile(_bundleInfo.Bundle, EVerifyLevel.High);
|
||||||
if (verifyResult == EVerifyResult.Succeed)
|
if (verifyResult == EVerifyResult.Succeed)
|
||||||
{
|
{
|
||||||
_steps = ESteps.Succeed;
|
_steps = ESteps.CachingFile;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -94,9 +78,7 @@ namespace YooAsset
|
||||||
if (_steps == ESteps.CreateGeneralDownloader)
|
if (_steps == ESteps.CreateGeneralDownloader)
|
||||||
{
|
{
|
||||||
if (File.Exists(_tempFilePath))
|
if (File.Exists(_tempFilePath))
|
||||||
{
|
|
||||||
File.Delete(_tempFilePath);
|
File.Delete(_tempFilePath);
|
||||||
}
|
|
||||||
|
|
||||||
_webRequest = new UnityWebRequest(_requestURL, UnityWebRequest.kHttpVerbGET);
|
_webRequest = new UnityWebRequest(_requestURL, UnityWebRequest.kHttpVerbGET);
|
||||||
DownloadHandlerFile handler = new DownloadHandlerFile(_tempFilePath);
|
DownloadHandlerFile handler = new DownloadHandlerFile(_tempFilePath);
|
||||||
|
@ -206,7 +188,7 @@ namespace YooAsset
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_steps = ESteps.VerifyDownload;
|
_steps = ESteps.VerifyingFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 释放下载器
|
// 释放下载器
|
||||||
|
@ -214,23 +196,55 @@ namespace YooAsset
|
||||||
}
|
}
|
||||||
|
|
||||||
// 验证下载文件
|
// 验证下载文件
|
||||||
if (_steps == ESteps.VerifyDownload)
|
if (_steps == ESteps.VerifyingFile)
|
||||||
{
|
{
|
||||||
var verifyResult = CacheSystem.VerifyAndCacheDownloadBundleFile(_tempFilePath, _bundleInfo.Bundle, EVerifyLevel.High);
|
var verifyResult = CacheSystem.VerifyingTempFile(_bundleInfo.Bundle, EVerifyLevel.High);
|
||||||
if (verifyResult == EVerifyResult.Succeed)
|
if (verifyResult == EVerifyResult.Succeed)
|
||||||
{
|
{
|
||||||
|
_steps = ESteps.CachingFile;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_lastError = $"Failed to verifying file : {_bundleInfo.Bundle.FileName}, ErrorCode : {verifyResult}";
|
||||||
|
|
||||||
|
// 注意:验证失败后删除文件
|
||||||
|
if (File.Exists(_tempFilePath))
|
||||||
|
File.Delete(_tempFilePath);
|
||||||
|
|
||||||
|
_steps = ESteps.TryAgain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 缓存下载文件
|
||||||
|
if (_steps == ESteps.CachingFile)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string destFilePath = _bundleInfo.Bundle.CachedDataFilePath;
|
||||||
|
if (File.Exists(destFilePath))
|
||||||
|
File.Delete(destFilePath);
|
||||||
|
|
||||||
|
FileInfo fileInfo = new FileInfo(_tempFilePath);
|
||||||
|
fileInfo.MoveTo(destFilePath);
|
||||||
|
|
||||||
|
// 写入信息文件记录验证数据
|
||||||
|
CacheFileInfo cacheInfo = new CacheFileInfo();
|
||||||
|
cacheInfo.FileCRC = _bundleInfo.Bundle.FileCRC;
|
||||||
|
cacheInfo.FileSize = _bundleInfo.Bundle.FileSize;
|
||||||
|
string jsonContent = UnityEngine.JsonUtility.ToJson(cacheInfo);
|
||||||
|
FileUtility.CreateFile(_bundleInfo.Bundle.CachedInfoFilePath, jsonContent);
|
||||||
|
|
||||||
|
// 记录缓存文件
|
||||||
|
var wrapper = new PackageCache.RecordWrapper(_bundleInfo.Bundle.CachedInfoFilePath, _bundleInfo.Bundle.CachedDataFilePath, _bundleInfo.Bundle.FileCRC, _bundleInfo.Bundle.FileSize);
|
||||||
|
CacheSystem.RecordFile(_bundleInfo.Bundle.PackageName, _bundleInfo.Bundle.CacheGUID, wrapper);
|
||||||
|
|
||||||
_lastError = string.Empty;
|
_lastError = string.Empty;
|
||||||
_lastCode = 0;
|
_lastCode = 0;
|
||||||
_steps = ESteps.Succeed;
|
_steps = ESteps.Succeed;
|
||||||
}
|
}
|
||||||
else
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
_lastError = $"Verify bundle content failed : {_bundleInfo.Bundle.FileName}";
|
_lastError = e.Message;
|
||||||
|
|
||||||
// 验证失败后删除文件
|
|
||||||
if (File.Exists(_tempFilePath))
|
|
||||||
File.Delete(_tempFilePath);
|
|
||||||
|
|
||||||
_steps = ESteps.TryAgain;
|
_steps = ESteps.TryAgain;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,150 +0,0 @@
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace YooAsset
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 检查包裹内容的完整性
|
|
||||||
/// </summary>
|
|
||||||
public abstract class CheckPackageContentsOperation : AsyncOperationBase
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
internal sealed class EditorSimulateModeCheckPackageContentsOperation : CheckPackageContentsOperation
|
|
||||||
{
|
|
||||||
internal EditorSimulateModeCheckPackageContentsOperation()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
internal override void Start()
|
|
||||||
{
|
|
||||||
Status = EOperationStatus.Succeed;
|
|
||||||
}
|
|
||||||
internal override void Update()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
internal sealed class OfflinePlayModeCheckPackageContentsOperation : CheckPackageContentsOperation
|
|
||||||
{
|
|
||||||
internal OfflinePlayModeCheckPackageContentsOperation()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
internal override void Start()
|
|
||||||
{
|
|
||||||
Status = EOperationStatus.Succeed;
|
|
||||||
}
|
|
||||||
internal override void Update()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
internal sealed class HostPlayModeCheckPackageContentsOperation : CheckPackageContentsOperation
|
|
||||||
{
|
|
||||||
private enum ESteps
|
|
||||||
{
|
|
||||||
None,
|
|
||||||
CheckActiveManifest,
|
|
||||||
LoadCacheManifest,
|
|
||||||
VerifyPackage,
|
|
||||||
Done,
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly HostPlayModeImpl _impl;
|
|
||||||
private readonly string _packageName;
|
|
||||||
private readonly string _packageVersion;
|
|
||||||
private LoadCacheManifestOperation _loadCacheManifestOp;
|
|
||||||
private VerifyPackageOperation _verifyOperation;
|
|
||||||
private PatchManifest _verifyManifest;
|
|
||||||
private ESteps _steps = ESteps.None;
|
|
||||||
|
|
||||||
internal HostPlayModeCheckPackageContentsOperation(HostPlayModeImpl impl, string packageName, string packageVersion)
|
|
||||||
{
|
|
||||||
_impl = impl;
|
|
||||||
_packageName = packageName;
|
|
||||||
_packageVersion = packageVersion;
|
|
||||||
}
|
|
||||||
internal override void Start()
|
|
||||||
{
|
|
||||||
_steps = ESteps.CheckActiveManifest;
|
|
||||||
}
|
|
||||||
internal override void Update()
|
|
||||||
{
|
|
||||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (_steps == ESteps.CheckActiveManifest)
|
|
||||||
{
|
|
||||||
// 检测当前激活的清单对象
|
|
||||||
if (_impl.ActiveManifest != null && _impl.ActiveManifest.PackageVersion == _packageVersion)
|
|
||||||
{
|
|
||||||
_verifyManifest = _impl.ActiveManifest;
|
|
||||||
_steps = ESteps.VerifyPackage;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_steps = ESteps.LoadCacheManifest;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_steps == ESteps.LoadCacheManifest)
|
|
||||||
{
|
|
||||||
if (_loadCacheManifestOp == null)
|
|
||||||
{
|
|
||||||
_loadCacheManifestOp = new LoadCacheManifestOperation(_packageName, _packageVersion);
|
|
||||||
OperationSystem.StartOperation(_loadCacheManifestOp);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_loadCacheManifestOp.IsDone == false)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (_loadCacheManifestOp.Status == EOperationStatus.Succeed)
|
|
||||||
{
|
|
||||||
_verifyManifest = _loadCacheManifestOp.Manifest;
|
|
||||||
_steps = ESteps.VerifyPackage;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_steps = ESteps.Done;
|
|
||||||
Status = EOperationStatus.Failed;
|
|
||||||
Error = _loadCacheManifestOp.Error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_steps == ESteps.VerifyPackage)
|
|
||||||
{
|
|
||||||
if (_verifyOperation == null)
|
|
||||||
{
|
|
||||||
_verifyOperation = VerifyPackageOperation.CreateOperation(_verifyManifest, _impl);
|
|
||||||
OperationSystem.StartOperation(_verifyOperation);
|
|
||||||
}
|
|
||||||
|
|
||||||
Progress = _verifyOperation.Progress;
|
|
||||||
if (_verifyOperation.IsDone == false)
|
|
||||||
return;
|
|
||||||
|
|
||||||
bool verifySucceed = true;
|
|
||||||
foreach (var verifyInfo in _verifyOperation.VerifyFailList)
|
|
||||||
{
|
|
||||||
// 注意:跳过内置资源文件
|
|
||||||
if (verifyInfo.IsBuildinFile)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
verifySucceed = false;
|
|
||||||
YooLogger.Warning($"Failed verify file : {verifyInfo.VerifyFilePath}");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (verifySucceed)
|
|
||||||
{
|
|
||||||
_steps = ESteps.Done;
|
|
||||||
Status = EOperationStatus.Succeed;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_steps = ESteps.Done;
|
|
||||||
Status = EOperationStatus.Failed;
|
|
||||||
Error = $"The package resource {_packageName} content has verify failed file !";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,104 +0,0 @@
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
namespace YooAsset
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 清理本地包裹未使用的缓存文件
|
|
||||||
/// </summary>
|
|
||||||
public sealed class ClearUnusedCacheFilesOperation : AsyncOperationBase
|
|
||||||
{
|
|
||||||
private enum ESteps
|
|
||||||
{
|
|
||||||
None,
|
|
||||||
GetUnusedCacheFiles,
|
|
||||||
ClearUnusedCacheFiles,
|
|
||||||
Done,
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly AssetsPackage _package;
|
|
||||||
private List<string> _unusedCacheFilePaths;
|
|
||||||
private int _unusedFileTotalCount = 0;
|
|
||||||
private ESteps _steps = ESteps.None;
|
|
||||||
|
|
||||||
internal ClearUnusedCacheFilesOperation(AssetsPackage package)
|
|
||||||
{
|
|
||||||
_package = package;
|
|
||||||
}
|
|
||||||
internal override void Start()
|
|
||||||
{
|
|
||||||
_steps = ESteps.GetUnusedCacheFiles;
|
|
||||||
}
|
|
||||||
internal override void Update()
|
|
||||||
{
|
|
||||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (_steps == ESteps.GetUnusedCacheFiles)
|
|
||||||
{
|
|
||||||
_unusedCacheFilePaths = GetUnusedCacheFilePaths();
|
|
||||||
_unusedFileTotalCount = _unusedCacheFilePaths.Count;
|
|
||||||
YooLogger.Log($"Found unused cache file count : {_unusedFileTotalCount}");
|
|
||||||
_steps = ESteps.ClearUnusedCacheFiles;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_steps == ESteps.ClearUnusedCacheFiles)
|
|
||||||
{
|
|
||||||
for (int i = _unusedCacheFilePaths.Count - 1; i >= 0; i--)
|
|
||||||
{
|
|
||||||
string filePath = _unusedCacheFilePaths[i];
|
|
||||||
if (File.Exists(filePath))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
File.Delete(filePath);
|
|
||||||
YooLogger.Log($"Delete unused cache file : {filePath}");
|
|
||||||
}
|
|
||||||
catch (System.Exception e)
|
|
||||||
{
|
|
||||||
YooLogger.Warning($"Failed delete cache file : {filePath} ! {e.Message}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_unusedCacheFilePaths.RemoveAt(i);
|
|
||||||
|
|
||||||
if (OperationSystem.IsBusy)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_unusedFileTotalCount == 0)
|
|
||||||
Progress = 1.0f;
|
|
||||||
else
|
|
||||||
Progress = 1.0f - (_unusedCacheFilePaths.Count / _unusedFileTotalCount);
|
|
||||||
|
|
||||||
if (_unusedCacheFilePaths.Count == 0)
|
|
||||||
{
|
|
||||||
_steps = ESteps.Done;
|
|
||||||
Status = EOperationStatus.Succeed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取未被使用的缓存文件路径集合
|
|
||||||
/// </summary>
|
|
||||||
private List<string> GetUnusedCacheFilePaths()
|
|
||||||
{
|
|
||||||
string cacheFolderPath = PersistentHelper.GetCacheFolderPath(_package.PackageName);
|
|
||||||
if (Directory.Exists(cacheFolderPath) == false)
|
|
||||||
return new List<string>();
|
|
||||||
|
|
||||||
DirectoryInfo directoryInfo = new DirectoryInfo(cacheFolderPath);
|
|
||||||
FileInfo[] fileInfos = directoryInfo.GetFiles();
|
|
||||||
List<string> result = new List<string>(fileInfos.Length);
|
|
||||||
foreach (FileInfo fileInfo in fileInfos)
|
|
||||||
{
|
|
||||||
if (_package.IsIncludeBundleFile(fileInfo.Name) == false)
|
|
||||||
{
|
|
||||||
result.Add(fileInfo.FullName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -79,7 +79,7 @@ namespace YooAsset
|
||||||
None,
|
None,
|
||||||
QueryBuildinPackageVersion,
|
QueryBuildinPackageVersion,
|
||||||
LoadBuildinManifest,
|
LoadBuildinManifest,
|
||||||
VerifyPackage,
|
PackageCaching,
|
||||||
Done,
|
Done,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@ namespace YooAsset
|
||||||
private readonly string _packageName;
|
private readonly string _packageName;
|
||||||
private QueryBuildinPackageVersionOperation _queryBuildinPackageVersionOp;
|
private QueryBuildinPackageVersionOperation _queryBuildinPackageVersionOp;
|
||||||
private LoadBuildinManifestOperation _loadBuildinManifestOp;
|
private LoadBuildinManifestOperation _loadBuildinManifestOp;
|
||||||
private VerifyPackageOperation _verifyOperation;
|
private PackageCachingOperation _cachingOperation;
|
||||||
private ESteps _steps = ESteps.None;
|
private ESteps _steps = ESteps.None;
|
||||||
|
|
||||||
internal OfflinePlayModeInitializationOperation(OfflinePlayModeImpl impl, string packageName)
|
internal OfflinePlayModeInitializationOperation(OfflinePlayModeImpl impl, string packageName)
|
||||||
|
@ -143,7 +143,7 @@ namespace YooAsset
|
||||||
{
|
{
|
||||||
PackageVersion = _loadBuildinManifestOp.Manifest.PackageVersion;
|
PackageVersion = _loadBuildinManifestOp.Manifest.PackageVersion;
|
||||||
_impl.ActiveManifest = _loadBuildinManifestOp.Manifest;
|
_impl.ActiveManifest = _loadBuildinManifestOp.Manifest;
|
||||||
_steps = ESteps.VerifyPackage;
|
_steps = ESteps.PackageCaching;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -153,16 +153,16 @@ namespace YooAsset
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_steps == ESteps.VerifyPackage)
|
if (_steps == ESteps.PackageCaching)
|
||||||
{
|
{
|
||||||
if (_verifyOperation == null)
|
if (_cachingOperation == null)
|
||||||
{
|
{
|
||||||
_verifyOperation = VerifyPackageOperation.CreateOperation(_impl.ActiveManifest, _impl);
|
_cachingOperation = new PackageCachingOperation(_packageName);
|
||||||
OperationSystem.StartOperation(_verifyOperation);
|
OperationSystem.StartOperation(_cachingOperation);
|
||||||
}
|
}
|
||||||
|
|
||||||
Progress = _verifyOperation.Progress;
|
Progress = _cachingOperation.Progress;
|
||||||
if (_verifyOperation.IsDone)
|
if (_cachingOperation.IsDone)
|
||||||
{
|
{
|
||||||
_steps = ESteps.Done;
|
_steps = ESteps.Done;
|
||||||
Status = EOperationStatus.Succeed;
|
Status = EOperationStatus.Succeed;
|
||||||
|
@ -186,7 +186,7 @@ namespace YooAsset
|
||||||
QueryBuildinPackageVersion,
|
QueryBuildinPackageVersion,
|
||||||
UnpackBuildinManifest,
|
UnpackBuildinManifest,
|
||||||
LoadBuildinManifest,
|
LoadBuildinManifest,
|
||||||
VerifyPackage,
|
PackageCaching,
|
||||||
Done,
|
Done,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,7 +197,7 @@ namespace YooAsset
|
||||||
private UnpackBuildinManifestOperation _unpackBuildinManifestOp;
|
private UnpackBuildinManifestOperation _unpackBuildinManifestOp;
|
||||||
private LoadBuildinManifestOperation _loadBuildinManifestOp;
|
private LoadBuildinManifestOperation _loadBuildinManifestOp;
|
||||||
private LoadCacheManifestOperation _loadCacheManifestOp;
|
private LoadCacheManifestOperation _loadCacheManifestOp;
|
||||||
private VerifyPackageOperation _verifyOperation;
|
private PackageCachingOperation _cachingOperation;
|
||||||
private ESteps _steps = ESteps.None;
|
private ESteps _steps = ESteps.None;
|
||||||
|
|
||||||
internal HostPlayModeInitializationOperation(HostPlayModeImpl impl, string packageName)
|
internal HostPlayModeInitializationOperation(HostPlayModeImpl impl, string packageName)
|
||||||
|
@ -265,7 +265,7 @@ namespace YooAsset
|
||||||
{
|
{
|
||||||
PackageVersion = _loadCacheManifestOp.Manifest.PackageVersion;
|
PackageVersion = _loadCacheManifestOp.Manifest.PackageVersion;
|
||||||
_impl.ActiveManifest = _loadCacheManifestOp.Manifest;
|
_impl.ActiveManifest = _loadCacheManifestOp.Manifest;
|
||||||
_steps = ESteps.VerifyPackage;
|
_steps = ESteps.PackageCaching;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -284,15 +284,14 @@ namespace YooAsset
|
||||||
if (_queryBuildinPackageVersionOp.IsDone == false)
|
if (_queryBuildinPackageVersionOp.IsDone == false)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// 注意:为了兼容MOD模式,初始化动态新增的包裹的时候,如果内置清单不存在也不需要报错!
|
|
||||||
if (_queryBuildinPackageVersionOp.Status == EOperationStatus.Succeed)
|
if (_queryBuildinPackageVersionOp.Status == EOperationStatus.Succeed)
|
||||||
{
|
{
|
||||||
_steps = ESteps.UnpackBuildinManifest;
|
_steps = ESteps.UnpackBuildinManifest;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_steps = ESteps.Done;
|
// 注意:为了兼容MOD模式,初始化动态新增的包裹的时候,如果内置清单不存在也不需要报错!
|
||||||
Status = EOperationStatus.Succeed;
|
_steps = ESteps.PackageCaching;
|
||||||
string error = _queryBuildinPackageVersionOp.Error;
|
string error = _queryBuildinPackageVersionOp.Error;
|
||||||
YooLogger.Log($"Failed to load buildin package version file : {error}");
|
YooLogger.Log($"Failed to load buildin package version file : {error}");
|
||||||
}
|
}
|
||||||
|
@ -337,7 +336,7 @@ namespace YooAsset
|
||||||
{
|
{
|
||||||
PackageVersion = _loadBuildinManifestOp.Manifest.PackageVersion;
|
PackageVersion = _loadBuildinManifestOp.Manifest.PackageVersion;
|
||||||
_impl.ActiveManifest = _loadBuildinManifestOp.Manifest;
|
_impl.ActiveManifest = _loadBuildinManifestOp.Manifest;
|
||||||
_steps = ESteps.VerifyPackage;
|
_steps = ESteps.PackageCaching;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -347,16 +346,16 @@ namespace YooAsset
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_steps == ESteps.VerifyPackage)
|
if (_steps == ESteps.PackageCaching)
|
||||||
{
|
{
|
||||||
if (_verifyOperation == null)
|
if (_cachingOperation == null)
|
||||||
{
|
{
|
||||||
_verifyOperation = VerifyPackageOperation.CreateOperation(_impl.ActiveManifest, _impl);
|
_cachingOperation = new PackageCachingOperation(_packageName);
|
||||||
OperationSystem.StartOperation(_verifyOperation);
|
OperationSystem.StartOperation(_cachingOperation);
|
||||||
}
|
}
|
||||||
|
|
||||||
Progress = _verifyOperation.Progress;
|
Progress = _cachingOperation.Progress;
|
||||||
if (_verifyOperation.IsDone)
|
if (_cachingOperation.IsDone)
|
||||||
{
|
{
|
||||||
_steps = ESteps.Done;
|
_steps = ESteps.Done;
|
||||||
Status = EOperationStatus.Succeed;
|
Status = EOperationStatus.Succeed;
|
||||||
|
|
|
@ -1,294 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Threading;
|
|
||||||
|
|
||||||
namespace YooAsset
|
|
||||||
{
|
|
||||||
internal abstract class VerifyPackageOperation : AsyncOperationBase
|
|
||||||
{
|
|
||||||
public List<VerifyInfo> VerifySuccessList { protected set; get; }
|
|
||||||
public List<VerifyInfo> VerifyFailList { protected set; get; }
|
|
||||||
|
|
||||||
public static VerifyPackageOperation CreateOperation(PatchManifest manifest, IPlayModeServices playModeServices)
|
|
||||||
{
|
|
||||||
#if UNITY_WEBGL
|
|
||||||
VerifyPackageOperation operation = new VerifyPackageWithoutThreadOperation(manifest, playModeServices);
|
|
||||||
#else
|
|
||||||
VerifyPackageOperation operation = new VerifyPackageWithThreadOperation(manifest, playModeServices);
|
|
||||||
#endif
|
|
||||||
return operation;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 本地缓存文件验证(线程版)
|
|
||||||
/// </summary>
|
|
||||||
internal class VerifyPackageWithThreadOperation : VerifyPackageOperation
|
|
||||||
{
|
|
||||||
private enum ESteps
|
|
||||||
{
|
|
||||||
None,
|
|
||||||
InitVerify,
|
|
||||||
PrepareVerify,
|
|
||||||
UpdateVerify,
|
|
||||||
Done,
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly PatchManifest _manifest;
|
|
||||||
private readonly IPlayModeServices _playModeServices;
|
|
||||||
private readonly ThreadSyncContext _syncContext = new ThreadSyncContext();
|
|
||||||
private List<VerifyInfo> _waitingList;
|
|
||||||
private List<VerifyInfo> _verifyingList;
|
|
||||||
private int _verifyMaxNum;
|
|
||||||
private int _verifyTotalCount;
|
|
||||||
private float _verifyStartTime;
|
|
||||||
private ESteps _steps = ESteps.None;
|
|
||||||
|
|
||||||
public VerifyPackageWithThreadOperation(PatchManifest manifest, IPlayModeServices playModeServices)
|
|
||||||
{
|
|
||||||
_manifest = manifest;
|
|
||||||
_playModeServices = playModeServices;
|
|
||||||
}
|
|
||||||
internal override void Start()
|
|
||||||
{
|
|
||||||
_steps = ESteps.InitVerify;
|
|
||||||
_verifyStartTime = UnityEngine.Time.realtimeSinceStartup;
|
|
||||||
}
|
|
||||||
internal override void Update()
|
|
||||||
{
|
|
||||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (_steps == ESteps.InitVerify)
|
|
||||||
{
|
|
||||||
int bundleCount = _manifest.BundleList.Count;
|
|
||||||
VerifySuccessList = new List<VerifyInfo>(bundleCount);
|
|
||||||
VerifyFailList = new List<VerifyInfo>(bundleCount);
|
|
||||||
|
|
||||||
// 设置同时验证的最大数
|
|
||||||
ThreadPool.GetMaxThreads(out int workerThreads, out int ioThreads);
|
|
||||||
YooLogger.Log($"Work threads : {workerThreads}, IO threads : {ioThreads}");
|
|
||||||
_verifyMaxNum = Math.Min(workerThreads, ioThreads);
|
|
||||||
_verifyTotalCount = bundleCount;
|
|
||||||
if (_verifyMaxNum < 1)
|
|
||||||
_verifyMaxNum = 1;
|
|
||||||
|
|
||||||
_waitingList = new List<VerifyInfo>(bundleCount);
|
|
||||||
_verifyingList = new List<VerifyInfo>(_verifyMaxNum);
|
|
||||||
_steps = ESteps.PrepareVerify;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_steps == ESteps.PrepareVerify)
|
|
||||||
{
|
|
||||||
foreach (var patchBundle in _manifest.BundleList)
|
|
||||||
{
|
|
||||||
if (CacheSystem.IsCached(patchBundle))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
bool isBuildinFile = _playModeServices.IsBuildinPatchBundle(patchBundle);
|
|
||||||
VerifyInfo verifyInfo = new VerifyInfo(isBuildinFile, patchBundle);
|
|
||||||
_waitingList.Add(verifyInfo);
|
|
||||||
}
|
|
||||||
_steps = ESteps.UpdateVerify;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_steps == ESteps.UpdateVerify)
|
|
||||||
{
|
|
||||||
_syncContext.Update();
|
|
||||||
|
|
||||||
Progress = GetVerifierProgress();
|
|
||||||
if (_waitingList.Count == 0 && _verifyingList.Count == 0)
|
|
||||||
{
|
|
||||||
_steps = ESteps.Done;
|
|
||||||
Status = EOperationStatus.Succeed;
|
|
||||||
float costTime = UnityEngine.Time.realtimeSinceStartup - _verifyStartTime;
|
|
||||||
YooLogger.Log($"Verify elapsed time {costTime:f1} seconds");
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = _waitingList.Count - 1; i >= 0; i--)
|
|
||||||
{
|
|
||||||
if (OperationSystem.IsBusy)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (_verifyingList.Count >= _verifyMaxNum)
|
|
||||||
break;
|
|
||||||
|
|
||||||
var verifyIno = _waitingList[i];
|
|
||||||
if (VerifyFileWithThread(verifyIno))
|
|
||||||
{
|
|
||||||
_waitingList.RemoveAt(i);
|
|
||||||
_verifyingList.Add(verifyIno);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
YooLogger.Warning("The thread pool is failed queued.");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private float GetVerifierProgress()
|
|
||||||
{
|
|
||||||
if (_verifyTotalCount == 0)
|
|
||||||
return 1f;
|
|
||||||
return (float)(VerifySuccessList.Count + VerifyFailList.Count) / _verifyTotalCount;
|
|
||||||
}
|
|
||||||
private bool VerifyFileWithThread(VerifyInfo verifyInfo)
|
|
||||||
{
|
|
||||||
return ThreadPool.QueueUserWorkItem(new WaitCallback(VerifyInThread), verifyInfo);
|
|
||||||
}
|
|
||||||
private void VerifyInThread(object infoObj)
|
|
||||||
{
|
|
||||||
VerifyInfo verifyInfo = (VerifyInfo)infoObj;
|
|
||||||
verifyInfo.Result = CacheSystem.VerifyBundle(verifyInfo.VerifyBundle, CacheSystem.InitVerifyLevel);
|
|
||||||
_syncContext.Post(VerifyCallback, verifyInfo);
|
|
||||||
}
|
|
||||||
private void VerifyCallback(object obj)
|
|
||||||
{
|
|
||||||
VerifyInfo verifyIno = (VerifyInfo)obj;
|
|
||||||
if (verifyIno.Result == EVerifyResult.Succeed)
|
|
||||||
{
|
|
||||||
VerifySuccessList.Add(verifyIno);
|
|
||||||
CacheSystem.CacheBundle(verifyIno.VerifyBundle);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
VerifyFailList.Add(verifyIno);
|
|
||||||
|
|
||||||
// 删除验证失败的缓存文件
|
|
||||||
if (File.Exists(verifyIno.VerifyBundle.CachedFilePath))
|
|
||||||
{
|
|
||||||
YooLogger.Warning($"Delete verify failed bundle file : {verifyIno.VerifyBundle.CachedFilePath}");
|
|
||||||
File.Delete(verifyIno.VerifyBundle.CachedFilePath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_verifyingList.Remove(verifyIno);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 本地缓存文件验证(非线程版)
|
|
||||||
/// </summary>
|
|
||||||
internal class VerifyPackageWithoutThreadOperation : VerifyPackageOperation
|
|
||||||
{
|
|
||||||
private enum ESteps
|
|
||||||
{
|
|
||||||
None,
|
|
||||||
InitVerify,
|
|
||||||
PrepareVerify,
|
|
||||||
UpdateVerify,
|
|
||||||
Done,
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly PatchManifest _manifest;
|
|
||||||
private readonly IPlayModeServices _playModeServices;
|
|
||||||
private List<VerifyInfo> _waitingList;
|
|
||||||
private List<VerifyInfo> _verifyingList;
|
|
||||||
private int _verifyMaxNum;
|
|
||||||
private int _verifyTotalCount;
|
|
||||||
private float _verifyStartTime;
|
|
||||||
private ESteps _steps = ESteps.None;
|
|
||||||
|
|
||||||
public VerifyPackageWithoutThreadOperation(PatchManifest manifest, IPlayModeServices playModeServices)
|
|
||||||
{
|
|
||||||
_manifest = manifest;
|
|
||||||
_playModeServices = playModeServices;
|
|
||||||
}
|
|
||||||
internal override void Start()
|
|
||||||
{
|
|
||||||
_steps = ESteps.InitVerify;
|
|
||||||
_verifyStartTime = UnityEngine.Time.realtimeSinceStartup;
|
|
||||||
}
|
|
||||||
internal override void Update()
|
|
||||||
{
|
|
||||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (_steps == ESteps.InitVerify)
|
|
||||||
{
|
|
||||||
int bundleCount = _manifest.BundleList.Count;
|
|
||||||
VerifySuccessList = new List<VerifyInfo>(bundleCount);
|
|
||||||
VerifyFailList = new List<VerifyInfo>(bundleCount);
|
|
||||||
|
|
||||||
// 设置同时验证的最大数
|
|
||||||
_verifyMaxNum = bundleCount;
|
|
||||||
_verifyTotalCount = bundleCount;
|
|
||||||
|
|
||||||
_waitingList = new List<VerifyInfo>(bundleCount);
|
|
||||||
_verifyingList = new List<VerifyInfo>(_verifyMaxNum);
|
|
||||||
_steps = ESteps.PrepareVerify;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_steps == ESteps.PrepareVerify)
|
|
||||||
{
|
|
||||||
foreach (var patchBundle in _manifest.BundleList)
|
|
||||||
{
|
|
||||||
if (CacheSystem.IsCached(patchBundle))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
bool isBuildinFile = _playModeServices.IsBuildinPatchBundle(patchBundle);
|
|
||||||
VerifyInfo verifyInfo = new VerifyInfo(isBuildinFile, patchBundle);
|
|
||||||
_waitingList.Add(verifyInfo);
|
|
||||||
}
|
|
||||||
_steps = ESteps.UpdateVerify;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_steps == ESteps.UpdateVerify)
|
|
||||||
{
|
|
||||||
Progress = GetVerifierProgress();
|
|
||||||
if (_waitingList.Count == 0 && _verifyingList.Count == 0)
|
|
||||||
{
|
|
||||||
_steps = ESteps.Done;
|
|
||||||
Status = EOperationStatus.Succeed;
|
|
||||||
float costTime = UnityEngine.Time.realtimeSinceStartup - _verifyStartTime;
|
|
||||||
YooLogger.Log($"Verify elapsed time {costTime:f1} seconds");
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = _waitingList.Count - 1; i >= 0; i--)
|
|
||||||
{
|
|
||||||
if (OperationSystem.IsBusy)
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (_verifyingList.Count >= _verifyMaxNum)
|
|
||||||
break;
|
|
||||||
|
|
||||||
var verifyIno = _waitingList[i];
|
|
||||||
VerifyFileWithoutThread(verifyIno);
|
|
||||||
_waitingList.RemoveAt(i);
|
|
||||||
_verifyingList.Add(verifyIno);
|
|
||||||
}
|
|
||||||
|
|
||||||
_verifyingList.Clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private float GetVerifierProgress()
|
|
||||||
{
|
|
||||||
if (_verifyTotalCount == 0)
|
|
||||||
return 1f;
|
|
||||||
return (float)(VerifySuccessList.Count + VerifyFailList.Count) / _verifyTotalCount;
|
|
||||||
}
|
|
||||||
private void VerifyFileWithoutThread(VerifyInfo verifyIno)
|
|
||||||
{
|
|
||||||
var verifyResult = CacheSystem.VerifyAndCacheLocalBundleFile(verifyIno.VerifyBundle, CacheSystem.InitVerifyLevel);
|
|
||||||
if (verifyResult == EVerifyResult.Succeed)
|
|
||||||
{
|
|
||||||
VerifySuccessList.Add(verifyIno);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
VerifyFailList.Add(verifyIno);
|
|
||||||
|
|
||||||
// 删除验证失败的缓存文件
|
|
||||||
if (File.Exists(verifyIno.VerifyBundle.CachedFilePath))
|
|
||||||
{
|
|
||||||
YooLogger.Warning($"Delete verify failed bundle file : {verifyIno.VerifyBundle.CachedFilePath}");
|
|
||||||
File.Delete(verifyIno.VerifyBundle.CachedFilePath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -47,7 +47,7 @@ namespace YooAsset
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 联机模式的更新清单操作
|
/// 联机模式的更新清单操作
|
||||||
/// 注意:优先加载沙盒里缓存的清单文件,如果有变化就更新远端清单文件,并保存到本地。
|
/// 注意:优先加载沙盒里缓存的清单文件,如果缓存没找到就下载远端清单文件,并保存到本地。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal sealed class HostPlayModeUpdatePackageManifestOperation : UpdatePackageManifestOperation
|
internal sealed class HostPlayModeUpdatePackageManifestOperation : UpdatePackageManifestOperation
|
||||||
{
|
{
|
||||||
|
@ -59,7 +59,6 @@ namespace YooAsset
|
||||||
DownloadManifest,
|
DownloadManifest,
|
||||||
LoadCacheManifest,
|
LoadCacheManifest,
|
||||||
CheckDeserializeManifest,
|
CheckDeserializeManifest,
|
||||||
VerifyPackage,
|
|
||||||
Done,
|
Done,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,7 +69,6 @@ namespace YooAsset
|
||||||
private LoadCacheManifestOperation _tryLoadCacheManifestOp;
|
private LoadCacheManifestOperation _tryLoadCacheManifestOp;
|
||||||
private LoadCacheManifestOperation _loadCacheManifestOp;
|
private LoadCacheManifestOperation _loadCacheManifestOp;
|
||||||
private DownloadManifestOperation _downloadManifestOp;
|
private DownloadManifestOperation _downloadManifestOp;
|
||||||
private VerifyPackageOperation _verifyOperation;
|
|
||||||
private ESteps _steps = ESteps.None;
|
private ESteps _steps = ESteps.None;
|
||||||
|
|
||||||
|
|
||||||
|
@ -118,7 +116,8 @@ namespace YooAsset
|
||||||
if (_tryLoadCacheManifestOp.Status == EOperationStatus.Succeed)
|
if (_tryLoadCacheManifestOp.Status == EOperationStatus.Succeed)
|
||||||
{
|
{
|
||||||
_impl.ActiveManifest = _tryLoadCacheManifestOp.Manifest;
|
_impl.ActiveManifest = _tryLoadCacheManifestOp.Manifest;
|
||||||
_steps = ESteps.VerifyPackage;
|
_steps = ESteps.Done;
|
||||||
|
Status = EOperationStatus.Succeed;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -163,7 +162,8 @@ namespace YooAsset
|
||||||
if (_loadCacheManifestOp.Status == EOperationStatus.Succeed)
|
if (_loadCacheManifestOp.Status == EOperationStatus.Succeed)
|
||||||
{
|
{
|
||||||
_impl.ActiveManifest = _loadCacheManifestOp.Manifest;
|
_impl.ActiveManifest = _loadCacheManifestOp.Manifest;
|
||||||
_steps = ESteps.VerifyPackage;
|
_steps = ESteps.Done;
|
||||||
|
Status = EOperationStatus.Succeed;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -172,22 +172,6 @@ namespace YooAsset
|
||||||
Error = _loadCacheManifestOp.Error;
|
Error = _loadCacheManifestOp.Error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_steps == ESteps.VerifyPackage)
|
|
||||||
{
|
|
||||||
if (_verifyOperation == null)
|
|
||||||
{
|
|
||||||
_verifyOperation = VerifyPackageOperation.CreateOperation(_impl.ActiveManifest, _impl);
|
|
||||||
OperationSystem.StartOperation(_verifyOperation);
|
|
||||||
}
|
|
||||||
|
|
||||||
Progress = _verifyOperation.Progress;
|
|
||||||
if (_verifyOperation.IsDone)
|
|
||||||
{
|
|
||||||
_steps = ESteps.Done;
|
|
||||||
Status = EOperationStatus.Succeed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -45,22 +45,63 @@ namespace YooAsset
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 所属的包裹名称
|
/// 所属的包裹名称
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private string _packageName;
|
public string PackageName { private set; get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 缓存文件路径
|
/// 缓存GUID
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private string _cachedFilePath;
|
public string CacheGUID
|
||||||
public string CachedFilePath
|
{
|
||||||
|
get { return FileHash; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 缓存的数据文件路径
|
||||||
|
/// </summary>
|
||||||
|
private string _cachedDataFilePath;
|
||||||
|
public string CachedDataFilePath
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(_cachedFilePath) == false)
|
if (string.IsNullOrEmpty(_cachedDataFilePath) == false)
|
||||||
return _cachedFilePath;
|
return _cachedDataFilePath;
|
||||||
|
|
||||||
string cacheRoot = PersistentHelper.GetCacheFolderPath(_packageName);
|
string cacheRoot = PersistentHelper.GetCacheFolderPath(PackageName);
|
||||||
_cachedFilePath = $"{cacheRoot}/{FileName}";
|
_cachedDataFilePath = $"{cacheRoot}/{CacheGUID}/{YooAssetSettings.CacheBundleDataFileName}";
|
||||||
return _cachedFilePath;
|
return _cachedDataFilePath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 缓存的信息文件路径
|
||||||
|
/// </summary>
|
||||||
|
private string _cachedInfoFilePath;
|
||||||
|
public string CachedInfoFilePath
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(_cachedInfoFilePath) == false)
|
||||||
|
return _cachedInfoFilePath;
|
||||||
|
|
||||||
|
string cacheRoot = PersistentHelper.GetCacheFolderPath(PackageName);
|
||||||
|
_cachedInfoFilePath = $"{cacheRoot}/{CacheGUID}/{YooAssetSettings.CacheBundleInfoFileName}";
|
||||||
|
return _cachedInfoFilePath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 临时的数据文件路径
|
||||||
|
/// </summary>
|
||||||
|
private string _tempDataFilePath;
|
||||||
|
public string TempDataFilePath
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(_tempDataFilePath) == false)
|
||||||
|
return _tempDataFilePath;
|
||||||
|
|
||||||
|
_tempDataFilePath = $"{CachedDataFilePath}.temp";
|
||||||
|
return _tempDataFilePath;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,7 +122,7 @@ namespace YooAsset
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 文件名称
|
/// 文件名称(远端文件名和内置文件名)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private string _fileName;
|
private string _fileName;
|
||||||
public string FileName
|
public string FileName
|
||||||
|
@ -94,20 +135,6 @@ namespace YooAsset
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 缓存查询Key
|
|
||||||
/// </summary>
|
|
||||||
private string _cacheKey;
|
|
||||||
public string CacheKey
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(_cacheKey))
|
|
||||||
throw new Exception("Should never get here !");
|
|
||||||
return _cacheKey;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public PatchBundle()
|
public PatchBundle()
|
||||||
{
|
{
|
||||||
|
@ -118,8 +145,7 @@ namespace YooAsset
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public void ParseBundle(string packageName, int nameStype)
|
public void ParseBundle(string packageName, int nameStype)
|
||||||
{
|
{
|
||||||
_packageName = packageName;
|
PackageName = packageName;
|
||||||
_cacheKey = $"{packageName}-{FileHash}";
|
|
||||||
_fileName = PatchManifestTools.CreateBundleFileName(nameStype, BundleName, FileHash, IsRawFile);
|
_fileName = PatchManifestTools.CreateBundleFileName(nameStype, BundleName, FileHash, IsRawFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -239,11 +239,11 @@ namespace YooAsset
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 是否包含资源文件
|
/// 是否包含资源文件
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsIncludeBundleFile(string fileName)
|
public bool IsIncludeBundleFile(string cacheGUID)
|
||||||
{
|
{
|
||||||
foreach (var patchBundle in BundleList)
|
foreach (var patchBundle in BundleList)
|
||||||
{
|
{
|
||||||
if (patchBundle.FileName == fileName)
|
if (patchBundle.CacheGUID == cacheGUID)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -159,13 +159,13 @@ namespace YooAsset
|
||||||
{
|
{
|
||||||
if (nameStyle == 1) //HashName
|
if (nameStyle == 1) //HashName
|
||||||
{
|
{
|
||||||
string fileExtension = isRawFile ? YooAssetSettingsData.Setting.RawFileVariant : YooAssetSettingsData.Setting.AssetBundleFileVariant;
|
string fileExtension = isRawFile ? YooAssetSettingsData.Setting.RawBundleFileVariant : YooAssetSettingsData.Setting.AssetBundleFileVariant;
|
||||||
return StringUtility.Format("{0}.{1}", fileHash, fileExtension);
|
return StringUtility.Format("{0}.{1}", fileHash, fileExtension);
|
||||||
}
|
}
|
||||||
else if (nameStyle == 4) //BundleName_HashName
|
else if (nameStyle == 4) //BundleName_HashName
|
||||||
{
|
{
|
||||||
string fileName = bundleName.Remove(bundleName.LastIndexOf('.'));
|
string fileName = bundleName.Remove(bundleName.LastIndexOf('.'));
|
||||||
string fileExtension = isRawFile ? YooAssetSettingsData.Setting.RawFileVariant : YooAssetSettingsData.Setting.AssetBundleFileVariant;
|
string fileExtension = isRawFile ? YooAssetSettingsData.Setting.RawBundleFileVariant : YooAssetSettingsData.Setting.AssetBundleFileVariant;
|
||||||
return StringUtility.Format("{0}_{1}.{2}", fileName, fileHash, fileExtension);
|
return StringUtility.Format("{0}_{1}.{2}", fileName, fileHash, fileExtension);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
|
@ -56,12 +56,6 @@ namespace YooAsset
|
||||||
OperationSystem.StartOperation(operation);
|
OperationSystem.StartOperation(operation);
|
||||||
return operation;
|
return operation;
|
||||||
}
|
}
|
||||||
CheckPackageContentsOperation IPlayModeServices.CheckPackageContentsOperation(string packageVersion)
|
|
||||||
{
|
|
||||||
var operation = new EditorSimulateModeCheckPackageContentsOperation();
|
|
||||||
OperationSystem.StartOperation(operation);
|
|
||||||
return operation;
|
|
||||||
}
|
|
||||||
|
|
||||||
PatchDownloaderOperation IPlayModeServices.CreatePatchDownloaderByAll(int downloadingMaxNumber, int failedTryAgain, int timeout)
|
PatchDownloaderOperation IPlayModeServices.CreatePatchDownloaderByAll(int downloadingMaxNumber, int failedTryAgain, int timeout)
|
||||||
{
|
{
|
||||||
|
|
|
@ -95,6 +95,10 @@ namespace YooAsset
|
||||||
{
|
{
|
||||||
return _queryServices.QueryStreamingAssets(patchBundle.FileName);
|
return _queryServices.QueryStreamingAssets(patchBundle.FileName);
|
||||||
}
|
}
|
||||||
|
public bool IsCachedPatchBundle(PatchBundle patchBundle)
|
||||||
|
{
|
||||||
|
return CacheSystem.IsCached(patchBundle.PackageName, patchBundle.CacheGUID);
|
||||||
|
}
|
||||||
|
|
||||||
UpdatePackageVersionOperation IPlayModeServices.UpdatePackageVersionAsync(bool appendTimeTicks, int timeout)
|
UpdatePackageVersionOperation IPlayModeServices.UpdatePackageVersionAsync(bool appendTimeTicks, int timeout)
|
||||||
{
|
{
|
||||||
|
@ -114,12 +118,6 @@ namespace YooAsset
|
||||||
OperationSystem.StartOperation(operation);
|
OperationSystem.StartOperation(operation);
|
||||||
return operation;
|
return operation;
|
||||||
}
|
}
|
||||||
CheckPackageContentsOperation IPlayModeServices.CheckPackageContentsOperation(string packageVersion)
|
|
||||||
{
|
|
||||||
var operation = new HostPlayModeCheckPackageContentsOperation(this, _packageName, packageVersion);
|
|
||||||
OperationSystem.StartOperation(operation);
|
|
||||||
return operation;
|
|
||||||
}
|
|
||||||
|
|
||||||
PatchDownloaderOperation IPlayModeServices.CreatePatchDownloaderByAll(int downloadingMaxNumber, int failedTryAgain, int timeout)
|
PatchDownloaderOperation IPlayModeServices.CreatePatchDownloaderByAll(int downloadingMaxNumber, int failedTryAgain, int timeout)
|
||||||
{
|
{
|
||||||
|
@ -133,7 +131,7 @@ namespace YooAsset
|
||||||
foreach (var patchBundle in patchManifest.BundleList)
|
foreach (var patchBundle in patchManifest.BundleList)
|
||||||
{
|
{
|
||||||
// 忽略缓存文件
|
// 忽略缓存文件
|
||||||
if (CacheSystem.IsCached(patchBundle))
|
if (IsCachedPatchBundle(patchBundle))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// 忽略APP资源
|
// 忽略APP资源
|
||||||
|
@ -158,7 +156,7 @@ namespace YooAsset
|
||||||
foreach (var patchBundle in patchManifest.BundleList)
|
foreach (var patchBundle in patchManifest.BundleList)
|
||||||
{
|
{
|
||||||
// 忽略缓存文件
|
// 忽略缓存文件
|
||||||
if (CacheSystem.IsCached(patchBundle))
|
if (IsCachedPatchBundle(patchBundle))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// 忽略APP资源
|
// 忽略APP资源
|
||||||
|
@ -219,7 +217,7 @@ namespace YooAsset
|
||||||
foreach (var patchBundle in checkList)
|
foreach (var patchBundle in checkList)
|
||||||
{
|
{
|
||||||
// 忽略缓存文件
|
// 忽略缓存文件
|
||||||
if (CacheSystem.IsCached(patchBundle))
|
if (IsCachedPatchBundle(patchBundle))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// 忽略APP资源
|
// 忽略APP资源
|
||||||
|
@ -244,7 +242,7 @@ namespace YooAsset
|
||||||
foreach (var patchBundle in patchManifest.BundleList)
|
foreach (var patchBundle in patchManifest.BundleList)
|
||||||
{
|
{
|
||||||
// 忽略缓存文件
|
// 忽略缓存文件
|
||||||
if (CacheSystem.IsCached(patchBundle))
|
if (IsCachedPatchBundle(patchBundle))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (IsBuildinPatchBundle(patchBundle))
|
if (IsBuildinPatchBundle(patchBundle))
|
||||||
|
@ -268,7 +266,7 @@ namespace YooAsset
|
||||||
foreach (var patchBundle in patchManifest.BundleList)
|
foreach (var patchBundle in patchManifest.BundleList)
|
||||||
{
|
{
|
||||||
// 忽略缓存文件
|
// 忽略缓存文件
|
||||||
if (CacheSystem.IsCached(patchBundle))
|
if (IsCachedPatchBundle(patchBundle))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// 查询DLC资源
|
// 查询DLC资源
|
||||||
|
@ -292,7 +290,7 @@ namespace YooAsset
|
||||||
throw new Exception("Should never get here !");
|
throw new Exception("Should never get here !");
|
||||||
|
|
||||||
// 查询沙盒资源
|
// 查询沙盒资源
|
||||||
if (CacheSystem.IsCached(patchBundle))
|
if (IsCachedPatchBundle(patchBundle))
|
||||||
{
|
{
|
||||||
BundleInfo bundleInfo = new BundleInfo(patchBundle, BundleInfo.ELoadMode.LoadFromCache);
|
BundleInfo bundleInfo = new BundleInfo(patchBundle, BundleInfo.ELoadMode.LoadFromCache);
|
||||||
return bundleInfo;
|
return bundleInfo;
|
||||||
|
|
|
@ -56,12 +56,6 @@ namespace YooAsset
|
||||||
OperationSystem.StartOperation(operation);
|
OperationSystem.StartOperation(operation);
|
||||||
return operation;
|
return operation;
|
||||||
}
|
}
|
||||||
CheckPackageContentsOperation IPlayModeServices.CheckPackageContentsOperation(string packageVersion)
|
|
||||||
{
|
|
||||||
var operation = new OfflinePlayModeCheckPackageContentsOperation();
|
|
||||||
OperationSystem.StartOperation(operation);
|
|
||||||
return operation;
|
|
||||||
}
|
|
||||||
|
|
||||||
PatchDownloaderOperation IPlayModeServices.CreatePatchDownloaderByAll(int downloadingMaxNumber, int failedTryAgain, int timeout)
|
PatchDownloaderOperation IPlayModeServices.CreatePatchDownloaderByAll(int downloadingMaxNumber, int failedTryAgain, int timeout)
|
||||||
{
|
{
|
||||||
|
@ -93,7 +87,7 @@ namespace YooAsset
|
||||||
throw new Exception("Should never get here !");
|
throw new Exception("Should never get here !");
|
||||||
|
|
||||||
// 查询沙盒资源
|
// 查询沙盒资源
|
||||||
if (CacheSystem.IsCached(patchBundle))
|
if (CacheSystem.IsCached(patchBundle.PackageName, patchBundle.CacheGUID))
|
||||||
{
|
{
|
||||||
BundleInfo bundleInfo = new BundleInfo(patchBundle, BundleInfo.ELoadMode.LoadFromCache);
|
BundleInfo bundleInfo = new BundleInfo(patchBundle, BundleInfo.ELoadMode.LoadFromCache);
|
||||||
return bundleInfo;
|
return bundleInfo;
|
||||||
|
|
|
@ -28,11 +28,6 @@ namespace YooAsset
|
||||||
/// </summary>
|
/// </summary>
|
||||||
PreDownloadPackageOperation PreDownloadPackageAsync(string packageVersion, int timeout);
|
PreDownloadPackageOperation PreDownloadPackageAsync(string packageVersion, int timeout);
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 检查包裹内容的完整性
|
|
||||||
/// </summary>
|
|
||||||
CheckPackageContentsOperation CheckPackageContentsOperation(string packageVersion);
|
|
||||||
|
|
||||||
// 下载相关
|
// 下载相关
|
||||||
PatchDownloaderOperation CreatePatchDownloaderByAll(int downloadingMaxNumber, int failedTryAgain, int timeout);
|
PatchDownloaderOperation CreatePatchDownloaderByAll(int downloadingMaxNumber, int failedTryAgain, int timeout);
|
||||||
PatchDownloaderOperation CreatePatchDownloaderByTags(string[] tags, int downloadingMaxNumber, int failedTryAgain, int timeout);
|
PatchDownloaderOperation CreatePatchDownloaderByTags(string[] tags, int downloadingMaxNumber, int failedTryAgain, int timeout);
|
||||||
|
|
|
@ -8,12 +8,12 @@ namespace YooAsset
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// AssetBundle文件的后缀名
|
/// AssetBundle文件的后缀名
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string BundleFileVariant = "bundle";
|
public string AssetBundleFileVariant = "bundle";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 原生文件的后缀名
|
/// 原生文件的后缀名
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string RawFileVariant = "rawfile";
|
public string RawBundleFileVariant = "rawfile";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 清单文件名称
|
/// 清单文件名称
|
||||||
|
|
|
@ -79,9 +79,9 @@ namespace YooAsset
|
||||||
{
|
{
|
||||||
string shareBundleName;
|
string shareBundleName;
|
||||||
if (uniqueBundleName)
|
if (uniqueBundleName)
|
||||||
shareBundleName = $"{packageName.ToLower()}_{YooAssetSettings.UnityShadersBundleName}.{Setting.BundleFileVariant}";
|
shareBundleName = $"{packageName.ToLower()}_{YooAssetSettings.UnityShadersBundleName}.{Setting.AssetBundleFileVariant}";
|
||||||
else
|
else
|
||||||
shareBundleName = $"{YooAssetSettings.UnityShadersBundleName}.{Setting.BundleFileVariant}";
|
shareBundleName = $"{YooAssetSettings.UnityShadersBundleName}.{Setting.AssetBundleFileVariant}";
|
||||||
return shareBundleName.ToLower();
|
return shareBundleName.ToLower();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,5 +98,8 @@ QQ群:**963240451**
|
||||||
|
|
||||||
## 友情链接
|
## 友情链接
|
||||||
[ET Framework](https://github.com/wqaetly/ET/tree/et7_fgui_yooasset_luban_huatuo): ET 7.0 + FGUI + luban + huatuo + YooAsset + NKGMoba + UniTask,并提供常用的编辑器工具。
|
[ET Framework](https://github.com/wqaetly/ET/tree/et7_fgui_yooasset_luban_huatuo): ET 7.0 + FGUI + luban + huatuo + YooAsset + NKGMoba + UniTask,并提供常用的编辑器工具。
|
||||||
|
|
||||||
|
[ETPro](https://github.com/526077247/ETPro) ET6+YooAsset+HybridCLR
|
||||||
|
|
||||||
[YooAssetEx](https://gitee.com/liu_zhongxiu/yoo-asset-ex/tree/master): YooAsset Odin扩展工具,用于支持Unity2017和Unity2018版本。
|
[YooAssetEx](https://gitee.com/liu_zhongxiu/yoo-asset-ex/tree/master): YooAsset Odin扩展工具,用于支持Unity2017和Unity2018版本。
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue