13 KiB
13 KiB
📡 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 编码):
{
"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(长度)+ N(UTF-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_APPLICATION(ID=1)
byte 1 // 消息类型
byte BROADCASTING_PROTOCOL_VERSION // = 2
string DisplayName // 显示名称
string ConnectionPassword // 连接密码(匹配 broadcasting.json)
int32 RealtimeUpdateInterval // 实时更新间隔(ms),建议 250
string CommandPassword // 命令密码
2. CHANGE_FOCUS(ID=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_REQUEST(ID=51)
byte 51 // 消息类型
int32 ConnectionId
float32 StartSessionTime // 回放起点(会话时间,ms)
float32 DurationMS // 回放时长(ms)
int32 InitialFocusedCar // 初始焦点车辆(-1 = 保持当前)
string InitialCameraSet
string InitialCamera
4. REQUEST_ENTRY_LIST(ID=10)/ REQUEST_TRACK_DATA(ID=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_RESULT(ID=1)
byte 1
int32 ConnectionId // 分配的连接 ID(后续请求必须携带)
uint8 ConnectionSuccess // 0=失败, 1=成功
uint8 IsReadOnly // 0=可读写(即拥有 commandPassword)
string ErrorMessage // 错误信息
成功后应立即发送 REQUEST_ENTRY_LIST 和 REQUEST_TRACK_DATA。
2. REALTIME_UPDATE(ID=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_UPDATE(ID=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_LIST(ID=4)+ ENTRY_LIST_CAR(ID=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_DATA(ID=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_EVENT(ID=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 | 黄旗 |
七、关键注意事项
- WorldPosX/Y 和 Yaw:Broadcasting API 中始终为 0(出于反作弊考虑),需要全车坐标请用 Shared Memory
- EntryList:在首次连接时发送一次,新会话开始时不自动重发
- TrackData:同样只在连接时发送一次,新会话不重发
- SplinePosition:0.0~1.0 表示车辆在赛道上的归一化位置(维修区也有效)
- Lap.Splits:Int32.MaxValue 表示无效分段,超出分段数返回 0
- CarUpdate 中 Gear:传输值 - 2 = 实际档位(传输 1 = -1/R,传输 2 = 0/N,传输 3 = 1 档...)
- broadcasting.json 编码:必须是 UTF-16LE with BOM,否则 ACC 无法读取