diff --git a/externals/ext-boost b/externals/ext-boost index f2474e1b5..a04136add 160000 --- a/externals/ext-boost +++ b/externals/ext-boost @@ -1 +1 @@ -Subproject commit f2474e1b584fb7a3ed6f85ba875e6eacd742ec8a +Subproject commit a04136add1e469f46d8ae8d3e8307779240a5c53 diff --git a/src/core/file_sys/fs.cpp b/src/core/file_sys/fs.cpp index 3b060dd83..88f5b0259 100644 --- a/src/core/file_sys/fs.cpp +++ b/src/core/file_sys/fs.cpp @@ -53,7 +53,14 @@ std::filesystem::path MntPoints::GetHostPath(std::string_view guest_directory, b // Remove device (e.g /app0) from path to retrieve relative path. pos = mount->mount.size() + 1; const auto rel_path = std::string_view(corrected_path).substr(pos); - const auto host_path = mount->host_path / rel_path; + std::filesystem::path host_path = mount->host_path / rel_path; + + //Use file in update directory instead if it's there (e.g. CUSAXXXXX-UPDATE) + std::filesystem::path patch_path = mount->host_path.string() + "-UPDATE"; + if (std::filesystem::exists(patch_path / rel_path)) { + host_path = patch_path / rel_path; + } + if (!NeedsCaseInsensitiveSearch) { return host_path; } diff --git a/src/emulator.cpp b/src/emulator.cpp index 67aaa0492..56f15fc21 100644 --- a/src/emulator.cpp +++ b/src/emulator.cpp @@ -114,7 +114,10 @@ void Emulator::Run(const std::filesystem::path& file) { std::string app_version; u32 fw_version; - std::filesystem::path sce_sys_folder = file.parent_path() / "sce_sys"; + std::filesystem::path game_patch_folder = (file.parent_path().string() + "-UPDATE"); + std::filesystem::path sce_sys_folder = std::filesystem::exists(game_patch_folder / "sce_sys") + ? game_patch_folder / "sce_sys" + : file.parent_path() / "sce_sys"; if (std::filesystem::is_directory(sce_sys_folder)) { for (const auto& entry : std::filesystem::directory_iterator(sce_sys_folder)) { if (entry.path().filename() == "param.sfo") { diff --git a/src/qt_gui/game_info.cpp b/src/qt_gui/game_info.cpp index d82f43f20..48643f8ed 100644 --- a/src/qt_gui/game_info.cpp +++ b/src/qt_gui/game_info.cpp @@ -17,7 +17,7 @@ void GameInfoClass::GetGameInfo(QWidget* parent) { QDir parentFolder(installDir); QFileInfoList fileList = parentFolder.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot); for (const auto& fileInfo : fileList) { - if (fileInfo.isDir()) { + if (fileInfo.isDir() && !fileInfo.filePath().endsWith("-UPDATE")) { filePaths.append(fileInfo.absoluteFilePath()); } } diff --git a/src/qt_gui/game_info.h b/src/qt_gui/game_info.h index 8f65803bf..1fa656b47 100644 --- a/src/qt_gui/game_info.h +++ b/src/qt_gui/game_info.h @@ -25,9 +25,15 @@ public: static GameInfo readGameInfo(const std::filesystem::path& filePath) { GameInfo game; game.path = filePath; + std::filesystem::path sce_folder_path = filePath / "sce_sys" / "param.sfo"; + std::filesystem::path game_update_path = + std::filesystem::path(filePath.string() + "-UPDATE"); + if (std::filesystem::exists(game_update_path)) { + sce_folder_path = (game_update_path / "sce_sys" / "param.sfo"); + } PSF psf; - if (psf.Open(game.path / "sce_sys" / "param.sfo")) { + if (psf.Open(sce_folder_path)) { game.icon_path = game.path / "sce_sys" / "icon0.png"; QString iconpath; Common::FS::PathToQString(iconpath, game.icon_path); diff --git a/src/qt_gui/gui_context_menus.h b/src/qt_gui/gui_context_menus.h index 4eb657572..15550fa56 100644 --- a/src/qt_gui/gui_context_menus.h +++ b/src/qt_gui/gui_context_menus.h @@ -68,6 +68,18 @@ public: menu.addMenu(copyMenu); + // "Delete" submenu. + QMenu* deleteMenu = new QMenu(tr("Delete..."), widget); + QAction* deleteGame = new QAction(tr("Delete Game"), widget); + QAction* deleteUpdate = new QAction(tr("Delete Update"), widget); + QAction* deleteDLC = new QAction(tr("Delete DLC"), widget); + + deleteMenu->addAction(deleteGame); + deleteMenu->addAction(deleteUpdate); + deleteMenu->addAction(deleteDLC); + + menu.addMenu(deleteMenu); + // Show menu. auto selected = menu.exec(global_pos); if (!selected) { @@ -82,7 +94,11 @@ public: if (selected == &openSfoViewer) { PSF psf; - if (psf.Open(std::filesystem::path(m_games[itemID].path) / "sce_sys" / "param.sfo")) { + std::string game_folder_path = m_games[itemID].path; + if (std::filesystem::exists(game_folder_path + "-UPDATE")) { + game_folder_path += "-UPDATE"; + } + if (psf.Open(std::filesystem::path(game_folder_path) / "sce_sys" / "param.sfo")) { int rows = psf.GetEntries().size(); QTableWidget* tableWidget = new QTableWidget(rows, 2); tableWidget->setAttribute(Qt::WA_DeleteOnClose); @@ -269,6 +285,47 @@ public: .arg(QString::fromStdString(m_games[itemID].size)); clipboard->setText(combinedText); } + + if (selected == deleteGame || selected == deleteUpdate || selected == deleteDLC) { + bool error = false; + QString folder_path = QString::fromStdString(m_games[itemID].path); + QString message_type = tr("Game"); + if (selected == deleteUpdate) { + if (!std::filesystem::exists(m_games[itemID].path + "-UPDATE")) { + QMessageBox::critical( + nullptr, tr("Error"), + QString(tr("This game has no update to delete!"))); + error = true; + } else { + folder_path = QString::fromStdString(m_games[itemID].path + "-UPDATE"); + message_type = tr("Update"); + } + } else if (selected == deleteDLC) { + std::filesystem::path game_path = folder_path.toStdString(); + std::filesystem::path addon_path = + Config::getAddonInstallDir() / game_path.parent_path().filename(); + if (!std::filesystem::exists(addon_path.string())) { + QMessageBox::critical(nullptr, tr("Error"), + QString(tr("This game has no DLC to delete!"))); + error = true; + } else { + folder_path = QString::fromStdString(addon_path.string()); + message_type = tr("DLC"); + } + } + if (!error) { + QString gameName = QString::fromStdString(m_games[itemID].name); + QDir dir(folder_path); + QMessageBox::StandardButton reply = QMessageBox::question( + nullptr, QString(tr("Delete %1")).arg(message_type), + QString(tr("Are you sure you want to delete %1's %2 directory?")) + .arg(gameName, message_type), + QMessageBox::Yes | QMessageBox::No); + if (reply == QMessageBox::Yes) { + dir.removeRecursively(); + } + } + } } int GetRowIndex(QTreeWidget* treeWidget, QTreeWidgetItem* item) { diff --git a/src/qt_gui/main_window.cpp b/src/qt_gui/main_window.cpp index 025749dd4..5fb3c16b6 100644 --- a/src/qt_gui/main_window.cpp +++ b/src/qt_gui/main_window.cpp @@ -676,10 +676,16 @@ void MainWindow::InstallDragDropPkg(std::filesystem::path file, int pkgNum, int InstallDirSelect ids; ids.exec(); auto game_install_dir = ids.getSelectedDirectory(); - auto extract_path = game_install_dir / pkg.GetTitleID(); + auto game_folder_path = game_install_dir / pkg.GetTitleID(); QString pkgType = QString::fromStdString(pkg.GetPkgFlags()); + auto game_update_path = pkgType.contains("PATCH") + ? Config::getGameInstallDir() / (std::string(pkg.GetTitleID()) + "-UPDATE") + : game_folder_path; + if (!std::filesystem::exists(game_update_path)) { + std::filesystem::create_directory(game_update_path); + } QString gameDirPath; - Common::FS::PathToQString(gameDirPath, extract_path); + Common::FS::PathToQString(gameDirPath, game_folder_path); QDir game_dir(gameDirPath); if (game_dir.exists()) { QMessageBox msgBox; @@ -715,7 +721,11 @@ void MainWindow::InstallDragDropPkg(std::filesystem::path file, int pkgNum, int QMessageBox::critical(this, tr("PKG ERROR"), "PSF file there is no APP_VER"); return; } - psf.Open(extract_path / "sce_sys" / "param.sfo"); + std::filesystem::path sce_folder_path = + std::filesystem::exists(game_update_path / "sce_sys" / "param.sfo") + ? game_update_path / "sce_sys" / "param.sfo" + : game_folder_path / "sce_sys" / "param.sfo"; + psf.Open(sce_folder_path); QString game_app_version; if (auto app_ver = psf.GetString("APP_VER"); app_ver.has_value()) { game_app_version = QString::fromStdString(std::string{*app_ver}); @@ -764,7 +774,7 @@ void MainWindow::InstallDragDropPkg(std::filesystem::path file, int pkgNum, int addonMsgBox.setDefaultButton(QMessageBox::No); int result = addonMsgBox.exec(); if (result == QMessageBox::Yes) { - extract_path = addon_extract_path; + game_update_path = addon_extract_path; } else { return; } @@ -775,12 +785,14 @@ void MainWindow::InstallDragDropPkg(std::filesystem::path file, int pkgNum, int msgBox.setDefaultButton(QMessageBox::No); int result = msgBox.exec(); if (result == QMessageBox::Yes) { - extract_path = addon_extract_path; + game_update_path = addon_extract_path; } else { return; } } } else { + QString gameDirPath; + Common::FS::PathToQString(gameDirPath, game_folder_path); msgBox.setText(QString(tr("Game already installed") + "\n" + gameDirPath + "\n" + tr("Would you like to overwrite?"))); msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); @@ -801,8 +813,7 @@ void MainWindow::InstallDragDropPkg(std::filesystem::path file, int pkgNum, int } // what else? } - - if (!pkg.Extract(file, extract_path, failreason)) { + if (!pkg.Extract(file, game_update_path, failreason)) { QMessageBox::critical(this, tr("PKG ERROR"), QString::fromStdString(failreason)); } else { int nfiles = pkg.GetNumberOfFiles();