TEngine 6

This commit is contained in:
Alex-Rachel
2025-03-07 23:09:46 +08:00
parent aad8ff3ee5
commit 551727687f
1988 changed files with 46223 additions and 94880 deletions

View File

@@ -0,0 +1,624 @@
#if UNITY_2019_4_OR_NEWER
using System;
using System.IO;
using System.Linq;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEditor.UIElements;
using UnityEngine.UIElements;
namespace YooAsset.Editor
{
public class AssetArtReporterWindow : EditorWindow
{
[MenuItem("YooAsset/AssetArt Reporter", false, 302)]
public static AssetArtReporterWindow OpenWindow()
{
AssetArtReporterWindow window = GetWindow<AssetArtReporterWindow>("AssetArt Reporter", true, WindowsDefine.DockedWindowTypes);
window.minSize = new Vector2(800, 600);
return window;
}
private class ElementTableData : DefaultTableData
{
public ReportElement Element;
}
private class PassesBtnCell : ITableCell, IComparable
{
public object CellValue { set; get; }
public string SearchTag { private set; get; }
public ReportElement Element
{
get
{
return (ReportElement)CellValue;
}
}
public PassesBtnCell(string searchTag, ReportElement element)
{
SearchTag = searchTag;
CellValue = element;
}
public object GetDisplayObject()
{
return string.Empty;
}
public int CompareTo(object other)
{
if (other is PassesBtnCell cell)
{
return this.Element.Passes.CompareTo(cell.Element.Passes);
}
else
{
return 0;
}
}
}
private class WhiteListBtnCell : ITableCell, IComparable
{
public object CellValue { set; get; }
public string SearchTag { private set; get; }
public ReportElement Element
{
get
{
return (ReportElement)CellValue;
}
}
public WhiteListBtnCell(string searchTag, ReportElement element)
{
SearchTag = searchTag;
CellValue = element;
}
public object GetDisplayObject()
{
return string.Empty;
}
public int CompareTo(object other)
{
if (other is WhiteListBtnCell cell)
{
return this.Element.IsWhiteList.CompareTo(cell.Element.IsWhiteList);
}
else
{
return 0;
}
}
}
private ToolbarSearchField _searchField;
private Button _showHiddenBtn;
private Button _whiteListVisibleBtn;
private Button _passesVisibleBtn;
private Label _titleLabel;
private Label _descLabel;
private TableViewer _elementTableView;
private ScanReportCombiner _reportCombiner;
private string _lastestOpenFolder;
private List<ITableData> _sourceDatas;
private bool _elementVisibleState = true;
private bool _whiteListVisibleState = true;
private bool _passesVisibleState = true;
public void CreateGUI()
{
try
{
VisualElement root = this.rootVisualElement;
// 加载布局文件
var visualAsset = UxmlLoader.LoadWindowUXML<AssetArtReporterWindow>();
if (visualAsset == null)
return;
visualAsset.CloneTree(root);
// 导入按钮
var importSingleBtn = root.Q<Button>("SingleImportButton");
importSingleBtn.clicked += ImportSingleBtn_clicked;
var importMultiBtn = root.Q<Button>("MultiImportButton");
importMultiBtn.clicked += ImportMultiBtn_clicked;
// 修复按钮
var fixAllBtn = root.Q<Button>("FixAllButton");
fixAllBtn.clicked += FixAllBtn_clicked;
var fixSelectBtn = root.Q<Button>("FixSelectButton");
fixSelectBtn.clicked += FixSelectBtn_clicked;
// 可见性按钮
_showHiddenBtn = root.Q<Button>("ShowHiddenButton");
_showHiddenBtn.clicked += ShowHiddenBtn_clicked;
_whiteListVisibleBtn = root.Q<Button>("WhiteListVisibleButton");
_whiteListVisibleBtn.clicked += WhiteListVisibleBtn_clicked;
_passesVisibleBtn = root.Q<Button>("PassesVisibleButton");
_passesVisibleBtn.clicked += PassesVsibleBtn_clicked;
// 文件导出按钮
var exportFilesBtn = root.Q<Button>("ExportFilesButton");
exportFilesBtn.clicked += ExportFilesBtn_clicked;
// 搜索过滤
_searchField = root.Q<ToolbarSearchField>("SearchField");
_searchField.RegisterValueChangedCallback(OnSearchKeyWordChange);
// 标题和备注
_titleLabel = root.Q<Label>("ReportTitle");
_descLabel = root.Q<Label>("ReportDesc");
// 列表相关
_elementTableView = root.Q<TableViewer>("TopTableView");
_elementTableView.ClickTableDataEvent = OnClickTableViewItem;
_lastestOpenFolder = EditorTools.GetProjectPath();
}
catch (System.Exception e)
{
Debug.LogError(e.ToString());
}
}
public void OnDestroy()
{
if (_reportCombiner != null)
_reportCombiner.SaveChange();
}
/// <summary>
/// 导入单个报告文件
/// </summary>
public void ImportSingleReprotFile(string filePath)
{
// 记录本次打开目录
_lastestOpenFolder = Path.GetDirectoryName(filePath);
_reportCombiner = new ScanReportCombiner();
try
{
var scanReport = ScanReportConfig.ImportJsonConfig(filePath);
_reportCombiner.Combine(scanReport);
// 刷新页面
RefreshToolbar();
FillTableView();
RebuildView();
}
catch (System.Exception e)
{
_reportCombiner = null;
_titleLabel.text = "导入报告失败!";
_descLabel.text = e.Message;
UnityEngine.Debug.LogError(e.StackTrace);
}
}
private void ImportSingleBtn_clicked()
{
string selectFilePath = EditorUtility.OpenFilePanel("导入报告", _lastestOpenFolder, "json");
if (string.IsNullOrEmpty(selectFilePath))
return;
ImportSingleReprotFile(selectFilePath);
}
private void ImportMultiBtn_clicked()
{
string selectFolderPath = EditorUtility.OpenFolderPanel("导入报告", _lastestOpenFolder, null);
if (string.IsNullOrEmpty(selectFolderPath))
return;
// 记录本次打开目录
_lastestOpenFolder = selectFolderPath;
_reportCombiner = new ScanReportCombiner();
try
{
string[] files = Directory.GetFiles(selectFolderPath);
foreach (string filePath in files)
{
string extension = System.IO.Path.GetExtension(filePath);
if (extension == ".json")
{
var scanReport = ScanReportConfig.ImportJsonConfig(filePath);
_reportCombiner.Combine(scanReport);
}
}
// 刷新页面
RefreshToolbar();
FillTableView();
RebuildView();
}
catch (System.Exception e)
{
_reportCombiner = null;
_titleLabel.text = "导入报告失败!";
_descLabel.text = e.Message;
UnityEngine.Debug.LogError(e.StackTrace);
}
}
private void FixAllBtn_clicked()
{
if (EditorUtility.DisplayDialog("提示", "修复全部资源(排除白名单和隐藏元素)", "Yes", "No"))
{
if (_reportCombiner != null)
_reportCombiner.FixAll();
}
}
private void FixSelectBtn_clicked()
{
if (EditorUtility.DisplayDialog("提示", "修复勾选资源(包含白名单和隐藏元素)", "Yes", "No"))
{
if (_reportCombiner != null)
_reportCombiner.FixSelect();
}
}
private void ShowHiddenBtn_clicked()
{
_elementVisibleState = !_elementVisibleState;
RefreshToolbar();
RebuildView();
}
private void WhiteListVisibleBtn_clicked()
{
_whiteListVisibleState = !_whiteListVisibleState;
RefreshToolbar();
RebuildView();
}
private void PassesVsibleBtn_clicked()
{
_passesVisibleState = !_passesVisibleState;
RefreshToolbar();
RebuildView();
}
private void ExportFilesBtn_clicked()
{
string selectFolderPath = EditorUtility.OpenFolderPanel("导入所有选中资源", EditorTools.GetProjectPath(), string.Empty);
if (string.IsNullOrEmpty(selectFolderPath) == false)
{
if (_reportCombiner != null)
_reportCombiner.ExportFiles(selectFolderPath);
}
}
private void RefreshToolbar()
{
if (_reportCombiner == null)
return;
_titleLabel.text = _reportCombiner.ReportTitle;
_descLabel.text = _reportCombiner.ReportDesc;
var enableColor = new Color32(18, 100, 18, 255);
var disableColor = new Color32(100, 100, 100, 255);
if (_elementVisibleState)
_showHiddenBtn.style.backgroundColor = new StyleColor(enableColor);
else
_showHiddenBtn.style.backgroundColor = new StyleColor(disableColor);
if (_whiteListVisibleState)
_whiteListVisibleBtn.style.backgroundColor = new StyleColor(enableColor);
else
_whiteListVisibleBtn.style.backgroundColor = new StyleColor(disableColor);
if (_passesVisibleState)
_passesVisibleBtn.style.backgroundColor = new StyleColor(enableColor);
else
_passesVisibleBtn.style.backgroundColor = new StyleColor(disableColor);
}
private void FillTableView()
{
if (_reportCombiner == null)
return;
_elementTableView.ClearAll(true, true);
// 眼睛标题
{
var columnStyle = new ColumnStyle(20);
columnStyle.Stretchable = false;
columnStyle.Searchable = false;
columnStyle.Sortable = false;
var column = new TableColumn("眼睛框", string.Empty, columnStyle);
column.MakeCell = () =>
{
var toggle = new ToggleDisplay();
toggle.text = string.Empty;
toggle.style.unityTextAlign = TextAnchor.MiddleCenter;
toggle.RegisterValueChangedCallback((evt) => { OnDisplayToggleValueChange(toggle, evt); });
return toggle;
};
column.BindCell = (VisualElement element, ITableData data, ITableCell cell) =>
{
var toggle = element as ToggleDisplay;
toggle.userData = data;
var tableData = data as ElementTableData;
toggle.SetValueWithoutNotify(tableData.Element.Hidden);
};
_elementTableView.AddColumn(column);
var headerElement = _elementTableView.GetHeaderElement("眼睛框");
headerElement.style.unityTextAlign = TextAnchor.MiddleCenter;
}
// 通过标题
{
var columnStyle = new ColumnStyle(70);
columnStyle.Stretchable = false;
columnStyle.Searchable = false;
columnStyle.Sortable = true;
var column = new TableColumn("通过", "通过", columnStyle);
column.MakeCell = () =>
{
var button = new Button();
button.text = "通过";
button.style.unityTextAlign = TextAnchor.MiddleCenter;
button.SetEnabled(false);
return button;
};
column.BindCell = (VisualElement element, ITableData data, ITableCell cell) =>
{
Button button = element as Button;
var elementTableData = data as ElementTableData;
if (elementTableData.Element.Passes)
{
button.style.backgroundColor = new StyleColor(new Color32(56, 147, 58, 255));
button.text = "通过";
}
else
{
button.style.backgroundColor = new StyleColor(new Color32(137, 0, 0, 255));
button.text = "失败";
}
};
_elementTableView.AddColumn(column);
var headerElement = _elementTableView.GetHeaderElement("通过");
headerElement.style.unityTextAlign = TextAnchor.MiddleCenter;
}
// 白名单标题
{
var columnStyle = new ColumnStyle(70);
columnStyle.Stretchable = false;
columnStyle.Searchable = false;
columnStyle.Sortable = true;
var column = new TableColumn("白名单", "白名单", columnStyle);
column.MakeCell = () =>
{
Button button = new Button();
button.text = "白名单";
button.style.unityTextAlign = TextAnchor.MiddleCenter;
button.clickable.clickedWithEventInfo += OnClickWhitListButton;
return button;
};
column.BindCell = (VisualElement element, ITableData data, ITableCell cell) =>
{
Button button = element as Button;
button.userData = data;
var elementTableData = data as ElementTableData;
if (elementTableData.Element.IsWhiteList)
button.style.backgroundColor = new StyleColor(new Color32(56, 147, 58, 255));
else
button.style.backgroundColor = new StyleColor(new Color32(100, 100, 100, 255));
};
_elementTableView.AddColumn(column);
var headerElement = _elementTableView.GetHeaderElement("白名单");
headerElement.style.unityTextAlign = TextAnchor.MiddleCenter;
}
// 选中标题
{
var columnStyle = new ColumnStyle(20);
columnStyle.Stretchable = false;
columnStyle.Searchable = false;
columnStyle.Sortable = false;
var column = new TableColumn("选中框", string.Empty, columnStyle);
column.MakeCell = () =>
{
var toggle = new Toggle();
toggle.text = string.Empty;
toggle.style.unityTextAlign = TextAnchor.MiddleCenter;
toggle.RegisterValueChangedCallback((evt) => { OnSelectToggleValueChange(toggle, evt); });
return toggle;
};
column.BindCell = (VisualElement element, ITableData data, ITableCell cell) =>
{
var toggle = element as Toggle;
toggle.userData = data;
var tableData = data as ElementTableData;
toggle.SetValueWithoutNotify(tableData.Element.IsSelected);
};
_elementTableView.AddColumn(column);
}
// 自定义标题栏
foreach (var header in _reportCombiner.Headers)
{
var columnStyle = new ColumnStyle(header.Width, header.MinWidth, header.MaxWidth);
columnStyle.Stretchable = header.Stretchable;
columnStyle.Searchable = header.Searchable;
columnStyle.Sortable = header.Sortable;
columnStyle.Counter = header.Counter;
columnStyle.Units = header.Units;
var column = new TableColumn(header.HeaderTitle, header.HeaderTitle, columnStyle);
column.MakeCell = () =>
{
var label = new Label();
label.style.marginLeft = 3f;
label.style.unityTextAlign = TextAnchor.MiddleLeft;
return label;
};
column.BindCell = (VisualElement element, ITableData data, ITableCell cell) =>
{
var infoLabel = element as Label;
infoLabel.text = (string)cell.GetDisplayObject();
};
_elementTableView.AddColumn(column);
}
// 填充数据源
_sourceDatas = new List<ITableData>(_reportCombiner.Elements.Count);
foreach (var element in _reportCombiner.Elements)
{
var tableData = new ElementTableData();
tableData.Element = element;
// 固定标题
tableData.AddButtonCell("眼睛框");
tableData.AddCell(new PassesBtnCell("通过", element));
tableData.AddCell(new WhiteListBtnCell("白名单", element));
tableData.AddButtonCell("选中框");
// 自定义标题
foreach (var scanInfo in element.ScanInfos)
{
var header = _reportCombiner.GetHeader(scanInfo.HeaderTitle);
if (header.HeaderType == EHeaderType.AssetPath)
{
tableData.AddAssetPathCell(scanInfo.HeaderTitle, scanInfo.ScanInfo);
}
else if (header.HeaderType == EHeaderType.StringValue)
{
tableData.AddStringValueCell(scanInfo.HeaderTitle, scanInfo.ScanInfo);
}
else if (header.HeaderType == EHeaderType.LongValue)
{
long value = Convert.ToInt64(scanInfo.ScanInfo);
tableData.AddLongValueCell(scanInfo.HeaderTitle, value);
}
else if (header.HeaderType == EHeaderType.DoubleValue)
{
double value = Convert.ToDouble(scanInfo.ScanInfo);
tableData.AddDoubleValueCell(scanInfo.HeaderTitle, value);
}
else
{
throw new NotImplementedException(header.HeaderType.ToString());
}
}
_sourceDatas.Add(tableData);
}
_elementTableView.itemsSource = _sourceDatas;
}
private void RebuildView()
{
if (_reportCombiner == null)
return;
string searchKeyword = _searchField.value;
// 搜索匹配
DefaultSearchSystem.Search(_sourceDatas, searchKeyword);
// 开关匹配
foreach (var tableData in _sourceDatas)
{
var elementTableData = tableData as ElementTableData;
if (_elementVisibleState == false && elementTableData.Element.Hidden)
{
tableData.Visible = false;
continue;
}
if (_passesVisibleState == false && elementTableData.Element.Passes)
{
tableData.Visible = false;
continue;
}
if (_whiteListVisibleState == false && elementTableData.Element.IsWhiteList)
{
tableData.Visible = false;
continue;
}
}
// 重建视图
_elementTableView.RebuildView();
}
private void OnClickTableViewItem(PointerDownEvent evt, ITableData tableData)
{
// 双击后检视对应的资源
if (evt.clickCount == 2)
{
foreach (var cell in tableData.Cells)
{
if (cell is AssetPathCell assetPathCell)
{
if (assetPathCell.PingAssetObject())
break;
}
}
}
}
private void OnSearchKeyWordChange(ChangeEvent<string> e)
{
RebuildView();
}
private void OnSelectToggleValueChange(Toggle toggle, ChangeEvent<bool> e)
{
// 处理自身
toggle.SetValueWithoutNotify(e.newValue);
// 记录数据
var elementTableData = toggle.userData as ElementTableData;
elementTableData.Element.IsSelected = e.newValue;
// 处理多选目标
var selectedItems = _elementTableView.selectedItems;
foreach (var selectedItem in selectedItems)
{
var selectElement = selectedItem as ElementTableData;
selectElement.Element.IsSelected = e.newValue;
}
// 重绘视图
RebuildView();
}
private void OnDisplayToggleValueChange(ToggleDisplay toggle, ChangeEvent<bool> e)
{
// 处理自身
toggle.SetValueWithoutNotify(e.newValue);
// 记录数据
var elementTableData = toggle.userData as ElementTableData;
elementTableData.Element.Hidden = e.newValue;
// 处理多选目标
var selectedItems = _elementTableView.selectedItems;
foreach (var selectedItem in selectedItems)
{
var selectElement = selectedItem as ElementTableData;
if (selectElement != null)
selectElement.Element.Hidden = e.newValue;
}
// 重绘视图
RebuildView();
}
private void OnClickWhitListButton(EventBase evt)
{
// 刷新点击的按钮
Button button = evt.target as Button;
var elementTableData = button.userData as ElementTableData;
elementTableData.Element.IsWhiteList = !elementTableData.Element.IsWhiteList;
// 刷新框选的按钮
var selectedItems = _elementTableView.selectedItems;
if (selectedItems.Count() > 1)
{
foreach (var selectedItem in selectedItems)
{
var selectElement = selectedItem as ElementTableData;
selectElement.Element.IsWhiteList = selectElement.Element.IsWhiteList;
}
}
RebuildView();
}
}
}
#endif

View File

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

View File

@@ -0,0 +1,22 @@
<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" editor-extension-mode="True">
<uie:Toolbar name="Toolbar" style="display: flex; flex-direction: row;">
<uie:ToolbarSearchField focusable="true" name="SearchField" style="flex-grow: 1;" />
<ui:Button text="Fix Select" display-tooltip-when-elided="true" name="FixSelectButton" style="width: 80px; background-color: rgb(56, 147, 58);" />
<ui:Button text="Fix All" display-tooltip-when-elided="true" name="FixAllButton" style="width: 80px; background-color: rgb(56, 147, 58);" />
<ui:Button text="Export Select" display-tooltip-when-elided="true" name="ExportFilesButton" style="width: 100px; background-color: rgb(56, 147, 58);" />
<ui:Button text=" Multi-Import" display-tooltip-when-elided="true" name="MultiImportButton" style="width: 100px; background-color: rgb(56, 147, 58);" />
<ui:Button text="Import" display-tooltip-when-elided="true" name="SingleImportButton" style="width: 100px; background-color: rgb(56, 147, 58);" />
</uie:Toolbar>
<ui:VisualElement name="PublicContainer" style="background-color: rgb(79, 79, 79); flex-direction: column; border-left-width: 5px; border-right-width: 5px; border-top-width: 5px; border-bottom-width: 5px;">
<ui:Label text="标题" display-tooltip-when-elided="true" name="ReportTitle" style="height: 16px; -unity-font-style: bold; -unity-text-align: middle-center;" />
<ui:Label text="说明" display-tooltip-when-elided="true" name="ReportDesc" style="-unity-text-align: upper-left; -unity-font-style: bold; background-color: rgb(42, 42, 42); min-height: 50px; border-top-left-radius: 3px; border-bottom-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; white-space: normal;" />
</ui:VisualElement>
<uie:Toolbar name="Toolbar" style="display: flex; flex-direction: row;">
<ui:Button text="显示隐藏元素" display-tooltip-when-elided="true" name="ShowHiddenButton" style="width: 100px;" />
<ui:Button text="显示通过元素" display-tooltip-when-elided="true" name="PassesVisibleButton" style="width: 100px;" />
<ui:Button text="显示白名单元素" display-tooltip-when-elided="true" name="WhiteListVisibleButton" style="width: 100px;" />
</uie:Toolbar>
<ui:VisualElement name="AssetGroup" 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;">
<YooAsset.Editor.TableViewer name="TopTableView" />
</ui:VisualElement>
</ui:UXML>

View File

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

View File

@@ -0,0 +1,26 @@

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

View File

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

View File

@@ -0,0 +1,88 @@
using System;
using System.Collections;
using System.Collections.Generic;
namespace YooAsset.Editor
{
[Serializable]
public class ReportElement
{
/// <summary>
/// GUID白名单存储对象
/// </summary>
public string GUID;
/// <summary>
/// 扫描是否通过
/// </summary>
public bool Passes = true;
/// <summary>
/// 反馈的信息列表
/// </summary>
public List<ReportScanInfo> ScanInfos = new List<ReportScanInfo>();
public ReportElement(string guid)
{
GUID = guid;
}
/// <summary>
/// 添加扫描信息
/// </summary>
public void AddScanInfo(string headerTitle, string value)
{
var reportScanInfo = new ReportScanInfo(headerTitle, value);
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>
public ReportScanInfo GetScanInfo(string headerTitle)
{
foreach (var scanInfo in ScanInfos)
{
if (scanInfo.HeaderTitle == headerTitle)
return scanInfo;
}
UnityEngine.Debug.LogWarning($"Not found {nameof(ReportScanInfo)} : {headerTitle}");
return null;
}
#region
/// <summary>
/// 是否在列表里选中
/// </summary>
public bool IsSelected { set; get; }
/// <summary>
/// 是否在白名单里
/// </summary>
public bool IsWhiteList { set; get; }
/// <summary>
/// 是否隐藏元素
/// </summary>
public bool Hidden { set; get; }
#endregion
}
}

View File

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

View File

@@ -0,0 +1,148 @@
using System;
using UnityEditor;
namespace YooAsset.Editor
{
[Serializable]
public class ReportHeader
{
public const int MaxValue = 8388608;
/// <summary>
/// 标题
/// </summary>
public string HeaderTitle;
/// <summary>
/// 标题宽度
/// </summary>
public int Width;
/// <summary>
/// 单元列最小宽度
/// </summary>
public int MinWidth = 50;
/// <summary>
/// 单元列最大宽度
/// </summary>
public int MaxWidth = MaxValue;
/// <summary>
/// 可伸缩选项
/// </summary>
public bool Stretchable = false;
/// <summary>
/// 可搜索选项
/// </summary>
public bool Searchable = false;
/// <summary>
/// 可排序选项
/// </summary>
public bool Sortable = false;
/// <summary>
/// 统计数量
/// </summary>
public bool Counter = false;
/// <summary>
/// 展示单位
/// </summary>
public string Units = string.Empty;
/// <summary>
/// 数值类型
/// </summary>
public EHeaderType HeaderType = EHeaderType.StringValue;
public ReportHeader(string headerTitle, int width)
{
HeaderTitle = headerTitle;
Width = width;
MinWidth = width;
MaxWidth = width;
}
public ReportHeader(string headerTitle, int width, int minWidth, int maxWidth)
{
HeaderTitle = headerTitle;
Width = width;
MinWidth = minWidth;
MaxWidth = maxWidth;
}
public ReportHeader SetMinWidth(int value)
{
MinWidth = value;
return this;
}
public ReportHeader SetMaxWidth(int value)
{
MaxWidth = value;
return this;
}
public ReportHeader SetStretchable()
{
Stretchable = true;
return this;
}
public ReportHeader SetSearchable()
{
Searchable = true;
return this;
}
public ReportHeader SetSortable()
{
Sortable = true;
return this;
}
public ReportHeader SetCounter()
{
Counter = true;
return this;
}
public ReportHeader SetUnits(string units)
{
Units = units;
return this;
}
public ReportHeader SetHeaderType(EHeaderType value)
{
HeaderType = value;
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

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

View File

@@ -0,0 +1,26 @@
using System;
using System.Collections;
using System.Collections.Generic;
namespace YooAsset.Editor
{
[Serializable]
public class ReportScanInfo
{
/// <summary>
/// 标题
/// </summary>
public string HeaderTitle;
/// <summary>
/// 扫描反馈的信息
/// </summary>
public string ScanInfo;
public ReportScanInfo(string headerTitle, string scanInfo)
{
HeaderTitle = headerTitle;
ScanInfo = scanInfo;
}
}
}

View File

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

View File

@@ -0,0 +1,118 @@
using System;
using System.Collections;
using System.Collections.Generic;
namespace YooAsset.Editor
{
[Serializable]
public class ScanReport
{
/// <summary>
/// 文件签名(自动填写)
/// </summary>
public string FileSign;
/// <summary>
/// 文件版本(自动填写)
/// </summary>
public string FileVersion;
/// <summary>
/// 模式类型(自动填写)
/// </summary>
public string SchemaType;
/// <summary>
/// 扫描器GUID自动填写
/// </summary>
public string ScannerGUID;
/// <summary>
/// 报告名称
/// </summary>
public string ReportName;
/// <summary>
/// 报告介绍
/// </summary>
public string ReportDesc;
/// <summary>
/// 报告的标题列表
/// </summary>
public List<ReportHeader> ReportHeaders = new List<ReportHeader>();
/// <summary>
/// 扫描的元素列表
/// </summary>
public List<ReportElement> ReportElements = new List<ReportElement>();
public ScanReport(string reportName, string reportDesc)
{
ReportName = reportName;
ReportDesc = reportDesc;
}
/// <summary>
/// 添加标题
/// </summary>
public ReportHeader AddHeader(string headerTitle, int width)
{
var reportHeader = new ReportHeader(headerTitle, width);
ReportHeaders.Add(reportHeader);
return reportHeader;
}
/// <summary>
/// 添加标题
/// </summary>
public ReportHeader AddHeader(string headerTitle, int width, int minWidth, int maxWidth)
{
var reportHeader = new ReportHeader(headerTitle, width, minWidth, maxWidth);
ReportHeaders.Add(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

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 650e3e4af4ede2a4eb2471c30e7820bb
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 System.IO;
using System;
using UnityEngine;
using UnityEditor;
namespace YooAsset.Editor
{
/// <summary>
/// 资源扫描报告合并器
/// 说明:相同类型的报告可以合并查看
/// </summary>
public class ScanReportCombiner
{
/// <summary>
/// 模式类型
/// </summary>
public string SchemaType { private set; get; }
/// <summary>
/// 报告标题
/// </summary>
public string ReportTitle { private set; get; }
/// <summary>
/// 报告介绍
/// </summary>
public string ReportDesc { private set; get; }
/// <summary>
/// 标题列表
/// </summary>
public List<ReportHeader> Headers = new List<ReportHeader>();
/// <summary>
/// 扫描结果
/// </summary>
public readonly List<ReportElement> Elements = new List<ReportElement>(10000);
private readonly Dictionary<string, ScanReport> _combines = new Dictionary<string, ScanReport>(100);
/// <summary>
/// 合并报告文件
/// 注意:模式不同的报告文件会合并失败!
/// </summary>
public bool Combine(ScanReport scanReport)
{
if (string.IsNullOrEmpty(scanReport.SchemaType))
{
Debug.LogError("Scan report schema type is null or empty !");
return false;
}
if (string.IsNullOrEmpty(SchemaType))
{
SchemaType = scanReport.SchemaType;
ReportTitle = scanReport.ReportName;
ReportDesc = scanReport.ReportDesc;
Headers = scanReport.ReportHeaders;
}
if (SchemaType != scanReport.SchemaType)
{
Debug.LogWarning($"Scan report has different schema type{scanReport.SchemaType} != {SchemaType}");
return false;
}
if (_combines.ContainsKey(scanReport.ScannerGUID))
{
Debug.LogWarning($"Scan report has already existed : {scanReport.ScannerGUID}");
return false;
}
_combines.Add(scanReport.ScannerGUID, scanReport);
CombineInternal(scanReport);
return true;
}
private void CombineInternal(ScanReport scanReport)
{
string scannerGUID = scanReport.ScannerGUID;
List<ReportElement> elements = scanReport.ReportElements;
// 设置白名单
var scanner = AssetArtScannerSettingData.Setting.GetScanner(scannerGUID);
if (scanner != null)
{
foreach (var element in elements)
{
if (scanner.CheckWhiteList(element.GUID))
element.IsWhiteList = true;
}
}
// 添加到集合
Elements.AddRange(elements);
}
/// <summary>
/// 获取指定的标题类
/// </summary>
public ReportHeader GetHeader(string headerTitle)
{
foreach (var header in Headers)
{
if (header.HeaderTitle == headerTitle)
return header;
}
UnityEngine.Debug.LogWarning($"Not found {nameof(ReportHeader)} : {headerTitle}");
return null;
}
/// <summary>
/// 导出选中文件
/// </summary>
public void ExportFiles(string exportFolderPath)
{
if (string.IsNullOrEmpty(exportFolderPath))
return;
foreach (var element in Elements)
{
if (element.IsSelected)
{
string assetPath = AssetDatabase.GUIDToAssetPath(element.GUID);
if (string.IsNullOrEmpty(assetPath) == false)
{
string destPath = Path.Combine(exportFolderPath, assetPath);
EditorTools.CopyFile(assetPath, destPath, true);
}
}
}
}
/// <summary>
/// 保存改变数据
/// </summary>
public void SaveChange()
{
// 存储白名单
foreach (var scanReport in _combines.Values)
{
string scannerGUID = scanReport.ScannerGUID;
var elements = scanReport.ReportElements;
var scanner = AssetArtScannerSettingData.Setting.GetScanner(scannerGUID);
if (scanner != null)
{
List<string> whiteList = new List<string>(elements.Count);
foreach (var element in elements)
{
if (element.IsWhiteList)
whiteList.Add(element.GUID);
}
whiteList.Sort();
scanner.WhiteList = whiteList;
AssetArtScannerSettingData.SaveFile();
}
}
}
/// <summary>
/// 修复所有元素
/// 注意:排除白名单和隐藏元素
/// </summary>
public void FixAll()
{
foreach (var scanReport in _combines.Values)
{
string scannerGUID = scanReport.ScannerGUID;
var elements = scanReport.ReportElements;
List<ReportElement> fixList = new List<ReportElement>(elements.Count);
foreach (var element in elements)
{
if (element.Passes || element.IsWhiteList || element.Hidden)
continue;
fixList.Add(element);
}
FixInternal(scannerGUID, fixList);
}
}
/// <summary>
/// 修复选定元素
/// 注意:包含白名单和隐藏元素
/// </summary>
public void FixSelect()
{
foreach (var scanReport in _combines.Values)
{
string scannerGUID = scanReport.ScannerGUID;
var elements = scanReport.ReportElements;
List<ReportElement> fixList = new List<ReportElement>(elements.Count);
foreach (var element in elements)
{
if (element.Passes)
continue;
if (element.IsSelected)
fixList.Add(element);
}
FixInternal(scannerGUID, fixList);
}
}
private void FixInternal(string scannerGUID, List<ReportElement> fixList)
{
AssetArtScanner scanner = AssetArtScannerSettingData.Setting.GetScanner(scannerGUID);
if (scanner != null)
{
var schema = scanner.LoadSchema();
if (schema != null)
{
schema.FixResult(fixList);
}
}
}
}
}

View File

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

View File

@@ -0,0 +1,54 @@
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System;
using UnityEngine;
namespace YooAsset.Editor
{
public class ScanReportConfig
{
/// <summary>
/// 导入JSON报告文件
/// </summary>
public static ScanReport ImportJsonConfig(string filePath)
{
if (File.Exists(filePath) == false)
throw new FileNotFoundException(filePath);
string jsonData = FileUtility.ReadAllText(filePath);
ScanReport report = JsonUtility.FromJson<ScanReport>(jsonData);
// 检测配置文件的签名
if (report.FileSign != ScannerDefine.ReportFileSign)
throw new Exception($"导入的报告文件无法识别 : {filePath}");
// 检测报告文件的版本
if (report.FileVersion != ScannerDefine.ReportFileVersion)
throw new Exception($"报告文件的版本不匹配 : {report.FileVersion} != {ScannerDefine.ReportFileVersion}");
// 检测标题数和内容是否匹配
foreach (var element in report.ReportElements)
{
if (element.ScanInfos.Count != report.ReportHeaders.Count)
{
throw new Exception($"报告的标题数和内容不匹配!");
}
}
return report;
}
/// <summary>
/// 导出JSON报告文件
/// </summary>
public static void ExportJsonConfig(string savePath, ScanReport scanReport)
{
if (File.Exists(savePath))
File.Delete(savePath);
string json = JsonUtility.ToJson(scanReport, true);
FileUtility.WriteAllText(savePath, json);
}
}
}

View File

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