mirror of https://github.com/tuyoogame/YooAsset
624 lines
23 KiB
C#
624 lines
23 KiB
C#
#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 TableView _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<TableView>("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 DisplayToggle();
|
|
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 DisplayToggle;
|
|
toggle.userData = data;
|
|
var tableData = data as ElementTableData;
|
|
toggle.SetValueWithoutNotify(tableData.Element.Hidden);
|
|
toggle.RefreshIcon();
|
|
};
|
|
_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;
|
|
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(DisplayToggle toggle, ChangeEvent<bool> e)
|
|
{
|
|
toggle.RefreshIcon();
|
|
|
|
// 处理自身
|
|
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;
|
|
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 |