wip favorites, multiple .fav working, force fav handling on result screen

This commit is contained in:
CrazyRedMachine 2024-04-28 15:01:49 +02:00
parent ed6a3a23f0
commit e838d88269
2 changed files with 77 additions and 6 deletions

View File

@ -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;
}

View File

@ -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;
}