Repository: godotengine/godot
File: scene/3d/collision_object_3d.cpp (C++)

Code before:
}

uint32_t CollisionObject3D::shape_find_owner(int p_shape_index) const {
	ERR_FAIL_INDEX_V(p_shape_index, total_subshapes, 0);

	for (const Map<uint32_t, ShapeData>::Element *E = shapes.front(); E; E = E->next()) {
		for (int i = 0; i < E->get().shapes.size(); i++) {
			if (E->get().shapes[i].index == p_shape_index) {
				return E->key();
			}
		}
	}

	//in theory it should be unreachable
	return 0;
}

CollisionObject3D::CollisionObject3D(RID p_rid, bool p_area) {
	rid = p_rid;
	area = p_area;
	set_notify_transform(true);

	if (p_area) {
		PhysicsServer3D::get_singleton()->area_attach_object_instance_id(rid, get_instance_id());
	} else {
		PhysicsServer3D::get_singleton()->body_attach_object_instance_id(rid, get_instance_id());
	}
	//set_transform_notify(true);
}

void CollisionObject3D::set_capture_input_on_drag(bool p_capture) {
	capture_input_on_drag = p_capture;
}

bool CollisionObject3D::get_capture_input_on_drag() const {
	return capture_input_on_drag;
}

String CollisionObject3D::get_configuration_warning() const {
	String warning = Node3D::get_configuration_warning();

	if (shapes.is_empty()) {
		if (!warning.is_empty()) {
			warning += "\n\n";
		}
		warning += TTR("This node has no shape, so it can't collide or interact with other objects.\nConsider adding a CollisionShape3D or CollisionPolygon3D as a child to define its shape.");
	}

	return warning;
}


Review comment (suggestion):
You could access `shapes[p_owner].shapes[p_shape]` only once before the line with `index_to_remove` in order to avoid redundant code.

Code after:

Ref<Shape3D> CollisionObject3D::shape_owner_get_shape(uint32_t p_owner, int p_shape) const {
	ERR_FAIL_COND_V(!shapes.has(p_owner), Ref<Shape3D>());
	ERR_FAIL_INDEX_V(p_shape, shapes[p_owner].shapes.size(), Ref<Shape3D>());

	return shapes[p_owner].shapes[p_shape].shape;
}

int CollisionObject3D::shape_owner_get_shape_index(uint32_t p_owner, int p_shape) const {
	ERR_FAIL_COND_V(!shapes.has(p_owner), -1);
	ERR_FAIL_INDEX_V(p_shape, shapes[p_owner].shapes.size(), -1);

	return shapes[p_owner].shapes[p_shape].index;
}

void CollisionObject3D::shape_owner_remove_shape(uint32_t p_owner, int p_shape) {
	ERR_FAIL_COND(!shapes.has(p_owner));
	ERR_FAIL_INDEX(p_shape, shapes[p_owner].shapes.size());

	const ShapeData::ShapeBase &s = shapes[p_owner].shapes[p_shape];
	int index_to_remove = s.index;

	if (area) {
		PhysicsServer3D::get_singleton()->area_remove_shape(rid, index_to_remove);
	} else {
		PhysicsServer3D::get_singleton()->body_remove_shape(rid, index_to_remove);
	}

	if (s.debug_shape) {
		s.debug_shape->queue_delete();
	}

	shapes[p_owner].shapes.remove(p_shape);

	for (Map<uint32_t, ShapeData>::Element *E = shapes.front(); E; E = E->next()) {
		for (int i = 0; i < E->get().shapes.size(); i++) {
			if (E->get().shapes[i].index > index_to_remove) {
				E->get().shapes.write[i].index -= 1;
			}
		}
	}

	total_subshapes--;
}

void CollisionObject3D::shape_owner_clear_shapes(uint32_t p_owner) {
	ERR_FAIL_COND(!shapes.has(p_owner));

	while (shape_owner_get_shape_count(p_owner) > 0) {
		shape_owner_remove_shape(p_owner, 0);
	}