Files
trail-into-darkness/Packages/com.jovian.utilties/Runtime/EditorRuntimeAccessible/SerializedObjectUtility.cs

211 lines
9.1 KiB
C#

using System;
using System.Collections;
using System.Diagnostics;
using System.Text.RegularExpressions;
using UnityEngine;
using Debug = UnityEngine.Debug;
using Object = UnityEngine.Object;
using Type = System.Type;
#if UNITY_EDITOR
using UnityEditor;
using System.Reflection;
#endif
namespace Jovian.Utilities {
public static class SerializedObjectUtility {
[Conditional("UNITY_EDITOR")]
public static void SaveObjectProperties(Object targetObject, params object[] args) {
#if UNITY_EDITOR
EditorSerializedObjectUtility.SaveObjectProperties(targetObject, args);
#endif
}
}
#if UNITY_EDITOR
public static class EditorSerializedObjectUtility {
//https://answers.unity.com/questions/929293/get-field-type-of-serializedproperty.html
public static Type GetTypeFromProperty(SerializedProperty property) {
//gets parent type info
string[] slices = property.propertyPath.Split('.');
System.Type type = property.serializedObject.targetObject.GetType();
for(int i = 0; i < slices.Length; i++)
if (slices[i] == "Array")
{
i++; //skips "data[x]"
type = type.GetElementType(); //gets info on array elements
}
//gets info on field and its type
else type = type.GetField(slices[i], BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.FlattenHierarchy | BindingFlags.Instance).FieldType;
//type is now the type of the property
return type;
}
private static readonly Regex isArrayElementRegex = new Regex("Array.data\\[\\d+\\]$");
public static bool IsPropertyAnArrayElement(SerializedProperty property) {
return isArrayElementRegex.IsMatch(property.propertyPath);
}
public static SerializedProperty GetArrayPropertyWithElementProperty(SerializedProperty property) {
SerializedObject serializedObject = property.serializedObject;
string propertyPath = property.propertyPath;
int arrayDataIndex = propertyPath.LastIndexOf(".Array.data", StringComparison.Ordinal);
string propertyPathWithoutArray = propertyPath.Substring(0, arrayDataIndex);
int pathDividerIndex = propertyPathWithoutArray.LastIndexOf(".", StringComparison.Ordinal);
string parentPropertyName = propertyPathWithoutArray;
if(pathDividerIndex != -1) {
parentPropertyName = propertyPathWithoutArray.Substring(pathDividerIndex);
}
return serializedObject.FindProperty(parentPropertyName);;
}
public static void SaveObjectProperties(Object targetObject, params object[] args) {
SerializedObject serializedObject = new SerializedObject(targetObject);
for(int i = 0; i < args.Length; i += 2) {
var keyArg = args[i];
var keyType = keyArg.GetType();
if((keyType == typeof(string)) == false) {
throw new System.NotSupportedException(string.Format("Key must be string. {0} is {1}", args[i], keyType));
}
else {
var property = serializedObject.FindProperty((string)keyArg);
object argValue = args[i + 1];
if(property == null) {
throw new System.Exception(string.Format("No property found for key {0}", keyArg));
}
if(argValue == null) {
property.objectReferenceValue = null;
}
else {
if(property.isArray) {
property.arraySize = 0;
IEnumerable argArray = (IEnumerable)argValue;
IEnumerator enumerator = argArray.GetEnumerator();
int index = 0;
while(enumerator.MoveNext()) {
property.InsertArrayElementAtIndex(index);
var arrayProperty = property.GetArrayElementAtIndex(index);
SetSerializedPropertyValue(arrayProperty, enumerator.Current);
index++;
}
}
else {
SetSerializedPropertyValue(property, argValue);
}
}
}
}
serializedObject.ApplyModifiedProperties();
}
private static void SetSerializedPropertyValue(SerializedProperty property, object value) {
if(property == null) {
UnityEngine.Debug.LogError("SetSerializedPropertyValue failed, property is null");
return;
}
switch(property.propertyType) {
case SerializedPropertyType.AnimationCurve:
property.animationCurveValue = (AnimationCurve)value;
break;
case SerializedPropertyType.Boolean:
property.boolValue = (bool)value;
break;
case SerializedPropertyType.BoundsInt:
property.boundsIntValue = (BoundsInt)value;
break;
case SerializedPropertyType.Character:
property.intValue = (int)(char)value;
break;
case SerializedPropertyType.Color: {
if(value is Color32) {
property.colorValue = (Color)(Color32)value;
}
else {
property.colorValue = (Color)value;
}
break;
}
case SerializedPropertyType.ExposedReference:
case SerializedPropertyType.ObjectReference:
property.objectReferenceValue = (Object)value;
break;
case SerializedPropertyType.Float:
property.floatValue = (float)value;
break;
case SerializedPropertyType.Integer:
property.intValue = (int)value;
break;
case SerializedPropertyType.LayerMask:
property.intValue = ((LayerMask)value).value;
break;
case SerializedPropertyType.Quaternion:
property.quaternionValue = (Quaternion)value;
break;
case SerializedPropertyType.Rect:
property.rectValue = (Rect)value;
break;
case SerializedPropertyType.RectInt:
property.rectIntValue = (RectInt)value;
break;
case SerializedPropertyType.String:
property.stringValue = (string)value;
break;
case SerializedPropertyType.Vector2:
property.vector2Value = (Vector2)value;
break;
case SerializedPropertyType.Vector2Int:
property.vector2IntValue = (Vector2Int)value;
break;
case SerializedPropertyType.Vector3:
property.vector3Value = (Vector3)value;
break;
case SerializedPropertyType.Vector3Int:
property.vector3IntValue = (Vector3Int)value;
break;
case SerializedPropertyType.Vector4:
property.vector4Value = (Vector4)value;
break;
case SerializedPropertyType.Enum:
property.enumValueIndex = (int)value; // need to test this
// flags???
break;
case SerializedPropertyType.Generic:
SaveGenericProperty(property, value);
break;
default:
throw new System.NotSupportedException($"PropertyType {property.propertyType} is not supported - yet. Array? {property.isArray} Path: {property.propertyPath}");
}
}
private static void SaveGenericProperty(SerializedProperty property, object instance) {
Type type = instance.GetType();
var fields = type.GetRuntimeFields();
foreach(FieldInfo field in fields) {
if(field.IsNotSerialized || field.IsStatic) {
continue;
}
SerializedProperty fieldProperty = property.FindPropertyRelative(field.Name);
if(fieldProperty != null) {
SetSerializedPropertyValue(property.FindPropertyRelative(field.Name), field.GetValue(instance));
}
else {
UnityEngine.Debug.Log($"SaveGenericProperty cannot field serializedProperty named '{field.Name}'");
}
}
}
}
#endif
}