Compare commits

...

109 Commits
1.4.17 ... main

Author SHA1 Message Date
何冠峰 2c68e5dfd5 Update CHANGELOG.md 2024-08-14 10:26:04 +08:00
何冠峰 1c6e54df21 Update package.json 2024-08-14 10:26:01 +08:00
hevinci a4d378894e fix #295 2024-05-10 10:45:57 +08:00
hevinci 9d5a90e8fa fix #276 2024-04-12 11:50:40 +08:00
hevinci bb1c64e444 合并2.x功能到1.5
1. 增加获取缓存文件信息的异步操作
2. 支持资源下载器合并
3. 新增资源导入器
2024-03-27 18:50:10 +08:00
hevinci 92ac301716 feat : support open harmony 2024-03-13 15:42:23 +08:00
hevinci 135d5b4f5b Update AssetBundleCollector.cs
打包忽略编辑器资产 LightmapParameters
2024-03-11 11:28:42 +08:00
hevinci 23931e5d58 update asset bundle collector
移除资源包名的空格
2024-02-20 09:48:32 +08:00
何冠峰 619b5dbdaf
Merge pull request #243 from ZensYue/main
去除文件名中的空格
2024-02-20 09:44:14 +08:00
e 3105521fa9 去除文件名中的空格 2024-02-19 22:20:34 +08:00
何冠峰 b180fd8fc6
Merge pull request #235 from JellyHoney/main
update DeserializeManifestOperation
2024-02-18 10:16:06 +08:00
JellyHoney 769678a4b5 update DeserializeManifestOperation
优化修改文件后缀耗时
2024-02-01 16:46:34 +08:00
hevinci f90530e9f4 fix #226 2024-01-02 10:49:46 +08:00
hevinci 2630a7e793 fix #177 2023-10-08 15:56:19 +08:00
hevinci 45b016ae0f fix #175 2023-10-07 18:56:30 +08:00
hevinci c8ab0a43dd Update CHANGELOG.md 2023-10-07 16:31:13 +08:00
hevinci 9457a804b4 Update package.json 2023-10-07 16:31:09 +08:00
hevinci 880d498618 update download system
webgl平台支持下载器
2023-09-27 16:54:44 +08:00
hevinci ca89113c67 Update CHANGELOG.md 2023-09-26 18:54:25 +08:00
hevinci 29d840b168 Update package.json 2023-09-26 18:54:19 +08:00
hevinci 41d1586109 fix #96 2023-09-26 18:51:00 +08:00
hevinci 8d6a1d0066 Update CHANGELOG.md 2023-09-25 19:09:20 +08:00
hevinci bdfaaa0973 Update package.json 2023-09-25 19:09:11 +08:00
hevinci 30854e4b93 update asset settings
可以自定义设置参数DefaultYooFolderName
2023-09-25 18:25:34 +08:00
hevinci 54d89d957a update package system 2023-09-25 18:19:58 +08:00
hevinci ade97605f9 update asset bundle collector
增加了AddressDisable规则
2023-09-25 18:19:48 +08:00
hevinci bcb6443300 update asset bundle builder 2023-09-25 17:59:31 +08:00
hevinci 11386a7ec2 fix #161 2023-09-25 16:57:35 +08:00
hevinci 6fc45a758c fix #171 2023-09-25 16:21:02 +08:00
hevinci dcdf41b7c2 fix #96 2023-09-25 15:38:49 +08:00
hevinci 1aaf569396 fix #167 2023-09-25 15:08:43 +08:00
hevinci 101960f6d8 fix #163 2023-09-25 12:18:55 +08:00
hevinci 49b188964c fix #169 2023-09-25 11:38:01 +08:00
何冠峰 5539d81c93
Merge pull request #153 from michael811125/main
判断分组不激活时,则不进行 CheckConfigError 的检测
2023-09-01 14:07:11 +08:00
MichaelO ac3154e2ae 判断分组不激活时,则不进行 CheckConfigError 的检测 2023-09-01 13:43:03 +08:00
何冠峰 880b6d429d
Merge pull request #151 from michael811125/main
加入 ExtdBuildTasks 进行 SBP 扩展,修复 Sprite 打包冗馀问题 (猫佬方案) + typo error
2023-08-28 10:30:58 +08:00
MichaelO 070db961fc corrected typo error 2023-08-26 15:03:12 +08:00
MichaelO 96ef379668
Merge branch 'tuyoogame:main' into main 2023-08-25 20:48:08 +08:00
hevinci 697a87721f Update CHANGELOG.md 2023-08-25 20:39:53 +08:00
hevinci 09cf93d852 Update package.json 2023-08-25 20:39:46 +08:00
hevinci 8725821a27 update download system 2023-08-25 20:15:58 +08:00
MichaelO 7ad8651ca0 加入 ExtdBuildTasks 进行 SBP 扩展,修复 Sprite 打包冗馀问题 2023-08-25 19:48:02 +08:00
hevinci a2e57c6e90 update operation system 2023-08-25 17:37:49 +08:00
hevinci 6d37bca2a9 update asset bundle builder 2023-08-25 17:37:34 +08:00
hevinci 8471bb0f9a update asset bundle builder
暂时移除xxHash
2023-08-25 17:19:57 +08:00
何冠峰 05cb57db09
Merge pull request #150 from yingnierxiao/main
优化打包速度,提示编辑器启动速度,md5替换xxhash,速度提升一倍以上
2023-08-25 15:17:49 +08:00
yingnierxiao 064e9a1aa3 优化打包速度,提示编辑器启动速度,md5替换xxhash,速度提升一倍以上 2023-08-25 14:53:59 +08:00
hevinci a618b6cf9e update asset bundle reporter 2023-08-18 18:31:15 +08:00
何冠峰 e3e810e702
Merge pull request #134 from gepengmiss/main
bundle viewer 功能扩展
2023-08-18 17:58:43 +08:00
hevinci b4f0d6bab8 fix #138 2023-08-18 17:40:55 +08:00
hevinci 44cb4168cf update asset bundle collector 2023-08-17 22:13:31 +08:00
hevinci 559ed95999 update asset bundle collector
增加在配置错误的时候警示提示。
2023-08-17 21:53:51 +08:00
hevinci b766df1d31 update shader variant collector 2023-08-17 21:18:21 +08:00
hevinci 057ff6b22b fix #130 2023-08-17 21:05:21 +08:00
hevinci 995b0c8050 update space shooter 2023-08-15 18:19:07 +08:00
hevinci a2d4691f04 update package system
IQueryServices接口变更为IBuildinQueryServices
2023-08-14 12:27:43 +08:00
hevinci ab2d7d4724 update operation system
Operation状态增加Processing处理中状态
2023-08-11 16:20:38 +08:00
hevinci 9b4abf86b6 update runtime code
可寻址模式默认支持通过资源路径加载。
2023-08-09 20:15:55 +08:00
hevinci 0331b7b6e3 update editor code 2023-08-09 20:15:33 +08:00
hevinci e31799e78b Update CHANGELOG.md 2023-07-28 17:32:44 +08:00
hevinci a8405eea6d Update package.json 2023-07-28 17:32:38 +08:00
hevinci c11f072c50 update asset system 2023-07-28 17:17:23 +08:00
YGP bd080eb19b modify bundleViewer func 2023-07-27 16:12:21 +08:00
YGP ef231e213e modify bundleViewer func 2023-07-27 16:06:09 +08:00
YGP a5900b5f99 ignore 2023-07-27 16:04:59 +08:00
hevinci b22bbd4e27 update editor code 2023-07-25 18:48:32 +08:00
hevinci 664866b627 update space shooter 2023-07-25 18:38:02 +08:00
hevinci ad9bdc6574 update download system 2023-07-25 18:37:43 +08:00
hevinci b93b993951 update package system 2023-07-20 14:28:22 +08:00
hevinci cb2cb4e556 update package system 2023-07-20 11:27:56 +08:00
hevinci ab32bd390d update space shooter 2023-07-20 11:08:52 +08:00
hevinci b34374adfa update runtime code 2023-07-20 11:08:38 +08:00
hevinci b53b6a4246 update runtime code 2023-07-20 11:08:28 +08:00
hevinci 191fbff768 update package system
增加对清单激活的检测
2023-07-19 18:18:03 +08:00
hevinci e8a4ddf331 update runtime code 2023-07-19 17:48:26 +08:00
hevinci aee6e2d2f8 update space shooter 2023-07-19 17:06:35 +08:00
hevinci b737b20602 update runtime code
支持开发者资源分发和加载
2023-07-19 17:06:20 +08:00
hevinci b5df539392 update package system
增加对UpdatePackageManifestOperation参数的检测
2023-07-19 15:57:34 +08:00
hevinci 36c53e5d94 update space shooter 2023-07-19 14:34:51 +08:00
hevinci 15ce6b8c8c update runtime code 2023-07-19 14:34:43 +08:00
hevinci 19aa82c131 update editor code 2023-07-19 11:22:59 +08:00
hevinci 92ed6e7d1c Update CHANGELOG.md 2023-07-18 14:50:42 +08:00
hevinci b9a45a58a8 Update package.json 2023-07-18 14:49:57 +08:00
hevinci 0c1efe7420 update runtime code
1. 新增WebGL专属模式WebPlayMode
2023-07-18 14:27:33 +08:00
hevinci 9dd7680457 update space shooter 2023-07-18 11:21:23 +08:00
hevinci 087216b9da update runtime code 2023-07-17 19:43:41 +08:00
hevinci ecb6f71f81 update editor code 2023-07-17 19:38:11 +08:00
hevinci ffffff16e9 update space shooter 2023-07-14 09:58:27 +08:00
hevinci 0311d976bb Update CHANGELOG.md 2023-07-12 21:08:22 +08:00
hevinci 120c07cc2e Update package.json 2023-07-12 21:07:57 +08:00
hevinci ed5ae40cb3 update asset system
修复了在销毁Package时,如果存在正在加载的bundle,会导致后续加载该bundle报错的问题。
2023-07-12 20:56:11 +08:00
hevinci 5931d91b5f update space shooter 2023-07-12 19:15:36 +08:00
hevinci 472a5ae97a update package system
1. 移除了HostPlayModeParameters.DefaultHostServer字段
2. 移除了HostPlayModeParameters.FallbackHostServer字段
3. 新增了HostPlayModeParameters.RemoteServices字段
2023-07-12 19:15:10 +08:00
hevinci 829ea66d0e update sapce shooter
修复生成内置文件清单的时候,目录不存在引发的异常。
2023-07-12 17:18:40 +08:00
hevinci ba39291ee7 update asset system
真机上使用错误方法加载原生文件的时候给予正确的错误提示。
2023-07-07 12:16:16 +08:00
hevinci d3d15fc59f Update CHANGELOG.md 2023-07-05 17:04:35 +08:00
hevinci 8a3358c990 Update package.json 2023-07-05 17:04:12 +08:00
hevinci 8eadba3aa6 update space shooter 2023-07-05 16:31:29 +08:00
hevinci b0917623b6 update runtime code
变更IQueryServices.QueryStreamingAssets(string packageName, string fileName)方法
2023-07-05 16:31:06 +08:00
hevinci a7d9a4ecbc update extension sample 2023-07-05 15:20:34 +08:00
hevinci 2643ab81ed update runtime code
重构了PersistentTools类
2023-07-05 15:14:21 +08:00
hevinci c5314c72f0 update runtime code
1. 新增了ResourcePackage.GetPackageBuildinRootDirectory()方法
2. 新增了ResourcePackage.GetPackageSandboxRootDirectory()方法
3. 新增了ResourcePackage.ClearPackageSandbox()方法
2023-07-05 14:56:18 +08:00
hevinci fbb48ba330 Update InitializeParameters.cs
1. 新增了InitializeParameters.BuildinRootDirectory字段
2. 新增了InitializeParameters.SandboxRootDirectory字段
2023-07-05 14:52:13 +08:00
hevinci 4e6879e34f update runtime code
1. 移除了YooAssets.SetCacheSystemBuildinPath()方法
2. 移除了YooAssets.SetCacheSystemSandboxPath()方法
3. 移除了YooAssets.GetStreamingAssetBuildinFolderName()方法
4. 移除了YooAssets.GetSandboxRoot()方法
5. 移除了YooAssets.ClearSandbox()方法
2023-07-05 14:50:21 +08:00
hevinci 09c3d4e479 update editor code
1. BuildParameters.OutputRoot重命名为BuildOutputRoot
2. 新增了BuildParameters.StreamingAssetsRoot字段
2023-07-05 11:51:49 +08:00
hevinci 1e88bad73e update cache system
新增方法YooAssets.SetCacheSystemBuildinPath()
2023-06-30 18:51:55 +08:00
hevinci 9a2ed64b4e update download system
新增方法YooAssets.SetDownloadSystemRedirectLimit()
2023-06-29 15:47:10 +08:00
hevinci 60e93f9809 update AssetBundleBuilder
1. 移除了资源包构建流程任务节点可扩展功能
2. 新增了构建流程可扩展的方法。
2023-06-29 10:53:07 +08:00
hevinci f5c72e913f update runtime code
新增方法YooAssets.SetCacheSystemDisableCacheOnWebGL()
2023-06-28 17:46:32 +08:00
172 changed files with 4207 additions and 2159 deletions

17
.gitignore vendored
View File

@ -10,8 +10,23 @@
/[Ll]ogs/
/[Mm]emoryCaptures/
/Bundles/
/ProjectSettings/
/App/
/yoo/
/Assets/StreamingAssets
/Assets/StreamingAssets.meta
/Assets/Samples
/Assets/Samples.meta
/Packages
/UserSettings
# Asset meta data should only be ignored when the corresponding asset is also ignored
!/[Aa]ssets/**/*.meta
# Uncomment this line if you wish to ignore the asset store tools plugin
# /[Aa]ssets/AssetStoreTools*

View File

@ -2,6 +2,296 @@
All notable changes to this package will be documented in this file.
## [1.5.8] - 2024-8-14
### Fixed
- (#175) 修复了Mac平台URL路径有空格的情况会报Malformed URL错误。
- (#177) 修复了加载一个地址的主资源或子资源之后无法再加载另一种的问题。
- (#266) 修复了资源系统遍历IsBusy次数过多导致过多的耗时的问题。
- (#276) 修复了HostPlayMode模式下如果内置清单是最新版本每次运行都会触发拷贝行为。
- (#295) 修复了在安卓平台,华为和三星真机上有极小概率加载资源包失败 : Unable to open archive file。
### Added
- 新增资源导入器。
- 新增获取缓存文件信息的方法。
### Changed
- 支持鸿蒙操作系统。
- 支持资源下载器合并。
## [1.5.7] - 2023-10-07
### Changed
- WebGL平台支持创建下载器。
## [1.5.6-preview] - 2023-09-26
### Fixed
- (#172) 修复包裹初始化后package的状态不正确的问题。
## [1.5.5-preview] - 2023-09-25
### Fixed
- (#96) 修复了异步操作任务的完成回调在业务层触发异常时无法正常完成的问题。
- (#156) 修复了多个Package存在时服务器请求地址请求顺序不对的问题。
- (#163) 修复了Unity2019版本编译报错的问题。
- (#167) 修复了初始化时每次都会提示文件验证失败日志。
- (#171) 修复了IsNeedDownloadFromRemote里缺少判断依赖的资源是否下载 。
### Added
- 资源收集器里增加了AddressDisable规则。
- 资源收集器里FilterRuleData结构体增加了多个备选字段。
```c#
public struct FilterRuleData
{
public string AssetPath;
public string CollectPath;
public string GroupName;
public string UserData;
}
```
### Changed
- 可以设置自定义参数DefaultYooFolderName。
- 资源配置界面的分组不激活时,不再进行配置检测。
- SBP构建管线增加新构建参数用于修复图集资源冗余问题。
```c#
public class SBPBuildParameters
{
/// <summary>
/// 修复图集资源冗余问题
/// </summary>
public bool FixSpriteAtlasRedundancy = false;
}
```
## [1.5.4-preview] - 2023-08-25
优化了资源清单文件构建速度极大提升构建体验感谢yingnierxiao同学
### Fixed
- (#130) 修复了打包路径无效问题bug
- (#138) 修复了Unity不支持的格式的原生文件会报warning
### Added
- 新增了IBuildinQueryServices 接口。
### Changed
- 在开启可寻址模式下,默认支持通过资源路径加载资源对象。
- 优化了资源收集界面,增加了配置相关的警示提示。
- 优化了资源报告界面增加了BundleView界面里的builtin资源的列表显示。
- IQueryServices接口变更为IBuildinQueryServices接口
- EOperationStatus增加了正在处理的状态。
```c#
public enum EOperationStatus
{
None,
Processing,
Succeed,
Failed
}
```
## [1.5.3-preview] - 2023-07-28
### Fixed
- 修复了Unity2020以下版本的编辑器提示找不到"autoLoadAssetBundle"的编译错误。
### Added
- 新增了支持开发者分发资源的功能。
```c#
public interface IQueryServices
{
/// <summary>
/// 查询应用程序里的内置资源是否存在
/// </summary>
bool QueryStreamingAssets(string packageName, string fileName);
/// <summary>
/// 查询是否为开发者分发的资源
/// </summary>
bool QueryDeliveryFiles(string packageName, string fileName);
/// <summary>
/// 获取开发者分发的资源信息
/// </summary>
DeliveryFileInfo GetDeliveryFileInfo(string packageName, string fileName);
}
```
### Changed
- 针对资源清单更新方法传入参数的合法性检测。
- 编辑器下针对激活的资源清单有效性的检测。
## [1.5.2-preview] - 2023-07-18
重新设计了对WebGL平台的支持新增加了专属模式WebPlayMode
## [1.5.1] - 2023-07-12
### Fixed
- 修复了太空战机DEMO在生成内置文件清单的时候目录不存在引发的异常。
- 修复了在销毁Package时如果存在正在加载的bundle会导致后续加载该bundle报错的问题。
### Changed
- 真机上使用错误方法加载原生文件的时候给予正确的错误提示。
### Added
- 新增了HostPlayModeParameters.RemoteServices字段
```c#
/// <summary>
/// 远端资源地址查询服务类
/// </summary>
public IRemoteServices RemoteServices = null;
```
### Removed
- 移除了HostPlayModeParameters.DefaultHostServer字段
- 移除了HostPlayModeParameters.FallbackHostServer字段
## [1.5.0] - 2023-07-05
该版本重构了Persistent类导致沙盒目录和内置目录的存储结构发生了变化。
该版本支持按照Package自定义沙盒存储目录和内置存储目录。
**注意低版本升级用户请使用Space Shooter目录下的StreamingAssetsHelper插件覆盖到本地工程**
### Changed
- BuildParameters.OutputRoot重命名为BuildOutputRoot
- 变更了IQueryServices.QueryStreamingAssets(string packageName, string fileName)方法
### Added
- 新增了YooAssets.SetCacheSystemDisableCacheOnWebGL()方法
```c#
/// <summary>
/// 设置缓存系统参数禁用缓存在WebGL平台
/// </summary>
public static void SetCacheSystemDisableCacheOnWebGL()
```
- 新增了YooAssets.SetDownloadSystemRedirectLimit()方法
```c#
/// <summary>
/// 设置下载系统参数网络重定向次数Unity引擎默认值32
/// 注意:不支持设置为负值
/// </summary>
public static void SetDownloadSystemRedirectLimit(int redirectLimit)
```
- 新增了构建流程可扩展的方法。
```c#
public class AssetBundleBuilder
{
/// <summary>
/// 构建资源包
/// </summary>
public BuildResult Run(BuildParameters buildParameters, List<IBuildTask> buildPipeline)
}
```
- 新增了BuildParameters.StreamingAssetsRoot字段
```c#
public class BuildParameters
{
/// <summary>
/// 内置资源的根目录
/// </summary>
public string StreamingAssetsRoot;
}
```
- 新增了InitializeParameters.BuildinRootDirectory字段
```c#
/// <summary>
/// 内置文件的根路径
/// 注意:当参数为空的时候会使用默认的根目录。
/// </summary>
public string BuildinRootDirectory = string.Empty;
```
- 新增了InitializeParameters.SandboxRootDirectory字段
```c#
/// <summary>
/// 沙盒文件的根路径
/// 注意:当参数为空的时候会使用默认的根目录。
/// </summary>
public string SandboxRootDirectory = string.Empty;
```
- 新增了ResourcePackage.GetPackageBuildinRootDirectory()方法
```c#
/// <summary>
/// 获取包裹的内置文件根路径
/// </summary>
public string GetPackageBuildinRootDirectory()
```
- 新增了ResourcePackage.GetPackageSandboxRootDirectory()方法
```c#
/// <summary>
/// 获取包裹的沙盒文件根路径
/// </summary>
public string GetPackageSandboxRootDirectory()
```
- 新增了ResourcePackage.ClearPackageSandbox()方法
```c#
/// <summary>
/// 清空包裹的沙盒目录
/// </summary>
public void ClearPackageSandbox()
```
### Removed
- 移除了资源包构建流程任务节点可扩展功能。
- 移除了YooAssets.SetCacheSystemSandboxPath()方法
- 移除了YooAssets.GetStreamingAssetBuildinFolderName()方法
- 移除了YooAssets.GetSandboxRoot()方法
- 移除了YooAssets.ClearSandbox()方法
## [1.4.17] - 2023-06-27
### Changed
@ -25,8 +315,6 @@ All notable changes to this package will be documented in this file.
- IShareAssetPackRule 重命名为 ISharedPackRule
-
### Added
- 新增了ResourcePackage.LoadAllAssetsAsync方法

View File

@ -13,29 +13,20 @@ namespace YooAsset.Editor
private readonly BuildContext _buildContext = new BuildContext();
/// <summary>
/// 开始构建
/// 构建资源包
/// </summary>
public BuildResult Run(BuildParameters buildParameters)
public BuildResult Run(BuildParameters buildParameters, List<IBuildTask> buildPipeline)
{
// 清空旧数据
_buildContext.ClearAllContext();
// 检测构建参数是否为空
if (buildParameters == null)
throw new Exception($"{nameof(buildParameters)} is null !");
// 检测可编程构建管线参数
if (buildParameters.BuildPipeline == EBuildPipeline.ScriptableBuildPipeline)
{
if (buildParameters.SBPParameters == null)
throw new Exception($"{nameof(BuildParameters.SBPParameters)} is null !");
// 检测构建参数是否为空
if (buildPipeline.Count == 0)
throw new Exception($"Build pipeline is empty !");
if (buildParameters.BuildMode == EBuildMode.DryRunBuild)
throw new Exception($"{nameof(EBuildPipeline.ScriptableBuildPipeline)} not support {nameof(EBuildMode.DryRunBuild)} build mode !");
if (buildParameters.BuildMode == EBuildMode.ForceRebuild)
throw new Exception($"{nameof(EBuildPipeline.ScriptableBuildPipeline)} not support {nameof(EBuildMode.ForceRebuild)} build mode !");
}
// 清空旧数据
_buildContext.ClearAllContext();
// 构建参数
var buildParametersContext = new BuildParametersContext(buildParameters);
@ -45,8 +36,7 @@ namespace YooAsset.Editor
BuildLogger.InitLogger(buildParameters.EnableLog);
// 执行构建流程
var pipeline = GetBuildTasks(buildParameters.BuildPipeline);
var buildResult = BuildRunner.Run(pipeline, _buildContext);
var buildResult = BuildRunner.Run(buildPipeline, _buildContext);
if (buildResult.Success)
{
buildResult.OutputPackageDirectory = buildParametersContext.GetPackageOutputDirectory();
@ -62,13 +52,23 @@ namespace YooAsset.Editor
return buildResult;
}
private List<IBuildTask> GetBuildTasks(EBuildPipeline buildPipeline)
/// <summary>
/// 构建资源包
/// </summary>
public BuildResult Run(BuildParameters buildParameters)
{
var buildPipeline = GetDefaultBuildPipeline(buildParameters.BuildPipeline);
return Run(buildParameters, buildPipeline);
}
/// <summary>
/// 获取默认的构建流程
/// </summary>
private List<IBuildTask> GetDefaultBuildPipeline(EBuildPipeline buildPipeline)
{
// 获取任务节点的属性集合
List<TaskAttribute> attrList = new List<TaskAttribute>();
if (buildPipeline == EBuildPipeline.BuiltinBuildPipeline)
{
/*
List<IBuildTask> pipeline = new List<IBuildTask>
{
new TaskPrepare(), //前期准备工作
@ -83,23 +83,10 @@ namespace YooAsset.Editor
new TaskCreatePackage(), //制作包裹
new TaskCopyBuildinFiles(), //拷贝内置文件
};
*/
var classTypes = EditorTools.GetAssignableTypes(typeof(IBuildTask));
foreach (var classType in classTypes)
{
var attribute = classType.GetCustomAttribute<TaskAttribute>();
if (attribute == null)
throw new Exception($"Not found {nameof(TaskAttribute)} int type : {classType.FullName}");
attribute.ClassType = classType;
if (attribute.Pipeline == ETaskPipeline.AllPipeline || attribute.Pipeline == ETaskPipeline.BuiltinBuildPipeline)
attrList.Add(attribute);
}
return pipeline;
}
else if (buildPipeline == EBuildPipeline.ScriptableBuildPipeline)
{
/*
List<IBuildTask> pipeline = new List<IBuildTask>
{
new TaskPrepare(), //前期准备工作
@ -114,42 +101,12 @@ namespace YooAsset.Editor
new TaskCreatePackage(), //制作补丁包
new TaskCopyBuildinFiles(), //拷贝内置文件
};
*/
var classTypes = EditorTools.GetAssignableTypes(typeof(IBuildTask));
foreach (var classType in classTypes)
{
var attribute = classType.GetCustomAttribute<TaskAttribute>();
if (attribute == null)
throw new Exception($"Not found {nameof(TaskAttribute)} int type : {classType.FullName}");
attribute.ClassType = classType;
if (attribute.Pipeline == ETaskPipeline.AllPipeline || attribute.Pipeline == ETaskPipeline.ScriptableBuildPipeline)
attrList.Add(attribute);
}
return pipeline;
}
else
{
throw new NotImplementedException();
}
// 对任务节点进行排序
attrList.Sort((a, b) =>
{
if (a.TaskOrder > b.TaskOrder) { return 1; }
else if (a.TaskOrder < b.TaskOrder) { return -1; }
else { return 0; }
});
// 创建任务节点实例
List<IBuildTask> pipeline = new List<IBuildTask>(attrList.Count);
foreach (var taskAttr in attrList)
{
var task = Activator.CreateInstance(taskAttr.ClassType) as IBuildTask;
pipeline.Add(task);
}
return pipeline;
}
}
}

View File

@ -11,7 +11,7 @@ namespace YooAsset.Editor
/// <summary>
/// 获取默认的输出根路录
/// </summary>
public static string GetDefaultOutputRoot()
public static string GetDefaultBuildOutputRoot()
{
string projectPath = EditorTools.GetProjectPath();
return $"{projectPath}/Bundles";
@ -20,43 +20,9 @@ namespace YooAsset.Editor
/// <summary>
/// 获取流文件夹路径
/// </summary>
public static string GetStreamingAssetsFolderPath()
public static string GetDefaultStreamingAssetsRoot()
{
return $"{Application.dataPath}/StreamingAssets/{YooAssetSettings.StreamingAssetsBuildinFolder}/";
}
/// <summary>
/// 清空流文件夹
/// </summary>
public static void ClearStreamingAssetsFolder()
{
string streamingFolderPath = GetStreamingAssetsFolderPath();
EditorTools.ClearFolder(streamingFolderPath);
}
/// <summary>
/// 删除流文件夹内无关的文件
/// 删除.manifest文件和.meta文件
/// </summary>
public static void DeleteStreamingAssetsIgnoreFiles()
{
string streamingFolderPath = GetStreamingAssetsFolderPath();
if (Directory.Exists(streamingFolderPath))
{
string[] files = Directory.GetFiles(streamingFolderPath, "*.manifest", SearchOption.AllDirectories);
foreach (var file in files)
{
FileInfo info = new FileInfo(file);
info.Delete();
}
files = Directory.GetFiles(streamingFolderPath, "*.meta", SearchOption.AllDirectories);
foreach (var item in files)
{
FileInfo info = new FileInfo(item);
info.Delete();
}
}
return $"{Application.dataPath}/StreamingAssets/{YooAssetSettingsData.Setting.DefaultYooFolderName}/";
}
}
}

View File

@ -1,215 +0,0 @@
using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEditor.Animations;
namespace YooAsset.Editor
{
public static class AssetBundleBuilderTools
{
/// <summary>
/// 检测所有损坏的预制体文件
/// </summary>
public static void CheckCorruptionPrefab(List<string> searchDirectorys)
{
if (searchDirectorys.Count == 0)
throw new Exception("路径列表不能为空!");
// 获取所有资源列表
int checkCount = 0;
int invalidCount = 0;
string[] findAssets = EditorTools.FindAssets(EAssetSearchType.Prefab, searchDirectorys.ToArray());
foreach (string assetPath in findAssets)
{
UnityEngine.Object prefab = AssetDatabase.LoadAssetAtPath(assetPath, typeof(UnityEngine.Object));
if (prefab == null)
{
invalidCount++;
Debug.LogError($"发现损坏预制件:{assetPath}");
}
EditorTools.DisplayProgressBar("检测预制件文件是否损坏", ++checkCount, findAssets.Length);
}
EditorTools.ClearProgressBar();
if (invalidCount == 0)
Debug.Log($"没有发现损坏预制件");
}
/// <summary>
/// 检测所有动画控制器的冗余状态
/// </summary>
public static void FindRedundantAnimationState(List<string> searchDirectorys)
{
if (searchDirectorys.Count == 0)
throw new Exception("路径列表不能为空!");
// 获取所有资源列表
int checkCount = 0;
int findCount = 0;
string[] findAssets = EditorTools.FindAssets(EAssetSearchType.RuntimeAnimatorController, searchDirectorys.ToArray());
foreach (string assetPath in findAssets)
{
AnimatorController animator= AssetDatabase.LoadAssetAtPath<AnimatorController>(assetPath);
if (FindRedundantAnimationState(animator))
{
findCount++;
Debug.LogWarning($"发现冗余的动画控制器:{assetPath}");
}
EditorTools.DisplayProgressBar("检测冗余的动画控制器", ++checkCount, findAssets.Length);
}
EditorTools.ClearProgressBar();
if (findCount == 0)
Debug.Log($"没有发现冗余的动画控制器");
else
AssetDatabase.SaveAssets();
}
/// <summary>
/// 清理所有材质球的冗余属性
/// </summary>
public static void ClearMaterialUnusedProperty(List<string> searchDirectorys)
{
if (searchDirectorys.Count == 0)
throw new Exception("路径列表不能为空!");
// 获取所有资源列表
int checkCount = 0;
int removedCount = 0;
string[] findAssets = EditorTools.FindAssets(EAssetSearchType.Material, searchDirectorys.ToArray());
foreach (string assetPath in findAssets)
{
Material mat = AssetDatabase.LoadAssetAtPath<Material>(assetPath);
if (ClearMaterialUnusedProperty(mat))
{
removedCount++;
Debug.LogWarning($"材质球已被处理:{assetPath}");
}
EditorTools.DisplayProgressBar("清理冗余的材质球", ++checkCount, findAssets.Length);
}
EditorTools.ClearProgressBar();
if (removedCount == 0)
Debug.Log($"没有发现冗余的材质球");
else
AssetDatabase.SaveAssets();
}
/// <summary>
/// 清理无用的材质球属性
/// </summary>
private static bool ClearMaterialUnusedProperty(Material mat)
{
bool removeUnused = false;
SerializedObject so = new SerializedObject(mat);
SerializedProperty sp = so.FindProperty("m_SavedProperties");
sp.Next(true);
do
{
if (sp.isArray == false)
continue;
for (int i = sp.arraySize - 1; i >= 0; --i)
{
var p1 = sp.GetArrayElementAtIndex(i);
if (p1.isArray)
{
for (int ii = p1.arraySize - 1; ii >= 0; --ii)
{
var p2 = p1.GetArrayElementAtIndex(ii);
var val = p2.FindPropertyRelative("first");
if (mat.HasProperty(val.stringValue) == false)
{
Debug.Log($"Material {mat.name} remove unused property : {val.stringValue}");
p1.DeleteArrayElementAtIndex(ii);
removeUnused = true;
}
}
}
else
{
var val = p1.FindPropertyRelative("first");
if (mat.HasProperty(val.stringValue) == false)
{
Debug.Log($"Material {mat.name} remove unused property : {val.stringValue}");
sp.DeleteArrayElementAtIndex(i);
removeUnused = true;
}
}
}
}
while (sp.Next(false));
so.ApplyModifiedProperties();
return removeUnused;
}
/// <summary>
/// 查找动画控制器里冗余的动画状态机
/// </summary>
private static bool FindRedundantAnimationState(AnimatorController animatorController)
{
if (animatorController == null)
return false;
string assetPath = AssetDatabase.GetAssetPath(animatorController);
// 查找使用的状态机名称
List<string> usedStateNames = new List<string>();
foreach (var layer in animatorController.layers)
{
foreach (var state in layer.stateMachine.states)
{
usedStateNames.Add(state.state.name);
}
}
List<string> allLines = new List<string>();
List<int> stateIndexList = new List<int>();
using (StreamReader reader = File.OpenText(assetPath))
{
string content;
while (null != (content = reader.ReadLine()))
{
allLines.Add(content);
if (content.StartsWith("AnimatorState:"))
{
stateIndexList.Add(allLines.Count - 1);
}
}
}
List<string> allStateNames = new List<string>();
foreach (var index in stateIndexList)
{
for (int i = index; i < allLines.Count; i++)
{
string content = allLines[i];
content = content.Trim();
if (content.StartsWith("m_Name"))
{
string[] splits = content.Split(':');
string name = splits[1].TrimStart(' '); //移除前面的空格
allStateNames.Add(name);
break;
}
}
}
bool foundRedundantState = false;
foreach (var stateName in allStateNames)
{
if (usedStateNames.Contains(stateName) == false)
{
Debug.LogWarning($"发现冗余的动画文件:{assetPath}={stateName}");
foundRedundantState = true;
}
}
return foundRedundantState;
}
}
}

View File

@ -63,7 +63,7 @@ namespace YooAsset.Editor
_encryptionServicesClassNames = _encryptionServicesClassTypes.Select(t => t.Name).ToList();
// 输出目录
string defaultOutputRoot = AssetBundleBuilderHelper.GetDefaultOutputRoot();
string defaultOutputRoot = AssetBundleBuilderHelper.GetDefaultBuildOutputRoot();
_buildOutputField = root.Q<TextField>("BuildOutput");
_buildOutputField.SetValueWithoutNotify(defaultOutputRoot);
_buildOutputField.SetEnabled(false);
@ -266,9 +266,9 @@ namespace YooAsset.Editor
/// </summary>
private void ExecuteBuild()
{
string defaultOutputRoot = AssetBundleBuilderHelper.GetDefaultOutputRoot();
BuildParameters buildParameters = new BuildParameters();
buildParameters.OutputRoot = defaultOutputRoot;
buildParameters.StreamingAssetsRoot = AssetBundleBuilderHelper.GetDefaultStreamingAssetsRoot();
buildParameters.BuildOutputRoot = AssetBundleBuilderHelper.GetDefaultBuildOutputRoot();
buildParameters.BuildTarget = _buildTarget;
buildParameters.BuildPipeline = AssetBundleBuilderSettingData.Setting.BuildPipeline;
buildParameters.BuildMode = AssetBundleBuilderSettingData.Setting.BuildMode;

View File

@ -11,9 +11,9 @@ namespace YooAsset.Editor
public static string SimulateBuild(string packageName)
{
Debug.Log($"Begin to create simulate package : {packageName}");
string defaultOutputRoot = AssetBundleBuilderHelper.GetDefaultOutputRoot();
BuildParameters buildParameters = new BuildParameters();
buildParameters.OutputRoot = defaultOutputRoot;
buildParameters.StreamingAssetsRoot = AssetBundleBuilderHelper.GetDefaultStreamingAssetsRoot();
buildParameters.BuildOutputRoot = AssetBundleBuilderHelper.GetDefaultBuildOutputRoot();
buildParameters.BuildTarget = EditorUserBuildSettings.activeBuildTarget;
buildParameters.BuildMode = EBuildMode.SimulateBuild;
buildParameters.PackageName = packageName;

View File

@ -8,39 +8,54 @@ namespace YooAsset.Editor
{
public class BuildBundleInfo
{
public class InfoWrapper
{
/// <summary>
/// 构建内容的哈希值
/// </summary>
public string ContentHash { set; get; }
#region 补丁文件的关键信息
/// <summary>
/// Unity引擎生成的哈希值构建内容的哈希值
/// </summary>
public string PackageUnityHash { set; get; }
/// <summary>
/// 文件哈希值
/// </summary>
public string FileHash { set; get; }
/// <summary>
/// Unity引擎生成的CRC
/// </summary>
public uint PackageUnityCRC { set; get; }
/// <summary>
/// 文件哈希值
/// </summary>
public string FileCRC { set; get; }
/// <summary>
/// 文件哈希值
/// </summary>
public string PackageFileHash { set; get; }
/// <summary>
/// 文件哈希值
/// </summary>
public long FileSize { set; get; }
/// <summary>
/// 文件哈希值
/// </summary>
public string PackageFileCRC { set; get; }
/// <summary>
/// 文件哈希值
/// </summary>
public long PackageFileSize { set; get; }
/// <summary>
/// 构建输出的文件路径
/// </summary>
public string BuildOutputFilePath { set; get; }
/// <summary>
/// 构建输出的文件路径
/// </summary>
public string BuildOutputFilePath { set; get; }
/// <summary>
/// 补丁包的源文件路径
/// </summary>
public string PackageSourceFilePath { set; get; }
/// <summary>
/// 补丁包的目标文件路径
/// </summary>
public string PackageDestFilePath { set; get; }
/// <summary>
/// 加密生成文件的路径
/// 注意:如果未加密该路径为空
/// </summary>
public string EncryptedFilePath { set; get; }
#endregion
/// <summary>
/// 补丁包输出文件路径
/// </summary>
public string PackageOutputFilePath { set; get; }
}
/// <summary>
/// 资源包名称
@ -53,22 +68,11 @@ namespace YooAsset.Editor
/// </summary>
public readonly List<BuildAssetInfo> AllMainAssets = new List<BuildAssetInfo>();
/// <summary>
/// 补丁文件信息
/// </summary>
public readonly InfoWrapper BundleInfo = new InfoWrapper();
/// <summary>
/// Bundle文件的加载方法
/// </summary>
public EBundleLoadMethod LoadMethod { set; get; }
/// <summary>
/// 加密生成文件的路径
/// 注意:如果未加密该路径为空
/// </summary>
public string EncryptedFilePath { set; get; }
/// <summary>
/// 是否为原生文件
/// </summary>
@ -208,9 +212,10 @@ namespace YooAsset.Editor
{
PackageBundle packageBundle = new PackageBundle();
packageBundle.BundleName = BundleName;
packageBundle.FileHash = BundleInfo.FileHash;
packageBundle.FileCRC = BundleInfo.FileCRC;
packageBundle.FileSize = BundleInfo.FileSize;
packageBundle.FileHash = PackageFileHash;
packageBundle.FileCRC = PackageFileCRC;
packageBundle.FileSize = PackageFileSize;
packageBundle.UnityCRC = PackageUnityCRC;
packageBundle.IsRawFile = IsRawFile;
packageBundle.LoadMethod = (byte)LoadMethod;
packageBundle.Tags = GetBundleTags();

View File

@ -28,6 +28,11 @@ namespace YooAsset.Editor
/// 缓存服务器端口
/// </summary>
public int CacheServerPort;
/// <summary>
/// 修复图集资源冗余问题
/// </summary>
public bool FixSpriteAtlasRedundancy = false;
}
/// <summary>
@ -37,9 +42,14 @@ namespace YooAsset.Editor
/// <summary>
/// 输出的根目录
/// 内置资源的根目录
/// </summary>
public string OutputRoot;
public string StreamingAssetsRoot;
/// <summary>
/// 构建输出的根目录
/// </summary>
public string BuildOutputRoot;
/// <summary>
/// 构建的平台

View File

@ -9,6 +9,8 @@ namespace YooAsset.Editor
{
private string _pipelineOutputDirectory = string.Empty;
private string _packageOutputDirectory = string.Empty;
private string _packageRootDirectory = string.Empty;
private string _streamingAssetsDirectory = string.Empty;
/// <summary>
/// 构建参数
@ -29,23 +31,47 @@ namespace YooAsset.Editor
{
if (string.IsNullOrEmpty(_pipelineOutputDirectory))
{
_pipelineOutputDirectory = $"{Parameters.OutputRoot}/{Parameters.BuildTarget}/{Parameters.PackageName}/{YooAssetSettings.OutputFolderName}";
_pipelineOutputDirectory = $"{Parameters.BuildOutputRoot}/{Parameters.BuildTarget}/{Parameters.PackageName}/{YooAssetSettings.OutputFolderName}";
}
return _pipelineOutputDirectory;
}
/// <summary>
/// 获取本次构建的补丁目录
/// 获取本次构建的补丁输出目录
/// </summary>
public string GetPackageOutputDirectory()
{
if (string.IsNullOrEmpty(_packageOutputDirectory))
{
_packageOutputDirectory = $"{Parameters.OutputRoot}/{Parameters.BuildTarget}/{Parameters.PackageName}/{Parameters.PackageVersion}";
_packageOutputDirectory = $"{Parameters.BuildOutputRoot}/{Parameters.BuildTarget}/{Parameters.PackageName}/{Parameters.PackageVersion}";
}
return _packageOutputDirectory;
}
/// <summary>
/// 获取本次构建的补丁根目录
/// </summary>
public string GetPackageRootDirectory()
{
if (string.IsNullOrEmpty(_packageRootDirectory))
{
_packageRootDirectory = $"{Parameters.BuildOutputRoot}/{Parameters.BuildTarget}/{Parameters.PackageName}";
}
return _packageRootDirectory;
}
/// <summary>
/// 获取内置资源的目录
/// </summary>
public string GetStreamingAssetsDirectory()
{
if (string.IsNullOrEmpty(_streamingAssetsDirectory))
{
_streamingAssetsDirectory = $"{Parameters.StreamingAssetsRoot}/{Parameters.PackageName}";
}
return _streamingAssetsDirectory;
}
/// <summary>
/// 获取内置构建管线的构建选项
/// </summary>

View File

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

View File

@ -1,22 +0,0 @@
using System;
namespace YooAsset.Editor
{
public enum ETaskPipeline
{
/// <summary>
/// 所有的构建管线
/// </summary>
AllPipeline,
/// <summary>
/// 内置构建管线
/// </summary>
BuiltinBuildPipeline,
/// <summary>
/// 可编程构建管线
/// </summary>
ScriptableBuildPipeline,
}
}

View File

@ -5,28 +5,13 @@ namespace YooAsset.Editor
[AttributeUsage(AttributeTargets.Class)]
public class TaskAttribute : Attribute
{
/// <summary>
/// 任务所属的构建流水线
/// </summary>
public ETaskPipeline Pipeline;
/// <summary>
/// 执行顺序
/// </summary>
public int TaskOrder;
/// <summary>
/// 任务说明
/// </summary>
public string TaskDesc;
// 关联的任务类
public Type ClassType { set; get; }
public TaskAttribute(ETaskPipeline pipeline, int taskOrder, string taskDesc)
public TaskAttribute(string taskDesc)
{
Pipeline = pipeline;
TaskOrder = taskOrder;
TaskDesc = taskDesc;
}
}

View File

@ -0,0 +1,68 @@
using System.Collections.Generic;
using UnityEditor.Build.Content;
using UnityEngine.U2D;
using UnityEditor.Build.Pipeline.Injector;
using UnityEditor.Build.Pipeline.Interfaces;
using UnityEngine;
using System.Linq;
namespace UnityEditor.Build.Pipeline.Tasks
{
/// <summary>
/// Ref https://zhuanlan.zhihu.com/p/586918159
/// </summary>
public class RemoveSpriteAtlasRedundancy : IBuildTask
{
public int Version => 1;
[InjectContext]
IBundleWriteData writeDataParam;
public ReturnCode Run()
{
#if UNITY_2020_3_OR_NEWER
BundleWriteData writeData = (BundleWriteData)writeDataParam;
// 图集引用的精灵图片集合
HashSet<GUID> spriteGuids = new HashSet<GUID>();
foreach (var pair in writeData.FileToObjects)
{
foreach (ObjectIdentifier objectIdentifier in pair.Value)
{
var assetPath = AssetDatabase.GUIDToAssetPath(objectIdentifier.guid);
var assetType = AssetDatabase.GetMainAssetTypeAtPath(assetPath);
if (assetType == typeof(SpriteAtlas))
{
var spritePaths = AssetDatabase.GetDependencies(assetPath, false);
foreach (string spritePath in spritePaths)
{
GUID spriteGuild = AssetDatabase.GUIDFromAssetPath(spritePath);
spriteGuids.Add(spriteGuild);
}
}
}
}
// 移除图集引用的精力图片对象
foreach (var pair in writeData.FileToObjects)
{
List<ObjectIdentifier> objectIdentifiers = pair.Value;
for (int i = objectIdentifiers.Count - 1; i >= 0; i--)
{
ObjectIdentifier objectIdentifier = objectIdentifiers[i];
if (spriteGuids.Contains(objectIdentifier.guid))
{
if (objectIdentifier.localIdentifierInFile == 2800000)
{
// 删除图集散图的冗余纹理
objectIdentifiers.RemoveAt(i);
}
}
}
}
#endif
return ReturnCode.Success;
}
}
}

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 32477ef3a448a9144aa1574a052fe54e
guid: f01d5c82be95c8f4b93aeefc0454ae5c
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@ -9,10 +9,10 @@ namespace UnityEditor.Build.Pipeline.Tasks
{
public static class SBPBuildTasks
{
public static IList<IBuildTask> Create(string builtInShaderBundleName)
public static IList<IBuildTask> Create(bool fixSpriteAtlasRedundancy, string builtInShaderBundleName)
{
var buildTasks = new List<IBuildTask>();
// Setup
buildTasks.Add(new SwitchToBuildPlatform());
buildTasks.Add(new RebuildSpriteAtlasCache());
@ -33,6 +33,8 @@ namespace UnityEditor.Build.Pipeline.Tasks
// Packing
buildTasks.Add(new GenerateBundlePacking());
if (fixSpriteAtlasRedundancy)
buildTasks.Add(new RemoveSpriteAtlasRedundancy());
buildTasks.Add(new UpdateBundleObjectLayout());
buildTasks.Add(new GenerateBundleCommands());
buildTasks.Add(new GenerateSubAssetPathMaps());

View File

@ -7,7 +7,7 @@ using UnityEngine;
namespace YooAsset.Editor
{
[TaskAttribute(ETaskPipeline.BuiltinBuildPipeline, 300, "资源构建内容打包")]
[TaskAttribute("资源构建内容打包")]
public class TaskBuilding : IBuildTask
{
public class BuildResultContext : IContextObject

View File

@ -9,7 +9,7 @@ using UnityEditor.Build.Pipeline.Tasks;
namespace YooAsset.Editor
{
[TaskAttribute(ETaskPipeline.ScriptableBuildPipeline, 300, "资源构建内容打包")]
[TaskAttribute("资源构建内容打包")]
public class TaskBuilding_SBP : IBuildTask
{
public class BuildResultContext : IContextObject
@ -33,7 +33,7 @@ namespace YooAsset.Editor
// 开始构建
IBundleBuildResults buildResults;
var buildParameters = buildParametersContext.GetSBPBuildParameters();
var taskList = SBPBuildTasks.Create(buildMapContext.Command.ShadersBundleName);
var taskList = SBPBuildTasks.Create(buildParametersContext.Parameters.SBPParameters.FixSpriteAtlasRedundancy, buildMapContext.Command.ShadersBundleName);
ReturnCode exitCode = ContentPipeline.BuildAssetBundles(buildParameters, buildContent, out buildResults, taskList);
if (exitCode < 0)
{

View File

@ -6,7 +6,7 @@ using UnityEngine;
namespace YooAsset.Editor
{
[TaskAttribute(ETaskPipeline.AllPipeline, 1100, "拷贝内置文件到流目录")]
[TaskAttribute("拷贝内置文件到流目录")]
public class TaskCopyBuildinFiles : IBuildTask
{
void IBuildTask.Run(BuildContext context)
@ -30,7 +30,7 @@ namespace YooAsset.Editor
{
ECopyBuildinFileOption option = buildParametersContext.Parameters.CopyBuildinFileOption;
string packageOutputDirectory = buildParametersContext.GetPackageOutputDirectory();
string streamingAssetsDirectory = AssetBundleBuilderHelper.GetStreamingAssetsFolderPath();
string streamingAssetsDirectory = buildParametersContext.GetStreamingAssetsDirectory();
string buildPackageName = buildParametersContext.Parameters.PackageName;
string buildPackageVersion = buildParametersContext.Parameters.PackageVersion;
@ -40,7 +40,7 @@ namespace YooAsset.Editor
// 清空流目录
if (option == ECopyBuildinFileOption.ClearAndCopyAll || option == ECopyBuildinFileOption.ClearAndCopyByTags)
{
AssetBundleBuilderHelper.ClearStreamingAssetsFolder();
EditorTools.ClearFolder(streamingAssetsDirectory);
}
// 拷贝补丁清单文件

View File

@ -5,7 +5,7 @@ using System.Collections.Generic;
namespace YooAsset.Editor
{
[TaskAttribute(ETaskPipeline.AllPipeline, 400, "拷贝原生文件")]
[TaskAttribute("拷贝原生文件")]
public class TaskCopyRawFile : IBuildTask
{
void IBuildTask.Run(BuildContext context)

View File

@ -13,7 +13,7 @@ namespace YooAsset.Editor
internal PackageManifest Manifest;
}
[TaskAttribute(ETaskPipeline.AllPipeline, 800, "创建清单文件")]
[TaskAttribute("创建清单文件")]
public class TaskCreateManifest : IBuildTask
{
void IBuildTask.Run(BuildContext context)
@ -40,7 +40,12 @@ namespace YooAsset.Editor
manifest.OutputNameStyle = (int)buildParameters.OutputNameStyle;
manifest.PackageName = buildParameters.PackageName;
manifest.PackageVersion = buildParameters.PackageVersion;
// 填充资源包集合
manifest.BundleList = GetAllPackageBundle(context);
CacheBundleIDs(manifest);
// 填充主资源集合
manifest.AssetList = GetAllPackageAsset(context, manifest);
// 更新Unity内置资源包的引用关系
@ -147,7 +152,7 @@ namespace YooAsset.Editor
packageAsset.AssetPath = assetInfo.AssetPath;
packageAsset.AssetGUID = buildMapContext.Command.IncludeAssetGUID ? assetInfo.AssetGUID : string.Empty;
packageAsset.AssetTags = assetInfo.AssetTags.ToArray();
packageAsset.BundleID = GetAssetBundleID(assetInfo.BundleName, manifest);
packageAsset.BundleID = GetCachedBundleID(assetInfo.BundleName);
packageAsset.DependIDs = GetAssetBundleDependIDs(packageAsset.BundleID, assetInfo, manifest);
result.Add(packageAsset);
}
@ -156,12 +161,12 @@ namespace YooAsset.Editor
}
private int[] GetAssetBundleDependIDs(int mainBundleID, BuildAssetInfo assetInfo, PackageManifest manifest)
{
List<int> result = new List<int>();
HashSet<int> result = new HashSet<int>();
foreach (var dependAssetInfo in assetInfo.AllDependAssetInfos)
{
if (dependAssetInfo.HasBundleName())
{
int bundleID = GetAssetBundleID(dependAssetInfo.BundleName, manifest);
int bundleID = GetCachedBundleID(dependAssetInfo.BundleName);
if (mainBundleID != bundleID)
{
if (result.Contains(bundleID) == false)
@ -171,15 +176,6 @@ namespace YooAsset.Editor
}
return result.ToArray();
}
private int GetAssetBundleID(string bundleName, PackageManifest manifest)
{
for (int index = 0; index < manifest.BundleList.Count; index++)
{
if (manifest.BundleList[index].BundleName == bundleName)
return index;
}
throw new Exception($"Not found bundle name : {bundleName}");
}
/// <summary>
/// 更新Unity内置资源包的引用关系
@ -212,7 +208,7 @@ namespace YooAsset.Editor
List<string> conflictAssetPathList = dependBundles.Intersect(shaderBundleReferenceList).ToList();
if (conflictAssetPathList.Count > 0)
{
List<int> newDependIDs = new List<int>(packageAsset.DependIDs);
HashSet<int> newDependIDs = new HashSet<int>(packageAsset.DependIDs);
if (newDependIDs.Contains(shaderBundleId) == false)
newDependIDs.Add(shaderBundleId);
packageAsset.DependIDs = newDependIDs.ToArray();
@ -226,7 +222,7 @@ namespace YooAsset.Editor
// 更新资源包标签
var packageBundle = manifest.BundleList[shaderBundleId];
List<string> newTags = new List<string>(packageBundle.Tags);
HashSet<string> newTags = new HashSet<string>(packageBundle.Tags);
foreach (var tag in tagTemps)
{
if (newTags.Contains(tag) == false)
@ -250,23 +246,22 @@ namespace YooAsset.Editor
#region 资源包引用关系相关
private readonly Dictionary<string, int> _cachedBundleID = new Dictionary<string, int>(10000);
private readonly Dictionary<string, string[]> _cachedBundleDepends = new Dictionary<string, string[]>(10000);
private void CacheBundleIDs(PackageManifest manifest)
{
UnityEngine.Debug.Assert(manifest.BundleList.Count != 0, "Manifest bundle list is empty !");
for (int index = 0; index < manifest.BundleList.Count; index++)
{
string bundleName = manifest.BundleList[index].BundleName;
_cachedBundleID.Add(bundleName, index);
}
}
private void UpdateScriptPipelineReference(PackageManifest manifest, TaskBuilding_SBP.BuildResultContext buildResultContext)
{
int progressValue;
int totalCount = manifest.BundleList.Count;
// 缓存资源包ID
_cachedBundleID.Clear();
progressValue = 0;
foreach (var packageBundle in manifest.BundleList)
{
int bundleID = GetAssetBundleID(packageBundle.BundleName, manifest);
_cachedBundleID.Add(packageBundle.BundleName, bundleID);
EditorTools.DisplayProgressBar("缓存资源包索引", ++progressValue, totalCount);
}
EditorTools.ClearProgressBar();
// 缓存资源包依赖
_cachedBundleDepends.Clear();
progressValue = 0;
@ -283,7 +278,11 @@ namespace YooAsset.Editor
var depends = buildResultContext.Results.BundleInfos[packageBundle.BundleName].Dependencies;
_cachedBundleDepends.Add(packageBundle.BundleName, depends);
EditorTools.DisplayProgressBar("缓存资源包依赖列表", ++progressValue, totalCount);
int pro = ++progressValue;
if (pro % 100 == 0)
{
EditorTools.DisplayProgressBar("缓存资源包依赖列表", pro, totalCount);
}
}
EditorTools.ClearProgressBar();
@ -291,7 +290,11 @@ namespace YooAsset.Editor
foreach (var packageBundle in manifest.BundleList)
{
packageBundle.ReferenceIDs = GetBundleRefrenceIDs(manifest, packageBundle);
EditorTools.DisplayProgressBar("计算资源包引用关系", ++progressValue, totalCount);
int pro = ++progressValue;
if (pro % 100 == 0)
{
EditorTools.DisplayProgressBar("计算资源包引用关系", pro, totalCount);
}
}
EditorTools.ClearProgressBar();
}
@ -300,17 +303,6 @@ namespace YooAsset.Editor
int progressValue;
int totalCount = manifest.BundleList.Count;
// 缓存资源包ID
_cachedBundleID.Clear();
progressValue = 0;
foreach (var packageBundle in manifest.BundleList)
{
int bundleID = GetAssetBundleID(packageBundle.BundleName, manifest);
_cachedBundleID.Add(packageBundle.BundleName, bundleID);
EditorTools.DisplayProgressBar("缓存资源包索引", ++progressValue, totalCount);
}
EditorTools.ClearProgressBar();
// 缓存资源包依赖
_cachedBundleDepends.Clear();
progressValue = 0;
@ -324,7 +316,11 @@ namespace YooAsset.Editor
var depends = buildResultContext.UnityManifest.GetDirectDependencies(packageBundle.BundleName);
_cachedBundleDepends.Add(packageBundle.BundleName, depends);
EditorTools.DisplayProgressBar("缓存资源包依赖列表", ++progressValue, totalCount);
int pro = ++progressValue;
if (pro % 100 == 0)
{
EditorTools.DisplayProgressBar("缓存资源包依赖列表", pro, totalCount);
}
}
EditorTools.ClearProgressBar();
@ -333,7 +329,11 @@ namespace YooAsset.Editor
foreach (var packageBundle in manifest.BundleList)
{
packageBundle.ReferenceIDs = GetBundleRefrenceIDs(manifest, packageBundle);
EditorTools.DisplayProgressBar("计算资源包引用关系", ++progressValue, totalCount);
int pro = ++progressValue;
if (pro % 100 == 0)
{
EditorTools.DisplayProgressBar("计算资源包引用关系", ++progressValue, totalCount);
}
}
EditorTools.ClearProgressBar();
}
@ -354,7 +354,7 @@ namespace YooAsset.Editor
}
}
List<int> result = new List<int>();
HashSet<int> result = new HashSet<int>();
foreach (var bundleName in referenceList)
{
int bundleID = GetCachedBundleID(bundleName);

View File

@ -3,7 +3,7 @@ using System.Collections.Generic;
namespace YooAsset.Editor
{
[TaskAttribute(ETaskPipeline.AllPipeline, 1000, "制作包裹")]
[TaskAttribute("制作包裹")]
public class TaskCreatePackage : IBuildTask
{
void IBuildTask.Run(BuildContext context)
@ -70,7 +70,7 @@ namespace YooAsset.Editor
int fileTotalCount = buildMapContext.Collection.Count;
foreach (var bundleInfo in buildMapContext.Collection)
{
EditorTools.CopyFile(bundleInfo.BundleInfo.BuildOutputFilePath, bundleInfo.BundleInfo.PackageOutputFilePath, true);
EditorTools.CopyFile(bundleInfo.PackageSourceFilePath, bundleInfo.PackageDestFilePath, true);
EditorTools.DisplayProgressBar("拷贝补丁文件", ++progressValue, fileTotalCount);
}
EditorTools.ClearProgressBar();

View File

@ -6,7 +6,7 @@ using UnityEditor;
namespace YooAsset.Editor
{
[TaskAttribute(ETaskPipeline.AllPipeline, 900, "创建构建报告文件")]
[TaskAttribute("创建构建报告文件")]
public class TaskCreateReport : IBuildTask
{
void IBuildTask.Run(BuildContext context)

View File

@ -6,7 +6,7 @@ using System.Collections.Generic;
namespace YooAsset.Editor
{
[TaskAttribute(ETaskPipeline.AllPipeline, 600, "资源包加密")]
[TaskAttribute("资源包加密")]
public class TaskEncryption : IBuildTask
{
void IBuildTask.Run(BuildContext context)

View File

@ -7,7 +7,7 @@ using UnityEditor;
namespace YooAsset.Editor
{
[TaskAttribute(ETaskPipeline.AllPipeline, 200, "获取资源构建内容")]
[TaskAttribute("获取资源构建内容")]
public class TaskGetBuildMap : IBuildTask
{
void IBuildTask.Run(BuildContext context)
@ -33,7 +33,7 @@ namespace YooAsset.Editor
Dictionary<string, BuildAssetInfo> allBuildAssetInfoDic = new Dictionary<string, BuildAssetInfo>(1000);
// 1. 检测配置合法性
AssetBundleCollectorSettingData.Setting.CheckConfigError();
AssetBundleCollectorSettingData.Setting.CheckPackageConfigError(packageName);
// 2. 获取所有收集器收集的资源
var collectResult = AssetBundleCollectorSettingData.Setting.GetPackageAssets(buildMode, packageName);
@ -147,17 +147,17 @@ namespace YooAsset.Editor
private void RemoveZeroReferenceAssets(List<CollectAssetInfo> allCollectAssetInfos)
{
// 1. 检测是否任何存在依赖资源
bool hasAnyDependAsset = false;
bool hasAnyDependCollector = false;
foreach (var collectAssetInfo in allCollectAssetInfos)
{
var collectorType = collectAssetInfo.CollectorType;
if (collectorType == ECollectorType.DependAssetCollector)
{
hasAnyDependAsset = true;
hasAnyDependCollector = true;
break;
}
}
if (hasAnyDependAsset == false)
if (hasAnyDependCollector == false)
return;
// 2. 获取所有主资源的依赖资源集合

View File

@ -6,7 +6,7 @@ using UnityEditor;
namespace YooAsset.Editor
{
[TaskAttribute(ETaskPipeline.AllPipeline, 100, "资源构建准备工作")]
[TaskAttribute("资源构建准备工作")]
public class TaskPrepare : IBuildTask
{
void IBuildTask.Run(BuildContext context)
@ -16,11 +16,27 @@ namespace YooAsset.Editor
// 检测构建参数合法性
if (buildParameters.BuildTarget == BuildTarget.NoTarget)
throw new Exception("请选择目标平台");
throw new Exception("请选择目标平台");
if (string.IsNullOrEmpty(buildParameters.PackageName))
throw new Exception("包裹名称不能为空");
throw new Exception("包裹名称不能为空");
if (string.IsNullOrEmpty(buildParameters.PackageVersion))
throw new Exception("包裹版本不能为空");
throw new Exception("包裹版本不能为空!");
if (string.IsNullOrEmpty(buildParameters.BuildOutputRoot))
throw new Exception("构建输出的根目录为空!");
if (string.IsNullOrEmpty(buildParameters.StreamingAssetsRoot))
throw new Exception("内置资源根目录为空!");
if (buildParameters.BuildPipeline == EBuildPipeline.ScriptableBuildPipeline)
{
if (buildParameters.SBPParameters == null)
throw new Exception($"{nameof(BuildParameters.SBPParameters)} is null !");
if (buildParameters.BuildMode == EBuildMode.DryRunBuild)
throw new Exception($"{nameof(EBuildPipeline.ScriptableBuildPipeline)} not support {nameof(EBuildMode.DryRunBuild)} build mode !");
if (buildParameters.BuildMode == EBuildMode.ForceRebuild)
throw new Exception($"{nameof(EBuildPipeline.ScriptableBuildPipeline)} not support {nameof(EBuildMode.ForceRebuild)} build mode !");
}
if (buildParameters.BuildMode != EBuildMode.SimulateBuild)
{
@ -72,11 +88,10 @@ namespace YooAsset.Editor
if (buildParameters.BuildMode == EBuildMode.ForceRebuild)
{
// 删除总目录
string platformDirectory = $"{buildParameters.OutputRoot}/{buildParameters.BuildTarget}/{buildParameters.PackageName}";
if (EditorTools.DeleteDirectory(platformDirectory))
string packageRootDirectory = buildParametersContext.GetPackageRootDirectory();
if (EditorTools.DeleteDirectory(packageRootDirectory))
{
BuildLogger.Log($"删除平台总目录:{platformDirectory}");
BuildLogger.Log($"删除包裹目录:{packageRootDirectory}");
}
}

View File

@ -1,12 +1,13 @@
using System;
using System.IO;
using System.Text;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
namespace YooAsset.Editor
{
[TaskAttribute(ETaskPipeline.AllPipeline, 700, "更新资源包信息")]
[TaskAttribute("更新资源包信息")]
public class TaskUpdateBundleInfo : IBuildTask
{
void IBuildTask.Run(BuildContext context)
@ -29,32 +30,35 @@ namespace YooAsset.Editor
// 2.更新构建输出的文件路径
foreach (var bundleInfo in buildMapContext.Collection)
{
bundleInfo.BuildOutputFilePath = $"{pipelineOutputDirectory}/{bundleInfo.BundleName}";
if (bundleInfo.IsEncryptedFile)
bundleInfo.BundleInfo.BuildOutputFilePath = bundleInfo.EncryptedFilePath;
bundleInfo.PackageSourceFilePath = bundleInfo.EncryptedFilePath;
else
bundleInfo.BundleInfo.BuildOutputFilePath = $"{pipelineOutputDirectory}/{bundleInfo.BundleName}";
bundleInfo.PackageSourceFilePath = bundleInfo.BuildOutputFilePath;
}
// 3.更新文件其它信息
foreach (var bundleInfo in buildMapContext.Collection)
{
string buildOutputFilePath = bundleInfo.BundleInfo.BuildOutputFilePath;
bundleInfo.BundleInfo.ContentHash = GetBundleContentHash(bundleInfo, context);
bundleInfo.BundleInfo.FileHash = GetBundleFileHash(buildOutputFilePath, buildParametersContext);
bundleInfo.BundleInfo.FileCRC = GetBundleFileCRC(buildOutputFilePath, buildParametersContext);
bundleInfo.BundleInfo.FileSize = GetBundleFileSize(buildOutputFilePath, buildParametersContext);
bundleInfo.PackageUnityHash = GetUnityHash(bundleInfo, context);
bundleInfo.PackageUnityCRC = GetUnityCRC(bundleInfo, context);
bundleInfo.PackageFileHash = GetBundleFileHash(bundleInfo.PackageSourceFilePath, buildParametersContext);
bundleInfo.PackageFileCRC = GetBundleFileCRC(bundleInfo.PackageSourceFilePath, buildParametersContext);
bundleInfo.PackageFileSize = GetBundleFileSize(bundleInfo.PackageSourceFilePath, buildParametersContext);
}
// 4.更新补丁包输出的文件路径
foreach (var bundleInfo in buildMapContext.Collection)
{
string fileExtension = ManifestTools.GetRemoteBundleFileExtension(bundleInfo.BundleName);
string fileName = ManifestTools.GetRemoteBundleFileName(outputNameStyle, bundleInfo.BundleName, fileExtension, bundleInfo.BundleInfo.FileHash);
bundleInfo.BundleInfo.PackageOutputFilePath = $"{packageOutputDirectory}/{fileName}";
string bundleName = bundleInfo.BundleName;
string fileHash = bundleInfo.PackageFileHash;
string fileExtension = ManifestTools.GetRemoteBundleFileExtension(bundleName);
string fileName = ManifestTools.GetRemoteBundleFileName(outputNameStyle, bundleName, fileExtension, fileHash);
bundleInfo.PackageDestFilePath = $"{packageOutputDirectory}/{fileName}";
}
}
private string GetBundleContentHash(BuildBundleInfo bundleInfo, BuildContext context)
private string GetUnityHash(BuildBundleInfo bundleInfo, BuildContext context)
{
var buildParametersContext = context.GetContextObject<BuildParametersContext>();
var parameters = buildParametersContext.Parameters;
@ -64,7 +68,7 @@ namespace YooAsset.Editor
if (bundleInfo.IsRawFile)
{
string filePath = bundleInfo.BundleInfo.BuildOutputFilePath;
string filePath = bundleInfo.PackageSourceFilePath;
return HashUtility.FileMD5(filePath);
}
@ -75,7 +79,7 @@ namespace YooAsset.Editor
if (hash.isValid)
return hash.ToString();
else
throw new Exception($"Not found bundle in build result : {bundleInfo.BundleName}");
throw new Exception($"Not found bundle hash in build result : {bundleInfo.BundleName}");
}
else if (parameters.BuildPipeline == EBuildPipeline.ScriptableBuildPipeline)
{
@ -84,7 +88,39 @@ namespace YooAsset.Editor
if (buildResult.Results.BundleInfos.TryGetValue(bundleInfo.BundleName, out var value))
return value.Hash.ToString();
else
throw new Exception($"Not found bundle in build result : {bundleInfo.BundleName}");
throw new Exception($"Not found bundle hash in build result : {bundleInfo.BundleName}");
}
else
{
throw new System.NotImplementedException();
}
}
private uint GetUnityCRC(BuildBundleInfo bundleInfo, BuildContext context)
{
var buildParametersContext = context.GetContextObject<BuildParametersContext>();
var parameters = buildParametersContext.Parameters;
var buildMode = parameters.BuildMode;
if (buildMode == EBuildMode.DryRunBuild || buildMode == EBuildMode.SimulateBuild)
return 0;
if (bundleInfo.IsRawFile)
return 0;
if (parameters.BuildPipeline == EBuildPipeline.BuiltinBuildPipeline)
{
string filePath = bundleInfo.BuildOutputFilePath;
if (BuildPipeline.GetCRCForAssetBundle(filePath, out uint crc))
return crc;
else
throw new Exception($"Not found bundle crc in build result : {bundleInfo.BundleName}");
}
else if (parameters.BuildPipeline == EBuildPipeline.ScriptableBuildPipeline)
{
var buildResult = context.GetContextObject<TaskBuilding_SBP.BuildResultContext>();
if (buildResult.Results.BundleInfos.TryGetValue(bundleInfo.BundleName, out var value))
return value.Crc;
else
throw new Exception($"Not found bundle crc in build result : {bundleInfo.BundleName}");
}
else
{
@ -95,7 +131,7 @@ namespace YooAsset.Editor
{
var buildMode = buildParametersContext.Parameters.BuildMode;
if (buildMode == EBuildMode.DryRunBuild || buildMode == EBuildMode.SimulateBuild)
return "00000000000000000000000000000000"; //32位
return GetFilePathTempHash(filePath);
else
return HashUtility.FileMD5(filePath);
}
@ -115,5 +151,32 @@ namespace YooAsset.Editor
else
return FileUtility.GetFileSize(filePath);
}
protected string GetFilePathTempHash(string filePath)
{
byte[] bytes = Encoding.UTF8.GetBytes(filePath);
return HashUtility.BytesMD5(bytes);
// 注意:在文件路径的哈希值冲突的情况下,可以使用下面的方法
//return $"{HashUtility.BytesMD5(bytes)}-{Guid.NewGuid():N}";
}
protected long GetBundleTempSize(BuildBundleInfo bundleInfo)
{
long tempSize = 0;
var assetPaths = bundleInfo.GetAllMainAssetPaths();
foreach (var assetPath in assetPaths)
{
long size = FileUtility.GetFileSize(assetPath);
tempSize += size;
}
if (tempSize == 0)
{
string message = $"Bundle temp size is zero, check bundle main asset list : {bundleInfo.BundleName}";
throw new Exception(message);
}
return tempSize;
}
}
}

View File

@ -8,7 +8,7 @@ using UnityEngine;
namespace YooAsset.Editor
{
[TaskAttribute(ETaskPipeline.BuiltinBuildPipeline, 500, "验证构建结果")]
[TaskAttribute("验证构建结果")]
public class TaskVerifyBuildResult : IBuildTask
{
void IBuildTask.Run(BuildContext context)

View File

@ -9,7 +9,7 @@ using UnityEditor.Build.Pipeline.Interfaces;
namespace YooAsset.Editor
{
[TaskAttribute(ETaskPipeline.ScriptableBuildPipeline, 500, "验证构建结果")]
[TaskAttribute("验证构建结果")]
public class TaskVerifyBuildResult_SBP : IBuildTask
{
void IBuildTask.Run(BuildContext context)

View File

@ -166,7 +166,7 @@ namespace YooAsset.Editor
string[] findAssets = EditorTools.FindAssets(EAssetSearchType.All, collectDirectory);
foreach (string assetPath in findAssets)
{
if (IsValidateAsset(assetPath, isRawFilePackRule) && IsCollectAsset(assetPath))
if (IsValidateAsset(assetPath, isRawFilePackRule) && IsCollectAsset(group, assetPath))
{
if (result.ContainsKey(assetPath) == false)
{
@ -183,7 +183,7 @@ namespace YooAsset.Editor
else
{
string assetPath = CollectPath;
if (IsValidateAsset(assetPath, isRawFilePackRule) && IsCollectAsset(assetPath))
if (IsValidateAsset(assetPath, isRawFilePackRule) && IsCollectAsset(group, assetPath))
{
var collectAssetInfo = CreateCollectAssetInfo(command, group, assetPath, isRawFilePackRule);
result.Add(assetPath, collectAssetInfo);
@ -204,6 +204,12 @@ namespace YooAsset.Editor
{
string address = collectInfoPair.Value.Address;
string assetPath = collectInfoPair.Value.AssetPath;
if (string.IsNullOrEmpty(address))
continue;
if (address.StartsWith("Assets/") || address.StartsWith("assets/"))
throw new Exception($"The address can not set asset path in collector : {CollectPath} \nAssetPath: {assetPath}");
if (addressTemper.TryGetValue(address, out var existed) == false)
addressTemper.Add(address, assetPath);
else
@ -245,7 +251,7 @@ namespace YooAsset.Editor
// 忽略编辑器下的类型资源
Type assetType = AssetDatabase.GetMainAssetTypeAtPath(assetPath);
if (assetType == typeof(LightingDataAsset))
if (assetType == typeof(LightingDataAsset) || assetType == typeof(LightmapParameters))
return false;
// 检测原生文件是否合规
@ -288,11 +294,11 @@ namespace YooAsset.Editor
return true;
}
private bool IsCollectAsset(string assetPath)
private bool IsCollectAsset(AssetBundleCollectorGroup group, string assetPath)
{
// 根据规则设置过滤资源文件
IFilterRule filterRuleInstance = AssetBundleCollectorSettingData.GetFilterRuleInstance(FilterRuleName);
return filterRuleInstance.IsCollectAsset(new FilterRuleData(assetPath));
return filterRuleInstance.IsCollectAsset(new FilterRuleData(assetPath, CollectPath, group.GroupName, UserData));
}
private string GetAddress(CollectCommand command, AssetBundleCollectorGroup group, string assetPath)
{
@ -336,11 +342,13 @@ namespace YooAsset.Editor
List<string> result = new List<string>(depends.Length);
foreach (string assetPath in depends)
{
// 注意:排除主资源对象
if (assetPath == mainAssetPath)
continue;
if (IsValidateAsset(assetPath, false))
{
// 注意:排除主资源对象
if (assetPath != mainAssetPath)
result.Add(assetPath);
result.Add(assetPath);
}
}
return result;

View File

@ -43,7 +43,10 @@ namespace YooAsset.Editor
{
if (AssetBundleCollectorSettingData.HasActiveRuleName(ActiveRuleName) == false)
throw new Exception($"Invalid {nameof(IActiveRule)} class type : {ActiveRuleName} in group : {GroupName}");
// 当分组不是激活状态时,直接不进行检测
if (ActiveRuleName == nameof(DisableGroup)) return;
foreach (var collector in Collectors)
{
collector.CheckConfigError();
@ -103,6 +106,9 @@ namespace YooAsset.Editor
{
string address = collectInfoPair.Value.Address;
string assetPath = collectInfoPair.Value.AssetPath;
if (string.IsNullOrEmpty(address))
continue;
if (addressTemper.TryGetValue(address, out var existed) == false)
addressTemper.Add(address, assetPath);
else

View File

@ -83,6 +83,9 @@ namespace YooAsset.Editor
{
string address = collectInfoPair.Value.Address;
string assetPath = collectInfoPair.Value.AssetPath;
if (string.IsNullOrEmpty(address))
continue;
if (addressTemper.TryGetValue(address, out var existed) == false)
addressTemper.Add(address, assetPath);
else

View File

@ -61,9 +61,18 @@ namespace YooAsset.Editor
}
/// <summary>
/// 检测配置错误
/// 检测包裹配置错误
/// </summary>
public void CheckConfigError()
public void CheckPackageConfigError(string packageName)
{
var package = GetPackage(packageName);
package.CheckConfigError();
}
/// <summary>
/// 检测所有配置错误
/// </summary>
public void CheckAllPackageConfigError()
{
foreach (var package in Packages)
{
@ -72,9 +81,9 @@ namespace YooAsset.Editor
}
/// <summary>
/// 修复配置错误
/// 修复所有配置错误
/// </summary>
public bool FixConfigError()
public bool FixAllPackageConfigError()
{
bool isFixed = false;
foreach (var package in Packages)
@ -92,16 +101,8 @@ namespace YooAsset.Editor
/// </summary>
public List<string> GetPackageAllTags(string packageName)
{
foreach (var package in Packages)
{
if (package.PackageName == packageName)
{
return package.GetAllTags();
}
}
Debug.LogWarning($"Not found package : {packageName}");
return new List<string>();
var package = GetPackage(packageName);
return package.GetAllTags();
}
/// <summary>
@ -110,21 +111,27 @@ namespace YooAsset.Editor
public CollectResult GetPackageAssets(EBuildMode buildMode, string packageName)
{
if (string.IsNullOrEmpty(packageName))
throw new Exception("Build package name is null or mepty !");
throw new Exception("Build package name is null or empty !");
var package = GetPackage(packageName);
CollectCommand command = new CollectCommand(buildMode, packageName,
EnableAddressable, LocationToLower, IncludeAssetGUID, UniqueBundleName);
CollectResult collectResult = new CollectResult(command);
collectResult.SetCollectAssets(package.GetAllCollectAssets(command));
return collectResult;
}
/// <summary>
/// 获取包裹类
/// </summary>
public AssetBundleCollectorPackage GetPackage(string packageName)
{
foreach (var package in Packages)
{
if (package.PackageName == packageName)
{
CollectCommand command = new CollectCommand(buildMode, packageName,
EnableAddressable, LocationToLower, IncludeAssetGUID, UniqueBundleName);
CollectResult collectResult = new CollectResult(command);
collectResult.SetCollectAssets(package.GetAllCollectAssets(command));
return collectResult;
}
return package;
}
throw new Exception($"Not found collector pacakge : {packageName}");
throw new Exception($"Not found package : {packageName}");
}
}
}

View File

@ -94,7 +94,8 @@ namespace YooAsset.Editor
typeof(AddressByFileName),
typeof(AddressByFilePath),
typeof(AddressByFolderAndFileName),
typeof(AddressByGroupAndFileName)
typeof(AddressByGroupAndFileName),
typeof(AddressDisable)
};
var customTypes = EditorTools.GetAssignableTypes(typeof(IAddressRule));
@ -161,7 +162,7 @@ namespace YooAsset.Editor
/// </summary>
public static void FixFile()
{
bool isFixed = Setting.FixConfigError();
bool isFixed = Setting.FixAllPackageConfigError();
if (isFixed)
{
IsDirty = true;

View File

@ -26,6 +26,7 @@ namespace YooAsset.Editor
private List<RuleDisplayName> _filterRuleList;
private Button _settingsButton;
private VisualElement _helpBoxContainer;
private VisualElement _setting1Container;
private VisualElement _setting2Container;
private Toggle _showPackageToogle;
@ -82,6 +83,9 @@ namespace YooAsset.Editor
visualAsset.CloneTree(root);
// 警示栏
_helpBoxContainer = root.Q("HelpBoxContainer");
// 公共设置相关
_settingsButton = root.Q<Button>("SettingsButton");
_settingsButton.clicked += SettingsBtn_clicked;
@ -328,6 +332,26 @@ namespace YooAsset.Editor
_uniqueBundleNameToogle.SetValueWithoutNotify(AssetBundleCollectorSettingData.Setting.UniqueBundleName);
_showEditorAliasToggle.SetValueWithoutNotify(AssetBundleCollectorSettingData.Setting.ShowEditorAlias);
// 警示框
#if UNITY_2020_3_OR_NEWER
_helpBoxContainer.Clear();
if (_enableAddressableToogle.value && _locationToLowerToogle.value)
{
var helpBox = new HelpBox("无法同时开启[Enable Addressable]选项和[Location To Lower]选项", HelpBoxMessageType.Error);
_helpBoxContainer.Add(helpBox);
}
if (AssetBundleCollectorSettingData.Setting.Packages.Count > 1 && _uniqueBundleNameToogle.value == false)
{
var helpBox = new HelpBox("检测到当前配置存在多个Package建议开启[Unique Bundle Name]选项", HelpBoxMessageType.Warning);
_helpBoxContainer.Add(helpBox);
}
if (_helpBoxContainer.childCount > 0)
_helpBoxContainer.style.display = DisplayStyle.Flex;
else
_helpBoxContainer.style.display = DisplayStyle.None;
#endif
// 设置栏
if (_showSettings)
{
_setting1Container.style.display = DisplayStyle.Flex;

View File

@ -1,4 +1,4 @@
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" editor-extension-mode="False">
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" editor-extension-mode="True">
<uie:Toolbar name="Toolbar" style="display: flex; flex-direction: row-reverse;">
<ui:Button text="Save" display-tooltip-when-elided="true" name="SaveButton" style="width: 50px; background-color: rgb(56, 147, 58);" />
<ui:Button text="导出" display-tooltip-when-elided="true" name="ExportButton" style="width: 50px; background-color: rgb(56, 147, 58);" />
@ -6,6 +6,7 @@
<ui:Button text="修复" display-tooltip-when-elided="true" name="FixButton" style="width: 50px; background-color: rgb(56, 147, 58);" />
</uie:Toolbar>
<ui:VisualElement name="PublicContainer" style="background-color: rgb(79, 79, 79); flex-direction: column; 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:Button text="Settings" display-tooltip-when-elided="true" name="SettingsButton" />
<ui:VisualElement name="PublicContainer1" style="flex-direction: row; flex-wrap: nowrap; height: 28px;">
<ui:Toggle label="Show Packages" name="ShowPackages" style="width: 196px; -unity-text-align: middle-left;" />

View File

@ -4,10 +4,16 @@ namespace YooAsset.Editor
public struct FilterRuleData
{
public string AssetPath;
public FilterRuleData(string assetPath)
public string CollectPath;
public string GroupName;
public string UserData;
public FilterRuleData(string assetPath, string collectPath, string groupName, string userData)
{
AssetPath = assetPath;
CollectPath = collectPath;
GroupName = groupName;
UserData = userData;
}
}

View File

@ -8,13 +8,6 @@ namespace YooAsset.Editor
public string GroupName;
public string UserData;
public PackRuleData(string assetPath)
{
AssetPath = assetPath;
CollectPath = string.Empty;
GroupName = string.Empty;
UserData = string.Empty;
}
public PackRuleData(string assetPath, string collectPath, string groupName, string userData)
{
AssetPath = assetPath;
@ -41,7 +34,7 @@ namespace YooAsset.Editor
public string GetMainBundleName(string packageName, bool uniqueBundleName)
{
string fullName;
string bundleName = EditorTools.GetRegularPath(_bundleName).Replace('/', '_').Replace('.', '_').ToLower();
string bundleName = EditorTools.GetRegularPath(_bundleName).Replace('/', '_').Replace('.', '_').Replace(" ", "_").ToLower();
if (uniqueBundleName)
fullName = $"{packageName}_{bundleName}.{_bundleExtension}";
else
@ -59,7 +52,7 @@ namespace YooAsset.Editor
return string.Empty;
string fullName;
string bundleName = EditorTools.GetRegularPath(_bundleName).Replace('/', '_').Replace('.', '_').ToLower();
string bundleName = EditorTools.GetRegularPath(_bundleName).Replace('/', '_').Replace('.', '_').Replace(" ", "_").ToLower();
if (uniqueBundleName)
fullName = $"{packageName}_share_{bundleName}.{_bundleExtension}";
else

View File

@ -2,6 +2,15 @@
namespace YooAsset.Editor
{
[DisplayName("定位地址: 禁用")]
public class AddressDisable : IAddressRule
{
string IAddressRule.GetAssetAddress(AddressRuleData data)
{
return string.Empty;
}
}
[DisplayName("定位地址: 文件名")]
public class AddressByFileName : IAddressRule
{
@ -16,7 +25,7 @@ namespace YooAsset.Editor
{
string IAddressRule.GetAssetAddress(AddressRuleData data)
{
return data.AssetPath;
throw new System.Exception("可寻址模式下已经默认支持通过资源路径加载!");
}
}

View File

@ -349,10 +349,24 @@ namespace YooAsset.Editor
private void FillIncludeListView(ReportBundleInfo bundleInfo)
{
List<ReportAssetInfo> containsList = new List<ReportAssetInfo>();
HashSet<string> mainAssetDic = new HashSet<string>();
foreach (var assetInfo in _buildReport.AssetInfos)
{
if (assetInfo.MainBundleName == bundleInfo.BundleName)
{
mainAssetDic.Add(assetInfo.AssetPath);
containsList.Add(assetInfo);
}
}
foreach (string assetPath in bundleInfo.AllBuiltinAssets)
{
if (mainAssetDic.Contains(assetPath) == false)
{
var assetInfo = new ReportAssetInfo();
assetInfo.AssetPath = assetPath;
assetInfo.AssetGUID = "--";
containsList.Add(assetInfo);
}
}
_includeListView.Clear();
@ -376,6 +390,16 @@ namespace YooAsset.Editor
element.Add(label);
}
{
var label = new Label();
label.name = "Label3";
label.style.unityTextAlign = TextAnchor.MiddleLeft;
label.style.marginLeft = 3f;
//label.style.flexGrow = 1f;
label.style.width = 100;
element.Add(label);
}
{
var label = new Label();
label.name = "Label2";
@ -397,6 +421,10 @@ namespace YooAsset.Editor
var label1 = element.Q<Label>("Label1");
label1.text = assetInfo.AssetPath;
// Asset Source
var label3 = element.Q<Label>("Label3");
label3.text = assetInfo.AssetGUID != "--" ? "Main Asset" : "Builtin Asset";
// GUID
var label2 = element.Q<Label>("Label2");
label2.text = assetInfo.AssetGUID;

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: a0319abb8eae03b4b88e8f900fe2276c
guid: 8875000dff445624da4d6a2d6ef2f446
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@ -12,6 +12,7 @@
<ui:VisualElement name="BottomGroup" style="height: 200px; border-left-width: 1px; border-right-width: 1px; border-top-width: 1px; border-bottom-width: 1px; border-left-color: rgb(0, 0, 0); border-right-color: rgb(0, 0, 0); border-top-color: rgb(0, 0, 0); border-bottom-color: rgb(0, 0, 0); margin-left: 0; margin-right: 0; margin-top: 1px; margin-bottom: 1px; display: flex;">
<uie:Toolbar name="BottomBar" style="height: 25px; margin-left: 1px; margin-right: 1px;">
<uie:ToolbarButton text="Include Assets" display-tooltip-when-elided="true" name="BottomBar1" style="width: 280px; -unity-text-align: middle-left; flex-grow: 1;" />
<uie:ToolbarButton text="Asset Source" display-tooltip-when-elided="true" name="BottomBar3" style="width: 100px; -unity-text-align: middle-left;" />
<uie:ToolbarButton text="GUID" display-tooltip-when-elided="true" name="BottomBar2" style="width: 280px; -unity-text-align: middle-left;" />
</uie:Toolbar>
<ui:ListView focusable="true" name="BottomListView" item-height="18" virtualization-method="DynamicHeight" style="flex-grow: 1;" />

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 56d6dbe0d65ce334a8996beb19612989
guid: cf2a9340bb457594d9bc1f80b84a89f6
ScriptedImporter:
internalIDToNameTable: []
externalObjects: {}

View File

@ -153,7 +153,7 @@ namespace YooAsset.Editor
guids = AssetDatabase.FindAssets($"t:{searchType}", searchInFolders);
// 注意AssetDatabase.FindAssets()可能会获取到重复的资源
List<string> result = new List<string>();
HashSet<string> result = new HashSet<string>();
for (int i = 0; i < guids.Length; i++)
{
string guid = guids[i];

View File

@ -30,17 +30,22 @@ namespace YooAsset.Editor
public class ShaderVariantInfo
{
/// <summary>
/// Shader asset path in editor.
/// 着色器资源路径.
/// </summary>
public string AssetPath;
/// <summary>
/// Shader name.
/// 着色器名称
/// </summary>
public string ShaderName;
/// <summary>
/// Shader variants elements list.
/// 着色器变种总数
/// </summary>
public int ShaderVariantCount = 0;
/// <summary>
/// 着色器变种列表
/// </summary>
public List<ShaderVariantElement> ShaderVariantElements = new List<ShaderVariantElement>(1000);
}
@ -71,6 +76,7 @@ namespace YooAsset.Editor
element.PassType = passType;
element.Keywords = keywords;
info.ShaderVariantElements.Add(element);
info.ShaderVariantCount++;
}
private ShaderVariantInfo GetOrCreateShaderVariantInfo(string assetPath, string shaderName)
{

View File

@ -72,37 +72,18 @@ namespace YooAsset
_isUnloadSafe = false;
for (int i = 0; i < _providerList.Count; i++)
{
var provider = _providerList[i];
if (provider.IsDone)
continue;
provider.Update();
if (IsBusy)
break;
_providerList[i].Update();
}
_isUnloadSafe = true;
}
/// <summary>
/// 销毁
/// </summary>
public void DestroyAll()
{
foreach (var provider in _providerList)
{
provider.Destroy();
}
_providerList.Clear();
_providerDic.Clear();
foreach (var loader in _loaderList)
{
loader.Destroy(true);
}
_loaderList.Clear();
_loaderDic.Clear();
ClearSceneHandle();
DecryptionServices = null;
BundleServices = null;
}
/// <summary>
/// 资源回收(卸载引用计数为零的资源)
/// </summary>
@ -135,7 +116,7 @@ namespace YooAsset
if (loader.CanDestroy())
{
string bundleName = loader.MainBundleInfo.Bundle.BundleName;
loader.Destroy(false);
loader.Destroy();
_loaderList.RemoveAt(i);
_loaderDic.Remove(bundleName);
}
@ -147,13 +128,18 @@ namespace YooAsset
/// </summary>
public void ForceUnloadAllAssets()
{
#if UNITY_WEBGL
throw new Exception($"WebGL not support invoke {nameof(ForceUnloadAllAssets)}");
#else
foreach (var provider in _providerList)
{
provider.WaitForAsyncComplete();
provider.Destroy();
}
foreach (var loader in _loaderList)
{
loader.Destroy(true);
loader.WaitForAsyncComplete();
loader.Destroy();
}
_providerList.Clear();
@ -164,6 +150,7 @@ namespace YooAsset
// 注意:调用底层接口释放所有资源
Resources.UnloadUnusedAssets();
#endif
}
/// <summary>
@ -217,7 +204,7 @@ namespace YooAsset
return completedProvider.CreateHandle<AssetOperationHandle>();
}
string providerGUID = assetInfo.GUID;
string providerGUID = nameof(LoadAssetAsync) + assetInfo.GUID;
ProviderBase provider = TryGetProvider(providerGUID);
if (provider == null)
{
@ -245,7 +232,7 @@ namespace YooAsset
return completedProvider.CreateHandle<SubAssetsOperationHandle>();
}
string providerGUID = assetInfo.GUID;
string providerGUID = nameof(LoadSubAssetsAsync) + assetInfo.GUID;
ProviderBase provider = TryGetProvider(providerGUID);
if (provider == null)
{
@ -273,7 +260,7 @@ namespace YooAsset
return completedProvider.CreateHandle<AllAssetsOperationHandle>();
}
string providerGUID = assetInfo.GUID;
string providerGUID = nameof(LoadAllAssetsAsync) + assetInfo.GUID;
ProviderBase provider = TryGetProvider(providerGUID);
if (provider == null)
{
@ -301,7 +288,7 @@ namespace YooAsset
return completedProvider.CreateHandle<RawFileOperationHandle>();
}
string providerGUID = assetInfo.GUID;
string providerGUID = nameof(LoadRawFileAsync) + assetInfo.GUID;
ProviderBase provider = TryGetProvider(providerGUID);
if (provider == null)
{

View File

@ -44,12 +44,16 @@ namespace YooAsset
{
if (IsValidWithWarning == false)
return EOperationStatus.None;
if (Provider.Status == ProviderBase.EStatus.Failed)
return EOperationStatus.Failed;
else if (Provider.Status == ProviderBase.EStatus.Succeed)
return EOperationStatus.Succeed;
else
var status = Provider.Status;
if (status == ProviderBase.EStatus.None)
return EOperationStatus.None;
else if (status == ProviderBase.EStatus.Succeed)
return EOperationStatus.Succeed;
else if (status == ProviderBase.EStatus.Failed)
return EOperationStatus.Failed;
else
return EOperationStatus.Processing;
}
}

View File

@ -73,9 +73,7 @@ namespace YooAsset
if (IsValidWithWarning == false)
return null;
string filePath = Provider.RawFilePath;
if (File.Exists(filePath) == false)
return null;
return File.ReadAllBytes(filePath);
return FileUtility.ReadAllBytes(filePath);
}
/// <summary>

View File

@ -15,7 +15,8 @@ namespace YooAsset
CheckDownload,
Unpack,
CheckUnpack,
LoadFile,
LoadBundleFile,
LoadDeliveryFile,
CheckLoadFile,
Done,
}
@ -59,19 +60,24 @@ namespace YooAsset
}
else
{
_steps = ESteps.LoadFile;
_steps = ESteps.LoadBundleFile;
FileLoadPath = MainBundleInfo.Bundle.StreamingFilePath;
}
#else
_steps = ESteps.LoadFile;
_steps = ESteps.LoadBundleFile;
FileLoadPath = MainBundleInfo.Bundle.StreamingFilePath;
#endif
}
else if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromCache)
{
_steps = ESteps.LoadFile;
_steps = ESteps.LoadBundleFile;
FileLoadPath = MainBundleInfo.Bundle.CachedDataFilePath;
}
else if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromDelivery)
{
_steps = ESteps.LoadDeliveryFile;
FileLoadPath = MainBundleInfo.DeliveryFilePath;
}
else
{
throw new System.NotImplementedException(MainBundleInfo.LoadMode.ToString());
@ -82,7 +88,8 @@ namespace YooAsset
if (_steps == ESteps.Download)
{
int failedTryAgain = Impl.DownloadFailedTryAgain;
_downloader = DownloadSystem.BeginDownload(MainBundleInfo, failedTryAgain);
_downloader = DownloadSystem.CreateDownload(MainBundleInfo, failedTryAgain);
_downloader.SendRequest();
_steps = ESteps.CheckDownload;
}
@ -102,7 +109,7 @@ namespace YooAsset
}
else
{
_steps = ESteps.LoadFile;
_steps = ESteps.LoadBundleFile;
return; //下载完毕等待一帧再去加载!
}
}
@ -112,7 +119,8 @@ namespace YooAsset
{
int failedTryAgain = Impl.DownloadFailedTryAgain;
var bundleInfo = ManifestTools.ConvertToUnpackInfo(MainBundleInfo.Bundle);
_unpacker = DownloadSystem.BeginDownload(bundleInfo, failedTryAgain);
_unpacker = DownloadSystem.CreateDownload(bundleInfo, failedTryAgain);
_unpacker.SendRequest();
_steps = ESteps.CheckUnpack;
}
@ -132,12 +140,12 @@ namespace YooAsset
}
else
{
_steps = ESteps.LoadFile;
_steps = ESteps.LoadBundleFile;
}
}
// 5. 加载AssetBundle
if (_steps == ESteps.LoadFile)
if (_steps == ESteps.LoadBundleFile)
{
#if UNITY_EDITOR
// 注意Unity2017.4编辑器模式下如果AssetBundle文件不存在会导致编辑器崩溃这里做了预判。
@ -212,7 +220,35 @@ namespace YooAsset
_steps = ESteps.CheckLoadFile;
}
// 6. 检测AssetBundle加载结果
// 6. 加载AssetBundle
if (_steps == ESteps.LoadDeliveryFile)
{
// 设置下载进度
DownloadProgress = 1f;
DownloadedBytes = (ulong)MainBundleInfo.Bundle.FileSize;
// Load assetBundle file
var loadMethod = (EBundleLoadMethod)MainBundleInfo.Bundle.LoadMethod;
if (loadMethod == EBundleLoadMethod.Normal)
{
ulong offset = MainBundleInfo.DeliveryFileOffset;
if (_isWaitForAsyncComplete)
CacheBundle = AssetBundle.LoadFromFile(FileLoadPath, 0, offset);
else
_createRequest = AssetBundle.LoadFromFileAsync(FileLoadPath, 0, offset);
}
else
{
_steps = ESteps.Done;
Status = EStatus.Failed;
LastError = $"Delivery file not support encryption : {MainBundleInfo.Bundle.BundleName}";
YooLogger.Error(LastError);
return;
}
_steps = ESteps.CheckLoadFile;
}
// 7. 检测AssetBundle加载结果
if (_steps == ESteps.CheckLoadFile)
{
if (_createRequest != null)
@ -234,22 +270,47 @@ namespace YooAsset
// Check error
if (CacheBundle == null)
{
_steps = ESteps.Done;
Status = EStatus.Failed;
LastError = $"Failed to load assetBundle : {MainBundleInfo.Bundle.BundleName}";
YooLogger.Error(LastError);
// 注意当缓存文件的校验等级为Low的时候并不能保证缓存文件的完整性。
// 在AssetBundle文件加载失败的情况下我们需要重新验证文件的完整性
if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromCache)
{
var result = CacheSystem.VerifyingRecordFile(MainBundleInfo.Bundle.PackageName, MainBundleInfo.Bundle.CacheGUID);
if (result != EVerifyResult.Succeed)
if (result == EVerifyResult.Succeed)
{
YooLogger.Error($"Found possibly corrupt file ! {MainBundleInfo.Bundle.CacheGUID} Verify result : {result}");
// 说明:在安卓移动平台,华为和三星真机上有极小概率加载资源包失败。
// 大多数情况在首次安装下载资源到沙盒内,游戏过程中切换到后台再回到游戏内有很大概率触发!
byte[] fileData = FileUtility.ReadAllBytes(FileLoadPath);
if (fileData != null && fileData.Length > 0)
CacheBundle = AssetBundle.LoadFromMemory(fileData);
if (CacheBundle == null)
{
_steps = ESteps.Done;
Status = EStatus.Failed;
LastError = $"Failed to load assetBundle from memory : {MainBundleInfo.Bundle.BundleName}";
YooLogger.Error(LastError);
}
else
{
_steps = ESteps.Done;
Status = EStatus.Succeed;
}
}
else
{
_steps = ESteps.Done;
Status = EStatus.Failed;
LastError = $"Found possibly corrupt file ! {MainBundleInfo.Bundle.CacheGUID} Verify result : {result}";
YooLogger.Error(LastError);
CacheSystem.DiscardFile(MainBundleInfo.Bundle.PackageName, MainBundleInfo.Bundle.CacheGUID);
}
}
else
{
_steps = ESteps.Done;
Status = EStatus.Failed;
LastError = $"Failed to load assetBundle : {MainBundleInfo.Bundle.BundleName}";
YooLogger.Error(LastError);
}
}
else
{
@ -262,9 +323,9 @@ namespace YooAsset
/// <summary>
/// 销毁
/// </summary>
public override void Destroy(bool forceDestroy)
public override void Destroy()
{
base.Destroy(forceDestroy);
base.Destroy();
if (_stream != null)
{

View File

@ -15,21 +15,14 @@ namespace YooAsset
private enum ESteps
{
None = 0,
Download,
CheckDownload,
LoadCacheFile,
CheckLoadCacheFile,
LoadWebFile,
CheckLoadWebFile,
TryLoadWebFile,
LoadWebSiteFile,
LoadRemoteFile,
CheckLoadFile,
Done,
}
private ESteps _steps = ESteps.None;
private float _tryTimer = 0;
private DownloaderBase _downloader;
private UnityWebRequest _webRequest;
private AssetBundleCreateRequest _createRequest;
private WebDownloader _downloader;
public AssetBundleWebLoader(AssetSystemImpl impl, BundleInfo bundleInfo) : base(impl, bundleInfo)
@ -48,18 +41,13 @@ namespace YooAsset
{
if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromRemote)
{
_steps = ESteps.Download;
FileLoadPath = MainBundleInfo.Bundle.CachedDataFilePath;
_steps = ESteps.LoadRemoteFile;
FileLoadPath = string.Empty;
}
else if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromStreaming)
{
_steps = ESteps.LoadWebFile;
FileLoadPath = MainBundleInfo.Bundle.StreamingFilePath;
}
else if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromCache)
{
_steps = ESteps.LoadCacheFile;
FileLoadPath = MainBundleInfo.Bundle.CachedDataFilePath;
_steps = ESteps.LoadWebSiteFile;
FileLoadPath = string.Empty;
}
else
{
@ -67,96 +55,40 @@ namespace YooAsset
}
}
// 1. 从服务器下载
if (_steps == ESteps.Download)
// 1. 跨域获取资源包
if (_steps == ESteps.LoadRemoteFile)
{
int failedTryAgain = Impl.DownloadFailedTryAgain;
_downloader = DownloadSystem.BeginDownload(MainBundleInfo, failedTryAgain);
_steps = ESteps.CheckDownload;
_downloader = DownloadSystem.CreateDownload(MainBundleInfo, failedTryAgain) as WebDownloader;
_downloader.SendRequest(true);
_steps = ESteps.CheckLoadFile;
}
// 2. 检测服务器下载结果
if (_steps == ESteps.CheckDownload)
// 2. 从站点获取资源包
if (_steps == ESteps.LoadWebSiteFile)
{
int failedTryAgain = Impl.DownloadFailedTryAgain;
var bundleInfo = ManifestTools.ConvertToUnpackInfo(MainBundleInfo.Bundle);
_downloader = DownloadSystem.CreateDownload(bundleInfo, failedTryAgain) as WebDownloader;
_downloader.SendRequest(true);
_steps = ESteps.CheckLoadFile;
}
// 3. 检测加载结果
if (_steps == ESteps.CheckLoadFile)
{
DownloadProgress = _downloader.DownloadProgress;
DownloadedBytes = _downloader.DownloadedBytes;
if (_downloader.IsDone() == false)
return;
if (_downloader.HasError())
{
_steps = ESteps.Done;
Status = EStatus.Failed;
LastError = _downloader.GetLastError();
}
else
{
_steps = ESteps.LoadCacheFile;
return; //下载完毕等待一帧再去加载!
}
}
// 3. 从本地缓存里加载AssetBundle
if (_steps == ESteps.LoadCacheFile)
{
#if UNITY_EDITOR
// 注意Unity2017.4编辑器模式下如果AssetBundle文件不存在会导致编辑器崩溃这里做了预判。
if (System.IO.File.Exists(FileLoadPath) == false)
{
_steps = ESteps.Done;
Status = EStatus.Failed;
LastError = $"Not found assetBundle file : {FileLoadPath}";
YooLogger.Error(LastError);
return;
}
#endif
// 设置下载进度
DownloadProgress = 1f;
DownloadedBytes = (ulong)MainBundleInfo.Bundle.FileSize;
// Load assetBundle file
var loadMethod = (EBundleLoadMethod)MainBundleInfo.Bundle.LoadMethod;
if (loadMethod == EBundleLoadMethod.Normal)
{
_createRequest = AssetBundle.LoadFromFileAsync(FileLoadPath);
}
else
{
_steps = ESteps.Done;
Status = EStatus.Failed;
LastError = $"WebGL not support encrypted bundle file : {MainBundleInfo.Bundle.BundleName}";
YooLogger.Error(LastError);
return;
}
_steps = ESteps.CheckLoadCacheFile;
}
// 4. 检测AssetBundle加载结果
if (_steps == ESteps.CheckLoadCacheFile)
{
if (_createRequest.isDone == false)
return;
CacheBundle = _createRequest.assetBundle;
CacheBundle = _downloader.GetAssetBundle();
if (CacheBundle == null)
{
_steps = ESteps.Done;
Status = EStatus.Failed;
LastError = $"Failed to load AssetBundle file : {MainBundleInfo.Bundle.BundleName}";
LastError = $"AssetBundle file is invalid : {MainBundleInfo.Bundle.BundleName}";
YooLogger.Error(LastError);
// 注意当缓存文件的校验等级为Low的时候并不能保证缓存文件的完整性。
// 在AssetBundle文件加载失败的情况下我们需要重新验证文件的完整性
if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromCache)
{
var result = CacheSystem.VerifyingRecordFile(MainBundleInfo.Bundle.PackageName, MainBundleInfo.Bundle.CacheGUID);
if (result != EVerifyResult.Succeed)
{
YooLogger.Error($"Found possibly corrupt file ! {MainBundleInfo.Bundle.CacheGUID}");
CacheSystem.DiscardFile(MainBundleInfo.Bundle.PackageName, MainBundleInfo.Bundle.CacheGUID);
}
}
}
else
{
@ -164,63 +96,6 @@ namespace YooAsset
Status = EStatus.Succeed;
}
}
// 5. 从WEB网站获取AssetBundle文件
if (_steps == ESteps.LoadWebFile)
{
var hash = Hash128.Parse(MainBundleInfo.Bundle.FileHash);
_webRequest = UnityWebRequestAssetBundle.GetAssetBundle(FileLoadPath, hash);
_webRequest.SendWebRequest();
_steps = ESteps.CheckLoadWebFile;
}
// 6. 检测AssetBundle加载结果
if (_steps == ESteps.CheckLoadWebFile)
{
DownloadProgress = _webRequest.downloadProgress;
DownloadedBytes = _webRequest.downloadedBytes;
if (_webRequest.isDone == false)
return;
#if UNITY_2020_1_OR_NEWER
if (_webRequest.result != UnityWebRequest.Result.Success)
#else
if (_webRequest.isNetworkError || _webRequest.isHttpError)
#endif
{
YooLogger.Warning($"Failed to get asset bundle from web : {FileLoadPath} Error : {_webRequest.error}");
_steps = ESteps.TryLoadWebFile;
_tryTimer = 0;
}
else
{
CacheBundle = DownloadHandlerAssetBundle.GetContent(_webRequest);
if (CacheBundle == null)
{
_steps = ESteps.Done;
Status = EStatus.Failed;
LastError = $"AssetBundle file is invalid : {MainBundleInfo.Bundle.BundleName}";
YooLogger.Error(LastError);
}
else
{
_steps = ESteps.Done;
Status = EStatus.Succeed;
}
}
}
// 7. 如果获取失败,重新尝试
if (_steps == ESteps.TryLoadWebFile)
{
_tryTimer += Time.unscaledDeltaTime;
if (_tryTimer > 1f)
{
_webRequest.Dispose();
_webRequest = null;
_steps = ESteps.LoadWebFile;
}
}
}
/// <summary>

View File

@ -153,18 +153,15 @@ namespace YooAsset
/// <summary>
/// 销毁
/// </summary>
public virtual void Destroy(bool forceDestroy)
public virtual void Destroy()
{
IsDestroyed = true;
// Check fatal
if (forceDestroy == false)
{
if (RefCount > 0)
throw new Exception($"Bundle file loader ref is not zero : {MainBundleInfo.Bundle.BundleName}");
if (IsDone() == false)
throw new Exception($"Bundle file loader is not done : {MainBundleInfo.Bundle.BundleName}");
}
if (RefCount > 0)
throw new Exception($"Bundle file loader ref is not zero : {MainBundleInfo.Bundle.BundleName}");
if (IsDone() == false)
throw new Exception($"Bundle file loader is not done : {MainBundleInfo.Bundle.BundleName}");
if (CacheBundle != null)
{

View File

@ -54,6 +54,11 @@ namespace YooAsset
_steps = ESteps.CheckFile;
FileLoadPath = MainBundleInfo.Bundle.CachedDataFilePath;
}
else if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromDelivery)
{
_steps = ESteps.CheckFile;
FileLoadPath = MainBundleInfo.DeliveryFilePath;
}
else
{
throw new System.NotImplementedException(MainBundleInfo.LoadMode.ToString());
@ -64,7 +69,8 @@ namespace YooAsset
if (_steps == ESteps.Download)
{
int failedTryAgain = Impl.DownloadFailedTryAgain;
_downloader = DownloadSystem.BeginDownload(MainBundleInfo, failedTryAgain);
_downloader = DownloadSystem.CreateDownload(MainBundleInfo, failedTryAgain);
_downloader.SendRequest();
_steps = ESteps.CheckDownload;
}
@ -93,7 +99,8 @@ namespace YooAsset
{
int failedTryAgain = Impl.DownloadFailedTryAgain;
var bundleInfo = ManifestTools.ConvertToUnpackInfo(MainBundleInfo.Bundle);
_unpacker = DownloadSystem.BeginDownload(bundleInfo, failedTryAgain);
_unpacker = DownloadSystem.CreateDownload(bundleInfo, failedTryAgain);
_unpacker.SendRequest();
_steps = ESteps.CheckUnpack;
}

View File

@ -47,11 +47,6 @@ namespace YooAsset
_steps = ESteps.Website;
FileLoadPath = MainBundleInfo.Bundle.CachedDataFilePath;
}
else if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromCache)
{
_steps = ESteps.CheckFile;
FileLoadPath = MainBundleInfo.Bundle.CachedDataFilePath;
}
else
{
throw new System.NotImplementedException(MainBundleInfo.LoadMode.ToString());
@ -62,7 +57,8 @@ namespace YooAsset
if (_steps == ESteps.Download)
{
int failedTryAgain = Impl.DownloadFailedTryAgain;
_downloader = DownloadSystem.BeginDownload(MainBundleInfo, failedTryAgain);
_downloader = DownloadSystem.CreateDownload(MainBundleInfo, failedTryAgain);
_downloader.SendRequest();
_steps = ESteps.CheckDownload;
}
@ -91,7 +87,8 @@ namespace YooAsset
{
int failedTryAgain = Impl.DownloadFailedTryAgain;
var bundleInfo = ManifestTools.ConvertToUnpackInfo(MainBundleInfo.Bundle);
_website = DownloadSystem.BeginDownload(bundleInfo, failedTryAgain);
_website = DownloadSystem.CreateDownload(bundleInfo, failedTryAgain);
_website.SendRequest();
_steps = ESteps.CheckWebsite;
}

View File

@ -53,6 +53,12 @@ namespace YooAsset
return;
}
if (OwnerBundle.CacheBundle == null)
{
ProcessCacheBundleException();
return;
}
Status = EStatus.Loading;
}

View File

@ -55,12 +55,7 @@ namespace YooAsset
if (OwnerBundle.CacheBundle == null)
{
if (OwnerBundle.IsDestroyed)
throw new System.Exception("Should never get here !");
Status = EStatus.Failed;
LastError = $"The bundle {OwnerBundle.MainBundleInfo.Bundle.BundleName} has been destroyed by unity bugs !";
YooLogger.Error(LastError);
InvokeCompletion();
ProcessCacheBundleException();
return;
}

View File

@ -53,6 +53,12 @@ namespace YooAsset
return;
}
if (OwnerBundle.CacheBundle == null)
{
ProcessCacheBundleException();
return;
}
Status = EStatus.Loading;
}

View File

@ -123,7 +123,7 @@ namespace YooAsset
/// <summary>
/// 销毁资源对象
/// </summary>
public virtual void Destroy()
public void Destroy()
{
IsDestroyed = true;
@ -220,6 +220,30 @@ namespace YooAsset
}
}
/// <summary>
/// 处理特殊异常
/// </summary>
protected void ProcessCacheBundleException()
{
if (OwnerBundle.IsDestroyed)
throw new System.Exception("Should never get here !");
if (OwnerBundle.MainBundleInfo.Bundle.IsRawFile)
{
Status = EStatus.Failed;
LastError = $"Cannot load asset bundle file using {nameof(ResourcePackage.LoadRawFileAsync)} method !";
YooLogger.Error(LastError);
InvokeCompletion();
}
else
{
Status = EStatus.Failed;
LastError = $"The bundle {OwnerBundle.MainBundleInfo.Bundle.BundleName} has been destroyed by unity bugs !";
YooLogger.Error(LastError);
InvokeCompletion();
}
}
/// <summary>
/// 异步操作任务
/// </summary>

View File

@ -10,6 +10,11 @@ namespace YooAsset
{
private readonly static Dictionary<string, PackageCache> _cachedDic = new Dictionary<string, PackageCache>(1000);
/// <summary>
/// 禁用Unity缓存系统在WebGL平台
/// </summary>
public static bool DisableUnityCacheOnWebGL = false;
/// <summary>
/// 初始化时的验证级别
/// </summary>
@ -85,10 +90,19 @@ namespace YooAsset
}
}
/// <summary>
/// 获取记录对象
/// </summary>
public static PackageCache.RecordWrapper TryGetWrapper(string packageName, string cacheGUID)
{
var cache = GetOrCreateCache(packageName);
return cache.TryGetWrapper(cacheGUID);
}
/// <summary>
/// 验证缓存文件(子线程内操作)
/// </summary>
public static EVerifyResult VerifyingCacheFile(VerifyCacheElement element)
public static EVerifyResult VerifyingCacheFile(VerifyCacheFileElement element)
{
try
{
@ -120,7 +134,7 @@ namespace YooAsset
/// <summary>
/// 验证下载文件(子线程内操作)
/// </summary>
public static EVerifyResult VerifyingTempFile(VerifyTempElement element)
public static EVerifyResult VerifyingTempFile(VerifyTempFileElement element)
{
return VerifyingInternal(element.TempDataFilePath, element.FileSize, element.FileCRC, EVerifyLevel.High);
}
@ -160,9 +174,9 @@ namespace YooAsset
/// <summary>
/// 获取所有的缓存文件
/// </summary>
public static List<string> GetAllCacheGUIDs(ResourcePackage package)
public static List<string> GetAllCacheGUIDs(string packageName)
{
var cache = GetOrCreateCache(package.PackageName);
var cache = GetOrCreateCache(packageName);
return cache.GetAllKeys();
}

View File

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

View File

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

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: fe50795c51a46884088139b840c1557f
guid: d37e37f5d78ddf8468adcf2dff1edfbb
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@ -25,7 +25,7 @@ namespace YooAsset
/// <summary>
/// 需要验证的元素
/// </summary>
public readonly List<VerifyCacheElement> VerifyElements = new List<VerifyCacheElement>(5000);
public readonly List<VerifyCacheFileElement> VerifyElements = new List<VerifyCacheFileElement>(5000);
public FindCacheFilesOperation(string packageName)
{
@ -45,7 +45,7 @@ namespace YooAsset
{
// BundleFiles
{
string rootPath = PersistentTools.GetCachedBundleFileFolderPath(_packageName);
string rootPath = PersistentTools.GetPersistent(_packageName).SandboxCacheBundleFilesRoot;
DirectoryInfo rootDirectory = new DirectoryInfo(rootPath);
if (rootDirectory.Exists)
{
@ -56,7 +56,7 @@ namespace YooAsset
// RawFiles
{
string rootPath = PersistentTools.GetCachedRawFileFolderPath(_packageName);
string rootPath = PersistentTools.GetPersistent(_packageName).SandboxCacheRawFilesRoot;
DirectoryInfo rootDirectory = new DirectoryInfo(rootPath);
if (rootDirectory.Exists)
{
@ -113,7 +113,7 @@ namespace YooAsset
string fileRootPath = chidDirectory.FullName;
string dataFilePath = $"{fileRootPath}/{ YooAssetSettings.CacheBundleDataFileName}";
string infoFilePath = $"{fileRootPath}/{ YooAssetSettings.CacheBundleInfoFileName}";
VerifyCacheElement element = new VerifyCacheElement(_packageName, cacheGUID, fileRootPath, dataFilePath, infoFilePath);
VerifyCacheFileElement element = new VerifyCacheFileElement(_packageName, cacheGUID, fileRootPath, dataFilePath, infoFilePath);
VerifyElements.Add(element);
}
@ -161,7 +161,7 @@ namespace YooAsset
string fileRootPath = chidDirectory.FullName;
string dataFilePath = $"{fileRootPath}/{ YooAssetSettings.CacheBundleDataFileName}{dataFileExtension}";
string infoFilePath = $"{fileRootPath}/{ YooAssetSettings.CacheBundleInfoFileName}";
VerifyCacheElement element = new VerifyCacheElement(_packageName, cacheGUID, fileRootPath, dataFilePath, infoFilePath);
VerifyCacheFileElement element = new VerifyCacheFileElement(_packageName, cacheGUID, fileRootPath, dataFilePath, infoFilePath);
VerifyElements.Add(element);
}

View File

@ -8,7 +8,7 @@ namespace YooAsset
{
internal abstract class VerifyCacheFilesOperation : AsyncOperationBase
{
public static VerifyCacheFilesOperation CreateOperation(List<VerifyCacheElement> elements)
public static VerifyCacheFilesOperation CreateOperation(List<VerifyCacheFileElement> elements)
{
#if UNITY_WEBGL
var operation = new VerifyCacheFilesWithoutThreadOperation(elements);
@ -33,8 +33,8 @@ namespace YooAsset
}
private readonly ThreadSyncContext _syncContext = new ThreadSyncContext();
private List<VerifyCacheElement> _waitingList;
private List<VerifyCacheElement> _verifyingList;
private List<VerifyCacheFileElement> _waitingList;
private List<VerifyCacheFileElement> _verifyingList;
private int _verifyMaxNum;
private int _verifyTotalCount;
private float _verifyStartTime;
@ -42,7 +42,7 @@ namespace YooAsset
private int _failedCount;
private ESteps _steps = ESteps.None;
public VerifyCacheFilesWithThreadOperation(List<VerifyCacheElement> elements)
public VerifyCacheFilesWithThreadOperation(List<VerifyCacheFileElement> elements)
{
_waitingList = elements;
}
@ -68,7 +68,7 @@ namespace YooAsset
if (_verifyMaxNum < 1)
_verifyMaxNum = 1;
_verifyingList = new List<VerifyCacheElement>(_verifyMaxNum);
_verifyingList = new List<VerifyCacheFileElement>(_verifyMaxNum);
_steps = ESteps.UpdateVerify;
}
@ -114,19 +114,19 @@ namespace YooAsset
return 1f;
return (float)(_succeedCount + _failedCount) / _verifyTotalCount;
}
private bool BeginVerifyFileWithThread(VerifyCacheElement element)
private bool BeginVerifyFileWithThread(VerifyCacheFileElement element)
{
return ThreadPool.QueueUserWorkItem(new WaitCallback(VerifyInThread), element);
}
private void VerifyInThread(object obj)
{
VerifyCacheElement element = (VerifyCacheElement)obj;
VerifyCacheFileElement element = (VerifyCacheFileElement)obj;
element.Result = CacheSystem.VerifyingCacheFile(element);
_syncContext.Post(VerifyCallback, element);
}
private void VerifyCallback(object obj)
{
VerifyCacheElement element = (VerifyCacheElement)obj;
VerifyCacheFileElement element = (VerifyCacheFileElement)obj;
_verifyingList.Remove(element);
if (element.Result == EVerifyResult.Succeed)
@ -158,8 +158,8 @@ namespace YooAsset
Done,
}
private List<VerifyCacheElement> _waitingList;
private List<VerifyCacheElement> _verifyingList;
private List<VerifyCacheFileElement> _waitingList;
private List<VerifyCacheFileElement> _verifyingList;
private int _verifyMaxNum;
private int _verifyTotalCount;
private float _verifyStartTime;
@ -167,7 +167,7 @@ namespace YooAsset
private int _failedCount;
private ESteps _steps = ESteps.None;
public VerifyCacheFilesWithoutThreadOperation(List<VerifyCacheElement> elements)
public VerifyCacheFilesWithoutThreadOperation(List<VerifyCacheFileElement> elements)
{
_waitingList = elements;
}
@ -189,7 +189,7 @@ namespace YooAsset
_verifyMaxNum = fileCount;
_verifyTotalCount = fileCount;
_verifyingList = new List<VerifyCacheElement>(_verifyMaxNum);
_verifyingList = new List<VerifyCacheFileElement>(_verifyMaxNum);
_steps = ESteps.UpdateVerify;
}
@ -229,7 +229,7 @@ namespace YooAsset
return 1f;
return (float)(_succeedCount + _failedCount) / _verifyTotalCount;
}
private void BeginVerifyFileWithoutThread(VerifyCacheElement element)
private void BeginVerifyFileWithoutThread(VerifyCacheFileElement element)
{
element.Result = CacheSystem.VerifyingCacheFile(element);
if (element.Result == EVerifyResult.Succeed)

View File

@ -10,7 +10,7 @@ namespace YooAsset
{
public EVerifyResult VerifyResult { protected set; get; }
public static VerifyTempFileOperation CreateOperation(VerifyTempElement element)
public static VerifyTempFileOperation CreateOperation(VerifyTempFileElement element)
{
#if UNITY_WEBGL
var operation = new VerifyTempFileWithoutThreadOperation(element);
@ -34,10 +34,10 @@ namespace YooAsset
Done,
}
private readonly VerifyTempElement _element;
private readonly VerifyTempFileElement _element;
private ESteps _steps = ESteps.None;
public VerifyTempFileWithThreadOperation(VerifyTempElement element)
public VerifyTempFileWithThreadOperation(VerifyTempFileElement element)
{
_element = element;
}
@ -79,13 +79,13 @@ namespace YooAsset
}
}
private bool BeginVerifyFileWithThread(VerifyTempElement element)
private bool BeginVerifyFileWithThread(VerifyTempFileElement element)
{
return ThreadPool.QueueUserWorkItem(new WaitCallback(VerifyInThread), element);
}
private void VerifyInThread(object obj)
{
VerifyTempElement element = (VerifyTempElement)obj;
VerifyTempFileElement element = (VerifyTempFileElement)obj;
int result = (int)CacheSystem.VerifyingTempFile(element);
element.Result = result;
}
@ -103,10 +103,10 @@ namespace YooAsset
Done,
}
private readonly VerifyTempElement _element;
private readonly VerifyTempFileElement _element;
private ESteps _steps = ESteps.None;
public VerifyTempFileWithoutThreadOperation(VerifyTempElement element)
public VerifyTempFileWithoutThreadOperation(VerifyTempFileElement element)
{
_element = element;
}

View File

@ -0,0 +1,169 @@
using System.IO;
namespace YooAsset
{
internal class Persistent
{
private readonly string _packageName;
public string BuildinRoot { private set; get; }
public string BuildinPackageRoot { private set; get; }
public string SandboxRoot { private set; get; }
public string SandboxPackageRoot { private set; get; }
public string SandboxCacheBundleFilesRoot { private set; get; }
public string SandboxCacheRawFilesRoot { private set; get; }
public string SandboxManifestFilesRoot { private set; get; }
public string SandboxAppFootPrintFilePath { private set; get; }
public Persistent(string packageName)
{
_packageName = packageName;
}
/// <summary>
/// 重写根路径
/// </summary>
public void OverwriteRootDirectory(string buildinRoot, string sandboxRoot)
{
if (string.IsNullOrEmpty(buildinRoot))
BuildinRoot = CreateDefaultBuildinRoot();
else
BuildinRoot = buildinRoot;
if (string.IsNullOrEmpty(sandboxRoot))
SandboxRoot = CreateDefaultSandboxRoot();
else
SandboxRoot = sandboxRoot;
BuildinPackageRoot = PathUtility.Combine(BuildinRoot, _packageName);
SandboxPackageRoot = PathUtility.Combine(SandboxRoot, _packageName);
SandboxCacheBundleFilesRoot = PathUtility.Combine(SandboxPackageRoot, YooAssetSettings.CachedBundleFileFolder);
SandboxCacheRawFilesRoot = PathUtility.Combine(SandboxPackageRoot, YooAssetSettings.CachedRawFileFolder);
SandboxManifestFilesRoot = PathUtility.Combine(SandboxPackageRoot, YooAssetSettings.ManifestFolderName);
SandboxAppFootPrintFilePath = PathUtility.Combine(SandboxPackageRoot, YooAssetSettings.AppFootPrintFileName);
}
private static string CreateDefaultBuildinRoot()
{
string path = PathUtility.Combine(UnityEngine.Application.streamingAssetsPath, YooAssetSettingsData.Setting.DefaultYooFolderName);
#if UNITY_OPENHARMONY
return $"file://{path}";
#else
return path;
#endif
}
private static string CreateDefaultSandboxRoot()
{
#if UNITY_EDITOR
// 注意:为了方便调试查看,编辑器下把存储目录放到项目里。
string projectPath = Path.GetDirectoryName(UnityEngine.Application.dataPath);
projectPath = PathUtility.RegularPath(projectPath);
return PathUtility.Combine(projectPath, YooAssetSettingsData.Setting.DefaultYooFolderName);
#elif UNITY_STANDALONE
return PathUtility.Combine(UnityEngine.Application.dataPath, YooAssetSettingsData.Setting.DefaultYooFolderName);
#else
return PathUtility.Combine(UnityEngine.Application.persistentDataPath, YooAssetSettingsData.Setting.DefaultYooFolderName);
#endif
}
/// <summary>
/// 删除沙盒里的包裹目录
/// </summary>
public void DeleteSandboxPackageFolder()
{
if (Directory.Exists(SandboxPackageRoot))
Directory.Delete(SandboxPackageRoot, true);
}
/// <summary>
/// 删除沙盒内的缓存文件夹
/// </summary>
public void DeleteSandboxCacheFilesFolder()
{
// CacheBundleFiles
if (Directory.Exists(SandboxCacheBundleFilesRoot))
Directory.Delete(SandboxCacheBundleFilesRoot, true);
// CacheRawFiles
if (Directory.Exists(SandboxCacheRawFilesRoot))
Directory.Delete(SandboxCacheRawFilesRoot, true);
}
/// <summary>
/// 删除沙盒内的清单文件夹
/// </summary>
public void DeleteSandboxManifestFilesFolder()
{
if (Directory.Exists(SandboxManifestFilesRoot))
Directory.Delete(SandboxManifestFilesRoot, true);
}
/// <summary>
/// 获取沙盒内包裹的清单文件的路径
/// </summary>
public string GetSandboxPackageManifestFilePath(string packageVersion)
{
string fileName = YooAssetSettingsData.GetManifestBinaryFileName(_packageName, packageVersion);
return PathUtility.Combine(SandboxManifestFilesRoot, fileName);
}
/// <summary>
/// 获取沙盒内包裹的哈希文件的路径
/// </summary>
public string GetSandboxPackageHashFilePath(string packageVersion)
{
string fileName = YooAssetSettingsData.GetPackageHashFileName(_packageName, packageVersion);
return PathUtility.Combine(SandboxManifestFilesRoot, fileName);
}
/// <summary>
/// 获取沙盒内包裹的版本文件的路径
/// </summary>
public string GetSandboxPackageVersionFilePath()
{
string fileName = YooAssetSettingsData.GetPackageVersionFileName(_packageName);
return PathUtility.Combine(SandboxManifestFilesRoot, fileName);
}
/// <summary>
/// 保存沙盒内默认的包裹版本
/// </summary>
public void SaveSandboxPackageVersionFile(string version)
{
YooLogger.Log($"Save package version : {version}");
string filePath = GetSandboxPackageVersionFilePath();
FileUtility.WriteAllText(filePath, version);
}
/// <summary>
/// 获取APP内包裹的清单文件的路径
/// </summary>
public string GetBuildinPackageManifestFilePath(string packageVersion)
{
string fileName = YooAssetSettingsData.GetManifestBinaryFileName(_packageName, packageVersion);
return PathUtility.Combine(BuildinPackageRoot, fileName);
}
/// <summary>
/// 获取APP内包裹的哈希文件的路径
/// </summary>
public string GetBuildinPackageHashFilePath(string packageVersion)
{
string fileName = YooAssetSettingsData.GetPackageHashFileName(_packageName, packageVersion);
return PathUtility.Combine(BuildinPackageRoot, fileName);
}
/// <summary>
/// 获取APP内包裹的版本文件的路径
/// </summary>
public string GetBuildinPackageVersionFilePath()
{
string fileName = YooAssetSettingsData.GetPackageVersionFileName(_packageName);
return PathUtility.Combine(BuildinPackageRoot, fileName);
}
}
}

View File

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

View File

@ -3,84 +3,31 @@ using System.Collections.Generic;
namespace YooAsset
{
internal static class PersistentTools
internal class PersistentTools
{
private const string SandboxFolderName = "Sandbox";
private const string CacheFolderName = "CacheFiles";
private const string CachedBundleFileFolder = "BundleFiles";
private const string CachedRawFileFolder = "RawFiles";
private const string ManifestFolderName = "ManifestFiles";
private const string AppFootPrintFileName = "ApplicationFootPrint.bytes";
private static string _buildinPath;
private static string _sandboxPath;
private static readonly Dictionary<string, Persistent> _persitentDic = new Dictionary<string, Persistent>(100);
/// <summary>
/// 重写沙盒跟路径
/// 获取包裹的持久化类
/// </summary>
public static void OverwriteSandboxPath(string sandboxPath)
public static Persistent GetPersistent(string packageName)
{
_sandboxPath = sandboxPath;
if (_persitentDic.ContainsKey(packageName) == false)
throw new System.Exception("Should never get here !");
return _persitentDic[packageName];
}
/// <summary>
/// 获取沙盒文件夹路径
/// 获取或创建包裹的持久化类
/// </summary>
public static string GetPersistentRootPath()
public static Persistent GetOrCreatePersistent(string packageName)
{
#if UNITY_EDITOR
// 注意:为了方便调试查看,编辑器下把存储目录放到项目里
if (string.IsNullOrEmpty(_sandboxPath))
if (_persitentDic.ContainsKey(packageName) == false)
{
string projectPath = Path.GetDirectoryName(UnityEngine.Application.dataPath);
projectPath = PathUtility.RegularPath(projectPath);
_sandboxPath = PathUtility.Combine(projectPath, SandboxFolderName);
Persistent persistent = new Persistent(packageName);
_persitentDic.Add(packageName, persistent);
}
#elif UNITY_STANDALONE
if (string.IsNullOrEmpty(_sandboxPath))
{
_sandboxPath = PathUtility.Combine(UnityEngine.Application.dataPath, SandboxFolderName);
}
#else
if (string.IsNullOrEmpty(_sandboxPath))
{
_sandboxPath = PathUtility.Combine(UnityEngine.Application.persistentDataPath, SandboxFolderName);
}
#endif
return _sandboxPath;
}
/// <summary>
/// 获取基于流文件夹的加载路径
/// </summary>
public static string MakeStreamingLoadPath(string path)
{
if (string.IsNullOrEmpty(_buildinPath))
{
_buildinPath = PathUtility.Combine(UnityEngine.Application.streamingAssetsPath, YooAssetSettings.StreamingAssetsBuildinFolder);
}
return PathUtility.Combine(_buildinPath, path);
}
/// <summary>
/// 获取基于沙盒文件夹的加载路径
/// </summary>
public static string MakePersistentLoadPath(string path)
{
string root = GetPersistentRootPath();
return PathUtility.Combine(root, path);
}
public static string MakePersistentLoadPath(string path1, string path2)
{
string root = GetPersistentRootPath();
return PathUtility.Combine(root, path1, path2);
}
public static string MakePersistentLoadPath(string path1, string path2, string path3)
{
string root = GetPersistentRootPath();
return PathUtility.Combine(root, path1, path2, path3);
return _persitentDic[packageName];
}
/// <summary>
@ -90,119 +37,24 @@ namespace YooAsset
{
#if UNITY_EDITOR
return StringUtility.Format("file:///{0}", path);
#elif UNITY_IPHONE
return StringUtility.Format("file://{0}", path);
#elif UNITY_ANDROID
return path;
#elif UNITY_STANDALONE
return StringUtility.Format("file:///{0}", path);
#elif UNITY_WEBGL
return path;
#elif UNITY_IPHONE
return StringUtility.Format("file://{0}", path);
#elif UNITY_ANDROID
if (path.StartsWith("jar:file://"))
return path;
else
return StringUtility.Format("jar:file://{0}", path);
#elif UNITY_STANDALONE_OSX
return new System.Uri(path).ToString();
#elif UNITY_STANDALONE
return StringUtility.Format("file:///{0}", path);
#elif UNITY_OPENHARMONY
return path;
#else
return path;
#endif
}
/// <summary>
/// 删除沙盒总目录
/// </summary>
public static void DeleteSandbox()
{
string directoryPath = GetPersistentRootPath();
if (Directory.Exists(directoryPath))
Directory.Delete(directoryPath, true);
}
/// <summary>
/// 删除沙盒内的缓存文件夹
/// </summary>
public static void DeleteCacheFolder()
{
string root = MakePersistentLoadPath(CacheFolderName);
if (Directory.Exists(root))
Directory.Delete(root, true);
}
/// <summary>
/// 删除沙盒内的清单文件夹
/// </summary>
public static void DeleteManifestFolder()
{
string root = MakePersistentLoadPath(ManifestFolderName);
if (Directory.Exists(root))
Directory.Delete(root, true);
}
/// <summary>
/// 获取缓存的BundleFile文件夹路径
/// </summary>
private readonly static Dictionary<string, string> _cachedBundleFileFolder = new Dictionary<string, string>(100);
public static string GetCachedBundleFileFolderPath(string packageName)
{
if (_cachedBundleFileFolder.TryGetValue(packageName, out string value) == false)
{
value = MakePersistentLoadPath(CacheFolderName, packageName, CachedBundleFileFolder);
_cachedBundleFileFolder.Add(packageName, value);
}
return value;
}
/// <summary>
/// 获取缓存的RawFile文件夹路径
/// </summary>
private readonly static Dictionary<string, string> _cachedRawFileFolder = new Dictionary<string, string>(100);
public static string GetCachedRawFileFolderPath(string packageName)
{
if (_cachedRawFileFolder.TryGetValue(packageName, out string value) == false)
{
value = MakePersistentLoadPath(CacheFolderName, packageName, CachedRawFileFolder);
_cachedRawFileFolder.Add(packageName, value);
}
return value;
}
/// <summary>
/// 获取应用程序的水印文件路径
/// </summary>
public static string GetAppFootPrintFilePath()
{
return MakePersistentLoadPath(AppFootPrintFileName);
}
/// <summary>
/// 获取沙盒内清单文件的路径
/// </summary>
public static string GetCacheManifestFilePath(string packageName, string packageVersion)
{
string fileName = YooAssetSettingsData.GetManifestBinaryFileName(packageName, packageVersion);
return MakePersistentLoadPath(ManifestFolderName, fileName);
}
/// <summary>
/// 获取沙盒内包裹的哈希文件的路径
/// </summary>
public static string GetCachePackageHashFilePath(string packageName, string packageVersion)
{
string fileName = YooAssetSettingsData.GetPackageHashFileName(packageName, packageVersion);
return MakePersistentLoadPath(ManifestFolderName, fileName);
}
/// <summary>
/// 获取沙盒内包裹的版本文件的路径
/// </summary>
public static string GetCachePackageVersionFilePath(string packageName)
{
string fileName = YooAssetSettingsData.GetPackageVersionFileName(packageName);
return MakePersistentLoadPath(ManifestFolderName, fileName);
}
/// <summary>
/// 保存默认的包裹版本
/// </summary>
public static void SaveCachePackageVersionFile(string packageName, string version)
{
string filePath = GetCachePackageVersionFilePath(packageName);
FileUtility.WriteAllText(filePath, version);
}
}
}

View File

@ -5,7 +5,7 @@ namespace YooAsset
/// <summary>
/// 缓存文件验证元素
/// </summary>
internal class VerifyCacheElement
internal class VerifyCacheFileElement
{
public string PackageName { private set; get; }
public string CacheGUID { private set; get; }
@ -17,7 +17,7 @@ namespace YooAsset
public string DataFileCRC;
public long DataFileSize;
public VerifyCacheElement(string packageName, string cacheGUID, string fileRootPath, string dataFilePath, string infoFilePath)
public VerifyCacheFileElement(string packageName, string cacheGUID, string fileRootPath, string dataFilePath, string infoFilePath)
{
PackageName = packageName;
CacheGUID = cacheGUID;
@ -28,14 +28,13 @@ namespace YooAsset
public void DeleteFiles()
{
if (File.Exists(DataFilePath))
try
{
File.Delete(DataFilePath);
Directory.Delete(FileRootPath, true);
}
if (File.Exists(InfoFilePath))
catch (System.Exception e)
{
File.Delete(InfoFilePath);
YooLogger.Warning($"Failed delete cache bundle folder : {e}");
}
}
}
@ -43,7 +42,7 @@ namespace YooAsset
/// <summary>
/// 下载文件验证元素
/// </summary>
internal class VerifyTempElement
internal class VerifyTempFileElement
{
public string TempDataFilePath { private set; get; }
public string FileCRC { private set; get; }
@ -51,7 +50,7 @@ namespace YooAsset
public int Result = 0; // 注意:原子操作对象
public VerifyTempElement(string tempDataFilePath, string fileCRC, long fileSize)
public VerifyTempFileElement(string tempDataFilePath, string fileCRC, long fileSize)
{
TempDataFilePath = tempDataFilePath;
FileCRC = fileCRC;

View File

@ -32,6 +32,11 @@ namespace YooAsset
/// </summary>
public static CertificateHandler CertificateHandlerInstance = null;
/// <summary>
/// 网络重定向次数
/// </summary>
public static int RedirectLimit { set; get; } = -1;
/// <summary>
/// 启用断点续传功能文件的最小字节数
/// </summary>
@ -93,34 +98,49 @@ namespace YooAsset
/// <summary>
/// 开始下载资源文件
/// 注意:只有第一次请求的参数才有效
/// 创建下载器
/// 注意:只有第一次请求的参数才有效
/// </summary>
public static DownloaderBase BeginDownload(BundleInfo bundleInfo, int failedTryAgain, int timeout = 60)
public static DownloaderBase CreateDownload(BundleInfo bundleInfo, int failedTryAgain, int timeout = 60)
{
// 查询存在的下载器
if (_downloaderDic.TryGetValue(bundleInfo.Bundle.CachedDataFilePath, out var downloader))
{
return downloader;
}
// 如果资源已经缓存
if (CacheSystem.IsCached(bundleInfo.Bundle.PackageName, bundleInfo.Bundle.CacheGUID))
{
var tempDownloader = new TempDownloader(bundleInfo);
return tempDownloader;
var completedDownloader = new CompletedDownloader(bundleInfo);
return completedDownloader;
}
// 创建新的下载器
YooLogger.Log($"Beginning to download bundle : {bundleInfo.Bundle.BundleName} URL : {bundleInfo.RemoteMainURL}");
#if UNITY_WEBGL
if (bundleInfo.Bundle.IsRawFile)
{
YooLogger.Log($"Beginning to download file : {bundleInfo.Bundle.FileName} URL : {bundleInfo.RemoteMainURL}");
FileUtility.CreateFileDirectory(bundleInfo.Bundle.CachedDataFilePath);
bool breakDownload = bundleInfo.Bundle.FileSize >= BreakpointResumeFileSize;
DownloaderBase newDownloader = new FileDownloader(bundleInfo, breakDownload);
newDownloader.SendRequest(failedTryAgain, timeout);
DownloaderBase newDownloader = new FileGeneralDownloader(bundleInfo, failedTryAgain, timeout);
_downloaderDic.Add(bundleInfo.Bundle.CachedDataFilePath, newDownloader);
return newDownloader;
}
else
{
WebDownloader newDownloader = new WebDownloader(bundleInfo, failedTryAgain, timeout);
_downloaderDic.Add(bundleInfo.Bundle.CachedDataFilePath, newDownloader);
return newDownloader;
}
#else
FileUtility.CreateFileDirectory(bundleInfo.Bundle.CachedDataFilePath);
bool resumeDownload = bundleInfo.Bundle.FileSize >= BreakpointResumeFileSize;
DownloaderBase newDownloader;
if (resumeDownload)
newDownloader = new FileResumeDownloader(bundleInfo, failedTryAgain, timeout);
else
newDownloader = new FileGeneralDownloader(bundleInfo, failedTryAgain, timeout);
_downloaderDic.Add(bundleInfo.Bundle.CachedDataFilePath, newDownloader);
return newDownloader;
#endif
}
/// <summary>
@ -128,11 +148,29 @@ namespace YooAsset
/// </summary>
public static UnityWebRequest NewRequest(string requestURL)
{
UnityWebRequest webRequest;
if (RequestDelegate != null)
return RequestDelegate.Invoke(requestURL);
webRequest = RequestDelegate.Invoke(requestURL);
else
webRequest = new UnityWebRequest(requestURL, UnityWebRequest.kHttpVerbGET);
var request = new UnityWebRequest(requestURL, UnityWebRequest.kHttpVerbGET);
return request;
SetUnityWebRequestParam(webRequest);
return webRequest;
}
/// <summary>
/// 设置网络请求的自定义参数
/// </summary>
private static void SetUnityWebRequestParam(UnityWebRequest webRequest)
{
if (RedirectLimit >= 0)
webRequest.redirectLimit = RedirectLimit;
if (CertificateHandlerInstance != null)
{
webRequest.certificateHandler = CertificateHandlerInstance;
webRequest.disposeCertificateHandlerOnDispose = false;
}
}
/// <summary>

View File

@ -0,0 +1,23 @@

namespace YooAsset
{
internal sealed class CompletedDownloader : DownloaderBase
{
public CompletedDownloader(BundleInfo bundleInfo) : base(bundleInfo, 0, 0)
{
_downloadProgress = 1f;
_downloadedBytes = (ulong)bundleInfo.Bundle.FileSize;
_status = EStatus.Succeed;
}
public override void SendRequest(params object[] param)
{
}
public override void Update()
{
}
public override void Abort()
{
}
}
}

View File

@ -1,39 +1,41 @@

using System.IO;
using UnityEngine;
using UnityEngine.Networking;
namespace YooAsset
{
internal abstract class DownloaderBase
{
protected enum ESteps
public enum EStatus
{
None,
CheckTempFile,
WaitingCheckTempFile,
PrepareDownload,
CreateResumeDownloader,
CreateGeneralDownloader,
CheckDownload,
VerifyTempFile,
WaitingVerifyTempFile,
CachingFile,
TryAgain,
None = 0,
Succeed,
Failed,
Failed
}
protected readonly BundleInfo _bundleInfo;
protected ESteps _steps = ESteps.None;
protected int _timeout;
protected readonly int _timeout;
protected int _failedTryAgain;
protected int _requestCount;
protected string _requestURL;
protected UnityWebRequest _webRequest;
protected EStatus _status = EStatus.None;
protected string _lastError = string.Empty;
protected long _lastCode = 0;
// 请求次数
protected int _requestCount = 0;
protected string _requestURL;
// 下载进度
protected float _downloadProgress = 0f;
protected ulong _downloadedBytes = 0;
// 超时相关
protected bool _isAbort = false;
protected ulong _latestDownloadBytes;
protected float _latestDownloadRealtime;
protected float _tryAgainTimer;
/// <summary>
/// 是否等待异步结束
/// 警告只能用于解压APP内部资源
@ -57,41 +59,31 @@ namespace YooAsset
}
public DownloaderBase(BundleInfo bundleInfo)
public DownloaderBase(BundleInfo bundleInfo, int failedTryAgain, int timeout)
{
_bundleInfo = bundleInfo;
_failedTryAgain = failedTryAgain;
_timeout = timeout;
}
public void SendRequest(int failedTryAgain, int timeout)
{
if (_steps == ESteps.None)
{
_failedTryAgain = failedTryAgain;
_timeout = timeout;
_steps = ESteps.CheckTempFile;
}
}
public abstract void SendRequest(params object[] param);
public abstract void Update();
public abstract void Abort();
/// <summary>
/// 获取网络请求地址
/// 获取下载文件的大小
/// </summary>
protected string GetRequestURL()
/// <returns></returns>
public long GetDownloadFileSize()
{
// 轮流返回请求地址
_requestCount++;
if (_requestCount % 2 == 0)
return _bundleInfo.RemoteFallbackURL;
else
return _bundleInfo.RemoteMainURL;
return _bundleInfo.Bundle.FileSize;
}
/// <summary>
/// 获取资源包信息
/// 获取下载文件的资源包名
/// </summary>
public BundleInfo GetBundleInfo()
public string GetDownloadBundleName()
{
return _bundleInfo;
return _bundleInfo.Bundle.BundleName;
}
/// <summary>
@ -99,7 +91,7 @@ namespace YooAsset
/// </summary>
public bool IsDone()
{
return _steps == ESteps.Succeed || _steps == ESteps.Failed;
return _status == EStatus.Succeed || _status == EStatus.Failed;
}
/// <summary>
@ -107,7 +99,7 @@ namespace YooAsset
/// </summary>
public bool HasError()
{
return _steps == ESteps.Failed;
return _status == EStatus.Failed;
}
/// <summary>
@ -133,5 +125,69 @@ namespace YooAsset
{
return $"Failed to download : {_requestURL} Error : {_lastError} Code : {_lastCode}";
}
/// <summary>
/// 获取网络请求地址
/// </summary>
protected string GetRequestURL()
{
// 轮流返回请求地址
_requestCount++;
if (_requestCount % 2 == 0)
return _bundleInfo.RemoteFallbackURL;
else
return _bundleInfo.RemoteMainURL;
}
/// <summary>
/// 超时判定方法
/// </summary>
protected void CheckTimeout()
{
// 注意:在连续时间段内无新增下载数据及判定为超时
if (_isAbort == false)
{
if (_latestDownloadBytes != DownloadedBytes)
{
_latestDownloadBytes = DownloadedBytes;
_latestDownloadRealtime = Time.realtimeSinceStartup;
}
float offset = Time.realtimeSinceStartup - _latestDownloadRealtime;
if (offset > _timeout)
{
YooLogger.Warning($"Web file request timeout : {_requestURL}");
_webRequest.Abort();
_isAbort = true;
}
}
}
/// <summary>
/// 缓存下载文件
/// </summary>
protected void CachingFile(string tempFilePath)
{
string infoFilePath = _bundleInfo.Bundle.CachedInfoFilePath;
string dataFilePath = _bundleInfo.Bundle.CachedDataFilePath;
string dataFileCRC = _bundleInfo.Bundle.FileCRC;
long dataFileSize = _bundleInfo.Bundle.FileSize;
if (File.Exists(infoFilePath))
File.Delete(infoFilePath);
if (File.Exists(dataFilePath))
File.Delete(dataFilePath);
FileInfo fileInfo = new FileInfo(tempFilePath);
fileInfo.MoveTo(dataFilePath);
// 写入信息文件记录验证数据
CacheFileInfo.WriteInfoToFile(infoFilePath, dataFileCRC, dataFileSize);
// 记录缓存文件
var wrapper = new PackageCache.RecordWrapper(infoFilePath, dataFilePath, dataFileCRC, dataFileSize);
CacheSystem.RecordFile(_bundleInfo.Bundle.PackageName, _bundleInfo.Bundle.CacheGUID, wrapper);
}
}
}

View File

@ -0,0 +1,229 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.Networking;
namespace YooAsset
{
/// <summary>
/// 普通的下载器
/// </summary>
internal sealed class FileGeneralDownloader : DownloaderBase
{
private enum ESteps
{
None,
PrepareDownload,
CreateDownloader,
CheckDownload,
VerifyTempFile,
WaitingVerifyTempFile,
CachingFile,
TryAgain,
Done,
}
private readonly string _tempFilePath;
private VerifyTempFileOperation _verifyFileOp = null;
private ESteps _steps = ESteps.None;
public FileGeneralDownloader(BundleInfo bundleInfo, int failedTryAgain, int timeout) : base(bundleInfo, failedTryAgain, timeout)
{
_tempFilePath = bundleInfo.Bundle.TempDataFilePath;
}
public override void SendRequest(params object[] param)
{
if (_steps == ESteps.None)
{
_steps = ESteps.PrepareDownload;
}
}
public override void Update()
{
if (_steps == ESteps.None)
return;
if (IsDone())
return;
// 准备下载
if (_steps == ESteps.PrepareDownload)
{
// 获取请求地址
_requestURL = GetRequestURL();
// 重置变量
_downloadProgress = 0f;
_downloadedBytes = 0;
// 重置变量
_isAbort = false;
_latestDownloadBytes = 0;
_latestDownloadRealtime = Time.realtimeSinceStartup;
// 重置计时器
if(_tryAgainTimer > 0f)
YooLogger.Warning($"Try again download : {_requestURL}");
_tryAgainTimer = 0f;
// 删除临时文件
if (File.Exists(_tempFilePath))
File.Delete(_tempFilePath);
_steps = ESteps.CreateDownloader;
}
// 创建下载器
if (_steps == ESteps.CreateDownloader)
{
_webRequest = DownloadSystem.NewRequest(_requestURL);
DownloadHandlerFile handler = new DownloadHandlerFile(_tempFilePath);
handler.removeFileOnAbort = true;
_webRequest.downloadHandler = handler;
_webRequest.disposeDownloadHandlerOnDispose = true;
_webRequest.SendWebRequest();
_steps = ESteps.CheckDownload;
}
// 检测下载结果
if (_steps == ESteps.CheckDownload)
{
_downloadProgress = _webRequest.downloadProgress;
_downloadedBytes = _webRequest.downloadedBytes;
if (_webRequest.isDone == false)
{
CheckTimeout();
return;
}
bool hasError = false;
// 检查网络错误
#if UNITY_2020_3_OR_NEWER
if (_webRequest.result != UnityWebRequest.Result.Success)
{
hasError = true;
_lastError = _webRequest.error;
_lastCode = _webRequest.responseCode;
}
#else
if (_webRequest.isNetworkError || _webRequest.isHttpError)
{
hasError = true;
_lastError = _webRequest.error;
_lastCode = _webRequest.responseCode;
}
#endif
// 如果网络异常
if (hasError)
{
// 下载失败之后删除文件
if (File.Exists(_tempFilePath))
File.Delete(_tempFilePath);
_steps = ESteps.TryAgain;
}
else
{
_steps = ESteps.VerifyTempFile;
}
// 最终释放下载器
DisposeWebRequest();
}
// 验证下载文件
if (_steps == ESteps.VerifyTempFile)
{
VerifyTempFileElement element = new VerifyTempFileElement(_bundleInfo.Bundle.TempDataFilePath, _bundleInfo.Bundle.FileCRC, _bundleInfo.Bundle.FileSize);
_verifyFileOp = VerifyTempFileOperation.CreateOperation(element);
OperationSystem.StartOperation(_verifyFileOp);
_steps = ESteps.WaitingVerifyTempFile;
}
// 等待验证完成
if (_steps == ESteps.WaitingVerifyTempFile)
{
if (WaitForAsyncComplete)
_verifyFileOp.Update();
if (_verifyFileOp.IsDone == false)
return;
if (_verifyFileOp.Status == EOperationStatus.Succeed)
{
_steps = ESteps.CachingFile;
}
else
{
if (File.Exists(_tempFilePath))
File.Delete(_tempFilePath);
_lastError = _verifyFileOp.Error;
_steps = ESteps.TryAgain;
}
}
// 缓存下载文件
if (_steps == ESteps.CachingFile)
{
try
{
CachingFile(_tempFilePath);
_status = EStatus.Succeed;
_steps = ESteps.Done;
_lastError = string.Empty;
_lastCode = 0;
}
catch (Exception e)
{
_lastError = e.Message;
_steps = ESteps.TryAgain;
}
}
// 重新尝试下载
if (_steps == ESteps.TryAgain)
{
if (_failedTryAgain <= 0)
{
ReportError();
_status = EStatus.Failed;
_steps = ESteps.Done;
return;
}
_tryAgainTimer += Time.unscaledDeltaTime;
if (_tryAgainTimer > 1f)
{
_failedTryAgain--;
_steps = ESteps.PrepareDownload;
ReportWarning();
}
}
}
public override void Abort()
{
if (IsDone() == false)
{
_status = EStatus.Failed;
_steps = ESteps.Done;
_lastError = "user abort";
_lastCode = 0;
DisposeWebRequest();
}
}
private void DisposeWebRequest()
{
if (_webRequest != null)
{
_webRequest.Dispose();
_webRequest = null;
}
}
}
}

View File

@ -7,28 +7,47 @@ using UnityEngine.Networking;
namespace YooAsset
{
internal sealed class FileDownloader : DownloaderBase
/// <summary>
/// 断点续传下载器
/// </summary>
internal sealed class FileResumeDownloader : DownloaderBase
{
private readonly bool _breakResume;
private enum ESteps
{
None,
CheckTempFile,
WaitingCheckTempFile,
PrepareDownload,
CreateDownloader,
CheckDownload,
VerifyTempFile,
WaitingVerifyTempFile,
CachingFile,
TryAgain,
Done,
}
private readonly string _tempFilePath;
private UnityWebRequest _webRequest = null;
private DownloadHandlerFileRange _downloadHandle = null;
private VerifyTempFileOperation _checkFileOp = null;
private VerifyTempFileOperation _verifyFileOp = null;
private ESteps _steps = ESteps.None;
// 重置变量
private bool _isAbort = false;
private ulong _fileOriginLength;
private ulong _latestDownloadBytes;
private float _latestDownloadRealtime;
private float _tryAgainTimer;
public FileDownloader(BundleInfo bundleInfo, bool breakResume) : base(bundleInfo)
public FileResumeDownloader(BundleInfo bundleInfo, int failedTryAgain, int timeout) : base(bundleInfo, failedTryAgain, timeout)
{
_breakResume = breakResume;
_tempFilePath = bundleInfo.Bundle.TempDataFilePath;
}
public override void SendRequest(params object[] param)
{
if (_steps == ESteps.None)
{
_steps = ESteps.CheckTempFile;
}
}
public override void Update()
{
if (_steps == ESteps.None)
@ -39,7 +58,7 @@ namespace YooAsset
// 检测临时文件
if (_steps == ESteps.CheckTempFile)
{
VerifyTempElement element = new VerifyTempElement(_bundleInfo.Bundle.TempDataFilePath, _bundleInfo.Bundle.FileCRC, _bundleInfo.Bundle.FileSize);
VerifyTempFileElement element = new VerifyTempFileElement(_bundleInfo.Bundle.TempDataFilePath, _bundleInfo.Bundle.FileCRC, _bundleInfo.Bundle.FileSize);
_checkFileOp = VerifyTempFileOperation.CreateOperation(element);
OperationSystem.StartOperation(_checkFileOp);
_steps = ESteps.WaitingCheckTempFile;
@ -72,48 +91,29 @@ namespace YooAsset
// 创建下载器
if (_steps == ESteps.PrepareDownload)
{
// 重置变量
_downloadProgress = 0f;
_downloadedBytes = 0;
_isAbort = false;
_fileOriginLength = 0;
_latestDownloadBytes = 0;
_latestDownloadRealtime = Time.realtimeSinceStartup;
_tryAgainTimer = 0f;
// 获取请求地址
_requestURL = GetRequestURL();
if (_breakResume)
_steps = ESteps.CreateResumeDownloader;
else
_steps = ESteps.CreateGeneralDownloader;
// 重置变量
_downloadProgress = 0f;
_downloadedBytes = 0;
// 重置变量
_isAbort = false;
_latestDownloadBytes = 0;
_latestDownloadRealtime = Time.realtimeSinceStartup;
_fileOriginLength = 0;
// 重置计时器
if (_tryAgainTimer > 0f)
YooLogger.Warning($"Try again download : {_requestURL}");
_tryAgainTimer = 0f;
_steps = ESteps.CreateDownloader;
}
// 创建普通的下载器
if (_steps == ESteps.CreateGeneralDownloader)
{
if (File.Exists(_tempFilePath))
File.Delete(_tempFilePath);
_webRequest = DownloadSystem.NewRequest(_requestURL);
DownloadHandlerFile handler = new DownloadHandlerFile(_tempFilePath);
handler.removeFileOnAbort = true;
_webRequest.downloadHandler = handler;
_webRequest.disposeDownloadHandlerOnDispose = true;
if (DownloadSystem.CertificateHandlerInstance != null)
{
_webRequest.certificateHandler = DownloadSystem.CertificateHandlerInstance;
_webRequest.disposeCertificateHandlerOnDispose = false;
}
_webRequest.SendWebRequest();
_steps = ESteps.CheckDownload;
}
// 创建断点续传下载器
if (_steps == ESteps.CreateResumeDownloader)
// 创建下载器
if (_steps == ESteps.CreateDownloader)
{
long fileLength = -1;
if (File.Exists(_tempFilePath))
@ -137,13 +137,6 @@ namespace YooAsset
_webRequest.disposeDownloadHandlerOnDispose = true;
if (fileLength > 0)
_webRequest.SetRequestHeader("Range", $"bytes={fileLength}-");
if (DownloadSystem.CertificateHandlerInstance != null)
{
_webRequest.certificateHandler = DownloadSystem.CertificateHandlerInstance;
_webRequest.disposeCertificateHandlerOnDispose = false;
}
_webRequest.SendWebRequest();
_steps = ESteps.CheckDownload;
}
@ -181,24 +174,15 @@ namespace YooAsset
// 如果网络异常
if (hasError)
{
if (_breakResume)
// 注意:下载断点续传文件发生特殊错误码之后删除文件
if (DownloadSystem.ClearFileResponseCodes != null)
{
// 注意:下载断点续传文件发生特殊错误码之后删除文件
if (DownloadSystem.ClearFileResponseCodes != null)
if (DownloadSystem.ClearFileResponseCodes.Contains(_webRequest.responseCode))
{
if (DownloadSystem.ClearFileResponseCodes.Contains(_webRequest.responseCode))
{
if (File.Exists(_tempFilePath))
File.Delete(_tempFilePath);
}
if (File.Exists(_tempFilePath))
File.Delete(_tempFilePath);
}
}
else
{
// 注意:非断点续传下载失败之后删除文件
if (File.Exists(_tempFilePath))
File.Delete(_tempFilePath);
}
_steps = ESteps.TryAgain;
}
@ -207,14 +191,14 @@ namespace YooAsset
_steps = ESteps.VerifyTempFile;
}
// 释放下载器
// 最终释放下载器
DisposeWebRequest();
}
// 验证下载文件
if (_steps == ESteps.VerifyTempFile)
{
VerifyTempElement element = new VerifyTempElement(_bundleInfo.Bundle.TempDataFilePath, _bundleInfo.Bundle.FileCRC, _bundleInfo.Bundle.FileSize);
VerifyTempFileElement element = new VerifyTempFileElement(_bundleInfo.Bundle.TempDataFilePath, _bundleInfo.Bundle.FileCRC, _bundleInfo.Bundle.FileSize);
_verifyFileOp = VerifyTempFileOperation.CreateOperation(element);
OperationSystem.StartOperation(_verifyFileOp);
_steps = ESteps.WaitingVerifyTempFile;
@ -248,29 +232,11 @@ namespace YooAsset
{
try
{
string infoFilePath = _bundleInfo.Bundle.CachedInfoFilePath;
string dataFilePath = _bundleInfo.Bundle.CachedDataFilePath;
string dataFileCRC = _bundleInfo.Bundle.FileCRC;
long dataFileSize = _bundleInfo.Bundle.FileSize;
if (File.Exists(infoFilePath))
File.Delete(infoFilePath);
if (File.Exists(dataFilePath))
File.Delete(dataFilePath);
FileInfo fileInfo = new FileInfo(_tempFilePath);
fileInfo.MoveTo(dataFilePath);
// 写入信息文件记录验证数据
CacheFileInfo.WriteInfoToFile(infoFilePath, dataFileCRC, dataFileSize);
// 记录缓存文件
var wrapper = new PackageCache.RecordWrapper(infoFilePath, dataFilePath, dataFileCRC, dataFileSize);
CacheSystem.RecordFile(_bundleInfo.Bundle.PackageName, _bundleInfo.Bundle.CacheGUID, wrapper);
CachingFile(_tempFilePath);
_status = EStatus.Succeed;
_steps = ESteps.Done;
_lastError = string.Empty;
_lastCode = 0;
_steps = ESteps.Succeed;
}
catch (Exception e)
{
@ -285,7 +251,8 @@ namespace YooAsset
if (_failedTryAgain <= 0)
{
ReportError();
_steps = ESteps.Failed;
_status = EStatus.Failed;
_steps = ESteps.Done;
return;
}
@ -295,7 +262,6 @@ namespace YooAsset
_failedTryAgain--;
_steps = ESteps.PrepareDownload;
ReportWarning();
YooLogger.Warning($"Try again download : {_requestURL}");
}
}
}
@ -303,33 +269,14 @@ namespace YooAsset
{
if (IsDone() == false)
{
_steps = ESteps.Failed;
_status = EStatus.Failed;
_steps = ESteps.Done;
_lastError = "user abort";
_lastCode = 0;
DisposeWebRequest();
}
}
private void CheckTimeout()
{
// 注意:在连续时间段内无新增下载数据及判定为超时
if (_isAbort == false)
{
if (_latestDownloadBytes != DownloadedBytes)
{
_latestDownloadBytes = DownloadedBytes;
_latestDownloadRealtime = Time.realtimeSinceStartup;
}
float offset = Time.realtimeSinceStartup - _latestDownloadRealtime;
if (offset > _timeout)
{
YooLogger.Warning($"Web file request timeout : {_requestURL}");
_webRequest.Abort();
_isAbort = true;
}
}
}
private void DisposeWebRequest()
{
if (_downloadHandle != null)

View File

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

View File

@ -1,20 +0,0 @@

namespace YooAsset
{
internal sealed class TempDownloader : DownloaderBase
{
public TempDownloader(BundleInfo bundleInfo) : base(bundleInfo)
{
_downloadProgress = 1f;
_downloadedBytes = (ulong)bundleInfo.Bundle.FileSize;
_steps = ESteps.Succeed;
}
public override void Update()
{
}
public override void Abort()
{
}
}
}

View File

@ -0,0 +1,211 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.Networking;
namespace YooAsset
{
internal sealed class WebDownloader : DownloaderBase
{
private enum ESteps
{
None,
PrepareDownload,
CreateDownloader,
CheckDownload,
VerifyTempFile,
WaitingVerifyTempFile,
CachingFile,
TryAgain,
Done,
}
private DownloadHandlerAssetBundle _downloadhandler;
private ESteps _steps = ESteps.None;
private bool _getAssetBundle = false;
private AssetBundle _cacheAssetBundle;
public WebDownloader(BundleInfo bundleInfo, int failedTryAgain, int timeout) : base(bundleInfo, failedTryAgain, timeout)
{
}
public override void SendRequest(params object[] param)
{
if (_steps == ESteps.None)
{
if (param.Length > 0)
{
_getAssetBundle = (bool)param[0];
}
_steps = ESteps.PrepareDownload;
}
}
public override void Update()
{
if (_steps == ESteps.None)
return;
if (IsDone())
return;
// 创建下载器
if (_steps == ESteps.PrepareDownload)
{
// 重置变量
_downloadProgress = 0f;
_downloadedBytes = 0;
// 重置变量
_isAbort = false;
_latestDownloadBytes = 0;
_latestDownloadRealtime = Time.realtimeSinceStartup;
_tryAgainTimer = 0f;
// 获取请求地址
_requestURL = GetRequestURL();
_steps = ESteps.CreateDownloader;
}
// 创建下载器
if (_steps == ESteps.CreateDownloader)
{
_webRequest = DownloadSystem.NewRequest(_requestURL);
if (CacheSystem.DisableUnityCacheOnWebGL)
{
uint crc = _bundleInfo.Bundle.UnityCRC;
_downloadhandler = new DownloadHandlerAssetBundle(_requestURL, crc);
#if UNITY_2020_3_OR_NEWER
_downloadhandler.autoLoadAssetBundle = false;
#endif
}
else
{
uint crc = _bundleInfo.Bundle.UnityCRC;
var hash = Hash128.Parse(_bundleInfo.Bundle.FileHash);
_downloadhandler = new DownloadHandlerAssetBundle(_requestURL, hash, crc);
#if UNITY_2020_3_OR_NEWER
_downloadhandler.autoLoadAssetBundle = false;
#endif
}
_webRequest.downloadHandler = _downloadhandler;
_webRequest.disposeDownloadHandlerOnDispose = false;
_webRequest.SendWebRequest();
_steps = ESteps.CheckDownload;
}
// 检测下载结果
if (_steps == ESteps.CheckDownload)
{
_downloadProgress = _webRequest.downloadProgress;
_downloadedBytes = _webRequest.downloadedBytes;
if (_webRequest.isDone == false)
{
CheckTimeout();
return;
}
bool hasError = false;
// 检查网络错误
#if UNITY_2020_3_OR_NEWER
if (_webRequest.result != UnityWebRequest.Result.Success)
{
hasError = true;
_lastError = _webRequest.error;
_lastCode = _webRequest.responseCode;
}
#else
if (_webRequest.isNetworkError || _webRequest.isHttpError)
{
hasError = true;
_lastError = _webRequest.error;
_lastCode = _webRequest.responseCode;
}
#endif
// 如果网络异常
if (hasError)
{
_steps = ESteps.TryAgain;
}
else
{
_status = EStatus.Succeed;
_steps = ESteps.Done;
_lastError = string.Empty;
_lastCode = 0;
}
if (_getAssetBundle)
{
_cacheAssetBundle = _downloadhandler.assetBundle;
if (_cacheAssetBundle == null)
{
_lastError = "assetBundle is null";
_steps = ESteps.TryAgain;
}
}
// 最终释放请求
DisposeRequest();
}
// 重新尝试下载
if (_steps == ESteps.TryAgain)
{
if (_failedTryAgain <= 0)
{
DisposeRequest();
ReportError();
_status = EStatus.Failed;
_steps = ESteps.Done;
return;
}
_tryAgainTimer += Time.unscaledDeltaTime;
if (_tryAgainTimer > 1f)
{
_failedTryAgain--;
_steps = ESteps.PrepareDownload;
ReportWarning();
YooLogger.Warning($"Try again download : {_requestURL}");
}
}
}
public override void Abort()
{
if (IsDone() == false)
{
_status = EStatus.Failed;
_steps = ESteps.Done;
_lastError = "user abort";
_lastCode = 0;
DisposeRequest();
}
}
private void DisposeRequest()
{
if (_webRequest != null)
{
_webRequest.Dispose();
_webRequest = null;
}
if (_downloadhandler != null)
{
_downloadhandler.Dispose();
_downloadhandler = null;
}
}
/// <summary>
/// 获取资源包
/// </summary>
public AssetBundle GetAssetBundle()
{
return _cacheAssetBundle;
}
}
}

View File

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

View File

@ -0,0 +1,36 @@
using System;
using System.Collections;
using System.Collections.Generic;
namespace YooAsset
{
public class RequestHelper
{
/// <summary>
/// 记录网络请求失败事件的次数
/// </summary>
private static readonly Dictionary<string, int> _requestFailedRecorder = new Dictionary<string, int>(1000);
/// <summary>
/// 记录请求失败事件
/// </summary>
public static void RecordRequestFailed(string packageName, string eventName)
{
string key = $"{packageName}_{eventName}";
if (_requestFailedRecorder.ContainsKey(key) == false)
_requestFailedRecorder.Add(key, 0);
_requestFailedRecorder[key]++;
}
/// <summary>
/// 获取请求失败的次数
/// </summary>
public static int GetRequestFailedCount(string packageName, string eventName)
{
string key = $"{packageName}_{eventName}";
if (_requestFailedRecorder.ContainsKey(key) == false)
_requestFailedRecorder.Add(key, 0);
return _requestFailedRecorder[key];
}
}
}

View File

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

View File

@ -2,38 +2,26 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine.Networking;
using UnityEngine;
namespace YooAsset
{
/// <summary>
/// 下载器
/// 说明UnityWebRequest(UWR) supports reading streaming assets since 2017.1
/// </summary>
internal class UnityWebDataRequester
internal class UnityWebDataRequester : UnityWebRequesterBase
{
private UnityWebRequest _webRequest;
private UnityWebRequestAsyncOperation _operationHandle;
/// <summary>
/// 请求URL地址
/// </summary>
public string URL { private set; get; }
/// <summary>
/// 发送GET请求
/// </summary>
/// <param name="timeout">超时:从请求开始计时</param>
public void SendRequest(string url, int timeout = 0)
public void SendRequest(string url, int timeout = 60)
{
if (_webRequest == null)
{
URL = url;
ResetTimeout(timeout);
_webRequest = DownloadSystem.NewRequest(URL);
DownloadHandlerBuffer handler = new DownloadHandlerBuffer();
_webRequest.downloadHandler = handler;
_webRequest.disposeDownloadHandlerOnDispose = true;
_webRequest.timeout = timeout;
_operationHandle = _webRequest.SendWebRequest();
}
}
@ -59,65 +47,5 @@ namespace YooAsset
else
return null;
}
/// <summary>
/// 释放下载器
/// </summary>
public void Dispose()
{
if (_webRequest != null)
{
_webRequest.Dispose();
_webRequest = null;
_operationHandle = null;
}
}
/// <summary>
/// 是否完毕(无论成功失败)
/// </summary>
public bool IsDone()
{
if (_operationHandle == null)
return false;
return _operationHandle.isDone;
}
/// <summary>
/// 下载进度
/// </summary>
public float Progress()
{
if (_operationHandle == null)
return 0;
return _operationHandle.progress;
}
/// <summary>
/// 下载是否发生错误
/// </summary>
public bool HasError()
{
#if UNITY_2020_3_OR_NEWER
return _webRequest.result != UnityWebRequest.Result.Success;
#else
if (_webRequest.isNetworkError || _webRequest.isHttpError)
return true;
else
return false;
#endif
}
/// <summary>
/// 获取错误信息
/// </summary>
public string GetError()
{
if (_webRequest != null)
{
return $"URL : {URL} Error : {_webRequest.error}";
}
return string.Empty;
}
}
}

View File

@ -6,129 +6,25 @@ using UnityEngine;
namespace YooAsset
{
/// <summary>
/// 下载器
/// 说明UnityWebRequest(UWR) supports reading streaming assets since 2017.1
/// </summary>
internal class UnityWebFileRequester
internal class UnityWebFileRequester : UnityWebRequesterBase
{
private UnityWebRequest _webRequest;
private UnityWebRequestAsyncOperation _operationHandle;
// 超时相关
private float _timeout;
private bool _isAbort = false;
private ulong _latestDownloadBytes;
private float _latestDownloadRealtime;
/// <summary>
/// 请求URL地址
/// </summary>
public string URL { private set; get; }
/// <summary>
/// 发送GET请求
/// </summary>
public void SendRequest(string url, string savePath, float timeout = 60)
public void SendRequest(string url, string fileSavePath, int timeout = 60)
{
if (_webRequest == null)
{
URL = url;
_timeout = timeout;
_latestDownloadBytes = 0;
_latestDownloadRealtime = Time.realtimeSinceStartup;
ResetTimeout(timeout);
_webRequest = DownloadSystem.NewRequest(URL);
DownloadHandlerFile handler = new DownloadHandlerFile(savePath);
DownloadHandlerFile handler = new DownloadHandlerFile(fileSavePath);
handler.removeFileOnAbort = true;
_webRequest.downloadHandler = handler;
_webRequest.disposeDownloadHandlerOnDispose = true;
_operationHandle = _webRequest.SendWebRequest();
}
}
/// <summary>
/// 释放下载器
/// </summary>
public void Dispose()
{
if (_webRequest != null)
{
_webRequest.Dispose();
_webRequest = null;
_operationHandle = null;
}
}
/// <summary>
/// 是否完毕(无论成功失败)
/// </summary>
public bool IsDone()
{
if (_operationHandle == null)
return false;
return _operationHandle.isDone;
}
/// <summary>
/// 下载进度
/// </summary>
public float Progress()
{
if (_operationHandle == null)
return 0;
return _operationHandle.progress;
}
/// <summary>
/// 下载是否发生错误
/// </summary>
public bool HasError()
{
#if UNITY_2020_3_OR_NEWER
return _webRequest.result != UnityWebRequest.Result.Success;
#else
if (_webRequest.isNetworkError || _webRequest.isHttpError)
return true;
else
return false;
#endif
}
/// <summary>
/// 获取错误信息
/// </summary>
public string GetError()
{
if (_webRequest != null)
{
return $"URL : {URL} Error : {_webRequest.error}";
}
return string.Empty;
}
/// <summary>
/// 检测超时
/// </summary>
public void CheckTimeout()
{
// 注意:在连续时间段内无新增下载数据及判定为超时
if (_isAbort == false)
{
if (_latestDownloadBytes != _webRequest.downloadedBytes)
{
_latestDownloadBytes = _webRequest.downloadedBytes;
_latestDownloadRealtime = Time.realtimeSinceStartup;
}
float offset = Time.realtimeSinceStartup - _latestDownloadRealtime;
if (offset > _timeout)
{
_webRequest.Abort();
_isAbort = true;
}
}
}
}
}
}

View File

@ -0,0 +1,116 @@
using System;
using System.Collections;
using System.Collections.Concurrent;
using UnityEngine.Networking;
using UnityEngine;
namespace YooAsset
{
internal abstract class UnityWebRequesterBase
{
protected UnityWebRequest _webRequest;
protected UnityWebRequestAsyncOperation _operationHandle;
// 超时相关
private float _timeout;
private bool _isAbort = false;
private ulong _latestDownloadBytes;
private float _latestDownloadRealtime;
/// <summary>
/// 请求URL地址
/// </summary>
public string URL { protected set; get; }
protected void ResetTimeout(float timeout)
{
_timeout = timeout;
_latestDownloadBytes = 0;
_latestDownloadRealtime = Time.realtimeSinceStartup;
}
/// <summary>
/// 释放下载器
/// </summary>
public void Dispose()
{
if (_webRequest != null)
{
_webRequest.Dispose();
_webRequest = null;
_operationHandle = null;
}
}
/// <summary>
/// 是否完毕(无论成功失败)
/// </summary>
public bool IsDone()
{
if (_operationHandle == null)
return false;
return _operationHandle.isDone;
}
/// <summary>
/// 下载进度
/// </summary>
public float Progress()
{
if (_operationHandle == null)
return 0;
return _operationHandle.progress;
}
/// <summary>
/// 下载是否发生错误
/// </summary>
public bool HasError()
{
#if UNITY_2020_3_OR_NEWER
return _webRequest.result != UnityWebRequest.Result.Success;
#else
if (_webRequest.isNetworkError || _webRequest.isHttpError)
return true;
else
return false;
#endif
}
/// <summary>
/// 获取错误信息
/// </summary>
public string GetError()
{
if (_webRequest != null)
{
return $"URL : {URL} Error : {_webRequest.error}";
}
return string.Empty;
}
/// <summary>
/// 检测超时
/// </summary>
public void CheckTimeout()
{
// 注意:在连续时间段内无新增下载数据及判定为超时
if (_isAbort == false)
{
if (_latestDownloadBytes != _webRequest.downloadedBytes)
{
_latestDownloadBytes = _webRequest.downloadedBytes;
_latestDownloadRealtime = Time.realtimeSinceStartup;
}
float offset = Time.realtimeSinceStartup - _latestDownloadRealtime;
if (offset > _timeout)
{
_webRequest.Abort();
_isAbort = true;
}
}
}
}
}

View File

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

View File

@ -20,6 +20,11 @@ namespace YooAsset
/// 联机运行模式
/// </summary>
HostPlayMode,
/// <summary>
/// WebGL运行模式
/// </summary>
WebPlayMode,
}
/// <summary>
@ -32,6 +37,18 @@ namespace YooAsset
/// </summary>
public IDecryptionServices DecryptionServices = null;
/// <summary>
/// 内置文件的根路径
/// 注意:当参数为空的时候会使用默认的根目录。
/// </summary>
public string BuildinRootDirectory = string.Empty;
/// <summary>
/// 沙盒文件的根路径
/// 注意:当参数为空的时候会使用默认的根目录。
/// </summary>
public string SandboxRootDirectory = string.Empty;
/// <summary>
/// 资源加载每帧处理的最大时间片段
/// 注意默认值为MaxValue
@ -69,18 +86,34 @@ namespace YooAsset
public class HostPlayModeParameters : InitializeParameters
{
/// <summary>
/// 默认的资源服务器下载地址
/// 内置资源查询服务接口
/// </summary>
public string DefaultHostServer = string.Empty;
public IBuildinQueryServices BuildinQueryServices = null;
/// <summary>
/// 备用的资源服务器下载地址
/// 分发资源查询服务接口
/// </summary>
public string FallbackHostServer = string.Empty;
public IDeliveryQueryServices DeliveryQueryServices = null;
/// <summary>
/// 远端资源地址查询服务类
/// </summary>
public IRemoteServices RemoteServices = null;
}
/// <summary>
/// WebGL运行模式的初始化参数
/// </summary>
public class WebPlayModeParameters : InitializeParameters
{
/// <summary>
/// 内置资源查询服务接口
/// </summary>
public IQueryServices QueryServices = null;
public IBuildinQueryServices BuildinQueryServices = null;
/// <summary>
/// 远端资源地址查询服务类
/// </summary>
public IRemoteServices RemoteServices = null;
}
}

View File

@ -73,13 +73,18 @@ namespace YooAsset
internal abstract void Start();
internal abstract void Update();
internal void Finish()
internal void SetFinish()
{
Progress = 1f;
_callback?.Invoke(this);
_callback?.Invoke(this); //注意如果完成回调内发生异常会导致Task无限期等待
if (_taskCompletionSource != null)
_taskCompletionSource.TrySetResult(null);
}
internal void SetStart()
{
Status = EOperationStatus.Processing;
}
/// <summary>
/// 清空完成回调

View File

@ -4,6 +4,7 @@ namespace YooAsset
public enum EOperationStatus
{
None,
Processing,
Succeed,
Failed
}

View File

@ -7,8 +7,7 @@ namespace YooAsset
internal class OperationSystem
{
private static readonly List<AsyncOperationBase> _operations = new List<AsyncOperationBase>(100);
private static readonly List<AsyncOperationBase> _addList = new List<AsyncOperationBase>(100);
private static readonly List<AsyncOperationBase> _removeList = new List<AsyncOperationBase>(100);
private static readonly List<AsyncOperationBase> _newList = new List<AsyncOperationBase>(100);
// 计时器相关
private static Stopwatch _watch;
@ -47,39 +46,26 @@ namespace YooAsset
_frameTime = _watch.ElapsedMilliseconds;
// 添加新的异步操作
if (_addList.Count > 0)
if (_newList.Count > 0)
{
for (int i = 0; i < _addList.Count; i++)
{
var operation = _addList[i];
_operations.Add(operation);
}
_addList.Clear();
_operations.AddRange(_newList);
_newList.Clear();
}
// 更新所有的异步操作
foreach (var operation in _operations)
for (int i = _operations.Count - 1; i >= 0; i--)
{
if (IsBusy)
break;
var operation = _operations[i];
operation.Update();
if (operation.IsDone)
{
_removeList.Add(operation);
operation.Finish();
_operations.RemoveAt(i);
operation.SetFinish(); //注意:如果业务端发生异常,保证异步操作提前移除。
}
}
// 移除已经完成的异步操作
if (_removeList.Count > 0)
{
foreach (var operation in _removeList)
{
_operations.Remove(operation);
}
_removeList.Clear();
}
}
/// <summary>
@ -88,8 +74,7 @@ namespace YooAsset
public static void DestroyAll()
{
_operations.Clear();
_addList.Clear();
_removeList.Clear();
_newList.Clear();
_watch = null;
_frameTime = 0;
MaxTimeSlice = long.MaxValue;
@ -100,7 +85,8 @@ namespace YooAsset
/// </summary>
public static void StartOperation(AsyncOperationBase operation)
{
_addList.Add(operation);
_newList.Add(operation);
operation.SetStart();
operation.Start();
}
}

View File

@ -28,9 +28,9 @@ namespace YooAsset
return _providerGUID;
if (AssetType == null)
_providerGUID = $"{AssetPath}[null]";
_providerGUID = $"[{AssetPath}][null]";
else
_providerGUID = $"{AssetPath}[{AssetType.Name}]";
_providerGUID = $"[{AssetPath}][{AssetType.Name}]";
return _providerGUID;
}
}

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