MortisClub/patchwright

GitHub: MortisClub/patchwright

Patchwright 是一个 Rust 编写的库与 CLI 工具,用于在不完全重新打包的情况下对 MessagePack 二进制存档进行定点字节级修改,避免游戏因编码宽度变化而损坏存档。

Stars: 0 | Forks: 0

Patchwright

Patchwright

针对 MessagePack 二进制存档的定点修改 —— 无需完全重新打包文件。
面向编写专属存档编辑器开发者的库 + CLI 工具。

Rust MIT MortisClub

许多基于 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, 二进制处理, 可视化界面, 文档结构分析, 游戏存档修改, 网络流量审计, 通知系统