mirror of
https://github.com/cemu-project/Cemu.git
synced 2025-07-04 05:51:19 +12:00
Parity with ChrisNonyminus:Cemu:savestates; Add SS menu; Move SS func to CafeSystem
This commit is contained in:
parent
bfbeeae6f6
commit
0f9d27ae12
19 changed files with 573 additions and 5 deletions
|
@ -68,6 +68,8 @@
|
||||||
// dependency to be removed
|
// dependency to be removed
|
||||||
#include "gui/guiWrapper.h"
|
#include "gui/guiWrapper.h"
|
||||||
|
|
||||||
|
#include "Cafe/OS/libs/coreinit/coreinit_FS.h"
|
||||||
|
|
||||||
std::string _pathToExecutable;
|
std::string _pathToExecutable;
|
||||||
std::string _pathToBaseExecutable;
|
std::string _pathToBaseExecutable;
|
||||||
|
|
||||||
|
@ -792,6 +794,99 @@ namespace CafeSystem
|
||||||
sSystemRunning = false;
|
sSystemRunning = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PauseTitle()
|
||||||
|
{
|
||||||
|
if (!sSystemRunning)
|
||||||
|
return;
|
||||||
|
coreinit::SuspendAllThreads();
|
||||||
|
sSystemRunning = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResumeTitle(bool* runningThreads)
|
||||||
|
{
|
||||||
|
if (sSystemRunning)
|
||||||
|
return;
|
||||||
|
|
||||||
|
coreinit::ResumeAllThreads(runningThreads);
|
||||||
|
sSystemRunning = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SaveState(std::string path)
|
||||||
|
{
|
||||||
|
cemuLog_log(LogType::Force, "[SAVESTATE] Saving state...");
|
||||||
|
MemStreamWriter writer(0);
|
||||||
|
// pause game
|
||||||
|
PauseTitle();
|
||||||
|
// memory
|
||||||
|
memory_Serialize(writer);
|
||||||
|
// gpu
|
||||||
|
writer.writeData(LatteGPUState.contextRegister, sizeof(LatteGPUState.contextRegister));
|
||||||
|
writer.writeData(LatteGPUState.contextRegisterShadowAddr, sizeof(LatteGPUState.contextRegister));
|
||||||
|
writer.writeData(LatteGPUState.sharedArea, sizeof(gx2GPUSharedArea_t));
|
||||||
|
// cpu
|
||||||
|
auto threads = coreinit::GetAllThreads();
|
||||||
|
for (auto& thr : threads)
|
||||||
|
{
|
||||||
|
writer.writeBE<bool>(thr != nullptr);
|
||||||
|
if (thr != nullptr)
|
||||||
|
writer.writeData(thr, sizeof(OSThread_t));
|
||||||
|
}
|
||||||
|
for (auto& thr : activeThread)
|
||||||
|
{
|
||||||
|
writer.writeBE(thr);
|
||||||
|
}
|
||||||
|
// fs
|
||||||
|
coreinit::FSSave(writer);
|
||||||
|
iosu::fsa::Save(writer);
|
||||||
|
|
||||||
|
FileStream* stream = FileStream::createFile(path);
|
||||||
|
stream->writeData(writer.getResult().data(), writer.getResult().size_bytes());
|
||||||
|
delete stream;
|
||||||
|
cemuLog_log(LogType::Force, "[SAVESTATE] Saved state to {}.", path);
|
||||||
|
ResumeTitle(/*isThreadRunning*/);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoadState(std::string path)
|
||||||
|
{
|
||||||
|
PauseTitle();
|
||||||
|
cemuLog_log(LogType::Force, "[SAVESTATE] Loading state...", path);
|
||||||
|
|
||||||
|
auto data = FileStream::LoadIntoMemory(path);
|
||||||
|
assert(data.has_value());
|
||||||
|
MemStreamReader reader(data->data(), data->size());
|
||||||
|
// memory
|
||||||
|
memory_Deserialize(reader);
|
||||||
|
// gpu
|
||||||
|
reader.readData(LatteGPUState.contextRegister, sizeof(LatteGPUState.contextRegister));
|
||||||
|
reader.readData(LatteGPUState.contextRegisterShadowAddr, sizeof(LatteGPUState.contextRegister));
|
||||||
|
reader.readData(LatteGPUState.sharedArea, sizeof(gx2GPUSharedArea_t));
|
||||||
|
// cpu
|
||||||
|
auto threads = coreinit::GetAllThreads();
|
||||||
|
for (auto& thr : threads)
|
||||||
|
{
|
||||||
|
bool notnull = reader.readBE<bool>();
|
||||||
|
if (notnull)
|
||||||
|
{
|
||||||
|
if (!thr)
|
||||||
|
{
|
||||||
|
thr = new OSThread_t;
|
||||||
|
}
|
||||||
|
reader.readData(thr, sizeof(OSThread_t));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < 256; i++)
|
||||||
|
{
|
||||||
|
activeThread[i] = reader.readBE<uint32>();
|
||||||
|
}
|
||||||
|
// fs
|
||||||
|
coreinit::FSRestore(reader);
|
||||||
|
iosu::fsa::Restore(reader);
|
||||||
|
|
||||||
|
cemuLog_log(LogType::Force, "[SAVESTATE] Loaded state from {}.", path);
|
||||||
|
|
||||||
|
ResumeTitle(/*isThreadRunning*/);
|
||||||
|
}
|
||||||
|
|
||||||
/* Virtual mlc storage */
|
/* Virtual mlc storage */
|
||||||
|
|
||||||
void InitVirtualMlcStorage()
|
void InitVirtualMlcStorage()
|
||||||
|
|
|
@ -30,6 +30,12 @@ namespace CafeSystem
|
||||||
|
|
||||||
void ShutdownTitle();
|
void ShutdownTitle();
|
||||||
|
|
||||||
|
void PauseTitle();
|
||||||
|
void ResumeTitle(bool* runningThreads = nullptr);
|
||||||
|
|
||||||
|
void SaveState(std::string path);
|
||||||
|
void LoadState(std::string path);
|
||||||
|
|
||||||
std::string GetMlcStoragePath(TitleId titleId);
|
std::string GetMlcStoragePath(TitleId titleId);
|
||||||
void MlcStorageMountAllTitles();
|
void MlcStorageMountAllTitles();
|
||||||
|
|
||||||
|
|
|
@ -269,6 +269,8 @@ FSCMountPathNode* fsc_lookupPathVirtualNode(const char* path, sint32 priority)
|
||||||
class FSCVirtualFileDirectoryIterator : public FSCVirtualFile
|
class FSCVirtualFileDirectoryIterator : public FSCVirtualFile
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
void Save(MemStreamWriter& writer) override;
|
||||||
|
|
||||||
sint32 fscGetType() override
|
sint32 fscGetType() override
|
||||||
{
|
{
|
||||||
return FSC_TYPE_DIRECTORY;
|
return FSC_TYPE_DIRECTORY;
|
||||||
|
@ -717,3 +719,59 @@ void fsc_init()
|
||||||
{
|
{
|
||||||
fsc_reset();
|
fsc_reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FSCVirtualFile::Save(MemStreamWriter& writer)
|
||||||
|
{
|
||||||
|
writer.writeBE(dirIterator != nullptr);
|
||||||
|
if (dirIterator) writer.writeBE(*dirIterator);
|
||||||
|
}
|
||||||
|
#include "Cafe/Filesystem/fscDeviceHostFS.h"
|
||||||
|
|
||||||
|
FSCVirtualFile* FSCVirtualFile::Restore(MemStreamReader& reader)
|
||||||
|
{
|
||||||
|
FSCVirtualFile* file;
|
||||||
|
switch ((Child)reader.readBE<uint32>())
|
||||||
|
{
|
||||||
|
case Child::DIRECTORY_ITERATOR:
|
||||||
|
{
|
||||||
|
std::string path = reader.readBE<std::string>();
|
||||||
|
std::vector<FSCVirtualFile*> folders{};
|
||||||
|
size_t size = reader.readBE<size_t>();
|
||||||
|
for (size_t i = 0; i < size; i++)
|
||||||
|
{
|
||||||
|
folders.push_back(Restore(reader));
|
||||||
|
}
|
||||||
|
file = new FSCVirtualFileDirectoryIterator(path, folders);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case Child::HOST:
|
||||||
|
{
|
||||||
|
std::string path = reader.readBE<std::string>();
|
||||||
|
FSC_ACCESS_FLAG flags = (FSC_ACCESS_FLAG)reader.readBE<uint32>();
|
||||||
|
sint32 status{};
|
||||||
|
file = FSCVirtualFile_Host::OpenFile(path, flags, status);
|
||||||
|
file->fscSetSeek(reader.readBE<uint64>());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
throw std::exception("Not implemented");
|
||||||
|
}
|
||||||
|
if (reader.readBE<bool>())
|
||||||
|
{
|
||||||
|
file->dirIterator = new FSCDirIteratorState;
|
||||||
|
*file->dirIterator = reader.readBE<FSCDirIteratorState>();
|
||||||
|
}
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FSCVirtualFileDirectoryIterator::Save(MemStreamWriter& writer)
|
||||||
|
{
|
||||||
|
writer.writeBE<uint32>((uint32)Child::DIRECTORY_ITERATOR);
|
||||||
|
writer.writeBE(m_path);
|
||||||
|
writer.writeBE(m_folders.size());
|
||||||
|
for (auto& folder : m_folders)
|
||||||
|
{
|
||||||
|
folder->Save(writer);
|
||||||
|
}
|
||||||
|
FSCVirtualFile::Save(writer);
|
||||||
|
}
|
|
@ -89,12 +89,20 @@ public:
|
||||||
|
|
||||||
struct FSCVirtualFile
|
struct FSCVirtualFile
|
||||||
{
|
{
|
||||||
|
enum class Child : uint32
|
||||||
|
{
|
||||||
|
DIRECTORY_ITERATOR, HOST, WUACTX, WUDCTX, NONE
|
||||||
|
};
|
||||||
|
|
||||||
struct FSCDirIteratorState
|
struct FSCDirIteratorState
|
||||||
{
|
{
|
||||||
sint32 index;
|
sint32 index;
|
||||||
std::vector<FSCDirEntry> dirEntries;
|
std::vector<FSCDirEntry> dirEntries;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
virtual void Save(MemStreamWriter& writer);
|
||||||
|
static FSCVirtualFile* Restore(MemStreamReader& reader);
|
||||||
|
|
||||||
FSCVirtualFile()
|
FSCVirtualFile()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
|
@ -157,6 +157,19 @@ bool FSCVirtualFile_Host::fscDirNext(FSCDirEntry* dirEntry)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FSCVirtualFile_Host::Save(MemStreamWriter& writer)
|
||||||
|
{
|
||||||
|
writer.writeBE<uint32>((uint32)Child::HOST);
|
||||||
|
|
||||||
|
writer.writeBE(m_path->string());
|
||||||
|
writer.writeBE((uint32)m_accessFlags);
|
||||||
|
|
||||||
|
writer.writeBE(m_seek);
|
||||||
|
|
||||||
|
FSCVirtualFile::Save(writer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
FSCVirtualFile* FSCVirtualFile_Host::OpenFile(const fs::path& path, FSC_ACCESS_FLAG accessFlags, sint32& fscStatus)
|
FSCVirtualFile* FSCVirtualFile_Host::OpenFile(const fs::path& path, FSC_ACCESS_FLAG accessFlags, sint32& fscStatus)
|
||||||
{
|
{
|
||||||
if (!HAS_FLAG(accessFlags, FSC_ACCESS_FLAG::OPEN_FILE) && !HAS_FLAG(accessFlags, FSC_ACCESS_FLAG::OPEN_DIR))
|
if (!HAS_FLAG(accessFlags, FSC_ACCESS_FLAG::OPEN_FILE) && !HAS_FLAG(accessFlags, FSC_ACCESS_FLAG::OPEN_DIR))
|
||||||
|
@ -191,9 +204,11 @@ FSCVirtualFile* FSCVirtualFile_Host::OpenFile(const fs::path& path, FSC_ACCESS_F
|
||||||
if (fs)
|
if (fs)
|
||||||
{
|
{
|
||||||
FSCVirtualFile_Host* vf = new FSCVirtualFile_Host(FSC_TYPE_FILE);
|
FSCVirtualFile_Host* vf = new FSCVirtualFile_Host(FSC_TYPE_FILE);
|
||||||
|
vf->m_path.reset(new std::filesystem::path(path));
|
||||||
vf->m_fs = fs;
|
vf->m_fs = fs;
|
||||||
vf->m_isWritable = writeAccessRequested;
|
vf->m_isWritable = writeAccessRequested;
|
||||||
vf->m_fileSize = fs->GetSize();
|
vf->m_fileSize = fs->GetSize();
|
||||||
|
vf->m_accessFlags = accessFlags;
|
||||||
fscStatus = FSC_STATUS_OK;
|
fscStatus = FSC_STATUS_OK;
|
||||||
return vf;
|
return vf;
|
||||||
}
|
}
|
||||||
|
@ -208,6 +223,7 @@ FSCVirtualFile* FSCVirtualFile_Host::OpenFile(const fs::path& path, FSC_ACCESS_F
|
||||||
{
|
{
|
||||||
FSCVirtualFile_Host* vf = new FSCVirtualFile_Host(FSC_TYPE_DIRECTORY);
|
FSCVirtualFile_Host* vf = new FSCVirtualFile_Host(FSC_TYPE_DIRECTORY);
|
||||||
vf->m_path.reset(new std::filesystem::path(path));
|
vf->m_path.reset(new std::filesystem::path(path));
|
||||||
|
vf->m_accessFlags = accessFlags;
|
||||||
fscStatus = FSC_STATUS_OK;
|
fscStatus = FSC_STATUS_OK;
|
||||||
return vf;
|
return vf;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
class FSCVirtualFile_Host : public FSCVirtualFile
|
class FSCVirtualFile_Host : public FSCVirtualFile
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
void Save(MemStreamWriter& writer) override;
|
||||||
static FSCVirtualFile* OpenFile(const fs::path& path, FSC_ACCESS_FLAG accessFlags, sint32& fscStatus);
|
static FSCVirtualFile* OpenFile(const fs::path& path, FSC_ACCESS_FLAG accessFlags, sint32& fscStatus);
|
||||||
~FSCVirtualFile_Host() override;
|
~FSCVirtualFile_Host() override;
|
||||||
|
|
||||||
|
@ -31,4 +32,6 @@ private:
|
||||||
// directory
|
// directory
|
||||||
std::unique_ptr<std::filesystem::path> m_path{};
|
std::unique_ptr<std::filesystem::path> m_path{};
|
||||||
std::unique_ptr<std::filesystem::directory_iterator> m_dirIterator{};
|
std::unique_ptr<std::filesystem::directory_iterator> m_dirIterator{};
|
||||||
|
// serialization
|
||||||
|
FSC_ACCESS_FLAG m_accessFlags;
|
||||||
};
|
};
|
|
@ -15,6 +15,11 @@ protected:
|
||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
void Save(MemStreamWriter& writer) override
|
||||||
|
{
|
||||||
|
throw std::exception("Not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
sint32 fscGetType() override
|
sint32 fscGetType() override
|
||||||
{
|
{
|
||||||
return m_fscType;
|
return m_fscType;
|
||||||
|
|
|
@ -22,6 +22,11 @@ protected:
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
void Save(MemStreamWriter& writer) override
|
||||||
|
{
|
||||||
|
throw std::exception("Not implemented");
|
||||||
|
}
|
||||||
|
|
||||||
sint32 fscGetType() override
|
sint32 fscGetType() override
|
||||||
{
|
{
|
||||||
return m_fscType;
|
return m_fscType;
|
||||||
|
|
|
@ -80,6 +80,66 @@ MMURange* memory_getMMURangeByAddress(MPTR address)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool MMURange::serializeImpl(MemStreamWriter& streamWriter)
|
||||||
|
{
|
||||||
|
streamWriter.writeBE<bool>(this->m_isMapped);
|
||||||
|
if (m_isMapped)
|
||||||
|
{
|
||||||
|
streamWriter.writeBE(this->baseAddress);
|
||||||
|
streamWriter.writeBE<uint8>((uint8)this->areaId);
|
||||||
|
streamWriter.writeBE<uint8>((uint8)this->flags);
|
||||||
|
streamWriter.writeBE(this->name);
|
||||||
|
streamWriter.writeBE(this->size);
|
||||||
|
streamWriter.writeBE(this->initSize);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
void MemStreamWriter::writeBE<MMURange>(const MMURange& v)
|
||||||
|
{
|
||||||
|
writeBE(v.m_isMapped);
|
||||||
|
writeBE(v.baseAddress);
|
||||||
|
writeBE<uint8>((uint8)v.areaId);
|
||||||
|
writeBE<uint8>((uint8)v.flags);
|
||||||
|
writeBE(v.name);
|
||||||
|
writeBE(v.size);
|
||||||
|
writeBE(v.initSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
MMURange MemStreamReader::readBE<MMURange>()
|
||||||
|
{
|
||||||
|
bool mapped = readBE<bool>();
|
||||||
|
uint32 base = readBE<uint32>();
|
||||||
|
MMU_MEM_AREA_ID areaid = (MMU_MEM_AREA_ID)readBE<uint8>();
|
||||||
|
MMURange::MFLAG flags = (MMURange::MFLAG)readBE<uint8>();
|
||||||
|
std::string name = readBE<std::string>();
|
||||||
|
uint32 size = readBE<uint32>();
|
||||||
|
uint32 initsize = readBE<uint32>();
|
||||||
|
MMURange range(base, size, areaid, name, flags);
|
||||||
|
if (mapped)
|
||||||
|
range.mapMem();
|
||||||
|
return range;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MMURange::deserializeImpl(MemStreamReader& streamReader)
|
||||||
|
{
|
||||||
|
m_isMapped = streamReader.readBE<bool>();
|
||||||
|
if (m_isMapped)
|
||||||
|
{
|
||||||
|
baseAddress = streamReader.readBE<uint32>();
|
||||||
|
areaId = (MMU_MEM_AREA_ID)streamReader.readBE<uint8>();
|
||||||
|
this->flags = (MFLAG)streamReader.readBE<uint8>();
|
||||||
|
this->name = streamReader.readBE<std::string>();
|
||||||
|
this->size = streamReader.readBE<uint32>();
|
||||||
|
this->initSize = streamReader.readBE<uint32>();
|
||||||
|
m_isMapped = false;
|
||||||
|
mapMem();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
MMURange::MMURange(const uint32 baseAddress, const uint32 size, MMU_MEM_AREA_ID areaId, const std::string_view name, MFLAG flags) : baseAddress(baseAddress), size(size), initSize(size), areaId(areaId), name(name), flags(flags)
|
MMURange::MMURange(const uint32 baseAddress, const uint32 size, MMU_MEM_AREA_ID areaId, const std::string_view name, MFLAG flags) : baseAddress(baseAddress), size(size), initSize(size), areaId(areaId), name(name), flags(flags)
|
||||||
{
|
{
|
||||||
g_mmuRanges.emplace_back(this);
|
g_mmuRanges.emplace_back(this);
|
||||||
|
@ -403,6 +463,35 @@ void memory_createDump()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void memory_Serialize(MemStreamWriter& s)
|
||||||
|
{
|
||||||
|
s.writeBE<uint64>(g_mmuRanges.size());
|
||||||
|
for (auto& itr : g_mmuRanges)
|
||||||
|
{
|
||||||
|
s.writeBE(*itr);
|
||||||
|
if (itr->isMapped())
|
||||||
|
{
|
||||||
|
s.writeData(memory_base + itr->getBase(), itr->getSize());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void memory_Deserialize(MemStreamReader& s)
|
||||||
|
{
|
||||||
|
g_mmuRanges.clear();
|
||||||
|
size_t cnt = s.readBE<uint64>();
|
||||||
|
for (size_t i = 0; i < cnt; i++)
|
||||||
|
{
|
||||||
|
auto range = s.readBE<MMURange>();
|
||||||
|
bool mapped = range.isMapped();
|
||||||
|
if (mapped)
|
||||||
|
{
|
||||||
|
s.readData(memory_base + range.getBase(), range.getSize());
|
||||||
|
}
|
||||||
|
g_mmuRanges.push_back(std::move(&range));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace MMU
|
namespace MMU
|
||||||
{
|
{
|
||||||
// MMIO access handler
|
// MMIO access handler
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "util/helpers/Serializer.h"
|
||||||
|
|
||||||
void memory_init();
|
void memory_init();
|
||||||
void memory_mapForCurrentTitle();
|
void memory_mapForCurrentTitle();
|
||||||
void memory_logModifiedMemoryRanges();
|
void memory_logModifiedMemoryRanges();
|
||||||
|
@ -48,6 +50,9 @@ struct MMURange
|
||||||
FLAG_MAP_EARLY = (1 << 1), // map at Cemu launch, normally memory is mapped when a game is loaded
|
FLAG_MAP_EARLY = (1 << 1), // map at Cemu launch, normally memory is mapped when a game is loaded
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool serializeImpl(MemStreamWriter& streamWriter);
|
||||||
|
bool deserializeImpl(MemStreamReader& streamReader);
|
||||||
|
|
||||||
MMURange(const uint32 baseAddress, const uint32 size, MMU_MEM_AREA_ID areaId, const std::string_view name, MFLAG flags = (MFLAG)0);
|
MMURange(const uint32 baseAddress, const uint32 size, MMU_MEM_AREA_ID areaId, const std::string_view name, MFLAG flags = (MFLAG)0);
|
||||||
|
|
||||||
void mapMem();
|
void mapMem();
|
||||||
|
@ -107,14 +112,16 @@ struct MMURange
|
||||||
bool isOptional() const { return (flags & MFLAG::FLAG_OPTIONAL) != 0; };
|
bool isOptional() const { return (flags & MFLAG::FLAG_OPTIONAL) != 0; };
|
||||||
bool isMappedEarly() const { return (flags & MFLAG::FLAG_MAP_EARLY) != 0; };
|
bool isMappedEarly() const { return (flags & MFLAG::FLAG_MAP_EARLY) != 0; };
|
||||||
|
|
||||||
const uint32 baseAddress;
|
uint32 baseAddress;
|
||||||
const uint32 initSize; // initial size
|
uint32 initSize; // initial size
|
||||||
const std::string name;
|
std::string name;
|
||||||
const MFLAG flags;
|
MFLAG flags;
|
||||||
const MMU_MEM_AREA_ID areaId;
|
MMU_MEM_AREA_ID areaId;
|
||||||
// runtime parameters
|
// runtime parameters
|
||||||
uint32 size;
|
uint32 size;
|
||||||
bool m_isMapped{};
|
bool m_isMapped{};
|
||||||
|
friend class MemStreamWriter;
|
||||||
|
friend class MemStreamReader;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -202,6 +209,9 @@ uint8 memory_readU8(uint32 address);
|
||||||
|
|
||||||
void memory_createDump();
|
void memory_createDump();
|
||||||
|
|
||||||
|
void memory_Serialize(MemStreamWriter& s);
|
||||||
|
void memory_Deserialize(MemStreamReader& s);
|
||||||
|
|
||||||
template<size_t count>
|
template<size_t count>
|
||||||
void memory_readBytes(VAddr address, std::array<uint8, count>& buffer)
|
void memory_readBytes(VAddr address, std::array<uint8, count>& buffer)
|
||||||
{
|
{
|
||||||
|
|
|
@ -169,6 +169,8 @@ namespace iosu
|
||||||
}
|
}
|
||||||
|
|
||||||
class _FSAHandleTable {
|
class _FSAHandleTable {
|
||||||
|
friend class MemStreamWriter;
|
||||||
|
friend class MemStreamReader;
|
||||||
struct _FSAHandleResource
|
struct _FSAHandleResource
|
||||||
{
|
{
|
||||||
bool isAllocated{false};
|
bool isAllocated{false};
|
||||||
|
@ -904,3 +906,109 @@ namespace iosu
|
||||||
}
|
}
|
||||||
} // namespace fsa
|
} // namespace fsa
|
||||||
} // namespace iosu
|
} // namespace iosu
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void MemStreamWriter::writeBE<FSCDirEntry>(const FSCDirEntry& v);
|
||||||
|
template <>
|
||||||
|
FSCDirEntry MemStreamReader::readBE<FSCDirEntry>();
|
||||||
|
template <>
|
||||||
|
FSCVirtualFile::FSCDirIteratorState MemStreamReader::readBE<FSCVirtualFile::FSCDirIteratorState>();
|
||||||
|
template <>
|
||||||
|
void MemStreamWriter::writeBE<FSCVirtualFile::FSCDirIteratorState>(const FSCVirtualFile::FSCDirIteratorState& v);
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void MemStreamWriter::writeBE<iosu::fsa::_FSAHandleTable>(const iosu::fsa::_FSAHandleTable& v)
|
||||||
|
{
|
||||||
|
writeBE(v.m_currentCounter);
|
||||||
|
for (int i = 0; i < 0x3C0; i++)
|
||||||
|
{
|
||||||
|
writeBE(v.m_handleTable[i].handleCheckValue);
|
||||||
|
writeBE(v.m_handleTable[i].isAllocated);
|
||||||
|
writeBE(v.m_handleTable[i].fscFile != nullptr);
|
||||||
|
if (v.m_handleTable[i].fscFile != nullptr) v.m_handleTable[i].fscFile->Save(*this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
iosu::fsa::_FSAHandleTable MemStreamReader::readBE<iosu::fsa::_FSAHandleTable>()
|
||||||
|
{
|
||||||
|
iosu::fsa::_FSAHandleTable table{};
|
||||||
|
table.m_currentCounter = readBE<uint32>();
|
||||||
|
for (int i = 0; i < 0x3C0; i++)
|
||||||
|
{
|
||||||
|
table.m_handleTable[i].handleCheckValue = readBE<uint16>();
|
||||||
|
table.m_handleTable[i].isAllocated = readBE<bool>();
|
||||||
|
if (readBE<bool>()) table.m_handleTable[i].fscFile = FSCVirtualFile::Restore(*this);
|
||||||
|
}
|
||||||
|
return table;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void MemStreamWriter::writeBE<FSCVirtualFile::FSCDirIteratorState>(const FSCVirtualFile::FSCDirIteratorState& v)
|
||||||
|
{
|
||||||
|
writeBE(v.index);
|
||||||
|
writeBE(v.dirEntries.size());
|
||||||
|
for (int i = 0; i < v.dirEntries.size(); i++)
|
||||||
|
{
|
||||||
|
writeBE(v.dirEntries[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void MemStreamWriter::writeBE<FSCDirEntry>(const FSCDirEntry& v)
|
||||||
|
{
|
||||||
|
writeData(v.path, FSC_MAX_DIR_NAME_LENGTH);
|
||||||
|
writeBE(v.isDirectory);
|
||||||
|
writeBE(v.isFile);
|
||||||
|
writeBE(v.fileSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
FSCDirEntry MemStreamReader::readBE<FSCDirEntry>()
|
||||||
|
{
|
||||||
|
FSCDirEntry entry{};
|
||||||
|
readData(entry.path, FSC_MAX_DIR_NAME_LENGTH);
|
||||||
|
entry.isDirectory = readBE<bool>();
|
||||||
|
entry.isFile = readBE<bool>();
|
||||||
|
entry.fileSize = readBE<uint32>();
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
FSCVirtualFile::FSCDirIteratorState MemStreamReader::readBE<FSCVirtualFile::FSCDirIteratorState>()
|
||||||
|
{
|
||||||
|
FSCVirtualFile::FSCDirIteratorState state{};
|
||||||
|
state.index = readBE<sint32>();
|
||||||
|
size_t size = readBE<size_t>();
|
||||||
|
for (size_t i = 0; i < size; i++)
|
||||||
|
{
|
||||||
|
state.dirEntries[i] = readBE<FSCDirEntry>();
|
||||||
|
}
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace iosu::fsa
|
||||||
|
{
|
||||||
|
|
||||||
|
void Save(MemStreamWriter& writer)
|
||||||
|
{
|
||||||
|
writer.writeBE(sFSAIoMsgQueue);
|
||||||
|
for (size_t i = 0; i < 352; i++)
|
||||||
|
{
|
||||||
|
writer.writeBE(_m_sFSAIoMsgQueueMsgBuffer[i]);
|
||||||
|
}
|
||||||
|
writer.writeBE(sDirHandleTable);
|
||||||
|
writer.writeBE(sFileHandleTable);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Restore(MemStreamReader& reader)
|
||||||
|
{
|
||||||
|
sFSAIoMsgQueue = reader.readBE<IOSMsgQueueId>();
|
||||||
|
for (size_t i = 0; i < 352; i++)
|
||||||
|
{
|
||||||
|
_m_sFSAIoMsgQueueMsgBuffer[i] = reader.readBE<iosu::kernel::IOSMessage>();
|
||||||
|
}
|
||||||
|
sDirHandleTable = reader.readBE<_FSAHandleTable>();
|
||||||
|
sFileHandleTable = reader.readBE<_FSAHandleTable>();
|
||||||
|
}
|
||||||
|
}
|
|
@ -213,5 +213,8 @@ namespace iosu
|
||||||
|
|
||||||
void Initialize();
|
void Initialize();
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
|
|
||||||
|
void Save(MemStreamWriter& writer);
|
||||||
|
void Restore(MemStreamReader& reader);
|
||||||
} // namespace fsa
|
} // namespace fsa
|
||||||
} // namespace iosu
|
} // namespace iosu
|
||||||
|
|
|
@ -2638,6 +2638,16 @@ namespace coreinit
|
||||||
return FSA_RESULT::OK;
|
return FSA_RESULT::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FSSave(MemStreamWriter& s)
|
||||||
|
{
|
||||||
|
s.writeData(g_fsRegisteredClientBodies, sizeof(FSClientBody_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
void FSRestore(MemStreamReader& s)
|
||||||
|
{
|
||||||
|
s.readData(g_fsRegisteredClientBodies, sizeof(FSClientBody_t));
|
||||||
|
}
|
||||||
|
|
||||||
void InitializeFS()
|
void InitializeFS()
|
||||||
{
|
{
|
||||||
cafeExportRegister("coreinit", FSInit, LogType::CoreinitFile);
|
cafeExportRegister("coreinit", FSInit, LogType::CoreinitFile);
|
||||||
|
|
|
@ -308,5 +308,8 @@ namespace coreinit
|
||||||
|
|
||||||
FS_VOLSTATE FSGetVolumeState(FSClient_t* fsClient);
|
FS_VOLSTATE FSGetVolumeState(FSClient_t* fsClient);
|
||||||
|
|
||||||
|
void FSSave(MemStreamWriter& s);
|
||||||
|
void FSRestore(MemStreamReader& s);
|
||||||
|
|
||||||
void InitializeFS();
|
void InitializeFS();
|
||||||
}; // namespace coreinit
|
}; // namespace coreinit
|
||||||
|
|
|
@ -198,6 +198,65 @@ namespace coreinit
|
||||||
return __currentCoreThread[currentInstance->spr.UPIR];
|
return __currentCoreThread[currentInstance->spr.UPIR];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SuspendAllThreads()
|
||||||
|
{
|
||||||
|
for (auto& thr : activeThread)
|
||||||
|
{
|
||||||
|
auto* ptr = (OSThread_t*)memory_getPointerFromVirtualOffset(thr);
|
||||||
|
if (thr != 0)
|
||||||
|
{
|
||||||
|
OSSuspendThread(ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (__currentCoreThread[0])
|
||||||
|
OSSuspendThread(__currentCoreThread[0]);
|
||||||
|
if (__currentCoreThread[1])
|
||||||
|
OSSuspendThread(__currentCoreThread[1]);
|
||||||
|
if (__currentCoreThread[2])
|
||||||
|
OSSuspendThread(__currentCoreThread[2]);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResumeAllThreads(bool* runningThreads)
|
||||||
|
{
|
||||||
|
for (auto& thr : activeThread)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
auto* ptr = (OSThread_t*)memory_getPointerFromVirtualOffset(thr);
|
||||||
|
if (thr != 0)
|
||||||
|
{
|
||||||
|
if (runningThreads && runningThreads[i])
|
||||||
|
{
|
||||||
|
if (s_threadToFiber.find(ptr) == s_threadToFiber.end())
|
||||||
|
__OSCreateHostThread(ptr);
|
||||||
|
OSResumeThread(ptr);
|
||||||
|
}
|
||||||
|
else if (!runningThreads)
|
||||||
|
{
|
||||||
|
if (s_threadToFiber.find(ptr) == s_threadToFiber.end())
|
||||||
|
__OSCreateHostThread(ptr);
|
||||||
|
OSResumeThread(ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
if (__currentCoreThread[0])
|
||||||
|
OSResumeThread(__currentCoreThread[0]);
|
||||||
|
if (__currentCoreThread[1])
|
||||||
|
OSResumeThread(__currentCoreThread[1]);
|
||||||
|
if (__currentCoreThread[2])
|
||||||
|
OSResumeThread(__currentCoreThread[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<OSThread_t*> GetAllThreads()
|
||||||
|
{
|
||||||
|
auto ret = std::vector<OSThread_t*>();
|
||||||
|
ret.push_back(__currentCoreThread[0]);
|
||||||
|
ret.push_back(__currentCoreThread[1]);
|
||||||
|
ret.push_back(__currentCoreThread[2]);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
MPTR funcPtr_threadEntry = 0;
|
MPTR funcPtr_threadEntry = 0;
|
||||||
|
|
||||||
void threadEntry(PPCInterpreter_t* hCPU)
|
void threadEntry(PPCInterpreter_t* hCPU)
|
||||||
|
|
|
@ -524,6 +524,9 @@ namespace coreinit
|
||||||
|
|
||||||
sint32 __OSResumeThreadInternal(OSThread_t* thread, sint32 resumeCount);
|
sint32 __OSResumeThreadInternal(OSThread_t* thread, sint32 resumeCount);
|
||||||
sint32 OSResumeThread(OSThread_t* thread);
|
sint32 OSResumeThread(OSThread_t* thread);
|
||||||
|
void SuspendAllThreads();
|
||||||
|
void ResumeAllThreads(bool* runningThreads);
|
||||||
|
std::vector<OSThread_t*> GetAllThreads();
|
||||||
void OSContinueThread(OSThread_t* thread);
|
void OSContinueThread(OSThread_t* thread);
|
||||||
void __OSSuspendThreadInternal(OSThread_t* thread);
|
void __OSSuspendThreadInternal(OSThread_t* thread);
|
||||||
void __OSSuspendThreadNolock(OSThread_t* thread);
|
void __OSSuspendThreadNolock(OSThread_t* thread);
|
||||||
|
|
|
@ -83,6 +83,8 @@ enum
|
||||||
MAINFRAME_MENU_ID_FILE_LOAD = 20100,
|
MAINFRAME_MENU_ID_FILE_LOAD = 20100,
|
||||||
MAINFRAME_MENU_ID_FILE_INSTALL_UPDATE,
|
MAINFRAME_MENU_ID_FILE_INSTALL_UPDATE,
|
||||||
MAINFRAME_MENU_ID_FILE_OPEN_CEMU_FOLDER,
|
MAINFRAME_MENU_ID_FILE_OPEN_CEMU_FOLDER,
|
||||||
|
MAINFRAME_MENU_ID_FILE_SAVESTATE,
|
||||||
|
MAINFRAME_MENU_ID_FILE_LOADSTATE,
|
||||||
MAINFRAME_MENU_ID_FILE_EXIT,
|
MAINFRAME_MENU_ID_FILE_EXIT,
|
||||||
MAINFRAME_MENU_ID_FILE_END_EMULATION,
|
MAINFRAME_MENU_ID_FILE_END_EMULATION,
|
||||||
MAINFRAME_MENU_ID_FILE_RECENT_0,
|
MAINFRAME_MENU_ID_FILE_RECENT_0,
|
||||||
|
@ -131,6 +133,13 @@ enum
|
||||||
MAINFRAME_MENU_ID_NFC_TOUCH_NFC_FILE = 21000,
|
MAINFRAME_MENU_ID_NFC_TOUCH_NFC_FILE = 21000,
|
||||||
MAINFRAME_MENU_ID_NFC_RECENT_0,
|
MAINFRAME_MENU_ID_NFC_RECENT_0,
|
||||||
MAINFRAME_MENU_ID_NFC_RECENT_LAST = MAINFRAME_MENU_ID_NFC_RECENT_0 + 15,
|
MAINFRAME_MENU_ID_NFC_RECENT_LAST = MAINFRAME_MENU_ID_NFC_RECENT_0 + 15,
|
||||||
|
|
||||||
|
// savestates
|
||||||
|
MAINFRAME_MENU_ID_SAVESTATES_PAUSE_TITLE,
|
||||||
|
MAINFRAME_MENU_ID_SAVESTATES_RESUME_TITLE,
|
||||||
|
MAINFRAME_MENU_ID_SAVESTATES_SAVE_STATE,
|
||||||
|
MAINFRAME_MENU_ID_SAVESTATES_LOAD_STATE,
|
||||||
|
|
||||||
// debug
|
// debug
|
||||||
MAINFRAME_MENU_ID_DEBUG_RENDER_UPSIDE_DOWN = 21100,
|
MAINFRAME_MENU_ID_DEBUG_RENDER_UPSIDE_DOWN = 21100,
|
||||||
MAINFRAME_MENU_ID_DEBUG_VIEW_LOGGING_WINDOW,
|
MAINFRAME_MENU_ID_DEBUG_VIEW_LOGGING_WINDOW,
|
||||||
|
@ -174,6 +183,7 @@ EVT_MOVE(MainWindow::OnMove)
|
||||||
EVT_MENU(MAINFRAME_MENU_ID_FILE_LOAD, MainWindow::OnFileMenu)
|
EVT_MENU(MAINFRAME_MENU_ID_FILE_LOAD, MainWindow::OnFileMenu)
|
||||||
EVT_MENU(MAINFRAME_MENU_ID_FILE_INSTALL_UPDATE, MainWindow::OnInstallUpdate)
|
EVT_MENU(MAINFRAME_MENU_ID_FILE_INSTALL_UPDATE, MainWindow::OnInstallUpdate)
|
||||||
EVT_MENU(MAINFRAME_MENU_ID_FILE_OPEN_CEMU_FOLDER, MainWindow::OnOpenCemuFolder)
|
EVT_MENU(MAINFRAME_MENU_ID_FILE_OPEN_CEMU_FOLDER, MainWindow::OnOpenCemuFolder)
|
||||||
|
|
||||||
EVT_MENU(MAINFRAME_MENU_ID_FILE_EXIT, MainWindow::OnFileExit)
|
EVT_MENU(MAINFRAME_MENU_ID_FILE_EXIT, MainWindow::OnFileExit)
|
||||||
EVT_MENU(MAINFRAME_MENU_ID_FILE_END_EMULATION, MainWindow::OnFileMenu)
|
EVT_MENU(MAINFRAME_MENU_ID_FILE_END_EMULATION, MainWindow::OnFileMenu)
|
||||||
EVT_MENU_RANGE(MAINFRAME_MENU_ID_FILE_RECENT_0 + 0, MAINFRAME_MENU_ID_FILE_RECENT_LAST, MainWindow::OnFileMenu)
|
EVT_MENU_RANGE(MAINFRAME_MENU_ID_FILE_RECENT_0 + 0, MAINFRAME_MENU_ID_FILE_RECENT_LAST, MainWindow::OnFileMenu)
|
||||||
|
@ -204,6 +214,11 @@ EVT_MENU(MAINFRAME_MENU_ID_TIMER_SPEED_0125X, MainWindow::OnDebugSetting)
|
||||||
// nfc menu
|
// nfc menu
|
||||||
EVT_MENU(MAINFRAME_MENU_ID_NFC_TOUCH_NFC_FILE, MainWindow::OnNFCMenu)
|
EVT_MENU(MAINFRAME_MENU_ID_NFC_TOUCH_NFC_FILE, MainWindow::OnNFCMenu)
|
||||||
EVT_MENU_RANGE(MAINFRAME_MENU_ID_NFC_RECENT_0 + 0, MAINFRAME_MENU_ID_NFC_RECENT_LAST, MainWindow::OnNFCMenu)
|
EVT_MENU_RANGE(MAINFRAME_MENU_ID_NFC_RECENT_0 + 0, MAINFRAME_MENU_ID_NFC_RECENT_LAST, MainWindow::OnNFCMenu)
|
||||||
|
// savestates menu
|
||||||
|
EVT_MENU(MAINFRAME_MENU_ID_SAVESTATES_PAUSE_TITLE, MainWindow::OnSavestatesMenu)
|
||||||
|
EVT_MENU(MAINFRAME_MENU_ID_SAVESTATES_RESUME_TITLE, MainWindow::OnSavestatesMenu)
|
||||||
|
EVT_MENU(MAINFRAME_MENU_ID_SAVESTATES_SAVE_STATE, MainWindow::OnSavestatesMenu)
|
||||||
|
EVT_MENU(MAINFRAME_MENU_ID_SAVESTATES_LOAD_STATE, MainWindow::OnSavestatesMenu)
|
||||||
// debug -> logging menu
|
// debug -> logging menu
|
||||||
EVT_MENU_RANGE(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + 0, MAINFRAME_MENU_ID_DEBUG_LOGGING0 + 98, MainWindow::OnDebugLoggingToggleFlagGeneric)
|
EVT_MENU_RANGE(MAINFRAME_MENU_ID_DEBUG_LOGGING0 + 0, MAINFRAME_MENU_ID_DEBUG_LOGGING0 + 98, MainWindow::OnDebugLoggingToggleFlagGeneric)
|
||||||
EVT_MENU(MAINFRAME_MENU_ID_DEBUG_ADVANCED_PPC_INFO, MainWindow::OnPPCInfoToggle)
|
EVT_MENU(MAINFRAME_MENU_ID_DEBUG_ADVANCED_PPC_INFO, MainWindow::OnPPCInfoToggle)
|
||||||
|
@ -778,6 +793,27 @@ void MainWindow::OnNFCMenu(wxCommandEvent& event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::OnSavestatesMenu(wxCommandEvent& event)
|
||||||
|
{
|
||||||
|
const auto menuId = event.GetId();
|
||||||
|
if (menuId == MAINFRAME_MENU_ID_SAVESTATES_PAUSE_TITLE)
|
||||||
|
{
|
||||||
|
CafeSystem::PauseTitle();
|
||||||
|
}
|
||||||
|
if (menuId == MAINFRAME_MENU_ID_SAVESTATES_RESUME_TITLE)
|
||||||
|
{
|
||||||
|
CafeSystem::ResumeTitle();
|
||||||
|
}
|
||||||
|
else if (menuId == MAINFRAME_MENU_ID_SAVESTATES_SAVE_STATE)
|
||||||
|
{
|
||||||
|
CafeSystem::SaveState("state.bin");
|
||||||
|
}
|
||||||
|
else if (menuId == MAINFRAME_MENU_ID_SAVESTATES_LOAD_STATE)
|
||||||
|
{
|
||||||
|
CafeSystem::LoadState("state.bin");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::OnFileExit(wxCommandEvent& event)
|
void MainWindow::OnFileExit(wxCommandEvent& event)
|
||||||
{
|
{
|
||||||
// todo: Safely clean up everything
|
// todo: Safely clean up everything
|
||||||
|
@ -2184,6 +2220,16 @@ void MainWindow::RecreateMenu()
|
||||||
nfcMenu->Append(MAINFRAME_MENU_ID_NFC_TOUCH_NFC_FILE, _("&Scan NFC tag from file"))->Enable(false);
|
nfcMenu->Append(MAINFRAME_MENU_ID_NFC_TOUCH_NFC_FILE, _("&Scan NFC tag from file"))->Enable(false);
|
||||||
m_menuBar->Append(nfcMenu, _("&NFC"));
|
m_menuBar->Append(nfcMenu, _("&NFC"));
|
||||||
m_nfcMenuSeparator0 = nullptr;
|
m_nfcMenuSeparator0 = nullptr;
|
||||||
|
|
||||||
|
// savestates menu
|
||||||
|
wxMenu* savestatesMenu = new wxMenu;
|
||||||
|
savestatesMenu->Append(MAINFRAME_MENU_ID_SAVESTATES_PAUSE_TITLE, _("&Pause"), wxEmptyString);
|
||||||
|
savestatesMenu->Append(MAINFRAME_MENU_ID_SAVESTATES_RESUME_TITLE, _("&Resume"), wxEmptyString);
|
||||||
|
savestatesMenu->AppendSeparator();
|
||||||
|
savestatesMenu->Append(MAINFRAME_MENU_ID_SAVESTATES_SAVE_STATE, _("&Save state"), wxEmptyString);
|
||||||
|
savestatesMenu->Append(MAINFRAME_MENU_ID_SAVESTATES_LOAD_STATE, _("&Load state"), wxEmptyString);
|
||||||
|
m_menuBar->Append(savestatesMenu, _("&Savestates"));
|
||||||
|
|
||||||
// debug->logging submenu
|
// debug->logging submenu
|
||||||
wxMenu* debugLoggingMenu = new wxMenu;
|
wxMenu* debugLoggingMenu = new wxMenu;
|
||||||
|
|
||||||
|
|
|
@ -93,6 +93,7 @@ public:
|
||||||
void OnInstallUpdate(wxCommandEvent& event);
|
void OnInstallUpdate(wxCommandEvent& event);
|
||||||
void OnFileExit(wxCommandEvent& event);
|
void OnFileExit(wxCommandEvent& event);
|
||||||
void OnNFCMenu(wxCommandEvent& event);
|
void OnNFCMenu(wxCommandEvent& event);
|
||||||
|
void OnSavestatesMenu(wxCommandEvent& event);
|
||||||
void OnOptionsInput(wxCommandEvent& event);
|
void OnOptionsInput(wxCommandEvent& event);
|
||||||
void OnAccountSelect(wxCommandEvent& event);
|
void OnAccountSelect(wxCommandEvent& event);
|
||||||
void OnConsoleLanguage(wxCommandEvent& event);
|
void OnConsoleLanguage(wxCommandEvent& event);
|
||||||
|
@ -227,6 +228,12 @@ private:
|
||||||
wxMenu* m_nfcMenu;
|
wxMenu* m_nfcMenu;
|
||||||
wxMenuItem* m_nfcMenuSeparator0;
|
wxMenuItem* m_nfcMenuSeparator0;
|
||||||
|
|
||||||
|
// savestates
|
||||||
|
//wxMenuItem* m_pause;
|
||||||
|
//wxMenuItem* m_resume;
|
||||||
|
//wxMenuItem* m_saveState;
|
||||||
|
//wxMenuItem* m_loadState;
|
||||||
|
|
||||||
// debug
|
// debug
|
||||||
wxMenu* m_debugMenu;
|
wxMenu* m_debugMenu;
|
||||||
wxMenu* m_loggingSubmenu;
|
wxMenu* m_loggingSubmenu;
|
||||||
|
|
|
@ -36,6 +36,19 @@ uint32 MemStreamReader::readBE()
|
||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
sint32 MemStreamReader::readBE()
|
||||||
|
{
|
||||||
|
if (!reserveReadLength(sizeof(sint32)))
|
||||||
|
return 0;
|
||||||
|
const uint8* p = m_data + m_cursorPos;
|
||||||
|
sint32 v;
|
||||||
|
std::memcpy(&v, p, sizeof(v));
|
||||||
|
v = _BE(v);
|
||||||
|
m_cursorPos += sizeof(sint32);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
uint64 MemStreamReader::readBE()
|
uint64 MemStreamReader::readBE()
|
||||||
{
|
{
|
||||||
|
@ -117,6 +130,14 @@ void MemStreamWriter::writeBE<uint32>(const uint32& v)
|
||||||
std::memcpy(p, &tmp, sizeof(tmp));
|
std::memcpy(p, &tmp, sizeof(tmp));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
void MemStreamWriter::writeBE<sint32>(const sint32& v)
|
||||||
|
{
|
||||||
|
m_buffer.resize(m_buffer.size() + 4);
|
||||||
|
uint8* p = m_buffer.data() + m_buffer.size() - 4;
|
||||||
|
uint32 tmp = _BE(v);
|
||||||
|
std::memcpy(p, &tmp, sizeof(tmp));
|
||||||
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
void MemStreamWriter::writeBE<uint16>(const uint16& v)
|
void MemStreamWriter::writeBE<uint16>(const uint16& v)
|
||||||
|
@ -134,6 +155,19 @@ void MemStreamWriter::writeBE<uint8>(const uint8& v)
|
||||||
m_buffer.emplace_back(v);
|
m_buffer.emplace_back(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
void MemStreamWriter::writeBE<bool>(const bool& v)
|
||||||
|
{
|
||||||
|
writeData(&v, sizeof(bool));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<>
|
||||||
|
bool MemStreamReader::readBE<bool>()
|
||||||
|
{
|
||||||
|
bool v{ false };
|
||||||
|
readData(&v, sizeof(bool));
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
void MemStreamWriter::writeBE<std::string>(const std::string& v)
|
void MemStreamWriter::writeBE<std::string>(const std::string& v)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue