- Rust 96.3%
- Kaitai Struct 1.1%
- Python 1%
- GLSL 0.5%
- Shell 0.4%
- Other 0.6%
| .claude | ||
| .forgejo/workflows | ||
| .idea | ||
| crates | ||
| docs | ||
| fixtures | ||
| formats | ||
| fuzz | ||
| scratch | ||
| scripts | ||
| tooling | ||
| .gitignore | ||
| Cargo.lock | ||
| Cargo.toml | ||
| deny.toml | ||
| LICENSE-APACHE | ||
| LICENSE-MIT | ||
| README.md | ||
| ROADMAP.md | ||
dm2-tools
A Cargo workspace of Rust libraries and a CLI for working with Dungeon Master II asset files (the 1995 Legend of Skullkeep).
The goal is to provide reusable, well-tested parsers for the formats the game
ships in — graphics.dat, dungeon.dat, music data, savegames — and a
single dm2 binary that uses them to extract, convert, and repack assets
into the layout downstream consumers expect (notably the unofficial
skproject C++ port).
This is tooling only. The runtime engine is out of scope here; if you want to play the game, point the converted output at an engine that knows how to load it.
Layout
crates/
├── dm2-graphics/ library: graphics.dat parser/writer (formats 4/5, LE+BE) + 107 SFX decoder
├── dm2-dungeon/ library: dungeon.dat parser/writer (LE+BE)
├── dm2-music/ library: HMP (DOS), MOD (Amiga), SMF + 'snd ' (Mac resource fork)
├── sms-audio/ library: SoundMusicSys (Mac) song renderer — SMF + Sound Manager sample bank to PCM
├── opl-audio/ library: pure-Rust OPL2 (YM3812) FM renderer — timed MIDI events + AdLib bank to PCM
├── mod-audio/ library: ProTracker (Amiga MOD) renderer, wraps xmrsplayer with Paula-faithful hard panning
├── dm2-saves/ library: SkSave#.dat / .bak full decode/encode (header, gameplay sections, record stream phases 1–7; DOS + Mac, bit-exact field re-encode)
├── dm2-ftl/ library: FTL 68k module container parser (Sega CD / Amiga) — decompressors + all four checksums
├── dm2-wav/ workspace-internal: shared mono 8-bit WAV writer (consumed by dm2-graphics + dm2-music)
├── dm2-binrw/ workspace-internal: binrw glue (parse/write_to/to_bytes helpers)
├── dm2-test-fixtures/ workspace-internal: fixture-path macros
└── dm2-cli/ binary `dm2`: info, extract, dump, convert, repack, verify, save, render
Editing savegames from the CLI is documented in
docs/cli-save-editing.md.
Library crates accept &[u8] or impl Read + Seek; only the CLI does path
I/O. This keeps parsers cheap to test and fuzz.
Build
cargo build --workspace
cargo test --workspace
cargo run -p dm2-cli -- --help
Format specs (Kaitai Struct)
formats/ holds machine-readable .ksy specifications
for the DM2 formats we have firm byte-level knowledge of —
graphics.dat (format 5, LE+BE), dungeon.dat header (LE+BE), Mac
md.dat, DOS songlist.dat, sksave#.dat header. The specs are
verified end-to-end against fixtures via the Python kaitaistruct
runtime and serve as the canonical declarative reference.
The Rust crates parse via binrw rather
than codegen — see formats/README.md for the
rationale and the hand-sync convention between .ksy and #[binrw]
structs.
Roadmap
ROADMAP.md tracks what is done versus what remains across
all crates and infrastructure. Update it as items move from one column to
the other rather than letting it go stale.
Contributing
docs/development.md collects the working
conventions: the branch/commit workflow, the pre-push gate that mirrors
CI, markdown/doc house style, the source-of-truth hierarchy for
reverse-engineering claims, and the Codeberg CI host quirks.
Format documentation
Format notes live under docs/formats/:
graphics-dat.md— the asset archivedungeon-dat.md— level datamusic.md— DOS HMP, Amiga MOD (Player 4.1A packed), Mac US SMF-via-SoundMusicSys, Sega CD / Mac JP Red Book CD-DA, and the Mac USmd.dat/ DOSsonglist.dat/ AmigaCD.DATmusic-routing tablessaves.md—SkSave#.datsavegames; see its capability matrix for per-port support and conversionqstrat-dat.md— Hint Oracle data (Mac US + Amiga; DOS embeds it insidegraphics.dat)mac-resources.md— Mac resource fork reference (the format the entire Mac US soundtrack is delivered in; Mac JP uses Red Book CD-DA instead)
Per-source notes live under docs/sources/; see
docs/sources/overview.md for the
cross-port doc index, the 16-fixture attribute matrix, and the
asset-family / DUNGEON.DAT lineage clusters. Each port has its own
extraction-recipe doc next to the overview.
Operational tooling notes — which external CLI tools (binwalk,
hexyl, rizin, sox, fluidsynth, kaitai-struct-compiler, …)
help with which task — live in
docs/tooling.md. None are workspace build
dependencies; they are agent-driveable companions for asset
extraction and verification work.
External references are collected in
docs/external-references.md; format
docs cite them by short name. Currently registered: [DMWEB],
[DMFORUM], [GREATSTONE], [DM2EDIT], [SKPROJECT], [KKDF2],
[IM], [RFC1740], [HMI], [SMF], [SMS], [SCUMMVM].
Test fixtures
No game data is committed. See fixtures/README.md for
the layout you can drop your own legitimately-owned copies into so integration
tests run against real data.
License
Dual-licensed under MIT or Apache-2.0 at your option. See LICENSE-MIT and
LICENSE-APACHE.