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:
@@ -8,29 +8,17 @@
|
||||
#include "save/save.h"
|
||||
#include "save/savestreamdolphin.h"
|
||||
#include "util/memory.h"
|
||||
#include "util/string.h"
|
||||
|
||||
static void _saveStreamGetFileName(
|
||||
char_t *out, const size_t max, const uint8_t slot
|
||||
) {
|
||||
snprintf(out, max, "%s_%u", SAVE_DOLPHIN_GAME_CODE, (uint32_t)slot);
|
||||
}
|
||||
|
||||
errorret_t saveStreamOpenReadDolphin(
|
||||
savestreamdolphin_t *p, bool_t *found, const uint8_t slot
|
||||
) {
|
||||
errorret_t saveStreamOpenReadDolphin(savestreamdolphin_t *p, bool_t *found) {
|
||||
if(!SAVE.platform.mounted) {
|
||||
*found = false;
|
||||
errorThrow("No memory card mounted");
|
||||
}
|
||||
|
||||
char_t fileName[SAVE_DOLPHIN_FILE_NAME_MAX];
|
||||
_saveStreamGetFileName(fileName, SAVE_DOLPHIN_FILE_NAME_MAX, slot);
|
||||
|
||||
int32_t result;
|
||||
do {
|
||||
result = CARD_Open(
|
||||
SAVE_DOLPHIN_CHANNEL, fileName, &p->cardFile
|
||||
SAVE_DOLPHIN_CHANNEL, SAVE_DOLPHIN_FILE_NAME, &p->cardFile
|
||||
);
|
||||
} while(result == CARD_ERROR_BUSY);
|
||||
if(result == CARD_ERROR_NOFILE) {
|
||||
@@ -41,8 +29,8 @@ errorret_t saveStreamOpenReadDolphin(
|
||||
}
|
||||
if(result < 0) {
|
||||
*found = false;
|
||||
errorThrow("Failed to open memory card file for slot %u: %s (%d)",
|
||||
(uint32_t)slot, saveCardErrorStringDolphin(result), result
|
||||
errorThrow("Failed to open memory card file: %s (%d)",
|
||||
saveCardErrorStringDolphin(result), result
|
||||
);
|
||||
}
|
||||
|
||||
@@ -52,44 +40,40 @@ errorret_t saveStreamOpenReadDolphin(
|
||||
CARD_Close(&p->cardFile);
|
||||
if(result < 0) {
|
||||
*found = false;
|
||||
errorThrow("Failed to read memory card data for slot %u: %s (%d)",
|
||||
(uint32_t)slot, saveCardErrorStringDolphin(result), result
|
||||
errorThrow("Failed to read memory card data: %s (%d)",
|
||||
saveCardErrorStringDolphin(result), result
|
||||
);
|
||||
}
|
||||
|
||||
*found = true;
|
||||
p->position = 0;
|
||||
p->writing = false;
|
||||
p->slot = slot;
|
||||
errorOk();
|
||||
}
|
||||
|
||||
errorret_t saveStreamOpenWriteDolphin(
|
||||
savestreamdolphin_t *p, const uint8_t slot
|
||||
) {
|
||||
errorret_t saveStreamOpenWriteDolphin(savestreamdolphin_t *p) {
|
||||
if(!SAVE.platform.mounted) errorThrow("No memory card mounted");
|
||||
|
||||
memoryZero(p->buffer, SAVE_DOLPHIN_SECTOR_SIZE);
|
||||
p->position = 0;
|
||||
p->writing = true;
|
||||
p->slot = slot;
|
||||
errorOk();
|
||||
}
|
||||
|
||||
void saveStreamCloseDolphin(savestreamdolphin_t *p) {
|
||||
if(!p->writing) return;
|
||||
|
||||
char_t fileName[SAVE_DOLPHIN_FILE_NAME_MAX];
|
||||
_saveStreamGetFileName(fileName, SAVE_DOLPHIN_FILE_NAME_MAX, p->slot);
|
||||
|
||||
int32_t result;
|
||||
do {
|
||||
result = CARD_Open(SAVE_DOLPHIN_CHANNEL, fileName, &p->cardFile);
|
||||
result = CARD_Open(
|
||||
SAVE_DOLPHIN_CHANNEL, SAVE_DOLPHIN_FILE_NAME, &p->cardFile
|
||||
);
|
||||
} while(result == CARD_ERROR_BUSY);
|
||||
if(result == CARD_ERROR_NOFILE) {
|
||||
do {
|
||||
result = CARD_Create(
|
||||
SAVE_DOLPHIN_CHANNEL, fileName, SAVE_DOLPHIN_SECTOR_SIZE, &p->cardFile
|
||||
SAVE_DOLPHIN_CHANNEL, SAVE_DOLPHIN_FILE_NAME,
|
||||
SAVE_DOLPHIN_SECTOR_SIZE, &p->cardFile
|
||||
);
|
||||
} while(result == CARD_ERROR_BUSY);
|
||||
}
|
||||
@@ -129,3 +113,8 @@ errorret_t saveStreamSeekDolphin(savestreamdolphin_t *p, const size_t pos) {
|
||||
p->position = pos;
|
||||
errorOk();
|
||||
}
|
||||
|
||||
errorret_t saveStreamTellDolphin(savestreamdolphin_t *p, size_t *out) {
|
||||
*out = p->position;
|
||||
errorOk();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user