feat(saves): lossless self-contained save JSON + dm2 dump path #311

Merged
jqueuniet merged 11 commits from feat/save-json-self-contained into main 2026-08-10 16:33:01 +02:00
Owner

Implements lossless, round-trippable save JSON for Dungeon Master II savegames — the self-contained variant (Plan 1 of 2, issue #308). Foundation for the future web save editor (#301) and GUI editors (#303).

What this adds

  • dm2-saves::json module — a DTO-based JSON layer (SaveDump) that serialises a parsed SaveFile to human-readable JSON and reconstructs it byte-for-byte. DTOs are hand-shaped because the wire types can't derive serde directly (FileHeader/ByteOrder lack serde; several byte blobs exceed serde's 32-element array limit).
    • SaveDump::gameplay_only(&save, variant) — lossy human-readable view (no reload).
    • SaveDump::self_contained(&save, variant) — gameplay + all structural sections + the full suppression bitstream (base64). Reconstructs with no external files.
    • SaveDump::reconstruct_self_contained() — rebuilds the original bytes; re-encodes gameplay phases 1–2 over the embedded bitstream and splices the phase-3–7 tail verbatim.
  • dm2 dump save path — default emits gameplay-only JSON; --self-contained emits the lossless self-contained form. No external files needed in either mode.

Editability model

gameplay (SGB, globals, champions, effects, timers) is editable and engine-safe. record_stream stays opaque inside the embedded bitstream here — promoting it to field-editable is the field-driven "full" variant (Plan 2), out of scope for this PR.

Losslessness

A byte-exact round-trip gate (tests/json_roundtrip.rs) runs the full public path (parse → self_contained → to_pretty_json → deserialize → reconstruct_self_contained) and asserts byte-identity over real fixtures in both byte orders — all 6 DOS-EN slots (Little, incl. the nonstandard SKSAVE4/5.DAT) and every Mac-US fixture (Big).

Verification

cargo fmt --all -- --check, cargo clippy --workspace --all-targets -- -D warnings, cargo build --workspace --locked, cargo doc --workspace --no-deps --locked, and cargo test --workspace all pass.

Implements lossless, round-trippable save JSON for Dungeon Master II savegames — the **self-contained** variant (Plan 1 of 2, issue #308). Foundation for the future web save editor (#301) and GUI editors (#303). ## What this adds - **`dm2-saves::json` module** — a DTO-based JSON layer (`SaveDump`) that serialises a parsed `SaveFile` to human-readable JSON and reconstructs it byte-for-byte. DTOs are hand-shaped because the wire types can't derive serde directly (`FileHeader`/`ByteOrder` lack serde; several byte blobs exceed serde's 32-element array limit). - `SaveDump::gameplay_only(&save, variant)` — lossy human-readable view (no reload). - `SaveDump::self_contained(&save, variant)` — gameplay + all structural sections + the full suppression bitstream (base64). Reconstructs with **no external files**. - `SaveDump::reconstruct_self_contained()` — rebuilds the original bytes; re-encodes gameplay phases 1–2 over the embedded bitstream and splices the phase-3–7 tail verbatim. - **`dm2 dump` save path** — default emits gameplay-only JSON; `--self-contained` emits the lossless self-contained form. No external files needed in either mode. ## Editability model `gameplay` (SGB, globals, champions, effects, timers) is editable and engine-safe. `record_stream` stays opaque inside the embedded bitstream here — promoting it to field-editable is the field-driven "full" variant (Plan 2), out of scope for this PR. ## Losslessness A byte-exact round-trip gate (`tests/json_roundtrip.rs`) runs the full public path (`parse → self_contained → to_pretty_json → deserialize → reconstruct_self_contained`) and asserts byte-identity over real fixtures in both byte orders — all 6 DOS-EN slots (Little, incl. the nonstandard `SKSAVE4/5.DAT`) and every Mac-US fixture (Big). ## Verification `cargo fmt --all -- --check`, `cargo clippy --workspace --all-targets -- -D warnings`, `cargo build --workspace --locked`, `cargo doc --workspace --no-deps --locked`, and `cargo test --workspace` all pass.
jqueuniet deleted branch feat/save-json-self-contained 2026-08-10 16:33:01 +02:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
jqueuniet/dm2-tools!311
No description provided.