Recover from a corrupt or version-mismatched save file instead of crashing

saveLoadSettings()/saveLoadSlot() previously let a read failure (e.g. a
version mismatch from the new schema check) propagate all the way up
through saveUpdate()/engineUpdate() to main(), which just prints the
error and exits - taking down the whole game over one bad file. Both
now catch the failure, log it, and fall back to init defaults instead,
matching the existing "no file yet" convention.
This commit is contained in:
2026-09-08 12:49:20 -05:00
parent 178d78ef72
commit 798db14bb5
+25 -4
View File
@@ -9,6 +9,7 @@
#include "util/memory.h" #include "util/memory.h"
#include "assert/assert.h" #include "assert/assert.h"
#include "rpg/cutscene/cutscenesystem.h" #include "rpg/cutscene/cutscenesystem.h"
#include "console/console.h"
save_t SAVE; save_t SAVE;
@@ -186,10 +187,18 @@ errorret_t saveSaveSettings() {
errorret_t saveLoadSettings() { errorret_t saveLoadSettings() {
assertTrue(SAVE.deviceCurrent != 0xFF, "No current device"); assertTrue(SAVE.deviceCurrent != 0xFF, "No current device");
errorChain(saveDeviceSettingsRead( errorret_t ret = saveDeviceSettingsRead(
&SAVE.devices[SAVE.deviceCurrent], &SAVE.devices[SAVE.deviceCurrent],
&SAVE.settings &SAVE.settings
)); );
if(errorIsNotOk(ret)) {
// Corrupt or incompatible (e.g. wrong/missing schema version) settings
// file - don't take the whole game down over it, just reset to
// defaults and carry on.
errorCatch(errorPrint(ret));
consolePrint("Settings file could not be loaded, resetting to defaults.\n");
saveSettingsInit(&SAVE.settings);
}
SAVE.settingsDirty = false; SAVE.settingsDirty = false;
errorOk(); errorOk();
@@ -222,11 +231,23 @@ errorret_t saveLoadSlot() {
errorOk(); errorOk();
} }
errorChain(saveDeviceSlotRead( errorret_t ret = saveDeviceSlotRead(
&SAVE.devices[SAVE.deviceCurrent], &SAVE.devices[SAVE.deviceCurrent],
&SAVE.slot, &SAVE.slot,
SAVE.slotCurrent SAVE.slotCurrent
)); );
if(errorIsNotOk(ret)) {
// Corrupt or incompatible (e.g. wrong/missing schema version) slot
// file - don't take the whole game down over it, treat it the same as
// an empty/unused slot.
errorCatch(errorPrint(ret));
consolePrint(
"Save slot %u could not be loaded, treating as empty.\n",
(uint32_t)SAVE.slotCurrent
);
saveSlotInit(&SAVE.slot);
}
// Update cache // Update cache
SAVE.caches[SAVE.slotCurrent] = SAVE.slot.cachedData; SAVE.caches[SAVE.slotCurrent] = SAVE.slot.cachedData;