• v0.2.0 810bc844f4

    v0.2.0
    All checks were successful
    CI / msrv (1.90) (pull_request) Successful in 45s
    CI / audit (pull_request) Successful in 22s
    CI / stable (pull_request) Successful in 1m17s
    CI / audit (push) Successful in 22s
    CI / stable (push) Successful in 1m16s
    CI / msrv (1.90) (push) Successful in 46s
    Release / build + release (push) Successful in 1m28s
    Stable

    jqueuniet released this 2026-09-04 19:23:59 +02:00 | 13 commits to main since this release

    Signed by jqueuniet
    SSH key fingerprint: SHA256:hjUxou9yR5AKBQ8zK2FkTEp12iDlEomvb63VBpXVwN4

    Added

    • dm2-wasm — browser bindings exposing the parser crates to JavaScript
      via wasm-bindgen. All parser crates already compile to
      wasm32-unknown-unknown unchanged, so this is a marshalling layer rather
      than a port: a pure fn(&[u8]) -> Result<_, WasmError> core covered by
      native tests, one unified WasmError whose Display is the JS-facing
      message, and #[wasm_bindgen] passthroughs with camelCase names. Saves and
      dungeons get a byte-exact self-contained JSON round-trip plus the lossy
      read views; graphics, music, and FTL are read-only decoders (header summary
      and image→PNG; detect, HMP→SMF, MOD→WAV, snd →WAV; FTL container info and
      round-trip). Byte order is auto-detected inside the crate.
    • dm2-convert — wasm-free crate holding the conversion functions and
      their unified error, extracted out of dm2-wasm (now a re-export plus a
      wasm-bindgen shim). Adds resource-fork listing and extraction.
    • dm2-ffi — C ABI over the parser crates: a stateless
      Dm2Buffer { data, len, error } return convention with a single
      dm2_buffer_free, 16 panic-guarded exports plus dm2_version, and a
      committed cbindgen-generated header guarded by a drift-check test.
    • Python bindings (bindings/python, pip-installable dm2-tools) —
      ctypes over dm2-ffi with a Pythonic dict/bytes API and a Dm2Error
      exception, a hatchling build hook that builds and bundles the dm2-ffi
      cdylib into a platform-tagged wheel, and a pytest suite mirroring the ABI
      round-trip and read proofs.
    • Savegame JSONdm2 dump now emits savegame JSON in three flavours:
      gameplay-only by default (typed header, SGB, globals, champions, effects,
      and timers, each with a raw escape hatch), --self-contained to embed the
      full bitstream so the JSON reloads without a dungeon.dat / graphics.dat,
      and --full (with --gdat and --dungeon) for a field-driven dump whose
      record_stream is editable. Both self-contained and field-driven dumps
      reconstruct byte-identical originals, gated over all 4 DOS retail slots and
      all 14 Mac retail saves. Reconstruction is hardened against hand-edited or
      untrusted JSON: typed errors instead of panics, and a 16 MiB allocation cap.
    • dm2 dump --format dungeon-lossless — self-contained lossless
      dungeon.dat JSON. DungeonDump carries every typed section as editable
      fields plus the tile-data-block tail as a base64 seed, so reconstruct()
      needs no external files, and parse → JSON → reconstruct is byte-exact over
      every dungeon fixture in both byte orders (including the FM-Towns JP
      off-by-one tail padding). Format, schema, length, and allocation guards
      return typed errors instead of panicking. The lossy skproject dump is
      unchanged.
    • serde Serialize/Deserialize derives across the dm2-saves
      RecordStream graph and every owned section type of the dm2-dungeon
      graph, so both are usable as data models outside the CLI.
    • Forgejo issue templates (feature / bug / research) that preset the type/*
      labels and prompt for area and port.

    Changed

    • Documentation: a Releasing runbook in the development guide covering the
      dependency-ordered publish; the "Known DM2 ports" table moved into
      docs/sources/overview.md as a "Platform families" section; the Sega CD
      in-game SFX location documented as resolved (they are cls3=0x02 dtSnd
      records in graphics.dat, missed by the 6-byte DOS/Mac SFX-framing scan).
    • Documentation and source comments no longer reference untracked working
      directories, so a fresh clone has no dangling pointers. The one
      load-bearing tool that lived there, extract_mac_object_masks.py, moved
      into tooling/oracle-compare/.
    • Corrected the documented Mac champion mask: its field bit widths are the
      same as DOS (HP/MP 10-bit, stamina 14-bit, food/water 16-bit, popcount
      1045), not widened/narrowed as previously claimed, and the -2 shift drops
      damagesuffered, not bodyflag. Three stale rows in the DOS mask table
      (0x29, food, water) were fixed alongside.
    • Dependencies updated.

    Removed

    • ROADMAP.md, in favour of issues and milestones on the project forge.
      Per-format and per-port reference material stays in docs/.

    Fixed

    • A corrupt savegame is now reported with the parser's own diagnostic instead
      of a generic "could not identify" / "not a recognised DM2 savegame". The
      savegame family gate (the looks_like_* header fingerprint) is now
      separated from the full parse, so info, verify, dump, raw-extract,
      and the save subcommands surface e.g. "sksave truncated in map_table:
      need 704 bytes, got 14" for a truncated save. Matches the behaviour the
      magic-bearing families (graphics.dat, FTL, Mac resource forks) already
      had.
    Downloads