mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-02-04 12:37:08 +00:00
Decouple save states from UI.
It's the UI's job to decide how and what things are displayed, not Core's. This also reduces reasons for linkage issues.
This commit is contained in:
parent
2862253f12
commit
27d135d48a
@ -43,7 +43,6 @@
|
||||
#include "Core/MIPS/JitCommon/JitBlockCache.h"
|
||||
#include "HW/MemoryStick.h"
|
||||
#include "GPU/GPUState.h"
|
||||
#include "UI/OnScreenDisplay.h"
|
||||
|
||||
namespace SaveState
|
||||
{
|
||||
@ -389,9 +388,8 @@ namespace SaveState
|
||||
Load(fn, callback, cbUserData);
|
||||
} else {
|
||||
I18NCategory *sy = GetI18NCategory("System");
|
||||
osm.Show(sy->T("Failed to load state. Error in the file system."), 2.0);
|
||||
if (callback)
|
||||
callback(false, cbUserData);
|
||||
callback(false, sy->T("Failed to load state. Error in the file system."), cbUserData);
|
||||
}
|
||||
}
|
||||
|
||||
@ -400,7 +398,7 @@ namespace SaveState
|
||||
std::string fn = GenerateSaveSlotFilename(gameFilename, slot, STATE_EXTENSION);
|
||||
std::string shot = GenerateSaveSlotFilename(gameFilename, slot, SCREENSHOT_EXTENSION);
|
||||
if (!fn.empty()) {
|
||||
auto renameCallback = [=](bool status, void *data) {
|
||||
auto renameCallback = [=](bool status, const std::string &message, void *data) {
|
||||
if (status) {
|
||||
if (File::Exists(fn)) {
|
||||
File::Delete(fn);
|
||||
@ -408,17 +406,16 @@ namespace SaveState
|
||||
File::Rename(fn + ".tmp", fn);
|
||||
}
|
||||
if (callback) {
|
||||
callback(status, data);
|
||||
callback(status, message, data);
|
||||
}
|
||||
};
|
||||
// Let's also create a screenshot.
|
||||
SaveScreenshot(shot, Callback(), 0);
|
||||
Save(fn + ".tmp", renameCallback, cbUserData);
|
||||
} else {
|
||||
I18NCategory *sc = GetI18NCategory("Screen");
|
||||
osm.Show("Failed to save state. Error in the file system.", 2.0);
|
||||
I18NCategory *sy = GetI18NCategory("System");
|
||||
if (callback)
|
||||
callback(false, cbUserData);
|
||||
callback(false, sy->T("Failed to save state. Error in the file system."), cbUserData);
|
||||
}
|
||||
}
|
||||
|
||||
@ -564,6 +561,7 @@ namespace SaveState
|
||||
Operation &op = operations[i];
|
||||
CChunkFileReader::Error result;
|
||||
bool callbackResult;
|
||||
std::string callbackMessage;
|
||||
std::string reason;
|
||||
|
||||
I18NCategory *sc = GetI18NCategory("Screen");
|
||||
@ -580,16 +578,16 @@ namespace SaveState
|
||||
INFO_LOG(COMMON, "Loading state from %s", op.filename.c_str());
|
||||
result = CChunkFileReader::Load(op.filename, PPSSPP_GIT_VERSION, state, &reason);
|
||||
if (result == CChunkFileReader::ERROR_NONE) {
|
||||
osm.Show(sc->T("Loaded State"), 2.0);
|
||||
callbackMessage = sc->T("Loaded State");
|
||||
callbackResult = true;
|
||||
hasLoadedState = true;
|
||||
} else if (result == CChunkFileReader::ERROR_BROKEN_STATE) {
|
||||
HandleFailure();
|
||||
osm.Show(i18nLoadFailure, 2.0);
|
||||
callbackMessage = i18nLoadFailure;
|
||||
ERROR_LOG(COMMON, "Load state failure: %s", reason.c_str());
|
||||
callbackResult = false;
|
||||
} else {
|
||||
osm.Show(sc->T(reason.c_str(), i18nLoadFailure), 2.0);
|
||||
callbackMessage = sc->T(reason.c_str(), i18nLoadFailure);
|
||||
callbackResult = false;
|
||||
}
|
||||
break;
|
||||
@ -598,45 +596,48 @@ namespace SaveState
|
||||
INFO_LOG(COMMON, "Saving state to %s", op.filename.c_str());
|
||||
result = CChunkFileReader::Save(op.filename, g_paramSFO.GetValueString("TITLE"), PPSSPP_GIT_VERSION, state);
|
||||
if (result == CChunkFileReader::ERROR_NONE) {
|
||||
|
||||
osm.Show(sc->T("Saved State"), 2.0);
|
||||
callbackMessage = sc->T("Saved State");
|
||||
callbackResult = true;
|
||||
} else if (result == CChunkFileReader::ERROR_BROKEN_STATE) {
|
||||
HandleFailure();
|
||||
osm.Show(i18nSaveFailure, 2.0);
|
||||
callbackMessage = i18nSaveFailure;
|
||||
ERROR_LOG(COMMON, "Save state failure: %s", reason.c_str());
|
||||
callbackResult = false;
|
||||
} else {
|
||||
osm.Show(i18nSaveFailure, 2.0);
|
||||
callbackMessage = i18nSaveFailure;
|
||||
callbackResult = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case SAVESTATE_VERIFY:
|
||||
INFO_LOG(COMMON, "Verifying save state system");
|
||||
callbackResult = CChunkFileReader::Verify(state) == CChunkFileReader::ERROR_NONE;
|
||||
if (callbackResult) {
|
||||
INFO_LOG(COMMON, "Verified save state system");
|
||||
} else {
|
||||
ERROR_LOG(COMMON, "Save state system verification failed");
|
||||
}
|
||||
break;
|
||||
|
||||
case SAVESTATE_REWIND:
|
||||
INFO_LOG(COMMON, "Rewinding to recent savestate snapshot");
|
||||
result = rewindStates.Restore();
|
||||
if (result == CChunkFileReader::ERROR_NONE) {
|
||||
osm.Show(sc->T("Loaded State"), 2.0);
|
||||
callbackMessage = sc->T("Loaded State");
|
||||
callbackResult = true;
|
||||
hasLoadedState = true;
|
||||
} else if (result == CChunkFileReader::ERROR_BROKEN_STATE) {
|
||||
// Cripes. Good news is, we might have more. Let's try those too, better than a reset.
|
||||
if (HandleFailure()) {
|
||||
// Well, we did rewind, even if too much...
|
||||
osm.Show(sc->T("Loaded State"), 2.0);
|
||||
callbackMessage = sc->T("Loaded State");
|
||||
callbackResult = true;
|
||||
hasLoadedState = true;
|
||||
} else {
|
||||
osm.Show(i18nLoadFailure, 2.0);
|
||||
callbackMessage = i18nLoadFailure;
|
||||
callbackResult = false;
|
||||
}
|
||||
} else {
|
||||
osm.Show(i18nLoadFailure, 2.0);
|
||||
callbackMessage = i18nLoadFailure;
|
||||
callbackResult = false;
|
||||
}
|
||||
break;
|
||||
@ -655,7 +656,7 @@ namespace SaveState
|
||||
}
|
||||
|
||||
if (op.callback)
|
||||
op.callback(callbackResult, op.cbUserData);
|
||||
op.callback(callbackResult, callbackMessage, op.cbUserData);
|
||||
}
|
||||
if (operations.size()) {
|
||||
// Avoid triggering frame skipping due to slowdown
|
||||
|
@ -23,7 +23,7 @@
|
||||
|
||||
namespace SaveState
|
||||
{
|
||||
typedef std::function<void(bool status, void *cbUserData)> Callback;
|
||||
typedef std::function<void(bool status, const std::string &message, void *cbUserData)> Callback;
|
||||
|
||||
static const int NUM_SLOTS = 5;
|
||||
static const char *STATE_EXTENSION = "ppst";
|
||||
|
@ -178,7 +178,7 @@ void MainWindow::closeAct()
|
||||
SetGameTitle("");
|
||||
}
|
||||
|
||||
void SaveStateActionFinished(bool result, void *userdata)
|
||||
void SaveStateActionFinished(bool result, const std::string &message, void *userdata)
|
||||
{
|
||||
// TODO: Improve messaging?
|
||||
if (!result)
|
||||
|
@ -218,7 +218,14 @@ void EmuScreen::dialogFinished(const Screen *dialog, DialogResult result) {
|
||||
RecreateViews();
|
||||
}
|
||||
|
||||
static void AfterStateLoad(bool success, void *ignored) {
|
||||
static void AfterSaveStateAction(bool success, const std::string &message, void *) {
|
||||
if (!message.empty()) {
|
||||
osm.Show(message, 2.0);
|
||||
}
|
||||
}
|
||||
|
||||
static void AfterStateBoot(bool success, const std::string &message, void *ignored) {
|
||||
AfterSaveStateAction(success, message, ignored);
|
||||
Core_EnableStepping(false);
|
||||
host->UpdateDisassembly();
|
||||
}
|
||||
@ -252,7 +259,7 @@ void EmuScreen::sendMessage(const char *message, const char *value) {
|
||||
} else if (!strcmp(message, "boot")) {
|
||||
const char *ext = strrchr(value, '.');
|
||||
if (ext != nullptr && !strcmp(ext, ".ppst")) {
|
||||
SaveState::Load(value, &AfterStateLoad);
|
||||
SaveState::Load(value, &AfterStateBoot);
|
||||
} else {
|
||||
PSP_Shutdown();
|
||||
bootPending_ = true;
|
||||
@ -385,16 +392,16 @@ void EmuScreen::onVKeyDown(int virtualKeyCode) {
|
||||
|
||||
case VIRTKEY_REWIND:
|
||||
if (SaveState::CanRewind()) {
|
||||
SaveState::Rewind();
|
||||
SaveState::Rewind(&AfterSaveStateAction);
|
||||
} else {
|
||||
osm.Show(sc->T("norewind", "No rewind save states available"), 2.0);
|
||||
}
|
||||
break;
|
||||
case VIRTKEY_SAVE_STATE:
|
||||
SaveState::SaveSlot(gamePath_, g_Config.iCurrentStateSlot, SaveState::Callback());
|
||||
SaveState::SaveSlot(gamePath_, g_Config.iCurrentStateSlot, &AfterSaveStateAction);
|
||||
break;
|
||||
case VIRTKEY_LOAD_STATE:
|
||||
SaveState::LoadSlot(gamePath_, g_Config.iCurrentStateSlot, SaveState::Callback());
|
||||
SaveState::LoadSlot(gamePath_, g_Config.iCurrentStateSlot, &AfterSaveStateAction);
|
||||
break;
|
||||
case VIRTKEY_NEXT_SLOT:
|
||||
SaveState::NextSlot();
|
||||
@ -1024,7 +1031,7 @@ void EmuScreen::autoLoad() {
|
||||
//check if save state has save, if so, load
|
||||
int lastSlot = SaveState::GetNewestSlot(gamePath_);
|
||||
if (g_Config.bEnableAutoLoad && lastSlot != -1) {
|
||||
SaveState::LoadSlot(gamePath_, lastSlot, SaveState::Callback(), 0);
|
||||
SaveState::LoadSlot(gamePath_, lastSlot, &AfterSaveStateAction);
|
||||
g_Config.iCurrentStateSlot = lastSlot;
|
||||
}
|
||||
}
|
||||
|
@ -489,8 +489,13 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!boot_filename.empty() && stateToLoad != NULL)
|
||||
SaveState::Load(stateToLoad);
|
||||
if (!boot_filename.empty() && stateToLoad != NULL) {
|
||||
SaveState::Load(stateToLoad, [](bool status, const std::string &message, void *) {
|
||||
if (!message.empty()) {
|
||||
osm.Show(message, 2.0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
screenManager = new ScreenManager();
|
||||
if (skipLogo) {
|
||||
|
@ -40,6 +40,7 @@
|
||||
#include "UI/ReportScreen.h"
|
||||
#include "UI/CwCheatScreen.h"
|
||||
#include "UI/MainScreen.h"
|
||||
#include "UI/OnScreenDisplay.h"
|
||||
#include "UI/GameInfoCache.h"
|
||||
|
||||
void AsyncImageFileView::GetContentDimensions(const UIContext &dc, float &w, float &h) const {
|
||||
@ -224,9 +225,15 @@ void SaveSlotView::Draw(UIContext &dc) {
|
||||
UI::LinearLayout::Draw(dc);
|
||||
}
|
||||
|
||||
static void AfterSaveStateAction(bool status, const std::string &message, void *) {
|
||||
if (!message.empty()) {
|
||||
osm.Show(message, 2.0);
|
||||
}
|
||||
}
|
||||
|
||||
UI::EventReturn SaveSlotView::OnLoadState(UI::EventParams &e) {
|
||||
g_Config.iCurrentStateSlot = slot_;
|
||||
SaveState::LoadSlot(gamePath_, slot_, SaveState::Callback(), 0);
|
||||
SaveState::LoadSlot(gamePath_, slot_, &AfterSaveStateAction);
|
||||
UI::EventParams e2;
|
||||
e2.v = this;
|
||||
OnStateLoaded.Trigger(e2);
|
||||
@ -235,7 +242,7 @@ UI::EventReturn SaveSlotView::OnLoadState(UI::EventParams &e) {
|
||||
|
||||
UI::EventReturn SaveSlotView::OnSaveState(UI::EventParams &e) {
|
||||
g_Config.iCurrentStateSlot = slot_;
|
||||
SaveState::SaveSlot(gamePath_, slot_, SaveState::Callback(), 0);
|
||||
SaveState::SaveSlot(gamePath_, slot_, &AfterSaveStateAction);
|
||||
UI::EventParams e2;
|
||||
e2.v = this;
|
||||
OnStateSaved.Trigger(e2);
|
||||
@ -389,7 +396,7 @@ UI::EventReturn GamePauseScreen::OnReportFeedback(UI::EventParams &e) {
|
||||
}
|
||||
|
||||
UI::EventReturn GamePauseScreen::OnRewind(UI::EventParams &e) {
|
||||
SaveState::Rewind(SaveState::Callback(), 0);
|
||||
SaveState::Rewind(&AfterSaveStateAction);
|
||||
|
||||
screenManager()->finishDialog(this, DR_CANCEL);
|
||||
return UI::EVENT_DONE;
|
||||
|
@ -400,7 +400,10 @@ namespace MainWindow {
|
||||
g_Config.iInternalScreenRotation = rotation;
|
||||
}
|
||||
|
||||
static void SaveStateActionFinished(bool result, void *userdata) {
|
||||
static void SaveStateActionFinished(bool result, const std::string &message, void *userdata) {
|
||||
if (!message.empty()) {
|
||||
osm.Show(message, 2.0);
|
||||
}
|
||||
PostMessage(MainWindow::GetHWND(), WM_USER_SAVESTATE_FINISH, 0, 0);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user