diff --git a/Source/SysVita/UI/MainMenuScreen.cpp b/Source/SysVita/UI/MainMenuScreen.cpp index 20dbbf50..8f58a6eb 100644 --- a/Source/SysVita/UI/MainMenuScreen.cpp +++ b/Source/SysVita/UI/MainMenuScreen.cpp @@ -44,6 +44,8 @@ char selectedRom[256]; char rom_name_filter[128] = {0}; +bool gHasOnlineRomList = false; + struct CompatibilityList { char name[128]; bool playable; @@ -57,6 +59,7 @@ struct CompatibilityList { struct RomSelection { char name[128]; char fullpath[256]; + bool is_online; RomSettings settings; RomID id; u32 size; @@ -119,10 +122,12 @@ void swap(RomSelection *a, RomSelection *b) { u32 sizetmp = a->size; ECicType cictmp = a->cic; CompatibilityList *statustmp = a->status; + bool onlinetmp = a->is_online; sprintf(a->name, b->name); sprintf(a->fullpath, b->fullpath); + a->is_online = b->is_online; a->settings = b->settings; a->id = b->id; a->size = b->size; @@ -132,6 +137,7 @@ void swap(RomSelection *a, RomSelection *b) { sprintf(b->name, nametmp); sprintf(b->fullpath, pathtmp); + b->is_online = onlinetmp; b->settings = settingstmp; b->id = idtmp; b->size = sizetmp; @@ -350,6 +356,7 @@ char *DrawRomSelector() { std::string full_path = rom_folders[i]; full_path += rom_filename; RomSelection *node = (RomSelection*)malloc(sizeof(RomSelection)); + node->is_online = false; sprintf(node->name, rom_filename); sprintf(node->fullpath, full_path.c_str()); if (ROM_GetRomDetailsByFilename(full_path.c_str(), &node->id, &node->size, &node->cic)) { @@ -373,6 +380,28 @@ char *DrawRomSelector() { IO::FindFileClose( find_handle ); } } + + if (gHasOnlineRomList) { + char *p = (char*)temp_download_mem; + while (p) { + char *r = strstr(p, ".v64"); + if (r) { + RomSelection *node = (RomSelection*)malloc(sizeof(RomSelection)); + node->is_online = true; + char *space = strstr(p, " "); + char *last_space = nullptr; + while (space) { + last_space = space; + space = strstr(space + 1, " "); + } + memcpy_neon(node->name, &p[49], (r - &p[49]) + 4); + node->name[(r - last_space) + 3] = 0; + node->next = list; + list = node; + } else break; + p = r + 1; + } + } } if (oldSortOrder != gSortOrder) { @@ -435,10 +464,17 @@ char *DrawRomSelector() { continue; } } + if (p->is_online) { + ImGui::PushStyleColor(ImGuiCol_Button, 0x880015FF); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, 0xFF0000FF); + } if (ImGui::Button(p->name)){ sprintf(selectedRom, p->fullpath); selected = true; } + if (p->is_online) { + ImGui::PopStyleColor(2); + } if (ImGui::IsItemHovered()) hovered = p; p = p->next; } @@ -450,44 +486,48 @@ char *DrawRomSelector() { ImGui::SetNextWindowSize(ImVec2(400, SCR_HEIGHT - 19 * UI_SCALE), ImGuiSetCond_Always); ImGui::Begin("Info Window", nullptr, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoBringToFrontOnFocus); if (hovered) { - if (has_preview_icon = LoadPreview(hovered)) { - ImGui::SetCursorPos(ImVec2(preview_x + PREVIEW_PADDING, preview_y + PREVIEW_PADDING)); - ImGui::Image((void*)preview_icon, ImVec2(preview_width, preview_height)); - } - ImGui::Text("%s: %s", lang_strings[STR_GAME_NAME], hovered->settings.GameName.c_str()); - ImGui::Text("%s: %s", lang_strings[STR_REGION], ROM_GetCountryNameFromID(hovered->id.CountryID)); - ImGui::Text("CRC: %04x%04x-%01x", hovered->id.CRC[0], hovered->id.CRC[1], hovered->id.CountryID); - ImGui::Text("%s: %s", lang_strings[STR_CIC_TYPE], ROM_GetCicName(hovered->cic)); - ImGui::Text("%s: %lu MBs", lang_strings[STR_ROM_SIZE], hovered->size); - ImGui::Text("%s: %s", lang_strings[STR_SAVE_TYPE], ROM_GetSaveTypeName(hovered->settings.SaveType)); - if (hovered->status) { - ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 10); - if (!gBigText) ImGui::Text("%s:", lang_strings[STR_TAGS]); - if (hovered->status->playable) { - ImGui::TextColored(ImVec4(0, 0.75f, 0, 1.0f), "%s", lang_strings[STR_GAME_PLAYABLE]); - if (!gBigText) SetTagDescription(lang_strings[STR_PLAYABLE_DESC]); - } - if (hovered->status->ingame_plus) { - ImGui::TextColored(ImVec4(1.0f, 1.0f, 0, 1.0f), "%s", lang_strings[STR_GAME_INGAME_PLUS]); - if (gBigText) ImGui::SameLine(); - else SetTagDescription(lang_strings[STR_INGAME_PLUS_DESC]); - } - if (hovered->status->ingame_low) { - ImGui::TextColored(ImVec4(1.0f, 0.5f, 0.25f, 1.0f), "%s", lang_strings[STR_GAME_INGAME_MINUS]); - if (!gBigText) SetTagDescription(lang_strings[STR_INGAME_MINUS_DESC]); + if (hovered->is_online) { + ImGui::Text("No info available for net roms."); + } else { + if (has_preview_icon = LoadPreview(hovered)) { + ImGui::SetCursorPos(ImVec2(preview_x + PREVIEW_PADDING, preview_y + PREVIEW_PADDING)); + ImGui::Image((void*)preview_icon, ImVec2(preview_width, preview_height)); } - if (hovered->status->crash) { - ImGui::TextColored(ImVec4(1.0f, 0, 0, 1.0f), "%s", lang_strings[STR_GAME_CRASH]); - if (!gBigText) SetTagDescription(lang_strings[STR_CRASH_DESC]); - } - if (hovered->status->slow) { - if (gBigText) { - ImGui::SameLine(); - ImGui::Text("&"); - ImGui::SameLine(); + ImGui::Text("%s: %s", lang_strings[STR_GAME_NAME], hovered->settings.GameName.c_str()); + ImGui::Text("%s: %s", lang_strings[STR_REGION], ROM_GetCountryNameFromID(hovered->id.CountryID)); + ImGui::Text("CRC: %04x%04x-%01x", hovered->id.CRC[0], hovered->id.CRC[1], hovered->id.CountryID); + ImGui::Text("%s: %s", lang_strings[STR_CIC_TYPE], ROM_GetCicName(hovered->cic)); + ImGui::Text("%s: %lu MBs", lang_strings[STR_ROM_SIZE], hovered->size); + ImGui::Text("%s: %s", lang_strings[STR_SAVE_TYPE], ROM_GetSaveTypeName(hovered->settings.SaveType)); + if (hovered->status) { + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 10); + if (!gBigText) ImGui::Text("%s:", lang_strings[STR_TAGS]); + if (hovered->status->playable) { + ImGui::TextColored(ImVec4(0, 0.75f, 0, 1.0f), "%s", lang_strings[STR_GAME_PLAYABLE]); + if (!gBigText) SetTagDescription(lang_strings[STR_PLAYABLE_DESC]); + } + if (hovered->status->ingame_plus) { + ImGui::TextColored(ImVec4(1.0f, 1.0f, 0, 1.0f), "%s", lang_strings[STR_GAME_INGAME_PLUS]); + if (gBigText) ImGui::SameLine(); + else SetTagDescription(lang_strings[STR_INGAME_PLUS_DESC]); + } + if (hovered->status->ingame_low) { + ImGui::TextColored(ImVec4(1.0f, 0.5f, 0.25f, 1.0f), "%s", lang_strings[STR_GAME_INGAME_MINUS]); + if (!gBigText) SetTagDescription(lang_strings[STR_INGAME_MINUS_DESC]); + } + if (hovered->status->crash) { + ImGui::TextColored(ImVec4(1.0f, 0, 0, 1.0f), "%s", lang_strings[STR_GAME_CRASH]); + if (!gBigText) SetTagDescription(lang_strings[STR_CRASH_DESC]); + } + if (hovered->status->slow) { + if (gBigText) { + ImGui::SameLine(); + ImGui::Text("&"); + ImGui::SameLine(); + } + ImGui::TextColored(ImVec4(0.5f, 0, 1.0f, 1.0f), "%s", lang_strings[STR_GAME_SLOW]); + if (!gBigText) SetTagDescription(lang_strings[STR_SLOW_DESC]); } - ImGui::TextColored(ImVec4(0.5f, 0, 1.0f, 1.0f), "%s", lang_strings[STR_GAME_SLOW]); - if (!gBigText) SetTagDescription(lang_strings[STR_SLOW_DESC]); } } } @@ -503,10 +543,19 @@ char *DrawRomSelector() { vglStopRendering(); if (pendingDownload) { - if (download_file("https://github.com/Rinnegatamante/DaedalusX64-vitaGL/releases/download/Nightly/DaedalusX64.zip", "ux0:data/temp.zip", lang_strings[STR_DLG_DOWNLOAD_DATA], 26 * 1024 * 1024) >= 0) { - extract_file("ux0:data/temp.zip", "ux0:data/"); - sceIoRemove("ux0:data/temp.zip"); - resetRomList(); + switch (cur_download.type) { + case FILE_DOWNLOAD: + { + if (download_file(cur_download.url, TEMP_DOWNLOAD_NAME, cur_download.msg, cur_download.size, true) >= 0) + cur_download.post_func(); + } + break; + case MEM_DOWNLOAD: + { + if (download_file(cur_download.url, TEMP_DOWNLOAD_NAME, cur_download.msg, cur_download.size, false) >= 0) + cur_download.post_func(); + } + break; } pendingDownload = false; } diff --git a/Source/SysVita/UI/Menu.h b/Source/SysVita/UI/Menu.h index febf12db..9431fb09 100644 --- a/Source/SysVita/UI/Menu.h +++ b/Source/SysVita/UI/Menu.h @@ -2,6 +2,7 @@ #include #include "stdafx.h" +#define TEMP_DOWNLOAD_NAME "ux0:data/daedalusx64.tmp" #define FUNC_TO_NAME(x) #x #define stringify(x) FUNC_TO_NAME(x) @@ -239,6 +240,20 @@ enum { ALERT_MESSAGE }; +// Download types +enum { + FILE_DOWNLOAD, + MEM_DOWNLOAD +}; + +struct Download { + void (*post_func)(); + char url[256]; + char msg[128]; + int size; + uint8_t type; +}; + struct Dialog { void (*yes_func)(); void (*no_func)(); @@ -264,6 +279,7 @@ struct Overlay { extern Dialog cur_dialog; extern Alert cur_alert; +extern Download cur_download; extern Overlay *overlays_list; extern PostProcessingEffect *effects_list; @@ -288,6 +304,7 @@ extern bool gUseMipmaps; extern bool gSkipCompatListUpdate; extern bool gAutoUpdate; extern bool gUseRearpad; +extern bool gHasOnlineRomList; extern int gPostProcessing; extern int gOverlay; extern int gSortOrder; @@ -301,6 +318,9 @@ extern bool pendingAlert; extern bool pendingDownload; extern bool custom_path_str_dirty; +extern volatile uint8_t *temp_download_mem; +extern volatile uint32_t temp_download_size; + char *DrawRomSelector(); void DrawInGameMenu(); void DrawMenuBar(); @@ -321,10 +341,11 @@ void stripGameName(char *name); void showDialog(char *text, void (*yes_func)(), void (*no_func)(), int type, char *args); void getDialogTextResult(char *text); void showAlert(char *text, int type); +void queueDownload(char *text, char *url, int size, void (*post_func)(), int type); void reloadFont(); void resetRomList(); void extract_file(char *file, char *dir); -int download_file(char *url, char *file, char *msg, float int_total_bytes); +int download_file(char *url, char *file, char *msg, float int_total_bytes, bool has_temp_file); void dummy_func(); diff --git a/Source/SysVita/UI/MenuBarScreen.cpp b/Source/SysVita/UI/MenuBarScreen.cpp index 762beb98..a4eac160 100644 --- a/Source/SysVita/UI/MenuBarScreen.cpp +++ b/Source/SysVita/UI/MenuBarScreen.cpp @@ -125,6 +125,12 @@ void loadShader(int idx, char *file) free(code); } +void install_data_files() { + extract_file(TEMP_DOWNLOAD_NAME, "ux0:data/"); + sceIoRemove(TEMP_DOWNLOAD_NAME); + resetRomList(); +} + void saveCustomRomPath() { sceIoMkdir(DAEDALUS_VITA_PATH("Configs/"), 0777); @@ -208,6 +214,11 @@ void change_custom_rom_path () { custom_path_str_dirty = true; } +void set_net_folder () { + gHasOnlineRomList = true; + resetRomList(); +} + void SetupVFlux() { colors = (float*)malloc(sizeof(float)*4*4); vflux_vertices = (float*)malloc(sizeof(float)*3*4); @@ -844,12 +855,16 @@ void DrawMenuBar() { if (ImGui::BeginMainMenuBar()){ if (ImGui::BeginMenu(lang_strings[STR_MENU_OPTIONS])) { if (ImGui::MenuItem(lang_strings[STR_DOWNLOAD_DATA])) { - pendingDownload = true; + queueDownload(lang_strings[STR_DLG_DOWNLOAD_DATA], "https://github.com/Rinnegatamante/DaedalusX64-vitaGL/releases/download/Nightly/DaedalusX64.zip", 26 * 1024 * 1024, install_data_files, FILE_DOWNLOAD); } ImGui::Separator(); if (ImGui::MenuItem(custom_path_str)) { showDialog(lang_strings[STR_DLG_CUSTOM_PATH], change_custom_rom_path, dummy_func, DIALOG_KEYBOARD, gCustomRomPath); } + /*if (ImGui::MenuItem("Test")) { // Future net roms support, disabled for now since libcurl has no FTP protocol support + queueDownload(lang_strings[STR_DLG_DOWNLOAD_DATA], "TESTLINKHERE", 1024, set_net_folder, MEM_DOWNLOAD); + }*/ + ImGui::Separator(); if (ImGui::BeginMenu(lang_strings[STR_MENU_SORT_ROMS])){ if (ImGui::MenuItem(lang_strings[STR_SORT_A_TO_Z], nullptr, gSortOrder == SORT_A_TO_Z)){ gSortOrder = SORT_A_TO_Z; diff --git a/Source/SysVita/main.cpp b/Source/SysVita/main.cpp index a7c1de41..86d34cb8 100644 --- a/Source/SysVita/main.cpp +++ b/Source/SysVita/main.cpp @@ -39,8 +39,8 @@ #include "UI/Menu.h" #include "minizip/unzip.h" -#define NET_INIT_SIZE 1*1024*1024 -#define TEMP_DOWNLOAD_NAME "ux0:data/DaedalusX64/tmp.bin" +#define NET_INIT_SIZE 1*1024*1024 +#define NET_TEMP_MEM_SIZE 1*1024*1024 bool gSkipCompatListUpdate = false; bool gStandaloneMode = true; @@ -55,6 +55,7 @@ int console_language; Dialog cur_dialog; Alert cur_alert; +Download cur_download; extern "C" { int32_t sceKernelChangeThreadVfpException(int32_t clear, int32_t set); @@ -74,6 +75,9 @@ char *bytes_string; static SceUID net_mutex; static bool sys_initialized = false; +volatile uint8_t *temp_download_mem = nullptr; +volatile uint32_t temp_download_size = 0; + int gUseCdram = GL_TRUE; int gUseVSync = GL_TRUE; @@ -167,13 +171,22 @@ void EnableMenuButtons(bool status) { ImGui_ImplVitaGL_MouseStickUsage(status); } -static size_t write_cb(void *ptr, size_t size, size_t nmemb, void *stream) +static size_t write_cb_file(void *ptr, size_t size, size_t nmemb, void *stream) { - downloaded_bytes += size * nmemb; + downloaded_bytes += nmemb; if (total_bytes < downloaded_bytes) total_bytes = downloaded_bytes; return fwrite(ptr, size, nmemb, fh); } +static size_t write_cb_mem(void *ptr, size_t size, size_t nmemb, void *stream) +{ + volatile uint8_t *dst = &temp_download_mem[downloaded_bytes]; + downloaded_bytes += nmemb; + if (total_bytes < downloaded_bytes) total_bytes = downloaded_bytes; + memcpy_neon(dst, ptr, nmemb); + return nmemb; +} + // GitHub API does not set Content-Length field /*static size_t header_cb(char *buffer, size_t size, size_t nitems, void *userdata) { @@ -184,7 +197,7 @@ static size_t write_cb(void *ptr, size_t size, size_t nmemb, void *stream) return nitems * size; }*/ -static void startDownload(const char *url) +static void startDownload(const char *url, bool has_temp_file) { curl_easy_reset(curl_handle); curl_easy_setopt(curl_handle, CURLOPT_URL, url); @@ -196,7 +209,7 @@ static void startDownload(const char *url) curl_easy_setopt(curl_handle, CURLOPT_CONNECTTIMEOUT, 10L); curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1L); curl_easy_setopt(curl_handle, CURLOPT_NOPROGRESS, 1L); - curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_cb); + curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, has_temp_file ? write_cb_file : write_cb_mem); curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, bytes_string); // Dummy /*curl_easy_setopt(curl_handle, CURLOPT_HEADERFUNCTION, header_cb); curl_easy_setopt(curl_handle, CURLOPT_HEADERDATA, bytes_string); // Dummy*/ @@ -226,7 +239,7 @@ static int compatListThread(unsigned int args, void* arg){ sceIoGetstat(dbname, &stat); total_bytes = stat.st_size; - startDownload(url); + startDownload(url, true); fclose(fh); if (downloaded_bytes > 12 * 1024) { @@ -240,13 +253,13 @@ static int compatListThread(unsigned int args, void* arg){ return 0; } -static int downloaderThread(unsigned int args, void* arg){ +static int downloaderThread_file(unsigned int args, void* arg){ char url[512]; curl_handle = curl_easy_init(); sprintf(url, net_url); fh = fopen(TEMP_DOWNLOAD_NAME, "wb"); downloaded_bytes = 0; - startDownload(url); + startDownload(url, true); fclose(fh); if (downloaded_bytes <= 12 * 1024) sceIoRemove(TEMP_DOWNLOAD_NAME); @@ -255,6 +268,23 @@ static int downloaderThread(unsigned int args, void* arg){ return 0; } +static int downloaderThread_mem(unsigned int args, void* arg){ + char url[512]; + curl_handle = curl_easy_init(); + sprintf(url, net_url); + temp_download_mem = (volatile uint8_t*)malloc(NET_TEMP_MEM_SIZE); + downloaded_bytes = 0; + startDownload(url, false); + fclose(fh); + if (downloaded_bytes <= 32) { + free(temp_download_mem); + temp_download_mem = nullptr; + } else temp_download_size = downloaded_bytes; + curl_easy_cleanup(curl_handle); + sceKernelExitDeleteThread(0); + return 0; +} + static int updaterThread(unsigned int args, void* arg){ uint8_t update_detected = 0; char url[512]; @@ -272,7 +302,7 @@ static int updaterThread(unsigned int args, void* arg){ // FIXME: Workaround since GitHub Api does not set Content-Length total_bytes = i == UPDATER_CHECK_UPDATES ? 20 * 1024 : 2 * 1024 * 1024; /* 20 KB / 2 MB */ - startDownload(url); + startDownload(url, true); fclose(fh); if (downloaded_bytes > 12 * 1024) { @@ -326,7 +356,7 @@ void start_net() { } } -int download_file(char *url, char *file, char *msg, float int_total_bytes) { +int download_file(char *url, char *file, char *msg, float int_total_bytes, bool use_temp_file) { start_net(); SceKernelThreadInfo info; @@ -336,22 +366,21 @@ int download_file(char *url, char *file, char *msg, float int_total_bytes) { downloaded_bytes = 0; net_url = url; - SceUID thd = sceKernelCreateThread("Net Downloader", &downloaderThread, 0x10000100, 0x100000, 0, 0, NULL); + SceUID thd = sceKernelCreateThread("Net Downloader", use_temp_file ? &downloaderThread_file : &downloaderThread_mem, 0x10000100, 0x100000, 0, 0, NULL); sceKernelStartThread(thd, 0, NULL); do { DrawDownloaderScreenCompat(downloaded_bytes, downloaded_bytes > int_total_bytes ? downloaded_bytes : int_total_bytes, msg); res = sceKernelGetThreadInfo(thd, &info); } while (info.status <= SCE_THREAD_STOPPED && res >= 0); - FILE *f = fopen(TEMP_DOWNLOAD_NAME, "r"); - if (f) { - fclose(f); - sceIoRemove(file); - sceIoRename(TEMP_DOWNLOAD_NAME, file); - }else return -1; - ImGui::GetIO().MouseDrawCursor = true; + if (use_temp_file) { + FILE *f = fopen(TEMP_DOWNLOAD_NAME, "r"); + if (f) fclose(f); + else return -1; + } else if (!temp_download_mem) return -1; + return 0; } @@ -523,6 +552,16 @@ void showAlert(char *text, int type) { pendingAlert = true; } +void queueDownload(char *text, char *url, int size, void (*post_func)(), int type) { + cur_download.size = size; + sprintf(cur_download.msg, text); + sprintf(cur_download.url, url); + cur_download.post_func = post_func; + cur_download.type = type; + + pendingDownload = true; +} + static uint16_t dialog_res_text[SCE_IME_DIALOG_MAX_TEXT_LENGTH]; void getDialogTextResult(char *text) { // Converting text from UTF16 to UTF8