-
-
Save capnslipp/8516384 to your computer and use it in GitHub Desktop.
| /// @creator: Slipp Douglas Thompson | |
| /// @license: Public Domain per The Unlicense. See <http://unlicense.org/>. | |
| /// @purpose: Genericized Unity3D SerializedProperty value access. | |
| /// @why: Because this functionality should be built-into Unity. | |
| /// @usage: Use as you would a native SerializedProperty method; | |
| /// e.g. `Debug.Log(mySerializedProperty.Value<Color>());` | |
| /// @intended project path: Assets/Plugins/Editor/UnityEditor Extensions/SerializedPropertyValueExtension.cs | |
| /// @interwebsouce: https://gist.github.com/capnslipp/8516384 | |
| using System; | |
| using System.Reflection; | |
| using System.Collections.Generic; // for: KeyValuePair<,> | |
| using UnityEngine; | |
| using UnityEditor; | |
| public static class SerializedPropertyValueExtension | |
| { | |
| /// @note: switch/case derived from the decompilation of SerializedProperty's internal SetToValueOfTarget() method. | |
| public static ValueT Value<ValueT>(this SerializedProperty thisSP) | |
| { | |
| Type valueType = typeof(ValueT); | |
| // First, do special Type checks | |
| if (valueType.IsEnum) | |
| return (ValueT)Enum.ToObject(valueType, thisSP.enumValueIndex); | |
| // Next, check for literal UnityEngine struct-types | |
| // @note: ->object->ValueT double-casts because C# is too dumb to realize that that the ValueT in each situation is the exact type needed. | |
| // e.g. `return thisSP.colorValue` spits _error CS0029: Cannot implicitly convert type `UnityEngine.Color' to `ValueT'_ | |
| // and `return (ValueT)thisSP.colorValue;` spits _error CS0030: Cannot convert type `UnityEngine.Color' to `ValueT'_ | |
| if (typeof(Color).IsAssignableFrom(valueType)) | |
| return (ValueT)(object)thisSP.colorValue; | |
| else if (typeof(LayerMask).IsAssignableFrom(valueType)) | |
| return (ValueT)(object)thisSP.intValue; | |
| else if (typeof(Vector2).IsAssignableFrom(valueType)) | |
| return (ValueT)(object)thisSP.vector2Value; | |
| else if (typeof(Vector3).IsAssignableFrom(valueType)) | |
| return (ValueT)(object)thisSP.vector3Value; | |
| else if (typeof(Rect).IsAssignableFrom(valueType)) | |
| return (ValueT)(object)thisSP.rectValue; | |
| else if (typeof(AnimationCurve).IsAssignableFrom(valueType)) | |
| return (ValueT)(object)thisSP.animationCurveValue; | |
| else if (typeof(Bounds).IsAssignableFrom(valueType)) | |
| return (ValueT)(object)thisSP.boundsValue; | |
| else if (typeof(Gradient).IsAssignableFrom(valueType)) | |
| return (ValueT)(object)SafeGradientValue(thisSP); | |
| else if (typeof(Quaternion).IsAssignableFrom(valueType)) | |
| return (ValueT)(object)thisSP.quaternionValue; | |
| // Next, check if derived from UnityEngine.Object base class | |
| if (typeof(UnityEngine.Object).IsAssignableFrom(valueType)) | |
| return (ValueT)(object)thisSP.objectReferenceValue; | |
| // Finally, check for native type-families | |
| if (typeof(int).IsAssignableFrom(valueType)) | |
| return (ValueT)(object)thisSP.intValue; | |
| else if (typeof(bool).IsAssignableFrom(valueType)) | |
| return (ValueT)(object)thisSP.boolValue; | |
| else if (typeof(float).IsAssignableFrom(valueType)) | |
| return (ValueT)(object)thisSP.floatValue; | |
| else if (typeof(string).IsAssignableFrom(valueType)) | |
| return (ValueT)(object)thisSP.stringValue; | |
| else if (typeof(char).IsAssignableFrom(valueType)) | |
| return (ValueT)(object)thisSP.intValue; | |
| // And if all fails, throw an exception. | |
| throw new NotImplementedException("Unimplemented propertyType "+thisSP.propertyType+"."); | |
| } | |
| public static dynamic Value(this SerializedProperty thisSP) | |
| { | |
| switch (thisSP.propertyType) { | |
| case SerializedPropertyType.Integer: | |
| return thisSP.intValue; | |
| case SerializedPropertyType.Boolean: | |
| return thisSP.boolValue; | |
| case SerializedPropertyType.Float: | |
| return thisSP.floatValue; | |
| case SerializedPropertyType.String: | |
| return thisSP.stringValue; | |
| case SerializedPropertyType.Color: | |
| return thisSP.colorValue; | |
| case SerializedPropertyType.ObjectReference: | |
| return thisSP.objectReferenceValue; | |
| case SerializedPropertyType.LayerMask: | |
| return thisSP.intValue; | |
| case SerializedPropertyType.Enum: | |
| int enumI = thisSP.enumValueIndex; | |
| return new KeyValuePair<int, string>(enumI, thisSP.enumNames[enumI]); | |
| case SerializedPropertyType.Vector2: | |
| return thisSP.vector2Value; | |
| case SerializedPropertyType.Vector3: | |
| return thisSP.vector3Value; | |
| case SerializedPropertyType.Rect: | |
| return thisSP.rectValue; | |
| case SerializedPropertyType.ArraySize: | |
| return thisSP.intValue; | |
| case SerializedPropertyType.Character: | |
| return (char)thisSP.intValue; | |
| case SerializedPropertyType.AnimationCurve: | |
| return thisSP.animationCurveValue; | |
| case SerializedPropertyType.Bounds: | |
| return thisSP.boundsValue; | |
| case SerializedPropertyType.Gradient: | |
| return SafeGradientValue(thisSP); | |
| case SerializedPropertyType.Quaternion: | |
| return thisSP.quaternionValue; | |
| default: | |
| throw new NotImplementedException("Unimplemented propertyType "+thisSP.propertyType+"."); | |
| } | |
| } | |
| /// Access to SerializedProperty's internal gradientValue property getter, in a manner that'll only soft break (returning null) if the property changes or disappears in future Unity revs. | |
| static Gradient SafeGradientValue(SerializedProperty sp) | |
| { | |
| BindingFlags instanceAnyPrivacyBindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance; | |
| PropertyInfo propertyInfo = typeof(SerializedProperty).GetProperty( | |
| "gradientValue", | |
| instanceAnyPrivacyBindingFlags, | |
| null, | |
| typeof(Gradient), | |
| new Type[0], | |
| null | |
| ); | |
| if (propertyInfo == null) | |
| return null; | |
| Gradient gradientValue = propertyInfo.GetValue(sp, null) as Gradient; | |
| return gradientValue; | |
| } | |
| } |
Usefull but for some reason when I try to use this for a LayerMask it gives the next error:
"InvalidCastException: Cannot cast from source type to destination type.
CustomPlugins.SerializedPropertyValueExtension.Value[LayerMask](UnityEditor.SerializedProperty thisSP) (at Assets/Plugins/SerializedPropertyValueExtension.cs:28)
PlayerCustomEditor.OnInspectorGUI () (at Assets/Editor/Player/PlayerCustomEditor.cs:35)
UnityEditor.InspectorWindow.DrawEditor (UnityEditor.Editor editor, Int32 editorIndex, Boolean forceDirty, System.Boolean& showImportedObjectBarNext, UnityEngine.Rect& importedObjectBarRect, Boolean eyeDropperDirty) (at C:/buildslave/unity/build/Editor/Mono/Inspector/InspectorWindow.cs:1162)
UnityEditor.DockArea:OnGUI()"
I testing with:
SerializedObject myScript = new SerializedObject(target);
SerializedProperty WhatIsGround = myScript.FindProperty("WhatIsGround");
Debug.Log(WhatIsGround.Value< LayerMask >());
public static dynamic Value(this SerializedProperty thisSP)
dynamic generates an error "Cannot define a class or member that utilizes 'dynamic' because the compiler required type 'System.Runtime.CompilerServices.DynamicAttribute' cannot be found. Are you missing a reference?"
How do I fix this? I'm using VisualStudio 2015 Enterprise Edition with Unity integration.
As long as I know the version of c# in Unity does not support dynamic which is available over c# 4.0
Hugely useful - thanks for this!