Search Unity

OnEnable - called in random order? Any way to fix this?

Discussion in 'Scripting' started by a436t4ataf, Jun 14, 2021.

  1. a436t4ataf

    a436t4ataf

    Joined:
    May 19, 2013
    Posts:
    1,933
    For a particular script/type, it seems that OnEnable is called in completely random order.

    If you make a new project, new scene, then ... OnEnable will *probably* be called in tree order: top-level parent first, then children, then grandchildren, etc.

    (I used this to base some logic off - fixes/workarounds to bugs in OnEnable/OnDisable/.activeSelf/.activeInHierarchy)

    OnDisable is invoked in the opposite order: children first, parent last. <-- this makes sense!

    In a complex scene, I just found that Unity randomized the order of OnEnable calls. Children were called, then the parent. ARGH. This explains some nasty bugs I've found it very hard to track down.

    So ... is there an official reason for Unity's ordering of OnEnable? If so, is there a way to change / set it? Or ... is this a bug in some versions of Unity (!)? Certianly: it's hard to use OnEnable effectively when you have no info about when it'll be called (in particular: without a guaranteed call-order there's no way to detect if the current object was enabled, or its parent/grandparent/etc).
     
  2. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,836
    PraetorBlue likes this.
  3. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,909
    It is not a bug. The Unity API intentionally makes no guarantees about the order of events between various Components in the scene.

    While it's generally encouraged to write your code in such a way that it doesn't matter which order your scripts run in, Unity does provide this tool for forcing a specific order:

    https://docs.unity3d.com/Manual/class-MonoManager.html
     
    Last edited: Jun 14, 2021
  4. a436t4ataf

    a436t4ataf

    Joined:
    May 19, 2013
    Posts:
    1,933
    Both your answers appear to have missed the first 5 words of my post :).

    ScriptExecutionOrder has nothing to do with this, sadly.

    However, it seems that I encountered a bug which has already been fixed. Just got to force people to use a more up-to-date Editor version. Fingers crossed!

    (and I have a workaround: for the most important case, I can create a different script for the highest-up parent, and use SOE as you guys suggested, because *in my case* the highest-up parent is always a special object anyway - although that wouldn't work on most projects)
     
  5. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,909
    Oh within a single component type? I've never experienced a use case for needing that to happen in a particular order. There's probably a way to rewrite your code so that it doesn't matter.

    Lazy-loaded properties are one of my go-to approaches.
     
  6. a436t4ataf

    a436t4ataf

    Joined:
    May 19, 2013
    Posts:
    1,933
    FYI the (simplified) use-case: "Replace OnEnable with OnEnableSelf and OnEnableInHierarchy"

    (where those methods are exactly the partners of Unitys ".activeSelf" and ".activeInHeirarchy", and are needed for the same reasons Unity had to replace .active with two different versions of .active -- enabling an object in Unity is not the same as 'your parent object got enabled', but the OnEnable method reports them identically).

    If Unity provides a guaranteed execution order for OnEnable and you have one of your components on every object in the scene then it's possible to implement the missing methods yourself (although it's weird that Unity hasn't provided them?). If Unity doesn't, or you don't want to spam your scene with components, then ... it's not possible.
     
  7. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,909
    This doesn't itself seem like a use-case, so much as a solution for yet another actual problem though, right?
     
  8. Ryiah

    Ryiah

    Joined:
    Oct 11, 2012
    Posts:
    21,147
    A custom manager that creates a list of the objects in the scene and executes functions on them in some order defined by the developer.
     
  9. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,836
    I would be flabbergasted if Unity guaranteed that multiple instances of the same class would have their events called in any particular order. They don't even try to call different classes in any particular order unless you specifically ask for it.

    You can always write your own manager script that calls whatever functions you want according to whatever rules you want, of course. (Which is what 99% of devs who need this would need to do anyway, because ordinarily if you need things to happen in a magic order, it's a magic order that Unity couldn't possibly guess.)


    It also sounds like you are confused about active vs. enabled. activeSelf and activeInHierarchy have to do with objects being active, which is a higher level of organization from behaviours being enabled ("enabled" is that checkbox on the individual component). There is in fact no magic method to detect either "activeSelf" or "activeInHierarchy".

    One reason for that is that "disabled" MEANS that magic methods are not called, so unless the script is "enabled in hierarchy" then it can't receive any events of any kind.

    But the main reason is that interfaces normally just tell you stuff that impacts you directly. That's how compartmentalization works. If you try to make every piece of code aware of everything else that's happening in the program at all times you just end up with one giant spaghetti class that controls everything. If there's a unique special reason that you care about one particular external thing, then you just have to write some custom code to deal with that particular thing.


    Of course, you could easily detect any combination of activeInHierarchy/activeSelf/enabled that you like by polling from some sort of always-active manager script.


    Or you could just do the standard OOP thing, and have whatever code is currently doing the enabling also explicitly call a method on the enabled object that tells it what you want it to do. Rather than having it try to guess from context.
     
  10. a436t4ataf

    a436t4ataf

    Joined:
    May 19, 2013
    Posts:
    1,933
    OnEnable/Disable are core callbacks from the Unity system - I literally don't have access to the Unity source code, there is no way I could possibly:

    The 'enabling' is usually done by a human, using the UnityEditor. If there is another callback for 'user has enabled or disabled a GO' then please point me at it! I would love to discover such a thing (I searched the docs for some time and could not find anything).

    Again: how? I don't have control of Unity's source code. How are you calling these methods, how are you detecting changes in state??

    You can 100% detect a deactivation of activeSelf, and a deactivation of activeInHierarchy. I've got a working code example, in one line of code. What I was struggling to do reliably was the opposite: detect activation of activeSelf vs activeInHierarchy. It is not unreasonable to expect to be able to do both.

    This is just ... not true. Sorry. Go test it.

    Well, yes, with that logic why doesn't Unity just delete all the "On..." methods - none of them are needed, everyone can poll everything! :)
     
  11. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,836
    ...you didn't specify you were doing editor scripting. I'm not familiar enough with run-in-edit-mode scripts to make any confident suggestions about how to make nontrivial stuff.

    Depending on your use-case, you could consider creating a custom inspector for your component, and managing their state through your own custom buttons instead of the built-in ones.

    You may want to consider answering PraetorBlue's question about your underlying goals, in order to maybe discover an alternate way of solving the root problem.