From 83ad84061e05fd7d07998757aa3fc9622066573f Mon Sep 17 00:00:00 2001 From: "Admiral H. Curtiss" Date: Sat, 20 Nov 2021 19:38:09 +0100 Subject: [PATCH 1/4] Core/Boot: Refactor storage of boot-to-savestate data into a separate class. --- Source/Android/jni/MainAndroid.cpp | 14 +++--- Source/Core/Core/Boot/Boot.cpp | 63 +++++++++++++++++++------- Source/Core/Core/Boot/Boot.h | 37 +++++++++++++-- Source/Core/Core/BootManager.cpp | 2 +- Source/Core/Core/Core.cpp | 6 ++- Source/Core/DolphinNoGUI/MainNoGUI.cpp | 6 ++- Source/Core/DolphinQt/Main.cpp | 6 ++- Source/Core/DolphinQt/MainWindow.cpp | 36 +++++++++------ Source/Core/DolphinQt/MainWindow.h | 9 ++-- 9 files changed, 126 insertions(+), 53 deletions(-) diff --git a/Source/Android/jni/MainAndroid.cpp b/Source/Android/jni/MainAndroid.cpp index c08106ee4f..4b94996796 100644 --- a/Source/Android/jni/MainAndroid.cpp +++ b/Source/Android/jni/MainAndroid.cpp @@ -549,8 +549,7 @@ static float GetRenderSurfaceScale(JNIEnv* env) } static void Run(JNIEnv* env, const std::vector& paths, bool riivolution, - const std::optional& savestate_path = {}, - bool delete_savestate = false) + BootSessionData boot_session_data = BootSessionData()) { ASSERT(!paths.empty()); __android_log_print(ANDROID_LOG_INFO, DOLPHIN_TAG, "Running : %s", paths[0].c_str()); @@ -561,9 +560,8 @@ static void Run(JNIEnv* env, const std::vector& paths, bool riivolu s_have_wm_user_stop = false; - std::unique_ptr boot = BootParameters::GenerateFromFile(paths, savestate_path); - if (boot) - boot->delete_savestate = delete_savestate; + std::unique_ptr boot = + BootParameters::GenerateFromFile(paths, std::move(boot_session_data)); if (riivolution && std::holds_alternative(boot->parameters)) { @@ -638,8 +636,10 @@ Java_org_dolphinemu_dolphinemu_NativeLibrary_Run___3Ljava_lang_String_2ZLjava_la JNIEnv* env, jclass, jobjectArray jPaths, jboolean jRiivolution, jstring jSavestate, jboolean jDeleteSavestate) { - Run(env, JStringArrayToVector(env, jPaths), jRiivolution, GetJString(env, jSavestate), - jDeleteSavestate); + DeleteSavestateAfterBoot delete_state = + jDeleteSavestate ? DeleteSavestateAfterBoot::Yes : DeleteSavestateAfterBoot::No; + Run(env, JStringArrayToVector(env, jPaths), jRiivolution, + BootSessionData(GetJString(env, jSavestate), delete_state)); } JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_ChangeDisc(JNIEnv* env, jclass, diff --git a/Source/Core/Core/Boot/Boot.cpp b/Source/Core/Core/Boot/Boot.cpp index 3bb2c5e53d..39f5c1c69d 100644 --- a/Source/Core/Core/Boot/Boot.cpp +++ b/Source/Core/Core/Boot/Boot.cpp @@ -112,22 +112,53 @@ static std::vector ReadM3UFile(const std::string& m3u_path, return result; } -BootParameters::BootParameters(Parameters&& parameters_, - const std::optional& savestate_path_) - : parameters(std::move(parameters_)), savestate_path(savestate_path_) +BootSessionData::BootSessionData() { } -std::unique_ptr -BootParameters::GenerateFromFile(std::string boot_path, - const std::optional& savestate_path) +BootSessionData::BootSessionData(std::optional savestate_path, + DeleteSavestateAfterBoot delete_savestate) + : m_savestate_path(std::move(savestate_path)), m_delete_savestate(delete_savestate) { - return GenerateFromFile(std::vector{std::move(boot_path)}, savestate_path); } -std::unique_ptr -BootParameters::GenerateFromFile(std::vector paths, - const std::optional& savestate_path) +BootSessionData::BootSessionData(BootSessionData&& other) = default; + +BootSessionData& BootSessionData::operator=(BootSessionData&& other) = default; + +BootSessionData::~BootSessionData() = default; + +const std::optional& BootSessionData::GetSavestatePath() const +{ + return m_savestate_path; +} + +DeleteSavestateAfterBoot BootSessionData::GetDeleteSavestate() const +{ + return m_delete_savestate; +} + +void BootSessionData::SetSavestateData(std::optional savestate_path, + DeleteSavestateAfterBoot delete_savestate) +{ + m_savestate_path = std::move(savestate_path); + m_delete_savestate = delete_savestate; +} + +BootParameters::BootParameters(Parameters&& parameters_, BootSessionData boot_session_data_) + : parameters(std::move(parameters_)), boot_session_data(std::move(boot_session_data_)) +{ +} + +std::unique_ptr BootParameters::GenerateFromFile(std::string boot_path, + BootSessionData boot_session_data_) +{ + return GenerateFromFile(std::vector{std::move(boot_path)}, + std::move(boot_session_data_)); +} + +std::unique_ptr BootParameters::GenerateFromFile(std::vector paths, + BootSessionData boot_session_data_) { ASSERT(!paths.empty()); @@ -176,21 +207,21 @@ BootParameters::GenerateFromFile(std::vector paths, if (disc) { return std::make_unique(Disc{std::move(path), std::move(disc), paths}, - savestate_path); + std::move(boot_session_data_)); } if (extension == ".elf") { auto elf_reader = std::make_unique(path); return std::make_unique(Executable{std::move(path), std::move(elf_reader)}, - savestate_path); + std::move(boot_session_data_)); } if (extension == ".dol") { auto dol_reader = std::make_unique(path); return std::make_unique(Executable{std::move(path), std::move(dol_reader)}, - savestate_path); + std::move(boot_session_data_)); } if (is_drive) @@ -209,13 +240,13 @@ BootParameters::GenerateFromFile(std::vector paths, } if (extension == ".dff") - return std::make_unique(DFF{std::move(path)}, savestate_path); + return std::make_unique(DFF{std::move(path)}, std::move(boot_session_data_)); if (extension == ".wad") { std::unique_ptr wad = DiscIO::CreateWAD(std::move(path)); if (wad) - return std::make_unique(std::move(*wad), savestate_path); + return std::make_unique(std::move(*wad), std::move(boot_session_data_)); } if (extension == ".json") @@ -223,7 +254,7 @@ BootParameters::GenerateFromFile(std::vector paths, auto descriptor = DiscIO::ParseGameModDescriptorFile(path); if (descriptor) { - auto boot_params = GenerateFromFile(descriptor->base_file, savestate_path); + auto boot_params = GenerateFromFile(descriptor->base_file, std::move(boot_session_data_)); if (!boot_params) { PanicAlertFmtT("Could not recognize file {0}", descriptor->base_file); diff --git a/Source/Core/Core/Boot/Boot.h b/Source/Core/Core/Boot/Boot.h index d9a891966b..b0564f751f 100644 --- a/Source/Core/Core/Boot/Boot.h +++ b/Source/Core/Core/Boot/Boot.h @@ -34,6 +34,34 @@ struct RegionSetting class BootExecutableReader; +enum class DeleteSavestateAfterBoot : u8 +{ + No, + Yes +}; + +class BootSessionData +{ +public: + BootSessionData(); + BootSessionData(std::optional savestate_path, + DeleteSavestateAfterBoot delete_savestate); + BootSessionData(const BootSessionData& other) = delete; + BootSessionData(BootSessionData&& other); + BootSessionData& operator=(const BootSessionData& other) = delete; + BootSessionData& operator=(BootSessionData&& other); + ~BootSessionData(); + + const std::optional& GetSavestatePath() const; + DeleteSavestateAfterBoot GetDeleteSavestate() const; + void SetSavestateData(std::optional savestate_path, + DeleteSavestateAfterBoot delete_savestate); + +private: + std::optional m_savestate_path; + DeleteSavestateAfterBoot m_delete_savestate = DeleteSavestateAfterBoot::No; +}; + struct BootParameters { struct Disc @@ -70,18 +98,17 @@ struct BootParameters }; static std::unique_ptr - GenerateFromFile(std::string boot_path, const std::optional& savestate_path = {}); + GenerateFromFile(std::string boot_path, BootSessionData boot_session_data_ = BootSessionData()); static std::unique_ptr GenerateFromFile(std::vector paths, - const std::optional& savestate_path = {}); + BootSessionData boot_session_data_ = BootSessionData()); using Parameters = std::variant; - BootParameters(Parameters&& parameters_, const std::optional& savestate_path_ = {}); + BootParameters(Parameters&& parameters_, BootSessionData boot_session_data_ = BootSessionData()); Parameters parameters; std::vector riivolution_patches; - std::optional savestate_path; - bool delete_savestate = false; + BootSessionData boot_session_data; }; class CBoot diff --git a/Source/Core/Core/BootManager.cpp b/Source/Core/Core/BootManager.cpp index fca36916b3..83361a1c1e 100644 --- a/Source/Core/Core/BootManager.cpp +++ b/Source/Core/Core/BootManager.cpp @@ -450,7 +450,7 @@ bool BootCore(std::unique_ptr boot, const WindowSystemInfo& wsi) std::make_unique( BootParameters::IPL{StartUp.m_region, std::move(std::get(boot->parameters))}, - boot->savestate_path), + std::move(boot->boot_session_data)), wsi); } return Core::Init(std::move(boot), wsi); diff --git a/Source/Core/Core/Core.cpp b/Source/Core/Core/Core.cpp index 622d7f9d90..e4a7dc7e46 100644 --- a/Source/Core/Core/Core.cpp +++ b/Source/Core/Core/Core.cpp @@ -479,8 +479,10 @@ static void EmuThread(std::unique_ptr boot, WindowSystemInfo wsi Keyboard::LoadConfig(); } - const std::optional savestate_path = boot->savestate_path; - const bool delete_savestate = boot->delete_savestate; + BootSessionData boot_session_data = std::move(boot->boot_session_data); + const std::optional& savestate_path = boot_session_data.GetSavestatePath(); + const bool delete_savestate = + boot_session_data.GetDeleteSavestate() == DeleteSavestateAfterBoot::Yes; // Load and Init Wiimotes - only if we are booting in Wii mode bool init_wiimotes = false; diff --git a/Source/Core/DolphinNoGUI/MainNoGUI.cpp b/Source/Core/DolphinNoGUI/MainNoGUI.cpp index 26b0e69a22..f439130441 100644 --- a/Source/Core/DolphinNoGUI/MainNoGUI.cpp +++ b/Source/Core/DolphinNoGUI/MainNoGUI.cpp @@ -187,7 +187,8 @@ int main(int argc, char* argv[]) const std::list paths_list = options.all("exec"); const std::vector paths{std::make_move_iterator(std::begin(paths_list)), std::make_move_iterator(std::end(paths_list))}; - boot = BootParameters::GenerateFromFile(paths, save_state_path); + boot = BootParameters::GenerateFromFile( + paths, BootSessionData(save_state_path, DeleteSavestateAfterBoot::No)); game_specified = true; } else if (options.is_set("nand_title")) @@ -204,7 +205,8 @@ int main(int argc, char* argv[]) } else if (args.size()) { - boot = BootParameters::GenerateFromFile(args.front(), save_state_path); + boot = BootParameters::GenerateFromFile( + args.front(), BootSessionData(save_state_path, DeleteSavestateAfterBoot::No)); args.erase(args.begin()); game_specified = true; } diff --git a/Source/Core/DolphinQt/Main.cpp b/Source/Core/DolphinQt/Main.cpp index f7e8084dab..9c05198ca7 100644 --- a/Source/Core/DolphinQt/Main.cpp +++ b/Source/Core/DolphinQt/Main.cpp @@ -197,7 +197,8 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine const std::list paths_list = options.all("exec"); const std::vector paths{std::make_move_iterator(std::begin(paths_list)), std::make_move_iterator(std::end(paths_list))}; - boot = BootParameters::GenerateFromFile(paths, save_state_path); + boot = BootParameters::GenerateFromFile( + paths, BootSessionData(save_state_path, DeleteSavestateAfterBoot::No)); game_specified = true; } else if (options.is_set("nand_title")) @@ -216,7 +217,8 @@ int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine } else if (!args.empty()) { - boot = BootParameters::GenerateFromFile(args.front(), save_state_path); + boot = BootParameters::GenerateFromFile( + args.front(), BootSessionData(save_state_path, DeleteSavestateAfterBoot::No)); game_specified = true; } diff --git a/Source/Core/DolphinQt/MainWindow.cpp b/Source/Core/DolphinQt/MainWindow.cpp index 7e442398dd..c245a41557 100644 --- a/Source/Core/DolphinQt/MainWindow.cpp +++ b/Source/Core/DolphinQt/MainWindow.cpp @@ -244,8 +244,13 @@ MainWindow::MainWindow(std::unique_ptr boot_parameters, if (!movie_path.empty()) { - if (Movie::PlayInput(movie_path, &m_pending_boot->savestate_path)) + std::optional savestate_path; + if (Movie::PlayInput(movie_path, &savestate_path)) + { + m_pending_boot->boot_session_data.SetSavestateData(std::move(savestate_path), + DeleteSavestateAfterBoot::No); emit RecordingStatusChanged(true); + } } } @@ -768,14 +773,16 @@ void MainWindow::Play(const std::optional& savestate_path) std::shared_ptr selection = m_game_list->GetSelectedGame(); if (selection) { - StartGame(selection->GetFilePath(), ScanForSecondDisc::Yes, savestate_path); + StartGame(selection->GetFilePath(), ScanForSecondDisc::Yes, + std::make_unique(savestate_path, DeleteSavestateAfterBoot::No)); } else { const QString default_path = QString::fromStdString(Config::Get(Config::MAIN_DEFAULT_ISO)); if (!default_path.isEmpty() && QFile::exists(default_path)) { - StartGame(default_path, ScanForSecondDisc::Yes, savestate_path); + StartGame(default_path, ScanForSecondDisc::Yes, + std::make_unique(savestate_path, DeleteSavestateAfterBoot::No)); } else { @@ -978,7 +985,7 @@ void MainWindow::ScreenShot() } void MainWindow::ScanForSecondDiscAndStartGame(const UICommon::GameFile& game, - const std::optional& savestate_path) + std::unique_ptr boot_session_data) { auto second_game = m_game_list->FindSecondDisc(game); @@ -986,35 +993,37 @@ void MainWindow::ScanForSecondDiscAndStartGame(const UICommon::GameFile& game, if (second_game != nullptr) paths.push_back(second_game->GetFilePath()); - StartGame(paths, savestate_path); + StartGame(paths, std::move(boot_session_data)); } void MainWindow::StartGame(const QString& path, ScanForSecondDisc scan, - const std::optional& savestate_path) + std::unique_ptr boot_session_data) { - StartGame(path.toStdString(), scan, savestate_path); + StartGame(path.toStdString(), scan, std::move(boot_session_data)); } void MainWindow::StartGame(const std::string& path, ScanForSecondDisc scan, - const std::optional& savestate_path) + std::unique_ptr boot_session_data) { if (scan == ScanForSecondDisc::Yes) { std::shared_ptr game = m_game_list->FindGame(path); if (game != nullptr) { - ScanForSecondDiscAndStartGame(*game, savestate_path); + ScanForSecondDiscAndStartGame(*game, std::move(boot_session_data)); return; } } - StartGame(BootParameters::GenerateFromFile(path, savestate_path)); + StartGame(BootParameters::GenerateFromFile( + path, boot_session_data ? std::move(*boot_session_data) : BootSessionData())); } void MainWindow::StartGame(const std::vector& paths, - const std::optional& savestate_path) + std::unique_ptr boot_session_data) { - StartGame(BootParameters::GenerateFromFile(paths, savestate_path)); + StartGame(BootParameters::GenerateFromFile( + paths, boot_session_data ? std::move(*boot_session_data) : BootSessionData())); } void MainWindow::StartGame(std::unique_ptr&& parameters) @@ -1818,8 +1827,7 @@ void MainWindow::ShowRiivolutionBootWidget(const UICommon::GameFile& game) std::vector paths = {game.GetFilePath()}; if (second_game != nullptr) paths.push_back(second_game->GetFilePath()); - std::unique_ptr boot_params = - BootParameters::GenerateFromFile(paths, std::nullopt); + std::unique_ptr boot_params = BootParameters::GenerateFromFile(paths); if (!boot_params) return; if (!std::holds_alternative(boot_params->parameters)) diff --git a/Source/Core/DolphinQt/MainWindow.h b/Source/Core/DolphinQt/MainWindow.h index c0e97af96d..6e53f2df10 100644 --- a/Source/Core/DolphinQt/MainWindow.h +++ b/Source/Core/DolphinQt/MainWindow.h @@ -15,6 +15,7 @@ class QStackedWidget; class QString; class BreakpointWidget; +class BootSessionData; struct BootParameters; class CheatsManager; class CodeWidget; @@ -132,13 +133,13 @@ private: }; void ScanForSecondDiscAndStartGame(const UICommon::GameFile& game, - const std::optional& savestate_path = {}); + std::unique_ptr boot_session_data = nullptr); void StartGame(const QString& path, ScanForSecondDisc scan, - const std::optional& savestate_path = {}); + std::unique_ptr boot_session_data = nullptr); void StartGame(const std::string& path, ScanForSecondDisc scan, - const std::optional& savestate_path = {}); + std::unique_ptr boot_session_data = nullptr); void StartGame(const std::vector& paths, - const std::optional& savestate_path = {}); + std::unique_ptr boot_session_data = nullptr); void StartGame(std::unique_ptr&& parameters); void ShowRenderWidget(); void HideRenderWidget(bool reinit = true, bool is_exit = false); From 7b776f376912f66d85f3aa6a68de39106c6144b8 Mon Sep 17 00:00:00 2001 From: "Admiral H. Curtiss" Date: Sat, 20 Nov 2021 19:59:14 +0100 Subject: [PATCH 2/4] NetPlay: Refactor game boot code path to allow passing BootSessionData through it. --- Source/Core/Core/NetPlayClient.cpp | 3 ++- Source/Core/Core/NetPlayClient.h | 5 ++++- Source/Core/DolphinQt/MainWindow.cpp | 8 +++++--- Source/Core/DolphinQt/NetPlay/NetPlayDialog.cpp | 12 ++++++++---- Source/Core/DolphinQt/NetPlay/NetPlayDialog.h | 17 ++++++++++++++--- 5 files changed, 33 insertions(+), 12 deletions(-) diff --git a/Source/Core/Core/NetPlayClient.cpp b/Source/Core/Core/NetPlayClient.cpp index e4cba66429..30f9f6871b 100644 --- a/Source/Core/Core/NetPlayClient.cpp +++ b/Source/Core/Core/NetPlayClient.cpp @@ -33,6 +33,7 @@ #include "Common/Version.h" #include "Core/ActionReplay.h" +#include "Core/Boot/Boot.h" #include "Core/Config/MainSettings.h" #include "Core/Config/NetplaySettings.h" #include "Core/Config/SessionSettings.h" @@ -1721,7 +1722,7 @@ bool NetPlayClient::StartGame(const std::string& path) } // boot game - m_dialog->BootGame(path); + m_dialog->BootGame(path, nullptr); UpdateDevices(); diff --git a/Source/Core/Core/NetPlayClient.h b/Source/Core/Core/NetPlayClient.h index 3c02cad266..4487358523 100644 --- a/Source/Core/Core/NetPlayClient.h +++ b/Source/Core/Core/NetPlayClient.h @@ -23,6 +23,8 @@ #include "Core/SyncIdentifier.h" #include "InputCommon/GCPadStatus.h" +class BootSessionData; + namespace UICommon { class GameFile; @@ -34,7 +36,8 @@ class NetPlayUI { public: virtual ~NetPlayUI() {} - virtual void BootGame(const std::string& filename) = 0; + virtual void BootGame(const std::string& filename, + std::unique_ptr boot_session_data) = 0; virtual void StopGame() = 0; virtual bool IsHosting() const = 0; diff --git a/Source/Core/DolphinQt/MainWindow.cpp b/Source/Core/DolphinQt/MainWindow.cpp index c245a41557..aacdea6a71 100644 --- a/Source/Core/DolphinQt/MainWindow.cpp +++ b/Source/Core/DolphinQt/MainWindow.cpp @@ -1372,13 +1372,15 @@ void MainWindow::NetPlayInit() { const auto& game_list_model = m_game_list->GetGameListModel(); m_netplay_setup_dialog = new NetPlaySetupDialog(game_list_model, this); - m_netplay_dialog = new NetPlayDialog(game_list_model); + m_netplay_dialog = new NetPlayDialog( + game_list_model, + [this](const std::string& path, std::unique_ptr boot_session_data) { + StartGame(path, ScanForSecondDisc::Yes, std::move(boot_session_data)); + }); #ifdef USE_DISCORD_PRESENCE m_netplay_discord = new DiscordHandler(this); #endif - connect(m_netplay_dialog, &NetPlayDialog::Boot, this, - [this](const QString& path) { StartGame(path, ScanForSecondDisc::Yes); }); connect(m_netplay_dialog, &NetPlayDialog::Stop, this, &MainWindow::ForceStop); connect(m_netplay_dialog, &NetPlayDialog::rejected, this, &MainWindow::NetPlayQuit); connect(m_netplay_setup_dialog, &NetPlaySetupDialog::Join, this, &MainWindow::NetPlayJoin); diff --git a/Source/Core/DolphinQt/NetPlay/NetPlayDialog.cpp b/Source/Core/DolphinQt/NetPlay/NetPlayDialog.cpp index 464cb506db..7e05a51add 100644 --- a/Source/Core/DolphinQt/NetPlay/NetPlayDialog.cpp +++ b/Source/Core/DolphinQt/NetPlay/NetPlayDialog.cpp @@ -31,6 +31,7 @@ #include "Common/Logging/Log.h" #include "Common/TraversalClient.h" +#include "Core/Boot/Boot.h" #include "Core/Config/GraphicsSettings.h" #include "Core/Config/MainSettings.h" #include "Core/Config/NetplaySettings.h" @@ -62,8 +63,10 @@ #include "VideoCommon/RenderBase.h" #include "VideoCommon/VideoConfig.h" -NetPlayDialog::NetPlayDialog(const GameListModel& game_list_model, QWidget* parent) - : QDialog(parent), m_game_list_model(game_list_model) +NetPlayDialog::NetPlayDialog(const GameListModel& game_list_model, + StartGameCallback start_game_callback, QWidget* parent) + : QDialog(parent), m_game_list_model(game_list_model), + m_start_game_callback(std::move(start_game_callback)) { setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); @@ -682,10 +685,11 @@ void NetPlayDialog::UpdateGUI() // NetPlayUI methods -void NetPlayDialog::BootGame(const std::string& filename) +void NetPlayDialog::BootGame(const std::string& filename, + std::unique_ptr boot_session_data) { m_got_stop_request = false; - emit Boot(QString::fromStdString(filename)); + m_start_game_callback(filename, std::move(boot_session_data)); } void NetPlayDialog::StopGame() diff --git a/Source/Core/DolphinQt/NetPlay/NetPlayDialog.h b/Source/Core/DolphinQt/NetPlay/NetPlayDialog.h index b2753236ba..5844c25cb4 100644 --- a/Source/Core/DolphinQt/NetPlay/NetPlayDialog.h +++ b/Source/Core/DolphinQt/NetPlay/NetPlayDialog.h @@ -3,6 +3,10 @@ #pragma once +#include +#include +#include + #include #include @@ -11,6 +15,7 @@ #include "DolphinQt/GameList/GameListModel.h" #include "VideoCommon/OnScreenDisplay.h" +class BootSessionData; class ChunkedProgressDialog; class MD5Dialog; class PadMappingDialog; @@ -30,14 +35,19 @@ class NetPlayDialog : public QDialog, public NetPlay::NetPlayUI { Q_OBJECT public: - explicit NetPlayDialog(const GameListModel& game_list_model, QWidget* parent = nullptr); + using StartGameCallback = std::function boot_session_data)>; + + explicit NetPlayDialog(const GameListModel& game_list_model, + StartGameCallback start_game_callback, QWidget* parent = nullptr); ~NetPlayDialog(); void show(std::string nickname, bool use_traversal); void reject() override; // NetPlayUI methods - void BootGame(const std::string& filename) override; + void BootGame(const std::string& filename, + std::unique_ptr boot_session_data) override; void StopGame() override; bool IsHosting() const override; @@ -85,7 +95,6 @@ public: void HideChunkedProgressDialog() override; void SetChunkedProgress(int pid, u64 progress) override; signals: - void Boot(const QString& filename); void Stop(); private: @@ -162,4 +171,6 @@ private: int m_player_count = 0; int m_old_player_count = 0; bool m_host_input_authority = false; + + StartGameCallback m_start_game_callback; }; From 894773f6079d1c5a38838e77f9eec789059c925a Mon Sep 17 00:00:00 2001 From: "Admiral H. Curtiss" Date: Sat, 20 Nov 2021 21:01:12 +0100 Subject: [PATCH 3/4] Core/Boot: Add Wii FS sync data (for temp NAND/netplay) to BootSessionData and handle it in the boot and shutdown logic. --- Source/Core/Core/Boot/Boot.cpp | 24 ++++++++++++++++++++++++ Source/Core/Core/Boot/Boot.h | 17 +++++++++++++++++ Source/Core/Core/Core.cpp | 7 +++++-- Source/Core/Core/WiiRoot.cpp | 17 ++++++++++------- Source/Core/Core/WiiRoot.h | 7 +++++-- 5 files changed, 61 insertions(+), 11 deletions(-) diff --git a/Source/Core/Core/Boot/Boot.cpp b/Source/Core/Core/Boot/Boot.cpp index 39f5c1c69d..b34e9bbbe5 100644 --- a/Source/Core/Core/Boot/Boot.cpp +++ b/Source/Core/Core/Boot/Boot.cpp @@ -145,6 +145,30 @@ void BootSessionData::SetSavestateData(std::optional savestate_path m_delete_savestate = delete_savestate; } +IOS::HLE::FS::FileSystem* BootSessionData::GetWiiSyncFS() const +{ + return m_wii_sync_fs.get(); +} + +const std::vector& BootSessionData::GetWiiSyncTitles() const +{ + return m_wii_sync_titles; +} + +void BootSessionData::InvokeWiiSyncCleanup() const +{ + if (m_wii_sync_cleanup) + m_wii_sync_cleanup(); +} + +void BootSessionData::SetWiiSyncData(std::unique_ptr fs, + std::vector titles, WiiSyncCleanupFunction cleanup) +{ + m_wii_sync_fs = std::move(fs); + m_wii_sync_titles = std::move(titles); + m_wii_sync_cleanup = std::move(cleanup); +} + BootParameters::BootParameters(Parameters&& parameters_, BootSessionData boot_session_data_) : parameters(std::move(parameters_)), boot_session_data(std::move(boot_session_data_)) { diff --git a/Source/Core/Core/Boot/Boot.h b/Source/Core/Core/Boot/Boot.h index b0564f751f..e27d6a41df 100644 --- a/Source/Core/Core/Boot/Boot.h +++ b/Source/Core/Core/Boot/Boot.h @@ -24,6 +24,11 @@ namespace File class IOFile; } +namespace IOS::HLE::FS +{ +class FileSystem; +} + struct RegionSetting { std::string area; @@ -57,9 +62,21 @@ public: void SetSavestateData(std::optional savestate_path, DeleteSavestateAfterBoot delete_savestate); + using WiiSyncCleanupFunction = std::function; + + IOS::HLE::FS::FileSystem* GetWiiSyncFS() const; + const std::vector& GetWiiSyncTitles() const; + void InvokeWiiSyncCleanup() const; + void SetWiiSyncData(std::unique_ptr fs, std::vector titles, + WiiSyncCleanupFunction cleanup); + private: std::optional m_savestate_path; DeleteSavestateAfterBoot m_delete_savestate = DeleteSavestateAfterBoot::No; + + std::unique_ptr m_wii_sync_fs; + std::vector m_wii_sync_titles; + WiiSyncCleanupFunction m_wii_sync_cleanup; }; struct BootParameters diff --git a/Source/Core/Core/Core.cpp b/Source/Core/Core/Core.cpp index e4a7dc7e46..6419d13e61 100644 --- a/Source/Core/Core/Core.cpp +++ b/Source/Core/Core/Core.cpp @@ -617,9 +617,12 @@ static void EmuThread(std::unique_ptr boot, WindowSystemInfo wsi // Initialise Wii filesystem contents. // This is done here after Boot and not in BootManager to ensure that we operate // with the correct title context since save copying requires title directories to exist. - Common::ScopeGuard wiifs_guard{&Core::CleanUpWiiFileSystemContents}; + Common::ScopeGuard wiifs_guard{[&boot_session_data] { + Core::CleanUpWiiFileSystemContents(boot_session_data); + boot_session_data.InvokeWiiSyncCleanup(); + }}; if (SConfig::GetInstance().bWii) - Core::InitializeWiiFileSystemContents(savegame_redirect); + Core::InitializeWiiFileSystemContents(savegame_redirect, boot_session_data); else wiifs_guard.Dismiss(); diff --git a/Source/Core/Core/WiiRoot.cpp b/Source/Core/Core/WiiRoot.cpp index d57f194ddc..2af5901dfb 100644 --- a/Source/Core/Core/WiiRoot.cpp +++ b/Source/Core/Core/WiiRoot.cpp @@ -17,6 +17,7 @@ #include "Common/Logging/Log.h" #include "Common/NandPaths.h" #include "Common/StringUtil.h" +#include "Core/Boot/Boot.h" #include "Core/CommonTitles.h" #include "Core/Config/SessionSettings.h" #include "Core/ConfigManager.h" @@ -114,7 +115,8 @@ static bool CopyNandFile(FS::FileSystem* source_fs, const std::string& source_fi return true; } -static void InitializeDeterministicWiiSaves(FS::FileSystem* session_fs) +static void InitializeDeterministicWiiSaves(FS::FileSystem* session_fs, + const BootSessionData& boot_session_data) { const u64 title_id = SConfig::GetInstance().GetTitleID(); const auto configured_fs = FS::MakeFileSystem(FS::Location::Configured); @@ -136,8 +138,8 @@ static void InitializeDeterministicWiiSaves(FS::FileSystem* session_fs) (Movie::IsMovieActive() && !Movie::IsStartingFromClearSave())) { // Copy the current user's save to the Blank NAND - auto* sync_fs = NetPlay::GetWiiSyncFS(); - auto& sync_titles = NetPlay::GetWiiSyncTitles(); + auto* sync_fs = boot_session_data.GetWiiSyncFS(); + auto& sync_titles = boot_session_data.GetWiiSyncTitles(); if (sync_fs) { for (const u64 title : sync_titles) @@ -298,7 +300,8 @@ static bool CopySysmenuFilesToFS(FS::FileSystem* fs, const std::string& host_sou } void InitializeWiiFileSystemContents( - std::optional save_redirect) + std::optional save_redirect, + const BootSessionData& boot_session_data) { const auto fs = IOS::HLE::GetIOS()->GetFS(); @@ -315,7 +318,7 @@ void InitializeWiiFileSystemContents( SysConf sysconf{fs}; sysconf.Save(); - InitializeDeterministicWiiSaves(fs.get()); + InitializeDeterministicWiiSaves(fs.get(), boot_session_data); } else if (save_redirect) { @@ -336,10 +339,10 @@ void InitializeWiiFileSystemContents( } } -void CleanUpWiiFileSystemContents() +void CleanUpWiiFileSystemContents(const BootSessionData& boot_session_data) { if (!WiiRootIsTemporary() || !Config::Get(Config::SESSION_SAVE_DATA_WRITABLE) || - NetPlay::GetWiiSyncFS()) + boot_session_data.GetWiiSyncFS()) { return; } diff --git a/Source/Core/Core/WiiRoot.h b/Source/Core/Core/WiiRoot.h index 0b17061b19..2b029b2e17 100644 --- a/Source/Core/Core/WiiRoot.h +++ b/Source/Core/Core/WiiRoot.h @@ -8,6 +8,8 @@ #include "DiscIO/RiivolutionPatcher.h" +class BootSessionData; + namespace IOS::HLE::FS { struct NandRedirect; @@ -32,8 +34,9 @@ void RestoreWiiSettings(RestoreReason reason); // Initialize or clean up the filesystem contents. void InitializeWiiFileSystemContents( - std::optional save_redirect); -void CleanUpWiiFileSystemContents(); + std::optional save_redirect, + const BootSessionData& boot_session_data); +void CleanUpWiiFileSystemContents(const BootSessionData& boot_session_data); const std::vector& GetActiveNandRedirects(); } // namespace Core From 6350c93ae15ebead036cbadbea5fae5c67b846f4 Mon Sep 17 00:00:00 2001 From: "Admiral H. Curtiss" Date: Sat, 20 Nov 2021 21:03:34 +0100 Subject: [PATCH 4/4] NetPlay: Pass Wii FS sync data directly to game boot logic instead of indirectly through globals. --- Source/Core/Core/NetPlayClient.cpp | 49 ++++++------------- Source/Core/Core/NetPlayClient.h | 12 +++++ Source/Core/Core/NetPlayProto.h | 4 -- Source/Core/Core/NetPlayServer.cpp | 2 +- .../Core/DolphinQt/NetPlay/NetPlayDialog.cpp | 8 +++ Source/Core/DolphinQt/NetPlay/NetPlayDialog.h | 3 ++ 6 files changed, 40 insertions(+), 38 deletions(-) diff --git a/Source/Core/Core/NetPlayClient.cpp b/Source/Core/Core/NetPlayClient.cpp index 30f9f6871b..66fc47e253 100644 --- a/Source/Core/Core/NetPlayClient.cpp +++ b/Source/Core/Core/NetPlayClient.cpp @@ -76,8 +76,6 @@ using namespace WiimoteCommon; static std::mutex crit_netplay_client; static NetPlayClient* netplay_client = nullptr; -static std::unique_ptr s_wii_sync_fs; -static std::vector s_wii_sync_titles; static bool s_si_poll_batching = false; // called from ---GUI--- thread @@ -1192,7 +1190,7 @@ void NetPlayClient::OnSyncSaveDataWii(sf::Packet& packet) } } - SetWiiSyncData(std::move(temp_fs), titles); + SetWiiSyncData(std::move(temp_fs), std::move(titles)); SyncSaveDataResponse(true); } @@ -1722,7 +1720,14 @@ bool NetPlayClient::StartGame(const std::string& path) } // boot game - m_dialog->BootGame(path, nullptr); + auto boot_session_data = std::make_unique(); + boot_session_data->SetWiiSyncData(std::move(m_wii_sync_fs), std::move(m_wii_sync_titles), [] { + // on emulation end clean up the Wii save sync directory -- see OnSyncSaveDataWii() + const std::string path = File::GetUserPath(D_USER_IDX) + "Wii" GC_MEMCARD_NETPLAY DIR_SEP; + if (File::Exists(path)) + File::DeleteDirRecursively(path); + }); + m_dialog->BootGame(path, std::move(boot_session_data)); UpdateDevices(); @@ -2252,8 +2257,6 @@ bool NetPlayClient::StopGame() // stop game m_dialog->StopGame(); - ClearWiiSyncData(); - return true; } @@ -2497,6 +2500,13 @@ void NetPlayClient::AdjustPadBufferSize(const unsigned int size) m_dialog->OnPadBufferChanged(size); } +void NetPlayClient::SetWiiSyncData(std::unique_ptr fs, + std::vector titles) +{ + m_wii_sync_fs = std::move(fs); + m_wii_sync_titles = std::move(titles); +} + SyncIdentifier NetPlayClient::GetSDCardIdentifier() { return SyncIdentifier{{}, "sd", {}, {}, {}, {}}; @@ -2539,33 +2549,6 @@ const NetSettings& GetNetSettings() return netplay_client->GetNetSettings(); } -IOS::HLE::FS::FileSystem* GetWiiSyncFS() -{ - return s_wii_sync_fs.get(); -} - -const std::vector& GetWiiSyncTitles() -{ - return s_wii_sync_titles; -} - -void SetWiiSyncData(std::unique_ptr fs, const std::vector& titles) -{ - s_wii_sync_fs = std::move(fs); - s_wii_sync_titles.insert(s_wii_sync_titles.end(), titles.begin(), titles.end()); -} - -void ClearWiiSyncData() -{ - // We're just assuming it will always be here because it is - const std::string path = File::GetUserPath(D_USER_IDX) + "Wii" GC_MEMCARD_NETPLAY DIR_SEP; - if (File::Exists(path)) - File::DeleteDirRecursively(path); - - s_wii_sync_fs.reset(); - s_wii_sync_titles.clear(); -} - void SetSIPollBatching(bool state) { s_si_poll_batching = state; diff --git a/Source/Core/Core/NetPlayClient.h b/Source/Core/Core/NetPlayClient.h index 4487358523..24cf494634 100644 --- a/Source/Core/Core/NetPlayClient.h +++ b/Source/Core/Core/NetPlayClient.h @@ -25,6 +25,11 @@ class BootSessionData; +namespace IOS::HLE::FS +{ +class FileSystem; +} + namespace UICommon { class GameFile; @@ -80,6 +85,8 @@ public: const std::vector& players) = 0; virtual void HideChunkedProgressDialog() = 0; virtual void SetChunkedProgress(int pid, u64 progress) = 0; + + virtual void SetHostWiiSyncTitles(std::vector titles) = 0; }; class Player @@ -150,6 +157,8 @@ public: void AdjustPadBufferSize(unsigned int size); + void SetWiiSyncData(std::unique_ptr fs, std::vector titles); + static SyncIdentifier GetSDCardIdentifier(); protected: @@ -316,6 +325,9 @@ private: u64 m_initial_rtc = 0; u32 m_timebase_frame = 0; + + std::unique_ptr m_wii_sync_fs; + std::vector m_wii_sync_titles; }; void NetPlay_Enable(NetPlayClient* const np); diff --git a/Source/Core/Core/NetPlayProto.h b/Source/Core/Core/NetPlayProto.h index 87af1fe26c..5c5db0da6b 100644 --- a/Source/Core/Core/NetPlayProto.h +++ b/Source/Core/Core/NetPlayProto.h @@ -257,10 +257,6 @@ bool IsNetPlayRunning(); // Precondition: A netplay client instance must be present. In other words, // IsNetPlayRunning() must be true before calling this. const NetSettings& GetNetSettings(); -IOS::HLE::FS::FileSystem* GetWiiSyncFS(); -const std::vector& GetWiiSyncTitles(); -void SetWiiSyncData(std::unique_ptr fs, const std::vector& titles); -void ClearWiiSyncData(); void SetSIPollBatching(bool state); void SendPowerButtonEvent(); bool IsSyncingAllWiiSaves(); diff --git a/Source/Core/Core/NetPlayServer.cpp b/Source/Core/Core/NetPlayServer.cpp index fc4f1da4d2..c0548a3384 100644 --- a/Source/Core/Core/NetPlayServer.cpp +++ b/Source/Core/Core/NetPlayServer.cpp @@ -1819,7 +1819,7 @@ bool NetPlayServer::SyncSaveData() } // Set titles for host-side loading in WiiRoot - SetWiiSyncData(nullptr, titles); + m_dialog->SetHostWiiSyncTitles(std::move(titles)); SendChunkedToClients(std::move(pac), 1, "Wii Save Synchronization"); } diff --git a/Source/Core/DolphinQt/NetPlay/NetPlayDialog.cpp b/Source/Core/DolphinQt/NetPlay/NetPlayDialog.cpp index 7e05a51add..bcf5704a29 100644 --- a/Source/Core/DolphinQt/NetPlay/NetPlayDialog.cpp +++ b/Source/Core/DolphinQt/NetPlay/NetPlayDialog.cpp @@ -40,6 +40,7 @@ #ifdef HAS_LIBMGBA #include "Core/HW/GBACore.h" #endif +#include "Core/IOS/FS/FileSystem.h" #include "Core/NetPlayServer.h" #include "Core/SyncIdentifier.h" @@ -1177,3 +1178,10 @@ void NetPlayDialog::SetChunkedProgress(const int pid, const u64 progress) m_chunked_progress_dialog->SetProgress(pid, progress); }); } + +void NetPlayDialog::SetHostWiiSyncTitles(std::vector titles) +{ + auto client = Settings::Instance().GetNetPlayClient(); + if (client) + client->SetWiiSyncData(nullptr, std::move(titles)); +} diff --git a/Source/Core/DolphinQt/NetPlay/NetPlayDialog.h b/Source/Core/DolphinQt/NetPlay/NetPlayDialog.h index 5844c25cb4..fd14cea4e7 100644 --- a/Source/Core/DolphinQt/NetPlay/NetPlayDialog.h +++ b/Source/Core/DolphinQt/NetPlay/NetPlayDialog.h @@ -94,6 +94,9 @@ public: const std::vector& players) override; void HideChunkedProgressDialog() override; void SetChunkedProgress(int pid, u64 progress) override; + + void SetHostWiiSyncTitles(std::vector titles) override; + signals: void Stop();