mirror of
https://github.com/bryanthaboi/gen1recomp
synced 2026-10-05 08:57:49 -04:00
42 lines
3.8 KiB
Markdown
42 lines
3.8 KiB
Markdown
# Save conversion
|
|
|
|
Cartridge `.sav` files go in and out of the launcher through `src/save_convert/`. One codec per generation:
|
|
`GenSave` (Red/Blue/Yellow), `Gen2Save` (Gold/Silver/Crystal), `Gen3Save` (FireRed/LeafGreen/Emerald).
|
|
`SaveConvert.importSav` / `exportSav` are the only entry points; both return `nil, message` instead of raising.
|
|
|
|
## Supported
|
|
|
|
- Gen 1: 32768 bytes, English. Gen 2: 32768 bytes plus an optional RTC footer, English. Gen 3: 128 KB flash plus an optional footer.
|
|
- Not converted: Japanese and Korean carts, Ruby/Sapphire. Detected ones are refused with a named reason.
|
|
- Gen 1 and Gen 2 need the selected game's imported ROM cache; missing data refuses conversion with a named reason.
|
|
|
|
## Round trips
|
|
|
|
- `export(import(cart), cart)` reproduces the cart except for a short list of normalizations (box checksums, party level byte, Gen 3 slot rotation and counter).
|
|
- Every region is tiered in `src/save_convert/regions/gen<N>.lua`: T1 modeled, T2 carried verbatim from the cart image, T3 derived.
|
|
- The cart image rides inside the slot (`rawImport` for Gen 1/2, `modData.cartImage` for Gen 3), so export needs no second file.
|
|
A `.cart` sidecar from an older build is read once at export, folded into the slot and deleted.
|
|
- Import returns an optional note (backup copy used, stale active box, older Gen 3 slot) that the launcher shows beside the result.
|
|
- Gen 2 preserves the current map's object visibility and rebuilds visible NPCs when exporting onto a new map. Fresh and moved exports need the current ROM cache's sprite metadata; re-import the ROM when an older cache is refused.
|
|
- Successful exports return named reader warnings to the launcher and CLI. Damaged embedded Gen 3 images refuse export unless a valid matching template can recover them.
|
|
- Gen 3 `modData.cartImage` is `PKCI1:<length>:<base64 of LZ>` (`gen3_port/imagepack.lua`, about 5 KB for a typical slot instead of 190 KB); a raw image from an older build is still read.
|
|
- Gen 3 regions with no engine state are carried and proven so in `regions/gen3.lua` (`proof` per row, checked by `tests/save_compat/gen3_carry_contract_test.lua`).
|
|
The FireRed quest log is carried and reset with the map window: the engine's own quest log is a sampled replay, the cart's is an input script.
|
|
- Emerald and FireRed engine sections (TV, Frontier, Trainer Hill, Mauville, Lilycove, Apprentices, Hall records, VS Seeker, Trainer Tower, minigame records, Mystery Gift news/card/metadata) live in `gen3_port/sections/`.
|
|
The Wonder Card gift payload is script bytecode and stays template-carried; a different engine card clears the cart card instead of writing a card the game would reject.
|
|
|
|
## Reader validator
|
|
|
|
`Compat.check(bytes, version)` mirrors the detectors of PKHeX, PKForge and OpenHome and the game's own checks.
|
|
Errors block the export (`Compat.gate`), warnings are returned and never block.
|
|
The tested PKHeX Gold/Silver writer overlaps the last 45 Hall of Fame bytes with a backup copy; exports warn when existing Hall of Fame data would change.
|
|
Rules are listed in `Compat.RULES`; `tests/save_compat/compat_validator_test.lua` crafts a bad image for each one.
|
|
|
|
## Tests and tools
|
|
|
|
- `luajit tests/run_save_compat.lua`: fixtures, R1/R2 round trips, fuzz, validator. `SAVE_COMPAT_FUZZ_N` and `SAVE_COMPAT_FUZZ_SEED` widen the fuzz runs.
|
|
- `SAVE_COMPAT_REAL_SAVES="red=/path/a.sav;crystal=/path/b.sav"` runs the validator over your own carts.
|
|
- `scripts/save-compat.sh` dumps every fixture export and runs the PKHeX probe (dotnet) and the OpenHome probe (node), then diffs against `tests/fixtures/save/expected/`.
|
|
`--bless` rewrites the expected files; a missing toolchain skips that probe. Needs `PKHEX_ROOT` and `OPENHOME_ROOT` checkouts.
|
|
- `tools/save_convert/convert.lua` is the CLI. Set `<GAME>_CACHE` (for example `YELLOW_CACHE` or `EMERALD_CACHE`) to that game's imported cache directory.
|