Repository: godotengine/godot
File: editor/scene_tree_dock.cpp (C++)

Code before:
			if (Object::cast_to<Node3D>(p_root)) {
				Node3D *node_3d = Object::cast_to<Node3D>(node);
				if (node_3d) {
					Transform3D gt = node_3d->get_global_transform();
					node_3d->get_parent()->remove_child(node_3d);
					p_root->add_child(node_3d);
					node_3d->set_global_transform(gt);
				} else {
					node->get_parent()->remove_child(node);
					p_root->add_child(node);
				}
			} else if (Object::cast_to<Node2D>(p_root)) {
				Node2D *node_2d = Object::cast_to<Node2D>(node);
				if (node_2d) {
					Transform2D gt = node_2d->get_global_transform();
					node_2d->get_parent()->remove_child(node_2d);
					p_root->add_child(node_2d);
					node_2d->set_global_transform(gt);
				} else {
					node->get_parent()->remove_child(node);
					p_root->add_child(node);
				}
			} else {
				node->get_parent()->remove_child(node);
				p_root->add_child(node);
			}

			for (Node *F : owned) {
				F->set_owner(p_owner);
			}
		}
	}
}

void SceneTreeDock::_reparent_nodes_to_paths_with_transform_and_name(Node *p_root, Array p_nodes, Array p_paths, Array p_transforms, Array p_names, Node *p_owner) {
	ERR_FAIL_COND(p_nodes.size() != p_paths.size());
	ERR_FAIL_COND(p_nodes.size() != p_transforms.size());
	ERR_FAIL_COND(p_nodes.size() != p_names.size());

	for (int i = 0; i < p_nodes.size(); i++) {
		Node *node = Object::cast_to<Node>(p_nodes[i]);
		ERR_FAIL_COND(node == nullptr);
		NodePath np = p_paths[i];
		Node *parent_node = p_root->get_node_or_null(np);
		ERR_FAIL_COND(!parent_node);

		List<Node *> owned;
		node->get_owned_by(p_owner, &owned, true);

		Node3D *node_3d = Object::cast_to<Node3D>(node);
		if (node_3d) {

Review comment (suggestion):
This can be replaced by the newly added `Node.reparent()`, which handles transforms.

Code after:
	}

	p_nodes.sort_custom<Node::Comparator>(); //Makes result reliable.

	const int first_idx = p_position_in_parent == -1 ? p_new_parent->get_child_count(false) : p_position_in_parent;
	int nodes_before = first_idx;
	bool no_change = true;
	for (int ni = 0; ni < p_nodes.size(); ni++) {
		if (p_nodes[ni] == p_new_parent) {
			return; // Attempt to reparent to itself.
		}
		// `move_child` + `get_index` doesn't really work for internal nodes.
		ERR_FAIL_COND_MSG(p_nodes[ni]->get_internal_mode() != INTERNAL_MODE_DISABLED, "Trying to move internal node, this is not supported.");

		if (p_nodes[ni]->get_index(false) < first_idx) {
			nodes_before--;
		}

		if (p_nodes[ni]->get_parent() != p_new_parent) {
			no_change = false;
		}
	}

	for (int ni = 0; ni < p_nodes.size() && no_change; ni++) {
		if (p_nodes[ni]->get_index(false) != nodes_before + ni) {
			no_change = false;
		}
	}

	if (no_change) {
		return; // Position and parent didn't change.
	}

	Node *validate = new_parent;
	while (validate) {
		ERR_FAIL_COND_MSG(p_nodes.has(validate), "Selection changed at some point. Can't reparent.");
		validate = validate->get_parent();
	}

	// Sort by tree order, so re-adding is easy.
	p_nodes.sort_custom<Node::Comparator>();

	EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
	undo_redo->create_action(TTR("Reparent Node"), UndoRedo::MERGE_DISABLE, p_nodes[0]);

	HashMap<Node *, NodePath> path_renames;
	Vector<StringName> former_names;

	int inc = 0;

	for (int ni = 0; ni < p_nodes.size(); ni++) {