Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save brunomikoski/c81441f74e5998c4dd8257e0c03a3824 to your computer and use it in GitHub Desktop.
Save brunomikoski/c81441f74e5998c4dd8257e0c03a3824 to your computer and use it in GitHub Desktop.
[Autohook] property drawer for unity - Add this [Autohook] attribute to a property to and the inspector will automagically hook up a valid reference for you if it can find a component attached to the same game object that matches the field you put it on. You can watch a demo of this in action here https://youtu.be/faVt09NGzws <3

heres a tiny little example of how to use it

public class AutohookTest : MonoBehaviour
{
    [Autohook] // <-- yeah its that easy!
    public Rigidbody rigidbody;
    
    // Update is called once per frame
    void Update()
    {
        // do something
        rigidbody.AddForce(Vector3.up);
    }
}

You can watch a demo of this in action here https://youtu.be/faVt09NGzws

ko-fi

// NOTE DONT put in an editor folder!
using UnityEngine;
public class AutohookAttribute : PropertyAttribute
{
}
// NOTE put in a Editor folder
using UnityEditor;
using UnityEngine;
[CustomPropertyDrawer(typeof(AutohookAttribute))]
public class AutohookPropertyDrawer : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
// First, lets attempt to find a valid component we could hook into this property
var component = FindAutohookTarget(property);
if (component != null)
{
// if we found something, AND the autohook is empty, lets slot it.
// the reason were straight up looking for a target component is so we
// can skip drawing the field if theres a valid autohook.
// this just looks a bit cleaner but isnt particularly safe. YMMV
if (property.objectReferenceValue == null)
property.objectReferenceValue = component;
return;
}
// havent found one? lets just draw the default property field, let the user manually
// hook something in.
EditorGUI.PropertyField(position, property, label);
}
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
// if theres a valid autohook target we skip drawing, so height is zeroed
var component = FindAutohookTarget(property);
if (component != null)
return 0;
// otherwise, return its default height (which should be the standard 16px unity usually uses)
return base.GetPropertyHeight(property, label);
}
/// <summary>
/// Takes a SerializedProperty and finds a local component that can be slotted into it.
/// Local in this context means its a component attached to the same GameObject.
/// This could easily be changed to use GetComponentInParent/GetComponentInChildren
/// </summary>
/// <param name="property"></param>
/// <returns></returns>
private Component FindAutohookTarget(SerializedProperty property)
{
var root = property.serializedObject;
if (root.targetObject is Component)
{
// first, lets find the type of component were trying to autohook...
var type = GetTypeFromProperty(property);
// ...then use GetComponent(type) to see if there is one on our object.
var component = (Component)root.targetObject;
return component.GetComponent(type);
}
else
{
Debug.Log("OH NO handle fails here better pls");
}
return null;
}
/// <summary>
/// Uses reflection to get the type from a serialized property
/// </summary>
/// <param name="property"></param>
/// <returns></returns>
private static System.Type GetTypeFromProperty(SerializedProperty property)
{
// first, lets get the Type of component this serialized property is part of...
var parentComponentType = property.serializedObject.targetObject.GetType();
// ... then, using reflection well get the raw field info of the property this
// SerializedProperty represents...
var fieldInfo = parentComponentType.GetField(property.propertyPath);
// ... using that we can return the raw .net type!
return fieldInfo.FieldType;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment