合并2.x功能到1.5

1. 增加获取缓存文件信息的异步操作
2. 支持资源下载器合并
3. 新增资源导入器
main
hevinci 2024-03-27 18:50:10 +08:00
parent 92ac301716
commit bb1c64e444
17 changed files with 387 additions and 33 deletions

View File

@ -1,5 +1,6 @@
using System; using System;
using System.IO; using System.IO;
using System.Text;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEditor; using UnityEditor;
@ -130,7 +131,7 @@ namespace YooAsset.Editor
{ {
var buildMode = buildParametersContext.Parameters.BuildMode; var buildMode = buildParametersContext.Parameters.BuildMode;
if (buildMode == EBuildMode.DryRunBuild || buildMode == EBuildMode.SimulateBuild) if (buildMode == EBuildMode.DryRunBuild || buildMode == EBuildMode.SimulateBuild)
return "00000000000000000000000000000000"; //32位 return GetFilePathTempHash(filePath);
else else
return HashUtility.FileMD5(filePath); return HashUtility.FileMD5(filePath);
} }
@ -150,5 +151,32 @@ namespace YooAsset.Editor
else else
return FileUtility.GetFileSize(filePath); return FileUtility.GetFileSize(filePath);
} }
protected string GetFilePathTempHash(string filePath)
{
byte[] bytes = Encoding.UTF8.GetBytes(filePath);
return HashUtility.BytesMD5(bytes);
// 注意:在文件路径的哈希值冲突的情况下,可以使用下面的方法
//return $"{HashUtility.BytesMD5(bytes)}-{Guid.NewGuid():N}";
}
protected long GetBundleTempSize(BuildBundleInfo bundleInfo)
{
long tempSize = 0;
var assetPaths = bundleInfo.GetAllMainAssetPaths();
foreach (var assetPath in assetPaths)
{
long size = FileUtility.GetFileSize(assetPath);
tempSize += size;
}
if (tempSize == 0)
{
string message = $"Bundle temp size is zero, check bundle main asset list : {bundleInfo.BundleName}";
throw new Exception(message);
}
return tempSize;
}
} }
} }

View File

@ -90,6 +90,15 @@ namespace YooAsset
} }
} }
/// <summary>
/// 获取记录对象
/// </summary>
public static PackageCache.RecordWrapper TryGetWrapper(string packageName, string cacheGUID)
{
var cache = GetOrCreateCache(packageName);
return cache.TryGetWrapper(cacheGUID);
}
/// <summary> /// <summary>
/// 验证缓存文件(子线程内操作) /// 验证缓存文件(子线程内操作)
/// </summary> /// </summary>
@ -165,9 +174,9 @@ namespace YooAsset
/// <summary> /// <summary>
/// 获取所有的缓存文件 /// 获取所有的缓存文件
/// </summary> /// </summary>
public static List<string> GetAllCacheGUIDs(ResourcePackage package) public static List<string> GetAllCacheGUIDs(string packageName)
{ {
var cache = GetOrCreateCache(package.PackageName); var cache = GetOrCreateCache(packageName);
return cache.GetAllKeys(); return cache.GetAllKeys();
} }

View File

@ -37,7 +37,7 @@ namespace YooAsset
if (_steps == ESteps.GetAllCacheFiles) if (_steps == ESteps.GetAllCacheFiles)
{ {
_allCacheGUIDs = CacheSystem.GetAllCacheGUIDs(_package); _allCacheGUIDs = CacheSystem.GetAllCacheGUIDs(_package.PackageName);
_fileTotalCount = _allCacheGUIDs.Count; _fileTotalCount = _allCacheGUIDs.Count;
YooLogger.Log($"Found all cache file count : {_fileTotalCount}"); YooLogger.Log($"Found all cache file count : {_fileTotalCount}");
_steps = ESteps.ClearAllCacheFiles; _steps = ESteps.ClearAllCacheFiles;

View File

@ -0,0 +1,85 @@
using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
namespace YooAsset
{
public class GetAllCacheFileInfosOperation : AsyncOperationBase
{
public class CacheInfo
{
public string FishHash { private set; get; }
public string FilePath { private set; get; }
public string FileCRC { private set; get; }
public long FileSize { private set; get; }
public CacheInfo(string fishHash, string filePath, string fileCRC, long fileSize)
{
FishHash = fishHash;
FilePath = filePath;
FileCRC = fileCRC;
FileSize = fileSize;
}
}
private enum ESteps
{
None,
GetCacheFileInfos,
Done,
}
private readonly string _packageName;
private ESteps _steps = ESteps.None;
private List<CacheInfo> _cacheFileInfos;
/// <summary>
/// 搜索结果
/// </summary>
public List<CacheInfo> Result
{
get { return _cacheFileInfos; }
}
internal GetAllCacheFileInfosOperation(string packageName)
{
_packageName = packageName;
}
internal override void Start()
{
_steps = ESteps.GetCacheFileInfos;
}
internal override void Update()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.GetCacheFileInfos)
{
var allCachedGUIDs = CacheSystem.GetAllCacheGUIDs(_packageName);
_cacheFileInfos = new List<CacheInfo>(allCachedGUIDs.Count);
for (int i = 0; i < allCachedGUIDs.Count; i++)
{
var cachedGUID = allCachedGUIDs[i];
var wrapper = CacheSystem.TryGetWrapper(_packageName, cachedGUID);
if (wrapper != null)
{
string directoryName = Path.GetDirectoryName(wrapper.DataFilePath);
var directoryInfo = new DirectoryInfo(directoryName);
if (directoryInfo.Exists)
{
string fishHash = directoryInfo.Name;
var cacheFileInfo = new CacheInfo(fishHash, wrapper.DataFilePath, wrapper.DataFileCRC, wrapper.DataFileSize);
_cacheFileInfos.Add(cacheFileInfo);
}
}
}
// 注意:总是返回成功
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}
}
}
}

View File

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

View File

@ -37,18 +37,23 @@ namespace YooAsset
{ {
#if UNITY_EDITOR #if UNITY_EDITOR
return StringUtility.Format("file:///{0}", path); return StringUtility.Format("file:///{0}", path);
#elif UNITY_WEBGL
return path;
#elif UNITY_IPHONE #elif UNITY_IPHONE
return StringUtility.Format("file://{0}", path); return StringUtility.Format("file://{0}", path);
#elif UNITY_ANDROID #elif UNITY_ANDROID
if (path.StartsWith("jar:file://"))
return path; return path;
else
return StringUtility.Format("jar:file://{0}", path);
#elif UNITY_STANDALONE_OSX #elif UNITY_STANDALONE_OSX
return new System.Uri(path).ToString(); return new System.Uri(path).ToString();
#elif UNITY_STANDALONE #elif UNITY_STANDALONE
return StringUtility.Format("file:///{0}", path); return StringUtility.Format("file:///{0}", path);
#elif UNITY_WEBGL
return path;
#elif UNITY_OPENHARMONY #elif UNITY_OPENHARMONY
return path; return path;
#else
return path;
#endif #endif
} }
} }

View File

@ -154,10 +154,12 @@ namespace YooAsset
// 填充BundleDic // 填充BundleDic
manifest.BundleDic = new Dictionary<string, PackageBundle>(manifest.BundleList.Count); manifest.BundleDic = new Dictionary<string, PackageBundle>(manifest.BundleList.Count);
manifest.BundleDic2 = new Dictionary<string, PackageBundle>(manifest.BundleList.Count);
foreach (var packageBundle in manifest.BundleList) foreach (var packageBundle in manifest.BundleList)
{ {
packageBundle.ParseBundle(manifest.PackageName, manifest.OutputNameStyle); packageBundle.ParseBundle(manifest.PackageName, manifest.OutputNameStyle);
manifest.BundleDic.Add(packageBundle.BundleName, packageBundle); manifest.BundleDic.Add(packageBundle.BundleName, packageBundle);
manifest.BundleDic2.Add(packageBundle.FileName, packageBundle);
} }
// 填充AssetDic // 填充AssetDic
@ -210,7 +212,18 @@ namespace YooAsset
} }
/// <summary> /// <summary>
/// 批量转换为解压BundleInfo /// 转换为导入BundleInfo
/// </summary>
public static BundleInfo ConvertToImportInfo(PackageBundle packageBundle, string filePath)
{
// 注意:我们把本地文件路径指定为远端下载地址
string persistentPath = PersistentTools.ConvertToWWWPath(filePath);
BundleInfo bundleInfo = new BundleInfo(packageBundle, BundleInfo.ELoadMode.None, persistentPath, persistentPath);
return bundleInfo;
}
/// <summary>
/// 批量转换解压为BundleInfo
/// </summary> /// </summary>
public static List<BundleInfo> ConvertToUnpackInfos(List<PackageBundle> unpackList) public static List<BundleInfo> ConvertToUnpackInfos(List<PackageBundle> unpackList)
{ {

View File

@ -91,14 +91,7 @@ namespace YooAsset
_failedTryAgain = failedTryAgain; _failedTryAgain = failedTryAgain;
_timeout = timeout; _timeout = timeout;
if (downloadList != null) CalculatDownloaderInfo();
{
TotalDownloadCount = downloadList.Count;
foreach (var packageBundle in downloadList)
{
TotalDownloadBytes += packageBundle.Bundle.FileSize;
}
}
} }
internal override void Start() internal override void Start()
{ {
@ -206,6 +199,57 @@ namespace YooAsset
} }
} }
} }
private void CalculatDownloaderInfo()
{
if (_downloadList != null)
{
TotalDownloadBytes = 0;
TotalDownloadCount = _downloadList.Count;
foreach (var packageBundle in _downloadList)
{
TotalDownloadBytes += packageBundle.Bundle.FileSize;
}
}
else
{
TotalDownloadBytes = 0;
TotalDownloadCount = 0;
}
}
/// <summary>
/// 合并其它下载器
/// </summary>
/// <param name="downloader">合并的下载器</param>
public void Combine(DownloaderOperation downloader)
{
if (_steps != ESteps.None)
{
YooLogger.Error("The downloader is running, can not combine with other downloader !");
return;
}
HashSet<string> temper = new HashSet<string>();
foreach (var bundleInfo in _downloadList)
{
if (temper.Contains(bundleInfo.Bundle.CachedDataFilePath) == false)
{
temper.Add(bundleInfo.Bundle.CachedDataFilePath);
}
}
// 合并下载列表
foreach (var bundleInfo in downloader._downloadList)
{
if (temper.Contains(bundleInfo.Bundle.CachedDataFilePath) == false)
{
_downloadList.Add(bundleInfo);
}
}
// 重新统计下载信息
CalculatDownloaderInfo();
}
/// <summary> /// <summary>
/// 开始下载 /// 开始下载
@ -282,4 +326,21 @@ namespace YooAsset
return operation; return operation;
} }
} }
public sealed class ResourceImporterOperation : DownloaderOperation
{
internal ResourceImporterOperation(List<BundleInfo> downloadList, int downloadingMaxNumber, int failedTryAgain, int timeout)
: base(downloadList, downloadingMaxNumber, failedTryAgain, timeout)
{
}
/// <summary>
/// 创建空的导入器
/// </summary>
internal static ResourceImporterOperation CreateEmptyImporter(int upackingMaxNumber, int failedTryAgain, int timeout)
{
List<BundleInfo> downloadList = new List<BundleInfo>();
var operation = new ResourceImporterOperation(downloadList, upackingMaxNumber, failedTryAgain, int.MaxValue);
return operation;
}
}
} }

View File

@ -11,6 +11,11 @@ namespace YooAsset
public abstract class InitializationOperation : AsyncOperationBase public abstract class InitializationOperation : AsyncOperationBase
{ {
public string PackageVersion { protected set; get; } public string PackageVersion { protected set; get; }
/// <summary>
/// 本地记录的资源包裹的版本
/// </summary>
public string RecordVersion { protected set; get; }
} }
/// <summary> /// <summary>
@ -242,6 +247,7 @@ namespace YooAsset
if (_queryCachePackageVersionOp.Status == EOperationStatus.Succeed) if (_queryCachePackageVersionOp.Status == EOperationStatus.Succeed)
{ {
RecordVersion = _queryCachePackageVersionOp.PackageVersion;
_steps = ESteps.TryLoadCacheManifest; _steps = ESteps.TryLoadCacheManifest;
} }
else else

View File

@ -189,6 +189,8 @@ namespace YooAsset
_packageBundleCount = _buffer.ReadInt32(); _packageBundleCount = _buffer.ReadInt32();
Manifest.BundleList = new List<PackageBundle>(_packageBundleCount); Manifest.BundleList = new List<PackageBundle>(_packageBundleCount);
Manifest.BundleDic = new Dictionary<string, PackageBundle>(_packageBundleCount); Manifest.BundleDic = new Dictionary<string, PackageBundle>(_packageBundleCount);
Manifest.BundleDic2 = new Dictionary<string, PackageBundle>(_packageBundleCount);
Manifest.BundleDic3 = new Dictionary<string, PackageBundle>(_packageBundleCount);
_progressTotalValue = _packageBundleCount; _progressTotalValue = _packageBundleCount;
_steps = ESteps.DeserializeBundleList; _steps = ESteps.DeserializeBundleList;
} }
@ -210,10 +212,11 @@ namespace YooAsset
packageBundle.ParseBundle(Manifest.PackageName, Manifest.OutputNameStyle); packageBundle.ParseBundle(Manifest.PackageName, Manifest.OutputNameStyle);
Manifest.BundleDic.Add(packageBundle.BundleName, packageBundle); Manifest.BundleDic.Add(packageBundle.BundleName, packageBundle);
Manifest.BundleDic2.Add(packageBundle.FileName, packageBundle);
// 注意原始文件可能存在相同的CacheGUID // 注意原始文件可能存在相同的CacheGUID
if (Manifest.CacheGUIDs.Contains(packageBundle.CacheGUID) == false) if (Manifest.BundleDic3.ContainsKey(packageBundle.CacheGUID) == false)
Manifest.CacheGUIDs.Add(packageBundle.CacheGUID); Manifest.BundleDic3.Add(packageBundle.CacheGUID, packageBundle);
_packageBundleCount--; _packageBundleCount--;
Progress = 1f - _packageBundleCount / _progressTotalValue; Progress = 1f - _packageBundleCount / _progressTotalValue;

View File

@ -64,6 +64,18 @@ namespace YooAsset
[NonSerialized] [NonSerialized]
public Dictionary<string, PackageBundle> BundleDic; public Dictionary<string, PackageBundle> BundleDic;
/// <summary>
/// 资源包集合提供FileName获取PackageBundle
/// </summary>
[NonSerialized]
public Dictionary<string, PackageBundle> BundleDic2;
/// <summary>
/// 资源包集合提供CacheGUID获取PackageBundle
/// </summary>
[NonSerialized]
public Dictionary<string, PackageBundle> BundleDic3;
/// <summary> /// <summary>
/// 资源映射集合提供AssetPath获取PackageAsset /// 资源映射集合提供AssetPath获取PackageAsset
/// </summary> /// </summary>
@ -82,12 +94,6 @@ namespace YooAsset
[NonSerialized] [NonSerialized]
public Dictionary<string, string> AssetPathMapping2; public Dictionary<string, string> AssetPathMapping2;
/// <summary>
/// 该资源清单所有文件的缓存GUID集合
/// </summary>
[NonSerialized]
public HashSet<string> CacheGUIDs = new HashSet<string>();
/// <summary> /// <summary>
/// 尝试映射为资源路径 /// 尝试映射为资源路径
@ -192,12 +198,28 @@ namespace YooAsset
return BundleDic.TryGetValue(bundleName, out result); return BundleDic.TryGetValue(bundleName, out result);
} }
/// <summary>
/// 尝试获取包裹的资源包
/// </summary>
public bool TryGetPackageBundleByFileName(string fileName, out PackageBundle result)
{
return BundleDic2.TryGetValue(fileName, out result);
}
/// <summary>
/// 尝试获取包裹的资源包
/// </summary>
public bool TryGetPackageBundleByCacheGUID(string cacheGUID, out PackageBundle result)
{
return BundleDic3.TryGetValue(cacheGUID, out result);
}
/// <summary> /// <summary>
/// 是否包含资源文件 /// 是否包含资源文件
/// </summary> /// </summary>
public bool IsIncludeBundleFile(string cacheGUID) public bool IsIncludeBundleFile(string cacheGUID)
{ {
return CacheGUIDs.Contains(cacheGUID); return BundleDic3.ContainsKey(cacheGUID);
} }
/// <summary> /// <summary>

View File

@ -74,6 +74,11 @@ namespace YooAsset
{ {
return ResourceUnpackerOperation.CreateEmptyUnpacker(upackingMaxNumber, failedTryAgain, timeout); return ResourceUnpackerOperation.CreateEmptyUnpacker(upackingMaxNumber, failedTryAgain, timeout);
} }
ResourceImporterOperation IPlayModeServices.CreateResourceImporterByFilePaths(string[] filePaths, int importerMaxNumber, int failedTryAgain, int timeout)
{
return ResourceImporterOperation.CreateEmptyImporter(importerMaxNumber, failedTryAgain, timeout);
}
#endregion #endregion
#region IBundleServices接口 #region IBundleServices接口

View File

@ -284,6 +284,39 @@ namespace YooAsset
return ManifestTools.ConvertToUnpackInfos(downloadList); return ManifestTools.ConvertToUnpackInfos(downloadList);
} }
ResourceImporterOperation IPlayModeServices.CreateResourceImporterByFilePaths(string[] filePaths, int importerMaxNumber, int failedTryAgain, int timeout)
{
List<BundleInfo> importerList = GetImporterListByFilePaths(_activeManifest, filePaths);
var operation = new ResourceImporterOperation(importerList, importerMaxNumber, failedTryAgain, timeout);
return operation;
}
private List<BundleInfo> GetImporterListByFilePaths(PackageManifest manifest, string[] filePaths)
{
List<BundleInfo> result = new List<BundleInfo>();
foreach (var filePath in filePaths)
{
string fileName = System.IO.Path.GetFileName(filePath);
if (manifest.TryGetPackageBundleByFileName(fileName, out PackageBundle packageBundle))
{
// 忽略缓存文件
if (IsCachedPackageBundle(packageBundle))
continue;
// 忽略APP资源
if (IsBuildinPackageBundle(packageBundle))
continue;
var bundleInfo = ManifestTools.ConvertToImportInfo(packageBundle, filePath);
result.Add(bundleInfo);
}
else
{
YooLogger.Warning($"Not found package bundle, importer file path : {filePath}");
}
}
return result;
}
#endregion #endregion
#region IBundleServices接口 #region IBundleServices接口

View File

@ -117,6 +117,35 @@ namespace YooAsset
return ManifestTools.ConvertToUnpackInfos(downloadList); return ManifestTools.ConvertToUnpackInfos(downloadList);
} }
ResourceImporterOperation IPlayModeServices.CreateResourceImporterByFilePaths(string[] filePaths, int importerMaxNumber, int failedTryAgain, int timeout)
{
List<BundleInfo> importerList = GetImporterListByFilePaths(_activeManifest, filePaths);
var operation = new ResourceImporterOperation(importerList, importerMaxNumber, failedTryAgain, timeout);
return operation;
}
private List<BundleInfo> GetImporterListByFilePaths(PackageManifest manifest, string[] filePaths)
{
List<BundleInfo> result = new List<BundleInfo>();
foreach (var filePath in filePaths)
{
string fileName = System.IO.Path.GetFileName(filePath);
if (manifest.TryGetPackageBundleByFileName(fileName, out PackageBundle packageBundle))
{
// 忽略缓存文件
if (IsCachedPackageBundle(packageBundle))
continue;
var bundleInfo = ManifestTools.ConvertToImportInfo(packageBundle, filePath);
result.Add(bundleInfo);
}
else
{
YooLogger.Warning($"Not found package bundle, importer file path : {filePath}");
}
}
return result;
}
#endregion #endregion
#region IBundleServices接口 #region IBundleServices接口

View File

@ -199,6 +199,11 @@ namespace YooAsset
{ {
return ResourceUnpackerOperation.CreateEmptyUnpacker(upackingMaxNumber, failedTryAgain, timeout); return ResourceUnpackerOperation.CreateEmptyUnpacker(upackingMaxNumber, failedTryAgain, timeout);
} }
ResourceImporterOperation IPlayModeServices.CreateResourceImporterByFilePaths(string[] filePaths, int importerMaxNumber, int failedTryAgain, int timeout)
{
return ResourceImporterOperation.CreateEmptyImporter(importerMaxNumber, failedTryAgain, timeout);
}
#endregion #endregion
#region IBundleServices接口 #region IBundleServices接口

View File

@ -299,6 +299,17 @@ namespace YooAsset
return operation; return operation;
} }
/// <summary>
/// 获取指定版本的缓存信息
/// </summary>
public GetAllCacheFileInfosOperation GetAllCacheFileInfosAsync(string packageVersion, int timeout = 60)
{
DebugCheckInitialize();
var operation = new GetAllCacheFileInfosOperation(PackageName);
OperationSystem.StartOperation(operation);
return operation;
}
/// <summary> /// <summary>
/// 获取本地包裹的版本信息 /// 获取本地包裹的版本信息
/// </summary> /// </summary>
@ -335,7 +346,7 @@ namespace YooAsset
{ {
DebugCheckInitialize(); DebugCheckInitialize();
var persistent = PersistentTools.GetPersistent(PackageName); var persistent = PersistentTools.GetPersistent(PackageName);
return persistent.BuildinRoot; return persistent.BuildinPackageRoot;
} }
/// <summary> /// <summary>
@ -345,7 +356,17 @@ namespace YooAsset
{ {
DebugCheckInitialize(); DebugCheckInitialize();
var persistent = PersistentTools.GetPersistent(PackageName); var persistent = PersistentTools.GetPersistent(PackageName);
return persistent.SandboxRoot; return persistent.SandboxPackageRoot;
}
/// <summary>
/// 获取包裹的沙盒文件AB文件的缓存目录
/// </summary>
public string GetPackageSandboxCacheBundleRootDirectory()
{
DebugCheckInitialize();
var persistent = PersistentTools.GetPersistent(PackageName);
return persistent.SandboxCacheBundleFilesRoot;
} }
/// <summary> /// <summary>
@ -1026,6 +1047,21 @@ namespace YooAsset
} }
#endregion #endregion
#region 资源导入
/// <summary>
/// 创建资源导入器
/// 注意:资源文件名称必须和资源服务器部署的文件名称一致!
/// </summary>
/// <param name="filePaths">资源路径列表</param>
/// <param name="importerMaxNumber">同时导入的最大文件数</param>
/// <param name="failedTryAgain">导入失败的重试次数</param>
public ResourceImporterOperation CreateResourceImporter(string[] filePaths, int importerMaxNumber, int failedTryAgain)
{
DebugCheckInitialize();
return _playModeServices.CreateResourceImporterByFilePaths(filePaths, importerMaxNumber, failedTryAgain, int.MaxValue);
}
#endregion
#region 内部方法 #region 内部方法
/// <summary> /// <summary>
/// 是否包含资源文件 /// 是否包含资源文件

View File

@ -36,5 +36,8 @@ namespace YooAsset
// 解压相关 // 解压相关
ResourceUnpackerOperation CreateResourceUnpackerByAll(int upackingMaxNumber, int failedTryAgain, int timeout); ResourceUnpackerOperation CreateResourceUnpackerByAll(int upackingMaxNumber, int failedTryAgain, int timeout);
ResourceUnpackerOperation CreateResourceUnpackerByTags(string[] tags, int upackingMaxNumber, int failedTryAgain, int timeout); ResourceUnpackerOperation CreateResourceUnpackerByTags(string[] tags, int upackingMaxNumber, int failedTryAgain, int timeout);
// 导入相关
ResourceImporterOperation CreateResourceImporterByFilePaths(string[] filePaths, int importerMaxNumber, int failedTryAgain, int timeout);
} }
} }