First commit for private source control. Older commits available on Github.
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
using UnityEngine;
|
||||
using System.Reflection;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace NaughtyAttributes.Editor
|
||||
{
|
||||
public static class ButtonUtility
|
||||
{
|
||||
public static bool IsEnabled(Object target, MethodInfo method)
|
||||
{
|
||||
EnableIfAttributeBase enableIfAttribute = method.GetCustomAttribute<EnableIfAttributeBase>();
|
||||
if (enableIfAttribute == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
List<bool> conditionValues = PropertyUtility.GetConditionValues(target, enableIfAttribute.Conditions);
|
||||
if (conditionValues.Count > 0)
|
||||
{
|
||||
bool enabled = PropertyUtility.GetConditionsFlag(conditionValues, enableIfAttribute.ConditionOperator, enableIfAttribute.Inverted);
|
||||
return enabled;
|
||||
}
|
||||
else
|
||||
{
|
||||
string message = enableIfAttribute.GetType().Name + " needs a valid boolean condition field, property or method name to work";
|
||||
Debug.LogWarning(message, target);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsVisible(Object target, MethodInfo method)
|
||||
{
|
||||
ShowIfAttributeBase showIfAttribute = method.GetCustomAttribute<ShowIfAttributeBase>();
|
||||
if (showIfAttribute == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
List<bool> conditionValues = PropertyUtility.GetConditionValues(target, showIfAttribute.Conditions);
|
||||
if (conditionValues.Count > 0)
|
||||
{
|
||||
bool enabled = PropertyUtility.GetConditionsFlag(conditionValues, showIfAttribute.ConditionOperator, showIfAttribute.Inverted);
|
||||
return enabled;
|
||||
}
|
||||
else
|
||||
{
|
||||
string message = showIfAttribute.GetType().Name + " needs a valid boolean condition field, property or method name to work";
|
||||
Debug.LogWarning(message, target);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a273f81125ec52d4cb5dec2228afda0e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 129996
|
||||
packageName: NaughtyAttributes
|
||||
packageVersion: 2.1.4
|
||||
assetPath: Assets/NaughtyAttributes/Scripts/Editor/Utility/ButtonUtility.cs
|
||||
uploadId: 480834
|
||||
@@ -0,0 +1,380 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Experimental.SceneManagement;
|
||||
using UnityEditor.SceneManagement;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NaughtyAttributes.Editor
|
||||
{
|
||||
public static class NaughtyEditorGUI
|
||||
{
|
||||
public const float IndentLength = 15.0f;
|
||||
public const float HorizontalSpacing = 2.0f;
|
||||
|
||||
private static GUIStyle _buttonStyle = new GUIStyle(GUI.skin.button) { richText = true };
|
||||
|
||||
private delegate void PropertyFieldFunction(Rect rect, SerializedProperty property, GUIContent label, bool includeChildren);
|
||||
|
||||
public static void PropertyField(Rect rect, SerializedProperty property, bool includeChildren)
|
||||
{
|
||||
PropertyField_Implementation(rect, property, includeChildren, DrawPropertyField);
|
||||
}
|
||||
|
||||
public static void PropertyField_Layout(SerializedProperty property, bool includeChildren)
|
||||
{
|
||||
Rect dummyRect = new Rect();
|
||||
PropertyField_Implementation(dummyRect, property, includeChildren, DrawPropertyField_Layout);
|
||||
}
|
||||
|
||||
private static void DrawPropertyField(Rect rect, SerializedProperty property, GUIContent label, bool includeChildren)
|
||||
{
|
||||
EditorGUI.PropertyField(rect, property, label, includeChildren);
|
||||
}
|
||||
|
||||
private static void DrawPropertyField_Layout(Rect rect, SerializedProperty property, GUIContent label, bool includeChildren)
|
||||
{
|
||||
EditorGUILayout.PropertyField(property, label, includeChildren);
|
||||
}
|
||||
|
||||
private static void PropertyField_Implementation(Rect rect, SerializedProperty property, bool includeChildren, PropertyFieldFunction propertyFieldFunction)
|
||||
{
|
||||
SpecialCaseDrawerAttribute specialCaseAttribute = PropertyUtility.GetAttribute<SpecialCaseDrawerAttribute>(property);
|
||||
if (specialCaseAttribute != null)
|
||||
{
|
||||
specialCaseAttribute.GetDrawer().OnGUI(rect, property);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check if visible
|
||||
bool visible = PropertyUtility.IsVisible(property);
|
||||
if (!visible)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate
|
||||
ValidatorAttribute[] validatorAttributes = PropertyUtility.GetAttributes<ValidatorAttribute>(property);
|
||||
foreach (var validatorAttribute in validatorAttributes)
|
||||
{
|
||||
validatorAttribute.GetValidator().ValidateProperty(property);
|
||||
}
|
||||
|
||||
// Check if enabled and draw
|
||||
EditorGUI.BeginChangeCheck();
|
||||
bool enabled = PropertyUtility.IsEnabled(property);
|
||||
|
||||
using (new EditorGUI.DisabledScope(disabled: !enabled))
|
||||
{
|
||||
propertyFieldFunction.Invoke(rect, property, PropertyUtility.GetLabel(property), includeChildren);
|
||||
}
|
||||
|
||||
// Call OnValueChanged callbacks
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
PropertyUtility.CallOnValueChangedCallbacks(property);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static float GetIndentLength(Rect sourceRect)
|
||||
{
|
||||
Rect indentRect = EditorGUI.IndentedRect(sourceRect);
|
||||
float indentLength = indentRect.x - sourceRect.x;
|
||||
|
||||
return indentLength;
|
||||
}
|
||||
|
||||
public static void BeginBoxGroup_Layout(string label = "")
|
||||
{
|
||||
EditorGUILayout.BeginVertical(GUI.skin.box);
|
||||
if (!string.IsNullOrEmpty(label))
|
||||
{
|
||||
EditorGUILayout.LabelField(label, EditorStyles.boldLabel);
|
||||
}
|
||||
}
|
||||
|
||||
public static void EndBoxGroup_Layout()
|
||||
{
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a dropdown
|
||||
/// </summary>
|
||||
/// <param name="rect">The rect the defines the position and size of the dropdown in the inspector</param>
|
||||
/// <param name="serializedObject">The serialized object that is being updated</param>
|
||||
/// <param name="target">The target object that contains the dropdown</param>
|
||||
/// <param name="dropdownField">The field of the target object that holds the currently selected dropdown value</param>
|
||||
/// <param name="label">The label of the dropdown</param>
|
||||
/// <param name="selectedValueIndex">The index of the value from the values array</param>
|
||||
/// <param name="values">The values of the dropdown</param>
|
||||
/// <param name="displayOptions">The display options for the values</param>
|
||||
public static void Dropdown(
|
||||
Rect rect, SerializedObject serializedObject, object target, FieldInfo dropdownField,
|
||||
string label, int selectedValueIndex, object[] values, string[] displayOptions)
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
int newIndex = EditorGUI.Popup(rect, label, selectedValueIndex, displayOptions);
|
||||
object newValue = values[newIndex];
|
||||
|
||||
object dropdownValue = dropdownField.GetValue(target);
|
||||
if (dropdownValue == null || !dropdownValue.Equals(newValue))
|
||||
{
|
||||
Undo.RecordObject(serializedObject.targetObject, "Dropdown");
|
||||
|
||||
// TODO: Problem with structs, because they are value type.
|
||||
// The solution is to make boxing/unboxing but unfortunately I don't know the compile time type of the target object
|
||||
dropdownField.SetValue(target, newValue);
|
||||
}
|
||||
}
|
||||
|
||||
public static void Button(UnityEngine.Object target, MethodInfo methodInfo)
|
||||
{
|
||||
bool visible = ButtonUtility.IsVisible(target, methodInfo);
|
||||
if (!visible)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (methodInfo.GetParameters().All(p => p.IsOptional))
|
||||
{
|
||||
ButtonAttribute buttonAttribute = (ButtonAttribute)methodInfo.GetCustomAttributes(typeof(ButtonAttribute), true)[0];
|
||||
string buttonText = string.IsNullOrEmpty(buttonAttribute.Text) ? ObjectNames.NicifyVariableName(methodInfo.Name) : buttonAttribute.Text;
|
||||
|
||||
bool buttonEnabled = ButtonUtility.IsEnabled(target, methodInfo);
|
||||
|
||||
EButtonEnableMode mode = buttonAttribute.SelectedEnableMode;
|
||||
buttonEnabled &=
|
||||
mode == EButtonEnableMode.Always ||
|
||||
mode == EButtonEnableMode.Editor && !Application.isPlaying ||
|
||||
mode == EButtonEnableMode.Playmode && Application.isPlaying;
|
||||
|
||||
bool methodIsCoroutine = methodInfo.ReturnType == typeof(IEnumerator);
|
||||
if (methodIsCoroutine)
|
||||
{
|
||||
buttonEnabled &= (Application.isPlaying ? true : false);
|
||||
}
|
||||
|
||||
EditorGUI.BeginDisabledGroup(!buttonEnabled);
|
||||
|
||||
if (GUILayout.Button(buttonText, _buttonStyle))
|
||||
{
|
||||
object[] defaultParams = methodInfo.GetParameters().Select(p => p.DefaultValue).ToArray();
|
||||
IEnumerator methodResult = methodInfo.Invoke(target, defaultParams) as IEnumerator;
|
||||
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
// Set target object and scene dirty to serialize changes to disk
|
||||
EditorUtility.SetDirty(target);
|
||||
|
||||
PrefabStage stage = PrefabStageUtility.GetCurrentPrefabStage();
|
||||
if (stage != null)
|
||||
{
|
||||
// Prefab mode
|
||||
EditorSceneManager.MarkSceneDirty(stage.scene);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Normal scene
|
||||
EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene());
|
||||
}
|
||||
}
|
||||
else if (methodResult != null && target is MonoBehaviour behaviour)
|
||||
{
|
||||
behaviour.StartCoroutine(methodResult);
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUI.EndDisabledGroup();
|
||||
}
|
||||
else
|
||||
{
|
||||
string warning = typeof(ButtonAttribute).Name + " works only on methods with no parameters";
|
||||
HelpBox_Layout(warning, MessageType.Warning, context: target, logToConsole: true);
|
||||
}
|
||||
}
|
||||
|
||||
public static void NativeProperty_Layout(UnityEngine.Object target, PropertyInfo property)
|
||||
{
|
||||
object value = property.GetValue(target, null);
|
||||
|
||||
if (value == null)
|
||||
{
|
||||
string warning = string.Format("{0} is null. {1} doesn't support reference types with null value", ObjectNames.NicifyVariableName(property.Name), typeof(ShowNativePropertyAttribute).Name);
|
||||
HelpBox_Layout(warning, MessageType.Warning, context: target);
|
||||
}
|
||||
else if (!Field_Layout(value, ObjectNames.NicifyVariableName(property.Name)))
|
||||
{
|
||||
string warning = string.Format("{0} doesn't support {1} types", typeof(ShowNativePropertyAttribute).Name, property.PropertyType.Name);
|
||||
HelpBox_Layout(warning, MessageType.Warning, context: target);
|
||||
}
|
||||
}
|
||||
|
||||
public static void NonSerializedField_Layout(UnityEngine.Object target, FieldInfo field)
|
||||
{
|
||||
object value = field.GetValue(target);
|
||||
|
||||
if (value == null)
|
||||
{
|
||||
string warning = string.Format("{0} is null. {1} doesn't support reference types with null value", ObjectNames.NicifyVariableName(field.Name), typeof(ShowNonSerializedFieldAttribute).Name);
|
||||
HelpBox_Layout(warning, MessageType.Warning, context: target);
|
||||
}
|
||||
else if (!Field_Layout(value, ObjectNames.NicifyVariableName(field.Name)))
|
||||
{
|
||||
string warning = string.Format("{0} doesn't support {1} types", typeof(ShowNonSerializedFieldAttribute).Name, field.FieldType.Name);
|
||||
HelpBox_Layout(warning, MessageType.Warning, context: target);
|
||||
}
|
||||
}
|
||||
|
||||
public static void HorizontalLine(Rect rect, float height, Color color)
|
||||
{
|
||||
rect.height = height;
|
||||
EditorGUI.DrawRect(rect, color);
|
||||
}
|
||||
|
||||
public static void HelpBox(Rect rect, string message, MessageType type, UnityEngine.Object context = null, bool logToConsole = false)
|
||||
{
|
||||
EditorGUI.HelpBox(rect, message, type);
|
||||
|
||||
if (logToConsole)
|
||||
{
|
||||
DebugLogMessage(message, type, context);
|
||||
}
|
||||
}
|
||||
|
||||
public static void HelpBox_Layout(string message, MessageType type, UnityEngine.Object context = null, bool logToConsole = false)
|
||||
{
|
||||
EditorGUILayout.HelpBox(message, type);
|
||||
|
||||
if (logToConsole)
|
||||
{
|
||||
DebugLogMessage(message, type, context);
|
||||
}
|
||||
}
|
||||
|
||||
public static bool Field_Layout(object value, string label)
|
||||
{
|
||||
using (new EditorGUI.DisabledScope(disabled: true))
|
||||
{
|
||||
bool isDrawn = true;
|
||||
Type valueType = value.GetType();
|
||||
|
||||
if (valueType == typeof(bool))
|
||||
{
|
||||
EditorGUILayout.Toggle(label, (bool)value);
|
||||
}
|
||||
else if (valueType == typeof(short))
|
||||
{
|
||||
EditorGUILayout.IntField(label, (short)value);
|
||||
}
|
||||
else if (valueType == typeof(ushort))
|
||||
{
|
||||
EditorGUILayout.IntField(label, (ushort)value);
|
||||
}
|
||||
else if (valueType == typeof(int))
|
||||
{
|
||||
EditorGUILayout.IntField(label, (int)value);
|
||||
}
|
||||
else if (valueType == typeof(uint))
|
||||
{
|
||||
EditorGUILayout.LongField(label, (uint)value);
|
||||
}
|
||||
else if (valueType == typeof(long))
|
||||
{
|
||||
EditorGUILayout.LongField(label, (long)value);
|
||||
}
|
||||
else if (valueType == typeof(ulong))
|
||||
{
|
||||
EditorGUILayout.TextField(label, ((ulong)value).ToString());
|
||||
}
|
||||
else if (valueType == typeof(float))
|
||||
{
|
||||
EditorGUILayout.FloatField(label, (float)value);
|
||||
}
|
||||
else if (valueType == typeof(double))
|
||||
{
|
||||
EditorGUILayout.DoubleField(label, (double)value);
|
||||
}
|
||||
else if (valueType == typeof(string))
|
||||
{
|
||||
EditorGUILayout.TextField(label, (string)value);
|
||||
}
|
||||
else if (valueType == typeof(Vector2))
|
||||
{
|
||||
EditorGUILayout.Vector2Field(label, (Vector2)value);
|
||||
}
|
||||
else if (valueType == typeof(Vector3))
|
||||
{
|
||||
EditorGUILayout.Vector3Field(label, (Vector3)value);
|
||||
}
|
||||
else if (valueType == typeof(Vector4))
|
||||
{
|
||||
EditorGUILayout.Vector4Field(label, (Vector4)value);
|
||||
}
|
||||
else if (valueType == typeof(Vector2Int))
|
||||
{
|
||||
EditorGUILayout.Vector2IntField(label, (Vector2Int)value);
|
||||
}
|
||||
else if (valueType == typeof(Vector3Int))
|
||||
{
|
||||
EditorGUILayout.Vector3IntField(label, (Vector3Int)value);
|
||||
}
|
||||
else if (valueType == typeof(Color))
|
||||
{
|
||||
EditorGUILayout.ColorField(label, (Color)value);
|
||||
}
|
||||
else if (valueType == typeof(Bounds))
|
||||
{
|
||||
EditorGUILayout.BoundsField(label, (Bounds)value);
|
||||
}
|
||||
else if (valueType == typeof(Rect))
|
||||
{
|
||||
EditorGUILayout.RectField(label, (Rect)value);
|
||||
}
|
||||
else if (valueType == typeof(RectInt))
|
||||
{
|
||||
EditorGUILayout.RectIntField(label, (RectInt)value);
|
||||
}
|
||||
else if (typeof(UnityEngine.Object).IsAssignableFrom(valueType))
|
||||
{
|
||||
EditorGUILayout.ObjectField(label, (UnityEngine.Object)value, valueType, true);
|
||||
}
|
||||
else if (valueType.BaseType == typeof(Enum))
|
||||
{
|
||||
EditorGUILayout.EnumPopup(label, (Enum)value);
|
||||
}
|
||||
else if (valueType.BaseType == typeof(System.Reflection.TypeInfo))
|
||||
{
|
||||
EditorGUILayout.TextField(label, value.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
isDrawn = false;
|
||||
}
|
||||
|
||||
return isDrawn;
|
||||
}
|
||||
}
|
||||
|
||||
private static void DebugLogMessage(string message, MessageType type, UnityEngine.Object context)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case MessageType.None:
|
||||
case MessageType.Info:
|
||||
Debug.Log(message, context);
|
||||
break;
|
||||
case MessageType.Warning:
|
||||
Debug.LogWarning(message, context);
|
||||
break;
|
||||
case MessageType.Error:
|
||||
Debug.LogError(message, context);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6ff27ff7705d6064e935bb2159a1b453
|
||||
timeCreated: 1510926159
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 129996
|
||||
packageName: NaughtyAttributes
|
||||
packageVersion: 2.1.4
|
||||
assetPath: Assets/NaughtyAttributes/Scripts/Editor/Utility/NaughtyEditorGUI.cs
|
||||
uploadId: 480834
|
||||
@@ -0,0 +1,374 @@
|
||||
using UnityEditor;
|
||||
using System.Reflection;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NaughtyAttributes.Editor
|
||||
{
|
||||
public static class PropertyUtility
|
||||
{
|
||||
public static T GetAttribute<T>(SerializedProperty property) where T : class
|
||||
{
|
||||
T[] attributes = GetAttributes<T>(property);
|
||||
return (attributes.Length > 0) ? attributes[0] : null;
|
||||
}
|
||||
|
||||
public static T[] GetAttributes<T>(SerializedProperty property) where T : class
|
||||
{
|
||||
FieldInfo fieldInfo = ReflectionUtility.GetField(GetTargetObjectWithProperty(property), property.name);
|
||||
if (fieldInfo == null)
|
||||
{
|
||||
return new T[] { };
|
||||
}
|
||||
|
||||
return (T[])fieldInfo.GetCustomAttributes(typeof(T), true);
|
||||
}
|
||||
|
||||
public static GUIContent GetLabel(SerializedProperty property)
|
||||
{
|
||||
LabelAttribute labelAttribute = GetAttribute<LabelAttribute>(property);
|
||||
string labelText = (labelAttribute == null)
|
||||
? property.displayName
|
||||
: labelAttribute.Label;
|
||||
|
||||
GUIContent label = new GUIContent(labelText);
|
||||
return label;
|
||||
}
|
||||
|
||||
public static void CallOnValueChangedCallbacks(SerializedProperty property)
|
||||
{
|
||||
OnValueChangedAttribute[] onValueChangedAttributes = GetAttributes<OnValueChangedAttribute>(property);
|
||||
if (onValueChangedAttributes.Length == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
object target = GetTargetObjectWithProperty(property);
|
||||
property.serializedObject.ApplyModifiedProperties(); // We must apply modifications so that the new value is updated in the serialized object
|
||||
|
||||
foreach (var onValueChangedAttribute in onValueChangedAttributes)
|
||||
{
|
||||
MethodInfo callbackMethod = ReflectionUtility.GetMethod(target, onValueChangedAttribute.CallbackName);
|
||||
if (callbackMethod != null &&
|
||||
callbackMethod.ReturnType == typeof(void) &&
|
||||
callbackMethod.GetParameters().Length == 0)
|
||||
{
|
||||
callbackMethod.Invoke(target, new object[] { });
|
||||
}
|
||||
else
|
||||
{
|
||||
string warning = string.Format(
|
||||
"{0} can invoke only methods with 'void' return type and 0 parameters",
|
||||
onValueChangedAttribute.GetType().Name);
|
||||
|
||||
Debug.LogWarning(warning, property.serializedObject.targetObject);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsEnabled(SerializedProperty property)
|
||||
{
|
||||
ReadOnlyAttribute readOnlyAttribute = GetAttribute<ReadOnlyAttribute>(property);
|
||||
if (readOnlyAttribute != null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
EnableIfAttributeBase enableIfAttribute = GetAttribute<EnableIfAttributeBase>(property);
|
||||
if (enableIfAttribute == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
object target = GetTargetObjectWithProperty(property);
|
||||
|
||||
// deal with enum conditions
|
||||
if (enableIfAttribute.EnumValue != null)
|
||||
{
|
||||
Enum value = GetEnumValue(target, enableIfAttribute.Conditions[0]);
|
||||
if (value != null)
|
||||
{
|
||||
bool matched = value.GetType().GetCustomAttribute<FlagsAttribute>() == null
|
||||
? enableIfAttribute.EnumValue.Equals(value)
|
||||
: value.HasFlag(enableIfAttribute.EnumValue);
|
||||
|
||||
return matched != enableIfAttribute.Inverted;
|
||||
}
|
||||
|
||||
string message = enableIfAttribute.GetType().Name + " needs a valid enum field, property or method name to work";
|
||||
Debug.LogWarning(message, property.serializedObject.targetObject);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// deal with normal conditions
|
||||
List<bool> conditionValues = GetConditionValues(target, enableIfAttribute.Conditions);
|
||||
if (conditionValues.Count > 0)
|
||||
{
|
||||
bool enabled = GetConditionsFlag(conditionValues, enableIfAttribute.ConditionOperator, enableIfAttribute.Inverted);
|
||||
return enabled;
|
||||
}
|
||||
else
|
||||
{
|
||||
string message = enableIfAttribute.GetType().Name + " needs a valid boolean condition field, property or method name to work";
|
||||
Debug.LogWarning(message, property.serializedObject.targetObject);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool IsVisible(SerializedProperty property)
|
||||
{
|
||||
ShowIfAttributeBase showIfAttribute = GetAttribute<ShowIfAttributeBase>(property);
|
||||
if (showIfAttribute == null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
object target = GetTargetObjectWithProperty(property);
|
||||
|
||||
// deal with enum conditions
|
||||
if (showIfAttribute.EnumValue != null)
|
||||
{
|
||||
Enum value = GetEnumValue(target, showIfAttribute.Conditions[0]);
|
||||
if (value != null)
|
||||
{
|
||||
bool matched = value.GetType().GetCustomAttribute<FlagsAttribute>() == null
|
||||
? showIfAttribute.EnumValue.Equals(value)
|
||||
: value.HasFlag(showIfAttribute.EnumValue);
|
||||
|
||||
return matched != showIfAttribute.Inverted;
|
||||
}
|
||||
|
||||
string message = showIfAttribute.GetType().Name + " needs a valid enum field, property or method name to work";
|
||||
Debug.LogWarning(message, property.serializedObject.targetObject);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// deal with normal conditions
|
||||
List<bool> conditionValues = GetConditionValues(target, showIfAttribute.Conditions);
|
||||
if (conditionValues.Count > 0)
|
||||
{
|
||||
bool enabled = GetConditionsFlag(conditionValues, showIfAttribute.ConditionOperator, showIfAttribute.Inverted);
|
||||
return enabled;
|
||||
}
|
||||
else
|
||||
{
|
||||
string message = showIfAttribute.GetType().Name + " needs a valid boolean condition field, property or method name to work";
|
||||
Debug.LogWarning(message, property.serializedObject.targetObject);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an enum value from reflection.
|
||||
/// </summary>
|
||||
/// <param name="target">The target object.</param>
|
||||
/// <param name="enumName">Name of a field, property, or method that returns an enum.</param>
|
||||
/// <returns>Null if can't find an enum value.</returns>
|
||||
internal static Enum GetEnumValue(object target, string enumName)
|
||||
{
|
||||
FieldInfo enumField = ReflectionUtility.GetField(target, enumName);
|
||||
if (enumField != null && enumField.FieldType.IsSubclassOf(typeof(Enum)))
|
||||
{
|
||||
return (Enum)enumField.GetValue(target);
|
||||
}
|
||||
|
||||
PropertyInfo enumProperty = ReflectionUtility.GetProperty(target, enumName);
|
||||
if (enumProperty != null && enumProperty.PropertyType.IsSubclassOf(typeof(Enum)))
|
||||
{
|
||||
return (Enum)enumProperty.GetValue(target);
|
||||
}
|
||||
|
||||
MethodInfo enumMethod = ReflectionUtility.GetMethod(target, enumName);
|
||||
if (enumMethod != null && enumMethod.ReturnType.IsSubclassOf(typeof(Enum)))
|
||||
{
|
||||
return (Enum)enumMethod.Invoke(target, null);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
internal static List<bool> GetConditionValues(object target, string[] conditions)
|
||||
{
|
||||
List<bool> conditionValues = new List<bool>();
|
||||
foreach (var condition in conditions)
|
||||
{
|
||||
FieldInfo conditionField = ReflectionUtility.GetField(target, condition);
|
||||
if (conditionField != null &&
|
||||
conditionField.FieldType == typeof(bool))
|
||||
{
|
||||
conditionValues.Add((bool)conditionField.GetValue(target));
|
||||
}
|
||||
|
||||
PropertyInfo conditionProperty = ReflectionUtility.GetProperty(target, condition);
|
||||
if (conditionProperty != null &&
|
||||
conditionProperty.PropertyType == typeof(bool))
|
||||
{
|
||||
conditionValues.Add((bool)conditionProperty.GetValue(target));
|
||||
}
|
||||
|
||||
MethodInfo conditionMethod = ReflectionUtility.GetMethod(target, condition);
|
||||
if (conditionMethod != null &&
|
||||
conditionMethod.ReturnType == typeof(bool) &&
|
||||
conditionMethod.GetParameters().Length == 0)
|
||||
{
|
||||
conditionValues.Add((bool)conditionMethod.Invoke(target, null));
|
||||
}
|
||||
}
|
||||
|
||||
return conditionValues;
|
||||
}
|
||||
|
||||
internal static bool GetConditionsFlag(List<bool> conditionValues, EConditionOperator conditionOperator, bool invert)
|
||||
{
|
||||
bool flag;
|
||||
if (conditionOperator == EConditionOperator.And)
|
||||
{
|
||||
flag = true;
|
||||
foreach (var value in conditionValues)
|
||||
{
|
||||
flag = flag && value;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
flag = false;
|
||||
foreach (var value in conditionValues)
|
||||
{
|
||||
flag = flag || value;
|
||||
}
|
||||
}
|
||||
|
||||
if (invert)
|
||||
{
|
||||
flag = !flag;
|
||||
}
|
||||
|
||||
return flag;
|
||||
}
|
||||
|
||||
public static Type GetPropertyType(SerializedProperty property)
|
||||
{
|
||||
object obj = GetTargetObjectOfProperty(property);
|
||||
Type objType = obj.GetType();
|
||||
|
||||
return objType;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the object the property represents.
|
||||
/// </summary>
|
||||
/// <param name="property"></param>
|
||||
/// <returns></returns>
|
||||
public static object GetTargetObjectOfProperty(SerializedProperty property)
|
||||
{
|
||||
if (property == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
string path = property.propertyPath.Replace(".Array.data[", "[");
|
||||
object obj = property.serializedObject.targetObject;
|
||||
string[] elements = path.Split('.');
|
||||
|
||||
foreach (var element in elements)
|
||||
{
|
||||
if (element.Contains("["))
|
||||
{
|
||||
string elementName = element.Substring(0, element.IndexOf("["));
|
||||
int index = Convert.ToInt32(element.Substring(element.IndexOf("[")).Replace("[", "").Replace("]", ""));
|
||||
obj = GetValue_Imp(obj, elementName, index);
|
||||
}
|
||||
else
|
||||
{
|
||||
obj = GetValue_Imp(obj, element);
|
||||
}
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the object that the property is a member of
|
||||
/// </summary>
|
||||
/// <param name="property"></param>
|
||||
/// <returns></returns>
|
||||
public static object GetTargetObjectWithProperty(SerializedProperty property)
|
||||
{
|
||||
string path = property.propertyPath.Replace(".Array.data[", "[");
|
||||
object obj = property.serializedObject.targetObject;
|
||||
string[] elements = path.Split('.');
|
||||
|
||||
for (int i = 0; i < elements.Length - 1; i++)
|
||||
{
|
||||
string element = elements[i];
|
||||
if (element.Contains("["))
|
||||
{
|
||||
string elementName = element.Substring(0, element.IndexOf("["));
|
||||
int index = Convert.ToInt32(element.Substring(element.IndexOf("[")).Replace("[", "").Replace("]", ""));
|
||||
obj = GetValue_Imp(obj, elementName, index);
|
||||
}
|
||||
else
|
||||
{
|
||||
obj = GetValue_Imp(obj, element);
|
||||
}
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
private static object GetValue_Imp(object source, string name)
|
||||
{
|
||||
if (source == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
Type type = source.GetType();
|
||||
|
||||
while (type != null)
|
||||
{
|
||||
FieldInfo field = type.GetField(name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
|
||||
if (field != null)
|
||||
{
|
||||
return field.GetValue(source);
|
||||
}
|
||||
|
||||
PropertyInfo property = type.GetProperty(name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
|
||||
if (property != null)
|
||||
{
|
||||
return property.GetValue(source, null);
|
||||
}
|
||||
|
||||
type = type.BaseType;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static object GetValue_Imp(object source, string name, int index)
|
||||
{
|
||||
IEnumerable enumerable = GetValue_Imp(source, name) as IEnumerable;
|
||||
if (enumerable == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
IEnumerator enumerator = enumerable.GetEnumerator();
|
||||
for (int i = 0; i <= index; i++)
|
||||
{
|
||||
if (!enumerator.MoveNext())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return enumerator.Current;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 312eedcb79c7a5542b87c0b848e3e2fa
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 129996
|
||||
packageName: NaughtyAttributes
|
||||
packageVersion: 2.1.4
|
||||
assetPath: Assets/NaughtyAttributes/Scripts/Editor/Utility/PropertyUtility.cs
|
||||
uploadId: 480834
|
||||
@@ -0,0 +1,128 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NaughtyAttributes.Editor
|
||||
{
|
||||
public static class ReflectionUtility
|
||||
{
|
||||
public static IEnumerable<FieldInfo> GetAllFields(object target, Func<FieldInfo, bool> predicate)
|
||||
{
|
||||
if (target == null)
|
||||
{
|
||||
Debug.LogError("The target object is null. Check for missing scripts.");
|
||||
yield break;
|
||||
}
|
||||
|
||||
List<Type> types = GetSelfAndBaseTypes(target);
|
||||
|
||||
for (int i = types.Count - 1; i >= 0; i--)
|
||||
{
|
||||
IEnumerable<FieldInfo> fieldInfos = types[i]
|
||||
.GetFields(BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.DeclaredOnly)
|
||||
.Where(predicate);
|
||||
|
||||
foreach (var fieldInfo in fieldInfos)
|
||||
{
|
||||
yield return fieldInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<PropertyInfo> GetAllProperties(object target, Func<PropertyInfo, bool> predicate)
|
||||
{
|
||||
if (target == null)
|
||||
{
|
||||
Debug.LogError("The target object is null. Check for missing scripts.");
|
||||
yield break;
|
||||
}
|
||||
|
||||
List<Type> types = GetSelfAndBaseTypes(target);
|
||||
|
||||
for (int i = types.Count - 1; i >= 0; i--)
|
||||
{
|
||||
IEnumerable<PropertyInfo> propertyInfos = types[i]
|
||||
.GetProperties(BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.DeclaredOnly)
|
||||
.Where(predicate);
|
||||
|
||||
foreach (var propertyInfo in propertyInfos)
|
||||
{
|
||||
yield return propertyInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerable<MethodInfo> GetAllMethods(object target, Func<MethodInfo, bool> predicate)
|
||||
{
|
||||
if (target == null)
|
||||
{
|
||||
Debug.LogError("The target object is null. Check for missing scripts.");
|
||||
yield break;
|
||||
}
|
||||
|
||||
List<Type> types = GetSelfAndBaseTypes(target);
|
||||
|
||||
for (int i = types.Count - 1; i >= 0; i--)
|
||||
{
|
||||
IEnumerable<MethodInfo> methodInfos = types[i]
|
||||
.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.DeclaredOnly)
|
||||
.Where(predicate);
|
||||
|
||||
foreach (var methodInfo in methodInfos)
|
||||
{
|
||||
yield return methodInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static FieldInfo GetField(object target, string fieldName)
|
||||
{
|
||||
return GetAllFields(target, f => f.Name.Equals(fieldName, StringComparison.Ordinal)).FirstOrDefault();
|
||||
}
|
||||
|
||||
public static PropertyInfo GetProperty(object target, string propertyName)
|
||||
{
|
||||
return GetAllProperties(target, p => p.Name.Equals(propertyName, StringComparison.Ordinal)).FirstOrDefault();
|
||||
}
|
||||
|
||||
public static MethodInfo GetMethod(object target, string methodName)
|
||||
{
|
||||
return GetAllMethods(target, m => m.Name.Equals(methodName, StringComparison.Ordinal)).FirstOrDefault();
|
||||
}
|
||||
|
||||
public static Type GetListElementType(Type listType)
|
||||
{
|
||||
if (listType.IsGenericType)
|
||||
{
|
||||
return listType.GetGenericArguments()[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
return listType.GetElementType();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get type and all base types of target, sorted as following:
|
||||
/// <para />[target's type, base type, base's base type, ...]
|
||||
/// </summary>
|
||||
/// <param name="target"></param>
|
||||
/// <returns></returns>
|
||||
private static List<Type> GetSelfAndBaseTypes(object target)
|
||||
{
|
||||
List<Type> types = new List<Type>()
|
||||
{
|
||||
target.GetType()
|
||||
};
|
||||
|
||||
while (types.Last().BaseType != null)
|
||||
{
|
||||
types.Add(types.Last().BaseType);
|
||||
}
|
||||
|
||||
return types;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1d86c581f02a55f458e36bf7e81e3084
|
||||
timeCreated: 1520258793
|
||||
licenseType: Store
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 129996
|
||||
packageName: NaughtyAttributes
|
||||
packageVersion: 2.1.4
|
||||
assetPath: Assets/NaughtyAttributes/Scripts/Editor/Utility/ReflectionUtility.cs
|
||||
uploadId: 480834
|
||||
@@ -0,0 +1,34 @@
|
||||
using UnityEditor;
|
||||
|
||||
namespace NaughtyAttributes.Editor
|
||||
{
|
||||
internal class SavedBool
|
||||
{
|
||||
private bool _value;
|
||||
private string _name;
|
||||
|
||||
public bool Value
|
||||
{
|
||||
get
|
||||
{
|
||||
return _value;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_value == value)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_value = value;
|
||||
EditorPrefs.SetBool(_name, value);
|
||||
}
|
||||
}
|
||||
|
||||
public SavedBool(string name, bool value)
|
||||
{
|
||||
_name = name;
|
||||
_value = EditorPrefs.GetBool(name, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 18613afe66b0c0344a2be5f430bf965a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 129996
|
||||
packageName: NaughtyAttributes
|
||||
packageVersion: 2.1.4
|
||||
assetPath: Assets/NaughtyAttributes/Scripts/Editor/Utility/SavedBool.cs
|
||||
uploadId: 480834
|
||||
Reference in New Issue
Block a user