Add full support for Adrenaline
Signed-off-by: Michal Chvila <miso.chvila@gmail.com>
This commit is contained in:
parent
9662dd7454
commit
72c015b63e
@ -25,27 +25,25 @@ if (NOT ${RELEASE})
|
|||||||
add_definitions(-DENABLE_LOGGING)
|
add_definitions(-DENABLE_LOGGING)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_executable(TrackPlug
|
add_executable(${PROJECT_NAME}
|
||||||
main.c
|
main.c
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(TrackPlug
|
target_link_libraries(${PROJECT_NAME}
|
||||||
|
gcc
|
||||||
taihen_stub
|
taihen_stub
|
||||||
SceAppUtil_stub
|
|
||||||
SceAppMgr_stub
|
SceAppMgr_stub
|
||||||
SceLibKernel_stub
|
SceLibKernel_stub
|
||||||
SceDisplay_stub
|
SceIofilemgr_stub
|
||||||
k
|
SceLibc_stub
|
||||||
gcc
|
|
||||||
ScePower_stub
|
|
||||||
kuio_stub
|
|
||||||
SceKernelModulemgr_stub
|
SceKernelModulemgr_stub
|
||||||
|
SceKernelThreadMgr_stub
|
||||||
)
|
)
|
||||||
|
|
||||||
set_target_properties(TrackPlug
|
set_target_properties(${PROJECT_NAME}
|
||||||
PROPERTIES LINK_FLAGS "-nostdlib"
|
PROPERTIES LINK_FLAGS "-nostdlib"
|
||||||
)
|
)
|
||||||
|
|
||||||
vita_create_self(TrackPlug.suprx TrackPlug
|
vita_create_self(${PROJECT_NAME}.suprx ${PROJECT_NAME}
|
||||||
CONFIG ${CMAKE_SOURCE_DIR}/TrackPlug.yml
|
CONFIG ${CMAKE_SOURCE_DIR}/${PROJECT_NAME}.yml
|
||||||
)
|
)
|
||||||
|
279
plugin/main.c
279
plugin/main.c
@ -1,183 +1,172 @@
|
|||||||
#include <vitasdk.h>
|
#include <vitasdk.h>
|
||||||
#include <taihen.h>
|
#include <taihen.h>
|
||||||
#include <kuio.h>
|
|
||||||
#include <libk/string.h>
|
|
||||||
#include <libk/stdio.h>
|
|
||||||
|
|
||||||
static SceUID hook;
|
#define SECOND 1000000
|
||||||
static tai_hook_ref_t ref;
|
#define SAVE_PERIOD 10
|
||||||
|
|
||||||
static char real_titleid[16];
|
int snprintf(char *s, size_t n, const char *format, ...);
|
||||||
static char titleid[128];
|
|
||||||
static char full_title[128];
|
|
||||||
|
|
||||||
static char fname[256];
|
// ScePspemu
|
||||||
static char fname_title[256];
|
static SceUID sub_810053F8_hookid = -1;
|
||||||
|
static tai_hook_ref_t sub_810053F8_hookref = {0};
|
||||||
|
|
||||||
static uint64_t playtime = 0;
|
static char adrenaline_titleid[12];
|
||||||
static uint64_t tick = 0;
|
|
||||||
|
|
||||||
static char playtime_loaded = 0;
|
static uint8_t is_pspemu_loaded = 0;
|
||||||
|
static uint8_t is_pspemu_custom_bbl = 0;
|
||||||
|
static uint8_t is_playtime_loaded = 0;
|
||||||
|
|
||||||
static int (* ScePspemuConvertAddress)(uint32_t addr, int mode, uint32_t cache_size);
|
static char playtime_bin_path[128];
|
||||||
#define ADRENALINE_ADDRESS 0xABCDE000
|
static uint64_t playtime_start = 0;
|
||||||
#define ADRENALINE_SIZE 0x2000
|
static uint64_t tick_start = 0;
|
||||||
|
|
||||||
void load_playtime() {
|
static void load_playtime(const char *titleid) {
|
||||||
// Getting current playtime
|
|
||||||
SceUID fd;
|
snprintf(playtime_bin_path, 128, "ux0:/data/TrackPlug/%s.bin", titleid);
|
||||||
sprintf(fname, "ux0:/data/TrackPlug/%s.bin", titleid);
|
tick_start = sceKernelGetProcessTimeWide();
|
||||||
kuIoOpen(fname, SCE_O_RDONLY, &fd);
|
|
||||||
if (fd >= 0){
|
SceUID fd = sceIoOpen(playtime_bin_path, SCE_O_RDONLY, 0777);
|
||||||
kuIoRead(fd, &playtime, sizeof(uint64_t));
|
if (fd < 0) {
|
||||||
kuIoClose(fd);
|
playtime_start = 0;
|
||||||
} else {
|
is_playtime_loaded = 1;
|
||||||
playtime = 0;
|
return;
|
||||||
}
|
}
|
||||||
playtime_loaded = 1;
|
|
||||||
|
sceIoRead(fd, &playtime_start, sizeof(uint64_t));
|
||||||
|
sceIoClose(fd);
|
||||||
|
|
||||||
|
is_playtime_loaded = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int get_pspemu_title() {
|
static void write_playtime(uint64_t playtime) {
|
||||||
void *adrenaline = (void *)ScePspemuConvertAddress(ADRENALINE_ADDRESS, 0x1/*KERMIT_INPUT_MODE*/, ADRENALINE_SIZE);
|
|
||||||
if (adrenaline <= 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
char *title = adrenaline + 0x18;
|
SceUID fd = sceIoOpen(playtime_bin_path, SCE_O_WRONLY | SCE_O_CREAT | SCE_O_TRUNC, 0777);
|
||||||
|
if (fd < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (title[0] == 0 || strncmp(title, "XMB", 3) == 0)
|
sceIoWrite(fd, &playtime, sizeof(uint64_t));
|
||||||
return 0;
|
sceIoClose(fd);
|
||||||
|
|
||||||
// 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() {
|
void write_title(const char *titleid, const char *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;
|
char path[128];
|
||||||
sprintf(fname_title, "ux0:/data/TrackPlugArchive/%s.txt", titleid);
|
snprintf(path, 128, "ux0:/data/TrackPlugArchive/%s.txt", titleid);
|
||||||
kuIoOpen(fname_title, SCE_O_RDONLY, &fd);
|
|
||||||
if (fd < 0){
|
// Check if already exists
|
||||||
kuIoOpen(fname_title, SCE_O_WRONLY|SCE_O_CREAT, &fd);
|
SceUID fd = sceIoOpen(path, SCE_O_RDONLY, 0777);
|
||||||
if (fd >= 0) {
|
if (fd >= 0) {
|
||||||
kuIoWrite(fd, buffer, strlen(buffer));
|
sceIoClose(fd);
|
||||||
kuIoClose(fd);
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
fd = sceIoOpen(path, SCE_O_WRONLY | SCE_O_CREAT, 0777);
|
||||||
|
if (fd < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sceIoWrite(fd, title, strlen(title));
|
||||||
|
sceIoClose(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
int sceDisplaySetFrameBuf_patched(const SceDisplayFrameBuf *pParam, int sync) {
|
static int check_adrenaline() {
|
||||||
|
void *SceAdrenaline = (void *)0x73CDE000;
|
||||||
|
|
||||||
uint64_t t_tick = sceKernelGetProcessTimeWide();
|
char *title = SceAdrenaline + 24;
|
||||||
|
char *titleid = SceAdrenaline + 152;
|
||||||
|
|
||||||
// Saving playtime every 10 seconds
|
if (title[0] == 0 || !strncmp(title, "XMB", 3))
|
||||||
if ((t_tick - tick) > 10000000){
|
return 0;
|
||||||
// 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) {
|
// Game changed?
|
||||||
goto exit;
|
if (strncmp(adrenaline_titleid, titleid, 9)) {
|
||||||
}
|
is_playtime_loaded = 0;
|
||||||
|
strcpy(adrenaline_titleid, titleid);
|
||||||
|
|
||||||
tick = t_tick;
|
load_playtime(titleid);
|
||||||
playtime += 10;
|
write_title(titleid, title);
|
||||||
SceUID fd;
|
return 0;
|
||||||
kuIoOpen(fname, SCE_O_WRONLY | SCE_O_CREAT | SCE_O_TRUNC, &fd);
|
}
|
||||||
kuIoWrite(fd, &playtime, sizeof(uint64_t));
|
|
||||||
kuIoClose(fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
exit:
|
return 1;
|
||||||
return TAI_CONTINUE(int, ref, pParam, sync);
|
}
|
||||||
|
|
||||||
|
int sub_810053F8_patched(int a1, int a2) {
|
||||||
|
|
||||||
|
char *pspemu_titleid = (char *)(a2 + 68);
|
||||||
|
|
||||||
|
// If using custom bubble
|
||||||
|
if (strncmp(pspemu_titleid, "PSPEMUCFW", 9)) {
|
||||||
|
is_pspemu_custom_bbl = 1;
|
||||||
|
load_playtime(pspemu_titleid);
|
||||||
|
}
|
||||||
|
|
||||||
|
is_pspemu_loaded = 1;
|
||||||
|
|
||||||
|
return TAI_CONTINUE(int, sub_810053F8_hookref, a1, a2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tracker_thread(SceSize args, void *argp) {
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
uint64_t tick_now = sceKernelGetProcessTimeWide();
|
||||||
|
|
||||||
|
if (is_pspemu_loaded) {
|
||||||
|
// Check if XMB/game has changed
|
||||||
|
if (!is_pspemu_custom_bbl && !check_adrenaline()) {
|
||||||
|
goto CONT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!is_playtime_loaded) {
|
||||||
|
goto CONT;
|
||||||
|
}
|
||||||
|
|
||||||
|
write_playtime(playtime_start + (tick_now - tick_start)/SECOND);
|
||||||
|
|
||||||
|
CONT:
|
||||||
|
sceKernelDelayThread(SAVE_PERIOD * SECOND);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sceKernelExitDeleteThread(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _start() __attribute__ ((weak, alias ("module_start")));
|
void _start() __attribute__ ((weak, alias ("module_start")));
|
||||||
int module_start(SceSize argc, const void *args) {
|
int module_start(SceSize argc, const void *args) {
|
||||||
|
|
||||||
// Getting game Title ID
|
char titleid[12];
|
||||||
sceAppMgrAppParamGetString(0, 12, real_titleid , 256);
|
sceAppMgrAppParamGetString(0, 12, titleid, 12);
|
||||||
|
|
||||||
// PspEmu game?
|
if (!strncmp(titleid, "NPXS10028", 9)) {
|
||||||
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
|
tai_module_info_t tai_info;
|
||||||
SceKernelModuleInfo ScePspemu_mod_info;
|
tai_info.size = sizeof(tai_module_info_t);
|
||||||
ScePspemu_mod_info.size = sizeof(SceKernelModuleInfo);
|
taiGetModuleInfo("ScePspemu", &tai_info);
|
||||||
sceKernelGetModuleInfo(ScePspemu_tai_info.modid, &ScePspemu_mod_info);
|
|
||||||
|
|
||||||
// Addresses
|
sub_810053F8_hookid = taiHookFunctionOffset(
|
||||||
uint32_t text_addr = (uint32_t)ScePspemu_mod_info.segments[0].vaddr;
|
&sub_810053F8_hookref,
|
||||||
ScePspemuConvertAddress = (void *)(text_addr + 0x6364 + 0x1);
|
tai_info.modid,
|
||||||
} else {
|
0, 0x53F8, 1,
|
||||||
strcpy(titleid, real_titleid);
|
sub_810053F8_patched);
|
||||||
load_playtime();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Getting starting tick
|
} else {
|
||||||
tick = sceKernelGetProcessTimeWide();
|
|
||||||
|
|
||||||
hook = taiHookFunctionImport(&ref,
|
load_playtime(titleid);
|
||||||
TAI_MAIN_MODULE,
|
}
|
||||||
TAI_ANY_LIBRARY,
|
|
||||||
0x7A410B64,
|
|
||||||
sceDisplaySetFrameBuf_patched);
|
|
||||||
|
|
||||||
return SCE_KERNEL_START_SUCCESS;
|
SceUID tracker_thread_id = sceKernelCreateThread("TrackPlugX", tracker_thread, 0x10000100, 0x10000, 0, 0, NULL);
|
||||||
|
if (tracker_thread_id >= 0)
|
||||||
|
sceKernelStartThread(tracker_thread_id, 0, NULL);
|
||||||
|
|
||||||
|
return SCE_KERNEL_START_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int module_stop(SceSize argc, const void *args) {
|
int module_stop(SceSize argc, const void *args) {
|
||||||
return SCE_KERNEL_STOP_SUCCESS;
|
|
||||||
|
if (sub_810053F8_hookid >= 0) {
|
||||||
|
taiHookRelease(sub_810053F8_hookid, sub_810053F8_hookref);
|
||||||
|
}
|
||||||
|
|
||||||
|
return SCE_KERNEL_STOP_SUCCESS;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user