From 961ca07bcf260bd04a9284b105e4fa87207650cb Mon Sep 17 00:00:00 2001 From: Benjamin Date: Thu, 11 Jun 2026 21:27:09 +0200 Subject: [PATCH] telemetry: emit track geometry (DriveGraph nodes) in RaceStarted Walk the main driveline graph at race start and populate TrackGeometry with center, left/right edge, width, and distance_from_start for each DriveNode quad. Includes bounding box and start position/heading for 2D minimap rendering. --- src/network/telemetry/telemetry_emitter.cpp | 103 ++++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/src/network/telemetry/telemetry_emitter.cpp b/src/network/telemetry/telemetry_emitter.cpp index 91e59fb..b44934c 100644 --- a/src/network/telemetry/telemetry_emitter.cpp +++ b/src/network/telemetry/telemetry_emitter.cpp @@ -19,9 +19,12 @@ #include "tracks/track.hpp" #include "tracks/track_sector.hpp" #include "tracks/check_manager.hpp" +#include "tracks/drive_graph.hpp" +#include "tracks/drive_node.hpp" #include "utils/log.hpp" #include "utils/string_utils.hpp" +#include #include #include #include @@ -176,6 +179,106 @@ void TelemetryEmitter::onRaceStarted() } } + // --- Track geometry (for 2D minimap / replay) --- + DriveGraph* graph = DriveGraph::get(); + if (graph != nullptr && graph->getNumNodes() > 0) + { + auto* geom = ev->mutable_track_geometry(); + + float min_x = 1e9f, min_y = 1e9f, min_z = 1e9f; + float max_x = -1e9f, max_y = -1e9f, max_z = -1e9f; + + // Walk the main driveline loop following successor 0. + unsigned int num_nodes = graph->getNumNodes(); + unsigned int current = 0; + unsigned int visited = 0; + + do { + const DriveNode* dn = graph->getNode(current); + if (dn == nullptr) break; + + auto* node = geom->add_nodes(); + + // Center + const Vec3& center = dn->getCenter(); + auto* c = node->mutable_center(); + c->set_x(center.x()); + c->set_y(center.y()); + c->set_z(center.z()); + + // Width + node->set_width(dn->getPathWidth()); + + // Distance from start + node->set_distance_from_start(dn->getDistanceFromStart()); + + // Left and right edge points from Quad corners. + // Quad layout: [0]=lower-right, [1]=lower-left, [2]=upper-left, [3]=upper-right + const Vec3& lr = (*dn)[0]; + const Vec3& ll = (*dn)[1]; + const Vec3& ul = (*dn)[2]; + const Vec3& ur = (*dn)[3]; + + // Left edge = midpoint of lower-left and upper-left + auto* left = node->mutable_left_edge(); + left->set_x((ll.x() + ul.x()) * 0.5f); + left->set_y((ll.y() + ul.y()) * 0.5f); + left->set_z((ll.z() + ul.z()) * 0.5f); + + // Right edge = midpoint of lower-right and upper-right + auto* right = node->mutable_right_edge(); + right->set_x((lr.x() + ur.x()) * 0.5f); + right->set_y((lr.y() + ur.y()) * 0.5f); + right->set_z((lr.z() + ur.z()) * 0.5f); + + // Update bounding box + min_x = std::min(min_x, center.x()); + min_y = std::min(min_y, center.y()); + min_z = std::min(min_z, center.z()); + max_x = std::max(max_x, center.x()); + max_y = std::max(max_y, center.y()); + max_z = std::max(max_z, center.z()); + + // Follow successor 0 (main driveline) + if (dn->getNumberOfSuccessors() > 0) + current = dn->getSuccessor(0); + else + break; + + visited++; + } while (current != 0 && visited < num_nodes); + + // Bounding box + auto* bmin = geom->mutable_bbox_min(); + bmin->set_x(min_x); + bmin->set_y(min_y); + bmin->set_z(min_z); + auto* bmax = geom->mutable_bbox_max(); + bmax->set_x(max_x); + bmax->set_y(max_y); + bmax->set_z(max_z); + + // Start position + heading + const DriveNode* start_node = graph->getNode(0); + if (start_node != nullptr) + { + auto* sp = geom->mutable_start_position(); + sp->set_x(start_node->getCenter().x()); + sp->set_y(start_node->getCenter().y()); + sp->set_z(start_node->getCenter().z()); + + // Heading from node 0 toward its successor + if (start_node->getNumberOfSuccessors() > 0) + { + geom->set_start_heading( + start_node->getAngleToSuccessor(0)); + } + } + + Log::info("Telemetry", "Track geometry: %u nodes, bbox=(%.0f,%.0f)-(%.0f,%.0f)", + visited, min_x, min_z, max_x, max_z); + } + sendFrame(frame); Log::info("Telemetry", "Race started: game_id=%s track=%s karts=%d", m_game_id.c_str(), rm->getTrackName().c_str(), num_karts);