mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-30 09:35:40 +00:00
CommonHostInterface: Add undo load state feature
This commit is contained in:
parent
af7dc40f5f
commit
762ab3ff43
|
@ -993,6 +993,9 @@ void QtHostInterface::populateSaveStateMenus(const char* game_code, QMenu* load_
|
|||
|
||||
loadState(path);
|
||||
});
|
||||
QAction* load_from_state = load_menu->addAction(tr("Undo Load State"));
|
||||
load_from_state->setEnabled(CanUndoLoadState());
|
||||
connect(load_from_state, &QAction::triggered, this, &QtHostInterface::undoLoadState);
|
||||
load_menu->addSeparator();
|
||||
|
||||
connect(save_menu->addAction(tr("Save To File...")), &QAction::triggered, [this]() {
|
||||
|
@ -1341,6 +1344,17 @@ void QtHostInterface::saveState(bool global, qint32 slot, bool block_until_done
|
|||
SaveState(global, slot);
|
||||
}
|
||||
|
||||
void QtHostInterface::undoLoadState()
|
||||
{
|
||||
if (!isOnWorkerThread())
|
||||
{
|
||||
QMetaObject::invokeMethod(this, "undoLoadState", Qt::QueuedConnection);
|
||||
return;
|
||||
}
|
||||
|
||||
UndoLoadState();
|
||||
}
|
||||
|
||||
void QtHostInterface::setAudioOutputVolume(int volume, int fast_forward_volume)
|
||||
{
|
||||
if (!isOnWorkerThread())
|
||||
|
|
|
@ -165,6 +165,7 @@ public Q_SLOTS:
|
|||
void loadState(bool global, qint32 slot);
|
||||
void saveState(const QString& filename, bool block_until_done = false);
|
||||
void saveState(bool global, qint32 slot, bool block_until_done = false);
|
||||
void undoLoadState();
|
||||
void setAudioOutputVolume(int volume, int fast_forward_volume);
|
||||
void setAudioOutputMuted(bool muted);
|
||||
void startDumpingAudio();
|
||||
|
|
|
@ -215,6 +215,7 @@ bool CommonHostInterface::BootSystem(std::shared_ptr<SystemBootParameters> param
|
|||
|
||||
void CommonHostInterface::DestroySystem()
|
||||
{
|
||||
m_undo_load_state.reset();
|
||||
SetTimerResolutionIncreased(false);
|
||||
m_save_state_selector_ui->Close();
|
||||
m_display->SetPostProcessingChain({});
|
||||
|
@ -700,9 +701,57 @@ void CommonHostInterface::UpdateControllerInterface()
|
|||
}
|
||||
}
|
||||
|
||||
bool CommonHostInterface::UndoLoadState()
|
||||
{
|
||||
if (!m_undo_load_state)
|
||||
return false;
|
||||
|
||||
Assert(System::IsValid());
|
||||
|
||||
m_undo_load_state->SeekAbsolute(0);
|
||||
if (!System::LoadState(m_undo_load_state.get()))
|
||||
{
|
||||
ReportError("Failed to load undo state, resetting system.");
|
||||
m_undo_load_state.reset();
|
||||
ResetSystem();
|
||||
return false;
|
||||
}
|
||||
|
||||
System::ResetPerformanceCounters();
|
||||
System::ResetThrottler();
|
||||
|
||||
#ifdef WITH_CHEEVOS
|
||||
Cheevos::Reset();
|
||||
#endif
|
||||
|
||||
Log_InfoPrintf("Loaded undo save state.");
|
||||
m_undo_load_state.reset();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CommonHostInterface::SaveUndoLoadState()
|
||||
{
|
||||
if (m_undo_load_state)
|
||||
m_undo_load_state.reset();
|
||||
|
||||
m_undo_load_state = ByteStream_CreateGrowableMemoryStream(nullptr, System::MAX_SAVE_STATE_SIZE);
|
||||
if (!System::SaveState(m_undo_load_state.get(), 0))
|
||||
{
|
||||
AddOSDMessage(TranslateStdString("OSDMessage", "Failed to save undo load state."), 15.0f);
|
||||
m_undo_load_state.reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
Log_InfoPrintf("Saved undo load state: % " PRIu64 " bytes", m_undo_load_state->GetSize());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CommonHostInterface::LoadState(const char* filename)
|
||||
{
|
||||
const bool system_was_valid = System::IsValid();
|
||||
if (system_was_valid)
|
||||
SaveUndoLoadState();
|
||||
|
||||
const bool result = HostInterface::LoadState(filename);
|
||||
if (system_was_valid || !result)
|
||||
{
|
||||
|
@ -711,6 +760,9 @@ bool CommonHostInterface::LoadState(const char* filename)
|
|||
#endif
|
||||
}
|
||||
|
||||
if (!result && CanUndoLoadState())
|
||||
UndoLoadState();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -2320,6 +2372,12 @@ void CommonHostInterface::RegisterSaveStateHotkeys()
|
|||
m_save_state_selector_ui->SelectNextSlot();
|
||||
});
|
||||
|
||||
RegisterHotkey(StaticString(TRANSLATABLE("Hotkeys", "Save States")), StaticString("UndoLoadState"),
|
||||
StaticString(TRANSLATABLE("Hotkeys", "Undo Load State")), [this](bool pressed) {
|
||||
if (pressed)
|
||||
UndoLoadState();
|
||||
});
|
||||
|
||||
for (u32 slot = 1; slot <= PER_GAME_SAVE_STATE_SLOTS; slot++)
|
||||
{
|
||||
RegisterHotkey(StaticString(TRANSLATABLE("Hotkeys", "Save States")),
|
||||
|
|
|
@ -155,6 +155,9 @@ public:
|
|||
/// Returns true if the fullscreen UI is enabled.
|
||||
ALWAYS_INLINE bool IsFullscreenUIEnabled() const { return m_fullscreen_ui_enabled; }
|
||||
|
||||
/// Returns true if an undo load state exists.
|
||||
ALWAYS_INLINE bool CanUndoLoadState() const { return static_cast<bool>(m_undo_load_state); }
|
||||
|
||||
/// Parses command line parameters for all frontends.
|
||||
bool ParseCommandLineParameters(int argc, char* argv[], std::unique_ptr<SystemBootParameters>* out_boot_params);
|
||||
|
||||
|
@ -176,6 +179,9 @@ public:
|
|||
/// Powers off the system, optionally saving the resume state.
|
||||
void PowerOffSystem(bool save_resume_state);
|
||||
|
||||
/// Undoes a load state, i.e. restores the state prior to the load.
|
||||
bool UndoLoadState();
|
||||
|
||||
/// Loads state from the specified filename.
|
||||
bool LoadState(const char* filename);
|
||||
|
||||
|
@ -352,6 +358,9 @@ protected:
|
|||
/// Executes per-frame tasks such as controller polling.
|
||||
virtual void PollAndUpdate();
|
||||
|
||||
/// Saves the undo load state, so it can be restored.
|
||||
bool SaveUndoLoadState();
|
||||
|
||||
virtual std::unique_ptr<AudioStream> CreateAudioStream(AudioBackend backend) override;
|
||||
virtual s32 GetAudioOutputVolume() const override;
|
||||
virtual void UpdateControllerInterface();
|
||||
|
@ -548,6 +557,9 @@ private:
|
|||
};
|
||||
std::vector<ControllerAutoFireState> m_controller_autofires;
|
||||
|
||||
// temporary save state, created when loading, used to undo load state
|
||||
std::unique_ptr<ByteStream> m_undo_load_state;
|
||||
|
||||
#ifdef WITH_DISCORD_PRESENCE
|
||||
// discord rich presence
|
||||
bool m_discord_presence_enabled = false;
|
||||
|
|
Loading…
Reference in a new issue