Ravenz16/dow-de-replay-parser
GitHub: Ravenz16/dow-de-replay-parser
针对《战争黎明》终极版回放文件进行二进制逆向解析的 Java 工具,能从命令流还原玩家操作并生成战术分析报告。
Stars: 1 | Forks: 0
# DoW 回放分析器
*其他语言阅读:[Русский](README.ru.md)*
这是一款 Java 工具,能够解析 **Dawn of War** 回放文件(`.rec`)并直接从二进制命令流中还原每位玩家的操作——包括建造顺序、据点占领、单位指令、技能以及针对每位玩家的战术总结。
由于回放格式未公开,命令流是逐字节进行逆向工程得出的。本项目即是这项工作的成果。
## 功能简介
给定一个 `.rec` 文件,分析器会输出一份结构化报告:
- **Header** — 地图、时长(ticks → 秒)以及玩家/观察者列表。
- **命令流摘要** — 解析的事件、读取的数据包、解码的子命令。
- **找到的 CMD_ID** — 遇到的每个命令操作码及其计数。
- **时间线** — 解码事件的按时间顺序列表(tick、时间、命令、实体、位置)。
- **建造/占领/发电厂事件** — 筛选出的建筑和据点占领视图。
- **玩家专属时间线** — 在两名人类玩家之间划分的事件。
- **建造顺序** — 每位玩家按顺序排列的关键经济和战术行动。
- **战术分析** — 针对每位玩家的经济状况(兵营、发电厂、LP 哨所、占领、科技)和军队状况(指令、攻击、技能)。
## 工作原理
`.rec` 文件是一个 Relic Chunky 容器。处理流水线如下:
1. `BinaryReader` — 针对原始字节的底层小端序读取器。
2. `RecursiveRelicChunkParser` + `RelicChunkNode` + `ChunkSearch` — 遍历 chunk 树并定位元数据(地图、玩家)和 **`FOLDINFO`** chunk。
3. `CommandStreamParser` — 命令流紧随 `FOLDINFO` 开始。该类将其解码为 `GameEvent` 列表,并将其归因于对应玩家。
4. `test.Main` — 入口点;运行流水线并打印报告。
### 命令流布局(逆向工程得出)
该流是 **packets** 的平铺序列,每个数据包代表一名玩家在一个游戏 tick 中的操作:
| Offset | Field | Notes |
|-------:|-------|-------|
| `-4` | packet size | payload 前的 4 字节小端序前缀 |
| `0` | `0x50` marker | 标识命令数据包 |
| `1..4` | tick | uint32 LE;`tick / 8.0` = 秒 |
| `13` | command count | 数据包中子命令的数量 |
| `25..28` | inner size | 仅覆盖**第一个**子命令块 |
| `30+` | sub-commands | 第一个块在此处;后续块通过尾部扫描恢复 |
每个**子命令**携带实体 ID(`+2..5`)、位于 `+27` 的 phase 字节,并且——对于 40 字节格式——还包含一个位置(`x@+34`, `y@+36`, `z@+38`, int16 LE)。子命令大小:
- `28 / 33 / 35` — 进度/完成标记(无坐标)。
- `40` — 带有坐标的真实放置/指令。
- `45` — 嵌入了多个操作码的复合命令。
操作码(`cmd_id`)对于 40 字节的命令在 `+29` 处读取,其他情况在 `+23` 处读取;phase 为 `3` 的 40 字节建造格式将类型编码为 `0xC300 | byte[28]`。
## 项目结构
```
com.dow.replay.parser.BinaryReader low-level binary reader
com.dow.replay.chunk.RelicChunkNode chunk tree node
com.dow.replay.chunk.ChunkSearch chunk lookup helpers
com.dow.replay.chunk.RecursiveRelicChunkParser Relic Chunky parser
com.dow.replay.parser.CommandStreamParser core: command stream → events + attribution
test.Main entry point / report printer
```
## 构建与运行
要求 **JDK 17**(基于 Amazon Corretto 17 开发)。源代码编码为 UTF-8。
在 IntelliJ IDEA 中:打开项目,将 SDK 设置为 17,并将 `test.Main` 作为主类运行,同时将回放文件路径作为程序参数:
```
test.Main scr\replays\.rec
```
从命令行运行:
```
javac -encoding UTF-8 -d out $(find src -name "*.java")
java -cp out test.Main scr/replays/.rec
```
回放文件名遵循 `W--L-` 约定(胜者/败者),例如 `#1521554-W-ORK-L-TAU.rec` 表示兽人获胜,钛帝国战败。
## 已知局限
这是对未公开格式的严谨逆向工程,有些信息仅从命令流中无法还原:
- **仅记录了状态改变指令。** Dawn of War 会记录建造、移动、攻击、技能、占领和增援——但**不包括**选择、镜头移动、控制组点击或待机指令(这些占据了原始 APM 的大部分)。因此,命令计数远低于玩家的真实 APM,这是由游戏设计决定的。
- **没有针对单条指令的玩家字段。** 经过调查已被排除:phase 字节追踪的是建造的*地图方位*,实体 ID 是全局按时间排序的计数器(玩家区间会重叠),且数据包头字节是同步哈希值。因此,玩家归属是一种**启发式算法**:种族专属命令族 + 主基地位置 + 最近邻传播。这对于技能、种族专属指令和基础设施是可靠的,但在两名玩家交替操作的窗口期,**共享指令(占领/移动/攻击)可能会被误判**。
- **`cmd_id` 的含义具有对局特异性。** 操作码是种族/建造菜单蓝图,而非通用动作代码——相同的操作码在不同的对局中可能含义不同。对于共享的命令,标签是通用的;只有在确认为种族专属时,才会使用 `TAU_*` / `ORK_*` 标签。
- **开局基础建筑可能不可见。** 一些早期建筑是通过 28 字节命令发布的,这些命令会融入完成时的噪声中,因此无法被单独解析。
- **AI/机器人指令**不会记录在回放命令流中。
- **观察者**会显示为额外的玩家槽位(一场 1v1 最多可容纳 6 名观众),但他们不会发出任何指令。
## 状态
已针对多种对战(钛帝国 vs 黑暗灵族,兽人 vs 钛帝国)进行了深入的逆向工程。命令流布局和事件解码已趋于稳定;玩家归属目前是基于尽力的启发式算法,并将随着更多真实回放被分析而持续改进。
标签:JS文件枚举, 二进制解析, 云资产清单, 代码示例, 域名枚举, 数据分析, 文件解析, 游戏工具, 逆向工程