From 07bfba0162bb260f4f1f6cd7fb6f25ea82f3a2ad Mon Sep 17 00:00:00 2001 From: Malkierian Date: Wed, 10 May 2023 14:10:13 -0700 Subject: [PATCH 01/17] Preliminary work on persistent save data json block. Added autosaveRegistry to set section to save with overall autosave triggers. --- soh/soh/SaveManager.cpp | 40 ++++++++++++++++++++++++++++++++-------- soh/soh/SaveManager.h | 8 +++++++- 2 files changed, 39 insertions(+), 9 deletions(-) diff --git a/soh/soh/SaveManager.cpp b/soh/soh/SaveManager.cpp index 466e9a7b3..82364fd08 100644 --- a/soh/soh/SaveManager.cpp +++ b/soh/soh/SaveManager.cpp @@ -50,10 +50,12 @@ SaveManager::SaveManager() { AddLoadFunction("base", 2, LoadBaseVersion2); AddLoadFunction("base", 3, LoadBaseVersion3); AddSaveFunction("base", 3, SaveBase); + RegisterSectionAutoSave("base"); AddLoadFunction("randomizer", 1, LoadRandomizerVersion1); AddLoadFunction("randomizer", 2, LoadRandomizerVersion2); AddSaveFunction("randomizer", 2, SaveRandomizer); + RegisterSectionAutoSave("randomizer"); AddInitFunction(InitFileImpl); @@ -83,6 +85,18 @@ SaveManager::SaveManager() { } } +void SaveManager::RegisterSectionAutoSave(std::string section) { + if (!std::any_of(autosaveRegistry.begin(), autosaveRegistry.end(), section)) { + autosaveRegistry.push_back(section); + } +} + +void SaveManager::UnregisterSectionAutoSave(std::string section) { + if (std::any_of(autosaveRegistry.begin(), autosaveRegistry.end(), section)) { + autosaveRegistry.erase(find(autosaveRegistry.begin(), autosaveRegistry.end(), section)); + } +} + void SaveManager::LoadRandomizerVersion1() { for (int i = 0; i < ARRAY_COUNT(gSaveContext.itemLocations); i++) { SaveManager::Instance->LoadStruct("get" + std::to_string(i), [&]() { @@ -726,17 +740,27 @@ void SaveManager::InitFileDebug() { } // Threaded SaveFile takes copy of gSaveContext for local unmodified storage -void SaveManager::SaveFileThreaded(int fileNum, SaveContext* saveContext) { - nlohmann::json baseBlock; +void SaveManager::SaveFileThreaded(int fileNum, SaveContext* saveContext, const std::string sectionString = "all") { + /*nlohmann::json baseBlock; baseBlock["version"] = 1; - baseBlock["sections"] = nlohmann::json::object(); - for (auto& section : sectionSaveHandlers) { - nlohmann::json& sectionBlock = baseBlock["sections"][section.first]; - sectionBlock["version"] = section.second.first; + baseBlock["sections"] = nlohmann::json::object();*/ + if (sectionString == "all") { + for (auto& sectionHandler : sectionSaveHandlers) { + nlohmann::json& sectionBlock = saveBlock["sections"][sectionHandler.first]; + sectionBlock["version"] = sectionHandler.second.first; + currentJsonContext = §ionBlock["data"]; + sectionHandler.second.second(saveContext); + } + } else if (sectionSaveHandlers.contains(sectionString) && std::any_of(autosaveRegistry.begin(), autosaveRegistry.end(), sectionString)) { + SectionSaveHandler handler = sectionSaveHandlers.find(sectionString)->second; + nlohmann::json& sectionBlock = saveBlock["sections"][sectionString]; + sectionBlock["version"] = handler.first; currentJsonContext = §ionBlock["data"]; - section.second.second(saveContext); + handler.second(saveContext); + } else { + return; } #if defined(__SWITCH__) || defined(__WIIU__) @@ -746,7 +770,7 @@ void SaveManager::SaveFileThreaded(int fileNum, SaveContext* saveContext) { fclose(w); #else std::ofstream output(GetFileName(fileNum)); - output << std::setw(4) << baseBlock << std::endl; + output << std::setw(4) << saveBlock << std::endl; #endif delete saveContext; diff --git a/soh/soh/SaveManager.h b/soh/soh/SaveManager.h index 8b32774e1..e31696fcf 100644 --- a/soh/soh/SaveManager.h +++ b/soh/soh/SaveManager.h @@ -118,13 +118,17 @@ public: static const int MaxFiles = 3; std::array fileMetaInfo; + void RegisterSectionAutoSave(std::string section); + void UnregisterSectionAutoSave(std::string section); + private: std::filesystem::path GetFileName(int fileNum); + nlohmann::json saveBlock; void ConvertFromUnversioned(); void CreateDefaultGlobal(); - void SaveFileThreaded(int fileNum, SaveContext* saveContext); + void SaveFileThreaded(int fileNum, SaveContext* saveContext, const std::string sectionString); void InitMeta(int slotNum); static void InitFileImpl(bool isDebug); @@ -147,6 +151,8 @@ public: using SectionSaveHandler = std::pair; std::map sectionSaveHandlers; + // sets a section to + std::vector autosaveRegistry; std::map postHandlers; From 2ae713464db4c67863ba10ab2133af0f02d16611 Mon Sep 17 00:00:00 2001 From: Malkierian Date: Thu, 11 May 2023 12:02:04 -0700 Subject: [PATCH 02/17] Moved sohStats to separate section, load and save code now in `gameplaystats.cpp`. Still needs new load version for base? --- soh/soh/Enhancements/gameplaystats.cpp | 91 ++++++ soh/soh/SaveManager.cpp | 418 ++++++++++++------------- soh/soh/SaveManager.h | 6 +- 3 files changed, 286 insertions(+), 229 deletions(-) diff --git a/soh/soh/Enhancements/gameplaystats.cpp b/soh/soh/Enhancements/gameplaystats.cpp index 5d60964bd..94029ecc8 100644 --- a/soh/soh/Enhancements/gameplaystats.cpp +++ b/soh/soh/Enhancements/gameplaystats.cpp @@ -2,6 +2,8 @@ extern "C" { #include "gameplaystats.h" } +#include "soh/SaveManager.h" +#include "macros.h" #include "ImGuiImpl.h" #include "../UIWidgets.hpp" @@ -174,6 +176,92 @@ void DisplayTimeHHMMSS(uint32_t timeInTenthsOfSeconds, std::string text, ImVec4 ImGui::PopStyleColor(); } +void LoadStatsVersion1() { + std::string buildVersion; + SaveManager::Instance->LoadData("buildVersion", buildVersion); + strncpy(gSaveContext.sohStats.buildVersion, buildVersion.c_str(), + ARRAY_COUNT(gSaveContext.sohStats.buildVersion) - 1); + gSaveContext.sohStats.buildVersion[ARRAY_COUNT(gSaveContext.sohStats.buildVersion) - 1] = 0; + SaveManager::Instance->LoadData("buildVersionMajor", gSaveContext.sohStats.buildVersionMajor); + SaveManager::Instance->LoadData("buildVersionMinor", gSaveContext.sohStats.buildVersionMinor); + SaveManager::Instance->LoadData("buildVersionPatch", gSaveContext.sohStats.buildVersionPatch); + + SaveManager::Instance->LoadData("heartPieces", gSaveContext.sohStats.heartPieces); + SaveManager::Instance->LoadData("heartContainers", gSaveContext.sohStats.heartContainers); + SaveManager::Instance->LoadArray("dungeonKeys", ARRAY_COUNT(gSaveContext.sohStats.dungeonKeys), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.sohStats.dungeonKeys[i]); + }); + SaveManager::Instance->LoadData("playTimer", gSaveContext.sohStats.playTimer); + SaveManager::Instance->LoadData("pauseTimer", gSaveContext.sohStats.pauseTimer); + SaveManager::Instance->LoadArray( + "itemTimestamps", ARRAY_COUNT(gSaveContext.sohStats.itemTimestamp), + [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.sohStats.itemTimestamp[i]); }); + SaveManager::Instance->LoadArray( + "sceneTimestamps", ARRAY_COUNT(gSaveContext.sohStats.sceneTimestamps), [](size_t i) { + SaveManager::Instance->LoadStruct("", [&i]() { + SaveManager::Instance->LoadData("scene", gSaveContext.sohStats.sceneTimestamps[i].scene); + SaveManager::Instance->LoadData("room", gSaveContext.sohStats.sceneTimestamps[i].room); + SaveManager::Instance->LoadData("sceneTime", gSaveContext.sohStats.sceneTimestamps[i].sceneTime); + SaveManager::Instance->LoadData("roomTime", gSaveContext.sohStats.sceneTimestamps[i].roomTime); + SaveManager::Instance->LoadData("isRoom", gSaveContext.sohStats.sceneTimestamps[i].isRoom); + }); + }); + SaveManager::Instance->LoadData("tsIdx", gSaveContext.sohStats.tsIdx); + SaveManager::Instance->LoadArray("counts", ARRAY_COUNT(gSaveContext.sohStats.count), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.sohStats.count[i]); + }); + SaveManager::Instance->LoadArray( + "scenesDiscovered", ARRAY_COUNT(gSaveContext.sohStats.scenesDiscovered), + [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.sohStats.scenesDiscovered[i]); }); + SaveManager::Instance->LoadArray( + "entrancesDiscovered", ARRAY_COUNT(gSaveContext.sohStats.entrancesDiscovered), + [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.sohStats.entrancesDiscovered[i]); }); + SaveManager::Instance->LoadArray( + "locationsSkipped", ARRAY_COUNT(gSaveContext.sohStats.locationsSkipped), + [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.sohStats.locationsSkipped[i]); }); +} + +void SaveStatsVersion1(SaveContext* saveContext) { + SaveManager::Instance->SaveData("buildVersion", saveContext->sohStats.buildVersion); + SaveManager::Instance->SaveData("buildVersionMajor", saveContext->sohStats.buildVersionMajor); + SaveManager::Instance->SaveData("buildVersionMinor", saveContext->sohStats.buildVersionMinor); + SaveManager::Instance->SaveData("buildVersionPatch", saveContext->sohStats.buildVersionPatch); + + SaveManager::Instance->SaveData("heartPieces", saveContext->sohStats.heartPieces); + SaveManager::Instance->SaveData("heartContainers", saveContext->sohStats.heartContainers); + SaveManager::Instance->SaveArray("dungeonKeys", ARRAY_COUNT(saveContext->sohStats.dungeonKeys), [&](size_t i) { + SaveManager::Instance->SaveData("", saveContext->sohStats.dungeonKeys[i]); + }); + SaveManager::Instance->SaveData("playTimer", saveContext->sohStats.playTimer); + SaveManager::Instance->SaveData("pauseTimer", saveContext->sohStats.pauseTimer); + SaveManager::Instance->SaveArray( + "itemTimestamps", ARRAY_COUNT(saveContext->sohStats.itemTimestamp), + [&](size_t i) { SaveManager::Instance->SaveData("", saveContext->sohStats.itemTimestamp[i]); }); + SaveManager::Instance->SaveArray( + "sceneTimestamps", ARRAY_COUNT(saveContext->sohStats.sceneTimestamps), [&](size_t i) { + SaveManager::Instance->SaveStruct("", [&]() { + SaveManager::Instance->SaveData("scene", saveContext->sohStats.sceneTimestamps[i].scene); + SaveManager::Instance->SaveData("room", saveContext->sohStats.sceneTimestamps[i].room); + SaveManager::Instance->SaveData("sceneTime", saveContext->sohStats.sceneTimestamps[i].sceneTime); + SaveManager::Instance->SaveData("roomTime", saveContext->sohStats.sceneTimestamps[i].roomTime); + SaveManager::Instance->SaveData("isRoom", saveContext->sohStats.sceneTimestamps[i].isRoom); + }); + }); + SaveManager::Instance->SaveData("tsIdx", saveContext->sohStats.tsIdx); + SaveManager::Instance->SaveArray("counts", ARRAY_COUNT(saveContext->sohStats.count), [&](size_t i) { + SaveManager::Instance->SaveData("", saveContext->sohStats.count[i]); + }); + SaveManager::Instance->SaveArray( + "scenesDiscovered", ARRAY_COUNT(saveContext->sohStats.scenesDiscovered), + [&](size_t i) { SaveManager::Instance->SaveData("", saveContext->sohStats.scenesDiscovered[i]); }); + SaveManager::Instance->SaveArray( + "entrancesDiscovered", ARRAY_COUNT(saveContext->sohStats.entrancesDiscovered), + [&](size_t i) { SaveManager::Instance->SaveData("", saveContext->sohStats.entrancesDiscovered[i]); }); + SaveManager::Instance->SaveArray( + "locationsSkipped", ARRAY_COUNT(saveContext->sohStats.locationsSkipped), + [&](size_t i) { SaveManager::Instance->SaveData("", saveContext->sohStats.locationsSkipped[i]); }); +} + void SortChronological(TimestampInfo* arr, size_t len) { TimestampInfo temp; for (int i = 0; i < len; i++) { @@ -673,4 +761,7 @@ extern "C" void InitStatTracker() { LUS::AddWindow("Enhancements", "Gameplay Stats", DrawStatsTracker, CVarGetInteger("gGameplayStatsEnabled", 0)); SetupDisplayNames(); SetupDisplayColors(); + SaveManager::Instance->AddLoadFunction("sohStats", 1, LoadStatsVersion1); + SaveManager::Instance->AddSaveFunction("sohStats", 1, SaveStatsVersion1); + SaveManager::Instance->RegisterAutosaveSection("sohStats"); } \ No newline at end of file diff --git a/soh/soh/SaveManager.cpp b/soh/soh/SaveManager.cpp index 6d928bbbd..d60f81d55 100644 --- a/soh/soh/SaveManager.cpp +++ b/soh/soh/SaveManager.cpp @@ -19,7 +19,7 @@ extern "C" SaveContext gSaveContext; void SaveManager::WriteSaveFile(const std::filesystem::path& savePath, const uintptr_t addr, void* dramAddr, - const size_t size) { + const size_t size) { std::ofstream saveFile = std::ofstream(savePath, std::fstream::in | std::fstream::out | std::fstream::binary); saveFile.seekp(addr); saveFile.write((char*)dramAddr, size); @@ -50,12 +50,12 @@ SaveManager::SaveManager() { AddLoadFunction("base", 2, LoadBaseVersion2); AddLoadFunction("base", 3, LoadBaseVersion3); AddSaveFunction("base", 3, SaveBase); - RegisterSectionAutoSave("base"); + RegisterAutosaveSection("base"); AddLoadFunction("randomizer", 1, LoadRandomizerVersion1); AddLoadFunction("randomizer", 2, LoadRandomizerVersion2); AddSaveFunction("randomizer", 2, SaveRandomizer); - RegisterSectionAutoSave("randomizer"); + RegisterAutosaveSection("randomizer"); AddInitFunction(InitFileImpl); @@ -85,15 +85,16 @@ SaveManager::SaveManager() { } } -void SaveManager::RegisterSectionAutoSave(std::string section) { - if (!std::any_of(autosaveRegistry.begin(), autosaveRegistry.end(), section)) { +void SaveManager::RegisterAutosaveSection(std::string section) { + if (std::find(autosaveRegistry.begin(), autosaveRegistry.end(), section) == autosaveRegistry.end()) { autosaveRegistry.push_back(section); } } -void SaveManager::UnregisterSectionAutoSave(std::string section) { - if (std::any_of(autosaveRegistry.begin(), autosaveRegistry.end(), section)) { - autosaveRegistry.erase(find(autosaveRegistry.begin(), autosaveRegistry.end(), section)); +void SaveManager::UnregisterAutosaveSection(std::string section) { + auto find = std::find(autosaveRegistry.begin(), autosaveRegistry.end(), section); + if (find != autosaveRegistry.end()) { + autosaveRegistry.erase(find); } } @@ -121,7 +122,8 @@ void SaveManager::LoadRandomizerVersion1() { for (int i = 0; i < ARRAY_COUNT(gSaveContext.hintLocations); i++) { SaveManager::Instance->LoadData("hc" + std::to_string(i), gSaveContext.hintLocations[i].check); for (int j = 0; j < ARRAY_COUNT(gSaveContext.hintLocations[i].hintText); j++) { - SaveManager::Instance->LoadData("ht" + std::to_string(i) + "-" + std::to_string(j), gSaveContext.hintLocations[i].hintText[j]); + SaveManager::Instance->LoadData("ht" + std::to_string(i) + "-" + std::to_string(j), + gSaveContext.hintLocations[i].hintText[j]); } } @@ -185,13 +187,13 @@ void SaveManager::LoadRandomizerVersion2() { SaveManager::Instance->LoadData("destination", gSaveContext.entranceOverrides[i].destination); SaveManager::Instance->LoadData("blueWarp", gSaveContext.entranceOverrides[i].blueWarp); SaveManager::Instance->LoadData("override", gSaveContext.entranceOverrides[i].override); - SaveManager::Instance->LoadData("overrideDestination", gSaveContext.entranceOverrides[i].overrideDestination); + SaveManager::Instance->LoadData("overrideDestination", + gSaveContext.entranceOverrides[i].overrideDestination); }); }); - SaveManager::Instance->LoadArray("seed", ARRAY_COUNT(gSaveContext.seedIcons), [&](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.seedIcons[i]); - }); + SaveManager::Instance->LoadArray("seed", ARRAY_COUNT(gSaveContext.seedIcons), + [&](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.seedIcons[i]); }); SaveManager::Instance->LoadArray("randoSettings", RSK_MAX, [&](size_t i) { gSaveContext.randoSettings[i].key = RandomizerSettingKey(i); @@ -277,7 +279,8 @@ void SaveManager::LoadRandomizerVersion2() { void SaveManager::SaveRandomizer(SaveContext* saveContext) { - if(!saveContext->n64ddFlag) return; + if (!saveContext->n64ddFlag) + return; SaveManager::Instance->SaveArray("itemLocations", RC_MAX, [&](size_t i) { SaveManager::Instance->SaveStruct("", [&]() { @@ -293,13 +296,13 @@ void SaveManager::SaveRandomizer(SaveContext* saveContext) { SaveManager::Instance->SaveData("destination", saveContext->entranceOverrides[i].destination); SaveManager::Instance->SaveData("blueWarp", saveContext->entranceOverrides[i].blueWarp); SaveManager::Instance->SaveData("override", saveContext->entranceOverrides[i].override); - SaveManager::Instance->SaveData("overrideDestination", saveContext->entranceOverrides[i].overrideDestination); + SaveManager::Instance->SaveData("overrideDestination", + saveContext->entranceOverrides[i].overrideDestination); }); }); - SaveManager::Instance->SaveArray("seed", ARRAY_COUNT(saveContext->seedIcons), [&](size_t i) { - SaveManager::Instance->SaveData("", saveContext->seedIcons[i]); - }); + SaveManager::Instance->SaveArray("seed", ARRAY_COUNT(saveContext->seedIcons), + [&](size_t i) { SaveManager::Instance->SaveData("", saveContext->seedIcons[i]); }); SaveManager::Instance->SaveArray("randoSettings", RSK_MAX, [&](size_t i) { SaveManager::Instance->SaveData("", saveContext->randoSettings[i].value); @@ -332,7 +335,7 @@ void SaveManager::SaveRandomizer(SaveContext* saveContext) { std::shared_ptr randomizer = OTRGlobals::Instance->gRandomizer; std::vector> merchantPrices; - for (const auto & [ check, price ] : randomizer->merchantPrices) { + for (const auto& [check, price] : randomizer->merchantPrices) { merchantPrices.push_back(std::make_pair(check, price)); } @@ -350,9 +353,8 @@ void SaveManager::SaveRandomizer(SaveContext* saveContext) { for (const auto scene : randomizer->masterQuestDungeons) { masterQuestDungeons.push_back(scene); } - SaveManager::Instance->SaveArray("masterQuestDungeons", masterQuestDungeons.size(), [&](size_t i) { - SaveManager::Instance->SaveData("", masterQuestDungeons[i]); - }); + SaveManager::Instance->SaveArray("masterQuestDungeons", masterQuestDungeons.size(), + [&](size_t i) { SaveManager::Instance->SaveData("", masterQuestDungeons[i]); }); } void SaveManager::Init() { @@ -361,7 +363,8 @@ void SaveManager::Init() { auto sOldSavePath = LUS::Context::GetPathRelativeToAppDirectory("oot_save.sav"); auto sOldBackupSavePath = LUS::Context::GetPathRelativeToAppDirectory("oot_save.bak"); LUS::RegisterHook([this]() { ThreadPoolWait(); }); - GameInteractor::Instance->RegisterGameHook([this](uint32_t fileNum) { ThreadPoolWait(); }); + GameInteractor::Instance->RegisterGameHook( + [this](uint32_t fileNum) { ThreadPoolWait(); }); // If the save directory does not exist, create it if (!std::filesystem::exists(sSavePath)) { @@ -409,7 +412,6 @@ void SaveManager::Init() { if (std::filesystem::exists(GetFileName(fileNum))) { LoadFile(fileNum); } - } } @@ -429,16 +431,20 @@ void SaveManager::InitMeta(int fileNum) { } fileMetaInfo[fileNum].randoSave = gSaveContext.n64ddFlag; - // If the file is marked as a Master Quest file or if we're randomized and have at least one master quest dungeon, we need the mq otr. - fileMetaInfo[fileNum].requiresMasterQuest = gSaveContext.isMasterQuest > 0 || (gSaveContext.n64ddFlag && gSaveContext.mqDungeonCount > 0); - // If the file is not marked as Master Quest, it could still theoretically be a rando save with all 12 MQ dungeons, in which case - // we don't actually require a vanilla OTR. - fileMetaInfo[fileNum].requiresOriginal = !gSaveContext.isMasterQuest && (!gSaveContext.n64ddFlag || gSaveContext.mqDungeonCount < 12); + // If the file is marked as a Master Quest file or if we're randomized and have at least one master quest dungeon, + // we need the mq otr. + fileMetaInfo[fileNum].requiresMasterQuest = + gSaveContext.isMasterQuest > 0 || (gSaveContext.n64ddFlag && gSaveContext.mqDungeonCount > 0); + // If the file is not marked as Master Quest, it could still theoretically be a rando save with all 12 MQ dungeons, + // in which case we don't actually require a vanilla OTR. + fileMetaInfo[fileNum].requiresOriginal = + !gSaveContext.isMasterQuest && (!gSaveContext.n64ddFlag || gSaveContext.mqDungeonCount < 12); fileMetaInfo[fileNum].buildVersionMajor = gSaveContext.sohStats.buildVersionMajor; fileMetaInfo[fileNum].buildVersionMinor = gSaveContext.sohStats.buildVersionMinor; fileMetaInfo[fileNum].buildVersionPatch = gSaveContext.sohStats.buildVersionPatch; - strncpy(fileMetaInfo[fileNum].buildVersion, gSaveContext.sohStats.buildVersion, sizeof(fileMetaInfo[fileNum].buildVersion) - 1); + strncpy(fileMetaInfo[fileNum].buildVersion, gSaveContext.sohStats.buildVersion, + sizeof(fileMetaInfo[fileNum].buildVersion) - 1); fileMetaInfo[fileNum].buildVersion[sizeof(fileMetaInfo[fileNum].buildVersion) - 1] = 0; } @@ -620,13 +626,14 @@ void SaveManager::InitFileNormal() { gSaveContext.pendingSale = ITEM_NONE; gSaveContext.pendingSaleMod = MOD_NONE; - strncpy(gSaveContext.sohStats.buildVersion, (const char*) gBuildVersion, sizeof(gSaveContext.sohStats.buildVersion) - 1); + strncpy(gSaveContext.sohStats.buildVersion, (const char*)gBuildVersion, + sizeof(gSaveContext.sohStats.buildVersion) - 1); gSaveContext.sohStats.buildVersion[sizeof(gSaveContext.sohStats.buildVersion) - 1] = 0; gSaveContext.sohStats.buildVersionMajor = gBuildVersionMajor; gSaveContext.sohStats.buildVersionMinor = gBuildVersionMinor; gSaveContext.sohStats.buildVersionPatch = gBuildVersionPatch; - //RANDOTODO (ADD ITEMLOCATIONS TO GSAVECONTEXT) + // RANDOTODO (ADD ITEMLOCATIONS TO GSAVECONTEXT) } void SaveManager::InitFileDebug() { @@ -671,11 +678,13 @@ void SaveManager::InitFileDebug() { gSaveContext.savedSceneNum = 0x51; // Equipment - static std::array sButtonItems = { ITEM_SWORD_MASTER, ITEM_BOW, ITEM_BOMB, ITEM_OCARINA_FAIRY, ITEM_NONE, ITEM_NONE, ITEM_NONE, ITEM_NONE }; + static std::array sButtonItems = { ITEM_SWORD_MASTER, ITEM_BOW, ITEM_BOMB, ITEM_OCARINA_FAIRY, + ITEM_NONE, ITEM_NONE, ITEM_NONE, ITEM_NONE }; for (int button = 0; button < ARRAY_COUNT(gSaveContext.equips.buttonItems); button++) { gSaveContext.equips.buttonItems[button] = sButtonItems[button]; } - static std::array sCButtonSlots = { SLOT_BOW, SLOT_BOMB, SLOT_OCARINA, SLOT_NONE, SLOT_NONE, SLOT_NONE, SLOT_NONE }; + static std::array sCButtonSlots = { SLOT_BOW, SLOT_BOMB, SLOT_OCARINA, SLOT_NONE, + SLOT_NONE, SLOT_NONE, SLOT_NONE }; for (int button = 0; button < ARRAY_COUNT(gSaveContext.equips.cButtonSlots); button++) { gSaveContext.equips.cButtonSlots[button] = sCButtonSlots[button]; } @@ -740,7 +749,7 @@ void SaveManager::InitFileDebug() { } // Threaded SaveFile takes copy of gSaveContext for local unmodified storage -void SaveManager::SaveFileThreaded(int fileNum, SaveContext* saveContext, const std::string sectionString = "all") { +void SaveManager::SaveFileThreaded(int fileNum, SaveContext* saveContext, const std::string sectionString) { /*nlohmann::json baseBlock; baseBlock["version"] = 1; @@ -753,7 +762,7 @@ void SaveManager::SaveFileThreaded(int fileNum, SaveContext* saveContext, const currentJsonContext = §ionBlock["data"]; sectionHandler.second.second(saveContext); } - } else if (sectionSaveHandlers.contains(sectionString) && std::any_of(autosaveRegistry.begin(), autosaveRegistry.end(), sectionString)) { + } else if (sectionSaveHandlers.contains(sectionString) && std::find(autosaveRegistry.begin(), autosaveRegistry.end(), sectionString) != autosaveRegistry.end()) { SectionSaveHandler handler = sectionSaveHandlers.find(sectionString)->second; nlohmann::json& sectionBlock = saveBlock["sections"][sectionString]; sectionBlock["version"] = handler.first; @@ -785,7 +794,7 @@ void SaveManager::SaveFile(int fileNum) { // Can't think of any time the promise would be needed, so use push_task instead of submit auto saveContext = new SaveContext; memcpy(saveContext, &gSaveContext, sizeof(gSaveContext)); - smThreadPool->push_task_back(&SaveManager::SaveFileThreaded, this, fileNum, saveContext); + smThreadPool->push_task_back(&SaveManager::SaveFileThreaded, this, fileNum, saveContext, "all"); } void SaveManager::SaveGlobal() { @@ -822,14 +831,15 @@ void SaveManager::LoadFile(int fileNum) { if (!sectionLoadHandlers.contains(sectionName)) { // Unloadable sections aren't necessarily errors, they are probably mods that were unloaded // TODO report in a more noticeable manner - SPDLOG_WARN("Save " + GetFileName(fileNum).string() + " contains unloadable section " + sectionName); + SPDLOG_WARN("Save " + GetFileName(fileNum).string() + " contains unloadable section " + + sectionName); continue; } SectionLoadHandler& handler = sectionLoadHandlers[sectionName]; if (!handler.contains(sectionVersion)) { - // A section that has a loader without a handler for the specific version means that the user has a mod - // at an earlier version than the save has. In this case, the user probably wants to load the save. - // Report the error so that the user can rectify the error. + // A section that has a loader without a handler for the specific version means that the user has a + // mod at an earlier version than the save has. In this case, the user probably wants to load the + // save. Report the error so that the user can rectify the error. // TODO report in a more noticeable manner SPDLOG_ERROR("Save " + GetFileName(fileNum).string() + " contains section " + sectionName + " with an unloadable version " + std::to_string(sectionVersion)); @@ -857,10 +867,9 @@ void SaveManager::ThreadPoolWait() { bool SaveManager::SaveFile_Exist(int fileNum) { try { bool exists = std::filesystem::exists(GetFileName(fileNum)); - SPDLOG_INFO("File[{}] - {}", fileNum, exists ? "exists" : "does not exist" ); + SPDLOG_INFO("File[{}] - {}", fileNum, exists ? "exists" : "does not exist"); return exists; - } - catch(std::filesystem::filesystem_error const& ex) { + } catch (std::filesystem::filesystem_error const& ex) { SPDLOG_ERROR("Filesystem error"); return false; } @@ -876,7 +885,8 @@ void SaveManager::AddLoadFunction(const std::string& name, int version, LoadFunc } if (sectionLoadHandlers[name].contains(version)) { - SPDLOG_ERROR("Adding load function for section and version that already has one: " + name + ", " + std::to_string(version)); + SPDLOG_ERROR("Adding load function for section and version that already has one: " + name + ", " + + std::to_string(version)); assert(false); return; } @@ -921,9 +931,8 @@ void SaveManager::LoadBaseVersion1() { SaveManager::Instance->LoadData("totalDays", gSaveContext.totalDays); SaveManager::Instance->LoadData("bgsDayCount", gSaveContext.bgsDayCount); SaveManager::Instance->LoadData("deaths", gSaveContext.deaths); - SaveManager::Instance->LoadArray("playerName", ARRAY_COUNT(gSaveContext.playerName), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.playerName[i]); - }); + SaveManager::Instance->LoadArray("playerName", ARRAY_COUNT(gSaveContext.playerName), + [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.playerName[i]); }); SaveManager::Instance->LoadData("n64ddFlag", gSaveContext.n64ddFlag); SaveManager::Instance->LoadData("healthCapacity", gSaveContext.healthCapacity); SaveManager::Instance->LoadData("health", gSaveContext.health); @@ -938,25 +947,29 @@ void SaveManager::LoadBaseVersion1() { SaveManager::Instance->LoadData("bgsFlag", gSaveContext.bgsFlag); SaveManager::Instance->LoadData("ocarinaGameRoundNum", gSaveContext.ocarinaGameRoundNum); SaveManager::Instance->LoadStruct("childEquips", []() { - SaveManager::Instance->LoadArray("buttonItems", ARRAY_COUNT(gSaveContext.childEquips.buttonItems), [](size_t i) { + SaveManager::Instance->LoadArray( + "buttonItems", ARRAY_COUNT(gSaveContext.childEquips.buttonItems), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.childEquips.buttonItems[i], static_cast(ITEM_NONE)); - }); - SaveManager::Instance->LoadArray("cButtonSlots", ARRAY_COUNT(gSaveContext.childEquips.cButtonSlots), [](size_t i) { + }); + SaveManager::Instance->LoadArray( + "cButtonSlots", ARRAY_COUNT(gSaveContext.childEquips.cButtonSlots), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.childEquips.cButtonSlots[i], static_cast(SLOT_NONE)); - }); + }); SaveManager::Instance->LoadData("equipment", gSaveContext.childEquips.equipment); }); SaveManager::Instance->LoadStruct("adultEquips", []() { - SaveManager::Instance->LoadArray("buttonItems", ARRAY_COUNT(gSaveContext.adultEquips.buttonItems), [](size_t i) { + SaveManager::Instance->LoadArray( + "buttonItems", ARRAY_COUNT(gSaveContext.adultEquips.buttonItems), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.adultEquips.buttonItems[i], static_cast(ITEM_NONE)); - }); - SaveManager::Instance->LoadArray("cButtonSlots", ARRAY_COUNT(gSaveContext.adultEquips.cButtonSlots), [](size_t i) { + }); + SaveManager::Instance->LoadArray( + "cButtonSlots", ARRAY_COUNT(gSaveContext.adultEquips.cButtonSlots), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.adultEquips.cButtonSlots[i], static_cast(SLOT_NONE)); - }); + }); SaveManager::Instance->LoadData("equipment", gSaveContext.adultEquips.equipment); }); SaveManager::Instance->LoadData("unk_54", gSaveContext.unk_54); @@ -980,9 +993,9 @@ void SaveManager::LoadBaseVersion1() { SaveManager::Instance->LoadData("equipment", gSaveContext.inventory.equipment); SaveManager::Instance->LoadData("upgrades", gSaveContext.inventory.upgrades); SaveManager::Instance->LoadData("questItems", gSaveContext.inventory.questItems); - SaveManager::Instance->LoadArray("dungeonItems", ARRAY_COUNT(gSaveContext.inventory.dungeonItems), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.inventory.dungeonItems[i]); - }); + SaveManager::Instance->LoadArray( + "dungeonItems", ARRAY_COUNT(gSaveContext.inventory.dungeonItems), + [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.inventory.dungeonItems[i]); }); SaveManager::Instance->LoadArray("dungeonKeys", ARRAY_COUNT(gSaveContext.inventory.dungeonKeys), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.inventory.dungeonKeys[i]); }); @@ -1014,21 +1027,17 @@ void SaveManager::LoadBaseVersion1() { SaveManager::Instance->LoadData("tempSwchFlags", gSaveContext.fw.tempSwchFlags); SaveManager::Instance->LoadData("tempCollectFlags", gSaveContext.fw.tempCollectFlags); }); - SaveManager::Instance->LoadArray("gsFlags", ARRAY_COUNT(gSaveContext.gsFlags), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.gsFlags[i]); - }); - SaveManager::Instance->LoadArray("highScores", ARRAY_COUNT(gSaveContext.highScores), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.highScores[i]); - }); + SaveManager::Instance->LoadArray("gsFlags", ARRAY_COUNT(gSaveContext.gsFlags), + [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.gsFlags[i]); }); + SaveManager::Instance->LoadArray("highScores", ARRAY_COUNT(gSaveContext.highScores), + [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.highScores[i]); }); SaveManager::Instance->LoadArray("eventChkInf", ARRAY_COUNT(gSaveContext.eventChkInf), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.eventChkInf[i]); }); - SaveManager::Instance->LoadArray("itemGetInf", ARRAY_COUNT(gSaveContext.itemGetInf), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.itemGetInf[i]); - }); - SaveManager::Instance->LoadArray("infTable", ARRAY_COUNT(gSaveContext.infTable), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.infTable[i]); - }); + SaveManager::Instance->LoadArray("itemGetInf", ARRAY_COUNT(gSaveContext.itemGetInf), + [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.itemGetInf[i]); }); + SaveManager::Instance->LoadArray("infTable", ARRAY_COUNT(gSaveContext.infTable), + [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.infTable[i]); }); SaveManager::Instance->LoadData("worldMapAreaData", gSaveContext.worldMapAreaData); SaveManager::Instance->LoadData("scarecrowCustomSongSet", gSaveContext.scarecrowLongSongSet); SaveManager::Instance->LoadArray("scarecrowCustomSong", sizeof(gSaveContext.scarecrowLongSong), [](size_t i) { @@ -1062,9 +1071,8 @@ void SaveManager::LoadBaseVersion2() { SaveManager::Instance->LoadData("totalDays", gSaveContext.totalDays); SaveManager::Instance->LoadData("bgsDayCount", gSaveContext.bgsDayCount); SaveManager::Instance->LoadData("deaths", gSaveContext.deaths); - SaveManager::Instance->LoadArray("playerName", ARRAY_COUNT(gSaveContext.playerName), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.playerName[i]); - }); + SaveManager::Instance->LoadArray("playerName", ARRAY_COUNT(gSaveContext.playerName), + [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.playerName[i]); }); SaveManager::Instance->LoadData("n64ddFlag", gSaveContext.n64ddFlag); SaveManager::Instance->LoadData("healthCapacity", gSaveContext.healthCapacity); SaveManager::Instance->LoadData("health", gSaveContext.health); @@ -1079,25 +1087,29 @@ void SaveManager::LoadBaseVersion2() { SaveManager::Instance->LoadData("bgsFlag", gSaveContext.bgsFlag); SaveManager::Instance->LoadData("ocarinaGameRoundNum", gSaveContext.ocarinaGameRoundNum); SaveManager::Instance->LoadStruct("childEquips", []() { - SaveManager::Instance->LoadArray("buttonItems", ARRAY_COUNT(gSaveContext.childEquips.buttonItems), [](size_t i) { + SaveManager::Instance->LoadArray( + "buttonItems", ARRAY_COUNT(gSaveContext.childEquips.buttonItems), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.childEquips.buttonItems[i], static_cast(ITEM_NONE)); - }); - SaveManager::Instance->LoadArray("cButtonSlots", ARRAY_COUNT(gSaveContext.childEquips.cButtonSlots), [](size_t i) { + }); + SaveManager::Instance->LoadArray( + "cButtonSlots", ARRAY_COUNT(gSaveContext.childEquips.cButtonSlots), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.childEquips.cButtonSlots[i], static_cast(SLOT_NONE)); - }); + }); SaveManager::Instance->LoadData("equipment", gSaveContext.childEquips.equipment); }); SaveManager::Instance->LoadStruct("adultEquips", []() { - SaveManager::Instance->LoadArray("buttonItems", ARRAY_COUNT(gSaveContext.adultEquips.buttonItems), [](size_t i) { + SaveManager::Instance->LoadArray( + "buttonItems", ARRAY_COUNT(gSaveContext.adultEquips.buttonItems), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.adultEquips.buttonItems[i], static_cast(ITEM_NONE)); - }); - SaveManager::Instance->LoadArray("cButtonSlots", ARRAY_COUNT(gSaveContext.adultEquips.cButtonSlots), [](size_t i) { + }); + SaveManager::Instance->LoadArray( + "cButtonSlots", ARRAY_COUNT(gSaveContext.adultEquips.cButtonSlots), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.adultEquips.cButtonSlots[i], static_cast(SLOT_NONE)); - }); + }); SaveManager::Instance->LoadData("equipment", gSaveContext.adultEquips.equipment); }); SaveManager::Instance->LoadData("unk_54", gSaveContext.unk_54); @@ -1121,9 +1133,9 @@ void SaveManager::LoadBaseVersion2() { SaveManager::Instance->LoadData("equipment", gSaveContext.inventory.equipment); SaveManager::Instance->LoadData("upgrades", gSaveContext.inventory.upgrades); SaveManager::Instance->LoadData("questItems", gSaveContext.inventory.questItems); - SaveManager::Instance->LoadArray("dungeonItems", ARRAY_COUNT(gSaveContext.inventory.dungeonItems), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.inventory.dungeonItems[i]); - }); + SaveManager::Instance->LoadArray( + "dungeonItems", ARRAY_COUNT(gSaveContext.inventory.dungeonItems), + [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.inventory.dungeonItems[i]); }); SaveManager::Instance->LoadArray("dungeonKeys", ARRAY_COUNT(gSaveContext.inventory.dungeonKeys), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.inventory.dungeonKeys[i]); }); @@ -1144,12 +1156,12 @@ void SaveManager::LoadBaseVersion2() { SaveManager::Instance->LoadArray("counts", ARRAY_COUNT(gSaveContext.sohStats.count), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.sohStats.count[i]); }); - SaveManager::Instance->LoadArray("scenesDiscovered", ARRAY_COUNT(gSaveContext.sohStats.scenesDiscovered), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.sohStats.scenesDiscovered[i]); - }); - SaveManager::Instance->LoadArray("entrancesDiscovered", ARRAY_COUNT(gSaveContext.sohStats.entrancesDiscovered), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.sohStats.entrancesDiscovered[i]); - }); + SaveManager::Instance->LoadArray( + "scenesDiscovered", ARRAY_COUNT(gSaveContext.sohStats.scenesDiscovered), + [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.sohStats.scenesDiscovered[i]); }); + SaveManager::Instance->LoadArray( + "entrancesDiscovered", ARRAY_COUNT(gSaveContext.sohStats.entrancesDiscovered), + [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.sohStats.entrancesDiscovered[i]); }); }); SaveManager::Instance->LoadArray("sceneFlags", ARRAY_COUNT(gSaveContext.sceneFlags), [](size_t i) { SaveManager::Instance->LoadStruct("", [&i]() { @@ -1176,21 +1188,17 @@ void SaveManager::LoadBaseVersion2() { SaveManager::Instance->LoadData("tempSwchFlags", gSaveContext.fw.tempSwchFlags); SaveManager::Instance->LoadData("tempCollectFlags", gSaveContext.fw.tempCollectFlags); }); - SaveManager::Instance->LoadArray("gsFlags", ARRAY_COUNT(gSaveContext.gsFlags), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.gsFlags[i]); - }); - SaveManager::Instance->LoadArray("highScores", ARRAY_COUNT(gSaveContext.highScores), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.highScores[i]); - }); + SaveManager::Instance->LoadArray("gsFlags", ARRAY_COUNT(gSaveContext.gsFlags), + [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.gsFlags[i]); }); + SaveManager::Instance->LoadArray("highScores", ARRAY_COUNT(gSaveContext.highScores), + [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.highScores[i]); }); SaveManager::Instance->LoadArray("eventChkInf", ARRAY_COUNT(gSaveContext.eventChkInf), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.eventChkInf[i]); }); - SaveManager::Instance->LoadArray("itemGetInf", ARRAY_COUNT(gSaveContext.itemGetInf), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.itemGetInf[i]); - }); - SaveManager::Instance->LoadArray("infTable", ARRAY_COUNT(gSaveContext.infTable), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.infTable[i]); - }); + SaveManager::Instance->LoadArray("itemGetInf", ARRAY_COUNT(gSaveContext.itemGetInf), + [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.itemGetInf[i]); }); + SaveManager::Instance->LoadArray("infTable", ARRAY_COUNT(gSaveContext.infTable), + [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.infTable[i]); }); SaveManager::Instance->LoadData("worldMapAreaData", gSaveContext.worldMapAreaData); SaveManager::Instance->LoadData("scarecrowCustomSongSet", gSaveContext.scarecrowLongSongSet); SaveManager::Instance->LoadArray("scarecrowCustomSong", ARRAY_COUNT(gSaveContext.scarecrowLongSong), [](size_t i) { @@ -1244,17 +1252,18 @@ void SaveManager::LoadBaseVersion2() { if (!gSaveContext.scarecrowLongSongSet) { SaveManager::Instance->LoadData("scarecrowLongSongSet", gSaveContext.scarecrowLongSongSet); if (gSaveContext.scarecrowLongSongSet) { - SaveManager::Instance->LoadArray("scarecrowLongSong", ARRAY_COUNT(gSaveContext.scarecrowLongSong), [](size_t i) { - SaveManager::Instance->LoadStruct("", [&i]() { - SaveManager::Instance->LoadData("noteIdx", gSaveContext.scarecrowLongSong[i].noteIdx); - SaveManager::Instance->LoadData("unk_01", gSaveContext.scarecrowLongSong[i].unk_01); - SaveManager::Instance->LoadData("unk_02", gSaveContext.scarecrowLongSong[i].unk_02); - SaveManager::Instance->LoadData("volume", gSaveContext.scarecrowLongSong[i].volume); - SaveManager::Instance->LoadData("vibrato", gSaveContext.scarecrowLongSong[i].vibrato); - SaveManager::Instance->LoadData("tone", gSaveContext.scarecrowLongSong[i].tone); - SaveManager::Instance->LoadData("semitone", gSaveContext.scarecrowLongSong[i].semitone); + SaveManager::Instance->LoadArray( + "scarecrowLongSong", ARRAY_COUNT(gSaveContext.scarecrowLongSong), [](size_t i) { + SaveManager::Instance->LoadStruct("", [&i]() { + SaveManager::Instance->LoadData("noteIdx", gSaveContext.scarecrowLongSong[i].noteIdx); + SaveManager::Instance->LoadData("unk_01", gSaveContext.scarecrowLongSong[i].unk_01); + SaveManager::Instance->LoadData("unk_02", gSaveContext.scarecrowLongSong[i].unk_02); + SaveManager::Instance->LoadData("volume", gSaveContext.scarecrowLongSong[i].volume); + SaveManager::Instance->LoadData("vibrato", gSaveContext.scarecrowLongSong[i].vibrato); + SaveManager::Instance->LoadData("tone", gSaveContext.scarecrowLongSong[i].tone); + SaveManager::Instance->LoadData("semitone", gSaveContext.scarecrowLongSong[i].semitone); + }); }); - }); } } } @@ -1268,9 +1277,8 @@ void SaveManager::LoadBaseVersion3() { SaveManager::Instance->LoadData("totalDays", gSaveContext.totalDays); SaveManager::Instance->LoadData("bgsDayCount", gSaveContext.bgsDayCount); SaveManager::Instance->LoadData("deaths", gSaveContext.deaths); - SaveManager::Instance->LoadArray("playerName", ARRAY_COUNT(gSaveContext.playerName), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.playerName[i]); - }); + SaveManager::Instance->LoadArray("playerName", ARRAY_COUNT(gSaveContext.playerName), + [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.playerName[i]); }); SaveManager::Instance->LoadData("n64ddFlag", gSaveContext.n64ddFlag); SaveManager::Instance->LoadData("healthCapacity", gSaveContext.healthCapacity); SaveManager::Instance->LoadData("health", gSaveContext.health); @@ -1285,25 +1293,29 @@ void SaveManager::LoadBaseVersion3() { SaveManager::Instance->LoadData("bgsFlag", gSaveContext.bgsFlag); SaveManager::Instance->LoadData("ocarinaGameRoundNum", gSaveContext.ocarinaGameRoundNum); SaveManager::Instance->LoadStruct("childEquips", []() { - SaveManager::Instance->LoadArray("buttonItems", ARRAY_COUNT(gSaveContext.childEquips.buttonItems), [](size_t i) { + SaveManager::Instance->LoadArray( + "buttonItems", ARRAY_COUNT(gSaveContext.childEquips.buttonItems), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.childEquips.buttonItems[i], static_cast(ITEM_NONE)); - }); - SaveManager::Instance->LoadArray("cButtonSlots", ARRAY_COUNT(gSaveContext.childEquips.cButtonSlots), [](size_t i) { + }); + SaveManager::Instance->LoadArray( + "cButtonSlots", ARRAY_COUNT(gSaveContext.childEquips.cButtonSlots), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.childEquips.cButtonSlots[i], static_cast(SLOT_NONE)); - }); + }); SaveManager::Instance->LoadData("equipment", gSaveContext.childEquips.equipment); }); SaveManager::Instance->LoadStruct("adultEquips", []() { - SaveManager::Instance->LoadArray("buttonItems", ARRAY_COUNT(gSaveContext.adultEquips.buttonItems), [](size_t i) { + SaveManager::Instance->LoadArray( + "buttonItems", ARRAY_COUNT(gSaveContext.adultEquips.buttonItems), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.adultEquips.buttonItems[i], static_cast(ITEM_NONE)); - }); - SaveManager::Instance->LoadArray("cButtonSlots", ARRAY_COUNT(gSaveContext.adultEquips.cButtonSlots), [](size_t i) { + }); + SaveManager::Instance->LoadArray( + "cButtonSlots", ARRAY_COUNT(gSaveContext.adultEquips.cButtonSlots), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.adultEquips.cButtonSlots[i], static_cast(SLOT_NONE)); - }); + }); SaveManager::Instance->LoadData("equipment", gSaveContext.adultEquips.equipment); }); SaveManager::Instance->LoadData("unk_54", gSaveContext.unk_54); @@ -1327,9 +1339,9 @@ void SaveManager::LoadBaseVersion3() { SaveManager::Instance->LoadData("equipment", gSaveContext.inventory.equipment); SaveManager::Instance->LoadData("upgrades", gSaveContext.inventory.upgrades); SaveManager::Instance->LoadData("questItems", gSaveContext.inventory.questItems); - SaveManager::Instance->LoadArray("dungeonItems", ARRAY_COUNT(gSaveContext.inventory.dungeonItems), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.inventory.dungeonItems[i]); - }); + SaveManager::Instance->LoadArray( + "dungeonItems", ARRAY_COUNT(gSaveContext.inventory.dungeonItems), + [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.inventory.dungeonItems[i]); }); SaveManager::Instance->LoadArray("dungeonKeys", ARRAY_COUNT(gSaveContext.inventory.dungeonKeys), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.inventory.dungeonKeys[i]); }); @@ -1339,7 +1351,8 @@ void SaveManager::LoadBaseVersion3() { SaveManager::Instance->LoadStruct("sohStats", []() { std::string buildVersion; SaveManager::Instance->LoadData("buildVersion", buildVersion); - strncpy(gSaveContext.sohStats.buildVersion, buildVersion.c_str(), ARRAY_COUNT(gSaveContext.sohStats.buildVersion) - 1); + strncpy(gSaveContext.sohStats.buildVersion, buildVersion.c_str(), + ARRAY_COUNT(gSaveContext.sohStats.buildVersion) - 1); gSaveContext.sohStats.buildVersion[ARRAY_COUNT(gSaveContext.sohStats.buildVersion) - 1] = 0; SaveManager::Instance->LoadData("buildVersionMajor", gSaveContext.sohStats.buildVersionMajor); SaveManager::Instance->LoadData("buildVersionMinor", gSaveContext.sohStats.buildVersionMinor); @@ -1352,32 +1365,32 @@ void SaveManager::LoadBaseVersion3() { }); SaveManager::Instance->LoadData("playTimer", gSaveContext.sohStats.playTimer); SaveManager::Instance->LoadData("pauseTimer", gSaveContext.sohStats.pauseTimer); - SaveManager::Instance->LoadArray("itemTimestamps", ARRAY_COUNT(gSaveContext.sohStats.itemTimestamp), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.sohStats.itemTimestamp[i]); - }); - SaveManager::Instance->LoadArray("sceneTimestamps", ARRAY_COUNT(gSaveContext.sohStats.sceneTimestamps), [](size_t i) { - SaveManager::Instance->LoadStruct("", [&i]() { - SaveManager::Instance->LoadData("scene", gSaveContext.sohStats.sceneTimestamps[i].scene); - SaveManager::Instance->LoadData("room", gSaveContext.sohStats.sceneTimestamps[i].room); - SaveManager::Instance->LoadData("sceneTime", gSaveContext.sohStats.sceneTimestamps[i].sceneTime); - SaveManager::Instance->LoadData("roomTime", gSaveContext.sohStats.sceneTimestamps[i].roomTime); - SaveManager::Instance->LoadData("isRoom", gSaveContext.sohStats.sceneTimestamps[i].isRoom); - + SaveManager::Instance->LoadArray( + "itemTimestamps", ARRAY_COUNT(gSaveContext.sohStats.itemTimestamp), + [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.sohStats.itemTimestamp[i]); }); + SaveManager::Instance->LoadArray( + "sceneTimestamps", ARRAY_COUNT(gSaveContext.sohStats.sceneTimestamps), [](size_t i) { + SaveManager::Instance->LoadStruct("", [&i]() { + SaveManager::Instance->LoadData("scene", gSaveContext.sohStats.sceneTimestamps[i].scene); + SaveManager::Instance->LoadData("room", gSaveContext.sohStats.sceneTimestamps[i].room); + SaveManager::Instance->LoadData("sceneTime", gSaveContext.sohStats.sceneTimestamps[i].sceneTime); + SaveManager::Instance->LoadData("roomTime", gSaveContext.sohStats.sceneTimestamps[i].roomTime); + SaveManager::Instance->LoadData("isRoom", gSaveContext.sohStats.sceneTimestamps[i].isRoom); + }); }); - }); SaveManager::Instance->LoadData("tsIdx", gSaveContext.sohStats.tsIdx); SaveManager::Instance->LoadArray("counts", ARRAY_COUNT(gSaveContext.sohStats.count), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.sohStats.count[i]); }); - SaveManager::Instance->LoadArray("scenesDiscovered", ARRAY_COUNT(gSaveContext.sohStats.scenesDiscovered), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.sohStats.scenesDiscovered[i]); - }); - SaveManager::Instance->LoadArray("entrancesDiscovered", ARRAY_COUNT(gSaveContext.sohStats.entrancesDiscovered), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.sohStats.entrancesDiscovered[i]); - }); - SaveManager::Instance->LoadArray("locationsSkipped", ARRAY_COUNT(gSaveContext.sohStats.locationsSkipped), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.sohStats.locationsSkipped[i]); - }); + SaveManager::Instance->LoadArray( + "scenesDiscovered", ARRAY_COUNT(gSaveContext.sohStats.scenesDiscovered), + [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.sohStats.scenesDiscovered[i]); }); + SaveManager::Instance->LoadArray( + "entrancesDiscovered", ARRAY_COUNT(gSaveContext.sohStats.entrancesDiscovered), + [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.sohStats.entrancesDiscovered[i]); }); + SaveManager::Instance->LoadArray( + "locationsSkipped", ARRAY_COUNT(gSaveContext.sohStats.locationsSkipped), + [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.sohStats.locationsSkipped[i]); }); }); SaveManager::Instance->LoadArray("sceneFlags", ARRAY_COUNT(gSaveContext.sceneFlags), [](size_t i) { SaveManager::Instance->LoadStruct("", [&i]() { @@ -1404,21 +1417,17 @@ void SaveManager::LoadBaseVersion3() { SaveManager::Instance->LoadData("tempSwchFlags", gSaveContext.fw.tempSwchFlags); SaveManager::Instance->LoadData("tempCollectFlags", gSaveContext.fw.tempCollectFlags); }); - SaveManager::Instance->LoadArray("gsFlags", ARRAY_COUNT(gSaveContext.gsFlags), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.gsFlags[i]); - }); - SaveManager::Instance->LoadArray("highScores", ARRAY_COUNT(gSaveContext.highScores), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.highScores[i]); - }); + SaveManager::Instance->LoadArray("gsFlags", ARRAY_COUNT(gSaveContext.gsFlags), + [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.gsFlags[i]); }); + SaveManager::Instance->LoadArray("highScores", ARRAY_COUNT(gSaveContext.highScores), + [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.highScores[i]); }); SaveManager::Instance->LoadArray("eventChkInf", ARRAY_COUNT(gSaveContext.eventChkInf), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.eventChkInf[i]); }); - SaveManager::Instance->LoadArray("itemGetInf", ARRAY_COUNT(gSaveContext.itemGetInf), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.itemGetInf[i]); - }); - SaveManager::Instance->LoadArray("infTable", ARRAY_COUNT(gSaveContext.infTable), [](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.infTable[i]); - }); + SaveManager::Instance->LoadArray("itemGetInf", ARRAY_COUNT(gSaveContext.itemGetInf), + [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.itemGetInf[i]); }); + SaveManager::Instance->LoadArray("infTable", ARRAY_COUNT(gSaveContext.infTable), + [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.infTable[i]); }); SaveManager::Instance->LoadData("worldMapAreaData", gSaveContext.worldMapAreaData); SaveManager::Instance->LoadData("scarecrowLongSongSet", gSaveContext.scarecrowLongSongSet); SaveManager::Instance->LoadArray("scarecrowLongSong", ARRAY_COUNT(gSaveContext.scarecrowLongSong), [](size_t i) { @@ -1501,21 +1510,21 @@ void SaveManager::SaveBase(SaveContext* saveContext) { SaveManager::Instance->SaveData("bgsFlag", saveContext->bgsFlag); SaveManager::Instance->SaveData("ocarinaGameRoundNum", saveContext->ocarinaGameRoundNum); SaveManager::Instance->SaveStruct("childEquips", [&]() { - SaveManager::Instance->SaveArray("buttonItems", ARRAY_COUNT(saveContext->childEquips.buttonItems), [&](size_t i) { - SaveManager::Instance->SaveData("", saveContext->childEquips.buttonItems[i]); - }); - SaveManager::Instance->SaveArray("cButtonSlots", ARRAY_COUNT(saveContext->childEquips.cButtonSlots), [&](size_t i) { - SaveManager::Instance->SaveData("", saveContext->childEquips.cButtonSlots[i]); - }); + SaveManager::Instance->SaveArray( + "buttonItems", ARRAY_COUNT(saveContext->childEquips.buttonItems), + [&](size_t i) { SaveManager::Instance->SaveData("", saveContext->childEquips.buttonItems[i]); }); + SaveManager::Instance->SaveArray( + "cButtonSlots", ARRAY_COUNT(saveContext->childEquips.cButtonSlots), + [&](size_t i) { SaveManager::Instance->SaveData("", saveContext->childEquips.cButtonSlots[i]); }); SaveManager::Instance->SaveData("equipment", saveContext->childEquips.equipment); }); SaveManager::Instance->SaveStruct("adultEquips", [&]() { - SaveManager::Instance->SaveArray("buttonItems", ARRAY_COUNT(saveContext->adultEquips.buttonItems), [&](size_t i) { - SaveManager::Instance->SaveData("", saveContext->adultEquips.buttonItems[i]); - }); - SaveManager::Instance->SaveArray("cButtonSlots", ARRAY_COUNT(saveContext->adultEquips.cButtonSlots), [&](size_t i) { - SaveManager::Instance->SaveData("", saveContext->adultEquips.cButtonSlots[i]); - }); + SaveManager::Instance->SaveArray( + "buttonItems", ARRAY_COUNT(saveContext->adultEquips.buttonItems), + [&](size_t i) { SaveManager::Instance->SaveData("", saveContext->adultEquips.buttonItems[i]); }); + SaveManager::Instance->SaveArray( + "cButtonSlots", ARRAY_COUNT(saveContext->adultEquips.cButtonSlots), + [&](size_t i) { SaveManager::Instance->SaveData("", saveContext->adultEquips.cButtonSlots[i]); }); SaveManager::Instance->SaveData("equipment", saveContext->adultEquips.equipment); }); SaveManager::Instance->SaveData("unk_54", saveContext->unk_54); @@ -1539,54 +1548,15 @@ void SaveManager::SaveBase(SaveContext* saveContext) { SaveManager::Instance->SaveData("equipment", saveContext->inventory.equipment); SaveManager::Instance->SaveData("upgrades", saveContext->inventory.upgrades); SaveManager::Instance->SaveData("questItems", saveContext->inventory.questItems); - SaveManager::Instance->SaveArray("dungeonItems", ARRAY_COUNT(saveContext->inventory.dungeonItems), [&](size_t i) { - SaveManager::Instance->SaveData("", saveContext->inventory.dungeonItems[i]); - }); + SaveManager::Instance->SaveArray( + "dungeonItems", ARRAY_COUNT(saveContext->inventory.dungeonItems), + [&](size_t i) { SaveManager::Instance->SaveData("", saveContext->inventory.dungeonItems[i]); }); SaveManager::Instance->SaveArray("dungeonKeys", ARRAY_COUNT(saveContext->inventory.dungeonKeys), [&](size_t i) { SaveManager::Instance->SaveData("", saveContext->inventory.dungeonKeys[i]); }); SaveManager::Instance->SaveData("defenseHearts", saveContext->inventory.defenseHearts); SaveManager::Instance->SaveData("gsTokens", saveContext->inventory.gsTokens); }); - SaveManager::Instance->SaveStruct("sohStats", [&]() { - SaveManager::Instance->SaveData("buildVersion", saveContext->sohStats.buildVersion); - SaveManager::Instance->SaveData("buildVersionMajor", saveContext->sohStats.buildVersionMajor); - SaveManager::Instance->SaveData("buildVersionMinor", saveContext->sohStats.buildVersionMinor); - SaveManager::Instance->SaveData("buildVersionPatch", saveContext->sohStats.buildVersionPatch); - - SaveManager::Instance->SaveData("heartPieces", saveContext->sohStats.heartPieces); - SaveManager::Instance->SaveData("heartContainers", saveContext->sohStats.heartContainers); - SaveManager::Instance->SaveArray("dungeonKeys", ARRAY_COUNT(saveContext->sohStats.dungeonKeys), [&](size_t i) { - SaveManager::Instance->SaveData("", saveContext->sohStats.dungeonKeys[i]); - }); - SaveManager::Instance->SaveData("playTimer", saveContext->sohStats.playTimer); - SaveManager::Instance->SaveData("pauseTimer", saveContext->sohStats.pauseTimer); - SaveManager::Instance->SaveArray("itemTimestamps", ARRAY_COUNT(saveContext->sohStats.itemTimestamp), [&](size_t i) { - SaveManager::Instance->SaveData("", saveContext->sohStats.itemTimestamp[i]); - }); - SaveManager::Instance->SaveArray("sceneTimestamps", ARRAY_COUNT(saveContext->sohStats.sceneTimestamps), [&](size_t i) { - SaveManager::Instance->SaveStruct("", [&]() { - SaveManager::Instance->SaveData("scene", saveContext->sohStats.sceneTimestamps[i].scene); - SaveManager::Instance->SaveData("room", saveContext->sohStats.sceneTimestamps[i].room); - SaveManager::Instance->SaveData("sceneTime", saveContext->sohStats.sceneTimestamps[i].sceneTime); - SaveManager::Instance->SaveData("roomTime", saveContext->sohStats.sceneTimestamps[i].roomTime); - SaveManager::Instance->SaveData("isRoom", saveContext->sohStats.sceneTimestamps[i].isRoom); - }); - }); - SaveManager::Instance->SaveData("tsIdx", saveContext->sohStats.tsIdx); - SaveManager::Instance->SaveArray("counts", ARRAY_COUNT(saveContext->sohStats.count), [&](size_t i) { - SaveManager::Instance->SaveData("", saveContext->sohStats.count[i]); - }); - SaveManager::Instance->SaveArray("scenesDiscovered", ARRAY_COUNT(saveContext->sohStats.scenesDiscovered), [&](size_t i) { - SaveManager::Instance->SaveData("", saveContext->sohStats.scenesDiscovered[i]); - }); - SaveManager::Instance->SaveArray("entrancesDiscovered", ARRAY_COUNT(saveContext->sohStats.entrancesDiscovered), [&](size_t i) { - SaveManager::Instance->SaveData("", saveContext->sohStats.entrancesDiscovered[i]); - }); - SaveManager::Instance->SaveArray("locationsSkipped", ARRAY_COUNT(saveContext->sohStats.locationsSkipped), [&](size_t i) { - SaveManager::Instance->SaveData("", saveContext->sohStats.locationsSkipped[i]); - }); - }); SaveManager::Instance->SaveArray("sceneFlags", ARRAY_COUNT(saveContext->sceneFlags), [&](size_t i) { SaveManager::Instance->SaveStruct("", [&]() { SaveManager::Instance->SaveData("chest", saveContext->sceneFlags[i].chest); @@ -1612,9 +1582,8 @@ void SaveManager::SaveBase(SaveContext* saveContext) { SaveManager::Instance->SaveData("tempSwchFlags", saveContext->fw.tempSwchFlags); SaveManager::Instance->SaveData("tempCollectFlags", saveContext->fw.tempCollectFlags); }); - SaveManager::Instance->SaveArray("gsFlags", ARRAY_COUNT(saveContext->gsFlags), [&](size_t i) { - SaveManager::Instance->SaveData("", saveContext->gsFlags[i]); - }); + SaveManager::Instance->SaveArray("gsFlags", ARRAY_COUNT(saveContext->gsFlags), + [&](size_t i) { SaveManager::Instance->SaveData("", saveContext->gsFlags[i]); }); SaveManager::Instance->SaveArray("highScores", ARRAY_COUNT(saveContext->highScores), [&](size_t i) { SaveManager::Instance->SaveData("", saveContext->highScores[i]); }); @@ -1624,9 +1593,8 @@ void SaveManager::SaveBase(SaveContext* saveContext) { SaveManager::Instance->SaveArray("itemGetInf", ARRAY_COUNT(saveContext->itemGetInf), [&](size_t i) { SaveManager::Instance->SaveData("", saveContext->itemGetInf[i]); }); - SaveManager::Instance->SaveArray("infTable", ARRAY_COUNT(saveContext->infTable), [&](size_t i) { - SaveManager::Instance->SaveData("", saveContext->infTable[i]); - }); + SaveManager::Instance->SaveArray("infTable", ARRAY_COUNT(saveContext->infTable), + [&](size_t i) { SaveManager::Instance->SaveData("", saveContext->infTable[i]); }); SaveManager::Instance->SaveData("worldMapAreaData", saveContext->worldMapAreaData); SaveManager::Instance->SaveData("scarecrowLongSongSet", saveContext->scarecrowLongSongSet); SaveManager::Instance->SaveArray("scarecrowLongSong", ARRAY_COUNT(saveContext->scarecrowLongSong), [&](size_t i) { @@ -1722,15 +1690,14 @@ void SaveManager::LoadArray(const std::string& name, const size_t size, LoadArra for (; (currentJsonArrayContext != currentJsonContext->end()) && (i < size); i++, currentJsonArrayContext++) { func(i); } - // Handle remainer of items. Either this was data that was manually deleted, or a later version extended the size of the array. - // The later members will be default constructed. + // Handle remainer of items. Either this was data that was manually deleted, or a later version extended the size of + // the array. The later members will be default constructed. for (; i < size; i++) { func(i); } currentJsonContext = saveJsonContext; } - void SaveManager::LoadStruct(const std::string& name, LoadStructFunc func) { // Create an empty struct and set it as the current load context, then call the function that loads the struct. // If it is an array entry, load it from the array instead. @@ -1756,8 +1723,7 @@ void SaveManager::LoadStruct(const std::string& name, LoadStructFunc func) { #if defined(__WIIU__) || defined(__SWITCH__) // std::filesystem::copy_file doesn't work properly with the Wii U's toolchain atm -int copy_file(const char* src, const char* dst) -{ +int copy_file(const char* src, const char* dst) { alignas(0x40) uint8_t buf[4096]; FILE* r = fopen(src, "r"); if (!r) { diff --git a/soh/soh/SaveManager.h b/soh/soh/SaveManager.h index e31696fcf..db36e22aa 100644 --- a/soh/soh/SaveManager.h +++ b/soh/soh/SaveManager.h @@ -118,8 +118,8 @@ public: static const int MaxFiles = 3; std::array fileMetaInfo; - void RegisterSectionAutoSave(std::string section); - void UnregisterSectionAutoSave(std::string section); + void RegisterAutosaveSection(std::string section); + void UnregisterAutosaveSection(std::string section); private: std::filesystem::path GetFileName(int fileNum); @@ -151,7 +151,7 @@ public: using SectionSaveHandler = std::pair; std::map sectionSaveHandlers; - // sets a section to + // tracks sections to save during autosave triggers std::vector autosaveRegistry; std::map postHandlers; From 685925cbb86d09da3c2afd12e11fca66e21d189d Mon Sep 17 00:00:00 2001 From: Malkierian Date: Fri, 12 May 2023 13:23:50 -0700 Subject: [PATCH 03/17] Moved `sohStats` to its own section, and moved the saving and loading to its own registered load and save functions within `gameplaystats.cpp`. Required making a new loader version for `base` without `sohStats` loading code. Improved save file efficiency by adding code to not write any "empty" entries in `sceneTimestamps` (as determined by room and scene being 254) when saving, and initializing them to 254 if not loaded from the save file. --- soh/soh/Enhancements/gameplaystats.cpp | 33 +++-- soh/soh/SaveManager.cpp | 195 +++++++++++++++++++++++-- soh/soh/SaveManager.h | 7 +- 3 files changed, 210 insertions(+), 25 deletions(-) diff --git a/soh/soh/Enhancements/gameplaystats.cpp b/soh/soh/Enhancements/gameplaystats.cpp index 94029ecc8..2b76b932a 100644 --- a/soh/soh/Enhancements/gameplaystats.cpp +++ b/soh/soh/Enhancements/gameplaystats.cpp @@ -3,6 +3,7 @@ extern "C" { } #include "soh/SaveManager.h" +#include "functions.h" #include "macros.h" #include "ImGuiImpl.h" #include "../UIWidgets.hpp" @@ -12,6 +13,8 @@ extern "C" { #include #include +//#define ARRAY_COUNT(arr) (s32)(sizeof(arr) / sizeof(arr[0])) + extern "C" { #include #include "variables.h" @@ -196,8 +199,9 @@ void LoadStatsVersion1() { SaveManager::Instance->LoadArray( "itemTimestamps", ARRAY_COUNT(gSaveContext.sohStats.itemTimestamp), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.sohStats.itemTimestamp[i]); }); + int sceneTimestampCount = 0; SaveManager::Instance->LoadArray( - "sceneTimestamps", ARRAY_COUNT(gSaveContext.sohStats.sceneTimestamps), [](size_t i) { + "sceneTimestamps", ARRAY_COUNT(gSaveContext.sohStats.sceneTimestamps), [&sceneTimestampCount](size_t i) { SaveManager::Instance->LoadStruct("", [&i]() { SaveManager::Instance->LoadData("scene", gSaveContext.sohStats.sceneTimestamps[i].scene); SaveManager::Instance->LoadData("room", gSaveContext.sohStats.sceneTimestamps[i].room); @@ -205,7 +209,12 @@ void LoadStatsVersion1() { SaveManager::Instance->LoadData("roomTime", gSaveContext.sohStats.sceneTimestamps[i].roomTime); SaveManager::Instance->LoadData("isRoom", gSaveContext.sohStats.sceneTimestamps[i].isRoom); }); + sceneTimestampCount++; }); + for (int j = sceneTimestampCount; j < 8191; j++) { + gSaveContext.sohStats.sceneTimestamps[j].scene = 254; + gSaveContext.sohStats.sceneTimestamps[j].room = 254; + } SaveManager::Instance->LoadData("tsIdx", gSaveContext.sohStats.tsIdx); SaveManager::Instance->LoadArray("counts", ARRAY_COUNT(gSaveContext.sohStats.count), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.sohStats.count[i]); @@ -221,7 +230,7 @@ void LoadStatsVersion1() { [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.sohStats.locationsSkipped[i]); }); } -void SaveStatsVersion1(SaveContext* saveContext) { +void SaveStats(SaveContext* saveContext) { SaveManager::Instance->SaveData("buildVersion", saveContext->sohStats.buildVersion); SaveManager::Instance->SaveData("buildVersionMajor", saveContext->sohStats.buildVersionMajor); SaveManager::Instance->SaveData("buildVersionMinor", saveContext->sohStats.buildVersionMinor); @@ -239,13 +248,15 @@ void SaveStatsVersion1(SaveContext* saveContext) { [&](size_t i) { SaveManager::Instance->SaveData("", saveContext->sohStats.itemTimestamp[i]); }); SaveManager::Instance->SaveArray( "sceneTimestamps", ARRAY_COUNT(saveContext->sohStats.sceneTimestamps), [&](size_t i) { - SaveManager::Instance->SaveStruct("", [&]() { - SaveManager::Instance->SaveData("scene", saveContext->sohStats.sceneTimestamps[i].scene); - SaveManager::Instance->SaveData("room", saveContext->sohStats.sceneTimestamps[i].room); - SaveManager::Instance->SaveData("sceneTime", saveContext->sohStats.sceneTimestamps[i].sceneTime); - SaveManager::Instance->SaveData("roomTime", saveContext->sohStats.sceneTimestamps[i].roomTime); - SaveManager::Instance->SaveData("isRoom", saveContext->sohStats.sceneTimestamps[i].isRoom); - }); + if (saveContext->sohStats.sceneTimestamps[i].scene != 254 && saveContext->sohStats.sceneTimestamps[i].room != 254) { + SaveManager::Instance->SaveStruct("", [&]() { + SaveManager::Instance->SaveData("scene", saveContext->sohStats.sceneTimestamps[i].scene); + SaveManager::Instance->SaveData("room", saveContext->sohStats.sceneTimestamps[i].room); + SaveManager::Instance->SaveData("sceneTime", saveContext->sohStats.sceneTimestamps[i].sceneTime); + SaveManager::Instance->SaveData("roomTime", saveContext->sohStats.sceneTimestamps[i].roomTime); + SaveManager::Instance->SaveData("isRoom", saveContext->sohStats.sceneTimestamps[i].isRoom); + }); + } }); SaveManager::Instance->SaveData("tsIdx", saveContext->sohStats.tsIdx); SaveManager::Instance->SaveArray("counts", ARRAY_COUNT(saveContext->sohStats.count), [&](size_t i) { @@ -762,6 +773,6 @@ extern "C" void InitStatTracker() { SetupDisplayNames(); SetupDisplayColors(); SaveManager::Instance->AddLoadFunction("sohStats", 1, LoadStatsVersion1); - SaveManager::Instance->AddSaveFunction("sohStats", 1, SaveStatsVersion1); - SaveManager::Instance->RegisterAutosaveSection("sohStats"); + SaveManager::Instance->AddSaveFunction("sohStats", 1, SaveStats); + SaveManager::Instance->RegisterGameSaveSection("sohStats"); } \ No newline at end of file diff --git a/soh/soh/SaveManager.cpp b/soh/soh/SaveManager.cpp index d60f81d55..52f5eab44 100644 --- a/soh/soh/SaveManager.cpp +++ b/soh/soh/SaveManager.cpp @@ -49,13 +49,14 @@ SaveManager::SaveManager() { AddLoadFunction("base", 1, LoadBaseVersion1); AddLoadFunction("base", 2, LoadBaseVersion2); AddLoadFunction("base", 3, LoadBaseVersion3); - AddSaveFunction("base", 3, SaveBase); - RegisterAutosaveSection("base"); + AddLoadFunction("base", 4, LoadBaseVersion4); + AddSaveFunction("base", 4, SaveBase); + RegisterGameSaveSection("base"); AddLoadFunction("randomizer", 1, LoadRandomizerVersion1); AddLoadFunction("randomizer", 2, LoadRandomizerVersion2); AddSaveFunction("randomizer", 2, SaveRandomizer); - RegisterAutosaveSection("randomizer"); + RegisterGameSaveSection("randomizer"); AddInitFunction(InitFileImpl); @@ -85,16 +86,17 @@ SaveManager::SaveManager() { } } -void SaveManager::RegisterAutosaveSection(std::string section) { - if (std::find(autosaveRegistry.begin(), autosaveRegistry.end(), section) == autosaveRegistry.end()) { - autosaveRegistry.push_back(section); +// GameSaveSection functions affect the list of sections that save their data when a game save is triggered +void SaveManager::RegisterGameSaveSection(std::string section) { + if (std::find(gameSaveRegistry.begin(), gameSaveRegistry.end(), section) == gameSaveRegistry.end()) { + gameSaveRegistry.push_back(section); } } void SaveManager::UnregisterAutosaveSection(std::string section) { - auto find = std::find(autosaveRegistry.begin(), autosaveRegistry.end(), section); - if (find != autosaveRegistry.end()) { - autosaveRegistry.erase(find); + auto find = std::find(gameSaveRegistry.begin(), gameSaveRegistry.end(), section); + if (find != gameSaveRegistry.end()) { + gameSaveRegistry.erase(find); } } @@ -762,7 +764,7 @@ void SaveManager::SaveFileThreaded(int fileNum, SaveContext* saveContext, const currentJsonContext = §ionBlock["data"]; sectionHandler.second.second(saveContext); } - } else if (sectionSaveHandlers.contains(sectionString) && std::find(autosaveRegistry.begin(), autosaveRegistry.end(), sectionString) != autosaveRegistry.end()) { + } else if (sectionSaveHandlers.contains(sectionString) && std::find(gameSaveRegistry.begin(), gameSaveRegistry.end(), sectionString) != gameSaveRegistry.end()) { SectionSaveHandler handler = sectionSaveHandlers.find(sectionString)->second; nlohmann::json& sectionBlock = saveBlock["sections"][sectionString]; sectionBlock["version"] = handler.first; @@ -817,7 +819,6 @@ void SaveManager::LoadFile(int fileNum) { std::ifstream input(GetFileName(fileNum)); - nlohmann::json saveBlock; input >> saveBlock; if (!saveBlock.contains("version")) { SPDLOG_ERROR("Save at " + GetFileName(fileNum).string() + " contains no version"); @@ -1484,6 +1485,178 @@ void SaveManager::LoadBaseVersion3() { SaveManager::Instance->LoadData("dogParams", gSaveContext.dogParams); } +void SaveManager::LoadBaseVersion4() { + SaveManager::Instance->LoadData("entranceIndex", gSaveContext.entranceIndex); + SaveManager::Instance->LoadData("linkAge", gSaveContext.linkAge); + SaveManager::Instance->LoadData("cutsceneIndex", gSaveContext.cutsceneIndex); + SaveManager::Instance->LoadData("dayTime", gSaveContext.dayTime); + SaveManager::Instance->LoadData("nightFlag", gSaveContext.nightFlag); + SaveManager::Instance->LoadData("totalDays", gSaveContext.totalDays); + SaveManager::Instance->LoadData("bgsDayCount", gSaveContext.bgsDayCount); + SaveManager::Instance->LoadData("deaths", gSaveContext.deaths); + SaveManager::Instance->LoadArray("playerName", ARRAY_COUNT(gSaveContext.playerName), + [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.playerName[i]); }); + SaveManager::Instance->LoadData("n64ddFlag", gSaveContext.n64ddFlag); + SaveManager::Instance->LoadData("healthCapacity", gSaveContext.healthCapacity); + SaveManager::Instance->LoadData("health", gSaveContext.health); + SaveManager::Instance->LoadData("magicLevel", gSaveContext.magicLevel); + SaveManager::Instance->LoadData("magic", gSaveContext.magic); + SaveManager::Instance->LoadData("rupees", gSaveContext.rupees); + SaveManager::Instance->LoadData("swordHealth", gSaveContext.swordHealth); + SaveManager::Instance->LoadData("naviTimer", gSaveContext.naviTimer); + SaveManager::Instance->LoadData("isMagicAcquired", gSaveContext.isMagicAcquired); + SaveManager::Instance->LoadData("isDoubleMagicAcquired", gSaveContext.isDoubleMagicAcquired); + SaveManager::Instance->LoadData("isDoubleDefenseAcquired", gSaveContext.isDoubleDefenseAcquired); + SaveManager::Instance->LoadData("bgsFlag", gSaveContext.bgsFlag); + SaveManager::Instance->LoadData("ocarinaGameRoundNum", gSaveContext.ocarinaGameRoundNum); + SaveManager::Instance->LoadStruct("childEquips", []() { + SaveManager::Instance->LoadArray( + "buttonItems", ARRAY_COUNT(gSaveContext.childEquips.buttonItems), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.childEquips.buttonItems[i], + static_cast(ITEM_NONE)); + }); + SaveManager::Instance->LoadArray( + "cButtonSlots", ARRAY_COUNT(gSaveContext.childEquips.cButtonSlots), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.childEquips.cButtonSlots[i], + static_cast(SLOT_NONE)); + }); + SaveManager::Instance->LoadData("equipment", gSaveContext.childEquips.equipment); + }); + SaveManager::Instance->LoadStruct("adultEquips", []() { + SaveManager::Instance->LoadArray( + "buttonItems", ARRAY_COUNT(gSaveContext.adultEquips.buttonItems), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.adultEquips.buttonItems[i], + static_cast(ITEM_NONE)); + }); + SaveManager::Instance->LoadArray( + "cButtonSlots", ARRAY_COUNT(gSaveContext.adultEquips.cButtonSlots), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.adultEquips.cButtonSlots[i], + static_cast(SLOT_NONE)); + }); + SaveManager::Instance->LoadData("equipment", gSaveContext.adultEquips.equipment); + }); + SaveManager::Instance->LoadData("unk_54", gSaveContext.unk_54); + SaveManager::Instance->LoadData("savedSceneNum", gSaveContext.savedSceneNum); + SaveManager::Instance->LoadStruct("equips", []() { + SaveManager::Instance->LoadArray("buttonItems", ARRAY_COUNT(gSaveContext.equips.buttonItems), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.equips.buttonItems[i], static_cast(ITEM_NONE)); + }); + SaveManager::Instance->LoadArray("cButtonSlots", ARRAY_COUNT(gSaveContext.equips.cButtonSlots), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.equips.cButtonSlots[i], static_cast(SLOT_NONE)); + }); + SaveManager::Instance->LoadData("equipment", gSaveContext.equips.equipment); + }); + SaveManager::Instance->LoadStruct("inventory", []() { + SaveManager::Instance->LoadArray("items", ARRAY_COUNT(gSaveContext.inventory.items), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.inventory.items[i]); + }); + SaveManager::Instance->LoadArray("ammo", ARRAY_COUNT(gSaveContext.inventory.ammo), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.inventory.ammo[i]); + }); + SaveManager::Instance->LoadData("equipment", gSaveContext.inventory.equipment); + SaveManager::Instance->LoadData("upgrades", gSaveContext.inventory.upgrades); + SaveManager::Instance->LoadData("questItems", gSaveContext.inventory.questItems); + SaveManager::Instance->LoadArray( + "dungeonItems", ARRAY_COUNT(gSaveContext.inventory.dungeonItems), + [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.inventory.dungeonItems[i]); }); + SaveManager::Instance->LoadArray("dungeonKeys", ARRAY_COUNT(gSaveContext.inventory.dungeonKeys), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.inventory.dungeonKeys[i]); + }); + SaveManager::Instance->LoadData("defenseHearts", gSaveContext.inventory.defenseHearts); + SaveManager::Instance->LoadData("gsTokens", gSaveContext.inventory.gsTokens); + }); + SaveManager::Instance->LoadArray("sceneFlags", ARRAY_COUNT(gSaveContext.sceneFlags), [](size_t i) { + SaveManager::Instance->LoadStruct("", [&i]() { + SaveManager::Instance->LoadData("chest", gSaveContext.sceneFlags[i].chest); + SaveManager::Instance->LoadData("swch", gSaveContext.sceneFlags[i].swch); + SaveManager::Instance->LoadData("clear", gSaveContext.sceneFlags[i].clear); + SaveManager::Instance->LoadData("collect", gSaveContext.sceneFlags[i].collect); + SaveManager::Instance->LoadData("unk", gSaveContext.sceneFlags[i].unk); + SaveManager::Instance->LoadData("rooms", gSaveContext.sceneFlags[i].rooms); + SaveManager::Instance->LoadData("floors", gSaveContext.sceneFlags[i].floors); + }); + }); + SaveManager::Instance->LoadStruct("fw", []() { + SaveManager::Instance->LoadStruct("pos", []() { + SaveManager::Instance->LoadData("x", gSaveContext.fw.pos.x); + SaveManager::Instance->LoadData("y", gSaveContext.fw.pos.y); + SaveManager::Instance->LoadData("z", gSaveContext.fw.pos.z); + }); + SaveManager::Instance->LoadData("yaw", gSaveContext.fw.yaw); + SaveManager::Instance->LoadData("playerParams", gSaveContext.fw.playerParams); + SaveManager::Instance->LoadData("entranceIndex", gSaveContext.fw.entranceIndex); + SaveManager::Instance->LoadData("roomIndex", gSaveContext.fw.roomIndex); + SaveManager::Instance->LoadData("set", gSaveContext.fw.set); + SaveManager::Instance->LoadData("tempSwchFlags", gSaveContext.fw.tempSwchFlags); + SaveManager::Instance->LoadData("tempCollectFlags", gSaveContext.fw.tempCollectFlags); + }); + SaveManager::Instance->LoadArray("gsFlags", ARRAY_COUNT(gSaveContext.gsFlags), + [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.gsFlags[i]); }); + SaveManager::Instance->LoadArray("highScores", ARRAY_COUNT(gSaveContext.highScores), + [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.highScores[i]); }); + SaveManager::Instance->LoadArray("eventChkInf", ARRAY_COUNT(gSaveContext.eventChkInf), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.eventChkInf[i]); + }); + SaveManager::Instance->LoadArray("itemGetInf", ARRAY_COUNT(gSaveContext.itemGetInf), + [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.itemGetInf[i]); }); + SaveManager::Instance->LoadArray("infTable", ARRAY_COUNT(gSaveContext.infTable), + [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.infTable[i]); }); + SaveManager::Instance->LoadData("worldMapAreaData", gSaveContext.worldMapAreaData); + SaveManager::Instance->LoadData("scarecrowLongSongSet", gSaveContext.scarecrowLongSongSet); + SaveManager::Instance->LoadArray("scarecrowLongSong", ARRAY_COUNT(gSaveContext.scarecrowLongSong), [](size_t i) { + SaveManager::Instance->LoadStruct("", [&i]() { + SaveManager::Instance->LoadData("noteIdx", gSaveContext.scarecrowLongSong[i].noteIdx); + SaveManager::Instance->LoadData("unk_01", gSaveContext.scarecrowLongSong[i].unk_01); + SaveManager::Instance->LoadData("unk_02", gSaveContext.scarecrowLongSong[i].unk_02); + SaveManager::Instance->LoadData("volume", gSaveContext.scarecrowLongSong[i].volume); + SaveManager::Instance->LoadData("vibrato", gSaveContext.scarecrowLongSong[i].vibrato); + SaveManager::Instance->LoadData("tone", gSaveContext.scarecrowLongSong[i].tone); + SaveManager::Instance->LoadData("semitone", gSaveContext.scarecrowLongSong[i].semitone); + }); + }); + SaveManager::Instance->LoadData("scarecrowSpawnSongSet", gSaveContext.scarecrowSpawnSongSet); + SaveManager::Instance->LoadArray("scarecrowSpawnSong", ARRAY_COUNT(gSaveContext.scarecrowSpawnSong), [](size_t i) { + SaveManager::Instance->LoadStruct("", [&i]() { + SaveManager::Instance->LoadData("noteIdx", gSaveContext.scarecrowSpawnSong[i].noteIdx); + SaveManager::Instance->LoadData("unk_01", gSaveContext.scarecrowSpawnSong[i].unk_01); + SaveManager::Instance->LoadData("unk_02", gSaveContext.scarecrowSpawnSong[i].unk_02); + SaveManager::Instance->LoadData("volume", gSaveContext.scarecrowSpawnSong[i].volume); + SaveManager::Instance->LoadData("vibrato", gSaveContext.scarecrowSpawnSong[i].vibrato); + SaveManager::Instance->LoadData("tone", gSaveContext.scarecrowSpawnSong[i].tone); + SaveManager::Instance->LoadData("semitone", gSaveContext.scarecrowSpawnSong[i].semitone); + }); + }); + SaveManager::Instance->LoadStruct("horseData", []() { + SaveManager::Instance->LoadData("scene", gSaveContext.horseData.scene); + SaveManager::Instance->LoadStruct("pos", []() { + SaveManager::Instance->LoadData("x", gSaveContext.horseData.pos.x); + SaveManager::Instance->LoadData("y", gSaveContext.horseData.pos.y); + SaveManager::Instance->LoadData("z", gSaveContext.horseData.pos.z); + }); + SaveManager::Instance->LoadData("angle", gSaveContext.horseData.angle); + }); + + SaveManager::Instance->LoadArray("randomizerInf", ARRAY_COUNT(gSaveContext.randomizerInf), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.randomizerInf[i]); + }); + SaveManager::Instance->LoadData("isMasterQuest", gSaveContext.isMasterQuest); + SaveManager::Instance->LoadStruct("backupFW", []() { + SaveManager::Instance->LoadStruct("pos", []() { + SaveManager::Instance->LoadData("x", gSaveContext.backupFW.pos.x); + SaveManager::Instance->LoadData("y", gSaveContext.backupFW.pos.y); + SaveManager::Instance->LoadData("z", gSaveContext.backupFW.pos.z); + }); + SaveManager::Instance->LoadData("yaw", gSaveContext.backupFW.yaw); + SaveManager::Instance->LoadData("playerParams", gSaveContext.backupFW.playerParams); + SaveManager::Instance->LoadData("entranceIndex", gSaveContext.backupFW.entranceIndex); + SaveManager::Instance->LoadData("roomIndex", gSaveContext.backupFW.roomIndex); + SaveManager::Instance->LoadData("set", gSaveContext.backupFW.set); + SaveManager::Instance->LoadData("tempSwchFlags", gSaveContext.backupFW.tempSwchFlags); + SaveManager::Instance->LoadData("tempCollectFlags", gSaveContext.backupFW.tempCollectFlags); + }); + SaveManager::Instance->LoadData("dogParams", gSaveContext.dogParams); +} + void SaveManager::SaveBase(SaveContext* saveContext) { SaveManager::Instance->SaveData("entranceIndex", saveContext->entranceIndex); SaveManager::Instance->SaveData("linkAge", saveContext->linkAge); diff --git a/soh/soh/SaveManager.h b/soh/soh/SaveManager.h index db36e22aa..3401e5781 100644 --- a/soh/soh/SaveManager.h +++ b/soh/soh/SaveManager.h @@ -118,7 +118,7 @@ public: static const int MaxFiles = 3; std::array fileMetaInfo; - void RegisterAutosaveSection(std::string section); + void RegisterGameSaveSection(std::string section); void UnregisterAutosaveSection(std::string section); private: @@ -142,6 +142,7 @@ public: static void LoadBaseVersion1(); static void LoadBaseVersion2(); static void LoadBaseVersion3(); + static void LoadBaseVersion4(); static void SaveBase(SaveContext* saveContext); std::vector initFuncs; @@ -151,8 +152,8 @@ public: using SectionSaveHandler = std::pair; std::map sectionSaveHandlers; - // tracks sections to save during autosave triggers - std::vector autosaveRegistry; + // tracks sections to save during game saves + std::vector gameSaveRegistry; std::map postHandlers; From 42b35634a50da4a812a5a44cff81126b3745c878 Mon Sep 17 00:00:00 2001 From: Malkierian Date: Fri, 12 May 2023 15:18:26 -0700 Subject: [PATCH 04/17] Fixed residual values in global save block causing new files to save all sections previously loaded for metadata initialization, regardless of that section's execution during the save process. Fixed loading and saving of blank sceneTimestamps due to default construction of data structures during JSON loading making all "empty" entries have scene and room of 0. Moved SoH stats initialization to `gameplaystats.cpp` via `SaveManager::AddInitFunction`. --- soh/soh/Enhancements/gameplaystats.cpp | 69 +++++++++++++++++++++----- soh/soh/SaveManager.cpp | 45 +---------------- 2 files changed, 59 insertions(+), 55 deletions(-) diff --git a/soh/soh/Enhancements/gameplaystats.cpp b/soh/soh/Enhancements/gameplaystats.cpp index 2b76b932a..a6d48a9a1 100644 --- a/soh/soh/Enhancements/gameplaystats.cpp +++ b/soh/soh/Enhancements/gameplaystats.cpp @@ -199,22 +199,25 @@ void LoadStatsVersion1() { SaveManager::Instance->LoadArray( "itemTimestamps", ARRAY_COUNT(gSaveContext.sohStats.itemTimestamp), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.sohStats.itemTimestamp[i]); }); - int sceneTimestampCount = 0; SaveManager::Instance->LoadArray( - "sceneTimestamps", ARRAY_COUNT(gSaveContext.sohStats.sceneTimestamps), [&sceneTimestampCount](size_t i) { + "sceneTimestamps", ARRAY_COUNT(gSaveContext.sohStats.sceneTimestamps), [](size_t i) { SaveManager::Instance->LoadStruct("", [&i]() { - SaveManager::Instance->LoadData("scene", gSaveContext.sohStats.sceneTimestamps[i].scene); - SaveManager::Instance->LoadData("room", gSaveContext.sohStats.sceneTimestamps[i].room); - SaveManager::Instance->LoadData("sceneTime", gSaveContext.sohStats.sceneTimestamps[i].sceneTime); - SaveManager::Instance->LoadData("roomTime", gSaveContext.sohStats.sceneTimestamps[i].roomTime); - SaveManager::Instance->LoadData("isRoom", gSaveContext.sohStats.sceneTimestamps[i].isRoom); + int scene, room, sceneTime, roomTime, isRoom; + SaveManager::Instance->LoadData("scene", scene); + SaveManager::Instance->LoadData("room", room); + SaveManager::Instance->LoadData("sceneTime", sceneTime); + SaveManager::Instance->LoadData("roomTime", roomTime); + SaveManager::Instance->LoadData("isRoom", isRoom); + if (scene == 0 && room == 0 && sceneTime == 0 && roomTime == 0 && isRoom == 0) { + return; + } + gSaveContext.sohStats.sceneTimestamps[i].scene = scene; + gSaveContext.sohStats.sceneTimestamps[i].room = room; + gSaveContext.sohStats.sceneTimestamps[i].sceneTime = sceneTime; + gSaveContext.sohStats.sceneTimestamps[i].roomTime = roomTime; + gSaveContext.sohStats.sceneTimestamps[i].isRoom = isRoom; }); - sceneTimestampCount++; }); - for (int j = sceneTimestampCount; j < 8191; j++) { - gSaveContext.sohStats.sceneTimestamps[j].scene = 254; - gSaveContext.sohStats.sceneTimestamps[j].room = 254; - } SaveManager::Instance->LoadData("tsIdx", gSaveContext.sohStats.tsIdx); SaveManager::Instance->LoadArray("counts", ARRAY_COUNT(gSaveContext.sohStats.count), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.sohStats.count[i]); @@ -273,6 +276,47 @@ void SaveStats(SaveContext* saveContext) { [&](size_t i) { SaveManager::Instance->SaveData("", saveContext->sohStats.locationsSkipped[i]); }); } +void InitStats(bool isDebug) { + gSaveContext.sohStats.heartPieces = isDebug ? 8 : 0; + gSaveContext.sohStats.heartContainers = isDebug ? 8 : 0; + for (int dungeon = 0; dungeon < ARRAY_COUNT(gSaveContext.sohStats.dungeonKeys); dungeon++) { + gSaveContext.sohStats.dungeonKeys[dungeon] = isDebug ? 8 : 0; + } + gSaveContext.sohStats.playTimer = 0; + gSaveContext.sohStats.pauseTimer = 0; + for (int timestamp = 0; timestamp < ARRAY_COUNT(gSaveContext.sohStats.itemTimestamp); timestamp++) { + gSaveContext.sohStats.itemTimestamp[timestamp] = 0; + } + for (int timestamp = 0; timestamp < ARRAY_COUNT(gSaveContext.sohStats.sceneTimestamps); timestamp++) { + gSaveContext.sohStats.sceneTimestamps[timestamp].sceneTime = 0; + gSaveContext.sohStats.sceneTimestamps[timestamp].roomTime = 0; + gSaveContext.sohStats.sceneTimestamps[timestamp].scene = 254; + gSaveContext.sohStats.sceneTimestamps[timestamp].room = 254; + gSaveContext.sohStats.sceneTimestamps[timestamp].isRoom = 0; + } + gSaveContext.sohStats.tsIdx = 0; + for (int count = 0; count < ARRAY_COUNT(gSaveContext.sohStats.count); count++) { + gSaveContext.sohStats.count[count] = 0; + } + gSaveContext.sohStats.gameComplete = false; + for (int scenesIdx = 0; scenesIdx < ARRAY_COUNT(gSaveContext.sohStats.scenesDiscovered); scenesIdx++) { + gSaveContext.sohStats.scenesDiscovered[scenesIdx] = 0; + } + for (int entrancesIdx = 0; entrancesIdx < ARRAY_COUNT(gSaveContext.sohStats.entrancesDiscovered); entrancesIdx++) { + gSaveContext.sohStats.entrancesDiscovered[entrancesIdx] = 0; + } + for (int rc = 0; rc < ARRAY_COUNT(gSaveContext.sohStats.locationsSkipped); rc++) { + gSaveContext.sohStats.locationsSkipped[rc] = 0; + } + + strncpy(gSaveContext.sohStats.buildVersion, (const char*)gBuildVersion, + sizeof(gSaveContext.sohStats.buildVersion) - 1); + gSaveContext.sohStats.buildVersion[sizeof(gSaveContext.sohStats.buildVersion) - 1] = 0; + gSaveContext.sohStats.buildVersionMajor = gBuildVersionMajor; + gSaveContext.sohStats.buildVersionMinor = gBuildVersionMinor; + gSaveContext.sohStats.buildVersionPatch = gBuildVersionPatch; +} + void SortChronological(TimestampInfo* arr, size_t len) { TimestampInfo temp; for (int i = 0; i < len; i++) { @@ -774,5 +818,6 @@ extern "C" void InitStatTracker() { SetupDisplayColors(); SaveManager::Instance->AddLoadFunction("sohStats", 1, LoadStatsVersion1); SaveManager::Instance->AddSaveFunction("sohStats", 1, SaveStats); + SaveManager::Instance->AddInitFunction(InitStats); SaveManager::Instance->RegisterGameSaveSection("sohStats"); } \ No newline at end of file diff --git a/soh/soh/SaveManager.cpp b/soh/soh/SaveManager.cpp index 52f5eab44..873399080 100644 --- a/soh/soh/SaveManager.cpp +++ b/soh/soh/SaveManager.cpp @@ -413,6 +413,7 @@ void SaveManager::Init() { for (int fileNum = 0; fileNum < MaxFiles; fileNum++) { if (std::filesystem::exists(GetFileName(fileNum))) { LoadFile(fileNum); + saveBlock = nlohmann::json::object(); } } } @@ -529,37 +530,6 @@ void SaveManager::InitFileNormal() { } gSaveContext.inventory.defenseHearts = 0; gSaveContext.inventory.gsTokens = 0; - gSaveContext.sohStats.heartPieces = 0; - gSaveContext.sohStats.heartContainers = 0; - for (int dungeon = 0; dungeon < ARRAY_COUNT(gSaveContext.sohStats.dungeonKeys); dungeon++) { - gSaveContext.sohStats.dungeonKeys[dungeon] = 0; - } - gSaveContext.sohStats.playTimer = 0; - gSaveContext.sohStats.pauseTimer = 0; - for (int timestamp = 0; timestamp < ARRAY_COUNT(gSaveContext.sohStats.itemTimestamp); timestamp++) { - gSaveContext.sohStats.itemTimestamp[timestamp] = 0; - } - for (int timestamp = 0; timestamp < ARRAY_COUNT(gSaveContext.sohStats.sceneTimestamps); timestamp++) { - gSaveContext.sohStats.sceneTimestamps[timestamp].sceneTime = 0; - gSaveContext.sohStats.sceneTimestamps[timestamp].roomTime = 0; - gSaveContext.sohStats.sceneTimestamps[timestamp].scene = 254; - gSaveContext.sohStats.sceneTimestamps[timestamp].room = 254; - gSaveContext.sohStats.sceneTimestamps[timestamp].isRoom = 0; - } - gSaveContext.sohStats.tsIdx = 0; - for (int count = 0; count < ARRAY_COUNT(gSaveContext.sohStats.count); count++) { - gSaveContext.sohStats.count[count] = 0; - } - gSaveContext.sohStats.gameComplete = false; - for (int scenesIdx = 0; scenesIdx < ARRAY_COUNT(gSaveContext.sohStats.scenesDiscovered); scenesIdx++) { - gSaveContext.sohStats.scenesDiscovered[scenesIdx] = 0; - } - for (int entrancesIdx = 0; entrancesIdx < ARRAY_COUNT(gSaveContext.sohStats.entrancesDiscovered); entrancesIdx++) { - gSaveContext.sohStats.entrancesDiscovered[entrancesIdx] = 0; - } - for (int rc = 0; rc < ARRAY_COUNT(gSaveContext.sohStats.locationsSkipped); rc++) { - gSaveContext.sohStats.locationsSkipped[rc] = 0; - } for (int scene = 0; scene < ARRAY_COUNT(gSaveContext.sceneFlags); scene++) { gSaveContext.sceneFlags[scene].chest = 0; gSaveContext.sceneFlags[scene].swch = 0; @@ -628,13 +598,6 @@ void SaveManager::InitFileNormal() { gSaveContext.pendingSale = ITEM_NONE; gSaveContext.pendingSaleMod = MOD_NONE; - strncpy(gSaveContext.sohStats.buildVersion, (const char*)gBuildVersion, - sizeof(gSaveContext.sohStats.buildVersion) - 1); - gSaveContext.sohStats.buildVersion[sizeof(gSaveContext.sohStats.buildVersion) - 1] = 0; - gSaveContext.sohStats.buildVersionMajor = gBuildVersionMajor; - gSaveContext.sohStats.buildVersionMinor = gBuildVersionMinor; - gSaveContext.sohStats.buildVersionPatch = gBuildVersionPatch; - // RANDOTODO (ADD ITEMLOCATIONS TO GSAVECONTEXT) } @@ -718,11 +681,6 @@ void SaveManager::InitFileDebug() { } gSaveContext.inventory.defenseHearts = 0; gSaveContext.inventory.gsTokens = 0; - gSaveContext.sohStats.heartPieces = 8; - gSaveContext.sohStats.heartContainers = 8; - for (int dungeon = 0; dungeon < ARRAY_COUNT(gSaveContext.sohStats.dungeonKeys); dungeon++) { - gSaveContext.sohStats.dungeonKeys[dungeon] = 8; - } gSaveContext.horseData.scene = SCENE_SPOT00; gSaveContext.horseData.pos.x = -1840; @@ -760,6 +718,7 @@ void SaveManager::SaveFileThreaded(int fileNum, SaveContext* saveContext, const for (auto& sectionHandler : sectionSaveHandlers) { nlohmann::json& sectionBlock = saveBlock["sections"][sectionHandler.first]; sectionBlock["version"] = sectionHandler.second.first; + sectionBlock["data"] = nlohmann::json::object(); currentJsonContext = §ionBlock["data"]; sectionHandler.second.second(saveContext); From dbe672444c0b5ddf5639e7eb2386858ef558f262 Mon Sep 17 00:00:00 2001 From: Malkierian Date: Sat, 13 May 2023 11:26:30 -0700 Subject: [PATCH 05/17] Changed string paramaters for save functions to proper const pointer type. Implemented subsectional saving (handled in the section's save function, and passed to the save function by & pointer). Default of "all" passed in from SaveFile for game saves. Implemented subsectional saving for sohStats and entrances/scenes discovered. Fixed check for game save registry by putting the check against the registry in the "all" section save code. --- soh/soh/Enhancements/gameplaystats.cpp | 85 ++++++++++--------- .../randomizer/randomizer_entrance.c | 2 + soh/soh/SaveManager.cpp | 50 +++++++---- soh/soh/SaveManager.h | 10 ++- 4 files changed, 86 insertions(+), 61 deletions(-) diff --git a/soh/soh/Enhancements/gameplaystats.cpp b/soh/soh/Enhancements/gameplaystats.cpp index a6d48a9a1..69b41974b 100644 --- a/soh/soh/Enhancements/gameplaystats.cpp +++ b/soh/soh/Enhancements/gameplaystats.cpp @@ -233,47 +233,54 @@ void LoadStatsVersion1() { [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.sohStats.locationsSkipped[i]); }); } -void SaveStats(SaveContext* saveContext) { - SaveManager::Instance->SaveData("buildVersion", saveContext->sohStats.buildVersion); - SaveManager::Instance->SaveData("buildVersionMajor", saveContext->sohStats.buildVersionMajor); - SaveManager::Instance->SaveData("buildVersionMinor", saveContext->sohStats.buildVersionMinor); - SaveManager::Instance->SaveData("buildVersionPatch", saveContext->sohStats.buildVersionPatch); +void SaveStats(SaveContext* saveContext, const std::string& subSection) { + if (subSection == "all") { + SaveManager::Instance->SaveData("buildVersion", saveContext->sohStats.buildVersion); + SaveManager::Instance->SaveData("buildVersionMajor", saveContext->sohStats.buildVersionMajor); + SaveManager::Instance->SaveData("buildVersionMinor", saveContext->sohStats.buildVersionMinor); + SaveManager::Instance->SaveData("buildVersionPatch", saveContext->sohStats.buildVersionPatch); - SaveManager::Instance->SaveData("heartPieces", saveContext->sohStats.heartPieces); - SaveManager::Instance->SaveData("heartContainers", saveContext->sohStats.heartContainers); - SaveManager::Instance->SaveArray("dungeonKeys", ARRAY_COUNT(saveContext->sohStats.dungeonKeys), [&](size_t i) { - SaveManager::Instance->SaveData("", saveContext->sohStats.dungeonKeys[i]); - }); - SaveManager::Instance->SaveData("playTimer", saveContext->sohStats.playTimer); - SaveManager::Instance->SaveData("pauseTimer", saveContext->sohStats.pauseTimer); - SaveManager::Instance->SaveArray( - "itemTimestamps", ARRAY_COUNT(saveContext->sohStats.itemTimestamp), - [&](size_t i) { SaveManager::Instance->SaveData("", saveContext->sohStats.itemTimestamp[i]); }); - SaveManager::Instance->SaveArray( - "sceneTimestamps", ARRAY_COUNT(saveContext->sohStats.sceneTimestamps), [&](size_t i) { - if (saveContext->sohStats.sceneTimestamps[i].scene != 254 && saveContext->sohStats.sceneTimestamps[i].room != 254) { - SaveManager::Instance->SaveStruct("", [&]() { - SaveManager::Instance->SaveData("scene", saveContext->sohStats.sceneTimestamps[i].scene); - SaveManager::Instance->SaveData("room", saveContext->sohStats.sceneTimestamps[i].room); - SaveManager::Instance->SaveData("sceneTime", saveContext->sohStats.sceneTimestamps[i].sceneTime); - SaveManager::Instance->SaveData("roomTime", saveContext->sohStats.sceneTimestamps[i].roomTime); - SaveManager::Instance->SaveData("isRoom", saveContext->sohStats.sceneTimestamps[i].isRoom); - }); - } + SaveManager::Instance->SaveData("heartPieces", saveContext->sohStats.heartPieces); + SaveManager::Instance->SaveData("heartContainers", saveContext->sohStats.heartContainers); + SaveManager::Instance->SaveArray("dungeonKeys", ARRAY_COUNT(saveContext->sohStats.dungeonKeys), [&](size_t i) { + SaveManager::Instance->SaveData("", saveContext->sohStats.dungeonKeys[i]); }); - SaveManager::Instance->SaveData("tsIdx", saveContext->sohStats.tsIdx); - SaveManager::Instance->SaveArray("counts", ARRAY_COUNT(saveContext->sohStats.count), [&](size_t i) { - SaveManager::Instance->SaveData("", saveContext->sohStats.count[i]); - }); - SaveManager::Instance->SaveArray( - "scenesDiscovered", ARRAY_COUNT(saveContext->sohStats.scenesDiscovered), - [&](size_t i) { SaveManager::Instance->SaveData("", saveContext->sohStats.scenesDiscovered[i]); }); - SaveManager::Instance->SaveArray( - "entrancesDiscovered", ARRAY_COUNT(saveContext->sohStats.entrancesDiscovered), - [&](size_t i) { SaveManager::Instance->SaveData("", saveContext->sohStats.entrancesDiscovered[i]); }); - SaveManager::Instance->SaveArray( - "locationsSkipped", ARRAY_COUNT(saveContext->sohStats.locationsSkipped), - [&](size_t i) { SaveManager::Instance->SaveData("", saveContext->sohStats.locationsSkipped[i]); }); + SaveManager::Instance->SaveData("playTimer", saveContext->sohStats.playTimer); + SaveManager::Instance->SaveData("pauseTimer", saveContext->sohStats.pauseTimer); + SaveManager::Instance->SaveArray( + "itemTimestamps", ARRAY_COUNT(saveContext->sohStats.itemTimestamp), + [&](size_t i) { SaveManager::Instance->SaveData("", saveContext->sohStats.itemTimestamp[i]); }); + SaveManager::Instance->SaveArray( + "sceneTimestamps", ARRAY_COUNT(saveContext->sohStats.sceneTimestamps), [&](size_t i) { + if (saveContext->sohStats.sceneTimestamps[i].scene != 254 && + saveContext->sohStats.sceneTimestamps[i].room != 254) { + SaveManager::Instance->SaveStruct("", [&]() { + SaveManager::Instance->SaveData("scene", saveContext->sohStats.sceneTimestamps[i].scene); + SaveManager::Instance->SaveData("room", saveContext->sohStats.sceneTimestamps[i].room); + SaveManager::Instance->SaveData("sceneTime", saveContext->sohStats.sceneTimestamps[i].sceneTime); + SaveManager::Instance->SaveData("roomTime", saveContext->sohStats.sceneTimestamps[i].roomTime); + SaveManager::Instance->SaveData("isRoom", saveContext->sohStats.sceneTimestamps[i].isRoom); + }); + } + }); + SaveManager::Instance->SaveData("tsIdx", saveContext->sohStats.tsIdx); + SaveManager::Instance->SaveArray("counts", ARRAY_COUNT(saveContext->sohStats.count), [&](size_t i) { + SaveManager::Instance->SaveData("", saveContext->sohStats.count[i]); + }); + SaveManager::Instance->SaveArray( + "locationsSkipped", ARRAY_COUNT(saveContext->sohStats.locationsSkipped), + [&](size_t i) { SaveManager::Instance->SaveData("", saveContext->sohStats.locationsSkipped[i]); }); + } + if (subSection == "entrances" || subSection == "all") { + SaveManager::Instance->SaveArray("entrancesDiscovered", ARRAY_COUNT(saveContext->sohStats.entrancesDiscovered), [&](size_t i) { + SaveManager::Instance->SaveData("", saveContext->sohStats.entrancesDiscovered[i]); + }); + } + if (subSection == "scenes" || subSection == "all") { + SaveManager::Instance->SaveArray("scenesDiscovered", ARRAY_COUNT(saveContext->sohStats.scenesDiscovered), [&](size_t i) { + SaveManager::Instance->SaveData("", saveContext->sohStats.scenesDiscovered[i]); + }); + } } void InitStats(bool isDebug) { diff --git a/soh/soh/Enhancements/randomizer/randomizer_entrance.c b/soh/soh/Enhancements/randomizer/randomizer_entrance.c index 3c3712afa..26be88a24 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_entrance.c +++ b/soh/soh/Enhancements/randomizer/randomizer_entrance.c @@ -769,6 +769,7 @@ void Entrance_SetSceneDiscovered(u8 sceneNum) { u32 sceneBit = 1 << (sceneNum - (idx * bitsPerIndex)); gSaveContext.sohStats.scenesDiscovered[idx] |= sceneBit; } + Save_SaveSection("sohStats.scenes"); } u8 Entrance_GetIsEntranceDiscovered(u16 entranceIndex) { @@ -801,4 +802,5 @@ void Entrance_SetEntranceDiscovered(u16 entranceIndex) { } } } + Save_SaveSection("sohStats.entrances"); } diff --git a/soh/soh/SaveManager.cpp b/soh/soh/SaveManager.cpp index 873399080..ad53de5a2 100644 --- a/soh/soh/SaveManager.cpp +++ b/soh/soh/SaveManager.cpp @@ -279,7 +279,7 @@ void SaveManager::LoadRandomizerVersion2() { }); } -void SaveManager::SaveRandomizer(SaveContext* saveContext) { +void SaveManager::SaveRandomizer(SaveContext* saveContext, const std::string& subString) { if (!saveContext->n64ddFlag) return; @@ -709,26 +709,32 @@ void SaveManager::InitFileDebug() { } // Threaded SaveFile takes copy of gSaveContext for local unmodified storage -void SaveManager::SaveFileThreaded(int fileNum, SaveContext* saveContext, const std::string sectionString) { - /*nlohmann::json baseBlock; - - baseBlock["version"] = 1; - baseBlock["sections"] = nlohmann::json::object();*/ +void SaveManager::SaveFileThreaded(int fileNum, SaveContext* saveContext, const std::string& sectionString) { + saveBlock["version"] = 1; + size_t period = sectionString.find("."); + std::string section = sectionString; + std::string subsection = ""; + if (period != std::string::npos) { + subsection = sectionString.substr(period + 1, std::string::npos); + section = sectionString.substr(0, sectionString.length() - (subsection.length() + 1)); + } if (sectionString == "all") { for (auto& sectionHandler : sectionSaveHandlers) { - nlohmann::json& sectionBlock = saveBlock["sections"][sectionHandler.first]; - sectionBlock["version"] = sectionHandler.second.first; - sectionBlock["data"] = nlohmann::json::object(); + if (std::find(gameSaveRegistry.begin(), gameSaveRegistry.end(), sectionHandler.first) != gameSaveRegistry.end()) { + nlohmann::json& sectionBlock = saveBlock["sections"][sectionHandler.first]; + sectionBlock["version"] = sectionHandler.second.first; + sectionBlock["data"] = nlohmann::json::object(); - currentJsonContext = §ionBlock["data"]; - sectionHandler.second.second(saveContext); + currentJsonContext = §ionBlock["data"]; + sectionHandler.second.second(saveContext, "all"); + } } - } else if (sectionSaveHandlers.contains(sectionString) && std::find(gameSaveRegistry.begin(), gameSaveRegistry.end(), sectionString) != gameSaveRegistry.end()) { - SectionSaveHandler handler = sectionSaveHandlers.find(sectionString)->second; - nlohmann::json& sectionBlock = saveBlock["sections"][sectionString]; + } else if (sectionSaveHandlers.contains(section)) { + SectionSaveHandler handler = sectionSaveHandlers.find(section)->second; + nlohmann::json& sectionBlock = saveBlock["sections"][section]; sectionBlock["version"] = handler.first; currentJsonContext = §ionBlock["data"]; - handler.second(saveContext); + handler.second(saveContext, subsection); } else { return; } @@ -748,14 +754,18 @@ void SaveManager::SaveFileThreaded(int fileNum, SaveContext* saveContext, const GameInteractor::Instance->ExecuteHooks(fileNum); } -void SaveManager::SaveFile(int fileNum) { +void SaveManager::SaveSection(int fileNum, const std::string& sectionString) { if (fileNum == 0xFF) { return; } // Can't think of any time the promise would be needed, so use push_task instead of submit auto saveContext = new SaveContext; memcpy(saveContext, &gSaveContext, sizeof(gSaveContext)); - smThreadPool->push_task_back(&SaveManager::SaveFileThreaded, this, fileNum, saveContext, "all"); + smThreadPool->push_task_back(&SaveManager::SaveFileThreaded, this, fileNum, saveContext, sectionString); +} + +void SaveManager::SaveFile(int fileNum) { + SaveSection(fileNum, "all"); } void SaveManager::SaveGlobal() { @@ -1616,7 +1626,7 @@ void SaveManager::LoadBaseVersion4() { SaveManager::Instance->LoadData("dogParams", gSaveContext.dogParams); } -void SaveManager::SaveBase(SaveContext* saveContext) { +void SaveManager::SaveBase(SaveContext* saveContext, const std::string& subString) { SaveManager::Instance->SaveData("entranceIndex", saveContext->entranceIndex); SaveManager::Instance->SaveData("linkAge", saveContext->linkAge); SaveManager::Instance->SaveData("cutsceneIndex", saveContext->cutsceneIndex); @@ -2281,6 +2291,10 @@ extern "C" void Save_SaveFile(void) { SaveManager::Instance->SaveFile(gSaveContext.fileNum); } +extern "C" void Save_SaveSection(char* sectionString) { + SaveManager::Instance->SaveSection(gSaveContext.fileNum, sectionString); +} + extern "C" void Save_SaveGlobal(void) { SaveManager::Instance->SaveGlobal(); } diff --git a/soh/soh/SaveManager.h b/soh/soh/SaveManager.h index 3401e5781..93a1fe336 100644 --- a/soh/soh/SaveManager.h +++ b/soh/soh/SaveManager.h @@ -45,7 +45,7 @@ public: using InitFunc = void(*)(bool isDebug); using LoadFunc = void(*)(); - using SaveFunc = void(*)(SaveContext* saveContext); + using SaveFunc = void(*)(SaveContext* saveContext, const std::string& subSection); using PostFunc = void(*)(int version); SaveManager(); @@ -53,6 +53,7 @@ public: void Init(); void InitFile(bool isDebug); void SaveFile(int fileNum); + void SaveSection(int fileNum, const std::string& sectionString); void SaveGlobal(); void LoadFile(int fileNum); bool SaveFile_Exist(int fileNum); @@ -128,7 +129,7 @@ public: void ConvertFromUnversioned(); void CreateDefaultGlobal(); - void SaveFileThreaded(int fileNum, SaveContext* saveContext, const std::string sectionString); + void SaveFileThreaded(int fileNum, SaveContext* saveContext, const std::string& sectionString); void InitMeta(int slotNum); static void InitFileImpl(bool isDebug); @@ -137,13 +138,13 @@ public: static void LoadRandomizerVersion1(); static void LoadRandomizerVersion2(); - static void SaveRandomizer(SaveContext* saveContext); + static void SaveRandomizer(SaveContext* saveContext, const std::string& subString); static void LoadBaseVersion1(); static void LoadBaseVersion2(); static void LoadBaseVersion3(); static void LoadBaseVersion4(); - static void SaveBase(SaveContext* saveContext); + static void SaveBase(SaveContext* saveContext, const std::string& subString); std::vector initFuncs; @@ -172,6 +173,7 @@ typedef void (*Save_SaveFunc)(const SaveContext* saveContext); void Save_Init(void); void Save_InitFile(int isDebug); void Save_SaveFile(void); +void Save_SaveSection(char* sectionString); void Save_SaveGlobal(void); void Save_LoadGlobal(void); void Save_AddLoadFunction(char* name, int version, Save_LoadFunc func); From 550c10b1c37d9204154445dd4f1d10c22dee45ed Mon Sep 17 00:00:00 2001 From: Malkierian Date: Sat, 13 May 2023 11:41:28 -0700 Subject: [PATCH 06/17] Little bit of code clarification. --- soh/soh/SaveManager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/soh/soh/SaveManager.cpp b/soh/soh/SaveManager.cpp index ad53de5a2..b72ea2076 100644 --- a/soh/soh/SaveManager.cpp +++ b/soh/soh/SaveManager.cpp @@ -736,6 +736,7 @@ void SaveManager::SaveFileThreaded(int fileNum, SaveContext* saveContext, const currentJsonContext = §ionBlock["data"]; handler.second(saveContext, subsection); } else { + // save function for specified section does not exist. should this error? return; } From e2177d7392e42cfec76b893edde561e7d54c6f85 Mon Sep 17 00:00:00 2001 From: Malkierian Date: Sat, 13 May 2023 11:45:20 -0700 Subject: [PATCH 07/17] Added sanity check to clearing `sectionBlock["data"]` to only be for randomizer and only when the save file is not randomizer (to clear the existing structure from the loaded spoiler log). --- soh/soh/SaveManager.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/soh/soh/SaveManager.cpp b/soh/soh/SaveManager.cpp index b72ea2076..f9e488b05 100644 --- a/soh/soh/SaveManager.cpp +++ b/soh/soh/SaveManager.cpp @@ -723,7 +723,9 @@ void SaveManager::SaveFileThreaded(int fileNum, SaveContext* saveContext, const if (std::find(gameSaveRegistry.begin(), gameSaveRegistry.end(), sectionHandler.first) != gameSaveRegistry.end()) { nlohmann::json& sectionBlock = saveBlock["sections"][sectionHandler.first]; sectionBlock["version"] = sectionHandler.second.first; - sectionBlock["data"] = nlohmann::json::object(); + if (sectionHandler.first == "randomizer" && !gSaveContext.n64ddFlag) { + sectionBlock["data"] = nlohmann::json::object(); + } currentJsonContext = §ionBlock["data"]; sectionHandler.second.second(saveContext, "all"); From 22531fed27bbacbc3d0ec2c05fbe53b1a90e8dea Mon Sep 17 00:00:00 2001 From: Malkierian Date: Sat, 13 May 2023 11:47:22 -0700 Subject: [PATCH 08/17] A little more code clarification. --- soh/soh/SaveManager.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/soh/soh/SaveManager.cpp b/soh/soh/SaveManager.cpp index f9e488b05..ab82bd0d2 100644 --- a/soh/soh/SaveManager.cpp +++ b/soh/soh/SaveManager.cpp @@ -723,6 +723,8 @@ void SaveManager::SaveFileThreaded(int fileNum, SaveContext* saveContext, const if (std::find(gameSaveRegistry.begin(), gameSaveRegistry.end(), sectionHandler.first) != gameSaveRegistry.end()) { nlohmann::json& sectionBlock = saveBlock["sections"][sectionHandler.first]; sectionBlock["version"] = sectionHandler.second.first; + // If any save file is loaded for medatata, or a spoiler log is loaded (not sure which at this point), there is still data in the "randomizer" section + // This clears the randomizer data block if and only if the section being called is "randomizer" and n64ddFlag is false. if (sectionHandler.first == "randomizer" && !gSaveContext.n64ddFlag) { sectionBlock["data"] = nlohmann::json::object(); } From 7861b4c092886fafe9ae7a84020e82ab702aa8f8 Mon Sep 17 00:00:00 2001 From: Malkierian Date: Sat, 13 May 2023 12:33:10 -0700 Subject: [PATCH 09/17] Missed `baseBlock` -> `saveBlock` change in WiiU/Switch file writing block XD. --- soh/soh/SaveManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/soh/soh/SaveManager.cpp b/soh/soh/SaveManager.cpp index ab82bd0d2..a5dc6a8c7 100644 --- a/soh/soh/SaveManager.cpp +++ b/soh/soh/SaveManager.cpp @@ -746,7 +746,7 @@ void SaveManager::SaveFileThreaded(int fileNum, SaveContext* saveContext, const #if defined(__SWITCH__) || defined(__WIIU__) FILE* w = fopen(GetFileName(fileNum).c_str(), "w"); - std::string json_string = baseBlock.dump(4); + std::string json_string = saveBlock.dump(4); fwrite(json_string.c_str(), sizeof(char), json_string.length(), w); fclose(w); #else From 374301db9b4def96f7f3f8008d1032cc332223e0 Mon Sep 17 00:00:00 2001 From: Malkierian Date: Sat, 13 May 2023 18:29:05 -0700 Subject: [PATCH 10/17] Formatting and whitespace cleanup. --- soh/soh/Enhancements/gameplaystats.cpp | 121 +++++----- soh/soh/SaveManager.cpp | 315 ++++++++++++------------- 2 files changed, 215 insertions(+), 221 deletions(-) diff --git a/soh/soh/Enhancements/gameplaystats.cpp b/soh/soh/Enhancements/gameplaystats.cpp index 69b41974b..0e873a705 100644 --- a/soh/soh/Enhancements/gameplaystats.cpp +++ b/soh/soh/Enhancements/gameplaystats.cpp @@ -196,80 +196,79 @@ void LoadStatsVersion1() { }); SaveManager::Instance->LoadData("playTimer", gSaveContext.sohStats.playTimer); SaveManager::Instance->LoadData("pauseTimer", gSaveContext.sohStats.pauseTimer); - SaveManager::Instance->LoadArray( - "itemTimestamps", ARRAY_COUNT(gSaveContext.sohStats.itemTimestamp), - [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.sohStats.itemTimestamp[i]); }); - SaveManager::Instance->LoadArray( - "sceneTimestamps", ARRAY_COUNT(gSaveContext.sohStats.sceneTimestamps), [](size_t i) { - SaveManager::Instance->LoadStruct("", [&i]() { - int scene, room, sceneTime, roomTime, isRoom; - SaveManager::Instance->LoadData("scene", scene); - SaveManager::Instance->LoadData("room", room); - SaveManager::Instance->LoadData("sceneTime", sceneTime); - SaveManager::Instance->LoadData("roomTime", roomTime); - SaveManager::Instance->LoadData("isRoom", isRoom); - if (scene == 0 && room == 0 && sceneTime == 0 && roomTime == 0 && isRoom == 0) { - return; - } - gSaveContext.sohStats.sceneTimestamps[i].scene = scene; - gSaveContext.sohStats.sceneTimestamps[i].room = room; - gSaveContext.sohStats.sceneTimestamps[i].sceneTime = sceneTime; - gSaveContext.sohStats.sceneTimestamps[i].roomTime = roomTime; - gSaveContext.sohStats.sceneTimestamps[i].isRoom = isRoom; - }); + SaveManager::Instance->LoadArray("itemTimestamps", ARRAY_COUNT(gSaveContext.sohStats.itemTimestamp), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.sohStats.itemTimestamp[i]); + }); + SaveManager::Instance->LoadArray("sceneTimestamps", ARRAY_COUNT(gSaveContext.sohStats.sceneTimestamps), [](size_t i) { + SaveManager::Instance->LoadStruct("", [&i]() { + int scene, room, sceneTime, roomTime, isRoom; + SaveManager::Instance->LoadData("scene", scene); + SaveManager::Instance->LoadData("room", room); + SaveManager::Instance->LoadData("sceneTime", sceneTime); + SaveManager::Instance->LoadData("roomTime", roomTime); + SaveManager::Instance->LoadData("isRoom", isRoom); + if (scene == 0 && room == 0 && sceneTime == 0 && roomTime == 0 && isRoom == 0) { + return; + } + gSaveContext.sohStats.sceneTimestamps[i].scene = scene; + gSaveContext.sohStats.sceneTimestamps[i].room = room; + gSaveContext.sohStats.sceneTimestamps[i].sceneTime = sceneTime; + gSaveContext.sohStats.sceneTimestamps[i].roomTime = roomTime; + gSaveContext.sohStats.sceneTimestamps[i].isRoom = isRoom; }); + }); SaveManager::Instance->LoadData("tsIdx", gSaveContext.sohStats.tsIdx); SaveManager::Instance->LoadArray("counts", ARRAY_COUNT(gSaveContext.sohStats.count), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.sohStats.count[i]); }); - SaveManager::Instance->LoadArray( - "scenesDiscovered", ARRAY_COUNT(gSaveContext.sohStats.scenesDiscovered), - [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.sohStats.scenesDiscovered[i]); }); - SaveManager::Instance->LoadArray( - "entrancesDiscovered", ARRAY_COUNT(gSaveContext.sohStats.entrancesDiscovered), - [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.sohStats.entrancesDiscovered[i]); }); - SaveManager::Instance->LoadArray( - "locationsSkipped", ARRAY_COUNT(gSaveContext.sohStats.locationsSkipped), - [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.sohStats.locationsSkipped[i]); }); + SaveManager::Instance->LoadArray("scenesDiscovered", ARRAY_COUNT(gSaveContext.sohStats.scenesDiscovered), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.sohStats.scenesDiscovered[i]); + }); + SaveManager::Instance->LoadArray("entrancesDiscovered", ARRAY_COUNT(gSaveContext.sohStats.entrancesDiscovered), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.sohStats.entrancesDiscovered[i]); + }); + SaveManager::Instance->LoadArray("locationsSkipped", ARRAY_COUNT(gSaveContext.sohStats.locationsSkipped), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.sohStats.locationsSkipped[i]); + }); } void SaveStats(SaveContext* saveContext, const std::string& subSection) { if (subSection == "all") { - SaveManager::Instance->SaveData("buildVersion", saveContext->sohStats.buildVersion); - SaveManager::Instance->SaveData("buildVersionMajor", saveContext->sohStats.buildVersionMajor); - SaveManager::Instance->SaveData("buildVersionMinor", saveContext->sohStats.buildVersionMinor); - SaveManager::Instance->SaveData("buildVersionPatch", saveContext->sohStats.buildVersionPatch); + std::string buildVersion; + SaveManager::Instance->LoadData("buildVersion", buildVersion); + strncpy(gSaveContext.sohStats.buildVersion, buildVersion.c_str(), + ARRAY_COUNT(gSaveContext.sohStats.buildVersion) - 1); + gSaveContext.sohStats.buildVersion[ARRAY_COUNT(gSaveContext.sohStats.buildVersion) - 1] = 0; + SaveManager::Instance->LoadData("buildVersionMajor", gSaveContext.sohStats.buildVersionMajor); + SaveManager::Instance->LoadData("buildVersionMinor", gSaveContext.sohStats.buildVersionMinor); + SaveManager::Instance->LoadData("buildVersionPatch", gSaveContext.sohStats.buildVersionPatch); - SaveManager::Instance->SaveData("heartPieces", saveContext->sohStats.heartPieces); - SaveManager::Instance->SaveData("heartContainers", saveContext->sohStats.heartContainers); - SaveManager::Instance->SaveArray("dungeonKeys", ARRAY_COUNT(saveContext->sohStats.dungeonKeys), [&](size_t i) { - SaveManager::Instance->SaveData("", saveContext->sohStats.dungeonKeys[i]); + SaveManager::Instance->LoadData("heartPieces", gSaveContext.sohStats.heartPieces); + SaveManager::Instance->LoadData("heartContainers", gSaveContext.sohStats.heartContainers); + SaveManager::Instance->LoadArray("dungeonKeys", ARRAY_COUNT(gSaveContext.sohStats.dungeonKeys), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.sohStats.dungeonKeys[i]); }); - SaveManager::Instance->SaveData("playTimer", saveContext->sohStats.playTimer); - SaveManager::Instance->SaveData("pauseTimer", saveContext->sohStats.pauseTimer); - SaveManager::Instance->SaveArray( - "itemTimestamps", ARRAY_COUNT(saveContext->sohStats.itemTimestamp), - [&](size_t i) { SaveManager::Instance->SaveData("", saveContext->sohStats.itemTimestamp[i]); }); - SaveManager::Instance->SaveArray( - "sceneTimestamps", ARRAY_COUNT(saveContext->sohStats.sceneTimestamps), [&](size_t i) { - if (saveContext->sohStats.sceneTimestamps[i].scene != 254 && - saveContext->sohStats.sceneTimestamps[i].room != 254) { - SaveManager::Instance->SaveStruct("", [&]() { - SaveManager::Instance->SaveData("scene", saveContext->sohStats.sceneTimestamps[i].scene); - SaveManager::Instance->SaveData("room", saveContext->sohStats.sceneTimestamps[i].room); - SaveManager::Instance->SaveData("sceneTime", saveContext->sohStats.sceneTimestamps[i].sceneTime); - SaveManager::Instance->SaveData("roomTime", saveContext->sohStats.sceneTimestamps[i].roomTime); - SaveManager::Instance->SaveData("isRoom", saveContext->sohStats.sceneTimestamps[i].isRoom); - }); - } + SaveManager::Instance->LoadData("playTimer", gSaveContext.sohStats.playTimer); + SaveManager::Instance->LoadData("pauseTimer", gSaveContext.sohStats.pauseTimer); + SaveManager::Instance->LoadArray("itemTimestamps", ARRAY_COUNT(gSaveContext.sohStats.itemTimestamp), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.sohStats.itemTimestamp[i]); + }); + SaveManager::Instance->LoadArray("sceneTimestamps", ARRAY_COUNT(gSaveContext.sohStats.sceneTimestamps), [](size_t i) { + SaveManager::Instance->LoadStruct("", [&i]() { + SaveManager::Instance->LoadData("scene", gSaveContext.sohStats.sceneTimestamps[i].scene); + SaveManager::Instance->LoadData("room", gSaveContext.sohStats.sceneTimestamps[i].room); + SaveManager::Instance->LoadData("sceneTime", gSaveContext.sohStats.sceneTimestamps[i].sceneTime); + SaveManager::Instance->LoadData("roomTime", gSaveContext.sohStats.sceneTimestamps[i].roomTime); + SaveManager::Instance->LoadData("isRoom", gSaveContext.sohStats.sceneTimestamps[i].isRoom); }); - SaveManager::Instance->SaveData("tsIdx", saveContext->sohStats.tsIdx); - SaveManager::Instance->SaveArray("counts", ARRAY_COUNT(saveContext->sohStats.count), [&](size_t i) { - SaveManager::Instance->SaveData("", saveContext->sohStats.count[i]); }); - SaveManager::Instance->SaveArray( - "locationsSkipped", ARRAY_COUNT(saveContext->sohStats.locationsSkipped), - [&](size_t i) { SaveManager::Instance->SaveData("", saveContext->sohStats.locationsSkipped[i]); }); + SaveManager::Instance->LoadData("tsIdx", gSaveContext.sohStats.tsIdx); + SaveManager::Instance->LoadArray("counts", ARRAY_COUNT(gSaveContext.sohStats.count), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.sohStats.count[i]); + }); + SaveManager::Instance->LoadArray("locationsSkipped", ARRAY_COUNT(gSaveContext.sohStats.locationsSkipped), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.sohStats.locationsSkipped[i]); + }); } if (subSection == "entrances" || subSection == "all") { SaveManager::Instance->SaveArray("entrancesDiscovered", ARRAY_COUNT(saveContext->sohStats.entrancesDiscovered), [&](size_t i) { diff --git a/soh/soh/SaveManager.cpp b/soh/soh/SaveManager.cpp index a5dc6a8c7..4f15b85f0 100644 --- a/soh/soh/SaveManager.cpp +++ b/soh/soh/SaveManager.cpp @@ -124,8 +124,7 @@ void SaveManager::LoadRandomizerVersion1() { for (int i = 0; i < ARRAY_COUNT(gSaveContext.hintLocations); i++) { SaveManager::Instance->LoadData("hc" + std::to_string(i), gSaveContext.hintLocations[i].check); for (int j = 0; j < ARRAY_COUNT(gSaveContext.hintLocations[i].hintText); j++) { - SaveManager::Instance->LoadData("ht" + std::to_string(i) + "-" + std::to_string(j), - gSaveContext.hintLocations[i].hintText[j]); + SaveManager::Instance->LoadData("ht" + std::to_string(i) + "-" + std::to_string(j), gSaveContext.hintLocations[i].hintText[j]); } } @@ -189,13 +188,13 @@ void SaveManager::LoadRandomizerVersion2() { SaveManager::Instance->LoadData("destination", gSaveContext.entranceOverrides[i].destination); SaveManager::Instance->LoadData("blueWarp", gSaveContext.entranceOverrides[i].blueWarp); SaveManager::Instance->LoadData("override", gSaveContext.entranceOverrides[i].override); - SaveManager::Instance->LoadData("overrideDestination", - gSaveContext.entranceOverrides[i].overrideDestination); + SaveManager::Instance->LoadData("overrideDestination", gSaveContext.entranceOverrides[i].overrideDestination); }); }); - SaveManager::Instance->LoadArray("seed", ARRAY_COUNT(gSaveContext.seedIcons), - [&](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.seedIcons[i]); }); + SaveManager::Instance->LoadArray("seed", ARRAY_COUNT(gSaveContext.seedIcons), [&](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.seedIcons[i]); + }); SaveManager::Instance->LoadArray("randoSettings", RSK_MAX, [&](size_t i) { gSaveContext.randoSettings[i].key = RandomizerSettingKey(i); @@ -281,8 +280,7 @@ void SaveManager::LoadRandomizerVersion2() { void SaveManager::SaveRandomizer(SaveContext* saveContext, const std::string& subString) { - if (!saveContext->n64ddFlag) - return; + if (!saveContext->n64ddFlag) return; SaveManager::Instance->SaveArray("itemLocations", RC_MAX, [&](size_t i) { SaveManager::Instance->SaveStruct("", [&]() { @@ -298,13 +296,13 @@ void SaveManager::SaveRandomizer(SaveContext* saveContext, const std::string& su SaveManager::Instance->SaveData("destination", saveContext->entranceOverrides[i].destination); SaveManager::Instance->SaveData("blueWarp", saveContext->entranceOverrides[i].blueWarp); SaveManager::Instance->SaveData("override", saveContext->entranceOverrides[i].override); - SaveManager::Instance->SaveData("overrideDestination", - saveContext->entranceOverrides[i].overrideDestination); + SaveManager::Instance->SaveData("overrideDestination", saveContext->entranceOverrides[i].overrideDestination); }); }); - SaveManager::Instance->SaveArray("seed", ARRAY_COUNT(saveContext->seedIcons), - [&](size_t i) { SaveManager::Instance->SaveData("", saveContext->seedIcons[i]); }); + SaveManager::Instance->SaveArray("seed", ARRAY_COUNT(saveContext->seedIcons), [&](size_t i) { + SaveManager::Instance->SaveData("", saveContext->seedIcons[i]); + }); SaveManager::Instance->SaveArray("randoSettings", RSK_MAX, [&](size_t i) { SaveManager::Instance->SaveData("", saveContext->randoSettings[i].value); @@ -337,7 +335,7 @@ void SaveManager::SaveRandomizer(SaveContext* saveContext, const std::string& su std::shared_ptr randomizer = OTRGlobals::Instance->gRandomizer; std::vector> merchantPrices; - for (const auto& [check, price] : randomizer->merchantPrices) { + for (const auto& [ check, price ] : randomizer->merchantPrices) { merchantPrices.push_back(std::make_pair(check, price)); } @@ -355,8 +353,9 @@ void SaveManager::SaveRandomizer(SaveContext* saveContext, const std::string& su for (const auto scene : randomizer->masterQuestDungeons) { masterQuestDungeons.push_back(scene); } - SaveManager::Instance->SaveArray("masterQuestDungeons", masterQuestDungeons.size(), - [&](size_t i) { SaveManager::Instance->SaveData("", masterQuestDungeons[i]); }); + SaveManager::Instance->SaveArray("masterQuestDungeons", masterQuestDungeons.size(), [&](size_t i) { + SaveManager::Instance->SaveData("", masterQuestDungeons[i]); + }); } void SaveManager::Init() { @@ -436,18 +435,15 @@ void SaveManager::InitMeta(int fileNum) { fileMetaInfo[fileNum].randoSave = gSaveContext.n64ddFlag; // If the file is marked as a Master Quest file or if we're randomized and have at least one master quest dungeon, // we need the mq otr. - fileMetaInfo[fileNum].requiresMasterQuest = - gSaveContext.isMasterQuest > 0 || (gSaveContext.n64ddFlag && gSaveContext.mqDungeonCount > 0); + fileMetaInfo[fileNum].requiresMasterQuest = gSaveContext.isMasterQuest > 0 || (gSaveContext.n64ddFlag && gSaveContext.mqDungeonCount > 0); // If the file is not marked as Master Quest, it could still theoretically be a rando save with all 12 MQ dungeons, // in which case we don't actually require a vanilla OTR. - fileMetaInfo[fileNum].requiresOriginal = - !gSaveContext.isMasterQuest && (!gSaveContext.n64ddFlag || gSaveContext.mqDungeonCount < 12); + fileMetaInfo[fileNum].requiresOriginal = !gSaveContext.isMasterQuest && (!gSaveContext.n64ddFlag || gSaveContext.mqDungeonCount < 12); fileMetaInfo[fileNum].buildVersionMajor = gSaveContext.sohStats.buildVersionMajor; fileMetaInfo[fileNum].buildVersionMinor = gSaveContext.sohStats.buildVersionMinor; fileMetaInfo[fileNum].buildVersionPatch = gSaveContext.sohStats.buildVersionPatch; - strncpy(fileMetaInfo[fileNum].buildVersion, gSaveContext.sohStats.buildVersion, - sizeof(fileMetaInfo[fileNum].buildVersion) - 1); + strncpy(fileMetaInfo[fileNum].buildVersion, gSaveContext.sohStats.buildVersion, sizeof(fileMetaInfo[fileNum].buildVersion) - 1); fileMetaInfo[fileNum].buildVersion[sizeof(fileMetaInfo[fileNum].buildVersion) - 1] = 0; } @@ -598,7 +594,7 @@ void SaveManager::InitFileNormal() { gSaveContext.pendingSale = ITEM_NONE; gSaveContext.pendingSaleMod = MOD_NONE; - // RANDOTODO (ADD ITEMLOCATIONS TO GSAVECONTEXT) + //RANDOTODO (ADD ITEMLOCATIONS TO GSAVECONTEXT) } void SaveManager::InitFileDebug() { @@ -643,13 +639,11 @@ void SaveManager::InitFileDebug() { gSaveContext.savedSceneNum = 0x51; // Equipment - static std::array sButtonItems = { ITEM_SWORD_MASTER, ITEM_BOW, ITEM_BOMB, ITEM_OCARINA_FAIRY, - ITEM_NONE, ITEM_NONE, ITEM_NONE, ITEM_NONE }; + static std::array sButtonItems = { ITEM_SWORD_MASTER, ITEM_BOW, ITEM_BOMB, ITEM_OCARINA_FAIRY, ITEM_NONE, ITEM_NONE, ITEM_NONE, ITEM_NONE }; for (int button = 0; button < ARRAY_COUNT(gSaveContext.equips.buttonItems); button++) { gSaveContext.equips.buttonItems[button] = sButtonItems[button]; } - static std::array sCButtonSlots = { SLOT_BOW, SLOT_BOMB, SLOT_OCARINA, SLOT_NONE, - SLOT_NONE, SLOT_NONE, SLOT_NONE }; + static std::array sCButtonSlots = { SLOT_BOW, SLOT_BOMB, SLOT_OCARINA, SLOT_NONE, SLOT_NONE, SLOT_NONE, SLOT_NONE }; for (int button = 0; button < ARRAY_COUNT(gSaveContext.equips.cButtonSlots); button++) { gSaveContext.equips.cButtonSlots[button] = sCButtonSlots[button]; } @@ -806,15 +800,14 @@ void SaveManager::LoadFile(int fileNum) { if (!sectionLoadHandlers.contains(sectionName)) { // Unloadable sections aren't necessarily errors, they are probably mods that were unloaded // TODO report in a more noticeable manner - SPDLOG_WARN("Save " + GetFileName(fileNum).string() + " contains unloadable section " + - sectionName); + SPDLOG_WARN("Save " + GetFileName(fileNum).string() + " contains unloadable section " + sectionName); continue; } SectionLoadHandler& handler = sectionLoadHandlers[sectionName]; if (!handler.contains(sectionVersion)) { - // A section that has a loader without a handler for the specific version means that the user has a - // mod at an earlier version than the save has. In this case, the user probably wants to load the - // save. Report the error so that the user can rectify the error. + // A section that has a loader without a handler for the specific version means that the user has a mod + // at an earlier version than the save has. In this case, the user probably wants to load the save. + // Report the error so that the user can rectify the error. // TODO report in a more noticeable manner SPDLOG_ERROR("Save " + GetFileName(fileNum).string() + " contains section " + sectionName + " with an unloadable version " + std::to_string(sectionVersion)); @@ -844,7 +837,8 @@ bool SaveManager::SaveFile_Exist(int fileNum) { bool exists = std::filesystem::exists(GetFileName(fileNum)); SPDLOG_INFO("File[{}] - {}", fileNum, exists ? "exists" : "does not exist"); return exists; - } catch (std::filesystem::filesystem_error const& ex) { + } + catch (std::filesystem::filesystem_error const& ex) { SPDLOG_ERROR("Filesystem error"); return false; } @@ -860,8 +854,7 @@ void SaveManager::AddLoadFunction(const std::string& name, int version, LoadFunc } if (sectionLoadHandlers[name].contains(version)) { - SPDLOG_ERROR("Adding load function for section and version that already has one: " + name + ", " + - std::to_string(version)); + SPDLOG_ERROR("Adding load function for section and version that already has one: " + name + ", " + std::to_string(version)); assert(false); return; } @@ -906,8 +899,9 @@ void SaveManager::LoadBaseVersion1() { SaveManager::Instance->LoadData("totalDays", gSaveContext.totalDays); SaveManager::Instance->LoadData("bgsDayCount", gSaveContext.bgsDayCount); SaveManager::Instance->LoadData("deaths", gSaveContext.deaths); - SaveManager::Instance->LoadArray("playerName", ARRAY_COUNT(gSaveContext.playerName), - [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.playerName[i]); }); + SaveManager::Instance->LoadArray("playerName", ARRAY_COUNT(gSaveContext.playerName), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.playerName[i]); + }); SaveManager::Instance->LoadData("n64ddFlag", gSaveContext.n64ddFlag); SaveManager::Instance->LoadData("healthCapacity", gSaveContext.healthCapacity); SaveManager::Instance->LoadData("health", gSaveContext.health); @@ -922,29 +916,25 @@ void SaveManager::LoadBaseVersion1() { SaveManager::Instance->LoadData("bgsFlag", gSaveContext.bgsFlag); SaveManager::Instance->LoadData("ocarinaGameRoundNum", gSaveContext.ocarinaGameRoundNum); SaveManager::Instance->LoadStruct("childEquips", []() { - SaveManager::Instance->LoadArray( - "buttonItems", ARRAY_COUNT(gSaveContext.childEquips.buttonItems), [](size_t i) { + SaveManager::Instance->LoadArray("buttonItems", ARRAY_COUNT(gSaveContext.childEquips.buttonItems), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.childEquips.buttonItems[i], static_cast(ITEM_NONE)); - }); - SaveManager::Instance->LoadArray( - "cButtonSlots", ARRAY_COUNT(gSaveContext.childEquips.cButtonSlots), [](size_t i) { + }); + SaveManager::Instance->LoadArray("cButtonSlots", ARRAY_COUNT(gSaveContext.childEquips.cButtonSlots), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.childEquips.cButtonSlots[i], static_cast(SLOT_NONE)); - }); + }); SaveManager::Instance->LoadData("equipment", gSaveContext.childEquips.equipment); }); SaveManager::Instance->LoadStruct("adultEquips", []() { - SaveManager::Instance->LoadArray( - "buttonItems", ARRAY_COUNT(gSaveContext.adultEquips.buttonItems), [](size_t i) { + SaveManager::Instance->LoadArray("buttonItems", ARRAY_COUNT(gSaveContext.adultEquips.buttonItems), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.adultEquips.buttonItems[i], static_cast(ITEM_NONE)); - }); - SaveManager::Instance->LoadArray( - "cButtonSlots", ARRAY_COUNT(gSaveContext.adultEquips.cButtonSlots), [](size_t i) { + }); + SaveManager::Instance->LoadArray("cButtonSlots", ARRAY_COUNT(gSaveContext.adultEquips.cButtonSlots), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.adultEquips.cButtonSlots[i], static_cast(SLOT_NONE)); - }); + }); SaveManager::Instance->LoadData("equipment", gSaveContext.adultEquips.equipment); }); SaveManager::Instance->LoadData("unk_54", gSaveContext.unk_54); @@ -968,8 +958,7 @@ void SaveManager::LoadBaseVersion1() { SaveManager::Instance->LoadData("equipment", gSaveContext.inventory.equipment); SaveManager::Instance->LoadData("upgrades", gSaveContext.inventory.upgrades); SaveManager::Instance->LoadData("questItems", gSaveContext.inventory.questItems); - SaveManager::Instance->LoadArray( - "dungeonItems", ARRAY_COUNT(gSaveContext.inventory.dungeonItems), + SaveManager::Instance->LoadArray("dungeonItems", ARRAY_COUNT(gSaveContext.inventory.dungeonItems), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.inventory.dungeonItems[i]); }); SaveManager::Instance->LoadArray("dungeonKeys", ARRAY_COUNT(gSaveContext.inventory.dungeonKeys), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.inventory.dungeonKeys[i]); @@ -1002,17 +991,21 @@ void SaveManager::LoadBaseVersion1() { SaveManager::Instance->LoadData("tempSwchFlags", gSaveContext.fw.tempSwchFlags); SaveManager::Instance->LoadData("tempCollectFlags", gSaveContext.fw.tempCollectFlags); }); - SaveManager::Instance->LoadArray("gsFlags", ARRAY_COUNT(gSaveContext.gsFlags), - [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.gsFlags[i]); }); - SaveManager::Instance->LoadArray("highScores", ARRAY_COUNT(gSaveContext.highScores), - [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.highScores[i]); }); + SaveManager::Instance->LoadArray("gsFlags", ARRAY_COUNT(gSaveContext.gsFlags), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.gsFlags[i]); + }); + SaveManager::Instance->LoadArray("highScores", ARRAY_COUNT(gSaveContext.highScores), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.highScores[i]); + }); SaveManager::Instance->LoadArray("eventChkInf", ARRAY_COUNT(gSaveContext.eventChkInf), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.eventChkInf[i]); }); - SaveManager::Instance->LoadArray("itemGetInf", ARRAY_COUNT(gSaveContext.itemGetInf), - [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.itemGetInf[i]); }); - SaveManager::Instance->LoadArray("infTable", ARRAY_COUNT(gSaveContext.infTable), - [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.infTable[i]); }); + SaveManager::Instance->LoadArray("itemGetInf", ARRAY_COUNT(gSaveContext.itemGetInf), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.itemGetInf[i]); + }); + SaveManager::Instance->LoadArray("infTable", ARRAY_COUNT(gSaveContext.infTable), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.infTable[i]); + }); SaveManager::Instance->LoadData("worldMapAreaData", gSaveContext.worldMapAreaData); SaveManager::Instance->LoadData("scarecrowCustomSongSet", gSaveContext.scarecrowLongSongSet); SaveManager::Instance->LoadArray("scarecrowCustomSong", sizeof(gSaveContext.scarecrowLongSong), [](size_t i) { @@ -1046,8 +1039,9 @@ void SaveManager::LoadBaseVersion2() { SaveManager::Instance->LoadData("totalDays", gSaveContext.totalDays); SaveManager::Instance->LoadData("bgsDayCount", gSaveContext.bgsDayCount); SaveManager::Instance->LoadData("deaths", gSaveContext.deaths); - SaveManager::Instance->LoadArray("playerName", ARRAY_COUNT(gSaveContext.playerName), - [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.playerName[i]); }); + SaveManager::Instance->LoadArray("playerName", ARRAY_COUNT(gSaveContext.playerName), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.playerName[i]); + }); SaveManager::Instance->LoadData("n64ddFlag", gSaveContext.n64ddFlag); SaveManager::Instance->LoadData("healthCapacity", gSaveContext.healthCapacity); SaveManager::Instance->LoadData("health", gSaveContext.health); @@ -1062,29 +1056,25 @@ void SaveManager::LoadBaseVersion2() { SaveManager::Instance->LoadData("bgsFlag", gSaveContext.bgsFlag); SaveManager::Instance->LoadData("ocarinaGameRoundNum", gSaveContext.ocarinaGameRoundNum); SaveManager::Instance->LoadStruct("childEquips", []() { - SaveManager::Instance->LoadArray( - "buttonItems", ARRAY_COUNT(gSaveContext.childEquips.buttonItems), [](size_t i) { + SaveManager::Instance->LoadArray("buttonItems", ARRAY_COUNT(gSaveContext.childEquips.buttonItems), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.childEquips.buttonItems[i], static_cast(ITEM_NONE)); - }); - SaveManager::Instance->LoadArray( - "cButtonSlots", ARRAY_COUNT(gSaveContext.childEquips.cButtonSlots), [](size_t i) { + }); + SaveManager::Instance->LoadArray("cButtonSlots", ARRAY_COUNT(gSaveContext.childEquips.cButtonSlots), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.childEquips.cButtonSlots[i], static_cast(SLOT_NONE)); - }); + }); SaveManager::Instance->LoadData("equipment", gSaveContext.childEquips.equipment); }); SaveManager::Instance->LoadStruct("adultEquips", []() { - SaveManager::Instance->LoadArray( - "buttonItems", ARRAY_COUNT(gSaveContext.adultEquips.buttonItems), [](size_t i) { + SaveManager::Instance->LoadArray("buttonItems", ARRAY_COUNT(gSaveContext.adultEquips.buttonItems), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.adultEquips.buttonItems[i], static_cast(ITEM_NONE)); - }); - SaveManager::Instance->LoadArray( - "cButtonSlots", ARRAY_COUNT(gSaveContext.adultEquips.cButtonSlots), [](size_t i) { + }); + SaveManager::Instance->LoadArray("cButtonSlots", ARRAY_COUNT(gSaveContext.adultEquips.cButtonSlots), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.adultEquips.cButtonSlots[i], static_cast(SLOT_NONE)); - }); + }); SaveManager::Instance->LoadData("equipment", gSaveContext.adultEquips.equipment); }); SaveManager::Instance->LoadData("unk_54", gSaveContext.unk_54); @@ -1108,9 +1098,9 @@ void SaveManager::LoadBaseVersion2() { SaveManager::Instance->LoadData("equipment", gSaveContext.inventory.equipment); SaveManager::Instance->LoadData("upgrades", gSaveContext.inventory.upgrades); SaveManager::Instance->LoadData("questItems", gSaveContext.inventory.questItems); - SaveManager::Instance->LoadArray( - "dungeonItems", ARRAY_COUNT(gSaveContext.inventory.dungeonItems), - [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.inventory.dungeonItems[i]); }); + SaveManager::Instance->LoadArray("dungeonItems", ARRAY_COUNT(gSaveContext.inventory.dungeonItems), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.inventory.dungeonItems[i]); + }); SaveManager::Instance->LoadArray("dungeonKeys", ARRAY_COUNT(gSaveContext.inventory.dungeonKeys), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.inventory.dungeonKeys[i]); }); @@ -1131,12 +1121,12 @@ void SaveManager::LoadBaseVersion2() { SaveManager::Instance->LoadArray("counts", ARRAY_COUNT(gSaveContext.sohStats.count), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.sohStats.count[i]); }); - SaveManager::Instance->LoadArray( - "scenesDiscovered", ARRAY_COUNT(gSaveContext.sohStats.scenesDiscovered), - [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.sohStats.scenesDiscovered[i]); }); - SaveManager::Instance->LoadArray( - "entrancesDiscovered", ARRAY_COUNT(gSaveContext.sohStats.entrancesDiscovered), - [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.sohStats.entrancesDiscovered[i]); }); + SaveManager::Instance->LoadArray("scenesDiscovered", ARRAY_COUNT(gSaveContext.sohStats.scenesDiscovered), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.sohStats.scenesDiscovered[i]); + }); + SaveManager::Instance->LoadArray("entrancesDiscovered", ARRAY_COUNT(gSaveContext.sohStats.entrancesDiscovered), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.sohStats.entrancesDiscovered[i]); + }); }); SaveManager::Instance->LoadArray("sceneFlags", ARRAY_COUNT(gSaveContext.sceneFlags), [](size_t i) { SaveManager::Instance->LoadStruct("", [&i]() { @@ -1163,17 +1153,21 @@ void SaveManager::LoadBaseVersion2() { SaveManager::Instance->LoadData("tempSwchFlags", gSaveContext.fw.tempSwchFlags); SaveManager::Instance->LoadData("tempCollectFlags", gSaveContext.fw.tempCollectFlags); }); - SaveManager::Instance->LoadArray("gsFlags", ARRAY_COUNT(gSaveContext.gsFlags), - [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.gsFlags[i]); }); - SaveManager::Instance->LoadArray("highScores", ARRAY_COUNT(gSaveContext.highScores), - [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.highScores[i]); }); + SaveManager::Instance->LoadArray("gsFlags", ARRAY_COUNT(gSaveContext.gsFlags), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.gsFlags[i]); + }); + SaveManager::Instance->LoadArray("highScores", ARRAY_COUNT(gSaveContext.highScores), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.highScores[i]); + }); SaveManager::Instance->LoadArray("eventChkInf", ARRAY_COUNT(gSaveContext.eventChkInf), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.eventChkInf[i]); }); - SaveManager::Instance->LoadArray("itemGetInf", ARRAY_COUNT(gSaveContext.itemGetInf), - [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.itemGetInf[i]); }); - SaveManager::Instance->LoadArray("infTable", ARRAY_COUNT(gSaveContext.infTable), - [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.infTable[i]); }); + SaveManager::Instance->LoadArray("itemGetInf", ARRAY_COUNT(gSaveContext.itemGetInf), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.itemGetInf[i]); + }); + SaveManager::Instance->LoadArray("infTable", ARRAY_COUNT(gSaveContext.infTable), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.infTable[i]); + }); SaveManager::Instance->LoadData("worldMapAreaData", gSaveContext.worldMapAreaData); SaveManager::Instance->LoadData("scarecrowCustomSongSet", gSaveContext.scarecrowLongSongSet); SaveManager::Instance->LoadArray("scarecrowCustomSong", ARRAY_COUNT(gSaveContext.scarecrowLongSong), [](size_t i) { @@ -1252,8 +1246,9 @@ void SaveManager::LoadBaseVersion3() { SaveManager::Instance->LoadData("totalDays", gSaveContext.totalDays); SaveManager::Instance->LoadData("bgsDayCount", gSaveContext.bgsDayCount); SaveManager::Instance->LoadData("deaths", gSaveContext.deaths); - SaveManager::Instance->LoadArray("playerName", ARRAY_COUNT(gSaveContext.playerName), - [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.playerName[i]); }); + SaveManager::Instance->LoadArray("playerName", ARRAY_COUNT(gSaveContext.playerName), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.playerName[i]); + }); SaveManager::Instance->LoadData("n64ddFlag", gSaveContext.n64ddFlag); SaveManager::Instance->LoadData("healthCapacity", gSaveContext.healthCapacity); SaveManager::Instance->LoadData("health", gSaveContext.health); @@ -1268,29 +1263,25 @@ void SaveManager::LoadBaseVersion3() { SaveManager::Instance->LoadData("bgsFlag", gSaveContext.bgsFlag); SaveManager::Instance->LoadData("ocarinaGameRoundNum", gSaveContext.ocarinaGameRoundNum); SaveManager::Instance->LoadStruct("childEquips", []() { - SaveManager::Instance->LoadArray( - "buttonItems", ARRAY_COUNT(gSaveContext.childEquips.buttonItems), [](size_t i) { + SaveManager::Instance->LoadArray("buttonItems", ARRAY_COUNT(gSaveContext.childEquips.buttonItems), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.childEquips.buttonItems[i], static_cast(ITEM_NONE)); - }); - SaveManager::Instance->LoadArray( - "cButtonSlots", ARRAY_COUNT(gSaveContext.childEquips.cButtonSlots), [](size_t i) { + }); + SaveManager::Instance->LoadArray("cButtonSlots", ARRAY_COUNT(gSaveContext.childEquips.cButtonSlots), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.childEquips.cButtonSlots[i], static_cast(SLOT_NONE)); - }); + }); SaveManager::Instance->LoadData("equipment", gSaveContext.childEquips.equipment); }); SaveManager::Instance->LoadStruct("adultEquips", []() { - SaveManager::Instance->LoadArray( - "buttonItems", ARRAY_COUNT(gSaveContext.adultEquips.buttonItems), [](size_t i) { + SaveManager::Instance->LoadArray("buttonItems", ARRAY_COUNT(gSaveContext.adultEquips.buttonItems), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.adultEquips.buttonItems[i], static_cast(ITEM_NONE)); - }); - SaveManager::Instance->LoadArray( - "cButtonSlots", ARRAY_COUNT(gSaveContext.adultEquips.cButtonSlots), [](size_t i) { + }); + SaveManager::Instance->LoadArray("cButtonSlots", ARRAY_COUNT(gSaveContext.adultEquips.cButtonSlots), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.adultEquips.cButtonSlots[i], static_cast(SLOT_NONE)); - }); + }); SaveManager::Instance->LoadData("equipment", gSaveContext.adultEquips.equipment); }); SaveManager::Instance->LoadData("unk_54", gSaveContext.unk_54); @@ -1314,9 +1305,9 @@ void SaveManager::LoadBaseVersion3() { SaveManager::Instance->LoadData("equipment", gSaveContext.inventory.equipment); SaveManager::Instance->LoadData("upgrades", gSaveContext.inventory.upgrades); SaveManager::Instance->LoadData("questItems", gSaveContext.inventory.questItems); - SaveManager::Instance->LoadArray( - "dungeonItems", ARRAY_COUNT(gSaveContext.inventory.dungeonItems), - [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.inventory.dungeonItems[i]); }); + SaveManager::Instance->LoadArray("dungeonItems", ARRAY_COUNT(gSaveContext.inventory.dungeonItems),[](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.inventory.dungeonItems[i]); + }); SaveManager::Instance->LoadArray("dungeonKeys", ARRAY_COUNT(gSaveContext.inventory.dungeonKeys), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.inventory.dungeonKeys[i]); }); @@ -1340,32 +1331,31 @@ void SaveManager::LoadBaseVersion3() { }); SaveManager::Instance->LoadData("playTimer", gSaveContext.sohStats.playTimer); SaveManager::Instance->LoadData("pauseTimer", gSaveContext.sohStats.pauseTimer); - SaveManager::Instance->LoadArray( - "itemTimestamps", ARRAY_COUNT(gSaveContext.sohStats.itemTimestamp), - [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.sohStats.itemTimestamp[i]); }); - SaveManager::Instance->LoadArray( - "sceneTimestamps", ARRAY_COUNT(gSaveContext.sohStats.sceneTimestamps), [](size_t i) { - SaveManager::Instance->LoadStruct("", [&i]() { - SaveManager::Instance->LoadData("scene", gSaveContext.sohStats.sceneTimestamps[i].scene); - SaveManager::Instance->LoadData("room", gSaveContext.sohStats.sceneTimestamps[i].room); - SaveManager::Instance->LoadData("sceneTime", gSaveContext.sohStats.sceneTimestamps[i].sceneTime); - SaveManager::Instance->LoadData("roomTime", gSaveContext.sohStats.sceneTimestamps[i].roomTime); - SaveManager::Instance->LoadData("isRoom", gSaveContext.sohStats.sceneTimestamps[i].isRoom); - }); + SaveManager::Instance->LoadArray("itemTimestamps", ARRAY_COUNT(gSaveContext.sohStats.itemTimestamp), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.sohStats.itemTimestamp[i]); + }); + SaveManager::Instance->LoadArray("sceneTimestamps", ARRAY_COUNT(gSaveContext.sohStats.sceneTimestamps), [](size_t i) { + SaveManager::Instance->LoadStruct("", [&i]() { + SaveManager::Instance->LoadData("scene", gSaveContext.sohStats.sceneTimestamps[i].scene); + SaveManager::Instance->LoadData("room", gSaveContext.sohStats.sceneTimestamps[i].room); + SaveManager::Instance->LoadData("sceneTime", gSaveContext.sohStats.sceneTimestamps[i].sceneTime); + SaveManager::Instance->LoadData("roomTime", gSaveContext.sohStats.sceneTimestamps[i].roomTime); + SaveManager::Instance->LoadData("isRoom", gSaveContext.sohStats.sceneTimestamps[i].isRoom); }); + }); SaveManager::Instance->LoadData("tsIdx", gSaveContext.sohStats.tsIdx); SaveManager::Instance->LoadArray("counts", ARRAY_COUNT(gSaveContext.sohStats.count), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.sohStats.count[i]); }); - SaveManager::Instance->LoadArray( - "scenesDiscovered", ARRAY_COUNT(gSaveContext.sohStats.scenesDiscovered), - [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.sohStats.scenesDiscovered[i]); }); - SaveManager::Instance->LoadArray( - "entrancesDiscovered", ARRAY_COUNT(gSaveContext.sohStats.entrancesDiscovered), - [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.sohStats.entrancesDiscovered[i]); }); - SaveManager::Instance->LoadArray( - "locationsSkipped", ARRAY_COUNT(gSaveContext.sohStats.locationsSkipped), - [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.sohStats.locationsSkipped[i]); }); + SaveManager::Instance->LoadArray("scenesDiscovered", ARRAY_COUNT(gSaveContext.sohStats.scenesDiscovered), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.sohStats.scenesDiscovered[i]); + }); + SaveManager::Instance->LoadArray("entrancesDiscovered", ARRAY_COUNT(gSaveContext.sohStats.entrancesDiscovered),[](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.sohStats.entrancesDiscovered[i]); + }); + SaveManager::Instance->LoadArray("locationsSkipped", ARRAY_COUNT(gSaveContext.sohStats.locationsSkipped), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.sohStats.locationsSkipped[i]); + }); }); SaveManager::Instance->LoadArray("sceneFlags", ARRAY_COUNT(gSaveContext.sceneFlags), [](size_t i) { SaveManager::Instance->LoadStruct("", [&i]() { @@ -1392,17 +1382,21 @@ void SaveManager::LoadBaseVersion3() { SaveManager::Instance->LoadData("tempSwchFlags", gSaveContext.fw.tempSwchFlags); SaveManager::Instance->LoadData("tempCollectFlags", gSaveContext.fw.tempCollectFlags); }); - SaveManager::Instance->LoadArray("gsFlags", ARRAY_COUNT(gSaveContext.gsFlags), - [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.gsFlags[i]); }); - SaveManager::Instance->LoadArray("highScores", ARRAY_COUNT(gSaveContext.highScores), - [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.highScores[i]); }); + SaveManager::Instance->LoadArray("gsFlags", ARRAY_COUNT(gSaveContext.gsFlags), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.gsFlags[i]); + }); + SaveManager::Instance->LoadArray("highScores", ARRAY_COUNT(gSaveContext.highScores), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.highScores[i]); + }); SaveManager::Instance->LoadArray("eventChkInf", ARRAY_COUNT(gSaveContext.eventChkInf), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.eventChkInf[i]); }); - SaveManager::Instance->LoadArray("itemGetInf", ARRAY_COUNT(gSaveContext.itemGetInf), - [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.itemGetInf[i]); }); - SaveManager::Instance->LoadArray("infTable", ARRAY_COUNT(gSaveContext.infTable), - [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.infTable[i]); }); + SaveManager::Instance->LoadArray("itemGetInf", ARRAY_COUNT(gSaveContext.itemGetInf), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.itemGetInf[i]); + }); + SaveManager::Instance->LoadArray("infTable", ARRAY_COUNT(gSaveContext.infTable), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.infTable[i]); + }); SaveManager::Instance->LoadData("worldMapAreaData", gSaveContext.worldMapAreaData); SaveManager::Instance->LoadData("scarecrowLongSongSet", gSaveContext.scarecrowLongSongSet); SaveManager::Instance->LoadArray("scarecrowLongSong", ARRAY_COUNT(gSaveContext.scarecrowLongSong), [](size_t i) { @@ -1468,8 +1462,9 @@ void SaveManager::LoadBaseVersion4() { SaveManager::Instance->LoadData("totalDays", gSaveContext.totalDays); SaveManager::Instance->LoadData("bgsDayCount", gSaveContext.bgsDayCount); SaveManager::Instance->LoadData("deaths", gSaveContext.deaths); - SaveManager::Instance->LoadArray("playerName", ARRAY_COUNT(gSaveContext.playerName), - [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.playerName[i]); }); + SaveManager::Instance->LoadArray("playerName", ARRAY_COUNT(gSaveContext.playerName), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.playerName[i]); + }); SaveManager::Instance->LoadData("n64ddFlag", gSaveContext.n64ddFlag); SaveManager::Instance->LoadData("healthCapacity", gSaveContext.healthCapacity); SaveManager::Instance->LoadData("health", gSaveContext.health); @@ -1484,29 +1479,25 @@ void SaveManager::LoadBaseVersion4() { SaveManager::Instance->LoadData("bgsFlag", gSaveContext.bgsFlag); SaveManager::Instance->LoadData("ocarinaGameRoundNum", gSaveContext.ocarinaGameRoundNum); SaveManager::Instance->LoadStruct("childEquips", []() { - SaveManager::Instance->LoadArray( - "buttonItems", ARRAY_COUNT(gSaveContext.childEquips.buttonItems), [](size_t i) { + SaveManager::Instance->LoadArray("buttonItems", ARRAY_COUNT(gSaveContext.childEquips.buttonItems), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.childEquips.buttonItems[i], static_cast(ITEM_NONE)); - }); - SaveManager::Instance->LoadArray( - "cButtonSlots", ARRAY_COUNT(gSaveContext.childEquips.cButtonSlots), [](size_t i) { + }); + SaveManager::Instance->LoadArray("cButtonSlots", ARRAY_COUNT(gSaveContext.childEquips.cButtonSlots), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.childEquips.cButtonSlots[i], static_cast(SLOT_NONE)); - }); + }); SaveManager::Instance->LoadData("equipment", gSaveContext.childEquips.equipment); }); SaveManager::Instance->LoadStruct("adultEquips", []() { - SaveManager::Instance->LoadArray( - "buttonItems", ARRAY_COUNT(gSaveContext.adultEquips.buttonItems), [](size_t i) { + SaveManager::Instance->LoadArray("buttonItems", ARRAY_COUNT(gSaveContext.adultEquips.buttonItems), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.adultEquips.buttonItems[i], static_cast(ITEM_NONE)); - }); - SaveManager::Instance->LoadArray( - "cButtonSlots", ARRAY_COUNT(gSaveContext.adultEquips.cButtonSlots), [](size_t i) { + }); + SaveManager::Instance->LoadArray("cButtonSlots", ARRAY_COUNT(gSaveContext.adultEquips.cButtonSlots), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.adultEquips.cButtonSlots[i], static_cast(SLOT_NONE)); - }); + }); SaveManager::Instance->LoadData("equipment", gSaveContext.adultEquips.equipment); }); SaveManager::Instance->LoadData("unk_54", gSaveContext.unk_54); @@ -1530,9 +1521,9 @@ void SaveManager::LoadBaseVersion4() { SaveManager::Instance->LoadData("equipment", gSaveContext.inventory.equipment); SaveManager::Instance->LoadData("upgrades", gSaveContext.inventory.upgrades); SaveManager::Instance->LoadData("questItems", gSaveContext.inventory.questItems); - SaveManager::Instance->LoadArray( - "dungeonItems", ARRAY_COUNT(gSaveContext.inventory.dungeonItems), - [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.inventory.dungeonItems[i]); }); + SaveManager::Instance->LoadArray("dungeonItems", ARRAY_COUNT(gSaveContext.inventory.dungeonItems),[](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.inventory.dungeonItems[i]); + }); SaveManager::Instance->LoadArray("dungeonKeys", ARRAY_COUNT(gSaveContext.inventory.dungeonKeys), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.inventory.dungeonKeys[i]); }); @@ -1564,17 +1555,21 @@ void SaveManager::LoadBaseVersion4() { SaveManager::Instance->LoadData("tempSwchFlags", gSaveContext.fw.tempSwchFlags); SaveManager::Instance->LoadData("tempCollectFlags", gSaveContext.fw.tempCollectFlags); }); - SaveManager::Instance->LoadArray("gsFlags", ARRAY_COUNT(gSaveContext.gsFlags), - [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.gsFlags[i]); }); - SaveManager::Instance->LoadArray("highScores", ARRAY_COUNT(gSaveContext.highScores), - [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.highScores[i]); }); + SaveManager::Instance->LoadArray("gsFlags", ARRAY_COUNT(gSaveContext.gsFlags), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.gsFlags[i]); + }); + SaveManager::Instance->LoadArray("highScores", ARRAY_COUNT(gSaveContext.highScores), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.highScores[i]); + }); SaveManager::Instance->LoadArray("eventChkInf", ARRAY_COUNT(gSaveContext.eventChkInf), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.eventChkInf[i]); }); - SaveManager::Instance->LoadArray("itemGetInf", ARRAY_COUNT(gSaveContext.itemGetInf), - [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.itemGetInf[i]); }); - SaveManager::Instance->LoadArray("infTable", ARRAY_COUNT(gSaveContext.infTable), - [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.infTable[i]); }); + SaveManager::Instance->LoadArray("itemGetInf", ARRAY_COUNT(gSaveContext.itemGetInf), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.itemGetInf[i]); + }); + SaveManager::Instance->LoadArray("infTable", ARRAY_COUNT(gSaveContext.infTable), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.infTable[i]); + }); SaveManager::Instance->LoadData("worldMapAreaData", gSaveContext.worldMapAreaData); SaveManager::Instance->LoadData("scarecrowLongSongSet", gSaveContext.scarecrowLongSongSet); SaveManager::Instance->LoadArray("scarecrowLongSong", ARRAY_COUNT(gSaveContext.scarecrowLongSong), [](size_t i) { From b5740bc878366d673120fa2bf5d189738868c670 Mon Sep 17 00:00:00 2001 From: Malkierian Date: Sat, 13 May 2023 18:35:27 -0700 Subject: [PATCH 11/17] v2 --- soh/soh/Enhancements/gameplaystats.cpp | 6 +-- soh/soh/SaveManager.cpp | 52 +++++++++++++------------- 2 files changed, 27 insertions(+), 31 deletions(-) diff --git a/soh/soh/Enhancements/gameplaystats.cpp b/soh/soh/Enhancements/gameplaystats.cpp index 0e873a705..99d61ff50 100644 --- a/soh/soh/Enhancements/gameplaystats.cpp +++ b/soh/soh/Enhancements/gameplaystats.cpp @@ -182,8 +182,7 @@ void DisplayTimeHHMMSS(uint32_t timeInTenthsOfSeconds, std::string text, ImVec4 void LoadStatsVersion1() { std::string buildVersion; SaveManager::Instance->LoadData("buildVersion", buildVersion); - strncpy(gSaveContext.sohStats.buildVersion, buildVersion.c_str(), - ARRAY_COUNT(gSaveContext.sohStats.buildVersion) - 1); + strncpy(gSaveContext.sohStats.buildVersion, buildVersion.c_str(), ARRAY_COUNT(gSaveContext.sohStats.buildVersion) - 1); gSaveContext.sohStats.buildVersion[ARRAY_COUNT(gSaveContext.sohStats.buildVersion) - 1] = 0; SaveManager::Instance->LoadData("buildVersionMajor", gSaveContext.sohStats.buildVersionMajor); SaveManager::Instance->LoadData("buildVersionMinor", gSaveContext.sohStats.buildVersionMinor); @@ -236,8 +235,7 @@ void SaveStats(SaveContext* saveContext, const std::string& subSection) { if (subSection == "all") { std::string buildVersion; SaveManager::Instance->LoadData("buildVersion", buildVersion); - strncpy(gSaveContext.sohStats.buildVersion, buildVersion.c_str(), - ARRAY_COUNT(gSaveContext.sohStats.buildVersion) - 1); + strncpy(gSaveContext.sohStats.buildVersion, buildVersion.c_str(), ARRAY_COUNT(gSaveContext.sohStats.buildVersion) - 1); gSaveContext.sohStats.buildVersion[ARRAY_COUNT(gSaveContext.sohStats.buildVersion) - 1] = 0; SaveManager::Instance->LoadData("buildVersionMajor", gSaveContext.sohStats.buildVersionMajor); SaveManager::Instance->LoadData("buildVersionMinor", gSaveContext.sohStats.buildVersionMinor); diff --git a/soh/soh/SaveManager.cpp b/soh/soh/SaveManager.cpp index 4f15b85f0..008f3b79f 100644 --- a/soh/soh/SaveManager.cpp +++ b/soh/soh/SaveManager.cpp @@ -19,7 +19,7 @@ extern "C" SaveContext gSaveContext; void SaveManager::WriteSaveFile(const std::filesystem::path& savePath, const uintptr_t addr, void* dramAddr, - const size_t size) { + const size_t size) { std::ofstream saveFile = std::ofstream(savePath, std::fstream::in | std::fstream::out | std::fstream::binary); saveFile.seekp(addr); saveFile.write((char*)dramAddr, size); @@ -193,7 +193,7 @@ void SaveManager::LoadRandomizerVersion2() { }); SaveManager::Instance->LoadArray("seed", ARRAY_COUNT(gSaveContext.seedIcons), [&](size_t i) { - SaveManager::Instance->LoadData("", gSaveContext.seedIcons[i]); + SaveManager::Instance->LoadData("", gSaveContext.seedIcons[i]); }); SaveManager::Instance->LoadArray("randoSettings", RSK_MAX, [&](size_t i) { @@ -280,7 +280,7 @@ void SaveManager::LoadRandomizerVersion2() { void SaveManager::SaveRandomizer(SaveContext* saveContext, const std::string& subString) { - if (!saveContext->n64ddFlag) return; + if(!saveContext->n64ddFlag) return; SaveManager::Instance->SaveArray("itemLocations", RC_MAX, [&](size_t i) { SaveManager::Instance->SaveStruct("", [&]() { @@ -335,7 +335,7 @@ void SaveManager::SaveRandomizer(SaveContext* saveContext, const std::string& su std::shared_ptr randomizer = OTRGlobals::Instance->gRandomizer; std::vector> merchantPrices; - for (const auto& [ check, price ] : randomizer->merchantPrices) { + for (const auto & [ check, price ] : randomizer->merchantPrices) { merchantPrices.push_back(std::make_pair(check, price)); } @@ -364,8 +364,7 @@ void SaveManager::Init() { auto sOldSavePath = LUS::Context::GetPathRelativeToAppDirectory("oot_save.sav"); auto sOldBackupSavePath = LUS::Context::GetPathRelativeToAppDirectory("oot_save.bak"); LUS::RegisterHook([this]() { ThreadPoolWait(); }); - GameInteractor::Instance->RegisterGameHook( - [this](uint32_t fileNum) { ThreadPoolWait(); }); + GameInteractor::Instance->RegisterGameHook([this](uint32_t fileNum) { ThreadPoolWait(); }); // If the save directory does not exist, create it if (!std::filesystem::exists(sSavePath)) { @@ -436,8 +435,8 @@ void SaveManager::InitMeta(int fileNum) { // If the file is marked as a Master Quest file or if we're randomized and have at least one master quest dungeon, // we need the mq otr. fileMetaInfo[fileNum].requiresMasterQuest = gSaveContext.isMasterQuest > 0 || (gSaveContext.n64ddFlag && gSaveContext.mqDungeonCount > 0); - // If the file is not marked as Master Quest, it could still theoretically be a rando save with all 12 MQ dungeons, - // in which case we don't actually require a vanilla OTR. + // If the file is not marked as Master Quest, it could still theoretically be a rando save with all 12 MQ dungeons, in which case + // we don't actually require a vanilla OTR. fileMetaInfo[fileNum].requiresOriginal = !gSaveContext.isMasterQuest && (!gSaveContext.n64ddFlag || gSaveContext.mqDungeonCount < 12); fileMetaInfo[fileNum].buildVersionMajor = gSaveContext.sohStats.buildVersionMajor; @@ -838,7 +837,7 @@ bool SaveManager::SaveFile_Exist(int fileNum) { SPDLOG_INFO("File[{}] - {}", fileNum, exists ? "exists" : "does not exist"); return exists; } - catch (std::filesystem::filesystem_error const& ex) { + catch(std::filesystem::filesystem_error const& ex) { SPDLOG_ERROR("Filesystem error"); return false; } @@ -958,8 +957,9 @@ void SaveManager::LoadBaseVersion1() { SaveManager::Instance->LoadData("equipment", gSaveContext.inventory.equipment); SaveManager::Instance->LoadData("upgrades", gSaveContext.inventory.upgrades); SaveManager::Instance->LoadData("questItems", gSaveContext.inventory.questItems); - SaveManager::Instance->LoadArray("dungeonItems", ARRAY_COUNT(gSaveContext.inventory.dungeonItems), - [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.inventory.dungeonItems[i]); }); + SaveManager::Instance->LoadArray("dungeonItems", ARRAY_COUNT(gSaveContext.inventory.dungeonItems), [](size_t i) { + SaveManager::Instance->LoadData("", gSaveContext.inventory.dungeonItems[i]); + }); SaveManager::Instance->LoadArray("dungeonKeys", ARRAY_COUNT(gSaveContext.inventory.dungeonKeys), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.inventory.dungeonKeys[i]); }); @@ -1221,18 +1221,17 @@ void SaveManager::LoadBaseVersion2() { if (!gSaveContext.scarecrowLongSongSet) { SaveManager::Instance->LoadData("scarecrowLongSongSet", gSaveContext.scarecrowLongSongSet); if (gSaveContext.scarecrowLongSongSet) { - SaveManager::Instance->LoadArray( - "scarecrowLongSong", ARRAY_COUNT(gSaveContext.scarecrowLongSong), [](size_t i) { - SaveManager::Instance->LoadStruct("", [&i]() { - SaveManager::Instance->LoadData("noteIdx", gSaveContext.scarecrowLongSong[i].noteIdx); - SaveManager::Instance->LoadData("unk_01", gSaveContext.scarecrowLongSong[i].unk_01); - SaveManager::Instance->LoadData("unk_02", gSaveContext.scarecrowLongSong[i].unk_02); - SaveManager::Instance->LoadData("volume", gSaveContext.scarecrowLongSong[i].volume); - SaveManager::Instance->LoadData("vibrato", gSaveContext.scarecrowLongSong[i].vibrato); - SaveManager::Instance->LoadData("tone", gSaveContext.scarecrowLongSong[i].tone); - SaveManager::Instance->LoadData("semitone", gSaveContext.scarecrowLongSong[i].semitone); - }); + SaveManager::Instance->LoadArray("scarecrowLongSong", ARRAY_COUNT(gSaveContext.scarecrowLongSong), [](size_t i) { + SaveManager::Instance->LoadStruct("", [&i]() { + SaveManager::Instance->LoadData("noteIdx", gSaveContext.scarecrowLongSong[i].noteIdx); + SaveManager::Instance->LoadData("unk_01", gSaveContext.scarecrowLongSong[i].unk_01); + SaveManager::Instance->LoadData("unk_02", gSaveContext.scarecrowLongSong[i].unk_02); + SaveManager::Instance->LoadData("volume", gSaveContext.scarecrowLongSong[i].volume); + SaveManager::Instance->LoadData("vibrato", gSaveContext.scarecrowLongSong[i].vibrato); + SaveManager::Instance->LoadData("tone", gSaveContext.scarecrowLongSong[i].tone); + SaveManager::Instance->LoadData("semitone", gSaveContext.scarecrowLongSong[i].semitone); }); + }); } } } @@ -1305,7 +1304,7 @@ void SaveManager::LoadBaseVersion3() { SaveManager::Instance->LoadData("equipment", gSaveContext.inventory.equipment); SaveManager::Instance->LoadData("upgrades", gSaveContext.inventory.upgrades); SaveManager::Instance->LoadData("questItems", gSaveContext.inventory.questItems); - SaveManager::Instance->LoadArray("dungeonItems", ARRAY_COUNT(gSaveContext.inventory.dungeonItems),[](size_t i) { + SaveManager::Instance->LoadArray("dungeonItems", ARRAY_COUNT(gSaveContext.inventory.dungeonItems), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.inventory.dungeonItems[i]); }); SaveManager::Instance->LoadArray("dungeonKeys", ARRAY_COUNT(gSaveContext.inventory.dungeonKeys), [](size_t i) { @@ -1317,8 +1316,7 @@ void SaveManager::LoadBaseVersion3() { SaveManager::Instance->LoadStruct("sohStats", []() { std::string buildVersion; SaveManager::Instance->LoadData("buildVersion", buildVersion); - strncpy(gSaveContext.sohStats.buildVersion, buildVersion.c_str(), - ARRAY_COUNT(gSaveContext.sohStats.buildVersion) - 1); + strncpy(gSaveContext.sohStats.buildVersion, buildVersion.c_str(), ARRAY_COUNT(gSaveContext.sohStats.buildVersion) - 1); gSaveContext.sohStats.buildVersion[ARRAY_COUNT(gSaveContext.sohStats.buildVersion) - 1] = 0; SaveManager::Instance->LoadData("buildVersionMajor", gSaveContext.sohStats.buildVersionMajor); SaveManager::Instance->LoadData("buildVersionMinor", gSaveContext.sohStats.buildVersionMinor); @@ -1350,7 +1348,7 @@ void SaveManager::LoadBaseVersion3() { SaveManager::Instance->LoadArray("scenesDiscovered", ARRAY_COUNT(gSaveContext.sohStats.scenesDiscovered), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.sohStats.scenesDiscovered[i]); }); - SaveManager::Instance->LoadArray("entrancesDiscovered", ARRAY_COUNT(gSaveContext.sohStats.entrancesDiscovered),[](size_t i) { + SaveManager::Instance->LoadArray("entrancesDiscovered", ARRAY_COUNT(gSaveContext.sohStats.entrancesDiscovered), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.sohStats.entrancesDiscovered[i]); }); SaveManager::Instance->LoadArray("locationsSkipped", ARRAY_COUNT(gSaveContext.sohStats.locationsSkipped), [](size_t i) { @@ -1521,7 +1519,7 @@ void SaveManager::LoadBaseVersion4() { SaveManager::Instance->LoadData("equipment", gSaveContext.inventory.equipment); SaveManager::Instance->LoadData("upgrades", gSaveContext.inventory.upgrades); SaveManager::Instance->LoadData("questItems", gSaveContext.inventory.questItems); - SaveManager::Instance->LoadArray("dungeonItems", ARRAY_COUNT(gSaveContext.inventory.dungeonItems),[](size_t i) { + SaveManager::Instance->LoadArray("dungeonItems", ARRAY_COUNT(gSaveContext.inventory.dungeonItems), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.inventory.dungeonItems[i]); }); SaveManager::Instance->LoadArray("dungeonKeys", ARRAY_COUNT(gSaveContext.inventory.dungeonKeys), [](size_t i) { From 4bc0d7d60d393ed653c00c8c4c4f48f7848be398 Mon Sep 17 00:00:00 2001 From: Malkierian Date: Sat, 13 May 2023 18:41:10 -0700 Subject: [PATCH 12/17] v3 >:( --- soh/soh/SaveManager.cpp | 49 +++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/soh/soh/SaveManager.cpp b/soh/soh/SaveManager.cpp index 008f3b79f..60dcb8876 100644 --- a/soh/soh/SaveManager.cpp +++ b/soh/soh/SaveManager.cpp @@ -19,7 +19,7 @@ extern "C" SaveContext gSaveContext; void SaveManager::WriteSaveFile(const std::filesystem::path& savePath, const uintptr_t addr, void* dramAddr, - const size_t size) { + const size_t size) { std::ofstream saveFile = std::ofstream(savePath, std::fstream::in | std::fstream::out | std::fstream::binary); saveFile.seekp(addr); saveFile.write((char*)dramAddr, size); @@ -432,8 +432,7 @@ void SaveManager::InitMeta(int fileNum) { } fileMetaInfo[fileNum].randoSave = gSaveContext.n64ddFlag; - // If the file is marked as a Master Quest file or if we're randomized and have at least one master quest dungeon, - // we need the mq otr. + // If the file is marked as a Master Quest file or if we're randomized and have at least one master quest dungeon, we need the mq otr. fileMetaInfo[fileNum].requiresMasterQuest = gSaveContext.isMasterQuest > 0 || (gSaveContext.n64ddFlag && gSaveContext.mqDungeonCount > 0); // If the file is not marked as Master Quest, it could still theoretically be a rando save with all 12 MQ dungeons, in which case // we don't actually require a vanilla OTR. @@ -1650,21 +1649,21 @@ void SaveManager::SaveBase(SaveContext* saveContext, const std::string& subStrin SaveManager::Instance->SaveData("bgsFlag", saveContext->bgsFlag); SaveManager::Instance->SaveData("ocarinaGameRoundNum", saveContext->ocarinaGameRoundNum); SaveManager::Instance->SaveStruct("childEquips", [&]() { - SaveManager::Instance->SaveArray( - "buttonItems", ARRAY_COUNT(saveContext->childEquips.buttonItems), - [&](size_t i) { SaveManager::Instance->SaveData("", saveContext->childEquips.buttonItems[i]); }); - SaveManager::Instance->SaveArray( - "cButtonSlots", ARRAY_COUNT(saveContext->childEquips.cButtonSlots), - [&](size_t i) { SaveManager::Instance->SaveData("", saveContext->childEquips.cButtonSlots[i]); }); + SaveManager::Instance->SaveArray("buttonItems", ARRAY_COUNT(saveContext->childEquips.buttonItems), [&](size_t i) { + SaveManager::Instance->SaveData("", saveContext->childEquips.buttonItems[i]); + }); + SaveManager::Instance->SaveArray("cButtonSlots", ARRAY_COUNT(saveContext->childEquips.cButtonSlots), [&](size_t i) { + SaveManager::Instance->SaveData("", saveContext->childEquips.cButtonSlots[i]); + }); SaveManager::Instance->SaveData("equipment", saveContext->childEquips.equipment); }); SaveManager::Instance->SaveStruct("adultEquips", [&]() { - SaveManager::Instance->SaveArray( - "buttonItems", ARRAY_COUNT(saveContext->adultEquips.buttonItems), - [&](size_t i) { SaveManager::Instance->SaveData("", saveContext->adultEquips.buttonItems[i]); }); - SaveManager::Instance->SaveArray( - "cButtonSlots", ARRAY_COUNT(saveContext->adultEquips.cButtonSlots), - [&](size_t i) { SaveManager::Instance->SaveData("", saveContext->adultEquips.cButtonSlots[i]); }); + SaveManager::Instance->SaveArray("buttonItems", ARRAY_COUNT(saveContext->adultEquips.buttonItems), [&](size_t i) { + SaveManager::Instance->SaveData("", saveContext->adultEquips.buttonItems[i]); + }); + SaveManager::Instance->SaveArray("cButtonSlots", ARRAY_COUNT(saveContext->adultEquips.cButtonSlots), [&](size_t i) { + SaveManager::Instance->SaveData("", saveContext->adultEquips.cButtonSlots[i]); + }); SaveManager::Instance->SaveData("equipment", saveContext->adultEquips.equipment); }); SaveManager::Instance->SaveData("unk_54", saveContext->unk_54); @@ -1688,9 +1687,9 @@ void SaveManager::SaveBase(SaveContext* saveContext, const std::string& subStrin SaveManager::Instance->SaveData("equipment", saveContext->inventory.equipment); SaveManager::Instance->SaveData("upgrades", saveContext->inventory.upgrades); SaveManager::Instance->SaveData("questItems", saveContext->inventory.questItems); - SaveManager::Instance->SaveArray( - "dungeonItems", ARRAY_COUNT(saveContext->inventory.dungeonItems), - [&](size_t i) { SaveManager::Instance->SaveData("", saveContext->inventory.dungeonItems[i]); }); + SaveManager::Instance->SaveArray("dungeonItems", ARRAY_COUNT(saveContext->inventory.dungeonItems), [&](size_t i) { + SaveManager::Instance->SaveData("", saveContext->inventory.dungeonItems[i]); + }); SaveManager::Instance->SaveArray("dungeonKeys", ARRAY_COUNT(saveContext->inventory.dungeonKeys), [&](size_t i) { SaveManager::Instance->SaveData("", saveContext->inventory.dungeonKeys[i]); }); @@ -1722,8 +1721,9 @@ void SaveManager::SaveBase(SaveContext* saveContext, const std::string& subStrin SaveManager::Instance->SaveData("tempSwchFlags", saveContext->fw.tempSwchFlags); SaveManager::Instance->SaveData("tempCollectFlags", saveContext->fw.tempCollectFlags); }); - SaveManager::Instance->SaveArray("gsFlags", ARRAY_COUNT(saveContext->gsFlags), - [&](size_t i) { SaveManager::Instance->SaveData("", saveContext->gsFlags[i]); }); + SaveManager::Instance->SaveArray("gsFlags", ARRAY_COUNT(saveContext->gsFlags), [&](size_t i) { + SaveManager::Instance->SaveData("", saveContext->gsFlags[i]); + }); SaveManager::Instance->SaveArray("highScores", ARRAY_COUNT(saveContext->highScores), [&](size_t i) { SaveManager::Instance->SaveData("", saveContext->highScores[i]); }); @@ -1733,8 +1733,9 @@ void SaveManager::SaveBase(SaveContext* saveContext, const std::string& subStrin SaveManager::Instance->SaveArray("itemGetInf", ARRAY_COUNT(saveContext->itemGetInf), [&](size_t i) { SaveManager::Instance->SaveData("", saveContext->itemGetInf[i]); }); - SaveManager::Instance->SaveArray("infTable", ARRAY_COUNT(saveContext->infTable), - [&](size_t i) { SaveManager::Instance->SaveData("", saveContext->infTable[i]); }); + SaveManager::Instance->SaveArray("infTable", ARRAY_COUNT(saveContext->infTable), [&](size_t i) { + SaveManager::Instance->SaveData("", saveContext->infTable[i]); + }); SaveManager::Instance->SaveData("worldMapAreaData", saveContext->worldMapAreaData); SaveManager::Instance->SaveData("scarecrowLongSongSet", saveContext->scarecrowLongSongSet); SaveManager::Instance->SaveArray("scarecrowLongSong", ARRAY_COUNT(saveContext->scarecrowLongSong), [&](size_t i) { @@ -1830,8 +1831,8 @@ void SaveManager::LoadArray(const std::string& name, const size_t size, LoadArra for (; (currentJsonArrayContext != currentJsonContext->end()) && (i < size); i++, currentJsonArrayContext++) { func(i); } - // Handle remainer of items. Either this was data that was manually deleted, or a later version extended the size of - // the array. The later members will be default constructed. + // Handle remainer of items. Either this was data that was manually deleted, or a later version extended the size of the array. + // The later members will be default constructed. for (; i < size; i++) { func(i); } From 50fbe5d00c710dcffb816b53b3e06f9f682e4707 Mon Sep 17 00:00:00 2001 From: Malkierian Date: Mon, 15 May 2023 17:21:14 -0700 Subject: [PATCH 13/17] Modified sectional saving to utilize an integer ID for calling specific sections to cut down on string copying. Utilizes enum values for non-mod sections to allow for cross-project use of those IDs, and sets up `AddSaveFunction` to add mod sections after that using max value enum. --- soh/include/z64save.h | 9 ++ soh/soh/Enhancements/gameplaystats.cpp | 15 +- .../randomizer/randomizer_entrance.c | 6 +- soh/soh/SaveManager.cpp | 129 +++++++++--------- soh/soh/SaveManager.h | 42 +++--- 5 files changed, 114 insertions(+), 87 deletions(-) diff --git a/soh/include/z64save.h b/soh/include/z64save.h index a7e7ca652..97a8837fa 100644 --- a/soh/include/z64save.h +++ b/soh/include/z64save.h @@ -61,6 +61,15 @@ typedef struct { u8 isRoom; } SceneTimestamp; +typedef enum { // Pre-existing IDs for save sections in base code + SECTION_ID_BASE, + SECTION_ID_RANDOMIZER, + SECTION_ID_STATS, + SECTION_ID_ENTRANCES, + SECTION_ID_SCENES, + SECTION_ID_MAX +} SaveFuncIDs; + typedef struct { /* */ char buildVersion[50]; /* */ s16 buildVersionMajor; diff --git a/soh/soh/Enhancements/gameplaystats.cpp b/soh/soh/Enhancements/gameplaystats.cpp index 99d61ff50..b4b1c9732 100644 --- a/soh/soh/Enhancements/gameplaystats.cpp +++ b/soh/soh/Enhancements/gameplaystats.cpp @@ -231,8 +231,8 @@ void LoadStatsVersion1() { }); } -void SaveStats(SaveContext* saveContext, const std::string& subSection) { - if (subSection == "all") { +void SaveStats(SaveContext* saveContext, int sectionID) { + if (sectionID == SECTION_ID_BASE) { std::string buildVersion; SaveManager::Instance->LoadData("buildVersion", buildVersion); strncpy(gSaveContext.sohStats.buildVersion, buildVersion.c_str(), ARRAY_COUNT(gSaveContext.sohStats.buildVersion) - 1); @@ -268,12 +268,12 @@ void SaveStats(SaveContext* saveContext, const std::string& subSection) { SaveManager::Instance->LoadData("", gSaveContext.sohStats.locationsSkipped[i]); }); } - if (subSection == "entrances" || subSection == "all") { + if (sectionID == SECTION_ID_ENTRANCES || sectionID == SECTION_ID_BASE) { SaveManager::Instance->SaveArray("entrancesDiscovered", ARRAY_COUNT(saveContext->sohStats.entrancesDiscovered), [&](size_t i) { SaveManager::Instance->SaveData("", saveContext->sohStats.entrancesDiscovered[i]); }); } - if (subSection == "scenes" || subSection == "all") { + if (sectionID == SECTION_ID_SCENES || sectionID == SECTION_ID_BASE) { SaveManager::Instance->SaveArray("scenesDiscovered", ARRAY_COUNT(saveContext->sohStats.scenesDiscovered), [&](size_t i) { SaveManager::Instance->SaveData("", saveContext->sohStats.scenesDiscovered[i]); }); @@ -821,7 +821,10 @@ extern "C" void InitStatTracker() { SetupDisplayNames(); SetupDisplayColors(); SaveManager::Instance->AddLoadFunction("sohStats", 1, LoadStatsVersion1); - SaveManager::Instance->AddSaveFunction("sohStats", 1, SaveStats); + // Add main section save, no parent + SaveManager::Instance->AddSaveFunction("sohStats", 1, SaveStats, true, SECTION_PARENT_NONE); + // Add subsections, parent of "sohStats". Not sure how to do this without the redundant references to "SaveStats" + SaveManager::Instance->AddSaveFunction("entrances", 1, SaveStats, false, SECTION_ID_STATS); + SaveManager::Instance->AddSaveFunction("scenes", 1, SaveStats, false, SECTION_ID_STATS); SaveManager::Instance->AddInitFunction(InitStats); - SaveManager::Instance->RegisterGameSaveSection("sohStats"); } \ No newline at end of file diff --git a/soh/soh/Enhancements/randomizer/randomizer_entrance.c b/soh/soh/Enhancements/randomizer/randomizer_entrance.c index 26be88a24..2ccb83627 100644 --- a/soh/soh/Enhancements/randomizer/randomizer_entrance.c +++ b/soh/soh/Enhancements/randomizer/randomizer_entrance.c @@ -769,7 +769,8 @@ void Entrance_SetSceneDiscovered(u8 sceneNum) { u32 sceneBit = 1 << (sceneNum - (idx * bitsPerIndex)); gSaveContext.sohStats.scenesDiscovered[idx] |= sceneBit; } - Save_SaveSection("sohStats.scenes"); + // Save scenesDiscovered + Save_SaveSection(SECTION_ID_SCENES); } u8 Entrance_GetIsEntranceDiscovered(u16 entranceIndex) { @@ -802,5 +803,6 @@ void Entrance_SetEntranceDiscovered(u16 entranceIndex) { } } } - Save_SaveSection("sohStats.entrances"); + // Save entrancesDiscovered + Save_SaveSection(SECTION_ID_ENTRANCES); } diff --git a/soh/soh/SaveManager.cpp b/soh/soh/SaveManager.cpp index 60dcb8876..2f8c52759 100644 --- a/soh/soh/SaveManager.cpp +++ b/soh/soh/SaveManager.cpp @@ -17,6 +17,7 @@ #include extern "C" SaveContext gSaveContext; +using namespace std::string_literals; void SaveManager::WriteSaveFile(const std::filesystem::path& savePath, const uintptr_t addr, void* dramAddr, const size_t size) { @@ -46,17 +47,20 @@ std::filesystem::path SaveManager::GetFileName(int fileNum) { } SaveManager::SaveManager() { + coreSectionIDsByName["base"] = SECTION_ID_BASE; + coreSectionIDsByName["randomizer"] = SECTION_ID_RANDOMIZER; + coreSectionIDsByName["sohStats"] = SECTION_ID_STATS; + coreSectionIDsByName["entrances"] = SECTION_ID_ENTRANCES; + coreSectionIDsByName["scenes"] = SECTION_ID_SCENES; AddLoadFunction("base", 1, LoadBaseVersion1); AddLoadFunction("base", 2, LoadBaseVersion2); AddLoadFunction("base", 3, LoadBaseVersion3); AddLoadFunction("base", 4, LoadBaseVersion4); - AddSaveFunction("base", 4, SaveBase); - RegisterGameSaveSection("base"); + AddSaveFunction("base", 4, SaveBase, true, SECTION_PARENT_NONE); AddLoadFunction("randomizer", 1, LoadRandomizerVersion1); AddLoadFunction("randomizer", 2, LoadRandomizerVersion2); - AddSaveFunction("randomizer", 2, SaveRandomizer); - RegisterGameSaveSection("randomizer"); + AddSaveFunction("randomizer", 2, SaveRandomizer, true, SECTION_PARENT_NONE); AddInitFunction(InitFileImpl); @@ -86,20 +90,6 @@ SaveManager::SaveManager() { } } -// GameSaveSection functions affect the list of sections that save their data when a game save is triggered -void SaveManager::RegisterGameSaveSection(std::string section) { - if (std::find(gameSaveRegistry.begin(), gameSaveRegistry.end(), section) == gameSaveRegistry.end()) { - gameSaveRegistry.push_back(section); - } -} - -void SaveManager::UnregisterAutosaveSection(std::string section) { - auto find = std::find(gameSaveRegistry.begin(), gameSaveRegistry.end(), section); - if (find != gameSaveRegistry.end()) { - gameSaveRegistry.erase(find); - } -} - void SaveManager::LoadRandomizerVersion1() { for (int i = 0; i < ARRAY_COUNT(gSaveContext.itemLocations); i++) { SaveManager::Instance->LoadStruct("get" + std::to_string(i), [&]() { @@ -278,7 +268,7 @@ void SaveManager::LoadRandomizerVersion2() { }); } -void SaveManager::SaveRandomizer(SaveContext* saveContext, const std::string& subString) { +void SaveManager::SaveRandomizer(SaveContext* saveContext, int sectionID) { if(!saveContext->n64ddFlag) return; @@ -700,40 +690,42 @@ void SaveManager::InitFileDebug() { gSaveContext.sceneFlags[5].swch = 0x40000000; } -// Threaded SaveFile takes copy of gSaveContext for local unmodified storage -void SaveManager::SaveFileThreaded(int fileNum, SaveContext* saveContext, const std::string& sectionString) { +void SaveManager::SaveFileThreaded(int fileNum, SaveContext* saveContext, int sectionID) { + // Needed for first time save, hasn't changed in forever anyway saveBlock["version"] = 1; - size_t period = sectionString.find("."); - std::string section = sectionString; - std::string subsection = ""; - if (period != std::string::npos) { - subsection = sectionString.substr(period + 1, std::string::npos); - section = sectionString.substr(0, sectionString.length() - (subsection.length() + 1)); - } - if (sectionString == "all") { - for (auto& sectionHandler : sectionSaveHandlers) { - if (std::find(gameSaveRegistry.begin(), gameSaveRegistry.end(), sectionHandler.first) != gameSaveRegistry.end()) { - nlohmann::json& sectionBlock = saveBlock["sections"][sectionHandler.first]; - sectionBlock["version"] = sectionHandler.second.first; - // If any save file is loaded for medatata, or a spoiler log is loaded (not sure which at this point), there is still data in the "randomizer" section - // This clears the randomizer data block if and only if the section being called is "randomizer" and n64ddFlag is false. - if (sectionHandler.first == "randomizer" && !gSaveContext.n64ddFlag) { - sectionBlock["data"] = nlohmann::json::object(); - } - - currentJsonContext = §ionBlock["data"]; - sectionHandler.second.second(saveContext, "all"); + if (sectionID == SECTION_ID_BASE) { + for (auto& sectionHandlerPair : sectionSaveHandlers) { + auto& saveFuncInfo = sectionHandlerPair.second; + // Don't call SaveFuncs for sections that aren't tied to game save + if (!saveFuncInfo.saveWithBase) { + continue; } + nlohmann::json& sectionBlock = saveBlock["sections"][saveFuncInfo.name]; + sectionBlock["version"] = sectionHandlerPair.second.version; + // If any save file is loaded for medatata, or a spoiler log is loaded (not sure which at this point), there is still data in the "randomizer" section + // This clears the randomizer data block if and only if the section being called is "randomizer" and n64ddFlag is false. + if (sectionHandlerPair.second.name == "randomizer" && !gSaveContext.n64ddFlag) { + sectionBlock["data"] = nlohmann::json::object(); + continue; + } + + currentJsonContext = §ionBlock["data"]; + sectionHandlerPair.second.func(saveContext, sectionID); } - } else if (sectionSaveHandlers.contains(section)) { - SectionSaveHandler handler = sectionSaveHandlers.find(section)->second; - nlohmann::json& sectionBlock = saveBlock["sections"][section]; - sectionBlock["version"] = handler.first; - currentJsonContext = §ionBlock["data"]; - handler.second(saveContext, subsection); } else { - // save function for specified section does not exist. should this error? - return; + SaveFuncInfo svi = sectionSaveHandlers.find(sectionID)->second; + auto& sectionName = svi.name; + auto sectionVersion = svi.version; + // If section has a parentSection, it is a subsection. Load parentSection version and set sectionBlock to parent string + if (svi.parentSection != -1 && svi.parentSection < sectionIndex) { + auto parentSvi = sectionSaveHandlers.find(svi.parentSection)->second; + sectionName = parentSvi.name; + sectionVersion = parentSvi.version; + } + nlohmann::json& sectionBlock = saveBlock["sections"][sectionName]; + sectionBlock["version"] = sectionVersion; + currentJsonContext = §ionBlock["data"]; + svi.func(saveContext, sectionID); } #if defined(__SWITCH__) || defined(__WIIU__) @@ -751,18 +743,24 @@ void SaveManager::SaveFileThreaded(int fileNum, SaveContext* saveContext, const GameInteractor::Instance->ExecuteHooks(fileNum); } -void SaveManager::SaveSection(int fileNum, const std::string& sectionString) { +// SaveSection creates a copy of gSaveContext to prevent mid-save data modification, and passes its reference to SaveFileThreaded +void SaveManager::SaveSection(int fileNum, int sectionID) { if (fileNum == 0xFF) { return; } - // Can't think of any time the promise would be needed, so use push_task instead of submit + // Don't save a nonexistent section + if (sectionID >= sectionIndex) { + SPDLOG_ERROR("SaveSection: Section ID not registered."); + return; + } auto saveContext = new SaveContext; memcpy(saveContext, &gSaveContext, sizeof(gSaveContext)); - smThreadPool->push_task_back(&SaveManager::SaveFileThreaded, this, fileNum, saveContext, sectionString); + // Can't think of any time the promise would be needed, so use push_task instead of submit + smThreadPool->push_task_back(&SaveManager::SaveFileThreaded, this, fileNum, saveContext, sectionID); } void SaveManager::SaveFile(int fileNum) { - SaveSection(fileNum, "all"); + SaveSection(fileNum, SECTION_ID_BASE); } void SaveManager::SaveGlobal() { @@ -860,14 +858,21 @@ void SaveManager::AddLoadFunction(const std::string& name, int version, LoadFunc sectionLoadHandlers[name][version] = func; } -void SaveManager::AddSaveFunction(const std::string& name, int version, SaveFunc func) { - if (sectionSaveHandlers.contains(name)) { +void SaveManager::AddSaveFunction(const std::string& name, int version, SaveFunc func, bool saveWithBase, int parentSection = -1) { + if (sectionRegistry.contains(name)) { SPDLOG_ERROR("Adding save function for section that already has one: " + name); assert(false); return; } - - sectionSaveHandlers[name] = std::make_pair(version, func); + int index = sectionIndex; + if (coreSectionIDsByName.contains(name)) { + index = coreSectionIDsByName.find(name)->second; + } else { + sectionIndex++; + } + SaveFuncInfo sfi = { name, version, func, saveWithBase, parentSection }; + sectionSaveHandlers.emplace(index, sfi); + sectionRegistry.emplace(name); } void SaveManager::AddPostFunction(const std::string& name, PostFunc func) { @@ -1623,7 +1628,7 @@ void SaveManager::LoadBaseVersion4() { SaveManager::Instance->LoadData("dogParams", gSaveContext.dogParams); } -void SaveManager::SaveBase(SaveContext* saveContext, const std::string& subString) { +void SaveManager::SaveBase(SaveContext* saveContext, int sectionID) { SaveManager::Instance->SaveData("entranceIndex", saveContext->entranceIndex); SaveManager::Instance->SaveData("linkAge", saveContext->linkAge); SaveManager::Instance->SaveData("cutsceneIndex", saveContext->cutsceneIndex); @@ -2290,8 +2295,8 @@ extern "C" void Save_SaveFile(void) { SaveManager::Instance->SaveFile(gSaveContext.fileNum); } -extern "C" void Save_SaveSection(char* sectionString) { - SaveManager::Instance->SaveSection(gSaveContext.fileNum, sectionString); +extern "C" void Save_SaveSection(int sectionID) { + SaveManager::Instance->SaveSection(gSaveContext.fileNum, sectionID); } extern "C" void Save_SaveGlobal(void) { @@ -2307,8 +2312,8 @@ extern "C" void Save_AddLoadFunction(char* name, int version, SaveManager::LoadF SaveManager::Instance->AddLoadFunction(name, version, func); } -extern "C" void Save_AddSaveFunction(char* name, int version, SaveManager::SaveFunc func) { - SaveManager::Instance->AddSaveFunction(name, version, func); +extern "C" void Save_AddSaveFunction(char* name, int version, SaveManager::SaveFunc func, bool saveWithBase, int parentSection = SECTION_PARENT_NONE) { + SaveManager::Instance->AddSaveFunction(name, version, func, saveWithBase, parentSection); } extern "C" SaveFileMetaInfo* Save_GetSaveMetaInfo(int fileNum) { diff --git a/soh/soh/SaveManager.h b/soh/soh/SaveManager.h index 93a1fe336..56c3692ba 100644 --- a/soh/soh/SaveManager.h +++ b/soh/soh/SaveManager.h @@ -2,6 +2,7 @@ #include +#define SECTION_PARENT_NONE -1 typedef struct { u8 valid; u16 deaths; @@ -27,6 +28,7 @@ typedef struct { #include #include #include +#include #include #include "thread-pool/BS_thread_pool.hpp" @@ -38,6 +40,7 @@ extern "C" { class SaveManager { public: + static SaveManager* Instance; static void WriteSaveFile(const std::filesystem::path& savePath, uintptr_t addr, void* dramAddr, size_t size); @@ -45,15 +48,23 @@ public: using InitFunc = void(*)(bool isDebug); using LoadFunc = void(*)(); - using SaveFunc = void(*)(SaveContext* saveContext, const std::string& subSection); - using PostFunc = void(*)(int version); + using SaveFunc = void(*)(SaveContext* saveContext, int sectionID); + using PostFunc = void (*)(int version); + + typedef struct { + std::string name; + int version; + SaveManager::SaveFunc func; + bool saveWithBase; + int parentSection; + } SaveFuncInfo; SaveManager(); void Init(); void InitFile(bool isDebug); void SaveFile(int fileNum); - void SaveSection(int fileNum, const std::string& sectionString); + void SaveSection(int fileNum, int sectionID); void SaveGlobal(); void LoadFile(int fileNum); bool SaveFile_Exist(int fileNum); @@ -66,7 +77,7 @@ public: void AddLoadFunction(const std::string& name, int version, LoadFunc func); // Adds a function that is called when saving. This should only be called once for each function, the version is filled in automatically. - void AddSaveFunction(const std::string& name, int version, SaveFunc func); + void AddSaveFunction(const std::string& name, int version, SaveFunc func, bool saveWithBase, int parentSection); // Adds a function to be called after loading is complete. This is to handle any cleanup required from loading old versions. void AddPostFunction(const std::string& name, PostFunc func); @@ -119,9 +130,6 @@ public: static const int MaxFiles = 3; std::array fileMetaInfo; - void RegisterGameSaveSection(std::string section); - void UnregisterAutosaveSection(std::string section); - private: std::filesystem::path GetFileName(int fileNum); nlohmann::json saveBlock; @@ -129,7 +137,7 @@ public: void ConvertFromUnversioned(); void CreateDefaultGlobal(); - void SaveFileThreaded(int fileNum, SaveContext* saveContext, const std::string& sectionString); + void SaveFileThreaded(int fileNum, SaveContext* saveContext, int sectionID); void InitMeta(int slotNum); static void InitFileImpl(bool isDebug); @@ -138,23 +146,23 @@ public: static void LoadRandomizerVersion1(); static void LoadRandomizerVersion2(); - static void SaveRandomizer(SaveContext* saveContext, const std::string& subString); + static void SaveRandomizer(SaveContext* saveContext, int sectionID); static void LoadBaseVersion1(); static void LoadBaseVersion2(); static void LoadBaseVersion3(); static void LoadBaseVersion4(); - static void SaveBase(SaveContext* saveContext, const std::string& subString); + static void SaveBase(SaveContext* saveContext, int sectionID); std::vector initFuncs; using SectionLoadHandler = std::map; std::map sectionLoadHandlers; - using SectionSaveHandler = std::pair; - std::map sectionSaveHandlers; - // tracks sections to save during game saves - std::vector gameSaveRegistry; + int sectionIndex = SECTION_ID_MAX; + std::map coreSectionIDsByName; + std::map sectionSaveHandlers; + std::set sectionRegistry; std::map postHandlers; @@ -168,16 +176,16 @@ public: // TODO feature parity to the C++ interface. We need Save_AddInitFunction and Save_AddPostFunction at least typedef void (*Save_LoadFunc)(void); -typedef void (*Save_SaveFunc)(const SaveContext* saveContext); +typedef void (*Save_SaveFunc)(const SaveContext* saveContext, int sectionID); void Save_Init(void); void Save_InitFile(int isDebug); void Save_SaveFile(void); -void Save_SaveSection(char* sectionString); +void Save_SaveSection(int sectionID); void Save_SaveGlobal(void); void Save_LoadGlobal(void); void Save_AddLoadFunction(char* name, int version, Save_LoadFunc func); -void Save_AddSaveFunction(char* name, int version, Save_SaveFunc func); +void Save_AddSaveFunction(char* name, int version, Save_SaveFunc func, bool saveWithBase, int parentSection); SaveFileMetaInfo* Save_GetSaveMetaInfo(int fileNum); void Save_CopyFile(int from, int to); void Save_DeleteFile(int fileNum); From 1a9ef29ac53bc38b22ce0f9131c0f123eca3b6b9 Mon Sep 17 00:00:00 2001 From: Malkierian Date: Mon, 15 May 2023 17:32:49 -0700 Subject: [PATCH 14/17] Added function to get sectionID for a specified section name, returning -1 if section name not registered. --- soh/soh/SaveManager.cpp | 9 +++++++++ soh/soh/SaveManager.h | 3 ++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/soh/soh/SaveManager.cpp b/soh/soh/SaveManager.cpp index 2f8c52759..97f09bd74 100644 --- a/soh/soh/SaveManager.cpp +++ b/soh/soh/SaveManager.cpp @@ -885,6 +885,15 @@ void SaveManager::AddPostFunction(const std::string& name, PostFunc func) { postHandlers[name] = func; } +// Returns -1 if section name not found +int SaveManager::GetSaveSectionID(std::string& sectionName) { + if (sectionRegistry.contains(sectionName)) { + return sectionRegistry.find(sectionName)->second; + } else { + return -1; + } +} + void SaveManager::CreateDefaultGlobal() { gSaveContext.audioSetting = 0; gSaveContext.zTargetSetting = 0; diff --git a/soh/soh/SaveManager.h b/soh/soh/SaveManager.h index 56c3692ba..e4c11b838 100644 --- a/soh/soh/SaveManager.h +++ b/soh/soh/SaveManager.h @@ -65,6 +65,7 @@ public: void InitFile(bool isDebug); void SaveFile(int fileNum); void SaveSection(int fileNum, int sectionID); + int GetSaveSectionID(std::string& name); void SaveGlobal(); void LoadFile(int fileNum); bool SaveFile_Exist(int fileNum); @@ -162,7 +163,7 @@ public: int sectionIndex = SECTION_ID_MAX; std::map coreSectionIDsByName; std::map sectionSaveHandlers; - std::set sectionRegistry; + std::map sectionRegistry; std::map postHandlers; From 4cf3172a3d83f95b630df90535fcfc5376a23bdf Mon Sep 17 00:00:00 2001 From: Malkierian Date: Mon, 15 May 2023 17:40:10 -0700 Subject: [PATCH 15/17] Fixed trying to emplace in `sectionRegistry` without index. --- soh/soh/SaveManager.cpp | 2 +- soh/soh/SaveManager.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/soh/soh/SaveManager.cpp b/soh/soh/SaveManager.cpp index 97f09bd74..d5f82123c 100644 --- a/soh/soh/SaveManager.cpp +++ b/soh/soh/SaveManager.cpp @@ -872,7 +872,7 @@ void SaveManager::AddSaveFunction(const std::string& name, int version, SaveFunc } SaveFuncInfo sfi = { name, version, func, saveWithBase, parentSection }; sectionSaveHandlers.emplace(index, sfi); - sectionRegistry.emplace(name); + sectionRegistry.emplace(name, index); } void SaveManager::AddPostFunction(const std::string& name, PostFunc func) { diff --git a/soh/soh/SaveManager.h b/soh/soh/SaveManager.h index e4c11b838..17ac8715c 100644 --- a/soh/soh/SaveManager.h +++ b/soh/soh/SaveManager.h @@ -28,7 +28,6 @@ typedef struct { #include #include #include -#include #include #include "thread-pool/BS_thread_pool.hpp" From d0c09394caf2f601222aa067bac6b2350542ac0d Mon Sep 17 00:00:00 2001 From: Malkierian Date: Thu, 25 May 2023 16:57:27 -0700 Subject: [PATCH 16/17] Re-added removal of empty `sceneTimestmps` objects for saving and loading, significantly reducing `sohStats` size. --- soh/soh/Enhancements/gameplaystats.cpp | 42 +++++++++++++++++--------- soh/soh/SaveManager.cpp | 2 +- 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/soh/soh/Enhancements/gameplaystats.cpp b/soh/soh/Enhancements/gameplaystats.cpp index dd4ededed..eb1726dad 100644 --- a/soh/soh/Enhancements/gameplaystats.cpp +++ b/soh/soh/Enhancements/gameplaystats.cpp @@ -297,14 +297,24 @@ void LoadStatsVersion1() { SaveManager::Instance->LoadArray("itemTimestamps", ARRAY_COUNT(gSaveContext.sohStats.itemTimestamp), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.sohStats.itemTimestamp[i]); }); - SaveManager::Instance->LoadArray("sceneTimestamps", ARRAY_COUNT(gSaveContext.sohStats.sceneTimestamps), [](size_t i) { - SaveManager::Instance->LoadStruct("", [&i]() { - SaveManager::Instance->LoadData("scene", gSaveContext.sohStats.sceneTimestamps[i].scene); - SaveManager::Instance->LoadData("room", gSaveContext.sohStats.sceneTimestamps[i].room); - SaveManager::Instance->LoadData("sceneTime", gSaveContext.sohStats.sceneTimestamps[i].sceneTime); - SaveManager::Instance->LoadData("roomTime", gSaveContext.sohStats.sceneTimestamps[i].roomTime); - SaveManager::Instance->LoadData("isRoom", gSaveContext.sohStats.sceneTimestamps[i].isRoom); - + uint32_t sceneTimestampCount = 0; + SaveManager::Instance->LoadArray("sceneTimestamps", ARRAY_COUNT(gSaveContext.sohStats.sceneTimestamps), [&](size_t i) { + SaveManager::Instance->LoadStruct("", [&]() { + int scene, room, sceneTime, roomTime, isRoom; + SaveManager::Instance->LoadData("scene", scene); + SaveManager::Instance->LoadData("room", room); + SaveManager::Instance->LoadData("sceneTime", sceneTime); + SaveManager::Instance->LoadData("roomTime", roomTime); + SaveManager::Instance->LoadData("isRoom", isRoom); + if (scene == 0 && room == 0 && sceneTime == 0 && roomTime == 0 && isRoom == 0) { + return; + } + gSaveContext.sohStats.sceneTimestamps[i].scene = scene; + gSaveContext.sohStats.sceneTimestamps[i].room = room; + gSaveContext.sohStats.sceneTimestamps[i].sceneTime = sceneTime; + gSaveContext.sohStats.sceneTimestamps[i].roomTime = roomTime; + gSaveContext.sohStats.sceneTimestamps[i].isRoom = isRoom; + sceneTimestampCount++; }); }); SaveManager::Instance->LoadData("tsIdx", gSaveContext.sohStats.tsIdx); @@ -341,13 +351,15 @@ void SaveStats(SaveContext* saveContext, int sectionID) { SaveManager::Instance->SaveData("", saveContext->sohStats.itemTimestamp[i]); }); SaveManager::Instance->SaveArray("sceneTimestamps", ARRAY_COUNT(saveContext->sohStats.sceneTimestamps), [&](size_t i) { - SaveManager::Instance->SaveStruct("", [&]() { - SaveManager::Instance->SaveData("scene", saveContext->sohStats.sceneTimestamps[i].scene); - SaveManager::Instance->SaveData("room", saveContext->sohStats.sceneTimestamps[i].room); - SaveManager::Instance->SaveData("sceneTime", saveContext->sohStats.sceneTimestamps[i].sceneTime); - SaveManager::Instance->SaveData("roomTime", saveContext->sohStats.sceneTimestamps[i].roomTime); - SaveManager::Instance->SaveData("isRoom", saveContext->sohStats.sceneTimestamps[i].isRoom); - }); + if (saveContext->sohStats.sceneTimestamps[i].scene != 254 && saveContext->sohStats.sceneTimestamps[i].room != 254) { + SaveManager::Instance->SaveStruct("", [&]() { + SaveManager::Instance->SaveData("scene", saveContext->sohStats.sceneTimestamps[i].scene); + SaveManager::Instance->SaveData("room", saveContext->sohStats.sceneTimestamps[i].room); + SaveManager::Instance->SaveData("sceneTime", saveContext->sohStats.sceneTimestamps[i].sceneTime); + SaveManager::Instance->SaveData("roomTime", saveContext->sohStats.sceneTimestamps[i].roomTime); + SaveManager::Instance->SaveData("isRoom", saveContext->sohStats.sceneTimestamps[i].isRoom); + }); + } }); SaveManager::Instance->SaveData("tsIdx", saveContext->sohStats.tsIdx); SaveManager::Instance->SaveArray("counts", ARRAY_COUNT(saveContext->sohStats.count), [&](size_t i) { diff --git a/soh/soh/SaveManager.cpp b/soh/soh/SaveManager.cpp index db39527ef..bbc884066 100644 --- a/soh/soh/SaveManager.cpp +++ b/soh/soh/SaveManager.cpp @@ -789,7 +789,7 @@ void SaveManager::LoadFile(int fileNum) { std::ifstream input(GetFileName(fileNum)); - nlohmann::json saveBlock; + saveBlock = nlohmann::json::object(); input >> saveBlock; if (!saveBlock.contains("version")) { SPDLOG_ERROR("Save at " + GetFileName(fileNum).string() + " contains no version"); From cab90e9ac63c4ba9fd0e0b204e1565eea4e46203 Mon Sep 17 00:00:00 2001 From: Malkierian Date: Thu, 25 May 2023 16:59:53 -0700 Subject: [PATCH 17/17] Removed unused variable. --- soh/soh/Enhancements/gameplaystats.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/soh/soh/Enhancements/gameplaystats.cpp b/soh/soh/Enhancements/gameplaystats.cpp index eb1726dad..032c4197b 100644 --- a/soh/soh/Enhancements/gameplaystats.cpp +++ b/soh/soh/Enhancements/gameplaystats.cpp @@ -297,7 +297,6 @@ void LoadStatsVersion1() { SaveManager::Instance->LoadArray("itemTimestamps", ARRAY_COUNT(gSaveContext.sohStats.itemTimestamp), [](size_t i) { SaveManager::Instance->LoadData("", gSaveContext.sohStats.itemTimestamp[i]); }); - uint32_t sceneTimestampCount = 0; SaveManager::Instance->LoadArray("sceneTimestamps", ARRAY_COUNT(gSaveContext.sohStats.sceneTimestamps), [&](size_t i) { SaveManager::Instance->LoadStruct("", [&]() { int scene, room, sceneTime, roomTime, isRoom; @@ -314,7 +313,6 @@ void LoadStatsVersion1() { gSaveContext.sohStats.sceneTimestamps[i].sceneTime = sceneTime; gSaveContext.sohStats.sceneTimestamps[i].roomTime = roomTime; gSaveContext.sohStats.sceneTimestamps[i].isRoom = isRoom; - sceneTimestampCount++; }); }); SaveManager::Instance->LoadData("tsIdx", gSaveContext.sohStats.tsIdx);