From 9662dd745456bac922c669e924de7a4bf80516ab Mon Sep 17 00:00:00 2001 From: Michal Chvila Date: Mon, 30 Jul 2018 15:21:41 +0200 Subject: [PATCH] plugin: Add hacky support for Adrenaline titles Signed-off-by: Michal Chvila --- plugin/CMakeLists.txt | 1 + plugin/main.c | 187 ++++++++++++++++++++++++++++++++++-------- 2 files changed, 155 insertions(+), 33 deletions(-) diff --git a/plugin/CMakeLists.txt b/plugin/CMakeLists.txt index 4379dc2..a105c8f 100644 --- a/plugin/CMakeLists.txt +++ b/plugin/CMakeLists.txt @@ -39,6 +39,7 @@ target_link_libraries(TrackPlug gcc ScePower_stub kuio_stub + SceKernelModulemgr_stub ) set_target_properties(TrackPlug diff --git a/plugin/main.c b/plugin/main.c index 892a9a7..36a4a95 100644 --- a/plugin/main.c +++ b/plugin/main.c @@ -6,34 +6,24 @@ static SceUID hook; static tai_hook_ref_t ref; -static char titleid[16]; + +static char real_titleid[16]; +static char titleid[128]; +static char full_title[128]; + static char fname[256]; +static char fname_title[256]; + static uint64_t playtime = 0; static uint64_t tick = 0; -int sceDisplaySetFrameBuf_patched(const SceDisplayFrameBuf *pParam, int sync) { - - uint64_t t_tick = sceKernelGetProcessTimeWide(); - - // Saving playtime every 10 seconds - if ((t_tick - tick) > 10000000){ - tick = t_tick; - playtime += 10; - SceUID fd; - kuIoOpen(fname, SCE_O_WRONLY | SCE_O_CREAT | SCE_O_TRUNC, &fd); - kuIoWrite(fd, &playtime, sizeof(uint64_t)); - kuIoClose(fd); - } - - return TAI_CONTINUE(int, ref, pParam, sync); -} +static char playtime_loaded = 0; -void _start() __attribute__ ((weak, alias ("module_start"))); -int module_start(SceSize argc, const void *args) { - - // Getting game Title ID - sceAppMgrAppParamGetString(0, 12, titleid , 256); - +static int (* ScePspemuConvertAddress)(uint32_t addr, int mode, uint32_t cache_size); +#define ADRENALINE_ADDRESS 0xABCDE000 +#define ADRENALINE_SIZE 0x2000 + +void load_playtime() { // Getting current playtime SceUID fd; sprintf(fname, "ux0:/data/TrackPlug/%s.bin", titleid); @@ -41,22 +31,153 @@ int module_start(SceSize argc, const void *args) { if (fd >= 0){ kuIoRead(fd, &playtime, sizeof(uint64_t)); kuIoClose(fd); + } else { + playtime = 0; } - + playtime_loaded = 1; +} + +int get_pspemu_title() { + void *adrenaline = (void *)ScePspemuConvertAddress(ADRENALINE_ADDRESS, 0x1/*KERMIT_INPUT_MODE*/, ADRENALINE_SIZE); + if (adrenaline <= 0) + return 0; + + char *title = adrenaline + 0x18; + + if (title[0] == 0 || strncmp(title, "XMB", 3) == 0) + return 0; + + // Game changed? + if (strcmp(full_title, title) != 0) { + playtime_loaded = 0; + } + + strcpy(full_title, title); + + titleid[0] = 'P'; + titleid[1] = 'S'; + titleid[2] = 'P'; + titleid[3] = '_'; + int j = 4, i = 0; + + while (j < sizeof(titleid) - 1 && title[i] != 0) { + if ((title[i] >= 'A' && title[i] <= 'Z') || + (title[i] >= 'a' && title[i] <= 'z') || + (title[i] >= '0' && title[i] <= '9')) { + titleid[j++] = title[i]; + } + i++; + } + + // Pad to min 9 chars, prevent app crashes + while (j < 9) { + titleid[j++] = 'x'; + } + + titleid[j] = 0; + + return 1; +} + +void write_pspemu_title() { + char buffer[128]; + snprintf(buffer, sizeof(buffer), "[PSP] "); + int i = 0, j = 6; + while (j < sizeof(buffer) && full_title[i] != 0) { + // Strip invalid chars + if (full_title[i] >= 32 && full_title[i] <= 126) { + buffer[j++] = full_title[i]; + } + i++; + } + buffer[j++] = 0; + + SceUID fd; + sprintf(fname_title, "ux0:/data/TrackPlugArchive/%s.txt", titleid); + kuIoOpen(fname_title, SCE_O_RDONLY, &fd); + if (fd < 0){ + kuIoOpen(fname_title, SCE_O_WRONLY|SCE_O_CREAT, &fd); + if (fd >= 0) { + kuIoWrite(fd, buffer, strlen(buffer)); + kuIoClose(fd); + } + } +} + +int sceDisplaySetFrameBuf_patched(const SceDisplayFrameBuf *pParam, int sync) { + + uint64_t t_tick = sceKernelGetProcessTimeWide(); + + // Saving playtime every 10 seconds + if ((t_tick - tick) > 10000000){ + // If in PspEmu + if (strcmp(real_titleid, "NPXS10028") == 0) { + if (get_pspemu_title()) { + // New game? + if (!playtime_loaded) { + load_playtime(); + write_pspemu_title(); + } + } else { + // No game running + playtime_loaded = 0; + } + } + + if (!playtime_loaded) { + goto exit; + } + + tick = t_tick; + playtime += 10; + SceUID fd; + kuIoOpen(fname, SCE_O_WRONLY | SCE_O_CREAT | SCE_O_TRUNC, &fd); + kuIoWrite(fd, &playtime, sizeof(uint64_t)); + kuIoClose(fd); + } + +exit: + return TAI_CONTINUE(int, ref, pParam, sync); +} + +void _start() __attribute__ ((weak, alias ("module_start"))); +int module_start(SceSize argc, const void *args) { + + // Getting game Title ID + sceAppMgrAppParamGetString(0, 12, real_titleid , 256); + + // PspEmu game? + if (strcmp(real_titleid, "NPXS10028") == 0) { + // Get ScePspemu tai module info + tai_module_info_t ScePspemu_tai_info; + ScePspemu_tai_info.size = sizeof(tai_module_info_t); + taiGetModuleInfo("ScePspemu", &ScePspemu_tai_info); + + // Module info + SceKernelModuleInfo ScePspemu_mod_info; + ScePspemu_mod_info.size = sizeof(SceKernelModuleInfo); + sceKernelGetModuleInfo(ScePspemu_tai_info.modid, &ScePspemu_mod_info); + + // Addresses + uint32_t text_addr = (uint32_t)ScePspemu_mod_info.segments[0].vaddr; + ScePspemuConvertAddress = (void *)(text_addr + 0x6364 + 0x1); + } else { + strcpy(titleid, real_titleid); + load_playtime(); + } + // Getting starting tick tick = sceKernelGetProcessTimeWide(); - + hook = taiHookFunctionImport(&ref, - TAI_MAIN_MODULE, - TAI_ANY_LIBRARY, - 0x7A410B64, - sceDisplaySetFrameBuf_patched); - + TAI_MAIN_MODULE, + TAI_ANY_LIBRARY, + 0x7A410B64, + sceDisplaySetFrameBuf_patched); + return SCE_KERNEL_START_SUCCESS; } int module_stop(SceSize argc, const void *args) { - return SCE_KERNEL_STOP_SUCCESS; - -} \ No newline at end of file +}