Skip to content

Instantly share code, notes, and snippets.

@mikerochip
Last active May 10, 2024 01:59
Show Gist options
  • Save mikerochip/ae80449a463433c9fafab87fba8d57eb to your computer and use it in GitHub Desktop.
Save mikerochip/ae80449a463433c9fafab87fba8d57eb to your computer and use it in GitHub Desktop.
Unity SerializedProperty extensions and utilities
using System;
using System.Collections;
using UnityEditor;
namespace MikeSchweitzer
{
public static class SerializedPropertyExtensions
{
public static T[] GetAllValues<T>(this SerializedProperty property)
{
var targetObjects = property.serializedObject.targetObjects;
var values = new T[targetObjects.Length];
for (var i = 0; i < targetObjects.Length; ++i)
values[i] = property.GetValue<T>(i);
return values;
}
public static void GetAllValues<T>(this SerializedProperty property, ref T[] values)
{
var targetObjects = property.serializedObject.targetObjects;
if (values == null)
values = new T[targetObjects.Length];
else
Array.Resize(ref values, targetObjects.Length);
for (var i = 0; i < targetObjects.Length; ++i)
values[i] = property.GetValue<T>(i);
}
public static T GetValue<T>(this SerializedProperty property, int targetObjectIndex = -1)
{
var value = targetObjectIndex < 0
? (object)property.serializedObject.targetObject
: property.serializedObject.targetObjects[targetObjectIndex];
var path = property.propertyPath;
var prevIndex = -1;
do
{
var nextIndex = path.IndexOf('.', prevIndex + 1);
var subPathLength = (nextIndex < 0 ? path.Length : nextIndex) - prevIndex - 1;
var subPath = path.AsSpan(prevIndex + 1, subPathLength).ToString();
if (subPath == "Array")
{
// list/array propertyPath values are weird and look like this
// {PropertyName}.Array.data[{ListIndex}]
// e.g.
// AudioLines.Array.data[0]
// RandomClipEntries.Array.data[0].ClipReference
var listIndexStart = path.IndexOf('[', nextIndex + 1) + 1;
var listIndexLength = path.IndexOf(']', listIndexStart) - listIndexStart;
var listIndexSpan = path.AsSpan(listIndexStart, listIndexLength);
var listIndex = int.Parse(listIndexSpan);
var enumerable = (IEnumerable)value;
var enumerator = enumerable!.GetEnumerator();
using var disposeDummy = enumerator as IDisposable;
var hasItemAtIndex = false;
for (var i = 0; i <= listIndex; ++i)
hasItemAtIndex = enumerator.MoveNext();
value = hasItemAtIndex ? enumerator.Current : null;
// have to move the prevIndex past the closing bracket and to the next dot
// OR the end of the string, whichever it happens to be
prevIndex = listIndexStart + listIndexLength + 1;
}
else
{
value = value!.GetType().GetField(subPath).GetValue(value);
prevIndex = nextIndex;
}
} while (prevIndex >= 0 && prevIndex < path.Length);
return (T)value;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment