forked from Shardstone/trail-into-darkness
255 lines
10 KiB
C#
255 lines
10 KiB
C#
#if UNITY_EDITOR
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Reflection;
|
|
using UnityEditor;
|
|
using Object = UnityEngine.Object;
|
|
|
|
namespace InspectorToolkit.EditorTools {
|
|
public static class MySerializedProperty {
|
|
#region Collections Handling
|
|
|
|
/// <summary>
|
|
/// Get array of property childs, if parent property is array
|
|
/// </summary>
|
|
public static SerializedProperty[] AsArray(this SerializedProperty property) {
|
|
List<SerializedProperty> items = new List<SerializedProperty>();
|
|
for(int i = 0; i < property.arraySize; i++)
|
|
items.Add(property.GetArrayElementAtIndex(i));
|
|
return items.ToArray();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get array of property childs casted to specific type
|
|
/// </summary>
|
|
public static T[] AsArray<T>(this SerializedProperty property) {
|
|
var propertiesArray = property.AsArray();
|
|
return propertiesArray.Select(s => s.objectReferenceValue).OfType<T>().ToArray();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get array of property childs, if parent property is array
|
|
/// </summary>
|
|
public static IEnumerable<SerializedProperty> AsIEnumerable(this SerializedProperty property) {
|
|
for(int i = 0; i < property.arraySize; i++)
|
|
yield return property.GetArrayElementAtIndex(i);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Replace array contents of SerializedProperty with another array
|
|
/// </summary>
|
|
public static void ReplaceArray(this SerializedProperty property, Object[] newElements) {
|
|
property.arraySize = 0;
|
|
property.serializedObject.ApplyModifiedProperties();
|
|
property.arraySize = newElements.Length;
|
|
for(var i = 0; i < newElements.Length; i++) {
|
|
property.GetArrayElementAtIndex(i).objectReferenceValue = newElements[i];
|
|
}
|
|
|
|
property.serializedObject.ApplyModifiedProperties();
|
|
}
|
|
|
|
/// <summary>
|
|
/// If property is array, insert new element at the end and get it as a property
|
|
/// </summary>
|
|
public static SerializedProperty NewElement(this SerializedProperty property) {
|
|
int newElementIndex = property.arraySize;
|
|
property.InsertArrayElementAtIndex(newElementIndex);
|
|
return property.GetArrayElementAtIndex(newElementIndex);
|
|
}
|
|
|
|
#endregion
|
|
|
|
/// <summary>
|
|
/// Property is float, int, vector or int vector
|
|
/// </summary>
|
|
public static bool IsNumerical(this SerializedProperty property) {
|
|
var propertyType = property.propertyType;
|
|
switch(propertyType) {
|
|
case SerializedPropertyType.Float:
|
|
case SerializedPropertyType.Integer:
|
|
case SerializedPropertyType.Vector2:
|
|
case SerializedPropertyType.Vector3:
|
|
case SerializedPropertyType.Vector4:
|
|
case SerializedPropertyType.Vector2Int:
|
|
case SerializedPropertyType.Vector3Int:
|
|
return true;
|
|
|
|
default: return false;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get string representation of serialized property
|
|
/// </summary>
|
|
public static string AsStringValue(this SerializedProperty property) {
|
|
switch(property.propertyType) {
|
|
case SerializedPropertyType.String:
|
|
return property.stringValue;
|
|
|
|
case SerializedPropertyType.Character:
|
|
case SerializedPropertyType.Integer:
|
|
if(property.type == "char") return Convert.ToChar(property.intValue).ToString();
|
|
return property.intValue.ToString();
|
|
|
|
case SerializedPropertyType.ObjectReference:
|
|
return property.objectReferenceValue != null ? property.objectReferenceValue.ToString() : "null";
|
|
|
|
case SerializedPropertyType.Boolean:
|
|
return property.boolValue.ToString();
|
|
|
|
case SerializedPropertyType.Enum:
|
|
return property.GetValue().ToString();
|
|
|
|
default:
|
|
return string.Empty;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Property path for collection without ".Array.data[x]" in it
|
|
/// </summary>
|
|
public static string GetFixedPropertyPath(this SerializedProperty property) => property.propertyPath.Replace(".Array.data[", "[");
|
|
|
|
|
|
/// <summary>
|
|
/// Get FieldInfo out of SerializedProperty
|
|
/// </summary>
|
|
public static FieldInfo GetFieldInfo(this SerializedProperty property) {
|
|
var targetObject = property.serializedObject.targetObject;
|
|
var targetType = targetObject.GetType();
|
|
return targetType.GetField(property.propertyPath);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get raw object value out of the SerializedProperty
|
|
/// </summary>
|
|
public static object GetValue(this SerializedProperty property) {
|
|
if(property == null) return null;
|
|
|
|
object obj = property.serializedObject.targetObject;
|
|
var elements = property.GetFixedPropertyPath().Split('.');
|
|
foreach(var element in elements) {
|
|
if(element.Contains("[")) {
|
|
var elementName = element.Substring(0, element.IndexOf("[", StringComparison.Ordinal));
|
|
var index = Convert.ToInt32(element.Substring(element.IndexOf("[", StringComparison.Ordinal)).Replace("[", "").Replace("]", ""));
|
|
obj = GetValueByArrayFieldName(obj, elementName, index);
|
|
}
|
|
else obj = GetValueByFieldName(obj, element);
|
|
}
|
|
return obj;
|
|
|
|
|
|
object GetValueByArrayFieldName(object source, string name, int index) {
|
|
if(!(GetValueByFieldName(source, name) is IEnumerable enumerable)) return null;
|
|
var enumerator = enumerable.GetEnumerator();
|
|
|
|
for(var i = 0; i <= index; i++) if(!enumerator.MoveNext()) return null;
|
|
return enumerator.Current;
|
|
}
|
|
|
|
// Search "source" object for a field with "name" and get it's value
|
|
object GetValueByFieldName(object source, string name) {
|
|
if(source == null) return null;
|
|
var type = source.GetType();
|
|
|
|
while(type != null) {
|
|
var fieldInfo = type.GetField(name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
|
|
if(fieldInfo != null) return fieldInfo.GetValue(source);
|
|
|
|
var propertyInfo = type.GetProperty(name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
|
|
if(propertyInfo != null) return propertyInfo.GetValue(source, null);
|
|
|
|
type = type.BaseType;
|
|
}
|
|
return null;
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Set raw object value to the SerializedProperty
|
|
/// </summary>
|
|
public static void SetValue(this SerializedProperty property, object value) {
|
|
GetFieldInfo(property).SetValue(property.serializedObject.targetObject, value);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Is specific attribute defined on SerializedProperty
|
|
/// </summary>
|
|
/// <param name="property"></param>
|
|
/// <typeparam name="T"></typeparam>
|
|
/// <returns></returns>
|
|
public static bool IsAttributeDefined<T>(this SerializedProperty property) where T : Attribute {
|
|
var fieldInfo = property.GetFieldInfo();
|
|
if(fieldInfo == null) return false;
|
|
return Attribute.IsDefined(fieldInfo, typeof(T));
|
|
}
|
|
|
|
#region SerializedProperty Get Parent
|
|
|
|
// Found here http://answers.unity.com/answers/425602/view.html
|
|
// Update here https://gist.github.com/AdrienVR/1548a145c039d2fddf030ebc22f915de to support inherited private members.
|
|
/// <summary>
|
|
/// Get parent object of SerializedProperty
|
|
/// </summary>
|
|
public static object GetParent(this SerializedProperty prop) {
|
|
var path = prop.propertyPath.Replace(".Array.data[", "[");
|
|
object obj = prop.serializedObject.targetObject;
|
|
var elements = path.Split('.');
|
|
foreach(var element in elements.Take(elements.Length - 1)) {
|
|
if(element.Contains("[")) {
|
|
var elementName = element.Substring(0, element.IndexOf("[", StringComparison.Ordinal));
|
|
var index = Convert.ToInt32(element.Substring(element.IndexOf("[", StringComparison.Ordinal)).Replace("[", "").Replace("]", ""));
|
|
obj = GetValueAt(obj, elementName, index);
|
|
}
|
|
else {
|
|
obj = GetValue(obj, element);
|
|
}
|
|
}
|
|
|
|
return obj;
|
|
}
|
|
|
|
private static object GetValue(object source, string name) {
|
|
if(source == null)
|
|
return null;
|
|
|
|
foreach(var type in GetHierarchyTypes(source.GetType())) {
|
|
var f = type.GetField(name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
|
|
if(f != null)
|
|
return f.GetValue(source);
|
|
|
|
var p = type.GetProperty(name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
|
|
if(p != null)
|
|
return p.GetValue(source, null);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private static IEnumerable<Type> GetHierarchyTypes(Type sourceType) {
|
|
yield return sourceType;
|
|
while(sourceType.BaseType != null) {
|
|
yield return sourceType.BaseType;
|
|
sourceType = sourceType.BaseType;
|
|
}
|
|
}
|
|
|
|
private static object GetValueAt(object source, string name, int index) {
|
|
var enumerable = GetValue(source, name) as IEnumerable;
|
|
if(enumerable == null) return null;
|
|
|
|
var enm = enumerable.GetEnumerator();
|
|
while(index-- >= 0)
|
|
enm.MoveNext();
|
|
return enm.Current;
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|
|
#endif
|