docs: add ACC UDP data format reference

This commit is contained in:
2026-07-27 18:41:56 +08:00
parent 2ca8dc53f4
commit 5bb4a82ae0
+434
View File
@@ -0,0 +1,434 @@
# 📡 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 无法读取