From 2ca8dc53f4433de1a368b72e44cb55b58fb7a813 Mon Sep 17 00:00:00 2001 From: AskaEth Date: Mon, 27 Jul 2026 18:38:16 +0800 Subject: [PATCH] docs: add F1 24 UDP data format reference --- docs/F1_DATA_FORMAT.md | 318 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 318 insertions(+) create mode 100644 docs/F1_DATA_FORMAT.md diff --git a/docs/F1_DATA_FORMAT.md b/docs/F1_DATA_FORMAT.md new file mode 100644 index 0000000..68e8c5e --- /dev/null +++ b/docs/F1_DATA_FORMAT.md @@ -0,0 +1,318 @@ + +## 🏎️ F1 24 UDP Telemetry 规范总览 + +### 📌 官方文档 +- **官方规范 Word 文档**:[EA Forums — Data Output from F1 24 v27.2x.docx](https://forums.ea.com/t5/s/tghpe58374/attachments/tghpe58374/f1-24-general-discussion-en/4624/1/Data%20Output%20from%20F1%2024%20v27.2x.docx) +- **GitHub 开源解析库参考**:https://github.com/MacManley/f1-24-udp + +--- + +## ⚙️ 游戏设置 + +在游戏中启用 UDP 遥测:**Game Options → Settings → Telemetry Settings** + +| 设置项 | 推荐值 | +|---|---| +| `UDP Telemetry` | On | +| `UDP Broadcast Mode` | Off(多设备时可开启) | +| `UDP IP Address` | 接收端 IP(本机用 `127.0.0.1`) | +| `Port` | `20777`(默认) | +| `UDP Send Rate` | `20Hz`(默认,最高 60Hz) | +| `UDP Format` | `2024` | + +> ⚠️ 注意:游戏仅在玩家进入 **计时圈(timed lap)** 后才开始发送有效遥测数据。 + +--- + +## 📦 数据编码 + +- **字节序**:Little Endian +- **对齐**:packed(无填充) +- **最大车辆数**:22 + +### 数据类型 + +| 类型 | 说明 | +|---|---| +| `uint8` / `int8` | 无符号/有符号 8-bit | +| `uint16` / `int16` | 无符号/有符号 16-bit | +| `uint32` | 无符号 32-bit | +| `uint64` | 无符号 64-bit | +| `float` | 32-bit 浮点 | + +--- + +## 📋 包头结构(PacketHeader) + +**大小:29 bytes** + +```c +struct PacketHeader { + uint16 m_packetFormat; // 2024 + uint8 m_gameYear; // 年份后两位,如 24 + uint8 m_gameMajorVersion; // 主版本号 "X.00" + uint8 m_gameMinorVersion; // 次版本号 "1.XX" + uint8 m_packetVersion; // 包类型版本号,从 1 开始 + uint8 m_packetId; // 包类型 ID(见下表) + uint64 m_sessionUID; // 会话唯一 ID + float m_sessionTime; // 会话时间戳 + uint32 m_frameIdentifier; // 帧标识符 + uint32 m_overallFrameIdentifier; // 全局帧标识符(Flashback 不回退) + uint8 m_playerCarIndex; // 玩家车辆索引 + uint8 m_secondaryPlayerCarIndex; // 分屏第二玩家索引(255 = 无) +}; +``` + +--- + +## 🆔 包类型 ID 汇总 + +| ID | 包名称 | 说明 | 频率 | 大小 | +|---|---|---|---|---| +| 0 | **Motion** | 所有车辆物理运动数据 | 菜单设定频率 | 1349 B | +| 1 | **Session** | 会话信息(赛道、剩余时间) | 2/秒 | 753 B | +| 2 | **Lap Data** | 所有车辆圈速数据 | 菜单设定频率 | 1285 B | +| 3 | **Event** | 会话事件 | 事件触发时 | 45 B | +| 4 | **Participants** | 参与者列表 | 每 5 秒 | 1350 B | +| 5 | **Car Setups** | 车辆调校参数 | 2/秒 | 1133 B | +| 6 | **Car Telemetry** | 遥测数据(速度/油门/DRS等) | 菜单设定频率 | 1352 B | +| 7 | **Car Status** | 车辆状态(燃油/ERS等) | 菜单设定频率 | 1239 B | +| 8 | **Final Classification** | 最终排名 | 结果界面每 5 秒 | 1020 B | +| 9 | **Lobby Info** | 多人游戏大厅信息 | 大厅中 2/秒 | 1306 B | +| 10 | **Car Damage** | 车辆损伤数据 | 10/秒 | 953 B | +| 11 | **Session History** | 圈速和轮胎历史 | 20/秒(轮询车辆) | 1460 B | +| 12 | **Tyre Sets** | 轮胎组详细数据 | 2/秒 | 231 B | +| 13 | **Motion Ex** | 玩家车辆扩展运动数据 | 菜单设定频率 | 237 B | +| 14 | **Time Trial** | 计时赛专用数据 | 1/秒(仅TT) | 101 B | + +--- + +## 🔍 各包数据结构详解 + +### 1. Motion Packet(ID=0) +包含所有 22 辆车的物理数据。 + +```c +struct CarMotionData { + float m_worldPositionX, m_worldPositionY, m_worldPositionZ; // 世界位置 (m) + float m_worldVelocityX, m_worldVelocityY, m_worldVelocityZ; // 世界速度 (m/s) + int16 m_worldForwardDirX, m_worldForwardDirY, m_worldForwardDirZ; // 前向向量(÷32767 归一化) + int16 m_worldRightDirX, m_worldRightDirY, m_worldRightDirZ; // 右向向量 + float m_gForceLateral, m_gForceLongitudinal, m_gForceVertical; // G 力分量 + float m_yaw, m_pitch, m_roll; // 角度 (rad) +}; +// PacketMotionData: PacketHeader + CarMotionData[22] +``` + +--- + +### 2. Session Packet(ID=1) +包含当前会话完整信息,如天气、温度、赛道、规则、辅助设置等。 + +关键字段: +- `m_weather`: 0=晴, 1=少云, 2=阴, 3=小雨, 4=大雨, 5=暴雨 +- `m_trackId`: 赛道 ID(-1=未知,见附录) +- `m_sessionType`: 会话类型 +- `m_formula`: 0=F1 Modern, 1=F1 Classic, 2=F2, 3=F1 Generic, 4=Beta, 6=Esports, 8=F1 World, 9=F1 Elimination +- `m_safetyCarStatus`: 0=无, 1=实体安全车, 2=虚拟安全车, 3=编队圈 +- `m_weatherForecastSamples[64]`: 天气预测(最多 64 样本,适配冲刺赛周末) +- `m_weekendStructure[12]`: 周末赛程结构 +- `m_sector2LapDistanceStart` / `m_sector3LapDistanceStart`: 赛段起点距离 + +--- + +### 3. Lap Data Packet(ID=2) +```c +struct LapData { + uint32 m_lastLapTimeInMS; // 上一圈时间 (ms) + uint32 m_currentLapTimeInMS; // 当前圈耗时 (ms) + uint16 m_sector1TimeMSPart; // S1 毫秒部分 + uint8 m_sector1TimeMinutesPart; // S1 分钟部分 + uint16 m_sector2TimeMSPart; // S2 毫秒部分 + uint8 m_sector2TimeMinutesPart; // S2 分钟部分 + uint16 m_deltaToCarInFrontMSPart; // 与前车差距毫秒 + uint8 m_deltaToCarInFrontMinutesPart; // 与前车差距分钟 + uint16 m_deltaToRaceLeaderMSPart; // 与领跑者差距毫秒 + uint8 m_deltaToRaceLeaderMinutesPart; // 与领跑者差距分钟 + float m_lapDistance; // 当前圈已跑距离 (m) + float m_totalDistance; // 总行驶距离 (m) + float m_safetyCarDelta; // 安全车时间差 (s) + uint8 m_carPosition; // 赛道排名 + uint8 m_currentLapNum; // 当前圈数 + uint8 m_pitStatus; // 0=无, 1=进站中, 2=维修区 + uint8 m_numPitStops; // 已进站次数 + uint8 m_sector; // 0=S1, 1=S2, 2=S3 + uint8 m_currentLapInvalid; // 0=有效, 1=无效 + uint8 m_penalties; // 累计罚时 (s) + uint8 m_driverStatus; // 0=车库, 1=飞行圈, 2=回场圈, 3=出场圈, 4=赛道上 + uint8 m_resultStatus; // 0-7 (invalid/active/finished/DNF/DSQ等) + float m_speedTrapFastestSpeed; // 速度陷阱最快速度 (km/h) + // ... 等 +}; +``` + +--- + +### 4. Event Packet(ID=3) +事件代码: + +| 代码 | 事件 | 代码 | 事件 | +|---|---|---|---| +| `SSTA` | 会话开始 | `SEND` | 会话结束 | +| `FTLP` | 最快圈速 | `RTMT` | 退赛 | +| `DRSE` | DRS 启用 | `DRSD` | DRS 禁用 | +| `TMPT` | 队友进站 | `CHQF` | 方格旗 | +| `RCWN` | 冠军产生 | `PENA` | 处罚发出 | +| `SPTP` | 速度陷阱触发 | `STLG` | 发车灯 | +| `LGOT` | 灯灭起跑 | `DTSV` | Drive-through 已执行 | +| `SGSV` | Stop-Go 已执行 | `FLBK` | Flashback | +| `BUTN` | 按钮状态 | `RDFL` | 红旗 | +| `OVTK` | 超车 | `SCAR` | 安全车事件 | +| `COLL` | 碰撞事件 | | | + +--- + +### 5. Car Telemetry Packet(ID=6) +```c +struct CarTelemetryData { + uint16 m_speed; // 速度 (km/h) + float m_throttle; // 油门 (0.0~1.0) + float m_steer; // 转向 (-1.0~1.0) + float m_brake; // 刹车 (0.0~1.0) + uint8 m_clutch; // 离合 (0~100) + int8 m_gear; // 档位 (1-8, N=0, R=-1) + uint16 m_engineRPM; // 引擎转速 + uint8 m_drs; // DRS: 0=关, 1=开 + uint8 m_revLightsPercent; // 转速灯百分比 + uint16 m_revLightsBitValue; // 转速灯位值 + uint16 m_brakesTemperature[4]; // 刹车温度 (°C) + uint8 m_tyresSurfaceTemperature[4]; // 胎面温度 (°C) + uint8 m_tyresInnerTemperature[4]; // 胎内温度 (°C) + uint16 m_engineTemperature; // 引擎温度 (°C) + float m_tyresPressure[4]; // 胎压 (PSI) + uint8 m_surfaceType[4]; // 路面类型 +}; +``` + +--- + +### 6. Car Status Packet(ID=7) +```c +struct CarStatusData { + uint8 m_tractionControl; // 0=关, 1=中, 2=全 + uint8 m_antiLockBrakes; // 0=关, 1=开 + uint8 m_fuelMix; // 0=Lean, 1=Standard, 2=Rich, 3=Max + uint8 m_frontBrakeBias; // 前刹车比 (%) + float m_fuelInTank; // 燃油量 (kg) + float m_fuelCapacity; // 油箱容量 + float m_fuelRemainingLaps; // 剩余油量可跑圈数 + uint8 m_drsAllowed; // DRS 是否允许 + uint16 m_drsActivationDistance; // DRS 激活距离 (m) + uint8 m_actualTyreCompound; // 实际轮胎配方 (16=C5, 17=C4, 18=C3, 19=C2, 20=C1, 21=C0, 7=半雨, 8=全雨) + uint8 m_visualTyreCompound; // 视觉轮胎配方 (16=软, 17=中, 18=硬) + uint8 m_tyresAgeLaps; // 轮胎使用圈数 + int8 m_vehicleFiaFlags; // FIA 旗帜 (-1=未知, 0=无, 1=绿, 2=蓝, 3=黄) + float m_enginePowerICE; // 内燃机功率 (W) + float m_enginePowerMGUK; // MGU-K 功率 (W) + float m_ersStoreEnergy; // ERS 储能 (J) + uint8 m_ersDeployMode; // 0=无, 1=Medium, 2=Hotlap, 3=Overtake + float m_ersHarvestedThisLapMGUK; // MGU-K 回收能量 + float m_ersHarvestedThisLapMGUH; // MGU-H 回收能量 + float m_ersDeployedThisLap; // 已使用 ERS 能量 +}; +``` + +--- + +### 7. Car Damage Packet(ID=10) +```c +struct CarDamageData { + float m_tyresWear[4]; // 轮胎磨损 (%) + uint8 m_tyresDamage[4]; // 轮胎损伤 (%) + uint8 m_brakesDamage[4]; // 刹车损伤 (%) + uint8 m_frontLeftWingDamage; // 前左翼损伤 (%) + uint8 m_frontRightWingDamage; // 前右翼损伤 (%) + uint8 m_rearWingDamage; // 尾翼损伤 (%) + uint8 m_floorDamage; // 底板损伤 (%) + uint8 m_diffuserDamage; // 扩散器损伤 (%) + uint8 m_sidepodDamage; // 侧箱损伤 (%) + uint8 m_drsFault; // DRS 故障 (0/1) + uint8 m_ersFault; // ERS 故障 (0/1) + uint8 m_gearBoxDamage; // 变速箱损伤 (%) + uint8 m_engineDamage; // 引擎损伤 (%) + uint8 m_engineMGUHWear; // MGU-H 磨损 (%) + uint8 m_engineESWear; // ES 磨损 (%) + uint8 m_engineCEWear; // CE 磨损 (%) + uint8 m_engineICEWear; // ICE 磨损 (%) + uint8 m_engineMGUKWear; // MGU-K 磨损 (%) + uint8 m_engineTCWear; // TC 磨损 (%) + uint8 m_engineBlown; // 引擎爆缸 (0/1) + uint8 m_engineSeized; // 引擎卡死 (0/1) +}; +``` + +--- + +### 8. Motion Ex Packet(ID=13)— 运动平台关键包 + +专为 **运动模拟平台(D-BOX 等)** 设计,包含更多细节: + +```c +float m_suspensionPosition[4]; // 悬挂位置 [RL, RR, FL, FR] +float m_suspensionVelocity[4]; // 悬挂速度 +float m_suspensionAcceleration[4]; // 悬挂加速度 +float m_wheelSpeed[4]; // 各轮速度 +float m_wheelSlipRatio[4]; // 滑移率 +float m_wheelSlipAngle[4]; // 滑移角 +float m_wheelLatForce[4]; // 横向力 +float m_wheelLongForce[4]; // 纵向力 +float m_wheelVertForce[4]; // 垂向力 +float m_heightOfCOGAboveGround; // 重心高度 +float m_localVelocityX/Y/Z; // 局部速度 +float m_angularVelocityX/Y/Z; // 角速度 (rad/s) +float m_angularAccelerationX/Y/Z; // 角加速度 (rad/s²) +float m_frontWheelsAngle; // 前轮转角 (rad) +float m_frontAeroHeight; // 前底盘高度 +float m_rearAeroHeight; // 后底盘高度 +float m_frontRollAngle; // 前悬挂侧倾角 +float m_rearRollAngle; // 后悬挂侧倾角 +float m_chassisYaw; // 底盘偏航角 (rad) — 可用于判断侧滑 +``` + +--- + +### 9. 其余包简介 + +| 包 | 关键内容 | +|---|---| +| **Final Classification (8)** | 最终排名、圈数、积分、最佳圈速、轮胎使用记录 | +| **Lobby Info (9)** | 多人游戏大厅的玩家信息 | +| **Session History (11)** | 每辆车的全部圈速历史 + 轮胎使用历史(最多 100 圈) | +| **Tyre Sets (12)** | 轮胎组详情:配方、磨损度、可用性、圈速差等 | +| **Time Trial (14)** | 计时赛专属:玩家最佳、个人最佳、对手数据 | + +--- + +## 🔒 隐私:Your Telemetry 设置 + +当玩家设置 `Your Telemetry = Restricted` 时,以下数据对其他玩家**归零**: +- **Car Status**:燃油、ERS 相关数据 +- **Car Damage**:所有损伤数据 +- **Tyre Sets**:全部轮胎组数据 + +--- + +## 🆕 F1 24 相比 F1 23 的主要变化 + +1. 会话包中新增模拟/规则选项 +2. 新增安全车事件详情(`SCAR`) +3. 大厅和参与者包中新增在线名称、Your Telemetry、F1 World Tech Level +4. 圈速包中新增与前车/领先者的分钟差距字段 +5. 最终排名包改为结果界面每 5 秒重复发送 +6. 新增 **Time Trial 包**(ID=14) +7. Motion Ex 包新增底盘高度(plank height)、悬挂侧倾角、底盘偏航角 +8. 新增碰撞事件(`COLL`) +9. 新增周末赛程结构(`m_weekendStructure`) +10. 天气预测数组从 56 扩展到 64 +11. 圈速包新增速度陷阱数据 +12. Car Setup 包新增发动机制动参数 + 下次进站前翼值