module-project-validator/Editor/Window/EditorProjectValidatorWindow.cs
Anders Ejlersen eb46c22ffc Validator: Skipping render pipeline check on shader, fi no RenderPipeline tag is found
Validator: Skipping textures in material, if marked as PerRendererData, HideInInspector or NonModifiableTextureData
Validator: Fixed issue, where arrays weren't iterated correctly, which resulted in an exception
Window: Added warning and error count
2026-05-27 21:50:04 +02:00

286 lines
No EOL
11 KiB
C#

using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine.UIElements;
namespace Module.ProjectValidator.Editor
{
internal sealed class EditorProjectValidatorWindow : EditorWindow
{
private VisualElement _groupWarnings;
private Label _labelWarnings;
private VisualElement _groupErrors;
private Label _labelErrors;
private MultiColumnTreeView _treeView;
private string _searchFilter;
private readonly List<TreeViewItemData<Report.Entry>> _list = new();
private readonly List<TreeViewItemData<Report.Entry>> _filteredList = new();
public void CreateGUI()
{
var root = rootVisualElement;
var asset = EditorAssetUtility.LoadFirstAsset<VisualTreeAsset>("UxmlEditorProjectValidatorWindow");
root.styleSheets.Add(EditorAssetUtility.LoadFirstAsset<StyleSheet>("StyleSheetEditorProjectValidatorWindow"));
root.Add(asset.Instantiate());
_groupWarnings = root.Q<VisualElement>("status-warnings");
_labelWarnings = _groupWarnings.Q<Label>("label-warnings");
_groupErrors = root.Q<VisualElement>("status-errors");
_labelErrors = _groupErrors.Q<Label>("label-errors");
_groupWarnings.style.display = DisplayStyle.None;
_groupErrors.style.display = DisplayStyle.None;
root.Q<ToolbarButton>("button-run").clicked += OnToolbarButtonRunClicked;
root.Q<ToolbarButton>("button-clear").clicked += OnToolbarButtonClearClicked;
root.Q<ToolbarSearchField>().RegisterValueChangedCallback(OnToolbarSearchFieldChanged);
root.Q<ToolbarButton>("button-settings").clicked += OnToolbarButtonSettingsClicked;
_treeView = root.Q<MultiColumnTreeView>();
_treeView.columns["asset"].makeCell = CreateObjectField;
_treeView.columns["type"].makeCell = CreateLabel;
_treeView.columns["severity"].makeCell = CreateLabel;
_treeView.columns["severity-message"].makeCell = CreateLabel;
_treeView.columns["relative-path"].makeCell = CreateLabel;
_treeView.columns["field-path"].makeCell = CreateLabel;
_treeView.columns["asset"].bindCell = OnTreeViewBindCellAsset;
_treeView.columns["type"].bindCell = OnTreeViewBindCellType;
_treeView.columns["severity"].bindCell = OnTreeViewBindCellSeverity;
_treeView.columns["severity-message"].bindCell = OnTreeViewBindCellSeverityMessage;
_treeView.columns["relative-path"].bindCell = OnTreeViewBindCellRelativePath;
_treeView.columns["field-path"].bindCell = OnTreeViewBindCellFieldPath;
_treeView.columns["severity"].unbindCell = OnTreeViewUnbindCellSeverity;
_treeView.columns["asset"].comparison = OnTreeViewComparisonCellAsset;
_treeView.columns["type"].comparison = OnTreeViewComparisonCellType;
_treeView.columns["severity"].comparison = OnTreeViewComparisonCellSeverity;
_treeView.columns["severity-message"].comparison = OnTreeViewComparisonCellSeverityMessage;
_treeView.columns["relative-path"].comparison = OnTreeViewComparisonCellRelativePath;
_treeView.columns["field-path"].comparison = OnTreeViewComparisonCellFieldPath;
_treeView.selectionChanged += OnTreeViewSelectionChanged;
Rebuild();
}
public void Rebuild()
{
if (!Report.HasActive)
return;
_list.Clear();
var entries = Report.Active.Entries;
var warningCount = 0;
var errorCount = 0;
for (var i = 0; i < entries.Count; i++)
{
_list.Add(new TreeViewItemData<Report.Entry>(i, entries[i]));
if (entries[i].Severity == EValidatorSeverity.Warning)
warningCount++;
if (entries[i].Severity == EValidatorSeverity.Error)
errorCount++;
}
_groupWarnings.style.display = warningCount > 0 ? DisplayStyle.Flex : DisplayStyle.None;
_labelWarnings.text = warningCount.ToString();
_groupErrors.style.display = errorCount > 0 ? DisplayStyle.Flex : DisplayStyle.None;
_labelErrors.text = errorCount.ToString();
Filter();
}
public void Clear()
{
_list.Clear();
Filter();
}
private void Filter()
{
_treeView.Clear();
if (string.IsNullOrEmpty(_searchFilter))
{
_treeView.SetRootItems(_list);
}
else
{
_filteredList.Clear();
for (var i = 0; i < _list.Count; i++)
{
if (_list[i].data.Filter(_searchFilter))
_filteredList.Add(_list[i]);
}
_treeView.SetRootItems(_filteredList);
}
_treeView.Rebuild();
}
private static VisualElement CreateLabel()
{
var label = new Label();
label.AddToClassList("tree-view-label");
return label;
}
private static VisualElement CreateObjectField()
{
return new ObjectField
{
objectType = typeof(UnityEngine.Object),
allowSceneObjects = true,
label = string.Empty
};
}
private void OnToolbarButtonRunClicked()
{
if (!ValidatorRunner.Run())
EditorUtility.DisplayDialog("Project Validator", "Failed to run validators, due to either project in play mode or compiling", "Ok");
}
private void OnToolbarButtonClearClicked()
{
_groupWarnings.style.display = DisplayStyle.None;
_groupErrors.style.display = DisplayStyle.None;
ValidatorRunner.Clear();
}
private void OnToolbarButtonSettingsClicked()
{
SettingsService.OpenProjectSettings(ProjectValidatorSettings.MenuPath);
}
private void OnToolbarSearchFieldChanged(ChangeEvent<string> evt)
{
_searchFilter = evt.newValue;
Filter();
}
private void OnTreeViewBindCellAsset(VisualElement ve, int index)
{
var objectField = (ObjectField)ve;
var entry = _treeView.GetItemDataForIndex<Report.Entry>(index);
if (!entry.AssetGuid.Empty())
{
objectField.value = AssetDatabase.LoadAssetByGUID(entry.AssetGuid, typeof(UnityEngine.Object));
objectField.style.display = DisplayStyle.Flex;
}
else
{
objectField.style.display = DisplayStyle.None;
}
}
private void OnTreeViewBindCellType(VisualElement ve, int index)
{
var label = (Label)ve;
var entry = _treeView.GetItemDataForIndex<Report.Entry>(index);
label.text = entry.Type;
}
private void OnTreeViewBindCellSeverity(VisualElement ve, int index)
{
var label = (Label)ve;
var entry = _treeView.GetItemDataForIndex<Report.Entry>(index);
label.text = entry.SeverityStr;
label.AddToClassList(entry.SeverityStr.ToLower());
}
private void OnTreeViewBindCellSeverityMessage(VisualElement ve, int index)
{
var label = (Label)ve;
var entry = _treeView.GetItemDataForIndex<Report.Entry>(index);
label.text = entry.SeverityResult;
}
private void OnTreeViewBindCellRelativePath(VisualElement ve, int index)
{
var label = (Label)ve;
var entry = _treeView.GetItemDataForIndex<Report.Entry>(index);
label.text = entry.RelativePathRichText;
}
private void OnTreeViewBindCellFieldPath(VisualElement ve, int index)
{
var label = (Label)ve;
var entry = _treeView.GetItemDataForIndex<Report.Entry>(index);
label.text = entry.FieldPathRichText;
}
private void OnTreeViewUnbindCellSeverity(VisualElement ve, int index)
{
var label = (Label)ve;
label.RemoveFromClassList("error");
label.RemoveFromClassList("warning");
}
private int OnTreeViewComparisonCellAsset(int index0, int index1)
{
var entry0 = _treeView.GetItemDataForIndex<Report.Entry>(index0);
var entry1 = _treeView.GetItemDataForIndex<Report.Entry>(index1);
var assetName0 = EditorAssetUtility.GetAssetName(entry0.AssetGuid);
var assetName1 = EditorAssetUtility.GetAssetName(entry1.AssetGuid);
return string.Compare(assetName0, assetName1, StringComparison.Ordinal);
}
private int OnTreeViewComparisonCellType(int index0, int index1)
{
var entry0 = _treeView.GetItemDataForIndex<Report.Entry>(index0);
var entry1 = _treeView.GetItemDataForIndex<Report.Entry>(index1);
return string.Compare(entry0.Type, entry1.Type, StringComparison.Ordinal);
}
private int OnTreeViewComparisonCellSeverity(int index0, int index1)
{
var entry0 = _treeView.GetItemDataForIndex<Report.Entry>(index0);
var entry1 = _treeView.GetItemDataForIndex<Report.Entry>(index1);
return entry0.Severity.CompareTo(entry1.Severity);
}
private int OnTreeViewComparisonCellSeverityMessage(int index0, int index1)
{
var entry0 = _treeView.GetItemDataForIndex<Report.Entry>(index0);
var entry1 = _treeView.GetItemDataForIndex<Report.Entry>(index1);
return string.Compare(entry0.SeverityResult, entry1.SeverityResult, StringComparison.Ordinal);
}
private int OnTreeViewComparisonCellRelativePath(int index0, int index1)
{
var entry0 = _treeView.GetItemDataForIndex<Report.Entry>(index0);
var entry1 = _treeView.GetItemDataForIndex<Report.Entry>(index1);
return string.Compare(entry0.RelativePath, entry1.RelativePath, StringComparison.Ordinal);
}
private int OnTreeViewComparisonCellFieldPath(int index0, int index1)
{
var entry0 = _treeView.GetItemDataForIndex<Report.Entry>(index0);
var entry1 = _treeView.GetItemDataForIndex<Report.Entry>(index1);
return string.Compare(entry0.FieldPath, entry1.FieldPath, StringComparison.Ordinal);
}
private void OnTreeViewSelectionChanged(IEnumerable<object> selection)
{
foreach (var obj in selection)
{
if (obj is Report.Entry entry)
ProjectValidatorUtility.PingObject(entry);
}
}
}
}