diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index 5a1c41072b..492aed799a 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -4213,54 +4213,62 @@ u32 Emulator::AddGamesFromDir(const std::string& path) m_games_config.set_save_on_dirty(false); - // search dropped path first or else the direct parent to an elf is wrongly skipped + // search for a game on the provided path first (game on ISO file or on folder type) if (const game_boot_result error = AddGame(path); error == game_boot_result::no_errors) { games_added++; } - std::vector entries; - - for (auto&& dir_entry : fs::dir(path)) + // search for games on subfolders only if not nested inside a discovered game folder + if (games_added == 0) { - // Prefetch entries, it is unsafe to keep fs::dir for a long time or for many operations - entries.emplace_back(std::move(dir_entry)); - } + std::vector entries; - auto path_it = entries.begin(); - - qt_events_aware_op(0, [&]() - { - // search direct subdirectories, that way we can drop one folder containing all games - for (; path_it != entries.end(); ++path_it) + for (auto&& dir_entry : fs::dir(path)) { - auto dir_entry = std::move(*path_it); - - if (dir_entry.name == "." || dir_entry.name == "..") - { - continue; - } - - const std::string dir_path = path + '/' + dir_entry.name; - - if (!dir_entry.is_directory && !is_file_iso(dir_path)) - { - continue; - } - - if (const game_boot_result error = AddGame(dir_path); error == game_boot_result::no_errors) - { - games_added++; - } - - // Process events - ++path_it; - return false; + // Prefetch entries, it is unsafe to keep fs::dir for a long time or for many operations + entries.emplace_back(std::move(dir_entry)); } - // Exit loop - return true; - }); + auto path_it = entries.begin(); + + qt_events_aware_op(0, [&]() + { + // search direct subdirectories, that way we can drop one folder containing all games + for (; path_it != entries.end(); ++path_it) + { + auto dir_entry = std::move(*path_it); + + if (dir_entry.name == "." || dir_entry.name == "..") + { + continue; + } + + const std::string dir_path = path + '/' + dir_entry.name; + + if (!dir_entry.is_directory && !is_file_iso(dir_path)) + { + continue; + } + + if (const game_boot_result error = AddGame(dir_path); error == game_boot_result::no_errors) + { + games_added++; + } + else if (g_cfg.misc.use_recursive_scan) + { + games_added += AddGamesFromDir(dir_path); + } + + // Process events + ++path_it; + return false; + } + + // Exit loop + return true; + }); + } m_games_config.set_save_on_dirty(true); diff --git a/rpcs3/Emu/system_config.h b/rpcs3/Emu/system_config.h index f9f6f2c8d3..18d3555555 100644 --- a/rpcs3/Emu/system_config.h +++ b/rpcs3/Emu/system_config.h @@ -361,6 +361,7 @@ struct cfg_root : cfg::node cfg::_bool show_fatal_error_hints{ this, "Show fatal error hints", false, true }; cfg::_bool show_capture_hints{ this, "Show capture hints", true, true }; cfg::_bool use_native_interface{ this, "Use native user interface", true }; + cfg::_bool use_recursive_scan{this, "Use recursive scan", false}; cfg::string gdb_server{ this, "GDB Server", "127.0.0.1:2345" }; cfg::_bool silence_all_logs{ this, "Silence All Logs", false, true }; cfg::string title_format{ this, "Window Title Format", "FPS: %F | %R | %V | %T [%t]", true }; diff --git a/rpcs3/rpcs3qt/emu_settings_type.h b/rpcs3/rpcs3qt/emu_settings_type.h index de04b81e85..834e71771e 100644 --- a/rpcs3/rpcs3qt/emu_settings_type.h +++ b/rpcs3/rpcs3qt/emu_settings_type.h @@ -184,6 +184,7 @@ enum class emu_settings_type ShowTrophyPopups, ShowRpcnPopups, UseNativeInterface, + UseRecursiveScan, ShowShaderCompilationHint, ShowPPUCompilationHint, ShowAutosaveAutoloadHint, diff --git a/rpcs3/rpcs3qt/settings_dialog.cpp b/rpcs3/rpcs3qt/settings_dialog.cpp index 26e062b67b..5ef783c473 100644 --- a/rpcs3/rpcs3qt/settings_dialog.cpp +++ b/rpcs3/rpcs3qt/settings_dialog.cpp @@ -1819,6 +1819,9 @@ settings_dialog::settings_dialog(std::shared_ptr gui_settings, std m_emu_settings->EnhanceCheckBox(ui->useNativeInterface, emu_settings_type::UseNativeInterface); SubscribeTooltip(ui->useNativeInterface, tooltips.settings.use_native_interface); + m_emu_settings->EnhanceCheckBox(ui->useRecursiveScan, emu_settings_type::UseRecursiveScan); + SubscribeTooltip(ui->useRecursiveScan, tooltips.settings.use_recursive_scan); + #if defined(__linux__) #if defined(GAMEMODE_AVAILABLE) m_emu_settings->EnhanceCheckBox(ui->enableGamemode, emu_settings_type::EnableGamemode); diff --git a/rpcs3/rpcs3qt/settings_dialog.ui b/rpcs3/rpcs3qt/settings_dialog.ui index 77b3f26593..5f0267d865 100644 --- a/rpcs3/rpcs3qt/settings_dialog.ui +++ b/rpcs3/rpcs3qt/settings_dialog.ui @@ -3012,6 +3012,13 @@ + + + + Use recursive scan + + + diff --git a/rpcs3/rpcs3qt/tooltips.h b/rpcs3/rpcs3qt/tooltips.h index 9ec1355392..c7f82c4010 100644 --- a/rpcs3/rpcs3qt/tooltips.h +++ b/rpcs3/rpcs3qt/tooltips.h @@ -157,6 +157,7 @@ public: const QString show_fatal_error_hints = tr("Shows fatal error hints using the native overlay."); const QString show_capture_hints = tr("Shows screenshot and recording hints using the native overlay."); const QString use_native_interface = tr("Enables use of native HUD within the game window that can interact with game controllers.\nWhen disabled, regular Qt dialogs are used instead.\nCurrently, the on-screen keyboard only supports the English key layout."); + const QString use_recursive_scan = tr("Enables use of recursive scan on subfolders when scanning games from the selected folder.\nWhen disabled, games are scanned only on the selected folder."); const QString record_with_overlays = tr("Enables recording with overlays.\nThis also affects screenshots."); const QString pause_during_home_menu = tr("When enabled, opening the home menu will also pause emulation.\nWhile most games pause themselves while the home menu is shown, some do not.\nIn that case it can be helpful to pause the emulation whenever the home menu is open."); const QString play_music_during_boot = tr("Play music during boot sequence if available.");