mirror of
https://github.com/tuyoogame/YooAsset.git
synced 2026-05-14 19:40:47 +00:00
Compare commits
60 Commits
1.4.1-prev
...
1.4.6-prev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a0bc521903 | ||
|
|
071a84d9ef | ||
|
|
aa40b5336e | ||
|
|
157402bb39 | ||
|
|
5a98a68c27 | ||
|
|
f6bc52fd59 | ||
|
|
d1f2712e5f | ||
|
|
8958317f61 | ||
|
|
fdf27cbc1a | ||
|
|
26ffb829d0 | ||
|
|
521e3e2587 | ||
|
|
17c6158478 | ||
|
|
fa0dc48993 | ||
|
|
826bdaab5c | ||
|
|
7d21da76fb | ||
|
|
70465a49d7 | ||
|
|
acca74dce7 | ||
|
|
d8e7892ab7 | ||
|
|
e887bf1fd7 | ||
|
|
145ca936e7 | ||
|
|
69c7a51215 | ||
|
|
c4875d4f80 | ||
|
|
eed3c9768b | ||
|
|
2c650f2bdf | ||
|
|
71e8392359 | ||
|
|
cfbf6e23ec | ||
|
|
9be5ec0f31 | ||
|
|
a8a0c3831b | ||
|
|
ef31d5a938 | ||
|
|
812db6dafe | ||
|
|
66fe2f0995 | ||
|
|
3b40cc7833 | ||
|
|
5a01ca061a | ||
|
|
ef0cc05f5c | ||
|
|
c5c6e4ae23 | ||
|
|
1c2bbfea93 | ||
|
|
8893317f59 | ||
|
|
ca8b5c85dd | ||
|
|
a64d485278 | ||
|
|
2612764922 | ||
|
|
8ce8e81792 | ||
|
|
fbba2ddec9 | ||
|
|
33a1b9d4bf | ||
|
|
03abac082c | ||
|
|
3672a7e1fa | ||
|
|
df27e7ba75 | ||
|
|
423655e1ca | ||
|
|
f620223613 | ||
|
|
365a94d7b7 | ||
|
|
a98efd83b6 | ||
|
|
6488e96127 | ||
|
|
cc75594747 | ||
|
|
e5de104933 | ||
|
|
954e76ab33 | ||
|
|
82bda518c9 | ||
|
|
cdc5bcd31f | ||
|
|
61f6d480ae | ||
|
|
df6df3548c | ||
|
|
ac839450e2 | ||
|
|
4fa01e1a29 |
@@ -2,6 +2,104 @@
|
||||
|
||||
All notable changes to this package will be documented in this file.
|
||||
|
||||
## [1.4.6-preview] - 2023-02-22
|
||||
|
||||
### Changed
|
||||
|
||||
- EVerifyLevel新增Middle级别。
|
||||
|
||||
```c#
|
||||
public enum EVerifyLevel
|
||||
{
|
||||
/// <summary>
|
||||
/// 验证文件存在
|
||||
/// </summary>
|
||||
Low,
|
||||
|
||||
/// <summary>
|
||||
/// 验证文件大小
|
||||
/// </summary>
|
||||
Middle,
|
||||
|
||||
/// <summary>
|
||||
/// 验证文件大小和CRC
|
||||
/// </summary>
|
||||
High,
|
||||
}
|
||||
```
|
||||
|
||||
- 补丁清单的资源包列表新增引用链。
|
||||
|
||||
(解决复杂依赖关系下,错误卸载资源包的问题)
|
||||
|
||||
- 缓存系统支持后缀格式存储。
|
||||
|
||||
(解决原生文件没有后缀格式的问题)
|
||||
|
||||
- 收集界面增加用户自定义数据栏。
|
||||
|
||||
## [1.4.5-preview] - 2023-02-17
|
||||
|
||||
### Fixed
|
||||
|
||||
- (#67)修复了报告查看界面在Unity2021.3上的兼容性问题。
|
||||
- (#66)修复了在Unity2021.3上编辑器模拟模式运行报错的问题。
|
||||
|
||||
### Changed
|
||||
|
||||
- 接口变更:IPackRule
|
||||
|
||||
````c#
|
||||
/// <summary>
|
||||
/// 资源打包规则接口
|
||||
/// </summary>
|
||||
public interface IPackRule
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取打包规则结果
|
||||
/// </summary>
|
||||
PackRuleResult GetPackRuleResult(PackRuleData data);
|
||||
|
||||
/// <summary>
|
||||
/// 是否为原生文件打包规则
|
||||
/// </summary>
|
||||
bool IsRawFilePackRule();
|
||||
}
|
||||
````
|
||||
|
||||
## [1.4.4-preview] - 2023-02-14
|
||||
|
||||
### Fixed
|
||||
|
||||
- (#65)修复了AssetBundle构建宏逻辑错误。
|
||||
- 修复了AssetBundle加载宏逻辑错误。
|
||||
|
||||
## [1.4.3-preview] - 2023-02-10
|
||||
|
||||
全新的缓存系统!
|
||||
|
||||
### Fixed
|
||||
|
||||
- 修复了WebGL平台本地文件验证报错。
|
||||
- 修复了WEBGL平台加载原生文件失败的问题。
|
||||
- 修复了通过Handle句柄查询资源包下载进度为零的问题。
|
||||
|
||||
### Changed
|
||||
|
||||
- 着色器变种收集增加分批次处理功能。
|
||||
- Unity2021版本开始不再支持内置构建管线。
|
||||
|
||||
### Removed
|
||||
|
||||
- 太空战机DEMO移除了BetterStreamingAssets插件。
|
||||
|
||||
## [1.4.2-preview] - 2023-01-03
|
||||
|
||||
### Fixed
|
||||
|
||||
- 修复了清单解析异步操作的进度条变化错误。
|
||||
- 修复了更新资源清单错误计算超时时间的问题。
|
||||
|
||||
## [1.4.1-preview] - 2022-12-26
|
||||
|
||||
### Fixed
|
||||
|
||||
@@ -54,6 +54,7 @@ namespace YooAsset.Editor
|
||||
new TaskPrepare(), //前期准备工作
|
||||
new TaskGetBuildMap(), //获取构建列表
|
||||
new TaskBuilding(), //开始执行构建
|
||||
new TaskCopyRawFile(), //拷贝原生文件
|
||||
new TaskVerifyBuildResult(), //验证构建结果
|
||||
new TaskEncryption(), //加密资源文件
|
||||
new TaskUpdateBuildInfo(), //更新构建信息
|
||||
@@ -70,6 +71,7 @@ namespace YooAsset.Editor
|
||||
new TaskPrepare(), //前期准备工作
|
||||
new TaskGetBuildMap(), //获取构建列表
|
||||
new TaskBuilding_SBP(), //开始执行构建
|
||||
new TaskCopyRawFile(), //拷贝原生文件
|
||||
new TaskVerifyBuildResult_SBP(), //验证构建结果
|
||||
new TaskEncryption(), //加密资源文件
|
||||
new TaskUpdateBuildInfo(), //更新构建信息
|
||||
|
||||
@@ -220,15 +220,27 @@ namespace YooAsset.Editor
|
||||
|
||||
private void RefreshWindow()
|
||||
{
|
||||
var buildPipeline = AssetBundleBuilderSettingData.Setting.BuildPipeline;
|
||||
var buildMode = AssetBundleBuilderSettingData.Setting.BuildMode;
|
||||
var copyOption = AssetBundleBuilderSettingData.Setting.CopyBuildinFileOption;
|
||||
bool enableElement = buildMode == EBuildMode.ForceRebuild;
|
||||
bool tagsFiledVisible = copyOption == ECopyBuildinFileOption.ClearAndCopyByTags || copyOption == ECopyBuildinFileOption.OnlyCopyByTags;
|
||||
_encryptionField.SetEnabled(enableElement);
|
||||
_compressionField.SetEnabled(enableElement);
|
||||
_outputNameStyleField.SetEnabled(enableElement);
|
||||
_copyBuildinFileOptionField.SetEnabled(enableElement);
|
||||
_copyBuildinFileTagsField.SetEnabled(enableElement);
|
||||
|
||||
if (buildPipeline == EBuildPipeline.BuiltinBuildPipeline)
|
||||
{
|
||||
_compressionField.SetEnabled(enableElement);
|
||||
_outputNameStyleField.SetEnabled(enableElement);
|
||||
_copyBuildinFileOptionField.SetEnabled(enableElement);
|
||||
_copyBuildinFileTagsField.SetEnabled(enableElement);
|
||||
}
|
||||
else
|
||||
{
|
||||
_compressionField.SetEnabled(true);
|
||||
_outputNameStyleField.SetEnabled(true);
|
||||
_copyBuildinFileOptionField.SetEnabled(true);
|
||||
_copyBuildinFileTagsField.SetEnabled(true);
|
||||
}
|
||||
|
||||
_copyBuildinFileTagsField.visible = tagsFiledVisible;
|
||||
}
|
||||
private void SaveBtn_clicked()
|
||||
|
||||
@@ -7,8 +7,6 @@ namespace YooAsset.Editor
|
||||
{
|
||||
public class BuildAssetInfo
|
||||
{
|
||||
private string _mainBundleName;
|
||||
private string _shareBundleName;
|
||||
private bool _isAddAssetTags = false;
|
||||
private readonly HashSet<string> _referenceBundleNames = new HashSet<string>();
|
||||
|
||||
@@ -17,6 +15,11 @@ namespace YooAsset.Editor
|
||||
/// </summary>
|
||||
public ECollectorType CollectorType { private set; get; }
|
||||
|
||||
/// <summary>
|
||||
/// 资源包完整名称
|
||||
/// </summary>
|
||||
public string BundleName { private set; get; }
|
||||
|
||||
/// <summary>
|
||||
/// 可寻址地址
|
||||
/// </summary>
|
||||
@@ -54,10 +57,10 @@ namespace YooAsset.Editor
|
||||
public List<BuildAssetInfo> AllDependAssetInfos { private set; get; }
|
||||
|
||||
|
||||
public BuildAssetInfo(ECollectorType collectorType, string mainBundleName, string address, string assetPath, bool isRawAsset)
|
||||
public BuildAssetInfo(ECollectorType collectorType, string bundleName, string address, string assetPath, bool isRawAsset)
|
||||
{
|
||||
_mainBundleName = mainBundleName;
|
||||
CollectorType = collectorType;
|
||||
BundleName = bundleName;
|
||||
Address = address;
|
||||
AssetPath = assetPath;
|
||||
IsRawAsset = isRawAsset;
|
||||
@@ -133,24 +136,12 @@ namespace YooAsset.Editor
|
||||
/// </summary>
|
||||
public bool HasBundleName()
|
||||
{
|
||||
string bundleName = GetBundleName();
|
||||
if (string.IsNullOrEmpty(bundleName))
|
||||
if (string.IsNullOrEmpty(BundleName))
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取资源包名称
|
||||
/// </summary>
|
||||
public string GetBundleName()
|
||||
{
|
||||
if (CollectorType == ECollectorType.None)
|
||||
return _shareBundleName;
|
||||
else
|
||||
return _mainBundleName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 添加关联的资源包名称
|
||||
/// </summary>
|
||||
@@ -164,53 +155,32 @@ namespace YooAsset.Editor
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 计算主资源或共享资源的完整包名
|
||||
/// 计算共享资源包的完整包名
|
||||
/// </summary>
|
||||
public void CalculateFullBundleName(bool uniqueBundleName, string packageName)
|
||||
public void CalculateShareBundleName(bool uniqueBundleName, string packageName, string shadersBundleName)
|
||||
{
|
||||
if (CollectorType == ECollectorType.None)
|
||||
if (CollectorType != ECollectorType.None)
|
||||
return;
|
||||
|
||||
if (IsRawAsset)
|
||||
throw new Exception("Should never get here !");
|
||||
|
||||
if (IsShaderAsset)
|
||||
{
|
||||
if (IsRawAsset)
|
||||
throw new Exception("Should never get here !");
|
||||
|
||||
if (IsShaderAsset)
|
||||
{
|
||||
_shareBundleName = YooAssetSettingsData.GetUnityShadersBundleFullName(uniqueBundleName, packageName);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_referenceBundleNames.Count > 1)
|
||||
{
|
||||
IPackRule packRule = PackDirectory.StaticPackRule;
|
||||
var bundleName = packRule.GetBundleName(new PackRuleData(AssetPath));
|
||||
if (YooAssetSettingsData.Setting.RegularBundleName)
|
||||
bundleName = EditorTools.GetRegularPath(bundleName).Replace('/', '_').Replace('.', '_').ToLower();
|
||||
else
|
||||
bundleName = EditorTools.GetRegularPath(bundleName).ToLower();
|
||||
|
||||
if (uniqueBundleName)
|
||||
_shareBundleName = $"{packageName.ToLower()}_share_{bundleName}.{YooAssetSettingsData.Setting.AssetBundleFileVariant}";
|
||||
else
|
||||
_shareBundleName = $"share_{bundleName}.{YooAssetSettingsData.Setting.AssetBundleFileVariant}";
|
||||
}
|
||||
}
|
||||
BundleName = shadersBundleName;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (IsRawAsset)
|
||||
if (_referenceBundleNames.Count > 1)
|
||||
{
|
||||
string mainBundleName = $"{_mainBundleName}.{YooAssetSettingsData.Setting.RawFileVariant}";
|
||||
_mainBundleName = mainBundleName.ToLower();
|
||||
IPackRule packRule = PackDirectory.StaticPackRule;
|
||||
PackRuleResult packRuleResult = packRule.GetPackRuleResult(new PackRuleData(AssetPath));
|
||||
BundleName = packRuleResult.GetShareBundleName(packageName, uniqueBundleName);
|
||||
}
|
||||
else
|
||||
{
|
||||
string mainBundleName = $"{_mainBundleName}.{YooAssetSettingsData.Setting.AssetBundleFileVariant}";
|
||||
_mainBundleName = mainBundleName.ToLower(); ;
|
||||
}
|
||||
|
||||
if (uniqueBundleName)
|
||||
{
|
||||
_mainBundleName = $"{packageName.ToLower()}_{_mainBundleName}";
|
||||
// 注意:被引用次数小于1的资源不需要设置资源包名称
|
||||
BundleName = string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,11 @@ namespace YooAsset.Editor
|
||||
/// </summary>
|
||||
public bool UniqueBundleName;
|
||||
|
||||
/// <summary>
|
||||
/// 着色器统一的全名称
|
||||
/// </summary>
|
||||
public string ShadersBundleName;
|
||||
|
||||
/// <summary>
|
||||
/// 资源包列表
|
||||
/// </summary>
|
||||
@@ -35,7 +40,7 @@ namespace YooAsset.Editor
|
||||
/// </summary>
|
||||
public void PackAsset(BuildAssetInfo assetInfo)
|
||||
{
|
||||
string bundleName = assetInfo.GetBundleName();
|
||||
string bundleName = assetInfo.BundleName;
|
||||
if (string.IsNullOrEmpty(bundleName))
|
||||
throw new Exception("Should never get here !");
|
||||
|
||||
|
||||
@@ -11,8 +11,7 @@ namespace YooAsset.Editor
|
||||
/// 执行资源构建上下文
|
||||
/// </summary>
|
||||
public static BuildMapContext CreateBuildMap(EBuildMode buildMode, string packageName)
|
||||
{
|
||||
BuildMapContext context = new BuildMapContext();
|
||||
{
|
||||
Dictionary<string, BuildAssetInfo> buildAssetDic = new Dictionary<string, BuildAssetInfo>(1000);
|
||||
|
||||
// 1. 检测配置合法性
|
||||
@@ -22,7 +21,7 @@ namespace YooAsset.Editor
|
||||
var buildResult = AssetBundleCollectorSettingData.Setting.GetPackageAssets(buildMode, packageName);
|
||||
List<CollectAssetInfo> allCollectAssets = buildResult.CollectAssets;
|
||||
|
||||
// 3. 剔除未被引用的依赖资源
|
||||
// 3. 剔除未被引用的依赖项资源
|
||||
List<CollectAssetInfo> removeDependList = new List<CollectAssetInfo>();
|
||||
foreach (var collectAssetInfo in allCollectAssets)
|
||||
{
|
||||
@@ -42,7 +41,8 @@ namespace YooAsset.Editor
|
||||
{
|
||||
if (buildAssetDic.ContainsKey(collectAssetInfo.AssetPath) == false)
|
||||
{
|
||||
var buildAssetInfo = new BuildAssetInfo(collectAssetInfo.CollectorType, collectAssetInfo.BundleName,
|
||||
var buildAssetInfo = new BuildAssetInfo(
|
||||
collectAssetInfo.CollectorType, collectAssetInfo.BundleName,
|
||||
collectAssetInfo.Address, collectAssetInfo.AssetPath, collectAssetInfo.IsRawAsset);
|
||||
buildAssetInfo.AddAssetTags(collectAssetInfo.AssetTags);
|
||||
buildAssetInfo.AddBundleTags(collectAssetInfo.AssetTags);
|
||||
@@ -54,32 +54,28 @@ namespace YooAsset.Editor
|
||||
}
|
||||
}
|
||||
|
||||
// 5. 录入相关依赖的资源
|
||||
// 5. 录入所有收集资源的依赖资源
|
||||
foreach (var collectAssetInfo in allCollectAssets)
|
||||
{
|
||||
string collectAssetBundleName = collectAssetInfo.BundleName;
|
||||
foreach (var dependAssetPath in collectAssetInfo.DependAssets)
|
||||
{
|
||||
if (buildAssetDic.ContainsKey(dependAssetPath))
|
||||
{
|
||||
buildAssetDic[dependAssetPath].AddBundleTags(collectAssetInfo.AssetTags);
|
||||
buildAssetDic[dependAssetPath].AddReferenceBundleName(collectAssetInfo.BundleName);
|
||||
buildAssetDic[dependAssetPath].AddReferenceBundleName(collectAssetBundleName);
|
||||
}
|
||||
else
|
||||
{
|
||||
var buildAssetInfo = new BuildAssetInfo(dependAssetPath);
|
||||
buildAssetInfo.AddBundleTags(collectAssetInfo.AssetTags);
|
||||
buildAssetInfo.AddReferenceBundleName(collectAssetInfo.BundleName);
|
||||
buildAssetInfo.AddReferenceBundleName(collectAssetBundleName);
|
||||
buildAssetDic.Add(dependAssetPath, buildAssetInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 6. 记录关键信息
|
||||
context.AssetFileCount = buildAssetDic.Count;
|
||||
context.EnableAddressable = buildResult.EnableAddressable;
|
||||
context.UniqueBundleName = buildResult.UniqueBundleName;
|
||||
|
||||
// 7. 填充主动收集资源的依赖列表
|
||||
// 6. 填充所有收集资源的依赖列表
|
||||
foreach (var collectAssetInfo in allCollectAssets)
|
||||
{
|
||||
var dependAssetInfos = new List<BuildAssetInfo>(collectAssetInfo.DependAssets.Count);
|
||||
@@ -93,10 +89,18 @@ namespace YooAsset.Editor
|
||||
buildAssetDic[collectAssetInfo.AssetPath].SetAllDependAssetInfos(dependAssetInfos);
|
||||
}
|
||||
|
||||
// 8. 计算完整的资源包名
|
||||
// 7. 记录关键信息
|
||||
BuildMapContext context = new BuildMapContext();
|
||||
context.AssetFileCount = buildAssetDic.Count;
|
||||
context.EnableAddressable = buildResult.Command.EnableAddressable;
|
||||
context.UniqueBundleName = buildResult.Command.UniqueBundleName;
|
||||
context.ShadersBundleName = buildResult.ShadersBundleName;
|
||||
|
||||
// 8. 计算共享的资源包名
|
||||
var command = buildResult.Command;
|
||||
foreach (KeyValuePair<string, BuildAssetInfo> pair in buildAssetDic)
|
||||
{
|
||||
pair.Value.CalculateFullBundleName(buildResult.UniqueBundleName, buildResult.PackageName);
|
||||
pair.Value.CalculateShareBundleName(command.UniqueBundleName, command.PackageName, buildResult.ShadersBundleName);
|
||||
}
|
||||
|
||||
// 9. 移除不参与构建的资源
|
||||
|
||||
@@ -45,32 +45,6 @@ namespace YooAsset.Editor
|
||||
BuildResultContext buildResultContext = new BuildResultContext();
|
||||
buildResultContext.UnityManifest = buildResults;
|
||||
context.SetContextObject(buildResultContext);
|
||||
|
||||
// 拷贝原生文件
|
||||
if (buildMode == EBuildMode.ForceRebuild || buildMode == EBuildMode.IncrementalBuild)
|
||||
{
|
||||
CopyRawBundle(buildMapContext, buildParametersContext);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 拷贝原生文件
|
||||
/// </summary>
|
||||
private void CopyRawBundle(BuildMapContext buildMapContext, BuildParametersContext buildParametersContext)
|
||||
{
|
||||
string pipelineOutputDirectory = buildParametersContext.GetPipelineOutputDirectory();
|
||||
foreach (var bundleInfo in buildMapContext.BundleInfos)
|
||||
{
|
||||
if (bundleInfo.IsRawFile)
|
||||
{
|
||||
string dest = $"{pipelineOutputDirectory}/{bundleInfo.BundleName}";
|
||||
foreach (var buildAsset in bundleInfo.BuildinAssets)
|
||||
{
|
||||
if (buildAsset.IsRawAsset)
|
||||
EditorTools.CopyFile(buildAsset.AssetPath, dest, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -33,8 +33,7 @@ namespace YooAsset.Editor
|
||||
// 开始构建
|
||||
IBundleBuildResults buildResults;
|
||||
var buildParameters = buildParametersContext.GetSBPBuildParameters();
|
||||
var shadersBunldeName = YooAssetSettingsData.GetUnityShadersBundleFullName(buildMapContext.UniqueBundleName, buildParametersContext.Parameters.PackageName);
|
||||
var taskList = SBPBuildTasks.Create(shadersBunldeName);
|
||||
var taskList = SBPBuildTasks.Create(buildMapContext.ShadersBundleName);
|
||||
ReturnCode exitCode = ContentPipeline.BuildAssetBundles(buildParameters, buildContent, out buildResults, taskList);
|
||||
if (exitCode < 0)
|
||||
{
|
||||
@@ -45,32 +44,6 @@ namespace YooAsset.Editor
|
||||
BuildResultContext buildResultContext = new BuildResultContext();
|
||||
buildResultContext.Results = buildResults;
|
||||
context.SetContextObject(buildResultContext);
|
||||
|
||||
// 拷贝原生文件
|
||||
if (buildMode == EBuildMode.ForceRebuild || buildMode == EBuildMode.IncrementalBuild)
|
||||
{
|
||||
CopyRawBundle(buildMapContext, buildParametersContext);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 拷贝原生文件
|
||||
/// </summary>
|
||||
private void CopyRawBundle(BuildMapContext buildMapContext, BuildParametersContext buildParametersContext)
|
||||
{
|
||||
string pipelineOutputDirectory = buildParametersContext.GetPipelineOutputDirectory();
|
||||
foreach (var bundleInfo in buildMapContext.BundleInfos)
|
||||
{
|
||||
if (bundleInfo.IsRawFile)
|
||||
{
|
||||
string dest = $"{pipelineOutputDirectory}/{bundleInfo.BundleName}";
|
||||
foreach (var buildAsset in bundleInfo.BuildinAssets)
|
||||
{
|
||||
if (buildAsset.IsRawAsset)
|
||||
EditorTools.CopyFile(buildAsset.AssetPath, dest, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace YooAsset.Editor
|
||||
{
|
||||
[TaskAttribute("拷贝原生文件")]
|
||||
public class TaskCopyRawFile : IBuildTask
|
||||
{
|
||||
void IBuildTask.Run(BuildContext context)
|
||||
{
|
||||
var buildParametersContext = context.GetContextObject<BuildParametersContext>();
|
||||
var buildParameters = context.GetContextObject<BuildParametersContext>();
|
||||
var buildMapContext = context.GetContextObject<BuildMapContext>();
|
||||
|
||||
var buildMode = buildParameters.Parameters.BuildMode;
|
||||
if (buildMode == EBuildMode.ForceRebuild || buildMode == EBuildMode.IncrementalBuild)
|
||||
{
|
||||
CopyRawBundle(buildMapContext, buildParametersContext);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 拷贝原生文件
|
||||
/// </summary>
|
||||
private void CopyRawBundle(BuildMapContext buildMapContext, BuildParametersContext buildParametersContext)
|
||||
{
|
||||
string pipelineOutputDirectory = buildParametersContext.GetPipelineOutputDirectory();
|
||||
foreach (var bundleInfo in buildMapContext.BundleInfos)
|
||||
{
|
||||
if (bundleInfo.IsRawFile)
|
||||
{
|
||||
string dest = $"{pipelineOutputDirectory}/{bundleInfo.BundleName}";
|
||||
foreach (var buildAsset in bundleInfo.BuildinAssets)
|
||||
{
|
||||
if (buildAsset.IsRawAsset)
|
||||
EditorTools.CopyFile(buildAsset.AssetPath, dest, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a6296859f09655c4191594304ddf378f
|
||||
guid: 3625d4b8b5b79324ebf7ec19a87677e7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
@@ -42,13 +42,32 @@ namespace YooAsset.Editor
|
||||
patchManifest.AssetList = GetAllPatchAsset(context, patchManifest);
|
||||
|
||||
// 更新Unity内置资源包的引用关系
|
||||
string shadersBunldeName = YooAssetSettingsData.GetUnityShadersBundleFullName(buildMapContext.UniqueBundleName, buildParameters.PackageName);
|
||||
if (buildParameters.BuildPipeline == EBuildPipeline.ScriptableBuildPipeline)
|
||||
{
|
||||
if (buildParameters.BuildMode == EBuildMode.IncrementalBuild)
|
||||
{
|
||||
var buildResultContext = context.GetContextObject<TaskBuilding_SBP.BuildResultContext>();
|
||||
UpdateBuiltInBundleReference(patchManifest, buildResultContext.Results, shadersBunldeName);
|
||||
UpdateBuiltInBundleReference(patchManifest, buildResultContext, buildMapContext.ShadersBundleName);
|
||||
}
|
||||
}
|
||||
|
||||
// 更新资源包之间的引用关系
|
||||
if (buildParameters.BuildPipeline == EBuildPipeline.ScriptableBuildPipeline)
|
||||
{
|
||||
if (buildParameters.BuildMode == EBuildMode.IncrementalBuild)
|
||||
{
|
||||
var buildResultContext = context.GetContextObject<TaskBuilding_SBP.BuildResultContext>();
|
||||
UpdateScriptPipelineReference(patchManifest, buildResultContext);
|
||||
}
|
||||
}
|
||||
|
||||
// 更新资源包之间的引用关系
|
||||
if (buildParameters.BuildPipeline == EBuildPipeline.BuiltinBuildPipeline)
|
||||
{
|
||||
if (buildParameters.BuildMode != EBuildMode.SimulateBuild)
|
||||
{
|
||||
var buildResultContext = context.GetContextObject<TaskBuilding.BuildResultContext>();
|
||||
UpdateBuiltinPipelineReference(patchManifest, buildResultContext, buildMapContext);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,7 +117,6 @@ namespace YooAsset.Editor
|
||||
private List<PatchBundle> GetAllPatchBundle(BuildContext context)
|
||||
{
|
||||
var buildMapContext = context.GetContextObject<BuildMapContext>();
|
||||
var buildParametersContext = context.GetContextObject<BuildParametersContext>();
|
||||
|
||||
List<PatchBundle> result = new List<PatchBundle>(1000);
|
||||
foreach (var bundleInfo in buildMapContext.BundleInfos)
|
||||
@@ -129,7 +147,7 @@ namespace YooAsset.Editor
|
||||
patchAsset.Address = string.Empty;
|
||||
patchAsset.AssetPath = assetInfo.AssetPath;
|
||||
patchAsset.AssetTags = assetInfo.AssetTags.ToArray();
|
||||
patchAsset.BundleID = GetAssetBundleID(assetInfo.GetBundleName(), patchManifest);
|
||||
patchAsset.BundleID = GetAssetBundleID(assetInfo.BundleName, patchManifest);
|
||||
patchAsset.DependIDs = GetAssetBundleDependIDs(patchAsset.BundleID, assetInfo, patchManifest);
|
||||
result.Add(patchAsset);
|
||||
}
|
||||
@@ -143,7 +161,7 @@ namespace YooAsset.Editor
|
||||
{
|
||||
if (dependAssetInfo.HasBundleName())
|
||||
{
|
||||
int bundleID = GetAssetBundleID(dependAssetInfo.GetBundleName(), patchManifest);
|
||||
int bundleID = GetAssetBundleID(dependAssetInfo.BundleName, patchManifest);
|
||||
if (mainBundleID != bundleID)
|
||||
{
|
||||
if (result.Contains(bundleID) == false)
|
||||
@@ -166,11 +184,11 @@ namespace YooAsset.Editor
|
||||
/// <summary>
|
||||
/// 更新Unity内置资源包的引用关系
|
||||
/// </summary>
|
||||
private void UpdateBuiltInBundleReference(PatchManifest patchManifest, IBundleBuildResults buildResults, string shadersBunldeName)
|
||||
private void UpdateBuiltInBundleReference(PatchManifest patchManifest, TaskBuilding_SBP.BuildResultContext buildResultContext, string shadersBunldeName)
|
||||
{
|
||||
// 获取所有依赖着色器资源包的资源包列表
|
||||
List<string> shaderBundleReferenceList = new List<string>();
|
||||
foreach (var valuePair in buildResults.BundleInfos)
|
||||
foreach (var valuePair in buildResultContext.Results.BundleInfos)
|
||||
{
|
||||
if (valuePair.Value.Dependencies.Any(t => t == shadersBunldeName))
|
||||
shaderBundleReferenceList.Add(valuePair.Key);
|
||||
@@ -212,5 +230,79 @@ namespace YooAsset.Editor
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新资源包之间的引用关系
|
||||
/// </summary>
|
||||
private void UpdateScriptPipelineReference(PatchManifest patchManifest, TaskBuilding_SBP.BuildResultContext buildResultContext)
|
||||
{
|
||||
foreach (var patchBundle in patchManifest.BundleList)
|
||||
{
|
||||
patchBundle.ReferenceIDs = GetScriptPipelineRefrenceIDs(patchManifest, patchBundle, buildResultContext);
|
||||
}
|
||||
}
|
||||
private int[] GetScriptPipelineRefrenceIDs(PatchManifest patchManifest, PatchBundle patchBundle, TaskBuilding_SBP.BuildResultContext buildResultContext)
|
||||
{
|
||||
if (buildResultContext.Results.BundleInfos.TryGetValue(patchBundle.BundleName, out var details) == false)
|
||||
{
|
||||
throw new Exception("Should never get here !");
|
||||
}
|
||||
|
||||
List<string> referenceList = new List<string>();
|
||||
foreach (var keyValuePair in buildResultContext.Results.BundleInfos)
|
||||
{
|
||||
string bundleName = keyValuePair.Key;
|
||||
if (bundleName == patchBundle.BundleName)
|
||||
continue;
|
||||
if (keyValuePair.Value.Dependencies.Contains(patchBundle.BundleName))
|
||||
{
|
||||
referenceList.Add(bundleName);
|
||||
}
|
||||
}
|
||||
|
||||
List<int> result = new List<int>();
|
||||
foreach (var bundleName in referenceList)
|
||||
{
|
||||
int bundleID = GetAssetBundleID(bundleName, patchManifest);
|
||||
if (result.Contains(bundleID) == false)
|
||||
result.Add(bundleID);
|
||||
}
|
||||
return result.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新资源包之间的引用关系
|
||||
/// </summary>
|
||||
private void UpdateBuiltinPipelineReference(PatchManifest patchManifest, TaskBuilding.BuildResultContext buildResultContext, BuildMapContext buildMapContext)
|
||||
{
|
||||
foreach (var patchBundle in patchManifest.BundleList)
|
||||
{
|
||||
patchBundle.ReferenceIDs = GetBuiltinPipelineRefrenceIDs(patchManifest, patchBundle, buildResultContext, buildMapContext);
|
||||
}
|
||||
}
|
||||
private int[] GetBuiltinPipelineRefrenceIDs(PatchManifest patchManifest, PatchBundle patchBundle, TaskBuilding.BuildResultContext buildResultContext, BuildMapContext buildMapContext)
|
||||
{
|
||||
List<string> referenceList = new List<string>();
|
||||
foreach (var bundleInfo in buildMapContext.BundleInfos)
|
||||
{
|
||||
string bundleName = bundleInfo.BundleName;
|
||||
if (bundleName == patchBundle.BundleName)
|
||||
continue;
|
||||
string[] dependencies = buildResultContext.UnityManifest.GetAllDependencies(bundleName);
|
||||
if (dependencies.Contains(patchBundle.BundleName))
|
||||
{
|
||||
referenceList.Add(bundleName);
|
||||
}
|
||||
}
|
||||
|
||||
List<int> result = new List<int>();
|
||||
foreach (var bundleName in referenceList)
|
||||
{
|
||||
int bundleID = GetAssetBundleID(bundleName, patchManifest);
|
||||
if (result.Contains(bundleID) == false)
|
||||
result.Add(bundleID);
|
||||
}
|
||||
return result.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,7 @@ namespace YooAsset.Editor
|
||||
throw new Exception("请选择目标平台");
|
||||
if (string.IsNullOrEmpty(buildParameters.PackageName))
|
||||
throw new Exception("包裹名称不能为空");
|
||||
if(string.IsNullOrEmpty(buildParameters.PackageVersion))
|
||||
if (string.IsNullOrEmpty(buildParameters.PackageVersion))
|
||||
throw new Exception("包裹版本不能为空");
|
||||
|
||||
if (buildParameters.BuildMode != EBuildMode.SimulateBuild)
|
||||
|
||||
@@ -48,7 +48,8 @@ namespace YooAsset.Editor
|
||||
// 4.更新补丁包输出的文件路径
|
||||
foreach (var bundleInfo in buildMapContext.BundleInfos)
|
||||
{
|
||||
string patchFileName = PatchManifest.CreateBundleFileName(outputNameStyle, bundleInfo.BundleName, bundleInfo.PatchInfo.PatchFileHash, bundleInfo.IsRawFile);
|
||||
string patchFileExtension = PatchManifestTools.GetRemoteBundleFileExtension(bundleInfo.BundleName);
|
||||
string patchFileName = PatchManifestTools.GetRemoteBundleFileName(outputNameStyle, bundleInfo.BundleName, patchFileExtension, bundleInfo.PatchInfo.PatchFileHash);
|
||||
bundleInfo.PatchInfo.PatchOutputFilePath = $"{packageOutputDirectory}/{patchFileName}";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,6 +45,11 @@ namespace YooAsset.Editor
|
||||
/// </summary>
|
||||
public string AssetTags = string.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// 用户自定义数据
|
||||
/// </summary>
|
||||
public string UserData = string.Empty;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 收集器是否有效
|
||||
@@ -142,11 +147,14 @@ namespace YooAsset.Editor
|
||||
}
|
||||
|
||||
Dictionary<string, CollectAssetInfo> result = new Dictionary<string, CollectAssetInfo>(1000);
|
||||
bool isRawAsset = PackRuleName == nameof(PackRawFile);
|
||||
|
||||
// 检测是否为原生资源打包规则
|
||||
IPackRule packRuleInstance = AssetBundleCollectorSettingData.GetPackRuleInstance(PackRuleName);
|
||||
bool isRawFilePackRule = packRuleInstance.IsRawFilePackRule();
|
||||
|
||||
// 检测原生资源包的收集器类型
|
||||
if (isRawAsset && CollectorType != ECollectorType.MainAssetCollector)
|
||||
throw new Exception($"The raw file must be set to {nameof(ECollectorType)}.{ECollectorType.MainAssetCollector} : {CollectPath}");
|
||||
if (isRawFilePackRule && CollectorType != ECollectorType.MainAssetCollector)
|
||||
throw new Exception($"The raw file pack rule must be set to {nameof(ECollectorType)}.{ECollectorType.MainAssetCollector} : {CollectPath}");
|
||||
|
||||
if (string.IsNullOrEmpty(CollectPath))
|
||||
throw new Exception($"The collect path is null or empty in group : {group.GroupName}");
|
||||
@@ -158,11 +166,11 @@ namespace YooAsset.Editor
|
||||
string[] findAssets = EditorTools.FindAssets(EAssetSearchType.All, collectDirectory);
|
||||
foreach (string assetPath in findAssets)
|
||||
{
|
||||
if (IsValidateAsset(assetPath) && IsCollectAsset(assetPath))
|
||||
if (IsValidateAsset(assetPath, isRawFilePackRule) && IsCollectAsset(assetPath))
|
||||
{
|
||||
if (result.ContainsKey(assetPath) == false)
|
||||
{
|
||||
var collectAssetInfo = CreateCollectAssetInfo(command, group, assetPath, isRawAsset);
|
||||
var collectAssetInfo = CreateCollectAssetInfo(command, group, assetPath, isRawFilePackRule);
|
||||
result.Add(assetPath, collectAssetInfo);
|
||||
}
|
||||
else
|
||||
@@ -175,9 +183,9 @@ namespace YooAsset.Editor
|
||||
else
|
||||
{
|
||||
string assetPath = CollectPath;
|
||||
if (IsValidateAsset(assetPath) && IsCollectAsset(assetPath))
|
||||
if (IsValidateAsset(assetPath, isRawFilePackRule) && IsCollectAsset(assetPath))
|
||||
{
|
||||
var collectAssetInfo = CreateCollectAssetInfo(command, group, assetPath, isRawAsset);
|
||||
var collectAssetInfo = CreateCollectAssetInfo(command, group, assetPath, isRawFilePackRule);
|
||||
result.Add(assetPath, collectAssetInfo);
|
||||
}
|
||||
else
|
||||
@@ -207,22 +215,22 @@ namespace YooAsset.Editor
|
||||
return result.Values.ToList();
|
||||
}
|
||||
|
||||
private CollectAssetInfo CreateCollectAssetInfo(CollectCommand command, AssetBundleCollectorGroup group, string assetPath, bool isRawAsset)
|
||||
private CollectAssetInfo CreateCollectAssetInfo(CollectCommand command, AssetBundleCollectorGroup group, string assetPath, bool isRawFilePackRule)
|
||||
{
|
||||
string address = GetAddress(group, assetPath);
|
||||
string bundleName = GetBundleName(group, assetPath);
|
||||
string bundleName = GetBundleName(command, group, assetPath);
|
||||
List<string> assetTags = GetAssetTags(group);
|
||||
CollectAssetInfo collectAssetInfo = new CollectAssetInfo(CollectorType, bundleName, address, assetPath, assetTags, isRawAsset);
|
||||
CollectAssetInfo collectAssetInfo = new CollectAssetInfo(CollectorType, bundleName, address, assetPath, isRawFilePackRule, assetTags);
|
||||
|
||||
// 注意:模拟构建模式下不需要收集依赖资源
|
||||
if (command.BuildMode == EBuildMode.SimulateBuild)
|
||||
collectAssetInfo.DependAssets = new List<string>();
|
||||
else
|
||||
collectAssetInfo.DependAssets = GetAllDependencies(assetPath);
|
||||
collectAssetInfo.DependAssets = GetAllDependencies(assetPath, isRawFilePackRule);
|
||||
|
||||
return collectAssetInfo;
|
||||
}
|
||||
private bool IsValidateAsset(string assetPath)
|
||||
private bool IsValidateAsset(string assetPath, bool isRawFilePackRule)
|
||||
{
|
||||
if (assetPath.StartsWith("Assets/") == false && assetPath.StartsWith("Packages/") == false)
|
||||
{
|
||||
@@ -239,10 +247,31 @@ namespace YooAsset.Editor
|
||||
if (type == typeof(LightingDataAsset))
|
||||
return false;
|
||||
|
||||
// 忽略Unity无法识别的无效文件
|
||||
// 注意:只对非原生文件收集器处理
|
||||
if(PackRuleName != nameof(PackRawFile))
|
||||
// 检测原生文件是否合规
|
||||
if (isRawFilePackRule)
|
||||
{
|
||||
string extension = StringUtility.RemoveFirstChar(System.IO.Path.GetExtension(assetPath));
|
||||
if (extension == EAssetFileExtension.unity.ToString() || extension == EAssetFileExtension.prefab.ToString() ||
|
||||
extension == EAssetFileExtension.mat.ToString() || extension == EAssetFileExtension.controller.ToString() ||
|
||||
extension == EAssetFileExtension.fbx.ToString() || extension == EAssetFileExtension.anim.ToString() ||
|
||||
extension == EAssetFileExtension.shader.ToString())
|
||||
{
|
||||
UnityEngine.Debug.LogWarning($"Raw file pack rule can not support file estension : {extension}");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 注意:原生文件只支持无依赖关系的资源
|
||||
string[] depends = AssetDatabase.GetDependencies(assetPath, true);
|
||||
if (depends.Length != 1)
|
||||
{
|
||||
UnityEngine.Debug.LogWarning($"Raw file pack rule can not support estension : {extension}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 忽略Unity无法识别的无效文件
|
||||
// 注意:只对非原生文件收集器处理
|
||||
if (type == typeof(UnityEditor.DefaultAsset))
|
||||
{
|
||||
UnityEngine.Debug.LogWarning($"Cannot pack default asset : {assetPath}");
|
||||
@@ -258,7 +287,7 @@ namespace YooAsset.Editor
|
||||
}
|
||||
private bool IsIgnoreFile(string fileExtension)
|
||||
{
|
||||
foreach (var extension in YooAssetSettings.IgnoreFileExtensions)
|
||||
foreach (var extension in DefaultFilterRule.IgnoreFileExtensions)
|
||||
{
|
||||
if (extension == fileExtension)
|
||||
return true;
|
||||
@@ -281,22 +310,25 @@ namespace YooAsset.Editor
|
||||
return string.Empty;
|
||||
|
||||
IAddressRule addressRuleInstance = AssetBundleCollectorSettingData.GetAddressRuleInstance(AddressRuleName);
|
||||
string adressValue = addressRuleInstance.GetAssetAddress(new AddressRuleData(assetPath, CollectPath, group.GroupName));
|
||||
string adressValue = addressRuleInstance.GetAssetAddress(new AddressRuleData(assetPath, CollectPath, group.GroupName, UserData));
|
||||
return adressValue;
|
||||
}
|
||||
private string GetBundleName(AssetBundleCollectorGroup group, string assetPath)
|
||||
private string GetBundleName(CollectCommand command, AssetBundleCollectorGroup group, string assetPath)
|
||||
{
|
||||
System.Type assetType = AssetDatabase.GetMainAssetTypeAtPath(assetPath);
|
||||
if (assetType == typeof(UnityEngine.Shader) || assetType == typeof(UnityEngine.ShaderVariantCollection))
|
||||
return EditorTools.GetRegularPath(YooAssetSettings.UnityShadersBundleName).ToLower();
|
||||
|
||||
// 根据规则设置获取资源包名称
|
||||
IPackRule packRuleInstance = AssetBundleCollectorSettingData.GetPackRuleInstance(PackRuleName);
|
||||
string bundleName = packRuleInstance.GetBundleName(new PackRuleData(assetPath, CollectPath, group.GroupName));
|
||||
if(YooAssetSettingsData.Setting.RegularBundleName)
|
||||
return EditorTools.GetRegularPath(bundleName).Replace('/', '_').Replace('.', '_').ToLower();
|
||||
{
|
||||
// 获取着色器打包规则结果
|
||||
PackRuleResult packRuleResult = DefaultPackRule.CreateShadersPackRuleResult();
|
||||
return packRuleResult.GetMainBundleName(command.PackageName, command.UniqueBundleName);
|
||||
}
|
||||
else
|
||||
return EditorTools.GetRegularPath(bundleName).ToLower();
|
||||
{
|
||||
// 获取其它资源打包规则结果
|
||||
IPackRule packRuleInstance = AssetBundleCollectorSettingData.GetPackRuleInstance(PackRuleName);
|
||||
PackRuleResult packRuleResult = packRuleInstance.GetPackRuleResult(new PackRuleData(assetPath, CollectPath, group.GroupName, UserData));
|
||||
return packRuleResult.GetMainBundleName(command.PackageName, command.UniqueBundleName);
|
||||
}
|
||||
}
|
||||
private List<string> GetAssetTags(AssetBundleCollectorGroup group)
|
||||
{
|
||||
@@ -305,13 +337,13 @@ namespace YooAsset.Editor
|
||||
tags.AddRange(temper);
|
||||
return tags;
|
||||
}
|
||||
private List<string> GetAllDependencies(string mainAssetPath)
|
||||
private List<string> GetAllDependencies(string mainAssetPath, bool isRawFilePackRule)
|
||||
{
|
||||
List<string> result = new List<string>();
|
||||
string[] depends = AssetDatabase.GetDependencies(mainAssetPath, true);
|
||||
foreach (string assetPath in depends)
|
||||
{
|
||||
if (IsValidateAsset(assetPath))
|
||||
if (IsValidateAsset(assetPath, isRawFilePackRule))
|
||||
{
|
||||
// 注意:排除主资源对象
|
||||
if (assetPath != mainAssetPath)
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace YooAsset.Editor
|
||||
{
|
||||
public class AssetBundleCollectorConfig
|
||||
{
|
||||
public const string ConfigVersion = "2.2";
|
||||
public const string ConfigVersion = "2.3";
|
||||
|
||||
public const string XmlVersion = "Version";
|
||||
public const string XmlCommon = "Common";
|
||||
@@ -34,6 +34,7 @@ namespace YooAsset.Editor
|
||||
public const string XmlAddressRule = "AddressRule";
|
||||
public const string XmlPackRule = "PackRule";
|
||||
public const string XmlFilterRule = "FilterRule";
|
||||
public const string XmlUserData = "UserData";
|
||||
public const string XmlAssetTags = "AssetTags";
|
||||
|
||||
/// <summary>
|
||||
@@ -137,6 +138,8 @@ namespace YooAsset.Editor
|
||||
throw new Exception($"Not found attribute {XmlPackRule} in {XmlCollector}");
|
||||
if (collectorElement.HasAttribute(XmlFilterRule) == false)
|
||||
throw new Exception($"Not found attribute {XmlFilterRule} in {XmlCollector}");
|
||||
if (collectorElement.HasAttribute(XmlUserData) == false)
|
||||
throw new Exception($"Not found attribute {XmlUserData} in {XmlCollector}");
|
||||
if (collectorElement.HasAttribute(XmlAssetTags) == false)
|
||||
throw new Exception($"Not found attribute {XmlAssetTags} in {XmlCollector}");
|
||||
|
||||
@@ -147,6 +150,7 @@ namespace YooAsset.Editor
|
||||
collector.AddressRuleName = collectorElement.GetAttribute(XmlAddressRule);
|
||||
collector.PackRuleName = collectorElement.GetAttribute(XmlPackRule);
|
||||
collector.FilterRuleName = collectorElement.GetAttribute(XmlFilterRule);
|
||||
collector.UserData = collectorElement.GetAttribute(XmlUserData);
|
||||
collector.AssetTags = collectorElement.GetAttribute(XmlAssetTags);
|
||||
group.Collectors.Add(collector);
|
||||
}
|
||||
@@ -219,6 +223,7 @@ namespace YooAsset.Editor
|
||||
collectorElement.SetAttribute(XmlAddressRule, collector.AddressRuleName);
|
||||
collectorElement.SetAttribute(XmlPackRule, collector.PackRuleName);
|
||||
collectorElement.SetAttribute(XmlFilterRule, collector.FilterRuleName);
|
||||
collectorElement.SetAttribute(XmlUserData, collector.UserData);
|
||||
collectorElement.SetAttribute(XmlAssetTags, collector.AssetTags);
|
||||
groupElement.AppendChild(collectorElement);
|
||||
}
|
||||
@@ -320,6 +325,28 @@ namespace YooAsset.Editor
|
||||
return UpdateXmlConfig(xmlDoc);
|
||||
}
|
||||
|
||||
// 2.2 -> 2.3
|
||||
if (configVersion == "2.2")
|
||||
{
|
||||
// 获取所有分组元素
|
||||
var groupNodeList = root.GetElementsByTagName(XmlGroup);
|
||||
foreach (var groupNode in groupNodeList)
|
||||
{
|
||||
XmlElement groupElement = groupNode as XmlElement;
|
||||
var collectorNodeList = groupElement.GetElementsByTagName(XmlCollector);
|
||||
foreach (var collectorNode in collectorNodeList)
|
||||
{
|
||||
XmlElement collectorElement = collectorNode as XmlElement;
|
||||
if (collectorElement.HasAttribute(XmlUserData) == false)
|
||||
collectorElement.SetAttribute(XmlUserData, string.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
// 更新版本
|
||||
root.SetAttribute(XmlVersion, "2.3");
|
||||
return UpdateXmlConfig(xmlDoc);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,8 +100,8 @@ namespace YooAsset.Editor
|
||||
{
|
||||
if (package.PackageName == packageName)
|
||||
{
|
||||
CollectCommand command = new CollectCommand(buildMode, EnableAddressable);
|
||||
CollectResult collectResult = new CollectResult(package.PackageName, EnableAddressable, UniqueBundleName);
|
||||
CollectCommand command = new CollectCommand(buildMode, package.PackageName, EnableAddressable, UniqueBundleName);
|
||||
CollectResult collectResult = new CollectResult(command);
|
||||
collectResult.SetCollectAssets(package.GetAllCollectAssets(command));
|
||||
return collectResult;
|
||||
}
|
||||
@@ -118,8 +118,8 @@ namespace YooAsset.Editor
|
||||
List<CollectResult> collectResultList = new List<CollectResult>(1000);
|
||||
foreach (var package in Packages)
|
||||
{
|
||||
CollectCommand command = new CollectCommand(buildMode, EnableAddressable);
|
||||
CollectResult collectResult = new CollectResult(package.PackageName, EnableAddressable, UniqueBundleName);
|
||||
CollectCommand command = new CollectCommand(buildMode, package.PackageName, EnableAddressable, UniqueBundleName);
|
||||
CollectResult collectResult = new CollectResult(command);
|
||||
collectResult.SetCollectAssets(package.GetAllCollectAssets(command));
|
||||
collectResultList.Add(collectResult);
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ namespace YooAsset.Editor
|
||||
List<Type> types = new List<Type>(100)
|
||||
{
|
||||
typeof(AddressByFileName),
|
||||
typeof(AddressByCollectorAndFileName),
|
||||
typeof(AddressByFolderAndFileName),
|
||||
typeof(AddressByGroupAndFileName)
|
||||
};
|
||||
|
||||
|
||||
@@ -594,14 +594,14 @@ namespace YooAsset.Editor
|
||||
var popupField = new PopupField<RuleDisplayName>(_addressRuleList, 0);
|
||||
popupField.name = "PopupField1";
|
||||
popupField.style.unityTextAlign = TextAnchor.MiddleLeft;
|
||||
popupField.style.width = 200;
|
||||
popupField.style.width = 220;
|
||||
elementBottom.Add(popupField);
|
||||
}
|
||||
{
|
||||
var popupField = new PopupField<RuleDisplayName>(_packRuleList, 0);
|
||||
popupField.name = "PopupField2";
|
||||
popupField.style.unityTextAlign = TextAnchor.MiddleLeft;
|
||||
popupField.style.width = 230;
|
||||
popupField.style.width = 220;
|
||||
elementBottom.Add(popupField);
|
||||
}
|
||||
{
|
||||
@@ -611,6 +611,15 @@ namespace YooAsset.Editor
|
||||
popupField.style.width = 150;
|
||||
elementBottom.Add(popupField);
|
||||
}
|
||||
{
|
||||
var textField = new TextField();
|
||||
textField.name = "TextField0";
|
||||
textField.label = "UserData";
|
||||
textField.style.width = 200;
|
||||
elementBottom.Add(textField);
|
||||
var label = textField.Q<Label>();
|
||||
label.style.minWidth = 63;
|
||||
}
|
||||
{
|
||||
var textField = new TextField();
|
||||
textField.name = "TextField1";
|
||||
@@ -750,6 +759,15 @@ namespace YooAsset.Editor
|
||||
}
|
||||
});
|
||||
|
||||
// UserData
|
||||
var textFiled0 = element.Q<TextField>("TextField0");
|
||||
textFiled0.SetValueWithoutNotify(collector.UserData);
|
||||
textFiled0.RegisterValueChangedCallback(evt =>
|
||||
{
|
||||
collector.UserData = evt.newValue;
|
||||
AssetBundleCollectorSettingData.ModifyCollector(selectGroup, collector);
|
||||
});
|
||||
|
||||
// Tags
|
||||
var textFiled1 = element.Q<TextField>("TextField1");
|
||||
textFiled1.SetValueWithoutNotify(collector.AssetTags);
|
||||
@@ -776,7 +794,7 @@ namespace YooAsset.Editor
|
||||
|
||||
try
|
||||
{
|
||||
CollectCommand command = new CollectCommand(EBuildMode.DryRunBuild, _enableAddressableToogle.value);
|
||||
CollectCommand command = new CollectCommand(EBuildMode.DryRunBuild, _packageNameTxt.value, _enableAddressableToogle.value, _uniqueBundleNameToogle.value);
|
||||
collectAssetInfos = collector.GetAllCollectAssets(command, group);
|
||||
}
|
||||
catch (System.Exception e)
|
||||
@@ -796,7 +814,7 @@ namespace YooAsset.Editor
|
||||
if (_enableAddressableToogle.value)
|
||||
{
|
||||
IAddressRule instance = AssetBundleCollectorSettingData.GetAddressRuleInstance(collector.AddressRuleName);
|
||||
AddressRuleData ruleData = new AddressRuleData(collectAssetInfo.AssetPath, collector.CollectPath, group.GroupName);
|
||||
AddressRuleData ruleData = new AddressRuleData(collectAssetInfo.AssetPath, collector.CollectPath, group.GroupName, collector.UserData);
|
||||
string addressValue = instance.GetAssetAddress(ruleData);
|
||||
showInfo = $"[{addressValue}] {showInfo}";
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace YooAsset.Editor
|
||||
/// 资源包名称
|
||||
/// </summary>
|
||||
public string BundleName { private set; get; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 可寻址地址
|
||||
/// </summary>
|
||||
@@ -25,30 +25,30 @@ namespace YooAsset.Editor
|
||||
/// </summary>
|
||||
public string AssetPath { private set; get; }
|
||||
|
||||
/// <summary>
|
||||
/// 资源分类标签
|
||||
/// </summary>
|
||||
public List<string> AssetTags { private set; get; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否为原生资源
|
||||
/// </summary>
|
||||
public bool IsRawAsset { private set; get; }
|
||||
|
||||
/// <summary>
|
||||
/// 资源分类标签
|
||||
/// </summary>
|
||||
public List<string> AssetTags { private set; get; }
|
||||
|
||||
/// <summary>
|
||||
/// 依赖的资源列表
|
||||
/// </summary>
|
||||
public List<string> DependAssets = new List<string>();
|
||||
|
||||
|
||||
public CollectAssetInfo(ECollectorType collectorType, string bundleName, string address, string assetPath, List<string> assetTags, bool isRawAsset)
|
||||
public CollectAssetInfo(ECollectorType collectorType, string bundleName, string address, string assetPath, bool isRawAsset, List<string> assetTags)
|
||||
{
|
||||
CollectorType = collectorType;
|
||||
BundleName = bundleName;
|
||||
Address = address;
|
||||
AssetPath = assetPath;
|
||||
AssetTags = assetTags;
|
||||
IsRawAsset = isRawAsset;
|
||||
AssetTags = assetTags;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,15 +8,27 @@ namespace YooAsset.Editor
|
||||
/// </summary>
|
||||
public EBuildMode BuildMode { private set; get; }
|
||||
|
||||
/// <summary>
|
||||
/// 包裹名称
|
||||
/// </summary>
|
||||
public string PackageName { private set; get; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否启用可寻址资源定位
|
||||
/// </summary>
|
||||
public bool EnableAddressable { private set; get; }
|
||||
|
||||
public CollectCommand(EBuildMode buildMode, bool enableAddressable)
|
||||
/// <summary>
|
||||
/// 资源包名唯一化
|
||||
/// </summary>
|
||||
public bool UniqueBundleName { private set; get; }
|
||||
|
||||
public CollectCommand(EBuildMode buildMode, string packageName, bool enableAddressable, bool uniqueBundleName)
|
||||
{
|
||||
BuildMode = buildMode;
|
||||
PackageName = packageName;
|
||||
EnableAddressable = enableAddressable;
|
||||
UniqueBundleName = uniqueBundleName;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,19 +6,14 @@ namespace YooAsset.Editor
|
||||
public class CollectResult
|
||||
{
|
||||
/// <summary>
|
||||
/// 包裹名称
|
||||
/// 收集命令
|
||||
/// </summary>
|
||||
public string PackageName { private set; get; }
|
||||
public CollectCommand Command { private set; get; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否启用可寻址资源定位
|
||||
/// 着色器统一全名称
|
||||
/// </summary>
|
||||
public bool EnableAddressable { private set; get; }
|
||||
|
||||
/// <summary>
|
||||
/// 资源包名唯一化
|
||||
/// </summary>
|
||||
public bool UniqueBundleName { private set; get; }
|
||||
public string ShadersBundleName { private set; get; }
|
||||
|
||||
/// <summary>
|
||||
/// 收集的资源信息列表
|
||||
@@ -26,11 +21,13 @@ namespace YooAsset.Editor
|
||||
public List<CollectAssetInfo> CollectAssets { private set; get; }
|
||||
|
||||
|
||||
public CollectResult(string packageName, bool enableAddressable, bool uniqueBundleName)
|
||||
public CollectResult(CollectCommand command)
|
||||
{
|
||||
PackageName = packageName;
|
||||
EnableAddressable = enableAddressable;
|
||||
UniqueBundleName = uniqueBundleName;
|
||||
Command = command;
|
||||
|
||||
// 着色器统一全名称
|
||||
var packRuleResult = DefaultPackRule.CreateShadersPackRuleResult();
|
||||
ShadersBundleName = packRuleResult.GetMainBundleName(command.PackageName, command.UniqueBundleName);
|
||||
}
|
||||
|
||||
public void SetCollectAssets(List<CollectAssetInfo> collectAssets)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace YooAsset.Editor
|
||||
{
|
||||
[DisplayName("以文件名称为定位地址")]
|
||||
[DisplayName("定位地址: 文件名")]
|
||||
public class AddressByFileName : IAddressRule
|
||||
{
|
||||
string IAddressRule.GetAssetAddress(AddressRuleData data)
|
||||
@@ -11,7 +11,7 @@ namespace YooAsset.Editor
|
||||
}
|
||||
}
|
||||
|
||||
[DisplayName("以分组名称+文件名称为定位地址")]
|
||||
[DisplayName("定位地址: 分组名+文件名")]
|
||||
public class AddressByGroupAndFileName : IAddressRule
|
||||
{
|
||||
string IAddressRule.GetAssetAddress(AddressRuleData data)
|
||||
@@ -21,8 +21,8 @@ namespace YooAsset.Editor
|
||||
}
|
||||
}
|
||||
|
||||
[DisplayName("以收集器名称+文件名称为定位地址")]
|
||||
public class AddressByCollectorAndFileName : IAddressRule
|
||||
[DisplayName("定位地址: 文件夹名+文件名")]
|
||||
public class AddressByFolderAndFileName : IAddressRule
|
||||
{
|
||||
string IAddressRule.GetAssetAddress(AddressRuleData data)
|
||||
{
|
||||
|
||||
@@ -4,6 +4,14 @@ using System.IO;
|
||||
|
||||
namespace YooAsset.Editor
|
||||
{
|
||||
public class DefaultFilterRule
|
||||
{
|
||||
/// <summary>
|
||||
/// 忽略的文件类型
|
||||
/// </summary>
|
||||
public static readonly string[] IgnoreFileExtensions = { "", ".so", ".dll", ".cs", ".js", ".boo", ".meta", ".cginc", ".hlsl" };
|
||||
}
|
||||
|
||||
[DisplayName("收集所有资源")]
|
||||
public class CollectAll : IFilterRule
|
||||
{
|
||||
|
||||
@@ -4,18 +4,50 @@ using UnityEditor;
|
||||
|
||||
namespace YooAsset.Editor
|
||||
{
|
||||
public class DefaultPackRule
|
||||
{
|
||||
/// <summary>
|
||||
/// AssetBundle文件的后缀名
|
||||
/// </summary>
|
||||
public const string AssetBundleFileExtension = "bundle";
|
||||
|
||||
/// <summary>
|
||||
/// 原生文件的后缀名
|
||||
/// </summary>
|
||||
public const string RawFileExtension = "rawfile";
|
||||
|
||||
/// <summary>
|
||||
/// Unity着色器资源包名称
|
||||
/// </summary>
|
||||
public const string ShadersBundleName = "unityshaders";
|
||||
|
||||
|
||||
public static PackRuleResult CreateShadersPackRuleResult()
|
||||
{
|
||||
PackRuleResult result = new PackRuleResult(ShadersBundleName, AssetBundleFileExtension);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 以文件路径作为资源包名
|
||||
/// 注意:每个文件独自打资源包
|
||||
/// 例如:"Assets/UIPanel/Shop/Image/backgroud.png" --> "assets_uipanel_shop_image_backgroud.bundle"
|
||||
/// 例如:"Assets/UIPanel/Shop/View/main.prefab" --> "assets_uipanel_shop_view_main.bundle"
|
||||
/// </summary>
|
||||
[DisplayName("以文件路径作为资源包名")]
|
||||
[DisplayName("资源包名: 文件路径")]
|
||||
public class PackSeparately : IPackRule
|
||||
{
|
||||
string IPackRule.GetBundleName(PackRuleData data)
|
||||
PackRuleResult IPackRule.GetPackRuleResult(PackRuleData data)
|
||||
{
|
||||
return StringUtility.RemoveExtension(data.AssetPath);
|
||||
string bundleName = StringUtility.RemoveExtension(data.AssetPath);
|
||||
PackRuleResult result = new PackRuleResult(bundleName, DefaultPackRule.AssetBundleFileExtension);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool IPackRule.IsRawFilePackRule()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,14 +57,21 @@ namespace YooAsset.Editor
|
||||
/// 例如:"Assets/UIPanel/Shop/Image/backgroud.png" --> "assets_uipanel_shop_image.bundle"
|
||||
/// 例如:"Assets/UIPanel/Shop/View/main.prefab" --> "assets_uipanel_shop_view.bundle"
|
||||
/// </summary>
|
||||
[DisplayName("以父类文件夹路径作为资源包名")]
|
||||
[DisplayName("资源包名: 父类文件夹路径")]
|
||||
public class PackDirectory : IPackRule
|
||||
{
|
||||
public static PackDirectory StaticPackRule = new PackDirectory();
|
||||
|
||||
string IPackRule.GetBundleName(PackRuleData data)
|
||||
PackRuleResult IPackRule.GetPackRuleResult(PackRuleData data)
|
||||
{
|
||||
return Path.GetDirectoryName(data.AssetPath);
|
||||
string bundleName = Path.GetDirectoryName(data.AssetPath);
|
||||
PackRuleResult result = new PackRuleResult(bundleName, DefaultPackRule.AssetBundleFileExtension);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool IPackRule.IsRawFilePackRule()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,10 +82,10 @@ namespace YooAsset.Editor
|
||||
/// 例如:"Assets/UIPanel/Shop/Image/backgroud.png" --> "assets_uipanel_shop.bundle"
|
||||
/// 例如:"Assets/UIPanel/Shop/View/main.prefab" --> "assets_uipanel_shop.bundle"
|
||||
/// </summary>
|
||||
[DisplayName("以收集器路径下顶级文件夹为资源包名")]
|
||||
[DisplayName("资源包名: 收集器下顶级文件夹路径")]
|
||||
public class PackTopDirectory : IPackRule
|
||||
{
|
||||
string IPackRule.GetBundleName(PackRuleData data)
|
||||
PackRuleResult IPackRule.GetPackRuleResult(PackRuleData data)
|
||||
{
|
||||
string assetPath = data.AssetPath.Replace(data.CollectPath, string.Empty);
|
||||
assetPath = assetPath.TrimStart('/');
|
||||
@@ -56,33 +95,48 @@ namespace YooAsset.Editor
|
||||
if (Path.HasExtension(splits[0]))
|
||||
throw new Exception($"Not found root directory : {assetPath}");
|
||||
string bundleName = $"{data.CollectPath}/{splits[0]}";
|
||||
return bundleName;
|
||||
PackRuleResult result = new PackRuleResult(bundleName, DefaultPackRule.AssetBundleFileExtension);
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception($"Not found root directory : {assetPath}");
|
||||
}
|
||||
}
|
||||
|
||||
bool IPackRule.IsRawFilePackRule()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 以收集器路径作为资源包名
|
||||
/// 注意:收集的所有文件打进一个资源包
|
||||
/// </summary>
|
||||
[DisplayName("以收集器路径作为资源包名")]
|
||||
[DisplayName("资源包名: 收集器路径")]
|
||||
public class PackCollector : IPackRule
|
||||
{
|
||||
string IPackRule.GetBundleName(PackRuleData data)
|
||||
PackRuleResult IPackRule.GetPackRuleResult(PackRuleData data)
|
||||
{
|
||||
string bundleName;
|
||||
string collectPath = data.CollectPath;
|
||||
if (AssetDatabase.IsValidFolder(collectPath))
|
||||
{
|
||||
return collectPath;
|
||||
bundleName = collectPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
return StringUtility.RemoveExtension(collectPath);
|
||||
bundleName = StringUtility.RemoveExtension(collectPath);
|
||||
}
|
||||
|
||||
PackRuleResult result = new PackRuleResult(bundleName, DefaultPackRule.AssetBundleFileExtension);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool IPackRule.IsRawFilePackRule()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,51 +144,55 @@ namespace YooAsset.Editor
|
||||
/// 以分组名称作为资源包名
|
||||
/// 注意:收集的所有文件打进一个资源包
|
||||
/// </summary>
|
||||
[DisplayName("以分组名称作为资源包名")]
|
||||
[DisplayName("资源包名: 分组名称")]
|
||||
public class PackGroup : IPackRule
|
||||
{
|
||||
string IPackRule.GetBundleName(PackRuleData data)
|
||||
PackRuleResult IPackRule.GetPackRuleResult(PackRuleData data)
|
||||
{
|
||||
return data.GroupName;
|
||||
string bundleName = data.GroupName;
|
||||
PackRuleResult result = new PackRuleResult(bundleName, DefaultPackRule.AssetBundleFileExtension);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool IPackRule.IsRawFilePackRule()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 打包原生文件
|
||||
/// 注意:原生文件打包支持:图片,音频,视频,文本
|
||||
/// </summary>
|
||||
[DisplayName("打包原生文件")]
|
||||
public class PackRawFile : IPackRule
|
||||
{
|
||||
string IPackRule.GetBundleName(PackRuleData data)
|
||||
PackRuleResult IPackRule.GetPackRuleResult(PackRuleData data)
|
||||
{
|
||||
string extension = StringUtility.RemoveFirstChar(Path.GetExtension(data.AssetPath));
|
||||
if (extension == EAssetFileExtension.unity.ToString() || extension == EAssetFileExtension.prefab.ToString() ||
|
||||
extension == EAssetFileExtension.mat.ToString() || extension == EAssetFileExtension.controller.ToString() ||
|
||||
extension == EAssetFileExtension.fbx.ToString() || extension == EAssetFileExtension.anim.ToString() ||
|
||||
extension == EAssetFileExtension.shader.ToString())
|
||||
{
|
||||
throw new Exception($"{nameof(PackRawFile)} is not support file estension : {extension}");
|
||||
}
|
||||
string bundleName = data.AssetPath;
|
||||
PackRuleResult result = new PackRuleResult(bundleName, DefaultPackRule.RawFileExtension);
|
||||
return result;
|
||||
}
|
||||
|
||||
// 注意:原生文件只支持无依赖关系的资源
|
||||
string[] depends = AssetDatabase.GetDependencies(data.AssetPath, true);
|
||||
if (depends.Length != 1)
|
||||
throw new Exception($"{nameof(PackRawFile)} is not support estension : {extension}");
|
||||
|
||||
return data.AssetPath;
|
||||
bool IPackRule.IsRawFilePackRule()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 打包着色器变种集合
|
||||
/// </summary>
|
||||
[DisplayName("打包着色器变种集合")]
|
||||
[DisplayName("打包着色器变种集合文件")]
|
||||
public class PackShaderVariants : IPackRule
|
||||
{
|
||||
public string GetBundleName(PackRuleData data)
|
||||
public PackRuleResult GetPackRuleResult(PackRuleData data)
|
||||
{
|
||||
return YooAssetSettings.UnityShadersBundleName;
|
||||
return DefaultPackRule.CreateShadersPackRuleResult();
|
||||
}
|
||||
|
||||
bool IPackRule.IsRawFilePackRule()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,12 +6,14 @@ namespace YooAsset.Editor
|
||||
public string AssetPath;
|
||||
public string CollectPath;
|
||||
public string GroupName;
|
||||
public string UserData;
|
||||
|
||||
public AddressRuleData(string assetPath, string collectPath, string groupName)
|
||||
public AddressRuleData(string assetPath, string collectPath, string groupName, string userData)
|
||||
{
|
||||
AssetPath = assetPath;
|
||||
CollectPath = collectPath;
|
||||
GroupName = groupName;
|
||||
UserData = userData;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,21 +3,64 @@ namespace YooAsset.Editor
|
||||
{
|
||||
public struct PackRuleData
|
||||
{
|
||||
public string AssetPath;
|
||||
public string AssetPath;
|
||||
public string CollectPath;
|
||||
public string GroupName;
|
||||
public string UserData;
|
||||
|
||||
public PackRuleData(string assetPath)
|
||||
{
|
||||
AssetPath = assetPath;
|
||||
CollectPath = string.Empty;
|
||||
GroupName = string.Empty;
|
||||
UserData = string.Empty;
|
||||
}
|
||||
public PackRuleData(string assetPath, string collectPath, string groupName)
|
||||
public PackRuleData(string assetPath, string collectPath, string groupName, string userData)
|
||||
{
|
||||
AssetPath = assetPath;
|
||||
CollectPath = collectPath;
|
||||
GroupName = groupName;
|
||||
UserData = userData;
|
||||
}
|
||||
}
|
||||
|
||||
public struct PackRuleResult
|
||||
{
|
||||
private readonly string _bundleName;
|
||||
private readonly string _bundleExtension;
|
||||
|
||||
public PackRuleResult(string bundleName, string bundleExtension)
|
||||
{
|
||||
_bundleName = bundleName;
|
||||
_bundleExtension = bundleExtension;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取主资源包全名称
|
||||
/// </summary>
|
||||
public string GetMainBundleName(string packageName, bool uniqueBundleName)
|
||||
{
|
||||
string fullName;
|
||||
string bundleName = EditorTools.GetRegularPath(_bundleName).Replace('/', '_').Replace('.', '_').ToLower();
|
||||
if (uniqueBundleName)
|
||||
fullName = $"{packageName}_{bundleName}.{_bundleExtension}";
|
||||
else
|
||||
fullName = $"{bundleName}.{_bundleExtension}";
|
||||
return fullName.ToLower();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取共享资源包全名称
|
||||
/// </summary>
|
||||
public string GetShareBundleName(string packageName, bool uniqueBundleName)
|
||||
{
|
||||
string fullName;
|
||||
string bundleName = EditorTools.GetRegularPath(_bundleName).Replace('/', '_').Replace('.', '_').ToLower();
|
||||
if (uniqueBundleName)
|
||||
fullName = $"{packageName}_share_{bundleName}.{_bundleExtension}";
|
||||
else
|
||||
fullName = $"share_{bundleName}.{_bundleExtension}";
|
||||
return fullName.ToLower();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,8 +70,13 @@ namespace YooAsset.Editor
|
||||
public interface IPackRule
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取资源打包所属的资源包名称
|
||||
/// 获取打包规则结果
|
||||
/// </summary>
|
||||
string GetBundleName(PackRuleData data);
|
||||
PackRuleResult GetPackRuleResult(PackRuleData data);
|
||||
|
||||
/// <summary>
|
||||
/// 是否为原生文件打包规则
|
||||
/// </summary>
|
||||
bool IsRawFilePackRule();
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" editor-extension-mode="False">
|
||||
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements">
|
||||
<ui:VisualElement name="TopGroup" style="flex-grow: 1; border-left-width: 1px; border-right-width: 1px; border-top-width: 1px; border-bottom-width: 1px; border-left-color: rgb(0, 0, 0); border-right-color: rgb(0, 0, 0); border-top-color: rgb(0, 0, 0); border-bottom-color: rgb(0, 0, 0); margin-left: 0; margin-right: 0; margin-top: 2px; margin-bottom: 1px; display: flex;">
|
||||
<uie:Toolbar name="TopBar" style="height: 25px; margin-left: 1px; margin-right: 1px;">
|
||||
<uie:ToolbarButton text="Asset Path" display-tooltip-when-elided="true" name="TopBar1" style="width: 280px; -unity-text-align: middle-left; flex-grow: 1;" />
|
||||
<uie:ToolbarButton text="Main Bundle" display-tooltip-when-elided="true" name="TopBar2" style="width: 145px; -unity-text-align: middle-left; flex-grow: 1;" />
|
||||
</uie:Toolbar>
|
||||
<ui:ListView focusable="true" name="TopListView" item-height="18" virtualization-method="DynamicHeight" style="flex-grow: 1;" />
|
||||
<ui:ListView focusable="true" name="TopListView" item-height="18" virtualization-method="DynamicHeight" style="flex-grow: 1; flex-basis: 60px;" />
|
||||
</ui:VisualElement>
|
||||
<ui:VisualElement name="BottomGroup" style="height: 200px; border-left-width: 1px; border-right-width: 1px; border-top-width: 1px; border-bottom-width: 1px; border-left-color: rgb(0, 0, 0); border-right-color: rgb(0, 0, 0); border-top-color: rgb(0, 0, 0); border-bottom-color: rgb(0, 0, 0); margin-left: 0; margin-right: 0; margin-top: 1px; margin-bottom: 1px; display: flex;">
|
||||
<uie:Toolbar name="BottomBar" style="height: 25px; margin-left: 1px; margin-right: 1px;">
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" editor-extension-mode="False">
|
||||
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements">
|
||||
<ui:VisualElement name="Viewer" style="flex-grow: 1; display: flex;">
|
||||
<ui:VisualElement name="TopGroup" style="flex-grow: 1; border-left-width: 1px; border-right-width: 1px; border-top-width: 1px; border-bottom-width: 1px; border-left-color: rgb(0, 0, 0); border-right-color: rgb(0, 0, 0); border-top-color: rgb(0, 0, 0); border-bottom-color: rgb(0, 0, 0); margin-left: 0; margin-right: 0; margin-top: 2px; margin-bottom: 1px; display: flex;">
|
||||
<uie:Toolbar name="TopBar" style="height: 25px; margin-left: 1px; margin-right: 1px;">
|
||||
@@ -8,7 +8,7 @@
|
||||
<uie:ToolbarButton text="LoadMethod" display-tooltip-when-elided="true" name="TopBar4" style="width: 150px; -unity-text-align: middle-left; flex-grow: 0;" />
|
||||
<uie:ToolbarButton text="Tags" display-tooltip-when-elided="true" name="TopBar5" style="width: 80px; -unity-text-align: middle-left; flex-grow: 1;" />
|
||||
</uie:Toolbar>
|
||||
<ui:ListView focusable="true" name="TopListView" item-height="18" virtualization-method="DynamicHeight" style="flex-grow: 1;" />
|
||||
<ui:ListView focusable="true" name="TopListView" item-height="18" virtualization-method="DynamicHeight" style="flex-grow: 1; flex-basis: 60px;" />
|
||||
</ui:VisualElement>
|
||||
<ui:VisualElement name="BottomGroup" style="height: 200px; border-left-width: 1px; border-right-width: 1px; border-top-width: 1px; border-bottom-width: 1px; border-left-color: rgb(0, 0, 0); border-right-color: rgb(0, 0, 0); border-top-color: rgb(0, 0, 0); border-bottom-color: rgb(0, 0, 0); margin-left: 0; margin-right: 0; margin-top: 1px; margin-bottom: 1px; display: flex;">
|
||||
<uie:Toolbar name="BottomBar" style="height: 25px; margin-left: 1px; margin-right: 1px;">
|
||||
|
||||
@@ -27,7 +27,6 @@ namespace YooAsset.Editor
|
||||
private TemplateContainer _root;
|
||||
|
||||
private ListView _listView;
|
||||
private BuildReport _buildReport;
|
||||
private readonly List<ItemWrapper> _items = new List<ItemWrapper>();
|
||||
|
||||
|
||||
@@ -55,14 +54,12 @@ namespace YooAsset.Editor
|
||||
/// </summary>
|
||||
public void FillViewData(BuildReport buildReport)
|
||||
{
|
||||
_buildReport = buildReport;
|
||||
|
||||
_items.Clear();
|
||||
|
||||
_items.Add(new ItemWrapper("YooAsset版本", buildReport.Summary.YooVersion));
|
||||
_items.Add(new ItemWrapper("引擎版本", buildReport.Summary.UnityVersion));
|
||||
_items.Add(new ItemWrapper("构建时间", buildReport.Summary.BuildDate));
|
||||
_items.Add(new ItemWrapper("构建耗时", $"{buildReport.Summary.BuildSeconds}秒"));
|
||||
_items.Add(new ItemWrapper("构建耗时", ConvertTime(buildReport.Summary.BuildSeconds)));
|
||||
_items.Add(new ItemWrapper("构建平台", $"{buildReport.Summary.BuildTarget}"));
|
||||
_items.Add(new ItemWrapper("构建管线", $"{buildReport.Summary.BuildPipeline}"));
|
||||
_items.Add(new ItemWrapper("构建模式", $"{buildReport.Summary.BuildMode}"));
|
||||
@@ -154,16 +151,23 @@ namespace YooAsset.Editor
|
||||
label2.text = itemWrapper.Value;
|
||||
}
|
||||
|
||||
private string ConvertTime(int time)
|
||||
{
|
||||
if (time <= 60)
|
||||
{
|
||||
return $"{time}秒钟";
|
||||
}
|
||||
else
|
||||
{
|
||||
int minute = time / 60;
|
||||
return $"{minute}分钟";
|
||||
}
|
||||
}
|
||||
private string ConvertSize(long size)
|
||||
{
|
||||
if (size == 0)
|
||||
return "0";
|
||||
if (size < 1024)
|
||||
return $"{size} Bytes";
|
||||
else if (size < 1024 * 1024)
|
||||
return $"{(int)(size / 1024)} KB";
|
||||
else
|
||||
return $"{(int)(size / (1024 * 1024))} MB";
|
||||
return EditorUtility.FormatBytes(size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,134 +12,169 @@ namespace YooAsset.Editor
|
||||
{
|
||||
public static class ShaderVariantCollector
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
Prepare,
|
||||
CollectAllMaterial,
|
||||
CollectVariants,
|
||||
CollectSleeping,
|
||||
WaitingDone,
|
||||
}
|
||||
|
||||
private const float WaitMilliseconds = 1000f;
|
||||
private static string _saveFilePath;
|
||||
private static bool _isStarted = false;
|
||||
private static readonly Stopwatch _elapsedTime = new Stopwatch();
|
||||
private const float SleepMilliseconds = 100f;
|
||||
private static string _savePath;
|
||||
private static string _packageName;
|
||||
private static int _processMaxNum;
|
||||
private static Action _completedCallback;
|
||||
|
||||
private static void EditorUpdate()
|
||||
{
|
||||
// 注意:一定要延迟保存才会起效
|
||||
if (_isStarted && _elapsedTime.ElapsedMilliseconds > WaitMilliseconds)
|
||||
{
|
||||
_isStarted = false;
|
||||
_elapsedTime.Stop();
|
||||
EditorApplication.update -= EditorUpdate;
|
||||
private static ESteps _steps = ESteps.None;
|
||||
private static Stopwatch _elapsedTime;
|
||||
private static List<string> _allMaterials;
|
||||
private static List<GameObject> _allSpheres = new List<GameObject>(1000);
|
||||
|
||||
// 保存结果
|
||||
ShaderVariantCollectionHelper.SaveCurrentShaderVariantCollection(_saveFilePath);
|
||||
|
||||
// 创建清单
|
||||
CreateManifest();
|
||||
|
||||
Debug.Log($"搜集SVC完毕!");
|
||||
_completedCallback?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 开始收集
|
||||
/// </summary>
|
||||
public static void Run(string saveFilePath, Action completedCallback)
|
||||
public static void Run(string savePath, string packageName, int processMaxNum, Action completedCallback)
|
||||
{
|
||||
if (_isStarted)
|
||||
if (_steps != ESteps.None)
|
||||
return;
|
||||
|
||||
if (Path.HasExtension(saveFilePath) == false)
|
||||
saveFilePath = $"{saveFilePath}.shadervariants";
|
||||
if (Path.GetExtension(saveFilePath) != ".shadervariants")
|
||||
if (Path.HasExtension(savePath) == false)
|
||||
savePath = $"{savePath}.shadervariants";
|
||||
if (Path.GetExtension(savePath) != ".shadervariants")
|
||||
throw new System.Exception("Shader variant file extension is invalid.");
|
||||
if (string.IsNullOrEmpty(packageName))
|
||||
throw new System.Exception("Package name is null or empty !");
|
||||
|
||||
// 注意:先删除再保存,否则ShaderVariantCollection内容将无法及时刷新
|
||||
AssetDatabase.DeleteAsset(ShaderVariantCollectorSettingData.Setting.SavePath);
|
||||
EditorTools.CreateFileDirectory(saveFilePath);
|
||||
_saveFilePath = saveFilePath;
|
||||
AssetDatabase.DeleteAsset(savePath);
|
||||
EditorTools.CreateFileDirectory(savePath);
|
||||
_savePath = savePath;
|
||||
_packageName = packageName;
|
||||
_processMaxNum = processMaxNum;
|
||||
_completedCallback = completedCallback;
|
||||
|
||||
// 聚焦到游戏窗口
|
||||
EditorTools.FocusUnityGameWindow();
|
||||
|
||||
// 清空旧数据
|
||||
ShaderVariantCollectionHelper.ClearCurrentShaderVariantCollection();
|
||||
|
||||
// 创建临时测试场景
|
||||
CreateTempScene();
|
||||
|
||||
// 收集着色器变种
|
||||
var materials = GetAllMaterials();
|
||||
CollectVariants(materials);
|
||||
|
||||
_steps = ESteps.Prepare;
|
||||
EditorApplication.update += EditorUpdate;
|
||||
_isStarted = true;
|
||||
_elapsedTime.Reset();
|
||||
_elapsedTime.Start();
|
||||
}
|
||||
|
||||
private static void EditorUpdate()
|
||||
{
|
||||
if (_steps == ESteps.None)
|
||||
return;
|
||||
|
||||
if (_steps == ESteps.Prepare)
|
||||
{
|
||||
ShaderVariantCollectionHelper.ClearCurrentShaderVariantCollection();
|
||||
_steps = ESteps.CollectAllMaterial;
|
||||
return; //等待一帧
|
||||
}
|
||||
|
||||
if (_steps == ESteps.CollectAllMaterial)
|
||||
{
|
||||
_allMaterials = GetAllMaterials();
|
||||
_steps = ESteps.CollectVariants;
|
||||
return; //等待一帧
|
||||
}
|
||||
|
||||
if (_steps == ESteps.CollectVariants)
|
||||
{
|
||||
int count = Mathf.Min(_processMaxNum, _allMaterials.Count);
|
||||
List<string> range = _allMaterials.GetRange(0, count);
|
||||
_allMaterials.RemoveRange(0, count);
|
||||
CollectVariants(range);
|
||||
|
||||
if (_allMaterials.Count > 0)
|
||||
{
|
||||
_elapsedTime = Stopwatch.StartNew();
|
||||
_steps = ESteps.CollectSleeping;
|
||||
}
|
||||
else
|
||||
{
|
||||
_elapsedTime = Stopwatch.StartNew();
|
||||
_steps = ESteps.WaitingDone;
|
||||
}
|
||||
}
|
||||
|
||||
if (_steps == ESteps.CollectSleeping)
|
||||
{
|
||||
if (_elapsedTime.ElapsedMilliseconds > SleepMilliseconds)
|
||||
{
|
||||
DestroyAllSpheres();
|
||||
_elapsedTime.Stop();
|
||||
_steps = ESteps.CollectVariants;
|
||||
}
|
||||
}
|
||||
|
||||
if (_steps == ESteps.WaitingDone)
|
||||
{
|
||||
// 注意:一定要延迟保存才会起效
|
||||
if (_elapsedTime.ElapsedMilliseconds > WaitMilliseconds)
|
||||
{
|
||||
_elapsedTime.Stop();
|
||||
_steps = ESteps.None;
|
||||
|
||||
// 保存结果并创建清单
|
||||
ShaderVariantCollectionHelper.SaveCurrentShaderVariantCollection(_savePath);
|
||||
CreateManifest();
|
||||
|
||||
Debug.Log($"搜集SVC完毕!");
|
||||
EditorApplication.update -= EditorUpdate;
|
||||
_completedCallback?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
private static void CreateTempScene()
|
||||
{
|
||||
EditorSceneManager.NewScene(NewSceneSetup.DefaultGameObjects);
|
||||
}
|
||||
private static List<Material> GetAllMaterials()
|
||||
private static List<string> GetAllMaterials()
|
||||
{
|
||||
int progressValue = 0;
|
||||
List<string> allAssets = new List<string>(1000);
|
||||
|
||||
// 获取所有打包的资源
|
||||
List<CollectAssetInfo> allCollectAssetInfos = new List<CollectAssetInfo>();
|
||||
List<CollectResult> collectResults = AssetBundleCollectorSettingData.Setting.GetAllPackageAssets(EBuildMode.DryRunBuild);
|
||||
foreach (var collectResult in collectResults)
|
||||
CollectResult collectResult = AssetBundleCollectorSettingData.Setting.GetPackageAssets(EBuildMode.DryRunBuild, _packageName);
|
||||
foreach (var assetInfo in collectResult.CollectAssets)
|
||||
{
|
||||
allCollectAssetInfos.AddRange(collectResult.CollectAssets);
|
||||
}
|
||||
List<string> allAssetPath = allCollectAssetInfos.Select(t => t.AssetPath).ToList();
|
||||
foreach (var assetPath in allAssetPath)
|
||||
{
|
||||
string[] depends = AssetDatabase.GetDependencies(assetPath, true);
|
||||
foreach (var depend in depends)
|
||||
string[] depends = AssetDatabase.GetDependencies(assetInfo.AssetPath, true);
|
||||
foreach (var dependAsset in depends)
|
||||
{
|
||||
if (allAssets.Contains(depend) == false)
|
||||
allAssets.Add(depend);
|
||||
if (allAssets.Contains(dependAsset) == false)
|
||||
allAssets.Add(dependAsset);
|
||||
}
|
||||
EditorTools.DisplayProgressBar("获取所有打包资源", ++progressValue, allAssetPath.Count);
|
||||
EditorTools.DisplayProgressBar("获取所有打包资源", ++progressValue, collectResult.CollectAssets.Count);
|
||||
}
|
||||
EditorTools.ClearProgressBar();
|
||||
|
||||
// 搜集所有材质球
|
||||
progressValue = 0;
|
||||
var shaderDic = new Dictionary<Shader, List<Material>>(100);
|
||||
List<string> allMaterial = new List<string>(1000);
|
||||
foreach (var assetPath in allAssets)
|
||||
{
|
||||
System.Type assetType = AssetDatabase.GetMainAssetTypeAtPath(assetPath);
|
||||
if (assetType == typeof(UnityEngine.Material))
|
||||
{
|
||||
var material = AssetDatabase.LoadAssetAtPath<Material>(assetPath);
|
||||
var shader = material.shader;
|
||||
if (shader == null)
|
||||
continue;
|
||||
|
||||
if (shaderDic.ContainsKey(shader) == false)
|
||||
{
|
||||
shaderDic.Add(shader, new List<Material>());
|
||||
}
|
||||
if (shaderDic[shader].Contains(material) == false)
|
||||
{
|
||||
shaderDic[shader].Add(material);
|
||||
}
|
||||
allMaterial.Add(assetPath);
|
||||
}
|
||||
EditorTools.DisplayProgressBar("搜集所有材质球", ++progressValue, allAssets.Count);
|
||||
}
|
||||
EditorTools.ClearProgressBar();
|
||||
|
||||
// 返回结果
|
||||
var materials = new List<Material>(1000);
|
||||
foreach (var valuePair in shaderDic)
|
||||
{
|
||||
materials.AddRange(valuePair.Value);
|
||||
}
|
||||
return materials;
|
||||
return allMaterial;
|
||||
}
|
||||
private static void CollectVariants(List<Material> materials)
|
||||
private static void CollectVariants(List<string> materials)
|
||||
{
|
||||
Camera camera = Camera.main;
|
||||
if (camera == null)
|
||||
@@ -164,7 +199,9 @@ namespace YooAsset.Editor
|
||||
{
|
||||
var material = materials[i];
|
||||
var position = new Vector3(x - halfWidth + 1f, y - halfHeight + 1f, 0f);
|
||||
CreateSphere(material, position, i);
|
||||
var go = CreateSphere(material, position, i);
|
||||
if (go != null)
|
||||
_allSpheres.Add(go);
|
||||
if (x == xMax)
|
||||
{
|
||||
x = 0;
|
||||
@@ -174,27 +211,44 @@ namespace YooAsset.Editor
|
||||
{
|
||||
x++;
|
||||
}
|
||||
EditorTools.DisplayProgressBar("测试所有材质球", ++progressValue, materials.Count);
|
||||
EditorTools.DisplayProgressBar("照射所有材质球", ++progressValue, materials.Count);
|
||||
}
|
||||
EditorTools.ClearProgressBar();
|
||||
}
|
||||
private static void CreateSphere(Material material, Vector3 position, int index)
|
||||
private static GameObject CreateSphere(string assetPath, Vector3 position, int index)
|
||||
{
|
||||
var material = AssetDatabase.LoadAssetAtPath<Material>(assetPath);
|
||||
var shader = material.shader;
|
||||
if (shader == null)
|
||||
return null;
|
||||
|
||||
var go = GameObject.CreatePrimitive(PrimitiveType.Sphere);
|
||||
go.GetComponent<Renderer>().material = material;
|
||||
go.GetComponent<Renderer>().sharedMaterial = material;
|
||||
go.transform.position = position;
|
||||
go.name = $"Sphere_{index}|{material.name}";
|
||||
go.name = $"Sphere_{index} | {material.name}";
|
||||
return go;
|
||||
}
|
||||
private static void DestroyAllSpheres()
|
||||
{
|
||||
foreach(var go in _allSpheres)
|
||||
{
|
||||
GameObject.DestroyImmediate(go);
|
||||
}
|
||||
_allSpheres.Clear();
|
||||
|
||||
// 尝试释放编辑器加载的资源
|
||||
EditorUtility.UnloadUnusedAssetsImmediate(true);
|
||||
}
|
||||
private static void CreateManifest()
|
||||
{
|
||||
AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate);
|
||||
|
||||
ShaderVariantCollection svc = AssetDatabase.LoadAssetAtPath<ShaderVariantCollection>(_saveFilePath);
|
||||
ShaderVariantCollection svc = AssetDatabase.LoadAssetAtPath<ShaderVariantCollection>(_savePath);
|
||||
if (svc != null)
|
||||
{
|
||||
var wrapper = ShaderVariantCollectionManifest.Extract(svc);
|
||||
string jsonData = JsonUtility.ToJson(wrapper, true);
|
||||
string savePath = _saveFilePath.Replace(".shadervariants", ".json");
|
||||
string savePath = _savePath.Replace(".shadervariants", ".json");
|
||||
File.WriteAllText(savePath, jsonData);
|
||||
}
|
||||
|
||||
|
||||
@@ -8,5 +8,10 @@ namespace YooAsset.Editor
|
||||
/// 文件存储路径
|
||||
/// </summary>
|
||||
public string SavePath = "Assets/MyShaderVariants.shadervariants";
|
||||
|
||||
/// <summary>
|
||||
/// 收集的包裹名称
|
||||
/// </summary>
|
||||
public string CollectPackage = string.Empty;
|
||||
}
|
||||
}
|
||||
@@ -18,10 +18,13 @@ namespace YooAsset.Editor
|
||||
window.minSize = new Vector2(800, 600);
|
||||
}
|
||||
|
||||
private List<string> _packageNames;
|
||||
|
||||
private Button _collectButton;
|
||||
private TextField _collectOutputField;
|
||||
private Label _currentShaderCountField;
|
||||
private Label _currentVariantCountField;
|
||||
private PopupField<string> _packageField;
|
||||
|
||||
public void CreateGUI()
|
||||
{
|
||||
@@ -36,6 +39,9 @@ namespace YooAsset.Editor
|
||||
|
||||
visualAsset.CloneTree(root);
|
||||
|
||||
// 包裹名称列表
|
||||
_packageNames = GetBuildPackageNames();
|
||||
|
||||
// 文件输出目录
|
||||
_collectOutputField = root.Q<TextField>("CollectOutput");
|
||||
_collectOutputField.SetValueWithoutNotify(ShaderVariantCollectorSettingData.Setting.SavePath);
|
||||
@@ -44,14 +50,34 @@ namespace YooAsset.Editor
|
||||
ShaderVariantCollectorSettingData.Setting.SavePath = _collectOutputField.value;
|
||||
});
|
||||
|
||||
// 收集的包裹
|
||||
var packageContainer = root.Q("PackageContainer");
|
||||
if (_packageNames.Count > 0)
|
||||
{
|
||||
int defaultIndex = GetDefaultPackageIndex(ShaderVariantCollectorSettingData.Setting.CollectPackage);
|
||||
_packageField = new PopupField<string>(_packageNames, defaultIndex);
|
||||
_packageField.label = "Package";
|
||||
_packageField.style.width = 350;
|
||||
_packageField.RegisterValueChangedCallback(evt =>
|
||||
{
|
||||
ShaderVariantCollectorSettingData.Setting.CollectPackage = _packageField.value;
|
||||
});
|
||||
packageContainer.Add(_packageField);
|
||||
}
|
||||
else
|
||||
{
|
||||
_packageField = new PopupField<string>();
|
||||
_packageField.label = "Package";
|
||||
_packageField.style.width = 350;
|
||||
packageContainer.Add(_packageField);
|
||||
}
|
||||
|
||||
_currentShaderCountField = root.Q<Label>("CurrentShaderCount");
|
||||
_currentVariantCountField = root.Q<Label>("CurrentVariantCount");
|
||||
|
||||
// 变种收集按钮
|
||||
_collectButton = root.Q<Button>("CollectButton");
|
||||
_collectButton.clicked += CollectButton_clicked;
|
||||
|
||||
//RefreshWindow();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@@ -75,7 +101,33 @@ namespace YooAsset.Editor
|
||||
|
||||
private void CollectButton_clicked()
|
||||
{
|
||||
ShaderVariantCollector.Run(ShaderVariantCollectorSettingData.Setting.SavePath, null);
|
||||
string savePath = ShaderVariantCollectorSettingData.Setting.SavePath;
|
||||
string packageName = ShaderVariantCollectorSettingData.Setting.CollectPackage;
|
||||
ShaderVariantCollector.Run(savePath, packageName, int.MaxValue, null);
|
||||
}
|
||||
|
||||
// 构建包裹相关
|
||||
private int GetDefaultPackageIndex(string packageName)
|
||||
{
|
||||
for (int index = 0; index < _packageNames.Count; index++)
|
||||
{
|
||||
if (_packageNames[index] == packageName)
|
||||
{
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
ShaderVariantCollectorSettingData.Setting.CollectPackage = _packageNames[0];
|
||||
return 0;
|
||||
}
|
||||
private List<string> GetBuildPackageNames()
|
||||
{
|
||||
List<string> result = new List<string>();
|
||||
foreach (var package in AssetBundleCollectorSettingData.Setting.Packages)
|
||||
{
|
||||
result.Add(package.PackageName);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" xsi="http://www.w3.org/2001/XMLSchema-instance" engine="UnityEngine.UIElements" editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../UIElementsSchema/UIElements.xsd" editor-extension-mode="True">
|
||||
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements">
|
||||
<uie:Toolbar name="Toolbar" style="display: flex; flex-direction: row-reverse;" />
|
||||
<ui:VisualElement name="BuildContainer">
|
||||
<ui:TextField picking-mode="Ignore" label="文件保存路径" name="CollectOutput" />
|
||||
<ui:Label text="Current Shader Count" display-tooltip-when-elided="true" name="CurrentShaderCount" />
|
||||
<ui:Label text="Current Variant Count" display-tooltip-when-elided="true" name="CurrentVariantCount" />
|
||||
<ui:VisualElement name="CollectContainer">
|
||||
<ui:TextField picking-mode="Ignore" label="文件保存路径" name="CollectOutput" style="height: 22px;" />
|
||||
<ui:VisualElement name="PackageContainer" style="height: 24px;" />
|
||||
<ui:Label text="Current Shader Count" display-tooltip-when-elided="true" name="CurrentShaderCount" style="height: 20px; padding-left: 4px;" />
|
||||
<ui:Label text="Current Variant Count" display-tooltip-when-elided="true" name="CurrentVariantCount" style="height: 20px; padding-left: 4px;" />
|
||||
<ui:Button text="开始搜集" display-tooltip-when-elided="true" name="CollectButton" style="height: 50px; background-color: rgb(40, 106, 42); margin-top: 10px;" />
|
||||
</ui:VisualElement>
|
||||
</ui:UXML>
|
||||
|
||||
8
Assets/YooAsset/Runtime/AssetReference.cs
Normal file
8
Assets/YooAsset/Runtime/AssetReference.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
public class AssetReference
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3d400b2548d79ca42bec7370f5d66b78
|
||||
guid: 1534f1a1b207ad542bf1fc73da8b4316
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
@@ -341,6 +341,14 @@ namespace YooAsset
|
||||
_providers.Remove(provider);
|
||||
}
|
||||
}
|
||||
internal bool CheckBundleCanDestroy(int bundleID)
|
||||
{
|
||||
string bundleName = BundleServices.GetBundleName(bundleID);
|
||||
BundleLoaderBase loader = TryGetAssetBundleLoader(bundleName);
|
||||
if (loader == null)
|
||||
return true;
|
||||
return loader.CanDestroy();
|
||||
}
|
||||
|
||||
private BundleLoaderBase CreateAssetBundleLoaderInternal(BundleInfo bundleInfo)
|
||||
{
|
||||
@@ -351,7 +359,10 @@ namespace YooAsset
|
||||
|
||||
// 新增下载需求
|
||||
#if UNITY_WEBGL
|
||||
loader = new AssetBundleWebLoader(this, bundleInfo);
|
||||
if (bundleInfo.Bundle.IsRawFile)
|
||||
loader = new RawBundleFileLoader(this, bundleInfo);
|
||||
else
|
||||
loader = new AssetBundleWebLoader(this, bundleInfo);
|
||||
#else
|
||||
if (bundleInfo.Bundle.IsRawFile)
|
||||
loader = new RawBundleFileLoader(this, bundleInfo);
|
||||
|
||||
@@ -46,7 +46,7 @@ namespace YooAsset
|
||||
if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromRemote)
|
||||
{
|
||||
_steps = ESteps.Download;
|
||||
FileLoadPath = MainBundleInfo.Bundle.CachedFilePath;
|
||||
FileLoadPath = MainBundleInfo.Bundle.CachedDataFilePath;
|
||||
}
|
||||
else if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromStreaming)
|
||||
{
|
||||
@@ -55,7 +55,7 @@ namespace YooAsset
|
||||
if (loadMethod == EBundleLoadMethod.LoadFromMemory || loadMethod == EBundleLoadMethod.LoadFromStream)
|
||||
{
|
||||
_steps = ESteps.Unpack;
|
||||
FileLoadPath = MainBundleInfo.Bundle.CachedFilePath;
|
||||
FileLoadPath = MainBundleInfo.Bundle.CachedDataFilePath;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -70,7 +70,7 @@ namespace YooAsset
|
||||
else if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromCache)
|
||||
{
|
||||
_steps = ESteps.LoadFile;
|
||||
FileLoadPath = MainBundleInfo.Bundle.CachedFilePath;
|
||||
FileLoadPath = MainBundleInfo.Bundle.CachedDataFilePath;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -110,7 +110,7 @@ namespace YooAsset
|
||||
if (_steps == ESteps.Unpack)
|
||||
{
|
||||
int failedTryAgain = 1;
|
||||
var bundleInfo = HostPlayModeImpl.ConvertToUnpackInfo(MainBundleInfo.Bundle);
|
||||
var bundleInfo = PatchManifestTools.GetUnpackInfo(MainBundleInfo.Bundle);
|
||||
_unpacker = DownloadSystem.BeginDownload(bundleInfo, failedTryAgain);
|
||||
_steps = ESteps.CheckUnpack;
|
||||
}
|
||||
@@ -242,14 +242,11 @@ namespace YooAsset
|
||||
// 在AssetBundle文件加载失败的情况下,我们需要重新验证文件的完整性!
|
||||
if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromCache)
|
||||
{
|
||||
string cacheLoadPath = MainBundleInfo.Bundle.CachedFilePath;
|
||||
if (CacheSystem.VerifyBundle(MainBundleInfo.Bundle, EVerifyLevel.High) != EVerifyResult.Succeed)
|
||||
var result = CacheSystem.VerifyingRecordFile(MainBundleInfo.Bundle.PackageName, MainBundleInfo.Bundle.CacheGUID);
|
||||
if (result != EVerifyResult.Succeed)
|
||||
{
|
||||
if (File.Exists(cacheLoadPath))
|
||||
{
|
||||
YooLogger.Error($"Delete the invalid cache file : {cacheLoadPath}");
|
||||
File.Delete(cacheLoadPath);
|
||||
}
|
||||
YooLogger.Error($"Found possibly corrupt file ! {MainBundleInfo.Bundle.CacheGUID}");
|
||||
CacheSystem.DiscardFile(MainBundleInfo.Bundle.PackageName, MainBundleInfo.Bundle.CacheGUID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ namespace YooAsset
|
||||
if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromRemote)
|
||||
{
|
||||
_steps = ESteps.Download;
|
||||
FileLoadPath = MainBundleInfo.Bundle.CachedFilePath;
|
||||
FileLoadPath = MainBundleInfo.Bundle.CachedDataFilePath;
|
||||
}
|
||||
else if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromStreaming)
|
||||
{
|
||||
@@ -57,7 +57,7 @@ namespace YooAsset
|
||||
else if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromCache)
|
||||
{
|
||||
_steps = ESteps.LoadCacheFile;
|
||||
FileLoadPath = MainBundleInfo.Bundle.CachedFilePath;
|
||||
FileLoadPath = MainBundleInfo.Bundle.CachedDataFilePath;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -147,14 +147,11 @@ namespace YooAsset
|
||||
// 在AssetBundle文件加载失败的情况下,我们需要重新验证文件的完整性!
|
||||
if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromCache)
|
||||
{
|
||||
string cacheLoadPath = MainBundleInfo.Bundle.CachedFilePath;
|
||||
if (CacheSystem.VerifyBundle(MainBundleInfo.Bundle, EVerifyLevel.High) != EVerifyResult.Succeed)
|
||||
var result = CacheSystem.VerifyingRecordFile(MainBundleInfo.Bundle.PackageName, MainBundleInfo.Bundle.CacheGUID);
|
||||
if (result != EVerifyResult.Succeed)
|
||||
{
|
||||
if (File.Exists(cacheLoadPath))
|
||||
{
|
||||
YooLogger.Error($"Delete the invalid cache file : {cacheLoadPath}");
|
||||
File.Delete(cacheLoadPath);
|
||||
}
|
||||
YooLogger.Error($"Found possibly corrupt file ! {MainBundleInfo.Bundle.CacheGUID}");
|
||||
CacheSystem.DiscardFile(MainBundleInfo.Bundle.PackageName, MainBundleInfo.Bundle.CacheGUID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,6 +122,15 @@ namespace YooAsset
|
||||
if (RefCount > _providers.Count)
|
||||
return;
|
||||
|
||||
// 条件3:检查依赖链上的资源包
|
||||
// 依赖该资源包的所有资源包可以销毁
|
||||
// 注意:互相引用的资源包无法卸载!
|
||||
foreach (var bundleID in MainBundleInfo.Bundle.ReferenceIDs)
|
||||
{
|
||||
if (Impl.CheckBundleCanDestroy(bundleID) == false)
|
||||
return;
|
||||
}
|
||||
|
||||
// 销毁所有Providers
|
||||
foreach (var provider in _providers)
|
||||
{
|
||||
|
||||
@@ -38,13 +38,13 @@ namespace YooAsset
|
||||
if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromRemote)
|
||||
{
|
||||
_steps = ESteps.Download;
|
||||
FileLoadPath = MainBundleInfo.Bundle.CachedFilePath;
|
||||
FileLoadPath = MainBundleInfo.Bundle.CachedDataFilePath;
|
||||
}
|
||||
else if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromStreaming)
|
||||
{
|
||||
#if UNITY_ANDROID || UNITY_WEBGL
|
||||
_steps = ESteps.Unpack;
|
||||
FileLoadPath = MainBundleInfo.Bundle.CachedFilePath;
|
||||
FileLoadPath = MainBundleInfo.Bundle.CachedDataFilePath;
|
||||
#else
|
||||
_steps = ESteps.CheckFile;
|
||||
FileLoadPath = MainBundleInfo.Bundle.StreamingFilePath;
|
||||
@@ -53,7 +53,7 @@ namespace YooAsset
|
||||
else if (MainBundleInfo.LoadMode == BundleInfo.ELoadMode.LoadFromCache)
|
||||
{
|
||||
_steps = ESteps.CheckFile;
|
||||
FileLoadPath = MainBundleInfo.Bundle.CachedFilePath;
|
||||
FileLoadPath = MainBundleInfo.Bundle.CachedDataFilePath;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -93,7 +93,7 @@ namespace YooAsset
|
||||
if (_steps == ESteps.Unpack)
|
||||
{
|
||||
int failedTryAgain = 1;
|
||||
var bundleInfo = HostPlayModeImpl.ConvertToUnpackInfo(MainBundleInfo.Bundle);
|
||||
var bundleInfo = PatchManifestTools.GetUnpackInfo(MainBundleInfo.Bundle);
|
||||
_unpacker = DownloadSystem.BeginDownload(bundleInfo, failedTryAgain);
|
||||
_steps = ESteps.CheckUnpack;
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ namespace YooAsset
|
||||
result.TotalSize += (ulong)dependBundle.MainBundleInfo.Bundle.FileSize;
|
||||
result.DownloadedBytes += dependBundle.DownloadedBytes;
|
||||
}
|
||||
result.Progress = result.DownloadedBytes / result.TotalSize;
|
||||
result.Progress = (float)result.DownloadedBytes / result.TotalSize;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -228,7 +228,7 @@ namespace YooAsset
|
||||
List<OperationHandleBase> tempers = new List<OperationHandleBase>(_handles);
|
||||
foreach (var hande in tempers)
|
||||
{
|
||||
if (hande.IsValidWithWarning)
|
||||
if (hande.IsValid)
|
||||
{
|
||||
hande.InvokeCallback();
|
||||
}
|
||||
|
||||
@@ -229,15 +229,6 @@ namespace YooAsset
|
||||
return _playModeServices.PreDownloadPackageAsync(packageVersion, timeout);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查包裹内容的完整性
|
||||
/// </summary>
|
||||
public CheckPackageContentsOperation CheckPackageContentsAsync(string packageVersion)
|
||||
{
|
||||
DebugCheckInitialize();
|
||||
return _playModeServices.CheckPackageContentsOperation(packageVersion);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清理包裹未使用的缓存文件
|
||||
/// </summary>
|
||||
@@ -731,12 +722,12 @@ namespace YooAsset
|
||||
/// <summary>
|
||||
/// 是否包含资源文件
|
||||
/// </summary>
|
||||
internal bool IsIncludeBundleFile(string fileName)
|
||||
internal bool IsIncludeBundleFile(string cacheGUID)
|
||||
{
|
||||
// NOTE : 编辑器模拟模式下始终返回TRUE
|
||||
if (_playMode == EPlayMode.EditorSimulateMode)
|
||||
return true;
|
||||
return _playModeServices.ActiveManifest.IsIncludeBundleFile(fileName);
|
||||
return _playModeServices.ActiveManifest.IsIncludeBundleFile(cacheGUID);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
36
Assets/YooAsset/Runtime/CacheSystem/CacheFileInfo.cs
Normal file
36
Assets/YooAsset/Runtime/CacheSystem/CacheFileInfo.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
internal class CacheFileInfo
|
||||
{
|
||||
private static readonly BufferWriter SharedBuffer = new BufferWriter(1024);
|
||||
|
||||
/// <summary>
|
||||
/// 写入资源包信息
|
||||
/// </summary>
|
||||
public static void WriteInfoToFile(string filePath, string dataFileCRC, long dataFileSize)
|
||||
{
|
||||
using (FileStream fs = new FileStream(filePath, FileMode.Create))
|
||||
{
|
||||
SharedBuffer.Clear();
|
||||
SharedBuffer.WriteUTF8(dataFileCRC);
|
||||
SharedBuffer.WriteInt64(dataFileSize);
|
||||
SharedBuffer.WriteToStream(fs);
|
||||
fs.Flush();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 读取资源包信息
|
||||
/// </summary>
|
||||
public static void ReadInfoFromFile(string filePath, out string dataFileCRC, out long dataFileSize)
|
||||
{
|
||||
byte[] binaryData = FileUtility.ReadAllBytes(filePath);
|
||||
BufferReader buffer = new BufferReader(binaryData);
|
||||
dataFileCRC = buffer.ReadUTF8();
|
||||
dataFileSize = buffer.ReadInt64();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 12bc032fc47a6c34fb90f0f4a48f4441
|
||||
timeCreated: 1506516969
|
||||
licenseType: Pro
|
||||
guid: e4a97c06e069c1146a881fcb359f9b4b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
@@ -2,18 +2,18 @@
|
||||
using System.IO;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
internal static class CacheSystem
|
||||
{
|
||||
private readonly static Dictionary<string, PatchBundle> _cachedDic = new Dictionary<string, PatchBundle>(1000);
|
||||
private readonly static Dictionary<string, PackageCache> _cachedDic = new Dictionary<string, PackageCache>(1000);
|
||||
|
||||
/// <summary>
|
||||
/// 初始化时的验证级别
|
||||
/// </summary>
|
||||
public static EVerifyLevel InitVerifyLevel { set; get; } = EVerifyLevel.Low;
|
||||
|
||||
public static EVerifyLevel InitVerifyLevel { set; get; } = EVerifyLevel.Middle;
|
||||
|
||||
/// <summary>
|
||||
/// 清空所有数据
|
||||
@@ -25,103 +25,127 @@ namespace YooAsset
|
||||
|
||||
/// <summary>
|
||||
/// 查询是否为验证文件
|
||||
/// 注意:被收录的文件完整性是绝对有效的
|
||||
/// </summary>
|
||||
public static bool IsCached(PatchBundle patchBundle)
|
||||
public static bool IsCached(string packageName, string cacheGUID)
|
||||
{
|
||||
string cacheKey = patchBundle.CacheKey;
|
||||
if (_cachedDic.ContainsKey(cacheKey))
|
||||
var cache = GetOrCreateCache(packageName);
|
||||
return cache.IsCached(cacheGUID);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 录入验证的文件
|
||||
/// </summary>
|
||||
public static void RecordFile(string packageName, string cacheGUID, PackageCache.RecordWrapper wrapper)
|
||||
{
|
||||
//YooLogger.Log($"Record file : {packageName} = {cacheGUID}");
|
||||
var cache = GetOrCreateCache(packageName);
|
||||
cache.Record(cacheGUID, wrapper);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 丢弃验证的文件(同时删除文件)
|
||||
/// </summary>
|
||||
public static void DiscardFile(string packageName, string cacheGUID)
|
||||
{
|
||||
var cache = GetOrCreateCache(packageName);
|
||||
var wrapper = cache.TryGetWrapper(cacheGUID);
|
||||
if (wrapper == null)
|
||||
return;
|
||||
|
||||
cache.Discard(cacheGUID);
|
||||
|
||||
try
|
||||
{
|
||||
string filePath = patchBundle.CachedFilePath;
|
||||
if (File.Exists(filePath))
|
||||
string dataFilePath = wrapper.DataFilePath;
|
||||
FileInfo fileInfo = new FileInfo(dataFilePath);
|
||||
if (fileInfo.Exists)
|
||||
fileInfo.Directory.Delete(true);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
YooLogger.Error($"Failed to delete cache file ! {e.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 验证缓存文件(子线程内操作)
|
||||
/// </summary>
|
||||
public static EVerifyResult VerifyingCacheFile(VerifyElement element)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (InitVerifyLevel == EVerifyLevel.Low)
|
||||
{
|
||||
return true;
|
||||
if (File.Exists(element.InfoFilePath) == false)
|
||||
return EVerifyResult.InfoFileNotExisted;
|
||||
if (File.Exists(element.DataFilePath) == false)
|
||||
return EVerifyResult.DataFileNotExisted;
|
||||
return EVerifyResult.Succeed;
|
||||
}
|
||||
else
|
||||
{
|
||||
_cachedDic.Remove(cacheKey);
|
||||
YooLogger.Error($"Cache file is missing : {filePath}");
|
||||
return false;
|
||||
if (File.Exists(element.InfoFilePath) == false)
|
||||
return EVerifyResult.InfoFileNotExisted;
|
||||
|
||||
// 解析信息文件获取验证数据
|
||||
CacheFileInfo.ReadInfoFromFile(element.InfoFilePath, out element.DataFileCRC, out element.DataFileSize);
|
||||
}
|
||||
}
|
||||
else
|
||||
catch (Exception)
|
||||
{
|
||||
return false;
|
||||
return EVerifyResult.Exception;
|
||||
}
|
||||
|
||||
return VerifyingInternal(element.DataFilePath, element.DataFileSize, element.DataFileCRC, InitVerifyLevel);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 缓存补丁包文件
|
||||
/// 验证下载文件
|
||||
/// </summary>
|
||||
public static void CacheBundle(PatchBundle patchBundle)
|
||||
public static EVerifyResult VerifyingTempFile(PatchBundle patchBundle)
|
||||
{
|
||||
string cacheKey = patchBundle.CacheKey;
|
||||
if (_cachedDic.ContainsKey(cacheKey) == false)
|
||||
return VerifyingInternal(patchBundle.TempDataFilePath, patchBundle.FileSize, patchBundle.FileCRC, EVerifyLevel.High);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 验证记录文件
|
||||
/// </summary>
|
||||
public static EVerifyResult VerifyingRecordFile(string packageName, string cacheGUID)
|
||||
{
|
||||
var cache = GetOrCreateCache(packageName);
|
||||
var wrapper = cache.TryGetWrapper(cacheGUID);
|
||||
if (wrapper == null)
|
||||
return EVerifyResult.CacheNotFound;
|
||||
|
||||
EVerifyResult result = VerifyingInternal(wrapper.DataFilePath, wrapper.DataFileSize, wrapper.DataFileCRC, EVerifyLevel.High);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取未被使用的缓存文件
|
||||
/// </summary>
|
||||
public static List<string> GetUnusedCacheGUIDs(AssetsPackage package)
|
||||
{
|
||||
var cache = GetOrCreateCache(package.PackageName);
|
||||
var keys = cache.GetAllKeys();
|
||||
List<string> result = new List<string>(keys.Count);
|
||||
foreach (var cacheGUID in keys)
|
||||
{
|
||||
string filePath = patchBundle.CachedFilePath;
|
||||
YooLogger.Log($"Cache verify file : {filePath}");
|
||||
_cachedDic.Add(cacheKey, 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 VerifyAndCacheLocalBundleFile(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 VerifyAndCacheDownloadBundleFile(string tempFilePath, PatchBundle patchBundle, EVerifyLevel verifyLevel)
|
||||
{
|
||||
var verifyResult = VerifyContentInternal(tempFilePath, patchBundle.FileSize, patchBundle.FileCRC, verifyLevel);
|
||||
if (verifyResult == EVerifyResult.Succeed)
|
||||
{
|
||||
try
|
||||
if (package.IsIncludeBundleFile(cacheGUID) == false)
|
||||
{
|
||||
string destFilePath = patchBundle.CachedFilePath;
|
||||
if (File.Exists(destFilePath))
|
||||
File.Delete(destFilePath);
|
||||
|
||||
FileInfo fileInfo = new FileInfo(tempFilePath);
|
||||
fileInfo.MoveTo(destFilePath);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
verifyResult = EVerifyResult.FileMoveFailed;
|
||||
}
|
||||
|
||||
if (verifyResult == EVerifyResult.Succeed)
|
||||
{
|
||||
CacheBundle(patchBundle);
|
||||
result.Add(cacheGUID);
|
||||
}
|
||||
}
|
||||
return verifyResult;
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 验证文件完整性
|
||||
/// </summary>
|
||||
private static EVerifyResult VerifyContentInternal(string filePath, long fileSize, string fileCRC, EVerifyLevel verifyLevel)
|
||||
|
||||
private static EVerifyResult VerifyingInternal(string filePath, long fileSize, string fileCRC, EVerifyLevel verifyLevel)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (File.Exists(filePath) == false)
|
||||
return EVerifyResult.FileNotExisted;
|
||||
return EVerifyResult.DataFileNotExisted;
|
||||
|
||||
// 先验证文件大小
|
||||
long size = FileUtility.GetFileSize(filePath);
|
||||
@@ -149,5 +173,14 @@ namespace YooAsset
|
||||
return EVerifyResult.Exception;
|
||||
}
|
||||
}
|
||||
private static PackageCache GetOrCreateCache(string packageName)
|
||||
{
|
||||
if (_cachedDic.TryGetValue(packageName, out PackageCache cache) == false)
|
||||
{
|
||||
cache = new PackageCache(packageName);
|
||||
_cachedDic.Add(packageName, cache);
|
||||
}
|
||||
return cache;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,10 +7,15 @@ namespace YooAsset
|
||||
public enum EVerifyLevel
|
||||
{
|
||||
/// <summary>
|
||||
/// 验证文件大小
|
||||
/// 验证文件存在
|
||||
/// </summary>
|
||||
Low,
|
||||
|
||||
/// <summary>
|
||||
/// 验证文件大小
|
||||
/// </summary>
|
||||
Middle,
|
||||
|
||||
/// <summary>
|
||||
/// 验证文件大小和CRC
|
||||
/// </summary>
|
||||
|
||||
@@ -7,14 +7,19 @@ namespace YooAsset
|
||||
internal enum EVerifyResult
|
||||
{
|
||||
/// <summary>
|
||||
/// 文件不存在
|
||||
/// 未找到缓存信息
|
||||
/// </summary>
|
||||
FileNotExisted = -5,
|
||||
CacheNotFound = -6,
|
||||
|
||||
/// <summary>
|
||||
/// 文件移动失败(重命名失败)
|
||||
/// 信息文件不存在
|
||||
/// </summary>
|
||||
FileMoveFailed = -4,
|
||||
InfoFileNotExisted = -5,
|
||||
|
||||
/// <summary>
|
||||
/// 数据文件不存在
|
||||
/// </summary>
|
||||
DataFileNotExisted = -4,
|
||||
|
||||
/// <summary>
|
||||
/// 文件内容不足(小于正常大小)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 89357359fd1b3f74fa7cb048a1ffa2b6
|
||||
guid: d29a9623b2b346e439b7a7e37fafa781
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
@@ -0,0 +1,71 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 清理本地包裹未使用的缓存文件
|
||||
/// </summary>
|
||||
public sealed class ClearUnusedCacheFilesOperation : AsyncOperationBase
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
GetUnusedCacheFiles,
|
||||
ClearUnusedCacheFiles,
|
||||
Done,
|
||||
}
|
||||
|
||||
private readonly AssetsPackage _package;
|
||||
private List<string> _unusedCacheGUIDs;
|
||||
private int _unusedFileTotalCount = 0;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
internal ClearUnusedCacheFilesOperation(AssetsPackage package)
|
||||
{
|
||||
_package = package;
|
||||
}
|
||||
internal override void Start()
|
||||
{
|
||||
_steps = ESteps.GetUnusedCacheFiles;
|
||||
}
|
||||
internal override void Update()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
if (_steps == ESteps.GetUnusedCacheFiles)
|
||||
{
|
||||
_unusedCacheGUIDs = CacheSystem.GetUnusedCacheGUIDs(_package);
|
||||
_unusedFileTotalCount = _unusedCacheGUIDs.Count;
|
||||
YooLogger.Log($"Found unused cache file count : {_unusedFileTotalCount}");
|
||||
_steps = ESteps.ClearUnusedCacheFiles;
|
||||
}
|
||||
|
||||
if (_steps == ESteps.ClearUnusedCacheFiles)
|
||||
{
|
||||
for (int i = _unusedCacheGUIDs.Count - 1; i >= 0; i--)
|
||||
{
|
||||
string cacheGUID = _unusedCacheGUIDs[i];
|
||||
CacheSystem.DiscardFile(_package.PackageName, cacheGUID);
|
||||
_unusedCacheGUIDs.RemoveAt(i);
|
||||
|
||||
if (OperationSystem.IsBusy)
|
||||
break;
|
||||
}
|
||||
|
||||
if (_unusedFileTotalCount == 0)
|
||||
Progress = 1.0f;
|
||||
else
|
||||
Progress = 1.0f - (_unusedCacheGUIDs.Count / _unusedFileTotalCount);
|
||||
|
||||
if (_unusedCacheGUIDs.Count == 0)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Succeed;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
internal class PackageCachingOperation : AsyncOperationBase
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
GetCacheFiles,
|
||||
VerifyCacheFiles,
|
||||
Done,
|
||||
}
|
||||
|
||||
private readonly string _packageName;
|
||||
private PackageVerifyOperation _packageVerifyOp;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
public PackageCachingOperation(string packageName)
|
||||
{
|
||||
_packageName = packageName;
|
||||
}
|
||||
internal override void Start()
|
||||
{
|
||||
_steps = ESteps.GetCacheFiles;
|
||||
}
|
||||
internal override void Update()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
if (_steps == ESteps.GetCacheFiles)
|
||||
{
|
||||
var elements = GetVerifyElements();
|
||||
_packageVerifyOp = PackageVerifyOperation.CreateOperation(elements);
|
||||
OperationSystem.StartOperation(_packageVerifyOp);
|
||||
_steps = ESteps.VerifyCacheFiles;
|
||||
}
|
||||
|
||||
if (_steps == ESteps.VerifyCacheFiles)
|
||||
{
|
||||
Progress = _packageVerifyOp.Progress;
|
||||
if (_packageVerifyOp.IsDone == false)
|
||||
return;
|
||||
|
||||
// 注意:总是返回成功
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Succeed;
|
||||
}
|
||||
}
|
||||
|
||||
private List<VerifyElement> GetVerifyElements()
|
||||
{
|
||||
string cacheFolderPath = PersistentHelper.GetCacheFolderPath(_packageName);
|
||||
if (Directory.Exists(cacheFolderPath) == false)
|
||||
return new List<VerifyElement>();
|
||||
|
||||
DirectoryInfo rootDirectory = new DirectoryInfo(cacheFolderPath);
|
||||
DirectoryInfo[] fileFolders = rootDirectory.GetDirectories();
|
||||
List<VerifyElement> result = new List<VerifyElement>(fileFolders.Length);
|
||||
foreach (var fileFoder in fileFolders)
|
||||
{
|
||||
string cacheGUID = fileFoder.Name;
|
||||
if (CacheSystem.IsCached(_packageName, cacheGUID))
|
||||
continue;
|
||||
|
||||
// 获取数据文件的后缀名
|
||||
string dataFileExtension = string.Empty;
|
||||
var fileInfos = fileFoder.GetFiles();
|
||||
foreach (var fileInfo in fileInfos)
|
||||
{
|
||||
if (fileInfo.Extension == ".temp")
|
||||
continue;
|
||||
|
||||
if (fileInfo.Name.StartsWith(YooAssetSettings.CacheBundleDataFileName))
|
||||
{
|
||||
dataFileExtension = fileInfo.Extension;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
string fileRootPath = fileFoder.FullName;
|
||||
string dataFilePath = $"{fileRootPath}/{ YooAssetSettings.CacheBundleDataFileName}{dataFileExtension}";
|
||||
string infoFilePath = $"{fileRootPath}/{ YooAssetSettings.CacheBundleInfoFileName}";
|
||||
VerifyElement element = new VerifyElement(_packageName, cacheGUID, fileRootPath, dataFilePath, infoFilePath);
|
||||
result.Add(element);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 34f6b4de9962c114299b3b9bfdd590d5
|
||||
timeCreated: 1506546248
|
||||
licenseType: Free
|
||||
guid: 4ff95e7516dbfa148b4fe16eaab783fb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
@@ -0,0 +1,250 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
internal abstract class PackageVerifyOperation : AsyncOperationBase
|
||||
{
|
||||
public static PackageVerifyOperation CreateOperation(List<VerifyElement> elements)
|
||||
{
|
||||
#if UNITY_WEBGL
|
||||
var operation = new PackageVerifyWithoutThreadOperation(elements);
|
||||
#else
|
||||
var operation = new PackageVerifyWithThreadOperation(elements);
|
||||
#endif
|
||||
return operation;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 本地缓存文件验证(线程版)
|
||||
/// </summary>
|
||||
internal class PackageVerifyWithThreadOperation : PackageVerifyOperation
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
InitVerify,
|
||||
UpdateVerify,
|
||||
Done,
|
||||
}
|
||||
|
||||
private readonly ThreadSyncContext _syncContext = new ThreadSyncContext();
|
||||
private List<VerifyElement> _waitingList;
|
||||
private List<VerifyElement> _verifyingList;
|
||||
private int _verifyMaxNum;
|
||||
private int _verifyTotalCount;
|
||||
private float _verifyStartTime;
|
||||
private int _succeedCount;
|
||||
private int _failedCount;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
public PackageVerifyWithThreadOperation(List<VerifyElement> elements)
|
||||
{
|
||||
_waitingList = elements;
|
||||
}
|
||||
internal override void Start()
|
||||
{
|
||||
_steps = ESteps.InitVerify;
|
||||
_verifyStartTime = UnityEngine.Time.realtimeSinceStartup;
|
||||
}
|
||||
internal override void Update()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
if (_steps == ESteps.InitVerify)
|
||||
{
|
||||
int fileCount = _waitingList.Count;
|
||||
|
||||
// 设置同时验证的最大数
|
||||
ThreadPool.GetMaxThreads(out int workerThreads, out int ioThreads);
|
||||
YooLogger.Log($"Work threads : {workerThreads}, IO threads : {ioThreads}");
|
||||
_verifyMaxNum = Math.Min(workerThreads, ioThreads);
|
||||
_verifyTotalCount = fileCount;
|
||||
if (_verifyMaxNum < 1)
|
||||
_verifyMaxNum = 1;
|
||||
|
||||
_verifyingList = new List<VerifyElement>(_verifyMaxNum);
|
||||
_steps = ESteps.UpdateVerify;
|
||||
}
|
||||
|
||||
if (_steps == ESteps.UpdateVerify)
|
||||
{
|
||||
_syncContext.Update();
|
||||
|
||||
Progress = GetProgress();
|
||||
if (_waitingList.Count == 0 && _verifyingList.Count == 0)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Succeed;
|
||||
float costTime = UnityEngine.Time.realtimeSinceStartup - _verifyStartTime;
|
||||
YooLogger.Log($"Package verify elapsed time {costTime:f1} seconds");
|
||||
}
|
||||
|
||||
for (int i = _waitingList.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (OperationSystem.IsBusy)
|
||||
break;
|
||||
|
||||
if (_verifyingList.Count >= _verifyMaxNum)
|
||||
break;
|
||||
|
||||
var element = _waitingList[i];
|
||||
if (BeginVerifyFileWithThread(element))
|
||||
{
|
||||
_waitingList.RemoveAt(i);
|
||||
_verifyingList.Add(element);
|
||||
}
|
||||
else
|
||||
{
|
||||
YooLogger.Warning("The thread pool is failed queued.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private float GetProgress()
|
||||
{
|
||||
if (_verifyTotalCount == 0)
|
||||
return 1f;
|
||||
return (float)(_succeedCount + _failedCount) / _verifyTotalCount;
|
||||
}
|
||||
private bool BeginVerifyFileWithThread(VerifyElement element)
|
||||
{
|
||||
return ThreadPool.QueueUserWorkItem(new WaitCallback(VerifyInThread), element);
|
||||
}
|
||||
private void VerifyInThread(object obj)
|
||||
{
|
||||
VerifyElement element = (VerifyElement)obj;
|
||||
element.Result = CacheSystem.VerifyingCacheFile(element);
|
||||
_syncContext.Post(VerifyCallback, element);
|
||||
}
|
||||
private void VerifyCallback(object obj)
|
||||
{
|
||||
VerifyElement element = (VerifyElement)obj;
|
||||
_verifyingList.Remove(element);
|
||||
|
||||
if (element.Result == EVerifyResult.Succeed)
|
||||
{
|
||||
_succeedCount++;
|
||||
var wrapper = new PackageCache.RecordWrapper(element.InfoFilePath, element.DataFilePath, element.DataFileCRC, element.DataFileSize);
|
||||
CacheSystem.RecordFile(element.PackageName, element.CacheGUID, wrapper);
|
||||
}
|
||||
else
|
||||
{
|
||||
_failedCount++;
|
||||
|
||||
YooLogger.Warning($"Failed verify file and delete files : {element.FileRootPath}");
|
||||
element.DeleteFiles();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 本地缓存文件验证(非线程版)
|
||||
/// </summary>
|
||||
internal class PackageVerifyWithoutThreadOperation : PackageVerifyOperation
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
InitVerify,
|
||||
UpdateVerify,
|
||||
Done,
|
||||
}
|
||||
|
||||
private List<VerifyElement> _waitingList;
|
||||
private List<VerifyElement> _verifyingList;
|
||||
private int _verifyMaxNum;
|
||||
private int _verifyTotalCount;
|
||||
private float _verifyStartTime;
|
||||
private int _succeedCount;
|
||||
private int _failedCount;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
public PackageVerifyWithoutThreadOperation(List<VerifyElement> elements)
|
||||
{
|
||||
_waitingList = elements;
|
||||
}
|
||||
internal override void Start()
|
||||
{
|
||||
_steps = ESteps.InitVerify;
|
||||
_verifyStartTime = UnityEngine.Time.realtimeSinceStartup;
|
||||
}
|
||||
internal override void Update()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
if (_steps == ESteps.InitVerify)
|
||||
{
|
||||
int fileCount = _waitingList.Count;
|
||||
|
||||
// 设置同时验证的最大数
|
||||
_verifyMaxNum = fileCount;
|
||||
_verifyTotalCount = fileCount;
|
||||
|
||||
_verifyingList = new List<VerifyElement>(_verifyMaxNum);
|
||||
_steps = ESteps.UpdateVerify;
|
||||
}
|
||||
|
||||
if (_steps == ESteps.UpdateVerify)
|
||||
{
|
||||
Progress = GetProgress();
|
||||
if (_waitingList.Count == 0 && _verifyingList.Count == 0)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Succeed;
|
||||
float costTime = UnityEngine.Time.realtimeSinceStartup - _verifyStartTime;
|
||||
YooLogger.Log($"Package verify elapsed time {costTime:f1} seconds");
|
||||
}
|
||||
|
||||
for (int i = _waitingList.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (OperationSystem.IsBusy)
|
||||
break;
|
||||
|
||||
if (_verifyingList.Count >= _verifyMaxNum)
|
||||
break;
|
||||
|
||||
var element = _waitingList[i];
|
||||
BeginVerifyFileWithoutThread(element);
|
||||
_waitingList.RemoveAt(i);
|
||||
_verifyingList.Add(element);
|
||||
}
|
||||
|
||||
// 主线程内验证,可以清空列表
|
||||
_verifyingList.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
private float GetProgress()
|
||||
{
|
||||
if (_verifyTotalCount == 0)
|
||||
return 1f;
|
||||
return (float)(_succeedCount + _failedCount) / _verifyTotalCount;
|
||||
}
|
||||
private void BeginVerifyFileWithoutThread(VerifyElement element)
|
||||
{
|
||||
element.Result = CacheSystem.VerifyingCacheFile(element);
|
||||
if (element.Result == EVerifyResult.Succeed)
|
||||
{
|
||||
_succeedCount++;
|
||||
var wrapper = new PackageCache.RecordWrapper(element.InfoFilePath, element.DataFilePath, element.DataFileCRC, element.DataFileSize);
|
||||
CacheSystem.RecordFile(element.PackageName, element.CacheGUID, wrapper);
|
||||
}
|
||||
else
|
||||
{
|
||||
_failedCount++;
|
||||
|
||||
YooLogger.Warning($"Failed verify file and delete files : {element.FileRootPath}");
|
||||
element.DeleteFiles();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
103
Assets/YooAsset/Runtime/CacheSystem/PackageCache.cs
Normal file
103
Assets/YooAsset/Runtime/CacheSystem/PackageCache.cs
Normal file
@@ -0,0 +1,103 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
internal class PackageCache
|
||||
{
|
||||
internal class RecordWrapper
|
||||
{
|
||||
public string InfoFilePath { private set; get; }
|
||||
public string DataFilePath { private set; get; }
|
||||
public string DataFileCRC { private set; get; }
|
||||
public long DataFileSize { private set; get; }
|
||||
|
||||
public RecordWrapper(string infoFilePath, string dataFilePath, string dataFileCRC, long dataFileSize)
|
||||
{
|
||||
InfoFilePath = infoFilePath;
|
||||
DataFilePath = dataFilePath;
|
||||
DataFileCRC = dataFileCRC;
|
||||
DataFileSize = dataFileSize;
|
||||
}
|
||||
}
|
||||
|
||||
private readonly Dictionary<string, RecordWrapper> _wrappers = new Dictionary<string, RecordWrapper>();
|
||||
|
||||
/// <summary>
|
||||
/// 包裹名称
|
||||
/// </summary>
|
||||
public string PackageName { private set; get; }
|
||||
|
||||
|
||||
public PackageCache(string packageName)
|
||||
{
|
||||
PackageName = packageName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清空所有数据
|
||||
/// </summary>
|
||||
public void ClearAll()
|
||||
{
|
||||
_wrappers.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查询缓存记录
|
||||
/// </summary>
|
||||
public bool IsCached(string cacheGUID)
|
||||
{
|
||||
return _wrappers.ContainsKey(cacheGUID);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 记录验证结果
|
||||
/// </summary>
|
||||
public void Record(string cacheGUID, RecordWrapper wrapper)
|
||||
{
|
||||
if (_wrappers.ContainsKey(cacheGUID) == false)
|
||||
{
|
||||
_wrappers.Add(cacheGUID, wrapper);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Should never get here !");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 丢弃验证结果
|
||||
/// </summary>
|
||||
public void Discard(string cacheGUID)
|
||||
{
|
||||
if (_wrappers.ContainsKey(cacheGUID))
|
||||
{
|
||||
_wrappers.Remove(cacheGUID);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取记录对象
|
||||
/// </summary>
|
||||
public RecordWrapper TryGetWrapper(string cacheGUID)
|
||||
{
|
||||
if (_wrappers.TryGetValue(cacheGUID, out RecordWrapper value))
|
||||
return value;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
internal List<string> GetAllKeys()
|
||||
{
|
||||
List<string> keys = new List<string>(_wrappers.Keys.Count);
|
||||
var keyCollection = _wrappers.Keys;
|
||||
foreach (var key in keyCollection)
|
||||
{
|
||||
keys.Add(key);
|
||||
}
|
||||
return keys;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/YooAsset/Runtime/CacheSystem/PackageCache.cs.meta
Normal file
11
Assets/YooAsset/Runtime/CacheSystem/PackageCache.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 08f3e92fdbd5d56459d8882be1f54f60
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
39
Assets/YooAsset/Runtime/CacheSystem/VerifyElement.cs
Normal file
39
Assets/YooAsset/Runtime/CacheSystem/VerifyElement.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using System.IO;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
internal class VerifyElement
|
||||
{
|
||||
public string PackageName { private set; get; }
|
||||
public string CacheGUID { private set; get; }
|
||||
public string FileRootPath { private set; get; }
|
||||
public string DataFilePath { private set; get; }
|
||||
public string InfoFilePath { private set; get; }
|
||||
|
||||
public EVerifyResult Result;
|
||||
public string DataFileCRC;
|
||||
public long DataFileSize;
|
||||
|
||||
public VerifyElement(string packageName, string cacheGUID, string fileRootPath, string dataFilePath, string infoFilePath)
|
||||
{
|
||||
PackageName = packageName;
|
||||
CacheGUID = cacheGUID;
|
||||
FileRootPath = fileRootPath;
|
||||
DataFilePath = dataFilePath;
|
||||
InfoFilePath = infoFilePath;
|
||||
}
|
||||
|
||||
public void DeleteFiles()
|
||||
{
|
||||
if (File.Exists(DataFilePath))
|
||||
{
|
||||
File.Delete(DataFilePath);
|
||||
}
|
||||
|
||||
if (File.Exists(InfoFilePath))
|
||||
{
|
||||
File.Delete(InfoFilePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/YooAsset/Runtime/CacheSystem/VerifyElement.cs.meta
Normal file
11
Assets/YooAsset/Runtime/CacheSystem/VerifyElement.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5a4b96484bd701f4289b2f74c38abaa8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,33 +0,0 @@
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
internal class VerifyInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// 验证的资源文件是否为内置资源
|
||||
/// </summary>
|
||||
public bool IsBuildinFile { private set; get; }
|
||||
|
||||
/// <summary>
|
||||
/// 验证的资源包实例
|
||||
/// </summary>
|
||||
public PatchBundle VerifyBundle { private set; get; }
|
||||
|
||||
/// <summary>
|
||||
/// 验证的文件路径
|
||||
/// </summary>
|
||||
public string VerifyFilePath { private set; get; }
|
||||
|
||||
/// <summary>
|
||||
/// 验证结果
|
||||
/// </summary>
|
||||
public EVerifyResult Result;
|
||||
|
||||
public VerifyInfo(bool isBuildinFile, PatchBundle verifyBundle)
|
||||
{
|
||||
IsBuildinFile = isBuildinFile;
|
||||
VerifyBundle = verifyBundle;
|
||||
VerifyFilePath = verifyBundle.CachedFilePath;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -77,13 +77,13 @@ namespace YooAsset
|
||||
public static DownloaderBase BeginDownload(BundleInfo bundleInfo, int failedTryAgain, int timeout = 60)
|
||||
{
|
||||
// 查询存在的下载器
|
||||
if (_downloaderDic.TryGetValue(bundleInfo.Bundle.CachedFilePath, out var downloader))
|
||||
if (_downloaderDic.TryGetValue(bundleInfo.Bundle.CachedDataFilePath, out var downloader))
|
||||
{
|
||||
return downloader;
|
||||
}
|
||||
|
||||
// 如果资源已经缓存
|
||||
if (CacheSystem.IsCached(bundleInfo.Bundle))
|
||||
if (CacheSystem.IsCached(bundleInfo.Bundle.PackageName, bundleInfo.Bundle.CacheGUID))
|
||||
{
|
||||
var tempDownloader = new TempDownloader(bundleInfo);
|
||||
return tempDownloader;
|
||||
@@ -92,11 +92,11 @@ namespace YooAsset
|
||||
// 创建新的下载器
|
||||
{
|
||||
YooLogger.Log($"Beginning to download file : {bundleInfo.Bundle.FileName} URL : {bundleInfo.RemoteMainURL}");
|
||||
FileUtility.CreateFileDirectory(bundleInfo.Bundle.CachedFilePath);
|
||||
FileUtility.CreateFileDirectory(bundleInfo.Bundle.CachedDataFilePath);
|
||||
bool breakDownload = bundleInfo.Bundle.FileSize >= BreakpointResumeFileSize;
|
||||
DownloaderBase newDownloader = new FileDownloader(bundleInfo, breakDownload);
|
||||
newDownloader.SendRequest(failedTryAgain, timeout);
|
||||
_downloaderDic.Add(bundleInfo.Bundle.CachedFilePath, newDownloader);
|
||||
_downloaderDic.Add(bundleInfo.Bundle.CachedDataFilePath, newDownloader);
|
||||
return newDownloader;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,13 +6,13 @@ namespace YooAsset
|
||||
protected enum ESteps
|
||||
{
|
||||
None,
|
||||
CheckLocalFile,
|
||||
CheckTempFile,
|
||||
PrepareDownload,
|
||||
CreateResumeDownloader,
|
||||
CreateGeneralDownloader,
|
||||
CheckDownload,
|
||||
VerifyDownload,
|
||||
VerifyingFile,
|
||||
CachingFile,
|
||||
TryAgain,
|
||||
Succeed,
|
||||
Failed,
|
||||
@@ -60,7 +60,7 @@ namespace YooAsset
|
||||
{
|
||||
_failedTryAgain = failedTryAgain;
|
||||
_timeout = timeout;
|
||||
_steps = ESteps.CheckLocalFile;
|
||||
_steps = ESteps.CheckTempFile;
|
||||
}
|
||||
}
|
||||
public abstract void Update();
|
||||
|
||||
@@ -25,7 +25,7 @@ namespace YooAsset
|
||||
public FileDownloader(BundleInfo bundleInfo, bool breakResume) : base(bundleInfo)
|
||||
{
|
||||
_breakResume = breakResume;
|
||||
_tempFilePath = bundleInfo.Bundle.CachedFilePath + ".temp";
|
||||
_tempFilePath = bundleInfo.Bundle.TempDataFilePath;
|
||||
}
|
||||
public override void Update()
|
||||
{
|
||||
@@ -34,29 +34,13 @@ namespace YooAsset
|
||||
if (IsDone())
|
||||
return;
|
||||
|
||||
// 检测本地正式文件
|
||||
if (_steps == ESteps.CheckLocalFile)
|
||||
{
|
||||
var verifyResult = CacheSystem.VerifyAndCacheLocalBundleFile(_bundleInfo.Bundle, CacheSystem.InitVerifyLevel);
|
||||
if (verifyResult == EVerifyResult.Succeed)
|
||||
{
|
||||
_steps = ESteps.Succeed;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (File.Exists(_bundleInfo.Bundle.CachedFilePath))
|
||||
File.Delete(_bundleInfo.Bundle.CachedFilePath);
|
||||
_steps = ESteps.CheckTempFile;
|
||||
}
|
||||
}
|
||||
|
||||
// 检测本地临时文件
|
||||
if (_steps == ESteps.CheckTempFile)
|
||||
{
|
||||
var verifyResult = CacheSystem.VerifyAndCacheDownloadBundleFile(_tempFilePath, _bundleInfo.Bundle, EVerifyLevel.High);
|
||||
var verifyResult = CacheSystem.VerifyingTempFile(_bundleInfo.Bundle);
|
||||
if (verifyResult == EVerifyResult.Succeed)
|
||||
{
|
||||
_steps = ESteps.Succeed;
|
||||
_steps = ESteps.CachingFile;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -94,9 +78,7 @@ namespace YooAsset
|
||||
if (_steps == ESteps.CreateGeneralDownloader)
|
||||
{
|
||||
if (File.Exists(_tempFilePath))
|
||||
{
|
||||
File.Delete(_tempFilePath);
|
||||
}
|
||||
|
||||
_webRequest = new UnityWebRequest(_requestURL, UnityWebRequest.kHttpVerbGET);
|
||||
DownloadHandlerFile handler = new DownloadHandlerFile(_tempFilePath);
|
||||
@@ -206,7 +188,7 @@ namespace YooAsset
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.VerifyDownload;
|
||||
_steps = ESteps.VerifyingFile;
|
||||
}
|
||||
|
||||
// 释放下载器
|
||||
@@ -214,23 +196,57 @@ namespace YooAsset
|
||||
}
|
||||
|
||||
// 验证下载文件
|
||||
if (_steps == ESteps.VerifyDownload)
|
||||
if (_steps == ESteps.VerifyingFile)
|
||||
{
|
||||
var verifyResult = CacheSystem.VerifyAndCacheDownloadBundleFile(_tempFilePath, _bundleInfo.Bundle, EVerifyLevel.High);
|
||||
var verifyResult = CacheSystem.VerifyingTempFile(_bundleInfo.Bundle);
|
||||
if (verifyResult == EVerifyResult.Succeed)
|
||||
{
|
||||
_steps = ESteps.CachingFile;
|
||||
}
|
||||
else
|
||||
{
|
||||
_lastError = $"Failed to verifying file : {_bundleInfo.Bundle.FileName}, ErrorCode : {verifyResult}";
|
||||
|
||||
// 注意:验证失败后删除文件
|
||||
if (File.Exists(_tempFilePath))
|
||||
File.Delete(_tempFilePath);
|
||||
|
||||
_steps = ESteps.TryAgain;
|
||||
}
|
||||
}
|
||||
|
||||
// 缓存下载文件
|
||||
if (_steps == ESteps.CachingFile)
|
||||
{
|
||||
try
|
||||
{
|
||||
string infoFilePath = _bundleInfo.Bundle.CachedInfoFilePath;
|
||||
string dataFilePath = _bundleInfo.Bundle.CachedDataFilePath;
|
||||
string dataFileCRC = _bundleInfo.Bundle.FileCRC;
|
||||
long dataFileSize = _bundleInfo.Bundle.FileSize;
|
||||
|
||||
if (File.Exists(infoFilePath))
|
||||
File.Delete(infoFilePath);
|
||||
if (File.Exists(dataFilePath))
|
||||
File.Delete(dataFilePath);
|
||||
|
||||
FileInfo fileInfo = new FileInfo(_tempFilePath);
|
||||
fileInfo.MoveTo(dataFilePath);
|
||||
|
||||
// 写入信息文件记录验证数据
|
||||
CacheFileInfo.WriteInfoToFile(infoFilePath, dataFileCRC, dataFileSize);
|
||||
|
||||
// 记录缓存文件
|
||||
var wrapper = new PackageCache.RecordWrapper(infoFilePath, dataFilePath, dataFileCRC, dataFileSize);
|
||||
CacheSystem.RecordFile(_bundleInfo.Bundle.PackageName, _bundleInfo.Bundle.CacheGUID, wrapper);
|
||||
|
||||
_lastError = string.Empty;
|
||||
_lastCode = 0;
|
||||
_steps = ESteps.Succeed;
|
||||
}
|
||||
else
|
||||
catch (Exception e)
|
||||
{
|
||||
_lastError = $"Verify bundle content failed : {_bundleInfo.Bundle.FileName}";
|
||||
|
||||
// 验证失败后删除文件
|
||||
if (File.Exists(_tempFilePath))
|
||||
File.Delete(_tempFilePath);
|
||||
|
||||
_lastError = e.Message;
|
||||
_steps = ESteps.TryAgain;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,9 @@ namespace YooAsset
|
||||
{
|
||||
URL = url;
|
||||
_timeout = timeout;
|
||||
_latestDownloadBytes = 0;
|
||||
_latestDownloadRealtime = Time.realtimeSinceStartup;
|
||||
|
||||
_webRequest = new UnityWebRequest(URL, UnityWebRequest.kHttpVerbGET);
|
||||
DownloadHandlerFile handler = new DownloadHandlerFile(savePath);
|
||||
handler.removeFileOnAbort = true;
|
||||
|
||||
@@ -7,6 +7,8 @@ namespace YooAsset
|
||||
internal class OperationSystem
|
||||
{
|
||||
private static readonly List<AsyncOperationBase> _operations = new List<AsyncOperationBase>(100);
|
||||
private static readonly List<AsyncOperationBase> _addList = new List<AsyncOperationBase>(100);
|
||||
private static readonly List<AsyncOperationBase> _removeList = new List<AsyncOperationBase>(100);
|
||||
|
||||
// 计时器相关
|
||||
private static Stopwatch _watch;
|
||||
@@ -44,19 +46,40 @@ namespace YooAsset
|
||||
{
|
||||
_frameTime = _watch.ElapsedMilliseconds;
|
||||
|
||||
for (int i = _operations.Count - 1; i >= 0; i--)
|
||||
// 添加新的异步操作
|
||||
if (_addList.Count > 0)
|
||||
{
|
||||
for (int i = 0; i < _addList.Count; i++)
|
||||
{
|
||||
var operation = _addList[i];
|
||||
_operations.Add(operation);
|
||||
}
|
||||
_addList.Clear();
|
||||
}
|
||||
|
||||
// 更新所有的异步操作
|
||||
foreach (var operation in _operations)
|
||||
{
|
||||
if (IsBusy)
|
||||
return;
|
||||
|
||||
var operation = _operations[i];
|
||||
operation.Update();
|
||||
if (operation.IsDone)
|
||||
{
|
||||
_operations.RemoveAt(i);
|
||||
_removeList.Add(operation);
|
||||
operation.Finish();
|
||||
}
|
||||
}
|
||||
|
||||
// 移除已经完成的异步操作
|
||||
if (_removeList.Count > 0)
|
||||
{
|
||||
foreach (var operation in _removeList)
|
||||
{
|
||||
_operations.Remove(operation);
|
||||
}
|
||||
_removeList.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -65,6 +88,8 @@ namespace YooAsset
|
||||
public static void DestroyAll()
|
||||
{
|
||||
_operations.Clear();
|
||||
_addList.Clear();
|
||||
_removeList.Clear();
|
||||
_watch = null;
|
||||
_frameTime = 0;
|
||||
MaxTimeSlice = long.MaxValue;
|
||||
@@ -73,10 +98,10 @@ namespace YooAsset
|
||||
/// <summary>
|
||||
/// 开始处理异步操作类
|
||||
/// </summary>
|
||||
public static void StartOperation(AsyncOperationBase operationBase)
|
||||
public static void StartOperation(AsyncOperationBase operation)
|
||||
{
|
||||
_operations.Add(operationBase);
|
||||
operationBase.Start();
|
||||
_addList.Add(operation);
|
||||
operation.Start();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,150 +0,0 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 检查包裹内容的完整性
|
||||
/// </summary>
|
||||
public abstract class CheckPackageContentsOperation : AsyncOperationBase
|
||||
{
|
||||
}
|
||||
|
||||
internal sealed class EditorSimulateModeCheckPackageContentsOperation : CheckPackageContentsOperation
|
||||
{
|
||||
internal EditorSimulateModeCheckPackageContentsOperation()
|
||||
{
|
||||
}
|
||||
internal override void Start()
|
||||
{
|
||||
Status = EOperationStatus.Succeed;
|
||||
}
|
||||
internal override void Update()
|
||||
{
|
||||
}
|
||||
}
|
||||
internal sealed class OfflinePlayModeCheckPackageContentsOperation : CheckPackageContentsOperation
|
||||
{
|
||||
internal OfflinePlayModeCheckPackageContentsOperation()
|
||||
{
|
||||
}
|
||||
internal override void Start()
|
||||
{
|
||||
Status = EOperationStatus.Succeed;
|
||||
}
|
||||
internal override void Update()
|
||||
{
|
||||
}
|
||||
}
|
||||
internal sealed class HostPlayModeCheckPackageContentsOperation : CheckPackageContentsOperation
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
CheckActiveManifest,
|
||||
LoadCacheManifest,
|
||||
VerifyPackage,
|
||||
Done,
|
||||
}
|
||||
|
||||
private readonly HostPlayModeImpl _impl;
|
||||
private readonly string _packageName;
|
||||
private readonly string _packageVersion;
|
||||
private LoadCacheManifestOperation _loadCacheManifestOp;
|
||||
private VerifyPackageOperation _verifyOperation;
|
||||
private PatchManifest _verifyManifest;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
internal HostPlayModeCheckPackageContentsOperation(HostPlayModeImpl impl, string packageName, string packageVersion)
|
||||
{
|
||||
_impl = impl;
|
||||
_packageName = packageName;
|
||||
_packageVersion = packageVersion;
|
||||
}
|
||||
internal override void Start()
|
||||
{
|
||||
_steps = ESteps.CheckActiveManifest;
|
||||
}
|
||||
internal override void Update()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
if (_steps == ESteps.CheckActiveManifest)
|
||||
{
|
||||
// 检测当前激活的清单对象
|
||||
if (_impl.ActiveManifest != null && _impl.ActiveManifest.PackageVersion == _packageVersion)
|
||||
{
|
||||
_verifyManifest = _impl.ActiveManifest;
|
||||
_steps = ESteps.VerifyPackage;
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.LoadCacheManifest;
|
||||
}
|
||||
}
|
||||
|
||||
if (_steps == ESteps.LoadCacheManifest)
|
||||
{
|
||||
if (_loadCacheManifestOp == null)
|
||||
{
|
||||
_loadCacheManifestOp = new LoadCacheManifestOperation(_packageName, _packageVersion);
|
||||
OperationSystem.StartOperation(_loadCacheManifestOp);
|
||||
}
|
||||
|
||||
if (_loadCacheManifestOp.IsDone == false)
|
||||
return;
|
||||
|
||||
if (_loadCacheManifestOp.Status == EOperationStatus.Succeed)
|
||||
{
|
||||
_verifyManifest = _loadCacheManifestOp.Manifest;
|
||||
_steps = ESteps.VerifyPackage;
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Failed;
|
||||
Error = _loadCacheManifestOp.Error;
|
||||
}
|
||||
}
|
||||
|
||||
if (_steps == ESteps.VerifyPackage)
|
||||
{
|
||||
if (_verifyOperation == null)
|
||||
{
|
||||
_verifyOperation = VerifyPackageOperation.CreateOperation(_verifyManifest, _impl);
|
||||
OperationSystem.StartOperation(_verifyOperation);
|
||||
}
|
||||
|
||||
Progress = _verifyOperation.Progress;
|
||||
if (_verifyOperation.IsDone == false)
|
||||
return;
|
||||
|
||||
bool verifySucceed = true;
|
||||
foreach (var verifyInfo in _verifyOperation.VerifyFailList)
|
||||
{
|
||||
// 注意:跳过内置资源文件
|
||||
if (verifyInfo.IsBuildinFile)
|
||||
continue;
|
||||
|
||||
verifySucceed = false;
|
||||
YooLogger.Warning($"Failed verify file : {verifyInfo.VerifyFilePath}");
|
||||
}
|
||||
|
||||
if (verifySucceed)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Succeed;
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Failed;
|
||||
Error = $"The package resource {_packageName} content has verify failed file !";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
/// <summary>
|
||||
/// 清理本地包裹未使用的缓存文件
|
||||
/// </summary>
|
||||
public sealed class ClearUnusedCacheFilesOperation : AsyncOperationBase
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
GetUnusedCacheFiles,
|
||||
ClearUnusedCacheFiles,
|
||||
Done,
|
||||
}
|
||||
|
||||
private readonly AssetsPackage _package;
|
||||
private List<string> _unusedCacheFilePaths;
|
||||
private int _unusedFileTotalCount = 0;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
internal ClearUnusedCacheFilesOperation(AssetsPackage package)
|
||||
{
|
||||
_package = package;
|
||||
}
|
||||
internal override void Start()
|
||||
{
|
||||
_steps = ESteps.GetUnusedCacheFiles;
|
||||
}
|
||||
internal override void Update()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
if (_steps == ESteps.GetUnusedCacheFiles)
|
||||
{
|
||||
_unusedCacheFilePaths = GetUnusedCacheFilePaths();
|
||||
_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))
|
||||
{
|
||||
try
|
||||
{
|
||||
File.Delete(filePath);
|
||||
YooLogger.Log($"Delete unused cache file : {filePath}");
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
YooLogger.Warning($"Failed delete cache file : {filePath} ! {e.Message}");
|
||||
}
|
||||
}
|
||||
_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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取未被使用的缓存文件路径集合
|
||||
/// </summary>
|
||||
private List<string> GetUnusedCacheFilePaths()
|
||||
{
|
||||
string cacheFolderPath = PersistentHelper.GetCacheFolderPath(_package.PackageName);
|
||||
if (Directory.Exists(cacheFolderPath) == false)
|
||||
return new List<string>();
|
||||
|
||||
DirectoryInfo directoryInfo = new DirectoryInfo(cacheFolderPath);
|
||||
FileInfo[] fileInfos = directoryInfo.GetFiles();
|
||||
List<string> result = new List<string>(fileInfos.Length);
|
||||
foreach (FileInfo fileInfo in fileInfos)
|
||||
{
|
||||
if (_package.IsIncludeBundleFile(fileInfo.Name) == false)
|
||||
{
|
||||
result.Add(fileInfo.FullName);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -79,7 +79,7 @@ namespace YooAsset
|
||||
None,
|
||||
QueryBuildinPackageVersion,
|
||||
LoadBuildinManifest,
|
||||
VerifyPackage,
|
||||
PackageCaching,
|
||||
Done,
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ namespace YooAsset
|
||||
private readonly string _packageName;
|
||||
private QueryBuildinPackageVersionOperation _queryBuildinPackageVersionOp;
|
||||
private LoadBuildinManifestOperation _loadBuildinManifestOp;
|
||||
private VerifyPackageOperation _verifyOperation;
|
||||
private PackageCachingOperation _cachingOperation;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
internal OfflinePlayModeInitializationOperation(OfflinePlayModeImpl impl, string packageName)
|
||||
@@ -143,7 +143,7 @@ namespace YooAsset
|
||||
{
|
||||
PackageVersion = _loadBuildinManifestOp.Manifest.PackageVersion;
|
||||
_impl.ActiveManifest = _loadBuildinManifestOp.Manifest;
|
||||
_steps = ESteps.VerifyPackage;
|
||||
_steps = ESteps.PackageCaching;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -153,16 +153,16 @@ namespace YooAsset
|
||||
}
|
||||
}
|
||||
|
||||
if (_steps == ESteps.VerifyPackage)
|
||||
if (_steps == ESteps.PackageCaching)
|
||||
{
|
||||
if (_verifyOperation == null)
|
||||
if (_cachingOperation == null)
|
||||
{
|
||||
_verifyOperation = VerifyPackageOperation.CreateOperation(_impl.ActiveManifest, _impl);
|
||||
OperationSystem.StartOperation(_verifyOperation);
|
||||
_cachingOperation = new PackageCachingOperation(_packageName);
|
||||
OperationSystem.StartOperation(_cachingOperation);
|
||||
}
|
||||
|
||||
Progress = _verifyOperation.Progress;
|
||||
if (_verifyOperation.IsDone)
|
||||
Progress = _cachingOperation.Progress;
|
||||
if (_cachingOperation.IsDone)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Succeed;
|
||||
@@ -186,7 +186,7 @@ namespace YooAsset
|
||||
QueryBuildinPackageVersion,
|
||||
UnpackBuildinManifest,
|
||||
LoadBuildinManifest,
|
||||
VerifyPackage,
|
||||
PackageCaching,
|
||||
Done,
|
||||
}
|
||||
|
||||
@@ -197,7 +197,7 @@ namespace YooAsset
|
||||
private UnpackBuildinManifestOperation _unpackBuildinManifestOp;
|
||||
private LoadBuildinManifestOperation _loadBuildinManifestOp;
|
||||
private LoadCacheManifestOperation _loadCacheManifestOp;
|
||||
private VerifyPackageOperation _verifyOperation;
|
||||
private PackageCachingOperation _cachingOperation;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
internal HostPlayModeInitializationOperation(HostPlayModeImpl impl, string packageName)
|
||||
@@ -265,7 +265,7 @@ namespace YooAsset
|
||||
{
|
||||
PackageVersion = _loadCacheManifestOp.Manifest.PackageVersion;
|
||||
_impl.ActiveManifest = _loadCacheManifestOp.Manifest;
|
||||
_steps = ESteps.VerifyPackage;
|
||||
_steps = ESteps.PackageCaching;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -284,15 +284,14 @@ namespace YooAsset
|
||||
if (_queryBuildinPackageVersionOp.IsDone == false)
|
||||
return;
|
||||
|
||||
// 注意:为了兼容MOD模式,初始化动态新增的包裹的时候,如果内置清单不存在也不需要报错!
|
||||
if (_queryBuildinPackageVersionOp.Status == EOperationStatus.Succeed)
|
||||
{
|
||||
_steps = ESteps.UnpackBuildinManifest;
|
||||
}
|
||||
else
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Succeed;
|
||||
// 注意:为了兼容MOD模式,初始化动态新增的包裹的时候,如果内置清单不存在也不需要报错!
|
||||
_steps = ESteps.PackageCaching;
|
||||
string error = _queryBuildinPackageVersionOp.Error;
|
||||
YooLogger.Log($"Failed to load buildin package version file : {error}");
|
||||
}
|
||||
@@ -337,7 +336,7 @@ namespace YooAsset
|
||||
{
|
||||
PackageVersion = _loadBuildinManifestOp.Manifest.PackageVersion;
|
||||
_impl.ActiveManifest = _loadBuildinManifestOp.Manifest;
|
||||
_steps = ESteps.VerifyPackage;
|
||||
_steps = ESteps.PackageCaching;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -347,16 +346,16 @@ namespace YooAsset
|
||||
}
|
||||
}
|
||||
|
||||
if (_steps == ESteps.VerifyPackage)
|
||||
if (_steps == ESteps.PackageCaching)
|
||||
{
|
||||
if (_verifyOperation == null)
|
||||
if (_cachingOperation == null)
|
||||
{
|
||||
_verifyOperation = VerifyPackageOperation.CreateOperation(_impl.ActiveManifest, _impl);
|
||||
OperationSystem.StartOperation(_verifyOperation);
|
||||
_cachingOperation = new PackageCachingOperation(_packageName);
|
||||
OperationSystem.StartOperation(_cachingOperation);
|
||||
}
|
||||
|
||||
Progress = _verifyOperation.Progress;
|
||||
if (_verifyOperation.IsDone)
|
||||
Progress = _cachingOperation.Progress;
|
||||
if (_cachingOperation.IsDone)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Succeed;
|
||||
|
||||
@@ -112,7 +112,7 @@ namespace YooAsset
|
||||
Manifest.AssetDic.Add(assetPath, patchAsset);
|
||||
|
||||
_patchAssetCount--;
|
||||
Progress = _patchAssetCount / _progressTotalValue;
|
||||
Progress = 1f - _patchAssetCount / _progressTotalValue;
|
||||
if (OperationSystem.IsBusy)
|
||||
break;
|
||||
}
|
||||
@@ -143,13 +143,14 @@ namespace YooAsset
|
||||
patchBundle.IsRawFile = _buffer.ReadBool();
|
||||
patchBundle.LoadMethod = _buffer.ReadByte();
|
||||
patchBundle.Tags = _buffer.ReadUTF8Array();
|
||||
patchBundle.ReferenceIDs = _buffer.ReadInt32Array();
|
||||
Manifest.BundleList.Add(patchBundle);
|
||||
|
||||
patchBundle.ParseBundle(Manifest.PackageName, Manifest.OutputNameStyle);
|
||||
Manifest.BundleDic.Add(patchBundle.BundleName, patchBundle);
|
||||
|
||||
_patchBundleCount--;
|
||||
Progress = _patchBundleCount / _progressTotalValue;
|
||||
Progress = 1f - _patchBundleCount / _progressTotalValue;
|
||||
if (OperationSystem.IsBusy)
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace YooAsset
|
||||
}
|
||||
|
||||
private static int RequestCount = 0;
|
||||
private readonly HostPlayModeImpl _impl;
|
||||
private readonly IRemoteServices _remoteServices;
|
||||
private readonly string _packageName;
|
||||
private readonly string _packageVersion;
|
||||
private readonly int _timeout;
|
||||
@@ -20,9 +20,9 @@ namespace YooAsset
|
||||
private UnityWebFileRequester _downloader2;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
internal DownloadManifestOperation(HostPlayModeImpl impl, string packageName, string packageVersion, int timeout)
|
||||
internal DownloadManifestOperation(IRemoteServices remoteServices, string packageName, string packageVersion, int timeout)
|
||||
{
|
||||
_impl = impl;
|
||||
_remoteServices = remoteServices;
|
||||
_packageName = packageName;
|
||||
_packageVersion = packageVersion;
|
||||
_timeout = timeout;
|
||||
@@ -103,9 +103,9 @@ namespace YooAsset
|
||||
{
|
||||
// 轮流返回请求地址
|
||||
if (RequestCount % 2 == 0)
|
||||
return _impl.GetPatchDownloadFallbackURL(fileName);
|
||||
return _remoteServices.GetRemoteFallbackURL(fileName);
|
||||
else
|
||||
return _impl.GetPatchDownloadMainURL(fileName);
|
||||
return _remoteServices.GetRemoteMainURL(fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@ namespace YooAsset
|
||||
}
|
||||
|
||||
private static int RequestCount = 0;
|
||||
private readonly HostPlayModeImpl _impl;
|
||||
private readonly IRemoteServices _remoteServices;
|
||||
private readonly string _packageName;
|
||||
private readonly bool _appendTimeTicks;
|
||||
private readonly int _timeout;
|
||||
@@ -25,9 +25,9 @@ namespace YooAsset
|
||||
public string PackageVersion { private set; get; }
|
||||
|
||||
|
||||
public QueryRemotePackageVersionOperation(HostPlayModeImpl impl, string packageName, bool appendTimeTicks, int timeout)
|
||||
public QueryRemotePackageVersionOperation(IRemoteServices remoteServices, string packageName, bool appendTimeTicks, int timeout)
|
||||
{
|
||||
_impl = impl;
|
||||
_remoteServices = remoteServices;
|
||||
_packageName = packageName;
|
||||
_appendTimeTicks = appendTimeTicks;
|
||||
_timeout = timeout;
|
||||
@@ -89,9 +89,9 @@ namespace YooAsset
|
||||
|
||||
// 轮流返回请求地址
|
||||
if (RequestCount % 2 == 0)
|
||||
url = _impl.GetPatchDownloadFallbackURL(fileName);
|
||||
url = _remoteServices.GetRemoteFallbackURL(fileName);
|
||||
else
|
||||
url = _impl.GetPatchDownloadMainURL(fileName);
|
||||
url = _remoteServices.GetRemoteMainURL(fileName);
|
||||
|
||||
// 在URL末尾添加时间戳
|
||||
if (_appendTimeTicks)
|
||||
|
||||
@@ -1,294 +0,0 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
internal abstract class VerifyPackageOperation : AsyncOperationBase
|
||||
{
|
||||
public List<VerifyInfo> VerifySuccessList { protected set; get; }
|
||||
public List<VerifyInfo> VerifyFailList { protected set; get; }
|
||||
|
||||
public static VerifyPackageOperation CreateOperation(PatchManifest manifest, IPlayModeServices playModeServices)
|
||||
{
|
||||
#if UNITY_WEBGL
|
||||
VerifyPackageOperation operation = new VerifyPackageWithoutThreadOperation(manifest, playModeServices);
|
||||
#else
|
||||
VerifyPackageOperation operation = new VerifyPackageWithThreadOperation(manifest, playModeServices);
|
||||
#endif
|
||||
return operation;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 本地缓存文件验证(线程版)
|
||||
/// </summary>
|
||||
internal class VerifyPackageWithThreadOperation : VerifyPackageOperation
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
InitVerify,
|
||||
PrepareVerify,
|
||||
UpdateVerify,
|
||||
Done,
|
||||
}
|
||||
|
||||
private readonly PatchManifest _manifest;
|
||||
private readonly IPlayModeServices _playModeServices;
|
||||
private readonly ThreadSyncContext _syncContext = new ThreadSyncContext();
|
||||
private List<VerifyInfo> _waitingList;
|
||||
private List<VerifyInfo> _verifyingList;
|
||||
private int _verifyMaxNum;
|
||||
private int _verifyTotalCount;
|
||||
private float _verifyStartTime;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
public VerifyPackageWithThreadOperation(PatchManifest manifest, IPlayModeServices playModeServices)
|
||||
{
|
||||
_manifest = manifest;
|
||||
_playModeServices = playModeServices;
|
||||
}
|
||||
internal override void Start()
|
||||
{
|
||||
_steps = ESteps.InitVerify;
|
||||
_verifyStartTime = UnityEngine.Time.realtimeSinceStartup;
|
||||
}
|
||||
internal override void Update()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
if (_steps == ESteps.InitVerify)
|
||||
{
|
||||
int bundleCount = _manifest.BundleList.Count;
|
||||
VerifySuccessList = new List<VerifyInfo>(bundleCount);
|
||||
VerifyFailList = new List<VerifyInfo>(bundleCount);
|
||||
|
||||
// 设置同时验证的最大数
|
||||
ThreadPool.GetMaxThreads(out int workerThreads, out int ioThreads);
|
||||
YooLogger.Log($"Work threads : {workerThreads}, IO threads : {ioThreads}");
|
||||
_verifyMaxNum = Math.Min(workerThreads, ioThreads);
|
||||
_verifyTotalCount = bundleCount;
|
||||
if (_verifyMaxNum < 1)
|
||||
_verifyMaxNum = 1;
|
||||
|
||||
_waitingList = new List<VerifyInfo>(bundleCount);
|
||||
_verifyingList = new List<VerifyInfo>(_verifyMaxNum);
|
||||
_steps = ESteps.PrepareVerify;
|
||||
}
|
||||
|
||||
if (_steps == ESteps.PrepareVerify)
|
||||
{
|
||||
foreach (var patchBundle in _manifest.BundleList)
|
||||
{
|
||||
if (CacheSystem.IsCached(patchBundle))
|
||||
continue;
|
||||
|
||||
bool isBuildinFile = _playModeServices.IsBuildinPatchBundle(patchBundle);
|
||||
VerifyInfo verifyInfo = new VerifyInfo(isBuildinFile, patchBundle);
|
||||
_waitingList.Add(verifyInfo);
|
||||
}
|
||||
_steps = ESteps.UpdateVerify;
|
||||
}
|
||||
|
||||
if (_steps == ESteps.UpdateVerify)
|
||||
{
|
||||
_syncContext.Update();
|
||||
|
||||
Progress = GetVerifierProgress();
|
||||
if (_waitingList.Count == 0 && _verifyingList.Count == 0)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Succeed;
|
||||
float costTime = UnityEngine.Time.realtimeSinceStartup - _verifyStartTime;
|
||||
YooLogger.Log($"Verify elapsed time {costTime:f1} seconds");
|
||||
}
|
||||
|
||||
for (int i = _waitingList.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (OperationSystem.IsBusy)
|
||||
break;
|
||||
|
||||
if (_verifyingList.Count >= _verifyMaxNum)
|
||||
break;
|
||||
|
||||
var verifyIno = _waitingList[i];
|
||||
if (VerifyFileWithThread(verifyIno))
|
||||
{
|
||||
_waitingList.RemoveAt(i);
|
||||
_verifyingList.Add(verifyIno);
|
||||
}
|
||||
else
|
||||
{
|
||||
YooLogger.Warning("The thread pool is failed queued.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private float GetVerifierProgress()
|
||||
{
|
||||
if (_verifyTotalCount == 0)
|
||||
return 1f;
|
||||
return (float)(VerifySuccessList.Count + VerifyFailList.Count) / _verifyTotalCount;
|
||||
}
|
||||
private bool VerifyFileWithThread(VerifyInfo verifyInfo)
|
||||
{
|
||||
return ThreadPool.QueueUserWorkItem(new WaitCallback(VerifyInThread), verifyInfo);
|
||||
}
|
||||
private void VerifyInThread(object infoObj)
|
||||
{
|
||||
VerifyInfo verifyInfo = (VerifyInfo)infoObj;
|
||||
verifyInfo.Result = CacheSystem.VerifyBundle(verifyInfo.VerifyBundle, CacheSystem.InitVerifyLevel);
|
||||
_syncContext.Post(VerifyCallback, verifyInfo);
|
||||
}
|
||||
private void VerifyCallback(object obj)
|
||||
{
|
||||
VerifyInfo verifyIno = (VerifyInfo)obj;
|
||||
if (verifyIno.Result == EVerifyResult.Succeed)
|
||||
{
|
||||
VerifySuccessList.Add(verifyIno);
|
||||
CacheSystem.CacheBundle(verifyIno.VerifyBundle);
|
||||
}
|
||||
else
|
||||
{
|
||||
VerifyFailList.Add(verifyIno);
|
||||
|
||||
// 删除验证失败的缓存文件
|
||||
if (File.Exists(verifyIno.VerifyBundle.CachedFilePath))
|
||||
{
|
||||
YooLogger.Warning($"Delete verify failed bundle file : {verifyIno.VerifyBundle.CachedFilePath}");
|
||||
File.Delete(verifyIno.VerifyBundle.CachedFilePath);
|
||||
}
|
||||
}
|
||||
_verifyingList.Remove(verifyIno);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 本地缓存文件验证(非线程版)
|
||||
/// </summary>
|
||||
internal class VerifyPackageWithoutThreadOperation : VerifyPackageOperation
|
||||
{
|
||||
private enum ESteps
|
||||
{
|
||||
None,
|
||||
InitVerify,
|
||||
PrepareVerify,
|
||||
UpdateVerify,
|
||||
Done,
|
||||
}
|
||||
|
||||
private readonly PatchManifest _manifest;
|
||||
private readonly IPlayModeServices _playModeServices;
|
||||
private List<VerifyInfo> _waitingList;
|
||||
private List<VerifyInfo> _verifyingList;
|
||||
private int _verifyMaxNum;
|
||||
private int _verifyTotalCount;
|
||||
private float _verifyStartTime;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
public VerifyPackageWithoutThreadOperation(PatchManifest manifest, IPlayModeServices playModeServices)
|
||||
{
|
||||
_manifest = manifest;
|
||||
_playModeServices = playModeServices;
|
||||
}
|
||||
internal override void Start()
|
||||
{
|
||||
_steps = ESteps.InitVerify;
|
||||
_verifyStartTime = UnityEngine.Time.realtimeSinceStartup;
|
||||
}
|
||||
internal override void Update()
|
||||
{
|
||||
if (_steps == ESteps.None || _steps == ESteps.Done)
|
||||
return;
|
||||
|
||||
if (_steps == ESteps.InitVerify)
|
||||
{
|
||||
int bundleCount = _manifest.BundleList.Count;
|
||||
VerifySuccessList = new List<VerifyInfo>(bundleCount);
|
||||
VerifyFailList = new List<VerifyInfo>(bundleCount);
|
||||
|
||||
// 设置同时验证的最大数
|
||||
_verifyMaxNum = bundleCount;
|
||||
_verifyTotalCount = _waitingList.Count;
|
||||
|
||||
_waitingList = new List<VerifyInfo>(bundleCount);
|
||||
_verifyingList = new List<VerifyInfo>(_verifyMaxNum);
|
||||
_steps = ESteps.PrepareVerify;
|
||||
}
|
||||
|
||||
if (_steps == ESteps.PrepareVerify)
|
||||
{
|
||||
foreach (var patchBundle in _manifest.BundleList)
|
||||
{
|
||||
if (CacheSystem.IsCached(patchBundle))
|
||||
continue;
|
||||
|
||||
bool isBuildinFile = _playModeServices.IsBuildinPatchBundle(patchBundle);
|
||||
VerifyInfo verifyInfo = new VerifyInfo(isBuildinFile, patchBundle);
|
||||
_waitingList.Add(verifyInfo);
|
||||
}
|
||||
_steps = ESteps.UpdateVerify;
|
||||
}
|
||||
|
||||
if (_steps == ESteps.UpdateVerify)
|
||||
{
|
||||
Progress = GetVerifierProgress();
|
||||
if (_waitingList.Count == 0 && _verifyingList.Count == 0)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Succeed;
|
||||
float costTime = UnityEngine.Time.realtimeSinceStartup - _verifyStartTime;
|
||||
YooLogger.Log($"Verify elapsed time {costTime:f1} seconds");
|
||||
}
|
||||
|
||||
for (int i = _waitingList.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (OperationSystem.IsBusy)
|
||||
break;
|
||||
|
||||
if (_verifyingList.Count >= _verifyMaxNum)
|
||||
break;
|
||||
|
||||
var verifyIno = _waitingList[i];
|
||||
VerifyFileWithoutThread(verifyIno);
|
||||
_waitingList.RemoveAt(i);
|
||||
_verifyingList.Add(verifyIno);
|
||||
}
|
||||
|
||||
_verifyingList.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
private float GetVerifierProgress()
|
||||
{
|
||||
if (_verifyTotalCount == 0)
|
||||
return 1f;
|
||||
return (float)(VerifySuccessList.Count + VerifyFailList.Count) / _verifyTotalCount;
|
||||
}
|
||||
private void VerifyFileWithoutThread(VerifyInfo verifyIno)
|
||||
{
|
||||
var verifyResult = CacheSystem.VerifyAndCacheLocalBundleFile(verifyIno.VerifyBundle, CacheSystem.InitVerifyLevel);
|
||||
if (verifyResult == EVerifyResult.Succeed)
|
||||
{
|
||||
VerifySuccessList.Add(verifyIno);
|
||||
}
|
||||
else
|
||||
{
|
||||
VerifyFailList.Add(verifyIno);
|
||||
|
||||
// 删除验证失败的缓存文件
|
||||
if (File.Exists(verifyIno.VerifyBundle.CachedFilePath))
|
||||
{
|
||||
YooLogger.Warning($"Delete verify failed bundle file : {verifyIno.VerifyBundle.CachedFilePath}");
|
||||
File.Delete(verifyIno.VerifyBundle.CachedFilePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -47,7 +47,7 @@ namespace YooAsset
|
||||
|
||||
/// <summary>
|
||||
/// 联机模式的更新清单操作
|
||||
/// 注意:优先加载沙盒里缓存的清单文件,如果有变化就更新远端清单文件,并保存到本地。
|
||||
/// 注意:优先加载沙盒里缓存的清单文件,如果缓存没找到就下载远端清单文件,并保存到本地。
|
||||
/// </summary>
|
||||
internal sealed class HostPlayModeUpdatePackageManifestOperation : UpdatePackageManifestOperation
|
||||
{
|
||||
@@ -59,7 +59,6 @@ namespace YooAsset
|
||||
DownloadManifest,
|
||||
LoadCacheManifest,
|
||||
CheckDeserializeManifest,
|
||||
VerifyPackage,
|
||||
Done,
|
||||
}
|
||||
|
||||
@@ -70,7 +69,6 @@ namespace YooAsset
|
||||
private LoadCacheManifestOperation _tryLoadCacheManifestOp;
|
||||
private LoadCacheManifestOperation _loadCacheManifestOp;
|
||||
private DownloadManifestOperation _downloadManifestOp;
|
||||
private VerifyPackageOperation _verifyOperation;
|
||||
private ESteps _steps = ESteps.None;
|
||||
|
||||
|
||||
@@ -118,7 +116,8 @@ namespace YooAsset
|
||||
if (_tryLoadCacheManifestOp.Status == EOperationStatus.Succeed)
|
||||
{
|
||||
_impl.ActiveManifest = _tryLoadCacheManifestOp.Manifest;
|
||||
_steps = ESteps.VerifyPackage;
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Succeed;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -163,7 +162,8 @@ namespace YooAsset
|
||||
if (_loadCacheManifestOp.Status == EOperationStatus.Succeed)
|
||||
{
|
||||
_impl.ActiveManifest = _loadCacheManifestOp.Manifest;
|
||||
_steps = ESteps.VerifyPackage;
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Succeed;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -172,22 +172,6 @@ namespace YooAsset
|
||||
Error = _loadCacheManifestOp.Error;
|
||||
}
|
||||
}
|
||||
|
||||
if (_steps == ESteps.VerifyPackage)
|
||||
{
|
||||
if (_verifyOperation == null)
|
||||
{
|
||||
_verifyOperation = VerifyPackageOperation.CreateOperation(_impl.ActiveManifest, _impl);
|
||||
OperationSystem.StartOperation(_verifyOperation);
|
||||
}
|
||||
|
||||
Progress = _verifyOperation.Progress;
|
||||
if (_verifyOperation.IsDone)
|
||||
{
|
||||
_steps = ESteps.Done;
|
||||
Status = EOperationStatus.Succeed;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -41,26 +41,72 @@ namespace YooAsset
|
||||
/// </summary>
|
||||
public string[] Tags;
|
||||
|
||||
/// <summary>
|
||||
/// 引用该资源包的ID列表
|
||||
/// </summary>
|
||||
public int[] ReferenceIDs;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 所属的包裹名称
|
||||
/// </summary>
|
||||
private string _packageName;
|
||||
public string PackageName { private set; get; }
|
||||
|
||||
/// <summary>
|
||||
/// 缓存文件路径
|
||||
/// 缓存GUID
|
||||
/// </summary>
|
||||
private string _cachedFilePath;
|
||||
public string CachedFilePath
|
||||
public string CacheGUID
|
||||
{
|
||||
get { return FileHash; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 缓存的数据文件路径
|
||||
/// </summary>
|
||||
private string _cachedDataFilePath;
|
||||
public string CachedDataFilePath
|
||||
{
|
||||
get
|
||||
{
|
||||
if (string.IsNullOrEmpty(_cachedFilePath) == false)
|
||||
return _cachedFilePath;
|
||||
if (string.IsNullOrEmpty(_cachedDataFilePath) == false)
|
||||
return _cachedDataFilePath;
|
||||
|
||||
string cacheRoot = PersistentHelper.GetCacheFolderPath(_packageName);
|
||||
_cachedFilePath = $"{cacheRoot}/{FileName}";
|
||||
return _cachedFilePath;
|
||||
string cacheRoot = PersistentHelper.GetCacheFolderPath(PackageName);
|
||||
_cachedDataFilePath = $"{cacheRoot}/{CacheGUID}/{YooAssetSettings.CacheBundleDataFileName}{_fileExtension}";
|
||||
return _cachedDataFilePath;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 缓存的信息文件路径
|
||||
/// </summary>
|
||||
private string _cachedInfoFilePath;
|
||||
public string CachedInfoFilePath
|
||||
{
|
||||
get
|
||||
{
|
||||
if (string.IsNullOrEmpty(_cachedInfoFilePath) == false)
|
||||
return _cachedInfoFilePath;
|
||||
|
||||
string cacheRoot = PersistentHelper.GetCacheFolderPath(PackageName);
|
||||
_cachedInfoFilePath = $"{cacheRoot}/{CacheGUID}/{YooAssetSettings.CacheBundleInfoFileName}";
|
||||
return _cachedInfoFilePath;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 临时的数据文件路径
|
||||
/// </summary>
|
||||
private string _tempDataFilePath;
|
||||
public string TempDataFilePath
|
||||
{
|
||||
get
|
||||
{
|
||||
if (string.IsNullOrEmpty(_tempDataFilePath) == false)
|
||||
return _tempDataFilePath;
|
||||
|
||||
_tempDataFilePath = $"{CachedDataFilePath}.temp";
|
||||
return _tempDataFilePath;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,16 +141,16 @@ namespace YooAsset
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 缓存查询Key
|
||||
/// 文件后缀名
|
||||
/// </summary>
|
||||
private string _cacheKey;
|
||||
public string CacheKey
|
||||
private string _fileExtension;
|
||||
public string FileExtension
|
||||
{
|
||||
get
|
||||
{
|
||||
if (string.IsNullOrEmpty(_cacheKey))
|
||||
if (string.IsNullOrEmpty(_fileExtension))
|
||||
throw new Exception("Should never get here !");
|
||||
return _cacheKey;
|
||||
return _fileExtension;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,9 +164,9 @@ namespace YooAsset
|
||||
/// </summary>
|
||||
public void ParseBundle(string packageName, int nameStype)
|
||||
{
|
||||
_packageName = packageName;
|
||||
_cacheKey = $"{packageName}-{FileHash}";
|
||||
_fileName = PatchManifest.CreateBundleFileName(nameStype, BundleName, FileHash, IsRawFile);
|
||||
PackageName = packageName;
|
||||
_fileExtension = PatchManifestTools.GetRemoteBundleFileExtension(BundleName);
|
||||
_fileName = PatchManifestTools.GetRemoteBundleFileName(nameStype, BundleName, _fileExtension, FileHash);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -220,6 +220,22 @@ namespace YooAsset
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取资源包名称
|
||||
/// </summary>
|
||||
public string GetBundleName(int bundleID)
|
||||
{
|
||||
if (bundleID >= 0 && bundleID < BundleList.Count)
|
||||
{
|
||||
var patchBundle = BundleList[bundleID];
|
||||
return patchBundle.BundleName;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception($"Invalid bundle id : {bundleID}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 尝试获取补丁资源
|
||||
/// </summary>
|
||||
@@ -239,11 +255,11 @@ namespace YooAsset
|
||||
/// <summary>
|
||||
/// 是否包含资源文件
|
||||
/// </summary>
|
||||
public bool IsIncludeBundleFile(string fileName)
|
||||
public bool IsIncludeBundleFile(string cacheGUID)
|
||||
{
|
||||
foreach (var patchBundle in BundleList)
|
||||
{
|
||||
if (patchBundle.FileName == fileName)
|
||||
if (patchBundle.CacheGUID == cacheGUID)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -292,28 +308,6 @@ namespace YooAsset
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成Bundle文件的正式名称
|
||||
/// </summary>
|
||||
public static string CreateBundleFileName(int nameStyle, string bundleName, string fileHash, bool isRawFile)
|
||||
{
|
||||
if (nameStyle == 1) //HashName
|
||||
{
|
||||
string fileExtension = isRawFile ? YooAssetSettingsData.Setting.RawFileVariant : YooAssetSettingsData.Setting.AssetBundleFileVariant;
|
||||
return StringUtility.Format("{0}.{1}", fileHash, fileExtension);
|
||||
}
|
||||
else if (nameStyle == 4) //BundleName_HashName
|
||||
{
|
||||
string fileName = bundleName.Remove(bundleName.LastIndexOf('.'));
|
||||
string fileExtension = isRawFile ? YooAssetSettingsData.Setting.RawFileVariant : YooAssetSettingsData.Setting.AssetBundleFileVariant;
|
||||
return StringUtility.Format("{0}_{1}.{2}", fileName, fileHash, fileExtension);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException($"Invalid name style : {nameStyle}");
|
||||
}
|
||||
}
|
||||
|
||||
#region 调试方法
|
||||
[Conditional("DEBUG")]
|
||||
private void DebugCheckLocation(string location)
|
||||
|
||||
@@ -8,6 +8,8 @@ namespace YooAsset
|
||||
{
|
||||
internal static class PatchManifestTools
|
||||
{
|
||||
|
||||
#if UNITY_EDITOR
|
||||
/// <summary>
|
||||
/// 序列化(JSON文件)
|
||||
/// </summary>
|
||||
@@ -63,6 +65,7 @@ namespace YooAsset
|
||||
buffer.WriteBool(patchBundle.IsRawFile);
|
||||
buffer.WriteByte(patchBundle.LoadMethod);
|
||||
buffer.WriteUTF8Array(patchBundle.Tags);
|
||||
buffer.WriteInt32Array(patchBundle.ReferenceIDs);
|
||||
}
|
||||
|
||||
// 写入文件流
|
||||
@@ -125,6 +128,7 @@ namespace YooAsset
|
||||
patchBundle.IsRawFile = buffer.ReadBool();
|
||||
patchBundle.LoadMethod = buffer.ReadByte();
|
||||
patchBundle.Tags = buffer.ReadUTF8Array();
|
||||
patchBundle.ReferenceIDs = buffer.ReadInt32Array();
|
||||
manifest.BundleList.Add(patchBundle);
|
||||
}
|
||||
}
|
||||
@@ -151,5 +155,39 @@ namespace YooAsset
|
||||
|
||||
return manifest;
|
||||
}
|
||||
#endif
|
||||
|
||||
public static string GetRemoteBundleFileExtension(string bundleName)
|
||||
{
|
||||
string fileExtension = Path.GetExtension(bundleName);
|
||||
return fileExtension;
|
||||
}
|
||||
public static string GetRemoteBundleFileName(int nameStyle, string bundleName, string fileExtension, string fileHash)
|
||||
{
|
||||
if (nameStyle == 1) //HashName
|
||||
{
|
||||
return StringUtility.Format("{0}{1}", fileHash, fileExtension);
|
||||
}
|
||||
else if (nameStyle == 4) //BundleName_HashName
|
||||
{
|
||||
string fileName = bundleName.Remove(bundleName.LastIndexOf('.'));
|
||||
return StringUtility.Format("{0}_{1}{2}", fileName, fileHash, fileExtension);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException($"Invalid name style : {nameStyle}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取解压BundleInfo
|
||||
/// </summary>
|
||||
public static BundleInfo GetUnpackInfo(PatchBundle patchBundle)
|
||||
{
|
||||
// 注意:我们把流加载路径指定为远端下载地址
|
||||
string streamingPath = PathHelper.ConvertToWWWPath(patchBundle.StreamingFilePath);
|
||||
BundleInfo bundleInfo = new BundleInfo(patchBundle, BundleInfo.ELoadMode.LoadFromStreaming, streamingPath, streamingPath);
|
||||
return bundleInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -56,12 +56,6 @@ namespace YooAsset
|
||||
OperationSystem.StartOperation(operation);
|
||||
return operation;
|
||||
}
|
||||
CheckPackageContentsOperation IPlayModeServices.CheckPackageContentsOperation(string packageVersion)
|
||||
{
|
||||
var operation = new EditorSimulateModeCheckPackageContentsOperation();
|
||||
OperationSystem.StartOperation(operation);
|
||||
return operation;
|
||||
}
|
||||
|
||||
PatchDownloaderOperation IPlayModeServices.CreatePatchDownloaderByAll(int downloadingMaxNumber, int failedTryAgain, int timeout)
|
||||
{
|
||||
@@ -101,6 +95,10 @@ namespace YooAsset
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
string IBundleServices.GetBundleName(int bundleID)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
bool IBundleServices.IsServicesValid()
|
||||
{
|
||||
return _activeManifest != null;
|
||||
|
||||
@@ -4,7 +4,7 @@ using System.Collections.Generic;
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
internal class HostPlayModeImpl : IPlayModeServices, IBundleServices
|
||||
internal class HostPlayModeImpl : IPlayModeServices, IBundleServices, IRemoteServices
|
||||
{
|
||||
private PatchManifest _activeManifest;
|
||||
|
||||
@@ -31,16 +31,6 @@ namespace YooAsset
|
||||
return operation;
|
||||
}
|
||||
|
||||
// WEB相关
|
||||
public string GetPatchDownloadMainURL(string fileName)
|
||||
{
|
||||
return $"{_defaultHostServer}/{fileName}";
|
||||
}
|
||||
public string GetPatchDownloadFallbackURL(string fileName)
|
||||
{
|
||||
return $"{_fallbackHostServer}/{fileName}";
|
||||
}
|
||||
|
||||
// 下载相关
|
||||
private List<BundleInfo> ConvertToDownloadList(List<PatchBundle> downloadList)
|
||||
{
|
||||
@@ -54,8 +44,8 @@ namespace YooAsset
|
||||
}
|
||||
private BundleInfo ConvertToDownloadInfo(PatchBundle patchBundle)
|
||||
{
|
||||
string remoteMainURL = GetPatchDownloadMainURL(patchBundle.FileName);
|
||||
string remoteFallbackURL = GetPatchDownloadFallbackURL(patchBundle.FileName);
|
||||
string remoteMainURL = GetRemoteMainURL(patchBundle.FileName);
|
||||
string remoteFallbackURL = GetRemoteFallbackURL(patchBundle.FileName);
|
||||
BundleInfo bundleInfo = new BundleInfo(patchBundle, BundleInfo.ELoadMode.LoadFromRemote, remoteMainURL, remoteFallbackURL);
|
||||
return bundleInfo;
|
||||
}
|
||||
@@ -71,14 +61,22 @@ namespace YooAsset
|
||||
}
|
||||
return result;
|
||||
}
|
||||
public static BundleInfo ConvertToUnpackInfo(PatchBundle patchBundle)
|
||||
private BundleInfo ConvertToUnpackInfo(PatchBundle patchBundle)
|
||||
{
|
||||
// 注意:我们把流加载路径指定为远端下载地址
|
||||
string streamingPath = PathHelper.ConvertToWWWPath(patchBundle.StreamingFilePath);
|
||||
BundleInfo bundleInfo = new BundleInfo(patchBundle, BundleInfo.ELoadMode.LoadFromStreaming, streamingPath, streamingPath);
|
||||
return bundleInfo;
|
||||
return PatchManifestTools.GetUnpackInfo(patchBundle);
|
||||
}
|
||||
|
||||
#region IRemoteServices接口
|
||||
public string GetRemoteMainURL(string fileName)
|
||||
{
|
||||
return $"{_defaultHostServer}/{fileName}";
|
||||
}
|
||||
public string GetRemoteFallbackURL(string fileName)
|
||||
{
|
||||
return $"{_fallbackHostServer}/{fileName}";
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region IPlayModeServices接口
|
||||
public PatchManifest ActiveManifest
|
||||
{
|
||||
@@ -97,7 +95,11 @@ namespace YooAsset
|
||||
{
|
||||
return _queryServices.QueryStreamingAssets(patchBundle.FileName);
|
||||
}
|
||||
|
||||
public bool IsCachedPatchBundle(PatchBundle patchBundle)
|
||||
{
|
||||
return CacheSystem.IsCached(patchBundle.PackageName, patchBundle.CacheGUID);
|
||||
}
|
||||
|
||||
UpdatePackageVersionOperation IPlayModeServices.UpdatePackageVersionAsync(bool appendTimeTicks, int timeout)
|
||||
{
|
||||
var operation = new HostPlayModeUpdatePackageVersionOperation(this, _packageName, appendTimeTicks, timeout);
|
||||
@@ -116,12 +118,6 @@ namespace YooAsset
|
||||
OperationSystem.StartOperation(operation);
|
||||
return operation;
|
||||
}
|
||||
CheckPackageContentsOperation IPlayModeServices.CheckPackageContentsOperation(string packageVersion)
|
||||
{
|
||||
var operation = new HostPlayModeCheckPackageContentsOperation(this, _packageName, packageVersion);
|
||||
OperationSystem.StartOperation(operation);
|
||||
return operation;
|
||||
}
|
||||
|
||||
PatchDownloaderOperation IPlayModeServices.CreatePatchDownloaderByAll(int downloadingMaxNumber, int failedTryAgain, int timeout)
|
||||
{
|
||||
@@ -135,7 +131,7 @@ namespace YooAsset
|
||||
foreach (var patchBundle in patchManifest.BundleList)
|
||||
{
|
||||
// 忽略缓存文件
|
||||
if (CacheSystem.IsCached(patchBundle))
|
||||
if (IsCachedPatchBundle(patchBundle))
|
||||
continue;
|
||||
|
||||
// 忽略APP资源
|
||||
@@ -160,7 +156,7 @@ namespace YooAsset
|
||||
foreach (var patchBundle in patchManifest.BundleList)
|
||||
{
|
||||
// 忽略缓存文件
|
||||
if (CacheSystem.IsCached(patchBundle))
|
||||
if (IsCachedPatchBundle(patchBundle))
|
||||
continue;
|
||||
|
||||
// 忽略APP资源
|
||||
@@ -221,7 +217,7 @@ namespace YooAsset
|
||||
foreach (var patchBundle in checkList)
|
||||
{
|
||||
// 忽略缓存文件
|
||||
if (CacheSystem.IsCached(patchBundle))
|
||||
if (IsCachedPatchBundle(patchBundle))
|
||||
continue;
|
||||
|
||||
// 忽略APP资源
|
||||
@@ -246,7 +242,7 @@ namespace YooAsset
|
||||
foreach (var patchBundle in patchManifest.BundleList)
|
||||
{
|
||||
// 忽略缓存文件
|
||||
if (CacheSystem.IsCached(patchBundle))
|
||||
if (IsCachedPatchBundle(patchBundle))
|
||||
continue;
|
||||
|
||||
if (IsBuildinPatchBundle(patchBundle))
|
||||
@@ -270,7 +266,7 @@ namespace YooAsset
|
||||
foreach (var patchBundle in patchManifest.BundleList)
|
||||
{
|
||||
// 忽略缓存文件
|
||||
if (CacheSystem.IsCached(patchBundle))
|
||||
if (IsCachedPatchBundle(patchBundle))
|
||||
continue;
|
||||
|
||||
// 查询DLC资源
|
||||
@@ -294,7 +290,7 @@ namespace YooAsset
|
||||
throw new Exception("Should never get here !");
|
||||
|
||||
// 查询沙盒资源
|
||||
if (CacheSystem.IsCached(patchBundle))
|
||||
if (IsCachedPatchBundle(patchBundle))
|
||||
{
|
||||
BundleInfo bundleInfo = new BundleInfo(patchBundle, BundleInfo.ELoadMode.LoadFromCache);
|
||||
return bundleInfo;
|
||||
@@ -334,6 +330,10 @@ namespace YooAsset
|
||||
}
|
||||
return result.ToArray();
|
||||
}
|
||||
string IBundleServices.GetBundleName(int bundleID)
|
||||
{
|
||||
return _activeManifest.GetBundleName(bundleID);
|
||||
}
|
||||
bool IBundleServices.IsServicesValid()
|
||||
{
|
||||
return _activeManifest != null;
|
||||
|
||||
@@ -56,12 +56,6 @@ namespace YooAsset
|
||||
OperationSystem.StartOperation(operation);
|
||||
return operation;
|
||||
}
|
||||
CheckPackageContentsOperation IPlayModeServices.CheckPackageContentsOperation(string packageVersion)
|
||||
{
|
||||
var operation = new OfflinePlayModeCheckPackageContentsOperation();
|
||||
OperationSystem.StartOperation(operation);
|
||||
return operation;
|
||||
}
|
||||
|
||||
PatchDownloaderOperation IPlayModeServices.CreatePatchDownloaderByAll(int downloadingMaxNumber, int failedTryAgain, int timeout)
|
||||
{
|
||||
@@ -93,7 +87,7 @@ namespace YooAsset
|
||||
throw new Exception("Should never get here !");
|
||||
|
||||
// 查询沙盒资源
|
||||
if (CacheSystem.IsCached(patchBundle))
|
||||
if (CacheSystem.IsCached(patchBundle.PackageName, patchBundle.CacheGUID))
|
||||
{
|
||||
BundleInfo bundleInfo = new BundleInfo(patchBundle, BundleInfo.ELoadMode.LoadFromCache);
|
||||
return bundleInfo;
|
||||
@@ -129,6 +123,10 @@ namespace YooAsset
|
||||
}
|
||||
return result.ToArray();
|
||||
}
|
||||
string IBundleServices.GetBundleName(int bundleID)
|
||||
{
|
||||
return _activeManifest.GetBundleName(bundleID);
|
||||
}
|
||||
bool IBundleServices.IsServicesValid()
|
||||
{
|
||||
return _activeManifest != null;
|
||||
|
||||
@@ -13,6 +13,11 @@ namespace YooAsset
|
||||
/// </summary>
|
||||
BundleInfo[] GetAllDependBundleInfos(AssetInfo assetPath);
|
||||
|
||||
/// <summary>
|
||||
/// 获取资源包名称
|
||||
/// </summary>
|
||||
string GetBundleName(int bundleID);
|
||||
|
||||
/// <summary>
|
||||
/// 服务接口是否有效
|
||||
/// </summary>
|
||||
|
||||
@@ -28,11 +28,6 @@ namespace YooAsset
|
||||
/// </summary>
|
||||
PreDownloadPackageOperation PreDownloadPackageAsync(string packageVersion, int timeout);
|
||||
|
||||
/// <summary>
|
||||
/// 检查包裹内容的完整性
|
||||
/// </summary>
|
||||
CheckPackageContentsOperation CheckPackageContentsOperation(string packageVersion);
|
||||
|
||||
// 下载相关
|
||||
PatchDownloaderOperation CreatePatchDownloaderByAll(int downloadingMaxNumber, int failedTryAgain, int timeout);
|
||||
PatchDownloaderOperation CreatePatchDownloaderByTags(string[] tags, int downloadingMaxNumber, int failedTryAgain, int timeout);
|
||||
|
||||
9
Assets/YooAsset/Runtime/Services/IRemoteServices.cs
Normal file
9
Assets/YooAsset/Runtime/Services/IRemoteServices.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
|
||||
namespace YooAsset
|
||||
{
|
||||
internal interface IRemoteServices
|
||||
{
|
||||
string GetRemoteMainURL(string fileName);
|
||||
string GetRemoteFallbackURL(string fileName);
|
||||
}
|
||||
}
|
||||
11
Assets/YooAsset/Runtime/Services/IRemoteServices.cs.meta
Normal file
11
Assets/YooAsset/Runtime/Services/IRemoteServices.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 55b92092303a8d44280c107e6c5a8379
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -5,26 +5,11 @@ namespace YooAsset
|
||||
[CreateAssetMenu(fileName = "YooAssetSettings", menuName = "YooAsset/Create Settings")]
|
||||
internal class YooAssetSettings : ScriptableObject
|
||||
{
|
||||
/// <summary>
|
||||
/// AssetBundle文件的后缀名
|
||||
/// </summary>
|
||||
public string AssetBundleFileVariant = "bundle";
|
||||
|
||||
/// <summary>
|
||||
/// 原生文件的后缀名
|
||||
/// </summary>
|
||||
public string RawFileVariant = "rawfile";
|
||||
|
||||
/// <summary>
|
||||
/// 清单文件名称
|
||||
/// </summary>
|
||||
public string PatchManifestFileName = "PatchManifest";
|
||||
|
||||
/// <summary>
|
||||
/// 资源包名正规化(移除路径分隔符)
|
||||
/// </summary>
|
||||
public bool RegularBundleName = true;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 清单文件头标记
|
||||
@@ -39,7 +24,18 @@ namespace YooAsset
|
||||
/// <summary>
|
||||
/// 清单文件格式版本
|
||||
/// </summary>
|
||||
public const string PatchManifestFileVersion = "1.4.0";
|
||||
public const string PatchManifestFileVersion = "1.4.6";
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 缓存的数据文件名称
|
||||
/// </summary>
|
||||
public const string CacheBundleDataFileName = "__data";
|
||||
|
||||
/// <summary>
|
||||
/// 缓存的信息文件名称
|
||||
/// </summary>
|
||||
public const string CacheBundleInfoFileName = "__info";
|
||||
|
||||
|
||||
/// <summary>
|
||||
@@ -52,20 +48,9 @@ namespace YooAsset
|
||||
/// </summary>
|
||||
public const string ReportFileName = "BuildReport";
|
||||
|
||||
/// <summary>
|
||||
/// Unity着色器资源包名称
|
||||
/// </summary>
|
||||
public const string UnityShadersBundleName = "unityshaders";
|
||||
|
||||
/// <summary>
|
||||
/// 内置资源目录名称
|
||||
/// </summary>
|
||||
public const string StreamingAssetsBuildinFolder = "BuildinFiles";
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 忽略的文件类型
|
||||
/// </summary>
|
||||
public static readonly string[] IgnoreFileExtensions = { "", ".so", ".dll", ".cs", ".js", ".boo", ".meta", ".cginc" };
|
||||
}
|
||||
}
|
||||
@@ -71,18 +71,5 @@ namespace YooAsset
|
||||
{
|
||||
return $"{Setting.PatchManifestFileName}_{packageName}.version";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取着色器资源包全名称(包含后缀名)
|
||||
/// </summary>
|
||||
public static string GetUnityShadersBundleFullName(bool uniqueBundleName, string packageName)
|
||||
{
|
||||
string shareBundleName;
|
||||
if (uniqueBundleName)
|
||||
shareBundleName = $"{packageName.ToLower()}_{YooAssetSettings.UnityShadersBundleName}.{Setting.AssetBundleFileVariant}";
|
||||
else
|
||||
shareBundleName = $"{YooAssetSettings.UnityShadersBundleName}.{Setting.AssetBundleFileVariant}";
|
||||
return shareBundleName.ToLower();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,14 @@ namespace YooAsset
|
||||
get { return _buffer.Length; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清空缓冲区
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
_index = 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将有效数据写入文件流
|
||||
/// </summary>
|
||||
|
||||
@@ -10,7 +10,7 @@ public class PackEffectTexture : IPackRule
|
||||
{
|
||||
private const string PackDirectory = "Assets/Effect/Textures/";
|
||||
|
||||
string IPackRule.GetBundleName(PackRuleData data)
|
||||
PackRuleResult IPackRule.GetPackRuleResult(PackRuleData data)
|
||||
{
|
||||
string assetPath = data.AssetPath;
|
||||
if (assetPath.StartsWith(PackDirectory) == false)
|
||||
@@ -18,6 +18,43 @@ public class PackEffectTexture : IPackRule
|
||||
|
||||
string assetName = Path.GetFileName(assetPath).ToLower();
|
||||
string firstChar = assetName.Substring(0, 1);
|
||||
return $"{PackDirectory}effect_texture_{firstChar}";
|
||||
string bundleName = $"{PackDirectory}effect_texture_{firstChar}";
|
||||
var packRuleResult = new PackRuleResult(bundleName, DefaultPackRule.AssetBundleFileExtension);
|
||||
return packRuleResult;
|
||||
}
|
||||
|
||||
bool IPackRule.IsRawFilePackRule()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
[DisplayName("打包视频(自定义)")]
|
||||
public class PackVideo : IPackRule
|
||||
{
|
||||
public PackRuleResult GetPackRuleResult(PackRuleData data)
|
||||
{
|
||||
string bundleName = RemoveExtension(data.AssetPath);
|
||||
string fileExtension = Path.GetExtension(data.AssetPath);
|
||||
fileExtension = fileExtension.Remove(0, 1);
|
||||
PackRuleResult result = new PackRuleResult(bundleName, fileExtension);
|
||||
return result;
|
||||
}
|
||||
|
||||
bool IPackRule.IsRawFilePackRule()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
private string RemoveExtension(string str)
|
||||
{
|
||||
if (string.IsNullOrEmpty(str))
|
||||
return str;
|
||||
|
||||
int index = str.LastIndexOf(".");
|
||||
if (index == -1)
|
||||
return str;
|
||||
else
|
||||
return str.Remove(index); //"assets/config/test.unity3d" --> "assets/config/test"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root Version="2.3">
|
||||
<Common AutoAddressable="True" UniqueBundleName="False" ShowPackageView="False" ShowEditorAlias="False" />
|
||||
<Package PackageName="DefaultPackage" PackageDesc="">
|
||||
<Group GroupName="battle" GroupDesc="" AssetTags="">
|
||||
<Collector CollectPath="Assets/Samples/Space Shooter/GameRes/Effect" CollectGUID="80d76514758554baaa96a9efffe9f3ef" CollectType="MainAssetCollector" AddressRule="AddressByFileName" PackRule="PackDirectory" FilterRule="CollectAll" UserData="" AssetTags="" />
|
||||
<Collector CollectPath="Assets/Samples/Space Shooter/GameRes/Entity" CollectGUID="4d7c84745db8e884f8020a8c5356e67c" CollectType="MainAssetCollector" AddressRule="AddressByFileName" PackRule="PackDirectory" FilterRule="CollectAll" UserData="" AssetTags="" />
|
||||
<Collector CollectPath="Assets/Samples/Space Shooter/GameRes/Audio" CollectGUID="306075fbe00b24251b6c889984a7a7d5" CollectType="MainAssetCollector" AddressRule="AddressByFileName" PackRule="PackDirectory" FilterRule="CollectAll" UserData="" AssetTags="" />
|
||||
</Group>
|
||||
<Group GroupName="shader" GroupDesc="" AssetTags="">
|
||||
<Collector CollectPath="Assets/Samples/Space Shooter/GameArt/ShaderVariants" CollectGUID="00781758c26692e40a9634ddeac838be" CollectType="MainAssetCollector" AddressRule="AddressByFileName" PackRule="PackShaderVariants" FilterRule="CollectShaderVariants" UserData="" AssetTags="" />
|
||||
</Group>
|
||||
<Group GroupName="scene" GroupDesc="" AssetTags="">
|
||||
<Collector CollectPath="Assets/Samples/Space Shooter/GameRes/Scene" CollectGUID="6070eae1192f2994887f2983a177d503" CollectType="MainAssetCollector" AddressRule="AddressByFileName" PackRule="PackSeparately" FilterRule="CollectAll" UserData="" AssetTags="" />
|
||||
</Group>
|
||||
<Group GroupName="ugui" GroupDesc="" AssetTags="">
|
||||
<Collector CollectPath="Assets/Samples/Space Shooter/GameRes/UIImage" CollectGUID="30c57db62bb02a24590e7046d3a9e33a" CollectType="MainAssetCollector" AddressRule="AddressByFileName" PackRule="PackDirectory" FilterRule="CollectAll" UserData="" AssetTags="" />
|
||||
<Collector CollectPath="Assets/Samples/Space Shooter/GameRes/UIPanel" CollectGUID="12d33f33f3a55224c9c747d7bffa1c68" CollectType="MainAssetCollector" AddressRule="AddressByFileName" PackRule="PackSeparately" FilterRule="CollectAll" UserData="" AssetTags="" />
|
||||
<Collector CollectPath="Assets/Samples/Space Shooter/GameRes/UISprite" CollectGUID="01865ad6f7c806147b6cb37f2d83bc96" CollectType="MainAssetCollector" AddressRule="AddressByFileName" PackRule="PackTopDirectory" FilterRule="CollectAll" UserData="" AssetTags="" />
|
||||
</Group>
|
||||
</Package>
|
||||
</root>
|
||||
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 08dafaa194a7143109cbe1c6403a2ec5
|
||||
guid: 218816e46e4f6304eaecd6fdc3a99f4d
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
@@ -32,6 +32,7 @@ MonoBehaviour:
|
||||
PackRuleName: PackDirectory
|
||||
FilterRuleName: CollectAll
|
||||
AssetTags:
|
||||
UserData:
|
||||
- CollectPath: Assets/Samples/Space Shooter/GameRes/Entity
|
||||
CollectorGUID: 4d7c84745db8e884f8020a8c5356e67c
|
||||
CollectorType: 0
|
||||
@@ -39,6 +40,7 @@ MonoBehaviour:
|
||||
PackRuleName: PackDirectory
|
||||
FilterRuleName: CollectAll
|
||||
AssetTags:
|
||||
UserData:
|
||||
- CollectPath: Assets/Samples/Space Shooter/GameRes/Audio
|
||||
CollectorGUID: 306075fbe00b24251b6c889984a7a7d5
|
||||
CollectorType: 0
|
||||
@@ -46,6 +48,7 @@ MonoBehaviour:
|
||||
PackRuleName: PackDirectory
|
||||
FilterRuleName: CollectAll
|
||||
AssetTags:
|
||||
UserData:
|
||||
- GroupName: shader
|
||||
GroupDesc:
|
||||
AssetTags:
|
||||
@@ -58,6 +61,7 @@ MonoBehaviour:
|
||||
PackRuleName: PackShaderVariants
|
||||
FilterRuleName: CollectShaderVariants
|
||||
AssetTags:
|
||||
UserData:
|
||||
- GroupName: scene
|
||||
GroupDesc:
|
||||
AssetTags:
|
||||
@@ -70,6 +74,7 @@ MonoBehaviour:
|
||||
PackRuleName: PackSeparately
|
||||
FilterRuleName: CollectAll
|
||||
AssetTags:
|
||||
UserData:
|
||||
- GroupName: ugui
|
||||
GroupDesc:
|
||||
AssetTags:
|
||||
@@ -82,6 +87,7 @@ MonoBehaviour:
|
||||
PackRuleName: PackDirectory
|
||||
FilterRuleName: CollectAll
|
||||
AssetTags:
|
||||
UserData:
|
||||
- CollectPath: Assets/Samples/Space Shooter/GameRes/UIPanel
|
||||
CollectorGUID: 12d33f33f3a55224c9c747d7bffa1c68
|
||||
CollectorType: 0
|
||||
@@ -89,6 +95,7 @@ MonoBehaviour:
|
||||
PackRuleName: PackSeparately
|
||||
FilterRuleName: CollectAll
|
||||
AssetTags:
|
||||
UserData:
|
||||
- CollectPath: Assets/Samples/Space Shooter/GameRes/UISprite
|
||||
CollectorGUID: 01865ad6f7c806147b6cb37f2d83bc96
|
||||
CollectorType: 0
|
||||
@@ -96,3 +103,4 @@ MonoBehaviour:
|
||||
PackRuleName: PackTopDirectory
|
||||
FilterRuleName: CollectAll
|
||||
AssetTags:
|
||||
UserData:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"ShaderTotalCount": 12,
|
||||
"VariantTotalCount": 16,
|
||||
"ShaderTotalCount": 13,
|
||||
"VariantTotalCount": 24,
|
||||
"ShaderVariantInfos": [
|
||||
{
|
||||
"AssetPath": "Resources/unity_builtin_extra",
|
||||
@@ -14,6 +14,109 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"AssetPath": "Resources/unity_builtin_extra",
|
||||
"ShaderName": "Standard",
|
||||
"ShaderVariantElements": [
|
||||
{
|
||||
"PassType": 4,
|
||||
"Keywords": [
|
||||
"DIRECTIONAL",
|
||||
"LIGHTPROBE_SH",
|
||||
"SHADOWS_SCREEN",
|
||||
"SHADOWS_SPLIT_SPHERES"
|
||||
]
|
||||
},
|
||||
{
|
||||
"PassType": 4,
|
||||
"Keywords": [
|
||||
"DIRECTIONAL",
|
||||
"LIGHTPROBE_SH",
|
||||
"SHADOWS_SCREEN",
|
||||
"SHADOWS_SPLIT_SPHERES",
|
||||
"_EMISSION"
|
||||
]
|
||||
},
|
||||
{
|
||||
"PassType": 4,
|
||||
"Keywords": [
|
||||
"DIRECTIONAL",
|
||||
"LIGHTPROBE_SH",
|
||||
"SHADOWS_SCREEN",
|
||||
"SHADOWS_SPLIT_SPHERES",
|
||||
"_NORMALMAP"
|
||||
]
|
||||
},
|
||||
{
|
||||
"PassType": 4,
|
||||
"Keywords": [
|
||||
"DIRECTIONAL",
|
||||
"LIGHTPROBE_SH",
|
||||
"SHADOWS_SCREEN",
|
||||
"SHADOWS_SPLIT_SPHERES",
|
||||
"_EMISSION",
|
||||
"_NORMALMAP"
|
||||
]
|
||||
},
|
||||
{
|
||||
"PassType": 8,
|
||||
"Keywords": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"PassType": 8,
|
||||
"Keywords": [
|
||||
"SHADOWS_DEPTH",
|
||||
"SHADOWS_SPLIT_SPHERES"
|
||||
]
|
||||
},
|
||||
{
|
||||
"PassType": 8,
|
||||
"Keywords": [
|
||||
"_EMISSION"
|
||||
]
|
||||
},
|
||||
{
|
||||
"PassType": 8,
|
||||
"Keywords": [
|
||||
"SHADOWS_DEPTH",
|
||||
"SHADOWS_SPLIT_SPHERES",
|
||||
"_EMISSION"
|
||||
]
|
||||
},
|
||||
{
|
||||
"PassType": 8,
|
||||
"Keywords": [
|
||||
"_NORMALMAP"
|
||||
]
|
||||
},
|
||||
{
|
||||
"PassType": 8,
|
||||
"Keywords": [
|
||||
"SHADOWS_DEPTH",
|
||||
"SHADOWS_SPLIT_SPHERES",
|
||||
"_NORMALMAP"
|
||||
]
|
||||
},
|
||||
{
|
||||
"PassType": 8,
|
||||
"Keywords": [
|
||||
"_EMISSION",
|
||||
"_NORMALMAP"
|
||||
]
|
||||
},
|
||||
{
|
||||
"PassType": 8,
|
||||
"Keywords": [
|
||||
"SHADOWS_DEPTH",
|
||||
"SHADOWS_SPLIT_SPHERES",
|
||||
"_EMISSION",
|
||||
"_NORMALMAP"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"AssetPath": "Resources/unity_builtin_extra",
|
||||
"ShaderName": "Skybox/Procedural",
|
||||
@@ -21,12 +124,23 @@
|
||||
{
|
||||
"PassType": 0,
|
||||
"Keywords": [
|
||||
"BILLBOARD_FACE_CAMERA_POS",
|
||||
"_SUNDISK_SIMPLE"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"AssetPath": "Resources/unity_builtin_extra",
|
||||
"ShaderName": "Legacy Shaders/Particles/Additive",
|
||||
"ShaderVariantElements": [
|
||||
{
|
||||
"PassType": 0,
|
||||
"Keywords": [
|
||||
""
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"AssetPath": "Resources/unity_builtin_extra",
|
||||
"ShaderName": "Hidden/Internal-GUITextureClip",
|
||||
@@ -87,18 +201,6 @@
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"AssetPath": "Resources/unity_builtin_extra",
|
||||
"ShaderName": "Hidden/Internal-GUIRoundedRectWithColorPerBorder",
|
||||
"ShaderVariantElements": [
|
||||
{
|
||||
"PassType": 0,
|
||||
"Keywords": [
|
||||
""
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"AssetPath": "Resources/unity_builtin_extra",
|
||||
"ShaderName": "Hidden/Internal-UIRAtlasBlitCopy",
|
||||
@@ -113,80 +215,37 @@
|
||||
},
|
||||
{
|
||||
"AssetPath": "Resources/unity_builtin_extra",
|
||||
"ShaderName": "Hidden/UIElements/EditorUIE",
|
||||
"ShaderName": "Hidden/Internal-GUIRoundedRectWithColorPerBorder",
|
||||
"ShaderVariantElements": [
|
||||
{
|
||||
"PassType": 0,
|
||||
"Keywords": [
|
||||
"BILLBOARD_FACE_CAMERA_POS"
|
||||
""
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"AssetPath": "Resources/unity_builtin_extra",
|
||||
"ShaderName": "Mobile/Diffuse",
|
||||
"ShaderName": "Mobile/Particles/Additive",
|
||||
"ShaderVariantElements": [
|
||||
{
|
||||
"PassType": 4,
|
||||
"Keywords": [
|
||||
"BILLBOARD_FACE_CAMERA_POS",
|
||||
"DIRECTIONAL",
|
||||
"LIGHTPROBE_SH",
|
||||
"SHADOWS_SCREEN",
|
||||
"SHADOWS_SOFT",
|
||||
"SHADOWS_SPLIT_SPHERES"
|
||||
]
|
||||
},
|
||||
{
|
||||
"PassType": 8,
|
||||
"PassType": 0,
|
||||
"Keywords": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"PassType": 8,
|
||||
"Keywords": [
|
||||
"SHADOWS_DEPTH",
|
||||
"SHADOWS_SOFT",
|
||||
"SHADOWS_SPLIT_SPHERES"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"AssetPath": "Assets/Samples/Basic Sample/GameArt/Shaders/StandardMobile.shader",
|
||||
"ShaderName": "Mobile/Standard",
|
||||
"AssetPath": "Resources/unity_builtin_extra",
|
||||
"ShaderName": "Unlit/Texture",
|
||||
"ShaderVariantElements": [
|
||||
{
|
||||
"PassType": 1,
|
||||
"PassType": 0,
|
||||
"Keywords": [
|
||||
"BILLBOARD_FACE_CAMERA_POS",
|
||||
"SHADOWS_SCREEN",
|
||||
"SHADOWS_SOFT",
|
||||
"SHADOWS_SPLIT_SPHERES",
|
||||
"_EMISSION",
|
||||
"_METALLICGLOSSMAP",
|
||||
"_NORMALMAP"
|
||||
]
|
||||
},
|
||||
{
|
||||
"PassType": 8,
|
||||
"Keywords": [
|
||||
"_EMISSION",
|
||||
"_METALLICGLOSSMAP",
|
||||
"_NORMALMAP"
|
||||
]
|
||||
},
|
||||
{
|
||||
"PassType": 8,
|
||||
"Keywords": [
|
||||
"SHADOWS_DEPTH",
|
||||
"SHADOWS_SOFT",
|
||||
"SHADOWS_SPLIT_SPHERES",
|
||||
"_EMISSION",
|
||||
"_METALLICGLOSSMAP",
|
||||
"_NORMALMAP"
|
||||
"SHADOWS_SPLIT_SPHERES"
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
@@ -13,10 +13,45 @@ ShaderVariantCollection:
|
||||
variants:
|
||||
- keywords:
|
||||
passType: 0
|
||||
- first: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0}
|
||||
second:
|
||||
variants:
|
||||
- keywords: DIRECTIONAL LIGHTPROBE_SH SHADOWS_SCREEN SHADOWS_SPLIT_SPHERES
|
||||
passType: 4
|
||||
- keywords: DIRECTIONAL LIGHTPROBE_SH SHADOWS_SCREEN SHADOWS_SPLIT_SPHERES
|
||||
_EMISSION
|
||||
passType: 4
|
||||
- keywords: DIRECTIONAL LIGHTPROBE_SH SHADOWS_SCREEN SHADOWS_SPLIT_SPHERES
|
||||
_NORMALMAP
|
||||
passType: 4
|
||||
- keywords: DIRECTIONAL LIGHTPROBE_SH SHADOWS_SCREEN SHADOWS_SPLIT_SPHERES
|
||||
_EMISSION _NORMALMAP
|
||||
passType: 4
|
||||
- keywords:
|
||||
passType: 8
|
||||
- keywords: SHADOWS_DEPTH SHADOWS_SPLIT_SPHERES
|
||||
passType: 8
|
||||
- keywords: _EMISSION
|
||||
passType: 8
|
||||
- keywords: SHADOWS_DEPTH SHADOWS_SPLIT_SPHERES _EMISSION
|
||||
passType: 8
|
||||
- keywords: _NORMALMAP
|
||||
passType: 8
|
||||
- keywords: SHADOWS_DEPTH SHADOWS_SPLIT_SPHERES _NORMALMAP
|
||||
passType: 8
|
||||
- keywords: _EMISSION _NORMALMAP
|
||||
passType: 8
|
||||
- keywords: SHADOWS_DEPTH SHADOWS_SPLIT_SPHERES _EMISSION _NORMALMAP
|
||||
passType: 8
|
||||
- first: {fileID: 106, guid: 0000000000000000f000000000000000, type: 0}
|
||||
second:
|
||||
variants:
|
||||
- keywords: BILLBOARD_FACE_CAMERA_POS _SUNDISK_SIMPLE
|
||||
- keywords: _SUNDISK_SIMPLE
|
||||
passType: 0
|
||||
- first: {fileID: 200, guid: 0000000000000000f000000000000000, type: 0}
|
||||
second:
|
||||
variants:
|
||||
- keywords:
|
||||
passType: 0
|
||||
- first: {fileID: 9000, guid: 0000000000000000f000000000000000, type: 0}
|
||||
second:
|
||||
@@ -43,39 +78,23 @@ ShaderVariantCollection:
|
||||
variants:
|
||||
- keywords:
|
||||
passType: 0
|
||||
- first: {fileID: 9006, guid: 0000000000000000f000000000000000, type: 0}
|
||||
second:
|
||||
variants:
|
||||
- keywords:
|
||||
passType: 0
|
||||
- first: {fileID: 9007, guid: 0000000000000000f000000000000000, type: 0}
|
||||
second:
|
||||
variants:
|
||||
- keywords:
|
||||
passType: 0
|
||||
- first: {fileID: 9101, guid: 0000000000000000f000000000000000, type: 0}
|
||||
- first: {fileID: 10720, guid: 0000000000000000f000000000000000, type: 0}
|
||||
second:
|
||||
variants:
|
||||
- keywords:
|
||||
passType: 0
|
||||
- first: {fileID: 9103, guid: 0000000000000000f000000000000000, type: 0}
|
||||
- first: {fileID: 10752, guid: 0000000000000000f000000000000000, type: 0}
|
||||
second:
|
||||
variants:
|
||||
- keywords: BILLBOARD_FACE_CAMERA_POS
|
||||
- keywords: SHADOWS_SCREEN SHADOWS_SPLIT_SPHERES
|
||||
passType: 0
|
||||
- first: {fileID: 10703, guid: 0000000000000000f000000000000000, type: 0}
|
||||
second:
|
||||
variants:
|
||||
- keywords: BILLBOARD_FACE_CAMERA_POS DIRECTIONAL LIGHTPROBE_SH SHADOWS_SCREEN
|
||||
SHADOWS_SOFT SHADOWS_SPLIT_SPHERES
|
||||
passType: 4
|
||||
- keywords:
|
||||
passType: 8
|
||||
- keywords: SHADOWS_DEPTH SHADOWS_SOFT SHADOWS_SPLIT_SPHERES
|
||||
passType: 8
|
||||
- first: {fileID: 4800000, guid: ba67c8b1d5e59dc428ad9fc9270f8353, type: 3}
|
||||
second:
|
||||
variants:
|
||||
- keywords: BILLBOARD_FACE_CAMERA_POS SHADOWS_SCREEN SHADOWS_SOFT SHADOWS_SPLIT_SPHERES
|
||||
_EMISSION _METALLICGLOSSMAP _NORMALMAP
|
||||
passType: 1
|
||||
- keywords: _EMISSION _METALLICGLOSSMAP _NORMALMAP
|
||||
passType: 8
|
||||
- keywords: SHADOWS_DEPTH SHADOWS_SOFT SHADOWS_SPLIT_SPHERES _EMISSION _METALLICGLOSSMAP
|
||||
_NORMALMAP
|
||||
passType: 8
|
||||
|
||||
@@ -42,7 +42,8 @@ public class FileStreamEncryption : IEncryptionServices
|
||||
{
|
||||
public EncryptResult Encrypt(EncryptFileInfo fileInfo)
|
||||
{
|
||||
if (fileInfo.BundleName.Contains("gameres_music"))
|
||||
// LoadFromStream
|
||||
if (fileInfo.BundleName.Contains("_gameres_audio"))
|
||||
{
|
||||
var fileData = File.ReadAllBytes(fileInfo.FilePath);
|
||||
for (int i = 0; i < fileData.Length; i++)
|
||||
@@ -55,7 +56,22 @@ public class FileStreamEncryption : IEncryptionServices
|
||||
result.EncryptedData = fileData;
|
||||
return result;
|
||||
}
|
||||
else
|
||||
|
||||
// LoadFromFileOffset
|
||||
if (fileInfo.BundleName.Contains("_gameres_uiimage"))
|
||||
{
|
||||
var fileData = File.ReadAllBytes(fileInfo.FilePath);
|
||||
int offset = 32;
|
||||
var temper = new byte[fileData.Length + offset];
|
||||
Buffer.BlockCopy(fileData, 0, temper, offset, fileData.Length);
|
||||
|
||||
EncryptResult result = new EncryptResult();
|
||||
result.LoadMethod = EBundleLoadMethod.LoadFromFileOffset;
|
||||
result.EncryptedData = temper;
|
||||
return result;
|
||||
}
|
||||
|
||||
// Normal
|
||||
{
|
||||
EncryptResult result = new EncryptResult();
|
||||
result.LoadMethod = EBundleLoadMethod.Normal;
|
||||
|
||||
@@ -18,9 +18,6 @@ public class Boot : MonoBehaviour
|
||||
}
|
||||
void Start()
|
||||
{
|
||||
// 初始化BetterStreaming
|
||||
BetterStreamingAssets.Initialize();
|
||||
|
||||
// 初始化事件系统
|
||||
UniEvent.Initalize();
|
||||
|
||||
|
||||
@@ -122,9 +122,8 @@ internal class FsmInitialize : IStateNode
|
||||
{
|
||||
public bool QueryStreamingAssets(string fileName)
|
||||
{
|
||||
// 注意:使用了BetterStreamingAssets插件,使用前需要初始化该插件!
|
||||
string buildinFolderName = YooAssets.GetStreamingAssetBuildinFolderName();
|
||||
return BetterStreamingAssets.FileExists($"{buildinFolderName}/{fileName}");
|
||||
return StreamingAssetsHelper.FileExists($"{buildinFolderName}/{fileName}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
/[Ll]ibrary/
|
||||
/[Tt]emp/
|
||||
/[Oo]bj/
|
||||
/[Bb]uild/
|
||||
/[Bb]uilds/
|
||||
/Assets/AssetStoreTools*
|
||||
|
||||
# Visual Studio 2015 cache directory
|
||||
/.vs/
|
||||
|
||||
# Autogenerated VS/MD/Consulo solution and project files
|
||||
ExportedObj/
|
||||
.consulo/
|
||||
*.csproj
|
||||
*.unityproj
|
||||
*.sln
|
||||
*.suo
|
||||
*.tmp
|
||||
*.user
|
||||
*.userprefs
|
||||
*.pidb
|
||||
*.booproj
|
||||
*.svd
|
||||
*.pdb
|
||||
|
||||
# Unity3D generated meta files
|
||||
*.pidb.meta
|
||||
|
||||
# Unity3D Generated File On Crash Reports
|
||||
sysinfo.txt
|
||||
|
||||
# Builds
|
||||
*.apk
|
||||
*.unitypackage
|
||||
@@ -1,21 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017 gwiazdorrr
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -1,117 +0,0 @@
|
||||
# Better Streaming Assets
|
||||
|
||||
Better Streaming Assets is a plugin that lets you access Streaming Assets directly in an uniform and thread-safe way, with tiny overhead. Mostly beneficial for Android projects, where the alternatives are to use archaic and hugely inefficient WWW or embed data in Asset Bundles. API is based on Syste.IO.File and System.IO.Directory classes.
|
||||
|
||||
# Note on Android & App Bundles
|
||||
|
||||
App Bundles (.aab) builds are bugged when it comes to Streaming Assets. See https://github.com/gwiazdorrr/BetterStreamingAssets/issues/10 for details. The bottom line is:
|
||||
|
||||
⚠️ **Keep all file names in Streaming Assets lowercase!** ⚠️
|
||||
|
||||
# Getting started
|
||||
|
||||
This plugin can be installed in following ways:
|
||||
* Select "Add package from git URL..." in the Unity Package Manager and use this URL: `https://github.com/gwiazdorrr/BetterStreamingAssets.git`
|
||||
* Clone this repository and copy `Runtime` directory to your project.
|
||||
* Download the latest release from the [Asset Store](https://assetstore.unity.com/packages/tools/input-management/better-streaming-assets-103788).
|
||||
|
||||
# Usage
|
||||
|
||||
Check examples below. Note that all the paths are relative to StreamingAssets directory. That is, if you have files
|
||||
|
||||
```
|
||||
<project>/Assets/StreamingAssets/foo.bar
|
||||
<project>/Assets/StreamingAssets/dir/foo.bar
|
||||
````
|
||||
|
||||
You are expected to use following paths:
|
||||
|
||||
```
|
||||
foo.bar (or /foo.bar)
|
||||
dir/foo.bar (or /dir/foo.bar)
|
||||
```
|
||||
|
||||
# Examples
|
||||
|
||||
Initialization (before first use, needs to be called on main thread):
|
||||
|
||||
```csharp
|
||||
BetterStreamingAssets.Initialize();
|
||||
```
|
||||
|
||||
Typical scenario, deserializing from Xml:
|
||||
|
||||
```csharp
|
||||
public static Foo ReadFromXml(string path)
|
||||
{
|
||||
if ( !BetterStreamingAssets.FileExists(path) )
|
||||
{
|
||||
Debug.LogErrorFormat("Streaming asset not found: {0}", path);
|
||||
return null;
|
||||
}
|
||||
|
||||
using ( var stream = BetterStreamingAssets.OpenRead(path) )
|
||||
{
|
||||
var serializer = new System.Xml.Serialization.XmlSerializer(typeof(Foo));
|
||||
return (Foo)serializer.Deserialize(stream);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Note that ReadFromXml can be called from any thread, as long as Foo's constructor doesn't make any UnityEngine calls.
|
||||
|
||||
Listing all Streaming Assets in with .xml extension:
|
||||
|
||||
```csharp
|
||||
// all the xmls
|
||||
string[] paths = BetterStreamingAssets.GetFiles("\\", "*.xml", SearchOption.AllDirectories);
|
||||
// just xmls in Config directory (and nested)
|
||||
string[] paths = BetterStreamingAssets.GetFiles("Config", "*.xml", SearchOption.AllDirectories);
|
||||
```
|
||||
|
||||
Checking if a directory exists:
|
||||
|
||||
```csharp
|
||||
Debug.Assert( BetterStreamingAssets.DirectoryExists("Config") );
|
||||
```
|
||||
|
||||
Ways of reading a file:
|
||||
|
||||
```csharp
|
||||
// all at once
|
||||
byte[] data = BetterStreamingAssets.ReadAllBytes("Foo/bar.data");
|
||||
|
||||
// as stream, last 10 bytes
|
||||
byte[] footer = new byte[10];
|
||||
using (var stream = BetterStreamingAssets.OpenRead("Foo/bar.data"))
|
||||
{
|
||||
stream.Seek(-footer.Length, SeekOrigin.End);
|
||||
stream.Read(footer, 0, footer.Length);
|
||||
}
|
||||
```
|
||||
|
||||
Asset bundles (again, main thread only):
|
||||
|
||||
```csharp
|
||||
// synchronous
|
||||
var bundle = BetterStreamingAssets.LoadAssetBundle(path);
|
||||
// async
|
||||
var bundleOp = BetterStreamingAssets.LoadAssetBundleAsync(path);
|
||||
```
|
||||
|
||||
# (Android) False-positive compressed Streaming Assets messages
|
||||
|
||||
Streaming Assets end up in the same part of APK as files added by many custom plugins (`assets` directory), so it is impossible to tell whether a compressed file is a Streaming Asset (an indication something has gone terribly wrong) or not. This tool acts conservatively and logs errors whenever it finds a compressed file inside of `assets`, but outside of `assets/bin`. If you are annoyed by this and are certain a compressed file was not meant to be a Streaming Asset, add a file like this in the same assembly as Better Streaming Assets:
|
||||
|
||||
```csharp
|
||||
partial class BetterStreamingAssets
|
||||
{
|
||||
static partial void AndroidIsCompressedFileStreamingAsset(string path, ref bool result)
|
||||
{
|
||||
if ( path == "assets/my_custom_plugin_settings.json")
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -1,663 +0,0 @@
|
||||
// Better Streaming Assets, Piotr Gwiazdowski <gwiazdorrr+github at gmail.com>, 2017
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
using Better;
|
||||
using Better.StreamingAssets;
|
||||
using Better.StreamingAssets.ZipArchive;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
using BetterStreamingAssetsImp = BetterStreamingAssets.EditorImpl;
|
||||
#elif UNITY_ANDROID
|
||||
using BetterStreamingAssetsImp = BetterStreamingAssets.ApkImpl;
|
||||
#else
|
||||
using BetterStreamingAssetsImp = BetterStreamingAssets.LooseFilesImpl;
|
||||
#endif
|
||||
|
||||
public static partial class BetterStreamingAssets
|
||||
{
|
||||
internal struct ReadInfo
|
||||
{
|
||||
public string readPath;
|
||||
public long size;
|
||||
public long offset;
|
||||
public uint crc32;
|
||||
}
|
||||
|
||||
public static string Root
|
||||
{
|
||||
get { return BetterStreamingAssetsImp.s_root; }
|
||||
}
|
||||
|
||||
public static void Initialize()
|
||||
{
|
||||
BetterStreamingAssetsImp.Initialize(Application.dataPath, Application.streamingAssetsPath);
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
public static void InitializeWithExternalApk(string apkPath)
|
||||
{
|
||||
BetterStreamingAssetsImp.ApkMode = true;
|
||||
BetterStreamingAssetsImp.Initialize(apkPath, "jar:file://" + apkPath + "!/assets/");
|
||||
}
|
||||
|
||||
public static void InitializeWithExternalDirectories(string dataPath, string streamingAssetsPath)
|
||||
{
|
||||
BetterStreamingAssetsImp.ApkMode = false;
|
||||
BetterStreamingAssetsImp.Initialize(dataPath, streamingAssetsPath);
|
||||
}
|
||||
#endif
|
||||
|
||||
public static bool FileExists(string path)
|
||||
{
|
||||
ReadInfo info;
|
||||
return BetterStreamingAssetsImp.TryGetInfo(path, out info);
|
||||
}
|
||||
|
||||
public static bool DirectoryExists(string path)
|
||||
{
|
||||
return BetterStreamingAssetsImp.DirectoryExists(path);
|
||||
}
|
||||
|
||||
public static AssetBundleCreateRequest LoadAssetBundleAsync(string path, uint crc = 0)
|
||||
{
|
||||
var info = GetInfoOrThrow(path);
|
||||
return AssetBundle.LoadFromFileAsync(info.readPath, crc, (ulong)info.offset);
|
||||
}
|
||||
|
||||
public static AssetBundle LoadAssetBundle(string path, uint crc = 0)
|
||||
{
|
||||
var info = GetInfoOrThrow(path);
|
||||
return AssetBundle.LoadFromFile(info.readPath, crc, (ulong)info.offset);
|
||||
}
|
||||
|
||||
public static System.IO.Stream OpenRead(string path)
|
||||
{
|
||||
if ( path == null )
|
||||
throw new ArgumentNullException("path");
|
||||
if ( path.Length == 0 )
|
||||
throw new ArgumentException("Empty path", "path");
|
||||
|
||||
return BetterStreamingAssetsImp.OpenRead(path);
|
||||
}
|
||||
|
||||
public static System.IO.StreamReader OpenText(string path)
|
||||
{
|
||||
Stream str = OpenRead(path);
|
||||
try
|
||||
{
|
||||
return new StreamReader(str);
|
||||
}
|
||||
catch (System.Exception)
|
||||
{
|
||||
if (str != null)
|
||||
str.Dispose();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public static string ReadAllText(string path)
|
||||
{
|
||||
using ( var sr = OpenText(path) )
|
||||
{
|
||||
return sr.ReadToEnd();
|
||||
}
|
||||
}
|
||||
|
||||
public static string[] ReadAllLines(string path)
|
||||
{
|
||||
string line;
|
||||
var lines = new List<string>();
|
||||
|
||||
using ( var sr = OpenText(path) )
|
||||
{
|
||||
while ( ( line = sr.ReadLine() ) != null )
|
||||
{
|
||||
lines.Add(line);
|
||||
}
|
||||
}
|
||||
|
||||
return lines.ToArray();
|
||||
}
|
||||
|
||||
public static byte[] ReadAllBytes(string path)
|
||||
{
|
||||
if ( path == null )
|
||||
throw new ArgumentNullException("path");
|
||||
if ( path.Length == 0 )
|
||||
throw new ArgumentException("Empty path", "path");
|
||||
|
||||
return BetterStreamingAssetsImp.ReadAllBytes(path);
|
||||
}
|
||||
|
||||
public static string[] GetFiles(string path, string searchPattern, SearchOption searchOption)
|
||||
{
|
||||
return BetterStreamingAssetsImp.GetFiles(path, searchPattern, searchOption);
|
||||
}
|
||||
|
||||
public static string[] GetFiles(string path)
|
||||
{
|
||||
return GetFiles(path, null);
|
||||
}
|
||||
|
||||
public static string[] GetFiles(string path, string searchPattern)
|
||||
{
|
||||
return GetFiles(path, searchPattern, SearchOption.TopDirectoryOnly);
|
||||
}
|
||||
|
||||
private static ReadInfo GetInfoOrThrow(string path)
|
||||
{
|
||||
ReadInfo result;
|
||||
if ( !BetterStreamingAssetsImp.TryGetInfo(path, out result) )
|
||||
ThrowFileNotFound(path);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static void ThrowFileNotFound(string path)
|
||||
{
|
||||
throw new FileNotFoundException("File not found", path);
|
||||
}
|
||||
|
||||
static partial void AndroidIsCompressedFileStreamingAsset(string path, ref bool result);
|
||||
|
||||
#if UNITY_EDITOR
|
||||
internal static class EditorImpl
|
||||
{
|
||||
public static bool ApkMode = false;
|
||||
|
||||
public static string s_root
|
||||
{
|
||||
get { return ApkMode ? ApkImpl.s_root : LooseFilesImpl.s_root; }
|
||||
}
|
||||
|
||||
internal static void Initialize(string dataPath, string streamingAssetsPath)
|
||||
{
|
||||
if ( ApkMode )
|
||||
{
|
||||
ApkImpl.Initialize(dataPath, streamingAssetsPath);
|
||||
}
|
||||
else
|
||||
{
|
||||
LooseFilesImpl.Initialize(dataPath, streamingAssetsPath);
|
||||
}
|
||||
}
|
||||
|
||||
internal static bool TryGetInfo(string path, out ReadInfo info)
|
||||
{
|
||||
if ( ApkMode )
|
||||
return ApkImpl.TryGetInfo(path, out info);
|
||||
else
|
||||
return LooseFilesImpl.TryGetInfo(path, out info);
|
||||
}
|
||||
|
||||
internal static bool DirectoryExists(string path)
|
||||
{
|
||||
if ( ApkMode )
|
||||
return ApkImpl.DirectoryExists(path);
|
||||
else
|
||||
return LooseFilesImpl.DirectoryExists(path);
|
||||
}
|
||||
|
||||
internal static Stream OpenRead(string path)
|
||||
{
|
||||
if ( ApkMode )
|
||||
return ApkImpl.OpenRead(path);
|
||||
else
|
||||
return LooseFilesImpl.OpenRead(path);
|
||||
}
|
||||
|
||||
internal static byte[] ReadAllBytes(string path)
|
||||
{
|
||||
if ( ApkMode )
|
||||
return ApkImpl.ReadAllBytes(path);
|
||||
else
|
||||
return LooseFilesImpl.ReadAllBytes(path);
|
||||
}
|
||||
|
||||
internal static string[] GetFiles(string path, string searchPattern, SearchOption searchOption)
|
||||
{
|
||||
if ( ApkMode )
|
||||
return ApkImpl.GetFiles(path, searchPattern, searchOption);
|
||||
else
|
||||
return LooseFilesImpl.GetFiles(path, searchPattern, searchOption);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if UNITY_EDITOR || !UNITY_ANDROID
|
||||
internal static class LooseFilesImpl
|
||||
{
|
||||
public static string s_root;
|
||||
private static string[] s_emptyArray = new string[0];
|
||||
|
||||
public static void Initialize(string dataPath, string streamingAssetsPath)
|
||||
{
|
||||
s_root = Path.GetFullPath(streamingAssetsPath).Replace('\\', '/').TrimEnd('/');
|
||||
}
|
||||
|
||||
public static string[] GetFiles(string path, string searchPattern, SearchOption searchOption)
|
||||
{
|
||||
if (!Directory.Exists(s_root))
|
||||
return s_emptyArray;
|
||||
|
||||
// this will throw if something is fishy
|
||||
path = PathUtil.NormalizeRelativePath(path, forceTrailingSlash : true);
|
||||
|
||||
Debug.Assert(s_root.Last() != '\\' && s_root.Last() != '/' && path.StartsWith("/"));
|
||||
|
||||
var files = Directory.GetFiles(s_root + path, searchPattern ?? "*", searchOption);
|
||||
|
||||
for ( int i = 0; i < files.Length; ++i )
|
||||
{
|
||||
Debug.Assert(files[i].StartsWith(s_root));
|
||||
files[i] = files[i].Substring(s_root.Length + 1).Replace('\\', '/');
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
// purge meta files
|
||||
{
|
||||
int j = 0;
|
||||
for ( int i = 0; i < files.Length; ++i )
|
||||
{
|
||||
if ( !files[i].EndsWith(".meta") )
|
||||
{
|
||||
files[j++] = files[i];
|
||||
}
|
||||
}
|
||||
Array.Resize(ref files, j);
|
||||
}
|
||||
|
||||
#endif
|
||||
return files;
|
||||
}
|
||||
|
||||
public static bool TryGetInfo(string path, out ReadInfo info)
|
||||
{
|
||||
path = PathUtil.NormalizeRelativePath(path);
|
||||
|
||||
info = new ReadInfo();
|
||||
|
||||
var fullPath = s_root + path;
|
||||
if ( !File.Exists(fullPath) )
|
||||
return false;
|
||||
|
||||
info.readPath = fullPath;
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool DirectoryExists(string path)
|
||||
{
|
||||
var normalized = PathUtil.NormalizeRelativePath(path);
|
||||
return Directory.Exists(s_root + normalized);
|
||||
}
|
||||
|
||||
public static byte[] ReadAllBytes(string path)
|
||||
{
|
||||
ReadInfo info;
|
||||
|
||||
if ( !TryGetInfo(path, out info) )
|
||||
ThrowFileNotFound(path);
|
||||
|
||||
return File.ReadAllBytes(info.readPath);
|
||||
}
|
||||
|
||||
public static System.IO.Stream OpenRead(string path)
|
||||
{
|
||||
ReadInfo info;
|
||||
if ( !TryGetInfo(path, out info) )
|
||||
ThrowFileNotFound(path);
|
||||
|
||||
Stream fileStream = File.OpenRead(info.readPath);
|
||||
try
|
||||
{
|
||||
return new SubReadOnlyStream(fileStream, leaveOpen: false);
|
||||
}
|
||||
catch ( System.Exception )
|
||||
{
|
||||
fileStream.Dispose();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if UNITY_EDITOR || UNITY_ANDROID
|
||||
internal static class ApkImpl
|
||||
{
|
||||
private static string[] s_paths;
|
||||
private static PartInfo[] s_streamingAssets;
|
||||
public static string s_root;
|
||||
|
||||
private struct PartInfo
|
||||
{
|
||||
public long size;
|
||||
public long offset;
|
||||
public uint crc32;
|
||||
}
|
||||
|
||||
public static void Initialize(string dataPath, string streamingAssetsPath)
|
||||
{
|
||||
s_root = dataPath;
|
||||
|
||||
List<string> paths = new List<string>();
|
||||
List<PartInfo> parts = new List<PartInfo>();
|
||||
|
||||
GetStreamingAssetsInfoFromJar(s_root, paths, parts);
|
||||
|
||||
if (paths.Count == 0 && !Application.isEditor && Path.GetFileName(dataPath) != "base.apk")
|
||||
{
|
||||
// maybe split?
|
||||
var newDataPath = Path.GetDirectoryName(dataPath) + "/base.apk";
|
||||
if (File.Exists(newDataPath))
|
||||
{
|
||||
s_root = newDataPath;
|
||||
GetStreamingAssetsInfoFromJar(newDataPath, paths, parts);
|
||||
}
|
||||
}
|
||||
|
||||
s_paths = paths.ToArray();
|
||||
s_streamingAssets = parts.ToArray();
|
||||
}
|
||||
|
||||
public static bool TryGetInfo(string path, out ReadInfo info)
|
||||
{
|
||||
path = PathUtil.NormalizeRelativePath(path);
|
||||
info = new ReadInfo();
|
||||
|
||||
var index = Array.BinarySearch(s_paths, path, StringComparer.OrdinalIgnoreCase);
|
||||
if ( index < 0 )
|
||||
return false;
|
||||
|
||||
var dataInfo = s_streamingAssets[index];
|
||||
info.crc32 = dataInfo.crc32;
|
||||
info.offset = dataInfo.offset;
|
||||
info.size = dataInfo.size;
|
||||
info.readPath = s_root;
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool DirectoryExists(string path)
|
||||
{
|
||||
var normalized = PathUtil.NormalizeRelativePath(path, forceTrailingSlash : true);
|
||||
var dirIndex = GetDirectoryIndex(normalized);
|
||||
return dirIndex >= 0 && dirIndex < s_paths.Length;
|
||||
}
|
||||
|
||||
public static string[] GetFiles(string path, string searchPattern, SearchOption searchOption)
|
||||
{
|
||||
if ( path == null )
|
||||
throw new ArgumentNullException("path");
|
||||
|
||||
var actualDirPath = PathUtil.NormalizeRelativePath(path, forceTrailingSlash : true);
|
||||
|
||||
// find first file there
|
||||
var index = GetDirectoryIndex(actualDirPath);
|
||||
if ( index < 0 )
|
||||
throw new IOException();
|
||||
if ( index == s_paths.Length )
|
||||
throw new DirectoryNotFoundException();
|
||||
|
||||
Predicate<string> filter;
|
||||
if ( string.IsNullOrEmpty(searchPattern) || searchPattern == "*" )
|
||||
{
|
||||
filter = null;
|
||||
}
|
||||
else if ( searchPattern.IndexOf('*') >= 0 || searchPattern.IndexOf('?') >= 0 )
|
||||
{
|
||||
var regex = PathUtil.WildcardToRegex(searchPattern);
|
||||
filter = (x) => regex.IsMatch(x);
|
||||
}
|
||||
else
|
||||
{
|
||||
filter = (x) => string.Compare(x, searchPattern, true) == 0;
|
||||
}
|
||||
|
||||
List<string> results = new List<string>();
|
||||
string fixedPath = null;
|
||||
|
||||
for ( int i = index; i < s_paths.Length; ++i )
|
||||
{
|
||||
var filePath = s_paths[i];
|
||||
|
||||
if ( !filePath.StartsWith(actualDirPath) )
|
||||
break;
|
||||
|
||||
string fileName;
|
||||
|
||||
var dirSeparatorIndex = filePath.LastIndexOf('/', filePath.Length - 1, filePath.Length - actualDirPath.Length);
|
||||
if ( dirSeparatorIndex >= 0 )
|
||||
{
|
||||
if ( searchOption == SearchOption.TopDirectoryOnly )
|
||||
continue;
|
||||
|
||||
fileName = filePath.Substring(dirSeparatorIndex + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
fileName = filePath.Substring(actualDirPath.Length);
|
||||
}
|
||||
|
||||
// now do a match
|
||||
if ( filter == null || filter(fileName) )
|
||||
{
|
||||
var normalizedPart = filePath.Substring(actualDirPath.Length);
|
||||
|
||||
if ( fixedPath == null )
|
||||
{
|
||||
fixedPath = PathUtil.FixTrailingDirectorySeparators(path);
|
||||
if ( fixedPath == "/" )
|
||||
fixedPath = string.Empty;
|
||||
}
|
||||
|
||||
var result = PathUtil.CombineSlash(fixedPath, normalizedPart);
|
||||
results.Add(result);
|
||||
}
|
||||
}
|
||||
|
||||
return results.ToArray();
|
||||
}
|
||||
|
||||
public static byte[] ReadAllBytes(string path)
|
||||
{
|
||||
ReadInfo info;
|
||||
if ( !TryGetInfo(path, out info) )
|
||||
ThrowFileNotFound(path);
|
||||
|
||||
byte[] buffer;
|
||||
using ( var fileStream = File.OpenRead(info.readPath) )
|
||||
{
|
||||
if ( info.offset != 0 )
|
||||
{
|
||||
if ( fileStream.Seek(info.offset, SeekOrigin.Begin) != info.offset )
|
||||
throw new IOException();
|
||||
}
|
||||
|
||||
if ( info.size > (long)int.MaxValue )
|
||||
throw new IOException();
|
||||
|
||||
int count = (int)info.size;
|
||||
int offset = 0;
|
||||
|
||||
buffer = new byte[count];
|
||||
while ( count > 0 )
|
||||
{
|
||||
int num = fileStream.Read(buffer, offset, count);
|
||||
if ( num == 0 )
|
||||
throw new EndOfStreamException();
|
||||
offset += num;
|
||||
count -= num;
|
||||
}
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public static System.IO.Stream OpenRead(string path)
|
||||
{
|
||||
ReadInfo info;
|
||||
if ( !TryGetInfo(path, out info) )
|
||||
ThrowFileNotFound(path);
|
||||
|
||||
Stream fileStream = File.OpenRead(info.readPath);
|
||||
try
|
||||
{
|
||||
return new SubReadOnlyStream(fileStream, info.offset, info.size, leaveOpen : false);
|
||||
}
|
||||
catch ( System.Exception )
|
||||
{
|
||||
fileStream.Dispose();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private static int GetDirectoryIndex(string path)
|
||||
{
|
||||
Debug.Assert(s_paths != null);
|
||||
|
||||
// find first file there
|
||||
var index = Array.BinarySearch(s_paths, path, StringComparer.OrdinalIgnoreCase);
|
||||
if ( index >= 0 )
|
||||
return ~index;
|
||||
|
||||
// if the end, no such directory exists
|
||||
index = ~index;
|
||||
if ( index == s_paths.Length )
|
||||
return index;
|
||||
|
||||
for ( int i = index; i < s_paths.Length && s_paths[i].StartsWith(path); ++i )
|
||||
{
|
||||
// because otherwise there would be a match
|
||||
Debug.Assert(s_paths[i].Length > path.Length);
|
||||
|
||||
if ( path[path.Length - 1] == '/' )
|
||||
return i;
|
||||
|
||||
if ( s_paths[i][path.Length] == '/' )
|
||||
return i;
|
||||
}
|
||||
|
||||
return s_paths.Length;
|
||||
}
|
||||
|
||||
private static void GetStreamingAssetsInfoFromJar(string apkPath, List<string> paths, List<PartInfo> parts)
|
||||
{
|
||||
using ( var stream = File.OpenRead(apkPath) )
|
||||
using ( var reader = new BinaryReader(stream) )
|
||||
{
|
||||
if ( !stream.CanRead )
|
||||
throw new ArgumentException();
|
||||
if ( !stream.CanSeek )
|
||||
throw new ArgumentException();
|
||||
|
||||
long expectedNumberOfEntries;
|
||||
long centralDirectoryStart;
|
||||
ZipArchiveUtils.ReadEndOfCentralDirectory(stream, reader, out expectedNumberOfEntries, out centralDirectoryStart);
|
||||
|
||||
try
|
||||
{
|
||||
stream.Seek(centralDirectoryStart, SeekOrigin.Begin);
|
||||
|
||||
long numberOfEntries = 0;
|
||||
|
||||
ZipCentralDirectoryFileHeader header;
|
||||
|
||||
const int prefixLength = 7;
|
||||
const string prefix = "assets/";
|
||||
const string assetsPrefix = "assets/bin/";
|
||||
Debug.Assert(prefixLength == prefix.Length);
|
||||
|
||||
while ( ZipCentralDirectoryFileHeader.TryReadBlock(reader, out header) )
|
||||
{
|
||||
if ( header.CompressedSize != header.UncompressedSize )
|
||||
{
|
||||
#if UNITY_ASSERTIONS
|
||||
var fileName = Encoding.UTF8.GetString(header.Filename);
|
||||
if (fileName.StartsWith(prefix) && !fileName.StartsWith(assetsPrefix))
|
||||
{
|
||||
bool isStreamingAsset = true;
|
||||
AndroidIsCompressedFileStreamingAsset(fileName, ref isStreamingAsset);
|
||||
if (isStreamingAsset)
|
||||
{
|
||||
Debug.LogAssertionFormat("BetterStreamingAssets: file {0} is where Streaming Assets are put, but is compressed. " +
|
||||
"If this is a App Bundle build, see README for a possible workaround. " +
|
||||
"If this file is not a Streaming Asset (has been on purpose by hand or by another plug-in), implement " +
|
||||
"BetterStreamingAssets.AndroidIsCompressedFileStreamingAsset partial method to prevent this message from appearing again. ",
|
||||
fileName);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// we only want uncompressed files
|
||||
}
|
||||
else
|
||||
{
|
||||
var fileName = Encoding.UTF8.GetString(header.Filename);
|
||||
|
||||
if (fileName.EndsWith("/"))
|
||||
{
|
||||
// there's some strangeness when it comes to OBB: directories are listed as files
|
||||
// simply ignoring them should be enough
|
||||
Debug.Assert(header.UncompressedSize == 0);
|
||||
}
|
||||
else if ( fileName.StartsWith(prefix) )
|
||||
{
|
||||
// ignore normal assets...
|
||||
if ( fileName.StartsWith(assetsPrefix) )
|
||||
{
|
||||
// Note: if you put bin directory in your StreamingAssets you will get false negative here
|
||||
}
|
||||
else
|
||||
{
|
||||
var relativePath = fileName.Substring(prefixLength - 1);
|
||||
var entry = new PartInfo()
|
||||
{
|
||||
crc32 = header.Crc32,
|
||||
offset = header.RelativeOffsetOfLocalHeader, // this offset will need fixing later on
|
||||
size = header.UncompressedSize
|
||||
};
|
||||
|
||||
var index = paths.BinarySearch(relativePath, StringComparer.OrdinalIgnoreCase);
|
||||
if ( index >= 0 )
|
||||
throw new System.InvalidOperationException("Paths duplicate! " + fileName);
|
||||
|
||||
paths.Insert(~index, relativePath);
|
||||
parts.Insert(~index, entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
numberOfEntries++;
|
||||
}
|
||||
|
||||
if ( numberOfEntries != expectedNumberOfEntries )
|
||||
throw new ZipArchiveException("Number of entries does not match");
|
||||
|
||||
}
|
||||
catch ( EndOfStreamException ex )
|
||||
{
|
||||
throw new ZipArchiveException("CentralDirectoryInvalid", ex);
|
||||
}
|
||||
|
||||
// now fix offsets
|
||||
for ( int i = 0; i < parts.Count; ++i )
|
||||
{
|
||||
var entry = parts[i];
|
||||
stream.Seek(entry.offset, SeekOrigin.Begin);
|
||||
|
||||
if ( !ZipLocalFileHeader.TrySkipBlock(reader) )
|
||||
throw new ZipArchiveException("Local file header corrupt");
|
||||
|
||||
entry.offset = stream.Position;
|
||||
|
||||
parts[i] = entry;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -1,164 +0,0 @@
|
||||
// Better Streaming Assets, Piotr Gwiazdowski <gwiazdorrr+github at gmail.com>, 2017
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Better.StreamingAssets
|
||||
{
|
||||
public static partial class PathUtil
|
||||
{
|
||||
private enum NormalizeState
|
||||
{
|
||||
PrevSlash,
|
||||
PrevDot,
|
||||
PrevDoubleDot,
|
||||
NothingSpecial,
|
||||
}
|
||||
|
||||
public static bool IsDirectorySeparator(char c)
|
||||
{
|
||||
return c == '/' || c == '\\';
|
||||
}
|
||||
|
||||
public static string FixTrailingDirectorySeparators(string path)
|
||||
{
|
||||
if ( path.Length >= 2 )
|
||||
{
|
||||
var lastChar = path[path.Length - 1];
|
||||
var prevChar = path[path.Length - 2];
|
||||
if ( PathUtil.IsDirectorySeparator(lastChar) && PathUtil.IsDirectorySeparator(prevChar) )
|
||||
{
|
||||
return path.TrimEnd('\\', '/') + lastChar;
|
||||
}
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
public static string CombineSlash(string a, string b)
|
||||
{
|
||||
if ( a == null )
|
||||
throw new ArgumentNullException("a");
|
||||
if ( b == null )
|
||||
throw new ArgumentNullException("b");
|
||||
|
||||
if ( string.IsNullOrEmpty(b) )
|
||||
return a;
|
||||
if ( string.IsNullOrEmpty(a) )
|
||||
return b;
|
||||
|
||||
if (b[0] == '/')
|
||||
return b;
|
||||
|
||||
if ( IsDirectorySeparator(a[a.Length -1]) )
|
||||
return a + b;
|
||||
else
|
||||
return a + '/' + b;
|
||||
}
|
||||
|
||||
public static string NormalizeRelativePath(string relative, bool forceTrailingSlash = false)
|
||||
{
|
||||
if (string.IsNullOrEmpty(relative))
|
||||
throw new System.ArgumentException("Empty or null", "relative");
|
||||
|
||||
StringBuilder output = new StringBuilder(relative.Length);
|
||||
|
||||
NormalizeState state = NormalizeState.PrevSlash;
|
||||
output.Append('/');
|
||||
|
||||
int startIndex = 0;
|
||||
int lastIndexPlus1 = relative.Length;
|
||||
|
||||
if ( relative[0] == '"' && relative.Length > 2 && relative[relative.Length - 1] == '"')
|
||||
{
|
||||
startIndex++;
|
||||
lastIndexPlus1--;
|
||||
}
|
||||
|
||||
for ( int i = startIndex; i <= lastIndexPlus1; ++i )
|
||||
{
|
||||
if (i == lastIndexPlus1 || relative[i] == '/' || relative[i] == '\\')
|
||||
{
|
||||
if ( state == NormalizeState.PrevSlash || state == NormalizeState.PrevDot )
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
else if ( state == NormalizeState.PrevDoubleDot )
|
||||
{
|
||||
if ( output.Length == 1 )
|
||||
throw new System.IO.IOException("Invalid path: double dot error (before " + i + ")");
|
||||
|
||||
// on level up!
|
||||
int j;
|
||||
for ( j = output.Length - 2; j >= 0 && output[j] != '/'; --j)
|
||||
{
|
||||
}
|
||||
|
||||
output.Remove(j + 1, output.Length - j - 1);
|
||||
}
|
||||
else if ( i < lastIndexPlus1 || forceTrailingSlash )
|
||||
{
|
||||
output.Append('/');
|
||||
}
|
||||
|
||||
state = NormalizeState.PrevSlash;
|
||||
}
|
||||
else if ( relative[i] == '.' )
|
||||
{
|
||||
if ( state == NormalizeState.PrevSlash )
|
||||
{
|
||||
state = NormalizeState.PrevDot;
|
||||
}
|
||||
else if ( state == NormalizeState.PrevDot )
|
||||
{
|
||||
state = NormalizeState.PrevDoubleDot;
|
||||
}
|
||||
else if ( state == NormalizeState.PrevDoubleDot )
|
||||
{
|
||||
state = NormalizeState.NothingSpecial;
|
||||
output.Append("...");
|
||||
}
|
||||
else
|
||||
{
|
||||
output.Append('.');
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( state == NormalizeState.PrevDot )
|
||||
{
|
||||
output.Append('.');
|
||||
}
|
||||
else if ( state == NormalizeState.PrevDoubleDot )
|
||||
{
|
||||
output.Append("..");
|
||||
}
|
||||
|
||||
if (!IsValidCharacter(relative[i]))
|
||||
throw new System.IO.IOException("Invalid characters");
|
||||
|
||||
output.Append(relative[i]);
|
||||
state = NormalizeState.NothingSpecial;
|
||||
}
|
||||
}
|
||||
|
||||
return output.ToString();
|
||||
}
|
||||
|
||||
public static bool IsValidCharacter(char c)
|
||||
{
|
||||
if (c == '\"' || c == '<' || c == '>' || c == '|' || c < 32 || c == ':' || c == '*' || c == '?')
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public static Regex WildcardToRegex(string pattern)
|
||||
{
|
||||
return new Regex("^" + Regex.Escape(pattern).Replace(@"\*", ".*").Replace(@"\?", ".") + "$", RegexOptions.IgnoreCase);
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user