Files
TurboSu/docs/ACC_DATA_FORMAT.md

435 lines
13 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 📡 ACC Broadcasting API 完整规范
## 一、概述
ACC 有两种遥测数据通道:
| 通道 | 协议 | 用途 |
|---|---|---|
| **Broadcasting API** | UDP(双向) | 广播/观战、实时计时、多车数据 |
| **Shared Memory** | 共享内存(Windows) | 仪表盘、运动平台、FFB(仅玩家车辆) |
SDK 路径:`steamapps/common/Assetto Corsa Competizione/sdk/broadcasting/`
---
## 二、启用 Broadcasting
### 配置文件
编辑 `文档/Assetto Corsa Competizione/Config/broadcasting.json`**必须 UTF-16LE BOM 编码**):
```json
{
"updListenerPort": 9000,
"connectionPassword": "asd",
"commandPassword": ""
}
```
| 字段 | 说明 |
|---|---|
| `updListenerPort` | ACC 监听的 UDP 端口(默认 9000 |
| `connectionPassword` | 客户端连接密码 |
| `commandPassword` | 控制命令密码(留空则所有已连接客户端都可发送命令) |
### 测试客户端
运行 `sdk/broadcasting/Testclient/ksBroadcastingTestClient.exe`,输入端口和密码后点击 Connect 即可验证。
---
## 三、协议规范
### 基本规则
- **字节序**Little Endian
- **协议版本**`BROADCASTING_PROTOCOL_VERSION = 2`
- **字符串编码**:UTF-8,前缀 `uint16` 长度字段
- **通信流程**:客户端 → ACC 发起注册 → ACC 回传数据流
### 数据序列化规则
| 类型 | 字节数 |
|---|---|
| `byte` / `int8` | 1 |
| `uint16` / `int16` | 2 |
| `int32` / `uint32` | 4 |
| `float32` | 4 |
| `string` | 2(长度)+ NUTF-8 内容) |
### Lap 结构体(通用圈速格式)
```
int32 LaptimeMS // 圈速(ms)Int32.MaxValue = 无圈速
uint16 CarIndex // 车辆索引
uint16 DriverIndex // 车手索引
uint8 SplitCount // 分段数(通常 3)
int32[] Splits // 各分段成绩(ms)Int32.MaxValue = 无效
uint8 IsInvalid // 0=有效, 1=无效
uint8 IsValidForBest // 0=不可作最佳圈, 1=可作最佳圈
uint8 IsOutLap // 0=非出场圈, 1=出场圈
uint8 IsInLap // 0=非回场圈, 1=回场圈
```
---
## 四、出站消息(客户端 → ACC)
所有消息首字节为消息类型。
| 类型 ID | 消息名 | 说明 |
|---|---|---|
| `1` | **REGISTER_COMMAND_APPLICATION** | 注册连接(必须最先发送) |
| `9` | UNREGISTER_COMMAND_APPLICATION | 取消注册 |
| `10` | **REQUEST_ENTRY_LIST** | 请求参赛者列表 |
| `11` | **REQUEST_TRACK_DATA** | 请求赛道数据 |
| `49` | CHANGE_HUD_PAGE | 切换 HUD 页面 |
| `50` | **CHANGE_FOCUS** | 切换焦点车辆/摄像机 |
| `51` | **INSTANT_REPLAY_REQUEST** | 请求即时回放 |
| `52` | PLAY_MANUAL_REPLAY_HIGHLIGHT | (预留) |
| `60` | SAVE_MANUAL_REPLAY_HIGHLIGHT | (预留) |
### 1. REGISTER_COMMAND_APPLICATIONID=1
```
byte 1 // 消息类型
byte BROADCASTING_PROTOCOL_VERSION // = 2
string DisplayName // 显示名称
string ConnectionPassword // 连接密码(匹配 broadcasting.json
int32 RealtimeUpdateInterval // 实时更新间隔(ms),建议 250
string CommandPassword // 命令密码
```
### 2. CHANGE_FOCUSID=50
```
byte 50 // 消息类型
int32 ConnectionId // 连接 ID
uint8 HasCarChange // 0=不变, 1=切换车辆
uint16 CarIndex // 目标车辆索引(仅 HasCarChange=1
uint8 HasCameraChange // 0=不变, 1=切换摄像机
string CameraSet // 摄像机集合名
string Camera // 摄像机名
```
### 3. INSTANT_REPLAY_REQUESTID=51
```
byte 51 // 消息类型
int32 ConnectionId
float32 StartSessionTime // 回放起点(会话时间,ms)
float32 DurationMS // 回放时长(ms)
int32 InitialFocusedCar // 初始焦点车辆(-1 = 保持当前)
string InitialCameraSet
string InitialCamera
```
### 4. REQUEST_ENTRY_LISTID=10/ REQUEST_TRACK_DATAID=11
```
byte 10 或 11
int32 ConnectionId
```
---
## 五、入站消息(ACC → 客户端)
| 类型 ID | 消息名 | 说明 |
|---|---|---|
| `1` | **REGISTRATION_RESULT** | 注册结果 |
| `2` | **REALTIME_UPDATE** | 会话实时信息(全局) |
| `3` | **REALTIME_CAR_UPDATE** | 车辆实时信息(每车) |
| `4` | **ENTRY_LIST** | 参赛者索引列表 |
| `5` | **TRACK_DATA** | 赛道和摄像机数据 |
| `6` | **ENTRY_LIST_CAR** | 单辆车详细信息 |
| `7` | **BROADCASTING_EVENT** | 广播事件 |
### 1. REGISTRATION_RESULTID=1
```
byte 1
int32 ConnectionId // 分配的连接 ID(后续请求必须携带)
uint8 ConnectionSuccess // 0=失败, 1=成功
uint8 IsReadOnly // 0=可读写(即拥有 commandPassword
string ErrorMessage // 错误信息
```
成功后应立即发送 `REQUEST_ENTRY_LIST``REQUEST_TRACK_DATA`
---
### 2. REALTIME_UPDATEID=2
```
byte 2
uint16 EventIndex // 赛事索引
uint16 SessionIndex // 会话索引
uint8 SessionType // 见下表
uint8 Phase // 会话阶段(见下表)
float32 SessionTime // 会话已过时间 (ms)
float32 SessionEndTime // 会话剩余时间 (ms)
int32 FocusedCarIndex // 当前焦点车辆
string ActiveCameraSet // 当前摄像机集合
string ActiveCamera // 当前摄像机
string CurrentHUDPage // 当前 HUD 页面
uint8 IsReplayPlaying // 是否回放中
// 以下仅 IsReplayPlaying=1 时存在:
float32 ReplaySessionTime // 回放中的会话时间
float32 ReplayRemainingTime // 回放剩余时间
int32 ReplayFocusedCar
// 始终存在:
uint16 TimeOfDay // 时间 hh*100+mm
uint8 AmbientTemp // 环境温度 (°C)
uint8 TrackTemp // 赛道温度 (°C)
uint8 Clouds // 云量(÷10,即 0.0~1.0
uint8 RainLevel // 降雨量(÷10)
uint8 Wetness // 路面湿度(÷10)
Lap BestSessionLap // 当前会话最佳圈速
```
#### RaceSessionType 枚举
| 值 | 类型 |
|---|---|
| 0 | Practice(练习) |
| 4 | Qualifying(排位赛) |
| 9 | Superpole(超级杆位) |
| 10 | Race(正赛) |
| 11 | Hotlap(单圈冲刺) |
| 12 | Hotstint(阶段冲刺) |
| 13 | HotlapSuperpole |
| 14 | Replay(回放) |
#### SessionPhase 枚举
| 值 | 阶段 |
|---|---|
| 0 | NONE |
| 1 | Starting |
| 2 | PreFormation |
| 3 | FormationLap(编队圈) |
| 4 | PreSession |
| 5 | **Session**(绿灯起跑后) |
| 6 | SessionOver |
| 7 | PostSession |
| 8 | ResultUI |
---
### 3. REALTIME_CAR_UPDATEID=3
**最重要的数据包**—每辆车独立发送。
```
byte 3
uint16 CarIndex // 车辆索引(对应 EntryList
uint16 DriverIndex // 当前车手索引
uint8 DriverCount // 该车车手总数
int8 Gear // -1=R, 0=N, 1~6...
float32 WorldPosX // 世界坐标 X(始终为 0)
float32 WorldPosY // 世界坐标 Y(始终为 0)
float32 Yaw // 偏航角(始终为 0)
uint8 CarLocation // 位置枚举(见下)
uint16 Kmh // 速度 (km/h)
uint16 Position // 排名(1-based
uint16 CupPosition // 组别排名(1-based
uint16 TrackPosition // 赛道位置序号(始终为 0)
float32 SplinePosition // 赛道位置 0.0~1.0
uint16 Laps // 已完成圈数
int32 Delta // 与最佳圈速的实时差距 (ms)
Lap BestSessionLap // 该车最佳圈速
Lap LastLap // 上一圈
Lap CurrentLap // 当前圈(时间持续更新,分段不填充)
```
#### CarLocation 枚举
| 值 | 位置 |
|---|---|
| 0 | NONE |
| 1 | **Track**(赛道上) |
| 2 | Pitlane(维修区通道) |
| 3 | PitEntry(进站入口) |
| 4 | PitExit(出站出口) |
---
### 4. ENTRY_LISTID=4+ ENTRY_LIST_CARID=6
**两步接收**:先收索引列表,再逐车收详情。
#### ENTRY_LIST 结构:
```
byte 4
int32 ConnectionId
uint16 CarEntryCount
uint16[] CarIndexes // 车辆索引数组
uint16 DriverEntryCount
uint16[] DriverIndexes // 保留字段
```
#### ENTRY_LIST_CAR 结构:
```
byte 6
uint16 CarIndex // 对应 ENTRY_LIST 中的索引
uint8 CarModelType // 车型(见下)
string TeamName // 车队名
int32 RaceNumber // 车号
string TeamCarName // 车型名称
string DisplayName // 显示名
uint8 CupCategory // 组别:0=Overall/Pro, 1=ProAm, 2=Am, 3=Silver, 4=National
uint8 CurrentDriverId // 当前车手 ID
uint16 Nationality // 国籍(见附录)
uint8 DriversOnCarCount // 该车手数量
// 每个车手:
uint16 DriverIndex
uint8 HasDriverInfo // 0/1
string FirstName
string LastName
string Nickname
string ShortName // 缩写(如 "VER"
uint8 Category // 3=Platinum, 2=Gold, 1=Silver, 0=Bronze
uint16 Nationality
```
#### CarModelType(部分)
| 值 | 车型 |
|---|---|
| 1 | Mercedes-AMG GT3 |
| 2 | Ferrari 488 GT3 |
| 15 | Lexus RC F GT3 |
| 16 | Lamborghini Huracán GT3 |
| 19 | Audi R8 LMS GT3 |
| 20 | Aston Martin Vantage GT3 |
| 23 | Porsche 911 GT3 R |
---
### 5. TRACK_DATAID=5
```
byte 5
int32 ConnectionId
string TrackName // 赛道名
int32 TrackId // 赛道 ID(见下)
int32 TrackMeters // 赛道长度 (m)
uint8 CameraSetCount
// 每个摄像机集合:
string CameraSetName
uint8 CameraCount
string[] CameraNames // 逐个摄像机名
uint8 HUDPageCount
string[] HUDPageNames
```
#### TrackId(部分)
| ID | 赛道 |
|---|---|
| 1 | Brands Hatch |
| 2 | Spa-Francorchamps |
| 3 | Monza |
| 4 | Misano |
| 5 | Paul Ricard |
| 6 | Silverstone |
| 7 | Hungaroring |
| 8 | Nürburgring |
| 9 | Barcelona |
| 10 | Zolder |
| 11 | Zandvoort |
| 13 | Mount Panorama (Bathurst) |
| 14 | Laguna Seca |
| 15 | Suzuka |
---
### 6. BROADCASTING_EVENTID=7
```
byte 7
uint8 Type // 事件类型
string Msg // 事件消息(常为圈速字符串)
int32 TimeMs // 自连接建立以来的时间 (ms)
int32 CarId // 相关车辆 ID
```
| 事件 Type | 说明 |
|---|---|
| 5 | LapCompleted(完成一圈) |
| 6 | BestSessionLap(全场最佳圈) |
| 7 | BestPersonalLap(个人最佳圈) |
---
## 六、Shared Memory API(补充)
用于本地仪表盘/运动平台,仅含玩家车辆数据。
### 三个内存页
| 页 | 大小 | 更新频率 | 内容 |
|---|---|---|---|
| **SPageFilePhysics** | ~800 B | 物理步进 | 速度、油门、刹车、G力、胎温等 |
| **SPageFileGraphic** | ~852 B | 图形帧率 | 圈速、排名、旗语、天气、油耗等 |
| **SPageFileStatic** | ~688 B | 固定 | 车辆名、赛道、最大RPM等 |
### Physics 关键字段
| 字段 | 类型 | 说明 |
|---|---|---|
| `gas` | float | 油门 0.0~1.0 |
| `brake` | float | 刹车 0.0~1.0 |
| `gear` | int | 档位 |
| `rpm` | int | 引擎转速 |
| `speedKmh` | float | 速度 |
| `steerAngle` | float | 转向角 |
| `wheelPressure[4]` | float | 胎压 |
| `tyreCoreTemp[4]` | float | 轮胎内核温度 |
| `brakeTemp[4]` | float | 刹车温度 |
| `carDamage` | struct | 车辆损伤 |
| `fuel` | float | 油量 (L) |
| `abs` | float | ABS 作用量 |
| `tc` | float | TC 作用量 |
| `localVelocity` | Vector3f | 局部速度 |
| `localAngularVel` | Vector3f | 局部角速度 |
| `gForce` | Vector3f | G力 |
### Graphics 关键字段
| 字段 | 类型 | 说明 |
|---|---|---|
| `status` | enum | AC_OFF=0, AC_LIVE=1 等 |
| `sessionType` | enum | 同 Broadcasting |
| `currentTime` | int | 当前圈速 (ms) |
| `lastTime` | int | 上一圈 (ms) |
| `bestTime` | int | 最佳圈 (ms) |
| `completedLaps` | int | 已完成圈数 |
| `position` | int | 排名 |
| `normalizedCarPosition` | float | 赛道位置 0.0~1.0 |
| `isInPit` | bool | 是否在维修区 |
| `flag` | enum | 旗语 |
| `fuelPerLap` | float | 每圈油耗 |
| `gapAhead` | int | 与前车差距 (ms) |
| `gapBehind` | int | 与后车差距 (ms) |
| `trackStatus` | string | Green/Fast/Optimum/Greasy/Damp/Wet/Flooded |
| `rainIntensity` | enum | 降雨强度 |
| `globalYellow` | bool | 黄旗 |
---
## 七、关键注意事项
1. **WorldPosX/Y 和 Yaw**Broadcasting API 中始终为 0(出于反作弊考虑),需要全车坐标请用 Shared Memory
2. **EntryList**:在首次连接时发送一次,新会话开始时不自动重发
3. **TrackData**:同样只在连接时发送一次,新会话不重发
4. **SplinePosition**:0.0~1.0 表示车辆在赛道上的归一化位置(维修区也有效)
5. **Lap.Splits**Int32.MaxValue 表示无效分段,超出分段数返回 0
6. **CarUpdate 中 Gear**:传输值 - 2 = 实际档位(传输 1 = -1/R,传输 2 = 0/N,传输 3 = 1 档...
7. **broadcasting.json 编码**:必须是 UTF-16LE with BOM,否则 ACC 无法读取