Search Unity

Advanced Inspector - Never Write An Editor Again

Discussion in 'Assets and Asset Store' started by LightStriker, May 4, 2014.

  1. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,717
    Yes, you're right that it should refresh the list properly. Just tested your snippet, and you're right, it's a bug. Thanks for spotting it. It will be fixed - both issues - in the next version.
     
  2. Zoey_O

    Zoey_O

    Joined:
    Mar 15, 2013
    Posts:
    28
    Ok thanks for your quick response! Both issues are not show stoppers for me but minor inconveniences so no worries there. I am definitely enjoying the product.
     
  3. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,717
    Happy you like it. I'll try to release that next version - 1.44 - this week.
     
  4. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,717
    Version 1.44 have been submitted to the Asset Store for review.

    Changelist;
    - Made "SelectedTab" property public in InspectorField.
    - Fixed an issue when mixing groups with tabs.
    - Optimized the lookup of FieldEditor attribute. If you had slow down with this attribute, it should be fine now.
    - Now able to inspect static field, properties and methods. Static fields and properties are read only, except when the game is playing.
    - InspectorField now has a Static property.
    - Added tooltips and URL to scripting documentation for the Camera, Animator, Light, and many other editors.
    - Added editors for Animation, RigidBody2D, SpringJoint2D, Sprite Renderer, and many other classes.
    - Note that editors for 2D Physic (Ex.: HingeJoint2D) requires Unity 4.5 or higher.
    - InspectorField now supports SerializedProperty arrays. Try to not break that feature.
    - Fixed an issue with IDataChanged when the item inspected is at the root.
    - Exception thrown on a method/delegate invokation now returns the inner exception, which would make debugging your own method a lot easier.
    - AdvancedInspector attribute are now properly inherited in classes hierarchy.
    - Enum drop down now properly uses Descriptor for their names.
    - Removed the compile define, it didn't work from within a library.
     
  5. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,717
    Version 1.44 is now available on the Asset Store.
     
  6. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,717
    A bug slipped in the latest - 1.44 - version where some enum became un-editable. An update have been submitted to the Asset Store.

    If you downloaded the latest version and have this issue, contact me - admin@lightstrikersoftware.com - and I'll send you the fix right away.
     
  7. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,717
    1.44a is now available on the Asset Store to fix the un-editable enums.
     
  8. gpvd

    gpvd

    Joined:
    Nov 2, 2013
    Posts:
    78
    Hello ,

    I've got a question, i don't know if it's already possible:

    Is it possible to to display multiple help messages in the header?
    Currently i do this by adding HelpAttributes to a list and just display the list in public void OnHeaderGUI().
    But the problem is that i first have to select all the fields with the Help attribute attached , before any help message is displayed.

    My solution at the moment;
    Code (CSharp):
    1. [AdvancedInspector(ShowScript = false, InspectDefaultItems = true)]
    2. abstract public class BaseGameObject : MonoBehaviour, IInspectorRunning
    3. {
    4.  
    5.     /// <summary>
    6.     /// Adds an info/warning/error message.
    7.     /// All messages are then displayed in the header.
    8.     /// </summary>
    9.     public HelpAttribute AddMessageToHeader(string instance, HelpAttribute helpAttribute)
    10.     {
    11.  
    12.         if(errorMessages != null)
    13.         {
    14.             KeyValuePair<string, HelpAttribute> uid = new KeyValuePair<string, HelpAttribute>(instance, helpAttribute);
    15.             if(errorMessages.Contains(uid) == false)
    16.                 errorMessages.Add(uid);
    17.         }
    18.  
    19.         return helpAttribute;
    20.     }
    21.  
    22.  
    23.  
    24.     /// <summary>
    25.     /// Called by AdvancedInspector
    26.     /// </summary>
    27.     public void OnHeaderGUI()
    28.     {
    29.         if(errorMessages != null)
    30.         {
    31.             StringBuilder b = new StringBuilder();
    32.             //--- Display messages ERROR , WARNING, INFO.
    33.             for(int i = 0; i < errorMessages.Count; i++)
    34.             {
    35.                 HelpAttribute ha = errorMessages[i].Value;
    36.                 GUIStyle s = new GUIStyle();
    37.  
    38.                 b.Remove(0, b.Length);
    39.                 b.AppendFormat("{0}    {1}    {2}",errorMessages[i].Key , ha.Type, ha.Message );
    40.  
    41.                 s.fontStyle = FontStyle.Bold;
    42.                 switch(ha.Type)
    43.                 {
    44.                     case HelpType.Info:
    45.                         s.normal.textColor = Color.blue;
    46.                         break;
    47.                     case HelpType.Warning:
    48.                         s.normal.textColor = Color.yellow;
    49.                         break;
    50.                     case HelpType.Error:
    51.                         s.normal.textColor = Color.red;
    52.                         break;
    53.                 }
    54.                 GUILayout.Label(b.ToString(),s);  
    55.             }
    56.          
    57.  
    58.         }
    59.  
    60.     }
    61. }
    62.  
    63.  
    64.  
    65.  
    66. [AdvancedInspector(InspectDefaultItems = true)]
    67. public class ExampleA : BaseGameObject{
    68.  
    69.     private HelpAttribute helpMsgDoDisplay = new HelpAttribute(HelpType.Info, "");
    70.  
    71.  
    72.     [Inspect, Help("helpDoDisplay")]
    73.     public bool doDisplay;
    74.  
    75.  
    76.     private HelpAttribute helpDoDisplay(){
    77.         if(doDisplay)
    78.         {
    79.             helpMsgDoDisplay.Message = "displaying...";
    80.             helpMsgDoDisplay.Type = HelpType.Info;
    81.         }else{
    82.             helpMsgDoDisplay.Message = " Display is OFF.";
    83.             helpMsgDoDisplay.Type = HelpType.Error;
    84.  
    85.         }
    86.  
    87.         return AddMessageToHeader(this.name, helpMsgDoDisplay);
    88.  
    89.     }
    90. }
    I hope you can give me some advice on this.

    Greetz,
    G
     
  9. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,717
    Good morning,

    I'm not sure to understand what you mean by "have to select all the fields". Do you want the same HelpBox to be displayed under the field and in the header?

    Yes, it's possible to display multiple help message in the header in two different ways;
    - Have multiple Help attribute on the class itself; easy but the number of help is static to the number of attributes.
    - Use OnHeaderGUI(), and draw boxes using UnityEditor.EditorGUILayout.HelpBox();

    If you want to contact me on Skype (lightstriker_qc) or by email (admin@lightstrikersoftware.com), I'll be happy to help you with your Advanced Inspector issues.
     
  10. gpvd

    gpvd

    Joined:
    Nov 2, 2013
    Posts:
    78

    Hello,

    Tnx for the awnser.

    With "have to select all the fields" i mean ; Click on each field in the inspector to display the help message.
    The messages are now shown under the field AND in the header and this is intended behaviour.

    As a designer, when modify settings on a prefab:
    - When i go to tab A, click on a field, a help message is shown.
    - When i go to tab B, the help message is still shown in the header. Any additional help messages will be shown in the header also.

    - This way i always have actual info of the settings in the header, without going trough the tabs to see if i missed a setting.

    I already make use of OnHeaderGUI() and thats not the issue now as that's the place where i want to show all messages.

    My issue is that as a designer i now must click on each available field in the inspector to get all help messages.


    Could you give me an example on how to use the Help attribute on class level?
     
  11. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,717
    It's this part I'm not understanding. I tried the code you posted and the header shows up with the label, and in the header without clicking on anything.

    Are you saying you're using tabs? If so, it's normal that a label/field that is not displayed won't have it's help attribute processed until it's visible.

    If you want all Help to always be displayed in the header, independently of if the labels are visible or not, you could do something like this;

    BaseGameObject;
    Code (CSharp):
    1. [AdvancedInspector(ShowScript = false, InspectDefaultItems = true)]
    2. abstract public class BaseGameObject : MonoBehaviour, IInspectorRunning
    3. {
    4.     protected List<HelpAttribute> helps = new List<HelpAttribute>();
    5.  
    6.     /// <summary>
    7.     /// Called by AdvancedInspector
    8.     /// </summary>
    9.     public virtual void OnHeaderGUI()
    10.     {
    11. #if UNITY_EDITOR
    12.         for (int i = 0; i < helps.Count; i++)
    13.             UnityEditor.EditorGUILayout.HelpBox(helps[i].Message, (UnityEditor.MessageType)(int)helps[i].Type);
    14. #endif
    15.     }
    16. }
    17.  
    ExampleA;
    Code (CSharp):
    1. [AdvancedInspector(InspectDefaultItems = true)]
    2. public class ExampleA : BaseGameObject
    3. {
    4.     [Inspect, Help("helpDoDisplay")]
    5.     public bool doDisplay;
    6.  
    7.     private HelpAttribute helpDoDisplay()
    8.     {
    9.         HelpAttribute help;
    10.         if (doDisplay)
    11.             help = new HelpAttribute(HelpType.Info, "Displaying...");
    12.         else
    13.             help = new HelpAttribute(HelpType.Error, "Display if OFF.");
    14.  
    15.         return help;
    16.     }
    17.  
    18.     public override void OnHeaderGUI()
    19.     {
    20.         helps.Clear();
    21.         helps.Add(helpDoDisplay());
    22.         base.OnHeaderGUI();
    23.     }
    24. }
    This way, you're not dependent on the visibility of an item.

    As for Class help, they work exactly the same way as field/property/method help; you simply apply the Help attribute on the class itself. However, I just spotted there's a layouting issue with that. I'm looking into it.
     
    Last edited: Nov 6, 2014
  12. gpvd

    gpvd

    Joined:
    Nov 2, 2013
    Posts:
    78
    Ah,

    I see where i'm going wrong. Indeed i use tabs; so i'll implement your sample code. That should work.
    Thank you very much!
    Will let you know if it worked.

    Greetz,
    G
     
  13. gpvd

    gpvd

    Joined:
    Nov 2, 2013
    Posts:
    78
    Hi,
    I would let you know...

    It works now.
    To show all messages of all fields on all tabs, i created a List and added all monobehaviours / componentmonobehaviours using AdvancedInspector.
    Now i the base object in OnHeaderGUI() i only need to walk trough the List and showing the messages.

    Thanks again for your help.

    Greetz,
    G
     
  14. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,717
    Any time. If you need any help or have any idea of features, feel free to contact me.
     
  15. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,717
    1.44b have been submitted to the Asset Store; it fix a bug where Help Attribute would fail to properly a runtime method when this attribute is affixed to a class.
     
  16. gpvd

    gpvd

    Joined:
    Nov 2, 2013
    Posts:
    78
    Hello,

    I've got a question,

    I've updated to 1.44 but get strange results when using int enum.
    Basicly Advanced inspector returns the index value instead of the name when i select a value from the dropdown other than the first option.
    E.g. in the given example;
    When selecting first option from dropdown -> LEFT_TO_RIGHT ; headingTowards has value LEFT_TO_RIGHT. (Which is correct)
    But, when selecting the sixth option from dropdown -> RIGHT_TO_LEFT ; headingTowards has value 6. (Wrong.)

    Code (CSharp):
    1.     public enum MOVEDIRECTION : int
    2.     {
    3.         UP = 90, DOWN = 270, RIGHT_TO_LEFT = -180, LEFT_TO_RIGHT = 0,
    4.         UP_LEFT = -135, UP_RIGHT = 45, DOWN_LEFT = -225, DOWN_RIGHT = -315
    5.     };
    6.  
    7. [Inspect]
    8.     public DirectionHelper.MOVEDIRECTION headingTowards;
    9.  
    10.  

    I noticed the error just now, but when testing with an older backup which included a previous version of AdvancedInspector it worked correctly. Unfortunatly i don't know which version of AdvancedInspector that was...

    Hoping you could help me out.

    Tnx in advance,

    Greetz,
    G
     
  17. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,717
    Ouch... Fix one thing, break another.

    I've submitted a fix to the AssetStore (1.44c), but it may takes a few days to have it accepted.

    If you want a quick fix, you can open the file named EnumEditor.cs, which is placed in Plugins/Editor/AdvancedInspector/FieldEditors, and replace its content with;

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEditor;
    3. using System;
    4. using System.Collections;
    5. using System.Collections.Generic;
    6. using System.Linq;
    7.  
    8. namespace AdvancedInspector
    9. {
    10.     public class EnumEditor : FieldEditor
    11.     {
    12.         public override bool EditDerived
    13.         {
    14.             get { return true; }
    15.         }
    16.  
    17.         public override bool Expandable
    18.         {
    19.             get { return false; }
    20.         }
    21.  
    22.         public override Type[] EditedTypes
    23.         {
    24.             get { return new Type[] { typeof(Enum) }; }
    25.         }
    26.  
    27.         public override void Draw(InspectorField field, GUIStyle style)
    28.         {
    29.             EnumAttribute display = field.GetAttribute<EnumAttribute>();
    30.  
    31.             EditorGUI.showMixedValue = field.Mixed;
    32.  
    33.             EditorGUI.BeginChangeCheck();
    34.  
    35.             object value = GetValue(field);
    36.             if (display == null || !display.Masked)
    37.             {
    38.                 if (display == null || display.Display == EnumDisplay.DropDown)
    39.                     value = DrawDropDown(field.Type, (int)value, style, false);
    40.                 else if (display.Display == EnumDisplay.Button)
    41.                     value = DrawEnum(field.Type, (int)value, display.MaxItemsPerRow, style == null ? EditorStyles.toolbarButton : style);
    42.                 else if (display.Display == EnumDisplay.Checkbox)
    43.                     value = DrawEnum(field.Type, (int)value, display.MaxItemsPerRow, style == null ? EditorStyles.toggle : style);
    44.             }
    45.             else
    46.             {
    47.                 if (display == null || display.Display == EnumDisplay.DropDown)
    48.                     value = DrawDropDown(field.Type, (int)value, style, true);
    49.                 else if (display.Display == EnumDisplay.Button)
    50.                     value = DrawMasked(field.Type, (int)value, display.MaxItemsPerRow, style == null ? EditorStyles.toolbarButton : style);
    51.                 else if (display.Display == EnumDisplay.Checkbox)
    52.                     value = DrawMasked(field.Type, (int)value, display.MaxItemsPerRow, style == null ? EditorStyles.toggle : style);
    53.             }
    54.  
    55.             if (EditorGUI.EndChangeCheck())
    56.                 field.SetValue(value);
    57.         }
    58.  
    59.         private int SelectedIndex(Array values, int value)
    60.         {
    61.             for (int i = 0; i < values.Length; i++)
    62.                 if ((int)values.GetValue(i) == value)
    63.                     return i;
    64.  
    65.             return 0;
    66.         }
    67.  
    68.         private string[] GetNames(Type type)
    69.         {
    70.             Array values = Enum.GetValues(type);
    71.             List<string> names = Enum.GetNames(type).ToList();
    72.  
    73.             for (int i = 0; i < names.Count; i++)
    74.             {
    75.                 DescriptorAttribute descriptor = ((Enum)values.GetValue(i)).GetAttribute<DescriptorAttribute>();
    76.                 if (descriptor != null && !string.IsNullOrEmpty(descriptor.Name))
    77.                     names[i] = descriptor.Name;
    78.                 else
    79.                     names[i] = ObjectNames.NicifyVariableName(names[i]);
    80.             }
    81.  
    82.             return names.ToArray();
    83.         }
    84.  
    85.         private object DrawDropDown(Type type, int value, GUIStyle style, bool masked)
    86.         {
    87.             string[] names = GetNames(type);
    88.             Array values = Enum.GetValues(type);
    89.  
    90.             if (masked)
    91.             {
    92.                 if (style == null)
    93.                     value = EditorGUILayout.MaskField(value, names);
    94.                 else
    95.                     value = EditorGUILayout.MaskField(value, names, style);
    96.  
    97.                 return Enum.ToObject(type, value);
    98.             }
    99.             else
    100.             {
    101.                 int selected = SelectedIndex(values, value);
    102.  
    103.                 if (style == null)
    104.                     selected = EditorGUILayout.Popup(selected, names);
    105.                 else
    106.                     selected = EditorGUILayout.Popup(selected, names, style);
    107.  
    108.                 return Enum.ToObject(type, values.GetValue(selected));
    109.             }
    110.         }
    111.  
    112.         private object DrawEnum(Type type, int value, int max, GUIStyle style)
    113.         {
    114.             if (max < 1)
    115.                 max = 6;
    116.  
    117.             string[] names = GetNames(type);
    118.             Array values = Enum.GetValues(type);
    119.  
    120.             int rows = Mathf.CeilToInt((float)names.Length / (float)max);
    121.             int count = (names.Length / rows);
    122.             if (count * rows < names.Length)
    123.                 count++;
    124.  
    125.             int selected = SelectedIndex(values, value);
    126.  
    127.             GUILayout.BeginVertical();
    128.  
    129.             for (int i = 0; i < rows; i++)
    130.             {
    131.                 GUILayout.BeginHorizontal();
    132.  
    133.                 for (int j = count * i; j < count * (i + 1); j++)
    134.                 {
    135.                     if (j >= names.Length)
    136.                         break;
    137.  
    138.                     if (selected == j)
    139.                         GUILayout.Toggle(true, names[j], style);
    140.                     else if (GUILayout.Toggle(false, names[j], style))
    141.                         selected = j;
    142.                 }
    143.  
    144.                 GUILayout.EndHorizontal();
    145.             }
    146.  
    147.             GUILayout.EndVertical();
    148.  
    149.             return Enum.ToObject(type, values.GetValue(selected));
    150.         }
    151.  
    152.         private object DrawMasked(Type type, int value, int max, GUIStyle style)
    153.         {
    154.             if (max < 1)
    155.                 max = 6;
    156.  
    157.             Array values = Enum.GetValues(type);
    158.             string[] names = GetNames(type);
    159.  
    160.             int rows = Mathf.CeilToInt((float)names.Length / (float)max);
    161.             int count = (names.Length / rows);
    162.             if (count * rows < names.Length)
    163.                 count++;
    164.  
    165.             int result = 0;
    166.  
    167.             GUILayout.BeginVertical();
    168.  
    169.             for (int i = 0; i < rows; i++)
    170.             {
    171.                 GUILayout.BeginHorizontal();
    172.  
    173.                 for (int j = count * i; j < count * (i + 1); j++)
    174.                 {
    175.                     if (j >= names.Length)
    176.                         break;
    177.  
    178.                     int v = (int)values.GetValue(j);
    179.                     if (GUILayout.Toggle(((int)value & v) == v, names[j], style))
    180.                         result |= v;
    181.                 }
    182.  
    183.                 GUILayout.EndHorizontal();
    184.             }
    185.  
    186.             GUILayout.EndVertical();
    187.  
    188.             return Enum.ToObject(type, result);
    189.         }
    190.     }
    191. }
    I'm very sorry about that.
     
  18. gpvd

    gpvd

    Joined:
    Nov 2, 2013
    Posts:
    78
    Ok,

    No problem for the bug.
    Many tnx for the quick fix!

    Greetz,
    G
     
  19. Guillaume-Portes

    Guillaume-Portes

    Joined:
    Oct 10, 2012
    Posts:
    13
    Hello!

    Is it possible to use the Restrict attribute to restrict the contents of a collection?
    For instance I want all values within a List<string> to be constrained to { "water", "earth", "fire" }.
    It kind of works, but doesn't allow to add elements to the collection.

    Thanks,

    G.
     
    Last edited: Nov 14, 2014
  20. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,717
    I would have told you "yes", but before saying it, I just tried it... For some reason it's a specific test case I haven't tried. I'm just half surprised that it tries to set the restricted value to the array itself, instead of the index. It's an IListAttribute, so it's most likely just missing an "if (isList)" somewhere.

    I'll fix it today. If you need a quick fix, I can mail you it.

    As a side note, version 1.44c with all the previous fixes is available on the AssetStore.
     
  21. Guillaume-Portes

    Guillaume-Portes

    Joined:
    Oct 10, 2012
    Posts:
    13
    Yes, I'd love a quick fix, thanks a lot :)
     
  22. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,717


    Code (CSharp):
    1.     [Inspect, Restrict("Restrict")]
    2.     public string[] myArray;
    3.  
    4.     private IList Restrict()
    5.     {
    6.         return new string[] { "Fire", "Water", "Earth", "Air" };
    7.     }
    Was submitted as version 1.44d. If you want it right now, just mail me to admin@lightstrikersoftware.com, I'll mail you the package.
     
  23. Guillaume-Portes

    Guillaume-Portes

    Joined:
    Oct 10, 2012
    Posts:
    13
    Superb, thanks a lot for the support!
     
  24. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,717
    1.44d is now available on the Asset Store.
     
  25. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,717
    1.44e have been submitted to the Asset Store to fix an issue where private members of a class would become invisible in a derived class
     
  26. Zoey_O

    Zoey_O

    Joined:
    Mar 15, 2013
    Posts:
    28
    I noticed in the Unity 5 beta with UnityVS that the reference to AdvancedInspector.dll does't seem to take in the Visual Studio project:

    Warning 1 Resolved file has a bad image, no metadata, or is otherwise inaccessible. Could not load file or assembly 'AdvancedInspector.dll' or one of its dependencies. An attempt was made to load a program with an incorrect format. UnityVS.<MyProjectName>.CSharp.Editor

    Works fine in other versions of Unity 4. Removing and Re-adding the reference manually does not resolve it, nor referencing it in another location.

    I just figured I would mention it, in case its something related to the compilation of the dlls that is incompatible with Unity 5 or something you might have to work around in the future =).

    This product has saved me countless hours. Thanks again!
     
  27. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,717
    Happy to hear it.

    Sadly, I do not have access to Unity 5 beta, otherwise I would be glad to make it compatible. I have a feeling - maybe unfounded - that most editor/tool compiled into a dll will face similar issues in Unity 5 because of how it references the UnityEditor.dll, which most likely have changed. Recompiling it with the new UnityEditor would most likely fix the issue.

    If needed, I could supply you with the source code, and you would try it without a compiled library (dll). However, I somewhat expect that some Unity call would change with 5.
     
  28. Zoey_O

    Zoey_O

    Joined:
    Mar 15, 2013
    Posts:
    28
    Sure. Message me with whatever information I need and I will give it a shot. Thanks!
     
  29. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,717
    There hasn't been a major release of Advanced Inspector in a while, mostly because of the new features in the work.

    Here's a video displaying three major features;


    The selection history is a very simple one, and a lot of time was wasted trying to bind the back/forth functionality on the back and forth button of the mouse. Sadly, Unity is not friendly with supporting those buttons, so it went to CTRL+Right Arrow and CTRL+Left Arrow. The system is similar to a web browser history.

    The Watch window supports any fields displayed on the Advanced Inspector, and keep its data between play mode. Watched items can be added or removed at anytime. Multiselection also works properly. That window is very handy to track how item behave at runtime.

    The last feature displayed here is the ability to save specific value that were modified at runtime. The current limitation is that you cannot add or remove components to a GameObject. Every other basic type are properly carried between playmode. In time, the "saved" field will be displayed in italic in the inspector so that the flagged fields are easy to spot.
     
  30. gpvd

    gpvd

    Joined:
    Nov 2, 2013
    Posts:
    78
    Hello,

    A little question.
    Consider the given example code;

    Code (CSharp):
    1.    
    2.  
    3. [AdvancedInspector(ShowScript = false, InspectDefaultItems=false)]
    4. [ExecuteInEditMode]
    5. public class Test : MonoBehaviour
    6.      //---
    7.     [Inspect, Restrict("restrictSequences"), Expandable]
    8.     public List<object> sequences;
    9.     private IList restrictSequences()
    10.     {
    11.         return new List<object>() { new Mover(), new Scaler(), new Delayer()};
    12.     }
    13.  
    14.  
    15.  
    16.  
    17.     //   INNER CLASSES
    18.     //
    19.     [Serializable, AdvancedInspector(ShowScript = false, InspectDefaultItems = true)]
    20.     public class Delayer
    21.     {
    22.         [Inspect]
    23.         public float delay = 0f;
    24.     }
    25.     //
    26.     [Serializable, AdvancedInspector(ShowScript = false, InspectDefaultItems = true)]
    27.     public class Mover
    28.     {
    29.         //---
    30.         [Inspect]
    31.         public float delaySequence = 0f;
    32.     }
    33.     //
    34.     [Serializable, AdvancedInspector(ShowScript = false, InspectDefaultItems = true)]
    35.     public class Scaler
    36.     {
    37.         //---
    38.         [Inspect]
    39.         public float delaySequence = 0f;
    40.  
    41.     }
    42.  
    Right now, adding a Mover/Scaler/Delayer to the list works as expected, however the dropdown selection box doesn't show the selected value.
    So i end up with a list of N values where all dropdown values are blank...

    The inner classes are just basic classes.

    Could you give me some advice on how to tackle this little thingy????

    Tnx in advance,
    Greetz,
    G
     
  31. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,717
    The main problem here is that Unity is unable to save properly "List<object>". Polymorphism with Unity works only with object that derives from UnityEngine.Object, and for us, we only have access at deriving from MonoBehaviour or ScriptableObject. So the moment you would press "Play" in the editor, your List would become empty.

    To get around that issue, Advanced Inspector offers the ComponentMonoBehaviour class and the CreateDerived attribute.

    So you should do something like this;

    Code (CSharp):
    1. [AdvancedInspector(ShowScript = false, InspectDefaultItems = false)]
    2. [ExecuteInEditMode]
    3. public class Test : MonoBehaviour
    4. {
    5.     [Inspect, CreateDerived]
    6.     public List<Action> sequences;
    7. }
    8.  
    9. [Expandable]
    10. public abstract class Action : ComponentMonoBehaviour { }
    11.  
    12. public class Delayer : Action
    13. {
    14.     [Inspect]
    15.     public float delay = 0f;
    16. }
    17.  
    18. public class Mover : Action
    19. {
    20.     [Inspect]
    21.     public float delaySequence = 0f;
    22. }
    23.  
    24. public class Scaler : Action
    25. {
    26.     [Inspect]
    27.     public float delaySequence = 0f;
    28. }
    29.  
    Where each class is in its own file. That's important, even if it's silly, otherwise Unity isn't too happy.
     
  32. gpvd

    gpvd

    Joined:
    Nov 2, 2013
    Posts:
    78
    Thank you very much.
    I'll implement your suggestion.

    Greetz,
    G
     
  33. gpvd

    gpvd

    Joined:
    Nov 2, 2013
    Posts:
    78

    Your suggestion works. Thanks again!
    However another question; Is it possible to restrict the possible values?
    E.g. from all classes deriving from Action, only Scaler and Mover are selectable, while Delayer is not shown in the list.
     
  34. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,717
    You mean Delayer should not show up or it is currently not showing up?

    If you want one to not show up, you can flag it abstract or make it derive something else.

    For example, you could do

    Action -> Motion -> Mover
    Action -> Motion -> Scaler
    Action -> Delayer

    Or any kind of hierarchy that make sense, and have List<Motion> instead of List<Action>.
     
  35. gpvd

    gpvd

    Joined:
    Nov 2, 2013
    Posts:
    78
    Ah, ok, so using [Restrict("someMethodReturnsLimitedList")] does not work with this solution?
    I meant i don't want to Delayer to show up.
     
  36. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,717
    No, it does not. Well, for now.
    I can see how that could be useful, so I'm taking note for the next version.
     
  37. Essential

    Essential

    Joined:
    Sep 8, 2011
    Posts:
    265
    Is it possible to use elements of a list or array as tabs?
     
  38. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,717
    No, because that would mean the tabs could be dynamic. I'm wondering how you would bind static field/property/method to dynamic values?

    Do you have a case where that would work and be useful?
     
  39. Essential

    Essential

    Joined:
    Sep 8, 2011
    Posts:
    265
    It's sorta useful for visually inspecting / editing data. Having lots of nested lists and drop down arrows gets difficult to navigate, whereas tabs feel neater and more natural for browsing.

    Not sure how you're generating the tabs but I know I had a dynamic 'tabbed' list working with a custom editor I made (I think I might have emailed you a screenshot a few months back for a different point.)
     
  40. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,717
    Ah! You're not talking about the header tabs, but a tab to navigate in a collection.

    Yes, that's an existing feature;

    Code (CSharp):
    1.     [Inspect, CreateDerived, Collection(Display = CollectionDisplay.Button)]
    2.     public AIExample_ComponentBase[] baseList;
    A collection can currently be displayed as a "list", as a drop down, or as a tab-like buttons.



    Is that what you meant?
     
  41. Essential

    Essential

    Joined:
    Sep 8, 2011
    Posts:
    265
    Ah yes! That works well. :)

    One thing I'm still confused about is the Serialization. Why do I need to add the `[Serializable]` tag to classes to get them to serialize when Unity usually does that by default?
     
  42. Essential

    Essential

    Joined:
    Sep 8, 2011
    Posts:
    265
    I tried adding `[AdvancedInspector(InspectDefaultItems = true)]` thinking I wouldn't need to use the [Inspect] tags (and maybe even use the default serialization Unity uses) but it doesn't seem to affect it, I still need [Inspect] tags on all the variables.
     
  43. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,717
    Object that directly derive from MonoBehaviour or ScriptableObject doesn't require the Serializable attribute, as Unity uses them as serialization entry point by default.

    However, everything else requires it. Example;

    Code (CSharp):
    1. // Doesn't require Serializable, as MonoBehaviour is Serializable.
    2. public class Action : MonoBehaviour { }
    3.  
    4. // Requires Serializable, because System.Object is not Serializable by default.
    5. [Serializable]
    6. public class SubAction { }
    7.  
    On what was your AdvancedInspector attribute applied on? Can you give me an example of your issue?
     
  44. Chronovore

    Chronovore

    Joined:
    Dec 20, 2014
    Posts:
    6
    Great tool. I Absolutely love it!

    Right now I have the situation where I'm working on ScriptableObjects and attempting to add a field for an abstract class. I understand that if I were working with MonoBehaviours I could use ComponentMonoBehaviour to create what I need, but is there a something similar for ScriptableObjects?

    The purpose of this would be to create an abstract Prerequisite class with derived classes like AndPrerequisite (which would have fields for two Prerequisites), OrPrererequisite (which would have fields for two Prerequisites), NotPrerequisite (which would have fields for one Prerequisite), HasSkillPrerequisite (which would have a field for a skill), etc.
     
  45. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,717
    Happy you like it. :)

    Sadly, there isn't anything that can be done, short off using a different serialization/files than Unity's own. We had a similar issue where we had quests or mission that could have different condition and action. Our first reaction was to make ScriptableObject, because a quests has no real need for spatial coordinates. We ended up using prefab to host our quests. Even if it works, it's unfortunately not the most efficient way to do it. However, the overhead of using a prefab instead of a ScriptableObject wasn't much of an issue in our case, even if we had hundred of quests.
     
  46. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,717
    Version 1.5 have been submitted for review.

    This is a major version increment, where quite some new features are added;



    Also, 1.5 is not supported on Unity 4.3. The new lowest version supported is 4.5.0.
    Version 1.5 have also been tested on Unity 5.0. Please contact me if you have any issue between AI 1.5 and Unity 5.

    The examples have been deleted and rewritten from scratch in a more manageable format with plenty of comment and explanation in the source code. On the other hand, it gives a rather long list of GameObject;



    Let me know if I've missed anything.

    Here's the changelist;

    1.5:
    - Now support Unity 5.
    - No longer support Unity 4.3, only 4.5+.
    - Added the Watch window, which allows you to track inspector values. Right click any value and select "Watch".
    - Added the Selected History. Use CTRL+Left Arrow and CTRL+Right Arrow to cycle in your previous selection.
    - Added the Runtime Save feature; it allows you to save changed value while playing the game. This feature is in beta and may have issues.
    - Redone all the examples, should be way easier to use.
    - Added a collection of supported Unity type, like Terrain Collider and Clothes.
    - Due to confusion and overlapping functionnality, the Expandable attribute is now limited to fields and properties and only override the expandability of an item.
    - Fixed an issue where sortable list would fail.
    - Fixed an issue of recursivity with self-referencing objects.
    - Fixed an issue with RuntimeResolved attribute in non-dynamic mode.
    - Fixed the draggable icon in Unity Pro.
    - Minor tweak to the expandable boxes visual; should look smoother.
     
    cybervaldez likes this.
  47. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,717
    Working on the data type that are usually not supported by Unity, such as short, ushort, long, ulong, double, decimal, uint, sbyte, TimeSpan and DateTime...

    For that last one, we got a calendar picker;

     
    cybervaldez likes this.
  48. cybervaldez

    cybervaldez

    Joined:
    Aug 16, 2014
    Posts:
    87
    That is nice! I'm not sure where I can use it for but that is very sweet looking :)
     
  49. thienhaflash

    thienhaflash

    Joined:
    Jun 16, 2012
    Posts:
    513
    Not really sure about the real life use case, but the Calendar looks pretty awesome ! Nice work, LightStriker :)
     
  50. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,717
    Well, DateTime is quite often used when you need date-specific event in your game. Like say, a sale special that only run a weekend.
     
    cybervaldez likes this.