From c289791df1bbbe5277b62870d71f00337269994f Mon Sep 17 00:00:00 2001 From: louist103 Date: Wed, 27 Apr 2022 00:13:05 -0400 Subject: [PATCH] IT WORKS BUT WOW ITS AWFUL LOOKING --- soh/include/z64.h | 3 + soh/soh.vcxproj | 3 +- soh/soh.vcxproj.filters | 2 + soh/soh/Enhancements/debugconsole.cpp | 9 +- soh/soh/Enhancements/savestates.cpp | 169 +++++++++++++++++++++++--- soh/soh/Enhancements/savestates.h | 71 +++++++++-- soh/soh/OTRAudio.h | 8 ++ soh/soh/OTRGlobals.cpp | 14 +-- soh/src/buffers/heaps.c | 5 +- soh/src/code/graph.c | 3 + 10 files changed, 238 insertions(+), 49 deletions(-) create mode 100644 soh/soh/OTRAudio.h 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:; }