gewenwu716/palworld-save-parser

GitHub: gewenwu716/palworld-save-parser

Palworld 存档解析器:用 Rust/WASM 在浏览器端提取游戏存档数据,并配合 TypeScript 引擎计算最优繁育路径。

Stars: 0 | Forks: 0

# PalForge 存档解析器 搭配一个 TypeScript 繁育引擎,可使用 BFS 寻路算法根据您实际的 Palbox 库存计算最优的多代繁育树。 ## 此仓库包含的内容 ``` ├── parser/ # Rust save parser (core) │ └── src/ │ ├── lib.rs # WASM exports + library entry │ ├── main.rs # CLI entry point │ ├── palsav.rs # SAV decompression (PlZ → zlib → GVAS) │ ├── gvas.rs # UE5 GVAS header + property tree parser │ ├── farchive.rs # FArchive binary reader (UE serialization) │ ├── character.rs # Character data extraction from property tree │ ├── types.rs # Shared data types (FGuid, PalEntry, etc.) │ └── json_output.rs # Manual JSON serializer (no serde) │ ├── js/ # TypeScript packages │ └── src/ │ ├── breeding-engine.ts # BFS pathfinding + passive convergence │ ├── wasm-bridge.ts # Browser-side WASM integration helper │ ├── sample-data.ts # 15-Pal sample dataset for testing │ └── types.ts # Shared TypeScript types │ ├── data/ # Game data documentation │ └── README.md # How to extract full dataset │ └── .github/workflows/ # CI (Rust + JS tests) ``` ## 快速开始 ### CLI — 解析存档文件 ``` cd parser cargo build --release ./target/release/palworld-save-parser /path/to/Level.sav > pals.json ``` 示例输出: ``` { "total_characters": 52, "pal_count": 48, "player_count": 1, "save_class": "/Script/Pal.PalWorldSaveGame", "engine_version": "5.1.0-0 (++UE5+Release-5.1)", "pals": [ { "character_id": "Anubis", "nickname": "", "gender": "Male", "level": 35, "is_player": false, "passive_skills": ["Artisan", "Work Slave", "Serious"] } ], "players": [...], "warnings": [] } ``` ### WASM — 在浏览器中解析 ``` # 构建 WASM target cd parser cargo build --target wasm32-unknown-unknown --release # 输出: target/wasm32-unknown-unknown/release/palworld_save_parser.wasm ``` 然后在您的 Web 应用中: ``` import { initParser, parseSaveFile } from 'palforge-breeding-engine/wasm-bridge' await initParser('/wasm/palworld_save_parser.wasm') const result = await parseSaveFile(file) // File from console.log(result.pals) // Array of extracted Pal entries ``` ### JS — 计算繁育路径 ``` import { createBreedingEngine, SAMPLE_DATA } from 'palforge-breeding-engine' const engine = createBreedingEngine(SAMPLE_DATA) // Find the shortest breeding path from your Pals to Anubis const path = engine.findBreedingPath( ['Mozzarina', 'Chikipi', 'Lamball', 'Tombat'], 'Anubis' ) console.log(`${path.steps.length} generations needed`) for (const step of path.steps) { console.log(`${step.parentA.name} + ${step.parentB.name} → ${step.child.name}`) } ``` ## 工作原理 ### 存档格式 Palworld 存档是一个三层结构: 1. **PlZ 容器** — 自定义的 Pocketpair 包装器。在偏移量 8 处具有魔数 `PlZ`(如果存在 `CNK` 头部,则在偏移量 20 处)。支持单次压缩 (0x31) 和双次压缩 (0x32) zlib 压缩。 2. **GVAS payload** — Unreal Engine 5 的标准存档游戏格式。魔数 `0x53415647`。头部包含引擎版本、自定义版本的 GUID 以及存档游戏类名 (`/Script/Pal.PalWorldSaveGame`)。 3. **FArchive 属性树** — UE 的二进制序列化格式。类型化属性(StructProperty、MapProperty、ArrayProperty、FloatProperty 等)的递归树。角色数据存储在 `worldSaveData → CharacterSaveParameterMap → MapProperty entries` 中。 ### 繁育算法 繁育引擎使用 BFS(广度优先搜索)和动态闭包: 1. 从玩家可用的 Pal 物种开始 2. 对于每一代,从当前可用的集合中计算所有可能的繁育组合 3. 新的后代被添加到可用集合中,形成反馈循环 4. 当达到目标或超过代数上限(默认为 5)时,搜索终止 5. 如果不存在纯库存路径,则会运行贪婪的捕获成本松弛阶段 ### 架构决策 - **不使用 `serde`** — JSON 是手动序列化的。在 WASM 二进制文件大小中节省了约 100KB,但更容易出错。在 v2 中会考虑使用 `serde`。 - **不使用 `wasm-bindgen`** — 使用原生的 `extern "C"` 导出。导出表上有四个函数:`alloc`、`parse_sav`、`free_string`、`parser_version`。没有胶水代码,没有代码生成步骤。 - **纯 Rust zlib** — 使用 `miniz_oxide` 而不是系统的 libz。无需 Emscripten 即可编译为 WASM。 - **数据无关的引擎** — 繁育引擎接受 `EngineData` 作为参数,而不是导入静态数据集。使其可以使用任何 Pal 列表进行测试。 ## 实际性能 | 文件大小 | 提取的 Pals 数量 | 解析时间(桌面端) | 解析时间(移动端) | |-----------|---------------|---------------------|---------------------| | 50 KB | 15 | < 20ms | < 50ms | | 2 MB | 80 | ~80ms | ~200ms | | 9 MB | 300+ | ~300ms | ~1.5s | | 20 MB | 500+ | ~600ms | ~3s | 已在 Palworld v0.2.0.6 到 v1.0 的存档文件上进行了测试。 ## 许可证 MIT — 详见 [LICENSE](./LICENSE)。 游戏数据格式是通过逆向公开的存档文件得到的。本项目与 Pocketpair 没有任何隶属关系。
标签:AI工具, Rust, TypeScript, WebAssembly, 可视化界面, 存档修改, 安全插件, 数据提取, 游戏工具, 网络流量审计, 解析器, 通知系统