Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Question For ExecuteInEditMode, when/how do I respond to changes in inspector values?

Discussion in 'Scripting' started by mortoray, Feb 20, 2023.

  1. mortoray

    mortoray

    Joined:
    Sep 14, 2018
    Posts:
    89
    I'm having trouble figuring out when/how I should be responding to changes in values in the inspector. I'm using ExecuteInEditMode as I'd like to work on some of my visuals, but I can't figure out the flow I need to work in edit mode, in the simulator, and at runtime.

    I've tried `OnValidate`, but it can be called prior to `OnEnable`, so I can't rely on anything in `OnEnable` having been run. Neither `Awake` nor `Start` are called in edit mode, so I can't rely on whatever code those use. At runtime I have no problem using these to add and adjust other components, but in edit mode I can't figure out the right place to do it.

    `Update` will always be called when something changes, but it means I have to write code to do updates, which might be duplicated for functions that also do the updates. Plus, I can't assume in Update that either Awake or Start has been called.

    I'm getting a bit frustrated trying to figure this out. Components with ExecuteInEditMode don't appear to be a well documented aspect of the editor. :(
     
  2. Leuki

    Leuki

    Joined:
    Feb 27, 2014
    Posts:
    130
    If you have a component that is running in ExecuteInEditMode mode and you want to respond to changes in its inspector values, you can also use the OnValidate method.

    The OnValidate method is called whenever a value in the inspector is changed, whether the component is in play mode or not. You can override this method in your component and implement the logic you want to perform in response to the change.

    Code (CSharp):
    1. [ExecuteInEditMode]
    2. public class MyComponent : MonoBehaviour
    3. {
    4.     [SerializeField] private int myValue;
    5.  
    6.     private void OnValidate()
    7.     {
    8.         Debug.Log("My value changed to: " + myValue);
    9.     }
    10. }
    11.  

    In this example, the MyComponent class is marked with the ExecuteInEditMode attribute and has a serialized field myValue. Whenever the value of myValue is changed in the inspector, the OnValidate method is called and logs the new value to the console.

    Note that OnValidate is called frequently and can cause performance issues if it performs expensive operations. In some cases, you may want to use a delay before performing the operation, or only perform it after the user has stopped editing the values in the inspector. You can achieve this by using a coroutine or a timer, for example.
     
  3. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,195
    In what kind of ways do you need to react?

    For ExecuteInEditMode scripts that should react to transforms being moved, checking transform.hasChanged and setting it back to false is a good way. For changing inspector values, I'd honestly have the inspector be a custom editor wrapped in change checks, and then call the required method from the editor.
     
    Bunny83 likes this.
  4. mortoray

    mortoray

    Joined:
    Sep 14, 2018
    Posts:
    89
    I'm wrapping my ui controls (and other elements) in higher level components/game-objects for ease of use and consistency in style. For example, I might have a `TokenCounter` element in my game, it has two properties, an "icon" (a sprite in this case), the count (an int), and a flag to indicate if it's "active" of not. If I change the properties I want the editor to show the changes.

    At runtime the values will also be changed (probably not sprite). I'm trying to avoid having to write entirely different update paths and enable/update handling depending on whether I'm in the editor or running.


    Maybe I do have to do custom editors, and not rely on the convenience of public fields.
     
  5. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,195
    I mean the custom editor I'm proposing is just:

    Code (csharp):
    1.  
    2. public override void OnInspectorGUI() {
    3.     EditorGUI.BeginChangeCheck();
    4.     base.OnInspectorGUI();
    5.     if (EditorGUI.EndChangeCheck())
    6.         target.ApplyNewInspectorValues();
    7.  
    And then you do the thing you want in ApplyNewInspectorValues. You don't lose the "convenience of public fields".
     
    ThermalFusion and Bunny83 like this.
  6. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,722
    Why does this have strong ChatGPT vibes?
     
  7. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,528
    :) Yes it does. Though I don't want to falsy accuse people anymore. No matter who "wrote" the answer, that person either has not really read the question, or did not understand what was written there.

    Anyways, I actually do not see any issues with using OnValidate. I don't quite get the complaint about OnEnable. OnValidate is called whenever something that is serialized is changed in the inspector. That's a fact.

    I sense that there is simply a massive abuse of ExecuteInEditMode. That attribute is NOT meant to implement editor tools. MonoBehaviours scripts are runtime script which represent runtime behaviour. That attribute simply allows you to get the same behaviour that the script represents while in edit mode. In most cases it would be used for things like a custom particle system when you want a preview in the editor. Or some other behaviour like a billboard script so you get a proper preview while in the editor.

    I've seen a lot people implement editor tools with that attribute over 8 years ago. However, that's not what this is designed for. Yes, it could be used for that in some cases, but it essentially abuses runtime scripts that way.

    Note it is of course possible to design certain MonoBehaviour scripts which are essentially "editor only" and are only attached temporarily. For certain editor tools that may be a simpler approach. Though in most cases it's not.

    EditorWindows, which are there for implementing editor tools, actually receive several events like OnProjectChange or
    OnInspectorUpdate. In most cases editor tools should be implemented either inside a custom Editor, an EditorWindow or a custom abstract tool class that hooks into one of the EditorApplication or SceneView callbacks.
     
    ThermalFusion likes this.
  8. ThermalFusion

    ThermalFusion

    Joined:
    May 1, 2011
    Posts:
    906
    I second Baste and Bunny83 suggestions to do proper editor scripts for this.
    ExecuteInEdit mode can dirty your scene just by opening it, which is absolutely terrible. I've had to use packages that relied on this method in the past. Nightmare. Never again, if it can be helped.
     
    Bunny83 likes this.
  9. mortoray

    mortoray

    Joined:
    Sep 14, 2018
    Posts:
    89
    I am not writing editor tools. I'm just trying to get my objects to look the same in editor mode as they do in runtime, so that I can properly adjust the layout. I'm looking for the cleanest option to make this happen without having a lot of redundant code, or code that differs from runtime behaviour -- since that would defeat the purpose of looking the same as at runtime.
     
  10. mortoray

    mortoray

    Joined:
    Sep 14, 2018
    Posts:
    89
    Thanks. This does feel saner than OnValidate, since for a single change it triggers only once, but it appears OnValidate triggers many times (maybe across many controls) -- though it may not be a problem at editor time. I will use this approach in cases where OnValidate is insufficient.
     
  11. highpockets

    highpockets

    Joined:
    Jan 17, 2013
    Posts:
    67