From e5f2c442c7bebed100e4fb305deefb31af0c94ce Mon Sep 17 00:00:00 2001 From: Juan Linietsky Date: Fri, 6 Jan 2023 16:08:36 +0100 Subject: [PATCH] Add SceneTree.unload_current_scene() Provides an obvious way to unload the currently loaded scene (which is nowhere to be found in the docs). The SceneTree.change_scene_to() method must now always provide a valid PackedScene. Fixes #63565. --- doc/classes/SceneTree.xml | 12 +++++++++--- scene/main/scene_tree.cpp | 18 +++++++++++++----- scene/main/scene_tree.h | 1 + 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/doc/classes/SceneTree.xml b/doc/classes/SceneTree.xml index bd5b656e1a3..bf19ebc23aa 100644 --- a/doc/classes/SceneTree.xml +++ b/doc/classes/SceneTree.xml @@ -42,15 +42,15 @@ Changes the running scene to the one at the given [param path], after loading it into a [PackedScene] and creating a new instance. Returns [constant OK] on success, [constant ERR_CANT_OPEN] if the [param path] cannot be loaded into a [PackedScene], or [constant ERR_CANT_CREATE] if that scene cannot be instantiated. - [b]Note:[/b] The scene change is deferred, which means that the new scene node is added on the next idle frame. You won't be able to access it immediately after the [method change_scene_to_file] call. + [b]Note:[/b] The scene change is deferred, which means that the new scene node is added on the next idle frame. This ensures that both scenes are never loaded at the same time, which can exhaust system resources if the scenes are too large or if running in a memory constrained environment. As such, you won't be able to access the loaded scene immediately after the [method change_scene_to_file] call. - Changes the running scene to a new instance of the given [PackedScene]. - Returns [constant OK] on success or [constant ERR_CANT_CREATE] if the scene cannot be instantiated. + Changes the running scene to a new instance of the given [PackedScene] (which must be valid). + Returns [constant OK] on success, [constant ERR_CANT_CREATE] if the scene cannot be instantiated, or [constant ERR_INVALID_PARAMETER] if the scene is invalid. [b]Note:[/b] The scene change is deferred, which means that the new scene node is added on the next idle frame. You won't be able to access it immediately after the [method change_scene_to_packed] call. @@ -209,6 +209,12 @@ Sets a custom [MultiplayerAPI] with the given [param root_path] (controlling also the relative subpaths), or override the default one if [param root_path] is empty. + + + + If a current scene is loaded, calling this method will unload it. + + diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp index 18253c6094c..51ba6c0473b 100644 --- a/scene/main/scene_tree.cpp +++ b/scene/main/scene_tree.cpp @@ -1131,11 +1131,11 @@ Error SceneTree::change_scene_to_file(const String &p_path) { } Error SceneTree::change_scene_to_packed(const Ref &p_scene) { - Node *new_scene = nullptr; - if (p_scene.is_valid()) { - new_scene = p_scene->instantiate(); - ERR_FAIL_COND_V(!new_scene, ERR_CANT_CREATE); - } + ERR_FAIL_COND_V_MSG(p_scene.is_null(), ERR_INVALID_PARAMETER, "Can't change to a null scene. Use unload_current_scene() if you wish to unload it."); + + Node *new_scene = p_scene->instantiate(); + new_scene = p_scene->instantiate(); + ERR_FAIL_COND_V(!new_scene, ERR_CANT_CREATE); call_deferred(SNAME("_change_scene"), new_scene); return OK; @@ -1147,6 +1147,13 @@ Error SceneTree::reload_current_scene() { return change_scene_to_file(fname); } +void SceneTree::unload_current_scene() { + if (current_scene) { + memdelete(current_scene); + current_scene = nullptr; + } +} + void SceneTree::add_current_scene(Node *p_current) { current_scene = p_current; root->add_child(p_current); @@ -1297,6 +1304,7 @@ void SceneTree::_bind_methods() { ClassDB::bind_method(D_METHOD("change_scene_to_packed", "packed_scene"), &SceneTree::change_scene_to_packed); ClassDB::bind_method(D_METHOD("reload_current_scene"), &SceneTree::reload_current_scene); + ClassDB::bind_method(D_METHOD("unload_current_scene"), &SceneTree::unload_current_scene); ClassDB::bind_method(D_METHOD("_change_scene"), &SceneTree::_change_scene); diff --git a/scene/main/scene_tree.h b/scene/main/scene_tree.h index 77cfe0a04a5..fc185b4f377 100644 --- a/scene/main/scene_tree.h +++ b/scene/main/scene_tree.h @@ -361,6 +361,7 @@ public: Error change_scene_to_file(const String &p_path); Error change_scene_to_packed(const Ref &p_scene); Error reload_current_scene(); + void unload_current_scene(); Ref create_timer(double p_delay_sec, bool p_process_always = true, bool p_process_in_physics = false, bool p_ignore_time_scale = false); Ref create_tween();