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

Code before:
		_clear_selected();
	}

	Vector<ObjectID> instances = RenderingServer::get_singleton()->instances_cull_convex(frustum, get_tree()->get_root()->get_world_3d()->get_scenario());
	HashSet<Node3D *> found_nodes;
	Vector<Node *> selected;

	Node *edited_scene = get_tree()->get_edited_scene_root();
	if (edited_scene == nullptr) {
		return;
	}

	for (int i = 0; i < instances.size(); i++) {
		Node3D *sp = Object::cast_to<Node3D>(ObjectDB::get_instance(instances[i]));
		if (!sp || _is_node_locked(sp)) {
			continue;
		}

		if (found_nodes.has(sp)) {
			continue;
		}

		found_nodes.insert(sp);

		Node *node = Object::cast_to<Node>(sp);
		if (node != edited_scene) {
			node = edited_scene->get_deepest_editable_node(node);
		}

		// Prevent selection of nodes not owned by the edited scene.
		while (node && node != edited_scene->get_parent()) {
			Node *node_owner = node->get_owner();
			if (node_owner == edited_scene || node == edited_scene || (node_owner != nullptr && edited_scene->is_editable_instance(node_owner))) {
				break;
			}
			node = node->get_parent();
		}

		// Replace the node by the group if grouped
		if (node->is_class("Node3D")) {
			Node3D *sel = Object::cast_to<Node3D>(node);
			while (node && node != EditorNode::get_singleton()->get_edited_scene()->get_parent()) {
				Node3D *selected_tmp = Object::cast_to<Node3D>(node);
				if (selected_tmp && node->has_meta("_edit_group_")) {
					sel = selected_tmp;
				}
				node = node->get_parent();
			}
			node = sel;
		}


Review comment (suggestion):
```suggestion
		// Selection requires that the node is the edited scene or its descendant, and has an owner.
```

Code after:
		_clear_selected();
	}

	Vector<ObjectID> instances = RenderingServer::get_singleton()->instances_cull_convex(frustum, get_tree()->get_root()->get_world_3d()->get_scenario());
	HashSet<Node3D *> found_nodes;
	Vector<Node *> selected;

	Node *edited_scene = get_tree()->get_edited_scene_root();
	if (edited_scene == nullptr) {
		return;
	}

	for (int i = 0; i < instances.size(); i++) {
		Node3D *sp = Object::cast_to<Node3D>(ObjectDB::get_instance(instances[i]));
		if (!sp || _is_node_locked(sp)) {
			continue;
		}

		if (found_nodes.has(sp)) {
			continue;
		}
		found_nodes.insert(sp);

		Node *node = Object::cast_to<Node>(sp);

		// Selection requires that the node is the edited scene or its descendant, and has an owner.
		if (node != edited_scene) {
			if (!node->get_owner() || !edited_scene->is_ancestor_of(node)) {
				continue;
			}
			node = edited_scene->get_deepest_editable_node(node);
			while (node != edited_scene) {
				Node *node_owner = node->get_owner();
				if (node_owner == edited_scene || (node_owner != nullptr && edited_scene->is_editable_instance(node_owner))) {
					break;
				}
				node = node->get_parent();
			}
		}

		// Replace the node by the group if grouped
		if (node->is_class("Node3D")) {
			Node3D *sel = Object::cast_to<Node3D>(node);
			while (node && node != EditorNode::get_singleton()->get_edited_scene()->get_parent()) {
				Node3D *selected_tmp = Object::cast_to<Node3D>(node);
				if (selected_tmp && node->has_meta("_edit_group_")) {
					sel = selected_tmp;
				}
				node = node->get_parent();
			}
			node = sel;