diff --git a/pcsx2-qt/Main.cpp b/pcsx2-qt/Main.cpp index b26daa564a..1992dc62e3 100644 --- a/pcsx2-qt/Main.cpp +++ b/pcsx2-qt/Main.cpp @@ -41,7 +41,9 @@ static void PrintCommandLineHelp(const char* progname) std::fprintf(stderr, "\n"); std::fprintf(stderr, " -help: Displays this information and exits.\n"); std::fprintf(stderr, " -version: Displays version information and exits.\n"); - std::fprintf(stderr, " -batch: Enables batch mode (exits after powering off).\n"); + std::fprintf(stderr, " -batch: Enables batch mode (exits after shutting down).\n"); + std::fprintf(stderr, " -elf : Overrides the boot ELF with the specified filename.\n"); + std::fprintf(stderr, " -disc : Uses the specified host DVD drive as a source.\n"); std::fprintf(stderr, " -fastboot: Force fast boot for provided filename.\n"); std::fprintf(stderr, " -slowboot: Force slow boot for provided filename.\n"); std::fprintf(stderr, " -resume: Load resume save state. If a boot filename is provided,\n" @@ -64,10 +66,8 @@ static void PrintCommandLineHelp(const char* progname) static std::shared_ptr& AutoBoot(std::shared_ptr& autoboot) { if (!autoboot) - { autoboot = std::make_shared(); - autoboot->source_type = CDVD_SourceType::NoDisc; - } + return autoboot; } @@ -134,6 +134,12 @@ static bool ParseCommandLineOptions(int argc, char* argv[], std::shared_ptrelf_override = argv[++i]; continue; } + else if (CHECK_ARG_PARAM("-disc")) + { + AutoBoot(autoboot)->source_type = CDVD_SourceType::Disc; + AutoBoot(autoboot)->filename = argv[++i]; + continue; + } else if (CHECK_ARG("-fullscreen")) { Console.WriteLn("Going fullscreen after booting."); @@ -172,12 +178,10 @@ static bool ParseCommandLineOptions(int argc, char* argv[], std::shared_ptrsource.empty()) - AutoBoot(autoboot)->source += ' '; - else - AutoBoot(autoboot)->source_type = CDVD_SourceType::Iso; + if (!AutoBoot(autoboot)->filename.empty()) + AutoBoot(autoboot)->filename += ' '; - AutoBoot(autoboot)->source += argv[i]; + AutoBoot(autoboot)->filename += argv[i]; } return true; diff --git a/pcsx2-qt/MainWindow.cpp b/pcsx2-qt/MainWindow.cpp index fad60120b7..a025c7aa1f 100644 --- a/pcsx2-qt/MainWindow.cpp +++ b/pcsx2-qt/MainWindow.cpp @@ -608,7 +608,10 @@ void MainWindow::clearProgressBar() m_ui.statusBar->removeWidget(m_status_progress_widget); } -bool MainWindow::isShowingGameList() const { return m_ui.mainContainer->currentIndex() == 0; } +bool MainWindow::isShowingGameList() const +{ + return m_ui.mainContainer->currentIndex() == 0; +} void MainWindow::switchToGameListView() { @@ -641,11 +644,20 @@ void MainWindow::switchToEmulationView() m_display_widget->setFocus(); } -void MainWindow::refreshGameList(bool invalidate_cache) { m_game_list_widget->refresh(invalidate_cache); } +void MainWindow::refreshGameList(bool invalidate_cache) +{ + m_game_list_widget->refresh(invalidate_cache); +} -void MainWindow::invalidateSaveStateCache() { m_save_states_invalidated = true; } +void MainWindow::invalidateSaveStateCache() +{ + m_save_states_invalidated = true; +} -void MainWindow::reportError(const QString& title, const QString& message) { QMessageBox::critical(this, title, message); } +void MainWindow::reportError(const QString& title, const QString& message) +{ + QMessageBox::critical(this, title, message); +} bool MainWindow::confirmShutdown() { @@ -666,7 +678,10 @@ void MainWindow::requestExit() close(); } -void Host::InvalidateSaveStateCache() { QMetaObject::invokeMethod(g_main_window, &MainWindow::invalidateSaveStateCache, Qt::QueuedConnection); } +void Host::InvalidateSaveStateCache() +{ + QMetaObject::invokeMethod(g_main_window, &MainWindow::invalidateSaveStateCache, Qt::QueuedConnection); +} void MainWindow::onGameListRefreshProgress(const QString& status, int current, int total) { @@ -674,7 +689,10 @@ void MainWindow::onGameListRefreshProgress(const QString& status, int current, i setProgressBar(current, total); } -void MainWindow::onGameListRefreshComplete() { clearProgressBar(); } +void MainWindow::onGameListRefreshComplete() +{ + clearProgressBar(); +} void MainWindow::onGameListSelectionChanged() { @@ -785,14 +803,13 @@ void MainWindow::onStartFileActionTriggered() return; std::shared_ptr params = std::make_shared(); - VMManager::SetBootParametersForPath(filename.toStdString(), params.get()); + params->filename = filename.toStdString(); g_emu_thread->startVM(std::move(params)); } void MainWindow::onStartBIOSActionTriggered() { std::shared_ptr params = std::make_shared(); - params->source_type = CDVD_SourceType::NoDisc; g_emu_thread->startVM(std::move(params)); } @@ -807,7 +824,10 @@ void MainWindow::onChangeDiscFromFileActionTriggered() g_emu_thread->changeDisc(filename); } -void MainWindow::onChangeDiscFromGameListActionTriggered() { switchToGameListView(); } +void MainWindow::onChangeDiscFromGameListActionTriggered() +{ + switchToGameListView(); +} void MainWindow::onChangeDiscFromDeviceActionTriggered() { @@ -891,11 +911,20 @@ void MainWindow::onViewGamePropertiesActionTriggered() SettingsDialog::openGamePropertiesDialog(nullptr, m_current_game_crc); } -void MainWindow::onGitHubRepositoryActionTriggered() { QtUtils::OpenURL(this, AboutDialog::getGitHubRepositoryUrl()); } +void MainWindow::onGitHubRepositoryActionTriggered() +{ + QtUtils::OpenURL(this, AboutDialog::getGitHubRepositoryUrl()); +} -void MainWindow::onSupportForumsActionTriggered() { QtUtils::OpenURL(this, AboutDialog::getSupportForumsUrl()); } +void MainWindow::onSupportForumsActionTriggered() +{ + QtUtils::OpenURL(this, AboutDialog::getSupportForumsUrl()); +} -void MainWindow::onDiscordServerActionTriggered() { QtUtils::OpenURL(this, AboutDialog::getDiscordServerUrl()); } +void MainWindow::onDiscordServerActionTriggered() +{ + QtUtils::OpenURL(this, AboutDialog::getDiscordServerUrl()); +} void MainWindow::onAboutActionTriggered() { @@ -1197,7 +1226,10 @@ void MainWindow::displayResizeRequested(qint32 width, qint32 height) resize(QSize(std::max(width, 1), std::max(height + extra_height, 1))); } -void MainWindow::destroyDisplay() { destroyDisplayWidget(); } +void MainWindow::destroyDisplay() +{ + destroyDisplayWidget(); +} void MainWindow::focusDisplayWidget() { @@ -1404,7 +1436,7 @@ void MainWindow::loadSaveStateFile(const QString& filename, const QString& state else { std::shared_ptr params = std::make_shared(); - VMManager::SetBootParametersForPath(filename.toStdString(), params.get()); + params->filename = filename.toStdString(); params->save_state = state_filename.toStdString(); g_emu_thread->startVM(std::move(params)); } diff --git a/pcsx2/Frontend/GameList.cpp b/pcsx2/Frontend/GameList.cpp index ed2735ea4c..d04fc58123 100644 --- a/pcsx2/Frontend/GameList.cpp +++ b/pcsx2/Frontend/GameList.cpp @@ -123,19 +123,19 @@ void GameList::FillBootParametersForEntry(VMBootParameters* params, const Entry* { if (entry->type == GameList::EntryType::PS1Disc || entry->type == GameList::EntryType::PS2Disc) { - params->source = entry->path; + params->filename = entry->path; params->source_type = CDVD_SourceType::Iso; params->elf_override.clear(); } else if (entry->type == GameList::EntryType::ELF) { - params->source.clear(); + params->filename.clear(); params->source_type = CDVD_SourceType::NoDisc; params->elf_override = entry->path; } else { - params->source.clear(); + params->filename.clear(); params->source_type = CDVD_SourceType::NoDisc; params->elf_override.clear(); } diff --git a/pcsx2/VMManager.cpp b/pcsx2/VMManager.cpp index b81d6787bc..e53a68a399 100644 --- a/pcsx2/VMManager.cpp +++ b/pcsx2/VMManager.cpp @@ -75,6 +75,9 @@ namespace VMManager static void CheckForSPU2ConfigChanges(const Pcsx2Config& old_config); static void CheckForDEV9ConfigChanges(const Pcsx2Config& old_config); static void CheckForMemoryCardConfigChanges(const Pcsx2Config& old_config); + + static bool AutoDetectSource(const std::string& filename); + static bool ApplyBootParameters(const VMBootParameters& params); static void UpdateRunningGame(bool force); static std::string GetCurrentSaveStateFileName(s32 slot); @@ -519,30 +522,86 @@ static LimiterModeType GetInitialLimiterMode() return EmuConfig.GS.FrameLimitEnable ? LimiterModeType::Nominal : LimiterModeType::Unlimited; } -static void ApplyBootParameters(const VMBootParameters& params) +bool VMManager::AutoDetectSource(const std::string& filename) +{ + if (!filename.empty()) + { + if (!FileSystem::FileExists(filename.c_str())) + { + Host::ReportFormattedErrorAsync("Error", "Requested filename '%s' does not exist.", filename.c_str()); + return false; + } + + const std::string display_name(FileSystem::GetDisplayNameFromPath(filename)); + if (IsGSDumpFileName(display_name)) + { + CDVDsys_ChangeSource(CDVD_SourceType::NoDisc); + return GSDumpReplayer::Initialize(filename.c_str()); + } + else if (IsElfFileName(display_name)) + { + // alternative way of booting an elf, change the elf override, and use no disc. + CDVDsys_ChangeSource(CDVD_SourceType::NoDisc); + s_elf_override = filename; + return true; + } + else + { + // TODO: Maybe we should check if it's a valid iso here... + CDVDsys_SetFile(CDVD_SourceType::Iso, filename); + CDVDsys_ChangeSource(CDVD_SourceType::Iso); + s_disc_path = filename; + return true; + } + } + else + { + // make sure we're not fast booting when we have no filename + CDVDsys_ChangeSource(CDVD_SourceType::NoDisc); + EmuConfig.UseBOOT2Injection = false; + return true; + } +} + +bool VMManager::ApplyBootParameters(const VMBootParameters& params) { const bool default_fast_boot = Host::GetBoolSettingValue("EmuCore", "EnableFastBoot", true); - EmuConfig.UseBOOT2Injection = - (params.source_type != CDVD_SourceType::NoDisc && params.fast_boot.value_or(default_fast_boot)); + EmuConfig.UseBOOT2Injection = params.fast_boot.value_or(default_fast_boot); + s_elf_override = params.elf_override; + s_disc_path.clear(); - CDVDsys_SetFile(CDVD_SourceType::Iso, params.source); - CDVDsys_ChangeSource(params.source_type); - - if (!params.elf_override.empty()) + if (params.source_type.has_value()) { - Hle_SetElfPath(params.elf_override.c_str()); - s_elf_override = std::move(params.elf_override); + if (params.source_type.value() == CDVD_SourceType::Iso && !FileSystem::FileExists(params.filename.c_str())) + { + Host::ReportFormattedErrorAsync("Error", "Requested filename '%s' does not exist.", params.filename.c_str()); + return false; + } + + // Use specified source type. + CDVDsys_SetFile(params.source_type.value(), params.filename); + CDVDsys_ChangeSource(params.source_type.value()); + } + else + { + // Automatic type detection of boot parameter based on filename. + if (!AutoDetectSource(params.filename)) + return false; + } + + if (!s_elf_override.empty()) + { + if (!FileSystem::FileExists(s_elf_override.c_str())) + { + Host::ReportFormattedErrorAsync("Error", "Requested boot ELF '%s' does not exist.", s_elf_override.c_str()); + return false; + } + + Hle_SetElfPath(s_elf_override.c_str()); EmuConfig.UseBOOT2Injection = true; } - else - { - std::string().swap(s_elf_override); - } - if (params.source_type == CDVD_SourceType::Iso) - s_disc_path = params.source; - else - s_disc_path.clear(); + return true; } bool VMManager::Initialize(const VMBootParameters& boot_params) @@ -559,16 +618,8 @@ bool VMManager::Initialize(const VMBootParameters& boot_params) LoadSettings(); - if (IsGSDumpFileName(boot_params.source)) - { - CDVDsys_ChangeSource(CDVD_SourceType::NoDisc); - if (!GSDumpReplayer::Initialize(boot_params.source.c_str())) - return false; - } - else - { - ApplyBootParameters(boot_params); - } + if (!ApplyBootParameters(boot_params)) + return false; EmuConfig.LimiterMode = GetInitialLimiterMode(); @@ -949,11 +1000,7 @@ bool VMManager::ChangeDisc(std::string path) bool VMManager::IsElfFileName(const std::string& path) { - const std::string::size_type pos = path.rfind('.'); - if (pos == std::string::npos) - return false; - - return (StringUtil::Strcasecmp(&path[pos], ".elf") == 0); + return StringUtil::EndsWithNoCase(path, ".elf"); } bool VMManager::IsGSDumpFileName(const std::string& path) @@ -961,29 +1008,6 @@ bool VMManager::IsGSDumpFileName(const std::string& path) return (StringUtil::EndsWithNoCase(path, ".gs") || StringUtil::EndsWithNoCase(path, ".gs.xz")); } -void VMManager::SetBootParametersForPath(const std::string& path, VMBootParameters* params) -{ - if (IsElfFileName(path)) - { - params->elf_override = path; - params->source_type = CDVD_SourceType::NoDisc; - } - else if (IsGSDumpFileName(path)) - { - params->source_type = CDVD_SourceType::NoDisc; - params->source = path; - } - else if (!path.empty()) - { - params->source_type = CDVD_SourceType::Iso; - params->source = path; - } - else - { - params->source_type = CDVD_SourceType::NoDisc; - } -} - void VMManager::Execute() { Cpu->Execute(); diff --git a/pcsx2/VMManager.h b/pcsx2/VMManager.h index 6eaa2dad20..fcee0167f9 100644 --- a/pcsx2/VMManager.h +++ b/pcsx2/VMManager.h @@ -39,10 +39,11 @@ enum class VMState struct VMBootParameters { - std::string source; - std::string save_state; - CDVD_SourceType source_type; + std::string filename; std::string elf_override; + std::string save_state; + std::optional source_type; + std::optional fast_boot; std::optional fullscreen; std::optional batch_mode; @@ -138,9 +139,6 @@ namespace VMManager /// Returns true if the specified path is a GS Dump. bool IsGSDumpFileName(const std::string& path); - /// Updates boot parameters for a given start filename. If it's an elf, it'll set elf_override, otherwise source. - void SetBootParametersForPath(const std::string& path, VMBootParameters* params); - /// Returns the path for the game settings ini file for the specified CRC. std::string GetGameSettingsPath(u32 game_crc);