diff --git a/out/bins/ext_booter.bin b/out/bins/ext_booter.bin index c62a581b..00a5aeb7 100644 Binary files a/out/bins/ext_booter.bin and b/out/bins/ext_booter.bin differ diff --git a/out/boot.dol b/out/boot.dol index da53a010..b11cd80c 100644 Binary files a/out/boot.dol and b/out/boot.dol differ diff --git a/source/defines.h b/source/defines.h index ac7faadc..6409b66e 100644 --- a/source/defines.h +++ b/source/defines.h @@ -6,7 +6,7 @@ #else #define APP_NAME "WiiFlow Lite" #endif -#define APP_VERSION "5.3.0 beta 2" +#define APP_VERSION "5.3.0 beta 3" #define APP_DATA_DIR "wiiflow" #ifdef APP_WIIFLOW diff --git a/source/gui/coverflow.cpp b/source/gui/coverflow.cpp index 9d2a509a..d0fd845f 100644 --- a/source/gui/coverflow.cpp +++ b/source/gui/coverflow.cpp @@ -2839,7 +2839,8 @@ CCoverFlow::CLRet CCoverFlow::_loadCoverTex(u32 i, bool box, bool hq, bool blank /* try to find the wfc texture file in the cache folder */ if(!m_cachePath.empty()) { - const char *wfcTitle = NULL; + char wfcTitle[64]; + wfcTitle[63] = '\0'; const char *wfcCoverDir = NULL; char *full_path = (char*)MEM2_alloc(MAX_FAT_PATH+1); if(full_path == NULL) @@ -2851,18 +2852,20 @@ CCoverFlow::CLRet CCoverFlow::_loadCoverTex(u32 i, bool box, bool hq, bool blank { const char *blankCoverPath = mainMenu.getBlankCoverPath(m_items[i].hdr); if(blankCoverPath != NULL && strrchr(blankCoverPath, '/') != NULL) - wfcTitle = strrchr(blankCoverPath, '/') + 1; + strncpy(wfcTitle, strrchr(blankCoverPath, '/') + 1, sizeof(wfcTitle) - 1); else return CL_ERROR; } else - wfcTitle = getFilenameId(m_items[i].hdr); + strncpy(wfcTitle, getFilenameId(m_items[i].hdr), sizeof(wfcTitle) - 1); - /* get coverfolder for plugins and sourceflow */ + /* get coverfolder for plugins, sourceflow, and homebrew */ if(m_items[i].hdr->type == TYPE_PLUGIN && m_pluginCacheFolders && !blankBoxCover) wfcCoverDir = m_plugin.GetCoverFolderName(m_items[i].hdr->settings[0]); if(m_items[i].hdr->type == TYPE_SOURCE && !blankBoxCover) wfcCoverDir = "sourceflow"; + if(m_items[i].hdr->type == TYPE_HOMEBREW) + wfcCoverDir = "homebrew"; /* set full path of wfc file */ if(wfcCoverDir != NULL) @@ -2879,7 +2882,6 @@ CCoverFlow::CLRet CCoverFlow::_loadCoverTex(u32 i, bool box, bool hq, bool blank else strncpy(full_path, fmt("%s/%s.wfc", m_cachePath.c_str(), wfcTitle), MAX_FAT_PATH); } - DCFlushRange(full_path, MAX_FAT_PATH+1); /* load wfc file */ @@ -2890,13 +2892,17 @@ CCoverFlow::CLRet CCoverFlow::_loadCoverTex(u32 i, bool box, bool hq, bool blank if(fp != NULL)//if wfc chache file is found { bool success = false; - struct stat stat_buf; - if(fstat(fileno(fp), &stat_buf) != 0) + if(fseek(fp, 0, SEEK_END) != 0) { fclose(fp); - return _loadCoverTexPNG(i, box, hq, blankBoxCover) ? CL_OK : CL_ERROR; + return CL_ERROR; + } + u32 fileSize = ftell(fp); + if(fseek(fp, 0, SEEK_SET) != 0) + { + fclose(fp); + return CL_ERROR; } - u32 fileSize = stat_buf.st_size; SWFCHeader header; if(fileSize > sizeof(header)) @@ -2904,7 +2910,7 @@ CCoverFlow::CLRet CCoverFlow::_loadCoverTex(u32 i, bool box, bool hq, bool blank if(fread(&header, 1, sizeof(header), fp) != sizeof(header)) { fclose(fp); - return _loadCoverTexPNG(i, box, hq, blankBoxCover) ? CL_OK : CL_ERROR; + return CL_ERROR; } DCFlushRange(&header, sizeof(header)); //make sure wfc cache file matches what we want @@ -2929,21 +2935,16 @@ CCoverFlow::CLRet CCoverFlow::_loadCoverTex(u32 i, bool box, bool hq, bool blank { /* if not HQ cover then skip (bufSize - texLen) texture data after header */ fseek(fp, sizeof(header) + (bufSize - texLen), SEEK_SET); - if(fread(tex.data, 1, texLen, fp) != texLen) + if(fread(tex.data, 1, texLen, fp) == texLen) { - fclose(fp); - return _loadCoverTexPNG(i, box, hq, blankBoxCover) ? CL_OK : CL_ERROR; + DCFlushRange(tex.data, texLen); + LockMutex lock(m_mutex); + TexHandle.Cleanup(m_items[i].texture); + m_items[i].texture = tex; + m_items[i].state = STATE_Ready; + m_items[i].boxTexture = header.full != 0; + success = true; } - DCFlushRange(tex.data, texLen); - } - if(!allocFailed) - { - LockMutex lock(m_mutex); - TexHandle.Cleanup(m_items[i].texture); - m_items[i].texture = tex; - m_items[i].state = STATE_Ready; - m_items[i].boxTexture = header.full != 0; - success = true; } if(!success && tex.data != NULL) { @@ -2960,8 +2961,7 @@ CCoverFlow::CLRet CCoverFlow::_loadCoverTex(u32 i, bool box, bool hq, bool blank if(allocFailed) return CL_NOMEM; - // If wfc cache file not found, load the PNG and create a wfc cache file - return _loadCoverTexPNG(i, box, hq, blankBoxCover) ? CL_OK : CL_ERROR; + return CL_ERROR; } void * CCoverFlow::_coverLoader(void *obj) @@ -2993,19 +2993,30 @@ void * CCoverFlow::_coverLoader(void *obj) } } ret = CL_OK; - for(j = 0; j <= bufferSize && !cf->m_moved && update && ret != CL_NOMEM; ++j) + bool hq_done = false; + /* we try 3 passes to get the full cover. because the cover loader randomly skips the wfc file for unknown reasons */ + /* first time is full cover only */ + /* second time is full then front */ + /* third is full then front then custom blank cover */ + for(u8 k = 1; k < 4 && !cf->m_moved && update && ret != CL_NOMEM; k++) { - i = loopNum((j & 1) ? firstItem - (j + 1) / 2 : firstItem + j / 2, cf->m_items.size()); - cur_pos_hq = (hq_req && i == firstItem); - if((!hq_req || !cur_pos_hq) && cf->m_items[i].state != STATE_Loading) - continue; - if((ret = cf->_loadCoverTex(i, cf->m_box, cur_pos_hq, false)) == CL_ERROR) + for(j = 0; j <= bufferSize && !cf->m_moved && update && ret != CL_NOMEM; ++j) { - if ((ret = cf->_loadCoverTex(i, !cf->m_box, cur_pos_hq, false)) == CL_ERROR) + i = loopNum((j & 1) ? firstItem - (j + 1) / 2 : firstItem + j / 2, cf->m_items.size()); + cur_pos_hq = (hq_req && i == firstItem); + if(!cur_pos_hq && cf->m_items[i].state != STATE_Loading) + continue; + if(cur_pos_hq && hq_done) + continue; + if(((ret = cf->_loadCoverTex(i, true, cur_pos_hq, false)) == CL_ERROR) && k > 1) { - if((ret = cf->_loadCoverTex(i, cf->m_box, cur_pos_hq, true)) == CL_ERROR) - cf->m_items[i].state = STATE_NoCover; + if(((ret = cf->_loadCoverTex(i, false, cur_pos_hq, false)) == CL_ERROR) && k > 2) + { + if((ret = cf->_loadCoverTex(i, true, cur_pos_hq, true)) == CL_ERROR) + cf->m_items[i].state = STATE_NoCover; + } } + hq_done = (hq_done == false && ret == CL_OK && cur_pos_hq); } } if(ret == CL_NOMEM && bufferSize > 3) diff --git a/source/menu/menu.cpp b/source/menu/menu.cpp index 06e4153f..0096b74b 100644 --- a/source/menu/menu.cpp +++ b/source/menu/menu.cpp @@ -79,6 +79,7 @@ CMenu::CMenu() m_clearCats = true; m_catStartPage = 1; cacheCovers = false; + SF_cacheCovers = true; /* Explorer stuff */ m_txt_view = false; m_txt_path = NULL; @@ -2241,6 +2242,11 @@ bool CMenu::_loadList(void) for(vector::iterator tmp_itr = m_cacheList.begin(); tmp_itr != m_cacheList.end(); tmp_itr++) m_gameList.push_back(*tmp_itr); m_cacheList.Clear(); + if(SF_cacheCovers) + { + SF_cacheCovers = false; + cacheCovers = true; + } return true; } gprintf("Creating Gamelist\n"); @@ -2294,7 +2300,12 @@ bool CMenu::_loadHomebrewList(const char *HB_Dir) gprintf("Adding homebrew list\n"); string gameDir(fmt("%s:/%s", DeviceName[currentPartition], HB_Dir)); - m_cacheList.CreateList(COVERFLOW_HOMEBREW, currentPartition, gameDir, stringToVector(".dol|.elf", '|'), std::string(), false); + string cacheDir(fmt("%s/%s_%s.db", m_listCacheDir.c_str(), DeviceName[currentPartition], HB_Dir)); + bool updateCache = m_cfg.getBool(HOMEBREW_DOMAIN, "update_cache"); + if(updateCache || !fsop_FileExist(cacheDir.c_str())) + cacheCovers = true; + m_cacheList.CreateList(COVERFLOW_HOMEBREW, currentPartition, gameDir, stringToVector(".dol|.elf", '|'), cacheDir, updateCache); + m_cfg.remove(HOMEBREW_DOMAIN, "update_cache"); for(vector::iterator tmp_itr = m_cacheList.begin(); tmp_itr != m_cacheList.end(); tmp_itr++) m_gameList.push_back(*tmp_itr); return true; @@ -2671,8 +2682,7 @@ const char *CMenu::getBlankCoverPath(const dir_discHdr *element) default: blankCoverKey = "wii"; } - return fmt("%s/%s", m_boxPicDir.c_str(), m_theme.getString("BLANK_COVERS", blankCoverKey, fmt("%s.jpg", blankCoverKey)).c_str()); - //return fmt("%s/%s.jpg", m_boxPicDir.c_str(), blankCoverKey); + return fmt("%s/blank_covers/%s", m_boxPicDir.c_str(), m_theme.getString("BLANK_COVERS", blankCoverKey, fmt("%s.jpg", blankCoverKey)).c_str()); } const char *CMenu::getBoxPath(const dir_discHdr *element) @@ -2689,7 +2699,7 @@ const char *CMenu::getBoxPath(const dir_discHdr *element) return fmt("%s/%s.png", m_boxPicDir.c_str(), tempname); } else if(element->type == TYPE_HOMEBREW) - return fmt("%s/%s.png", m_boxPicDir.c_str(), strrchr(element->path, '/') + 1); + return fmt("%s/homebrew/%s.png", m_boxPicDir.c_str(), strrchr(element->path, '/') + 1); else if(element->type == TYPE_SOURCE)//sourceflow { const char *coverImg = strrchr(element->path, '/') + 1; @@ -2714,7 +2724,12 @@ const char *CMenu::getFrontPath(const dir_discHdr *element) return fmt("%s/%s.png", m_picDir.c_str(), tempname); } else if(element->type == TYPE_HOMEBREW) - return fmt("%s/icon.png", element->path); + { + if(m_cfg.getBool(HOMEBREW_DOMAIN, "smallbox")) + return fmt("%s/icon.png", element->path); + else + return fmt("%s/homebrew/%s.png", m_picDir.c_str(), strrchr(element->path, '/') + 1); + } else if(element->type == TYPE_SOURCE)//sourceflow { const char *coverImg = strrchr(element->path, '/') + 1; diff --git a/source/menu/menu.hpp b/source/menu/menu.hpp index 38d83522..2f252eb3 100644 --- a/source/menu/menu.hpp +++ b/source/menu/menu.hpp @@ -62,6 +62,7 @@ private: bool m_newGame; bool show_mem; bool cacheCovers; + bool SF_cacheCovers; bool CFLocked; vector m_gameList; diff --git a/source/menu/menu_config_hb.cpp b/source/menu/menu_config_hb.cpp index e130f140..2d356ca5 100644 --- a/source/menu/menu_config_hb.cpp +++ b/source/menu/menu_config_hb.cpp @@ -103,6 +103,7 @@ void CMenu::_CfgHB(void) else if (m_btnMgr.selected(m_cfghbBtnSmallbox)) { m_refreshGameList = true; + m_cfg.setBool(HOMEBREW_DOMAIN, "update_cache", true); m_cfg.setBool(HOMEBREW_DOMAIN, "smallbox", !m_cfg.getBool(HOMEBREW_DOMAIN, "smallbox", false)); m_btnMgr.setText(m_cfghbBtnSmallbox, m_cfg.getBool(HOMEBREW_DOMAIN, "smallbox") ? _t("on", L"On") : _t("off", L"Off")); } @@ -115,6 +116,7 @@ void CMenu::_CfgHB(void) else if (m_btnMgr.selected(m_cfghbBtnPartitionP) || m_btnMgr.selected(m_cfghbBtnPartitionM)) { m_refreshGameList = true; + m_cfg.setBool(HOMEBREW_DOMAIN, "update_cache", true); s8 direction = m_btnMgr.selected(m_cfghbBtnPartitionP) ? 1 : -1; _setPartition(direction); const char *partitionname = DeviceName[currentPartition]; diff --git a/source/menu/menu_config_source.cpp b/source/menu/menu_config_source.cpp index 8a6a803b..ee064580 100644 --- a/source/menu/menu_config_source.cpp +++ b/source/menu/menu_config_source.cpp @@ -125,12 +125,14 @@ void CMenu::_CfgSrc(void) } else if(m_btnMgr.selected(m_cfgsrcBtnSmallbox)) { + SF_cacheCovers = true; temp = !m_cfg.getBool(SOURCEFLOW_DOMAIN, "smallbox", false); m_cfg.setBool(SOURCEFLOW_DOMAIN, "smallbox", temp); m_btnMgr.setText(m_cfgsrcBtnSmallbox, temp ? _t("on", L"On") : _t("off", L"Off")); } else if(m_btnMgr.selected(m_cfgsrcBtnBoxMode)) { + SF_cacheCovers = true; temp = !m_cfg.getBool(SOURCEFLOW_DOMAIN, "box_mode", false); m_cfg.setBool(SOURCEFLOW_DOMAIN, "box_mode", temp); m_btnMgr.setText(m_cfgsrcBtnBoxMode, temp ? _t("on", L"On") : _t("off", L"Off")); diff --git a/source/menu/menu_home.cpp b/source/menu/menu_home.cpp index a9274fbb..ebd642dc 100644 --- a/source/menu/menu_home.cpp +++ b/source/menu/menu_home.cpp @@ -90,6 +90,8 @@ bool CMenu::_Home(void) m_cfg.setBool(CHANNEL_DOMAIN, "update_cache", true); if(m_current_view & COVERFLOW_PLUGIN) m_cfg.setBool(PLUGIN_DOMAIN, "update_cache", true); + if(m_current_view & COVERFLOW_HOMEBREW) + m_cfg.setBool(HOMEBREW_DOMAIN, "update_cache", true); m_refreshGameList = true; break; } @@ -416,13 +418,25 @@ int CMenu::_cacheCovers() bool m_pluginCacheFolders = m_cfg.getBool(PLUGIN_DOMAIN, "subfolder_cache", true); char coverPath[MAX_FAT_PATH]; - char wfcPath[MAX_FAT_PATH+5]; + char wfcPath[MAX_FAT_PATH+20]; char cachePath[MAX_FAT_PATH]; u32 total = m_gameList.size(); m_thrdTotal = total; u32 index = 0; + bool smallBox = false; + if(m_current_view == COVERFLOW_HOMEBREW && !m_sourceflow) + smallBox = m_cfg.getBool(HOMEBREW_DOMAIN, "smallbox", false); + else if(m_sourceflow) + smallBox = m_cfg.getBool(SOURCEFLOW_DOMAIN, "smallbox", false); + else if(m_current_view == COVERFLOW_PLUGIN && !m_sourceflow) + { + m_plugin.GetEnabledPlugins(m_cfg, &enabledPluginsCount); + if(enabledPluginsCount == 1 && m_cfg.getBool(PLUGIN_ENABLED, "48425257")) + smallBox = m_cfg.getBool(HOMEBREW_DOMAIN, "smallbox", false); + } + for(vector::iterator hdr = m_gameList.begin(); hdr != m_gameList.end(); ++hdr) { index++; @@ -430,30 +444,42 @@ int CMenu::_cacheCovers() m_thrdMessage = wfmt(_fmt("dlmsg31", L"converting cover %i of %i"), index, total); m_thrdMessageAdded = true; - bool fullCover = true; - /* get game name or ID */ - const char *gameNameOrID = CoverFlow.getFilenameId(&(*hdr));// &(*hdr) converts iterator to pointer to mem address + const char *gameNameOrID = NULL; + gameNameOrID = CoverFlow.getFilenameId(&(*hdr));// &(*hdr) converts iterator to pointer to mem address /* get cover png path */ + bool fullCover = true; strlcpy(coverPath, getBoxPath(&(*hdr)), sizeof(coverPath)); - if(!fsop_FileExist(coverPath)) + if(!fsop_FileExist(coverPath) || smallBox) { fullCover = false; strlcpy(coverPath, getFrontPath(&(*hdr)), sizeof(coverPath)); - if(!fsop_FileExist(coverPath)) - continue; + if(!fsop_FileExist(coverPath) && !smallBox) + { + fullCover = true; + strlcpy(coverPath, getBlankCoverPath(&(*hdr)), sizeof(coverPath)); + gameNameOrID = strrchr(coverPath, '/') + 1; + if(!fsop_FileExist(coverPath)) + continue; + } } - /* get cover wfc path */ + /* get cache folder path */ if(hdr->type == TYPE_PLUGIN && m_pluginCacheFolders) - { snprintf(cachePath, sizeof(cachePath), "%s/%s", m_cacheDir.c_str(), m_plugin.GetCoverFolderName(hdr->settings[0])); - } + else if(m_sourceflow) + snprintf(cachePath, sizeof(cachePath), "%s/sourceflow", m_cacheDir.c_str()); + else if(hdr->type == TYPE_HOMEBREW) + snprintf(cachePath, sizeof(cachePath), "%s/homebrew", m_cacheDir.c_str()); else snprintf(cachePath, sizeof(cachePath), "%s", m_cacheDir.c_str()); - snprintf(wfcPath, sizeof(wfcPath), "%s/%s.wfc", cachePath, gameNameOrID); + /* get cover wfc path */ + if(smallBox) + snprintf(wfcPath, sizeof(wfcPath), "%s/%s_small.wfc", cachePath, gameNameOrID); + else + snprintf(wfcPath, sizeof(wfcPath), "%s/%s.wfc", cachePath, gameNameOrID); /* if wfc doesn't exist or is flat and have full cover */ if(!fsop_FileExist(wfcPath) || (!CoverFlow.fullCoverCached(wfcPath) && fullCover)) diff --git a/source/menu/menu_main.cpp b/source/menu/menu_main.cpp index 5d7afe82..316a23e2 100644 --- a/source/menu/menu_main.cpp +++ b/source/menu/menu_main.cpp @@ -188,6 +188,8 @@ void CMenu::_showCF(bool refreshList) _stop_pThread(); m_btnMgr.setText(m_wbfsLblDialog, _t("dlmsg14", L"Done.")); u8 pause = 150; + if(m_sourceflow) + pause = 1; while(!m_exit) { _mainLoopCommon(); diff --git a/source/menu/menu_nandemu.cpp b/source/menu/menu_nandemu.cpp index 682acbf9..37e637f6 100644 --- a/source/menu/menu_nandemu.cpp +++ b/source/menu/menu_nandemu.cpp @@ -139,7 +139,7 @@ void CMenu::_checkEmuNandSettings(void) savesPart = SD; } //cfgne8=No valid FAT partition found for NAND Emulation! - _listEmuNands(fmt("%s:/%s", DeviceName[emuPart], emu_nands_dir), emuNands); + _listEmuNands(fmt("%s:/%s", DeviceName[emuPart], emu_nands_dir), emuNands); curEmuNand = 0; for(i = 0; i < emuNands.size(); ++i)// find current emunand folder { @@ -160,7 +160,7 @@ void CMenu::_checkEmuNandSettings(void) } } } - gprintf("emu nand path = %s:/%s/%s\n", DeviceName[emuPart], emu_nands_dir, emuNands[curEmuNand]); + gprintf("emu nand path = %s:/%s/%s\n", DeviceName[emuPart], emu_nands_dir, emuNands[curEmuNand].c_str()); _listEmuNands(fmt("%s:/%s", DeviceName[savesPart], emu_nands_dir), savesNands); curSavesNand = 0; @@ -183,7 +183,7 @@ void CMenu::_checkEmuNandSettings(void) } } } - gprintf("saves nand path = %s:/%s/%s\n", DeviceName[savesPart], emu_nands_dir, savesNands[curSavesNand]); + gprintf("saves nand path = %s:/%s/%s\n", DeviceName[savesPart], emu_nands_dir, savesNands[curSavesNand].c_str()); m_cfg.setString(WII_DOMAIN, "current_save_emunand", savesNands[curSavesNand]); m_cfg.setInt(WII_DOMAIN, "savepartition", savesPart); diff --git a/source/menu/menu_source.cpp b/source/menu/menu_source.cpp index 0c61d79d..650030b9 100644 --- a/source/menu/menu_source.cpp +++ b/source/menu/menu_source.cpp @@ -99,6 +99,7 @@ void CMenu::_sourceFlow() tiers.push_back(fn); m_source.unload(); m_source.load(fmt("%s/%s", m_sourceDir.c_str(), fn.c_str())); + SF_cacheCovers = true; curflow = m_source.getInt("general", "flow", m_cfg.getInt(SOURCEFLOW_DOMAIN, "last_cf_mode", 1)); /* get max source button # */ m_max_source_btn = 0;