diff --git a/soh/include/z64.h b/soh/include/z64.h
index 103c8650f..7720144b4 100644
--- a/soh/include/z64.h
+++ b/soh/include/z64.h
@@ -30,6 +30,9 @@
#include "ichain.h"
#include "regs.h"
+#define AUDIO_HEAP_SIZE 0x38000
+#define SYSTEM_HEAP_SIZE (1024 * 1024 * 4)
+
#ifdef __cplusplus
namespace Ship
{
diff --git a/soh/soh.vcxproj b/soh/soh.vcxproj
index c3419d7cb..fd4f3a755 100644
--- a/soh/soh.vcxproj
+++ b/soh/soh.vcxproj
@@ -932,6 +932,7 @@
+
@@ -1411,4 +1412,4 @@
-
+
\ No newline at end of file
diff --git a/soh/soh.vcxproj.filters b/soh/soh.vcxproj.filters
index 4f77fdb7c..ae812a509 100644
--- a/soh/soh.vcxproj.filters
+++ b/soh/soh.vcxproj.filters
@@ -3751,6 +3751,8 @@
Header Files\soh\Enhancements\debugger
+
+ Source Files\soh
diff --git a/soh/soh/Enhancements/debugconsole.cpp b/soh/soh/Enhancements/debugconsole.cpp
index 72eea1cd8..e353917f2 100644
--- a/soh/soh/Enhancements/debugconsole.cpp
+++ b/soh/soh/Enhancements/debugconsole.cpp
@@ -307,8 +307,8 @@ static bool EntranceHandler(const std::vector& args) {
}
static bool SaveStateHandler(const std::vector& args) {
- const SaveStateReturn rtn = SaveState::Save(gCurrentSlot);
-
+ const SaveStateReturn rtn = SaveState::RequestSaveState(gCurrentSlot);
+
switch (rtn) {
case SaveStateReturn::SUCCESS:
INFO("[SOH] Saved state to slot %u", gCurrentSlot);
@@ -316,14 +316,11 @@ static bool SaveStateHandler(const std::vector& args) {
case SaveStateReturn::FAIL_INVALID_SLOT:
ERROR("[SOH] Invalid State Slot Number (%u)", gCurrentSlot);
return CMD_FAILED;
- case SaveStateReturn::FAIL_NO_MEMORY:
- ERROR("[SOH] No Memory to save state to slot %u", gCurrentSlot);
- return CMD_FAILED;
}
}
static bool LoadStateHandler(const std::vector& args) {
- const SaveStateReturn rtn = SaveState::Load(gCurrentSlot);
+ const SaveStateReturn rtn = SaveState::RequestLoadState(gCurrentSlot);
switch (rtn) {
case SaveStateReturn::SUCCESS:
diff --git a/soh/soh/Enhancements/savestates.cpp b/soh/soh/Enhancements/savestates.cpp
index 403510fbb..4e7491e8b 100644
--- a/soh/soh/Enhancements/savestates.cpp
+++ b/soh/soh/Enhancements/savestates.cpp
@@ -4,15 +4,21 @@
#include
#include // std::sprintf
+#include
+#include "soh/OTRAudio.h"
+//#include "spdlog/spdlog.h"
//#include "global.h"
//#include
+
//TODO is there a better way?
unsigned int gCurrentSlot = 0;
-static std::array gSaveStates;
+static std::array gSaveStates;
+
+
SaveState::SaveState(){}
SaveState::~SaveState() {}
@@ -77,7 +83,7 @@ SaveStateReturn SaveState::Import(const unsigned int slot) {
if (inFile == nullptr) {
return SaveStateReturn::FAIL_FILE_NOT_OPENED;
}
-
+
std::fseek(inFile, 0, SEEK_END);
const size_t inFileSize = std::ftell(inFile);
@@ -86,7 +92,7 @@ SaveStateReturn SaveState::Import(const unsigned int slot) {
return SaveStateReturn::FAIL_INVALID_SIZE;
}
std::fseek(inFile, 0, SEEK_SET);
-
+
SaveStateHeader tempHeader;
std::fread(&tempHeader, sizeof(SaveStateHeader), 1, inFile);
@@ -96,7 +102,7 @@ SaveStateReturn SaveState::Import(const unsigned int slot) {
}
if (gSaveStates[slot] == nullptr) {
- gSaveStates[slot] = new SaveState;
+ gSaveStates[slot] = new SaveStateInfo;
if (gSaveStates[slot] == nullptr) {
fclose(inFile);
return SaveStateReturn::FAIL_NO_MEMORY;
@@ -104,7 +110,7 @@ SaveStateReturn SaveState::Import(const unsigned int slot) {
}
std::fseek(inFile, 0, SEEK_SET);
- std::fread(gSaveStates[slot], sizeof(SaveState), 1, inFile);
+ std::fread(gSaveStates[slot], sizeof(SaveStateInfo), 1, inFile);
std::fclose(inFile);
//TODO version system
//if (gSaveStates[slot]->stateHeader.stateVersion != 0) {
@@ -115,39 +121,139 @@ SaveStateReturn SaveState::Import(const unsigned int slot) {
}
+void SaveState::BackupSeqScriptState(SaveStateInfo* state) {
+ for (unsigned int i = 0; i < 4; i++) {
+ state->seqScriptStateCopy[i].value = gAudioContext.seqPlayers[i].scriptState.value;
+
+ state->seqScriptStateCopy[i].remLoopIters[0] = gAudioContext.seqPlayers[i].scriptState.remLoopIters[0];
+ state->seqScriptStateCopy[i].remLoopIters[1] = gAudioContext.seqPlayers[i].scriptState.remLoopIters[1];
+ state->seqScriptStateCopy[i].remLoopIters[2] = gAudioContext.seqPlayers[i].scriptState.remLoopIters[2];
+ state->seqScriptStateCopy[i].remLoopIters[3] = gAudioContext.seqPlayers[i].scriptState.remLoopIters[3];
+
+ state->seqScriptStateCopy[i].depth = gAudioContext.seqPlayers[i].scriptState.depth;
+
+ state->seqScriptStateCopy[i].pc = (u8*)((uintptr_t)gAudioContext.seqPlayers[i].scriptState.pc - (uintptr_t)gAudioHeap);
+
+ state->seqScriptStateCopy[i].stack[0] =
+ (u8*)((uintptr_t)gAudioContext.seqPlayers[i].scriptState.stack[0] - (uintptr_t)gAudioHeap);
+ state->seqScriptStateCopy[i].stack[1] =
+ (u8*)((uintptr_t)gAudioContext.seqPlayers[i].scriptState.stack[1] - (uintptr_t)gAudioHeap);
+ state->seqScriptStateCopy[i].stack[2] =
+ (u8*)((uintptr_t)gAudioContext.seqPlayers[i].scriptState.stack[2] - (uintptr_t)gAudioHeap);
+ state->seqScriptStateCopy[i].stack[3] =
+ (u8*)((uintptr_t)gAudioContext.seqPlayers[i].scriptState.stack[3] - (uintptr_t)gAudioHeap);
+ }
+}
+
+void SaveState::LoadSeqScriptState(SaveStateInfo* state) {
+ for (unsigned int i = 0; i < 4; i++) {
+ gAudioContext.seqPlayers[i].scriptState.value = state->seqScriptStateCopy[i].value;
+
+ gAudioContext.seqPlayers[i].scriptState.remLoopIters[0] = state->seqScriptStateCopy[i].remLoopIters[0];
+ gAudioContext.seqPlayers[i].scriptState.remLoopIters[1] = state->seqScriptStateCopy[i].remLoopIters[1];
+ gAudioContext.seqPlayers[i].scriptState.remLoopIters[2] = state->seqScriptStateCopy[i].remLoopIters[2];
+ gAudioContext.seqPlayers[i].scriptState.remLoopIters[3] = state->seqScriptStateCopy[i].remLoopIters[3];
+
+ gAudioContext.seqPlayers[i].scriptState.depth = state->seqScriptStateCopy[i].depth;
+
+ gAudioContext.seqPlayers[i].scriptState.pc =
+ (u8*)((uintptr_t)state->seqScriptStateCopy[i].pc + (uintptr_t)gAudioHeap);
+
+ gAudioContext.seqPlayers[i].scriptState.stack[0] =
+ (u8*)((uintptr_t)state->seqScriptStateCopy[i].stack[0] + (uintptr_t)gAudioHeap);
+ gAudioContext.seqPlayers[i].scriptState.stack[1] =
+ (u8*)((uintptr_t)state->seqScriptStateCopy[i].stack[1] + (uintptr_t)gAudioHeap);
+ gAudioContext.seqPlayers[i].scriptState.stack[2] =
+ (u8*)((uintptr_t)state->seqScriptStateCopy[i].stack[2] + (uintptr_t)gAudioHeap);
+ gAudioContext.seqPlayers[i].scriptState.stack[3] =
+ (u8*)((uintptr_t)state->seqScriptStateCopy[i].stack[3] + (uintptr_t)gAudioHeap);
+
+ }
+}
+
extern "C" MtxF* sMatrixStack;
extern "C" MtxF* sCurrentMatrix;
extern "C" LightsBuffer sLightsBuffer;
extern "C" s16 sWarpTimerTarget;
-extern "C" SaveStateReturn SaveState::Save(const unsigned int slot) {
+std::queue SaveState::requests;
+
+extern "C" void ProcessSaveStateRequests(void) {
+ SaveState::ProcessSaveStateRequestsImpl();
+}
+
+void SaveState::ProcessSaveStateRequestsImpl(void) {
+ while (!requests.empty()) {
+ if (requests.front().type == RequestType::SAVE) {
+ SaveState::Save(requests.front().slot);
+ } else if (requests.front().type == RequestType::LOAD) {
+ SaveState::Load(requests.front().slot);
+ } else {
+ // SPDLOG_ERROR("Invalid Request type for SaveState: {}", requests.front().type);
+ }
+ requests.pop();
+ }
+}
+
+SaveStateReturn SaveState::RequestSaveState(const unsigned int slot) {
if (slot > SaveState::SAVE_SLOT_MAX) {
return SaveStateReturn::FAIL_INVALID_SLOT;
}
if (gSaveStates[slot] == nullptr) {
- gSaveStates[slot] = new SaveState;
+ gSaveStates[slot] = new SaveStateInfo;
if (gSaveStates[slot] == nullptr) {
return SaveStateReturn::FAIL_NO_MEMORY;
}
}
+ SaveState::requests.push({ slot, RequestType::SAVE });
+ return SaveStateReturn::SUCCESS;
+}
+
+extern "C" void SaveState::Save(const unsigned int slot) {
+ std::unique_lock Lock(audio.mutex);
+
+
SaveState::SetHeader(gSaveStates[slot]->stateHeader);
- memcpy(&gSaveStates[slot]->sysHeapCopy, &gSystemHeap, 1024 * 1024 * 4 /* sizeof(gSystemHeap) */);
+ memcpy(&gSaveStates[slot]->sysHeapCopy, gSystemHeap, SYSTEM_HEAP_SIZE /* sizeof(gSystemHeap) */);
+ memcpy(&gSaveStates[slot]->audioHeapCopy, gAudioHeap, AUDIO_HEAP_SIZE /* sizeof(gAudioContext) */);
+
+ memcpy(&gSaveStates[slot]->audioContextCopy, &gAudioContext, sizeof(AudioContext));
+ memcpy(&gSaveStates[slot]->unk_D_8016E750Copy, D_8016E750, sizeof(gSaveStates[slot]->unk_D_8016E750Copy));
+ BackupSeqScriptState(gSaveStates[slot]);
+
+ memcpy(gSaveStates[slot]->gActiveSoundsCopy, gActiveSounds, sizeof(gActiveSounds));
+ memcpy(&gSaveStates[slot]->gSoundBankMutedCopy, gSoundBankMuted, sizeof(gSaveStates[0]->gSoundBankMutedCopy));
+ gSaveStates[slot]->D_801333F0_copy = D_801333F0;
+ gSaveStates[slot]->gAudioSfxSwapOff_copy = gAudioSfxSwapOff;
+
+ memcpy(&gSaveStates[slot]->gAudioSfxSwapSource_copy, gAudioSfxSwapSource,
+ sizeof(gSaveStates[slot]->gAudioSfxSwapSource_copy));
+ memcpy(&gSaveStates[slot]->gAudioSfxSwapTarget_copy, gAudioSfxSwapTarget,
+ sizeof(gSaveStates[slot]->gAudioSfxSwapTarget_copy));
+ memcpy(&gSaveStates[slot]->gAudioSfxSwapMode_copy, gAudioSfxSwapMode,
+ sizeof(&gSaveStates[slot]->gAudioSfxSwapMode_copy));
+
+ gSaveStates[slot]->D_801755D0_copy = D_801755D0;
+
+
+ // gSaveStates[slot]->seqIdCopy[0] = gAudioContext.seqPlayers[0].seqId;
+ // gSaveStates[slot]->seqIdCopy[1] = gAudioContext.seqPlayers[1].seqId;
+ // gSaveStates[slot]->seqIdCopy[2] = gAudioContext.seqPlayers[2].seqId;
+ // gSaveStates[slot]->seqIdCopy[3] = gAudioContext.seqPlayers[3].seqId;
+
+
memcpy(&gSaveStates[slot]->saveContextCopy, &gSaveContext, sizeof(gSaveContext));
memcpy(&gSaveStates[slot]->gameInfoCopy, gGameInfo, sizeof(*gGameInfo));
- // memcpy(&gSaveStates[slot]->audioContextCopy, &gAudioContext, sizeof(AudioContext));
memcpy(&gSaveStates[slot]->lightBufferCopy, &sLightsBuffer, sizeof(sLightsBuffer));
memcpy(&gSaveStates[slot]->mtxStackCopy, &sMatrixStack, sizeof(MtxF) * 20);
memcpy(&gSaveStates[slot]->currentMtxCopy, &sCurrentMatrix, sizeof(MtxF));
gSaveStates[slot]->blueWarpTimerCopy = sWarpTimerTarget;
- //TODO RNG seed
-
- return SaveStateReturn::SUCCESS;
}
-SaveStateReturn SaveState::Load(const unsigned int slot) {
+SaveStateReturn SaveState::RequestLoadState(const unsigned int slot) {
if (slot > SaveState::SAVE_SLOT_MAX) {
return SaveStateReturn::FAIL_INVALID_SLOT;
}
@@ -155,19 +261,50 @@ SaveStateReturn SaveState::Load(const unsigned int slot) {
return SaveStateReturn::FAIL_STATE_EMPTY;
}
+ SaveState::requests.push({ slot, RequestType::LOAD });
+ return SaveStateReturn::SUCCESS;
+}
+
+void SaveState::Load(const unsigned int slot) {
+
+ std::unique_lock Lock(audio.mutex);
+
+
+
//gSaveStates[slot]->stateHeader.gameVersion = 0;
//gSaveStates[slot]->stateHeader.stateVersion = 0;
- memcpy(&gSystemHeap, &gSaveStates[slot]->sysHeapCopy, 1024 * 1024 * 4);
+ memcpy(gSystemHeap, &gSaveStates[slot]->sysHeapCopy, SYSTEM_HEAP_SIZE);
+ memcpy(gAudioHeap, &gSaveStates[slot]->audioHeapCopy, AUDIO_HEAP_SIZE);
+
+ memcpy(&gAudioContext, &gSaveStates[slot]->audioContextCopy, sizeof(AudioContext));
+ memcpy(D_8016E750, &gSaveStates[slot]->unk_D_8016E750Copy, sizeof(gSaveStates[slot]->unk_D_8016E750Copy));
+ LoadSeqScriptState(gSaveStates[slot]);
+ //gAudioContext.seqPlayers[0].seqId = gSaveStates[slot]->seqIdCopy[0];
+ //gAudioContext.seqPlayers[1].seqId = gSaveStates[slot]->seqIdCopy[1];
+ //gAudioContext.seqPlayers[2].seqId = gSaveStates[slot]->seqIdCopy[2];
+ //gAudioContext.seqPlayers[3].seqId = gSaveStates[slot]->seqIdCopy[3];
+
memcpy(&gSaveContext, &gSaveStates[slot]->saveContextCopy, sizeof(gSaveContext));
memcpy(gGameInfo, &gSaveStates[slot]->gameInfoCopy, sizeof(*gGameInfo));
- //memcpy(&gAudioContext, &gSaveStates[slot]->audioContextCopy, sizeof(AudioContext));
memcpy(&sLightsBuffer, &gSaveStates[slot]->lightBufferCopy, sizeof(sLightsBuffer));
memcpy(&sMatrixStack, &gSaveStates[slot]->mtxStackCopy, sizeof(MtxF) * 20);
memcpy(&sCurrentMatrix, &gSaveStates[slot]->currentMtxCopy, sizeof(MtxF));
sWarpTimerTarget = gSaveStates[slot]->blueWarpTimerCopy;
//TODO RNG seed
+ memcpy(gActiveSounds, gSaveStates[slot]->gActiveSoundsCopy, sizeof(gActiveSounds));
+ memcpy(gSoundBankMuted, &gSaveStates[slot]->gSoundBankMutedCopy, sizeof(gSaveStates[0]->gSoundBankMutedCopy));
+ D_801333F0 = gSaveStates[slot]->D_801333F0_copy;
+ gAudioSfxSwapOff = gSaveStates[slot]->gAudioSfxSwapOff_copy;
+
+ memcpy(gAudioSfxSwapSource, &gSaveStates[slot]->gAudioSfxSwapSource_copy,
+ sizeof(&gSaveStates[slot]->gAudioSfxSwapSource_copy));
+ memcpy(gAudioSfxSwapTarget, &gSaveStates[slot]->gAudioSfxSwapTarget_copy,
+ sizeof(&gSaveStates[slot]->gAudioSfxSwapTarget_copy));
+ memcpy(gAudioSfxSwapMode, &gSaveStates[slot]->gAudioSfxSwapMode_copy,
+ sizeof(&gSaveStates[slot]->gAudioSfxSwapMode_copy));
+
+ D_801755D0 = gSaveStates[slot]->D_801755D0_copy;
- return SaveStateReturn::SUCCESS;
}
diff --git a/soh/soh/Enhancements/savestates.h b/soh/soh/Enhancements/savestates.h
index 7cb92337e..5a378702b 100644
--- a/soh/soh/Enhancements/savestates.h
+++ b/soh/soh/Enhancements/savestates.h
@@ -5,6 +5,7 @@
#include
#include
+#include
// FROM z_lights.c
// I didn't feel like moving it into a header file.
@@ -35,11 +36,53 @@ typedef struct SaveStateHeader {
//uint32_t gameVersion;
} SaveStateHeader;
+enum class RequestType {
+ SAVE,
+ LOAD,
+};
+
+typedef struct SaveStateInfo {
+ SaveStateHeader stateHeader;
+
+ unsigned char sysHeapCopy[SYSTEM_HEAP_SIZE];
+ unsigned char audioHeapCopy[AUDIO_HEAP_SIZE];
+
+ SaveContext saveContextCopy;
+ GameInfo gameInfoCopy;
+ LightsBuffer lightBufferCopy;
+ AudioContext audioContextCopy;
+ std::array mtxStackCopy; // always 20 matricies
+ MtxF currentMtxCopy;
+ uint32_t rngSeed;
+ int16_t blueWarpTimerCopy; /* From door_warp_1 */
+
+ std::array seqScriptStateCopy; // Unrelocated
+ // std::array seqIdCopy;
+ std::array unk_D_8016E750Copy;
+
+ ActiveSound gActiveSoundsCopy[7][MAX_CHANNELS_PER_BANK];
+ std::array gSoundBankMutedCopy;
+ u8 D_801333F0_copy;
+ u8 gAudioSfxSwapOff_copy;
+ std::array gAudioSfxSwapSource_copy;
+ std::array gAudioSfxSwapTarget_copy;
+ std::array gAudioSfxSwapMode_copy;
+ void (*D_801755D0_copy)(void);
+} SaveStateInfo;
+
extern unsigned int gCurrentSlot;
+typedef struct SaveStateRequest {
+ unsigned int slot;
+ RequestType type;
+} SaveStateRequest;
+
class SaveState {
public:
static constexpr unsigned int SAVE_SLOT_MAX = 2;
+
+ static std::queue requests;
+
SaveState();
~SaveState();
@@ -47,27 +90,29 @@ class SaveState {
SaveState(const SaveState& rhs) = delete;
void Init(void);
- static SaveStateReturn Save(const unsigned int slot);
- static SaveStateReturn Load(const unsigned int slot);
+
static SaveStateReturn Export(const unsigned int slot);
static SaveStateReturn Import(const unsigned int slot);
static SaveStateReturn Delete(const unsigned int slot);
+ SaveStateInfo* GetSaveStateInfo(const unsigned int slot);
+ static SaveStateReturn RequestSaveState(const unsigned int slot);
+ static SaveStateReturn RequestLoadState(const unsigned int slot);
+ static void ProcessSaveStateRequestsImpl(void);
+
private:
+ static void Save(const unsigned int slot);
+ static void Load(const unsigned int slot);
static void SetHeader(SaveStateHeader& header);
static void GetHeader(SaveStateHeader& header);
- SaveStateHeader stateHeader;
- unsigned char sysHeapCopy[1024 * 1024 * 4]; //TODO, make a macro for this
- SaveContext saveContextCopy;
- GameInfo gameInfoCopy;
- LightsBuffer lightBufferCopy;
- //AudioContext audioContextCopy;
- std::array mtxStackCopy; // always 20 matricies
- MtxF currentMtxCopy;
- uint32_t rngSeed;
- int16_t blueWarpTimerCopy; /* From door_warp_1 */
-
+ static void BackupSeqScriptState(SaveStateInfo* state);
+ static void LoadSeqScriptState(SaveStateInfo* state);
+
+ SaveStateInfo saveStateInfo;
+
+
};
+
#endif
diff --git a/soh/soh/OTRAudio.h b/soh/soh/OTRAudio.h
new file mode 100644
index 000000000..ee0ec46a2
--- /dev/null
+++ b/soh/soh/OTRAudio.h
@@ -0,0 +1,8 @@
+#pragma once
+
+static struct {
+ std::condition_variable cv_to_thread, cv_from_thread;
+ std::mutex mutex;
+ bool initialized;
+ bool processing;
+} audio;
diff --git a/soh/soh/OTRGlobals.cpp b/soh/soh/OTRGlobals.cpp
index f7ff39cdc..8eccfcf25 100644
--- a/soh/soh/OTRGlobals.cpp
+++ b/soh/soh/OTRGlobals.cpp
@@ -1,4 +1,5 @@
#include "OTRGlobals.h"
+#include "OTRAudio.h"
#include
#include
#include
@@ -35,13 +36,6 @@
OTRGlobals* OTRGlobals::Instance;
-static struct {
- std::condition_variable cv_to_thread, cv_from_thread;
- std::mutex mutex;
- bool initialized;
- bool processing;
-} audio;
-
OTRGlobals::OTRGlobals() {
context = Ship::GlobalCtx2::CreateInstance("Ship of Harkinian");
context->GetWindow()->Init();
@@ -131,6 +125,7 @@ extern "C" void Graph_ProcessGfxCommands(Gfx* commands) {
audio.cv_to_thread.wait(Lock);
}
}
+ std::unique_lock Lock(audio.mutex);
//AudioMgr_ThreadEntry(&gAudioMgr);
// 528 and 544 relate to 60 fps at 32 kHz 32000/60 = 533.333..
// in an ideal world, one third of the calls should use num_samples=544 and two thirds num_samples=528
@@ -156,10 +151,7 @@ extern "C" void Graph_ProcessGfxCommands(Gfx* commands) {
// printf("Audio samples before submitting: %d\n", audio_api->buffered());
AudioPlayer_Play((u8*)audio_buffer, num_audio_samples * (sizeof(int16_t) * NUM_AUDIO_CHANNELS * AUDIO_FRAMES_PER_UPDATE));
- {
- std::unique_lock Lock(audio.mutex);
- audio.processing = false;
- }
+ audio.processing = false;
audio.cv_from_thread.notify_one();
}
}).detach();
diff --git a/soh/src/buffers/heaps.c b/soh/src/buffers/heaps.c
index d09f86e72..7c6b7218b 100644
--- a/soh/src/buffers/heaps.c
+++ b/soh/src/buffers/heaps.c
@@ -6,8 +6,9 @@
#include
#endif
-#define AUDIO_HEAP_SIZE 0x38000
-#define SYSTEM_HEAP_SIZE (1024 * 1024 * 128)
+//#ifdef _MSC_VER
+//#include
+//#include <>
u8* gAudioHeap;
u8* gSystemHeap;
diff --git a/soh/src/code/graph.c b/soh/src/code/graph.c
index 9f744ec02..4b1887c18 100644
--- a/soh/src/code/graph.c
+++ b/soh/src/code/graph.c
@@ -431,6 +431,8 @@ static struct RunFrameContext {
extern AudioMgr gAudioMgr;
+extern void ProcessSaveStateRequests(void);
+
static void RunFrame()
{
u32 size;
@@ -487,6 +489,7 @@ static void RunFrame()
//uint64_t diff = (ticksB - ticksA) / (freq / 1000);
//printf("Frame simulated in %ims\n", diff);
runFrameContext.state = 1;
+ ProcessSaveStateRequests();
return;
nextFrame:;
}