1
0
mirror of https://github.com/maxartz15/Validator.git synced 2025-07-04 14:36:05 +02:00

Compare commits

...

7 Commits

Author SHA1 Message Date
max
5b70e24c32 Changed naming and tabs 2022-07-21 02:03:11 +02:00
max
15808ce035 Changed MenuName of attribute validators 2022-05-07 02:02:33 +02:00
max
8399d043f5 Update RequiredAttributeValidator
Fix required attribute validator by adding flags when getting the fields.
2022-05-04 00:39:01 +02:00
max
b4dd8744df Fix attribute 2022-05-03 21:11:12 +02:00
max
b13cf47fbf Update README.md 2022-01-02 15:21:39 +01:00
max
9c01bed215 Update README.md 2022-01-01 20:33:46 +01:00
max
74fd067220 Required Attribute Validator 2021-12-29 23:46:52 +01:00
18 changed files with 581 additions and 425 deletions

View File

@ -1,4 +1,12 @@
# Change Log: # Change Log:
## 0.1.4
- Fix attribute validator..?
## 0.1.3
- Fix attribute validator..?
## 0.1.2
- ...
## 0.1.1
- First prototype of Attribute validator.
## 0.1.1 ## 0.1.1
- Search input. - Search input.
- GUI toolbar. - GUI toolbar.

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

View File

@ -1,7 +1,8 @@
namespace Validator.Editor namespace Validator.Editor
{ {
public interface IValidator public interface IValidator
{ {
public Report Validate(); public string MenuName { get; }
} public Report Validate();
}
} }

View File

@ -8,432 +8,432 @@ using Object = UnityEngine.Object;
namespace Validator.Editor namespace Validator.Editor
{ {
public class ValidatorEditorWindow : EditorWindow public class ValidatorEditorWindow : EditorWindow
{ {
private class ValidatorInfo private class ValidatorInfo
{ {
public IValidator validator = null; public IValidator validator = null;
public bool isEnabled = true; public bool isEnabled = true;
public ValidatorInfo(IValidator validator) public ValidatorInfo(IValidator validator)
{ {
this.validator = validator; this.validator = validator;
} }
} }
private class ReportStats private class ReportStats
{ {
public int infoCount = 0; public int infoCount = 0;
public int warningCount = 0; public int warningCount = 0;
public int errorCount = 0; public int errorCount = 0;
} }
private class Settings private class Settings
{ {
public bool showInfo = true; public bool showInfo = true;
public bool showWarning = true; public bool showWarning = true;
public bool showError = true; public bool showError = true;
public string searchInput = ""; public string searchInput = "";
public readonly Color lightColor = new Color(0.25f, 0.25f, 0.25f, 1); public readonly Color lightColor = new Color(0.25f, 0.25f, 0.25f, 1);
public readonly Color darkColor = new Color(0.22f, 0.22f, 0.22f, 1); public readonly Color darkColor = new Color(0.22f, 0.22f, 0.22f, 1);
} }
private static readonly List<ValidatorInfo> validators = new List<ValidatorInfo>(); private static readonly List<ValidatorInfo> validators = new List<ValidatorInfo>();
private static readonly List<Report> reports = new List<Report>(); private static readonly List<Report> reports = new List<Report>();
private static readonly Settings settings = new Settings(); private static readonly Settings settings = new Settings();
private static ReportStats reportStats = new ReportStats(); private static ReportStats reportStats = new ReportStats();
private MultiColumnHeaderState multiColumnHeaderState; private MultiColumnHeaderState multiColumnHeaderState;
private MultiColumnHeader multiColumnHeader; private MultiColumnHeader multiColumnHeader;
private MultiColumnHeaderState.Column[] columns; private MultiColumnHeaderState.Column[] columns;
private Vector2 scrollPosition; private Vector2 scrollPosition;
private float multiColumnHeaderWidth; private float multiColumnHeaderWidth;
private float rows; private float rows;
[MenuItem("Window/General/Validator")] [MenuItem("Window/General/Validator")]
private static void Init() private static void Init()
{ {
ValidatorEditorWindow window = (ValidatorEditorWindow)GetWindow(typeof(ValidatorEditorWindow)); ValidatorEditorWindow window = (ValidatorEditorWindow)GetWindow(typeof(ValidatorEditorWindow));
window.titleContent = new GUIContent("Validator", EditorGUIUtility.IconContent("d_UnityEditor.ConsoleWindow").image); window.titleContent = new GUIContent("Validator", EditorGUIUtility.IconContent("d_UnityEditor.ConsoleWindow").image);
window.Show(); window.Show();
window.LoadValidators(); window.LoadValidators();
} }
private void OnGUI() private void OnGUI()
{
using (new EditorGUILayout.VerticalScope(GUILayout.ExpandWidth(true), GUILayout.ExpandHeight(true)))
{
DrawMenu();
GUILayout.Space(EditorGUIUtility.standardVerticalSpacing);
DrawMultiColumnScope();
}
}
private void InitializeMultiColumn()
{ {
columns = new MultiColumnHeaderState.Column[] using (new EditorGUILayout.VerticalScope(GUILayout.ExpandWidth(true), GUILayout.ExpandHeight(true)))
{ {
new MultiColumnHeaderState.Column() DrawMenu();
{ GUILayout.Space(EditorGUIUtility.standardVerticalSpacing);
allowToggleVisibility = false, // At least one column must be there. DrawMultiColumnScope();
autoResize = false, }
width = 36f, }
minWidth = 36f,
maxWidth = 36f,
canSort = false,
sortingArrowAlignment = TextAlignment.Right,
headerContent = EditorGUIUtility.IconContent("d_console.erroricon.inactive.sml", "Warning Type."),
headerTextAlignment = TextAlignment.Center,
},
new MultiColumnHeaderState.Column()
{
allowToggleVisibility = true,
autoResize = false,
width = 36f,
minWidth = 36f,
maxWidth = 36f,
canSort = false,
sortingArrowAlignment = TextAlignment.Right,
headerContent = EditorGUIUtility.IconContent("Animation.FilterBySelection", "Target Objects"),
headerTextAlignment = TextAlignment.Center,
},
new MultiColumnHeaderState.Column()
{
allowToggleVisibility = true,
autoResize = true,
width = 75.0f,
minWidth = 75.0f,
canSort = false,
sortingArrowAlignment = TextAlignment.Right,
headerContent = new GUIContent("Category", "Warning Category."),
headerTextAlignment = TextAlignment.Center,
},
new MultiColumnHeaderState.Column()
{
allowToggleVisibility = true,
autoResize = true,
width = 200.0f,
minWidth = 200.0f,
canSort = false,
sortingArrowAlignment = TextAlignment.Right,
headerContent = new GUIContent("Message", "Warning Message."),
headerTextAlignment = TextAlignment.Center,
},
new MultiColumnHeaderState.Column()
{
allowToggleVisibility = true,
autoResize = true,
width = 200.0f,
minWidth = 200.0f,
canSort = false,
sortingArrowAlignment = TextAlignment.Right,
headerContent = new GUIContent("Solution", "Warning Solution."),
headerTextAlignment = TextAlignment.Center,
},
};
multiColumnHeaderState = new MultiColumnHeaderState(columns); private void InitializeMultiColumn()
multiColumnHeader = new MultiColumnHeader(multiColumnHeaderState);
multiColumnHeader.ResizeToFit();
}
private void DrawMenu()
{ {
using (new EditorGUILayout.HorizontalScope(EditorStyles.toolbar)) columns = new MultiColumnHeaderState.Column[]
{ {
if (GUILayout.Button(EditorGUIUtility.IconContent("Refresh", "Refresh"), EditorStyles.toolbarButton)) new MultiColumnHeaderState.Column()
{ {
LoadValidators(); allowToggleVisibility = false, // At least one column must be there.
} autoResize = false,
width = 36f,
minWidth = 36f,
maxWidth = 36f,
canSort = false,
sortingArrowAlignment = TextAlignment.Right,
headerContent = EditorGUIUtility.IconContent("d_console.erroricon.inactive.sml", "Warning Type."),
headerTextAlignment = TextAlignment.Center,
},
new MultiColumnHeaderState.Column()
{
allowToggleVisibility = true,
autoResize = false,
width = 36f,
minWidth = 36f,
maxWidth = 36f,
canSort = false,
sortingArrowAlignment = TextAlignment.Right,
headerContent = EditorGUIUtility.IconContent("Animation.FilterBySelection", "Target Objects"),
headerTextAlignment = TextAlignment.Center,
},
new MultiColumnHeaderState.Column()
{
allowToggleVisibility = true,
autoResize = true,
width = 75.0f,
minWidth = 75.0f,
canSort = false,
sortingArrowAlignment = TextAlignment.Right,
headerContent = new GUIContent("Category", "Warning Category."),
headerTextAlignment = TextAlignment.Center,
},
new MultiColumnHeaderState.Column()
{
allowToggleVisibility = true,
autoResize = true,
width = 200.0f,
minWidth = 200.0f,
canSort = false,
sortingArrowAlignment = TextAlignment.Right,
headerContent = new GUIContent("Message", "Warning Message."),
headerTextAlignment = TextAlignment.Center,
},
new MultiColumnHeaderState.Column()
{
allowToggleVisibility = true,
autoResize = true,
width = 200.0f,
minWidth = 200.0f,
canSort = false,
sortingArrowAlignment = TextAlignment.Right,
headerContent = new GUIContent("Solution", "Warning Solution."),
headerTextAlignment = TextAlignment.Center,
},
};
multiColumnHeaderState = new MultiColumnHeaderState(columns);
multiColumnHeader = new MultiColumnHeader(multiColumnHeaderState);
multiColumnHeader.ResizeToFit();
}
private void DrawMenu()
{
using (new EditorGUILayout.HorizontalScope(EditorStyles.toolbar))
{
if (GUILayout.Button(EditorGUIUtility.IconContent("Refresh", "Refresh"), EditorStyles.toolbarButton))
{
LoadValidators();
}
if (GUILayout.Button(EditorGUIUtility.IconContent("d_Settings", "Select validator"), EditorStyles.toolbarButton)) if (GUILayout.Button(EditorGUIUtility.IconContent("d_Settings", "Select validator"), EditorStyles.toolbarButton))
{ {
GenericMenu validatorOptionsMenu = new GenericMenu(); GenericMenu validatorOptionsMenu = new GenericMenu();
validatorOptionsMenu.AddItem(new GUIContent($"All"), false, OnValidatorInfoVisibilityAllEvent); validatorOptionsMenu.AddItem(new GUIContent($"All"), false, OnValidatorInfoVisibilityAllEvent);
validatorOptionsMenu.AddItem(new GUIContent($"None"), false, OnValidatorInfoVisibilityNoneEvent); validatorOptionsMenu.AddItem(new GUIContent($"None"), false, OnValidatorInfoVisibilityNoneEvent);
validatorOptionsMenu.AddSeparator(""); validatorOptionsMenu.AddSeparator("");
foreach (ValidatorInfo validatorInfo in validators) foreach (ValidatorInfo validatorInfo in validators)
{ {
validatorOptionsMenu.AddItem(new GUIContent($"{validatorInfo.validator.GetType().Name}"), validatorInfo.isEnabled, OnValidatorInfoVisibilityChangedEvent, validatorInfo); validatorOptionsMenu.AddItem(new GUIContent($"{validatorInfo.validator.MenuName}"), validatorInfo.isEnabled, OnValidatorInfoVisibilityChangedEvent, validatorInfo);
} }
validatorOptionsMenu.ShowAsContext(); validatorOptionsMenu.ShowAsContext();
} }
if (GUILayout.Button(EditorGUIUtility.IconContent("PlayButton", "Run all"), EditorStyles.toolbarButton)) if (GUILayout.Button(EditorGUIUtility.IconContent("PlayButton", "Run all"), EditorStyles.toolbarButton))
{
RunValidators();
UpdateStats();
}
GUILayout.FlexibleSpace();
settings.searchInput = GUILayout.TextField(settings.searchInput, EditorStyles.toolbarSearchField, GUILayout.MaxWidth(300));
if(reportStats != null)
{ {
settings.showInfo = GUILayout.Toggle(settings.showInfo, new GUIContent($"{reportStats.infoCount}", EditorGUIUtility.IconContent(GetWarningIconName(WarningType.Info)).image), EditorStyles.toolbarButton); RunValidators();
settings.showWarning = GUILayout.Toggle(settings.showWarning, new GUIContent($"{reportStats.warningCount}", EditorGUIUtility.IconContent(GetWarningIconName(WarningType.Warning)).image), EditorStyles.toolbarButton); UpdateStats();
settings.showError = GUILayout.Toggle(settings.showError, new GUIContent($"{reportStats.errorCount}", EditorGUIUtility.IconContent(GetWarningIconName(WarningType.Error)).image), EditorStyles.toolbarButton);
} }
}
}
private void DrawMultiColumnScope() GUILayout.FlexibleSpace();
{
//GUILayout.FlexibleSpace(); // If nothing has been drawn yet, uncomment this because GUILayoutUtility.GetLastRect() needs it.
Rect windowRect = GUILayoutUtility.GetLastRect();
windowRect.width = position.width;
windowRect.height = position.height;
if (multiColumnHeader == null) settings.searchInput = GUILayout.TextField(settings.searchInput, EditorStyles.toolbarSearchField, GUILayout.MaxWidth(300));
{
InitializeMultiColumn();
}
float columnHeight = EditorGUIUtility.singleLineHeight * 2; if(reportStats != null)
{
settings.showInfo = GUILayout.Toggle(settings.showInfo, new GUIContent($"{reportStats.infoCount}", EditorGUIUtility.IconContent(GetWarningIconName(WarningType.Info)).image), EditorStyles.toolbarButton);
settings.showWarning = GUILayout.Toggle(settings.showWarning, new GUIContent($"{reportStats.warningCount}", EditorGUIUtility.IconContent(GetWarningIconName(WarningType.Warning)).image), EditorStyles.toolbarButton);
settings.showError = GUILayout.Toggle(settings.showError, new GUIContent($"{reportStats.errorCount}", EditorGUIUtility.IconContent(GetWarningIconName(WarningType.Error)).image), EditorStyles.toolbarButton);
}
}
}
Rect headerRect = new Rect(windowRect) private void DrawMultiColumnScope()
{ {
height = EditorGUIUtility.singleLineHeight, //GUILayout.FlexibleSpace(); // If nothing has been drawn yet, uncomment this because GUILayoutUtility.GetLastRect() needs it.
}; Rect windowRect = GUILayoutUtility.GetLastRect();
windowRect.width = position.width;
windowRect.height = position.height;
Rect scrollViewPositionRect = GUILayoutUtility.GetRect(0, float.MaxValue, 0, float.MaxValue); if (multiColumnHeader == null)
scrollViewPositionRect.y += headerRect.height - EditorGUIUtility.standardVerticalSpacing;
scrollViewPositionRect.height -= headerRect.height - EditorGUIUtility.standardVerticalSpacing;
Rect scrollViewRect = new Rect(windowRect)
{
width = multiColumnHeaderState.widthOfAllVisibleColumns,
height = rows * columnHeight
};
Rect rowRect = new Rect(windowRect)
{
width = multiColumnHeaderWidth,
height = columnHeight,
};
// Draw column header.
multiColumnHeader.OnGUI(headerRect, scrollPosition.x);
// Draw scroll view.
using (GUI.ScrollViewScope scope = new GUI.ScrollViewScope(scrollViewPositionRect, scrollPosition, scrollViewRect, false, false))
{ {
scrollPosition = scope.scrollPosition; InitializeMultiColumn();
multiColumnHeaderWidth = Mathf.Max(scrollViewPositionRect.width + scrollPosition.x, multiColumnHeaderWidth); }
rows = 0; float columnHeight = EditorGUIUtility.singleLineHeight * 2;
for (int i = 0; i < reports.Count; i++)
{ Rect headerRect = new Rect(windowRect)
for (int j = 0; j < reports[i].Reports.Count; j++) {
{ height = EditorGUIUtility.singleLineHeight,
// Type filter. };
Rect scrollViewPositionRect = GUILayoutUtility.GetRect(0, float.MaxValue, 0, float.MaxValue);
scrollViewPositionRect.y += headerRect.height - EditorGUIUtility.standardVerticalSpacing;
scrollViewPositionRect.height -= headerRect.height - EditorGUIUtility.standardVerticalSpacing;
Rect scrollViewRect = new Rect(windowRect)
{
width = multiColumnHeaderState.widthOfAllVisibleColumns,
height = rows * columnHeight
};
Rect rowRect = new Rect(windowRect)
{
width = multiColumnHeaderWidth,
height = columnHeight,
};
// Draw column header.
multiColumnHeader.OnGUI(headerRect, scrollPosition.x);
// Draw scroll view.
using (GUI.ScrollViewScope scope = new GUI.ScrollViewScope(scrollViewPositionRect, scrollPosition, scrollViewRect, false, false))
{
scrollPosition = scope.scrollPosition;
multiColumnHeaderWidth = Mathf.Max(scrollViewPositionRect.width + scrollPosition.x, multiColumnHeaderWidth);
rows = 0;
for (int i = 0; i < reports.Count; i++)
{
for (int j = 0; j < reports[i].Reports.Count; j++)
{
// Type filter.
switch (reports[i].Reports[j].WarningType) switch (reports[i].Reports[j].WarningType)
{ {
case WarningType.Info: case WarningType.Info:
if (!settings.showInfo) if (!settings.showInfo)
continue; continue;
break; break;
case WarningType.Warning: case WarningType.Warning:
if (!settings.showWarning) if (!settings.showWarning)
continue; continue;
break; break;
case WarningType.Error: case WarningType.Error:
if (!settings.showError) if (!settings.showError)
continue; continue;
break; break;
default: default:
break; break;
} }
// Search filter. // Search filter.
if (!string.IsNullOrWhiteSpace(settings.searchInput)) if (!string.IsNullOrWhiteSpace(settings.searchInput))
{ {
if (!reports[i].Reports[j].Category.Contains(settings.searchInput) && !reports[i].Reports[j].Message.Contains(settings.searchInput) && !reports[i].Reports[j].Solution.Contains(settings.searchInput)) if (!reports[i].Reports[j].Category.Contains(settings.searchInput) && !reports[i].Reports[j].Message.Contains(settings.searchInput) && !reports[i].Reports[j].Solution.Contains(settings.searchInput))
{ {
continue; continue;
} }
} }
// Only draw what is visible within the view. // Only draw what is visible within the view.
if (rowRect.yMax > windowRect.y + scrollPosition.y && rowRect.yMin < windowRect.height + scrollPosition.y) if (rowRect.yMax > windowRect.y + scrollPosition.y && rowRect.yMin < windowRect.height + scrollPosition.y)
{ {
if (rows % 2 == 0) if (rows % 2 == 0)
{ {
EditorGUI.DrawRect(rowRect, settings.darkColor); EditorGUI.DrawRect(rowRect, settings.darkColor);
} }
else else
{ {
EditorGUI.DrawRect(rowRect, settings.lightColor); EditorGUI.DrawRect(rowRect, settings.lightColor);
} }
// Warning Field. // Warning Field.
int columnIndex = 0; int columnIndex = 0;
if (multiColumnHeader.IsColumnVisible(columnIndex)) if (multiColumnHeader.IsColumnVisible(columnIndex))
{ {
int visibleColumnIndex = multiColumnHeader.GetVisibleColumnIndex(columnIndex); int visibleColumnIndex = multiColumnHeader.GetVisibleColumnIndex(columnIndex);
Rect columnRect = multiColumnHeader.GetColumnRect(visibleColumnIndex); Rect columnRect = multiColumnHeader.GetColumnRect(visibleColumnIndex);
columnRect.y = rowRect.y; columnRect.y = rowRect.y;
columnRect.height = rowRect.height; columnRect.height = rowRect.height;
Rect labelFieldRect = multiColumnHeader.GetCellRect(visibleColumnIndex, columnRect); Rect labelFieldRect = multiColumnHeader.GetCellRect(visibleColumnIndex, columnRect);
labelFieldRect.x += 9; labelFieldRect.x += 9;
labelFieldRect.width -= 9; labelFieldRect.width -= 9;
EditorGUI.LabelField( EditorGUI.LabelField(
labelFieldRect, labelFieldRect,
EditorGUIUtility.IconContent(GetWarningIconName(reports[i].Reports[j].WarningType), $"{reports[i].Reports[j].WarningType}") EditorGUIUtility.IconContent(GetWarningIconName(reports[i].Reports[j].WarningType), $"{reports[i].Reports[j].WarningType}")
); );
} }
// Target Field. // Target Field.
columnIndex = 1; columnIndex = 1;
if (multiColumnHeader.IsColumnVisible(columnIndex)) if (multiColumnHeader.IsColumnVisible(columnIndex))
{ {
int visibleColumnIndex = multiColumnHeader.GetVisibleColumnIndex(columnIndex); int visibleColumnIndex = multiColumnHeader.GetVisibleColumnIndex(columnIndex);
Rect columnRect = multiColumnHeader.GetColumnRect(visibleColumnIndex); Rect columnRect = multiColumnHeader.GetColumnRect(visibleColumnIndex);
columnRect.y = rowRect.y; columnRect.y = rowRect.y;
columnRect.height = rowRect.height; columnRect.height = rowRect.height;
if(reports[i].Reports[j].Target != null) if(reports[i].Reports[j].Target != null)
{ {
if (GUI.Button( if (GUI.Button(
multiColumnHeader.GetCellRect(visibleColumnIndex, columnRect), multiColumnHeader.GetCellRect(visibleColumnIndex, columnRect),
EditorGUIUtility.IconContent("Animation.FilterBySelection", "Ping Object") EditorGUIUtility.IconContent("Animation.FilterBySelection", "Ping Object")
)) ))
{ {
Selection.objects = new Object[] { reports[i].Reports[j].Target }; Selection.objects = new Object[] { reports[i].Reports[j].Target };
if (!Selection.activeObject) if (!Selection.activeObject)
{ {
Debug.Log($"{nameof(Selection.activeObject)} is null."); Debug.Log($"{nameof(Selection.activeObject)} is null.");
continue; continue;
} }
foreach (Object o in Selection.objects) foreach (Object o in Selection.objects)
{ {
EditorGUIUtility.PingObject(o); EditorGUIUtility.PingObject(o);
} }
} }
} }
} }
// Category Field. // Category Field.
columnIndex = 2; columnIndex = 2;
if (multiColumnHeader.IsColumnVisible(columnIndex)) if (multiColumnHeader.IsColumnVisible(columnIndex))
{ {
int visibleColumnIndex = multiColumnHeader.GetVisibleColumnIndex(columnIndex); int visibleColumnIndex = multiColumnHeader.GetVisibleColumnIndex(columnIndex);
Rect columnRect = multiColumnHeader.GetColumnRect(visibleColumnIndex); Rect columnRect = multiColumnHeader.GetColumnRect(visibleColumnIndex);
columnRect.y = rowRect.y; columnRect.y = rowRect.y;
columnRect.height = rowRect.height; columnRect.height = rowRect.height;
Rect labelFieldRect = multiColumnHeader.GetCellRect(visibleColumnIndex, columnRect); Rect labelFieldRect = multiColumnHeader.GetCellRect(visibleColumnIndex, columnRect);
labelFieldRect.x += 7; labelFieldRect.x += 7;
labelFieldRect.width -= 7; labelFieldRect.width -= 7;
EditorGUI.LabelField( EditorGUI.LabelField(
labelFieldRect, labelFieldRect,
new GUIContent($"{reports[i].Reports[j].Category}") new GUIContent($"{reports[i].Reports[j].Category}")
); );
} }
// Message Field. // Message Field.
columnIndex = 3; columnIndex = 3;
if (multiColumnHeader.IsColumnVisible(columnIndex)) if (multiColumnHeader.IsColumnVisible(columnIndex))
{ {
int visibleColumnIndex = multiColumnHeader.GetVisibleColumnIndex(columnIndex); int visibleColumnIndex = multiColumnHeader.GetVisibleColumnIndex(columnIndex);
Rect columnRect = multiColumnHeader.GetColumnRect(visibleColumnIndex); Rect columnRect = multiColumnHeader.GetColumnRect(visibleColumnIndex);
columnRect.y = rowRect.y; columnRect.y = rowRect.y;
columnRect.height = rowRect.height; columnRect.height = rowRect.height;
Rect labelFieldRect = multiColumnHeader.GetCellRect(visibleColumnIndex, columnRect); Rect labelFieldRect = multiColumnHeader.GetCellRect(visibleColumnIndex, columnRect);
labelFieldRect.x += 7; labelFieldRect.x += 7;
labelFieldRect.width -= 7; labelFieldRect.width -= 7;
EditorGUI.LabelField( EditorGUI.LabelField(
labelFieldRect, labelFieldRect,
new GUIContent($"{reports[i].Reports[j].Message}") new GUIContent($"{reports[i].Reports[j].Message}")
); );
} }
// Solution Field. // Solution Field.
columnIndex = 4; columnIndex = 4;
if (multiColumnHeader.IsColumnVisible(columnIndex)) if (multiColumnHeader.IsColumnVisible(columnIndex))
{ {
int visibleColumnIndex = multiColumnHeader.GetVisibleColumnIndex(columnIndex); int visibleColumnIndex = multiColumnHeader.GetVisibleColumnIndex(columnIndex);
Rect columnRect = multiColumnHeader.GetColumnRect(visibleColumnIndex); Rect columnRect = multiColumnHeader.GetColumnRect(visibleColumnIndex);
columnRect.y = rowRect.y; columnRect.y = rowRect.y;
columnRect.height = rowRect.height; columnRect.height = rowRect.height;
Rect labelFieldRect = multiColumnHeader.GetCellRect(visibleColumnIndex, columnRect); Rect labelFieldRect = multiColumnHeader.GetCellRect(visibleColumnIndex, columnRect);
labelFieldRect.x += 7; labelFieldRect.x += 7;
labelFieldRect.width -= 7; labelFieldRect.width -= 7;
EditorGUI.LabelField( EditorGUI.LabelField(
labelFieldRect, labelFieldRect,
new GUIContent($"{reports[i].Reports[j].Solution}") new GUIContent($"{reports[i].Reports[j].Solution}")
); );
} }
} }
rowRect.y += columnHeight; rowRect.y += columnHeight;
rows++; rows++;
} }
} }
scope.handleScrollWheel = true; scope.handleScrollWheel = true;
}
}
private void LoadValidators()
{
for (int i = validators.Count - 1; i >= 0; i--)
{
if (validators[i].validator == null)
{
validators.RemoveAt(i);
}
}
foreach (Type type in GetValidatorTypes())
{
bool hasValidator = false;
foreach (ValidatorInfo validatorInfo in validators)
{
if (validatorInfo.validator.GetType() == type)
{
hasValidator = true;
}
}
if (!hasValidator)
{
IValidator validator = (IValidator)Activator.CreateInstance(type);
if (validator != null)
{
validators.Add(new ValidatorInfo(validator));
}
}
}
}
private void RunValidators()
{
reports.Clear();
foreach (ValidatorInfo validatorInfo in validators)
{
if (validatorInfo.isEnabled)
{
reports.Add(validatorInfo.validator.Validate());
}
} }
} }
private void UpdateStats() private void LoadValidators()
{ {
reportStats = new ReportStats(); for (int i = validators.Count - 1; i >= 0; i--)
{
if (validators[i].validator == null)
{
validators.RemoveAt(i);
}
}
foreach (Type type in GetValidatorTypes())
{
bool hasValidator = false;
foreach (ValidatorInfo validatorInfo in validators)
{
if (validatorInfo.validator.GetType() == type)
{
hasValidator = true;
}
}
if (!hasValidator)
{
IValidator validator = (IValidator)Activator.CreateInstance(type);
if (validator != null)
{
validators.Add(new ValidatorInfo(validator));
}
}
}
}
private void RunValidators()
{
reports.Clear();
foreach (ValidatorInfo validatorInfo in validators)
{
if (validatorInfo.isEnabled)
{
reports.Add(validatorInfo.validator.Validate());
}
}
}
private void UpdateStats()
{
reportStats = new ReportStats();
foreach (Report report in reports) foreach (Report report in reports)
{ {
@ -442,7 +442,7 @@ namespace Validator.Editor
switch (report.Reports[i].WarningType) switch (report.Reports[i].WarningType)
{ {
case WarningType.Info: case WarningType.Info:
reportStats.infoCount++; reportStats.infoCount++;
break; break;
case WarningType.Warning: case WarningType.Warning:
reportStats.warningCount++; reportStats.warningCount++;
@ -451,26 +451,26 @@ namespace Validator.Editor
reportStats.errorCount++; reportStats.errorCount++;
break; break;
default: default:
break; break;
} }
} }
} }
} }
private void OnValidatorInfoVisibilityChangedEvent(object info) private void OnValidatorInfoVisibilityChangedEvent(object info)
{ {
if(info is ValidatorInfo validatorInfo) if(info is ValidatorInfo validatorInfo)
{ {
validatorInfo.isEnabled = !validatorInfo.isEnabled; validatorInfo.isEnabled = !validatorInfo.isEnabled;
} }
} }
private void OnValidatorInfoVisibilityAllEvent() private void OnValidatorInfoVisibilityAllEvent()
{ {
foreach (ValidatorInfo validatorInfo in validators) foreach (ValidatorInfo validatorInfo in validators)
{ {
validatorInfo.isEnabled = true; validatorInfo.isEnabled = true;
} }
} }
private void OnValidatorInfoVisibilityNoneEvent() private void OnValidatorInfoVisibilityNoneEvent()
@ -483,10 +483,10 @@ namespace Validator.Editor
private static Type[] GetValidatorTypes() private static Type[] GetValidatorTypes()
{ {
return TypeCache.GetTypesDerivedFrom<IValidator>().ToArray(); return TypeCache.GetTypesDerivedFrom<IValidator>().ToArray();
} }
private static string GetWarningIconName(WarningType warningType) private static string GetWarningIconName(WarningType warningType)
{ {
return warningType switch return warningType switch
{ {

View File

@ -0,0 +1,79 @@
using System.Linq;
using System.Reflection;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
namespace Validator.Editor
{
public class RequiredAttributeAssetValidator : IValidator
{
public string MenuName => nameof(RequiredAttributeAssetValidator);
private const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
public Report Validate()
{
Report report = new Report(nameof(RequiredAttributeAssetValidator));
List<Object> objects = ValidatableAssetValidator.FindAssetsByType<Object>();
for (int i = 0; i < objects.Count; i++)
{
EditorUtility.DisplayProgressBar("RequiredAttributeAssetValidator", "RequiredAttribute...", (float)i / objects.Count);
IEnumerable<(FieldInfo FieldInfo, RequiredAttribute Attribute)> fieldsWithRequiredAttribute = from fi in objects[i].GetType().GetFields(flags)
let attr = fi.GetCustomAttributes(typeof(RequiredAttribute), true)
where attr.Length == 1
select (FieldInfo: fi, Attribute: attr.First() as RequiredAttribute);
foreach ((FieldInfo FieldInfo, RequiredAttribute Attribute) field in fieldsWithRequiredAttribute)
{
object o = field.FieldInfo.GetValue(objects[i]);
if (o == null || o.Equals(null))
{
report.Log(objects[i], field.Attribute.WarningType, field.Attribute.Category, $"{field.FieldInfo.Name} is null", $"Assign {field.FieldInfo.FieldType}");
}
}
}
EditorUtility.ClearProgressBar();
return report;
}
}
public class RequiredAttributeSceneValidator : IValidator
{
public string MenuName => nameof(RequiredAttributeSceneValidator);
private const BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
public Report Validate()
{
Report report = new Report(nameof(RequiredAttributeSceneValidator));
List<MonoBehaviour> objects = ValidatableSceneValidator.FindAllObjectsOfType<MonoBehaviour>();
for (int i = 0; i < objects.Count; i++)
{
EditorUtility.DisplayProgressBar("RequiredAttributeSceneValidator", "RequiredAttribute...", (float)i / objects.Count);
IEnumerable<(FieldInfo FieldInfo, RequiredAttribute Attribute)> fieldsWithRequiredAttribute = from fi in objects[i].GetType().GetFields(flags)
let attr = fi.GetCustomAttributes(typeof(RequiredAttribute), true)
where attr.Length == 1
select (FieldInfo: fi, Attribute: attr.First() as RequiredAttribute);
foreach ((FieldInfo FieldInfo, RequiredAttribute Attribute) field in fieldsWithRequiredAttribute)
{
object o = field.FieldInfo.GetValue(objects[i]);
if (o == null || o.Equals(null))
{
report.Log(objects[i], field.Attribute.WarningType, field.Attribute.Category, $"{field.FieldInfo.Name} is null", $"Assign {field.FieldInfo.FieldType}");
}
}
}
EditorUtility.ClearProgressBar();
return report;
}
}
}

View File

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

View File

@ -1,55 +0,0 @@
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.SceneManagement;
namespace Validator.Editor
{
public class SceneValidator : IValidator
{
public Report Validate()
{
Report report = new Report("SceneValidator");
List<IValidatable> objects = FindAllObjectsOfType<IValidatable>();
for (int i = 0; i < objects.Count; i++)
{
EditorUtility.DisplayProgressBar("SceneValidator", "Validate...", (float)i / objects.Count);
objects[i].Validate(report);
}
EditorUtility.ClearProgressBar();
return report;
}
private static List<GameObject> GetAllRootGameObjects()
{
List<GameObject> gameObjects = new List<GameObject>();
for (int i = 0; i < SceneManager.sceneCount; i++)
{
EditorUtility.DisplayProgressBar("SceneValidator", "GetAllRootGameObjects...", (float)i / SceneManager.sceneCount);
gameObjects.AddRange(SceneManager.GetSceneAt(i).GetRootGameObjects());
}
EditorUtility.ClearProgressBar();
return gameObjects;
}
private static List<T> FindAllObjectsOfType<T>()
{
List<T> objects = new List<T>();
List<GameObject> gameObjects = GetAllRootGameObjects();
for (int i = 0; i < gameObjects.Count; i++)
{
EditorUtility.DisplayProgressBar("SceneValidator", "FindAllObjectsOfType...", (float)i / gameObjects.Count);
objects.AddRange(gameObjects[i].GetComponentsInChildren<T>(true));
}
EditorUtility.ClearProgressBar();
return objects;
}
}
}

View File

@ -4,11 +4,13 @@ using UnityEngine;
namespace Validator.Editor namespace Validator.Editor
{ {
public class AssetValidator : IValidator public class ValidatableAssetValidator : IValidator
{ {
public string MenuName => nameof(ValidatableAssetValidator);
public Report Validate() public Report Validate()
{ {
Report report = new Report("AssetValidator"); Report report = new Report(nameof(ValidatableAssetValidator));
List<Object> objects = FindAssetsByType<Object>(); List<Object> objects = FindAssetsByType<Object>();
for (int i = 0; i < objects.Count; i++) for (int i = 0; i < objects.Count; i++)

View File

@ -0,0 +1,57 @@
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.SceneManagement;
namespace Validator.Editor
{
public class ValidatableSceneValidator : IValidator
{
public string MenuName => nameof(ValidatableSceneValidator);
public Report Validate()
{
Report report = new Report(nameof(ValidatableSceneValidator));
List<IValidatable> objects = FindAllObjectsOfType<IValidatable>();
for (int i = 0; i < objects.Count; i++)
{
EditorUtility.DisplayProgressBar("SceneValidator", "Validate...", (float)i / objects.Count);
objects[i].Validate(report);
}
EditorUtility.ClearProgressBar();
return report;
}
private static List<GameObject> GetAllRootGameObjects()
{
List<GameObject> gameObjects = new List<GameObject>();
for (int i = 0; i < SceneManager.sceneCount; i++)
{
EditorUtility.DisplayProgressBar("SceneValidator", "GetAllRootGameObjects...", (float)i / SceneManager.sceneCount);
gameObjects.AddRange(SceneManager.GetSceneAt(i).GetRootGameObjects());
}
EditorUtility.ClearProgressBar();
return gameObjects;
}
public static List<T> FindAllObjectsOfType<T>()
{
List<T> objects = new List<T>();
List<GameObject> gameObjects = GetAllRootGameObjects();
for (int i = 0; i < gameObjects.Count; i++)
{
EditorUtility.DisplayProgressBar("SceneValidator", "FindAllObjectsOfType...", (float)i / gameObjects.Count);
objects.AddRange(gameObjects[i].GetComponentsInChildren<T>(true));
}
EditorUtility.ClearProgressBar();
return objects;
}
}
}

View File

@ -1,12 +1,11 @@
# Validator # Validator
![ValidatorWindow](Documentation~/Images/ValidatorWindow_01.png)
Unity project validator framework. Unity project validator framework.
## Getting Started ## Getting Started
Open Validator Window: Add a custom validate check using the `IValidatable` interface:
> Window -> General -> Validator
Add validatable:
```C# ```C#
using Validator; using Validator;
@ -17,10 +16,10 @@ public class MyBehaviour : MonoBehaviour, IValidatable
#if UNITY_EDITOR #if UNITY_EDITOR
public void Validate(Report report) public void Validate(Report report)
{ {
// Check if health is valid. // Check if health is valid.
if(startHealth <= 0) if(startHealth <= 0)
{ {
// If not, log it. // If not, log it.
report.Log(this, WarningType.Warning, ReportCategories.Design, $"{nameof(startHealth)} is to low", $"Make value > 0"); report.Log(this, WarningType.Warning, ReportCategories.Design, $"{nameof(startHealth)} is to low", $"Make value > 0");
} }
} }
@ -28,13 +27,21 @@ public class MyBehaviour : MonoBehaviour, IValidatable
} }
``` ```
Add a validate check using `[Required]` attribute:
```C#
[SerializeField, Required] private GameObject playerPrefab = null; // If someone forgets to assign it, it would be invalid.
```
Open Validator Window:
> Window -> General -> Validator
Run the validator:
> Click the 'run/play' button and wait for the report to be generated.
## Install ## Install
[Installing from a Git URL](https://docs.unity3d.com/Manual/upm-ui-giturl.html) [Installing from a Git URL](https://docs.unity3d.com/Manual/upm-ui-giturl.html)
[Unitypackage](https://github.com/COMPANYNAME/PACKAGENAME/releases)
## LICENSE ## LICENSE
Overall package is licensed under [MIT](/LICENSE.md), unless otherwise noted in the [3rd party licenses](/THIRD%20PARTY%20NOTICES.md) file and/or source code. Overall package is licensed under [MIT](/LICENSE.md), unless otherwise noted in the [3rd party licenses](/THIRD%20PARTY%20NOTICES.md) file and/or source code.

View File

@ -1,9 +1,9 @@
namespace Validator namespace Validator
{ {
public static partial class ReportCategories public static partial class ReportCategories
{ {
public const string Art = "Art"; public const string Art = "Art";
public const string Design = "Design"; public const string Design = "Design";
public const string Code = "Code"; public const string Code = "Code";
} }
} }

8
Runtime/Validators.meta Normal file
View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 8cd25e23ad137e24ea0f469556831712
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 25705f09a21a10049aed213ea301db84
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,19 @@
using System;
namespace Validator
{
[AttributeUsage(AttributeTargets.Field, Inherited = true, AllowMultiple = false)]
public class RequiredAttribute : Attribute
{
public WarningType WarningType { get; private set; } = WarningType.Error;
public string Category { get; private set; } = ReportCategories.Design;
public RequiredAttribute() { }
public RequiredAttribute(WarningType warningType = WarningType.Error, string category = ReportCategories.Design)
{
WarningType = warningType;
Category = category;
}
}
}

View File

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

View File

@ -1,7 +1,7 @@
{ {
"name": "com.vertexcolor.validator", "name": "com.vertexcolor.validator",
"displayName": "Validator", "displayName": "Validator",
"version": "0.1.1", "version": "0.1.4",
"unity": "2019.3", "unity": "2019.3",
"description": "Unity project validator framework.", "description": "Unity project validator framework.",
"category": "Tool", "category": "Tool",