From a99174bfd1daba012312d927d4510034361b1a55 Mon Sep 17 00:00:00 2001 From: Cecilia Carter Date: Sat, 21 Sep 2024 19:28:55 -0400 Subject: [PATCH] fix bug where signals from scene instances are included in packed scenes --- core/object/object.h | 2 +- scene/resources/packed_scene.cpp | 15 ++++++-- tests/scene/test_packed_scene.h | 62 +++++++++++++++++++++++++++++++- 3 files changed, 74 insertions(+), 5 deletions(-) diff --git a/core/object/object.h b/core/object/object.h index 763e2974b9df..7f113ac941ed 100644 --- a/core/object/object.h +++ b/core/object/object.h @@ -572,7 +572,7 @@ class Object { CONNECT_PERSIST = 2, // hint for scene to save this connection CONNECT_ONE_SHOT = 4, CONNECT_REFERENCE_COUNTED = 8, - CONNECT_INHERITED = 16, // Used in editor builds. + CONNECT_INHERITED = 16, // Whether or not the connection is in an instance of a scene }; struct Connection { diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp index d6fe4385c47e..8003696694bc 100644 --- a/scene/resources/packed_scene.cpp +++ b/scene/resources/packed_scene.cpp @@ -1034,6 +1034,7 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Has } Error SceneState::_parse_connections(Node *p_owner, Node *p_node, HashMap &name_map, HashMap &variant_map, HashMap &node_map, HashMap &nodepath_map) { + // Ignore nodes that are within a scene instance if (p_node != p_owner && p_node->get_owner() && p_node->get_owner() != p_owner && !p_owner->is_editable_instance(p_node->get_owner())) { return OK; } @@ -1054,7 +1055,14 @@ Error SceneState::_parse_connections(Node *p_owner, Node *p_node, HashMapget_child_count(); i++) { - Node *c = p_node->get_child(i); - Error err = _parse_connections(p_owner, c, name_map, variant_map, node_map, nodepath_map); + Node *child = p_node->get_child(i); + Error err = _parse_connections(p_owner, child, name_map, variant_map, node_map, nodepath_map); if (err) { return err; } diff --git a/tests/scene/test_packed_scene.h b/tests/scene/test_packed_scene.h index 1e784c199da8..8dcb16298dc5 100644 --- a/tests/scene/test_packed_scene.h +++ b/tests/scene/test_packed_scene.h @@ -32,7 +32,6 @@ #define TEST_PACKED_SCENE_H #include "scene/resources/packed_scene.h" - #include "tests/test_macros.h" namespace TestPackedScene { @@ -56,6 +55,67 @@ TEST_CASE("[PackedScene] Pack Scene and Retrieve State") { memdelete(scene); } +TEST_CASE("[PackedScene] Test That Correct Signals are Preserved when Packing Scene") { + // Create main scene + // root + // `- sub_node (local) + // `- sub_scene (instance of another scene) + // `- sub_scene_node (owned by sub_scene) + Node *main_scene_root = memnew(Node); + Node *sub_node = memnew(Node); + Node *sub_scene_root = memnew(Node); + Node *sub_scene_node = memnew(Node); + + main_scene_root->add_child(sub_node); + sub_node->set_owner(main_scene_root); + + sub_scene_root->add_child(sub_scene_node); + sub_scene_node->set_owner(sub_scene_root); + + main_scene_root->add_child(sub_scene_root); + sub_scene_root->set_owner(main_scene_root); + + SUBCASE("Signals that should be saved") { + int main_flags = Object::CONNECT_PERSIST; + // sub node to a node in main scene + sub_node->connect("ready", callable_mp(main_scene_root, &Node::is_ready), main_flags); + // subscene root to a node in main scene + sub_scene_root->connect("ready", callable_mp(main_scene_root, &Node::is_ready), main_flags); + //subscene root to subscene root (connected within main scene) + sub_scene_root->connect("ready", callable_mp(sub_scene_root, &Node::is_ready), main_flags); + + // Pack the scene. + PackedScene packed_scene; + const Error err = packed_scene.pack(main_scene_root); + CHECK(err == OK); + + // Make sure the right connections are in packed scene + Ref state = packed_scene.get_state(); + CHECK_EQ(state->get_connection_count(), 3); + } + + SUBCASE("Signals that should not be saved") { + int subscene_flags = Object::CONNECT_PERSIST | Object::CONNECT_INHERITED; + // subscene node to itself + sub_scene_node->connect("ready", callable_mp(sub_scene_node, &Node::is_ready), subscene_flags); + // subscene node to subscene root + sub_scene_node->connect("ready", callable_mp(sub_scene_root, &Node::is_ready), subscene_flags); + //subscene root to subscene root (connected within sub scene) + sub_scene_root->connect("ready", callable_mp(sub_scene_root, &Node::is_ready), subscene_flags); + + // Pack the scene. + PackedScene packed_scene; + const Error err = packed_scene.pack(main_scene_root); + CHECK(err == OK); + + // Make sure the right connections are in packed scene + Ref state = packed_scene.get_state(); + CHECK_EQ(state->get_connection_count(), 0); + } + + memdelete(main_scene_root); +} + TEST_CASE("[PackedScene] Clear Packed Scene") { // Create a scene to pack. Node *scene = memnew(Node);