From 29d51ad59e2447022b41f656fe5199582df163dc Mon Sep 17 00:00:00 2001 From: AskaEth Date: Mon, 27 Jul 2026 18:46:01 +0800 Subject: [PATCH] docs: add iRacing telemetry data format reference --- docs/IRACING_DATA_FORMAT.md | 752 ++++++++++++++++++++++++++++++++++++ 1 file changed, 752 insertions(+) create mode 100644 docs/IRACING_DATA_FORMAT.md diff --git a/docs/IRACING_DATA_FORMAT.md b/docs/IRACING_DATA_FORMAT.md new file mode 100644 index 0000000..126b991 --- /dev/null +++ b/docs/IRACING_DATA_FORMAT.md @@ -0,0 +1,752 @@ + + +# 📡 iRacing Telemetry API(IRSDK)完整规范 + +## 一、概述 + +iRacing 的遥测系统通过 **共享内存映射文件(Memory-Mapped File)** 工作,所有数据是**只读**的。API 版本当前为 **IRSDK_VER = 2**。 + +### 三种数据通道 + +| 通道 | 形式 | 频率 | 说明 | +|---|---|---|---| +| **Live Telemetry** | 共享内存 `Local\IRSDKMemMapFileName` | 60Hz(或 360Hz) | 实时变量数据,三缓冲机制 | +| **Session String** | 共享内存中的 YAML 字符串 | 变更时更新 | 会话元数据(赛道、车手、天气等) | +| **Disk Telemetry (.ibt)** | 二进制文件 | 60Hz | 按 `Alt+L` 录制,结构等同于 Live 数据 | + +### 启用遥测 + +在 iRacing 的 `app.ini` 中确认: + +```ini +[External Telemetry] +enableTelemetry=1 # 启用遥测 +enableIRSDKTelemetry=1 # 启用 IRSDK +``` + +--- + +## 二、核心架构 + +### 共享内存布局 + +``` +[irsdk_header] + ↓ +[irsdk_varHeader[0] ... irsdk_varHeader[numVars-1]] + ↓ +[Session Info YAML String] + ↓ +[irsdk_varBuf[0]] → [Telemetry Data Line 0] +[irsdk_varBuf[1]] → [Telemetry Data Line 1] +[irsdk_varBuf[2]] → [Telemetry Data Line 2] +[irsdk_varBuf[3]] → [Telemetry Data Line 3] (IRSDK_MAX_BUFS = 4) +``` + +- **三缓冲**:模拟器写满一个缓冲区后立即切到下一个,给客户端 16ms+ 窗口来读取 +- **同步事件**:`Local\IRSDKDataValidEvent` — 新数据就绪时触发 + +### 字节序与编码 + +- **字节序**:Little Endian +- **YAML 编码**:UTF-8 +- **对齐**:16 字节对齐 +- **变量名最大长**:`IRSDK_MAX_STRING = 32` +- **描述最大长**:`IRSDK_MAX_DESC = 64` + +--- + +## 三、数据结构 + +### 1. irsdk_header(主头部) + +```c +struct irsdk_header { + int ver; // API 版本 = 2 + int status; // 位字段 (irsdk_stConnected = 1) + int tickRate; // tick 频率 (60 或 360) + + // 会话信息(变更时更新) + int sessionInfoUpdate; // 会话信息变更计数 + int sessionInfoLen; // YAML 字符串长度(字节) + int sessionInfoOffset; // 距头部的偏移 + + // 遥测变量 + int numVars; // 变量数量 + int varHeaderOffset; // varHeader 数组偏移 + int numBuf; // 缓冲区数量(4) + int bufLen; // 每行字节数 + int pad1[2]; // 16 字节对齐 + + irsdk_varBuf varBuf[IRSDK_MAX_BUFS]; // 4 个缓冲区 +}; +``` + +### 2. irsdk_varHeader(变量描述头) + +```c +struct irsdk_varHeader { + int type; // irsdk_VarType 枚举 + int offset; // 在缓冲区行中的偏移 + int count; // 数组元素数(标量 = 1) + bool countAsTime; + char pad[3]; // 16 字节对齐 + + char name[IRSDK_MAX_STRING]; // 变量名,如 "Speed" + char desc[IRSDK_MAX_DESC]; // 描述,如 "GPS vehicle speed" + char unit[IRSDK_MAX_STRING]; // 单位,如 "m/s" +}; +``` + +### 3. irsdk_varBuf(数据缓冲区) + +```c +struct irsdk_varBuf { + int tickCount; // 检测数据更新 + int bufOffset; // 距头部的偏移 + int pad[2]; // 16 字节对齐 +}; +``` + +### 4. irsdk_VarType(变量类型) + +| 枚举值 | 类型 | 字节数 | +|---|---|---| +| `irsdk_char = 0` | char | 1 | +| `irsdk_bool` | bool | 1 | +| `irsdk_int` | int32 | 4 | +| `irsdk_bitField` | bitfield (int32) | 4 | +| `irsdk_float` | float32 | 4 | +| `irsdk_double` | float64 | 8 | + +### 5. irsdk_diskSubHeader(仅 .ibt 文件) + +```c +struct irsdk_diskSubHeader { + time_t sessionStartDate; + double sessionStartTime; + double sessionEndTime; + int sessionLapCount; + int sessionRecordCount; +}; +``` + +--- + +## 四、Session String(YAML 结构) + +YAML 字符串通过 `irsdk_getSessionInfoStr()` 获取,包含以下顶级节点: + +### WeekendInfo + +```yaml +WeekendInfo: + TrackName: "suzuka" + TrackID: 123 + TrackLength: "5807 m" + TrackDisplayName: "Suzuka International Racing Course" + TrackCity: "Suzuka" + TrackCountry: "JPN" + TrackNumTurns: 18 + TrackPitSpeedLimit: "80 kph" + TrackType: "road" + TrackWeatherType: "Dynamic" + TrackSkies: "Partly Cloudy" + TrackSurfaceTemp: "38 C" + TrackAirTemp: "25 C" + TrackWindVel: "3 m/s" + TrackWindDir: "180 deg" + TrackRelativeHumidity: "55 %" + TrackFogLevel: "0 %" + SeriesID: 100 + SeasonID: 2024 + SessionID: 456 + SubSessionID: 789 + LeagueID: 0 + Official: 1 + RaceWeek: 5 + EventType: "Race" + Category: "Road" + SimMode: "full" + TeamRacing: 0 + MinDrivers: 6 + MaxDrivers: 26 + NumCarClasses: 1 + NumCarTypes: 3 + WeekendOptions: + NumStarters: 20 + StartingGrid: "2x2" + QualifyScoring: "single" + CourseCautions: "full" + StandingStart: 0 + Restarts: "singleFile" + WeatherType: "Dynamic" + Skies: "Partly Cloudy" + WindDirection: "180 deg" + WindSpeed: "3 m/s" + WeatherTemp: "25 C" + RelativeHumidity: "55 %" + FogLevel: "0 %" + Unofficial: 0 + IsFixedSetup: 0 + HardcoreLevel: 1 +``` + +### SessionInfo + +```yaml +SessionInfo: + Sessions: + - SessionNum: 0 + SessionLaps: "unlimited" + SessionTime: "30 min" + SessionType: "Practice" + ResultsPositions: [] + ResultsFastestLap: [] + - SessionNum: 1 + SessionLaps: "2 laps" + SessionTime: "10 min" + SessionType: "Lone Qualify" + - SessionNum: 2 + SessionLaps: "12 laps" + SessionTime: "30 min" + SessionType: "Race" +``` + +### DriverInfo + +```yaml +DriverInfo: + DriverCarIdx: 0 + DriverCarIdleRPM: 3500.0 + DriverCarRedLine: 9500.0 + DriverCarSLFirstRPM: 8500.0 + DriverCarSLShiftRPM: 9000.0 + DriverCarSLLastRPM: 9500.0 + DriverCarSLBlinkRPM: 9200.0 + Drivers: + - CarIdx: 0 + UserName: "John Doe" + AbbrevName: "J. Doe" + Initials: "JD" + CarNumber: "23" + CarPath: "mercedesamggt3" + CarClassID: 1 + IRating: 2500 + LicString: "A 4.99" + IsSpectator: 0 +``` + +### CameraInfo + +```yaml +CameraInfo: + Groups: + - GroupNum: 1 + GroupName: "TV1" + Cameras: + - CameraNum: 1 + CameraName: "TV1_Turn1" +``` + +### SplitTimeInfo + +```yaml +SplitTimeInfo: + Sectors: + - SectorNum: 0 + SectorStartPct: 0.0 + - SectorNum: 1 + SectorStartPct: 0.35 + - SectorNum: 2 + SectorStartPct: 0.70 +``` + +--- + +## 五、核心遥测变量列表(完整) + +### 🏎️ 玩家车辆控制 + +| 变量名 | 类型 | 单位 | 说明 | +|---|---|---|---| +| `SteeringWheelAngle` | float | rad | 方向盘转角 | +| `Throttle` | float | % (0-1) | 油门(处理后的) | +| `Brake` | float | % (0-1) | 刹车(处理后的) | +| `Clutch` | float | % (0-1) | 离合 | +| `Gear` | int | — | -1=R,0=N,1~n=前进档 | +| `RPM` | float | revs/min | 引擎转速 | +| `ThrottleRaw` | float | % (0-1) | 原始油门输入 | +| `BrakeRaw` | float | % (0-1) | 原始刹车输入 | +| `HandbrakeRaw` | float | % (0-1) | 原始手刹输入 | +| `Speed` | float | m/s | GPS 车速 | +| `OnPitRoad` | bool | — | 是否在维修区通道 | + +### 📐 位置与运动 + +| 变量名 | 类型 | 单位 | 说明 | +|---|---|---|---| +| `Yaw` | float | rad | 偏航角 | +| `YawNorth` | float | rad | 相对北方的偏航角 | +| `Pitch` | float | rad | 俯仰角 | +| `Roll` | float | rad | 侧倾角 | +| `YawRate` / `YawRate_ST` | float | rad/s | 偏航率(ST=子tick精度) | +| `PitchRate` / `PitchRate_ST` | float | rad/s | 俯仰率 | +| `RollRate` / `RollRate_ST` | float | rad/s | 侧倾率 | +| `VelocityX` / `VelocityX_ST` | float | m/s | X 方向速度 | +| `VelocityY` / `VelocityY_ST` | float | m/s | Y 方向速度 | +| `VelocityZ` / `VelocityZ_ST` | float | m/s | Z 方向速度 | +| `LatAccel` / `LatAccel_ST` | float | m/s² | 横向加速度 | +| `LongAccel` / `LongAccel_ST` | float | m/s² | 纵向加速度 | +| `VertAccel` / `VertAccel_ST` | float | m/s² | 垂向加速度 | + +> `_ST` 后缀变量提供 **子 tick 精度**,适合运动平台等精密场景。 + +### ⏱️ 圈速与计时 + +| 变量名 | 类型 | 单位 | 说明 | +|---|---|---|---| +| `Lap` | int | — | 当前圈号 | +| `LapCompleted` | int | — | 已完成圈数 | +| `LapDist` | float | m | 当前圈已跑距离 | +| `LapDistPct` | float | % | 当前圈完成百分比 | +| `RaceLaps` | int | — | 比赛中已完成圈数 | +| `LapBestLap` | int | — | 最佳圈号 | +| `LapBestLapTime` | float | s | 最佳圈速 | +| `LapLastLapTime` | float | s | 上一圈用时 | +| `LapCurrentLapTime` | float | s | 当前圈用时(F3 黑盒) | +| `LapBestNLapLap` | int | — | 最佳 N 圈均值的最后一圈 | +| `LapBestNLapTime` | float | s | 最佳 N 圈平均时间 | +| `LapLastNLapTime` | float | s | 最近 N 圈平均时间 | +| `LapLasNLapSeq` | int | — | 连续干净圈数 | + +### 🎯 Delta 时间 + +| 变量名 | 类型 | 单位 | 说明 | +|---|---|---|---| +| `LapDeltaToBestLap` | float | s | 与个人最佳圈的差距 | +| `LapDeltaToBestLap_DD` | float | s/s | 差距变化率 | +| `LapDeltaToBestLap_OK` | bool | — | delta 数据是否有效 | +| `LapDeltaToOptimalLap` | float | s | 与理论最佳圈的差距 | +| `LapDeltaToOptimalLap_DD` | float | s/s | 差距变化率 | +| `LapDeltaToOptimalLap_OK` | bool | — | 是否有效 | +| `LapDeltaToSessionBestLap` | float | s | 与全场最佳圈差距 | +| `LapDeltaToSessionBestLap_DD` | float | s/s | 差距变化率 | +| `LapDeltaToSessionBestLap_OK` | bool | — | 是否有效 | +| `LapDeltaToSessionOptimalLap` | float | s | 与全场理论最佳差距 | +| `LapDeltaToSessionLastlLap` | float | s | 与全场上一圈差距 | + +### ⛽ 引擎 & 燃油 + +| 变量名 | 类型 | 单位 | 说明 | +|---|---|---|---| +| `FuelLevel` | float | L | 剩余油量(升) | +| `FuelLevelPct` | float | % | 剩余油量百分比 | +| `FuelPress` | float | bar | 燃油压力 | +| `FuelUsePerHour` | float | kg/h | 瞬时油耗率 | +| `ManifoldPress` | float | bar | 进气歧管压力 | +| `OilLevel` | float | L | 机油液位 | +| `OilPress` | float | bar | 机油压力 | +| `OilTemp` | float | °C | 机油温度 | +| `WaterLevel` | float | L | 冷却液液位 | +| `WaterTemp` | float | °C | 冷却液温度 | +| `Voltage` | float | V | 电压 | +| `EngineWarnings` | bitfield | — | 引擎警告灯(见下文) | +| `BrakeABSactive` | bool | — | ABS 是否激活 | + +### 🛞 轮胎数据(每轮 LF/RF/LR/RR) + +设 `X` ∈ {LF, RF, LR, RR}: + +| 变量名 | 类型 | 单位 | 说明 | +|---|---|---|---| +| `XcoldPressure` | float | kPa | 冷胎压 | +| `Xpressure` | float | kPa | 当前胎压 | +| `XtempCL/M/R` | float | °C | 胎面左/中/右温度 | +| `XwearL/M/R` | float | % | 胎面左/中/右磨损 | +| `XbrakeLinePress` | float | bar | 刹车管压力 | +| `XshockDefl` | float | mm | 悬挂压缩量 | +| `XshockVel` | float | mm/s | 悬挂速度 | +| `XrideHeight` | float | mm | 行驶高度 | +| `Xspeed` | float | rad/s | 轮速 | + +### 🎛️ 力反馈 + +| 变量名 | 类型 | 单位 | 说明 | +|---|---|---|---| +| `SteeringWheelTorque` | float | N·m | 转向轴输出扭矩 | +| `SteeringWheelTorque_ST` | float | N·m | 转向轴扭矩(子tick) | +| `SteeringWheelPctTorque` | float | % | FFB 扭矩百分比(无符号) | +| `SteeringWheelPctTorqueSign` | float | % | FFB 扭矩百分比(有符号) | +| `SteeringWheelPctTorqueSignStops` | float | % | FFB 扭矩百分比(含止挡) | +| `SteeringWheelPctDamper` | float | % | FFB 阻尼百分比 | +| `SteeringWheelAngleMax` | float | rad | 方向盘最大转角 | +| `SteeringWheelPeakForceNm` | float | N·m | FFB 峰值力映射 | +| `SteeringWheelMaxForceNm` | float | N·m | 最大力 | +| `SteeringWheelUseLinear` | bool | — | 是否线性模式 | + +### 🏁 会话状态 + +| 变量名 | 类型 | 单位 | 说明 | +|---|---|---|---| +| `SessionTime` | double | s | 当前会话已过时间 | +| `SessionTimeRemain` | double | s | 会话剩余时间 | +| `SessionTimeTotal` | double | s | 会话总时间 | +| `SessionLapsRemain` | int | — | 剩余圈数 | +| `SessionLapsRemainEx` | int | — | 扩展剩余圈数 | +| `SessionLapsTotal` | int | — | 总圈数 | +| `SessionNum` | int | — | 会话序号 | +| `SessionState` | int | — | 会话状态(见枚举) | +| `SessionUniqueID` | int | — | 会话唯一 ID | +| `SessionFlags` | bitfield | — | 旗语(见下文) | +| `SessionTick` | int | — | Tick 计数 | +| `SessionTimeOfDay` | float | s | 赛道时间 | + +### 🚩 旗语 & 状态 + +**SessionFlags** 位字段: + +| 位标记 | 含义 | +|---|---| +| `0x00000001` | 🏁 方格旗 | +| `0x00000002` | ⬜ 白旗 | +| `0x00000004` | 🟩 绿旗 | +| `0x00000008` | 🟨 黄旗 | +| `0x00000010` | 🟥 红旗 | +| `0x00000020` | 🟦 蓝旗 | +| `0x00000040` | 💥 碎片 | +| `0x00000100` | 🟨 黄旗挥动 | +| `0x00000200` | 绿旗前最后一圈 | +| `0x00004000` | ⚠️ Full Course Caution | +| `0x00010000` | ⬛ 黑旗 | +| `0x00020000` | ❌ DSQ | +| `0x10000000` | 🔴 发车灯隐藏 | +| `0x20000000` | 🔴 发车灯就绪 | +| `0x40000000` | 🔴 发车灯 Set | +| `0x80000000` | 🟢 发车灯 Go | + +**EngineWarnings** 位字段: + +| 位标记 | 含义 | +|---|---| +| `0x0001` | 水温警告 | +| `0x0002` | 燃油压力警告 | +| `0x0004` | 机油压力警告 | +| `0x0008` | 引擎熄火 | +| `0x0010` | Pit Speed Limiter | +| `0x0020` | 转速限制器激活 | +| `0x0040` | 油温警告 | + +### 🚗 多车数据(CarIdx 数组,最多 64 辆车) + +| 变量名 | 类型 | 说明 | +|---|---|---| +| `CarIdxLap` | int[] | 每辆车的圈数 | +| `CarIdxLapCompleted` | int[] | 每辆车已完成圈数 | +| `CarIdxLapDistPct` | float[] | 每辆车的位置百分比 | +| `CarIdxPosition` | int[] | 每辆车的排名 | +| `CarIdxClassPosition` | int[] | 组别排名 | +| `CarIdxClass` | int[] | 组别 ID | +| `CarIdxF2Time` | float[] | 与领先者的差距(或最快圈速) | +| `CarIdxEstTime` | float[] | 预计到达当前位置的时间 | +| `CarIdxLastLapTime` | float[] | 上一圈时间 | +| `CarIdxBestLapTime` | float[] | 最佳圈时间 | +| `CarIdxBestLapNum` | int[] | 最佳圈号 | +| `CarIdxSteer` | float[] | 方向盘转角 | +| `CarIdxRPM` | float[] | 引擎转速 | +| `CarIdxGear` | int[] | 档位 | +| `CarIdxOnPitRoad` | bool[] | 是否在维修区 | +| `CarIdxTrackSurface` | int[] | 赛道位置类型 | +| `CarIdxTrackSurfaceMaterial` | int[] | 路面材质 | +| `CarIdxTireCompound` | int[] | 轮胎配方 | +| `CarIdxP2P_Status` | bool[] | Push-to-Pass 状态 | +| `CarIdxP2P_Count` | int[] | Push-to-Pass 剩余次数 | + +### 🛑 进站 & 维修 + +| 变量名 | 类型 | 单位 | 说明 | +|---|---|---|---| +| `PitsOpen` | bool | — | 维修区是否开放 | +| `PitstopActive` | bool | — | 正在进站 | +| `PitRepairLeft` | float | s | 强制维修剩余时间 | +| `PitOptRepairLeft` | float | s | 可选维修剩余时间 | +| `PitSvFlags` | bitfield | — | 进站服务勾选 | +| `PitSvLFP/RFP/LRP/RRP` | float | kPa | 指定胎压 | +| `PitSvFuel` | float | L | 指定加油量 | +| `PitSvTireCompound` | int | — | 指定轮胎配方 | +| `FastRepairUsed` | int | — | 已用快速维修次数 | +| `FastRepairAvailable` | int | — | 可用快速维修次数 | +| `PlayerCarInPitStall` | bool | — | 玩家在维修位 | +| `PlayerCarPitSvStatus` | int | — | 进站服务状态 | + +**PitSvFlags** 位字段: + +| 位标记 | 含义 | +|---|---| +| `0x0001` | 左前换胎 | +| `0x0002` | 右前换胎 | +| `0x0004` | 左后换胎 | +| `0x0008` | 右后换胎 | +| `0x0010` | 加油 | +| `0x0020` | 撕膜 | +| `0x0040` | 快速维修 | + +### 🌦️ 天气 & 环境 + +| 变量名 | 类型 | 单位 | 说明 | +|---|---|---|---| +| `TrackTemp` | float | °C | 赛道温度(起终点) | +| `TrackTempCrew` | float | °C | 赛道温度(Pit 区) | +| `TrackWetness` | float | — | 赛道湿度级别 | +| `AirTemp` | float | °C | 空气温度 | +| `AirDensity` | float | kg/m³ | 空气密度 | +| `AirPressure` | float | Hg | 气压 | +| `WindVel` | float | m/s | 风速 | +| `WindDir` | float | rad | 风向 | +| `RelativeHumidity` | float | % | 相对湿度 | +| `FogLevel` | float | % | 雾级别 | +| `WeatherType` | int | — | 0=恒定,1=动态 | +| `Skies` | int | — | 0=晴,1=少云,2=多云,3=阴 | + +### 🎥 回放 & 系统 + +| 变量名 | 类型 | 说明 | +|---|---|---| +| `IsReplayPlaying` | bool | 是否回放中 | +| `ReplayFrameNum` | int | 回放当前帧号 | +| `ReplayFrameNumEnd` | int | 回放末尾帧号 | +| `ReplayPlaySpeed` | int | 回放速度 | +| `ReplayPlaySlowMotion` | bool | 是否慢动作 | +| `ReplaySessionTime` | double | 回放中的会话时间 | +| `ReplaySessionNum` | int | 回放会话序号 | +| `IsOnTrack` | bool | 玩家是否在赛道上 | +| `IsInGarage` | bool | 是否在车库 | +| `IsDiskLoggingEnabled` | bool | 磁盘遥测是否开启 | +| `IsDiskLoggingActive` | bool | 是否正在录制 .ibt | + +### 👥 车手变更(Team Racing) + +| 变量名 | 类型 | 说明 | +|---|---|---| +| `DCLapStatus` | int | Driver Change 圈数状态 | +| `DCDriversSoFar` | int | 已驾驶过的车手数 | + +### 📷 摄像机 + +| 变量名 | 类型 | 说明 | +|---|---|---| +| `CamCarIdx` | int | 当前焦点车辆索引 | +| `CamCameraNumber` | int | 当前摄像机编号 | +| `CamGroupNumber` | int | 当前摄像机组编号 | +| `CamCameraState` | bitfield | 摄像机状态位字段 | + +--- + +## 六、重要枚举汇总 + +### SessionState + +| 值 | 状态 | +|---|---| +| 0 | StateInvalid | +| 1 | StateGetInCar(上车中) | +| 2 | StateWarmup(暖胎圈) | +| 3 | StateParadeLaps(编队圈) | +| 4 | **StateRacing**(正赛中) | +| 5 | StateCheckered(方格旗) | +| 6 | StateCoolDown(冷却圈) | + +### TrkLoc(赛道位置) + +| 值 | 含义 | +|---|---| +| -1 | NotInWorld | +| 0 | OffTrack | +| 1 | InPitStall(维修区) | +| 2 | AproachingPits | +| 3 | OnTrack | + +### TrkSurf(路面材质) + +| 值 | 材质 | +|---|---| +| 0 | Undefined | +| 1-4 | Asphalt | +| 5-6 | Concrete | +| 7-8 | Racing Dirt | +| 9-10 | Paint | +| 11-14 | Rumble Strip(路肩) | +| 15-18 | Grass | +| 19-22 | Dirt | +| 23 | Sand | +| 24-25 | Gravel | +| 26 | Grasscrete | +| 27 | Astroturf | + +### TrackWetness(赛道湿度) + +| 值 | 级别 | +|---|---| +| 0 | Unknown | +| 1 | Dry | +| 2 | Mostly Dry | +| 3 | Very Lightly Wet | +| 4 | Lightly Wet | +| 5 | Moderately Wet | +| 6 | Very Wet | +| 7 | Extremely Wet | + +### PaceMode + +| 值 | 模式 | +|---|---| +| 0 | Single File Start | +| 1 | Double File Start | +| 2 | Single File Restart | +| 3 | Double File Restart | +| 4 | Not Pacing | + +### CarLeftRight + +| 值 | 含义 | +|---|---| +| 0 | Off | +| 1 | Clear(两侧无车) | +| 2 | Car Left | +| 3 | Car Right | +| 4 | Cars on Both Sides | +| 5 | 2 Cars Left | +| 6 | 2 Cars Right | + +--- + +## 七、SDK 客户端 API(C 语言接口) + +```c +// 初始化 / 关闭 +bool irsdk_startup(); +void irsdk_shutdown(); + +// 连接检测 +bool irsdk_isConnected(); + +// 获取头部 +const irsdk_header* irsdk_getHeader(); + +// 等待新数据并复制到本地缓冲区(推荐方式) +bool irsdk_waitForDataReady(int timeOut, char *data); + +// 获取会话 YAML 字符串 +const char* irsdk_getSessionInfoStr(); +int irsdk_getSessionInfoStrUpdate(); // 检测会话信息更新 + +// 获取变量头 +const irsdk_varHeader* irsdk_getVarHeaderPtr(); +const irsdk_varHeader* irsdk_getVarHeaderEntry(int index); + +// 按名称查找变量 +int irsdk_varNameToIndex(const char *name); +int irsdk_varNameToOffset(const char *name); + +// 获取指定缓冲区的数据 +const char* irsdk_getData(int index); +``` + +--- + +## 八、Broadcast Messages(远程控制) + +通过 Windows 消息 `IRSDK_BROADCASTMSG` 发送控制命令: + +### 摄像机控制 + +```c +// 切换摄像机:按位置 +irsdk_broadcastMsg(irsdk_BroadcastCamSwitchPos, carPosition, group, camera); + +// 切换摄像机:按车号 +irsdk_broadcastMsg(irsdk_BroadcastCamSwitchNum, driverNum, group, camera); + +// 设置摄像机状态 +irsdk_broadcastMsg(irsdk_BroadcastCamSetState, irsdk_CameraState, 0, 0); +``` + +### 回放控制 + +```c +// 设置播放速度 +irsdk_broadcastMsg(irsdk_BroadcastReplaySetPlaySpeed, speed, slowMotion, 0); + +// 跳转位置 +irsdk_broadcastMsg(irskd_BroadcastReplaySetPlayPosition, + irsdk_RpyPos_Begin, frameHigh, frameLow); + +// 搜索事件 +irsdk_broadcastMsg(irsdk_BroadcastReplaySearch, + irsdk_RpySrch_NextLap, 0, 0); + +// 搜索会话时间 +irsdk_broadcastMsg(irsdk_BroadcastReplaySearchSessionTime, + sessionNum, sessionTimeMS_high, sessionTimeMS_low); +``` + +### 进站控制 + +```c +// 清空所有勾选 +irsdk_broadcastMsg(irsdk_BroadcastPitCommand, irsdk_PitCommand_Clear, 0); + +// 加油(0 = 使用默认值) +irsdk_broadcastMsg(irsdk_BroadcastPitCommand, irsdk_PitCommand_Fuel, addLiters); + +// 换左前胎(指定胎压 kPa,0 = 默认) +irsdk_broadcastMsg(irsdk_BroadcastPitCommand, irsdk_PitCommand_LF, pressureKpa); + +// 换胎配方 +irsdk_broadcastMsg(irsdk_BroadcastPitCommand, irsdk_PitCommand_TC, compound); + +// 快速维修 +irsdk_broadcastMsg(irsdk_BroadcastPitCommand, irsdk_PitCommand_FR, 0); +``` + +### 遥测录制控制 + +```c +irsdk_broadcastMsg(irsdk_BroadcastTelemCommand, irsdk_TelemCommand_Start, 0, 0); +irsdk_broadcastMsg(irsdk_BroadcastTelemCommand, irsdk_TelemCommand_Stop, 0, 0); +irsdk_broadcastMsg(irsdk_BroadcastTelemCommand, irsdk_TelemCommand_Restart, 0, 0); +``` + +### 聊天宏 + +```c +irsdk_broadcastMsg(irsdk_BroadcastChatComand, irsdk_ChatCommand_Macro, macroNum, 0); +``` + +--- + +## 九、与 F1 24 / ACC 的对比 + +| 特性 | iRacing | F1 24 | ACC | +|---|---|---|---| +| **协议** | 共享内存 | UDP | UDP + 共享内存 | +| **更新频率** | 60Hz(可 360Hz) | 最高 60Hz | 物理步进 | +| **多车数据** | ✅ CarIdx 数组(≤64 辆车) | ✅ 22 辆车 | ✅ Broadcasting | +| **回放数据** | ✅ .ibt 文件 | ❌ | ❌ | +| **远程控制** | ✅ Broadcast Msg | ❌ | ✅ Camera/Focus | +| **写入支持** | ✅ 进站/摄像机/遥测 | ❌ | ✅ Camera/HUD | +| **变量动态性** | 每车/每会话不同 | 固定结构 | 固定结构 | +| **子 Tick 精度** | ✅ `_ST` 后缀变量 | ❌ | ❌ | +| **运动平台** | ✅ 完整扭矩/加速度 | ✅ Motion Ex | ✅ Shared Memory | + +--- + +## 十、关键注意事项 + +1. **变量动态性**:iRacing 的变量列表不是固定的—不同车辆/会话中可能不同,必须先读取 `varHeader` 来确定可用的变量和偏移量 +2. **只读**:所有遥测数据只读,不能通过 SDK 修改车辆参数(只能通过 Broadcast Message 控制进站选项) +3. **三缓冲**:务必在 `irsdk_waitForDataReady()` 返回后立即拷贝数据,不要直接引用共享内存 +4. **Session Info 更新**:通过 `sessionInfoUpdate` 计数器检测 YAML 字符串是否变化 +5. **.ibt 兼容**:磁盘遥测文件结构与 Live 相同,可用相同代码解析(多了 `irsdk_diskSubHeader`) +6. **启动时序**:先调用 `irsdk_startup()` → 等待 `irsdk_isConnected()` → 等待 `SessionState >= StateRacing` +7. **360Hz 模式**:部分车辆支持 360Hz 遥测,检查 `tickRate` 字段