diff options
| author | Archez <Archez@users.noreply.github.com> | 2024-08-18 18:04:25 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-08-18 18:04:25 -0400 |
| commit | 542feb038e5808196f13a26278fb0926cde7da61 (patch) | |
| tree | 5acd8161cf55b6df4b66c5a50909c4de3757950d | |
| parent | b0ca99f18cbfd9c724020b23d7912443472f2ca9 (diff) | |
Implement save backups and better invalid json detection (#749)
| -rw-r--r-- | mm/2s2h/SaveManager/SaveManager.cpp | 92 | ||||
| -rw-r--r-- | mm/src/code/z_sram_NES.c | 4 |
2 files changed, 68 insertions, 28 deletions
diff --git a/mm/2s2h/SaveManager/SaveManager.cpp b/mm/2s2h/SaveManager/SaveManager.cpp index d816972f6..a841ca439 100644 --- a/mm/2s2h/SaveManager/SaveManager.cpp +++ b/mm/2s2h/SaveManager/SaveManager.cpp @@ -12,10 +12,12 @@ extern "C" { #include "src/overlays/gamestates/ovl_file_choose/z_file_select.h" extern FileSelectState* gFileSelectState; + +u16 Sram_CalcChecksum(void* data, size_t count); } // This entire thing is temporary until we have a more robust save system that -// supports backwards compatability, migrations, threaded saving, save sections, etc. +// supports backwards compatibility, migrations, threaded saving, save sections, etc. typedef enum FlashSlotFile { /* -1 */ FLASH_SLOT_FILE_UNAVAILABLE = -1, /* 0 */ FLASH_SLOT_FILE_1_NEW_CYCLE, @@ -66,20 +68,20 @@ const std::unordered_map<uint32_t, std::function<void(nlohmann::json&)>> migrati }; int SaveManager_MigrateSave(nlohmann::json& j) { - int version = j.value("version", 0); + try { + int version = j.value("version", 0); - if (version > CURRENT_SAVE_VERSION) { - SPDLOG_ERROR("Save version is greater than current version"); - return -1; - } + if (version > (int)CURRENT_SAVE_VERSION) { + SPDLOG_ERROR("Save version is greater than current version"); + return -1; + } - if (version >= 4 && !j.contains("newCycleSave") && !j.contains("owlSave")) { - SPDLOG_ERROR("Save file is missing newCycleSave and owlSave"); - return -1; - } + if (version >= 4 && !j.contains("newCycleSave") && !j.contains("owlSave")) { + SPDLOG_ERROR("Save file is missing newCycleSave and owlSave"); + return -1; + } - try { - while (version < CURRENT_SAVE_VERSION) { + while (version < (int)CURRENT_SAVE_VERSION) { if (migrations.contains(version)) { auto migration = migrations.at(version); if (version < 4) { @@ -98,6 +100,9 @@ int SaveManager_MigrateSave(nlohmann::json& j) { version = j["version"] = version + 1; } return 0; + } catch (std::exception& e) { + SPDLOG_ERROR("Failed to migrate save file: {}", e.what()); + return -1; } catch (...) { SPDLOG_ERROR("Failed to migrate save file"); return -1; @@ -156,6 +161,7 @@ void SaveManager_MoveInvalidSaveFile(std::filesystem::path fileName, std::string std::filesystem::rename(filePath, backupFilePath); } + SPDLOG_INFO("{}", message.c_str()); auto gui = Ship::Context::GetInstance()->GetWindow()->GetGui(); gui->GetGameOverlay()->TextDrawNotification(30.0f, true, message.c_str()); } catch (...) { SPDLOG_ERROR("Failed to move invalid save file"); } @@ -235,7 +241,7 @@ bool SaveManager_HandleFileDropped(std::string filePath) { nlohmann::json j; try { fileStream >> j; - } catch (nlohmann::json::parse_error& e) { return false; } + } catch (nlohmann::json::exception& e) { return false; } if (!j.contains("type") || j["type"] != "2S2H_SAVE") { return false; @@ -292,6 +298,14 @@ extern "C" void SaveManager_SysFlashrom_WriteData(u8* saveBuffer, u32 pageNum, u return; } + // A new cycle save with the "special" page count means that both the regular slot and the backup slot should be + // saved together. We replicate that here by running the save again on the matching backup slot + if ((flashSlotFile == FLASH_SLOT_FILE_1_NEW_CYCLE || flashSlotFile == FLASH_SLOT_FILE_2_NEW_CYCLE) && + pageCount == (u32)gFlashSpecialSaveNumPages[flashSlotFile]) { + SaveManager_SysFlashrom_WriteData(saveBuffer, gFlashSaveStartPages[flashSlotFile + 1], + gFlashSaveNumPages[flashSlotFile + 1]); + } + switch (flashSlotFile) { case FLASH_SLOT_FILE_1_NEW_CYCLE_BACKUP: case FLASH_SLOT_FILE_2_NEW_CYCLE_BACKUP: @@ -402,10 +416,17 @@ extern "C" s32 SaveManager_SysFlashrom_ReadData(void* saveBuffer, u32 pageNum, u return result; } - SaveOptions saveOptions = j; + try { + SaveOptions saveOptions = j; - memcpy(saveBuffer, &saveOptions, sizeof(SaveOptions)); - return 0; + memcpy(saveBuffer, &saveOptions, sizeof(SaveOptions)); + return 0; + } catch (nlohmann::json::exception& je) { + SPDLOG_ERROR("Failed to parse global settings json: {}", je.what()); + SaveManager_MoveInvalidSaveFile( + fileName, "Failed to parse global settings json, the original file has been backed up."); + return -1; + } } bool isOwlSave = @@ -434,18 +455,41 @@ extern "C" s32 SaveManager_SysFlashrom_ReadData(void* saveBuffer, u32 pageNum, u return -1; } - SaveContext saveContext = j["owlSave"]; - - memcpy(saveBuffer, &saveContext, offsetof(SaveContext, fileNum)); - return 0; + try { + SaveContext saveContext = j["owlSave"]; + + // Recompute the checksum in case the save was edited externally or a migration changed it + // By doing this we sacrifice "real" checksum verification of the save, + saveContext.save.saveInfo.checksum = 0; + saveContext.save.saveInfo.checksum = Sram_CalcChecksum(&saveContext, offsetof(SaveContext, fileNum)); + + memcpy(saveBuffer, &saveContext, offsetof(SaveContext, fileNum)); + return 0; + } catch (nlohmann::json::exception& je) { + SPDLOG_ERROR("Failed to parse owl save json: {}", je.what()); + SaveManager_MoveInvalidSaveFile(fileName, + "Failed to parse save json, the original file has been backed up."); + return -1; + } } else { if (!j.contains("newCycleSave")) { return -1; } - Save save = j["newCycleSave"]["save"]; - - memcpy(saveBuffer, &save, sizeof(Save)); - return 0; + try { + Save save = j["newCycleSave"]["save"]; + + // Recompute the checksum, see message above + save.saveInfo.checksum = 0; + save.saveInfo.checksum = Sram_CalcChecksum(&save, sizeof(Save)); + + memcpy(saveBuffer, &save, sizeof(Save)); + return 0; + } catch (nlohmann::json::exception& je) { + SPDLOG_ERROR("Failed to parse new cycle save json: {}", je.what()); + SaveManager_MoveInvalidSaveFile(fileName, + "Failed to parse save json, the original file has been backed up."); + return -1; + } } } diff --git a/mm/src/code/z_sram_NES.c b/mm/src/code/z_sram_NES.c index 2174b4e00..77977d9cb 100644 --- a/mm/src/code/z_sram_NES.c +++ b/mm/src/code/z_sram_NES.c @@ -690,10 +690,6 @@ void Sram_IncrementDay(void) { } u16 Sram_CalcChecksum(void* data, size_t count) { - // #region 2S2H [Port] I'm not really sure what this is doing or how to port it, for now always return the same - return 1; - // #endregion - u8* dataPtr = data; u16 chkSum = 0; |
