diff --git a/soh/include/z64save.h b/soh/include/z64save.h index 0abfe32d8..086dbccba 100644 --- a/soh/include/z64save.h +++ b/soh/include/z64save.h @@ -97,6 +97,7 @@ typedef struct { /* */ u32 entrancesDiscovered[SAVEFILE_ENTRANCES_DISCOVERED_IDX_COUNT]; /* */ u32 scenesDiscovered[SAVEFILE_SCENES_DISCOVERED_IDX_COUNT]; /* */ bool rtaTiming; + /* */ uint64_t firstInput; /* */ uint64_t fileCreatedAt; } SohStats; diff --git a/soh/soh/Enhancements/gameplaystats.cpp b/soh/soh/Enhancements/gameplaystats.cpp index ca360543f..628ce24a5 100644 --- a/soh/soh/Enhancements/gameplaystats.cpp +++ b/soh/soh/Enhancements/gameplaystats.cpp @@ -299,6 +299,7 @@ void LoadStatsVersion1() { SaveManager::Instance->LoadData("", gSaveContext.ship.stats.dungeonKeys[i]); }); SaveManager::Instance->LoadData("rtaTiming", gSaveContext.ship.stats.rtaTiming); + SaveManager::Instance->LoadData("firstInput", gSaveContext.ship.stats.firstInput); SaveManager::Instance->LoadData("fileCreatedAt", gSaveContext.ship.stats.fileCreatedAt); SaveManager::Instance->LoadData("playTimer", gSaveContext.ship.stats.playTimer); SaveManager::Instance->LoadData("pauseTimer", gSaveContext.ship.stats.pauseTimer); @@ -348,6 +349,7 @@ void SaveStats(SaveContext* saveContext, int sectionID, bool fullSave) { SaveManager::Instance->SaveData("", saveContext->ship.stats.dungeonKeys[i]); }); SaveManager::Instance->SaveData("rtaTiming", saveContext->ship.stats.rtaTiming); + SaveManager::Instance->SaveData("firstInput", saveContext->ship.stats.firstInput); SaveManager::Instance->SaveData("fileCreatedAt", saveContext->ship.stats.fileCreatedAt); SaveManager::Instance->SaveData("playTimer", saveContext->ship.stats.playTimer); SaveManager::Instance->SaveData("pauseTimer", saveContext->ship.stats.pauseTimer); @@ -694,7 +696,8 @@ void InitStats(bool isDebug) { gSaveContext.ship.stats.dungeonKeys[dungeon] = isDebug ? 8 : 0; } gSaveContext.ship.stats.rtaTiming = CVarGetInteger(CVAR_GAMEPLAY_STATS("RTATiming"), 0); - gSaveContext.ship.stats.fileCreatedAt = 0; + gSaveContext.ship.stats.fileCreatedAt = GetUnixTimestamp(); + gSaveContext.ship.stats.firstInput = 0; gSaveContext.ship.stats.playTimer = 0; gSaveContext.ship.stats.pauseTimer = 0; for (int timestamp = 0; timestamp < ARRAY_COUNT(gSaveContext.ship.stats.itemTimestamp); timestamp++) { diff --git a/soh/soh/Enhancements/gameplaystats.h b/soh/soh/Enhancements/gameplaystats.h index 1d60b5dfc..f3cdeaa5d 100644 --- a/soh/soh/Enhancements/gameplaystats.h +++ b/soh/soh/Enhancements/gameplaystats.h @@ -22,9 +22,9 @@ char* GameplayStats_GetCurrentTime(); #define GAMEPLAYSTAT_TOTAL_TIME \ (gSaveContext.ship.stats.rtaTiming \ ? (!gSaveContext.ship.stats.gameComplete \ - ? (!gSaveContext.ship.stats.fileCreatedAt \ + ? (!gSaveContext.ship.stats.firstInput \ ? 0 \ - : ((GetUnixTimestamp() - gSaveContext.ship.stats.fileCreatedAt) / 100)) \ + : ((GetUnixTimestamp() - gSaveContext.ship.stats.firstInput) / 100)) \ : (gSaveContext.ship.stats.itemTimestamp[TIMESTAMP_DEFEAT_GANON] \ ? gSaveContext.ship.stats.itemTimestamp[TIMESTAMP_DEFEAT_GANON] \ : gSaveContext.ship.stats.itemTimestamp[TIMESTAMP_TRIFORCE_COMPLETED])) \ diff --git a/soh/soh/Network/Anchor/JsonConversions.hpp b/soh/soh/Network/Anchor/JsonConversions.hpp index b99b78496..f9357c142 100644 --- a/soh/soh/Network/Anchor/JsonConversions.hpp +++ b/soh/soh/Network/Anchor/JsonConversions.hpp @@ -93,12 +93,14 @@ inline void from_json(const json& j, Inventory& inventory) { inline void to_json(json& j, const SohStats& sohStats) { j = json{ { "entrancesDiscovered", sohStats.entrancesDiscovered }, + { "firstInput", sohStats.firstInput }, { "fileCreatedAt", sohStats.fileCreatedAt }, }; } inline void from_json(const json& j, SohStats& sohStats) { j.at("entrancesDiscovered").get_to(sohStats.entrancesDiscovered); + j.at("firstInput").get_to(sohStats.firstInput); j.at("fileCreatedAt").get_to(sohStats.fileCreatedAt); } diff --git a/soh/soh/Network/Anchor/Packets/UpdateTeamState.cpp b/soh/soh/Network/Anchor/Packets/UpdateTeamState.cpp index deb3fedc3..9e9169779 100644 --- a/soh/soh/Network/Anchor/Packets/UpdateTeamState.cpp +++ b/soh/soh/Network/Anchor/Packets/UpdateTeamState.cpp @@ -189,6 +189,7 @@ void Anchor::HandlePacket_UpdateTeamState(nlohmann::json payload) { gSaveContext.gsFlags[i] = loadedData.gsFlags[i]; } + gSaveContext.ship.stats.firstInput = loadedData.ship.stats.firstInput; gSaveContext.ship.stats.fileCreatedAt = loadedData.ship.stats.fileCreatedAt; // Restore master sword state diff --git a/soh/soh/SaveManager.cpp b/soh/soh/SaveManager.cpp index 5059deade..dc5072d27 100644 --- a/soh/soh/SaveManager.cpp +++ b/soh/soh/SaveManager.cpp @@ -1631,6 +1631,7 @@ void SaveManager::LoadBaseVersion2() { SaveManager::Instance->LoadData("", gSaveContext.ship.stats.dungeonKeys[i]); }); SaveManager::Instance->LoadData("rtaTiming", gSaveContext.ship.stats.rtaTiming); + SaveManager::Instance->LoadData("firstInput", gSaveContext.ship.stats.firstInput); SaveManager::Instance->LoadData("fileCreatedAt", gSaveContext.ship.stats.fileCreatedAt); SaveManager::Instance->LoadData("playTimer", gSaveContext.ship.stats.playTimer); SaveManager::Instance->LoadData("pauseTimer", gSaveContext.ship.stats.pauseTimer); @@ -1848,6 +1849,7 @@ void SaveManager::LoadBaseVersion3() { SaveManager::Instance->LoadData("", gSaveContext.ship.stats.dungeonKeys[i]); }); SaveManager::Instance->LoadData("rtaTiming", gSaveContext.ship.stats.rtaTiming); + SaveManager::Instance->LoadData("firstInput", gSaveContext.ship.stats.firstInput); SaveManager::Instance->LoadData("fileCreatedAt", gSaveContext.ship.stats.fileCreatedAt); SaveManager::Instance->LoadData("playTimer", gSaveContext.ship.stats.playTimer); SaveManager::Instance->LoadData("pauseTimer", gSaveContext.ship.stats.pauseTimer); diff --git a/soh/src/code/z_play.c b/soh/src/code/z_play.c index 89583e598..38a040a8a 100644 --- a/soh/src/code/z_play.c +++ b/soh/src/code/z_play.c @@ -781,10 +781,10 @@ void Play_Update(PlayState* play) { } // Start RTA timing on first non-c-up input after intro cutscene - if (!gSaveContext.ship.stats.fileCreatedAt && !Player_InCsMode(play) && + if (!gSaveContext.ship.stats.firstInput && !Player_InCsMode(play) && ((input[0].press.button && input[0].press.button != 0x8) || input[0].rel.stick_x != 0 || input[0].rel.stick_y != 0)) { - gSaveContext.ship.stats.fileCreatedAt = GetUnixTimestamp(); + gSaveContext.ship.stats.firstInput = GetUnixTimestamp(); } } // #endregion