diff --git a/dist/popnhax/popnhax.xml b/dist/popnhax/popnhax.xml index f741f45..fbc4f33 100644 --- a/dist/popnhax/popnhax.xml +++ b/dist/popnhax/popnhax.xml @@ -89,6 +89,8 @@ 0 + + 0 0 diff --git a/popnhax/Module.mk b/popnhax/Module.mk index c0c2f7f..befa899 100644 --- a/popnhax/Module.mk +++ b/popnhax/Module.mk @@ -19,4 +19,5 @@ srcpp_popnhax := \ translation.cc \ omnimix_patch.cc \ custom_categs.cc \ + attract.cc \ tachi.cc diff --git a/popnhax/attract.cc b/popnhax/attract.cc new file mode 100644 index 0000000..258dbe5 --- /dev/null +++ b/popnhax/attract.cc @@ -0,0 +1,283 @@ +#include +#include +#include +#include + +#include "SearchFile.h" + +#include "util/search.h" + +#include "util/log.h" +#include "util/patch.h" + +#include "tableinfo.h" +#include "loader.h" + +#include "imports/avs.h" +#include "xmlhelper.h" + +#include "minhook/hde32.h" +#include "minhook/include/MinHook.h" + +#include "custom_categs.h" + +extern const char* g_game_dll_fn; + +uint32_t g_autoplay_marker_addr = 0; +uint32_t g_attract_marker_addr = 0; +uint32_t g_is_button_pressed_fn = 0; +uint32_t g_interactive_cooldown = 0; + +void (*real_attract)(void); +void hook_ex_attract() +{ + __asm("push ebx\n"); + __asm("mov ebx, eax\n"); + __asm("add ebx, 2\n"); + __asm("mov byte ptr [ebx], 3\n"); //force EX chart_num + __asm("add ebx, 8\n"); + __asm("mov byte ptr [ebx], 40\n"); // force x4.0 multiplier + __asm("pop ebx\n"); + real_attract(); +} + +bool patch_ex_attract() +{ + DWORD dllSize = 0; + char *data = getDllData(g_game_dll_fn, &dllSize); + + { + int64_t pattern_offset = search(data, dllSize, "\x81\xE7\x01\x00\x00\x80\x79\x05\x4F", 9, 0); + if (pattern_offset == -1) { + LOG("popnhax: attract_ex: cannot find attract mode song info\n"); + return false; + } + + uint64_t patch_addr = (int64_t)data + pattern_offset; + + MH_CreateHook((LPVOID)patch_addr, (LPVOID)hook_ex_attract, + (void **)&real_attract); + } + LOG("popnhax: attract mode will play EX charts at 4.0x hispeed\n"); + return true; +} + +bool patch_full_attract() +{ + DWORD dllSize = 0; + char *data = getDllData(g_game_dll_fn, &dllSize); + + { + int64_t pattern_offset = search(data, dllSize, "\xB8\xD0\x07\x00\x00\x66\xA3", 7, 0); + if (pattern_offset == -1) { + LOG("popnhax: attract_full: cannot find attract mode timer set function\n"); + return false; + } + + uint32_t timer_addr = *(uint32_t*)((int64_t)data + pattern_offset + 7); + uint8_t new_pattern[9] = "\x66\x83\x05\x00\x00\x00\x00\xFF"; + memcpy(new_pattern+3, &timer_addr, 4); + + if (!find_and_patch_hex(g_game_dll_fn, (char*)new_pattern, 8, 7, "\x00", 1)) + { + LOG("popnhax: attract_full: cannot stop attract mode song timer\n"); + return false; + } + } + LOG("popnhax: attract mode will play full songs\n"); + return true; +} + +void (*real_attract_inter)(void); +void hook_attract_inter() +{ + __asm("push 0x1EF\n"); + __asm("mov eax, dword ptr [_g_is_button_pressed_fn]\n"); + __asm("call eax\n"); + __asm("add esp, 4\n"); + __asm("test al, al\n"); + __asm("je skip_disable_autoplay\n"); + __asm("mov eax, dword ptr [_g_autoplay_marker_addr]\n"); + __asm("mov dword ptr [eax], 0\n"); + __asm("skip_disable_autoplay:"); + real_attract_inter(); +} + +void (*real_retire_handling)(void); +void hook_attract_inter_rearm() +{ + __asm("push eax\n"); + __asm("mov eax, dword ptr [_g_attract_marker_addr]\n"); + __asm("cmp word ptr [eax], 0x0101\n"); + __asm("jne skip_rearm_autoplay\n"); + __asm("mov eax, dword ptr [_g_autoplay_marker_addr]\n"); + __asm("mov dword ptr [eax], 1\n"); + __asm("skip_rearm_autoplay:"); + __asm("pop eax\n"); + real_retire_handling(); +} + +void (*real_songend_handling)(void); +void hook_attract_inter_songend_rearm() +{ + __asm("push eax\n"); + __asm("mov eax, dword ptr [_g_attract_marker_addr]\n"); + __asm("cmp word ptr [eax], 0x0101\n"); + __asm("jne skip_se_rearm_autoplay\n"); + __asm("mov eax, dword ptr [_g_autoplay_marker_addr]\n"); + __asm("mov dword ptr [eax], 1\n"); + __asm("skip_se_rearm_autoplay:"); + __asm("pop eax\n"); + real_songend_handling(); +} + +void (*real_test_handling)(void); +void hook_attract_inter_rearm_test() +{ + __asm("push eax\n"); + __asm("mov eax, dword ptr [_g_attract_marker_addr]\n"); + __asm("cmp word ptr [eax], 0x0101\n"); + __asm("jne skip_rearm_autoplay_test\n"); + __asm("mov eax, dword ptr [_g_autoplay_marker_addr]\n"); + __asm("mov dword ptr [eax], 1\n"); + __asm("skip_rearm_autoplay_test:"); + __asm("pop eax\n"); + real_test_handling(); +} + +void (*real_rearm_marker)(void); +void hook_retrieve_attractmarker() +{ + __asm("add esi, 0x18\n"); + __asm("mov dword ptr [_g_attract_marker_addr], esi\n"); + __asm("sub esi, 0x18\n"); + real_rearm_marker(); +} +bool patch_attract_interactive() +{ + DWORD dllSize = 0; + char *data = getDllData(g_game_dll_fn, &dllSize); + + { + int64_t pattern_offset = search(data, dllSize, "\x33\xC4\x89\x44\x24\x0C\x56\x57\x53\xE8", 10, 0); + if (pattern_offset == -1) { + LOG("popnhax: attract_interactive: cannot find set autoplay marker function call\n"); + return false; + } + + uint64_t patch_addr = (int64_t)data + pattern_offset + 0x14; + + uint32_t function_offset = *((uint32_t*)(patch_addr+0x01)); + uint64_t function_addr = patch_addr+5+function_offset; + + g_autoplay_marker_addr = *((uint32_t*)(function_addr+0x02)); + } + { + int64_t pattern_offset = search(data, dllSize, "\x00\x00\x88\x46\x18\x88\x46", 7, 0); + if (pattern_offset == -1) { + LOG("popnhax: attract_interactive: cannot find get songinfozone function call\n"); + return false; + } + + uint64_t patch_addr = (int64_t)data + pattern_offset + 0x02; + + MH_CreateHook((LPVOID)patch_addr, (LPVOID)hook_retrieve_attractmarker, + (void **)&real_rearm_marker); + + } + //bad version + //g_attract_marker_addr = g_autoplay_marker_addr - 0x105; //TODO: check other versions peace ya 8 de moins + //exit(0); + + + /* enable interactive mode on button press (except red) */ + { + int64_t pattern_offset = wildcard_search(data, dllSize, "\xCC\xCC\x53\x32\xDB\xE8????\x84\xC0\x74\x78", 14, 0); + if (pattern_offset == -1) { + LOG("popnhax: attract_interactive: cannot find attract mode demo loop function\n"); + return false; + } + + int64_t pattern_offset2 = search(data, dllSize-pattern_offset, "\x6A\x10\xE8", 3, pattern_offset); + if (pattern_offset2 == -1) { + LOG("popnhax: attract_interactive: cannot find isButtonPressed function\n"); + return false; + } + uint64_t patch_addr2 = (int64_t)data + pattern_offset2 + 0x02; + uint32_t function_offset = *((uint32_t*)(patch_addr2+0x01)); + g_is_button_pressed_fn = patch_addr2+5+function_offset; + + uint64_t patch_addr = (int64_t)data + pattern_offset + 0x02; + MH_CreateHook((LPVOID)patch_addr, (LPVOID)hook_attract_inter, + (void **)&real_attract_inter); + + } + + /* disable interactive mode after a while without button press */ + { + int64_t pattern_offset = search(data, dllSize, "\x3D\x58\x02\x00\x00\x7C", 6, 0); + if (pattern_offset == -1) { + LOG("popnhax: attract_interactive: cannot find retire handling\n"); + return false; + } + + uint64_t patch_addr = (int64_t)data + pattern_offset + 0x07; + + MH_CreateHook((LPVOID)patch_addr, (LPVOID)hook_attract_inter_rearm, + (void **)&real_retire_handling); + } + + /* fix end of song crash */ + { + int64_t pattern_offset = search(data, dllSize, "\xB8\xD0\x07\x00\x00\x66\xA3", 7, 0); + if (pattern_offset == -1) { + LOG("popnhax: attract_full: cannot find attract mode timer set function\n"); + return false; + } + + uint32_t timer_addr = *(uint32_t*)((int64_t)data + pattern_offset + 7); + uint8_t new_pattern[8] = "\x66\x83\x05\x00\x00\x00\x00"; + memcpy(new_pattern+3, &timer_addr, 4); + + pattern_offset = search(data, dllSize, (const char *)new_pattern, 7, 0); + if (pattern_offset == -1) { + LOG("popnhax: attract_interactive: cannot find attract mode timer set function\n"); + return false; + } + int64_t pattern_offset2 = search(data, dllSize-pattern_offset, "\x66\x85\xC0\x74", 4, pattern_offset); + if (pattern_offset2 == -1) { + LOG("popnhax: attract_interactive: cannot find end of song handling function\n"); //TODO: FIX FOR PEACE and maybe other + return false; + } + + uint64_t patch_addr = (int64_t)data + pattern_offset2 + 0x05; + + MH_CreateHook((LPVOID)patch_addr, (LPVOID)hook_attract_inter_songend_rearm, + (void **)&real_songend_handling); + /* mauvais endroit, commun à attract et regular (par contre dans cette zone faudra reset le marker autoplay quand on arrive en fin de song pour pas crash) + a partir de pattern offset, on cherche 74 0B 89 2D + 0x02 , idem on check si 01 01 auquel cas on remet autoplay à 1 + 19 3d + uint64_t patch_addr = (int64_t)data + pattern_offset - 0x1B; + MH_CreateHook((LPVOID)patch_addr, (LPVOID)hook_attract_inter, + (void **)&real_attract_inter); +*/ + } + + /* fix crash when pressing test button during interactive mode */ + { + int64_t pattern_offset = search(data, dllSize, "\x83\xC4\x04\x84\xC0\x74\x75\x38\x1D", 9, 0); + if (pattern_offset == -1) { + LOG("popnhax: attract_interactive: cannot find test button handling\n"); + return false; + } + + uint64_t patch_addr = (int64_t)data + pattern_offset + 0x07; + + MH_CreateHook((LPVOID)patch_addr, (LPVOID)hook_attract_inter_rearm_test, + (void **)&real_test_handling); + } + + LOG("popnhax: attract mode is interactive\n"); + return true; + +} \ No newline at end of file diff --git a/popnhax/attract.h b/popnhax/attract.h new file mode 100644 index 0000000..a92ed58 --- /dev/null +++ b/popnhax/attract.h @@ -0,0 +1,11 @@ +#ifndef __ATTRACT_H__ +#define __ATTRACT_H__ + +#include +#include "popnhax/config.h" + +bool patch_attract_interactive(); +bool patch_ex_attract(); +bool patch_full_attract(); + +#endif diff --git a/popnhax/config.h b/popnhax/config.h index d4b1fc4..790b3a8 100644 --- a/popnhax/config.h +++ b/popnhax/config.h @@ -37,6 +37,7 @@ struct popnhax_config { bool tachi_scorehook_skip_omni; bool tachi_rivals; bool autopin; + bool attract_interactive; bool attract_ex; bool attract_full; bool force_slow_timer; diff --git a/popnhax/dllmain.cc b/popnhax/dllmain.cc index f900388..0668a02 100644 --- a/popnhax/dllmain.cc +++ b/popnhax/dllmain.cc @@ -28,6 +28,7 @@ #include "translation.h" #include "custom_categs.h" #include "omnimix_patch.h" +#include "attract.h" #include "tachi.h" #include "tableinfo.h" @@ -223,6 +224,8 @@ PSMAP_MEMBER_REQ(PSMAP_PROPERTY_TYPE_BOOL, struct popnhax_config, autopin, "/popnhax/autopin") PSMAP_MEMBER_REQ(PSMAP_PROPERTY_TYPE_BOOL, struct popnhax_config, attract_ex, "/popnhax/attract_ex") +PSMAP_MEMBER_REQ(PSMAP_PROPERTY_TYPE_BOOL, struct popnhax_config, attract_interactive, + "/popnhax/attract_interactive") PSMAP_MEMBER_REQ(PSMAP_PROPERTY_TYPE_BOOL, struct popnhax_config, attract_full, "/popnhax/attract_full") PSMAP_MEMBER_REQ(PSMAP_PROPERTY_TYPE_BOOL, struct popnhax_config, force_slow_timer, @@ -8096,66 +8099,6 @@ static bool patch_half_timer_speed() return true; } -void (*real_attract)(void); -void hook_ex_attract() -{ - __asm("push ebx\n"); - __asm("mov ebx, eax\n"); - __asm("add ebx, 2\n"); - __asm("mov byte ptr [ebx], 3\n"); //force EX chart_num - __asm("add ebx, 8\n"); - __asm("mov byte ptr [ebx], 40\n"); // force x4.0 multiplier - __asm("pop ebx\n"); - real_attract(); -} - -static bool patch_ex_attract() -{ - DWORD dllSize = 0; - char *data = getDllData(g_game_dll_fn, &dllSize); - - { - int64_t pattern_offset = search(data, dllSize, "\x81\xE7\x01\x00\x00\x80\x79\x05\x4F", 9, 0); - if (pattern_offset == -1) { - LOG("popnhax: attract_ex: cannot find attract mode song info\n"); - return false; - } - - uint64_t patch_addr = (int64_t)data + pattern_offset; - - MH_CreateHook((LPVOID)patch_addr, (LPVOID)hook_ex_attract, - (void **)&real_attract); - } - LOG("popnhax: attract mode will play EX charts at 4.0x hispeed\n"); - return true; -} - -static bool patch_full_attract() -{ - DWORD dllSize = 0; - char *data = getDllData(g_game_dll_fn, &dllSize); - - { - int64_t pattern_offset = search(data, dllSize, "\xB8\xD0\x07\x00\x00\x66\xA3", 7, 0); - if (pattern_offset == -1) { - LOG("popnhax: attract_full: cannot find attract mode timer set function\n"); - return false; - } - - uint32_t timer_addr = *(uint32_t*)((int64_t)data + pattern_offset + 7); - uint8_t new_pattern[9] = "\x66\x83\x05\x00\x00\x00\x00\xFF"; - memcpy(new_pattern+3, &timer_addr, 4); - - if (!find_and_patch_hex(g_game_dll_fn, (char*)new_pattern, 8, 7, "\x00", 1)) - { - LOG("popnhax: attract_full: cannot stop attract mode song timer\n"); - return false; - } - } - LOG("popnhax: attract mode will play full songs\n"); - return true; -} - static bool patch_afp_framerate(uint16_t fps) { DWORD framerate = fps; @@ -8700,6 +8643,11 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserv patch_autopin(); } + if (config.attract_interactive) + { + patch_attract_interactive(); + } + if (config.attract_ex) { patch_ex_attract();