First Commit
This commit is contained in:
23
Assets/Attributes/Button.cs
Normal file
23
Assets/Attributes/Button.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
|
||||
namespace Golems.Attributes
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds an Inspector Button which Invokes
|
||||
/// decorated methods
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
|
||||
public class Button : Attribute
|
||||
{
|
||||
public string Ident = "";
|
||||
|
||||
public Button()
|
||||
{
|
||||
}
|
||||
|
||||
public Button(string ident)
|
||||
{
|
||||
Ident = ident;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Attributes/Button.cs.meta
Normal file
11
Assets/Attributes/Button.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f89f456d36a348344b864d363f48d953
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
44
Assets/Attributes/DrawIf.cs
Normal file
44
Assets/Attributes/DrawIf.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
using UnityEngine;
|
||||
using System;
|
||||
|
||||
namespace Golems.Attributes
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Draws the field/property ONLY if the compared property compared by the comparison type with the value of comparedValue returns true.
|
||||
/// Based on: https://forum.unity.com/threads/draw-a-field-only-if-a-condition-is-met.448855/
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = true)]
|
||||
public class DrawIfAttribute : PropertyAttribute
|
||||
{
|
||||
#region Fields
|
||||
|
||||
public string comparedPropertyName { get; private set; }
|
||||
public object comparedValue { get; private set; }
|
||||
public DisablingType disablingType { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Types of comperisons.
|
||||
/// </summary>
|
||||
public enum DisablingType
|
||||
{
|
||||
ReadOnly = 2,
|
||||
DontDraw = 3
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Only draws the field only if a condition is met. Supports enum and bools.
|
||||
/// </summary>
|
||||
/// <param name="comparedPropertyName">The name of the property that is being compared (case sensitive).</param>
|
||||
/// <param name="comparedValue">The value the property is being compared to.</param>
|
||||
/// <param name="disablingType">The type of disabling that should happen if the condition is NOT met. Defaulted to DisablingType.DontDraw.</param>
|
||||
public DrawIfAttribute(string comparedPropertyName, object comparedValue, DisablingType disablingType = DisablingType.DontDraw)
|
||||
{
|
||||
this.comparedPropertyName = comparedPropertyName;
|
||||
this.comparedValue = comparedValue;
|
||||
this.disablingType = disablingType;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Attributes/DrawIf.cs.meta
Normal file
11
Assets/Attributes/DrawIf.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 50c83007ce1d47648bcadd778ed48e91
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Attributes/Editor.meta
Normal file
8
Assets/Attributes/Editor.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: de1de1091ea1b8d4ba479915afce8358
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
35
Assets/Attributes/Editor/AttributesEditor.cs
Normal file
35
Assets/Attributes/Editor/AttributesEditor.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace Golems
|
||||
{
|
||||
/// <summary>
|
||||
/// Custom Editor for All Objects.
|
||||
/// Checks for any custom RS Attributes.
|
||||
/// *F Odin*
|
||||
/// </summary>
|
||||
[CustomEditor(typeof(Object), true)]
|
||||
public partial class AttributesEditor : UnityEditor.Editor
|
||||
{
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
//
|
||||
// Button Attribute for automatic Inspector Buttons on
|
||||
//
|
||||
OnInspectorGUIButtonAttribute();
|
||||
//
|
||||
// OnValueChanged Attribute for callback on Field Value Changes
|
||||
//
|
||||
OnInspectorGUIOnValueChangedAttribute();
|
||||
|
||||
//
|
||||
// ShowLevelAttribute
|
||||
//
|
||||
OnInspectorGUIShowLevelAttribute();
|
||||
base.OnInspectorGUI();
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Attributes/Editor/AttributesEditor.cs.meta
Normal file
11
Assets/Attributes/Editor/AttributesEditor.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 027fb565513fdd248b0c17fc81c6ca53
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
184
Assets/Attributes/Editor/ButtonEditor.cs
Normal file
184
Assets/Attributes/Editor/ButtonEditor.cs
Normal file
@@ -0,0 +1,184 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using Golems.Attributes;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace Golems
|
||||
{
|
||||
public partial class AttributesEditor
|
||||
{
|
||||
private const BindingFlags k_ButtonBindingFlags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public |
|
||||
BindingFlags.NonPublic;
|
||||
|
||||
/// <summary>
|
||||
/// Map between Method names and parameters for Methods
|
||||
/// </summary>
|
||||
private Dictionary<string, object[]> m_Parameters = new Dictionary<string, object[]>();
|
||||
|
||||
private void OnInspectorGUIButtonAttribute ()
|
||||
{
|
||||
var methods = target.GetType().GetMethods(k_ButtonBindingFlags);
|
||||
|
||||
//
|
||||
// Search for Button Attribute within Each Method on this Object
|
||||
//
|
||||
for (int i = 0, counti = methods.Length; i < counti; ++i)
|
||||
{
|
||||
var method = methods[i];
|
||||
var buttonAttribute = method.GetCustomAttribute<Button>(false);
|
||||
if (buttonAttribute == null)
|
||||
continue;
|
||||
|
||||
var name = string.IsNullOrEmpty(buttonAttribute.Ident) ? method.Name : buttonAttribute.Ident;
|
||||
//
|
||||
// Invoke Method with parms on button pressed
|
||||
//
|
||||
if (GUILayout.Button(name))
|
||||
{
|
||||
m_Parameters.TryGetValue(name, out var parms);
|
||||
if (parms != null)
|
||||
{
|
||||
var p = new List<object>();
|
||||
for (int j = 0, countj = parms.Length; j < countj; ++j)
|
||||
{
|
||||
p.Add(parms[j]);
|
||||
//
|
||||
// Skip over array size
|
||||
//
|
||||
if (parms[j].GetType().IsArray) ++j;
|
||||
}
|
||||
method.Invoke(target, p.ToArray());
|
||||
} else method.Invoke(target, parms);
|
||||
}
|
||||
EditorGUI.indentLevel++;
|
||||
SetUpParameters(name, method);
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set up Parameters for use on Method Invocation
|
||||
/// </summary>
|
||||
private void SetUpParameters(string name, MethodInfo method)
|
||||
{
|
||||
var parameterInfo = method.GetParameters();
|
||||
if (parameterInfo.Length <= 0) return;
|
||||
|
||||
//
|
||||
// Check if Method has already has its parameters setup.
|
||||
// If not create a new array and add to dict.
|
||||
//
|
||||
if (!m_Parameters.TryGetValue(name, out var parameters))
|
||||
{
|
||||
var p = new List<object>(parameterInfo.Length);
|
||||
for (int i = 0, counti = parameterInfo.Length; i < counti; ++i)
|
||||
{
|
||||
p.Add(default);
|
||||
|
||||
//
|
||||
// If we have an Array add an additional parameter for size
|
||||
//
|
||||
if (parameterInfo[i].ParameterType.IsArray)
|
||||
{
|
||||
p.Add(default);
|
||||
}
|
||||
}
|
||||
m_Parameters.Add(name, p.ToArray());
|
||||
}
|
||||
|
||||
if (parameters == null) return;
|
||||
|
||||
//
|
||||
// Iterate over each parameter and set up relevant display Field.
|
||||
//
|
||||
for (int i = 0, counti = parameters.Length, pi = 0; i < counti; ++i, ++pi)
|
||||
{
|
||||
var paramName = parameterInfo[pi].Name;
|
||||
if (parameterInfo[pi].ParameterType == typeof(int))
|
||||
{
|
||||
int val = parameters[i] == null ? 0 : (int)parameters[i];
|
||||
parameters[i] = EditorGUILayout.IntField(paramName, val);
|
||||
}
|
||||
else if (parameterInfo[pi].ParameterType == typeof(float))
|
||||
{
|
||||
float val = parameters[i] == null ? 0 : (float)parameters[i];
|
||||
parameters[i] = EditorGUILayout.FloatField(paramName, val);
|
||||
}
|
||||
else if (parameterInfo[pi].ParameterType == typeof(string))
|
||||
{
|
||||
string val = String.IsNullOrEmpty((string)parameters[i]) ? "" : (string)parameters[i];
|
||||
parameters[i] = EditorGUILayout.TextField(paramName, val);
|
||||
}
|
||||
else if (parameterInfo[pi].ParameterType == typeof(bool))
|
||||
{
|
||||
bool val = parameters[i] != null && (bool)parameters[i];
|
||||
parameters[i] = EditorGUILayout.Toggle(paramName, val);
|
||||
}
|
||||
else if (parameterInfo[pi].ParameterType == typeof(char))
|
||||
{
|
||||
string val = "";
|
||||
if (parameters[i] != null)
|
||||
{
|
||||
val = ((char)parameters[i]).ToString();
|
||||
}
|
||||
|
||||
val = EditorGUILayout.TextField(paramName, val);
|
||||
if (!String.IsNullOrEmpty(val))
|
||||
{
|
||||
parameters[i] = val[0];
|
||||
}
|
||||
}
|
||||
else if (parameterInfo[pi].ParameterType == typeof(Sprite))
|
||||
{
|
||||
Sprite val = parameters[i] != null ? (Sprite)parameters[i] : default;
|
||||
parameters[i] = EditorGUILayout.ObjectField(paramName, val, typeof(Sprite), false) as Sprite;
|
||||
}
|
||||
else
|
||||
{
|
||||
//
|
||||
// GameObject Array support - copy me around if we want more Inspector Button Arrays
|
||||
//
|
||||
if (parameterInfo[pi].ParameterType.IsArray)
|
||||
{
|
||||
//
|
||||
// We can Safely assume next item is index
|
||||
//
|
||||
var arraySizeIndex = i + 1;
|
||||
int size = parameters[arraySizeIndex] == null ? 0 : (int)parameters[arraySizeIndex];
|
||||
parameters[arraySizeIndex] = EditorGUILayout.IntField($"{paramName} Size: ", size);
|
||||
|
||||
var arrayParameter = (GameObject[]) parameters[i] ?? new GameObject[0];
|
||||
|
||||
if (arrayParameter.Length != size)
|
||||
{
|
||||
Array.Resize(ref arrayParameter, size);
|
||||
}
|
||||
|
||||
EditorGUI.indentLevel++;
|
||||
for (int j = 0, countj = size; j < countj; ++j)
|
||||
{
|
||||
GameObject val = arrayParameter[j] == null ? default : arrayParameter[j];
|
||||
arrayParameter[j] = EditorGUILayout.ObjectField($"{paramName} - {j}", val, typeof(UnityEngine.GameObject), true) as GameObject;
|
||||
}
|
||||
EditorGUI.indentLevel--;
|
||||
|
||||
parameters[i] = arrayParameter;
|
||||
|
||||
//
|
||||
// Advance an extra step to skip Array size
|
||||
//
|
||||
++i;
|
||||
}
|
||||
else
|
||||
{
|
||||
GameObject val = (UnityEngine.GameObject) parameters[i];
|
||||
parameters[i] = EditorGUILayout.ObjectField(paramName, val, parameterInfo[pi].ParameterType, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Attributes/Editor/ButtonEditor.cs.meta
Normal file
11
Assets/Attributes/Editor/ButtonEditor.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dc40108d26c2d2a4e97b205ed11e0666
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
77
Assets/Attributes/Editor/DrawIfPropertyDraw.cs
Normal file
77
Assets/Attributes/Editor/DrawIfPropertyDraw.cs
Normal file
@@ -0,0 +1,77 @@
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Golems.Attributes
|
||||
{
|
||||
/// <summary>
|
||||
/// Based on: https://forum.unity.com/threads/draw-a-field-only-if-a-condition-is-met.448855/
|
||||
/// </summary>
|
||||
[CustomPropertyDrawer(typeof(DrawIfAttribute))]
|
||||
public class DrawIfPropertyDrawer : PropertyDrawer
|
||||
{
|
||||
#region Fields
|
||||
|
||||
// Reference to the attribute on the property.
|
||||
DrawIfAttribute drawIf;
|
||||
|
||||
// Field that is being compared.
|
||||
SerializedProperty comparedField;
|
||||
|
||||
#endregion
|
||||
|
||||
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
|
||||
{
|
||||
if (!ShowMe(property) && drawIf.disablingType == DrawIfAttribute.DisablingType.DontDraw)
|
||||
return 0f;
|
||||
|
||||
// The height of the property should be defaulted to the default height.
|
||||
return base.GetPropertyHeight(property, label);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Errors default to showing the property.
|
||||
/// </summary>
|
||||
private bool ShowMe(SerializedProperty property)
|
||||
{
|
||||
drawIf = attribute as DrawIfAttribute;
|
||||
// Replace propertyname to the value from the parameter
|
||||
string path = property.propertyPath.Contains(".") ? System.IO.Path.ChangeExtension(property.propertyPath, drawIf.comparedPropertyName) : drawIf.comparedPropertyName;
|
||||
|
||||
comparedField = property.serializedObject.FindProperty(path);
|
||||
|
||||
if (comparedField == null)
|
||||
{
|
||||
Debug.LogError("Cannot find property with name: " + path);
|
||||
return true;
|
||||
}
|
||||
|
||||
// get the value & compare based on types
|
||||
switch (comparedField.type)
|
||||
{ // Possible extend cases to support your own type
|
||||
case "bool":
|
||||
return comparedField.boolValue.Equals(drawIf.comparedValue);
|
||||
case "Enum":
|
||||
return comparedField.enumValueIndex.Equals((int)drawIf.comparedValue);
|
||||
default:
|
||||
Debug.LogError("Error: " + comparedField.type + " is not supported of " + path);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
||||
{
|
||||
// If the condition is met, simply draw the field.
|
||||
if (ShowMe(property))
|
||||
{
|
||||
EditorGUI.PropertyField(position, property, new GUIContent($"{property.displayName}:"));
|
||||
} //...check if the disabling type is read only. If it is, draw it disabled
|
||||
else if (drawIf.disablingType == DrawIfAttribute.DisablingType.ReadOnly)
|
||||
{
|
||||
GUI.enabled = false;
|
||||
EditorGUI.PropertyField(position, property);
|
||||
GUI.enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
11
Assets/Attributes/Editor/DrawIfPropertyDraw.cs.meta
Normal file
11
Assets/Attributes/Editor/DrawIfPropertyDraw.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 055d2af24e193c44e85989dfd4427361
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
47
Assets/Attributes/Editor/EnumFlagDrawer.cs
Normal file
47
Assets/Attributes/Editor/EnumFlagDrawer.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Golems
|
||||
{
|
||||
// http://wiki.unity3d.com/index.php?title=EnumFlagPropertyDrawer&oldid=19986S
|
||||
[CustomPropertyDrawer(typeof(EnumFlagAttribute))]
|
||||
public class EnumFlagDrawer : PropertyDrawer
|
||||
{
|
||||
private const BindingFlags k_BindingFlags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public |
|
||||
BindingFlags.NonPublic;
|
||||
|
||||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
||||
{
|
||||
EnumFlagAttribute flagSettings = (EnumFlagAttribute) attribute;
|
||||
Enum targetEnum = GetBaseProperty<Enum>(property);
|
||||
|
||||
string propName = flagSettings.AttributeName;
|
||||
if (string.IsNullOrEmpty(propName))
|
||||
propName = property.name;
|
||||
|
||||
EditorGUI.BeginProperty(position, label, property);
|
||||
Enum enumNew = EditorGUI.EnumFlagsField(position, propName, targetEnum);
|
||||
property.intValue = (int) Convert.ChangeType(enumNew, targetEnum.GetType());
|
||||
EditorGUI.EndProperty();
|
||||
}
|
||||
|
||||
static T GetBaseProperty<T>(SerializedProperty prop)
|
||||
{
|
||||
// Separate the steps it takes to get to this property
|
||||
string[] separatedPaths = prop.propertyPath.Split('.');
|
||||
|
||||
// Go down to the root of this serialized property
|
||||
System.Object reflectionTarget = prop.serializedObject.targetObject as object;
|
||||
// Walk down the path to get the target object
|
||||
foreach (var path in separatedPaths)
|
||||
{
|
||||
FieldInfo fieldInfo = reflectionTarget.GetType().GetField(path, k_BindingFlags);
|
||||
reflectionTarget = fieldInfo.GetValue(reflectionTarget);
|
||||
}
|
||||
|
||||
return (T) reflectionTarget;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Attributes/Editor/EnumFlagDrawer.cs.meta
Normal file
11
Assets/Attributes/Editor/EnumFlagDrawer.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 04325198546078740b805eccad279563
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
35
Assets/Attributes/Editor/NavMeshMaskDrawer.cs
Normal file
35
Assets/Attributes/Editor/NavMeshMaskDrawer.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
using UnityEngine;
|
||||
|
||||
namespace Golems.Attributes
|
||||
{
|
||||
[CustomPropertyDrawer(typeof(NavMeshMaskAttribute))]
|
||||
public class NavMeshMaskDrawer : PropertyDrawer
|
||||
{
|
||||
// Draw the property inside the given rect
|
||||
public override void OnGUI(Rect position, SerializedProperty serializedProperty, GUIContent label)
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
string[] navMeshAreaNames = GameObjectUtility.GetNavMeshAreaNames();
|
||||
int navMeshArea = serializedProperty.intValue;
|
||||
int selectedIndex = -1;
|
||||
for (int i = 0; i < navMeshAreaNames.Length; i++)
|
||||
{
|
||||
if (GameObjectUtility.GetNavMeshAreaFromName(navMeshAreaNames[i]) == navMeshArea)
|
||||
{
|
||||
selectedIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int num = EditorGUI.Popup(position, "Navigation Area", selectedIndex, navMeshAreaNames);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
int navMeshAreaFromName = GameObjectUtility.GetNavMeshAreaFromName(navMeshAreaNames[num]);
|
||||
serializedProperty.intValue = navMeshAreaFromName;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Attributes/Editor/NavMeshMaskDrawer.cs.meta
Normal file
11
Assets/Attributes/Editor/NavMeshMaskDrawer.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 85aa6985c75db0041a410a92859bf2c7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
75
Assets/Attributes/Editor/OnValueChangedEditor.cs
Normal file
75
Assets/Attributes/Editor/OnValueChangedEditor.cs
Normal file
@@ -0,0 +1,75 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using Golems.Attributes;
|
||||
|
||||
namespace Golems
|
||||
{
|
||||
public partial class AttributesEditor
|
||||
{
|
||||
const BindingFlags k_OnValChangedFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
|
||||
|
||||
private Dictionary<string, object> m_Fields = new Dictionary<string, object>();
|
||||
|
||||
private void OnInspectorGUIOnValueChangedAttribute()
|
||||
{
|
||||
var targetType = target.GetType();
|
||||
var fields = targetType.GetFields(k_OnValChangedFlags);
|
||||
//
|
||||
// Search for OnValueChanged Attribute on Each Field on this Object
|
||||
//
|
||||
for (int i = 0, counti = fields.Length; i < counti; ++i)
|
||||
{
|
||||
var field = fields[i];
|
||||
var onValueChangedAttribute = field.GetCustomAttribute<OnValueChanged>();
|
||||
|
||||
//
|
||||
// If we find an attribute and haven't already included it in m_Fields, include it!
|
||||
//
|
||||
if (onValueChangedAttribute == null || m_Fields.TryGetValue(field.Name, out var fieldValue)) continue;
|
||||
var method = targetType.GetMethod(onValueChangedAttribute.Method, k_ButtonBindingFlags);
|
||||
|
||||
if (method != null)
|
||||
{
|
||||
m_Fields.Add(field.Name, field.GetValue(this.target));
|
||||
}
|
||||
}
|
||||
|
||||
var changed = new List<Action>();
|
||||
|
||||
//
|
||||
// Now check all our found Fields and see if a value has changed
|
||||
//
|
||||
foreach (var fieldValueKeypair in m_Fields)
|
||||
{
|
||||
//
|
||||
// Retrieve the FieldInfo for the cached field name
|
||||
//
|
||||
var fieldInfo = targetType.GetField(fieldValueKeypair.Key, k_OnValChangedFlags);
|
||||
if (fieldInfo == null) continue;
|
||||
|
||||
//
|
||||
// Detect any change?
|
||||
//
|
||||
var currentValue = fieldInfo.GetValue(target);
|
||||
if (currentValue != null && currentValue.Equals(fieldValueKeypair.Value) ||
|
||||
currentValue == null && fieldValueKeypair.Value == null) continue;
|
||||
|
||||
var key = fieldValueKeypair.Key;
|
||||
changed.Add(() => { m_Fields[key] = currentValue; });
|
||||
|
||||
// ...a bit lazy, probably should cache this stuff but here we are :(
|
||||
var onValueChangedAttribute = fieldInfo.GetCustomAttribute<OnValueChanged>();
|
||||
if (onValueChangedAttribute == null) continue;
|
||||
|
||||
var method = targetType.GetMethod(onValueChangedAttribute.Method, k_ButtonBindingFlags);
|
||||
method?.Invoke(target, null);
|
||||
}
|
||||
|
||||
//
|
||||
// Update m_Fields which have been changed
|
||||
//
|
||||
changed.ForEach(x => x.Invoke());
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Attributes/Editor/OnValueChangedEditor.cs.meta
Normal file
11
Assets/Attributes/Editor/OnValueChangedEditor.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 595d2059fa7c03f4c8c5601e985467cb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
15
Assets/Attributes/Editor/ReadOnlyEditor.cs
Normal file
15
Assets/Attributes/Editor/ReadOnlyEditor.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using Golems.Attributes;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Golems
|
||||
{
|
||||
[CustomPropertyDrawer(typeof(ReadOnly))]
|
||||
public class ReadOnlyPropertyDrawer : PropertyDrawer
|
||||
{
|
||||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
||||
{
|
||||
EditorGUI.LabelField(position, $"{property.displayName}");
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Attributes/Editor/ReadOnlyEditor.cs.meta
Normal file
3
Assets/Attributes/Editor/ReadOnlyEditor.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 419c0496451345568582194a3ca84016
|
||||
timeCreated: 1629738460
|
||||
15
Assets/Attributes/Editor/ShowLevelAttributeEditor.cs
Normal file
15
Assets/Attributes/Editor/ShowLevelAttributeEditor.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using Golems.Attributes;
|
||||
|
||||
namespace Golems
|
||||
{
|
||||
public partial class AttributesEditor
|
||||
{
|
||||
/// <summary>
|
||||
/// Show the ShowLevelAttributes
|
||||
/// </summary>
|
||||
private void OnInspectorGUIShowLevelAttribute()
|
||||
{
|
||||
ShowLevelAttribute.EditorShowLevelInfo(target, "<color=green>Level info</color>");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7a10473fb25a4548a133b600bdb80984
|
||||
timeCreated: 1645812805
|
||||
19
Assets/Attributes/EnumFlag.cs
Normal file
19
Assets/Attributes/EnumFlag.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Golems
|
||||
{
|
||||
// http://wiki.unity3d.com/index.php?title=EnumFlagPropertyDrawer&oldid=19986S
|
||||
public class EnumFlagAttribute : PropertyAttribute
|
||||
{
|
||||
public string AttributeName;
|
||||
|
||||
public EnumFlagAttribute()
|
||||
{
|
||||
}
|
||||
|
||||
public EnumFlagAttribute(string name)
|
||||
{
|
||||
AttributeName = name;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Attributes/EnumFlag.cs.meta
Normal file
11
Assets/Attributes/EnumFlag.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 06d3d8b981898964da953a3cdce0bd42
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
39
Assets/Attributes/NavMeshMask.cs
Normal file
39
Assets/Attributes/NavMeshMask.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Golems.Attributes
|
||||
{
|
||||
[CustomPropertyDrawer(typeof(NavMeshMaskAttribute))]
|
||||
public class NavMeshMaskDrawer : PropertyDrawer
|
||||
{
|
||||
public override void OnGUI(Rect position, SerializedProperty serializedProperty, GUIContent label)
|
||||
{
|
||||
float width = position.width;
|
||||
position.width = EditorGUIUtility.labelWidth;
|
||||
EditorGUI.PrefixLabel(position, label);
|
||||
|
||||
string[] areaNames = GameObjectUtility.GetNavMeshAreaNames();
|
||||
int mask = serializedProperty.intValue;
|
||||
position.x += EditorGUIUtility.labelWidth;
|
||||
position.width = width - EditorGUIUtility.labelWidth;
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
mask = EditorGUI.MaskField(position, mask, areaNames);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
serializedProperty.intValue = mask;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = true)]
|
||||
public class NavMeshMaskAttribute : PropertyAttribute // if there are build issues move the NavMeshMaskAttribute class out of the unity editor folder
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
11
Assets/Attributes/NavMeshMask.cs.meta
Normal file
11
Assets/Attributes/NavMeshMask.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 66f5c29600cacf64892081213937119e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
22
Assets/Attributes/OnValueChanged.cs
Normal file
22
Assets/Attributes/OnValueChanged.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
|
||||
namespace Golems.Attributes
|
||||
{
|
||||
/// <summary>
|
||||
/// OnValueChange Attribute Invokes
|
||||
/// passed Method when Field Value is changed.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Field, AllowMultiple = true)]
|
||||
public class OnValueChanged : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// Method to Invoke when Value change detected
|
||||
/// </summary>
|
||||
public string Method { get; private set; } = "";
|
||||
|
||||
public OnValueChanged(string method)
|
||||
{
|
||||
Method = method;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Attributes/OnValueChanged.cs.meta
Normal file
11
Assets/Attributes/OnValueChanged.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f31eac74bacac3c4f8138e10208ac952
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
11
Assets/Attributes/ReadOnly.cs
Normal file
11
Assets/Attributes/ReadOnly.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Golems.Attributes
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = true)]
|
||||
public class ReadOnly : PropertyAttribute
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
3
Assets/Attributes/ReadOnly.cs.meta
Normal file
3
Assets/Attributes/ReadOnly.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1b36eef4ba5e4a7290eab96d800a0c78
|
||||
timeCreated: 1629738411
|
||||
147
Assets/Attributes/ShowLevelAttribute.cs
Normal file
147
Assets/Attributes/ShowLevelAttribute.cs
Normal file
@@ -0,0 +1,147 @@
|
||||
using System;
|
||||
#if UNITY_EDITOR
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
#endif
|
||||
|
||||
namespace Golems.Attributes
|
||||
{
|
||||
/// <summary>
|
||||
/// Show the EditorInspectableLevel property on the field.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Field)]
|
||||
public class ShowLevelAttribute : Attribute
|
||||
{
|
||||
public bool ShowWhenNotPlaying
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public ShowLevelAttribute()
|
||||
{
|
||||
ShowWhenNotPlaying = false;
|
||||
}
|
||||
|
||||
public ShowLevelAttribute(bool showWhenNotPlaying)
|
||||
{
|
||||
ShowWhenNotPlaying = showWhenNotPlaying;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
private const BindingFlags k_ShowLevelBindingFlags = BindingFlags.Public | BindingFlags.NonPublic |
|
||||
BindingFlags.Instance | BindingFlags.DeclaredOnly;
|
||||
|
||||
private static readonly List<FieldInfo> s_Fields = new List<FieldInfo>();
|
||||
|
||||
private static GUIStyle s_LabelStyle = null;
|
||||
|
||||
private const string k_EditorLevelProperty = "EditorInspectableLevel";
|
||||
|
||||
public static void EditorShowLevelInfo(UnityEngine.Object target, string label)
|
||||
{
|
||||
s_Fields.Clear();
|
||||
|
||||
GetShowLevelAttributeFields(target, s_Fields, EditorApplication.isPlaying);
|
||||
|
||||
if (s_Fields.Count <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!string.IsNullOrEmpty(label))
|
||||
{
|
||||
if (s_LabelStyle == null)
|
||||
{
|
||||
s_LabelStyle = EditorStyles.boldLabel;
|
||||
s_LabelStyle.richText = true;
|
||||
}
|
||||
EditorGUILayout.LabelField(label, s_LabelStyle);
|
||||
}
|
||||
|
||||
var origIndent = EditorGUI.indentLevel;
|
||||
EditorGUI.indentLevel += 1;
|
||||
for (int i = 0; i < s_Fields.Count; i++)
|
||||
{
|
||||
var field = s_Fields[i];
|
||||
|
||||
var niceName = ObjectNames.NicifyVariableName(field.Name);
|
||||
var fieldValue = field.GetValue(target);
|
||||
if (fieldValue != null)
|
||||
{
|
||||
var levelProperty = GetLevelNoSideEffectsProperty(fieldValue);
|
||||
|
||||
if (levelProperty != null)
|
||||
{
|
||||
var levelValue = levelProperty.GetValue(fieldValue);
|
||||
var level = levelValue;
|
||||
EditorGUI.BeginDisabledGroup(true);
|
||||
EditorGUI.EndDisabledGroup();
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.LabelField($"{niceName} does not implement LevelNoSideEffects");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.LabelField($"{niceName} is null");
|
||||
}
|
||||
}
|
||||
EditorGUI.indentLevel = origIndent;
|
||||
}
|
||||
|
||||
private static void GetShowLevelAttributeFields(object target, List<FieldInfo> resList, bool appPlaying)
|
||||
{
|
||||
int count = 0;
|
||||
for (var currentType = target.GetType(); currentType != null; currentType = currentType.BaseType)
|
||||
{
|
||||
if (count == 100)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var fields = currentType.GetFields(k_ShowLevelBindingFlags);
|
||||
|
||||
//
|
||||
// Search for ShowLevelAttribute within each field on this Object
|
||||
//
|
||||
for (int i = 0, counti = fields.Length; i < counti; ++i)
|
||||
{
|
||||
var field = fields[i];
|
||||
var showLevelAttribute = field.GetCustomAttribute<ShowLevelAttribute>(true);
|
||||
if (showLevelAttribute == null)
|
||||
continue;
|
||||
|
||||
if (!appPlaying && !showLevelAttribute.ShowWhenNotPlaying)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
resList.Add(field);
|
||||
}
|
||||
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
private static PropertyInfo GetLevelNoSideEffectsProperty(object fieldValue)
|
||||
{
|
||||
var properties = fieldValue.GetType().GetProperties(BindingFlags.GetProperty |
|
||||
BindingFlags.Public | BindingFlags.Instance);
|
||||
|
||||
for (int i = 0; i < properties.Length; i++)
|
||||
{
|
||||
var property = properties[i];
|
||||
|
||||
if (k_EditorLevelProperty.CompareTo(property.Name) == 0)
|
||||
{
|
||||
return property;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
3
Assets/Attributes/ShowLevelAttribute.cs.meta
Normal file
3
Assets/Attributes/ShowLevelAttribute.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 39074075b7a640d2913b2dbdfed4d978
|
||||
timeCreated: 1645812118
|
||||
Reference in New Issue
Block a user