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..b34e9bbbe5 100644 --- a/Source/Core/Core/Boot/Boot.cpp +++ b/Source/Core/Core/Boot/Boot.cpp @@ -112,22 +112,77 @@ 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; +} + +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_)) +{ +} + +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 +231,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 +264,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 +278,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..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; @@ -34,6 +39,46 @@ 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); + + 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 { struct Disc @@ -70,18 +115,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..6419d13e61 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; @@ -615,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/NetPlayClient.cpp b/Source/Core/Core/NetPlayClient.cpp index e4cba66429..66fc47e253 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" @@ -75,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 @@ -1191,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); } @@ -1721,7 +1720,14 @@ bool NetPlayClient::StartGame(const std::string& path) } // boot game - m_dialog->BootGame(path); + 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(); @@ -2251,8 +2257,6 @@ bool NetPlayClient::StopGame() // stop game m_dialog->StopGame(); - ClearWiiSyncData(); - return true; } @@ -2496,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", {}, {}, {}, {}}; @@ -2538,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 3c02cad266..24cf494634 100644 --- a/Source/Core/Core/NetPlayClient.h +++ b/Source/Core/Core/NetPlayClient.h @@ -23,6 +23,13 @@ #include "Core/SyncIdentifier.h" #include "InputCommon/GCPadStatus.h" +class BootSessionData; + +namespace IOS::HLE::FS +{ +class FileSystem; +} + namespace UICommon { class GameFile; @@ -34,7 +41,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; @@ -77,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 @@ -147,6 +157,8 @@ public: void AdjustPadBufferSize(unsigned int size); + void SetWiiSyncData(std::unique_ptr fs, std::vector titles); + static SyncIdentifier GetSDCardIdentifier(); protected: @@ -313,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/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 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..aacdea6a71 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) @@ -1363,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); @@ -1818,8 +1829,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); diff --git a/Source/Core/DolphinQt/NetPlay/NetPlayDialog.cpp b/Source/Core/DolphinQt/NetPlay/NetPlayDialog.cpp index 464cb506db..bcf5704a29 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" @@ -39,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" @@ -62,8 +64,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 +686,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() @@ -1173,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 b2753236ba..fd14cea4e7 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; @@ -84,8 +94,10 @@ public: const std::vector& players) override; void HideChunkedProgressDialog() override; void SetChunkedProgress(int pid, u64 progress) override; + + void SetHostWiiSyncTitles(std::vector titles) override; + signals: - void Boot(const QString& filename); void Stop(); private: @@ -162,4 +174,6 @@ private: int m_player_count = 0; int m_old_player_count = 0; bool m_host_input_authority = false; + + StartGameCallback m_start_game_callback; };