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;