-
-
Notifications
You must be signed in to change notification settings - Fork 21.4k
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
get_tree() returning null immediately after calling change_scene_to_file() in _process or _physics_process() #85251
Comments
Confirmed in both 4.2-rc1 and fa4a653, it's a regression in 4.2. It started in 4.2-dev2. Presumably a regression from #78988. #85184 didn't solve that part. |
Different possibilities here: |
I tested the two linked issues, and they seem to highlight different problems, only one of which was fixed by #78988. The MRP in #78788 seems fixed for me, i.e. scene changing no longer causes the #70910 on the other hand is more complex, it's a problem that could be triggered by changing scenes (as seen in #78788), but not only. It seems to be a more general issue with removing/adding children. The recent MRP in #70910 (comment) still triggers an issue as of 4.2-rc1, even worse than in 4.1.3-stable for me (in 4.1.3 it spams errors, in 4.2-rc1 it segfaults). Overall #78988 did not address the main issue which is a difference in behavior between So #78988 might have made things better in some cases, but not solved the root of the problem. So maybe a revert for now is the better approach, to re-assess for 4.3. On the other hand If we keep the change as is (scenario (b)), we would need to document this behavior clearly, advising to yield for a frame before accessing the scene tree after changing scene. Edit: Notably, this bug doesn't seem too critical / game breaking. To be clear, the behavior in 4.1.3 would be that So a combination of (b) and maybe (c) to avoid getting a runtime error could be nice. But it's a bit worrying that we're only discovering this regression at 4.2-rc1 for a change merged in 4.2-dev2... so it might well need a bit more time to cook given the impact it can have on projects. |
Worth noting that the same "bug" can be reproduced in 4.1.3-stable with this: print(get_tree())
get_parent().remove_child(self)
print(get_tree()) And something like this doesn't execute the second print at all: print(get_tree())
get_tree().change_scene_to_file("res://scene2.tscn")
await get_tree().process_frame
print(get_tree()) So the change in assumption here is that IMO documenting this as an intentional change is enough for 4.2. |
So to reiterate, as of 4.2 calls to change the current scene are processed immediate and the node which you are replacing is removed immediately. This is consistent with other types of tree manipulation, like adding and removing children yourself, as illustrated above. Calling Prior to 4.2 the change would only be processed at the end of the frame, so the node would remain in the tree. I would say, you should not rely on this behavior in general. This is not the case with any other method of tree/child manipulation. The engine may defer some steps internally for performance or logical reasons, but you should always consider the node as detached after you requested it to be so. Store a tree reference before replacing the node if you need it afterwards. Or better yet, this should probably be called outside of the node being replaced. From an autoload perhaps. |
@YuriSizov It that's the case, it is a rather big change in respect to all other previous versions where changing the scene was considered a deferred call (stated explicitly in docs). Although I think it's better for scene change to take effect "immediately" it may fundamentally break many people's existing code. If this is intentional design choice, it should be prominently highlighted on "what's new" page. |
@nenad-jalsovec We'll see how big it is, I guess. So far this is the first report on this matter, and I'm not sure people who use such a high level method consider low level implications of it being a deferred call or not. I have no problem listing it among breaking changes in the release article. |
@YuriSizov I'm reporting this after trying to help a forum user with a scene swapping related problem. Because of this change the approach to solve it would differ rather significantly between 4.1 and 4.2. |
Feel free to post the exact problem if you want to discuss it. But from your simplified example the changes would be minimal. Although as I mentioned before, calling for a change of scene from the scene that is going to be changed away — that always has been a bad idea in my opinion. |
I'd agree that the exact timing of methods which do not have specific timing declared is an implementation detail, and not compatibility enforcing Further anything that changes things like this should in my opinion be seen as "no use beyond this point", similar with |
@YuriSizov I'll describe the specific situation here if you don't mind. I made initial trivial reproduction example under assumption that the scene change is deferred. |
This comment was marked as outdated.
This comment was marked as outdated.
Are you saying that |
@YuriSizov Oops, I was wrong there. The autoload works fine. Can you then 100% confirm that this change in |
@nenad-jalsovec Yes, the change to the timing is done intentionally and is a core part of the fix. We will mention the difference in behavior introduced by it in the release article. |
@YuriSizov It'd also be good to remove the following paragraph from the SceneTree reference page in docs: Note: The new scene node is added to the tree at the end of the frame. This ensures that both scenes aren't running at the same time, while still freeing the previous scene in a safe way similar to Node.queue_free(). As such, you won't be able to access the loaded scene immediately after the change_scene_to_file() call. |
This can be closed I guess. Thanks for the quick response guys 👍 |
This should still be documented, please leave open until resolved |
I think that paragraph is still true. The docs fix would consist in adding some info about the fate of the current scene, wouldn't it? |
Yes, good point. What is mentioned in this note is still true, but we should probably mention the current/leaving scene and its fate explicitly. |
@YuriSizov Hm, yes. Also what happens with the loaded scene? If querying |
That's what the note you quoted says, yes.
The current scene is removed as soon as possible so everything can finish processing gracefully and without overlapping with the incoming scene. |
Isn't that precisely what's already accomplished by doing it deferred, but without losing the access to current scene until the end of current frame? |
I believe I may have tripped over this issue (or something adjacent to it) when I was converting a project from Godot3 to Godot4 a few weeks ago. I had some code in I "fixed" it by just reversing the order of operations, but can confirm that putting it back the old way still crashes in 4.2. If this was indeed related, then updating the documentation to just warn against |
Godot version
v4.2.beta4.official [93cdacb]
System information
Windows 10
Issue description
get_tree()
returns null when called immediately after callingchange_scene_to_file()
in_process()
or_physics_process()
. The error printed in debugger:scene1.gd:14 @ _process(): Parameter "data.tree" is null.
Regardless of this the scene gets properly changed.Doing the same from
_ready()
works as expected.Steps to reproduce
Make a scene with a node and another test scene to change to. Attach the following script to the node in the first scene:
Press enter and the output will be:
Minimal reproduction project
N/A
The text was updated successfully, but these errors were encountered: