diff --git a/CMakeLists.txt b/CMakeLists.txt index 8a6e9db..97b7a64 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,6 +2,11 @@ cmake_minimum_required(VERSION 3.25) project(TaikoArcadeLoader VERSION 1.0.0 LANGUAGES C CXX) +# Set runtime library to static +if(MSVC) + set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>" CACHE INTERNAL "") +endif() + # Set C and C++ standards set(CMAKE_C_STANDARD 11) set(CMAKE_CXX_STANDARD 23) @@ -134,8 +139,8 @@ set(SOURCES src/pollasync.cpp src/bnusio.cpp src/patches/amauth.cpp - src/patches/dxgi.cpp - src/patches/fpslimiter.cpp + # src/patches/dxgi.cpp + # src/patches/fpslimiter.cpp src/patches/audio.cpp src/patches/plugins.cpp src/patches/scanner.cpp @@ -143,6 +148,7 @@ set(SOURCES src/patches/testmode.cpp src/patches/timer.cpp src/patches/language.cpp + # src/patches/unlimitsong.cpp src/patches/versions/JPN00.cpp src/patches/versions/JPN08.cpp src/patches/versions/JPN39.cpp diff --git a/README.md b/README.md index 323faf8..eecc985 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,7 @@ version = "auto" # Patch version # | - JPN39: For use with Taiko JPN 39.06 # | - CHN00: For use with Taiko CHN 00.32 unlock_songs = true # not active for JPN39 (see TestMode) + # More options are available in the ModManager, in the TestMode menu (Default key is F1) [patches.chn00] # These patches are only available for version CHN00 fix_language = false # Sync test mode language to attract etc @@ -41,25 +42,26 @@ demo_movie = true # Show demo movie 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 # If usio emulation is disabled, you need to place bnusio_original.dll (unmodified bnusio.dll) in the executable folder. card_reader = true # Disable this if you have an original namco card reader -accept_invalid = false # Enable this if you want to accept cards incompatible with the original readers +accept_invalid = false # Enable this if you want to accept cards incompatible with the original readers qr = true # Disable this if you have an original namco qr code scanner + [graphics] res = { x = 1920, y = 1080 } -windowed = false -cursor = true -vsync = false -fpslimit = 120 +windowed = false # not windowed will automatically fullscreen +cursor = true # fullscreen will automatically hide cursor +vsync = false # enable this if you are using a 120fps screen (and use "Let Application Decide" in Nvidia panel) +# fpslimit = 0 # temporoly remove it, limit it to 120 in Nvidia panel instead!!! +model_res_rate = 1.0 # Don-Model resolution rate (currently JPN39 only) + # | rate <= 0: default 1280x720 + # | rate > 0: current resolution * rate [audio] -wasapi_shared = true # Wasapi shared mode, allows you to have multiple audio sources at once at a cost of having higher latency. +wasapi_shared = false # Wasapi shared mode, allows you to have multiple audio sources at once at a cost of having higher latency. asio = false # Use asio audio mode asio_driver = "ASIO4ALL v2" # Asio driver name # | If you're not using asio4all, open up regedit then navigate to HKEY_LOCAL_MACHINE\SOFTWARE\ASIO for your driver's name. @@ -76,7 +78,7 @@ type = 0 # qr type song_no = [] # Song noes used for custom folder [controller] -wait_period = 4 # Input interval (if using taiko drum controller, should be set to 0) +wait_period = 0 # Input interval (if using taiko drum controller, should be set to 0) analog_input = false # Use analog input (you need a compatible controller, this allows playing small and big notes like on arcade cabinets) [keyboard] @@ -86,8 +88,8 @@ jp_layout = false # Use jp layout scan code (if using jp layout keyboa [layeredfs] enabled = false # Replace assets from the game using a layered file system. # | For example if you want to edit the wordlist, add your edited version like so: - # | .\Data_mods\x64\datatable\wordlist.json - # | You can provide both unencrypted and encrypted files. + # | .\Data_mods\x64\datatable\wordlist.json + # | You can provide both unencrypted and encrypted files. [logging] log_level = "INFO" # Log level, Can be either "NONE", "ERROR", "WARN", "INFO", "DEBUG" and "HOOKS" @@ -105,17 +107,22 @@ The follow options are available in "MOD MANAGER" menu: * FIX LANGUAGE (sync test mode language to attract etc) * UNLOCK SONGS (show all of the songs) * FREEZE TIMER (stop timer count down) -* KIMETSU MODE (enable collabo024, will show a blank title) +* KIMETSU MODE (enable collabo024, will show a blank title and crash when enter) * ONE PIECE MODE (enable collabo025) * AI SOSHINA MODE (enable collabo026) * AOHARU MODE (enable aprilfool001) -* INSTANT RESULT (send result per song) +* INSTANT RESULT (send result per song, experimental not stable) Enhanced original option: * Louder volume (Speaker Volume is now up to 300%, **WARNING: May damage your speakers**) * Attract demo (Only available if FIX LANGUAGE is ON) +With chs-patch (Only unlock while resource correctly settled): + +* Add Language: zh-cn +* Add Voice Language (Could switch between JPN and CHN) + ## Building Manually To compile TaikoArcadeLoader, you'll need to install [MSVC](https://aka.ms/vs/17/release/vs_BuildTools.exe). diff --git a/dist/config.toml b/dist/config.toml index f647985..86b90bb 100644 --- a/dist/config.toml +++ b/dist/config.toml @@ -15,7 +15,6 @@ version = "auto" # Patch version # | - JPN39: For use with Taiko JPN 39.06 # | - CHN00: For use with Taiko CHN 00.32 unlock_songs = true -high_res_timer = true # (experimental) Enable High Resolution Timer, which might improve judgement timing [patches.chn00] # These patches are only available for version CHN00 fix_language = false # Sync test mode language to attract etc @@ -27,20 +26,23 @@ mode_collabo026 = false # Enable ai soshina mode [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 -accept_invalid = false # Enable this if you want to accept cards incompatible with the original readers +accept_invalid = false # Enable this if you want to accept cards incompatible with the original readers qr = true # Disable this if you want to use an original Namco QR code scanner [graphics] res = { x = 1920, y = 1080 } -windowed = false -cursor = true -vsync = false -fpslimit = 120 +windowed = false # not windowed will automatically fullscreen +cursor = true # fullscreen will automatically hide cursor +vsync = false # enable this if you are using a 120fps screen (and use "Let Application Decide" in Nvidia panel) +# fpslimit = 0 # temporoly remove it, limit it to 120 in Nvidia panel instead!!! +model_res_rate = 1.0 # Don-Model resolution rate (currently JPN39 only) + # | rate <= 0: default 1280x720 + # | rate > 0: current resolution * rate [audio] -wasapi_shared = true # Wasapi shared mode, allows you to have multiple audio sources at once at a cost of having higher latency. +wasapi_shared = false # Wasapi shared mode, allows you to have multiple audio sources at once at a cost of having higher latency. asio = false # Use asio audio mode asio_driver = "ASIO4ALL v2" # Asio driver name # | If you're not using asio4all, open up regedit then navigate to HKEY_LOCAL_MACHINE\SOFTWARE\ASIO for your driver's name. @@ -60,20 +62,20 @@ song_no = [] # Song noes used for custom folder [controller] -wait_period = 4 # Input interval (if using taiko drum controller, should be set to 0) +wait_period = 0 # Input interval (if using taiko drum controller, should be set to 0) analog_input = false # Use analog input (you need a compatible controller, this allows playing small and big notes like on arcade cabinets) [keyboard] -auto_ime = false # Automatically change to english ime mode upon game startup +auto_ime = true # Automatically change to english ime mode upon game startup jp_layout = false # Use jp layout scan code (if using jp layout keyboard, must be set to true) [layeredfs] enabled = false # Replace assets from the game using a layered file system. # | For example if you want to edit the wordlist, add your edited version like so: - # | .\Data_mods\x64\datatable\wordlist.json - # | You can provide both unencrypted and encrypted files. + # | .\Data_mods\x64\datatable\wordlist.json + # | You can provide both unencrypted and encrypted files. [logging] diff --git a/dist/keyconfig.toml b/dist/keyconfig.toml index ad076e4..405217d 100644 --- a/dist/keyconfig.toml +++ b/dist/keyconfig.toml @@ -21,7 +21,7 @@ P2_LEFT_RED = ["X"] P2_RIGHT_RED = ["C"] P2_RIGHT_BLUE = ["V"] -# ESCAPE F1 through F12 +# ESCAPE F1 through F12 # ` 1 through 0 -= BACKSPACE ^ YEN # TAB QWERTYUIOP [ ] BACKSLASH @ # CAPS_LOCK ASDFGHJKL ;' ENTER : diff --git a/src/bnusio.cpp b/src/bnusio.cpp index 624ae70..b7ce835 100644 --- a/src/bnusio.cpp +++ b/src/bnusio.cpp @@ -13,22 +13,11 @@ extern char accessCode1[21]; extern char accessCode2[21]; extern char chipId1[33]; extern char chipId2[33]; -extern bool autoIme; + extern bool emulateUsio; -extern bool emulateCardReader; extern bool acceptInvalidCards; extern HWND hGameWnd; -typedef i32 (*callbackAttach) (i32, i32, i32 *); -typedef void (*callbackTouch) (i32, i32, u8[168], u64); -typedef void event (); -typedef void waitTouchEvent (callbackTouch, u64); -bool waitingForTouch = false; -callbackTouch touchCallback; -u64 touchData; -callbackAttach attachCallback; -i32 *attachData; - Keybindings EXIT = {.keycodes = {VK_ESCAPE}}; Keybindings TEST = {.keycodes = {VK_F1}}; Keybindings SERVICE = {.keycodes = {VK_F2}}; @@ -48,9 +37,6 @@ Keybindings P2_LEFT_BLUE = {.keycodes = {'Z'}}; Keybindings P2_LEFT_RED = {.keycodes = {'X'}}; Keybindings P2_RIGHT_RED = {.keycodes = {'C'}}; Keybindings P2_RIGHT_BLUE = {.keycodes = {'V'}}; -// Keybindings ALL[] = { EXIT, TEST, SERVICE, DEBUG_UP, DEBUG_DOWN, DEBUG_ENTER, COIN_ADD, -// CARD_INSERT_1, CARD_INSERT_2, QR_DATA_READ, QR_IMAGE_READ, P1_LEFT_BLUE, P1_LEFT_RED, -// P1_RIGHT_RED, P1_RIGHT_BLUE, P2_LEFT_BLUE, P2_LEFT_RED, P2_RIGHT_RED, P2_RIGHT_BLUE }; const int exitWait = 100; int exited = 0; @@ -64,64 +50,68 @@ bool updateByCoin = false; HWND windowHandle = nullptr; float axisThreshold = 0.6f; u8 inputState = 1 | (1 << 2); -bool globalKeyboard = false;; -HKL currentLayout; +bool globalKeyboard = false; namespace bnusio { -#define RETURN_FALSE(returnType, functionName, ...) \ - returnType functionName (__VA_ARGS__) { return 0; } +HMODULE bnusioOriginal = LoadLibrary ("bnusio_original.dll"); +#define BNUSIO_EXPORT(returnType, functionName, ...) \ + typedef returnType (*type_##functionName) (__VA_ARGS__); \ + type_##functionName ori_##functionName = bnusioOriginal == nullptr ? nullptr : (type_##functionName)GetProcAddress (bnusioOriginal, #functionName); \ + returnType functionName (__VA_ARGS__) + +#define CALL_BNUSIO_FALSE(functionName, ...) \ + { if (!emulateUsio && ori_##functionName) return ori_##functionName (__VA_ARGS__); else return 0; } typedef u16 (__fastcall *AnalogMethod) (const u8); AnalogMethod analogMethod = nullptr; extern "C" { -RETURN_FALSE (i64, bnusio_Open); -RETURN_FALSE (i64, bnusio_Close); -RETURN_FALSE (i64, bnusio_Communication, i32 a1); -RETURN_FALSE (u8, bnusio_IsConnected); -RETURN_FALSE (i32, bnusio_ResetIoBoard); -RETURN_FALSE (u16, bnusio_GetStatusU16, u16 a1); -RETURN_FALSE (u8, bnusio_GetStatusU8, u16 a1); -RETURN_FALSE (u16, bnusio_GetRegisterU16, i16 a1); -RETURN_FALSE (u8, bnusio_GetRegisterU8, u16 a1); -RETURN_FALSE (void *, bnusio_GetBuffer, u16 a1, i64 a2, i16 a3); -RETURN_FALSE (i64, bnusio_SetRegisterU16, u16 a1, u16 a2); -RETURN_FALSE (i64, bnusio_SetRegisterU8, u16 a1, u8 a2); -RETURN_FALSE (i64, bnusio_SetBuffer, u16 a1, i32 a2, i16 a3); -RETURN_FALSE (void *, bnusio_GetSystemError); -RETURN_FALSE (i64, bnusio_SetSystemError, i16 a1); -RETURN_FALSE (i64, bnusio_ClearSram); -RETURN_FALSE (void *, bnusio_GetExpansionMode); -RETURN_FALSE (i64, bnusio_SetExpansionMode, i16 a1); -RETURN_FALSE (u8, bnusio_IsWideUsio); -RETURN_FALSE (u64, bnusio_GetSwIn64); -RETURN_FALSE (u8, bnusio_GetGout, u8 a1); -RETURN_FALSE (i64, bnusio_SetGout, u8 a1, u8 a2); -RETURN_FALSE (u64, bnusio_GetEncoder); -RETURN_FALSE (i64, bnusio_GetCoinLock, u8 a1); -RETURN_FALSE (i64, bnusio_SetCoinLock, u8 a1, u8 a2); -RETURN_FALSE (i64, bnusio_GetCDOut, u8 a1); -RETURN_FALSE (i64, bnusio_SetCDOut, u8 a1, u8 a2); -RETURN_FALSE (i64, bnusio_GetHopOut, u8 a1); -RETURN_FALSE (i64, bnusio_SetHopOut, u8 a1, u8 a2); -RETURN_FALSE (void *, bnusio_SetPLCounter, i16 a1); -RETURN_FALSE (char *, bnusio_GetIoBoardName); -RETURN_FALSE (i64, bnusio_SetHopperRequest, u16 a1, i16 a2); -RETURN_FALSE (i64, bnusio_SetHopperLimit, u16 a1, i16 a2); -RETURN_FALSE (i64, bnusio_SramRead, i32 a1, u8 a2, i32 a3, u16 a4); -RETURN_FALSE (i64, bnusio_SramWrite, i32 a1, u8 a2, i32 a3, u16 a4); -RETURN_FALSE (void *, bnusio_GetCoinError, i32 a1); -RETURN_FALSE (void *, bnusio_GetServiceError, i32 a1); -RETURN_FALSE (i64, bnusio_DecCoin, i32 a1, u16 a2); -RETURN_FALSE (i64, bnusio_DecService, i32 a1, u16 a2); -RETURN_FALSE (i64, bnusio_ResetCoin); -size_t -bnusio_GetFirmwareVersion () { - return 126; +BNUSIO_EXPORT (i64, bnusio_Open) CALL_BNUSIO_FALSE (bnusio_Open) +BNUSIO_EXPORT (i64, bnusio_Close) CALL_BNUSIO_FALSE (bnusio_Close) +BNUSIO_EXPORT (i64, bnusio_Communication, i32 a1) CALL_BNUSIO_FALSE (bnusio_Communication, a1) +BNUSIO_EXPORT (u8, bnusio_IsConnected) CALL_BNUSIO_FALSE (bnusio_IsConnected) +BNUSIO_EXPORT (i32, bnusio_ResetIoBoard) CALL_BNUSIO_FALSE (bnusio_ResetIoBoard) +BNUSIO_EXPORT (u16, bnusio_GetStatusU16, u16 a1) CALL_BNUSIO_FALSE (bnusio_GetStatusU16, a1) +BNUSIO_EXPORT (u8, bnusio_GetStatusU8, u16 a1) CALL_BNUSIO_FALSE (bnusio_GetStatusU8, a1) +BNUSIO_EXPORT (u16, bnusio_GetRegisterU16, i16 a1) CALL_BNUSIO_FALSE (bnusio_GetRegisterU16, a1) +BNUSIO_EXPORT (u8, bnusio_GetRegisterU8, u16 a1) CALL_BNUSIO_FALSE (bnusio_GetRegisterU8, a1) +BNUSIO_EXPORT (void *, bnusio_GetBuffer, u16 a1, i64 a2, i16 a3) CALL_BNUSIO_FALSE (bnusio_GetBuffer, a1, a2, a3) +BNUSIO_EXPORT (i64, bnusio_SetRegisterU16, u16 a1, u16 a2) CALL_BNUSIO_FALSE (bnusio_SetRegisterU16, a1, a2) +BNUSIO_EXPORT (i64, bnusio_SetRegisterU8, u16 a1, u8 a2) CALL_BNUSIO_FALSE (bnusio_SetRegisterU8, a1, a2) +BNUSIO_EXPORT (i64, bnusio_SetBuffer, u16 a1, i32 a2, i16 a3) CALL_BNUSIO_FALSE (bnusio_SetBuffer, a1, a2, a3) +BNUSIO_EXPORT (void *, bnusio_GetSystemError) CALL_BNUSIO_FALSE (bnusio_GetSystemError) +BNUSIO_EXPORT (i64, bnusio_SetSystemError, i16 a1) CALL_BNUSIO_FALSE (bnusio_SetSystemError, a1) +BNUSIO_EXPORT (i64, bnusio_ClearSram) CALL_BNUSIO_FALSE (bnusio_ClearSram) +BNUSIO_EXPORT (void *, bnusio_GetExpansionMode) CALL_BNUSIO_FALSE (bnusio_GetExpansionMode) +BNUSIO_EXPORT (i64, bnusio_SetExpansionMode, i16 a1) CALL_BNUSIO_FALSE (bnusio_SetExpansionMode, a1) +BNUSIO_EXPORT (u8, bnusio_IsWideUsio) CALL_BNUSIO_FALSE (bnusio_IsWideUsio) +BNUSIO_EXPORT (u64, bnusio_GetSwIn64) CALL_BNUSIO_FALSE (bnusio_GetSwIn64) +BNUSIO_EXPORT (u8, bnusio_GetGout, u8 a1) CALL_BNUSIO_FALSE (bnusio_GetGout, a1) +BNUSIO_EXPORT (i64, bnusio_SetGout, u8 a1, u8 a2) CALL_BNUSIO_FALSE (bnusio_SetGout, a1, a2) +BNUSIO_EXPORT (u64, bnusio_GetEncoder) CALL_BNUSIO_FALSE (bnusio_GetEncoder) +BNUSIO_EXPORT (i64, bnusio_GetCoinLock, u8 a1) CALL_BNUSIO_FALSE (bnusio_GetCoinLock, a1) +BNUSIO_EXPORT (i64, bnusio_SetCoinLock, u8 a1, u8 a2) CALL_BNUSIO_FALSE (bnusio_SetCoinLock, a1, a2) +BNUSIO_EXPORT (i64, bnusio_GetCDOut, u8 a1) CALL_BNUSIO_FALSE (bnusio_GetCDOut, a1) +BNUSIO_EXPORT (i64, bnusio_SetCDOut, u8 a1, u8 a2) CALL_BNUSIO_FALSE (bnusio_SetCDOut, a1, a2) +BNUSIO_EXPORT (i64, bnusio_GetHopOut, u8 a1) CALL_BNUSIO_FALSE (bnusio_GetHopOut, a1) +BNUSIO_EXPORT (i64, bnusio_SetHopOut, u8 a1, u8 a2) CALL_BNUSIO_FALSE (bnusio_SetHopOut, a1, a2) +BNUSIO_EXPORT (void *, bnusio_SetPLCounter, i16 a1) CALL_BNUSIO_FALSE (bnusio_SetPLCounter, a1) +BNUSIO_EXPORT (char *, bnusio_GetIoBoardName) CALL_BNUSIO_FALSE (bnusio_GetIoBoardName) +BNUSIO_EXPORT (i64, bnusio_SetHopperRequest, u16 a1, i16 a2) CALL_BNUSIO_FALSE (bnusio_SetHopperRequest, a1, a2) +BNUSIO_EXPORT (i64, bnusio_SetHopperLimit, u16 a1, i16 a2) CALL_BNUSIO_FALSE (bnusio_SetHopperLimit, a1, a2) +BNUSIO_EXPORT (i64, bnusio_SramRead, i32 a1, u8 a2, i32 a3, u16 a4) CALL_BNUSIO_FALSE (bnusio_SramRead, a1, a2, a3, a4) +BNUSIO_EXPORT (i64, bnusio_SramWrite, i32 a1, u8 a2, i32 a3, u16 a4) CALL_BNUSIO_FALSE (bnusio_SramWrite, a1, a2, a3, a4) +BNUSIO_EXPORT (void *, bnusio_GetCoinError, i32 a1) CALL_BNUSIO_FALSE (bnusio_GetCoinError, a1) +BNUSIO_EXPORT (void *, bnusio_GetServiceError, i32 a1) CALL_BNUSIO_FALSE (bnusio_GetServiceError, a1) +BNUSIO_EXPORT (i64, bnusio_DecCoin, i32 a1, u16 a2) CALL_BNUSIO_FALSE (bnusio_DecCoin, a1, a2) +BNUSIO_EXPORT (i64, bnusio_DecService, i32 a1, u16 a2) CALL_BNUSIO_FALSE (bnusio_DecService, a1, a2) +BNUSIO_EXPORT (i64, bnusio_ResetCoin) CALL_BNUSIO_FALSE (bnusio_ResetCoin) +BNUSIO_EXPORT (size_t, bnusio_GetFirmwareVersion) { + if (!emulateUsio && ori_bnusio_GetFirmwareVersion) return ori_bnusio_GetFirmwareVersion(); + else return 126; } - -u32 -bnusio_GetSwIn () { +BNUSIO_EXPORT (u32, bnusio_GetSwIn) { + if (!emulateUsio && ori_bnusio_GetSwIn) return ori_bnusio_GetSwIn (); u32 sw = 0; sw |= static_cast (testEnabled) << 7; sw |= static_cast (IsButtonDown (DEBUG_ENTER)) << 9; @@ -130,91 +120,41 @@ bnusio_GetSwIn () { sw |= static_cast (IsButtonDown (SERVICE)) << 14; return sw; } +BNUSIO_EXPORT (u16, bnusio_GetAnalogIn, const u8 which) { + if (!emulateUsio && ori_bnusio_GetAnalogIn) return ori_bnusio_GetAnalogIn (which); + if (analogMethod) return analogMethod (which); + else return 0; +} +BNUSIO_EXPORT (u16, bnusio_GetCoin, i32 a1) { + if (updateByCoin && a1 == 1) bnusio::Update (); + if (!emulateUsio && ori_bnusio_GetCoin) return ori_bnusio_GetCoin (a1); + return coin_count; +} +BNUSIO_EXPORT (u16, bnusio_GetService, i32 a1) { + if (!emulateUsio && ori_bnusio_GetService) return ori_bnusio_GetService (a1); + return service_count; +} +} -bool waitAll = false; -short drumWaitPeriod = 4; bool analogInput = false; -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}; - -u8 cooldown[8] = { 0 }; -u16 buttonWaitPeriod[] = { 0, 0 }; -std::queue buttonQueue[] = { {}, {} }; - 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 }; - -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) { - // LogMessage (LogLevel::DEBUG, "GetCoin p={}", a1); - if (updateByCoin && a1 == 1) bnusio::Update (); - return coin_count; -} -u16 __fastcall bnusio_GetService (i32 a1) { return service_count; } -} - -FUNCTION_PTR (i64, bnusio_Open_Original, PROC_ADDRESS ("bnusio_original.dll", "bnusio_Open")); -FUNCTION_PTR (i64, bnusio_Close_Original, PROC_ADDRESS ("bnusio_original.dll", "bnusio_Close")); -FUNCTION_PTR (u64, bnusio_Communication_Original, PROC_ADDRESS ("bnusio_original.dll", "bnusio_Communication"), i32); -FUNCTION_PTR (u8, bnusio_IsConnected_Original, PROC_ADDRESS ("bnusio_original.dll", "bnusio_IsConnected")); -FUNCTION_PTR (i32, bnusio_ResetIoBoard_Original, PROC_ADDRESS ("bnusio_original.dll", "bnusio_ResetIoBoard")); -FUNCTION_PTR (u16, bnusio_GetStatusU16_Original, PROC_ADDRESS ("bnusio_original.dll", "bnusio_GetStatusU16"), u16); -FUNCTION_PTR (u8, bnusio_GetStatusU8_Original, PROC_ADDRESS ("bnusio_original.dll", "bnusio_GetStatusU8"), u16); -FUNCTION_PTR (u16, bnusio_GetRegisterU16_Original, PROC_ADDRESS ("bnusio_original.dll", "bnusio_GetRegisterU16"), i16); -FUNCTION_PTR (u8, bnusio_GetRegisterU8_Original, PROC_ADDRESS ("bnusio_original.dll", "bnusio_GetRegisterU8"), i16); -FUNCTION_PTR (void *, bnusio_GetBuffer_Original, PROC_ADDRESS ("bnusio_original.dll", "bnusio_GetBuffer"), u16, i64, i16); -FUNCTION_PTR (i64, bnusio_SetRegisterU16_Original, PROC_ADDRESS ("bnusio_original.dll", "bnusio_SetRegisterU16"), u16, u16); -FUNCTION_PTR (i64, bnusio_SetRegisterU8_Original, PROC_ADDRESS ("bnusio_original.dll", "bnusio_SetRegisterU8"), u16, u8); -FUNCTION_PTR (i64, bnusio_SetBuffer_Original, PROC_ADDRESS ("bnusio_original.dll", "bnusio_SetBuffer"), u16, i32, i16); -FUNCTION_PTR (void *, bnusio_GetSystemError_Original, PROC_ADDRESS ("bnusio_original.dll", "bnusio_GetSystemError")); -FUNCTION_PTR (i64, bnusio_SetSystemError_Original, PROC_ADDRESS ("bnusio_original.dll", "bnusio_SetSystemError"), i16); -FUNCTION_PTR (size_t, bnusio_GetFirmwareVersion_Original, PROC_ADDRESS ("bnusio_original.dll", "bnusio_GetFirmwareVersion")); -FUNCTION_PTR (i64, bnusio_ClearSram_Original, PROC_ADDRESS ("bnusio_original.dll", "bnusio_ClearSram")); -FUNCTION_PTR (void *, bnusio_GetExpansionMode_Original, PROC_ADDRESS ("bnusio_original.dll", "bnusio_GetExpansionMode")); -FUNCTION_PTR (i64, bnusio_SetExpansionMode_Original, PROC_ADDRESS ("bnusio_original.dll", "bnusio_SetExpansionMode"), i16); -FUNCTION_PTR (u8, bnusio_IsWideUsio_Original, PROC_ADDRESS ("bnusio_original.dll", "bnusio_IsWideUsio")); -FUNCTION_PTR (u32, bnusio_GetSwIn_Original, PROC_ADDRESS ("bnusio_original.dll", "bnusio_GetSwIn")); -FUNCTION_PTR (u64, bnusio_GetSwIn64_Original, PROC_ADDRESS ("bnusio_original.dll", "bnusio_GetSwIn64")); -FUNCTION_PTR (u16, bnusio_GetAnalogIn_Original, PROC_ADDRESS ("bnusio_original.dll", "bnusio_GetAnalogIn"), u8); -FUNCTION_PTR (u8, bnusio_GetGout_Original, PROC_ADDRESS ("bnusio_original.dll", "bnusio_GetGout"), u8); -FUNCTION_PTR (i64, bnusio_SetGout_Original, PROC_ADDRESS ("bnusio_original.dll", "bnusio_SetGout"), u8, u8); -FUNCTION_PTR (u64, bnusio_GetEncoder_Original, PROC_ADDRESS ("bnusio_original.dll", "bnusio_GetEncoder")); -FUNCTION_PTR (i64, bnusio_GetCoinLock_Original, PROC_ADDRESS ("bnusio_original.dll", "bnusio_GetCoinLock"), u8); -FUNCTION_PTR (i64, bnusio_SetCoinLock_Original, PROC_ADDRESS ("bnusio_original.dll", "bnusio_SetCoinLock"), u8, u8); -FUNCTION_PTR (i64, bnusio_GetCDOut_Original, PROC_ADDRESS ("bnusio_original.dll", "bnusio_GetCDOut"), u8); -FUNCTION_PTR (i64, bnusio_SetCDOut_Original, PROC_ADDRESS ("bnusio_original.dll", "bnusio_SetCDOut"), u8, u8); -FUNCTION_PTR (i64, bnusio_GetHopOut_Original, PROC_ADDRESS ("bnusio_original.dll", "bnusio_GetHopOut"), u8); -FUNCTION_PTR (i64, bnusio_SetHopOut_Original, PROC_ADDRESS ("bnusio_original.dll", "bnusio_SetHopOut"), u8, u8); -FUNCTION_PTR (void *, bnusio_SetPLCounter_Original, PROC_ADDRESS ("bnusio_original.dll", "bnusio_SetPLCounter"), i16); -FUNCTION_PTR (char *, bnusio_GetIoBoardName_Original, PROC_ADDRESS ("bnusio_original.dll", "bnusio_GetIoBoardName")); -FUNCTION_PTR (i64, bnusio_SetHopperRequest_Original, PROC_ADDRESS ("bnusio_original.dll", "bnusio_SetHopperRequest"), u16, i16); -FUNCTION_PTR (i64, bnusio_SetHopperLimit_Original, PROC_ADDRESS ("bnusio_original.dll", "bnusio_SetHopperLimit"), u16, i16); -FUNCTION_PTR (i64, bnusio_SramRead_Original, PROC_ADDRESS ("bnusio_original.dll", "bnusio_SramRead"), i32, u8, i32, u16); -FUNCTION_PTR (i64, bnusio_SramWrite_Original, PROC_ADDRESS ("bnusio_original.dll", "bnusio_SramWrite"), i32, u8, i32, u16); -FUNCTION_PTR (u16, bnusio_GetCoin_Original, PROC_ADDRESS ("bnusio_original.dll", "bnusio_GetCoin"), i32); -FUNCTION_PTR (void *, bnusio_GetCoinError_Original, PROC_ADDRESS ("bnusio_original.dll", "bnusio_GetCoinError"), i32); -FUNCTION_PTR (void *, bnusio_GetService_Original, PROC_ADDRESS ("bnusio_original.dll", "bnusio_GetService"), i32); -FUNCTION_PTR (void *, bnusio_GetServiceError_Original, PROC_ADDRESS ("bnusio_original.dll", "bnusio_GetServiceError"), i32); -FUNCTION_PTR (i64, bnusio_DecCoin_Original, PROC_ADDRESS ("bnusio_original.dll", "bnusio_DecCoin"), i32, u16); -FUNCTION_PTR (u64, bnusio_DecService_Original, PROC_ADDRESS ("bnusio_original.dll", "bnusio_DecService"), i32, u16); -FUNCTION_PTR (i64, bnusio_ResetCoin_Original, PROC_ADDRESS ("bnusio_original.dll", "bnusio_ResetCoin")); - u16 __fastcall AnalogInputAxis (const u8 which) { u16 analogIn = (u16)(32768 * ControllerAxisIsDown (analogBindings[which])) + 1; return analogIn > 100 ? analogIn : 0; } +bool waitAll = false; +short drumWaitPeriod = 0; +u16 buttonWaitPeriod[] = { 0, 0 }; +std::queue buttonQueue[] = { {}, {} }; +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 __fastcall AnalogInputWaitPeriod (const u8 which) { const auto button = analogButtons[which]; @@ -245,6 +185,7 @@ AnalogInputWaitPeriod (const u8 which) { return analogValue; } +int cooldown[8] = { 0 }; u8 blueCooldown = 1, redCooldown = 1; u16 __fastcall AnalogInputCooldown (const u8 which) { @@ -276,7 +217,7 @@ void Init () { SetKeyboardButtons (); - int fpsLimit = 120; + int fpsLimit = 0; const auto configPath = std::filesystem::current_path () / "config.toml"; const std::unique_ptr config_ptr (openConfig (configPath), toml_free); @@ -287,11 +228,15 @@ Init () { analogInput = readConfigBool (controller, "analog_input", analogInput); globalKeyboard = readConfigBool (controller, "global_keyboard", globalKeyboard); } - auto graphics = openConfigSection (config, "graphics"); - if (graphics) { - fpsLimit = (int)readConfigInt (graphics, "fpslimit", fpsLimit); - } + // auto graphics = openConfigSection (config, "graphics"); + // if (graphics) { + // fpsLimit = (int)readConfigInt (graphics, "fpslimit", fpsLimit); + // } } + updateByCoin = fpsLimit == 0; + // if (updateByCoin) { + // LogMessage (LogLevel::INFO, "fpsLimit is set to 0, bnusio::Update() will invoke in getCoin callback"); + // } if (analogInput) { LogMessage (LogLevel::WARN, "[Analog Type] Axis: All the keyboard drum inputs have been disabled"); @@ -307,10 +252,6 @@ Init () { analogMethod = AnalogInputSimple; } - updateByCoin = fpsLimit == 0; - if (updateByCoin) { - LogMessage (LogLevel::INFO, "fpsLimit is set to 0, bnusio::Update() will invoke in getCoin callback"); - } const auto keyConfigPath = std::filesystem::current_path () / "keyconfig.toml"; const std::unique_ptr keyConfig_ptr (openConfig (keyConfigPath), toml_free); if (keyConfig_ptr) { @@ -341,7 +282,7 @@ Init () { SetConfigValue (keyConfig, "P2_RIGHT_BLUE", &P2_RIGHT_BLUE, &inputState); } - LogMessage (LogLevel::INFO, "Finish Loading keyconfig.toml useKeyboard={} useMouse={} useController={}", + 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")) { @@ -349,52 +290,7 @@ Init () { LogMessage (LogLevel::ERROR, "bnusio_original.dll not found! usio emulation enabled"); } - if (!emulateUsio) { - INSTALL_HOOK_DIRECT (bnusio_Open, bnusio_Open_Original); - INSTALL_HOOK_DIRECT (bnusio_Close, bnusio_Close_Original); - INSTALL_HOOK_DIRECT (bnusio_Communication, bnusio_Communication_Original); - INSTALL_HOOK_DIRECT (bnusio_IsConnected, bnusio_IsConnected_Original); - INSTALL_HOOK_DIRECT (bnusio_ResetIoBoard, bnusio_ResetIoBoard_Original); - INSTALL_HOOK_DIRECT (bnusio_GetStatusU16, bnusio_GetStatusU16_Original); - INSTALL_HOOK_DIRECT (bnusio_GetStatusU8, bnusio_GetStatusU8_Original); - INSTALL_HOOK_DIRECT (bnusio_GetRegisterU16, bnusio_GetRegisterU16_Original); - INSTALL_HOOK_DIRECT (bnusio_GetRegisterU8, bnusio_GetRegisterU8_Original); - INSTALL_HOOK_DIRECT (bnusio_GetBuffer, bnusio_GetBuffer_Original); - INSTALL_HOOK_DIRECT (bnusio_SetRegisterU16, bnusio_SetRegisterU16_Original); - INSTALL_HOOK_DIRECT (bnusio_SetRegisterU8, bnusio_SetRegisterU8_Original); - INSTALL_HOOK_DIRECT (bnusio_SetBuffer, bnusio_SetBuffer_Original); - INSTALL_HOOK_DIRECT (bnusio_GetSystemError, bnusio_GetSystemError_Original); - INSTALL_HOOK_DIRECT (bnusio_SetSystemError, bnusio_SetSystemError_Original); - INSTALL_HOOK_DIRECT (bnusio_GetFirmwareVersion, bnusio_GetFirmwareVersion_Original); - INSTALL_HOOK_DIRECT (bnusio_ClearSram, bnusio_ClearSram_Original); - INSTALL_HOOK_DIRECT (bnusio_GetExpansionMode, bnusio_GetExpansionMode_Original); - INSTALL_HOOK_DIRECT (bnusio_SetExpansionMode, bnusio_SetExpansionMode_Original); - INSTALL_HOOK_DIRECT (bnusio_IsWideUsio, bnusio_IsWideUsio_Original); - INSTALL_HOOK_DIRECT (bnusio_GetSwIn, bnusio_GetSwIn_Original); - INSTALL_HOOK_DIRECT (bnusio_GetSwIn64, bnusio_GetSwIn64_Original); - INSTALL_HOOK_DIRECT (bnusio_GetAnalogIn, bnusio_GetAnalogIn_Original); - INSTALL_HOOK_DIRECT (bnusio_GetGout, bnusio_GetGout_Original); - INSTALL_HOOK_DIRECT (bnusio_SetGout, bnusio_SetGout_Original); - INSTALL_HOOK_DIRECT (bnusio_GetEncoder, bnusio_GetEncoder_Original); - INSTALL_HOOK_DIRECT (bnusio_GetCoinLock, bnusio_GetCoinLock_Original); - INSTALL_HOOK_DIRECT (bnusio_SetCoinLock, bnusio_SetCoinLock_Original); - INSTALL_HOOK_DIRECT (bnusio_GetCDOut, bnusio_GetCDOut_Original); - INSTALL_HOOK_DIRECT (bnusio_SetCDOut, bnusio_SetCDOut_Original); - INSTALL_HOOK_DIRECT (bnusio_GetHopOut, bnusio_GetHopOut_Original); - INSTALL_HOOK_DIRECT (bnusio_SetHopOut, bnusio_SetHopOut_Original); - INSTALL_HOOK_DIRECT (bnusio_SetPLCounter, bnusio_SetPLCounter_Original); - INSTALL_HOOK_DIRECT (bnusio_GetIoBoardName, bnusio_GetIoBoardName_Original); - INSTALL_HOOK_DIRECT (bnusio_SetHopperRequest, bnusio_SetHopperRequest_Original); - INSTALL_HOOK_DIRECT (bnusio_SetHopperLimit, bnusio_SetHopperLimit_Original); - INSTALL_HOOK_DIRECT (bnusio_SramRead, bnusio_SramRead_Original); - INSTALL_HOOK_DIRECT (bnusio_SramWrite, bnusio_SramWrite_Original); - INSTALL_HOOK_DIRECT (bnusio_GetCoin, bnusio_GetCoin_Original); - INSTALL_HOOK_DIRECT (bnusio_GetCoinError, bnusio_GetCoinError_Original); - INSTALL_HOOK_DIRECT (bnusio_GetService, bnusio_GetService_Original); - INSTALL_HOOK_DIRECT (bnusio_GetServiceError, bnusio_GetServiceError_Original); - INSTALL_HOOK_DIRECT (bnusio_DecCoin, bnusio_DecCoin_Original); - INSTALL_HOOK_DIRECT (bnusio_DecService, bnusio_DecService_Original); - INSTALL_HOOK_DIRECT (bnusio_ResetCoin, bnusio_ResetCoin_Original); + if (!emulateUsio && bnusioOriginal) { LogMessage (LogLevel::WARN, "USIO emulation disabled"); } } @@ -405,11 +301,6 @@ Update () { 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; } @@ -439,7 +330,6 @@ Update () { void Close () { - if (autoIme) ActivateKeyboardLayout (currentLayout, KLF_SETFORPROCESS); // patches::Plugins::Exit (); CleanupLogger (); } diff --git a/src/dllmain.cpp b/src/dllmain.cpp index c3056bd..d8f6f78 100644 --- a/src/dllmain.cpp +++ b/src/dllmain.cpp @@ -24,13 +24,17 @@ char accessCode2[21] = "00000000000000000002"; char chipId1[33] = "00000000000000000000000000000001"; char chipId2[33] = "00000000000000000000000000000002"; bool windowed = false; -bool autoIme = false; +bool autoIme = true; bool jpLayout = false; bool cursor = true; bool emulateUsio = true; bool emulateCardReader = true; bool emulateQr = true; bool acceptInvalidCards = false; +HKL currentLayout = nullptr; +i32 xRes = 1920; +i32 yRes = 1080; +bool vsync = false; std::string logLevelStr = "INFO"; bool logToFile = true; @@ -39,6 +43,22 @@ std::string logPath = "TaikoArcadeLoader.log"; HWND hGameWnd; FAST_HOOK (i32, ShowMouse, PROC_ADDRESS ("user32.dll", "ShowCursor"), bool) { return originalShowMouse.stdcall (true); } FAST_HOOK (i32, ExitWindows, PROC_ADDRESS ("user32.dll", "ExitWindowsEx")) { ExitProcess (0); } +// FAST_HOOK (ATOM, HookRegisterClassA, PROC_ADDRESS ("winuser.h", "RegisterClassA"), WNDCLASSA *lpWndClass) { +// LogMessage (LogLevel::DEBUG, "RegisterClassA name={}", lpWndClass->lpszClassName); +// return originalHookRegisterClassA.call (lpWndClass); +// } +// FAST_HOOK (ATOM, HookRegisterClassW, PROC_ADDRESS ("winuser.h", "RegisterClassW"), WNDCLASSW *lpWndClass) { +// LogMessage (LogLevel::DEBUG, L"RegisterClassW name={}", lpWndClass->lpszClassName); +// return originalHookRegisterClassW.call (lpWndClass); +// } +// FAST_HOOK (ATOM, HookRegisterClassExA, PROC_ADDRESS ("winuser.h", "RegisterClassExA"), WNDCLASSEXA *lpWndClass) { +// LogMessage (LogLevel::DEBUG, "RegisterClassExA name={}", lpWndClass->lpszClassName); +// return originalHookRegisterClassExA.call (lpWndClass); +// } +// FAST_HOOK (ATOM, HookRegisterClassExW, PROC_ADDRESS ("winuser.h", "RegisterClassExW"), WNDCLASSEXW *lpWndClass) { +// LogMessage (LogLevel::DEBUG, L"RegisterClassExW name={}", lpWndClass->lpszClassName); +// return originalHookRegisterClassExW.call (lpWndClass); +// } FAST_HOOK (HWND, CreateWindow, PROC_ADDRESS ("user32.dll", "CreateWindowExW"), DWORD dwExStyle, LPCWSTR lpClassName, LPCWSTR lpWindowName, DWORD dwStyle, i32 X, i32 Y, i32 nWidth, i32 nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam) { if (lpWindowName != nullptr) { @@ -152,10 +172,6 @@ DllMain (HMODULE module, const DWORD reason, LPVOID reserved) { InitializeLogger (GetLogLevel (logLevelStr), logToFile, logPath); patches::Timer::Init (); - // #ifdef ASYNC_IO - // InitializeKeyboard (); - // #endif - LogMessage (LogLevel::INFO, "Loading config..."); std::string version = "auto"; @@ -190,6 +206,11 @@ DllMain (HMODULE module, const DWORD reason, LPVOID reserved) { if (const auto graphics = openConfigSection (config, "graphics")) { windowed = readConfigBool (graphics, "windowed", windowed); cursor = readConfigBool (graphics, "cursor", cursor); + if (auto res = openConfigSection (graphics, "res")) { + xRes = static_cast (readConfigInt (res, "x", xRes)); + yRes = static_cast (readConfigInt (res, "y", yRes)); + } + vsync = readConfigBool (graphics, "vsync", vsync); } if (const auto keyboard = openConfigSection (config, "keyboard")) { autoIme = readConfigBool (keyboard, "auto_ime", autoIme); @@ -203,6 +224,49 @@ DllMain (HMODULE module, const DWORD reason, LPVOID reserved) { } } + SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_UNAWARE); + auto activeWindow = GetActiveWindow(); + HMONITOR monitor = MonitorFromWindow(activeWindow, MONITOR_DEFAULTTONEAREST); + + // Get the logical width and height of the monitor + MONITORINFOEX monitorInfoEx; + monitorInfoEx.cbSize = sizeof(monitorInfoEx); + GetMonitorInfo(monitor, &monitorInfoEx); + auto cxLogical = monitorInfoEx.rcMonitor.right - monitorInfoEx.rcMonitor.left; + auto cyLogical = monitorInfoEx.rcMonitor.bottom - monitorInfoEx.rcMonitor.top; + + // Get the physical width and height of the monitor + DEVMODE devMode; + devMode.dmSize = sizeof(devMode); + devMode.dmDriverExtra = 0; + EnumDisplaySettings(monitorInfoEx.szDevice, ENUM_CURRENT_SETTINGS, &devMode); + auto cxPhysical = devMode.dmPelsWidth; + auto cyPhysical = devMode.dmPelsHeight; + + // Calculate the scaling factor + auto horizontalScale = (static_cast (cxPhysical) / static_cast (cxLogical)); + auto verticalScale = (static_cast (cyPhysical) / static_cast (cyLogical)); + if (windowed) { + // Game will automatically adjust scale + xRes = (int)(xRes / horizontalScale); + yRes = (int)(yRes / verticalScale); + } else { + xRes = cxLogical; + yRes = cyLogical; + if (yRes * 16 > xRes * 9) yRes = (int)(xRes * 9.0 / 16.0); + else if (yRes * 16 < xRes * 9) xRes = (int)(yRes * 16.0 / 9.0); + } + + LogMessage (LogLevel::INFO, "Scale Rate: x={} y={}", horizontalScale, verticalScale); + LogMessage (LogLevel::INFO, "Boot with {} mode ({}x{})", windowed ? "window" : "fullscreen", xRes, yRes); + + if (autoIme) { + currentLayout = GetKeyboardLayout (0); + auto engLayout = LoadKeyboardLayout (TEXT ("00000409"), KLF_ACTIVATE); + ActivateKeyboardLayout (engLayout, KLF_SETFORPROCESS); + LogMessage (LogLevel::DEBUG, "Initial change KeyboardLayout {}", LOWORD(engLayout)); + } + // Update the logger with the level read from config file. InitializeLogger (GetLogLevel (logLevelStr), logToFile, logPath); LogMessage (LogLevel::INFO, "Application started."); @@ -235,9 +299,13 @@ DllMain (HMODULE module, const DWORD reason, LPVOID reserved) { LogMessage (LogLevel::INFO, "==== Loading patches, please wait..."); - if (cursor) INSTALL_FAST_HOOK (ShowMouse); + if (windowed && cursor) INSTALL_FAST_HOOK (ShowMouse); INSTALL_FAST_HOOK (ExitWindows); INSTALL_FAST_HOOK (CreateWindow); + // INSTALL_FAST_HOOK (HookRegisterClassA); + // INSTALL_FAST_HOOK (HookRegisterClassW); + // INSTALL_FAST_HOOK (HookRegisterClassExA); + // INSTALL_FAST_HOOK (HookRegisterClassExW); INSTALL_FAST_HOOK (SetWindowPosition); INSTALL_FAST_HOOK (ExitProcessHook); @@ -266,11 +334,12 @@ DllMain (HMODULE module, const DWORD reason, LPVOID reserved) { patches::Scanner::Init (); patches::Audio::Init (); - patches::Dxgi::Init (); + // patches::Dxgi::Init (); patches::AmAuth::Init (); patches::Language::Init (); patches::TestMode::Init (); patches::LayeredFs::Init (); + // patches::UnlimitSong::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 a557ef4..e8deba5 100644 --- a/src/helpers.cpp +++ b/src/helpers.cpp @@ -73,6 +73,16 @@ readConfigInt (const toml_table_t *table, const std::string &key, const i64 notF return u.i; } +double +readConfigDouble (const toml_table_t *table, const std::string &key, const double notFoundValue) { + const auto [ok, u] = toml_double_in (table, key.c_str ()); + if (!ok) { + LogMessage (LogLevel::WARN, ("Could not find Int named " + key).c_str ()); + return notFoundValue; + } + return u.d; +} + std::string readConfigString (const toml_table_t *table, const std::string &key, const std::string ¬FoundValue) { const auto [ok, u] = toml_string_in (table, key.c_str ()); @@ -184,7 +194,7 @@ AreAllBytesZero (const u8 *array, const size_t offset, const size_t length) { return true; } -void +void withFile (const char *fileName, std::function callback) { FILE *file = fopen (fileName, "rb"); if (file == nullptr) return; diff --git a/src/helpers.h b/src/helpers.h index b2983d7..86a110c 100644 --- a/src/helpers.h +++ b/src/helpers.h @@ -128,50 +128,6 @@ const HMODULE MODULE_HANDLE = GetModuleHandle (nullptr); original##functionName = safetyhook::create_inline ((void *)location, (void*)implOf##functionName); \ } -inline bool sendFlag = false; -#define SCENE_RESULT_HOOK(functionName, location) \ - FAST_HOOK (void, functionName, location, i64 a1, i64 a2, i64 a3) { \ - if (TestMode::ReadTestModeValue (L"ModInstantResult") != 1 && TestMode::ReadTestModeValue (L"NumberOfStageItem") <= 4) { \ - original##functionName.fastcall (a1, a2, a3); \ - return; \ - } \ - sendFlag = true; \ - original##functionName.fastcall (a1, a2, a3); \ - ExecuteSendResultData (); \ - } - -#define SEND_RESULT_HOOK(functionName, location) \ - FAST_HOOK (void, functionName, location, i64 a1) { \ - if (TestMode::ReadTestModeValue (L"ModInstantResult") != 1 && TestMode::ReadTestModeValue (L"NumberOfStageItem") <= 4) { \ - original##functionName.fastcall (a1); \ - return; \ - } \ - if (sendFlag) { \ - sendFlag = false; \ - original##functionName.fastcall (a1); \ - } \ - } - -#define CHANGE_RESULT_SIZE_HOOK(functionName, location, target) \ - MID_HOOK (functionName, location, SafetyHookContext &ctx) { \ - if (TestMode::ReadTestModeValue (L"ModInstantResult") != 1 && TestMode::ReadTestModeValue (L"NumberOfStageItem") <= 4) { return; } \ - i64 instance = RefPlayDataManager (*(i64 *)ctx.r12); \ - u32 currentStageCount = *(u32 *)(instance + 8); \ - ctx.target &= 0xFFFFFFFF00000000; \ - ctx.target |= currentStageCount; \ - } - -#define CHANGE_RESULT_INDEX_HOOK(functionName, location, target, offset, skip) \ - MID_HOOK (functionName, location, SafetyHookContext &ctx) { \ - if (TestMode::ReadTestModeValue (L"ModInstantResult") != 1 && TestMode::ReadTestModeValue (L"NumberOfStageItem") <= 4) { return; } \ - i64 instance = RefPlayDataManager (*(i64 *)ctx.r12); \ - u32 currentStageCount = *(u32 *)(instance + 8); \ - ctx.target &= 0xFFFFFFFF00000000; \ - ctx.target |= currentStageCount - 1; \ - *(u32 *)(ctx.rsp + offset) = currentStageCount - 1; \ - ctx.rip += skip; \ - } - #define READ_MEMORY(location, type) *(type *)location #define WRITE_MEMORY(location, type, ...) \ @@ -216,6 +172,7 @@ toml_table_t *openConfig (const std::filesystem::path &path); toml_table_t *openConfigSection (const toml_table_t *config, const std::string §ionName); bool readConfigBool (const toml_table_t *table, const std::string &key, bool notFoundValue); i64 readConfigInt (const toml_table_t *table, const std::string &key, i64 notFoundValue); +double readConfigDouble (const toml_table_t *table, const std::string &key, const double 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); diff --git a/src/patches/amauth.cpp b/src/patches/amauth.cpp index e2b6511..6b23909 100644 --- a/src/patches/amauth.cpp +++ b/src/patches/amauth.cpp @@ -121,8 +121,7 @@ typedef struct amcus_state { /* Offset: 8 */ i32 allnet_auth_state; /* Offset: 12 */ i32 allnet_auth_count; /* Offset: 16 */ i32 allnet_last_error; - /* Offset: 24 */ - mucha_state mucha_state; + /* Offset: 24 */ mucha_state mucha_state; /* Offset: 176 */ i64 clock_status; /* Offset: 184 */ i64 name_resolution_timeout; /* Offset: 192 */ /* ENUM32 */ u32 auth_type; diff --git a/src/patches/language.cpp b/src/patches/language.cpp index c3a5121..649f2cc 100644 --- a/src/patches/language.cpp +++ b/src/patches/language.cpp @@ -9,6 +9,7 @@ namespace patches::Language { const std::vector languages = { "jpn", "en_us", "cn_tw", "kor", "cn_cn" }; std::vector language_patch = { }; boolean cnFontPatches = false; +// TestMode::Value *languageItem = TestMode::CreateValue (L"LanguageItem"); int language = 0; FUNCTION_PTR (void, lua_settop, PROC_ADDRESS ("lua51.dll", "lua_settop"), i64, i32); @@ -40,7 +41,7 @@ typedef struct { 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 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 }; @@ -77,7 +78,7 @@ FAST_HOOK_DYNAMIC (int, initial_load_setting) { *(u32 *)(basicOffset + 0x68) = lang == 0 ? 0 : (3 * lang + shapeIndex + 1); } } - } + } return 0; } @@ -101,7 +102,7 @@ void Init () { bool fontExistAll = true; const char *fontToCheck[]{ - "cn_30.nutexb", "cn_30.xml", "cn_32_EB.nutexb", "cn_32_EB.xml", "cn_32_B.nutexb", + "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++) { @@ -122,7 +123,7 @@ Init () { node.attribute (L"max").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 + // load_setting INSTALL_FAST_HOOK_DYNAMIC (initial_load_setting, ASLR (0x14001B010)); // SceneBoot::LoadFont language_patch.push_back (safetyhook::create_mid (ASLR (0x140464235), [](SafetyHookContext &ctx){ @@ -130,12 +131,12 @@ Init () { ctx.rax = (uintptr_t)languageData; ctx.rip = ASLR (0x140464243); })); - language_patch.push_back (safetyhook::create_mid (ASLR (0x14046426C), [](SafetyHookContext &ctx){ + 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){ + 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; @@ -202,7 +203,7 @@ MID_HOOK_DYNAMIC (WordlistLanguageType, SafetyHookContext &ctx) { 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); + } else taiko_assign ((void *)(ctx.rsp + 0x60), "", 0); if (fallback != -1) { if (jsonHasMember (json, languageFontTypes[fallback].c_str ())) { @@ -359,24 +360,17 @@ MID_HOOK_DYNAMIC (ChangeOnpFile, SafetyHookContext &ctx) { 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); -} - -std::string *season_nulm = nullptr; -std::string *season_nutexb = nullptr; +bool titleExistSeason = true, titleExistMaid = true, titleExistMaidCn = true; +std::string seasonNulm = "title_season.nulm", seasonNutexb = "title_" + season () + ".nutexb"; +std::string maidNulmCn = "title_maid.nulm", maidNutexbCn = "title_maid.nutexb"; +std::string maidNulm = "title_maid.nulm", maidNutexb = "title_maid.nutexb"; +TestMode::Value *titleScreen = TestMode::CreateValue (L"ModTitleScreen"); void Init () { switch (gameVersion) { @@ -399,55 +393,78 @@ Init () { 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){ + 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 + { InjectLanguageType (ctx.rax, 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 + { InjectLanguageType (ctx.rax, 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 + { InjectLanguageType (ctx.rax, 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 + { InjectLanguageType (ctx.rax, 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 + { InjectLanguageType (ctx.rax, 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 + { InjectLanguageType (ctx.rax, ctx.rdx); ctx.rip = ASLR (0x14012B8D0); })); // ScoreGetLanguageType LayeredFs::RegisterBefore ([&] (const std::string &originalFileName, const std::string ¤tFileName) -> std::string { - if (language != 4 || currentFileName.starts_with ("F:\\") || currentFileName.find ("\\lumen\\") == std::string::npos) return ""; + if (language != 4 || currentFileName.starts_with ("F:\\lumen\\") || 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 ""; - }); + std::string base[] = {"..\\..\\Data\\x64\\lumen\\000_default\\attract\\", "..\\..\\Data_mods\\x64\\lumen\\000_default\\attract\\"}; + std::string baseCn[] = {"..\\..\\Data\\x64\\lumen_cn\\000_default\\attract\\", "..\\..\\Data_mods\\x64\\lumen_cn\\000_default\\attract\\"}; + for (std::string prefix : baseCn) { + if (!seasonNulm.starts_with ("..\\") && std::filesystem::exists (prefix + seasonNulm)) seasonNulm = prefix + seasonNulm; + if (!seasonNutexb.starts_with ("..\\") && std::filesystem::exists (prefix + seasonNutexb)) seasonNutexb = prefix + seasonNutexb; + } + if (!seasonNulm.starts_with ("..\\") || !seasonNutexb.starts_with ("..\\")) titleExistSeason = false; + for (std::string prefix : baseCn) { + if (!maidNulmCn.starts_with ("..\\") && std::filesystem::exists (prefix + maidNulmCn)) maidNulmCn = prefix + maidNulmCn; + if (!maidNutexbCn.starts_with ("..\\") && std::filesystem::exists (prefix + maidNutexbCn)) maidNutexbCn = prefix + maidNutexbCn; + } + if (!maidNulmCn.starts_with ("..\\") || !maidNutexbCn.starts_with ("..\\")) titleExistMaidCn = false; + for (std::string prefix : base) { + if (!maidNulm.starts_with ("..\\") && std::filesystem::exists (prefix + maidNulm)) maidNulm = prefix + maidNulm; + if (!maidNutexb.starts_with ("..\\") && std::filesystem::exists (prefix + maidNutexb)) maidNutexb = prefix + maidNutexb; + } + if (!maidNulm.starts_with ("..\\") || !maidNutexb.starts_with ("..\\")) titleExistMaid = false; + + if (titleExistSeason || (titleExistMaid && titleExistMaidCn)) { + TestMode::RegisterItem ( + L"", + [&](){ + LayeredFs::RegisterBefore ([&] (const std::string &originalFileName, const std::string ¤tFileName) -> std::string { + if (currentFileName.starts_with ("F:\\lumen\\") || currentFileName.find ("title") == std::string::npos) return ""; + if (currentFileName.ends_with ("\\title.nulm")) { + if (language == 4 && titleScreen->Read () == 1 && titleExistSeason) return seasonNulm; + if (language == 4 && titleScreen->Read () == 2 && titleExistMaidCn) return maidNulmCn; + if (titleScreen->Read () == 2 && titleExistMaid) return maidNulm; + } else if (currentFileName.ends_with ("\\title.nutexb")) { + LogMessage (LogLevel::DEBUG, "nutexb"); + if (language == 4 && titleScreen->Read () == 1 && titleExistSeason) return seasonNutexb; + if (language == 4 && titleScreen->Read () == 2 && titleExistMaidCn) return maidNutexbCn; + if (titleScreen->Read () == 2 && titleExistMaid) return maidNutexb; + } + return ""; + }); + LayeredFs::RegisterBefore ([&] (const std::string &originalFileName, const std::string ¤tFileName) -> std::string { + if (titleScreen->Read () != 2 || currentFileName.starts_with ("F:\\lumen\\") || currentFileName.find ("\\lumen\\") == std::string::npos) return ""; + std::string fileName = std::string (currentFileName); + fileName = replace (fileName, "\\lumen\\", "\\lumen_maid\\"); + if (std::filesystem::exists (fileName)) return fileName; + return ""; + }); + }); + } } break; } } @@ -617,7 +634,7 @@ Init () { LogMessage (LogLevel::INFO, "Detected voice files, install voice patches!"); TestMode::RegisterItemAfter( L"/root/menu[@id='OthersMenu']/layout[@type='Center']/select-item[@id='LanguageItem']", - L"", [&](){ INSTALL_FAST_HOOK_DYNAMIC (PlaySoundMain, ASLR (0x1404C6DC0)); @@ -632,7 +649,7 @@ Init () { } } -boolean +boolean CnFontPatches () { return cnFontPatches; } diff --git a/src/patches/layeredfs.cpp b/src/patches/layeredfs.cpp index 54dfe29..05035c3 100644 --- a/src/patches/layeredfs.cpp +++ b/src/patches/layeredfs.cpp @@ -279,7 +279,7 @@ FAST_HOOK (HANDLE, CreateFileAHook, PROC_ADDRESS ("kernel32.dll", "CreateFileA") LPCSTR pFinalFileName = changed ? currentFileName.c_str () : lpFileName; if (changed) LogMessage (LogLevel::HOOKS, "Final Redirect: {}", currentFileName); - return originalCreateFileAHook.stdcall (pFinalFileName, dwDesiredAccess, dwShareMode, + return originalCreateFileAHook.stdcall (pFinalFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile); } @@ -293,7 +293,7 @@ Init () { } register_cipher (&aes_desc); if (useLayeredFs || !beforeHandlers.empty () || !afterHandlers.empty ()) { - LogMessage (LogLevel::INFO, "using LayeredFs! Data_mods={} beforHandlers={} afterHandlers={}", + LogMessage (LogLevel::INFO, "using LayeredFs! Data_mods={} beforHandlers={} afterHandlers={}", useLayeredFs ? "enabled" : "disabled", beforeHandlers.size (), afterHandlers.size ()); INSTALL_FAST_HOOK (CreateFileAHook); } diff --git a/src/patches/patches.h b/src/patches/patches.h index 7410622..659d3e6 100644 --- a/src/patches/patches.h +++ b/src/patches/patches.h @@ -52,7 +52,7 @@ public: }; class Value { public: - virtual int Read() = 0; + virtual int Read(int value = -1) = 0; virtual void Write(int value) = 0; virtual void Reset() = 0; }; @@ -129,5 +129,8 @@ void Init (); namespace Language { boolean CnFontPatches (); void Init (); -} +} // namespace Language +namespace UnlimitSong { +void Init (); +} // namespace UnlimitSong } // namespace patches diff --git a/src/patches/plugins.cpp b/src/patches/plugins.cpp index c072a41..2484645 100644 --- a/src/patches/plugins.cpp +++ b/src/patches/plugins.cpp @@ -40,7 +40,7 @@ namespace patches::Plugins { } } // Card API - void + void WaitTouch (CallBackTouchCard callback, uint64_t touchData) { for (auto plugin : plugins) { auto event = GetProcAddress (plugin, "WaitTouch"); @@ -48,7 +48,7 @@ namespace patches::Plugins { } } // QR API (deprecated) - void + void InitQr (GameVersion gameVersion) { for (auto plugin : plugins) { auto event = GetProcAddress (plugin, "InitQr"); @@ -62,7 +62,7 @@ namespace patches::Plugins { if (event) ((BasicEvent)event) (); } } - void * + void * CheckQr () { for (auto plugin : plugins) { auto event = GetProcAddress (plugin, "UsingQr"); @@ -70,7 +70,7 @@ namespace patches::Plugins { } return nullptr; } - size_t + size_t GetQr (void *plugin, size_t size, uint8_t *buffer) { auto event = GetProcAddress (*(HMODULE *)plugin, "GetQr"); if (event) return ((CopyDataEvent)event) (size, buffer); diff --git a/src/patches/scanner.cpp b/src/patches/scanner.cpp index 2531804..4d9abf3 100644 --- a/src/patches/scanner.cpp +++ b/src/patches/scanner.cpp @@ -147,7 +147,7 @@ namespace Card { patches::Scanner::Card::Internal::InsertCard (cardData, internalInvoke); return true; } - } + } FAST_HOOK (u64, bngrw_Init, PROC_ADDRESS ("bngrw.dll", "BngRwInit")) { return 0; } FAST_HOOK (void, bngrw_Fin, PROC_ADDRESS ("bngrw.dll", "BngRwFin")) { return; } @@ -167,7 +167,7 @@ namespace Card { FAST_HOOK (i32, bngrw_ReqLatchID, PROC_ADDRESS ("bngrw.dll", "BngRwReqLatchID")) { return 1; } FAST_HOOK (u64, bngrw_ReqAiccAuth, PROC_ADDRESS ("bngrw.dll", "BngRwReqAiccAuth")) { return 1; } FAST_HOOK (u64, bngrw_DevReset, PROC_ADDRESS ("bngrw.dll", "BngRwDevReset")) { return 1; } // Invoke when enter testmode - FAST_HOOK (i32, bngrw_ReqCancel, PROC_ADDRESS ("bngrw.dll", "BngRwReqCancel")) { + FAST_HOOK (i32, bngrw_ReqCancel, PROC_ADDRESS ("bngrw.dll", "BngRwReqCancel")) { if (state != State::Disable) { state = State::Disable; patches::Scanner::Card::Internal::Commit0 (accessCodeTemplate, chipIdTemplate, true); @@ -188,7 +188,7 @@ namespace Card { return 1; } - HOOK (i64, bngrw_ReqCancelOfficial, PROC_ADDRESS ("bngrw.dll", "BngRwReqCancel"), u32 a1) { + HOOK (i64, bngrw_ReqCancelOfficial, PROC_ADDRESS ("bngrw.dll", "BngRwReqCancel"), u32 a1) { if (state != State::Disable) { state = State::Disable; patches::Plugins::UpdateStatus (StatusType::CardStatus, false); @@ -339,7 +339,7 @@ namespace Qr { } if (scanQueue.empty() || *scanQueue.back() != buffer) { std::vector *scanData = new std::vector (); - for (uint8_t byte_data : buffer) + for (uint8_t byte_data : buffer) scanData->push_back (byte_data); scanQueue.push (scanData); } @@ -355,7 +355,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 feddde3..e3c2cd4 100644 --- a/src/patches/testmode.cpp +++ b/src/patches/testmode.cpp @@ -18,6 +18,7 @@ std::mutex hooksMutex; std::condition_variable hooksCV; std::vector patches = {}; std::vector values = {}; +std::map valueMap = {}; std::wstring mergeCondition (std::wstring original, std::wstring addition, std::wstring value) { @@ -214,15 +215,16 @@ public: this->reset = true; } int - Read () override { - if (reset) { - this->value = ReadTestModeValue (key.c_str ()); + Read (int value) 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; + if (this->value == -1) return value; + else return this->value; } void Write (int value) override { @@ -357,58 +359,58 @@ LocalizationCHT () { ); TestMode::RegisterModify( L"/root/menu[@id='ModManagerMenu']/layout[@type='Center']/select-item[@id='ModFixLanguage']", - [&](pugi::xml_node &node) { - node.attribute(L"label").set_value(L"修復語言"); - node.attribute(L"replace-text").set_value(L"0:關閉, 1:開啓"); + [&](pugi::xml_node &node) { + node.attribute(L"label").set_value(L"修復語言"); + node.attribute(L"replace-text").set_value(L"0:關閉, 1:開啓"); }, [](){} ); TestMode::RegisterModify( L"/root/menu[@id='ModManagerMenu']/layout[@type='Center']/select-item[@id='ModUnlockSongs']", - [&](pugi::xml_node &node) { - node.attribute(L"label").set_value(L"解鎖歌曲"); - node.attribute(L"replace-text").set_value(L"0:關閉, 1:開啓, 2:強制"); + [&](pugi::xml_node &node) { + node.attribute(L"label").set_value(L"解鎖歌曲"); + node.attribute(L"replace-text").set_value(L"0:關閉, 1:開啓, 2:強制"); }, [](){} ); TestMode::RegisterModify( L"/root/menu[@id='ModManagerMenu']/layout[@type='Center']/select-item[@id='ModFreezeTimer']", - [&](pugi::xml_node &node) { - node.attribute(L"label").set_value(L"凍結計時"); - node.attribute(L"replace-text").set_value(L"0:關閉, 1:開啓"); + [&](pugi::xml_node &node) { + node.attribute(L"label").set_value(L"凍結計時"); + node.attribute(L"replace-text").set_value(L"0:關閉, 1:開啓"); }, [](){} ); TestMode::RegisterModify( L"/root/menu[@id='ModManagerMenu']/layout[@type='Center']/select-item[@id='ModModeCollabo024']", - [&](pugi::xml_node &node) { - node.attribute(L"label").set_value(L"鬼滅之刃模式"); - node.attribute(L"replace-text").set_value(L"0:黙認, 1:啓用, 2:僅登入"); + [&](pugi::xml_node &node) { + node.attribute(L"label").set_value(L"鬼滅之刃模式"); + node.attribute(L"replace-text").set_value(L"0:黙認, 1:啓用, 2:僅登入"); }, [](){} ); TestMode::RegisterModify( L"/root/menu[@id='ModManagerMenu']/layout[@type='Center']/select-item[@id='ModModeCollabo025']", - [&](pugi::xml_node &node) { - node.attribute(L"label").set_value(L"航海王模式"); - node.attribute(L"replace-text").set_value(L"0:黙認, 1:啓用, 2:僅登入"); + [&](pugi::xml_node &node) { + node.attribute(L"label").set_value(L"航海王模式"); + node.attribute(L"replace-text").set_value(L"0:黙認, 1:啓用, 2:僅登入"); }, [](){} ); TestMode::RegisterModify( L"/root/menu[@id='ModManagerMenu']/layout[@type='Center']/select-item[@id='ModModeCollabo026']", - [&](pugi::xml_node &node) { - node.attribute(L"label").set_value(L"AI粗品模式"); - node.attribute(L"replace-text").set_value(L"0:黙認, 1:啓用, 2:僅登入"); + [&](pugi::xml_node &node) { + node.attribute(L"label").set_value(L"AI粗品模式"); + node.attribute(L"replace-text").set_value(L"0:黙認, 1:啓用, 2:僅登入"); }, [](){} ); TestMode::RegisterModify( L"/root/menu[@id='ModManagerMenu']/layout[@type='Center']/select-item[@id='ModModeAprilFool001']", - [&](pugi::xml_node &node) { - node.attribute(L"label").set_value(L"青春之達人模式"); - node.attribute(L"replace-text").set_value(L"0:黙認, 1:啓用, 2:僅登入"); + [&](pugi::xml_node &node) { + node.attribute(L"label").set_value(L"青春之達人模式"); + node.attribute(L"replace-text").set_value(L"0:黙認, 1:啓用, 2:僅登入"); }, [](){} ); TestMode::RegisterModify( L"/root/menu[@id='ModManagerMenu']/layout[@type='Center']/select-item[@id='ModInstantResult']", - [&](pugi::xml_node &node) { - node.attribute(L"label").set_value(L"即時保存"); - node.attribute(L"replace-text").set_value(L"0:關閉, 1:開啓"); + [&](pugi::xml_node &node) { + node.attribute(L"label").set_value(L"即時保存"); + node.attribute(L"replace-text").set_value(L"0:關閉, 1:開啓"); }, [](){} ); TestMode::RegisterModify( @@ -417,9 +419,9 @@ LocalizationCHT () { ); TestMode::RegisterModify( L"/root/menu[@id='OthersMenu']/layout[@type='Center']/select-item[@id='AttractDemoItem']", - [&](pugi::xml_node &node) { - node.attribute(L"label").set_value(L"演示遊玩影片"); - node.attribute(L"replace-text").set_value(L"0:關閉, 1:開啓"); + [&](pugi::xml_node &node) { + node.attribute(L"label").set_value(L"演示遊玩影片"); + node.attribute(L"replace-text").set_value(L"0:關閉, 1:開啓"); }, [](){} ); } @@ -521,11 +523,15 @@ SetupAccessor (const u64 appAccessor, const RefTestModeMain refTestMode) { int ReadTestModeValue (const wchar_t *itemId) { if (appAccessor) { - if (const u64 testModeMain = refTestMode (appAccessor)) { - int value = 0; - u64 *reader = *reinterpret_cast (testModeMain + 16); - (*reinterpret_cast (*reader + 256)) (reader, itemId, &value); - return value; + try { + if (const u64 testModeMain = refTestMode (appAccessor)) { + int value = 0; + u64 *reader = *reinterpret_cast (testModeMain + 16); + (*reinterpret_cast (*reader + 256)) (reader, itemId, &value); + return value; + } + } catch ([[maybe_unused]] std::exception &e) { + LogMessage (LogLevel::ERROR, L"Reading Value({}) Error!", itemId); } } return -1; @@ -550,8 +556,10 @@ CreateMenu (const std::wstring &menuName, const std::wstring &menuId) { Value * CreateValue (const std::wstring &key) { LogMessage (LogLevel::DEBUG, L"Create TestMode Value key: {}", key); + // if (valueMap.count (key)) return valueMap[key]; Value *value = (Value *)(new TestModeValue (key)); values.push_back ((Value *)value); + // valueMap[key] = value; return value; } diff --git a/src/patches/versions/CHN00.cpp b/src/patches/versions/CHN00.cpp index 6ae159e..9996ecb 100644 --- a/src/patches/versions/CHN00.cpp +++ b/src/patches/versions/CHN00.cpp @@ -2,6 +2,9 @@ #include "../patches.h" extern std::string chassisId; +extern i32 xRes; +extern i32 yRes; +extern bool vsync; namespace patches::CHN00 { int language = 0; @@ -101,9 +104,6 @@ ReplaceLeaBufferAddress (const std::vector &bufferAddresses, void *ne void Init () { LogMessage (LogLevel::INFO, "Init CHN00 patches"); - i32 xRes = 1920; - i32 yRes = 1080; - bool vsync = false; bool unlockSongs = true; bool fixLanguage = false; bool demoMovie = true; @@ -139,14 +139,6 @@ Init () { modeCollabo026 = readConfigBool (chn00, "mode_collabo026", modeCollabo026); } } - - if (const auto graphics = openConfigSection (config_ptr.get (), "graphics")) { - if (const auto res = openConfigSection (graphics, "res")) { - xRes = static_cast (readConfigInt (res, "x", xRes)); - yRes = static_cast (readConfigInt (res, "y", yRes)); - } - vsync = readConfigBool (graphics, "vsync", vsync); - } } // Apply common config patch diff --git a/src/patches/versions/JPN00.cpp b/src/patches/versions/JPN00.cpp index 301f595..fe1e492 100644 --- a/src/patches/versions/JPN00.cpp +++ b/src/patches/versions/JPN00.cpp @@ -1,6 +1,10 @@ #include "helpers.h" #include "../patches.h" +extern i32 xRes; +extern i32 yRes; +extern bool vsync; + namespace patches::JPN00 { HOOK_DYNAMIC (char, AMFWTerminate, i64) { return 0; } @@ -37,9 +41,6 @@ ReplaceLeaBufferAddress (const std::vector &bufferAddresses, void *ne void Init () { LogMessage (LogLevel::INFO, "Init JNP00 patches"); - i32 xRes = 1920; - i32 yRes = 1080; - bool vsync = false; bool unlockSongs = true; const auto configPath = std::filesystem::current_path () / "config.toml"; @@ -47,14 +48,6 @@ Init () { if (config_ptr) { if (const auto patches = openConfigSection (config_ptr.get (), "patches")) unlockSongs = readConfigBool (patches, "unlock_songs", unlockSongs); - - if (const auto graphics = openConfigSection (config_ptr.get (), "graphics")) { - if (const auto res = openConfigSection (graphics, "res")) { - xRes = static_cast (readConfigInt (res, "x", xRes)); - yRes = static_cast (readConfigInt (res, "y", yRes)); - } - vsync = readConfigBool (graphics, "vsync", vsync); - } } // Apply common config patch diff --git a/src/patches/versions/JPN08.cpp b/src/patches/versions/JPN08.cpp index 9a4d04b..851b4f3 100644 --- a/src/patches/versions/JPN08.cpp +++ b/src/patches/versions/JPN08.cpp @@ -3,6 +3,9 @@ extern u64 song_data_size; extern void *song_data; +extern i32 xRes; +extern i32 yRes; +extern bool vsync; #define RDX_MOV 0x48, 0xBA #define R8_MOV 0x49, 0xB8 @@ -48,23 +51,12 @@ ReplaceLeaBufferAddress (const std::vector &bufferAddresses, void *ne void Init () { LogMessage (LogLevel::INFO, "Init JPN08 patches"); - i32 xRes = 1920; - i32 yRes = 1080; - bool vsync = false; bool unlockSongs = true; 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 graphics = openConfigSection (config_ptr.get (), "graphics")) { - if (auto res = openConfigSection (graphics, "res")) { - xRes = static_cast (readConfigInt (res, "x", xRes)); - yRes = static_cast (readConfigInt (res, "y", yRes)); - } - vsync = readConfigBool (graphics, "vsync", vsync); - } } // Apply common config patch diff --git a/src/patches/versions/JPN39.cpp b/src/patches/versions/JPN39.cpp index 62a79d4..284a718 100644 --- a/src/patches/versions/JPN39.cpp +++ b/src/patches/versions/JPN39.cpp @@ -3,6 +3,10 @@ #include "../patches.h" #include +extern i32 xRes; +extern i32 yRes; +extern bool vsync; + namespace patches::JPN39 { int language = 0; FAST_HOOK_DYNAMIC (char, AMFWTerminate, i64) { @@ -39,7 +43,7 @@ FUNCTION_PTR (i32, luaL_loadstring, PROC_ADDRESS ("lua51.dll", "luaL_loadstring" FUNCTION_PTR (u64, RefTestModeMain, ASLR (0x1400337C0), u64); FUNCTION_PTR (u64, RefPlayDataManager, ASLR (0x140024AC0), u64); -FUNCTION_PTR (i64, GetUserCount, ASLR (0x1403F1020), u64); +FUNCTION_PTR (i64, GetUserCount, ASLR (0x1403F1080), u64); i64 lua_pushbool (const i64 a1, const bool val) { @@ -196,6 +200,52 @@ ExecuteSendResultData () { ); } +bool sendFlag = false; +TestMode::Value *instantResult = TestMode::CreateValue (L"ModInstantResult"); +TestMode::Value *stageNumber = TestMode::CreateValue (L"NumberOfStageItem"); +#define SCENE_RESULT_HOOK(functionName, location) \ + FAST_HOOK (void, functionName, location, i64 a1, i64 a2, i64 a3) { \ + if (instantResult->Read () != 1 && stageNumber->Read () <= 4) { \ + original##functionName.fastcall (a1, a2, a3); \ + return; \ + } \ + sendFlag = true; \ + original##functionName.fastcall (a1, a2, a3); \ + ExecuteSendResultData (); \ + } + +#define SEND_RESULT_HOOK(functionName, location) \ + FAST_HOOK (void, functionName, location, i64 a1) { \ + if (instantResult->Read () != 1 && stageNumber->Read () <= 4) { \ + original##functionName.fastcall (a1); \ + return; \ + } \ + if (sendFlag) { \ + sendFlag = false; \ + original##functionName.fastcall (a1); \ + } \ + } + +#define CHANGE_RESULT_SIZE_HOOK(functionName, location, target) \ + MID_HOOK (functionName, location, SafetyHookContext &ctx) { \ + if (instantResult->Read () != 1 && stageNumber->Read () <= 4) { return; } \ + i64 instance = RefPlayDataManager (*(i64 *)ctx.r12); \ + u32 currentStageCount = *(u32 *)(instance + 8); \ + ctx.target &= 0xFFFFFFFF00000000; \ + ctx.target |= currentStageCount; \ + } + +#define CHANGE_RESULT_INDEX_HOOK(functionName, location, target, offset, skip) \ + MID_HOOK (functionName, location, SafetyHookContext &ctx) { \ + if (instantResult->Read () != 1 && stageNumber->Read () <= 4) { return; } \ + i64 instance = RefPlayDataManager (*(i64 *)ctx.r12); \ + u32 currentStageCount = *(u32 *)(instance + 8); \ + ctx.target &= 0xFFFFFFFF00000000; \ + ctx.target |= currentStageCount - 1; \ + *(u32 *)(ctx.rsp + offset) = currentStageCount - 1; \ + ctx.rip += skip; \ + } + SCENE_RESULT_HOOK (SceneResultInitialize_Enso, ASLR (0x140411FD0)); SCENE_RESULT_HOOK (SceneResultInitialize_AI, ASLR (0x140411FD0)); SCENE_RESULT_HOOK (SceneResultInitialize_Collabo025, ASLR (0x140411FD0)); @@ -248,12 +298,13 @@ MID_HOOK (AttractDemo, ASLR (0x14045A720), SafetyHookContext &ctx) { if (attractDemo->Read () == 1) ctx.r14 = 0; } -// 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); -// } +FAST_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[0] = xRes; + // a3[1] = yRes; + // LogMessage (LogLevel::DEBUG, "AcquireMostCompatibleDisplayMode {:d} {:d} {:f} {:f}", a3[0], a3[1], (float)(int)a3[2], (float)(int)a3[3]); + return originalAcquireMostCompatibleDisplayMode.fastcall (a1, a2, a3); +} constexpr i32 datatableBufferSize = 1024 * 1024 * 12; uint8_t *datatableBuffer[3] = { nullptr }; @@ -281,10 +332,8 @@ ReplaceDatatableBufferAddresses () { void Init () { LogMessage (LogLevel::INFO, "Init JPN39 patches"); - i32 xRes = 1920; - i32 yRes = 1080; - bool vsync = false; bool unlockSongs = true; + double modelResRate = 1.0; auto configPath = std::filesystem::current_path () / "config.toml"; std::unique_ptr config_ptr (openConfig (configPath), toml_free); @@ -292,24 +341,45 @@ Init () { if (auto patches = openConfigSection (config_ptr.get (), "patches")) { unlockSongs = readConfigBool (patches, "unlock_songs", unlockSongs); } - if (auto graphics = openConfigSection (config_ptr.get (), "graphics")) { - if (auto res = openConfigSection (graphics, "res")) { - xRes = static_cast (readConfigInt (res, "x", xRes)); - yRes = static_cast (readConfigInt (res, "y", yRes)); - } - vsync = readConfigBool (graphics, "vsync", vsync); + modelResRate = readConfigDouble (graphics, "model_res_rate", modelResRate); } } // Hook to get AppAccessor and ComponentAccessor INSTALL_FAST_HOOK (DeviceCheck); INSTALL_FAST_HOOK (luaL_newstate); - // INSTALL_HOOK (AcquireMostCompatibleDisplayMode); + // INSTALL_FAST_HOOK (AcquireMostCompatibleDisplayMode); - // Apply common config patch + // Window Size WRITE_MEMORY (ASLR (0x140494533), i32, xRes); WRITE_MEMORY (ASLR (0x14049453A), i32, yRes); + // DonSystem::DonModelRenderer::DonModelRenderer + if (modelResRate > 0) { + i32 donModelX = (i32)(xRes * modelResRate); + i32 donModelY = (i32)(yRes * modelResRate); + LogMessage (LogLevel::INFO, "Patch DonModel use resolution {}x{}", donModelX, donModelY); + WRITE_MEMORY (ASLR (0x1404F3D5B), i32, donModelX); + WRITE_MEMORY (ASLR (0x1404F3D62), i32, donModelY); + } + // // DonSystem::Renderer::Renderer + // WRITE_MEMORY (ASLR (0x1404FBF33), i32, xRes); + // WRITE_MEMORY (ASLR (0x1404FBF3A), i32, yRes); + // // DonSystem::Renderer::CreateOnpuPass + // WRITE_MEMORY (ASLR (0x1404FCF77), i32, xRes); + // WRITE_MEMORY (ASLR (0x1404FCF81), i32, yRes / 2); + // // nu::LightManager::LightManager + // WRITE_MEMORY (ASLR (0x1406BED7A), i32, xRes); + // WRITE_MEMORY (ASLR (0x1406BED82), i32, yRes); + // WRITE_MEMORY (ASLR (0x1406BEF26), i32, xRes); + // WRITE_MEMORY (ASLR (0x1406BEF33), i32, yRes); + // // google::protobuf::TextFormat::Parser::ParserImpl::ConsumeField + // WRITE_MEMORY (ASLR (0x1406F7E47), i32, xRes); + // // google::protobuf::DescriptorBuilder::AddSymbol + // WRITE_MEMORY (ASLR (0x140719191), i32, xRes); + // nuscDecoderCalcObjectSize + // WRITE_MEMORY (ASLR (0x140719191), i32, xRes); + if (!vsync) WRITE_MEMORY (ASLR (0x14064C7E9), u8, 0xBA, 0x00, 0x00, 0x00, 0x00, 0x90); // Bypass errors @@ -350,10 +420,10 @@ Init () { TestMode::RegisterItem ( L"", - [&]() { - INSTALL_FAST_HOOK (IsSongRelease); - INSTALL_FAST_HOOK (IsSongReleasePlayer); - INSTALL_MID_HOOK (DifficultyPanelCrown); + [&]() { + INSTALL_FAST_HOOK (IsSongRelease); + INSTALL_FAST_HOOK (IsSongReleasePlayer); + INSTALL_MID_HOOK (DifficultyPanelCrown); } ); // Freeze Timer diff --git a/src/poll.h b/src/poll.h index 9b7edb4..cf3982d 100644 --- a/src/poll.h +++ b/src/poll.h @@ -40,10 +40,10 @@ struct SDLAxisState { enum Scroll { MOUSE_SCROLL_INVALID, MOUSE_SCROLL_UP, MOUSE_SCROLL_DOWN }; struct Keybindings { - u8 keycodes[255]; - SDL_GamepadButton buttons[255]; - SDLAxis axis[255]; - Scroll scroll[2]; + u8 keycodes[255] = { '\0' }; + SDL_GamepadButton buttons[255] = { SDL_GAMEPAD_BUTTON_INVALID }; + SDLAxis axis[255] = { SDL_AXIS_NULL }; + Scroll scroll[2] = { MOUSE_SCROLL_INVALID }; }; enum EnumType { none, keycode, button, axis, scroll }; diff --git a/src/pollasync.cpp b/src/pollasync.cpp index f4e6132..17e1e54 100644 --- a/src/pollasync.cpp +++ b/src/pollasync.cpp @@ -10,6 +10,9 @@ extern int exited; extern u8 inputState; extern float axisThreshold; extern bool globalKeyboardInput; +extern bool autoIme; +extern HKL currentLayout; +extern bool emulateUsio; bool wndForeground = false; bool usingKeyboard = false; @@ -67,6 +70,7 @@ SetConfigValue (const toml_table_t *table, const char *key, Keybindings *key_bin switch (value.type) { case keycode: { + LogMessage (LogLevel::DEBUG, "config {} type=keycode value={}", key, (int)value.keycode); *inputState |= 1; for (int i = 0; i < std::size (key_bind->keycodes); i++) { if (key_bind->keycodes[i] == 0) { @@ -77,6 +81,7 @@ SetConfigValue (const toml_table_t *table, const char *key, Keybindings *key_bin break; } case button: { + LogMessage (LogLevel::DEBUG, "config {} type=button value={}", key, (int)value.button); *inputState |= (1 << 2); for (int i = 0; i < std::size (key_bind->buttons); i++) { if (key_bind->buttons[i] == SDL_GAMEPAD_BUTTON_INVALID) { @@ -87,6 +92,7 @@ SetConfigValue (const toml_table_t *table, const char *key, Keybindings *key_bin break; } case axis: { + LogMessage (LogLevel::DEBUG, "config {} type=axis value={}", key, (int)value.axis); *inputState |= (1 << 2); for (int i = 0; i < std::size (key_bind->axis); i++) { if (key_bind->axis[i] == 0) { @@ -94,8 +100,10 @@ SetConfigValue (const toml_table_t *table, const char *key, Keybindings *key_bin break; } } + break; } case scroll: { + LogMessage (LogLevel::DEBUG, "config {} type=scroll value={}", key, (int)value.scroll); *inputState |= (1 << 1); for (int i = 0; i < std::size (key_bind->scroll); i++) { if (key_bind->scroll[i] == 0) { @@ -196,16 +204,19 @@ CheckFlipped (uint32_t which, SDL_Gamepad *gamepad) { bool InitializePoll (HWND windowHandle) { + wndForeground = windowHandle == GetForegroundWindow (); + if (!emulateUsio) return false; + usingKeyboard = inputState & 1; usingMouse = inputState & (1 << 1); usingController = inputState & (1 << 2); usingSDLEvent = usingMouse || usingController; + atexit ([](){ if (currentLayout != nullptr) ActivateKeyboardLayout (currentLayout, KLF_SETFORPROCESS);}); InitializeKeyboard (); if (usingSDLEvent) { LogMessage (LogLevel::DEBUG, "InitializePoll"); bool hasRumble = true; - wndForeground = windowHandle == GetForegroundWindow (); SDL_SetMainReady (); SDL_SetHint (SDL_HINT_JOYSTICK_HIDAPI_PS4, "1"); @@ -267,9 +278,18 @@ InitializePoll (HWND windowHandle) { bool CheckForegroundWindow (HWND processWindow) { if (processWindow == nullptr) return false; - if (wndForeground ^ (processWindow == GetForegroundWindow ())) { + HWND foregroundWnd = GetForegroundWindow (); + if (wndForeground ^ (processWindow == foregroundWnd)) { wndForeground = !wndForeground; LogMessage (LogLevel::DEBUG, "window focus={}", wndForeground); + if (autoIme) { + if (wndForeground) { + currentLayout = GetKeyboardLayout (0); + auto engLayout = LoadKeyboardLayout (TEXT ("00000409"), KLF_ACTIVATE); + ActivateKeyboardLayout (engLayout, KLF_SETFORPROCESS); + LogMessage (LogLevel::DEBUG, "(experimental) auto change KeyboardLayout {}", LOWORD(engLayout)); + } + } } return wndForeground; } @@ -288,11 +308,11 @@ CorrectButton (uint32_t which, uint8_t button) { void CleanPoll () { - if (usingKeyboard && keyboardClean) { - keyboardClean = false; - for (int i=0; i<0xFF; i++) keyboardCount[i] -= (bool)keyboardDiff[i]; + if (usingKeyboard) { + for (int i=0; i<0xFF; i++) keyboardCount[i] -= (bool)keyboardDiff[i]; memset (keyboardDiff, 0, 0XFF); } + if (usingMouse) { currentMouseState.ScrolledUp = false; currentMouseState.ScrolledDown = false; @@ -311,7 +331,8 @@ CleanPoll () { void UpdatePoll (HWND windowHandle) { - if (!CheckForegroundWindow (windowHandle)) return; + if (!CheckForegroundWindow (windowHandle)) return; + if (!emulateUsio) return; CleanPoll (); if (usingSDLEvent) { SDL_Event event; @@ -347,7 +368,7 @@ UpdatePoll (HWND windowHandle) { uint8_t button = CorrectButton (event.gbutton.which, event.gbutton.button); currentControllerButtonsState[button] = false; } break; - case SDL_EVENT_GAMEPAD_BUTTON_DOWN: + case SDL_EVENT_GAMEPAD_BUTTON_DOWN: if (wndForeground) { uint8_t button = CorrectButton (event.gbutton.which, event.gbutton.button); LogMessage (LogLevel::DEBUG, "Controller {}: button {} pressed, remapped to {}", event.gbutton.which, event.gbutton.button, button); @@ -379,7 +400,7 @@ UpdatePoll (HWND windowHandle) { currentControllerAxisState[button] = sensorValue; } break; } break; - } + } } } } @@ -504,20 +525,28 @@ ControllerAxisIsTapped (const SDLAxis axis) { 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; + if (bindings.keycodes[i] == '\0') continue; + if (KeyboardIsTapped (bindings.keycodes[i])) { + return true; + } } for (size_t i = 0; i < std::size (ConfigControllerButtons); i++) { if (bindings.buttons[i] == SDL_GAMEPAD_BUTTON_INVALID) continue; - if (ControllerButtonIsTapped (bindings.buttons[i])) return true; + if (ControllerButtonIsTapped (bindings.buttons[i])) { + return true; + } } for (size_t i = 0; i < std::size (ConfigControllerAXIS); i++) { - if (bindings.axis[i] == 0) continue; - if (float val = ControllerAxisIsTapped (bindings.axis[i]); val > 0) return true; + if (bindings.axis[i] == SDL_AXIS_NULL) continue; + if (ControllerAxisIsTapped (bindings.axis[i])) { + return true; + } } for (size_t i = 0; i < std::size (ConfigMouseScroll); i++) { - if (bindings.scroll[i] == 0) continue; - if (GetMouseScrollIsTapped (bindings.scroll[i])) return true; + if (bindings.scroll[i] == MOUSE_SCROLL_INVALID) continue; + if (GetMouseScrollIsTapped (bindings.scroll[i])) { + return true; + } } return false; }