diff --git a/Source/Core/DolphinNoGUI/MainNoGUI.cpp b/Source/Core/DolphinNoGUI/MainNoGUI.cpp index ecd2d3ba88..5619689abc 100644 --- a/Source/Core/DolphinNoGUI/MainNoGUI.cpp +++ b/Source/Core/DolphinNoGUI/MainNoGUI.cpp @@ -360,14 +360,26 @@ int main(int argc, char* argv[]) optparse::Values& options = CommandLineParse::ParseArguments(parser.get(), argc, argv); std::vector args = parser->args(); - std::string boot_filename; + std::unique_ptr boot; if (options.is_set("exec")) { - boot_filename = static_cast(options.get("exec")); + boot = BootParameters::GenerateFromFile(static_cast(options.get("exec"))); + } + else if (options.is_set("nand_title")) + { + const std::string hex_string = static_cast(options.get("nand_title")); + if (hex_string.length() != 16) + { + fprintf(stderr, "Invalid title ID\n"); + parser->print_help(); + return 1; + } + const u64 title_id = std::stoull(hex_string, nullptr, 16); + boot = std::make_unique(BootParameters::NANDTitle{title_id}); } else if (args.size()) { - boot_filename = args.front(); + boot = BootParameters::GenerateFromFile(args.front()); args.erase(args.begin()); } else @@ -408,9 +420,9 @@ int main(int argc, char* argv[]) DolphinAnalytics::Instance()->ReportDolphinStart("nogui"); - if (!BootManager::BootCore(BootParameters::GenerateFromFile(boot_filename))) + if (!BootManager::BootCore(std::move(boot))) { - fprintf(stderr, "Could not boot %s\n", boot_filename.c_str()); + fprintf(stderr, "Could not boot the specified file\n"); return 1; } diff --git a/Source/Core/DolphinQt2/Main.cpp b/Source/Core/DolphinQt2/Main.cpp index fea2b56379..1a9b66cbae 100644 --- a/Source/Core/DolphinQt2/Main.cpp +++ b/Source/Core/DolphinQt2/Main.cpp @@ -10,6 +10,7 @@ #include "Common/MsgHandler.h" #include "Core/Analytics.h" +#include "Core/Boot/Boot.h" #include "Core/BootManager.h" #include "Core/Core.h" #include "DolphinQt2/Host.h" @@ -84,6 +85,21 @@ int main(int argc, char* argv[]) QObject::connect(QAbstractEventDispatcher::instance(), &QAbstractEventDispatcher::aboutToBlock, &app, &Core::HostDispatchJobs); + std::unique_ptr boot; + if (options.is_set("nand_title")) + { + const std::string hex_string = static_cast(options.get("nand_title")); + if (hex_string.length() == 16) + { + const u64 title_id = std::stoull(hex_string, nullptr, 16); + boot = std::make_unique(BootParameters::NANDTitle{title_id}); + } + else + { + QMessageBox::critical(nullptr, QObject::tr("Error"), QObject::tr("Invalid title ID.")); + } + } + int retval = 0; if (SConfig::GetInstance().m_show_development_warning) @@ -95,7 +111,7 @@ int main(int argc, char* argv[]) { DolphinAnalytics::Instance()->ReportDolphinStart("qt"); - MainWindow win; + MainWindow win{std::move(boot)}; win.show(); #if defined(USE_ANALYTICS) && USE_ANALYTICS diff --git a/Source/Core/DolphinQt2/MainWindow.cpp b/Source/Core/DolphinQt2/MainWindow.cpp index 7ebc6e9546..304327a4b7 100644 --- a/Source/Core/DolphinQt2/MainWindow.cpp +++ b/Source/Core/DolphinQt2/MainWindow.cpp @@ -65,7 +65,7 @@ #include "UICommon/X11Utils.h" #endif -MainWindow::MainWindow() : QMainWindow(nullptr) +MainWindow::MainWindow(std::unique_ptr boot_parameters) : QMainWindow(nullptr) { setWindowTitle(QString::fromStdString(Common::scm_rev_str)); setWindowIcon(QIcon(Resources::GetMisc(Resources::LOGO_SMALL))); @@ -84,6 +84,9 @@ MainWindow::MainWindow() : QMainWindow(nullptr) InitCoreCallbacks(); NetPlayInit(); + + if (boot_parameters) + StartGame(std::move(boot_parameters)); } MainWindow::~MainWindow() diff --git a/Source/Core/DolphinQt2/MainWindow.h b/Source/Core/DolphinQt2/MainWindow.h index 93d5431334..d8db4fc01b 100644 --- a/Source/Core/DolphinQt2/MainWindow.h +++ b/Source/Core/DolphinQt2/MainWindow.h @@ -35,7 +35,7 @@ class MainWindow final : public QMainWindow Q_OBJECT public: - explicit MainWindow(); + explicit MainWindow(std::unique_ptr boot_parameters); ~MainWindow(); bool eventFilter(QObject* object, QEvent* event) override; diff --git a/Source/Core/DolphinWX/Frame.h b/Source/Core/DolphinWX/Frame.h index 30f86ae6dc..4e33b645e5 100644 --- a/Source/Core/DolphinWX/Frame.h +++ b/Source/Core/DolphinWX/Frame.h @@ -106,6 +106,7 @@ public: void StatusBarMessage(const char* format, ...); void ClearStatusBar(); void BootGame(const std::string& filename); + void StartGame(std::unique_ptr boot); bool RendererHasFocus(); bool RendererIsFullscreen(); void OpenGeneralConfiguration(wxWindowID tab_id = wxID_ANY); @@ -193,7 +194,6 @@ private: void InitializeTASDialogs(); void InitializeCoreCallbacks(); - void StartGame(std::unique_ptr boot); void SetDebuggerStartupParameters() const; // Utility diff --git a/Source/Core/DolphinWX/Main.cpp b/Source/Core/DolphinWX/Main.cpp index bff1c34adb..fd87aaea8e 100644 --- a/Source/Core/DolphinWX/Main.cpp +++ b/Source/Core/DolphinWX/Main.cpp @@ -34,6 +34,7 @@ #include "Common/Version.h" #include "Core/Analytics.h" +#include "Core/Boot/Boot.h" #include "Core/ConfigManager.h" #include "Core/Core.h" #include "Core/HW/Wiimote.h" @@ -169,13 +170,24 @@ void DolphinApp::ParseCommandLine() if (options.is_set("exec")) { - m_load_file = true; - m_file_to_load = static_cast(options.get("exec")); + m_boot = BootParameters::GenerateFromFile(static_cast(options.get("exec"))); + } + else if (options.is_set("nand_title")) + { + const std::string hex_string = static_cast(options.get("nand_title")); + if (hex_string.length() == 16) + { + const u64 title_id = std::stoull(hex_string, nullptr, 16); + m_boot = std::make_unique(BootParameters::NANDTitle{title_id}); + } + else + { + WxUtils::ShowErrorDialog(_("The title ID is invalid.")); + } } else if (args.size()) { - m_load_file = true; - m_file_to_load = args.front(); + m_boot = BootParameters::GenerateFromFile(args.front()); args.erase(args.begin()); } @@ -201,9 +213,7 @@ void DolphinApp::ParseCommandLine() #ifdef __APPLE__ void DolphinApp::MacOpenFile(const wxString& fileName) { - m_file_to_load = fileName; - m_load_file = true; - main_frame->BootGame(WxStrToStr(m_file_to_load)); + main_frame->StartGame(BootParameters::GenerateFromFile(fileName.ToStdString())); } #endif @@ -241,20 +251,16 @@ void DolphinApp::AfterInit() { if (Movie::PlayInput(WxStrToStr(m_movie_file))) { - if (m_load_file && !m_file_to_load.empty()) - { - main_frame->BootGame(WxStrToStr(m_file_to_load)); - } + if (m_boot) + main_frame->StartGame(std::move(m_boot)); else - { main_frame->BootGame(""); - } } } // First check if we have an exec command line. - else if (m_load_file && !m_file_to_load.empty()) + else if (m_boot) { - main_frame->BootGame(WxStrToStr(m_file_to_load)); + main_frame->StartGame(std::move(m_boot)); } // If we have selected Automatic Start, start the default ISO, // or if no default ISO exists, start the last loaded ISO diff --git a/Source/Core/DolphinWX/Main.h b/Source/Core/DolphinWX/Main.h index 46f3d80e91..324051fdbd 100644 --- a/Source/Core/DolphinWX/Main.h +++ b/Source/Core/DolphinWX/Main.h @@ -13,6 +13,8 @@ class wxLocale; extern CFrame* main_frame; +struct BootParameters; + // Define a new application class DolphinApp : public wxApp { @@ -43,7 +45,6 @@ private: bool m_batch_mode = false; bool m_confirm_stop = false; bool m_is_active = true; - bool m_load_file = false; bool m_play_movie = false; bool m_use_debugger = false; bool m_use_logger = false; @@ -53,7 +54,7 @@ private: wxString m_video_backend_name; wxString m_audio_emulation_name; wxString m_user_path; - wxString m_file_to_load; + std::unique_ptr m_boot; wxString m_movie_file; std::unique_ptr m_locale; }; diff --git a/Source/Core/UICommon/CommandLineParse.cpp b/Source/Core/UICommon/CommandLineParse.cpp index c5db8b57e0..d76a2052c4 100644 --- a/Source/Core/UICommon/CommandLineParse.cpp +++ b/Source/Core/UICommon/CommandLineParse.cpp @@ -73,6 +73,11 @@ std::unique_ptr CreateParser(ParserOptions options) .metavar("") .type("string") .help("Load the specified file"); + parser->add_option("-n", "--nand_title") + .action("store") + .metavar("<16-character ASCII title ID>") + .type("string") + .help("Launch a NAND title"); parser->add_option("-C", "--config") .action("append") .metavar(".
.=")