Compare commits

...

50 Commits
1.4.11 ... main

Author SHA1 Message Date
hevinci dc33abde46 update asset system 2023-06-16 15:01:13 +08:00
hevinci aae7b08dd1 update space shooter 2023-06-16 14:10:33 +08:00
hevinci f70582af1a Update CHANGELOG.md 2023-06-14 19:23:02 +08:00
hevinci f04d84bb93 Update package.json 2023-06-14 19:22:53 +08:00
hevinci 78693deed6 update space shooter
启用了新的内置资源查询机制。
2023-06-14 18:52:59 +08:00
hevinci f1a5965b4c update editor code
增加自动分析冗余资源的开关
2023-06-14 16:40:27 +08:00
hevinci cd43d0775d update runtime code 2023-06-13 16:41:27 +08:00
hevinci cf532a84ef update editor code 2023-06-13 16:41:08 +08:00
hevinci 651b65d148 update runtime code
优化了文件路径合并的逻辑。
2023-06-09 18:25:43 +08:00
hevinci 895dde1cc8 update logic code
优化了创建文件的方式。
2023-06-09 18:12:03 +08:00
hevinci f6e94c9514 Update CHANGELOG.md 2023-06-09 11:27:33 +08:00
hevinci da4ba4453c Update package.json 2023-06-09 11:27:19 +08:00
hevinci 53ea8c8002 update runtime code 2023-06-09 11:27:15 +08:00
hevinci d4549b1228 update space shooter
修复了DEMO里IOS平台流解密失败的问题。
2023-06-05 19:02:13 +08:00
hevinci fcf9eff2f6 update space shooter 2023-06-05 18:04:09 +08:00
hevinci 93b58149d2 update runtime code 2023-05-30 15:03:22 +08:00
hevinci c91c49465b update cache system
修复验证远端下载文件,极小概率失败的问题。
2023-05-29 19:28:07 +08:00
hevinci e9fa3ead04 update asset system
修复安卓平台下,小米8手机上有小概率加载原生文件失败的问题。
2023-05-29 17:30:43 +08:00
hevinci eff2f1d968 update space shooter 2023-05-26 18:35:34 +08:00
hevinci cd0a6579b8 Update CHANGELOG.md 2023-05-26 18:07:32 +08:00
hevinci 18c2e232cf Update package.json 2023-05-26 18:07:20 +08:00
hevinci ad680638ac update AssetBundleBuilder
Unity2021版本及以上推荐使用可编程构建管线(SBP)
2023-05-26 18:05:39 +08:00
hevinci 0764061d8f update space shooter 2023-05-25 16:38:33 +08:00
hevinci d448026250 update AssetBundleBuilder
修复了内置着色器Tag未正确传染给依赖资源包的问题。
2023-05-25 16:38:02 +08:00
hevinci 34f553b9e3 update AssetBundleCollector
修复了收集器对着色器未过滤的问题。
2023-05-25 16:35:18 +08:00
hevinci 25d1e32ce9 update asset system 2023-05-15 15:34:49 +08:00
hevinci 8686c32ada Update CHANGELOG.md 2023-05-12 17:45:24 +08:00
hevinci f043c6710a Update CHANGELOG.md 2023-05-12 17:43:13 +08:00
hevinci acd27e36fa Update package.json 2023-05-12 17:43:05 +08:00
hevinci 37f0d1e5a1 update runtime code
新增方法YooAssets.SetCacheSystemSandboxPath()
2023-05-12 17:32:41 +08:00
hevinci e6397559ff update cache system
新增方法ResoucePackage.ClearAllCacheFilesAsync()
2023-05-12 14:30:08 +08:00
hevinci 812c46adeb update runtime code
销毁Package的时候清空缓存记录。
2023-05-06 10:42:33 +08:00
hevinci 4d7fb6301a update samples 2023-05-05 10:35:02 +08:00
hevinci f0951f2a25 update samples 2023-05-05 09:49:08 +08:00
hevinci 7d2defedb7 update asset bundle collector 2023-05-04 11:14:01 +08:00
何冠峰 17ab618bed
Merge pull request #102 from hanazonoyurine/main
可寻址地址冲突时,打印冲突地址的资源地址
2023-05-04 10:46:44 +08:00
hanazonoyurine 0f9e932616
可寻址地址冲突时,打印冲突地址的资源地址 2023-04-27 16:30:17 +08:00
hevinci 20b0bd26ae Update CHANGELOG.md 2023-04-22 17:45:25 +08:00
hevinci 3b395861d9 Update package.json 2023-04-22 17:45:13 +08:00
hevinci d5d1f851ab update runtime code 2023-04-22 17:37:07 +08:00
hevinci c2e2a33af1 update samples 2023-04-22 17:23:51 +08:00
hevinci 9a729f921e update editor code
BuildParameters增加共享资源的打包规则字段
2023-04-22 17:22:59 +08:00
hevinci 1b75f4b6e9 update runtime code
UpdatePackageManifestAsync方法增加自动保存版本号参数
2023-04-22 17:20:23 +08:00
hevinci aaab6692c3 update runtime code 2023-04-22 11:25:51 +08:00
hevinci 70fc85e456 update runtime code
增加DestroyPackage()方法
2023-04-22 11:22:28 +08:00
hevinci 29358a7b4b update runtime code 2023-04-22 10:27:56 +08:00
hevinci b1b0563d84 update editor code
增加右键创建配置文件
2023-04-22 10:27:46 +08:00
hevinci 21b1e5bee7 Update LICENSE.md 2023-04-20 21:22:27 +08:00
hevinci c02eeef846 update edtior code
增加home page菜单栏
2023-04-20 21:22:19 +08:00
hevinci e84e50708b update asset bundle builder
增加对WEBGL平台加密选项的检测。
2023-04-20 17:56:21 +08:00
232 changed files with 7269 additions and 359 deletions

View File

@ -2,6 +2,131 @@
All notable changes to this package will be documented in this file. All notable changes to this package will be documented in this file.
## [1.4.16] - 2023-06-14
### Changed
- 增加了自动分析冗余资源的开关
```c#
/// <summary>
/// 构建参数
/// </summary>
public class BuildParameters
{
/// <summary>
/// 自动分析冗余资源
/// </summary>
public bool AutoAnalyzeRedundancy = true;
}
```
- 太空战机DEMO启用了新的内置资源查询机制。
## [1.4.15] - 2023-06-09
### Fixed
- 修复了安卓平台,解压内置文件到沙盒失败后不再重新尝试的问题。
- 修复了验证远端下载文件,极小概率失败的问题。
- 修复了太空战机DEMO在IOS平台流解密失败的问题。
## [1.4.14] - 2023-05-26
### Fixed
- 修复了收集器对着色器未过滤的问题。
- 修复了内置着色器Tag特殊情况下未正确传染给依赖资源包的问题。
### Changed
- Unity2021版本及以上推荐使用可编程构建管线SBP
## [1.4.13] - 2023-05-12
### Changed
- 可寻址地址冲突时,打印冲突地址的资源路径。
- 销毁Package的时候清空该Package的缓存记录。
### Added
- 新增方法ResoucePackage.ClearAllCacheFilesAsync()
```c#
public class ResoucePackage
{
/// <summary>
/// 清理包裹本地所有的缓存文件
/// </summary>
public ClearAllCacheFilesOperation ClearAllCacheFilesAsync();
}
```
- 新增方法YooAssets.SetCacheSystemSandboxPath()
```c#
public class YooAssets
{
/// <summary>
/// 设置缓存系统参数,沙盒目录的存储路径
/// </summary>
public static void SetCacheSystemSandboxPath(string sandboxPath);
}
```
## [1.4.12] - 2023-04-22
### Changed
- 增加了对WEBGL平台加密选项的检测。
- 增加了YooAsset/Home Page菜单栏。
- 增加了鼠标右键创建配置的菜单。
- 增加了YooAssets.DestroyPackage()方法。
```c#
class YooAssets
{
/// <summary>
/// 销毁资源包
/// </summary>
/// <param name="package">资源包对象</param>
public static void DestroyPackage(string packageName);
}
```
- UpdatePackageManifestAsync方法增加了新参数autoSaveVersion
```c#
class ResourcePackage
{
/// <summary>
/// 向网络端请求并更新清单
/// </summary>
/// <param name="packageVersion">更新的包裹版本</param>
/// <param name="autoSaveVersion">更新成功后自动保存版本号,作为下次初始化的版本。</param>
/// <param name="timeout">超时时间默认值60秒</param>
public UpdatePackageManifestOperation UpdatePackageManifestAsync(string packageVersion, bool autoSaveVersion = true, int timeout = 60)
}
```
- BuildParameters类增加了新字段。
可以自定义共享资源文件的打包规则。
```c#
class BuildParameters
{
/// <summary>
/// 共享资源的打包规则
/// </summary>
public IShareAssetPackRule ShareAssetPackRule = null;
}
```
## [1.4.11] - 2023-04-14 ## [1.4.11] - 2023-04-14
### Fixed ### Fixed

View File

@ -94,7 +94,7 @@ namespace YooAsset.Editor
{ {
BuildLogger.Warning($"{buildParameters.BuildMode} pipeline build failed !"); BuildLogger.Warning($"{buildParameters.BuildMode} pipeline build failed !");
BuildLogger.Error($"Build task failed : {buildResult.FailedTask}"); BuildLogger.Error($"Build task failed : {buildResult.FailedTask}");
BuildLogger.Error($"Build task error : {buildResult.FailedInfo}"); BuildLogger.Error(buildResult.ErrorInfo);
} }
return buildResult; return buildResult;

View File

@ -3,6 +3,7 @@ using UnityEngine;
namespace YooAsset.Editor namespace YooAsset.Editor
{ {
[CreateAssetMenu(fileName = "AssetBundleBuilderSetting", menuName = "YooAsset/Create AssetBundle Builder Settings")]
public class AssetBundleBuilderSetting : ScriptableObject public class AssetBundleBuilderSetting : ScriptableObject
{ {
/// <summary> /// <summary>

View File

@ -12,7 +12,7 @@ namespace YooAsset.Editor
public class AssetBundleBuilderWindow : EditorWindow public class AssetBundleBuilderWindow : EditorWindow
{ {
[MenuItem("YooAsset/AssetBundle Builder", false, 102)] [MenuItem("YooAsset/AssetBundle Builder", false, 102)]
public static void ShowExample() public static void OpenWindow()
{ {
AssetBundleBuilderWindow window = GetWindow<AssetBundleBuilderWindow>("资源包构建工具", true, WindowsDefine.DockedWindowTypes); AssetBundleBuilderWindow window = GetWindow<AssetBundleBuilderWindow>("资源包构建工具", true, WindowsDefine.DockedWindowTypes);
window.minSize = new Vector2(800, 600); window.minSize = new Vector2(800, 600);
@ -275,6 +275,8 @@ namespace YooAsset.Editor
buildParameters.PackageName = AssetBundleBuilderSettingData.Setting.BuildPackage; buildParameters.PackageName = AssetBundleBuilderSettingData.Setting.BuildPackage;
buildParameters.PackageVersion = _buildVersionField.value; buildParameters.PackageVersion = _buildVersionField.value;
buildParameters.VerifyBuildingResult = true; buildParameters.VerifyBuildingResult = true;
buildParameters.AutoAnalyzeRedundancy = true;
buildParameters.ShareAssetPackRule = new DefaultShareAssetPackRule();
buildParameters.EncryptionServices = CreateEncryptionServicesInstance(); buildParameters.EncryptionServices = CreateEncryptionServicesInstance();
buildParameters.CompressOption = AssetBundleBuilderSettingData.Setting.CompressOption; buildParameters.CompressOption = AssetBundleBuilderSettingData.Setting.CompressOption;
buildParameters.OutputNameStyle = AssetBundleBuilderSettingData.Setting.OutputNameStyle; buildParameters.OutputNameStyle = AssetBundleBuilderSettingData.Setting.OutputNameStyle;

View File

@ -157,7 +157,7 @@ namespace YooAsset.Editor
/// <summary> /// <summary>
/// 计算共享资源包的完整包名 /// 计算共享资源包的完整包名
/// </summary> /// </summary>
public void CalculateShareBundleName(bool uniqueBundleName, string packageName, string shadersBundleName) public void CalculateShareBundleName(IShareAssetPackRule packRule, bool uniqueBundleName, string packageName, string shadersBundleName)
{ {
if (CollectorType != ECollectorType.None) if (CollectorType != ECollectorType.None)
return; return;
@ -173,8 +173,7 @@ namespace YooAsset.Editor
{ {
if (_referenceBundleNames.Count > 1) if (_referenceBundleNames.Count > 1)
{ {
IPackRule packRule = PackDirectory.StaticPackRule; PackRuleResult packRuleResult = packRule.GetPackRuleResult(AssetPath);
PackRuleResult packRuleResult = packRule.GetPackRuleResult(new PackRuleData(AssetPath));
BundleName = packRuleResult.GetShareBundleName(packageName, uniqueBundleName); BundleName = packRuleResult.GetShareBundleName(packageName, uniqueBundleName);
} }
else else
@ -184,5 +183,27 @@ namespace YooAsset.Editor
} }
} }
} }
/// <summary>
/// 判断是否为冗余资源
/// </summary>
public bool IsRedundancyAsset()
{
if (CollectorType != ECollectorType.None)
return false;
if (IsRawAsset)
throw new Exception("Should never get here !");
return _referenceBundleNames.Count > 1;
}
/// <summary>
/// 获取关联资源包的数量
/// </summary>
public int GetReferenceBundleCount()
{
return _referenceBundleNames.Count;
}
} }
} }

View File

@ -10,6 +10,11 @@ namespace YooAsset.Editor
{ {
private readonly Dictionary<string, BuildBundleInfo> _bundleInfoDic = new Dictionary<string, BuildBundleInfo>(10000); private readonly Dictionary<string, BuildBundleInfo> _bundleInfoDic = new Dictionary<string, BuildBundleInfo>(10000);
/// <summary>
/// 冗余的资源列表
/// </summary>
public readonly List<ReportRedundancyInfo> RedundancyInfos= new List<ReportRedundancyInfo>(1000);
/// <summary> /// <summary>
/// 参与构建的资源总数 /// 参与构建的资源总数
/// 说明:包括主动收集的资源以及其依赖的所有资源 /// 说明:包括主动收集的资源以及其依赖的所有资源

View File

@ -76,9 +76,19 @@ namespace YooAsset.Editor
/// 验证构建结果 /// 验证构建结果
/// </summary> /// </summary>
public bool VerifyBuildingResult = false; public bool VerifyBuildingResult = false;
/// <summary>
/// 自动分析冗余资源
/// </summary>
public bool AutoAnalyzeRedundancy = true;
/// <summary> /// <summary>
/// 加密类 /// 共享资源的打包规则
/// </summary>
public IShareAssetPackRule ShareAssetPackRule = null;
/// <summary>
/// 资源的加密接口
/// </summary> /// </summary>
public IEncryptionServices EncryptionServices = null; public IEncryptionServices EncryptionServices = null;

View File

@ -27,6 +27,11 @@ namespace YooAsset.Editor
/// </summary> /// </summary>
public List<ReportBundleInfo> BundleInfos = new List<ReportBundleInfo>(); public List<ReportBundleInfo> BundleInfos = new List<ReportBundleInfo>();
/// <summary>
/// 冗余的资源列表
/// </summary>
public List<ReportRedundancyInfo> RedundancyInfos = new List<ReportRedundancyInfo>();
/// <summary> /// <summary>
/// 获取资源包信息类 /// 获取资源包信息类
@ -61,7 +66,7 @@ namespace YooAsset.Editor
File.Delete(savePath); File.Delete(savePath);
string json = JsonUtility.ToJson(buildReport, true); string json = JsonUtility.ToJson(buildReport, true);
FileUtility.CreateFile(savePath, json); FileUtility.WriteAllText(savePath, json);
} }
public static BuildReport Deserialize(string jsonData) public static BuildReport Deserialize(string jsonData)
{ {

View File

@ -0,0 +1,36 @@
using System;
using System.Collections;
using System.Collections.Generic;
namespace YooAsset.Editor
{
[Serializable]
public class ReportRedundancyInfo
{
/// <summary>
/// 资源路径
/// </summary>
public string AssetPath;
/// <summary>
/// 资源类型
/// </summary>
public string AssetType;
/// <summary>
/// 资源GUID
/// 说明Meta文件记录的GUID
/// </summary>
public string AssetGUID;
/// <summary>
/// 资源文件大小
/// </summary>
public long FileSize;
/// <summary>
/// 冗余的资源包数量
/// </summary>
public int Number;
}
}

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 7bfd05221983858429246096617dff1d guid: 7fbb7b27f54d3b0439a951348fd9d785
MonoImporter: MonoImporter:
externalObjects: {} externalObjects: {}
serializedVersion: 2 serializedVersion: 2

View File

@ -22,7 +22,7 @@ namespace YooAsset.Editor
/// 构建时间 /// 构建时间
/// </summary> /// </summary>
public string BuildDate; public string BuildDate;
/// <summary> /// <summary>
/// 构建耗时(单位:秒) /// 构建耗时(单位:秒)
/// </summary> /// </summary>
@ -63,6 +63,16 @@ namespace YooAsset.Editor
/// </summary> /// </summary>
public bool UniqueBundleName; public bool UniqueBundleName;
/// <summary>
/// 自动分析冗余
/// </summary>
public bool AutoAnalyzeRedundancy;
/// <summary>
/// 共享资源的打包类名称
/// </summary>
public string ShareAssetPackRuleClassName;
/// <summary> /// <summary>
/// 加密服务类名称 /// 加密服务类名称
/// </summary> /// </summary>

View File

@ -19,7 +19,7 @@ namespace YooAsset.Editor
/// <summary> /// <summary>
/// 构建失败的信息 /// 构建失败的信息
/// </summary> /// </summary>
public string FailedInfo; public string ErrorInfo;
/// <summary> /// <summary>
/// 输出的补丁包目录 /// 输出的补丁包目录

View File

@ -52,7 +52,7 @@ namespace YooAsset.Editor
{ {
EditorTools.ClearProgressBar(); EditorTools.ClearProgressBar();
buildResult.FailedTask = task.GetType().Name; buildResult.FailedTask = task.GetType().Name;
buildResult.FailedInfo = e.ToString(); buildResult.ErrorInfo = e.ToString();
buildResult.Success = false; buildResult.Success = false;
break; break;
} }

View File

@ -98,7 +98,7 @@ namespace YooAsset.Editor
{ {
string fileName = YooAssetSettingsData.GetPackageHashFileName(buildParameters.PackageName, buildParameters.PackageVersion); string fileName = YooAssetSettingsData.GetPackageHashFileName(buildParameters.PackageName, buildParameters.PackageVersion);
string filePath = $"{packageOutputDirectory}/{fileName}"; string filePath = $"{packageOutputDirectory}/{fileName}";
FileUtility.CreateFile(filePath, packageHash); FileUtility.WriteAllText(filePath, packageHash);
BuildLogger.Log($"创建补丁清单哈希文件:{filePath}"); BuildLogger.Log($"创建补丁清单哈希文件:{filePath}");
} }
@ -106,7 +106,7 @@ namespace YooAsset.Editor
{ {
string fileName = YooAssetSettingsData.GetPackageVersionFileName(buildParameters.PackageName); string fileName = YooAssetSettingsData.GetPackageVersionFileName(buildParameters.PackageName);
string filePath = $"{packageOutputDirectory}/{fileName}"; string filePath = $"{packageOutputDirectory}/{fileName}";
FileUtility.CreateFile(filePath, buildParameters.PackageVersion); FileUtility.WriteAllText(filePath, buildParameters.PackageVersion);
BuildLogger.Log($"创建补丁清单版本文件:{filePath}"); BuildLogger.Log($"创建补丁清单版本文件:{filePath}");
} }
} }
@ -205,6 +205,7 @@ namespace YooAsset.Editor
throw new Exception("没有发现着色器资源包!"); throw new Exception("没有发现着色器资源包!");
// 检测依赖交集并更新依赖ID // 检测依赖交集并更新依赖ID
HashSet<string> tagTemps = new HashSet<string>();
foreach (var packageAsset in manifest.AssetList) foreach (var packageAsset in manifest.AssetList)
{ {
List<string> dependBundles = GetPackageAssetAllDependBundles(manifest, packageAsset); List<string> dependBundles = GetPackageAssetAllDependBundles(manifest, packageAsset);
@ -215,8 +216,23 @@ namespace YooAsset.Editor
if (newDependIDs.Contains(shaderBundleId) == false) if (newDependIDs.Contains(shaderBundleId) == false)
newDependIDs.Add(shaderBundleId); newDependIDs.Add(shaderBundleId);
packageAsset.DependIDs = newDependIDs.ToArray(); packageAsset.DependIDs = newDependIDs.ToArray();
foreach (var tag in packageAsset.AssetTags)
{
if (tagTemps.Contains(tag) == false)
tagTemps.Add(tag);
}
} }
} }
// 更新资源包标签
var packageBundle = manifest.BundleList[shaderBundleId];
List<string> newTags = new List<string>(packageBundle.Tags);
foreach (var tag in tagTemps)
{
if (newTags.Contains(tag) == false)
newTags.Add(tag);
}
packageBundle.Tags = newTags.ToArray();
} }
private List<string> GetPackageAssetAllDependBundles(PackageManifest manifest, PackageAsset packageAsset) private List<string> GetPackageAssetAllDependBundles(PackageManifest manifest, PackageAsset packageAsset)
{ {
@ -302,7 +318,7 @@ namespace YooAsset.Editor
{ {
if (packageBundle.IsRawFile) if (packageBundle.IsRawFile)
{ {
_cachedBundleDepends.Add(packageBundle.BundleName, new string[] { } ); _cachedBundleDepends.Add(packageBundle.BundleName, new string[] { });
continue; continue;
} }
@ -321,7 +337,7 @@ namespace YooAsset.Editor
} }
EditorTools.ClearProgressBar(); EditorTools.ClearProgressBar();
} }
private int[] GetBundleRefrenceIDs(PackageManifest manifest, PackageBundle targetBundle) private int[] GetBundleRefrenceIDs(PackageManifest manifest, PackageBundle targetBundle)
{ {
List<string> referenceList = new List<string>(); List<string> referenceList = new List<string>();

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using UnityEditor; using UnityEditor;
namespace YooAsset.Editor namespace YooAsset.Editor
@ -46,6 +47,9 @@ namespace YooAsset.Editor
buildReport.Summary.BuildPackageVersion = buildParameters.PackageVersion; buildReport.Summary.BuildPackageVersion = buildParameters.PackageVersion;
buildReport.Summary.EnableAddressable = buildMapContext.EnableAddressable; buildReport.Summary.EnableAddressable = buildMapContext.EnableAddressable;
buildReport.Summary.UniqueBundleName = buildMapContext.UniqueBundleName; buildReport.Summary.UniqueBundleName = buildMapContext.UniqueBundleName;
buildReport.Summary.AutoAnalyzeRedundancy = buildParameters.AutoAnalyzeRedundancy;
buildReport.Summary.ShareAssetPackRuleClassName = buildParameters.ShareAssetPackRule == null ?
"null" : buildParameters.ShareAssetPackRule.GetType().FullName;
buildReport.Summary.EncryptionServicesClassName = buildParameters.EncryptionServices == null ? buildReport.Summary.EncryptionServicesClassName = buildParameters.EncryptionServices == null ?
"null" : buildParameters.EncryptionServices.GetType().FullName; "null" : buildParameters.EncryptionServices.GetType().FullName;
@ -101,6 +105,9 @@ namespace YooAsset.Editor
buildReport.BundleInfos.Add(reportBundleInfo); buildReport.BundleInfos.Add(reportBundleInfo);
} }
// 冗余资源列表
buildReport.RedundancyInfos = new List<ReportRedundancyInfo>(buildMapContext.RedundancyInfos);
// 序列化文件 // 序列化文件
string fileName = YooAssetSettingsData.GetReportFileName(buildParameters.PackageName, buildParameters.PackageVersion); string fileName = YooAssetSettingsData.GetReportFileName(buildParameters.PackageName, buildParameters.PackageVersion);
string filePath = $"{packageOutputDirectory}/{fileName}"; string filePath = $"{packageOutputDirectory}/{fileName}";

View File

@ -52,7 +52,7 @@ namespace YooAsset.Editor
} }
string filePath = $"{pipelineOutputDirectory}/{bundleInfo.BundleName}.encrypt"; string filePath = $"{pipelineOutputDirectory}/{bundleInfo.BundleName}.encrypt";
FileUtility.CreateFile(filePath, encryptResult.EncryptedData); FileUtility.WriteAllBytes(filePath, encryptResult.EncryptedData);
bundleInfo.EncryptedFilePath = filePath; bundleInfo.EncryptedFilePath = filePath;
bundleInfo.LoadMethod = encryptResult.LoadMethod; bundleInfo.LoadMethod = encryptResult.LoadMethod;
BuildLogger.Log($"Bundle文件加密完成{filePath}"); BuildLogger.Log($"Bundle文件加密完成{filePath}");

View File

@ -13,7 +13,7 @@ namespace YooAsset.Editor
void IBuildTask.Run(BuildContext context) void IBuildTask.Run(BuildContext context)
{ {
var buildParametersContext = context.GetContextObject<BuildParametersContext>(); var buildParametersContext = context.GetContextObject<BuildParametersContext>();
var buildMapContext = CreateBuildMap(buildParametersContext.Parameters.BuildMode, buildParametersContext.Parameters.PackageName); var buildMapContext = CreateBuildMap(buildParametersContext.Parameters);
context.SetContextObject(buildMapContext); context.SetContextObject(buildMapContext);
BuildLogger.Log("构建内容准备完毕!"); BuildLogger.Log("构建内容准备完毕!");
@ -24,8 +24,13 @@ namespace YooAsset.Editor
/// <summary> /// <summary>
/// 资源构建上下文 /// 资源构建上下文
/// </summary> /// </summary>
public BuildMapContext CreateBuildMap(EBuildMode buildMode, string packageName) public BuildMapContext CreateBuildMap(BuildParameters buildParameters)
{ {
EBuildMode buildMode = buildParameters.BuildMode;
string packageName = buildParameters.PackageName;
IShareAssetPackRule sharePackRule = buildParameters.ShareAssetPackRule;
bool autoAnalyzeRedundancy = buildParameters.AutoAnalyzeRedundancy;
Dictionary<string, BuildAssetInfo> allBuildAssetInfoDic = new Dictionary<string, BuildAssetInfo>(1000); Dictionary<string, BuildAssetInfo> allBuildAssetInfoDic = new Dictionary<string, BuildAssetInfo>(1000);
// 1. 检测配置合法性 // 1. 检测配置合法性
@ -98,10 +103,30 @@ namespace YooAsset.Editor
context.ShadersBundleName = collectResult.Command.ShadersBundleName; context.ShadersBundleName = collectResult.Command.ShadersBundleName;
// 8. 计算共享的资源包名 // 8. 计算共享的资源包名
var command = collectResult.Command; if (autoAnalyzeRedundancy)
foreach (var buildAssetInfo in allBuildAssetInfoDic.Values)
{ {
buildAssetInfo.CalculateShareBundleName(command.UniqueBundleName, command.PackageName, command.ShadersBundleName); var command = collectResult.Command;
foreach (var buildAssetInfo in allBuildAssetInfoDic.Values)
{
buildAssetInfo.CalculateShareBundleName(sharePackRule, command.UniqueBundleName, command.PackageName, command.ShadersBundleName);
}
}
else
{
// 记录冗余资源
foreach (var buildAssetInfo in allBuildAssetInfoDic.Values)
{
if (buildAssetInfo.IsRedundancyAsset())
{
var redundancyInfo = new ReportRedundancyInfo();
redundancyInfo.AssetPath = buildAssetInfo.AssetPath;
redundancyInfo.AssetType = AssetDatabase.GetMainAssetTypeAtPath(buildAssetInfo.AssetPath).Name;
redundancyInfo.AssetGUID = AssetDatabase.AssetPathToGUID(buildAssetInfo.AssetPath);
redundancyInfo.FileSize = FileUtility.GetFileSize(buildAssetInfo.AssetPath);
redundancyInfo.Number = buildAssetInfo.GetReferenceBundleCount();
context.RedundancyInfos.Add(redundancyInfo);
}
}
} }
// 9. 移除不参与构建的资源 // 9. 移除不参与构建的资源

View File

@ -24,6 +24,13 @@ namespace YooAsset.Editor
if (buildParameters.BuildMode != EBuildMode.SimulateBuild) if (buildParameters.BuildMode != EBuildMode.SimulateBuild)
{ {
#if UNITY_2021_3_OR_NEWER
if (buildParameters.BuildPipeline == EBuildPipeline.BuiltinBuildPipeline)
{
BuildLogger.Warning("推荐使用可编程构建管线SBP");
}
#endif
// 检测当前是否正在构建资源包 // 检测当前是否正在构建资源包
if (BuildPipeline.isBuildingPlayer) if (BuildPipeline.isBuildingPlayer)
throw new Exception("当前正在构建资源包,请结束后再试"); throw new Exception("当前正在构建资源包,请结束后再试");
@ -40,6 +47,20 @@ namespace YooAsset.Editor
throw new Exception("首包资源标签不能为空!"); throw new Exception("首包资源标签不能为空!");
} }
// 检测共享资源打包规则
if (buildParameters.ShareAssetPackRule == null)
throw new Exception("共享资源打包规则不能为空!");
#if UNITY_WEBGL
if (buildParameters.EncryptionServices != null)
{
if (buildParameters.EncryptionServices.GetType() != typeof(EncryptionNone))
{
throw new Exception("WebGL平台不支持加密");
}
}
#endif
// 检测包裹输出目录是否存在 // 检测包裹输出目录是否存在
string packageOutputDirectory = buildParametersContext.GetPackageOutputDirectory(); string packageOutputDirectory = buildParametersContext.GetPackageOutputDirectory();
if (Directory.Exists(packageOutputDirectory)) if (Directory.Exists(packageOutputDirectory))

View File

@ -197,16 +197,17 @@ namespace YooAsset.Editor
// 检测可寻址地址是否重复 // 检测可寻址地址是否重复
if (command.EnableAddressable) if (command.EnableAddressable)
{ {
HashSet<string> adressTemper = new HashSet<string>(); var addressTemper = new Dictionary<string, string>();
foreach (var collectInfoPair in result) foreach (var collectInfoPair in result)
{ {
if (collectInfoPair.Value.CollectorType == ECollectorType.MainAssetCollector) if (collectInfoPair.Value.CollectorType == ECollectorType.MainAssetCollector)
{ {
string address = collectInfoPair.Value.Address; string address = collectInfoPair.Value.Address;
if (adressTemper.Contains(address) == false) string assetPath = collectInfoPair.Value.AssetPath;
adressTemper.Add(address); if (addressTemper.TryGetValue(address, out var existed) == false)
addressTemper.Add(address, assetPath);
else else
throw new Exception($"The address is existed : {address} in collector : {CollectPath}"); throw new Exception($"The address is existed : {address} in collector : {CollectPath} \nAssetPath:\n {existed}\n {assetPath}");
} }
} }
} }
@ -250,7 +251,7 @@ namespace YooAsset.Editor
// 检测原生文件是否合规 // 检测原生文件是否合规
if (isRawFilePackRule) if (isRawFilePackRule)
{ {
string extension = StringUtility.RemoveFirstChar(System.IO.Path.GetExtension(assetPath)); string extension = EditorTools.RemoveFirstChar(System.IO.Path.GetExtension(assetPath));
if (extension == EAssetFileExtension.unity.ToString() || extension == EAssetFileExtension.prefab.ToString() || if (extension == EAssetFileExtension.unity.ToString() || extension == EAssetFileExtension.prefab.ToString() ||
extension == EAssetFileExtension.fbx.ToString() || extension == EAssetFileExtension.mat.ToString() || extension == EAssetFileExtension.fbx.ToString() || extension == EAssetFileExtension.mat.ToString() ||
extension == EAssetFileExtension.controller.ToString() || extension == EAssetFileExtension.anim.ToString() || extension == EAssetFileExtension.controller.ToString() || extension == EAssetFileExtension.anim.ToString() ||
@ -289,10 +290,6 @@ namespace YooAsset.Editor
} }
private bool IsCollectAsset(string assetPath) private bool IsCollectAsset(string assetPath)
{ {
Type assetType = AssetDatabase.GetMainAssetTypeAtPath(assetPath);
if (assetType == typeof(UnityEngine.Shader) || assetType == typeof(UnityEngine.ShaderVariantCollection))
return true;
// 根据规则设置过滤资源文件 // 根据规则设置过滤资源文件
IFilterRule filterRuleInstance = AssetBundleCollectorSettingData.GetFilterRuleInstance(FilterRuleName); IFilterRule filterRuleInstance = AssetBundleCollectorSettingData.GetFilterRuleInstance(FilterRuleName);
return filterRuleInstance.IsCollectAsset(new FilterRuleData(assetPath)); return filterRuleInstance.IsCollectAsset(new FilterRuleData(assetPath));

View File

@ -96,16 +96,17 @@ namespace YooAsset.Editor
// 检测可寻址地址是否重复 // 检测可寻址地址是否重复
if (command.EnableAddressable) if (command.EnableAddressable)
{ {
HashSet<string> adressTemper = new HashSet<string>(); var addressTemper = new Dictionary<string, string>();
foreach (var collectInfoPair in result) foreach (var collectInfoPair in result)
{ {
if (collectInfoPair.Value.CollectorType == ECollectorType.MainAssetCollector) if (collectInfoPair.Value.CollectorType == ECollectorType.MainAssetCollector)
{ {
string address = collectInfoPair.Value.Address; string address = collectInfoPair.Value.Address;
if (adressTemper.Contains(address) == false) string assetPath = collectInfoPair.Value.AssetPath;
adressTemper.Add(address); if (addressTemper.TryGetValue(address, out var existed) == false)
addressTemper.Add(address, assetPath);
else else
throw new Exception($"The address is existed : {address} in group : {GroupName}"); throw new Exception($"The address is existed : {address} in group : {GroupName} \nAssetPath:\n {existed}\n {assetPath}");
} }
} }
} }

View File

@ -76,16 +76,17 @@ namespace YooAsset.Editor
// 检测可寻址地址是否重复 // 检测可寻址地址是否重复
if (command.EnableAddressable) if (command.EnableAddressable)
{ {
HashSet<string> adressTemper = new HashSet<string>(); var addressTemper = new Dictionary<string, string>();
foreach (var collectInfoPair in result) foreach (var collectInfoPair in result)
{ {
if (collectInfoPair.Value.CollectorType == ECollectorType.MainAssetCollector) if (collectInfoPair.Value.CollectorType == ECollectorType.MainAssetCollector)
{ {
string address = collectInfoPair.Value.Address; string address = collectInfoPair.Value.Address;
if (adressTemper.Contains(address) == false) string assetPath = collectInfoPair.Value.AssetPath;
adressTemper.Add(address); if (addressTemper.TryGetValue(address, out var existed) == false)
addressTemper.Add(address, assetPath);
else else
throw new Exception($"The address is existed : {address}"); throw new Exception($"The address is existed : {address} \nAssetPath:\n {existed}\n {assetPath}");
} }
} }
} }

View File

@ -6,6 +6,7 @@ using UnityEngine;
namespace YooAsset.Editor namespace YooAsset.Editor
{ {
[CreateAssetMenu(fileName = "AssetBundleCollectorSetting", menuName = "YooAsset/Create AssetBundle Collector Settings")]
public class AssetBundleCollectorSetting : ScriptableObject public class AssetBundleCollectorSetting : ScriptableObject
{ {
/// <summary> /// <summary>

View File

@ -12,7 +12,7 @@ namespace YooAsset.Editor
public class AssetBundleCollectorWindow : EditorWindow public class AssetBundleCollectorWindow : EditorWindow
{ {
[MenuItem("YooAsset/AssetBundle Collector", false, 101)] [MenuItem("YooAsset/AssetBundle Collector", false, 101)]
public static void ShowExample() public static void OpenWindow()
{ {
AssetBundleCollectorWindow window = GetWindow<AssetBundleCollectorWindow>("资源包收集工具", true, WindowsDefine.DockedWindowTypes); AssetBundleCollectorWindow window = GetWindow<AssetBundleCollectorWindow>("资源包收集工具", true, WindowsDefine.DockedWindowTypes);
window.minSize = new Vector2(800, 600); window.minSize = new Vector2(800, 600);

View File

@ -40,7 +40,7 @@ namespace YooAsset.Editor
{ {
PackRuleResult IPackRule.GetPackRuleResult(PackRuleData data) PackRuleResult IPackRule.GetPackRuleResult(PackRuleData data)
{ {
string bundleName = StringUtility.RemoveExtension(data.AssetPath); string bundleName = PathUtility.RemoveExtension(data.AssetPath);
PackRuleResult result = new PackRuleResult(bundleName, DefaultPackRule.AssetBundleFileExtension); PackRuleResult result = new PackRuleResult(bundleName, DefaultPackRule.AssetBundleFileExtension);
return result; return result;
} }
@ -60,8 +60,6 @@ namespace YooAsset.Editor
[DisplayName("资源包名: 父类文件夹路径")] [DisplayName("资源包名: 父类文件夹路径")]
public class PackDirectory : IPackRule public class PackDirectory : IPackRule
{ {
public static PackDirectory StaticPackRule = new PackDirectory();
PackRuleResult IPackRule.GetPackRuleResult(PackRuleData data) PackRuleResult IPackRule.GetPackRuleResult(PackRuleData data)
{ {
string bundleName = Path.GetDirectoryName(data.AssetPath); string bundleName = Path.GetDirectoryName(data.AssetPath);
@ -127,7 +125,7 @@ namespace YooAsset.Editor
} }
else else
{ {
bundleName = StringUtility.RemoveExtension(collectPath); bundleName = PathUtility.RemoveExtension(collectPath);
} }
PackRuleResult result = new PackRuleResult(bundleName, DefaultPackRule.AssetBundleFileExtension); PackRuleResult result = new PackRuleResult(bundleName, DefaultPackRule.AssetBundleFileExtension);

View File

@ -0,0 +1,16 @@
using System;
using System.IO;
using UnityEditor;
namespace YooAsset.Editor
{
public class DefaultShareAssetPackRule : IShareAssetPackRule
{
public PackRuleResult GetPackRuleResult(string assetPath)
{
string bundleName = Path.GetDirectoryName(assetPath);
PackRuleResult result = new PackRuleResult(bundleName, DefaultPackRule.AssetBundleFileExtension);
return result;
}
}
}

View File

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

View File

@ -0,0 +1,14 @@

namespace YooAsset.Editor
{
/// <summary>
/// 共享资源的打包规则
/// </summary>
public interface IShareAssetPackRule
{
/// <summary>
/// 获取打包规则结果
/// </summary>
PackRuleResult GetPackRuleResult(string assetPath);
}
}

View File

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

View File

@ -13,7 +13,7 @@ namespace YooAsset.Editor
public class AssetBundleDebuggerWindow : EditorWindow public class AssetBundleDebuggerWindow : EditorWindow
{ {
[MenuItem("YooAsset/AssetBundle Debugger", false, 104)] [MenuItem("YooAsset/AssetBundle Debugger", false, 104)]
public static void ShowExample() public static void OpenWindow()
{ {
AssetBundleDebuggerWindow wnd = GetWindow<AssetBundleDebuggerWindow>("资源包调试工具", true, WindowsDefine.DockedWindowTypes); AssetBundleDebuggerWindow wnd = GetWindow<AssetBundleDebuggerWindow>("资源包调试工具", true, WindowsDefine.DockedWindowTypes);
wnd.minSize = new Vector2(800, 600); wnd.minSize = new Vector2(800, 600);
@ -278,7 +278,7 @@ namespace YooAsset.Editor
string filePath = $"{resultPath}/{nameof(DebugReport)}_{_currentReport.FrameCount}.json"; string filePath = $"{resultPath}/{nameof(DebugReport)}_{_currentReport.FrameCount}.json";
string fileContent = JsonUtility.ToJson(_currentReport, true); string fileContent = JsonUtility.ToJson(_currentReport, true);
FileUtility.CreateFile(filePath, fileContent); FileUtility.WriteAllText(filePath, fileContent);
} }
} }
private void OnSearchKeyWordChange(ChangeEvent<string> e) private void OnSearchKeyWordChange(ChangeEvent<string> e)

View File

@ -10,7 +10,7 @@ namespace YooAsset.Editor
public class AssetBundleReporterWindow : EditorWindow public class AssetBundleReporterWindow : EditorWindow
{ {
[MenuItem("YooAsset/AssetBundle Reporter", false, 103)] [MenuItem("YooAsset/AssetBundle Reporter", false, 103)]
public static void ShowExample() public static void OpenWindow()
{ {
AssetBundleReporterWindow window = GetWindow<AssetBundleReporterWindow>("资源包报告工具", true, WindowsDefine.DockedWindowTypes); AssetBundleReporterWindow window = GetWindow<AssetBundleReporterWindow>("资源包报告工具", true, WindowsDefine.DockedWindowTypes);
window.minSize = new Vector2(800, 600); window.minSize = new Vector2(800, 600);
@ -35,12 +35,18 @@ namespace YooAsset.Editor
/// 资源包视图 /// 资源包视图
/// </summary> /// </summary>
BundleView, BundleView,
/// <summary>
/// 冗余资源试图
/// </summary>
Redundancy,
} }
private ToolbarMenu _viewModeMenu; private ToolbarMenu _viewModeMenu;
private ReporterSummaryViewer _summaryViewer; private ReporterSummaryViewer _summaryViewer;
private ReporterAssetListViewer _assetListViewer; private ReporterAssetListViewer _assetListViewer;
private ReporterBundleListViewer _bundleListViewer; private ReporterBundleListViewer _bundleListViewer;
private ReporterRedundancyListViewer _redundancyListViewer;
private EViewMode _viewMode; private EViewMode _viewMode;
private BuildReport _buildReport; private BuildReport _buildReport;
@ -70,6 +76,7 @@ namespace YooAsset.Editor
_viewModeMenu.menu.AppendAction(EViewMode.Summary.ToString(), ViewModeMenuAction0, ViewModeMenuFun0); _viewModeMenu.menu.AppendAction(EViewMode.Summary.ToString(), ViewModeMenuAction0, ViewModeMenuFun0);
_viewModeMenu.menu.AppendAction(EViewMode.AssetView.ToString(), ViewModeMenuAction1, ViewModeMenuFun1); _viewModeMenu.menu.AppendAction(EViewMode.AssetView.ToString(), ViewModeMenuAction1, ViewModeMenuFun1);
_viewModeMenu.menu.AppendAction(EViewMode.BundleView.ToString(), ViewModeMenuAction2, ViewModeMenuFun2); _viewModeMenu.menu.AppendAction(EViewMode.BundleView.ToString(), ViewModeMenuAction2, ViewModeMenuFun2);
_viewModeMenu.menu.AppendAction(EViewMode.Redundancy.ToString(), ViewModeMenuAction3, ViewModeMenuFun3);
// 搜索栏 // 搜索栏
var searchField = root.Q<ToolbarSearchField>("SearchField"); var searchField = root.Q<ToolbarSearchField>("SearchField");
@ -87,6 +94,10 @@ namespace YooAsset.Editor
_bundleListViewer = new ReporterBundleListViewer(); _bundleListViewer = new ReporterBundleListViewer();
_bundleListViewer.InitViewer(); _bundleListViewer.InitViewer();
// 加载试图
_redundancyListViewer = new ReporterRedundancyListViewer();
_redundancyListViewer.InitViewer();
// 显示视图 // 显示视图
_viewMode = EViewMode.Summary; _viewMode = EViewMode.Summary;
_viewModeMenu.text = EViewMode.Summary.ToString(); _viewModeMenu.text = EViewMode.Summary.ToString();
@ -111,9 +122,10 @@ namespace YooAsset.Editor
_reportFilePath = selectFilePath; _reportFilePath = selectFilePath;
string jsonData = FileUtility.ReadAllText(_reportFilePath); string jsonData = FileUtility.ReadAllText(_reportFilePath);
_buildReport = BuildReport.Deserialize(jsonData); _buildReport = BuildReport.Deserialize(jsonData);
_summaryViewer.FillViewData(_buildReport);
_assetListViewer.FillViewData(_buildReport, _searchKeyWord); _assetListViewer.FillViewData(_buildReport, _searchKeyWord);
_bundleListViewer.FillViewData(_buildReport, _reportFilePath, _searchKeyWord); _bundleListViewer.FillViewData(_buildReport, _reportFilePath, _searchKeyWord);
_summaryViewer.FillViewData(_buildReport); _redundancyListViewer.FillViewData(_buildReport, _searchKeyWord);
} }
private void OnSearchKeyWordChange(ChangeEvent<string> e) private void OnSearchKeyWordChange(ChangeEvent<string> e)
{ {
@ -134,6 +146,7 @@ namespace YooAsset.Editor
_summaryViewer.AttachParent(root); _summaryViewer.AttachParent(root);
_assetListViewer.DetachParent(); _assetListViewer.DetachParent();
_bundleListViewer.DetachParent(); _bundleListViewer.DetachParent();
_redundancyListViewer.DetachParent();
} }
} }
private void ViewModeMenuAction1(DropdownMenuAction action) private void ViewModeMenuAction1(DropdownMenuAction action)
@ -146,6 +159,7 @@ namespace YooAsset.Editor
_summaryViewer.DetachParent(); _summaryViewer.DetachParent();
_assetListViewer.AttachParent(root); _assetListViewer.AttachParent(root);
_bundleListViewer.DetachParent(); _bundleListViewer.DetachParent();
_redundancyListViewer.DetachParent();
} }
} }
private void ViewModeMenuAction2(DropdownMenuAction action) private void ViewModeMenuAction2(DropdownMenuAction action)
@ -158,6 +172,20 @@ namespace YooAsset.Editor
_summaryViewer.DetachParent(); _summaryViewer.DetachParent();
_assetListViewer.DetachParent(); _assetListViewer.DetachParent();
_bundleListViewer.AttachParent(root); _bundleListViewer.AttachParent(root);
_redundancyListViewer.DetachParent();
}
}
private void ViewModeMenuAction3(DropdownMenuAction action)
{
if (_viewMode != EViewMode.Redundancy)
{
_viewMode = EViewMode.Redundancy;
VisualElement root = this.rootVisualElement;
_viewModeMenu.text = EViewMode.Redundancy.ToString();
_summaryViewer.DetachParent();
_assetListViewer.DetachParent();
_bundleListViewer.DetachParent();
_redundancyListViewer.AttachParent(root);
} }
} }
private DropdownMenuAction.Status ViewModeMenuFun0(DropdownMenuAction action) private DropdownMenuAction.Status ViewModeMenuFun0(DropdownMenuAction action)
@ -181,6 +209,13 @@ namespace YooAsset.Editor
else else
return DropdownMenuAction.Status.Normal; return DropdownMenuAction.Status.Normal;
} }
private DropdownMenuAction.Status ViewModeMenuFun3(DropdownMenuAction action)
{
if (_viewMode == EViewMode.Redundancy)
return DropdownMenuAction.Status.Checked;
else
return DropdownMenuAction.Status.Normal;
}
} }
} }
#endif #endif

View File

@ -0,0 +1,317 @@
#if UNITY_2019_4_OR_NEWER
using System;
using System.Linq;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEditor.UIElements;
using UnityEngine.UIElements;
namespace YooAsset.Editor
{
internal class ReporterRedundancyListViewer
{
private enum ESortMode
{
AssetPath,
AssetType,
FileSize,
Number,
}
private VisualTreeAsset _visualAsset;
private TemplateContainer _root;
private ToolbarButton _topBar1;
private ToolbarButton _topBar2;
private ToolbarButton _topBar3;
private ToolbarButton _topBar4;
private ListView _assetListView;
private BuildReport _buildReport;
private string _searchKeyWord;
private ESortMode _sortMode = ESortMode.AssetPath;
private bool _descendingSort = false;
/// <summary>
/// 初始化页面
/// </summary>
public void InitViewer()
{
// 加载布局文件
_visualAsset = UxmlLoader.LoadWindowUXML<ReporterRedundancyListViewer>();
if (_visualAsset == null)
return;
_root = _visualAsset.CloneTree();
_root.style.flexGrow = 1f;
// 顶部按钮栏
_topBar1 = _root.Q<ToolbarButton>("TopBar1");
_topBar2 = _root.Q<ToolbarButton>("TopBar2");
_topBar3 = _root.Q<ToolbarButton>("TopBar3");
_topBar4 = _root.Q<ToolbarButton>("TopBar4");
_topBar1.clicked += TopBar1_clicked;
_topBar2.clicked += TopBar2_clicked;
_topBar3.clicked += TopBar3_clicked;
_topBar4.clicked += TopBar4_clicked;
// 资源列表
_assetListView = _root.Q<ListView>("TopListView");
_assetListView.makeItem = MakeAssetListViewItem;
_assetListView.bindItem = BindAssetListViewItem;
}
/// <summary>
/// 填充页面数据
/// </summary>
public void FillViewData(BuildReport buildReport, string searchKeyWord)
{
_buildReport = buildReport;
_searchKeyWord = searchKeyWord;
RefreshView();
}
private void RefreshView()
{
_assetListView.Clear();
_assetListView.ClearSelection();
_assetListView.itemsSource = FilterAndSortViewItems();
_assetListView.Rebuild();
RefreshSortingSymbol();
}
private List<ReportRedundancyInfo> FilterAndSortViewItems()
{
List<ReportRedundancyInfo> result = new List<ReportRedundancyInfo>(_buildReport.RedundancyInfos.Count);
// 过滤列表
foreach (var redundancyInfo in _buildReport.RedundancyInfos)
{
if (string.IsNullOrEmpty(_searchKeyWord) == false)
{
if (redundancyInfo.AssetPath.Contains(_searchKeyWord) == false)
continue;
}
result.Add(redundancyInfo);
}
// 排序列表
if (_sortMode == ESortMode.AssetPath)
{
if (_descendingSort)
return result.OrderByDescending(a => a.AssetPath).ToList();
else
return result.OrderBy(a => a.AssetPath).ToList();
}
else if(_sortMode == ESortMode.AssetType)
{
if (_descendingSort)
return result.OrderByDescending(a => a.AssetType).ToList();
else
return result.OrderBy(a => a.AssetType).ToList();
}
else if (_sortMode == ESortMode.FileSize)
{
if (_descendingSort)
return result.OrderByDescending(a => a.FileSize).ToList();
else
return result.OrderBy(a => a.FileSize).ToList();
}
else if (_sortMode == ESortMode.Number)
{
if (_descendingSort)
return result.OrderByDescending(a => a.Number).ToList();
else
return result.OrderBy(a => a.Number).ToList();
}
else
{
throw new System.NotImplementedException();
}
}
private void RefreshSortingSymbol()
{
_topBar1.text = $"Asset Path ({_assetListView.itemsSource.Count})";
_topBar2.text = "Asset Type";
_topBar3.text = "File Size";
_topBar4.text = "Redundancy Num";
if (_sortMode == ESortMode.AssetPath)
{
if (_descendingSort)
_topBar1.text = $"Asset Path ({_assetListView.itemsSource.Count}) ↓";
else
_topBar1.text = $"Asset Path ({_assetListView.itemsSource.Count}) ↑";
}
else if(_sortMode == ESortMode.AssetType)
{
if (_descendingSort)
_topBar2.text = "Asset Type ↓";
else
_topBar2.text = "Asset Type ↑";
}
else if (_sortMode == ESortMode.FileSize)
{
if (_descendingSort)
_topBar3.text = "File Size ↓";
else
_topBar3.text = "File Size ↑";
}
else if (_sortMode == ESortMode.Number)
{
if (_descendingSort)
_topBar4.text = "Redundancy Num ↓";
else
_topBar4.text = "Redundancy Num ↑";
}
else
{
throw new System.NotImplementedException();
}
}
/// <summary>
/// 挂接到父类页面上
/// </summary>
public void AttachParent(VisualElement parent)
{
parent.Add(_root);
}
/// <summary>
/// 从父类页面脱离开
/// </summary>
public void DetachParent()
{
_root.RemoveFromHierarchy();
}
// 资源列表相关
private VisualElement MakeAssetListViewItem()
{
VisualElement element = new VisualElement();
element.style.flexDirection = FlexDirection.Row;
{
var label = new Label();
label.name = "Label1";
label.style.unityTextAlign = TextAnchor.MiddleLeft;
label.style.marginLeft = 3f;
label.style.flexGrow = 1f;
label.style.width = 280;
element.Add(label);
}
{
var label = new Label();
label.name = "Label2";
label.style.unityTextAlign = TextAnchor.MiddleLeft;
label.style.marginLeft = 3f;
label.style.flexGrow = 0;
label.style.width = 125;
element.Add(label);
}
{
var label = new Label();
label.name = "Label3";
label.style.unityTextAlign = TextAnchor.MiddleLeft;
label.style.marginLeft = 3f;
label.style.flexGrow = 0;
label.style.width = 125;
element.Add(label);
}
{
var label = new Label();
label.name = "Label4";
label.style.unityTextAlign = TextAnchor.MiddleLeft;
label.style.marginLeft = 3f;
label.style.flexGrow = 0;
label.style.width = 125;
element.Add(label);
}
return element;
}
private void BindAssetListViewItem(VisualElement element, int index)
{
var sourceData = _assetListView.itemsSource as List<ReportRedundancyInfo>;
var redundancyInfo = sourceData[index];
// Asset Path
var label1 = element.Q<Label>("Label1");
label1.text = redundancyInfo.AssetPath;
// Asset Type
var label2 = element.Q<Label>("Label2");
label2.text = redundancyInfo.AssetType;
// File Size
var label3 = element.Q<Label>("Label3");
label3.text = EditorUtility.FormatBytes(redundancyInfo.FileSize);
// Number
var label4 = element.Q<Label>("Label4");
label4.text = redundancyInfo.Number.ToString();
}
private void TopBar1_clicked()
{
if (_sortMode != ESortMode.AssetPath)
{
_sortMode = ESortMode.AssetPath;
_descendingSort = false;
RefreshView();
}
else
{
_descendingSort = !_descendingSort;
RefreshView();
}
}
private void TopBar2_clicked()
{
if (_sortMode != ESortMode.AssetType)
{
_sortMode = ESortMode.AssetType;
_descendingSort = false;
RefreshView();
}
else
{
_descendingSort = !_descendingSort;
RefreshView();
}
}
private void TopBar3_clicked()
{
if (_sortMode != ESortMode.FileSize)
{
_sortMode = ESortMode.FileSize;
_descendingSort = false;
RefreshView();
}
else
{
_descendingSort = !_descendingSort;
RefreshView();
}
}
private void TopBar4_clicked()
{
if (_sortMode != ESortMode.Number)
{
_sortMode = ESortMode.Number;
_descendingSort = false;
RefreshView();
}
else
{
_descendingSort = !_descendingSort;
RefreshView();
}
}
}
}
#endif

View File

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

View File

@ -0,0 +1,11 @@
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" editor-extension-mode="False">
<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="Asset Type" display-tooltip-when-elided="true" name="TopBar2" style="width: 125px; -unity-text-align: middle-left; flex-grow: 0; flex-shrink: 1;" />
<uie:ToolbarButton text="File Size" display-tooltip-when-elided="true" name="TopBar3" style="width: 125px; -unity-text-align: middle-left; flex-grow: 0; flex-shrink: 1;" />
<uie:ToolbarButton text="Redundancy Num" display-tooltip-when-elided="true" name="TopBar4" style="width: 125px; -unity-text-align: middle-left; flex-grow: 0; flex-shrink: 1;" />
</uie:Toolbar>
<ui:ListView focusable="true" name="TopListView" item-height="18" virtualization-method="DynamicHeight" style="flex-grow: 1; flex-basis: 60px;" />
</ui:VisualElement>
</ui:UXML>

View File

@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: a5296d9c037ce3944b5c197cbdd78a8b
ScriptedImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 2
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 13804, guid: 0000000000000000e000000000000000, type: 0}

View File

@ -68,7 +68,9 @@ namespace YooAsset.Editor
_items.Add(new ItemWrapper("启用可寻址资源定位", $"{buildReport.Summary.EnableAddressable}")); _items.Add(new ItemWrapper("启用可寻址资源定位", $"{buildReport.Summary.EnableAddressable}"));
_items.Add(new ItemWrapper("资源包名唯一化", $"{buildReport.Summary.UniqueBundleName}")); _items.Add(new ItemWrapper("资源包名唯一化", $"{buildReport.Summary.UniqueBundleName}"));
_items.Add(new ItemWrapper("加密服务类名称", $"{buildReport.Summary.EncryptionServicesClassName}")); _items.Add(new ItemWrapper("自动分析冗余资源", $"{buildReport.Summary.AutoAnalyzeRedundancy}"));
_items.Add(new ItemWrapper("共享资源的打包类名称", buildReport.Summary.ShareAssetPackRuleClassName));
_items.Add(new ItemWrapper("加密服务类名称", buildReport.Summary.EncryptionServicesClassName));
_items.Add(new ItemWrapper(string.Empty, string.Empty)); _items.Add(new ItemWrapper(string.Empty, string.Empty));
_items.Add(new ItemWrapper("构建参数", string.Empty)); _items.Add(new ItemWrapper("构建参数", string.Empty));

View File

@ -286,6 +286,18 @@ namespace YooAsset.Editor
#endregion #endregion
#region StringUtility #region StringUtility
public static string RemoveFirstChar(string str)
{
if (string.IsNullOrEmpty(str))
return str;
return str.Substring(1);
}
public static string RemoveLastChar(string str)
{
if (string.IsNullOrEmpty(str))
return str;
return str.Substring(0, str.Length - 1);
}
public static List<string> StringToStringList(string str, char separator) public static List<string> StringToStringList(string str, char separator)
{ {
List<string> result = new List<string>(); List<string> result = new List<string>();
@ -303,7 +315,6 @@ namespace YooAsset.Editor
} }
return result; return result;
} }
public static T NameToEnum<T>(string name) public static T NameToEnum<T>(string name)
{ {
if (Enum.IsDefined(typeof(T), name) == false) if (Enum.IsDefined(typeof(T), name) == false)

View File

@ -0,0 +1,17 @@
#if UNITY_2019_4_OR_NEWER
using System;
using UnityEditor;
using UnityEngine;
namespace YooAsset.Editor
{
internal class HomePageWindow
{
[MenuItem("YooAsset/Home Page", false, 1)]
public static void OpenWindow()
{
Application.OpenURL("https://www.yooasset.com/");
}
}
}
#endif

View File

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

View File

@ -2,6 +2,7 @@
namespace YooAsset.Editor namespace YooAsset.Editor
{ {
[CreateAssetMenu(fileName = "ShaderVariantCollectorSetting", menuName = "YooAsset/Create ShaderVariant Collector Settings")]
public class ShaderVariantCollectorSetting : ScriptableObject public class ShaderVariantCollectorSetting : ScriptableObject
{ {
/// <summary> /// <summary>

View File

@ -12,7 +12,7 @@ namespace YooAsset.Editor
public class ShaderVariantCollectorWindow : EditorWindow public class ShaderVariantCollectorWindow : EditorWindow
{ {
[MenuItem("YooAsset/ShaderVariant Collector", false, 201)] [MenuItem("YooAsset/ShaderVariant Collector", false, 201)]
public static void ShowExample() public static void OpenWindow()
{ {
ShaderVariantCollectorWindow window = GetWindow<ShaderVariantCollectorWindow>("着色器变种收集工具", true, WindowsDefine.DockedWindowTypes); ShaderVariantCollectorWindow window = GetWindow<ShaderVariantCollectorWindow>("着色器变种收集工具", true, WindowsDefine.DockedWindowTypes);
window.minSize = new Vector2(800, 600); window.minSize = new Vector2(800, 600);

View File

@ -187,7 +187,7 @@
identification within third-party archives. identification within third-party archives.
Copyright 2018-2021 何冠峰 Copyright 2018-2021 何冠峰
Copyright 2021-2022 TuYoo Games Copyright 2021-2023 TuYoo Games
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

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

View File

@ -112,8 +112,6 @@ namespace YooAsset
var retObject = assetObject as TObject; var retObject = assetObject as TObject;
if (retObject != null) if (retObject != null)
ret.Add(retObject); ret.Add(retObject);
else
YooLogger.Warning($"The type conversion failed : {assetObject.name}");
} }
return ret.ToArray(); return ret.ToArray();
} }

View File

@ -103,13 +103,14 @@ namespace YooAsset
else else
{ {
_steps = ESteps.LoadFile; _steps = ESteps.LoadFile;
return; //下载完毕等待一帧再去加载!
} }
} }
// 3. 内置文件解压 // 3. 内置文件解压
if (_steps == ESteps.Unpack) if (_steps == ESteps.Unpack)
{ {
int failedTryAgain = 1; int failedTryAgain = Impl.DownloadFailedTryAgain;
var bundleInfo = ManifestTools.GetUnpackInfo(MainBundleInfo.Bundle); var bundleInfo = ManifestTools.GetUnpackInfo(MainBundleInfo.Bundle);
_unpacker = DownloadSystem.BeginDownload(bundleInfo, failedTryAgain); _unpacker = DownloadSystem.BeginDownload(bundleInfo, failedTryAgain);
_steps = ESteps.CheckUnpack; _steps = ESteps.CheckUnpack;
@ -245,7 +246,7 @@ namespace YooAsset
var result = CacheSystem.VerifyingRecordFile(MainBundleInfo.Bundle.PackageName, MainBundleInfo.Bundle.CacheGUID); var result = CacheSystem.VerifyingRecordFile(MainBundleInfo.Bundle.PackageName, MainBundleInfo.Bundle.CacheGUID);
if (result != EVerifyResult.Succeed) if (result != EVerifyResult.Succeed)
{ {
YooLogger.Error($"Found possibly corrupt file ! {MainBundleInfo.Bundle.CacheGUID}"); YooLogger.Error($"Found possibly corrupt file ! {MainBundleInfo.Bundle.CacheGUID} Verify result : {result}");
CacheSystem.DiscardFile(MainBundleInfo.Bundle.PackageName, MainBundleInfo.Bundle.CacheGUID); CacheSystem.DiscardFile(MainBundleInfo.Bundle.PackageName, MainBundleInfo.Bundle.CacheGUID);
} }
} }

View File

@ -92,6 +92,7 @@ namespace YooAsset
else else
{ {
_steps = ESteps.LoadCacheFile; _steps = ESteps.LoadCacheFile;
return; //下载完毕等待一帧再去加载!
} }
} }

View File

@ -91,7 +91,7 @@ namespace YooAsset
// 3. 解压内置文件 // 3. 解压内置文件
if (_steps == ESteps.Unpack) if (_steps == ESteps.Unpack)
{ {
int failedTryAgain = 1; int failedTryAgain = Impl.DownloadFailedTryAgain;
var bundleInfo = ManifestTools.GetUnpackInfo(MainBundleInfo.Bundle); var bundleInfo = ManifestTools.GetUnpackInfo(MainBundleInfo.Bundle);
_unpacker = DownloadSystem.BeginDownload(bundleInfo, failedTryAgain); _unpacker = DownloadSystem.BeginDownload(bundleInfo, failedTryAgain);
_steps = ESteps.CheckUnpack; _steps = ESteps.CheckUnpack;

View File

@ -89,7 +89,7 @@ namespace YooAsset
// 3. 从站点下载 // 3. 从站点下载
if (_steps == ESteps.Website) if (_steps == ESteps.Website)
{ {
int failedTryAgain = 1; int failedTryAgain = Impl.DownloadFailedTryAgain;
var bundleInfo = ManifestTools.GetUnpackInfo(MainBundleInfo.Bundle); var bundleInfo = ManifestTools.GetUnpackInfo(MainBundleInfo.Bundle);
_website = DownloadSystem.BeginDownload(bundleInfo, failedTryAgain); _website = DownloadSystem.BeginDownload(bundleInfo, failedTryAgain);
_steps = ESteps.CheckWebsite; _steps = ESteps.CheckWebsite;

View File

@ -23,6 +23,15 @@ namespace YooAsset
_cachedDic.Clear(); _cachedDic.Clear();
} }
/// <summary>
/// 清空指定包裹的所有缓存数据
/// </summary>
public static void ClearPackage(string packageName)
{
var cache = GetOrCreateCache(packageName);
cache.ClearAll();
}
/// <summary> /// <summary>
/// 获取缓存文件总数 /// 获取缓存文件总数
/// </summary> /// </summary>
@ -115,7 +124,7 @@ namespace YooAsset
{ {
return VerifyingInternal(element.TempDataFilePath, element.FileSize, element.FileCRC, EVerifyLevel.High); return VerifyingInternal(element.TempDataFilePath, element.FileSize, element.FileCRC, EVerifyLevel.High);
} }
/// <summary> /// <summary>
/// 验证记录文件(主线程内操作) /// 验证记录文件(主线程内操作)
/// </summary> /// </summary>
@ -148,6 +157,14 @@ namespace YooAsset
return result; return result;
} }
/// <summary>
/// 获取所有的缓存文件
/// </summary>
public static List<string> GetAllCacheGUIDs(ResourcePackage package)
{
var cache = GetOrCreateCache(package.PackageName);
return cache.GetAllKeys();
}
private static EVerifyResult VerifyingInternal(string filePath, long fileSize, string fileCRC, EVerifyLevel verifyLevel) private static EVerifyResult VerifyingInternal(string filePath, long fileSize, string fileCRC, EVerifyLevel verifyLevel)
{ {

View File

@ -6,6 +6,11 @@ namespace YooAsset
/// </summary> /// </summary>
internal enum EVerifyResult internal enum EVerifyResult
{ {
/// <summary>
/// 验证异常
/// </summary>
Exception = -7,
/// <summary> /// <summary>
/// 未找到缓存信息 /// 未找到缓存信息
/// </summary> /// </summary>
@ -37,9 +42,9 @@ namespace YooAsset
FileCrcError = -1, FileCrcError = -1,
/// <summary> /// <summary>
/// 验证异常 /// 默认状态(校验未完成)
/// </summary> /// </summary>
Exception = 0, None = 0,
/// <summary> /// <summary>
/// 验证成功 /// 验证成功

View File

@ -0,0 +1,71 @@
using System.Collections;
using System.Collections.Generic;
using System.IO;
namespace YooAsset
{
/// <summary>
/// 清理本地包裹所有的缓存文件
/// </summary>
public sealed class ClearAllCacheFilesOperation : AsyncOperationBase
{
private enum ESteps
{
None,
GetAllCacheFiles,
ClearAllCacheFiles,
Done,
}
private readonly ResourcePackage _package;
private List<string> _allCacheGUIDs;
private int _fileTotalCount = 0;
private ESteps _steps = ESteps.None;
internal ClearAllCacheFilesOperation(ResourcePackage package)
{
_package = package;
}
internal override void Start()
{
_steps = ESteps.GetAllCacheFiles;
}
internal override void Update()
{
if (_steps == ESteps.None || _steps == ESteps.Done)
return;
if (_steps == ESteps.GetAllCacheFiles)
{
_allCacheGUIDs = CacheSystem.GetAllCacheGUIDs(_package);
_fileTotalCount = _allCacheGUIDs.Count;
YooLogger.Log($"Found all cache file count : {_fileTotalCount}");
_steps = ESteps.ClearAllCacheFiles;
}
if (_steps == ESteps.ClearAllCacheFiles)
{
for (int i = _allCacheGUIDs.Count - 1; i >= 0; i--)
{
string cacheGUID = _allCacheGUIDs[i];
CacheSystem.DiscardFile(_package.PackageName, cacheGUID);
_allCacheGUIDs.RemoveAt(i);
if (OperationSystem.IsBusy)
break;
}
if (_fileTotalCount == 0)
Progress = 1.0f;
else
Progress = 1.0f - (_allCacheGUIDs.Count / _fileTotalCount);
if (_allCacheGUIDs.Count == 0)
{
_steps = ESteps.Done;
Status = EOperationStatus.Succeed;
}
}
}
}
}

View File

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

View File

@ -45,7 +45,7 @@ namespace YooAsset
{ {
// BundleFiles // BundleFiles
{ {
string rootPath = PersistentHelper.GetCachedBundleFileFolderPath(_packageName); string rootPath = PersistentTools.GetCachedBundleFileFolderPath(_packageName);
DirectoryInfo rootDirectory = new DirectoryInfo(rootPath); DirectoryInfo rootDirectory = new DirectoryInfo(rootPath);
if (rootDirectory.Exists) if (rootDirectory.Exists)
{ {
@ -56,7 +56,7 @@ namespace YooAsset
// RawFiles // RawFiles
{ {
string rootPath = PersistentHelper.GetCachedRawFileFolderPath(_packageName); string rootPath = PersistentTools.GetCachedRawFileFolderPath(_packageName);
DirectoryInfo rootDirectory = new DirectoryInfo(rootPath); DirectoryInfo rootDirectory = new DirectoryInfo(rootPath);
if (rootDirectory.Exists) if (rootDirectory.Exists)
{ {

View File

@ -60,11 +60,12 @@ namespace YooAsset
if (_steps == ESteps.Waiting) if (_steps == ESteps.Waiting)
{ {
if (_element.IsDone == false) int result = _element.Result;
if (result == 0)
return; return;
VerifyResult = _element.Result; VerifyResult = (EVerifyResult)result;
if (_element.Result == EVerifyResult.Succeed) if (VerifyResult == EVerifyResult.Succeed)
{ {
_steps = ESteps.Done; _steps = ESteps.Done;
Status = EOperationStatus.Succeed; Status = EOperationStatus.Succeed;
@ -73,7 +74,7 @@ namespace YooAsset
{ {
_steps = ESteps.Done; _steps = ESteps.Done;
Status = EOperationStatus.Failed; Status = EOperationStatus.Failed;
Error = $"Failed verify file : {_element.TempDataFilePath} ! ErrorCode : {_element.Result}"; Error = $"Failed verify file : {_element.TempDataFilePath} ! ErrorCode : {VerifyResult}";
} }
} }
} }
@ -85,8 +86,8 @@ namespace YooAsset
private void VerifyInThread(object obj) private void VerifyInThread(object obj)
{ {
VerifyTempElement element = (VerifyTempElement)obj; VerifyTempElement element = (VerifyTempElement)obj;
element.Result = CacheSystem.VerifyingTempFile(element); int result = (int)CacheSystem.VerifyingTempFile(element);
element.IsDone = true; element.Result = result;
} }
} }
@ -120,11 +121,10 @@ namespace YooAsset
if (_steps == ESteps.VerifyFile) if (_steps == ESteps.VerifyFile)
{ {
_element.Result = CacheSystem.VerifyingTempFile(_element); _element.Result = (int)CacheSystem.VerifyingTempFile(_element);
_element.IsDone = true;
VerifyResult = _element.Result; VerifyResult = (EVerifyResult)_element.Result;
if (_element.Result == EVerifyResult.Succeed) if (VerifyResult == EVerifyResult.Succeed)
{ {
_steps = ESteps.Done; _steps = ESteps.Done;
Status = EOperationStatus.Succeed; Status = EOperationStatus.Succeed;
@ -133,7 +133,7 @@ namespace YooAsset
{ {
_steps = ESteps.Done; _steps = ESteps.Done;
Status = EOperationStatus.Failed; Status = EOperationStatus.Failed;
Error = $"Failed verify file : {_element.TempDataFilePath} ! ErrorCode : {_element.Result}"; Error = $"Failed verify file : {_element.TempDataFilePath} ! ErrorCode : {VerifyResult}";
} }
} }
} }

View File

@ -3,33 +3,25 @@ using System.Collections.Generic;
namespace YooAsset namespace YooAsset
{ {
/// <summary> internal static class PersistentTools
/// 资源路径帮助类
/// </summary>
internal static class PathHelper
{ {
private const string SandboxFolderName = "Sandbox";
private const string CacheFolderName = "CacheFiles";
private const string CachedBundleFileFolder = "BundleFiles";
private const string CachedRawFileFolder = "RawFiles";
private const string ManifestFolderName = "ManifestFiles";
private const string AppFootPrintFileName = "ApplicationFootPrint.bytes";
private static string _buildinPath; private static string _buildinPath;
private static string _sandboxPath; private static string _sandboxPath;
/// <summary>
/// 获取基于流文件夹的加载路径
/// </summary>
public static string MakeStreamingLoadPath(string path)
{
if (string.IsNullOrEmpty(_buildinPath))
{
_buildinPath = StringUtility.Format("{0}/{1}", UnityEngine.Application.streamingAssetsPath, YooAssetSettings.StreamingAssetsBuildinFolder);
}
return StringUtility.Format("{0}/{1}", _buildinPath, path);
}
/// <summary> /// <summary>
/// 获取基于沙盒文件夹的加载路径 /// 重写沙盒跟路径
/// </summary> /// </summary>
public static string MakePersistentLoadPath(string path) public static void OverwriteSandboxPath(string sandboxPath)
{ {
string root = GetPersistentRootPath(); _sandboxPath = sandboxPath;
return StringUtility.Format("{0}/{1}", root, path);
} }
/// <summary> /// <summary>
@ -41,22 +33,54 @@ namespace YooAsset
// 注意:为了方便调试查看,编辑器下把存储目录放到项目里 // 注意:为了方便调试查看,编辑器下把存储目录放到项目里
if (string.IsNullOrEmpty(_sandboxPath)) if (string.IsNullOrEmpty(_sandboxPath))
{ {
string directory = Path.GetDirectoryName(UnityEngine.Application.dataPath); string projectPath = Path.GetDirectoryName(UnityEngine.Application.dataPath);
string projectPath = GetRegularPath(directory); projectPath = PathUtility.RegularPath(projectPath);
_sandboxPath = StringUtility.Format("{0}/Sandbox", projectPath); _sandboxPath = PathUtility.Combine(projectPath, SandboxFolderName);
}
#elif UNITY_STANDALONE
if (string.IsNullOrEmpty(_sandboxPath))
{
_sandboxPath = PathUtility.Combine(UnityEngine.Application.dataPath, SandboxFolderName);
} }
return _sandboxPath;
#else #else
if (string.IsNullOrEmpty(_sandboxPath)) if (string.IsNullOrEmpty(_sandboxPath))
{ {
_sandboxPath = StringUtility.Format("{0}/Sandbox", UnityEngine.Application.persistentDataPath); _sandboxPath = PathUtility.Combine(UnityEngine.Application.persistentDataPath, SandboxFolderName);
} }
return _sandboxPath;
#endif #endif
return _sandboxPath;
} }
private static string GetRegularPath(string path)
/// <summary>
/// 获取基于流文件夹的加载路径
/// </summary>
public static string MakeStreamingLoadPath(string path)
{ {
return path.Replace('\\', '/').Replace("\\", "/"); //替换为Linux路径格式 if (string.IsNullOrEmpty(_buildinPath))
{
_buildinPath = PathUtility.Combine(UnityEngine.Application.streamingAssetsPath, YooAssetSettings.StreamingAssetsBuildinFolder);
}
return PathUtility.Combine(_buildinPath, path);
}
/// <summary>
/// 获取基于沙盒文件夹的加载路径
/// </summary>
public static string MakePersistentLoadPath(string path)
{
string root = GetPersistentRootPath();
return PathUtility.Combine(root, path);
}
public static string MakePersistentLoadPath(string path1, string path2)
{
string root = GetPersistentRootPath();
return PathUtility.Combine(root, path1, path2);
}
public static string MakePersistentLoadPath(string path1, string path2, string path3)
{
string root = GetPersistentRootPath();
return PathUtility.Combine(root, path1, path2, path3);
} }
/// <summary> /// <summary>
@ -76,18 +100,6 @@ namespace YooAsset
return path; return path;
#endif #endif
} }
}
/// <summary>
/// 持久化目录帮助类
/// </summary>
internal static class PersistentHelper
{
private const string CacheFolderName = "CacheFiles";
private const string CachedBundleFileFolder = "BundleFiles";
private const string CachedRawFileFolder = "RawFiles";
private const string ManifestFolderName = "ManifestFiles";
private const string AppFootPrintFileName = "ApplicationFootPrint.bytes";
/// <summary> /// <summary>
@ -95,7 +107,7 @@ namespace YooAsset
/// </summary> /// </summary>
public static void DeleteSandbox() public static void DeleteSandbox()
{ {
string directoryPath = PathHelper.MakePersistentLoadPath(string.Empty); string directoryPath = GetPersistentRootPath();
if (Directory.Exists(directoryPath)) if (Directory.Exists(directoryPath))
Directory.Delete(directoryPath, true); Directory.Delete(directoryPath, true);
} }
@ -105,7 +117,7 @@ namespace YooAsset
/// </summary> /// </summary>
public static void DeleteCacheFolder() public static void DeleteCacheFolder()
{ {
string root = PathHelper.MakePersistentLoadPath(CacheFolderName); string root = MakePersistentLoadPath(CacheFolderName);
if (Directory.Exists(root)) if (Directory.Exists(root))
Directory.Delete(root, true); Directory.Delete(root, true);
} }
@ -115,7 +127,7 @@ namespace YooAsset
/// </summary> /// </summary>
public static void DeleteManifestFolder() public static void DeleteManifestFolder()
{ {
string root = PathHelper.MakePersistentLoadPath(ManifestFolderName); string root = MakePersistentLoadPath(ManifestFolderName);
if (Directory.Exists(root)) if (Directory.Exists(root))
Directory.Delete(root, true); Directory.Delete(root, true);
} }
@ -129,8 +141,7 @@ namespace YooAsset
{ {
if (_cachedBundleFileFolder.TryGetValue(packageName, out string value) == false) if (_cachedBundleFileFolder.TryGetValue(packageName, out string value) == false)
{ {
string root = PathHelper.MakePersistentLoadPath(CacheFolderName); value = MakePersistentLoadPath(CacheFolderName, packageName, CachedBundleFileFolder);
value = $"{root}/{packageName}/{CachedBundleFileFolder}";
_cachedBundleFileFolder.Add(packageName, value); _cachedBundleFileFolder.Add(packageName, value);
} }
return value; return value;
@ -144,8 +155,7 @@ namespace YooAsset
{ {
if (_cachedRawFileFolder.TryGetValue(packageName, out string value) == false) if (_cachedRawFileFolder.TryGetValue(packageName, out string value) == false)
{ {
string root = PathHelper.MakePersistentLoadPath(CacheFolderName); value = MakePersistentLoadPath(CacheFolderName, packageName, CachedRawFileFolder);
value = $"{root}/{packageName}/{CachedRawFileFolder}";
_cachedRawFileFolder.Add(packageName, value); _cachedRawFileFolder.Add(packageName, value);
} }
return value; return value;
@ -156,7 +166,7 @@ namespace YooAsset
/// </summary> /// </summary>
public static string GetAppFootPrintFilePath() public static string GetAppFootPrintFilePath()
{ {
return PathHelper.MakePersistentLoadPath(AppFootPrintFileName); return MakePersistentLoadPath(AppFootPrintFileName);
} }
/// <summary> /// <summary>
@ -165,7 +175,7 @@ namespace YooAsset
public static string GetCacheManifestFilePath(string packageName, string packageVersion) public static string GetCacheManifestFilePath(string packageName, string packageVersion)
{ {
string fileName = YooAssetSettingsData.GetManifestBinaryFileName(packageName, packageVersion); string fileName = YooAssetSettingsData.GetManifestBinaryFileName(packageName, packageVersion);
return PathHelper.MakePersistentLoadPath($"{ManifestFolderName}/{fileName}"); return MakePersistentLoadPath(ManifestFolderName, fileName);
} }
/// <summary> /// <summary>
@ -174,7 +184,7 @@ namespace YooAsset
public static string GetCachePackageHashFilePath(string packageName, string packageVersion) public static string GetCachePackageHashFilePath(string packageName, string packageVersion)
{ {
string fileName = YooAssetSettingsData.GetPackageHashFileName(packageName, packageVersion); string fileName = YooAssetSettingsData.GetPackageHashFileName(packageName, packageVersion);
return PathHelper.MakePersistentLoadPath($"{ManifestFolderName}/{fileName}"); return MakePersistentLoadPath(ManifestFolderName, fileName);
} }
/// <summary> /// <summary>
@ -183,7 +193,7 @@ namespace YooAsset
public static string GetCachePackageVersionFilePath(string packageName) public static string GetCachePackageVersionFilePath(string packageName)
{ {
string fileName = YooAssetSettingsData.GetPackageVersionFileName(packageName); string fileName = YooAssetSettingsData.GetPackageVersionFileName(packageName);
return PathHelper.MakePersistentLoadPath($"{ManifestFolderName}/{fileName}"); return MakePersistentLoadPath(ManifestFolderName, fileName);
} }
/// <summary> /// <summary>
@ -192,7 +202,7 @@ namespace YooAsset
public static void SaveCachePackageVersionFile(string packageName, string version) public static void SaveCachePackageVersionFile(string packageName, string version)
{ {
string filePath = GetCachePackageVersionFilePath(packageName); string filePath = GetCachePackageVersionFilePath(packageName);
FileUtility.CreateFile(filePath, version); FileUtility.WriteAllText(filePath, version);
} }
} }
} }

View File

@ -49,8 +49,7 @@ namespace YooAsset
public string FileCRC { private set; get; } public string FileCRC { private set; get; }
public long FileSize { private set; get; } public long FileSize { private set; get; }
public bool IsDone = false; public int Result = 0; // 注意:原子操作对象
public EVerifyResult Result;
public VerifyTempElement(string tempDataFilePath, string fileCRC, long fileSize) public VerifyTempElement(string tempDataFilePath, string fileCRC, long fileSize)
{ {

View File

@ -16,7 +16,7 @@ namespace YooAsset
public static void SerializeToJson(string savePath, PackageManifest manifest) public static void SerializeToJson(string savePath, PackageManifest manifest)
{ {
string json = JsonUtility.ToJson(manifest, true); string json = JsonUtility.ToJson(manifest, true);
FileUtility.CreateFile(savePath, json); FileUtility.WriteAllText(savePath, json);
} }
/// <summary> /// <summary>
@ -193,7 +193,7 @@ namespace YooAsset
public static BundleInfo GetUnpackInfo(PackageBundle packageBundle) public static BundleInfo GetUnpackInfo(PackageBundle packageBundle)
{ {
// 注意:我们把流加载路径指定为远端下载地址 // 注意:我们把流加载路径指定为远端下载地址
string streamingPath = PathHelper.ConvertToWWWPath(packageBundle.StreamingFilePath); string streamingPath = PersistentTools.ConvertToWWWPath(packageBundle.StreamingFilePath);
BundleInfo bundleInfo = new BundleInfo(packageBundle, BundleInfo.ELoadMode.LoadFromStreaming, streamingPath, streamingPath); BundleInfo bundleInfo = new BundleInfo(packageBundle, BundleInfo.ELoadMode.LoadFromStreaming, streamingPath, streamingPath);
return bundleInfo; return bundleInfo;
} }

View File

@ -222,7 +222,7 @@ namespace YooAsset
// 如果水印发生变化,则说明覆盖安装后首次打开游戏 // 如果水印发生变化,则说明覆盖安装后首次打开游戏
if (appFootPrint.IsDirty()) if (appFootPrint.IsDirty())
{ {
PersistentHelper.DeleteManifestFolder(); PersistentTools.DeleteManifestFolder();
appFootPrint.Coverage(); appFootPrint.Coverage();
YooLogger.Log("Delete manifest files when application foot print dirty !"); YooLogger.Log("Delete manifest files when application foot print dirty !");
} }
@ -376,7 +376,7 @@ namespace YooAsset
/// </summary> /// </summary>
public void Load() public void Load()
{ {
string footPrintFilePath = PersistentHelper.GetAppFootPrintFilePath(); string footPrintFilePath = PersistentTools.GetAppFootPrintFilePath();
if (File.Exists(footPrintFilePath)) if (File.Exists(footPrintFilePath))
{ {
_footPrint = FileUtility.ReadAllText(footPrintFilePath); _footPrint = FileUtility.ReadAllText(footPrintFilePath);
@ -409,8 +409,8 @@ namespace YooAsset
#else #else
_footPrint = Application.buildGUID; _footPrint = Application.buildGUID;
#endif #endif
string footPrintFilePath = PersistentHelper.GetAppFootPrintFilePath(); string footPrintFilePath = PersistentTools.GetAppFootPrintFilePath();
FileUtility.CreateFile(footPrintFilePath, _footPrint); FileUtility.WriteAllText(footPrintFilePath, _footPrint);
YooLogger.Log($"Save application foot print : {_footPrint}"); YooLogger.Log($"Save application foot print : {_footPrint}");
} }
} }

View File

@ -41,7 +41,7 @@ namespace YooAsset
{ {
if (_downloader1 == null) if (_downloader1 == null)
{ {
string savePath = PersistentHelper.GetCachePackageHashFilePath(_packageName, _packageVersion); string savePath = PersistentTools.GetCachePackageHashFilePath(_packageName, _packageVersion);
string fileName = YooAssetSettingsData.GetPackageHashFileName(_packageName, _packageVersion); string fileName = YooAssetSettingsData.GetPackageHashFileName(_packageName, _packageVersion);
string webURL = GetDownloadRequestURL(fileName); string webURL = GetDownloadRequestURL(fileName);
YooLogger.Log($"Beginning to download package hash file : {webURL}"); YooLogger.Log($"Beginning to download package hash file : {webURL}");
@ -71,7 +71,7 @@ namespace YooAsset
{ {
if (_downloader2 == null) if (_downloader2 == null)
{ {
string savePath = PersistentHelper.GetCacheManifestFilePath(_packageName, _packageVersion); string savePath = PersistentTools.GetCacheManifestFilePath(_packageName, _packageVersion);
string fileName = YooAssetSettingsData.GetManifestBinaryFileName(_packageName, _packageVersion); string fileName = YooAssetSettingsData.GetManifestBinaryFileName(_packageName, _packageVersion);
string webURL = GetDownloadRequestURL(fileName); string webURL = GetDownloadRequestURL(fileName);
YooLogger.Log($"Beginning to download manifest file : {webURL}"); YooLogger.Log($"Beginning to download manifest file : {webURL}");

View File

@ -42,8 +42,8 @@ namespace YooAsset
if (_downloader == null) if (_downloader == null)
{ {
string fileName = YooAssetSettingsData.GetManifestBinaryFileName(_buildinPackageName, _buildinPackageVersion); string fileName = YooAssetSettingsData.GetManifestBinaryFileName(_buildinPackageName, _buildinPackageVersion);
string filePath = PathHelper.MakeStreamingLoadPath(fileName); string filePath = PersistentTools.MakeStreamingLoadPath(fileName);
string url = PathHelper.ConvertToWWWPath(filePath); string url = PersistentTools.ConvertToWWWPath(filePath);
_downloader = new UnityWebDataRequester(); _downloader = new UnityWebDataRequester();
_downloader.SendRequest(url); _downloader.SendRequest(url);
} }

View File

@ -67,7 +67,7 @@ namespace YooAsset
if (_steps == ESteps.VerifyFileHash) if (_steps == ESteps.VerifyFileHash)
{ {
_manifestFilePath = PersistentHelper.GetCacheManifestFilePath(_packageName, _packageVersion); _manifestFilePath = PersistentTools.GetCacheManifestFilePath(_packageName, _packageVersion);
if (File.Exists(_manifestFilePath) == false) if (File.Exists(_manifestFilePath) == false)
{ {
_steps = ESteps.Done; _steps = ESteps.Done;
@ -131,7 +131,7 @@ namespace YooAsset
File.Delete(_manifestFilePath); File.Delete(_manifestFilePath);
} }
string hashFilePath = PersistentHelper.GetCachePackageHashFilePath(_packageName, _packageVersion); string hashFilePath = PersistentTools.GetCachePackageHashFilePath(_packageName, _packageVersion);
if (File.Exists(hashFilePath)) if (File.Exists(hashFilePath))
{ {
File.Delete(hashFilePath); File.Delete(hashFilePath);

View File

@ -38,8 +38,8 @@ namespace YooAsset
if (_downloader == null) if (_downloader == null)
{ {
string fileName = YooAssetSettingsData.GetPackageVersionFileName(_packageName); string fileName = YooAssetSettingsData.GetPackageVersionFileName(_packageName);
string filePath = PathHelper.MakeStreamingLoadPath(fileName); string filePath = PersistentTools.MakeStreamingLoadPath(fileName);
string url = PathHelper.ConvertToWWWPath(filePath); string url = PersistentTools.ConvertToWWWPath(filePath);
_downloader = new UnityWebDataRequester(); _downloader = new UnityWebDataRequester();
_downloader.SendRequest(url); _downloader.SendRequest(url);
} }

View File

@ -37,7 +37,7 @@ namespace YooAsset
if (_steps == ESteps.LoadCachePackageHashFile) if (_steps == ESteps.LoadCachePackageHashFile)
{ {
string filePath = PersistentHelper.GetCachePackageHashFilePath(_packageName, _packageVersion); string filePath = PersistentTools.GetCachePackageHashFilePath(_packageName, _packageVersion);
if (File.Exists(filePath) == false) if (File.Exists(filePath) == false)
{ {
_steps = ESteps.Done; _steps = ESteps.Done;

View File

@ -35,7 +35,7 @@ namespace YooAsset
if (_steps == ESteps.LoadCachePackageVersionFile) if (_steps == ESteps.LoadCachePackageVersionFile)
{ {
string filePath = PersistentHelper.GetCachePackageVersionFilePath(_packageName); string filePath = PersistentTools.GetCachePackageVersionFilePath(_packageName);
if (File.Exists(filePath) == false) if (File.Exists(filePath) == false)
{ {
_steps = ESteps.Done; _steps = ESteps.Done;

View File

@ -35,10 +35,10 @@ namespace YooAsset
{ {
if (_downloader1 == null) if (_downloader1 == null)
{ {
string savePath = PersistentHelper.GetCachePackageHashFilePath(_buildinPackageName, _buildinPackageVersion); string savePath = PersistentTools.GetCachePackageHashFilePath(_buildinPackageName, _buildinPackageVersion);
string fileName = YooAssetSettingsData.GetPackageHashFileName(_buildinPackageName, _buildinPackageVersion); string fileName = YooAssetSettingsData.GetPackageHashFileName(_buildinPackageName, _buildinPackageVersion);
string filePath = PathHelper.MakeStreamingLoadPath(fileName); string filePath = PersistentTools.MakeStreamingLoadPath(fileName);
string url = PathHelper.ConvertToWWWPath(filePath); string url = PersistentTools.ConvertToWWWPath(filePath);
_downloader1 = new UnityWebFileRequester(); _downloader1 = new UnityWebFileRequester();
_downloader1.SendRequest(url, savePath); _downloader1.SendRequest(url, savePath);
} }
@ -64,10 +64,10 @@ namespace YooAsset
{ {
if (_downloader2 == null) if (_downloader2 == null)
{ {
string savePath = PersistentHelper.GetCacheManifestFilePath(_buildinPackageName, _buildinPackageVersion); string savePath = PersistentTools.GetCacheManifestFilePath(_buildinPackageName, _buildinPackageVersion);
string fileName = YooAssetSettingsData.GetManifestBinaryFileName(_buildinPackageName, _buildinPackageVersion); string fileName = YooAssetSettingsData.GetManifestBinaryFileName(_buildinPackageName, _buildinPackageVersion);
string filePath = PathHelper.MakeStreamingLoadPath(fileName); string filePath = PersistentTools.MakeStreamingLoadPath(fileName);
string url = PathHelper.ConvertToWWWPath(filePath); string url = PersistentTools.ConvertToWWWPath(filePath);
_downloader2 = new UnityWebFileRequester(); _downloader2 = new UnityWebFileRequester();
_downloader2.SendRequest(url, savePath); _downloader2.SendRequest(url, savePath);
} }

View File

@ -69,6 +69,7 @@ namespace YooAsset
private readonly HostPlayModeImpl _impl; private readonly HostPlayModeImpl _impl;
private readonly string _packageName; private readonly string _packageName;
private readonly string _packageVersion; private readonly string _packageVersion;
private readonly bool _autoSaveVersion;
private readonly int _timeout; private readonly int _timeout;
private LoadCacheManifestOperation _tryLoadCacheManifestOp; private LoadCacheManifestOperation _tryLoadCacheManifestOp;
private LoadCacheManifestOperation _loadCacheManifestOp; private LoadCacheManifestOperation _loadCacheManifestOp;
@ -76,11 +77,12 @@ namespace YooAsset
private ESteps _steps = ESteps.None; private ESteps _steps = ESteps.None;
internal HostPlayModeUpdatePackageManifestOperation(HostPlayModeImpl impl, string packageName, string packageVersion, int timeout) internal HostPlayModeUpdatePackageManifestOperation(HostPlayModeImpl impl, string packageName, string packageVersion, bool autoSaveVersion, int timeout)
{ {
_impl = impl; _impl = impl;
_packageName = packageName; _packageName = packageName;
_packageVersion = packageVersion; _packageVersion = packageVersion;
_autoSaveVersion = autoSaveVersion;
_timeout = timeout; _timeout = timeout;
} }
internal override void Start() internal override void Start()
@ -120,6 +122,8 @@ namespace YooAsset
if (_tryLoadCacheManifestOp.Status == EOperationStatus.Succeed) if (_tryLoadCacheManifestOp.Status == EOperationStatus.Succeed)
{ {
_impl.ActiveManifest = _tryLoadCacheManifestOp.Manifest; _impl.ActiveManifest = _tryLoadCacheManifestOp.Manifest;
if (_autoSaveVersion)
SavePackageVersion();
_steps = ESteps.Done; _steps = ESteps.Done;
Status = EOperationStatus.Succeed; Status = EOperationStatus.Succeed;
} }
@ -166,6 +170,8 @@ namespace YooAsset
if (_loadCacheManifestOp.Status == EOperationStatus.Succeed) if (_loadCacheManifestOp.Status == EOperationStatus.Succeed)
{ {
_impl.ActiveManifest = _loadCacheManifestOp.Manifest; _impl.ActiveManifest = _loadCacheManifestOp.Manifest;
if (_autoSaveVersion)
SavePackageVersion();
_steps = ESteps.Done; _steps = ESteps.Done;
Status = EOperationStatus.Succeed; Status = EOperationStatus.Succeed;
} }

View File

@ -74,13 +74,14 @@ namespace YooAsset
string folderName = FileHash.Substring(0, 2); string folderName = FileHash.Substring(0, 2);
if (IsRawFile) if (IsRawFile)
{ {
string cacheRoot = PersistentHelper.GetCachedRawFileFolderPath(PackageName); string cacheRoot = PersistentTools.GetCachedRawFileFolderPath(PackageName);
_cachedDataFilePath = $"{cacheRoot}/{folderName}/{CacheGUID}/{YooAssetSettings.CacheBundleDataFileName}{_fileExtension}"; _cachedDataFilePath = PathUtility.Combine(cacheRoot, folderName, CacheGUID, YooAssetSettings.CacheBundleDataFileName);
_cachedDataFilePath += _fileExtension;
} }
else else
{ {
string cacheRoot = PersistentHelper.GetCachedBundleFileFolderPath(PackageName); string cacheRoot = PersistentTools.GetCachedBundleFileFolderPath(PackageName);
_cachedDataFilePath = $"{cacheRoot}/{folderName}/{CacheGUID}/{YooAssetSettings.CacheBundleDataFileName}"; _cachedDataFilePath = PathUtility.Combine(cacheRoot, folderName, CacheGUID, YooAssetSettings.CacheBundleDataFileName);
} }
return _cachedDataFilePath; return _cachedDataFilePath;
} }
@ -100,13 +101,13 @@ namespace YooAsset
string folderName = FileHash.Substring(0, 2); string folderName = FileHash.Substring(0, 2);
if (IsRawFile) if (IsRawFile)
{ {
string cacheRoot = PersistentHelper.GetCachedRawFileFolderPath(PackageName); string cacheRoot = PersistentTools.GetCachedRawFileFolderPath(PackageName);
_cachedInfoFilePath = $"{cacheRoot}/{folderName}/{CacheGUID}/{YooAssetSettings.CacheBundleInfoFileName}"; _cachedInfoFilePath = PathUtility.Combine(cacheRoot, folderName, CacheGUID, YooAssetSettings.CacheBundleInfoFileName);
} }
else else
{ {
string cacheRoot = PersistentHelper.GetCachedBundleFileFolderPath(PackageName); string cacheRoot = PersistentTools.GetCachedBundleFileFolderPath(PackageName);
_cachedInfoFilePath = $"{cacheRoot}/{folderName}/{CacheGUID}/{YooAssetSettings.CacheBundleInfoFileName}"; _cachedInfoFilePath = PathUtility.Combine(cacheRoot, folderName, CacheGUID, YooAssetSettings.CacheBundleInfoFileName);
} }
return _cachedInfoFilePath; return _cachedInfoFilePath;
} }
@ -139,7 +140,7 @@ namespace YooAsset
if (string.IsNullOrEmpty(_streamingFilePath) == false) if (string.IsNullOrEmpty(_streamingFilePath) == false)
return _streamingFilePath; return _streamingFilePath;
_streamingFilePath = PathHelper.MakeStreamingLoadPath(FileName); _streamingFilePath = PersistentTools.MakeStreamingLoadPath(FileName);
return _streamingFilePath; return _streamingFilePath;
} }
} }

View File

@ -114,7 +114,7 @@ namespace YooAsset
// 添加无后缀名路径的映射 // 添加无后缀名路径的映射
if (Path.HasExtension(location)) if (Path.HasExtension(location))
{ {
string locationWithoutExtension = StringUtility.RemoveExtension(location); string locationWithoutExtension = PathUtility.RemoveExtension(location);
if (AssetPathMapping.ContainsKey(locationWithoutExtension)) if (AssetPathMapping.ContainsKey(locationWithoutExtension))
YooLogger.Warning($"AssetPath have existed : {locationWithoutExtension}"); YooLogger.Warning($"AssetPath have existed : {locationWithoutExtension}");
else else

View File

@ -43,7 +43,7 @@ namespace YooAsset
OperationSystem.StartOperation(operation); OperationSystem.StartOperation(operation);
return operation; return operation;
} }
UpdatePackageManifestOperation IPlayModeServices.UpdatePackageManifestAsync(string packageVersion, int timeout) UpdatePackageManifestOperation IPlayModeServices.UpdatePackageManifestAsync(string packageVersion, bool autoSaveVersion, int timeout)
{ {
var operation = new EditorPlayModeUpdatePackageManifestOperation(); var operation = new EditorPlayModeUpdatePackageManifestOperation();
OperationSystem.StartOperation(operation); OperationSystem.StartOperation(operation);

View File

@ -93,7 +93,7 @@ namespace YooAsset
public void FlushManifestVersionFile() public void FlushManifestVersionFile()
{ {
if (_activeManifest != null) if (_activeManifest != null)
PersistentHelper.SaveCachePackageVersionFile(_packageName, _activeManifest.PackageVersion); PersistentTools.SaveCachePackageVersionFile(_packageName, _activeManifest.PackageVersion);
} }
private bool IsBuildinPackageBundle(PackageBundle packageBundle) private bool IsBuildinPackageBundle(PackageBundle packageBundle)
@ -111,9 +111,9 @@ namespace YooAsset
OperationSystem.StartOperation(operation); OperationSystem.StartOperation(operation);
return operation; return operation;
} }
UpdatePackageManifestOperation IPlayModeServices.UpdatePackageManifestAsync(string packageVersion, int timeout) UpdatePackageManifestOperation IPlayModeServices.UpdatePackageManifestAsync(string packageVersion, bool autoSaveVersion, int timeout)
{ {
var operation = new HostPlayModeUpdatePackageManifestOperation(this, _packageName, packageVersion, timeout); var operation = new HostPlayModeUpdatePackageManifestOperation(this, _packageName, packageVersion, autoSaveVersion, timeout);
OperationSystem.StartOperation(operation); OperationSystem.StartOperation(operation);
return operation; return operation;
} }

View File

@ -43,7 +43,7 @@ namespace YooAsset
OperationSystem.StartOperation(operation); OperationSystem.StartOperation(operation);
return operation; return operation;
} }
UpdatePackageManifestOperation IPlayModeServices.UpdatePackageManifestAsync(string packageVersion, int timeout) UpdatePackageManifestOperation IPlayModeServices.UpdatePackageManifestAsync(string packageVersion, bool autoSaveVersion, int timeout)
{ {
var operation = new OfflinePlayModeUpdatePackageManifestOperation(); var operation = new OfflinePlayModeUpdatePackageManifestOperation();
OperationSystem.StartOperation(operation); OperationSystem.StartOperation(operation);

View File

@ -220,13 +220,13 @@ namespace YooAsset
/// 向网络端请求并更新清单 /// 向网络端请求并更新清单
/// </summary> /// </summary>
/// <param name="packageVersion">更新的包裹版本</param> /// <param name="packageVersion">更新的包裹版本</param>
/// <param name="autoActiveManifest">自动激活清单</param> /// <param name="autoSaveVersion">更新成功后自动保存版本号,作为下次初始化的版本。</param>
/// <param name="timeout">超时时间默认值60秒</param> /// <param name="timeout">超时时间默认值60秒</param>
public UpdatePackageManifestOperation UpdatePackageManifestAsync(string packageVersion, int timeout = 60) public UpdatePackageManifestOperation UpdatePackageManifestAsync(string packageVersion, bool autoSaveVersion = true, int timeout = 60)
{ {
DebugCheckInitialize(); DebugCheckInitialize();
DebugCheckUpdateManifest(); DebugCheckUpdateManifest();
return _playModeServices.UpdatePackageManifestAsync(packageVersion, timeout); return _playModeServices.UpdatePackageManifestAsync(packageVersion, autoSaveVersion, timeout);
} }
/// <summary> /// <summary>
@ -251,6 +251,17 @@ namespace YooAsset
return operation; return operation;
} }
/// <summary>
/// 清理包裹本地所有的缓存文件
/// </summary>
public ClearAllCacheFilesOperation ClearAllCacheFilesAsync()
{
DebugCheckInitialize();
var operation = new ClearAllCacheFilesOperation(this);
OperationSystem.StartOperation(operation);
return operation;
}
/// <summary> /// <summary>
/// 获取本地包裹的版本信息 /// 获取本地包裹的版本信息
/// </summary> /// </summary>

View File

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

View File

@ -21,7 +21,7 @@ namespace YooAsset
/// <summary> /// <summary>
/// 向网络端请求并更新清单 /// 向网络端请求并更新清单
/// </summary> /// </summary>
UpdatePackageManifestOperation UpdatePackageManifestAsync(string packageVersion, int timeout); UpdatePackageManifestOperation UpdatePackageManifestAsync(string packageVersion, bool autoSaveVersion, int timeout);
/// <summary> /// <summary>
/// 预下载指定版本的包裹内容 /// 预下载指定版本的包裹内容

View File

@ -2,7 +2,7 @@
namespace YooAsset namespace YooAsset
{ {
[CreateAssetMenu(fileName = "YooAssetSettings", menuName = "YooAsset/Create Settings")] [CreateAssetMenu(fileName = "YooAssetSettings", menuName = "YooAsset/Create YooAsset Settings")]
internal class YooAssetSettings : ScriptableObject internal class YooAssetSettings : ScriptableObject
{ {
/// <summary> /// <summary>

View File

@ -7,13 +7,67 @@ using System.Security.Cryptography;
namespace YooAsset namespace YooAsset
{ {
/// <summary>
/// 路径工具类
/// </summary>
internal static class PathUtility
{
/// <summary>
/// 路径归一化
/// 注意替换为Linux路径格式
/// </summary>
public static string RegularPath(string path)
{
return path.Replace('\\', '/').Replace("\\", "/");
}
/// <summary>
/// 移除路径里的后缀名
/// </summary>
public static 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"
}
/// <summary>
/// 合并路径
/// </summary>
public static string Combine(string path1, string path2)
{
return StringUtility.Format("{0}/{1}", path1, path2);
}
/// <summary>
/// 合并路径
/// </summary>
public static string Combine(string path1, string path2, string path3)
{
return StringUtility.Format("{0}/{1}/{2}", path1, path2, path3);
}
/// <summary>
/// 合并路径
/// </summary>
public static string Combine(string path1, string path2, string path3, string path4)
{
return StringUtility.Format("{0}/{1}/{2}/{3}", path1, path2, path3, path4);
}
}
/// <summary> /// <summary>
/// 字符串工具类 /// 字符串工具类
/// </summary> /// </summary>
internal static class StringUtility internal static class StringUtility
{ {
[ThreadStatic] [ThreadStatic]
private static StringBuilder _cacheBuilder = new StringBuilder(1024); private static StringBuilder _cacheBuilder = new StringBuilder(2048);
public static string Format(string format, object arg0) public static string Format(string format, object arg0)
{ {
@ -54,30 +108,6 @@ namespace YooAsset
_cacheBuilder.AppendFormat(format, args); _cacheBuilder.AppendFormat(format, args);
return _cacheBuilder.ToString(); return _cacheBuilder.ToString();
} }
public static string RemoveFirstChar(string str)
{
if (string.IsNullOrEmpty(str))
return str;
return str.Substring(1);
}
public static string RemoveLastChar(string str)
{
if (string.IsNullOrEmpty(str))
return str;
return str.Substring(0, str.Length - 1);
}
public static 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"
}
} }
/// <summary> /// <summary>
@ -106,46 +136,26 @@ namespace YooAsset
} }
/// <summary> /// <summary>
/// 创建文件(如果已经存在则删除旧文件) /// 写入文本数据(会覆盖指定路径的文件)
/// </summary> /// </summary>
public static void CreateFile(string filePath, string content) public static void WriteAllText(string filePath, string content)
{ {
// 删除旧文件
if (File.Exists(filePath))
File.Delete(filePath);
// 创建文件夹路径 // 创建文件夹路径
CreateFileDirectory(filePath); CreateFileDirectory(filePath);
// 创建新文件
byte[] bytes = Encoding.UTF8.GetBytes(content); byte[] bytes = Encoding.UTF8.GetBytes(content);
using (FileStream fs = File.Create(filePath)) File.WriteAllBytes(filePath, bytes); //避免写入BOM标记
{
fs.Write(bytes, 0, bytes.Length);
fs.Flush();
fs.Close();
}
} }
/// <summary> /// <summary>
/// 创建文件(如果已经存在则删除旧文件) /// 写入字节数据(会覆盖指定路径的文件)
/// </summary> /// </summary>
public static void CreateFile(string filePath, byte[] data) public static void WriteAllBytes(string filePath, byte[] data)
{ {
// 删除旧文件
if (File.Exists(filePath))
File.Delete(filePath);
// 创建文件夹路径 // 创建文件夹路径
CreateFileDirectory(filePath); CreateFileDirectory(filePath);
// 创建新文件 File.WriteAllBytes(filePath, data);
using (FileStream fs = File.Create(filePath))
{
fs.Write(data, 0, data.Length);
fs.Flush();
fs.Close();
}
} }
/// <summary> /// <summary>

View File

@ -19,7 +19,10 @@ namespace YooAsset
public static void Initialize(ILogger logger = null) public static void Initialize(ILogger logger = null)
{ {
if (_isInitialize) if (_isInitialize)
throw new Exception($"{nameof(YooAssets)} is initialized !"); {
UnityEngine.Debug.LogWarning($"{nameof(YooAssets)} is initialized !");
return;
}
if (_isInitialize == false) if (_isInitialize == false)
{ {
@ -99,6 +102,7 @@ namespace YooAsset
if (HasPackage(packageName)) if (HasPackage(packageName))
throw new Exception($"Package {packageName} already existed !"); throw new Exception($"Package {packageName} already existed !");
YooLogger.Log($"Create resource package : {packageName}");
ResourcePackage package = new ResourcePackage(packageName); ResourcePackage package = new ResourcePackage(packageName);
_packages.Add(package); _packages.Add(package);
return package; return package;
@ -112,7 +116,7 @@ namespace YooAsset
{ {
var package = TryGetPackage(packageName); var package = TryGetPackage(packageName);
if (package == null) if (package == null)
YooLogger.Error($"Not found assets package : {packageName}"); YooLogger.Error($"Not found resource package : {packageName}");
return package; return package;
} }
@ -136,6 +140,24 @@ namespace YooAsset
return null; return null;
} }
/// <summary>
/// 销毁资源包
/// </summary>
/// <param name="packageName">资源包名称</param>
public static void DestroyPackage(string packageName)
{
ResourcePackage package = GetPackage(packageName);
if (package == null)
return;
YooLogger.Log($"Destroy resource package : {packageName}");
_packages.Remove(package);
package.DestroyPackage();
// 清空缓存
CacheSystem.ClearPackage(packageName);
}
/// <summary> /// <summary>
/// 检测资源包是否存在 /// 检测资源包是否存在
/// </summary> /// </summary>
@ -215,6 +237,27 @@ namespace YooAsset
{ {
CacheSystem.InitVerifyLevel = verifyLevel; CacheSystem.InitVerifyLevel = verifyLevel;
} }
/// <summary>
/// 设置缓存系统参数,沙盒目录的存储路径
/// </summary>
public static void SetCacheSystemSandboxPath(string sandboxPath)
{
if (string.IsNullOrEmpty(sandboxPath))
{
YooLogger.Error($"Sandbox path is null or empty !");
return;
}
// 注意:需要确保没有任何资源系统起效之前才可以设置沙盒目录!
if (_packages.Count > 0)
{
YooLogger.Error($"Please call this method {nameof(SetCacheSystemSandboxPath)} before the package is created !");
return;
}
PersistentTools.OverwriteSandboxPath(sandboxPath);
}
#endregion #endregion
#region 沙盒相关 #region 沙盒相关
@ -231,15 +274,16 @@ namespace YooAsset
/// </summary> /// </summary>
public static string GetSandboxRoot() public static string GetSandboxRoot()
{ {
return PathHelper.GetPersistentRootPath(); return PersistentTools.GetPersistentRootPath();
} }
/// <summary> /// <summary>
/// 清空沙盒目录 /// 清空沙盒目录需要重启APP
/// </summary> /// </summary>
public static void ClearSandbox() public static void ClearSandbox()
{ {
PersistentHelper.DeleteSandbox(); YooLogger.Warning("Clear sandbox folder files, Finally, restart the application !");
PersistentTools.DeleteSandbox();
} }
#endregion #endregion

View File

@ -47,20 +47,6 @@ public class FileStreamEncryption : IEncryptionServices
return result; return result;
} }
// 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 // Normal
{ {
EncryptResult result = new EncryptResult(); EncryptResult result = new EncryptResult();

View File

@ -8,7 +8,7 @@ public class BundleStream : FileStream
{ {
public const byte KEY = 64; public const byte KEY = 64;
public BundleStream(string path, FileMode mode, FileAccess access, FileShare share, int bufferSize, bool useAsync) : base(path, mode, access, share, bufferSize, useAsync) public BundleStream(string path, FileMode mode, FileAccess access, FileShare share) : base(path, mode, access, share)
{ {
} }
public BundleStream(string path, FileMode mode) : base(path, mode) public BundleStream(string path, FileMode mode) : base(path, mode)

View File

@ -74,7 +74,7 @@ internal class FsmInitialize : IStateNode
} }
yield return initializationOperation; yield return initializationOperation;
if (package.InitializeStatus == EOperationStatus.Succeed) if (initializationOperation.Status == EOperationStatus.Succeed)
{ {
_machine.ChangeState<FsmUpdateVersion>(); _machine.ChangeState<FsmUpdateVersion>();
} }
@ -92,41 +92,29 @@ internal class FsmInitialize : IStateNode
{ {
//string hostServerIP = "http://10.0.2.2"; //安卓模拟器地址 //string hostServerIP = "http://10.0.2.2"; //安卓模拟器地址
string hostServerIP = "http://127.0.0.1"; string hostServerIP = "http://127.0.0.1";
string gameVersion = "v1.0"; string appVersion = "v1.0";
#if UNITY_EDITOR #if UNITY_EDITOR
if (UnityEditor.EditorUserBuildSettings.activeBuildTarget == UnityEditor.BuildTarget.Android) if (UnityEditor.EditorUserBuildSettings.activeBuildTarget == UnityEditor.BuildTarget.Android)
return $"{hostServerIP}/CDN/Android/{gameVersion}"; return $"{hostServerIP}/CDN/Android/{appVersion}";
else if (UnityEditor.EditorUserBuildSettings.activeBuildTarget == UnityEditor.BuildTarget.iOS) else if (UnityEditor.EditorUserBuildSettings.activeBuildTarget == UnityEditor.BuildTarget.iOS)
return $"{hostServerIP}/CDN/IPhone/{gameVersion}"; return $"{hostServerIP}/CDN/IPhone/{appVersion}";
else if (UnityEditor.EditorUserBuildSettings.activeBuildTarget == UnityEditor.BuildTarget.WebGL) else if (UnityEditor.EditorUserBuildSettings.activeBuildTarget == UnityEditor.BuildTarget.WebGL)
return $"{hostServerIP}/CDN/WebGL/{gameVersion}"; return $"{hostServerIP}/CDN/WebGL/{appVersion}";
else else
return $"{hostServerIP}/CDN/PC/{gameVersion}"; return $"{hostServerIP}/CDN/PC/{appVersion}";
#else #else
if (Application.platform == RuntimePlatform.Android) if (Application.platform == RuntimePlatform.Android)
return $"{hostServerIP}/CDN/Android/{gameVersion}"; return $"{hostServerIP}/CDN/Android/{appVersion}";
else if (Application.platform == RuntimePlatform.IPhonePlayer) else if (Application.platform == RuntimePlatform.IPhonePlayer)
return $"{hostServerIP}/CDN/IPhone/{gameVersion}"; return $"{hostServerIP}/CDN/IPhone/{appVersion}";
else if (Application.platform == RuntimePlatform.WebGLPlayer) else if (Application.platform == RuntimePlatform.WebGLPlayer)
return $"{hostServerIP}/CDN/WebGL/{gameVersion}"; return $"{hostServerIP}/CDN/WebGL/{appVersion}";
else else
return $"{hostServerIP}/CDN/PC/{gameVersion}"; return $"{hostServerIP}/CDN/PC/{appVersion}";
#endif #endif
} }
/// <summary>
/// 内置文件查询服务类
/// </summary>
private class GameQueryServices : IQueryServices
{
public bool QueryStreamingAssets(string fileName)
{
string buildinFolderName = YooAssets.GetStreamingAssetBuildinFolderName();
return StreamingAssetsHelper.FileExists($"{buildinFolderName}/{fileName}");
}
}
/// <summary> /// <summary>
/// 资源文件解密服务类 /// 资源文件解密服务类
/// </summary> /// </summary>
@ -144,7 +132,7 @@ internal class FsmInitialize : IStateNode
public Stream LoadFromStream(DecryptFileInfo fileInfo) public Stream LoadFromStream(DecryptFileInfo fileInfo)
{ {
BundleStream bundleStream = new BundleStream(fileInfo.FilePath, FileMode.Open); BundleStream bundleStream = new BundleStream(fileInfo.FilePath, FileMode.Open, FileAccess.Read, FileShare.Read);
return bundleStream; return bundleStream;
} }

View File

@ -32,13 +32,13 @@ public class FsmUpdateManifest : IStateNode
{ {
yield return new WaitForSecondsRealtime(0.5f); yield return new WaitForSecondsRealtime(0.5f);
bool savePackageVersion = true;
var package = YooAssets.GetPackage("DefaultPackage"); var package = YooAssets.GetPackage("DefaultPackage");
var operation = package.UpdatePackageManifestAsync(PatchManager.Instance.PackageVersion); var operation = package.UpdatePackageManifestAsync(PatchManager.Instance.PackageVersion, savePackageVersion);
yield return operation; yield return operation;
if(operation.Status == EOperationStatus.Succeed) if(operation.Status == EOperationStatus.Succeed)
{ {
operation.SavePackageVersion();
_machine.ChangeState<FsmCreateDownloader>(); _machine.ChangeState<FsmCreateDownloader>();
} }
else else

View File

@ -0,0 +1,10 @@
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 内置资源清单
/// </summary>
public class BuildinFileManifest : ScriptableObject
{
public List<string> BuildinFiles = new List<string>();
}

View File

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

View File

@ -1,57 +0,0 @@
//-------------------------------------
// 作者Stark
//-------------------------------------
using System.Collections.Generic;
using UnityEngine;
public sealed class StreamingAssetsHelper
{
private static readonly Dictionary<string, bool> _cacheData = new Dictionary<string, bool>(1000);
#if UNITY_ANDROID && !UNITY_EDITOR
private static AndroidJavaClass _unityPlayerClass;
public static AndroidJavaClass UnityPlayerClass
{
get
{
if (_unityPlayerClass == null)
_unityPlayerClass = new UnityEngine.AndroidJavaClass("com.unity3d.player.UnityPlayer");
return _unityPlayerClass;
}
}
private static AndroidJavaObject _currentActivity;
public static AndroidJavaObject CurrentActivity
{
get
{
if (_currentActivity == null)
_currentActivity = UnityPlayerClass.GetStatic<AndroidJavaObject>("currentActivity");
return _currentActivity;
}
}
/// <summary>
/// 利用安卓原生接口查询内置文件是否存在
/// </summary>
public static bool FileExists(string filePath)
{
if (_cacheData.TryGetValue(filePath, out bool result) == false)
{
result = CurrentActivity.Call<bool>("CheckAssetExist", filePath);
_cacheData.Add(filePath, result);
}
return result;
}
#else
public static bool FileExists(string filePath)
{
if (_cacheData.TryGetValue(filePath, out bool result) == false)
{
result = System.IO.File.Exists(System.IO.Path.Combine(Application.streamingAssetsPath, filePath));
_cacheData.Add(filePath, result);
}
return result;
}
#endif
}

View File

@ -0,0 +1,97 @@
using System.IO;
using System.Collections.Generic;
using UnityEngine;
using YooAsset;
/// <summary>
/// 内置文件查询服务类
/// </summary>
public class GameQueryServices : IQueryServices
{
public bool QueryStreamingAssets(string fileName)
{
// 注意fileName包含文件格式
return StreamingAssetsHelper.FileExists(fileName);
}
}
/// <summary>
/// StreamingAssets目录下资源查询帮助类
/// </summary>
public sealed class StreamingAssetsHelper
{
private static bool _isInit = false;
private static readonly HashSet<string> _cacheData = new HashSet<string>();
#if UNITY_EDITOR
public static void Init() { _isInit = true; }
public static bool FileExists(string fileName)
{
return File.Exists(System.IO.Path.Combine(Application.streamingAssetsPath, "BuildinFiles", fileName));
}
#else
/// <summary>
/// 初始化
/// </summary>
public static void Init()
{
if (_isInit == false)
{
_isInit = true;
var manifest = Resources.Load<BuildinFileManifest>("BuildinFileManifest");
foreach (string fileName in manifest.BuildinFiles)
{
_cacheData.Add(fileName);
}
}
}
/// <summary>
/// 内置文件查询方法
/// </summary>
public static bool FileExists(string fileName)
{
if (_isInit == false)
Init();
return _cacheData.Contains(fileName);
}
#endif
}
#if UNITY_EDITOR
internal class PreprocessBuild : UnityEditor.Build.IPreprocessBuildWithReport
{
public int callbackOrder { get { return 0; } }
/// <summary>
/// 在构建应用程序前处理
/// </summary>
public void OnPreprocessBuild(UnityEditor.Build.Reporting.BuildReport report)
{
var manifest = ScriptableObject.CreateInstance<BuildinFileManifest>();
string folderPath = $"{Application.dataPath}/StreamingAssets/BuildinFiles";
DirectoryInfo root = new DirectoryInfo(folderPath);
FileInfo[] files = root.GetFiles();
foreach (var fileInfo in files)
{
if (fileInfo.Extension == ".meta")
continue;
if (fileInfo.Name.StartsWith("PackageManifest_"))
continue;
manifest.BuildinFiles.Add(fileInfo.Name);
}
string saveFilePath = "Assets/Resources/BuildinFileManifest.asset";
if (File.Exists(saveFilePath))
File.Delete(saveFilePath);
if (Directory.Exists("Assets/Resources") == false)
Directory.CreateDirectory("Assets/Resources");
UnityEditor.AssetDatabase.CreateAsset(manifest, saveFilePath);
UnityEditor.AssetDatabase.SaveAssets();
UnityEditor.AssetDatabase.Refresh();
Debug.Log($"内置资源清单保存成功 : {saveFilePath}");
}
}
#endif

View File

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

View File

@ -1,8 +1,80 @@
//------------------------------------- //-------------------------------------
// 作者Stark // 作者Stark
//------------------------------------- //-------------------------------------
using System.Collections.Generic;
using UnityEngine;
using YooAsset;
#if UNITY_ANDROID /*
/// <summary>
/// 内置文件查询服务类
/// </summary>
public class GameQueryServices : IQueryServices
{
public bool QueryStreamingAssets(string fileName)
{
string buildinFolderName = YooAssets.GetStreamingAssetBuildinFolderName();
return StreamingAssetsHelper.FileExists($"{buildinFolderName}/{fileName}");
}
}
/// <summary>
/// StreamingAssets目录下资源查询帮助类
/// </summary>
public sealed class StreamingAssetsHelper
{
private static readonly Dictionary<string, bool> _cacheData = new Dictionary<string, bool>(1000);
#if UNITY_ANDROID && !UNITY_EDITOR
private static AndroidJavaClass _unityPlayerClass;
public static AndroidJavaClass UnityPlayerClass
{
get
{
if (_unityPlayerClass == null)
_unityPlayerClass = new UnityEngine.AndroidJavaClass("com.unity3d.player.UnityPlayer");
return _unityPlayerClass;
}
}
private static AndroidJavaObject _currentActivity;
public static AndroidJavaObject CurrentActivity
{
get
{
if (_currentActivity == null)
_currentActivity = UnityPlayerClass.GetStatic<AndroidJavaObject>("currentActivity");
return _currentActivity;
}
}
/// <summary>
/// 利用安卓原生接口查询内置文件是否存在
/// </summary>
public static bool FileExists(string filePath)
{
if (_cacheData.TryGetValue(filePath, out bool result) == false)
{
result = CurrentActivity.Call<bool>("CheckAssetExist", filePath);
_cacheData.Add(filePath, result);
}
return result;
}
#else
public static bool FileExists(string filePath)
{
if (_cacheData.TryGetValue(filePath, out bool result) == false)
{
result = System.IO.File.Exists(System.IO.Path.Combine(Application.streamingAssetsPath, filePath));
_cacheData.Add(filePath, result);
}
return result;
}
#endif
}
#if UNITY_ANDROID && UNITY_EDITOR
/// <summary> /// <summary>
/// 为Github对开发者的友好采用自动补充UnityPlayerActivity.java文件的通用姿势满足各个开发者 /// 为Github对开发者的友好采用自动补充UnityPlayerActivity.java文件的通用姿势满足各个开发者
/// </summary> /// </summary>
@ -30,7 +102,6 @@ internal class AndroidPost : UnityEditor.Android.IPostGenerateGradleAndroidProje
" } \n" + " } \n" +
" catch(java.io.IOException e) \n" + " catch(java.io.IOException e) \n" +
" { \n" + " { \n" +
" e.printStackTrace(); \n" +
" } \n" + " } \n" +
" return false; \n" + " return false; \n" +
" } \n" + " } \n" +
@ -53,6 +124,8 @@ internal class AndroidPost : UnityEditor.Android.IPostGenerateGradleAndroidProje
} }
} }
#endif #endif
*/
/* /*
//auto-gen-function //auto-gen-function
@ -70,7 +143,7 @@ public boolean CheckAssetExist(String filePath)
} }
catch(java.io.IOException e) catch(java.io.IOException e)
{ {
e.printStackTrace(); //e.printStackTrace();
} }
return false; return false;
} }

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 4b1fa97e8bb8c5c46ad030b9554e1b5c guid: 22c4a6746deb208479f4b7a040eed7f3
folderAsset: yes folderAsset: yes
DefaultImporter: DefaultImporter:
externalObjects: {} externalObjects: {}

View File

@ -0,0 +1,5 @@
# UniFramework.Animation
一个轻量级的高效率的动画系统。
支持新的动画文件格式不再依赖Animator文件来驱动动画使用方式非常类似于老的Animation系统。

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 6a7da62cb3785ef45b2dda8fa0b3c8e5
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: b19a7385dee2d0141901167dbfda9300 guid: 8664294e17a47c14c8d12545da2349a1
folderAsset: yes folderAsset: yes
DefaultImporter: DefaultImporter:
externalObjects: {} externalObjects: {}

View File

@ -0,0 +1,106 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Animations;
namespace UniFramework.Animation
{
internal sealed class AnimClip : AnimNode
{
public readonly string Name;
private readonly AnimationClip _clip;
public AnimationClipPlayable _clipPlayable;
/// <summary>
/// 动画层级
/// </summary>
public int Layer = 0;
/// <summary>
/// 动画长度
/// </summary>
public float ClipLength
{
get
{
if (_clip == null)
return 0f;
if (Speed == 0f)
return Mathf.Infinity;
return _clip.length / Speed;
}
}
/// <summary>
/// 归一化时间轴
/// </summary>
public float NormalizedTime
{
set
{
if (_clip == null)
return;
Time = _clip.length * value;
}
get
{
if (_clip == null)
return 1f;
return Time / _clip.length;
}
}
/// <summary>
/// 动画模式
/// </summary>
public WrapMode WrapMode
{
set
{
if (_clip != null)
_clip.wrapMode = value;
}
get
{
if (_clip == null)
return WrapMode.Default;
return _clip.wrapMode;
}
}
/// <summary>
/// 动画状态
/// </summary>
public AnimState State { private set; get; }
public AnimClip(PlayableGraph graph, AnimationClip clip, string name, int layer) : base(graph)
{
_clip = clip;
Name = name;
Layer = layer;
_clipPlayable = AnimationClipPlayable.Create(graph, clip);
_clipPlayable.SetApplyFootIK(false);
_clipPlayable.SetApplyPlayableIK(false);
SetSourcePlayable(_clipPlayable);
if (clip.wrapMode == WrapMode.Once)
{
_clipPlayable.SetDuration(clip.length);
}
State = new AnimState(this);
}
public override void PlayNode()
{
if (_clip.wrapMode == WrapMode.Once || _clip.wrapMode == WrapMode.ClampForever)
{
Time = 0;
}
base.PlayNode();
}
}
}

View File

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

View File

@ -0,0 +1,196 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Animations;
namespace UniFramework.Animation
{
internal sealed class AnimMixer : AnimNode
{
private const float HIDE_DURATION = 0.25f;
private readonly List<AnimClip> _animClips = new List<AnimClip>(10);
private AnimationMixerPlayable _mixer;
private bool _isQuiting = false;
/// <summary>
/// 动画层级
/// </summary>
public int Layer { private set; get; }
public AnimMixer(PlayableGraph graph, int layer) : base(graph)
{
Layer = layer;
_mixer = AnimationMixerPlayable.Create(graph);
SetSourcePlayable(_mixer);
}
public override void Update(float deltaTime)
{
base.Update(deltaTime);
for (int i = 0; i < _animClips.Count; i++)
{
var animClip = _animClips[i];
if (animClip != null)
animClip.Update(deltaTime);
}
bool isAllDone = true;
for (int i = 0; i < _animClips.Count; i++)
{
var animClip = _animClips[i];
if (animClip != null)
{
if (animClip.IsDone == false)
isAllDone = false;
}
}
// 当子节点都已经完成的时候断开连接
if (isAllDone && _isQuiting == false)
{
_isQuiting = true;
StartWeightFade(0, HIDE_DURATION);
}
if (_isQuiting)
{
if (Mathf.Approximately(Weight, 0f))
DisconnectMixer();
}
}
/// <summary>
/// 播放指定动画
/// </summary>
public void Play(AnimClip newAnimClip, float fadeDuration)
{
// 重新激活混合器
_isQuiting = false;
StartWeightFade(1f, 0);
if (IsContains(newAnimClip) == false)
{
// 优先插入到一个空位
int index = _animClips.FindIndex(s => s == null);
if (index == -1)
{
// Increase input count
int inputCount = _mixer.GetInputCount();
_mixer.SetInputCount(inputCount + 1);
newAnimClip.Connect(_mixer, inputCount);
_animClips.Add(newAnimClip);
}
else
{
newAnimClip.Connect(_mixer, index);
_animClips[index] = newAnimClip;
}
}
for (int i = 0; i < _animClips.Count; i++)
{
var animClip = _animClips[i];
if (animClip == null)
continue;
if (animClip == newAnimClip)
{
animClip.StartWeightFade(1f, fadeDuration);
animClip.PlayNode();
}
else
{
animClip.StartWeightFade(0f, fadeDuration);
animClip.PauseNode();
}
}
}
/// <summary>
/// 停止指定动画,恢复为初始状态
/// </summary>
public void Stop(string name)
{
AnimClip animClip = FindClip(name);
if (animClip == null)
return;
animClip.PauseNode();
animClip.ResetNode();
}
/// <summary>
/// 暂停所有动画
/// </summary>
public void PauseAll()
{
for (int i = 0; i < _animClips.Count; i++)
{
var animClip = _animClips[i];
if (animClip == null)
continue;
animClip.PauseNode();
}
}
/// <summary>
/// 是否包含该动画
/// </summary>
public bool IsContains(AnimClip clip)
{
foreach (var animClip in _animClips)
{
if (animClip == clip)
return true;
}
return false;
}
/// <summary>
/// 移除一个动画
/// </summary>
public void RemoveClip(string name)
{
var animClip = FindClip(name);
if (animClip == null)
return;
_animClips[animClip.InputPort] = null;
animClip.Destroy();
}
/// <summary>
/// 获取指定的动画
/// </summary>
/// <returns>如果没有返回NULL</returns>
private AnimClip FindClip(string name)
{
foreach (var animClip in _animClips)
{
if (animClip != null && animClip.Name == name)
return animClip;
}
UniLogger.Warning($"${nameof(AnimClip)} doesn't exist : {name}");
return null;
}
private void DisconnectMixer()
{
for (int i = 0; i < _animClips.Count; i++)
{
var animClip = _animClips[i];
if (animClip == null)
continue;
animClip.Disconnect();
_animClips[i] = null;
}
Disconnect();
}
}
}

View File

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

View File

@ -0,0 +1,221 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Animations;
namespace UniFramework.Animation
{
internal abstract class AnimNode
{
private readonly PlayableGraph _graph;
private Playable _source;
private Playable _parent;
private float _fadeSpeed = 0f;
private float _fadeWeight = 0f;
private bool _isFading = false;
/// <summary>
/// 是否已经连接
/// </summary>
public bool IsConnect { get; private set; } = false;
/// <summary>
/// 输入端口
/// </summary>
public int InputPort { private set; get; }
/// <summary>
/// 是否已经完成
/// If the duration of the playable is set, when the time of the playable reaches its duration during playback this flag will be set to true.
/// </summary>
public bool IsDone
{
get
{
return _source.IsDone();
}
}
/// <summary>
/// 是否有效
/// if the Playable is properly constructed by the PlayableGraph and has not been destroyed, false otherwise.
/// </summary>
public bool IsValid
{
get
{
return _source.IsValid();
}
}
/// <summary>
/// 是否正在播放中
/// </summary>
public bool IsPlaying
{
get
{
return _source.GetPlayState() == PlayState.Playing;
}
}
/// <summary>
/// 时间轴
/// </summary>
public float Time
{
set
{
_source.SetTime(value);
}
get
{
return (float)_source.GetTime();
}
}
/// <summary>
/// 播放速度
/// </summary>
public float Speed
{
set
{
_source.SetSpeed(value);
}
get
{
return (float)_source.GetSpeed();
}
}
/// <summary>
/// 权重值
/// </summary>
public float Weight
{
set
{
_parent.SetInputWeight(InputPort, value);
}
get
{
return _parent.GetInputWeight(InputPort);
}
}
public AnimNode(PlayableGraph graph)
{
_graph = graph;
}
public virtual void Update(float deltaTime)
{
if (_isFading)
{
Weight = Mathf.MoveTowards(Weight, _fadeWeight, _fadeSpeed * deltaTime);
if (Mathf.Approximately(Weight, _fadeWeight))
{
_isFading = false;
}
}
}
public virtual void Destroy()
{
if (IsValid)
{
_graph.DestroySubgraph(_source);
}
}
public virtual void PlayNode()
{
// NOTE : When playing, the local time of this Playable will be updated during the evaluation of the PlayableGraph.
_source.Play();
// NOTE : Changes a flag indicating that a playable has completed its operation.
// Playable that reach the end of their duration are automatically marked as done.
_source.SetDone(false);
}
public virtual void PauseNode()
{
// NOTE : When paused, the local time of this Playable will not be updated during the evaluation of the PlayableGraph.
_source.Pause();
// NOTE : Changes a flag indicating that a playable has completed its operation.
// Playable that reach the end of their duration are automatically marked as done.
_source.SetDone(true);
}
public virtual void ResetNode()
{
_fadeSpeed = 0;
_fadeWeight = 0;
_isFading = false;
Time = 0;
Speed = 1;
Weight = 0;
}
/// <summary>
/// 连接到父节点
/// </summary>
/// <param name="parent">父节点对象</param>
/// <param name="inputPort">父节点上的输入端口</param>
public void Connect(Playable parent, int parentInputPort)
{
if (IsConnect)
throw new System.Exception("AnimNode is connected.");
_parent = parent;
InputPort = parentInputPort;
// 重置节点
ResetNode();
// 连接
_graph.Connect(_source, 0, parent, parentInputPort);
IsConnect = true;
}
/// <summary>
/// 同父节点断开连接
/// </summary>
public void Disconnect()
{
if (IsConnect == false)
throw new System.Exception("AnimNode is disconnected.");
// 断开
_graph.Disconnect(_parent, InputPort);
IsConnect = false;
}
/// <summary>
/// 开始权重值过渡
/// </summary>
/// <param name="destWeight">目标权重值</param>
/// <param name="fadeDuration">过渡时间</param>
public void StartWeightFade(float destWeight, float fadeDuration)
{
if (fadeDuration <= 0)
{
Weight = destWeight;
_isFading = false;
return;
}
//注意:保持统一的渐变速度
_fadeSpeed = 1f / fadeDuration;
_fadeWeight = destWeight;
_isFading = true;
}
protected void SetSourcePlayable(Playable playable)
{
_source = playable;
}
}
}

View File

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

View File

@ -0,0 +1,238 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Animations;
namespace UniFramework.Animation
{
internal class AnimPlayable
{
private readonly List<AnimClip> _animClips = new List<AnimClip>(10);
private readonly List<AnimMixer> _animMixers = new List<AnimMixer>(10);
private PlayableGraph _graph;
private AnimationPlayableOutput _output;
private AnimationLayerMixerPlayable _mixerRoot;
public void Create(Animator animator)
{
string name = animator.gameObject.name;
_graph = PlayableGraph.Create(name);
_graph.SetTimeUpdateMode(DirectorUpdateMode.Manual);
_mixerRoot = AnimationLayerMixerPlayable.Create(_graph);
_output = AnimationPlayableOutput.Create(_graph, name, animator);
_output.SetSourcePlayable(_mixerRoot);
}
public void Update(float deltaTime)
{
_graph.Evaluate(deltaTime);
// 更新所有层级
for (int i = 0; i < _animMixers.Count; i++)
{
var mixer = _animMixers[i];
if(mixer.IsConnect)
mixer.Update(deltaTime);
}
}
public void Destroy()
{
_graph.Destroy();
}
/// <summary>
/// Play the graph
/// </summary>
public void PlayGraph()
{
_graph.Play();
}
/// <summary>
/// Stop the graph
/// </summary>
public void StopGraph()
{
_graph.Stop();
}
/// <summary>
/// 获取动画的状态
/// </summary>
/// <param name="name">动画名称</param>
/// <returns>如果动画不存在返回空</returns>
public AnimState GetAnimState(string name)
{
for (int i = 0; i < _animClips.Count; i++)
{
if (_animClips[i].Name == name)
return _animClips[i].State;
}
return null;
}
/// <summary>
/// 检测动画是否正在播放
/// </summary>
/// <param name="name">动画名称</param>
public bool IsPlaying(string name)
{
AnimClip animClip = GetAnimClip(name);
if (animClip == null)
return false;
return animClip.IsConnect && animClip.IsPlaying;
}
/// <summary>
/// 播放一个动画
/// </summary>
/// <param name="name">动画名称</param>
/// <param name="fadeLength">融合时间</param>
public void Play(string name, float fadeLength)
{
var animClip = GetAnimClip(name);
if (animClip == null)
{
UniLogger.Warning($"Not found animation {name}");
return;
}
int layer = animClip.Layer;
var animMixer = GetAnimMixer(layer);
if (animMixer == null)
animMixer = CreateAnimMixer(layer);
if(animMixer.IsConnect == false)
animMixer.Connect(_mixerRoot, animMixer.Layer);
animMixer.Play(animClip, fadeLength);
}
/// <summary>
/// 停止一个动画
/// </summary>
/// <param name="name">动画名称</param>
public void Stop(string name)
{
var animClip = GetAnimClip(name);
if (animClip == null)
{
UniLogger.Warning($"Not found animation {name}");
return;
}
if (animClip.IsConnect == false)
return;
var animMixer = GetAnimMixer(animClip.Layer);
if (animMixer == null)
throw new System.Exception("Should never get here.");
animMixer.Stop(animClip.Name);
}
/// <summary>
/// 添加一个动画片段
/// </summary>
/// <param name="name">动画名称</param>
/// <param name="clip">动画片段</param>
/// <param name="layer">动画层级</param>
public bool AddAnimation(string name, AnimationClip clip, int layer = 0)
{
if (string.IsNullOrEmpty(name))
throw new System.ArgumentException("Name is null or empty.");
if (clip == null)
throw new System.ArgumentNullException();
if (layer < 0)
throw new System.Exception("Layer must be greater than zero.");
if (IsContains(name))
{
UniLogger.Warning($"Animation already exists : {name}");
return false;
}
AnimClip animClip = new AnimClip(_graph, clip, name, layer);
_animClips.Add(animClip);
return true;
}
/// <summary>
/// 移除一个动画片段
/// </summary>
/// <param name="name">动画名称</param>
public bool RemoveAnimation(string name)
{
if (IsContains(name) == false)
{
UniLogger.Warning($"Not found Animation : {name}");
return false;
}
AnimClip animClip = GetAnimClip(name);
AnimMixer animMixer = GetAnimMixer(animClip.Layer);
if(animMixer != null)
animMixer.RemoveClip(animClip.Name);
animClip.Destroy();
_animClips.Remove(animClip);
return true;
}
/// <summary>
/// 是否包含一个动画状态
/// </summary>
/// <param name="name">动画名称</param>
public bool IsContains(string name)
{
for (int i = 0; i < _animClips.Count; i++)
{
if (_animClips[i].Name == name)
return true;
}
return false;
}
private AnimClip GetAnimClip(string name)
{
for (int i = 0; i < _animClips.Count; i++)
{
if (_animClips[i].Name == name)
return _animClips[i];
}
return null;
}
private AnimMixer GetAnimMixer(int layer)
{
for (int i = 0; i < _animMixers.Count; i++)
{
if (_animMixers[i].Layer == layer)
return _animMixers[i];
}
return null;
}
private AnimMixer CreateAnimMixer(int layer)
{
// Increase input count
int inputCount = _mixerRoot.GetInputCount();
if(layer == 0 && inputCount == 0)
{
_mixerRoot.SetInputCount(1);
}
else
{
if (layer > inputCount - 1)
{
_mixerRoot.SetInputCount(layer + 1);
}
}
var animMixer = new AnimMixer(_graph, layer);
_animMixers.Add(animMixer);
return animMixer;
}
}
}

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