Skip to content

Saves

A save bundle is one game’s state as the medium stored it. It is the shape an emulator or a cartridge reader writes, and this is the only document such a producer needs: cards and collections are other shapes, with documents of their own.

shape is "save". Everything else identifies what the bytes are.

KeyNameReq?Notes
0shapeyes"save".
1systemnoWhat will load these bytes. See the System Registry.
2gamenoIdentification hints. Absent means unidentified, which is a valid save.
3sourcenoWhat produced it.
5descriptionnoFree-form note.
6created_atnoWhen the bundle was assembled, not when the player saved.

card is forbidden. A save that came off a card is still a save; the card it came off is a card bundle that holds it.

The full definitions are in the header map. Everything about the save that is not in a payload belongs here, because the header is what survives the bundle being carried anywhere.

One part, and that part is the save. Its payload is the bytes the console wrote, its sha256 is the digest of those bytes, and every other part key is absent: kind defaults to save, role to primary, path to nothing.

A consumer MAY refuse a save bundle with more than one part. A producer that writes one part is therefore the producer most consumers can read, and an emulator writing a cartridge save has no reason to write more.

KeyNameReq?Notes
0idyesThe part’s index, counting from 0.
9sha256yesTag 18540 over the uncompressed payload.
-1payloadyesThe bytes, or a reference to them. Always last in the map.
7sizeon compressionThe uncompressed length, carried only when it cannot be derived.

Every other key is for a save the container gave more than one part, and Bundle defines them all.

Two forms, and a producer picks one:

  • Embedded, the ordinary case: sha256 and the bytes. No encoding, no size, because an embedded uncompressed payload states its own length.
  • Compressed: encoding, size and sha256, then the compressed bytes. sha256 and size both describe the payload before compression, so neither changes when a producer recompresses.

Every container is definite-length and deterministically encoded per RFC 8949 section 4.2: map keys in canonical order, preferred integer heads, no indefinite lengths. Text is NFC. The rule and its reasons are in One encoding per bundle, and a producer that emits canonical CBOR meets it without doing anything special.

Three cases need it, and a producer that does not meet them should not reach for it.

  • Several sockets. One game whose state spans two places on the same system: 3DS savedata in sysnand beside extdata on sd, or an N64 cartridge save beside that game’s note in a Controller Pak. role tells them apart.
  • Several files. A PS2 save is a directory and a 3DS extdata save is a folder. An arcade board is the same case in different clothes: its state is battery-backed NVRAM and an EEPROM and sometimes a timekeeper chip, one part each. path tells those apart, carrying the name the dumping tool uses for the chip.
  • Anything else binary. An aux part with a content_type.

A save’s parts are never bundle parts. One game’s note in a Controller Pak is an ordinary part, told apart by its role; the whole pak is a card in its own right, and a dump holding both the cartridge and the whole pak is a device, because it is two storage components rather than one game’s bytes.

One system’s software wrapping another’s save is not a nesting either. A Wii Virtual Console save of an NES game is an nes save, the same as any other, and what wrapped it is source provenance.

No two parts may agree on role, path and slot together, which is how a consumer names one.

These attach to the header, because they describe the save and travel with it:

A shape, one part, and the digest of its payload:

827539798([
{ 0: "save", 1: "gb" },
[ { 0: 0, 9: 18540(h'…32 bytes…'), -1: h'…the SRAM…' } ]
])

Everything else is optional. A save with no game is unidentified rather than malformed, and a consumer stores it and lets the user associate it later.

The card map, slot, dirent and directory entries belong to Cards. Nesting, content hashes against file hashes, and what a shape may hold matter only where a bundle holds another one. A producer writing single saves needs none of it.