This commit is contained in:
陈思海 2025-09-10 16:04:39 +08:00
parent f4406e86a7
commit 056a377e2a
173 changed files with 3741 additions and 1317 deletions

View File

@ -2,6 +2,104 @@
All notable changes to this package will be documented in this file. All notable changes to this package will be documented in this file.
## [2.3.15] - 2025-09-09
**重要**:升级了资源清单版本,不兼容老版本。建议重新提审安装包。
### Improvements
- 重构了UniTask扩展库的目录结构和说明文档。
- 重构了内置文件系统类的加载和拷贝逻辑,解决在一些特殊机型上遇到的偶发性拷贝失败问题。
- 增加了生成内置清单文件的窗口工具详情见扩展工程里CreateBuildinCatalog目录。
- 优化了异步操作系统的繁忙检测机制。
- (#621) 资源配置页面可以展示DependCollector和StaticCollector包含的文件列表内容。
- (#627) 优化了资源清单部分字段类型CRC字段从字符串类型调整为整形可以降低清单尺寸。
### Fixed
- 修复了构建页面扩展类缺少指定属性报错的问题。
- (#611) 修复了资源扫描器配置页面,修改备注信息后会丢失焦点的问题。
- (#622) 修复了纯鸿蒙系统读取内置加密文件失败的问题。
- (#620) 修复了LINUX系统URL地址转换失败的问题。
- (#631) 修复了NET 4.x程序集库Math.Clamp导致的编译错误。
### Added
- 新增了支持支付宝小游戏的文件系统扩展类。
- 新增了支持Taptap小游戏的文件系统扩展类。
- 新增了资源系统初始化参数UseWeakReferenceHandle
目前处于预览版可以在引擎设置页面开启宏YOOASSET_EXPERIMENTAL
```csharp
/// <summary>
/// 启用弱引用资源句柄
/// </summary>
public bool UseWeakReferenceHandle = false;
```
- 内置文件系统和缓存文件系统新增初始化参数FILE_VERIFY_MAX_CONCURRENCY
```csharp
/// <summary>
/// 自定义参数:初始化的时候缓存文件校验最大并发数
/// </summary>
public int FileVerifyMaxConcurrency { private set; get; }
```
- (#623) 内置构建管线新增构建参数StripUnityVersion
```csharp
/// <summary>
/// 从文件头里剥离Unity版本信息
/// </summary>
public bool StripUnityVersion = false;
```
- 可编程构建管线新增构建参数TrackSpriteAtlasDependencies
```csharp
/// <summary>
/// 自动建立资源对象对图集的依赖关系
/// </summary>
public bool TrackSpriteAtlasDependencies = false;
```
- (#617) 新增资源收集配置参数SupportExtensionless
在不需要模糊加载模式的前提下,开启此选项,可以降低运行时内存大小。
```csharp
public class CollectCommand
{
/// <summary>
/// 支持无后缀名的资源定位地址
/// </summary>
public bool SupportExtensionless { set; get; }
}
```
- (#625) 异步操作系统类新增监听方法。
```csharp
class OperationSystem
{
/// <summary>
/// 监听任务开始
/// </summary>
public static void RegisterStartCallback(Action<string, AsyncOperationBase> callback);
/// <summary>
/// 监听任务结束
/// </summary>
public static void RegisterFinishCallback(Action<string, AsyncOperationBase> callback);
}
```
## [2.3.14] - 2025-07-23 ## [2.3.14] - 2025-07-23
**重要****所有下载相关的超时参数timeout已更新判定逻辑** **重要****所有下载相关的超时参数timeout已更新判定逻辑**

View File

@ -294,6 +294,11 @@ namespace YooAsset.Editor
_scannerListView.itemsSource = filterItems; _scannerListView.itemsSource = filterItems;
_scannerListView.Rebuild(); _scannerListView.Rebuild();
} }
if (_lastModifyScannerIndex >= 0 && _lastModifyScannerIndex < _scannerListView.itemsSource.Count)
{
_scannerListView.selectedIndex = _lastModifyScannerIndex;
}
} }
private List<AssetArtScanner> FilterScanners() private List<AssetArtScanner> FilterScanners()
{ {

View File

@ -77,6 +77,12 @@ namespace YooAsset.Editor
foreach (var classType in viewerClassTypes) foreach (var classType in viewerClassTypes)
{ {
var buildPipelineAttribute = EditorTools.GetAttribute<BuildPipelineAttribute>(classType); var buildPipelineAttribute = EditorTools.GetAttribute<BuildPipelineAttribute>(classType);
if (buildPipelineAttribute == null)
{
Debug.LogWarning($"The class {classType.FullName} need attribute {nameof(BuildPipelineAttribute)}");
continue;
}
string pipelineName = buildPipelineAttribute.PipelineName; string pipelineName = buildPipelineAttribute.PipelineName;
if (_viewClassDic.ContainsKey(pipelineName)) if (_viewClassDic.ContainsKey(pipelineName))
{ {

View File

@ -27,7 +27,7 @@ namespace YooAsset.Editor
/// <summary> /// <summary>
/// 文件哈希值 /// 文件哈希值
/// </summary> /// </summary>
public string PackageFileCRC { set; get; } public uint PackageFileCRC { set; get; }
/// <summary> /// <summary>
/// 文件哈希值 /// 文件哈希值

View File

@ -13,6 +13,11 @@ namespace YooAsset.Editor
/// </summary> /// </summary>
private readonly Dictionary<string, BuildBundleInfo> _bundleInfoDic = new Dictionary<string, BuildBundleInfo>(10000); private readonly Dictionary<string, BuildBundleInfo> _bundleInfoDic = new Dictionary<string, BuildBundleInfo>(10000);
/// <summary>
/// 图集资源集合
/// </summary>
public readonly List<BuildAssetInfo> SpriteAtlasAssetList = new List<BuildAssetInfo>(10000);
/// <summary> /// <summary>
/// 未被依赖的资源列表 /// 未被依赖的资源列表
/// </summary> /// </summary>
@ -60,6 +65,12 @@ namespace YooAsset.Editor
newBundleInfo.PackAsset(assetInfo); newBundleInfo.PackAsset(assetInfo);
_bundleInfoDic.Add(bundleName, newBundleInfo); _bundleInfoDic.Add(bundleName, newBundleInfo);
} }
// 统计所有的精灵图集
if (assetInfo.AssetInfo.IsSpriteAtlas())
{
SpriteAtlasAssetList.Add(assetInfo);
}
} }
/// <summary> /// <summary>

View File

@ -2,6 +2,7 @@
using System.Linq; using System.Linq;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEditor;
namespace YooAsset.Editor namespace YooAsset.Editor
{ {
@ -32,6 +33,7 @@ namespace YooAsset.Editor
PackageManifest manifest = new PackageManifest(); PackageManifest manifest = new PackageManifest();
manifest.FileVersion = ManifestDefine.FileVersion; manifest.FileVersion = ManifestDefine.FileVersion;
manifest.EnableAddressable = buildMapContext.Command.EnableAddressable; manifest.EnableAddressable = buildMapContext.Command.EnableAddressable;
manifest.SupportExtensionless = buildMapContext.Command.SupportExtensionless;
manifest.LocationToLower = buildMapContext.Command.LocationToLower; manifest.LocationToLower = buildMapContext.Command.LocationToLower;
manifest.IncludeAssetGUID = buildMapContext.Command.IncludeAssetGUID; manifest.IncludeAssetGUID = buildMapContext.Command.IncludeAssetGUID;
manifest.OutputNameStyle = (int)buildParameters.FileNameStyle; manifest.OutputNameStyle = (int)buildParameters.FileNameStyle;
@ -300,18 +302,40 @@ namespace YooAsset.Editor
#region YOOASSET_LEGACY_DEPENDENCY #region YOOASSET_LEGACY_DEPENDENCY
private void ProcessBuiltinBundleDependency(BuildContext context, PackageManifest manifest) private void ProcessBuiltinBundleDependency(BuildContext context, PackageManifest manifest)
{ {
// 注意:初始化资源清单建立引用关系
ManifestTools.InitManifest(manifest);
// 注意:如果是可编程构建管线,需要补充内置资源包 // 注意:如果是可编程构建管线,需要补充内置资源包
// 注意:该步骤依赖前面的操作! // 注意:该步骤依赖前面的操作!
var buildResultContext = context.TryGetContextObject<TaskBuilding_SBP.BuildResultContext>(); var buildResultContext = context.TryGetContextObject<TaskBuilding_SBP.BuildResultContext>();
if (buildResultContext != null) if (buildResultContext != null)
{ {
// 注意:初始化资源清单建立引用关系 ProcessBuiltinBundleReference(manifest, buildResultContext.BuiltinShadersBundleName);
ManifestTools.InitManifest(manifest); ProcessBuiltinBundleReference(manifest, buildResultContext.MonoScriptsBundleName);
ProcessBuiltinBundleReference(context, manifest, buildResultContext.BuiltinShadersBundleName);
ProcessBuiltinBundleReference(context, manifest, buildResultContext.MonoScriptsBundleName); var buildParametersContext = context.TryGetContextObject<BuildParametersContext>();
var buildParameters = buildParametersContext.Parameters;
if (buildParameters is ScriptableBuildParameters scriptableBuildParameters)
{
if (scriptableBuildParameters.TrackSpriteAtlasDependencies)
{
// 注意:检测是否开启图集模式
// 说明:需要记录主资源对象对图集的依赖关系!
if (EditorSettings.spritePackerMode != SpritePackerMode.Disabled)
{
var buildMapContext = context.GetContextObject<BuildMapContext>();
foreach (var spriteAtlasAsset in buildMapContext.SpriteAtlasAssetList)
{
string spriteAtlasBundleName = spriteAtlasAsset.BundleName;
ProcessBuiltinBundleReference(manifest, spriteAtlasBundleName);
}
}
}
}
} }
} }
private void ProcessBuiltinBundleReference(BuildContext context, PackageManifest manifest, string builtinBundleName) private void ProcessBuiltinBundleReference(PackageManifest manifest, string builtinBundleName)
{ {
if (string.IsNullOrEmpty(builtinBundleName)) if (string.IsNullOrEmpty(builtinBundleName))
return; return;

View File

@ -32,6 +32,7 @@ namespace YooAsset.Editor
// 收集器配置 // 收集器配置
buildReport.Summary.UniqueBundleName = buildMapContext.Command.UniqueBundleName; buildReport.Summary.UniqueBundleName = buildMapContext.Command.UniqueBundleName;
buildReport.Summary.EnableAddressable = buildMapContext.Command.EnableAddressable; buildReport.Summary.EnableAddressable = buildMapContext.Command.EnableAddressable;
buildReport.Summary.SupportExtensionless = buildMapContext.Command.SupportExtensionless;
buildReport.Summary.LocationToLower = buildMapContext.Command.LocationToLower; buildReport.Summary.LocationToLower = buildMapContext.Command.LocationToLower;
buildReport.Summary.IncludeAssetGUID = buildMapContext.Command.IncludeAssetGUID; buildReport.Summary.IncludeAssetGUID = buildMapContext.Command.IncludeAssetGUID;
buildReport.Summary.AutoCollectShaders = buildMapContext.Command.AutoCollectShaders; buildReport.Summary.AutoCollectShaders = buildMapContext.Command.AutoCollectShaders;

View File

@ -63,7 +63,7 @@ namespace YooAsset.Editor
protected abstract string GetUnityHash(BuildBundleInfo bundleInfo, BuildContext context); protected abstract string GetUnityHash(BuildBundleInfo bundleInfo, BuildContext context);
protected abstract uint GetUnityCRC(BuildBundleInfo bundleInfo, BuildContext context); protected abstract uint GetUnityCRC(BuildBundleInfo bundleInfo, BuildContext context);
protected abstract string GetBundleFileHash(BuildBundleInfo bundleInfo, BuildParametersContext buildParametersContext); protected abstract string GetBundleFileHash(BuildBundleInfo bundleInfo, BuildParametersContext buildParametersContext);
protected abstract string GetBundleFileCRC(BuildBundleInfo bundleInfo, BuildParametersContext buildParametersContext); protected abstract uint GetBundleFileCRC(BuildBundleInfo bundleInfo, BuildParametersContext buildParametersContext);
protected abstract long GetBundleFileSize(BuildBundleInfo bundleInfo, BuildParametersContext buildParametersContext); protected abstract long GetBundleFileSize(BuildBundleInfo bundleInfo, BuildParametersContext buildParametersContext);
} }
} }

View File

@ -45,10 +45,10 @@ namespace YooAsset.Editor
string filePath = bundleInfo.PackageSourceFilePath; string filePath = bundleInfo.PackageSourceFilePath;
return HashUtility.FileMD5(filePath); return HashUtility.FileMD5(filePath);
} }
protected override string GetBundleFileCRC(BuildBundleInfo bundleInfo, BuildParametersContext buildParametersContext) protected override uint GetBundleFileCRC(BuildBundleInfo bundleInfo, BuildParametersContext buildParametersContext)
{ {
string filePath = bundleInfo.PackageSourceFilePath; string filePath = bundleInfo.PackageSourceFilePath;
return HashUtility.FileCRC32(filePath); return HashUtility.FileCRC32Value(filePath);
} }
protected override long GetBundleFileSize(BuildBundleInfo bundleInfo, BuildParametersContext buildParametersContext) protected override long GetBundleFileSize(BuildBundleInfo bundleInfo, BuildParametersContext buildParametersContext)
{ {

View File

@ -12,6 +12,11 @@ namespace YooAsset.Editor
/// </summary> /// </summary>
public ECompressOption CompressOption = ECompressOption.Uncompressed; public ECompressOption CompressOption = ECompressOption.Uncompressed;
/// <summary>
/// 从文件头里剥离Unity版本信息
/// </summary>
public bool StripUnityVersion = false;
/// <summary> /// <summary>
/// 禁止写入类型树结构(可以降低包体和内存并提高加载效率) /// 禁止写入类型树结构(可以降低包体和内存并提高加载效率)
/// </summary> /// </summary>
@ -41,6 +46,8 @@ namespace YooAsset.Editor
if (ClearBuildCacheFiles) if (ClearBuildCacheFiles)
opt |= BuildAssetBundleOptions.ForceRebuildAssetBundle; //Force rebuild the asset bundles opt |= BuildAssetBundleOptions.ForceRebuildAssetBundle; //Force rebuild the asset bundles
if (StripUnityVersion)
opt |= BuildAssetBundleOptions.AssetBundleStripUnityVersion; //Removes the Unity Version number in the Archive File & Serialized File headers
if (DisableWriteTypeTree) if (DisableWriteTypeTree)
opt |= BuildAssetBundleOptions.DisableWriteTypeTree; //Do not include type information within the asset bundle (don't write type tree). opt |= BuildAssetBundleOptions.DisableWriteTypeTree; //Do not include type information within the asset bundle (don't write type tree).
if (IgnoreTypeTreeChanges) if (IgnoreTypeTreeChanges)

View File

@ -24,9 +24,9 @@ namespace YooAsset.Editor
string filePath = bundleInfo.PackageSourceFilePath; string filePath = bundleInfo.PackageSourceFilePath;
return GetFilePathTempHash(filePath); return GetFilePathTempHash(filePath);
} }
protected override string GetBundleFileCRC(BuildBundleInfo bundleInfo, BuildParametersContext buildParametersContext) protected override uint GetBundleFileCRC(BuildBundleInfo bundleInfo, BuildParametersContext buildParametersContext)
{ {
return "00000000"; //8位 return 0;
} }
protected override long GetBundleFileSize(BuildBundleInfo bundleInfo, BuildParametersContext buildParametersContext) protected override long GetBundleFileSize(BuildBundleInfo bundleInfo, BuildParametersContext buildParametersContext)
{ {

View File

@ -27,10 +27,10 @@ namespace YooAsset.Editor
string filePath = bundleInfo.PackageSourceFilePath; string filePath = bundleInfo.PackageSourceFilePath;
return HashUtility.FileMD5(filePath); return HashUtility.FileMD5(filePath);
} }
protected override string GetBundleFileCRC(BuildBundleInfo bundleInfo, BuildParametersContext buildParametersContext) protected override uint GetBundleFileCRC(BuildBundleInfo bundleInfo, BuildParametersContext buildParametersContext)
{ {
string filePath = bundleInfo.PackageSourceFilePath; string filePath = bundleInfo.PackageSourceFilePath;
return HashUtility.FileCRC32(filePath); return HashUtility.FileCRC32Value(filePath);
} }
protected override long GetBundleFileSize(BuildBundleInfo bundleInfo, BuildParametersContext buildParametersContext) protected override long GetBundleFileSize(BuildBundleInfo bundleInfo, BuildParametersContext buildParametersContext)
{ {

View File

@ -45,10 +45,10 @@ namespace YooAsset.Editor
string filePath = bundleInfo.PackageSourceFilePath; string filePath = bundleInfo.PackageSourceFilePath;
return HashUtility.FileMD5(filePath); return HashUtility.FileMD5(filePath);
} }
protected override string GetBundleFileCRC(BuildBundleInfo bundleInfo, BuildParametersContext buildParametersContext) protected override uint GetBundleFileCRC(BuildBundleInfo bundleInfo, BuildParametersContext buildParametersContext)
{ {
string filePath = bundleInfo.PackageSourceFilePath; string filePath = bundleInfo.PackageSourceFilePath;
return HashUtility.FileCRC32(filePath); return HashUtility.FileCRC32Value(filePath);
} }
protected override long GetBundleFileSize(BuildBundleInfo bundleInfo, BuildParametersContext buildParametersContext) protected override long GetBundleFileSize(BuildBundleInfo bundleInfo, BuildParametersContext buildParametersContext)
{ {

View File

@ -15,7 +15,7 @@ namespace YooAsset.Editor
public ECompressOption CompressOption = ECompressOption.Uncompressed; public ECompressOption CompressOption = ECompressOption.Uncompressed;
/// <summary> /// <summary>
/// 从AssetBundle文件头里剥离Unity版本信息 /// 从文件头里剥离Unity版本信息
/// </summary> /// </summary>
public bool StripUnityVersion = false; public bool StripUnityVersion = false;
@ -25,10 +25,15 @@ namespace YooAsset.Editor
public bool DisableWriteTypeTree = false; public bool DisableWriteTypeTree = false;
/// <summary> /// <summary>
/// 忽略类型树变化 /// 忽略类型树变化(无效参数)
/// </summary> /// </summary>
public bool IgnoreTypeTreeChanges = true; public bool IgnoreTypeTreeChanges = true;
/// <summary>
/// 自动建立资源对象对图集的依赖关系
/// </summary>
public bool TrackSpriteAtlasDependencies = false;
/// <summary> /// <summary>
/// 生成代码防裁剪配置 /// 生成代码防裁剪配置
@ -76,10 +81,9 @@ namespace YooAsset.Editor
throw new System.NotImplementedException(CompressOption.ToString()); throw new System.NotImplementedException(CompressOption.ToString());
if (StripUnityVersion) if (StripUnityVersion)
buildParams.ContentBuildFlags |= UnityEditor.Build.Content.ContentBuildFlags.StripUnityVersion; buildParams.ContentBuildFlags |= UnityEditor.Build.Content.ContentBuildFlags.StripUnityVersion; // Build Flag to indicate the Unity Version should not be written to the serialized file.
if (DisableWriteTypeTree) if (DisableWriteTypeTree)
buildParams.ContentBuildFlags |= UnityEditor.Build.Content.ContentBuildFlags.DisableWriteTypeTree; buildParams.ContentBuildFlags |= UnityEditor.Build.Content.ContentBuildFlags.DisableWriteTypeTree; //Do not include type information within the built content.
buildParams.UseCache = true; buildParams.UseCache = true;
buildParams.CacheServerHost = CacheServerHost; buildParams.CacheServerHost = CacheServerHost;

View File

@ -104,7 +104,6 @@ namespace YooAsset.Editor
var compressOption = AssetBundleBuilderSetting.GetPackageCompressOption(PackageName, PipelineName); var compressOption = AssetBundleBuilderSetting.GetPackageCompressOption(PackageName, PipelineName);
var clearBuildCache = AssetBundleBuilderSetting.GetPackageClearBuildCache(PackageName, PipelineName); var clearBuildCache = AssetBundleBuilderSetting.GetPackageClearBuildCache(PackageName, PipelineName);
var useAssetDependencyDB = AssetBundleBuilderSetting.GetPackageUseAssetDependencyDB(PackageName, PipelineName); var useAssetDependencyDB = AssetBundleBuilderSetting.GetPackageUseAssetDependencyDB(PackageName, PipelineName);
var builtinShaderBundleName = GetBuiltinShaderBundleName();
ScriptableBuildParameters buildParameters = new ScriptableBuildParameters(); ScriptableBuildParameters buildParameters = new ScriptableBuildParameters();
buildParameters.BuildOutputRoot = AssetBundleBuilderHelper.GetDefaultBuildOutputRoot(); buildParameters.BuildOutputRoot = AssetBundleBuilderHelper.GetDefaultBuildOutputRoot();
@ -122,10 +121,10 @@ namespace YooAsset.Editor
buildParameters.CompressOption = compressOption; buildParameters.CompressOption = compressOption;
buildParameters.ClearBuildCacheFiles = clearBuildCache; buildParameters.ClearBuildCacheFiles = clearBuildCache;
buildParameters.UseAssetDependencyDB = useAssetDependencyDB; buildParameters.UseAssetDependencyDB = useAssetDependencyDB;
buildParameters.BuiltinShadersBundleName = builtinShaderBundleName;
buildParameters.EncryptionServices = CreateEncryptionServicesInstance(); buildParameters.EncryptionServices = CreateEncryptionServicesInstance();
buildParameters.ManifestProcessServices = CreateManifestProcessServicesInstance(); buildParameters.ManifestProcessServices = CreateManifestProcessServicesInstance();
buildParameters.ManifestRestoreServices = CreateManifestRestoreServicesInstance(); buildParameters.ManifestRestoreServices = CreateManifestRestoreServicesInstance();
buildParameters.BuiltinShadersBundleName = GetBuiltinShaderBundleName();
ScriptableBuildPipeline pipeline = new ScriptableBuildPipeline(); ScriptableBuildPipeline pipeline = new ScriptableBuildPipeline();
var buildResult = pipeline.Run(buildParameters, true); var buildResult = pipeline.Run(buildParameters, true);
@ -143,6 +142,16 @@ namespace YooAsset.Editor
var packRuleResult = DefaultPackRule.CreateShadersPackRuleResult(); var packRuleResult = DefaultPackRule.CreateShadersPackRuleResult();
return packRuleResult.GetBundleName(PackageName, uniqueBundleName); return packRuleResult.GetBundleName(PackageName, uniqueBundleName);
} }
/// <summary>
/// Mono脚本的资源包名称
/// </summary>
protected string GetMonoScriptsBundleName()
{
var uniqueBundleName = AssetBundleCollectorSettingData.Setting.UniqueBundleName;
var packRuleResult = DefaultPackRule.CreateMonosPackRuleResult();
return packRuleResult.GetBundleName(PackageName, uniqueBundleName);
}
} }
} }
#endif #endif

View File

@ -139,13 +139,6 @@ namespace YooAsset.Editor
/// </summary> /// </summary>
public List<CollectAssetInfo> GetAllCollectAssets(CollectCommand command, AssetBundleCollectorGroup group) public List<CollectAssetInfo> GetAllCollectAssets(CollectCommand command, AssetBundleCollectorGroup group)
{ {
// 注意:模拟构建模式下只收集主资源
if (command.SimulateBuild)
{
if (CollectorType != ECollectorType.MainAssetCollector)
return new List<CollectAssetInfo>();
}
Dictionary<string, CollectAssetInfo> result = new Dictionary<string, CollectAssetInfo>(1000); Dictionary<string, CollectAssetInfo> result = new Dictionary<string, CollectAssetInfo>(1000);
// 收集打包资源路径 // 收集打包资源路径

View File

@ -10,7 +10,7 @@ namespace YooAsset.Editor
{ {
public class AssetBundleCollectorConfig public class AssetBundleCollectorConfig
{ {
public const string ConfigVersion = "v2.1"; public const string ConfigVersion = "v2025.8.28";
public const string XmlVersion = "Version"; public const string XmlVersion = "Version";
public const string XmlCommon = "Common"; public const string XmlCommon = "Common";
@ -23,6 +23,7 @@ namespace YooAsset.Editor
public const string XmlPackageName = "PackageName"; public const string XmlPackageName = "PackageName";
public const string XmlPackageDesc = "PackageDesc"; public const string XmlPackageDesc = "PackageDesc";
public const string XmlEnableAddressable = "AutoAddressable"; public const string XmlEnableAddressable = "AutoAddressable";
public const string XmlSupportExtensionless = "SupportExtensionless";
public const string XmlLocationToLower = "LocationToLower"; public const string XmlLocationToLower = "LocationToLower";
public const string XmlIncludeAssetGUID = "IncludeAssetGUID"; public const string XmlIncludeAssetGUID = "IncludeAssetGUID";
public const string XmlIgnoreRuleName = "IgnoreRuleName"; public const string XmlIgnoreRuleName = "IgnoreRuleName";
@ -99,6 +100,7 @@ namespace YooAsset.Editor
package.PackageName = packageElement.GetAttribute(XmlPackageName); package.PackageName = packageElement.GetAttribute(XmlPackageName);
package.PackageDesc = packageElement.GetAttribute(XmlPackageDesc); package.PackageDesc = packageElement.GetAttribute(XmlPackageDesc);
package.EnableAddressable = packageElement.GetAttribute(XmlEnableAddressable) == "True" ? true : false; package.EnableAddressable = packageElement.GetAttribute(XmlEnableAddressable) == "True" ? true : false;
package.SupportExtensionless = packageElement.GetAttribute(XmlSupportExtensionless) == "True" ? true : false;
package.LocationToLower = packageElement.GetAttribute(XmlLocationToLower) == "True" ? true : false; package.LocationToLower = packageElement.GetAttribute(XmlLocationToLower) == "True" ? true : false;
package.IncludeAssetGUID = packageElement.GetAttribute(XmlIncludeAssetGUID) == "True" ? true : false; package.IncludeAssetGUID = packageElement.GetAttribute(XmlIncludeAssetGUID) == "True" ? true : false;
package.IgnoreRuleName = packageElement.GetAttribute(XmlIgnoreRuleName); package.IgnoreRuleName = packageElement.GetAttribute(XmlIgnoreRuleName);
@ -211,6 +213,7 @@ namespace YooAsset.Editor
packageElement.SetAttribute(XmlPackageName, package.PackageName); packageElement.SetAttribute(XmlPackageName, package.PackageName);
packageElement.SetAttribute(XmlPackageDesc, package.PackageDesc); packageElement.SetAttribute(XmlPackageDesc, package.PackageDesc);
packageElement.SetAttribute(XmlEnableAddressable, package.EnableAddressable.ToString()); packageElement.SetAttribute(XmlEnableAddressable, package.EnableAddressable.ToString());
packageElement.SetAttribute(XmlSupportExtensionless, package.SupportExtensionless.ToString());
packageElement.SetAttribute(XmlLocationToLower, package.LocationToLower.ToString()); packageElement.SetAttribute(XmlLocationToLower, package.LocationToLower.ToString());
packageElement.SetAttribute(XmlIncludeAssetGUID, package.IncludeAssetGUID.ToString()); packageElement.SetAttribute(XmlIncludeAssetGUID, package.IncludeAssetGUID.ToString());
packageElement.SetAttribute(XmlIgnoreRuleName, package.IgnoreRuleName); packageElement.SetAttribute(XmlIgnoreRuleName, package.IgnoreRuleName);
@ -275,6 +278,23 @@ namespace YooAsset.Editor
return UpdateXmlConfig(xmlDoc); return UpdateXmlConfig(xmlDoc);
} }
// v2.1 -> v2025.8.28
if (configVersion == "v2.1")
{
// 读取包裹配置
var packageNodeList = root.GetElementsByTagName(XmlPackage);
foreach (var packageNode in packageNodeList)
{
XmlElement packageElement = packageNode as XmlElement;
if (packageElement.HasAttribute(XmlSupportExtensionless) == false)
packageElement.SetAttribute(XmlSupportExtensionless, "True");
}
// 更新版本
root.SetAttribute(XmlVersion, "v2025.8.28");
return UpdateXmlConfig(xmlDoc);
}
return false; return false;
} }
} }

View File

@ -25,6 +25,11 @@ namespace YooAsset.Editor
/// </summary> /// </summary>
public bool EnableAddressable = false; public bool EnableAddressable = false;
/// <summary>
/// 支持无后缀名的资源定位地址
/// </summary>
public bool SupportExtensionless = true;
/// <summary> /// <summary>
/// 资源定位地址大小写不敏感 /// 资源定位地址大小写不敏感
/// </summary> /// </summary>

View File

@ -111,6 +111,7 @@ namespace YooAsset.Editor
command.UniqueBundleName = UniqueBundleName; command.UniqueBundleName = UniqueBundleName;
command.UseAssetDependencyDB = useAssetDependencyDB; command.UseAssetDependencyDB = useAssetDependencyDB;
command.EnableAddressable = package.EnableAddressable; command.EnableAddressable = package.EnableAddressable;
command.SupportExtensionless = package.SupportExtensionless;
command.LocationToLower = package.LocationToLower; command.LocationToLower = package.LocationToLower;
command.IncludeAssetGUID = package.IncludeAssetGUID; command.IncludeAssetGUID = package.IncludeAssetGUID;
command.AutoCollectShaders = package.AutoCollectShaders; command.AutoCollectShaders = package.AutoCollectShaders;

View File

@ -38,6 +38,7 @@ namespace YooAsset.Editor
private VisualElement _setting2Container; private VisualElement _setting2Container;
private Toggle _enableAddressableToogle; private Toggle _enableAddressableToogle;
private Toggle _supportExtensionlessToogle;
private Toggle _locationToLowerToogle; private Toggle _locationToLowerToogle;
private Toggle _includeAssetGUIDToogle; private Toggle _includeAssetGUIDToogle;
private Toggle _autoCollectShadersToogle; private Toggle _autoCollectShadersToogle;
@ -131,6 +132,17 @@ namespace YooAsset.Editor
RefreshWindow(); RefreshWindow();
} }
}); });
_supportExtensionlessToogle = root.Q<Toggle>("SupportExtensionless");
_supportExtensionlessToogle.RegisterValueChangedCallback(evt =>
{
var selectPackage = _packageListView.selectedItem as AssetBundleCollectorPackage;
if (selectPackage != null)
{
selectPackage.SupportExtensionless = evt.newValue;
AssetBundleCollectorSettingData.ModifyPackage(selectPackage);
RefreshWindow();
}
});
_locationToLowerToogle = root.Q<Toggle>("LocationToLower"); _locationToLowerToogle = root.Q<Toggle>("LocationToLower");
_locationToLowerToogle.RegisterValueChangedCallback(evt => _locationToLowerToogle.RegisterValueChangedCallback(evt =>
{ {
@ -487,6 +499,7 @@ namespace YooAsset.Editor
_packageSettingsButton.SetEnabled(true); _packageSettingsButton.SetEnabled(true);
_packageSettingsButton.text = $"{packageSettingName} ({selectPackage.PackageName})"; _packageSettingsButton.text = $"{packageSettingName} ({selectPackage.PackageName})";
_enableAddressableToogle.SetValueWithoutNotify(selectPackage.EnableAddressable); _enableAddressableToogle.SetValueWithoutNotify(selectPackage.EnableAddressable);
_supportExtensionlessToogle.SetValueWithoutNotify(selectPackage.SupportExtensionless);
_locationToLowerToogle.SetValueWithoutNotify(selectPackage.LocationToLower); _locationToLowerToogle.SetValueWithoutNotify(selectPackage.LocationToLower);
_includeAssetGUIDToogle.SetValueWithoutNotify(selectPackage.IncludeAssetGUID); _includeAssetGUIDToogle.SetValueWithoutNotify(selectPackage.IncludeAssetGUID);
_autoCollectShadersToogle.SetValueWithoutNotify(selectPackage.AutoCollectShaders); _autoCollectShadersToogle.SetValueWithoutNotify(selectPackage.AutoCollectShaders);
@ -831,7 +844,7 @@ namespace YooAsset.Editor
var foldout = new Foldout(); var foldout = new Foldout();
foldout.name = "Foldout1"; foldout.name = "Foldout1";
foldout.value = false; foldout.value = false;
foldout.text = "Main Assets"; foldout.text = "Assets";
elementFoldout.Add(foldout); elementFoldout.Add(foldout);
} }
@ -864,11 +877,9 @@ namespace YooAsset.Editor
var foldout = element.Q<Foldout>("Foldout1"); var foldout = element.Q<Foldout>("Foldout1");
foldout.RegisterValueChangedCallback(evt => foldout.RegisterValueChangedCallback(evt =>
{ {
if (evt.newValue) RefreshFoldoutContent(foldout, selectGroup, collector);
RefreshFoldout(foldout, selectGroup, collector);
else
foldout.Clear();
}); });
RefreshFoldoutName(foldout, collector.CollectorType);
// Remove Button // Remove Button
var removeBtn = element.Q<Button>("Button1"); var removeBtn = element.Q<Button>("Button1");
@ -885,10 +896,7 @@ namespace YooAsset.Editor
collector.CollectPath = AssetDatabase.GetAssetPath(evt.newValue); collector.CollectPath = AssetDatabase.GetAssetPath(evt.newValue);
collector.CollectorGUID = AssetDatabase.AssetPathToGUID(collector.CollectPath); collector.CollectorGUID = AssetDatabase.AssetPathToGUID(collector.CollectPath);
AssetBundleCollectorSettingData.ModifyCollector(selectGroup, collector); AssetBundleCollectorSettingData.ModifyCollector(selectGroup, collector);
if (foldout.value) RefreshFoldoutContent(foldout, selectGroup, collector);
{
RefreshFoldout(foldout, selectGroup, collector);
}
}); });
UIElementsTools.RefreshObjectFieldShowPath(objectField1); UIElementsTools.RefreshObjectFieldShowPath(objectField1);
@ -899,10 +907,7 @@ namespace YooAsset.Editor
{ {
collector.CollectorType = EditorTools.NameToEnum<ECollectorType>(evt.newValue); collector.CollectorType = EditorTools.NameToEnum<ECollectorType>(evt.newValue);
AssetBundleCollectorSettingData.ModifyCollector(selectGroup, collector); AssetBundleCollectorSettingData.ModifyCollector(selectGroup, collector);
if (foldout.value) RefreshFoldoutContent(foldout, selectGroup, collector);
{
RefreshFoldout(foldout, selectGroup, collector);
}
if (collector.CollectorType == ECollectorType.MainAssetCollector) if (collector.CollectorType == ECollectorType.MainAssetCollector)
textTags.SetEnabled(true); textTags.SetEnabled(true);
@ -921,10 +926,7 @@ namespace YooAsset.Editor
{ {
collector.AddressRuleName = evt.newValue.ClassName; collector.AddressRuleName = evt.newValue.ClassName;
AssetBundleCollectorSettingData.ModifyCollector(selectGroup, collector); AssetBundleCollectorSettingData.ModifyCollector(selectGroup, collector);
if (foldout.value) RefreshFoldoutContent(foldout, selectGroup, collector);
{
RefreshFoldout(foldout, selectGroup, collector);
}
}); });
} }
@ -937,10 +939,7 @@ namespace YooAsset.Editor
{ {
collector.PackRuleName = evt.newValue.ClassName; collector.PackRuleName = evt.newValue.ClassName;
AssetBundleCollectorSettingData.ModifyCollector(selectGroup, collector); AssetBundleCollectorSettingData.ModifyCollector(selectGroup, collector);
if (foldout.value) RefreshFoldoutContent(foldout, selectGroup, collector);
{
RefreshFoldout(foldout, selectGroup, collector);
}
}); });
// Filter Rule // Filter Rule
@ -952,10 +951,7 @@ namespace YooAsset.Editor
{ {
collector.FilterRuleName = evt.newValue.ClassName; collector.FilterRuleName = evt.newValue.ClassName;
AssetBundleCollectorSettingData.ModifyCollector(selectGroup, collector); AssetBundleCollectorSettingData.ModifyCollector(selectGroup, collector);
if (foldout.value) RefreshFoldoutContent(foldout, selectGroup, collector);
{
RefreshFoldout(foldout, selectGroup, collector);
}
}); });
// UserData // UserData
@ -976,61 +972,101 @@ namespace YooAsset.Editor
AssetBundleCollectorSettingData.ModifyCollector(selectGroup, collector); AssetBundleCollectorSettingData.ModifyCollector(selectGroup, collector);
}); });
} }
private void RefreshFoldout(Foldout foldout, AssetBundleCollectorGroup group, AssetBundleCollector collector) private void RefreshFoldoutName(Foldout foldout, ECollectorType collectorType, int elementNumber = -1)
{ {
if (collectorType == ECollectorType.MainAssetCollector)
{
if (elementNumber >= 0)
foldout.text = $"Main Assets ({elementNumber})";
else
foldout.text = $"Main Assets";
}
else if (collectorType == ECollectorType.StaticAssetCollector)
{
if (elementNumber >= 0)
foldout.text = $"Static Assets ({elementNumber})";
else
foldout.text = $"Static Assets";
}
else if (collectorType == ECollectorType.DependAssetCollector)
{
if (elementNumber >= 0)
foldout.text = $"Depend Assets ({elementNumber})";
else
foldout.text = $"Depend Assets";
}
else
{
throw new System.NotImplementedException(collectorType.ToString());
}
}
private void RefreshFoldoutContent(Foldout foldout, AssetBundleCollectorGroup group, AssetBundleCollector collector)
{
RefreshFoldoutName(foldout, collector.CollectorType);
// 折叠栏不可见
if (foldout.value == false)
{
foldout.Clear();
return;
}
// 清空旧元素 // 清空旧元素
foldout.Clear(); foldout.Clear();
// 检测配置是否有效
if (collector.IsValid() == false) if (collector.IsValid() == false)
{ {
collector.CheckConfigError(); collector.CheckConfigError();
return; return;
} }
if (collector.CollectorType == ECollectorType.MainAssetCollector || collector.CollectorType == ECollectorType.StaticAssetCollector) List<CollectAssetInfo> collectAssetInfos = null;
try
{ {
List<CollectAssetInfo> collectAssetInfos = null; IIgnoreRule ignoreRule = AssetBundleCollectorSettingData.GetIgnoreRuleInstance(_ignoreRulePopupField.value.ClassName);
string packageName = _packageNameTxt.value;
var command = new CollectCommand(packageName, ignoreRule);
command.SimulateBuild = true;
command.UniqueBundleName = _uniqueBundleNameToogle.value;
command.EnableAddressable = _enableAddressableToogle.value;
command.SupportExtensionless = _supportExtensionlessToogle.value;
command.LocationToLower = _locationToLowerToogle.value;
command.IncludeAssetGUID = _includeAssetGUIDToogle.value;
command.AutoCollectShaders = _autoCollectShadersToogle.value;
try collector.CheckConfigError();
collectAssetInfos = collector.GetAllCollectAssets(command, group);
}
catch (System.Exception e)
{
Debug.LogError(e.ToString());
}
if (collectAssetInfos != null)
{
bool showAdress = false;
if (_enableAddressableToogle.value && collector.CollectorType == ECollectorType.MainAssetCollector)
showAdress = true;
RefreshFoldoutName(foldout, collector.CollectorType, collectAssetInfos.Count);
foreach (var collectAsset in collectAssetInfos)
{ {
IIgnoreRule ignoreRule = AssetBundleCollectorSettingData.GetIgnoreRuleInstance(_ignoreRulePopupField.value.ClassName); VisualElement elementRow = new VisualElement();
string packageName = _packageNameTxt.value; elementRow.style.flexDirection = FlexDirection.Row;
var command = new CollectCommand(packageName, ignoreRule); foldout.Add(elementRow);
command.SimulateBuild = true;
command.UniqueBundleName = _uniqueBundleNameToogle.value;
command.UseAssetDependencyDB = true;
command.EnableAddressable = _enableAddressableToogle.value;
command.LocationToLower = _locationToLowerToogle.value;
command.IncludeAssetGUID = _includeAssetGUIDToogle.value;
command.AutoCollectShaders = _autoCollectShadersToogle.value;
collector.CheckConfigError(); string showInfo = collectAsset.AssetInfo.AssetPath;
collectAssetInfos = collector.GetAllCollectAssets(command, group); if (showAdress)
} showInfo = $"[{collectAsset.Address}] {collectAsset.AssetInfo.AssetPath}";
catch (System.Exception e)
{
Debug.LogError(e.ToString());
}
if (collectAssetInfos != null) var label = new Label();
{ label.text = showInfo;
foreach (var collectAsset in collectAssetInfos) label.style.width = 300;
{ label.style.marginLeft = 0;
VisualElement elementRow = new VisualElement(); label.style.flexGrow = 1;
elementRow.style.flexDirection = FlexDirection.Row; elementRow.Add(label);
foldout.Add(elementRow);
string showInfo = collectAsset.AssetInfo.AssetPath;
if (_enableAddressableToogle.value)
showInfo = $"[{collectAsset.Address}] {collectAsset.AssetInfo.AssetPath}";
var label = new Label();
label.text = showInfo;
label.style.width = 300;
label.style.marginLeft = 0;
label.style.flexGrow = 1;
elementRow.Add(label);
}
} }
} }
} }

View File

@ -19,6 +19,7 @@
<ui:Button text="Package Settings" display-tooltip-when-elided="true" name="PackageSettingsButton" /> <ui:Button text="Package Settings" display-tooltip-when-elided="true" name="PackageSettingsButton" />
<ui:VisualElement name="PublicContainer2"> <ui:VisualElement name="PublicContainer2">
<ui:Toggle label="Enable Addressable" name="EnableAddressable" style="width: 196px; -unity-text-align: middle-left;" /> <ui:Toggle label="Enable Addressable" name="EnableAddressable" style="width: 196px; -unity-text-align: middle-left;" />
<ui:Toggle label="Support Extensionless" name="SupportExtensionless" style="width: 196px; -unity-text-align: middle-left;" />
<ui:Toggle label="Location To Lower" name="LocationToLower" style="width: 196px; -unity-text-align: middle-left;" /> <ui:Toggle label="Location To Lower" name="LocationToLower" style="width: 196px; -unity-text-align: middle-left;" />
<ui:Toggle label="Include Asset GUID" name="IncludeAssetGUID" style="width: 196px; -unity-text-align: middle-left;" /> <ui:Toggle label="Include Asset GUID" name="IncludeAssetGUID" style="width: 196px; -unity-text-align: middle-left;" />
<ui:Toggle label="Auto Collect Shaders" name="AutoCollectShaders" value="true" style="width: 196px; -unity-text-align: middle-left;" /> <ui:Toggle label="Auto Collect Shaders" name="AutoCollectShaders" value="true" style="width: 196px; -unity-text-align: middle-left;" />

View File

@ -34,6 +34,11 @@ namespace YooAsset.Editor
/// </summary> /// </summary>
public bool EnableAddressable { set; get; } public bool EnableAddressable { set; get; }
/// <summary>
/// 支持无后缀名的资源定位地址
/// </summary>
public bool SupportExtensionless { set; get; }
/// <summary> /// <summary>
/// 资源定位地址大小写不敏感 /// 资源定位地址大小写不敏感
/// </summary> /// </summary>

View File

@ -17,16 +17,25 @@ namespace YooAsset.Editor
public const string RawFileExtension = "rawfile"; public const string RawFileExtension = "rawfile";
/// <summary> /// <summary>
/// Unity着色器资源包名称 /// 默认的Unity着色器资源包名称
/// </summary> /// </summary>
public const string ShadersBundleName = "unityshaders"; public const string ShadersBundleName = "unityshaders";
/// <summary>
/// 默认的Unity脚本资源包名称
/// </summary>
public const string MonosBundleName = "unitymonos";
public static PackRuleResult CreateShadersPackRuleResult() public static PackRuleResult CreateShadersPackRuleResult()
{ {
PackRuleResult result = new PackRuleResult(ShadersBundleName, AssetBundleFileExtension); PackRuleResult result = new PackRuleResult(ShadersBundleName, AssetBundleFileExtension);
return result; return result;
} }
public static PackRuleResult CreateMonosPackRuleResult()
{
PackRuleResult result = new PackRuleResult(MonosBundleName, AssetBundleFileExtension);
return result;
}
} }
/// <summary> /// <summary>

View File

@ -26,7 +26,7 @@ namespace YooAsset.Editor
/// <summary> /// <summary>
/// 文件校验码 /// 文件校验码
/// </summary> /// </summary>
public string FileCRC; public uint FileCRC;
/// <summary> /// <summary>
/// 文件大小(字节数) /// 文件大小(字节数)

View File

@ -61,6 +61,7 @@ namespace YooAsset.Editor
// 收集器配置 // 收集器配置
public bool UniqueBundleName; public bool UniqueBundleName;
public bool EnableAddressable; public bool EnableAddressable;
public bool SupportExtensionless;
public bool LocationToLower; public bool LocationToLower;
public bool IncludeAssetGUID; public bool IncludeAssetGUID;
public bool AutoCollectShaders; public bool AutoCollectShaders;

View File

@ -55,6 +55,7 @@ namespace YooAsset.Editor
BindListViewHeader("Collect Settings"); BindListViewHeader("Collect Settings");
BindListViewItem("Unique Bundle Name", $"{buildReport.Summary.UniqueBundleName}"); BindListViewItem("Unique Bundle Name", $"{buildReport.Summary.UniqueBundleName}");
BindListViewItem("Enable Addressable", $"{buildReport.Summary.EnableAddressable}"); BindListViewItem("Enable Addressable", $"{buildReport.Summary.EnableAddressable}");
BindListViewItem("Support Extensionless", $"{buildReport.Summary.SupportExtensionless}");
BindListViewItem("Location To Lower", $"{buildReport.Summary.LocationToLower}"); BindListViewItem("Location To Lower", $"{buildReport.Summary.LocationToLower}");
BindListViewItem("Include Asset GUID", $"{buildReport.Summary.IncludeAssetGUID}"); BindListViewItem("Include Asset GUID", $"{buildReport.Summary.IncludeAssetGUID}");
BindListViewItem("Auto Collect Shaders", $"{buildReport.Summary.AutoCollectShaders}"); BindListViewItem("Auto Collect Shaders", $"{buildReport.Summary.AutoCollectShaders}");

View File

@ -62,6 +62,17 @@ namespace YooAsset.Editor
return false; return false;
} }
/// <summary>
/// 是否为图集资源
/// </summary>
public bool IsSpriteAtlas()
{
if (AssetType == typeof(UnityEngine.U2D.SpriteAtlas))
return true;
else
return false;
}
public int CompareTo(AssetInfo other) public int CompareTo(AssetInfo other)
{ {
return this.AssetPath.CompareTo(other.AssetPath); return this.AssetPath.CompareTo(other.AssetPath);

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 97923f5987c469a4898718033af09e99 guid: f450f29c62aedae4390edc923f71811d
folderAsset: yes folderAsset: yes
DefaultImporter: DefaultImporter:
externalObjects: {} externalObjects: {}

View File

@ -0,0 +1,92 @@
using System.IO;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEditor;
namespace YooAsset.Editor
{
public class CreateBuildinCatalogWindow : EditorWindow
{
static CreateBuildinCatalogWindow _thisInstance;
[MenuItem("YooAsset/Tools/内置清单生成工具Catalog", false, 101)]
static void ShowWindow()
{
if (_thisInstance == null)
{
_thisInstance = EditorWindow.GetWindow(typeof(CreateBuildinCatalogWindow), false, "内置清单生成工具", true) as CreateBuildinCatalogWindow;
_thisInstance.minSize = new Vector2(800, 600);
}
_thisInstance.Show();
}
private string _directoryRoot = string.Empty;
private void OnGUI()
{
GUILayout.Space(10);
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("选择内置资源目录", GUILayout.MaxWidth(150)))
{
string resultPath = EditorUtility.OpenFolderPanel("Find", "Assets/", "StreamingAssets");
if (!string.IsNullOrEmpty(resultPath))
_directoryRoot = resultPath;
}
EditorGUILayout.LabelField(_directoryRoot);
EditorGUILayout.EndHorizontal();
if (string.IsNullOrEmpty(_directoryRoot) == false)
{
if (GUILayout.Button("生成Catalog文件", GUILayout.MaxWidth(150)))
{
CreateCatalogFile(_directoryRoot);
}
}
}
private void CreateCatalogFile(string directoryRoot)
{
// 搜索所有Package目录
List<string> packageRoots = GetPackageRoots(directoryRoot);
foreach (var packageRoot in packageRoots)
{
DirectoryInfo directoryInfo = new DirectoryInfo(packageRoot);
string packageName = directoryInfo.Name;
try
{
bool result = CatalogTools.CreateCatalogFile(null, packageName, packageRoot); //TODO 自行处理解密
if (result == false)
{
Debug.LogError($"Create package {packageName} catalog file failed ! See the detail error in console !");
}
}
catch (System.Exception ex)
{
Debug.LogError($"Create package {packageName} catalog file failed ! {ex.Message}");
}
}
}
private List<string> GetPackageRoots(string rootPath)
{
// 检查目录是否存在
if (Directory.Exists(rootPath) == false)
{
throw new DirectoryNotFoundException($"目录不存在: {rootPath}");
}
// 搜索所有 .version 文件(包含子目录)
string[] versionFiles = Directory.GetFiles(
rootPath,
"*.version",
SearchOption.AllDirectories
);
// 提取文件所在目录路径并去重
return versionFiles
.Select(file => Path.GetDirectoryName(file))
.Distinct()
.ToList();
}
}
}

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 8ac57bde14f2e1a4e9323751a7157ed7 guid: 16ab831593388974fa7e8f8c7e8199a8
MonoImporter: MonoImporter:
externalObjects: {} externalObjects: {}
serializedVersion: 2 serializedVersion: 2

View File

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

View File

@ -0,0 +1,18 @@
using System;
using System.IO;
using System.Linq;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEditor.UIElements;
using UnityEngine.UIElements;
using YooAsset.Editor;
[BuildPipelineAttribute("CustomBuildPipeline")]
internal class CustomBuildPipelineViewer : BuiltinBuildPipelineViewer
{
protected override string GetDefaultPackageVersion()
{
return "v1.0.0";
}
}

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 69f62f6b4185d06498f96aa272e9b926 guid: e721201eb2cad4e4ca207b9c99208055
MonoImporter: MonoImporter:
externalObjects: {} externalObjects: {}
serializedVersion: 2 serializedVersion: 2

View File

@ -18,7 +18,6 @@ namespace YooAsset.Editor
_thisInstance = EditorWindow.GetWindow(typeof(PackageComparatorWindow), false, "补丁包比对工具", true) as PackageComparatorWindow; _thisInstance = EditorWindow.GetWindow(typeof(PackageComparatorWindow), false, "补丁包比对工具", true) as PackageComparatorWindow;
_thisInstance.minSize = new Vector2(800, 600); _thisInstance.minSize = new Vector2(800, 600);
} }
_thisInstance.Show(); _thisInstance.Show();
} }
@ -40,7 +39,6 @@ namespace YooAsset.Editor
return; return;
_manifestPath1 = resultPath; _manifestPath1 = resultPath;
} }
EditorGUILayout.LabelField(_manifestPath1); EditorGUILayout.LabelField(_manifestPath1);
EditorGUILayout.EndHorizontal(); EditorGUILayout.EndHorizontal();
@ -53,7 +51,6 @@ namespace YooAsset.Editor
return; return;
_manifestPath2 = resultPath; _manifestPath2 = resultPath;
} }
EditorGUILayout.LabelField(_manifestPath2); EditorGUILayout.LabelField(_manifestPath2);
EditorGUILayout.EndHorizontal(); EditorGUILayout.EndHorizontal();

View File

@ -47,7 +47,10 @@ public class ShaderVariantCollectorWindow : EditorWindow
// 文件输出目录 // 文件输出目录
_collectOutputField = root.Q<TextField>("CollectOutput"); _collectOutputField = root.Q<TextField>("CollectOutput");
_collectOutputField.SetValueWithoutNotify(ShaderVariantCollectorSetting.GeFileSavePath(_currentPackageName)); _collectOutputField.SetValueWithoutNotify(ShaderVariantCollectorSetting.GeFileSavePath(_currentPackageName));
_collectOutputField.RegisterValueChangedCallback(evt => { ShaderVariantCollectorSetting.SetFileSavePath(_currentPackageName, _collectOutputField.value); }); _collectOutputField.RegisterValueChangedCallback(evt =>
{
ShaderVariantCollectorSetting.SetFileSavePath(_currentPackageName, _collectOutputField.value);
});
// 收集的包裹 // 收集的包裹
var packageContainer = root.Q("PackageContainer"); var packageContainer = root.Q("PackageContainer");
@ -57,7 +60,10 @@ public class ShaderVariantCollectorWindow : EditorWindow
_packageField = new PopupField<string>(_packageNames, defaultIndex); _packageField = new PopupField<string>(_packageNames, defaultIndex);
_packageField.label = "Package"; _packageField.label = "Package";
_packageField.style.width = 350; _packageField.style.width = 350;
_packageField.RegisterValueChangedCallback(evt => { _currentPackageName = _packageField.value; }); _packageField.RegisterValueChangedCallback(evt =>
{
_currentPackageName = _packageField.value;
});
packageContainer.Add(_packageField); packageContainer.Add(_packageField);
} }
else else
@ -79,7 +85,10 @@ public class ShaderVariantCollectorWindow : EditorWindow
_processCapacitySlider.label = $"Capacity ({_processCapacitySlider.value})"; _processCapacitySlider.label = $"Capacity ({_processCapacitySlider.value})";
}); });
#else #else
_processCapacitySlider.RegisterValueChangedCallback(evt => { ShaderVariantCollectorSetting.SetProcessCapacity(_currentPackageName, _processCapacitySlider.value); }); _processCapacitySlider.RegisterValueChangedCallback(evt =>
{
ShaderVariantCollectorSetting.SetProcessCapacity(_currentPackageName, _processCapacitySlider.value);
});
#endif #endif
_currentShaderCountField = root.Q<Label>("CurrentShaderCount"); _currentShaderCountField = root.Q<Label>("CurrentShaderCount");
@ -94,7 +103,6 @@ public class ShaderVariantCollectorWindow : EditorWindow
Debug.LogError(e.ToString()); Debug.LogError(e.ToString());
} }
} }
private void Update() private void Update()
{ {
if (_currentShaderCountField != null) if (_currentShaderCountField != null)
@ -127,10 +135,8 @@ public class ShaderVariantCollectorWindow : EditorWindow
return index; return index;
} }
} }
return 0; return 0;
} }
private List<string> GetBuildPackageNames() private List<string> GetBuildPackageNames()
{ {
List<string> result = new List<string>(); List<string> result = new List<string>();
@ -138,7 +144,6 @@ public class ShaderVariantCollectorWindow : EditorWindow
{ {
result.Add(package.PackageName); result.Add(package.PackageName);
} }
return result; return result;
} }
} }

View File

@ -37,13 +37,17 @@ namespace YooAsset
string url; string url;
// 获取对应平台的URL地址 // 获取对应平台的URL地址
// 说明:苹果不同设备上操作系统不同。
// 说明iPhone和iPod对应的是iOS系统。
// 说明iPad对应的是iPadOS系统。
// 说明AppleTV对应的是tvOS系统。
#if UNITY_EDITOR_OSX #if UNITY_EDITOR_OSX
url = StringUtility.Format("file://{0}", path); url = StringUtility.Format("file://{0}", path);
#elif UNITY_EDITOR #elif UNITY_EDITOR_WIN
url = StringUtility.Format("file:///{0}", path); url = StringUtility.Format("file:///{0}", path);
#elif UNITY_WEBGL #elif UNITY_WEBGL
url = path; url = path;
#elif UNITY_IPHONE #elif UNITY_IOS || UNITY_IPHONE
url = StringUtility.Format("file://{0}", path); url = StringUtility.Format("file://{0}", path);
#elif UNITY_ANDROID #elif UNITY_ANDROID
if (path.StartsWith("jar:file://")) if (path.StartsWith("jar:file://"))
@ -65,12 +69,17 @@ namespace YooAsset
else else
url = StringUtility.Format("file://{0}", path); url = StringUtility.Format("file://{0}", path);
} }
#elif UNITY_STANDALONE_OSX
url = new System.Uri(path).ToString(); #elif UNITY_WSA
#elif UNITY_STANDALONE || UNITY_WSA
url = StringUtility.Format("file:///{0}", path); url = StringUtility.Format("file:///{0}", path);
#elif UNITY_TVOS #elif UNITY_TVOS
url = StringUtility.Format("file:///{0}", path); url = StringUtility.Format("file:///{0}", path);
#elif UNITY_STANDALONE_OSX
url = new System.Uri(path).ToString();
#elif UNITY_STANDALONE_WIN
url = StringUtility.Format("file:///{0}", path);
#elif UNITY_STANDALONE_LINUX
url = StringUtility.Format("file:///root/{0}", path);
#else #else
throw new System.NotImplementedException(); throw new System.NotImplementedException();
#endif #endif

View File

@ -53,15 +53,20 @@ namespace YooAsset
} }
#region #region
/// <summary>
/// 自定义参数:覆盖安装缓存清理模式
/// </summary>
public EOverwriteInstallClearMode InstallClearMode { private set; get; } = EOverwriteInstallClearMode.ClearAllManifestFiles;
/// <summary> /// <summary>
/// 自定义参数:初始化的时候缓存文件校验级别 /// 自定义参数:初始化的时候缓存文件校验级别
/// </summary> /// </summary>
public EFileVerifyLevel FileVerifyLevel { private set; get; } = EFileVerifyLevel.Middle; public EFileVerifyLevel FileVerifyLevel { private set; get; } = EFileVerifyLevel.Middle;
/// <summary> /// <summary>
/// 自定义参数:覆盖安装缓存清理模式 /// 自定义参数:初始化的时候缓存文件校验最大并发数
/// </summary> /// </summary>
public EOverwriteInstallClearMode InstallClearMode { private set; get; } = EOverwriteInstallClearMode.ClearAllManifestFiles; public int FileVerifyMaxConcurrency { private set; get; } = int.MaxValue;
/// <summary> /// <summary>
/// 自定义参数:数据文件追加文件格式 /// 自定义参数:数据文件追加文件格式
@ -156,13 +161,18 @@ namespace YooAsset
public virtual void SetParameter(string name, object value) public virtual void SetParameter(string name, object value)
{ {
if (name == FileSystemParametersDefine.FILE_VERIFY_LEVEL) if (name == FileSystemParametersDefine.INSTALL_CLEAR_MODE)
{
InstallClearMode = (EOverwriteInstallClearMode)value;
}
else if (name == FileSystemParametersDefine.FILE_VERIFY_LEVEL)
{ {
FileVerifyLevel = (EFileVerifyLevel)value; FileVerifyLevel = (EFileVerifyLevel)value;
} }
else if (name == FileSystemParametersDefine.INSTALL_CLEAR_MODE) else if (name == FileSystemParametersDefine.FILE_VERIFY_MAX_CONCURRENCY)
{ {
InstallClearMode = (EOverwriteInstallClearMode)value; int convertValue = Convert.ToInt32(value);
FileVerifyMaxConcurrency = Mathf.Clamp(convertValue, 1, int.MaxValue);
} }
else if (name == FileSystemParametersDefine.APPEND_FILE_EXTENSION) else if (name == FileSystemParametersDefine.APPEND_FILE_EXTENSION)
{ {
@ -210,8 +220,9 @@ namespace YooAsset
var remoteServices = new DefaultUnpackRemoteServices(_packageRoot); var remoteServices = new DefaultUnpackRemoteServices(_packageRoot);
_unpackFileSystem = new DefaultUnpackFileSystem(); _unpackFileSystem = new DefaultUnpackFileSystem();
_unpackFileSystem.SetParameter(FileSystemParametersDefine.REMOTE_SERVICES, remoteServices); _unpackFileSystem.SetParameter(FileSystemParametersDefine.REMOTE_SERVICES, remoteServices);
_unpackFileSystem.SetParameter(FileSystemParametersDefine.FILE_VERIFY_LEVEL, FileVerifyLevel);
_unpackFileSystem.SetParameter(FileSystemParametersDefine.INSTALL_CLEAR_MODE, InstallClearMode); _unpackFileSystem.SetParameter(FileSystemParametersDefine.INSTALL_CLEAR_MODE, InstallClearMode);
_unpackFileSystem.SetParameter(FileSystemParametersDefine.FILE_VERIFY_LEVEL, FileVerifyLevel);
_unpackFileSystem.SetParameter(FileSystemParametersDefine.FILE_VERIFY_MAX_CONCURRENCY, FileVerifyMaxConcurrency);
_unpackFileSystem.SetParameter(FileSystemParametersDefine.APPEND_FILE_EXTENSION, AppendFileExtension); _unpackFileSystem.SetParameter(FileSystemParametersDefine.APPEND_FILE_EXTENSION, AppendFileExtension);
_unpackFileSystem.SetParameter(FileSystemParametersDefine.DECRYPTION_SERVICES, DecryptionServices); _unpackFileSystem.SetParameter(FileSystemParametersDefine.DECRYPTION_SERVICES, DecryptionServices);
_unpackFileSystem.SetParameter(FileSystemParametersDefine.COPY_LOCAL_FILE_SERVICES, CopyLocalFileServices); _unpackFileSystem.SetParameter(FileSystemParametersDefine.COPY_LOCAL_FILE_SERVICES, CopyLocalFileServices);
@ -335,6 +346,27 @@ namespace YooAsset
#endif #endif
} }
/// <summary>
/// 是否属于解压资源包文件
/// </summary>
protected virtual bool IsUnpackBundleFile(PackageBundle bundle)
{
if (Belong(bundle) == false)
return false;
#if UNITY_ANDROID || UNITY_OPENHARMONY
if (bundle.Encrypted)
return true;
if (bundle.BundleType == (int)EBuildBundleType.RawBundle)
return true;
return false;
#else
return false;
#endif
}
#region #region
protected string GetDefaultBuildinPackageRoot(string packageName) protected string GetDefaultBuildinPackageRoot(string packageName)
{ {
@ -370,27 +402,6 @@ namespace YooAsset
return PathUtility.Combine(_packageRoot, DefaultBuildinFileSystemDefine.BuildinCatalogBinaryFileName); return PathUtility.Combine(_packageRoot, DefaultBuildinFileSystemDefine.BuildinCatalogBinaryFileName);
} }
/// <summary>
/// 是否属于解压资源包文件
/// </summary>
protected bool IsUnpackBundleFile(PackageBundle bundle)
{
if (Belong(bundle) == false)
return false;
#if UNITY_ANDROID
if (bundle.Encrypted)
return true;
if (bundle.BundleType == (int)EBuildBundleType.RawBundle)
return true;
return false;
#else
return false;
#endif
}
/// <summary> /// <summary>
/// 记录文件信息 /// 记录文件信息
/// </summary> /// </summary>

View File

@ -8,14 +8,18 @@ namespace YooAsset
private enum ESteps private enum ESteps
{ {
None, None,
CopyBuildinManifest, LoadBuildinPackageVersion,
CopyBuildinPackageHash,
CopyBuildinPackageManifest,
InitUnpackFileSystem, InitUnpackFileSystem,
LoadCatalogFile, LoadCatalogFile,
Done, Done,
} }
private readonly DefaultBuildinFileSystem _fileSystem; private readonly DefaultBuildinFileSystem _fileSystem;
private CopyBuildinPackageManifestOperation _copyBuildinPackageManifestOp; private RequestBuildinPackageVersionOperation _requestBuildinPackageVersionOp;
private CopyBuildinFileOperation _copyBuildinHashFileOp;
private CopyBuildinFileOperation _copyBuildinManifestFileOp;
private FSInitializeFileSystemOperation _initUnpackFIleSystemOp; private FSInitializeFileSystemOperation _initUnpackFIleSystemOp;
private LoadBuildinCatalogFileOperation _loadBuildinCatalogFileOp; private LoadBuildinCatalogFileOperation _loadBuildinCatalogFileOp;
private ESteps _steps = ESteps.None; private ESteps _steps = ESteps.None;
@ -32,7 +36,7 @@ namespace YooAsset
Error = $"{nameof(DefaultBuildinFileSystem)} is not support WEBGL platform !"; Error = $"{nameof(DefaultBuildinFileSystem)} is not support WEBGL platform !";
#else #else
if (_fileSystem.CopyBuildinPackageManifest) if (_fileSystem.CopyBuildinPackageManifest)
_steps = ESteps.CopyBuildinManifest; _steps = ESteps.LoadBuildinPackageVersion;
else else
_steps = ESteps.InitUnpackFileSystem; _steps = ESteps.InitUnpackFileSystem;
#endif #endif
@ -42,20 +46,76 @@ namespace YooAsset
if (_steps == ESteps.None || _steps == ESteps.Done) if (_steps == ESteps.None || _steps == ESteps.Done)
return; return;
if (_steps == ESteps.CopyBuildinManifest) if (_steps == ESteps.LoadBuildinPackageVersion)
{ {
if (_copyBuildinPackageManifestOp == null) if (_requestBuildinPackageVersionOp == null)
{ {
_copyBuildinPackageManifestOp = new CopyBuildinPackageManifestOperation(_fileSystem); _requestBuildinPackageVersionOp = new RequestBuildinPackageVersionOperation(_fileSystem);
_copyBuildinPackageManifestOp.StartOperation(); _requestBuildinPackageVersionOp.StartOperation();
AddChildOperation(_copyBuildinPackageManifestOp); AddChildOperation(_requestBuildinPackageVersionOp);
} }
_copyBuildinPackageManifestOp.UpdateOperation(); _requestBuildinPackageVersionOp.UpdateOperation();
if (_copyBuildinPackageManifestOp.IsDone == false) if (_requestBuildinPackageVersionOp.IsDone == false)
return; return;
if (_copyBuildinPackageManifestOp.Status == EOperationStatus.Succeed) if (_requestBuildinPackageVersionOp.Status == EOperationStatus.Succeed)
{
_steps = ESteps.CopyBuildinPackageHash;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _requestBuildinPackageVersionOp.Error;
}
}
if (_steps == ESteps.CopyBuildinPackageHash)
{
if (_copyBuildinHashFileOp == null)
{
string packageVersion = _requestBuildinPackageVersionOp.PackageVersion;
string destFilePath = GetCopyPackageHashDestPath(packageVersion);
string sourceFilePath = _fileSystem.GetBuildinPackageHashFilePath(packageVersion);
_copyBuildinHashFileOp = new CopyBuildinFileOperation(sourceFilePath, destFilePath);
_copyBuildinHashFileOp.StartOperation();
AddChildOperation(_copyBuildinHashFileOp);
}
_copyBuildinHashFileOp.UpdateOperation();
if (_copyBuildinHashFileOp.IsDone == false)
return;
if (_copyBuildinHashFileOp.Status == EOperationStatus.Succeed)
{
_steps = ESteps.CopyBuildinPackageManifest;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _copyBuildinHashFileOp.Error;
}
}
if (_steps == ESteps.CopyBuildinPackageManifest)
{
if (_copyBuildinManifestFileOp == null)
{
string packageVersion = _requestBuildinPackageVersionOp.PackageVersion;
string destFilePath = GetCopyPackageManifestDestPath(packageVersion);
string sourceFilePath = _fileSystem.GetBuildinPackageManifestFilePath(packageVersion);
_copyBuildinManifestFileOp = new CopyBuildinFileOperation(sourceFilePath, destFilePath);
_copyBuildinManifestFileOp.StartOperation();
AddChildOperation(_copyBuildinManifestFileOp);
}
_copyBuildinManifestFileOp.UpdateOperation();
if (_copyBuildinManifestFileOp.IsDone == false)
return;
if (_copyBuildinManifestFileOp.Status == EOperationStatus.Succeed)
{ {
_steps = ESteps.InitUnpackFileSystem; _steps = ESteps.InitUnpackFileSystem;
} }
@ -63,7 +123,7 @@ namespace YooAsset
{ {
_steps = ESteps.Done; _steps = ESteps.Done;
Status = EOperationStatus.Failed; Status = EOperationStatus.Failed;
Error = _copyBuildinPackageManifestOp.Error; Error = _copyBuildinManifestFileOp.Error;
} }
} }
@ -116,6 +176,30 @@ namespace YooAsset
if (_loadBuildinCatalogFileOp.Status == EOperationStatus.Succeed) if (_loadBuildinCatalogFileOp.Status == EOperationStatus.Succeed)
{ {
var catalog = _loadBuildinCatalogFileOp.Catalog;
if (catalog == null)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = "Fatal error : catalog is null !";
return;
}
if (catalog.PackageName != _fileSystem.PackageName)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Catalog file package name {catalog.PackageName} cannot match the file system package name {_fileSystem.PackageName}";
return;
}
foreach (var wrapper in catalog.Wrappers)
{
var fileWrapper = new DefaultBuildinFileSystem.FileWrapper(wrapper.FileName);
_fileSystem.RecordCatalogFile(wrapper.BundleGUID, fileWrapper);
}
YooLogger.Log($"Package '{_fileSystem.PackageName}' buildin catalog files count : {catalog.Wrappers.Count}");
_steps = ESteps.Done; _steps = ESteps.Done;
Status = EOperationStatus.Succeed; Status = EOperationStatus.Succeed;
} }
@ -127,5 +211,28 @@ namespace YooAsset
} }
} }
} }
private string GetCopyManifestFileRoot()
{
string destRoot = _fileSystem.CopyBuildinPackageManifestDestRoot;
if (string.IsNullOrEmpty(destRoot))
{
string defaultCacheRoot = YooAssetSettingsData.GetYooDefaultCacheRoot();
destRoot = PathUtility.Combine(defaultCacheRoot, _fileSystem.PackageName, DefaultCacheFileSystemDefine.ManifestFilesFolderName);
}
return destRoot;
}
private string GetCopyPackageHashDestPath(string packageVersion)
{
string fileRoot = GetCopyManifestFileRoot();
string fileName = YooAssetSettingsData.GetPackageHashFileName(_fileSystem.PackageName, packageVersion);
return PathUtility.Combine(fileRoot, fileName);
}
private string GetCopyPackageManifestDestPath(string packageVersion)
{
string fileRoot = GetCopyManifestFileRoot();
string fileName = YooAssetSettingsData.GetManifestBinaryFileName(_fileSystem.PackageName, packageVersion);
return PathUtility.Combine(fileRoot, fileName);
}
} }
} }

View File

@ -0,0 +1,102 @@
using System;
using System.IO;
namespace YooAsset
{
internal class CopyBuildinFileOperation : AsyncOperationBase
{
private enum ESteps
{
None,
CheckFileExist,
TryCopyFile,
UnpackFile,
Done,
}
private UnityWebFileRequestOperation _webFileRequestOp;
private readonly string _sourceFilePath;
private readonly string _destFilePath;
private ESteps _steps = ESteps.None;
public CopyBuildinFileOperation(string sourceFilePath, string destFilePath)
{
_sourceFilePath = sourceFilePath;
_destFilePath = destFilePath;
}
internal override void InternalStart()
{
_steps = ESteps.CheckFileExist;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.CheckFileExist)
{
if (File.Exists(_destFilePath))
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}
else
{
_steps = ESteps.TryCopyFile;
}
}
if (_steps == ESteps.TryCopyFile)
{
if (File.Exists(_sourceFilePath))
{
try
{
var directory = Path.GetDirectoryName(_destFilePath);
if (Directory.Exists(directory) == false)
Directory.CreateDirectory(directory);
File.Copy(_sourceFilePath, _destFilePath, true);
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}
catch (Exception ex)
{
YooLogger.Warning($"Failed copy buildin file : {ex.Message}");
_steps = ESteps.UnpackFile;
}
}
else
{
_steps = ESteps.UnpackFile;
}
}
if (_steps == ESteps.UnpackFile)
{
if (_webFileRequestOp == null)
{
string url = DownloadSystemHelper.ConvertToWWWPath(_sourceFilePath);
_webFileRequestOp = new UnityWebFileRequestOperation(url, _destFilePath, 60);
_webFileRequestOp.StartOperation();
AddChildOperation(_webFileRequestOp);
}
_webFileRequestOp.UpdateOperation();
if (_webFileRequestOp.IsDone == false)
return;
if (_webFileRequestOp.Status == EOperationStatus.Succeed)
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _webFileRequestOp.Error;
}
}
}
}
}

View File

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

View File

@ -1,173 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
namespace YooAsset
{
internal class CopyBuildinPackageManifestOperation : AsyncOperationBase
{
private enum ESteps
{
None,
RequestPackageVersion,
CheckHashFile,
UnpackHashFile,
CheckManifestFile,
UnpackManifestFile,
Done,
}
private readonly DefaultBuildinFileSystem _fileSystem;
private RequestBuildinPackageVersionOperation _requestBuildinPackageVersionOp;
private UnityWebFileRequestOperation _hashWebFileRequestOp;
private UnityWebFileRequestOperation _manifestWebFileRequestOp;
private string _buildinPackageVersion;
private ESteps _steps = ESteps.None;
public CopyBuildinPackageManifestOperation(DefaultBuildinFileSystem fileSystem)
{
_fileSystem = fileSystem;
}
internal override void InternalStart()
{
_steps = ESteps.RequestPackageVersion;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.RequestPackageVersion)
{
if (_requestBuildinPackageVersionOp == null)
{
_requestBuildinPackageVersionOp = new RequestBuildinPackageVersionOperation(_fileSystem);
_requestBuildinPackageVersionOp.StartOperation();
AddChildOperation(_requestBuildinPackageVersionOp);
}
_requestBuildinPackageVersionOp.UpdateOperation();
if (_requestBuildinPackageVersionOp.IsDone == false)
return;
if (_requestBuildinPackageVersionOp.Status == EOperationStatus.Succeed)
{
_steps = ESteps.CheckHashFile;
_buildinPackageVersion = _requestBuildinPackageVersionOp.PackageVersion;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _requestBuildinPackageVersionOp.Error;
}
}
if (_steps == ESteps.CheckHashFile)
{
string hashFilePath = GetCopyPackageHashDestPath(_buildinPackageVersion);
if (File.Exists(hashFilePath))
{
_steps = ESteps.CheckManifestFile;
return;
}
_steps = ESteps.UnpackHashFile;
}
if (_steps == ESteps.UnpackHashFile)
{
if (_hashWebFileRequestOp == null)
{
string sourcePath = _fileSystem.GetBuildinPackageHashFilePath(_buildinPackageVersion);
string destPath = GetCopyPackageHashDestPath(_buildinPackageVersion);
string url = DownloadSystemHelper.ConvertToWWWPath(sourcePath);
_hashWebFileRequestOp = new UnityWebFileRequestOperation(url, destPath, 60);
_hashWebFileRequestOp.StartOperation();
AddChildOperation(_hashWebFileRequestOp);
}
_hashWebFileRequestOp.UpdateOperation();
if (_hashWebFileRequestOp.IsDone == false)
return;
if (_hashWebFileRequestOp.Status == EOperationStatus.Succeed)
{
_steps = ESteps.CheckManifestFile;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _hashWebFileRequestOp.Error;
}
}
if (_steps == ESteps.CheckManifestFile)
{
string manifestFilePath = GetCopyPackageManifestDestPath(_buildinPackageVersion);
if (File.Exists(manifestFilePath))
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
return;
}
_steps = ESteps.UnpackManifestFile;
}
if (_steps == ESteps.UnpackManifestFile)
{
if (_manifestWebFileRequestOp == null)
{
string sourcePath = _fileSystem.GetBuildinPackageManifestFilePath(_buildinPackageVersion);
string destPath = GetCopyPackageManifestDestPath(_buildinPackageVersion);
string url = DownloadSystemHelper.ConvertToWWWPath(sourcePath);
_manifestWebFileRequestOp = new UnityWebFileRequestOperation(url, destPath, 60);
_manifestWebFileRequestOp.StartOperation();
AddChildOperation(_manifestWebFileRequestOp);
}
_manifestWebFileRequestOp.UpdateOperation();
if (_manifestWebFileRequestOp.IsDone == false)
return;
if (_manifestWebFileRequestOp.Status == EOperationStatus.Succeed)
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _manifestWebFileRequestOp.Error;
}
}
}
private string GetCopyManifestFileRoot()
{
string destRoot = _fileSystem.CopyBuildinPackageManifestDestRoot;
if (string.IsNullOrEmpty(destRoot))
{
string defaultCacheRoot = YooAssetSettingsData.GetYooDefaultCacheRoot();
destRoot = PathUtility.Combine(defaultCacheRoot, _fileSystem.PackageName, DefaultCacheFileSystemDefine.ManifestFilesFolderName);
}
return destRoot;
}
private string GetCopyPackageHashDestPath(string packageVersion)
{
string fileRoot = GetCopyManifestFileRoot();
string fileName = YooAssetSettingsData.GetPackageHashFileName(_fileSystem.PackageName, packageVersion);
return PathUtility.Combine(fileRoot, fileName);
}
private string GetCopyPackageManifestDestPath(string packageVersion)
{
string fileRoot = GetCopyManifestFileRoot();
string fileName = YooAssetSettingsData.GetManifestBinaryFileName(_fileSystem.PackageName, packageVersion);
return PathUtility.Combine(fileRoot, fileName);
}
}
}

View File

@ -1,4 +1,5 @@
using System; using System;
using System.IO;
namespace YooAsset namespace YooAsset
{ {
@ -7,29 +8,50 @@ namespace YooAsset
private enum ESteps private enum ESteps
{ {
None, None,
RequestData, TryLoadFileData,
RequestFileData,
LoadCatalog, LoadCatalog,
Done, Done,
} }
private readonly DefaultBuildinFileSystem _fileSystem; private readonly DefaultBuildinFileSystem _fileSystem;
private UnityWebDataRequestOperation _webDataRequestOp; private UnityWebDataRequestOperation _webDataRequestOp;
private byte[] _fileData;
private ESteps _steps = ESteps.None; private ESteps _steps = ESteps.None;
/// <summary>
/// 内置资源目录
/// </summary>
public DefaultBuildinFileCatalog Catalog;
internal LoadBuildinCatalogFileOperation(DefaultBuildinFileSystem fileSystem) internal LoadBuildinCatalogFileOperation(DefaultBuildinFileSystem fileSystem)
{ {
_fileSystem = fileSystem; _fileSystem = fileSystem;
} }
internal override void InternalStart() internal override void InternalStart()
{ {
_steps = ESteps.RequestData; _steps = ESteps.TryLoadFileData;
} }
internal override void InternalUpdate() internal override void InternalUpdate()
{ {
if (_steps == ESteps.None || _steps == ESteps.Done) if (_steps == ESteps.None || _steps == ESteps.Done)
return; return;
if (_steps == ESteps.RequestData) if (_steps == ESteps.TryLoadFileData)
{
string filePath = _fileSystem.GetCatalogBinaryFileLoadPath();
if (File.Exists(filePath))
{
_fileData = File.ReadAllBytes(filePath);
_steps = ESteps.LoadCatalog;
}
else
{
_steps = ESteps.RequestFileData;
}
}
if (_steps == ESteps.RequestFileData)
{ {
if (_webDataRequestOp == null) if (_webDataRequestOp == null)
{ {
@ -46,6 +68,7 @@ namespace YooAsset
if (_webDataRequestOp.Status == EOperationStatus.Succeed) if (_webDataRequestOp.Status == EOperationStatus.Succeed)
{ {
_fileData = _webDataRequestOp.Result;
_steps = ESteps.LoadCatalog; _steps = ESteps.LoadCatalog;
} }
else else
@ -60,22 +83,7 @@ namespace YooAsset
{ {
try try
{ {
var catalog = CatalogTools.DeserializeFromBinary(_webDataRequestOp.Result); Catalog = CatalogTools.DeserializeFromBinary(_fileData);
if (catalog.PackageName != _fileSystem.PackageName)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Catalog file package name {catalog.PackageName} cannot match the file system package name {_fileSystem.PackageName}";
return;
}
foreach (var wrapper in catalog.Wrappers)
{
var fileWrapper = new DefaultBuildinFileSystem.FileWrapper(wrapper.FileName);
_fileSystem.RecordCatalogFile(wrapper.BundleGUID, fileWrapper);
}
YooLogger.Log($"Package '{_fileSystem.PackageName}' buildin catalog files count : {catalog.Wrappers.Count}");
_steps = ESteps.Done; _steps = ESteps.Done;
Status = EOperationStatus.Succeed; Status = EOperationStatus.Succeed;
} }

View File

@ -1,4 +1,5 @@
 using System.IO;
namespace YooAsset namespace YooAsset
{ {
internal class LoadBuildinPackageManifestOperation : AsyncOperationBase internal class LoadBuildinPackageManifestOperation : AsyncOperationBase
@ -6,6 +7,7 @@ namespace YooAsset
private enum ESteps private enum ESteps
{ {
None, None,
TryLoadFileData,
RequestFileData, RequestFileData,
VerifyFileData, VerifyFileData,
LoadManifest, LoadManifest,
@ -17,6 +19,7 @@ namespace YooAsset
private readonly string _packageHash; private readonly string _packageHash;
private UnityWebDataRequestOperation _webDataRequestOp; private UnityWebDataRequestOperation _webDataRequestOp;
private DeserializeManifestOperation _deserializer; private DeserializeManifestOperation _deserializer;
private byte[] _fileData;
private ESteps _steps = ESteps.None; private ESteps _steps = ESteps.None;
/// <summary> /// <summary>
@ -33,13 +36,27 @@ namespace YooAsset
} }
internal override void InternalStart() internal override void InternalStart()
{ {
_steps = ESteps.RequestFileData; _steps = ESteps.TryLoadFileData;
} }
internal override void InternalUpdate() internal override void InternalUpdate()
{ {
if (_steps == ESteps.None || _steps == ESteps.Done) if (_steps == ESteps.None || _steps == ESteps.Done)
return; return;
if (_steps == ESteps.TryLoadFileData)
{
string filePath = _fileSystem.GetBuildinPackageManifestFilePath(_packageVersion);
if (File.Exists(filePath))
{
_fileData = File.ReadAllBytes(filePath);
_steps = ESteps.VerifyFileData;
}
else
{
_steps = ESteps.RequestFileData;
}
}
if (_steps == ESteps.RequestFileData) if (_steps == ESteps.RequestFileData)
{ {
if (_webDataRequestOp == null) if (_webDataRequestOp == null)
@ -57,6 +74,7 @@ namespace YooAsset
if (_webDataRequestOp.Status == EOperationStatus.Succeed) if (_webDataRequestOp.Status == EOperationStatus.Succeed)
{ {
_fileData = _webDataRequestOp.Result;
_steps = ESteps.VerifyFileData; _steps = ESteps.VerifyFileData;
} }
else else
@ -69,7 +87,7 @@ namespace YooAsset
if (_steps == ESteps.VerifyFileData) if (_steps == ESteps.VerifyFileData)
{ {
if (ManifestTools.VerifyManifestData(_webDataRequestOp.Result, _packageHash)) if (ManifestTools.VerifyManifestData(_fileData, _packageHash))
{ {
_steps = ESteps.LoadManifest; _steps = ESteps.LoadManifest;
} }
@ -85,7 +103,7 @@ namespace YooAsset
{ {
if (_deserializer == null) if (_deserializer == null)
{ {
_deserializer = new DeserializeManifestOperation(_fileSystem.ManifestServices, _webDataRequestOp.Result); _deserializer = new DeserializeManifestOperation(_fileSystem.ManifestServices, _fileData);
_deserializer.StartOperation(); _deserializer.StartOperation();
AddChildOperation(_deserializer); AddChildOperation(_deserializer);
} }

View File

@ -1,4 +1,5 @@
 using System.IO;
namespace YooAsset namespace YooAsset
{ {
internal class RequestBuildinPackageHashOperation : AsyncOperationBase internal class RequestBuildinPackageHashOperation : AsyncOperationBase
@ -6,7 +7,9 @@ namespace YooAsset
private enum ESteps private enum ESteps
{ {
None, None,
TryLoadPackageHash,
RequestPackageHash, RequestPackageHash,
CheckResult,
Done, Done,
} }
@ -28,13 +31,27 @@ namespace YooAsset
} }
internal override void InternalStart() internal override void InternalStart()
{ {
_steps = ESteps.RequestPackageHash; _steps = ESteps.TryLoadPackageHash;
} }
internal override void InternalUpdate() internal override void InternalUpdate()
{ {
if (_steps == ESteps.None || _steps == ESteps.Done) if (_steps == ESteps.None || _steps == ESteps.Done)
return; return;
if (_steps == ESteps.TryLoadPackageHash)
{
string filePath = _fileSystem.GetBuildinPackageHashFilePath(_packageVersion);
if (File.Exists(filePath))
{
PackageHash = File.ReadAllText(filePath);
_steps = ESteps.CheckResult;
}
else
{
_steps = ESteps.RequestPackageHash;
}
}
if (_steps == ESteps.RequestPackageHash) if (_steps == ESteps.RequestPackageHash)
{ {
if (_webTextRequestOp == null) if (_webTextRequestOp == null)
@ -53,17 +70,7 @@ namespace YooAsset
if (_webTextRequestOp.Status == EOperationStatus.Succeed) if (_webTextRequestOp.Status == EOperationStatus.Succeed)
{ {
PackageHash = _webTextRequestOp.Result; PackageHash = _webTextRequestOp.Result;
if (string.IsNullOrEmpty(PackageHash)) _steps = ESteps.CheckResult;
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Buildin package hash file content is empty !";
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}
} }
else else
{ {
@ -72,6 +79,21 @@ namespace YooAsset
Error = _webTextRequestOp.Error; Error = _webTextRequestOp.Error;
} }
} }
if (_steps == ESteps.CheckResult)
{
if (string.IsNullOrEmpty(PackageHash))
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Buildin package hash file content is empty !";
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}
}
} }
} }
} }

View File

@ -1,4 +1,5 @@
 using System.IO;
namespace YooAsset namespace YooAsset
{ {
internal class RequestBuildinPackageVersionOperation : AsyncOperationBase internal class RequestBuildinPackageVersionOperation : AsyncOperationBase
@ -6,7 +7,9 @@ namespace YooAsset
private enum ESteps private enum ESteps
{ {
None, None,
TryLoadPackageVersion,
RequestPackageVersion, RequestPackageVersion,
CheckResult,
Done, Done,
} }
@ -26,13 +29,27 @@ namespace YooAsset
} }
internal override void InternalStart() internal override void InternalStart()
{ {
_steps = ESteps.RequestPackageVersion; _steps = ESteps.TryLoadPackageVersion;
} }
internal override void InternalUpdate() internal override void InternalUpdate()
{ {
if (_steps == ESteps.None || _steps == ESteps.Done) if (_steps == ESteps.None || _steps == ESteps.Done)
return; return;
if (_steps == ESteps.TryLoadPackageVersion)
{
string filePath = _fileSystem.GetBuildinPackageVersionFilePath();
if (File.Exists(filePath))
{
PackageVersion = File.ReadAllText(filePath);
_steps = ESteps.CheckResult;
}
else
{
_steps = ESteps.RequestPackageVersion;
}
}
if (_steps == ESteps.RequestPackageVersion) if (_steps == ESteps.RequestPackageVersion)
{ {
if (_webTextRequestOp == null) if (_webTextRequestOp == null)
@ -51,17 +68,7 @@ namespace YooAsset
if (_webTextRequestOp.Status == EOperationStatus.Succeed) if (_webTextRequestOp.Status == EOperationStatus.Succeed)
{ {
PackageVersion = _webTextRequestOp.Result; PackageVersion = _webTextRequestOp.Result;
if (string.IsNullOrEmpty(PackageVersion)) _steps = ESteps.CheckResult;
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Buildin package version file content is empty !";
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}
} }
else else
{ {
@ -70,6 +77,21 @@ namespace YooAsset
Error = _webTextRequestOp.Error; Error = _webTextRequestOp.Error;
} }
} }
if (_steps == ESteps.CheckResult)
{
if (string.IsNullOrEmpty(PackageVersion))
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Buildin package version file content is empty !";
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}
}
} }
} }
} }

View File

@ -2,6 +2,7 @@
using System.IO; using System.IO;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using UnityEngine;
namespace YooAsset namespace YooAsset
{ {
@ -60,15 +61,20 @@ namespace YooAsset
/// </summary> /// </summary>
public IRemoteServices RemoteServices { private set; get; } public IRemoteServices RemoteServices { private set; get; }
/// <summary>
/// 自定义参数:覆盖安装缓存清理模式
/// </summary>
public EOverwriteInstallClearMode InstallClearMode { private set; get; } = EOverwriteInstallClearMode.ClearAllManifestFiles;
/// <summary> /// <summary>
/// 自定义参数:初始化的时候缓存文件校验级别 /// 自定义参数:初始化的时候缓存文件校验级别
/// </summary> /// </summary>
public EFileVerifyLevel FileVerifyLevel { private set; get; } = EFileVerifyLevel.Middle; public EFileVerifyLevel FileVerifyLevel { private set; get; } = EFileVerifyLevel.Middle;
/// <summary> /// <summary>
/// 自定义参数:覆盖安装缓存清理模式 /// 自定义参数:初始化的时候缓存文件校验最大并发数
/// </summary> /// </summary>
public EOverwriteInstallClearMode InstallClearMode { private set; get; } = EOverwriteInstallClearMode.ClearAllManifestFiles; public int FileVerifyMaxConcurrency { private set; get; } = int.MaxValue;
/// <summary> /// <summary>
/// 自定义参数:数据文件追加文件格式 /// 自定义参数:数据文件追加文件格式
@ -215,13 +221,18 @@ namespace YooAsset
{ {
RemoteServices = (IRemoteServices)value; RemoteServices = (IRemoteServices)value;
} }
else if (name == FileSystemParametersDefine.INSTALL_CLEAR_MODE)
{
InstallClearMode = (EOverwriteInstallClearMode)value;
}
else if (name == FileSystemParametersDefine.FILE_VERIFY_LEVEL) else if (name == FileSystemParametersDefine.FILE_VERIFY_LEVEL)
{ {
FileVerifyLevel = (EFileVerifyLevel)value; FileVerifyLevel = (EFileVerifyLevel)value;
} }
else if (name == FileSystemParametersDefine.INSTALL_CLEAR_MODE) else if (name == FileSystemParametersDefine.FILE_VERIFY_MAX_CONCURRENCY)
{ {
InstallClearMode = (EOverwriteInstallClearMode)value; int convertValue = Convert.ToInt32(value);
FileVerifyMaxConcurrency = Mathf.Clamp(convertValue, 1, int.MaxValue);
} }
else if (name == FileSystemParametersDefine.APPEND_FILE_EXTENSION) else if (name == FileSystemParametersDefine.APPEND_FILE_EXTENSION)
{ {
@ -233,11 +244,13 @@ namespace YooAsset
} }
else if (name == FileSystemParametersDefine.DOWNLOAD_MAX_CONCURRENCY) else if (name == FileSystemParametersDefine.DOWNLOAD_MAX_CONCURRENCY)
{ {
DownloadMaxConcurrency = Convert.ToInt32(value); int convertValue = Convert.ToInt32(value);
DownloadMaxConcurrency = Mathf.Clamp(convertValue, 1, int.MaxValue);
} }
else if (name == FileSystemParametersDefine.DOWNLOAD_MAX_REQUEST_PER_FRAME) else if (name == FileSystemParametersDefine.DOWNLOAD_MAX_REQUEST_PER_FRAME)
{ {
DownloadMaxRequestPerFrame = Convert.ToInt32(value); int convertValue = Convert.ToInt32(value);
DownloadMaxRequestPerFrame = Mathf.Clamp(convertValue, 1, int.MaxValue);
} }
else if (name == FileSystemParametersDefine.RESUME_DOWNLOAD_MINMUM_SIZE) else if (name == FileSystemParametersDefine.RESUME_DOWNLOAD_MINMUM_SIZE)
{ {
@ -493,22 +506,22 @@ namespace YooAsset
} }
private readonly BufferWriter _sharedBuffer = new BufferWriter(1024); private readonly BufferWriter _sharedBuffer = new BufferWriter(1024);
public void WriteBundleInfoFile(string filePath, string dataFileCRC, long dataFileSize) public void WriteBundleInfoFile(string filePath, uint dataFileCRC, long dataFileSize)
{ {
using (FileStream fs = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.Read)) using (FileStream fs = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.Read))
{ {
_sharedBuffer.Clear(); _sharedBuffer.Clear();
_sharedBuffer.WriteUTF8(dataFileCRC); _sharedBuffer.WriteUInt32(dataFileCRC);
_sharedBuffer.WriteInt64(dataFileSize); _sharedBuffer.WriteInt64(dataFileSize);
_sharedBuffer.WriteToStream(fs); _sharedBuffer.WriteToStream(fs);
fs.Flush(); fs.Flush();
} }
} }
public void ReadBundleInfoFile(string filePath, out string dataFileCRC, out long dataFileSize) public void ReadBundleInfoFile(string filePath, out uint dataFileCRC, out long dataFileSize)
{ {
byte[] binaryData = FileUtility.ReadAllBytes(filePath); byte[] binaryData = FileUtility.ReadAllBytes(filePath);
BufferReader buffer = new BufferReader(binaryData); BufferReader buffer = new BufferReader(binaryData);
dataFileCRC = buffer.ReadUTF8(); dataFileCRC = buffer.ReadUInt32();
dataFileSize = buffer.ReadInt64(); dataFileSize = buffer.ReadInt64();
} }
#endregion #endregion

View File

@ -7,10 +7,10 @@ namespace YooAsset
{ {
public string InfoFilePath { private set; get; } public string InfoFilePath { private set; get; }
public string DataFilePath { private set; get; } public string DataFilePath { private set; get; }
public string DataFileCRC { private set; get; } public uint DataFileCRC { private set; get; }
public long DataFileSize { private set; get; } public long DataFileSize { private set; get; }
public RecordFileElement(string infoFilePath, string dataFilePath, string dataFileCRC, long dataFileSize) public RecordFileElement(string infoFilePath, string dataFilePath, uint dataFileCRC, long dataFileSize)
{ {
InfoFilePath = infoFilePath; InfoFilePath = infoFilePath;
DataFilePath = dataFilePath; DataFilePath = dataFilePath;

View File

@ -4,7 +4,7 @@ namespace YooAsset
internal class TempFileElement internal class TempFileElement
{ {
public string TempFilePath { private set; get; } public string TempFilePath { private set; get; }
public string TempFileCRC { private set; get; } public uint TempFileCRC { private set; get; }
public long TempFileSize { private set; get; } public long TempFileSize { private set; get; }
/// <summary> /// <summary>
@ -12,7 +12,7 @@ namespace YooAsset
/// </summary> /// </summary>
public volatile int Result = 0; public volatile int Result = 0;
public TempFileElement(string filePath, string fileCRC, long fileSize) public TempFileElement(string filePath, uint fileCRC, long fileSize)
{ {
TempFilePath = filePath; TempFilePath = filePath;
TempFileCRC = fileCRC; TempFileCRC = fileCRC;

View File

@ -10,7 +10,7 @@ namespace YooAsset
public string DataFilePath { private set; get; } public string DataFilePath { private set; get; }
public string InfoFilePath { private set; get; } public string InfoFilePath { private set; get; }
public string DataFileCRC; public uint DataFileCRC;
public long DataFileSize; public long DataFileSize;
/// <summary> /// <summary>

View File

@ -54,11 +54,13 @@ namespace YooAsset
// 设置同时验证的最大数 // 设置同时验证的最大数
ThreadPool.GetMaxThreads(out int workerThreads, out int ioThreads); ThreadPool.GetMaxThreads(out int workerThreads, out int ioThreads);
YooLogger.Log($"Work threads : {workerThreads}, IO threads : {ioThreads}"); YooLogger.Log($"Work threads : {workerThreads}, IO threads : {ioThreads}");
_verifyMaxNum = Math.Min(workerThreads, ioThreads); int threads = Math.Min(workerThreads, ioThreads);
_verifyMaxNum = Math.Min(threads, _fileSystem.FileVerifyMaxConcurrency);
_verifyTotalCount = fileCount; _verifyTotalCount = fileCount;
if (_verifyMaxNum < 1) if (_verifyMaxNum < 1)
_verifyMaxNum = 1; _verifyMaxNum = 1;
YooLogger.Log($"Verify max concurrency : {_verifyMaxNum}");
_verifyingList = new List<VerifyFileElement>(_verifyMaxNum); _verifyingList = new List<VerifyFileElement>(_verifyMaxNum);
_steps = ESteps.UpdateVerify; _steps = ESteps.UpdateVerify;
} }

View File

@ -14,8 +14,8 @@ namespace YooAsset
private readonly DefaultWebRemoteFileSystem _fileSystem; private readonly DefaultWebRemoteFileSystem _fileSystem;
private readonly string _packageVersion; private readonly string _packageVersion;
private readonly int _timeout; private readonly int _timeout;
private RequestWebRemotePackageHashOperation _requestWebPackageHashOp; private RequestWebPackageHashOperation _requestWebPackageHashOp;
private LoadWebRemotePackageManifestOperation _loadWebPackageManifestOp; private LoadWebPackageManifestOperation _loadWebPackageManifestOp;
private ESteps _steps = ESteps.None; private ESteps _steps = ESteps.None;
@ -38,7 +38,7 @@ namespace YooAsset
{ {
if (_requestWebPackageHashOp == null) if (_requestWebPackageHashOp == null)
{ {
_requestWebPackageHashOp = new RequestWebRemotePackageHashOperation(_fileSystem, _packageVersion, _timeout); _requestWebPackageHashOp = new RequestWebPackageHashOperation(_fileSystem.RemoteServices, _fileSystem.PackageName, _packageVersion, _timeout);
_requestWebPackageHashOp.StartOperation(); _requestWebPackageHashOp.StartOperation();
AddChildOperation(_requestWebPackageHashOp); AddChildOperation(_requestWebPackageHashOp);
} }
@ -64,7 +64,10 @@ namespace YooAsset
if (_loadWebPackageManifestOp == null) if (_loadWebPackageManifestOp == null)
{ {
string packageHash = _requestWebPackageHashOp.PackageHash; string packageHash = _requestWebPackageHashOp.PackageHash;
_loadWebPackageManifestOp = new LoadWebRemotePackageManifestOperation(_fileSystem, _packageVersion, packageHash, _timeout); string packageName = _fileSystem.PackageName;
var manifestServices = _fileSystem.ManifestServices;
var remoteServices = _fileSystem.RemoteServices;
_loadWebPackageManifestOp = new LoadWebPackageManifestOperation(manifestServices, remoteServices, packageName, _packageVersion, packageHash, _timeout);
_loadWebPackageManifestOp.StartOperation(); _loadWebPackageManifestOp.StartOperation();
AddChildOperation(_loadWebPackageManifestOp); AddChildOperation(_loadWebPackageManifestOp);
} }

View File

@ -13,7 +13,7 @@ namespace YooAsset
private readonly DefaultWebRemoteFileSystem _fileSystem; private readonly DefaultWebRemoteFileSystem _fileSystem;
private readonly bool _appendTimeTicks; private readonly bool _appendTimeTicks;
private readonly int _timeout; private readonly int _timeout;
private RequestWebRemotePackageVersionOperation _requestWebPackageVersionOp; private RequestWebPackageVersionOperation _requestWebPackageVersionOp;
private ESteps _steps = ESteps.None; private ESteps _steps = ESteps.None;
@ -36,7 +36,7 @@ namespace YooAsset
{ {
if (_requestWebPackageVersionOp == null) if (_requestWebPackageVersionOp == null)
{ {
_requestWebPackageVersionOp = new RequestWebRemotePackageVersionOperation(_fileSystem, _appendTimeTicks, _timeout); _requestWebPackageVersionOp = new RequestWebPackageVersionOperation(_fileSystem.RemoteServices, _fileSystem.PackageName, _appendTimeTicks, _timeout);
_requestWebPackageVersionOp.StartOperation(); _requestWebPackageVersionOp.StartOperation();
AddChildOperation(_requestWebPackageVersionOp); AddChildOperation(_requestWebPackageVersionOp);
} }

View File

@ -1,131 +0,0 @@

namespace YooAsset
{
internal class LoadWebRemotePackageManifestOperation : AsyncOperationBase
{
private enum ESteps
{
None,
RequestFileData,
VerifyFileData,
LoadManifest,
Done,
}
private readonly DefaultWebRemoteFileSystem _fileSystem;
private readonly string _packageVersion;
private readonly string _packageHash;
private readonly int _timeout;
private UnityWebDataRequestOperation _webDataRequestOp;
private DeserializeManifestOperation _deserializer;
private int _requestCount = 0;
private ESteps _steps = ESteps.None;
/// <summary>
/// 包裹清单
/// </summary>
public PackageManifest Manifest { private set; get; }
internal LoadWebRemotePackageManifestOperation(DefaultWebRemoteFileSystem fileSystem, string packageVersion, string packageHash, int timeout)
{
_fileSystem = fileSystem;
_packageVersion = packageVersion;
_packageHash = packageHash;
_timeout = timeout;
}
internal override void InternalStart()
{
_requestCount = WebRequestCounter.GetRequestFailedCount(_fileSystem.PackageName, nameof(LoadWebRemotePackageManifestOperation));
_steps = ESteps.RequestFileData;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.RequestFileData)
{
if (_webDataRequestOp == null)
{
string fileName = YooAssetSettingsData.GetManifestBinaryFileName(_fileSystem.PackageName, _packageVersion);
string url = GetWebRequestURL(fileName);
_webDataRequestOp = new UnityWebDataRequestOperation(url, _timeout);
_webDataRequestOp.StartOperation();
AddChildOperation(_webDataRequestOp);
}
_webDataRequestOp.UpdateOperation();
if (_webDataRequestOp.IsDone == false)
return;
if (_webDataRequestOp.Status == EOperationStatus.Succeed)
{
_steps = ESteps.VerifyFileData;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _webDataRequestOp.Error;
WebRequestCounter.RecordRequestFailed(_fileSystem.PackageName, nameof(LoadWebRemotePackageManifestOperation));
}
}
if (_steps == ESteps.VerifyFileData)
{
if (ManifestTools.VerifyManifestData(_webDataRequestOp.Result, _packageHash))
{
_steps = ESteps.LoadManifest;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = "Failed to verify web remote package manifest file!";
}
}
if (_steps == ESteps.LoadManifest)
{
if (_deserializer == null)
{
_deserializer = new DeserializeManifestOperation(_fileSystem.ManifestServices, _webDataRequestOp.Result);
_deserializer.StartOperation();
AddChildOperation(_deserializer);
}
_deserializer.UpdateOperation();
Progress = _deserializer.Progress;
if (_deserializer.IsDone == false)
return;
if (_deserializer.Status == EOperationStatus.Succeed)
{
_steps = ESteps.Done;
Manifest = _deserializer.Manifest;
Status = EOperationStatus.Succeed;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _deserializer.Error;
}
}
}
internal override string InternalGetDesc()
{
return $"PackageVersion : {_packageVersion} PackageHash : {_packageHash}";
}
private string GetWebRequestURL(string fileName)
{
// 轮流返回请求地址
if (_requestCount % 2 == 0)
return _fileSystem.RemoteServices.GetRemoteMainURL(fileName);
else
return _fileSystem.RemoteServices.GetRemoteFallbackURL(fileName);
}
}
}

View File

@ -1,92 +0,0 @@

namespace YooAsset
{
internal class RequestWebRemotePackageHashOperation : AsyncOperationBase
{
private enum ESteps
{
None,
RequestPackageHash,
Done,
}
private readonly DefaultWebRemoteFileSystem _fileSystem;
private readonly string _packageVersion;
private readonly int _timeout;
private UnityWebTextRequestOperation _webTextRequestOp;
private int _requestCount = 0;
private ESteps _steps = ESteps.None;
/// <summary>
/// 包裹哈希值
/// </summary>
public string PackageHash { private set; get; }
public RequestWebRemotePackageHashOperation(DefaultWebRemoteFileSystem fileSystem, string packageVersion, int timeout)
{
_fileSystem = fileSystem;
_packageVersion = packageVersion;
_timeout = timeout;
}
internal override void InternalStart()
{
_requestCount = WebRequestCounter.GetRequestFailedCount(_fileSystem.PackageName, nameof(RequestWebRemotePackageHashOperation));
_steps = ESteps.RequestPackageHash;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.RequestPackageHash)
{
if (_webTextRequestOp == null)
{
string fileName = YooAssetSettingsData.GetPackageHashFileName(_fileSystem.PackageName, _packageVersion);
string url = GetWebRequestURL(fileName);
_webTextRequestOp = new UnityWebTextRequestOperation(url, _timeout);
_webTextRequestOp.StartOperation();
AddChildOperation(_webTextRequestOp);
}
_webTextRequestOp.UpdateOperation();
Progress = _webTextRequestOp.Progress;
if (_webTextRequestOp.IsDone == false)
return;
if (_webTextRequestOp.Status == EOperationStatus.Succeed)
{
PackageHash = _webTextRequestOp.Result;
if (string.IsNullOrEmpty(PackageHash))
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Web remote package hash file content is empty !";
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _webTextRequestOp.Error;
WebRequestCounter.RecordRequestFailed(_fileSystem.PackageName, nameof(RequestWebRemotePackageHashOperation));
}
}
}
private string GetWebRequestURL(string fileName)
{
// 轮流返回请求地址
if (_requestCount % 2 == 0)
return _fileSystem.RemoteServices.GetRemoteMainURL(fileName);
else
return _fileSystem.RemoteServices.GetRemoteFallbackURL(fileName);
}
}
}

View File

@ -1,100 +0,0 @@

namespace YooAsset
{
internal class RequestWebRemotePackageVersionOperation : AsyncOperationBase
{
private enum ESteps
{
None,
RequestPackageVersion,
Done,
}
private readonly DefaultWebRemoteFileSystem _fileSystem;
private readonly bool _appendTimeTicks;
private readonly int _timeout;
private UnityWebTextRequestOperation _webTextRequestOp;
private int _requestCount = 0;
private ESteps _steps = ESteps.None;
/// <summary>
/// 包裹版本
/// </summary>
public string PackageVersion { private set; get; }
internal RequestWebRemotePackageVersionOperation(DefaultWebRemoteFileSystem fileSystem, bool appendTimeTicks, int timeout)
{
_fileSystem = fileSystem;
_appendTimeTicks = appendTimeTicks;
_timeout = timeout;
}
internal override void InternalStart()
{
_requestCount = WebRequestCounter.GetRequestFailedCount(_fileSystem.PackageName, nameof(RequestWebRemotePackageVersionOperation));
_steps = ESteps.RequestPackageVersion;
}
internal override void InternalUpdate()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.RequestPackageVersion)
{
if (_webTextRequestOp == null)
{
string fileName = YooAssetSettingsData.GetPackageVersionFileName(_fileSystem.PackageName);
string url = GetWebRequestURL(fileName);
_webTextRequestOp = new UnityWebTextRequestOperation(url, _timeout);
_webTextRequestOp.StartOperation();
AddChildOperation(_webTextRequestOp);
}
_webTextRequestOp.UpdateOperation();
Progress = _webTextRequestOp.Progress;
if (_webTextRequestOp.IsDone == false)
return;
if (_webTextRequestOp.Status == EOperationStatus.Succeed)
{
PackageVersion = _webTextRequestOp.Result;
if (string.IsNullOrEmpty(PackageVersion))
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Web remote package version file content is empty !";
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _webTextRequestOp.Error;
WebRequestCounter.RecordRequestFailed(_fileSystem.PackageName, nameof(RequestWebRemotePackageVersionOperation));
}
}
}
private string GetWebRequestURL(string fileName)
{
string url;
// 轮流返回请求地址
if (_requestCount % 2 == 0)
url = _fileSystem.RemoteServices.GetRemoteMainURL(fileName);
else
url = _fileSystem.RemoteServices.GetRemoteFallbackURL(fileName);
// 在URL末尾添加时间戳
if (_appendTimeTicks)
return $"{url}?{System.DateTime.UtcNow.Ticks}";
else
return url;
}
}
}

View File

@ -4,6 +4,7 @@ namespace YooAsset
public class FileSystemParametersDefine public class FileSystemParametersDefine
{ {
public const string FILE_VERIFY_LEVEL = "FILE_VERIFY_LEVEL"; public const string FILE_VERIFY_LEVEL = "FILE_VERIFY_LEVEL";
public const string FILE_VERIFY_MAX_CONCURRENCY = "FILE_VERIFY_MAX_CONCURRENCY";
public const string INSTALL_CLEAR_MODE = "INSTALL_CLEAR_MODE"; public const string INSTALL_CLEAR_MODE = "INSTALL_CLEAR_MODE";
public const string REMOTE_SERVICES = "REMOTE_SERVICES"; public const string REMOTE_SERVICES = "REMOTE_SERVICES";
public const string DECRYPTION_SERVICES = "DECRYPTION_SERVICES"; public const string DECRYPTION_SERVICES = "DECRYPTION_SERVICES";

View File

@ -8,7 +8,7 @@ namespace YooAsset
/// <summary> /// <summary>
/// 文件校验 /// 文件校验
/// </summary> /// </summary>
public static EFileVerifyResult FileVerify(string filePath, long fileSize, string fileCRC, EFileVerifyLevel verifyLevel) public static EFileVerifyResult FileVerify(string filePath, long fileSize, uint fileCRC, EFileVerifyLevel verifyLevel)
{ {
try try
{ {
@ -25,7 +25,7 @@ namespace YooAsset
// 再验证文件CRC // 再验证文件CRC
if (verifyLevel == EFileVerifyLevel.High) if (verifyLevel == EFileVerifyLevel.High)
{ {
string crc = HashUtility.FileCRC32(filePath); uint crc = HashUtility.FileCRC32Value(filePath);
if (crc == fileCRC) if (crc == fileCRC)
return EFileVerifyResult.Succeed; return EFileVerifyResult.Succeed;
else else

View File

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

View File

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

View File

@ -1,7 +1,6 @@
#if UNITY_WEBGL && DOUYINMINIGAME using YooAsset;
using YooAsset;
internal class LoadTiktokPackageManifestOperation : AsyncOperationBase internal class LoadWebPackageManifestOperation : AsyncOperationBase
{ {
private enum ESteps private enum ESteps
{ {
@ -12,7 +11,9 @@ internal class LoadTiktokPackageManifestOperation : AsyncOperationBase
Done, Done,
} }
private readonly TiktokFileSystem _fileSystem; private readonly IManifestRestoreServices _manifestServices;
private readonly IRemoteServices _remoteServices;
private readonly string _packageName;
private readonly string _packageVersion; private readonly string _packageVersion;
private readonly string _packageHash; private readonly string _packageHash;
private readonly int _timeout; private readonly int _timeout;
@ -27,16 +28,19 @@ internal class LoadTiktokPackageManifestOperation : AsyncOperationBase
public PackageManifest Manifest { private set; get; } public PackageManifest Manifest { private set; get; }
internal LoadTiktokPackageManifestOperation(TiktokFileSystem fileSystem, string packageVersion, string packageHash, int timeout) internal LoadWebPackageManifestOperation(IManifestRestoreServices manifestServices, IRemoteServices remoteServices,
string packageName, string packageVersion, string packageHash, int timeout)
{ {
_fileSystem = fileSystem; _manifestServices = manifestServices;
_remoteServices = remoteServices;
_packageName = packageName;
_packageVersion = packageVersion; _packageVersion = packageVersion;
_packageHash = packageHash; _packageHash = packageHash;
_timeout = timeout; _timeout = timeout;
} }
internal override void InternalStart() internal override void InternalStart()
{ {
_requestCount = WebRequestCounter.GetRequestFailedCount(_fileSystem.PackageName, nameof(LoadTiktokPackageManifestOperation)); _requestCount = WebRequestCounter.GetRequestFailedCount(_packageName, nameof(LoadWebPackageManifestOperation));
_steps = ESteps.RequestFileData; _steps = ESteps.RequestFileData;
} }
internal override void InternalUpdate() internal override void InternalUpdate()
@ -48,7 +52,7 @@ internal class LoadTiktokPackageManifestOperation : AsyncOperationBase
{ {
if (_webDataRequestOp == null) if (_webDataRequestOp == null)
{ {
string fileName = YooAssetSettingsData.GetManifestBinaryFileName(_fileSystem.PackageName, _packageVersion); string fileName = YooAssetSettingsData.GetManifestBinaryFileName(_packageName, _packageVersion);
string url = GetRequestURL(fileName); string url = GetRequestURL(fileName);
_webDataRequestOp = new UnityWebDataRequestOperation(url, _timeout); _webDataRequestOp = new UnityWebDataRequestOperation(url, _timeout);
_webDataRequestOp.StartOperation(); _webDataRequestOp.StartOperation();
@ -69,14 +73,13 @@ internal class LoadTiktokPackageManifestOperation : AsyncOperationBase
_steps = ESteps.Done; _steps = ESteps.Done;
Status = EOperationStatus.Failed; Status = EOperationStatus.Failed;
Error = _webDataRequestOp.Error; Error = _webDataRequestOp.Error;
WebRequestCounter.RecordRequestFailed(_fileSystem.PackageName, nameof(LoadTiktokPackageManifestOperation)); WebRequestCounter.RecordRequestFailed(_packageName, nameof(LoadWebPackageManifestOperation));
} }
} }
if (_steps == ESteps.VerifyFileData) if (_steps == ESteps.VerifyFileData)
{ {
string fileHash = HashUtility.BytesCRC32(_webDataRequestOp.Result); if (ManifestTools.VerifyManifestData(_webDataRequestOp.Result, _packageHash))
if (fileHash == _packageHash)
{ {
_steps = ESteps.LoadManifest; _steps = ESteps.LoadManifest;
} }
@ -84,7 +87,7 @@ internal class LoadTiktokPackageManifestOperation : AsyncOperationBase
{ {
_steps = ESteps.Done; _steps = ESteps.Done;
Status = EOperationStatus.Failed; Status = EOperationStatus.Failed;
Error = "Failed to verify package manifest file!"; Error = "Failed to verify web package manifest file!";
} }
} }
@ -92,7 +95,7 @@ internal class LoadTiktokPackageManifestOperation : AsyncOperationBase
{ {
if (_deserializer == null) if (_deserializer == null)
{ {
_deserializer = new DeserializeManifestOperation(_fileSystem.ManifestServices, _webDataRequestOp.Result); _deserializer = new DeserializeManifestOperation(_manifestServices, _webDataRequestOp.Result);
_deserializer.StartOperation(); _deserializer.StartOperation();
AddChildOperation(_deserializer); AddChildOperation(_deserializer);
} }
@ -116,14 +119,17 @@ internal class LoadTiktokPackageManifestOperation : AsyncOperationBase
} }
} }
} }
internal override string InternalGetDesc()
{
return $"PackageVersion : {_packageVersion} PackageHash : {_packageHash}";
}
private string GetRequestURL(string fileName) private string GetRequestURL(string fileName)
{ {
// 轮流返回请求地址 // 轮流返回请求地址
if (_requestCount % 2 == 0) if (_requestCount % 2 == 0)
return _fileSystem.RemoteServices.GetRemoteMainURL(fileName); return _remoteServices.GetRemoteMainURL(fileName);
else else
return _fileSystem.RemoteServices.GetRemoteFallbackURL(fileName); return _remoteServices.GetRemoteFallbackURL(fileName);
} }
} }
#endif

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: f2a5bb0106a45e540a43a05b72a75bcd guid: eb2ed9a86dbe88c42a3715b90df0e266
MonoImporter: MonoImporter:
externalObjects: {} externalObjects: {}
serializedVersion: 2 serializedVersion: 2

View File

@ -1,7 +1,6 @@
#if UNITY_WEBGL && DOUYINMINIGAME using YooAsset;
using YooAsset;
internal class RequestTiktokPackageHashOperation : AsyncOperationBase internal class RequestWebPackageHashOperation : AsyncOperationBase
{ {
private enum ESteps private enum ESteps
{ {
@ -10,7 +9,8 @@ internal class RequestTiktokPackageHashOperation : AsyncOperationBase
Done, Done,
} }
private readonly TiktokFileSystem _fileSystem; private readonly IRemoteServices _remoteServices;
private readonly string _packageName;
private readonly string _packageVersion; private readonly string _packageVersion;
private readonly int _timeout; private readonly int _timeout;
private UnityWebTextRequestOperation _webTextRequestOp; private UnityWebTextRequestOperation _webTextRequestOp;
@ -23,15 +23,16 @@ internal class RequestTiktokPackageHashOperation : AsyncOperationBase
public string PackageHash { private set; get; } public string PackageHash { private set; get; }
public RequestTiktokPackageHashOperation(TiktokFileSystem fileSystem, string packageVersion, int timeout) public RequestWebPackageHashOperation(IRemoteServices remoteServices, string packageName, string packageVersion, int timeout)
{ {
_fileSystem = fileSystem; _remoteServices = remoteServices;
_packageName = packageName;
_packageVersion = packageVersion; _packageVersion = packageVersion;
_timeout = timeout; _timeout = timeout;
} }
internal override void InternalStart() internal override void InternalStart()
{ {
_requestCount = WebRequestCounter.GetRequestFailedCount(_fileSystem.PackageName, nameof(RequestTiktokPackageHashOperation)); _requestCount = WebRequestCounter.GetRequestFailedCount(_packageName, nameof(RequestWebPackageHashOperation));
_steps = ESteps.RequestPackageHash; _steps = ESteps.RequestPackageHash;
} }
internal override void InternalUpdate() internal override void InternalUpdate()
@ -43,7 +44,7 @@ internal class RequestTiktokPackageHashOperation : AsyncOperationBase
{ {
if (_webTextRequestOp == null) if (_webTextRequestOp == null)
{ {
string fileName = YooAssetSettingsData.GetPackageHashFileName(_fileSystem.PackageName, _packageVersion); string fileName = YooAssetSettingsData.GetPackageHashFileName(_packageName, _packageVersion);
string url = GetRequestURL(fileName); string url = GetRequestURL(fileName);
_webTextRequestOp = new UnityWebTextRequestOperation(url, _timeout); _webTextRequestOp = new UnityWebTextRequestOperation(url, _timeout);
_webTextRequestOp.StartOperation(); _webTextRequestOp.StartOperation();
@ -62,7 +63,7 @@ internal class RequestTiktokPackageHashOperation : AsyncOperationBase
{ {
_steps = ESteps.Done; _steps = ESteps.Done;
Status = EOperationStatus.Failed; Status = EOperationStatus.Failed;
Error = $"Wechat package hash file content is empty !"; Error = $"Web package hash file content is empty !";
} }
else else
{ {
@ -75,7 +76,7 @@ internal class RequestTiktokPackageHashOperation : AsyncOperationBase
_steps = ESteps.Done; _steps = ESteps.Done;
Status = EOperationStatus.Failed; Status = EOperationStatus.Failed;
Error = _webTextRequestOp.Error; Error = _webTextRequestOp.Error;
WebRequestCounter.RecordRequestFailed(_fileSystem.PackageName, nameof(RequestTiktokPackageHashOperation)); WebRequestCounter.RecordRequestFailed(_packageName, nameof(RequestWebPackageHashOperation));
} }
} }
} }
@ -84,9 +85,8 @@ internal class RequestTiktokPackageHashOperation : AsyncOperationBase
{ {
// 轮流返回请求地址 // 轮流返回请求地址
if (_requestCount % 2 == 0) if (_requestCount % 2 == 0)
return _fileSystem.RemoteServices.GetRemoteMainURL(fileName); return _remoteServices.GetRemoteMainURL(fileName);
else else
return _fileSystem.RemoteServices.GetRemoteFallbackURL(fileName); return _remoteServices.GetRemoteFallbackURL(fileName);
} }
} }
#endif

View File

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

View File

@ -1,7 +1,6 @@
#if UNITY_WEBGL && DOUYINMINIGAME using YooAsset;
using YooAsset;
internal class RequestTiktokPackageVersionOperation : AsyncOperationBase internal class RequestWebPackageVersionOperation : AsyncOperationBase
{ {
private enum ESteps private enum ESteps
{ {
@ -10,7 +9,8 @@ internal class RequestTiktokPackageVersionOperation : AsyncOperationBase
Done, Done,
} }
private readonly TiktokFileSystem _fileSystem; private readonly IRemoteServices _remoteServices;
private readonly string _packageName;
private readonly bool _appendTimeTicks; private readonly bool _appendTimeTicks;
private readonly int _timeout; private readonly int _timeout;
private UnityWebTextRequestOperation _webTextRequestOp; private UnityWebTextRequestOperation _webTextRequestOp;
@ -23,15 +23,16 @@ internal class RequestTiktokPackageVersionOperation : AsyncOperationBase
public string PackageVersion { private set; get; } public string PackageVersion { private set; get; }
public RequestTiktokPackageVersionOperation(TiktokFileSystem fileSystem, bool appendTimeTicks, int timeout) public RequestWebPackageVersionOperation(IRemoteServices remoteServices, string packageName, bool appendTimeTicks, int timeout)
{ {
_fileSystem = fileSystem; _remoteServices = remoteServices;
_packageName = packageName;
_appendTimeTicks = appendTimeTicks; _appendTimeTicks = appendTimeTicks;
_timeout = timeout; _timeout = timeout;
} }
internal override void InternalStart() internal override void InternalStart()
{ {
_requestCount = WebRequestCounter.GetRequestFailedCount(_fileSystem.PackageName, nameof(RequestTiktokPackageVersionOperation)); _requestCount = WebRequestCounter.GetRequestFailedCount(_packageName, nameof(RequestWebPackageVersionOperation));
_steps = ESteps.RequestPackageVersion; _steps = ESteps.RequestPackageVersion;
} }
internal override void InternalUpdate() internal override void InternalUpdate()
@ -43,7 +44,7 @@ internal class RequestTiktokPackageVersionOperation : AsyncOperationBase
{ {
if (_webTextRequestOp == null) if (_webTextRequestOp == null)
{ {
string fileName = YooAssetSettingsData.GetPackageVersionFileName(_fileSystem.PackageName); string fileName = YooAssetSettingsData.GetPackageVersionFileName(_packageName);
string url = GetRequestURL(fileName); string url = GetRequestURL(fileName);
_webTextRequestOp = new UnityWebTextRequestOperation(url, _timeout); _webTextRequestOp = new UnityWebTextRequestOperation(url, _timeout);
_webTextRequestOp.StartOperation(); _webTextRequestOp.StartOperation();
@ -62,7 +63,7 @@ internal class RequestTiktokPackageVersionOperation : AsyncOperationBase
{ {
_steps = ESteps.Done; _steps = ESteps.Done;
Status = EOperationStatus.Failed; Status = EOperationStatus.Failed;
Error = $"Wechat package version file content is empty !"; Error = $"Web package version file content is empty !";
} }
else else
{ {
@ -75,7 +76,7 @@ internal class RequestTiktokPackageVersionOperation : AsyncOperationBase
_steps = ESteps.Done; _steps = ESteps.Done;
Status = EOperationStatus.Failed; Status = EOperationStatus.Failed;
Error = _webTextRequestOp.Error; Error = _webTextRequestOp.Error;
WebRequestCounter.RecordRequestFailed(_fileSystem.PackageName, nameof(RequestTiktokPackageVersionOperation)); WebRequestCounter.RecordRequestFailed(_packageName, nameof(RequestWebPackageVersionOperation));
} }
} }
} }
@ -86,9 +87,9 @@ internal class RequestTiktokPackageVersionOperation : AsyncOperationBase
// 轮流返回请求地址 // 轮流返回请求地址
if (_requestCount % 2 == 0) if (_requestCount % 2 == 0)
url = _fileSystem.RemoteServices.GetRemoteMainURL(fileName); url = _remoteServices.GetRemoteMainURL(fileName);
else else
url = _fileSystem.RemoteServices.GetRemoteFallbackURL(fileName); url = _remoteServices.GetRemoteFallbackURL(fileName);
// 在URL末尾添加时间戳 // 在URL末尾添加时间戳
if (_appendTimeTicks) if (_appendTimeTicks)
@ -96,5 +97,4 @@ internal class RequestTiktokPackageVersionOperation : AsyncOperationBase
else else
return url; return url;
} }
} }
#endif

View File

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

View File

@ -47,6 +47,15 @@ namespace YooAsset
/// WebGL平台强制同步加载资源对象 /// WebGL平台强制同步加载资源对象
/// </summary> /// </summary>
public bool WebGLForceSyncLoadAsset = false; public bool WebGLForceSyncLoadAsset = false;
#if YOOASSET_EXPERIMENTAL
/// <summary>
/// 启用弱引用资源句柄
/// </summary>
public bool UseWeakReferenceHandle = false;
#else
internal bool UseWeakReferenceHandle = false;
#endif
} }
/// <summary> /// <summary>

View File

@ -1,4 +1,5 @@
using System.Collections; using System;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
@ -16,6 +17,8 @@ namespace YooAsset
private static readonly List<AsyncOperationBase> _operations = new List<AsyncOperationBase>(1000); private static readonly List<AsyncOperationBase> _operations = new List<AsyncOperationBase>(1000);
private static readonly List<AsyncOperationBase> _newList = new List<AsyncOperationBase>(1000); private static readonly List<AsyncOperationBase> _newList = new List<AsyncOperationBase>(1000);
private static Action<string, AsyncOperationBase> _startCallback = null;
private static Action<string, AsyncOperationBase> _finishCallback = null;
// 计时器相关 // 计时器相关
private static Stopwatch _watch; private static Stopwatch _watch;
@ -33,6 +36,7 @@ namespace YooAsset
{ {
get get
{ {
// NOTE : 单次调用开销约1微秒
return _watch.ElapsedMilliseconds - _frameTime >= MaxTimeSlice; return _watch.ElapsedMilliseconds - _frameTime >= MaxTimeSlice;
} }
} }
@ -57,7 +61,12 @@ namespace YooAsset
{ {
var operation = _operations[i]; var operation = _operations[i];
if (operation.IsFinish) if (operation.IsFinish)
{
_operations.RemoveAt(i); _operations.RemoveAt(i);
if (_finishCallback != null)
_finishCallback.Invoke(operation.PackageName, operation);
}
} }
// 添加新增的异步操作 // 添加新增的异步操作
@ -82,10 +91,11 @@ namespace YooAsset
} }
// 更新进行中的异步操作 // 更新进行中的异步操作
bool checkBusy = MaxTimeSlice < long.MaxValue;
_frameTime = _watch.ElapsedMilliseconds; _frameTime = _watch.ElapsedMilliseconds;
for (int i = 0; i < _operations.Count; i++) for (int i = 0; i < _operations.Count; i++)
{ {
if (IsBusy) if (checkBusy && IsBusy)
break; break;
var operation = _operations[i]; var operation = _operations[i];
@ -103,6 +113,8 @@ namespace YooAsset
{ {
_operations.Clear(); _operations.Clear();
_newList.Clear(); _newList.Clear();
_startCallback = null;
_finishCallback = null;
_watch = null; _watch = null;
_frameTime = 0; _frameTime = 0;
MaxTimeSlice = long.MaxValue; MaxTimeSlice = long.MaxValue;
@ -140,6 +152,25 @@ namespace YooAsset
_newList.Add(operation); _newList.Add(operation);
operation.SetPackageName(packageName); operation.SetPackageName(packageName);
operation.StartOperation(); operation.StartOperation();
if (_startCallback != null)
_startCallback.Invoke(packageName, operation);
}
/// <summary>
/// 监听任务开始
/// </summary>
public static void RegisterStartCallback(Action<string, AsyncOperationBase> callback)
{
_startCallback = callback;
}
/// <summary>
/// 监听任务结束
/// </summary>
public static void RegisterFinishCallback(Action<string, AsyncOperationBase> callback)
{
_finishCallback = callback;
} }
#region #region

View File

@ -17,7 +17,7 @@ namespace YooAsset
AddChildOperation(_loadAllAssetsOp); AddChildOperation(_loadAllAssetsOp);
#if UNITY_WEBGL #if UNITY_WEBGL
if (_resManager.WebGLForceSyncLoadAsset()) if (_resManager.WebGLForceSyncLoadAsset)
_loadAllAssetsOp.WaitForAsyncComplete(); _loadAllAssetsOp.WaitForAsyncComplete();
#endif #endif
} }

View File

@ -17,7 +17,7 @@ namespace YooAsset
AddChildOperation(_loadAssetOp); AddChildOperation(_loadAssetOp);
#if UNITY_WEBGL #if UNITY_WEBGL
if (_resManager.WebGLForceSyncLoadAsset()) if (_resManager.WebGLForceSyncLoadAsset)
_loadAssetOp.WaitForAsyncComplete(); _loadAssetOp.WaitForAsyncComplete();
#endif #endif
} }

View File

@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using System;
namespace YooAsset namespace YooAsset
{ {
@ -72,6 +73,7 @@ namespace YooAsset
private readonly LoadBundleFileOperation _mainBundleLoader; private readonly LoadBundleFileOperation _mainBundleLoader;
private readonly List<LoadBundleFileOperation> _bundleLoaders = new List<LoadBundleFileOperation>(10); private readonly List<LoadBundleFileOperation> _bundleLoaders = new List<LoadBundleFileOperation>(10);
private readonly HashSet<HandleBase> _handles = new HashSet<HandleBase>(); private readonly HashSet<HandleBase> _handles = new HashSet<HandleBase>();
private readonly LinkedList<WeakReference<HandleBase>> _weakReferences = new LinkedList<WeakReference<HandleBase>>();
public ProviderOperation(ResourceManager manager, string providerGUID, AssetInfo assetInfo) public ProviderOperation(ResourceManager manager, string providerGUID, AssetInfo assetInfo)
{ {
@ -210,6 +212,11 @@ namespace YooAsset
if (_steps == ESteps.ProcessBundleResult) if (_steps == ESteps.ProcessBundleResult)
return false; return false;
if (_resManager.UseWeakReferenceHandle)
{
TryCleanupWeakReference();
}
return RefCount <= 0; return RefCount <= 0;
} }
@ -222,7 +229,15 @@ namespace YooAsset
RefCount++; RefCount++;
HandleBase handle = HandleFactory.CreateHandle(this, typeof(T)); HandleBase handle = HandleFactory.CreateHandle(this, typeof(T));
_handles.Add(handle); if (_resManager.UseWeakReferenceHandle)
{
var weakRef = new WeakReference<HandleBase>(handle);
_weakReferences.AddLast(weakRef);
}
else
{
_handles.Add(handle);
}
return handle as T; return handle as T;
} }
@ -234,8 +249,16 @@ namespace YooAsset
if (RefCount <= 0) if (RefCount <= 0)
throw new System.Exception("Should never get here !"); throw new System.Exception("Should never get here !");
if (_handles.Remove(handle) == false) if (_resManager.UseWeakReferenceHandle)
throw new System.Exception("Should never get here !"); {
if (RemoveWeakReference(handle) == false)
throw new System.Exception("Should never get here !");
}
else
{
if (_handles.Remove(handle) == false)
throw new System.Exception("Should never get here !");
}
// 引用计数减少 // 引用计数减少
RefCount--; RefCount--;
@ -246,10 +269,24 @@ namespace YooAsset
/// </summary> /// </summary>
public void ReleaseAllHandles() public void ReleaseAllHandles()
{ {
List<HandleBase> tempers = _handles.ToList(); if (_resManager.UseWeakReferenceHandle)
foreach (var handle in tempers)
{ {
handle.Release(); List<WeakReference<HandleBase>> tempers = _weakReferences.ToList();
foreach (var weakRef in tempers)
{
if (weakRef.TryGetTarget(out HandleBase target))
{
target.Release();
}
}
}
else
{
List<HandleBase> tempers = _handles.ToList();
foreach (var handle in tempers)
{
handle.Release();
}
} }
} }
@ -264,12 +301,29 @@ namespace YooAsset
// 注意:创建临时列表是为了防止外部逻辑在回调函数内创建或者释放资源句柄。 // 注意:创建临时列表是为了防止外部逻辑在回调函数内创建或者释放资源句柄。
// 注意:回调方法如果发生异常,会阻断列表里的后续回调方法! // 注意:回调方法如果发生异常,会阻断列表里的后续回调方法!
List<HandleBase> tempers = _handles.ToList(); if (_resManager.UseWeakReferenceHandle)
foreach (var hande in tempers)
{ {
if (hande.IsValid) List<WeakReference<HandleBase>> tempers = _weakReferences.ToList();
foreach (var weakRef in tempers)
{ {
hande.InvokeCallback(); if (weakRef.TryGetTarget(out HandleBase target))
{
if (target.IsValid)
{
target.InvokeCallback();
}
}
}
}
else
{
List<HandleBase> tempers = _handles.ToList();
foreach (var handle in tempers)
{
if (handle.IsValid)
{
handle.InvokeCallback();
}
} }
} }
} }
@ -294,6 +348,50 @@ namespace YooAsset
return status; return status;
} }
/// <summary>
/// 移除指定句柄的弱引用对象
/// </summary>
private bool RemoveWeakReference(HandleBase handle)
{
bool removed = false;
var currentNode = _weakReferences.First;
while (currentNode != null)
{
var nextNode = currentNode.Next;
if (currentNode.Value.TryGetTarget(out HandleBase target))
{
if (ReferenceEquals(target, handle))
{
_weakReferences.Remove(currentNode);
removed = true;
break;
}
}
currentNode = nextNode;
}
return removed;
}
/// <summary>
/// 清理所有失效的弱引用
/// </summary>
private void TryCleanupWeakReference()
{
var currentNode = _weakReferences.First;
while (currentNode != null)
{
var nextNode = currentNode.Next;
if (currentNode.Value.TryGetTarget(out HandleBase target) == false)
{
_weakReferences.Remove(currentNode);
// 引用计数减少
RefCount--;
}
currentNode = nextNode;
}
}
#region #region
/// <summary> /// <summary>
/// 出生的场景 /// 出生的场景

View File

@ -17,7 +17,7 @@ namespace YooAsset
AddChildOperation(_loadSubAssetsOp); AddChildOperation(_loadSubAssetsOp);
#if UNITY_WEBGL #if UNITY_WEBGL
if (_resManager.WebGLForceSyncLoadAsset()) if (_resManager.WebGLForceSyncLoadAsset)
_loadSubAssetsOp.WaitForAsyncComplete(); _loadSubAssetsOp.WaitForAsyncComplete();
#endif #endif
} }

View File

@ -15,7 +15,10 @@ namespace YooAsset
private long _sceneCreateIndex = 0; private long _sceneCreateIndex = 0;
private IBundleQuery _bundleQuery; private IBundleQuery _bundleQuery;
private int _bundleLoadingMaxConcurrency; private int _bundleLoadingMaxConcurrency;
private bool _webGLForceSyncLoadAsset;
// 开发者配置选项
public bool WebGLForceSyncLoadAsset { private set; get; }
public bool UseWeakReferenceHandle { private set; get; }
/// <summary> /// <summary>
/// 所属包裹 /// 所属包裹
@ -44,7 +47,8 @@ namespace YooAsset
public void Initialize(InitializeParameters parameters, IBundleQuery bundleServices) public void Initialize(InitializeParameters parameters, IBundleQuery bundleServices)
{ {
_bundleLoadingMaxConcurrency = parameters.BundleLoadingMaxConcurrency; _bundleLoadingMaxConcurrency = parameters.BundleLoadingMaxConcurrency;
_webGLForceSyncLoadAsset = parameters.WebGLForceSyncLoadAsset; WebGLForceSyncLoadAsset = parameters.WebGLForceSyncLoadAsset;
UseWeakReferenceHandle = parameters.UseWeakReferenceHandle;
_bundleQuery = bundleServices; _bundleQuery = bundleServices;
SceneManager.sceneUnloaded += OnSceneUnloaded; SceneManager.sceneUnloaded += OnSceneUnloaded;
} }
@ -331,10 +335,6 @@ namespace YooAsset
{ {
return BundleLoadingCounter >= _bundleLoadingMaxConcurrency; return BundleLoadingCounter >= _bundleLoadingMaxConcurrency;
} }
internal bool WebGLForceSyncLoadAsset()
{
return _webGLForceSyncLoadAsset;
}
private LoadBundleFileOperation CreateBundleFileLoaderInternal(BundleInfo bundleInfo) private LoadBundleFileOperation CreateBundleFileLoaderInternal(BundleInfo bundleInfo)
{ {

View File

@ -16,6 +16,6 @@ namespace YooAsset
/// <summary> /// <summary>
/// 文件格式版本 /// 文件格式版本
/// </summary> /// </summary>
public const string FileVersion = "2.3.1"; public const string FileVersion = "2025.8.28";
} }
} }

View File

@ -59,6 +59,7 @@ namespace YooAsset
// 写入文件头信息 // 写入文件头信息
buffer.WriteBool(manifest.EnableAddressable); buffer.WriteBool(manifest.EnableAddressable);
buffer.WriteBool(manifest.SupportExtensionless);
buffer.WriteBool(manifest.LocationToLower); buffer.WriteBool(manifest.LocationToLower);
buffer.WriteBool(manifest.IncludeAssetGUID); buffer.WriteBool(manifest.IncludeAssetGUID);
buffer.WriteInt32(manifest.OutputNameStyle); buffer.WriteInt32(manifest.OutputNameStyle);
@ -89,7 +90,7 @@ namespace YooAsset
buffer.WriteUTF8(packageBundle.BundleName); buffer.WriteUTF8(packageBundle.BundleName);
buffer.WriteUInt32(packageBundle.UnityCRC); buffer.WriteUInt32(packageBundle.UnityCRC);
buffer.WriteUTF8(packageBundle.FileHash); buffer.WriteUTF8(packageBundle.FileHash);
buffer.WriteUTF8(packageBundle.FileCRC); buffer.WriteUInt32(packageBundle.FileCRC);
buffer.WriteInt64(packageBundle.FileSize); buffer.WriteInt64(packageBundle.FileSize);
buffer.WriteBool(packageBundle.Encrypted); buffer.WriteBool(packageBundle.Encrypted);
buffer.WriteUTF8Array(packageBundle.Tags); buffer.WriteUTF8Array(packageBundle.Tags);
@ -153,6 +154,7 @@ namespace YooAsset
// 读取文件头信息 // 读取文件头信息
manifest.FileVersion = fileVersion; manifest.FileVersion = fileVersion;
manifest.EnableAddressable = buffer.ReadBool(); manifest.EnableAddressable = buffer.ReadBool();
manifest.SupportExtensionless = buffer.ReadBool();
manifest.LocationToLower = buffer.ReadBool(); manifest.LocationToLower = buffer.ReadBool();
manifest.IncludeAssetGUID = buffer.ReadBool(); manifest.IncludeAssetGUID = buffer.ReadBool();
manifest.OutputNameStyle = buffer.ReadInt32(); manifest.OutputNameStyle = buffer.ReadInt32();
@ -190,7 +192,7 @@ namespace YooAsset
packageBundle.BundleName = buffer.ReadUTF8(); packageBundle.BundleName = buffer.ReadUTF8();
packageBundle.UnityCRC = buffer.ReadUInt32(); packageBundle.UnityCRC = buffer.ReadUInt32();
packageBundle.FileHash = buffer.ReadUTF8(); packageBundle.FileHash = buffer.ReadUTF8();
packageBundle.FileCRC = buffer.ReadUTF8(); packageBundle.FileCRC = buffer.ReadUInt32();
packageBundle.FileSize = buffer.ReadInt64(); packageBundle.FileSize = buffer.ReadInt64();
packageBundle.Encrypted = buffer.ReadBool(); packageBundle.Encrypted = buffer.ReadBool();
packageBundle.Tags = buffer.ReadUTF8Array(); packageBundle.Tags = buffer.ReadUTF8Array();
@ -280,13 +282,16 @@ namespace YooAsset
manifest.AssetPathMapping1.Add(location, packageAsset.AssetPath); manifest.AssetPathMapping1.Add(location, packageAsset.AssetPath);
// 添加无后缀名路径的映射 // 添加无后缀名路径的映射
string locationWithoutExtension = Path.ChangeExtension(location, null); if (manifest.SupportExtensionless)
if (ReferenceEquals(location, locationWithoutExtension) == false)
{ {
if (manifest.AssetPathMapping1.ContainsKey(locationWithoutExtension)) string locationWithoutExtension = Path.ChangeExtension(location, null);
YooLogger.Warning($"Location have existed : {locationWithoutExtension}"); if (ReferenceEquals(location, locationWithoutExtension) == false)
else {
manifest.AssetPathMapping1.Add(locationWithoutExtension, packageAsset.AssetPath); if (manifest.AssetPathMapping1.ContainsKey(locationWithoutExtension))
YooLogger.Warning($"Location have existed : {locationWithoutExtension}");
else
manifest.AssetPathMapping1.Add(locationWithoutExtension, packageAsset.AssetPath);
}
} }
} }

View File

@ -96,6 +96,7 @@ namespace YooAsset
Manifest = new PackageManifest(); Manifest = new PackageManifest();
Manifest.FileVersion = fileVersion; Manifest.FileVersion = fileVersion;
Manifest.EnableAddressable = _buffer.ReadBool(); Manifest.EnableAddressable = _buffer.ReadBool();
Manifest.SupportExtensionless = _buffer.ReadBool();
Manifest.LocationToLower = _buffer.ReadBool(); Manifest.LocationToLower = _buffer.ReadBool();
Manifest.IncludeAssetGUID = _buffer.ReadBool(); Manifest.IncludeAssetGUID = _buffer.ReadBool();
Manifest.OutputNameStyle = _buffer.ReadInt32(); Manifest.OutputNameStyle = _buffer.ReadInt32();
@ -159,7 +160,7 @@ namespace YooAsset
packageBundle.BundleName = _buffer.ReadUTF8(); packageBundle.BundleName = _buffer.ReadUTF8();
packageBundle.UnityCRC = _buffer.ReadUInt32(); packageBundle.UnityCRC = _buffer.ReadUInt32();
packageBundle.FileHash = _buffer.ReadUTF8(); packageBundle.FileHash = _buffer.ReadUTF8();
packageBundle.FileCRC = _buffer.ReadUTF8(); packageBundle.FileCRC = _buffer.ReadUInt32();
packageBundle.FileSize = _buffer.ReadInt64(); packageBundle.FileSize = _buffer.ReadInt64();
packageBundle.Encrypted = _buffer.ReadBool(); packageBundle.Encrypted = _buffer.ReadBool();
packageBundle.Tags = _buffer.ReadUTF8Array(); packageBundle.Tags = _buffer.ReadUTF8Array();

View File

@ -25,7 +25,7 @@ namespace YooAsset
/// <summary> /// <summary>
/// 文件校验码 /// 文件校验码
/// </summary> /// </summary>
public string FileCRC; public uint FileCRC;
/// <summary> /// <summary>
/// 文件大小(字节数) /// 文件大小(字节数)

View File

@ -13,6 +13,11 @@ namespace YooAsset
/// </summary> /// </summary>
public bool EnableAddressable; public bool EnableAddressable;
/// <summary>
/// 支持无后缀名的资源定位地址
/// </summary>
public bool SupportExtensionless;
/// <summary> /// <summary>
/// 资源定位地址大小写不敏感 /// 资源定位地址大小写不敏感
/// </summary> /// </summary>

View File

@ -21,6 +21,11 @@ namespace YooAsset
/// </summary> /// </summary>
public bool EnableAddressable; public bool EnableAddressable;
/// <summary>
/// 支持无后缀名的资源定位地址
/// </summary>
public bool SupportExtensionless;
/// <summary> /// <summary>
/// 资源定位地址大小写不敏感 /// 资源定位地址大小写不敏感
/// </summary> /// </summary>
@ -116,6 +121,7 @@ namespace YooAsset
PackageDetails details = new PackageDetails(); PackageDetails details = new PackageDetails();
details.FileVersion = FileVersion; details.FileVersion = FileVersion;
details.EnableAddressable = EnableAddressable; details.EnableAddressable = EnableAddressable;
details.SupportExtensionless = SupportExtensionless;
details.LocationToLower = LocationToLower; details.LocationToLower = LocationToLower;
details.IncludeAssetGUID = IncludeAssetGUID; details.IncludeAssetGUID = IncludeAssetGUID;
details.OutputNameStyle = OutputNameStyle; details.OutputNameStyle = OutputNameStyle;

View File

@ -251,7 +251,7 @@ namespace YooAsset
/// 预下载指定版本的包裹资源 /// 预下载指定版本的包裹资源
/// </summary> /// </summary>
/// <param name="packageVersion">包裹版本</param> /// <param name="packageVersion">包裹版本</param>
/// <param name="timeout">超时时间默认值60秒</param> /// <param name="timeout">资源清单下载的超时时间默认值60秒</param>
public PreDownloadContentOperation PreDownloadContentAsync(string packageVersion, int timeout = 60) public PreDownloadContentOperation PreDownloadContentAsync(string packageVersion, int timeout = 60)
{ {
DebugCheckInitialize(false); DebugCheckInitialize(false);

View File

@ -73,6 +73,17 @@ namespace YooAsset
{ {
private uint _currentCrc; private uint _currentCrc;
/// <summary>
/// Gets the computed hash value.
/// </summary>
public uint CRCValue
{
get
{
return _currentCrc;
}
}
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="CRC32Algorithm"/> class. /// Initializes a new instance of the <see cref="CRC32Algorithm"/> class.
/// </summary> /// </summary>

View File

@ -339,6 +339,11 @@ namespace YooAsset
byte[] buffer = Encoding.UTF8.GetBytes(str); byte[] buffer = Encoding.UTF8.GetBytes(str);
return BytesCRC32(buffer); return BytesCRC32(buffer);
} }
public static uint StringCRC32Value(string str)
{
byte[] buffer = Encoding.UTF8.GetBytes(str);
return BytesCRC32Value(buffer);
}
/// <summary> /// <summary>
/// 获取文件的CRC32 /// 获取文件的CRC32
@ -350,6 +355,13 @@ namespace YooAsset
return StreamCRC32(fs); return StreamCRC32(fs);
} }
} }
public static uint FileCRC32Value(string filePath)
{
using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
{
return StreamCRC32Value(fs);
}
}
/// <summary> /// <summary>
/// 获取文件的CRC32 /// 获取文件的CRC32
@ -366,6 +378,18 @@ namespace YooAsset
return string.Empty; return string.Empty;
} }
} }
public static uint FileCRC32ValueSafely(string filePath)
{
try
{
return FileCRC32Value(filePath);
}
catch (Exception e)
{
YooLogger.Exception(e);
return 0;
}
}
/// <summary> /// <summary>
/// 获取数据流的CRC32 /// 获取数据流的CRC32
@ -376,6 +400,12 @@ namespace YooAsset
byte[] hashBytes = hash.ComputeHash(stream); byte[] hashBytes = hash.ComputeHash(stream);
return ToString(hashBytes); return ToString(hashBytes);
} }
public static uint StreamCRC32Value(Stream stream)
{
CRC32Algorithm hash = new CRC32Algorithm();
hash.ComputeHash(stream);
return hash.CRCValue;
}
/// <summary> /// <summary>
/// 获取字节数组的CRC32 /// 获取字节数组的CRC32
@ -386,6 +416,12 @@ namespace YooAsset
byte[] hashBytes = hash.ComputeHash(buffer); byte[] hashBytes = hash.ComputeHash(buffer);
return ToString(hashBytes); return ToString(hashBytes);
} }
public static uint BytesCRC32Value(byte[] buffer)
{
CRC32Algorithm hash = new CRC32Algorithm();
hash.ComputeHash(buffer);
return hash.CRCValue;
}
#endregion #endregion
} }
} }

View File

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

View File

@ -0,0 +1,21 @@
using System;
using UnityEngine;
using YooAsset;
public static class OperationMonitor
{
public static void RegisterOperationCallback()
{
OperationSystem.RegisterStartCallback(OperationStartCallback);
OperationSystem.RegisterFinishCallback(OperationFinishCallback);
}
private static void OperationStartCallback(string packageName, AsyncOperationBase operation)
{
Debug.Log($"Operation start : {operation.GetType().Name}");
}
private static void OperationFinishCallback(string packageName, AsyncOperationBase operation)
{
Debug.Log($"Operation finish : {operation.GetType().Name}");
}
}

View File

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

View File

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

View File

@ -0,0 +1,280 @@
#if UNITY_WEBGL && UNITY_ALIMINIGAME
using System;
using System.Collections.Generic;
using UnityEngine;
using YooAsset;
using AlipaySdk;
public static class AlipayFileSystemCreater
{
public static FileSystemParameters CreateFileSystemParameters(string packageRoot, IRemoteServices remoteServices)
{
string fileSystemClass = $"{nameof(AlipayFileSystem)},YooAsset.MiniGame";
var fileSystemParams = new FileSystemParameters(fileSystemClass, packageRoot);
fileSystemParams.AddParameter(FileSystemParametersDefine.REMOTE_SERVICES, remoteServices);
return fileSystemParams;
}
public static FileSystemParameters CreateFileSystemParameters(string packageRoot, IRemoteServices remoteServices, IWebDecryptionServices decryptionServices)
{
string fileSystemClass = $"{nameof(AlipayFileSystem)},YooAsset.MiniGame";
var fileSystemParams = new FileSystemParameters(fileSystemClass, packageRoot);
fileSystemParams.AddParameter(FileSystemParametersDefine.REMOTE_SERVICES, remoteServices);
fileSystemParams.AddParameter(FileSystemParametersDefine.DECRYPTION_SERVICES, decryptionServices);
return fileSystemParams;
}
}
/// <summary>
/// 支付宝小游戏文件系统
/// 参考https://opendocs.alipay.com/mini-game/0ftleg
/// </summary>
internal class AlipayFileSystem : IFileSystem
{
private class WebRemoteServices : IRemoteServices
{
private readonly string _webPackageRoot;
protected readonly Dictionary<string, string> _mapping = new Dictionary<string, string>(10000);
public WebRemoteServices(string buildinPackRoot)
{
_webPackageRoot = buildinPackRoot;
}
string IRemoteServices.GetRemoteMainURL(string fileName)
{
return GetFileLoadURL(fileName);
}
string IRemoteServices.GetRemoteFallbackURL(string fileName)
{
return GetFileLoadURL(fileName);
}
private string GetFileLoadURL(string fileName)
{
if (_mapping.TryGetValue(fileName, out string url) == false)
{
string filePath = PathUtility.Combine(_webPackageRoot, fileName);
url = DownloadSystemHelper.ConvertToWWWPath(filePath);
_mapping.Add(fileName, url);
}
return url;
}
}
private readonly Dictionary<string, string> _cacheFilePathMapping = new Dictionary<string, string>(10000);
private AlipayFSManager _fileSystemMgr;
private string _aliCacheRoot = string.Empty;
/// <summary>
/// 包裹名称
/// </summary>
public string PackageName { private set; get; }
/// <summary>
/// 文件根目录
/// </summary>
public string FileRoot
{
get
{
return _aliCacheRoot;
}
}
/// <summary>
/// 文件数量
/// </summary>
public int FileCount
{
get
{
return 0;
}
}
#region
/// <summary>
/// 自定义参数:远程服务接口
/// </summary>
public IRemoteServices RemoteServices { private set; get; } = null;
/// <summary>
/// 自定义参数:解密方法类
/// </summary>
public IWebDecryptionServices DecryptionServices { private set; get; }
/// <summary>
/// 自定义参数:资源清单服务类
/// </summary>
public IManifestRestoreServices ManifestServices { private set; get; }
#endregion
public AlipayFileSystem()
{
}
public virtual FSInitializeFileSystemOperation InitializeFileSystemAsync()
{
var operation = new APFSInitializeOperation(this);
return operation;
}
public virtual FSLoadPackageManifestOperation LoadPackageManifestAsync(string packageVersion, int timeout)
{
var operation = new APFSLoadPackageManifestOperation(this, packageVersion, timeout);
return operation;
}
public virtual FSRequestPackageVersionOperation RequestPackageVersionAsync(bool appendTimeTicks, int timeout)
{
var operation = new APFSRequestPackageVersionOperation(this, appendTimeTicks, timeout);
return operation;
}
public virtual FSClearCacheFilesOperation ClearCacheFilesAsync(PackageManifest manifest, ClearCacheFilesOptions options)
{
var operation = new FSClearCacheFilesCompleteOperation();
return operation;
}
public virtual FSDownloadFileOperation DownloadFileAsync(PackageBundle bundle, DownloadFileOptions options)
{
string mainURL = RemoteServices.GetRemoteMainURL(bundle.FileName);
string fallbackURL = RemoteServices.GetRemoteFallbackURL(bundle.FileName);
options.SetURL(mainURL, fallbackURL);
var operation = new APFSDownloadFileOperation(this, bundle, options);
return operation;
}
public virtual FSLoadBundleOperation LoadBundleFile(PackageBundle bundle)
{
if (bundle.BundleType == (int)EBuildBundleType.AssetBundle)
{
var operation = new APFSLoadBundleOperation(this, bundle);
return operation;
}
else
{
string error = $"{nameof(AlipayFileSystem)} not support load bundle type : {bundle.BundleType}";
var operation = new FSLoadBundleCompleteOperation(error);
return operation;
}
}
public virtual void SetParameter(string name, object value)
{
if (name == FileSystemParametersDefine.REMOTE_SERVICES)
{
RemoteServices = (IRemoteServices)value;
}
else if (name == FileSystemParametersDefine.DECRYPTION_SERVICES)
{
DecryptionServices = (IWebDecryptionServices)value;
}
else if (name == FileSystemParametersDefine.MANIFEST_SERVICES)
{
ManifestServices = (IManifestRestoreServices)value;
}
else
{
YooLogger.Warning($"Invalid parameter : {name}");
}
}
public virtual void OnCreate(string packageName, string rootDirectory)
{
PackageName = packageName;
_aliCacheRoot = rootDirectory;
if (string.IsNullOrEmpty(_aliCacheRoot))
{
throw new System.Exception("请配置小游戏的缓存根目录!");
}
// 注意CDN服务未启用的情况下使用WEB服务器
if (RemoteServices == null)
{
string webRoot = PathUtility.Combine(Application.streamingAssetsPath, YooAssetSettingsData.Setting.DefaultYooFolderName, packageName);
RemoteServices = new WebRemoteServices(webRoot);
}
_fileSystemMgr = AlipaySDK.API.GetFileSystemManager();
}
public virtual void OnDestroy()
{
}
public virtual bool Belong(PackageBundle bundle)
{
return true;
}
public virtual bool Exists(PackageBundle bundle)
{
return CheckCacheFileExist(bundle);
}
public virtual bool NeedDownload(PackageBundle bundle)
{
if (Belong(bundle) == false)
return false;
return Exists(bundle) == false;
}
public virtual bool NeedUnpack(PackageBundle bundle)
{
return false;
}
public virtual bool NeedImport(PackageBundle bundle)
{
return false;
}
public virtual string GetBundleFilePath(PackageBundle bundle)
{
return GetCacheFileLoadPath(bundle);
}
public virtual byte[] ReadBundleFileData(PackageBundle bundle)
{
if (CheckCacheFileExist(bundle))
{
string filePath = GetCacheFileLoadPath(bundle);
return _fileSystemMgr.ReadFileSync(filePath);
}
else
{
return Array.Empty<byte>();
}
}
public virtual string ReadBundleFileText(PackageBundle bundle)
{
if (CheckCacheFileExist(bundle))
{
string filePath = GetCacheFileLoadPath(bundle);
return _fileSystemMgr.ReadFileSync(filePath, "utf8");
}
else
{
return string.Empty;
}
}
#region
public AlipayFSManager GetFileSystemMgr()
{
return _fileSystemMgr;
}
public bool CheckCacheFileExist(PackageBundle bundle)
{
//TODO : 效率极低
/*
string filePath = GetCacheFileLoadPath(bundle);
string result = _fileSystemMgr.AccessSync(filePath);
return result.Equals("access:ok", StringComparison.Ordinal);
*/
return false;
}
private string GetCacheFileLoadPath(PackageBundle bundle)
{
if (_cacheFilePathMapping.TryGetValue(bundle.BundleGUID, out string filePath) == false)
{
filePath = PathUtility.Combine(_aliCacheRoot, bundle.FileName);
_cacheFilePathMapping.Add(bundle.BundleGUID, filePath);
}
return filePath;
}
#endregion
}
#endif

View File

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

View File

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

View File

@ -0,0 +1,67 @@
#if UNITY_WEBGL && UNITY_ALIMINIGAME
using System.IO;
using UnityEngine;
using UnityEngine.SceneManagement;
using AlipaySdk;
namespace YooAsset
{
internal class APAssetBundleResult : BundleResult
{
private readonly IFileSystem _fileSystem;
private readonly PackageBundle _packageBundle;
private readonly AssetBundle _assetBundle;
public APAssetBundleResult(IFileSystem fileSystem, PackageBundle packageBundle, AssetBundle assetBundle)
{
_fileSystem = fileSystem;
_packageBundle = packageBundle;
_assetBundle = assetBundle;
}
public override void UnloadBundleFile()
{
if (_assetBundle != null)
{
if (_packageBundle.Encrypted)
_assetBundle.Unload(true);
else
_assetBundle.APUnload(true);
}
}
public override string GetBundleFilePath()
{
return _fileSystem.GetBundleFilePath(_packageBundle);
}
public override byte[] ReadBundleFileData()
{
return _fileSystem.ReadBundleFileData(_packageBundle);
}
public override string ReadBundleFileText()
{
return _fileSystem.ReadBundleFileText(_packageBundle);
}
public override FSLoadAssetOperation LoadAssetAsync(AssetInfo assetInfo)
{
var operation = new AssetBundleLoadAssetOperation(_packageBundle, _assetBundle, assetInfo);
return operation;
}
public override FSLoadAllAssetsOperation LoadAllAssetsAsync(AssetInfo assetInfo)
{
var operation = new AssetBundleLoadAllAssetsOperation(_packageBundle, _assetBundle, assetInfo);
return operation;
}
public override FSLoadSubAssetsOperation LoadSubAssetsAsync(AssetInfo assetInfo)
{
var operation = new AssetBundleLoadSubAssetsOperation(_packageBundle, _assetBundle, assetInfo);
return operation;
}
public override FSLoadSceneOperation LoadSceneOperation(AssetInfo assetInfo, LoadSceneParameters loadParams, bool suspendLoad)
{
var operation = new AssetBundleLoadSceneOperation(assetInfo, loadParams, suspendLoad);
return operation;
}
}
}
#endif

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