forked from Shardstone/trail-into-darkness
93 lines
4.0 KiB
C#
93 lines
4.0 KiB
C#
using System;
|
|
using UnityEngine;
|
|
|
|
namespace Jovian.InspectorTools {
|
|
public class InterfaceComponentAttribute : PropertyAttribute {
|
|
public readonly Type interfaceType;
|
|
public readonly bool allowMismatch;
|
|
|
|
public InterfaceComponentAttribute(Type interfaceType, bool allowMismatch = false) {
|
|
this.interfaceType = interfaceType;
|
|
this.allowMismatch = allowMismatch;
|
|
}
|
|
}
|
|
}
|
|
|
|
#if UNITY_EDITOR
|
|
namespace Jovian.InspectorTools.Internal {
|
|
using UnityEditor;
|
|
|
|
[CustomPropertyDrawer(typeof(InterfaceComponentAttribute))]
|
|
public class InterfaceComponentAttributeDrawer : PropertyDrawer {
|
|
|
|
private const float MESSAGE_HEIGHT = 40f;
|
|
private const float FIELD_HEIGHT = 18f;
|
|
|
|
private enum ValueImplementation {
|
|
Null,
|
|
Match,
|
|
Mismatch
|
|
}
|
|
|
|
public override float GetPropertyHeight(SerializedProperty property, GUIContent label) {
|
|
ValueImplementation valueImplementation = GetValueInterfaceImplementation(property, ((InterfaceComponentAttribute)attribute).interfaceType);
|
|
return base.GetPropertyHeight(property, label) + (valueImplementation != ValueImplementation.Match ? MESSAGE_HEIGHT : 0f);
|
|
}
|
|
|
|
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) {
|
|
InterfaceComponentAttribute interfaceAttribute = (InterfaceComponentAttribute)attribute;
|
|
Type interfaceType = interfaceAttribute.interfaceType;
|
|
bool allowMismatch = interfaceAttribute.allowMismatch;
|
|
UnityEngine.Object value = property.objectReferenceValue;
|
|
if(value is GameObject gameObject) {
|
|
value = gameObject.GetComponent(interfaceType) as Component;
|
|
if(value != null) {
|
|
property.objectReferenceValue = value;
|
|
property.serializedObject.ApplyModifiedPropertiesWithoutUndo();
|
|
}
|
|
}
|
|
else if(value is Transform transform) {
|
|
value = transform.GetComponent(interfaceType) as Component;
|
|
if(value != null) {
|
|
property.objectReferenceValue = value;
|
|
property.serializedObject.ApplyModifiedPropertiesWithoutUndo();
|
|
}
|
|
}
|
|
|
|
ValueImplementation valueImplementation = GetValueInterfaceImplementation(property, interfaceType);
|
|
|
|
string message = null;
|
|
if(valueImplementation == ValueImplementation.Null) {
|
|
message = $"Component must implement '{interfaceType.Name}'";
|
|
}
|
|
else if(valueImplementation == ValueImplementation.Mismatch) {
|
|
message = $"Component does not implement '{interfaceType.Name}'";
|
|
|
|
if(allowMismatch == false) {
|
|
property.objectReferenceValue = null;
|
|
property.serializedObject.ApplyModifiedPropertiesWithoutUndo();
|
|
}
|
|
}
|
|
|
|
if(string.IsNullOrEmpty(message) == false) {
|
|
Rect boxPosition = new Rect(position.x, position.y, position.width, MESSAGE_HEIGHT - 2f);
|
|
EditorGUI.HelpBox(boxPosition, message, valueImplementation == ValueImplementation.Mismatch ? MessageType.Warning : MessageType.Info);
|
|
}
|
|
|
|
Rect fieldPosition = new Rect(position.x, position.yMax - FIELD_HEIGHT, position.width, FIELD_HEIGHT);
|
|
EditorGUI.PropertyField(fieldPosition, property, label);
|
|
}
|
|
|
|
private ValueImplementation GetValueInterfaceImplementation(SerializedProperty property, Type interfaceType) {
|
|
UnityEngine.Object value = property.objectReferenceValue;
|
|
if(value == null) {
|
|
return ValueImplementation.Null;
|
|
}
|
|
else if(interfaceType.IsAssignableFrom(property.objectReferenceValue.GetType())) {
|
|
return ValueImplementation.Match;
|
|
}
|
|
return ValueImplementation.Mismatch;
|
|
}
|
|
}
|
|
}
|
|
#endif |