Compare commits

...

6 Commits

Author SHA1 Message Date
何冠峰 f861279c49 Update CHANGELOG.md 2025-02-10 20:04:35 +08:00
何冠峰 ee89f81d46 Update package.json 2025-02-10 20:04:31 +08:00
何冠峰 6d216561f8 fix #468 2025-02-10 20:00:48 +08:00
何冠峰 2d6488abf4 update AssetArtScanner
配置和报告容错性检测
2025-02-10 16:21:43 +08:00
何冠峰 7dfbac4a24 update AssetBundleCollector 2025-02-10 16:19:07 +08:00
何冠峰 7cfe4cb2c9 fix #465 2025-02-10 16:17:38 +08:00
15 changed files with 263 additions and 97 deletions

View File

@ -2,6 +2,17 @@
All notable changes to this package will be documented in this file. All notable changes to this package will be documented in this file.
## [2.2.11] - 2025-02-10
### Improvements
- AssetArtScanner配置和生成报告的容错性检测。
### Fixed
- (#465) 修复了特殊情况下,没有配置资源包文件后缀名构建失败的问题。
- (#468) 修复了安卓平台二次启动加载原生文件或加密文件失败的问题。
## [2.2.10] - 2025-02-08 ## [2.2.10] - 2025-02-08
### Improvements ### Improvements

View File

@ -3,9 +3,24 @@ namespace YooAsset.Editor
{ {
public enum EHeaderType public enum EHeaderType
{ {
/// <summary>
/// 资源路径
/// </summary>
AssetPath, AssetPath,
/// <summary>
/// 字符串
/// </summary>
StringValue, StringValue,
/// <summary>
/// 整数数值
/// </summary>
LongValue, LongValue,
/// <summary>
/// 浮点数数值
/// </summary>
DoubleValue, DoubleValue,
} }
} }

View File

@ -31,12 +31,28 @@ namespace YooAsset.Editor
/// <summary> /// <summary>
/// 添加扫描信息 /// 添加扫描信息
/// </summary> /// </summary>
public void AddScanInfo(string headerTitle, string scanInfo) public void AddScanInfo(string headerTitle, string value)
{ {
var reportScanInfo = new ReportScanInfo(headerTitle, scanInfo); var reportScanInfo = new ReportScanInfo(headerTitle, value);
ScanInfos.Add(reportScanInfo); ScanInfos.Add(reportScanInfo);
} }
/// <summary>
/// 添加扫描信息
/// </summary>
public void AddScanInfo(string headerTitle, long value)
{
AddScanInfo(headerTitle, value.ToString());
}
/// <summary>
/// 添加扫描信息
/// </summary>
public void AddScanInfo(string headerTitle, double value)
{
AddScanInfo(headerTitle, value.ToString());
}
/// <summary> /// <summary>
/// 获取扫描信息 /// 获取扫描信息
/// </summary> /// </summary>

View File

@ -1,4 +1,5 @@
using System; using System;
using UnityEditor;
namespace YooAsset.Editor namespace YooAsset.Editor
{ {
@ -93,5 +94,35 @@ namespace YooAsset.Editor
HeaderType = value; HeaderType = value;
return this; return this;
} }
/// <summary>
/// 检测数值有效性
/// </summary>
public void CheckValueValid(string value)
{
if (HeaderType == EHeaderType.AssetPath)
{
string guid = AssetDatabase.AssetPathToGUID(value);
if (string.IsNullOrEmpty(guid))
throw new Exception($"{HeaderTitle} value is invalid asset path : {value}");
}
else if (HeaderType == EHeaderType.DoubleValue)
{
if (double.TryParse(value, out double doubleValue) == false)
throw new Exception($"{HeaderTitle} value is invalid double value : {value}");
}
else if (HeaderType == EHeaderType.LongValue)
{
if (long.TryParse(value, out long longValue) == false)
throw new Exception($"{HeaderTitle} value is invalid long value : {value}");
}
else if (HeaderType == EHeaderType.StringValue)
{
}
else
{
throw new System.NotImplementedException(HeaderType.ToString());
}
}
} }
} }

View File

@ -29,9 +29,9 @@ namespace YooAsset.Editor
/// <summary> /// <summary>
/// 报告标题 /// 报告名称
/// </summary> /// </summary>
public string ReportTitle; public string ReportName;
/// <summary> /// <summary>
/// 报告介绍 /// 报告介绍
@ -41,7 +41,7 @@ namespace YooAsset.Editor
/// <summary> /// <summary>
/// 报告的标题列表 /// 报告的标题列表
/// </summary> /// </summary>
public List<ReportHeader> HeaderTitles = new List<ReportHeader>(); public List<ReportHeader> ReportHeaders = new List<ReportHeader>();
/// <summary> /// <summary>
/// 扫描的元素列表 /// 扫描的元素列表
@ -49,23 +49,70 @@ namespace YooAsset.Editor
public List<ReportElement> ReportElements = new List<ReportElement>(); public List<ReportElement> ReportElements = new List<ReportElement>();
public ScanReport(string reportTitle, string reportDesc) public ScanReport(string reportName, string reportDesc)
{ {
ReportTitle = reportTitle; ReportName = reportName;
ReportDesc = reportDesc; ReportDesc = reportDesc;
} }
/// <summary>
/// 添加标题
/// </summary>
public ReportHeader AddHeader(string headerTitle, int width) public ReportHeader AddHeader(string headerTitle, int width)
{ {
var reportHeader = new ReportHeader(headerTitle, width); var reportHeader = new ReportHeader(headerTitle, width);
HeaderTitles.Add(reportHeader); ReportHeaders.Add(reportHeader);
return reportHeader; return reportHeader;
} }
/// <summary>
/// 添加标题
/// </summary>
public ReportHeader AddHeader(string headerTitle, int width, int minWidth, int maxWidth) public ReportHeader AddHeader(string headerTitle, int width, int minWidth, int maxWidth)
{ {
var reportHeader = new ReportHeader(headerTitle, width, minWidth, maxWidth); var reportHeader = new ReportHeader(headerTitle, width, minWidth, maxWidth);
HeaderTitles.Add(reportHeader); ReportHeaders.Add(reportHeader);
return reportHeader; return reportHeader;
} }
/// <summary>
/// 检测错误
/// </summary>
public void CheckError()
{
// 检测标题
Dictionary<string, ReportHeader> headerMap = new Dictionary<string, ReportHeader>();
foreach (var header in ReportHeaders)
{
string headerTitle = header.HeaderTitle;
if (headerMap.ContainsKey(headerTitle))
throw new Exception($"The header title {headerTitle} already exists !");
else
headerMap.Add(headerTitle, header);
}
// 检测扫描元素
HashSet<string> elementMap = new HashSet<string>();
foreach (var element in ReportElements)
{
if (string.IsNullOrEmpty(element.GUID))
throw new Exception($"The report element GUID is null or empty !");
if (elementMap.Contains(element.GUID))
throw new Exception($"The report element GUID already exists ! {element.GUID}");
else
elementMap.Add(element.GUID);
foreach (var scanInfo in element.ScanInfos)
{
if (headerMap.ContainsKey(scanInfo.HeaderTitle) == false)
throw new Exception($"The report element header {scanInfo.HeaderTitle} is missing !");
// 检测数值有效性
var header = headerMap[scanInfo.HeaderTitle];
header.CheckValueValid(scanInfo.ScanInfo);
}
}
}
} }
} }

View File

@ -55,9 +55,9 @@ namespace YooAsset.Editor
if (string.IsNullOrEmpty(SchemaType)) if (string.IsNullOrEmpty(SchemaType))
{ {
SchemaType = scanReport.SchemaType; SchemaType = scanReport.SchemaType;
ReportTitle = scanReport.ReportTitle; ReportTitle = scanReport.ReportName;
ReportDesc = scanReport.ReportDesc; ReportDesc = scanReport.ReportDesc;
Headers = scanReport.HeaderTitles; Headers = scanReport.ReportHeaders;
} }
if (SchemaType != scanReport.SchemaType) if (SchemaType != scanReport.SchemaType)
@ -82,7 +82,7 @@ namespace YooAsset.Editor
List<ReportElement> elements = scanReport.ReportElements; List<ReportElement> elements = scanReport.ReportElements;
// 设置白名单 // 设置白名单
var scanner = AssetArtScannerSettingData.GetScannerByGUID(scannerGUID); var scanner = AssetArtScannerSettingData.Setting.GetScanner(scannerGUID);
if (scanner != null) if (scanner != null)
{ {
foreach (var element in elements) foreach (var element in elements)
@ -144,7 +144,7 @@ namespace YooAsset.Editor
string scannerGUID = scanReport.ScannerGUID; string scannerGUID = scanReport.ScannerGUID;
var elements = scanReport.ReportElements; var elements = scanReport.ReportElements;
var scanner = AssetArtScannerSettingData.GetScannerByGUID(scannerGUID); var scanner = AssetArtScannerSettingData.Setting.GetScanner(scannerGUID);
if (scanner != null) if (scanner != null)
{ {
List<string> whiteList = new List<string>(elements.Count); List<string> whiteList = new List<string>(elements.Count);
@ -207,7 +207,7 @@ namespace YooAsset.Editor
private void FixInternal(string scannerGUID, List<ReportElement> fixList) private void FixInternal(string scannerGUID, List<ReportElement> fixList)
{ {
AssetArtScanner scanner = AssetArtScannerSettingData.GetScannerByGUID(scannerGUID); AssetArtScanner scanner = AssetArtScannerSettingData.Setting.GetScanner(scannerGUID);
if (scanner != null) if (scanner != null)
{ {
var schema = scanner.LoadSchema(); var schema = scanner.LoadSchema();

View File

@ -30,7 +30,7 @@ namespace YooAsset.Editor
// 检测标题数和内容是否匹配 // 检测标题数和内容是否匹配
foreach (var element in report.ReportElements) foreach (var element in report.ReportElements)
{ {
if (element.ScanInfos.Count != report.HeaderTitles.Count) if (element.ScanInfos.Count != report.ReportHeaders.Count)
{ {
throw new Exception($"报告的标题数和内容不匹配!"); throw new Exception($"报告的标题数和内容不匹配!");
} }

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.IO;
using UnityEditor; using UnityEditor;
using UnityEngine; using UnityEngine;
@ -46,6 +47,17 @@ namespace YooAsset.Editor
public List<string> WhiteList = new List<string>(); public List<string> WhiteList = new List<string>();
/// <summary>
/// 检测关键字匹配
/// </summary>
public bool CheckKeyword(string keyword)
{
if (ScannerName.Contains(keyword) || ScannerDesc.Contains(keyword))
return true;
else
return false;
}
/// <summary> /// <summary>
/// 是否在白名单里 /// 是否在白名单里
/// </summary> /// </summary>
@ -54,6 +66,24 @@ namespace YooAsset.Editor
return WhiteList.Contains(guid); return WhiteList.Contains(guid);
} }
/// <summary>
/// 检测配置错误
/// </summary>
public void CheckConfigError()
{
if (string.IsNullOrEmpty(ScannerName))
throw new Exception($"Scanner name is null or empty !");
if (string.IsNullOrEmpty(ScannerSchema))
throw new Exception($"Scanner {ScannerName} schema is null !");
if (string.IsNullOrEmpty(SaveDirectory) == false)
{
if (Directory.Exists(SaveDirectory) == false)
throw new Exception($"Scanner {ScannerName} save directory is invalid : {SaveDirectory}");
}
}
/// <summary> /// <summary>
/// 加载扫描模式实例 /// 加载扫描模式实例
/// </summary> /// </summary>
@ -85,14 +115,11 @@ namespace YooAsset.Editor
public ScanReport RunScanner() public ScanReport RunScanner()
{ {
if (Collectors.Count == 0) if (Collectors.Count == 0)
{ Debug.LogWarning($"Scanner {ScannerName} collector is empty !");
Debug.LogWarning($"Scanner collector is empty : {ScannerName}");
return null;
}
ScannerSchema schema = LoadSchema(); ScannerSchema schema = LoadSchema();
if (schema == null) if (schema == null)
return null; throw new Exception($"Failed to load schema : {ScannerSchema}");
var report = schema.RunScanner(this); var report = schema.RunScanner(this);
report.FileSign = ScannerDefine.ReportFileSign; report.FileSign = ScannerDefine.ReportFileSign;
@ -101,13 +128,5 @@ namespace YooAsset.Editor
report.ScannerGUID = ScannerGUID; report.ScannerGUID = ScannerGUID;
return report; return report;
} }
public bool CheckKeyword(string keyword)
{
if (ScannerName.Contains(keyword) || ScannerDesc.Contains(keyword))
return true;
else
return false;
}
} }
} }

View File

@ -4,6 +4,7 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.IO; using System.IO;
using UnityEngine; using UnityEngine;
using NUnit.Framework.Constraints;
namespace YooAsset.Editor namespace YooAsset.Editor
{ {
@ -13,5 +14,55 @@ namespace YooAsset.Editor
/// 扫描器列表 /// 扫描器列表
/// </summary> /// </summary>
public List<AssetArtScanner> Scanners = new List<AssetArtScanner>(); public List<AssetArtScanner> Scanners = new List<AssetArtScanner>();
/// <summary>
/// 开始扫描
/// </summary>
public ScannerResult BeginScan(string scannerGUID)
{
try
{
// 获取扫描器配置
var scanner = GetScanner(scannerGUID);
if (scanner == null)
throw new Exception($"Invalid scanner GUID : {scannerGUID}");
// 检测配置合法性
scanner.CheckConfigError();
// 开始扫描工作
ScanReport report = scanner.RunScanner();
// 检测报告合法性
report.CheckError();
// 保存扫描结果
string saveDirectory = scanner.SaveDirectory;
if (string.IsNullOrEmpty(saveDirectory))
saveDirectory = "Assets/";
string filePath = $"{saveDirectory}/{scanner.ScannerName}_{scanner.ScannerDesc}.json";
ScanReportConfig.ExportJsonConfig(filePath, report);
return new ScannerResult(filePath, report);
}
catch (Exception e)
{
return new ScannerResult(e.Message);
}
}
/// <summary>
/// 获取指定的扫描器
/// </summary>
public AssetArtScanner GetScanner(string scannerGUID)
{
foreach (var scanner in Scanners)
{
if (scanner.ScannerGUID == scannerGUID)
return scanner;
}
Debug.LogWarning($"Not found scanner : {scannerGUID}");
return null;
}
} }
} }

View File

@ -61,10 +61,10 @@ namespace YooAsset.Editor
{ {
foreach (var scanner in Setting.Scanners) foreach (var scanner in Setting.Scanners)
{ {
var scanResult = ScanInternal(scanner); var scanResult = Setting.BeginScan(scanner.ScannerGUID);
if (scanResult.Succeed == false) if (scanResult.Succeed == false)
{ {
Debug.LogError($"Scanner {scanner.ScannerName} failed ! {scanResult.ErrorInfo}"); Debug.LogError($"{scanner.ScannerName} failed : {scanResult.ErrorInfo}");
} }
} }
} }
@ -82,10 +82,10 @@ namespace YooAsset.Editor
continue; continue;
} }
var scanResult = ScanInternal(scanner); var scanResult = Setting.BeginScan(scanner.ScannerGUID);
if (scanResult.Succeed == false) if (scanResult.Succeed == false)
{ {
Debug.LogError($"Scanner {scanner.ScannerName} failed ! {scanResult.ErrorInfo}"); Debug.LogError($"{scanner.ScannerName} failed : {scanResult.ErrorInfo}");
} }
} }
} }
@ -95,30 +95,14 @@ namespace YooAsset.Editor
/// </summary> /// </summary>
public static ScannerResult Scan(string scannerGUID) public static ScannerResult Scan(string scannerGUID)
{ {
AssetArtScanner scanner = GetScannerByGUID(scannerGUID); var scanResult = Setting.BeginScan(scannerGUID);
var scanResult = ScanInternal(scanner);
if (scanResult.Succeed == false) if (scanResult.Succeed == false)
{ {
Debug.LogError($"Scanner {scanner.ScannerName} failed ! {scanResult.ErrorInfo}"); Debug.LogError(scanResult.ErrorInfo);
} }
return scanResult; return scanResult;
} }
/// <summary>
/// 获取指定的扫描器
/// </summary>
public static AssetArtScanner GetScannerByGUID(string scannerGUID)
{
foreach (var scanner in Setting.Scanners)
{
if (scanner.ScannerGUID == scannerGUID)
return scanner;
}
Debug.LogWarning($"Not found scanner : {scannerGUID}");
return null;
}
// 扫描器编辑相关 // 扫描器编辑相关
public static AssetArtScanner CreateScanner(string name, string desc) public static AssetArtScanner CreateScanner(string name, string desc)
{ {
@ -173,31 +157,5 @@ namespace YooAsset.Editor
IsDirty = true; IsDirty = true;
} }
} }
private static ScannerResult ScanInternal(AssetArtScanner scanner)
{
if (scanner == null)
return new ScannerResult("Scanner is null !");
string saveDirectory = "Assets/";
if (string.IsNullOrEmpty(scanner.SaveDirectory) == false)
{
saveDirectory = scanner.SaveDirectory;
if (Directory.Exists(saveDirectory) == false)
return new ScannerResult($"Scanner save directory is invalid : {saveDirectory}");
}
ScanReport report = scanner.RunScanner();
if (report != null)
{
string filePath = $"{saveDirectory}/{scanner.ScannerName}_{scanner.ScannerDesc}.json";
ScanReportConfig.ExportJsonConfig(filePath, report);
return new ScannerResult(filePath, report);
}
else
{
return new ScannerResult($"Scanner run failed : {scanner.ScannerName}");
}
}
} }
} }

View File

@ -98,9 +98,9 @@ namespace YooAsset.Editor
} }
/// <summary> /// <summary>
/// 开始收集工作 /// 获取收集的资源列表
/// </summary> /// </summary>
public CollectResult BeginCollect(CollectCommand command) public List<CollectAssetInfo> GetCollectAssets(CollectCommand command)
{ {
Dictionary<string, CollectAssetInfo> result = new Dictionary<string, CollectAssetInfo>(10000); Dictionary<string, CollectAssetInfo> result = new Dictionary<string, CollectAssetInfo>(10000);
@ -139,9 +139,7 @@ namespace YooAsset.Editor
} }
// 返回结果 // 返回结果
var collectAssets = result.Values.ToList(); return result.Values.ToList();
var collectResult = new CollectResult(command, collectAssets);
return collectResult;
} }
/// <summary> /// <summary>

View File

@ -116,7 +116,8 @@ namespace YooAsset.Editor
command.AutoCollectShaders = package.AutoCollectShaders; command.AutoCollectShaders = package.AutoCollectShaders;
// 开始收集工作 // 开始收集工作
CollectResult collectResult = package.BeginCollect(command); var collectAssets = package.GetCollectAssets(command);
var collectResult = new CollectResult(command, collectAssets);
return collectResult; return collectResult;
} }

View File

@ -113,12 +113,13 @@ namespace YooAsset
} }
public virtual FSDownloadFileOperation DownloadFileAsync(PackageBundle bundle, DownloadParam param) public virtual FSDownloadFileOperation DownloadFileAsync(PackageBundle bundle, DownloadParam param)
{ {
// 注意:业务层的解压下载器会依赖内置文件系统的下载方法
param.ImportFilePath = GetBuildinFileLoadPath(bundle); param.ImportFilePath = GetBuildinFileLoadPath(bundle);
return _unpackFileSystem.DownloadFileAsync(bundle, param); return _unpackFileSystem.DownloadFileAsync(bundle, param);
} }
public virtual FSLoadBundleOperation LoadBundleFile(PackageBundle bundle) public virtual FSLoadBundleOperation LoadBundleFile(PackageBundle bundle)
{ {
if (NeedUnpack(bundle)) if (IsUnpackBundleFile(bundle))
{ {
return _unpackFileSystem.LoadBundleFile(bundle); return _unpackFileSystem.LoadBundleFile(bundle);
} }
@ -216,11 +217,7 @@ namespace YooAsset
} }
public virtual bool NeedUnpack(PackageBundle bundle) public virtual bool NeedUnpack(PackageBundle bundle)
{ {
if (Belong(bundle) == false) if (IsUnpackBundleFile(bundle))
return false;
#if UNITY_ANDROID
if (bundle.BundleType == (int)EBuildBundleType.RawBundle || bundle.Encrypted)
{ {
return _unpackFileSystem.Exists(bundle) == false; return _unpackFileSystem.Exists(bundle) == false;
} }
@ -228,9 +225,6 @@ namespace YooAsset
{ {
return false; return false;
} }
#else
return false;
#endif
} }
public virtual bool NeedImport(PackageBundle bundle) public virtual bool NeedImport(PackageBundle bundle)
{ {
@ -239,14 +233,14 @@ namespace YooAsset
public virtual string GetBundleFilePath(PackageBundle bundle) public virtual string GetBundleFilePath(PackageBundle bundle)
{ {
if (NeedUnpack(bundle)) if (IsUnpackBundleFile(bundle))
return _unpackFileSystem.GetBundleFilePath(bundle); return _unpackFileSystem.GetBundleFilePath(bundle);
return GetBuildinFileLoadPath(bundle); return GetBuildinFileLoadPath(bundle);
} }
public virtual byte[] ReadBundleFileData(PackageBundle bundle) public virtual byte[] ReadBundleFileData(PackageBundle bundle)
{ {
if (NeedUnpack(bundle)) if (IsUnpackBundleFile(bundle))
return _unpackFileSystem.ReadBundleFileData(bundle); return _unpackFileSystem.ReadBundleFileData(bundle);
if (Exists(bundle) == false) if (Exists(bundle) == false)
@ -277,7 +271,7 @@ namespace YooAsset
} }
public virtual string ReadBundleFileText(PackageBundle bundle) public virtual string ReadBundleFileText(PackageBundle bundle)
{ {
if (NeedUnpack(bundle)) if (IsUnpackBundleFile(bundle))
return _unpackFileSystem.ReadBundleFileText(bundle); return _unpackFileSystem.ReadBundleFileText(bundle);
if (Exists(bundle) == false) if (Exists(bundle) == false)
@ -343,6 +337,24 @@ namespace YooAsset
return YooAssetSettingsData.GetYooResourcesLoadPath(PackageName, fileName); return YooAssetSettingsData.GetYooResourcesLoadPath(PackageName, fileName);
} }
/// <summary>
/// 是否属于解压资源包文件
/// </summary>
protected bool IsUnpackBundleFile(PackageBundle bundle)
{
if (Belong(bundle) == false)
return false;
#if UNITY_ANDROID
if (bundle.BundleType == (int)EBuildBundleType.RawBundle || bundle.Encrypted)
return true;
else
return false;
#else
return false;
#endif
}
/// <summary> /// <summary>
/// 记录文件信息 /// 记录文件信息
/// </summary> /// </summary>

View File

@ -318,8 +318,15 @@ namespace YooAsset
} }
else if (nameStyle == (int)EFileNameStyle.BundleName_HashName) else if (nameStyle == (int)EFileNameStyle.BundleName_HashName)
{ {
string fileName = bundleName.Remove(bundleName.LastIndexOf('.')); if (string.IsNullOrEmpty(fileExtension))
return StringUtility.Format("{0}_{1}{2}", fileName, fileHash, fileExtension); {
return StringUtility.Format("{0}_{1}", bundleName, fileHash);
}
else
{
string fileName = bundleName.Remove(bundleName.LastIndexOf('.'));
return StringUtility.Format("{0}_{1}{2}", fileName, fileHash, fileExtension);
}
} }
else else
{ {

View File

@ -1,7 +1,7 @@
{ {
"name": "com.tuyoogame.yooasset", "name": "com.tuyoogame.yooasset",
"displayName": "YooAsset", "displayName": "YooAsset",
"version": "2.2.10", "version": "2.2.11",
"unity": "2019.4", "unity": "2019.4",
"description": "unity3d resources management system.", "description": "unity3d resources management system.",
"author": { "author": {