Skip to content

Commit

Permalink
Added custom attributes
Browse files Browse the repository at this point in the history
  • Loading branch information
App24 committed May 31, 2023
1 parent b38c65f commit 763d530
Show file tree
Hide file tree
Showing 63 changed files with 1,039 additions and 78 deletions.
8 changes: 8 additions & 0 deletions Assets/RicUtils/Editor/AttributeDrawer.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
using RicUtils.Attributes;
using RicUtils.Editor.Utilities;
using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;

namespace RicUtils.Editor.AttributeDrawer
{
[CustomPropertyDrawer(typeof(ConstantSelectorAttribute))]
public class ConstantSelectorAttributeDrawer : PropertyDrawer
{
private ConstantSelectorAttribute cachedProperty;
private Type targetType;
private string[] names;
private object[] values;
private int selectedIndex;
private bool foundValue;

public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
return EditorGUI.GetPropertyHeight(property, label);
}

public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
CacheProperty(property);

if (values == null || values.Length == 0)
{
EditorGUI.PropertyField(position, property, label);
return;
}

if (targetType != fieldInfo.FieldType)
{
EditorGUI.HelpBox(position, $"[ConstantSelector] '{targetType}' is not the same as '{fieldInfo.FieldType}'", MessageType.Error);
return;
}

if (!foundValue && selectedIndex == 0)
{
EditorGUIHelper.DrawBox(position, Color.yellow);
}

EditorGUI.BeginChangeCheck();
selectedIndex = EditorGUI.Popup(position, label.text, selectedIndex, names);
if (EditorGUI.EndChangeCheck())
{
fieldInfo.SetValue(property.serializedObject.targetObject, values[selectedIndex]);
property.serializedObject.ApplyModifiedProperties();
EditorUtility.SetDirty(property.serializedObject.targetObject);
}
}

private void CacheProperty(SerializedProperty property)
{
if (cachedProperty == null)
{
cachedProperty = attribute as ConstantSelectorAttribute;

targetType = fieldInfo.FieldType;

var fields = targetType.GetFields(System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.FlattenHierarchy);
var properties = targetType.GetProperties(System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.FlattenHierarchy);

List<string> names = new List<string>();
List<object> values = new List<object>();

foreach (var field in fields)
{
if ((field.IsInitOnly || field.IsLiteral) && field.FieldType == targetType)
{
names.Add(field.Name);
values.Add(field.GetValue(null));
}
}

foreach (var p in properties)
{
if (p.PropertyType == targetType)
{
names.Add(p.Name);
values.Add(p.GetValue(null));
}
}

var currentValue = fieldInfo.GetValue(property.serializedObject.targetObject);
if (currentValue != null)
{
for (int i = 0; i < values.Count; i++)
{
if (currentValue.Equals(values[i]))
{
foundValue = true;
selectedIndex = i;
}
}
}

if (!foundValue)
{
var value = fieldInfo.GetValue(property.serializedObject.targetObject);
var valueString = value == null ? "NULL" : value.ToString();
names.Add("ERROR: NO " + valueString);
values.Add(value);
}

this.names = names.ToArray();
this.values = values.ToArray();
}
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

34 changes: 34 additions & 0 deletions Assets/RicUtils/Editor/AttributeDrawer/MaxValueAttributeDrawer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using RicUtils.Attributes;
using RicUtils.Utilities;
using UnityEditor;
using UnityEngine;

namespace RicUtils.Editor.AttributeDrawer
{
[CustomPropertyDrawer(typeof(MaxValueAttribute))]
public class MaxValueAttributeDrawer : PropertyDrawer
{
private MaxValueAttribute cachedAttribute;

public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
return EditorGUI.GetPropertyHeight(property, label);
}

public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
if (cachedAttribute == null) cachedAttribute = attribute as MaxValueAttribute;

if (!property.IsNumerical() && !property.IsVector())
{
EditorGUI.HelpBox(position, "[MaxValue] used with non-numeric property", MessageType.Warning);
return;
}
if ((property.IsNumerical() && property.HandleMaxNumericalValues(cachedAttribute.X)) ||
(property.IsVectorInt() && property.HandleMaxVectorIntValues(new Vector3Int((int)cachedAttribute.X, (int)cachedAttribute.Y, (int)cachedAttribute.Z))) ||
(property.IsVectorFloat() && property.HandleMaxVectorValues(new Vector4(cachedAttribute.X, cachedAttribute.Y, cachedAttribute.Z, cachedAttribute.W))))
property.serializedObject.ApplyModifiedProperties();
EditorGUI.PropertyField(position, property, label, true);
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

34 changes: 34 additions & 0 deletions Assets/RicUtils/Editor/AttributeDrawer/MinValueAttributeDrawer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
using RicUtils.Attributes;
using RicUtils.Utilities;
using UnityEditor;
using UnityEngine;

namespace RicUtils.Editor
{
[CustomPropertyDrawer(typeof(MinValueAttribute))]
public class MinValueAttributeDrawer : PropertyDrawer
{
private MinValueAttribute cachedAttribute;

public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
return EditorGUI.GetPropertyHeight(property, label);
}

public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
if (cachedAttribute == null) cachedAttribute = attribute as MinValueAttribute;

if (!property.IsNumerical() && !property.IsVector())
{
EditorGUI.HelpBox(position, "[MinValue] used with non-numeric property", MessageType.Warning);
return;
}
if ((property.IsNumerical() && property.HandleMinNumericalValues(cachedAttribute.X)) ||
(property.IsVectorInt() && property.HandleMinVectorIntValues(new Vector3Int((int)cachedAttribute.X, (int)cachedAttribute.Y, (int)cachedAttribute.Z))) ||
(property.IsVectorFloat() && property.HandleMinVectorValues(new Vector4(cachedAttribute.X, cachedAttribute.Y, cachedAttribute.Z, cachedAttribute.W))))
property.serializedObject.ApplyModifiedProperties();
EditorGUI.PropertyField(position, property, label, true);
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
using RicUtils.Attributes;
using RicUtils.Editor.Utilities;
using System.Reflection;
using UnityEditor;
using UnityEngine;

namespace RicUtils.Editor.AttributeDrawer
{
[CustomPropertyDrawer(typeof(MustBeAssignedAttribute))]
public class MustBeAssignedAttributeDrawer : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
if (MustBeAssignedCheck.GetError(fieldInfo, property.serializedObject.targetObject) > 0)
{
EditorGUIHelper.DrawBox(position, Color.red);
}

EditorGUI.PropertyField(position, property, label);
}
}

[InitializeOnLoad]
internal class MustBeAssignedCheck : UnityEditor.AssetModificationProcessor
{
static MustBeAssignedCheck()
{
Assert();
}

public static string[] OnWillSaveAssets(string[] paths)
{
if (paths.Length == 1 && (paths[0] == null || paths[0].EndsWith(".prefab"))) return paths;

Assert();

return paths;
}

private static void Assert()
{
var behaviours = Object.FindObjectsOfType<MonoBehaviour>(true);

foreach (var behaviour in behaviours)
{
if (behaviour == null) continue;

var objType = behaviour.GetType();
var fields = objType.GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);

foreach (var field in fields)
{
if (!field.IsDefined(typeof(MustBeAssignedAttribute), false) && !field.IsDefined(typeof(SerializeField), false)) continue;

var error = GetError(field, behaviour);

switch (error)
{
case 1:
Debug.LogError($"{objType.Name}: '{field.Name}' is Value Type with default value", behaviour);
break;
case 2:
Debug.LogError($"{objType.Name}: '{field.Name}' not assigned (null value)", behaviour);
break;
case 3:
Debug.LogError($"{objType.Name}: '{field.Name}' not assigned (empty string)", behaviour);
break;
case 4:
Debug.LogError($"{objType.Name}: '{field.Name}' not assigned (empty array)", behaviour);
break;
}
}
}
}

public static int GetError(FieldInfo field, Object targetObject)
{
var value = field.GetValue(targetObject);
bool valueTypeWithDefaultValue = field.FieldType.IsValueType && System.Activator.CreateInstance(field.FieldType).Equals(value);
if (valueTypeWithDefaultValue)
{
return 1;
}


bool nullReferenceType = value == null || value.Equals(null);
if (nullReferenceType)
{
return 2;
}


bool emptyString = field.FieldType == typeof(string) && (string)value == string.Empty;
if (emptyString)
{
return 3;
}


var arr = value as System.Array;
bool emptyArray = arr != null && arr.Length == 0;
if (emptyArray)
{
return 4;
}

return 0;
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using RicUtils.Attributes;
using RicUtils.Utilities;
using UnityEditor;
using UnityEngine;

namespace RicUtils.Editor.AttributeDrawer
{
[CustomPropertyDrawer(typeof(NegativeValueOnlyAttribute))]
public class NegativeValueOnlyAttributeDrawer : PropertyDrawer
{
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
return EditorGUI.GetPropertyHeight(property, label);
}

public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
if (!property.IsNumerical() && !property.IsVector())
{
EditorGUI.HelpBox(position, "[NegativeValueOnly] used with non-numeric property", MessageType.Warning);
return;
}
if (property.HandleMaxValues(0)) property.serializedObject.ApplyModifiedProperties();
EditorGUI.PropertyField(position, property, label, true);
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 763d530

Please sign in to comment.