Redesign the ability to load state at boot

BootParameters can now contain the path of a savestate to load at boot.
Movie has been made to use this instead of poking at Core.cpp's state.
This commit is contained in:
JosJuice 2017-12-25 18:07:29 +01:00
parent c9b78e23a2
commit 9dd88d76dd
13 changed files with 93 additions and 81 deletions

View File

@ -48,11 +48,15 @@
#include "DiscIO/Enums.h" #include "DiscIO/Enums.h"
#include "DiscIO/Volume.h" #include "DiscIO/Volume.h"
BootParameters::BootParameters(Parameters&& parameters_) : parameters(std::move(parameters_)) BootParameters::BootParameters(Parameters&& parameters_,
const std::optional<std::string>& savestate_path_)
: parameters(std::move(parameters_)), savestate_path(savestate_path_)
{ {
} }
std::unique_ptr<BootParameters> BootParameters::GenerateFromFile(const std::string& path) std::unique_ptr<BootParameters>
BootParameters::GenerateFromFile(const std::string& path,
const std::optional<std::string>& savestate_path)
{ {
const bool is_drive = cdio_is_cdrom(path); const bool is_drive = cdio_is_cdrom(path);
// Check if the file exist, we may have gotten it from a --elf command line // Check if the file exist, we may have gotten it from a --elf command line
@ -73,13 +77,19 @@ std::unique_ptr<BootParameters> BootParameters::GenerateFromFile(const std::stri
{ {
std::unique_ptr<DiscIO::Volume> volume = DiscIO::CreateVolumeFromFilename(path); std::unique_ptr<DiscIO::Volume> volume = DiscIO::CreateVolumeFromFilename(path);
if (volume) if (volume)
return std::make_unique<BootParameters>(Disc{path, std::move(volume)}); return std::make_unique<BootParameters>(Disc{path, std::move(volume)}, savestate_path);
if (extension == ".elf") if (extension == ".elf")
return std::make_unique<BootParameters>(Executable{path, std::make_unique<ElfReader>(path)}); {
return std::make_unique<BootParameters>(Executable{path, std::make_unique<ElfReader>(path)},
savestate_path);
}
if (extension == ".dol") if (extension == ".dol")
return std::make_unique<BootParameters>(Executable{path, std::make_unique<DolReader>(path)}); {
return std::make_unique<BootParameters>(Executable{path, std::make_unique<DolReader>(path)},
savestate_path);
}
if (is_drive) if (is_drive)
{ {
@ -97,10 +107,10 @@ std::unique_ptr<BootParameters> BootParameters::GenerateFromFile(const std::stri
} }
if (extension == ".dff") if (extension == ".dff")
return std::make_unique<BootParameters>(DFF{path}); return std::make_unique<BootParameters>(DFF{path}, savestate_path);
if (extension == ".wad") if (extension == ".wad")
return std::make_unique<BootParameters>(DiscIO::WiiWAD{path}); return std::make_unique<BootParameters>(DiscIO::WiiWAD{path}, savestate_path);
PanicAlertT("Could not recognize file %s", path.c_str()); PanicAlertT("Could not recognize file %s", path.c_str());
return {}; return {};

View File

@ -67,12 +67,15 @@ struct BootParameters
std::string dff_path; std::string dff_path;
}; };
static std::unique_ptr<BootParameters> GenerateFromFile(const std::string& path); static std::unique_ptr<BootParameters>
GenerateFromFile(const std::string& boot_path,
const std::optional<std::string>& savestate_path = {});
using Parameters = std::variant<Disc, Executable, DiscIO::WiiWAD, NANDTitle, IPL, DFF>; using Parameters = std::variant<Disc, Executable, DiscIO::WiiWAD, NANDTitle, IPL, DFF>;
BootParameters(Parameters&& parameters_); BootParameters(Parameters&& parameters_, const std::optional<std::string>& savestate_path_ = {});
Parameters parameters; Parameters parameters;
std::optional<std::string> savestate_path;
}; };
class CBoot class CBoot

View File

@ -382,8 +382,10 @@ bool BootCore(std::unique_ptr<BootParameters> boot)
std::holds_alternative<BootParameters::Disc>(boot->parameters); std::holds_alternative<BootParameters::Disc>(boot->parameters);
if (load_ipl) if (load_ipl)
{ {
return Core::Init(std::make_unique<BootParameters>(BootParameters::IPL{ return Core::Init(std::make_unique<BootParameters>(
StartUp.m_region, std::move(std::get<BootParameters::Disc>(boot->parameters))})); BootParameters::IPL{StartUp.m_region,
std::move(std::get<BootParameters::Disc>(boot->parameters))},
boot->savestate_path));
} }
return Core::Init(std::move(boot)); return Core::Init(std::move(boot));
} }

View File

@ -96,7 +96,6 @@ static bool s_hardware_initialized = false;
static bool s_is_started = false; static bool s_is_started = false;
static Common::Flag s_is_booting; static Common::Flag s_is_booting;
static void* s_window_handle = nullptr; static void* s_window_handle = nullptr;
static std::string s_state_filename;
static std::thread s_emu_thread; static std::thread s_emu_thread;
static StateChangedCallbackFunc s_on_state_changed_callback; static StateChangedCallbackFunc s_on_state_changed_callback;
@ -136,15 +135,6 @@ void SetIsThrottlerTempDisabled(bool disable)
s_is_throttler_temp_disabled = 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() void FrameUpdateOnCPUThread()
{ {
if (NetPlay::IsNetPlayRunning()) if (NetPlay::IsNetPlayRunning())
@ -328,7 +318,7 @@ static void CPUSetInitialExecutionState()
} }
// Create the CPU thread, which is a CPU + Video thread in Single Core mode. // Create the CPU thread, which is a CPU + Video thread in Single Core mode.
static void CpuThread() static void CpuThread(const std::optional<std::string>& savestate_path)
{ {
DeclareAsCPUThread(); DeclareAsCPUThread();
@ -351,17 +341,8 @@ static void CpuThread()
if (_CoreParameter.bFastmem) if (_CoreParameter.bFastmem)
EMM::InstallExceptionHandler(); // Let's run under memory watch EMM::InstallExceptionHandler(); // Let's run under memory watch
if (!s_state_filename.empty()) if (savestate_path)
{ QueueHostJob([&savestate_path] { ::State::LoadAs(*savestate_path); });
// 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);
});
}
s_is_started = true; s_is_started = true;
CPUSetInitialExecutionState(); CPUSetInitialExecutionState();
@ -399,7 +380,7 @@ static void CpuThread()
EMM::UninstallExceptionHandler(); EMM::UninstallExceptionHandler();
} }
static void FifoPlayerThread() static void FifoPlayerThread(const std::optional<std::string>& savestate_path)
{ {
DeclareAsCPUThread(); DeclareAsCPUThread();
const SConfig& _CoreParameter = SConfig::GetInstance(); const SConfig& _CoreParameter = SConfig::GetInstance();
@ -535,15 +516,20 @@ static void EmuThread(std::unique_ptr<BootParameters> boot)
Keyboard::LoadConfig(); Keyboard::LoadConfig();
} }
const std::optional<std::string> savestate_path = boot->savestate_path;
// Load and Init Wiimotes - only if we are booting in Wii mode // Load and Init Wiimotes - only if we are booting in Wii mode
if (core_parameter.bWii && !SConfig::GetInstance().m_bt_passthrough_enabled) if (core_parameter.bWii && !SConfig::GetInstance().m_bt_passthrough_enabled)
{ {
if (init_controllers) if (init_controllers)
Wiimote::Initialize(!s_state_filename.empty() ? {
Wiimote::InitializeMode::DO_WAIT_FOR_WIIMOTES : Wiimote::Initialize(savestate_path ? Wiimote::InitializeMode::DO_WAIT_FOR_WIIMOTES :
Wiimote::InitializeMode::DO_NOT_WAIT_FOR_WIIMOTES); Wiimote::InitializeMode::DO_NOT_WAIT_FOR_WIIMOTES);
}
else else
{
Wiimote::LoadConfig(); Wiimote::LoadConfig();
}
} }
Common::ScopeGuard controller_guard{[init_controllers] { Common::ScopeGuard controller_guard{[init_controllers] {
@ -570,7 +556,7 @@ static void EmuThread(std::unique_ptr<BootParameters> boot)
PowerPC::SetMode(PowerPC::CoreMode::Interpreter); PowerPC::SetMode(PowerPC::CoreMode::Interpreter);
// Determine the CPU thread function // Determine the CPU thread function
void (*cpuThreadFunc)(); void (*cpuThreadFunc)(const std::optional<std::string>& savestate_path);
if (std::holds_alternative<BootParameters::DFF>(boot->parameters)) if (std::holds_alternative<BootParameters::DFF>(boot->parameters))
cpuThreadFunc = FifoPlayerThread; cpuThreadFunc = FifoPlayerThread;
else else
@ -611,7 +597,7 @@ static void EmuThread(std::unique_ptr<BootParameters> boot)
Host_Message(WM_USER_CREATE); Host_Message(WM_USER_CREATE);
// Spawn the CPU thread // Spawn the CPU thread
s_cpu_thread = std::thread(cpuThreadFunc); s_cpu_thread = std::thread(cpuThreadFunc, savestate_path);
// become the GPU thread // become the GPU thread
Fifo::RunGpuLoop(); Fifo::RunGpuLoop();
@ -629,7 +615,7 @@ static void EmuThread(std::unique_ptr<BootParameters> boot)
Common::SetCurrentThreadName("Emuthread - Idle"); Common::SetCurrentThreadName("Emuthread - Idle");
// Spawn the CPU+GPU thread // 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) while (CPU::GetState() != CPU::State::PowerDown)
{ {

View File

@ -64,9 +64,6 @@ void Callback_WiimoteInterruptChannel(int _number, u16 _channelID, const void* _
// This displays messages in a user-visible way. // This displays messages in a user-visible way.
void DisplayMessage(const std::string& message, int time_in_ms); void DisplayMessage(const std::string& message, int time_in_ms);
std::string GetStateFileName();
void SetStateFileName(const std::string& val);
void FrameUpdateOnCPUThread(); void FrameUpdateOnCPUThread();
bool ShouldSkipFrame(int skipped); bool ShouldSkipFrame(int skipped);

View File

@ -232,8 +232,6 @@ void Init(const BootParameters& boot)
} }
memset(&s_padState, 0, sizeof(s_padState)); memset(&s_padState, 0, sizeof(s_padState));
if (!tmpHeader.bFromSaveState || !IsPlayingInput())
Core::SetStateFileName("");
for (auto& disp : s_InputDisplay) for (auto& disp : s_InputDisplay)
disp.clear(); disp.clear();
@ -865,12 +863,12 @@ void ReadHeader()
} }
// NOTE: Host Thread // NOTE: Host Thread
bool PlayInput(const std::string& filename) bool PlayInput(const std::string& movie_path, std::optional<std::string>* savestate_path)
{ {
if (s_playMode != MODE_NONE) if (s_playMode != MODE_NONE)
return false; return false;
File::IOFile recording_file(filename, "rb"); File::IOFile recording_file(movie_path, "rb");
if (!recording_file.ReadArray(&tmpHeader, 1)) if (!recording_file.ReadArray(&tmpHeader, 1))
return false; return false;
@ -902,13 +900,13 @@ bool PlayInput(const std::string& filename)
recording_file.Close(); recording_file.Close();
// Load savestate (and skip to frame data) // Load savestate (and skip to frame data)
if (tmpHeader.bFromSaveState) if (tmpHeader.bFromSaveState && savestate_path)
{ {
const std::string stateFilename = filename + ".sav"; const std::string savestate_path_temp = movie_path + ".sav";
if (File::Exists(stateFilename)) if (File::Exists(savestate_path_temp))
Core::SetStateFileName(stateFilename); *savestate_path = savestate_path_temp;
s_bRecordingFromSaveState = true; s_bRecordingFromSaveState = true;
Movie::LoadInput(filename); Movie::LoadInput(movie_path);
} }
return true; return true;
@ -928,12 +926,12 @@ void DoState(PointerWrap& p)
} }
// NOTE: Host Thread // NOTE: Host Thread
void LoadInput(const std::string& filename) void LoadInput(const std::string& movie_path)
{ {
File::IOFile t_record; 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); EndPlayInput(false);
return; return;
} }
@ -942,7 +940,7 @@ void LoadInput(const std::string& filename)
if (!IsMovieHeader(tmpHeader.filetype)) 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); EndPlayInput(false);
return; return;
} }

View File

@ -5,6 +5,7 @@
#pragma once #pragma once
#include <functional> #include <functional>
#include <optional>
#include <string> #include <string>
#include "Common/CommonTypes.h" #include "Common/CommonTypes.h"
@ -157,8 +158,8 @@ bool BeginRecordingInput(int controllers);
void RecordInput(GCPadStatus* PadStatus, int controllerID); void RecordInput(GCPadStatus* PadStatus, int controllerID);
void RecordWiimote(int wiimote, u8* data, u8 size); void RecordWiimote(int wiimote, u8* data, u8 size);
bool PlayInput(const std::string& filename); bool PlayInput(const std::string& movie_path, std::optional<std::string>* savestate_path);
void LoadInput(const std::string& filename); void LoadInput(const std::string& movie_path);
void ReadHeader(); void ReadHeader();
void PlayController(GCPadStatus* PadStatus, int controllerID); void PlayController(GCPadStatus* PadStatus, int controllerID);
bool PlayWiimote(int wiimote, u8* data, const struct WiimoteEmu::ReportFeatures& rptf, int ext, bool PlayWiimote(int wiimote, u8* data, const struct WiimoteEmu::ReportFeatures& rptf, int ext,

View File

@ -15,6 +15,7 @@
#include <QProgressDialog> #include <QProgressDialog>
#include <future> #include <future>
#include <optional>
#include "Common/Version.h" #include "Common/Version.h"
@ -164,7 +165,7 @@ void MainWindow::CreateComponents()
m_fifo_window = new FIFOPlayerWindow(this); m_fifo_window = new FIFOPlayerWindow(this);
connect(m_fifo_window, &FIFOPlayerWindow::LoadFIFORequested, this, connect(m_fifo_window, &FIFOPlayerWindow::LoadFIFORequested, this,
static_cast<void (MainWindow::*)(const QString&)>(&MainWindow::StartGame)); [this](const QString& path) { StartGame(path); });
#if defined(HAVE_XRANDR) && HAVE_XRANDR #if defined(HAVE_XRANDR) && HAVE_XRANDR
m_graphics_window = new GraphicsWindow( m_graphics_window = new GraphicsWindow(
@ -192,7 +193,7 @@ void MainWindow::ConnectMenuBar()
// Emulation // Emulation
connect(m_menu_bar, &MenuBar::Pause, this, &MainWindow::Pause); 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::Stop, this, &MainWindow::RequestStop);
connect(m_menu_bar, &MenuBar::Reset, this, &MainWindow::Reset); connect(m_menu_bar, &MenuBar::Reset, this, &MainWindow::Reset);
connect(m_menu_bar, &MenuBar::Fullscreen, this, &MainWindow::FullScreen); connect(m_menu_bar, &MenuBar::Fullscreen, this, &MainWindow::FullScreen);
@ -278,7 +279,7 @@ void MainWindow::ConnectToolBar()
{ {
addToolBar(m_tool_bar); addToolBar(m_tool_bar);
connect(m_tool_bar, &ToolBar::OpenPressed, this, &MainWindow::Open); 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::PausePressed, this, &MainWindow::Pause);
connect(m_tool_bar, &ToolBar::StopPressed, this, &MainWindow::RequestStop); connect(m_tool_bar, &ToolBar::StopPressed, this, &MainWindow::RequestStop);
connect(m_tool_bar, &ToolBar::FullScreenPressed, this, &MainWindow::FullScreen); connect(m_tool_bar, &ToolBar::FullScreenPressed, this, &MainWindow::FullScreen);
@ -290,7 +291,7 @@ void MainWindow::ConnectToolBar()
void MainWindow::ConnectGameList() 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::NetPlayHost, this, &MainWindow::NetPlayHost);
connect(m_game_list, &GameList::OpenGeneralSettings, this, &MainWindow::ShowGeneralWindow); connect(m_game_list, &GameList::OpenGeneralSettings, this, &MainWindow::ShowGeneralWindow);
@ -327,7 +328,7 @@ void MainWindow::Open()
StartGame(file); StartGame(file);
} }
void MainWindow::Play() void MainWindow::Play(const std::optional<std::string>& savestate_path)
{ {
// If we're in a paused game, start it up again. // If we're in a paused game, start it up again.
// Otherwise, play the selected game, if there is one. // Otherwise, play the selected game, if there is one.
@ -343,14 +344,14 @@ void MainWindow::Play()
QSharedPointer<GameFile> selection = m_game_list->GetSelectedGame(); QSharedPointer<GameFile> selection = m_game_list->GetSelectedGame();
if (selection) if (selection)
{ {
StartGame(selection->GetFilePath()); StartGame(selection->GetFilePath(), savestate_path);
} }
else else
{ {
auto default_path = QString::fromStdString(SConfig::GetInstance().m_strDefaultISO); auto default_path = QString::fromStdString(SConfig::GetInstance().m_strDefaultISO);
if (!default_path.isEmpty() && QFile::exists(default_path)) if (!default_path.isEmpty() && QFile::exists(default_path))
{ {
StartGame(default_path); StartGame(default_path, savestate_path);
} }
else else
{ {
@ -472,9 +473,9 @@ void MainWindow::ScreenShot()
Core::SaveScreenShot(); Core::SaveScreenShot();
} }
void MainWindow::StartGame(const QString& path) void MainWindow::StartGame(const QString& path, const std::optional<std::string>& savestate_path)
{ {
StartGame(BootParameters::GenerateFromFile(path.toStdString())); StartGame(BootParameters::GenerateFromFile(path.toStdString(), savestate_path));
} }
void MainWindow::StartGame(std::unique_ptr<BootParameters>&& parameters) void MainWindow::StartGame(std::unique_ptr<BootParameters>&& parameters)
@ -680,7 +681,7 @@ void MainWindow::NetPlayInit()
m_netplay_dialog = new NetPlayDialog(this); m_netplay_dialog = new NetPlayDialog(this);
connect(m_netplay_dialog, &NetPlayDialog::Boot, this, connect(m_netplay_dialog, &NetPlayDialog::Boot, this,
static_cast<void (MainWindow::*)(const QString&)>(&MainWindow::StartGame)); [this](const QString& path) { StartGame(path); });
connect(m_netplay_dialog, &NetPlayDialog::Stop, this, &MainWindow::RequestStop); connect(m_netplay_dialog, &NetPlayDialog::Stop, this, &MainWindow::RequestStop);
connect(m_netplay_dialog, &NetPlayDialog::rejected, this, &MainWindow::NetPlayQuit); connect(m_netplay_dialog, &NetPlayDialog::rejected, this, &MainWindow::NetPlayQuit);
connect(m_netplay_setup_dialog, &NetPlaySetupDialog::Join, this, &MainWindow::NetPlayJoin); connect(m_netplay_setup_dialog, &NetPlaySetupDialog::Join, this, &MainWindow::NetPlayJoin);
@ -938,11 +939,12 @@ void MainWindow::OnPlayRecording()
emit ReadOnlyModeChanged(true); emit ReadOnlyModeChanged(true);
} }
if (Movie::PlayInput(dtm_file.toStdString())) std::optional<std::string> savestate_path;
if (Movie::PlayInput(dtm_file.toStdString(), &savestate_path))
{ {
emit RecordingStatusChanged(true); emit RecordingStatusChanged(true);
Play(); Play(savestate_path);
} }
} }

View File

@ -10,6 +10,7 @@
#include <QToolBar> #include <QToolBar>
#include <memory> #include <memory>
#include <optional>
#include "DolphinQt2/GameList/GameList.h" #include "DolphinQt2/GameList/GameList.h"
#include "DolphinQt2/MenuBar.h" #include "DolphinQt2/MenuBar.h"
@ -47,7 +48,7 @@ signals:
private: private:
void Open(); void Open();
void Play(); void Play(const std::optional<std::string>& savestate_path = {});
void Pause(); void Pause();
// May ask for confirmation. Returns whether or not it actually stopped. // May ask for confirmation. Returns whether or not it actually stopped.
@ -86,7 +87,7 @@ private:
void InitCoreCallbacks(); void InitCoreCallbacks();
void StartGame(const QString& path); void StartGame(const QString& path, const std::optional<std::string>& savestate_path = {});
void StartGame(std::unique_ptr<BootParameters>&& parameters); void StartGame(std::unique_ptr<BootParameters>&& parameters);
void ShowRenderWidget(); void ShowRenderWidget();
void HideRenderWidget(); void HideRenderWidget();

View File

@ -8,6 +8,7 @@
#include <atomic> #include <atomic>
#include <cstddef> #include <cstddef>
#include <fstream> #include <fstream>
#include <optional>
#include <string> #include <string>
#include <utility> #include <utility>
#include <vector> #include <vector>
@ -130,8 +131,9 @@ void CRenderFrame::OnDropFiles(wxDropFilesEvent& event)
main_frame->GetMenuBar()->FindItem(IDM_RECORD_READ_ONLY)->Check(true); main_frame->GetMenuBar()->FindItem(IDM_RECORD_READ_ONLY)->Check(true);
} }
if (Movie::PlayInput(filepath)) std::optional<std::string> savestate_path;
main_frame->BootGame(""); if (Movie::PlayInput(filepath, &savestate_path))
main_frame->BootGame("", savestate_path);
} }
else if (!Core::IsRunning()) else if (!Core::IsRunning())
{ {

View File

@ -8,6 +8,7 @@
#include <cstddef> #include <cstddef>
#include <memory> #include <memory>
#include <mutex> #include <mutex>
#include <optional>
#include <string> #include <string>
#include <vector> #include <vector>
#include <wx/bitmap.h> #include <wx/bitmap.h>
@ -105,7 +106,7 @@ public:
void ToggleLogConfigWindow(bool bShow); void ToggleLogConfigWindow(bool bShow);
void StatusBarMessage(const char* format, ...); void StatusBarMessage(const char* format, ...);
void ClearStatusBar(); void ClearStatusBar();
void BootGame(const std::string& filename); void BootGame(const std::string& filename, const std::optional<std::string>& savestate_path = {});
void StartGame(std::unique_ptr<BootParameters> boot); void StartGame(std::unique_ptr<BootParameters> boot);
bool RendererHasFocus(); bool RendererHasFocus();
bool RendererIsFullscreen(); bool RendererIsFullscreen();

View File

@ -9,6 +9,7 @@
#include <cstdio> #include <cstdio>
#include <future> #include <future>
#include <mutex> #include <mutex>
#include <optional>
#include <string> #include <string>
#include <vector> #include <vector>
#include <wx/app.h> #include <wx/app.h>
@ -301,7 +302,7 @@ void CFrame::OpenGeneralConfiguration(wxWindowID tab_id)
// 1. Show the game list and boot the selected game. // 1. Show the game list and boot the selected game.
// 2. Default ISO // 2. Default ISO
// 3. Boot last selected game // 3. Boot last selected game
void CFrame::BootGame(const std::string& filename) void CFrame::BootGame(const std::string& filename, const std::optional<std::string>& savestate_path)
{ {
std::string bootfile = filename; std::string bootfile = filename;
SConfig& StartUp = SConfig::GetInstance(); SConfig& StartUp = SConfig::GetInstance();
@ -331,7 +332,7 @@ void CFrame::BootGame(const std::string& filename)
} }
if (!bootfile.empty()) 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(); GetMenuBar()->FindItem(IDM_RECORD_READ_ONLY)->Check();
} }
if (Movie::PlayInput(WxStrToStr(path))) std::optional<std::string> savestate_path;
BootGame(""); if (Movie::PlayInput(WxStrToStr(path), &savestate_path))
BootGame("", savestate_path);
} }
void CFrame::OnStopRecording(wxCommandEvent& WXUNUSED(event)) void CFrame::OnStopRecording(wxCommandEvent& WXUNUSED(event))

View File

@ -5,6 +5,7 @@
#include <OptionParser.h> #include <OptionParser.h>
#include <cstdio> #include <cstdio>
#include <cstring> #include <cstring>
#include <optional>
#include <string> #include <string>
#include <utility> #include <utility>
#include <wx/app.h> #include <wx/app.h>
@ -256,12 +257,18 @@ void DolphinApp::AfterInit()
if (m_play_movie && !m_movie_file.empty()) if (m_play_movie && !m_movie_file.empty())
{ {
if (Movie::PlayInput(WxStrToStr(m_movie_file))) std::optional<std::string> savestate_path;
if (Movie::PlayInput(WxStrToStr(m_movie_file), &savestate_path))
{ {
if (m_boot) if (m_boot)
{
m_boot->savestate_path = savestate_path;
main_frame->StartGame(std::move(m_boot)); main_frame->StartGame(std::move(m_boot));
}
else else
main_frame->BootGame(""); {
main_frame->BootGame("", savestate_path);
}
} }
} }
// First check if we have an exec command line. // First check if we have an exec command line.