Clashing namespaces when loading scenes

Godot Version

4.4

Question

I’m running into an issue where it looks like ResourceLoader is automatically adding nodes into the scene tree after it’s finished loading, instead of waiting until I manually add the child to the tree.

func monitor_load_status() -> void:
	var progress = []
	var load_status = ResourceLoader.load_threaded_get_status(next_scene, progress)
	
	match load_status:
        <...>
		ResourceLoader.THREAD_LOAD_LOADED:
			scene_finished_loading.emit(ResourceLoader.load_threaded_get(next_scene).instantiate())

When the thread is loaded, a signal is emitted calling next_scene_loaded() that then adds the new scene to the CurrentScene node after all the child nodes have been deleted.

func next_scene_loaded(new_scene) -> void:
	await clear_current_scene()
	current_scene.call_deferred("add_child", new_scene)
	
func clear_current_scene() -> void:
	for child in current_scene.get_children():
		child.queue_free()

The problem here is that every other time this method is called to load a scene the name at the root of the scene is wrong (because it already exists, and Godot automatically creates a temporary name for the node).

The solution here is to clear the current scene even before the thread attempts to load which is fine, but is this expected behavior where the resource loader is adding things to the scene tree (or at the least causing naming clashes) prior to it actually being added as a child?

This also adds a wrinkle, where I want the game to stay on the previous screen prior to loading the new one for as long as possible, to prevent a jarring transition.

ResourceLoader does not add anything to the SceneTree it just loads a resource.

This await does nothing because the function isn’t async.

Both queue_free() queues the deletion of the node at the end of the frame and call_deferred() delays the execution of the method to the end of the frame.

The reason call_deferred() is called before deleting nodes is to prevent executing methods on deleted objects. In your case, this results in adding the new_scene before freeing the children of the current_scene.

Try to not use the name of the nodes for anything as the engine can change them as needed.

Interesting to learn about how queue_free() and call_deferred(). If I know that what will be deleted will not interact with whatever is being executed in call_deferred() is there some way to make the queue_free() execute before the deferred call? Is there some way to ensure that the call deferred happens on the next frame?

As for the naming issue I was writing the path to certain nodes but realized using signals and groups ends up being easier to mass update things like UI elements with game events occur :+1:.

There’s Object.free() but I’d not recommend it with nodes as there may have pending signals or method calls that will result on an runtime error.

call_deferred() delays the execution to the end of the frame. If you want to do something the next frame maybe awaiting for the next process frame like this may work:

await get_tree().process_frame
do_something()