Files
trail-into-darkness/Packages/com.jovian.inspector/Editor/Attributes/InterfaceComponentAttribute.cs
2026-03-29 19:16:39 +02:00

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