feat(dungeon): lossless round-trippable JSON for dungeon.dat (#309) #313
No reviewers
Labels
No labels
area/ci-release
area/cli
area/docs
area/dungeon
area/ftl
area/graphics
area/gui
area/music
area/saves
area/tooling
port/amiga
port/dos
port/fm-towns
port/mac
port/pc98
port/sega-cd
priority/high
priority/low
priority/medium
type/bug
type/chore
type/docs
type/feature
type/research
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
jqueuniet/dm2-tools!313
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feat/dungeon-json-roundtrip"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Closes #309 — a lossless, round-trippable JSON representation for
dungeon.datindm2-dungeon, alongside (not replacing) the existing lossyjson::skprojectinterop dump. Follows the owned-DTO + base64-seed + byte-exact-gate pattern established for saves (#308).Design — self-contained, no external files
Dungeon::to_bytesreads the original bytes in exactly one place:self.bytes[block_start..](the tile-data-block tail). Everything beforeblock_startre-emits purely from typed owned fields. So the losslessDungeonDumpembeds:map_data_size=12436+1 byte).reconstruct()rebuilds a syntheticvec![0; block_start] ++ seedbuffer, constructs aDungeon, and callsto_bytes(). Becauseto_bytesreads only[block_start..] == seedand re-emits the rest from the (round-tripped-identical) typed fields, the output is byte-exact. Unlike the saves field-driven variant, reconstruction needs no external files — the whole dungeon lives in the one JSON document.What this adds
FileHeader,Map,ByteOrder,Columns,ObjectList,TextDatabase,Tile,Oid,MapBody,ObjectTables, and the 13 record types),#[serde(transparent)]on the newtypes. Newbase64dep.json::lossless—DungeonDumpwithfrom_dungeon,to_pretty_json, andreconstruct.json::skprojectis untouched.block_start, and map/body length + body-fit checks. Every failure mode returns a typedJsonError; no reachable panic or over-allocation.tests/json_lossless_roundtrip.rs) — the #309 acceptance criterion, over real fixtures in both byte orders.dm2 dump <dungeon.dat> --format dungeon-lossless, a distinctJsonFormatvariant (does not overload the save-only--self-contained/--full/--gdat/--dungeonflags).Proof
Byte-exact round trip through the JSON text over every present fixture: LE 10/10 (dos-en, dos-fr, dos-de, dos-demo, dos-en-beta, ibm-psv-jp, fm-towns-jp, pc9801-jp, pc9801-jp-demo, pc9821-jp) + BE 6/6 (mac-us, mac-jp, mac-demo, amiga-eu, sega-cd-us, sega-cd-jp), plus the FM-Towns padding regression.
dm2-dungeonsuite 114 lib + all integration tests green;dump_saveunchanged (6/6). fmt clean; no new clippy warning on changed files; no new workspace dep beyondbase64.Notes / follow-ups (non-blocking)
map_bodiesre-emit — a documented size tradeoff (the typed body deterministically wins via the splice), matching the self-contained precedent; a pad-only optimization is possible later but risks missing an undiscovered padding gap.body.to_bytes()length) is not supported through this path without also adjusting theMapsize word — a limitation inherited fromto_bytes, not introduced here.Out of scope (per #309): the #307 web serialization scheme and graphics.