From 117ffaeb60ffc40ab6809a0214b93c4d99a08398 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 13 Apr 2013 01:13:28 -0700 Subject: [PATCH 1/2] Include the git version in savestates. This way we can provide better warnings when it fails to load. --- Core/HLE/sceKernel.cpp | 14 ++++++++++---- Core/SaveState.cpp | 13 +++++++------ Core/SaveState.h | 4 ++-- 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/Core/HLE/sceKernel.cpp b/Core/HLE/sceKernel.cpp index ae8b9e4763..b7372f15bf 100644 --- a/Core/HLE/sceKernel.cpp +++ b/Core/HLE/sceKernel.cpp @@ -15,10 +15,11 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include "HLE.h" -#include "../MIPS/MIPS.h" -#include "../MIPS/MIPSCodeUtils.h" -#include "../MIPS/MIPSInt.h" +#include "Core/Config.h" +#include "Core/HLE/HLE.h" +#include "Core/MIPS/MIPS.h" +#include "Core/MIPS/MIPSCodeUtils.h" +#include "Core/MIPS/MIPSInt.h" #include "Common/LogManager.h" #include "../FileSystems/FileSystem.h" @@ -161,6 +162,11 @@ void __KernelShutdown() void __KernelDoState(PointerWrap &p) { + std::string git_version = PPSSPP_GIT_VERSION; + p.Do(git_version); + if (git_version != PPSSPP_GIT_VERSION) + WARN_LOG(HLE, "Warning: this savestate was generated by a different version of PPSSPP. It may not load properly."); + p.Do(kernelRunning); kernelObjects.DoState(p); p.DoMarker("KernelObjects"); diff --git a/Core/SaveState.cpp b/Core/SaveState.cpp index a320c4e70b..fcc9d19f1a 100644 --- a/Core/SaveState.cpp +++ b/Core/SaveState.cpp @@ -111,6 +111,11 @@ namespace SaveState Enqueue(Operation(SAVESTATE_SAVE, filename, callback, cbUserData)); } + void Verify(Callback callback, void *cbUserData) + { + Enqueue(Operation(SAVESTATE_VERIFY, std::string(""), callback, cbUserData)); + } + // Slot utilities @@ -148,9 +153,10 @@ namespace SaveState (*callback)(false, cbUserData); } - void HasSaveInSlot(int slot) + bool HasSaveInSlot(int slot) { std::string fn = GenerateSaveSlotFilename(slot); + return File::Exists(fn); } bool operator < (const tm &t1, const tm &t2) { @@ -186,11 +192,6 @@ namespace SaveState } - void Verify(Callback callback, void *cbUserData) - { - Enqueue(Operation(SAVESTATE_VERIFY, std::string(""), callback, cbUserData)); - } - std::vector Flush() { std::lock_guard guard(mutex); diff --git a/Core/SaveState.h b/Core/SaveState.h index 7ca6d143b0..8023756ecc 100644 --- a/Core/SaveState.h +++ b/Core/SaveState.h @@ -24,14 +24,14 @@ namespace SaveState typedef void (*Callback)(bool status, void *cbUserData); // TODO: Better place for this? - const int REVISION = 1; + const int REVISION = 2; const int SAVESTATESLOTS = 4; void Init(); void SaveSlot(int slot, Callback callback, void *cbUserData = 0); void LoadSlot(int slot, Callback callback, void *cbUserData = 0); - void HasSaveInSlot(int slot); + bool HasSaveInSlot(int slot); int GetNewestSlot(); // Load the specified file into the current state (async.) From fe97fd6fc5aba1bbe0d969a381ca22e9ebb82b84 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 13 Apr 2013 01:39:17 -0700 Subject: [PATCH 2/2] Add better savestate error handling. Aborts when it can't load. --- Common/ChunkFile.h | 24 +++++++++++++++++++----- Core/FileSystems/DirectoryFileSystem.cpp | 2 ++ Core/FileSystems/MetaFileSystem.cpp | 1 + Core/HLE/sceKernel.cpp | 7 +++++++ Core/HLE/sceKernelInterrupt.cpp | 1 + Core/HLE/sceKernelThread.cpp | 7 ++++++- Windows/WndMainWindow.cpp | 3 +-- 7 files changed, 37 insertions(+), 8 deletions(-) diff --git a/Common/ChunkFile.h b/Common/ChunkFile.h index 1fbf453adf..9edc88a850 100644 --- a/Common/ChunkFile.h +++ b/Common/ChunkFile.h @@ -115,16 +115,30 @@ public: MODE_VERIFY, // compare }; + enum Error { + ERROR_NONE = 0, + ERROR_WARNING = 1, + ERROR_FAILURE = 2, + }; + u8 **ptr; Mode mode; + Error error; public: - PointerWrap(u8 **ptr_, Mode mode_) : ptr(ptr_), mode(mode_) {} - PointerWrap(unsigned char **ptr_, int mode_) : ptr((u8**)ptr_), mode((Mode)mode_) {} + PointerWrap(u8 **ptr_, Mode mode_) : ptr(ptr_), mode(mode_), error(ERROR_NONE) {} + PointerWrap(unsigned char **ptr_, int mode_) : ptr((u8**)ptr_), mode((Mode)mode_), error(ERROR_NONE) {} void SetMode(Mode mode_) {mode = mode_;} Mode GetMode() const {return mode;} u8 **GetPPtr() {return ptr;} + void SetError(Error error_) + { + if (error < error_) + error = error_; + if (error != ERROR_NONE) + mode = PointerWrap::MODE_MEASURE; + } void DoVoid(void *data, int size) { @@ -556,7 +570,7 @@ public: if(mode == PointerWrap::MODE_READ && cookie != arbitraryNumber) { PanicAlertT("Error: After \"%s\", found %d (0x%X) instead of save marker %d (0x%X). Aborting savestate load...", prevName, cookie, cookie, arbitraryNumber, arbitraryNumber); - mode = PointerWrap::MODE_MEASURE; + SetError(ERROR_FAILURE); } } }; @@ -642,7 +656,7 @@ public: delete[] buf; INFO_LOG(COMMON, "ChunkReader: Done loading %s" , _rFilename.c_str()); - return true; + return p.error != p.ERROR_FAILURE; } // Save file template @@ -712,7 +726,7 @@ public: INFO_LOG(COMMON,"ChunkReader: Done writing %s", _rFilename.c_str()); - return true; + return p.error != p.ERROR_FAILURE; } template diff --git a/Core/FileSystems/DirectoryFileSystem.cpp b/Core/FileSystems/DirectoryFileSystem.cpp index bc9aeed86d..9013f87897 100644 --- a/Core/FileSystems/DirectoryFileSystem.cpp +++ b/Core/FileSystems/DirectoryFileSystem.cpp @@ -611,6 +611,7 @@ std::vector DirectoryFileSystem::GetDirListing(std::string path) { void DirectoryFileSystem::DoState(PointerWrap &p) { if (!entries.empty()) { + p.SetError(p.ERROR_WARNING); ERROR_LOG(FILESYS, "FIXME: Open files during savestate, could go badly."); } } @@ -761,6 +762,7 @@ std::vector VFSFileSystem::GetDirListing(std::string path) { void VFSFileSystem::DoState(PointerWrap &p) { if (!entries.empty()) { + p.SetError(p.ERROR_WARNING); ERROR_LOG(FILESYS, "FIXME: Open files during savestate, could go badly."); } } diff --git a/Core/FileSystems/MetaFileSystem.cpp b/Core/FileSystems/MetaFileSystem.cpp index 7c971264ed..3f4f7e51a5 100644 --- a/Core/FileSystems/MetaFileSystem.cpp +++ b/Core/FileSystems/MetaFileSystem.cpp @@ -422,6 +422,7 @@ void MetaFileSystem::DoState(PointerWrap &p) p.Do(n); if (n != (u32) fileSystems.size()) { + p.SetError(p.ERROR_FAILURE); ERROR_LOG(FILESYS, "Savestate failure: number of filesystems doesn't match."); return; } diff --git a/Core/HLE/sceKernel.cpp b/Core/HLE/sceKernel.cpp index b7372f15bf..4c05537e17 100644 --- a/Core/HLE/sceKernel.cpp +++ b/Core/HLE/sceKernel.cpp @@ -165,7 +165,10 @@ void __KernelDoState(PointerWrap &p) std::string git_version = PPSSPP_GIT_VERSION; p.Do(git_version); if (git_version != PPSSPP_GIT_VERSION) + { + p.SetError(p.ERROR_WARNING); WARN_LOG(HLE, "Warning: this savestate was generated by a different version of PPSSPP. It may not load properly."); + } p.Do(kernelRunning); kernelObjects.DoState(p); @@ -462,7 +465,11 @@ void KernelObjectPool::DoState(PointerWrap &p) p.Do(_maxCount); if (_maxCount != maxCount) + { + p.SetError(p.ERROR_FAILURE); ERROR_LOG(HLE, "Unable to load state: different kernel object storage."); + return; + } if (p.mode == p.MODE_READ) { diff --git a/Core/HLE/sceKernelInterrupt.cpp b/Core/HLE/sceKernelInterrupt.cpp index 6b9e53536d..e026962fc9 100644 --- a/Core/HLE/sceKernelInterrupt.cpp +++ b/Core/HLE/sceKernelInterrupt.cpp @@ -227,6 +227,7 @@ void __InterruptsDoState(PointerWrap &p) p.Do(numInterrupts); if (numInterrupts != PSP_NUMBER_INTERRUPTS) { + p.SetError(p.ERROR_FAILURE); ERROR_LOG(HLE, "Savestate failure: wrong number of interrupts, can't load."); return; } diff --git a/Core/HLE/sceKernelThread.cpp b/Core/HLE/sceKernelThread.cpp index b80d310b05..5d43d9c1d6 100644 --- a/Core/HLE/sceKernelThread.cpp +++ b/Core/HLE/sceKernelThread.cpp @@ -405,7 +405,11 @@ public: u32 numCallbacks = THREAD_CALLBACK_NUM_TYPES; p.Do(numCallbacks); if (numCallbacks != THREAD_CALLBACK_NUM_TYPES) - ERROR_LOG(HLE, "Unable to load state: different kernel object storage."); + { + p.SetError(p.ERROR_FAILURE); + ERROR_LOG(HLE, "Unable to load state: different thread callback storage."); + return; + } for (size_t i = 0; i < THREAD_CALLBACK_NUM_TYPES; ++i) { @@ -581,6 +585,7 @@ struct ThreadQueueList p.Do(numQueues); if (numQueues != NUM_QUEUES) { + p.SetError(p.ERROR_FAILURE); ERROR_LOG(HLE, "Savestate loading error: invalid data"); return; } diff --git a/Windows/WndMainWindow.cpp b/Windows/WndMainWindow.cpp index 3b2c6a2917..19ee41f086 100644 --- a/Windows/WndMainWindow.cpp +++ b/Windows/WndMainWindow.cpp @@ -879,9 +879,8 @@ namespace MainWindow void SaveStateActionFinished(bool result, void *userdata) { - // TODO: Improve messaging? if (!result) - MessageBox(0, "Savestate failure. Please try again later.", "Sorry", MB_OK); + MessageBox(0, "Savestate failure. Using savestates between different PPSSPP versions is not supported.", "Sorry", MB_OK); SetCursor(LoadCursor(0, IDC_ARROW)); }