ronantakizawa/codereview-bench huggingface dataset:
Repository: godotengine/godot
File: platform/linuxbsd/x11/display_server_x11.cpp (C++)

Code before:
			result = XGetWindowProperty(x11_display, x11_window,
					selection, 0, bytes_left, 0,
					AnyPropertyType, &type, &format,
					&len, &dummy, &data);

			if (result == Success) {
				ret.parse_utf8((const char *)data);
			} else {
				print_verbose("Failed to get selection data.");
			}

			if (data) {
				XFree(data);
			}
		}
	}

	return ret;
}

String DisplayServerX11::_clipboard_get(Atom p_source, Window x11_window) const {
	String ret;
	Atom utf8_atom = XInternAtom(x11_display, "UTF8_STRING", True);
	if (utf8_atom != None) {
		ret = _clipboard_get_impl(p_source, x11_window, utf8_atom);
	}
	if (ret.is_empty()) {
		ret = _clipboard_get_impl(p_source, x11_window, XA_STRING);
	}
	return ret;
}

String DisplayServerX11::clipboard_get() const {
	_THREAD_SAFE_METHOD_

	String ret;
	ret = _clipboard_get(XInternAtom(x11_display, "CLIPBOARD", 0), windows[MAIN_WINDOW_ID].x11_window);

	if (ret.is_empty()) {
		ret = _clipboard_get(XA_PRIMARY, windows[MAIN_WINDOW_ID].x11_window);
	}

	return ret;
}

String DisplayServerX11::clipboard_get_primary() const {
	_THREAD_SAFE_METHOD_

	String ret;
	ret = _clipboard_get(XInternAtom(x11_display, "PRIMARY", 0), windows[MAIN_WINDOW_ID].x11_window);


Review comment (bug):
```suggestion
	Atom *valid_targets = nullptr;
	unsigned long atom_count = 0;
```

Code after:
			// Data is ready and can be processed all at once.
			result = XGetWindowProperty(x11_display, x11_window,
					selection, 0, bytes_left, 0,
					AnyPropertyType, &type, &format,
					&len, &dummy, &data);

			if (result == Success) {
				ret.parse_utf8((const char *)data);
			} else {
				print_verbose("Failed to get selection data.");
			}

			if (data) {
				XFree(data);
			}
		}
	}

	return ret;
}

Atom DisplayServerX11::_clipboard_get_image_target(Atom p_source, Window x11_window) const {
	Atom target = XInternAtom(x11_display, "TARGETS", 0);
	Atom png = XInternAtom(x11_display, "image/png", 0);
	Atom *valid_targets = nullptr;
	unsigned long atom_count = 0;

	Window selection_owner = XGetSelectionOwner(x11_display, p_source);
	if (selection_owner != None) {
		// Block events polling while processing selection events.
		MutexLock mutex_lock(events_mutex);

		Atom selection = XA_PRIMARY;
		XConvertSelection(x11_display, p_source, target, selection, x11_window, CurrentTime);

		XFlush(x11_display);

		// Blocking wait for predicate to be True and remove the event from the queue.
		XEvent event;
		XIfEvent(x11_display, &event, _predicate_clipboard_selection, (XPointer)&x11_window);
		// Do not get any data, see how much data is there.
		Atom type;
		int format, result;
		unsigned long len, bytes_left, dummy;
		XGetWindowProperty(x11_display, x11_window,
				selection, // Tricky..
				0, 0, // offset - len
				0, // Delete 0==FALSE
				XA_ATOM, // flag
				&type, // return type
				&format, // return format
Repository: godotengine/godot
File: editor/plugins/node_3d_editor_plugin.cpp (C++)

Code before:
void Node3DEditor::set_can_preview(Camera3D *p_preview) {
	for (int i = 0; i < 4; i++) {
		viewports[i]->set_can_preview(p_preview);
	}
}

VSplitContainer *Node3DEditor::get_shader_split() {
	return shader_split;
}

void Node3DEditor::add_control_to_left_panel(Control *p_control) {
	left_panel_split->add_child(p_control);
	left_panel_split->move_child(p_control, 0);
}

void Node3DEditor::add_control_to_right_panel(Control *p_control) {
	right_panel_split->add_child(p_control);
	right_panel_split->move_child(p_control, 1);
}

void Node3DEditor::remove_control_from_left_panel(Control *p_control) {
	left_panel_split->remove_child(p_control);
}

void Node3DEditor::remove_control_from_right_panel(Control *p_control) {
	right_panel_split->remove_child(p_control);
}

void Node3DEditor::move_control_to_left_panel(Control *p_control) {
	ERR_FAIL_NULL(p_control);
	if (p_control->get_parent() == left_panel_split) {
		return;
	}

	ERR_FAIL_COND(p_control->get_parent() != right_panel_split);
	right_panel_split->remove_child(p_control);

	add_control_to_left_panel(p_control);
}

void Node3DEditor::move_control_to_right_panel(Control *p_control) {
	ERR_FAIL_NULL(p_control);
	if (p_control->get_parent() == right_panel_split) {
		return;
	}

	ERR_FAIL_COND(p_control->get_parent() != left_panel_split);
	left_panel_split->remove_child(p_control);

	add_control_to_right_panel(p_control);
}

Review comment (performance):
You could use the HashMap::Iterator trick here instead of `has()`, but I guess this code is less performance critical.

Code after:

	p_control->connect("visibility_changed", callable_mp(this, &Node3DEditor::_update_context_toolbar));

	_update_context_toolbar();
}

void Node3DEditor::remove_control_from_menu_panel(Control *p_control) {
	ERR_FAIL_NULL(p_control);
	ERR_FAIL_COND(p_control->get_parent() != context_toolbar_hbox);

	p_control->disconnect("visibility_changed", callable_mp(this, &Node3DEditor::_update_context_toolbar));

	context_toolbar_hbox->remove_child(context_toolbar_separators[p_control]);
	context_toolbar_hbox->remove_child(p_control);
	context_toolbar_separators.erase(p_control);

	_update_context_toolbar();
}

void Node3DEditor::_update_context_toolbar() {
	bool has_visible = false;
	bool first_visible = false;

	for (int i = 0; i < context_toolbar_hbox->get_child_count(); i++) {
		Control *child = Object::cast_to<Control>(context_toolbar_hbox->get_child(i));
		if (!child || !context_toolbar_separators.has(child)) {
			continue;
		}
		if (child->is_visible()) {
			first_visible = !has_visible;
			has_visible = true;
		}

		VSeparator *sep = context_toolbar_separators[child];
		sep->set_visible(!first_visible && child->is_visible());
	}

	context_toolbar_panel->set_visible(has_visible);
}

void Node3DEditor::set_can_preview(Camera3D *p_preview) {
	for (int i = 0; i < 4; i++) {
		viewports[i]->set_can_preview(p_preview);
	}
}

VSplitContainer *Node3DEditor::get_shader_split() {
	return shader_split;
}

void Node3DEditor::add_control_to_left_panel(Control *p_control) {
Repository: godotengine/godot
File: editor/plugins/node_3d_editor_plugin.cpp (C++)

Code before:

void Node3DEditor::add_control_to_left_panel(Control *p_control) {
	left_panel_split->add_child(p_control);
	left_panel_split->move_child(p_control, 0);
}

void Node3DEditor::add_control_to_right_panel(Control *p_control) {
	right_panel_split->add_child(p_control);
	right_panel_split->move_child(p_control, 1);
}

void Node3DEditor::remove_control_from_left_panel(Control *p_control) {
	left_panel_split->remove_child(p_control);
}

void Node3DEditor::remove_control_from_right_panel(Control *p_control) {
	right_panel_split->remove_child(p_control);
}

void Node3DEditor::move_control_to_left_panel(Control *p_control) {
	ERR_FAIL_NULL(p_control);
	if (p_control->get_parent() == left_panel_split) {
		return;
	}

	ERR_FAIL_COND(p_control->get_parent() != right_panel_split);
	right_panel_split->remove_child(p_control);

	add_control_to_left_panel(p_control);
}

void Node3DEditor::move_control_to_right_panel(Control *p_control) {
	ERR_FAIL_NULL(p_control);
	if (p_control->get_parent() == right_panel_split) {
		return;
	}

	ERR_FAIL_COND(p_control->get_parent() != left_panel_split);
	left_panel_split->remove_child(p_control);

	add_control_to_right_panel(p_control);
}

void Node3DEditor::_request_gizmo(Object *p_obj) {
	Node3D *sp = Object::cast_to<Node3D>(p_obj);
	if (!sp) {
		return;
	}

	bool is_selected = (sp == selected);


Review comment (suggestion):
```suggestion
		sep->set_visible(!first_visible && child->is_visible());
```
Free optimization.

Code after:

	p_control->disconnect("visibility_changed", callable_mp(this, &Node3DEditor::_update_context_toolbar));

	context_toolbar_hbox->remove_child(context_toolbar_separators[p_control]);
	context_toolbar_hbox->remove_child(p_control);
	context_toolbar_separators.erase(p_control);

	_update_context_toolbar();
}

void Node3DEditor::_update_context_toolbar() {
	bool has_visible = false;
	bool first_visible = false;

	for (int i = 0; i < context_toolbar_hbox->get_child_count(); i++) {
		Control *child = Object::cast_to<Control>(context_toolbar_hbox->get_child(i));
		if (!child || !context_toolbar_separators.has(child)) {
			continue;
		}
		if (child->is_visible()) {
			first_visible = !has_visible;
			has_visible = true;
		}

		VSeparator *sep = context_toolbar_separators[child];
		sep->set_visible(!first_visible && child->is_visible());
	}

	context_toolbar_panel->set_visible(has_visible);
}

void Node3DEditor::set_can_preview(Camera3D *p_preview) {
	for (int i = 0; i < 4; i++) {
		viewports[i]->set_can_preview(p_preview);
	}
}

VSplitContainer *Node3DEditor::get_shader_split() {
	return shader_split;
}

void Node3DEditor::add_control_to_left_panel(Control *p_control) {
	left_panel_split->add_child(p_control);
	left_panel_split->move_child(p_control, 0);
}

void Node3DEditor::add_control_to_right_panel(Control *p_control) {
	right_panel_split->add_child(p_control);
	right_panel_split->move_child(p_control, 1);
}
Repository: godotengine/godot
File: editor/gui/editor_zoom_widget.cpp (C++)

Code before:
	}
	zoom_text += " " + TS->percent_sign();
	zoom_reset->set_text(zoom_text);
}

void EditorZoomWidget::_button_zoom_minus() {
	set_zoom_by_increments(-6, Input::get_singleton()->is_key_pressed(Key::ALT));
	emit_signal(SNAME("zoom_changed"), zoom);
}

void EditorZoomWidget::_button_zoom_reset() {
	set_zoom(1.0 * MAX(1, EDSCALE));
	emit_signal(SNAME("zoom_changed"), zoom);
}

void EditorZoomWidget::_button_zoom_plus() {
	set_zoom_by_increments(6, Input::get_singleton()->is_key_pressed(Key::ALT));
	emit_signal(SNAME("zoom_changed"), zoom);
}

float EditorZoomWidget::get_zoom() {
	return zoom;
}

void EditorZoomWidget::set_zoom(float p_zoom) {
	if (p_zoom > 0 && p_zoom != zoom) {
		zoom = p_zoom;
		_update_zoom_label();
	}
}

void EditorZoomWidget::set_zoom_by_increments(int p_increment_count, bool p_integer_only) {
	// Remove editor scale from the index computation.
	const float zoom_noscale = zoom / MAX(1, EDSCALE);

	if (p_integer_only) {
		// Only visit integer scaling factors above 100%, and fractions with an integer denominator below 100%
		// (1/2 = 50%, 1/3 = 33.33%, 1/4 = 25%, …).
		// This is useful when working on pixel art projects to avoid distortion.
		// This algorithm is designed to handle fractional start zoom values correctly
		// (e.g. 190% will zoom up to 200% and down to 100%).
		if (zoom_noscale + p_increment_count * 0.001 >= 1.0 - CMP_EPSILON) {
			// New zoom is certain to be above 100%.
			if (p_increment_count >= 1) {
				// Zooming.
				set_zoom(Math::floor(zoom_noscale + p_increment_count) * MAX(1, EDSCALE));
			} else {
				// Dezooming.
				set_zoom(Math::ceil(zoom_noscale + p_increment_count) * MAX(1, EDSCALE));
			}
		} else {

Review comment (suggestion):
```suggestion
	float new_zoom = CLAMP(p_zoom, min_zoom, max_zoom);
```

Code after:
	}
	zoom_text += " " + TS->percent_sign();
	zoom_reset->set_text(zoom_text);
}

void EditorZoomWidget::_button_zoom_minus() {
	set_zoom_by_increments(-6, Input::get_singleton()->is_key_pressed(Key::ALT));
	emit_signal(SNAME("zoom_changed"), zoom);
}

void EditorZoomWidget::_button_zoom_reset() {
	set_zoom(1.0 * MAX(1, EDSCALE));
	emit_signal(SNAME("zoom_changed"), zoom);
}

void EditorZoomWidget::_button_zoom_plus() {
	set_zoom_by_increments(6, Input::get_singleton()->is_key_pressed(Key::ALT));
	emit_signal(SNAME("zoom_changed"), zoom);
}

float EditorZoomWidget::get_zoom() {
	return zoom;
}

void EditorZoomWidget::set_zoom(float p_zoom) {
	float new_zoom = CLAMP(p_zoom, min_zoom, max_zoom);
	if (zoom != new_zoom) {
		zoom = new_zoom;
		_update_zoom_label();
	}
}

float EditorZoomWidget::get_min_zoom() {
	return min_zoom;
}

float EditorZoomWidget::get_max_zoom() {
	return max_zoom;
}

void EditorZoomWidget::setup_zoom_limits(float p_min, float p_max) {
	ERR_FAIL_COND(p_min < 0 || p_min > p_max);

	min_zoom = p_min;
	max_zoom = p_max;

	if (zoom > max_zoom) {
		set_zoom(max_zoom);
		emit_signal(SNAME("zoom_changed"), zoom);
	} else if (zoom < min_zoom) {
		set_zoom(min_zoom);
Repository: godotengine/godot
File: scene/animation/tween.cpp (C++)

Code before:
}

IntervalTweener::IntervalTweener(double p_time) {
	duration = p_time;
}

IntervalTweener::IntervalTweener() {
	ERR_FAIL_MSG("IntervalTweener can't be created directly. Use the tween_interval() method in Tween.");
}

Ref<CallbackTweener> CallbackTweener::set_delay(double p_delay) {
	delay = p_delay;
	return this;
}

void CallbackTweener::start() {
	elapsed_time = 0;
	finished = false;
}

bool CallbackTweener::step(double &r_delta) {
	if (finished) {
		return false;
	}

	if (!callback.get_object()) {
		return false;
	}

	elapsed_time += r_delta;
	if (elapsed_time >= delay) {
		Variant result;
		Callable::CallError ce;
		callback.callp(nullptr, 0, result, ce);
		if (ce.error != Callable::CallError::CALL_OK) {
			ERR_FAIL_V_MSG(false, "Error calling method from CallbackTweener: " + Variant::get_callable_error_text(callback, nullptr, 0, ce));
		}

		finished = true;
		r_delta = elapsed_time - delay;
		emit_signal(SNAME("finished"));
		return false;
	}

	r_delta = 0;
	return true;
}

void CallbackTweener::_bind_methods() {
	ClassDB::bind_method(D_METHOD("set_delay", "delay"), &CallbackTweener::set_delay);
}

Review comment (suggestion):
This breaks static methods. For whatever reason their `is_valid()` returns false, but their Object is the source GDScript. Example:
```GDScript
@tool
extends EditorScript

class CustomNode extends Node:
	static func test():
		print(1)

func _run():
	var tw = Engine.get_main_loop().create_tween()
	tw.tween_callback(CustomNode.test)
```
Does not work with this PR.

Code after:
}

IntervalTweener::IntervalTweener(double p_time) {
	duration = p_time;
}

IntervalTweener::IntervalTweener() {
	ERR_FAIL_MSG("IntervalTweener can't be created directly. Use the tween_interval() method in Tween.");
}

Ref<CallbackTweener> CallbackTweener::set_delay(double p_delay) {
	delay = p_delay;
	return this;
}

void CallbackTweener::start() {
	elapsed_time = 0;
	finished = false;
}

bool CallbackTweener::step(double &r_delta) {
	if (finished) {
		return false;
	}

	if (!callback.is_valid()) {
		return false;
	}

	elapsed_time += r_delta;
	if (elapsed_time >= delay) {
		Variant result;
		Callable::CallError ce;
		callback.callp(nullptr, 0, result, ce);
		if (ce.error != Callable::CallError::CALL_OK) {
			ERR_FAIL_V_MSG(false, "Error calling method from CallbackTweener: " + Variant::get_callable_error_text(callback, nullptr, 0, ce));
		}

		finished = true;
		r_delta = elapsed_time - delay;
		emit_signal(SNAME("finished"));
		return false;
	}

	r_delta = 0;
	return true;
}

void CallbackTweener::_bind_methods() {
	ClassDB::bind_method(D_METHOD("set_delay", "delay"), &CallbackTweener::set_delay);
}
Repository: godotengine/godot
File: editor/code_editor.cpp (C++)

Code before:
	hide();
}

void FindReplaceBar::_show_search(bool p_focus_replace, bool p_show_only) {
	show();
	if (p_show_only) {
		return;
	}

	if (p_focus_replace) {
		search_text->deselect();
		replace_text->call_deferred(SNAME("grab_focus"));
	} else {
		replace_text->deselect();
		search_text->call_deferred(SNAME("grab_focus"));
	}

	if (text_editor->has_selection(0) && !is_selection_only()) {
		search_text->set_text(text_editor->get_selected_text(0));
		result_line = text_editor->get_selection_from_line();
		result_col = text_editor->get_selection_from_column();
	}

	if (!get_search_text().is_empty()) {
		if (p_focus_replace) {
			replace_text->select_all();
			replace_text->set_caret_column(replace_text->get_text().length());
		} else {
			search_text->select_all();
			search_text->set_caret_column(search_text->get_text().length());
		}

		results_count = -1;
		results_count_to_current = -1;
		needs_to_count_results = true;
		_update_results_count();
		_update_matches_label();
	}
}

void FindReplaceBar::popup_search(bool p_show_only) {
	replace_text->hide();
	hbc_button_replace->hide();
	hbc_option_replace->hide();
	selection_only->set_pressed(false);

	_show_search(false, p_show_only);
}

void FindReplaceBar::popup_replace() {
	if (!replace_text->is_visible_in_tree()) {

Review comment (suggestion):
Should probably set `preserve_cursor=true` before this to prevent the jumping around the text when simply opening the searchbar, with whatever was in there previously. 

Code after:

	if (p_focus_replace) {
		search_text->deselect();
		replace_text->call_deferred(SNAME("grab_focus"));
	} else {
		replace_text->deselect();
		search_text->call_deferred(SNAME("grab_focus"));
	}

	if (text_editor->has_selection(0) && !is_selection_only()) {
		search_text->set_text(text_editor->get_selected_text(0));
		result_line = text_editor->get_selection_from_line();
		result_col = text_editor->get_selection_from_column();
	}

	if (!get_search_text().is_empty()) {
		if (p_focus_replace) {
			replace_text->select_all();
			replace_text->set_caret_column(replace_text->get_text().length());
		} else {
			search_text->select_all();
			search_text->set_caret_column(search_text->get_text().length());
		}

		preserve_cursor = true;
		_search_text_changed(get_search_text());
		preserve_cursor = false;
	}
}

void FindReplaceBar::popup_search(bool p_show_only) {
	replace_text->hide();
	hbc_button_replace->hide();
	hbc_option_replace->hide();
	selection_only->set_pressed(false);

	_show_search(false, p_show_only);
}

void FindReplaceBar::popup_replace() {
	if (!replace_text->is_visible_in_tree()) {
		replace_text->show();
		hbc_button_replace->show();
		hbc_option_replace->show();
	}

	selection_only->set_pressed((text_editor->has_selection(0) && text_editor->get_selection_from_line(0) < text_editor->get_selection_to_line(0)));

	_show_search(is_visible() || text_editor->has_selection(0));
}
Repository: godotengine/godot
File: scene/main/node.cpp (C++)

Code before:
		List<PropertyInfo> plist;
		N->get()->get_property_list(&plist);

		for (const PropertyInfo &E : plist) {
			if (!(E.usage & PROPERTY_USAGE_STORAGE)) {
				continue;
			}
			String name = E.name;
			if (name == script_property_name) {
				continue;
			}

			Variant value = N->get()->get(name).duplicate(true);

			if (E.usage & PROPERTY_USAGE_ALWAYS_DUPLICATE) {
				Resource *res = Object::cast_to<Resource>(value);
				if (res) { // Duplicate only if it's a resource
					current_node->set(name, res->duplicate());
				}

			} else {
				current_node->set(name, value);
			}
		}
	}

	if (get_name() != String()) {
		node->set_name(get_name());
	}

#ifdef TOOLS_ENABLED
	if ((p_flags & DUPLICATE_FROM_EDITOR) && r_duplimap) {
		r_duplimap->insert(this, node);
	}
#endif

	if (p_flags & DUPLICATE_GROUPS) {
		List<GroupInfo> gi;
		get_groups(&gi);
		for (const GroupInfo &E : gi) {
#ifdef TOOLS_ENABLED
			if ((p_flags & DUPLICATE_FROM_EDITOR) && !E.persistent) {
				continue;
			}
#endif

			node->add_to_group(E.name, E.persistent);
		}
	}

	for (int i = 0; i < get_child_count(); i++) {

Review comment (suggestion):
```suggestion
						if (is_ancestor_of(property_node)) {
```

Code after:
		get_groups(&gi);
		for (const GroupInfo &E : gi) {
#ifdef TOOLS_ENABLED
			if ((p_flags & DUPLICATE_FROM_EDITOR) && !E.persistent) {
				continue;
			}
#endif

			node->add_to_group(E.name, E.persistent);
		}
	}

	for (int i = 0; i < get_child_count(); i++) {
		if (get_child(i)->data.parent_owned) {
			continue;
		}
		if (instantiated && get_child(i)->data.owner == this) {
			continue; //part of instance
		}

		Node *dup = get_child(i)->_duplicate(p_flags, r_duplimap);
		if (!dup) {
			memdelete(node);
			return nullptr;
		}

		node->add_child(dup);
		if (i < node->get_child_count() - 1) {
			node->move_child(dup, i);
		}
	}

	for (const Node *&E : hidden_roots) {
		Node *parent = node->get_node(get_path_to(E->data.parent));
		if (!parent) {
			memdelete(node);
			return nullptr;
		}

		Node *dup = E->_duplicate(p_flags, r_duplimap);
		if (!dup) {
			memdelete(node);
			return nullptr;
		}

		parent->add_child(dup);
		int pos = E->get_index();

		if (pos < parent->get_child_count() - 1) {
			parent->move_child(dup, pos);
		}
Repository: godotengine/godot
File: scene/main/node.cpp (C++)

Code before:
			}

			Variant value = N->get()->get(name).duplicate(true);

			if (E.usage & PROPERTY_USAGE_ALWAYS_DUPLICATE) {
				Resource *res = Object::cast_to<Resource>(value);
				if (res) { // Duplicate only if it's a resource
					current_node->set(name, res->duplicate());
				}

			} else {
				current_node->set(name, value);
			}
		}
	}

	if (get_name() != String()) {
		node->set_name(get_name());
	}

#ifdef TOOLS_ENABLED
	if ((p_flags & DUPLICATE_FROM_EDITOR) && r_duplimap) {
		r_duplimap->insert(this, node);
	}
#endif

	if (p_flags & DUPLICATE_GROUPS) {
		List<GroupInfo> gi;
		get_groups(&gi);
		for (const GroupInfo &E : gi) {
#ifdef TOOLS_ENABLED
			if ((p_flags & DUPLICATE_FROM_EDITOR) && !E.persistent) {
				continue;
			}
#endif

			node->add_to_group(E.name, E.persistent);
		}
	}

	for (int i = 0; i < get_child_count(); i++) {
		if (get_child(i)->data.parent_owned) {
			continue;
		}
		if (instantiated && get_child(i)->data.owner == this) {
			continue; //part of instance
		}

		Node *dup = get_child(i)->_duplicate(p_flags, r_duplimap);
		if (!dup) {
			memdelete(node);

Review comment (suggestion):
```suggestion
								if (is_ancestor_of(property_node)) {
```

Code after:
	}

	for (int i = 0; i < get_child_count(); i++) {
		if (get_child(i)->data.parent_owned) {
			continue;
		}
		if (instantiated && get_child(i)->data.owner == this) {
			continue; //part of instance
		}

		Node *dup = get_child(i)->_duplicate(p_flags, r_duplimap);
		if (!dup) {
			memdelete(node);
			return nullptr;
		}

		node->add_child(dup);
		if (i < node->get_child_count() - 1) {
			node->move_child(dup, i);
		}
	}

	for (const Node *&E : hidden_roots) {
		Node *parent = node->get_node(get_path_to(E->data.parent));
		if (!parent) {
			memdelete(node);
			return nullptr;
		}

		Node *dup = E->_duplicate(p_flags, r_duplimap);
		if (!dup) {
			memdelete(node);
			return nullptr;
		}

		parent->add_child(dup);
		int pos = E->get_index();

		if (pos < parent->get_child_count() - 1) {
			parent->move_child(dup, pos);
		}
	}

	for (List<const Node *>::Element *N = node_tree.front(); N; N = N->next()) {
		Node *current_node = node->get_node(get_path_to(N->get()));
		ERR_CONTINUE(!current_node);

		if (p_flags & DUPLICATE_SCRIPTS) {
			bool is_valid = false;
			Variant scr = N->get()->get(script_property_name, &is_valid);
			if (is_valid) {