Script execution order: Awake not called first

I have a game manager script that controls a lot of various universal functions.
To make sure all my scripts have easy access to the Game Manager, I have a static reference to the instance of the script. Thus, everyone can call “GameManager.GM” to access any functions of the Game Manager.
To make sure it works, the Game Manager assigns this variable in its awake function.

This also means that many various functions CANNOT be called until AFTER awake has been called in the Game Manager.

I just added a such a function to a script that was called in its awake function, and found a bunch of errors because they were getting called before awake was called in the GM.
Well okay; I’ll just go into the Script execution Order in my Project Settings and make the Game Manager get called before default time.

Except I had already done that. The GameManager script is set to -95. But these other scripts are still calling awake before the GM. Which means that “Awake” is not affected by the Script Execution order.

Umm, what?
So how am I supposed to adjust the order that Awake gets called on scripts in my scene?

If anything I would have thought that at the very least the Game Manager might happen to get awakened first because it is one of the first objects in my scene, but nope, some of the newest objects I’ve put in my scene are getting awakened before the GM.

Any advice?

Try lazy-loading the reference to GameManager.GM. Let it be set to null by default and then create an instance of it once it’s referenced:

public class GameManager : MonoBehaviour
{
  private static GameManager _gm;

  public static GameManager GM
  {
    get {
      if(_gm == null)
      {
        GameObject gmObject = new GameObject("Game Manager");
        _gm = gmObject.AddComponent<GameManager>();
      }

      return _gm;
    }
  }
}

This way, GameManager is guaranteed to be instantiated whenever it’s referenced.

3 Likes

I like what you’re promising, but I don’t understand what is going on in this example.
And… is that code goin inside my list of variables? Not in a function, just… hanging out with the variables?

If you’re not familiar with C# properties, the above code is basically just a getter-method for a private field.
It can be written in typical OOP fashion like so:

private static GameManager _gm;

public static GameManger GetGM()
{
  return _gm;
}

And the C# property equivalent would be:

private static GameManager _gm;

public static GameManger GM
{
  get {
    return _gm;
  }
}

//Get-only properties can also just be shortened to this, if no additional get-logic is needed:
public static GameManager GM => _gm;

The additional logic in the getter-method is first checking if the private field is null, and if so, it will create a new instance before returning it:

private static GameManager _gm;

public static GameManger GetGM()
{
  //_gm is null by default - there is no existing GameManager in the scene until GetGM() is called for the first time.
  if(_gm == null)
  {
    GameObject gmObject = new GameObject("Game Manager");
    _gm = gmObject.AddComponent<GameManager>();
  }

  return _gm;
}

Now whenever another part of the application calls GameManager.GetGM(), the GetGM() method will handle instantiating a GameManager component before returning it, if it has not already been instantiated.

The original code is the same process, except instead of a getter-method, it’s a getter-property. The only real difference with that is instead of calling GameManager.GetGM(), you just call GameManager.GM.
Everything between the get { } block of code will execute whenever some part of the application is getting a reference to GameManager.GM.

You could also totally just use the traditional OOP getter-method if that’s what you prefer.

More about C# properties here:
https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/properties

It goes inside of the GameManger class scope, if that’s what you mean?

It’s not a prefab by any chance and also you don’t create it after the scene load, right? Those are known to cause similar effects. Awake’s first place is only guaranteed if the go loaded and activated with the scene (the very first scene obviously).

That just makes it all the more odd that something else got awake called first; the game manager is in the first and primary scene, while these other items are additional scenes that are open.
Now certainly, in the final version they could never be called first because they wouldn’t exist when the game first loads, wheras the Manager will. But I can’t test my game properly if I’m getting these other objects calling awake before the GM.

Maybe because they are in the “active scene” and that’s getting awakened before the main scene?

Yes, exactly. You can write a static method with RuntimeInitializeOnLoadMethod with BeforeSceneLoad loadType and load and activate your bootstrap scene to prevent this. That method should run before your current scene to reload.