mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-05-30 23:33:17 +00:00
* Added recursive game scan and only using game directories * Added recursion depth limit to scan directories * Added recursive search by ID in cli mode * Added recursive search to pkg installing
This commit is contained in:
parent
8057ed408c
commit
f3c33b29dd
6 changed files with 117 additions and 20 deletions
|
@ -176,6 +176,34 @@ void SetUserPath(PathType shad_path, const fs::path& new_path) {
|
||||||
UserPaths.insert_or_assign(shad_path, new_path);
|
UserPaths.insert_or_assign(shad_path, new_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<fs::path> FindGameByID(const fs::path& dir, const std::string& game_id,
|
||||||
|
int max_depth) {
|
||||||
|
if (max_depth < 0) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if this is the game we're looking for
|
||||||
|
if (dir.filename() == game_id && fs::exists(dir / "sce_sys" / "param.sfo")) {
|
||||||
|
auto eboot_path = dir / "eboot.bin";
|
||||||
|
if (fs::exists(eboot_path)) {
|
||||||
|
return eboot_path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recursively search subdirectories
|
||||||
|
std::error_code ec;
|
||||||
|
for (const auto& entry : fs::directory_iterator(dir, ec)) {
|
||||||
|
if (!entry.is_directory()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (auto found = FindGameByID(entry.path(), game_id, max_depth - 1)) {
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef ENABLE_QT_GUI
|
#ifdef ENABLE_QT_GUI
|
||||||
void PathToQString(QString& result, const std::filesystem::path& path) {
|
void PathToQString(QString& result, const std::filesystem::path& path) {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
#include <optional>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#ifdef ENABLE_QT_GUI
|
#ifdef ENABLE_QT_GUI
|
||||||
|
@ -115,4 +116,18 @@ void PathToQString(QString& result, const std::filesystem::path& path);
|
||||||
[[nodiscard]] std::filesystem::path PathFromQString(const QString& path);
|
[[nodiscard]] std::filesystem::path PathFromQString(const QString& path);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursively searches for a game directory by its ID.
|
||||||
|
* Limits search depth to prevent excessive filesystem traversal.
|
||||||
|
*
|
||||||
|
* @param dir Base directory to start the search from
|
||||||
|
* @param game_id The game ID to search for
|
||||||
|
* @param max_depth Maximum directory depth to search
|
||||||
|
*
|
||||||
|
* @returns Path to eboot.bin if found, std::nullopt otherwise
|
||||||
|
*/
|
||||||
|
[[nodiscard]] std::optional<std::filesystem::path> FindGameByID(const std::filesystem::path& dir,
|
||||||
|
const std::string& game_id,
|
||||||
|
int max_depth);
|
||||||
|
|
||||||
} // namespace Common::FS
|
} // namespace Common::FS
|
||||||
|
|
|
@ -167,12 +167,12 @@ int main(int argc, char* argv[]) {
|
||||||
|
|
||||||
// Check if the provided path is a valid file
|
// Check if the provided path is a valid file
|
||||||
if (!std::filesystem::exists(eboot_path)) {
|
if (!std::filesystem::exists(eboot_path)) {
|
||||||
// If not a file, treat it as a game ID and search in install directories
|
// If not a file, treat it as a game ID and search in install directories recursively
|
||||||
bool game_found = false;
|
bool game_found = false;
|
||||||
|
const int max_depth = 5;
|
||||||
for (const auto& install_dir : Config::getGameInstallDirs()) {
|
for (const auto& install_dir : Config::getGameInstallDirs()) {
|
||||||
const auto candidate_path = install_dir / game_path / "eboot.bin";
|
if (auto found_path = Common::FS::FindGameByID(install_dir, game_path, max_depth)) {
|
||||||
if (std::filesystem::exists(candidate_path)) {
|
eboot_path = *found_path;
|
||||||
eboot_path = candidate_path;
|
|
||||||
game_found = true;
|
game_found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,33 @@
|
||||||
#include "compatibility_info.h"
|
#include "compatibility_info.h"
|
||||||
#include "game_info.h"
|
#include "game_info.h"
|
||||||
|
|
||||||
|
// Maximum depth to search for games in subdirectories
|
||||||
|
const int max_recursion_depth = 5;
|
||||||
|
|
||||||
|
void ScanDirectoryRecursively(const QString& dir, QStringList& filePaths, int current_depth = 0) {
|
||||||
|
// Stop recursion if we've reached the maximum depth
|
||||||
|
if (current_depth >= max_recursion_depth) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QDir directory(dir);
|
||||||
|
QFileInfoList entries = directory.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
|
||||||
|
|
||||||
|
for (const auto& entry : entries) {
|
||||||
|
if (entry.fileName().endsWith("-UPDATE")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if this directory contains a PS4 game (has sce_sys/param.sfo)
|
||||||
|
if (QFile::exists(entry.filePath() + "/sce_sys/param.sfo")) {
|
||||||
|
filePaths.append(entry.absoluteFilePath());
|
||||||
|
} else {
|
||||||
|
// If not a game directory, recursively scan it with increased depth
|
||||||
|
ScanDirectoryRecursively(entry.absoluteFilePath(), filePaths, current_depth + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
GameInfoClass::GameInfoClass() = default;
|
GameInfoClass::GameInfoClass() = default;
|
||||||
GameInfoClass::~GameInfoClass() = default;
|
GameInfoClass::~GameInfoClass() = default;
|
||||||
|
|
||||||
|
@ -15,13 +42,7 @@ void GameInfoClass::GetGameInfo(QWidget* parent) {
|
||||||
for (const auto& installLoc : Config::getGameInstallDirs()) {
|
for (const auto& installLoc : Config::getGameInstallDirs()) {
|
||||||
QString installDir;
|
QString installDir;
|
||||||
Common::FS::PathToQString(installDir, installLoc);
|
Common::FS::PathToQString(installDir, installLoc);
|
||||||
QDir parentFolder(installDir);
|
ScanDirectoryRecursively(installDir, filePaths, 0);
|
||||||
QFileInfoList fileList = parentFolder.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
|
|
||||||
for (const auto& fileInfo : fileList) {
|
|
||||||
if (fileInfo.isDir() && !fileInfo.filePath().endsWith("-UPDATE")) {
|
|
||||||
filePaths.append(fileInfo.absoluteFilePath());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_games = QtConcurrent::mapped(filePaths, [&](const QString& path) {
|
m_games = QtConcurrent::mapped(filePaths, [&](const QString& path) {
|
||||||
|
|
|
@ -181,12 +181,12 @@ int main(int argc, char* argv[]) {
|
||||||
|
|
||||||
// Check if the provided path is a valid file
|
// Check if the provided path is a valid file
|
||||||
if (!std::filesystem::exists(game_file_path)) {
|
if (!std::filesystem::exists(game_file_path)) {
|
||||||
// If not a file, treat it as a game ID and search in install directories
|
// If not a file, treat it as a game ID and search in install directories recursively
|
||||||
bool game_found = false;
|
bool game_found = false;
|
||||||
|
const int max_depth = 5;
|
||||||
for (const auto& install_dir : Config::getGameInstallDirs()) {
|
for (const auto& install_dir : Config::getGameInstallDirs()) {
|
||||||
auto potential_game_path = install_dir / game_path / "eboot.bin";
|
if (auto found_path = Common::FS::FindGameByID(install_dir, game_path, max_depth)) {
|
||||||
if (std::filesystem::exists(potential_game_path)) {
|
game_file_path = *found_path;
|
||||||
game_file_path = potential_game_path;
|
|
||||||
game_found = true;
|
game_found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -747,12 +747,42 @@ void MainWindow::InstallDragDropPkg(std::filesystem::path file, int pkgNum, int
|
||||||
}
|
}
|
||||||
std::filesystem::path game_install_dir = last_install_dir;
|
std::filesystem::path game_install_dir = last_install_dir;
|
||||||
|
|
||||||
auto game_folder_path = game_install_dir / pkg.GetTitleID();
|
|
||||||
QString pkgType = QString::fromStdString(pkg.GetPkgFlags());
|
QString pkgType = QString::fromStdString(pkg.GetPkgFlags());
|
||||||
bool use_game_update = pkgType.contains("PATCH") && Config::getSeparateUpdateEnabled();
|
bool use_game_update = pkgType.contains("PATCH") && Config::getSeparateUpdateEnabled();
|
||||||
auto game_update_path = use_game_update
|
|
||||||
? game_install_dir / (std::string(pkg.GetTitleID()) + "-UPDATE")
|
// Default paths
|
||||||
: game_folder_path;
|
auto game_folder_path = game_install_dir / pkg.GetTitleID();
|
||||||
|
auto game_update_path = use_game_update ? game_folder_path.parent_path() /
|
||||||
|
(std::string{pkg.GetTitleID()} + "-UPDATE")
|
||||||
|
: game_folder_path;
|
||||||
|
const int max_depth = 5;
|
||||||
|
|
||||||
|
if (pkgType.contains("PATCH")) {
|
||||||
|
// For patches, try to find the game recursively
|
||||||
|
auto found_game = Common::FS::FindGameByID(game_install_dir,
|
||||||
|
std::string{pkg.GetTitleID()}, max_depth);
|
||||||
|
if (found_game.has_value()) {
|
||||||
|
game_folder_path = found_game.value().parent_path();
|
||||||
|
game_update_path = use_game_update ? game_folder_path.parent_path() /
|
||||||
|
(std::string{pkg.GetTitleID()} + "-UPDATE")
|
||||||
|
: game_folder_path;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// For base games, we check if the game is already installed
|
||||||
|
auto found_game = Common::FS::FindGameByID(game_install_dir,
|
||||||
|
std::string{pkg.GetTitleID()}, max_depth);
|
||||||
|
if (found_game.has_value()) {
|
||||||
|
game_folder_path = found_game.value().parent_path();
|
||||||
|
}
|
||||||
|
// If the game is not found, we install it in the game install directory
|
||||||
|
else {
|
||||||
|
game_folder_path = game_install_dir / pkg.GetTitleID();
|
||||||
|
}
|
||||||
|
game_update_path = use_game_update ? game_folder_path.parent_path() /
|
||||||
|
(std::string{pkg.GetTitleID()} + "-UPDATE")
|
||||||
|
: game_folder_path;
|
||||||
|
}
|
||||||
|
|
||||||
QString gameDirPath;
|
QString gameDirPath;
|
||||||
Common::FS::PathToQString(gameDirPath, game_folder_path);
|
Common::FS::PathToQString(gameDirPath, game_folder_path);
|
||||||
QDir game_dir(gameDirPath);
|
QDir game_dir(gameDirPath);
|
||||||
|
@ -897,10 +927,13 @@ void MainWindow::InstallDragDropPkg(std::filesystem::path file, int pkgNum, int
|
||||||
connect(&futureWatcher, &QFutureWatcher<void>::finished, this, [=, this]() {
|
connect(&futureWatcher, &QFutureWatcher<void>::finished, this, [=, this]() {
|
||||||
if (pkgNum == nPkg) {
|
if (pkgNum == nPkg) {
|
||||||
QString path;
|
QString path;
|
||||||
Common::FS::PathToQString(path, game_install_dir);
|
|
||||||
|
// We want to show the parent path instead of the full path
|
||||||
|
Common::FS::PathToQString(path, game_folder_path.parent_path());
|
||||||
QIcon windowIcon(
|
QIcon windowIcon(
|
||||||
Common::FS::PathToUTF8String(game_folder_path / "sce_sys/icon0.png")
|
Common::FS::PathToUTF8String(game_folder_path / "sce_sys/icon0.png")
|
||||||
.c_str());
|
.c_str());
|
||||||
|
|
||||||
QMessageBox extractMsgBox(this);
|
QMessageBox extractMsgBox(this);
|
||||||
extractMsgBox.setWindowTitle(tr("Extraction Finished"));
|
extractMsgBox.setWindowTitle(tr("Extraction Finished"));
|
||||||
if (!windowIcon.isNull()) {
|
if (!windowIcon.isNull()) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue