Files

6.0 KiB

游戏插件兼容开发指南

TurboSu 通过插件系统支持任意赛车游戏的遥测数据接入。每个插件是 games/builtin/games/user/ 下的独立文件夹。

文件夹结构

games/user/my_game/
├── manifest.json     # 元信息
└── parser.py         # 解析逻辑

manifest.json 格式

{
    "id": "my_game",
    "name": "我的游戏",
    "parser_type": "forza",
    "protocol": "udp",
    "mode": "server",
    "description": "自定义游戏遥测",
    "author": "你的名字",
    "version": "1.0.0",
    "default_port": 20777
}
字段 类型 必填 说明
id string 唯一标识,= 文件夹名
name string 显示名称
parser_type string 解析器类型标签
protocol string 传输协议: udp(默认) / tcp
mode string TCP模式: server(框架监听) / client(插件自连)
description string 描述文字
author string 作者
version string 版本号
default_port int 默认端口 (UDP默认20777, TCP默认20778)

parser.py 规范

必须导出 get_parser() 函数,返回的对象必须实现以下接口:

class MyParser:
    def game_id(self) -> str:
        """返回与 manifest.json 一致的 game id"""
        return "my_game"

    def parse(self, data: bytes, addr: tuple) -> TelemetryData:
        """
        解析 UDP 数据包
        data: 原始字节数据
        addr: (host, port) 发送方地址
        返回: server.telemetry.data.TelemetryData
        """

完整示例

import struct
import time
from server.telemetry.data import TelemetryData


def get_parser():
    return MyGameParser()


class MyGameParser:
    def game_id(self) -> str:
        return "my_game"

    def parse(self, data: bytes, addr: tuple) -> TelemetryData:
        td = TelemetryData(
            game_id="my_game",
            timestamp=time.time(),
        )
        td.raw = {
            "raw_hex": data.hex(),
            "length": len(data),
            "addr": f"{addr[0]}:{addr[1]}",
        }

        # 解析你的游戏数据协议
        # 示例: 简单的二进制格式
        try:
            td.speed_kmh = struct.unpack_from("<f", data, 0)[0]
            td.rpm = struct.unpack_from("<f", data, 4)[0]
            td.gear = struct.unpack_from("<B", data, 8)[0]
            td.throttle = struct.unpack_from("<f", data, 12)[0]
            td.brake = struct.unpack_from("<f", data, 16)[0]
            td.steering = struct.unpack_from("<f", data, 20)[0]
        except struct.error:
            pass

        return td

TelemetryData 完整字段

@dataclass
class TelemetryData:
    game_id: str = ""           # 游戏标识
    timestamp: float = 0.0      # 时间戳

    # 速度和转速
    speed_kmh: float = 0.0      # 速度 (km/h)
    speed_mph: float = 0.0      # 速度 (mph)
    rpm: float = 0.0            # 发动机转速
    max_rpm: float = 8000.0     # 最大转速

    # 传动
    gear: int = 0               # 档位 (0=N, -1=R, 1~8+)

    # 踏板 (0~1)
    throttle: float = 0.0       # 油门
    brake: float = 0.0          # 刹车
    clutch: float = 0.0         # 离合
    handbrake: float = 0.0      # 手刹

    # 转向 (-1 ~ 1)
    steering: float = 0.0

    # 计时
    lap_time: float = 0.0       # 当前圈速 (秒)
    best_lap: float = 0.0       # 最佳圈速 (秒)
    last_lap: float = 0.0       # 上圈时间 (秒)
    lap_number: int = 0         # 圈数

    # 位置/加速度
    position_x: float = 0.0
    position_y: float = 0.0
    position_z: float = 0.0
    acceleration_x: float = 0.0
    acceleration_y: float = 0.0
    acceleration_z: float = 0.0

    # 车辆状态
    engine_temp: float = 0.0    # 发动机温度
    oil_temp: float = 0.0       # 油温
    fuel: float = 0.0           # 燃油量

    # 性能
    boost: float = 0.0          # 涡轮增压
    horsepower: float = 0.0     # 马力
    torque: float = 0.0         # 扭矩

    # 车辆信息
    car_name: str = ""          # 车辆名称
    car_class: str = ""         # 车辆等级

    # 原始数据 (自动转发给前端调试)
    raw: dict = {}

数据协议解析技巧

二进制格式 (Forza / ACC / F1 / iRacing)

使用 struct 模块解析固定长度的二进制包:

import struct

# 小端浮点
speed = struct.unpack_from("<f", data, offset)[0]

# 小端无符号字节
gear = struct.unpack_from("<B", data, offset)[0]

# 小端无符号短整型
rpm = struct.unpack_from("<H", data, offset)[0]

文本格式 (Assetto Corsa)

使用字符串分割解析:

text = data.decode("utf-8", errors="replace").rstrip("\r\n")
parts = text.split("\t")
speed = float(parts[0])
rpm = float(parts[1])
gear = int(float(parts[2]))

未知协议

如果游戏使用未知/自定义协议:

  1. 启用 TurboSu 的数据测试页面查看原始 hex 数据
  2. 分析数据模式 (浮点数/整数/字符串)
  3. 对照游戏文档或社区逆向结果

测试方法

  1. 将插件文件夹放入 games/user/
  2. 启动 TurboSu → 侧边栏选择你的游戏
  3. 打开数据测试页面查看实时数据
  4. 调整解析逻辑直到字段正确

打包分发

将整个文件夹压缩为 zip,改后缀为 .tsp,即可在 TurboSu 设置页面导入。

# 进入插件目录
cd games/user/my_game

# 打包 (不含父路径)
zip -r my_game.tsp manifest.json parser.py

常见游戏数据格式参考

游戏 格式 数据包大小 参考来源
Forza Horizon 4/5 二进制 LE ~324 bytes Forza Data Out 文档
Forza Motorsport 二进制 LE ~324 bytes Forza Data Out 文档
Assetto Corsa 文本 (TSV) 变长 AC UDP 插件协议
ACC 二进制 LE ~200 bytes ACC Broadcasting SDK
F1 系列 二进制 LE ~1289+ bytes Codemasters F1 UDP Spec
iRacing 二进制 LE 变长 iRacing IRSDK