Compare commits

...

69 Commits
1.2.2 ... 1.2.4

Author SHA1 Message Date
hevinci
39c277b090 Update CHANGELOG.md 2022-09-22 15:07:39 +08:00
hevinci
81e6aab53d Update package.json 2022-09-22 15:07:09 +08:00
hevinci
7c1e1ab593 Update Basic Sample 2022-09-22 14:29:24 +08:00
hevinci
2381b67312 Update BasicSamples 2022-09-22 14:18:54 +08:00
hevinci
ca83a4450d Update Basic Samples 2022-09-22 11:42:13 +08:00
hevinci
8cec0abf0e Update AssetBundleCollector
增加配置表自我修复功能。
2022-09-22 11:40:30 +08:00
hevinci
a89127df1d Update YooAssetDriver
在游戏对象销毁的时候释放YooAssets
2022-09-21 11:36:28 +08:00
hevinci
95924868f7 Update AssetBundleCollector
移除对Gizmos资源的打包限制。
2022-09-21 11:21:13 +08:00
hevinci
778b097f7a Update TaskCreateReport.cs 2022-09-21 11:20:41 +08:00
hevinci
3a7f3bb68d Update AssetBundleBuilder
修复在可编程构建管线下模拟构建模式报错。
2022-09-21 11:20:32 +08:00
hevinci
02b9b689b7 Update AssetBundleBuilder
可编程构建管线强制使用增量构建模式。
2022-09-21 11:18:38 +08:00
hevinci
3882fe9f3f Update Samples.md 2022-09-16 11:16:22 +08:00
hevinci
af29cb738d Update AssetBundleBuilder
对内置管线构建结果做容错处理
2022-09-14 17:36:41 +08:00
hevinci
4975d3b1ba Update AssetBundleBuilder
修复加密文件下载验证失败问题。
2022-09-13 11:48:57 +08:00
hevinci
fb4910e265 Update CHANGELOG.md 2022-09-09 16:29:55 +08:00
hevinci
9ccaba480a Update package.json 2022-09-09 16:29:49 +08:00
hevinci
97a7624b94 Update HttpDownloader.cs 2022-09-09 15:15:58 +08:00
hevinci
d697ebe521 Update YooAssets
在更新资源清单之前检查已加载资源包并给与警告。
2022-09-08 17:04:39 +08:00
hevinci
6df57cd3cd Update YooAssetSetting
增加文件过滤配置
2022-09-08 15:55:35 +08:00
hevinci
3f518ec321 Update PatchSystem
增加清理缓存资源的异步操作类
2022-09-06 18:19:50 +08:00
hevinci
f112f18723 Update document 2022-09-06 14:52:50 +08:00
hevinci
ee9389db2c Update README.md 2022-09-06 14:51:10 +08:00
hevinci
769e0199d5 Update document 2022-09-06 14:49:26 +08:00
hevinci
e77dfb5ca3 Update YooAssets.cs 2022-09-06 09:57:48 +08:00
hevinci
53b53eb0a0 Update AssetSystem
加载方法容错提示。
2022-09-05 15:31:26 +08:00
hevinci
ec25af8517 Update download system
完善断点续传下载
2022-09-05 15:06:13 +08:00
hevinci
8d2779b446 Update AssetSystem
HostPlayMode支持WEBGL
2022-09-02 16:28:19 +08:00
hevinci
7e20c39fb3 Update asset system
支持WebGL
2022-08-30 18:04:16 +08:00
hevinci
a9e858bc9a Update cache system 2022-08-30 18:03:20 +08:00
hevinci
d47c0bf4b6 Update AssetBundleCollector
修复无法识别.bank类似音频文件格式。
2022-08-29 12:11:16 +08:00
hevinci
ea99232d3b Update Samples 2022-08-29 12:10:21 +08:00
hevinci
5bd444f9b3 Update document 2022-08-25 14:29:04 +08:00
hevinci
4498fed8be Update document 2022-08-25 14:25:15 +08:00
hevinci
b5c82438a0 Update download system
使用新的断点续传下载器
2022-08-23 15:27:20 +08:00
hevinci
16f8592497 Update AssetBundleCollector 2022-08-22 19:12:55 +08:00
hevinci
fbbf762e70 Update CacheSystem
优化缓存系统代码结构
2022-08-15 11:55:13 +08:00
hevinci
aba68f859f Update AssetBundleBuilder 2022-08-15 10:30:10 +08:00
hevinci
b5be5b60da Update DefaultPackRule.cs
修改了默认的打包规则
2022-08-15 10:29:28 +08:00
hevinci
631547f8c7 Update AssemblyInfo
增加运行时代码扩展支持。
2022-08-12 17:34:12 +08:00
hevinci
a422bcc858 Update AssetSystem 2022-08-12 14:30:23 +08:00
何冠峰
4b11238b6c Merge pull request #35 from LiuOcean/main
Update UniTask Sample
2022-08-10 11:20:54 +08:00
L
c5ca825b25 Update UniTask Sample 2022-08-09 20:49:03 +08:00
hevinci
314c5cd86a Update CacheSystem 2022-08-06 16:40:40 +08:00
hevinci
a1ad7acb3d Update CacheSystem 2022-08-06 16:23:38 +08:00
hevinci
dcd4475617 Fix #34
修复一个拼写错误
2022-08-06 11:23:43 +08:00
hevinci
a6fdb5691a Update PatchSystem
HostPlayMode支持WebGL平台。
2022-08-05 16:24:10 +08:00
hevinci
2ff01d10b0 Update Extension Sample 2022-08-05 14:40:50 +08:00
hevinci
d6e3da322b Update AssetBundleBuilder 2022-08-05 14:40:27 +08:00
hevinci
188957ee91 Update ShaderVariantCollector 2022-08-05 11:18:32 +08:00
何冠峰
706e8601a3 Merge pull request #33 from LiuOcean/main
Update UniTask README Example
2022-08-04 17:43:12 +08:00
L
216949d7a5 Update UniTask README Example 2022-08-03 23:34:18 +08:00
hevinci
7e6c678e91 Update runtime 2022-08-03 20:51:06 +08:00
hevinci
195d1805e9 Update AssetBundleReporter 2022-08-03 20:47:53 +08:00
hevinci
4ea52a9287 Update AssetBundleBuilder 2022-08-03 20:47:43 +08:00
hevinci
1253ce71af Update AssetBundleBuilder
构建结果增加输出的补丁包目录。
2022-08-03 16:39:36 +08:00
hevinci
3401c69729 Update YooAssets 2022-08-03 15:46:45 +08:00
hevinci
68e14a48f1 Update asset setting
不再提供着色器收集选项,已经内置为必定收集。
优化了SBP打包着色器收集系统。
2022-08-03 15:46:27 +08:00
hevinci
5b8a004720 Update AssetBundleBuilder 2022-08-03 15:43:54 +08:00
hevinci
3e716887c9 Update AssetBundleReporter 2022-08-03 15:37:25 +08:00
hevinci
fe95b8ec5d Update AssetBundleCollector 2022-08-03 15:37:01 +08:00
hevinci
e3dcaec9b5 Update AssetBundleCollector 2022-08-02 16:05:22 +08:00
hevinci
b4dfba9a44 Update document 2022-08-02 14:31:07 +08:00
hevinci
e80c715e44 Merge branch 'main' of https://github.com/tuyoogame/YooAsset 2022-08-02 14:30:27 +08:00
hevinci
8b8f44d2a8 Update AssetBundleBuilder 2022-08-02 14:30:25 +08:00
何冠峰
b8b85e30a6 Merge pull request #31 from LiuOcean/main
Update UniTask Sample
2022-08-01 15:01:01 +08:00
L
81b28a0407 Update UniTask Sample 2022-08-01 14:55:24 +08:00
hevinci
cecbb35f1a Update document 2022-08-01 11:54:48 +08:00
hevinci
083c7af361 Update document 2022-08-01 11:51:35 +08:00
hevinci
a7993efeda Update samples 2022-08-01 11:48:15 +08:00
688 changed files with 74541 additions and 1284 deletions

View File

@@ -2,6 +2,46 @@
All notable changes to this package will be documented in this file.
## [1.2.4] - 2022-09-22
### Fixed
- 修复了加密文件下载验证失败的问题。
- 修复了可编程构建管线下模拟构建模式报错的问题。
### Changed
- 可编程构建管线强制使用增量构建模式。
- 移除了对Gizmos资源的打包限制。
- AssetBundleCollector窗口增加配置表修复功能。
## [1.2.3] - 2022-09-09
### Fixed
- 修复了资源收集器无法识别.bank音频文件格式。
### Changed
- **HostPlayMode正式支持WebGL平台。**
- AssetBundleCollector里的着色器收集选项已经移除现在必定收集。
- AssetBundleCollector修改了默认的打包规则类。
- AssetBundleBuilder现在构建结果增加补丁包目录。
- 更新了UniTask的Sample。
- 优化了缓存系统的代码结构。
- 使用了新的断点续传下载器。
### Added
- 增加清理缓存资源的异步操作类。
````c#
/// <summary>
/// 清空未被使用的缓存文件
/// </summary>
public static ClearUnusedCacheFilesOperation ClearUnusedCacheFiles();
````
## [1.2.2] - 2022-07-31
### Fixed

View File

@@ -20,13 +20,19 @@ namespace YooAsset.Editor
// 检测构建参数是否为空
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 (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 !");
}
// 构建参数
@@ -80,6 +86,7 @@ namespace YooAsset.Editor
var buildResult = BuildRunner.Run(pipeline, _buildContext);
if (buildResult.Success)
{
buildResult.OutputPackageDirectory = buildParametersContext.GetPackageDirectory();
Debug.Log($"{buildParameters.BuildMode} pipeline build succeed !");
}
else

View File

@@ -173,14 +173,11 @@ namespace YooAsset.Editor
if (IsRawAsset)
throw new Exception("Should never get here !");
if (AssetBundleCollectorSettingData.Setting.AutoCollectShaders)
if (IsShaderAsset)
{
if (IsShaderAsset)
{
string shareBundleName = $"{AssetBundleCollectorSettingData.Setting.ShadersBundleName}.{YooAssetSettingsData.Setting.AssetBundleFileVariant}";
_shareBundleName = EditorTools.GetRegularPath(shareBundleName).ToLower();
return;
}
string shareBundleName = YooAssetSettingsData.GetUnityShadersBundleFullName();
_shareBundleName = EditorTools.GetRegularPath(shareBundleName).ToLower();
return;
}
if (_referenceBundleNames.Count > 1)

View File

@@ -35,6 +35,11 @@ namespace YooAsset.Editor
}
}
/// <summary>
/// 构建内容哈希值
/// </summary>
public string ContentHash { set; get; } = "00000000000000000000000000000000"; //32位
public BuildBundleInfo(string bundleName)
{

View File

@@ -118,6 +118,4 @@ namespace YooAsset.Editor
return StringUtility.StringToStringList(BuildinTags, ';');
}
}
}

View File

@@ -85,9 +85,6 @@ namespace YooAsset.Editor
if (Parameters.BuildMode == EBuildMode.SimulateBuild)
throw new Exception("Should never get here !");
if (Parameters.BuildMode == EBuildMode.DryRunBuild)
throw new Exception($"SBP not support {nameof(EBuildMode.DryRunBuild)} build mode !");
var targetGroup = BuildPipeline.GetBuildTargetGroup(Parameters.BuildTarget);
var buildParams = new UnityEditor.Build.Pipeline.BundleBuildParameters(Parameters.BuildTarget, targetGroup, PipelineOutputDirectory);
@@ -103,16 +100,9 @@ namespace YooAsset.Editor
if (Parameters.DisableWriteTypeTree)
buildParams.ContentBuildFlags |= UnityEditor.Build.Content.ContentBuildFlags.DisableWriteTypeTree;
if(Parameters.BuildMode == EBuildMode.ForceRebuild)
{
buildParams.UseCache = false;
}
else
{
buildParams.UseCache = true;
buildParams.CacheServerHost = Parameters.SBPParameters.CacheServerHost;
buildParams.CacheServerPort = Parameters.SBPParameters.CacheServerPort;
}
buildParams.UseCache = true;
buildParams.CacheServerHost = Parameters.SBPParameters.CacheServerHost;
buildParams.CacheServerPort = Parameters.SBPParameters.CacheServerPort;
buildParams.WriteLinkXML = Parameters.SBPParameters.WriteLinkXML;
return buildParams;

View File

@@ -34,19 +34,19 @@ namespace YooAsset.Editor
public string FileName;
/// <summary>
/// 哈希值
/// 文件哈希值
/// </summary>
public string Hash;
public string FileHash;
/// <summary>
/// 文件校验码
/// </summary>
public string CRC;
public string FileCRC;
/// <summary>
/// 文件大小(字节数)
/// </summary>
public long SizeBytes;
public long FileSize;
/// <summary>
/// Tags

View File

@@ -63,16 +63,6 @@ namespace YooAsset.Editor
/// </summary>
public bool CopyBuildinTagFiles;
/// <summary>
/// 自动收集着色器
/// </summary>
public bool AutoCollectShaders;
/// <summary>
/// 自动收集的着色器资源包名称
/// </summary>
public string ShadersBundleName;
/// <summary>
/// 加密服务类名称
/// </summary>

View File

@@ -20,5 +20,10 @@ namespace YooAsset.Editor
/// 构建失败的信息
/// </summary>
public string FailedInfo;
/// <summary>
/// 输出的补丁包目录
/// </summary>
public string OutputPackageDirectory;
}
}

View File

@@ -0,0 +1,52 @@
using System;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using UnityEditor.Build.Pipeline;
using UnityEditor.Build.Pipeline.Interfaces;
namespace UnityEditor.Build.Pipeline.Tasks
{
public static class SBPBuildTasks
{
public static IList<IBuildTask> Create(string builtInShaderBundleName)
{
var buildTasks = new List<IBuildTask>();
// Setup
buildTasks.Add(new SwitchToBuildPlatform());
buildTasks.Add(new RebuildSpriteAtlasCache());
// Player Scripts
buildTasks.Add(new BuildPlayerScripts());
buildTasks.Add(new PostScriptsCallback());
// Dependency
buildTasks.Add(new CalculateSceneDependencyData());
#if UNITY_2019_3_OR_NEWER
buildTasks.Add(new CalculateCustomDependencyData());
#endif
buildTasks.Add(new CalculateAssetDependencyData());
buildTasks.Add(new StripUnusedSpriteSources());
buildTasks.Add(new CreateBuiltInShadersBundle(builtInShaderBundleName));
buildTasks.Add(new PostDependencyCallback());
// Packing
buildTasks.Add(new GenerateBundlePacking());
buildTasks.Add(new UpdateBundleObjectLayout());
buildTasks.Add(new GenerateBundleCommands());
buildTasks.Add(new GenerateSubAssetPathMaps());
buildTasks.Add(new GenerateBundleMaps());
buildTasks.Add(new PostPackingCallback());
// Writing
buildTasks.Add(new WriteSerializedFiles());
buildTasks.Add(new ArchiveAndCompressBundles());
buildTasks.Add(new AppendBundleHash());
buildTasks.Add(new GenerateLinkXml());
buildTasks.Add(new PostWritingCallback());
return buildTasks;
}
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 03baa90d8f534834c9c31d469a507f66
guid: f38422f6a64300243af6b4fbf84644ba
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@@ -10,7 +10,7 @@ namespace YooAsset.Editor
[TaskAttribute("资源构建内容打包")]
public class TaskBuilding : IBuildTask
{
public class UnityManifestContext : IContextObject
public class BuildResultContext : IContextObject
{
public AssetBundleManifest UnityManifest;
}
@@ -26,19 +26,26 @@ namespace YooAsset.Editor
return;
BuildAssetBundleOptions opt = buildParametersContext.GetPipelineBuildOptions();
AssetBundleManifest unityManifest = BuildPipeline.BuildAssetBundles(buildParametersContext.PipelineOutputDirectory, buildMapContext.GetPipelineBuilds(), opt, buildParametersContext.Parameters.BuildTarget);
if (unityManifest == null)
AssetBundleManifest buildResults = BuildPipeline.BuildAssetBundles(buildParametersContext.PipelineOutputDirectory, buildMapContext.GetPipelineBuilds(), opt, buildParametersContext.Parameters.BuildTarget);
if (buildResults == null)
throw new Exception("构建过程中发生错误!");
BuildRunner.Log("Unity引擎打包成功");
UnityManifestContext unityManifestContext = new UnityManifestContext();
unityManifestContext.UnityManifest = unityManifest;
context.SetContextObject(unityManifestContext);
if (buildMode == EBuildMode.ForceRebuild || buildMode == EBuildMode.IncrementalBuild)
{
string unityOutputManifestFilePath = $"{buildParametersContext.PipelineOutputDirectory}/{YooAssetSettings.OutputFolderName}";
if(System.IO.File.Exists(unityOutputManifestFilePath) == false)
throw new Exception("构建过程中发生严重错误!请查阅上下文日志!");
}
BuildRunner.Log("Unity引擎打包成功");
BuildResultContext buildResultContext = new BuildResultContext();
buildResultContext.UnityManifest = buildResults;
context.SetContextObject(buildResultContext);
// 拷贝原生文件
if (buildMode == EBuildMode.ForceRebuild || buildMode == EBuildMode.IncrementalBuild)
{
CopyRawBundle(buildMapContext, buildParametersContext);
UpdateBuildBundleInfo(buildMapContext, buildParametersContext, buildResultContext);
}
}
@@ -60,5 +67,28 @@ namespace YooAsset.Editor
}
}
}
/// <summary>
/// 更新构建结果
/// </summary>
private void UpdateBuildBundleInfo(BuildMapContext buildMapContext, BuildParametersContext buildParametersContext, BuildResultContext buildResult)
{
foreach (var bundleInfo in buildMapContext.BundleInfos)
{
if (bundleInfo.IsRawFile)
{
string filePath = $"{buildParametersContext.PipelineOutputDirectory}/{bundleInfo.BundleName}";
bundleInfo.ContentHash = HashUtility.FileMD5(filePath);
}
else
{
var hash = buildResult.UnityManifest.GetAssetBundleHash(bundleInfo.BundleName);
if (hash.isValid)
bundleInfo.ContentHash = hash.ToString();
else
throw new Exception($"Not found bundle in build result : {bundleInfo.BundleName}");
}
}
}
}
}

View File

@@ -2,18 +2,17 @@
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEditor.Build.Pipeline;
using UnityEditor.Build.Pipeline.Interfaces;
using UnityEditor.Build.Pipeline.Tasks;
namespace YooAsset.Editor
{
[TaskAttribute("资源构建内容打包")]
public class TaskBuilding_SBP : IBuildTask
{
public class SBPBuildResultContext : IContextObject
public class BuildResultContext : IContextObject
{
public IBundleBuildResults Results;
}
@@ -34,7 +33,8 @@ namespace YooAsset.Editor
// 开始构建
IBundleBuildResults buildResults;
var buildParameters = buildParametersContext.GetSBPBuildParameters();
var taskList = DefaultBuildTasks.Create(DefaultBuildTasks.Preset.AssetBundleBuiltInShaderExtraction);
var shadersBunldeName = YooAssetSettingsData.GetUnityShadersBundleFullName();
var taskList = SBPBuildTasks.Create(shadersBunldeName);
ReturnCode exitCode = ContentPipeline.BuildAssetBundles(buildParameters, buildContent, out buildResults, taskList);
if (exitCode < 0)
{
@@ -42,21 +42,14 @@ namespace YooAsset.Editor
}
BuildRunner.Log("Unity引擎打包成功");
SBPBuildResultContext buildResultContext = new SBPBuildResultContext();
BuildResultContext buildResultContext = new BuildResultContext();
buildResultContext.Results = buildResults;
context.SetContextObject(buildResultContext);
// 添加Unity内置资源包信息
if (buildResults.BundleInfos.Keys.Any(t => t == YooAssetSettings.UnityBuiltInShadersBundleName))
{
BuildBundleInfo builtInBundleInfo = new BuildBundleInfo(YooAssetSettings.UnityBuiltInShadersBundleName);
buildMapContext.BundleInfos.Add(builtInBundleInfo);
}
// 拷贝原生文件
if (buildMode == EBuildMode.ForceRebuild || buildMode == EBuildMode.IncrementalBuild)
{
CopyRawBundle(buildMapContext, buildParametersContext);
UpdateBuildBundleInfo(buildMapContext, buildParametersContext, buildResultContext);
}
}
@@ -78,5 +71,28 @@ namespace YooAsset.Editor
}
}
}
/// <summary>
/// 更新构建结果
/// </summary>
private void UpdateBuildBundleInfo(BuildMapContext buildMapContext, BuildParametersContext buildParametersContext, BuildResultContext buildResult)
{
foreach (var bundleInfo in buildMapContext.BundleInfos)
{
if (bundleInfo.IsRawFile)
{
string filePath = $"{buildParametersContext.PipelineOutputDirectory}/{bundleInfo.BundleName}";
bundleInfo.ContentHash = HashUtility.FileMD5(filePath);
}
else
{
// 注意当资源包的依赖列表发生变化的时候ContentHash也会发生变化
if (buildResult.Results.BundleInfos.TryGetValue(bundleInfo.BundleName, out var value))
bundleInfo.ContentHash = value.Hash.ToString();
else
throw new Exception($"Not found bundle in build result : {bundleInfo.BundleName}");
}
}
}
}
}

View File

@@ -22,8 +22,6 @@ namespace YooAsset.Editor
private void CreatePatchManifestFile(BuildContext context)
{
var buildParameters = context.GetContextObject<BuildParametersContext>();
var buildMapContext = context.GetContextObject<BuildMapContext>();
var encryptionContext = context.GetContextObject<TaskEncryption.EncryptionContext>();
int resourceVersion = buildParameters.Parameters.BuildVersion;
// 创建新补丁清单
@@ -33,14 +31,17 @@ namespace YooAsset.Editor
patchManifest.EnableAddressable = buildParameters.Parameters.EnableAddressable;
patchManifest.OutputNameStyle = (int)buildParameters.Parameters.OutputNameStyle;
patchManifest.BuildinTags = buildParameters.Parameters.BuildinTags;
patchManifest.BundleList = GetAllPatchBundle(buildParameters, buildMapContext, encryptionContext);
patchManifest.AssetList = GetAllPatchAsset(buildParameters, buildMapContext, patchManifest);
patchManifest.BundleList = GetAllPatchBundle(context);
patchManifest.AssetList = GetAllPatchAsset(context, patchManifest);
// 更新Unity内置资源包的引用关系
if (buildParameters.Parameters.BuildPipeline == EBuildPipeline.ScriptableBuildPipeline)
{
var buildResultContext = context.GetContextObject<TaskBuilding_SBP.SBPBuildResultContext>();
UpdateBuiltInBundleReference(patchManifest, buildResultContext.Results);
if(buildParameters.Parameters.BuildMode == EBuildMode.IncrementalBuild)
{
var buildResultContext = context.GetContextObject<TaskBuilding_SBP.BuildResultContext>();
UpdateBuiltInBundleReference(patchManifest, buildResultContext.Results);
}
}
// 创建补丁清单文件
@@ -64,27 +65,27 @@ namespace YooAsset.Editor
/// <summary>
/// 获取资源包列表
/// </summary>
private List<PatchBundle> GetAllPatchBundle(BuildParametersContext buildParameters, BuildMapContext buildMapContext,
TaskEncryption.EncryptionContext encryptionContext)
private List<PatchBundle> GetAllPatchBundle(BuildContext context)
{
var buildParameters = context.GetContextObject<BuildParametersContext>();
var buildMapContext = context.GetContextObject<BuildMapContext>();
var encryptionContext = context.GetContextObject<TaskEncryption.EncryptionContext>();
List<PatchBundle> result = new List<PatchBundle>(1000);
List<string> buildinTags = buildParameters.Parameters.GetBuildinTags();
var buildMode = buildParameters.Parameters.BuildMode;
bool standardBuild = buildMode == EBuildMode.ForceRebuild || buildMode == EBuildMode.IncrementalBuild;
foreach (var bundleInfo in buildMapContext.BundleInfos)
{
var bundleName = bundleInfo.BundleName;
string filePath = $"{buildParameters.PipelineOutputDirectory}/{bundleName}";
string hash = GetFileHash(filePath, standardBuild);
string crc32 = GetFileCRC(filePath, standardBuild);
long size = GetFileSize(filePath, standardBuild);
string fileHash = GetBundleFileHash(bundleInfo, buildParameters);
string fileCRC = GetBundleFileCRC(bundleInfo, buildParameters);
long fileSize = GetBundleFileSize(bundleInfo, buildParameters);
string[] tags = buildMapContext.GetBundleTags(bundleName);
bool isEncrypted = encryptionContext.IsEncryptFile(bundleName);
bool isBuildin = IsBuildinBundle(tags, buildinTags);
bool isRawFile = bundleInfo.IsRawFile;
PatchBundle patchBundle = new PatchBundle(bundleName, hash, crc32, size, tags);
PatchBundle patchBundle = new PatchBundle(bundleName, fileHash, fileCRC, fileSize, tags);
patchBundle.SetFlagsValue(isEncrypted, isBuildin, isRawFile);
result.Add(patchBundle);
}
@@ -104,33 +105,42 @@ namespace YooAsset.Editor
}
return false;
}
private string GetFileHash(string filePath, bool standardBuild)
private string GetBundleFileHash(BuildBundleInfo bundleInfo, BuildParametersContext buildParametersContext)
{
if (standardBuild)
return HashUtility.FileMD5(filePath);
else
var buildMode = buildParametersContext.Parameters.BuildMode;
if (buildMode == EBuildMode.DryRunBuild || buildMode == EBuildMode.SimulateBuild)
return "00000000000000000000000000000000"; //32位
string filePath = $"{buildParametersContext.PipelineOutputDirectory}/{bundleInfo.BundleName}";
return HashUtility.FileMD5(filePath);
}
private string GetFileCRC(string filePath, bool standardBuild)
private string GetBundleFileCRC(BuildBundleInfo bundleInfo, BuildParametersContext buildParametersContext)
{
if (standardBuild)
return HashUtility.FileCRC32(filePath);
else
var buildMode = buildParametersContext.Parameters.BuildMode;
if (buildMode == EBuildMode.DryRunBuild || buildMode == EBuildMode.SimulateBuild)
return "00000000"; //8位
string filePath = $"{buildParametersContext.PipelineOutputDirectory}/{bundleInfo.BundleName}";
return HashUtility.FileCRC32(filePath);
}
private long GetFileSize(string filePath, bool standardBuild)
private long GetBundleFileSize(BuildBundleInfo bundleInfo, BuildParametersContext buildParametersContext)
{
if (standardBuild)
return FileUtility.GetFileSize(filePath);
else
var buildMode = buildParametersContext.Parameters.BuildMode;
if (buildMode == EBuildMode.DryRunBuild || buildMode == EBuildMode.SimulateBuild)
return 0;
string filePath = $"{buildParametersContext.PipelineOutputDirectory}/{bundleInfo.BundleName}";
return FileUtility.GetFileSize(filePath);
}
/// <summary>
/// 获取资源列表
/// </summary>
private List<PatchAsset> GetAllPatchAsset(BuildParametersContext buildParameters, BuildMapContext buildMapContext, PatchManifest patchManifest)
private List<PatchAsset> GetAllPatchAsset(BuildContext context, PatchManifest patchManifest)
{
var buildParameters = context.GetContextObject<BuildParametersContext>();
var buildMapContext = context.GetContextObject<BuildMapContext>();
List<PatchAsset> result = new List<PatchAsset>(1000);
foreach (var bundleInfo in buildMapContext.BundleInfos)
{
@@ -183,24 +193,31 @@ namespace YooAsset.Editor
/// </summary>
private void UpdateBuiltInBundleReference(PatchManifest patchManifest, IBundleBuildResults buildResults)
{
// 获取所有依赖内置资源包的资源包列表
List<string> builtInBundleReferenceList = new List<string>();
// 获取所有依赖着色器资源包的资源包列表
string shadersBunldeName = YooAssetSettingsData.GetUnityShadersBundleFullName();
List<string> shaderBundleReferenceList = new List<string>();
foreach (var valuePair in buildResults.BundleInfos)
{
if (valuePair.Value.Dependencies.Any(t => t == YooAssetSettings.UnityBuiltInShadersBundleName))
builtInBundleReferenceList.Add(valuePair.Key);
if (valuePair.Value.Dependencies.Any(t => t == shadersBunldeName))
shaderBundleReferenceList.Add(valuePair.Key);
}
// 获取着色器资源包索引
Predicate<PatchBundle> predicate = new Predicate<PatchBundle>(s => s.BundleName == shadersBunldeName);
int shaderBundleId = patchManifest.BundleList.FindIndex(predicate);
if (shaderBundleId == -1)
throw new Exception("没有发现着色器资源包!");
// 检测依赖交集并更新依赖ID
int builtInBundleId = patchManifest.BundleList.Count - 1;
foreach (var patchAsset in patchManifest.AssetList)
{
List<string> dependBundles = GetPatchAssetAllDependBundles(patchManifest, patchAsset);
List<string> conflictAssetPathList = dependBundles.Intersect(builtInBundleReferenceList).ToList();
List<string> conflictAssetPathList = dependBundles.Intersect(shaderBundleReferenceList).ToList();
if (conflictAssetPathList.Count > 0)
{
List<int> newDependIDs = new List<int>(patchAsset.DependIDs);
newDependIDs.Add(builtInBundleId);
if (newDependIDs.Contains(shaderBundleId) == false)
newDependIDs.Add(shaderBundleId);
patchAsset.DependIDs = newDependIDs.ToArray();
}
}

View File

@@ -19,11 +19,9 @@ namespace YooAsset.Editor
{
CreateReportFile(buildParameters, buildMapContext);
}
else
{
float buildSeconds = buildParameters.GetBuildingSeconds();
BuildRunner.Info($"Build time consuming {buildSeconds} seconds.");
}
float buildSeconds = buildParameters.GetBuildingSeconds();
BuildRunner.Info($"Build time consuming {buildSeconds} seconds.");
}
private void CreateReportFile(BuildParametersContext buildParameters, BuildMapContext buildMapContext)
@@ -48,8 +46,6 @@ namespace YooAsset.Editor
buildReport.Summary.BuildinTags = buildParameters.Parameters.BuildinTags;
buildReport.Summary.EnableAddressable = buildParameters.Parameters.EnableAddressable;
buildReport.Summary.CopyBuildinTagFiles = buildParameters.Parameters.CopyBuildinTagFiles;
buildReport.Summary.AutoCollectShaders = AssetBundleCollectorSettingData.Setting.AutoCollectShaders;
buildReport.Summary.ShadersBundleName = AssetBundleCollectorSettingData.Setting.ShadersBundleName;
buildReport.Summary.EncryptionServicesClassName = buildParameters.Parameters.EncryptionServices == null ?
"null" : buildParameters.Parameters.EncryptionServices.GetType().FullName;
@@ -83,7 +79,7 @@ namespace YooAsset.Editor
reportAssetInfo.AssetTags = patchAsset.AssetTags;
reportAssetInfo.AssetGUID = AssetDatabase.AssetPathToGUID(patchAsset.AssetPath);
reportAssetInfo.MainBundleName = mainBundle.BundleName;
reportAssetInfo.MainBundleSize = mainBundle.SizeBytes;
reportAssetInfo.MainBundleSize = mainBundle.FileSize;
reportAssetInfo.DependBundles = GetDependBundles(patchManifest, patchAsset);
reportAssetInfo.DependAssets = GetDependAssets(buildMapContext, mainBundle.BundleName, patchAsset.AssetPath);
buildReport.AssetInfos.Add(reportAssetInfo);
@@ -96,9 +92,9 @@ namespace YooAsset.Editor
ReportBundleInfo reportBundleInfo = new ReportBundleInfo();
reportBundleInfo.BundleName = patchBundle.BundleName;
reportBundleInfo.FileName = patchBundle.FileName;
reportBundleInfo.Hash = patchBundle.Hash;
reportBundleInfo.CRC = patchBundle.CRC;
reportBundleInfo.SizeBytes = patchBundle.SizeBytes;
reportBundleInfo.FileHash = patchBundle.FileHash;
reportBundleInfo.FileCRC = patchBundle.FileCRC;
reportBundleInfo.FileSize = patchBundle.FileSize;
reportBundleInfo.Tags = patchBundle.Tags;
reportBundleInfo.Flags = patchBundle.Flags;
buildReport.BundleInfos.Add(reportBundleInfo);
@@ -174,7 +170,7 @@ namespace YooAsset.Editor
long fileBytes = 0;
foreach (var patchBundle in patchManifest.BundleList)
{
fileBytes += patchBundle.SizeBytes;
fileBytes += patchBundle.FileSize;
}
return fileBytes;
}
@@ -194,7 +190,7 @@ namespace YooAsset.Editor
foreach (var patchBundle in patchManifest.BundleList)
{
if (patchBundle.IsBuildin)
fileBytes += patchBundle.SizeBytes;
fileBytes += patchBundle.FileSize;
}
return fileBytes;
}
@@ -214,7 +210,7 @@ namespace YooAsset.Editor
foreach (var patchBundle in patchManifest.BundleList)
{
if (patchBundle.IsEncrypted)
fileBytes += patchBundle.SizeBytes;
fileBytes += patchBundle.FileSize;
}
return fileBytes;
}
@@ -234,7 +230,7 @@ namespace YooAsset.Editor
foreach (var patchBundle in patchManifest.BundleList)
{
if (patchBundle.IsRawFile)
fileBytes += patchBundle.SizeBytes;
fileBytes += patchBundle.FileSize;
}
return fileBytes;
}

View File

@@ -14,6 +14,8 @@ namespace YooAsset.Editor
var buildParameters = context.GetContextObject<BuildParametersContext>();
buildParameters.BeginWatch();
var buildMode = buildParameters.Parameters.BuildMode;
// 检测构建平台是否合法
if (buildParameters.Parameters.BuildTarget == BuildTarget.NoTarget)
throw new Exception("请选择目标平台");
@@ -26,19 +28,21 @@ namespace YooAsset.Editor
if (string.IsNullOrEmpty(buildParameters.PipelineOutputDirectory))
throw new Exception("输出目录不能为空");
// 检测当前是否正在构建资源包
if (BuildPipeline.isBuildingPlayer)
throw new Exception("当前正在构建资源包,请结束后再试");
if (buildMode != EBuildMode.SimulateBuild)
{
// 检测当前是否正在构建资源包
if (BuildPipeline.isBuildingPlayer)
throw new Exception("当前正在构建资源包,请结束后再试");
// 检测是否有未保存场景
if (EditorTools.HasDirtyScenes())
throw new Exception("检测到未保存的场景文件");
// 检测是否有未保存场景
if (EditorTools.HasDirtyScenes())
throw new Exception("检测到未保存的场景文件");
// 保存改动的资源
AssetDatabase.SaveAssets();
// 保存改动的资源
AssetDatabase.SaveAssets();
}
// 增量更新时候的必要检测
var buildMode = buildParameters.Parameters.BuildMode;
if (buildMode == EBuildMode.IncrementalBuild)
{
// 检测历史版本是否存在

View File

@@ -14,7 +14,7 @@ namespace YooAsset.Editor
void IBuildTask.Run(BuildContext context)
{
var buildParametersContext = context.GetContextObject<BuildParametersContext>();
// 模拟构建模式下跳过验证
if (buildParametersContext.Parameters.BuildMode == EBuildMode.SimulateBuild)
return;
@@ -22,8 +22,8 @@ namespace YooAsset.Editor
// 验证构建结果
if (buildParametersContext.Parameters.VerifyBuildingResult)
{
var unityManifestContext = context.GetContextObject<TaskBuilding.UnityManifestContext>();
VerifyingBuildingResult(context, unityManifestContext.UnityManifest);
var buildResultContext = context.GetContextObject<TaskBuilding.BuildResultContext>();
VerifyingBuildingResult(context, buildResultContext.UnityManifest);
}
}
@@ -37,20 +37,31 @@ namespace YooAsset.Editor
string[] buildedBundles = unityManifest.GetAllAssetBundles();
// 1. 过滤掉原生Bundle
string[] expectBundles = buildMapContext.BundleInfos.Where(t => t.IsRawFile == false).Select(t => t.BundleName).ToArray();
string[] mapBundles = buildMapContext.BundleInfos.Where(t => t.IsRawFile == false).Select(t => t.BundleName).ToArray();
// 2. 验证Bundle
List<string> intersectBundleList = buildedBundles.Except(expectBundles).ToList();
if (intersectBundleList.Count > 0)
List<string> exceptBundleList1 = buildedBundles.Except(mapBundles).ToList();
if (exceptBundleList1.Count > 0)
{
foreach (var intersectBundle in intersectBundleList)
foreach (var exceptBundle in exceptBundleList1)
{
Debug.LogWarning($"差异资源包: {intersectBundle}");
Debug.LogWarning($"差异资源包: {exceptBundle}");
}
throw new System.Exception("存在差异资源包!请查看警告信息!");
}
// 3. 验证Asset
// 3. 验证Bundle
List<string> exceptBundleList2 = mapBundles.Except(buildedBundles).ToList();
if (exceptBundleList2.Count > 0)
{
foreach (var exceptBundle in exceptBundleList2)
{
Debug.LogWarning($"差异资源包: {exceptBundle}");
}
throw new System.Exception("存在差异资源包!请查看警告信息!");
}
// 4. 验证Asset
bool isPass = true;
var buildMode = buildParameters.Parameters.BuildMode;
if (buildMode == EBuildMode.ForceRebuild || buildMode == EBuildMode.IncrementalBuild)
@@ -59,15 +70,20 @@ namespace YooAsset.Editor
foreach (var buildedBundle in buildedBundles)
{
string filePath = $"{buildParameters.PipelineOutputDirectory}/{buildedBundle}";
string[] allBuildinAssetPaths = GetAssetBundleAllAssets(filePath);
string[] expectBuildinAssetPaths = buildMapContext.GetBuildinAssetPaths(buildedBundle);
if (expectBuildinAssetPaths.Length != allBuildinAssetPaths.Length)
string[] buildedAssetPaths = GetAssetBundleAllAssets(filePath);
string[] mapAssetPaths = buildMapContext.GetBuildinAssetPaths(buildedBundle);
if (mapAssetPaths.Length != buildedAssetPaths.Length)
{
Debug.LogWarning($"构建的Bundle文件内的资源对象数量和预期不匹配 : {buildedBundle}");
var intersectAssetList = expectBuildinAssetPaths.Except(allBuildinAssetPaths).ToList();
foreach (var intersectAssset in intersectAssetList)
var exceptAssetList1 = mapAssetPaths.Except(buildedAssetPaths).ToList();
foreach (var excpetAsset in exceptAssetList1)
{
Debug.LogWarning($"构建失败的资源对象路径为 : {intersectAssset}");
Debug.LogWarning($"构建失败的资源对象路径为 : {excpetAsset}");
}
var exceptAssetList2 = buildedAssetPaths.Except(mapAssetPaths).ToList();
foreach (var excpetAsset in exceptAssetList2)
{
Debug.LogWarning($"构建失败的资源对象路径为 : {excpetAsset}");
}
isPass = false;
continue;
@@ -75,6 +91,7 @@ namespace YooAsset.Editor
EditorTools.DisplayProgressBar("验证构建结果", ++progressValue, buildedBundles.Length);
}
EditorTools.ClearProgressBar();
if (isPass == false)
{
throw new Exception("构建结果验证没有通过,请参考警告日志!");

View File

@@ -23,7 +23,7 @@ namespace YooAsset.Editor
// 验证构建结果
if (buildParametersContext.Parameters.VerifyBuildingResult)
{
var buildResultContext = context.GetContextObject<TaskBuilding_SBP.SBPBuildResultContext>();
var buildResultContext = context.GetContextObject<TaskBuilding_SBP.BuildResultContext>();
VerifyingBuildingResult(context, buildResultContext.Results);
}
}
@@ -35,21 +35,29 @@ namespace YooAsset.Editor
{
var buildParameters = context.GetContextObject<BuildParametersContext>();
var buildMapContext = context.GetContextObject<BuildMapContext>();
// 1. 移除特定Bundle
List<string> buildedBundles = buildResults.BundleInfos.Keys.ToList();
buildedBundles.Remove(YooAssetSettings.UnityBuiltInShadersBundleName);
// 2. 过滤掉原生Bundle
// 1. 过滤掉原生Bundle
List<string> expectBundles = buildMapContext.BundleInfos.Where(t => t.IsRawFile == false).Select(t => t.BundleName).ToList();
// 3. 验证Bundle
List<string> intersectBundleList = buildedBundles.Except(expectBundles).ToList();
if (intersectBundleList.Count > 0)
// 2. 验证Bundle
List<string> exceptBundleList1 = buildedBundles.Except(expectBundles).ToList();
if (exceptBundleList1.Count > 0)
{
foreach (var intersectBundle in intersectBundleList)
foreach (var exceptBundle in exceptBundleList1)
{
Debug.LogWarning($"差异资源包: {intersectBundle}");
Debug.LogWarning($"差异资源包: {exceptBundle}");
}
throw new System.Exception("存在差异资源包!请查看警告信息!");
}
// 3. 验证Bundle
List<string> exceptBundleList2 = expectBundles.Except(buildedBundles).ToList();
if (exceptBundleList2.Count > 0)
{
foreach (var exceptBundle in exceptBundleList2)
{
Debug.LogWarning($"差异资源包: {exceptBundle}");
}
throw new System.Exception("存在差异资源包!请查看警告信息!");
}

View File

@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;
namespace YooAsset.Editor
{
@@ -14,6 +15,11 @@ namespace YooAsset.Editor
/// </summary>
public string CollectPath = string.Empty;
/// <summary>
/// 收集器的GUID
/// </summary>
public string CollectorGUID = string.Empty;
/// <summary>
/// 收集器类型
/// </summary>
@@ -68,7 +74,8 @@ namespace YooAsset.Editor
/// </summary>
public void CheckConfigError()
{
if (AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(CollectPath) == null)
string assetGUID = AssetDatabase.AssetPathToGUID(CollectPath);
if (string.IsNullOrEmpty(assetGUID))
throw new Exception($"Invalid collect path : {CollectPath}");
if (CollectorType == ECollectorType.None)
@@ -84,6 +91,44 @@ namespace YooAsset.Editor
throw new Exception($"Invalid {nameof(IAddressRule)} class type : {AddressRuleName} in collector : {CollectPath}");
}
/// <summary>
/// 修复配置错误
/// </summary>
public bool FixConfigError()
{
bool isFixed = false;
if (string.IsNullOrEmpty(CollectorGUID) == false)
{
string convertAssetPath = AssetDatabase.GUIDToAssetPath(CollectorGUID);
if (string.IsNullOrEmpty(convertAssetPath))
{
Debug.LogWarning($"Collector GUID {CollectorGUID} is invalid and has been auto removed !");
CollectorGUID = string.Empty;
isFixed = true;
}
else
{
if (CollectPath != convertAssetPath)
{
CollectPath = convertAssetPath;
isFixed = true;
Debug.LogWarning($"Fix collect path : {CollectPath} -> {convertAssetPath}");
}
}
}
/*
string convertGUID = AssetDatabase.AssetPathToGUID(CollectPath);
if(string.IsNullOrEmpty(convertGUID) == false)
{
CollectorGUID = convertGUID;
}
*/
return isFixed;
}
/// <summary>
/// 获取打包收集的资源文件
/// </summary>
@@ -184,11 +229,6 @@ namespace YooAsset.Editor
UnityEngine.Debug.LogError($"Invalid asset path : {assetPath}");
return false;
}
if (assetPath.Contains("/Gizmos/"))
{
UnityEngine.Debug.LogWarning($"Cannot pack gizmos asset : {assetPath}");
return false;
}
// 忽略文件夹
if (AssetDatabase.IsValidFolder(assetPath))
@@ -200,27 +240,34 @@ namespace YooAsset.Editor
return false;
// 忽略Unity无法识别的无效文件
/*
if (type == typeof(UnityEditor.DefaultAsset))
{
UnityEngine.Debug.LogWarning($"Cannot pack default asset : {assetPath}");
return false;
}
*/
string ext = System.IO.Path.GetExtension(assetPath);
if (ext == "" || ext == ".dll" || ext == ".cs" || ext == ".js" || ext == ".boo" || ext == ".meta" || ext == ".cginc")
string fileExtension = System.IO.Path.GetExtension(assetPath);
if (IsIgnoreFile(fileExtension))
return false;
return true;
}
private bool IsCollectAsset(string assetPath)
private bool IsIgnoreFile(string fileExtension)
{
// 如果收集全路径着色器
if (AssetBundleCollectorSettingData.Setting.AutoCollectShaders)
foreach (var extension in YooAssetSettings.IgnoreFileExtensions)
{
Type assetType = AssetDatabase.GetMainAssetTypeAtPath(assetPath);
if (assetType == typeof(UnityEngine.Shader))
if (extension == fileExtension)
return true;
}
return false;
}
private bool IsCollectAsset(string assetPath)
{
Type assetType = AssetDatabase.GetMainAssetTypeAtPath(assetPath);
if (assetType == typeof(UnityEngine.Shader))
return true;
// 根据规则设置过滤资源文件
IFilterRule filterRuleInstance = AssetBundleCollectorSettingData.GetFilterRuleInstance(FilterRuleName);
@@ -237,23 +284,16 @@ namespace YooAsset.Editor
}
private string GetBundleName(AssetBundleCollectorGroup group, string assetPath)
{
// 如果自动收集所有的着色器
if (AssetBundleCollectorSettingData.Setting.AutoCollectShaders)
System.Type assetType = AssetDatabase.GetMainAssetTypeAtPath(assetPath);
if (assetType == typeof(UnityEngine.Shader))
{
System.Type assetType = AssetDatabase.GetMainAssetTypeAtPath(assetPath);
if (assetType == typeof(UnityEngine.Shader))
{
string bundleName = AssetBundleCollectorSettingData.Setting.ShadersBundleName;
return EditorTools.GetRegularPath(bundleName).ToLower();
}
return EditorTools.GetRegularPath(YooAssetSettings.UnityShadersBundleName).ToLower();
}
// 根据规则设置获取资源包名称
{
IPackRule packRuleInstance = AssetBundleCollectorSettingData.GetPackRuleInstance(PackRuleName);
string bundleName = packRuleInstance.GetBundleName(new PackRuleData(assetPath, CollectPath, group.GroupName));
return EditorTools.GetRegularPath(bundleName).ToLower();
}
IPackRule packRuleInstance = AssetBundleCollectorSettingData.GetPackRuleInstance(PackRuleName);
string bundleName = packRuleInstance.GetBundleName(new PackRuleData(assetPath, CollectPath, group.GroupName));
return EditorTools.GetRegularPath(bundleName).ToLower();
}
private List<string> GetAssetTags(AssetBundleCollectorGroup group)
{

View File

@@ -15,19 +15,18 @@ namespace YooAsset.Editor
public const string XmlVersion = "Version";
public const string XmlCommon = "Common";
public const string XmlEnableAddressable = "AutoAddressable";
public const string XmlAutoCollectShader = "AutoCollectShader";
public const string XmlShaderBundleName = "ShaderBundleName";
public const string XmlGroup = "Group";
public const string XmlGroupName = "GroupName";
public const string XmlGroupDesc = "GroupDesc";
public const string XmlCollector = "Collector";
public const string XmlCollectPath = "CollectPath";
public const string XmlCollectorGUID = "CollectGUID";
public const string XmlCollectorType = "CollectType";
public const string XmlAddressRule = "AddressRule";
public const string XmlPackRule = "PackRule";
public const string XmlFilterRule = "FilterRule";
public const string XmlAssetTags = "AssetTags";
/// <summary>
/// 导入XML配置表
/// </summary>
@@ -46,29 +45,20 @@ namespace YooAsset.Editor
// 读取配置版本
string configVersion = root.GetAttribute(XmlVersion);
if(configVersion != ConfigVersion)
if (configVersion != ConfigVersion)
{
throw new Exception($"The config version is invalid : {configVersion}");
}
// 读取公共配置
bool enableAddressable = false;
bool autoCollectShaders = false;
string shaderBundleName = string.Empty;
var commonNodeList = root.GetElementsByTagName(XmlCommon);
if (commonNodeList.Count > 0)
{
XmlElement commonElement = commonNodeList[0] as XmlElement;
if (commonElement.HasAttribute(XmlEnableAddressable) == false)
throw new Exception($"Not found attribute {XmlEnableAddressable} in {XmlCommon}");
if (commonElement.HasAttribute(XmlAutoCollectShader) == false)
throw new Exception($"Not found attribute {XmlAutoCollectShader} in {XmlCommon}");
if (commonElement.HasAttribute(XmlShaderBundleName) == false)
throw new Exception($"Not found attribute {XmlShaderBundleName} in {XmlCommon}");
enableAddressable = commonElement.GetAttribute(XmlEnableAddressable) == "True" ? true : false;
autoCollectShaders = commonElement.GetAttribute(XmlAutoCollectShader) == "True" ? true : false;
shaderBundleName = commonElement.GetAttribute(XmlShaderBundleName);
}
// 读取分组配置
@@ -108,13 +98,18 @@ namespace YooAsset.Editor
if (collectorElement.HasAttribute(XmlAssetTags) == false)
throw new Exception($"Not found attribute {XmlAssetTags} in {XmlCollector}");
string collectorGUID = string.Empty;
if (collectorElement.HasAttribute(XmlCollectorGUID))
collectorGUID = collectorElement.GetAttribute(XmlCollectorGUID);
AssetBundleCollector collector = new AssetBundleCollector();
collector.CollectPath = collectorElement.GetAttribute(XmlCollectPath);
collector.CollectorGUID = collectorGUID;
collector.CollectorType = StringUtility.NameToEnum<ECollectorType>(collectorElement.GetAttribute(XmlCollectorType));
collector.AddressRuleName = collectorElement.GetAttribute(XmlAddressRule);
collector.PackRuleName = collectorElement.GetAttribute(XmlPackRule);
collector.FilterRuleName = collectorElement.GetAttribute(XmlFilterRule);
collector.AssetTags = collectorElement.GetAttribute(XmlAssetTags); ;
collector.AssetTags = collectorElement.GetAttribute(XmlAssetTags);
group.Collectors.Add(collector);
}
}
@@ -122,8 +117,6 @@ namespace YooAsset.Editor
// 保存配置数据
AssetBundleCollectorSettingData.ClearAll();
AssetBundleCollectorSettingData.Setting.EnableAddressable = enableAddressable;
AssetBundleCollectorSettingData.Setting.AutoCollectShaders = autoCollectShaders;
AssetBundleCollectorSettingData.Setting.ShadersBundleName = shaderBundleName;
AssetBundleCollectorSettingData.Setting.Groups.AddRange(groupTemper);
AssetBundleCollectorSettingData.SaveFile();
Debug.Log($"导入配置完毕!");
@@ -152,8 +145,6 @@ namespace YooAsset.Editor
// 设置公共配置
var commonElement = xmlDoc.CreateElement(XmlCommon);
commonElement.SetAttribute(XmlEnableAddressable, AssetBundleCollectorSettingData.Setting.EnableAddressable.ToString());
commonElement.SetAttribute(XmlAutoCollectShader, AssetBundleCollectorSettingData.Setting.AutoCollectShaders.ToString());
commonElement.SetAttribute(XmlShaderBundleName, AssetBundleCollectorSettingData.Setting.ShadersBundleName);
root.AppendChild(commonElement);
// 设置分组配置
@@ -170,6 +161,7 @@ namespace YooAsset.Editor
{
var collectorElement = xmlDoc.CreateElement(XmlCollector);
collectorElement.SetAttribute(XmlCollectPath, collector.CollectPath);
collectorElement.SetAttribute(XmlCollectorGUID, collector.CollectorGUID);
collectorElement.SetAttribute(XmlCollectorType, collector.CollectorType.ToString());
collectorElement.SetAttribute(XmlAddressRule, collector.AddressRuleName);
collectorElement.SetAttribute(XmlPackRule, collector.PackRuleName);

View File

@@ -13,16 +13,6 @@ namespace YooAsset.Editor
/// </summary>
public bool EnableAddressable = false;
/// <summary>
/// 自动收集着色器
/// </summary>
public bool AutoCollectShaders = true;
/// <summary>
/// 自动收集的着色器资源包名称
/// </summary>
public string ShadersBundleName = "myshaders";
/// <summary>
/// 分组列表
/// </summary>
@@ -40,6 +30,54 @@ namespace YooAsset.Editor
}
}
/// <summary>
/// 修复配置错误
/// </summary>
public bool FixConfigError()
{
bool result = false;
foreach (var group in Groups)
{
foreach (var collector in group.Collectors)
{
bool isFixed = collector.FixConfigError();
if (isFixed)
{
result = true;
}
}
}
return result;
}
/// <summary>
/// 获取所有的资源标签
/// </summary>
public List<string> GetAllTags()
{
HashSet<string> result = new HashSet<string>();
foreach (var group in Groups)
{
List<string> groupTags = StringUtility.StringToStringList(group.AssetTags, ';');
foreach (var tag in groupTags)
{
if (result.Contains(tag) == false)
result.Add(tag);
}
foreach (var collector in group.Collectors)
{
List<string> collectorTags = StringUtility.StringToStringList(collector.AssetTags, ';');
foreach (var tag in collectorTags)
{
if (result.Contains(tag) == false)
result.Add(tag);
}
}
}
return result.ToList();
}
/// <summary>
/// 获取打包收集的资源文件
/// </summary>
@@ -56,7 +94,7 @@ namespace YooAsset.Editor
if (result.ContainsKey(assetInfo.AssetPath) == false)
result.Add(assetInfo.AssetPath, assetInfo);
else
throw new Exception($"The collecting asset file is existed : {assetInfo.AssetPath} in group setting.");
throw new Exception($"The collecting asset file is existed : {assetInfo.AssetPath}");
}
}
@@ -72,7 +110,7 @@ namespace YooAsset.Editor
if (adressTemper.Contains(address) == false)
adressTemper.Add(address);
else
throw new Exception($"The address is existed : {address} in group setting.");
throw new Exception($"The address is existed : {address}");
}
}
}

View File

@@ -232,7 +232,7 @@ namespace YooAsset.Editor
}
/// <summary>
/// 存储文件
/// 存储配置文件
/// </summary>
public static void SaveFile()
{
@@ -245,13 +245,24 @@ namespace YooAsset.Editor
}
}
/// <summary>
/// 修复配置文件
/// </summary>
public static void FixFile()
{
bool isFixed = Setting.FixConfigError();
if (isFixed)
{
IsDirty = true;
}
}
/// <summary>
/// 清空所有数据
/// </summary>
public static void ClearAll()
{
Setting.AutoCollectShaders = false;
Setting.ShadersBundleName = string.Empty;
Setting.EnableAddressable = false;
Setting.Groups.Clear();
SaveFile();
}
@@ -333,14 +344,6 @@ namespace YooAsset.Editor
IsDirty = true;
}
// 着色器编辑相关
public static void ModifyShader(bool isCollectAllShaders, string shadersBundleName)
{
Setting.AutoCollectShaders = isCollectAllShaders;
Setting.ShadersBundleName = shadersBundleName;
IsDirty = true;
}
// 资源分组编辑相关
public static void CreateGroup(string groupName)
{
@@ -369,10 +372,9 @@ namespace YooAsset.Editor
}
// 资源收集器编辑相关
public static void CreateCollector(AssetBundleCollectorGroup group, string collectPath)
public static void CreateCollector(AssetBundleCollectorGroup group)
{
AssetBundleCollector collector = new AssetBundleCollector();
collector.CollectPath = collectPath;
group.Collectors.Add(collector);
IsDirty = true;
}
@@ -394,5 +396,14 @@ namespace YooAsset.Editor
IsDirty = true;
}
}
/// <summary>
/// 获取所有的资源标签
/// </summary>
public static string GetAllTags()
{
var allTags = Setting.GetAllTags();
return string.Join(";", allTags);
}
}
}

View File

@@ -28,8 +28,6 @@ namespace YooAsset.Editor
private ScrollView _collectorScrollView;
private PopupField<string> _activeRulePopupField;
private Toggle _enableAddressableToogle;
private Toggle _autoCollectShaderToogle;
private TextField _shaderBundleNameTxt;
private TextField _groupNameTxt;
private TextField _groupDescTxt;
private TextField _groupAssetTagsTxt;
@@ -64,6 +62,10 @@ namespace YooAsset.Editor
visualAsset.CloneTree(root);
// 配置修复按钮
var fixBtn = root.Q<Button>("FixButton");
fixBtn.clicked += FixBtn_clicked;
// 导入导出按钮
var exportBtn = root.Q<Button>("ExportButton");
exportBtn.clicked += ExportBtn_clicked;
@@ -81,17 +83,6 @@ namespace YooAsset.Editor
AssetBundleCollectorSettingData.ModifyAddressable(evt.newValue);
RefreshWindow();
});
_autoCollectShaderToogle = root.Q<Toggle>("AutoCollectShader");
_autoCollectShaderToogle.RegisterValueChangedCallback(evt =>
{
AssetBundleCollectorSettingData.ModifyShader(evt.newValue, _shaderBundleNameTxt.value);
_shaderBundleNameTxt.SetEnabled(evt.newValue);
});
_shaderBundleNameTxt = root.Q<TextField>("ShaderBundleName");
_shaderBundleNameTxt.RegisterValueChangedCallback(evt =>
{
AssetBundleCollectorSettingData.ModifyShader(_autoCollectShaderToogle.value, evt.newValue);
});
// 分组列表相关
_groupListView = root.Q<ListView>("GroupListView");
@@ -218,13 +209,14 @@ namespace YooAsset.Editor
private void RefreshWindow()
{
_enableAddressableToogle.SetValueWithoutNotify(AssetBundleCollectorSettingData.Setting.EnableAddressable);
_autoCollectShaderToogle.SetValueWithoutNotify(AssetBundleCollectorSettingData.Setting.AutoCollectShaders);
_shaderBundleNameTxt.SetEnabled(AssetBundleCollectorSettingData.Setting.AutoCollectShaders);
_shaderBundleNameTxt.SetValueWithoutNotify(AssetBundleCollectorSettingData.Setting.ShadersBundleName);
_groupContainer.visible = false;
FillGroupViewData();
}
private void FixBtn_clicked()
{
AssetBundleCollectorSettingData.FixFile();
}
private void ExportBtn_clicked()
{
string resultPath = EditorTools.OpenFolderPanel("Export XML", "Assets/");
@@ -488,6 +480,7 @@ namespace YooAsset.Editor
objectField1.RegisterValueChangedCallback(evt =>
{
collector.CollectPath = AssetDatabase.GetAssetPath(evt.newValue);
collector.CollectorGUID = AssetDatabase.AssetPathToGUID(collector.CollectPath);
objectField1.value.name = collector.CollectPath;
AssetBundleCollectorSettingData.ModifyCollector(selectGroup, collector);
if (foldout.value)
@@ -618,7 +611,7 @@ namespace YooAsset.Editor
return;
Undo.RecordObject(AssetBundleCollectorSettingData.Setting, "YooAsset.AssetBundleCollectorWindow AddCollector");
AssetBundleCollectorSettingData.CreateCollector(selectGroup, string.Empty);
AssetBundleCollectorSettingData.CreateCollector(selectGroup);
FillCollectorViewData();
}
private void RemoveCollectorBtn_clicked(AssetBundleCollector selectCollector)

View File

@@ -3,6 +3,7 @@
<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);" />
<ui:Button text="导入" display-tooltip-when-elided="true" name="ImportButton" style="width: 50px; background-color: rgb(56, 147, 58);" />
<ui:Button text="修复" display-tooltip-when-elided="true" name="FixButton" style="width: 50px; background-color: rgb(56, 147, 58);" />
</uie:Toolbar>
<ui:VisualElement name="ContentContainer" style="flex-grow: 1; flex-direction: row;">
<ui:VisualElement name="LeftContainer" style="width: 200px; flex-grow: 0; background-color: rgb(67, 67, 67); border-left-width: 5px; border-right-width: 5px; border-top-width: 5px; border-bottom-width: 5px;">
@@ -15,8 +16,6 @@
<ui:VisualElement name="RightContainer" style="flex-direction: column; flex-grow: 1;">
<ui:VisualElement name="PublicContainer" style="height: 30px; background-color: rgb(67, 67, 67); flex-direction: row; border-left-width: 5px; border-right-width: 5px; border-top-width: 5px; border-bottom-width: 5px;">
<ui:Toggle label="Enable Addressable" name="EnableAddressable" style="width: 196px; -unity-text-align: middle-left;" />
<ui:Toggle label="Auto Collect Shaders" name="AutoCollectShader" style="width: 196px; -unity-text-align: middle-left;" />
<ui:TextField picking-mode="Ignore" label="Shader Bundle Name" name="ShaderBundleName" style="flex-grow: 1; -unity-text-align: middle-left;" />
</ui:VisualElement>
<ui:VisualElement name="GroupContainer" style="flex-grow: 1; border-left-width: 5px; border-right-width: 5px; border-top-width: 5px; border-bottom-width: 5px;">
<ui:VisualElement name="ActiveRuleContainer" style="height: 20px;" />

View File

@@ -59,4 +59,15 @@ namespace YooAsset.Editor
}
}
}
/// <summary>
/// 只收集着色器变种收集文件
/// </summary>
public class CollectShaderVariants : IFilterRule
{
public bool IsCollectAsset(FilterRuleData data)
{
return Path.GetExtension(data.AssetPath) == ".shadervariants";
}
}
}

View File

@@ -15,7 +15,8 @@ namespace YooAsset.Editor
{
string IPackRule.GetBundleName(PackRuleData data)
{
return StringUtility.RemoveExtension(data.AssetPath);
string bundleName = StringUtility.RemoveExtension(data.AssetPath);
return EditorTools.GetRegularPath(bundleName).Replace('/', '_');
}
}
@@ -32,7 +33,8 @@ namespace YooAsset.Editor
string IPackRule.GetBundleName(PackRuleData data)
{
return Path.GetDirectoryName(data.AssetPath);
string bundleName = Path.GetDirectoryName(data.AssetPath);
return EditorTools.GetRegularPath(bundleName).Replace('/', '_');
}
}
@@ -55,7 +57,7 @@ namespace YooAsset.Editor
if (Path.HasExtension(splits[0]))
throw new Exception($"Not found root directory : {assetPath}");
string bundleName = $"{data.CollectPath}/{splits[0]}";
return bundleName;
return EditorTools.GetRegularPath(bundleName).Replace('/', '_');
}
else
{
@@ -72,7 +74,8 @@ namespace YooAsset.Editor
{
string IPackRule.GetBundleName(PackRuleData data)
{
return StringUtility.RemoveExtension(data.CollectPath);
string bundleName = StringUtility.RemoveExtension(data.CollectPath);
return EditorTools.GetRegularPath(bundleName).Replace('/', '_');
}
}
@@ -110,7 +113,19 @@ namespace YooAsset.Editor
if (depends.Length != 1)
throw new Exception($"{nameof(PackRawFile)} is not support estension : {extension}");
return StringUtility.RemoveExtension(data.AssetPath);
string bundleName = StringUtility.RemoveExtension(data.AssetPath);
return EditorTools.GetRegularPath(bundleName).Replace('/', '_');
}
}
/// <summary>
/// 着色器变种收集文件
/// </summary>
public class PackShaderVariants : IPackRule
{
public string GetBundleName(PackRuleData data)
{
return YooAssetSettings.UnityShadersBundleName;
}
}
}

View File

@@ -310,11 +310,11 @@ namespace YooAsset.Editor
// Size
var label2 = element.Q<Label>("Label2");
label2.text = EditorUtility.FormatBytes(bundleInfo.SizeBytes);
label2.text = EditorUtility.FormatBytes(bundleInfo.FileSize);
// Hash
var label3 = element.Q<Label>("Label3");
label3.text = bundleInfo.Hash;
label3.text = bundleInfo.FileHash;
}
}
}

View File

@@ -122,9 +122,9 @@ namespace YooAsset.Editor
else if (_sortMode == ESortMode.BundleSize)
{
if (_descendingSort)
return result.OrderByDescending(a => a.SizeBytes).ToList();
return result.OrderByDescending(a => a.FileSize).ToList();
else
return result.OrderBy(a => a.SizeBytes).ToList();
return result.OrderBy(a => a.FileSize).ToList();
}
else if (_sortMode == ESortMode.BundleTags)
{
@@ -249,11 +249,11 @@ namespace YooAsset.Editor
// Size
var label2 = element.Q<Label>("Label2");
label2.text = EditorUtility.FormatBytes(bundleInfo.SizeBytes);
label2.text = EditorUtility.FormatBytes(bundleInfo.FileSize);
// Hash
var label3 = element.Q<Label>("Label3");
label3.text = bundleInfo.Hash;
label3.text = bundleInfo.FileHash;
// Tags
var label5 = element.Q<Label>("Label5");

View File

@@ -71,8 +71,6 @@ namespace YooAsset.Editor
_items.Add(new ItemWrapper("启用可寻址资源定位", $"{buildReport.Summary.EnableAddressable}"));
_items.Add(new ItemWrapper("拷贝内置资源文件", $"{buildReport.Summary.CopyBuildinTagFiles}"));
_items.Add(new ItemWrapper("自动收集着色器", $"{buildReport.Summary.AutoCollectShaders}"));
_items.Add(new ItemWrapper("着色器资源包名称", $"{buildReport.Summary.ShadersBundleName}"));
_items.Add(new ItemWrapper("加密服务类名称", $"{buildReport.Summary.EncryptionServicesClassName}"));
_items.Add(new ItemWrapper(string.Empty, string.Empty));

View File

@@ -10,103 +10,31 @@ namespace YooAsset.Editor
{
public static class ShaderVariantCollectionHelper
{
[Serializable]
public class ShaderVariantWrapper
public static void ClearCurrentShaderVariantCollection()
{
/// <summary>
/// Shader asset path in editor.
/// </summary>
public string AssetPath;
/// <summary>
/// Shader name.
/// </summary>
public string ShaderName;
/// <summary>
/// Pass type to use in this variant.
/// </summary>
public PassType PassType;
/// <summary>
/// Array of shader keywords to use in this variant.
/// </summary>
public string[] Keywords;
public ShaderVariantWrapper(string assetPath, string shaderName, PassType passType, params string[] keywords)
{
AssetPath = assetPath;
ShaderName = shaderName;
PassType = passType;
Keywords = keywords;
}
EditorTools.InvokeNonPublicStaticMethod(typeof(ShaderUtil), "ClearCurrentShaderVariantCollection");
}
public static void SaveCurrentShaderVariantCollection(string savePath)
{
EditorTools.InvokeNonPublicStaticMethod(typeof(ShaderUtil), "SaveCurrentShaderVariantCollection", savePath);
}
public static int GetCurrentShaderVariantCollectionShaderCount()
{
return (int)EditorTools.InvokeNonPublicStaticMethod(typeof(ShaderUtil), "GetCurrentShaderVariantCollectionShaderCount");
}
public static int GetCurrentShaderVariantCollectionVariantCount()
{
return (int)EditorTools.InvokeNonPublicStaticMethod(typeof(ShaderUtil), "GetCurrentShaderVariantCollectionVariantCount");
}
[Serializable]
public class ShaderVariantCollectionWrapper
/// <summary>
/// 获取着色器的变种总数量
/// </summary>
public static string GetShaderVariantCount(string assetPath)
{
/// <summary>
/// Number of shaders in this collection
/// </summary>
public int ShaderCount;
/// <summary>
/// Number of total varians in this collection
/// </summary>
public int VariantCount;
/// <summary>
/// Shader variants list.
/// </summary>
public List<ShaderVariantWrapper> ShaderVariants = new List<ShaderVariantWrapper>(1000);
public void Add(ShaderVariantWrapper variant)
{
ShaderVariants.Add(variant);
}
}
public static ShaderVariantCollectionWrapper Extract(ShaderVariantCollection svc)
{
var result = new ShaderVariantCollectionWrapper();
using (var so = new SerializedObject(svc))
{
var shaderArray = so.FindProperty("m_Shaders.Array");
if (shaderArray != null && shaderArray.isArray)
{
for (int i = 0; i < shaderArray.arraySize; ++i)
{
var shaderRef = shaderArray.FindPropertyRelative($"data[{i}].first");
var shaderVariantsArray = shaderArray.FindPropertyRelative($"data[{i}].second.variants");
if (shaderRef != null && shaderRef.propertyType == SerializedPropertyType.ObjectReference && shaderVariantsArray != null && shaderVariantsArray.isArray)
{
var shader = shaderRef.objectReferenceValue as Shader;
if (shader == null)
{
throw new Exception("Invalid shader in ShaderVariantCollection file.");
}
string shaderAssetPath = AssetDatabase.GetAssetPath(shader);
string shaderName = shader.name;
// 添加变种信息
for (int j = 0; j < shaderVariantsArray.arraySize; ++j)
{
var propKeywords = shaderVariantsArray.FindPropertyRelative($"Array.data[{j}].keywords");
var propPassType = shaderVariantsArray.FindPropertyRelative($"Array.data[{j}].passType");
if (propKeywords != null && propPassType != null && propKeywords.propertyType == SerializedPropertyType.String)
{
string[] keywords = propKeywords.stringValue.Split(' ');
PassType pathType = (PassType)propPassType.intValue;
result.Add(new ShaderVariantWrapper(shaderAssetPath, shaderName, pathType, keywords));
}
}
}
}
}
}
return result;
Shader shader = AssetDatabase.LoadAssetAtPath<Shader>(assetPath);
var variantCount = EditorTools.InvokeNonPublicStaticMethod(typeof(ShaderUtil), "GetVariantCount", shader, true);
return variantCount.ToString();
}
}
}

View File

@@ -0,0 +1,145 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEditor;
namespace YooAsset.Editor
{
public static class ShaderVariantCollectionReadme
{
[Serializable]
public class ShaderVariantElement
{
/// <summary>
/// Pass type to use in this variant.
/// </summary>
public PassType PassType;
/// <summary>
/// Array of shader keywords to use in this variant.
/// </summary>
public string[] Keywords;
}
[Serializable]
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 List<ShaderVariantElement> ShaderVariantElements = new List<ShaderVariantElement>(1000);
}
[Serializable]
public class ShaderVariantCollectionManifest
{
/// <summary>
/// Number of shaders in this collection
/// </summary>
public int ShaderTotalCount;
/// <summary>
/// Number of total varians in this collection
/// </summary>
public int VariantTotalCount;
/// <summary>
/// Shader variants info list.
/// </summary>
public List<ShaderVariantInfo> ShaderVariantInfos = new List<ShaderVariantInfo>(1000);
/// <summary>
/// 添加着色器变种信息
/// </summary>
public void AddShaderVariant(string assetPath, string shaderName, PassType passType, string[] keywords)
{
var info = GetOrCreateShaderVariantInfo(assetPath, shaderName);
ShaderVariantElement element = new ShaderVariantElement();
element.PassType = passType;
element.Keywords = keywords;
info.ShaderVariantElements.Add(element);
}
private ShaderVariantInfo GetOrCreateShaderVariantInfo(string assetPath, string shaderName)
{
var selectList = ShaderVariantInfos.Where(t => t.ShaderName == shaderName && t.AssetPath == assetPath).ToList();
if (selectList.Count == 0)
{
ShaderVariantInfo newInfo = new ShaderVariantInfo();
newInfo.AssetPath = assetPath;
newInfo.ShaderName = shaderName;
ShaderVariantInfos.Add(newInfo);
return newInfo;
}
if (selectList.Count != 1)
throw new Exception("Should never get here !");
return selectList[0];
}
}
/// <summary>
/// 解析SVC文件并将数据写入到清单
/// </summary>
public static ShaderVariantCollectionManifest Extract(ShaderVariantCollection svc)
{
var manifest = new ShaderVariantCollectionManifest();
manifest.ShaderTotalCount = ShaderVariantCollectionHelper.GetCurrentShaderVariantCollectionShaderCount();
manifest.VariantTotalCount = ShaderVariantCollectionHelper.GetCurrentShaderVariantCollectionVariantCount();
using (var so = new SerializedObject(svc))
{
var shaderArray = so.FindProperty("m_Shaders.Array");
if (shaderArray != null && shaderArray.isArray)
{
for (int i = 0; i < shaderArray.arraySize; ++i)
{
var shaderRef = shaderArray.FindPropertyRelative($"data[{i}].first");
var shaderVariantsArray = shaderArray.FindPropertyRelative($"data[{i}].second.variants");
if (shaderRef != null && shaderRef.propertyType == SerializedPropertyType.ObjectReference && shaderVariantsArray != null && shaderVariantsArray.isArray)
{
var shader = shaderRef.objectReferenceValue as Shader;
if (shader == null)
{
throw new Exception("Invalid shader in ShaderVariantCollection file.");
}
string shaderAssetPath = AssetDatabase.GetAssetPath(shader);
string shaderName = shader.name;
// 添加变种信息
for (int j = 0; j < shaderVariantsArray.arraySize; ++j)
{
var propKeywords = shaderVariantsArray.FindPropertyRelative($"Array.data[{j}].keywords");
var propPassType = shaderVariantsArray.FindPropertyRelative($"Array.data[{j}].passType");
if (propKeywords != null && propPassType != null && propKeywords.propertyType == SerializedPropertyType.String)
{
string[] keywords = propKeywords.stringValue.Split(' ');
PassType pathType = (PassType)propPassType.intValue;
manifest.AddShaderVariant(shaderAssetPath, shaderName, pathType, keywords);
}
}
}
}
}
}
return manifest;
}
}
}

View File

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

View File

@@ -28,7 +28,7 @@ namespace YooAsset.Editor
EditorApplication.update -= EditorUpdate;
// 保存结果
SaveCurrentShaderVariantCollection();
ShaderVariantCollectionHelper.SaveCurrentShaderVariantCollection(_saveFilePath);
// 创建说明文件
CreateReadme();
@@ -61,7 +61,7 @@ namespace YooAsset.Editor
EditorTools.FocusUnityGameWindow();
// 清空旧数据
ClearCurrentShaderVariantCollection();
ShaderVariantCollectionHelper.ClearCurrentShaderVariantCollection();
// 创建临时测试场景
CreateTemperScene();
@@ -181,7 +181,6 @@ namespace YooAsset.Editor
go.transform.position = position;
go.name = $"Sphere_{index}|{material.name}";
}
private static void CreateReadme()
{
AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate);
@@ -189,29 +188,13 @@ namespace YooAsset.Editor
ShaderVariantCollection svc = AssetDatabase.LoadAssetAtPath<ShaderVariantCollection>(_saveFilePath);
if (svc != null)
{
var wrapper = ShaderVariantCollectionHelper.Extract(svc);
var wrapper = ShaderVariantCollectionReadme.Extract(svc);
string jsonContents = JsonUtility.ToJson(wrapper, true);
string savePath = _saveFilePath.Replace(".shadervariants", "_Readme.json");
string savePath = _saveFilePath.Replace(".shadervariants", "Manifest.json");
File.WriteAllText(savePath, jsonContents);
}
AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate);
}
private static void ClearCurrentShaderVariantCollection()
{
EditorTools.InvokeNonPublicStaticMethod(typeof(ShaderUtil), "ClearCurrentShaderVariantCollection");
}
private static void SaveCurrentShaderVariantCollection()
{
EditorTools.InvokeNonPublicStaticMethod(typeof(ShaderUtil), "SaveCurrentShaderVariantCollection", _saveFilePath);
}
public static int GetCurrentShaderVariantCollectionShaderCount()
{
return (int)EditorTools.InvokeNonPublicStaticMethod(typeof(ShaderUtil), "GetCurrentShaderVariantCollectionShaderCount");
}
public static int GetCurrentShaderVariantCollectionVariantCount()
{
return (int)EditorTools.InvokeNonPublicStaticMethod(typeof(ShaderUtil), "GetCurrentShaderVariantCollectionVariantCount");
}
}
}

View File

@@ -25,8 +25,8 @@ namespace YooAsset.Editor
EditorGUILayout.Space();
ShaderVariantCollectorSettingData.Setting.SavePath = EditorGUILayout.TextField("收集文件保存路径", ShaderVariantCollectorSettingData.Setting.SavePath);
int currentShaderCount = ShaderVariantCollector.GetCurrentShaderVariantCollectionShaderCount();
int currentVariantCount = ShaderVariantCollector.GetCurrentShaderVariantCollectionVariantCount();
int currentShaderCount = ShaderVariantCollectionHelper.GetCurrentShaderVariantCollectionShaderCount();
int currentVariantCount = ShaderVariantCollectionHelper.GetCurrentShaderVariantCollectionVariantCount();
EditorGUILayout.LabelField($"CurrentShaderCount : {currentShaderCount}");
EditorGUILayout.LabelField($"CurrentVariantCount : {currentVariantCount}");

View File

@@ -141,7 +141,7 @@ namespace YooAsset
if (assetInfo.IsInvalid)
{
CompletedProvider completedProvider = new CompletedProvider(assetInfo);
completedProvider.SetCompleted();
completedProvider.SetCompleted(assetInfo.Error);
return completedProvider.CreateHandle<SceneOperationHandle>();
}
@@ -176,7 +176,7 @@ namespace YooAsset
if (assetInfo.IsInvalid)
{
CompletedProvider completedProvider = new CompletedProvider(assetInfo);
completedProvider.SetCompleted();
completedProvider.SetCompleted(assetInfo.Error);
return completedProvider.CreateHandle<AssetOperationHandle>();
}
@@ -202,7 +202,7 @@ namespace YooAsset
if (assetInfo.IsInvalid)
{
CompletedProvider completedProvider = new CompletedProvider(assetInfo);
completedProvider.SetCompleted();
completedProvider.SetCompleted(assetInfo.Error);
return completedProvider.CreateHandle<SubAssetsOperationHandle>();
}
@@ -273,7 +273,7 @@ namespace YooAsset
private static AssetBundleLoaderBase CreateAssetBundleLoaderInternal(BundleInfo bundleInfo)
{
// 如果加载器已经存在
AssetBundleLoaderBase loader = TryGetAssetBundleLoader(bundleInfo.BundleName);
AssetBundleLoaderBase loader = TryGetAssetBundleLoader(bundleInfo.Bundle.BundleName);
if (loader != null)
return loader;
@@ -293,7 +293,7 @@ namespace YooAsset
for (int i = 0; i < _loaders.Count; i++)
{
AssetBundleLoaderBase temp = _loaders[i];
if (temp.MainBundleInfo.BundleName.Equals(bundleName))
if (temp.MainBundleInfo.Bundle.BundleName.Equals(bundleName))
{
loader = temp;
break;
@@ -346,6 +346,15 @@ namespace YooAsset
report.ProviderInfos.Sort();
return report;
}
internal static List<BundleInfo> GetLoadedBundleInfos()
{
List<BundleInfo> result = new List<BundleInfo>(100);
foreach (var bundleLoader in _loaders)
{
result.Add(bundleLoader.MainBundleInfo);
}
return result;
}
#endregion
}
}

View File

@@ -149,7 +149,7 @@ namespace YooAsset
private InstantiateOperation InstantiateAsyncInternal(Vector3 position, Quaternion rotation, Transform parent, bool setPositionRotation)
{
InstantiateOperation operation = new InstantiateOperation(this, position, rotation, parent, setPositionRotation);
OperationSystem.StartOperaiton(operation);
OperationSystem.StartOperation(operation);
return operation;
}
}

View File

@@ -102,7 +102,7 @@ namespace YooAsset
{
string error = $"{nameof(SceneOperationHandle)} is invalid.";
var operation = new UnloadSceneOperation(error);
OperationSystem.StartOperaiton(operation);
OperationSystem.StartOperation(operation);
return operation;
}
@@ -112,7 +112,7 @@ namespace YooAsset
string error = $"Cannot unload main scene. Use {nameof(YooAssets.LoadSceneAsync)} method to change the main scene !";
YooLogger.Error(error);
var operation = new UnloadSceneOperation(error);
OperationSystem.StartOperaiton(operation);
OperationSystem.StartOperation(operation);
return operation;
}
@@ -121,7 +121,7 @@ namespace YooAsset
AssetSystem.UnloadSubScene(Provider);
{
var operation = new UnloadSceneOperation(sceneObject);
OperationSystem.StartOperaiton(operation);
OperationSystem.StartOperation(operation);
return operation;
}
}

View File

@@ -14,7 +14,7 @@ namespace YooAsset
Download,
CheckDownload,
LoadFile,
CheckFile,
CheckLoadFile,
Done,
}
@@ -23,7 +23,7 @@ namespace YooAsset
private bool _isWaitForAsyncComplete = false;
private bool _isShowWaitForAsyncError = false;
private DownloaderBase _downloader;
private AssetBundleCreateRequest _cacheRequest;
private AssetBundleCreateRequest _createRequest;
public AssetBundleFileLoader(BundleInfo bundleInfo) : base(bundleInfo)
@@ -40,29 +40,20 @@ namespace YooAsset
if (_steps == ESteps.None)
{
if (MainBundleInfo.IsInvalid)
{
_steps = ESteps.Done;
Status = EStatus.Failed;
LastError = $"The bundle info is invalid : {MainBundleInfo.BundleName}";
YooLogger.Error(LastError);
return;
}
if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromRemote)
{
_steps = ESteps.Download;
_fileLoadPath = MainBundleInfo.GetCacheLoadPath();
_fileLoadPath = MainBundleInfo.Bundle.CachedFilePath;
}
else if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromStreaming)
{
_steps = ESteps.LoadFile;
_fileLoadPath = MainBundleInfo.GetStreamingLoadPath();
_fileLoadPath = MainBundleInfo.Bundle.StreamingFilePath;
}
else if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromCache)
{
_steps = ESteps.LoadFile;
_fileLoadPath = MainBundleInfo.GetCacheLoadPath();
_fileLoadPath = MainBundleInfo.Bundle.CachedFilePath;
}
else
{
@@ -112,47 +103,46 @@ namespace YooAsset
#endif
// Load assetBundle file
if (MainBundleInfo.IsEncrypted)
if (MainBundleInfo.Bundle.IsEncrypted)
{
if (AssetSystem.DecryptionServices == null)
throw new Exception($"{nameof(AssetBundleFileLoader)} need {nameof(IDecryptionServices)} : {MainBundleInfo.BundleName}");
throw new Exception($"{nameof(AssetBundleFileLoader)} need {nameof(IDecryptionServices)} : {MainBundleInfo.Bundle.BundleName}");
DecryptionFileInfo fileInfo = new DecryptionFileInfo();
fileInfo.BundleName = MainBundleInfo.BundleName;
fileInfo.BundleHash = MainBundleInfo.Hash;
fileInfo.BundleCRC = MainBundleInfo.CRC;
fileInfo.BundleName = MainBundleInfo.Bundle.BundleName;
fileInfo.FileHash = MainBundleInfo.Bundle.FileHash;
ulong offset = AssetSystem.DecryptionServices.GetFileOffset(fileInfo);
if (_isWaitForAsyncComplete)
CacheBundle = AssetBundle.LoadFromFile(_fileLoadPath, 0, offset);
else
_cacheRequest = AssetBundle.LoadFromFileAsync(_fileLoadPath, 0, offset);
_createRequest = AssetBundle.LoadFromFileAsync(_fileLoadPath, 0, offset);
}
else
{
if (_isWaitForAsyncComplete)
CacheBundle = AssetBundle.LoadFromFile(_fileLoadPath);
else
_cacheRequest = AssetBundle.LoadFromFileAsync(_fileLoadPath);
_createRequest = AssetBundle.LoadFromFileAsync(_fileLoadPath);
}
_steps = ESteps.CheckFile;
_steps = ESteps.CheckLoadFile;
}
// 4. 检测AssetBundle加载结果
if (_steps == ESteps.CheckFile)
if (_steps == ESteps.CheckLoadFile)
{
if (_cacheRequest != null)
if (_createRequest != null)
{
if (_isWaitForAsyncComplete)
{
// 强制挂起主线程(注意:该操作会很耗时)
YooLogger.Warning("Suspend the main thread to load unity bundle.");
CacheBundle = _cacheRequest.assetBundle;
CacheBundle = _createRequest.assetBundle;
}
else
{
if (_cacheRequest.isDone == false)
if (_createRequest.isDone == false)
return;
CacheBundle = _cacheRequest.assetBundle;
CacheBundle = _createRequest.assetBundle;
}
}
@@ -161,15 +151,15 @@ namespace YooAsset
{
_steps = ESteps.Done;
Status = EStatus.Failed;
LastError = $"Failed to load assetBundle : {MainBundleInfo.BundleName}";
LastError = $"Failed to load assetBundle : {MainBundleInfo.Bundle.BundleName}";
YooLogger.Error(LastError);
// 注意当缓存文件的校验等级为Low的时候并不能保证缓存文件的完整性。
// 在AssetBundle文件加载失败的情况下我们需要重新验证文件的完整性
if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromCache)
{
string cacheLoadPath = MainBundleInfo.GetCacheLoadPath();
if (DownloadSystem.CheckContentIntegrity(EVerifyLevel.High, cacheLoadPath, MainBundleInfo.SizeBytes, MainBundleInfo.CRC) == false)
string cacheLoadPath = MainBundleInfo.Bundle.CachedFilePath;
if (CacheSystem.VerifyBundle(MainBundleInfo.Bundle, EVerifyLevel.High) != EVerifyResult.Succeed)
{
if (File.Exists(cacheLoadPath))
{
@@ -205,7 +195,7 @@ namespace YooAsset
if (_isShowWaitForAsyncError == false)
{
_isShowWaitForAsyncError = true;
YooLogger.Error($"WaitForAsyncComplete failed ! Try load bundle : {MainBundleInfo.BundleName} from remote with sync load method !");
YooLogger.Error($"WaitForAsyncComplete failed ! Try load bundle : {MainBundleInfo.Bundle.BundleName} from remote with sync load method !");
}
break;
}

View File

@@ -91,9 +91,9 @@ namespace YooAsset
if (forceDestroy == false)
{
if (RefCount > 0)
throw new Exception($"Bundle file loader ref is not zero : {MainBundleInfo.BundleName}");
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.BundleName}");
throw new Exception($"Bundle file loader is not done : {MainBundleInfo.Bundle.BundleName}");
}
if (CacheBundle != null)

View File

@@ -1,4 +1,5 @@
using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
@@ -11,19 +12,25 @@ namespace YooAsset
private enum ESteps
{
None = 0,
LoadFile,
CheckFile,
TryLoad,
Download,
CheckDownload,
LoadCacheFile,
CheckLoadCacheFile,
LoadWebFile,
CheckLoadWebFile,
TryLoadWebFile,
Done,
}
private ESteps _steps = ESteps.None;
private float _tryTimer = 0;
private string _webURL;
private string _fileLoadPath;
private bool _isShowWaitForAsyncError = false;
private DownloaderBase _downloader;
private UnityWebRequest _webRequest;
private AssetBundleCreateRequest _createRequest;
public AssetBundleWebLoader(BundleInfo bundleInfo) : base(bundleInfo)
{
}
@@ -38,19 +45,20 @@ namespace YooAsset
if (_steps == ESteps.None)
{
if (MainBundleInfo.IsInvalid)
if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromRemote)
{
_steps = ESteps.Done;
Status = EStatus.Failed;
LastError = $"The bundle info is invalid : {MainBundleInfo.BundleName}";
YooLogger.Error(LastError);
return;
_steps = ESteps.Download;
_fileLoadPath = MainBundleInfo.Bundle.CachedFilePath;
}
if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromStreaming)
else if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromStreaming)
{
_steps = ESteps.LoadFile;
_webURL = MainBundleInfo.GetStreamingLoadPath();
_steps = ESteps.LoadWebFile;
_fileLoadPath = MainBundleInfo.Bundle.StreamingFilePath;
}
else if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromCache)
{
_steps = ESteps.LoadCacheFile;
_fileLoadPath = MainBundleInfo.Bundle.CachedFilePath;
}
else
{
@@ -58,16 +66,112 @@ namespace YooAsset
}
}
// 1. 从服务器或缓存中获取AssetBundle文件
if (_steps == ESteps.LoadFile)
// 1. 从服务器下载
if (_steps == ESteps.Download)
{
_webRequest = UnityWebRequestAssetBundle.GetAssetBundle(_webURL, Hash128.Parse(MainBundleInfo.Hash));
_webRequest.SendWebRequest();
_steps = ESteps.CheckFile;
int failedTryAgain = int.MaxValue;
_downloader = DownloadSystem.BeginDownload(MainBundleInfo, failedTryAgain);
_steps = ESteps.CheckDownload;
}
// 2. 检测获取的AssetBundle文件
if (_steps == ESteps.CheckFile)
// 2. 检测服务器下载结果
if (_steps == ESteps.CheckDownload)
{
if (_downloader.IsDone() == false)
return;
if (_downloader.HasError())
{
_steps = ESteps.Done;
Status = EStatus.Failed;
LastError = _downloader.GetLastError();
}
else
{
_steps = ESteps.LoadCacheFile;
}
}
// 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
// Load assetBundle file
if (MainBundleInfo.Bundle.IsEncrypted)
{
if (AssetSystem.DecryptionServices == null)
throw new Exception($"{nameof(AssetBundleFileLoader)} need {nameof(IDecryptionServices)} : {MainBundleInfo.Bundle.BundleName}");
DecryptionFileInfo fileInfo = new DecryptionFileInfo();
fileInfo.BundleName = MainBundleInfo.Bundle.BundleName;
fileInfo.FileHash = MainBundleInfo.Bundle.FileHash;
ulong offset = AssetSystem.DecryptionServices.GetFileOffset(fileInfo);
_createRequest = AssetBundle.LoadFromFileAsync(_fileLoadPath, 0, offset);
}
else
{
_createRequest = AssetBundle.LoadFromFileAsync(_fileLoadPath);
}
_steps = ESteps.CheckLoadCacheFile;
}
// 4. 检测AssetBundle加载结果
if (_steps == ESteps.CheckLoadCacheFile)
{
if (_createRequest.isDone == false)
return;
CacheBundle = _createRequest.assetBundle;
if (CacheBundle == null)
{
_steps = ESteps.Done;
Status = EStatus.Failed;
LastError = $"Failed to load AssetBundle file : {MainBundleInfo.Bundle.BundleName}";
YooLogger.Error(LastError);
// 注意当缓存文件的校验等级为Low的时候并不能保证缓存文件的完整性。
// 在AssetBundle文件加载失败的情况下我们需要重新验证文件的完整性
if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromCache)
{
string cacheLoadPath = MainBundleInfo.Bundle.CachedFilePath;
if (CacheSystem.VerifyBundle(MainBundleInfo.Bundle, EVerifyLevel.High) != EVerifyResult.Succeed)
{
if (File.Exists(cacheLoadPath))
{
YooLogger.Error($"Delete the invalid cache file : {cacheLoadPath}");
File.Delete(cacheLoadPath);
}
}
}
}
else
{
_steps = ESteps.Done;
Status = EStatus.Succeed;
}
}
// 5. 从WEB网站获取AssetBundle文件
if (_steps == ESteps.LoadWebFile)
{
_webRequest = UnityWebRequestAssetBundle.GetAssetBundle(_fileLoadPath, Hash128.Parse(MainBundleInfo.Bundle.FileHash));
_webRequest.SendWebRequest();
_steps = ESteps.CheckLoadWebFile;
}
// 6. 检测AssetBundle加载结果
if (_steps == ESteps.CheckLoadWebFile)
{
if (_webRequest.isDone == false)
return;
@@ -78,8 +182,8 @@ namespace YooAsset
if (_webRequest.isNetworkError || _webRequest.isHttpError)
#endif
{
YooLogger.Warning($"Failed to get asset bundle form web : {_webURL} Error : {_webRequest.error}");
_steps = ESteps.TryLoad;
YooLogger.Warning($"Failed to get asset bundle from web : {_fileLoadPath} Error : {_webRequest.error}");
_steps = ESteps.TryLoadWebFile;
_tryTimer = 0;
}
else
@@ -89,7 +193,7 @@ namespace YooAsset
{
_steps = ESteps.Done;
Status = EStatus.Failed;
LastError = $"AssetBundle file is invalid : {MainBundleInfo.BundleName}";
LastError = $"AssetBundle file is invalid : {MainBundleInfo.Bundle.BundleName}";
YooLogger.Error(LastError);
}
else
@@ -100,15 +204,15 @@ namespace YooAsset
}
}
// 3. 如果获取失败,重新尝试
if (_steps == ESteps.TryLoad)
// 7. 如果获取失败,重新尝试
if (_steps == ESteps.TryLoadWebFile)
{
_tryTimer += Time.unscaledDeltaTime;
if (_tryTimer > 1f)
{
_webRequest.Dispose();
_webRequest = null;
_steps = ESteps.LoadFile;
_steps = ESteps.LoadWebFile;
}
}
}

View File

@@ -102,7 +102,7 @@ namespace YooAsset
foreach (var loader in _dependBundles)
{
var bundleInfo = new DebugBundleInfo();
bundleInfo.BundleName = loader.MainBundleInfo.BundleName;
bundleInfo.BundleName = loader.MainBundleInfo.Bundle.BundleName;
bundleInfo.RefCount = loader.RefCount;
bundleInfo.Status = (int)loader.Status;
output.Add(bundleInfo);

View File

@@ -171,14 +171,14 @@ namespace YooAsset
{
None,
Prepare,
DownloadFromApk,
CheckDownloadFromApk,
DownloadBuildinFile,
CheckDownload,
CheckAndCopyFile,
Done,
}
private ESteps _steps = ESteps.None;
private UnityWebFileRequester _fileRequester;
private DownloaderBase _downloader;
public OfflinePlayModeRawFileOperation(BundleInfo bundleInfo, string copyPath) : base(bundleInfo, copyPath)
{
@@ -199,14 +199,15 @@ namespace YooAsset
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Bundle info is invalid : {_bundleInfo.BundleName}";
Error = $"Bundle info is invalid : {_bundleInfo.Bundle.BundleName}";
}
else if (_bundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromStreaming)
{
if (DownloadSystem.ContainsVerifyFile(_bundleInfo.Hash))
_steps = ESteps.CheckAndCopyFile;
else
_steps = ESteps.DownloadFromApk;
_steps = ESteps.DownloadBuildinFile;
}
else if (_bundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromCache)
{
_steps = ESteps.CheckAndCopyFile;
}
else
{
@@ -214,43 +215,32 @@ namespace YooAsset
}
}
// 2. 从APK拷贝文件
if (_steps == ESteps.DownloadFromApk)
// 2. 下载文件
if (_steps == ESteps.DownloadBuildinFile)
{
string downloadURL = PathHelper.ConvertToWWWPath(_bundleInfo.GetStreamingLoadPath());
_fileRequester = new UnityWebFileRequester();
_fileRequester.SendRequest(downloadURL, GetCachePath());
_steps = ESteps.CheckDownloadFromApk;
int failedTryAgain = int.MaxValue;
var bundleInfo = PatchHelper.ConvertToUnpackInfo(_bundleInfo.Bundle);
_downloader = DownloadSystem.BeginDownload(bundleInfo, failedTryAgain);
_steps = ESteps.CheckDownload;
}
// 3. 检测APK拷贝文件结果
if (_steps == ESteps.CheckDownloadFromApk)
// 3. 检测下载结果
if (_steps == ESteps.CheckDownload)
{
Progress = _fileRequester.Progress();
if (_fileRequester.IsDone() == false)
Progress = _downloader.DownloadProgress;
if (_downloader.IsDone() == false)
return;
if (_fileRequester.HasError())
if (_downloader.HasError())
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _fileRequester.GetError();
Error = _downloader.GetLastError();
}
else
{
if (DownloadSystem.CheckContentIntegrity(GetCachePath(), _bundleInfo.SizeBytes, _bundleInfo.CRC))
{
DownloadSystem.CacheVerifyFile(_bundleInfo.Hash, _bundleInfo.FileName);
_steps = ESteps.CheckAndCopyFile;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = "File content verify failed !";
}
_steps = ESteps.CheckAndCopyFile;
}
_fileRequester.Dispose();
}
// 4. 检测并拷贝原生文件
@@ -267,8 +257,8 @@ namespace YooAsset
// 如果原生文件已经存在,则验证其完整性
if (File.Exists(CopyPath))
{
bool result = DownloadSystem.CheckContentIntegrity(CopyPath, _bundleInfo.SizeBytes, _bundleInfo.CRC);
if (result)
var verifyResult = CacheSystem.VerifyContentInternal(CopyPath, _bundleInfo.Bundle.FileSize, _bundleInfo.Bundle.FileCRC, EVerifyLevel.High);
if (verifyResult == EVerifyResult.Succeed)
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
@@ -303,12 +293,12 @@ namespace YooAsset
{
if (_bundleInfo == null)
return string.Empty;
return _bundleInfo.GetCacheLoadPath();
return _bundleInfo.Bundle.CachedFilePath;
}
}
/// <summary>
/// 网络模式的原生文件操作
/// 联机模式的原生文件操作
/// </summary>
internal sealed class HostPlayModeRawFileOperation : RawFileOperation
{
@@ -316,17 +306,15 @@ namespace YooAsset
{
None,
Prepare,
DownloadFromWeb,
CheckDownloadFromWeb,
DownloadFromApk,
CheckDownloadFromApk,
DownloadWebFile,
DownloadBuildinFile,
CheckDownload,
CheckAndCopyFile,
Done,
}
private ESteps _steps = ESteps.None;
private DownloaderBase _downloader;
private UnityWebFileRequester _fileRequester;
internal HostPlayModeRawFileOperation(BundleInfo bundleInfo, string copyPath) : base(bundleInfo, copyPath)
{
@@ -347,18 +335,15 @@ namespace YooAsset
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = $"Bundle info is invalid : {_bundleInfo.BundleName}";
Error = $"Bundle info is invalid : {_bundleInfo.Bundle.BundleName}";
}
else if (_bundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromRemote)
{
_steps = ESteps.DownloadFromWeb;
_steps = ESteps.DownloadWebFile;
}
else if (_bundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromStreaming)
{
if (DownloadSystem.ContainsVerifyFile(_bundleInfo.Hash))
_steps = ESteps.CheckAndCopyFile;
else
_steps = ESteps.DownloadFromApk;
_steps = ESteps.DownloadBuildinFile;
}
else if (_bundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromCache)
{
@@ -370,16 +355,25 @@ namespace YooAsset
}
}
// 2. 从服务器下载
if (_steps == ESteps.DownloadFromWeb)
// 2. 下载远端文件
if (_steps == ESteps.DownloadWebFile)
{
int failedTryAgain = int.MaxValue;
_downloader = DownloadSystem.BeginDownload(_bundleInfo, failedTryAgain);
_steps = ESteps.CheckDownloadFromWeb;
_steps = ESteps.CheckDownload;
}
// 3. 检测服务器下载结果
if (_steps == ESteps.CheckDownloadFromWeb)
// 3. 下载内置文件
if (_steps == ESteps.DownloadBuildinFile)
{
int failedTryAgain = int.MaxValue;
var bundleInfo = PatchHelper.ConvertToUnpackInfo(_bundleInfo.Bundle);
_downloader = DownloadSystem.BeginDownload(bundleInfo, failedTryAgain);
_steps = ESteps.CheckDownload;
}
// 4. 检测下载结果
if (_steps == ESteps.CheckDownload)
{
Progress = _downloader.DownloadProgress;
if (_downloader.IsDone() == false)
@@ -397,46 +391,7 @@ namespace YooAsset
}
}
// 4. 从APK拷贝文件
if (_steps == ESteps.DownloadFromApk)
{
string downloadURL = PathHelper.ConvertToWWWPath(_bundleInfo.GetStreamingLoadPath());
_fileRequester = new UnityWebFileRequester();
_fileRequester.SendRequest(downloadURL, GetCachePath());
_steps = ESteps.CheckDownloadFromApk;
}
// 5. 检测APK拷贝文件结果
if (_steps == ESteps.CheckDownloadFromApk)
{
Progress = _fileRequester.Progress();
if (_fileRequester.IsDone() == false)
return;
if (_fileRequester.HasError())
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = _fileRequester.GetError();
}
else
{
if (DownloadSystem.CheckContentIntegrity(GetCachePath(), _bundleInfo.SizeBytes, _bundleInfo.CRC))
{
DownloadSystem.CacheVerifyFile(_bundleInfo.Hash, _bundleInfo.FileName);
_steps = ESteps.CheckAndCopyFile;
}
else
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
Error = "File content verify failed !";
}
}
_fileRequester.Dispose();
}
// 6. 检测并拷贝原生文件
// 5. 检测并拷贝原生文件
if (_steps == ESteps.CheckAndCopyFile)
{
// 如果不需要保存文件
@@ -450,8 +405,8 @@ namespace YooAsset
// 如果原生文件已经存在,则验证其完整性
if (File.Exists(CopyPath))
{
bool result = DownloadSystem.CheckContentIntegrity(CopyPath, _bundleInfo.SizeBytes, _bundleInfo.CRC);
if (result)
var verifyResult = CacheSystem.VerifyContentInternal(CopyPath, _bundleInfo.Bundle.FileSize, _bundleInfo.Bundle.FileCRC, EVerifyLevel.High);
if (verifyResult == EVerifyResult.Succeed)
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
@@ -486,7 +441,7 @@ namespace YooAsset
{
if (_bundleInfo == null)
return string.Empty;
return _bundleInfo.GetCacheLoadPath();
return _bundleInfo.Bundle.CachedFilePath;
}
}
}

View File

@@ -60,6 +60,16 @@ namespace YooAsset
return;
}
if (OwnerBundle.CacheBundle == null)
{
if (OwnerBundle.IsDestroyed)
throw new System.Exception("Should never get here !");
Status = EStatus.Fail;
LastError = $"The bundle {OwnerBundle.MainBundleInfo.Bundle.BundleName} has been destroyed by unity bugs !";
InvokeCompletion();
return;
}
Status = EStatus.Loading;
}
@@ -105,10 +115,10 @@ namespace YooAsset
Status = AssetObject == null ? EStatus.Fail : EStatus.Success;
if (Status == EStatus.Fail)
{
if(MainAssetInfo.AssetType == null)
LastError = $"Failed to load asset : {MainAssetInfo.AssetPath} AssetType : null AssetBundle : {OwnerBundle.MainBundleInfo.BundleName}";
if (MainAssetInfo.AssetType == null)
LastError = $"Failed to load asset : {MainAssetInfo.AssetPath} AssetType : null AssetBundle : {OwnerBundle.MainBundleInfo.Bundle.BundleName}";
else
LastError = $"Failed to load asset : {MainAssetInfo.AssetPath} AssetType : {MainAssetInfo.AssetType} AssetBundle : {OwnerBundle.MainBundleInfo.BundleName}";
LastError = $"Failed to load asset : {MainAssetInfo.AssetPath} AssetType : {MainAssetInfo.AssetType} AssetBundle : {OwnerBundle.MainBundleInfo.Bundle.BundleName}";
YooLogger.Error(LastError);
}
InvokeCompletion();

View File

@@ -41,7 +41,7 @@ namespace YooAsset
internal void GetBundleDebugInfos(List<DebugBundleInfo> output)
{
var bundleInfo = new DebugBundleInfo();
bundleInfo.BundleName = OwnerBundle.MainBundleInfo.BundleName;
bundleInfo.BundleName = OwnerBundle.MainBundleInfo.Bundle.BundleName;
bundleInfo.RefCount = OwnerBundle.RefCount;
bundleInfo.Status = (int)OwnerBundle.Status;
output.Add(bundleInfo);

View File

@@ -106,9 +106,9 @@ namespace YooAsset
if (Status == EStatus.Fail)
{
if (MainAssetInfo.AssetType == null)
LastError = $"Failed to load sub assets : {MainAssetInfo.AssetPath} AssetType : null AssetBundle : {OwnerBundle.MainBundleInfo.BundleName}";
LastError = $"Failed to load sub assets : {MainAssetInfo.AssetPath} AssetType : null AssetBundle : {OwnerBundle.MainBundleInfo.Bundle.BundleName}";
else
LastError = $"Failed to load sub assets : {MainAssetInfo.AssetPath} AssetType : {MainAssetInfo.AssetType} AssetBundle : {OwnerBundle.MainBundleInfo.BundleName}";
LastError = $"Failed to load sub assets : {MainAssetInfo.AssetPath} AssetType : {MainAssetInfo.AssetType} AssetBundle : {OwnerBundle.MainBundleInfo.Bundle.BundleName}";
YooLogger.Error(LastError);
}
InvokeCompletion();

View File

@@ -20,12 +20,12 @@ namespace YooAsset
public override void Update()
{
}
public void SetCompleted()
public void SetCompleted(string error)
{
if (Status == EStatus.None)
{
Status = EStatus.Fail;
LastError = MainAssetInfo.Error;
LastError = error;
InvokeCompletion();
}
}

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 55116a5bff2672b48be55ea42b5cc2dd
guid: 96a75a20111d6124696665e7aac3564c
folderAsset: yes
DefaultImporter:
externalObjects: {}

View File

@@ -0,0 +1,124 @@
using System;
using System.IO;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace YooAsset
{
internal static class CacheSystem
{
private readonly static Dictionary<string, PatchBundle> _cachedDic = new Dictionary<string, PatchBundle>(1000);
/// <summary>
/// 初始化时的验证级别
/// </summary>
public static EVerifyLevel InitVerifyLevel { private set; get; }
public static void Initialize(EVerifyLevel initVerifyLevel)
{
InitVerifyLevel = initVerifyLevel;
}
public static void DestroyAll()
{
_cachedDic.Clear();
}
/// <summary>
/// 查询是否为验证文件
/// 注意:被收录的文件完整性是绝对有效的
/// </summary>
public static bool IsCached(PatchBundle patchBundle)
{
string fileHash = patchBundle.FileHash;
if (_cachedDic.ContainsKey(fileHash))
{
string filePath = patchBundle.CachedFilePath;
if (File.Exists(filePath))
{
return true;
}
else
{
_cachedDic.Remove(fileHash);
YooLogger.Error($"Cache file is missing : {filePath}");
return false;
}
}
else
{
return false;
}
}
/// <summary>
/// 缓存补丁包文件
/// </summary>
public static void CacheBundle(PatchBundle patchBundle)
{
string fileHash = patchBundle.FileHash;
if (_cachedDic.ContainsKey(fileHash) == false)
{
string filePath = patchBundle.CachedFilePath;
YooLogger.Log($"Cache verify file : {filePath}");
_cachedDic.Add(fileHash, patchBundle);
}
}
/// <summary>
/// 验证补丁包文件
/// </summary>
public static EVerifyResult VerifyBundle(PatchBundle patchBundle, EVerifyLevel verifyLevel)
{
return VerifyContentInternal(patchBundle.CachedFilePath, patchBundle.FileSize, patchBundle.FileCRC, verifyLevel);
}
/// <summary>
/// 验证并缓存补丁包文件
/// </summary>
public static EVerifyResult VerifyAndCacheBundle(PatchBundle patchBundle, EVerifyLevel verifyLevel)
{
var verifyResult = VerifyContentInternal(patchBundle.CachedFilePath, patchBundle.FileSize, patchBundle.FileCRC, verifyLevel);
if (verifyResult == EVerifyResult.Succeed)
CacheBundle(patchBundle);
return verifyResult;
}
/// <summary>
/// 验证文件完整性
/// </summary>
public static EVerifyResult VerifyContentInternal(string filePath, long fileSize, string fileCRC, EVerifyLevel verifyLevel)
{
try
{
if (File.Exists(filePath) == false)
return EVerifyResult.FileNotExisted;
// 先验证文件大小
long size = FileUtility.GetFileSize(filePath);
if (size < fileSize)
return EVerifyResult.FileNotComplete;
else if (size > fileSize)
return EVerifyResult.FileOverflow;
// 再验证文件CRC
if (verifyLevel == EVerifyLevel.High)
{
string crc = HashUtility.FileCRC32(filePath);
if (crc == fileCRC)
return EVerifyResult.Succeed;
else
return EVerifyResult.FileCrcError;
}
else
{
return EVerifyResult.Succeed;
}
}
catch (Exception)
{
return EVerifyResult.Exception;
}
}
}
}

View File

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

View File

@@ -0,0 +1,39 @@

namespace YooAsset
{
/// <summary>
/// 下载文件校验结果
/// </summary>
public enum EVerifyResult
{
/// <summary>
/// 文件不存在
/// </summary>
FileNotExisted = -4,
/// <summary>
/// 文件内容不足(小于正常大小)
/// </summary>
FileNotComplete = -3,
/// <summary>
/// 文件内容溢出(超过正常大小)
/// </summary>
FileOverflow = -2,
/// <summary>
/// 文件内容不匹配
/// </summary>
FileCrcError = -1,
/// <summary>
/// 验证异常
/// </summary>
Exception = 0,
/// <summary>
/// 验证成功
/// </summary>
Succeed = 1,
}
}

View File

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

View File

@@ -0,0 +1,255 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Threading;
namespace YooAsset
{
/// <summary>
/// 本地缓存文件验证器
/// </summary>
internal abstract class PatchCacheVerifier
{
public abstract bool InitVerifier(PatchManifest appPatchManifest, PatchManifest localPatchManifest, bool weaklyUpdate);
public abstract bool UpdateVerifier();
public abstract float GetVerifierProgress();
public int VerifySuccessCount { protected set; get; } = 0;
public int VerifyFailCount { protected set; get; } = 0;
}
/// <summary>
/// 本地缓存文件验证器(线程版)
/// </summary>
internal class PatchCacheVerifierWithThread : PatchCacheVerifier
{
private class ThreadInfo
{
public EVerifyResult Result;
public string FilePath { private set; get; }
public PatchBundle Bundle { private set; get; }
public ThreadInfo(string filePath, PatchBundle bundle)
{
FilePath = filePath;
Bundle = bundle;
}
}
private readonly ThreadSyncContext _syncContext = new ThreadSyncContext();
private readonly List<PatchBundle> _waitingList = new List<PatchBundle>(1000);
private readonly List<PatchBundle> _verifyingList = new List<PatchBundle>(100);
private int _verifyMaxNum;
private int _verifyTotalCount;
public override bool InitVerifier(PatchManifest appPatchManifest, PatchManifest localPatchManifest, bool weaklyUpdate)
{
// 遍历所有文件然后验证并缓存合法文件
foreach (var patchBundle in localPatchManifest.BundleList)
{
// 忽略缓存文件
if (CacheSystem.IsCached(patchBundle))
continue;
// 忽略APP资源
// 注意如果是APP资源并且哈希值相同则不需要下载
if (appPatchManifest.TryGetPatchBundle(patchBundle.BundleName, out PatchBundle appPatchBundle))
{
if (appPatchBundle.IsBuildin && appPatchBundle.Equals(patchBundle))
continue;
}
// 注意:在弱联网模式下,我们需要验证指定资源版本的所有资源完整性
if (weaklyUpdate)
{
string filePath = patchBundle.CachedFilePath;
if (File.Exists(filePath))
_waitingList.Add(patchBundle);
else
return false;
}
else
{
string filePath = patchBundle.CachedFilePath;
if (File.Exists(filePath))
_waitingList.Add(patchBundle);
}
}
// 设置同时验证的最大数
ThreadPool.GetMaxThreads(out int workerThreads, out int ioThreads);
YooLogger.Log($"Work threads : {workerThreads}, IO threads : {ioThreads}");
_verifyMaxNum = Math.Min(workerThreads, ioThreads);
_verifyTotalCount = _waitingList.Count;
if (_verifyMaxNum < 1)
_verifyMaxNum = 1;
return true;
}
public override bool UpdateVerifier()
{
_syncContext.Update();
if (_waitingList.Count == 0 && _verifyingList.Count == 0)
return true;
if (_verifyingList.Count >= _verifyMaxNum)
return false;
for (int i = _waitingList.Count - 1; i >= 0; i--)
{
if (_verifyingList.Count >= _verifyMaxNum)
break;
var patchBundle = _waitingList[i];
if (VerifyFile(patchBundle))
{
_waitingList.RemoveAt(i);
_verifyingList.Add(patchBundle);
}
else
{
YooLogger.Warning("The thread pool is failed queued.");
break;
}
}
return false;
}
public override float GetVerifierProgress()
{
if (_verifyTotalCount == 0)
return 1f;
return (float)(VerifySuccessCount + VerifyFailCount) / _verifyTotalCount;
}
private bool VerifyFile(PatchBundle patchBundle)
{
string filePath = patchBundle.CachedFilePath;
ThreadInfo info = new ThreadInfo(filePath, patchBundle);
return ThreadPool.QueueUserWorkItem(new WaitCallback(VerifyInThread), info);
}
private void VerifyInThread(object infoObj)
{
ThreadInfo info = (ThreadInfo)infoObj;
info.Result = CacheSystem.VerifyBundle(info.Bundle, CacheSystem.InitVerifyLevel);
_syncContext.Post(VerifyCallback, info);
}
private void VerifyCallback(object obj)
{
ThreadInfo info = (ThreadInfo)obj;
if (info.Result == EVerifyResult.Succeed)
{
VerifySuccessCount++;
CacheSystem.CacheBundle(info.Bundle);
}
else
{
VerifyFailCount++;
YooLogger.Warning($"Failed to verify file : {info.Bundle.CachedFilePath}");
// NOTE不期望删除断点续传的资源文件
/*
if (File.Exists(patchBundle.CachedBundleFilePath))
File.Delete(patchBundle.CachedBundleFilePath);
*/
}
_verifyingList.Remove(info.Bundle);
}
}
/// <summary>
/// 本地缓存文件验证器(非线程版)
/// </summary>
internal class PatchCacheVerifierWithoutThread : PatchCacheVerifier
{
private readonly List<PatchBundle> _waitingList = new List<PatchBundle>(1000);
private readonly List<PatchBundle> _verifyingList = new List<PatchBundle>(100);
private int _verifyMaxNum;
private int _verifyTotalCount;
public override bool InitVerifier(PatchManifest appPatchManifest, PatchManifest localPatchManifest, bool weaklyUpdate)
{
// 遍历所有文件然后验证并缓存合法文件
foreach (var patchBundle in localPatchManifest.BundleList)
{
// 忽略缓存文件
if (CacheSystem.IsCached(patchBundle))
continue;
// 忽略APP资源
// 注意如果是APP资源并且哈希值相同则不需要下载
if (appPatchManifest.TryGetPatchBundle(patchBundle.BundleName, out PatchBundle appPatchBundle))
{
if (appPatchBundle.IsBuildin && appPatchBundle.Equals(patchBundle))
continue;
}
// 注意:在弱联网模式下,我们需要验证指定资源版本的所有资源完整性
if (weaklyUpdate)
{
string filePath = patchBundle.CachedFilePath;
if (File.Exists(filePath))
_waitingList.Add(patchBundle);
else
return false;
}
else
{
string filePath = patchBundle.CachedFilePath;
if (File.Exists(filePath))
_waitingList.Add(patchBundle);
}
}
// 设置同时验证的最大数
_verifyMaxNum = 32;
_verifyTotalCount = _waitingList.Count;
return true;
}
public override bool UpdateVerifier()
{
if (_waitingList.Count == 0 && _verifyingList.Count == 0)
return true;
for (int i = _waitingList.Count - 1; i >= 0; i--)
{
if (_verifyingList.Count >= _verifyMaxNum)
break;
var patchBundle = _waitingList[i];
VerifyFile(patchBundle);
_waitingList.RemoveAt(i);
_verifyingList.Add(patchBundle);
}
_verifyingList.Clear();
return false;
}
public override float GetVerifierProgress()
{
if (_verifyTotalCount == 0)
return 1f;
return (float)(VerifySuccessCount + VerifyFailCount) / _verifyTotalCount;
}
private void VerifyFile(PatchBundle patchBundle)
{
var verifyResult = CacheSystem.VerifyAndCacheBundle(patchBundle, CacheSystem.InitVerifyLevel);
if (verifyResult == EVerifyResult.Succeed)
{
VerifySuccessCount++;
}
else
{
VerifyFailCount++;
YooLogger.Warning($"Failed to verify file : {patchBundle.CachedFilePath}");
// NOTE不期望删除断点续传的资源文件
/*
if (File.Exists(patchBundle.CachedBundleFilePath))
File.Delete(patchBundle.CachedBundleFilePath);
*/
}
}
}
}

View File

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

View File

@@ -14,18 +14,15 @@ namespace YooAsset
{
private static readonly Dictionary<string, DownloaderBase> _downloaderDic = new Dictionary<string, DownloaderBase>();
private static readonly List<string> _removeList = new List<string>(100);
private static readonly Dictionary<string, string> _cachedHashList = new Dictionary<string, string>(1000);
private static int _breakpointResumeFileSize = int.MaxValue;
private static EVerifyLevel _verifyLevel = EVerifyLevel.High;
/// <summary>
/// 初始化
/// </summary>
public static void Initialize(int breakpointResumeFileSize, EVerifyLevel verifyLevel)
public static void Initialize(int breakpointResumeFileSize)
{
_breakpointResumeFileSize = breakpointResumeFileSize;
_verifyLevel = verifyLevel;
}
/// <summary>
@@ -62,7 +59,6 @@ namespace YooAsset
}
_downloaderDic.Clear();
_removeList.Clear();
_cachedHashList.Clear();
_breakpointResumeFileSize = int.MaxValue;
}
@@ -74,13 +70,13 @@ namespace YooAsset
public static DownloaderBase BeginDownload(BundleInfo bundleInfo, int failedTryAgain, int timeout = 60)
{
// 查询存在的下载器
if (_downloaderDic.TryGetValue(bundleInfo.Hash, out var downloader))
if (_downloaderDic.TryGetValue(bundleInfo.Bundle.CachedFilePath, out var downloader))
{
return downloader;
}
// 如果资源已经缓存
if (ContainsVerifyFile(bundleInfo.Hash))
if (CacheSystem.IsCached(bundleInfo.Bundle))
{
var tempDownloader = new TempDownloader(bundleInfo);
return tempDownloader;
@@ -88,15 +84,12 @@ namespace YooAsset
// 创建新的下载器
{
YooLogger.Log($"Beginning to download file : {bundleInfo.FileName} URL : {bundleInfo.RemoteMainURL}");
FileUtility.CreateFileDirectory(bundleInfo.GetCacheLoadPath());
DownloaderBase newDownloader;
if (bundleInfo.SizeBytes >= _breakpointResumeFileSize)
newDownloader = new HttpDownloader(bundleInfo);
else
newDownloader = new FileDownloader(bundleInfo);
YooLogger.Log($"Beginning to download file : {bundleInfo.Bundle.FileName} URL : {bundleInfo.RemoteMainURL}");
FileUtility.CreateFileDirectory(bundleInfo.Bundle.CachedFilePath);
bool breakDownload = bundleInfo.Bundle.FileSize >= _breakpointResumeFileSize;
DownloaderBase newDownloader = new FileDownloader(bundleInfo, breakDownload);
newDownloader.SendRequest(failedTryAgain, timeout);
_downloaderDic.Add(bundleInfo.Hash, newDownloader);
_downloaderDic.Add(bundleInfo.Bundle.CachedFilePath, newDownloader);
return newDownloader;
}
}
@@ -108,84 +101,5 @@ namespace YooAsset
{
return _downloaderDic.Count;
}
/// <summary>
/// 查询是否为验证文件
/// 注意:被收录的文件完整性是绝对有效的
/// </summary>
public static bool ContainsVerifyFile(string hash)
{
if (_cachedHashList.ContainsKey(hash))
{
string fileName = _cachedHashList[hash];
string filePath = SandboxHelper.MakeCacheFilePath(fileName);
if (File.Exists(filePath))
{
return true;
}
else
{
_cachedHashList.Remove(hash);
YooLogger.Error($"Cache file is missing : {fileName}");
return false;
}
}
else
{
return false;
}
}
/// <summary>
/// 缓存验证过的文件
/// </summary>
public static void CacheVerifyFile(string hash, string fileName)
{
if (_cachedHashList.ContainsKey(hash) == false)
{
YooLogger.Log($"Cache verify file : {fileName}");
_cachedHashList.Add(hash, fileName);
}
}
/// <summary>
/// 验证文件完整性
/// </summary>
public static bool CheckContentIntegrity(string filePath, long size, string crc)
{
return CheckContentIntegrity(_verifyLevel, filePath, size, crc);
}
/// <summary>
/// 验证文件完整性
/// </summary>
public static bool CheckContentIntegrity(EVerifyLevel verifyLevel, string filePath, long size, string crc)
{
try
{
if (File.Exists(filePath) == false)
return false;
// 先验证文件大小
long fileSize = FileUtility.GetFileSize(filePath);
if (fileSize != size)
return false;
// 再验证文件CRC
if (verifyLevel == EVerifyLevel.High)
{
string fileCRC = HashUtility.FileCRC32(filePath);
return fileCRC == crc;
}
else
{
return true;
}
}
catch (Exception)
{
return false;
}
}
}
}

View File

@@ -0,0 +1,87 @@
using System;
using System.IO;
using UnityEngine;
using UnityEngine.Networking;
namespace YooAsset
{
/// <summary>
/// 支持Unity2018版本的断点续传下载器
/// </summary>
public class DownloadHandlerFileRange : DownloadHandlerScript
{
private string _fileSavePath;
private long _fileTotalSize;
private UnityWebRequest _webRequest;
private FileStream _fileStream;
private long _localFileSize = 0;
private long _curFileSize = 0;
public DownloadHandlerFileRange(string fileSavePath, long fileTotalSize, UnityWebRequest webRequest) : base(new byte[1024 * 1024])
{
_fileSavePath = fileSavePath;
_fileTotalSize = fileTotalSize;
_webRequest = webRequest;
if (File.Exists(fileSavePath))
{
FileInfo fileInfo = new FileInfo(fileSavePath);
_localFileSize = fileInfo.Length;
}
_fileStream = new FileStream(_fileSavePath, FileMode.Append, FileAccess.Write);
_curFileSize = _localFileSize;
}
protected override bool ReceiveData(byte[] data, int dataLength)
{
if (data == null || dataLength == 0 || _webRequest.responseCode >= 400)
return false;
if (_fileStream == null)
return false;
_fileStream.Write(data, 0, dataLength);
_curFileSize += dataLength;
return true;
}
/// <summary>
/// UnityWebRequest.downloadHandler.data
/// </summary>
protected override byte[] GetData()
{
return null;
}
/// <summary>
/// UnityWebRequest.downloadHandler.text
/// </summary>
protected override string GetText()
{
return null;
}
/// <summary>
/// UnityWebRequest.downloadProgress
/// </summary>
protected override float GetProgress()
{
return _fileTotalSize == 0 ? 0 : ((float)_curFileSize) / _fileTotalSize;
}
/// <summary>
/// 释放下载句柄
/// </summary>
public void Cleanup()
{
if (_fileStream != null)
{
_fileStream.Flush();
_fileStream.Dispose();
_fileStream = null;
}
}
}
}

View File

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

View File

@@ -6,6 +6,7 @@ namespace YooAsset
protected enum ESteps
{
None,
CheckLocalFile,
CreateDownload,
CheckDownload,
TryAgain,
@@ -54,7 +55,7 @@ namespace YooAsset
{
_failedTryAgain = failedTryAgain;
_timeout = timeout;
_steps = ESteps.CreateDownload;
_steps = ESteps.CheckLocalFile;
}
}
public abstract void Update();

View File

@@ -9,8 +9,9 @@ namespace YooAsset
{
internal sealed class FileDownloader : DownloaderBase
{
private UnityWebRequest _webRequest;
private UnityWebRequestAsyncOperation _operationHandle;
private readonly bool _breakResume;
private UnityWebRequest _webRequest = null;
private DownloadHandlerFileRange _downloadHandle = null;
// 重置变量
private bool _isAbort = false;
@@ -19,8 +20,9 @@ namespace YooAsset
private float _tryAgainTimer;
public FileDownloader(BundleInfo bundleInfo) : base(bundleInfo)
public FileDownloader(BundleInfo bundleInfo, bool breakResume) : base(bundleInfo)
{
_breakResume = breakResume;
}
public override void Update()
{
@@ -29,9 +31,31 @@ namespace YooAsset
if (IsDone())
return;
// 检测本地文件
if (_steps == ESteps.CheckLocalFile)
{
var verifyResult = CacheSystem.VerifyAndCacheBundle(_bundleInfo.Bundle, EVerifyLevel.High);
if (verifyResult == EVerifyResult.Succeed)
{
_steps = ESteps.Succeed;
}
else
{
if (verifyResult == EVerifyResult.FileOverflow)
{
string cacheFilePath = _bundleInfo.Bundle.CachedFilePath;
if (File.Exists(cacheFilePath))
File.Delete(cacheFilePath);
}
_steps = ESteps.CreateDownload;
}
}
// 创建下载器
if (_steps == ESteps.CreateDownload)
{
string fileSavePath = _bundleInfo.Bundle.CachedFilePath;
// 重置变量
_downloadProgress = 0f;
_downloadedBytes = 0;
@@ -40,14 +64,45 @@ namespace YooAsset
_latestDownloadRealtime = Time.realtimeSinceStartup;
_tryAgainTimer = 0f;
_requestURL = GetRequestURL();
_webRequest = new UnityWebRequest(_requestURL, UnityWebRequest.kHttpVerbGET);
DownloadHandlerFile handler = new DownloadHandlerFile(_bundleInfo.GetCacheLoadPath());
handler.removeFileOnAbort = true;
_webRequest.downloadHandler = handler;
_webRequest.disposeDownloadHandlerOnDispose = true;
_operationHandle = _webRequest.SendWebRequest();
_steps = ESteps.CheckDownload;
// 是否开启断点续传下载
if (_breakResume)
{
long fileLength = -1;
if (File.Exists(fileSavePath))
{
FileInfo fileInfo = new FileInfo(fileSavePath);
fileLength = fileInfo.Length;
}
_requestURL = GetRequestURL();
_webRequest = UnityWebRequest.Get(_requestURL);
#if UNITY_2019_4_OR_NEWER
var handler = new DownloadHandlerFile(fileSavePath, true);
handler.removeFileOnAbort = false;
#else
var handler = new DownloadHandlerFileRange(fileSavePath, _bundleInfo.Bundle.FileSize, _webRequest);
_downloadHandle = handler;
#endif
_webRequest.downloadHandler = handler;
_webRequest.disposeDownloadHandlerOnDispose = true;
if (fileLength > 0)
_webRequest.SetRequestHeader("Range", $"bytes={fileLength}-");
_webRequest.SendWebRequest();
_steps = ESteps.CheckDownload;
}
else
{
_requestURL = GetRequestURL();
_webRequest = new UnityWebRequest(_requestURL, UnityWebRequest.kHttpVerbGET);
DownloadHandlerFile handler = new DownloadHandlerFile(fileSavePath);
handler.removeFileOnAbort = true;
_webRequest.downloadHandler = handler;
_webRequest.disposeDownloadHandlerOnDispose = true;
_webRequest.SendWebRequest();
_steps = ESteps.CheckDownload;
}
}
// 检测下载结果
@@ -55,14 +110,15 @@ namespace YooAsset
{
_downloadProgress = _webRequest.downloadProgress;
_downloadedBytes = _webRequest.downloadedBytes;
if (_operationHandle.isDone == false)
if (_webRequest.isDone == false)
{
CheckTimeout();
return;
}
// 检查网络错误
bool hasError = false;
// 检查网络错误
#if UNITY_2020_3_OR_NEWER
if (_webRequest.result != UnityWebRequest.Result.Success)
{
@@ -80,24 +136,29 @@ namespace YooAsset
// 检查文件完整性
if (hasError == false)
{
// 注意:如果文件验证失败需要删除文件
if (DownloadSystem.CheckContentIntegrity(_bundleInfo.GetCacheLoadPath(), _bundleInfo.SizeBytes, _bundleInfo.CRC) == false)
var verifyResult = CacheSystem.VerifyAndCacheBundle(_bundleInfo.Bundle, EVerifyLevel.High);
if (verifyResult != EVerifyResult.Succeed)
{
hasError = true;
_lastError = $"Verification failed";
_lastError = $"Verify bundle content failed : {_bundleInfo.Bundle.FileName}";
// 验证失败后删除文件
string cacheFilePath = _bundleInfo.Bundle.CachedFilePath;
if (File.Exists(cacheFilePath))
File.Delete(cacheFilePath);
}
}
if (hasError == false)
// 如果下载失败
if (hasError)
{
_steps = ESteps.Succeed;
DownloadSystem.CacheVerifyFile(_bundleInfo.Hash, _bundleInfo.FileName);
}
else
{
string cacheFilePath = _bundleInfo.GetCacheLoadPath();
if (File.Exists(cacheFilePath))
File.Delete(cacheFilePath);
// 注意:非断点续传下载失败后删除文件
if (_breakResume == false)
{
string cacheFilePath = _bundleInfo.Bundle.CachedFilePath;
if (File.Exists(cacheFilePath))
File.Delete(cacheFilePath);
}
// 失败后重新尝试
if (_failedTryAgain > 0)
@@ -111,6 +172,11 @@ namespace YooAsset
_steps = ESteps.Failed;
}
}
else
{
_lastError = string.Empty;
_steps = ESteps.Succeed;
}
// 释放下载器
DisposeWebRequest();
@@ -160,11 +226,16 @@ namespace YooAsset
}
private void DisposeWebRequest()
{
if(_downloadHandle != null)
{
_downloadHandle.Cleanup();
_downloadHandle = null;
}
if (_webRequest != null)
{
_webRequest.Dispose();
_webRequest = null;
_operationHandle = null;
}
}
}

View File

@@ -8,6 +8,7 @@ using System.Threading;
namespace YooAsset
{
/*
internal sealed class HttpDownloader : DownloaderBase
{
/// <summary>
@@ -21,8 +22,6 @@ namespace YooAsset
private bool _running = true;
private string _url;
private string _savePath;
private string _fileName;
private string _fileCRC;
private long _fileSize;
private int _timeout;
@@ -50,12 +49,10 @@ namespace YooAsset
/// <summary>
/// 开始下载
/// </summary>
public void Run(string url, string savePath, string fileName, string fileCRC, long fileSize, int timeout)
public void Run(string url, string savePath, long fileSize, int timeout)
{
_url = url;
_savePath = savePath;
_fileName = fileName;
_fileCRC = fileCRC;
_fileSize = fileSize;
_timeout = timeout;
@@ -153,22 +150,6 @@ namespace YooAsset
fileStream.Close();
}
// 验证下载文件完整性
if (DownloadedBytes == (ulong)_fileSize)
{
bool verfiyResult = DownloadSystem.CheckContentIntegrity(_savePath, _fileSize, _fileCRC);
if (verfiyResult == false)
{
Error = $"Verify download content failed : {_fileName}";
if (File.Exists(_savePath))
File.Delete(_savePath);
}
}
else
{
Error = $"Download content is incomplete : {_fileName}";
}
IsDone = true;
}
}
@@ -188,6 +169,27 @@ namespace YooAsset
if (IsDone())
return;
// 检测本地文件
if (_steps == ESteps.CheckLocalFile)
{
var verifyResult = CacheSystem.VerifyAndCacheBundle(_bundleInfo.Bundle, EVerifyLevel.High);
if (verifyResult == EVerifyResult.Succeed)
{
_steps = ESteps.Succeed;
}
else
{
if (verifyResult == EVerifyResult.FileOverflow)
{
string cacheFilePath = _bundleInfo.Bundle.CachedFilePath;
if (File.Exists(cacheFilePath))
File.Delete(cacheFilePath);
}
_steps = ESteps.CreateDownload;
}
}
// 创建下载器
if (_steps == ESteps.CreateDownload)
{
// 重置变量
@@ -197,10 +199,11 @@ namespace YooAsset
_requestURL = GetRequestURL();
_threadDownloader = new ThreadDownloader();
_threadDownloader.Run(_requestURL, _bundleInfo.GetCacheLoadPath(), _bundleInfo.FileName, _bundleInfo.CRC, _bundleInfo.SizeBytes, _timeout);
_threadDownloader.Run(_requestURL, _bundleInfo.Bundle.CachedFilePath, _bundleInfo.Bundle.FileSize, _timeout);
_steps = ESteps.CheckDownload;
}
// 检测下载结果
if (_steps == ESteps.CheckDownload)
{
_downloadProgress = _threadDownloader.DownloadProgress;
@@ -208,10 +211,34 @@ namespace YooAsset
if (_threadDownloader.IsDone == false)
return;
bool hasError = false;
// 检查下载错误
if (_threadDownloader.HasError())
{
hasError = true;
_lastError = _threadDownloader.Error;
}
// 检查文件完整性
if (hasError == false)
{
var verifyResult = CacheSystem.VerifyAndCacheBundle(_bundleInfo.Bundle, EVerifyLevel.High);
if (verifyResult != EVerifyResult.Succeed)
{
hasError = true;
_lastError = $"Verify bundle content failed : {_bundleInfo.Bundle.FileName}";
// 验证失败后删除文件
string cacheFilePath = _bundleInfo.Bundle.CachedFilePath;
if (File.Exists(cacheFilePath))
File.Delete(cacheFilePath);
}
}
// 如果下载失败
if (hasError)
{
// 失败后重新尝试
if (_failedTryAgain > 0)
{
@@ -226,7 +253,7 @@ namespace YooAsset
}
else
{
DownloadSystem.CacheVerifyFile(_bundleInfo.Hash, _bundleInfo.FileName);
_lastError = string.Empty;
_steps = ESteps.Succeed;
}
}
@@ -257,4 +284,5 @@ namespace YooAsset
}
}
}
*/
}

View File

@@ -6,7 +6,7 @@ namespace YooAsset
public TempDownloader(BundleInfo bundleInfo) : base(bundleInfo)
{
_downloadProgress = 1f;
_downloadedBytes = (ulong)bundleInfo.SizeBytes;
_downloadedBytes = (ulong)bundleInfo.Bundle.FileSize;
_steps = ESteps.Succeed;
}

View File

@@ -13,6 +13,17 @@ namespace YooAsset
private static long _maxTimeSlice;
private static long _frameTime;
/// <summary>
/// 处理器是否繁忙
/// </summary>
public static bool IsBusy
{
get
{
return _watch.ElapsedMilliseconds - _frameTime >= _maxTimeSlice;
}
}
/// <summary>
/// 初始化异步操作系统
@@ -32,7 +43,7 @@ namespace YooAsset
for (int i = _operations.Count - 1; i >= 0; i--)
{
if (_watch.ElapsedMilliseconds - _frameTime >= _maxTimeSlice)
if (IsBusy)
return;
var operation = _operations[i];
@@ -59,7 +70,7 @@ namespace YooAsset
/// <summary>
/// 开始处理异步操作类
/// </summary>
public static void StartOperaiton(AsyncOperationBase operationBase)
public static void StartOperation(AsyncOperationBase operationBase)
{
_operations.Add(operationBase);
operationBase.Start();

View File

@@ -12,22 +12,9 @@ namespace YooAsset
LoadFromEditor,
}
private readonly PatchBundle _patchBundle;
public readonly PatchBundle Bundle;
public readonly ELoadMode LoadMode;
private string _streamingPath;
private string _cachePath;
/// <summary>
/// 资源包名称
/// </summary>
public string BundleName { private set; get; }
/// <summary>
/// 文件名称
/// </summary>
public string FileName { private set; get; }
/// <summary>
/// 远端下载地址
/// </summary>
@@ -43,147 +30,35 @@ namespace YooAsset
/// </summary>
public string EditorAssetPath { private set; get; }
/// <summary>
/// 文件哈希值
/// </summary>
public string Hash
{
get
{
if (_patchBundle == null)
return string.Empty;
else
return _patchBundle.Hash;
}
}
/// <summary>
/// 校验的CRC
/// </summary>
public string CRC
{
get
{
if (_patchBundle == null)
return string.Empty;
else
return _patchBundle.CRC;
}
}
/// <summary>
/// 文件大小
/// </summary>
public long SizeBytes
{
get
{
if (_patchBundle == null)
return 0;
else
return _patchBundle.SizeBytes;
}
}
/// <summary>
/// 是否为加密文件
/// </summary>
public bool IsEncrypted
{
get
{
if (_patchBundle == null)
return false;
else
return _patchBundle.IsEncrypted;
}
}
/// <summary>
/// 是否为原生文件
/// </summary>
public bool IsRawFile
{
get
{
if (_patchBundle == null)
return false;
else
return _patchBundle.IsRawFile;
}
}
/// <summary>
/// 身份是否无效
/// </summary>
public bool IsInvalid
{
get
{
return _patchBundle == null;
}
}
private BundleInfo()
{
}
public BundleInfo(PatchBundle patchBundle, ELoadMode loadMode, string mainURL, string fallbackURL)
{
_patchBundle = patchBundle;
Bundle = patchBundle;
LoadMode = loadMode;
BundleName = patchBundle.BundleName;
FileName = patchBundle.FileName;
RemoteMainURL = mainURL;
RemoteFallbackURL = fallbackURL;
EditorAssetPath = string.Empty;
}
public BundleInfo(PatchBundle patchBundle, ELoadMode loadMode, string editorAssetPath)
{
_patchBundle = patchBundle;
Bundle = patchBundle;
LoadMode = loadMode;
BundleName = patchBundle.BundleName;
FileName = patchBundle.FileName;
RemoteMainURL = string.Empty;
RemoteFallbackURL = string.Empty;
EditorAssetPath = editorAssetPath;
}
public BundleInfo(PatchBundle patchBundle, ELoadMode loadMode)
{
_patchBundle = patchBundle;
Bundle = patchBundle;
LoadMode = loadMode;
BundleName = patchBundle.BundleName;
FileName = patchBundle.FileName;
RemoteMainURL = string.Empty;
RemoteFallbackURL = string.Empty;
EditorAssetPath = string.Empty;
}
/// <summary>
/// 获取流文件夹的加载路径
/// </summary>
public string GetStreamingLoadPath()
{
if (_patchBundle == null)
return string.Empty;
if (string.IsNullOrEmpty(_streamingPath))
_streamingPath = PathHelper.MakeStreamingLoadPath(_patchBundle.FileName);
return _streamingPath;
}
/// <summary>
/// 获取缓存文件夹的加载路径
/// </summary>
public string GetCacheLoadPath()
{
if (_patchBundle == null)
return string.Empty;
if (string.IsNullOrEmpty(_cachePath))
_cachePath = SandboxHelper.MakeCacheFilePath(_patchBundle.FileName);
return _cachePath;
}
/// <summary>
/// 是否为JAR包内文件

View File

@@ -0,0 +1,111 @@
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
namespace YooAsset
{
/// <summary>
/// 清理未使用的缓存资源操作类
/// </summary>
public abstract class ClearUnusedCacheFilesOperation : AsyncOperationBase
{
}
/// <summary>
/// 编辑器模式
/// </summary>
internal sealed class EditorPlayModeClearUnusedCacheFilesOperation : ClearUnusedCacheFilesOperation
{
internal override void Start()
{
Status = EOperationStatus.Succeed;
}
internal override void Update()
{
}
}
/// <summary>
/// 离线模式
/// </summary>
internal sealed class OfflinePlayModeClearUnusedCacheFilesOperation : ClearUnusedCacheFilesOperation
{
internal override void Start()
{
Status = EOperationStatus.Succeed;
}
internal override void Update()
{
}
}
/// <summary>
/// 联机模式
/// </summary>
internal sealed class HostPlayModeClearUnusedCacheFilesOperation : ClearUnusedCacheFilesOperation
{
private enum ESteps
{
None,
GetUnusedCacheFiles,
ClearUnusedCacheFiles,
Done,
}
private ESteps _steps = ESteps.None;
private List<string> _unusedCacheFilePaths;
private int _unusedFileTotalCount = 0;
private HostPlayModeImpl _impl;
internal HostPlayModeClearUnusedCacheFilesOperation(HostPlayModeImpl impl)
{
_impl = impl;
}
internal override void Start()
{
_steps = ESteps.GetUnusedCacheFiles;
}
internal override void Update()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.GetUnusedCacheFiles)
{
_unusedCacheFilePaths = _impl.ClearUnusedCacheFilePaths();
_unusedFileTotalCount = _unusedCacheFilePaths.Count;
YooLogger.Log($"Found unused cache file count : {_unusedFileTotalCount}");
_steps = ESteps.ClearUnusedCacheFiles;
}
if (_steps == ESteps.ClearUnusedCacheFiles)
{
for (int i = _unusedCacheFilePaths.Count - 1; i >= 0; i--)
{
string filePath = _unusedCacheFilePaths[i];
if (File.Exists(filePath))
{
YooLogger.Log($"Delete unused cache file : {filePath}");
File.Delete(filePath);
}
_unusedCacheFilePaths.RemoveAt(i);
if (OperationSystem.IsBusy)
break;
}
if (_unusedFileTotalCount == 0)
Progress = 1.0f;
else
Progress = 1.0f - (_unusedCacheFilePaths.Count / _unusedFileTotalCount);
if (_unusedCacheFilePaths.Count == 0)
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}
}
}
}
}

View File

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

View File

@@ -86,7 +86,7 @@ namespace YooAsset
TotalDownloadCount = downloadList.Count;
foreach (var patchBundle in downloadList)
{
TotalDownloadBytes += patchBundle.SizeBytes;
TotalDownloadBytes += patchBundle.Bundle.FileSize;
}
}
}
@@ -138,7 +138,7 @@ namespace YooAsset
// 下载成功
_removeList.Add(downloader);
CurrentDownloadCount++;
CurrentDownloadBytes += bundleInfo.SizeBytes;
CurrentDownloadBytes += bundleInfo.Bundle.FileSize;
}
// 移除已经完成的下载器(无论成功或失败)
@@ -170,7 +170,7 @@ namespace YooAsset
var operation = DownloadSystem.BeginDownload(bundleInfo, _failedTryAgain);
_downloaders.Add(operation);
_downloadList.RemoveAt(index);
OnStartDownloadFileCallback?.Invoke(bundleInfo.BundleName, bundleInfo.SizeBytes);
OnStartDownloadFileCallback?.Invoke(bundleInfo.Bundle.BundleName, bundleInfo.Bundle.FileSize);
}
}
@@ -180,7 +180,7 @@ namespace YooAsset
if (_failedList.Count > 0)
{
var failedDownloader = _failedList[0];
string fileName = failedDownloader.GetBundleInfo().BundleName;
string fileName = failedDownloader.GetBundleInfo().Bundle.BundleName;
Error = $"Failed to download file : {fileName}";
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
@@ -205,7 +205,7 @@ namespace YooAsset
{
if (_steps == ESteps.None)
{
OperationSystem.StartOperaiton(this);
OperationSystem.StartOperation(this);
}
}

View File

@@ -129,7 +129,7 @@ namespace YooAsset
}
/// <summary>
/// 网络运行模式的初始化操作
/// 联机运行模式的初始化操作
/// </summary>
internal sealed class HostPlayModeInitializationOperation : InitializationOperation
{

View File

@@ -2,7 +2,6 @@
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Threading;
namespace YooAsset
{
@@ -46,7 +45,7 @@ namespace YooAsset
}
/// <summary>
/// 网络模式的更新清单操作
/// 联机模式的更新清单操作
/// </summary>
internal sealed class HostPlayModeUpdateManifestOperation : UpdateManifestOperation
{
@@ -69,7 +68,7 @@ namespace YooAsset
private ESteps _steps = ESteps.None;
private UnityWebDataRequester _downloader1;
private UnityWebDataRequester _downloader2;
private VerifyManager _verifyManager = new VerifyManager();
private PatchCacheVerifier _patchCacheVerifier;
private float _verifyTime;
internal HostPlayModeUpdateManifestOperation(HostPlayModeImpl impl, int resourceVersion, int timeout)
@@ -77,6 +76,12 @@ namespace YooAsset
_impl = impl;
_resourceVersion = resourceVersion;
_timeout = timeout;
#if UNITY_WEBGL
_patchCacheVerifier = new PatchCacheVerifierWithoutThread();
#else
_patchCacheVerifier = new PatchCacheVerifierWithThread();
#endif
}
internal override void Start()
{
@@ -172,20 +177,20 @@ namespace YooAsset
if (_steps == ESteps.InitVerifyingCache)
{
_verifyManager.InitVerifyingCache(_impl.AppPatchManifest, _impl.LocalPatchManifest, false);
_patchCacheVerifier.InitVerifier(_impl.AppPatchManifest, _impl.LocalPatchManifest, false);
_verifyTime = UnityEngine.Time.realtimeSinceStartup;
_steps = ESteps.UpdateVerifyingCache;
}
if (_steps == ESteps.UpdateVerifyingCache)
{
Progress = _verifyManager.GetVerifyProgress();
if (_verifyManager.UpdateVerifyingCache())
Progress = _patchCacheVerifier.GetVerifierProgress();
if (_patchCacheVerifier.UpdateVerifier())
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
float costTime = UnityEngine.Time.realtimeSinceStartup - _verifyTime;
YooLogger.Log($"Verify result : Success {_verifyManager.VerifySuccessCount}, Fail {_verifyManager.VerifyFailCount}, Elapsed time {costTime} seconds");
YooLogger.Log($"Verify result : Success {_patchCacheVerifier.VerifySuccessCount}, Fail {_patchCacheVerifier.VerifyFailCount}, Elapsed time {costTime} seconds");
}
}
}
@@ -252,7 +257,7 @@ namespace YooAsset
}
/// <summary>
/// 网络模式的更新清单操作(弱联网)
/// 联机模式的更新清单操作(弱联网)
/// </summary>
internal sealed class HostPlayModeWeaklyUpdateManifestOperation : UpdateManifestOperation
{
@@ -268,13 +273,19 @@ namespace YooAsset
private readonly HostPlayModeImpl _impl;
private readonly int _resourceVersion;
private ESteps _steps = ESteps.None;
private VerifyManager _verifyManager = new VerifyManager();
private PatchCacheVerifier _patchCacheVerifier;
private float _verifyTime;
internal HostPlayModeWeaklyUpdateManifestOperation(HostPlayModeImpl impl, int resourceVersion)
{
_impl = impl;
_resourceVersion = resourceVersion;
#if UNITY_WEBGL
_patchCacheVerifier = new PatchCacheVerifierWithoutThread();
#else
_patchCacheVerifier = new PatchCacheVerifierWithThread();
#endif
}
internal override void Start()
{
@@ -293,7 +304,7 @@ namespace YooAsset
if (_steps == ESteps.InitVerifyingCache)
{
if (_verifyManager.InitVerifyingCache(_impl.AppPatchManifest, _impl.LocalPatchManifest, true))
if (_patchCacheVerifier.InitVerifier(_impl.AppPatchManifest, _impl.LocalPatchManifest, true))
{
_verifyTime = UnityEngine.Time.realtimeSinceStartup;
_steps = ESteps.UpdateVerifyingCache;
@@ -308,12 +319,12 @@ namespace YooAsset
if (_steps == ESteps.UpdateVerifyingCache)
{
Progress = _verifyManager.GetVerifyProgress();
if (_verifyManager.UpdateVerifyingCache())
Progress = _patchCacheVerifier.GetVerifierProgress();
if (_patchCacheVerifier.UpdateVerifier())
{
float costTime = UnityEngine.Time.realtimeSinceStartup - _verifyTime;
YooLogger.Log($"Verify result : Success {_verifyManager.VerifySuccessCount}, Fail {_verifyManager.VerifyFailCount}, Elapsed time {costTime} seconds");
if (_verifyManager.VerifyFailCount > 0)
YooLogger.Log($"Verify result : Success {_patchCacheVerifier.VerifySuccessCount}, Fail {_patchCacheVerifier.VerifyFailCount}, Elapsed time {costTime} seconds");
if (_patchCacheVerifier.VerifyFailCount > 0)
{
_steps = ESteps.Done;
Status = EOperationStatus.Failed;
@@ -344,143 +355,4 @@ namespace YooAsset
}
}
}
/// <summary>
/// 本地缓存文件验证管理器
/// </summary>
internal class VerifyManager
{
private class ThreadInfo
{
public bool Result = false;
public string FilePath { private set; get; }
public PatchBundle Bundle { private set; get; }
public ThreadInfo(string filePath, PatchBundle bundle)
{
FilePath = filePath;
Bundle = bundle;
}
}
private readonly List<PatchBundle> _waitingList = new List<PatchBundle>(1000);
private readonly List<PatchBundle> _verifyingList = new List<PatchBundle>(100);
private readonly ThreadSyncContext _syncContext = new ThreadSyncContext();
private int _verifyMaxNum = 32;
private int _verifyTotalCount = 0;
public int VerifySuccessCount { private set; get; } = 0;
public int VerifyFailCount { private set; get; } = 0;
public bool InitVerifyingCache(PatchManifest appPatchManifest, PatchManifest localPatchManifest, bool weaklyUpdate)
{
// 遍历所有文件然后验证并缓存合法文件
foreach (var patchBundle in localPatchManifest.BundleList)
{
// 忽略缓存文件
if (DownloadSystem.ContainsVerifyFile(patchBundle.Hash))
continue;
// 忽略APP资源
// 注意如果是APP资源并且哈希值相同则不需要下载
if (appPatchManifest.TryGetPatchBundle(patchBundle.BundleName, out PatchBundle appPatchBundle))
{
if (appPatchBundle.IsBuildin && appPatchBundle.Hash == patchBundle.Hash)
continue;
}
// 注意:在弱联网模式下,我们需要验证指定资源版本的所有资源完整性
if (weaklyUpdate)
{
string filePath = SandboxHelper.MakeCacheFilePath(patchBundle.FileName);
if (File.Exists(filePath))
_waitingList.Add(patchBundle);
else
return false;
}
else
{
string filePath = SandboxHelper.MakeCacheFilePath(patchBundle.FileName);
if (File.Exists(filePath))
_waitingList.Add(patchBundle);
}
}
// 设置同时验证的最大数
ThreadPool.GetMaxThreads(out int workerThreads, out int ioThreads);
YooLogger.Log($"Work threads : {workerThreads}, IO threads : {ioThreads}");
_verifyMaxNum = Math.Min(workerThreads, ioThreads);
_verifyTotalCount = _waitingList.Count;
return true;
}
public bool UpdateVerifyingCache()
{
_syncContext.Update();
if (_waitingList.Count == 0 && _verifyingList.Count == 0)
return true;
if (_verifyingList.Count >= _verifyMaxNum)
return false;
for (int i = _waitingList.Count - 1; i >= 0; i--)
{
if (_verifyingList.Count >= _verifyMaxNum)
break;
var patchBundle = _waitingList[i];
if (RunThread(patchBundle))
{
_waitingList.RemoveAt(i);
_verifyingList.Add(patchBundle);
}
else
{
YooLogger.Warning("The thread pool is failed queued.");
break;
}
}
return false;
}
public float GetVerifyProgress()
{
if (_verifyTotalCount == 0)
return 1f;
return (float)(VerifySuccessCount + VerifyFailCount) / _verifyTotalCount;
}
private bool RunThread(PatchBundle patchBundle)
{
string filePath = SandboxHelper.MakeCacheFilePath(patchBundle.FileName);
ThreadInfo info = new ThreadInfo(filePath, patchBundle);
return ThreadPool.QueueUserWorkItem(new WaitCallback(VerifyInThread), info);
}
private void VerifyInThread(object infoObj)
{
ThreadInfo info = (ThreadInfo)infoObj;
info.Result = DownloadSystem.CheckContentIntegrity(info.FilePath, info.Bundle.SizeBytes, info.Bundle.CRC);
_syncContext.Post(VerifyCallback, info);
}
private void VerifyCallback(object obj)
{
ThreadInfo info = (ThreadInfo)obj;
if (info.Result)
{
VerifySuccessCount++;
DownloadSystem.CacheVerifyFile(info.Bundle.Hash, info.Bundle.FileName);
}
else
{
VerifyFailCount++;
// NOTE不期望删除断点续传的资源文件
/*
YooLogger.Warning($"Failed to verify file : {info.FilePath}");
if (File.Exists(info.FilePath))
File.Delete(info.FilePath);
*/
}
_verifyingList.Remove(info.Bundle);
}
}
}

View File

@@ -64,7 +64,7 @@ namespace YooAsset
}
/// <summary>
/// 网络模式的更新资源包裹操作
/// 联机模式的更新资源包裹操作
/// </summary>
internal sealed class HostPlayModeUpdatePackageOperation : UpdatePackageOperation
{
@@ -198,24 +198,14 @@ namespace YooAsset
foreach (var patchBundle in _remotePatchManifest.BundleList)
{
// 忽略缓存文件
if (DownloadSystem.ContainsVerifyFile(patchBundle.Hash))
if (CacheSystem.IsCached(patchBundle))
continue;
// 忽略APP资源
// 注意如果是APP资源并且哈希值相同则不需要下载
if (_impl.AppPatchManifest.TryGetPatchBundle(patchBundle.BundleName, out PatchBundle appPatchBundle))
{
if (appPatchBundle.IsBuildin && appPatchBundle.Hash == patchBundle.Hash)
continue;
}
// 注意:通过比对文件大小做快速的文件校验!
// 注意:在初始化的时候会去做最终校验!
string filePath = SandboxHelper.MakeCacheFilePath(patchBundle.FileName);
if (File.Exists(filePath))
{
long fileSize = FileUtility.GetFileSize(filePath);
if (fileSize == patchBundle.SizeBytes)
if (appPatchBundle.IsBuildin && appPatchBundle.Equals(patchBundle))
continue;
}

View File

@@ -43,7 +43,7 @@ namespace YooAsset
}
/// <summary>
/// 网络模式的更新静态版本操作
/// 联机模式的更新静态版本操作
/// </summary>
internal sealed class HostPlayModeUpdateStaticVersionOperation : UpdateStaticVersionOperation
{

View File

@@ -1,5 +1,6 @@
using System;
using System.Linq;
using System.IO;
namespace YooAsset
{
@@ -14,17 +15,17 @@ namespace YooAsset
/// <summary>
/// 文件哈希值
/// </summary>
public string Hash;
public string FileHash;
/// <summary>
/// 文件校验码
/// </summary>
public string CRC;
public string FileCRC;
/// <summary>
/// 文件大小(字节数)
/// </summary>
public long SizeBytes;
public long FileSize;
/// <summary>
/// 资源包的分类标签
@@ -57,13 +58,46 @@ namespace YooAsset
/// </summary>
public string FileName { private set; get; }
/// <summary>
/// 缓存文件路径
/// </summary>
private string _cachedFilePath;
public string CachedFilePath
{
get
{
if (string.IsNullOrEmpty(_cachedFilePath) == false)
return _cachedFilePath;
public PatchBundle(string bundleName, string hash, string crc, long sizeBytes, string[] tags)
string cacheRoot = SandboxHelper.GetCacheFolderPath();
_cachedFilePath = $"{cacheRoot}/{FileName}";
return _cachedFilePath;
}
}
/// <summary>
/// 内置文件路径
/// </summary>
private string _streamingFilePath;
public string StreamingFilePath
{
get
{
if (string.IsNullOrEmpty(_streamingFilePath) == false)
return _streamingFilePath;
_streamingFilePath = PathHelper.MakeStreamingLoadPath(FileName);
return _streamingFilePath;
}
}
public PatchBundle(string bundleName, string fileHash, string fileCRC, long fileSize, string[] tags)
{
BundleName = bundleName;
Hash = hash;
CRC = crc;
SizeBytes = sizeBytes;
FileHash = fileHash;
FileCRC = fileCRC;
FileSize = fileSize;
Tags = tags;
}
@@ -101,24 +135,24 @@ namespace YooAsset
{
if (nameStype == 1)
{
FileName = Hash;
FileName = FileHash;
}
else if (nameStype == 2)
{
string tempFileExtension = System.IO.Path.GetExtension(BundleName);
FileName = $"{Hash}{tempFileExtension}";
FileName = $"{FileHash}{tempFileExtension}";
}
else if (nameStype == 3)
{
string tempFileExtension = System.IO.Path.GetExtension(BundleName);
string tempBundleName = BundleName.Replace('/', '_').Replace(tempFileExtension, "");
FileName = $"{tempBundleName}_{Hash}";
FileName = $"{tempBundleName}_{FileHash}";
}
else if (nameStype == 4)
{
string tempFileExtension = System.IO.Path.GetExtension(BundleName);
string tempBundleName = BundleName.Replace('/', '_').Replace(tempFileExtension, "");
FileName = $"{tempBundleName}_{Hash}{tempFileExtension}";
FileName = $"{tempBundleName}_{FileHash}{tempFileExtension}";
}
else
{
@@ -154,5 +188,16 @@ namespace YooAsset
else
return false;
}
/// <summary>
/// 检测资源包文件内容是否相同
/// </summary>
public bool Equals(PatchBundle otherBundle)
{
if (FileHash == otherBundle.FileHash)
return true;
return false;
}
}
}

View File

@@ -16,7 +16,7 @@ namespace YooAsset
{
_locationToLower = locationToLower;
var operation = new EditorSimulateModeInitializationOperation(this, simulatePatchManifestPath);
OperationSystem.StartOperaiton(operation);
OperationSystem.StartOperation(operation);
return operation;
}

View File

@@ -33,7 +33,7 @@ namespace YooAsset
_fallbackHostServer = fallbackHostServer;
var operation = new HostPlayModeInitializationOperation(this);
OperationSystem.StartOperaiton(operation);
OperationSystem.StartOperation(operation);
return operation;
}
@@ -43,7 +43,7 @@ namespace YooAsset
public UpdateStaticVersionOperation UpdateStaticVersionAsync(int timeout)
{
var operation = new HostPlayModeUpdateStaticVersionOperation(this, timeout);
OperationSystem.StartOperaiton(operation);
OperationSystem.StartOperation(operation);
return operation;
}
@@ -53,7 +53,7 @@ namespace YooAsset
public UpdateManifestOperation UpdatePatchManifestAsync(int resourceVersion, int timeout)
{
var operation = new HostPlayModeUpdateManifestOperation(this, resourceVersion, timeout);
OperationSystem.StartOperaiton(operation);
OperationSystem.StartOperation(operation);
return operation;
}
@@ -63,7 +63,7 @@ namespace YooAsset
public UpdateManifestOperation WeaklyUpdatePatchManifestAsync(int resourceVersion)
{
var operation = new HostPlayModeWeaklyUpdateManifestOperation(this, resourceVersion);
OperationSystem.StartOperaiton(operation);
OperationSystem.StartOperation(operation);
return operation;
}
@@ -73,7 +73,7 @@ namespace YooAsset
public UpdatePackageOperation UpdatePackageAsync(int resourceVersion, int timeout)
{
var operation = new HostPlayModeUpdatePackageOperation(this, resourceVersion, timeout);
OperationSystem.StartOperaiton(operation);
OperationSystem.StartOperation(operation);
return operation;
}
@@ -88,16 +88,18 @@ namespace YooAsset
}
/// <summary>
/// 清空未被使用的缓存文件
/// 获取未被使用的缓存文件路径集合
/// </summary>
public void ClearUnusedCacheFiles()
public List<string> ClearUnusedCacheFilePaths()
{
string cacheFolderPath = SandboxHelper.GetCacheFolderPath();
if (Directory.Exists(cacheFolderPath) == false)
return;
return new List<string>();
DirectoryInfo directoryInfo = new DirectoryInfo(cacheFolderPath);
foreach (FileInfo fileInfo in directoryInfo.GetFiles())
FileInfo[] fileInfos = directoryInfo.GetFiles();
List<string> result = new List<string>(fileInfos.Length);
foreach (FileInfo fileInfo in fileInfos)
{
bool used = false;
foreach (var patchBundle in LocalPatchManifest.BundleList)
@@ -109,11 +111,9 @@ namespace YooAsset
}
}
if (used == false)
{
YooLogger.Log($"Delete unused cache file : {fileInfo.Name}");
File.Delete(fileInfo.FullName);
}
result.Add(fileInfo.FullName);
}
return result;
}
/// <summary>
@@ -131,14 +131,14 @@ namespace YooAsset
foreach (var patchBundle in LocalPatchManifest.BundleList)
{
// 忽略缓存文件
if (DownloadSystem.ContainsVerifyFile(patchBundle.Hash))
if (CacheSystem.IsCached(patchBundle))
continue;
// 忽略APP资源
// 注意如果是APP资源并且哈希值相同则不需要下载
if (AppPatchManifest.TryGetPatchBundle(patchBundle.BundleName, out PatchBundle appPatchBundle))
{
if (appPatchBundle.IsBuildin && appPatchBundle.Hash == patchBundle.Hash)
if (appPatchBundle.IsBuildin && appPatchBundle.Equals(patchBundle))
continue;
}
@@ -163,14 +163,14 @@ namespace YooAsset
foreach (var patchBundle in LocalPatchManifest.BundleList)
{
// 忽略缓存文件
if (DownloadSystem.ContainsVerifyFile(patchBundle.Hash))
if (CacheSystem.IsCached(patchBundle))
continue;
// 忽略APP资源
// 注意如果是APP资源并且哈希值相同则不需要下载
if (AppPatchManifest.TryGetPatchBundle(patchBundle.BundleName, out PatchBundle appPatchBundle))
{
if (appPatchBundle.IsBuildin && appPatchBundle.Hash == patchBundle.Hash)
if (appPatchBundle.IsBuildin && appPatchBundle.Equals(patchBundle))
continue;
}
@@ -233,14 +233,14 @@ namespace YooAsset
foreach (var patchBundle in checkList)
{
// 忽略缓存文件
if (DownloadSystem.ContainsVerifyFile(patchBundle.Hash))
if (CacheSystem.IsCached(patchBundle))
continue;
// 忽略APP资源
// 注意如果是APP资源并且哈希值相同则不需要下载
if (AppPatchManifest.TryGetPatchBundle(patchBundle.BundleName, out PatchBundle appPatchBundle))
{
if (appPatchBundle.IsBuildin && appPatchBundle.Hash == patchBundle.Hash)
if (appPatchBundle.IsBuildin && appPatchBundle.Equals(patchBundle))
continue;
}
@@ -269,7 +269,7 @@ namespace YooAsset
continue;
// 忽略缓存文件
if (DownloadSystem.ContainsVerifyFile(patchBundle.Hash))
if (CacheSystem.IsCached(patchBundle))
continue;
// 查询DLC资源
@@ -279,7 +279,7 @@ namespace YooAsset
}
}
return ConvertToUnpackList(downloadList);
return PatchHelper.ConvertToUnpackList(downloadList);
}
/// <summary>
@@ -301,13 +301,13 @@ namespace YooAsset
continue;
// 忽略缓存文件
if (DownloadSystem.ContainsVerifyFile(patchBundle.Hash))
if (CacheSystem.IsCached(patchBundle))
continue;
downloadList.Add(patchBundle);
}
return ConvertToUnpackList(downloadList);
return PatchHelper.ConvertToUnpackList(downloadList);
}
// WEB相关
@@ -339,26 +339,6 @@ namespace YooAsset
return bundleInfo;
}
// 解压相关
public List<BundleInfo> ConvertToUnpackList(List<PatchBundle> unpackList)
{
List<BundleInfo> result = new List<BundleInfo>(unpackList.Count);
foreach (var patchBundle in unpackList)
{
var bundleInfo = ConvertToUnpackInfo(patchBundle);
result.Add(bundleInfo);
}
return result;
}
public BundleInfo ConvertToUnpackInfo(PatchBundle patchBundle)
{
// 注意:我们把流加载路径指定为远端下载地址
string streamingPath = PathHelper.MakeStreamingLoadPath(patchBundle.FileName);
streamingPath = PathHelper.ConvertToWWWPath(streamingPath);
BundleInfo bundleInfo = new BundleInfo(patchBundle, BundleInfo.ELoadMode.LoadFromRemote, streamingPath, streamingPath);
return bundleInfo;
}
// 设置资源清单
internal void SetAppPatchManifest(PatchManifest patchManifest)
{
@@ -377,7 +357,7 @@ namespace YooAsset
throw new Exception("Should never get here !");
// 查询沙盒资源
if (DownloadSystem.ContainsVerifyFile(patchBundle.Hash))
if (CacheSystem.IsCached(patchBundle))
{
BundleInfo bundleInfo = new BundleInfo(patchBundle, BundleInfo.ELoadMode.LoadFromCache);
return bundleInfo;
@@ -386,7 +366,7 @@ namespace YooAsset
// 查询APP资源
if (AppPatchManifest.TryGetPatchBundle(patchBundle.BundleName, out PatchBundle appPatchBundle))
{
if (appPatchBundle.IsBuildin && appPatchBundle.Hash == patchBundle.Hash)
if (appPatchBundle.IsBuildin && appPatchBundle.Equals(patchBundle))
{
BundleInfo bundleInfo = new BundleInfo(appPatchBundle, BundleInfo.ELoadMode.LoadFromStreaming);
return bundleInfo;

View File

@@ -16,7 +16,7 @@ namespace YooAsset
{
_locationToLower = locationToLower;
var operation = new OfflinePlayModeInitializationOperation(this);
OperationSystem.StartOperaiton(operation);
OperationSystem.StartOperation(operation);
return operation;
}
@@ -43,8 +43,18 @@ namespace YooAsset
if (patchBundle == null)
throw new Exception("Should never get here !");
BundleInfo bundleInfo = new BundleInfo(patchBundle, BundleInfo.ELoadMode.LoadFromStreaming);
return bundleInfo;
// 查询沙盒资源
if (CacheSystem.IsCached(patchBundle))
{
BundleInfo bundleInfo = new BundleInfo(patchBundle, BundleInfo.ELoadMode.LoadFromCache);
return bundleInfo;
}
// 查询APP资源
{
BundleInfo bundleInfo = new BundleInfo(patchBundle, BundleInfo.ELoadMode.LoadFromStreaming);
return bundleInfo;
}
}
BundleInfo IBundleServices.GetBundleInfo(AssetInfo assetInfo)
{

View File

@@ -1,12 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
/*
namespace YooAsset
{
internal class WebPlayModeImpl : IBundleServices
{
}
}
*/

View File

@@ -1,4 +1,5 @@
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("YooAsset.Editor")]
[assembly: InternalsVisibleTo("YooAsset.EditorExtension")]
[assembly: InternalsVisibleTo("YooAsset.EditorExtension")]
[assembly: InternalsVisibleTo("YooAsset.RuntimeExtension")]

View File

@@ -4,8 +4,7 @@ namespace YooAsset
public struct DecryptionFileInfo
{
public string BundleName;
public string BundleHash;
public string BundleCRC;
public string FileHash;
}
public interface IDecryptionServices

View File

@@ -42,8 +42,13 @@ namespace YooAsset
public const string VersionFileName = "StaticVersion.bytes";
/// <summary>
/// Unity内置着色器资源包名称
/// Unity着色器资源包名称
/// </summary>
public const string UnityBuiltInShadersBundleName = "UnityBuiltInShaders.bundle";
public const string UnityShadersBundleName = "unityshaders";
/// <summary>
/// 忽略的文件类型
/// </summary>
public static readonly string[] IgnoreFileExtensions = { "", ".so", ".dll", ".cs", ".js", ".boo", ".meta", ".cginc" };
}
}

View File

@@ -55,5 +55,13 @@ namespace YooAsset
{
return $"{Setting.PatchManifestFileName}_{resourceVersion}.hash";
}
/// <summary>
/// 获取着色器资源包全名称(包含后缀名)
/// </summary>
public static string GetUnityShadersBundleFullName()
{
return $"{YooAssetSettings.UnityShadersBundleName}.{Setting.AssetBundleFileVariant}";
}
}
}

View File

@@ -57,7 +57,7 @@ namespace YooAsset
}
/// <summary>
/// 获取网络资源加载路径
/// 获取WWW加载本地资源的路径
/// </summary>
public static string ConvertToWWWPath(string path)
{
@@ -109,14 +109,6 @@ namespace YooAsset
{
return PathHelper.MakePersistentLoadPath(CacheFolderName);
}
/// <summary>
/// 获取缓存文件的存储路径
/// </summary>
public static string MakeCacheFilePath(string fileName)
{
return PathHelper.MakePersistentLoadPath($"{CacheFolderName}/{fileName}");
}
}
/// <summary>
@@ -140,5 +132,26 @@ namespace YooAsset
}
return result.ToArray();
}
/// <summary>
/// 资源解压相关
/// </summary>
public static List<BundleInfo> ConvertToUnpackList(List<PatchBundle> unpackList)
{
List<BundleInfo> result = new List<BundleInfo>(unpackList.Count);
foreach (var patchBundle in unpackList)
{
var bundleInfo = ConvertToUnpackInfo(patchBundle);
result.Add(bundleInfo);
}
return result;
}
public static BundleInfo ConvertToUnpackInfo(PatchBundle patchBundle)
{
// 注意:我们把流加载路径指定为远端下载地址
string streamingPath = PathHelper.ConvertToWWWPath(patchBundle.StreamingFilePath);
BundleInfo bundleInfo = new BundleInfo(patchBundle, BundleInfo.ELoadMode.LoadFromStreaming, streamingPath, streamingPath);
return bundleInfo;
}
}
}

View File

@@ -127,7 +127,7 @@ namespace YooAsset
}
/// <summary>
/// 创建文件
/// 创建文件(如果已经存在则删除旧文件)
/// </summary>
public static void CreateFile(string filePath, string content)
{

View File

@@ -9,6 +9,11 @@ namespace YooAsset
YooAssets.InternalUpdate();
}
void OnDestroy()
{
YooAssets.InternalDestroy();
}
void OnApplicationQuit()
{
YooAssets.InternalDestroy();

View File

@@ -6,7 +6,7 @@ using UnityEngine.SceneManagement;
namespace YooAsset
{
public static class YooAssets
public static partial class YooAssets
{
/// <summary>
/// 运行模式
@@ -25,7 +25,7 @@ namespace YooAsset
OfflinePlayMode,
/// <summary>
/// 网络运行模式
/// 联机运行模式
/// </summary>
HostPlayMode,
}
@@ -81,7 +81,7 @@ namespace YooAsset
}
/// <summary>
/// 网络运行模式的初始化参数
/// 联机运行模式的初始化参数
/// </summary>
public class HostPlayModeParameters : InitializeParameters
{
@@ -100,10 +100,17 @@ namespace YooAsset
/// </summary>
public bool ClearCacheWhenDirty = false;
#if UNITY_WEBGL
/// <summary>
/// WEBGL模式不支持多线程下载
/// </summary>
internal int BreakpointResumeFileSize = int.MaxValue;
#else
/// <summary>
/// 启用断点续传功能的文件大小
/// </summary>
public int BreakpointResumeFileSize = int.MaxValue;
#endif
/// <summary>
/// 下载文件校验等级
@@ -194,12 +201,14 @@ namespace YooAsset
// 初始化下载系统
if (_playMode == EPlayMode.HostPlayMode)
{
#if UNITY_WEBGL
throw new Exception($"{EPlayMode.HostPlayMode} not supports WebGL platform !");
#else
var hostPlayModeParameters = parameters as HostPlayModeParameters;
DownloadSystem.Initialize(hostPlayModeParameters.BreakpointResumeFileSize, hostPlayModeParameters.VerifyLevel);
#endif
CacheSystem.Initialize(hostPlayModeParameters.VerifyLevel);
DownloadSystem.Initialize(hostPlayModeParameters.BreakpointResumeFileSize);
}
else
{
CacheSystem.Initialize(EVerifyLevel.Low);
DownloadSystem.Initialize(int.MaxValue);
}
// 初始化资源系统
@@ -258,13 +267,13 @@ namespace YooAsset
if (_playMode == EPlayMode.EditorSimulateMode)
{
var operation = new EditorPlayModeUpdateStaticVersionOperation();
OperationSystem.StartOperaiton(operation);
OperationSystem.StartOperation(operation);
return operation;
}
else if (_playMode == EPlayMode.OfflinePlayMode)
{
var operation = new OfflinePlayModeUpdateStaticVersionOperation();
OperationSystem.StartOperaiton(operation);
OperationSystem.StartOperation(operation);
return operation;
}
else if (_playMode == EPlayMode.HostPlayMode)
@@ -285,16 +294,17 @@ namespace YooAsset
public static UpdateManifestOperation UpdateManifestAsync(int resourceVersion, int timeout = 60)
{
DebugCheckInitialize();
DebugCheckUpdateManifest();
if (_playMode == EPlayMode.EditorSimulateMode)
{
var operation = new EditorPlayModeUpdateManifestOperation();
OperationSystem.StartOperaiton(operation);
OperationSystem.StartOperation(operation);
return operation;
}
else if (_playMode == EPlayMode.OfflinePlayMode)
{
var operation = new OfflinePlayModeUpdateManifestOperation();
OperationSystem.StartOperaiton(operation);
OperationSystem.StartOperation(operation);
return operation;
}
else if (_playMode == EPlayMode.HostPlayMode)
@@ -318,13 +328,13 @@ namespace YooAsset
if (_playMode == EPlayMode.EditorSimulateMode)
{
var operation = new EditorPlayModeUpdateManifestOperation();
OperationSystem.StartOperaiton(operation);
OperationSystem.StartOperation(operation);
return operation;
}
else if (_playMode == EPlayMode.OfflinePlayMode)
{
var operation = new OfflinePlayModeUpdateManifestOperation();
OperationSystem.StartOperaiton(operation);
OperationSystem.StartOperation(operation);
return operation;
}
else if (_playMode == EPlayMode.HostPlayMode)
@@ -341,9 +351,9 @@ namespace YooAsset
/// 开启一个异步操作
/// </summary>
/// <param name="operation">异步操作对象</param>
public static void StartOperaiton(GameAsyncOperation operation)
public static void StartOperation(GameAsyncOperation operation)
{
OperationSystem.StartOperaiton(operation);
OperationSystem.StartOperation(operation);
}
/// <summary>
@@ -509,36 +519,39 @@ namespace YooAsset
if (assetInfo.IsInvalid)
{
RawFileOperation operation = new CompletedRawFileOperation(assetInfo.Error, copyPath);
OperationSystem.StartOperaiton(operation);
OperationSystem.StartOperation(operation);
return operation;
}
BundleInfo bundleInfo = _bundleServices.GetBundleInfo(assetInfo);
if (bundleInfo.IsRawFile == false)
#if UNITY_EDITOR
if (bundleInfo.Bundle.IsRawFile == false)
{
string error = $"Cannot load asset bundle file using {nameof(GetRawFileAsync)} interfaces !";
YooLogger.Warning(error);
string error = $"Cannot load asset bundle file using {nameof(GetRawFileAsync)} method !";
YooLogger.Error(error);
RawFileOperation operation = new CompletedRawFileOperation(error, copyPath);
OperationSystem.StartOperaiton(operation);
OperationSystem.StartOperation(operation);
return operation;
}
#endif
if (_playMode == EPlayMode.EditorSimulateMode)
{
RawFileOperation operation = new EditorPlayModeRawFileOperation(bundleInfo, copyPath);
OperationSystem.StartOperaiton(operation);
OperationSystem.StartOperation(operation);
return operation;
}
else if (_playMode == EPlayMode.OfflinePlayMode)
{
RawFileOperation operation = new OfflinePlayModeRawFileOperation(bundleInfo, copyPath);
OperationSystem.StartOperaiton(operation);
OperationSystem.StartOperation(operation);
return operation;
}
else if (_playMode == EPlayMode.HostPlayMode)
{
RawFileOperation operation = new HostPlayModeRawFileOperation(bundleInfo, copyPath);
OperationSystem.StartOperaiton(operation);
OperationSystem.StartOperation(operation);
return operation;
}
else
@@ -658,6 +671,18 @@ namespace YooAsset
private static AssetOperationHandle LoadAssetInternal(AssetInfo assetInfo, bool waitForAsyncComplete)
{
#if UNITY_EDITOR
BundleInfo bundleInfo = _bundleServices.GetBundleInfo(assetInfo);
if (bundleInfo.Bundle.IsRawFile)
{
string error = $"Cannot load raw file using LoadAsset method !";
YooLogger.Error(error);
CompletedProvider completedProvider = new CompletedProvider(assetInfo);
completedProvider.SetCompleted(error);
return completedProvider.CreateHandle<AssetOperationHandle>();
}
#endif
var handle = AssetSystem.LoadAssetAsync(assetInfo);
if (waitForAsyncComplete)
handle.WaitForAsyncComplete();
@@ -742,6 +767,18 @@ namespace YooAsset
private static SubAssetsOperationHandle LoadSubAssetsInternal(AssetInfo assetInfo, bool waitForAsyncComplete)
{
#if UNITY_EDITOR
BundleInfo bundleInfo = _bundleServices.GetBundleInfo(assetInfo);
if (bundleInfo.Bundle.IsRawFile)
{
string error = $"Cannot load raw file using LoadSubAssets method !";
YooLogger.Error(error);
CompletedProvider completedProvider = new CompletedProvider(assetInfo);
completedProvider.SetCompleted(error);
return completedProvider.CreateHandle<SubAssetsOperationHandle>();
}
#endif
var handle = AssetSystem.LoadSubAssetsAsync(assetInfo);
if (waitForAsyncComplete)
handle.WaitForAsyncComplete();
@@ -956,13 +993,13 @@ namespace YooAsset
if (_playMode == EPlayMode.EditorSimulateMode)
{
var operation = new EditorPlayModeUpdatePackageOperation();
OperationSystem.StartOperaiton(operation);
OperationSystem.StartOperation(operation);
return operation;
}
else if (_playMode == EPlayMode.OfflinePlayMode)
{
var operation = new OfflinePlayModeUpdatePackageOperation();
OperationSystem.StartOperaiton(operation);
OperationSystem.StartOperation(operation);
return operation;
}
else if (_playMode == EPlayMode.HostPlayMode)
@@ -1004,30 +1041,55 @@ namespace YooAsset
/// <summary>
/// 清空未被使用的缓存文件
/// </summary>
public static void ClearUnusedCacheFiles()
public static ClearUnusedCacheFilesOperation ClearUnusedCacheFiles()
{
if (_playMode == EPlayMode.HostPlayMode)
_hostPlayModeImpl.ClearUnusedCacheFiles();
DebugCheckInitialize();
if (_playMode == EPlayMode.EditorSimulateMode)
{
var operation = new EditorPlayModeClearUnusedCacheFilesOperation();
OperationSystem.StartOperation(operation);
return operation;
}
else if (_playMode == EPlayMode.OfflinePlayMode)
{
var operation = new OfflinePlayModeClearUnusedCacheFilesOperation();
OperationSystem.StartOperation(operation);
return operation;
}
else if (_playMode == EPlayMode.HostPlayMode)
{
var operation = new HostPlayModeClearUnusedCacheFilesOperation(_hostPlayModeImpl);
OperationSystem.StartOperation(operation);
return operation;
}
else
{
throw new NotImplementedException();
}
}
#endregion
#region
internal static void InternalDestroy()
{
_isInitialize = false;
_initializeError = string.Empty;
_initializeStatus = EOperationStatus.None;
if (_isInitialize)
{
_isInitialize = false;
_initializeError = string.Empty;
_initializeStatus = EOperationStatus.None;
_bundleServices = null;
_locationServices = null;
_editorSimulateModeImpl = null;
_offlinePlayModeImpl = null;
_hostPlayModeImpl = null;
_bundleServices = null;
_locationServices = null;
_editorSimulateModeImpl = null;
_offlinePlayModeImpl = null;
_hostPlayModeImpl = null;
OperationSystem.DestroyAll();
DownloadSystem.DestroyAll();
AssetSystem.DestroyAll();
YooLogger.Log("YooAssets destroy all !");
OperationSystem.DestroyAll();
DownloadSystem.DestroyAll();
CacheSystem.DestroyAll();
AssetSystem.DestroyAll();
YooLogger.Log("YooAssets destroy all !");
}
}
internal static void InternalUpdate()
{
@@ -1072,6 +1134,16 @@ namespace YooAsset
YooLogger.Warning($"Found illegal character in location : \"{location}\"");
}
}
[Conditional("DEBUG")]
private static void DebugCheckUpdateManifest()
{
var loadedBundleInfos = AssetSystem.GetLoadedBundleInfos();
if (loadedBundleInfos.Count > 0)
{
YooLogger.Warning($"Found loaded bundle before update manifest ! Recommended to call the {nameof(ForceUnloadAllAssets)} method to release loaded bundle !");
}
}
#endregion
#region

View File

@@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: d50604ec71178f548a60e324da99255d
guid: ec6bf912e76d0e84d8c58b9da0b020ce
folderAsset: yes
DefaultImporter:
externalObjects: {}

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