Skip to content

Commit

Permalink
VMManager/Qt: Block shutdown, reset, change disc, drag events, save/l…
Browse files Browse the repository at this point in the history
…oad state if memcards are busy
  • Loading branch information
RedPanda4552 committed Dec 9, 2023
1 parent fe6b016 commit cd665d5
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 5 deletions.
80 changes: 75 additions & 5 deletions pcsx2-qt/MainWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
#include "pcsx2/PerformanceMetrics.h"
#include "pcsx2/Recording/InputRecording.h"
#include "pcsx2/Recording/InputRecordingControls.h"
#include "pcsx2/SIO/Sio.h"

#include "common/Assertions.h"
#include "common/CocoaTools.h"
Expand Down Expand Up @@ -433,10 +434,10 @@ void MainWindow::connectVMThreadSignals(EmuThread* thread)
connect(thread, &EmuThread::onAchievementsHardcoreModeChanged, this, &MainWindow::onAchievementsHardcoreModeChanged);
connect(thread, &EmuThread::onCoverDownloaderOpenRequested, this, &MainWindow::onToolsCoverDownloaderTriggered);

connect(m_ui.actionReset, &QAction::triggered, thread, &EmuThread::resetVM);
connect(m_ui.actionReset, &QAction::triggered, this, &MainWindow::requestReset);
connect(m_ui.actionPause, &QAction::toggled, thread, &EmuThread::setVMPaused);
connect(m_ui.actionFullscreen, &QAction::triggered, thread, &EmuThread::toggleFullscreen);
connect(m_ui.actionToolbarReset, &QAction::triggered, thread, &EmuThread::resetVM);
connect(m_ui.actionToolbarReset, &QAction::triggered, this, &MainWindow::requestReset);
connect(m_ui.actionToolbarPause, &QAction::toggled, thread, &EmuThread::setVMPaused);
connect(m_ui.actionToolbarFullscreen, &QAction::triggered, thread, &EmuThread::toggleFullscreen);
connect(m_ui.actionToggleSoftwareRendering, &QAction::triggered, thread, &EmuThread::toggleSoftwareRendering);
Expand Down Expand Up @@ -1044,6 +1045,29 @@ void MainWindow::runOnUIThread(const std::function<void()>& func)
func();
}

void MainWindow::requestReset()
{
if (!s_vm_valid)
return;

// Check if memcard is busy, deny request if so
if (MemcardBusy::IsBusy() && !GSDumpReplayer::IsReplayingDump())
{
VMLock lock(pauseAndLockVM());
QMessageBox msgbox(lock.getDialogParent());
msgbox.setIcon(QMessageBox::Warning);
msgbox.setWindowTitle(tr("WARNING: Memory Card Busy"));
msgbox.setText(tr("WARNING: Your memory card is still writing data. Shutting down now will IRREVERSIBLY DESTORY YOUR MEMORY CARD. It is strongly recommended to resume your game and let it finish saving.\n\nDo you wish to shutdown anyways and IRREVERSIBLY DESTROY YOUR MEMORY CARD?"));
msgbox.addButton(QMessageBox::Yes);
msgbox.addButton(QMessageBox::No);
msgbox.setDefaultButton(QMessageBox::No);
if (msgbox.exec() != QMessageBox::Yes)
return;

g_emu_thread->resetVM();
}
}

bool MainWindow::requestShutdown(bool allow_confirm, bool allow_save_to_state, bool default_save_to_state)
{
if (!s_vm_valid)
Expand All @@ -1052,12 +1076,26 @@ bool MainWindow::requestShutdown(bool allow_confirm, bool allow_save_to_state, b
// If we don't have a crc, we can't save state.
allow_save_to_state &= (m_current_disc_crc != 0);
bool save_state = allow_save_to_state && default_save_to_state;
VMLock lock(pauseAndLockVM());

// Only confirm on UI thread because we need to display a msgbox.
if (!m_is_closing && allow_confirm && !GSDumpReplayer::IsReplayingDump() && Host::GetBoolSettingValue("UI", "ConfirmShutdown", true))
// Check if memcard is busy, deny request if so
if (MemcardBusy::IsBusy() && !GSDumpReplayer::IsReplayingDump())
{
VMLock lock(pauseAndLockVM());
QMessageBox msgbox(lock.getDialogParent());
msgbox.setIcon(QMessageBox::Warning);
msgbox.setWindowTitle(tr("WARNING: Memory Card Busy"));
msgbox.setText(tr("WARNING: Your memory card is still writing data. Shutting down now will IRREVERSIBLY DESTORY YOUR MEMORY CARD. It is strongly recommended to resume your game and let it finish saving.\n\nDo you wish to shutdown anyways and IRREVERSIBLY DESTROY YOUR MEMORY CARD?"));
msgbox.addButton(QMessageBox::Yes);
msgbox.addButton(QMessageBox::No);
msgbox.setDefaultButton(QMessageBox::No);
if (msgbox.exec() != QMessageBox::Yes)
return false;

lock.cancelResume();
}
// Only confirm on UI thread because we need to display a msgbox.
else if (!m_is_closing && allow_confirm && !GSDumpReplayer::IsReplayingDump() && Host::GetBoolSettingValue("UI", "ConfirmShutdown", true))
{
QMessageBox msgbox(lock.getDialogParent());
msgbox.setIcon(QMessageBox::Question);
msgbox.setWindowTitle(tr("Confirm Shutdown"));
Expand Down Expand Up @@ -1899,6 +1937,22 @@ void MainWindow::dragEnterEvent(QDragEnterEvent* event)

void MainWindow::dropEvent(QDropEvent* event)
{
// Check if memcard is busy, deny request if so
if (!GSDumpReplayer::IsReplayingDump() && MemcardBusy::IsBusy())
{
VMLock lock(pauseAndLockVM());

QMessageBox msgbox(lock.getDialogParent());
msgbox.setIcon(QMessageBox::Warning);
msgbox.setWindowTitle(tr("WARNING: Memory Card Busy"));
msgbox.setText(tr("WARNING: Your memory card is still writing data. Shutting down now will IRREVERSIBLY DESTORY YOUR MEMORY CARD. It is strongly recommended to resume your game and let it finish saving.\n\nDo you wish to shutdown anyways and IRREVERSIBLY DESTROY YOUR MEMORY CARD?"));
msgbox.addButton(QMessageBox::Yes);
msgbox.addButton(QMessageBox::No);
msgbox.setDefaultButton(QMessageBox::No);
if (msgbox.exec() != QMessageBox::Yes)
return;
}

const QString filename(getFilenameFromMimeData(event->mimeData()));
const std::string filename_str(filename.toStdString());
if (VMManager::IsSaveStateFileName(filename_str))
Expand Down Expand Up @@ -2730,6 +2784,22 @@ void MainWindow::doDiscChange(CDVD_SourceType source, const QString& path)
{
const auto lock = pauseAndLockVM();

// Check if memcard is busy, deny request if so
if (!GSDumpReplayer::IsReplayingDump() && MemcardBusy::IsBusy())
{
VMLock lock(pauseAndLockVM());

QMessageBox msgbox(lock.getDialogParent());
msgbox.setIcon(QMessageBox::Warning);
msgbox.setWindowTitle(tr("WARNING: Memory Card Busy"));
msgbox.setText(tr("WARNING: Your memory card is still writing data. Shutting down now will IRREVERSIBLY DESTORY YOUR MEMORY CARD. It is strongly recommended to resume your game and let it finish saving.\n\nDo you wish to shutdown anyways and IRREVERSIBLY DESTROY YOUR MEMORY CARD?"));
msgbox.addButton(QMessageBox::Yes);
msgbox.addButton(QMessageBox::No);
msgbox.setDefaultButton(QMessageBox::No);
if (msgbox.exec() != QMessageBox::Yes)
return;
}

bool reset_system = false;
if (!m_was_disc_change_request)
{
Expand Down
1 change: 1 addition & 0 deletions pcsx2-qt/MainWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ public Q_SLOTS:
void reportError(const QString& title, const QString& message);
bool confirmMessage(const QString& title, const QString& message);
void runOnUIThread(const std::function<void()>& func);
void requestReset();
bool requestShutdown(bool allow_confirm = true, bool allow_save_to_state = true, bool default_save_to_state = true);
void requestExit(bool allow_confirm = true);
void checkForSettingChanges();
Expand Down
32 changes: 32 additions & 0 deletions pcsx2/VMManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1745,6 +1745,14 @@ bool VMManager::LoadState(const char* filename)
return false;
}

if (MemcardBusy::IsBusy())
{
Host::AddIconOSDMessage("LoadStateFromSlot", ICON_FA_EXCLAMATION_TRIANGLE,
fmt::format(TRANSLATE_FS("VMManager", "Failed to load state (Memory card is busy)")),
Host::OSD_QUICK_DURATION);
return false;
}

// TODO: Save the current state so we don't need to reset.
if (DoLoadState(filename))
return true;
Expand Down Expand Up @@ -1774,13 +1782,29 @@ bool VMManager::LoadStateFromSlot(s32 slot)
return false;
}

if (MemcardBusy::IsBusy())
{
Host::AddIconOSDMessage("LoadStateFromSlot", ICON_FA_EXCLAMATION_TRIANGLE,
fmt::format(TRANSLATE_FS("VMManager", "Failed to load state from slot {} (Memory card is busy)"), slot),
Host::OSD_QUICK_DURATION);
return false;
}

Host::AddIconOSDMessage("LoadStateFromSlot", ICON_FA_FOLDER_OPEN,
fmt::format(TRANSLATE_FS("VMManager", "Loading state from slot {}..."), slot), Host::OSD_QUICK_DURATION);
return DoLoadState(filename.c_str());
}

bool VMManager::SaveState(const char* filename, bool zip_on_thread, bool backup_old_state)
{
if (MemcardBusy::IsBusy())
{
Host::AddIconOSDMessage("LoadStateFromSlot", ICON_FA_EXCLAMATION_TRIANGLE,
fmt::format(TRANSLATE_FS("VMManager", "Failed to save state (Memory card is busy)")),
Host::OSD_QUICK_DURATION);
return false;
}

return DoSaveState(filename, -1, zip_on_thread, backup_old_state);
}

Expand All @@ -1790,6 +1814,14 @@ bool VMManager::SaveStateToSlot(s32 slot, bool zip_on_thread)
if (filename.empty())
return false;

if (MemcardBusy::IsBusy())
{
Host::AddIconOSDMessage("LoadStateFromSlot", ICON_FA_EXCLAMATION_TRIANGLE,
fmt::format(TRANSLATE_FS("VMManager", "Failed to save state to slot {} (Memory card is busy)"), slot),
Host::OSD_QUICK_DURATION);
return false;
}

// if it takes more than a minute.. well.. wtf.
Host::AddIconOSDMessage(fmt::format("SaveStateSlot{}", slot), ICON_FA_SAVE,
fmt::format(TRANSLATE_FS("VMManager", "Saving state to slot {}..."), slot), 60.0f);
Expand Down

0 comments on commit cd665d5

Please sign in to comment.