AddChild() to /root

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By slavi

How to attach the created node (stored in the “instance” variable) not to the current one (and not to its child nodes), but to the parent nodes and in particular to /root?

public partial class Inst : Node
{
    [Export] PackedScene prefab;
    public override void _Ready()
    {
        // var instance = prefab.Instantiate();
        Node3D instance = (Node3D)prefab.Instantiate(); //Here I use Node3D to be able to set the position
        GetTree().Root.AddChild(instance);
        instance.Position = new Vector3(1,1,0);
    }
}

The problem is that I only managed to attach to the current and child, any attempt to attach above ends with a runtime error.

At the moment, the scene structure is as follows:
-Node3D
–node [script inst]
—Node3D

The structure of the scene in the variable “prefab” (although I think it doesn’t really matter)
-StaticBody3D
–Sprite3D

These options work

AddChild(instance);
GetNode("/root/Node3D/Node/Node3D").AddChild(instance);
GetNode("/root/Node3D/Node").AddChild(instance);

These options don’t work

GetNode("/root").AddChild(instance);
GetNode("/root").AddChild((Node)instance);
GetParent().AddChild(instance);
GetTree().Root.AddChild(instance);

The main idea of these experiments that I want to achieve is to attach several scenes to the root. For example, start with the “Managers” scene and use it to load and unload scenes of the levels of the game world
-root
–Managers
–SomeLevelOfWorld1
–SomeLevelOfWorld2

GetTree().Root.AddChild(instance);

This is the way; there’s something else wrong with the script if this causes an error - debug it and find out (i.e. has the prefab been assigned a value?).

Using SceneTree — Godot Engine (stable) documentation in English

However, you’re essentially implementing godot Singletons (AutoLoad).

spaceyjase | 2023-03-30 10:51

Yes, the prefab is assigned, and it is created correctly if some other commands are used, for example “GetNode(”/root/Node3D/Node/Node3D").AddChild(instance);" or just “AddChild(instance);”

Perhaps I do not understand some nuances, or maybe the problem is on Godot’s side?

E 0:00:01:0628 Godot.NativeInterop.NativeFuncs.generated.cs:332 @ void Godot.NativeInterop.NativeFuncs.godotsharp_method_bind_ptrcall(IntPtr , IntPtr , System.Void** , System.Void* ): Parent node is busy setting up children, add_child() failed. Consider using add_child.call_deferred(child) instead.
<C++ Error> Condition “data.blocked > 0” is true.
<C++ Source> scene/main/node.cpp:1136 @ add_child()
Godot.NativeInterop.NativeFuncs.generated.cs:332 @ void Godot.NativeInterop.NativeFuncs.godotsharp_method_bind_ptrcall(IntPtr , IntPtr , System.Void** , System.Void* )
NativeCalls.cs:5859 @ void Godot.NativeCalls.godot_icall_3_655(IntPtr , IntPtr , IntPtr , Godot.NativeInterop.godot_bool , Int32 )
Node.cs:582 @ void Godot.Node.AddChild(Godot.Node , Boolean , Godot.Node+InternalMode )
Inst.cs:14 @ void Inst._Ready()
Node.cs:1783 @ Boolean Godot.Node.InvokeGodotClassMethod(Godot.NativeInterop.godot_string_name& , Godot.NativeInterop.NativeVariantPtrArgs , Godot.NativeInterop.godot_variant& )
Inst_ScriptMethods.generated.cs:31 @ Boolean Inst.InvokeGodotClassMethod(Godot.NativeInterop.godot_string_name& , Godot.NativeInterop.NativeVariantPtrArgs , Godot.NativeInterop.godot_variant& )
CSharpInstanceBridge.cs:24 @ Godot.NativeInterop.godot_bool Godot.Bridge.CSharpInstanceBridge.Call(IntPtr , Godot.NativeInterop.godot_string_name* , Godot.NativeInterop.godot_variant** , Int32 , Godot.NativeInterop.godot_variant_call_error* , Godot.NativeInterop.godot_variant* )

slavi | 2023-03-31 03:26

Parent node is busy setting up children, add_child() failed

Perhaps this isn’t allowed in Ready as the scene tree is still busy (I do the same but not in Ready, only when required). The other references that work are to different nodes. Using deferred, as answered by the other poster, pushes this back until the next frame that likely means the node is no longer busy.

spaceyjase | 2023-03-31 07:26

I did a little experiment, created a script and attached it to all nodes

public override void _Ready()
{
    GD.Print("READY" + Name);
}

And I found out that if a year has children, then the Ready method of each of its children is executed first, and only then the Ready of the node itself is executed.

So “root” is loaded last?

And the moment that I don’t understand: the node doesn’t exist yet until its Ready method is executed?

slavi | 2023-04-02 08:10

This might help: Using SceneTree — Godot Engine (stable) documentation in English

I suspect that Root is iterating its children so adding another child is probably the engine being sensible (bad things usually happen if a loop is modified while in use), although I haven’t checked the source.

spaceyjase | 2023-04-02 08:16

:bust_in_silhouette: Reply From: GlitchedCode

You can go up to your project settings and into the Autoload tab. From here of course you can load scripts, but you can also use a full scene here. Adding a scene here will attach it to the root.

If you absolutely need to add a scene to the root and don’t want to have it loaded as an autoload, here is how we can add an instance of a scene to the root window/node.

var scene = load("res://MyManager.tscn")
var si = scene.instantiate()
get_window().add_child.call_deferred(si)

enter image description here

Thanks for your reply!
I write in C# and this command did not work for me in this form

GetWindow().AddChild.CallDeferred(instance)

But it works like this

GetWindow().CallDeferred("add_child", instance);

slavi | 2023-03-31 03:51

Right, my bad xD completely overlooked the C# part lol afterawhile its just all the same to me xD.

GlitchedCode | 2023-03-31 05:37