Search Unity

Runtime Inspector and Hierarchy [Open Source]

Discussion in 'Assets and Asset Store' started by yasirkula, Oct 22, 2017.

  1. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    What did you do?
     
  2. MFKJ

    MFKJ

    Joined:
    May 13, 2015
    Posts:
    264
    Actually my scene name was not correct + the object was disabled.
     
  3. iosphere

    iosphere

    Joined:
    Dec 28, 2019
    Posts:
    13
    I would like to use this asset to expose the variables within a particle system. This doesn't seem to happen out of the boxy, however. Can you steer me in the right direction to do this? Thanks!
     
  4. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    RuntimeInspector doesn't display properties without a setter and ParticleSystem modules only have a getter. The fact that these modules are non-serializable structs makes things even more challenging. There's an ugly workaround:
    • attach the following script to the ParticleSystem object:
    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class ParticleSystemProperties : MonoBehaviour
    4. {
    5.     public ParticleSystem.MainModule main;
    6.  
    7.     private void Awake()
    8.     {
    9.         main = GetComponent<ParticleSystem>().main;
    10.     }
    11. }
    Settings.png

    Now, you'll be able to edit the MainModule's properties:

    Exposed Module.png

    For other modules, you can create other variables and add them to the Runtime Inspector Settings asset.

    You'll notice that each module has a lot of settings and probably you are not interested in most of these settings. A better solution that doesn't require modifying the RuntimeInspector source code or creating a new Runtime Inspector Settings asset would be as follows:
    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class ParticleSystemProperties : MonoBehaviour
    4. {
    5.     private ParticleSystem.MainModule main;
    6.  
    7.     public float Duration
    8.     {
    9.         get { return main.duration; }
    10.         set { main.duration = value; }
    11.     }
    12.  
    13.     public bool Loop
    14.     {
    15.         get { return main.loop; }
    16.         set { main.loop = value; }
    17.     }
    18.  
    19.     private void Awake()
    20.     {
    21.         main = GetComponent<ParticleSystem>().main;
    22.     }
    23. }
    You simply create wrapper properties for only the values that you are interested in:

    Exposed Settings.png

    Hope it helps!
     
  5. Handy-TT

    Handy-TT

    Joined:
    May 9, 2017
    Posts:
    2
    Hi, I have been using your plugin to create a runtime level editor. But I am only using the RuntimeInspector. So, is there any way when I use RuntimeInspector.Inspect(object), I also want to detect for any changes on the inspected object, I want to fire some kind of event?
     
    Last edited: Jul 10, 2020
  6. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
  7. Handy-TT

    Handy-TT

    Joined:
    May 9, 2017
    Posts:
    2
    Update:
    My current solution for this is not optimized, but it works for now. I will pass an action as parameter in Inspect method which will be stored and get Invoked in Refresh method. Since Unity OnInspectorGUI works like that too.

    Thanks the information. But my requirement here is I have a List<T> to be inspected where typeof T can be any subclass of T. Each subclass of T has their own inspectable members maybe like some enums, integers, or strings. What I need is I need some kind of onValueChanged event for each of the members / variables changed like those enums, integers, strings, etc. Is there any way to do that?
    I want to avoid making a custom editor script for each subclass of T, since it is not a good practice in my work pipeline.
     
    Last edited: Jul 13, 2020
  8. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    InspectorField has some interesting fields, perhaps they could help:

    - RuntimeInspector m_inspector: RuntimeInspector that the field belongs to. You can access RuntimeInspector's Action this way
    - Type m_boundVariableType: type of this field's value (e.g. enum, int, a T implementation)
    - If necessary, you can also store MemberInfo passed to OnBound in a variable and then use it with reflection. This MemberInfo stores the variable this field is bound to
     
  9. Andefob

    Andefob

    Joined:
    Sep 17, 2018
    Posts:
    99
    I found a bug related to BoundSlider and NumberRangeField.

    I noticed that sometimes, when opening inspector on my object, some of the bound values (floating points with RangeAttribute set, using NumberRangeField) got changed to the min value. The reason turned out to be that when SetRange was called, if the old/default slider value was not inside the range, SliderValueChanged got called and it changed the real value.

    This only happens when NumberRangeField is taken from pool in InstantiateDrawer. If it is not pooled but a new one is created, OnValueChanged does not get called in BoundSlider.SliderValueChanged since sliderFocused is false.

    When trying to understand the point of sliderFocused I noticed this:

    sliderPointerListener.PointerDown += ( ev ) => sliderFocused = true;
    sliderPointerListener.PointerDown -= ( ev ) => sliderFocused = false;


    Most probably, the intention was:

    sliderPointerListener.PointerDown += ( ev ) => sliderFocused = true;
    sliderPointerListener.PointerUp += ( ev ) => sliderFocused = false;


    I still don't fully get the point of sliderFocused other than it helps make this bug happen more rarely. But even with the fix, it does not entirely fix the issue since in my case, it is possible to close the inspector window (I have hotkey Esc for that) while dragging the slider. In that case, when that particular NumberRangeField gets reused from the pool, the bug can happen again.

    If there are no better ways to fix it, I will probably add a new virtual InitializePooled method to InspectorField to be called for pooled fields and set BoundSlider.sliderFocused to false in NumberRangeField. Alternatively, there could be some cleanup method while adding fields to pool (which might also help getting rid of unused asset references if Unity is tracking those for inactive objects, not sure about that). But anyway, it is worth checking if there are other similar issues with other pooled fields.
     
    yasirkula likes this.
  10. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    Thank you for the very detailed post, it'll greatly help me resolve the issue.
     
  11. Andefob

    Andefob

    Joined:
    Sep 17, 2018
    Posts:
    99
    No problem! I am interested in seeing how you will fix it and maybe it will help find similar other issues :). I added the new InitializePooled call in InstantiateDrawer and it at least fixed the issue for my case.
     
  12. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
  13. Andefob

    Andefob

    Joined:
    Sep 17, 2018
    Posts:
    99
  14. Andefob

    Andefob

    Joined:
    Sep 17, 2018
    Posts:
    99
    Hi again!

    One thing worth mentioning is that if Inspect is called on RuntimeInspector whose Awake has not been called because if it is for example in an inactive tab (even if activeSelf is true), canvas and drawArea don't get initialized. Having null canvas crashes at least EnumField initialization and having null drawArea causes the items to be created in wrong place in the scene and scroll view remains empty when the tab is opened.

    This can be fixed in many ways, e.g. by conditionally initializing them in the beginning of Inspect (if not initialized yet) or whenever referred - or in case of drawArea by using "private RectTransform DrawArea => scrollView.content" instead of the drawArea reference.

    BTW, if you want to see how I am using RuntimeInspector, here are a couple of videos of my hobby project:



    (EDIT: Is there some way to post the links without embedding them?)

    Best regards,
    Antti
     
    Last edited: Sep 9, 2020
  15. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    Fixing the issue by calling the initialization logic in Inspect makes sense to me, thanks!

    In my opinion, your project visually looks great. If you want, you can hide the dark grey background of the items by changing
    variableNameMask.color = Skin.BackgroundColor;
    to
    variableNameMask.color = Color.clear;
    in InspectorField.OnSkinChanged.
     
  16. Andefob

    Andefob

    Joined:
    Sep 17, 2018
    Posts:
    99
    Thanks for the tip! I am quite happy with the current looks already and the dark background may even emphasize right things but I will remember this if I ever get so far in the project that I start polishing visual stuff :).
     
    yasirkula likes this.
  17. hdxpmc

    hdxpmc

    Joined:
    May 1, 2016
    Posts:
    53
    Hello,
    How to hide the IsActive/Name/Layer field when show GameObjects inspector ?
     
  18. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    You should comment out these lines and decrement the value of +4 in Length property accordingly.
     
    Last edited: May 6, 2023
  19. hdxpmc

    hdxpmc

    Joined:
    May 1, 2016
    Posts:
    53
    Thank you very much
     
    yasirkula likes this.
  20. hdxpmc

    hdxpmc

    Joined:
    May 1, 2016
    Posts:
    53
    Hello,
    We have property like this:
    [Range(0.2f, 0.8f)]
    public float floatRange;
    ------------------------------
    How to align title label and slider middle as:
    Float Range
    --------------[Slider]------------------

    And how to use custom uGui component (ex: use slider prefab for slider) ?
     
  21. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    You can modify the NumberRangeField prefab's visuals and layout as you wish.
     
  22. hdxpmc

    hdxpmc

    Joined:
    May 1, 2016
    Posts:
    53
    Thank you very much
     
  23. hdxpmc

    hdxpmc

    Joined:
    May 1, 2016
    Posts:
    53
    Hello,
    How to hide gameobject's name row ? (also for component name row). We want to show only component's properties drawer.
     
  24. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    Object's name can be toggled with RuntimeInspector's "Inspected Object Header Visibility" property but you can't hide component names.
     
  25. hdxpmc

    hdxpmc

    Joined:
    May 1, 2016
    Posts:
    53
    Thank you for help.

    Our development for mobile requiring to show thousands of item as horizontal scrollview with image & title cell in many times. We dream to implement it automatically in Runtime Inspector to save us a lot of time.
    Would you like to guide us to create custom drawer for horizontal scrollview (with dynamic loading cell data) ? For example: we have list<model>, image_at_index(int), title_at_index(int), cell_size_at_index(int), did_select_at_index(int),...

    Best regards
     
  26. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    Just to be sure, are you trying to change a particular Component's drawer so that it has a horizontal scroll view with 1000s of items inside? So, the other components' drawers will stay as is. Am I right?
     
  27. hdxpmc

    hdxpmc

    Joined:
    May 1, 2016
    Posts:
    53
    Currently, Runtime Inspector use ArrayField to draw the List<item>, and it will show all item data vertical after expanding.

    We want to create new property drawer (ListField) to show List<Item> in scrollview to scroll horizontal or vertical with lazy loading

    Best regards
     
  28. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    First, you should read the relevant section of the documentation. You'll need to create a new class that extends from InspectorField. ExpandableInspectorField wouldn't be suitable in your case because a) it generates all child items at once and b) it has collapse functionality that you don't need. Your class' SupportsType function must return true only for List<MySpecificItem> type.

    While creating the drawer prefab, I'd recommend you to duplicate a simple one like BoolField, clear it of unnecessary objects and then build on top of it. Here, you'll have to experiment. You'll be using your favorite scroll view plugin in this prefab and connecting it to the script you've created. Inside the script's Refresh function, you'll be checking if List<MySpecificItem> has been modified and if it is, you'll refresh your scroll view.

    P.S. To accelerate the process and keep things simple, you can first create your scroll view in the scene independently of RuntimeInspector, set it up and make sure that it works properly. Then, you can simply move that scroll view to your RuntimeInspector drawer's prefab and make small adjustments to your drawer's code so that it communicates with your scroll view, if necessary.

    P.P.S. If you'll be using RuntimeInspector solely for this List<MySpecificItem> list, then I don't think RuntimeInspector plugin is the right choice for you.
     
    Last edited: Dec 29, 2020
  29. xkingjohnx

    xkingjohnx

    Joined:
    Feb 22, 2016
    Posts:
    67
    Hi @yasirkula
    I hope you can help me a bit.

    I would like to click in runtime on some objects and than without showing the runtime hierarchy just automatically highlighting the selected object in the runtime inspector..

    I tried to achieve this by using this code:


    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. namespace RLD
    5. {
    6.  
    7.     public class Inspect : MonoBehaviour
    8. {
    9.     public RuntimeInspectorNamespace.RuntimeInspector inspector;
    10.  
    11.         public void InspectObject(GameObject clickedObject)
    12.         {
    13.             RTObjectSelection.Get.Changed += OnSelectionChanged;
    14.             inspector.Inspect(clickedObject.transform);
    15.         }
    16.  
    17.         private void OnSelectionChanged(ObjectSelectionChangedEventArgs args)
    18.         {
    19.             if (args.SelectReason == ObjectSelectReason.Click ||
    20.             args.SelectReason == ObjectSelectReason.ClickAppend)
    21.             {
    22.                 var objectsWhichWereSelected = args.ObjectsWhichWereSelected;
    23.                 InspectObject(objectsWhichWereSelected[0]);
    24.             }
    25.         }
    26.     }
    27. }
    but the runtime instantiated prefabs which I select are not highlited in the inspector...
    I am doing something wrong..

    I would very much appreciate if you could take a look at that ...
    How can this be achieved?

    Many thanks
     
  30. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    I'd change the code like this:
    Code (CSharp):
    1. void Start()
    2. {
    3.     RTObjectSelection.Get.Changed -= OnSelectionChanged;
    4.     RTObjectSelection.Get.Changed += OnSelectionChanged;
    5. }
    6.  
    7. private void OnSelectionChanged(ObjectSelectionChangedEventArgs args)
    8. {
    9.     if (args.SelectReason == ObjectSelectReason.Click ||
    10.     args.SelectReason == ObjectSelectReason.ClickAppend)
    11.     {
    12.         var objectsWhichWereSelected = args.ObjectsWhichWereSelected;
    13.         inspector.Inspect(objectsWhichWereSelected[0]);
    14.     }
    15. }
    If this doesn't resolve the issue, try inserting a Debug.Log to above
    inspector.Inspect
    line and see if it is called. Also check if there are any error messages in Console.
     
  31. xkingjohnx

    xkingjohnx

    Joined:
    Feb 22, 2016
    Posts:
    67

    hi thanks for your fast reply,
    I changed the code to yours and I am getting
    " error CS0116: A namespace cannot directly contain members such as fields or methods"

    in the console now..

    any idea how to fix this?
     
  32. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    I hope you didn't delete all your code. You need to replace just InspectObject and OnSelectionChanged functions with the functions I've posted.
     
  33. xkingjohnx

    xkingjohnx

    Joined:
    Feb 22, 2016
    Posts:
    67
    ah ok thanks. I just changed the code to:


    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. namespace RLD
    5. {
    6.  
    7.     public class Inspect : MonoBehaviour
    8. {
    9.     public RuntimeInspectorNamespace.RuntimeInspector inspector;
    10.  
    11.         public void InspectObject(GameObject clickedObject)
    12.         {
    13.             RTObjectSelection.Get.Changed -= OnSelectionChanged;
    14.             RTObjectSelection.Get.Changed += OnSelectionChanged;
    15.         }
    16.  
    17.         private void OnSelectionChanged(ObjectSelectionChangedEventArgs args)
    18.         {
    19.             if (args.SelectReason == ObjectSelectReason.Click ||
    20.             args.SelectReason == ObjectSelectReason.ClickAppend)
    21.             {
    22.                 var objectsWhichWereSelected = args.ObjectsWhichWereSelected;
    23.                 inspector.Inspect(objectsWhichWereSelected[0]);
    24.             }
    25.         }
    26.     }
    27. }
    Now I have no error in the console, but when I click on a runtime instantiated object, it´s still not highlited in the inspector.. any idea ?
     
  34. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    Is the Debug.Log I've told you to insert to the code invoked? Any runtime errors?
     
  35. xkingjohnx

    xkingjohnx

    Joined:
    Feb 22, 2016
    Posts:
    67

    Hi,
    I did it like this:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. namespace RLD
    5. {
    6.  
    7.     public class Inspect : MonoBehaviour
    8. {
    9.     public RuntimeInspectorNamespace.RuntimeInspector inspector;
    10.  
    11.         public void InspectObject(GameObject clickedObject)
    12.         {
    13.             RTObjectSelection.Get.Changed -= OnSelectionChanged;
    14.             RTObjectSelection.Get.Changed += OnSelectionChanged;
    15.             Debug.Log("RT Selected");
    16.         }
    17.      
    18.         private void OnSelectionChanged(ObjectSelectionChangedEventArgs args)
    19.         {
    20.             if (args.SelectReason == ObjectSelectReason.Click ||
    21.             args.SelectReason == ObjectSelectReason.ClickAppend)
    22.              Debug.Log("RT ObjectSelection");
    23.             {
    24.                 var objectsWhichWereSelected = args.ObjectsWhichWereSelected;
    25.                 inspector.Inspect(objectsWhichWereSelected[0]);
    26.                 Debug.Log("Selected");
    27.             }
    28.          
    29.         }
    30.     }
    31. }
    But no debug msg is showing in the console, and no error message
     
  36. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    Change
    public void InspectObject(GameObject clickedObject)
    to
    void Start()
    and put
    Debug.Log("RT ObjectSelection");
    inside the curly braces.
     
  37. xkingjohnx

    xkingjohnx

    Joined:
    Feb 22, 2016
    Posts:
    67
    Hi,

    thank you very much, it´s showing now the transform data of each clicked object :)

    However I would very much appreciate if you could tell me how to show the Runtime Inspector like this:
    https://ibb.co/zs1GCf1

    so basically I don´t need all other data.. I saw I can deactivate the children-objects from the Runtime inspector while in runtime, but how can I do that so that it´s always only showing the transform data?

    many thanks for your support!
     
  38. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    Does
    inspector.Inspect(objectsWhichWereSelected[0].transform);
    make a difference?

    P.S. You should really remove the
    Debug.Log("RT ObjectSelection");
    line.
     
  39. xkingjohnx

    xkingjohnx

    Joined:
    Feb 22, 2016
    Posts:
    67
    hi, thanks for your fast reply..
    it looks like I am not quite sure where to put that.. I am getting The name 'objectsWhichWereSelected' does not exist in the current context
     
  40. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    You should change the
    inspector.Inspect(objectsWhichWereSelected[0]);
    line. Don't be afraid to improvise;
    inspector.Inspect(objectsWhichWereSelected[0]);
    is the closest thing to
    inspector.Inspect(objectsWhichWereSelected[0].transform);
    , after all.
     
  41. xkingjohnx

    xkingjohnx

    Joined:
    Feb 22, 2016
    Posts:
    67
    ah ok I thinkl I am getting it slowly :)
    That´s what I wanted - thank you very much!

    Just one more question..
    Would it be possible to show the title of the clicked object e.g
    "wall-3m(Clone)(Transform)"

    without: (Clone)(Transform) - so just to display: "Wall-3m" (even if it´s a clone)?
     
  42. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    You should change this line as follows:
    inspectedObjectDrawer.NameRaw = obj.GetName().Replace( "(Clone)", "" );
     
  43. xkingjohnx

    xkingjohnx

    Joined:
    Feb 22, 2016
    Posts:
    67

    Hi,
    Thanks for your fast reply.

    I did as you said but I am getting:
    Assets\Plugins\RuntimeInspector\Scripts\RuntimeInspector.cs(414,53): error CS1929: 'object' does not contain a definition for 'GetName' and the best extension method overload 'RuntimeInspectorUtils.GetName(Object)' requires a receiver of type 'Object'

    here is how I did it:

    Code (CSharp):
    1.                    //inspectedObjectDrawer.NameRaw = obj.GetNameWithType();
    2.                     inspectedObjectDrawer.NameRaw = obj.GetName().Replace("(Clone)", "");
     
  44. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    Hmm, yes you're right. Following should work:
    Code (CSharp):
    1. if( obj as Object )
    2.     inspectedObjectDrawer.NameRaw = ( (Object) obj ).name.Replace("(Clone)", "");
    3. else
    4.     inspectedObjectDrawer.NameRaw = obj.GetNameWithType();
    Please ask any further questions via private message.
     
  45. Nikz_89

    Nikz_89

    Joined:
    Sep 16, 2014
    Posts:
    1
    Hello @yasirkula,

    Big fan :) Really appreciate your work. I'm using your package and I've few doubts mentioned below:

    1) I want to add the "Add Component" Button in Inspector Hierarchy just like the Unity Inspector(refer 'Screenshot_10' in attachment) so that I can add a new script as a component to the game object using this. How we can do using your RuntimeInspector unity package???


    2) If we select any game object from Hierarchy Panel we see all the attached unity components of it in the Inspector panel. How we can do so to show only selective components only like Transform and MeshRenderer only????

    3) I can see a lot of properties of Mesh Renderer in the inspector. How I can see only selective properties such as shared material and hide all others???

    Kindly help me out with these. Cheers!
     

    Attached Files:

  46. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    Thank you for your support ^^ I'll be mentioning several things from the online documentation so please give it a read: https://github.com/yasirkula/UnityRuntimeInspector

    1) This isn't going to be easy, you'll have to do most of the hard work here. You can either use a combination of RuntimeInspectorButton attribute and RuntimeInspectorUtils.ExposedExtensionMethodsHolder property to add a new button to GameObject's inspector, or you can modify GameObjectField prefab and its source code.
    2) Simply register to RuntimeInspector's ComponentFilter delegate
    3) Check out the Settings field of RuntimeInspector: https://github.com/yasirkula/UnityRuntimeInspector#e1-inspector
     
  47. wechat_os_Qy01XPZ9b5CHC5VqzzUM8pS4s

    wechat_os_Qy01XPZ9b5CHC5VqzzUM8pS4s

    Joined:
    Mar 17, 2021
    Posts:
    1
    Hi @yasirkula ,
    I love this assert, it's awesome. I'm using your package and I've a question. For example, there is an object with two scripts. I want to Debug.log("1") if the input of the first script has changed and Debug.log("2) if the second script has changed. How could I do this? I'd appreciate it if you could do me a favor.
    Best wishes.
     
  48. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    There is no such callback, unfortunately. But the good thing is, RuntimeInspector shows properties in addition to fields. So, you can make a property in the first script that modifies the script's input and invokes Debug.Log("1") in the setter function if the value is different. To hide the backing field from RuntimeInspector (so that only the property is displayed, not the field), you can add the field to RuntimeInspectorSettings' Hidden Variables list.
     
  49. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,879
    @Nikz_89 Added options for showing "Add Component" and "Remove Component" buttons in the latest update. Prefabs aren't modified so you don't have to overwrite your changes to prefabs (if any).
     
  50. Tech27

    Tech27

    Joined:
    Dec 13, 2016
    Posts:
    8
    Hai
    yasirkula,

    in editor at runtime hierarchy is visible, but when i build the hierarchy is not showing. can you please help me.?