The attached project consists of 3 scripts: “Early” with execution order -10, “Late” with execution order 10 and “Normal” with default execution order.
When entering play mode, OnEnable gets called in the correct order: Early => Normal => Late.
When exiting play mode, OnDisable gets called in the wrong order: Normal => Late => Early. It follows the order of the components in the GameObject instead of the script execution order.
This happens both in Unity 2022.2.16 and Unity 2022.2.15.
Am I doing something wrong? Or does OnDisable generally not follow script execution order? Advice is appreciated.
What are you doing that requires a specific execution order? Ideally, you should not have to rely on this at all except in situations where you need to hack in a quick fix.
Thanks for chiming in, Spiney! Let’s keep this thread focused on the expected behavior of OnDisable for now. Once we have confirmation that OnDisable doesn’t follow the execution order, I’d love to get your input on what to do for my specific scenario
Good question! I added this line to the OnEnable() method of the “Late” script:
SceneManager.LoadScene(“Scene2”, LoadSceneMode.Single);
(“Scene2” is an empty scene)
Result of entering play mode from the scene containing an instance of each component:
OnEnable calls: Early => Normal => Late (correct)
OnDisable calls: Normal => Late => Early (same incorrect order as exiting play mode without loading Scene2)
It doesn’t do that for me either in my test project and the documentation doesn’t specify that OnDisabled doesn’t observe the execution order so I submitted a bug report: IN-40397.
What exactly are you trying to achieve, maybe we can provide some workaround for you.
I’m relying on the the component order as a workaround, though I’m sure this will come and haunt me later.
How do folks generally handle cross scene references when working with Unity Timeline (eg: assigning an animator in different scene to an animation track)? Just keep everything in 1 scene? Use a 3rd party tool? Write a custom reference manager? Some other magic solution I’m not aware of?
In my case I’ve always written code with the expectation that the components will execute in a random order and as a result have never used manual script execution order for my own code. For code that needed to fire in a specific order it was always easiest (and guaranteed to work) to make a script that was responsible for it.
I’m not sure why you need the Script Execution Order, but in general, relying on it is a big mess. It shows you have strong coupling between classes which you shouldn’t have. C# is a garbage-collected language, you don’t pay attention to wind-down properly most of the time. When you have this kind of dependency you either have the problem I mentioned above or you’re doing something really-really specific, which not many people do. This is why it went this long without noticing: not enough people doing this kind of things, because it’s a bad way of doing things, so no one raised it as an error.
Thanks for the insights! I’m trying to implement the following logic in component A:
“Make sure component B stays disabled till some other scene loads and the reference its looking for is available”.
Component B is built-in and I have no control over its implementation. I’m struggling to find a solution that doesn’t involve ensuring that Component A runs before component B.
Only if it weren’t handling all of them, and even then only if it actually mattered.
Are you unable to disable the component in the editor? Because if it can start off disabled I would just have it turned on when the time is appropriate.
That’s right. I did consider keeping all GameObjects disabled by default so I can have more control over their initialization, but it felt like quite a bit of hassle:
I can’t keep them all disabled during editing since I need to edit them.
Turning them on and off manually when editing is tedious.
Writing a tool that automates disabling all GameObjects when entering play mode and on game builds feels like a lot of work.
Would you say that something like applying IK should also not rely on script execution order?
You never need to use such mechanisms, imo. Like everybody says you simply don’t make your systems that fragile to rely on arbitrary ordering: whether its the execution order or the hierarchy (edit: breadth, not depth). If you need something in order, manage that order yourself.
The only time I have seen execution order being used (or have used it myself) is when there is some scene-wide overarching initialization object whose Awake needs to kick-in earlier than everyone else’s. Practically EarlyAwake. But that’s a relativistic use (i.e. keep X in front of everything), not order-like.
Edit: I forgot to add that I haven’t done this in a while, it’s sort of a design smell, unless it’s a very well documented/self-evident behavior and/or the project/scene is sufficiently light. So even though it sounds like I agree with this kind of set up (and I might in certain special situations), it’s still completely avoidable.