diff --git a/meta/meta.xml b/meta/meta.xml index f399e30..50148f9 100644 --- a/meta/meta.xml +++ b/meta/meta.xml @@ -2,14 +2,14 @@ SaveMii Ryuzaki_MrL original (GabyPCgeeK mod) - 1.2.0.m1 - 20170429000000 + 1.2.0.m2 + 20170707000000 WiiU/vWii Save Manager WiiU/vWii Save Manager -You need to run iosuhax/mocha cfw first in order for this homebrew to work. +You need to run haxchi/iosuhax/mocha cfw first in order for this homebrew to work. This homebrew allows you to backup your Wii U and vWii savegames to the SD card and also restore them. Can also copy saves from NAND<->USB if title is installed to both. Up to 256 backups can be made per title. Backups are stored in sd:/wiiu/backups. tool https://github.com/Ryuzaki-MrL/savemii/releases - \ No newline at end of file + diff --git a/src/lib_easy.c b/src/lib_easy.c index 52b794e..ab444af 100644 --- a/src/lib_easy.c +++ b/src/lib_easy.c @@ -51,6 +51,21 @@ void updateReleasedButtons() { buttons_released = vpad.btns_r; } +bool stickPos(u8 stick, f32 value) { + switch(stick) { + case 0 : + return (value > 0) ? (vpad.lstick.x > value): (vpad.lstick.x < value); + case 1 : + return ((value > 0) ? (vpad.lstick.y > value): (vpad.lstick.y < value)); + case 2 : + return (value > 0) ? (vpad.rstick.x > value): (vpad.rstick.x < value); + case 3 : + return (value > 0) ? (vpad.rstick.y > value): (vpad.rstick.y < value); + default : + return 0; + } +} + int isPressed(int button) { return (buttons_pressed&button); } diff --git a/src/lib_easy.h b/src/lib_easy.h index 27d1867..5b6bef6 100644 --- a/src/lib_easy.h +++ b/src/lib_easy.h @@ -49,6 +49,7 @@ void flipBuffers(); void updatePressedButtons(); void updateHeldButtons(); void updateReleasedButtons(); +bool stickPos(u8 stick, f32 value); int isPressed(int button); int isHeld(int button); int isReleased(int button); diff --git a/src/main.c b/src/main.c index 48aaf65..b46e1fb 100644 --- a/src/main.c +++ b/src/main.c @@ -15,10 +15,11 @@ u8 slot = 0; bool allusers = 0, common = 1; -int menu = 0, mode = 0, task = 0, targ = 0; +int menu = 0, mode = 0, task = 0, targ = 0, tsort = 0, sorta = 1; int cursor = 0, scroll = 0; int cursorb = 0, scrollb = 0; int titleswiiu = 0, titlesvwii = 0; +const char *sortn[4] = {"None", "Name", "Storage", "Storage+Name"}; //just to be able to call async void someFunc(void *arg) { @@ -51,17 +52,45 @@ void MCPHookClose() { mcp_hook_fd = -1; } -Title* loadWiiUTitles() { +int titleSort(const void *c1, const void *c2) +{ + if (tsort==0) { + return ((Title*)c1)->listID - ((Title*)c2)->listID; + } else if (tsort==1) { + return strcmp(((Title*)c1)->shortName,((Title*)c2)->shortName) * sorta; + } else if (tsort==2) { + if (((Title*)c1)->isTitleOnUSB == ((Title*)c2)->isTitleOnUSB) + return 0; + if (((Title*)c1)->isTitleOnUSB) + return 1 * sorta; + if (((Title*)c2)->isTitleOnUSB) + return -1 * sorta; + return 0; + } else if (tsort==3) { + if (((Title*)c1)->isTitleOnUSB && !((Title*)c2)->isTitleOnUSB) + return 1 * sorta; + if (!((Title*)c1)->isTitleOnUSB && ((Title*)c2)->isTitleOnUSB) + return -1 * sorta; + return strcmp(((Title*)c1)->shortName,((Title*)c2)->shortName) * sorta; + } +} + +Title* loadWiiUTitles(int run) { + static char *tList; + static int receivedCount; // Source: haxchi installer - int mcp_handle = MCP_Open(); - int count = MCP_TitleCount(mcp_handle); - int listSize = count*0x61; - char *tList = memalign(32, listSize); - memset(tList, 0, listSize); - int receivedCount = count; - MCP_TitleList(mcp_handle, &receivedCount, tList, listSize); - MCP_Close(mcp_handle); + if (run == 0) { + int mcp_handle = MCP_Open(); + int count = MCP_TitleCount(mcp_handle); + int listSize = count*0x61; + tList = memalign(32, listSize); + memset(tList, 0, listSize); + receivedCount = count; + MCP_TitleList(mcp_handle, &receivedCount, tList, listSize); + MCP_Close(mcp_handle); + return NULL; + } Title* titles = malloc(receivedCount*sizeof(Title)); if (!titles) { @@ -111,9 +140,9 @@ Title* loadWiiUTitles() { free(xmlBuf); } } - + titles[titleswiiu].isTitleDupe = false; - for (int i = 0; i < titleswiiu; i++) { + for (int i = 0; i < titleswiiu; i++) { if ((titles[i].highID == highID) && (titles[i].lowID == lowID)) { titles[titleswiiu].isTitleDupe = true; titles[titleswiiu].dupeID = i; @@ -125,6 +154,7 @@ Title* loadWiiUTitles() { titles[titleswiiu].highID = highID; titles[titleswiiu].lowID = lowID; titles[titleswiiu].isTitleOnUSB = isTitleOnUSB; + titles[titleswiiu].listID = titleswiiu; titleswiiu++; OSScreenClearBufferEx(0, 0); @@ -205,6 +235,7 @@ void unloadTitles(Title* titles) { int Menu_Main(void) { mount_sd_fat("sd"); + loadWiiUTitles(0); int res = IOSUHAX_Open(NULL); if (res < 0) { @@ -233,7 +264,7 @@ int Menu_Main(void) { mount_fs("storage_odd", fsaFd, "/dev/odd03", "/vol/storage_odd_content"); ucls(); - Title* wiiutitles = loadWiiUTitles(); + Title* wiiutitles = loadWiiUTitles(1); Title* wiititles = loadWiiTitles(); int* versionList = (int*)malloc(0x100*sizeof(int)); @@ -242,7 +273,7 @@ int Menu_Main(void) { OSScreenClearBufferEx(0, 0); OSScreenClearBufferEx(1, 0); - console_print_pos(0, 0, "SaveMii v%u.%u.%u", VERSION_MAJOR, VERSION_MINOR, VERSION_MICRO); + console_print_pos(0, 0, "SaveMii v%u.%u.%u.%s", VERSION_MAJOR, VERSION_MINOR, VERSION_MICRO, "mod2"); console_print_pos(0, 1, "--------------------------------------------------"); Title* titles = mode ? wiititles : wiiutitles; @@ -252,11 +283,12 @@ int Menu_Main(void) { switch(menu) { case 0: { // Main Menu entrycount = 2; - console_print_pos(0, 2, " Wii U Save Management"); - console_print_pos(0, 3, " vWii Save Management"); + console_print_pos(0, 2, " Wii U Save Management (%u Title%s)", titleswiiu, (titleswiiu > 1) ? "s": ""); + console_print_pos(0, 3, " vWii Save Management (%u Title%s)", titlesvwii, (titlesvwii > 1) ? "s": ""); console_print_pos(0, 2 + cursor, "->"); } break; case 1: { // Select Title + console_print_pos(30, 0, "Sort: %s %s", sortn[tsort], (tsort > 0) ? ((sorta == 1) ? "v": "^"): ""); entrycount = count; for (int i = 0; i < 14; i++) { if (i+scroll<0 || i+scroll>=count) break; @@ -276,7 +308,7 @@ int Menu_Main(void) { console_print_pos(0, 7, " Copy Savedata to Title in %s", titles[targ].isTitleOnUSB ? "NAND" : "USB"); } } - + console_print_pos(0, 2 + cursor, "->"); } break; @@ -288,7 +320,9 @@ int Menu_Main(void) { else console_print_pos(0, 3, " < %03u > (%s)", slot, isSlotEmpty(titles[targ].highID, titles[targ].lowID, slot) ? "Empty" : "Used"); if (mode==0) { console_print_pos(0, 5, "Select user:"); - console_print_pos(0, 6, " < %s >", (allusers&&((task<3) || task==5)) ? "all users" : "this user"); + char usrPath[16]; + getUserID(usrPath); + console_print_pos(0, 6, " < %s > %s", (allusers&&((task<3) || task==5)) ? "all users" : "this user", (allusers&&((task<3) || task==5)) ? "" : usrPath); console_print_pos(0, 8, "Include 'common' save?"); console_print_pos(0, 9, " < %s >", common ? "yes" : "no "); console_print_pos(0, 3 + cursor*3, "->"); @@ -305,13 +339,13 @@ int Menu_Main(void) { updatePressedButtons(); updateHeldButtons(); - if (isPressed(VPAD_BUTTON_DOWN) || isHeld(VPAD_BUTTON_DOWN)) { + if (isPressed(VPAD_BUTTON_DOWN) || isHeld(VPAD_BUTTON_DOWN) || stickPos(1, -0.7)) { if (entrycount<=14) cursor = (cursor + 1) % entrycount; else if (cursor < 6) cursor++; else if ((cursor+scroll+1) % entrycount) scroll++; else cursor = scroll = 0; usleep(100000); - } else if (isPressed(VPAD_BUTTON_UP) || isHeld(VPAD_BUTTON_UP)) { + } else if (isPressed(VPAD_BUTTON_UP) || isHeld(VPAD_BUTTON_UP) || stickPos(1, 0.7)) { if (scroll > 0) cursor -= (cursor>6) ? 1 : 0*(scroll--); else if (cursor > 0) cursor--; else if (entrycount>14) scroll = entrycount - (cursor = 6) - 1; @@ -319,7 +353,7 @@ int Menu_Main(void) { usleep(100000); } - if (isPressed(VPAD_BUTTON_LEFT) || isHeld(VPAD_BUTTON_LEFT)) { + if (isPressed(VPAD_BUTTON_LEFT) || isHeld(VPAD_BUTTON_LEFT) || stickPos(0, -0.7)) { if (menu==3) { switch(cursor) { case 0: slot--; break; @@ -328,7 +362,7 @@ int Menu_Main(void) { } } usleep(100000); - } else if (isPressed(VPAD_BUTTON_RIGHT) || isHeld(VPAD_BUTTON_RIGHT)) { + } else if (isPressed(VPAD_BUTTON_RIGHT) || isHeld(VPAD_BUTTON_RIGHT) || stickPos(0, 0.7)) { if (menu==3) { switch(cursor) { case 0: slot++; break; @@ -339,6 +373,15 @@ int Menu_Main(void) { usleep(100000); } + if (isPressed(VPAD_BUTTON_R) && (menu==1)) { + tsort = (tsort + 1) % 4; + qsort(wiiutitles, titleswiiu, sizeof(Title), titleSort); + } + + if (isPressed(VPAD_BUTTON_L) && (menu==1) && (tsort > 0)) { + sorta *= -1; + qsort(wiiutitles, titleswiiu, sizeof(Title), titleSort); + } if (isPressed(VPAD_BUTTON_A)) { ucls(); if (menu<3) { @@ -355,8 +398,8 @@ int Menu_Main(void) { } if (menu==1) { targ = cursor+scroll; - cursorb = cursor; - scrollb = scroll; + cursorb = cursor; + scrollb = scroll; if (titles[targ].highID==0 || titles[targ].lowID==0) continue; } if (menu==2) { diff --git a/src/savemng.c b/src/savemng.c index e7c9192..d399ca6 100644 --- a/src/savemng.c +++ b/src/savemng.c @@ -328,8 +328,8 @@ void copySavedata(Title* title, Title* titleb, bool allusers, bool common) { if (!promptConfirm("Are you sure?")) return; int slotb = getEmptySlot(titleb->highID, titleb->lowID); if (slotb>=0 && promptConfirm("Backup current savedata first?")) { - backupSavedata(titleb, slotb, allusers, common); - promptError("Backup done. Now copying Savedata."); + backupSavedata(titleb, slotb, allusers, common); + promptError("Backup done. Now copying Savedata."); } char srcPath[PATH_SIZE]; diff --git a/src/savemng.h b/src/savemng.h index cf2659e..0e084ad 100644 --- a/src/savemng.h +++ b/src/savemng.h @@ -19,6 +19,7 @@ extern "C" { typedef struct { u32 highID; u32 lowID; + u16 listID; char shortName[256]; char productCode[32]; bool isTitleOnUSB; @@ -29,6 +30,7 @@ typedef struct { void console_print_pos(int x, int y, const char* format, ...); bool promptConfirm(const char* question); void promptError(const char* message); +void getUserID(char* out); int getLoadiineGameSaveDir(char* out, const char* productCode); int getLoadiineSaveVersionList(int* out, const char* gamePath);