diff options
Diffstat (limited to 'Assets/Plugins/AdvancedInspector')
89 files changed, 3981 insertions, 0 deletions
diff --git a/Assets/Plugins/AdvancedInspector/Attributes.meta b/Assets/Plugins/AdvancedInspector/Attributes.meta new file mode 100644 index 00000000..37a6962f --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Attributes.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: f415bc03d4b29594193286c0bef51f76 +folderAsset: yes +DefaultImporter: + userData: diff --git a/Assets/Plugins/AdvancedInspector/Attributes/AdvancedInspector.cs b/Assets/Plugins/AdvancedInspector/Attributes/AdvancedInspector.cs new file mode 100644 index 00000000..047710d5 --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Attributes/AdvancedInspector.cs @@ -0,0 +1,60 @@ +using System; + +namespace AdvancedInspector +{ + /// <summary> + /// Turn off the default Inspector in favor or the Advanced one. + /// If false, both may be draw if some members are flagged "Inspect", one after the other... + /// </summary> + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface, Inherited = true)] + public class AdvancedInspectorAttribute : Attribute + { + private bool inspectDefaultItems = false; + + /// <summary> + /// If true, the Advanced Inspector inspect all the item the default Inspector does without adding the [Inspect] attribute. + /// You can still add item that Unity would not display by adding the [Inspect] attribute. + /// </summary> + public bool InspectDefaultItems + { + get { return inspectDefaultItems; } + set { inspectDefaultItems = value; } + } + + private bool showScript = true; + + /// <summary> + /// Show or hide the script field at the top of the inspector. + /// The script field allow to change the type of the object. + /// </summary> + public bool ShowScript + { + get { return showScript; } + set { showScript = value; } + } + + private bool expandable = true; + + /// <summary> + /// Is this object expandable in a in-lined context? + /// </summary> + public bool Expandable + { + get { return expandable; } + set { expandable = value; } + } + + public AdvancedInspectorAttribute() { } + + public AdvancedInspectorAttribute(bool inspectDefaultItems) + { + this.inspectDefaultItems = inspectDefaultItems; + } + + public AdvancedInspectorAttribute(bool inspectDefaultItems, bool showScript) + { + this.showScript = showScript; + this.inspectDefaultItems = inspectDefaultItems; + } + } +} diff --git a/Assets/Plugins/AdvancedInspector/Attributes/AdvancedInspector.cs.meta b/Assets/Plugins/AdvancedInspector/Attributes/AdvancedInspector.cs.meta new file mode 100644 index 00000000..c0c82e2e --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Attributes/AdvancedInspector.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 37170739434a8a74bb0aae3f57b1ed64 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/AdvancedInspector/Attributes/Angle.cs b/Assets/Plugins/AdvancedInspector/Attributes/Angle.cs new file mode 100644 index 00000000..8b80ade5 --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Attributes/Angle.cs @@ -0,0 +1,34 @@ +using System; + +namespace AdvancedInspector +{ + /// <summary> + /// Turns a float/int into a spinning knob. + /// Because... Fancy. + /// </summary> + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] + public class AngleAttribute : Attribute, IListAttribute + { + private float snap = -1; + + /// <summary> + /// Makes the control snap to the multiple of that value + /// Default; -1. Negative values turn this behaviour off. + /// </summary> + public float Snap + { + get { return snap; } + } + + public AngleAttribute() { } + + /// <summary> + /// If snap is -1, the snap is disable. + /// Snap makes the wheel "stick" to multiple of a fixed value. + /// </summary> + public AngleAttribute(float snap) + { + this.snap = snap; + } + } +}
\ No newline at end of file diff --git a/Assets/Plugins/AdvancedInspector/Attributes/Angle.cs.meta b/Assets/Plugins/AdvancedInspector/Attributes/Angle.cs.meta new file mode 100644 index 00000000..1afd5dc4 --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Attributes/Angle.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ce761f6d5740bc9438033f37b24d3923 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/AdvancedInspector/Attributes/Background.cs b/Assets/Plugins/AdvancedInspector/Attributes/Background.cs new file mode 100644 index 00000000..e5ade555 --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Attributes/Background.cs @@ -0,0 +1,100 @@ +using System; +using UnityEngine; +using System.Reflection; +using System.Collections.Generic; + +namespace AdvancedInspector +{ + /// <summary> + /// Changes the color of the background of an expandable item. + /// </summary> + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Class | AttributeTargets.Struct)] + public class BackgroundAttribute : Attribute, IRuntimeAttribute<Color> + { + public delegate Color BackgroundDelegate(); + public delegate Color BackgroundStaticDelegate(BackgroundAttribute background, object instance, object value); + + private Color color = Color.clear; + + /// <summary> + /// Give this item's background a color. + /// </summary> + public Color Color + { + get { return color; } + set { color = value; } + } + + #region IRuntime Implementation + private string methodName = ""; + + public string MethodName + { + get { return methodName; } + set { methodName = value; } + } + + public Type Template + { + get { return typeof(BackgroundDelegate); } + } + + public Type TemplateStatic + { + get { return typeof(BackgroundStaticDelegate); } + } + + private List<Delegate> delegates = new List<Delegate>(); + + public List<Delegate> Delegates + { + get { return delegates; } + set { delegates = value; } + } + + public Color Invoke(int index, object instance, object value) + { + if (delegates.Count == 0 || index >= delegates.Count) + return color; + + try + { + if (delegates[index].Target == null) + { + return (Color)delegates[index].DynamicInvoke(this, instance, value); + } + else + { + return (Color)delegates[index].DynamicInvoke(); + } + } + catch (Exception e) + { + if (e is TargetInvocationException) + e = ((TargetInvocationException)e).InnerException; + + Debug.LogError(string.Format("Invoking a method to retrieve a Background attribute failed. The exception was \"{0}\".", e.Message)); + return color; + } + } + #endregion + + public BackgroundAttribute(string methodName) + { + this.methodName = methodName; + } + + public BackgroundAttribute(Delegate method) + { + this.delegates.Add(method); + } + + public BackgroundAttribute(float r, float g, float b) + : this(r, g, b, 1) { } + + public BackgroundAttribute(float r, float g, float b, float a) + { + this.color = new Color(r, g, b, a); + } + } +}
\ No newline at end of file diff --git a/Assets/Plugins/AdvancedInspector/Attributes/Background.cs.meta b/Assets/Plugins/AdvancedInspector/Attributes/Background.cs.meta new file mode 100644 index 00000000..71c26ea6 --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Attributes/Background.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4b99ed308d9ecd94eac01d3045a59165 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/AdvancedInspector/Attributes/Bypass.cs b/Assets/Plugins/AdvancedInspector/Attributes/Bypass.cs new file mode 100644 index 00000000..3419ebb6 --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Attributes/Bypass.cs @@ -0,0 +1,13 @@ +using System; + +namespace AdvancedInspector +{ + /// <summary> + /// Since internal Unity classes are not "Advanced Inspector" friendly, + /// this attribute force their own members to be exposed without the need of "InspectAttribute". + /// Be careful, all public property/fields will be exposed in a recursive manner. + /// This may expose stuff that were not meant to be exposed. + /// </summary> + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] + public class BypassAttribute : Attribute, IListAttribute { } +}
\ No newline at end of file diff --git a/Assets/Plugins/AdvancedInspector/Attributes/Bypass.cs.meta b/Assets/Plugins/AdvancedInspector/Attributes/Bypass.cs.meta new file mode 100644 index 00000000..fb65f729 --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Attributes/Bypass.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: eae36bd4c4e7de04d920900da8944a23 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/AdvancedInspector/Attributes/Collection.cs b/Assets/Plugins/AdvancedInspector/Attributes/Collection.cs new file mode 100644 index 00000000..2e9f870a --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Attributes/Collection.cs @@ -0,0 +1,151 @@ +using System; +using System.Collections.Generic; +using System.Reflection; + +using UnityEngine; + +namespace AdvancedInspector +{ + /// <summary> + /// When affixes to a collection, prevent this collection's size to be modified by the inspector. + /// </summary> + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] + public class CollectionAttribute : Attribute, IListAttribute + { + private int size = -1; + + /// <summary> + /// Size of this collection. + /// Default -1; size is not controlled by code. + /// 0 means the collection's size will be handled internally. + /// > 0 indicate the same of the collection. + /// </summary> + public int Size + { + get { return size; } + set { size = value; } + } + + private bool sortable = true; + + /// <summary> + /// If true, the list can be sorted by hand. + /// </summary> + public bool Sortable + { + get { return sortable; } + set { sortable = value; } + } + + private CollectionDisplay display = CollectionDisplay.List; + + /// <summary> + /// If not default, removes the collection list and only display one item at a time. + /// </summary> + public CollectionDisplay Display + { + get { return display; } + set { display = value; } + } + + private int maxDisplayedItems = 25; + + /// <summary> + /// When a collection is very large, it get up/down arrows to scrolls in items instead of displaying them all. + /// This property controls how many items are displayed before the scrolls appears. + /// </summary> + public int MaxDisplayedItems + { + get { return maxDisplayedItems; } + set { maxDisplayedItems = value; } + } + + private int maxItemsPerRow = 6; + + /// <summary> + /// When display is using Button, this is the maximum number of button displayed per rows before creating a new one. + /// </summary> + public int MaxItemsPerRow + { + get { return maxItemsPerRow; } + set { maxItemsPerRow = value; } + } + + private Type enumType = null; + + /// <summary> + /// Bind the size of a collection to the values of an enum. + /// The name of the indexed are displayed using the enum values' names. + /// </summary> + public Type EnumType + { + get { return enumType; } + set + { + if (!value.IsEnum) + return; + + int index = 0; + foreach (object i in Enum.GetValues(value)) + { + if ((int)i != index) + return; + + index++; + } + + enumType = value; + } + } + + public CollectionAttribute() { } + + public CollectionAttribute(int size) + : this(size, true) { } + + public CollectionAttribute(Type enumType) + : this(enumType, true) { } + + public CollectionAttribute(bool sortable) + : this(-1, sortable) { } + + public CollectionAttribute(CollectionDisplay display) + : this(-1, true, display) { } + + public CollectionAttribute(int size, bool sortable) + : this(size, sortable, CollectionDisplay.List) { } + + public CollectionAttribute(Type enumType, bool sortable) + : this(enumType, sortable, CollectionDisplay.List) { } + + public CollectionAttribute(int size, CollectionDisplay display) + : this(size, true, display) { } + + public CollectionAttribute(Type enumType, CollectionDisplay display) + : this(enumType, true, display) { } + + public CollectionAttribute(int size, bool sortable, CollectionDisplay display) + { + this.size = size; + this.sortable = sortable; + this.display = display; + } + + public CollectionAttribute(Type enumType, bool sortable, CollectionDisplay display) + { + this.EnumType = enumType; + this.sortable = sortable; + this.display = display; + } + } + + /// <summary> + /// None default display should only be used on collection that contain expandable objects. + /// </summary> + public enum CollectionDisplay + { + List, + DropDown, + Button + } +}
\ No newline at end of file diff --git a/Assets/Plugins/AdvancedInspector/Attributes/Collection.cs.meta b/Assets/Plugins/AdvancedInspector/Attributes/Collection.cs.meta new file mode 100644 index 00000000..3024d617 --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Attributes/Collection.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fca33267bb5f8b043a4dd1079e32af1c +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/AdvancedInspector/Attributes/Constructor.cs b/Assets/Plugins/AdvancedInspector/Attributes/Constructor.cs new file mode 100644 index 00000000..1b3f7438 --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Attributes/Constructor.cs @@ -0,0 +1,82 @@ +using System; +using System.Collections.Generic; +using System.Reflection; + +using UnityEngine; + +namespace AdvancedInspector +{ + /// <summary> + /// Some object cannot be created with an empty constructor. + /// This runtime attribute lets you create the object by yourself. + /// </summary> + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] + public class ConstructorAttribute : Attribute, IRuntimeAttribute<object> + { + public delegate object ConstructorDelegate(); + public delegate object ConstructorStaticDelegate(ConstructorAttribute constructor, object instance, object value); + + #region IRuntime Implementation + private string methodName = ""; + + public string MethodName + { + get { return methodName; } + } + + public Type Template + { + get { return typeof(ConstructorDelegate); } + } + + public Type TemplateStatic + { + get { return typeof(ConstructorStaticDelegate); } + } + + private List<Delegate> delegates = new List<Delegate>(); + + public List<Delegate> Delegates + { + get { return delegates; } + set { delegates = value; } + } + + public object Invoke(int index, object instance, object value) + { + if (delegates.Count == 0 || index >= delegates.Count) + return null; + + try + { + if (delegates[index].Target == null) + { + return delegates[index].DynamicInvoke(this, instance, value); + } + else + { + return delegates[index].DynamicInvoke(); + } + } + catch (Exception e) + { + if (e is TargetInvocationException) + e = ((TargetInvocationException)e).InnerException; + + Debug.LogError(string.Format("Invoking a method from a constructor failed. The exception was \"{0}\".", e.Message)); + return null; + } + } + #endregion + + public ConstructorAttribute(string methodName) + { + this.methodName = methodName; + } + + public ConstructorAttribute(Delegate method) + { + this.delegates.Add(method); + } + } +}
\ No newline at end of file diff --git a/Assets/Plugins/AdvancedInspector/Attributes/Constructor.cs.meta b/Assets/Plugins/AdvancedInspector/Attributes/Constructor.cs.meta new file mode 100644 index 00000000..f333c05f --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Attributes/Constructor.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 8e27defafd172764c9e999b947b2f4e6 +timeCreated: 1426031598 +licenseType: Store +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Plugins/AdvancedInspector/Attributes/CreateDerived.cs b/Assets/Plugins/AdvancedInspector/Attributes/CreateDerived.cs new file mode 100644 index 00000000..3fac45f8 --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Attributes/CreateDerived.cs @@ -0,0 +1,15 @@ +using System; + +namespace AdvancedInspector +{ + /// <summary> + /// Define an exposed property that act as a object creator. + /// The field gives the user the choices of all type deriving from that property type. + /// In the case of a generic List, it offers way to add object in the list. + /// If the list is of a value type (Ex.: int), it automaticly create an entry with the default value of that type. + /// Field/Property's type sporting this attribute should derive from ComponentMonoBehaviour! + /// Otherwise, Unity's serialization will kill the polymorphism involved. + /// </summary> + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] + public class CreateDerivedAttribute : Attribute, IListAttribute { } +}
\ No newline at end of file diff --git a/Assets/Plugins/AdvancedInspector/Attributes/CreateDerived.cs.meta b/Assets/Plugins/AdvancedInspector/Attributes/CreateDerived.cs.meta new file mode 100644 index 00000000..2fcb841a --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Attributes/CreateDerived.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fe2444b9e8ef55340952cecad2cc75c0 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/AdvancedInspector/Attributes/Descriptor.cs b/Assets/Plugins/AdvancedInspector/Attributes/Descriptor.cs new file mode 100644 index 00000000..a452e72b --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Attributes/Descriptor.cs @@ -0,0 +1,262 @@ +using System; +using System.Collections.Generic; +using System.Reflection; + +using UnityEngine; + +namespace AdvancedInspector +{ + /// <summary> + /// A description is the information about "something". + /// It contains an optional name, description, icon, color. + /// It can be used both as a attributes or a normal object, container of information. + /// Ex.: The Toolbox is using it as object. + /// </summary> + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method | AttributeTargets.Class | + AttributeTargets.Interface | AttributeTargets.Struct | AttributeTargets.Enum, Inherited = false)] + public class DescriptorAttribute : Attribute, IRuntimeAttribute<DescriptorAttribute> + { + public delegate DescriptorAttribute DescriptorDelegate(); + public delegate DescriptorAttribute DescriptorStaticDelegate(DescriptorAttribute descriptor, object instance, object value); + + private static Color TRANSPARENT = new Color(0, 0, 0, 0); + + private string name = ""; + + /// <summary> + /// Give this item a name. + /// </summary> + public string Name + { + get { return name; } + set { name = value; } + } + + private string description = ""; + + /// <summary> + /// Give this item a description. + /// Usually used for tooltip. + /// </summary> + public string Description + { + get { return description; } + set { description = value; } + } + + private string url = ""; + + /// <summary> + /// Give this item an help URL. + /// </summary> + public string URL + { + get { return url; } + set { url = value; } + } + + private Texture icon = null; + + /// <summary> + /// Give this item an icon. + /// Useful in a list of items. + /// </summary> + public Texture Icon + { + get { return icon; } + set { icon = value; } + } + + private Color color = Color.clear; + + /// <summary> + /// Give this item a color. + /// Default is transparent + /// </summary> + public Color Color + { + get { return color; } + set { color = value; } + } + + #region IRuntime Implementation + private string methodName = ""; + + public string MethodName + { + get { return methodName; } + } + + public Type Template + { + get { return typeof(DescriptorDelegate); } + } + + public Type TemplateStatic + { + get { return typeof(DescriptorStaticDelegate); } + } + + private List<Delegate> delegates = new List<Delegate>(); + + public List<Delegate> Delegates + { + get { return delegates; } + set { delegates = value; } + } + + public DescriptorAttribute Invoke(int index, object instance, object value) + { + if (delegates.Count == 0 || index >= delegates.Count) + return this; + + try + { + if (delegates[index].Target == null) + { + return delegates[0].DynamicInvoke(this, instance, value) as DescriptorAttribute; + } + else + { + return delegates[0].DynamicInvoke() as DescriptorAttribute; + } + } + catch (Exception e) + { + if (e is TargetInvocationException) + e = ((TargetInvocationException)e).InnerException; + + Debug.LogError(string.Format("Invoking a method to retrieve a Destriptor attribute failed. The exception was \"{0}\".", e.Message)); + return null; + } + } + #endregion + + public DescriptorAttribute() { } + + #region Attributes Constructor + public DescriptorAttribute(string methodName) + { + this.methodName = methodName; + } + + public DescriptorAttribute(float r, float g, float b) + : this("", "", "", r, g, b, 1) { } + + public DescriptorAttribute(string name, string description) + : this(name, description, "", 0, 0, 0, 0) { } + + public DescriptorAttribute(string name, string description, string url) + : this(name, description, url, 0, 0, 0, 0) { } + + public DescriptorAttribute(string name, string description, string url, float r, float g, float b) + : this(name, description, url, r, g, b, 1) { } + + private DescriptorAttribute(string name, string description, string url, float r, float g, float b, float a) + { + this.name = name; + this.description = description; + this.url = url; + color = new Color(r, g, b, a); + } + #endregion + + #region Object Constructor + public DescriptorAttribute(string name, string description, Texture icon) + : this(name, description, icon, TRANSPARENT) { } + + public DescriptorAttribute(string name, string description, Texture icon, Color color) + { + this.name = name; + this.description = description; + this.icon = icon; + this.color = color; + } + #endregion + + public static DescriptorAttribute GetDescriptor(Type type) + { + object[] obj = type.GetCustomAttributes(typeof(DescriptorAttribute), true); + + if (obj.Length == 0) + return null; + else + return (obj[0] as DescriptorAttribute); + } + + public static List<DescriptorAttribute> GetDescriptors(List<Type> types) + { + List<DescriptorAttribute> descriptors = new List<DescriptorAttribute>(); + + foreach (Type type in types) + descriptors.Add(GetDescriptor(type)); + + return descriptors; + } + } + + /// <summary> + /// Pairs an object with a descriptor. + /// Used by the Toolbox and the Advanced Inspector. + /// </summary> + public class DescriptorPair + { + private object value; + + public object Value + { + get { return value; } + } + + private DescriptorAttribute descriptor; + + public DescriptorAttribute Descriptor + { + get { return descriptor; } + } + + public DescriptorPair(object value, DescriptorAttribute descriptor) + { + this.value = value; + this.descriptor = descriptor; + } + + public DescriptorPair(object value, string name) + : this(value, new DescriptorAttribute(name, "")) { } + + public DescriptorPair(object value, string name, string description) + : this(value, new DescriptorAttribute(name, description)) { } + + public static bool operator ==(DescriptorPair a, DescriptorPair b) + { + // If both are null, or both are same instance, return true. + if (System.Object.ReferenceEquals(a, b)) + return true; + + // If one is null, but not both, return false. + if (((object)a == null) || ((object)b == null)) + return false; + + return a.Equals(b); + } + + public static bool operator !=(DescriptorPair a, DescriptorPair b) + { + return !(a == b); + } + + public override bool Equals(object obj) + { + DescriptorPair other = obj as DescriptorPair; + if (other == null) + return false; + + return this.Value.Equals(other.Value); + } + + public override int GetHashCode() + { + return base.GetHashCode(); + } + } +}
\ No newline at end of file diff --git a/Assets/Plugins/AdvancedInspector/Attributes/Descriptor.cs.meta b/Assets/Plugins/AdvancedInspector/Attributes/Descriptor.cs.meta new file mode 100644 index 00000000..eee13f0a --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Attributes/Descriptor.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c543914d76893214f9fceba693c0ed76 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/AdvancedInspector/Attributes/DisplayAsParent.cs b/Assets/Plugins/AdvancedInspector/Attributes/DisplayAsParent.cs new file mode 100644 index 00000000..acec32e9 --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Attributes/DisplayAsParent.cs @@ -0,0 +1,10 @@ +using System; + +namespace AdvancedInspector +{ + /// <summary> + /// Prevent a nested object from having to be unfolded. + /// </summary> + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] + public class DisplayAsParentAttribute : Attribute { } +}
\ No newline at end of file diff --git a/Assets/Plugins/AdvancedInspector/Attributes/DisplayAsParent.cs.meta b/Assets/Plugins/AdvancedInspector/Attributes/DisplayAsParent.cs.meta new file mode 100644 index 00000000..3632a07b --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Attributes/DisplayAsParent.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3fca13597b0728d41a25aa9d670f0b86 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/AdvancedInspector/Attributes/DontAllowSceneObject.cs b/Assets/Plugins/AdvancedInspector/Attributes/DontAllowSceneObject.cs new file mode 100644 index 00000000..7c8506a6 --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Attributes/DontAllowSceneObject.cs @@ -0,0 +1,11 @@ +using System; + +namespace AdvancedInspector +{ + /// <summary> + /// Prevent Scene Object from being browsed in a Object property. + /// By default, scene and asset are displayed. + /// </summary> + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] + public class DontAllowSceneObjectAttribute : Attribute, IListAttribute { } +}
\ No newline at end of file diff --git a/Assets/Plugins/AdvancedInspector/Attributes/DontAllowSceneObject.cs.meta b/Assets/Plugins/AdvancedInspector/Attributes/DontAllowSceneObject.cs.meta new file mode 100644 index 00000000..72b6f6c1 --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Attributes/DontAllowSceneObject.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 819e08560dc14324ebaa532c3f65751a +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/AdvancedInspector/Attributes/Enum.cs b/Assets/Plugins/AdvancedInspector/Attributes/Enum.cs new file mode 100644 index 00000000..f9b88281 --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Attributes/Enum.cs @@ -0,0 +1,68 @@ +using System; + +namespace AdvancedInspector +{ + /// <summary> + /// Controls how an enum is handled and displayed. + /// </summary> + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] + public class EnumAttribute : Attribute, IListAttribute + { + private bool masked = false; + + /// <summary> + /// Turns a normal enum into a bitfield. + /// Careful, your enum should be properly setup to accepted bitfield input. + /// </summary> + public bool Masked + { + get { return masked; } + set { masked = value; } + } + + private EnumDisplay display = EnumDisplay.DropDown; + + /// <summary> + /// Forces an enum to be displayed differently. + /// </summary> + public EnumDisplay Display + { + get { return display; } + set { display = value; } + } + + private int maxItemsPerRow = 6; + + /// <summary> + /// When display is using Button or Checkbox, this is the maximum number of button displayed per rows before creating a new one. + /// </summary> + public int MaxItemsPerRow + { + get { return maxItemsPerRow; } + set { maxItemsPerRow = value; } + } + + public EnumAttribute(bool masked) + { + this.masked = masked; + } + + public EnumAttribute(EnumDisplay display) + { + this.display = display; + } + + public EnumAttribute(bool masked, EnumDisplay display) + { + this.masked = masked; + this.display = display; + } + } + + public enum EnumDisplay + { + DropDown, + Button, + Checkbox + } +}
\ No newline at end of file diff --git a/Assets/Plugins/AdvancedInspector/Attributes/Enum.cs.meta b/Assets/Plugins/AdvancedInspector/Attributes/Enum.cs.meta new file mode 100644 index 00000000..d47eb345 --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Attributes/Enum.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6bb7fceb011c74e43a49f0124591cb7e +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/AdvancedInspector/Attributes/Expandable.cs b/Assets/Plugins/AdvancedInspector/Attributes/Expandable.cs new file mode 100644 index 00000000..b63d5c38 --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Attributes/Expandable.cs @@ -0,0 +1,46 @@ +using System; + +namespace AdvancedInspector +{ + /// <summary> + /// Redefine if a field/property can be expanded or not. + /// </summary> + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property, Inherited = true)] + public class ExpandableAttribute : Attribute, IListAttribute + { + private bool expanded = false; + + /// <summary> + /// Makes the item expanded by default. + /// </summary> + public bool Expanded + { + get { return expanded; } + set { expanded = value; } + } + + private bool expandable = true; + + /// <summary> + /// Default true, can force a field to not be expandable. + /// </summary> + public bool Expandable + { + get { return expandable; } + set { expandable = value; } + } + + public ExpandableAttribute() { } + + public ExpandableAttribute(bool expandable) + { + this.expandable = expandable; + } + + public ExpandableAttribute(bool expandable, bool expanded) + { + this.expanded = expanded; + this.expandable = expandable; + } + } +}
\ No newline at end of file diff --git a/Assets/Plugins/AdvancedInspector/Attributes/Expandable.cs.meta b/Assets/Plugins/AdvancedInspector/Attributes/Expandable.cs.meta new file mode 100644 index 00000000..60aef708 --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Attributes/Expandable.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 574c9c65c35362d4c81087ea01d49be7 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/AdvancedInspector/Attributes/FieldEditor.cs b/Assets/Plugins/AdvancedInspector/Attributes/FieldEditor.cs new file mode 100644 index 00000000..b5c833d9 --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Attributes/FieldEditor.cs @@ -0,0 +1,26 @@ +using System; + +namespace AdvancedInspector +{ + /// <summary> + /// Can only be placed a classed derived from FieldEditor, or a field/property taking a specific editor. + /// </summary> + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] + public class FieldEditorAttribute : Attribute, IListAttribute + { + private string type = ""; + + /// <summary> + /// Type's name of the FieldEditor to use. + /// </summary> + public string Type + { + get { return type; } + } + + public FieldEditorAttribute(string type) + { + this.type = type; + } + } +}
\ No newline at end of file diff --git a/Assets/Plugins/AdvancedInspector/Attributes/FieldEditor.cs.meta b/Assets/Plugins/AdvancedInspector/Attributes/FieldEditor.cs.meta new file mode 100644 index 00000000..7be7565f --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Attributes/FieldEditor.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 48265bc16ba070a4f9c105cdd29d2805 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/AdvancedInspector/Attributes/Group.cs b/Assets/Plugins/AdvancedInspector/Attributes/Group.cs new file mode 100644 index 00000000..e95709ad --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Attributes/Group.cs @@ -0,0 +1,110 @@ +using System; +using UnityEngine; + +namespace AdvancedInspector +{ + /// <summary> + /// Allow to groups inspector items. + /// </summary> + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Method)] + public class GroupAttribute : Attribute + { + private string name = ""; + + /// <summary> + /// Name of the group. + /// </summary> + public string Name + { + get { return name; } + set { name = value; } + } + + private string description = ""; + + /// <summary> + /// Extra text for the group, displayed on the right side. + /// </summary> + public string Description + { + get { return description; } + set { description = value; } + } + + private string style = ""; + + /// <summary> + /// Style of this group. + /// Only need to be flagged on one item. + /// </summary> + public string Style + { + get { return style; } + set { style = value; } + } + + private int priority = 0; + + /// <summary> + /// Priority of this group when sorting items. + /// Only need to be flagged on one item. + /// </summary> + public int Priority + { + get { return priority; } + set { priority = value; } + } + + private bool expandable = true; + + /// <summary> + /// If false, the group is always expanded and does not have an foldout arrow. + /// </summary> + public bool Expandable + { + get { return expandable; } + set { expandable = value; } + } + + private Color color = Color.clear; + + /// <summary> + /// Give this item's background a color. + /// </summary> + public Color Color + { + get { return color; } + set { color = value; } + } + + public GroupAttribute(string name) + : this(name, "", 0) { } + + public GroupAttribute(string name, int priority) + : this(name, "", priority) { } + + public GroupAttribute(string name, string style) + : this(name, style, 0) { } + + public GroupAttribute(string name, float r, float g, float b) + : this(name, "", "", 0, r, g, b, 1) { } + + public GroupAttribute(string name, string style, int priority) + : this(name, "", style, priority, 0, 0, 0, 0) { } + + public GroupAttribute(string name, string style, float r, float g, float b) + : this(name, "", style, 0, r, g, b, 1) { } + + public GroupAttribute(string name, string style, int priority, float r, float g, float b) + : this(name, "", style, priority, r, g, b, 1) { } + + public GroupAttribute(string name, string description, string style, int priority, float r, float g, float b, float a) + { + this.name = name; + this.description = description; + this.style = style; + this.priority = priority; + this.color = new Color(r, g, b, a); + } + } +}
\ No newline at end of file diff --git a/Assets/Plugins/AdvancedInspector/Attributes/Group.cs.meta b/Assets/Plugins/AdvancedInspector/Attributes/Group.cs.meta new file mode 100644 index 00000000..2a0b75a8 --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Attributes/Group.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 363188602a056ed47970a96a0f55d619 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/AdvancedInspector/Attributes/Help.cs b/Assets/Plugins/AdvancedInspector/Attributes/Help.cs new file mode 100644 index 00000000..ea4825d9 --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Attributes/Help.cs @@ -0,0 +1,199 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Text; +using System.Text.RegularExpressions; + +using UnityEngine; + +namespace AdvancedInspector +{ + /// <summary> + /// When a property is flagged this way, a help box is added after the inspector's field. + /// </summary> + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method | AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = true)] + public class HelpAttribute : Attribute, IRuntimeAttribute<HelpAttribute> + { + public const string IsNull = "HelpAttribute.IsValueNull"; + public const string IsNullOrEmpty = "HelpAttribute.IsStringNullOrEmpty"; + public const string IsMatch = "HelpAttribute.IsRegexMatch"; + + + public delegate HelpAttribute HelpDelegate(); + public delegate HelpAttribute HelpStaticDelegate(HelpAttribute help, object instance, object value); + + private HelpType type; + + /// <summary> + /// Help type. + /// Displays a specific icon. + /// </summary> + public HelpType Type + { + get { return type; } + set { type = value; } + } + + private string message; + + /// <summary> + /// Help message. + /// </summary> + public string Message + { + get { return message; } + set { message = value; } + } + + private HelpPosition position = HelpPosition.After; + + /// <summary> + /// By default, the helpbox is drawn after the field. + /// If this is false, it is drawn before the field. + /// </summary> + public HelpPosition Position + { + get { return position; } + set { position = value; } + } + + private string regex; + + /// <summary> + /// When using the IsRegex conditional, this string is used as a regular expresion. + /// </summary> + public string Regex + { + get { return regex; } + set { regex = value; } + } + + #region IRuntime Implementation + private string methodName = ""; + + public string MethodName + { + get { return methodName; } + } + + public Type Template + { + get { return typeof(HelpDelegate); } + } + + public Type TemplateStatic + { + get { return typeof(HelpStaticDelegate); } + } + + private List<Delegate> delegates = new List<Delegate>(); + + public List<Delegate> Delegates + { + get { return delegates; } + set { delegates = value; } + } + + public HelpAttribute Invoke(int index, object instance, object value) + { + if (delegates.Count == 0 || index >= delegates.Count) + return this; + + try + { + if (delegates[index].Target == null) + { + return delegates[0].DynamicInvoke(this, instance, value) as HelpAttribute; + } + else + { + return delegates[0].DynamicInvoke() as HelpAttribute; + } + } + catch (Exception e) + { + if (e is TargetInvocationException) + e = ((TargetInvocationException)e).InnerException; + + Debug.LogError(string.Format("Invoking a method failed while trying to retrieve a Help attribute. The exception was \"{0}\".", e.Message)); + return null; + } + } + #endregion + + public HelpAttribute(string methodName) + : this(methodName, HelpType.None, HelpPosition.After, "") { } + + public HelpAttribute(string methodName, HelpType type, string message) + : this(methodName, type, HelpPosition.After, message) { } + + public HelpAttribute(HelpType type, string message) + : this("", type, HelpPosition.After, message) { } + + public HelpAttribute(HelpType type, HelpPosition position, string message) + : this("", type, position, message) { } + + public HelpAttribute(string methodName, HelpType type, HelpPosition position, string message) + { + this.methodName = methodName; + this.type = type; + this.position = position; + this.message = message; + } + + public HelpAttribute(Delegate method) + { + this.delegates.Add(method); + } + + private static HelpAttribute IsValueNull(HelpAttribute help, object instance, object value) + { + if (value == null || (value is UnityEngine.Object && ((UnityEngine.Object)value) == null)) + { + return help; + } + + return null; + } + + private static HelpAttribute IsStringNullOrEmpty(HelpAttribute help, object instance, object value) + { + if (value is string && string.IsNullOrEmpty((string)value)) + return help; + + return null; + } + + private static HelpAttribute IsRegexMatch(HelpAttribute help, object instance, object value) + { + if (value == null) + return null; + + string text = value.ToString(); + if (System.Text.RegularExpressions.Regex.IsMatch(text, help.regex)) + return help; + + return null; + } + } + + /// <summary> + /// Because the internal enum for help display is Editor only. + /// </summary> + public enum HelpType + { + None = 0, + Info = 1, + Warning = 2, + Error = 3, + } + + /// <summary> + /// The position where the help box should be placed. + /// </summary> + public enum HelpPosition + { + After, + Before + } +}
\ No newline at end of file diff --git a/Assets/Plugins/AdvancedInspector/Attributes/Help.cs.meta b/Assets/Plugins/AdvancedInspector/Attributes/Help.cs.meta new file mode 100644 index 00000000..1d663fe8 --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Attributes/Help.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d071ab40c60bc8a458f4e2578a30440e +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/AdvancedInspector/Attributes/Inspect.cs b/Assets/Plugins/AdvancedInspector/Attributes/Inspect.cs new file mode 100644 index 00000000..210e3558 --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Attributes/Inspect.cs @@ -0,0 +1,195 @@ +using System; +using System.Reflection; +using System.Collections.Generic; +using UnityEngine; + +namespace AdvancedInspector +{ + /// <summary> + /// Makes a property viewable in the Inspector of Unity. + /// Turns a method into a button in the Inspector. + /// You can input a conditional statement for your property to show up or not. + /// </summary> + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method)] + public class InspectAttribute : Attribute, IRuntimeAttribute<bool> + { + public delegate bool InspectDelegate(); + public delegate bool InspectStaticDelegate(InspectAttribute inspect, object instance, object value); + + private InspectorLevel level; + + /// <summary> + /// Inspector level are use to hide more advanced item. + /// Items under the current Inspector levels are hidden. + /// </summary> + public InspectorLevel Level + { + get { return level; } + set { level = value; } + } + + private bool condition = true; + + /// <summary> + /// Inverse the condition used by the IRuntime method. + /// </summary> + public bool Condition + { + get { return condition; } + set { condition = value; } + } + + private int priority = 0; + + /// <summary> + /// Priority of display of this item. + /// Smaller values are displayed first. Negative value are supported. + /// </summary> + public int Priority + { + get { return priority; } + set { priority = value; } + } + + #region IRuntime Implementation + private string methodName = ""; + + public string MethodName + { + get { return methodName; } + set { methodName = value; } + } + + public Type Template + { + get { return typeof(InspectDelegate); } + } + + public Type TemplateStatic + { + get { return typeof(InspectStaticDelegate); } + } + + private List<Delegate> delegates = new List<Delegate>(); + + public List<Delegate> Delegates + { + get { return delegates; } + set { delegates = value; } + } + + public bool Invoke(int index, object instance, object value) + { + if (delegates.Count == 0 || index >= delegates.Count) + return true; + + try + { + if (delegates[index].Target == null) + { + if (condition) + return (bool)delegates[index].DynamicInvoke(this, instance, value); + else + return !(bool)delegates[index].DynamicInvoke(this, instance, value); + } + else + { + if (condition) + return (bool)delegates[index].DynamicInvoke(); + else + return !(bool)delegates[index].DynamicInvoke(); + } + } + catch (Exception e) + { + if (e is TargetInvocationException) + e = ((TargetInvocationException)e).InnerException; + + Debug.LogError(string.Format("Invoking a method to retrieve a Inspect attribute failed. The exception was \"{0}\".", e.Message)); + return true; + } + } + #endregion + + #region Compile Time Constructor + public InspectAttribute() + : this(InspectorLevel.Basic, "", true, 0) { } + + public InspectAttribute(int priority) + : this(InspectorLevel.Basic, "", true, priority) { } + + public InspectAttribute(InspectorLevel level) + : this(level, "", true, 0) { } + + public InspectAttribute(InspectorLevel level, int priority) + : this(level, "", true, priority) { } + + public InspectAttribute(InspectorLevel level, string methodName) + : this(level, methodName, true, 0) { } + + public InspectAttribute(InspectorLevel level, string methodName, int priority) + : this(level, methodName, true, priority) { } + + public InspectAttribute(InspectorLevel level, string methodName, bool condition) + : this(level, methodName, condition, 0) { } + + public InspectAttribute(string methodName) + : this(InspectorLevel.Basic, methodName, true, 0) { } + + public InspectAttribute(string methodName, int priority) + : this(InspectorLevel.Basic, methodName, true, priority) { } + + public InspectAttribute(string methodName, bool condition) + : this(InspectorLevel.Basic, methodName, condition, 0) { } + + public InspectAttribute(string methodName, bool condition, int priority) + : this(InspectorLevel.Basic, methodName, condition, priority) { } + + public InspectAttribute(InspectorLevel level, string methodName, bool condition, int priority) + { + this.level = level; + this.condition = condition; + this.methodName = methodName; + this.priority = priority; + } + #endregion + + #region Runtime Constructor + public InspectAttribute(Delegate method) + : this(InspectorLevel.Basic, method, true, 0) { } + + public InspectAttribute(Delegate method, int priority) + : this(InspectorLevel.Basic, method, true, priority) { } + + public InspectAttribute(Delegate method, bool condition) + : this(InspectorLevel.Basic, method, condition, 0) { } + + public InspectAttribute(Delegate method, bool condition, int priority) + : this(InspectorLevel.Basic, method, condition, priority) { } + + public InspectAttribute(InspectorLevel level, Delegate method) + : this(level, method, true, 0) { } + + public InspectAttribute(InspectorLevel level, Delegate method, int priority) + : this(level, method, true, priority) { } + + public InspectAttribute(InspectorLevel level, Delegate method, bool condition, int priority) + { + this.level = level; + this.condition = condition; + this.priority = priority; + this.delegates.Add(method); + } + #endregion + } + + /// <summary> + /// You can change or add your own levels. + /// </summary> + public enum InspectorLevel + { + Basic = 0, + Advanced = 1, + Debug = 2 + } +}
\ No newline at end of file diff --git a/Assets/Plugins/AdvancedInspector/Attributes/Inspect.cs.meta b/Assets/Plugins/AdvancedInspector/Attributes/Inspect.cs.meta new file mode 100644 index 00000000..f3b0b2fc --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Attributes/Inspect.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b1d1add23978a924d9da822c16ecca5d +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/AdvancedInspector/Attributes/Method.cs b/Assets/Plugins/AdvancedInspector/Attributes/Method.cs new file mode 100644 index 00000000..df08abc8 --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Attributes/Method.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; + +namespace AdvancedInspector +{ + /// <summary> + /// Used when inspected a method, gives control over how it is displayed or handled. + /// </summary> + [AttributeUsage(AttributeTargets.Method)] + public class MethodAttribute : Attribute + { + private MethodDisplay display = MethodDisplay.Button; + + public MethodDisplay Display + { + get { return display; } + set { display = value; } + } + + public MethodAttribute() { } + + public MethodAttribute(MethodDisplay display) + { + this.display = display; + } + } + + + /// <summary> + /// How the method is displayed. + /// </summary> + public enum MethodDisplay + { + Button, // A button + Invoke // Invoke it so it draws its own stuff. + } +}
\ No newline at end of file diff --git a/Assets/Plugins/AdvancedInspector/Attributes/Method.cs.meta b/Assets/Plugins/AdvancedInspector/Attributes/Method.cs.meta new file mode 100644 index 00000000..7738c797 --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Attributes/Method.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d18c976511db4614f89166425f46b342 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/AdvancedInspector/Attributes/NoPicker.cs b/Assets/Plugins/AdvancedInspector/Attributes/NoPicker.cs new file mode 100644 index 00000000..0619ccec --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Attributes/NoPicker.cs @@ -0,0 +1,13 @@ +using UnityEngine; +using System; +using System.Collections; + +namespace AdvancedInspector +{ + /// <summary> + /// Removes the object picking field from a selectable object. + /// Useful when the object is set internally, should be edited but not changed. + /// </summary> + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] + public class NoPicker : Attribute, IListAttribute { } +} diff --git a/Assets/Plugins/AdvancedInspector/Attributes/NoPicker.cs.meta b/Assets/Plugins/AdvancedInspector/Attributes/NoPicker.cs.meta new file mode 100644 index 00000000..00643d66 --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Attributes/NoPicker.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 76bfee0f7aa5c3e429aae6af201d0f66 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/AdvancedInspector/Attributes/RangeValue.cs b/Assets/Plugins/AdvancedInspector/Attributes/RangeValue.cs new file mode 100644 index 00000000..a0331216 --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Attributes/RangeValue.cs @@ -0,0 +1,40 @@ +using System; + +namespace AdvancedInspector +{ + /// <summary> + /// Similar to Unity's "Range" attribute but for the Advanced Inspector. + /// However, Unity's version is flagged to be "Field Only", while this one can be placed on Properties. + /// </summary> + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] + public class RangeValueAttribute : Attribute, IListAttribute + { + private float min; + + /// <summary> + /// Min value, the current value cannot go below that. + /// </summary> + public float Min + { + get { return min; } + set { min = value; } + } + + private float max; + + /// <summary> + /// Max value, the current value cannot go above that. + /// </summary> + public float Max + { + get { return max; } + set { max = value; } + } + + public RangeValueAttribute(float min, float max) + { + this.min = min; + this.max = max; + } + } +}
\ No newline at end of file diff --git a/Assets/Plugins/AdvancedInspector/Attributes/RangeValue.cs.meta b/Assets/Plugins/AdvancedInspector/Attributes/RangeValue.cs.meta new file mode 100644 index 00000000..780732c1 --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Attributes/RangeValue.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 214bf4d5f010cd14f8f02b9debfca40d +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/AdvancedInspector/Attributes/ReadOnly.cs b/Assets/Plugins/AdvancedInspector/Attributes/ReadOnly.cs new file mode 100644 index 00000000..145f1167 --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Attributes/ReadOnly.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using System.Reflection; + +using UnityEngine; + +namespace AdvancedInspector +{ + /// <summary> + /// Makes a Property read only (cannot be modified) + /// It's grayed out in the inspector, even if there's a setter. + /// </summary> + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method, AllowMultiple = false)] + public class ReadOnlyAttribute : Attribute, IListAttribute, IRuntimeAttribute<bool> + { + public delegate bool ReadOnlyDelegate(); + public delegate bool ReadOnlyStaticDelegate(ReadOnlyAttribute readOnly, object instance, object value); + + #region IRuntime Implementation + private string methodName = ""; + + public string MethodName + { + get { return methodName; } + } + + public Type Template + { + get { return typeof(ReadOnlyDelegate); } + } + + public Type TemplateStatic + { + get { return typeof(ReadOnlyStaticDelegate); } + } + + private List<Delegate> delegates = new List<Delegate>(); + + public List<Delegate> Delegates + { + get { return delegates; } + set { delegates = value; } + } + + public bool Invoke(int index, object instance, object value) + { + if (delegates.Count == 0 || index >= delegates.Count) + return true; + + try + { + if (delegates[index].Target == null) + { + return (bool)delegates[index].DynamicInvoke(this, instance, value); + } + else + { + return (bool)delegates[index].DynamicInvoke(); + } + } + catch (Exception e) + { + if (e is TargetInvocationException) + e = ((TargetInvocationException)e).InnerException; + + Debug.LogError(string.Format("Invoking a method to retrieve a ReadOnly attribute failed. The exception was \"{0}\".", e.Message)); + return false; + } + } + #endregion + + public ReadOnlyAttribute() { } + + public ReadOnlyAttribute(Delegate method) + { + this.delegates.Add(method); + } + + public ReadOnlyAttribute(string methodName) + { + this.methodName = methodName; + } + } +}
\ No newline at end of file diff --git a/Assets/Plugins/AdvancedInspector/Attributes/ReadOnly.cs.meta b/Assets/Plugins/AdvancedInspector/Attributes/ReadOnly.cs.meta new file mode 100644 index 00000000..d0993047 --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Attributes/ReadOnly.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 807b8f48dfd4f724d979f453c48556e1 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/AdvancedInspector/Attributes/Restrict.cs b/Assets/Plugins/AdvancedInspector/Attributes/Restrict.cs new file mode 100644 index 00000000..43d48f76 --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Attributes/Restrict.cs @@ -0,0 +1,122 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; + +using UnityEngine; + +namespace AdvancedInspector +{ + /// <summary> + /// Restrict an object field to a list of object define by a delegate from the owner. + /// In essence, turn any field into a drop down list of choices. + /// Attributes cannot recieve a delegate, instead you pass the name of the method. + /// The method itself is resolved when creating the field to know which instance to invoke. + /// </summary> + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] + public class RestrictAttribute : Attribute, IListAttribute, IRuntimeAttribute<IList> + { + public delegate IList RestrictDelegate(); + public delegate IList RestrictStaticDelegate(RestrictAttribute restrict, object instance, object value); + + private RestrictDisplay display = RestrictDisplay.DropDown; + + /// <summary> + /// Should this restricted field use the toolbox instead of a drop down popup. + /// </summary> + public RestrictDisplay Display + { + get { return display; } + set { display = value; } + } + + private int maxItemsPerRow = 6; + + /// <summary> + /// When display is using Button, limits the number of items per row. + /// </summary> + public int MaxItemsPerRow + { + get { return maxItemsPerRow; } + set { maxItemsPerRow = value; } + } + + #region IRuntime Implementation + private string methodName = ""; + + public string MethodName + { + get { return methodName; } + } + + public Type Template + { + get { return typeof(RestrictDelegate); } + } + + public Type TemplateStatic + { + get { return typeof(RestrictStaticDelegate); } + } + + private List<Delegate> delegates = new List<Delegate>(); + + public List<Delegate> Delegates + { + get { return delegates; } + set { delegates = value; } + } + + public IList Invoke(int index, object instance, object value) + { + if (delegates.Count == 0 || index >= delegates.Count) + return null; + + try + { + if (delegates[index].Target == null) + { + return delegates[index].DynamicInvoke(this, instance, value) as IList; + } + else + { + return delegates[index].DynamicInvoke() as IList; + } + } + catch (Exception e) + { + if (e is TargetInvocationException) + e = ((TargetInvocationException)e).InnerException; + + Debug.LogError(string.Format("Invoking a method to retrieve a Restrict attribute data failed. The exception was \"{0}\".", e.Message)); + return null; + } + } + #endregion + + public RestrictAttribute(string methodName) + : this(methodName, RestrictDisplay.DropDown) { } + + public RestrictAttribute(string methodName, RestrictDisplay display) + { + this.methodName = methodName; + this.display = display; + } + + public RestrictAttribute(Delegate method) + : this(method, RestrictDisplay.DropDown) { } + + public RestrictAttribute(Delegate method, RestrictDisplay display) + { + this.delegates.Add(method); + this.display = display; + } + } + + public enum RestrictDisplay + { + DropDown, + Toolbox, + Button + } +}
\ No newline at end of file diff --git a/Assets/Plugins/AdvancedInspector/Attributes/Restrict.cs.meta b/Assets/Plugins/AdvancedInspector/Attributes/Restrict.cs.meta new file mode 100644 index 00000000..05cc475f --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Attributes/Restrict.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f427a8594327b11458d6ebc38c5fc6b6 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/AdvancedInspector/Attributes/RuntimeResolve.cs b/Assets/Plugins/AdvancedInspector/Attributes/RuntimeResolve.cs new file mode 100644 index 00000000..16a56fc4 --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Attributes/RuntimeResolve.cs @@ -0,0 +1,85 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; + +using UnityEngine; + +namespace AdvancedInspector +{ + /// <summary> + /// Forces a field to display a FieldEditor related to its current runtime type instead of the field type. + /// The Runtime version supply the type itself. Useful when the field value is null or for an unknown object picker. + /// </summary> + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] + public class RuntimeResolveAttribute : Attribute, IListAttribute, IRuntimeAttribute<Type> + { + public delegate Type RuntimeResolveDelegate(); + public delegate Type RuntimeResolveStaticDelegate(RuntimeResolveAttribute runtimeResolve, object instance, object value); + + #region IRuntime Implementation + private string methodName = ""; + + public string MethodName + { + get { return methodName; } + } + + public Type Template + { + get { return typeof(RuntimeResolveDelegate); } + } + + public Type TemplateStatic + { + get { return typeof(RuntimeResolveStaticDelegate); } + } + + private List<Delegate> delegates = new List<Delegate>(); + + public List<Delegate> Delegates + { + get { return delegates; } + set { delegates = value; } + } + + public Type Invoke(int index, object instance, object value) + { + if (delegates.Count == 0 || index >= delegates.Count) + return null; + + try + { + if (delegates[index].Target == null) + { + return delegates[index].DynamicInvoke(this, instance, value) as Type; + } + else + { + return delegates[index].DynamicInvoke() as Type; + } + } + catch (Exception e) + { + if (e is TargetInvocationException) + e = ((TargetInvocationException)e).InnerException; + + Debug.LogError(string.Format("Invoking a method from a RuntimeResolve attribute failed. The exception was \"{0}\".", e.Message)); + return null; + } + } + #endregion + + public RuntimeResolveAttribute() { } + + public RuntimeResolveAttribute(string methodName) + { + this.methodName = methodName; + } + + public RuntimeResolveAttribute(Delegate method) + { + this.delegates.Add(method); + } + } +}
\ No newline at end of file diff --git a/Assets/Plugins/AdvancedInspector/Attributes/RuntimeResolve.cs.meta b/Assets/Plugins/AdvancedInspector/Attributes/RuntimeResolve.cs.meta new file mode 100644 index 00000000..8e5deeb7 --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Attributes/RuntimeResolve.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c41d12d2aa0e9824c828bab3957ce2ea +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/AdvancedInspector/Attributes/Space.cs b/Assets/Plugins/AdvancedInspector/Attributes/Space.cs new file mode 100644 index 00000000..02972663 --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Attributes/Space.cs @@ -0,0 +1,48 @@ +using System; + +namespace AdvancedInspector +{ + /// <summary> + /// Add a space after the current fields. + /// </summary> + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method)] + public class SpacingAttribute : Attribute + { + private int before = 0; + + /// <summary> + /// Size of the space to add before the item. + /// Default is 0. + /// </summary> + public int Before + { + get { return before; } + set { before = value; } + } + + private int after = 0; + + /// <summary> + /// Size of the space to add after the item. + /// Default is 1. + /// </summary> + public int After + { + get { return after; } + set { after = value; } + } + + public SpacingAttribute() { } + + public SpacingAttribute(int after) + { + this.after = after; + } + + public SpacingAttribute(int before, int after) + { + this.after = after; + this.before = before; + } + } +}
\ No newline at end of file diff --git a/Assets/Plugins/AdvancedInspector/Attributes/Space.cs.meta b/Assets/Plugins/AdvancedInspector/Attributes/Space.cs.meta new file mode 100644 index 00000000..3c698339 --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Attributes/Space.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 342298f826c259a4f8efdca9740e39a6 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/AdvancedInspector/Attributes/Style.cs b/Assets/Plugins/AdvancedInspector/Attributes/Style.cs new file mode 100644 index 00000000..5ffa27ac --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Attributes/Style.cs @@ -0,0 +1,43 @@ +using System; + +namespace AdvancedInspector +{ + /// <summary> + /// Allow to change the style of an field item. + /// </summary> + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Method)] + public class StyleAttribute : Attribute + { + private string style = ""; + + /// <summary> + /// Name of the style to use. + /// Must be findable by GUI.skin.Find() + /// </summary> + public string Style + { + get { return style; } + set { style = value; } + } + + private bool label = true; + + /// <summary> + /// Force or prevent the field's label from being displayed. + /// </summary> + public bool Label + { + get { return label; } + set { label = value; } + } + + public StyleAttribute(string style) + : this(style, true) { } + + public StyleAttribute(string style, bool label) + { + this.style = style; + this.label = label; + } + } +}
\ No newline at end of file diff --git a/Assets/Plugins/AdvancedInspector/Attributes/Style.cs.meta b/Assets/Plugins/AdvancedInspector/Attributes/Style.cs.meta new file mode 100644 index 00000000..fcb288c0 --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Attributes/Style.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e4345a0f2d3a3744d90ee1c995161357 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/AdvancedInspector/Attributes/Tab.cs b/Assets/Plugins/AdvancedInspector/Attributes/Tab.cs new file mode 100644 index 00000000..a7efea4d --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Attributes/Tab.cs @@ -0,0 +1,25 @@ +using System; + +namespace AdvancedInspector +{ + /// <summary> + /// The tabs allows to create a collection of tabs at the top based on an Enum's values. + /// Hides or shows items that are part of the selected tab. + /// </summary> + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Method)] + public class TabAttribute : Attribute + { + private Enum tab; + + public Enum Tab + { + get { return tab; } + set { tab = value; } + } + + public TabAttribute(object tab) + { + this.tab = (Enum)tab; + } + } +}
\ No newline at end of file diff --git a/Assets/Plugins/AdvancedInspector/Attributes/Tab.cs.meta b/Assets/Plugins/AdvancedInspector/Attributes/Tab.cs.meta new file mode 100644 index 00000000..4c19797c --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Attributes/Tab.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b3a31f241bcc75944a1919a273e85010 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/AdvancedInspector/Attributes/TextField.cs b/Assets/Plugins/AdvancedInspector/Attributes/TextField.cs new file mode 100644 index 00000000..555fa1cb --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Attributes/TextField.cs @@ -0,0 +1,87 @@ +using System; + +namespace AdvancedInspector +{ + /// <summary> + /// This allows control over how a string field is displayed. + /// Only useful on string field. + /// </summary> + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)] + public class TextFieldAttribute : Attribute, IListAttribute + { + private const string TITLE = "Select Path..."; + private const string PATH = ""; + private const string EXTENSION = ""; + + private string title = ""; + + /// <summary> + /// Title of the modal dialog + /// </summary> + public string Title + { + get { return title; } + set { title = value; } + } + + private string path = "C:\\"; + + /// <summary> + /// Default file/folder path + /// </summary> + public string Path + { + get { return path; } + set { path = value; } + } + + private string extension = ""; + + /// <summary> + /// Force the file dialog to show only specific file type. + /// </summary> + public string Extension + { + get { return extension; } + set { extension = value; } + } + + private TextFieldType type; + + /// <summary> + /// What type of control is this string. + /// </summary> + public TextFieldType Type + { + get { return type; } + set { type = value; } + } + + public TextFieldAttribute(TextFieldType type) + : this(type, TITLE, PATH, EXTENSION) { } + + public TextFieldAttribute(TextFieldType type, string title) + : this(type, title, PATH, EXTENSION) { } + + public TextFieldAttribute(TextFieldType type, string title, string path) + : this(type, title, path, EXTENSION) { } + + public TextFieldAttribute(TextFieldType type, string title, string path, string extension) + { + this.type = type; + this.title = title; + this.path = path; + this.extension = extension; + } + } + + public enum TextFieldType + { + Standard, + Password, + Area, + Tag, + File, + Folder + } +}
\ No newline at end of file diff --git a/Assets/Plugins/AdvancedInspector/Attributes/TextField.cs.meta b/Assets/Plugins/AdvancedInspector/Attributes/TextField.cs.meta new file mode 100644 index 00000000..9aeb2b82 --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Attributes/TextField.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ce81aa34d03e9e84a981812d142a46a1 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/AdvancedInspector/Attributes/Title.cs b/Assets/Plugins/AdvancedInspector/Attributes/Title.cs new file mode 100644 index 00000000..2330db37 --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Attributes/Title.cs @@ -0,0 +1,111 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Linq; +using System.Text; + +using UnityEngine; + +namespace AdvancedInspector +{ + /// <summary> + /// Similar to Unity "Header" attribute, but can be place on any members and be set at runtime. + /// </summary> + [AttributeUsage(AttributeTargets.Field | AttributeTargets.Property | AttributeTargets.Method)] + public class TitleAttribute : Attribute, IRuntimeAttribute<TitleAttribute> + { + public delegate TitleAttribute TitleDelegate(); + public delegate TitleAttribute TitleStaticDelegate(TitleAttribute title, object instance, object value); + + private string message; + + /// <summary> + /// The title message + /// </summary> + public string Message + { + get { return message; } + set { message = value; } + } + + private FontStyle style = FontStyle.Bold; + + /// <summary> + /// The font style. + /// </summary> + public FontStyle Style + { + get { return style; } + set { style = value; } + } + + #region IRuntime Implementation + private string methodName = ""; + + public string MethodName + { + get { return methodName; } + } + + public Type Template + { + get { return typeof(TitleDelegate); } + } + + public Type TemplateStatic + { + get { return typeof(TitleStaticDelegate); } + } + + private List<Delegate> delegates = new List<Delegate>(); + + public List<Delegate> Delegates + { + get { return delegates; } + set { delegates = value; } + } + + public TitleAttribute Invoke(int index, object instance, object value) + { + if (delegates.Count == 0 || index >= delegates.Count) + return this; + + try + { + if (delegates[index].Target == null) + { + return delegates[0].DynamicInvoke(this, instance, value) as TitleAttribute; + } + else + { + return delegates[0].DynamicInvoke() as TitleAttribute; + } + } + catch (Exception e) + { + if (e is TargetInvocationException) + e = ((TargetInvocationException)e).InnerException; + + Debug.LogError(string.Format("Invoking a method failed while trying to retrieve a Title attribute. The exception was \"{0}\".", e.Message)); + return null; + } + } + #endregion + + public TitleAttribute(string methodName) + { + this.methodName = methodName; + } + + public TitleAttribute(FontStyle style, string message) + { + this.style = style; + this.message = message; + } + + public TitleAttribute(Delegate method) + { + this.delegates.Add(method); + } + } +} diff --git a/Assets/Plugins/AdvancedInspector/Attributes/Title.cs.meta b/Assets/Plugins/AdvancedInspector/Attributes/Title.cs.meta new file mode 100644 index 00000000..f0377be3 --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Attributes/Title.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 50a11bb467421824c95d21c7fb6d8073 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/AdvancedInspector/Attributes/Toolbar.cs b/Assets/Plugins/AdvancedInspector/Attributes/Toolbar.cs new file mode 100644 index 00000000..8044b984 --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Attributes/Toolbar.cs @@ -0,0 +1,108 @@ +using System; + +namespace AdvancedInspector +{ + /// <summary> + /// Allow to groups inspector items. + /// </summary> + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Method)] + public class ToolbarAttribute : Attribute + { + public const string ToolbarStyle = "Toolbar"; + + private string name = ""; + + /// <summary> + /// Name of the toolbar, used to group items. + /// If Label is true, the name is displayed. + /// </summary> + public string Name + { + get { return name; } + set { name = value; } + } + + private string style = ""; + + /// <summary> + /// Style of this toolbar. Defaul; "Toolbar" + /// Only need to be flagged on one item. + /// </summary> + public string Style + { + get { return style; } + set { style = value; } + } + + private bool label = false; + + /// <summary> + /// Show or hide the toolbar label + /// Only need to be flagged on one item. + /// </summary> + public bool Label + { + get { return label; } + set { label = value; } + } + + private bool flexible = false; + + /// <summary> + /// This specific item will have a Flexible Space before + /// </summary> + public bool Flexible + { + get { return flexible; } + set { flexible = value; } + } + + private int priority = 0; + + /// <summary> + /// Priority of this toolbar when sorting items. + /// Only need to be flagged on one item. + /// </summary> + public int Priority + { + get { return priority; } + set { priority = value; } + } + + public ToolbarAttribute(string name) + : this(name, "", false, false, 0) { } + + public ToolbarAttribute(string name, int priority) + : this(name, "", false, false, priority) { } + + public ToolbarAttribute(string name, string style) + : this(name, style, false, false, 0) { } + + public ToolbarAttribute(string name, string style, int priority) + : this(name, style, false, false, priority) { } + + public ToolbarAttribute(string name, bool label) + : this(name, "", label, false, 0) { } + + public ToolbarAttribute(string name, bool label, int priority) + : this(name, "", label, false, priority) { } + + public ToolbarAttribute(string name, string style, bool label) + : this(name, style, label, false, 0) { } + + public ToolbarAttribute(string name, string style, bool label, int priority) + : this(name, style, label, false, priority) { } + + public ToolbarAttribute(string name, string style, bool label, bool flexible) + : this(name, style, label, flexible, 0) { } + + public ToolbarAttribute(string name, string style, bool label, bool flexible, int priority) + { + this.name = name; + this.style = style; + this.label = label; + this.flexible = flexible; + this.priority = priority; + } + } +}
\ No newline at end of file diff --git a/Assets/Plugins/AdvancedInspector/Attributes/Toolbar.cs.meta b/Assets/Plugins/AdvancedInspector/Attributes/Toolbar.cs.meta new file mode 100644 index 00000000..1b49b862 --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Attributes/Toolbar.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 03350da06d5fe9643b20b6796771ad56 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/AdvancedInspector/Core.meta b/Assets/Plugins/AdvancedInspector/Core.meta new file mode 100644 index 00000000..c6c63969 --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Core.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 0d71452a5ed8d3c4a9a83a9e27d4d2bd +folderAsset: yes +DefaultImporter: + userData: diff --git a/Assets/Plugins/AdvancedInspector/Core/ActionBinding.cs b/Assets/Plugins/AdvancedInspector/Core/ActionBinding.cs new file mode 100644 index 00000000..55573bbd --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Core/ActionBinding.cs @@ -0,0 +1,744 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; + +using UnityEngine; + +namespace AdvancedInspector +{ + /// <summary> + /// This class represent an event, and allows the Inspector to bind it to another method. + /// Arguments can be sent to the invoked method from a static field, internal from the code invoking, or from another method returned value. + /// </summary> + [Serializable, AdvancedInspector] + public class ActionBinding : ICopiable + { + [SerializeField] + private string[] internalParameters = new string[0]; + + [SerializeField] + private GameObject gameObject; + + [Inspect] + public GameObject GameObject + { + get { return gameObject; } + set + { + if (gameObject != value) + { + gameObject = value; + Component = null; + } + } + } + + [SerializeField] + private Component component; + + [Inspect, Restrict("GetComponents")] + public Component Component + { + get { return component; } + set + { + if (component != value) + { + component = value; + Method = null; + } + } + } + + private IList GetComponents() + { + List<DescriptorPair> components = new List<DescriptorPair>(); + if (gameObject == null) + return components; + + foreach (Component component in gameObject.GetComponents(typeof(Component))) + components.Add(new DescriptorPair(component, new DescriptorAttribute(component.GetType().Name, ""))); + + return components; + } + + [SerializeField] + private string method; + + [Inspect, Restrict("GetMethods", RestrictDisplay.Toolbox)] + public MethodInfo Method + { + get { return GetMethodInfo(); } + set + { + if (value == null) + { + parameters = new BindingParameter[0]; + method = ""; + return; + } + + MethodInfo info = GetMethodInfo(); + if (info != value) + { + method = value.Name; + ParameterInfo[] param = value.GetParameters(); + parameters = new BindingParameter[param.Length]; + for (int i = 0; i < param.Length; i++) + { + parameters[i] = new BindingParameter(internalParameters.Length > i); + parameters[i].Type = param[i].ParameterType; + if (internalParameters.Length > i) + parameters[i].binding = BindingParameter.BindingType.Internal; + } + } + } + } + + private IList GetMethods() + { + List<DescriptorPair> methods = new List<DescriptorPair>(); + if (gameObject == null || component == null) + return methods; + + foreach (MethodInfo info in component.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy)) + { + if (info.IsGenericMethod || info.IsConstructor || info.IsFinal || info.IsSpecialName || info.DeclaringType == typeof(object) || info.DeclaringType == typeof(Component)) + continue; + + if (!IsMethodValid(info)) + continue; + + ParameterInfo[] param = info.GetParameters(); + + methods.Add(new DescriptorPair(info, new DescriptorAttribute(GetParamNames(info.Name, param), ""))); + } + + foreach (PropertyInfo info in component.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy)) + { + if (!info.CanWrite || info.DeclaringType == typeof(object) || info.DeclaringType == typeof(UnityEngine.Object) || info.DeclaringType == typeof(Component)) + continue; + + MethodInfo method = info.GetSetMethod(); + if (method == null || !IsMethodValid(method)) + continue; + + ParameterInfo[] param = method.GetParameters(); + + methods.Add(new DescriptorPair(method, new DescriptorAttribute(GetParamNames(info.Name, param), ""))); + } + + return methods; + } + + private bool IsMethodValid(MethodInfo info) + { + ParameterInfo[] param = info.GetParameters(); + + bool valid = true; + for (int i = 0; i < param.Length; i++) + { + if (!BindingParameter.IsValidType(param[i].ParameterType)) + { + valid = false; + break; + } + + if (internalParameters.Length > i) + { + Type type = Type.GetType(internalParameters[i]); + if (!type.IsAssignableFrom(param[i].ParameterType)) + { + valid = false; + break; + } + } + } + + return valid; + } + + private string GetParamNames(string name, ParameterInfo[] param) + { + string paramName = name + " ("; + for (int i = 0; i < param.Length; i++) + { + paramName += param[i].ParameterType.Name; + if (i < param.Length - 1) + paramName += ", "; + } + paramName += ")"; + + return paramName; + } + + private MethodInfo GetMethodInfo() + { + if (gameObject == null || component == null || string.IsNullOrEmpty(method)) + return null; + + Type[] types = new Type[parameters.Length]; + for (int i = 0; i < parameters.Length; i++) + types[i] = parameters[i].Type; + + return component.GetType().GetMethod(method, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy, null, types, null); + } + + [Inspect, Collection(0, false), SerializeField] + private BindingParameter[] parameters = new BindingParameter[0]; + + public event ActionEventHandler OnInvoke; + + /// <summary> + /// Parameter-less method constructor. + /// </summary> + public ActionBinding() { } + + /// <summary> + /// The array of types is the method definition. + /// Method with the wrong parameters are not selectable. + /// </summary> + public ActionBinding(Type[] types) + { + internalParameters = new string[types.Length]; + for (int i = 0; i < types.Length; i++) + internalParameters[i] = types[i].AssemblyQualifiedName; + } + + /// <summary> + /// Invoke the method. + /// Be careful to pass the proper type as args, otherwise they will be ignored. + /// Args are only retained if the parameter is flagged as internal. + /// </summary> + public void Invoke(params object[] args) + { + if (gameObject == null || component == null || string.IsNullOrEmpty(method)) + return; + + MethodInfo info = GetMethodInfo(); + if (info == null) + return; + + object[] values = new object[parameters.Length]; + for (int i = 0; i < parameters.Length; i++) + { + if (args.Length > i && parameters[i].binding == BindingParameter.BindingType.Internal) + values[i] = args[i]; + else + values[i] = parameters[i].Value; + } + + info.Invoke(component, values); + + if (OnInvoke != null) + OnInvoke(this, values); + } + + public override string ToString() + { + string supplied = "("; + for (int i = 0; i < internalParameters.Length; i++) + { + supplied += Type.GetType(internalParameters[i]).Name; + if (i < internalParameters.Length - 1) + supplied += ", "; + } + + supplied += ")"; + + if (component != null) + return component.GetType().Name + " : " + method + " : " + supplied; + else + return supplied; + } + + public bool Copiable(object destination) + { + ActionBinding action = destination as ActionBinding; + if (action == null) + return false; + + if (action.internalParameters.Length != internalParameters.Length) + return false; + + for (int i = 0; i < internalParameters.Length; i++) + if (internalParameters[i] != action.internalParameters[i]) + return false; + + return true; + } + + /// <summary> + /// The binding parameter define how each of the argument of the invoked method is handled. + /// </summary> + [Serializable, AdvancedInspector] + public class BindingParameter : ICopy, ICopiable + { + [Inspect(-1), Restrict("RestrictBinding")] + public BindingType binding; + + private IList RestrictBinding() + { + List<object> list = new List<object>(); + if (canBeInternal) + list.Add(BindingType.Internal); + + list.Add(BindingType.Static); + list.Add(BindingType.External); + return list; + } + + private bool canBeInternal = true; + + private bool CanBeInternal + { + get { return canBeInternal; } + } + + #region Values + [SerializeField] + private BindingValueType type; + + [SerializeField] + private string qualifiedTypeName; + + public Type Type + { + get + { + if (string.IsNullOrEmpty(qualifiedTypeName)) + return null; + else + return Type.GetType(qualifiedTypeName); + } + + set + { + if (value == typeof(bool)) + type = BindingValueType.Boolean; + else if (value == typeof(Bounds)) + type = BindingValueType.Bounds; + else if (value == typeof(Color)) + type = BindingValueType.Color; + else if (value == typeof(float)) + type = BindingValueType.Float; + else if (value == typeof(int)) + type = BindingValueType.Integer; + else if (value == typeof(Rect)) + type = BindingValueType.Rect; + else if (typeof(UnityEngine.Object).IsAssignableFrom(value)) + type = BindingValueType.Reference; + else if (value == typeof(string)) + type = BindingValueType.String; + else if (value == typeof(Vector2)) + type = BindingValueType.Vector2; + else if (value == typeof(Vector3)) + type = BindingValueType.Vector3; + else if (value == typeof(Vector4)) + type = BindingValueType.Vector4; + else + type = BindingValueType.None; + + if (type != BindingValueType.None) + qualifiedTypeName = value.AssemblyQualifiedName; + else + qualifiedTypeName = ""; + } + } + + [Inspect(-2)] + public string BoundType + { + get + { + if (Type == null) + return ""; + + return Type.Name; + } + } + + [SerializeField] + private bool boolValue = false; + [SerializeField] + private int intValue = 0; + [SerializeField] + private float floatValue = 0; + [SerializeField] + private string stringValue = ""; + [SerializeField] + private Vector2 vector2Value = Vector2.zero; + [SerializeField] + private Vector3 vector3Value = Vector3.zero; + [SerializeField] + private Vector4 vector4Value = Vector4.zero; + [SerializeField] + private Color colorValue = Color.black; + [SerializeField] + private Rect rectValue = new Rect(0, 0, 0, 0); + [SerializeField] + private Bounds boundsValue = new Bounds(Vector3.zero, Vector3.zero); + [SerializeField] + private UnityEngine.Object referenceValue = new UnityEngine.Object(); + #endregion + + [Inspect("IsStatic")] + [RuntimeResolve("GetRuntimeType")] + public object Value + { + get + { + if (binding == BindingType.External) + { + object value = Invoke(); + if (value.GetType().IsAssignableFrom(Type)) + return value; + + System.ComponentModel.TypeConverter converter = System.ComponentModel.TypeDescriptor.GetConverter(Type); + return converter.ConvertTo(value, Type); + } + + switch (type) + { + case BindingValueType.Boolean: + return boolValue; + case BindingValueType.Bounds: + return boundsValue; + case BindingValueType.Color: + return colorValue; + case BindingValueType.Float: + return floatValue; + case BindingValueType.Integer: + return intValue; + case BindingValueType.Rect: + return rectValue; + case BindingValueType.Reference: + return referenceValue; + case BindingValueType.String: + return stringValue; + case BindingValueType.Vector2: + return vector2Value; + case BindingValueType.Vector3: + return vector3Value; + case BindingValueType.Vector4: + return vector4Value; + default: + return null; + } + } + + set + { + if (value == null && type != BindingValueType.Reference) + return; + + switch (type) + { + case BindingValueType.Boolean: + boolValue = (bool)value; + break; + case BindingValueType.Bounds: + boundsValue = (Bounds)value; + break; + case BindingValueType.Color: + colorValue = (Color)value; + break; + case BindingValueType.Float: + floatValue = (float)value; + break; + case BindingValueType.Integer: + intValue = (int)value; + break; + case BindingValueType.Rect: + rectValue = (Rect)value; + break; + case BindingValueType.Reference: + referenceValue = (UnityEngine.Object)value; + break; + case BindingValueType.String: + stringValue = (string)value; + break; + case BindingValueType.Vector2: + vector2Value = (Vector2)value; + break; + case BindingValueType.Vector3: + vector3Value = (Vector3)value; + break; + case BindingValueType.Vector4: + vector4Value = (Vector4)value; + break; + default: + return; + } + } + } + + [SerializeField] + private GameObject gameObject; + + [Inspect("IsExternal")] + public GameObject GameObject + { + get { return gameObject; } + set + { + if (gameObject != value) + { + gameObject = value; + Component = null; + } + } + } + + [SerializeField] + private Component component; + + [Inspect("IsExternal")] + [Restrict("GetComponents")] + public Component Component + { + get { return component; } + set + { + if (component != value) + { + component = value; + Method = null; + } + } + } + + private IList GetComponents() + { + List<DescriptorPair> components = new List<DescriptorPair>(); + if (gameObject == null) + return components; + + foreach (Component component in gameObject.GetComponents(typeof(Component))) + components.Add(new DescriptorPair(component, new DescriptorAttribute(component.GetType().Name, ""))); + + return components; + } + + [SerializeField] + private string method; + + [Inspect("IsExternal")] + [Restrict("GetMethods", RestrictDisplay.Toolbox)] + public MethodInfo Method + { + get { return GetMethodInfo(); } + set + { + if (value == null) + { + method = ""; + return; + } + + MethodInfo info = GetMethodInfo(); + if (info != value) + method = value.Name; + } + } + + private IList GetMethods() + { + List<DescriptorPair> methods = new List<DescriptorPair>(); + if (gameObject == null || component == null) + return methods; + + foreach (MethodInfo info in component.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy)) + { + if (info.IsGenericMethod || info.IsConstructor || info.IsFinal || info.IsSpecialName) + continue; + + if (!IsMethodValid(info)) + continue; + + string paramName = info.ReturnType.Name + " " + info.Name + "()"; + methods.Add(new DescriptorPair(info, new DescriptorAttribute(paramName, ""))); + } + + foreach (PropertyInfo info in component.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy)) + { + if (!info.CanRead) + continue; + + MethodInfo method = info.GetGetMethod(); + if (method == null || !IsMethodValid(method)) + continue; + + string paramName = method.ReturnType.Name + " " + info.Name + "()"; + methods.Add(new DescriptorPair(method, new DescriptorAttribute(paramName, ""))); + } + + return methods; + } + + private bool IsMethodValid(MethodInfo info) + { + ParameterInfo[] param = info.GetParameters(); + if (param.Length > 0) + return false; + + if (info.ReturnType == null || info.ReturnType == typeof(void)) + return false; + + System.ComponentModel.TypeConverter converter = System.ComponentModel.TypeDescriptor.GetConverter(info.ReturnType); + if (!Type.IsAssignableFrom(info.ReturnType) && !converter.CanConvertTo(Type)) + return false; + + return true; + } + + private MethodInfo GetMethodInfo() + { + if (gameObject == null || component == null || string.IsNullOrEmpty(method)) + return null; + + return component.GetType().GetMethod(method, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy); + } + + private bool IsStatic() + { + return binding == BindingType.Static; + } + + private bool IsExternal() + { + return binding == BindingType.External; + } + + private Type GetRuntimeType() + { + return Type; + } + + public BindingParameter() { } + + public BindingParameter(bool canBeInternal) + { + this.canBeInternal = canBeInternal; + } + + public static bool IsValidType(Type type) + { + if (type == typeof(bool)) + return true; + else if (type == typeof(Bounds)) + return true; + else if (type == typeof(Color)) + return true; + else if (type == typeof(float)) + return true; + else if (type == typeof(int)) + return true; + else if (type == typeof(Rect)) + return true; + else if (typeof(UnityEngine.Object).IsAssignableFrom(type)) + return true; + else if (type == typeof(string)) + return true; + else if (type == typeof(Vector2)) + return true; + else if (type == typeof(Vector3)) + return true; + else if (type == typeof(Vector4)) + return true; + + return false; + } + + public enum BindingType + { + Internal, + Static, + External + } + + private enum BindingValueType + { + None, + + Boolean, + Integer, + Float, + String, + Vector2, + Vector3, + Vector4, + Color, + Rect, + Bounds, + Reference + } + + private object Invoke() + { + if (gameObject == null || component == null || string.IsNullOrEmpty(method)) + return null; + + MethodInfo info = GetMethodInfo(); + if (info == null) + return null; + + return info.Invoke(component, new object[0]); + } + + public bool Copiable(object destination) + { + BindingParameter target = destination as BindingParameter; + if (target == null) + return false; + + if (target.type != type) + return false; + + if (!target.canBeInternal && binding == BindingType.Internal) + return false; + + return true; + } + + public object Copy(object destination) + { + BindingParameter target = destination as BindingParameter; + + BindingParameter copy = new BindingParameter(); + if (target != null) + copy.canBeInternal = target.canBeInternal; + else + copy.canBeInternal = canBeInternal; + + copy.binding = binding; + copy.boolValue = boolValue; + copy.boundsValue = boundsValue; + copy.colorValue = colorValue; + copy.component = component; + copy.floatValue = floatValue; + copy.gameObject = gameObject; + copy.intValue = intValue; + copy.method = method; + copy.qualifiedTypeName = qualifiedTypeName; + copy.rectValue = rectValue; + copy.referenceValue = referenceValue; + copy.stringValue = stringValue; + copy.type = type; + copy.vector2Value = vector2Value; + copy.vector3Value = vector3Value; + copy.vector4Value = vector4Value; + + return copy; + } + + public override string ToString() + { + return type.ToString(); + } + } + } +}
\ No newline at end of file diff --git a/Assets/Plugins/AdvancedInspector/Core/ActionBinding.cs.meta b/Assets/Plugins/AdvancedInspector/Core/ActionBinding.cs.meta new file mode 100644 index 00000000..1b2c79dc --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Core/ActionBinding.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3dda590f8ffeb5848b2e6775c1caa63a +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/AdvancedInspector/Core/ComponentMonoBehaviour.cs b/Assets/Plugins/AdvancedInspector/Core/ComponentMonoBehaviour.cs new file mode 100644 index 00000000..e5d04884 --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Core/ComponentMonoBehaviour.cs @@ -0,0 +1,199 @@ +using UnityEngine; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; + +namespace AdvancedInspector +{ + /// <summary> + /// ScriptableObject are not serializable within the scope of a GameObject. + /// Therefore, they are improper to prefab, copy and so on. + /// This class' goal is to provide a polymorphic solution and give an easy way of handling up front. + /// + /// Derived from Object; no polymorphism supported. + /// Derived from ScriptableObject; cannot be prefabed, copied, duplicated or instanced. + /// Derived from MonoBehaviour; can only live on a GameObject. + /// + /// A ComponentMonoBehaviour is created from another MonoBehaviour; its parent. + /// A parent can be another ComponentMonoBehaviour. + /// If the parent is destroyed, the subcomponent is destroyed too. + /// If a subcomponent is found without a parent, it's destroyed too. + /// </summary> + [AdvancedInspector] + public abstract class ComponentMonoBehaviour : MonoBehaviour + { + [SerializeField] + private MonoBehaviour owner; + + /// <summary> + /// The owner of a "subcomponent". + /// Use to know if this component lost its parent. + /// If so, the AdvancedInspector will delete any unused component. + /// </summary> + public MonoBehaviour Owner + { + get { return owner; } + set + { + if (value != null) + owner = value; + } + } + + /// <summary> + /// A subcomponent is not visible the normal way in the Inspector. + /// It's shown as being part of another item. + /// </summary> + protected virtual void Reset() + { + hideFlags = HideFlags.HideInInspector; + } + + /// <summary> + /// Called when the inspector is about to destroy this one. + /// Loop in all the internal and destroy sub-components. + /// </summary> + public void Erase() + { + foreach (FieldInfo info in GetFields(GetType(), false)) + { + object value = info.GetValue(this); + + if (value is ComponentMonoBehaviour) + { + ComponentMonoBehaviour component = value as ComponentMonoBehaviour; + + if (component.Owner == Owner) + component.Erase(); + } + } + + DestroyImmediate(this, true); + } + + /// <summary> + /// Instanciate an existing Component on the same owner GameObject + /// </summary> + public ComponentMonoBehaviour Instantiate() + { + return Instantiate(gameObject, Owner); + } + + /// <summary> + /// Instanciate an existing Component on the same owner GameObject but with a new onwer. + /// </summary> + public ComponentMonoBehaviour Instantiate(MonoBehaviour owner) + { + return Instantiate(gameObject, owner); + } + + /// <summary> + /// Instanciate an existing Component on the target GameObject. + /// </summary> + public ComponentMonoBehaviour Instantiate(GameObject go, MonoBehaviour owner) + { + return CopyObject(go, owner, this) as ComponentMonoBehaviour; + } + + private static object CopyObject(GameObject go, MonoBehaviour owner, object original) + { + if (original == null) + return null; + + Type type = original.GetType(); + + if (type == typeof(string)) + + return ((string)original).Clone(); + else if (type.Namespace == "System") + return original; + else if (typeof(IList).IsAssignableFrom(type)) + return CopyList(go, owner, (IList)original); + else if (typeof(ComponentMonoBehaviour).IsAssignableFrom(type) && ((ComponentMonoBehaviour)original).Owner == owner) + return CopyComponent(go, owner, (ComponentMonoBehaviour)original); + else if (typeof(Component).IsAssignableFrom(type)) + return original; + else if (typeof(ScriptableObject).IsAssignableFrom(type)) + return ScriptableObject.Instantiate((ScriptableObject)original); + else if (typeof(UnityEngine.Object).IsAssignableFrom(type)) + return original; + else if (type.IsClass) + return CopyClass(go, owner, original); + else + return original; + } + + private static IList CopyList(GameObject go, MonoBehaviour owner, IList original) + { + Type type = original.GetType(); + IList copy; + + if (type.IsArray) + { + copy = Array.CreateInstance(type.GetElementType(), original.Count); + for (int i = 0; i < original.Count; i++) + copy[i] = CopyObject(go, owner, original[i]); + } + else + { + copy = Activator.CreateInstance(type) as IList; + for (int i = 0; i < original.Count; i++) + copy.Add(CopyObject(go, owner, original[i])); + + } + + return copy; + } + + private static ComponentMonoBehaviour CopyComponent(GameObject go, MonoBehaviour owner, ComponentMonoBehaviour original) + { + Type type = original.GetType(); + ComponentMonoBehaviour copy = go.AddComponent(original.GetType()) as ComponentMonoBehaviour; + + foreach (FieldInfo info in GetFields(type, false)) + { + if (info.IsLiteral) + continue; + + info.SetValue(copy, CopyObject(go, copy, info.GetValue(original))); + } + + copy.Owner = owner; + + return copy; + } + + private static object CopyClass(GameObject go, MonoBehaviour owner, object original) + { + Type type = original.GetType(); + object copy = Activator.CreateInstance(type); + + foreach (FieldInfo info in GetFields(type, false)) + { + if (info.IsLiteral) + continue; + + info.SetValue(copy, CopyObject(go, owner, info.GetValue(original))); + } + + return copy; + } + + private static List<FieldInfo> GetFields(Type type, bool recursive) + { + List<FieldInfo> infos; + + if (recursive) + infos = type.GetFields(BindingFlags.NonPublic | BindingFlags.Instance).ToList(); + else + infos = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy).ToList(); + + if (type.BaseType != null && type.BaseType != typeof(object)) + infos.AddRange(GetFields(type.BaseType, true)); + + return infos; + } + } +}
\ No newline at end of file diff --git a/Assets/Plugins/AdvancedInspector/Core/ComponentMonoBehaviour.cs.meta b/Assets/Plugins/AdvancedInspector/Core/ComponentMonoBehaviour.cs.meta new file mode 100644 index 00000000..d987b370 --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Core/ComponentMonoBehaviour.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d411934b81db62841acf60342a15b9c3 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/AdvancedInspector/Core/RangeFloat.cs b/Assets/Plugins/AdvancedInspector/Core/RangeFloat.cs new file mode 100644 index 00000000..f7442db6 --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Core/RangeFloat.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace AdvancedInspector +{ + [Serializable] + public struct RangeFloat + { + public float min; + public float max; + + public RangeFloat(float min, float max) + { + this.min = min; + this.max = max; + } + } +}
\ No newline at end of file diff --git a/Assets/Plugins/AdvancedInspector/Core/RangeFloat.cs.meta b/Assets/Plugins/AdvancedInspector/Core/RangeFloat.cs.meta new file mode 100644 index 00000000..a2c19ce3 --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Core/RangeFloat.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bee2349f549bbc341bd8f823cb45ccbf +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/AdvancedInspector/Core/RangeInt.cs b/Assets/Plugins/AdvancedInspector/Core/RangeInt.cs new file mode 100644 index 00000000..bfe55c58 --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Core/RangeInt.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace AdvancedInspector +{ + [Serializable] + public struct RangeInt + { + public int min; + public int max; + + public RangeInt(int min, int max) + { + this.min = min; + this.max = max; + } + } +}
\ No newline at end of file diff --git a/Assets/Plugins/AdvancedInspector/Core/RangeInt.cs.meta b/Assets/Plugins/AdvancedInspector/Core/RangeInt.cs.meta new file mode 100644 index 00000000..3b73338c --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Core/RangeInt.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6c92ce2aa7de2a7438784b0cc719f9ac +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/AdvancedInspector/Core/UDictionary.cs b/Assets/Plugins/AdvancedInspector/Core/UDictionary.cs new file mode 100644 index 00000000..5322154f --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Core/UDictionary.cs @@ -0,0 +1,230 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Runtime.InteropServices; +using System.Runtime.Serialization; +using System.Text; + +using UnityEngine; + +namespace AdvancedInspector +{ + [Serializable] + [ComVisible(false)] + [DebuggerDisplay("Count = {Count}")] + public class UDictionary<TKey, TValue> : IDictionary<TKey, TValue>, ICollection<KeyValuePair<TKey, TValue>>, IEnumerable<KeyValuePair<TKey, TValue>>, IDictionary, ICollection, IEnumerable, ISerializable, IDeserializationCallback, ISerializationCallbackReceiver + { + [SerializeField] + private List<TKey> keys = new List<TKey>(); + + [SerializeField] + private List<TValue> values = new List<TValue>(); + + [NonSerialized] + private Dictionary<TKey, TValue> dictionary = new Dictionary<TKey, TValue>(); + + #region Implementation of ISerializationCallbackReceiver + public void OnAfterDeserialize() + { + dictionary.Clear(); + for (int i = 0; i < keys.Count; i++) + if (keys[i] != null && (!(keys[i] is UnityEngine.Object) || ((UnityEngine.Object)(object)keys[i]))) + dictionary.Add(keys[i], values[i]); + } + + public void OnBeforeSerialize() + { + keys.Clear(); + values.Clear(); + foreach (KeyValuePair<TKey, TValue> pair in dictionary) + { + if (pair.Key == null || (pair.Key is UnityEngine.Object && !((UnityEngine.Object)(object)pair.Key))) + continue; + + keys.Add(pair.Key); + values.Add(pair.Value); + } + } + #endregion + + #region Implementation of ISerializable + public void GetObjectData(SerializationInfo info, StreamingContext context) + { + dictionary.GetObjectData(info, context); + } + #endregion + + #region Implementation of IDeserializationCallback + public void OnDeserialization(object sender) + { + dictionary.OnDeserialization(sender); + } + #endregion + + #region Implementation IDictionary + public bool IsFixedSize + { + get { return false; } + } + + public ICollection<TKey> Keys + { + get { return dictionary.Keys; } + } + + ICollection IDictionary.Keys + { + get { return dictionary.Keys; } + } + + public ICollection<TValue> Values + { + get { return dictionary.Values; } + } + + ICollection IDictionary.Values + { + get { return dictionary.Values; } + } + + public TValue this[TKey key] + { + get { return dictionary[key]; } + set { dictionary[key] = value; } + } + + object IDictionary.this[object key] + { + get + { + if (!(key is TKey)) + return null; + + return dictionary[(TKey)key]; + } + set + { + if (!(key is TKey)) + return; + + if (!(value is TValue) && value != null) + return; + + dictionary[(TKey)key] = (TValue)value; + } + } + + public void Add(TKey key, TValue value) + { + dictionary.Add(key, value); + } + + void IDictionary.Add(object key, object value) + { + if (!(key is TKey)) + return; + + if (!(value is TValue) && value != null) + return; + + dictionary.Add((TKey)key, (TValue)value); + } + + public bool ContainsKey(TKey key) + { + return dictionary.ContainsKey(key); + } + + bool IDictionary.Contains(object key) + { + if (!(key is TKey)) + return false; + + return dictionary.ContainsKey((TKey)key); + } + + public bool Remove(TKey key) + { + return dictionary.Remove(key); + } + + void IDictionary.Remove(object key) + { + if (!(key is TKey)) + return; + + dictionary.Remove((TKey)key); + } + + public bool TryGetValue(TKey key, out TValue value) + { + return dictionary.TryGetValue(key, out value); + } + + IDictionaryEnumerator IDictionary.GetEnumerator() + { + return ((IDictionary)dictionary).GetEnumerator(); + } + #endregion + + #region Implementation ICollection + public int Count + { + get { return dictionary.Count; } + } + + public bool IsReadOnly + { + get { return false; } + } + + public bool IsSynchronized + { + get { return false; } + } + + public object SyncRoot + { + get { return null; } + } + + public void Add(KeyValuePair<TKey, TValue> item) + { + dictionary.Add(item.Key, item.Value); + } + + public void Clear() + { + dictionary.Clear(); + } + + public bool Contains(KeyValuePair<TKey, TValue> item) + { + return dictionary.ContainsKey(item.Key) && dictionary[item.Key].Equals(item.Value); + } + + void ICollection.CopyTo(Array array, int index) { } + + void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) { } + + public bool Remove(KeyValuePair<TKey, TValue> item) + { + return dictionary.Remove(item.Key); + } + #endregion + + #region Implementation of IEnumerable + public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() + { + return dictionary.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return dictionary.GetEnumerator(); + } + #endregion + } +}
\ No newline at end of file diff --git a/Assets/Plugins/AdvancedInspector/Core/UDictionary.cs.meta b/Assets/Plugins/AdvancedInspector/Core/UDictionary.cs.meta new file mode 100644 index 00000000..f39539f9 --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Core/UDictionary.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9e2fe3e177768eb42ac8308f4f3e3c6a +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/AdvancedInspector/Event.meta b/Assets/Plugins/AdvancedInspector/Event.meta new file mode 100644 index 00000000..135b7127 --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Event.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: cfb5bf0cc1004984c86ae71dfdef427c +folderAsset: yes +DefaultImporter: + userData: diff --git a/Assets/Plugins/AdvancedInspector/Event/EventHandlers.cs b/Assets/Plugins/AdvancedInspector/Event/EventHandlers.cs new file mode 100644 index 00000000..9c0418d4 --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Event/EventHandlers.cs @@ -0,0 +1,22 @@ +using UnityEngine; + +namespace AdvancedInspector +{ + public delegate void GenericEventHandler(); + + public delegate void SenderEventHandler(object sender); + + public delegate void BoolEventHandler(object sender, bool value); + public delegate void IntEventHandler(object sender, int value); + public delegate void FloatEventHandler(object sender, float value); + public delegate void StringEventHandler(object sender, string value); + public delegate void ObjectEventHandler(object sender, object value); + public delegate void Vector2EventHandler(object sender, Vector2 value); + public delegate void Vector3EventHandler(object sender, Vector3 value); + public delegate void Vector4EventHandler(object sender, Vector4 value); + + public delegate void CollisionEventHandler(object sender, Collision value); + public delegate void ColliderEventHandler(object sender, Collider value); + + public delegate void ActionEventHandler(object sender, object[] args); +}
\ No newline at end of file diff --git a/Assets/Plugins/AdvancedInspector/Event/EventHandlers.cs.meta b/Assets/Plugins/AdvancedInspector/Event/EventHandlers.cs.meta new file mode 100644 index 00000000..4c6c1268 --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Event/EventHandlers.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ada727c2815079443b04c23643983797 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/AdvancedInspector/Interface.meta b/Assets/Plugins/AdvancedInspector/Interface.meta new file mode 100644 index 00000000..16d6ab7f --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Interface.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: f1b6b242a5028dc4b8f87041356c7c93 +folderAsset: yes +DefaultImporter: + userData: diff --git a/Assets/Plugins/AdvancedInspector/Interface/ICopiable.cs b/Assets/Plugins/AdvancedInspector/Interface/ICopiable.cs new file mode 100644 index 00000000..8498e056 --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Interface/ICopiable.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace AdvancedInspector +{ + /// <summary> + /// Give an object the power to detect if it can be clone to the target location. + /// </summary> + public interface ICopiable + { + /// <summary> + /// Should return true if the object can be copied to replace the object destination. + /// </summary> + bool Copiable(object destination); + } +} diff --git a/Assets/Plugins/AdvancedInspector/Interface/ICopiable.cs.meta b/Assets/Plugins/AdvancedInspector/Interface/ICopiable.cs.meta new file mode 100644 index 00000000..fe1413d4 --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Interface/ICopiable.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5be419eaa25267d4abffe1323b92fdba +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/AdvancedInspector/Interface/ICopy.cs b/Assets/Plugins/AdvancedInspector/Interface/ICopy.cs new file mode 100644 index 00000000..d3584276 --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Interface/ICopy.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace AdvancedInspector +{ + /// <summary> + /// Give an object the power to handle it's own copying over an target destination. + /// </summary> + public interface ICopy + { + /// <summary> + /// Should return a copy of itself. The overriden destination object is passed in case important fields are not to be replaced. + /// </summary> + object Copy(object destination); + } +} diff --git a/Assets/Plugins/AdvancedInspector/Interface/ICopy.cs.meta b/Assets/Plugins/AdvancedInspector/Interface/ICopy.cs.meta new file mode 100644 index 00000000..e96268ea --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Interface/ICopy.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: c3c8bf575d7676a4bb245bda97724449 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/AdvancedInspector/Interface/IDataChanged.cs b/Assets/Plugins/AdvancedInspector/Interface/IDataChanged.cs new file mode 100644 index 00000000..65e93a85 --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Interface/IDataChanged.cs @@ -0,0 +1,24 @@ +using UnityEngine; +using System; +using System.Collections; + +namespace AdvancedInspector +{ + /// <summary> + /// Define an interface called when the Inspector has performed changes. + /// The event works the other way around, as a way to notify the Inspector something changed and needs to be refreshed. + /// </summary> + public interface IDataChanged + { + /// <summary> + /// Fired when the Inspector changed. + /// </summary> + void DataChanged(); + + /// <summary> + /// Should be fired internal by the object when the fields structure changed. + /// Ex.: Added an object to a list. + /// </summary> + event GenericEventHandler OnDataChanged; + } +}
\ No newline at end of file diff --git a/Assets/Plugins/AdvancedInspector/Interface/IDataChanged.cs.meta b/Assets/Plugins/AdvancedInspector/Interface/IDataChanged.cs.meta new file mode 100644 index 00000000..957af94f --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Interface/IDataChanged.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: d075315f0f1460743ac06aafae48b280 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/AdvancedInspector/Interface/IInspectorRunning.cs b/Assets/Plugins/AdvancedInspector/Interface/IInspectorRunning.cs new file mode 100644 index 00000000..c2038537 --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Interface/IInspectorRunning.cs @@ -0,0 +1,29 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace AdvancedInspector +{ + /// <summary> + /// When implementing this, gives the object ability to draw the header and footer of the Inspector's space. + /// </summary> + public interface IInspectorRunning + { + /// <summary> + /// Draw at the top of the inspector, in this order; + /// - This + /// - Class Helpbox + /// - Tabs + /// rest of the fields + /// </summary> + void OnHeaderGUI(); + + /// <summary> + /// Draw at the bottom of the inspector, in this order; + /// - Helpbox + /// - This + /// </summary> + void OnFooterGUI(); + } +}
\ No newline at end of file diff --git a/Assets/Plugins/AdvancedInspector/Interface/IInspectorRunning.cs.meta b/Assets/Plugins/AdvancedInspector/Interface/IInspectorRunning.cs.meta new file mode 100644 index 00000000..ad85b3be --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Interface/IInspectorRunning.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 94767ceadd7c79e4da722e9aa451f87e +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/AdvancedInspector/Interface/IListAttribute.cs b/Assets/Plugins/AdvancedInspector/Interface/IListAttribute.cs new file mode 100644 index 00000000..2f020402 --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Interface/IListAttribute.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace AdvancedInspector +{ + /// <summary> + /// Define an attribute that can be passed down to list/array elements. + /// </summary> + public interface IListAttribute { } +} diff --git a/Assets/Plugins/AdvancedInspector/Interface/IListAttribute.cs.meta b/Assets/Plugins/AdvancedInspector/Interface/IListAttribute.cs.meta new file mode 100644 index 00000000..d180ca1e --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Interface/IListAttribute.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: fec0fc7a00e58804ab5c94aa860790b7 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/AdvancedInspector/Interface/IPreview.cs b/Assets/Plugins/AdvancedInspector/Interface/IPreview.cs new file mode 100644 index 00000000..9dcf487c --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Interface/IPreview.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +using UnityEngine; + +namespace AdvancedInspector +{ + /// <summary> + /// Implements the method required to display an inspector preview. + /// </summary> + public interface IPreview + { + /// <summary> + /// This should return instance(s) of the following type; + /// GameObject + /// Mesh + /// Material + /// Texture + /// Cubemap + /// If return null or empty array, preview is turned off. + /// </summary> + UnityEngine.Object[] Preview { get; } + } +}
\ No newline at end of file diff --git a/Assets/Plugins/AdvancedInspector/Interface/IPreview.cs.meta b/Assets/Plugins/AdvancedInspector/Interface/IPreview.cs.meta new file mode 100644 index 00000000..841448df --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Interface/IPreview.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bea75a5ed3255024b904a3ebfddcb15b +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/AdvancedInspector/Interface/IRuntimeAttribute.cs b/Assets/Plugins/AdvancedInspector/Interface/IRuntimeAttribute.cs new file mode 100644 index 00000000..10710819 --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Interface/IRuntimeAttribute.cs @@ -0,0 +1,44 @@ +using UnityEngine; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Reflection; + +namespace AdvancedInspector +{ + /// <summary> + /// Define an attribute that stores a method name + /// Which should be turned into a delegate at runtime. + /// </summary> + public interface IRuntimeAttribute<T> : IRuntimeAttribute + { + /// <summary> + /// Invoke the internal delegates and returns the requested values. + /// T should be the same type as the Delegate return type. + /// </summary> + T Invoke(int index, object instance, object value); + } + + public interface IRuntimeAttribute + { + /// <summary> + /// Name of the MethodInfo to retrieve at runtime. + /// </summary> + string MethodName { get; } + + /// <summary> + /// Prototype template of the delegate to create + /// </summary> + Type Template { get; } + + /// <summary> + /// Prototype template for static external delegate + /// </summary> + Type TemplateStatic { get; } + + /// <summary> + /// List of delegates to invoke. + /// </summary> + List<Delegate> Delegates { get; set; } + } +}
\ No newline at end of file diff --git a/Assets/Plugins/AdvancedInspector/Interface/IRuntimeAttribute.cs.meta b/Assets/Plugins/AdvancedInspector/Interface/IRuntimeAttribute.cs.meta new file mode 100644 index 00000000..54a67e7e --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Interface/IRuntimeAttribute.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a59d020caab68e44bbc71d13e9f12fc1 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Plugins/AdvancedInspector/Utility.meta b/Assets/Plugins/AdvancedInspector/Utility.meta new file mode 100644 index 00000000..d7968f20 --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Utility.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 24d4e9172de017a4b805b56622be50d7 +folderAsset: yes +DefaultImporter: + userData: diff --git a/Assets/Plugins/AdvancedInspector/Utility/TypeUtility.cs b/Assets/Plugins/AdvancedInspector/Utility/TypeUtility.cs new file mode 100644 index 00000000..a445b8e9 --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Utility/TypeUtility.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; + +namespace AdvancedInspector +{ + public class TypeUtility + { + public static Type GetTypeByName(string name) + { + foreach (Assembly assembly in AppDomain.CurrentDomain.GetAssemblies()) + { + foreach (Type type in assembly.GetTypes()) + { + if (type.Name == name) + return type; + } + } + + return null; + } + } +} diff --git a/Assets/Plugins/AdvancedInspector/Utility/TypeUtility.cs.meta b/Assets/Plugins/AdvancedInspector/Utility/TypeUtility.cs.meta new file mode 100644 index 00000000..dd719c2c --- /dev/null +++ b/Assets/Plugins/AdvancedInspector/Utility/TypeUtility.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2053e8109e8ace34897756007aa622d2 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: |