diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9557fa5..21f7967 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,33 +1,24 @@ # 贡献指南 -感谢你对 TurboSu 的关注!本指南将帮助你参与项目开发。 - ## 贡献方式 -### 提交游戏插件 +### 提交游戏插件 (`.tsp`) -如果你想让 TurboSu 支持一款新的赛车游戏,只需创建一个游戏插件: - -1. 在 `games/user/` 下新建文件夹 (以游戏 ID 命名) -2. 编写 `manifest.json` (元信息) 和 `parser.py` (数据解析) -3. 提交 Pull Request 到 `games/user/` 目录,或直接在设置页面通过 "导入插件" 安装 - -插件结构: +创建一个包含 `manifest.json` 和 `parser.py` 的文件夹,压缩为 zip 改后缀: ``` -games/user// -├── manifest.json # 游戏元信息 -└── parser.py # 解析逻辑 +my_game/ +├── manifest.json +└── parser.py ``` -#### manifest.json 格式 +#### manifest.json ```json { "id": "unique_game_id", "name": "游戏名称", "parser_type": "forza", - "telemetry_format": "fh5", "description": "简短描述", "author": "你的名字", "version": "1.0.0", @@ -37,71 +28,62 @@ games/user// #### parser.py 规范 -必须实现 `get_parser()` 函数,返回一个包含以下方法的对象: +必须实现 `get_parser()` 函数,返回对象包含: ```python +import time +from server.telemetry.data import TelemetryData + + +def get_parser(): + return MyParser() + + class MyParser: def game_id(self) -> str: - """返回与 manifest.json 一致的 game id""" return "unique_game_id" def parse(self, data: bytes, addr: tuple) -> TelemetryData: - """ - 解析 UDP 数据包 - data: 原始字节数据 - addr: (host, port) 发送方地址 - 返回: server.telemetry.data.TelemetryData 对象 - """ + td = TelemetryData(game_id="unique_game_id", timestamp=time.time()) + td.raw = {"raw_hex": data.hex(), "length": len(data)} + # 填充遥测字段... + return td ``` -#### TelemetryData 可用字段 +安装方式:在 TurboSu 设置页面 → 游戏插件管理 → 导入 `.tsp` -| 字段 | 类型 | 说明 | -|------|------|------| -| speed_kmh | float | 速度 (km/h) | -| speed_mph | float | 速度 (mph) | -| rpm | float | 发动机转速 | -| max_rpm | float | 最大转速 | -| gear | int | 当前档位 (0=N, 1-8, -1=R) | -| throttle | float | 油门 (0-1) | -| brake | float | 刹车 (0-1) | -| clutch | float | 离合 (0-1) | -| handbrake | float | 手刹 (0-1) | -| steering | float | 转向 (-1 to 1) | -| lap_time | float | 当前圈速 (秒) | -| best_lap | float | 最佳圈速 (秒) | -| last_lap | float | 上一圈速 (秒) | -| lap_number | int | 圈数 | -| fuel | float | 燃油量 | -| boost | float | 涡轮增压值 | -| horsepower | float | 马力 | -| torque | float | 扭矩 | -| position_x/y/z | float | 车辆坐标 | -| engine_temp | float | 发动机温度 | -| oil_temp | float | 油温 | -| raw | dict | 原始数据 (自动记录) | +### 提交仪表盘主题 (`.tsd`) -### 提交仪表盘主题 +创建独立文件夹: -1. 在 TurboSu 设置页面创建/编辑仪表盘 -2. 导出为 JSON 文件 -3. 提交到 `dashboards/` 目录 +``` +my_dashboard/ +├── manifest.json # 元信息 (参考下方格式) +└── index.html # 完整独立页面 +``` + +`index.html` 需包含: +- WebSocket 连接:`ws:///ws` +- 接收 `telemetry` 消息类型的数据 +- 用 `data-bind="字段名"` 属性绑定数据 +- 比例约束渲染逻辑 + +安装方式:在 TurboSu 仪表盘页面 → 导入 `.tsd`,或右键卡片导出。 ### 报告 Bug -在 GitHub Issues 中提交,请包含: -- 操作系统和 Python 版本 -- 错误日志 (logs/turbosu.log) +请在 Issue 中包含: +- 系统信息 (OS, Python 版本) +- 错误日志 (`logs/turbosu.log`) - 复现步骤 ### 功能建议 -欢迎提交 Issue 讨论新功能方向。 +欢迎提交 Issue 讨论。 ## 开发环境 ```bash -cd Project/TurboSu python3 -m venv venv source venv/bin/activate pip install -r requirements.txt @@ -110,10 +92,10 @@ python app.py ## 代码规范 -- Python 代码遵循 PEP 8 -- 使用 `utils.logger` 进行日志记录(不要用 print) -- 前端 JS 使用模块化结构,文件放在对应目录下 +- Python: PEP 8 +- 日志使用 `utils.logger`,不用 `print` +- 前端 JS 模块化,文件放对应目录 ## 许可证 -贡献即表示同意你的代码在 Apache 2.0 许可下发布。 +贡献即表示同意代码在 Apache 2.0 许可下发布。 diff --git a/README.md b/README.md index 5f18cf2..7287493 100644 --- a/README.md +++ b/README.md @@ -8,15 +8,16 @@ ## 功能特性 -- **多游戏支持** —— 插件化架构,内置支持 Forza Horizon 4/5、Forza Motorsport、Assetto Corsa/ACC、F1、iRacing -- **社区扩展** —— 游戏插件可独立导入导出,方便社区贡献小众游戏支持 -- **实时仪表盘** —— 速度表、转速表、档位指示器、圈速计时器等 -- **场景模式** —— 多仪表盘布局组合,支持多比例画布切换 -- **局域网共享** —— 仪表盘/场景生成独立链接,手机/平板/笔记本均可全屏访问 -- **跨端自适应** —— 响应式布局,桌面侧边栏 / 平板折叠 / 手机底部导航 -- **比例约束渲染** —— 每个仪表盘可指定渲染比例(auto/16:9/4:3/1:1)和渲染模式 -- **主题切换** —— Xiaomi HyperOS (Miuix) 风格,支持日间/夜间模式 -- **导出导入** —— 仪表盘主题和场景独立配置文件,社区友好 +- **多游戏支持** — 插件化架构,内置 Forza Horizon 4/5、Forza Motorsport、Assetto Corsa/ACC、F1、iRacing +- **社区扩展** — 游戏插件可独立打包导入导出 (`.tsp`),方便社区贡献小众游戏支持 +- **实时仪表盘** — 速度表、转速表、档位指示器、圈速计时器 +- **独立仪表盘** — 每个仪表盘是独立文件夹 (`manifest.json` + `index.html`),启动自动扫描 +- **场景模式** — 多仪表盘布局组合,支持多比例画布切换 +- **局域网共享** — 仪表盘/场景生成独立链接,手机/平板/笔记本均可全屏访问 +- **跨端自适应** — 响应式布局:桌面侧边栏 / 平板折叠 / 手机底部导航 +- **比例约束渲染** — 仪表盘可指定比例 (`auto`/`16:9`/`4:3`/`1:1`) 和渲染模式 (`contain`/`cover`/`fill`/`center`) +- **HyperOS 风格** — Miuix 设计语言,毛玻璃模糊效果,日间/夜间模式 +- **社区分发** — 仪表盘 `.tsd`、场景 `.tss`、插件 `.tsp` — zip 格式,便于分享 ## 快速开始 @@ -25,75 +26,108 @@ - Python 3.10+ - pip -### 安装运行 +### 运行 ```bash -# 克隆/下载项目 -cd Project/TurboSu +git clone ssh://git@git.yeij.top:2222/AskaEth/TurboSu.git +cd TurboSu -# 创建虚拟环境 -python3 -m venv venv -source venv/bin/activate +# 一键启动 (自动创建 venv 并安装依赖) +./run.sh -# 安装依赖 +# 或手动启动 +python3 -m venv venv && source venv/bin/activate pip install -r requirements.txt - -# 启动服务 python app.py ``` 浏览器访问 `http://localhost:9527` -### 一键启动 - -```bash -chmod +x run.sh -./run.sh -``` - ## 使用指南 ### 1. 选择游戏 -侧边栏 → "选择游戏" 下拉 → 点击你要玩的游戏。 +侧边栏 → 游戏列表展开 → 选择你要玩的游戏。列表来自 `games/builtin/` (内置) 和 `games/user/` (社区)。 -游戏列表来自 `games/builtin/` (内置) 和 `games/user/` (社区插件)。 +### 2. 配置遥测输出 -### 2. 配置游戏遥测输出 - -在各游戏中设置 UDP 数据输出: +在各游戏中开启 UDP 数据输出功能: | 游戏 | 设置位置 | 端口 | |------|----------|------| | Forza Horizon 4/5 | 设置 → HUD与游戏 → 数据输出 | 20777 | -| Forza Motorsport | 设置 → 游戏玩法 → UDP 数据输出 | 20777 | -| Assetto Corsa | 内容管理器 → 设置 → 自定义UDP | 9996 | +| Forza Motorsport | 设置 → 游戏玩法 → UDP数据输出 | 20777 | +| Assetto Corsa | 内容管理器 → 自定义UDP | 9996 | | ACC | 设置 → 电子设备 → UDP | 20777 | | F1 24 | 设置 → 遥测设置 → UDP | 20777 | | iRacing | 选项 → 杂项 → 数据记录 | 20777 | ### 3. 浏览仪表盘 -点击侧边栏 "仪表盘" → 浏览/筛选 → 点击卡片在新标签打开。 +侧边栏 → 仪表盘 → 浏览/分类筛选 → 点击卡片在新标签打开全屏仪表盘。 -链接会自动复制,可在局域网设备(手机/平板)打开全屏显示。 +链接自动复制,局域网设备可直接访问。右键卡片可导出 `.tsd` 文件。 ### 4. 创建场景 -侧边栏 → "场景" → 新建 → 编辑添加多个仪表盘 → 渲染。 +侧边栏 → 场景 → 新建场景 → 编辑添加多个仪表盘 → 选择画布比例 → 渲染。 -场景支持多个画布比例(16:9/4:3等),渲染前选择。 +场景卡片支持导出 `.tss`,页面顶栏可导入。 ### 5. 数据调试 -侧边栏 → "数据测试" → 查看解析后的实时数据和原始数据流。 +侧边栏 → 数据测试 → 实时查看解析字段和原始 JSON 数据流。 ## 开发指南 -### 创建自定义游戏插件 +### 自定义仪表盘格式 -1. 在 `games/user/` 下创建文件夹,如 `games/user/my_game/` -2. 创建 `manifest.json`: +每个仪表盘是一个独立文件夹,放在 `dashboards/` 或 `data/dashboards/`: + +``` +dashboards/my_dashboard/ +├── manifest.json # 元信息 +└── index.html # 完整独立页面 (含 WS 连接 + 数据绑定) +``` + +#### manifest.json + +```json +{ + "id": "my_dashboard", + "name": "我的仪表盘", + "category": "custom", + "description": "简短描述", + "author": "你的名字", + "version": "1.0.0", + "config": { + "icon": "🏎️", + "aspect_ratio": "16:9", + "render_mode": "contain" + } +} +``` + +#### index.html + +完全独立的 HTML 页面。需包含: +- WebSocket 连接到 `ws:///ws` 接收遥测数据 +- `data-bind` 属性绑定数据字段(如 `data-bind="speed_kmh"`) +- 比例约束渲染逻辑(参考内置仪表盘) + +打包分发:将整个文件夹压缩为 zip,改后缀为 `.tsd`。 + +### 自定义游戏插件 + +插件文件夹放在 `games/user/`: + +``` +games/user/my_game/ +├── manifest.json # 元信息 +└── parser.py # 解析逻辑 (get_parser() + parse()) +``` + +#### manifest.json ```json { @@ -107,10 +141,9 @@ chmod +x run.sh } ``` -3. 创建 `parser.py`: +#### parser.py ```python -import struct import time from server.telemetry.data import TelemetryData @@ -126,70 +159,102 @@ class MyGameParser: 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)} - - # 解析你的游戏数据 + # 解析你的游戏数据... # td.speed_kmh = ... # td.rpm = ... # td.gear = ... - return td ``` -4. 重启 TurboSu 或点击设置 → 重新加载插件 +打包分发:将文件夹压缩为 zip,改后缀为 `.tsp`,在设置页面导入。 -### 创建自定义仪表盘主题 +### TelemetryData 可用字段 -在设置页面的仪表盘管理中创建,或直接编写配置文件。 +| 字段 | 类型 | 说明 | +|------|------|------| +| `speed_kmh` | float | 速度 (km/h) | +| `speed_mph` | float | 速度 (mph) | +| `rpm` | float | 发动机转速 | +| `max_rpm` | float | 最大转速 | +| `gear` | int | 档位 (0=N, -1=R) | +| `throttle` | float | 油门 (0~1) | +| `brake` | float | 刹车 (0~1) | +| `clutch` | float | 离合 (0~1) | +| `handbrake` | float | 手刹 (0~1) | +| `steering` | float | 转向 (-1~1) | +| `lap_time` | float | 当前圈速 (秒) | +| `best_lap` | float | 最佳圈速 (秒) | +| `last_lap` | float | 上圈时间 (秒) | +| `lap_number` | int | 圈数 | +| `fuel` | float | 燃油 | +| `boost` | float | 涡轮增压 | +| `horsepower` | float | 马力 | +| `torque` | float | 扭矩 | +| `position_x/y/z` | float | 坐标 | +| `engine_temp` | float | 发动机温度 | +| `oil_temp` | float | 油温 | +| `raw` | dict | 原始数据 | ## 项目结构 ``` TurboSu/ -├── app.py # FastAPI 主入口 -├── config/settings.py # 全局配置管理 +├── app.py # FastAPI 主入口 (lifespan) +├── run.sh # 一键启动脚本 +├── requirements.txt +├── config/settings.py # 全局配置 (JSON 持久化) ├── server/ -│ ├── api.py # REST API 路由 -│ ├── websocket.py # WebSocket 实时推送 -│ ├── game_manager.py # 游戏插件管理器 +│ ├── api.py # REST API (状态/配置/CRUD/导入导出) +│ ├── websocket.py # WebSocket 广播 (30fps 限流) +│ ├── game_manager.py # 游戏插件发现/加载/导入导出(.tsp) │ └── telemetry/ -│ ├── data.py # 遥测数据结构 -│ ├── listener.py # UDP 监听器 -│ └── parsers/ # 内置解析器 +│ ├── data.py # TelemetryData 27字段数据类 +│ ├── listener.py # UDP 异步监听器 +│ └── parsers/ # 内置解析器 (base/forza/ac/acc/f1/iracing) ├── games/ -│ ├── builtin/ # 内置游戏插件 (7款) -│ └── user/ # 用户/社区插件 +│ ├── builtin/ # 7 款内置游戏插件 +│ │ ├── forza_horizon_5/ # manifest.json + parser.py +│ │ ├── forza_horizon_4/ +│ │ ├── forza_motorsport/ +│ │ ├── assetto_corsa/ +│ │ ├── assetto_corsa_competizione/ +│ │ ├── f1_24/ +│ │ └── iracing/ +│ └── user/ # 社区插件 (运行时安装) +├── dashboards/ # 内置仪表盘 (4 款) +│ ├── speedometer/ # manifest.json + index.html +│ ├── tachometer/ +│ ├── gear_indicator/ +│ └── lap_timer/ ├── models/ -│ ├── dashboard.py # 仪表盘数据模型 -│ └── scene.py # 场景数据模型 -├── dashboards/ # 内置仪表盘主题 (4款) +│ ├── dashboard.py # 仪表盘模型 + 自动扫描 + zip导入导出 +│ └── scene.py # 场景模型 + 画布/布局 + zip导入导出 ├── templates/ │ ├── index.html # 主 SPA 页面 -│ ├── dashboard.html # 仪表盘渲染页 -│ └── scene.html # 场景渲染页 +│ └── scene.html # 场景渲染页 (iframe组合) ├── static/ │ ├── css/ -│ │ ├── miuix.css # HyperOS 样式框架 -│ │ └── main.css # 布局样式 -│ └── js/ # 前端 JavaScript 模块 -├── utils/logger.py # 日志系统 -├── data/ # 运行时数据存储 -├── logs/ # 日志文件 -├── requirements.txt -└── run.sh +│ │ ├── miuix.css # HyperOS/Miuix 样式框架 (CSS变量+毛玻璃+主题) +│ │ └── main.css # 布局 + 跨端响应式 (3断点) +│ └── js/ +│ ├── app.js / router.js # 应用入口 + Hash路由 +│ ├── api.js / ws.js # API + WebSocket 客户端 +│ ├── components/ # sidebar.js / topbar.js +│ ├── pages/ # home / dashboard / scene / debug / settings +│ └── utils/ # theme.js / toast.js +├── data/ # 运行时数据 (user dashboards, scenes, config) +├── logs/ # 日志 (轮转文件, 10MB x5) +├── README.md +└── CONTRIBUTING.md ``` -## 仪表盘配置说明 +## 导入导出格式 -每个仪表盘主题的 `config.json` 支持以下渲染配置: - -```json -{ - "aspect_ratio": "auto", // auto | 16:9 | 4:3 | 1:1 | 21:9 - "render_mode": "contain", // contain(留黑边) | cover(裁切) | fill(拉伸) | center(居中) - "max_width": 1920, // center 模式最大宽度 - "max_height": 1080 // center 模式最大高度 -} -``` +| 格式 | 后缀 | 本质 | 说明 | +|------|------|------|------| +| 仪表盘 | `.tsd` | zip | 含 `manifest.json` + `index.html` | +| 场景 | `.tss` | zip | 含 `scene.json` | +| 游戏插件 | `.tsp` | zip | 含 `manifest.json` + `parser.py` | ## 作者