dougwithseismic/racemake-challenge
GitHub: dougwithseismic/racemake-challenge
一个面向赛车模拟游戏的遥测分析管道方案,包含 Hono API、二进制编解码器和运行时 schema 提取等生产级组件。
Stars: 1 | Forks: 0
## 重要链接
| 资源 | URL |
|---|---|
| **Live Web App** | [racemake-challenge.up.railway.app](https://racemake-challenge.up.railway.app) |
| **API Documentation (Scalar)** | [racemake-challenge.up.railway.app/docs](https://racemake-challenge.up.railway.app/docs) |
| **Live API Base** | [racemake-challenge.up.railway.app/api/v2](https://racemake-challenge.up.railway.app/api/v2) |
| **OpenAPI Spec** | [racemake-challenge.up.railway.app/openapi.json](https://racemake-challenge.up.railway.app/openapi.json) |
| **Source Code** | [github.com/dougwithseismic/racemake-challenge](https://github.com/dougwithseismic/racemake-challenge) |
| **dezlock-dump** (Runtime Schema Extraction) | [github.com/dougwithseismic/dezlock-dump](https://github.com/dougwithseismic/dezlock-dump) |
| **arc-probe** (AI Process Inspector) | [github.com/vzco/arc-probe](https://github.com/vzco/arc-probe) |
| **s2-framework** (RL Bot Platform) | [github.com/dougwithseismic/s2-framework](https://github.com/dougwithseismic/s2-framework) |
## 结构
Turborepo monorepo。每个挑战都是一个独立的 package。
```
apps/
api/ # Hono API — mounts all challenges with Scalar docs
packages/
challenge-easy/
src/original/ # Untouched challenge file from RACEMAKE
src/solution/ # Our solution — bug fix, stint extension, scaling answer
challenge-hard/
src/original/ # Untouched challenge file from RACEMAKE
src/solution/ # Our solution — Hono API with telemetry processing
```
### Live API
**https://racemake-challenge.up.railway.app**
- **Docs (Scalar):** [/docs](https://racemake-challenge.up.railway.app/docs)
- **Easy — Analyze:** [/api/v2/easy/analyze](https://racemake-challenge.up.railway.app/api/v2/easy/analyze)
- **Easy — Stint:** [/api/v2/easy/stint](https://racemake-challenge.up.railway.app/api/v2/easy/stint)
- **Hard — Laps:** [/api/v2/hard/laps](https://racemake-challenge.up.railway.app/api/v2/hard/laps)
- **Hard — Analysis:** [/api/v2/hard/analysis](https://racemake-challenge.up.railway.app/api/v2/hard/analysis)
- **IRL — Architecture:** [/api/v2/irl](https://racemake-challenge.up.railway.app/api/v2/irl)
- **IRL — Wire Format Codec:** [/api/v2/irl/codec/compare](https://racemake-challenge.up.railway.app/api/v2/irl/codec/compare)
- **IRL — Roundtrip Proof:** [/api/v2/irl/codec/roundtrip](https://racemake-challenge.up.railway.app/api/v2/irl/codec/roundtrip)
- **IRL — SSE Stream:** [/api/v2/irl/stream](https://racemake-challenge.up.railway.app/api/v2/irl/stream)
### 快速开始(本地)
```
pnpm install
# Full API with all routes + Scalar docs
npx tsx apps/api/src/index.ts
# Easy challenge standalone
pnpm --filter @repo/challenge-easy start
# Hard challenge standalone + integration test
npx tsx packages/challenge-hard/src/solution/test.ts
```
## 挑战解决方案
### Easy — `@repo/challenge-easy`
**Level 1 (Fix it):** `analyzeLap` 中的排序比较器是 `a.delta - b.delta` —— 升序。由于 `generateCoaching` 选择 `findings[0]` 作为最差的扇区,它返回的是*最少*的时间损失而不是最多的。修复:`b.delta - a.delta`。单行差异。
**Level 2 (Extend it):** 添加了 `analyzeStint()`,它为每个车手圈速运行 `analyzeLap` 并检测整个 stint 期间的扇区级趋势。跟踪每个扇区的 delta 进展,将趋势分类为恶化/稳定/改善,并生成 PitGPT stint 总结,以捕捉补偿模式(例如,早期的抬油门掩盖了因轮胎退化导致的抓地力损失)。
**Level 3 (Think about it):** 参见 `challenge.ts` 中的注释块。TL;DR —— 在 20 辆车 x 50 圈 x 120 Hz 的情况下,内存首先耗尽。流式处理进入时间序列存储,在 worker 中按车辆隔离,添加背压,在扇区边界去抖动 coaching。
### Hard — `@repo/challenge-hard`
基于 Hono 构建的三个端点:
| 端点 | 功能 |
|---|---|
| `POST /ingest` | 接收原始遥测帧,存储在内存中 |
| `GET /laps` | 返回带有扇区分段、速度指标的已完成圈速摘要 |
| `GET /analysis` | 比较圈速,找出最差圈速的最差扇区,检测问题,返回 PitGPT coaching |
处理的边缘情况:
- **Out-lap 已排除** — 第 0 圈从位置 0.541 开始,而不是从起点/终点线开始
- **不完整圈速已排除** — 第 4 圈只有 S1 数据
- **静止帧已过滤** — 速度 < 5 且位置未变
- **问题检测** — 轮胎过热(>110C)在第 3 圈 S2 中正确识别
- **扇区边界插值** — 在 10Hz 下,帧间隔约 3.2 秒。一种朴素的方法(测量每个扇区帧内的时间)会丢失扇区间的间隙 —— **每圈 6.4 秒** 无法计算,且扇区总和不等于圈时间。我们在跨越每条扇区线的两帧之间插值确切的边界穿越时间,因此 S1 + S2 + S3 = lapTime 精确无误。
## IRL 挑战:逆向工程与遥测管道
### 问题
模拟赛车遥测是从游戏内存或 API 中提取的。当游戏更新补丁时,偏移量会移动,结构体会改变,你的管道就会崩溃。社区等待有人逆向工程新的偏移量。这种等待会扼杀你的产品。
### 解决方案:Runtime Schema Extraction
我为 Source 2 游戏构建了这个确切的系统。与其硬编码每次更新都会损坏的偏移量:
1. **运行时注入** — 手动 PE 映射(无 LoadLibrary,对模块列表不可见)。DLL 通过 vtable 拦截挂钩到游戏进程中。
2. **从游戏本身提取 schema** — Source 2 在运行时暴露其自己的 `SchemaSystem`。以编程方式遍历它以转储每个类、字段、偏移量和继承链。游戏*告诉你*它自己的结构。
3. **生成防补丁 SDK** — 字段偏移量通过 schema 在运行时动态解析,而不是通过硬编码值。当游戏打补丁时,schema 会改变 —— 但解析机制不会。零手动工作。
4. **将其输送给下游** — 提取的 schema 直接输入到 SDK 生成器,生成类型化的 C++ 头文件(2,400+ 结构体,229 个实体类)和完整的 JSON 导出供工具消费者使用。
这就是 [dezlock-dump](https://github.com/dougwithseismic/dezlock-dump) 所做的。
### 应用于赛车遥测
该模式对于模拟赛车是完全相同的:
```
Game Process -> DLL Injection -> Schema Extraction -> Typed SDK -> Telemetry Pipeline -> Analysis
```
专门针对 RACEMAKE 的技术栈:
- **游戏更新发布** -> 运行 schema 提取器 -> 几分钟内获得新偏移量,而不是几天
- **遥测格式更改** -> SDK 自动重新生成,根据游戏自己的定义进行类型化
- **新数据字段出现** -> 它们在任何人记录它们之前就出现在 schema 转储中
### 保持最新:偏移量与转储
关键见解:你不再需要手动逆向工程偏移量。你构建提取它们的系统。相关工具:
| 工具 | 功能 | 仓库 |
|---|---|---|
| **dezlock-dump** | 运行时 RTTI + schema 提取,自动 SDK 生成,跨 58+ 个 DLL 的签名扫描 | [链接](https://github.com/dougwithseismic/dezlock-dump) |
| **s2-framework** | 通过 DLL 注入 + TCP 遥测流传输到 Python/PyTorch 的 ML 机器人训练。精确的注入-提取-流模式。 | [链接](https://github.com/dougwithseismic/s2-framework) |
| **memory-hooking-tool** | 带有 TypeScript 脚本功能的进程内存读/写。模式扫描,PE 解析,全自动化层。 | [链接](https://github.com/dougwithseismic/memory-hooking-tool) |
| **arc-probe** | AI 代理驱动的进程检查器。DLL 注入,反汇编,结构映射 —— 均可通过 Claude Code 技能控制。Tauri v2 应用 (Rust + React)。 | [链接](https://github.com/vzco/arc-probe) |
### 最佳方法
**为了 schema 稳定性:**
- 运行时解析优于硬编码偏移量。始终如此。
- 模式签名(字节序列)作为后备 —— 它们可以在无法进行完整 schema 提取的小补丁中存活。
- 带有版本标签的 schema 缓存,这样你就可以在游戏版本之间进行 diff 并自动检测发生了什么变化。
**为了管道弹性:**
- Protobuf/flatbuffers 作为有线格式 —— schema 演进内置于协议中。
- 记录器(Tauri/Rust 端)应该是 schema 感知的,而不仅仅是转储原始字节。如果字段移动,记录器会自适应。
- Canary 检查:在游戏启动时,根据预期范围验证少量已知字段值。如果它们错误,则 schema 发生了偏移 —— 在发送垃圾数据 downstream 之前发出警报。
**为了领先于社区:**
- 构建你自己的提取器。不要等待社区转储。
- 自动化转储管道:检测到游戏更新 -> 注入 -> 提取 -> diff -> PR -> 部署。逆向工程的 CI。
- 监控游戏测试版分支 —— schema 更改通常首先出现在那里。
### 有线格式:为什么 JSON 遥测是疯狂的
120Hz 下的原始 JSON 每帧约 131 字节。20 辆车那就是 **307 KB/s** 的纯开销 —— 每帧重复字段名,无增量编码,无 schema 版本控制。
`/api/v2/irl/codec` 路由展示了一个生产级的替代方案:
| 格式 | 每帧 | 20 辆车 @ 120Hz | 减少 |
|---|---|---|---|
| JSON | ~131 bytes | 307 KB/s | — |
| Binary (v1 schema) | 19 bytes | 45 KB/s | **85.5%** |
| Delta-encoded | ~6 bytes avg | ~14 KB/s | **95.4%** |
**编解码器的主要特性:**
- **版本化 schema 注册表** — 当游戏打补丁并添加字段时,添加新的 schema 版本。旧消费者仍然可以工作(向前兼容性)。与 Protobuf 字段编号相同的原理。
- **双向映射** — 通过 `/roundtrip` 端点证明 `encode()` 和 `decode()` 在所有 166 个遥测帧中是无损的。量化低于传感器噪声底限。
- **Delta encoding** — 120Hz 下的连续帧可能在 3-4 个字段上有所不同。只传输变化的内容。一个 2 字节的 bitmask 头 + 变化的字段字节。
在生产中,你会使用 Protobuf(RACEMAKE 已经在用)或 FlatBuffers 来实现零拷贝。这是一个从头开始的实现,用于展示原理。
[在线试用:/api/v2/irl/codec/compare](https://racemake-challenge.up.railway.app/api/v2/irl/codec/compare)
github.com/dougwithseismic
标签:AI, Bun, C++, Dota, GNU通用公共许可证, Hono API, Node.js, Python, React, Rust, Scalar, Source 2 引擎, Syscalls, Tauri, TypeScript, Wire Format, 云资产清单, 产品工程师, 反恐精英, 可视化界面, 安全插件, 技术面试, 数据处理管道, 数据擦除, 无后门, 机器人开发, 游戏事件API, 游戏工具开发, 生产级编解码器, 网络流量审计, 网络调试, 自动化, 自动化代码审查, 自动化攻击, 计算机视觉, 远程测量分析, 逆向工具, 逆向工程