Cargo workspace:
core/(sav_core) — the whole pipeline, pure Rust: chunked zlib decompression, save parsing into a compactSaveStore(the decompressed buffer is retained; strings are zero-copyu32ranges into it), andmapdata/— the map-payload builder, save index, and the six detail queries the frontend uses (describeInstance,findItemLocations, building/vehicle/train info, selection inventory). Static game data (game_data/generated/{docs,world}/*.json,game_data/curated/*.json, the item-icon manifest) is embedded at compile time, so building requires the game data extracted first (see the root README).wasm/(sav_wasm) — the wasm-bindgen boundary.SaveSession::loadparses a.savfrom bytes and builds payload + index; the query methods return JSON strings. Loaded bymap/static/map/worker.jsinside a Web Worker (built withwasm-pack --target no-modulesbytools/build_site.py).
- Single-threaded on wasm; the
parallelfeature enables rayon chunk decompression for native builds (same chunk order, identical output bytes). - Progress reporting is a plain
FnMut(phase, current, total)driven synchronously from inside the parse/build; the worker forwards it to the page aspostMessageevents. mapdata/is a behavioral port of the original Pythonmap/sav_map_data.py(see git history / themainbranch). It was landed collector-by-collector behind a bit-exact differential gate against the Python reference (order-strict JSON comparison,float.hex()equality), which is why the code deliberately reproduces Python quirks: dict insertion-order semantics (IndexMap; last-value-wins/first-position-kept), CPython's ownmath.hypotalgorithm (jsonval::py_hypot), banker's rounding (py_round), exact Pythonrepr(float)(display.rs),rem_euclidfor Python%, absence-vs-null-vs-0 distinctions. Do not "simplify" these without understanding what they mirror.- Decompressed-save size cap is wasm32-only:
StrRef/DataRefand the store's span/offset fields useusizeoffsets, which isu32on wasm32 (the browser build — a 4GB address space it can't exceed anyway) and 64-bit on native (the desktop app), so native has no cap. The guard indecompress.rsis#[cfg(target_pointer_width = "32")].
cargo test -p sav_core # unit tests (fixtures generated from CPython)
py tools/build_site.py # wasm build + site assembly into dist/