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
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user