diff --git a/popnhax/custom_categs.cc b/popnhax/custom_categs.cc index cf68ac7..00eb695 100644 --- a/popnhax/custom_categs.cc +++ b/popnhax/custom_categs.cc @@ -21,6 +21,7 @@ uint32_t g_playerdata_ptr_addr; //pointer to the playerdata memory zone (offset 0x08 is popn friend ID as ascii (12 char long), offset 0x1A5 is "is logged in" flag) char *g_current_friendid; +uint32_t g_current_songid; void (*add_song_in_list)(); //game code takes array start address from offset 0xC and the address after the list end from offset 0x10 @@ -51,6 +52,29 @@ uint32_t favorites_count = 0; songlist_t favorites_struct; uint32_t favorites_struct_addr = (uint32_t)&favorites_struct; +void add_song_to_favorites() +{ + favorites = (uint32_t *) realloc(favorites, sizeof(uint32_t)*(favorites_count+5)); + favorites[favorites_count++] = g_current_songid | 0x00060000; // game wants this otherwise only easy difficulty will appear + return; +} +void remove_song_from_favorites() +{ + for (uint32_t i = 0; i < favorites_count; i++) + { + if ( g_current_songid == (favorites[i] & 0x0000FFFF) ) + { + for (uint32_t j = i+1; j < favorites_count; j++) + { + favorites[j-1] = favorites[j]; + } + favorites_count--; + return; + } + } + return; +} + void prepare_favorite_list(){ char fav_filepath[64]; @@ -77,8 +101,8 @@ void prepare_favorite_list(){ int songid = strtol(line, NULL, 10); if ( songid != 0 ) { - favorites = (uint32_t *) realloc(favorites, sizeof(uint32_t)*(favorites_count+5)); - favorites[favorites_count++] = songid | 0x00060000; // game wants this otherwise only easy difficulty will appear + g_current_songid = songid; + add_song_to_favorites(); } } fclose(file); @@ -86,6 +110,93 @@ void prepare_favorite_list(){ return; } +void commit_favorites() +{ + if ( favorites_count == 0 ) + return; + + char fav_filepath[64]; + sprintf(fav_filepath, "data_mods\\%s.fav", g_current_friendid); + FILE *file = fopen(fav_filepath, "w"); + + if ( file == NULL ) + { + file = fopen("data_mods\\default.fav", "w"); + + if (file == NULL) + { + return; + } + } + + for (uint32_t i = 0; i < favorites_count; i++) + { + fprintf(file, "%d\n", (favorites[i] & 0x0000FFFF)); + } + fclose(file); + return; +} + +void (*real_song_is_in_favorite)(); +void hook_song_is_in_favorite() +{ + __asm("push ecx\n"); + __asm("push edx\n"); + //dx contains songid + __asm("mov _g_current_songid, dx\n"); + + for (uint32_t i = 0; i < favorites_count; i++) + { + if ( g_current_songid == (favorites[i] & 0x0000FFFF) ) + { + __asm("pop edx\n"); + __asm("pop ecx\n"); + __asm("pop ebx\n"); + __asm("mov eax, 0x01\n"); + __asm("ret\n"); + } + } + __asm("pop edx\n"); + __asm("pop ecx\n"); + __asm("pop ebx\n"); + __asm("mov eax, 0x00\n"); + __asm("ret\n"); +} + +void (*real_add_to_favorite)(); +void hook_add_to_favorite() +{ + __asm("push ecx\n"); + //dx contains songid + __asm("mov _g_current_songid, dx\n"); + + add_song_to_favorites(); + commit_favorites(); + + __asm("mov eax, [_favorites_count]\n"); + __asm("mov edx, _g_current_songid\n"); + __asm("pop ecx\n"); + real_add_to_favorite(); +} + + +void (*real_remove_from_favorite)(); +void hook_remove_from_favorite() +{ + //code pushes edi, esi and ebx as well + __asm("push ecx\n"); + __asm("push edx\n"); + //dx contains songid + __asm("mov _g_current_songid, cx\n"); + + remove_song_from_favorites(); + commit_favorites(); + + __asm("pop edx\n"); + __asm("pop ecx\n"); + real_remove_from_favorite(); +} + //this replaces the category handling function ( add_song_in_list is a subroutine called by the game ) void (*real_categ_favorite)(); void categ_inject_favorites() @@ -575,10 +686,6 @@ static bool patch_favorite_categ(const char *game_dll_fn) { return false; } - //uint64_t patch_addr = (int64_t)data + pattern_offset + 0x05 + 0x5A; //call to function when categ is favorites - - - uint64_t function_call_addr = (int64_t)(data + pattern_offset + 0x05 + 0x5A); uint32_t function_offset = *((uint32_t*)(function_call_addr +0x01)); uint64_t function_addr = function_call_addr+5+function_offset; @@ -598,6 +705,36 @@ static bool patch_favorite_categ(const char *game_dll_fn) { g_playerdata_ptr_addr = (*(uint32_t *)(data + pattern_offset + 0x25)); } + //hook result screen to replace 3 functions + { + int64_t pattern_offset = search(data, dllSize, "\xBF\x07\x00\x00\x00\xC6\x85\x61\xD3", 9, 0); + if (pattern_offset == -1) { + LOG("popnhax: custom_favorites: cannot find result screen function\n"); + return false; + } + +//song is in favorite + uint64_t function_call_addr = (int64_t)(data + pattern_offset + 0x5F); + uint32_t function_offset = *((uint32_t*)(function_call_addr +0x01)); + uint64_t function_addr = function_call_addr+5+function_offset; + MH_CreateHook((LPVOID)function_addr, (LPVOID)hook_song_is_in_favorite, + (void **)&real_song_is_in_favorite); + +//add to favorites + uint64_t function2_call_addr = (int64_t)(data + pattern_offset + 0xBA); + uint32_t function2_offset = *((uint32_t*)(function2_call_addr +0x01)); + uint64_t function2_addr = function2_call_addr+5+function2_offset; + MH_CreateHook((LPVOID)function2_addr, (LPVOID)hook_add_to_favorite, + (void **)&real_add_to_favorite); + +//remove from favorites + uint64_t function3_call_addr = (int64_t)(data + pattern_offset + 0x89); + uint32_t function3_offset = *((uint32_t*)(function3_call_addr +0x01)); + uint64_t function3_addr = function3_call_addr+5+function3_offset; + MH_CreateHook((LPVOID)function3_addr, (LPVOID)hook_remove_from_favorite, + (void **)&real_remove_from_favorite); + + } LOG("popnhax: custom_favorites: favorite category handling replaced\n"); return true; }