Search Unity

  1. Good news ✨ We have more Unite Now videos available for you to watch on-demand! Come check them out and ask our experts any questions!
    Dismiss Notice

Advanced Inspector - Never Write An Editor Again

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

  1. NeatWolf

    NeatWolf

    Joined:
    Sep 27, 2013
    Posts:
    896
    Are the Revert function and proper bold highlighting of changed fields going to be fixed in next update? I didn't receive any feedback on this. Do you have an eta?
     
  2. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,604
    Open the file "StringEditor.cs", and you can add at line #40;

    Code (CSharp):
    1.                EditorStyles.textField.wordWrap = true;
    So it should read;

    Code (CSharp):
    1.             else if (multiline != null || area != null || text.Type == TextFieldType.Area)
    2.             {
    3.                 EditorStyles.textField.wordWrap = true;
    4.                 if (style != null)
    5.                     result = EditorGUILayout.TextArea((string)value, style);
    6.                 else
    7.                     result = EditorGUILayout.TextArea((string)value);
    8.             }
     
  3. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,604
    I'll have to dig deeper. Right now, I just noticed some odd stuff happening with apply/revert, and I'm not sure where it's coming from.
     
    NeatWolf likes this.
  4. NeatWolf

    NeatWolf

    Joined:
    Sep 27, 2013
    Posts:
    896
    Thanks for replying about this, in my project this is really an issue since the level designer may get confused about seeing certaing fields are "reverted", others that have been changed but not shown in bold, and I had to explain to him that he had to switch to debug mode to actually revert changes... and this totally defeats the purpose of taking the time to build a clean and tidy interface with AI.

    If you could please prioritize this a bit, I'd really appreciate that, also because I fear I could be asked just to give up on building custom interfaces this way, and that would mean losing a lot of work and time, because a lot of features of AI really speed up the development process and I'd be forced to manually write them, one by one :-(
     
  5. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,604
    I just found out that Unity in Debug mode have some issues itself.

    Assume the following;

    Code (CSharp):
    1.         public Inner inner = new Inner();
    2.  
    3.         [Serializable]
    4.         public class Inner
    5.         {
    6.             [SerializeField]
    7.             private float value = 10;
    8.         }
    Here's a screenshot, with the instance on the left in debug, and the prefab on the right;



    Unity claims the instance in the scene is different from the original. However, the inner values of the "Inner" object are the same. For this reason, Advanced Inspector sees no difference, because plain System.Object shouldn't be compared from their memory adress, but from their inner data. However, Unity sees a difference, which doesn't really exist.

    I'm digging deeper, but I haven't found any major issue in Advanced Inspector so far.

    Can you PM me some reproductible steps?
     
  6. NeatWolf

    NeatWolf

    Joined:
    Sep 27, 2013
    Posts:
    896
    Hi,
    actually it's always been the Unity intended behavior.
    When you change the value of a field you "break" the connection with the field in its prefab, so the field gets marked correctly as "changed", doesn't matter if you set it back to the original value, it's always worked like that.

    The only way to restore this "link" is to use the revert Unity function, that not only reverts the value, but also restores the link between the field in the instance to the field on the prefab.

    So just reverting the value to it's prefab value still leaves the value of the field marked as "changed".

    Unity correctly shows that the value is still considered modified, and will only revert this state when using the native "Revert" functionality.

    Since IA apparently only checks the prefab value when restoring it, it just changes back the value to its original value, but doesn't restore the "changed" flag.

    So when you're using IA, you get the bold label only when checking if the value is different from the prefab, but it's not checking if the "modified" flag is actually set to modified or not, which can lead to confusion.

    I don't know how it works internally because I didn't do any in-depth study, but it's likely that this "modified" flag exists.
    I just don't know if there's some way to read/write it. That would really bad news to know that there are no exposed methods to directly revert a field value. I should probably ask in the forum.
     
  7. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,604
    Unity doesn't do much check. The only place where there's a "flag" is in SerializedProperty and it's called "prefabOverride" which is a native call. No clue what Unity does under the hood to determine if something is overriden or not.

    But let's rewind as bit first.

    Here's two screenshot taken from a clean Unity solution with a single class;





    Do you see the difference between those two screenshots?

    From a memory and data perspective, there is none. However, on one I modified the value, then entered back the previous one. Unity - behind the scene - just flagged that SerializedProperty as "being modified". It's not checking if the value is the same or not in this case, because it's wrapped in an object.

    And before you tell me that the object is the same or not, let me be clear; they are NEVER the same object, they exists at a different memory address, otherwise modifying one instance of a prefab would modify all instances. And no, a new object is not created when you modify a value in the inspector or at runtime.

    Why am I not simply checking that flag in SerializedProperty, beside the fact that it's flawed? Simple; I cannot use SerializedProperty for properties or data that are not serialized, two very important things in AI.
     
  8. NeatWolf

    NeatWolf

    Joined:
    Sep 27, 2013
    Posts:
    896
    I'm sorry, but it doesn't work like that. Which kind of worries me, because this may lead me to think you developed a feature and an asset with the wrong assumptions.

    Yes, it's Unity default and intended behaviour. The https://docs.unity3d.com/ScriptReference/SerializedProperty-prefabOverride.html field doesn't get cleared until you press revert. The description of the field is a bit vague.
    There are examples in the web that show how to actually revert a single field properly.

    Here are a few links that may be useful to properly implement bold "overriden" text, TRUE revert, and also the ability to use the builtin "Revert field" menuitem on a custom inspector (I can't remember where this is, I made a search on late night):

    http://answers.unity3d.com/questions/402138/how-to-dont-apply-fields-in-prefab.html

    http://answers.unity3d.com/questions/62455/how-do-i-make-fields-in-the-inspector-go-bold-when.html

    http://answers.unity3d.com/questions/685602/using-a-custom-editor-script-with-a-prefab-instanc.html

    http://catlikecoding.com/unity/tutorials/editor/custom-list/

    https://www.assetstore.unity3d.com/en/#!/content/21193

    https://docs.unity3d.com/ScriptReference/PrefabUtility.RevertPrefabInstance.html

    https://docs.unity3d.com/ScriptReference/PrefabUtility.ResetToPrefabState.html

    https://forum.unity3d.com/threads/c...s-to-a-prefab-instance-changes-revert.233915/

    http://answers.unity3d.com/questions/155431/saving-its-values-through-custom-editor.html

    https://forum.unity3d.com/threads/breaking-connection-from-gameobject-to-prefab-for-good.82883/

    https://forum.unity3d.com/threads/little-script-apply-and-revert-several-prefab-at-once.295311/

    http://answers.unity3d.com/questions/395852/script-for-revert-value-to-prefab.html

    http://unityready.com/wip-can-revert-single-prefab-value-instead-entrie-object/
    From this link (but it's been said and repeated on every tutorial about prefabs):
    This means that even if you set just the value back to the original, it of course won't restore the connection to the prefab.

    Imagine to change a field in an instance. You then set it back to the default value, but want that instance to stick to that value. You simply change the field to something different and back to the default value. The field is marked as overriden, and changing the prefab won't make you lose your value.

    Now imagine if the connection restored automatically by doing a simple check on the value.
    You set the instance field value back to a value that *by pure chance* is similar to the one in the prefab, and you reconnect to the prefab automagically. As soon as you change the prefab field value, all the instances that you wanted to keep the value of get changed to the new prefab value. This is an unwanted behaviour and in fact Unity doesn't work like this.

    From a memory and data perspective, there is a difference: the prefabOverride flag is set to true. It's not checking the actual value because it's not supposed to. It doesn't work like that.

    The actual implementation is irrelevant, let me be clear: Unity doesn't work like that.

    It's not flawed, it just works like this and has propably always worked like this. If you're not convinced yet, I may open a thread in the forum just to check what is right and what is not.

    You're not checking the prefabOverride value because you're making the "Revert" function work as per your personal interpretation

    (instance field value == prefab value ==> instance gets reconnected to the prefab and not marked as bold) - Revert value to prefab function = just change the value back to the prefab one.

    which is not how Unity works:

    (instance field value gets changed ==> forever marked as overriden until you clear the overridePrefab Flag, setting the value of the instance back to the one on the prefab doesn't clear the field) - Revert value to Prefab function = useful and with a clear function: restore the value and clear the overridePrefab flag.

    Of course you need SerializedProperties, and they are important to AI because AI should reflect the way Unity works behind the scenes, and not viceversa pretending AI does it right and Unity is bugged, because it's not.

    That's why I reported AI's behaviour, and I'm positive AI will get this fixed because it's a must have tool I'd really love to keep using.
     
    Last edited: Dec 22, 2016
  9. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,604
    I see. Makes sense, I guess.

    I can make that, shouldn't be too hard... However, there is simply no way to handle that for properties and any type unity don't serialize directly, such as Dictionaries.

    EDIT: Sent you a package with a beta version.
     
    Last edited: Dec 22, 2016
    NeatWolf likes this.
  10. NeatWolf

    NeatWolf

    Joined:
    Sep 27, 2013
    Posts:
    896
    Hi @LightStriker,

    sorry, I didn't receive any notification about the edit...and checked my spam folders of all my mailboxes, and haven't received any email with attachment, I'm going to contact you via PM.

    I actually noticed the edit by chance, as I had another question about AI usage.

    I have been using Inspect Default Items as ON during the development, and I have a third party custom attribute that is needed to alter the appearance of a public string in a MonoBehaviour. I tried the Bypass attribute, adding Inspect and switching off "Inspect Default Items", and other possible permutiations. I came to the conclusion that the custom 3rd party inspector only shows up whe Inspect Default Items is OFF.

    I can also add the Inspect attribute with IDI OFF and I'm still able to use the 3rd party custom inspector.

    Is there a way to bypass the way a single public field is shown, using AI, so that AI shows the "default" inspector for that field, also allowing 3rd party solution to alter it? I also tried using the "Bypass" and "AdvancedInspector" attributes with no success.

    Am I doing something wrong? Is there an "override" or "Skip" Attribute to allow me to use a 3rd party attribute that changes the way a public string gets shown (it changes it with a fixed list of dialogues - Dialogue System - with a checkbox to also allow the manual insertion of the string). I also thought about replicating the behaviour of that attribute using AI, but I ended up asking myself, why reinvent the wheel?

    Could you please help me to sort out this issue?
     
  11. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,604
    Are you talking about PropertyDrawers and PropertyAttributes? If so, someone else also notified me the issue, and the package you should have received have a fix for it.
     
  12. electroflame

    electroflame

    Joined:
    May 7, 2014
    Posts:
    177
    I've got a quick question about the Tabs attribute. Basically, I'm trying to rename them via a Descriptor method (like in the docs) and the docs have this to say:

    It is possible to change the tabs name or icon, but it has to be done in a specific way. Please see
    the example in the package for binding an extension enum method to the Descriptor attribute.

    However, I can't seem to figure out where this actually is taking place in the examples, or what I'm supposed to do for this. My goal is to have an overridable method (like something akin to ToString) that lets me change what the Tabs say based on the current class's implementation. For example, say I have this:

    "Parent" class (which has a virtual Descriptor method, and the tab enum)
    "Child" class (which derives from "Parent" and overrides the Descriptor method)

    The first tab will house data values for the "Parent" class (even on the children), whereas the second tab will house the "Child" data, which is why I'd like to dynamically change the name of that tab to reflect the name of the "Child" script (or whatever I decide to put into the overridable method.

    I'm not sure if the Tabs class can do that, can it? It's not a huge dealbreaker if it can't, but I'm basically trying to separate inheritable values from the specific, child values so my inspectors don't get too huge and unwieldy.

    At the very least, I'd love to know how the Descriptor works on the Tabs, so I can rename the enum value Tab titles to something more fitting.

    Any advice?
     
  13. NeatWolf

    NeatWolf

    Joined:
    Sep 27, 2013
    Posts:
    896
    Yup, the beta works like a charm regarding that particular previous issue :)
     
  14. TinyCobra

    TinyCobra

    Joined:
    Jan 19, 2015
    Posts:
    3
    Just wanted to say thanks so much for this tool! I use it at work all the time, and have felt a clear difference in my workflow when I work on personal projects at home without this extension (I'm a 3D artist / UI designer+developer ). I'm hoping to get a copy for myself and my husband to use at home, hopefully soon :)

    I'm excited to see what you come up with in the future! Great work!
     
  15. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,604
    Thanks, always nice to hear.

    It's not currently possible with version 1.70.

    If you send me an email at admin@lightstrikersoftware.com, I can send you a beta version with that feature.
     
  16. electroflame

    electroflame

    Joined:
    May 7, 2014
    Posts:
    177
    I sent you an email. Thanks for looking into the feature!
     
  17. NeatWolf

    NeatWolf

    Joined:
    Sep 27, 2013
    Posts:
    896
    Just curious:

    if I have a serializable class ValueKeyPair with 2 public fields, and want to create a class that is actually a List<ValueKeyPair>, is there a way in AI to have each line of the list have both key and value on the same row (splitting the width horizontally, like a Vector2D/3D)? The Key is a String, and the Value is a GameObject, so I need to keep the appropriate style for each field.

    Code (CSharp):
    1. [System.Serializable]
    2. public class InteractableKeyValuePair
    3. {
    4.     [Restrict("getTemplateNames")]
    5.     public string name;
    6.    
    7.     private IList getTemplateNames()
    8.     {
    9.         return GlobalGameSettings.Instance.interactableTemplateNames;
    10.     }
    11.    
    12.     public GameObject template;
    13. }
    14.  
    15. [System.Serializable]
    16. public class InteractableList
    17. {
    18.     [DisplayAsParent, Expandable(AlwaysExpanded = true)]
    19.     public List<InteractableKeyValuePair> list;
    20. }
    21.  
    22.  
    23. [CreateAssetMenu(fileName = "GlobalGameSettings", menuName = "MyGameNameHere", order = 100)]
    24. public class GlobalGameSettings : ScriptableObject
    25. {
    26.     static GlobalGameSettings globalGameSettings;
    27.     public GameObject gameManagers;
    28.     public GameObject globalCamera;
    29.     public GameObject globalUICamera;
    30.    
    31.     public AudioMixer globalMixer;
    32.     public AudioMixerGroup mixerMaster;
    33.     public AudioMixerGroup mixerSFX;
    34.     public AudioMixerGroup mixerMusic;
    35.    
    36.     [Space(8)]
    37.     [Header("Interactions\nand Templates")]
    38.     public bool showTemplates = false;
    39.     private bool showTemplatesCheck() {return showTemplates;}
    40.    
    41.     [Inspect("showTemplatesCheck")]
    42.     public bool lockTemplates = true;
    43.     private bool lockTemplatesCheck() {return lockTemplates;}
    44.    
    45.     [DisplayAsParent(false)]
    46.     [Inspect("showTemplatesCheck"), ReadOnly("lockTemplatesCheck")]
    47.     public List<string> interactableTemplateNames;
    48.    
    49.     [DisplayAsParent(false)]
    50.     [Inspect("showTemplatesCheck"), ReadOnly("lockTemplatesCheck")]
    51.     public InteractableList interactableTemplates;
    and the result is a bit bulky:



    Having Name(label) , dropdownlist, Template(label), GameObject picker on the same line would be definitely more tidy.

    I also tried to make the List a little bit more compact, but with no success (having directly all the labels and fields on the same line of the list index number would be great, or at least a dynamic label or field)

    Is there a way to make this interface a bit more compact using AI, using the same data structure?
     
  18. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,604
    Damn... Sorry for the slow answer. For some reason, this forum decided to not warn me of a new reply on this thread.

    A list of KeyValuePair, sounds to me like a Dictionary. Is it what you're after?

    If you want to have two field side by side, you can write your own FieldEditor, with or without a FieldAttribute associated with it.
     
  19. NeatWolf

    NeatWolf

    Joined:
    Sep 27, 2013
    Posts:
    896
    No worries, it wasn't urgent :)

    Yes, it's the ugly way to make a dictionary, but I don't want to enter inside the world of "how I can get my dictionaries serialized properly", so I implemented in the old and robust way.

    Sure, I can always write a custom inspector, but I'm using AI to avoid to :p

    Since you added support for toolbars and tabs, I was wondering if you could add a similar function for generic fields to have the same "Row" attribute, grouped by string, ordered by index or declaration.

    Maybe is this going to be a feature request since I'm implying it's not possible with AI at the moment?
     
  20. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,604
    Have you tried the AI support for dictionaries? Namely, the UDictionary class? It is directly serializable by Unity - no hack - and it is displayed properly by AI.
     
  21. NeatWolf

    NeatWolf

    Joined:
    Sep 27, 2013
    Posts:
    896
    (I was asking because I have no experience with FieldEditors and custom inspectors (and I think many AI users don't have as well) - even if I believe a 2 fields custom inspector woudln't be too hard to write, I've been peeking at the source code of many different assets - I should really take some time to master them as soon as the storm is gone :) )

    Ahum, nope! I had no idea such class was there!
    I will have a look, thanks!
    I hope it's using Generics and the serialization is also crossplatform(Android-iOS), I'd need string keys and Gameobject(prefab) values :)

    Thanks for the hint!
     
  22. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,604
    The low-level serialization is totally handled by Unity, so it is as cross-platform as Unity.
    Behind the scene, it is a List<Key> and a List<Value>, and when Unity deserialize it, it is combined back into a Dictionary<Key, Value>.

    Look at AIExample32_Dictionary.

    Also, UDictionary is not in any library, it is an open class you can modify. AI doesn't care about UDictionary, it only displays the IDictionary .NET interface. So you could write your own dictionary type and it would still work with AI.
     
    NeatWolf likes this.
  23. Astro75

    Astro75

    Joined:
    Dec 18, 2014
    Posts:
    45
  24. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,604
    Hmm... Honestly, I cannot know what your Method will do when clicked. Imagine it modify another object? How should I know I should flag it as dirty?
     
  25. Astro75

    Astro75

    Joined:
    Dec 18, 2014
    Posts:
    45
    I think you did not understand what I wanted to say. I have a prefab that is not connected to any scene. I just select it in the project hierarchy window and click method button through Advanced Inspector.
    EditorUtility.SetDirty needs to be called in addition to Undo.RecordObject on the same object. Otherwise it does not save that prefab on the disk and after restarting Unity I find the old values restored.
     
    Last edited: Jan 7, 2017
  26. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,604
    Ah... I see. If you send me an email at admin@lightstrikersoftware.com, I can send you a version that should fix that.
     
  27. Astro75

    Astro75

    Joined:
    Dec 18, 2014
    Posts:
    45
    I have my own for now so it is not important to update your right away. I'll just wait for next AI release.

    There is another thing. joint2d editors don't have all the values of unity standard editor. Autoconfigure Connected Anchor checkbox is the one I missed after upgrading unity to 5.3. I have them disabled in my project. I think you should look into that.
     
  28. LunaTrap

    LunaTrap

    Joined:
    Apr 10, 2015
    Posts:
    107
    Hello im having problems with using this i dont know why, but when i close Unity, all values are gone, is the [Inspect] attibute the same as [SerializeField]? what im doing wrong? help please

    Im deriving from the base ItemData ScriptableObject class for all my Items data.

    Code (CSharp):
    1.     /// <summary>
    2.     /// Base ScriptableObject class from which all ItemsData derive from, ItemData contains required data for all Items, while the Item script contains the logic.
    3.     /// </summary>
    4.     public class ItemData : ScriptableObject
    5.     {
    6.         #region Inspector
    7.  
    8.         [Inspect(), Group("Item Data", Expandable = false), ReadOnly, Tooltip("Unique number ID that indentifies this Item.")]
    9.         protected int id;
    10.         /// <summary>
    11.         /// Unique number ID that indentifies this Item.
    12.         /// </summary>
    13.         public int ID
    14.         {
    15.             get { return id; }
    16.         }
    17.         [Inspect, Group("Item Data", Expandable = false), Tooltip("The name of this item.")]
    18.         protected string itemName;
    19.         /// <summary>
    20.         /// The name of this item.
    21.         /// </summary>
    22.         public string ItemName
    23.         {
    24.             get { return itemName; }
    25.         }
    26.         [Inspect, Group("Item Data", Expandable = false), Tooltip("Texture used for this item icon.")]
    27.         protected Sprite itemIcon;
    28.         /// <summary>
    29.         /// Texture used for this Item icon.
    30.         /// </summary>
    31.         public Sprite ItemIcon
    32.         {
    33.             get { return itemIcon; }
    34.      
     
  29. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,604
    [Inspect] is not the same as [SerializeField].

    One is to display a value in the inspector, the other is to save a value.

    Advanced Inspector does not change in any way how Unity save stuff. In most case on fields, you should just use [SerializeField]. [Inspect] is useful when you want to expose properties and methods.
     
  30. LunaTrap

    LunaTrap

    Joined:
    Apr 10, 2015
    Posts:
    107
    Wow! that was a quick answer! and yes, now i fixed the problem, thanks a lot, this asset deserves rating of 5 stars for sure!
     
  31. XaneFeather

    XaneFeather

    Joined:
    Sep 4, 2013
    Posts:
    90
    I recently noticed that invoked methods (Inspect, Method(Display = MethodDisplay.Invoke) actually adds spacing to the inspector even though nothing is visible (in most cases).
    Is this an intended behavior? If so, is there a way to disable the spacing? I was wondering why some of my inspectors showed random spacing between elements.
     
  32. LunaTrap

    LunaTrap

    Joined:
    Apr 10, 2015
    Posts:
    107
    Hi, i want to know if there is a way to make the Inspect attribute update the value being inspected constantly? right now it gets updated only when i select and re-select the object.

    I noticed that if i add the value to the Watch window, then it will upadate constantly, so then i notice that i cant add more than 1 value to the Watch window, is this how is supossed to work?



    Here im adding both values, but only AnyDetected is shown, here is the script:

    Code (CSharp):
    1. using UnityEngine;
    2. using AdvancedInspector;
    3.  
    4. public class DecalDetection : MonoBehaviour
    5. {
    6.     [Inspect]
    7.     public bool AnyDectected { get; private set; }
    8.     [Inspect]
    9.     private int numberOnDecalsDetected = 0;
    10.  
    11.     private void OnTriggerEnter(Collider decalCol)
    12.     {
    13.         if (decalCol.transform.CompareTag(GameTags.GameObjects.Decal))
    14.         {
    15.             AnyDectected = true;
    16.             numberOnDecalsDetected++;
    17.         }
    18.     }
    19.  
    20.     private void OnTriggerExit(Collider decalCol)
    21.     {
    22.         if (decalCol.transform.CompareTag(GameTags.GameObjects.Decal))
    23.         {
    24.             numberOnDecalsDetected--;
    25.             if(numberOnDecalsDetected <= 0)
    26.             {
    27.                 AnyDectected = false;
    28.             }
    29.         }
    30.     }
    31. }
     
  33. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,604
    Well your method adds a field, even if there is no label. The moment a field is added, you have all the GUILayout going on. I would guess you could use [Inspect] to turn it off if you're not displaying anything.
     
  34. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,604
    It's clearly a bug, and I've been able to reproduce it here.

    I don't know what causes it yet.
     
  35. XaneFeather

    XaneFeather

    Joined:
    Sep 4, 2013
    Posts:
    90
    I'm primarily using some of the Invoke methods to simply have a certain algorithm run any time the inspector is being refreshed to do some sanity checks (removing null objects from collections, setting item values in a collection as soon as an element is reordered or created/deleted, etc). They do not display or render anything at all.

    All I'd need is a property in the Method attribute telling the system to not create a field for the method. Would that be possible?
     
    Last edited: Jan 13, 2017
  36. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,604
    Why are you not using the IDataChanged interface? Or the Unity OnValidate method?
     
  37. NeatWolf

    NeatWolf

    Joined:
    Sep 27, 2013
    Posts:
    896
    Hi @LightStriker,

    I'd like to have some sort of callback whenever the "+" button of a list gets pressed on a List which is using AI to be shown.
    And maybe another when an item gets removed or reordered.

    Is there a way to have this working on AI, or the solution isn't bound to AI?
    If it's the latter case, could you please point me to the right direction on how to implement it?
    (I basically need to initialize properly a new Item in the list as soon as a new null reference is added to the list, only on the newly added list object)

    Thank you :)

    (btw, how is the reworking of the bold text/prefab override proper showing/revertion going? I haven't seen any update recently, do you have any eta?)
     
  38. mdrotar

    mdrotar

    Joined:
    Aug 26, 2013
    Posts:
    377
    I have a ScriptableObject that has some POCO objects and other Unity Objects within it and when I select it, I get this error:
    Is the source code available for Advanced Inspector so I can dig deeper at this?

    UnityEngine.GameObject:GetComponentsInternal (System.Type,bool,bool,bool,bool,object)
    at UnityEngine.GameObject.GetComponents (System.Type type) [0x00000] in C:\buildslave\unity\build\artifacts\generated\common\runtime\UnityEngineGameObjectBindings.gen.cs:96
    at AdvancedInspector.ObjectEditor.DrawObjectSelector (AdvancedInspector.InspectorField field) [0x0001f] in C:\Users\Matthew\Documents\Unity Projects\SpriteSwap\Assets\Plugins\Editor\AdvancedInspector\FieldEditors\ObjectEditor.cs:218
    at AdvancedInspector.ObjectEditor.Draw (AdvancedInspector.InspectorField field, UnityEngine.GUIStyle style) [0x00419] in C:\Users\Matthew\Documents\Unity Projects\SpriteSwap\Assets\Plugins\Editor\AdvancedInspector\FieldEditors\ObjectEditor.cs:154
    at AdvancedInspector.AdvancedInspectorControl.DrawField (AdvancedInspector.InspectorEditor editor, AdvancedInspector.InspectorField field, UnityEditor.PropertyDrawer[] properyDrawers, System.Collections.Generic.Dictionary`2 fieldDrawers, AdvancedInspector.FieldEditor fieldEditor, UnityEngine.GUIStyle style) [0x00436] in A:\LightStrikerSoftware\Projet\AdvancedInspector\AdvancedInspector 5\Lib\AdvancedInspector\AdvancedInspector\AdvancedInspectorControl.cs:1336
    UnityEngine.Debug:LogError(Object)
    AdvancedInspector.AdvancedInspectorControl:DrawField(InspectorEditor, InspectorField, PropertyDrawer[], Dictionary`2, FieldEditor, GUIStyle) (at A:/LightStrikerSoftware/Projet/AdvancedInspector/AdvancedInspector 5/Lib/AdvancedInspector/AdvancedInspector/AdvancedInspectorControl.cs:1341)
    AdvancedInspector.AdvancedInspectorControl:DrawNode(InspectorEditor, InspectorField, Boolean, Boolean) (at A:/LightStrikerSoftware/Projet/AdvancedInspector/AdvancedInspector 5/Lib/AdvancedInspector/AdvancedInspector/AdvancedInspectorControl.cs:1153)
    AdvancedInspector.AdvancedInspectorControl:Draw(InspectorEditor, InspectorField, List`1, Boolean, Boolean, Boolean) (at A:/LightStrikerSoftware/Projet/AdvancedInspector/AdvancedInspector 5/Lib/AdvancedInspector/AdvancedInspector/AdvancedInspectorControl.cs:797)
    AdvancedInspector.AdvancedInspectorControl:DrawChildren(InspectorEditor, InspectorField, Boolean, Boolean) (at A:/LightStrikerSoftware/Projet/AdvancedInspector/AdvancedInspector 5/Lib/AdvancedInspector/AdvancedInspector/AdvancedInspectorControl.cs:1524)
    AdvancedInspector.AdvancedInspectorControl:DrawNode(InspectorEditor, InspectorField, Boolean, Boolean) (at A:/LightStrikerSoftware/Projet/AdvancedInspector/AdvancedInspector 5/Lib/AdvancedInspector/AdvancedInspector/AdvancedInspectorControl.cs:1170)
    AdvancedInspector.AdvancedInspectorControl:Draw(InspectorEditor, InspectorField, List`1, Boolean, Boolean, Boolean) (at A:/LightStrikerSoftware/Projet/AdvancedInspector/AdvancedInspector 5/Lib/AdvancedInspector/AdvancedInspector/AdvancedInspectorControl.cs:797)
    AdvancedInspector.AdvancedInspectorControl:DrawChildren(InspectorEditor, InspectorField, Boolean, Boolean) (at A:/LightStrikerSoftware/Projet/AdvancedInspector/AdvancedInspector 5/Lib/AdvancedInspector/AdvancedInspector/AdvancedInspectorControl.cs:1524)
    AdvancedInspector.AdvancedInspectorControl:DrawNode(InspectorEditor, InspectorField, Boolean, Boolean) (at A:/LightStrikerSoftware/Projet/AdvancedInspector/AdvancedInspector 5/Lib/AdvancedInspector/AdvancedInspector/AdvancedInspectorControl.cs:1170)
    AdvancedInspector.AdvancedInspectorControl:Draw(InspectorEditor, InspectorField, List`1, Boolean, Boolean, Boolean) (at A:/LightStrikerSoftware/Projet/AdvancedInspector/AdvancedInspector 5/Lib/AdvancedInspector/AdvancedInspector/AdvancedInspectorControl.cs:797)
    AdvancedInspector.AdvancedInspectorControl:Inspect(InspectorEditor, List`1, Boolean, Boolean, Boolean, Separator) (at A:/LightStrikerSoftware/Projet/AdvancedInspector/AdvancedInspector 5/Lib/AdvancedInspector/AdvancedInspector/AdvancedInspectorControl.cs:700)
    AdvancedInspector.AdvancedInspectorControl:Inspect(InspectorEditor, List`1, Boolean, Boolean) (at A:/LightStrikerSoftware/Projet/AdvancedInspector/AdvancedInspector 5/Lib/AdvancedInspector/AdvancedInspector/AdvancedInspectorControl.cs:639)
    AdvancedInspector.InspectorEditor:DrawAdvancedInspector() (at A:/LightStrikerSoftware/Projet/AdvancedInspector/AdvancedInspector 5/Lib/AdvancedInspector/AdvancedInspector/InspectorEditor.cs:496)
    AdvancedInspector.InspectorEditor:OnInspectorGUI() (at A:/LightStrikerSoftware/Projet/AdvancedInspector/AdvancedInspector 5/Lib/AdvancedInspector/AdvancedInspector/InspectorEditor.cs:385)
    UnityEditor.DockArea:OnGUI()
     
  39. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,604
    You could use the Constructor attribute, which let you "build" a new entry to a collection to the way you want. It's called when the + is clicked.

    There is no callback for the item moved, except IDataChanged and Unity's OnValidate.

    And no... I have no ETA on the prefab issue. Honestly, I hadn't much time to work on AI lately, things about trying to save my video game studio. Making a kickstarter a bit in a rush.
     
    NeatWolf likes this.
  40. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,604
    The source code is not totally available. As you can see, the error comes from ObjectEditor file, which is not compiled, and you can modify it yourself.

    Would you have any snippet of code of where the error happens?
     
  41. NeatWolf

    NeatWolf

    Joined:
    Sep 27, 2013
    Posts:
    896
    Thanks, I will try your solutions.

    I had no idea, sorry about that. If you've got a mailing list to insert me into at the launch of the campaign, please let me know.
     
  42. mdrotar

    mdrotar

    Joined:
    Aug 26, 2013
    Posts:
    377
    Thanks. For whatever reason, my usual double clicking on the stack line wasn't taking me to the source file so assumed that meant the source for the class wasn't available. I was able to edit ObjectEditor to at least suppress the error so it doesn't spam the console.

    You can reproduce the error with this ScriptableObject class:
    Code (csharp):
    1. using System.Collections.Generic;
    2. using UnityEngine;
    3.  
    4. [CreateAssetMenu]
    5. public class AdvInspectRepro : ScriptableObject
    6. {
    7.     public List<TestClass1> TestObjects = new List<TestClass1>();
    8. }
    9. [System.Serializable]
    10. public class TestClass1
    11. {
    12.     public UnityEngine.Object TargetObject;
    13. }
    Then do the following steps:
    1. Create an instance of the scriptable object and select it.
    2. Add an entry to TestObjects from the inspector.
    3. For that entry, fill in the 'TargetObject' with a reference to an 'Image' component (or probably any other MonoBehaviour, it seems). Make sure you drag from the Image component, not the GameObject, which means you'll have to use 2 inspectors and lock one on the AdvInspectRepro object.
    4. The error should show immediately. If not select something else and then reselect the AdvInspectRepro object and make sure everything is expanded so you can see the Target Object field. It should look like this: upload_2017-1-15_12-26-47.png
     
  43. XaneFeather

    XaneFeather

    Joined:
    Sep 4, 2013
    Posts:
    90
    I'm doing that where I need to track changes inside the inspector, but what I need is a method that gets called whenever the Inspector receives focus as I want to, say, update a list by fetching all child components of a certain type. I need to make sure the inspector always has valid entries in a list and when you're referencing GameObjects and you delete them in the hierarchy, the inspector will not be notified as the changes happen outside the inspector and you end up with null-objects in a list.
    By using an Invoke method that goes through the entire list any time the inspector is focused, I can remove any null entries in a list and refresh the inspector. If there is any alternative way of calling a method any time an inspector receives focus, I'm all ear! The only alternative I can think of is writing a dummy Editor class that simply invokes a method on any OnInspectorGUI call, which obviously isn't optimal.

    EDIT:

    Something unrelated, but the "ReadOnly"-attribute really needs a Condition property, synonymous to the same field in the Inspect-attribute, which lets us check for positive or negative conditions.
     
    Last edited: Jan 17, 2017
  44. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,604
    Sure... you can go at http://www.cradlegames.com and click on "subscribe" at the bottom.
     
    NeatWolf likes this.
  45. electroflame

    electroflame

    Joined:
    May 7, 2014
    Posts:
    177
    I know you're busy, @LightStriker, so I'm not looking for a super fast response here. That said, I've got another question about Tabs. Is it possible to do some additional checking on your end before deciding whether or not to display the tab bar? I'm thinking that, mainly:
    • A Tab shouldn't display if there's nothing assigned to it.
    • Likewise, if you have two tabs, and one is empty, it seems like the empty one shouldn't display, which should also negate the use of the tab bar for everything (as there's no need to display a one-tab tab bar). Basically, if there's no reason to display the Tabs, don't.
    I'm not sure if these are possible, but it would make Tabs much more useful. As it stands now, I've got a couple of objects with "Empty" tabs that just take up valuable Inspector space and increase visual clutter, since the Tabs themselves are part of an inheritance chain. Doing it this way would also allow for extra Tab definitions in the base class's enum, and let the child classes mix-and-match and only display the tabs containing data they expose to the Inspector.

    Is it possible to do some kind of validation like that before you start drawing the Tabs?
     
  46. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,604
    Stupid question... but how do you get an empty tab??
     
  47. electroflame

    electroflame

    Joined:
    May 7, 2014
    Posts:
    177
    Oh, basically have an an entry in the Enum for the tabs, but never assign anything to that Enum. For example, given the following Enum:

    Code (CSharp):
    1. public enum InspectorTabs
    2. {
    3.      Tab1,
    4.      Tab2
    5. }
    You'd assign everything to Tab1, but never use Tab2. In the Inspector for the object assigning all of its fields to Tab1, it'd show the Tab bar with Tab1 and Tab2, but Tab2 will be empty.

    If everything being exposed to the Inspector is assigned to Tab1, the Tab2 tab will have nothing to display, so it'll just show the inspector divider and that's it.

    Hopefully that makes sense.
     
  48. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,604
    I've been able to reproduce the issue.

    Replace the last method of ObjectEditor.cs with;

    Code (CSharp):
    1.         private void DrawObjectSelector(InspectorField field)
    2.         {
    3.             Component behaviour = field.GetValue() as Component;
    4.             if (behaviour == null)
    5.                 return;
    6.  
    7.             List<Component> components;
    8.             if (typeof(Component).IsAssignableFrom(field.BaseType))
    9.                 components = new List<Component>(behaviour.gameObject.GetComponents(field.BaseType));
    10.             else
    11.                 components = new List<Component>(behaviour.gameObject.GetComponents(behaviour.GetType()));
    12.  
    13.             if (components.Count == 1)
    14.                 return;
    15.  
    16.             int index = components.IndexOf(behaviour);
    17.             string[] texts = new string[components.Count];
    18.  
    19.             for (int i = 0; i < components.Count; i++)
    20.                 texts[i] = i.ToString() + " : " + components[i].ToString();
    21.  
    22.             EditorGUILayout.BeginHorizontal();
    23.             int selection = EditorGUILayout.Popup(index, texts);
    24.             EditorGUILayout.EndHorizontal();
    25.  
    26.             if (selection == index)
    27.                 return;
    28.  
    29.             field.SetValue(components[selection]);
    30.         }
     
  49. Barliesque

    Barliesque

    Joined:
    Jan 12, 2014
    Posts:
    46
    Is there a way to allow Custom Property Drawers to be used (instead of Unity's default inspector) within Advanced Inspector's array list gadget?
     
  50. LightStriker

    LightStriker

    Joined:
    Aug 3, 2013
    Posts:
    2,604
    If you're on version 1.70, contact me at admin@lightstrikersoftware.com as it has a bug with property drawers not showing up. They should work fine in or outside lists.
     
unityunity