From 80cf97d72de2a99d9b09ce1aec9c7c3b7435d8f9 Mon Sep 17 00:00:00 2001 From: RyuMiyaX <52694802+ryumiyax@users.noreply.github.com> Date: Sun, 15 Dec 2024 02:31:13 +0800 Subject: [PATCH 01/11] Add Graphic Card Attention in README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 984507a..5b470d4 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,8 @@ It currently supports the following versions: * JPN 39.06 * CHN 00.32 (based on JPN 32.09) +**Attention**: As far as we know, game couldn't run on graphic card equals or lower than GTX 7xx series(GTX 7xx is not supported either), so if game crashes before it shows `avaliableRefreshRate`, that most likely means your graphic card is not supported! + ## Setup Copy the extracted contents of `dist.zip` to the same directory as Taiko.exe From 32512d0dbc9bf2fcadbcf3d047f31e06b453b315 Mon Sep 17 00:00:00 2001 From: ptmaster Date: Sat, 21 Dec 2024 06:03:09 +0800 Subject: [PATCH 02/11] Language patch | Fix boot lag | Fix axis input --- CMakeLists.txt | 1 + dist/config.toml | 5 - src/bnusio.cpp | 29 +- src/constants.h | 5 + src/dllmain.cpp | 53 +-- src/helpers.cpp | 18 + src/helpers.h | 12 +- src/patches/language.cpp | 626 +++++++++++++++++++++++++++++++++ src/patches/layeredfs.cpp | 33 +- src/patches/patches.h | 9 +- src/patches/scanner.cpp | 18 +- src/patches/testmode.cpp | 134 ++----- src/patches/versions/JPN39.cpp | 406 ++------------------- src/pollasync.cpp | 159 +++++++-- 14 files changed, 905 insertions(+), 603 deletions(-) create mode 100644 src/patches/language.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index eaaad31..8a6e9db 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -142,6 +142,7 @@ set(SOURCES src/patches/layeredfs.cpp src/patches/testmode.cpp src/patches/timer.cpp + src/patches/language.cpp src/patches/versions/JPN00.cpp src/patches/versions/JPN08.cpp src/patches/versions/JPN39.cpp diff --git a/dist/config.toml b/dist/config.toml index fba0b8a..484baaa 100644 --- a/dist/config.toml +++ b/dist/config.toml @@ -24,11 +24,6 @@ mode_collabo025 = false # Enable one piece collab mode mode_collabo026 = false # Enable ai soshina mode -[patches.jpn39] # These patches are only available for version JPN39 -chs_patch = false # Use Chinese font and Simplified Chinese values from the wordlist - # More options are available in the ModManager, in the TestMode menu (Default key is F1) - - [emulation] usio = true # Disable this if you want to use an original Namco USIO board. you need to place bnusio_original.dll (unmodified bnusio.dll) in the executable folder. card_reader = true # Disable this if you want to use an original Namco card reader diff --git a/src/bnusio.cpp b/src/bnusio.cpp index 0f82475..459d0fb 100644 --- a/src/bnusio.cpp +++ b/src/bnusio.cpp @@ -137,16 +137,10 @@ bool valueStates[] = {false, false, false, false, false, false, false, false}; Keybindings *analogButtons[] = {&P1_LEFT_BLUE, &P1_LEFT_RED, &P1_RIGHT_RED, &P1_RIGHT_BLUE, &P2_LEFT_BLUE, &P2_LEFT_RED, &P2_RIGHT_RED, &P2_RIGHT_BLUE}; -// u16 cooldown[8] = { 0 }; +u8 cooldown[8] = { 0 }; u16 buttonWaitPeriod[] = { 0, 0 }; std::queue buttonQueue[] = { {}, {} }; -// u16 buttonWaitPeriodP1 = 0; -// u16 buttonWaitPeriodP2 = 0; -// std::queue buttonQueueP1; -// std::queue buttonQueueP2; - - SDLAxis analogBindings[] = { SDL_AXIS_LEFT_LEFT, SDL_AXIS_LEFT_RIGHT, SDL_AXIS_LEFT_DOWN, SDL_AXIS_LEFT_UP, // P1: LB, LR, RR, RB SDL_AXIS_RIGHT_LEFT, SDL_AXIS_RIGHT_RIGHT, SDL_AXIS_RIGHT_DOWN, SDL_AXIS_RIGHT_UP, // P2: LB, LR, RR, RB @@ -248,6 +242,22 @@ AnalogInputWaitPeriod (const u8 which) { return analogValue; } +u8 blueCooldown = 1, redCooldown = 1; +u16 __fastcall +AnalogInputCooldown (const u8 which) { + const auto button = analogButtons[which]; + const bool blue = !(which % 4 % 3); + + if (cooldown[which] > 0) cooldown[which]--; + if (IsButtonTapped (*button)) { + if (cooldown[which] > 0) return 0; + cooldown[which] = blue ? blueCooldown : redCooldown; + const u16 hitValue = !valueStates[which] ? 50 : 51; + valueStates[which] = !valueStates[which]; + return (hitValue << 15) / 100 + 1; + } else return 0; +} + u16 __fastcall AnalogInputSimple (const u8 which) { const auto button = analogButtons[which]; @@ -299,7 +309,7 @@ UpdateLoop () { if (IsButtonTapped (TEST)) testEnabled = !testEnabled; if (IsButtonTapped (EXIT)) { LogMessage (LogLevel::INFO, "Exit By Press Exit Button!"); - exited += 1; testEnabled = 1; patches::Plugins::Exit (); + exited += 1; testEnabled = 1; std::thread([](){patches::Plugins::Exit ();}).detach(); } if (GameVersion::CHN00 == gameVersion) { if (IsButtonTapped (CARD_INSERT_1)) patches::Scanner::Qr::CommitLogin (accessCode1); @@ -344,6 +354,9 @@ Init () { } else if (drumWaitPeriod > 0) { LogMessage (LogLevel::WARN, "[Analog Type] WaitPeriod: Fast input might be queued"); analogMethod = AnalogInputWaitPeriod; + } else if (drumWaitPeriod == 0) { + LogMessage (LogLevel::INFO, "[Analog Type] Cooldown: Fastest and original input"); + analogMethod = AnalogInputCooldown; } else { LogMessage (LogLevel::INFO, "[Analog Type] Simple: Fastest and original input"); analogMethod = AnalogInputSimple; diff --git a/src/constants.h b/src/constants.h index 33222f1..4bbf46d 100644 --- a/src/constants.h +++ b/src/constants.h @@ -7,4 +7,9 @@ enum class GameVersion : XXH64_hash_t { JPN08 = 0x67C0F3042746D488, JPN39 = 0x49F643ADB6B18705, CHN00 = 0xA7EE39F2CC2C57C8, +}; + +enum StatusType { + CardStatus = 1, + QrStatus = 2 }; \ No newline at end of file diff --git a/src/dllmain.cpp b/src/dllmain.cpp index 1bec855..af4440a 100644 --- a/src/dllmain.cpp +++ b/src/dllmain.cpp @@ -140,51 +140,6 @@ CreateCard () { WritePrivateProfileStringA ("card", "chipId2", buf, ".\\card.ini"); } -void -ElevateProcess () { - HANDLE hToken; - TOKEN_PRIVILEGES tp; - LUID luid; - - // 获取当前进程的访问令牌 - if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) { - LogMessage (LogLevel::ERROR, "OpenProcessToken failed: {}", GetLastError()); - return; - } - - // 获取 SE_DEBUG_NAME 权限的 LUID - if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid)) { - LogMessage (LogLevel::ERROR, "LookupPrivilegeValue failed: {}", GetLastError()); - CloseHandle(hToken); - return; - } - - tp.PrivilegeCount = 1; - tp.Privileges[0].Luid = luid; - tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; - - // 调整权限 - if (!AdjustTokenPrivileges(hToken, FALSE, &tp, 0, NULL, NULL)) { - LogMessage (LogLevel::ERROR, "AdjustTokenPrivileges failed: {}", GetLastError()); - CloseHandle(hToken); - return; - } - - LogMessage (LogLevel::INFO, "Privileges adjusted successfully!"); - CloseHandle(hToken); -} - -bool DisableDEP() { - if (SetProcessDEPPolicy(PROCESS_DEP_ENABLE)) { - // std::cout << "DEP disabled successfully.\n"; - return true; - } else { - LogMessage (LogLevel::ERROR, "Failed to disable DEP: {}", GetLastError()); - // std::cerr << "Failed to disable DEP: " << GetLastError() << std::endl; - return false; - } -} - BOOL DllMain (HMODULE module, const DWORD reason, LPVOID reserved) { if (reason == DLL_PROCESS_ATTACH) { @@ -192,14 +147,11 @@ DllMain (HMODULE module, const DWORD reason, LPVOID reserved) { // I/O in DllMain can easily cause a deadlock // Init logger for loading config - auto start = std::chrono::high_resolution_clock::now(); InitializeLogger (GetLogLevel (logLevelStr), logToFile); - // ElevateProcess (); - // DisableDEP (); patches::Timer::Init (); + #ifdef ASYNC_IO - LogMessage (LogLevel::WARN, "(experimental) Using Async IO!"); InitializeKeyboard (); #endif @@ -314,8 +266,9 @@ DllMain (HMODULE module, const DWORD reason, LPVOID reserved) { patches::Audio::Init (); patches::Dxgi::Init (); patches::AmAuth::Init (); - patches::LayeredFs::Init (); + patches::Language::Init (); patches::TestMode::Init (); + patches::LayeredFs::Init (); std::chrono::duration duration = std::chrono::high_resolution_clock::now() - start; LogMessage (LogLevel::INFO, "==== Finished Loading patches! using: {:.2f}ms", duration.count () * 1000); diff --git a/src/helpers.cpp b/src/helpers.cpp index 8cd2968..8e5ec58 100644 --- a/src/helpers.cpp +++ b/src/helpers.cpp @@ -182,4 +182,22 @@ AreAllBytesZero (const u8 *array, const size_t offset, const size_t length) { for (size_t i = 0; i < length; ++i) if (array[offset + i] != 0x00) return false; return true; +} + +void +withFile (const char *fileName, std::function callback) { + FILE *file = fopen (fileName, "rb"); + if (file == nullptr) return; + + fseek (file, 0, SEEK_END); + long size = ftell (file); + fseek (file, 0, SEEK_SET); + + u8 *buffer = (u8 *)malloc(size); + fread (buffer, 1, size, file); + + callback (buffer); + + free (buffer); + fclose (file); } \ No newline at end of file diff --git a/src/helpers.h b/src/helpers.h index ef3b708..7ed853a 100644 --- a/src/helpers.h +++ b/src/helpers.h @@ -11,6 +11,8 @@ #include #include #include +#include +#include #include "constants.h" #include "logger.h" @@ -123,15 +125,8 @@ const HMODULE MODULE_HANDLE = GetModuleHandle (nullptr); #define INSTALL_FAST_HOOK_DYNAMIC(functionName, location) \ { \ LogMessage (LogLevel::DEBUG, std::string ("Installing fast hook dynamic for ") + #functionName); \ - if (auto hook = safetyhook::InlineHook::create((void *)location, (void*)implOf##functionName)) {\ - original##functionName = std::move(*hook); \ - } else { \ - LogMessage (LogLevel::ERROR, std::string ("Error Installing fast hook dynamic for ") + #functionName);\ - ExitProcess (1); \ - } \ + original##functionName = safetyhook::create_inline ((void *)location, (void*)implOf##functionName); \ } - // original##functionName = safetyhook::create_inline ((void *)location, (void*)implOf##functionName); \ - // } inline bool sendFlag = false; #define SCENE_RESULT_HOOK(functionName, location) \ @@ -228,3 +223,4 @@ const char *GameVersionToString (GameVersion version); const char *languageStr (int language); std::string ConvertWideToUtf8 (const std::wstring &wstr); bool AreAllBytesZero (const u8 *array, size_t offset, size_t length); +void withFile (const char *fileName, std::function callback); diff --git a/src/patches/language.cpp b/src/patches/language.cpp new file mode 100644 index 0000000..abf9f3d --- /dev/null +++ b/src/patches/language.cpp @@ -0,0 +1,626 @@ +#include "constants.h" +#include "helpers.h" +#include "patches.h" +#include + +extern GameVersion gameVersion; + +namespace patches::Language { +const std::vector languages = { "jpn", "en_us", "cn_tw", "kor", "cn_cn" }; +std::vector language_patch = { }; +int language = 0; + +FUNCTION_PTR (void, lua_settop, PROC_ADDRESS ("lua51.dll", "lua_settop"), i64, i32); +FUNCTION_PTR (void, lua_replace, PROC_ADDRESS ("lua51.dll", "lua_replace"), i64, i32); +FUNCTION_PTR (const char *, lua_pushstring, PROC_ADDRESS ("lua51.dll", "lua_pushstring"), i64, const char *); +FUNCTION_PTR (const char *, lua_tolstring, PROC_ADDRESS ("lua51.dll", "lua_tolstring"), u64, i32, size_t *); +FUNCTION_PTR (void, lua_pushnumber, PROC_ADDRESS ("lua51.dll", "lua_pushnumber"), i64, double); + +typedef void *(*Taiko_string) (void *address, const char *src); +typedef void *(*Taiko_assign) (void *address, const char *src, size_t size); +typedef int (*LanguageFix) (int language); + +Taiko_string taiko_string = nullptr; +Taiko_assign taiko_assign = nullptr; +Taiko_assign std_assign = nullptr; +Taiko_assign std_append = nullptr; +LanguageFix languageFix = [](int lang){ return lang; }; + +namespace Font { +typedef u64 *(*Taiko_mapping) (u64 *a1, u8 *a2); +Taiko_mapping taiko_mapping = nullptr; + +typedef struct { + const char *font_name; + const char *font_shape; + const char *font_file; +} LanguageItem; + +void *languageData = nullptr; +const size_t languageOffset = languages.size () * 560; +// jp_64, jp_30, jp_32, en_64, en_30, en_32, tw_64, tw_30, tw_32, ko_64, ko_30, ko_32, cn_64, cn_30, cn_32 +const float upA[15] = { -1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f }; +const float upB[15] = { -0.265625f, 0.15f, 0.078125f, -0.21875f, 0.2329999f, 0.140625f, -0.0625f, 0.333f, 0.28125f, -0.109375f, 0.333f, 0.28125f, -0.09375f, 0.30000001f, 0.25f }; +const float downA[15] = { -0.25f, 0.167f, 0.125f, -0.21875f, 0.233f, 0.140625f, -0.0625f, 0.333f, 0.25f, -0.125f, 0.333f, 0.28125f, -0.09375f, 0.30000001f, 0.25f }; +const float downB[15] = { 50.5f, 10.0f, 13.0f, 46.0f, 8.0f, 11.5f, 36.0f, 5.0f, 7.0f, 39.0f, 5.0f, 7.0f, 38.0f, 6.0f, 8.0f }; +// xx_64, 00_30, xx_32 +const float downC[3] = { 64.0f, 30.0f, 32.0f }; +const float shapes[3] = { 20.0f, 12.0f, 16.0f }; +const LanguageItem languageItems[5][5] = { + {{"jp", "64", "jp_64"},{"jp", "30", "jp_30"},{"jp", "32_EB", "jp_32_EB"},{"jp", "32_B", "jp_32_B"},{"jp", "32_DB", "jp_32_DB"}}, + {{"en", "64", "en_64"},{"en", "30", "en_30"},{"en", "32_EB", "en_32" },{"en", "32_B", "en_32" },{"en", "32_DB", "en_32" }}, + {{"tw", "64", "tw_64"},{"tw", "30", "tw_30"},{"tw", "32_EB", "tw_32" },{"tw", "32_B", "tw_32" },{"tw", "32_DB", "tw_32" }}, + {{"kr", "64", "kr_64"},{"kr", "30", "kr_30"},{"kr", "32_EB", "kr_32" },{"kr", "32_B", "kr_32" },{"kr", "32_DB", "kr_32" }}, + {{"cn", "64", "cn_64"},{"cn", "30", "cn_30"},{"cn", "32_EB", "cn_32" },{"cn", "32_B", "cn_32" },{"cn", "32_DB", "cn_32" }}, +}; + +FAST_HOOK_DYNAMIC (int, initial_load_setting) { + for (int repeat = 0; repeat < languages.size (); repeat ++) { + u64 offsetR = repeat * languages.size () * 0x5 * 0x70; + for (int lang = 0; lang < languages.size (); lang ++) { + u64 offsetI = lang * 0x5 * 0x70; + const LanguageItem *group = languageItems[lang]; + for (int shape = 0; shape < 0x5; shape ++) { + LanguageItem item = group[shape]; + u64 basicOffset = (u64)languageData + offsetR + offsetI + shape * 0x70; + u32 shapeIndex = shape > 2 ? 2 : shape; + + std::string *str = new std::string (item.font_name); + memcpy ((void *)(basicOffset + 0x00), str, 0x20); + str = new std::string (item.font_shape); + memcpy ((void *)(basicOffset + 0x20), str, 0x20); + str = new std::string (item.font_file); + memcpy ((void *)(basicOffset + 0x40), str, 0x20); + *(float *)(basicOffset + 0x60) = shapes[shapeIndex]; + *(u32 *)(basicOffset + 0x64) = lang == 0 ? 0 : shapeIndex + 1; + *(u32 *)(basicOffset + 0x68) = lang == 0 ? 0 : (3 * lang + shapeIndex + 1); + } + } + } + return 0; +} + +FAST_HOOK_DYNAMIC (double, GetCorrectionOffsetY, u64 a1, u32 a2) { + if (!a2) return 0.0; + double result; + u8 type = *(u8 *)(a1 + 572); + float varA = *(float *)(a1 + 532); + if (type) { + *(float *)&result = upA[a2 - 1] + upB[a2 - 1] * varA; + } else { + float varB = *(float *)(a1 + 564); + float varC = downC[(a2 - 1) % 3]; + float val = (varC - varA) * downA[a2 - 1] + (varB - varC) * 0.5f + downB[a2 - 1] - varB * 0.5f; + *(u64 *)&result = *(u64 *)&val ^ 0x8000000080000000ui64; + } + return result; +} + +void +Init () { + bool fontExistAll = true; + const char *fontToCheck[]{"cn_30.nutexb", "cn_30.xml", "cn_32.nutexb", "cn_32.xml", "cn_64.nutexb", "cn_64.xml"}; + for (int i = 0; i < 6; i++) { + if (std::filesystem::exists (std::string ("..\\..\\Data\\x64\\font\\") + fontToCheck[i])) continue; + fontExistAll = false; + } + if (fontExistAll == false) return; + LogMessage (LogLevel::INFO, "Detected cn_xx files, Install Font patches"); + languageData = calloc (languages.size () * languages.size () * 0x70 * 0x5, sizeof (u8)); + + switch (gameVersion) { + default: case GameVersion::JPN00: case GameVersion::JPN08: case GameVersion::CHN00: break; + case GameVersion::JPN39: { + taiko_mapping = (Taiko_mapping)ASLR (0x140369B60); + TestMode::RegisterModify ( + L"/root/menu[@id='OthersMenu']/layout[@type='Center']/select-item[@id='LanguageItem']", + [](pugi::xml_node &node) { + node.attribute (L"max").set_value (L"4"); + node.attribute (L"default").set_value (L"4"); + node.attribute (L"replace-text").set_value (L"0:JPN, 1:ENG, 2:zh-tw, 3:KOR, 4:zh-cn"); + }, [&](){ + // load_setting + INSTALL_FAST_HOOK_DYNAMIC (initial_load_setting, ASLR (0x14001B010)); + // SceneBoot::LoadFont + language_patch.push_back (safetyhook::create_mid (ASLR (0x140464235), [](SafetyHookContext &ctx){ + ctx.rbp = ctx.rbx * languageOffset; + ctx.rax = (uintptr_t)languageData; + ctx.rip = ASLR (0x140464243); + })); + language_patch.push_back (safetyhook::create_mid (ASLR (0x14046426C), [](SafetyHookContext &ctx){ + ctx.r15 = ctx.rbp + languageOffset; + ctx.rip = ASLR (0x140464273); + })); + // SceneBoot::SetFontShift + language_patch.push_back (safetyhook::create_mid (ASLR (0x1404644AF), [](SafetyHookContext &ctx){ + ctx.rdi = ctx.rcx * languageOffset; + ctx.rax = (uintptr_t)languageData; + ctx.rdi += ctx.rax; + ctx.rsi = ctx.rdi + languageOffset; + ctx.rip = ASLR (0x1404644C7); + })); + // AppLumenRenderer + language_patch.push_back (safetyhook::create_mid (ASLR (0x140368961), [](SafetyHookContext &ctx){ + *(u64 *)(ctx.rsp + 0x20) = 4; + void *buf = taiko_mapping ((u64 *)(ctx.r14), (u8 *)(ctx.rsp + 0x20)); + taiko_assign (buf, "cn", 2); + })); + // CorrectionOffsetY + INSTALL_FAST_HOOK_DYNAMIC (GetCorrectionOffsetY, ASLR (0x14049FAD0)); + // user_name_entry + language_patch.push_back (safetyhook::create_mid (ASLR (0x14016128D), [](SafetyHookContext &ctx) + { *(int *)(ctx.rsp + 0xD0) = (int)(ctx.rcx % languages.size ()); ctx.rip = ASLR (0x1401612C7); })); + // user_name_p + language_patch.push_back (safetyhook::create_mid (ASLR (0x140160F63), [](SafetyHookContext &ctx) + { *(int *)(ctx.rsp + 0xD0) = (int)(ctx.rdi % languages.size ()); ctx.rip = ASLR (0x140160F9D); })); + // user_name_ai + language_patch.push_back (safetyhook::create_mid (ASLR (0x14016146D), [](SafetyHookContext &ctx) + { *(int *)(ctx.rsp + 0xD0) = (int)(ctx.rcx % languages.size ()); ctx.rip = ASLR (0x1401614A7); })); + // user_name_soshina + language_patch.push_back (safetyhook::create_mid (ASLR (0x14016164D), [](SafetyHookContext &ctx) + { *(int *)(ctx.rsp + 0xD0) = (int)(ctx.rcx % languages.size ()); ctx.rip = ASLR (0x140161687); })); + } + ); + } break; + } +} +} + +namespace Datatable { +const std::vector languageTexts = {"japaneseText", "englishUsText", "chineseTText", "koreanText", "chineseSText"}; +const std::vector languageFontTypes = {"japaneseFontType", "englishUsFontType", "chineseTFontType", "koreanFontType", "chineseSFontType"}; +const std::vector languageFlas = {"taikoSelectFla", "taikoSelectFlaENUS", "taikoSelectFlaCNTW", "taikoSelectFlaKOR", "taikoSelectFlaZHCN"}; + +typedef bool (*JsonHasMember) (u64, const char *); +typedef u64 *(*JsonGetMember) (u64, const char *); +typedef void (*VectorIterator) (char *, u64, u64, u64); +JsonHasMember jsonHasMember = nullptr; +JsonGetMember jsonGetMember = nullptr; +VectorIterator vectorIterator = nullptr; + +uintptr_t WordlistLanguageTypeRIP = 0; +MID_HOOK_DYNAMIC (WordlistLanguageType, SafetyHookContext &ctx) { + int language = (int)ctx.r12, offset = (int)ctx.rdi; + u64 wordlist = ctx.rbx; + + int fallback = -1; + language = language > 0 && language < languages.size () ? language : 0; + u64 json = 0xFFFFFFFFFFFFi64 & wordlist + offset; + if (jsonHasMember (json, languageTexts[language].c_str ())) { + u64 *data = jsonGetMember (json, languageTexts[language].c_str ()); + if ((*((u16 *)data + 7) & 0x1000) == 0) data = (u64 *)(data[1] & 0xFFFFFFFFFFFF); + taiko_assign ((void *)(ctx.rsp + 0x60), (char *)data, strlen ((char *)data)); + } else if (language == 4 && jsonHasMember (json, languageTexts[2].c_str ())) { + fallback = 2; + u64 *data = jsonGetMember (json, languageTexts[2].c_str ()); + if ((*((u16 *)data + 7) & 0x1000) == 0) data = (u64 *)(data[1] & 0xFFFFFFFFFFFF); + taiko_assign ((void *)(ctx.rsp + 0x60), (char *)data, strlen ((char *)data)); + } else if (language != 0 && jsonHasMember (json, languageTexts[0].c_str ())) { + fallback = 0; + u64 *data = jsonGetMember (json, languageTexts[0].c_str ()); + if ((*((u16 *)data + 7) & 0x1000) == 0) data = (u64 *)(data[1] & 0xFFFFFFFFFFFF); + taiko_assign ((void *)(ctx.rsp + 0x60), (char *)data, strlen ((char *)data)); + } else taiko_assign ((void *)(ctx.rsp + 0x60), "", 0); + + if (fallback != -1) { + if (jsonHasMember (json, languageFontTypes[fallback].c_str ())) { + ctx.rcx = *jsonGetMember (json, languageFontTypes[fallback].c_str ()); + } else ctx.rcx = 0; + } else if (jsonHasMember (json, languageFontTypes[language].c_str ())) { + ctx.rcx = *jsonGetMember (json, languageFontTypes[language].c_str ()); + } else ctx.rcx = 0; + + ctx.rip = WordlistLanguageTypeRIP; +} + +char *languageFla = nullptr; +uintptr_t QrcodeInfoResourceTypeRIP = 0; +MID_HOOK_DYNAMIC (QrcodeInfoResourceType, SafetyHookContext &ctx) { + languageFla = (char *)(ctx.rsp + 0x130); + u64 json = ctx.rbx; + for (int i = 0; i < 4; i ++) { + int lang = language == 4 ? (i == 2 ? 4 : i) : i; + if (jsonHasMember (json, languageFlas[lang].c_str ())) { + u64 *data = jsonGetMember (json, languageFlas[lang].c_str ()); + if ((*((u16 *)data + 7) & 0x1000) == 0) data = (u64 *)(data[1] & 0xFFFFFFFFFFFF); + std_assign (languageFla + i * 0x20, (char *)data, strlen ((char *)data)); + } else if (language == 4 && jsonHasMember (json, languageFlas[2].c_str ())) { + u64 *data = jsonGetMember (json, languageFlas[2].c_str ()); + if ((*((u16 *)data + 7) & 0x1000) == 0) data = (u64 *)(data[1] & 0xFFFFFFFFFFFF); + std_assign (languageFla + i * 0x20, (char *)data, strlen ((char *)data)); + } else if (language != 0 && jsonHasMember (json, languageFlas[0].c_str ())) { + u64 *data = jsonGetMember (json, languageFlas[0].c_str ()); + if ((*((u16 *)data + 7) & 0x1000) == 0) data = (u64 *)(data[1] & 0xFFFFFFFFFFFF); + std_assign (languageFla + i * 0x20, (char *)data, strlen ((char *)data)); + } else std_assign (languageFla + i * 0x20, "", 0); + } + ctx.rip = QrcodeInfoResourceTypeRIP; +} + +std::string CHSGaidenTitle = ""; +MID_HOOK_DYNAMIC (GaidenTitleExtren, SafetyHookContext &ctx) { + LogMessage (LogLevel::DEBUG, "GaidenTitle: {}", (char *)ctx.rcx); + std::string gaidenTitle = std::string ((char *)ctx.rcx); + if (gaidenTitle.find ("[CHS]") != std::string::npos) { + CHSGaidenTitle = gaidenTitle; + } +} +uintptr_t JumpInjectGaidenTitleRIP = 0; +MID_HOOK_DYNAMIC (GaidenTitleInject, SafetyHookContext &ctx) { + // only handle ctx.rdx > 2 2 => lang4 => zh-cn etc. + if (ctx.rdx == 2) { + ctx.rdx = (uintptr_t)CHSGaidenTitle.c_str (); + ctx.r8 = CHSGaidenTitle.size (); + LogMessage (LogLevel::DEBUG, "GaidenTitleInjectCHS title={} length={}", CHSGaidenTitle, CHSGaidenTitle.size ()); + ctx.rip = JumpInjectGaidenTitleRIP; + } +} +MID_HOOK_DYNAMIC (GaidenTitleClean, SafetyHookContext &ctx) { + CHSGaidenTitle = ""; +} +uintptr_t JumpInjectGaidenLanguageRIP = 0; +MID_HOOK_DYNAMIC (GaidenLanguageInject, SafetyHookContext &ctx) { + if (ctx.rbx == 2) { + *(int *)(ctx.rsp + 0x2D8) = 4; + ctx.rip = JumpInjectGaidenLanguageRIP; + } +} + +void +Init () { + switch (gameVersion) { + default: case GameVersion::JPN00: case GameVersion::JPN08: case GameVersion::CHN00: break; + case GameVersion::JPN39: { + jsonHasMember = (JsonHasMember)ASLR (0x1400B5A30); + jsonGetMember = (JsonGetMember)ASLR (0x1400B6080); + vectorIterator = (VectorIterator)ASLR (0x14079C430); + // App::DataTableHolder::Serialize + WordlistLanguageTypeRIP = ASLR (0x1400B20B8); + INSTALL_MID_HOOK_DYNAMIC (WordlistLanguageType, ASLR (0x1400B1E47)); + // App::DataTableHolder::Serialize + QrcodeInfoResourceTypeRIP = ASLR (0x1400B2959); + INSTALL_MID_HOOK_DYNAMIC (QrcodeInfoResourceType, ASLR (0x1400B276E)); + INSTALL_MID_HOOK_DYNAMIC (GaidenTitleExtren, ASLR (0x1403E2224)); + JumpInjectGaidenTitleRIP = ASLR (0x1403E2416); + INSTALL_MID_HOOK_DYNAMIC (GaidenTitleInject, ASLR (0x1403E238F)); + INSTALL_MID_HOOK_DYNAMIC (GaidenTitleClean, ASLR (0x1403E2980)); + JumpInjectGaidenLanguageRIP = ASLR (0x1403E2721); + INSTALL_MID_HOOK_DYNAMIC (GaidenLanguageInject, ASLR (0x1403E26E2)); + } break; + } +} +} + +namespace Script { +FAST_HOOK_DYNAMIC (i64, RefPlayDataManager, i64 a1) { + LogMessage (LogLevel::HOOKS, "RefPlayDataManager was called"); + const auto result = originalRefPlayDataManager.fastcall (a1); + language = *reinterpret_cast (result); + return result; +} +FAST_HOOK_DYNAMIC (i64, GetLanguage, u64 *a1, i64 a2) { + LogMessage (LogLevel::HOOKS, "GetLanguage was called"); + lua_settop (a2, 0); + int langFix = languageFix (language); + const char* type = languageStr (langFix); + lua_pushstring (a2, type); + return 1; +} +FAST_HOOK_DYNAMIC (i64, GetRegionLanguage, i64 a1) { + LogMessage (LogLevel::HOOKS, "GetRegionLanguage was called"); + lua_settop (a1, 0); + int langFix = languageFix (language); + lua_pushstring (a1, languageStr (langFix)); + return 1; +} +std::thread::id *LoadMovieThreadId = nullptr; +FAST_HOOK_DYNAMIC (i64, GetCabinetLanguage, u64 *a1, i64 a2) { + LogMessage (LogLevel::HOOKS, "GetCabinetLanguage was called"); + i64 result = originalGetCabinetLanguage.fastcall (a1, a2); + if (language == 4 && (LoadMovieThreadId == nullptr || *LoadMovieThreadId != std::this_thread::get_id())) { + std_assign ((void *)result, languageStr (2), 5); + } else std_assign ((void *)result, languageStr (language), (language == 0 || language == 3) ? 3 : 5); + return result; +} +FAST_HOOK_DYNAMIC (i64, GetLanguageType, i64 a1) { + LogMessage (LogLevel::HOOKS, "GetLanguageType was called"); + lua_settop (a1, 0); + lua_pushnumber (a1, languageFix (language)); + return 1; +} +void +Init () { + switch (gameVersion) { + default: case GameVersion::JPN00: case GameVersion::JPN08: case GameVersion::CHN00: break; + case GameVersion::JPN39: { + INSTALL_FAST_HOOK_DYNAMIC (RefPlayDataManager, ASLR (0x140024AC0)); + // Export methods for lua invoke + INSTALL_FAST_HOOK_DYNAMIC (GetLanguage, ASLR (0x1401D1930)); + INSTALL_FAST_HOOK_DYNAMIC (GetRegionLanguage, ASLR (0x1401CE9B0)); + INSTALL_FAST_HOOK_DYNAMIC (GetCabinetLanguage, ASLR (0x14014DB80)); + INSTALL_FAST_HOOK_DYNAMIC (GetLanguageType, ASLR (0x1401CECE0)); + } break; + } +} +} + +namespace Lumen { +FAST_HOOK_DYNAMIC (i64, LoadDemoMovie, i64 a1, i64 a2, i64 a3) { + std::thread::id this_id = std::this_thread::get_id(); + Script::LoadMovieThreadId = &this_id; + i64 result = originalLoadDemoMovie.fastcall (a1, a2, a3); + Script::LoadMovieThreadId = nullptr; + return result; +} +std::string onpCn = "textures/onpu_cn/onp_all.nutexb"; +MID_HOOK_DYNAMIC (ChangeOnpFile, SafetyHookContext &ctx) { + if (language != 4) return; + ctx.rdx = (uintptr_t) onpCn.c_str (); + ctx.r8 = 0x1F; +} +void * +GetLanguageType (Taiko_assign assign, int language, void *buf) { + int langFix = languageFix (language); + return assign (buf, languageStr (langFix), (langFix == 0 || langFix == 3) ? 3 : 5); +} +void +InjectLanguageType (uintptr_t language, uintptr_t ®) { + int langFix = languageFix ((int)language); + reg = (uintptr_t)languageStr (langFix); +} + +FAST_HOOK_DYNAMIC (u64, GraphicBaseGetLanguageType, u64 a1, void *a2) { + int language = *(int *)(a1 + 56); + return (u64)GetLanguageType (taiko_assign, language, a2); +} + +void +Init () { + switch (gameVersion) { + default: case GameVersion::JPN00: case GameVersion::JPN08: case GameVersion::CHN00: break; + case GameVersion::JPN39: { + bool demoMovieExistAll = true; + const char *movieToCheck[]{"movie\\attractdemo_cn_cn.wmv", "sound\\attractdemo_cn_cn.nus3bank"}; + for (int i = 0; i < 2; i++) { + if (std::filesystem::exists (std::string ("..\\..\\Data\\x64\\") + movieToCheck[i])) continue; + demoMovieExistAll = false; + } + if (demoMovieExistAll) { + LogMessage (LogLevel::INFO, "Detected attractdemo_cn files, install attractdemo patches!"); + INSTALL_FAST_HOOK_DYNAMIC (LoadDemoMovie, ASLR (0x1404313F0)); + } + + bool onpCnExist = false; + if (std::filesystem::exists (std::string ("..\\..\\Data\\x64\\textures\\onpu_cn\\onp_all.nutexb"))) onpCnExist = true; + if (onpCnExist) { + LogMessage (LogLevel::INFO, "Detected onpu_cn files, install onp patches!"); + INSTALL_MID_HOOK_DYNAMIC (ChangeOnpFile, ASLR (0x140134D16)); + } + language_patch.push_back (safetyhook::create_mid (ASLR (0x140134E22), [](SafetyHookContext &ctx){ + if (ctx.rcx == 4) *(int *)(ctx.r15 + 0x3100) = 2; + else *(int *)(ctx.r15 + 0x3100) = (int)ctx.rcx; + ctx.rip = ASLR (0x140134E29); + })); + + INSTALL_FAST_HOOK_DYNAMIC (GraphicBaseGetLanguageType, ASLR (0x1400E8740)); + language_patch.push_back (safetyhook::create_mid (ASLR (0x1400E8791), [](SafetyHookContext &ctx) + { InjectLanguageType (ctx.rsp + 0x58 + ctx.rax * 8, ctx.rdx); ctx.rip = ASLR (0x1400E8796); })); // HitEffectGetLanguageType + language_patch.push_back (safetyhook::create_mid (ASLR (0x14011F8E4), [](SafetyHookContext &ctx) + { InjectLanguageType (ctx.rbp + 0x57 + ctx.rax * 8, ctx.rdx); ctx.rip = ASLR (0x14011F8E9); })); // KusudamaGetLanguageType + language_patch.push_back (safetyhook::create_mid (ASLR (0x140122404), [](SafetyHookContext &ctx) + { InjectLanguageType (ctx.rbp + 0x140 + ctx.rax * 8, ctx.rdx); ctx.rip = ASLR (0x14012240C); })); // NoteJumpGetLanguageType + language_patch.push_back (safetyhook::create_mid (ASLR (0x14012425E), [](SafetyHookContext &ctx) + { InjectLanguageType (ctx.rbp + 0x57 + ctx.rax * 8, ctx.rdx); ctx.rip = ASLR (0x140124263); })); // RendaEffectGetLanguageType + language_patch.push_back (safetyhook::create_mid (ASLR (0x140129450), [](SafetyHookContext &ctx) + { InjectLanguageType (ctx.rbp + 0x57 + ctx.rax * 8, ctx.rdx); ctx.rip = ASLR (0x140129455); })); // RendaEffectGetLanguageType + language_patch.push_back (safetyhook::create_mid (ASLR (0x14012B8C8), [](SafetyHookContext &ctx) + { InjectLanguageType (ctx.rbp + 0x180 + ctx.rax * 8, ctx.rdx); ctx.rip = ASLR (0x14012B8D0); })); // ScoreGetLanguageType + LayeredFs::RegisterBefore ([&] (const std::string &originalFileName, const std::string ¤tFileName) -> std::string { + if (language != 4 || currentFileName.find ("\\lumen\\") == std::string::npos) return ""; + std::string fileName = currentFileName; + fileName = replace (fileName, "\\lumen\\", "\\lumen_cn\\"); + if (std::filesystem::exists (fileName)) return fileName; + return ""; + }); + + } break; + } +} +} + +namespace Voice { +std::map voiceCnExist; +std::map nus3bankMap; +bool enableSwitchVoice = false; +int nus3bankIdCounter = 0; +std::mutex nus3bankMtx; + +int +get_bank_id (const std::string &bankName) { + if (!nus3bankMap.contains (bankName)) { + nus3bankMap[bankName] = nus3bankIdCounter; + nus3bankIdCounter++; + } + LogMessage (LogLevel::DEBUG, "LoadBank {} id={}", bankName, nus3bankMap[bankName]); + return nus3bankMap[bankName]; +} + +void +check_voice_tail (const std::string &bankName, u8 *pBinfBlock, std::map &voiceExist, const std::string &tail) { + // check if any voice_xxx.nus3bank has xxx_cn audio inside while loading + if (bankName.starts_with ("voice_")) { + const int binfLength = *reinterpret_cast (pBinfBlock + 4); + u8 *pGrpBlock = pBinfBlock + 8 + binfLength; + const int grpLength = *reinterpret_cast (pGrpBlock + 4); + u8 *pDtonBlock = pGrpBlock + 8 + grpLength; + const int dtonLength = *reinterpret_cast (pDtonBlock + 4); + u8 *pToneBlock = pDtonBlock + 8 + dtonLength; + const int toneSize = *reinterpret_cast (pToneBlock + 8); + u8 *pToneBase = pToneBlock + 12; + for (int i = 0; i < toneSize; i++) { + if (*reinterpret_cast (pToneBase + i * 8 + 4) <= 0x0C) continue; // skip empty space + u8 *currToneBase = pToneBase + *reinterpret_cast (pToneBase + i * 8); + int titleOffset = -1; + switch (*currToneBase) { + case 0xFF: titleOffset = 9; break; // audio mark + case 0x7F: titleOffset = 5; break; // randomizer mark + default: continue; // unknown mark skip + } + if (titleOffset > 0) { + std::string title (reinterpret_cast (currToneBase + titleOffset)); + if (title.ends_with (tail)) { + if (!voiceExist.contains (bankName) || !voiceExist[bankName]) { + voiceExist[bankName] = true; + enableSwitchVoice = true; + } + return; + } + } + } + if (!voiceExist.contains (bankName) || voiceExist[bankName]) voiceExist[bankName] = false; + } +} + +void +checkVoiceFile (const char *fileName) { + withFile (fileName, [](u8 *bankData){ + if (bankData[0] == 'N' && bankData[1] == 'U' && bankData[2] == 'S' && bankData[3] == '3') { + const int tocLength = *reinterpret_cast (bankData + 16); + u8 *pPropBlock = bankData + 20 + tocLength; + const int propLength = *reinterpret_cast (pPropBlock + 4); + u8 *pBinfBlock = pPropBlock + 8 + propLength; + const std::string bankName (reinterpret_cast (pBinfBlock + 0x11)); + check_voice_tail (bankName, pBinfBlock, voiceCnExist, "_cn"); + } + }); +} + +MID_HOOK_DYNAMIC (GenNus3bankId, SafetyHookContext &ctx) { + LogMessage (LogLevel::HOOKS, "GenNus3bankId was called"); + std::lock_guard lock (nus3bankMtx); + if (reinterpret_cast (ctx.rcx + 8) != nullptr) { + u8 *pNus3bankFile = *reinterpret_cast (ctx.rcx + 8); + if (pNus3bankFile[0] == 'N' && pNus3bankFile[1] == 'U' && pNus3bankFile[2] == 'S' && pNus3bankFile[3] == '3') { + const int tocLength = *reinterpret_cast (pNus3bankFile + 16); + u8 *pPropBlock = pNus3bankFile + 20 + tocLength; + const int propLength = *reinterpret_cast (pPropBlock + 4); + u8 *pBinfBlock = pPropBlock + 8 + propLength; + const std::string bankName (reinterpret_cast (pBinfBlock + 0x11)); + ctx.rax = get_bank_id (bankName); + } + } +} + +std::string +FixToneName (const std::string &bankName, std::string toneName, int voiceLang) { + if (voiceLang == 1) { + if (voiceCnExist.contains (bankName) && voiceCnExist[bankName]) return toneName + "_cn"; + } + return toneName; +} + +size_t commonSize = 0; +FAST_HOOK_DYNAMIC (i64, PlaySoundMain, i64 a1) { + LogMessage (LogLevel::HOOKS, "PlaySoundMain was called"); + int lang = TestMode::ReadTestModeValue (L"VoiceLanguageItem"); + if (lang > 0) { + const std::string bankName (lua_tolstring (a1, -3, &commonSize)); + if (bankName[0] == 'v') { + lua_pushstring (a1, FixToneName (bankName, lua_tolstring (a1, -2, &commonSize), lang).c_str ()); + lua_replace (a1, -3); + } + } + return originalPlaySoundMain.fastcall (a1); +} + +FAST_HOOK_DYNAMIC (i64, PlaySoundMulti, i64 a1) { + LogMessage (LogLevel::HOOKS, "PlaySoundMulti was called"); + int lang = TestMode::ReadTestModeValue (L"VoiceLanguageItem"); + if (lang > 0) { + const std::string bankName (const_cast (lua_tolstring (a1, -3, &commonSize))); + if (bankName[0] == 'v') { + lua_pushstring (a1, FixToneName (bankName, lua_tolstring (a1, -2, &commonSize), lang).c_str ()); + lua_replace (a1, -3); + } + } + return originalPlaySoundMulti.fastcall (a1); +} + +u64 * +FixToneNameEnso (u64 *Src, const std::string &bankName, int voiceLang) { + if (voiceLang == 1) { + if (voiceCnExist.contains (bankName) && voiceCnExist[bankName]) Src = (u64 *)std_append (Src, "_cn", 3); + } + return Src; +} + +FAST_HOOK_DYNAMIC (bool, PlaySoundEnso, u64 *a1, u64 *a2, i64 a3) { + LogMessage (LogLevel::HOOKS, "PlaySoundEnso was called"); + int lang = TestMode::ReadTestModeValue (L"VoiceLanguageItem"); + if (lang > 0) { + const std::string bankName = a1[3] > 0x10 ? std::string (*reinterpret_cast (a1)) : std::string (reinterpret_cast (a1)); + if (bankName[0] == 'v') a2 = FixToneNameEnso (a2, bankName, lang); + } + return originalPlaySoundEnso.fastcall (a1, a2, a3); +} + +FAST_HOOK_DYNAMIC (bool, PlaySoundSpecial, u64 *a1, u64 *a2) { + LogMessage (LogLevel::HOOKS, "PlaySoundSpecial was called"); + int lang = TestMode::ReadTestModeValue (L"VoiceLanguageItem"); + if (lang > 0) { + const std::string bankName = a1[3] > 0x10 ? std::string (*reinterpret_cast (a1)) : std::string (reinterpret_cast (a1)); + if (bankName[0] == 'v') a2 = FixToneNameEnso (a2, bankName, lang); + } + return originalPlaySoundSpecial.fastcall (a1, a2); +} + +void +Init () { + switch (gameVersion) { + default: case GameVersion::JPN00: case GameVersion::JPN08: case GameVersion::CHN00: break; + case GameVersion::JPN39: { + INSTALL_MID_HOOK_DYNAMIC (GenNus3bankId, ASLR (0x1407B97BD)); + std::vector voiceFiles = { + "voice_aienso_v12g.nus3bank", "voice_airesult_v12g.nus3bank", "voice_aistory_v12g.nus3bank", + "voice_aoharu_v1238.nus3bank", "voice_common_v12a.nus3bank", "voice_daniodai_v12e.nus3bank", + "voice_daniresult_v12e.nus3bank", "voice_enso_v12a.nus3bank", "voice_entry_v12a.nus3bank", + "voice_howtoplay_v12a.nus3bank", "voice_result_v12a.nus3bank", "voice_senkuoku_v12a.nus3bank" + }; + for (std::string voiceFile : voiceFiles) checkVoiceFile (("..\\..\\Data\\x64\\sound\\" + voiceFile).c_str ()); + if (enableSwitchVoice) { + TestMode::RegisterItemAfter( + L"/root/menu[@id='OthersMenu']/layout[@type='Center']/select-item[@id='LanguageItem']", + L"", + [&](){ + INSTALL_FAST_HOOK_DYNAMIC (PlaySoundMain, ASLR (0x1404C6DC0)); + INSTALL_FAST_HOOK_DYNAMIC (PlaySoundMulti, ASLR (0x1404C6D60)); + INSTALL_FAST_HOOK_DYNAMIC (PlaySoundEnso, ASLR (0x1404ED590)); + INSTALL_FAST_HOOK_DYNAMIC (PlaySoundSpecial, ASLR (0x1404ED230)); + } + ); + } + } break; + } +} +} + +void +Init () { + switch (gameVersion) { + default: case GameVersion::JPN00: case GameVersion::JPN08: case GameVersion::CHN00: break; + case GameVersion::JPN39: { + languageFix = [](int lang){ return lang == 4 ? 2 : lang; }; + taiko_string = (Taiko_string)ASLR (0x1400203B0); + taiko_assign = (Taiko_assign)ASLR (0x140020850); + std_assign = (Taiko_assign)ASLR (0x1400209E0); + std_append = (Taiko_assign)ASLR (0x140028DA0); + Language::Font::Init (); + Language::Datatable::Init (); + Language::Script::Init (); + Language::Lumen::Init (); + Language::Voice::Init (); + } break; + } +} +} \ No newline at end of file diff --git a/src/patches/layeredfs.cpp b/src/patches/layeredfs.cpp index 434dbbe..54dfe29 100644 --- a/src/patches/layeredfs.cpp +++ b/src/patches/layeredfs.cpp @@ -251,51 +251,40 @@ LayeredFsHandler (const std::string &originalFileName, const std::string ¤ return ""; // we return an empty string, causing the rest of CreateFileAHook to not update the returned value } -HOOK (HANDLE, CreateFileAHook, PROC_ADDRESS ("kernel32.dll", "CreateFileA"), LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, - LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) { +FAST_HOOK (HANDLE, CreateFileAHook, PROC_ADDRESS ("kernel32.dll", "CreateFileA"), LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, + LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) { bool changed = false; const auto originalFileName = std::string (lpFileName); std::string currentFileName = originalFileName; - LogMessage (LogLevel::HOOKS, ("CreateFileA: " + originalFileName).c_str ()); + LogMessage (LogLevel::HOOKS, "CreateFileA: {}", originalFileName); if (!beforeHandlers.empty ()) { for (const auto handler : beforeHandlers) { std::string result = handler->handlerMethod (originalFileName, currentFileName); - if (result != "") { - currentFileName = result; - changed = true; - } + if (result != "") { currentFileName = result; changed = true; } } } if (useLayeredFs) { const std::string result = LayeredFsHandler (originalFileName, currentFileName); - if (result != "") { - currentFileName = result; - changed = true; - } + if (result != "") { currentFileName = result; changed = true; } } if (!afterHandlers.empty ()) { for (const auto handler : afterHandlers) { std::string result = handler->handlerMethod (originalFileName, currentFileName); - if (result != "") { - currentFileName = result; - changed = true; - } + if (result != "") { currentFileName = result; changed = true; } } } LPCSTR pFinalFileName = changed ? currentFileName.c_str () : lpFileName; - if (changed) LogMessage (LogLevel::DEBUG, "Final Redirect: {}", currentFileName); - return originalCreateFileAHook (pFinalFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, - dwFlagsAndAttributes, hTemplateFile); + if (changed) LogMessage (LogLevel::HOOKS, "Final Redirect: {}", currentFileName); + return originalCreateFileAHook.stdcall (pFinalFileName, dwDesiredAccess, dwShareMode, + lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); } void Init () { - // LogMessage (LogLevel::INFO, "Init LayeredFs patches"); - const auto configPath = std::filesystem::current_path () / "config.toml"; const std::unique_ptr config_ptr (openConfig (configPath), toml_free); if (config_ptr) { @@ -306,17 +295,19 @@ Init () { if (useLayeredFs || !beforeHandlers.empty () || !afterHandlers.empty ()) { LogMessage (LogLevel::INFO, "using LayeredFs! Data_mods={} beforHandlers={} afterHandlers={}", useLayeredFs ? "enabled" : "disabled", beforeHandlers.size (), afterHandlers.size ()); - INSTALL_HOOK (CreateFileAHook); + INSTALL_FAST_HOOK (CreateFileAHook); } } void RegisterBefore (const std::function &fileHandler) { + LogMessage (LogLevel::DEBUG, "Registered Before"); beforeHandlers.push_back (new RegisteredHandler (fileHandler)); } void RegisterAfter (const std::function &fileHandler) { + LogMessage (LogLevel::DEBUG, "Registered After"); afterHandlers.push_back (new RegisteredHandler (fileHandler)); } diff --git a/src/patches/patches.h b/src/patches/patches.h index 4e95601..2bbb60c 100644 --- a/src/patches/patches.h +++ b/src/patches/patches.h @@ -38,10 +38,8 @@ void Init (); } // namespace AmAuth namespace LayeredFs { void Init (); -void RegisterBeforeA (const std::function &fileHandler); -void RegisterAfterA (const std::function &fileHandler); -void RegisterBeforeW (const std::function &fileHandler); -void RegisterAfterW (const std::function &fileHandler); +void RegisterBefore (const std::function &fileHandler); +void RegisterAfter (const std::function &fileHandler); } // namespace LayeredFs namespace TestMode { class Applicable { @@ -121,4 +119,7 @@ std::vector &ReadQRImage (std::vector &buffer); namespace Timer { void Init (); } // namespace timer +namespace Language { +void Init (); +} } // namespace patches diff --git a/src/patches/scanner.cpp b/src/patches/scanner.cpp index 5a574b8..8f8ad2c 100644 --- a/src/patches/scanner.cpp +++ b/src/patches/scanner.cpp @@ -53,7 +53,7 @@ namespace Card { InsertCard (uint8_t cardData[168], bool internalInvoke) { if (callbackTouch) { state = internalInvoke ? State::Disable : State::CopyWait; - patches::Plugins::UpdateStatus (1, false); + patches::Plugins::UpdateStatus (StatusType::CardStatus, false); if (!internalInvoke) { LogMessage (LogLevel::DEBUG, "[Card] Call CallbackTouch!"); for (int i = 0; i < 8; i++) { @@ -73,7 +73,7 @@ namespace Card { InsertError (CardErrorCode errorCode) { if (callbackTouch) { state = State::CopyWait; - patches::Plugins::UpdateStatus (1, false); + patches::Plugins::UpdateStatus (StatusType::CardStatus, false); callbackTouch (0, errorCode, cardData, touchData); } } @@ -82,7 +82,7 @@ namespace Card { AgentCallbackTouch (int32_t a1, int32_t a2, uint8_t *a3, uint64_t a4) { if (callbackTouch) { state = State::CopyWait; - patches::Plugins::UpdateStatus (1, false); + patches::Plugins::UpdateStatus (StatusType::CardStatus, false); callbackTouch (a1, a2, a3, a4); } } @@ -91,7 +91,7 @@ namespace Card { AgentCallbackTouchOfficial (int32_t a1, int32_t a2, uint8_t *a3, uint64_t a4) { if (callbackTouch) { state = State::CopyWait; - patches::Plugins::UpdateStatus (1, false); + patches::Plugins::UpdateStatus (StatusType::CardStatus, false); LogMessage (LogLevel::DEBUG, "Official CallbackTouch a1={} a2={}", a1, a2); if (acceptInvalidCards && !a3[0]) { char AccessId[21] = "00000000000000000001"; @@ -154,7 +154,7 @@ namespace Card { } FAST_HOOK (u64, bngrw_ReqWaitTouch, PROC_ADDRESS ("bngrw.dll", "BngRwReqWaitTouch"), u32 a1, i32 a2, u32 a3, CallbackTouch callback, u64 a5) { state = State::Ready; - patches::Plugins::UpdateStatus (1, true); + patches::Plugins::UpdateStatus (StatusType::CardStatus, true); patches::Plugins::WaitTouch (Internal::AgentCallbackTouch, a5); callbackTouch = callback; touchData = a5; @@ -164,13 +164,13 @@ namespace Card { HOOK (i64, bngrw_ReqCancelOfficial, PROC_ADDRESS ("bngrw.dll", "BngRwReqCancel"), u32 a1) { if (state != State::Disable) { state = State::Disable; - patches::Plugins::UpdateStatus (1, false); + patches::Plugins::UpdateStatus (StatusType::CardStatus, false); } return originalbngrw_ReqCancelOfficial (a1); } HOOK (u64, bngrw_ReqWaitTouchOfficial, PROC_ADDRESS ("bngrw.dll", "BngRwReqWaitTouch"), u32 a1, i32 a2, u32 a3, CallbackTouch callback, u64 a5) { state = State::Ready; - patches::Plugins::UpdateStatus (1, true); + patches::Plugins::UpdateStatus (StatusType::CardStatus, true); callbackTouch = callback; touchData = a5; return originalbngrw_ReqWaitTouchOfficial (a1, a2, a3, Internal::AgentCallbackTouchOfficial, a5); @@ -291,7 +291,7 @@ namespace Qr { scanQueue.pop (); } state = State::Ready; - patches::Plugins::UpdateStatus (2, true); + patches::Plugins::UpdateStatus (StatusType::QrStatus, true); } return 0; } @@ -339,7 +339,7 @@ namespace Qr { if (state != State::Disable) { if ((lastScan + 200) < std::chrono::duration_cast(std::chrono::system_clock::now ().time_since_epoch ()).count ()) { state = State::Disable; - patches::Plugins::UpdateStatus (2, false); + patches::Plugins::UpdateStatus (StatusType::QrStatus, false); } else { void *plugin = patches::Plugins::CheckQr (); if (plugin) { diff --git a/src/patches/testmode.cpp b/src/patches/testmode.cpp index dede594..d00a7e4 100644 --- a/src/patches/testmode.cpp +++ b/src/patches/testmode.cpp @@ -17,25 +17,6 @@ std::thread *hookInstall; std::mutex hooksMutex; std::condition_variable hooksCV; -// void -// AddHookInLoop (std::function installMethod) { -// // hooks.push (installMethod); -// hooksCV.notify_all (); -// } - -// void -// HookInstallLoop () { -// std::unique_lock hooksLock(hooksMutex); -// while (!hookInstallFinished) { -// while (!hooks.empty ()) { -// auto installMethod = hooks.front (); -// hooks.pop (); -// if (installMethod) installMethod (); -// } -// if (!hookInstallFinished) hooksCV.wait (hooksLock); -// } -// } - std::wstring mergeCondition (std::wstring original, std::wstring addition, std::wstring value) { size_t pos = original.find (L"/"); @@ -56,18 +37,6 @@ addConditionValue (pugi::xml_node *node, std::wstring key, std::wstring addition attr.set_value (mergeCondition(attr.value (), addition, value).c_str ()); } else node->append_attribute (key.c_str ()) = std::format(L"True/{}:{}", addition, value).c_str (); } -class RegisteredHook : public Applicable { -public: - std::function registerInit; - RegisteredHook (const std::function &initMethod) { - this->registerInit = initMethod; - } - pugi::xml_node * - Apply (pugi::xml_node *doc, pugi::xml_node *node) override { - // AddHookInLoop (this->registerInit); - return node; - } -}; class RegisteredItem : public Applicable { public: std::wstring selectItem; @@ -237,26 +206,27 @@ Menu *modManager = new RegisteredMenu (L"MOD MANAGER", L"ModManagerMenu"); // std::vector registeredItems = {}; std::vector registeredSingleItems = {}; std::vector registeredModifies = {}; -std::vector registeredHooks = {}; std::wstring moddedInitial = L""; std::wstring modded = L""; +std::wstring originalDeviceInitialize = L""; +std::wstring usingDeviceInitialize = L""; +std::wstring moddedDeviceInitialize = L"DeviceInitialize_mod.xml"; +std::wstring originalTestMode = L""; +std::wstring usingTestMode = L""; +std::wstring moddedTestMode = L"TestMode_mod.xml"; + u64 appAccessor = 0; RefTestModeMain refTestMode = nullptr; -std::wstring -ReadXMLFileSwitcher (std::wstring &fileName) { - const std::size_t pos = fileName.rfind (L"/"); - const std::wstring file = fileName.substr (pos + 1, fileName.size ()); - std::wstring base = fileName.substr (0, pos + 1); +FAST_HOOK_DYNAMIC (char, SceneTestModeLoading, u64 a1, u64 a2, u64 a3) { + char result = originalSceneTestModeLoading.fastcall (a1, a2, a3); + return result; +} - if (gameVersion == GameVersion::JPN39 && chsPatch) { - if (file.starts_with (L"DeviceInitialize")) base.append (L"DeviceInitialize_china.xml"); - if (file.starts_with (L"TestMode")) base.append (L"TestMode_china.xml"); - if (std::filesystem::exists (base)) return base; - } - - return fileName; +FAST_HOOK_DYNAMIC (char, SceneTestModeFinalize, u64 a1, u64 a2, u64 a3) { + char result = originalSceneTestModeFinalize.fastcall (a1, a2, a3); + return result; } FAST_HOOK_DYNAMIC (void, TestModeSetMenuHook, u64 testModeLibrary, const wchar_t *lFileName) { @@ -264,17 +234,15 @@ FAST_HOOK_DYNAMIC (void, TestModeSetMenuHook, u64 testModeLibrary, const wchar_t const auto originalFileName = std::wstring (lFileName); LogMessage (LogLevel::DEBUG, L"Begin Loading {}", originalFileName); std::wstring fileName = originalFileName; - if (fileName.ends_with (L"DeviceInitialize.xml") || fileName.ends_with (L"DeviceInitialize_asia.xml") - || fileName.ends_with (L"DeviceInitialize_china.xml")) { + if (fileName.ends_with (originalDeviceInitialize)) { if (moddedInitial == L"") { - fileName = ReadXMLFileSwitcher (fileName); + fileName = replace (originalFileName, originalDeviceInitialize, usingDeviceInitialize); if (pugi::xml_document doc; !doc.load_file (fileName.c_str ())) { LogMessage (LogLevel::ERROR, L"Loading DeviceInitialize structure failed! path: " + fileName); - moddedInitial = fileName; + moddedInitial = originalFileName; + fileName = originalFileName; } else { - const std::wstring modFileName - = replace (replace (replace (fileName, L"lize_asia.xml", L"lize_mod.xml"), L"lize_china.xml", L"lize_mod.xml"), L"lize.xml", - L"lize_mod.xml"); + const std::wstring modFileName = replace (originalFileName, originalDeviceInitialize, moddedDeviceInitialize); const pugi::xpath_query dongleQuery = pugi::xpath_query (L"/root/menu[@id='TopMenu']/layout[@type='Center']/select-item[@id='DongleItem']"); const pugi::xml_node dongleItem = doc.select_node (dongleQuery).node (); pugi::xml_node talItem = dongleItem.parent ().append_copy (dongleItem); @@ -288,17 +256,16 @@ FAST_HOOK_DYNAMIC (void, TestModeSetMenuHook, u64 testModeLibrary, const wchar_t fileName = modFileName; } } else fileName = moddedInitial; - } else if (fileName.ends_with (L"TestMode.xml") || fileName.ends_with (L"TestMode_asia.xml") || fileName.ends_with (L"TestMode_china.xml")) { + } else if (fileName.ends_with (originalTestMode)) { if (modded == L"") { if (!((RegisteredMenu*)modManager)->items.empty () || registeredSingleItems.empty () || !registeredModifies.empty ()) { - fileName = ReadXMLFileSwitcher (fileName); + fileName = replace (originalFileName, originalTestMode, usingTestMode); if (pugi::xml_document doc; !doc.load_file (fileName.c_str ())) { LogMessage (LogLevel::ERROR, L"Loading TestMode structure failed! path: " + fileName); - modded = fileName; + modded = originalFileName; + fileName = originalFileName; } else { - const std::wstring modFileName - = replace (replace (replace (fileName, L"Mode_asia.xml", L"Mode_mod.xml"), L"Mode_china.xml", L"Mode_mod.xml"), L"Mode.xml", - L"Mode_mod.xml"); + const std::wstring modFileName = replace (originalFileName, originalTestMode, moddedTestMode); if (!((RegisteredMenu*)modManager)->items.empty ()) { LogMessage (LogLevel::DEBUG, "Begin generate Mod Manager menu"); pugi::xpath_query menuQuery @@ -320,13 +287,6 @@ FAST_HOOK_DYNAMIC (void, TestModeSetMenuHook, u64 testModeLibrary, const wchar_t LogMessage (LogLevel::DEBUG, "End Apply Modify Items"); } - if (!registeredHooks.empty ()) { - LogMessage (LogLevel::DEBUG, "Begin Apply Hooks"); - for (RegisteredHook *hook : registeredHooks) hook->Apply (&doc, &doc); - LogMessage (LogLevel::DEBUG, "End Apply Hooks"); - } - - // AddHookInLoop ([&](){ hookInstallFinished = true; }); [[maybe_unused]] auto _ = doc.save_file (modFileName.c_str ()); modded = modFileName; fileName = modFileName; @@ -340,16 +300,6 @@ FAST_HOOK_DYNAMIC (void, TestModeSetMenuHook, u64 testModeLibrary, const wchar_t originalTestModeSetMenuHook.fastcall (testModeLibrary, fileName.c_str ()); } -// HOOK_DYNAMIC (void, TestModeGetValueHook, u64 *reader, const wchar_t *lItemName, int *value) { -// originalTestModeGetValueHook (reader, lItemName, value); -// LogMessage (LogLevel::DEBUG, L"TestMode get Item: {} Value: {}", lItemName, *value); -// } - -// HOOK_DYNAMIC (void, TestModeSetValueHook, u64 *reader, const wchar_t *lItemName, int value) { -// LogMessage (LogLevel::DEBUG, L"TestMode set Item: {} Value: {}", lItemName, value); -// originalTestModeSetValueHook (reader, lItemName, value); -// } - void CommonModify () { // Default off Close time @@ -482,28 +432,29 @@ void Init () { LogMessage (LogLevel::INFO, "Init TestMode patches"); - const auto configPath = std::filesystem::current_path () / "config.toml"; - const std::unique_ptr config_ptr (openConfig (configPath), toml_free); - const u64 testModeLibrary = (u64)GetModuleHandle ("TestModeLibrary.dll"); const u64 testModeSetMenu = testModeLibrary + 0x99D0; - // const u64 testModeGetValue = testModeLibrary + 0x6FB18; - // const u64 testModeSetValue = testModeLibrary + 0x6FAC8; - LogMessage (LogLevel::DEBUG, "TestModeLibrary: {}", testModeLibrary); - // LogMessage (LogLevel::DEBUG, "TestModeLibrary set: {}", testModeSetValue); - // LogMessage (LogLevel::DEBUG, "TestModeLibrary get: {}", testModeGetValue); switch (gameVersion) { case GameVersion::UNKNOWN: break; case GameVersion::JPN00: break; case GameVersion::JPN08: break; case GameVersion::JPN39: { - if (config_ptr) { - if (const auto patches = openConfigSection (config_ptr.get (), "patches")) { - if (const auto jpn39 = openConfigSection (patches, "jpn39")) chsPatch = readConfigBool (jpn39, "chs_patch", chsPatch); - } - } - if (chsPatch) LocalizationCHT (); + INSTALL_FAST_HOOK_DYNAMIC (SceneTestModeLoading, ASLR (0x1404793D0)); + INSTALL_FAST_HOOK_DYNAMIC (SceneTestModeFinalize, ASLR (0x140479600)); + originalDeviceInitialize = L"DeviceInitialize.xml"; + if (std::filesystem::exists ("..\\..\\Data\\x64\\testmode\\DeviceInitialize_chspatch.xml")) { + usingDeviceInitialize = L"DeviceInitialize_chspatch.xml"; + WRITE_MEMORY (ASLR (0x140CD1E40), wchar_t, L"加載中\0"); + WRITE_MEMORY (ASLR (0x140CD1E28), wchar_t, L"加載中.\0"); + WRITE_MEMORY (ASLR (0x140CD1E68), wchar_t, L"加載中..\0"); + WRITE_MEMORY (ASLR (0x140CD1E50), wchar_t, L"加載中...\0"); + } else usingDeviceInitialize = originalDeviceInitialize; + originalTestMode = L"TestMode.xml"; + if (std::filesystem::exists ("..\\..\\Data\\x64\\testmode\\TestMode_chspatch.xml")) { + usingTestMode = L"TestMode_chspatch.xml"; + } else usingTestMode = originalTestMode; + } break; case GameVersion::CHN00: break; } @@ -512,8 +463,6 @@ Init () { INSTALL_FAST_HOOK_DYNAMIC (TestModeSetMenuHook, testModeSetMenu); for (auto method : hooks) method (); - // INSTALL_HOOK_DYNAMIC (TestModeGetValueHook, testModeGetValue); - // INSTALL_HOOK_DYNAMIC (TestModeSetValueHook, testModeSetValue); } void @@ -528,13 +477,10 @@ ReadTestModeValue (const wchar_t *itemId) { if (const u64 testModeMain = refTestMode (appAccessor)) { int value = 0; u64 *reader = *reinterpret_cast (testModeMain + 16); - // LogMessage (LogLevel::DEBUG, "TestMode get:{} set:{}", *reader + 256, *reader + 176); (*reinterpret_cast (*reader + 256)) (reader, itemId, &value); - // originalTestModeGetValueHook (reader, itemId, &value); return value; } } - LogMessage (LogLevel::ERROR, (std::wstring (L"Read TestMode(") + itemId + L") failed!").c_str ()); return -1; } @@ -544,7 +490,6 @@ SetTestModeValue (const wchar_t *itemId, int value) { if (const u64 testModeMain = refTestMode (appAccessor)) { u64 *reader = *reinterpret_cast (testModeMain + 16); (*reinterpret_cast (*reader + 176)) (reader, itemId, value); - // ((TestModeSetValueHook)whereTestModeSetMenuHook) (reader, itemId, value); } } } @@ -629,7 +574,6 @@ void RegisterHook (const std::function &initMethod) { LogMessage (LogLevel::DEBUG, L"Register Hook"); hooks.push_back (initMethod); - // registeredHooks.push_back (new RegisteredHook (initMethod)); } void diff --git a/src/patches/versions/JPN39.cpp b/src/patches/versions/JPN39.cpp index 6ee5022..028d3fc 100644 --- a/src/patches/versions/JPN39.cpp +++ b/src/patches/versions/JPN39.cpp @@ -192,195 +192,11 @@ CHANGE_RESULT_INDEX_HOOK (ChangeResultDataIndex_AI, ASLR (0x140173EDD), r13, 0x2 CHANGE_RESULT_INDEX_HOOK (ChangeResultDataIndex_Collabo025_026, ASLR (0x1401789AD), r13, 0x24, 0x08); CHANGE_RESULT_INDEX_HOOK (ChangeResultDataIndex_AprilFool, ASLR (0x140176716), rax, 0x34, 0x06); -FAST_HOOK (i64, GetLanguage, ASLR (0x140024AC0), i64 a1) { - LogMessage (LogLevel::HOOKS, "GetLanguage was called"); - const auto result = originalGetLanguage.fastcall (a1); - language = *reinterpret_cast (result); - return result; -} -FAST_HOOK (i64, GetRegionLanguage, ASLR (0x1401CE9B0), i64 a1) { - LogMessage (LogLevel::HOOKS, "GetRegionLanguage was called"); - if (patches::TestMode::ReadTestModeValue (L"ModFixLanguage") == 1) { - lua_settop (a1, 0); - lua_pushstring (a1, languageStr (language)); - return 1; - } else return originalGetRegionLanguage.fastcall (a1); -} -std::thread::id *LoadMovieThreadId = nullptr; -FUNCTION_PTR (void **, std_string_assign, ASLR (0x1400209E0), void **, const void *, size_t); -FAST_HOOK (i64, GetCabinetLanguage, ASLR (0x14014DB80), u64 *a1, i64 a2) { - LogMessage (LogLevel::HOOKS, "GetCabinetLanguage was called"); - i64 result = originalGetCabinetLanguage.fastcall (a1, a2); - if (patches::TestMode::ReadTestModeValue (L"ModFixLanguage") == 1) { - if (language == 2 && LoadMovieThreadId != nullptr && *LoadMovieThreadId == std::this_thread::get_id()) { - LogMessage (LogLevel::DEBUG, "Loading DemoMovie cn_tw, redirect to cn_cn"); - std_string_assign ((void **)result, (const void*)languageStr (4), 5); - } else { - std_string_assign ((void **)result, (const void*)languageStr (language), (language == 0 || language == 3) ? 3 : 5); - } - } - return result; -} -FAST_HOOK (i64, LoadDemoMovie, ASLR (0x1404313F0), i64 a1, i64 a2, i64 a3) { - std::thread::id this_id = std::this_thread::get_id(); - LoadMovieThreadId = &this_id; - i64 result = originalLoadDemoMovie.fastcall (a1, a2, a3); - LoadMovieThreadId = nullptr; - return result; -} -std::string onpCn = "textures/onpu_cn/onp_all.nutexb"; -MID_HOOK (ChangeOnpFile, ASLR (0x140134D16), SafetyHookContext &ctx) { - if (language == 2 && patches::TestMode::ReadTestModeValue (L"ModFixLanguage") == 1) { - LogMessage (LogLevel::DEBUG, "Load onp_all_cn"); - ctx.rdx = (uintptr_t) onpCn.c_str (); - ctx.r8 = 0x1F; - } -} - -MID_HOOK (ChangeLanguageType, ASLR (0x1400B2016), SafetyHookContext &ctx) { - LogMessage (LogLevel::HOOKS, "ChangeLanguageType was called"); - if (const auto pFontType = reinterpret_cast (ctx.rax); *pFontType == 4) *pFontType = 2; -} - MID_HOOK (CountLockedCrown, ASLR (0x1403F2A25), SafetyHookContext &ctx) { LogMessage (LogLevel::HOOKS, "CountLockedCrown was called"); ctx.r15 |= 1; } -std::map nus3bankMap; -int nus3bankIdCounter = 0; -std::map voiceCnExist; -bool enableSwitchVoice = false; -std::mutex nus3bankMtx; - -int -get_bank_id (const std::string &bankName) { - if (!nus3bankMap.contains (bankName)) { - nus3bankMap[bankName] = nus3bankIdCounter; - nus3bankIdCounter++; - } - LogMessage (LogLevel::DEBUG, "LoadBank {} id={}", bankName, nus3bankMap[bankName]); - return nus3bankMap[bankName]; -} - -void -check_voice_tail (const std::string &bankName, u8 *pBinfBlock, std::map &voiceExist, const std::string &tail) { - // check if any voice_xxx.nus3bank has xxx_cn audio inside while loading - if (bankName.starts_with ("voice_")) { - const int binfLength = *reinterpret_cast (pBinfBlock + 4); - u8 *pGrpBlock = pBinfBlock + 8 + binfLength; - const int grpLength = *reinterpret_cast (pGrpBlock + 4); - u8 *pDtonBlock = pGrpBlock + 8 + grpLength; - const int dtonLength = *reinterpret_cast (pDtonBlock + 4); - u8 *pToneBlock = pDtonBlock + 8 + dtonLength; - const int toneSize = *reinterpret_cast (pToneBlock + 8); - u8 *pToneBase = pToneBlock + 12; - for (int i = 0; i < toneSize; i++) { - if (*reinterpret_cast (pToneBase + i * 8 + 4) <= 0x0C) continue; // skip empty space - u8 *currToneBase = pToneBase + *reinterpret_cast (pToneBase + i * 8); - int titleOffset = -1; - switch (*currToneBase) { - case 0xFF: titleOffset = 9; break; // audio mark - case 0x7F: titleOffset = 5; break; // randomizer mark - default: continue; // unknown mark skip - } - if (titleOffset > 0) { - std::string title (reinterpret_cast (currToneBase + titleOffset)); - if (title.ends_with (tail)) { - if (!voiceExist.contains (bankName) || !voiceExist[bankName]) { - voiceExist[bankName] = true; - enableSwitchVoice = true; - } - return; - } - } - } - if (!voiceExist.contains (bankName) || voiceExist[bankName]) voiceExist[bankName] = false; - } -} - -MID_HOOK (GenNus3bankId, ASLR (0x1407B97BD), SafetyHookContext &ctx) { - LogMessage (LogLevel::HOOKS, "GenNus3bankId was called"); - std::lock_guard lock (nus3bankMtx); - if (reinterpret_cast (ctx.rcx + 8) != nullptr) { - u8 *pNus3bankFile = *reinterpret_cast (ctx.rcx + 8); - if (pNus3bankFile[0] == 'N' && pNus3bankFile[1] == 'U' && pNus3bankFile[2] == 'S' && pNus3bankFile[3] == '3') { - const int tocLength = *reinterpret_cast (pNus3bankFile + 16); - u8 *pPropBlock = pNus3bankFile + 20 + tocLength; - const int propLength = *reinterpret_cast (pPropBlock + 4); - u8 *pBinfBlock = pPropBlock + 8 + propLength; - const std::string bankName (reinterpret_cast (pBinfBlock + 0x11)); - check_voice_tail (bankName, pBinfBlock, voiceCnExist, "_cn"); - ctx.rax = get_bank_id (bankName); - } - } -} - -std::string -FixToneName (const std::string &bankName, std::string toneName, int voiceLang) { - if (voiceLang == 1) { - if (voiceCnExist.contains (bankName) && voiceCnExist[bankName]) return toneName + "_cn"; - } - return toneName; -} - -size_t commonSize = 0; -FAST_HOOK (i64, PlaySoundMain, ASLR (0x1404C6DC0), i64 a1) { - LogMessage (LogLevel::HOOKS, "PlaySoundMain was called"); - int lang = TestMode::ReadTestModeValue (L"VoiceLanguageItem"); - if (enableSwitchVoice && lang != 0) { - const std::string bankName (lua_tolstring (a1, -3, &commonSize)); - if (bankName[0] == 'v') { - lua_pushstring (a1, FixToneName (bankName, lua_tolstring (a1, -2, &commonSize), lang).c_str ()); - lua_replace (a1, -3); - } - } - return originalPlaySoundMain.fastcall (a1); -} - -FAST_HOOK (i64, PlaySoundMulti, ASLR (0x1404C6D60), i64 a1) { - LogMessage (LogLevel::HOOKS, "PlaySoundMulti was called"); - int lang = TestMode::ReadTestModeValue (L"VoiceLanguageItem"); - if (enableSwitchVoice && lang != 0) { - const std::string bankName (const_cast (lua_tolstring (a1, -3, &commonSize))); - if (bankName[0] == 'v') { - lua_pushstring (a1, FixToneName (bankName, lua_tolstring (a1, -2, &commonSize), lang).c_str ()); - lua_replace (a1, -3); - } - } - return originalPlaySoundMulti.fastcall (a1); -} - -FUNCTION_PTR (u64 *, append_chars_to_basic_string, ASLR (0x140028DA0), u64 *, const char *, size_t); - -u64 * -FixToneNameEnso (u64 *Src, const std::string &bankName, int voiceLang) { - if (voiceLang == 1) { - if (voiceCnExist.contains (bankName) && voiceCnExist[bankName]) Src = append_chars_to_basic_string (Src, "_cn", 3); - } - return Src; -} - -FAST_HOOK (bool, PlaySoundEnso, ASLR (0x1404ED590), u64 *a1, u64 *a2, i64 a3) { - LogMessage (LogLevel::HOOKS, "PlaySoundEnso was called"); - int lang = TestMode::ReadTestModeValue (L"VoiceLanguageItem"); - if (enableSwitchVoice && lang != 0) { - const std::string bankName = a1[3] > 0x10 ? std::string (*reinterpret_cast (a1)) : std::string (reinterpret_cast (a1)); - if (bankName[0] == 'v') a2 = FixToneNameEnso (a2, bankName, lang); - } - return originalPlaySoundEnso.fastcall (a1, a2, a3); -} - -FAST_HOOK (bool, PlaySoundSpecial, ASLR (0x1404ED230), u64 *a1, u64 *a2) { - LogMessage (LogLevel::HOOKS, "PlaySoundSpecial was called"); - int lang = TestMode::ReadTestModeValue (L"VoiceLanguageItem"); - if (enableSwitchVoice && lang != 0) { - const std::string bankName = a1[3] > 0x10 ? std::string (*reinterpret_cast (a1)) : std::string (reinterpret_cast (a1)); - if (bankName[0] == 'v') a2 = FixToneNameEnso (a2, bankName, lang); - } - return originalPlaySoundSpecial.fastcall (a1, a2); -} - int loaded_fail_count = 0; FAST_HOOK (char, LoadedBankAll, ASLR (0x1404EC2F0), u64 a1) { LogMessage (LogLevel::HOOKS, "LoadedBankAll was called"); @@ -405,68 +221,52 @@ FAST_HOOK (i32, SetMasterVolumeSpeaker, ASLR (0x140160330), i32 a1) { return originalSetMasterVolumeSpeaker.fastcall (a1 > 100 ? 100 : a1); } -// std::string *fontName = nullptr; -// HOOK (u8, SetupFontInfo, ASLR (0x14049D820), u64 a1, u64 a2, size_t a3, u64 a4) { -// LogMessage (LogLevel::HOOKS, "SetupFontInfo was called"); -// if (fontName != nullptr) delete fontName; -// fontName = new std::string (reinterpret_cast (a1) + 120); -// return originalSetupFontInfo (a1, a2, a3, a4); -// } - -// HOOK (u32, ReadFontInfoInt, ASLR (0x14049EAC0), u64 a1, u64 a2) { -// LogMessage (LogLevel::HOOKS, "ReadFontInfoInt was called"); -// const std::string attribute (reinterpret_cast (a2)); -// u32 result = originalReadFontInfoInt (a1, a2); -// if (fontName->starts_with ("cn_") && attribute == "offsetV") result += 1; -// return result; -// } - MID_HOOK (AttractDemo, ASLR (0x14045A720), SafetyHookContext &ctx) { if (TestMode::ReadTestModeValue (L"AttractDemoItem") == 1) ctx.r14 = 0; } -FAST_HOOK (u64, EnsoGameManagerInitialize, ASLR (0x1400E2520), u64 a1, u64 a2, u64 a3) { - LogMessage (LogLevel::DEBUG, "Begin EnsoGameManagerInitialize"); - u64 result = originalEnsoGameManagerInitialize.fastcall (a1, a2, a3); - LogMessage (LogLevel::DEBUG, "End EnsoGameManagerInitialize result={}", result); - return result; -} +// FAST_HOOK (u64, EnsoGameManagerInitialize, ASLR (0x1400E2520), u64 a1, u64 a2, u64 a3) { +// LogMessage (LogLevel::DEBUG, "Begin EnsoGameManagerInitialize"); +// u64 result = originalEnsoGameManagerInitialize.fastcall (a1, a2, a3); +// LogMessage (LogLevel::DEBUG, "End EnsoGameManagerInitialize result={}", result); +// return result; +// } -FAST_HOOK (u64, EnsoGameManagerLoading, ASLR (0x1400E2750), u64 a1, u64 a2, u64 a3) { - LogMessage (LogLevel::DEBUG, "Begin EnsoGameManagerLoading"); - u64 result = originalEnsoGameManagerLoading.fastcall (a1, a2, a3); - LogMessage (LogLevel::DEBUG, "End EnsoGameManagerLoading result={}", result); - return result; -} +// FAST_HOOK (u64, EnsoGameManagerLoading, ASLR (0x1400E2750), u64 a1, u64 a2, u64 a3) { +// LogMessage (LogLevel::DEBUG, "Begin EnsoGameManagerLoading"); +// u64 result = originalEnsoGameManagerLoading.fastcall (a1, a2, a3); +// LogMessage (LogLevel::DEBUG, "End EnsoGameManagerLoading result={}", result); +// return result; +// } -FAST_HOOK (bool, EnsoGameManagerPreparing, ASLR (0x1400E2990), u64 a1, u64 a2, u64 a3) { - LogMessage (LogLevel::DEBUG, "Begin EnsoGameManagerPreparing"); - bool result = originalEnsoGameManagerPreparing.fastcall (a1, a2, a3); // crashes here - LogMessage (LogLevel::DEBUG, "End EnsoGameManagerPreparing result={}", result); - return result; -} +// FAST_HOOK (bool, EnsoGameManagerPreparing, ASLR (0x1400E2990), u64 a1, u64 a2, u64 a3) { +// LogMessage (LogLevel::DEBUG, "Begin EnsoGameManagerPreparing"); +// bool result = originalEnsoGameManagerPreparing.fastcall (a1, a2, a3); // crashes here +// LogMessage (LogLevel::DEBUG, "End EnsoGameManagerPreparing result={}", result); +// return result; +// } -FAST_HOOK (u64, EnsoGraphicManagerPreparing, ASLR (0x1400F0AB0), u64 a1, u64 a2, u64 a3) { - LogMessage (LogLevel::DEBUG, "Begin EnsoGraphicManagerPreparing"); - u64 result = originalEnsoGraphicManagerPreparing.fastcall (a1, a2, a3); - LogMessage (LogLevel::DEBUG, "End EnsoGraphicManagerPreparing result={}", result); - return result; -} +// FAST_HOOK (u64, EnsoGraphicManagerPreparing, ASLR (0x1400F0AB0), u64 a1, u64 a2, u64 a3) { +// LogMessage (LogLevel::DEBUG, "Begin EnsoGraphicManagerPreparing"); +// u64 result = originalEnsoGraphicManagerPreparing.fastcall (a1, a2, a3); +// LogMessage (LogLevel::DEBUG, "End EnsoGraphicManagerPreparing result={}", result); +// return result; +// } -FAST_HOOK (u64, EnsoGameManagerStart, ASLR (0x1400E2A10), u64 a1, u64 a2, u64 a3) { - LogMessage (LogLevel::DEBUG, "Begin EnsoGameManagerStart"); - u64 result = originalEnsoGameManagerStart.fastcall (a1, a2, a3); - LogMessage (LogLevel::DEBUG, "End EnsoGameManagerStart result={}", result); - return result; -} +// FAST_HOOK (u64, EnsoGameManagerStart, ASLR (0x1400E2A10), u64 a1, u64 a2, u64 a3) { +// LogMessage (LogLevel::DEBUG, "Begin EnsoGameManagerStart"); +// u64 result = originalEnsoGameManagerStart.fastcall (a1, a2, a3); +// LogMessage (LogLevel::DEBUG, "End EnsoGameManagerStart result={}", result); +// return result; +// } -FAST_HOOK (u64, EnsoGameManagerChechEnsoEnd, ASLR (0x1400E2A10), u64 a1, u64 a2, u64 a3) { - LogMessage (LogLevel::DEBUG, "Begin EnsoGameManagerChechEnsoEnd"); - u64 result = originalEnsoGameManagerChechEnsoEnd.fastcall (a1, a2, a3); - LogMessage (LogLevel::DEBUG, "End EnsoGameManagerChechEnsoEnd result={}", result); - return result; -} +// FAST_HOOK (u64, EnsoGameManagerChechEnsoEnd, ASLR (0x1400E2A10), u64 a1, u64 a2, u64 a3) { +// LogMessage (LogLevel::DEBUG, "Begin EnsoGameManagerChechEnsoEnd"); +// u64 result = originalEnsoGameManagerChechEnsoEnd.fastcall (a1, a2, a3); +// LogMessage (LogLevel::DEBUG, "End EnsoGameManagerChechEnsoEnd result={}", result); +// return result; +// } // HOOK (DWORD*, AcquireMostCompatibleDisplayMode, ASLR (0x14064C870), i64 a1, DWORD *a2, DWORD *a3) { // LogMessage (LogLevel::DEBUG, "AcquireMostCompatibleDisplayMode {:d} {:d} {:f} {:f}", a3[0], a3[1], (float)(int)a3[2], (float)(int)a3[3]); @@ -475,24 +275,6 @@ FAST_HOOK (u64, EnsoGameManagerChechEnsoEnd, ASLR (0x1400E2A10), u64 a1, u64 a2, // return originalAcquireMostCompatibleDisplayMode (a1, a2, a3); // } -FAST_HOOK (char, SceneTestModeLoading, ASLR (0x1404793D0), u64 a1, u64 a2, u64 a3) { - // LogMessage (LogLevel::DEBUG, "Begin SceneTestModeLoading"); - char result = originalSceneTestModeLoading.fastcall (a1, a2, a3); - // LogMessage (LogLevel::DEBUG, "End originalSceneTestModeLoading result={}", (int)result); - TestMode::SetTestModeValue (L"EnableSwitchVoice", (int)enableSwitchVoice); - // if (!enableSwitchVoice) TestMode::SetTestModeValue (L"VoiceLanguageItem", 0); - // LogMessage (LogLevel::DEBUG, "End SceneTestModeLoading"); - return result; -} - -MID_HOOK (LogLoadTexture12, ASLR (0x14065BC8A), SafetyHookContext &ctx) { - char* src = (char*)(ctx.rsp + 0x2B0); - if (src != nullptr) { - std::string srcStr = std::string (src); - LogMessage (LogLevel::HOOKS, "LogLoadTexture12 src={}", srcStr); - } else LogMessage (LogLevel::HOOKS, "LogLoadTexture12 src=nullptr"); -} - constexpr i32 datatableBufferSize = 1024 * 1024 * 12; uint8_t *datatableBuffer[3] = { nullptr }; std::vector datatable_patch = {}; @@ -550,7 +332,6 @@ Init () { // Hook to get AppAccessor and ComponentAccessor INSTALL_FAST_HOOK (DeviceCheck); INSTALL_FAST_HOOK (luaL_newstate); - INSTALL_MID_HOOK (LogLoadTexture12); // INSTALL_HOOK (AcquireMostCompatibleDisplayMode); // Apply common config patch @@ -591,52 +372,6 @@ Init () { // Remove datatable size limit ReplaceDatatableBufferAddresses (); - // { - // for (auto address : memsetSizeAddresses) - // WRITE_MEMORY (ASLR (address) + 2, i32, datatableBufferSize); - - // auto bufferBase = MODULE_HANDLE - 0x03000000; - // AllocateStaticBufferNear (bufferBase, datatableBufferSize, &datatableBuffer1); - // bufferBase += datatableBufferSize; - // AllocateStaticBufferNear (bufferBase, datatableBufferSize, &datatableBuffer2); - // bufferBase += datatableBufferSize; - // AllocateStaticBufferNear (bufferBase, datatableBufferSize, &datatableBuffer3); - - // ReplaceLeaBufferAddress (datatableBuffer1Addresses, datatableBuffer1.data ()); - // ReplaceLeaBufferAddress (datatableBuffer2Addresses, datatableBuffer2.data ()); - // ReplaceLeaBufferAddress (datatableBuffer3Addresses, datatableBuffer3.data ()); - // } - - // Language - TestMode::Menu *langPatchesMenu = TestMode::CreateMenu (L"LANGUAGE PATCHES", L"LanguagePatchesMenu"); - TestMode::Menu *langResourceIndicator = TestMode::CreateMenu (L"RESOURCE INDICATOR", L"LanguageResourceIndicatorMenu"); - TestMode::RegisterItem ( - L"", - [&]() { - INSTALL_FAST_HOOK (GetLanguage); - INSTALL_FAST_HOOK (GetRegionLanguage); - INSTALL_FAST_HOOK (GetCabinetLanguage); - }, langPatchesMenu - ); - TestMode::RegisterItem( - L"", - langResourceIndicator - ); - TestMode::RegisterItemAfter( - L"/root/menu[@id='OthersMenu']/layout[@type='Center']/select-item[@id='LanguageItem']", - L"", - [&](){ - INSTALL_FAST_HOOK (PlaySoundMain); - INSTALL_FAST_HOOK (PlaySoundMulti); - INSTALL_FAST_HOOK (PlaySoundEnso); - INSTALL_FAST_HOOK (PlaySoundSpecial); - } - ); - TestMode::RegisterItem(langResourceIndicator, langPatchesMenu); - TestMode::RegisterItem(langPatchesMenu); // Unlock Songs TestMode::RegisterItem ( @@ -713,20 +448,10 @@ Init () { ); TestMode::RegisterItemAfter( L"/root/menu[@id='OthersMenu']/layout[@type='Center']/select-item[@id='AttractMovieItem']", - L"", [&](){ INSTALL_MID_HOOK (AttractDemo); } ); - TestMode::RegisterHook([&](){ - INSTALL_FAST_HOOK (EnsoGameManagerInitialize); - INSTALL_FAST_HOOK (EnsoGameManagerLoading); - INSTALL_FAST_HOOK (EnsoGameManagerPreparing); - INSTALL_FAST_HOOK (EnsoGraphicManagerPreparing); - INSTALL_FAST_HOOK (EnsoGameManagerStart); - INSTALL_FAST_HOOK (EnsoGameManagerChechEnsoEnd); - INSTALL_FAST_HOOK (SceneTestModeLoading); - }); - // for (size_t i=0; i < 40; i++) TestMode::RegisterItem(std::format (L"", i + 1)); // Instant Result // TestMode::RegisterModify( @@ -735,63 +460,8 @@ Init () { // [&](){} // ); - // Use chs font/wordlist instead of cht - if (chsPatch) { - WRITE_MEMORY (ASLR (0x140CD1E40), wchar_t, L"加載中\0"); - WRITE_MEMORY (ASLR (0x140CD1E28), wchar_t, L"加載中.\0"); - WRITE_MEMORY (ASLR (0x140CD1E68), wchar_t, L"加載中..\0"); - WRITE_MEMORY (ASLR (0x140CD1E50), wchar_t, L"加載中...\0"); - - bool fontExistAll = true; - const char *fontToCheck[]{"cn_30.nutexb", "cn_30.xml", "cn_32.nutexb", "cn_32.xml", "cn_64.nutexb", "cn_64.xml"}; - for (int i = 0; i < 6; i++) { - if (useLayeredfs && std::filesystem::exists (std::string ("..\\..\\Data_mods\\x64\\font\\") + fontToCheck[i])) continue; - if (std::filesystem::exists (std::string ("..\\..\\Data\\x64\\font\\") + fontToCheck[i])) continue; - fontExistAll = false; - } - if (fontExistAll) { - LogMessage (LogLevel::INFO, "Font all exist, using chs_patch font part!"); - WRITE_MEMORY (ASLR (0x140CD1AE0), char, "cn_64"); - WRITE_MEMORY (ASLR (0x140CD1AF0), char, "cn_32"); - WRITE_MEMORY (ASLR (0x140CD1AF8), char, "cn_30"); - WRITE_MEMORY (ASLR (0x140C946A0), char, "chineseSText"); - WRITE_MEMORY (ASLR (0x140C946B0), char, "chineseSFontType"); - INSTALL_MID_HOOK (ChangeLanguageType); - // INSTALL_HOOK (SetupFontInfo); - // INSTALL_HOOK (ReadFontInfoInt); - } - - bool demoMovieExistAll = true; - const char *movieToCheck[]{"movie\\attractdemo_cn_cn.wmv", "sound\\attractdemo_cn_cn.nus3bank"}; - for (int i = 0; i < 2; i++) { - if (useLayeredfs && std::filesystem::exists (std::string ("..\\..\\Data_mods\\x64\\") + movieToCheck[i])) continue; - if (std::filesystem::exists (std::string ("..\\..\\Data\\x64\\") + movieToCheck[i])) continue; - demoMovieExistAll = false; - } - if (demoMovieExistAll) { - LogMessage (LogLevel::INFO, "Resource all exist, using chs_patch attractdemo part!"); - INSTALL_FAST_HOOK (LoadDemoMovie); - } - - bool onpCnExist = false; - if (useLayeredfs && std::filesystem::exists (std::string ("..\\..\\Data_mods\\x64\\textures\\onpu_cn\\onp_all.nutexb"))) onpCnExist = true; - if (std::filesystem::exists (std::string ("..\\..\\Data\\x64\\textures\\onpu_cn\\onp_all.nutexb"))) onpCnExist = true; - if (onpCnExist) { - LogMessage (LogLevel::INFO, "onpu_cn/onp_all exist, using chs_patch onp part!"); - INSTALL_MID_HOOK (ChangeOnpFile); - } - - // LayeredFs::RegisterBeforeA ([=] (const std::string &originalFileName, const std::string ¤tFileName) -> std::string { - // if (currentFileName.find ("\\lumen\\") == std::string::npos) return ""; - // std::string fileName = currentFileName; - // fileName = replace (fileName, "\\lumen\\", "\\lumen_cn\\"); - // if (std::filesystem::exists (fileName)) return fileName; - // return ""; - // }); - } - // Fix normal song play after passing through silent song - INSTALL_MID_HOOK (GenNus3bankId); + // INSTALL_MID_HOOK (GenNus3bankId); INSTALL_FAST_HOOK (LoadedBankAll); // Disable live check diff --git a/src/pollasync.cpp b/src/pollasync.cpp index 361adad..a16ea99 100644 --- a/src/pollasync.cpp +++ b/src/pollasync.cpp @@ -20,10 +20,11 @@ uint8_t controllerDiff[SDL_GAMEPAD_BUTTON_COUNT] = { 0 }; char currentMouseWheelDirection = 0; uint8_t mouseWheelCount[2] = { 0 }; uint8_t mouseWheelDiff[2] = { 0 }; - -int maxCount = 1; - SDLAxisState currentControllerAxisState; +uint8_t controllerAxisCount[SDL_AXIS_MAX] = { 0 }; +uint8_t controllerAxisDiff[SDL_AXIS_MAX] = { 0 }; + +int maxCount = 2; SDL_Window *window; SDL_Gamepad *controllers[255]; @@ -136,19 +137,60 @@ LRESULT CALLBACK InputProc(int nCode, WPARAM wParam, LPARAM lParam) { return CallNextHookEx(keyboardHook, nCode, wParam, lParam); } -void -InitializeKeyboard () { - keyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, InputProc, nullptr, 0); +LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { + switch (msg) { + case WM_DESTROY: PostQuitMessage(0); break; + default: return DefWindowProc(hwnd, msg, wParam, lParam); + } + return 0; +} + +HWND CreateInvisibleWindow(HINSTANCE hInstance) { + WNDCLASS wc = {0}; + wc.lpfnWndProc = WndProc; + wc.hInstance = hInstance; + wc.lpszClassName = "InvisibleWindowClass"; + if (!RegisterClass(&wc)) return nullptr; + HWND hwnd = CreateWindowEx( + WS_EX_LAYERED | WS_EX_TOOLWINDOW, + wc.lpszClassName, + "Invisible Window", + 0, 0, 0, 0, 0, + NULL, NULL, hInstance, NULL + ); + if (hwnd) SetLayeredWindowAttributes(hwnd, RGB(0, 0, 0), 0, LWA_COLORKEY); + return hwnd; +} + +void KeyboardMainLoop() { + HINSTANCE hInstance = GetModuleHandle(NULL); + HWND hwnd = CreateInvisibleWindow(hInstance); + if (!hwnd) LogMessage (LogLevel::ERROR, "Failed to create window!\n"); + keyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, InputProc, nullptr, 0); if (keyboardHook == nullptr) LogMessage (LogLevel::ERROR, "Failed to install keyboard hook!\n"); mouseHook = SetWindowsHookEx(WH_MOUSE_LL, InputProc, nullptr, 0); - if (maxCount > 1) LogMessage (LogLevel::ERROR, "CHEATING MODE! max count is set to {}", maxCount); - atexit (DisposeKeyboard); + if (mouseHook == nullptr) LogMessage (LogLevel::ERROR, "Failed to install mouse hook!\n"); + if (maxCount > 2) LogMessage (LogLevel::ERROR, "CHEATING MODE! max count is set to {}", maxCount); + LogMessage (LogLevel::WARN, "(experimental) Using Async IO!"); + MSG msg; + while (GetMessage(&msg, hwnd, 0, 0) > 0) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + if (keyboardHook) UnhookWindowsHookEx(keyboardHook); + if (mouseHook) UnhookWindowsHookEx(mouseHook); +} + +void +InitializeKeyboard () { + std::thread (KeyboardMainLoop).detach (); + // atexit (DisposeKeyboard); } void DisposeKeyboard () { - if (keyboardHook) UnhookWindowsHookEx(keyboardHook); - if (mouseHook) UnhookWindowsHookEx(mouseHook); + // if (keyboardHook) UnhookWindowsHookEx(keyboardHook); + // if (mouseHook) UnhookWindowsHookEx(mouseHook); } void @@ -261,7 +303,9 @@ UpdatePoll (HWND windowHandle, bool useController) { // ScreenToClient (windowHandle, ¤tMouseState.Position); if (useController) { for (int i=0; i 0 ? 32767.0f : -32768.0f); if (wndForeground || sensorValue == 0) { switch (event.gaxis.axis) { - case SDL_GAMEPAD_AXIS_LEFTX: currentControllerAxisState.LeftRight = sensorValue; break; - case SDL_GAMEPAD_AXIS_LEFTY: currentControllerAxisState.LeftDown = sensorValue; break; - case SDL_GAMEPAD_AXIS_RIGHTX: currentControllerAxisState.RightRight = sensorValue; break; - case SDL_GAMEPAD_AXIS_RIGHTY: currentControllerAxisState.RightDown = sensorValue; break; - case SDL_GAMEPAD_AXIS_LEFT_TRIGGER: currentControllerAxisState.LTriggerDown = sensorValue; break; - case SDL_GAMEPAD_AXIS_RIGHT_TRIGGER: currentControllerAxisState.RTriggerDown = sensorValue; break; - } + case SDL_GAMEPAD_AXIS_LEFTX: if (sensorValue < 0) { + currentControllerAxisState.LeftRight = 0.0f; + if (currentControllerAxisState.LeftLeft == 0.0f) { + controllerAxisCount[SDL_AXIS_LEFT_LEFT] = std::min (controllerAxisCount[SDL_AXIS_LEFT_LEFT] + 1, maxCount); + } + currentControllerAxisState.LeftLeft = -sensorValue; + } else { + currentControllerAxisState.LeftLeft = 0.0f; + if (currentControllerAxisState.LeftRight == 0.0f) { + controllerAxisCount[SDL_AXIS_LEFT_RIGHT] = std::min (controllerAxisCount[SDL_AXIS_LEFT_RIGHT] + 1, maxCount); + } + currentControllerAxisState.LeftRight = sensorValue; + } break; + case SDL_GAMEPAD_AXIS_LEFTY: if (sensorValue < 0) { + currentControllerAxisState.LeftDown = 0.0f; + if (currentControllerAxisState.LeftUp == 0.0f) { + controllerAxisCount[SDL_AXIS_LEFT_UP] = std::min (controllerAxisCount[SDL_AXIS_LEFT_UP] + 1, maxCount); + } + currentControllerAxisState.LeftUp = -sensorValue; + } else { + currentControllerAxisState.LeftUp = 0.0f; + if (currentControllerAxisState.LeftDown == 0.0f) { + controllerAxisCount[SDL_AXIS_LEFT_DOWN] = std::min (controllerAxisCount[SDL_AXIS_LEFT_DOWN] + 1, maxCount); + } + currentControllerAxisState.LeftDown = sensorValue; + } break; + case SDL_GAMEPAD_AXIS_RIGHTX: if (sensorValue < 0) { + currentControllerAxisState.RightRight = 0.0f; + if (currentControllerAxisState.RightLeft == 0.0f) { + controllerAxisCount[SDL_AXIS_RIGHT_LEFT] = std::min (controllerAxisCount[SDL_AXIS_RIGHT_LEFT] + 1, maxCount); + } + currentControllerAxisState.RightLeft = -sensorValue; + } else { + currentControllerAxisState.RightLeft = 0.0f; + if (currentControllerAxisState.RightRight == 0.0f) { + controllerAxisCount[SDL_AXIS_RIGHT_RIGHT] = std::min (controllerAxisCount[SDL_AXIS_RIGHT_RIGHT] + 1, maxCount); + } + currentControllerAxisState.RightRight = sensorValue; + } break; + case SDL_GAMEPAD_AXIS_RIGHTY: if (sensorValue < 0) { + currentControllerAxisState.RightDown = 0.0f; + if (currentControllerAxisState.RightUp == 0.0f) { + controllerAxisCount[SDL_AXIS_RIGHT_UP] = std::min (controllerAxisCount[SDL_AXIS_RIGHT_UP] + 1, maxCount); + } + currentControllerAxisState.RightUp = -sensorValue; + } else { + currentControllerAxisState.RightUp = 0.0f; + if (currentControllerAxisState.RightDown == 0.0f) { + controllerAxisCount[SDL_AXIS_RIGHT_DOWN] = std::min (controllerAxisCount[SDL_AXIS_RIGHT_DOWN] + 1, maxCount); + } + currentControllerAxisState.RightDown = sensorValue; + } break; + case SDL_GAMEPAD_AXIS_LEFT_TRIGGER: { + if (currentControllerAxisState.LTriggerDown == 0.0f) { + controllerAxisCount[SDL_AXIS_LTRIGGER_DOWN] = std::min (controllerAxisCount[SDL_AXIS_LTRIGGER_DOWN] + 1, maxCount); + } + currentControllerAxisState.LTriggerDown = sensorValue; + } break; + case SDL_GAMEPAD_AXIS_RIGHT_TRIGGER: { + if (currentControllerAxisState.RTriggerDown == 0.0f) { + controllerAxisCount[SDL_AXIS_RTRIGGER_DOWN] = std::min (controllerAxisCount[SDL_AXIS_RTRIGGER_DOWN] + 1, maxCount); + } + currentControllerAxisState.RTriggerDown = sensorValue; + } break; + } break; } - break; } } } @@ -371,10 +472,6 @@ int maxKeyboardCount = 1; bool KeyboardIsTapped (const uint8_t keycode) { if (keyboardCount[keycode] > 0) { - // if (maxKeyboardCount < keyboardCount[keycode]) { - // maxKeyboardCount = keyboardCount[keycode]; - // LogMessage (LogLevel::DEBUG, "MAX KEYBOARD COLLECTED {} {}", keycode, maxKeyboardCount); - // } keyboardDiff[keycode] = 1; keyboardClean = true; return true; @@ -402,10 +499,6 @@ bool GetMouseScrollIsTapped (const Scroll scroll) { if (scroll == MOUSE_SCROLL_INVALID) return false; if (mouseWheelCount[scroll - 1] > 0) { - // if (maxWheelCount < mouseWheelCount[scroll - 1]) { - // maxWheelCount = mouseWheelCount[scroll - 1]; - // LogMessage (LogLevel::DEBUG, "MAX WHEEL COLLECTED {} {}", (int)scroll, maxWheelCount); - // } mouseWheelDiff[scroll - 1] = 1; return true; } return false; @@ -420,10 +513,6 @@ int maxButtonCount = 1; bool ControllerButtonIsTapped (const SDL_GamepadButton button) { if (controllerCount[button] > 0) { - // if (maxButtonCount < controllerCount[button]) { - // maxButtonCount = controllerCount[button]; - // LogMessage (LogLevel::DEBUG, "MAX BUTTON COLLECTED {} {}", (int)button, maxButtonCount); - // } controllerDiff[button] = 1; return true; } return false; @@ -442,18 +531,20 @@ ControllerAxisIsDown (const SDLAxis axis) { case SDL_AXIS_RIGHT_DOWN: return currentControllerAxisState.RightDown; case SDL_AXIS_LTRIGGER_DOWN: return currentControllerAxisState.LTriggerDown; case SDL_AXIS_RTRIGGER_DOWN: return currentControllerAxisState.RTriggerDown; - default: return false; + default: return 0.0f; } } bool ControllerAxisIsTapped (const SDLAxis axis) { - return ControllerAxisIsDown (axis); + if (controllerAxisCount[axis] > 0) { + controllerAxisDiff[axis] = 1; + return true; + } return false; } bool IsButtonTapped (const Keybindings &bindings) { - for (size_t i = 0; i < ConfigKeyboardButtonsCount; i++) { if (bindings.keycodes[i] == 0) continue; if (KeyboardIsTapped (bindings.keycodes[i])) return true; @@ -471,7 +562,6 @@ IsButtonTapped (const Keybindings &bindings) { if (GetMouseScrollIsTapped (bindings.scroll[i])) return true; } return false; - // return GetInternalButtonState (bindings).Tapped; } float @@ -493,6 +583,5 @@ IsButtonDown (const Keybindings &bindings) { if (GetMouseScrollIsDown (bindings.scroll[i])) return 1.0f; } return 0.0f; - // return GetInternalButtonState (bindings).Down; } #endif \ No newline at end of file From 2267d827903c97a4f182be108bde0b67f94defb0 Mon Sep 17 00:00:00 2001 From: ptmaster Date: Sun, 22 Dec 2024 00:02:50 +0800 Subject: [PATCH 03/11] Fix Axis | season title | clean up --- src/bnusio.cpp | 57 ++++---- src/dllmain.cpp | 6 +- src/helpers.cpp | 16 ++- src/helpers.h | 5 +- src/patches/language.cpp | 28 +++- src/patches/versions/JPN39.cpp | 7 - src/poll.h | 4 +- src/pollasync.cpp | 251 ++++++++++++++------------------- 8 files changed, 180 insertions(+), 194 deletions(-) diff --git a/src/bnusio.cpp b/src/bnusio.cpp index 459d0fb..dcbb38f 100644 --- a/src/bnusio.cpp +++ b/src/bnusio.cpp @@ -62,7 +62,8 @@ u16 service_count = 0; bool inited = false; bool updateByCoin = false; HWND windowHandle = nullptr; -bool usePoll = false; +float axisThreshold = 0.6f; +u8 inputState = 0; HKL currentLayout; namespace bnusio { @@ -207,9 +208,8 @@ FUNCTION_PTR (i64, bnusio_ResetCoin_Original, PROC_ADDRESS ("bnusio_original.dll u16 __fastcall AnalogInputAxis (const u8 which) { - const u16 analogValue = static_cast (32768 * ControllerAxisIsDown (analogBindings[which])); - if (analogValue > 100) return analogValue; - else return 0; + u16 analogIn = (u16)(32768 * ControllerAxisIsDown (analogBindings[which])) + 1; + return analogIn > 100 ? analogIn : 0; } u16 __fastcall @@ -307,7 +307,7 @@ UpdateLoop () { if (IsButtonTapped (COIN_ADD)) coin_count++; if (IsButtonTapped (SERVICE)) service_count++; if (IsButtonTapped (TEST)) testEnabled = !testEnabled; - if (IsButtonTapped (EXIT)) { + if (exited == 0 && IsButtonTapped (EXIT)) { LogMessage (LogLevel::INFO, "Exit By Press Exit Button!"); exited += 1; testEnabled = 1; std::thread([](){patches::Plugins::Exit ();}).detach(); } @@ -369,33 +369,30 @@ Init () { const auto keyConfigPath = std::filesystem::current_path () / "keyconfig.toml"; const std::unique_ptr keyConfig_ptr (openConfig (keyConfigPath), toml_free); if (keyConfig_ptr) { - if (analogInput) usePoll = true; + if (analogInput) inputState |= (1 << 2); const toml_table_t *keyConfig = keyConfig_ptr.get (); - SetConfigValue (keyConfig, "EXIT", &EXIT, &usePoll); + SetConfigValue (keyConfig, "EXIT", &EXIT, &inputState); - SetConfigValue (keyConfig, "TEST", &TEST, &usePoll); - SetConfigValue (keyConfig, "SERVICE", &SERVICE, &usePoll); - SetConfigValue (keyConfig, "DEBUG_UP", &DEBUG_UP, &usePoll); - SetConfigValue (keyConfig, "DEBUG_DOWN", &DEBUG_DOWN, &usePoll); - SetConfigValue (keyConfig, "DEBUG_ENTER", &DEBUG_ENTER, &usePoll); + SetConfigValue (keyConfig, "TEST", &TEST, &inputState); + SetConfigValue (keyConfig, "SERVICE", &SERVICE, &inputState); + SetConfigValue (keyConfig, "DEBUG_UP", &DEBUG_UP, &inputState); + SetConfigValue (keyConfig, "DEBUG_DOWN", &DEBUG_DOWN, &inputState); + SetConfigValue (keyConfig, "DEBUG_ENTER", &DEBUG_ENTER, &inputState); - SetConfigValue (keyConfig, "COIN_ADD", &COIN_ADD, &usePoll); - SetConfigValue (keyConfig, "CARD_INSERT_1", &CARD_INSERT_1, &usePoll); - SetConfigValue (keyConfig, "CARD_INSERT_2", &CARD_INSERT_2, &usePoll); - SetConfigValue (keyConfig, "QR_DATA_READ", &QR_DATA_READ, &usePoll); - SetConfigValue (keyConfig, "QR_IMAGE_READ", &QR_IMAGE_READ, &usePoll); + SetConfigValue (keyConfig, "COIN_ADD", &COIN_ADD, &inputState); + SetConfigValue (keyConfig, "CARD_INSERT_1", &CARD_INSERT_1, &inputState); + SetConfigValue (keyConfig, "CARD_INSERT_2", &CARD_INSERT_2, &inputState); + SetConfigValue (keyConfig, "QR_DATA_READ", &QR_DATA_READ, &inputState); + SetConfigValue (keyConfig, "QR_IMAGE_READ", &QR_IMAGE_READ, &inputState); - SetConfigValue (keyConfig, "P1_LEFT_BLUE", &P1_LEFT_BLUE, &usePoll); - SetConfigValue (keyConfig, "P1_LEFT_RED", &P1_LEFT_RED, &usePoll); - SetConfigValue (keyConfig, "P1_RIGHT_RED", &P1_RIGHT_RED, &usePoll); - SetConfigValue (keyConfig, "P1_RIGHT_BLUE", &P1_RIGHT_BLUE, &usePoll); - SetConfigValue (keyConfig, "P2_LEFT_BLUE", &P2_LEFT_BLUE, &usePoll); - SetConfigValue (keyConfig, "P2_LEFT_RED", &P2_LEFT_RED, &usePoll); - SetConfigValue (keyConfig, "P2_RIGHT_RED", &P2_RIGHT_RED, &usePoll); - SetConfigValue (keyConfig, "P2_RIGHT_BLUE", &P2_RIGHT_BLUE, &usePoll); - if (!usePoll) { - LogMessage (LogLevel::WARN, "Only Keyboard config detected, disable poll!"); - } + SetConfigValue (keyConfig, "P1_LEFT_BLUE", &P1_LEFT_BLUE, &inputState); + SetConfigValue (keyConfig, "P1_LEFT_RED", &P1_LEFT_RED, &inputState); + SetConfigValue (keyConfig, "P1_RIGHT_RED", &P1_RIGHT_RED, &inputState); + SetConfigValue (keyConfig, "P1_RIGHT_BLUE", &P1_RIGHT_BLUE, &inputState); + SetConfigValue (keyConfig, "P2_LEFT_BLUE", &P2_LEFT_BLUE, &inputState); + SetConfigValue (keyConfig, "P2_LEFT_RED", &P2_LEFT_RED, &inputState); + SetConfigValue (keyConfig, "P2_RIGHT_RED", &P2_RIGHT_RED, &inputState); + SetConfigValue (keyConfig, "P2_RIGHT_BLUE", &P2_RIGHT_BLUE, &inputState); } if (!emulateUsio && !exists (std::filesystem::current_path () / "bnusio_original.dll")) { @@ -464,7 +461,7 @@ void Update () { if (!inited) { windowHandle = FindWindowA ("nuFoundation.Window", nullptr); - if (usePoll) InitializePoll (windowHandle); + InitializePoll (windowHandle); if (autoIme) { currentLayout = GetKeyboardLayout (0); auto engLayout = LoadKeyboardLayout (TEXT ("00000409"), KLF_ACTIVATE); @@ -474,7 +471,7 @@ Update () { patches::Plugins::Init (); inited = true; } - UpdatePoll (windowHandle, usePoll); + UpdatePoll (windowHandle); syncCV.notify_all (); } #endif diff --git a/src/dllmain.cpp b/src/dllmain.cpp index af4440a..1852129 100644 --- a/src/dllmain.cpp +++ b/src/dllmain.cpp @@ -151,9 +151,9 @@ DllMain (HMODULE module, const DWORD reason, LPVOID reserved) { InitializeLogger (GetLogLevel (logLevelStr), logToFile); patches::Timer::Init (); - #ifdef ASYNC_IO - InitializeKeyboard (); - #endif + // #ifdef ASYNC_IO + // InitializeKeyboard (); + // #endif LogMessage (LogLevel::INFO, "Loading config..."); diff --git a/src/helpers.cpp b/src/helpers.cpp index 8e5ec58..a557ef4 100644 --- a/src/helpers.cpp +++ b/src/helpers.cpp @@ -104,7 +104,7 @@ readConfigIntArray (const toml_table_t *table, const std::string &key, std::vect } std::wstring -replace (const std::wstring &orignStr, const std::wstring &oldStr, const std::wstring &newStr) { +replace (const std::wstring orignStr, const std::wstring &oldStr, const std::wstring &newStr) { size_t pos = 0; std::wstring tempStr = orignStr; const std::wstring::size_type newStrLen = newStr.length (); @@ -121,7 +121,7 @@ replace (const std::wstring &orignStr, const std::wstring &oldStr, const std::ws } std::string -replace (const std::string &orignStr, const std::string &oldStr, const std::string &newStr) { +replace (const std::string orignStr, const std::string &oldStr, const std::string &newStr) { size_t pos = 0; std::string tempStr = orignStr; const std::string::size_type newStrLen = newStr.length (); @@ -200,4 +200,16 @@ withFile (const char *fileName, std::function callback) { free (buffer); fclose (file); +} + +std::string +season () { + std::time_t time = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); + std::tm* tm = std::localtime(&time); + int month = tm->tm_mon + 1; + return std::to_string (tm->tm_year + 1900) + ( + (month >= 3 && month <= 5) ? "spr" : + (month >= 6 && month <= 8) ? "sum" : + (month >= 9 && month <= 11) ? "aut" : "win" + ); } \ No newline at end of file diff --git a/src/helpers.h b/src/helpers.h index 7ed853a..e0b1eeb 100644 --- a/src/helpers.h +++ b/src/helpers.h @@ -217,10 +217,11 @@ bool readConfigBool (const toml_table_t *table, const std::string &key, bool not i64 readConfigInt (const toml_table_t *table, const std::string &key, i64 notFoundValue); std::string readConfigString (const toml_table_t *table, const std::string &key, const std::string ¬FoundValue); std::vector readConfigIntArray (const toml_table_t *table, const std::string &key, std::vector notFoundValue); -std::wstring replace (const std::wstring &orignStr, const std::wstring &oldStr, const std::wstring &newStr); -std::string replace (const std::string &orignStr, const std::string &oldStr, const std::string &newStr); +std::wstring replace (const std::wstring orignStr, const std::wstring &oldStr, const std::wstring &newStr); +std::string replace (const std::string orignStr, const std::string &oldStr, const std::string &newStr); const char *GameVersionToString (GameVersion version); const char *languageStr (int language); std::string ConvertWideToUtf8 (const std::wstring &wstr); bool AreAllBytesZero (const u8 *array, size_t offset, size_t length); void withFile (const char *fileName, std::function callback); +std::string season (); diff --git a/src/patches/language.cpp b/src/patches/language.cpp index abf9f3d..4edcb24 100644 --- a/src/patches/language.cpp +++ b/src/patches/language.cpp @@ -374,6 +374,8 @@ FAST_HOOK_DYNAMIC (u64, GraphicBaseGetLanguageType, u64 a1, void *a2) { return (u64)GetLanguageType (taiko_assign, language, a2); } +std::string *season_nulm = nullptr; +std::string *season_nutexb = nullptr; void Init () { switch (gameVersion) { @@ -416,12 +418,34 @@ Init () { language_patch.push_back (safetyhook::create_mid (ASLR (0x14012B8C8), [](SafetyHookContext &ctx) { InjectLanguageType (ctx.rbp + 0x180 + ctx.rax * 8, ctx.rdx); ctx.rip = ASLR (0x14012B8D0); })); // ScoreGetLanguageType LayeredFs::RegisterBefore ([&] (const std::string &originalFileName, const std::string ¤tFileName) -> std::string { - if (language != 4 || currentFileName.find ("\\lumen\\") == std::string::npos) return ""; - std::string fileName = currentFileName; + if (language != 4 || currentFileName.starts_with ("F:\\") || currentFileName.find ("\\lumen\\") == std::string::npos) return ""; + std::string fileName = std::string (currentFileName); fileName = replace (fileName, "\\lumen\\", "\\lumen_cn\\"); if (std::filesystem::exists (fileName)) return fileName; return ""; }); + + LayeredFs::RegisterBefore ([&] (const std::string &originalFileName, const std::string ¤tFileName) -> std::string { + if (language != 4 || currentFileName.starts_with ("F:\\")) return ""; + if (currentFileName.ends_with ("title.nulm")) { + std::string fileName = std::string (currentFileName); + if (season_nulm == nullptr) { + fileName = replace (fileName, "title.nulm", "title_season.nulm"); + if (std::filesystem::exists (fileName)) { + std::string nutexb = std::string (currentFileName); + nutexb = replace (nutexb, "title.nulm", "title_" + season () + ".nutexb"); + if (std::filesystem::exists (nutexb)) { + season_nulm = new std::string (fileName), season_nutexb = new std::string (nutexb); + return *season_nulm; + } + } + season_nulm = new std::string (""), season_nutexb = new std::string (""); + return ""; + } else return *season_nulm; + } else if (currentFileName.ends_with ("title.nutexb") && season_nutexb != nullptr) { + return *season_nutexb; + } else return ""; + }); } break; } diff --git a/src/patches/versions/JPN39.cpp b/src/patches/versions/JPN39.cpp index 028d3fc..fe56ef0 100644 --- a/src/patches/versions/JPN39.cpp +++ b/src/patches/versions/JPN39.cpp @@ -305,17 +305,12 @@ Init () { i32 yRes = 1080; bool vsync = false; bool unlockSongs = true; - bool chsPatch = false; - bool useLayeredfs = false; auto configPath = std::filesystem::current_path () / "config.toml"; std::unique_ptr config_ptr (openConfig (configPath), toml_free); if (config_ptr) { if (auto patches = openConfigSection (config_ptr.get (), "patches")) { unlockSongs = readConfigBool (patches, "unlock_songs", unlockSongs); - if (auto jpn39 = openConfigSection (patches, "jpn39")) { - chsPatch = readConfigBool (jpn39, "chs_patch", chsPatch); - } } if (auto graphics = openConfigSection (config_ptr.get (), "graphics")) { @@ -325,8 +320,6 @@ Init () { } vsync = readConfigBool (graphics, "vsync", vsync); } - - if (auto layeredfs = openConfigSection (config_ptr.get (), "layeredfs")) useLayeredfs = readConfigBool (layeredfs, "enabled", useLayeredfs); } // Hook to get AppAccessor and ComponentAccessor diff --git a/src/poll.h b/src/poll.h index 29e7d8c..90ec0ac 100644 --- a/src/poll.h +++ b/src/poll.h @@ -68,7 +68,7 @@ bool InitializePoll (HWND windowHandle); void DisposePoll (); void SetKeyboardButtons (); ConfigValue StringToConfigEnum (const char *value); -void SetConfigValue (const toml_table_t *table, const char *key, Keybindings *keybind, bool *usePoll); +void SetConfigValue (const toml_table_t *table, const char *key, Keybindings *keybind, u8 *inputState); InternalButtonState GetInternalButtonState (const Keybindings &bindings); void SetRumble (int left, int right, int length); @@ -108,7 +108,7 @@ bool ControllerAxisWasUp (const SDLAxis axis); bool ControllerAxisIsReleased (const SDLAxis axis); bool IsButtonReleased (const Keybindings &bindings); #else -void UpdatePoll (HWND windowHandle, bool useController); +void UpdatePoll (HWND windowHandle); void InitializeKeyboard (); void DisposeKeyboard (); #endif \ No newline at end of file diff --git a/src/pollasync.cpp b/src/pollasync.cpp index a16ea99..1366a33 100644 --- a/src/pollasync.cpp +++ b/src/pollasync.cpp @@ -7,6 +7,8 @@ extern bool jpLayout; extern int exited; +extern u8 inputState; +extern float axisThreshold; bool wndForeground = false; @@ -20,11 +22,12 @@ uint8_t controllerDiff[SDL_GAMEPAD_BUTTON_COUNT] = { 0 }; char currentMouseWheelDirection = 0; uint8_t mouseWheelCount[2] = { 0 }; uint8_t mouseWheelDiff[2] = { 0 }; -SDLAxisState currentControllerAxisState; +// SDLAxisState currentControllerAxisState; +float currentControllerAxisState[SDL_AXIS_MAX] = { 0.0 }; uint8_t controllerAxisCount[SDL_AXIS_MAX] = { 0 }; uint8_t controllerAxisDiff[SDL_AXIS_MAX] = { 0 }; -int maxCount = 2; +int maxCount = 1; SDL_Window *window; SDL_Gamepad *controllers[255]; @@ -40,7 +43,7 @@ SetKeyboardButtons () { } void -SetConfigValue (const toml_table_t *table, const char *key, Keybindings *key_bind, bool *usePoll) { +SetConfigValue (const toml_table_t *table, const char *key, Keybindings *key_bind, u8 *inputState) { const toml_array_t *array = toml_array_in (table, key); if (!array) { LogMessage (LogLevel::WARN, std::string (key) + ": Cannot find array"); @@ -59,6 +62,7 @@ SetConfigValue (const toml_table_t *table, const char *key, Keybindings *key_bin switch (value.type) { case keycode: { + *inputState |= 1; for (int i = 0; i < std::size (key_bind->keycodes); i++) { if (key_bind->keycodes[i] == 0) { key_bind->keycodes[i] = value.keycode; @@ -68,7 +72,7 @@ SetConfigValue (const toml_table_t *table, const char *key, Keybindings *key_bin break; } case button: { - *usePoll = true; + *inputState |= (1 << 2); for (int i = 0; i < std::size (key_bind->buttons); i++) { if (key_bind->buttons[i] == SDL_GAMEPAD_BUTTON_INVALID) { key_bind->buttons[i] = value.button; @@ -78,7 +82,7 @@ SetConfigValue (const toml_table_t *table, const char *key, Keybindings *key_bin break; } case axis: { - *usePoll = true; + *inputState |= (1 << 2); for (int i = 0; i < std::size (key_bind->axis); i++) { if (key_bind->axis[i] == 0) { key_bind->axis[i] = value.axis; @@ -87,6 +91,7 @@ SetConfigValue (const toml_table_t *table, const char *key, Keybindings *key_bin } } case scroll: { + *inputState |= (1 << 1); for (int i = 0; i < std::size (key_bind->scroll); i++) { if (key_bind->scroll[i] == 0) { key_bind->scroll[i] = value.scroll; @@ -166,10 +171,16 @@ void KeyboardMainLoop() { HINSTANCE hInstance = GetModuleHandle(NULL); HWND hwnd = CreateInvisibleWindow(hInstance); if (!hwnd) LogMessage (LogLevel::ERROR, "Failed to create window!\n"); - keyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, InputProc, nullptr, 0); - if (keyboardHook == nullptr) LogMessage (LogLevel::ERROR, "Failed to install keyboard hook!\n"); - mouseHook = SetWindowsHookEx(WH_MOUSE_LL, InputProc, nullptr, 0); - if (mouseHook == nullptr) LogMessage (LogLevel::ERROR, "Failed to install mouse hook!\n"); + if (inputState & 1) { + keyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, InputProc, nullptr, 0); + if (keyboardHook == nullptr) LogMessage (LogLevel::ERROR, "Failed to install keyboard hook!\n"); + else LogMessage (LogLevel::INFO, "KeyboardLL hook installed!"); + } + if (inputState & (1 << 1)) { + mouseHook = SetWindowsHookEx(WH_MOUSE_LL, InputProc, nullptr, 0); + if (mouseHook == nullptr) LogMessage (LogLevel::ERROR, "Failed to install mouse hook!\n"); + else LogMessage (LogLevel::INFO, "MouseLL hook installed!"); + } if (maxCount > 2) LogMessage (LogLevel::ERROR, "CHEATING MODE! max count is set to {}", maxCount); LogMessage (LogLevel::WARN, "(experimental) Using Async IO!"); MSG msg; @@ -183,8 +194,9 @@ void KeyboardMainLoop() { void InitializeKeyboard () { - std::thread (KeyboardMainLoop).detach (); - // atexit (DisposeKeyboard); + if (inputState & (1 | 1 << 1)) { + std::thread (KeyboardMainLoop).detach (); + } } void @@ -202,64 +214,67 @@ CheckFlipped (uint32_t which, SDL_Gamepad *gamepad) { bool InitializePoll (HWND windowHandle) { - LogMessage (LogLevel::DEBUG, "InitializePoll"); - bool hasRumble = true; - wndForeground = windowHandle == GetForegroundWindow (); - SDL_SetMainReady (); + InitializeKeyboard (); + if (inputState & (1 << 2)) { + LogMessage (LogLevel::DEBUG, "InitializePoll"); + bool hasRumble = true; + wndForeground = windowHandle == GetForegroundWindow (); + SDL_SetMainReady (); - SDL_SetHint (SDL_HINT_JOYSTICK_HIDAPI_PS4, "1"); - SDL_SetHint (SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, "1"); - SDL_SetHint (SDL_HINT_JOYSTICK_HIDAPI_PS5, "1"); - SDL_SetHint (SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, "1"); + SDL_SetHint (SDL_HINT_JOYSTICK_HIDAPI_PS4, "1"); + SDL_SetHint (SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, "1"); + SDL_SetHint (SDL_HINT_JOYSTICK_HIDAPI_PS5, "1"); + SDL_SetHint (SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, "1"); - if (!SDL_Init (SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMEPAD | SDL_INIT_EVENTS | SDL_INIT_VIDEO)) { - if (SDL_Init (SDL_INIT_JOYSTICK | SDL_INIT_GAMEPAD | SDL_INIT_EVENTS | SDL_INIT_VIDEO)) { - hasRumble = false; - } else { - LogMessage (LogLevel::ERROR, std::string ("SDL_Init (SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMEPAD | SDL_INIT_EVENTS | SDL_INIT_VIDEO): ") + SDL_GetError ()); - return false; - } - } - - auto configPath = std::filesystem::current_path () / "gamecontrollerdb.txt"; - if (SDL_AddGamepadMappingsFromFile (configPath.string ().c_str ()) == -1) - LogMessage (LogLevel::ERROR, "Cannot read gamecontrollerdb.txt"); - SDL_SetGamepadEventsEnabled (true); - SDL_SetJoystickEventsEnabled (true); - - int numJoysticks = 0; - auto* joyStickIds = SDL_GetJoysticks(&numJoysticks); - if (joyStickIds == nullptr) { - LogMessage (LogLevel::ERROR, "Error getting joystick ids"); - exit(1); - } - for (int i = 0; i < numJoysticks; i++) { - auto id = joyStickIds[i]; - if (!SDL_IsGamepad (id)) continue; - SDL_Gamepad *controller = SDL_OpenGamepad (id); - - if (!controller) { - LogMessage (LogLevel::WARN, std::string ("Could not open gamecontroller ") + SDL_GetGamepadNameForID (id) + ": " + SDL_GetError ()); - continue; + if (!SDL_Init (SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMEPAD | SDL_INIT_EVENTS | SDL_INIT_VIDEO)) { + if (SDL_Init (SDL_INIT_JOYSTICK | SDL_INIT_GAMEPAD | SDL_INIT_EVENTS | SDL_INIT_VIDEO)) { + hasRumble = false; + } else { + LogMessage (LogLevel::ERROR, std::string ("SDL_Init (SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMEPAD | SDL_INIT_EVENTS | SDL_INIT_VIDEO): ") + SDL_GetError ()); + return false; + } } - LogMessage (LogLevel::DEBUG, "Init Controller connected!"); - CheckFlipped (id, controller); - controllers[id] = controller; - } - SDL_free (joyStickIds); + auto configPath = std::filesystem::current_path () / "gamecontrollerdb.txt"; + if (SDL_AddGamepadMappingsFromFile (configPath.string ().c_str ()) == -1) + LogMessage (LogLevel::ERROR, "Cannot read gamecontrollerdb.txt"); + SDL_SetGamepadEventsEnabled (true); + SDL_SetJoystickEventsEnabled (true); - SDL_PropertiesID props = SDL_CreateProperties(); - if(props == 0) { - LogMessage (LogLevel::ERROR, "Unable to create SDL_Properties"); - exit(1); - } - SDL_SetPointerProperty (props, SDL_PROP_WINDOW_CREATE_WIN32_HWND_POINTER, windowHandle); - window = SDL_CreateWindowWithProperties (props); - if (window == NULL) LogMessage (LogLevel::ERROR, std::string ("SDL_CreateWindowFrom (windowHandle): ") + SDL_GetError ()); + int numJoysticks = 0; + auto* joyStickIds = SDL_GetJoysticks(&numJoysticks); + if (joyStickIds == nullptr) { + LogMessage (LogLevel::ERROR, "Error getting joystick ids"); + exit(1); + } + for (int i = 0; i < numJoysticks; i++) { + auto id = joyStickIds[i]; + if (!SDL_IsGamepad (id)) continue; + SDL_Gamepad *controller = SDL_OpenGamepad (id); - atexit (DisposePoll); - return hasRumble; + if (!controller) { + LogMessage (LogLevel::WARN, std::string ("Could not open gamecontroller ") + SDL_GetGamepadNameForID (id) + ": " + SDL_GetError ()); + continue; + } + + LogMessage (LogLevel::DEBUG, "Init Controller connected!"); + CheckFlipped (id, controller); + controllers[id] = controller; + } + SDL_free (joyStickIds); + + SDL_PropertiesID props = SDL_CreateProperties(); + if(props == 0) { + LogMessage (LogLevel::ERROR, "Unable to create SDL_Properties"); + exit(1); + } + SDL_SetPointerProperty (props, SDL_PROP_WINDOW_CREATE_WIN32_HWND_POINTER, windowHandle); + window = SDL_CreateWindowWithProperties (props); + if (window == NULL) LogMessage (LogLevel::ERROR, std::string ("SDL_CreateWindowFrom (windowHandle): ") + SDL_GetError ()); + + atexit (DisposePoll); + return hasRumble; + } else return false; } bool @@ -285,23 +300,26 @@ CorrectButton (uint32_t which, uint8_t button) { } void -UpdatePoll (HWND windowHandle, bool useController) { +UpdatePoll (HWND windowHandle) { if (!CheckForegroundWindow (windowHandle)) return; - currentMouseState.ScrolledUp = false; - currentMouseState.ScrolledDown = false; - if (keyboardClean) { + if ((inputState & 1) && keyboardClean) { keyboardClean = false; for (int i=0; i<0xFF; i++) keyboardCount[i] -= (bool)keyboardDiff[i]; memset (keyboardDiff, 0, 0XFF); } - if (mouseWheelCount[0] > 0) mouseWheelCount[0] -= (bool)mouseWheelDiff[0]; - if (mouseWheelCount[1] > 0) mouseWheelCount[1] -= (bool)mouseWheelDiff[1]; - memset (mouseWheelDiff, 0, 2); + + if (inputState & (1 << 1)) { + currentMouseState.ScrolledUp = false; + currentMouseState.ScrolledDown = false; + if (mouseWheelCount[0] > 0) mouseWheelCount[0] -= (bool)mouseWheelDiff[0]; + if (mouseWheelCount[1] > 0) mouseWheelCount[1] -= (bool)mouseWheelDiff[1]; + memset (mouseWheelDiff, 0, 2); + } // GetCursorPos (¤tMouseState.Position); // ScreenToClient (windowHandle, ¤tMouseState.Position); - if (useController) { + if (inputState & (1 << 2)) { for (int i=0; i 0 ? 32767.0f : -32768.0f); - if (wndForeground || sensorValue == 0) { + if (wndForeground || sensorValue < axisThreshold) { switch (event.gaxis.axis) { - case SDL_GAMEPAD_AXIS_LEFTX: if (sensorValue < 0) { - currentControllerAxisState.LeftRight = 0.0f; - if (currentControllerAxisState.LeftLeft == 0.0f) { - controllerAxisCount[SDL_AXIS_LEFT_LEFT] = std::min (controllerAxisCount[SDL_AXIS_LEFT_LEFT] + 1, maxCount); + case SDL_GAMEPAD_AXIS_LEFTX: case SDL_GAMEPAD_AXIS_LEFTY: case SDL_GAMEPAD_AXIS_RIGHTX: case SDL_GAMEPAD_AXIS_RIGHTY: { + int direction = event.gaxis.axis * 2 + (event.gaxis.value < 0 ? 1 : 2); + int reverse = event.gaxis.axis * 2 + (event.gaxis.value < 0 ? 2 : 1); + currentControllerAxisState[reverse] = 0.0; + if (sensorValue > axisThreshold && currentControllerAxisState[direction] <= axisThreshold) { + LogMessage (LogLevel::DEBUG, "direction: {} value: {}", direction, sensorValue); + controllerAxisCount[direction] = std::min (controllerAxisCount[direction] + 1, maxCount); } - currentControllerAxisState.LeftLeft = -sensorValue; - } else { - currentControllerAxisState.LeftLeft = 0.0f; - if (currentControllerAxisState.LeftRight == 0.0f) { - controllerAxisCount[SDL_AXIS_LEFT_RIGHT] = std::min (controllerAxisCount[SDL_AXIS_LEFT_RIGHT] + 1, maxCount); - } - currentControllerAxisState.LeftRight = sensorValue; + currentControllerAxisState[direction] = sensorValue; } break; - case SDL_GAMEPAD_AXIS_LEFTY: if (sensorValue < 0) { - currentControllerAxisState.LeftDown = 0.0f; - if (currentControllerAxisState.LeftUp == 0.0f) { - controllerAxisCount[SDL_AXIS_LEFT_UP] = std::min (controllerAxisCount[SDL_AXIS_LEFT_UP] + 1, maxCount); + case SDL_GAMEPAD_AXIS_LEFT_TRIGGER: case SDL_GAMEPAD_AXIS_RIGHT_TRIGGER: { + int button = 5 + event.gaxis.axis; + if (sensorValue > axisThreshold && currentControllerAxisState[button] <= axisThreshold) { + controllerAxisCount[button] = std::min (controllerAxisCount[button] + 1, maxCount); } - currentControllerAxisState.LeftUp = -sensorValue; - } else { - currentControllerAxisState.LeftUp = 0.0f; - if (currentControllerAxisState.LeftDown == 0.0f) { - controllerAxisCount[SDL_AXIS_LEFT_DOWN] = std::min (controllerAxisCount[SDL_AXIS_LEFT_DOWN] + 1, maxCount); - } - currentControllerAxisState.LeftDown = sensorValue; + currentControllerAxisState[button] = sensorValue; } break; - case SDL_GAMEPAD_AXIS_RIGHTX: if (sensorValue < 0) { - currentControllerAxisState.RightRight = 0.0f; - if (currentControllerAxisState.RightLeft == 0.0f) { - controllerAxisCount[SDL_AXIS_RIGHT_LEFT] = std::min (controllerAxisCount[SDL_AXIS_RIGHT_LEFT] + 1, maxCount); - } - currentControllerAxisState.RightLeft = -sensorValue; - } else { - currentControllerAxisState.RightLeft = 0.0f; - if (currentControllerAxisState.RightRight == 0.0f) { - controllerAxisCount[SDL_AXIS_RIGHT_RIGHT] = std::min (controllerAxisCount[SDL_AXIS_RIGHT_RIGHT] + 1, maxCount); - } - currentControllerAxisState.RightRight = sensorValue; } break; - case SDL_GAMEPAD_AXIS_RIGHTY: if (sensorValue < 0) { - currentControllerAxisState.RightDown = 0.0f; - if (currentControllerAxisState.RightUp == 0.0f) { - controllerAxisCount[SDL_AXIS_RIGHT_UP] = std::min (controllerAxisCount[SDL_AXIS_RIGHT_UP] + 1, maxCount); - } - currentControllerAxisState.RightUp = -sensorValue; - } else { - currentControllerAxisState.RightUp = 0.0f; - if (currentControllerAxisState.RightDown == 0.0f) { - controllerAxisCount[SDL_AXIS_RIGHT_DOWN] = std::min (controllerAxisCount[SDL_AXIS_RIGHT_DOWN] + 1, maxCount); - } - currentControllerAxisState.RightDown = sensorValue; - } break; - case SDL_GAMEPAD_AXIS_LEFT_TRIGGER: { - if (currentControllerAxisState.LTriggerDown == 0.0f) { - controllerAxisCount[SDL_AXIS_LTRIGGER_DOWN] = std::min (controllerAxisCount[SDL_AXIS_LTRIGGER_DOWN] + 1, maxCount); - } - currentControllerAxisState.LTriggerDown = sensorValue; - } break; - case SDL_GAMEPAD_AXIS_RIGHT_TRIGGER: { - if (currentControllerAxisState.RTriggerDown == 0.0f) { - controllerAxisCount[SDL_AXIS_RTRIGGER_DOWN] = std::min (controllerAxisCount[SDL_AXIS_RTRIGGER_DOWN] + 1, maxCount); - } - currentControllerAxisState.RTriggerDown = sensorValue; - } break; - } break; - } + } } } } @@ -520,19 +491,7 @@ ControllerButtonIsTapped (const SDL_GamepadButton button) { float ControllerAxisIsDown (const SDLAxis axis) { - switch (axis) { - case SDL_AXIS_LEFT_LEFT: return currentControllerAxisState.LeftLeft; - case SDL_AXIS_LEFT_RIGHT: return currentControllerAxisState.LeftRight; - case SDL_AXIS_LEFT_UP: return currentControllerAxisState.LeftUp; - case SDL_AXIS_LEFT_DOWN: return currentControllerAxisState.LeftDown; - case SDL_AXIS_RIGHT_LEFT: return currentControllerAxisState.RightLeft; - case SDL_AXIS_RIGHT_RIGHT: return currentControllerAxisState.RightRight; - case SDL_AXIS_RIGHT_UP: return currentControllerAxisState.RightUp; - case SDL_AXIS_RIGHT_DOWN: return currentControllerAxisState.RightDown; - case SDL_AXIS_LTRIGGER_DOWN: return currentControllerAxisState.LTriggerDown; - case SDL_AXIS_RTRIGGER_DOWN: return currentControllerAxisState.RTriggerDown; - default: return 0.0f; - } + return currentControllerAxisState[axis]; } bool From 7769800b11fa91f42784f7c70cb65f3e1148a3fb Mon Sep 17 00:00:00 2001 From: ptmaster Date: Sun, 22 Dec 2024 23:23:37 +0800 Subject: [PATCH 04/11] try use _china.xml and cn_font from testmode --- src/patches/language.cpp | 7 ++++++ src/patches/patches.h | 1 + src/patches/testmode.cpp | 25 ++++++++++++++++---- src/patches/versions/JPN39.cpp | 43 ---------------------------------- 4 files changed, 28 insertions(+), 48 deletions(-) diff --git a/src/patches/language.cpp b/src/patches/language.cpp index 4edcb24..52544a3 100644 --- a/src/patches/language.cpp +++ b/src/patches/language.cpp @@ -8,6 +8,7 @@ extern GameVersion gameVersion; namespace patches::Language { const std::vector languages = { "jpn", "en_us", "cn_tw", "kor", "cn_cn" }; std::vector language_patch = { }; +boolean cnFontPatches = false; int language = 0; FUNCTION_PTR (void, lua_settop, PROC_ADDRESS ("lua51.dll", "lua_settop"), i64, i32); @@ -159,6 +160,7 @@ Init () { // user_name_soshina language_patch.push_back (safetyhook::create_mid (ASLR (0x14016164D), [](SafetyHookContext &ctx) { *(int *)(ctx.rsp + 0xD0) = (int)(ctx.rcx % languages.size ()); ctx.rip = ASLR (0x140161687); })); + cnFontPatches = true; } ); } break; @@ -629,6 +631,11 @@ Init () { } } +boolean +CnFontPatches () { + return cnFontPatches; +} + void Init () { switch (gameVersion) { diff --git a/src/patches/patches.h b/src/patches/patches.h index 2bbb60c..650855a 100644 --- a/src/patches/patches.h +++ b/src/patches/patches.h @@ -120,6 +120,7 @@ namespace Timer { void Init (); } // namespace timer namespace Language { +boolean CnFontPatches (); void Init (); } } // namespace patches diff --git a/src/patches/testmode.cpp b/src/patches/testmode.cpp index d00a7e4..b002d64 100644 --- a/src/patches/testmode.cpp +++ b/src/patches/testmode.cpp @@ -16,6 +16,7 @@ std::vector> hooks = {}; std::thread *hookInstall; std::mutex hooksMutex; std::condition_variable hooksCV; +std::vector patches = {}; std::wstring mergeCondition (std::wstring original, std::wstring addition, std::wstring value) { @@ -435,6 +436,9 @@ Init () { const u64 testModeLibrary = (u64)GetModuleHandle ("TestModeLibrary.dll"); const u64 testModeSetMenu = testModeLibrary + 0x99D0; + CommonModify (); + for (auto method : hooks) method (); + switch (gameVersion) { case GameVersion::UNKNOWN: break; case GameVersion::JPN00: break; @@ -443,7 +447,15 @@ Init () { INSTALL_FAST_HOOK_DYNAMIC (SceneTestModeLoading, ASLR (0x1404793D0)); INSTALL_FAST_HOOK_DYNAMIC (SceneTestModeFinalize, ASLR (0x140479600)); originalDeviceInitialize = L"DeviceInitialize.xml"; - if (std::filesystem::exists ("..\\..\\Data\\x64\\testmode\\DeviceInitialize_chspatch.xml")) { + if (Language::CnFontPatches () && std::filesystem::exists ("..\\..\\Data\\x64\\testmode\\DeviceInitialize_china.xml")) { + usingDeviceInitialize = L"DeviceInitialize_china.xml"; + patches.push_back (safetyhook::create_mid (ASLR (0x140465549), [](SafetyHookContext &ctx) + { ctx.r8 = 2; ctx.rdx = (uintptr_t)"cn"; ctx.rip = ASLR (0x140465556); })); + WRITE_MEMORY (ASLR (0x140CD1E40), wchar_t, L"加载中\0"); + WRITE_MEMORY (ASLR (0x140CD1E28), wchar_t, L"加载中.\0"); + WRITE_MEMORY (ASLR (0x140CD1E68), wchar_t, L"加载中..\0"); + WRITE_MEMORY (ASLR (0x140CD1E50), wchar_t, L"加载中...\0"); + } else if (std::filesystem::exists ("..\\..\\Data\\x64\\testmode\\DeviceInitialize_chspatch.xml")) { usingDeviceInitialize = L"DeviceInitialize_chspatch.xml"; WRITE_MEMORY (ASLR (0x140CD1E40), wchar_t, L"加載中\0"); WRITE_MEMORY (ASLR (0x140CD1E28), wchar_t, L"加載中.\0"); @@ -451,7 +463,13 @@ Init () { WRITE_MEMORY (ASLR (0x140CD1E50), wchar_t, L"加載中...\0"); } else usingDeviceInitialize = originalDeviceInitialize; originalTestMode = L"TestMode.xml"; - if (std::filesystem::exists ("..\\..\\Data\\x64\\testmode\\TestMode_chspatch.xml")) { + if (Language::CnFontPatches () && std::filesystem::exists ("..\\..\\Data\\x64\\testmode\\TestMode_china.xml")) { + usingTestMode = L"TestMode_china.xml"; + patches.push_back (safetyhook::create_mid (ASLR (0x14047C603), [](SafetyHookContext &ctx) + { ctx.r8 = 2; ctx.rdx = (uintptr_t)"cn"; ctx.rip = ASLR (0x14047C610); })); + patches.push_back (safetyhook::create_mid (ASLR (0x1404676E7), [](SafetyHookContext &ctx) + { ctx.r8 = 2; ctx.rdx = (uintptr_t)"cn"; ctx.rip = ASLR (0x1404676F4); })); + } else if (std::filesystem::exists ("..\\..\\Data\\x64\\testmode\\TestMode_chspatch.xml")) { usingTestMode = L"TestMode_chspatch.xml"; } else usingTestMode = originalTestMode; @@ -459,10 +477,7 @@ Init () { case GameVersion::CHN00: break; } - CommonModify (); - INSTALL_FAST_HOOK_DYNAMIC (TestModeSetMenuHook, testModeSetMenu); - for (auto method : hooks) method (); } void diff --git a/src/patches/versions/JPN39.cpp b/src/patches/versions/JPN39.cpp index fe56ef0..9db41f5 100644 --- a/src/patches/versions/JPN39.cpp +++ b/src/patches/versions/JPN39.cpp @@ -225,49 +225,6 @@ MID_HOOK (AttractDemo, ASLR (0x14045A720), SafetyHookContext &ctx) { if (TestMode::ReadTestModeValue (L"AttractDemoItem") == 1) ctx.r14 = 0; } -// FAST_HOOK (u64, EnsoGameManagerInitialize, ASLR (0x1400E2520), u64 a1, u64 a2, u64 a3) { -// LogMessage (LogLevel::DEBUG, "Begin EnsoGameManagerInitialize"); -// u64 result = originalEnsoGameManagerInitialize.fastcall (a1, a2, a3); -// LogMessage (LogLevel::DEBUG, "End EnsoGameManagerInitialize result={}", result); -// return result; -// } - -// FAST_HOOK (u64, EnsoGameManagerLoading, ASLR (0x1400E2750), u64 a1, u64 a2, u64 a3) { -// LogMessage (LogLevel::DEBUG, "Begin EnsoGameManagerLoading"); -// u64 result = originalEnsoGameManagerLoading.fastcall (a1, a2, a3); -// LogMessage (LogLevel::DEBUG, "End EnsoGameManagerLoading result={}", result); -// return result; -// } - -// FAST_HOOK (bool, EnsoGameManagerPreparing, ASLR (0x1400E2990), u64 a1, u64 a2, u64 a3) { -// LogMessage (LogLevel::DEBUG, "Begin EnsoGameManagerPreparing"); -// bool result = originalEnsoGameManagerPreparing.fastcall (a1, a2, a3); // crashes here -// LogMessage (LogLevel::DEBUG, "End EnsoGameManagerPreparing result={}", result); -// return result; -// } - -// FAST_HOOK (u64, EnsoGraphicManagerPreparing, ASLR (0x1400F0AB0), u64 a1, u64 a2, u64 a3) { -// LogMessage (LogLevel::DEBUG, "Begin EnsoGraphicManagerPreparing"); -// u64 result = originalEnsoGraphicManagerPreparing.fastcall (a1, a2, a3); -// LogMessage (LogLevel::DEBUG, "End EnsoGraphicManagerPreparing result={}", result); -// return result; -// } - - -// FAST_HOOK (u64, EnsoGameManagerStart, ASLR (0x1400E2A10), u64 a1, u64 a2, u64 a3) { -// LogMessage (LogLevel::DEBUG, "Begin EnsoGameManagerStart"); -// u64 result = originalEnsoGameManagerStart.fastcall (a1, a2, a3); -// LogMessage (LogLevel::DEBUG, "End EnsoGameManagerStart result={}", result); -// return result; -// } - -// FAST_HOOK (u64, EnsoGameManagerChechEnsoEnd, ASLR (0x1400E2A10), u64 a1, u64 a2, u64 a3) { -// LogMessage (LogLevel::DEBUG, "Begin EnsoGameManagerChechEnsoEnd"); -// u64 result = originalEnsoGameManagerChechEnsoEnd.fastcall (a1, a2, a3); -// LogMessage (LogLevel::DEBUG, "End EnsoGameManagerChechEnsoEnd result={}", result); -// return result; -// } - // HOOK (DWORD*, AcquireMostCompatibleDisplayMode, ASLR (0x14064C870), i64 a1, DWORD *a2, DWORD *a3) { // LogMessage (LogLevel::DEBUG, "AcquireMostCompatibleDisplayMode {:d} {:d} {:f} {:f}", a3[0], a3[1], (float)(int)a3[2], (float)(int)a3[3]); // a3[2] = (DWORD)(int)120.0f; From c69fd38faa5ff15b249514e01698bafa299ef52c Mon Sep 17 00:00:00 2001 From: ptmaster Date: Mon, 23 Dec 2024 03:43:45 +0800 Subject: [PATCH 05/11] Use TestMode::Value to cache values which read from RefTestModeMain --- src/patches/audio.cpp | 3 +- src/patches/language.cpp | 9 +++--- src/patches/patches.h | 7 +++++ src/patches/testmode.cpp | 50 +++++++++++++++++++++++++++++++--- src/patches/versions/JPN39.cpp | 36 ++++++++++++++---------- 5 files changed, 82 insertions(+), 23 deletions(-) diff --git a/src/patches/audio.cpp b/src/patches/audio.cpp index 394faf0..89b9df0 100644 --- a/src/patches/audio.cpp +++ b/src/patches/audio.cpp @@ -41,9 +41,10 @@ FAST_HOOK_DYNAMIC (bool, LoadASIODriver, void *a1, const char *a2) { } return result; } +TestMode::Value *speakerLevel = TestMode::CreateValue(L"OutputLevelSpeakerItem"); FAST_HOOK_DYNAMIC (u64, NuscBusVolume, u64 a1, u64 a2, float a3) { if (volumeRate == 0.0f) { - int value = patches::TestMode::ReadTestModeValue (L"OutputLevelSpeakerItem"); + int value = speakerLevel->Read (); if (value == -1) return originalNuscBusVolume.fastcall (a1, a2, a3); volumeRate = value <= 100 ? 1.0f : value / 100.0f; } diff --git a/src/patches/language.cpp b/src/patches/language.cpp index 52544a3..8b787a6 100644 --- a/src/patches/language.cpp +++ b/src/patches/language.cpp @@ -546,9 +546,10 @@ FixToneName (const std::string &bankName, std::string toneName, int voiceLang) { } size_t commonSize = 0; +TestMode::Value *voiceLanguage = TestMode::CreateValue (L"VoiceLanguageItem"); FAST_HOOK_DYNAMIC (i64, PlaySoundMain, i64 a1) { LogMessage (LogLevel::HOOKS, "PlaySoundMain was called"); - int lang = TestMode::ReadTestModeValue (L"VoiceLanguageItem"); + int lang = voiceLanguage->Read (); if (lang > 0) { const std::string bankName (lua_tolstring (a1, -3, &commonSize)); if (bankName[0] == 'v') { @@ -561,7 +562,7 @@ FAST_HOOK_DYNAMIC (i64, PlaySoundMain, i64 a1) { FAST_HOOK_DYNAMIC (i64, PlaySoundMulti, i64 a1) { LogMessage (LogLevel::HOOKS, "PlaySoundMulti was called"); - int lang = TestMode::ReadTestModeValue (L"VoiceLanguageItem"); + int lang = voiceLanguage->Read (); if (lang > 0) { const std::string bankName (const_cast (lua_tolstring (a1, -3, &commonSize))); if (bankName[0] == 'v') { @@ -582,7 +583,7 @@ FixToneNameEnso (u64 *Src, const std::string &bankName, int voiceLang) { FAST_HOOK_DYNAMIC (bool, PlaySoundEnso, u64 *a1, u64 *a2, i64 a3) { LogMessage (LogLevel::HOOKS, "PlaySoundEnso was called"); - int lang = TestMode::ReadTestModeValue (L"VoiceLanguageItem"); + int lang = voiceLanguage->Read (); if (lang > 0) { const std::string bankName = a1[3] > 0x10 ? std::string (*reinterpret_cast (a1)) : std::string (reinterpret_cast (a1)); if (bankName[0] == 'v') a2 = FixToneNameEnso (a2, bankName, lang); @@ -592,7 +593,7 @@ FAST_HOOK_DYNAMIC (bool, PlaySoundEnso, u64 *a1, u64 *a2, i64 a3) { FAST_HOOK_DYNAMIC (bool, PlaySoundSpecial, u64 *a1, u64 *a2) { LogMessage (LogLevel::HOOKS, "PlaySoundSpecial was called"); - int lang = TestMode::ReadTestModeValue (L"VoiceLanguageItem"); + int lang = voiceLanguage->Read (); if (lang > 0) { const std::string bankName = a1[3] > 0x10 ? std::string (*reinterpret_cast (a1)) : std::string (reinterpret_cast (a1)); if (bankName[0] == 'v') a2 = FixToneNameEnso (a2, bankName, lang); diff --git a/src/patches/patches.h b/src/patches/patches.h index 650855a..7410622 100644 --- a/src/patches/patches.h +++ b/src/patches/patches.h @@ -50,6 +50,12 @@ class Menu : public Applicable { public: virtual void RegisterItem (Applicable *item) = 0; }; +class Value { +public: + virtual int Read() = 0; + virtual void Write(int value) = 0; + virtual void Reset() = 0; +}; typedef u64 (*RefTestModeMain) (u64); void Init (); void Append (const pugi::xml_node &node, const wchar_t *attr, const std::wstring &append); @@ -57,6 +63,7 @@ void SetupAccessor (u64 appAccessor, RefTestModeMain refTestMode); int ReadTestModeValue (const wchar_t *itemId); void SetTestModeValue (const wchar_t *itemId, int value); Menu *CreateMenu (const std::wstring &menuName, const std::wstring &menuId); +Value *CreateValue (const std::wstring &key); void RegisterItem (const std::wstring &item, const std::function &initMethod, Menu *menu); void RegisterItem (const std::wstring &item, const std::function &initMethod); void RegisterItem (const std::wstring &item, Menu *menu); diff --git a/src/patches/testmode.cpp b/src/patches/testmode.cpp index b002d64..215e675 100644 --- a/src/patches/testmode.cpp +++ b/src/patches/testmode.cpp @@ -17,6 +17,7 @@ std::thread *hookInstall; std::mutex hooksMutex; std::condition_variable hooksCV; std::vector patches = {}; +std::vector values = {}; std::wstring mergeCondition (std::wstring original, std::wstring addition, std::wstring value) { @@ -202,9 +203,38 @@ public: return nullptr; } }; - +class TestModeValue : Value { +public: + std::wstring key; + int value; + boolean reset; + TestModeValue (std::wstring key) { + this->key = key; + this->value = -1; + this->reset = true; + } + int + Read () override { + if (reset) { + this->value = ReadTestModeValue (key.c_str ()); + if (this->value != -1) { + LogMessage (LogLevel::DEBUG, L"TestMode Value({}) got val: {}", this->key, this->value); + reset = false; + } + } + return this->value; + } + void + Write (int value) override { + SetTestModeValue (this->key.c_str (), value); + this->reset = true; + } + void + Reset () override { + this->reset = true; + } +}; Menu *modManager = new RegisteredMenu (L"MOD MANAGER", L"ModManagerMenu"); -// std::vector registeredItems = {}; std::vector registeredSingleItems = {}; std::vector registeredModifies = {}; std::wstring moddedInitial = L""; @@ -227,6 +257,7 @@ FAST_HOOK_DYNAMIC (char, SceneTestModeLoading, u64 a1, u64 a2, u64 a3) { FAST_HOOK_DYNAMIC (char, SceneTestModeFinalize, u64 a1, u64 a2, u64 a3) { char result = originalSceneTestModeFinalize.fastcall (a1, a2, a3); + for (auto value : values) { value->Reset (); value->Read (); } return result; } @@ -482,8 +513,11 @@ Init () { void SetupAccessor (const u64 appAccessor, const RefTestModeMain refTestMode) { - TestMode::appAccessor = appAccessor; - TestMode::refTestMode = refTestMode; + if (TestMode::appAccessor != appAccessor) { + LogMessage (LogLevel::DEBUG, "TestMode setup!"); + TestMode::appAccessor = appAccessor; + TestMode::refTestMode = refTestMode; + } } int @@ -515,6 +549,14 @@ CreateMenu (const std::wstring &menuName, const std::wstring &menuId) { return new RegisteredMenu (menuName, menuId); } +Value * +CreateValue (const std::wstring &key) { + LogMessage (LogLevel::DEBUG, L"Create TestMode Value key: {}", key); + Value *value = (Value *)(new TestModeValue (key)); + values.push_back ((Value *)value); + return value; +} + void RegisterItem (const std::wstring &item, const std::function &initMethod, Menu *menu) { LogMessage (LogLevel::DEBUG, L"Register \nItem: {}", item); diff --git a/src/patches/versions/JPN39.cpp b/src/patches/versions/JPN39.cpp index 9db41f5..d3ab4e3 100644 --- a/src/patches/versions/JPN39.cpp +++ b/src/patches/versions/JPN39.cpp @@ -66,55 +66,62 @@ GetUserStatus () { return -1; } +TestMode::Value *unlockSongs = TestMode::CreateValue (L"ModUnlockSongs"); FAST_HOOK (bool, IsSongRelease, ASLR (0x1403F4510), i64 a1, i64 a2, int a3) { - if (TestMode::ReadTestModeValue (L"ModUnlockSongs") == 1) return true; + if (unlockSongs->Read () == 1) return true; return originalIsSongRelease.fastcall (a1, a2, a3); } FAST_HOOK (bool, IsSongReleasePlayer, ASLR (0x1403F45F0), i64 a1, u64 a2, i32 a3) { - if (TestMode::ReadTestModeValue (L"ModUnlockSongs") == 2) return true; + if (unlockSongs->Read () == 2) return true; return originalIsSongReleasePlayer.fastcall (a1, a2, a3); } MID_HOOK (DifficultyPanelCrown, ASLR (0x1403F2A25), SafetyHookContext &ctx) { - if (TestMode::ReadTestModeValue (L"ModUnlockSongs") != 1) return; + if (unlockSongs->Read () != 1) return; ctx.r15 |= 1; } +TestMode::Value *tournmentMode = TestMode::CreateValue (L"TournamentMode"); +TestMode::Value *mode024 = TestMode::CreateValue (L"ModModeCollabo024"); +TestMode::Value *mode025 = TestMode::CreateValue (L"ModModeCollabo025"); +TestMode::Value *mode026 = TestMode::CreateValue (L"ModModeCollabo026"); +TestMode::Value *modeApril001 = TestMode::CreateValue (L"ModModeAprilFool001"); FAST_HOOK (i64, AvailableMode_Collabo024, ASLR (0x1402DE710), i64 a1) { LogMessage (LogLevel::HOOKS, "AvailableMode_Collabo024 was called"); - const int tournamentMode = TestMode::ReadTestModeValue (L"TournamentMode"); + const int tournamentMode = tournmentMode->Read (); if (tournamentMode == 1) return originalAvailableMode_Collabo024.fastcall (a1); - const int status = TestMode::ReadTestModeValue (L"ModModeCollabo024"); + const int status = mode024->Read (); if (status == 1 && GetUserStatus () == 1) return lua_pushbool (a1, true); return originalAvailableMode_Collabo024.fastcall (a1); } FAST_HOOK (i64, AvailableMode_Collabo025, ASLR (0x1402DE6B0), i64 a1) { LogMessage (LogLevel::HOOKS, "AvailableMode_Collabo025 was called"); - const int tournamentMode = TestMode::ReadTestModeValue (L"TournamentMode"); + const int tournamentMode = tournmentMode->Read (); if (tournamentMode == 1) return originalAvailableMode_Collabo025.fastcall (a1); - const int status = TestMode::ReadTestModeValue (L"ModModeCollabo025"); + const int status = mode025->Read (); if (status == 1 && GetUserStatus () == 1) return lua_pushbool (a1, true); return originalAvailableMode_Collabo025.fastcall (a1); } FAST_HOOK (i64, AvailableMode_Collabo026, ASLR (0x1402DE670), i64 a1) { LogMessage (LogLevel::HOOKS, "AvailableMode_Collabo026 was called"); - const int tournamentMode = TestMode::ReadTestModeValue (L"TournamentMode"); + const int tournamentMode = tournmentMode->Read (); if (tournamentMode == 1) return originalAvailableMode_Collabo026.fastcall (a1); - const int status = TestMode::ReadTestModeValue (L"ModModeCollabo026"); + const int status = mode026->Read (); if (status == 1 && GetUserStatus () == 1) return lua_pushbool (a1, true); return originalAvailableMode_Collabo026.fastcall (a1); } FAST_HOOK (i64, AvailableMode_AprilFool001, ASLR (0x1402DE5B0), i64 a1) { LogMessage (LogLevel::HOOKS, "AvailableMode_AprilFool001 was called"); - const int tournamentMode = TestMode::ReadTestModeValue (L"TournamentMode"); + const int tournamentMode = tournmentMode->Read (); if (tournamentMode == 1) return originalAvailableMode_AprilFool001.fastcall (a1); - const int status = TestMode::ReadTestModeValue (L"ModModeAprilFool001"); + const int status = modeApril001->Read (); if (status == 1) return lua_pushbool (a1, true); return originalAvailableMode_AprilFool001.fastcall (a1); } +TestMode::Value *freezeTimer = TestMode::CreateValue (L"ModFreezeTimer"); i64 __fastcall lua_freeze_timer (const i64 a1) { LogMessage (LogLevel::HOOKS, "lua_freeze_timer was called"); - const int tournamentMode = TestMode::ReadTestModeValue (L"TournamentMode"); + const int tournamentMode = tournmentMode->Read (); if (tournamentMode == 1) return lua_pushbool (a1, true); - const int status = TestMode::ReadTestModeValue (L"ModFreezeTimer"); + const int status = freezeTimer-> Read (); if (status == 1) return lua_pushbool (a1, true); return lua_pushbool (a1, false); } @@ -221,8 +228,9 @@ FAST_HOOK (i32, SetMasterVolumeSpeaker, ASLR (0x140160330), i32 a1) { return originalSetMasterVolumeSpeaker.fastcall (a1 > 100 ? 100 : a1); } +TestMode::Value *attractDemo = TestMode::CreateValue (L"AttractDemoItem"); MID_HOOK (AttractDemo, ASLR (0x14045A720), SafetyHookContext &ctx) { - if (TestMode::ReadTestModeValue (L"AttractDemoItem") == 1) ctx.r14 = 0; + if (attractDemo->Read () == 1) ctx.r14 = 0; } // HOOK (DWORD*, AcquireMostCompatibleDisplayMode, ASLR (0x14064C870), i64 a1, DWORD *a2, DWORD *a3) { From eacdd50d9c24b19014a7ed0d86676fef14865cd2 Mon Sep 17 00:00:00 2001 From: ptmaster Date: Mon, 23 Dec 2024 04:13:43 +0800 Subject: [PATCH 06/11] TestMode Value lifecycle control --- src/logger.cpp | 5 +++++ src/logger.h | 4 ++++ src/patches/testmode.cpp | 9 ++++++++- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/logger.cpp b/src/logger.cpp index 639edc4..e0d451e 100644 --- a/src/logger.cpp +++ b/src/logger.cpp @@ -98,6 +98,11 @@ LogMessageHandler (const char *function, const char *codeFile, const int codeLin va_end (args); } +bool +EnableLogging (LogLevel messageLevel) { + return loggerInstance != nullptr && messageLevel <= loggerInstance->logLevel; +} + void CleanupLogger () { if (loggerInstance != nullptr) { diff --git a/src/logger.h b/src/logger.h index d5e2ecf..c1b7073 100644 --- a/src/logger.h +++ b/src/logger.h @@ -35,6 +35,8 @@ void InitializeLogger (LogLevel level, bool logToFile); void LogMessageHandler (const char *function, const char *codeFile, int codeLine, LogLevel messageLevel, const char *format, ...); void LogMessageHandler (const char *function, const char *codeFile, int codeLine, LogLevel messageLevel, const wchar_t *format, ...); +bool EnableLogging (LogLevel level); + /* * * Logs a message with file and line information, if the log level permits. * @@ -44,12 +46,14 @@ template struct LogMessage { LogMessage (const LogLevel level, const std::string_view format, Args &&...args, const std::source_location &loc = std::source_location::current ()) { + if (!EnableLogging (level)) return; std::string formatted_message = std::vformat(std::string(format), std::make_format_args(args...)); LogMessageHandler (loc.function_name (), loc.file_name (), loc.line (), level, formatted_message.c_str ()); } LogMessage (const LogLevel level, const std::wstring_view format, Args &&...args, const std::source_location &loc = std::source_location::current ()) { + if (!EnableLogging (level)) return; std::wstring formatted_message = std::vformat(std::wstring(format), std::make_wformat_args(args...)); LogMessageHandler (loc.function_name (), loc.file_name (), loc.line (), level, formatted_message.c_str ()); } diff --git a/src/patches/testmode.cpp b/src/patches/testmode.cpp index 215e675..937a135 100644 --- a/src/patches/testmode.cpp +++ b/src/patches/testmode.cpp @@ -257,10 +257,15 @@ FAST_HOOK_DYNAMIC (char, SceneTestModeLoading, u64 a1, u64 a2, u64 a3) { FAST_HOOK_DYNAMIC (char, SceneTestModeFinalize, u64 a1, u64 a2, u64 a3) { char result = originalSceneTestModeFinalize.fastcall (a1, a2, a3); - for (auto value : values) { value->Reset (); value->Read (); } + std::thread ([](){for (auto value : values) { value->Reset (); value->Read (); }}).detach (); return result; } +FAST_HOOK_DYNAMIC (void, SceneFirstInitialize, u64 a1, u64 a2, u64 a3) { + std::thread ([](){for (auto value : values) { value->Reset (); value->Read (); }}).detach (); + originalSceneFirstInitialize.fastcall (a1, a2, a3); +} + FAST_HOOK_DYNAMIC (void, TestModeSetMenuHook, u64 testModeLibrary, const wchar_t *lFileName) { auto start = std::chrono::high_resolution_clock::now(); const auto originalFileName = std::wstring (lFileName); @@ -477,6 +482,7 @@ Init () { case GameVersion::JPN39: { INSTALL_FAST_HOOK_DYNAMIC (SceneTestModeLoading, ASLR (0x1404793D0)); INSTALL_FAST_HOOK_DYNAMIC (SceneTestModeFinalize, ASLR (0x140479600)); + INSTALL_FAST_HOOK_DYNAMIC (SceneFirstInitialize, ASLR (0x1404574B0)); originalDeviceInitialize = L"DeviceInitialize.xml"; if (Language::CnFontPatches () && std::filesystem::exists ("..\\..\\Data\\x64\\testmode\\DeviceInitialize_china.xml")) { usingDeviceInitialize = L"DeviceInitialize_china.xml"; @@ -517,6 +523,7 @@ SetupAccessor (const u64 appAccessor, const RefTestModeMain refTestMode) { LogMessage (LogLevel::DEBUG, "TestMode setup!"); TestMode::appAccessor = appAccessor; TestMode::refTestMode = refTestMode; + // std::thread ([](){for (auto value : values) { value->Reset (); value->Read (); }}).detach (); } } From a2fc72180dc37f91005e4de4c40e6249e141f930 Mon Sep 17 00:00:00 2001 From: ptmaster Date: Tue, 24 Dec 2024 00:41:40 +0800 Subject: [PATCH 07/11] Implement Card Only selection to Mode Unlock | fix mouse laggy on crash issue --- src/bnusio.cpp | 25 ++++++++--- src/patches/language.cpp | 1 - src/patches/versions/JPN39.cpp | 31 ++++++++++---- src/poll.h | 1 - src/pollasync.cpp | 78 +++++++++++++++++----------------- 5 files changed, 81 insertions(+), 55 deletions(-) diff --git a/src/bnusio.cpp b/src/bnusio.cpp index dcbb38f..b8f93e9 100644 --- a/src/bnusio.cpp +++ b/src/bnusio.cpp @@ -63,7 +63,8 @@ bool inited = false; bool updateByCoin = false; HWND windowHandle = nullptr; float axisThreshold = 0.6f; -u8 inputState = 0; +u8 inputState = 1 | (1 << 2); +bool globalKeyboard = false;; HKL currentLayout; namespace bnusio { @@ -304,11 +305,20 @@ UpdateLoop () { UpdatePoll (windowHandle); #endif std::vector buffer = {}; - if (IsButtonTapped (COIN_ADD)) coin_count++; - if (IsButtonTapped (SERVICE)) service_count++; - if (IsButtonTapped (TEST)) testEnabled = !testEnabled; + if (IsButtonTapped (COIN_ADD)) { + LogMessage (LogLevel::DEBUG, "Insert Coin!"); + coin_count++; + } + if (IsButtonTapped (SERVICE)) { + LogMessage (LogLevel::DEBUG, "Insert Severice Coin!"); + service_count++; + } + if (IsButtonTapped (TEST)) { + LogMessage (LogLevel::INFO, "Enter TestMode by Press TestMode Button!"); + testEnabled = !testEnabled; + } if (exited == 0 && IsButtonTapped (EXIT)) { - LogMessage (LogLevel::INFO, "Exit By Press Exit Button!"); + LogMessage (LogLevel::INFO, "Exit by Press Exit Button!"); exited += 1; testEnabled = 1; std::thread([](){patches::Plugins::Exit ();}).detach(); } if (GameVersion::CHN00 == gameVersion) { @@ -341,6 +351,7 @@ Init () { if (const auto controller = openConfigSection (config, "controller")) { drumWaitPeriod = static_cast (readConfigInt (controller, "wait_period", drumWaitPeriod)); analogInput = readConfigBool (controller, "analog_input", analogInput); + globalKeyboard = readConfigBool (controller, "global_keyboard", globalKeyboard); } auto graphics = openConfigSection (config, "graphics"); if (graphics) { @@ -369,6 +380,7 @@ Init () { const auto keyConfigPath = std::filesystem::current_path () / "keyconfig.toml"; const std::unique_ptr keyConfig_ptr (openConfig (keyConfigPath), toml_free); if (keyConfig_ptr) { + inputState = 0; if (analogInput) inputState |= (1 << 2); const toml_table_t *keyConfig = keyConfig_ptr.get (); SetConfigValue (keyConfig, "EXIT", &EXIT, &inputState); @@ -395,6 +407,9 @@ Init () { SetConfigValue (keyConfig, "P2_RIGHT_BLUE", &P2_RIGHT_BLUE, &inputState); } + LogMessage (LogLevel::INFO, "Finish Loading keyconfig.toml useKeyboard={} useMouse={} useController={}", + (inputState & 1) ? "true" : "false", (inputState & (1 << 1)) ? "true" : "false", (inputState & (1 << 2)) ? "true" : "false"); + if (!emulateUsio && !exists (std::filesystem::current_path () / "bnusio_original.dll")) { emulateUsio = true; LogMessage (LogLevel::ERROR, "bnusio_original.dll not found! usio emulation enabled"); diff --git a/src/patches/language.cpp b/src/patches/language.cpp index 8b787a6..513eb18 100644 --- a/src/patches/language.cpp +++ b/src/patches/language.cpp @@ -117,7 +117,6 @@ Init () { L"/root/menu[@id='OthersMenu']/layout[@type='Center']/select-item[@id='LanguageItem']", [](pugi::xml_node &node) { node.attribute (L"max").set_value (L"4"); - node.attribute (L"default").set_value (L"4"); node.attribute (L"replace-text").set_value (L"0:JPN, 1:ENG, 2:zh-tw, 3:KOR, 4:zh-cn"); }, [&](){ // load_setting diff --git a/src/patches/versions/JPN39.cpp b/src/patches/versions/JPN39.cpp index d3ab4e3..62a79d4 100644 --- a/src/patches/versions/JPN39.cpp +++ b/src/patches/versions/JPN39.cpp @@ -59,12 +59,23 @@ FAST_HOOK (i64, DeviceCheck, ASLR (0x140464FC0), i64 a1, i64 a2, i64 a3) { } i64 -GetUserStatus () { +GetPlayererCount () { if (appAccessor) { if (const u64 playDataManager = RefPlayDataManager (appAccessor)) return GetUserCount (playDataManager); } return -1; } +boolean +HaveCardPlayer () { + if (appAccessor) { + if (const u64 playDataManager = RefPlayDataManager (appAccessor)) { + int p1PlayerType = *(i32 *)(*(i64 *)(playDataManager + 9920) + 4); + int p2PlayerType = *(i32 *)(*(i64 *)(playDataManager + 9928) + 4); + return p1PlayerType == 2 || p2PlayerType == 2; + } + } + return false; +} TestMode::Value *unlockSongs = TestMode::CreateValue (L"ModUnlockSongs"); FAST_HOOK (bool, IsSongRelease, ASLR (0x1403F4510), i64 a1, i64 a2, int a3) { @@ -89,7 +100,8 @@ FAST_HOOK (i64, AvailableMode_Collabo024, ASLR (0x1402DE710), i64 a1) { const int tournamentMode = tournmentMode->Read (); if (tournamentMode == 1) return originalAvailableMode_Collabo024.fastcall (a1); const int status = mode024->Read (); - if (status == 1 && GetUserStatus () == 1) return lua_pushbool (a1, true); + if (status == 1 && GetPlayererCount () == 1) return lua_pushbool (a1, true); + else if (status == 2 && GetPlayererCount () == 1 && HaveCardPlayer ()) return lua_pushbool (a1, true); return originalAvailableMode_Collabo024.fastcall (a1); } FAST_HOOK (i64, AvailableMode_Collabo025, ASLR (0x1402DE6B0), i64 a1) { @@ -97,7 +109,8 @@ FAST_HOOK (i64, AvailableMode_Collabo025, ASLR (0x1402DE6B0), i64 a1) { const int tournamentMode = tournmentMode->Read (); if (tournamentMode == 1) return originalAvailableMode_Collabo025.fastcall (a1); const int status = mode025->Read (); - if (status == 1 && GetUserStatus () == 1) return lua_pushbool (a1, true); + if (status == 1 && GetPlayererCount () == 1) return lua_pushbool (a1, true); + else if (status == 2 && GetPlayererCount () == 1 && HaveCardPlayer ()) return lua_pushbool (a1, true); return originalAvailableMode_Collabo025.fastcall (a1); } FAST_HOOK (i64, AvailableMode_Collabo026, ASLR (0x1402DE670), i64 a1) { @@ -105,7 +118,8 @@ FAST_HOOK (i64, AvailableMode_Collabo026, ASLR (0x1402DE670), i64 a1) { const int tournamentMode = tournmentMode->Read (); if (tournamentMode == 1) return originalAvailableMode_Collabo026.fastcall (a1); const int status = mode026->Read (); - if (status == 1 && GetUserStatus () == 1) return lua_pushbool (a1, true); + if (status == 1 && GetPlayererCount () == 1) return lua_pushbool (a1, true); + else if (status == 2 && GetPlayererCount () == 1 && HaveCardPlayer ()) return lua_pushbool (a1, true); return originalAvailableMode_Collabo026.fastcall (a1); } FAST_HOOK (i64, AvailableMode_AprilFool001, ASLR (0x1402DE5B0), i64 a1) { @@ -114,6 +128,7 @@ FAST_HOOK (i64, AvailableMode_AprilFool001, ASLR (0x1402DE5B0), i64 a1) { if (tournamentMode == 1) return originalAvailableMode_AprilFool001.fastcall (a1); const int status = modeApril001->Read (); if (status == 1) return lua_pushbool (a1, true); + else if (status == 2 && HaveCardPlayer ()) return lua_pushbool (a1, true); return originalAvailableMode_AprilFool001.fastcall (a1); } TestMode::Value *freezeTimer = TestMode::CreateValue (L"ModFreezeTimer"); @@ -351,22 +366,22 @@ Init () { // TestMode::Menu *modeUnlock = TestMode::CreateMenu (L"MODE UNLOCK", L"ModeUnlockMenu"); TestMode::RegisterItem ( L"", + L"2:CARD ONLY\" group=\"Setting\" id=\"ModModeCollabo024\" max=\"2\" min=\"0\" default=\"0\"/>", [&] { INSTALL_FAST_HOOK (AvailableMode_Collabo024); }//, modeUnlock ); TestMode::RegisterItem ( L"", + L"1:ENABLE, 2:CARD ONLY\" group=\"Setting\" id=\"ModModeCollabo025\" max=\"2\" min=\"0\" default=\"0\"/>", [&] { INSTALL_FAST_HOOK (AvailableMode_Collabo025); }//, modeUnlock ); TestMode::RegisterItem ( L"", + L"1:ENABLE, 2:CARD ONLY\" group=\"Setting\" id=\"ModModeCollabo026\" max=\"2\" min=\"0\" default=\"0\"/>", [&] { INSTALL_FAST_HOOK (AvailableMode_Collabo026); }//, modeUnlock ); TestMode::RegisterItem ( L"", + L"2:CARD ONLY\" group=\"Setting\" id=\"ModModeAprilFool001\" max=\"2\" min=\"0\" default=\"0\"/>", [&] { INSTALL_FAST_HOOK (AvailableMode_AprilFool001); }//, modeUnlock ); // TestMode::RegisterItem (modeUnlock); diff --git a/src/poll.h b/src/poll.h index 90ec0ac..dc92682 100644 --- a/src/poll.h +++ b/src/poll.h @@ -110,5 +110,4 @@ bool IsButtonReleased (const Keybindings &bindings); #else void UpdatePoll (HWND windowHandle); void InitializeKeyboard (); -void DisposeKeyboard (); #endif \ No newline at end of file diff --git a/src/pollasync.cpp b/src/pollasync.cpp index 1366a33..9bc5422 100644 --- a/src/pollasync.cpp +++ b/src/pollasync.cpp @@ -9,8 +9,13 @@ extern bool jpLayout; extern int exited; extern u8 inputState; extern float axisThreshold; +extern bool globalKeyboardInput; bool wndForeground = false; +bool usingKeyboard = false; +bool usingMouse = false; +bool usingController = false; +bool usingSDLEvent = false; bool currentKeyboardState[0xFF] = { false }; uint8_t keyboardCount[0xFF] = { 0 }; @@ -125,17 +130,6 @@ LRESULT CALLBACK InputProc(int nCode, WPARAM wParam, LPARAM lParam) { DWORD keyCode = pKeyboard->vkCode; currentKeyboardState[keyCode] = false; } break; - case WM_MOUSEWHEEL: if (wndForeground) { - MSLLHOOKSTRUCT *pMouseStruct = (MSLLHOOKSTRUCT*)lParam; - int wheelDelta = GET_WHEEL_DELTA_WPARAM(pMouseStruct->mouseData); - if (wheelDelta > 0) { - mouseWheelCount[0] = std::min (mouseWheelCount[0] + wheelDelta, maxCount); - currentMouseState.ScrolledUp = true; - } else if (wheelDelta < 0) { - mouseWheelCount[1] = std::min (mouseWheelCount[1] - wheelDelta, maxCount); - currentMouseState.ScrolledDown = true; - } - } break; default: break; } } @@ -171,16 +165,11 @@ void KeyboardMainLoop() { HINSTANCE hInstance = GetModuleHandle(NULL); HWND hwnd = CreateInvisibleWindow(hInstance); if (!hwnd) LogMessage (LogLevel::ERROR, "Failed to create window!\n"); - if (inputState & 1) { + if (usingKeyboard) { keyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL, InputProc, nullptr, 0); if (keyboardHook == nullptr) LogMessage (LogLevel::ERROR, "Failed to install keyboard hook!\n"); else LogMessage (LogLevel::INFO, "KeyboardLL hook installed!"); } - if (inputState & (1 << 1)) { - mouseHook = SetWindowsHookEx(WH_MOUSE_LL, InputProc, nullptr, 0); - if (mouseHook == nullptr) LogMessage (LogLevel::ERROR, "Failed to install mouse hook!\n"); - else LogMessage (LogLevel::INFO, "MouseLL hook installed!"); - } if (maxCount > 2) LogMessage (LogLevel::ERROR, "CHEATING MODE! max count is set to {}", maxCount); LogMessage (LogLevel::WARN, "(experimental) Using Async IO!"); MSG msg; @@ -189,22 +178,15 @@ void KeyboardMainLoop() { DispatchMessage(&msg); } if (keyboardHook) UnhookWindowsHookEx(keyboardHook); - if (mouseHook) UnhookWindowsHookEx(mouseHook); } void InitializeKeyboard () { - if (inputState & (1 | 1 << 1)) { + if (usingKeyboard) { std::thread (KeyboardMainLoop).detach (); } } -void -DisposeKeyboard () { - // if (keyboardHook) UnhookWindowsHookEx(keyboardHook); - // if (mouseHook) UnhookWindowsHookEx(mouseHook); -} - void CheckFlipped (uint32_t which, SDL_Gamepad *gamepad) { if (SDL_GetGamepadButtonLabel(gamepad, SDL_GAMEPAD_BUTTON_SOUTH) == SDL_GAMEPAD_BUTTON_LABEL_B) { @@ -214,8 +196,13 @@ CheckFlipped (uint32_t which, SDL_Gamepad *gamepad) { bool InitializePoll (HWND windowHandle) { + usingKeyboard = inputState & 1; + usingMouse = inputState & (1 << 1); + usingController = inputState & (1 << 2); + usingSDLEvent = usingMouse || usingController; + InitializeKeyboard (); - if (inputState & (1 << 2)) { + if (usingSDLEvent) { LogMessage (LogLevel::DEBUG, "InitializePoll"); bool hasRumble = true; wndForeground = windowHandle == GetForegroundWindow (); @@ -303,31 +290,42 @@ void UpdatePoll (HWND windowHandle) { if (!CheckForegroundWindow (windowHandle)) return; - if ((inputState & 1) && keyboardClean) { + if (usingKeyboard && keyboardClean) { keyboardClean = false; for (int i=0; i<0xFF; i++) keyboardCount[i] -= (bool)keyboardDiff[i]; memset (keyboardDiff, 0, 0XFF); } - if (inputState & (1 << 1)) { - currentMouseState.ScrolledUp = false; - currentMouseState.ScrolledDown = false; - if (mouseWheelCount[0] > 0) mouseWheelCount[0] -= (bool)mouseWheelDiff[0]; - if (mouseWheelCount[1] > 0) mouseWheelCount[1] -= (bool)mouseWheelDiff[1]; - memset (mouseWheelDiff, 0, 2); - } - // GetCursorPos (¤tMouseState.Position); // ScreenToClient (windowHandle, ¤tMouseState.Position); - if (inputState & (1 << 2)) { - for (int i=0; i 0) mouseWheelCount[0] -= (bool)mouseWheelDiff[0]; + if (mouseWheelCount[1] > 0) mouseWheelCount[1] -= (bool)mouseWheelDiff[1]; + memset (mouseWheelDiff, 0, 2); + } + + if (usingController) { + for (int i=0; i 0) { + mouseWheelCount[0] = std::min (mouseWheelCount[0] + 1, maxCount); + currentMouseState.ScrolledUp = true; + } else if (event.wheel.y < 0) { + mouseWheelCount[1] = std::min (mouseWheelCount[1] + 1, maxCount); + currentMouseState.ScrolledDown = true; + } + } break; case SDL_EVENT_GAMEPAD_ADDED: if (!SDL_IsGamepad (event.gdevice.which)) break; controller = SDL_OpenGamepad (event.gdevice.which); From 625795d3ee05cd0dab38f09f08657b9e101f5800 Mon Sep 17 00:00:00 2001 From: ptmaster Date: Tue, 24 Dec 2024 02:10:05 +0800 Subject: [PATCH 08/11] Fix encrypted qr issue --- src/patches/scanner.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/patches/scanner.cpp b/src/patches/scanner.cpp index 8f8ad2c..54ecca3 100644 --- a/src/patches/scanner.cpp +++ b/src/patches/scanner.cpp @@ -278,7 +278,7 @@ namespace Qr { hexStream << std::hex << std::uppercase << std::setfill ('0') << std::setw (2); for (size_t i = 0; i < data->size (); i++) hexStream << static_cast ((*data)[i]) << " "; LogMessage (LogLevel::INFO, "[QR] Read QRData size: {} data: {}\n", data->size (), hexStream.str ()); - size_t finalCopySize = std::min (data->size () + 1, (size_t)length); + size_t finalCopySize = std::min (data->size (), (size_t)length); memcpy (dest, data->data (), finalCopySize); scanQueue.pop (); delete data; From 9bce6fee935a240a6cade87b72169818408e5a59 Mon Sep 17 00:00:00 2001 From: ptmaster Date: Wed, 25 Dec 2024 22:20:50 +0800 Subject: [PATCH 09/11] Input Optimize | language & testmode cleanup --- src/bnusio.cpp | 104 ++++++++++----------------------------- src/helpers.h | 1 + src/patches/language.cpp | 11 +++-- src/patches/plugins.cpp | 24 +++++++-- src/patches/testmode.cpp | 18 ++----- src/poll.h | 1 + src/pollasync.cpp | 39 ++++++++------- 7 files changed, 78 insertions(+), 120 deletions(-) diff --git a/src/bnusio.cpp b/src/bnusio.cpp index b8f93e9..624ae70 100644 --- a/src/bnusio.cpp +++ b/src/bnusio.cpp @@ -150,12 +150,14 @@ SDLAxis analogBindings[] = { u16 bnusio_GetAnalogIn (const u8 which) { + // LogMessage (LogLevel::DEBUG, "GetAnalogIn p={}", which); if (analogMethod) return analogMethod (which); else return 0; } u16 __fastcall bnusio_GetCoin (i32 a1) { - if (updateByCoin) bnusio::Update (); + // LogMessage (LogLevel::DEBUG, "GetCoin p={}", a1); + if (updateByCoin && a1 == 1) bnusio::Update (); return coin_count; } u16 __fastcall bnusio_GetService (i32 a1) { return service_count; } @@ -270,74 +272,6 @@ AnalogInputSimple (const u8 which) { return 0; } -#ifndef ASYNC_UPDATE -void -Update () { -#else -std::thread pollThread; -std::thread updateThread; -std::mutex syncMtx; -std::condition_variable syncCV; - -void -UpdateLoop () { - LogMessage (LogLevel::WARN, "(experimental) Using Async Update!"); - std::unique_lock syncLock(syncMtx); - while (exited < exitWait) { - syncCV.wait (syncLock); -#endif - if (exited && ++exited >= exitWait) ExitProcess (0); - -#ifndef ASYNC_IO - if (!inited) { - windowHandle = FindWindowA ("nuFoundation.Window", nullptr); - InitializePoll (windowHandle); - if (autoIme) { - currentLayout = GetKeyboardLayout (0); - auto engLayout = LoadKeyboardLayout (TEXT ("00000409"), KLF_ACTIVATE); - ActivateKeyboardLayout (engLayout, KLF_SETFORPROCESS); - } - - patches::Plugins::Init (); - inited = true; - } - - UpdatePoll (windowHandle); -#endif - std::vector buffer = {}; - if (IsButtonTapped (COIN_ADD)) { - LogMessage (LogLevel::DEBUG, "Insert Coin!"); - coin_count++; - } - if (IsButtonTapped (SERVICE)) { - LogMessage (LogLevel::DEBUG, "Insert Severice Coin!"); - service_count++; - } - if (IsButtonTapped (TEST)) { - LogMessage (LogLevel::INFO, "Enter TestMode by Press TestMode Button!"); - testEnabled = !testEnabled; - } - if (exited == 0 && IsButtonTapped (EXIT)) { - LogMessage (LogLevel::INFO, "Exit by Press Exit Button!"); - exited += 1; testEnabled = 1; std::thread([](){patches::Plugins::Exit ();}).detach(); - } - if (GameVersion::CHN00 == gameVersion) { - if (IsButtonTapped (CARD_INSERT_1)) patches::Scanner::Qr::CommitLogin (accessCode1); - if (IsButtonTapped (CARD_INSERT_2)) patches::Scanner::Qr::CommitLogin (accessCode2); - } else { - if (IsButtonTapped (CARD_INSERT_1)) patches::Scanner::Card::Commit (accessCode1, chipId1); - if (IsButtonTapped (CARD_INSERT_2)) patches::Scanner::Card::Commit (accessCode2, chipId2); - } - if (IsButtonTapped (QR_DATA_READ)) patches::Scanner::Qr::Commit (patches::Scanner::Qr::ReadQRData (buffer)); - if (IsButtonTapped (QR_IMAGE_READ)) patches::Scanner::Qr::Commit (patches::Scanner::Qr::ReadQRImage (buffer)); - - patches::Plugins::Update (); - patches::Scanner::Update (); -#ifdef ASYNC_UPDATE - } -#endif -} - void Init () { SetKeyboardButtons (); @@ -463,17 +397,11 @@ Init () { INSTALL_HOOK_DIRECT (bnusio_ResetCoin, bnusio_ResetCoin_Original); LogMessage (LogLevel::WARN, "USIO emulation disabled"); } -#ifdef ASYNC_UPDATE - else { - updateThread = std::thread (bnusio::UpdateLoop); - updateThread.detach (); - } -#endif } -#ifdef ASYNC_UPDATE void Update () { + if (exited && ++exited >= exitWait) ExitProcess (0); if (!inited) { windowHandle = FindWindowA ("nuFoundation.Window", nullptr); InitializePoll (windowHandle); @@ -482,14 +410,32 @@ Update () { auto engLayout = LoadKeyboardLayout (TEXT ("00000409"), KLF_ACTIVATE); ActivateKeyboardLayout (engLayout, KLF_SETFORPROCESS); } - patches::Plugins::Init (); inited = true; } UpdatePoll (windowHandle); - syncCV.notify_all (); + + std::vector buffer = {}; + if (IsButtonTapped (COIN_ADD)) coin_count++; + if (IsButtonTapped (SERVICE)) service_count++; + if (IsButtonTapped (TEST)) testEnabled = !testEnabled; + if (exited == 0 && IsButtonTapped (EXIT)) { + LogMessage (LogLevel::INFO, "Exit by Press Exit Button!"); + exited += 1; testEnabled = 1; std::thread([](){patches::Plugins::Exit ();}).detach(); + } + if (GameVersion::CHN00 == gameVersion) { + if (IsButtonTapped (CARD_INSERT_1)) patches::Scanner::Qr::CommitLogin (accessCode1); + if (IsButtonTapped (CARD_INSERT_2)) patches::Scanner::Qr::CommitLogin (accessCode2); + } else { + if (IsButtonTapped (CARD_INSERT_1)) patches::Scanner::Card::Commit (accessCode1, chipId1); + if (IsButtonTapped (CARD_INSERT_2)) patches::Scanner::Card::Commit (accessCode2, chipId2); + } + if (IsButtonTapped (QR_DATA_READ)) patches::Scanner::Qr::Commit (patches::Scanner::Qr::ReadQRData (buffer)); + if (IsButtonTapped (QR_IMAGE_READ)) patches::Scanner::Qr::Commit (patches::Scanner::Qr::ReadQRImage (buffer)); + + patches::Plugins::Update (); + patches::Scanner::Update (); } -#endif void Close () { diff --git a/src/helpers.h b/src/helpers.h index e0b1eeb..b2983d7 100644 --- a/src/helpers.h +++ b/src/helpers.h @@ -210,6 +210,7 @@ inline bool sendFlag = false; } #define round(num) ((num > 0) ? (int)(num + 0.5) : (int)(num - 0.5)) +#define timestamp() (std::chrono::duration_cast(std::chrono::system_clock::now ().time_since_epoch ()).count ()) toml_table_t *openConfig (const std::filesystem::path &path); toml_table_t *openConfigSection (const toml_table_t *config, const std::string §ionName); diff --git a/src/patches/language.cpp b/src/patches/language.cpp index 513eb18..c3a5121 100644 --- a/src/patches/language.cpp +++ b/src/patches/language.cpp @@ -52,7 +52,7 @@ const LanguageItem languageItems[5][5] = { {{"en", "64", "en_64"},{"en", "30", "en_30"},{"en", "32_EB", "en_32" },{"en", "32_B", "en_32" },{"en", "32_DB", "en_32" }}, {{"tw", "64", "tw_64"},{"tw", "30", "tw_30"},{"tw", "32_EB", "tw_32" },{"tw", "32_B", "tw_32" },{"tw", "32_DB", "tw_32" }}, {{"kr", "64", "kr_64"},{"kr", "30", "kr_30"},{"kr", "32_EB", "kr_32" },{"kr", "32_B", "kr_32" },{"kr", "32_DB", "kr_32" }}, - {{"cn", "64", "cn_64"},{"cn", "30", "cn_30"},{"cn", "32_EB", "cn_32" },{"cn", "32_B", "cn_32" },{"cn", "32_DB", "cn_32" }}, + {{"cn", "64", "cn_64"},{"cn", "30", "cn_30"},{"cn", "32_EB", "cn_32_EB"},{"cn", "32_B", "cn_32_B"},{"cn", "32_DB", "cn_32_DB"}}, }; FAST_HOOK_DYNAMIC (int, initial_load_setting) { @@ -100,7 +100,10 @@ FAST_HOOK_DYNAMIC (double, GetCorrectionOffsetY, u64 a1, u32 a2) { void Init () { bool fontExistAll = true; - const char *fontToCheck[]{"cn_30.nutexb", "cn_30.xml", "cn_32.nutexb", "cn_32.xml", "cn_64.nutexb", "cn_64.xml"}; + const char *fontToCheck[]{ + "cn_30.nutexb", "cn_30.xml", "cn_32_EB.nutexb", "cn_32_EB.xml", "cn_32_B.nutexb", + "cn_32_B.xml", "cn_32_DB.nutexb", "cn_32_DB.xml", "cn_64.nutexb", "cn_64.xml" + }; for (int i = 0; i < 6; i++) { if (std::filesystem::exists (std::string ("..\\..\\Data\\x64\\font\\") + fontToCheck[i])) continue; fontExistAll = false; @@ -174,10 +177,8 @@ const std::vector languageFlas = {"taikoSelectFla", "taikoSelectFla typedef bool (*JsonHasMember) (u64, const char *); typedef u64 *(*JsonGetMember) (u64, const char *); -typedef void (*VectorIterator) (char *, u64, u64, u64); JsonHasMember jsonHasMember = nullptr; JsonGetMember jsonGetMember = nullptr; -VectorIterator vectorIterator = nullptr; uintptr_t WordlistLanguageTypeRIP = 0; MID_HOOK_DYNAMIC (WordlistLanguageType, SafetyHookContext &ctx) { @@ -274,7 +275,6 @@ Init () { case GameVersion::JPN39: { jsonHasMember = (JsonHasMember)ASLR (0x1400B5A30); jsonGetMember = (JsonGetMember)ASLR (0x1400B6080); - vectorIterator = (VectorIterator)ASLR (0x14079C430); // App::DataTableHolder::Serialize WordlistLanguageTypeRIP = ASLR (0x1400B20B8); INSTALL_MID_HOOK_DYNAMIC (WordlistLanguageType, ASLR (0x1400B1E47)); @@ -614,6 +614,7 @@ Init () { }; for (std::string voiceFile : voiceFiles) checkVoiceFile (("..\\..\\Data\\x64\\sound\\" + voiceFile).c_str ()); if (enableSwitchVoice) { + LogMessage (LogLevel::INFO, "Detected voice files, install voice patches!"); TestMode::RegisterItemAfter( L"/root/menu[@id='OthersMenu']/layout[@type='Center']/select-item[@id='LanguageItem']", L" plugins = {}; @@ -15,6 +17,9 @@ namespace patches::Plugins { typedef void (*SendQRLoginEvent) (CommitQrLoginCallback login); typedef void (*StatusChangeEvent) (size_t type, bool status); + std::mutex updateMutex; + std::condition_variable updateCV; + void Init () { for (auto plugin : plugins) { @@ -24,13 +29,11 @@ namespace patches::Plugins { } void Update () { - for (auto plugin : plugins) { - auto event = GetProcAddress (plugin, "Update"); - if (event) ((BasicEvent)event) (); - } + updateCV.notify_all (); } void Exit () { + updateCV.notify_all (); for (auto plugin : plugins) { auto event = GetProcAddress (plugin, "Exit"); if (event) ((BasicEvent)event) (); @@ -129,6 +132,19 @@ namespace patches::Plugins { } } } + + std::thread ([&](){ + std::unique_lock updateLock(updateMutex); + while (exited == 0) { + updateCV.wait (updateLock); + if (exited == 0) { + for (auto plugin : plugins) { + auto event = GetProcAddress (plugin, "Update"); + if (event) ((BasicEvent)event) (); + } + } + } + }).detach (); } diff --git a/src/patches/testmode.cpp b/src/patches/testmode.cpp index 937a135..42b3477 100644 --- a/src/patches/testmode.cpp +++ b/src/patches/testmode.cpp @@ -483,33 +483,25 @@ Init () { INSTALL_FAST_HOOK_DYNAMIC (SceneTestModeLoading, ASLR (0x1404793D0)); INSTALL_FAST_HOOK_DYNAMIC (SceneTestModeFinalize, ASLR (0x140479600)); INSTALL_FAST_HOOK_DYNAMIC (SceneFirstInitialize, ASLR (0x1404574B0)); + bool originalDeviceInitialize = L"DeviceInitialize.xml"; if (Language::CnFontPatches () && std::filesystem::exists ("..\\..\\Data\\x64\\testmode\\DeviceInitialize_china.xml")) { usingDeviceInitialize = L"DeviceInitialize_china.xml"; patches.push_back (safetyhook::create_mid (ASLR (0x140465549), [](SafetyHookContext &ctx) - { ctx.r8 = 2; ctx.rdx = (uintptr_t)"cn"; ctx.rip = ASLR (0x140465556); })); + { ctx.r8 = 2; ctx.rdx = (uintptr_t)"cn"; ctx.rip = ASLR (0x140465556); })); // DeviceCheck = Loading Font + patches.push_back (safetyhook::create_mid (ASLR (0x1404676E7), [](SafetyHookContext &ctx) + { ctx.r8 = 2; ctx.rdx = (uintptr_t)"cn"; ctx.rip = ASLR (0x1404676F4); })); // ?? WRITE_MEMORY (ASLR (0x140CD1E40), wchar_t, L"加载中\0"); WRITE_MEMORY (ASLR (0x140CD1E28), wchar_t, L"加载中.\0"); WRITE_MEMORY (ASLR (0x140CD1E68), wchar_t, L"加载中..\0"); WRITE_MEMORY (ASLR (0x140CD1E50), wchar_t, L"加载中...\0"); - } else if (std::filesystem::exists ("..\\..\\Data\\x64\\testmode\\DeviceInitialize_chspatch.xml")) { - usingDeviceInitialize = L"DeviceInitialize_chspatch.xml"; - WRITE_MEMORY (ASLR (0x140CD1E40), wchar_t, L"加載中\0"); - WRITE_MEMORY (ASLR (0x140CD1E28), wchar_t, L"加載中.\0"); - WRITE_MEMORY (ASLR (0x140CD1E68), wchar_t, L"加載中..\0"); - WRITE_MEMORY (ASLR (0x140CD1E50), wchar_t, L"加載中...\0"); } else usingDeviceInitialize = originalDeviceInitialize; originalTestMode = L"TestMode.xml"; if (Language::CnFontPatches () && std::filesystem::exists ("..\\..\\Data\\x64\\testmode\\TestMode_china.xml")) { usingTestMode = L"TestMode_china.xml"; patches.push_back (safetyhook::create_mid (ASLR (0x14047C603), [](SafetyHookContext &ctx) - { ctx.r8 = 2; ctx.rdx = (uintptr_t)"cn"; ctx.rip = ASLR (0x14047C610); })); - patches.push_back (safetyhook::create_mid (ASLR (0x1404676E7), [](SafetyHookContext &ctx) - { ctx.r8 = 2; ctx.rdx = (uintptr_t)"cn"; ctx.rip = ASLR (0x1404676F4); })); - } else if (std::filesystem::exists ("..\\..\\Data\\x64\\testmode\\TestMode_chspatch.xml")) { - usingTestMode = L"TestMode_chspatch.xml"; + { ctx.r8 = 2; ctx.rdx = (uintptr_t)"cn"; ctx.rip = ASLR (0x14047C610); })); // TestMode = DeviceInitialize } else usingTestMode = originalTestMode; - } break; case GameVersion::CHN00: break; } diff --git a/src/poll.h b/src/poll.h index dc92682..9b7edb4 100644 --- a/src/poll.h +++ b/src/poll.h @@ -109,5 +109,6 @@ bool ControllerAxisIsReleased (const SDLAxis axis); bool IsButtonReleased (const Keybindings &bindings); #else void UpdatePoll (HWND windowHandle); +void CleanPoll (); void InitializeKeyboard (); #endif \ No newline at end of file diff --git a/src/pollasync.cpp b/src/pollasync.cpp index 9bc5422..f4e6132 100644 --- a/src/pollasync.cpp +++ b/src/pollasync.cpp @@ -287,32 +287,33 @@ CorrectButton (uint32_t which, uint8_t button) { } void -UpdatePoll (HWND windowHandle) { - if (!CheckForegroundWindow (windowHandle)) return; - +CleanPoll () { if (usingKeyboard && keyboardClean) { keyboardClean = false; for (int i=0; i<0xFF; i++) keyboardCount[i] -= (bool)keyboardDiff[i]; memset (keyboardDiff, 0, 0XFF); } + if (usingMouse) { + currentMouseState.ScrolledUp = false; + currentMouseState.ScrolledDown = false; + if (mouseWheelCount[0] > 0) mouseWheelCount[0] -= (bool)mouseWheelDiff[0]; + if (mouseWheelCount[1] > 0) mouseWheelCount[1] -= (bool)mouseWheelDiff[1]; + memset (mouseWheelDiff, 0, 2); + } - // GetCursorPos (¤tMouseState.Position); - // ScreenToClient (windowHandle, ¤tMouseState.Position); + if (usingController) { + for (int i=0; i 0) mouseWheelCount[0] -= (bool)mouseWheelDiff[0]; - if (mouseWheelCount[1] > 0) mouseWheelCount[1] -= (bool)mouseWheelDiff[1]; - memset (mouseWheelDiff, 0, 2); - } - - if (usingController) { - for (int i=0; i Date: Wed, 25 Dec 2024 23:05:57 +0800 Subject: [PATCH 10/11] fix testmode crash --- src/patches/testmode.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/patches/testmode.cpp b/src/patches/testmode.cpp index 42b3477..feddde3 100644 --- a/src/patches/testmode.cpp +++ b/src/patches/testmode.cpp @@ -483,7 +483,6 @@ Init () { INSTALL_FAST_HOOK_DYNAMIC (SceneTestModeLoading, ASLR (0x1404793D0)); INSTALL_FAST_HOOK_DYNAMIC (SceneTestModeFinalize, ASLR (0x140479600)); INSTALL_FAST_HOOK_DYNAMIC (SceneFirstInitialize, ASLR (0x1404574B0)); - bool originalDeviceInitialize = L"DeviceInitialize.xml"; if (Language::CnFontPatches () && std::filesystem::exists ("..\\..\\Data\\x64\\testmode\\DeviceInitialize_china.xml")) { usingDeviceInitialize = L"DeviceInitialize_china.xml"; From 899445a09c5c6200477e01622d0bc2f81efba049 Mon Sep 17 00:00:00 2001 From: RyuMiyaX <52694802+ryumiyax@users.noreply.github.com> Date: Sat, 28 Dec 2024 15:02:47 +0800 Subject: [PATCH 11/11] Fix build.yml version issue --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1cfcf43..b99846a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -12,7 +12,7 @@ jobs: - name: Set up MSVC uses: ilammy/msvc-dev-cmd@v1 - name: Configure CMake - run: cmake -B build -S . -G "Visual Studio 17 2022" -A x64 -DCMAKE_BUILD_TYPE=Release -DCMAKE_SYSTEM_VERSION=10.0.26100.0 + run: cmake -B build -S . -G "Visual Studio 17 2022" -A x64 -DCMAKE_BUILD_TYPE=Release -DCMAKE_SYSTEM_VERSION="10.0.26100.0" - name: Build run: cmake --build build --config Release --target bnusio --verbose - uses: actions/upload-artifact@v4