module-inspector/Editor/Extensions/SerializedPropertyExtension.cs

430 lines
17 KiB
C#

using System;
using System.Reflection;
using System.Runtime.CompilerServices;
using Module.Inspector.Editor.Utilities;
using UnityEditor;
using UnityEngine;
using Object = UnityEngine.Object;
namespace Module.Inspector.Editor
{
public static class SerializedPropertyExtension
{
public enum ECompareType : byte { False, True, Unknown };
public static SerializedProperty GetParent(this SerializedProperty sp)
{
string propertyPath = GetRootPath(sp.propertyPath);
return !propertyPath.Equals(sp.propertyPath) ? sp.serializedObject.FindProperty(propertyPath) : null;
}
public static SerializedProperty GetSibling(this SerializedProperty sp, string fieldName)
{
string propertyPath = GetRootPath(sp.propertyPath);
if (string.IsNullOrEmpty(propertyPath))
propertyPath = fieldName;
else
propertyPath += "." + fieldName;
return sp.serializedObject.FindProperty(propertyPath);
}
public static SerializedProperty GetRelativeProperty(this SerializedProperty sp, string relativePath)
{
SerializedProperty rp = sp;
string[] split = relativePath.Split('/');
for (var i = 0; i < split.Length; i++)
{
rp = split[i].Equals("PARENT") ? GetParent(rp) : GetSibling(rp, split[i]);
if (rp == null)
break;
}
return rp;
}
public static bool IsSiblingValue(this SerializedProperty sp, string siblingFieldName, object siblingFieldValue, bool useFieldValue)
{
if (string.IsNullOrEmpty(siblingFieldName))
return false;
SerializedProperty spSibling = sp.GetRelativeProperty(siblingFieldName);
return EditorSerializedPropertyUtility.IsValue(spSibling, siblingFieldValue, useFieldValue);
}
public static ECompareType IsGreaterOrEqualToSiblingValue(this SerializedProperty sp, string siblingFieldName)
{
if (string.IsNullOrEmpty(siblingFieldName))
return ECompareType.Unknown;
SerializedProperty spSibling = sp.GetRelativeProperty(siblingFieldName);
if (spSibling == null)
return ECompareType.Unknown;
if (spSibling.propertyType != sp.propertyType)
return ECompareType.Unknown;
if (sp.propertyType == SerializedPropertyType.Integer)
return sp.IsGreaterOrEqualToSiblingValue(siblingFieldName, sp.intValue);
if (sp.propertyType == SerializedPropertyType.Float)
return sp.IsGreaterOrEqualToSiblingValue(siblingFieldName, sp.floatValue);
if (sp.propertyType == SerializedPropertyType.Enum)
return sp.IsGreaterOrEqualToSiblingValue(siblingFieldName, sp.intValue);
return ECompareType.Unknown;
}
public static ECompareType IsGreaterOrEqualToSiblingValue(this SerializedProperty sp, string siblingFieldName, object siblingFieldValue)
{
if (string.IsNullOrEmpty(siblingFieldName))
return ECompareType.Unknown;
SerializedProperty spSibling = sp.GetRelativeProperty(siblingFieldName);
if (spSibling == null)
return ECompareType.Unknown;
if (spSibling.propertyType == SerializedPropertyType.Integer && siblingFieldValue is int i)
return spSibling.intValue <= i ? ECompareType.True : ECompareType.False;
if (spSibling.propertyType == SerializedPropertyType.Float && siblingFieldValue is float f)
return spSibling.floatValue <= f ? ECompareType.True : ECompareType.False;
if (spSibling.propertyType == SerializedPropertyType.Enum && siblingFieldValue is int e)
return spSibling.intValue <= e ? ECompareType.True : ECompareType.False;
return ECompareType.Unknown;
}
public static ECompareType IsSmallerOrEqualToSiblingValue(this SerializedProperty sp, string siblingFieldName)
{
if (string.IsNullOrEmpty(siblingFieldName))
return ECompareType.Unknown;
SerializedProperty spSibling = sp.GetRelativeProperty(siblingFieldName);
if (spSibling == null)
return ECompareType.Unknown;
if (spSibling.propertyType != sp.propertyType)
return ECompareType.Unknown;
if (sp.propertyType == SerializedPropertyType.Integer)
return sp.IsSmallerOrEqualToSiblingValue(siblingFieldName, sp.intValue);
if (sp.propertyType == SerializedPropertyType.Float)
return sp.IsSmallerOrEqualToSiblingValue(siblingFieldName, sp.floatValue);
if (sp.propertyType == SerializedPropertyType.Enum)
return sp.IsSmallerOrEqualToSiblingValue(siblingFieldName, sp.intValue);
return ECompareType.Unknown;
}
public static ECompareType IsSmallerOrEqualToSiblingValue(this SerializedProperty sp, string siblingFieldName, object siblingFieldValue)
{
if (string.IsNullOrEmpty(siblingFieldName))
return ECompareType.Unknown;
SerializedProperty spSibling = sp.GetRelativeProperty(siblingFieldName);
if (spSibling == null)
return ECompareType.Unknown;
if (spSibling.propertyType == SerializedPropertyType.Integer && siblingFieldValue is int i)
return spSibling.intValue >= i ? ECompareType.True : ECompareType.False;
if (spSibling.propertyType == SerializedPropertyType.Float && siblingFieldValue is float f)
return spSibling.floatValue >= f ? ECompareType.True : ECompareType.False;
if (spSibling.propertyType == SerializedPropertyType.Enum && siblingFieldValue is int e)
return spSibling.intValue >= e ? ECompareType.True : ECompareType.False;
return ECompareType.Unknown;
}
public static void SetValueTo(this SerializedProperty sp, SerializedProperty other)
{
if (sp.propertyType != other.propertyType)
return;
switch (sp.propertyType)
{
case SerializedPropertyType.LayerMask:
case SerializedPropertyType.Integer:
case SerializedPropertyType.Enum:
sp.intValue = other.intValue;
break;
case SerializedPropertyType.Boolean:
sp.boolValue = other.boolValue;
break;
case SerializedPropertyType.Float:
sp.floatValue = other.floatValue;
break;
case SerializedPropertyType.String:
sp.stringValue = other.stringValue;
break;
case SerializedPropertyType.Color:
sp.colorValue = other.colorValue;
break;
case SerializedPropertyType.ObjectReference:
sp.objectReferenceValue = other.objectReferenceValue;
break;
case SerializedPropertyType.Vector2:
sp.vector2Value = other.vector2Value;
break;
case SerializedPropertyType.Vector3:
sp.vector3Value = other.vector3Value;
break;
case SerializedPropertyType.Vector4:
sp.vector4Value = other.vector4Value;
break;
case SerializedPropertyType.Rect:
sp.rectValue = other.rectValue;
break;
case SerializedPropertyType.AnimationCurve:
sp.animationCurveValue = other.animationCurveValue;
break;
case SerializedPropertyType.Bounds:
sp.boundsValue = other.boundsValue;
break;
case SerializedPropertyType.Quaternion:
sp.quaternionValue = other.quaternionValue;
break;
case SerializedPropertyType.Vector2Int:
sp.vector2IntValue = other.vector2IntValue;
break;
case SerializedPropertyType.Vector3Int:
sp.vector3IntValue = other.vector3IntValue;
break;
case SerializedPropertyType.RectInt:
sp.rectIntValue = other.rectIntValue;
break;
case SerializedPropertyType.BoundsInt:
sp.boundsIntValue = other.boundsIntValue;
break;
}
}
public static bool TrySetValueTo(this SerializedProperty sp, object value, bool allowDuplicate)
{
if (sp.isArray && sp.propertyType != SerializedPropertyType.String)
{
if (!allowDuplicate && sp.Contains(value))
return true;
Type type = value.GetType();
if (!type.IsArray)
{
sp.InsertArrayElementAtIndex(sp.arraySize);
sp = sp.GetArrayElementAtIndex(sp.arraySize - 1);
}
}
switch (sp.propertyType)
{
case SerializedPropertyType.LayerMask:
case SerializedPropertyType.Integer:
case SerializedPropertyType.Enum:
if (!(value is int i))
return false;
sp.intValue = i;
return true;
case SerializedPropertyType.Boolean:
if (!(value is bool b))
return false;
sp.boolValue = b;
return true;
case SerializedPropertyType.Float:
if (!(value is float f))
return false;
sp.floatValue = f;
return true;
case SerializedPropertyType.String:
if (!(value is string str))
return false;
sp.stringValue = str;
return true;
case SerializedPropertyType.Color:
if (!(value is Color c))
return false;
sp.colorValue = c;
return true;
case SerializedPropertyType.ObjectReference:
if (!(value is Object o))
return false;
sp.objectReferenceValue = o;
return true;
case SerializedPropertyType.Vector2:
if (!(value is Vector2 v2))
return false;
sp.vector2Value = v2;
return true;
case SerializedPropertyType.Vector3:
if (!(value is Vector3 v3))
return false;
sp.vector3Value = v3;
return true;
case SerializedPropertyType.Vector4:
if (!(value is Vector4 v4))
return false;
sp.vector4Value = v4;
return true;
case SerializedPropertyType.Rect:
if (!(value is Rect r))
return false;
sp.rectValue = r;
return true;
case SerializedPropertyType.AnimationCurve:
if (!(value is AnimationCurve ac))
return false;
sp.animationCurveValue = ac;
return true;
case SerializedPropertyType.Bounds:
if (!(value is Bounds bounds))
return false;
sp.boundsValue = bounds;
return true;
case SerializedPropertyType.Quaternion:
if (!(value is Quaternion q))
return false;
sp.quaternionValue = q;
return true;
case SerializedPropertyType.Vector2Int:
if (!(value is Vector2Int v2i))
return false;
sp.vector2IntValue = v2i;
return true;
case SerializedPropertyType.Vector3Int:
if (!(value is Vector3Int v3i))
return false;
sp.vector3IntValue = v3i;
return true;
case SerializedPropertyType.RectInt:
if (!(value is RectInt ri))
return false;
sp.rectIntValue = ri;
return true;
case SerializedPropertyType.BoundsInt:
if (!(value is BoundsInt bi))
return false;
sp.boundsIntValue = bi;
return true;
}
return false;
}
private static bool Contains(this SerializedProperty sp, object value)
{
if (sp.isArray)
{
for (var i = 0; i < sp.arraySize; i++)
{
SerializedProperty temp = sp.GetArrayElementAtIndex(i);
if (temp.Contains(value))
return true;
}
}
else
{
try
{
switch (sp.propertyType)
{
case SerializedPropertyType.LayerMask:
case SerializedPropertyType.Integer:
case SerializedPropertyType.Enum:
return Convert.ToInt32(value) == sp.intValue;
case SerializedPropertyType.Boolean:
return Convert.ToBoolean(value) == sp.boolValue;
case SerializedPropertyType.Float:
return Mathf.Approximately(Convert.ToSingle(value), sp.floatValue);
case SerializedPropertyType.String:
return Convert.ToString(value).Equals(sp.stringValue);
case SerializedPropertyType.ObjectReference:
if (!(value is Object))
return false;
return sp.objectReferenceValue == (Object)value;
}
}
catch (Exception e)
{
Debug.LogException(e);
}
}
return false;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static string GetRootPath(string propertyPath)
{
int lastIndex = propertyPath.LastIndexOf('.');
return lastIndex != -1 ? propertyPath.Remove(lastIndex) : string.Empty;
}
public static T GetValue<T>(this SerializedProperty property) where T : class
{
return property.GetValue() as T;
}
private static object GetValue(this SerializedProperty property)
{
object obj = property.serializedObject.targetObject;
foreach (string path in property.propertyPath.Split('.'))
{
Type type = obj.GetType();
FieldInfo field = type.GetField(path);
obj = field.GetValue(obj);
}
return obj;
}
public static Type GetValueType(this SerializedProperty property)
{
object obj = property.serializedObject.targetObject;
Type type = null;
foreach (string path in property.propertyPath.Split('.'))
{
type = obj.GetType();
FieldInfo field = type.GetField(path);
obj = field.GetValue(obj);
type = field.FieldType;
}
return type;
}
public static void SetArray<T>(this SerializedProperty property, T[] array) where T : Object
{
property.ClearArray();
for (var i = 0; i < array.Length; i++)
{
property.InsertArrayElementAtIndex(i);
SerializedProperty sp = property.GetArrayElementAtIndex(i);
sp.objectReferenceValue = array[i];
}
}
}
}