diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index a436f63c3e1c..964061505f84 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -4107,7 +4107,7 @@ Error EditorNode::load_scene(const String &p_scene, bool p_ignore_broken_deps, b return OK; } -HashMap EditorNode::get_modified_properties_for_node(Node *p_node) { +HashMap EditorNode::get_modified_properties_for_node(Node *p_node, bool p_node_references_only) { HashMap modified_property_map; List pinfo; @@ -4119,7 +4119,17 @@ HashMap EditorNode::get_modified_properties_for_node(Node * Variant current_value = p_node->get(E.name); if (is_valid_revert) { if (PropertyUtils::is_property_value_different(current_value, revert_value)) { - modified_property_map[E.name] = current_value; + // If this property is a direct node reference, save a NodePath instead to prevent corrupted references. + if (E.type == Variant::OBJECT && E.hint == PROPERTY_HINT_NODE_TYPE) { + Node *target_node = Object::cast_to(current_value); + if (target_node) { + modified_property_map[E.name] = p_node->get_path_to(target_node); + } + } else { + if (!p_node_references_only) { + modified_property_map[E.name] = current_value; + } + } } } } @@ -4137,10 +4147,118 @@ void EditorNode::update_ownership_table_for_addition_node_ancestors(Node *p_curr } } -void EditorNode::update_diff_data_for_node( - Node *p_edited_scene, +void EditorNode::update_node_from_node_modification_entry(Node *p_node, ModificationNodeEntry &p_node_modification) { + if (p_node) { + // First, attempt to restore the script property since it may affect the get_property_list method. + Variant *script_property_table_entry = p_node_modification.property_table.getptr(CoreStringName(script)); + if (script_property_table_entry) { + p_node->set_script(*script_property_table_entry); + } + + // Get properties for this node. + List pinfo; + p_node->get_property_list(&pinfo); + + // Get names of all valid property names. + HashMap property_node_reference_table; + for (const PropertyInfo &E : pinfo) { + if (E.usage & PROPERTY_USAGE_STORAGE) { + if (E.type == Variant::OBJECT && E.hint == PROPERTY_HINT_NODE_TYPE) { + property_node_reference_table[E.name] = true; + } else { + property_node_reference_table[E.name] = false; + } + } + } + + // Restore the modified properties for this node. + for (const KeyValue &E : p_node_modification.property_table) { + bool *property_node_reference_table_entry = property_node_reference_table.getptr(E.key); + if (property_node_reference_table_entry) { + // If the property is a node reference, attempt to restore from the node path instead. + bool is_node_reference = *property_node_reference_table_entry; + if (is_node_reference) { + if (E.value.get_type() == Variant::NODE_PATH) { + p_node->set(E.key, p_node->get_node_or_null(E.value)); + } + } else { + p_node->set(E.key, E.value); + } + } + } + + // Restore the connections to other nodes. + for (const ConnectionWithNodePath &E : p_node_modification.connections_to) { + Connection conn = E.connection; + + // Get the node the callable is targeting. + Node *target_node = Object::cast_to(conn.callable.get_object()); + + // If the callable object no longer exists or is marked for deletion, + // attempt to reaccquire the closest match by using the node path + // we saved earlier. + if (!target_node || !target_node->is_queued_for_deletion()) { + target_node = p_node->get_node_or_null(E.node_path); + } + + if (target_node) { + // Reconstruct the callable. + Callable new_callable = Callable(target_node, conn.callable.get_method()); + + if (!p_node->is_connected(conn.signal.get_name(), new_callable)) { + ERR_FAIL_COND(p_node->connect(conn.signal.get_name(), new_callable, conn.flags) != OK); + } + } + } + + // Restore the connections from other nodes. + for (const Connection &E : p_node_modification.connections_from) { + Connection conn = E; + + bool valid = p_node->has_method(conn.callable.get_method()) || Ref