diff --git a/popnhax/custom_categs.cc b/popnhax/custom_categs.cc index e870383..cf68ac7 100644 --- a/popnhax/custom_categs.cc +++ b/popnhax/custom_categs.cc @@ -19,6 +19,9 @@ #include "minhook/hde32.h" #include "minhook/include/MinHook.h" +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; + void (*add_song_in_list)(); //game code takes array start address from offset 0xC and the address after the list end from offset 0x10 typedef struct songlist_s { @@ -48,12 +51,68 @@ uint32_t favorites_count = 0; songlist_t favorites_struct; uint32_t favorites_struct_addr = (uint32_t)&favorites_struct; +void prepare_favorite_list(){ + + char fav_filepath[64]; + sprintf(fav_filepath, "data_mods\\%s.fav", g_current_friendid); + FILE *file = fopen(fav_filepath, "rb"); + + favorites_count = 0; + + if ( file == NULL ) + { + file = fopen("data_mods\\default.fav", "rb"); + + if (file == NULL) + { + return; + } + } + + char line[32]; + + while (fgets(line, sizeof(line), file)) { + /* note that fgets don't strip the terminating \n, checking its + presence would allow to handle lines longer that sizeof(line) */ + 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 + } + } + fclose(file); + //printf("added %d songs from %s to favorites\n",favorites_count,fav_filepath); + return; +} + //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() { + __asm("add esp, 0xC"); // cancel a sub esp 0xC that is added by this code for no reason __asm("push ecx\n"); __asm("push edx\n"); + + //fake login if necessary + __asm("mov ecx, dword ptr [_g_playerdata_ptr_addr]\n"); + __asm("mov edx, [ecx]\n"); + __asm("add edx, 0x1A5\n"); //offset where result screen is checking to decide if the favorite option should be displayed/handled + __asm("mov ecx, [edx]\n"); + __asm("cmp ecx, 0\n"); + __asm("jne skip_fake_login\n"); + __asm("mov dword ptr [edx], 0xFF000001\n"); + __asm("skip_fake_login:\n"); + + //retrieve songlist according to friend id + __asm("mov ecx, dword ptr [_g_playerdata_ptr_addr]\n"); + __asm("mov edx, [ecx]\n"); + __asm("add edx, 0x08\n"); + __asm("mov _g_current_friendid, edx\n"); + + prepare_favorite_list(); + + //finally prepare songlist struct and inject it in the category favorites_struct.array_start = (uint32_t)favorites; favorites_struct.array_end = (uint32_t)&(favorites[favorites_count]); __asm("pop edx\n"); @@ -527,6 +586,18 @@ static bool patch_favorite_categ(const char *game_dll_fn) { MH_CreateHook((LPVOID)function_addr, (LPVOID)categ_inject_favorites, (void **)&real_categ_favorite); } + //categ_inject_favorites will need to force "logged in" status (for result screen) + { + //this is the same function used in score challenge patch, checking if we're logged in... but now we just directly retrieve the address + int64_t pattern_offset = search(data, dllSize, "\x8B\x01\x8B\x50\x14\xFF\xE2\xC3\xCC\xCC\xCC\xCC", 12, 0); + if (pattern_offset == -1) { + LOG("popnhax: custom_favorites: cannot find check if logged function\n"); + return false; + } + + g_playerdata_ptr_addr = (*(uint32_t *)(data + pattern_offset + 0x25)); + } + LOG("popnhax: custom_favorites: favorite category handling replaced\n"); return true; } @@ -757,11 +828,11 @@ bool load_favorites(){ FILE *file = fopen("data_mods\\default.fav", "rb"); if (file == NULL) - { - return false; - } - -char line[32]; + { + return false; + } + + char line[32]; while (fgets(line, sizeof(line), file)) { /* note that fgets don't strip the terminating \n, checking its diff --git a/popnhax/dllmain.cc b/popnhax/dllmain.cc index e2409d8..9b67792 100644 --- a/popnhax/dllmain.cc +++ b/popnhax/dllmain.cc @@ -3869,7 +3869,7 @@ static bool patch_score_challenge() { int64_t pattern_offset = search(data, dllSize, "\xF7\xD8\x1B\xC0\x40\xC3\xE8", 7, 0); if (pattern_offset == -1) { - LOG("popnhax: score challenge: cannot find check if logged function\n"); + LOG("popnhax: score challenge: cannot find check if normal mode function\n"); return false; }