Two alternative activity diagrams

DevBlog: Back to the Execution Order Pit

My article on script execution order in Unity’s UNet networking layer is my most successful article. It is 6 years old now and still being clicked regularly, more often than most others. No small wonder, as I had to find out yet again. Fixing a bug in Network Traders, I fell into almost the same trap, again! Always be aware of event execution order! And continue reading if you want to know why!

Standard appearance of the network screen in Network Traders.
The network screen, as it should be.

So what happened? One of the screens of Network Traders shows a graph with all cities known to the player. In the center, there is the player’s own city, and grouped around it are the cities her merchants have already visited. Since this network can become arbitrarily complex, the screen can be zoomed and scrolled. This worked great during testing with the Unity editor. But when deployed on an Android smartphone, something unexpected happened. The scaling of the central city was totally off, as you can see below.

Execution Order of Awake and OnEnable

Bug in Network Traders because of script execution order problems.
Broken scaling of objects on the network screen.

The reason for this unwanted behavior may be a, let’s say, less than optimal class architecture, but very instructive nonetheless. The class which is responsible for zooming the screen, TradeNetworkScaler, is a Unity component placed on the same GameObject as the screen manager class itself, TradeNetworkView. In Awake, the “Scaler” registers itself with the “View” object:

  private void Awake()
  {
    tradeNetwork = GetComponent<TradeNetworkView>();

    tradeNetwork.OnNetworkViewEnabling += OnNetworkViewEnable;
  }

The callback OnNetworkViewEnabling is in turn called in OnEnable of TradeNetworkView.

So, what’s the problem? The respective Unity documentation on event execution order shows it, but I would not have seen it at first glance. Do you?

Screenshot from Unity Manual showing event execution order.
Initial steps of event execution. (Screenshot: Unity Manual)

Neither is the description of Awake and OnEnable clear enough to explain what happens. It says:

  • Awake: This function is always called before any Start functions and also just after a prefab is instantiated. (If a GameObject is inactive during start up Awake is not called until it is made active.)
  • OnEnable: (only called if the Object is active): This function is called just after the object is enabled. This happens when a MonoBehaviour instance is created, such as when a level is loaded or a GameObject with the script component is instantiated.

It does not mention what the catch is here: Awake and OnEnable both happen during the Initialization step! This means that while OnEnable follows Awake, this is only true for one object. It does not state that all Awakes are processed before any OnEnable, and neither is that the case. As a result, the sequence of Awake and OnEnable of two different objects is arbitrary, as in my case. In the editor, TradeNetworkScaler was handled before TradeNetworkView. On an Android device it was the other way around. This broke the system.

Execution Order Settings to the Rescue

Fortunately, Unity offers a remedy, although I would not recommend over-using it. The project settings contain a section Script Execution Order where you can tell Unity how to handle this.

Script Execution Order window in Unity Editor.
Set the script execution order manually in the settings window. (Screenshot: Unity Editor)

By adjusting the execution order of different Awakes and OnEnables manually, I was able to make sure that the TradeNetworkScaler always precedes TradeNetworkView. As I said before, not an elegant solution. But I hope it helps you in case you struggle with a similar problem.

So, now that you’ve read so far, tell me in the comments why you are here! Do you have a similar problem, and did this help you? Or did you look for something entirely different?

0 0 votes
Article Rating
Abonnieren
Benachrichtige mich bei
0 Comments
Inline Feedbacks
View all comments
0
Was denkst Du? Bitte hinterlasse einen Kommentar!x