merging Electry's changes so pspemu also works

This commit is contained in:
Furkan Mudanyali 2020-03-15 13:41:20 +03:00
commit eb898d9cbb
5 changed files with 328 additions and 157 deletions

3
.gitignore vendored
View File

@ -45,3 +45,6 @@ $RECYCLE.BIN/
Network Trash Folder Network Trash Folder
Temporary Items Temporary Items
.apdisk .apdisk
# Build directory
build/

View File

@ -19,51 +19,114 @@ end
tbl = System.listDirectory("ux0:/data/TrackPlug") tbl = System.listDirectory("ux0:/data/TrackPlug")
if tbl == nil then if tbl == nil then
tbl = {} tbl = {}
end end
-- Convert a 32 bit binary string to an integer -- Convert a 32 bit binary string to an integer
function bin2int(str) function bin2int(str)
local b1, b2, b3, b4 = string.byte(str, 1, 4) local b1, b2, b3, b4 = string.byte(str, 1, 4)
return (b4 << 24) + (b3 << 16) + (b2 << 8) + b1 return bit32.lshift(b4, 24) + bit32.lshift(b3, 16) + bit32.lshift(b2, 8) + b1
end end
-- Format raw time data -- Format raw time data
function FormatTime(val) function FormatTime(val)
local minutes = math.floor(val/60) local minutes = math.floor(val/60)
local seconds = val%60 local seconds = val%60
local hours = math.floor(minutes/60) local hours = math.floor(minutes/60)
local minutes = minutes%60 local minutes = minutes%60
local res = "" local res = ""
if hours > 0 then if hours > 0 then
res = hours .. "h " res = hours .. "h "
end end
if minutes > 0 then if minutes > 0 then
res = res .. minutes .. "m " res = res .. minutes .. "m "
end end
res = res .. seconds .. "s " res = res .. seconds .. "s "
return res return res
end end
-- Recover title from homebrew database -- Recover title from homebrew database
function recoverTitle(tid) function recoverTitle(tid)
local file = System.openFile("ux0:/data/TrackPlugArchive/" .. tid .. ".txt", FREAD) local file = System.openFile("ux0:/data/TrackPlugArchive/" .. tid .. ".txt", FREAD)
fsize = System.sizeFile(file) fsize = System.sizeFile(file)
local title = System.readFile(file, fsize) local title = System.readFile(file, fsize)
System.closeFile(file) System.closeFile(file)
return title return title
end end
-- Extracts title name from an SFO file -- Extracts title name from an SFO file
function extractTitle(file, tid) function extractTitle(file, tid)
local data = System.extractSFO(file) local data = System.extractSfo(file)
if System.doesFileExist("ux0:/data/TrackPlugArchive/" .. tid .. ".txt") then if System.doesFileExist("ux0:/data/TrackPlugArchive/" .. tid .. ".txt") then
System.deleteFile("ux0:/data/TrackPlugArchive/" .. tid .. ".txt") System.deleteFile("ux0:/data/TrackPlugArchive/" .. tid .. ".txt")
end end
local file = System.openFile("ux0:/data/TrackPlugArchive/" .. tid .. ".txt", FCREATE) local file = System.openFile("ux0:/data/TrackPlugArchive/" .. tid .. ".txt", FCREATE)
System.writeFile(file, data.title, string.len(data.title)) System.writeFile(file, data.title, string.len(data.title))
System.closeFile(file) System.closeFile(file)
return data.title return data.title
end
function getRegion(titleid)
local regioncode = string.sub(titleid,1,4)
local prefix = string.sub(regioncode,1,2)
local region = "Unknown"
-- PSV common
if regioncode == "PCSA" or regioncode == "PCSE" then
region = "USA"
elseif regioncode == "PCSB" or regioncode == "PCSF" then
region = "Europe"
elseif regioncode == "PCSC" or regioncode == "PCSG" then
region = "Japan"
elseif regioncode == "PCSD" or regioncode == "PCSH" then
region = "Asia"
-- Physical & NP releases (PSV/PSP/PS1)
elseif prefix == "VC" or prefix == "VL" or
prefix == "UC" or prefix == "UL" or
prefix == "SC" or prefix == "SL" or
prefix == "NP" then
n1 = string.sub(regioncode,1,1)
n3 = string.sub(regioncode,3,3)
n4 = string.sub(regioncode,4,4)
if n3 == "A" then
region = "Asia"
elseif n3 == "C" then
region = "China"
elseif n3 == "E" then
region = "Europe"
elseif n3 == "H" then
region = "Hong Kong"
elseif n3 == "J" or n3 == "P" then
region = "Japan"
elseif n3 == "K" then
region = "Korea"
elseif n3 == "U" then
region = "USA"
end
if n1 == "S" then
region = region .. " (PS1)"
elseif n1 == "U" or
(prefix == "NP" and (n4 == "G" or n4 == "H")) then
region = region .. " (PSP)"
elseif prefix == "NP" then
if n4 == "E" or n4 == "F" then
region = region .. " (PS1 - PAL)"
elseif n4 == "I" or n4 == "J" then
region = region .. " (PS1 - NTSC)"
end
end
elseif prefix == "PE" then
region = "Europe (PS1)"
elseif prefix == "PT" then
region = "Asia (PS1)"
elseif prefix == "PU" then
region = "USA (PS1)"
elseif string.sub(file.name,1,6) == "PSPEMU" then
region = "PSP/PS1"
end
return region
end end
-- Loading unknown icon -- Loading unknown icon
@ -71,46 +134,34 @@ local unk = Graphics.loadImage("app0:/unk.png")
-- Getting region, playtime, icon and title name for any game -- Getting region, playtime, icon and title name for any game
for i, file in pairs(tbl) do for i, file in pairs(tbl) do
if file.name == "config.lua" then if file.name == "config.lua" then
dofile("ux0:/data/TrackPlug/"..file.name) dofile("ux0:/data/TrackPlug/"..file.name)
cfg_idx = i cfg_idx = i
else else
local titleid = string.sub(file.name,1,-5) local titleid = string.sub(file.name,1,-5)
local regioncode = string.sub(file.name,1,4) file.region = getRegion(titleid)
if regioncode == "PCSA" or regioncode == "PCSE" then
file.region = "USA" if System.doesFileExist("ur0:/appmeta/" .. titleid .. "/icon0.png") then
elseif regioncode == "PCSB" then file.icon = Graphics.loadImage("ur0:/appmeta/" .. titleid .. "/icon0.png")
file.region = "EUR" else
elseif regioncode == "PCSF" then file.icon = unk
file.region = "AUS" end
elseif regioncode == "PCSG" then if System.doesFileExist("ux0:/data/TrackPlugArchive/" .. titleid .. ".txt") then
file.region = "JPN" file.title = recoverTitle(titleid)
elseif regioncode == "PCSH" then elseif System.doesFileExist("ux0:/app/" .. titleid .. "/sce_sys/param.sfo") then
file.region = "ASN" file.title = extractTitle("ux0:/app/" .. titleid .. "/sce_sys/param.sfo", titleid)
else else
file.region = "UNK" file.title = "Unknown Title"
end end
if System.doesFileExist("ur0:/appmeta/" .. titleid .. "/icon0.png") then file.id = titleid
file.icon = Graphics.loadImage("ur0:/appmeta/" .. titleid .. "/icon0.png") fd = System.openFile("ux0:/data/TrackPlug/" .. file.name, FREAD)
else file.rtime = bin2int(System.readFile(fd, 4))
file.icon = unk file.ptime = FormatTime(file.rtime)
end System.closeFile(fd)
if System.doesFileExist("ux0:/data/TrackPlugArchive/" .. titleid .. ".txt") then end
file.title = recoverTitle(titleid)
elseif System.doesFileExist("ux0:/app/" .. titleid .. "/sce_sys/param.sfo") then
file.title = extractTitle("ux0:/app/" .. titleid .. "/sce_sys/param.sfo", titleid)
else
file.title = "Unknown Title"
end
file.id = titleid
fd = System.openFile("ux0:/data/TrackPlug/" .. file.name, FREAD)
file.rtime = bin2int(System.readFile(fd, 4))
file.ptime = FormatTime(file.rtime)
System.closeFile(fd)
end
end end
if cfg_idx ~= nil then if cfg_idx ~= nil then
table.remove(tbl, cfg_idx) table.remove(tbl, cfg_idx)
end end
-- Background wave effect -- Background wave effect
@ -179,23 +230,23 @@ local grey = Color.new(40, 40, 40)
local alarm_val = 128 local alarm_val = 128
local alarm_decrease = true local alarm_decrease = true
function showAlarm(title, select_idx) function showAlarm(title, select_idx)
if alarm_decrease then if alarm_decrease then
alarm_val = alarm_val - 4 alarm_val = alarm_val - 4
if alarm_val == 40 then if alarm_val == 40 then
alarm_decrease = false alarm_decrease = false
end end
else else
alarm_val = alarm_val + 4 alarm_val = alarm_val + 4
if alarm_val == 128 then if alarm_val == 128 then
alarm_decrease = true alarm_decrease = true
end end
end end
local sclr = Color.new(alarm_val, alarm_val, alarm_val) local sclr = Color.new(alarm_val, alarm_val, alarm_val)
Graphics.fillRect(200, 760, 200, 280, grey) Graphics.fillRect(200, 760, 200, 280, grey)
Graphics.debugPrint(205, 205, title, yellow) Graphics.debugPrint(205, 205, title, yellow)
Graphics.fillRect(200, 760, 215 + select_idx * 20, 235 + select_idx * 20, sclr) Graphics.fillRect(200, 760, 215 + select_idx * 20, 235 + select_idx * 20, sclr)
Graphics.debugPrint(205, 235, "Yes", white) Graphics.debugPrint(205, 235, "Yes", white)
Graphics.debugPrint(205, 255, "No", white) Graphics.debugPrint(205, 255, "No", white)
end end
-- Scroll-list Renderer -- Scroll-list Renderer
local sel_val = 128 local sel_val = 128
@ -322,10 +373,10 @@ end
-- No games played yet apparently -- No games played yet apparently
while true do while true do
Graphics.initBlend() Graphics.initBlend()
Screen.clear() Screen.clear()
Graphics.debugPrint(5, 5, "No games tracked yet.", white) Graphics.debugPrint(5, 5, "No games tracked yet.", white)
Graphics.termBlend() Graphics.termBlend()
Screen.flip() Screen.flip()
Screen.waitVblankStart() Screen.waitVblankStart()
end end

View File

@ -8,7 +8,7 @@ if(NOT DEFINED CMAKE_TOOLCHAIN_FILE)
endif() endif()
endif() endif()
project(TrackPlug) project(TrackPlugX)
include("${VITASDK}/share/vita.cmake" REQUIRED) include("${VITASDK}/share/vita.cmake" REQUIRED)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wl,-q -Wall -O3 -std=gnu99") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wl,-q -Wall -O3 -std=gnu99")
@ -25,26 +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 SceKernelModulemgr_stub
ScePower_stub SceKernelThreadMgr_stub
kuio_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
) )

6
plugin/TrackPlug.yml → plugin/TrackPlugX.yml Normal file → Executable file
View File

@ -1,8 +1,8 @@
TrackPlug: TrackPlugX:
attributes: 0 attributes: 0
version: version:
major: 1 major: 2
minor: 2 minor: 1
main: main:
start: module_start start: module_start
stop: module_stop stop: module_stop

View File

@ -1,62 +1,180 @@
#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 titleid[16];
static char fname[256];
static uint64_t playtime = 0;
static uint64_t tick = 0;
int sceDisplaySetFrameBuf_patched(const SceDisplayFrameBuf *pParam, int sync) { int snprintf(char *s, size_t n, const char *format, ...);
uint64_t t_tick = sceKernelGetProcessTimeWide(); // ScePspemu
static SceUID sub_810053F8_hookid = -1;
static tai_hook_ref_t sub_810053F8_hookref = {0};
// Saving playtime every 10 seconds static char adrenaline_titleid[12];
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 uint8_t is_pspemu_loaded = 0;
static uint8_t is_pspemu_custom_bbl = 0;
static uint8_t is_pspemu_title_written = 0;
static uint8_t is_playtime_loaded = 0;
static char playtime_bin_path[128];
static uint64_t playtime_start = 0;
static uint64_t tick_start = 0;
static void load_playtime(const char *titleid) {
snprintf(playtime_bin_path, 128, "ux0:/data/TrackPlug/%s.bin", titleid);
tick_start = sceKernelGetProcessTimeWide();
is_pspemu_title_written = 0;
SceUID fd = sceIoOpen(playtime_bin_path, SCE_O_RDONLY, 0777);
if (fd < 0) {
playtime_start = 0;
is_playtime_loaded = 1;
return;
}
sceIoRead(fd, &playtime_start, sizeof(uint64_t));
sceIoClose(fd);
is_playtime_loaded = 1;
}
static void write_playtime() {
uint32_t playtime = playtime_start +
(sceKernelGetProcessTimeWide() - tick_start) / SECOND;
SceUID fd = sceIoOpen(playtime_bin_path,
SCE_O_WRONLY | SCE_O_CREAT | SCE_O_TRUNC, 0777);
if (fd < 0) {
return;
}
sceIoWrite(fd, &playtime, sizeof(uint64_t));
sceIoClose(fd);
}
void write_title(const char *titleid, const char *title) {
char path[128];
snprintf(path, 128, "ux0:/data/TrackPlugArchive/%s.txt", titleid);
is_pspemu_title_written = 1;
// Check if already exists
SceUID fd = sceIoOpen(path, SCE_O_RDONLY, 0777);
if (fd >= 0) {
sceIoClose(fd);
return;
}
fd = sceIoOpen(path, SCE_O_WRONLY | SCE_O_CREAT, 0777);
if (fd < 0) {
return;
}
sceIoWrite(fd, title, strlen(title));
sceIoClose(fd);
}
static int check_adrenaline() {
void *SceAdrenaline = (void *)0x73CDE000;
char *title = SceAdrenaline + 24;
char *titleid = SceAdrenaline + 152;
if (title[0] == 0 || !strncmp(title, "XMB", 3))
return 0;
// Write custom bubble Title
if (is_pspemu_custom_bbl && !is_pspemu_title_written)
write_title(adrenaline_titleid, title);
// XMB game changed?
if (!is_pspemu_custom_bbl && strncmp(adrenaline_titleid, titleid, 9)) {
if (is_playtime_loaded)
write_playtime(); // Save closed game
is_playtime_loaded = 0;
strcpy(adrenaline_titleid, titleid);
load_playtime(titleid);
write_title(titleid, title);
return 0;
}
return 1;
}
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;
strcpy(adrenaline_titleid, pspemu_titleid);
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) {
if (is_pspemu_loaded) {
// Check if XMB/game has changed, write Title if necessary
int ret = check_adrenaline();
if (!is_pspemu_custom_bbl && !ret) {
goto CONT;
}
}
if (is_playtime_loaded) {
write_playtime();
}
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) {
char titleid[12];
sceAppMgrAppParamGetString(0, 12, titleid, 12);
// Getting game Title ID if (!strncmp(titleid, "NPXS10028", 9)) {
sceAppMgrAppParamGetString(0, 12, titleid , 256); tai_module_info_t tai_info;
tai_info.size = sizeof(tai_module_info_t);
taiGetModuleInfo("ScePspemu", &tai_info);
// Getting current playtime sub_810053F8_hookid = taiHookFunctionOffset(
SceUID fd; &sub_810053F8_hookref,
sprintf(fname, "ux0:/data/TrackPlug/%s.bin", titleid); tai_info.modid,
kuIoOpen(fname, SCE_O_RDONLY, &fd); 0, 0x53F8, 1,
if (fd >= 0){ sub_810053F8_patched);
kuIoRead(fd, &playtime, sizeof(uint64_t)); } else {
kuIoClose(fd); load_playtime(titleid);
} }
// Getting starting tick SceUID tracker_thread_id = sceKernelCreateThread(
tick = sceKernelGetProcessTimeWide(); "TrackPlugX",
tracker_thread,
0x10000100,
0x10000,
0, 0, NULL);
if (tracker_thread_id >= 0)
sceKernelStartThread(tracker_thread_id, 0, NULL);
hook = taiHookFunctionImport(&ref, return SCE_KERNEL_START_SUCCESS;
TAI_MAIN_MODULE,
TAI_ANY_LIBRARY,
0x7A410B64,
sceDisplaySetFrameBuf_patched);
return SCE_KERNEL_START_SUCCESS;
} }
int module_stop(SceSize argc, const void *args) { int module_stop(SceSize argc, const void *args) {
if (sub_810053F8_hookid >= 0) {
taiHookRelease(sub_810053F8_hookid, sub_810053F8_hookref);
}
return SCE_KERNEL_STOP_SUCCESS; return SCE_KERNEL_STOP_SUCCESS;
} }