Skip to content

Instantly share code, notes, and snippets.

@CustomPhase
Created July 28, 2019 16:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save CustomPhase/5adf565b92cf247d1d658ffc7abcf995 to your computer and use it in GitHub Desktop.
Save CustomPhase/5adf565b92cf247d1d658ffc7abcf995 to your computer and use it in GitHub Desktop.
Custom reorderable UnityActions
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[System.Serializable]
public class CustomUnityAction {
[SerializeField]
public List<SerializableAction> actions;
public void Invoke()
{
if (actions != null)
{
for (int i = 0; i < actions.Count; i++)
{
actions[i].Invoke();
}
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
[CustomPropertyDrawer(typeof(CustomUnityAction))]
public class CustomUnityActionDrawer : PropertyDrawer {
public override float GetPropertyHeight(SerializedProperty property, UnityEngine.GUIContent label)
{
return getList(property.FindPropertyRelative("actions")).GetHeight()+8;
}
private UnityEditorInternal.ReorderableList list;
private string propName;
private UnityEditorInternal.ReorderableList getList(SerializedProperty property)
{
if (list == null)
{
list = new UnityEditorInternal.ReorderableList(property.serializedObject, property, true, true, true, true);
list.drawElementCallback = (Rect rect, int index, bool isActive, bool isFocused) =>
{
rect.width -= 5;
rect.x += 5;
EditorGUI.PropertyField(rect, property.GetArrayElementAtIndex(index), true);
};
list.drawHeaderCallback += DrawHeader;
}
return list;
}
private void DrawHeader(Rect rect)
{
GUI.Label(rect, propName, EditorStyles.boldLabel);
}
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
// Using BeginProperty / EndProperty on the parent property means that
// prefab override logic works on the entire property.
EditorGUI.BeginProperty(position, label, property);
propName = ObjectNames.NicifyVariableName(property.name);
var listProperty = property.FindPropertyRelative("actions");
var list = getList(listProperty);
var height = 0f;
for (var i = 0; i < listProperty.arraySize; i++)
{
height = Mathf.Max(height, EditorGUI.GetPropertyHeight(listProperty.GetArrayElementAtIndex(i)));
}
list.elementHeight = height;
position.x += 4;
list.DoList(position);
EditorGUI.EndProperty();
}
}
using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using UnityEngine;
[Serializable]
public class SerializableAction
{
[SerializeField]
private UnityEngine.Object _target;
[SerializeField]
private string _methodName = "";
[SerializeField]
private byte[] _serialData = { };
[SerializeField]
private GameObject go;
Action _action;
public void Invoke()
{
if (_action == null)
{
_action = CreateDelegate();
}
_action.Invoke();
}
public void SetDelegate(Action action)
{
if (action == null)
{
_target = null;
_methodName = "";
_serialData = new byte[] { };
return;
}
var delAction = action as Delegate;
if (delAction == null)
{
throw new InvalidOperationException(typeof(Action).Name + " is not a delegate type.");
}
_target = delAction.Target as UnityEngine.Object;
if (_target != null)
{
_methodName = delAction.Method.Name;
_serialData = null;
}
else
{
//Serialize the data to a binary stream
using (var stream = new MemoryStream())
{
(new BinaryFormatter()).Serialize(stream, action);
stream.Flush();
_serialData = stream.ToArray();
}
_methodName = null;
}
}
public Action CreateDelegate()
{
if (_serialData.Length == 0 && _methodName == "")
{
return null;
}
if (_target != null)
{
return Delegate.CreateDelegate(typeof(Action), _target, _methodName) as Action;
}
using (var stream = new MemoryStream(_serialData))
{
return (new BinaryFormatter()).Deserialize(stream) as Action;
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.Reflection;
using System.Linq;
[CustomPropertyDrawer(typeof(SerializableAction))]
public class SerializableActionDrawer : PropertyDrawer {
int selection;
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
return 26;
}
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
// Using BeginProperty / EndProperty on the parent property means that
// prefab override logic works on the entire property.
EditorGUI.BeginProperty(position, label, property);
// Draw label
//position = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label);
// Don't make child fields be indented
var indent = EditorGUI.indentLevel;
EditorGUI.indentLevel = 0;
// Calculate rects
Rect objectRect = new Rect(position.x, position.y+5, 90, position.height-10);
var selectRect = new Rect(position.x + 96, position.y+5, position.width - 96, position.height-10);
bool changedObject = false;
EditorGUI.BeginChangeCheck();
EditorGUI.ObjectField(objectRect, property.FindPropertyRelative("go"), typeof(GameObject), GUIContent.none);
changedObject = EditorGUI.EndChangeCheck();
//EditorGUI.PropertyField(objectRect, property.FindPropertyRelative("go"), GUIContent.none);
if (property.FindPropertyRelative("go").objectReferenceValue != null)
{
selection = 0;
int count = 0;
GameObject go = property.FindPropertyRelative("go").objectReferenceValue as GameObject;
Component[] components = go.GetComponents<Component>();
List<string> methods = new List<string>();
Dictionary<int, KeyValuePair<Object, string>> data = new Dictionary<int, KeyValuePair<Object, string>>();
for (int i = 0; i<components.Length; i++)
{
if (components[i].GetType() != typeof(Transform)) {
MethodInfo[] _meth = components[i].GetType().GetMethods();
for (int m = 0; m < _meth.Length; m++)
{
if (_meth[m].IsPublic && !_meth[m].IsSpecialName)
{
methods.Add(components[i].GetType().Name + "/" + _meth[m].Name);
if (components[i]==property.FindPropertyRelative("_target").objectReferenceValue &&
_meth[m].Name==property.FindPropertyRelative("_methodName").stringValue )
{
selection = count;
}
data.Add(count, new KeyValuePair<Object, string>(components[i], _meth[m].Name));
count++;
}
}
}
}
EditorGUI.BeginChangeCheck();
selection = EditorGUI.Popup(selectRect, selection, methods.ToArray());
if (EditorGUI.EndChangeCheck() || changedObject)
{
property.FindPropertyRelative("_target").objectReferenceValue = data[selection].Key;
property.FindPropertyRelative("_methodName").stringValue = data[selection].Value;
}
} else
{
GUI.enabled = false;
EditorGUI.Popup(selectRect, selection, new string[] { "Select object first" });
GUI.enabled = true;
}
// Draw fields - passs GUIContent.none to each so they are drawn without labels
//EditorGUI.PropertyField(amountRect, property.FindPropertyRelative("amount"), GUIContent.none);
//EditorGUI.PropertyField(unitRect, property.FindPropertyRelative("unit"), GUIContent.none);
//EditorGUI.PropertyField(nameRect, property.FindPropertyRelative("name"), GUIContent.none);
// Set indent back to what it was
EditorGUI.indentLevel = indent;
EditorGUI.EndProperty();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment