mirror of
https://github.com/tuyoogame/YooAsset.git
synced 2026-06-19 02:23:44 +00:00
Compare commits
35 Commits
3.0.1-beta
...
3.0.3-beta
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bfb166ad91 | ||
|
|
f31e24bf59 | ||
|
|
868a186199 | ||
|
|
092af257d7 | ||
|
|
d39d9b59ef | ||
|
|
31c09d53bb | ||
|
|
a6299268d3 | ||
|
|
89b516942e | ||
|
|
8c49c27264 | ||
|
|
51c8c00604 | ||
|
|
cb96767f2d | ||
|
|
55d98dde02 | ||
|
|
f631d67db3 | ||
|
|
a2fa8ff6fc | ||
|
|
477954377d | ||
|
|
513c1d0b18 | ||
|
|
289dee326b | ||
|
|
d5a9b9f0f4 | ||
|
|
aff50317cb | ||
|
|
9e969d34f6 | ||
|
|
926f72d129 | ||
|
|
72c5a9588e | ||
|
|
af7aecbf0b | ||
|
|
d337a86e68 | ||
|
|
9c05f3514e | ||
|
|
b31bb1bcfb | ||
|
|
92e34fb8b5 | ||
|
|
687dc1d9e9 | ||
|
|
7842235af6 | ||
|
|
0142828b91 | ||
|
|
a36a7cc6d2 | ||
|
|
485ed5198e | ||
|
|
2170156216 | ||
|
|
99b975554a | ||
|
|
2f8355c3f4 |
@@ -2,6 +2,87 @@
|
|||||||
|
|
||||||
All notable changes to this package will be documented in this file.
|
All notable changes to this package will be documented in this file.
|
||||||
|
|
||||||
|
## [3.0.3-beta] - 2026-06-18
|
||||||
|
|
||||||
|
本版本重点优化资源清单二进制结构,显著减小清单体积、同时降低运行时内存占用并提升资源定位查询效率。。
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- 新增 `AssetInfo.Tags` 资源标签访问接口
|
||||||
|
|
||||||
|
支持通过 `AssetInfo` 直接访问资源标签集合,便于在资源查询结果中判断和遍历标签。
|
||||||
|
|
||||||
|
- 新增 Bundle Collector 可编辑 Inspector 扩展
|
||||||
|
|
||||||
|
支持在 Inspector 面板中扩展和编辑 Bundle Collector 相关配置,方便自定义收集器配置界面。
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- 优化资源清单二进制结构
|
||||||
|
|
||||||
|
减小资源清单文件体积,降低运行时内存占用,并提升资源定位查询效率。
|
||||||
|
|
||||||
|
小型清单体积约减少 20%,重度项目预计可减少 35%~50%。
|
||||||
|
|
||||||
|
- 重构 `AssetReference`
|
||||||
|
|
||||||
|
调整资源引用相关实现,提升接口一致性和维护性,新增对 `Texture2D` 的支持。
|
||||||
|
|
||||||
|
- 调整编辑器缓存目录位置
|
||||||
|
|
||||||
|
编辑器模式下的缓存根目录调整到项目 `Library` 目录内,避免缓存文件直接生成在项目根目录,减少对工程目录的污染。
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- (#752) 修复小游戏扩展类解密器枚举命名错误。
|
||||||
|
|
||||||
|
- (#660) 修复了UniTask扩展类里 IL2CPP 逆变委托崩溃。
|
||||||
|
|
||||||
|
|
||||||
|
## [3.0.2-beta] - 2026-05-28
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- 新增 `WebNetworkFileSystem` 文件系统
|
||||||
|
|
||||||
|
用于统一 WebGL 远程加载和 Mini Game 平台资源加载流程,并通过 `IWebPlatformStrategy` 适配不同平台的 AssetBundle 请求、提取和卸载行为。
|
||||||
|
|
||||||
|
- 新增 Web 文件系统对 `RawBundle` 和 `ArchiveBundle` 的加载支持
|
||||||
|
|
||||||
|
`WebServerFileSystem` 和 `WebNetworkFileSystem` 支持在 WebGL 平台加载原始文件包和归档资源包。
|
||||||
|
|
||||||
|
- 新增加密 `ArchiveBundle` 构建和加载支持
|
||||||
|
|
||||||
|
`ArchiveFileBuildPipeline` 支持加密归档资源包,运行时可通过 `EFileSystemParameter.ArchiveBundleDecryptor` 配置对应解密器。
|
||||||
|
|
||||||
|
- 新增 `IBundleUnpackPolicy` 内置资源包解包策略
|
||||||
|
|
||||||
|
支持根据资源包名称、文件名、类型、加密状态和标签,自定义哪些内置资源包需要解包。
|
||||||
|
|
||||||
|
- 新增 `IBuiltinFileAccessor` 内置文件访问器
|
||||||
|
|
||||||
|
支持为 `StreamingAssets` 文件提供自定义存在检测和字节读取能力,方便 Android 等平台接入第三方同步读取方案。
|
||||||
|
|
||||||
|
- 新增 Bundle Collector 资源搜索功能
|
||||||
|
|
||||||
|
支持在收集器窗口输入或拖入资源路径,定位资源所在的分组和收集器,并高亮命中的资源配置。
|
||||||
|
|
||||||
|
- 新增 Mini Game 平台示例
|
||||||
|
|
||||||
|
补充 OPPO、vivo、快手小游戏文件系统示例。
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- WebGL 运行模式文件系统结构调整
|
||||||
|
|
||||||
|
移除旧版 `WebGameFileSystem` 和 `WebRemoteFileSystem`,相关能力已合并到新的文件系统 `WebNetworkFileSystem`。
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- 修复微信小游戏示例宏兼容问题
|
||||||
|
|
||||||
|
微信小游戏文件系统同时支持 `WEIXINMINIGAME` 和 `UNITY_WECHATMINIGAME` 宏。
|
||||||
|
|
||||||
## [3.0.1-beta] - 2026-05-19
|
## [3.0.1-beta] - 2026-05-19
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
@@ -216,19 +216,19 @@ namespace YooAsset.Editor
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 创建PackageBundle类
|
/// 创建BuildBundle类
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal PackageBundle CreatePackageBundle()
|
internal BuildBundle CreateBuildBundle()
|
||||||
{
|
{
|
||||||
PackageBundle packageBundle = new PackageBundle();
|
BuildBundle buildBundle = new BuildBundle();
|
||||||
packageBundle.BundleName = BundleName;
|
buildBundle.BundleName = BundleName;
|
||||||
packageBundle.UnityCrc = PackageUnityCRC;
|
buildBundle.UnityCrc = PackageUnityCRC;
|
||||||
packageBundle.FileHash = PackageFileHash;
|
buildBundle.FileHash = PackageFileHash;
|
||||||
packageBundle.FileCrc = PackageFileCRC;
|
buildBundle.FileCrc = PackageFileCRC;
|
||||||
packageBundle.FileSize = PackageFileSize;
|
buildBundle.FileSize = PackageFileSize;
|
||||||
packageBundle.IsEncrypted = Encrypted;
|
buildBundle.IsEncrypted = Encrypted;
|
||||||
packageBundle.DependentBundleIDs = Array.Empty<int>();
|
buildBundle.DependentBundleIDs = Array.Empty<int>();
|
||||||
return packageBundle;
|
return buildBundle;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -27,14 +27,6 @@ namespace YooAsset.Editor
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void CheckBuildParametersCore()
|
protected override void CheckBuildParametersCore()
|
||||||
{
|
{
|
||||||
// ArchiveBundle 不支持资源包加密
|
|
||||||
if (BundleEncryptor != null)
|
|
||||||
{
|
|
||||||
string message = BuildLogger.GetErrorMessage(ErrorCode.BundleEncryptionNotSupported,
|
|
||||||
$"ArchiveFileBuildPipeline does not support bundle encryption. Please remove the BundleEncryptor configuration.");
|
|
||||||
throw new NotSupportedException(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 校验文件对齐参数范围
|
// 校验文件对齐参数范围
|
||||||
if (FileAlignment < 0 || FileAlignment > MaxFileAlignment)
|
if (FileAlignment < 0 || FileAlignment > MaxFileAlignment)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#if TUANJIE_1_8_OR_NEWER
|
#if TUANJIE_1_8_OR_NEWER && YOOASSET_INSTANT_ASSET_SUPPORT
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#if TUANJIE_1_8_OR_NEWER
|
#if TUANJIE_1_8_OR_NEWER && YOOASSET_INSTANT_ASSET_SUPPORT
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
|
|
||||||
namespace YooAsset.Editor
|
namespace YooAsset.Editor
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#if TUANJIE_1_8_OR_NEWER
|
#if TUANJIE_1_8_OR_NEWER && YOOASSET_INSTANT_ASSET_SUPPORT
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace YooAsset.Editor
|
namespace YooAsset.Editor
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#if TUANJIE_1_8_OR_NEWER
|
#if TUANJIE_1_8_OR_NEWER && YOOASSET_INSTANT_ASSET_SUPPORT
|
||||||
namespace YooAsset.Editor
|
namespace YooAsset.Editor
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#if TUANJIE_1_8_OR_NEWER
|
#if TUANJIE_1_8_OR_NEWER && YOOASSET_INSTANT_ASSET_SUPPORT
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace YooAsset.Editor
|
namespace YooAsset.Editor
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#if TUANJIE_1_8_OR_NEWER
|
#if TUANJIE_1_8_OR_NEWER && YOOASSET_INSTANT_ASSET_SUPPORT
|
||||||
namespace YooAsset.Editor
|
namespace YooAsset.Editor
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#if TUANJIE_1_8_OR_NEWER
|
#if TUANJIE_1_8_OR_NEWER && YOOASSET_INSTANT_ASSET_SUPPORT
|
||||||
namespace YooAsset.Editor
|
namespace YooAsset.Editor
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#if TUANJIE_1_8_OR_NEWER
|
#if TUANJIE_1_8_OR_NEWER && YOOASSET_INSTANT_ASSET_SUPPORT
|
||||||
namespace YooAsset.Editor
|
namespace YooAsset.Editor
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#if TUANJIE_1_8_OR_NEWER
|
#if TUANJIE_1_8_OR_NEWER && YOOASSET_INSTANT_ASSET_SUPPORT
|
||||||
using System;
|
using System;
|
||||||
|
|
||||||
namespace YooAsset.Editor
|
namespace YooAsset.Editor
|
||||||
@@ -68,8 +68,7 @@ namespace YooAsset.Editor
|
|||||||
{
|
{
|
||||||
string bundleName = bundleInfo.BundleName;
|
string bundleName = bundleInfo.BundleName;
|
||||||
string fileHash = bundleInfo.PackageFileHash;
|
string fileHash = bundleInfo.PackageFileHash;
|
||||||
string fileExtension = PackageManifestHelper.GetRemoteBundleFileExtension(bundleName);
|
string fileName = BundleFileNaming.GetBundleFileName(outputNameStyle, bundleName, fileHash);
|
||||||
string fileName = PackageManifestHelper.GetRemoteBundleFileName(outputNameStyle, bundleName, fileExtension, fileHash);
|
|
||||||
bundleInfo.PackageDestFilePath = $"{packageOutputDirectory}/{fileName}";
|
bundleInfo.PackageDestFilePath = $"{packageOutputDirectory}/{fileName}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#if TUANJIE_1_8_OR_NEWER
|
#if TUANJIE_1_8_OR_NEWER && YOOASSET_INSTANT_ASSET_SUPPORT
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#if TUANJIE_1_8_OR_NEWER
|
#if TUANJIE_1_8_OR_NEWER && YOOASSET_INSTANT_ASSET_SUPPORT
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#if TUANJIE_1_8_OR_NEWER
|
#if TUANJIE_1_8_OR_NEWER && YOOASSET_INSTANT_ASSET_SUPPORT
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
|
|
||||||
namespace YooAsset.Editor
|
namespace YooAsset.Editor
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#if TUANJIE_1_8_OR_NEWER
|
#if TUANJIE_1_8_OR_NEWER && YOOASSET_INSTANT_ASSET_SUPPORT
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#if TUANJIE_1_8_OR_NEWER
|
#if TUANJIE_1_8_OR_NEWER && YOOASSET_INSTANT_ASSET_SUPPORT
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ namespace YooAsset.Editor
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 拷贝首包资源文件
|
/// 拷贝首包资源文件
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal void CopyBundledFilesToStreaming(BuildParametersContext buildParametersContext, PackageManifest manifest)
|
internal void CopyBundledFilesToStreaming(BuildParametersContext buildParametersContext, BuildManifest manifest)
|
||||||
{
|
{
|
||||||
EBundledCopyOption copyOption = buildParametersContext.Parameters.BundledCopyOption;
|
EBundledCopyOption copyOption = buildParametersContext.Parameters.BundledCopyOption;
|
||||||
string packageOutputDirectory = buildParametersContext.GetPackageOutputDirectory();
|
string packageOutputDirectory = buildParametersContext.GetPackageOutputDirectory();
|
||||||
@@ -67,10 +67,10 @@ namespace YooAsset.Editor
|
|||||||
// 拷贝文件列表(所有文件)
|
// 拷贝文件列表(所有文件)
|
||||||
if (copyOption == EBundledCopyOption.ClearAndCopyAll || copyOption == EBundledCopyOption.OnlyCopyAll)
|
if (copyOption == EBundledCopyOption.ClearAndCopyAll || copyOption == EBundledCopyOption.OnlyCopyAll)
|
||||||
{
|
{
|
||||||
foreach (var packageBundle in manifest.BundleList)
|
foreach (var buildBundle in manifest.BundleList)
|
||||||
{
|
{
|
||||||
string sourcePath = $"{packageOutputDirectory}/{packageBundle.GetFileName()}";
|
string sourcePath = $"{packageOutputDirectory}/{buildBundle.GetFileName(manifest.OutputNameStyle)}";
|
||||||
string destPath = $"{bundledRootDirectory}/{packageBundle.GetFileName()}";
|
string destPath = $"{bundledRootDirectory}/{buildBundle.GetFileName(manifest.OutputNameStyle)}";
|
||||||
EditorFileUtility.CopyFile(sourcePath, destPath, true);
|
EditorFileUtility.CopyFile(sourcePath, destPath, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -85,12 +85,12 @@ namespace YooAsset.Editor
|
|||||||
throw new InvalidOperationException(message);
|
throw new InvalidOperationException(message);
|
||||||
}
|
}
|
||||||
string[] tags = copyParams.Split(';');
|
string[] tags = copyParams.Split(';');
|
||||||
foreach (var packageBundle in manifest.BundleList)
|
foreach (var buildBundle in manifest.BundleList)
|
||||||
{
|
{
|
||||||
if (packageBundle.HasAnyTag(tags) == false)
|
if (buildBundle.HasAnyTag(tags) == false)
|
||||||
continue;
|
continue;
|
||||||
string sourcePath = $"{packageOutputDirectory}/{packageBundle.GetFileName()}";
|
string sourcePath = $"{packageOutputDirectory}/{buildBundle.GetFileName(manifest.OutputNameStyle)}";
|
||||||
string destPath = $"{bundledRootDirectory}/{packageBundle.GetFileName()}";
|
string destPath = $"{bundledRootDirectory}/{buildBundle.GetFileName(manifest.OutputNameStyle)}";
|
||||||
EditorFileUtility.CopyFile(sourcePath, destPath, true);
|
EditorFileUtility.CopyFile(sourcePath, destPath, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ namespace YooAsset.Editor
|
|||||||
[ContextObject]
|
[ContextObject]
|
||||||
public class ManifestContext
|
public class ManifestContext
|
||||||
{
|
{
|
||||||
internal PackageManifest Manifest;
|
internal BuildManifest Manifest;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -44,7 +44,7 @@ namespace YooAsset.Editor
|
|||||||
CheckBundleHashConflict(buildMapContext);
|
CheckBundleHashConflict(buildMapContext);
|
||||||
|
|
||||||
// 创建新补丁清单
|
// 创建新补丁清单
|
||||||
PackageManifest manifest = new PackageManifest();
|
BuildManifest manifest = new BuildManifest();
|
||||||
manifest.FileVersion = PackageManifestConsts.FileVersion;
|
manifest.FileVersion = PackageManifestConsts.FileVersion;
|
||||||
manifest.EnableAddressable = buildMapContext.Command.EnableAddressable;
|
manifest.EnableAddressable = buildMapContext.Command.EnableAddressable;
|
||||||
manifest.SupportExtensionless = buildMapContext.Command.SupportExtensionless;
|
manifest.SupportExtensionless = buildMapContext.Command.SupportExtensionless;
|
||||||
@@ -74,20 +74,15 @@ namespace YooAsset.Editor
|
|||||||
// 4. 处理首包资源包
|
// 4. 处理首包资源包
|
||||||
if (processBundleDepends)
|
if (processBundleDepends)
|
||||||
{
|
{
|
||||||
// 注意:初始化资源清单建立引用关系
|
// 注意:建立资源包引用关系图
|
||||||
manifest.Initialize();
|
manifest.BuildReferrerGraph();
|
||||||
|
|
||||||
ProcessBuiltinBundleDependency(context, manifest);
|
ProcessBuiltinBundleDependency(context, manifest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 5. 构建全局标签表与目录表
|
||||||
// 创建资源清单文本文件
|
manifest.BuildTagTable();
|
||||||
{
|
manifest.BuildDirectoryTable();
|
||||||
string fileName = YooAssetConfiguration.GetManifestJsonFileName(buildParameters.PackageName, buildParameters.PackageVersion);
|
|
||||||
string filePath = $"{packageOutputDirectory}/{fileName}";
|
|
||||||
PackageManifestHelper.SerializeManifestToJson(filePath, manifest);
|
|
||||||
BuildLogger.Log($"Create package manifest file: '{filePath}'.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 创建资源清单二进制文件
|
// 创建资源清单二进制文件
|
||||||
string packageHash;
|
string packageHash;
|
||||||
@@ -119,8 +114,7 @@ namespace YooAsset.Editor
|
|||||||
// 填充上下文
|
// 填充上下文
|
||||||
{
|
{
|
||||||
ManifestContext manifestContext = new ManifestContext();
|
ManifestContext manifestContext = new ManifestContext();
|
||||||
byte[] bytesData = FileUtility.ReadAllBytes(packagePath);
|
manifestContext.Manifest = manifest;
|
||||||
manifestContext.Manifest = PackageManifestHelper.DeserializeManifestFromBinary(bytesData, buildParameters.ManifestDecryptor);
|
|
||||||
context.SetContextObject(manifestContext);
|
context.SetContextObject(manifestContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -158,21 +152,21 @@ namespace YooAsset.Editor
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 创建资源对象列表
|
/// 创建资源对象列表
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private List<PackageAsset> CreatePackageAssetList(BuildMapContext buildMapContext)
|
private List<BuildAsset> CreatePackageAssetList(BuildMapContext buildMapContext)
|
||||||
{
|
{
|
||||||
List<PackageAsset> result = new List<PackageAsset>(1000);
|
List<BuildAsset> result = new List<BuildAsset>(1000);
|
||||||
foreach (var bundleInfo in buildMapContext.Collection)
|
foreach (var bundleInfo in buildMapContext.Collection)
|
||||||
{
|
{
|
||||||
var assetInfos = bundleInfo.GetAllManifestAssetInfos();
|
var assetInfos = bundleInfo.GetAllManifestAssetInfos();
|
||||||
foreach (var assetInfo in assetInfos)
|
foreach (var assetInfo in assetInfos)
|
||||||
{
|
{
|
||||||
PackageAsset packageAsset = new PackageAsset();
|
BuildAsset buildAsset = new BuildAsset();
|
||||||
packageAsset.Address = buildMapContext.Command.EnableAddressable ? assetInfo.Address : string.Empty;
|
buildAsset.Address = buildMapContext.Command.EnableAddressable ? assetInfo.Address : string.Empty;
|
||||||
packageAsset.AssetPath = assetInfo.AssetInfo.AssetPath;
|
buildAsset.AssetPath = assetInfo.AssetInfo.AssetPath;
|
||||||
packageAsset.AssetGuid = buildMapContext.Command.IncludeAssetGUID ? assetInfo.AssetInfo.AssetGUID : string.Empty;
|
buildAsset.AssetGuid = buildMapContext.Command.IncludeAssetGUID ? assetInfo.AssetInfo.AssetGUID : string.Empty;
|
||||||
packageAsset.AssetTags = assetInfo.AssetTags.ToArray();
|
buildAsset.Tags = assetInfo.AssetTags.ToArray();
|
||||||
packageAsset.EditorUserData = assetInfo;
|
buildAsset.EditorUserData = assetInfo;
|
||||||
result.Add(packageAsset);
|
result.Add(buildAsset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,13 +178,13 @@ namespace YooAsset.Editor
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 创建资源包列表
|
/// 创建资源包列表
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private List<PackageBundle> CreatePackageBundleList(BuildMapContext buildMapContext)
|
private List<BuildBundle> CreatePackageBundleList(BuildMapContext buildMapContext)
|
||||||
{
|
{
|
||||||
List<PackageBundle> result = new List<PackageBundle>(1000);
|
List<BuildBundle> result = new List<BuildBundle>(1000);
|
||||||
foreach (var bundleInfo in buildMapContext.Collection)
|
foreach (var bundleInfo in buildMapContext.Collection)
|
||||||
{
|
{
|
||||||
var packageBundle = bundleInfo.CreatePackageBundle();
|
var buildBundle = bundleInfo.CreateBuildBundle();
|
||||||
result.Add(packageBundle);
|
result.Add(buildBundle);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 按照BundleName排序
|
// 按照BundleName排序
|
||||||
@@ -201,7 +195,7 @@ namespace YooAsset.Editor
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 处理资源清单的资源对象列表
|
/// 处理资源清单的资源对象列表
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void ProcessPackageAsset(PackageManifest manifest)
|
private void ProcessPackageAsset(BuildManifest manifest)
|
||||||
{
|
{
|
||||||
// 注意:优先缓存资源包索引
|
// 注意:优先缓存资源包索引
|
||||||
for (int index = 0; index < manifest.BundleList.Count; index++)
|
for (int index = 0; index < manifest.BundleList.Count; index++)
|
||||||
@@ -211,31 +205,31 @@ namespace YooAsset.Editor
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 记录资源对象所属的资源包ID
|
// 记录资源对象所属的资源包ID
|
||||||
foreach (var packageAsset in manifest.AssetList)
|
foreach (var buildAsset in manifest.AssetList)
|
||||||
{
|
{
|
||||||
var assetInfo = packageAsset.EditorUserData as BuildAssetInfo;
|
var assetInfo = buildAsset.EditorUserData as BuildAssetInfo;
|
||||||
packageAsset.BundleID = GetCachedBundleIndexID(assetInfo.BundleName);
|
buildAsset.BundleID = GetCachedBundleIndexID(assetInfo.BundleName);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 记录资源对象依赖的资源包ID集合
|
// 记录资源对象依赖的资源包ID集合
|
||||||
// 注意:依赖关系非引擎构建结果里查询!
|
// 注意:依赖关系非引擎构建结果里查询!
|
||||||
foreach (var packageAsset in manifest.AssetList)
|
foreach (var buildAsset in manifest.AssetList)
|
||||||
{
|
{
|
||||||
var mainAssetInfo = packageAsset.EditorUserData as BuildAssetInfo;
|
var mainAssetInfo = buildAsset.EditorUserData as BuildAssetInfo;
|
||||||
packageAsset.DependentBundleIDs = GetAssetDependBundleIDs(mainAssetInfo);
|
buildAsset.DependentBundleIDs = GetAssetDependBundleIDs(mainAssetInfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 处理资源包的依赖集合
|
/// 处理资源包的依赖集合
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void ProcessBundleDepends(BuildContext context, PackageManifest manifest)
|
private void ProcessBundleDepends(BuildContext context, BuildManifest manifest)
|
||||||
{
|
{
|
||||||
// 查询引擎生成的资源包依赖关系,然后记录到清单
|
// 查询引擎生成的资源包依赖关系,然后记录到清单
|
||||||
foreach (var packageBundle in manifest.BundleList)
|
foreach (var buildBundle in manifest.BundleList)
|
||||||
{
|
{
|
||||||
int mainBundleID = GetCachedBundleIndexID(packageBundle.BundleName);
|
int mainBundleID = GetCachedBundleIndexID(buildBundle.BundleName);
|
||||||
string[] dependNames = GetBundleDepends(context, packageBundle.BundleName);
|
string[] dependNames = GetBundleDepends(context, buildBundle.BundleName);
|
||||||
List<int> dependIDs = new List<int>(dependNames.Length);
|
List<int> dependIDs = new List<int>(dependNames.Length);
|
||||||
foreach (var dependName in dependNames)
|
foreach (var dependName in dependNames)
|
||||||
{
|
{
|
||||||
@@ -246,29 +240,29 @@ namespace YooAsset.Editor
|
|||||||
|
|
||||||
// 排序并填充数据
|
// 排序并填充数据
|
||||||
dependIDs.Sort();
|
dependIDs.Sort();
|
||||||
packageBundle.DependentBundleIDs = dependIDs.ToArray();
|
buildBundle.DependentBundleIDs = dependIDs.ToArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 处理资源包的标签集合
|
/// 处理资源包的标签集合
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void ProcessBundleTags(PackageManifest manifest)
|
private void ProcessBundleTags(BuildManifest manifest)
|
||||||
{
|
{
|
||||||
foreach (var packageBundle in manifest.BundleList)
|
foreach (var buildBundle in manifest.BundleList)
|
||||||
{
|
{
|
||||||
packageBundle.Tags = Array.Empty<string>();
|
buildBundle.Tags = Array.Empty<string>();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 将主资源的标签信息传染给其依赖的资源包集合
|
// 将主资源的标签信息传染给其依赖的资源包集合
|
||||||
foreach (var packageAsset in manifest.AssetList)
|
foreach (var buildAsset in manifest.AssetList)
|
||||||
{
|
{
|
||||||
var assetTags = packageAsset.AssetTags;
|
var assetTags = buildAsset.Tags;
|
||||||
int bundleID = packageAsset.BundleID;
|
int bundleID = buildAsset.BundleID;
|
||||||
CacheBundleTags(bundleID, assetTags);
|
CacheBundleTags(bundleID, assetTags);
|
||||||
if (packageAsset.DependentBundleIDs != null)
|
if (buildAsset.DependentBundleIDs != null)
|
||||||
{
|
{
|
||||||
foreach (var dependBundleID in packageAsset.DependentBundleIDs)
|
foreach (var dependBundleID in buildAsset.DependentBundleIDs)
|
||||||
{
|
{
|
||||||
CacheBundleTags(dependBundleID, assetTags);
|
CacheBundleTags(dependBundleID, assetTags);
|
||||||
}
|
}
|
||||||
@@ -278,15 +272,15 @@ namespace YooAsset.Editor
|
|||||||
// 将缓存的资源标签赋值给资源包
|
// 将缓存的资源标签赋值给资源包
|
||||||
for (int index = 0; index < manifest.BundleList.Count; index++)
|
for (int index = 0; index < manifest.BundleList.Count; index++)
|
||||||
{
|
{
|
||||||
var packageBundle = manifest.BundleList[index];
|
var buildBundle = manifest.BundleList[index];
|
||||||
if (_cacheBundleTags.TryGetValue(index, out var value))
|
if (_cacheBundleTags.TryGetValue(index, out var value))
|
||||||
{
|
{
|
||||||
packageBundle.Tags = value.ToArray();
|
buildBundle.Tags = value.ToArray();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// 注意:SBP构建管线会自动剔除一些冗余资源的引用关系,导致游离资源包没有被任何主资源包引用。
|
// 注意:SBP构建管线会自动剔除一些冗余资源的引用关系,导致游离资源包没有被任何主资源包引用。
|
||||||
string warning = BuildLogger.GetErrorMessage(ErrorCode.FoundStrayBundle, $"Found stray bundle. Bundle ID: {index}, bundle name: '{packageBundle.BundleName}'.");
|
string warning = BuildLogger.GetErrorMessage(ErrorCode.FoundStrayBundle, $"Found stray bundle. Bundle ID: {index}, bundle name: '{buildBundle.BundleName}'.");
|
||||||
BuildLogger.Warning(warning);
|
BuildLogger.Warning(warning);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -324,7 +318,7 @@ namespace YooAsset.Editor
|
|||||||
}
|
}
|
||||||
|
|
||||||
#region YOOASSET_LEGACY_DEPENDENCY
|
#region YOOASSET_LEGACY_DEPENDENCY
|
||||||
private void ProcessBuiltinBundleDependency(BuildContext context, PackageManifest manifest)
|
private void ProcessBuiltinBundleDependency(BuildContext context, BuildManifest manifest)
|
||||||
{
|
{
|
||||||
// 注意:如果是可编程构建管线,需要补充首包资源包
|
// 注意:如果是可编程构建管线,需要补充首包资源包
|
||||||
// 注意:该步骤依赖前面的操作!
|
// 注意:该步骤依赖前面的操作!
|
||||||
@@ -356,7 +350,7 @@ namespace YooAsset.Editor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private void ProcessBuiltinBundleReference(PackageManifest manifest, string builtinBundleName)
|
private void ProcessBuiltinBundleReference(BuildManifest manifest, string builtinBundleName)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(builtinBundleName))
|
if (string.IsNullOrEmpty(builtinBundleName))
|
||||||
return;
|
return;
|
||||||
@@ -367,23 +361,23 @@ namespace YooAsset.Editor
|
|||||||
|
|
||||||
// 获取首包资源包
|
// 获取首包资源包
|
||||||
int builtinBundleID = GetCachedBundleIndexID(builtinBundleName);
|
int builtinBundleID = GetCachedBundleIndexID(builtinBundleName);
|
||||||
var builtinPackageBundle = manifest.BundleList[builtinBundleID];
|
var builtinBuildBundle = manifest.BundleList[builtinBundleID];
|
||||||
|
|
||||||
// 更新依赖资源包ID集合
|
// 更新依赖资源包ID集合
|
||||||
HashSet<int> cacheBundleIDs = new HashSet<int>(builtinPackageBundle.ReferrerBundleIDs);
|
HashSet<int> cacheBundleIDs = new HashSet<int>(builtinBuildBundle.ReferrerBundleIDs);
|
||||||
HashSet<string> tempTags = new HashSet<string>();
|
HashSet<string> tempTags = new HashSet<string>();
|
||||||
foreach (var packageAsset in manifest.AssetList)
|
foreach (var buildAsset in manifest.AssetList)
|
||||||
{
|
{
|
||||||
if (cacheBundleIDs.Contains(packageAsset.BundleID))
|
if (cacheBundleIDs.Contains(buildAsset.BundleID))
|
||||||
{
|
{
|
||||||
if (packageAsset.DependentBundleIDs.Contains(builtinBundleID) == false)
|
if (buildAsset.DependentBundleIDs.Contains(builtinBundleID) == false)
|
||||||
{
|
{
|
||||||
var tempBundleIDs = new List<int>(packageAsset.DependentBundleIDs);
|
var tempBundleIDs = new List<int>(buildAsset.DependentBundleIDs);
|
||||||
tempBundleIDs.Add(builtinBundleID);
|
tempBundleIDs.Add(builtinBundleID);
|
||||||
packageAsset.DependentBundleIDs = tempBundleIDs.ToArray();
|
buildAsset.DependentBundleIDs = tempBundleIDs.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var tag in packageAsset.AssetTags)
|
foreach (var tag in buildAsset.Tags)
|
||||||
{
|
{
|
||||||
if (tempTags.Contains(tag) == false)
|
if (tempTags.Contains(tag) == false)
|
||||||
tempTags.Add(tag);
|
tempTags.Add(tag);
|
||||||
@@ -392,12 +386,12 @@ namespace YooAsset.Editor
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 更新首包资源包的标签集合
|
// 更新首包资源包的标签集合
|
||||||
foreach (var tag in builtinPackageBundle.Tags)
|
foreach (var tag in builtinBuildBundle.Tags)
|
||||||
{
|
{
|
||||||
if (tempTags.Contains(tag) == false)
|
if (tempTags.Contains(tag) == false)
|
||||||
tempTags.Add(tag);
|
tempTags.Add(tag);
|
||||||
}
|
}
|
||||||
builtinPackageBundle.Tags = tempTags.ToArray();
|
builtinBuildBundle.Tags = tempTags.ToArray();
|
||||||
}
|
}
|
||||||
private int[] GetAssetDependBundleIDs(BuildAssetInfo mainAssetInfo)
|
private int[] GetAssetDependBundleIDs(BuildAssetInfo mainAssetInfo)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ namespace YooAsset.Editor
|
|||||||
var buildParameters = buildParametersContext.Parameters;
|
var buildParameters = buildParametersContext.Parameters;
|
||||||
|
|
||||||
string packageOutputDirectory = buildParametersContext.GetPackageOutputDirectory();
|
string packageOutputDirectory = buildParametersContext.GetPackageOutputDirectory();
|
||||||
PackageManifest manifest = manifestContext.Manifest;
|
BuildManifest manifest = manifestContext.Manifest;
|
||||||
BuildReport buildReport = new BuildReport();
|
BuildReport buildReport = new BuildReport();
|
||||||
|
|
||||||
// 概述信息
|
// 概述信息
|
||||||
@@ -89,36 +89,36 @@ namespace YooAsset.Editor
|
|||||||
|
|
||||||
// 资源对象列表
|
// 资源对象列表
|
||||||
buildReport.AssetInfos = new List<ReportAssetInfo>(manifest.AssetList.Count);
|
buildReport.AssetInfos = new List<ReportAssetInfo>(manifest.AssetList.Count);
|
||||||
foreach (var packageAsset in manifest.AssetList)
|
foreach (var buildAsset in manifest.AssetList)
|
||||||
{
|
{
|
||||||
var mainBundle = manifest.BundleList[packageAsset.BundleID];
|
var mainBundle = manifest.BundleList[buildAsset.BundleID];
|
||||||
ReportAssetInfo reportAssetInfo = new ReportAssetInfo();
|
ReportAssetInfo reportAssetInfo = new ReportAssetInfo();
|
||||||
reportAssetInfo.Address = packageAsset.Address;
|
reportAssetInfo.Address = buildAsset.Address;
|
||||||
reportAssetInfo.AssetPath = packageAsset.AssetPath;
|
reportAssetInfo.AssetPath = buildAsset.AssetPath;
|
||||||
reportAssetInfo.AssetTags = packageAsset.AssetTags;
|
reportAssetInfo.AssetTags = buildAsset.Tags;
|
||||||
reportAssetInfo.AssetGuid = AssetDatabase.AssetPathToGUID(packageAsset.AssetPath);
|
reportAssetInfo.AssetGuid = AssetDatabase.AssetPathToGUID(buildAsset.AssetPath);
|
||||||
reportAssetInfo.MainBundleName = mainBundle.BundleName;
|
reportAssetInfo.MainBundleName = mainBundle.BundleName;
|
||||||
reportAssetInfo.MainBundleSize = mainBundle.FileSize;
|
reportAssetInfo.MainBundleSize = mainBundle.FileSize;
|
||||||
reportAssetInfo.DependAssets = GetAssetDependAssets(buildMapContext, mainBundle.BundleName, packageAsset.AssetPath);
|
reportAssetInfo.DependAssets = GetAssetDependAssets(buildMapContext, mainBundle.BundleName, buildAsset.AssetPath);
|
||||||
reportAssetInfo.DependBundles = GetAssetDependBundles(manifest, packageAsset);
|
reportAssetInfo.DependBundles = GetAssetDependBundles(manifest, buildAsset);
|
||||||
buildReport.AssetInfos.Add(reportAssetInfo);
|
buildReport.AssetInfos.Add(reportAssetInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 资源包列表
|
// 资源包列表
|
||||||
buildReport.BundleInfos = new List<ReportBundleInfo>(manifest.BundleList.Count);
|
buildReport.BundleInfos = new List<ReportBundleInfo>(manifest.BundleList.Count);
|
||||||
foreach (var packageBundle in manifest.BundleList)
|
foreach (var buildBundle in manifest.BundleList)
|
||||||
{
|
{
|
||||||
ReportBundleInfo reportBundleInfo = new ReportBundleInfo();
|
ReportBundleInfo reportBundleInfo = new ReportBundleInfo();
|
||||||
reportBundleInfo.BundleName = packageBundle.BundleName;
|
reportBundleInfo.BundleName = buildBundle.BundleName;
|
||||||
reportBundleInfo.FileName = packageBundle.GetFileName();
|
reportBundleInfo.FileName = buildBundle.GetFileName(manifest.OutputNameStyle);
|
||||||
reportBundleInfo.FileHash = packageBundle.FileHash;
|
reportBundleInfo.FileHash = buildBundle.FileHash;
|
||||||
reportBundleInfo.FileCrc = packageBundle.FileCrc;
|
reportBundleInfo.FileCrc = buildBundle.FileCrc;
|
||||||
reportBundleInfo.FileSize = packageBundle.FileSize;
|
reportBundleInfo.FileSize = buildBundle.FileSize;
|
||||||
reportBundleInfo.Encrypted = packageBundle.IsEncrypted;
|
reportBundleInfo.Encrypted = buildBundle.IsEncrypted;
|
||||||
reportBundleInfo.Tags = packageBundle.Tags;
|
reportBundleInfo.Tags = buildBundle.Tags;
|
||||||
reportBundleInfo.DependBundles = GetBundleDependBundles(manifest, packageBundle);
|
reportBundleInfo.DependBundles = GetBundleDependBundles(manifest, buildBundle);
|
||||||
reportBundleInfo.ReferenceBundles = GetBundleReferenceBundles(manifest, packageBundle);
|
reportBundleInfo.ReferenceBundles = GetBundleReferenceBundles(manifest, buildBundle);
|
||||||
reportBundleInfo.BundleContents = GetBundleContents(buildMapContext, packageBundle.BundleName);
|
reportBundleInfo.BundleContents = GetBundleContents(buildMapContext, buildBundle.BundleName);
|
||||||
buildReport.BundleInfos.Add(reportBundleInfo);
|
buildReport.BundleInfos.Add(reportBundleInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,10 +151,10 @@ namespace YooAsset.Editor
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取资源对象依赖的资源包集合
|
/// 获取资源对象依赖的资源包集合
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private List<string> GetAssetDependBundles(PackageManifest manifest, PackageAsset packageAsset)
|
private List<string> GetAssetDependBundles(BuildManifest manifest, BuildAsset buildAsset)
|
||||||
{
|
{
|
||||||
List<string> dependBundles = new List<string>(packageAsset.DependentBundleIDs.Length);
|
List<string> dependBundles = new List<string>(buildAsset.DependentBundleIDs.Length);
|
||||||
foreach (int index in packageAsset.DependentBundleIDs)
|
foreach (int index in buildAsset.DependentBundleIDs)
|
||||||
{
|
{
|
||||||
string dependBundleName = manifest.BundleList[index].BundleName;
|
string dependBundleName = manifest.BundleList[index].BundleName;
|
||||||
dependBundles.Add(dependBundleName);
|
dependBundles.Add(dependBundleName);
|
||||||
@@ -166,10 +166,10 @@ namespace YooAsset.Editor
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取资源包依赖的资源包集合
|
/// 获取资源包依赖的资源包集合
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private List<string> GetBundleDependBundles(PackageManifest manifest, PackageBundle packageBundle)
|
private List<string> GetBundleDependBundles(BuildManifest manifest, BuildBundle buildBundle)
|
||||||
{
|
{
|
||||||
List<string> dependBundles = new List<string>(packageBundle.DependentBundleIDs.Length);
|
List<string> dependBundles = new List<string>(buildBundle.DependentBundleIDs.Length);
|
||||||
foreach (int index in packageBundle.DependentBundleIDs)
|
foreach (int index in buildBundle.DependentBundleIDs)
|
||||||
{
|
{
|
||||||
string dependBundleName = manifest.BundleList[index].BundleName;
|
string dependBundleName = manifest.BundleList[index].BundleName;
|
||||||
dependBundles.Add(dependBundleName);
|
dependBundles.Add(dependBundleName);
|
||||||
@@ -181,10 +181,10 @@ namespace YooAsset.Editor
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取引用该资源包的资源包集合
|
/// 获取引用该资源包的资源包集合
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private List<string> GetBundleReferenceBundles(PackageManifest manifest, PackageBundle packageBundle)
|
private List<string> GetBundleReferenceBundles(BuildManifest manifest, BuildBundle buildBundle)
|
||||||
{
|
{
|
||||||
List<string> referenceBundles = new List<string>(packageBundle.ReferrerBundleIDs.Count);
|
List<string> referenceBundles = new List<string>(buildBundle.ReferrerBundleIDs.Count);
|
||||||
foreach (int index in packageBundle.ReferrerBundleIDs)
|
foreach (int index in buildBundle.ReferrerBundleIDs)
|
||||||
{
|
{
|
||||||
string dependBundleName = manifest.BundleList[index].BundleName;
|
string dependBundleName = manifest.BundleList[index].BundleName;
|
||||||
referenceBundles.Add(dependBundleName);
|
referenceBundles.Add(dependBundleName);
|
||||||
@@ -204,15 +204,15 @@ namespace YooAsset.Editor
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private int GetMainAssetCount(PackageManifest manifest)
|
private int GetMainAssetCount(BuildManifest manifest)
|
||||||
{
|
{
|
||||||
return manifest.AssetList.Count;
|
return manifest.AssetList.Count;
|
||||||
}
|
}
|
||||||
private int GetAllBundleCount(PackageManifest manifest)
|
private int GetAllBundleCount(BuildManifest manifest)
|
||||||
{
|
{
|
||||||
return manifest.BundleList.Count;
|
return manifest.BundleList.Count;
|
||||||
}
|
}
|
||||||
private long GetAllBundleSize(PackageManifest manifest)
|
private long GetAllBundleSize(BuildManifest manifest)
|
||||||
{
|
{
|
||||||
long fileBytes = 0;
|
long fileBytes = 0;
|
||||||
foreach (var packageBundle in manifest.BundleList)
|
foreach (var packageBundle in manifest.BundleList)
|
||||||
@@ -221,7 +221,7 @@ namespace YooAsset.Editor
|
|||||||
}
|
}
|
||||||
return fileBytes;
|
return fileBytes;
|
||||||
}
|
}
|
||||||
private int GetEncryptedBundleCount(PackageManifest manifest)
|
private int GetEncryptedBundleCount(BuildManifest manifest)
|
||||||
{
|
{
|
||||||
int fileCount = 0;
|
int fileCount = 0;
|
||||||
foreach (var packageBundle in manifest.BundleList)
|
foreach (var packageBundle in manifest.BundleList)
|
||||||
@@ -231,7 +231,7 @@ namespace YooAsset.Editor
|
|||||||
}
|
}
|
||||||
return fileCount;
|
return fileCount;
|
||||||
}
|
}
|
||||||
private long GetEncryptedBundleSize(PackageManifest manifest)
|
private long GetEncryptedBundleSize(BuildManifest manifest)
|
||||||
{
|
{
|
||||||
long fileBytes = 0;
|
long fileBytes = 0;
|
||||||
foreach (var packageBundle in manifest.BundleList)
|
foreach (var packageBundle in manifest.BundleList)
|
||||||
|
|||||||
@@ -61,8 +61,7 @@ namespace YooAsset.Editor
|
|||||||
{
|
{
|
||||||
string bundleName = bundleInfo.BundleName;
|
string bundleName = bundleInfo.BundleName;
|
||||||
string fileHash = bundleInfo.PackageFileHash;
|
string fileHash = bundleInfo.PackageFileHash;
|
||||||
string fileExtension = PackageManifestHelper.GetRemoteBundleFileExtension(bundleName);
|
string fileName = BundleFileNaming.GetBundleFileName(outputNameStyle, bundleName, fileHash);
|
||||||
string fileName = PackageManifestHelper.GetRemoteBundleFileName(outputNameStyle, bundleName, fileExtension, fileHash);
|
|
||||||
bundleInfo.PackageDestFilePath = $"{packageOutputDirectory}/{fileName}";
|
bundleInfo.PackageDestFilePath = $"{packageOutputDirectory}/{fileName}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#if TUANJIE_1_8_OR_NEWER
|
#if TUANJIE_1_8_OR_NEWER && YOOASSET_INSTANT_ASSET_SUPPORT
|
||||||
using System;
|
using System;
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 9c86f68bc316ce54ca9396e6e6c2dd8f
|
guid: 07c436f0dfa2bcf43b12628aed2aa91c
|
||||||
folderAsset: yes
|
folderAsset: yes
|
||||||
DefaultImporter:
|
DefaultImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
|
||||||
|
namespace YooAsset.Editor
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 收集资源搜索结果
|
||||||
|
/// </summary>
|
||||||
|
public class CollectAssetSearchResult
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 命中的收集器分组
|
||||||
|
/// </summary>
|
||||||
|
public BundleCollectorGroup Group { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 命中的收集器分组索引
|
||||||
|
/// </summary>
|
||||||
|
public int GroupIndex { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 命中的收集器
|
||||||
|
/// </summary>
|
||||||
|
public BundleCollector Collector { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 命中的收集器索引
|
||||||
|
/// </summary>
|
||||||
|
public int CollectorIndex { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 命中的资源路径
|
||||||
|
/// </summary>
|
||||||
|
public string AssetPath { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 构建收集资源搜索结果
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="group">命中的收集器分组</param>
|
||||||
|
/// <param name="groupIndex">命中的收集器分组索引</param>
|
||||||
|
/// <param name="collector">命中的收集器</param>
|
||||||
|
/// <param name="collectorIndex">命中的收集器索引</param>
|
||||||
|
/// <param name="assetPath">命中的资源路径</param>
|
||||||
|
public CollectAssetSearchResult(BundleCollectorGroup group, int groupIndex,
|
||||||
|
BundleCollector collector, int collectorIndex, string assetPath)
|
||||||
|
{
|
||||||
|
Group = group;
|
||||||
|
GroupIndex = groupIndex;
|
||||||
|
Collector = collector;
|
||||||
|
CollectorIndex = collectorIndex;
|
||||||
|
AssetPath = assetPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 4c79e03ac8bcbef4aa0e2eede5bf63fb
|
guid: ff1a09e6aca8b104c9b256885b06130f
|
||||||
MonoImporter:
|
MonoImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
@@ -0,0 +1,148 @@
|
|||||||
|
using System;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEditor;
|
||||||
|
|
||||||
|
namespace YooAsset.Editor
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 收集资源搜索工具类
|
||||||
|
/// </summary>
|
||||||
|
public static class CollectAssetSearchUtility
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 验证搜索路径
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="input">搜索路径</param>
|
||||||
|
/// <returns>搜索路径错误类型</returns>
|
||||||
|
public static ECollectAssetSearchError ValidateSearchPath(string input)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(input))
|
||||||
|
return ECollectAssetSearchError.InputPathEmpty;
|
||||||
|
|
||||||
|
if (input.StartsWith("Assets/", StringComparison.OrdinalIgnoreCase) == false)
|
||||||
|
return ECollectAssetSearchError.InputPathMissingAssetsPrefix;
|
||||||
|
|
||||||
|
if (input.EndsWith("/"))
|
||||||
|
return ECollectAssetSearchError.InputPathEndsWithSlash;
|
||||||
|
|
||||||
|
string fileName = System.IO.Path.GetFileName(input);
|
||||||
|
if (fileName.Contains(".") == false)
|
||||||
|
return ECollectAssetSearchError.InputPathMissingExtension;
|
||||||
|
|
||||||
|
if (AssetDatabase.IsValidFolder(input))
|
||||||
|
return ECollectAssetSearchError.InputPathIsFolder;
|
||||||
|
|
||||||
|
string guid = AssetDatabase.AssetPathToGUID(input);
|
||||||
|
if (string.IsNullOrEmpty(guid))
|
||||||
|
return ECollectAssetSearchError.AssetPathNotExists;
|
||||||
|
|
||||||
|
return ECollectAssetSearchError.None;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取搜索路径错误提示信息
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="error">搜索路径错误类型</param>
|
||||||
|
/// <param name="input">搜索路径</param>
|
||||||
|
/// <returns>错误提示信息</returns>
|
||||||
|
public static string GetSearchPathErrorMessage(ECollectAssetSearchError error, string input)
|
||||||
|
{
|
||||||
|
switch (error)
|
||||||
|
{
|
||||||
|
case ECollectAssetSearchError.InputPathEmpty:
|
||||||
|
return "Please enter an asset path.";
|
||||||
|
case ECollectAssetSearchError.InputPathMissingAssetsPrefix:
|
||||||
|
return "Path must start with Assets/.";
|
||||||
|
case ECollectAssetSearchError.InputPathEndsWithSlash:
|
||||||
|
return "Please enter a file path. Do not end with /.";
|
||||||
|
case ECollectAssetSearchError.InputPathMissingExtension:
|
||||||
|
return "Path is missing a file extension (e.g. .prefab, .png, .mat).";
|
||||||
|
case ECollectAssetSearchError.InputPathIsFolder:
|
||||||
|
return "Please enter an asset file path, not a folder path.";
|
||||||
|
case ECollectAssetSearchError.AssetPathNotExists:
|
||||||
|
return $"Asset not found: {input}";
|
||||||
|
default:
|
||||||
|
return "Invalid input format.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 在指定 Package 中搜索资源路径,找到第一个命中结果即返回
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="package">搜索的资源包裹</param>
|
||||||
|
/// <param name="assetPath">资源路径</param>
|
||||||
|
/// <returns>搜索结果,如果未找到返回 null</returns>
|
||||||
|
public static CollectAssetSearchResult SearchAssetPath(BundleCollectorPackage package, string assetPath)
|
||||||
|
{
|
||||||
|
if (ValidateSearchPath(assetPath) != ECollectAssetSearchError.None)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
IAssetIgnoreRule ignoreRule = BundleCollectorSettingData.GetAssetIgnoreRuleInstance(package.IgnoreRuleName);
|
||||||
|
var command = new CollectCommand(package.PackageName, ignoreRule);
|
||||||
|
command.SetFlag(ECollectFlags.IgnoreGetDependencies, true);
|
||||||
|
command.UniqueBundleName = BundleCollectorSettingData.Setting.UniqueBundleName;
|
||||||
|
command.EnableAddressable = package.EnableAddressable;
|
||||||
|
command.SupportExtensionless = package.SupportExtensionless;
|
||||||
|
command.LocationToLower = package.LocationToLower;
|
||||||
|
command.IncludeAssetGUID = package.IncludeAssetGUID;
|
||||||
|
command.AutoCollectShaders = package.AutoCollectShaders;
|
||||||
|
|
||||||
|
for (int groupIndex = 0; groupIndex < package.Groups.Count; groupIndex++)
|
||||||
|
{
|
||||||
|
var group = package.Groups[groupIndex];
|
||||||
|
for (int collectIndex = 0; collectIndex < group.Collectors.Count; collectIndex++)
|
||||||
|
{
|
||||||
|
var collector = group.Collectors[collectIndex];
|
||||||
|
|
||||||
|
// 判断收集器是否可能收集指定资源
|
||||||
|
if (IsCandidateCollector(collector, assetPath) == false)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// 检测配置是否有效
|
||||||
|
collector.CheckConfigError();
|
||||||
|
|
||||||
|
// 收集有效资源信息
|
||||||
|
var collectAssets = collector.GetAllCollectAssets(command, group);
|
||||||
|
foreach (var collectAsset in collectAssets)
|
||||||
|
{
|
||||||
|
if (string.Equals(collectAsset.AssetInfo.AssetPath, assetPath, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return new CollectAssetSearchResult(group, groupIndex, collector, collectIndex, assetPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Debug.LogError($"Invalid collector : {collector.CollectPath}, error: {e.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 未找到匹配资源
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 判断收集器是否可能收集指定资源
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="collector">收集器</param>
|
||||||
|
/// <param name="assetPath">资源路径</param>
|
||||||
|
/// <returns>如果收集器可能收集该资源返回 true</returns>
|
||||||
|
private static bool IsCandidateCollector(BundleCollector collector, string assetPath)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(collector.CollectPath))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (AssetDatabase.IsValidFolder(collector.CollectPath))
|
||||||
|
{
|
||||||
|
string folderPath = collector.CollectPath.TrimEnd('/') + "/";
|
||||||
|
return assetPath.StartsWith(folderPath, StringComparison.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 注意:资源收集器也可能直接配置的单个资源路径
|
||||||
|
return string.Equals(assetPath, collector.CollectPath, StringComparison.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 1cfc5979929f8cd43b58e1fcc541eaa8
|
guid: 6c8bc2931bda7884198893f1d2e8f364
|
||||||
MonoImporter:
|
MonoImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
|
||||||
|
namespace YooAsset.Editor
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 搜索错误类型
|
||||||
|
/// </summary>
|
||||||
|
public enum ECollectAssetSearchError
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 无错误
|
||||||
|
/// </summary>
|
||||||
|
None,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 输入路径为空
|
||||||
|
/// </summary>
|
||||||
|
InputPathEmpty,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 输入路径缺少 Assets/ 路径前缀
|
||||||
|
/// </summary>
|
||||||
|
InputPathMissingAssetsPrefix,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 输入路径以斜杠结尾
|
||||||
|
/// </summary>
|
||||||
|
InputPathEndsWithSlash,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 输入路径缺少文件扩展名
|
||||||
|
/// </summary>
|
||||||
|
InputPathMissingExtension,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 输入路径的是文件夹路径
|
||||||
|
/// </summary>
|
||||||
|
InputPathIsFolder,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 资源文件不存在
|
||||||
|
/// </summary>
|
||||||
|
AssetPathNotExists,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 5ef65b981b91200439b05f29435e7c92
|
guid: 9a2c8a878d6041b4d8bad2a2d2f1896d
|
||||||
MonoImporter:
|
MonoImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
@@ -60,21 +60,22 @@ namespace YooAsset.Editor
|
|||||||
/// <returns>如果收集器配置有效返回 true</returns>
|
/// <returns>如果收集器配置有效返回 true</returns>
|
||||||
public bool IsValid()
|
public bool IsValid()
|
||||||
{
|
{
|
||||||
if (AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(CollectPath) == null)
|
string assetGUID = AssetDatabase.AssetPathToGUID(CollectPath);
|
||||||
|
if (string.IsNullOrEmpty(assetGUID))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (CollectorType == ECollectorType.None)
|
if (CollectorType == ECollectorType.None)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (BundleCollectorSettingData.HasAddressRuleName(AddressRuleName) == false)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (BundleCollectorSettingData.HasBundlePackRuleName(PackRuleName) == false)
|
if (BundleCollectorSettingData.HasBundlePackRuleName(PackRuleName) == false)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (BundleCollectorSettingData.HasAssetFilterRuleName(FilterRuleName) == false)
|
if (BundleCollectorSettingData.HasAssetFilterRuleName(FilterRuleName) == false)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (BundleCollectorSettingData.HasAddressRuleName(AddressRuleName) == false)
|
||||||
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -175,6 +175,17 @@ namespace YooAsset.Editor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 工程中是否已存在收集器配置文件
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>存在返回 true</returns>
|
||||||
|
public static bool HasSettingAsset()
|
||||||
|
{
|
||||||
|
string typeName = nameof(BundleCollectorSetting);
|
||||||
|
var guids = AssetDatabase.FindAssets($"t:{typeName}");
|
||||||
|
return guids != null && guids.Length > 0;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 存储配置文件
|
/// 存储配置文件
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -19,12 +19,34 @@ namespace YooAsset.Editor
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[MenuItem("YooAsset/Bundle Collector", false, 101)]
|
[MenuItem("YooAsset/Bundle Collector", false, 101)]
|
||||||
public static void OpenWindow()
|
public static void OpenWindow()
|
||||||
|
{
|
||||||
|
OpenWindowInternal();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 打开资源收集器窗口并定位到指定的收集器
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="packageName">包裹名称</param>
|
||||||
|
/// <param name="groupName">分组名称</param>
|
||||||
|
/// <param name="collectPath">收集路径</param>
|
||||||
|
public static void OpenWindow(string packageName, string groupName, string collectPath)
|
||||||
|
{
|
||||||
|
BundleCollectorWindow window = OpenWindowInternal();
|
||||||
|
window.SetFocusCollector(packageName, groupName, collectPath);
|
||||||
|
window.RefreshWindow();
|
||||||
|
window.Focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static BundleCollectorWindow OpenWindowInternal()
|
||||||
{
|
{
|
||||||
Type[] dockedTypes = EditorWindowDefine.GetDockedWindowTypes();
|
Type[] dockedTypes = EditorWindowDefine.GetDockedWindowTypes();
|
||||||
BundleCollectorWindow window = GetWindow<BundleCollectorWindow>("Bundle Collector", true, dockedTypes);
|
BundleCollectorWindow window = GetWindow<BundleCollectorWindow>("Bundle Collector", true, dockedTypes);
|
||||||
window.minSize = new Vector2(800, 600);
|
window.minSize = new Vector2(800, 600);
|
||||||
|
return window;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private const string PlaceholderClass = "search-placeholder";
|
||||||
|
|
||||||
private Button _saveButton;
|
private Button _saveButton;
|
||||||
private List<string> _collectorTypeList;
|
private List<string> _collectorTypeList;
|
||||||
private List<RuleDisplayName> _groupActiveRuleList;
|
private List<RuleDisplayName> _groupActiveRuleList;
|
||||||
@@ -35,6 +57,11 @@ namespace YooAsset.Editor
|
|||||||
|
|
||||||
private VisualElement _helpBoxContainer;
|
private VisualElement _helpBoxContainer;
|
||||||
|
|
||||||
|
private ToolbarSearchField _searchField;
|
||||||
|
private TextField _searchTextField;
|
||||||
|
private Button _searchButton;
|
||||||
|
private Label _searchResultLabel;
|
||||||
|
|
||||||
private Button _globalSettingsButton;
|
private Button _globalSettingsButton;
|
||||||
private Button _packageSettingsButton;
|
private Button _packageSettingsButton;
|
||||||
|
|
||||||
@@ -66,8 +93,11 @@ namespace YooAsset.Editor
|
|||||||
private ScrollView _collectorScrollView;
|
private ScrollView _collectorScrollView;
|
||||||
private PopupField<RuleDisplayName> _activeRulePopupField;
|
private PopupField<RuleDisplayName> _activeRulePopupField;
|
||||||
|
|
||||||
|
private string _highlightAssetPath;
|
||||||
|
private int _highlightCollectorIndex = -1;
|
||||||
private int _lastModifyPackageIndex = 0;
|
private int _lastModifyPackageIndex = 0;
|
||||||
private int _lastModifyGroupIndex = 0;
|
private int _lastModifyGroupIndex = 0;
|
||||||
|
private bool _hasFocusCollector = false;
|
||||||
private bool _showGlobalSettings = false;
|
private bool _showGlobalSettings = false;
|
||||||
private bool _showPackageSettings = false;
|
private bool _showPackageSettings = false;
|
||||||
|
|
||||||
@@ -219,6 +249,44 @@ namespace YooAsset.Editor
|
|||||||
_saveButton = root.Q<Button>("SaveButton");
|
_saveButton = root.Q<Button>("SaveButton");
|
||||||
_saveButton.clicked += OnSaveButtonClicked;
|
_saveButton.clicked += OnSaveButtonClicked;
|
||||||
|
|
||||||
|
// 搜索相关
|
||||||
|
_searchField = root.Q<ToolbarSearchField>("SearchField");
|
||||||
|
_searchTextField = _searchField.Q<TextField>();
|
||||||
|
_searchTextField.RegisterCallback<FocusInEvent>(evt =>
|
||||||
|
{
|
||||||
|
if (_searchTextField.ClassListContains(PlaceholderClass))
|
||||||
|
{
|
||||||
|
_searchField.value = string.Empty;
|
||||||
|
ClearSearchPlaceholder();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
_searchTextField.RegisterCallback<FocusOutEvent>(evt =>
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(_searchField.value))
|
||||||
|
ApplySearchPlaceholder();
|
||||||
|
});
|
||||||
|
_searchField.RegisterCallback<DragUpdatedEvent>(evt =>
|
||||||
|
{
|
||||||
|
if (DragAndDrop.objectReferences.Length > 0)
|
||||||
|
DragAndDrop.visualMode = DragAndDropVisualMode.Generic;
|
||||||
|
});
|
||||||
|
_searchField.RegisterCallback<DragPerformEvent>(evt =>
|
||||||
|
{
|
||||||
|
if (DragAndDrop.objectReferences.Length > 0)
|
||||||
|
{
|
||||||
|
string assetPath = AssetDatabase.GetAssetPath(DragAndDrop.objectReferences[0]);
|
||||||
|
if (string.IsNullOrEmpty(assetPath) == false)
|
||||||
|
{
|
||||||
|
_searchField.value = assetPath;
|
||||||
|
ClearSearchPlaceholder();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
ApplySearchPlaceholder();
|
||||||
|
_searchButton = root.Q<Button>("SearchButton");
|
||||||
|
_searchButton.clicked += OnSearchButtonClicked;
|
||||||
|
_searchResultLabel = root.Q<Label>("SearchResultLabel");
|
||||||
|
|
||||||
// 包裹容器
|
// 包裹容器
|
||||||
_packageContainer = root.Q("PackageContainer");
|
_packageContainer = root.Q("PackageContainer");
|
||||||
|
|
||||||
@@ -423,6 +491,9 @@ namespace YooAsset.Editor
|
|||||||
|
|
||||||
private void RefreshWindow()
|
private void RefreshWindow()
|
||||||
{
|
{
|
||||||
|
_highlightAssetPath = null;
|
||||||
|
if (_hasFocusCollector == false)
|
||||||
|
_highlightCollectorIndex = -1;
|
||||||
_groupContainer.visible = false;
|
_groupContainer.visible = false;
|
||||||
_collectorContainer.visible = false;
|
_collectorContainer.visible = false;
|
||||||
|
|
||||||
@@ -455,6 +526,55 @@ namespace YooAsset.Editor
|
|||||||
{
|
{
|
||||||
BundleCollectorSettingData.SaveFile();
|
BundleCollectorSettingData.SaveFile();
|
||||||
}
|
}
|
||||||
|
private void OnSearchButtonClicked()
|
||||||
|
{
|
||||||
|
_highlightAssetPath = null;
|
||||||
|
_highlightCollectorIndex = -1;
|
||||||
|
_hasFocusCollector = false;
|
||||||
|
FillCollectorViewData();
|
||||||
|
|
||||||
|
string searchInput = GetSearchInput();
|
||||||
|
var pathError = CollectAssetSearchUtility.ValidateSearchPath(searchInput);
|
||||||
|
if (pathError != ECollectAssetSearchError.None)
|
||||||
|
{
|
||||||
|
string message = CollectAssetSearchUtility.GetSearchPathErrorMessage(pathError, searchInput);
|
||||||
|
ShowSearchResult(message, new Color(1f, 0.4f, 0.4f));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var selectPackage = _packageListView.selectedItem as BundleCollectorPackage;
|
||||||
|
if (selectPackage == null)
|
||||||
|
{
|
||||||
|
string message = "No package selected. Please select a package first.";
|
||||||
|
ShowSearchResult(message, new Color(1f, 0.8f, 0.3f));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var searchResult = CollectAssetSearchUtility.SearchAssetPath(selectPackage, searchInput);
|
||||||
|
if (searchResult == null)
|
||||||
|
{
|
||||||
|
string message = $"No results found in package '{selectPackage.PackageName}'.";
|
||||||
|
ShowSearchResult(message, new Color(1f, 0.8f, 0.3f));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string resultMessage = $"Found in group '{searchResult.Group.GroupName}', collector '{searchResult.Collector.CollectPath}'";
|
||||||
|
ShowSearchResult(resultMessage, Color.white);
|
||||||
|
|
||||||
|
_searchResultLabel.style.unityFontStyleAndWeight = FontStyle.Bold;
|
||||||
|
_searchResultLabel.style.unityTextAlign = TextAnchor.MiddleLeft;
|
||||||
|
|
||||||
|
_highlightAssetPath = searchResult.AssetPath;
|
||||||
|
_highlightCollectorIndex = searchResult.CollectorIndex;
|
||||||
|
|
||||||
|
_groupContainer.visible = true;
|
||||||
|
_lastModifyGroupIndex = searchResult.GroupIndex;
|
||||||
|
|
||||||
|
if (_groupListView.selectedIndex == searchResult.GroupIndex)
|
||||||
|
FillCollectorViewData();
|
||||||
|
else
|
||||||
|
_groupListView.selectedIndex = searchResult.GroupIndex;
|
||||||
|
}
|
||||||
private void OnGlobalSettingsButtonClicked()
|
private void OnGlobalSettingsButtonClicked()
|
||||||
{
|
{
|
||||||
_showGlobalSettings = !_showGlobalSettings;
|
_showGlobalSettings = !_showGlobalSettings;
|
||||||
@@ -480,6 +600,85 @@ namespace YooAsset.Editor
|
|||||||
return ruleDisplayName.ClassName;
|
return ruleDisplayName.ClassName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 焦点相关
|
||||||
|
private void SetFocusCollector(string packageName, string groupName, string collectPath)
|
||||||
|
{
|
||||||
|
var packages = BundleCollectorSettingData.Setting.Packages;
|
||||||
|
int packageIndex = packages.FindIndex(item => item.PackageName == packageName);
|
||||||
|
if (packageIndex < 0)
|
||||||
|
{
|
||||||
|
Debug.LogWarning($"Package not found: '{packageName}'.");
|
||||||
|
_highlightCollectorIndex = -1;
|
||||||
|
_hasFocusCollector = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var package = packages[packageIndex];
|
||||||
|
int groupIndex = package.Groups.FindIndex(item => item.GroupName == groupName);
|
||||||
|
if (groupIndex < 0)
|
||||||
|
{
|
||||||
|
Debug.LogWarning($"Group not found: '{groupName}' in package '{packageName}'.");
|
||||||
|
_highlightCollectorIndex = -1;
|
||||||
|
_hasFocusCollector = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var group = package.Groups[groupIndex];
|
||||||
|
int collectorIndex = group.Collectors.FindIndex(item => string.Equals(item.CollectPath, collectPath, StringComparison.OrdinalIgnoreCase));
|
||||||
|
if (collectorIndex < 0)
|
||||||
|
{
|
||||||
|
Debug.LogWarning($"Collector not found: '{collectPath}'.");
|
||||||
|
_highlightCollectorIndex = -1;
|
||||||
|
_hasFocusCollector = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_highlightAssetPath = null;
|
||||||
|
_highlightCollectorIndex = collectorIndex;
|
||||||
|
_lastModifyPackageIndex = packageIndex;
|
||||||
|
_lastModifyGroupIndex = groupIndex;
|
||||||
|
_hasFocusCollector = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 搜索栏相关
|
||||||
|
private void ShowSearchResult(string message, Color color)
|
||||||
|
{
|
||||||
|
_searchResultLabel.text = message;
|
||||||
|
_searchResultLabel.style.color = color;
|
||||||
|
_searchResultLabel.style.unityFontStyleAndWeight = FontStyle.Normal;
|
||||||
|
_searchResultLabel.style.unityTextAlign = TextAnchor.MiddleCenter;
|
||||||
|
_searchResultLabel.style.display = DisplayStyle.Flex;
|
||||||
|
}
|
||||||
|
private void ClearSearchResult()
|
||||||
|
{
|
||||||
|
_searchResultLabel.text = string.Empty;
|
||||||
|
_searchResultLabel.style.display = DisplayStyle.None;
|
||||||
|
}
|
||||||
|
private void ApplySearchPlaceholder()
|
||||||
|
{
|
||||||
|
_searchField.value = "Drag or enter asset path here (e.g. Assets/Res/icon.png)";
|
||||||
|
if (_searchTextField.ClassListContains(PlaceholderClass) == false)
|
||||||
|
_searchTextField.AddToClassList(PlaceholderClass);
|
||||||
|
|
||||||
|
var inputElement = _searchTextField.Q("unity-text-input");
|
||||||
|
inputElement.style.color = new Color(0.7f, 0.7f, 0.7f, 0.6f);
|
||||||
|
}
|
||||||
|
private void ClearSearchPlaceholder()
|
||||||
|
{
|
||||||
|
if (_searchTextField.ClassListContains(PlaceholderClass))
|
||||||
|
{
|
||||||
|
_searchTextField.RemoveFromClassList(PlaceholderClass);
|
||||||
|
var inputElement = _searchTextField.Q("unity-text-input");
|
||||||
|
inputElement.style.color = StyleKeyword.Null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private string GetSearchInput()
|
||||||
|
{
|
||||||
|
if (_searchTextField.ClassListContains(PlaceholderClass))
|
||||||
|
return string.Empty;
|
||||||
|
return _searchField.value;
|
||||||
|
}
|
||||||
|
|
||||||
// 设置栏相关
|
// 设置栏相关
|
||||||
private void RefreshSettings()
|
private void RefreshSettings()
|
||||||
{
|
{
|
||||||
@@ -607,6 +806,8 @@ namespace YooAsset.Editor
|
|||||||
}
|
}
|
||||||
private void OnPackageListViewSelectionChange(IEnumerable<object> objs)
|
private void OnPackageListViewSelectionChange(IEnumerable<object> objs)
|
||||||
{
|
{
|
||||||
|
ClearSearchResult();
|
||||||
|
|
||||||
var selectPackage = _packageListView.selectedItem as BundleCollectorPackage;
|
var selectPackage = _packageListView.selectedItem as BundleCollectorPackage;
|
||||||
if (selectPackage == null)
|
if (selectPackage == null)
|
||||||
{
|
{
|
||||||
@@ -752,6 +953,16 @@ namespace YooAsset.Editor
|
|||||||
BindCollectorListViewItem(element, i);
|
BindCollectorListViewItem(element, i);
|
||||||
_collectorScrollView.Add(element);
|
_collectorScrollView.Add(element);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_highlightCollectorIndex >= 0 && _highlightCollectorIndex < selectGroup.Collectors.Count)
|
||||||
|
{
|
||||||
|
var targetElement = _collectorScrollView[_highlightCollectorIndex];
|
||||||
|
var foldout = targetElement.Q<Foldout>("Foldout1");
|
||||||
|
if (foldout != null)
|
||||||
|
foldout.value = true;
|
||||||
|
_highlightCollectorIndex = -1;
|
||||||
|
_hasFocusCollector = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
private VisualElement MakeCollectorListViewItem()
|
private VisualElement MakeCollectorListViewItem()
|
||||||
{
|
{
|
||||||
@@ -1033,13 +1244,6 @@ namespace YooAsset.Editor
|
|||||||
// 清空旧元素
|
// 清空旧元素
|
||||||
foldout.Clear();
|
foldout.Clear();
|
||||||
|
|
||||||
// 检测配置是否有效
|
|
||||||
if (collector.IsValid() == false)
|
|
||||||
{
|
|
||||||
collector.CheckConfigError();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<CollectAssetInfo> collectAssetInfos = null;
|
List<CollectAssetInfo> collectAssetInfos = null;
|
||||||
|
|
||||||
try
|
try
|
||||||
@@ -1055,12 +1259,15 @@ namespace YooAsset.Editor
|
|||||||
command.IncludeAssetGUID = _includeAssetGUIDToggle.value;
|
command.IncludeAssetGUID = _includeAssetGUIDToggle.value;
|
||||||
command.AutoCollectShaders = _autoCollectShadersToggle.value;
|
command.AutoCollectShaders = _autoCollectShadersToggle.value;
|
||||||
|
|
||||||
|
// 检测配置是否有效
|
||||||
collector.CheckConfigError();
|
collector.CheckConfigError();
|
||||||
|
|
||||||
|
// 收集有效资源信息
|
||||||
collectAssetInfos = collector.GetAllCollectAssets(command, group);
|
collectAssetInfos = collector.GetAllCollectAssets(command, group);
|
||||||
}
|
}
|
||||||
catch (System.Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Debug.LogError(e.ToString());
|
Debug.LogError($"Invalid collector : {collector.CollectPath}, error: {e.Message}");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (collectAssetInfos != null)
|
if (collectAssetInfos != null)
|
||||||
@@ -1085,6 +1292,13 @@ namespace YooAsset.Editor
|
|||||||
label.style.width = 300;
|
label.style.width = 300;
|
||||||
label.style.marginLeft = 0;
|
label.style.marginLeft = 0;
|
||||||
label.style.flexGrow = 1;
|
label.style.flexGrow = 1;
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(_highlightAssetPath) == false &&
|
||||||
|
string.Equals(collectAsset.AssetInfo.AssetPath, _highlightAssetPath, StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
label.style.color = new Color(1f, 0.2f, 0.2f);
|
||||||
|
}
|
||||||
|
|
||||||
elementRow.Add(label);
|
elementRow.Add(label);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,11 @@
|
|||||||
<ui:Button text="Import" display-tooltip-when-elided="true" name="ImportButton" style="width: 50px; background-color: rgb(56, 147, 58);" />
|
<ui:Button text="Import" display-tooltip-when-elided="true" name="ImportButton" style="width: 50px; background-color: rgb(56, 147, 58);" />
|
||||||
<ui:Button text="Fix" display-tooltip-when-elided="true" name="FixButton" style="width: 50px; background-color: rgb(56, 147, 58);" />
|
<ui:Button text="Fix" display-tooltip-when-elided="true" name="FixButton" style="width: 50px; background-color: rgb(56, 147, 58);" />
|
||||||
</uie:Toolbar>
|
</uie:Toolbar>
|
||||||
|
<uie:Toolbar name="SearchToolbar" style="display: flex; flex-direction: row;">
|
||||||
|
<uie:ToolbarSearchField focusable="true" name="SearchField" style="flex-grow: 1;" />
|
||||||
|
<ui:Button text="Search" display-tooltip-when-elided="true" name="SearchButton" style="width: 60px; background-color: rgb(56, 147, 58);" />
|
||||||
|
</uie:Toolbar>
|
||||||
|
<ui:Label name="SearchResultLabel" style="display: none; height: 24px; -unity-text-align: middle-center; padding-left: 5px; padding-right: 5px;" />
|
||||||
<ui:VisualElement name="PublicContainer" style="background-color: rgb(79, 79, 79); border-left-width: 5px; border-right-width: 5px; border-top-width: 5px; border-bottom-width: 5px;">
|
<ui:VisualElement name="PublicContainer" style="background-color: rgb(79, 79, 79); border-left-width: 5px; border-right-width: 5px; border-top-width: 5px; border-bottom-width: 5px;">
|
||||||
<ui:VisualElement name="HelpBoxContainer" style="flex-grow: 1;" />
|
<ui:VisualElement name="HelpBoxContainer" style="flex-grow: 1;" />
|
||||||
<ui:VisualElement name="GlobalSettingsContainer">
|
<ui:VisualElement name="GlobalSettingsContainer">
|
||||||
|
|||||||
@@ -1,57 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace YooAsset
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 淘汰策略执行结果
|
|
||||||
/// </summary>
|
|
||||||
internal readonly struct EvictionResult
|
|
||||||
{
|
|
||||||
private readonly bool _initialized;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 错误信息
|
|
||||||
/// </summary>
|
|
||||||
public string Error { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 需要清理的资源标识符集合
|
|
||||||
/// </summary>
|
|
||||||
public IReadOnlyList<string> BundleGuids { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 是否执行成功
|
|
||||||
/// </summary>
|
|
||||||
public bool Succeeded
|
|
||||||
{
|
|
||||||
get { return _initialized && Error == null; }
|
|
||||||
}
|
|
||||||
|
|
||||||
private EvictionResult(string error, IReadOnlyList<string> bundleGuids)
|
|
||||||
{
|
|
||||||
_initialized = true;
|
|
||||||
Error = error;
|
|
||||||
BundleGuids = bundleGuids;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 创建表示执行成功的淘汰结果
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="bundleGuids">需要清理的资源包标识符列表</param>
|
|
||||||
/// <returns>携带待清理列表的成功结果</returns>
|
|
||||||
public static EvictionResult CreateSuccess(IReadOnlyList<string> bundleGuids)
|
|
||||||
{
|
|
||||||
return new EvictionResult(null, bundleGuids);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 创建表示执行失败的淘汰结果
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="error">描述失败原因的错误信息</param>
|
|
||||||
/// <returns>携带错误信息的失败结果</returns>
|
|
||||||
public static EvictionResult CreateFailure(string error)
|
|
||||||
{
|
|
||||||
return new EvictionResult(error, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,6 +2,59 @@ using System.Collections.Generic;
|
|||||||
|
|
||||||
namespace YooAsset
|
namespace YooAsset
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 淘汰策略执行结果
|
||||||
|
/// </summary>
|
||||||
|
internal readonly struct EvictionResult
|
||||||
|
{
|
||||||
|
private readonly bool _initialized;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 错误信息
|
||||||
|
/// </summary>
|
||||||
|
public string Error { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 需要清理的资源标识符集合
|
||||||
|
/// </summary>
|
||||||
|
public IReadOnlyList<string> BundleGuids { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 是否执行成功
|
||||||
|
/// </summary>
|
||||||
|
public bool Succeeded
|
||||||
|
{
|
||||||
|
get { return _initialized && Error == null; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private EvictionResult(string error, IReadOnlyList<string> bundleGuids)
|
||||||
|
{
|
||||||
|
_initialized = true;
|
||||||
|
Error = error;
|
||||||
|
BundleGuids = bundleGuids;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 创建表示执行成功的淘汰结果
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="bundleGuids">需要清理的资源包标识符列表</param>
|
||||||
|
/// <returns>携带待清理列表的成功结果</returns>
|
||||||
|
public static EvictionResult CreateSuccess(IReadOnlyList<string> bundleGuids)
|
||||||
|
{
|
||||||
|
return new EvictionResult(null, bundleGuids);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 创建表示执行失败的淘汰结果
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="error">描述失败原因的错误信息</param>
|
||||||
|
/// <returns>携带错误信息的失败结果</returns>
|
||||||
|
public static EvictionResult CreateFailure(string error)
|
||||||
|
{
|
||||||
|
return new EvictionResult(error, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 缓存淘汰策略接口
|
/// 缓存淘汰策略接口
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
namespace YooAsset
|
namespace YooAsset
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 清理缓存操作选项
|
/// 清理缓存的操作选项
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal readonly struct BCClearCacheOptions
|
internal readonly struct BCClearCacheOptions
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
namespace YooAsset
|
namespace YooAsset
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 加载资源包操作选项
|
/// 加载资源包的操作选项
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal readonly struct BCLoadBundleOptions
|
internal readonly struct BCLoadBundleOptions
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
namespace YooAsset
|
namespace YooAsset
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 验证缓存操作选项
|
/// 验证缓存的操作选项
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal readonly struct BCVerifyCacheOptions
|
internal readonly struct BCVerifyCacheOptions
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
namespace YooAsset
|
namespace YooAsset
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 写入缓存操作选项
|
/// 写入缓存的操作选项
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal readonly struct BCWriteCacheOptions
|
internal readonly struct BCWriteCacheOptions
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ namespace YooAsset
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 创建加载内置资源目录操作实例
|
/// 创建加载内置资源目录操作实例
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="options">加载内置资源目录的配置选项</param>
|
/// <param name="options">加载内置资源目录的操作选项</param>
|
||||||
internal LoadBuiltinCatalogOperation(LoadBuiltinCatalogOptions options)
|
internal LoadBuiltinCatalogOperation(LoadBuiltinCatalogOptions options)
|
||||||
{
|
{
|
||||||
_options = options;
|
_options = options;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
namespace YooAsset
|
namespace YooAsset
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 加载内置资源目录操作选项
|
/// 加载内置资源目录的操作选项
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal readonly struct LoadBuiltinCatalogOptions
|
internal readonly struct LoadBuiltinCatalogOptions
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ namespace YooAsset
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 创建本地 ArchiveBundle 加载操作实例
|
/// 创建本地 ArchiveBundle 加载操作实例
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="options">从本地加载 ArchiveBundle 的配置选项</param>
|
/// <param name="options">从本地加载 ArchiveBundle 的操作选项</param>
|
||||||
public LoadLocalArchiveBundleOperation(LoadLocalArchiveBundleOptions options)
|
public LoadLocalArchiveBundleOperation(LoadLocalArchiveBundleOptions options)
|
||||||
{
|
{
|
||||||
_options = options;
|
_options = options;
|
||||||
@@ -38,26 +38,51 @@ namespace YooAsset
|
|||||||
|
|
||||||
if (_steps == ESteps.LoadBundle)
|
if (_steps == ESteps.LoadBundle)
|
||||||
{
|
{
|
||||||
if (_options.Bundle.IsEncrypted)
|
if (_options.Bundle.IsEncrypted == false)
|
||||||
{
|
{
|
||||||
_steps = ESteps.Done;
|
if (FileUtility.IsFileIOSupported(_options.FilePath) == false)
|
||||||
SetError($"ArchiveBundle encrypted loading is not supported: '{_options.FilePath}'.");
|
{
|
||||||
return;
|
_steps = ESteps.Done;
|
||||||
}
|
SetError($"FileIO is not supported for builtin path: '{_options.FilePath}'.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (FileUtility.IsFileIOSupported(_options.FilePath) == false)
|
LoadResult result = LoadFromFile();
|
||||||
{
|
if (result.Succeeded == false)
|
||||||
_steps = ESteps.Done;
|
{
|
||||||
SetError($"FileIO is not supported for builtin path: '{_options.FilePath}'.");
|
_steps = ESteps.Done;
|
||||||
return;
|
SetError(result.Error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
LoadResult result = ParseArchiveFile();
|
|
||||||
if (result.Succeeded == false)
|
|
||||||
{
|
{
|
||||||
_steps = ESteps.Done;
|
var decryptor = _options.ArchiveBundleDecryptor;
|
||||||
SetError(result.Error);
|
if (decryptor == null)
|
||||||
return;
|
{
|
||||||
|
_steps = ESteps.Done;
|
||||||
|
SetError($"{_options.CacheName} archive bundle decryptor is null.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LoadResult result;
|
||||||
|
if (decryptor is IBundleMemoryDecryptor memoryDecryptor)
|
||||||
|
{
|
||||||
|
result = LoadFromMemory(memoryDecryptor);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_steps = ESteps.Done;
|
||||||
|
SetError($"{_options.CacheName} does not support '{decryptor.GetType().Name}' for ArchiveBundle.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.Succeeded == false)
|
||||||
|
{
|
||||||
|
_steps = ESteps.Done;
|
||||||
|
SetError(result.Error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_steps = ESteps.CheckResult;
|
_steps = ESteps.CheckResult;
|
||||||
@@ -83,16 +108,33 @@ namespace YooAsset
|
|||||||
ExecuteBatch();
|
ExecuteBatch();
|
||||||
}
|
}
|
||||||
|
|
||||||
private LoadResult ParseArchiveFile()
|
private LoadResult LoadFromFile()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_archiveBundle = ArchiveBundleHelper.LoadArchiveBundle(_options.FilePath);
|
_archiveBundle = ArchiveBundleHelper.LoadFromFile(_options.FilePath);
|
||||||
return LoadResult.Default();
|
return LoadResult.Default();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
return LoadResult.Failure($"Failed to parse archive file: {ex.Message}.");
|
return LoadResult.Failure($"Failed to load archive bundle file: {ex.Message}.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private LoadResult LoadFromMemory(IBundleMemoryDecryptor decryptor)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var args = new BundleDecryptArgs(_options.Bundle, null, _options.FilePath);
|
||||||
|
byte[] binaryData = decryptor.GetDecryptedData(args);
|
||||||
|
if (binaryData == null)
|
||||||
|
return LoadResult.Failure($"{_options.CacheName} decryptor returned null data.");
|
||||||
|
|
||||||
|
_archiveBundle = ArchiveBundleHelper.LoadFromMemory(binaryData);
|
||||||
|
return LoadResult.Default();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return LoadResult.Failure($"Failed to load archive bundle file from memory: {ex.Message}.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
namespace YooAsset
|
namespace YooAsset
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 加载 ArchiveBundle 的上下文信息
|
/// 本地加载 ArchiveBundle 的操作选项
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal readonly struct LoadLocalArchiveBundleOptions
|
internal readonly struct LoadLocalArchiveBundleOptions
|
||||||
{
|
{
|
||||||
@@ -21,11 +21,17 @@ namespace YooAsset
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public string FilePath { get; }
|
public string FilePath { get; }
|
||||||
|
|
||||||
public LoadLocalArchiveBundleOptions(string cacheName, PackageBundle bundle, string filePath)
|
/// <summary>
|
||||||
|
/// ArchiveBundle 解密器
|
||||||
|
/// </summary>
|
||||||
|
public IBundleDecryptor ArchiveBundleDecryptor { get; }
|
||||||
|
|
||||||
|
public LoadLocalArchiveBundleOptions(string cacheName, PackageBundle bundle, string filePath, IBundleDecryptor archiveBundleDecryptor)
|
||||||
{
|
{
|
||||||
CacheName = cacheName;
|
CacheName = cacheName;
|
||||||
Bundle = bundle;
|
Bundle = bundle;
|
||||||
FilePath = filePath;
|
FilePath = filePath;
|
||||||
|
ArchiveBundleDecryptor = archiveBundleDecryptor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ namespace YooAsset
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 创建本地 AssetBundle 加载操作实例
|
/// 创建本地 AssetBundle 加载操作实例
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="options">从本地加载 AssetBundle 的配置选项</param>
|
/// <param name="options">从本地加载 AssetBundle 的操作选项</param>
|
||||||
public LoadLocalAssetBundleOperation(LoadLocalAssetBundleOptions options)
|
public LoadLocalAssetBundleOperation(LoadLocalAssetBundleOptions options)
|
||||||
{
|
{
|
||||||
_options = options;
|
_options = options;
|
||||||
@@ -56,14 +56,14 @@ namespace YooAsset
|
|||||||
if (decryptor == null)
|
if (decryptor == null)
|
||||||
{
|
{
|
||||||
_steps = ESteps.Done;
|
_steps = ESteps.Done;
|
||||||
SetError($"{_options.CacheName} decryptor is null.");
|
SetError($"{_options.CacheName} asset bundle decryptor is null.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
LoadResult result;
|
LoadResult result;
|
||||||
if (decryptor is IBundleOffsetDecryptor offsetDecryptor)
|
if (decryptor is IBundleOffsetDecryptor offsetDecryptor)
|
||||||
{
|
{
|
||||||
result = LoadFromFileWithOffset(offsetDecryptor);
|
result = LoadFromFile(offsetDecryptor);
|
||||||
}
|
}
|
||||||
else if (decryptor is IBundleMemoryDecryptor memoryDecryptor)
|
else if (decryptor is IBundleMemoryDecryptor memoryDecryptor)
|
||||||
{
|
{
|
||||||
@@ -76,7 +76,7 @@ namespace YooAsset
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
_steps = ESteps.Done;
|
_steps = ESteps.Done;
|
||||||
SetError($"{_options.CacheName} does not support '{decryptor.GetType().Name}'.");
|
SetError($"{_options.CacheName} does not support '{decryptor.GetType().Name}' for AssetBundle.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,18 +137,17 @@ namespace YooAsset
|
|||||||
else
|
else
|
||||||
_createRequest = AssetBundle.LoadFromFileAsync(_options.FilePath);
|
_createRequest = AssetBundle.LoadFromFileAsync(_options.FilePath);
|
||||||
}
|
}
|
||||||
private LoadResult LoadFromFileWithOffset(IBundleOffsetDecryptor decryptor)
|
private LoadResult LoadFromFile(IBundleOffsetDecryptor decryptor)
|
||||||
{
|
{
|
||||||
var args = new BundleDecryptArgs(_options.Bundle, null, _options.FilePath);
|
var args = new BundleDecryptArgs(_options.Bundle, null, _options.FilePath);
|
||||||
long rawOffset = decryptor.GetFileOffset(args);
|
long offset = decryptor.GetFileOffset(args);
|
||||||
if (rawOffset < 0)
|
if (offset < 0)
|
||||||
return LoadResult.Failure($"{_options.CacheName} decryptor returned negative offset: {rawOffset}.");
|
return LoadResult.Failure($"{_options.CacheName} decryptor returned negative offset: {offset}.");
|
||||||
ulong offset = (ulong)rawOffset;
|
|
||||||
|
|
||||||
if (IsWaitForCompletion)
|
if (IsWaitForCompletion)
|
||||||
_assetBundle = AssetBundle.LoadFromFile(_options.FilePath, 0, offset);
|
_assetBundle = AssetBundle.LoadFromFile(_options.FilePath, 0, (ulong)offset);
|
||||||
else
|
else
|
||||||
_createRequest = AssetBundle.LoadFromFileAsync(_options.FilePath, 0, offset);
|
_createRequest = AssetBundle.LoadFromFileAsync(_options.FilePath, 0, (ulong)offset);
|
||||||
|
|
||||||
return LoadResult.Default();
|
return LoadResult.Default();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
namespace YooAsset
|
namespace YooAsset
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 加载 AssetBundle 的上下文信息
|
/// 本地加载 AssetBundle 的操作选项
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal readonly struct LoadLocalAssetBundleOptions
|
internal readonly struct LoadLocalAssetBundleOptions
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
namespace YooAsset
|
namespace YooAsset
|
||||||
{
|
{
|
||||||
@@ -23,7 +22,7 @@ namespace YooAsset
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// 创建本地 RawBundle 加载操作实例
|
/// 创建本地 RawBundle 加载操作实例
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="options">从本地加载 RawBundle 的配置选项</param>
|
/// <param name="options">从本地加载 RawBundle 的操作选项</param>
|
||||||
public LoadLocalRawBundleOperation(LoadLocalRawBundleOptions options)
|
public LoadLocalRawBundleOperation(LoadLocalRawBundleOptions options)
|
||||||
{
|
{
|
||||||
_options = options;
|
_options = options;
|
||||||
@@ -62,7 +61,7 @@ namespace YooAsset
|
|||||||
if (decryptor == null)
|
if (decryptor == null)
|
||||||
{
|
{
|
||||||
_steps = ESteps.Done;
|
_steps = ESteps.Done;
|
||||||
SetError($"{_options.CacheName} decryptor is null.");
|
SetError($"{_options.CacheName} raw bundle decryptor is null.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -74,7 +73,7 @@ namespace YooAsset
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
_steps = ESteps.Done;
|
_steps = ESteps.Done;
|
||||||
SetError($"{_options.CacheName} does not support '{decryptor.GetType().Name}'.");
|
SetError($"{_options.CacheName} does not support '{decryptor.GetType().Name}' for RawBundle.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,13 +112,12 @@ namespace YooAsset
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
byte[] data = File.ReadAllBytes(_options.FilePath);
|
_rawBundle = RawBundleHelper.LoadFromFile(_options.FilePath);
|
||||||
_rawBundle = new RawBundle(data);
|
|
||||||
return LoadResult.Default();
|
return LoadResult.Default();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
return LoadResult.Failure($"Failed to read raw bundle file: {ex.Message}.");
|
return LoadResult.Failure($"Failed to load raw bundle file: {ex.Message}.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private LoadResult LoadFromMemory(IBundleMemoryDecryptor decryptor)
|
private LoadResult LoadFromMemory(IBundleMemoryDecryptor decryptor)
|
||||||
@@ -129,7 +127,7 @@ namespace YooAsset
|
|||||||
if (binaryData == null)
|
if (binaryData == null)
|
||||||
return LoadResult.Failure($"{_options.CacheName} decryptor returned null data.");
|
return LoadResult.Failure($"{_options.CacheName} decryptor returned null data.");
|
||||||
|
|
||||||
_rawBundle = new RawBundle(binaryData);
|
_rawBundle = RawBundleHelper.LoadFromMemory(binaryData);
|
||||||
return LoadResult.Default();
|
return LoadResult.Default();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
namespace YooAsset
|
namespace YooAsset
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 加载 RawBundle 的上下文信息
|
/// 本地加载 RawBundle 的操作选项
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal readonly struct LoadLocalRawBundleOptions
|
internal readonly struct LoadLocalRawBundleOptions
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -0,0 +1,216 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace YooAsset
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// WebGL 平台加载 ArchiveBundle 操作
|
||||||
|
/// </summary>
|
||||||
|
internal sealed class LoadWebArchiveBundleOperation : BCLoadBundleOperation
|
||||||
|
{
|
||||||
|
private enum ESteps
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
Prepare,
|
||||||
|
DataRequest,
|
||||||
|
CheckRequest,
|
||||||
|
VerifyData,
|
||||||
|
LoadBundle,
|
||||||
|
TryAgain,
|
||||||
|
Done,
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly LoadWebArchiveBundleOptions _options;
|
||||||
|
private readonly DownloadRetryController _downloadRetryController;
|
||||||
|
private IDownloadBytesRequest _downloadBytesRequest;
|
||||||
|
private IBundleMemoryDecryptor _decryptor;
|
||||||
|
private ArchiveBundle _archiveBundle;
|
||||||
|
private ESteps _steps = ESteps.None;
|
||||||
|
|
||||||
|
internal LoadWebArchiveBundleOperation(LoadWebArchiveBundleOptions options)
|
||||||
|
{
|
||||||
|
_options = options;
|
||||||
|
|
||||||
|
// 注意:网络原因失败后,重新尝试直到成功
|
||||||
|
_downloadRetryController = new DownloadRetryController(int.MaxValue, options.DownloadRetryPolicy);
|
||||||
|
}
|
||||||
|
protected override void InternalStart()
|
||||||
|
{
|
||||||
|
_steps = ESteps.Prepare;
|
||||||
|
}
|
||||||
|
protected override void InternalUpdate()
|
||||||
|
{
|
||||||
|
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_steps == ESteps.Prepare)
|
||||||
|
{
|
||||||
|
if (_options.Bundle.IsEncrypted == false)
|
||||||
|
{
|
||||||
|
_steps = ESteps.DataRequest;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var decryptor = _options.ArchiveBundleDecryptor;
|
||||||
|
if (decryptor == null)
|
||||||
|
{
|
||||||
|
_steps = ESteps.Done;
|
||||||
|
SetError($"{_options.CacheName} archive bundle decryptor is null.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (decryptor is IBundleMemoryDecryptor)
|
||||||
|
{
|
||||||
|
_decryptor = decryptor as IBundleMemoryDecryptor;
|
||||||
|
_steps = ESteps.DataRequest;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_steps = ESteps.Done;
|
||||||
|
SetError($"{_options.CacheName} does not support '{decryptor.GetType().Name}' for ArchiveBundle.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_steps == ESteps.DataRequest)
|
||||||
|
{
|
||||||
|
string url = _options.DownloadUrlPolicy.SelectUrl(_options.CandidateUrls);
|
||||||
|
var args = new DownloadDataRequestArgs(
|
||||||
|
url: url,
|
||||||
|
timeout: 0,
|
||||||
|
watchdogTimeout: _options.WatchdogTimeout);
|
||||||
|
_downloadBytesRequest = _options.DownloadBackend.CreateBytesRequest(args);
|
||||||
|
_downloadBytesRequest.SendRequest();
|
||||||
|
_steps = ESteps.CheckRequest;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_steps == ESteps.CheckRequest)
|
||||||
|
{
|
||||||
|
Progress = _downloadBytesRequest.DownloadProgress;
|
||||||
|
if (_downloadBytesRequest.IsDone == false)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_downloadBytesRequest.Status == EDownloadRequestStatus.Succeeded)
|
||||||
|
{
|
||||||
|
_options.DownloadUrlPolicy.OnRequestSucceeded(_downloadBytesRequest.Url);
|
||||||
|
_steps = ESteps.VerifyData;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string url = _downloadBytesRequest.Url;
|
||||||
|
long httpCode = _downloadBytesRequest.HttpCode;
|
||||||
|
string httpError = _downloadBytesRequest.HttpError;
|
||||||
|
_options.DownloadUrlPolicy.OnRequestFailed(url, httpCode, httpError);
|
||||||
|
if (IsWaitForCompletion == false && _downloadRetryController.CanRetryRequest(url, httpCode, httpError))
|
||||||
|
{
|
||||||
|
_downloadRetryController.StartRetryDelay();
|
||||||
|
_steps = ESteps.TryAgain;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_steps = ESteps.Done;
|
||||||
|
SetError(_downloadBytesRequest.Error);
|
||||||
|
YooLogger.LogError(Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_steps == ESteps.VerifyData)
|
||||||
|
{
|
||||||
|
// 注意:网络/代理/服务器异常导致内容不完整但请求仍成功
|
||||||
|
EFileVerifyResult verifyResult;
|
||||||
|
if (_options.DownloadVerifyLevel == EFileVerifyLevel.Low || _options.DownloadVerifyLevel == EFileVerifyLevel.Middle)
|
||||||
|
verifyResult = FileVerifyHelper.VerifyFile(_downloadBytesRequest.Result, _options.Bundle.FileSize, 0);
|
||||||
|
else if (_options.DownloadVerifyLevel == EFileVerifyLevel.High)
|
||||||
|
verifyResult = FileVerifyHelper.VerifyFile(_downloadBytesRequest.Result, _options.Bundle.FileSize, _options.Bundle.FileCrc);
|
||||||
|
else
|
||||||
|
throw new YooInternalException($"Unexpected verify level: {_options.DownloadVerifyLevel}.");
|
||||||
|
|
||||||
|
if (verifyResult == EFileVerifyResult.Succeed)
|
||||||
|
{
|
||||||
|
_steps = ESteps.LoadBundle;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string error = $"Verify failed. Url: '{_downloadBytesRequest.Url}' Level: {_options.DownloadVerifyLevel} Result: {verifyResult}.";
|
||||||
|
YooLogger.LogWarning(error);
|
||||||
|
|
||||||
|
if (IsWaitForCompletion == false && _downloadRetryController.HasRetriesRemaining())
|
||||||
|
{
|
||||||
|
_downloadRetryController.StartRetryDelay();
|
||||||
|
_steps = ESteps.TryAgain;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_steps = ESteps.Done;
|
||||||
|
SetError(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_steps == ESteps.LoadBundle)
|
||||||
|
{
|
||||||
|
LoadResult result = LoadFromMemory(_decryptor, _downloadBytesRequest.Result);
|
||||||
|
if (result.Succeeded == false)
|
||||||
|
{
|
||||||
|
_steps = ESteps.Done;
|
||||||
|
SetError(result.Error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_steps = ESteps.Done;
|
||||||
|
SetResult();
|
||||||
|
BundleHandle = new ArchiveBundleHandle(_options.Bundle, _archiveBundle);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_steps == ESteps.TryAgain)
|
||||||
|
{
|
||||||
|
// 注意:失败后释放网络请求
|
||||||
|
if (_downloadBytesRequest != null)
|
||||||
|
{
|
||||||
|
_downloadBytesRequest.Dispose();
|
||||||
|
_downloadBytesRequest = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_downloadRetryController.TickRetryDelay())
|
||||||
|
{
|
||||||
|
Progress = 0f;
|
||||||
|
_steps = ESteps.DataRequest;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
protected override void InternalDispose()
|
||||||
|
{
|
||||||
|
if (_downloadBytesRequest != null)
|
||||||
|
{
|
||||||
|
_downloadBytesRequest.Dispose();
|
||||||
|
_downloadBytesRequest = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private LoadResult LoadFromMemory(IBundleMemoryDecryptor decryptor, byte[] fileData)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (decryptor != null)
|
||||||
|
{
|
||||||
|
var args = new BundleDecryptArgs(_options.Bundle, fileData, null);
|
||||||
|
var binaryData = decryptor.GetDecryptedData(args);
|
||||||
|
if (binaryData == null)
|
||||||
|
return LoadResult.Failure($"{_options.CacheName} decryptor returned null data.");
|
||||||
|
|
||||||
|
_archiveBundle = ArchiveBundleHelper.LoadFromMemory(binaryData);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_archiveBundle = ArchiveBundleHelper.LoadFromMemory(fileData);
|
||||||
|
}
|
||||||
|
return LoadResult.Default();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return LoadResult.Failure($"Failed to load archive bundle from memory: {ex.Message}.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: f0fd9af541471154d9fc968abd450d31
|
guid: 00ec926bdc7c65e40a464570d27570d9
|
||||||
MonoImporter:
|
MonoImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
serializedVersion: 2
|
serializedVersion: 2
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace YooAsset
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// WebGL 平台加载 ArchiveBundle 的操作选项
|
||||||
|
/// </summary>
|
||||||
|
internal readonly struct LoadWebArchiveBundleOptions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 文件缓存名称
|
||||||
|
/// </summary>
|
||||||
|
public string CacheName { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 资源包描述
|
||||||
|
/// </summary>
|
||||||
|
public PackageBundle Bundle { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 候选下载地址列表
|
||||||
|
/// </summary>
|
||||||
|
public IReadOnlyList<string> CandidateUrls { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// ArchiveBundle 解密器
|
||||||
|
/// </summary>
|
||||||
|
public IBundleDecryptor ArchiveBundleDecryptor { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 下载后台接口
|
||||||
|
/// </summary>
|
||||||
|
public IDownloadBackend DownloadBackend { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 下载数据校验级别
|
||||||
|
/// </summary>
|
||||||
|
public EFileVerifyLevel DownloadVerifyLevel { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 看门狗超时时间
|
||||||
|
/// </summary>
|
||||||
|
public int WatchdogTimeout { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 下载重试判定策略
|
||||||
|
/// </summary>
|
||||||
|
public IDownloadRetryPolicy DownloadRetryPolicy { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// URL 选择策略
|
||||||
|
/// </summary>
|
||||||
|
public IDownloadUrlPolicy DownloadUrlPolicy { get; }
|
||||||
|
|
||||||
|
public LoadWebArchiveBundleOptions(string cacheName, PackageBundle bundle, IReadOnlyList<string> candidateUrls,
|
||||||
|
IBundleDecryptor archiveBundleDecryptor, IDownloadBackend downloadBackend, EFileVerifyLevel downloadVerifyLevel,
|
||||||
|
int watchdogTimeout, IDownloadRetryPolicy downloadRetryPolicy, IDownloadUrlPolicy downloadUrlPolicy)
|
||||||
|
{
|
||||||
|
CacheName = cacheName;
|
||||||
|
Bundle = bundle;
|
||||||
|
CandidateUrls = candidateUrls;
|
||||||
|
ArchiveBundleDecryptor = archiveBundleDecryptor;
|
||||||
|
DownloadBackend = downloadBackend;
|
||||||
|
DownloadVerifyLevel = downloadVerifyLevel;
|
||||||
|
WatchdogTimeout = watchdogTimeout;
|
||||||
|
DownloadRetryPolicy = downloadRetryPolicy;
|
||||||
|
DownloadUrlPolicy = downloadUrlPolicy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 87ff97cf646c9e240a2f2f2e37963353
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -3,136 +3,14 @@ using UnityEngine;
|
|||||||
namespace YooAsset
|
namespace YooAsset
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 从网络加载未加密 AssetBundle 操作
|
/// WebGL 平台加载加密 AssetBundle 操作
|
||||||
/// </summary>
|
|
||||||
internal sealed class LoadWebNormalAssetBundleOperation : BCLoadBundleOperation
|
|
||||||
{
|
|
||||||
private enum ESteps
|
|
||||||
{
|
|
||||||
None,
|
|
||||||
BundleRequest,
|
|
||||||
CheckRequest,
|
|
||||||
TryAgain,
|
|
||||||
Done,
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly LoadWebAssetBundleOptions _options;
|
|
||||||
private readonly DownloadRetryController _downloadRetryController;
|
|
||||||
private IDownloadAssetBundleRequest _downloadAssetBundleRequest;
|
|
||||||
private ESteps _steps = ESteps.None;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 创建 LoadWebNormalAssetBundleOperation 实例
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="options">从网络加载 AssetBundle 的配置选项</param>
|
|
||||||
public LoadWebNormalAssetBundleOperation(LoadWebAssetBundleOptions options)
|
|
||||||
{
|
|
||||||
_options = options;
|
|
||||||
|
|
||||||
// 注意:网络原因失败后,重新尝试直到成功
|
|
||||||
_downloadRetryController = new DownloadRetryController(int.MaxValue, options.DownloadRetryPolicy);
|
|
||||||
}
|
|
||||||
protected override void InternalStart()
|
|
||||||
{
|
|
||||||
_steps = ESteps.BundleRequest;
|
|
||||||
}
|
|
||||||
protected override void InternalUpdate()
|
|
||||||
{
|
|
||||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (_steps == ESteps.BundleRequest)
|
|
||||||
{
|
|
||||||
string url = _options.DownloadUrlPolicy.SelectUrl(_options.CandidateUrls);
|
|
||||||
var args = new DownloadAssetBundleRequestArgs(
|
|
||||||
url: url,
|
|
||||||
timeout: 0,
|
|
||||||
watchdogTimeout: _options.WatchdogTimeout,
|
|
||||||
disableUnityWebCache: _options.DisableUnityWebCache,
|
|
||||||
fileHash: _options.Bundle.FileHash,
|
|
||||||
unityCrc: _options.Bundle.UnityCrc);
|
|
||||||
_downloadAssetBundleRequest = _options.DownloadBackend.CreateAssetBundleRequest(args);
|
|
||||||
_downloadAssetBundleRequest.SendRequest();
|
|
||||||
_steps = ESteps.CheckRequest;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_steps == ESteps.CheckRequest)
|
|
||||||
{
|
|
||||||
Progress = _downloadAssetBundleRequest.DownloadProgress;
|
|
||||||
if (_downloadAssetBundleRequest.IsDone == false)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (_downloadAssetBundleRequest.Status == EDownloadRequestStatus.Succeeded)
|
|
||||||
{
|
|
||||||
_options.DownloadUrlPolicy.OnRequestSucceeded(_downloadAssetBundleRequest.Url);
|
|
||||||
var assetBundle = _downloadAssetBundleRequest.Result;
|
|
||||||
if (assetBundle == null)
|
|
||||||
{
|
|
||||||
_steps = ESteps.Done;
|
|
||||||
SetError($"Downloaded asset bundle is null. URL: {_downloadAssetBundleRequest.Url}");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_steps = ESteps.Done;
|
|
||||||
SetResult();
|
|
||||||
BundleHandle = new AssetBundleHandle(_options.Bundle, assetBundle, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
string url = _downloadAssetBundleRequest.Url;
|
|
||||||
long httpCode = _downloadAssetBundleRequest.HttpCode;
|
|
||||||
string httpError = _downloadAssetBundleRequest.HttpError;
|
|
||||||
_options.DownloadUrlPolicy.OnRequestFailed(url, httpCode, httpError);
|
|
||||||
|
|
||||||
if (IsWaitForCompletion == false && _downloadRetryController.CanRetryRequest(url, httpCode, httpError))
|
|
||||||
{
|
|
||||||
_downloadRetryController.StartRetryDelay();
|
|
||||||
_steps = ESteps.TryAgain;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_steps = ESteps.Done;
|
|
||||||
SetError(_downloadAssetBundleRequest.Error);
|
|
||||||
YooLogger.LogError(Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_steps == ESteps.TryAgain)
|
|
||||||
{
|
|
||||||
// 注意:失败后释放网络请求
|
|
||||||
if (_downloadAssetBundleRequest != null)
|
|
||||||
{
|
|
||||||
_downloadAssetBundleRequest.Dispose();
|
|
||||||
_downloadAssetBundleRequest = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_downloadRetryController.TickRetryDelay())
|
|
||||||
{
|
|
||||||
Progress = 0f;
|
|
||||||
_steps = ESteps.BundleRequest;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
protected override void InternalDispose()
|
|
||||||
{
|
|
||||||
if (_downloadAssetBundleRequest != null)
|
|
||||||
{
|
|
||||||
_downloadAssetBundleRequest.Dispose();
|
|
||||||
_downloadAssetBundleRequest = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 从网络加载加密的 AssetBundle 操作
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal sealed class LoadWebEncryptedAssetBundleOperation : BCLoadBundleOperation
|
internal sealed class LoadWebEncryptedAssetBundleOperation : BCLoadBundleOperation
|
||||||
{
|
{
|
||||||
private enum ESteps
|
private enum ESteps
|
||||||
{
|
{
|
||||||
None,
|
None,
|
||||||
|
Prepare,
|
||||||
DataRequest,
|
DataRequest,
|
||||||
CheckRequest,
|
CheckRequest,
|
||||||
VerifyData,
|
VerifyData,
|
||||||
@@ -142,18 +20,14 @@ namespace YooAsset
|
|||||||
Done,
|
Done,
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly LoadWebAssetBundleOptions _options;
|
private readonly LoadWebEncryptedAssetBundleOptions _options;
|
||||||
private readonly DownloadRetryController _downloadRetryController;
|
private readonly DownloadRetryController _downloadRetryController;
|
||||||
private IDownloadBytesRequest _downloadBytesRequest;
|
private IDownloadBytesRequest _downloadBytesRequest;
|
||||||
private IBundleMemoryDecryptor _decryptor;
|
private IBundleMemoryDecryptor _decryptor;
|
||||||
private AssetBundleCreateRequest _createRequest;
|
private AssetBundleCreateRequest _createRequest;
|
||||||
private ESteps _steps = ESteps.None;
|
private ESteps _steps = ESteps.None;
|
||||||
|
|
||||||
/// <summary>
|
public LoadWebEncryptedAssetBundleOperation(LoadWebEncryptedAssetBundleOptions options)
|
||||||
/// 创建 LoadWebEncryptedAssetBundleOperation 实例
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="options">从网络加载 AssetBundle 的配置选项</param>
|
|
||||||
public LoadWebEncryptedAssetBundleOperation(LoadWebAssetBundleOptions options)
|
|
||||||
{
|
{
|
||||||
_options = options;
|
_options = options;
|
||||||
|
|
||||||
@@ -162,43 +36,48 @@ namespace YooAsset
|
|||||||
}
|
}
|
||||||
protected override void InternalStart()
|
protected override void InternalStart()
|
||||||
{
|
{
|
||||||
_steps = ESteps.DataRequest;
|
_steps = ESteps.Prepare;
|
||||||
}
|
}
|
||||||
protected override void InternalUpdate()
|
protected override void InternalUpdate()
|
||||||
{
|
{
|
||||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (_steps == ESteps.DataRequest)
|
if (_steps == ESteps.Prepare)
|
||||||
{
|
{
|
||||||
var decryptor = _options.AssetBundleDecryptor;
|
var decryptor = _options.AssetBundleDecryptor;
|
||||||
if (decryptor == null)
|
if (decryptor == null)
|
||||||
{
|
{
|
||||||
_steps = ESteps.Done;
|
_steps = ESteps.Done;
|
||||||
SetError($"{_options.CacheName} decryptor is null.");
|
SetError($"{_options.CacheName} asset bundle decryptor is null.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (decryptor is IBundleMemoryDecryptor)
|
if (decryptor is IBundleMemoryDecryptor)
|
||||||
{
|
{
|
||||||
_decryptor = decryptor as IBundleMemoryDecryptor;
|
_decryptor = decryptor as IBundleMemoryDecryptor;
|
||||||
string url = _options.DownloadUrlPolicy.SelectUrl(_options.CandidateUrls);
|
_steps = ESteps.DataRequest;
|
||||||
var args = new DownloadDataRequestArgs(
|
|
||||||
url: url,
|
|
||||||
timeout: 0,
|
|
||||||
watchdogTimeout: _options.WatchdogTimeout);
|
|
||||||
_downloadBytesRequest = _options.DownloadBackend.CreateBytesRequest(args);
|
|
||||||
_downloadBytesRequest.SendRequest();
|
|
||||||
_steps = ESteps.CheckRequest;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_steps = ESteps.Done;
|
_steps = ESteps.Done;
|
||||||
SetError($"{_options.CacheName} does not support '{decryptor.GetType().Name}'.");
|
SetError($"{_options.CacheName} does not support '{decryptor.GetType().Name}' for ArchiveBundle.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_steps == ESteps.DataRequest)
|
||||||
|
{
|
||||||
|
string url = _options.DownloadUrlPolicy.SelectUrl(_options.CandidateUrls);
|
||||||
|
var args = new DownloadDataRequestArgs(
|
||||||
|
url: url,
|
||||||
|
timeout: 0,
|
||||||
|
watchdogTimeout: _options.WatchdogTimeout);
|
||||||
|
_downloadBytesRequest = _options.DownloadBackend.CreateBytesRequest(args);
|
||||||
|
_downloadBytesRequest.SendRequest();
|
||||||
|
_steps = ESteps.CheckRequest;
|
||||||
|
}
|
||||||
|
|
||||||
if (_steps == ESteps.CheckRequest)
|
if (_steps == ESteps.CheckRequest)
|
||||||
{
|
{
|
||||||
Progress = _downloadBytesRequest.DownloadProgress;
|
Progress = _downloadBytesRequest.DownloadProgress;
|
||||||
@@ -225,6 +104,7 @@ namespace YooAsset
|
|||||||
{
|
{
|
||||||
_steps = ESteps.Done;
|
_steps = ESteps.Done;
|
||||||
SetError(_downloadBytesRequest.Error);
|
SetError(_downloadBytesRequest.Error);
|
||||||
|
YooLogger.LogError(Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -246,7 +126,7 @@ namespace YooAsset
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
string error = $"[WebBundleVerify] Verify failed. Url: '{_downloadBytesRequest.Url}' Level: {_options.DownloadVerifyLevel} Result: {verifyResult}.";
|
string error = $"Verify failed. Url: '{_downloadBytesRequest.Url}' Level: {_options.DownloadVerifyLevel} Result: {verifyResult}.";
|
||||||
YooLogger.LogWarning(error);
|
YooLogger.LogWarning(error);
|
||||||
|
|
||||||
if (IsWaitForCompletion == false && _downloadRetryController.HasRetriesRemaining())
|
if (IsWaitForCompletion == false && _downloadRetryController.HasRetriesRemaining())
|
||||||
@@ -284,7 +164,7 @@ namespace YooAsset
|
|||||||
if (assetBundle == null)
|
if (assetBundle == null)
|
||||||
{
|
{
|
||||||
_steps = ESteps.Done;
|
_steps = ESteps.Done;
|
||||||
SetError("Unity engine load failed.");
|
SetError("Unity engine load asset bundle failed.");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 559636cb5e3e48e4bb79e14a70a1ea4f
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -3,9 +3,9 @@ using System.Collections.Generic;
|
|||||||
namespace YooAsset
|
namespace YooAsset
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 加载 AssetBundle 的上下文信息
|
/// WebGL 平台加载加密 AssetBundle 的操作选项
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal readonly struct LoadWebAssetBundleOptions
|
internal readonly struct LoadWebEncryptedAssetBundleOptions
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 文件缓存名称
|
/// 文件缓存名称
|
||||||
@@ -42,11 +42,6 @@ namespace YooAsset
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public int WatchdogTimeout { get; }
|
public int WatchdogTimeout { get; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 禁用 Unity 内置网络缓存
|
|
||||||
/// </summary>
|
|
||||||
public bool DisableUnityWebCache { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 下载重试判定策略
|
/// 下载重试判定策略
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -57,9 +52,9 @@ namespace YooAsset
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public IDownloadUrlPolicy DownloadUrlPolicy { get; }
|
public IDownloadUrlPolicy DownloadUrlPolicy { get; }
|
||||||
|
|
||||||
public LoadWebAssetBundleOptions(string cacheName, PackageBundle bundle, IReadOnlyList<string> candidateUrls,
|
public LoadWebEncryptedAssetBundleOptions(string cacheName, PackageBundle bundle, IReadOnlyList<string> candidateUrls,
|
||||||
IBundleDecryptor assetBundleDecryptor, IDownloadBackend downloadBackend, EFileVerifyLevel downloadVerifyLevel,
|
IBundleDecryptor assetBundleDecryptor, IDownloadBackend downloadBackend, EFileVerifyLevel downloadVerifyLevel,
|
||||||
int watchdogTimeout, bool disableUnityWebCache, IDownloadRetryPolicy downloadRetryPolicy, IDownloadUrlPolicy downloadUrlPolicy)
|
int watchdogTimeout, IDownloadRetryPolicy downloadRetryPolicy, IDownloadUrlPolicy downloadUrlPolicy)
|
||||||
{
|
{
|
||||||
CacheName = cacheName;
|
CacheName = cacheName;
|
||||||
Bundle = bundle;
|
Bundle = bundle;
|
||||||
@@ -68,7 +63,6 @@ namespace YooAsset
|
|||||||
DownloadBackend = downloadBackend;
|
DownloadBackend = downloadBackend;
|
||||||
DownloadVerifyLevel = downloadVerifyLevel;
|
DownloadVerifyLevel = downloadVerifyLevel;
|
||||||
WatchdogTimeout = watchdogTimeout;
|
WatchdogTimeout = watchdogTimeout;
|
||||||
DisableUnityWebCache = disableUnityWebCache;
|
|
||||||
DownloadRetryPolicy = downloadRetryPolicy;
|
DownloadRetryPolicy = downloadRetryPolicy;
|
||||||
DownloadUrlPolicy = downloadUrlPolicy;
|
DownloadUrlPolicy = downloadUrlPolicy;
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: e98882b2de6b0644fab7549b1a19eb76
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -1,11 +1,9 @@
|
|||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace YooAsset
|
namespace YooAsset
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 从 WebGL 游戏平台加载非加密 AssetBundle 操作
|
/// WebGL 平台加载非加密 AssetBundle 操作
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal sealed class LoadWebGameAssetBundleOperation : BCLoadBundleOperation
|
internal sealed class LoadWebPlatformAssetBundleOperation : BCLoadBundleOperation
|
||||||
{
|
{
|
||||||
private enum ESteps
|
private enum ESteps
|
||||||
{
|
{
|
||||||
@@ -16,12 +14,12 @@ namespace YooAsset
|
|||||||
Done,
|
Done,
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly LoadWebGameAssetBundleOptions _options;
|
private readonly LoadWebPlatformAssetBundleOptions _options;
|
||||||
private readonly DownloadRetryController _downloadRetryController;
|
private readonly DownloadRetryController _downloadRetryController;
|
||||||
private IDownloadAssetBundleRequest _downloadAssetBundleRequest;
|
private IDownloadAssetBundleRequest _downloadAssetBundleRequest;
|
||||||
private ESteps _steps = ESteps.None;
|
private ESteps _steps = ESteps.None;
|
||||||
|
|
||||||
internal LoadWebGameAssetBundleOperation(LoadWebGameAssetBundleOptions options)
|
internal LoadWebPlatformAssetBundleOperation(LoadWebPlatformAssetBundleOptions options)
|
||||||
{
|
{
|
||||||
_options = options;
|
_options = options;
|
||||||
|
|
||||||
@@ -40,11 +38,15 @@ namespace YooAsset
|
|||||||
if (_steps == ESteps.BundleRequest)
|
if (_steps == ESteps.BundleRequest)
|
||||||
{
|
{
|
||||||
string url = _options.DownloadUrlPolicy.SelectUrl(_options.CandidateUrls);
|
string url = _options.DownloadUrlPolicy.SelectUrl(_options.CandidateUrls);
|
||||||
var args = new DownloadRequestArgs(
|
var args = new DownloadAssetBundleRequestArgs(
|
||||||
url: url,
|
url: url,
|
||||||
timeout: 0,
|
timeout: 0,
|
||||||
watchdogTimeout: _options.WatchdogTimeout);
|
watchdogTimeout: _options.WatchdogTimeout,
|
||||||
_downloadAssetBundleRequest = new WebGameAssetBundleRequest(args, _options.GamePlatform);
|
disableUnityWebCache: _options.DisableUnityWebCache,
|
||||||
|
fileHash: _options.Bundle.FileHash,
|
||||||
|
unityCrc: _options.Bundle.UnityCrc,
|
||||||
|
platformStrategy: _options.PlatformStrategy);
|
||||||
|
_downloadAssetBundleRequest = _options.DownloadBackend.CreateAssetBundleRequest(args);
|
||||||
_downloadAssetBundleRequest.SendRequest();
|
_downloadAssetBundleRequest.SendRequest();
|
||||||
_steps = ESteps.CheckRequest;
|
_steps = ESteps.CheckRequest;
|
||||||
}
|
}
|
||||||
@@ -69,7 +71,7 @@ namespace YooAsset
|
|||||||
{
|
{
|
||||||
_steps = ESteps.Done;
|
_steps = ESteps.Done;
|
||||||
SetResult();
|
SetResult();
|
||||||
BundleHandle = new WebGameAssetBundleHandle(_options.Bundle, assetBundle, _options.GamePlatform);
|
BundleHandle = new WebAssetBundleHandle(_options.Bundle, assetBundle, _options.PlatformStrategy);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: dc432c9fb60357e4f985284caae506f6
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -3,9 +3,9 @@ using System.Collections.Generic;
|
|||||||
namespace YooAsset
|
namespace YooAsset
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// WebGL 游戏平台加载 AssetBundle 的配置选项
|
/// WebGL 平台加载非加密 AssetBundle 的操作选项
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal readonly struct LoadWebGameAssetBundleOptions
|
internal readonly struct LoadWebPlatformAssetBundleOptions
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 资源包描述
|
/// 资源包描述
|
||||||
@@ -18,15 +18,25 @@ namespace YooAsset
|
|||||||
public IReadOnlyList<string> CandidateUrls { get; }
|
public IReadOnlyList<string> CandidateUrls { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 游戏平台接口
|
/// 平台策略
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IWebGamePlatform GamePlatform { get; }
|
public IWebPlatformStrategy PlatformStrategy { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 下载后台接口
|
||||||
|
/// </summary>
|
||||||
|
public IDownloadBackend DownloadBackend { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 看门狗超时时间
|
/// 看门狗超时时间
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int WatchdogTimeout { get; }
|
public int WatchdogTimeout { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 禁用 Unity 内置网络缓存
|
||||||
|
/// </summary>
|
||||||
|
public bool DisableUnityWebCache { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 下载重试判定策略
|
/// 下载重试判定策略
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -37,14 +47,16 @@ namespace YooAsset
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public IDownloadUrlPolicy DownloadUrlPolicy { get; }
|
public IDownloadUrlPolicy DownloadUrlPolicy { get; }
|
||||||
|
|
||||||
public LoadWebGameAssetBundleOptions(PackageBundle bundle, IReadOnlyList<string> candidateUrls,
|
public LoadWebPlatformAssetBundleOptions(PackageBundle bundle, IReadOnlyList<string> candidateUrls,
|
||||||
IWebGamePlatform gamePlatform, int watchdogTimeout,
|
IWebPlatformStrategy platformStrategy, IDownloadBackend downloadBackend, int watchdogTimeout, bool disableUnityWebCache,
|
||||||
IDownloadRetryPolicy downloadRetryPolicy, IDownloadUrlPolicy downloadUrlPolicy)
|
IDownloadRetryPolicy downloadRetryPolicy, IDownloadUrlPolicy downloadUrlPolicy)
|
||||||
{
|
{
|
||||||
Bundle = bundle;
|
Bundle = bundle;
|
||||||
CandidateUrls = candidateUrls;
|
CandidateUrls = candidateUrls;
|
||||||
GamePlatform = gamePlatform;
|
PlatformStrategy = platformStrategy;
|
||||||
|
DownloadBackend = downloadBackend;
|
||||||
WatchdogTimeout = watchdogTimeout;
|
WatchdogTimeout = watchdogTimeout;
|
||||||
|
DisableUnityWebCache = disableUnityWebCache;
|
||||||
DownloadRetryPolicy = downloadRetryPolicy;
|
DownloadRetryPolicy = downloadRetryPolicy;
|
||||||
DownloadUrlPolicy = downloadUrlPolicy;
|
DownloadUrlPolicy = downloadUrlPolicy;
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 28cb5372ae5766e409aab15dfe109e95
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,216 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace YooAsset
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// WebGL 平台加载 RawBundle 操作
|
||||||
|
/// </summary>
|
||||||
|
internal sealed class LoadWebRawBundleOperation : BCLoadBundleOperation
|
||||||
|
{
|
||||||
|
private enum ESteps
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
Prepare,
|
||||||
|
DataRequest,
|
||||||
|
CheckRequest,
|
||||||
|
VerifyData,
|
||||||
|
LoadBundle,
|
||||||
|
TryAgain,
|
||||||
|
Done,
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly LoadWebRawBundleOptions _options;
|
||||||
|
private readonly DownloadRetryController _downloadRetryController;
|
||||||
|
private IDownloadBytesRequest _downloadBytesRequest;
|
||||||
|
private IBundleMemoryDecryptor _decryptor;
|
||||||
|
private RawBundle _rawBundle;
|
||||||
|
private ESteps _steps = ESteps.None;
|
||||||
|
|
||||||
|
internal LoadWebRawBundleOperation(LoadWebRawBundleOptions options)
|
||||||
|
{
|
||||||
|
_options = options;
|
||||||
|
|
||||||
|
// 注意:网络原因失败后,重新尝试直到成功
|
||||||
|
_downloadRetryController = new DownloadRetryController(int.MaxValue, options.DownloadRetryPolicy);
|
||||||
|
}
|
||||||
|
protected override void InternalStart()
|
||||||
|
{
|
||||||
|
_steps = ESteps.Prepare;
|
||||||
|
}
|
||||||
|
protected override void InternalUpdate()
|
||||||
|
{
|
||||||
|
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_steps == ESteps.Prepare)
|
||||||
|
{
|
||||||
|
if (_options.Bundle.IsEncrypted == false)
|
||||||
|
{
|
||||||
|
_steps = ESteps.DataRequest;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var decryptor = _options.RawBundleDecryptor;
|
||||||
|
if (decryptor == null)
|
||||||
|
{
|
||||||
|
_steps = ESteps.Done;
|
||||||
|
SetError($"{_options.CacheName} raw bundle decryptor is null.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (decryptor is IBundleMemoryDecryptor)
|
||||||
|
{
|
||||||
|
_decryptor = decryptor as IBundleMemoryDecryptor;
|
||||||
|
_steps = ESteps.DataRequest;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_steps = ESteps.Done;
|
||||||
|
SetError($"{_options.CacheName} does not support '{decryptor.GetType().Name}' for RawBundle.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_steps == ESteps.DataRequest)
|
||||||
|
{
|
||||||
|
string url = _options.DownloadUrlPolicy.SelectUrl(_options.CandidateUrls);
|
||||||
|
var args = new DownloadDataRequestArgs(
|
||||||
|
url: url,
|
||||||
|
timeout: 0,
|
||||||
|
watchdogTimeout: _options.WatchdogTimeout);
|
||||||
|
_downloadBytesRequest = _options.DownloadBackend.CreateBytesRequest(args);
|
||||||
|
_downloadBytesRequest.SendRequest();
|
||||||
|
_steps = ESteps.CheckRequest;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_steps == ESteps.CheckRequest)
|
||||||
|
{
|
||||||
|
Progress = _downloadBytesRequest.DownloadProgress;
|
||||||
|
if (_downloadBytesRequest.IsDone == false)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_downloadBytesRequest.Status == EDownloadRequestStatus.Succeeded)
|
||||||
|
{
|
||||||
|
_options.DownloadUrlPolicy.OnRequestSucceeded(_downloadBytesRequest.Url);
|
||||||
|
_steps = ESteps.VerifyData;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string url = _downloadBytesRequest.Url;
|
||||||
|
long httpCode = _downloadBytesRequest.HttpCode;
|
||||||
|
string httpError = _downloadBytesRequest.HttpError;
|
||||||
|
_options.DownloadUrlPolicy.OnRequestFailed(url, httpCode, httpError);
|
||||||
|
if (IsWaitForCompletion == false && _downloadRetryController.CanRetryRequest(url, httpCode, httpError))
|
||||||
|
{
|
||||||
|
_downloadRetryController.StartRetryDelay();
|
||||||
|
_steps = ESteps.TryAgain;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_steps = ESteps.Done;
|
||||||
|
SetError(_downloadBytesRequest.Error);
|
||||||
|
YooLogger.LogError(Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_steps == ESteps.VerifyData)
|
||||||
|
{
|
||||||
|
// 注意:网络/代理/服务器异常导致内容不完整但请求仍成功
|
||||||
|
EFileVerifyResult verifyResult;
|
||||||
|
if (_options.DownloadVerifyLevel == EFileVerifyLevel.Low || _options.DownloadVerifyLevel == EFileVerifyLevel.Middle)
|
||||||
|
verifyResult = FileVerifyHelper.VerifyFile(_downloadBytesRequest.Result, _options.Bundle.FileSize, 0);
|
||||||
|
else if (_options.DownloadVerifyLevel == EFileVerifyLevel.High)
|
||||||
|
verifyResult = FileVerifyHelper.VerifyFile(_downloadBytesRequest.Result, _options.Bundle.FileSize, _options.Bundle.FileCrc);
|
||||||
|
else
|
||||||
|
throw new YooInternalException($"Unexpected verify level: {_options.DownloadVerifyLevel}.");
|
||||||
|
|
||||||
|
if (verifyResult == EFileVerifyResult.Succeed)
|
||||||
|
{
|
||||||
|
_steps = ESteps.LoadBundle;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string error = $"Verify failed. Url: '{_downloadBytesRequest.Url}' Level: {_options.DownloadVerifyLevel} Result: {verifyResult}.";
|
||||||
|
YooLogger.LogWarning(error);
|
||||||
|
|
||||||
|
if (IsWaitForCompletion == false && _downloadRetryController.HasRetriesRemaining())
|
||||||
|
{
|
||||||
|
_downloadRetryController.StartRetryDelay();
|
||||||
|
_steps = ESteps.TryAgain;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_steps = ESteps.Done;
|
||||||
|
SetError(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_steps == ESteps.LoadBundle)
|
||||||
|
{
|
||||||
|
LoadResult result = LoadFromMemory(_decryptor, _downloadBytesRequest.Result);
|
||||||
|
if (result.Succeeded == false)
|
||||||
|
{
|
||||||
|
_steps = ESteps.Done;
|
||||||
|
SetError(result.Error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_steps = ESteps.Done;
|
||||||
|
SetResult();
|
||||||
|
BundleHandle = new RawBundleHandle(_options.Bundle, _rawBundle);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_steps == ESteps.TryAgain)
|
||||||
|
{
|
||||||
|
// 注意:失败后释放网络请求
|
||||||
|
if (_downloadBytesRequest != null)
|
||||||
|
{
|
||||||
|
_downloadBytesRequest.Dispose();
|
||||||
|
_downloadBytesRequest = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_downloadRetryController.TickRetryDelay())
|
||||||
|
{
|
||||||
|
Progress = 0f;
|
||||||
|
_steps = ESteps.DataRequest;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
protected override void InternalDispose()
|
||||||
|
{
|
||||||
|
if (_downloadBytesRequest != null)
|
||||||
|
{
|
||||||
|
_downloadBytesRequest.Dispose();
|
||||||
|
_downloadBytesRequest = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private LoadResult LoadFromMemory(IBundleMemoryDecryptor decryptor, byte[] fileData)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (decryptor != null)
|
||||||
|
{
|
||||||
|
var args = new BundleDecryptArgs(_options.Bundle, fileData, null);
|
||||||
|
var binaryData = decryptor.GetDecryptedData(args);
|
||||||
|
if (binaryData == null)
|
||||||
|
return LoadResult.Failure($"{_options.CacheName} decryptor returned null data.");
|
||||||
|
|
||||||
|
_rawBundle = RawBundleHelper.LoadFromMemory(binaryData);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_rawBundle = RawBundleHelper.LoadFromMemory(fileData);
|
||||||
|
}
|
||||||
|
return LoadResult.Default();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
return LoadResult.Failure($"Failed to load archive bundle from memory: {ex.Message}.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: b30e1d41b966e63488837244e907363b
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace YooAsset
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// WebGL 平台加载 RawBundle 的操作选项
|
||||||
|
/// </summary>
|
||||||
|
internal readonly struct LoadWebRawBundleOptions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 文件缓存名称
|
||||||
|
/// </summary>
|
||||||
|
public string CacheName { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 资源包描述
|
||||||
|
/// </summary>
|
||||||
|
public PackageBundle Bundle { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 候选下载地址列表
|
||||||
|
/// </summary>
|
||||||
|
public IReadOnlyList<string> CandidateUrls { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// RawBundle 解密器
|
||||||
|
/// </summary>
|
||||||
|
public IBundleDecryptor RawBundleDecryptor { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 下载后台接口
|
||||||
|
/// </summary>
|
||||||
|
public IDownloadBackend DownloadBackend { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 下载数据校验级别
|
||||||
|
/// </summary>
|
||||||
|
public EFileVerifyLevel DownloadVerifyLevel { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 看门狗超时时间
|
||||||
|
/// </summary>
|
||||||
|
public int WatchdogTimeout { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 下载重试判定策略
|
||||||
|
/// </summary>
|
||||||
|
public IDownloadRetryPolicy DownloadRetryPolicy { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// URL 选择策略
|
||||||
|
/// </summary>
|
||||||
|
public IDownloadUrlPolicy DownloadUrlPolicy { get; }
|
||||||
|
|
||||||
|
public LoadWebRawBundleOptions(string cacheName, PackageBundle bundle, IReadOnlyList<string> candidateUrls,
|
||||||
|
IBundleDecryptor rawBundleDecryptor, IDownloadBackend downloadBackend, EFileVerifyLevel downloadVerifyLevel,
|
||||||
|
int watchdogTimeout, IDownloadRetryPolicy downloadRetryPolicy, IDownloadUrlPolicy downloadUrlPolicy)
|
||||||
|
{
|
||||||
|
CacheName = cacheName;
|
||||||
|
Bundle = bundle;
|
||||||
|
CandidateUrls = candidateUrls;
|
||||||
|
RawBundleDecryptor = rawBundleDecryptor;
|
||||||
|
DownloadBackend = downloadBackend;
|
||||||
|
DownloadVerifyLevel = downloadVerifyLevel;
|
||||||
|
WatchdogTimeout = watchdogTimeout;
|
||||||
|
DownloadRetryPolicy = downloadRetryPolicy;
|
||||||
|
DownloadUrlPolicy = downloadUrlPolicy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: c3f863ac69271e243b9270f23c70b02e
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -33,7 +33,7 @@ namespace YooAsset
|
|||||||
{
|
{
|
||||||
if (options.Manifest.TryGetPackageBundleByBundleGuid(entry.BundleGuid, out PackageBundle bundle))
|
if (options.Manifest.TryGetPackageBundleByBundleGuid(entry.BundleGuid, out PackageBundle bundle))
|
||||||
{
|
{
|
||||||
if (bundle.HasAnyTag(tags))
|
if (bundle.Tags.HasAnyTag(tags))
|
||||||
bundleGuids.Add(bundle.BundleGuid);
|
bundleGuids.Add(bundle.BundleGuid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,15 +20,22 @@ namespace YooAsset
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public IBundleDecryptor RawBundleDecryptor { get; }
|
public IBundleDecryptor RawBundleDecryptor { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// ArchiveBundle 解密器
|
||||||
|
/// </summary>
|
||||||
|
public IBundleDecryptor ArchiveBundleDecryptor { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 下载后台
|
/// 下载后台
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IDownloadBackend DownloadBackend { get; }
|
public IDownloadBackend DownloadBackend { get; }
|
||||||
|
|
||||||
public Configuration(IBundleDecryptor assetBundleDecryptor, IBundleDecryptor rawBundleDecryptor, IDownloadBackend downloadBackend)
|
public Configuration(IBundleDecryptor assetBundleDecryptor, IBundleDecryptor rawBundleDecryptor,
|
||||||
|
IBundleDecryptor archiveBundleDecryptor, IDownloadBackend downloadBackend)
|
||||||
{
|
{
|
||||||
AssetBundleDecryptor = assetBundleDecryptor;
|
AssetBundleDecryptor = assetBundleDecryptor;
|
||||||
RawBundleDecryptor = rawBundleDecryptor;
|
RawBundleDecryptor = rawBundleDecryptor;
|
||||||
|
ArchiveBundleDecryptor = archiveBundleDecryptor;
|
||||||
DownloadBackend = downloadBackend;
|
DownloadBackend = downloadBackend;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,7 +60,8 @@ namespace YooAsset
|
|||||||
var options = new LoadLocalArchiveBundleOptions(
|
var options = new LoadLocalArchiveBundleOptions(
|
||||||
cacheName: _fileCache.GetType().Name,
|
cacheName: _fileCache.GetType().Name,
|
||||||
bundle: _bundle,
|
bundle: _bundle,
|
||||||
filePath: _cacheEntry.FilePath);
|
filePath: _cacheEntry.FilePath,
|
||||||
|
archiveBundleDecryptor: _fileCache.Config.ArchiveBundleDecryptor);
|
||||||
_loadLocalArchiveBundleOp = new LoadLocalArchiveBundleOperation(options);
|
_loadLocalArchiveBundleOp = new LoadLocalArchiveBundleOperation(options);
|
||||||
_loadLocalArchiveBundleOp.StartOperation();
|
_loadLocalArchiveBundleOp.StartOperation();
|
||||||
AddChildOperation(_loadLocalArchiveBundleOp);
|
AddChildOperation(_loadLocalArchiveBundleOp);
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
namespace YooAsset
|
namespace YooAsset
|
||||||
{
|
{
|
||||||
@@ -22,8 +21,7 @@ namespace YooAsset
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
byte[] data = File.ReadAllBytes(editorFilePath);
|
var rawBundle = RawBundleHelper.LoadFromFile(editorFilePath);
|
||||||
var rawBundle = new RawBundle(data);
|
|
||||||
|
|
||||||
SetResult();
|
SetResult();
|
||||||
BundleHandle = new VirtualRawBundleHandle(_bundle, rawBundle);
|
BundleHandle = new VirtualRawBundleHandle(_bundle, rawBundle);
|
||||||
|
|||||||
@@ -61,7 +61,8 @@ namespace YooAsset
|
|||||||
var options = new LoadLocalArchiveBundleOptions(
|
var options = new LoadLocalArchiveBundleOptions(
|
||||||
cacheName: _fileCache.GetType().Name,
|
cacheName: _fileCache.GetType().Name,
|
||||||
bundle: _bundle,
|
bundle: _bundle,
|
||||||
filePath: _cacheEntry.DataFilePath);
|
filePath: _cacheEntry.DataFilePath,
|
||||||
|
archiveBundleDecryptor: _fileCache.Config.ArchiveBundleDecryptor);
|
||||||
_loadLocalArchiveBundleOp = new LoadLocalArchiveBundleOperation(options);
|
_loadLocalArchiveBundleOp = new LoadLocalArchiveBundleOperation(options);
|
||||||
_loadLocalArchiveBundleOp.StartOperation();
|
_loadLocalArchiveBundleOp.StartOperation();
|
||||||
AddChildOperation(_loadLocalArchiveBundleOp);
|
AddChildOperation(_loadLocalArchiveBundleOp);
|
||||||
|
|||||||
@@ -30,18 +30,25 @@ namespace YooAsset
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public IBundleDecryptor RawBundleDecryptor { get; }
|
public IBundleDecryptor RawBundleDecryptor { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// ArchiveBundle 解密器
|
||||||
|
/// </summary>
|
||||||
|
public IBundleDecryptor ArchiveBundleDecryptor { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// AssetBundle 备用解密器
|
/// AssetBundle 备用解密器
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public IBundleMemoryDecryptor AssetBundleFallbackDecryptor { get; }
|
public IBundleMemoryDecryptor AssetBundleFallbackDecryptor { get; }
|
||||||
|
|
||||||
public Configuration(int fileVerifyMaxConcurrency, EFileVerifyLevel fileVerifyLevel,
|
public Configuration(int fileVerifyMaxConcurrency, EFileVerifyLevel fileVerifyLevel,
|
||||||
IBundleDecryptor assetBundleDecryptor, IBundleDecryptor rawBundleDecryptor, IBundleMemoryDecryptor assetBundleFallbackDecryptor)
|
IBundleDecryptor assetBundleDecryptor, IBundleDecryptor rawBundleDecryptor,
|
||||||
|
IBundleDecryptor archiveBundleDecryptor, IBundleMemoryDecryptor assetBundleFallbackDecryptor)
|
||||||
{
|
{
|
||||||
FileVerifyMaxConcurrency = fileVerifyMaxConcurrency;
|
FileVerifyMaxConcurrency = fileVerifyMaxConcurrency;
|
||||||
FileVerifyLevel = fileVerifyLevel;
|
FileVerifyLevel = fileVerifyLevel;
|
||||||
AssetBundleDecryptor = assetBundleDecryptor;
|
AssetBundleDecryptor = assetBundleDecryptor;
|
||||||
RawBundleDecryptor = rawBundleDecryptor;
|
RawBundleDecryptor = rawBundleDecryptor;
|
||||||
|
ArchiveBundleDecryptor = archiveBundleDecryptor;
|
||||||
AssetBundleFallbackDecryptor = assetBundleFallbackDecryptor;
|
AssetBundleFallbackDecryptor = assetBundleFallbackDecryptor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: f71ffbb8bf041e5478862cc179cd7e3f
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 5b2ea6881f51a434db344d28e4e5f410
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: c5aefbf5ae866434483465f633edf635
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,165 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace YooAsset
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// WebGL 游戏平台缓存系统
|
|
||||||
/// </summary>
|
|
||||||
internal class WebGameBundleCache : IBundleCache
|
|
||||||
{
|
|
||||||
internal readonly struct Configuration
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 游戏平台接口
|
|
||||||
/// </summary>
|
|
||||||
public IWebGamePlatform GamePlatform { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 看门狗超时时间
|
|
||||||
/// </summary>
|
|
||||||
public int WatchdogTimeout { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 禁用 Unity 内置网络缓存
|
|
||||||
/// </summary>
|
|
||||||
public bool DisableUnityWebCache { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 下载数据校验级别
|
|
||||||
/// </summary>
|
|
||||||
public EFileVerifyLevel DownloadVerifyLevel { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// AssetBundle 解密器
|
|
||||||
/// </summary>
|
|
||||||
public IBundleDecryptor AssetBundleDecryptor { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 远程服务接口
|
|
||||||
/// </summary>
|
|
||||||
public IRemoteService RemoteService { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 下载后台接口
|
|
||||||
/// </summary>
|
|
||||||
public IDownloadBackend DownloadBackend { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 下载重试判定策略
|
|
||||||
/// </summary>
|
|
||||||
public IDownloadRetryPolicy DownloadRetryPolicy { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// URL 选择策略
|
|
||||||
/// </summary>
|
|
||||||
public IDownloadUrlPolicy DownloadUrlPolicy { get; }
|
|
||||||
|
|
||||||
public Configuration(IWebGamePlatform gamePlatform,
|
|
||||||
int watchdogTimeout, bool disableUnityWebCache,
|
|
||||||
EFileVerifyLevel downloadVerifyLevel, IBundleDecryptor assetBundleDecryptor, IRemoteService remoteService,
|
|
||||||
IDownloadBackend downloadBackend, IDownloadRetryPolicy downloadRetryPolicy, IDownloadUrlPolicy downloadUrlPolicy)
|
|
||||||
{
|
|
||||||
GamePlatform = gamePlatform;
|
|
||||||
WatchdogTimeout = watchdogTimeout;
|
|
||||||
DisableUnityWebCache = disableUnityWebCache;
|
|
||||||
DownloadVerifyLevel = downloadVerifyLevel;
|
|
||||||
AssetBundleDecryptor = assetBundleDecryptor;
|
|
||||||
RemoteService = remoteService;
|
|
||||||
DownloadBackend = downloadBackend;
|
|
||||||
DownloadRetryPolicy = downloadRetryPolicy;
|
|
||||||
DownloadUrlPolicy = downloadUrlPolicy;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 缓存配置
|
|
||||||
/// </summary>
|
|
||||||
internal readonly Configuration Config;
|
|
||||||
|
|
||||||
#region 接口属性
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public string PackageName { get; }
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public string RootPath { get; }
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public bool IsReadOnly { get; }
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public int FileCount { get; }
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public long SpaceOccupied { get; }
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 创建 WebGameBundleCache 实例
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="packageName">包裹名称</param>
|
|
||||||
/// <param name="rootPath">缓存根目录</param>
|
|
||||||
/// <param name="config">缓存配置</param>
|
|
||||||
public WebGameBundleCache(string packageName, string rootPath, Configuration config)
|
|
||||||
{
|
|
||||||
PackageName = packageName;
|
|
||||||
RootPath = rootPath;
|
|
||||||
Config = config;
|
|
||||||
IsReadOnly = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public BCInitializeOperation InitializeAsync()
|
|
||||||
{
|
|
||||||
var operation = new WGBCInitializeOperation();
|
|
||||||
return operation;
|
|
||||||
}
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public BCWriteCacheOperation WriteCacheAsync(BCWriteCacheOptions options)
|
|
||||||
{
|
|
||||||
var operation = new BCWriteCacheCompleteOperation($"{nameof(WebGameBundleCache)} is readonly.");
|
|
||||||
return operation;
|
|
||||||
}
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public BCClearCacheOperation ClearCacheAsync(BCClearCacheOptions options)
|
|
||||||
{
|
|
||||||
var operation = new BCClearCacheCompleteOperation();
|
|
||||||
return operation;
|
|
||||||
}
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public BCVerifyCacheOperation VerifyCacheAsync(BCVerifyCacheOptions options)
|
|
||||||
{
|
|
||||||
var operation = new BCVerifyCacheCompleteOperation();
|
|
||||||
return operation;
|
|
||||||
}
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public BCLoadBundleOperation LoadBundleAsync(BCLoadBundleOptions options)
|
|
||||||
{
|
|
||||||
if (options.Bundle.GetBundleType() == (int)EBundleType.AssetBundle)
|
|
||||||
{
|
|
||||||
var operation = new WGBCLoadAssetBundleOperation(this, options);
|
|
||||||
return operation;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
string error = $"{nameof(WebGameBundleCache)} does not support bundle type: {options.Bundle.GetBundleType()}.";
|
|
||||||
var operation = new BCLoadBundleErrorOperation(error);
|
|
||||||
return operation;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public bool IsCached(string bundleGuid)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
/// <inheritdoc/>
|
|
||||||
public string GetCacheFilePath(string bundleGuid)
|
|
||||||
{
|
|
||||||
YooLogger.LogWarning($"{nameof(WebGameBundleCache)} does not support local cache file path.");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: ddef4533d379a984c8d1669776147acf
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: f6cbd76495075b54993179318fdda8dc
|
guid: c284033155b7a7f4f9bcd7fa16e8f169
|
||||||
folderAsset: yes
|
folderAsset: yes
|
||||||
DefaultImporter:
|
DefaultImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: ead67fdda05e99747b03f49accc1526a
|
guid: 9494c5da1a02a7b43b40729e88fbda21
|
||||||
folderAsset: yes
|
folderAsset: yes
|
||||||
DefaultImporter:
|
DefaultImporter:
|
||||||
externalObjects: {}
|
externalObjects: {}
|
||||||
@@ -2,9 +2,9 @@
|
|||||||
namespace YooAsset
|
namespace YooAsset
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// WebGL 游戏平台缓存系统初始化操作
|
/// WebGL 平台网络缓存初始化操作
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal sealed class WGBCInitializeOperation : BCInitializeOperation
|
internal sealed class WNBCInitializeOperation : BCInitializeOperation
|
||||||
{
|
{
|
||||||
protected override void InternalStart()
|
protected override void InternalStart()
|
||||||
{
|
{
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 8a286ded9b4bbc340959221a542c8885
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -2,9 +2,9 @@
|
|||||||
namespace YooAsset
|
namespace YooAsset
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Web远端文件缓存加载 AssetBundle 操作
|
/// WebGL 平台网络缓存加载 ArchiveBundle 操作
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal sealed class WRBCLoadAssetBundleOperation : BCLoadBundleOperation
|
internal sealed class WNBCLoadArchiveBundleOperation : BCLoadBundleOperation
|
||||||
{
|
{
|
||||||
private enum ESteps
|
private enum ESteps
|
||||||
{
|
{
|
||||||
@@ -13,17 +13,12 @@ namespace YooAsset
|
|||||||
Done,
|
Done,
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly WebRemoteBundleCache _fileCache;
|
private readonly WebNetworkBundleCache _fileCache;
|
||||||
private readonly BCLoadBundleOptions _options;
|
private readonly BCLoadBundleOptions _options;
|
||||||
private BCLoadBundleOperation _loadBundleOp;
|
private BCLoadBundleOperation _loadBundleOp;
|
||||||
private ESteps _steps = ESteps.None;
|
private ESteps _steps = ESteps.None;
|
||||||
|
|
||||||
/// <summary>
|
internal WNBCLoadArchiveBundleOperation(WebNetworkBundleCache fileCache, BCLoadBundleOptions options)
|
||||||
/// 创建 WRBCLoadAssetBundleOperation 实例
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="fileCache">Web 远端文件缓存系统</param>
|
|
||||||
/// <param name="options">加载资源包操作选项</param>
|
|
||||||
public WRBCLoadAssetBundleOperation(WebRemoteBundleCache fileCache, BCLoadBundleOptions options)
|
|
||||||
{
|
{
|
||||||
_fileCache = fileCache;
|
_fileCache = fileCache;
|
||||||
_options = options;
|
_options = options;
|
||||||
@@ -42,23 +37,17 @@ namespace YooAsset
|
|||||||
if (_loadBundleOp == null)
|
if (_loadBundleOp == null)
|
||||||
{
|
{
|
||||||
var urls = _fileCache.Config.RemoteService.GetRemoteUrls(_options.Bundle.GetFileName());
|
var urls = _fileCache.Config.RemoteService.GetRemoteUrls(_options.Bundle.GetFileName());
|
||||||
var options = new LoadWebAssetBundleOptions(
|
var options = new LoadWebArchiveBundleOptions(
|
||||||
cacheName: _fileCache.GetType().Name,
|
cacheName: _fileCache.GetType().Name,
|
||||||
bundle: _options.Bundle,
|
bundle: _options.Bundle,
|
||||||
candidateUrls: urls,
|
candidateUrls: urls,
|
||||||
assetBundleDecryptor: _fileCache.Config.AssetBundleDecryptor,
|
archiveBundleDecryptor: _fileCache.Config.ArchiveBundleDecryptor,
|
||||||
downloadBackend: _fileCache.Config.DownloadBackend,
|
downloadBackend: _fileCache.Config.DownloadBackend,
|
||||||
downloadVerifyLevel: _fileCache.Config.DownloadVerifyLevel,
|
downloadVerifyLevel: _fileCache.Config.DownloadVerifyLevel,
|
||||||
watchdogTimeout: _fileCache.Config.WatchdogTimeout,
|
watchdogTimeout: 0,
|
||||||
disableUnityWebCache: _fileCache.Config.DisableUnityWebCache,
|
|
||||||
downloadRetryPolicy: _fileCache.Config.DownloadRetryPolicy,
|
downloadRetryPolicy: _fileCache.Config.DownloadRetryPolicy,
|
||||||
downloadUrlPolicy: _fileCache.Config.DownloadUrlPolicy);
|
downloadUrlPolicy: _fileCache.Config.DownloadUrlPolicy);
|
||||||
|
_loadBundleOp = new LoadWebArchiveBundleOperation(options);
|
||||||
if (_options.Bundle.IsEncrypted)
|
|
||||||
_loadBundleOp = new LoadWebEncryptedAssetBundleOperation(options);
|
|
||||||
else
|
|
||||||
_loadBundleOp = new LoadWebNormalAssetBundleOperation(options);
|
|
||||||
|
|
||||||
_loadBundleOp.StartOperation();
|
_loadBundleOp.StartOperation();
|
||||||
AddChildOperation(_loadBundleOp);
|
AddChildOperation(_loadBundleOp);
|
||||||
}
|
}
|
||||||
@@ -94,4 +83,4 @@ namespace YooAsset
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: b06ab626f2f3afe4e94f6ceaaaf1ba2c
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -1,9 +1,10 @@
|
|||||||
|
|
||||||
namespace YooAsset
|
namespace YooAsset
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// WebGL 游戏平台加载 AssetBundle 操作
|
/// WebGL 平台网络缓存加载 AssetBundle 操作
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal sealed class WGBCLoadAssetBundleOperation : BCLoadBundleOperation
|
internal sealed class WNBCLoadAssetBundleOperation : BCLoadBundleOperation
|
||||||
{
|
{
|
||||||
private enum ESteps
|
private enum ESteps
|
||||||
{
|
{
|
||||||
@@ -12,12 +13,12 @@ namespace YooAsset
|
|||||||
Done,
|
Done,
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly WebGameBundleCache _fileCache;
|
private readonly WebNetworkBundleCache _fileCache;
|
||||||
private readonly BCLoadBundleOptions _options;
|
private readonly BCLoadBundleOptions _options;
|
||||||
private BCLoadBundleOperation _loadBundleOp;
|
private BCLoadBundleOperation _loadBundleOp;
|
||||||
private ESteps _steps = ESteps.None;
|
private ESteps _steps = ESteps.None;
|
||||||
|
|
||||||
internal WGBCLoadAssetBundleOperation(WebGameBundleCache fileCache, BCLoadBundleOptions options)
|
internal WNBCLoadAssetBundleOperation(WebNetworkBundleCache fileCache, BCLoadBundleOptions options)
|
||||||
{
|
{
|
||||||
_fileCache = fileCache;
|
_fileCache = fileCache;
|
||||||
_options = options;
|
_options = options;
|
||||||
@@ -38,29 +39,30 @@ namespace YooAsset
|
|||||||
var urls = _fileCache.Config.RemoteService.GetRemoteUrls(_options.Bundle.GetFileName());
|
var urls = _fileCache.Config.RemoteService.GetRemoteUrls(_options.Bundle.GetFileName());
|
||||||
if (_options.Bundle.IsEncrypted)
|
if (_options.Bundle.IsEncrypted)
|
||||||
{
|
{
|
||||||
var options = new LoadWebAssetBundleOptions(
|
var encryptedOptions = new LoadWebEncryptedAssetBundleOptions(
|
||||||
cacheName: _fileCache.GetType().Name,
|
cacheName: _fileCache.GetType().Name,
|
||||||
bundle: _options.Bundle,
|
bundle: _options.Bundle,
|
||||||
candidateUrls: urls,
|
candidateUrls: urls,
|
||||||
assetBundleDecryptor: _fileCache.Config.AssetBundleDecryptor,
|
assetBundleDecryptor: _fileCache.Config.AssetBundleDecryptor,
|
||||||
downloadBackend: _fileCache.Config.DownloadBackend,
|
downloadBackend: _fileCache.Config.DownloadBackend,
|
||||||
downloadVerifyLevel: _fileCache.Config.DownloadVerifyLevel,
|
downloadVerifyLevel: _fileCache.Config.DownloadVerifyLevel,
|
||||||
watchdogTimeout: _fileCache.Config.WatchdogTimeout,
|
watchdogTimeout: 0,
|
||||||
disableUnityWebCache: _fileCache.Config.DisableUnityWebCache,
|
|
||||||
downloadRetryPolicy: _fileCache.Config.DownloadRetryPolicy,
|
downloadRetryPolicy: _fileCache.Config.DownloadRetryPolicy,
|
||||||
downloadUrlPolicy: _fileCache.Config.DownloadUrlPolicy);
|
downloadUrlPolicy: _fileCache.Config.DownloadUrlPolicy);
|
||||||
_loadBundleOp = new LoadWebEncryptedAssetBundleOperation(options);
|
_loadBundleOp = new LoadWebEncryptedAssetBundleOperation(encryptedOptions);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var webGameOptions = new LoadWebGameAssetBundleOptions(
|
var platformOptions = new LoadWebPlatformAssetBundleOptions(
|
||||||
bundle: _options.Bundle,
|
bundle: _options.Bundle,
|
||||||
candidateUrls: urls,
|
candidateUrls: urls,
|
||||||
gamePlatform: _fileCache.Config.GamePlatform,
|
platformStrategy: _fileCache.Config.PlatformStrategy,
|
||||||
watchdogTimeout: _fileCache.Config.WatchdogTimeout,
|
downloadBackend: _fileCache.Config.DownloadBackend,
|
||||||
|
watchdogTimeout: 0,
|
||||||
|
disableUnityWebCache: _fileCache.Config.DisableUnityWebCache,
|
||||||
downloadRetryPolicy: _fileCache.Config.DownloadRetryPolicy,
|
downloadRetryPolicy: _fileCache.Config.DownloadRetryPolicy,
|
||||||
downloadUrlPolicy: _fileCache.Config.DownloadUrlPolicy);
|
downloadUrlPolicy: _fileCache.Config.DownloadUrlPolicy);
|
||||||
_loadBundleOp = new LoadWebGameAssetBundleOperation(webGameOptions);
|
_loadBundleOp = new LoadWebPlatformAssetBundleOperation(platformOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
_loadBundleOp.StartOperation();
|
_loadBundleOp.StartOperation();
|
||||||
@@ -98,4 +100,4 @@ namespace YooAsset
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: d23033bab8f508240af14aea1d1c9776
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -2,9 +2,9 @@
|
|||||||
namespace YooAsset
|
namespace YooAsset
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Web远端文件系统的加载资源包操作
|
/// WebGL 平台网络缓存加载 RawBundle 操作
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal sealed class WRFSLoadPackageBundleOperation : FSLoadPackageBundleOperation
|
internal sealed class WNBCLoadRawBundleOperation : BCLoadBundleOperation
|
||||||
{
|
{
|
||||||
private enum ESteps
|
private enum ESteps
|
||||||
{
|
{
|
||||||
@@ -13,14 +13,14 @@ namespace YooAsset
|
|||||||
Done,
|
Done,
|
||||||
}
|
}
|
||||||
|
|
||||||
private readonly WebRemoteFileSystem _fileSystem;
|
private readonly WebNetworkBundleCache _fileCache;
|
||||||
private readonly FSLoadPackageBundleOptions _options;
|
private readonly BCLoadBundleOptions _options;
|
||||||
private BCLoadBundleOperation _loadBundleOp;
|
private BCLoadBundleOperation _loadBundleOp;
|
||||||
private ESteps _steps = ESteps.None;
|
private ESteps _steps = ESteps.None;
|
||||||
|
|
||||||
internal WRFSLoadPackageBundleOperation(WebRemoteFileSystem fileSystem, FSLoadPackageBundleOptions options)
|
internal WNBCLoadRawBundleOperation(WebNetworkBundleCache fileCache, BCLoadBundleOptions options)
|
||||||
{
|
{
|
||||||
_fileSystem = fileSystem;
|
_fileCache = fileCache;
|
||||||
_options = options;
|
_options = options;
|
||||||
}
|
}
|
||||||
protected override void InternalStart()
|
protected override void InternalStart()
|
||||||
@@ -36,7 +36,18 @@ namespace YooAsset
|
|||||||
{
|
{
|
||||||
if (_loadBundleOp == null)
|
if (_loadBundleOp == null)
|
||||||
{
|
{
|
||||||
_loadBundleOp = _fileSystem.BundleCache.LoadBundleAsync(_options.ConvertTo());
|
var urls = _fileCache.Config.RemoteService.GetRemoteUrls(_options.Bundle.GetFileName());
|
||||||
|
var options = new LoadWebRawBundleOptions(
|
||||||
|
cacheName: _fileCache.GetType().Name,
|
||||||
|
bundle: _options.Bundle,
|
||||||
|
candidateUrls: urls,
|
||||||
|
rawBundleDecryptor: _fileCache.Config.RawBundleDecryptor,
|
||||||
|
downloadBackend: _fileCache.Config.DownloadBackend,
|
||||||
|
downloadVerifyLevel: _fileCache.Config.DownloadVerifyLevel,
|
||||||
|
watchdogTimeout: 0,
|
||||||
|
downloadRetryPolicy: _fileCache.Config.DownloadRetryPolicy,
|
||||||
|
downloadUrlPolicy: _fileCache.Config.DownloadUrlPolicy);
|
||||||
|
_loadBundleOp = new LoadWebRawBundleOperation(options);
|
||||||
_loadBundleOp.StartOperation();
|
_loadBundleOp.StartOperation();
|
||||||
AddChildOperation(_loadBundleOp);
|
AddChildOperation(_loadBundleOp);
|
||||||
}
|
}
|
||||||
@@ -49,16 +60,11 @@ namespace YooAsset
|
|||||||
if (_loadBundleOp.Status == EOperationStatus.Succeeded)
|
if (_loadBundleOp.Status == EOperationStatus.Succeeded)
|
||||||
{
|
{
|
||||||
if (_loadBundleOp.BundleHandle == null)
|
if (_loadBundleOp.BundleHandle == null)
|
||||||
{
|
throw new YooInternalException("Loaded bundle handle is null.");
|
||||||
_steps = ESteps.Done;
|
|
||||||
SetError("Fatal error: loaded bundle handle is null.");
|
_steps = ESteps.Done;
|
||||||
}
|
SetResult();
|
||||||
else
|
BundleHandle = _loadBundleOp.BundleHandle;
|
||||||
{
|
|
||||||
_steps = ESteps.Done;
|
|
||||||
SetResult();
|
|
||||||
BundleHandle = _loadBundleOp.BundleHandle;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -77,4 +83,4 @@ namespace YooAsset
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 2757bc29c7400b24c8bd4f250e414b65
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -1,20 +1,12 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
|
|
||||||
namespace YooAsset
|
namespace YooAsset
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Web远端文件缓存系统,用于从远程服务器加载资源。
|
/// WebGL 平台网络缓存系统
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal class WebRemoteBundleCache : IBundleCache
|
internal class WebNetworkBundleCache : IBundleCache
|
||||||
{
|
{
|
||||||
internal readonly struct Configuration
|
internal readonly struct Configuration
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// 看门狗超时时间
|
|
||||||
/// </summary>
|
|
||||||
public int WatchdogTimeout { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 禁用 Unity 内置网络缓存
|
/// 禁用 Unity 内置网络缓存
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -30,6 +22,21 @@ namespace YooAsset
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public IBundleDecryptor AssetBundleDecryptor { get; }
|
public IBundleDecryptor AssetBundleDecryptor { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// RawBundle 解密器
|
||||||
|
/// </summary>
|
||||||
|
public IBundleDecryptor RawBundleDecryptor { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// ArchiveBundle 解密器
|
||||||
|
/// </summary>
|
||||||
|
public IBundleDecryptor ArchiveBundleDecryptor { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 平台策略接口
|
||||||
|
/// </summary>
|
||||||
|
public IWebPlatformStrategy PlatformStrategy { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 远程服务接口
|
/// 远程服务接口
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -50,14 +57,17 @@ namespace YooAsset
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public IDownloadUrlPolicy DownloadUrlPolicy { get; }
|
public IDownloadUrlPolicy DownloadUrlPolicy { get; }
|
||||||
|
|
||||||
public Configuration(int watchdogTimeout, bool disableUnityWebCache,
|
public Configuration(bool disableUnityWebCache,
|
||||||
EFileVerifyLevel downloadVerifyLevel, IBundleDecryptor assetBundleDecryptor, IRemoteService remoteService,
|
EFileVerifyLevel downloadVerifyLevel, IBundleDecryptor assetBundleDecryptor, IBundleDecryptor rawBundleDecryptor,
|
||||||
IDownloadBackend downloadBackend, IDownloadRetryPolicy downloadRetryPolicy, IDownloadUrlPolicy downloadUrlPolicy)
|
IBundleDecryptor archiveBundleDecryptor, IWebPlatformStrategy platformStrategy, IRemoteService remoteService,
|
||||||
|
IDownloadBackend downloadBackend, IDownloadRetryPolicy downloadRetryPolicy, IDownloadUrlPolicy downloadUrlPolicy)
|
||||||
{
|
{
|
||||||
WatchdogTimeout = watchdogTimeout;
|
|
||||||
DisableUnityWebCache = disableUnityWebCache;
|
DisableUnityWebCache = disableUnityWebCache;
|
||||||
DownloadVerifyLevel = downloadVerifyLevel;
|
DownloadVerifyLevel = downloadVerifyLevel;
|
||||||
AssetBundleDecryptor = assetBundleDecryptor;
|
AssetBundleDecryptor = assetBundleDecryptor;
|
||||||
|
RawBundleDecryptor = rawBundleDecryptor;
|
||||||
|
ArchiveBundleDecryptor = archiveBundleDecryptor;
|
||||||
|
PlatformStrategy = platformStrategy;
|
||||||
RemoteService = remoteService;
|
RemoteService = remoteService;
|
||||||
DownloadBackend = downloadBackend;
|
DownloadBackend = downloadBackend;
|
||||||
DownloadRetryPolicy = downloadRetryPolicy;
|
DownloadRetryPolicy = downloadRetryPolicy;
|
||||||
@@ -87,16 +97,9 @@ namespace YooAsset
|
|||||||
public long SpaceOccupied { get; }
|
public long SpaceOccupied { get; }
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
/// <summary>
|
public WebNetworkBundleCache(string packageName, Configuration config)
|
||||||
/// 创建 WebRemoteBundleCache 实例
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="packageName">包裹名称</param>
|
|
||||||
/// <param name="rootPath">缓存根目录</param>
|
|
||||||
/// <param name="config">缓存配置</param>
|
|
||||||
public WebRemoteBundleCache(string packageName, string rootPath, Configuration config)
|
|
||||||
{
|
{
|
||||||
PackageName = packageName;
|
PackageName = packageName;
|
||||||
RootPath = rootPath;
|
|
||||||
Config = config;
|
Config = config;
|
||||||
IsReadOnly = true;
|
IsReadOnly = true;
|
||||||
}
|
}
|
||||||
@@ -108,13 +111,13 @@ namespace YooAsset
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public BCInitializeOperation InitializeAsync()
|
public BCInitializeOperation InitializeAsync()
|
||||||
{
|
{
|
||||||
var operation = new WRBCInitializeOperation(this);
|
var operation = new WNBCInitializeOperation();
|
||||||
return operation;
|
return operation;
|
||||||
}
|
}
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public BCWriteCacheOperation WriteCacheAsync(BCWriteCacheOptions options)
|
public BCWriteCacheOperation WriteCacheAsync(BCWriteCacheOptions options)
|
||||||
{
|
{
|
||||||
var operation = new BCWriteCacheCompleteOperation($"{nameof(WebRemoteBundleCache)} is readonly.");
|
var operation = new BCWriteCacheCompleteOperation($"{nameof(WebNetworkBundleCache)} is readonly.");
|
||||||
return operation;
|
return operation;
|
||||||
}
|
}
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@@ -134,12 +137,22 @@ namespace YooAsset
|
|||||||
{
|
{
|
||||||
if (options.Bundle.GetBundleType() == (int)EBundleType.AssetBundle)
|
if (options.Bundle.GetBundleType() == (int)EBundleType.AssetBundle)
|
||||||
{
|
{
|
||||||
var operation = new WRBCLoadAssetBundleOperation(this, options);
|
var operation = new WNBCLoadAssetBundleOperation(this, options);
|
||||||
|
return operation;
|
||||||
|
}
|
||||||
|
else if (options.Bundle.GetBundleType() == (int)EBundleType.RawBundle)
|
||||||
|
{
|
||||||
|
var operation = new WNBCLoadRawBundleOperation(this, options);
|
||||||
|
return operation;
|
||||||
|
}
|
||||||
|
else if (options.Bundle.GetBundleType() == (int)EBundleType.ArchiveBundle)
|
||||||
|
{
|
||||||
|
var operation = new WNBCLoadArchiveBundleOperation(this, options);
|
||||||
return operation;
|
return operation;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
string error = $"{nameof(WebRemoteBundleCache)} does not support bundle type: {options.Bundle.GetBundleType()}.";
|
string error = $"{nameof(WebNetworkBundleCache)} does not support bundle type: {options.Bundle.GetBundleType()}.";
|
||||||
var operation = new BCLoadBundleErrorOperation(error);
|
var operation = new BCLoadBundleErrorOperation(error);
|
||||||
return operation;
|
return operation;
|
||||||
}
|
}
|
||||||
@@ -152,8 +165,8 @@ namespace YooAsset
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public string GetCacheFilePath(string bundleGuid)
|
public string GetCacheFilePath(string bundleGuid)
|
||||||
{
|
{
|
||||||
YooLogger.LogWarning($"{nameof(WebRemoteBundleCache)} does not support local cache file path.");
|
YooLogger.LogWarning($"{nameof(WebNetworkBundleCache)} does not support local cache file path.");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: ea8b93fb2515f5b49b16486f87be98d7
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
|
|
||||||
namespace YooAsset
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Web远端文件缓存初始化操作
|
|
||||||
/// </summary>
|
|
||||||
internal sealed class WRBCInitializeOperation : BCInitializeOperation
|
|
||||||
{
|
|
||||||
private readonly WebRemoteBundleCache _fileCache;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 创建 Web 远端缓存初始化操作实例
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="fileCache">Web 远端文件缓存系统</param>
|
|
||||||
public WRBCInitializeOperation(WebRemoteBundleCache fileCache)
|
|
||||||
{
|
|
||||||
_fileCache = fileCache;
|
|
||||||
}
|
|
||||||
protected override void InternalStart()
|
|
||||||
{
|
|
||||||
SetResult();
|
|
||||||
}
|
|
||||||
protected override void InternalUpdate()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 476dbbea577819a43a807f22bb91f974
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: 8821049e94e79ff4b9c83c24e7b10d49
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: ebc556c0bb6cbe146a502e678761ace1
|
|
||||||
MonoImporter:
|
|
||||||
externalObjects: {}
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
namespace YooAsset
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Web服务器文件缓存加载 ArchiveBundle 操作
|
||||||
|
/// </summary>
|
||||||
|
internal sealed class WSBCLoadArchiveBundleOperation : BCLoadBundleOperation
|
||||||
|
{
|
||||||
|
private enum ESteps
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
GetEntry,
|
||||||
|
LoadBundle,
|
||||||
|
Done,
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly WebServerBundleCache _fileCache;
|
||||||
|
private readonly BCLoadBundleOptions _options;
|
||||||
|
private BCLoadBundleOperation _loadBundleOp;
|
||||||
|
private WebServerBundleCacheEntry _cacheEntry;
|
||||||
|
private ESteps _steps = ESteps.None;
|
||||||
|
|
||||||
|
public WSBCLoadArchiveBundleOperation(WebServerBundleCache fileCache, BCLoadBundleOptions options)
|
||||||
|
{
|
||||||
|
_fileCache = fileCache;
|
||||||
|
_options = options;
|
||||||
|
}
|
||||||
|
protected override void InternalStart()
|
||||||
|
{
|
||||||
|
_steps = ESteps.GetEntry;
|
||||||
|
}
|
||||||
|
protected override void InternalUpdate()
|
||||||
|
{
|
||||||
|
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_steps == ESteps.GetEntry)
|
||||||
|
{
|
||||||
|
_cacheEntry = _fileCache.GetEntry(_options.Bundle.BundleGuid);
|
||||||
|
if (_cacheEntry == null)
|
||||||
|
{
|
||||||
|
_steps = ESteps.Done;
|
||||||
|
SetError($"File cache entry not found: '{_options.Bundle.BundleGuid}'.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_steps = ESteps.LoadBundle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_steps == ESteps.LoadBundle)
|
||||||
|
{
|
||||||
|
if (_loadBundleOp == null)
|
||||||
|
{
|
||||||
|
string url = DownloadUrlHelper.ToLocalFileUrl(_cacheEntry.FilePath);
|
||||||
|
var options = new LoadWebArchiveBundleOptions(
|
||||||
|
cacheName: _fileCache.GetType().Name,
|
||||||
|
bundle: _options.Bundle,
|
||||||
|
candidateUrls: new[] { url },
|
||||||
|
archiveBundleDecryptor: _fileCache.Config.ArchiveBundleDecryptor,
|
||||||
|
downloadBackend: _fileCache.Config.DownloadBackend,
|
||||||
|
downloadVerifyLevel: _fileCache.Config.DownloadVerifyLevel,
|
||||||
|
watchdogTimeout: _fileCache.Config.WatchdogTimeout,
|
||||||
|
downloadRetryPolicy: _fileCache.Config.DownloadRetryPolicy,
|
||||||
|
downloadUrlPolicy: _fileCache.Config.DownloadUrlPolicy);
|
||||||
|
_loadBundleOp = new LoadWebArchiveBundleOperation(options);
|
||||||
|
_loadBundleOp.StartOperation();
|
||||||
|
AddChildOperation(_loadBundleOp);
|
||||||
|
}
|
||||||
|
|
||||||
|
_loadBundleOp.UpdateOperation();
|
||||||
|
Progress = _loadBundleOp.Progress;
|
||||||
|
if (_loadBundleOp.IsDone == false)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_loadBundleOp.Status == EOperationStatus.Succeeded)
|
||||||
|
{
|
||||||
|
if (_loadBundleOp.BundleHandle == null)
|
||||||
|
throw new YooInternalException("Loaded bundle handle is null.");
|
||||||
|
|
||||||
|
_steps = ESteps.Done;
|
||||||
|
SetResult();
|
||||||
|
BundleHandle = _loadBundleOp.BundleHandle;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_steps = ESteps.Done;
|
||||||
|
SetError(_loadBundleOp.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
protected override void InternalWaitForCompletion()
|
||||||
|
{
|
||||||
|
if (_steps != ESteps.Done)
|
||||||
|
{
|
||||||
|
_steps = ESteps.Done;
|
||||||
|
SetError("WebGL platform does not support synchronous loading.");
|
||||||
|
YooLogger.LogError(Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 789cead93f0d6c340b3b7cb855d1fc70
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -58,22 +58,33 @@ namespace YooAsset
|
|||||||
if (_loadBundleOp == null)
|
if (_loadBundleOp == null)
|
||||||
{
|
{
|
||||||
string url = DownloadUrlHelper.ToLocalFileUrl(_cacheEntry.FilePath);
|
string url = DownloadUrlHelper.ToLocalFileUrl(_cacheEntry.FilePath);
|
||||||
var options = new LoadWebAssetBundleOptions(
|
|
||||||
cacheName: _fileCache.GetType().Name,
|
|
||||||
bundle: _options.Bundle,
|
|
||||||
candidateUrls: new[] { url },
|
|
||||||
assetBundleDecryptor: _fileCache.Config.AssetBundleDecryptor,
|
|
||||||
downloadBackend: _fileCache.Config.DownloadBackend,
|
|
||||||
downloadVerifyLevel: _fileCache.Config.DownloadVerifyLevel,
|
|
||||||
watchdogTimeout: _fileCache.Config.WatchdogTimeout,
|
|
||||||
disableUnityWebCache: _fileCache.Config.DisableUnityWebCache,
|
|
||||||
downloadRetryPolicy: _fileCache.Config.DownloadRetryPolicy,
|
|
||||||
downloadUrlPolicy: _fileCache.Config.DownloadUrlPolicy);
|
|
||||||
|
|
||||||
if (_options.Bundle.IsEncrypted)
|
if (_options.Bundle.IsEncrypted)
|
||||||
_loadBundleOp = new LoadWebEncryptedAssetBundleOperation(options);
|
{
|
||||||
|
var encryptedOptions = new LoadWebEncryptedAssetBundleOptions(
|
||||||
|
cacheName: _fileCache.GetType().Name,
|
||||||
|
bundle: _options.Bundle,
|
||||||
|
candidateUrls: new[] { url },
|
||||||
|
assetBundleDecryptor: _fileCache.Config.AssetBundleDecryptor,
|
||||||
|
downloadBackend: _fileCache.Config.DownloadBackend,
|
||||||
|
downloadVerifyLevel: _fileCache.Config.DownloadVerifyLevel,
|
||||||
|
watchdogTimeout: _fileCache.Config.WatchdogTimeout,
|
||||||
|
downloadRetryPolicy: _fileCache.Config.DownloadRetryPolicy,
|
||||||
|
downloadUrlPolicy: _fileCache.Config.DownloadUrlPolicy);
|
||||||
|
_loadBundleOp = new LoadWebEncryptedAssetBundleOperation(encryptedOptions);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
_loadBundleOp = new LoadWebNormalAssetBundleOperation(options);
|
{
|
||||||
|
var platformOptions = new LoadWebPlatformAssetBundleOptions(
|
||||||
|
bundle: _options.Bundle,
|
||||||
|
candidateUrls: new[] { url },
|
||||||
|
platformStrategy: _fileCache.Config.PlatformStrategy,
|
||||||
|
downloadBackend: _fileCache.Config.DownloadBackend,
|
||||||
|
watchdogTimeout: _fileCache.Config.WatchdogTimeout,
|
||||||
|
disableUnityWebCache: _fileCache.Config.DisableUnityWebCache,
|
||||||
|
downloadRetryPolicy: _fileCache.Config.DownloadRetryPolicy,
|
||||||
|
downloadUrlPolicy: _fileCache.Config.DownloadUrlPolicy);
|
||||||
|
_loadBundleOp = new LoadWebPlatformAssetBundleOperation(platformOptions);
|
||||||
|
}
|
||||||
|
|
||||||
_loadBundleOp.StartOperation();
|
_loadBundleOp.StartOperation();
|
||||||
AddChildOperation(_loadBundleOp);
|
AddChildOperation(_loadBundleOp);
|
||||||
|
|||||||
@@ -0,0 +1,101 @@
|
|||||||
|
namespace YooAsset
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Web服务器文件缓存加载 RawBundle 操作
|
||||||
|
/// </summary>
|
||||||
|
internal sealed class WSBCLoadRawBundleOperation : BCLoadBundleOperation
|
||||||
|
{
|
||||||
|
private enum ESteps
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
GetEntry,
|
||||||
|
LoadBundle,
|
||||||
|
Done,
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly WebServerBundleCache _fileCache;
|
||||||
|
private readonly BCLoadBundleOptions _options;
|
||||||
|
private BCLoadBundleOperation _loadBundleOp;
|
||||||
|
private WebServerBundleCacheEntry _cacheEntry;
|
||||||
|
private ESteps _steps = ESteps.None;
|
||||||
|
|
||||||
|
public WSBCLoadRawBundleOperation(WebServerBundleCache fileCache, BCLoadBundleOptions options)
|
||||||
|
{
|
||||||
|
_fileCache = fileCache;
|
||||||
|
_options = options;
|
||||||
|
}
|
||||||
|
protected override void InternalStart()
|
||||||
|
{
|
||||||
|
_steps = ESteps.GetEntry;
|
||||||
|
}
|
||||||
|
protected override void InternalUpdate()
|
||||||
|
{
|
||||||
|
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_steps == ESteps.GetEntry)
|
||||||
|
{
|
||||||
|
_cacheEntry = _fileCache.GetEntry(_options.Bundle.BundleGuid);
|
||||||
|
if (_cacheEntry == null)
|
||||||
|
{
|
||||||
|
_steps = ESteps.Done;
|
||||||
|
SetError($"File cache entry not found: '{_options.Bundle.BundleGuid}'.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_steps = ESteps.LoadBundle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_steps == ESteps.LoadBundle)
|
||||||
|
{
|
||||||
|
if (_loadBundleOp == null)
|
||||||
|
{
|
||||||
|
string url = DownloadUrlHelper.ToLocalFileUrl(_cacheEntry.FilePath);
|
||||||
|
var options = new LoadWebRawBundleOptions(
|
||||||
|
cacheName: _fileCache.GetType().Name,
|
||||||
|
bundle: _options.Bundle,
|
||||||
|
candidateUrls: new[] { url },
|
||||||
|
rawBundleDecryptor: _fileCache.Config.RawBundleDecryptor,
|
||||||
|
downloadBackend: _fileCache.Config.DownloadBackend,
|
||||||
|
downloadVerifyLevel: _fileCache.Config.DownloadVerifyLevel,
|
||||||
|
watchdogTimeout: _fileCache.Config.WatchdogTimeout,
|
||||||
|
downloadRetryPolicy: _fileCache.Config.DownloadRetryPolicy,
|
||||||
|
downloadUrlPolicy: _fileCache.Config.DownloadUrlPolicy);
|
||||||
|
_loadBundleOp = new LoadWebRawBundleOperation(options);
|
||||||
|
_loadBundleOp.StartOperation();
|
||||||
|
AddChildOperation(_loadBundleOp);
|
||||||
|
}
|
||||||
|
|
||||||
|
_loadBundleOp.UpdateOperation();
|
||||||
|
Progress = _loadBundleOp.Progress;
|
||||||
|
if (_loadBundleOp.IsDone == false)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_loadBundleOp.Status == EOperationStatus.Succeeded)
|
||||||
|
{
|
||||||
|
if (_loadBundleOp.BundleHandle == null)
|
||||||
|
throw new YooInternalException("Loaded bundle handle is null.");
|
||||||
|
|
||||||
|
_steps = ESteps.Done;
|
||||||
|
SetResult();
|
||||||
|
BundleHandle = _loadBundleOp.BundleHandle;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_steps = ESteps.Done;
|
||||||
|
SetError(_loadBundleOp.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
protected override void InternalWaitForCompletion()
|
||||||
|
{
|
||||||
|
if (_steps != ESteps.Done)
|
||||||
|
{
|
||||||
|
_steps = ESteps.Done;
|
||||||
|
SetError("WebGL platform does not support synchronous loading.");
|
||||||
|
YooLogger.LogError(Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 7244b365359a0d94d89188e1f114b5c9
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -30,6 +30,21 @@ namespace YooAsset
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public IBundleDecryptor AssetBundleDecryptor { get; }
|
public IBundleDecryptor AssetBundleDecryptor { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// RawBundle 解密器
|
||||||
|
/// </summary>
|
||||||
|
public IBundleDecryptor RawBundleDecryptor { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// ArchiveBundle 解密器
|
||||||
|
/// </summary>
|
||||||
|
public IBundleDecryptor ArchiveBundleDecryptor { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Web 平台策略
|
||||||
|
/// </summary>
|
||||||
|
public IWebPlatformStrategy PlatformStrategy { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 下载后台
|
/// 下载后台
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -45,14 +60,18 @@ namespace YooAsset
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public IDownloadUrlPolicy DownloadUrlPolicy { get; }
|
public IDownloadUrlPolicy DownloadUrlPolicy { get; }
|
||||||
|
|
||||||
public Configuration(int watchdogTimeout, bool disableUnityWebCache,
|
public Configuration(int watchdogTimeout, bool disableUnityWebCache,
|
||||||
EFileVerifyLevel downloadVerifyLevel, IBundleDecryptor assetBundleDecryptor,
|
EFileVerifyLevel downloadVerifyLevel, IBundleDecryptor assetBundleDecryptor, IBundleDecryptor rawBundleDecryptor,
|
||||||
IDownloadBackend downloadBackend, IDownloadRetryPolicy downloadRetryPolicy, IDownloadUrlPolicy downloadUrlPolicy)
|
IBundleDecryptor archiveBundleDecryptor, IWebPlatformStrategy platformStrategy, IDownloadBackend downloadBackend,
|
||||||
|
IDownloadRetryPolicy downloadRetryPolicy, IDownloadUrlPolicy downloadUrlPolicy)
|
||||||
{
|
{
|
||||||
WatchdogTimeout = watchdogTimeout;
|
WatchdogTimeout = watchdogTimeout;
|
||||||
DisableUnityWebCache = disableUnityWebCache;
|
DisableUnityWebCache = disableUnityWebCache;
|
||||||
DownloadVerifyLevel = downloadVerifyLevel;
|
DownloadVerifyLevel = downloadVerifyLevel;
|
||||||
AssetBundleDecryptor = assetBundleDecryptor;
|
AssetBundleDecryptor = assetBundleDecryptor;
|
||||||
|
RawBundleDecryptor = rawBundleDecryptor;
|
||||||
|
ArchiveBundleDecryptor = archiveBundleDecryptor;
|
||||||
|
PlatformStrategy = platformStrategy;
|
||||||
DownloadBackend = downloadBackend;
|
DownloadBackend = downloadBackend;
|
||||||
DownloadRetryPolicy = downloadRetryPolicy;
|
DownloadRetryPolicy = downloadRetryPolicy;
|
||||||
DownloadUrlPolicy = downloadUrlPolicy;
|
DownloadUrlPolicy = downloadUrlPolicy;
|
||||||
@@ -139,6 +158,16 @@ namespace YooAsset
|
|||||||
var operation = new WSBCLoadAssetBundleOperation(this, options);
|
var operation = new WSBCLoadAssetBundleOperation(this, options);
|
||||||
return operation;
|
return operation;
|
||||||
}
|
}
|
||||||
|
else if (options.Bundle.GetBundleType() == (int)EBundleType.RawBundle)
|
||||||
|
{
|
||||||
|
var operation = new WSBCLoadRawBundleOperation(this, options);
|
||||||
|
return operation;
|
||||||
|
}
|
||||||
|
else if (options.Bundle.GetBundleType() == (int)EBundleType.ArchiveBundle)
|
||||||
|
{
|
||||||
|
var operation = new WSBCLoadArchiveBundleOperation(this, options);
|
||||||
|
return operation;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
string error = $"{nameof(WebServerBundleCache)} does not support bundle type: {options.Bundle.GetBundleType()}.";
|
string error = $"{nameof(WebServerBundleCache)} does not support bundle type: {options.Bundle.GetBundleType()}.";
|
||||||
|
|||||||
@@ -56,15 +56,14 @@ namespace YooAsset
|
|||||||
}
|
}
|
||||||
|
|
||||||
private readonly string _archiveFilePath;
|
private readonly string _archiveFilePath;
|
||||||
|
private readonly byte[] _memoryData;
|
||||||
private readonly Dictionary<string, FileEntry> _entries;
|
private readonly Dictionary<string, FileEntry> _entries;
|
||||||
private readonly Dictionary<string, RawFileObject> _cachedObjects = new Dictionary<string, RawFileObject>();
|
private readonly Dictionary<string, RawFileObject> _cachedObjects = new Dictionary<string, RawFileObject>();
|
||||||
private bool _isUnloaded;
|
private bool _isUnloaded;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 创建 ArchiveBundle 实例
|
/// 从本地文件创建 ArchiveBundle 实例
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="archiveFilePath">归档文件的本地路径</param>
|
|
||||||
/// <param name="entries">子文件索引字典</param>
|
|
||||||
public ArchiveBundle(string archiveFilePath, Dictionary<string, FileEntry> entries)
|
public ArchiveBundle(string archiveFilePath, Dictionary<string, FileEntry> entries)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(archiveFilePath))
|
if (string.IsNullOrEmpty(archiveFilePath))
|
||||||
@@ -73,6 +72,23 @@ namespace YooAsset
|
|||||||
throw new ArgumentNullException(nameof(entries));
|
throw new ArgumentNullException(nameof(entries));
|
||||||
|
|
||||||
_archiveFilePath = archiveFilePath;
|
_archiveFilePath = archiveFilePath;
|
||||||
|
_memoryData = null;
|
||||||
|
_entries = entries;
|
||||||
|
_isUnloaded = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 从解密后的内存数据创建 ArchiveBundle 实例
|
||||||
|
/// </summary>
|
||||||
|
public ArchiveBundle(byte[] memoryData, Dictionary<string, FileEntry> entries)
|
||||||
|
{
|
||||||
|
if (memoryData == null)
|
||||||
|
throw new ArgumentNullException(nameof(memoryData));
|
||||||
|
if (entries == null)
|
||||||
|
throw new ArgumentNullException(nameof(entries));
|
||||||
|
|
||||||
|
_archiveFilePath = null;
|
||||||
|
_memoryData = memoryData;
|
||||||
_entries = entries;
|
_entries = entries;
|
||||||
_isUnloaded = false;
|
_isUnloaded = false;
|
||||||
}
|
}
|
||||||
@@ -92,8 +108,8 @@ namespace YooAsset
|
|||||||
if (_cachedObjects.TryGetValue(assetPath, out RawFileObject cached))
|
if (_cachedObjects.TryGetValue(assetPath, out RawFileObject cached))
|
||||||
return cached;
|
return cached;
|
||||||
|
|
||||||
byte[] fileData = ReadFileData(assetPath);
|
byte[] assetData = ReadAssetData(assetPath);
|
||||||
var rawFileObject = RawFileObject.CreateFromBytes(fileData);
|
var rawFileObject = RawFileObject.CreateFromBytes(assetData);
|
||||||
_cachedObjects[assetPath] = rawFileObject;
|
_cachedObjects[assetPath] = rawFileObject;
|
||||||
return rawFileObject;
|
return rawFileObject;
|
||||||
}
|
}
|
||||||
@@ -113,14 +129,24 @@ namespace YooAsset
|
|||||||
_entries.Clear();
|
_entries.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
private byte[] ReadAssetData(string assetPath)
|
||||||
/// 从归档文件中读取子文件的字节数据
|
|
||||||
/// </summary>
|
|
||||||
private byte[] ReadFileData(string assetPath)
|
|
||||||
{
|
{
|
||||||
if (_entries.TryGetValue(assetPath, out FileEntry entry) == false)
|
if (_entries.TryGetValue(assetPath, out FileEntry entry) == false)
|
||||||
throw new InvalidOperationException($"Asset not found in archive: '{assetPath}'.");
|
throw new InvalidOperationException($"Asset not found in archive: '{assetPath}'.");
|
||||||
|
|
||||||
|
if (_memoryData != null)
|
||||||
|
return ReadFromMemory(entry);
|
||||||
|
else
|
||||||
|
return ReadFromFile(entry);
|
||||||
|
}
|
||||||
|
private byte[] ReadFromMemory(FileEntry entry)
|
||||||
|
{
|
||||||
|
byte[] buffer = new byte[entry.DataLength];
|
||||||
|
Buffer.BlockCopy(_memoryData, (int)entry.DataOffset, buffer, 0, (int)entry.DataLength);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
private byte[] ReadFromFile(FileEntry entry)
|
||||||
|
{
|
||||||
byte[] buffer = new byte[entry.DataLength];
|
byte[] buffer = new byte[entry.DataLength];
|
||||||
using (var fs = new FileStream(_archiveFilePath, FileMode.Open, FileAccess.Read, FileShare.Read))
|
using (var fs = new FileStream(_archiveFilePath, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||||
{
|
{
|
||||||
@@ -130,7 +156,7 @@ namespace YooAsset
|
|||||||
{
|
{
|
||||||
int read = fs.Read(buffer, bytesRead, buffer.Length - bytesRead);
|
int read = fs.Read(buffer, bytesRead, buffer.Length - bytesRead);
|
||||||
if (read == 0)
|
if (read == 0)
|
||||||
throw new EndOfStreamException($"Unexpected end of archive file while reading '{assetPath}'.");
|
throw new EndOfStreamException($"Unexpected end of archive file while reading '{entry.AssetPath}'.");
|
||||||
bytesRead += read;
|
bytesRead += read;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,14 +8,36 @@ namespace YooAsset
|
|||||||
internal static class ArchiveBundleHelper
|
internal static class ArchiveBundleHelper
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 解析 YARK 归档文件
|
/// 从本地文件解析 YARK 归档
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="filePath">归档文件路径</param>
|
/// <param name="filePath">归档文件路径</param>
|
||||||
/// <returns>解析成功的 ArchiveBundle 实例</returns>
|
/// <returns>解析成功的 ArchiveBundle 实例</returns>
|
||||||
public static ArchiveBundle LoadArchiveBundle(string filePath)
|
public static ArchiveBundle LoadFromFile(string filePath)
|
||||||
{
|
{
|
||||||
using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
|
using (var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
|
||||||
using (var reader = new BinaryReader(fs))
|
{
|
||||||
|
var entries = ParseEntries(fs, fs.Length);
|
||||||
|
return new ArchiveBundle(filePath, entries);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 从解密后的内存数据解析 YARK 归档
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fileData">解密后的完整归档字节数据</param>
|
||||||
|
/// <returns>解析成功的 ArchiveBundle 实例</returns>
|
||||||
|
public static ArchiveBundle LoadFromMemory(byte[] fileData)
|
||||||
|
{
|
||||||
|
using (var ms = new MemoryStream(fileData, false))
|
||||||
|
{
|
||||||
|
var entries = ParseEntries(ms, fileData.Length);
|
||||||
|
return new ArchiveBundle(fileData, entries);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Dictionary<string, ArchiveBundle.FileEntry> ParseEntries(Stream stream, long dataLength)
|
||||||
|
{
|
||||||
|
using (var reader = new BinaryReader(stream, Encoding.UTF8, true))
|
||||||
{
|
{
|
||||||
// 校验文件头魔数(YARK)
|
// 校验文件头魔数(YARK)
|
||||||
uint magic = reader.ReadUInt32();
|
uint magic = reader.ReadUInt32();
|
||||||
@@ -34,7 +56,6 @@ namespace YooAsset
|
|||||||
if (fileCount > ArchiveBundleConsts.MaxChildFileCount)
|
if (fileCount > ArchiveBundleConsts.MaxChildFileCount)
|
||||||
throw new InvalidOperationException($"Archive child file count {fileCount} exceeds maximum ({ArchiveBundleConsts.MaxChildFileCount}).");
|
throw new InvalidOperationException($"Archive child file count {fileCount} exceeds maximum ({ArchiveBundleConsts.MaxChildFileCount}).");
|
||||||
|
|
||||||
long fileLength = fs.Length;
|
|
||||||
var entries = new Dictionary<string, ArchiveBundle.FileEntry>(fileCount);
|
var entries = new Dictionary<string, ArchiveBundle.FileEntry>(fileCount);
|
||||||
for (int i = 0; i < fileCount; i++)
|
for (int i = 0; i < fileCount; i++)
|
||||||
{
|
{
|
||||||
@@ -44,9 +65,9 @@ namespace YooAsset
|
|||||||
throw new InvalidOperationException($"Invalid path length {pathLen} at entry index {i}.");
|
throw new InvalidOperationException($"Invalid path length {pathLen} at entry index {i}.");
|
||||||
if (pathLen > ArchiveBundleConsts.MaxChildFilePathBytes)
|
if (pathLen > ArchiveBundleConsts.MaxChildFilePathBytes)
|
||||||
throw new InvalidOperationException($"Path length {pathLen} exceeds maximum ({ArchiveBundleConsts.MaxChildFilePathBytes}) at entry index {i}.");
|
throw new InvalidOperationException($"Path length {pathLen} exceeds maximum ({ArchiveBundleConsts.MaxChildFilePathBytes}) at entry index {i}.");
|
||||||
long remaining = fileLength - fs.Position;
|
long remaining = dataLength - stream.Position;
|
||||||
if (pathLen > remaining)
|
if (pathLen > remaining)
|
||||||
throw new InvalidOperationException($"Path length {pathLen} exceeds remaining file size at entry index {i}.");
|
throw new InvalidOperationException($"Path length {pathLen} exceeds remaining data size at entry index {i}.");
|
||||||
|
|
||||||
string assetPath = Encoding.UTF8.GetString(reader.ReadBytes(pathLen));
|
string assetPath = Encoding.UTF8.GetString(reader.ReadBytes(pathLen));
|
||||||
if (string.IsNullOrEmpty(assetPath))
|
if (string.IsNullOrEmpty(assetPath))
|
||||||
@@ -59,15 +80,15 @@ namespace YooAsset
|
|||||||
uint crc = reader.ReadUInt32();
|
uint crc = reader.ReadUInt32();
|
||||||
|
|
||||||
// 校验数据范围是否越过文件边界
|
// 校验数据范围是否越过文件边界
|
||||||
if (offset < 0 || offset > fileLength)
|
if (offset < 0 || offset > dataLength)
|
||||||
throw new InvalidOperationException($"Invalid data offset {offset} for '{assetPath}'.");
|
throw new InvalidOperationException($"Invalid data offset {offset} for '{assetPath}'.");
|
||||||
if (length < 0 || length > fileLength - offset)
|
if (length < 0 || length > dataLength - offset)
|
||||||
throw new InvalidOperationException($"Data range [{offset}, {offset + length}) exceeds file size {fileLength} for '{assetPath}'.");
|
throw new InvalidOperationException($"Data range [{offset}, {offset + length}) exceeds data size {dataLength} for '{assetPath}'.");
|
||||||
|
|
||||||
entries[assetPath] = new ArchiveBundle.FileEntry(assetPath, offset, length, crc);
|
entries[assetPath] = new ArchiveBundle.FileEntry(assetPath, offset, length, crc);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ArchiveBundle(filePath, entries);
|
return entries;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,124 @@
|
|||||||
|
#if TUANJIE_1_8_OR_NEWER && YOOASSET_INSTANT_ASSET_SUPPORT
|
||||||
|
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace YooAsset
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// InstantAsset 表上下文
|
||||||
|
/// </summary>
|
||||||
|
internal sealed class InstantAssetTableContext
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 初始化结果
|
||||||
|
/// </summary>
|
||||||
|
public readonly struct InitializeResult
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 错误信息
|
||||||
|
/// </summary>
|
||||||
|
public readonly string Error;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 初始化是否成功
|
||||||
|
/// </summary>
|
||||||
|
public bool Succeeded
|
||||||
|
{
|
||||||
|
get { return Error == null; }
|
||||||
|
}
|
||||||
|
|
||||||
|
private InitializeResult(string error)
|
||||||
|
{
|
||||||
|
Error = error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 创建表示初始化成功的默认结果
|
||||||
|
/// </summary>
|
||||||
|
public static InitializeResult Default()
|
||||||
|
{
|
||||||
|
return new InitializeResult(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 创建表示初始化失败的结果
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="error">错误信息</param>
|
||||||
|
public static InitializeResult Failure(string error)
|
||||||
|
{
|
||||||
|
return new InitializeResult(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly string _rootPath;
|
||||||
|
private readonly string _assetTableName;
|
||||||
|
private readonly string _sceneTableName;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 资源表
|
||||||
|
/// </summary>
|
||||||
|
public InstantAssetTable AssetTable { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 场景表
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// 如果不包含场景资源,该值为空值。
|
||||||
|
/// </remarks>
|
||||||
|
public InstantAssetTable SceneTable { get; private set; }
|
||||||
|
|
||||||
|
public InstantAssetTableContext(string rootPath, string assetTableName)
|
||||||
|
{
|
||||||
|
_rootPath = rootPath;
|
||||||
|
_assetTableName = assetTableName;
|
||||||
|
_sceneTableName = $"{assetTableName}-scene";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 初始化表上下文
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>初始化结果</returns>
|
||||||
|
public InitializeResult Initialize()
|
||||||
|
{
|
||||||
|
InstantAsset.SetInstantAssetRootPath(_rootPath);
|
||||||
|
|
||||||
|
string assetTablePath = PathUtility.Combine(_rootPath, _assetTableName);
|
||||||
|
AssetTable = InstantAsset.ReadAssetTable(assetTablePath) as InstantAssetTable;
|
||||||
|
if (AssetTable == null)
|
||||||
|
{
|
||||||
|
string error = $"Failed to load InstantAssetTable: '{assetTablePath}'.";
|
||||||
|
return InitializeResult.Failure(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
string sceneTablePath = PathUtility.Combine(_rootPath, _sceneTableName);
|
||||||
|
SceneTable = InstantAsset.ReadAssetTable(sceneTablePath) as InstantAssetTable;
|
||||||
|
if (SceneTable == null)
|
||||||
|
{
|
||||||
|
YooLogger.LogWarning($"InstantAsset scene table not found: '{sceneTablePath}'.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return InitializeResult.Default();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 卸载当前上下文持有的所有表
|
||||||
|
/// </summary>
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (AssetTable != null)
|
||||||
|
{
|
||||||
|
string assetTablePath = PathUtility.Combine(_rootPath, _assetTableName);
|
||||||
|
InstantAsset.UnloadAssetTable(assetTablePath);
|
||||||
|
AssetTable = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SceneTable != null)
|
||||||
|
{
|
||||||
|
string sceneTablePath = PathUtility.Combine(_rootPath, _sceneTableName);
|
||||||
|
InstantAsset.UnloadAssetTable(sceneTablePath);
|
||||||
|
SceneTable = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: a5b6f5ba1933ecc43aca5558fef29a05
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user