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
+31 -12
View File
@@ -7,10 +7,12 @@
#pragma once
#include "error/error.h"
#include "save/savefile.h"
#include "save/saveslot.h"
#include "save/savemeta.h"
#define SAVE_LINUX_PATH_MAX FILENAME_MAX
#define SAVE_LINUX_FILE_FORMAT "%s/save_%u.dat"
#define SAVE_LINUX_SLOT_FILE_FORMAT "%s/slot%u.json"
#define SAVE_LINUX_META_FILE_FORMAT "%s/settings.json"
#ifndef SAVE_LINUX_PATH
#define SAVE_LINUX_PATH "./saves"
@@ -21,7 +23,8 @@ typedef struct {
} savelinux_t;
/**
* Initializes the save system on Linux.
* Initializes the save system on Linux - ensures the save directory
* exists (shared by both save slots and meta).
*
* @return An error code if initialization fails.
*/
@@ -35,27 +38,43 @@ errorret_t saveInitLinux(void);
errorret_t saveDisposeLinux(void);
/**
* Loads a save file from disk for the given slot.
* Loads a save slot as JSON (slotN.json) from disk, if it exists.
*
* @param slot The save slot index.
* @param file Output save file data.
* @return An error code if the load fails.
* @param out Output slot data.
* @return An error code if the slot exists but fails to parse.
*/
errorret_t saveLoadLinux(const uint8_t slot, savefile_t *file);
errorret_t saveSlotLoadLinux(const uint8_t slot, saveslot_t *out);
/**
* Writes a save file to disk for the given slot.
* Writes a save slot as JSON (slotN.json) to disk.
*
* @param slot The save slot index.
* @param file Save file data to write.
* @param slotData Slot data to write.
* @return An error code if the write fails.
*/
errorret_t saveWriteLinux(const uint8_t slot, const savefile_t *file);
errorret_t saveSlotWriteLinux(const uint8_t slot, saveslot_t *slotData);
/**
* Deletes the save file for the given slot from disk.
* Deletes the save slot JSON file for the given index.
*
* @param slot The save slot index.
* @return An error code if the delete fails.
*/
errorret_t saveDeleteLinux(const uint8_t slot);
errorret_t saveDeleteSlotLinux(const uint8_t slot);
/**
* Loads save meta as JSON (settings.json) from disk, if it exists.
*
* @param out Output meta data.
* @return An error code if the file exists but fails to parse.
*/
errorret_t saveMetaLoadLinux(savemeta_t *out);
/**
* Writes save meta as JSON (settings.json) to disk.
*
* @param meta Meta data to write.
* @return An error code if the write fails.
*/
errorret_t saveMetaWriteLinux(savemeta_t *meta);