summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJuan Linietsky <reduzio@gmail.com>2023-01-06 16:08:36 +0100
committerJuan Linietsky <reduzio@gmail.com>2023-01-10 14:02:06 +0100
commite5f2c442c7bebed100e4fb305deefb31af0c94ce (patch)
treeae37202b355919c7ee975a296731b30cb062591a
parentb14f7aa9f92ff44135c283a9c88dab5ef9136d64 (diff)
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.
-rw-r--r--doc/classes/SceneTree.xml12
-rw-r--r--scene/main/scene_tree.cpp18
-rw-r--r--scene/main/scene_tree.h1
3 files changed, 23 insertions, 8 deletions
diff --git a/doc/classes/SceneTree.xml b/doc/classes/SceneTree.xml
index bd5b656e1a..bf19ebc23a 100644
--- a/doc/classes/SceneTree.xml
+++ b/doc/classes/SceneTree.xml
@@ -42,15 +42,15 @@
<description>
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.
</description>
</method>
<method name="change_scene_to_packed">
<return type="int" enum="Error" />
<param index="0" name="packed_scene" type="PackedScene" />
<description>
- 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.
</description>
</method>
@@ -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.
</description>
</method>
+ <method name="unload_current_scene">
+ <return type="void" />
+ <description>
+ If a current scene is loaded, calling this method will unload it.
+ </description>
+ </method>
</methods>
<members>
<member name="auto_accept_quit" type="bool" setter="set_auto_accept_quit" getter="is_auto_accept_quit" default="true">
diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp
index 18253c6094..51ba6c0473 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<PackedScene> &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 77cfe0a04a..fc185b4f37 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<PackedScene> &p_scene);
Error reload_current_scene();
+ void unload_current_scene();
Ref<SceneTreeTimer> create_timer(double p_delay_sec, bool p_process_always = true, bool p_process_in_physics = false, bool p_ignore_time_scale = false);
Ref<Tween> create_tween();