diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp index 11fea8b7285b..80c4c49c87f3 100644 --- a/editor/editor_data.cpp +++ b/editor/editor_data.cpp @@ -141,6 +141,16 @@ void EditorSelectionHistory::add_object(ObjectID p_object, const String &p_prope current_elem_idx++; } +void EditorSelectionHistory::replace_object(ObjectID p_old_object, ObjectID p_new_object) { + for (HistoryElement &element : history) { + for (int index = 0; index < element.path.size(); index++) { + if (element.path[index].object == p_old_object) { + element.path.write[index].object = p_new_object; + } + } + } +} + int EditorSelectionHistory::get_history_len() { return history.size(); } diff --git a/editor/editor_data.h b/editor/editor_data.h index 42b2d2ed0c98..524c93807bb0 100644 --- a/editor/editor_data.h +++ b/editor/editor_data.h @@ -74,6 +74,7 @@ class EditorSelectionHistory { // Adds an object to the selection history. A property name can be passed if the target is a subresource of the given object. // If the object should not change the main screen plugin, it can be set as inspector only. void add_object(ObjectID p_object, const String &p_property = String(), bool p_inspector_only = false); + void replace_object(ObjectID p_old_object, ObjectID p_new_object); int get_history_len(); int get_history_pos(); diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 8b6d316dd16f..1256b1d7cec0 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -4446,6 +4446,21 @@ void EditorNode::update_reimported_diff_data_for_additional_nodes( } } +void EditorNode::replace_history_reimported_nodes(Node *p_original_root_node, Node *p_new_root_node, Node *p_node) { + NodePath scene_path_to_node = p_original_root_node->get_path_to(p_node); + Node *new_node = p_new_root_node->get_node_or_null(scene_path_to_node); + if (new_node) { + editor_history.replace_object(p_node->get_instance_id(), new_node->get_instance_id()); + } else { + editor_history.replace_object(p_node->get_instance_id(), ObjectID()); + } + + for (int i = 0; i < p_node->get_child_count(); i++) { + Node *child = p_node->get_child(i); + replace_history_reimported_nodes(p_original_root_node, p_new_root_node, child); + } +} + void EditorNode::open_request(const String &p_path) { if (!opening_prev) { List::Element *prev_scene_item = previous_scenes.find(p_path); @@ -6094,6 +6109,13 @@ void EditorNode::reload_instances_with_path_in_edited_scenes(const String &p_ins owned_node->set_owner(nullptr); } + // Replace the old nodes in the history with the new ones. + // Otherwise, the history will contain old nodes, and some could still be + // instantiated if used elsewhere, causing the "current edited item" to be + // linked to a node that will be destroyed later. This caused the editor to + // crash when reimporting scenes with animations when "Editable children" was enabled. + replace_history_reimported_nodes(original_node, instantiated_node, original_node); + // Delete all the remaining node children. while (original_node->get_child_count()) { Node *child = original_node->get_child(0); diff --git a/editor/editor_node.h b/editor/editor_node.h index 4d55eaf1b2ab..5719e671b484 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -843,6 +843,8 @@ class EditorNode : public Node { List &p_addition_list); bool is_additional_node_in_scene(Node *p_edited_scene, Node *p_reimported_root, Node *p_node); + void replace_history_reimported_nodes(Node *p_original_root_node, Node *p_new_root_node, Node *p_node); + bool is_scene_open(const String &p_path); bool is_multi_window_enabled() const;