Unify save system into one save.h/.c; diverge storage format per platform

Renames savefile_t to saveslot_t and folds last session's standalone
settings.h/.c module back in as savemeta_t, so there's one save system
(SAVE.slots[] + SAVE.meta) instead of two parallel ones - while letting
each platform pick its own physical format for the two concepts:

- Linux now writes human-editable JSON (slot0.json, settings.json, ...)
  via yyjson's mutable writer API, so players can hand-fix a bad setting.
- PSP folds meta into the same sceUtilitySavedata binary payload as its
  one save slot (SAVE_SLOT_COUNT_MAX=1 there - a future save picker will
  let players manage multiple named saves via the OS's own browser).
- GameCube consolidates the 3 per-slot memory card files and the separate
  settings file into one combined card file.

Also fixes two bugs surfaced while building this: the CRC finalize step
seeked to a hardcoded offset (only safe for one section per file, breaks
once meta+slots share a buffer), and save.c's async/sync dispatch left an
unconditional fallback call that doesn't exist on PSP-only platforms.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-04 18:35:06 -05:00
parent 7f7be39230
commit aa0180571e
59 changed files with 1142 additions and 2071 deletions
+17 -14
View File
@@ -20,34 +20,28 @@ typedef struct {
size_t position;
/** True when opened for writing; flushes buffer to card on close. */
bool_t writing;
/** Slot index stored at open time so Close can derive the filename. */
uint8_t slot;
} savestreamdolphin_t;
/**
* Opens a memory card slot for reading by loading its sector into buffer.
* Opens the consolidated memory card file for reading by loading its
* sector into buffer.
*
* @param p Stream to initialize.
* @param found Set to true if the file exists, false if it does not.
* @param slot Save slot index.
* @return An error if reading the card fails for a reason other than
* missing file.
*/
errorret_t saveStreamOpenReadDolphin(
savestreamdolphin_t *p, bool_t *found, const uint8_t slot
);
errorret_t saveStreamOpenReadDolphin(savestreamdolphin_t *p, bool_t *found);
/**
* Opens a memory card slot for writing by zeroing the sector buffer.
* The buffer is flushed to the card when savestreamCloseDolphin is called.
* Opens the consolidated memory card file for writing by zeroing the
* sector buffer. The buffer is flushed to the card when
* saveStreamCloseDolphin is called.
*
* @param p Stream to initialize.
* @param slot Save slot index.
* @param p Stream to initialize.
* @return An error if initialization fails.
*/
errorret_t saveStreamOpenWriteDolphin(
savestreamdolphin_t *p, const uint8_t slot
);
errorret_t saveStreamOpenWriteDolphin(savestreamdolphin_t *p);
/**
* Flushes the sector buffer to the memory card (write mode only) and
@@ -89,3 +83,12 @@ errorret_t saveStreamWriteBytesDolphin(
* @return An error if pos is out of range.
*/
errorret_t saveStreamSeekDolphin(savestreamdolphin_t *p, const size_t pos);
/**
* Gets the current read/write position within the sector buffer.
*
* @param p Active stream.
* @param out Receives the current position.
* @return An error - always succeeds, matches saveStreamTellImpl's shape.
*/
errorret_t saveStreamTellDolphin(savestreamdolphin_t *p, size_t *out);