From 3d5b1b860f2e21963306f00f89b17d995472f2e4 Mon Sep 17 00:00:00 2001 From: Matt Penny Date: Sun, 7 Jan 2024 14:03:31 -0500 Subject: [PATCH] Do not save partial savefile on first boot (fixes #583) With the implementation of save file deletion, I refactored savefileNew() to re-use the common save file deletion code. However, savefileDeleteGame() has the side effect of writing the save back to SRAM. Since the rest of savefileNew() does not write to SRAM, this means that on first boot it was possible to get a partially-written save file if the game was powered off before the first real save (some options had zero/null values). To fix this, I created a helper function to update a save file in memory without writing it back to SRAM. This has the added benefit of not unnecessarily re-ordering the slots in savefileNew(). I chose not to add a savefileSave() to the end of savefileNew() since it is called from savefileLoad(), and saving while loading doesn't seem intuitive. I also don't think it's a good idea to save in the middle of initialization, in case a user is able to cut power at the (im)perfect time. The operation should be atomic. --- src/savefile/savefile.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/savefile/savefile.c b/src/savefile/savefile.c index 52f2e93..0cf081d 100755 --- a/src/savefile/savefile.c +++ b/src/savefile/savefile.c @@ -77,6 +77,12 @@ int savefileSramLoad(void* sramAddr, void* ramAddr, int size) { return 1; } +static void savefileUpdateSlot(int slotIndex, unsigned char testChamber, unsigned char subjectNumber, unsigned char slotOrder) { + gSaveData.saveSlotMetadata[slotIndex].testChamber = testChamber; + gSaveData.saveSlotMetadata[slotIndex].testSubjectNumber = subjectNumber; + gSaveData.saveSlotMetadata[slotIndex].saveSlotOrder = slotOrder; +} + void savefileNew() { zeroMemory(&gSaveData, sizeof(gSaveData)); gSaveData.header.header = SAVEFILE_HEADER; @@ -85,7 +91,7 @@ void savefileNew() { gSaveData.header.flags = 0; for (int i = 0; i < MAX_SAVE_SLOTS; ++i) { - savefileDeleteGame(i); + savefileUpdateSlot(i, NO_TEST_CHAMBER, 0xFF, 0xFF); } controllerSetDefaultSource(); @@ -162,9 +168,7 @@ void savefileDeleteGame(int slotIndex) { } } - gSaveData.saveSlotMetadata[slotIndex].testChamber = NO_TEST_CHAMBER; - gSaveData.saveSlotMetadata[slotIndex].testSubjectNumber = 0xFF; - gSaveData.saveSlotMetadata[slotIndex].saveSlotOrder = 0xFF; + savefileUpdateSlot(slotIndex, NO_TEST_CHAMBER, 0xFF, 0xFF); savefileSave(); } @@ -184,9 +188,7 @@ void savefileSaveGame(Checkpoint checkpoint, u16* screenshot, int testChamberDis } } - gSaveData.saveSlotMetadata[slotIndex].testChamber = testChamberDisplayNumber; - gSaveData.saveSlotMetadata[slotIndex].testSubjectNumber = subjectNumber; - gSaveData.saveSlotMetadata[slotIndex].saveSlotOrder = 0; + savefileUpdateSlot(slotIndex, testChamberDisplayNumber, subjectNumber, 0); savefileSave(); }