Skip to content

Instantly share code, notes, and snippets.

@Refsa
Last active September 16, 2019 06:54
Show Gist options
  • Save Refsa/a7989687d74f935ca78c8e8fdf8d31b3 to your computer and use it in GitHub Desktop.
Save Refsa/a7989687d74f935ca78c8e8fdf8d31b3 to your computer and use it in GitHub Desktop.
Getting the SerializedProperty of the actual object of a CustomPropertyDrawer, when the object is stored in a List
using System.Collections.Generic;
using System.Text.RegularExpressions;
using UnityEditor;
public static class SerializedPropertyExtensions
{
// Takes the property path and does a regex to find all the sub paths to reach the actual object,
// then follows the path to find the actual SerializedProperty
//
// Example of how a property path string looks like in an extreme use case:
// testClassList.Array.data[0].testClass2.testClass3List.Array.data[0].testClass4.testClass5
public static SerializedProperty FindActualProperty (SerializedProperty property)
{
// Regex to find different parts of property path
Regex regex = new Regex (@"((\w+).Array.data\[(\d)\]|\.?(\w+)\.?)");
MatchCollection mc = regex.Matches (property.propertyPath);
var arrays = new List < (string, int) > ( );
foreach (Match m in mc)
{
if (m.Groups[4].Value != "")
arrays.Add ((m.Groups[4].Value, -1));
else
arrays.Add ((m.Groups[2].Value, int.Parse (m.Groups[3].Value)));
}
// Go down the hierarchy from the containing SerializedObject
var prop = property.serializedObject.FindProperty (arrays[0].Item1);
if (arrays[0].Item2 != -1)
prop = prop.GetArrayElementAtIndex (arrays[0].Item2);
for (int i = 1; i < arrays.Count; i++)
{
prop = prop.FindPropertyRelative (arrays[i].Item1);
if (arrays[i].Item2 != -1)
prop = prop.GetArrayElementAtIndex (arrays[i].Item2);
}
return prop;
}
}
using UnityEngine;
using UnityEditor;
// A CustomPropertyDrawer to show how the above script is used
[CustomPropertyDrawer (typeof (TestClass4))]
public class TestPropertyDrawer : PropertyDrawer
{
public override void OnGUI (Rect position, SerializedProperty property, GUIContent label)
{
EditorGUI.BeginProperty (position, label, property);
var prop = SerializedPropertyExtensions.FindActualProperty (property);
EditorGUI.PropertyField (position, prop.FindPropertyRelative ("testField"));
EditorGUI.EndProperty ( );
}
}
// Example structure where the script would be helpful. When the actual object of the
// SerializedProperty is stored in a list, the SerializedProperty will link to the list
// and not the wanted object
using System.Collections.Generic;
using UnityEngine;
[CreateAssetMenu (menuName = "TestSO")]
public class TestSO : ScriptableObject
{
public List<TestClass> testClassList = new List<TestClass> ( );
}
[System.Serializable]
public class TestClass
{
public TestClass2 testClass2;
}
[System.Serializable]
public class TestClass2
{
public List<TestClass3> testClass3List = new List<TestClass3> ( );
}
[System.Serializable]
public class TestClass3
{
public TestClass4 testClass4;
}
[System.Serializable]
public class TestClass4
{
public float testField = 0f;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment