Repository: godot
Issue: Mainloop is being created and initialized after main scene and singletons
Labels: bug,topic:core

### Godot version

4.0.dev (14fdd28de9f1f9979cb6cffa4b715a16d406439d)

### 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 https://github.com/godotengine/godot/pull/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](https://github.com/godotengine/godot/files/10461192/test_init_order.zip)