I want to create a custom attribute for the Unity Inspector. Similar to how Attributes and PropertyDrawers work, but on a class level. Specifically, I want to create a custom attribute I can add to a MonoBehaviour class or one of it’s methods, which creates a button at the top the Inspector. Triggering the method. Is this something possible or would I have to make some hacky solution of some base class for everything and go through reflection on every class looking for method attributes?
There’s no built-in way to decorate methods or classes and have them customize the inspector the way that property drawers do. You can create your own MonoBehaviour Editor …
[CustomEditor(typeof(MonoBehaviour), true)]
… to avoid creating your own base MyBaseMonoBehaviour class, but there’s a good chance it might break some Unity built-in types (a lot of them have custom editors) or your own editors. This may or may not prove to be an issue for you.
You’re stuck with using reflection to find the method and class attributes though. I wouldn’t describe that as “hacky”. I personally went with the custom base class, but I use a lot of attributes and other operations to speed up development.
Yeah I think that’s probably the way to go. The only other alternate I could think of would be to make some custom property drawers for fields containing UnityEvent’s, and triggering them on button press. Like this:
[System.Serializable]
[ExecuteInEditMode]
public class InspectorButton
{
[SerializeField] private string name;
[SerializeField] private UnityEvent onPress;
public string Name { get => name; }
public void Press()
{
onPress.Invoke();
}
}
[CustomPropertyDrawer(typeof(InspectorButton))]
public class InspectorButtonDrawer : PropertyDrawer
{
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
return EditorGUI.GetPropertyHeight(property, label);
}
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
EditorGUI.PropertyField(position, property, label, true);
var btn = (InspectorButton)fieldInfo.GetValue(property.serializedObject.targetObject);
if (GUILayout.Button(btn.Name))
{
btn.Press();
}
EditorGUILayout.Space();
}
}