From 0d4ca8b79e2ed69f3b858d6c6f590c876c8a13f8 Mon Sep 17 00:00:00 2001 From: ptmaster Date: Sat, 7 Dec 2024 06:22:53 +0800 Subject: [PATCH] optimize bnusio_GetAnalogIn add High Resolution Timer move chs_voice to testmode remove garmc dirty logs fix pollasync keyboard & mouse wheel --- CMakeLists.txt | 1 + src/bnusio.cpp | 84 ++++++++--------- src/bnusio.h | 2 +- src/dllmain.cpp | 2 + src/patches/patches.h | 4 + src/patches/scanner.cpp | 2 +- src/patches/testmode.cpp | 41 +++++++- src/patches/timer.cpp | 45 +++++++++ src/patches/versions/JPN39.cpp | 118 ++++++++++++++--------- src/pollasync.cpp | 166 +++++++++++++++++++-------------- 10 files changed, 305 insertions(+), 160 deletions(-) create mode 100644 src/patches/timer.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 253385b..abf3be6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -140,6 +140,7 @@ set(SOURCES # src/patches/qr.cpp src/patches/layeredfs.cpp src/patches/testmode.cpp + src/patches/timer.cpp src/patches/versions/JPN00.cpp src/patches/versions/JPN08.cpp src/patches/versions/JPN39.cpp diff --git a/src/bnusio.cpp b/src/bnusio.cpp index 5359f3f..230447d 100644 --- a/src/bnusio.cpp +++ b/src/bnusio.cpp @@ -125,10 +125,14 @@ 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 buttonWaitPeriodP1 = 0; -u16 buttonWaitPeriodP2 = 0; -std::queue buttonQueueP1; -std::queue buttonQueueP2; +u16 cooldown[8] = { 0 }; +u16 buttonWaitPeriod[] = { 0, 0 }; +std::queue buttonQueue[] = { {}, {} }; + +// u16 buttonWaitPeriodP1 = 0; +// u16 buttonWaitPeriodP2 = 0; +// std::queue buttonQueueP1; +// std::queue buttonQueueP2; bool analogInput; SDLAxis analogBindings[] = { @@ -139,52 +143,39 @@ SDLAxis analogBindings[] = { u16 bnusio_GetAnalogIn (const u8 which) { if (analogInput) { - if (const u16 analogValue = static_cast (32768 * ControllerAxisIsDown (analogBindings[which])); analogValue > 100) return analogValue; - return 0; + const u16 analogValue = static_cast (32768 * ControllerAxisIsDown (analogBindings[which])); + if (analogValue > 100) return analogValue; + else return 0; } const auto button = analogButtons[which]; - if (which == 0) { - if (buttonWaitPeriodP1 > 0) buttonWaitPeriodP1--; - if (buttonWaitPeriodP2 > 0) buttonWaitPeriodP2--; - } - if (const bool isP1 = which / 4 == 0; (isP1 && !buttonQueueP1.empty ()) || (!isP1 && !buttonQueueP2.empty ())) { - if ((isP1 && buttonQueueP1.front () == which && buttonWaitPeriodP1 == 0) - || (!isP1 && buttonQueueP2.front () == which && buttonWaitPeriodP2 == 0)) { - if (isP1) { - buttonQueueP1.pop (); - buttonWaitPeriodP1 = drumWaitPeriod; - } else { - buttonQueueP2.pop (); - buttonWaitPeriodP2 = drumWaitPeriod; - } + const int blue = !(which % 4 % 3); + const int player = which / 4; - const u16 hitValue = !valueStates[which] ? 50 : 51; - valueStates[which] = !valueStates[which]; - return (hitValue << 15) / 100 + 1; - } - if (IsButtonTapped (*button)) { - if (isP1) buttonQueueP1.push (which); - else buttonQueueP2.push (which); - } - return 0; - } else if (IsButtonTapped (*button)) { - if (isP1 && buttonWaitPeriodP1 > 0) { - buttonQueueP1.push (which); - return 0; - } - if (!isP1 && buttonWaitPeriodP2 > 0) { - buttonQueueP2.push (which); - return 0; - } - if (isP1) buttonWaitPeriodP1 = drumWaitPeriod; - else buttonWaitPeriodP2 = drumWaitPeriod; + u16 analogValue = 0; + if (which == 0) { + for (int i=0; i<2; i++) if (buttonWaitPeriod[i] > 0) buttonWaitPeriod[i]--; + for (int i=0; i<8; i++) if (cooldown[i] > 0) cooldown[i]--; + } + if (buttonWaitPeriod[player] == 0 && !buttonQueue[player].empty () && buttonQueue[player].front () == which) { + buttonQueue[player].pop (); + buttonWaitPeriod[player] = drumWaitPeriod; const u16 hitValue = !valueStates[which] ? 50 : 51; valueStates[which] = !valueStates[which]; - return (hitValue << 15) / 100 + 1; + analogValue = (hitValue << 15) / 100 + 1; } + if (IsButtonTapped (*button)) { + if (drumWaitPeriod > 0) { + if (blue && buttonWaitPeriod[player] > 0) buttonQueue[player].push (which); + buttonWaitPeriod[player] = drumWaitPeriod; + } else if (blue && cooldown[which] > 0) return 0; - return 0; + if (blue) cooldown[which] = 4; + const u16 hitValue = !valueStates[which] ? 50 : 51; + valueStates[which] = !valueStates[which]; + analogValue = (hitValue << 15) / 100 + 1; + } + return analogValue; } u16 __fastcall bnusio_GetCoin (i32 a1) { @@ -277,10 +268,10 @@ void UpdateLoop () { LogMessage (LogLevel::WARN, "Using Async Update (experimental)!"); std::unique_lock syncLock(syncMtx); - while (exited < 50) { + while (exited < 120) { syncCV.wait (syncLock); #endif - if (exited && ++exited >= 50) ExitProcess (0); + if (exited && ++exited >= 120) ExitProcess (0); if (!inited) { windowHandle = FindWindowA ("nuFoundation.Window", nullptr); InitializePoll (windowHandle); @@ -301,7 +292,10 @@ UpdateLoop () { if (IsButtonTapped (COIN_ADD)) coin_count++; if (IsButtonTapped (SERVICE) && !testEnabled) service_count++; if (IsButtonTapped (TEST)) testEnabled = !testEnabled; - if (IsButtonTapped (EXIT)) { exited += 1; testEnabled = 1; patches::Plugins::Exit (); } + if (IsButtonTapped (EXIT)) { + LogMessage (LogLevel::INFO, "Exit By Press Exit Button!"); + exited += 1; testEnabled = 1; patches::Plugins::Exit (); + } if (GameVersion::CHN00 == gameVersion) { if (IsButtonTapped (CARD_INSERT_1)) patches::Scanner::Qr::CommitLogin (accessCode1); if (IsButtonTapped (CARD_INSERT_2)) patches::Scanner::Qr::CommitLogin (accessCode2); diff --git a/src/bnusio.h b/src/bnusio.h index b0f7588..c964101 100644 --- a/src/bnusio.h +++ b/src/bnusio.h @@ -1,5 +1,5 @@ #pragma once -#define ASYNC_UPDATE +// #define ASYNC_UPDATE namespace bnusio { void Init (); void Update (); diff --git a/src/dllmain.cpp b/src/dllmain.cpp index 1642b67..b0fbcd5 100644 --- a/src/dllmain.cpp +++ b/src/dllmain.cpp @@ -266,6 +266,8 @@ DllMain (HMODULE module, const DWORD reason, LPVOID reserved) { patches::LayeredFs::Init (); patches::TestMode::Init (); + patches::Timer::Init (); + LogMessage (LogLevel::INFO, "==== Finished Loading patches!"); } return true; diff --git a/src/patches/patches.h b/src/patches/patches.h index 00769cb..03cc8d6 100644 --- a/src/patches/patches.h +++ b/src/patches/patches.h @@ -55,6 +55,7 @@ void Init (); void Append (const pugi::xml_node &node, const wchar_t *attr, const std::wstring &append); 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); void RegisterItem (const std::wstring &item, const std::function &initMethod, Menu *menu); void RegisterItem (const std::wstring &item, const std::function &initMethod); @@ -114,4 +115,7 @@ std::vector &ReadQRData (std::vector &buffer); std::vector &ReadQRImage (std::vector &buffer); } // namespace Qr } // namespace Scanner +namespace Timer { +void Init (); +} // namespace timer } // namespace patches diff --git a/src/patches/scanner.cpp b/src/patches/scanner.cpp index 83ec999..1b4a469 100644 --- a/src/patches/scanner.cpp +++ b/src/patches/scanner.cpp @@ -297,7 +297,7 @@ namespace Qr { } std::vector buffer = {}; std::string accessQRDataBase = "BNTTCNID"; - if (!accessCode._Starts_with (accessQRDataBase)) + if (!accessCode.starts_with (accessQRDataBase)) for (char word : accessQRDataBase) buffer.push_back (word); for (char word : accessCode) buffer.push_back (word); return patches::Scanner::Qr::Commit (buffer); diff --git a/src/patches/testmode.cpp b/src/patches/testmode.cpp index baca783..46353ac 100644 --- a/src/patches/testmode.cpp +++ b/src/patches/testmode.cpp @@ -82,7 +82,10 @@ public: if (size == 0) return node; size_t maxPage = size <= 14 ? 1 : (size / 13 + (size % 13 > 0)); LogMessage (LogLevel::DEBUG, "Render testmode menu with items(size={}, page={})", size, maxPage); - std::wstring parentId = node->parent ().parent ().attribute (L"id").value (); + std::wstring menuName = L"menu"; + pugi::xml_node parentNode = node->parent (); + while (parentNode.name() != menuName) parentNode = parentNode.parent (); + std::wstring parentId = parentNode.attribute (L"id").value (); pugi::xml_document menuItem; menuItem.load_string (std::format (L"", this->menuName, this->menuId).c_str ()); @@ -289,6 +292,16 @@ HOOK_DYNAMIC (void, TestModeSetMenuHook, u64 testModeLibrary, const wchar_t *lFi originalTestModeSetMenuHook (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 @@ -424,7 +437,14 @@ Init () { const auto configPath = std::filesystem::current_path () / "config.toml"; const std::unique_ptr config_ptr (openConfig (configPath), toml_free); - const u64 testModeSetMenuAddress = PROC_ADDRESS_OFFSET ("TestModeLibrary.dll", 0x99D0); + 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; @@ -442,7 +462,9 @@ Init () { CommonModify (); - INSTALL_HOOK_DYNAMIC (TestModeSetMenuHook, testModeSetMenuAddress); + INSTALL_HOOK_DYNAMIC (TestModeSetMenuHook, testModeSetMenu); + // INSTALL_HOOK_DYNAMIC (TestModeGetValueHook, testModeGetValue); + // INSTALL_HOOK_DYNAMIC (TestModeSetValueHook, testModeSetValue); } void @@ -457,7 +479,9 @@ 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; } } @@ -465,6 +489,17 @@ ReadTestModeValue (const wchar_t *itemId) { return -1; } +void +SetTestModeValue (const wchar_t *itemId, int value) { + if (appAccessor) { + if (const u64 testModeMain = refTestMode (appAccessor)) { + u64 *reader = *reinterpret_cast (testModeMain + 16); + (*reinterpret_cast (*reader + 176)) (reader, itemId, value); + // ((TestModeSetValueHook)whereTestModeSetMenuHook) (reader, itemId, value); + } + } +} + Menu * CreateMenu (const std::wstring &menuName, const std::wstring &menuId) { LogMessage (LogLevel::DEBUG, L"Create MenuName: {} MenuId: {}", menuName, menuId); diff --git a/src/patches/timer.cpp b/src/patches/timer.cpp new file mode 100644 index 0000000..85f738c --- /dev/null +++ b/src/patches/timer.cpp @@ -0,0 +1,45 @@ +#include "constants.h" +#include "helpers.h" +#include "patches.h" + +extern "C" NTSTATUS NTAPI NtSetTimerResolution( + IN ULONG DesiredResolution, + IN BOOLEAN SetResolution, + OUT PULONG CurrentResolution +); + +extern "C" NTSTATUS NTAPI NtQueryTimerResolution( + OUT PULONG CurrentResolution, + OUT PULONG MinimumResolution, + OUT PULONG MaximumResolution +); + +namespace patches::Timer { + ULONG currentResolution = 0; + ULONG minimumResolution = 0; + ULONG maximumResolution = 0; + + void + Release () { + NtSetTimerResolution(currentResolution, FALSE, ¤tResolution); + } + + void + Init () { + NTSTATUS queryStatus = NtQueryTimerResolution(¤tResolution, &minimumResolution, &maximumResolution); + if (queryStatus == 0) { + bool setHighResolutionTimer = currentResolution > maximumResolution; + LogMessage (LogLevel::INFO, "Timer Resolution current: {}ms maximum: {}ms", currentResolution / 10000.0, maximumResolution / 10000.0); + + if (setHighResolutionTimer) { + NTSTATUS status = NtSetTimerResolution(maximumResolution, TRUE, ¤tResolution); + if (status == 0) { + LogMessage (LogLevel::INFO, "Successfully change Timer resolution to {}ms", maximumResolution / 10000.0); + } else { + LogMessage (LogLevel::ERROR, "Failed to change Timer resolution, status={}", status); + } + atexit (Release); + } + } else LogMessage (LogLevel::ERROR, "Failed to query Timer resolution, status={}", queryStatus); + } +} \ No newline at end of file diff --git a/src/patches/versions/JPN39.cpp b/src/patches/versions/JPN39.cpp index 468beb3..fb71d0b 100644 --- a/src/patches/versions/JPN39.cpp +++ b/src/patches/versions/JPN39.cpp @@ -16,6 +16,10 @@ HOOK_DYNAMIC (i64, curl_easy_setopt, i64 a1, i64 a2, i64 a3, i64 a4, i64 a5) { originalcurl_easy_setopt (a1, 81, 0, 0, 0); return originalcurl_easy_setopt (a1, a2, a3, a4, a5); } +HOOK_DYNAMIC (void, garmc_logger_log, i64 a1, int a2, void *a3, char a4) { + // remove garmc log + return; +} FUNCTION_PTR (i64, GetPlayDataManagerRef, ASLR (0x140024AC0), i64); @@ -50,6 +54,7 @@ HOOK (i64, DeviceCheck, ASLR (0x140464FC0), i64 a1, i64 a2, i64 a3) { LogMessage (LogLevel::HOOKS, "DeviceCheck was called"); TestMode::SetupAccessor (a3, RefTestModeMain); componentAccessor = a2; + appAccessor = a3; return originalDeviceCheck (a1, a2, a3); } @@ -75,7 +80,8 @@ MID_HOOK (DifficultyPanelCrown, ASLR (0x1403F2A25), SafetyHookContext &ctx) { } HOOK (i64, AvailableMode_Collabo024, ASLR (0x1402DE710), i64 a1) { LogMessage (LogLevel::HOOKS, "AvailableMode_Collabo024 was called"); - if (const int tournamentMode = TestMode::ReadTestModeValue (L"TournamentMode"); tournamentMode == 1) return originalAvailableMode_Collabo024 (a1); + const int tournamentMode = TestMode::ReadTestModeValue (L"TournamentMode"); + if (tournamentMode == 1) return originalAvailableMode_Collabo024 (a1); const int status = TestMode::ReadTestModeValue (L"ModModeCollabo024"); if (status == 1 && GetUserStatus () == 1) return lua_pushbool (a1, true); return originalAvailableMode_Collabo024 (a1); @@ -240,7 +246,7 @@ get_bank_id (const std::string &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 (enableSwitchVoice && bankName.starts_with ("voice_")) { + if (bankName.starts_with ("voice_")) { const int binfLength = *reinterpret_cast (pBinfBlock + 4); u8 *pGrpBlock = pBinfBlock + 8 + binfLength; const int grpLength = *reinterpret_cast (pGrpBlock + 4); @@ -261,7 +267,10 @@ check_voice_tail (const std::string &bankName, u8 *pBinfBlock, std::map 0) { std::string title (reinterpret_cast (currToneBase + titleOffset)); if (title.ends_with (tail)) { - if (!voiceExist.contains (bankName) || !voiceExist[bankName]) voiceExist[bankName] = true; + if (!voiceExist.contains (bankName) || !voiceExist[bankName]) { + voiceExist[bankName] = true; + enableSwitchVoice = true; + } return; } } @@ -288,32 +297,34 @@ MID_HOOK (GenNus3bankId, ASLR (0x1407B97BD), SafetyHookContext &ctx) { } std::string -FixToneName (const std::string &bankName, std::string toneName) { - if (language == 2 || language == 4) { +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; -HOOK (i64, PlaySound, ASLR (0x1404C6DC0), i64 a1) { - LogMessage (LogLevel::HOOKS, "PlaySound was called"); - if (enableSwitchVoice && language != 0) { +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)).c_str ()); + lua_pushstring (a1, FixToneName (bankName, lua_tolstring (a1, -2, &commonSize), lang).c_str ()); lua_replace (a1, -3); } } - return originalPlaySound (a1); + return originalPlaySoundMain (a1); } HOOK (i64, PlaySoundMulti, ASLR (0x1404C6D60), i64 a1) { LogMessage (LogLevel::HOOKS, "PlaySoundMulti was called"); - if (enableSwitchVoice && language != 0) { + 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)).c_str ()); + lua_pushstring (a1, FixToneName (bankName, lua_tolstring (a1, -2, &commonSize), lang).c_str ()); lua_replace (a1, -3); } } @@ -323,8 +334,8 @@ HOOK (i64, PlaySoundMulti, ASLR (0x1404C6D60), i64 a1) { FUNCTION_PTR (u64 *, append_chars_to_basic_string, ASLR (0x140028DA0), u64 *, const char *, size_t); u64 * -FixToneNameEnso (u64 *Src, const std::string &bankName) { - if (language == 2 || language == 4) { +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; @@ -332,18 +343,20 @@ FixToneNameEnso (u64 *Src, const std::string &bankName) { HOOK (bool, PlaySoundEnso, ASLR (0x1404ED590), u64 *a1, u64 *a2, i64 a3) { LogMessage (LogLevel::HOOKS, "PlaySoundEnso was called"); - if (enableSwitchVoice && language != 0) { + 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); + if (bankName[0] == 'v') a2 = FixToneNameEnso (a2, bankName, lang); } return originalPlaySoundEnso (a1, a2, a3); } HOOK (bool, PlaySoundSpecial, ASLR (0x1404ED230), u64 *a1, u64 *a2) { LogMessage (LogLevel::HOOKS, "PlaySoundSpecial was called"); - if (enableSwitchVoice && language != 0) { + 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); + if (bankName[0] == 'v') a2 = FixToneNameEnso (a2, bankName, lang); } return originalPlaySoundSpecial (a1, a2); } @@ -437,6 +450,23 @@ HOOK (u64, EnsoGameManagerChechEnsoEnd, ASLR (0x1400E2A10), u64 a1, u64 a2, u64 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; + LogMessage (LogLevel::DEBUG, "AcquireMostCompatibleDisplayMode {:d} {:d} {:f} {:f}", a3[0], a3[1], (float)(int)a3[2], (float)(int)a3[3]); + return originalAcquireMostCompatibleDisplayMode (a1, a2, a3); +} + +HOOK (char, SceneTestModeLoading, ASLR (0x1404793D0), u64 a1, u64 a2, u64 a3) { + LogMessage (LogLevel::DEBUG, "Begin SceneTestModeLoading"); + char result = originalSceneTestModeLoading (a1, a2, a3); + LogMessage (LogLevel::DEBUG, "End originalSceneTestModeLoading"); + TestMode::SetTestModeValue (L"EnableSwitchVoice", (int)enableSwitchVoice); + if (!enableSwitchVoice) TestMode::SetTestModeValue (L"VoiceLanguageItem", 0); + LogMessage (LogLevel::DEBUG, "End SceneTestModeLoading"); + return result; +} + constexpr i32 datatableBufferSize = 1024 * 1024 * 12; safetyhook::Allocation datatableBuffer1; safetyhook::Allocation datatableBuffer2; @@ -506,15 +536,13 @@ Init () { INSTALL_HOOK (EnsoGraphicManagerPreparing); INSTALL_HOOK (EnsoGameManagerStart); INSTALL_HOOK (EnsoGameManagerChechEnsoEnd); + INSTALL_HOOK (AcquireMostCompatibleDisplayMode); + INSTALL_HOOK (SceneTestModeLoading); // Apply common config patch WRITE_MEMORY (ASLR (0x140494533), i32, xRes); WRITE_MEMORY (ASLR (0x14049453A), i32, yRes); if (!vsync) WRITE_MEMORY (ASLR (0x14064C7E9), u8, 0xBA, 0x00, 0x00, 0x00, 0x00, 0x90); - if (unlockSongs) { - WRITE_MEMORY (ASLR (0x1403F45CF), u8, 0xB0, 0x01); - INSTALL_MID_HOOK (CountLockedCrown); - } // Bypass errors WRITE_MEMORY (ASLR (0x140041A00), u8, 0xC3); @@ -564,18 +592,39 @@ Init () { ReplaceLeaBufferAddress (datatableBuffer3Addresses, datatableBuffer3.data ()); } - // Fix Language - TestMode::RegisterItem( + // 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_HOOK (GetLanguage); INSTALL_HOOK (GetRegionLanguage); INSTALL_HOOK (GetCabinetLanguage); + }, langPatchesMenu + ); + TestMode::RegisterItem( + L"", + langResourceIndicator + ); + TestMode::RegisterItemAfter( + L"/root/menu[@id='OthersMenu']/layout[@type='Center']/select-item[@id='LanguageItem']", + L"", + [&](){ + INSTALL_HOOK (PlaySoundMain); + INSTALL_HOOK (PlaySoundMulti); + INSTALL_HOOK (PlaySoundEnso); + INSTALL_HOOK (PlaySoundSpecial); } ); + TestMode::RegisterItem(langResourceIndicator, langPatchesMenu); + TestMode::RegisterItem(langPatchesMenu); + // Unlock Songs - TestMode::RegisterItem( + TestMode::RegisterItem ( L"", [&]() { @@ -653,6 +702,7 @@ Init () { L"replace-text=\"0:ON, 1:OFF\" group=\"Setting\" id=\"AttractDemoItem\" max=\"1\" min=\"0\" default=\"0\"/>", [&](){ INSTALL_MID_HOOK (AttractDemo); } ); + // for (size_t i=0; i < 40; i++) TestMode::RegisterItem(std::format (L"", i + 1)); // Instant Result @@ -696,23 +746,6 @@ Init () { }); } - // Fix language - if (fixLanguage) { - INSTALL_HOOK (GetLanguage); // Language will use in other place - INSTALL_HOOK (GetRegionLanguage); - INSTALL_HOOK (GetCabinetLanguage); - } - - // if both chsPatch & fixLanguage enabled, try use cn voice from nus3bank - // don't worry, we will check if cn voice existed - if (chsPatch && fixLanguage) { - enableSwitchVoice = true; - INSTALL_HOOK (PlaySound); - INSTALL_HOOK (PlaySoundMulti); - INSTALL_HOOK (PlaySoundEnso); - INSTALL_HOOK (PlaySoundSpecial); - } - // Fix normal song play after passing through silent song INSTALL_MID_HOOK (GenNus3bankId); INSTALL_HOOK (LoadedBankAll); @@ -734,5 +767,6 @@ Init () { // Redirect garmc requests auto garmcHandle = reinterpret_cast (GetModuleHandle ("garmc.dll")); INSTALL_HOOK_DYNAMIC (curl_easy_setopt, reinterpret_cast (garmcHandle + 0x1FBBB0)); + INSTALL_HOOK_DYNAMIC (garmc_logger_log, reinterpret_cast (garmcHandle + 0x13AB70)); } } // namespace patches::JPN39 diff --git a/src/pollasync.cpp b/src/pollasync.cpp index 51608b8..a4b3992 100644 --- a/src/pollasync.cpp +++ b/src/pollasync.cpp @@ -5,6 +5,10 @@ extern bool jpLayout; extern int exited; +#ifndef MIN +#define MIN(a,b) ((a)<(b)?(a):(b)) +#endif + bool wndForeground = false; bool currentKeyboardState[0xFF] = { false }; @@ -13,6 +17,12 @@ int keyboardDiff[0xFF] = { 0 }; bool currentControllerButtonsState[SDL_CONTROLLER_BUTTON_MAX] = { false }; int controllerCount[SDL_CONTROLLER_BUTTON_MAX] = { 0 }; int controllerDiff[SDL_CONTROLLER_BUTTON_MAX] = { 0 }; +char currentMouseWheelDirection = 0; +int mouseWheelCount[2] = { 0 }; +int mouseWheelDiff[2] = { 0 }; + +int maxCount = 1; + SDLAxisState currentControllerAxisState; SDL_Window *window; @@ -96,7 +106,7 @@ LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) { DWORD keyCode = pKeyboard->vkCode; switch (wParam) { case WM_KEYDOWN: if (wndForeground) { - if (!currentKeyboardState[keyCode]) keyboardCount[keyCode] ++; + if (!currentKeyboardState[keyCode]) keyboardCount[keyCode] = MIN (keyboardCount[keyCode] + 1, maxCount); currentKeyboardState[keyCode] = true; } break; // keyup will accepted even if you're not focus in this window @@ -118,63 +128,14 @@ DisposeKeyboard () { if (keyboardHook) UnhookWindowsHookEx(keyboardHook); } -void -UpdateLoop () { - LogMessage (LogLevel::DEBUG, "Enter Controller UpdateLoop"); - SDL_Event event; - SDL_GameController *controller; - while (!exited) { - while (SDL_WaitEvent (&event) != 0) { - switch (event.type) { - case SDL_CONTROLLERDEVICEADDED: - if (!SDL_IsGameController (event.cdevice.which)) break; - - controller = SDL_GameControllerOpen (event.cdevice.which); - if (!controller) { - LogMessage (LogLevel::ERROR, std::string ("Could not open gamecontroller ") + SDL_GameControllerNameForIndex (event.cdevice.which) - + ": " + SDL_GetError ()); - continue; - } - LogMessage (LogLevel::DEBUG, "Controller connected!"); - controllers[event.cdevice.which] = controller; - break; - case SDL_CONTROLLERDEVICEREMOVED: - LogMessage (LogLevel::DEBUG, "Controller removed!"); - if (!SDL_IsGameController (event.cdevice.which)) break; - SDL_GameControllerClose (controllers[event.cdevice.which]); - break; - case SDL_MOUSEWHEEL: - if (wndForeground) { - if (event.wheel.y > 0) currentMouseState.ScrolledUp = true; - else if (event.wheel.y < 0) currentMouseState.ScrolledDown = true; - } - break; - case SDL_CONTROLLERBUTTONUP: - // keyup will accepted even if you're not focus in this window - currentControllerButtonsState[event.cbutton.button] = false; break; - case SDL_CONTROLLERBUTTONDOWN: - if (wndForeground) { - if (!currentControllerButtonsState[event.cbutton.button]) controllerCount[event.cbutton.button]++; - currentControllerButtonsState[event.cbutton.button] = true; - } else LogMessage (LogLevel::WARN, "Controller button pressed but window not focused!"); - break; - case SDL_CONTROLLERAXISMOTION: - float sensorValue = event.caxis.value == 0 ? 0 : event.caxis.value / (event.caxis.value > 0 ? 32767.0f : -32768.0f); - if (wndForeground || sensorValue == 0) { - switch (event.caxis.axis) { - case SDL_CONTROLLER_AXIS_LEFTX: currentControllerAxisState.LeftRight = sensorValue; break; - case SDL_CONTROLLER_AXIS_LEFTY: currentControllerAxisState.LeftDown = sensorValue; break; - case SDL_CONTROLLER_AXIS_RIGHTX: currentControllerAxisState.RightRight = sensorValue; break; - case SDL_CONTROLLER_AXIS_RIGHTY: currentControllerAxisState.RightDown = sensorValue; break; - case SDL_CONTROLLER_AXIS_TRIGGERLEFT: currentControllerAxisState.LTriggerDown = sensorValue; break; - case SDL_CONTROLLER_AXIS_TRIGGERRIGHT: currentControllerAxisState.RTriggerDown = sensorValue; break; - } - } - break; - } - } - } -} +// void +// UpdateLoop () { +// LogMessage (LogLevel::DEBUG, "Enter Controller UpdateLoop"); + +// while (!exited) { + +// } +// } bool InitializePoll (HWND windowHandle) { @@ -223,8 +184,8 @@ InitializePoll (HWND windowHandle) { atexit (DisposePoll); - updatePollThread = std::thread (UpdateLoop); - updatePollThread.detach (); + // updatePollThread = std::thread (UpdateLoop); + // updatePollThread.detach (); return hasRumble; } @@ -243,15 +204,78 @@ void UpdatePoll (HWND windowHandle) { if (!CheckForegroundWindow (windowHandle)) return; - // currentMouseState.ScrolledUp = false; - // currentMouseState.ScrolledDown = false; + currentMouseState.ScrolledUp = false; + currentMouseState.ScrolledDown = false; for (int i=0; i<255; i++) keyboardCount[i] -= (bool)keyboardDiff[i]; for (int i=0; i 0) mouseWheelCount[i] -= (bool)mouseWheelDiff[i]; std::fill_n (keyboardDiff, 0xFF, 0); std::fill_n (controllerDiff, SDL_CONTROLLER_BUTTON_MAX, 0); + std::fill_n (mouseWheelDiff, 2, 0); // GetCursorPos (¤tMouseState.Position); // ScreenToClient (windowHandle, ¤tMouseState.Position); + SDL_Event event; + SDL_GameController *controller; + while (SDL_PollEvent (&event) != 0) { + // LogMessage (LogLevel::DEBUG, "Receive SDL Event! type={}", (u64)event.type); + switch (event.type) { + case SDL_CONTROLLERDEVICEADDED: + if (!SDL_IsGameController (event.cdevice.which)) break; + controller = SDL_GameControllerOpen (event.cdevice.which); + if (!controller) { + LogMessage (LogLevel::ERROR, std::string ("Could not open gamecontroller ") + SDL_GameControllerNameForIndex (event.cdevice.which) + + ": " + SDL_GetError ()); + continue; + } + LogMessage (LogLevel::DEBUG, "Controller connected!"); + controllers[event.cdevice.which] = controller; + break; + case SDL_CONTROLLERDEVICEREMOVED: + LogMessage (LogLevel::DEBUG, "Controller removed!"); + if (!SDL_IsGameController (event.cdevice.which)) break; + SDL_GameControllerClose (controllers[event.cdevice.which]); + break; + case SDL_MOUSEWHEEL: + if (wndForeground) { + // LogMessage (LogLevel::DEBUG, "Mouse Wheel moves {}", event.wheel.y); + if (event.wheel.y > 0) { + mouseWheelCount[0] = MIN (mouseWheelCount[0] + event.wheel.y, maxCount); + mouseWheelCount[1] = 0; + currentMouseState.ScrolledUp = true; + } else if (event.wheel.y < 0) { + mouseWheelCount[1] = MIN (mouseWheelCount[1] - event.wheel.y, maxCount); + mouseWheelCount[0] = 0; + currentMouseState.ScrolledDown = true; + } + } + break; + case SDL_CONTROLLERBUTTONUP: + // keyup will accepted even if you're not focus in this window + currentControllerButtonsState[event.cbutton.button] = false; break; + case SDL_CONTROLLERBUTTONDOWN: + if (wndForeground) { + if (!currentControllerButtonsState[event.cbutton.button]) { + controllerCount[event.cbutton.button] = MIN (controllerCount[event.cbutton.button] + 1, maxCount); + } + currentControllerButtonsState[event.cbutton.button] = true; + } else LogMessage (LogLevel::WARN, "Controller button pressed but window not focused!"); + break; + case SDL_CONTROLLERAXISMOTION: + float sensorValue = event.caxis.value == 0 ? 0 : event.caxis.value / (event.caxis.value > 0 ? 32767.0f : -32768.0f); + if (wndForeground || sensorValue == 0) { + switch (event.caxis.axis) { + case SDL_CONTROLLER_AXIS_LEFTX: currentControllerAxisState.LeftRight = sensorValue; break; + case SDL_CONTROLLER_AXIS_LEFTY: currentControllerAxisState.LeftDown = sensorValue; break; + case SDL_CONTROLLER_AXIS_RIGHTX: currentControllerAxisState.RightRight = sensorValue; break; + case SDL_CONTROLLER_AXIS_RIGHTY: currentControllerAxisState.RightDown = sensorValue; break; + case SDL_CONTROLLER_AXIS_TRIGGERLEFT: currentControllerAxisState.LTriggerDown = sensorValue; break; + case SDL_CONTROLLER_AXIS_TRIGGERRIGHT: currentControllerAxisState.RTriggerDown = sensorValue; break; + } + } + break; + } + } } void @@ -330,16 +354,22 @@ GetMouseScrollDown () { bool GetMouseScrollIsDown (const Scroll scroll) { - return false; - // if (scroll == MOUSE_SCROLL_UP) return GetMouseScrollUp (); - // else return GetMouseScrollDown (); + if (scroll == MOUSE_SCROLL_UP) return GetMouseScrollUp (); + else return GetMouseScrollDown (); } +int maxWheelCount = 1; bool GetMouseScrollIsTapped (const Scroll scroll) { - return false; - // if (scroll == MOUSE_SCROLL_UP) return GetMouseScrollUp () && !GetWasMouseScrollUp (); - // else return GetMouseScrollDown () && !GetWasMouseScrollDown (); + 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; } bool