mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-01 14:58:14 +00:00
Savestates: Add quicksave/quickload. Add Android UI for savestates. All single slot for now.
This commit is contained in:
1 parent
28684a3ba2
commit
883f61e3dd
25 files changed
+267
-91
No files matched your search
@@ -376,3 +376,11 @@ std::string UriEncode(const std::string & sSrc)
|
||||
delete [] pStart;
|
||||
return sResult;
|
||||
}
|
||||
|
||||
bool StringEndsWith(std::string const &fullString, std::string const &ending) {
|
||||
if (fullString.length() >= ending.length()) {
|
||||
return (0 == fullString.compare (fullString.length() - ending.length(), ending.length(), ending));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -129,4 +129,6 @@ std::string ReplaceAll(std::string result, const std::string& src, const std::st
|
||||
std::string UriDecode(const std::string & sSrc);
|
||||
std::string UriEncode(const std::string & sSrc);
|
||||
|
||||
bool StringEndsWith(std::string const &fullString, std::string const &ending);
|
||||
|
||||
#endif // _STRINGUTIL_H_
|
||||
+1
-2
@@ -59,7 +59,7 @@ void CConfig::Load(const char *iniFileName)
|
||||
graphics->Get("DisplayFramebuffer", &bDisplayFramebuffer, false);
|
||||
graphics->Get("WindowZoom", &iWindowZoom, 1);
|
||||
graphics->Get("BufferedRendering", &bBufferedRendering, true);
|
||||
graphics->Get("HardwareTransform", &bHardwareTransform, false);
|
||||
graphics->Get("HardwareTransform", &bHardwareTransform, true);
|
||||
graphics->Get("LinearFiltering", &bLinearFiltering, false);
|
||||
|
||||
IniFile::Section *sound = iniFile.GetOrCreateSection("Sound");
|
||||
@@ -69,7 +69,6 @@ void CConfig::Load(const char *iniFileName)
|
||||
control->Get("ShowStick", &bShowAnalogStick, false);
|
||||
control->Get("ShowTouchControls", &bShowTouchControls, true);
|
||||
|
||||
|
||||
// Ephemeral settings
|
||||
bDrawWireframe = false;
|
||||
}
|
||||
|
||||
@@ -226,8 +226,8 @@ bool SavedataParam::Save(SceUtilitySavedataParam* param, int saveId)
|
||||
PSPFileInfo sfoInfo = pspFileSystem.GetFileInfo(sfopath);
|
||||
if(sfoInfo.exists) // Read old sfo if exist
|
||||
{
|
||||
u8 *sfoData = new u8[sfoInfo.size];
|
||||
size_t sfoSize = sfoInfo.size;
|
||||
u8 *sfoData = new u8[(size_t)sfoInfo.size];
|
||||
size_t sfoSize = (size_t)sfoInfo.size;
|
||||
if(ReadPSPFile(sfopath,sfoData,sfoSize))
|
||||
{
|
||||
sfoFile.ReadSFO(sfoData,sfoSize);
|
||||
@@ -475,7 +475,7 @@ bool SavedataParam::GetList(SceUtilitySavedataParam *param)
|
||||
if (Memory::IsValidAddress(outputBuffer))
|
||||
{
|
||||
std::string searchString = GetGameName(param)+GetSaveName(param);
|
||||
for(int i = 0; i < allDir.size() && i < maxFile; i++)
|
||||
for (size_t i = 0; i < allDir.size() && i < maxFile; i++)
|
||||
{
|
||||
std::string dirName = allDir[i].name;
|
||||
if(PSPMatch(dirName, searchString))
|
||||
@@ -484,7 +484,7 @@ bool SavedataParam::GetList(SceUtilitySavedataParam *param)
|
||||
}
|
||||
}
|
||||
|
||||
for(int i = 0; i < validDir.size(); i++)
|
||||
for (size_t i = 0; i < validDir.size(); i++)
|
||||
{
|
||||
u32 baseAddr = outputBuffer + (i*72);
|
||||
Memory::Write_U32(0x11FF,baseAddr + 0); // mode
|
||||
@@ -514,7 +514,7 @@ bool SavedataParam::GetFilesList(SceUtilitySavedataParam *param)
|
||||
}
|
||||
|
||||
u32 dataAddr = param->fileListAddr;
|
||||
if(!Memory::IsValidAddress(dataAddr))
|
||||
if (!Memory::IsValidAddress(dataAddr))
|
||||
return false;
|
||||
|
||||
// TODO : Need to be checked against more game
|
||||
@@ -524,7 +524,7 @@ bool SavedataParam::GetFilesList(SceUtilitySavedataParam *param)
|
||||
//for Valkyria2, dataAddr+0 and dataAddr+12 has "5" for 5 files
|
||||
int numFiles = Memory::Read_U32(dataAddr+12);
|
||||
int foundFiles = 0;
|
||||
for(int i = 0; i < numFiles; i++)
|
||||
for (int i = 0; i < numFiles; i++)
|
||||
{
|
||||
// for each file (80 bytes):
|
||||
// u32 mode, u32 ??, u64 size, u64 ctime, u64 ??, u64 atime, u64 ???, u64 mtime, u64 ???
|
||||
@@ -535,7 +535,7 @@ bool SavedataParam::GetFilesList(SceUtilitySavedataParam *param)
|
||||
strncpy(fileName, Memory::GetCharPointer(curFileInfoAddr + 64),16);
|
||||
std::string filePath = savePath + GetGameName(param) + GetSaveName(param) + "/" + fileName;
|
||||
PSPFileInfo info = pspFileSystem.GetFileInfo(filePath);
|
||||
if(info.exists)
|
||||
if (info.exists)
|
||||
{
|
||||
Memory::Write_U32(0x21FF, curFileInfoAddr+0);
|
||||
Memory::Write_U64(info.size, curFileInfoAddr+8);
|
||||
|
||||
@@ -147,7 +147,7 @@ bool ParamSFOData::WriteSFO(u8 **paramsfo, size_t *size)
|
||||
total_size += sizeof(Header);
|
||||
|
||||
// Get size info
|
||||
for(std::map<std::string,ValueData>::iterator it = values.begin(); it != values.end(); it++)
|
||||
for (std::map<std::string,ValueData>::iterator it = values.begin(); it != values.end(); it++)
|
||||
{
|
||||
key_size += it->first.size()+1;
|
||||
data_size += it->second.max_size;
|
||||
@@ -168,29 +168,29 @@ bool ParamSFOData::WriteSFO(u8 **paramsfo, size_t *size)
|
||||
|
||||
u8* data = new u8[total_size];
|
||||
*paramsfo = data;
|
||||
memset(data,0,total_size);
|
||||
memcpy(data,&header,sizeof(Header));
|
||||
memset(data, 0, total_size);
|
||||
memcpy(data, &header, sizeof(Header));
|
||||
|
||||
// Now fill
|
||||
IndexTable *index_ptr = (IndexTable*)(data + sizeof(Header));
|
||||
u8* key_ptr = data + header.key_table_start;
|
||||
u8* data_ptr = data + header.data_table_start;
|
||||
|
||||
for(std::map<std::string,ValueData>::iterator it = values.begin(); it != values.end(); it++)
|
||||
for (std::map<std::string,ValueData>::iterator it = values.begin(); it != values.end(); it++)
|
||||
{
|
||||
u16 offset = (u16)(key_ptr - (data+header.key_table_start));
|
||||
index_ptr->key_table_offset = offset;
|
||||
offset = (u16)(data_ptr - (data+header.data_table_start));
|
||||
index_ptr->data_table_offset = offset;
|
||||
index_ptr->param_max_len = it->second.max_size;
|
||||
if(it->second.type == VT_INT)
|
||||
if (it->second.type == VT_INT)
|
||||
{
|
||||
index_ptr->param_fmt = 0x0404;
|
||||
index_ptr->param_len = 4;
|
||||
|
||||
*(int*)data_ptr = it->second.i_value;
|
||||
}
|
||||
else if(it->second.type == VT_UTF8_SPE)
|
||||
else if (it->second.type == VT_UTF8_SPE)
|
||||
{
|
||||
index_ptr->param_fmt = 0x0004;
|
||||
index_ptr->param_len = it->second.u_size;
|
||||
@@ -198,7 +198,7 @@ bool ParamSFOData::WriteSFO(u8 **paramsfo, size_t *size)
|
||||
memset(data_ptr,0,index_ptr->param_max_len);
|
||||
memcpy(data_ptr,it->second.u_value,index_ptr->param_len);
|
||||
}
|
||||
else if(it->second.type == VT_UTF8)
|
||||
else if (it->second.type == VT_UTF8)
|
||||
{
|
||||
index_ptr->param_fmt = 0x0204;
|
||||
index_ptr->param_len = it->second.s_value.size()+1;
|
||||
|
||||
+2
-1
@@ -33,14 +33,15 @@ public:
|
||||
|
||||
bool ReadSFO(const u8 *paramsfo, size_t size);
|
||||
bool WriteSFO(u8 **paramsfo, size_t *size);
|
||||
private:
|
||||
|
||||
private:
|
||||
enum ValueType
|
||||
{
|
||||
VT_INT,
|
||||
VT_UTF8,
|
||||
VT_UTF8_SPE // raw data in u8
|
||||
};
|
||||
|
||||
class ValueData
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -38,28 +38,32 @@ public:
|
||||
|
||||
class CISOFileBlockDevice : public BlockDevice
|
||||
{
|
||||
public:
|
||||
CISOFileBlockDevice(std::string _filename);
|
||||
~CISOFileBlockDevice();
|
||||
bool ReadBlock(int blockNumber, u8 *outPtr);
|
||||
int GetNumBlocks() { return numBlocks;}
|
||||
|
||||
private:
|
||||
std::string filename;
|
||||
FILE *f;
|
||||
u32 *index;
|
||||
int indexShift;
|
||||
u32 blockSize;
|
||||
int numBlocks;
|
||||
public:
|
||||
CISOFileBlockDevice(std::string _filename);
|
||||
~CISOFileBlockDevice();
|
||||
bool ReadBlock(int blockNumber, u8 *outPtr);
|
||||
int GetNumBlocks() { return numBlocks;}
|
||||
};
|
||||
|
||||
|
||||
class FileBlockDevice : public BlockDevice
|
||||
{
|
||||
std::string filename;
|
||||
FILE *f;
|
||||
size_t filesize;
|
||||
public:
|
||||
FileBlockDevice(std::string _filename);
|
||||
~FileBlockDevice();
|
||||
bool ReadBlock(int blockNumber, u8 *outPtr);
|
||||
int GetNumBlocks() {return (int)(filesize/GetBlockSize());}
|
||||
int GetNumBlocks() {return (int)(filesize / GetBlockSize());}
|
||||
|
||||
private:
|
||||
std::string filename;
|
||||
FILE *f;
|
||||
size_t filesize;
|
||||
};
|
||||
@@ -510,6 +510,11 @@ PSPFileInfo DirectoryFileSystem::GetFileInfo(std::string filename) {
|
||||
return x;
|
||||
}
|
||||
|
||||
bool DirectoryFileSystem::GetHostPath(const std::string &inpath, std::string &outpath) {
|
||||
outpath = GetLocalPath(inpath);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<PSPFileInfo> DirectoryFileSystem::GetDirListing(std::string path) {
|
||||
std::vector<PSPFileInfo> myVector;
|
||||
#ifdef _WIN32
|
||||
|
||||
@@ -67,6 +67,7 @@ public:
|
||||
bool RmDir(const std::string &dirname);
|
||||
bool RenameFile(const std::string &from, const std::string &to);
|
||||
bool DeleteFile(const std::string &filename);
|
||||
bool GetHostPath(const std::string &inpath, std::string &outpath);
|
||||
|
||||
private:
|
||||
struct OpenFileEntry {
|
||||
|
||||
@@ -103,6 +103,7 @@ public:
|
||||
virtual bool RmDir(const std::string &dirname) = 0;
|
||||
virtual bool RenameFile(const std::string &from, const std::string &to) = 0;
|
||||
virtual bool DeleteFile(const std::string &filename) = 0;
|
||||
virtual bool GetHostPath(const std::string &inpath, std::string &outpath) = 0;
|
||||
};
|
||||
|
||||
|
||||
@@ -122,6 +123,7 @@ public:
|
||||
virtual bool RmDir(const std::string &dirname) {return false;}
|
||||
virtual bool RenameFile(const std::string &from, const std::string &to) {return false;}
|
||||
virtual bool DeleteFile(const std::string &filename) {return false;}
|
||||
virtual bool GetHostPath(const std::string &inpath, std::string &outpath) {return false;}
|
||||
};
|
||||
|
||||
|
||||
@@ -27,6 +27,26 @@
|
||||
|
||||
class ISOFileSystem : public IFileSystem
|
||||
{
|
||||
public:
|
||||
ISOFileSystem(IHandleAllocator *_hAlloc, BlockDevice *_blockDevice);
|
||||
~ISOFileSystem();
|
||||
void DoState(PointerWrap &p);
|
||||
std::vector<PSPFileInfo> GetDirListing(std::string path);
|
||||
u32 OpenFile(std::string filename, FileAccess access);
|
||||
void CloseFile(u32 handle);
|
||||
size_t ReadFile(u32 handle, u8 *pointer, s64 size);
|
||||
size_t SeekFile(u32 handle, s32 position, FileMove type);
|
||||
PSPFileInfo GetFileInfo(std::string filename);
|
||||
bool OwnsHandle(u32 handle);
|
||||
|
||||
size_t WriteFile(u32 handle, const u8 *pointer, s64 size);
|
||||
bool GetHostPath(const std::string &inpath, std::string &outpath) {return false;}
|
||||
virtual bool MkDir(const std::string &dirname) {return false;}
|
||||
virtual bool RmDir(const std::string &dirname) {return false;}
|
||||
virtual bool RenameFile(const std::string &from, const std::string &to) {return false;}
|
||||
virtual bool DeleteFile(const std::string &filename) {return false;}
|
||||
|
||||
private:
|
||||
struct TreeEntry
|
||||
{
|
||||
TreeEntry(){}
|
||||
@@ -69,22 +89,4 @@ class ISOFileSystem : public IFileSystem
|
||||
void ReadDirectory(u32 startsector, u32 dirsize, TreeEntry *root);
|
||||
TreeEntry *GetFromPath(std::string path, bool catchError=true);
|
||||
std::string EntryFullPath(TreeEntry *e);
|
||||
|
||||
public:
|
||||
ISOFileSystem(IHandleAllocator *_hAlloc, BlockDevice *_blockDevice);
|
||||
~ISOFileSystem();
|
||||
void DoState(PointerWrap &p);
|
||||
std::vector<PSPFileInfo> GetDirListing(std::string path);
|
||||
u32 OpenFile(std::string filename, FileAccess access);
|
||||
void CloseFile(u32 handle);
|
||||
size_t ReadFile(u32 handle, u8 *pointer, s64 size);
|
||||
size_t WriteFile(u32 handle, const u8 *pointer, s64 size);
|
||||
size_t SeekFile(u32 handle, s32 position, FileMove type);
|
||||
PSPFileInfo GetFileInfo(std::string filename);
|
||||
bool OwnsHandle(u32 handle);
|
||||
|
||||
virtual bool MkDir(const std::string &dirname) {return false;}
|
||||
virtual bool RmDir(const std::string &dirname) {return false;}
|
||||
virtual bool RenameFile(const std::string &from, const std::string &to) {return false;}
|
||||
virtual bool DeleteFile(const std::string &filename) {return false;}
|
||||
};
|
||||
@@ -16,6 +16,7 @@
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#include <set>
|
||||
#include "Common/StringUtil.h"
|
||||
#include "MetaFileSystem.h"
|
||||
|
||||
static bool ApplyPathStringToComponentsVector(std::vector<std::string> &vector, const std::string &pathString)
|
||||
@@ -251,14 +252,15 @@ PSPFileInfo MetaFileSystem::GetFileInfo(std::string filename)
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: Not sure where this should live. Seems a bit wrong putting it in common
|
||||
bool stringEndsWith (std::string const &fullString, std::string const &ending)
|
||||
bool MetaFileSystem::GetHostPath(const std::string &inpath, std::string &outpath)
|
||||
{
|
||||
if (fullString.length() >= ending.length()) {
|
||||
return (0 == fullString.compare (fullString.length() - ending.length(), ending.length(), ending));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
std::string of;
|
||||
IFileSystem *system;
|
||||
if (MapFilePath(inpath, of, &system)) {
|
||||
return system->GetHostPath(of, outpath);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<PSPFileInfo> MetaFileSystem::GetDirListing(std::string path)
|
||||
|
||||
@@ -41,6 +41,9 @@ public:
|
||||
IFileSystem *GetHandleOwner(u32 handle);
|
||||
bool MapFilePath(const std::string &inpath, std::string &outpath, IFileSystem **system);
|
||||
|
||||
// Only possible if a file system is a DirectoryFileSystem or similar.
|
||||
bool GetHostPath(const std::string &inpath, std::string &outpath);
|
||||
|
||||
std::vector<PSPFileInfo> GetDirListing(std::string path);
|
||||
u32 OpenFile(std::string filename, FileAccess access);
|
||||
void CloseFile(u32 handle);
|
||||
|
||||
@@ -78,7 +78,6 @@ void __KernelInit()
|
||||
return;
|
||||
}
|
||||
|
||||
SaveState::Init();
|
||||
__KernelTimeInit();
|
||||
__InterruptsInit();
|
||||
__KernelMemoryInit();
|
||||
@@ -101,6 +100,7 @@ void __KernelInit()
|
||||
__ImposeInit();
|
||||
__UsbInit();
|
||||
__FontInit();
|
||||
SaveState::Init(); // Must be after IO, as it may create a directory
|
||||
|
||||
// "Internal" PSP libraries
|
||||
__PPGeInit();
|
||||
|
||||
+2
-3
@@ -77,11 +77,10 @@ bool Load_PSP_ISO(const char *filename, std::string *error_string)
|
||||
u32 fd = pspFileSystem.OpenFile(sfoPath, FILEACCESS_READ);
|
||||
pspFileSystem.ReadFile(fd, paramsfo, fileInfo.size);
|
||||
pspFileSystem.CloseFile(fd);
|
||||
ParamSFOData data;
|
||||
if (data.ReadSFO(paramsfo, (size_t)fileInfo.size))
|
||||
if (g_paramSFO.ReadSFO(paramsfo, (size_t)fileInfo.size))
|
||||
{
|
||||
char title[1024];
|
||||
sprintf(title, "%s : %s", data.GetValueString("DISC_ID").c_str(), data.GetValueString("TITLE").c_str());
|
||||
sprintf(title, "%s : %s", g_paramSFO.GetValueString("DISC_ID").c_str(), g_paramSFO.GetValueString("TITLE").c_str());
|
||||
INFO_LOG(LOADER, "%s", title);
|
||||
host->SetWindowTitle(title);
|
||||
}
|
||||
|
||||
+88
-10
@@ -16,6 +16,7 @@
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#include "../Common/StdMutex.h"
|
||||
#include "../Common/FileUtil.h"
|
||||
#include <vector>
|
||||
|
||||
#include "SaveState.h"
|
||||
@@ -45,14 +46,15 @@ namespace SaveState
|
||||
|
||||
struct Operation
|
||||
{
|
||||
Operation(OperationType t, const std::string &f, Callback cb)
|
||||
: type(t), filename(f), callback(cb)
|
||||
Operation(OperationType t, const std::string &f, Callback cb, void *cbUserData_)
|
||||
: type(t), filename(f), callback(cb), cbUserData(cbUserData_)
|
||||
{
|
||||
}
|
||||
|
||||
OperationType type;
|
||||
std::string filename;
|
||||
Callback callback;
|
||||
void *cbUserData;
|
||||
};
|
||||
|
||||
static int timer;
|
||||
@@ -61,7 +63,6 @@ namespace SaveState
|
||||
|
||||
void Process(u64 userdata, int cyclesLate);
|
||||
|
||||
// This is where the magic happens.
|
||||
void SaveStart::DoState(PointerWrap &p)
|
||||
{
|
||||
// Gotta do CoreTiming first since we'll restore into it.
|
||||
@@ -96,19 +97,94 @@ namespace SaveState
|
||||
CoreTiming::ScheduleEvent_Threadsafe(0, timer);
|
||||
}
|
||||
|
||||
void Load(const std::string &filename, Callback callback)
|
||||
void Load(const std::string &filename, Callback callback, void *cbUserData)
|
||||
{
|
||||
Enqueue(Operation(SAVESTATE_LOAD, filename, callback));
|
||||
Enqueue(Operation(SAVESTATE_LOAD, filename, callback, cbUserData));
|
||||
}
|
||||
|
||||
void Save(const std::string &filename, Callback callback)
|
||||
void Save(const std::string &filename, Callback callback, void *cbUserData)
|
||||
{
|
||||
Enqueue(Operation(SAVESTATE_SAVE, filename, callback));
|
||||
Enqueue(Operation(SAVESTATE_SAVE, filename, callback, cbUserData));
|
||||
}
|
||||
|
||||
void Verify(Callback callback)
|
||||
|
||||
// Slot utilities
|
||||
|
||||
std::string GenerateSaveSlotFilename(int slot)
|
||||
{
|
||||
Enqueue(Operation(SAVESTATE_VERIFY, std::string(""), callback));
|
||||
char discID[256];
|
||||
char temp[256];
|
||||
sprintf(discID, "%s_%s",
|
||||
g_paramSFO.GetValueString("DISC_ID").c_str(),
|
||||
g_paramSFO.GetValueString("DISC_VERSION").c_str());
|
||||
sprintf(temp, "ms0:/PSP/PPSSPP_STATE/%s_%i.ppst", discID, slot);
|
||||
std::string hostPath;
|
||||
if (pspFileSystem.GetHostPath(std::string(temp), hostPath)) {
|
||||
return hostPath;
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
void LoadSlot(int slot, Callback callback, void *cbUserData)
|
||||
{
|
||||
std::string fn = GenerateSaveSlotFilename(slot);
|
||||
if (!fn.empty())
|
||||
Load(fn, callback, cbUserData);
|
||||
else
|
||||
(*callback)(false, cbUserData);
|
||||
}
|
||||
|
||||
void SaveSlot(int slot, Callback callback, void *cbUserData)
|
||||
{
|
||||
std::string fn = GenerateSaveSlotFilename(slot);
|
||||
if (!fn.empty())
|
||||
Save(fn, callback, cbUserData);
|
||||
else
|
||||
(*callback)(false, cbUserData);
|
||||
}
|
||||
|
||||
void HasSaveInSlot(int slot)
|
||||
{
|
||||
std::string fn = GenerateSaveSlotFilename(slot);
|
||||
}
|
||||
|
||||
bool operator < (const tm &t1, const tm &t2) {
|
||||
if (t1.tm_year < t2.tm_year) return true;
|
||||
if (t1.tm_year > t2.tm_year) return false;
|
||||
if (t1.tm_mon < t2.tm_mon) return true;
|
||||
if (t1.tm_mon > t2.tm_mon) return false;
|
||||
if (t1.tm_mday < t2.tm_mday) return true;
|
||||
if (t1.tm_mday > t2.tm_mday) return false;
|
||||
if (t1.tm_hour < t2.tm_hour) return true;
|
||||
if (t1.tm_hour > t2.tm_hour) return false;
|
||||
if (t1.tm_min < t2.tm_min) return true;
|
||||
if (t1.tm_min > t2.tm_min) return false;
|
||||
if (t1.tm_sec < t2.tm_sec) return true;
|
||||
if (t1.tm_sec > t2.tm_sec) return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
int GetMostRecentSaveSlot() {
|
||||
int newestSlot = -1;
|
||||
tm newestDate = {0};
|
||||
for (int i = 0; i < SAVESTATESLOTS; i++) {
|
||||
std::string fn = GenerateSaveSlotFilename(i);
|
||||
if (File::Exists(fn)) {
|
||||
tm time = File::GetModifTime(fn);
|
||||
if (newestDate < time) {
|
||||
newestDate = time;
|
||||
newestSlot = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return newestSlot;
|
||||
}
|
||||
|
||||
|
||||
void Verify(Callback callback, void *cbUserData)
|
||||
{
|
||||
Enqueue(Operation(SAVESTATE_VERIFY, std::string(""), callback, cbUserData));
|
||||
}
|
||||
|
||||
std::vector<Operation> Flush()
|
||||
@@ -164,12 +240,14 @@ namespace SaveState
|
||||
}
|
||||
|
||||
if (op.callback != NULL)
|
||||
op.callback(result);
|
||||
op.callback(result, op.cbUserData);
|
||||
}
|
||||
}
|
||||
|
||||
void Init()
|
||||
{
|
||||
timer = CoreTiming::RegisterEvent("SaveState", Process);
|
||||
// Make sure there's a directory for save slots
|
||||
pspFileSystem.MkDir("ms0:/PSP/PPSSPP_STATE");
|
||||
}
|
||||
}
|
||||
+12
-4
@@ -20,20 +20,28 @@
|
||||
|
||||
namespace SaveState
|
||||
{
|
||||
typedef void (*Callback)(bool status);
|
||||
typedef void (*Callback)(bool status, void *cbUserData);
|
||||
|
||||
// TODO: Better place for this?
|
||||
const int REVISION = 1;
|
||||
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);
|
||||
int GetNewestSlot();
|
||||
|
||||
// Load the specified file into the current state (async.)
|
||||
// Warning: callback will be called on a different thread.
|
||||
void Load(const std::string &filename, Callback callback = NULL);
|
||||
void Load(const std::string &filename, Callback callback = 0, void *cbUserData = 0);
|
||||
|
||||
// Save the current state to the specified file (async.)
|
||||
// Warning: callback will be called on a different thread.
|
||||
void Save(const std::string &filename, Callback callback = NULL);
|
||||
void Save(const std::string &filename, Callback callback = 0, void *cbUserData = 0);
|
||||
|
||||
// For testing / automated tests. Runs a save state verification pass (async.)
|
||||
// Warning: callback will be called on a different thread.
|
||||
void Verify(Callback callback = NULL);
|
||||
void Verify(Callback callback = 0, void *cbUserData = 0);
|
||||
};
|
||||
+2
-2
@@ -37,10 +37,10 @@
|
||||
#include "CoreParameter.h"
|
||||
#include "FileSystems/MetaFileSystem.h"
|
||||
#include "Loaders.h"
|
||||
|
||||
#include "ELF/ParamSFO.h"
|
||||
|
||||
MetaFileSystem pspFileSystem;
|
||||
|
||||
ParamSFOData g_paramSFO;
|
||||
static CoreParameter coreParameter;
|
||||
|
||||
bool PSP_Init(const CoreParameter &coreParam, std::string *error_string)
|
||||
|
||||
@@ -21,8 +21,10 @@
|
||||
#include "MemMap.h"
|
||||
#include "FileSystems/MetaFileSystem.h"
|
||||
#include "CoreParameter.h"
|
||||
#include "ELF/ParamSFO.h"
|
||||
|
||||
extern MetaFileSystem pspFileSystem;
|
||||
extern ParamSFOData g_paramSFO;
|
||||
|
||||
bool PSP_Init(const CoreParameter &coreParam, std::string *error_string);
|
||||
bool PSP_IsInited();
|
||||
|
||||
@@ -312,7 +312,7 @@ namespace MainWindow
|
||||
UpdateMenus();
|
||||
break;
|
||||
|
||||
case ID_FILE_LOADSTATE:
|
||||
case ID_FILE_LOADSTATEFILE:
|
||||
if (g_State.bEmuThreadStarted)
|
||||
{
|
||||
nextState = Core_IsStepping() ? CORE_STEPPING : CORE_RUNNING;
|
||||
@@ -327,7 +327,7 @@ namespace MainWindow
|
||||
}
|
||||
break;
|
||||
|
||||
case ID_FILE_SAVESTATE:
|
||||
case ID_FILE_SAVESTATEFILE:
|
||||
if (g_State.bEmuThreadStarted)
|
||||
{
|
||||
nextState = Core_IsStepping() ? CORE_STEPPING : CORE_RUNNING;
|
||||
@@ -342,6 +342,32 @@ namespace MainWindow
|
||||
}
|
||||
break;
|
||||
|
||||
// TODO: Add UI for multiple slots
|
||||
|
||||
case ID_FILE_QUICKLOADSTATE:
|
||||
if (g_State.bEmuThreadStarted)
|
||||
{
|
||||
nextState = Core_IsStepping() ? CORE_STEPPING : CORE_RUNNING;
|
||||
for (int i=0; i<numCPUs; i++)
|
||||
if (disasmWindow[i])
|
||||
SendMessage(disasmWindow[i]->GetDlgHandle(), WM_COMMAND, IDC_STOP, 0);
|
||||
}
|
||||
SetCursor(LoadCursor(0,IDC_WAIT));
|
||||
SaveState::LoadSlot(0, SaveStateActionFinished);
|
||||
break;
|
||||
|
||||
case ID_FILE_QUICKSAVESTATE:
|
||||
if (g_State.bEmuThreadStarted)
|
||||
{
|
||||
nextState = Core_IsStepping() ? CORE_STEPPING : CORE_RUNNING;
|
||||
for (int i=0; i<numCPUs; i++)
|
||||
if (disasmWindow[i])
|
||||
SendMessage(disasmWindow[i]->GetDlgHandle(), WM_COMMAND, IDC_STOP, 0);
|
||||
}
|
||||
SetCursor(LoadCursor(0,IDC_WAIT));
|
||||
SaveState::SaveSlot(0, SaveStateActionFinished);
|
||||
break;
|
||||
|
||||
case ID_OPTIONS_SCREEN1X:
|
||||
SetZoom(1);
|
||||
UpdateMenus();
|
||||
@@ -675,8 +701,10 @@ namespace MainWindow
|
||||
|
||||
enable = g_State.bEmuThreadStarted ? MF_GRAYED : MF_ENABLED;
|
||||
EnableMenuItem(menu,ID_FILE_LOAD,enable);
|
||||
EnableMenuItem(menu,ID_FILE_SAVESTATE,!enable);
|
||||
EnableMenuItem(menu,ID_FILE_LOADSTATE,!enable);
|
||||
EnableMenuItem(menu,ID_FILE_SAVESTATEFILE,!enable);
|
||||
EnableMenuItem(menu,ID_FILE_LOADSTATEFILE,!enable);
|
||||
EnableMenuItem(menu,ID_FILE_QUICKSAVESTATE,!enable);
|
||||
EnableMenuItem(menu,ID_FILE_QUICKLOADSTATE,!enable);
|
||||
EnableMenuItem(menu,ID_CPU_DYNAREC,enable);
|
||||
EnableMenuItem(menu,ID_CPU_INTERPRETER,enable);
|
||||
EnableMenuItem(menu,ID_CPU_FASTINTERPRETER,enable);
|
||||
@@ -788,7 +816,7 @@ namespace MainWindow
|
||||
}
|
||||
}
|
||||
|
||||
void SaveStateActionFinished(bool result)
|
||||
void SaveStateActionFinished(bool result, void *userdata)
|
||||
{
|
||||
// TODO: Improve messaging?
|
||||
if (!result)
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace MainWindow
|
||||
void SetPlaying(const char*text);
|
||||
void BrowseAndBoot();
|
||||
void SetNextState(CoreState state);
|
||||
void SaveStateActionFinished(bool result);
|
||||
void SaveStateActionFinished(bool result, void *userdata);
|
||||
void _ViewFullScreen(HWND hWnd);
|
||||
void _ViewNormal(HWND hWnd);
|
||||
}
|
||||
+7
-5
@@ -187,9 +187,11 @@ BEGIN
|
||||
MENUITEM "&Open...", ID_FILE_LOAD
|
||||
MENUITEM "&Close", ID_EMULATION_STOP
|
||||
MENUITEM SEPARATOR
|
||||
MENUITEM "&Load State\tF4" ID_FILE_LOADSTATE
|
||||
MENUITEM "&Save State\tF2" ID_FILE_SAVESTATE
|
||||
MENUITEM SEPARATOR
|
||||
MENUITEM "Quickload state\tF4" ID_FILE_QUICKLOADSTATE
|
||||
MENUITEM "Quicksave state\tF2" ID_FILE_QUICKSAVESTATE
|
||||
MENUITEM "&Load State File..." ID_FILE_LOADSTATEFILE
|
||||
MENUITEM "&Save State File..." ID_FILE_SAVESTATEFILE
|
||||
MENUITEM SEPARATOR
|
||||
MENUITEM "E&xit", ID_FILE_EXIT
|
||||
END
|
||||
POPUP "&Emulation"
|
||||
@@ -321,8 +323,8 @@ BEGIN
|
||||
"R", ID_DEBUG_REGISTERS, VIRTKEY, CONTROL, NOINVERT
|
||||
VK_F7, ID_EMULATION_RUN, VIRTKEY, NOINVERT
|
||||
VK_F8, ID_EMULATION_PAUSE, VIRTKEY, NOINVERT
|
||||
VK_F2, ID_FILE_SAVESTATE, VIRTKEY, NOINVERT
|
||||
VK_F4, ID_FILE_LOADSTATE, VIRTKEY, NOINVERT
|
||||
VK_F2, ID_FILE_QUICKSAVESTATE, VIRTKEY, NOINVERT
|
||||
VK_F4, ID_FILE_QUICKLOADSTATE, VIRTKEY, NOINVERT
|
||||
"1", ID_OPTIONS_SCREEN1X, VIRTKEY, CONTROL, NOINVERT
|
||||
"2", ID_OPTIONS_SCREEN2X, VIRTKEY, CONTROL, NOINVERT
|
||||
"3", ID_OPTIONS_SCREEN3X, VIRTKEY, CONTROL, NOINVERT
|
||||
|
||||
+5
-3
@@ -53,8 +53,8 @@
|
||||
#define ID_DEBUG_BREAKPOINTS 122
|
||||
#define ID_FILE_LOAD_BIN 123
|
||||
#define ID_FILE_LOAD_ISO 125
|
||||
#define ID_FILE_LOADSTATE 126
|
||||
#define ID_FILE_SAVESTATE 127
|
||||
#define ID_FILE_LOADSTATEFILE 126
|
||||
#define ID_FILE_SAVESTATEFILE 127
|
||||
#define ID_EMULATION_RESET 130
|
||||
#define IDD_ABOUTBOX 133
|
||||
#define ID_DEBUG_LOADMAPFILE 134
|
||||
@@ -248,13 +248,15 @@
|
||||
#define ID_OPTIONS_FASTMEMORY 40125
|
||||
#define IDC_STEPHLE 40126
|
||||
#define ID_OPTIONS_LINEARFILTERING 40127
|
||||
#define ID_FILE_QUICKSAVESTATE 40128
|
||||
#define ID_FILE_QUICKLOADSTATE 40129
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 232
|
||||
#define _APS_NEXT_COMMAND_VALUE 40127
|
||||
#define _APS_NEXT_COMMAND_VALUE 40130
|
||||
#define _APS_NEXT_CONTROL_VALUE 1162
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "ui/ui.h"
|
||||
#include "ui_atlas.h"
|
||||
#include "util/random/rng.h"
|
||||
#include "util/text/utf8.h"
|
||||
#include "UIShader.h"
|
||||
|
||||
#include "../../GPU/ge_constants.h"
|
||||
@@ -36,10 +37,16 @@
|
||||
#include "../../GPU/GPUInterface.h"
|
||||
#include "../../Core/Config.h"
|
||||
#include "../../Core/CoreParameter.h"
|
||||
#include "../../Core/SaveState.h"
|
||||
|
||||
#include "MenuScreens.h"
|
||||
#include "EmuScreen.h"
|
||||
|
||||
|
||||
// Ugly communication with NativeApp
|
||||
extern std::string game_title;
|
||||
|
||||
|
||||
static const int symbols[4] = {
|
||||
I_CROSS,
|
||||
I_CIRCLE,
|
||||
@@ -207,22 +214,39 @@ void InGameMenuScreen::render() {
|
||||
UIBegin();
|
||||
DrawBackground(1.0f);
|
||||
|
||||
ui_draw2d.DrawText(UBUNTU48, "Emulation Paused", dp_xres / 2, 30, 0xFFFFFFFF, ALIGN_HCENTER);
|
||||
const char *title;
|
||||
if (UTF8StringHasNonASCII(game_title.c_str())) {
|
||||
title = "(can't display japanese title)";
|
||||
} else {
|
||||
title = game_title.c_str();
|
||||
}
|
||||
|
||||
ui_draw2d.DrawText(UBUNTU48, title, dp_xres / 2, 30, 0xFFFFFFFF, ALIGN_HCENTER);
|
||||
|
||||
int x = 30;
|
||||
int y = 50;
|
||||
UICheckBox(GEN_ID, x, y += 50, "Show Debug Statistics (experimental)", ALIGN_TOPLEFT, &g_Config.bShowDebugStats);
|
||||
UICheckBox(GEN_ID, x, y += 50, "Hardware Transform (experimental)", ALIGN_TOPLEFT, &g_Config.bHardwareTransform);
|
||||
UICheckBox(GEN_ID, x, y += 50, "Show Debug Statistics", ALIGN_TOPLEFT, &g_Config.bShowDebugStats);
|
||||
UICheckBox(GEN_ID, x, y += 50, "Hardware Transform", ALIGN_TOPLEFT, &g_Config.bHardwareTransform);
|
||||
|
||||
// TODO: Add UI for more than one slot.
|
||||
VLinear vlinear1(x, y + 80, 20);
|
||||
UIText(UBUNTU24, vlinear1, "Save states are experimental (and large)", 0xFFFFFFFF);
|
||||
if (UIButton(GEN_ID, vlinear1, LARGE_BUTTON_WIDTH, "Save State", ALIGN_LEFT)) {
|
||||
SaveState::SaveSlot(0, 0, 0);
|
||||
screenManager()->finishDialog(this, DR_CANCEL);
|
||||
}
|
||||
if (UIButton(GEN_ID, vlinear1, LARGE_BUTTON_WIDTH, "Load State", ALIGN_LEFT)) {
|
||||
SaveState::LoadSlot(0, 0, 0);
|
||||
screenManager()->finishDialog(this, DR_CANCEL);
|
||||
}
|
||||
|
||||
VLinear vlinear(dp_xres - 10, 160, 20);
|
||||
if (UIButton(GEN_ID, vlinear, LARGE_BUTTON_WIDTH, "Continue", ALIGN_RIGHT)) {
|
||||
screenManager()->finishDialog(this, DR_CANCEL);
|
||||
}
|
||||
|
||||
if (UIButton(GEN_ID, vlinear, LARGE_BUTTON_WIDTH, "Return to Menu", ALIGN_RIGHT)) {
|
||||
screenManager()->finishDialog(this, DR_OK);
|
||||
}
|
||||
|
||||
if (UIButton(GEN_ID, vlinear, LARGE_BUTTON_WIDTH, "Dump Next Frame", ALIGN_RIGHT)) {
|
||||
gpu->DumpNextFrame();
|
||||
}
|
||||
@@ -253,7 +277,7 @@ void SettingsScreen::render() {
|
||||
int y = 50;
|
||||
UICheckBox(GEN_ID, x, y += 50, "Sound Emulation", ALIGN_TOPLEFT, &g_Config.bEnableSound);
|
||||
UICheckBox(GEN_ID, x, y += 50, "Buffered Rendering (may fix flicker)", ALIGN_TOPLEFT, &g_Config.bBufferedRendering);
|
||||
UICheckBox(GEN_ID, x, y += 50, "Hardware Transform (experimental)", ALIGN_TOPLEFT, &g_Config.bHardwareTransform);
|
||||
UICheckBox(GEN_ID, x, y += 50, "Hardware Transform", ALIGN_TOPLEFT, &g_Config.bHardwareTransform);
|
||||
|
||||
bool useFastInt = g_Config.iCpuCore == CPU_FASTINTERPRETER;
|
||||
UICheckBox(GEN_ID, x, y += 50, "Slightly faster interpreter (may crash)", ALIGN_TOPLEFT, &useFastInt);
|
||||
|
||||
@@ -53,6 +53,7 @@ Texture *uiTexture;
|
||||
|
||||
ScreenManager *screenManager;
|
||||
std::string config_filename;
|
||||
std::string game_title;
|
||||
|
||||
class AndroidLogger : public LogListener
|
||||
{
|
||||
@@ -112,6 +113,9 @@ public:
|
||||
virtual bool AttemptLoadSymbolMap() {return false;}
|
||||
virtual void ResetSymbolMap() {}
|
||||
virtual void AddSymbol(std::string name, u32 addr, u32 size, int type=0) {}
|
||||
virtual void SetWindowTitle(const char *message) {
|
||||
game_title = message;
|
||||
}
|
||||
};
|
||||
|
||||
// globals
|
||||
|
||||
Reference in new issue
Block a user