mirror of https://github.com/PCSX2/pcsx2.git
Qt: Implement save-state-on-shutdown
This commit is contained in:
parent
935dd046da
commit
c21d475bbd
|
@ -109,6 +109,7 @@ void EmuThread::startVM(std::shared_ptr<VMBootParameters> boot_params)
|
|||
m_is_fullscreen = boot_params->fullscreen.value_or(QtHost::GetBaseBoolSettingValue("UI", "StartFullscreen", false));
|
||||
m_is_rendering_to_main = QtHost::GetBaseBoolSettingValue("UI", "RenderToMainWindow", true);
|
||||
m_is_surfaceless = false;
|
||||
m_save_state_on_shutdown = false;
|
||||
if (!VMManager::Initialize(*boot_params))
|
||||
return;
|
||||
|
||||
|
@ -142,14 +143,21 @@ void EmuThread::setVMPaused(bool paused)
|
|||
VMManager::SetPaused(paused);
|
||||
}
|
||||
|
||||
void EmuThread::shutdownVM(bool allow_save_to_state /* = true */)
|
||||
void EmuThread::shutdownVM(bool save_state /* = true */)
|
||||
{
|
||||
if (!isOnEmuThread())
|
||||
{
|
||||
QMetaObject::invokeMethod(this, "shutdownVM", Qt::QueuedConnection, Q_ARG(bool, save_state));
|
||||
return;
|
||||
}
|
||||
|
||||
const VMState state = VMManager::GetState();
|
||||
if (state == VMState::Paused)
|
||||
m_event_loop->quit();
|
||||
else if (state != VMState::Running)
|
||||
return;
|
||||
|
||||
m_save_state_on_shutdown = save_state;
|
||||
VMManager::SetState(VMState::Stopping);
|
||||
}
|
||||
|
||||
|
@ -254,7 +262,7 @@ void EmuThread::destroyVM()
|
|||
m_last_video_fps = 0.0f;
|
||||
m_last_internal_width = 0;
|
||||
m_last_internal_height = 0;
|
||||
VMManager::Shutdown();
|
||||
VMManager::Shutdown(m_save_state_on_shutdown);
|
||||
}
|
||||
|
||||
void EmuThread::executeVM()
|
||||
|
|
|
@ -59,7 +59,7 @@ public Q_SLOTS:
|
|||
void startVM(std::shared_ptr<VMBootParameters> boot_params);
|
||||
void resetVM();
|
||||
void setVMPaused(bool paused);
|
||||
void shutdownVM(bool allow_save_to_state = true);
|
||||
void shutdownVM(bool save_state = true);
|
||||
void loadState(const QString& filename);
|
||||
void loadStateFromSlot(qint32 slot);
|
||||
void saveState(const QString& filename);
|
||||
|
@ -159,6 +159,7 @@ private:
|
|||
bool m_is_rendering_to_main = false;
|
||||
bool m_is_fullscreen = false;
|
||||
bool m_is_surfaceless = false;
|
||||
bool m_save_state_on_shutdown = false;
|
||||
|
||||
float m_last_speed = 0.0f;
|
||||
float m_last_game_fps = 0.0f;
|
||||
|
|
|
@ -143,7 +143,8 @@ void MainWindow::connectSignals()
|
|||
connect(m_ui.actionChangeDiscFromGameList, &QAction::triggered, this, &MainWindow::onChangeDiscFromGameListActionTriggered);
|
||||
connect(m_ui.menuChangeDisc, &QMenu::aboutToShow, this, &MainWindow::onChangeDiscMenuAboutToShow);
|
||||
connect(m_ui.menuChangeDisc, &QMenu::aboutToHide, this, &MainWindow::onChangeDiscMenuAboutToHide);
|
||||
connect(m_ui.actionPowerOff, &QAction::triggered, this, [this]() { requestShutdown(); });
|
||||
connect(m_ui.actionPowerOff, &QAction::triggered, this, [this]() { requestShutdown(true, true); });
|
||||
connect(m_ui.actionPowerOffWithoutSaving, &QAction::triggered, this, [this]() { requestShutdown(false, false); });
|
||||
connect(m_ui.actionLoadState, &QAction::triggered, this, [this]() { m_ui.menuLoadState->exec(QCursor::pos()); });
|
||||
connect(m_ui.actionSaveState, &QAction::triggered, this, [this]() { m_ui.menuSaveState->exec(QCursor::pos()); });
|
||||
connect(m_ui.actionExit, &QAction::triggered, this, &MainWindow::close);
|
||||
|
@ -562,6 +563,7 @@ void MainWindow::updateEmulationActions(bool starting, bool running)
|
|||
m_ui.actionStartBios->setDisabled(starting_or_running);
|
||||
|
||||
m_ui.actionPowerOff->setEnabled(running);
|
||||
m_ui.actionPowerOffWithoutSaving->setEnabled(running);
|
||||
m_ui.actionReset->setEnabled(running);
|
||||
m_ui.actionPause->setEnabled(running);
|
||||
m_ui.actionChangeDisc->setEnabled(running);
|
||||
|
@ -739,18 +741,34 @@ bool MainWindow::requestShutdown(bool allow_confirm /* = true */, bool allow_sav
|
|||
if (!VMManager::HasValidVM())
|
||||
return true;
|
||||
|
||||
// if we don't have a crc, we can't save state
|
||||
allow_save_to_state &= (m_current_game_crc != 0);
|
||||
bool save_state = allow_save_to_state && EmuConfig.SaveStateOnShutdown;
|
||||
|
||||
// only confirm on UI thread because we need to display a msgbox
|
||||
if (allow_confirm && !GSDumpReplayer::IsReplayingDump() && QtHost::GetBaseBoolSettingValue("UI", "ConfirmShutdown", true))
|
||||
{
|
||||
VMLock lock(pauseAndLockVM());
|
||||
if (QMessageBox::question(lock.getDialogParent(), tr("Confirm Shutdown"),
|
||||
tr("Are you sure you want to shut down the virtual machine?\n\nAll unsaved progress will be lost.")) != QMessageBox::Yes)
|
||||
{
|
||||
|
||||
QMessageBox msgbox(lock.getDialogParent());
|
||||
msgbox.setIcon(QMessageBox::Question);
|
||||
msgbox.setWindowTitle(tr("Confirm Shutdown"));
|
||||
msgbox.setText("Are you sure you want to shut down the virtual machine?");
|
||||
|
||||
QCheckBox* save_cb = new QCheckBox(tr("Save State For Resume"), &msgbox);
|
||||
save_cb->setChecked(save_state);
|
||||
save_cb->setEnabled(allow_save_to_state);
|
||||
msgbox.setCheckBox(save_cb);
|
||||
msgbox.addButton(QMessageBox::Yes);
|
||||
msgbox.addButton(QMessageBox::No);
|
||||
msgbox.setDefaultButton(QMessageBox::Yes);
|
||||
if (msgbox.exec() != QMessageBox::Yes)
|
||||
return false;
|
||||
}
|
||||
|
||||
save_state = save_cb->isChecked();
|
||||
}
|
||||
|
||||
g_emu_thread->shutdownVM(allow_save_to_state);
|
||||
g_emu_thread->shutdownVM(save_state);
|
||||
|
||||
if (block_until_done || QtHost::InBatchMode())
|
||||
{
|
||||
|
@ -817,9 +835,16 @@ void MainWindow::onGameListEntryActivated()
|
|||
return;
|
||||
}
|
||||
|
||||
const std::optional<bool> resume = promptForResumeState(
|
||||
QString::fromStdString(VMManager::GetSaveStateFileName(entry->serial.c_str(), entry->crc, -1)));
|
||||
if (!resume.has_value())
|
||||
{
|
||||
// cancelled
|
||||
return;
|
||||
}
|
||||
|
||||
// only resume if the option is enabled, and we have one for this game
|
||||
const bool resume = (VMManager::ShouldSaveResumeState() && VMManager::HasSaveStateInSlot(entry->serial.c_str(), entry->crc, -1));
|
||||
startGameListEntry(entry, resume ? std::optional<s32>(-1) : std::optional<s32>(), std::nullopt);
|
||||
startGameListEntry(entry, resume.value() ? std::optional<s32>(-1) : std::optional<s32>(), std::nullopt);
|
||||
}
|
||||
|
||||
void MainWindow::onGameListEntryContextMenuRequested(const QPoint& point)
|
||||
|
@ -856,7 +881,7 @@ void MainWindow::onGameListEntryContextMenuRequested(const QPoint& point)
|
|||
connect(action, &QAction::triggered, [this, entry]() { startGameListEntry(entry); });
|
||||
|
||||
// Make bold to indicate it's the default choice when double-clicking
|
||||
if (!VMManager::ShouldSaveResumeState() || !VMManager::HasSaveStateInSlot(entry->serial.c_str(), entry->crc, -1))
|
||||
if (!VMManager::HasSaveStateInSlot(entry->serial.c_str(), entry->crc, -1))
|
||||
QtUtils::MarkActionAsDefault(action);
|
||||
|
||||
action = menu.addAction(tr("Fast Boot"));
|
||||
|
@ -902,6 +927,15 @@ void MainWindow::onStartFileActionTriggered()
|
|||
|
||||
std::shared_ptr<VMBootParameters> params = std::make_shared<VMBootParameters>();
|
||||
params->filename = filename.toStdString();
|
||||
|
||||
const std::optional<bool> resume(
|
||||
promptForResumeState(
|
||||
QString::fromStdString(VMManager::GetSaveStateFileName(params->filename.c_str(), -1))));
|
||||
if (!resume.has_value())
|
||||
return;
|
||||
else if (resume.value())
|
||||
params->state_index = -1;
|
||||
|
||||
g_emu_thread->startVM(std::move(params));
|
||||
}
|
||||
|
||||
|
@ -1582,6 +1616,49 @@ void MainWindow::setGameListEntryCoverImage(const GameList::Entry* entry)
|
|||
m_game_list_widget->refreshGridCovers();
|
||||
}
|
||||
|
||||
std::optional<bool> MainWindow::promptForResumeState(const QString& save_state_path)
|
||||
{
|
||||
if (save_state_path.isEmpty())
|
||||
return false;
|
||||
|
||||
QFileInfo fi(save_state_path);
|
||||
if (!fi.exists())
|
||||
return false;
|
||||
|
||||
QMessageBox msgbox(this);
|
||||
msgbox.setIcon(QMessageBox::Question);
|
||||
msgbox.setWindowTitle(tr("Load Resume State"));
|
||||
msgbox.setText(
|
||||
tr("A resume save state was found for this game, saved at:\n\n%1.\n\nDo you want to load this state, or start from a fresh boot?")
|
||||
.arg(fi.lastModified().toLocalTime().toString()));
|
||||
|
||||
QPushButton* load = msgbox.addButton(tr("Load State"), QMessageBox::AcceptRole);
|
||||
QPushButton* boot = msgbox.addButton(tr("Fresh Boot"), QMessageBox::RejectRole);
|
||||
QPushButton* delboot = msgbox.addButton(tr("Delete And Boot"), QMessageBox::RejectRole);
|
||||
QPushButton* cancel = msgbox.addButton(QMessageBox::Cancel);
|
||||
msgbox.setDefaultButton(load);
|
||||
msgbox.exec();
|
||||
|
||||
QAbstractButton* clicked = msgbox.clickedButton();
|
||||
if (load == clicked)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (boot == clicked)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (delboot == clicked)
|
||||
{
|
||||
if (!QFile::remove(save_state_path))
|
||||
QMessageBox::critical(this, tr("Error"), tr("Failed to delete save state file '%1'.").arg(save_state_path));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
void MainWindow::loadSaveStateSlot(s32 slot)
|
||||
{
|
||||
if (m_vm_valid)
|
||||
|
@ -1659,8 +1736,7 @@ void MainWindow::populateLoadStateMenu(QMenu* menu, const QString& filename, con
|
|||
connect(action, &QAction::triggered, [this]() { loadSaveStateSlot(-1); });
|
||||
|
||||
// Make bold to indicate it's the default choice when double-clicking
|
||||
if (VMManager::ShouldSaveResumeState())
|
||||
QtUtils::MarkActionAsDefault(action);
|
||||
QtUtils::MarkActionAsDefault(action);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -185,6 +185,7 @@ private:
|
|||
std::optional<bool> fast_boot = std::nullopt);
|
||||
void setGameListEntryCoverImage(const GameList::Entry* entry);
|
||||
|
||||
std::optional<bool> promptForResumeState(const QString& save_state_path);
|
||||
void loadSaveStateSlot(s32 slot);
|
||||
void loadSaveStateFile(const QString& filename, const QString& state_filename);
|
||||
void populateLoadStateMenu(QMenu* menu, const QString& filename, const QString& serial, quint32 crc);
|
||||
|
|
|
@ -80,6 +80,7 @@
|
|||
<addaction name="actionStartBios"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionPowerOff"/>
|
||||
<addaction name="actionPowerOffWithoutSaving"/>
|
||||
<addaction name="actionReset"/>
|
||||
<addaction name="actionPause"/>
|
||||
<addaction name="menuChangeDisc"/>
|
||||
|
@ -285,6 +286,15 @@
|
|||
<string>Shut &Down</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionPowerOffWithoutSaving">
|
||||
<property name="icon">
|
||||
<iconset theme="close-line">
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Shut Down &Without Saving</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionReset">
|
||||
<property name="icon">
|
||||
<iconset theme="restart-line">
|
||||
|
|
|
@ -42,7 +42,7 @@ InterfaceSettingsWidget::InterfaceSettingsWidget(SettingsDialog* dialog, QWidget
|
|||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.inhibitScreensaver, "UI", "InhibitScreensaver", true);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.discordPresence, "UI", "DiscordPresence", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.confirmShutdown, "UI", "ConfirmShutdown", true);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.saveStateOnExit, "EmuCore", "AutoStateLoadSave", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.saveStateOnShutdown, "EmuCore", "SaveStateOnShutdown", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.pauseOnStart, "UI", "StartPaused", false);
|
||||
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.pauseOnFocusLoss, "UI", "PauseOnFocusLoss", false);
|
||||
|
||||
|
@ -87,7 +87,7 @@ InterfaceSettingsWidget::InterfaceSettingsWidget(SettingsDialog* dialog, QWidget
|
|||
m_ui.confirmShutdown, tr("Confirm Shutdown"), tr("Checked"),
|
||||
tr("Determines whether a prompt will be displayed to confirm shutting down the virtual machine "
|
||||
"when the hotkey is pressed."));
|
||||
dialog->registerWidgetHelp(m_ui.saveStateOnExit, tr("Save State On Exit"), tr("Checked"),
|
||||
dialog->registerWidgetHelp(m_ui.saveStateOnShutdown, tr("Save State On Shutdown"), tr("Checked"),
|
||||
tr("Automatically saves the emulator state when powering down or exiting. You can then "
|
||||
"resume directly from where you left off next time."));
|
||||
dialog->registerWidgetHelp(m_ui.pauseOnStart, tr("Pause On Start"), tr("Unchecked"),
|
||||
|
|
|
@ -68,9 +68,9 @@
|
|||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QCheckBox" name="saveStateOnExit">
|
||||
<widget class="QCheckBox" name="saveStateOnShutdown">
|
||||
<property name="text">
|
||||
<string>Save Or Load State On Exit / Resume</string>
|
||||
<string>Save State On Shutdown</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
|
@ -939,6 +939,7 @@ struct Pcsx2Config
|
|||
#endif
|
||||
#ifdef PCSX2_CORE
|
||||
EnableGameFixes : 1, // enables automatic game fixes
|
||||
SaveStateOnShutdown : 1, // default value for saving state on shutdown
|
||||
#endif
|
||||
// when enabled uses BOOT2 injection, skipping sony bios splashes
|
||||
UseBOOT2Injection : 1,
|
||||
|
|
|
@ -1062,6 +1062,7 @@ void Pcsx2Config::LoadSave(SettingsWrapper& wrap)
|
|||
#endif
|
||||
#ifdef PCSX2_CORE
|
||||
SettingsWrapBitBool(EnableGameFixes);
|
||||
SettingsWrapBitBool(SaveStateOnShutdown);
|
||||
#endif
|
||||
SettingsWrapBitBool(ConsoleToStdio);
|
||||
SettingsWrapBitBool(HostFs);
|
||||
|
|
|
@ -783,8 +783,7 @@ static bool SaveState_CompressScreenshot(SaveStateScreenshotData* data, zip_t* z
|
|||
// --------------------------------------------------------------------------------------
|
||||
// CompressThread_VmState
|
||||
// --------------------------------------------------------------------------------------
|
||||
static void ZipStateToDiskOnThread(std::unique_ptr<ArchiveEntryList> srclist, std::unique_ptr<SaveStateScreenshotData> screenshot,
|
||||
std::string filename, s32 slot_for_message)
|
||||
void SaveState_ZipToDisk(std::unique_ptr<ArchiveEntryList> srclist, std::unique_ptr<SaveStateScreenshotData> screenshot, std::string filename, s32 slot_for_message)
|
||||
{
|
||||
#ifndef PCSX2_CORE
|
||||
wxGetApp().StartPendingSave();
|
||||
|
@ -858,9 +857,10 @@ static void ZipStateToDiskOnThread(std::unique_ptr<ArchiveEntryList> srclist, st
|
|||
#endif
|
||||
}
|
||||
|
||||
void SaveState_ZipToDisk(std::unique_ptr<ArchiveEntryList> srclist, std::unique_ptr<SaveStateScreenshotData> screenshot, std::string filename, s32 slot_for_message)
|
||||
|
||||
void SaveState_ZipToDiskOnThread(std::unique_ptr<ArchiveEntryList> srclist, std::unique_ptr<SaveStateScreenshotData> screenshot, std::string filename, s32 slot_for_message)
|
||||
{
|
||||
std::thread threaded_save(ZipStateToDiskOnThread, std::move(srclist), std::move(screenshot), std::move(filename), slot_for_message);
|
||||
std::thread threaded_save(SaveState_ZipToDisk, std::move(srclist), std::move(screenshot), std::move(filename), slot_for_message);
|
||||
threaded_save.detach();
|
||||
}
|
||||
|
||||
|
|
|
@ -59,6 +59,7 @@ class ArchiveEntryList;
|
|||
extern std::unique_ptr<ArchiveEntryList> SaveState_DownloadState();
|
||||
extern std::unique_ptr<SaveStateScreenshotData> SaveState_SaveScreenshot();
|
||||
extern void SaveState_ZipToDisk(std::unique_ptr<ArchiveEntryList> srclist, std::unique_ptr<SaveStateScreenshotData> screenshot, std::string filename, s32 slot_for_message);
|
||||
extern void SaveState_ZipToDiskOnThread(std::unique_ptr<ArchiveEntryList> srclist, std::unique_ptr<SaveStateScreenshotData> screenshot, std::string filename, s32 slot_for_message);
|
||||
extern void SaveState_UnzipFromDisk(const std::string& filename);
|
||||
|
||||
// --------------------------------------------------------------------------------------
|
||||
|
|
|
@ -84,7 +84,7 @@ namespace VMManager
|
|||
|
||||
static std::string GetCurrentSaveStateFileName(s32 slot);
|
||||
static bool DoLoadState(const char* filename);
|
||||
static bool DoSaveState(const char* filename, s32 slot_for_message);
|
||||
static bool DoSaveState(const char* filename, s32 slot_for_message, bool save_on_thread);
|
||||
|
||||
static void SetTimerResolutionIncreased(bool enabled);
|
||||
static void SetEmuThreadAffinities(bool force);
|
||||
|
@ -534,30 +534,11 @@ bool VMManager::ApplyBootParameters(const VMBootParameters& params, std::string*
|
|||
return false;
|
||||
}
|
||||
|
||||
// try the game list first, but this won't work if we're in batch mode
|
||||
*state_to_load = GetSaveStateFileName(params.filename.c_str(), params.state_index.value());
|
||||
if (state_to_load->empty())
|
||||
{
|
||||
auto lock = GameList::GetLock();
|
||||
if (const GameList::Entry* entry = GameList::GetEntryForPath(params.filename.c_str()); entry)
|
||||
{
|
||||
*state_to_load = GetSaveStateFileName(entry->serial.c_str(), entry->crc, params.state_index.value());
|
||||
}
|
||||
else
|
||||
{
|
||||
// just scan it.. hopefully it'll come back okay
|
||||
GameList::Entry temp_entry;
|
||||
if (!GameList::PopulateEntryFromPath(params.filename.c_str(), &temp_entry))
|
||||
{
|
||||
Host::ReportFormattedErrorAsync("Error", "Could not scan path '%s' for indexed save state load.", params.filename.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
*state_to_load = GetSaveStateFileName(temp_entry.serial.c_str(), temp_entry.crc, params.state_index.value());
|
||||
}
|
||||
if (state_to_load->empty())
|
||||
{
|
||||
Host::ReportFormattedErrorAsync("Error", "Could not resolve path indexed save state load.");
|
||||
return false;
|
||||
}
|
||||
Host::ReportFormattedErrorAsync("Error", "Could not resolve path indexed save state load.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -771,7 +752,7 @@ bool VMManager::Initialize(const VMBootParameters& boot_params)
|
|||
{
|
||||
if (!DoLoadState(state_to_load.c_str()))
|
||||
{
|
||||
Shutdown();
|
||||
Shutdown(false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -779,7 +760,7 @@ bool VMManager::Initialize(const VMBootParameters& boot_params)
|
|||
return true;
|
||||
}
|
||||
|
||||
void VMManager::Shutdown(bool allow_save_resume_state /* = true */)
|
||||
void VMManager::Shutdown(bool save_resume_state)
|
||||
{
|
||||
SetTimerResolutionIncreased(false);
|
||||
|
||||
|
@ -788,10 +769,10 @@ void VMManager::Shutdown(bool allow_save_resume_state /* = true */)
|
|||
vu1Thread.WaitVU();
|
||||
GetMTGS().WaitGS();
|
||||
|
||||
if (!GSDumpReplayer::IsReplayingDump() && allow_save_resume_state && ShouldSaveResumeState())
|
||||
if (!GSDumpReplayer::IsReplayingDump() && save_resume_state)
|
||||
{
|
||||
std::string resume_file_name(GetCurrentSaveStateFileName(-1));
|
||||
if (!resume_file_name.empty() && !DoSaveState(resume_file_name.c_str(), -1))
|
||||
if (!resume_file_name.empty() && !DoSaveState(resume_file_name.c_str(), -1, false))
|
||||
Console.Error("Failed to save resume state");
|
||||
}
|
||||
else if (GSDumpReplayer::IsReplayingDump())
|
||||
|
@ -854,23 +835,45 @@ void VMManager::Reset()
|
|||
UpdateRunningGame(true);
|
||||
}
|
||||
|
||||
bool VMManager::ShouldSaveResumeState()
|
||||
{
|
||||
return Host::GetBoolSettingValue("EmuCore", "AutoStateLoadSave", false);
|
||||
}
|
||||
|
||||
std::string VMManager::GetSaveStateFileName(const char* game_serial, u32 game_crc, s32 slot)
|
||||
{
|
||||
if (!game_serial || game_serial[0] == '\0')
|
||||
return std::string();
|
||||
|
||||
std::string filename;
|
||||
if (slot < 0)
|
||||
filename = StringUtil::StdStringFromFormat("%s (%08X).resume.p2s", game_serial, game_crc);
|
||||
else
|
||||
filename = StringUtil::StdStringFromFormat("%s (%08X).%02d.p2s", game_serial, game_crc, slot);
|
||||
if (game_crc != 0)
|
||||
{
|
||||
if (slot < 0)
|
||||
filename = StringUtil::StdStringFromFormat("%s (%08X).resume.p2s", game_serial, game_crc);
|
||||
else
|
||||
filename = StringUtil::StdStringFromFormat("%s (%08X).%02d.p2s", game_serial, game_crc, slot);
|
||||
|
||||
return Path::CombineStdString(EmuFolders::Savestates, filename);
|
||||
filename = Path::CombineStdString(EmuFolders::Savestates, filename);
|
||||
}
|
||||
|
||||
return filename;
|
||||
}
|
||||
|
||||
std::string VMManager::GetSaveStateFileName(const char* filename, s32 slot)
|
||||
{
|
||||
pxAssertRel(!HasValidVM(), "Should not have a VM when calling the non-gamelist GetSaveStateFileName()");
|
||||
|
||||
std::string ret;
|
||||
|
||||
// try the game list first, but this won't work if we're in batch mode
|
||||
auto lock = GameList::GetLock();
|
||||
if (const GameList::Entry* entry = GameList::GetEntryForPath(filename); entry)
|
||||
{
|
||||
ret = GetSaveStateFileName(entry->serial.c_str(), entry->crc, slot);
|
||||
}
|
||||
else
|
||||
{
|
||||
// just scan it.. hopefully it'll come back okay
|
||||
GameList::Entry temp_entry;
|
||||
if (GameList::PopulateEntryFromPath(filename, &temp_entry))
|
||||
{
|
||||
ret = GetSaveStateFileName(temp_entry.serial.c_str(), temp_entry.crc, slot);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool VMManager::HasSaveStateInSlot(const char* game_serial, u32 game_crc, s32 slot)
|
||||
|
@ -906,7 +909,7 @@ bool VMManager::DoLoadState(const char* filename)
|
|||
}
|
||||
}
|
||||
|
||||
bool VMManager::DoSaveState(const char* filename, s32 slot_for_message)
|
||||
bool VMManager::DoSaveState(const char* filename, s32 slot_for_message, bool zip_on_thread)
|
||||
{
|
||||
if (GSDumpReplayer::IsReplayingDump())
|
||||
return false;
|
||||
|
@ -914,7 +917,11 @@ bool VMManager::DoSaveState(const char* filename, s32 slot_for_message)
|
|||
try
|
||||
{
|
||||
std::unique_ptr<ArchiveEntryList> elist = SaveState_DownloadState();
|
||||
SaveState_ZipToDisk(std::move(elist), SaveState_SaveScreenshot(), filename, slot_for_message);
|
||||
if (zip_on_thread)
|
||||
SaveState_ZipToDiskOnThread(std::move(elist), SaveState_SaveScreenshot(), filename, slot_for_message);
|
||||
else
|
||||
SaveState_ZipToDisk(std::move(elist), SaveState_SaveScreenshot(), filename, slot_for_message);
|
||||
|
||||
Host::InvalidateSaveStateCache();
|
||||
Host::OnSaveStateSaved(filename);
|
||||
return true;
|
||||
|
@ -949,12 +956,12 @@ bool VMManager::LoadStateFromSlot(s32 slot)
|
|||
return DoLoadState(filename.c_str());
|
||||
}
|
||||
|
||||
bool VMManager::SaveState(const char* filename)
|
||||
bool VMManager::SaveState(const char* filename, bool zip_on_thread)
|
||||
{
|
||||
return DoSaveState(filename, -1);
|
||||
return DoSaveState(filename, -1, zip_on_thread);
|
||||
}
|
||||
|
||||
bool VMManager::SaveStateToSlot(s32 slot)
|
||||
bool VMManager::SaveStateToSlot(s32 slot, bool zip_on_thread)
|
||||
{
|
||||
const std::string filename(GetCurrentSaveStateFileName(slot));
|
||||
if (filename.empty())
|
||||
|
@ -962,7 +969,7 @@ bool VMManager::SaveStateToSlot(s32 slot)
|
|||
|
||||
// if it takes more than a minute.. well.. wtf.
|
||||
Host::AddKeyedFormattedOSDMessage(StringUtil::StdStringFromFormat("SaveStateSlot%d", slot), 60.0f, "Saving state to slot %d...", slot);
|
||||
return DoSaveState(filename.c_str(), slot);
|
||||
return DoSaveState(filename.c_str(), slot, zip_on_thread);
|
||||
}
|
||||
|
||||
LimiterModeType VMManager::GetLimiterMode()
|
||||
|
|
|
@ -76,7 +76,7 @@ namespace VMManager
|
|||
bool Initialize(const VMBootParameters& boot_params);
|
||||
|
||||
/// Destroys all system components.
|
||||
void Shutdown(bool allow_save_resume_state = true);
|
||||
void Shutdown(bool save_resume_state);
|
||||
|
||||
/// Resets all subsystems to a cold boot.
|
||||
void Reset();
|
||||
|
@ -96,12 +96,12 @@ namespace VMManager
|
|||
/// Reloads cheats/patches. If verbose is set, the number of patches loaded will be shown in the OSD.
|
||||
void ReloadPatches(bool verbose);
|
||||
|
||||
/// Returns true if a resume save state should be saved/loaded.
|
||||
bool ShouldSaveResumeState();
|
||||
|
||||
/// Returns the save state filename for the given game serial/crc.
|
||||
std::string GetSaveStateFileName(const char* game_serial, u32 game_crc, s32 slot);
|
||||
|
||||
/// Returns the path to save state for the specified disc/elf.
|
||||
std::string GetSaveStateFileName(const char* filename, s32 slot);
|
||||
|
||||
/// Returns true if there is a save state in the specified slot.
|
||||
bool HasSaveStateInSlot(const char* game_serial, u32 game_crc, s32 slot);
|
||||
|
||||
|
@ -112,10 +112,10 @@ namespace VMManager
|
|||
bool LoadStateFromSlot(s32 slot);
|
||||
|
||||
/// Saves state to the specified filename.
|
||||
bool SaveState(const char* filename);
|
||||
bool SaveState(const char* filename, bool zip_on_thread = true);
|
||||
|
||||
/// Saves state to the specified slot.
|
||||
bool SaveStateToSlot(s32 slot);
|
||||
bool SaveStateToSlot(s32 slot, bool zip_on_thread = true);
|
||||
|
||||
/// Returns the current limiter mode.
|
||||
LimiterModeType GetLimiterMode();
|
||||
|
|
|
@ -61,7 +61,7 @@ protected:
|
|||
std::unique_ptr<ArchiveEntryList> elist = SaveState_DownloadState();
|
||||
UI_EnableStateActions();
|
||||
paused_core.AllowResume();
|
||||
SaveState_ZipToDisk(std::move(elist), nullptr, StringUtil::wxStringToUTF8String(m_filename), -1);
|
||||
SaveState_ZipToDiskOnThread(std::move(elist), nullptr, StringUtil::wxStringToUTF8String(m_filename), -1);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in New Issue