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
|
||||
#include "gui/guiWrapper.h"
|
||||
|
||||
#include "Cafe/OS/libs/coreinit/coreinit_FS.h"
|
||||
|
||||
std::string _pathToExecutable;
|
||||
std::string _pathToBaseExecutable;
|
||||
|
||||
|
@ -792,6 +794,99 @@ namespace CafeSystem
|
|||
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 */
|
||||
|
||||
void InitVirtualMlcStorage()
|
||||
|
|
|
@ -30,6 +30,12 @@ namespace CafeSystem
|
|||
|
||||
void ShutdownTitle();
|
||||
|
||||
void PauseTitle();
|
||||
void ResumeTitle(bool* runningThreads = nullptr);
|
||||
|
||||
void SaveState(std::string path);
|
||||
void LoadState(std::string path);
|
||||
|
||||
std::string GetMlcStoragePath(TitleId titleId);
|
||||
void MlcStorageMountAllTitles();
|
||||
|
||||
|
|
|
@ -269,6 +269,8 @@ FSCMountPathNode* fsc_lookupPathVirtualNode(const char* path, sint32 priority)
|
|||
class FSCVirtualFileDirectoryIterator : public FSCVirtualFile
|
||||
{
|
||||
public:
|
||||
void Save(MemStreamWriter& writer) override;
|
||||
|
||||
sint32 fscGetType() override
|
||||
{
|
||||
return FSC_TYPE_DIRECTORY;
|
||||
|
@ -717,3 +719,59 @@ void fsc_init()
|
|||
{
|
||||
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
|
||||
{
|
||||
enum class Child : uint32
|
||||
{
|
||||
DIRECTORY_ITERATOR, HOST, WUACTX, WUDCTX, NONE
|
||||
};
|
||||
|
||||
struct FSCDirIteratorState
|
||||
{
|
||||
sint32 index;
|
||||
std::vector<FSCDirEntry> dirEntries;
|
||||
};
|
||||
|
||||
virtual void Save(MemStreamWriter& writer);
|
||||
static FSCVirtualFile* Restore(MemStreamReader& reader);
|
||||
|
||||
FSCVirtualFile()
|
||||
{
|
||||
|
||||
|
|
|
@ -157,6 +157,19 @@ bool FSCVirtualFile_Host::fscDirNext(FSCDirEntry* dirEntry)
|
|||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
FSCVirtualFile_Host* vf = new FSCVirtualFile_Host(FSC_TYPE_FILE);
|
||||
vf->m_path.reset(new std::filesystem::path(path));
|
||||
vf->m_fs = fs;
|
||||
vf->m_isWritable = writeAccessRequested;
|
||||
vf->m_fileSize = fs->GetSize();
|
||||
vf->m_accessFlags = accessFlags;
|
||||
fscStatus = FSC_STATUS_OK;
|
||||
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);
|
||||
vf->m_path.reset(new std::filesystem::path(path));
|
||||
vf->m_accessFlags = accessFlags;
|
||||
fscStatus = FSC_STATUS_OK;
|
||||
return vf;
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
class FSCVirtualFile_Host : public FSCVirtualFile
|
||||
{
|
||||
public:
|
||||
void Save(MemStreamWriter& writer) override;
|
||||
static FSCVirtualFile* OpenFile(const fs::path& path, FSC_ACCESS_FLAG accessFlags, sint32& fscStatus);
|
||||
~FSCVirtualFile_Host() override;
|
||||
|
||||
|
@ -31,4 +32,6 @@ private:
|
|||
// directory
|
||||
std::unique_ptr<std::filesystem::path> m_path{};
|
||||
std::unique_ptr<std::filesystem::directory_iterator> m_dirIterator{};
|
||||
// serialization
|
||||
FSC_ACCESS_FLAG m_accessFlags;
|
||||
};
|
|
@ -15,6 +15,11 @@ protected:
|
|||
};
|
||||
|
||||
public:
|
||||
void Save(MemStreamWriter& writer) override
|
||||
{
|
||||
throw std::exception("Not implemented");
|
||||
}
|
||||
|
||||
sint32 fscGetType() override
|
||||
{
|
||||
return m_fscType;
|
||||
|
|
|
@ -22,6 +22,11 @@ protected:
|
|||
}
|
||||
|
||||
public:
|
||||
void Save(MemStreamWriter& writer) override
|
||||
{
|
||||
throw std::exception("Not implemented");
|
||||
}
|
||||
|
||||
sint32 fscGetType() override
|
||||
{
|
||||
return m_fscType;
|
||||
|
|
|
@ -80,6 +80,66 @@ MMURange* memory_getMMURangeByAddress(MPTR address)
|
|||
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)
|
||||
{
|
||||
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
|
||||
{
|
||||
// MMIO access handler
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "util/helpers/Serializer.h"
|
||||
|
||||
void memory_init();
|
||||
void memory_mapForCurrentTitle();
|
||||
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
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
void mapMem();
|
||||
|
@ -107,14 +112,16 @@ struct MMURange
|
|||
bool isOptional() const { return (flags & MFLAG::FLAG_OPTIONAL) != 0; };
|
||||
bool isMappedEarly() const { return (flags & MFLAG::FLAG_MAP_EARLY) != 0; };
|
||||
|
||||
const uint32 baseAddress;
|
||||
const uint32 initSize; // initial size
|
||||
const std::string name;
|
||||
const MFLAG flags;
|
||||
const MMU_MEM_AREA_ID areaId;
|
||||
uint32 baseAddress;
|
||||
uint32 initSize; // initial size
|
||||
std::string name;
|
||||
MFLAG flags;
|
||||
MMU_MEM_AREA_ID areaId;
|
||||
// runtime parameters
|
||||
uint32 size;
|
||||
bool m_isMapped{};
|
||||
friend class MemStreamWriter;
|
||||
friend class MemStreamReader;
|
||||
};
|
||||
|
||||
|
||||
|
@ -202,6 +209,9 @@ uint8 memory_readU8(uint32 address);
|
|||
|
||||
void memory_createDump();
|
||||
|
||||
void memory_Serialize(MemStreamWriter& s);
|
||||
void memory_Deserialize(MemStreamReader& s);
|
||||
|
||||
template<size_t count>
|
||||
void memory_readBytes(VAddr address, std::array<uint8, count>& buffer)
|
||||
{
|
||||
|
|
|
@ -169,6 +169,8 @@ namespace iosu
|
|||
}
|
||||
|
||||
class _FSAHandleTable {
|
||||
friend class MemStreamWriter;
|
||||
friend class MemStreamReader;
|
||||
struct _FSAHandleResource
|
||||
{
|
||||
bool isAllocated{false};
|
||||
|
@ -904,3 +906,109 @@ namespace iosu
|
|||
}
|
||||
} // namespace fsa
|
||||
} // 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 Shutdown();
|
||||
|
||||
void Save(MemStreamWriter& writer);
|
||||
void Restore(MemStreamReader& reader);
|
||||
} // namespace fsa
|
||||
} // namespace iosu
|
||||
|
|
|
@ -2638,6 +2638,16 @@ namespace coreinit
|
|||
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()
|
||||
{
|
||||
cafeExportRegister("coreinit", FSInit, LogType::CoreinitFile);
|
||||
|
|
|
@ -308,5 +308,8 @@ namespace coreinit
|
|||
|
||||
FS_VOLSTATE FSGetVolumeState(FSClient_t* fsClient);
|
||||
|
||||
void FSSave(MemStreamWriter& s);
|
||||
void FSRestore(MemStreamReader& s);
|
||||
|
||||
void InitializeFS();
|
||||
}; // namespace coreinit
|
||||
|
|
|
@ -198,6 +198,65 @@ namespace coreinit
|
|||
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;
|
||||
|
||||
void threadEntry(PPCInterpreter_t* hCPU)
|
||||
|
|
|
@ -524,6 +524,9 @@ namespace coreinit
|
|||
|
||||
sint32 __OSResumeThreadInternal(OSThread_t* thread, sint32 resumeCount);
|
||||
sint32 OSResumeThread(OSThread_t* thread);
|
||||
void SuspendAllThreads();
|
||||
void ResumeAllThreads(bool* runningThreads);
|
||||
std::vector<OSThread_t*> GetAllThreads();
|
||||
void OSContinueThread(OSThread_t* thread);
|
||||
void __OSSuspendThreadInternal(OSThread_t* thread);
|
||||
void __OSSuspendThreadNolock(OSThread_t* thread);
|
||||
|
|
|
@ -83,6 +83,8 @@ enum
|
|||
MAINFRAME_MENU_ID_FILE_LOAD = 20100,
|
||||
MAINFRAME_MENU_ID_FILE_INSTALL_UPDATE,
|
||||
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_END_EMULATION,
|
||||
MAINFRAME_MENU_ID_FILE_RECENT_0,
|
||||
|
@ -131,6 +133,13 @@ enum
|
|||
MAINFRAME_MENU_ID_NFC_TOUCH_NFC_FILE = 21000,
|
||||
MAINFRAME_MENU_ID_NFC_RECENT_0,
|
||||
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
|
||||
MAINFRAME_MENU_ID_DEBUG_RENDER_UPSIDE_DOWN = 21100,
|
||||
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_INSTALL_UPDATE, MainWindow::OnInstallUpdate)
|
||||
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_END_EMULATION, 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
|
||||
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)
|
||||
// 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
|
||||
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)
|
||||
|
@ -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)
|
||||
{
|
||||
// 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);
|
||||
m_menuBar->Append(nfcMenu, _("&NFC"));
|
||||
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
|
||||
wxMenu* debugLoggingMenu = new wxMenu;
|
||||
|
||||
|
|
|
@ -93,6 +93,7 @@ public:
|
|||
void OnInstallUpdate(wxCommandEvent& event);
|
||||
void OnFileExit(wxCommandEvent& event);
|
||||
void OnNFCMenu(wxCommandEvent& event);
|
||||
void OnSavestatesMenu(wxCommandEvent& event);
|
||||
void OnOptionsInput(wxCommandEvent& event);
|
||||
void OnAccountSelect(wxCommandEvent& event);
|
||||
void OnConsoleLanguage(wxCommandEvent& event);
|
||||
|
@ -227,6 +228,12 @@ private:
|
|||
wxMenu* m_nfcMenu;
|
||||
wxMenuItem* m_nfcMenuSeparator0;
|
||||
|
||||
// savestates
|
||||
//wxMenuItem* m_pause;
|
||||
//wxMenuItem* m_resume;
|
||||
//wxMenuItem* m_saveState;
|
||||
//wxMenuItem* m_loadState;
|
||||
|
||||
// debug
|
||||
wxMenu* m_debugMenu;
|
||||
wxMenu* m_loggingSubmenu;
|
||||
|
|
|
@ -36,6 +36,19 @@ uint32 MemStreamReader::readBE()
|
|||
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<>
|
||||
uint64 MemStreamReader::readBE()
|
||||
{
|
||||
|
@ -117,6 +130,14 @@ void MemStreamWriter::writeBE<uint32>(const uint32& v)
|
|||
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<>
|
||||
void MemStreamWriter::writeBE<uint16>(const uint16& v)
|
||||
|
@ -134,6 +155,19 @@ void MemStreamWriter::writeBE<uint8>(const uint8& 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<>
|
||||
void MemStreamWriter::writeBE<std::string>(const std::string& v)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue