code running after change_scene() still uses data from previous scene

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

From what I can find from googling, get_tree().change_scene(newScene) should pause execution of the code until the scene is changed, and then resume.

for example, this should work (root nodes of a scene belong to group “level”):
print(get_tree().get_nodes_in_group(“level”)[0].name)#prints out name of current level
get_tree().change_scene(newScenePath)
print(get_tree().get_nodes_in_group(“level”)[0].name) #prints out name of new loaded level

However, in my case it prints out the name of the old level both times. I looked up how to yield until scene is done changing, but everyone just says that get_scene() halts code anyways so you don’t need to. I’m really confused.

:bust_in_silhouette: Reply From: Zylann

gettree().changescene(newScene) should pause execution of the code until the scene is changed, and then resume.

It doesn’t pause anything. I wonder where you saw that, maybe that’s a misinterpretation?

I looked up how to yield until scene is done changing, but everyone just says that get_scene() halts code anyways so you don’t need to.

See how it’s implemented: https://github.com/godotengine/godot/blob/e2b66cacf78ae39b94df748e9740b98a1f011e77/scene/main/scene_tree.cpp#L1310

The change is deferred. Which means it won’t happen right away, but it will happen during idle time. So yeah, we could say it will happen at the end of the frame. But your script is not halted in any way, it continues and finishes the function.
Then once every script is done running, then it might happen.

It’s done in this way because when the change happens, it deletes all nodes from the scene. If it was doing it immediately, and if one of these nodes was the one that called change_scene(), then just after the call, that script and its node would be destroyed. Anything it does next, like getting the tree, would cause a crash (the script would “bite its own tail”).
So that’s why it is deferred, and why you should also not yield if you are in that situation.
See how the change is done: https://github.com/godotengine/godot/blob/e2b66cacf78ae39b94df748e9740b98a1f011e77/scene/main/scene_tree.cpp#L1281

Also, if the script doing change_scene is in an autoload, it won’t be part of the scene, but if it gets called to do so by a node or signal in the scene tree, the same risk occurs. However, you can yield there.