diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp index 3059ce445c24..160581e617b8 100644 --- a/editor/editor_data.cpp +++ b/editor/editor_data.cpp @@ -635,7 +635,10 @@ bool EditorData::check_and_update_scene(int p_idx) { HashSet checked_scenes; - bool must_reload = _find_updated_instances(edited_scene[p_idx].root, edited_scene[p_idx].root, checked_scenes); + //_find_updated_instances() only detects changes in direct inherited scenes + //if the edited scene has inherited_nodes stored it means that an ancestor scene was saved and the current edited scene hasn't been reloaded since then + bool base_scene_updated = edited_scene[p_idx].root->get_scene_inherited_state().is_valid() && edited_scene[p_idx].inherited_nodes.size() > 0; + bool must_reload = _find_updated_instances(edited_scene[p_idx].root, edited_scene[p_idx].root, checked_scenes) || base_scene_updated; if (must_reload) { Ref pscene; @@ -644,6 +647,7 @@ bool EditorData::check_and_update_scene(int p_idx) { EditorProgress ep("update_scene", TTR("Updating Scene"), 2); ep.step(TTR("Storing local changes..."), 0); // Pack first, so it stores diffs to previous version of saved scene. + pscene->get_state()->set_inherited_nodes(edited_scene[p_idx].inherited_nodes); //tell the packed scene which nodes are inherited Error err = pscene->pack(edited_scene[p_idx].root); ERR_FAIL_COND_V(err != OK, false); ep.step(TTR("Updating scene..."), 1); @@ -669,6 +673,9 @@ bool EditorData::check_and_update_scene(int p_idx) { } edited_scene.write[p_idx].selection = new_selection; + //information no longer needed, if kept, the editor won't add nodes of the same name as the ones deleted in an ancestor scene + clear_edited_scene_inherited_nodes(p_idx); + return true; } @@ -877,6 +884,35 @@ void EditorData::clear_edited_scenes() { edited_scene.clear(); } +void EditorData::update_edited_scene_inherited_nodes(int p_edited_scene) { + //adds to the set of inherited nodes of the edited_scene specified by p_edited_scene + //helps correctly updating sub-inherited scenes + //the function is currently called when a scene is saved + if (p_edited_scene >= edited_scene.size()) { + return; + } + EditedScene es = edited_scene.get(p_edited_scene); + es.inherited_nodes.insert(NodePath(".")); //store something even if there are no inherited nodes to indicate scene save + Ref inherited_state = es.root->get_scene_inherited_state(); + while (inherited_state.is_valid()) { + for (int i = 1; i < inherited_state->get_node_count(); i++) { + es.inherited_nodes.insert(inherited_state->get_node_path(i)); + } + inherited_state = inherited_state->get_base_scene_state(); + } + edited_scene.set(p_edited_scene, es); +} + +void EditorData::clear_edited_scene_inherited_nodes(int p_edited_scene) { + //this function is called after the edited scene is updated, as it no longer needs the information on which nodes are inherited + if (p_edited_scene >= edited_scene.size()) { + return; + } + EditedScene es = edited_scene.get(p_edited_scene); + es.inherited_nodes.clear(); + edited_scene.set(p_edited_scene, es); +} + void EditorData::set_plugin_window_layout(Ref p_layout) { for (int i = 0; i < editor_plugins.size(); i++) { editor_plugins[i]->set_window_layout(p_layout); diff --git a/editor/editor_data.h b/editor/editor_data.h index d00501280d00..32dec31375e1 100644 --- a/editor/editor_data.h +++ b/editor/editor_data.h @@ -120,6 +120,7 @@ class EditorData { NodePath live_edit_root; int history_id = 0; uint64_t last_checked_version = 0; + HashSet inherited_nodes; }; private: @@ -196,6 +197,8 @@ class EditorData { Node *get_edited_scene_root(int p_idx = -1); int get_edited_scene_count() const; Vector get_edited_scenes() const; + void update_edited_scene_inherited_nodes(int p_edited_scene); + void clear_edited_scene_inherited_nodes(int p_edited_scene); String get_scene_title(int p_idx, bool p_always_strip_extension = false) const; String get_scene_path(int p_idx) const; String get_scene_type(int p_idx) const; diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 3555caac8acd..eb38dff50c6d 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -1743,6 +1743,24 @@ void EditorNode::_save_scene(String p_file, int idx) { _set_scene_metadata(p_file, idx); + //tell (sub)inherited edited scenes to keep track of nodes inherited + //the states are still in their old versions, this allows for knowing which nodes were deleted when updating an inherited scene + for (int i = 0; i < editor_data.get_edited_scene_count(); i++) { + //only update for edited scenes that has just been reloaded to avoid issues when saving more than once + if (editor_data.get_edited_scenes()[i].inherited_nodes.size() > 0) { + continue; + } + Ref ss = editor_data.get_edited_scene_root(i)->get_scene_inherited_state(); + //update for edited scenes that inherit the saved scene + while (ss.is_valid()) { + if (ss->get_path() == p_file) { + editor_data.update_edited_scene_inherited_nodes(i); + break; + } + ss = ss->get_base_scene_state(); + } + } + Ref sdata; if (ResourceCache::has(p_file)) { @@ -3718,6 +3736,7 @@ bool EditorNode::is_changing_scene() const { } void EditorNode::set_current_scene(int p_idx) { + HashSet checked_scenes; // Save the folding in case the scene gets reloaded. if (editor_data.get_scene_path(p_idx) != "" && editor_data.get_edited_scene_root(p_idx)) { editor_folding.save_scene_folding(editor_data.get_edited_scene_root(p_idx), editor_data.get_scene_path(p_idx)); diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp index 1e9038139e71..d8997163bf34 100644 --- a/scene/resources/packed_scene.cpp +++ b/scene/resources/packed_scene.cpp @@ -549,7 +549,18 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Has // and only save what has changed bool instantiated_by_owner = false; + //the following line doesn't deal with nodes in sub-inherited scenes Vector states_stack = PropertyUtils::get_node_states_stack(p_node, p_owner, &instantiated_by_owner); + //below fixes above issue so sub-inherited scenes can update properly after changes in ancestor scenes + bool node_inherited = false; + if (p_node != p_owner) { + for (HashSet::Iterator E = inherited_nodes.begin(); E; ++E) { + if (String(*E) == "./" + String(p_owner->get_path_to(p_node))) { + node_inherited = true; //so save_node becomes false + break; + } + } + } if (!p_node->get_scene_file_path().is_empty() && p_node->get_owner() == p_owner && instantiated_by_owner) { if (p_node->get_scene_instance_load_placeholder()) { @@ -696,8 +707,9 @@ Error SceneState::_parse_node(Node *p_owner, Node *p_node, int p_parent_idx, Has // that hold changes bool save_node = nd.properties.size() || nd.groups.size(); // some local properties or groups exist - save_node = save_node || p_node == p_owner; // owner is always saved save_node = save_node || (p_node->get_owner() == p_owner && instantiated_by_owner); //part of scene and not instanced + save_node = save_node && !node_inherited; //even if local properties exist, if the node is inherited, it should not be saved + save_node = save_node || p_node == p_owner; // owner is always saved int idx = nodes.size(); int parent_node = NO_PARENT_SAVED; diff --git a/scene/resources/packed_scene.h b/scene/resources/packed_scene.h index 5c53ffdb4567..06a50d74adab 100644 --- a/scene/resources/packed_scene.h +++ b/scene/resources/packed_scene.h @@ -43,6 +43,7 @@ class SceneState : public RefCounted { Vector editable_instances; mutable HashMap node_path_cache; mutable HashMap base_scene_node_remap; + HashSet inherited_nodes; int base_scene_idx = -1; @@ -183,6 +184,9 @@ class SceneState : public RefCounted { Vector get_editable_instances() const; + void set_inherited_nodes(HashSet p_inherited_node_paths) { inherited_nodes = p_inherited_node_paths; } + HashSet get_inherited_nodes() const { return inherited_nodes; } + //build API int add_name(const StringName &p_name);