mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-27 08:05:41 +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);
|
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();
|
load_menu->addSeparator();
|
||||||
|
|
||||||
connect(save_menu->addAction(tr("Save To File...")), &QAction::triggered, [this]() {
|
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);
|
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)
|
void QtHostInterface::setAudioOutputVolume(int volume, int fast_forward_volume)
|
||||||
{
|
{
|
||||||
if (!isOnWorkerThread())
|
if (!isOnWorkerThread())
|
||||||
|
|
|
@ -165,6 +165,7 @@ public Q_SLOTS:
|
||||||
void loadState(bool global, qint32 slot);
|
void loadState(bool global, qint32 slot);
|
||||||
void saveState(const QString& filename, bool block_until_done = false);
|
void saveState(const QString& filename, bool block_until_done = false);
|
||||||
void saveState(bool global, qint32 slot, 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 setAudioOutputVolume(int volume, int fast_forward_volume);
|
||||||
void setAudioOutputMuted(bool muted);
|
void setAudioOutputMuted(bool muted);
|
||||||
void startDumpingAudio();
|
void startDumpingAudio();
|
||||||
|
|
|
@ -215,6 +215,7 @@ bool CommonHostInterface::BootSystem(std::shared_ptr<SystemBootParameters> param
|
||||||
|
|
||||||
void CommonHostInterface::DestroySystem()
|
void CommonHostInterface::DestroySystem()
|
||||||
{
|
{
|
||||||
|
m_undo_load_state.reset();
|
||||||
SetTimerResolutionIncreased(false);
|
SetTimerResolutionIncreased(false);
|
||||||
m_save_state_selector_ui->Close();
|
m_save_state_selector_ui->Close();
|
||||||
m_display->SetPostProcessingChain({});
|
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)
|
bool CommonHostInterface::LoadState(const char* filename)
|
||||||
{
|
{
|
||||||
const bool system_was_valid = System::IsValid();
|
const bool system_was_valid = System::IsValid();
|
||||||
|
if (system_was_valid)
|
||||||
|
SaveUndoLoadState();
|
||||||
|
|
||||||
const bool result = HostInterface::LoadState(filename);
|
const bool result = HostInterface::LoadState(filename);
|
||||||
if (system_was_valid || !result)
|
if (system_was_valid || !result)
|
||||||
{
|
{
|
||||||
|
@ -711,6 +760,9 @@ bool CommonHostInterface::LoadState(const char* filename)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!result && CanUndoLoadState())
|
||||||
|
UndoLoadState();
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2320,6 +2372,12 @@ void CommonHostInterface::RegisterSaveStateHotkeys()
|
||||||
m_save_state_selector_ui->SelectNextSlot();
|
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++)
|
for (u32 slot = 1; slot <= PER_GAME_SAVE_STATE_SLOTS; slot++)
|
||||||
{
|
{
|
||||||
RegisterHotkey(StaticString(TRANSLATABLE("Hotkeys", "Save States")),
|
RegisterHotkey(StaticString(TRANSLATABLE("Hotkeys", "Save States")),
|
||||||
|
|
|
@ -155,6 +155,9 @@ public:
|
||||||
/// Returns true if the fullscreen UI is enabled.
|
/// Returns true if the fullscreen UI is enabled.
|
||||||
ALWAYS_INLINE bool IsFullscreenUIEnabled() const { return m_fullscreen_ui_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.
|
/// Parses command line parameters for all frontends.
|
||||||
bool ParseCommandLineParameters(int argc, char* argv[], std::unique_ptr<SystemBootParameters>* out_boot_params);
|
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.
|
/// Powers off the system, optionally saving the resume state.
|
||||||
void PowerOffSystem(bool save_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.
|
/// Loads state from the specified filename.
|
||||||
bool LoadState(const char* filename);
|
bool LoadState(const char* filename);
|
||||||
|
|
||||||
|
@ -352,6 +358,9 @@ protected:
|
||||||
/// Executes per-frame tasks such as controller polling.
|
/// Executes per-frame tasks such as controller polling.
|
||||||
virtual void PollAndUpdate();
|
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 std::unique_ptr<AudioStream> CreateAudioStream(AudioBackend backend) override;
|
||||||
virtual s32 GetAudioOutputVolume() const override;
|
virtual s32 GetAudioOutputVolume() const override;
|
||||||
virtual void UpdateControllerInterface();
|
virtual void UpdateControllerInterface();
|
||||||
|
@ -548,6 +557,9 @@ private:
|
||||||
};
|
};
|
||||||
std::vector<ControllerAutoFireState> m_controller_autofires;
|
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
|
#ifdef WITH_DISCORD_PRESENCE
|
||||||
// discord rich presence
|
// discord rich presence
|
||||||
bool m_discord_presence_enabled = false;
|
bool m_discord_presence_enabled = false;
|
||||||
|
|
Loading…
Reference in a new issue