diff --git a/Source/Core/Core/Boot/Boot.cpp b/Source/Core/Core/Boot/Boot.cpp index 981cebc550..c83677987f 100644 --- a/Source/Core/Core/Boot/Boot.cpp +++ b/Source/Core/Core/Boot/Boot.cpp @@ -48,11 +48,15 @@ #include "DiscIO/Enums.h" #include "DiscIO/Volume.h" -BootParameters::BootParameters(Parameters&& parameters_) : parameters(std::move(parameters_)) +BootParameters::BootParameters(Parameters&& parameters_, + const std::optional& savestate_path_) + : parameters(std::move(parameters_)), savestate_path(savestate_path_) { } -std::unique_ptr BootParameters::GenerateFromFile(const std::string& path) +std::unique_ptr +BootParameters::GenerateFromFile(const std::string& path, + const std::optional& savestate_path) { const bool is_drive = cdio_is_cdrom(path); // Check if the file exist, we may have gotten it from a --elf command line @@ -73,13 +77,19 @@ std::unique_ptr BootParameters::GenerateFromFile(const std::stri { std::unique_ptr volume = DiscIO::CreateVolumeFromFilename(path); if (volume) - return std::make_unique(Disc{path, std::move(volume)}); + return std::make_unique(Disc{path, std::move(volume)}, savestate_path); if (extension == ".elf") - return std::make_unique(Executable{path, std::make_unique(path)}); + { + return std::make_unique(Executable{path, std::make_unique(path)}, + savestate_path); + } if (extension == ".dol") - return std::make_unique(Executable{path, std::make_unique(path)}); + { + return std::make_unique(Executable{path, std::make_unique(path)}, + savestate_path); + } if (is_drive) { @@ -97,10 +107,10 @@ std::unique_ptr BootParameters::GenerateFromFile(const std::stri } if (extension == ".dff") - return std::make_unique(DFF{path}); + return std::make_unique(DFF{path}, savestate_path); if (extension == ".wad") - return std::make_unique(DiscIO::WiiWAD{path}); + return std::make_unique(DiscIO::WiiWAD{path}, savestate_path); PanicAlertT("Could not recognize file %s", path.c_str()); return {}; diff --git a/Source/Core/Core/Boot/Boot.h b/Source/Core/Core/Boot/Boot.h index 9295244bcb..7581b2abb8 100644 --- a/Source/Core/Core/Boot/Boot.h +++ b/Source/Core/Core/Boot/Boot.h @@ -67,12 +67,15 @@ struct BootParameters std::string dff_path; }; - static std::unique_ptr GenerateFromFile(const std::string& path); + static std::unique_ptr + GenerateFromFile(const std::string& boot_path, + const std::optional& savestate_path = {}); using Parameters = std::variant; - BootParameters(Parameters&& parameters_); + BootParameters(Parameters&& parameters_, const std::optional& savestate_path_ = {}); Parameters parameters; + std::optional savestate_path; }; class CBoot diff --git a/Source/Core/Core/BootManager.cpp b/Source/Core/Core/BootManager.cpp index 965c182afb..200074c589 100644 --- a/Source/Core/Core/BootManager.cpp +++ b/Source/Core/Core/BootManager.cpp @@ -382,8 +382,10 @@ bool BootCore(std::unique_ptr boot) std::holds_alternative(boot->parameters); if (load_ipl) { - return Core::Init(std::make_unique(BootParameters::IPL{ - StartUp.m_region, std::move(std::get(boot->parameters))})); + return Core::Init(std::make_unique( + BootParameters::IPL{StartUp.m_region, + std::move(std::get(boot->parameters))}, + boot->savestate_path)); } return Core::Init(std::move(boot)); } diff --git a/Source/Core/Core/Core.cpp b/Source/Core/Core/Core.cpp index a081d6e883..1d77f4e2fc 100644 --- a/Source/Core/Core/Core.cpp +++ b/Source/Core/Core/Core.cpp @@ -96,7 +96,6 @@ static bool s_hardware_initialized = false; static bool s_is_started = false; static Common::Flag s_is_booting; static void* s_window_handle = nullptr; -static std::string s_state_filename; static std::thread s_emu_thread; static StateChangedCallbackFunc s_on_state_changed_callback; @@ -136,15 +135,6 @@ void SetIsThrottlerTempDisabled(bool disable) s_is_throttler_temp_disabled = disable; } -std::string GetStateFileName() -{ - return s_state_filename; -} -void SetStateFileName(const std::string& val) -{ - s_state_filename = val; -} - void FrameUpdateOnCPUThread() { if (NetPlay::IsNetPlayRunning()) @@ -328,7 +318,7 @@ static void CPUSetInitialExecutionState() } // Create the CPU thread, which is a CPU + Video thread in Single Core mode. -static void CpuThread() +static void CpuThread(const std::optional& savestate_path) { DeclareAsCPUThread(); @@ -351,17 +341,8 @@ static void CpuThread() if (_CoreParameter.bFastmem) EMM::InstallExceptionHandler(); // Let's run under memory watch - if (!s_state_filename.empty()) - { - // Needs to PauseAndLock the Core - // NOTE: EmuThread should have left us in State::Stepping so nothing will happen - // until after the job is serviced. - QueueHostJob([] { - // Recheck in case Movie cleared it since. - if (!s_state_filename.empty()) - ::State::LoadAs(s_state_filename); - }); - } + if (savestate_path) + QueueHostJob([&savestate_path] { ::State::LoadAs(*savestate_path); }); s_is_started = true; CPUSetInitialExecutionState(); @@ -399,7 +380,7 @@ static void CpuThread() EMM::UninstallExceptionHandler(); } -static void FifoPlayerThread() +static void FifoPlayerThread(const std::optional& savestate_path) { DeclareAsCPUThread(); const SConfig& _CoreParameter = SConfig::GetInstance(); @@ -535,15 +516,20 @@ static void EmuThread(std::unique_ptr boot) Keyboard::LoadConfig(); } + const std::optional savestate_path = boot->savestate_path; + // Load and Init Wiimotes - only if we are booting in Wii mode if (core_parameter.bWii && !SConfig::GetInstance().m_bt_passthrough_enabled) { if (init_controllers) - Wiimote::Initialize(!s_state_filename.empty() ? - Wiimote::InitializeMode::DO_WAIT_FOR_WIIMOTES : - Wiimote::InitializeMode::DO_NOT_WAIT_FOR_WIIMOTES); + { + Wiimote::Initialize(savestate_path ? Wiimote::InitializeMode::DO_WAIT_FOR_WIIMOTES : + Wiimote::InitializeMode::DO_NOT_WAIT_FOR_WIIMOTES); + } else + { Wiimote::LoadConfig(); + } } Common::ScopeGuard controller_guard{[init_controllers] { @@ -570,7 +556,7 @@ static void EmuThread(std::unique_ptr boot) PowerPC::SetMode(PowerPC::CoreMode::Interpreter); // Determine the CPU thread function - void (*cpuThreadFunc)(); + void (*cpuThreadFunc)(const std::optional& savestate_path); if (std::holds_alternative(boot->parameters)) cpuThreadFunc = FifoPlayerThread; else @@ -611,7 +597,7 @@ static void EmuThread(std::unique_ptr boot) Host_Message(WM_USER_CREATE); // Spawn the CPU thread - s_cpu_thread = std::thread(cpuThreadFunc); + s_cpu_thread = std::thread(cpuThreadFunc, savestate_path); // become the GPU thread Fifo::RunGpuLoop(); @@ -629,7 +615,7 @@ static void EmuThread(std::unique_ptr boot) Common::SetCurrentThreadName("Emuthread - Idle"); // Spawn the CPU+GPU thread - s_cpu_thread = std::thread(cpuThreadFunc); + s_cpu_thread = std::thread(cpuThreadFunc, savestate_path); while (CPU::GetState() != CPU::State::PowerDown) { diff --git a/Source/Core/Core/Core.h b/Source/Core/Core/Core.h index 4ed2570081..51537f2ce9 100644 --- a/Source/Core/Core/Core.h +++ b/Source/Core/Core/Core.h @@ -64,9 +64,6 @@ void Callback_WiimoteInterruptChannel(int _number, u16 _channelID, const void* _ // This displays messages in a user-visible way. void DisplayMessage(const std::string& message, int time_in_ms); -std::string GetStateFileName(); -void SetStateFileName(const std::string& val); - void FrameUpdateOnCPUThread(); bool ShouldSkipFrame(int skipped); diff --git a/Source/Core/Core/Movie.cpp b/Source/Core/Core/Movie.cpp index 9d0114ecfc..8c292e53b1 100644 --- a/Source/Core/Core/Movie.cpp +++ b/Source/Core/Core/Movie.cpp @@ -232,8 +232,6 @@ void Init(const BootParameters& boot) } memset(&s_padState, 0, sizeof(s_padState)); - if (!tmpHeader.bFromSaveState || !IsPlayingInput()) - Core::SetStateFileName(""); for (auto& disp : s_InputDisplay) disp.clear(); @@ -865,12 +863,12 @@ void ReadHeader() } // NOTE: Host Thread -bool PlayInput(const std::string& filename) +bool PlayInput(const std::string& movie_path, std::optional* savestate_path) { if (s_playMode != MODE_NONE) return false; - File::IOFile recording_file(filename, "rb"); + File::IOFile recording_file(movie_path, "rb"); if (!recording_file.ReadArray(&tmpHeader, 1)) return false; @@ -902,13 +900,13 @@ bool PlayInput(const std::string& filename) recording_file.Close(); // Load savestate (and skip to frame data) - if (tmpHeader.bFromSaveState) + if (tmpHeader.bFromSaveState && savestate_path) { - const std::string stateFilename = filename + ".sav"; - if (File::Exists(stateFilename)) - Core::SetStateFileName(stateFilename); + const std::string savestate_path_temp = movie_path + ".sav"; + if (File::Exists(savestate_path_temp)) + *savestate_path = savestate_path_temp; s_bRecordingFromSaveState = true; - Movie::LoadInput(filename); + Movie::LoadInput(movie_path); } return true; @@ -928,12 +926,12 @@ void DoState(PointerWrap& p) } // NOTE: Host Thread -void LoadInput(const std::string& filename) +void LoadInput(const std::string& movie_path) { File::IOFile t_record; - if (!t_record.Open(filename, "r+b")) + if (!t_record.Open(movie_path, "r+b")) { - PanicAlertT("Failed to read %s", filename.c_str()); + PanicAlertT("Failed to read %s", movie_path.c_str()); EndPlayInput(false); return; } @@ -942,7 +940,7 @@ void LoadInput(const std::string& filename) if (!IsMovieHeader(tmpHeader.filetype)) { - PanicAlertT("Savestate movie %s is corrupted, movie recording stopping...", filename.c_str()); + PanicAlertT("Savestate movie %s is corrupted, movie recording stopping...", movie_path.c_str()); EndPlayInput(false); return; } diff --git a/Source/Core/Core/Movie.h b/Source/Core/Core/Movie.h index b4ab682d8c..14d8fdf3c8 100644 --- a/Source/Core/Core/Movie.h +++ b/Source/Core/Core/Movie.h @@ -5,6 +5,7 @@ #pragma once #include +#include #include #include "Common/CommonTypes.h" @@ -157,8 +158,8 @@ bool BeginRecordingInput(int controllers); void RecordInput(GCPadStatus* PadStatus, int controllerID); void RecordWiimote(int wiimote, u8* data, u8 size); -bool PlayInput(const std::string& filename); -void LoadInput(const std::string& filename); +bool PlayInput(const std::string& movie_path, std::optional* savestate_path); +void LoadInput(const std::string& movie_path); void ReadHeader(); void PlayController(GCPadStatus* PadStatus, int controllerID); bool PlayWiimote(int wiimote, u8* data, const struct WiimoteEmu::ReportFeatures& rptf, int ext, diff --git a/Source/Core/DolphinQt2/MainWindow.cpp b/Source/Core/DolphinQt2/MainWindow.cpp index beefe311c3..99e762cdb8 100644 --- a/Source/Core/DolphinQt2/MainWindow.cpp +++ b/Source/Core/DolphinQt2/MainWindow.cpp @@ -15,6 +15,7 @@ #include #include +#include #include "Common/Version.h" @@ -164,7 +165,7 @@ void MainWindow::CreateComponents() m_fifo_window = new FIFOPlayerWindow(this); connect(m_fifo_window, &FIFOPlayerWindow::LoadFIFORequested, this, - static_cast(&MainWindow::StartGame)); + [this](const QString& path) { StartGame(path); }); #if defined(HAVE_XRANDR) && HAVE_XRANDR m_graphics_window = new GraphicsWindow( @@ -192,7 +193,7 @@ void MainWindow::ConnectMenuBar() // Emulation connect(m_menu_bar, &MenuBar::Pause, this, &MainWindow::Pause); - connect(m_menu_bar, &MenuBar::Play, this, &MainWindow::Play); + connect(m_menu_bar, &MenuBar::Play, this, [this]() { Play(); }); connect(m_menu_bar, &MenuBar::Stop, this, &MainWindow::RequestStop); connect(m_menu_bar, &MenuBar::Reset, this, &MainWindow::Reset); connect(m_menu_bar, &MenuBar::Fullscreen, this, &MainWindow::FullScreen); @@ -278,7 +279,7 @@ void MainWindow::ConnectToolBar() { addToolBar(m_tool_bar); connect(m_tool_bar, &ToolBar::OpenPressed, this, &MainWindow::Open); - connect(m_tool_bar, &ToolBar::PlayPressed, this, &MainWindow::Play); + connect(m_tool_bar, &ToolBar::PlayPressed, this, [this]() { Play(); }); connect(m_tool_bar, &ToolBar::PausePressed, this, &MainWindow::Pause); connect(m_tool_bar, &ToolBar::StopPressed, this, &MainWindow::RequestStop); connect(m_tool_bar, &ToolBar::FullScreenPressed, this, &MainWindow::FullScreen); @@ -290,7 +291,7 @@ void MainWindow::ConnectToolBar() void MainWindow::ConnectGameList() { - connect(m_game_list, &GameList::GameSelected, this, &MainWindow::Play); + connect(m_game_list, &GameList::GameSelected, this, [this]() { Play(); }); connect(m_game_list, &GameList::NetPlayHost, this, &MainWindow::NetPlayHost); connect(m_game_list, &GameList::OpenGeneralSettings, this, &MainWindow::ShowGeneralWindow); @@ -327,7 +328,7 @@ void MainWindow::Open() StartGame(file); } -void MainWindow::Play() +void MainWindow::Play(const std::optional& savestate_path) { // If we're in a paused game, start it up again. // Otherwise, play the selected game, if there is one. @@ -343,14 +344,14 @@ void MainWindow::Play() QSharedPointer selection = m_game_list->GetSelectedGame(); if (selection) { - StartGame(selection->GetFilePath()); + StartGame(selection->GetFilePath(), savestate_path); } else { auto default_path = QString::fromStdString(SConfig::GetInstance().m_strDefaultISO); if (!default_path.isEmpty() && QFile::exists(default_path)) { - StartGame(default_path); + StartGame(default_path, savestate_path); } else { @@ -472,9 +473,9 @@ void MainWindow::ScreenShot() Core::SaveScreenShot(); } -void MainWindow::StartGame(const QString& path) +void MainWindow::StartGame(const QString& path, const std::optional& savestate_path) { - StartGame(BootParameters::GenerateFromFile(path.toStdString())); + StartGame(BootParameters::GenerateFromFile(path.toStdString(), savestate_path)); } void MainWindow::StartGame(std::unique_ptr&& parameters) @@ -680,7 +681,7 @@ void MainWindow::NetPlayInit() m_netplay_dialog = new NetPlayDialog(this); connect(m_netplay_dialog, &NetPlayDialog::Boot, this, - static_cast(&MainWindow::StartGame)); + [this](const QString& path) { StartGame(path); }); connect(m_netplay_dialog, &NetPlayDialog::Stop, this, &MainWindow::RequestStop); connect(m_netplay_dialog, &NetPlayDialog::rejected, this, &MainWindow::NetPlayQuit); connect(m_netplay_setup_dialog, &NetPlaySetupDialog::Join, this, &MainWindow::NetPlayJoin); @@ -938,11 +939,12 @@ void MainWindow::OnPlayRecording() emit ReadOnlyModeChanged(true); } - if (Movie::PlayInput(dtm_file.toStdString())) + std::optional savestate_path; + if (Movie::PlayInput(dtm_file.toStdString(), &savestate_path)) { emit RecordingStatusChanged(true); - Play(); + Play(savestate_path); } } diff --git a/Source/Core/DolphinQt2/MainWindow.h b/Source/Core/DolphinQt2/MainWindow.h index 33288e9830..a230a2322f 100644 --- a/Source/Core/DolphinQt2/MainWindow.h +++ b/Source/Core/DolphinQt2/MainWindow.h @@ -10,6 +10,7 @@ #include #include +#include #include "DolphinQt2/GameList/GameList.h" #include "DolphinQt2/MenuBar.h" @@ -47,7 +48,7 @@ signals: private: void Open(); - void Play(); + void Play(const std::optional& savestate_path = {}); void Pause(); // May ask for confirmation. Returns whether or not it actually stopped. @@ -86,7 +87,7 @@ private: void InitCoreCallbacks(); - void StartGame(const QString& path); + void StartGame(const QString& path, const std::optional& savestate_path = {}); void StartGame(std::unique_ptr&& parameters); void ShowRenderWidget(); void HideRenderWidget(); diff --git a/Source/Core/DolphinWX/Frame.cpp b/Source/Core/DolphinWX/Frame.cpp index ccfdd729d2..afe4817917 100644 --- a/Source/Core/DolphinWX/Frame.cpp +++ b/Source/Core/DolphinWX/Frame.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -130,8 +131,9 @@ void CRenderFrame::OnDropFiles(wxDropFilesEvent& event) main_frame->GetMenuBar()->FindItem(IDM_RECORD_READ_ONLY)->Check(true); } - if (Movie::PlayInput(filepath)) - main_frame->BootGame(""); + std::optional savestate_path; + if (Movie::PlayInput(filepath, &savestate_path)) + main_frame->BootGame("", savestate_path); } else if (!Core::IsRunning()) { diff --git a/Source/Core/DolphinWX/Frame.h b/Source/Core/DolphinWX/Frame.h index 4e33b645e5..bdef068a58 100644 --- a/Source/Core/DolphinWX/Frame.h +++ b/Source/Core/DolphinWX/Frame.h @@ -8,6 +8,7 @@ #include #include #include +#include #include #include #include @@ -105,7 +106,7 @@ public: void ToggleLogConfigWindow(bool bShow); void StatusBarMessage(const char* format, ...); void ClearStatusBar(); - void BootGame(const std::string& filename); + void BootGame(const std::string& filename, const std::optional& savestate_path = {}); void StartGame(std::unique_ptr boot); bool RendererHasFocus(); bool RendererIsFullscreen(); diff --git a/Source/Core/DolphinWX/FrameTools.cpp b/Source/Core/DolphinWX/FrameTools.cpp index bf1072b68c..929e435bd9 100644 --- a/Source/Core/DolphinWX/FrameTools.cpp +++ b/Source/Core/DolphinWX/FrameTools.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -301,7 +302,7 @@ void CFrame::OpenGeneralConfiguration(wxWindowID tab_id) // 1. Show the game list and boot the selected game. // 2. Default ISO // 3. Boot last selected game -void CFrame::BootGame(const std::string& filename) +void CFrame::BootGame(const std::string& filename, const std::optional& savestate_path) { std::string bootfile = filename; SConfig& StartUp = SConfig::GetInstance(); @@ -331,7 +332,7 @@ void CFrame::BootGame(const std::string& filename) } if (!bootfile.empty()) { - StartGame(BootParameters::GenerateFromFile(bootfile)); + StartGame(BootParameters::GenerateFromFile(bootfile, savestate_path)); } } @@ -513,8 +514,9 @@ void CFrame::OnPlayRecording(wxCommandEvent& WXUNUSED(event)) GetMenuBar()->FindItem(IDM_RECORD_READ_ONLY)->Check(); } - if (Movie::PlayInput(WxStrToStr(path))) - BootGame(""); + std::optional savestate_path; + if (Movie::PlayInput(WxStrToStr(path), &savestate_path)) + BootGame("", savestate_path); } void CFrame::OnStopRecording(wxCommandEvent& WXUNUSED(event)) diff --git a/Source/Core/DolphinWX/Main.cpp b/Source/Core/DolphinWX/Main.cpp index be07009c46..ff6b3810cb 100644 --- a/Source/Core/DolphinWX/Main.cpp +++ b/Source/Core/DolphinWX/Main.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -256,12 +257,18 @@ void DolphinApp::AfterInit() if (m_play_movie && !m_movie_file.empty()) { - if (Movie::PlayInput(WxStrToStr(m_movie_file))) + std::optional savestate_path; + if (Movie::PlayInput(WxStrToStr(m_movie_file), &savestate_path)) { if (m_boot) + { + m_boot->savestate_path = savestate_path; main_frame->StartGame(std::move(m_boot)); + } else - main_frame->BootGame(""); + { + main_frame->BootGame("", savestate_path); + } } } // First check if we have an exec command line.