From cba97ff22a8278ca9a4be2ec5b456eb9b8639ee8 Mon Sep 17 00:00:00 2001 From: somewhatlurker <52014015+somewhatlurker@users.noreply.github.com> Date: Wed, 18 Sep 2019 17:20:41 +1000 Subject: [PATCH] score_saver: add tracking of alltime best rank, improve pv list scrolling --- .../plugins/TLAC/Components/ScoreSaver.cpp | 237 +++++++++++++----- .../plugins/TLAC/Components/ScoreSaver.h | 3 +- 2 files changed, 170 insertions(+), 70 deletions(-) diff --git a/source-code/source/plugins/TLAC/Components/ScoreSaver.cpp b/source-code/source/plugins/TLAC/Components/ScoreSaver.cpp index c56eb5b..74e5d5e 100644 --- a/source-code/source/plugins/TLAC/Components/ScoreSaver.cpp +++ b/source-code/source/plugins/TLAC/Components/ScoreSaver.cpp @@ -25,9 +25,9 @@ namespace TLAC::Components return "score_saver"; } - char ScoreSaver::selHighScore[9] = "39393939"; - char ScoreSaver::selHighPct1[4] = "39"; - char ScoreSaver::selHighPct2[3] = "39"; + char ScoreSaver::selHighScore[12] = "--------(-)"; + char ScoreSaver::selHighPct1[4] = "---"; + char ScoreSaver::selHighPct2[3] = "--"; void(__stdcall* ScoreSaver::divaInitResults)(void* cls) = (void(__stdcall*)(void* cls))RESULTS_INIT_ADDRESS; void ScoreSaver::Initialize(ComponentsManager*) { @@ -80,12 +80,65 @@ namespace TLAC::Components InjectCode((void*)0x1405bfdc2, { 0x4c, 0x8b, 0xce }); // MOV R9, RSI InjectCode((void*)0x1405bfdc5, { 0x4c, 0x8d, 0x05, 0x90, 0x5b, 0x3e, 0x00 }); // LEA R8, [0x1409a595c] + // override font to song name font for larger character set + InjectCode((void*)0x1405bfa9d, { 0x11 }); + //InjectCode((void*)0x1405bfb80, { 0x11 }); + //InjectCode((void*)0x1405bfb9c, { 0x11 }); + DetourTransactionBegin(); DetourUpdateThread(GetCurrentThread()); DetourAttach(&(PVOID&)ScoreSaver::divaInitResults, (PVOID)(ScoreSaver::hookedInitResults)); DetourTransactionCommit(); } + + bool ScoreSaver::checkExistingScoreValid(int pv, int difficulty, int isEx) + { + 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 (isEx == 0) + swprintf(keyBase, 32, L"pv.%03d.diff.%01d", pv, difficulty); + else + swprintf(keyBase, 32, L"pv.%03d.diff.%01d.ex", pv, difficulty); + + + swprintf(key, 32, L"%ls.%ls", keyBase, L"score"); + int score = GetPrivateProfileIntW(section, key, 0, configPath); + + swprintf(key, 32, L"%ls.%ls", keyBase, L"notecounts"); + WCHAR countsBufW[32]; + char countsBufA[32]; + int cntHitTypes[2] = { 0, 0 }; + GetPrivateProfileStringW(section, key, L"", countsBufW, 32, configPath); + WideCharToMultiByte(CP_UTF8, 0, countsBufW, -1, countsBufA, 32, NULL, NULL); + std::vector countToks = TLAC::Utilities::Split(countsBufA, ","); + if (countToks.size() >= 2) + { + cntHitTypes[0] = atoi(countToks[0].c_str()); + cntHitTypes[1] = atoi(countToks[1].c_str()); + } + + swprintf(key, 32, L"%ls.%ls", keyBase, L"percent"); + int percent = GetPrivateProfileIntW(section, key, 0, configPath); + + swprintf(key, 32, L"%ls.%ls", keyBase, L"combo"); + int combo = GetPrivateProfileIntW(section, key, 0, configPath); + + swprintf(key, 32, L"%ls.%ls", keyBase, L"alltimerank"); + int allTimeRank = GetPrivateProfileIntW(section, key, 0, configPath); + + swprintf(key, 32, L"%ls.%ls", keyBase, L"rank"); + int clearRank = GetPrivateProfileIntW(section, key, 0, configPath); + + swprintf(key, 32, L"%ls.%ls", keyBase, L"check"); + int expectedCheck = GetPrivateProfileIntW(section, key, -1, configPath); + + + return expectedCheck == (int)(((short)score ^ ((short)cntHitTypes[0] << 16) ^ ((short)cntHitTypes[1]) ^ ((short)percent << 16) ^ ((short)combo)) * clearRank + (allTimeRank * clearRank)); + } void ScoreSaver::hookedInitResults(void* cls) { @@ -114,8 +167,6 @@ namespace TLAC::Components int percent = *(int*)(resultBase + 0x190); int slideScore = *(int*)(resultBase + 0x194); - int checkField = ((short)score ^ ((short)cntHitTypes[0] << 16) ^ ((short)cntHitTypes[1]) ^ ((short)percent << 16) ^ ((short)combo)) * clearRank; - WCHAR songName[256]; //std::string utf8song = *(std::string*)(CURRENT_SONG_NAME_ADDRESS); uint64_t songnamelen = *(uint64_t*)(CURRENT_SONG_NAME_ADDRESS + 0x18); @@ -137,55 +188,88 @@ namespace TLAC::Components swprintf(key, 32, L"%ls.%ls", keyBase, L"score"); int oldScore = GetPrivateProfileIntW(section, key, 0, configPath); - if (score <= oldScore) - return; + swprintf(key, 32, L"%ls.%ls", keyBase, L"alltimerank"); + int oldAlltimeRank = GetPrivateProfileIntW(section, key, 0, configPath); + int allTimeRank = clearRank > oldAlltimeRank ? clearRank : oldAlltimeRank; - swprintf(key, 32, L"%ls.%ls", keyBase, L"challengescore"); - swprintf(val, 32, L"%d", challengeScore); - WritePrivateProfileStringW(section, key, val, configPath); + bool oldScoreValid = true; + if (!checkExistingScoreValid(pvNum, pvDifficulty, pvDifficultyIsEx)) + { + oldScore = 0; // ensure new score is written + allTimeRank = clearRank; // don't trust old all-time clear rank, use a new one + oldScoreValid = false; + } - swprintf(key, 32, L"%ls.%ls", keyBase, L"combo"); - swprintf(val, 32, L"%d", combo); - WritePrivateProfileStringW(section, key, val, configPath); + if (score > oldScore) + { + swprintf(key, 32, L"%ls.%ls", keyBase, L"alltimerank"); + swprintf(val, 32, L"%d", allTimeRank); + WritePrivateProfileStringW(section, key, val, configPath); - swprintf(key, 32, L"%ls.%ls", keyBase, L"holdscore"); - swprintf(val, 32, L"%d", holdScore); - WritePrivateProfileStringW(section, key, val, configPath); + swprintf(key, 32, L"%ls.%ls", keyBase, L"challengescore"); + swprintf(val, 32, L"%d", challengeScore); + WritePrivateProfileStringW(section, key, val, configPath); - swprintf(key, 32, L"%ls.%ls", keyBase, L"modifier"); - swprintf(val, 32, L"%d", modifier); - WritePrivateProfileStringW(section, key, val, configPath); + swprintf(key, 32, L"%ls.%ls", keyBase, L"combo"); + swprintf(val, 32, L"%d", combo); + WritePrivateProfileStringW(section, key, val, configPath); - swprintf(key, 32, L"%ls.%ls", keyBase, L"name"); - WritePrivateProfileStringW(section, key, songName, configPath); + swprintf(key, 32, L"%ls.%ls", keyBase, L"holdscore"); + swprintf(val, 32, L"%d", holdScore); + WritePrivateProfileStringW(section, key, val, configPath); - swprintf(key, 32, L"%ls.%ls", keyBase, L"notecounts"); - swprintf(val, 32, L"%d,%d,%d,%d,%d", cntHitTypes[0], cntHitTypes[1], cntHitTypes[2], cntHitTypes[3], cntHitTypes[4]); - WritePrivateProfileStringW(section, key, val, configPath); + swprintf(key, 32, L"%ls.%ls", keyBase, L"modifier"); + swprintf(val, 32, L"%d", modifier); + WritePrivateProfileStringW(section, key, val, configPath); - swprintf(key, 32, L"%ls.%ls", keyBase, L"notepercents"); - swprintf(val, 32, L"%d,%d,%d,%d,%d", pctHitTypes[0], pctHitTypes[1], pctHitTypes[2], pctHitTypes[3], pctHitTypes[4]); - WritePrivateProfileStringW(section, key, val, configPath); + swprintf(key, 32, L"%ls.%ls", keyBase, L"name"); + WritePrivateProfileStringW(section, key, songName, configPath); - swprintf(key, 32, L"%ls.%ls", keyBase, L"percent"); - swprintf(val, 32, L"%d", percent); - WritePrivateProfileStringW(section, key, val, configPath); + swprintf(key, 32, L"%ls.%ls", keyBase, L"notecounts"); + swprintf(val, 32, L"%d,%d,%d,%d,%d", cntHitTypes[0], cntHitTypes[1], cntHitTypes[2], cntHitTypes[3], cntHitTypes[4]); + WritePrivateProfileStringW(section, key, val, configPath); - swprintf(key, 32, L"%ls.%ls", keyBase, L"rank"); - swprintf(val, 32, L"%d", clearRank); - WritePrivateProfileStringW(section, key, val, configPath); + swprintf(key, 32, L"%ls.%ls", keyBase, L"notepercents"); + swprintf(val, 32, L"%d,%d,%d,%d,%d", pctHitTypes[0], pctHitTypes[1], pctHitTypes[2], pctHitTypes[3], pctHitTypes[4]); + WritePrivateProfileStringW(section, key, val, configPath); - swprintf(key, 32, L"%ls.%ls", keyBase, L"score"); - swprintf(val, 32, L"%d", score); - WritePrivateProfileStringW(section, key, val, configPath); + swprintf(key, 32, L"%ls.%ls", keyBase, L"percent"); + swprintf(val, 32, L"%d", percent); + WritePrivateProfileStringW(section, key, val, configPath); - swprintf(key, 32, L"%ls.%ls", keyBase, L"slidescore"); - swprintf(val, 32, L"%d", slideScore); - WritePrivateProfileStringW(section, key, val, configPath); + swprintf(key, 32, L"%ls.%ls", keyBase, L"rank"); + swprintf(val, 32, L"%d", clearRank); + WritePrivateProfileStringW(section, key, val, configPath); - swprintf(key, 32, L"%ls.%ls", keyBase, L"check"); - swprintf(val, 32, L"%d", checkField); - WritePrivateProfileStringW(section, key, val, configPath); + swprintf(key, 32, L"%ls.%ls", keyBase, L"score"); + swprintf(val, 32, L"%d", score); + WritePrivateProfileStringW(section, key, val, configPath); + + swprintf(key, 32, L"%ls.%ls", keyBase, L"slidescore"); + swprintf(val, 32, L"%d", slideScore); + WritePrivateProfileStringW(section, key, val, configPath); + + int checkField = ((short)score ^ ((short)cntHitTypes[0] << 16) ^ ((short)cntHitTypes[1]) ^ ((short)percent << 16) ^ ((short)combo)) * clearRank + (allTimeRank * clearRank); + swprintf(key, 32, L"%ls.%ls", keyBase, L"check"); + swprintf(val, 32, L"%d", checkField); + WritePrivateProfileStringW(section, key, val, configPath); + } + else if (oldScoreValid && allTimeRank > oldAlltimeRank) + { + swprintf(key, 32, L"%ls.%ls", keyBase, L"alltimerank"); + swprintf(val, 32, L"%d", allTimeRank); + WritePrivateProfileStringW(section, key, val, configPath); + + swprintf(key, 32, L"%ls.%ls", keyBase, L"rank"); + int oldClearRank = GetPrivateProfileIntW(section, key, 0, configPath); + + swprintf(key, 32, L"%ls.%ls", keyBase, L"check"); + int oldCheck = GetPrivateProfileIntW(section, key, -1, configPath); + + swprintf(key, 32, L"%ls.%ls", keyBase, L"check"); + swprintf(val, 32, L"%d", oldCheck - (oldAlltimeRank * oldClearRank) + (allTimeRank * oldClearRank)); + WritePrivateProfileStringW(section, key, val, configPath); + } } void ScoreSaver::Update() @@ -214,46 +298,61 @@ namespace TLAC::Components swprintf(key, 32, L"%ls.%ls", keyBase, L"score"); - int score = GetPrivateProfileIntW(section, key, 0, configPath); + int score = GetPrivateProfileIntW(section, key, -1, configPath); - swprintf(key, 32, L"%ls.%ls", keyBase, L"notecounts"); - WCHAR countsBufW[32]; - char countsBufA[32]; - int cntHitTypes[2] = { 0, 0 }; - GetPrivateProfileStringW(section, key, L"", countsBufW, 32, configPath); - WideCharToMultiByte(CP_UTF8, 0, countsBufW, -1, countsBufA, 32, NULL, NULL); - std::vector countToks = TLAC::Utilities::Split(countsBufA, ","); - if (countToks.size() >= 2) + if (score < 0) { - cntHitTypes[0] = atoi(countToks[0].c_str()); - cntHitTypes[1] = atoi(countToks[1].c_str()); + snprintf(selHighScore, sizeof(selHighScore), "--------(-)"); + snprintf(selHighPct1, sizeof(selHighPct1), "---"); + snprintf(selHighPct2, sizeof(selHighPct2), "--"); + return; } - swprintf(key, 32, L"%ls.%ls", keyBase, L"percent"); - int percent = GetPrivateProfileIntW(section, key, 0, configPath); - swprintf(key, 32, L"%ls.%ls", keyBase, L"combo"); - int combo = GetPrivateProfileIntW(section, key, 0, configPath); - - swprintf(key, 32, L"%ls.%ls", keyBase, L"rank"); - int clearRank = GetPrivateProfileIntW(section, key, 0, configPath); - - swprintf(key, 32, L"%ls.%ls", keyBase, L"check"); - int expectedCheck = GetPrivateProfileIntW(section, key, -1, configPath); - - - if (expectedCheck == (int)(((short)score ^ ((short)cntHitTypes[0] << 16) ^ ((short)cntHitTypes[1]) ^ ((short)percent << 16) ^ ((short)combo)) * clearRank)) + if (checkExistingScoreValid(currentPv, currentDifficulty, currentDifficultyIsEx)) { if (score > 99999999) score = 99999999; - snprintf(selHighScore, sizeof(selHighScore), "%d", score); + 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); + + char allTimeRankLetter[2] = "-"; + switch (allTimeRank) + { + case 0: // misstake + allTimeRankLetter[0] = '-'; + break; + case 1: // cheap + allTimeRankLetter[0] = '-'; + break; + case 2: // clear + allTimeRankLetter[0] = 'C'; + break; + case 3: // great + allTimeRankLetter[0] = 'G'; + break; + case 4: // excellent + allTimeRankLetter[0] = 'E'; + break; + case 5: // perfect + allTimeRankLetter[0] = 'P'; + break; + default: + allTimeRankLetter[0] = '-'; + break; + } + + snprintf(selHighScore, sizeof(selHighScore), "%d(%s)", score, allTimeRankLetter); snprintf(selHighPct1, sizeof(selHighPct1), "%d", percent / 100); - snprintf(selHighPct2, sizeof(selHighPct2), "%d", percent % 100); + snprintf(selHighPct2, sizeof(selHighPct2), "%02d", percent % 100); } else { - snprintf(selHighScore, sizeof(selHighScore), "--------"); + snprintf(selHighScore, sizeof(selHighScore), "--------(-)"); snprintf(selHighPct1, sizeof(selHighPct1), "---"); snprintf(selHighPct2, sizeof(selHighPct2), "--"); } diff --git a/source-code/source/plugins/TLAC/Components/ScoreSaver.h b/source-code/source/plugins/TLAC/Components/ScoreSaver.h index 1a647b9..c23b539 100644 --- a/source-code/source/plugins/TLAC/Components/ScoreSaver.h +++ b/source-code/source/plugins/TLAC/Components/ScoreSaver.h @@ -22,9 +22,10 @@ namespace TLAC::Components static void(__stdcall* divaInitResults)(void* cls); static void hookedInitResults(void* cls); static void InjectCode(void* address, const std::vector data); + static bool checkExistingScoreValid(int pv, int difficulty, int isEx); static WCHAR configPath[256]; - static char selHighScore[9]; + static char selHighScore[12]; static char selHighPct1[4]; static char selHighPct2[3];