-
v0.2.1
StableAll checks were successfulCI / stable (pull_request) Successful in 1m36sCI / python bindings (3.11) (pull_request) Successful in 38sCI / msrv (1.90) (pull_request) Successful in 42sCI / audit (pull_request) Successful in 23sCI / msrv (1.90) (push) Successful in 43sCI / audit (push) Successful in 24sCI / stable (push) Successful in 1m37sCI / python bindings (3.11) (push) Successful in 39sRelease / wheel + c bundle (manylinux x86_64) (push) Successful in 1m44sRelease / build (cli + windows wheel + c bundle) (push) Successful in 2m14sRelease / publish (push) Successful in 23sreleased this
2026-09-05 08:29:21 +02:00 | 4 commits to main since this releaseAdded
- C bundles — tagged releases now attach
dm2-ffi-<ver>-x86_64-linux-gnu
and-x86_64-windows-gnuarchives, each with the cbindgen header, the shared
library, the crate README carrying theDm2Bufferownership contract, and
both licenses. The Linux one is built in the manylinux image, so it needs
only glibc 2.28. The 30-40 MB static archive is left out: it would grow the
compressed bundle elevenfold to duplicate what the shared library provides.
Changed
dm2-wasm— prepared for npm.build-npm.shbuilds the package for the
bundlertarget and publishes it under the namedm2-tools, matching the
PyPI distribution; the crate ships copies of the two licenses, which
wasm-pack bundles,build-npm.shlists infilesso npm actually packs
them, and CI diffs against the originals; andwasm-optnow optimises for
size (-Oz). CI gained awasm32-unknown-unknowncheck,
since a host build compiles the#[wasm_bindgen]layer inertly and cannot
catch a break in it.dm2-wasm— no longer published to crates.io (publish = false, and
0.2.0 deleted there). The bindings target JavaScript, which reaches them
through wasm-pack output rather than cargo, and the crates.io copy
documented nothing: docs.rs builds for x86-64, where every#[wasm_bindgen]
export is compiled out, so the page listed onlyWasmError. The crate stays
in the workspace and is built and tested exactly as before. Its unused
[workspace.dependencies]entry, which carried a version requirement no
crate consumed, is dropped.- Python bindings —
requires-pythonraised to>=3.11. 3.9 went EOL in
October 2025 and 3.10 follows in October 2026, so the old>=3.9floor
advertised runtimes that no longer get security fixes and that the suite
could not import anyway. Installing already requires a Rust toolchain to
build the cdylib, so a distro system Python was never the constraint. The
test helper now parses the manifests with the stdlibtomllibinstead of a
regex. Adds aclassifierslist so a PyPI upload carries version, platform
andTyping :: Typedtrove tags. - CI — new
pythonjob installs the bindings on a standalone CPython 3.11
(fetched by a pinned, hash-checkeduv) and runs their pytest suite, so the
declared floor and the hatchling cdylib-bundling hook are both exercised.
Previously nothing in CI touchedbindings/pythonat all. - Python bindings — the wheel is now tagged
py3-none-<platform>instead
ofcp3XX-cp3XX-<platform>. Nothing links against the CPython C API, so the
old tag demanded a separate wheel per interpreter minor for no reason; one
wheel per platform now installs on every supported Python. The build hook
also clears its_libstaging directory, which previously let a cross-built
wheel ship a second, wrong-platform library. - Python bindings — packaging metadata filled in:
[project.urls],
keywords, and the twoLICENSE-*files, which the wheel previously omitted
despite declaringLicense-Expression. - Release — tagged builds now attach Python wheels:
py3-none-manylinux_2_28_x86_64from a newwheel-linuxjob in the
manylinux image (auditwheelrelabels thelinux_x86_64tag PyPI rejects),
andpy3-none-win_amd64cross-built with mingw alongside the CLI. Wheels
only, no sdist — an sdist ofbindings/pythoncannot build, since the
cdylib it compiles lives in the cargo workspace above it. macOS and aarch64
Linux wheels are not built; seedocs/development.md. - Release — the workflow is now two build jobs feeding a
publishjob
through Forgejo'supload-artifactaction, instead of one job that built
and published in sequence. Assets are attached only once every build has
succeeded, so a failure can no longer leave a published tag missing one;
SHA256SUMS.txtcovers the wheels as well as the CLI archives; and a
workflow_dispatchrun leaves every asset downloadable from the run page.
Fixed
- Python bindings —
bindings/python/pyproject.tomlstill declared
0.1.1, so the 0.2.0 wheel carried pip metadata a version behind the
cdylib it bundles, and the suite's version assertion (hardcoded to the old
string) failed against it. The package version now tracks the workspace, and
the test derives both sides from the manifests instead of pinning a literal. - Python bindings —
tests/test_roundtrip.pyannotated a helper with a
PEP 604 union but omittedfrom __future__ import annotations, so importing
the module raisedTypeErroron the 3.9 and 3.10 thatrequires-python
claims to support. The suite only ever ran on 3.11+.
Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads
- C bundles — tagged releases now attach
-
v0.2.0
StableAll checks were successfulCI / msrv (1.90) (pull_request) Successful in 45sCI / audit (pull_request) Successful in 22sCI / stable (pull_request) Successful in 1m17sCI / audit (push) Successful in 22sCI / stable (push) Successful in 1m16sCI / msrv (1.90) (push) Successful in 46sRelease / build + release (push) Successful in 1m28sreleased this
2026-09-04 19:23:59 +02:00 | 13 commits to main since this releaseAdded
dm2-wasm— browser bindings exposing the parser crates to JavaScript
viawasm-bindgen. All parser crates already compile to
wasm32-unknown-unknownunchanged, so this is a marshalling layer rather
than a port: a purefn(&[u8]) -> Result<_, WasmError>core covered by
native tests, one unifiedWasmErrorwhoseDisplayis 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 ofdm2-wasm(now a re-export plus a
wasm-bindgenshim). 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 plusdm2_version, and a
committed cbindgen-generated header guarded by a drift-check test.- Python bindings (
bindings/python, pip-installabledm2-tools) —
ctypes overdm2-ffiwith a Pythonic dict/bytes API and aDm2Error
exception, a hatchling build hook that builds and bundles thedm2-ffi
cdylib into a platform-tagged wheel, and a pytest suite mirroring the ABI
round-trip and read proofs. - Savegame JSON —
dm2 dumpnow 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-containedto embed the
full bitstream so the JSON reloads without adungeon.dat/graphics.dat,
and--full(with--gdatand--dungeon) for a field-driven dump whose
record_streamis 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.datJSON.DungeonDumpcarries every typed section as editable
fields plus the tile-data-block tail as a base64 seed, soreconstruct()
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 lossyskprojectdump is
unchanged.serdeSerialize/Deserializederives across thedm2-saves
RecordStreamgraph and every owned section type of thedm2-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.mdas a "Platform families" section; the Sega CD
in-game SFX location documented as resolved (they arecls3=0x02dtSnd
records ingraphics.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
intotooling/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-2shift drops
damagesuffered, notbodyflag. 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 indocs/.
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 (thelooks_like_*header fingerprint) is now
separated from the full parse, soinfo,verify,dump,raw-extract,
and thesavesubcommands 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
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads
-
v0.1.1
StableAll checks were successfulCI / msrv (1.90) (pull_request) Successful in 42sCI / stable (pull_request) Successful in 1m1sCI / audit (pull_request) Successful in 19sCI / msrv (1.90) (push) Successful in 44sCI / stable (push) Successful in 1m1sCI / audit (push) Successful in 18sRelease / build + release (push) Successful in 1m28sreleased this
2026-07-23 14:10:31 +02:00 | 53 commits to main since this releaseFixed
- Dependency issue on internal dev crate
Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads
-
v0.1.0
StableAll checks were successfulCI / msrv (1.90) (pull_request) Successful in 44sCI / stable (pull_request) Successful in 58sCI / audit (pull_request) Successful in 15sCI / msrv (1.90) (push) Successful in 42sCI / stable (push) Successful in 57sCI / audit (push) Successful in 15sRelease / build + release (push) Successful in 1m26sreleased this
2026-07-23 13:34:48 +02:00 | 56 commits to main since this releaseFirst public release: a Rust workspace of parsers, decoders, and a
dm2
command-line tool for the assets of Dungeon Master II: The Legend of
Skullkeep, covering the PC (DOS), Macintosh, Amiga, and Sega CD editions in
both little- and big-endian byte orders.Added
dm2CLI — inspect, extract, convert, repack, render, and edit game
assets:info— print format metadata for a single asset file.extract— unpackgraphics.dat/dungeon.datinto a directory, with
indexed-PNG transparency detection, font-sheet spacing control,
console-family lighting (--style/--light), per-language text
filtering, and additive type filters (--sfx,--music,--palette,
--font, …).dump— convert a recognised file to JSON.convert— transcode music between formats (HMP↔MIDI, …) and savegames
between DOS and Mac layouts.repack— reassemble an original install into a target engine's expected
layout.render— render music to 16-bit audio: Mac via the SoundMusicSys synth
(22254 Hz), DOS via OPL2/OPL3 (49716 Hz), Amiga via a Paula-faithful
ProTracker replayer (44100 Hz). WAV to a file, raw s16le PCM to stdout.verify— round-trip parse → emit → byte-compare to prove writer fidelity.save— read and edit savegames.
dm2-graphics— parser and writer forgraphics.dat(format 3/4/5, LE
and BE), including image, palette, font, text, and sound-effect payloads.dm2-dungeon— parser and writer fordungeon.dat(LE and BE variants).dm2-saves— parser and writer for savegame files (SkSave.dat,
sksave.bak), across DOS and Mac variants.dm2-music— decoders for DM2 music and audio: HMI/HMP (DOS), Amiga MOD,
and the Macintosh classic resource fork ('Midi'SMF,'snd 'Sound Manager
samples, plus AppleDouble v2 / MacBinary II unwrappers).mod-audio— ProTracker (Amiga MOD) rendering with Paula-faithful hard
panning.dm2-ftl— parser for the FTL 68k module container used by the Sega CD
and Amiga ports (and the DM/CSB console ports), including the zero-run
HUNK_DATAand nibble-streamHUNK_CODEdecompressors and all four
container checksums.dm2-wav— WAV writing helpers for the audio formats the game shipped.dm2-binrw— workspace-internalbinrwglue: trait-bounded
parse / write / to-bytes helpers shared by the binary parsers.dm2-test-fixtures— workspace-internal test helpers that resolve paths
againstfixtures/and skip silently when a fixture is absent.- Per-crate
examples/demonstrating minimal use of each library crate. - Engineering hygiene: CI,
cargo-denysupply-chain checks, Kaitai Struct
format specs, rustdoc pages, and fuzz targets.
Notes
- The reusable synth crates
opl-audioandsms-audiowere split out of this
workspace and are published separately on crates.io;dm2-toolsconsumes
them as external dependencies.
Downloads
-
Source code (ZIP)
0 downloads
-
Source code (TAR.GZ)
0 downloads