| 3175 | } |
| 3176 | |
| 3177 | void SceneTreeDock::_replace_node(Node *p_node, Node *p_by_node, bool p_keep_properties, bool p_remove_old) { |
| 3178 | ERR_FAIL_COND_MSG(!p_node->is_inside_tree(), "_replace_node() can't be called on a node outside of tree. You might have called it twice."); |
| 3179 | Node *oldnode = p_node; |
| 3180 | Node *newnode = p_by_node; |
| 3181 | |
| 3182 | if (p_keep_properties) { |
| 3183 | Node *default_oldnode = nullptr; |
| 3184 | |
| 3185 | // If we're dealing with a custom node type, we need to create a default instance of the custom type instead of the native type for property comparison. |
| 3186 | if (oldnode->has_meta(SceneStringName(_custom_type_script))) { |
| 3187 | Ref<Script> cts = PropertyUtils::get_custom_type_script(oldnode); |
| 3188 | ERR_FAIL_COND_MSG(cts.is_null(), "Invalid custom type script."); |
| 3189 | default_oldnode = Object::cast_to<Node>(get_editor_data()->script_class_instance(cts->get_global_name())); |
| 3190 | if (default_oldnode) { |
| 3191 | default_oldnode->set_name(cts->get_global_name()); |
| 3192 | get_editor_data()->instantiate_object_properties(default_oldnode); |
| 3193 | } else { |
| 3194 | /// Legacy custom type, registered with "add_custom_type()". |
| 3195 | /// @todo Should probably be deprecated in 4.x. |
| 3196 | const EditorData::CustomType *custom_type = get_editor_data()->get_custom_type_by_path(cts->get_path()); |
| 3197 | if (custom_type) { |
| 3198 | default_oldnode = Object::cast_to<Node>(get_editor_data()->instantiate_custom_type(custom_type->name, cts->get_instance_base_type())); |
| 3199 | } |
| 3200 | } |
| 3201 | } |
| 3202 | |
| 3203 | if (!default_oldnode) { |
| 3204 | default_oldnode = Object::cast_to<Node>(ClassDB::instantiate(oldnode->get_class())); |
| 3205 | } |
| 3206 | |
| 3207 | List<PropertyInfo> pinfo; |
| 3208 | oldnode->get_property_list(&pinfo); |
| 3209 | |
| 3210 | for (const PropertyInfo &E : pinfo) { |
| 3211 | if (!(E.usage & PROPERTY_USAGE_STORAGE)) { |
| 3212 | continue; |
| 3213 | } |
| 3214 | |
| 3215 | bool valid; |
| 3216 | const Variant &default_val = default_oldnode->get(E.name, &valid); |
| 3217 | if (!valid || default_val != oldnode->get(E.name)) { |
| 3218 | newnode->set(E.name, oldnode->get(E.name)); |
| 3219 | } |
| 3220 | } |
| 3221 | |
| 3222 | memdelete(default_oldnode); |
| 3223 | } |
| 3224 | |
| 3225 | _push_item(nullptr); |
| 3226 | |
| 3227 | //reconnect signals |
| 3228 | List<MethodInfo> sl; |
| 3229 | |
| 3230 | oldnode->get_signal_list(&sl); |
| 3231 | for (const MethodInfo &E : sl) { |
| 3232 | List<Object::Connection> cl; |
| 3233 | oldnode->get_signal_connection_list(E.name, &cl); |
| 3234 |
nothing calls this directly
no test coverage detected