From da92b62bcdc40cee37117388950962d9a586f92a Mon Sep 17 00:00:00 2001 From: somewhatlurker <52014015+somewhatlurker@users.noreply.github.com> Date: Fri, 20 Sep 2019 17:15:38 +1000 Subject: [PATCH] score_saver: cache scores for speed, add clear counts (use_card only?), add "-PROTECTED-" message in protected mode should probably replace a bunch of ints with UINTs to do less range checks, but meh lol --- .../plugins/TLAC/Components/ScoreSaver.cpp | 178 +++++++++++++----- .../plugins/TLAC/Components/ScoreSaver.h | 15 +- source-code/source/plugins/TLAC/Constants.h | 1 + 3 files changed, 150 insertions(+), 44 deletions(-) diff --git a/source-code/source/plugins/TLAC/Components/ScoreSaver.cpp b/source-code/source/plugins/TLAC/Components/ScoreSaver.cpp index 727239e..662ebd8 100644 --- a/source-code/source/plugins/TLAC/Components/ScoreSaver.cpp +++ b/source-code/source/plugins/TLAC/Components/ScoreSaver.cpp @@ -9,9 +9,23 @@ namespace TLAC::Components { + static char emptySelHighScore[12] = "--------(-)"; + static char emptySelHighPct1[4] = "---"; + static char emptySelHighPct2[3] = "--"; + static char protectedSelHighScore[12] = "-PROTECTED-"; + static char protectedSelHighPct1[4] = "---"; + static char protectedSelHighPct2[3] = "--"; + char ScoreSaver::selHighScore[12]; + char ScoreSaver::selHighPct1[4]; + char ScoreSaver::selHighPct2[3]; + WCHAR ScoreSaver::configPath[256]; ScoreSaver::ScoreSaver() { + strcpy_s(selHighScore, sizeof(selHighScore), emptySelHighScore); + strcpy_s(selHighPct1, sizeof(selHighPct1), emptySelHighPct1); + strcpy_s(selHighPct2, sizeof(selHighPct2), emptySelHighPct2); + std::string utf8path = TLAC::framework::GetModuleDirectory() + "/scores.ini"; MultiByteToWideChar(CP_UTF8, 0, utf8path.c_str(), -1, configPath, 256); } @@ -25,9 +39,6 @@ namespace TLAC::Components return "score_saver"; } - char ScoreSaver::selHighScore[12] = "--------(-)"; - char ScoreSaver::selHighPct1[4] = "---"; - char ScoreSaver::selHighPct2[3] = "--"; bool(__stdcall* ScoreSaver::divaInitResults)(void* cls) = (bool(__stdcall*)(void* cls))RESULTS_INIT_ADDRESS; void ScoreSaver::Initialize(ComponentsManager*) { @@ -96,6 +107,11 @@ namespace TLAC::Components DetourUpdateThread(GetCurrentThread()); DetourAttach(&(PVOID&)ScoreSaver::divaInitResults, (PVOID)(ScoreSaver::hookedInitResults)); DetourTransactionCommit(); + + + // build the score cache + UpdateScoreCache(); + UpdateClearCounts(); } bool ScoreSaver::checkExistingScoreValid(int pv, int difficulty, int isEx) @@ -153,7 +169,7 @@ namespace TLAC::Components int clearRank = *(int*)(RESULTS_BASE_ADDRESS + 0xe8); byte insurance = *(byte*)(GAME_INFO_ADDRESS + 0x14); - if (clearRank < 2 || insurance !=0) + if (clearRank < 2 || insurance != 0) return result; // get the base for this specific set of results @@ -277,6 +293,9 @@ namespace TLAC::Components WritePrivateProfileStringW(section, key, val, configPath); } + UpdateSingleScoreCacheEntry(pvNum, pvDifficulty, pvDifficultyIsEx); + UpdateClearCounts(); + return result; } @@ -285,51 +304,42 @@ namespace TLAC::Components int pvNum = *(int*)SELPV_CURRENT_SONG_ADDRESS; int diff = *(int*)(GAME_INFO_ADDRESS); int diffIsEx = *(int*)(GAME_INFO_ADDRESS + 0x4); + byte insurance = *(byte*)(GAME_INFO_ADDRESS + 0x14); - if (pvNum == currentPv && diff == currentDifficulty && diffIsEx == currentDifficultyIsEx) + if (pvNum == currentPv && diff == currentDifficulty && diffIsEx == currentDifficultyIsEx && insurance == currentInsurance) return; currentPv = pvNum; currentDifficulty = diff; currentDifficultyIsEx = diffIsEx; + currentInsurance = insurance; - - WCHAR keyBase[32]; // needs to be big enough to store pv.999.diff.4.ex - WCHAR key[32]; // needs to be big enough to store pv.999.diff.4.challengescore - - const WCHAR section[] = L"scores"; - - if (currentDifficultyIsEx == 0) - swprintf(keyBase, 32, L"pv.%03d.diff.%01d", currentPv, currentDifficulty); - else - swprintf(keyBase, 32, L"pv.%03d.diff.%01d.ex", currentPv, currentDifficulty); - - - swprintf(key, 32, L"%ls.%ls", keyBase, L"score"); - int score = GetPrivateProfileIntW(section, key, -1, configPath); - - if (score < 0) + if (insurance != 0) { - snprintf(selHighScore, sizeof(selHighScore), "--------(-)"); - snprintf(selHighPct1, sizeof(selHighPct1), "---"); - snprintf(selHighPct2, sizeof(selHighPct2), "--"); + strcpy_s(selHighScore, sizeof(selHighScore), protectedSelHighScore); + strcpy_s(selHighPct1, sizeof(selHighPct1), protectedSelHighPct1); + strcpy_s(selHighPct2, sizeof(selHighPct2), protectedSelHighPct2); return; } + if (currentPv < 0 || currentDifficulty < 0 || currentDifficultyIsEx < 0 || currentPv > 999 || currentDifficulty > 3 || currentDifficultyIsEx > 1) + return; - if (checkExistingScoreValid(currentPv, currentDifficulty, currentDifficultyIsEx)) + CachedScoreInfo info = ScoreCache[currentPv][currentDifficulty][currentDifficultyIsEx]; + + if (info.score < 0) { - if (score > 99999999) - score = 99999999; - - swprintf(key, 32, L"%ls.%ls", keyBase, L"percent"); - int percent = GetPrivateProfileIntW(section, key, 0, configPath); - - swprintf(key, 32, L"%ls.%ls", keyBase, L"alltimerank"); - int allTimeRank = GetPrivateProfileIntW(section, key, 0, configPath); + strcpy_s(selHighScore, sizeof(selHighScore), emptySelHighScore); + strcpy_s(selHighPct1, sizeof(selHighPct1), emptySelHighPct1); + strcpy_s(selHighPct2, sizeof(selHighPct2), emptySelHighPct2); + } + else + { + if (info.score > 99999999) + info.score = 99999999; char allTimeRankLetter[2] = "-"; - switch (allTimeRank) + switch (info.rank) { case 0: // misstake allTimeRankLetter[0] = '-'; @@ -354,15 +364,9 @@ namespace TLAC::Components break; } - snprintf(selHighScore, sizeof(selHighScore), "%d(%s)", score, allTimeRankLetter); - snprintf(selHighPct1, sizeof(selHighPct1), "%d", percent / 100); - snprintf(selHighPct2, sizeof(selHighPct2), "%02d", percent % 100); - } - else - { - snprintf(selHighScore, sizeof(selHighScore), "--------(-)"); - snprintf(selHighPct1, sizeof(selHighPct1), "---"); - snprintf(selHighPct2, sizeof(selHighPct2), "--"); + snprintf(selHighScore, sizeof(selHighScore), "%d(%s)", info.score, allTimeRankLetter); + snprintf(selHighPct1, sizeof(selHighPct1), "%d", info.percent / 100); + snprintf(selHighPct2, sizeof(selHighPct2), "%02d", info.percent % 100); } } @@ -380,4 +384,92 @@ namespace TLAC::Components memcpy(address, data.data(), byteCount); VirtualProtect(address, byteCount, oldProtect, nullptr); } + + ScoreSaver::CachedScoreInfo ScoreSaver::ScoreCache[1000][4][2]; + void ScoreSaver::UpdateSingleScoreCacheEntry(int pvNum, int diff, int exDiff) + { + if (pvNum < 0 || diff < 0 || exDiff < 0 || pvNum > 999 || diff > 3 || exDiff > 1) + return; + + + WCHAR keyBase[32]; // needs to be big enough to store pv.999.diff.4.ex + WCHAR key[32]; // needs to be big enough to store pv.999.diff.4.challengescore + + const WCHAR section[] = L"scores"; + + if (exDiff == 0) + swprintf(keyBase, 32, L"pv.%03d.diff.%01d", pvNum, diff); + else + swprintf(keyBase, 32, L"pv.%03d.diff.%01d.ex", pvNum, diff); + + + swprintf(key, 32, L"%ls.%ls", keyBase, L"score"); + int score = GetPrivateProfileIntW(section, key, -1, configPath); + + if (score >= 0 && checkExistingScoreValid(pvNum, diff, exDiff)) + { + if (score > 99999999) + score = 99999999; + + swprintf(key, 32, L"%ls.%ls", keyBase, L"percent"); + int percent = GetPrivateProfileIntW(section, key, 0, configPath); + + swprintf(key, 32, L"%ls.%ls", keyBase, L"alltimerank"); + int allTimeRank = GetPrivateProfileIntW(section, key, -1, configPath); + + if (allTimeRank == -1) // fallback for old scores without alltimerank + { + swprintf(key, 32, L"%ls.%ls", keyBase, L"rank"); + allTimeRank = GetPrivateProfileIntW(section, key, 0, configPath); + } + + ScoreCache[pvNum][diff][exDiff] = { score, percent, allTimeRank }; + } + else + { + ScoreCache[pvNum][diff][exDiff] = { -1, -1, -1 }; + } + } + + void ScoreSaver::UpdateScoreCache() + { + for (int pvNum = 0; pvNum < 1000; pvNum++) + { + for (int diff = 0; diff < 4; diff++) + { + for (int exDiff = 0; exDiff < 2; exDiff++) + { + UpdateSingleScoreCacheEntry(pvNum, diff, exDiff); + } + } + } + } + + void ScoreSaver::UpdateClearCounts() + { + int* counts = (int*)SONG_CLEAR_COUNTS_ADDRESS; + for (int i = 0; i < 20; i++) + { + counts[i] = 0; + } + + for (int pvNum = 0; pvNum < 1000; pvNum++) + { + for (int diff = 0; diff < 4; diff++) + { + CachedScoreInfo info = ScoreCache[pvNum][diff][0]; + if (info.rank > 1 && info.rank <= 5) // at least clear and no greater than perfect + { + counts[diff * 4 + info.rank - 2] += 1; + } + } + + // exex special case + CachedScoreInfo info = ScoreCache[pvNum][3][1]; + if (info.rank > 1 && info.rank <= 5) // at least clear and no greater than perfect + { + counts[4 * 4 + info.rank - 2] += 1; + } + } + } } diff --git a/source-code/source/plugins/TLAC/Components/ScoreSaver.h b/source-code/source/plugins/TLAC/Components/ScoreSaver.h index 7a006d8..d056d88 100644 --- a/source-code/source/plugins/TLAC/Components/ScoreSaver.h +++ b/source-code/source/plugins/TLAC/Components/ScoreSaver.h @@ -18,6 +18,18 @@ namespace TLAC::Components virtual void Update() override; virtual void UpdateInput() override; + struct CachedScoreInfo + { + int score; + int percent; + int rank; + }; + static CachedScoreInfo ScoreCache[1000][4][2]; // 1000 slots * 4 difficulties * ex or not + + static void UpdateScoreCache(); + static void UpdateSingleScoreCacheEntry(int pvNum, int diff, int exDiff); + static void UpdateClearCounts(); + private: static bool(__stdcall* divaInitResults)(void* cls); static bool hookedInitResults(void* cls); @@ -28,9 +40,10 @@ namespace TLAC::Components static char selHighScore[12]; static char selHighPct1[4]; static char selHighPct2[3]; - + int currentPv; int currentDifficulty; int currentDifficultyIsEx; + byte currentInsurance; }; } diff --git a/source-code/source/plugins/TLAC/Constants.h b/source-code/source/plugins/TLAC/Constants.h index c26ca9a..d5ce191 100644 --- a/source-code/source/plugins/TLAC/Constants.h +++ b/source-code/source/plugins/TLAC/Constants.h @@ -95,6 +95,7 @@ constexpr uint64_t GAME_INFO_ADDRESS = 0x0000000141197E00; constexpr uint64_t CURRENT_SONG_NAME_ADDRESS = 0x0000000140D0A578; constexpr uint64_t CURRENT_SONG_ID_ADDRESS = 0x0000000140CDD8E0; constexpr uint64_t SELPV_CURRENT_SONG_ADDRESS = 0x000000014CC12438; +constexpr uint64_t SONG_CLEAR_COUNTS_ADDRESS = 0x00000001411A95E8; #define XINPUT_A 0x00 #define XINPUT_B 0x01