dm2-saves: timer-count decode — Mac BE handling missing in GameplaySections::decode; LE path truncates the 9-bit field to 8 bits #170

Closed
opened 2026-07-04 15:14:48 +02:00 by jqueuniet · 1 comment
jqueuniet commented 2026-07-04 15:14:48 +02:00 (Migrated from codeberg.org)

Problem

The SGB timer-count field (w_14, mask 0xFF 0x01, 9 bits) is read differently in the two decode paths, and both have defects:

  1. GameplaySections::decode has no Mac branch (gameplay.rs:112: timer_count_raw & 0xFF). SaveFile::decode_full (sksave.rs:860-866) documents and fixes exactly this — "Reading it LE on Mac yields a wrong count" — with the 9-bit BE formula (b20 << 1) | (b21 & 1), but the fix never reached the non-full path. Measured on Mac fixtures: early_game decodes 0 timers instead of 1 (raw 0x0100), endgame 11 instead of 22, skullkeep_void_gate 12 instead of 24. Every CLI path built on decode_gameplay_sections (dm2 save show/party/champion/global, dm2 info's section decode) sees a truncated wrong timer list on Mac. Scalar edits still splice byte-safely (the error is symmetric between decode and re-encode), but all timer reads are wrong.
  2. The LE path truncates to 8 bits (& 0xFF) while the engine reads the full i16 (sksvgame.cpp:1517 passes timdat.num_timers whole) and the mask field is 9 bits. Irrelevant for retail DOS (timer cap 50), but SKWINSPX's DM2_EXTENDED_MODE raises the cap to 500 — an extended-mode save with >255 timers mis-decodes. Should be & 0x1FF.

Additionally info.rs:167 prints sgb.timer_count_raw & 0xff directly, which is wrong on Mac independent of the section decode.

Fix direction

One byte-order-aware helper (9-bit, Mac BE formula) used by decode_full, GameplaySections::decode, and the CLI display — the logic currently exists only inline in decode_full.

Reproduction

SaveFile::parse(fixtures/mac-us/saves/early_game, ByteOrder::Big).decode_gameplay_sections() returns 0 timers; decode_full with the Mac dungeon decodes 1.

## Problem The SGB timer-count field (`w_14`, mask `0xFF 0x01`, 9 bits) is read differently in the two decode paths, and both have defects: 1. **`GameplaySections::decode` has no Mac branch** (`gameplay.rs:112`: `timer_count_raw & 0xFF`). `SaveFile::decode_full` (`sksave.rs:860-866`) documents and fixes exactly this — "Reading it LE on Mac yields a wrong count" — with the 9-bit BE formula `(b20 << 1) | (b21 & 1)`, but the fix never reached the non-full path. Measured on Mac fixtures: `early_game` decodes **0 timers instead of 1** (raw `0x0100`), `endgame` 11 instead of 22, `skullkeep_void_gate` 12 instead of 24. Every CLI path built on `decode_gameplay_sections` (`dm2 save show/party/champion/global`, `dm2 info`'s section decode) sees a truncated wrong timer list on Mac. Scalar edits still splice byte-safely (the error is symmetric between decode and re-encode), but all timer reads are wrong. 2. **The LE path truncates to 8 bits** (`& 0xFF`) while the engine reads the full i16 (`sksvgame.cpp:1517` passes `timdat.num_timers` whole) and the mask field is 9 bits. Irrelevant for retail DOS (timer cap 50), but SKWINSPX's `DM2_EXTENDED_MODE` raises the cap to 500 — an extended-mode save with >255 timers mis-decodes. Should be `& 0x1FF`. Additionally `info.rs:167` prints `sgb.timer_count_raw & 0xff` directly, which is wrong on Mac independent of the section decode. ## Fix direction One byte-order-aware helper (9-bit, Mac BE formula) used by `decode_full`, `GameplaySections::decode`, and the CLI display — the logic currently exists only inline in `decode_full`. ## Reproduction `SaveFile::parse(fixtures/mac-us/saves/early_game, ByteOrder::Big).decode_gameplay_sections()` returns 0 timers; `decode_full` with the Mac dungeon decodes 1.
jqueuniet commented 2026-07-06 08:47:20 +02:00 (Migrated from codeberg.org)

Fixed by #209 (merged into main).

Fixed by #209 (merged into `main`).
Sign in to join this conversation.
No labels
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#170
No description provided.