MortisClub/patchwright
GitHub: MortisClub/patchwright
Patchwright 是一个 Rust 编写的库与 CLI 工具,用于在不完全重新打包的情况下对 MessagePack 二进制存档进行定点字节级修改,避免游戏因编码宽度变化而损坏存档。
Stars: 0 | Forks: 0
Patchwright
针对 MessagePack 二进制存档的定点修改 —— 无需完全重新打包文件。
面向编写专属存档编辑器开发者的库 + CLI 工具。
许多基于 Unity 的游戏会通过 MessagePack-CSharp 序列化存档,但它们写入的并非最小化
字节,而是强制使用的宽度:对于较小的数字使用 `int32` 而不是 fixint,使用 `float32` 而不是
紧凑形式。普通的 msgpack 编码器并不知道这一点 —— 如果将文件完整读取后再重新写入,它会
默默地这些字段压缩至最小编码,导致游戏在下次读取时获得损坏的存档(这在分析 Esports Manager
2026 的格式时确实发生过,`schemas/em2026-slotdata.toml` 是一个真实的例子)。
Patchwright 不会重新序列化文件。它会根据索引路径找到需要的字段,直接在原地确定原始标签
和宽度,并仅替换这些字节 —— 文件的其余部分依然保持游戏写入时的逐字节原样。如果新值不适配
原始宽度,宽度会增加(`int32` → `int64`),但绝不会自行缩小。
## 安装
需要 [Rust](https://rustup.rs)。
```
git clone https://github.com/MortisClub/patchwright
cd patchwright
cargo build --release
```
可执行文件位于 `target/release/patchwright`。
## 快速开始
无需真实游戏即可测试的存档:
```
cargo run --example demo_save -p patchwright-core
```
这会在当前文件夹下生成 `demo.mpack` —— 其结构与下方的 schema 示例一致。
```
$ patchwright inspect demo.mpack --schema schemas/em2026-slotdata.toml
balance = 500000.5
game_date = 20260415
players (3 elements)
[0] cost=45000 nickname=Ivan rating=78
[1] cost=61000 nickname=Zoe rating=82
[2] cost=22000 nickname=Marcus rating=65
teams (1 elements)
[0] money_a=120000 money_b=30000 money_c=15000 money_d=5000 roster_a=1 roster_b=2
$ patchwright set demo.mpack --schema schemas/em2026-slotdata.toml players.1.nickname Zoe-Ann
$ patchwright get demo.mpack --schema schemas/em2026-slotdata.toml players.1.nickname
Zoe-Ann
```
不带 `--out` 参数的 `set` 命令会直接在原文件上修改,并在同级目录留下 `
.bak` 备份。
## Schema
字段的寻址不是通过字节偏移量,而是通过嵌套 msgpack 数组的索引路径:
`players.1.nickname` 表示 `players` 数组的元素 1 中的 `nickname` 字段。Path 是根据
TOML schema 构建的:
```
[[scalar]]
name = "balance"
path = [25, 0]
[[collection]]
name = "players"
base = [9]
[collection.fields]
nickname = 0
rating = 9
```
`scalar` —— 单个字段的路径。`collection` —— 包含同类型记录的数组:`base` 是指向
数组的路径,`fields` 定义了记录中各个字段及其对应的索引位置。CLI 会将引用
`collection.index.field` 解析为具体的 path,然后再用它去文件中查找。
真实游戏的现成示例 —— `schemas/em2026-slotdata.toml`(Esports Manager 2026,
`SlotData.mpack`,46 个部分中仅有已标记的部分)。
## 实现原理
- `patchwright-core/src/msgpack.rs` —— 标签算术:`skip` 在不解析为值的
情况下遍历字节,`decode_scalar`/`encode_preserving` 在读写时保留
原始宽度
- `patchwright-core/src/lib.rs` —— `SaveFile`:path → 字节范围 → splice
(`Vec::splice`)
- `patchwright-core/src/schema.rs` —— TOML schema 及 `name` / `collection.index.field` 解析
- `patchwright-cli/src/main.rs` —— `inspect` / `get` / `set`
## 限制
目前仅支持编辑数组内部的标量字段(数字、字符串、bool、nil)。暂不支持 Map 键、
`bin`/`ext` 以及按键寻址(而非按索引寻址)—— 在目前遇到的基于
MessagePack-CSharp 的真实存档中,结构通常是扁平且基于位置的,因此这对于初始阶段
已经足够。
## 许可证
MIT,详见 [LICENSE](LICENSE)。图标由 [Microsoft Fluent Emoji](https://github.com/microsoft/fluentui-emoji) (MIT) 组合而成。
© MortisClub 2026
标签:MessagePack, Python安全, Rust, 二进制处理, 可视化界面, 文档结构分析, 游戏存档修改, 网络流量审计, 通知系统