Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mainloop is being created and initialized after main scene and singletons #71695

Open
RedwanFox opened this issue Jan 19, 2023 · 5 comments · Fixed by #72248
Open

Mainloop is being created and initialized after main scene and singletons #71695

RedwanFox opened this issue Jan 19, 2023 · 5 comments · Fixed by #72248

Comments

@RedwanFox
Copy link
Contributor

Godot version

4.0.dev (14fdd28)

System information

Windows 11

Issue description

Experimenting with nodes initialization order, I have found something strange.

I have sample hierarchy like this:

Mainloop # custom
    Singleton
    Singleton2
    Node2D # main scene root node
        Node2D_2

Every node prints its status upon construction, being ready, and entering and exiting tree. For Mainloop it's construction, initialization and finalization

I have expected order like this:

# init
Mainloop constructed and initialized
    Singleton constructed, entered tree, ready
    Singleton2 constructed, entered tree, ready
    Node2D constructed, entered tree
         Node2D constructed, entered tree, ready
    Node2D ready

# and then deinit in reverse order

    Node2D_2 exited tree
    Node2D exited tree
    Singleton2 exited tree
    Singleton exited tree
MainLoop finalized

Real order imho is broken (output from my test project attached to ticket):

singleton _init obj: (name: null, id: 26658997261)
singleton _init obj: (name: null, id: 26709329027)
node _init obj: (name: null, id: 27279754254)
    scenetree is  obj: null                     <------- 0.
node _init obj: (name: null, id: 27296531439)
    scenetree is  obj: null
singleton _enter_tree obj: (name: Singleton, id: 26658997261)
singleton _enter_tree obj: (name: Singleton2, id: 26709329027)
node _enter_tree obj: (name: Node2D, id: 27279754254)
node _enter_tree obj: (name: Node2D_2, id: 27296531439)
singleton _ready obj: (name: Singleton, id: 26658997261)    <--------- 1.
singleton _ready obj: (name: Singleton2, id: 26709329027)
node _ready obj: (name: Node2D_2, id: 27296531439)
node _ready obj: (name: Node2D, id: 27279754254)
mainloop _init obj: (name: <null>, id: 25954354228)  <------- 2.
mainloop _initialize obj: (name: <null>, id: 25954354228)
mainloop _finalize obj: (name: <null>, id: 25954354228)
node _exit_tree obj: (name: Node2D_2, id: 27296531439)
    scenetree is  obj: (name: <null>, id: 25954354228)
node _exit_tree obj: (name: Node2D, id: 27279754254)
    scenetree is  obj: (name: <null>, id: 25954354228)
singleton _exit_tree obj: (name: Singleton2, id: 26709329027)
singleton _exit_tree obj: (name: Singleton, id: 26658997261)

(0.) during init of first frame custom mainloop is not initialized yet (related problem is fixed here #70771, and discussion in ticket led to this experiment)

(1.) Singletons while being slightly glorified nodes break tree initialization order : they enter tree before root scene node and are expected to be ready before it (because they are siblings), but in reality "singleton enters tree, node enters tree, singleton becomes ready, node becomes ready".

(2.). And mainloop is only created and becomes initialized after all nodes, and also is destroyed before final destruction of tree, while nominally being a container for all nodes. Such behavior diminishes it's usefulness, because user can't count on custom mainloop for early initialization checks (cli arguments, hardware, etc) or final cleanups. (Ok they can be set in very first singleton in list, but it's too easy to break their order).

More to this: Nodes of very first scene expect to have tree available at any moment. I have tried accessing mainloop from Node2D._ready. This leads to change in initialization order!

Like this

mainloop _init obj: (name: <null>, id: 25954353607)
singleton _init obj: (name: null, id: 26692551073)
singleton _init obj: (name: null, id: 26742882840)
node _init obj: (name: null, id: 27346862499)
    scenetree is  obj: null
node _init obj: (name: null, id: 27363639707)
    scenetree is  obj: null
singleton _enter_tree obj: (name: Singleton, id: 26692551073)
singleton _enter_tree obj: (name: Singleton2, id: 26742882840)
node _enter_tree obj: (name: Node2D, id: 27346862499)
node _enter_tree obj: (name: Node2D_2, id: 27363639707)
singleton _ready obj: (name: Singleton, id: 26692551073)
    scenetree is  obj: (name: <null>, id: 25954353607)
singleton _ready obj: (name: Singleton2, id: 26742882840)
    scenetree is  obj: (name: <null>, id: 25954353607)
node _ready obj: (name: Node2D_2, id: 27363639707)
node _ready obj: (name: Node2D, id: 27346862499)
mainloop _initialize obj: (name: <null>, id: 25954353607)
mainloop _finalize obj: (name: <null>, id: 25954353607)
node _exit_tree obj: (name: Node2D_2, id: 27363639707)
    scenetree is  obj: (name: <null>, id: 25954353607)
node _exit_tree obj: (name: Node2D, id: 27346862499)
    scenetree is  obj: (name: <null>, id: 25954353607)
singleton _exit_tree obj: (name: Singleton2, id: 26742882840)
singleton _exit_tree obj: (name: Singleton, id: 26692551073)

Mainloop becomes constructed before everything else, and during first scene initialization nodes get access to half-baked mainloop, while it's init completion and finalization stay where they very.

My question is are (1.) and (2.) bugs or such behavior has some purpose?

Steps to reproduce

  1. Run reproduction project from console. Running from editor skips deinit steps.
  2. See init order
  3. Go to Node2D.gd _ready (or Singleton.gd _ready) and uncomment print
  4. Run reproduction project again
  5. See another init order

Minimal reproduction project

test_init_order.zip

@RedwanFox
Copy link
Contributor Author

Same behavior in Godot 3.5.1 stable. But GameLoop._init isn't flaky and always called after first scene ready.

@RedwanFox
Copy link
Contributor Author

RedwanFox commented Jan 28, 2023

From documentation https://docs.godotengine.org/en/latest/classes/class_node.html

This means that when adding a node to the scene tree, the following order will be used for the callbacks: _enter_tree of the parent, _enter_tree of the children, _ready of the children and finally _ready of the parent (recursively for the entire scene tree).

It seems I was wrong in original message. And singleton init order is correct right now. But anyways singletons should be initialized completely before all other nodes. because as main_loop they must be accessed at any time by normal modes.
I'll add experimental pull request.

UPD: #72266

@YuriSizov
Copy link
Contributor

This was actually only partially addressed by the linked PR.

@akien-mga
Copy link
Member

What part of the issue is still relevant after #72248?

@RedwanFox
Copy link
Contributor Author

@akien-mga Singletons initialization is not split from other nodes. I've made another pull request (closed now) for discussion #72266 , you can read more of problem in description

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants