From d0374dca1bcf0db79d1d4ad093e7d12e27486ea3 Mon Sep 17 00:00:00 2001 From: KIT! Date: Sun, 24 Nov 2024 17:41:44 +0100 Subject: [PATCH] Added Logger to TAL (#13) * Added Logger for TAL with __VA_ARGS__ support * Added Tatacon entries in SDL DB * Added comments to exported config file * Included keys for LayeredFS * Cleaned up a bit of code in JPN39 patches * Formatted all files using clang-format * Force invalid cards on original readers You can now use any cards with the original namco readers. * Move helper functions to cpp file --------- Co-authored-by: ptmaster --- README.md | 146 ++++++------- dist/config.toml | 84 +++++--- dist/gamecontrollerdb.txt | 5 + meson.build | 1 + src/bnusio.cpp | 140 +++++++------ src/dllmain.cpp | 77 ++++--- src/helpers.cpp | 112 ++++++---- src/helpers.h | 83 ++++++-- src/logger.cpp | 111 ++++++++++ src/logger.h | 65 ++++++ src/patches/amauth.cpp | 133 +++--------- src/patches/audio.cpp | 5 + src/patches/dxgi.cpp | 1 + src/patches/fpslimiter.cpp | 1 + src/patches/layeredfs.cpp | 101 ++++----- src/patches/patches.h | 12 +- src/patches/qr.cpp | 43 ++-- src/patches/testmode.cpp | 366 ++++++++++++++++++--------------- src/patches/versions/CHN00.cpp | 40 ++-- src/patches/versions/JPN00.cpp | 9 - src/patches/versions/JPN39.cpp | 246 +++++++++------------- src/poll.cpp | 25 +-- 22 files changed, 996 insertions(+), 810 deletions(-) create mode 100644 src/logger.cpp create mode 100644 src/logger.h diff --git a/README.md b/README.md index 209430d..8287ace 100644 --- a/README.md +++ b/README.md @@ -17,113 +17,81 @@ If your game hangs on a black screen at launch for more than a minute, Start Tai ```toml [amauth] -# server ip server = "127.0.0.1" -# server port port = "54430" -# dongle serial chassis_id = "284111080000" -# shop name shop_id = "TAIKO ARCADE LOADER" -# game version game_ver = "00.00" -# country code country_code = "JPN" [patches] -# patch version -# auto: hash detection (you need to use the original exe) -# JPN00: JPN 00.18 -# JPN08: JPN 08.18 -# JPN39: JPN 39.06 -# CHN00: CHN 00.32 (based on JPN 32.09) -version = "auto" -# unlock all songs +version = "auto" # Patch version + # | - auto: hash detection (you need to use the original exe otherwise it will not load). + # | - JPN00: For use with Taiko JPN 00.18 + # | - JPN08: For use with Taiko JPN 08.18 + # | - JPN39: For use with Taiko JPN 39.06 + # | - CHN00: For use with Taiko CHN 00.32 unlock_songs = true - [patches.chn00] - # sync test mode language to attract etc - fix_language = false - # show demo movie - demo_movie = true - # enable one piece collab mode - mode_collabo025 = false - # enable ai soshina mode - mode_collabo026 = false +[patches.chn00] # These patches are only available for version CHN00 +fix_language = false # Sync test mode language to attract etc +demo_movie = true # Show demo movie +mode_collabo025 = false # Enable one piece collab mode +mode_collabo026 = false # Enable ai soshina mode - [patches.jpn39] - # sync test mode language to attract etc - fix_language = false - # use cn font and chineseS wordlist value - chs_patch = false - # more options is now moved to testmode +[patches.jpn39] # These patches are only available for version JPN39 +fix_language = false # Sync test mode language to attract etc +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] -# If usio emulation is disabled, you need to place bnusio_original.dll (unmodified bnusio.dll) in the executable folder. -usio = true -card_reader = true -qr = true +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 +qr = true # Disable this if you have an original namco qr code scanner [graphics] -# window resolution res = { x = 1920, y = 1080 } -# window mode windowed = false -# vertical sync vsync = false -# fps limit fpslimit = 120 [audio] -# wasapi shared mode -# allows you to have multiple audio sources at once at a cost of having higher latency. -wasapi_shared = true -# use asio audio mode -asio = false -# asio driver name -# to find it, open up regedit then navigate to HKEY_LOCAL_MACHINE\SOFTWARE\ASIO -# the name is case sensitive. -asio_driver = "" +wasapi_shared = true # 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. + # | It is case sensitive. [qr] -# qr image path -image_path = "" +image_path = "" # Path to the image of the QR Code you want to use - # qr data used for other events (ex. gaiden, custom folder) - [qr.data] - # qr serial - serial = "" - # qr type - # 0: default (serial only) - # 5: custom folder - type = 0 - # song noes used for custom folder - song_no = [] - -[drum] -# input interval (if using taiko drum controller, should be set to 0) -wait_period = 4 +[qr.data] # qr data used for other events (ex. gaiden, custom folder) +serial = "" # qr serial +type = 0 # qr type + # | 0: default (serial only) + # | 5: custom folder +song_no = [] # Song noes used for custom folder [controller] -# use analog input -analog_input = false +wait_period = 4 # 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 change to english ime mode -auto_ime = false -# use jp layout scan code (if using jp layout keyboard, must be set to true) -jp_layout = false +auto_ime = false # 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] -# 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.bin -enabled = false -# AES encryption keys needed to dynamically encrypt datatable files and fumens. -# keys need to be provided in an hexlified form. A missing or incorrect key will crash the game. -# keys are not needed if you provide already encrypted files. -datatable_key = "" -fumen_key = "" +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. + +[logging] +log_level = "INFO" # Log level, Can be either "NONE", "ERROR", "WARN", "INFO", "DEBUG" and "HOOKS" + # | Keep this as low as possible (Info is usually more than enough) as more logging will slow down your game +log_to_file = false # Log to file, set this to true to save the logs from your last session to TaikoArcadeLoader.log + # |Again, if you do not have a use for this (debugging mods or whatnot), turn it off. ``` ## TestMode options (JPN39 only) @@ -131,15 +99,17 @@ fumen_key = "" TaikoArcadeLoader offers several patches to select in TestMode The follow options are available in "MOD MANAGER" menu: -- FREEZE TIMER (stop timer count down) -- KIMETSU MODE (enable collabo024, will show a blank title) -- ONE PIECE MODE (enable collabo025) -- AI SOSHINA MODE (enable collabo026) -- AOHARU MODE (enable aprilfool001) -- INSTANT RESULT (send result per song) + +* FREEZE TIMER (stop timer count down) +* KIMETSU MODE (enable collabo024, will show a blank title) +* ONE PIECE MODE (enable collabo025) +* AI SOSHINA MODE (enable collabo026) +* AOHARU MODE (enable aprilfool001) +* INSTANT RESULT (send result per song) Enhanced original option: -- Louder volume (Speaker Volume is now up to 300%, **WARNING: May damage your speakers**) + +* Louder volume (Speaker Volume is now up to 300%, **WARNING: May damage your speakers**) ## Building @@ -147,16 +117,16 @@ TaikoArcadeLoader can be a bit tricky to build if you've never done it before. Go to the TaikoArcadeLoader folder and run the following commands: ```bash -apt install -y npm mingw-w64 ninja-build nasm pip 7zip cmake +apt install -y npm mingw-w64 ninja-build nasm 7zip cmake python3-pip pip3 install meson npm install n -g && n latest && npm install --global xpm@latest npx xpm init && npx xpm install @xpack-dev-tools/mingw-w64-gcc@latest -# make sure you entered TaikoArcadeLoader folder +# make sure you're in the TaikoArcadeLoader folder before running this export PATH=`pwd`/xpacks/.bin:$PATH -make setup +make clean-setup ``` Once that's done, run `make` to build TAL. -The output will be written in the `out` folder. \ No newline at end of file +The output will be written in the `out` folder. diff --git a/dist/config.toml b/dist/config.toml index 09e5de9..fb8df90 100644 --- a/dist/config.toml +++ b/dist/config.toml @@ -6,24 +6,36 @@ shop_id = "TAIKO ARCADE LOADER" game_ver = "00.00" country_code = "JPN" + [patches] -version = "auto" +version = "auto" # Patch version + # | - auto: hash detection (you need to use the original exe otherwise it will not load). + # | - JPN00: For use with Taiko JPN 00.18 + # | - JPN08: For use with Taiko JPN 08.18 + # | - JPN39: For use with Taiko JPN 39.06 + # | - CHN00: For use with Taiko CHN 00.32 unlock_songs = true - [patches.chn00] - fix_language = false - demo_movie = true - mode_collabo025 = false - mode_collabo026 = false - [patches.jpn39] - fix_language = false - chs_patch = false +[patches.chn00] # These patches are only available for version CHN00 +fix_language = false # Sync test mode language to attract etc +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 +fix_language = false # Sync test mode language to attract etc +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 -card_reader = true -qr = true +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 +qr = true # Disable this if you want to use an original Namco QR code scanner + [graphics] res = { x = 1920, y = 1080 } @@ -31,30 +43,46 @@ windowed = false vsync = false fpslimit = 120 + [audio] -wasapi_shared = true -asio = false -asio_driver = "" +wasapi_shared = true # 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. + # | It is case sensitive. + [qr] -image_path = "" +image_path = "" # Path to the image of the QR Code you want to use - [qr.data] - serial = "" - type = 0 - song_no = [] -[drum] -wait_period = 4 +[qr.data] # QR data used for other events (ex. gaiden, custom folder) +serial = "" # QR serial +type = 0 # QR type + # | 0: default (serial only) + # | 5: custom folder +song_no = [] # Song noes used for custom folder + [controller] -analog_input = false +wait_period = 4 # 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 -jp_layout = false +auto_ime = false # 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 -datatable_key = "" -fumen_key = "" \ No newline at end of file +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. + + +[logging] +log_level = "INFO" # Log level, Can be either "NONE", "ERROR", "WARN", "INFO", "DEBUG" and "HOOKS" + # | Keep this as low as possible (Info is usually more than enough) as more logging will slow down your game +log_to_file = false # Log to file, set this to true to save the logs from your last session to TaikoArcadeLoader.log + # |Again, if you do not have a use for this (debugging mods or whatnot), turn it off. \ No newline at end of file diff --git a/dist/gamecontrollerdb.txt b/dist/gamecontrollerdb.txt index 8a072a4..51f50a7 100644 --- a/dist/gamecontrollerdb.txt +++ b/dist/gamecontrollerdb.txt @@ -1,6 +1,11 @@ # Game Controller DB for SDL in 2.0.16 format # Source: https://github.com/gabomdq/SDL_GameControllerDB +# Taiko stuff +03000000de280000ff11000001007801,HORI Taiko Controller,platform:Windows,leftstick:b6,rightstick:b7,lefttrigger:b4,righttrigger:b5, +030000000d0f0000f000000000000000,Hori Taiko Controller,platform:Windows,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,lefttrigger:b6,righttrigger:b7,platform:Windows, +030000000d0f0000f000000011010000,HORI Taiko Controller,leftstick:b10,rightstick:b11,lefttrigger:b6,righttrigger:b7,platform:Linux, + # Windows 03000000300f00000a01000000000000,3 In 1 Conversion Box,a:b2,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b8,x:b3,y:b0,platform:Windows, 03000000fa2d00000100000000000000,3dRudder Foot Motion Controller,leftx:a0,lefty:a1,rightx:a5,righty:a2,platform:Windows, diff --git a/meson.build b/meson.build index 69541b9..f50c2e8 100644 --- a/meson.build +++ b/meson.build @@ -79,6 +79,7 @@ library( sources : [ 'src/dllmain.cpp', 'src/helpers.cpp', + 'src/logger.cpp', 'src/poll.cpp', 'src/bnusio.cpp', 'src/patches/amauth.cpp', diff --git a/src/bnusio.cpp b/src/bnusio.cpp index 69a82aa..6012ab7 100644 --- a/src/bnusio.cpp +++ b/src/bnusio.cpp @@ -14,6 +14,7 @@ extern char chipId2[33]; extern bool autoIme; extern bool emulateUsio; extern bool emulateCardReader; +extern bool acceptInvalidCards; typedef i32 (*callbackAttach) (i32, i32, i32 *); typedef void (*callbackTouch) (i32, i32, u8[168], u64); @@ -40,10 +41,10 @@ Keybindings P1_LEFT_BLUE = {.keycodes = {'D'}, .axis = {SDL_AXIS_LEFT_DOWN}}; Keybindings P1_LEFT_RED = {.keycodes = {'F'}, .axis = {SDL_AXIS_LEFT_RIGHT}}; Keybindings P1_RIGHT_RED = {.keycodes = {'J'}, .axis = {SDL_AXIS_RIGHT_RIGHT}}; Keybindings P1_RIGHT_BLUE = {.keycodes = {'K'}, .axis = {SDL_AXIS_RIGHT_DOWN}}; -Keybindings P2_LEFT_BLUE = {}; -Keybindings P2_LEFT_RED = {}; -Keybindings P2_RIGHT_RED = {}; -Keybindings P2_RIGHT_BLUE = {}; +Keybindings P2_LEFT_BLUE = {.keycodes = {'Z'}}; +Keybindings P2_LEFT_RED = {.keycodes = {'X'}}; +Keybindings P2_RIGHT_RED = {.keycodes = {'C'}}; +Keybindings P2_RIGHT_BLUE = {.keycodes = {'V'}}; bool testEnabled = false; int coin_count = 0; @@ -187,6 +188,30 @@ u16 __fastcall bnusio_GetCoin (i32 a1) { return coin_count; } u16 __fastcall bnusio_GetService (i32 a1) { return service_count; } } +void +InspectWaitTouch (i32 a1, i32 a2, u8 _cardData[168], u64 _touchData) { + if (AreAllBytesZero (_cardData, 0x00, 168)) // This happens when you enter test mode. + return touchCallback (a1, a2, _cardData, _touchData); + + bool valid = !AreAllBytesZero (_cardData, 0x50, 21); + if (valid) { + LogMessage (LOG_LEVEL_DEBUG, "Card is valid"); + } else { + memcpy (_cardData + 0x50, _cardData + 0x2C, 16); // 16 to match felica lite serial number length + LogMessage (LOG_LEVEL_DEBUG, "Card is usually not supported"); + } + + std::ostringstream oss; + for (size_t i = 0; i < 168; ++i) { + oss << std::setw (2) << std::setfill ('0') << std::hex << static_cast (_cardData[i]) << " "; + if ((i + 1) % 21 == 0) oss << "\n"; + } + + LogMessage (LOG_LEVEL_DEBUG, "A1: %d, A2: %d, Card data: \n%s", a1, a2, oss.str ().c_str ()); + + if (touchCallback) return valid ? touchCallback (a1, a2, _cardData, _touchData) : touchCallback (0, 0, _cardData, _touchData); +} + 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); @@ -238,9 +263,9 @@ HOOK (void, bngrw_Fin, PROC_ADDRESS ("bngrw.dll", "BngRwFin")) { return; } HOOK (u64, bngrw_IsCmdExec, PROC_ADDRESS ("bngrw.dll", "BngRwIsCmdExec")) { return 0xFFFFFFFF; } HOOK (i32, bngrw_ReqCancel, PROC_ADDRESS ("bngrw.dll", "BngRwReqCancel")) { return 1; } HOOK (i32, bngrw_ReqSendUrl, PROC_ADDRESS ("bngrw.dll", "BngRwReqSendUrlTo")) { return 1; } -HOOK (u64, bngrw_ReqLed, PROC_ADDRESS ("bngrw.dll", "BngRwReqLed")) { return 1; } -HOOK (u64, bngrw_ReqBeep, PROC_ADDRESS ("bngrw.dll", "BngRwReqBeep")) { return 1; } -HOOK (u64, bngrw_ReqAction, PROC_ADDRESS ("bngrw.dll", "BngRwReqAction")) { return 1; } +HOOK (u64, bngrw_ReqLed, PROC_ADDRESS ("bngrw.dll", "BngRwReqLed"), u32 a1, u32 ledType, i64 a3, i64 a4) { return 1; } +HOOK (u64, bngrw_ReqBeep, PROC_ADDRESS ("bngrw.dll", "BngRwReqBeep"), u32 a1, u32 beepType, i64 a3, i64 a4) { return 1; } +HOOK (u64, bngrw_ReqAction, PROC_ADDRESS ("bngrw.dll", "BngRwReqAction"), u32 a1, u32 actionType, i64 a3, i64 a4) { return 1; } HOOK (u64, bngrw_SetLedPower, PROC_ADDRESS ("bngrw.dll", "BngRwSetLedPower")) { return 0; } HOOK (u64, bngrw_GetRetryCount, PROC_ADDRESS ("bngrw.dll", "BngRwGetTotalRetryCount")) { return 0; } HOOK (u64, bngrw_GetFwVersion, PROC_ADDRESS ("bngrw.dll", "BngRwGetFwVersion")) { return 0; } @@ -252,22 +277,28 @@ HOOK (i32, bngrw_ReqSendMail, PROC_ADDRESS ("bngrw.dll", "BngRwReqSendMailTo")) HOOK (i32, bngrw_ReqLatchID, PROC_ADDRESS ("bngrw.dll", "BngRwReqLatchID")) { return 1; } HOOK (u64, bngrw_ReqAiccAuth, PROC_ADDRESS ("bngrw.dll", "BngRwReqAiccAuth")) { return 1; } HOOK (u64, bngrw_DevReset, PROC_ADDRESS ("bngrw.dll", "BngRwDevReset")) { return 1; } -HOOK (u64, bngrw_Attach, PROC_ADDRESS ("bngrw.dll", "BngRwAttach"), i32 a1, char *a2, i32 a3, i32 a4, i32 (*callback) (i32, i32, i32 *), i32 *a6) { +HOOK (u64, bngrw_Attach, PROC_ADDRESS ("bngrw.dll", "BngRwAttach"), i32 a1, char *a2, i32 a3, i32 a4, callbackAttach callback, i32 *_attachData) { + LogMessage (LOG_LEVEL_DEBUG, "BngRwAttach"); // This is way too fucking jank attachCallback = callback; - attachData = a6; + attachData = _attachData; return 1; } -HOOK (u64, bngrw_ReqWaitTouch, PROC_ADDRESS ("bngrw.dll", "BngRwReqWaitTouch"), u32 a1, i32 a2, u32 a3, void (*callback) (i32, i32, u8[168], u64), - u64 a5) { - waitingForTouch = true; - touchCallback = callback; - touchData = a5; - for (auto plugin : plugins) { - FARPROC touchEvent = GetProcAddress (plugin, "WaitTouch"); - if (touchEvent) ((waitTouchEvent *)touchEvent) (callback, a5); +HOOK (u64, bngrw_ReqWaitTouch, PROC_ADDRESS ("bngrw.dll", "BngRwReqWaitTouch"), u32 a1, i32 a2, u32 a3, callbackTouch _callback, u64 _touchData) { + LogMessage (LOG_LEVEL_DEBUG, "BngRwReqWaitTouch"); + touchCallback = _callback; + if (emulateCardReader) { + waitingForTouch = true; + touchData = _touchData; + for (auto plugin : plugins) { + FARPROC touchEvent = GetProcAddress (plugin, "WaitTouch"); + if (touchEvent) ((waitTouchEvent *)touchEvent) (_callback, _touchData); + } + return 1; + } else { + // This is called when we use an original card reader and acceptInvalidCards is set to true + return originalbngrw_ReqWaitTouch.call (a1, a2, a3, InspectWaitTouch, _touchData); } - return 1; } void @@ -278,12 +309,11 @@ Init () { std::unique_ptr config_ptr (openConfig (configPath), toml_free); if (config_ptr) { toml_table_t *config = config_ptr.get (); - auto drum = openConfigSection (config, "drum"); - if (drum) drumWaitPeriod = readConfigInt (drum, "wait_period", drumWaitPeriod); - auto controller = openConfigSection (config, "controller"); + auto controller = openConfigSection (config, "controller"); if (controller) { - analogInput = readConfigBool (controller, "analog_input", analogInput); - if (analogInput) printf ("Using analog input mode. All the keyboard drum inputs have been disabled.\n"); + drumWaitPeriod = readConfigInt (controller, "wait_period", drumWaitPeriod); + analogInput = readConfigBool (controller, "analog_input", analogInput); + if (analogInput) LogMessage (LOG_LEVEL_WARN, "Using analog input mode. All the keyboard drum inputs have been disabled."); } } @@ -317,7 +347,7 @@ Init () { if (!emulateUsio && !std::filesystem::exists (std::filesystem::current_path () / "bnusio_original.dll")) { emulateUsio = true; - std::cerr << "[Init] bnusio_original.dll not found! usio emulation enabled" << std::endl; + LogMessage (LOG_LEVEL_ERROR, "bnusio_original.dll not found! usio emulation enabled"); } if (!emulateUsio) { @@ -367,7 +397,7 @@ Init () { INSTALL_HOOK_DIRECT (bnusio_DecService, bnusio_DecService_Original); INSTALL_HOOK_DIRECT (bnusio_ResetCoin, bnusio_ResetCoin_Original); - std::cout << "[Init] USIO emulation disabled" << std::endl; + LogMessage (LOG_LEVEL_WARN, "USIO emulation disabled"); } if (emulateCardReader) { @@ -393,7 +423,11 @@ Init () { INSTALL_HOOK (bngrw_Attach); INSTALL_HOOK (bngrw_DevReset); } else { - std::cout << "[Init] Card reader emulation disabled" << std::endl; + LogMessage (LOG_LEVEL_WARN, "Card reader emulation disabled"); + if (acceptInvalidCards) { + LogMessage (LOG_LEVEL_WARN, "Original reader will accept invalid cards!"); + INSTALL_HOOK (bngrw_ReqWaitTouch); + } } } @@ -422,48 +456,34 @@ Update () { if (IsButtonTapped (TEST)) testEnabled = !testEnabled; if (IsButtonTapped (EXIT)) ExitProcess (0); if (waitingForTouch) { - static u8 cardData[168] - = {0x01, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0x2E, 0x58, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x5C, 0x97, 0x44, 0xF0, 0x88, 0x04, 0x00, 0x43, 0x26, 0x2C, 0x33, 0x00, 0x04, - 0x06, 0x10, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x30, 0x30, - 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4E, 0x42, 0x47, 0x49, 0x43, 0x36, - 0x00, 0x00, 0xFA, 0xE9, 0x69, 0x00, 0xF6, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; bool hasInserted = false; - if (IsButtonTapped (CARD_INSERT_1)) { + if (IsButtonTapped (CARD_INSERT_1) || IsButtonTapped (CARD_INSERT_2)) { + bool p1 = IsButtonTapped (CARD_INSERT_1); + static u8 cardData[168] + = {0x01, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0x2E, 0x58, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x5C, 0x97, 0x44, 0xF0, 0x88, 0x04, 0x00, 0x43, 0x26, 0x2C, 0x33, 0x00, 0x04, + 0x06, 0x10, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4E, 0x42, 0x47, 0x49, 0x43, 0x36, + 0x00, 0x00, 0xFA, 0xE9, 0x69, 0x00, 0xF6, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + for (auto plugin : plugins) { - FARPROC insertEvent = GetProcAddress (plugin, "BeforeCard1Insert"); + FARPROC insertEvent = GetProcAddress (plugin, p1 ? "BeforeCard1Insert" : "BeforeCard2Insert"); if (insertEvent) ((event *)insertEvent) (); - } - for (auto plugin : plugins) { - FARPROC insertEvent = GetProcAddress (plugin, "Card1Insert"); + insertEvent = GetProcAddress (plugin, p1 ? "Card1Insert" : "Card2Insert"); if (insertEvent) { ((event *)insertEvent) (); hasInserted = true; + break; } } + if (!hasInserted) { - memcpy (cardData + 0x2C, chipId1, 33); - memcpy (cardData + 0x50, accessCode1, 21); - touchCallback (0, 0, cardData, touchData); - } - } else if (IsButtonTapped (CARD_INSERT_2)) { - for (auto plugin : plugins) { - FARPROC insertEvent = GetProcAddress (plugin, "BeforeCard2Insert"); - if (insertEvent) ((event *)insertEvent) (); - } - for (auto plugin : plugins) { - FARPROC insertEvent = GetProcAddress (plugin, "Card2Insert"); - if (insertEvent) { - ((event *)insertEvent) (); - hasInserted = true; - } - } - if (!hasInserted) { - memcpy (cardData + 0x2C, chipId2, 33); - memcpy (cardData + 0x50, accessCode2, 21); + LogMessage (LOG_LEVEL_INFO, "Inserting card for player %d: %s", p1 ? "1" : "2", p1 ? accessCode1 : accessCode2); + memcpy (cardData + 0x2C, p1 ? chipId1 : chipId2, 33); + memcpy (cardData + 0x50, p1 ? accessCode1 : accessCode2, 21); touchCallback (0, 0, cardData, touchData); } } @@ -486,5 +506,7 @@ Close () { FARPROC exitEvent = GetProcAddress (plugin, "Exit"); if (exitEvent) ((event *)exitEvent) (); } + + CleanupLogger (); } } // namespace bnusio diff --git a/src/dllmain.cpp b/src/dllmain.cpp index 2b31aa3..4628fd5 100644 --- a/src/dllmain.cpp +++ b/src/dllmain.cpp @@ -3,31 +3,36 @@ #include "helpers.h" #include "patches/patches.h" #include "poll.h" +#include "logger.h" GameVersion gameVersion = GameVersion::UNKNOWN; std::vector plugins; u64 song_data_size = 1024 * 1024 * 64; void *song_data; -std::string server = "127.0.0.1"; -std::string port = "54430"; -std::string chassisId = "284111080000"; -std::string shopId = "TAIKO ARCADE LOADER"; -std::string gameVerNum = "00.00"; -std::string countryCode = "JPN"; -char fullAddress[256] = {'\0'}; -char placeId[16] = {'\0'}; -char accessCode1[21] = "00000000000000000001"; -char accessCode2[21] = "00000000000000000002"; -char chipId1[33] = "00000000000000000000000000000001"; -char chipId2[33] = "00000000000000000000000000000002"; -bool windowed = false; -bool autoIme = false; -bool jpLayout = false; -bool useLayeredFs = false; -bool emulateUsio = true; -bool emulateCardReader = true; -bool emulateQr = true; +std::string server = "127.0.0.1"; +std::string port = "54430"; +std::string chassisId = "284111080000"; +std::string shopId = "TAIKO ARCADE LOADER"; +std::string gameVerNum = "00.00"; +std::string countryCode = "JPN"; +char fullAddress[256] = {'\0'}; +char placeId[16] = {'\0'}; +char accessCode1[21] = "00000000000000000001"; +char accessCode2[21] = "00000000000000000002"; +char chipId1[33] = "00000000000000000000000000000001"; +char chipId2[33] = "00000000000000000000000000000002"; +bool windowed = false; +bool autoIme = false; +bool jpLayout = false; +bool useLayeredFs = false; +bool emulateUsio = true; +bool emulateCardReader = true; +bool emulateQr = true; +bool acceptInvalidCards = false; + +std::string logLevelStr = "INFO"; +bool logToFile = true; HWND hGameWnd; HOOK (i32, ShowMouse, PROC_ADDRESS ("user32.dll", "ShowCursor"), bool) { return originalShowMouse.call (true); } @@ -120,6 +125,7 @@ GetGameVersion () { void CreateCard () { + LogMessage (LOG_LEVEL_INFO, "Creating card.ini"); const char hexCharacterTable[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; char buf[64] = {0}; srand (time (nullptr)); @@ -140,8 +146,12 @@ DllMain (HMODULE module, DWORD reason, LPVOID reserved) { // This is bad, dont do this // I/O in DllMain can easily cause a deadlock - std::string version = "auto"; - auto configPath = std::filesystem::current_path () / "config.toml"; + // Init logger for loading config + InitializeLogger (GetLogLevel (logLevelStr), logToFile); + LogMessage (LOG_LEVEL_INFO, "Loading config..."); + + std::string version = "auto"; + std::filesystem::path configPath = std::filesystem::current_path () / "config.toml"; std::unique_ptr config_ptr (openConfig (configPath), toml_free); if (config_ptr) { toml_table_t *config = config_ptr.get (); @@ -167,9 +177,10 @@ DllMain (HMODULE module, DWORD reason, LPVOID reserved) { if (patches) version = readConfigString (patches, "version", version); auto emulation = openConfigSection (config, "emulation"); if (emulation) { - emulateUsio = readConfigBool (emulation, "usio", emulateUsio); - emulateCardReader = readConfigBool (emulation, "card_reader", emulateCardReader); - emulateQr = readConfigBool (emulation, "qr", emulateQr); + emulateUsio = readConfigBool (emulation, "usio", emulateUsio); + emulateCardReader = readConfigBool (emulation, "card_reader", emulateCardReader); + acceptInvalidCards = readConfigBool (emulation, "accept_invalid", acceptInvalidCards); + emulateQr = readConfigBool (emulation, "qr", emulateQr); } auto graphics = openConfigSection (config, "graphics"); if (graphics) windowed = readConfigBool (graphics, "windowed", windowed); @@ -178,8 +189,18 @@ DllMain (HMODULE module, DWORD reason, LPVOID reserved) { autoIme = readConfigBool (keyboard, "auto_ime", autoIme); jpLayout = readConfigBool (keyboard, "jp_layout", jpLayout); } + + auto logging = openConfigSection (config, "logging"); + if (logging) { + logLevelStr = readConfigString (logging, "log_level", logLevelStr); + logToFile = readConfigBool (logging, "log_to_file", logToFile); + } } + // Update the logger with the level read from config file. + InitializeLogger (GetLogLevel (logLevelStr), logToFile); + LogMessage (LOG_LEVEL_INFO, "Application started."); + if (version == "auto") { GetGameVersion (); } else if (version == "JPN00") { @@ -191,9 +212,11 @@ DllMain (HMODULE module, DWORD reason, LPVOID reserved) { } else if (version == "CHN00") { gameVersion = GameVersion::CHN00; } else { + LogMessage (LOG_LEVEL_ERROR, "GameVersion is UNKNOWN!"); MessageBoxA (nullptr, "Unknown patch version", nullptr, MB_OK); ExitProcess (0); } + LogMessage (LOG_LEVEL_INFO, "GameVersion is %s", GameVersionToString (gameVersion)); auto pluginPath = std::filesystem::current_path () / "plugins"; @@ -201,13 +224,13 @@ DllMain (HMODULE module, DWORD reason, LPVOID reserved) { for (const auto &entry : std::filesystem::directory_iterator (pluginPath)) { if (entry.path ().extension () == ".dll") { auto name = entry.path ().wstring (); + auto shortName = entry.path ().filename ().wstring (); HMODULE hModule = LoadLibraryW (name.c_str ()); if (!hModule) { - wchar_t buf[128]; - wsprintfW (buf, L"Failed to load plugin %ls", name.c_str ()); - MessageBoxW (0, buf, name.c_str (), MB_ICONERROR); + LogMessage (LOG_LEVEL_ERROR, L"Failed to load plugin " + shortName); } else { plugins.push_back (hModule); + LogMessage (LOG_LEVEL_INFO, L"Loaded plugin " + shortName); } } } diff --git a/src/helpers.cpp b/src/helpers.cpp index 14b4edc..c9144f3 100644 --- a/src/helpers.cpp +++ b/src/helpers.cpp @@ -1,8 +1,6 @@ #include "helpers.h" #include -void *consoleHandle = 0; - static void toml_myfree (void *p) { if (p) { @@ -14,13 +12,13 @@ toml_myfree (void *p) { toml_table_t * openConfig (std::filesystem::path path) { if (!std::filesystem::exists (path) || !path.has_filename ()) { - printWarning ("%s (%s): file does not exist\n", __func__, path.string ().c_str ()); + LogMessage (LOG_LEVEL_WARN, (std::string (path.string ()) + ": file does not exist").c_str ()); return 0; } std::ifstream stream (path); if (!stream.is_open ()) { - printWarning ("%s (%s): could not open\n", __func__, path.string ().c_str ()); + LogMessage (LOG_LEVEL_WARN, ("Could not open " + std::string (path.string ())).c_str ()); return 0; } @@ -37,7 +35,7 @@ openConfig (std::filesystem::path path) { free (buf); if (!config) { - printWarning ("%s (%s): %s\n", __func__, path.string ().c_str (), errorbuf); + LogMessage (LOG_LEVEL_WARN, (path.string () + ": " + errorbuf).c_str ()); return 0; } @@ -48,7 +46,7 @@ toml_table_t * openConfigSection (toml_table_t *config, const std::string §ionName) { toml_table_t *section = toml_table_in (config, sectionName.c_str ()); if (!section) { - printWarning ("%s (%s): cannot find section\n", __func__, sectionName.c_str ()); + LogMessage (LOG_LEVEL_ERROR, ("Cannot find section " + sectionName).c_str ()); return 0; } @@ -58,33 +56,42 @@ openConfigSection (toml_table_t *config, const std::string §ionName) { bool readConfigBool (toml_table_t *table, const std::string &key, bool notFoundValue) { toml_datum_t data = toml_bool_in (table, key.c_str ()); - if (!data.ok) return notFoundValue; - + if (!data.ok) { + LogMessage (LOG_LEVEL_WARN, ("Could not find Boolean named " + key).c_str ()); + return notFoundValue; + } return (bool)data.u.b; } int64_t readConfigInt (toml_table_t *table, const std::string &key, int64_t notFoundValue) { toml_datum_t data = toml_int_in (table, key.c_str ()); - if (!data.ok) return notFoundValue; - + if (!data.ok) { + LogMessage (LOG_LEVEL_WARN, ("Could not find Int named " + key).c_str ()); + return notFoundValue; + } return data.u.i; } const std::string readConfigString (toml_table_t *table, const std::string &key, const std::string ¬FoundValue) { toml_datum_t data = toml_string_in (table, key.c_str ()); - if (!data.ok) return notFoundValue; + if (!data.ok) { + LogMessage (LOG_LEVEL_WARN, ("Could not find String named " + key).c_str ()); + return notFoundValue; + } std::string str = data.u.s; toml_myfree (data.u.s); - return str; } std::vector readConfigIntArray (toml_table_t *table, const std::string &key, std::vector notFoundValue) { toml_array_t *array = toml_array_in (table, key.c_str ()); - if (!array) return notFoundValue; + if (!array) { + LogMessage (LOG_LEVEL_WARN, ("Could not find int Array named " + key).c_str ()); + return notFoundValue; + } std::vector datas; for (int i = 0;; i++) { @@ -96,32 +103,17 @@ readConfigIntArray (toml_table_t *table, const std::string &key, std::vector > converter; + return converter.to_bytes (wstr); +} + +bool +AreAllBytesZero (const uint8_t *array, size_t offset, size_t length) { + for (size_t i = 0; i < length; ++i) + if (array[offset + i] != 0x00) return false; + return true; } \ No newline at end of file diff --git a/src/helpers.h b/src/helpers.h index a4095dd..95cbca0 100644 --- a/src/helpers.h +++ b/src/helpers.h @@ -10,6 +10,8 @@ #include #include #include +#include "constants.h" +#include "logger.h" typedef int8_t i8; typedef int16_t i16; @@ -59,8 +61,11 @@ const HMODULE MODULE_HANDLE = GetModuleHandle (nullptr); void *where##functionName = NULL; \ void implOf##functionName (SafetyHookContext &ctx) -#define INSTALL_HOOK(functionName) \ - { original##functionName = safetyhook::create_inline (where##functionName, implOf##functionName); } +#define INSTALL_HOOK(functionName) \ + { \ + LogMessage (LOG_LEVEL_DEBUG, (std::string ("Installing hook for ") + #functionName).c_str ()); \ + original##functionName = safetyhook::create_inline (where##functionName, implOf##functionName); \ + } #define INSTALL_HOOK_DYNAMIC(functionName, location) \ { \ @@ -68,8 +73,11 @@ const HMODULE MODULE_HANDLE = GetModuleHandle (nullptr); INSTALL_HOOK (functionName); \ } -#define INSTALL_HOOK_DIRECT(location, locationOfHook) \ - { directHooks.push_back (safetyhook::create_inline ((void *)location, (void *)locationOfHook)); } +#define INSTALL_HOOK_DIRECT(location, locationOfHook) \ + { \ + LogMessage (LOG_LEVEL_DEBUG, (std::string ("Installing direct hook for ") + #location).c_str ()); \ + directHooks.push_back (safetyhook::create_inline ((void *)location, (void *)locationOfHook)); \ + } #define INSTALL_VTABLE_HOOK(className, object, functionName, functionIndex) \ { \ @@ -77,8 +85,11 @@ const HMODULE MODULE_HANDLE = GetModuleHandle (nullptr); INSTALL_HOOK (className##functionName); \ } -#define INSTALL_MID_HOOK(functionName) \ - { midHook##functionName = safetyhook::create_mid (where##functionName, implOf##functionName); } +#define INSTALL_MID_HOOK(functionName) \ + { \ + LogMessage (LOG_LEVEL_DEBUG, (std::string ("Installing mid hook for ") + #functionName).c_str ()); \ + midHook##functionName = safetyhook::create_mid (where##functionName, implOf##functionName); \ + } #define INSTALL_MID_HOOK_DYNAMIC(functionName, location) \ { \ @@ -86,6 +97,50 @@ const HMODULE MODULE_HANDLE = GetModuleHandle (nullptr); INSTALL_MID_HOOK (functionName); \ } +bool sendFlag = false; +#define SCENE_RESULT_HOOK(functionName, location) \ + HOOK (void, functionName, location, i64 a1, i64 a2, i64 a3) { \ + if (TestMode::ReadTestModeValue (L"ModInstantResult") != 1 && TestMode::ReadTestModeValue (L"NumberOfStageItem") <= 4) { \ + original##functionName.call (a1, a2, a3); \ + return; \ + } \ + sendFlag = true; \ + original##functionName.call (a1, a2, a3); \ + ExecuteSendResultData (); \ + } + +#define SEND_RESULT_HOOK(functionName, location) \ + HOOK (void, functionName, location, i64 a1) { \ + if (TestMode::ReadTestModeValue (L"ModInstantResult") != 1 && TestMode::ReadTestModeValue (L"NumberOfStageItem") <= 4) { \ + original##functionName.call (a1); \ + return; \ + } \ + if (sendFlag) { \ + sendFlag = false; \ + original##functionName.call (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, ...) \ @@ -124,14 +179,7 @@ const HMODULE MODULE_HANDLE = GetModuleHandle (nullptr); } #define COUNTOFARR(arr) sizeof (arr) / sizeof (arr[0]) - -#define INFO_COLOUR FOREGROUND_GREEN -#define WARNING_COLOUR (FOREGROUND_RED | FOREGROUND_GREEN) -#define ERROR_COLOUR FOREGROUND_RED -#define printInfo(format, ...) printColour (INFO_COLOUR, format, __VA_ARGS__) -#define printWarning(format, ...) printColour (WARNING_COLOUR, format, __VA_ARGS__) -#define printError(format, ...) printColour (ERROR_COLOUR, format, __VA_ARGS__) -#define round(num) ((num > 0) ? (int)(num + 0.5) : (int)(num - 0.5)) +#define round(num) ((num > 0) ? (int)(num + 0.5) : (int)(num - 0.5)) toml_table_t *openConfig (std::filesystem::path path); toml_table_t *openConfigSection (toml_table_t *config, const std::string §ionName); @@ -139,7 +187,10 @@ bool readConfigBool (toml_table_t *table, const std::string &key, bool notFoundV int64_t readConfigInt (toml_table_t *table, const std::string &key, int64_t notFoundValue); const std::string readConfigString (toml_table_t *table, const std::string &key, const std::string ¬FoundValue); std::vector readConfigIntArray (toml_table_t *table, const std::string &key, std::vector notFoundValue); -void printColour (int colour, const char *format, ...); std::wstring replace (const std::wstring orignStr, const std::wstring oldStr, const std::wstring newStr); std::string replace (const std::string orignStr, const std::string oldStr, const std::string newStr); -std::vector directHooks = {}; \ No newline at end of file +std::vector directHooks = {}; +const char *GameVersionToString (GameVersion version); +const char *languageStr (int language); +std::string ConvertWideToUtf8 (const std::wstring &wstr); +bool AreAllBytesZero (const uint8_t *array, size_t offset, size_t length); diff --git a/src/logger.cpp b/src/logger.cpp new file mode 100644 index 0000000..4087b57 --- /dev/null +++ b/src/logger.cpp @@ -0,0 +1,111 @@ +/* +// Copyright (c) 2019 Onur Dundar +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +*/ + +#include "logger.h" +#include "helpers.h" +#include +#include +#include + +static Logger *loggerInstance = NULL; +void *consoleHandle = 0; +std::mutex logMutex; // Mutex for thread-safe logging + +char timeStr[64]; +time_t rawtime; +struct tm *timeinfo; +SYSTEMTIME systemTime; + +void +InitializeLogger (LogLevel level, bool logToFile) { + if (loggerInstance == nullptr) { + loggerInstance = (Logger *)malloc (sizeof (Logger)); + if (consoleHandle == 0) consoleHandle = GetStdHandle (STD_OUTPUT_HANDLE); + } + + loggerInstance->logLevel = level; + + if (logToFile) { + loggerInstance->logFile = fopen ("TaikoArcadeLoader.log", "w"); // Open in write mode + if (!loggerInstance->logFile) LogMessage (LOG_LEVEL_WARN, "Failed to open TaikoArcadeLoader.log for writing."); + } else loggerInstance->logFile = nullptr; // No file logging +} + +void +LogMessageHandler (const char *function, const char *codeFile, int codeLine, LogLevel messageLevel, const std::string format, ...) { + // Return if no logger or log level is too high + if (loggerInstance == nullptr || messageLevel > loggerInstance->logLevel) return; + + // Lock for thread safety + std::lock_guard lock (logMutex); + + // Format the user-provided message + va_list args; + va_start (args, format); + int requiredSize = vsnprintf (nullptr, 0, format.c_str (), args) + 1; // +1 for null terminator + std::unique_ptr buffer (new char[requiredSize]); // Allocate buffer dynamically + vsnprintf (buffer.get (), requiredSize, format.c_str (), args); // Format the string + std::string formattedMessage (buffer.get ()); // Convert to std::string + va_end (args); + + // Determine log type string + std::string logType = GetLogLevelString (messageLevel); + + // Get current time and milliseconds + SYSTEMTIME systemTime; + GetSystemTime (&systemTime); + time_t rawtime = time (nullptr); + struct tm *timeinfo = localtime (&rawtime); + std::ostringstream timeStamp; + timeStamp << std::put_time (timeinfo, "%Y/%m/%d %H:%M:%S") << "." << std::setw (3) << std::setfill ('0') << systemTime.wMilliseconds; + + // Construct the log message + std::ostringstream logStream; + logStream << function << " (" << codeFile << ":" << codeLine << "): " << formattedMessage; + std::string logMessage = logStream.str (); + + // Print the log message + std::cout << "[" << timeStamp.str () << "] "; // Timestamp + SetConsoleTextAttribute (consoleHandle, GetLogLevelColor (messageLevel)); // Set Level color + std::cout << logType; // Level + SetConsoleTextAttribute (consoleHandle, 4 | 6 | 7 | 9 | 10 | 13); // Reset console color + std::cout << logMessage << std::endl; // Log message + std::cout.flush (); // Flush to ensure immediate writing + + if (loggerInstance->logFile) { + fprintf (loggerInstance->logFile, "[%s] %s%s\n", timeStamp.str ().c_str (), logType.c_str (), logMessage.c_str ()); + fflush (loggerInstance->logFile); // Flush to ensure immediate writing + } +} + +void +LogMessageHandler (const char *function, const char *codeFile, int codeLine, LogLevel messageLevel, const std::wstring format, ...) { + std::string utf8Message = ConvertWideToUtf8 (format); // Convert wide string to UTF-8 + + va_list args; + va_start (args, format); + LogMessageHandler (function, codeFile, codeLine, messageLevel, utf8Message, args); // Delegate to the original handler + va_end (args); +} + +void +CleanupLogger () { + if (loggerInstance != NULL) { + if (loggerInstance->logFile) fclose (loggerInstance->logFile); + free (loggerInstance); + loggerInstance = NULL; + } +} diff --git a/src/logger.h b/src/logger.h new file mode 100644 index 0000000..544bc13 --- /dev/null +++ b/src/logger.h @@ -0,0 +1,65 @@ +#ifndef LOGGER_H +#define LOGGER_H + +#include +#include + +typedef enum { LOG_LEVEL_NONE = 0, LOG_LEVEL_ERROR = 1, LOG_LEVEL_WARN = 2, LOG_LEVEL_INFO = 3, LOG_LEVEL_DEBUG = 4, LOG_LEVEL_HOOKS = 5 } LogLevel; + +/** + * Logger Struct Used to Store Logging Preferences and State + */ +typedef struct { + LogLevel logLevel; + FILE *logFile; +} Logger; + +/* Initializes a global Logger instance. */ +void InitializeLogger (LogLevel level, bool logToFile); + +/* Logs a message with file and line information, if the log level permits. */ +#define LogMessage(level, format, ...) LogMessageHandler (__FUNCTION__, __FILE__, __LINE__, level, format, ##__VA_ARGS__) +void LogMessageHandler (const char *function, const char *codeFile, int codeLine, LogLevel messageLevel, const std::string format, ...); +void LogMessageHandler (const char *function, const char *codeFile, int codeLine, LogLevel messageLevel, const std::wstring format, ...); + +/* Converts a string to a LogLevel type. */ +LogLevel +GetLogLevel (const std::string &logLevelStr) { + if (logLevelStr == "DEBUG") return LOG_LEVEL_DEBUG; + else if (logLevelStr == "INFO") return LOG_LEVEL_INFO; + else if (logLevelStr == "WARN") return LOG_LEVEL_WARN; + else if (logLevelStr == "ERROR") return LOG_LEVEL_ERROR; + else if (logLevelStr == "HOOKS") return LOG_LEVEL_HOOKS; + return LOG_LEVEL_NONE; +} + +/* Converts a LogLevel type to a string for logging. */ +std::string +GetLogLevelString (LogLevel messageLevel) { + switch (messageLevel) { + case LOG_LEVEL_DEBUG: return "DEBUG: "; + case LOG_LEVEL_INFO: return "INFO: "; + case LOG_LEVEL_WARN: return "WARN: "; + case LOG_LEVEL_ERROR: return "ERROR: "; + case LOG_LEVEL_HOOKS: return "HOOKS: "; + default: return "NONE: "; + } +} + +int +GetLogLevelColor (LogLevel messageLevel) { + // Colors: https://i.sstatic.net/ZG625.png + switch (messageLevel) { + case LOG_LEVEL_DEBUG: return 9; // Pale Blue + case LOG_LEVEL_INFO: return 10; // Pale Green + case LOG_LEVEL_WARN: return 6; // Bright Yellow + case LOG_LEVEL_ERROR: return 4; // Bright RED + case LOG_LEVEL_HOOKS: return 13; // Pale Purple + default: return 7; + } +} + +/* Cleans up the logger, closing files if necessary. */ +void CleanupLogger (); + +#endif /* LOGGER_H */ \ No newline at end of file diff --git a/src/patches/amauth.cpp b/src/patches/amauth.cpp index 12b9bd0..9463ccc 100644 --- a/src/patches/amauth.cpp +++ b/src/patches/amauth.cpp @@ -290,38 +290,19 @@ public: return this->refCount; } - virtual int64_t Unk3 (uint32_t a1) { - // printf ("Unk3 called\n"); - return 1; - } + virtual int64_t Unk3 (uint32_t a1) { return 1; } - virtual int64_t Unk4 () { - // printf ("Unk4 called\n"); - return 1; - } + virtual int64_t Unk4 () { return 1; } - virtual int32_t Unk5 () { - // printf ("Unk5 called\n"); - return 0; - } + virtual int32_t Unk5 () { return 0; } - virtual int64_t Unk6 () { - // printf ("Unk6 called\n"); - return 1; - } + virtual int64_t Unk6 () { return 1; } - virtual int32_t Unk7 () { - // printf ("Unk7 called\n"); - return 0; - } + virtual int32_t Unk7 () { return 0; } - virtual int32_t Unk8 () { - // printf ("Unk8 called\n"); - return 0; - } + virtual int32_t Unk8 () { return 0; } virtual int32_t IAuth_GetUpdaterState (amcus_state_t *arr) { - // printf("IAuth_GetUpdaterState called\n"); memset (arr, 0, sizeof (*arr)); // Convert gameVerNum from string to double double ver_d = std::stod (gameVerNum.c_str ()); @@ -378,7 +359,6 @@ public: } virtual int32_t IAuth_GetCabinetConfig (amcus_network_state_t *state) { - // printf("IAuth_GetCabinetConfig called\n"); memset (state, 0, sizeof (*state)); strcpy_s (state->mode, "STANDALONE"); strcpy_s (state->pcbid, "ABLN1080001"); @@ -400,7 +380,6 @@ public: } virtual int32_t IAuth_GetVersionInfo (amcus_version_info_t *version) { - // printf("IAuth_GetVersionInfo called\n"); memset (version, 0, sizeof (*version)); strcpy_s (version->game_rev, "1"); strcpy_s (version->auth_type, "ALL.NET"); @@ -414,18 +393,11 @@ public: return 0; } - virtual int32_t Unk12 () { - // printf ("Unk12 called\n"); - return 1; - } + virtual int32_t Unk12 () { return 1; } - virtual int32_t Unk13 () { - // printf ("Unk13 called\n"); - return 1; - } + virtual int32_t Unk13 () { return 1; } virtual int32_t IAuth_GetAuthServerResp (amcus_auth_server_resp_t *resp) { - // printf("IAuth_GetAuthServerResp called\n"); memset (resp, 0, sizeof (*resp)); strcpy_s (resp->uri, fullAddress); strcpy_s (resp->host, fullAddress); @@ -447,24 +419,13 @@ public: return 0; } - virtual int32_t Unk15 () { - // printf ("Unk15 called\n"); - return 0; - } + virtual int32_t Unk15 () { return 0; } - virtual int32_t Unk16 () { - // printf ("Unk16 called\n"); - return 0; - } + virtual int32_t Unk16 () { return 0; } - virtual int32_t Unk17 () { - // printf ("Unk17 called\n"); - return 0; - } + virtual int32_t Unk17 () { return 0; } virtual int32_t IAuth_GetMuchaAuthResponse (mucha_boardauth_resp_t *arr) { - // printf("IAuth_GetMuchaAuthResponse called\n"); - memset (arr, 0, sizeof (*arr)); strcpy_s (arr->shop_name, sizeof (arr->shop_name), shopId.c_str ()); strcpy_s (arr->shop_name_en, sizeof (arr->shop_name_en), shopId.c_str ()); @@ -500,80 +461,38 @@ public: } virtual int32_t Unk19 (uint8_t *a1) { - // printf("Unk19 called\n"); memset (a1, 0, 0x38); a1[0] = 1; return 1; } - virtual int32_t Unk20 () { - // printf ("Unk20 called\n"); - return 0; - } + virtual int32_t Unk20 () { return 0; } - virtual int32_t Unk21 () { - // printf ("Unk21 called\n"); - return 1; - } + virtual int32_t Unk21 () { return 1; } - virtual int32_t Unk22 () { - // printf ("Unk22 called\n"); - return 0; - } + virtual int32_t Unk22 () { return 0; } - virtual int32_t Unk23 () { - // printf ("Unk23 called\n"); - return 0; - } + virtual int32_t Unk23 () { return 0; } - virtual int32_t Unk24 () { - // printf ("Unk24 called\n"); - return 0; - } + virtual int32_t Unk24 () { return 0; } - virtual int32_t Unk25 () { - // printf ("Unk25 called\n"); - return 1; - } + virtual int32_t Unk25 () { return 1; } - virtual int32_t Unk26 () { - // printf ("Unk26 called\n"); - return 0; - } + virtual int32_t Unk26 () { return 0; } - virtual int32_t Unk27 () { - // printf ("Unk27 called\n"); - return 1; - } + virtual int32_t Unk27 () { return 1; } - virtual int32_t Unk28 () { - // printf ("Unk28 called\n"); - return 0; - } + virtual int32_t Unk28 () { return 0; } - virtual int32_t Unk29 () { - // printf ("Unk29 called\n"); - return 0; - } + virtual int32_t Unk29 () { return 0; } - virtual int32_t Unk30 () { - // printf ("Unk30 called\n"); - return 0; - } + virtual int32_t Unk30 () { return 0; } - virtual int32_t PrintDebugInfo () { - // printf ("Unk31 called\n"); - return 0; - } + virtual int32_t PrintDebugInfo () { return 0; } - virtual int32_t Unk32 (void *a1) { - // printf ("Unk32 called\n"); - return 0; - } + virtual int32_t Unk32 (void *a1) { return 0; } - virtual void Unk33 () { - // printf ("Unk33 called\n"); - } + virtual void Unk33 () {} public: CAuth () {} @@ -639,6 +558,8 @@ CoCreateInstanceHook (const IID *const rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsC void Init () { + LogMessage (LOG_LEVEL_DEBUG, "Init AmAuth patches"); + g_origCoCreateInstance = safetyhook::create_inline (PROC_ADDRESS ("ole32.dll", "CoCreateInstance"), CoCreateInstanceHook); struct addrinfo *res = 0; diff --git a/src/patches/audio.cpp b/src/patches/audio.cpp index 445d3d1..33b4bb9 100644 --- a/src/patches/audio.cpp +++ b/src/patches/audio.cpp @@ -23,6 +23,8 @@ bool asio = false; std::string asioDriver = ""; HOOK_DYNAMIC (i64, NUSCDeviceInit, void *a1, nusc_init_config_t *a2, nusc_init_config_t *a3, void *a4) { + LogMessage (LOG_LEVEL_INFO, (std::string ("Device mode is ") + (asio ? "ASIO" : (wasapiShared ? "wasapi shared" : "wasapi exclusive"))).c_str ()); + if (asio) LogMessage (LOG_LEVEL_INFO, (std::string ("ASIO driver is ") + asioDriver).c_str ()); a2->device_mode = asio; a2->asio_driver_name = asio ? asioDriver.c_str () : ""; a2->wasapi_exclusive = asio ? 1 : wasapiShared ? 0 : 1; @@ -31,6 +33,7 @@ HOOK_DYNAMIC (i64, NUSCDeviceInit, void *a1, nusc_init_config_t *a2, nusc_init_c HOOK_DYNAMIC (bool, LoadASIODriver, void *a1, const char *a2) { auto result = originalLoadASIODriver.call (a1, a2); if (!result) { + LogMessage (LOG_LEVEL_ERROR, (std::string ("Failed to load ASIO driver ") + asioDriver).c_str ()); MessageBoxA (nullptr, "Failed to load ASIO driver", nullptr, MB_OK); ExitProcess (0); } @@ -39,6 +42,8 @@ HOOK_DYNAMIC (bool, LoadASIODriver, void *a1, const char *a2) { void Init () { + LogMessage (LOG_LEVEL_DEBUG, "Init Audio patches"); + auto configPath = std::filesystem::current_path () / "config.toml"; std::unique_ptr config_ptr (openConfig (configPath), toml_free); if (config_ptr) { diff --git a/src/patches/dxgi.cpp b/src/patches/dxgi.cpp index 519f0fc..e3927df 100644 --- a/src/patches/dxgi.cpp +++ b/src/patches/dxgi.cpp @@ -198,6 +198,7 @@ D3D11CreateDeviceAndSwapChainWrap (IDXGIAdapter *pAdapter, D3D_DRIVER_TYPE Drive void Init () { + LogMessage (LOG_LEVEL_DEBUG, "Init Dxgi patches"); i32 fpsLimit = 120; auto configPath = std::filesystem::current_path () / "config.toml"; diff --git a/src/patches/fpslimiter.cpp b/src/patches/fpslimiter.cpp index 1375fb9..0436e80 100644 --- a/src/patches/fpslimiter.cpp +++ b/src/patches/fpslimiter.cpp @@ -16,6 +16,7 @@ static u32 i = 0; void Init (float fpsLimit) { + if (fpsLimit > 0) LogMessage (LOG_LEVEL_DEBUG, "Init Fps Limiter"); targetFrameTime = 1000.0 / fpsLimit; } diff --git a/src/patches/layeredfs.cpp b/src/patches/layeredfs.cpp index e34dc10..923187e 100644 --- a/src/patches/layeredfs.cpp +++ b/src/patches/layeredfs.cpp @@ -3,22 +3,21 @@ #include bool useLayeredFs = false; -std::string datatableKey = "0000000000000000000000000000000000000000000000000000000000000000"; -std::string fumenKey = "0000000000000000000000000000000000000000000000000000000000000000"; + +std::string datatableKey = "3530304242323633353537423431384139353134383346433246464231354534"; +std::string fumenKey = "4434423946383537303842433443383030333843444132343339373531353830"; #define CRCPOLY 0x82F63B78 namespace patches::LayeredFs { class RegisteredHandler { public: - std::function handlerMethod; - RegisteredHandler (const std::function &handlerMethod) { - this->handlerMethod = handlerMethod; - } + std::function handlerMethod; + RegisteredHandler (const std::function &handlerMethod) { this->handlerMethod = handlerMethod; } }; std::vector beforeHandlers = {}; -std::vector afterHandlers = {}; +std::vector afterHandlers = {}; uint32_t CRC32C (uint32_t crc, const unsigned char *buf, size_t len) { @@ -161,12 +160,10 @@ EncryptFile (const std::string &input_file, const std::string &hex_key) { bool IsFumenEncrypted (const std::string &filename) { // Check if the filename ends with ".bin" - if (filename.size() < 4 || filename.substr(filename.size() - 4) != ".bin") { - std::cout << "Not a Fumen file: " << filename << std::endl; + if (filename.size () < 4 || filename.substr (filename.size () - 4) != ".bin") return true; // If it doesn't we return early, as the file we're seeing isn't a fumen ! - } - std::ifstream file(filename, std::ios::binary); + std::ifstream file (filename, std::ios::binary); file.seekg (0x214, std::ios::beg); std::vector buffer (24); file.read (reinterpret_cast (buffer.data ()), buffer.size ()); @@ -180,7 +177,7 @@ IsFumenEncrypted (const std::string &filename) { std::string LayeredFsHandler (const std::string originalFileName, const std::string currentFileName) { - std::filesystem::path path (originalFileName.c_str()); + std::filesystem::path path (originalFileName.c_str ()); if (!path.is_absolute ()) path = std::filesystem::absolute (path); auto originalDataFolder = std::filesystem::current_path ().parent_path ().parent_path () / "Data" / "x64"; auto originalLayeredFsFolder = std::filesystem::current_path ().parent_path ().parent_path () / "Data_mods" / "x64"; @@ -197,22 +194,24 @@ LayeredFsHandler (const std::string originalFileName, const std::string currentF if (std::filesystem::exists (newPath)) { // If a file exists in the datamod folder if (IsFumenEncrypted (newPath)) { // And if it's an encrypted fumen or a different type of file, use it. - std::cout << "Redirecting " << std::filesystem::relative (path).string () << std::endl; + LogMessage (LOG_LEVEL_DEBUG, ("Redirecting " + std::filesystem::relative (path).string ()).c_str ()); return newPath; } else { // Otherwise if it's an unencrypted fumen. if (!std::filesystem::exists (encPath)) { // We check if we don't already have a cached file. if (fumenKey.length () == 64) { - std::cout << "Encrypting " << std::filesystem::relative (newPath) << std::endl; // If we don't we encrypt the file + LogMessage (LOG_LEVEL_DEBUG, + ("Encrypting " + std::filesystem::relative (newPath).string ()).c_str ()); // If we don't we encrypt the file std::ifstream crc_file (newPath, std::ios::binary); std::vector crc_vector ((std::istreambuf_iterator (crc_file)), std::istreambuf_iterator ()); uint32_t crc = CRC32C (0, crc_vector.data (), crc_vector.size ()); WriteFile (encPath, EncryptFile (newPath, fumenKey), crc); // And we save it } else { - std::cout << "Missing or invalid fumen key: " << std::filesystem::relative (newPath) << " couldn't be encrypted." - << std::endl; + LogMessage ( + LOG_LEVEL_ERROR, + ("Missing or invalid fumen key: " + std::filesystem::relative (newPath).string () + " couldn't be encrypted.").c_str ()); encPath = path.string (); } - } else std::cout << "Using cached file for " << std::filesystem::relative (newPath) << std::endl; + } else LogMessage (LOG_LEVEL_DEBUG, ("Using cached file for: " + std::filesystem::relative (newPath).string ()).c_str ()); return encPath; } } @@ -232,58 +231,55 @@ LayeredFsHandler (const std::string originalFileName, const std::string currentF if (!std::filesystem::exists (encPath) || crcBool) { // And if it hasn't been encrypted before if (datatableKey.length () == 64) { - std::cout << "Encrypting " << std::filesystem::relative (json_path) << std::endl; // Encrypt the file + // Encrypt the file + LogMessage (LOG_LEVEL_DEBUG, ("Encrypting " + std::filesystem::relative (json_path).string ()).c_str ()); std::ifstream crc_file (json_path.string (), std::ios::binary); std::vector crc_vector ((std::istreambuf_iterator (crc_file)), std::istreambuf_iterator ()); uint32_t crc = CRC32C (0, crc_vector.data (), crc_vector.size ()); WriteFile (encPath, EncryptFile (json_path.string (), datatableKey), crc); // And save it } else { - std::cout << "Missing or invalid datatable key: " << std::filesystem::relative (newPath) << " couldn't be encrypted." - << std::endl; + LogMessage ( + LOG_LEVEL_ERROR, + ("Missing or invalid datatable key: " + std::filesystem::relative (newPath).string () + " couldn't be encrypted.").c_str ()); encPath = path.string (); } } else - std::cout << "Using cached file for " << std::filesystem::relative (json_path) - << std::endl; // Otherwise use the already encrypted file. + // Otherwise use the already encrypted file. + LogMessage (LOG_LEVEL_DEBUG, ("Using cached file for: " + std::filesystem::relative (json_path).string ()).c_str ()); return encPath; } } - return ""; + return ""; // we return an empty string, causing the rest of CreateFileAHook to not update the returned value } -HOOK ( - HANDLE, CreateFileAHook, PROC_ADDRESS ("kernel32.dll", "CreateFileA"), - LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, - DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile -) { - // std::wcout << "CreateFileA: file " << lpFileName << std::endl; - std::string originalFileName = std::string(lpFileName); - std::string currentFileName = originalFileName; +HOOK (HANDLE, CreateFileAHook, PROC_ADDRESS ("kernel32.dll", "CreateFileA"), LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, + LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) { + std::string originalFileName = std::string (lpFileName); + std::string currentFileName = originalFileName; + LogMessage (LOG_LEVEL_HOOKS, ("CreateFileA: " + originalFileName).c_str ()); - if (!beforeHandlers.empty()) { + if (!beforeHandlers.empty ()) { for (auto handler : beforeHandlers) { - std::string result = handler->handlerMethod(originalFileName, currentFileName); + std::string result = handler->handlerMethod (originalFileName, currentFileName); if (result != "") currentFileName = result; } } if (useLayeredFs) { - std::string result = LayeredFsHandler(originalFileName, currentFileName); + std::string result = LayeredFsHandler (originalFileName, currentFileName); if (result != "") currentFileName = result; - } + } - if (!afterHandlers.empty()) { + if (!afterHandlers.empty ()) { for (auto handler : afterHandlers) { - std::string result = handler->handlerMethod(originalFileName, currentFileName); + std::string result = handler->handlerMethod (originalFileName, currentFileName); if (result != "") currentFileName = result; } } - return originalCreateFileAHook.call ( - currentFileName.c_str(), dwDesiredAccess, dwShareMode, lpSecurityAttributes, - dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile - ); + return originalCreateFileAHook.call (currentFileName.c_str (), dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, + dwFlagsAndAttributes, hTemplateFile); } // HOOK (HANDLE, CreateFileWHook, PROC_ADDRESS ("kernel32.dll", "CreateFileW"), LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, @@ -315,34 +311,27 @@ HOOK ( void Init () { + LogMessage (LOG_LEVEL_DEBUG, "Init LayeredFs patches"); + auto configPath = std::filesystem::current_path () / "config.toml"; std::unique_ptr config_ptr (openConfig (configPath), toml_free); if (config_ptr) { - auto layeredFs = openConfigSection (config_ptr.get(), "layeredfs"); - if (layeredFs) { - useLayeredFs = readConfigBool (layeredFs, "enabled", useLayeredFs); - datatableKey = readConfigString (layeredFs, "datatable_key", datatableKey); - fumenKey = readConfigString (layeredFs, "fumen_key", fumenKey); - } + auto layeredFs = openConfigSection (config_ptr.get (), "layeredfs"); + if (layeredFs) useLayeredFs = readConfigBool (layeredFs, "enabled", useLayeredFs); } - - if (useLayeredFs) { - std::wcout << "Using LayeredFs!" << std::endl; - } - register_cipher (&aes_desc); INSTALL_HOOK (CreateFileAHook); // INSTALL_HOOK (CreateFileWHook); } void -RegisterBefore (const std::function &fileHandler) { - beforeHandlers.push_back (new RegisteredHandler(fileHandler)); +RegisterBefore (const std::function &fileHandler) { + beforeHandlers.push_back (new RegisteredHandler (fileHandler)); } void -RegisterAfter (const std::function &fileHandler) { - afterHandlers.push_back (new RegisteredHandler(fileHandler)); +RegisterAfter (const std::function &fileHandler) { + afterHandlers.push_back (new RegisteredHandler (fileHandler)); } } // namespace patches::LayeredFs diff --git a/src/patches/patches.h b/src/patches/patches.h index 6c9c27c..90300fb 100644 --- a/src/patches/patches.h +++ b/src/patches/patches.h @@ -35,16 +35,16 @@ void Init (); } // namespace AmAuth namespace LayeredFs { void Init (); -void RegisterBefore (const std::function &fileHandler); -void RegisterAfter (const std::function &fileHandler); +void RegisterBefore (const std::function &fileHandler); +void RegisterAfter (const std::function &fileHandler); } // namespace LayeredFs namespace TestMode { -typedef u64 (*RefTestModeMain)(u64); +typedef u64 (*RefTestModeMain) (u64); void Init (); void SetupAccessor (u64 appAccessor, RefTestModeMain refTestMode); -int ReadTestModeValue (const wchar_t* itemId); -void RegisterItem (const std::wstring item, const std::function &initMethod); -void RegisterModify (const std::wstring query, const std::function &nodeModify, const std::function &initMethod); +int ReadTestModeValue (const wchar_t *itemId); +void RegisterItem (const std::wstring item, const std::function &initMethod); +void RegisterModify (const std::wstring query, const std::function &nodeModify, const std::function &initMethod); void Append (pugi::xml_node &node, const wchar_t *attr, const std::wstring append); } // namespace TestMode } // namespace patches diff --git a/src/patches/qr.cpp b/src/patches/qr.cpp index 81b1435..58c6cf8 100644 --- a/src/patches/qr.cpp +++ b/src/patches/qr.cpp @@ -62,8 +62,7 @@ HOOK_DYNAMIC (bool, Send3, i64, char) { return true; } HOOK_DYNAMIC (bool, Send4, i64, const void *, i64) { return true; } HOOK_DYNAMIC (i64, CopyData, i64, void *dest, int length) { if (gState == State::CopyWait) { - std::cout << "Copy data, length: " << length << std::endl; - + // std::cout << "Copy data, length: " << length << std::endl; auto configPath = std::filesystem::current_path () / "config.toml"; std::unique_ptr config_ptr (openConfig (configPath), toml_free); @@ -114,9 +113,10 @@ HOOK_DYNAMIC (i64, CopyData, i64, void *dest, int length) { byteBuffer.push_back (0xEE); byteBuffer.push_back (0xFF); + std::stringstream hexStream; for (auto byteData : byteBuffer) - std::cout << std::hex << std::uppercase << std::setfill ('0') << std::setw (2) << static_cast (byteData) << " "; - std::cout << std::endl; + hexStream << std::hex << std::uppercase << std::setfill ('0') << std::setw (2) << static_cast (byteData) << " "; + LogMessage (LOG_LEVEL_INFO, ("Data dump: " + hexStream.str ()).c_str ()); memcpy (dest, byteBuffer.data (), byteBuffer.size ()); gState = State::Ready; @@ -132,8 +132,7 @@ HOOK_DYNAMIC (i64, CopyData, i64, void *dest, int length) { std::u8string u8PathStr (imagePath.begin (), imagePath.end ()); std::filesystem::path u8Path (u8PathStr); if (!std::filesystem::is_regular_file (u8Path)) { - std::cerr << "Failed to open image: " << u8Path.string () << " (file not found)" - << "\n"; + LogMessage (LOG_LEVEL_ERROR, ("Failed to open image: " + u8Path.string () + " (file not found)").c_str ()); gState = State::Ready; return 0; } @@ -142,8 +141,7 @@ HOOK_DYNAMIC (i64, CopyData, i64, void *dest, int length) { std::unique_ptr buffer (stbi_load (u8Path.string ().c_str (), &width, &height, &channels, 3), stbi_image_free); if (!buffer) { - std::cerr << "Failed to read image: " << u8Path << " (" << stbi_failure_reason () << ")" - << "\n"; + LogMessage (LOG_LEVEL_ERROR, ("Failed to read image: " + u8Path.string () + " (" + stbi_failure_reason () + ")").c_str ()); gState = State::Ready; return 0; } @@ -151,15 +149,14 @@ HOOK_DYNAMIC (i64, CopyData, i64, void *dest, int length) { ZXing::ImageView image{buffer.get (), width, height, ZXing::ImageFormat::RGB}; auto result = ReadBarcode (image); if (!result.isValid ()) { - std::cerr << "Failed to read QR: " << imagePath << " (" << ToString (result.error ()) << ")" - << "\n"; + LogMessage (LOG_LEVEL_ERROR, ("Failed to read QR: " + imagePath + " (" + ToString (result.error ()) + ")").c_str ()); gState = State::Ready; return 0; } - std::cout << "Valid" << std::endl; + // std::cout << "Valid" << std::endl; auto byteData = result.bytes (); - std::cout << ZXing::ToHex (byteData) << std::endl; + // std::cout << ZXing::ToHex (byteData) << std::endl; auto dataSize = byteData.size (); memcpy (dest, byteData.data (), dataSize); @@ -171,12 +168,13 @@ HOOK_DYNAMIC (i64, CopyData, i64, void *dest, int length) { unsigned char plugin_data[length]; int buf_len = ((getQrEvent *)getEvent) (length, plugin_data); if (0 < buf_len && buf_len <= length) { + std::stringstream hexStream; for (int i = 0; i < buf_len; i++) - std::cout << std::hex << std::uppercase << std::setfill ('0') << std::setw (2) << static_cast (plugin_data[i]) << " "; - std::cout << std::endl; + hexStream << std::hex << std::uppercase << std::setfill ('0') << std::setw (2) << static_cast (plugin_data[i]) << " "; + LogMessage (LOG_LEVEL_INFO, ("QR dump: " + hexStream.str ()).c_str ()); memcpy (dest, plugin_data, buf_len); } else { - std::cerr << "QR discard! Length invalid: " << buf_len << ", valid range: 0~" << length << std::endl; + LogMessage (LOG_LEVEL_ERROR, ("QR discard! Length invalid: " + std::to_string (buf_len) + ", valid range: 0~").c_str ()); } gState = State::Ready; return buf_len; @@ -198,35 +196,29 @@ void Update () { if (!emulateQr) return; if (gState == State::Ready) { + // std::cout << "Insert" << std::endl; if (IsButtonTapped (CARD_INSERT_1)) { if (gameVersion != GameVersion::CHN00) return; - - std::cout << "Insert" << std::endl; accessCode = "BNTTCNID"; accessCode += accessCode1; gState = State::CopyWait; gMode = Mode::Card; } else if (IsButtonTapped (CARD_INSERT_2)) { if (gameVersion != GameVersion::CHN00) return; - - std::cout << "Insert" << std::endl; accessCode = "BNTTCNID"; accessCode += accessCode2; gState = State::CopyWait; gMode = Mode::Card; } else if (IsButtonTapped (QR_DATA_READ)) { - std::cout << "Insert" << std::endl; gState = State::CopyWait; gMode = Mode::Data; } else if (IsButtonTapped (QR_IMAGE_READ)) { - std::cout << "Insert" << std::endl; gState = State::CopyWait; gMode = Mode::Image; } else if (qrPluginRegistered) { for (auto plugin : qrPlugins) { FARPROC checkEvent = GetProcAddress (plugin, "CheckQr"); if (checkEvent && ((checkQrEvent *)checkEvent) ()) { - std::cout << "Insert" << std::endl; gState = State::CopyWait; gMode = Mode::Plugin; gPlugin = plugin; @@ -239,8 +231,10 @@ Update () { void Init () { + LogMessage (LOG_LEVEL_DEBUG, "Init Qr patches"); + if (!emulateQr) { - std::cout << "[Init] QR emulation disabled" << std::endl; + LogMessage (LOG_LEVEL_WARN, "QR emulation disabled"); return; } @@ -252,7 +246,8 @@ Init () { if (usingQrEvent) qrPlugins.push_back (plugin); } if (qrPlugins.size () > 0) { - std::cout << "QR plugin found!" << std::endl; + + LogMessage (LOG_LEVEL_INFO, "QR plugin found!"); qrPluginRegistered = true; } diff --git a/src/patches/testmode.cpp b/src/patches/testmode.cpp index 493d5da..20f370c 100644 --- a/src/patches/testmode.cpp +++ b/src/patches/testmode.cpp @@ -11,281 +11,303 @@ namespace patches::TestMode { class RegisteredItem { public: std::wstring selectItem; - std::function registerInit; - RegisteredItem (const std::wstring selectItem, const std::function &initMethod) { - this->selectItem = selectItem; + std::function registerInit; + RegisteredItem (const std::wstring selectItem, const std::function &initMethod) { + this->selectItem = selectItem; this->registerInit = initMethod; } }; class RegisteredModify { public: std::wstring query; - std::function nodeModify; - std::function registerInit; - RegisteredModify (const std::wstring query, const std::function &nodeModify, const std::function &initMethod) { - this->query = query; - this->nodeModify = nodeModify; + std::function nodeModify; + std::function registerInit; + RegisteredModify (const std::wstring query, const std::function &nodeModify, const std::function &initMethod) { + this->query = query; + this->nodeModify = nodeModify; this->registerInit = initMethod; } }; -std::vector registeredItems = {}; +std::vector registeredItems = {}; std::vector registeredModifies = {}; -std::wstring moddedInitial = L""; -std::wstring modded = L""; +std::wstring moddedInitial = L""; +std::wstring modded = L""; -u64 appAccessor = 0; +u64 appAccessor = 0; RefTestModeMain refTestMode = nullptr; pugi::xml_document & CreateMenu (pugi::xml_document &menuMain, std::wstring menuId, std::wstring menuName, std::vector items, std::wstring backId) { + LogMessage (LOG_LEVEL_DEBUG, L"Create Menu " + menuName); std::wstring menuBasicLine = L""; - if (menuMain.load_string(menuBasicLine.c_str())) { - pugi::xml_node menu = menuMain.first_child (); - pugi::xml_node menuHeader = menu.append_child(L"layout"); - pugi::xml_node menuCenter = menu.append_child(L"layout"); - pugi::xml_node menuFooter = menu.append_child(L"layout"); + if (menuMain.load_string (menuBasicLine.c_str ())) { + pugi::xml_node menu = menuMain.first_child (); + pugi::xml_node menuHeader = menu.append_child (L"layout"); + pugi::xml_node menuCenter = menu.append_child (L"layout"); + pugi::xml_node menuFooter = menu.append_child (L"layout"); // Mod Manager Menu Header - menuHeader.append_attribute(L"type") = L"Header"; - menuHeader.append_child(L"break-item"); - pugi::xml_node menuTitle = menuHeader.append_child(L"text-item"); - std::wstring menuNameFull = L"   " + menuName; - menuTitle.append_attribute(L"label") = menuNameFull.c_str(); - menuHeader.append_child(L"break-item"); - menuHeader.append_child(L"break-item"); - pugi::xml_node menuTitleData = menuHeader.append_child(L"data-item"); - menuTitleData.append_attribute(L"data") = L"HeaderTextData"; - menuTitleData.append_attribute(L"param-offset-x") = L"-15"; - menuHeader.append_child(L"break-item"); + menuHeader.append_attribute (L"type") = L"Header"; + menuHeader.append_child (L"break-item"); + pugi::xml_node menuTitle = menuHeader.append_child (L"text-item"); + std::wstring menuNameFull = L" " + menuName; + menuTitle.append_attribute (L"label") = menuNameFull.c_str (); + menuHeader.append_child (L"break-item"); + menuHeader.append_child (L"break-item"); + pugi::xml_node menuTitleData = menuHeader.append_child (L"data-item"); + menuTitleData.append_attribute (L"data") = L"HeaderTextData"; + menuTitleData.append_attribute (L"param-offset-x") = L"-15"; + menuHeader.append_child (L"break-item"); // Mod Manager Menu Center - menuCenter.append_attribute(L"type") = L"Center"; - menuCenter.append_attribute(L"padding-x") = L"23"; + menuCenter.append_attribute (L"type") = L"Center"; + menuCenter.append_attribute (L"padding-x") = L"23"; for (std::wstring item : items) { pugi::xml_document menuItem; std::wstring itemLine = L"" + item + L""; - if (menuItem.load_string(itemLine.c_str())) { - menuCenter.append_copy(menuItem.first_child().first_child()); - } else { - std::wcerr << "[TestMode Error] failed to parse option line: " << item << std::endl; - } - menuCenter.append_child(L"break-item"); + if (menuItem.load_string (itemLine.c_str ())) menuCenter.append_copy (menuItem.first_child ().first_child ()); + else LogMessage (LOG_LEVEL_ERROR, L"Failed to parse option line: " + item); + menuCenter.append_child (L"break-item"); } - menuCenter.append_child(L"break-item"); - pugi::xml_node menuCenterExit = menuCenter.append_child(L"menu-item"); - menuCenterExit.append_attribute(L"label") = L"EXIT"; - menuCenterExit.append_attribute(L"menu") = backId.c_str(); + menuCenter.append_child (L"break-item"); + pugi::xml_node menuCenterExit = menuCenter.append_child (L"menu-item"); + menuCenterExit.append_attribute (L"label") = L"EXIT"; + menuCenterExit.append_attribute (L"menu") = backId.c_str (); // Mod Manager Menu Footer - menuFooter.append_attribute(L"type") = L"Footer"; - pugi::xml_node menuFooterData = menuFooter.append_child(L"data-item"); - menuFooterData.append_attribute(L"data") = L"FooterTextData"; - menuFooterData.append_attribute(L"param-offset-x") = L"-20"; + menuFooter.append_attribute (L"type") = L"Footer"; + pugi::xml_node menuFooterData = menuFooter.append_child (L"data-item"); + menuFooterData.append_attribute (L"data") = L"FooterTextData"; + menuFooterData.append_attribute (L"param-offset-x") = L"-20"; } return menuMain; } std::wstring ReadXMLFileSwitcher (std::wstring &fileName) { - std::size_t pos = fileName.rfind(L"/"); - std::wstring base = fileName.substr(0, pos + 1); - std::wstring file = fileName.substr(pos + 1, fileName.size()); + std::size_t pos = fileName.rfind (L"/"); + std::wstring base = fileName.substr (0, pos + 1); + std::wstring file = fileName.substr (pos + 1, fileName.size ()); if (gameVersion == GameVersion::JPN39 && chsPatch) { - if (file.starts_with (L"DeviceInitialize")) base.append(L"DeviceInitialize_china.xml"); - if (file.starts_with (L"TestMode")) base.append(L"TestMode_china.xml"); + if (file.starts_with (L"DeviceInitialize")) base.append (L"DeviceInitialize_china.xml"); + if (file.starts_with (L"TestMode")) base.append (L"TestMode_china.xml"); if (std::filesystem::exists (base)) return base; } return fileName; } -HOOK_DYNAMIC (void, TestModeSetMenuHook, u64 testModeLibrary, const wchar_t* lFileName) { - std::wstring originalFileName = std::wstring(lFileName); - std::wstring fileName = originalFileName; - if (fileName.ends_with (L"DeviceInitialize.xml") || fileName.ends_with (L"DeviceInitialize_asia.xml") || fileName.ends_with (L"DeviceInitialize_china.xml")) { +HOOK_DYNAMIC (void, TestModeSetMenuHook, u64 testModeLibrary, const wchar_t *lFileName) { + std::wstring originalFileName = std::wstring (lFileName); + std::wstring fileName = originalFileName; + if (fileName.ends_with (L"DeviceInitialize.xml") || fileName.ends_with (L"DeviceInitialize_asia.xml") + || fileName.ends_with (L"DeviceInitialize_china.xml")) { if (moddedInitial == L"") { fileName = ReadXMLFileSwitcher (fileName); pugi::xml_document doc; - if (!doc.load_file(fileName.c_str())) { - std::wcerr << "Loading DeviceInitialize structure failed! path: " << fileName << std::endl; + if (!doc.load_file (fileName.c_str ())) { + LogMessage (LOG_LEVEL_ERROR, L"Loading DeviceInitialize structure failed! path: " + fileName); moddedInitial = fileName; } else { - std::wstring modFileName = replace (replace (replace (fileName, L"lize_asia.xml", L"lize_mod.xml"), L"lize_china.xml", L"lize_mod.xml"), L"lize.xml", L"lize_mod.xml"); - pugi::xpath_query dongleQuery = pugi::xpath_query(L"/root/menu[@id='TopMenu']/layout[@type='Center']/select-item[@id='DongleItem']"); - pugi::xml_node dongleItem = doc.select_node(dongleQuery).node(); - pugi::xml_node talItem = dongleItem.parent().append_copy(dongleItem); - talItem.attribute(L"label").set_value(L"TAIKOARCADELOADER"); - talItem.attribute(L"id").set_value(L"TaikoArcadeLoader"); - talItem.append_attribute(L"default") = L"1"; - dongleItem.parent().append_child(L"break-item"); + std::wstring modFileName + = replace (replace (replace (fileName, L"lize_asia.xml", L"lize_mod.xml"), L"lize_china.xml", L"lize_mod.xml"), L"lize.xml", + L"lize_mod.xml"); + pugi::xpath_query dongleQuery = pugi::xpath_query (L"/root/menu[@id='TopMenu']/layout[@type='Center']/select-item[@id='DongleItem']"); + pugi::xml_node dongleItem = doc.select_node (dongleQuery).node (); + pugi::xml_node talItem = dongleItem.parent ().append_copy (dongleItem); + talItem.attribute (L"label").set_value (L"TAIKOARCADELOADER"); + talItem.attribute (L"id").set_value (L"TaikoArcadeLoader"); + talItem.append_attribute (L"default") = L"1"; + dongleItem.parent ().append_child (L"break-item"); - doc.save_file(modFileName.c_str()); + doc.save_file (modFileName.c_str ()); moddedInitial = modFileName; - fileName = modFileName; + fileName = modFileName; } } else fileName = moddedInitial; } else if (fileName.ends_with (L"TestMode.xml") || fileName.ends_with (L"TestMode_asia.xml") || fileName.ends_with (L"TestMode_china.xml")) { if (modded == L"") { - if (!registeredItems.empty() || !registeredModifies.empty()) { + if (!registeredItems.empty () || !registeredModifies.empty ()) { fileName = ReadXMLFileSwitcher (fileName); pugi::xml_document doc; - if (!doc.load_file(fileName.c_str())) { - std::wcerr << "Loading TestMode structure failed! path: " << fileName << std::endl; + if (!doc.load_file (fileName.c_str ())) { + LogMessage (LOG_LEVEL_ERROR, L"Loading TestMode structure failed! path: " + fileName); modded = fileName; } else { - std::wstring modFileName = replace (replace (replace (fileName, L"Mode_asia.xml", L"Mode_mod.xml"), L"Mode_china.xml", L"Mode_mod.xml"), L"Mode.xml", L"Mode_mod.xml"); - if (!registeredItems.empty()) { - pugi::xpath_query menuQuery = pugi::xpath_query(L"/root/menu[@id='TopMenu']/layout[@type='Center']/menu-item[@menu='GameOptionsMenu']"); - pugi::xml_node menuItem = doc.select_node(menuQuery).node(); - menuItem = menuItem.next_sibling(); - pugi::xml_node modMenuEntry = menuItem.parent().insert_child_after(L"menu-item", menuItem); - modMenuEntry.append_attribute(L"label") = L"MOD MANAGER"; - modMenuEntry.append_attribute(L"menu") = L"ModManagerMenu"; - menuItem.parent().insert_child_after(L"break-item", modMenuEntry); + std::wstring modFileName + = replace (replace (replace (fileName, L"Mode_asia.xml", L"Mode_mod.xml"), L"Mode_china.xml", L"Mode_mod.xml"), L"Mode.xml", + L"Mode_mod.xml"); + if (!registeredItems.empty ()) { + pugi::xpath_query menuQuery + = pugi::xpath_query (L"/root/menu[@id='TopMenu']/layout[@type='Center']/menu-item[@menu='GameOptionsMenu']"); + pugi::xml_node menuItem = doc.select_node (menuQuery).node (); + menuItem = menuItem.next_sibling (); + pugi::xml_node modMenuEntry = menuItem.parent ().insert_child_after (L"menu-item", menuItem); + modMenuEntry.append_attribute (L"label") = L"MOD MANAGER"; + modMenuEntry.append_attribute (L"menu") = L"ModManagerMenu"; + menuItem.parent ().insert_child_after (L"break-item", modMenuEntry); pugi::xml_document modMenu; std::vector toInsertItems = {}; for (RegisteredItem *item : registeredItems) { - toInsertItems.push_back(item->selectItem); - item->registerInit(); + toInsertItems.push_back (item->selectItem); + item->registerInit (); } - CreateMenu(modMenu, L"ModManagerMenu", L"MOD MANAGER", toInsertItems, L"TopMenu"); - pugi::xpath_query topMenuQuery = pugi::xpath_query(L"/root/menu[@id='TopMenu']"); - pugi::xml_node topMenu = doc.select_node(topMenuQuery).node(); - topMenu.parent().insert_copy_after(modMenu.first_child(), topMenu); + CreateMenu (modMenu, L"ModManagerMenu", L"MOD MANAGER", toInsertItems, L"TopMenu"); + pugi::xpath_query topMenuQuery = pugi::xpath_query (L"/root/menu[@id='TopMenu']"); + pugi::xml_node topMenu = doc.select_node (topMenuQuery).node (); + topMenu.parent ().insert_copy_after (modMenu.first_child (), topMenu); } - if (!registeredModifies.empty()) { + if (!registeredModifies.empty ()) { for (RegisteredModify *modify : registeredModifies) { - pugi::xpath_query modifyQuery = pugi::xpath_query(modify->query.c_str()); + pugi::xpath_query modifyQuery = pugi::xpath_query (modify->query.c_str ()); try { - pugi::xml_node modifyNode = doc.select_node(modifyQuery).node(); + pugi::xml_node modifyNode = doc.select_node (modifyQuery).node (); if (modifyNode) { - modify->nodeModify(modifyNode); - modify->registerInit(); + modify->nodeModify (modifyNode); + modify->registerInit (); } - } catch (std::exception &e) { - std::wcerr << "[TestMode Error] failed to find node by xpath: " << modify->query << std::endl; - } + } catch (std::exception &e) { LogMessage (LOG_LEVEL_ERROR, L"Failed to find node by xpath: " + modify->query); } } } - doc.save_file(modFileName.c_str()); - modded = modFileName; + doc.save_file (modFileName.c_str ()); + modded = modFileName; fileName = modFileName; } } else modded = fileName; } else fileName = modded; } - std::wcout << "TestModeLibrary load: " << fileName << std::endl; - - originalTestModeSetMenuHook.call (testModeLibrary, fileName.c_str()); + LogMessage (LOG_LEVEL_DEBUG, L"TestModeLibrary load: " + fileName); + originalTestModeSetMenuHook.call (testModeLibrary, fileName.c_str ()); } void CommonModify () { // Default off Close time - TestMode::RegisterModify( + TestMode::RegisterModify ( L"/root/menu[@id='CloseTimeSettingMenu']/layout[@type='Center']/select-item[@id='ScheduleTypeItem']", - [&](pugi::xml_node &node) { node.attribute(L"default").set_value(L"0"); }, [&](){} - ); + [&] (pugi::xml_node &node) { node.attribute (L"default").set_value (L"0"); }, [&] () {}); } void LocalizationCHT () { - TestMode::RegisterModify( + TestMode::RegisterModify ( L"/root/menu[@id='TopMenu']/layout[@type='Center']/menu-item[@menu='ModManagerMenu']", - [&](pugi::xml_node &node) { node.attribute(L"label").set_value(L"模組管理"); }, [](){} - ); - TestMode::RegisterModify( + [&] (pugi::xml_node &node) { node.attribute (L"label").set_value (L"模組管理"); }, [] () {}); + TestMode::RegisterModify ( L"/root/menu[@id='ModManagerMenu']/layout[@type='Header']/text-item", - [&](pugi::xml_node &node) { node.attribute(L"label").set_value(L"模組管理"); }, [](){} - ); - TestMode::RegisterModify( + [&] (pugi::xml_node &node) { node.attribute (L"label").set_value (L"模組管理"); }, [] () {}); + 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:開啓"); }, [](){} - ); - TestMode::RegisterModify( + [&] (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:僅刷卡"); }, [](){} - ); - TestMode::RegisterModify( + [&] (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:僅刷卡"); }, [](){} - ); - TestMode::RegisterModify( + [&] (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:僅刷卡"); }, [](){} - ); - TestMode::RegisterModify( + [&] (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:僅刷卡"); }, [](){} - ); - TestMode::RegisterModify( + [&] (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']/menu-item[@menu='TopMenu']", - [&](pugi::xml_node &node) { node.attribute(L"label").set_value(L"離開"); }, [](){} - ); + [&] (pugi::xml_node &node) { node.attribute (L"label").set_value (L"離開"); }, [] () {}); } void LocalizationCHS () { - TestMode::RegisterModify( + TestMode::RegisterModify ( L"/root/menu[@id='TopMenu']/layout[@type='Center']/menu-item[@menu='ModManagerMenu']", - [&](pugi::xml_node &node) { node.attribute(L"label").set_value(L"模组管理"); }, [](){} - ); - TestMode::RegisterModify( + [&] (pugi::xml_node &node) { node.attribute (L"label").set_value (L"模组管理"); }, [] () {}); + TestMode::RegisterModify ( L"/root/menu[@id='ModManagerMenu']/layout[@type='Header']/text-item", - [&](pugi::xml_node &node) { node.attribute(L"label").set_value(L"模组管理"); }, [](){} - ); - TestMode::RegisterModify( + [&] (pugi::xml_node &node) { node.attribute (L"label").set_value (L"模组管理"); }, [] () {}); + 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:启用"); }, [](){} - ); - TestMode::RegisterModify( + [&] (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:仅刷卡"); }, [](){} - ); - TestMode::RegisterModify( + [&] (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:仅刷卡"); }, [](){} - ); - TestMode::RegisterModify( + [&] (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( + TestMode::RegisterModify ( L"/root/menu[@id='ModManagerMenu']/layout[@type='Center']/menu-item[@menu='TopMenu']", - [&](pugi::xml_node &node) { node.attribute(L"label").set_value(L"离开"); }, [](){} - ); + [&] (pugi::xml_node &node) { node.attribute (L"label").set_value (L"离开"); }, [] () {}); } void Init () { + LogMessage (LOG_LEVEL_DEBUG, "Init TestMode patches"); + auto configPath = std::filesystem::current_path () / "config.toml"; std::unique_ptr config_ptr (openConfig (configPath), toml_free); - + u64 testModeSetMenuAddress = PROC_ADDRESS_OFFSET ("TestModeLibrary.dll", 0x99D0); switch (gameVersion) { - case GameVersion::UNKNOWN: break; - case GameVersion::JPN00: break; - case GameVersion::JPN08: break; - case GameVersion::JPN39: { - if (config_ptr) { - auto patches = openConfigSection (config_ptr.get (), "patches"); - if (patches) { - auto jpn39 = openConfigSection (patches, "jpn39"); - if (jpn39) { - chsPatch = readConfigBool (jpn39, "chs_patch", chsPatch); - } - } + case GameVersion::UNKNOWN: break; + case GameVersion::JPN00: break; + case GameVersion::JPN08: break; + case GameVersion::JPN39: { + if (config_ptr) { + auto patches = openConfigSection (config_ptr.get (), "patches"); + if (patches) { + auto jpn39 = openConfigSection (patches, "jpn39"); + if (jpn39) chsPatch = readConfigBool (jpn39, "chs_patch", chsPatch); } - if (chsPatch) LocalizationCHT(); - } break; - case GameVersion::CHN00: break; + } + if (chsPatch) LocalizationCHT (); + } break; + case GameVersion::CHN00: break; } CommonModify (); @@ -300,34 +322,36 @@ SetupAccessor (u64 appAccessor, RefTestModeMain refTestMode) { } int -ReadTestModeValue (const wchar_t* itemId) { +ReadTestModeValue (const wchar_t *itemId) { if (appAccessor) { u64 testModeMain = refTestMode (appAccessor); if (testModeMain) { - int value = 0; - u64* reader = *(u64**)(testModeMain + 16); - (*(void (__fastcall **)(u64*, const wchar_t *, int *))(*reader + 256))(reader, itemId, &value); + int value = 0; + u64 *reader = *(u64 **)(testModeMain + 16); + (*(void (__fastcall **) (u64 *, const wchar_t *, int *)) (*reader + 256)) (reader, itemId, &value); return value; } } - std::wcerr << "Read TestMode(" << itemId << ") failed!" << std::endl; + LogMessage (LOG_LEVEL_ERROR, (std::wstring (L"Read TestMode(") + itemId + L") failed!").c_str ()); return -1; } void -RegisterItem (const std::wstring item, const std::function &initMethod) { - registeredItems.push_back(new RegisteredItem(item, initMethod)); +RegisterItem (const std::wstring item, const std::function &initMethod) { + LogMessage (LOG_LEVEL_DEBUG, L"Register Item " + item); + registeredItems.push_back (new RegisteredItem (item, initMethod)); } void -RegisterModify (const std::wstring query, const std::function &nodeModify, const std::function &initMethod) { - registeredModifies.push_back(new RegisteredModify(query, nodeModify, initMethod)); +RegisterModify (const std::wstring query, const std::function &nodeModify, const std::function &initMethod) { + LogMessage (LOG_LEVEL_DEBUG, L"Register Modify " + query); + registeredModifies.push_back (new RegisteredModify (query, nodeModify, initMethod)); } void Append (pugi::xml_node &node, const wchar_t *attr, const std::wstring append) { pugi::xml_attribute attribute = node.attribute (attr); - std::wstring attrValue = std::wstring(attribute.value ()) + append; + std::wstring attrValue = std::wstring (attribute.value ()) + append; attribute.set_value (attrValue.c_str ()); } } \ No newline at end of file diff --git a/src/patches/versions/CHN00.cpp b/src/patches/versions/CHN00.cpp index 926e286..65cfa94 100644 --- a/src/patches/versions/CHN00.cpp +++ b/src/patches/versions/CHN00.cpp @@ -5,7 +5,7 @@ extern std::string chassisId; namespace patches::CHN00 { - +int language = 0; u8 *haspBuffer; HOOK (i32, HaspDecrypt, PROC_ADDRESS ("hasp_windows_x64.dll", "hasp_decrypt")) { return 0; } HOOK (i32, HaspEncrypt, PROC_ADDRESS ("hasp_windows_x64.dll", "hasp_encrypt")) { return 0; } @@ -35,38 +35,42 @@ lua_pushtrue (i64 a1) { return 1; } -HOOK (i64, AvailableMode_Dani_AI, ASLR (0x1401AC550), i64 a1) { return lua_pushtrue (a1); } -HOOK (i64, AvailableMode_Collabo025, ASLR (0x1402BFF70), i64 *, i64 a2) { return lua_pushtrue (a2); } -HOOK (i64, AvailableMode_Collabo026, ASLR (0x1402BC9B0), i64 a1) { return lua_pushtrue (a1); } - -int language = 0; -const char * -languageStr () { - switch (language) { - case 1: return "en_us"; - case 2: return "cn_tw"; - case 3: return "kor"; - case 4: return "cn_cn"; - default: return "jpn"; - } +HOOK (i64, AvailableMode_Dani_AI, ASLR (0x1401AC550), i64 a1) { + LogMessage (LOG_LEVEL_HOOKS, "AvailableMode_Dani_AI was called"); + return lua_pushtrue (a1); } +HOOK (i64, AvailableMode_Collabo025, ASLR (0x1402BFF70), i64 *, i64 a2) { + LogMessage (LOG_LEVEL_HOOKS, "AvailableMode_Collabo025 was called"); + return lua_pushtrue (a2); +} +HOOK (i64, AvailableMode_Collabo026, ASLR (0x1402BC9B0), i64 a1) { + LogMessage (LOG_LEVEL_HOOKS, "AvailableMode_Collabo026 was called"); + return lua_pushtrue (a1); +} + HOOK (i64, GetLanguage, ASLR (0x140023720), i64 a1) { + LogMessage (LOG_LEVEL_HOOKS, "GetLanguage was called"); auto result = originalGetLanguage.call (a1); language = *((u32 *)result); return result; } HOOK (i64, GetRegionLanguage, ASLR (0x1401AC300), i64 a1) { + LogMessage (LOG_LEVEL_HOOKS, "GetRegionLanguage was called"); lua_settop (a1, 0); - lua_pushstring (a1, (u64)languageStr ()); + lua_pushstring (a1, (u64)languageStr (language)); return 1; } HOOK (i64, GetCabinetLanguage, ASLR (0x1401AF270), i64, i64 a2) { + LogMessage (LOG_LEVEL_HOOKS, "GetCabinetLanguage was called"); lua_settop (a2, 0); - lua_pushstring (a2, (u64)languageStr ()); + lua_pushstring (a2, (u64)languageStr (language)); return 1; } -HOOK_DYNAMIC (char, AMFWTerminate, i64) { return 0; } +HOOK_DYNAMIC (char, AMFWTerminate, i64) { + LogMessage (LOG_LEVEL_HOOKS, "AMFWTerminate was called"); + return 0; +} const i32 datatableBufferSize = 1024 * 1024 * 12; safetyhook::Allocation datatableBuffer1; diff --git a/src/patches/versions/JPN00.cpp b/src/patches/versions/JPN00.cpp index d1c349c..cf15f84 100644 --- a/src/patches/versions/JPN00.cpp +++ b/src/patches/versions/JPN00.cpp @@ -2,15 +2,6 @@ #include "../patches.h" #include -extern u64 song_data_size; -extern void *song_data; - -#define RDX_MOV 0x48, 0xBA -#define R8_MOV 0x49, 0xB8 -#define GENERATE_MOV(instruction, location) \ - instruction, (u8)(u64)(location), (u8)((u64)(location) >> 8), (u8)((u64)(location) >> 16), (u8)((u64)(location) >> 24), \ - (u8)((u64)(location) >> 32), (u8)((u64)(location) >> 40), (u8)((u64)(location) >> 48), (u8)((u64)(location) >> 56) - namespace patches::JPN00 { HOOK_DYNAMIC (char, AMFWTerminate, i64) { return 0; } diff --git a/src/patches/versions/JPN39.cpp b/src/patches/versions/JPN39.cpp index fd3cbba..1c2650a 100644 --- a/src/patches/versions/JPN39.cpp +++ b/src/patches/versions/JPN39.cpp @@ -4,11 +4,14 @@ #include namespace patches::JPN39 { - -HOOK_DYNAMIC (char, AMFWTerminate, i64) { return 0; } +int language = 0; +HOOK_DYNAMIC (char, AMFWTerminate, i64) { + LogMessage (LOG_LEVEL_HOOKS, "AMFWTerminate was called"); + return 0; +} HOOK_DYNAMIC (i64, curl_easy_setopt, i64 a1, i64 a2, i64 a3, i64 a4, i64 a5) { - // printf ("garmc curl_easy_setopt\n"); + LogMessage (LOG_LEVEL_HOOKS, "Garmc curl_easy_setopt was called"); originalcurl_easy_setopt.call (a1, 64, 0, 0, 0); originalcurl_easy_setopt.call (a1, 81, 0, 0, 0); return originalcurl_easy_setopt.call (a1, a2, a3, a4, a5); @@ -41,9 +44,10 @@ lua_pushbool (i64 a1, bool val) { return 1; } -u64 appAccessor = 0; +u64 appAccessor = 0; u64 componentAccessor = 0; -HOOK (i64, DeviceCheck, ASLR(0x140464FC0), i64 a1, i64 a2, i64 a3) { +HOOK (i64, DeviceCheck, ASLR (0x140464FC0), i64 a1, i64 a2, i64 a3) { + LogMessage (LOG_LEVEL_HOOKS, "DeviceCheck was called"); TestMode::SetupAccessor (a3, RefTestModeMain); componentAccessor = a2; return originalDeviceCheck.call (a1, a2, a3); @@ -53,55 +57,53 @@ int GetUserStatus () { if (appAccessor) { u64 playDataManager = RefPlayDataManager (appAccessor); - if (playDataManager) return GetUserCount(playDataManager); + if (playDataManager) return GetUserCount (playDataManager); } return -1; } HOOK (i64, AvailableMode_Collabo024, ASLR (0x1402DE710), i64 a1) { + LogMessage (LOG_LEVEL_HOOKS, "AvailableMode_Collabo024 was called"); int tournamentMode = TestMode::ReadTestModeValue (L"TournamentMode"); if (tournamentMode == 1) return originalAvailableMode_Collabo024.call (a1); int status = TestMode::ReadTestModeValue (L"ModModeCollabo024"); - if (status == 1 && GetUserStatus () == 1) { - return lua_pushbool (a1, true); - } + if (status == 1 && GetUserStatus () == 1) return lua_pushbool (a1, true); return originalAvailableMode_Collabo024.call (a1); } HOOK (i64, AvailableMode_Collabo025, ASLR (0x1402DE6B0), i64 a1) { + LogMessage (LOG_LEVEL_HOOKS, "AvailableMode_Collabo025 was called"); int tournamentMode = TestMode::ReadTestModeValue (L"TournamentMode"); if (tournamentMode == 1) return originalAvailableMode_Collabo025.call (a1); int status = TestMode::ReadTestModeValue (L"ModModeCollabo025"); - if (status == 1 && GetUserStatus () == 1) { - return lua_pushbool (a1, true); - } + if (status == 1 && GetUserStatus () == 1) return lua_pushbool (a1, true); return originalAvailableMode_Collabo025.call (a1); } HOOK (i64, AvailableMode_Collabo026, ASLR (0x1402DE670), i64 a1) { + LogMessage (LOG_LEVEL_HOOKS, "AvailableMode_Collabo026 was called"); int tournamentMode = TestMode::ReadTestModeValue (L"TournamentMode"); if (tournamentMode == 1) return originalAvailableMode_Collabo026.call (a1); int status = TestMode::ReadTestModeValue (L"ModModeCollabo026"); - if (status == 1 && GetUserStatus () == 1) { - return lua_pushbool (a1, true); - } + if (status == 1 && GetUserStatus () == 1) return lua_pushbool (a1, true); return originalAvailableMode_Collabo026.call (a1); } HOOK (i64, AvailableMode_AprilFool001, ASLR (0x1402DE5B0), i64 a1) { + LogMessage (LOG_LEVEL_HOOKS, "AvailableMode_AprilFool001 was called"); int tournamentMode = TestMode::ReadTestModeValue (L"TournamentMode"); if (tournamentMode == 1) return originalAvailableMode_AprilFool001.call (a1); int status = TestMode::ReadTestModeValue (L"ModModeAprilFool001"); - if (status == 1) { - return lua_pushbool (a1, true); - } + if (status == 1) return lua_pushbool (a1, true); return originalAvailableMode_AprilFool001.call (a1); } i64 __fastcall lua_freeze_timer (i64 a1) { + LogMessage (LOG_LEVEL_HOOKS, "lua_freeze_timer was called"); int tournamentMode = TestMode::ReadTestModeValue (L"TournamentMode"); - if (tournamentMode == 1) return lua_pushbool (a1, true); + if (tournamentMode == 1) return lua_pushbool (a1, true); int status = TestMode::ReadTestModeValue (L"ModFreezeTimer"); if (status == 1) return lua_pushbool (a1, true); return lua_pushbool (a1, false); } MID_HOOK (FreezeTimer, ASLR (0x14019FF51), SafetyHookContext &ctx) { + LogMessage (LOG_LEVEL_HOOKS, "FreezeTimer was called"); auto a1 = ctx.rdi; int v9 = (int)(ctx.rax + 1); lua_pushcclosure (a1, reinterpret_cast (&lua_freeze_timer), v9); @@ -156,110 +158,53 @@ ExecuteSendResultData () { ); } -bool sendFlag = false; -#define SCENE_RESULT_HOOK(functionName, location) \ - HOOK (void, functionName, location, i64 a1, i64 a2, i64 a3) { \ - if ( \ - TestMode::ReadTestModeValue (L"ModInstantResult") != 1 && \ - TestMode::ReadTestModeValue (L"NumberOfStageItem") <= 4 \ - ) { original##functionName.call (a1, a2, a3); return; } \ - sendFlag = true; \ - original##functionName.call (a1, a2, a3); \ - ExecuteSendResultData (); \ - } - SCENE_RESULT_HOOK (SceneResultInitialize_Enso, ASLR (0x140411FD0)); SCENE_RESULT_HOOK (SceneResultInitialize_AI, ASLR (0x140411FD0)); SCENE_RESULT_HOOK (SceneResultInitialize_Collabo025, ASLR (0x140411FD0)); SCENE_RESULT_HOOK (SceneResultInitialize_Collabo026, ASLR (0x140411FD0)); SCENE_RESULT_HOOK (SceneResultInitialize_AprilFool, ASLR (0x140411FD0)); - -#define SEND_RESULT_HOOK(functionName, location) \ - HOOK (void, functionName, location, i64 a1) { \ - if ( \ - TestMode::ReadTestModeValue (L"ModInstantResult") != 1 && \ - TestMode::ReadTestModeValue (L"NumberOfStageItem") <= 4 \ - ) { original##functionName.call (a1); return; } \ - if (sendFlag) { \ - sendFlag = false; \ - original##functionName.call (a1); \ - } \ - } - SEND_RESULT_HOOK (SendResultData_Enso, ASLR (0x1401817B0)); SEND_RESULT_HOOK (SendResultData_AI, ASLR (0x1401755E0)); SEND_RESULT_HOOK (SendResultData_Collabo025_026, ASLR (0x140179A00)); SEND_RESULT_HOOK (SendResultData_AprilFool, ASLR (0x140177800)); -#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; \ - } - CHANGE_RESULT_SIZE_HOOK (ChangeResultDataSize_Enso, ASLR (0x140180074), rax); CHANGE_RESULT_SIZE_HOOK (ChangeResultDataSize_AI, ASLR (0x140173774), rax); CHANGE_RESULT_SIZE_HOOK (ChangeResultDataSize_Collabo025_026, ASLR (0x140178244), rax); CHANGE_RESULT_SIZE_HOOK (ChangeResultDataSize_AprilFool, ASLR (0x140176044), rax); - -#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; \ - } - + CHANGE_RESULT_INDEX_HOOK (ChangeResultDataIndex_Enso, ASLR (0x14018074B), rax, 0x34, 0x07); CHANGE_RESULT_INDEX_HOOK (ChangeResultDataIndex_AI, ASLR (0x140173EDD), r13, 0x24, 0x08); CHANGE_RESULT_INDEX_HOOK (ChangeResultDataIndex_Collabo025_026, ASLR (0x1401789AD), r13, 0x24, 0x08); CHANGE_RESULT_INDEX_HOOK (ChangeResultDataIndex_AprilFool, ASLR (0x140176716), rax, 0x34, 0x06); -int language = 0; -const char * -languageStr () { - switch (language) { - case 1: return "en_us"; - case 2: return "cn_tw"; - case 3: return "kor"; - case 4: return "cn_cn"; - default: return "jpn"; - } -} HOOK (i64, GetLanguage, ASLR (0x140024AC0), i64 a1) { + LogMessage (LOG_LEVEL_HOOKS, "GetLanguage was called"); auto result = originalGetLanguage.call (a1); language = *((u32 *)result); return result; } HOOK (i64, GetRegionLanguage, ASLR (0x1401CE9B0), i64 a1) { + LogMessage (LOG_LEVEL_HOOKS, "GetRegionLanguage was called"); lua_settop (a1, 0); - lua_pushstring (a1, languageStr ()); + lua_pushstring (a1, languageStr (language)); return 1; } HOOK (i64, GetCabinetLanguage, ASLR (0x1401D1A60), i64, i64 a2) { + LogMessage (LOG_LEVEL_HOOKS, "GetCabinetLanguage was called"); lua_settop (a2, 0); - lua_pushstring (a2, languageStr ()); + lua_pushstring (a2, languageStr (language)); return 1; } MID_HOOK (ChangeLanguageType, ASLR (0x1400B2016), SafetyHookContext &ctx) { + LogMessage (LOG_LEVEL_HOOKS, "ChangeLanguageType was called"); int *pFontType = (int *)ctx.rax; if (*pFontType == 4) *pFontType = 2; } MID_HOOK (CountLockedCrown, ASLR (0x1403F2A25), SafetyHookContext &ctx) { + LogMessage (LOG_LEVEL_HOOKS, "CountLockedCrown was called"); ctx.r15 |= 1; } @@ -312,6 +257,7 @@ check_voice_tail (std::string bankName, uint8_t *pBinfBlock, std::map lock (nus3bankMtx); if ((uint8_t **)(ctx.rcx + 8) != nullptr) { uint8_t *pNus3bankFile = *((uint8_t **)(ctx.rcx + 8)); @@ -337,6 +283,7 @@ FixToneName (std::string bankName, std::string toneName) { size_t commonSize = 0; HOOK (i64, PlaySound, ASLR (0x1404C6DC0), i64 a1) { + LogMessage (LOG_LEVEL_HOOKS, "PlaySound was called"); if (enableSwitchVoice && language != 0) { std::string bankName (lua_tolstring (a1, -3, &commonSize)); if (bankName[0] == 'v') { @@ -348,6 +295,7 @@ HOOK (i64, PlaySound, ASLR (0x1404C6DC0), i64 a1) { } HOOK (i64, PlaySoundMulti, ASLR (0x1404C6D60), i64 a1) { + LogMessage (LOG_LEVEL_HOOKS, "PlaySoundMulti was called"); if (enableSwitchVoice && language != 0) { std::string bankName ((char *)lua_tolstring (a1, -3, &commonSize)); if (bankName[0] == 'v') { @@ -369,6 +317,7 @@ FixToneNameEnso (u64 *Src, std::string &bankName) { } HOOK (bool, PlaySoundEnso, ASLR (0x1404ED590), u64 *a1, u64 *a2, i64 a3) { + LogMessage (LOG_LEVEL_HOOKS, "PlaySoundEnso was called"); if (enableSwitchVoice && language != 0) { std::string bankName = a1[3] > 0x10 ? std::string (*((char **)a1)) : std::string ((char *)a1); if (bankName[0] == 'v') a2 = FixToneNameEnso (a2, bankName); @@ -377,6 +326,7 @@ HOOK (bool, PlaySoundEnso, ASLR (0x1404ED590), u64 *a1, u64 *a2, i64 a3) { } HOOK (bool, PlaySoundSpecial, ASLR (0x1404ED230), u64 *a1, u64 *a2) { + LogMessage (LOG_LEVEL_HOOKS, "PlaySoundSpecial was called"); if (enableSwitchVoice && language != 0) { std::string bankName = a1[3] > 0x10 ? std::string (*((char **)a1)) : std::string ((char *)a1); if (bankName[0] == 'v') a2 = FixToneNameEnso (a2, bankName); @@ -386,6 +336,7 @@ HOOK (bool, PlaySoundSpecial, ASLR (0x1404ED230), u64 *a1, u64 *a2) { int loaded_fail_count = 0; HOOK (i64, LoadedBankAll, ASLR (0x1404C69F0), i64 a1) { + LogMessage (LOG_LEVEL_HOOKS, "LoadedBankAll was called"); originalLoadedBankAll.call (a1); auto result = lua_toboolean (a1, -1); lua_settop (a1, 0); @@ -404,27 +355,29 @@ HOOK (i64, LoadedBankAll, ASLR (0x1404C69F0), i64 a1) { float soundRate = 1.0F; HOOK (i32, SetMasterVolumeSpeaker, ASLR (0x140160330), i32 a1) { + LogMessage (LOG_LEVEL_HOOKS, "SetMasterVolumeSpeaker was called"); soundRate = a1 <= 100 ? 1.0F : a1 / 100.0; return originalSetMasterVolumeSpeaker.call (a1 > 100 ? 100 : a1); } HOOK (u64, NuscBusVolume, ASLR (0x1407B1C30), u64 a1, u64 a2, float a3) { + LogMessage (LOG_LEVEL_HOOKS, "NuscBusVolume was called"); return originalNuscBusVolume.call (a1, a2, a3 * soundRate); } -std::string* fontName = nullptr; +std::string *fontName = nullptr; HOOK (u8, SetupFontInfo, ASLR (0x14049D820), u64 a1, u64 a2, size_t a3, u64 a4) { + LogMessage (LOG_LEVEL_HOOKS, "SetupFontInfo was called"); if (fontName != nullptr) delete fontName; - fontName = new std::string(((char*)a1) + 120); + fontName = new std::string (((char *)a1) + 120); return originalSetupFontInfo.call (a1, a2, a3, a4); } HOOK (u32, ReadFontInfoInt, ASLR (0x14049EAC0), u64 a1, u64 a2) { - std::string attribute((char*)a2); + LogMessage (LOG_LEVEL_HOOKS, "ReadFontInfoInt was called"); + std::string attribute ((char *)a2); u32 result = originalReadFontInfoInt.call (a1, a2); - if (fontName->starts_with("cn_") && attribute == "offsetV") { - result += 1; - } + if (fontName->starts_with ("cn_") && attribute == "offsetV") result += 1; return result; } @@ -457,13 +410,12 @@ ReplaceLeaBufferAddress (const std::vector &bufferAddresses, void *ne void Init () { - i32 xRes = 1920; - i32 yRes = 1080; - bool vsync = false; - bool unlockSongs = true; - bool fixLanguage = false; - bool chsPatch = false; - + i32 xRes = 1920; + i32 yRes = 1080; + bool vsync = false; + bool unlockSongs = true; + bool fixLanguage = false; + bool chsPatch = false; bool useLayeredfs = false; auto configPath = std::filesystem::current_path () / "config.toml"; @@ -474,8 +426,8 @@ Init () { unlockSongs = readConfigBool (patches, "unlock_songs", unlockSongs); auto jpn39 = openConfigSection (patches, "jpn39"); if (jpn39) { - fixLanguage = readConfigBool (jpn39, "fix_language", fixLanguage); - chsPatch = readConfigBool (jpn39, "chs_patch", chsPatch); + fixLanguage = readConfigBool (jpn39, "fix_language", fixLanguage); + chsPatch = readConfigBool (jpn39, "chs_patch", chsPatch); } } @@ -555,55 +507,55 @@ Init () { } // Freeze Timer - TestMode::RegisterItem( - L"", - [&]() { INSTALL_MID_HOOK (FreezeTimer); } - ); + TestMode::RegisterItem (L"", + [&] () { INSTALL_MID_HOOK (FreezeTimer); }); // Mode Unlock - TestMode::RegisterItem( - L"", - [&]() { INSTALL_HOOK (AvailableMode_Collabo024); } - ); - TestMode::RegisterItem( - L"", - [&]() { INSTALL_HOOK (AvailableMode_Collabo025); } - ); - TestMode::RegisterItem( - L"", - [&]() { INSTALL_HOOK (AvailableMode_Collabo026); } - ); - TestMode::RegisterItem( - L"", - [&]() { INSTALL_HOOK (AvailableMode_AprilFool001); } - ); - TestMode::RegisterItem( - L"", - [&]() { - INSTALL_HOOK (SceneResultInitialize_Enso); - INSTALL_HOOK (SceneResultInitialize_AI); - INSTALL_HOOK (SceneResultInitialize_Collabo025); - INSTALL_HOOK (SceneResultInitialize_Collabo026); - INSTALL_HOOK (SceneResultInitialize_AprilFool); - INSTALL_HOOK (SendResultData_Enso); - INSTALL_HOOK (SendResultData_AI); - INSTALL_HOOK (SendResultData_Collabo025_026); - INSTALL_HOOK (SendResultData_AprilFool); - INSTALL_MID_HOOK (ChangeResultDataSize_Enso); - INSTALL_MID_HOOK (ChangeResultDataSize_AI); - INSTALL_MID_HOOK (ChangeResultDataSize_Collabo025_026); - INSTALL_MID_HOOK (ChangeResultDataSize_AprilFool); - INSTALL_MID_HOOK (ChangeResultDataIndex_Enso); - INSTALL_MID_HOOK (ChangeResultDataIndex_AI); - INSTALL_MID_HOOK (ChangeResultDataIndex_Collabo025_026); - INSTALL_MID_HOOK (ChangeResultDataIndex_AprilFool); - } - ); + TestMode::RegisterItem (L"", + [&] () { INSTALL_HOOK (AvailableMode_Collabo024); }); + TestMode::RegisterItem (L"", + [&] () { INSTALL_HOOK (AvailableMode_Collabo025); }); + TestMode::RegisterItem (L"", + [&] () { INSTALL_HOOK (AvailableMode_Collabo026); }); + TestMode::RegisterItem (L"", + [&] () { INSTALL_HOOK (AvailableMode_AprilFool001); }); + TestMode::RegisterItem (L"", + [&] () { + INSTALL_HOOK (SceneResultInitialize_Enso); + INSTALL_HOOK (SceneResultInitialize_AI); + INSTALL_HOOK (SceneResultInitialize_Collabo025); + INSTALL_HOOK (SceneResultInitialize_Collabo026); + INSTALL_HOOK (SceneResultInitialize_AprilFool); + INSTALL_HOOK (SendResultData_Enso); + INSTALL_HOOK (SendResultData_AI); + INSTALL_HOOK (SendResultData_Collabo025_026); + INSTALL_HOOK (SendResultData_AprilFool); + INSTALL_MID_HOOK (ChangeResultDataSize_Enso); + INSTALL_MID_HOOK (ChangeResultDataSize_AI); + INSTALL_MID_HOOK (ChangeResultDataSize_Collabo025_026); + INSTALL_MID_HOOK (ChangeResultDataSize_AprilFool); + INSTALL_MID_HOOK (ChangeResultDataIndex_Enso); + INSTALL_MID_HOOK (ChangeResultDataIndex_AI); + INSTALL_MID_HOOK (ChangeResultDataIndex_Collabo025_026); + INSTALL_MID_HOOK (ChangeResultDataIndex_AprilFool); + }); // Unlimit Volume - TestMode::RegisterModify( + TestMode::RegisterModify ( L"/root/menu[@id='SoundTestMenu']/layout[@type='Center']/select-item[@id='OutputLevelSpeakerItem']", - [&](pugi::xml_node &node) { TestMode::Append(node, L"label", L"*"); node.attribute(L"max").set_value(L"300"); node.attribute(L"delta").set_value(L"1"); }, - [&]() { INSTALL_HOOK (SetMasterVolumeSpeaker); INSTALL_HOOK (NuscBusVolume); } - ); + [&] (pugi::xml_node &node) { + TestMode::Append (node, L"label", L"*"); + node.attribute (L"max").set_value (L"300"); + node.attribute (L"delta").set_value (L"1"); + }, + [&] () { + INSTALL_HOOK (SetMasterVolumeSpeaker); + INSTALL_HOOK (NuscBusVolume); + }); // Instant Result // TestMode::RegisterModify( // L"/root/menu[@id='GameOptionsMenu']/layout[@type='Center']/select-item[@id='NumberOfStageItem']", @@ -636,10 +588,10 @@ Init () { INSTALL_HOOK (ReadFontInfoInt); } - LayeredFs::RegisterBefore([=](const std::string originalFileName, const std::string currentFileName) -> std::string { + LayeredFs::RegisterBefore ([=] (const std::string originalFileName, const std::string currentFileName) -> std::string { if (currentFileName.find ("\\lumen\\") == std::string::npos) return ""; std::string fileName = currentFileName; - fileName = replace(fileName, "\\lumen\\", "\\lumen_cn\\"); + fileName = replace (fileName, "\\lumen\\", "\\lumen_cn\\"); if (std::filesystem::exists (fileName)) return fileName; else return currentFileName; }); diff --git a/src/poll.cpp b/src/poll.cpp index 90c011e..396ee4c 100644 --- a/src/poll.cpp +++ b/src/poll.cpp @@ -330,7 +330,7 @@ void SetConfigValue (toml_table_t *table, const char *key, Keybindings *keybind) { toml_array_t *array = toml_array_in (table, key); if (!array) { - printWarning ("%s (%s): Cannot find array\n", __func__, key); + LogMessage (LOG_LEVEL_WARN, (std::string (key) + ": Cannot find array").c_str ()); return; } @@ -395,16 +395,16 @@ InitializePoll (HWND windowHandle) { if (SDL_Init (SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER | SDL_INIT_EVENTS | SDL_INIT_VIDEO) == 0) { hasRumble = false; } else { - printError ("SDL_Init (SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMECONTROLLER | SDL_INIT_EVENTS | SDL_INIT_VIDEO): " - "%s\n", - SDL_GetError ()); + LogMessage (LOG_LEVEL_ERROR, + (std::string ("SDL_Init (SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMECONTROLLER | SDL_INIT_EVENTS | SDL_INIT_VIDEO): ") + + SDL_GetError ()) + .c_str ()); return false; } } auto configPath = std::filesystem::current_path () / "gamecontrollerdb.txt"; - if (SDL_GameControllerAddMappingsFromFile (configPath.string ().c_str ()) == -1) - printError ("%s (): Cannot read gamecontrollerdb.txt\n", __func__); + if (SDL_GameControllerAddMappingsFromFile (configPath.string ().c_str ()) == -1) LogMessage (LOG_LEVEL_ERROR, "Cannot read gamecontrollerdb.txt"); SDL_GameControllerEventState (SDL_ENABLE); SDL_JoystickEventState (SDL_ENABLE); @@ -413,15 +413,15 @@ InitializePoll (HWND windowHandle) { SDL_GameController *controller = SDL_GameControllerOpen (i); if (!controller) { - printWarning ("Could not open gamecontroller %s: %s\n", SDL_GameControllerNameForIndex (i), SDL_GetError ()); + LogMessage (LOG_LEVEL_WARN, + (std::string ("Could not open gamecontroller ") + SDL_GameControllerNameForIndex (i) + ": " + SDL_GetError ()).c_str ()); continue; } controllers[i] = controller; } window = SDL_CreateWindowFrom (windowHandle); - if (window == NULL) printError ("SDL_CreateWindowFrom (windowHandle): %s\n", SDL_GetError ()); - + if (window == NULL) LogMessage (LOG_LEVEL_ERROR, (std::string ("SDL_CreateWindowFrom (windowHandle): ") + SDL_GetError ()).c_str ()); atexit (DisposePoll); return hasRumble; @@ -454,8 +454,9 @@ UpdatePoll (HWND windowHandle) { controller = SDL_GameControllerOpen (event.cdevice.which); if (!controller) { - printError ("%s (): Could not open gamecontroller %s: %s\n", __func__, SDL_GameControllerNameForIndex (event.cdevice.which), - SDL_GetError ()); + LogMessage (LOG_LEVEL_ERROR, (std::string ("Could not open gamecontroller ") + SDL_GameControllerNameForIndex (event.cdevice.which) + + ": " + SDL_GetError ()) + .c_str ()); continue; } controllers[event.cdevice.which] = controller; @@ -548,7 +549,7 @@ StringToConfigEnum (const char *value) { return rval; } - printError ("%s (%s): Unknown value\n", __func__, value); + LogMessage (LOG_LEVEL_ERROR, (std::string (value) + ": Unknown value").c_str ()); return rval; }