Shipwright/soh/soh/Enhancements/savestates.cpp
briaguya 3914781ebf
Import libultraship as a submodule (#1943)
Co-authored-by: briaguya <briaguya>
Co-authored-by: Christopher Leggett <chris@leggett.dev>
Co-authored-by: David Chavez <davi@dcvz.io>
2022-11-14 11:22:34 +01:00

977 lines
40 KiB
C++

#include "savestates.h"
#include <GameVersions.h>
#include <cstdio> // std::sprintf
#include <spdlog/spdlog.h>
#include <spdlog/fmt/fmt.h>
#include <soh/OTRGlobals.h>
#include <soh/OTRAudio.h>
#include <ImGuiImpl.h>
#include "z64.h"
#include "z64save.h"
#include <variables.h>
#include <functions.h>
#include "z64map_mark.h"
#include "../../src/overlays/actors/ovl_Boss_Ganon/z_boss_ganon.h"
#include "../../src/overlays/actors/ovl_Boss_Ganon2/z_boss_ganon2.h"
#include "../../src/overlays/actors/ovl_Boss_Tw/z_boss_tw.h"
#include "../../src/overlays/actors/ovl_En_Clear_Tag/z_en_clear_tag.h"
#include "../../src/overlays/actors/ovl_En_Fr/z_en_fr.h"
extern "C" PlayState* gPlayState;
template <> struct fmt::formatter<RequestType> {
constexpr auto parse(format_parse_context& ctx) { return ctx.begin(); }
template <typename FormatContext>
auto format(const RequestType& type, FormatContext& ctx) {
switch (type) {
case RequestType::SAVE: return fmt::format_to(ctx.out(), "Save");
case RequestType::LOAD: return fmt::format_to(ctx.out(), "Load");
default: return fmt::format_to(ctx.out(), "Unknown");
}
}
};
// FROM z_lights.c
// I didn't feel like moving it into a header file.
#define LIGHTS_BUFFER_SIZE 32
typedef struct {
/* 0x000 */ s32 numOccupied;
/* 0x004 */ s32 searchIndex;
/* 0x008 */ LightNode buf[LIGHTS_BUFFER_SIZE];
} LightsBuffer; // size = 0x188
#include "savestates_extern.inc"
typedef struct SaveStateInfo {
unsigned char sysHeapCopy[SYSTEM_HEAP_SIZE];
unsigned char audioHeapCopy[AUDIO_HEAP_SIZE];
SaveContext saveContextCopy;
GameInfo gameInfoCopy;
LightsBuffer lightBufferCopy;
AudioContext audioContextCopy;
MtxF mtxStackCopy[20]; // always 20 matricies
MtxF currentMtxCopy;
uint32_t rngSeed;
int16_t blueWarpTimerCopy; /* From door_warp_1 */
SeqScriptState seqScriptStateCopy[4];// Unrelocated
unk_D_8016E750 unk_D_8016E750Copy[4];
ActiveSound gActiveSoundsCopy[7][MAX_CHANNELS_PER_BANK];
uint8_t gSoundBankMutedCopy[7];
u8 D_801333F0_copy;
u8 gAudioSfxSwapOff_copy;
uint16_t gAudioSfxSwapSource_copy[10];
uint16_t gAudioSfxSwapTarget_copy[10];
uint8_t gAudioSfxSwapMode_copy[10];
void (*D_801755D0_copy)(void);
MapMarkData** sLoadedMarkDataTableCopy;
//Static Data
//Camera data
int32_t sInitRegs_copy;
int32_t gDbgCamEnabled_copy;
int32_t sDbgModeIdx_copy;
int16_t sNextUID_copy;
int32_t sCameraInterfaceFlags_copy;
int32_t sCameraInterfaceAlpha_copy;
int32_t sCameraShrinkWindowVal_copy;
int32_t D_8011D3AC_copy;
int32_t sDemo5PrevAction12Frame_copy;
int32_t sDemo5PrevSfxFrame_copy;
int32_t D_8011D3F0_copy;
OnePointCsFull D_8011D6AC_copy[3];
OnePointCsFull D_8011D724_copy[3];
OnePointCsFull D_8011D79C_copy[3];
OnePointCsFull D_8011D83C_copy[2];
OnePointCsFull D_8011D88C_copy[2];
OnePointCsFull D_8011D8DC_copy[3];
OnePointCsFull D_8011D954_copy[4];
OnePointCsFull D_8011D9F4_copy[3];
int16_t depthPhase_copy;
int16_t screenPlanePhase_copy;
int32_t sOOBTimer_copy;
f32 D_8015CE50_copy;
f32 D_8015CE54_copy;
CamColChk D_8015CE58_copy;
//Gameover
uint16_t gGameOverTimer_copy;
//One point demo
uint32_t sPrevFrameCs1100_copy;
CutsceneCameraPoint D_8012013C_copy[14];
CutsceneCameraPoint D_8012021C_copy[14];
CutsceneCameraPoint D_801204D4_copy[14];
CutsceneCameraPoint D_801205B4_copy[14];
OnePointCsFull D_801208EC_copy[3];
OnePointCsFull D_80120964_copy[2];
OnePointCsFull D_801209B4_copy[4];
OnePointCsFull D_80120ACC_copy[5];
OnePointCsFull D_80120B94_copy[11];
OnePointCsFull D_80120D4C_copy[7];
OnePointCsFull D_80120FA4_copy[6];
OnePointCsFull D_80121184_copy[2];
OnePointCsFull D_801211D4_copy[2];
OnePointCsFull D_8012133C_copy[3];
OnePointCsFull D_801213B4_copy[5];
OnePointCsFull D_8012151C_copy[2];
OnePointCsFull D_8012156C_copy[2];
OnePointCsFull D_801215BC_copy[1];
OnePointCsFull D_80121C24_copy[7];
OnePointCsFull D_80121D3C_copy[3];
OnePointCsFull D_80121F1C_copy[4];
OnePointCsFull D_80121FBC_copy[4];
OnePointCsFull D_801220D4_copy[5];
OnePointCsFull D_80122714_copy[4];
OnePointCsFull D_80122CB4_copy[2];
OnePointCsFull D_80122D04_copy[2];
OnePointCsFull D_80122E44_copy[2][7];
OnePointCsFull D_8012313C_copy[3];
OnePointCsFull D_801231B4_copy[4];
OnePointCsFull D_80123254_copy[2];
OnePointCsFull D_801232A4_copy[1];
OnePointCsFull D_80123894_copy[3];
OnePointCsFull D_8012390C_copy[2];
OnePointCsFull D_8012395C_copy[3];
OnePointCsFull D_801239D4_copy[3];
uint16_t gTimeIncrement_copy;
//Overlay static data
// z_bg_ddan_kd
Vec3f sBgDdanKdVelocity_copy;
Vec3f sBgDdanKdAccel_copy;
// z_bg_dodoago
s16 sBgDodoagoFirstExplosiveFlag_copy;
u8 sBgDodoagoDisableBombCatcher_copy;
s32 sBgDodoagoTimer_copy;
// z_bg_haka_trap
uint32_t D_80880F30_copy;
uint32_t D_80881014_copy;
// z_bg_hidan_rock
float D_8088BFC0_copy;
// z_bg_menkuri_eye
int32_t D_8089C1A0_copy;
// z_bg_mori_hineri
int16_t sBgMoriHineriNextCamIdx_copy;
// z_bg_po_event
uint8_t sBgPoEventBlocksAtRest_copy;
uint8_t sBgPoEventPuzzleState_copy;
float sBgPoEventblockPushDist_copy;
// z_bg_relay_objects
uint32_t D_808A9508_copy;
// z_bg_spot18_basket
int16_t D_808B85D0_copy;
// z_boss_ganon
uint32_t sBossGanonSeed1_copy;
uint32_t sBossGanonSeed2_copy;
uint32_t sBossGanonSeed3_copy;
void* sBossGanonGanondorf_copy;
void* sBossGanonZelda_copy;
void* sBossGanonCape_copy;
GanondorfEffect sBossGanonEffectBuf_copy[200];
// z_boss_ganon
uint32_t sBossGanonSeed1;
uint32_t sBossGanonSeed2;
uint32_t sBossGanonSeed3;
void* sBossGanonGanondorf;
void* sBossGanonZelda;
void* sBossGanonCape;
GanondorfEffect sBossGanonEffectBuf[200];
// z_boss_ganon2
Vec3f D_8090EB20_copy;
int8_t D_80910638_copy;
void* sBossGanon2Zelda_copy;
void* D_8090EB30_copy;
int32_t sBossGanon2Seed1_copy;
int32_t sBossGanon2Seed2_copy;
int32_t sBossGanon2Seed3_copy;
Vec3f D_809105D8_copy[4];
Vec3f D_80910608_copy[4];
BossGanon2Effect sBossGanon2Particles_copy[100];
// z_boss_tw
uint8_t sTwInitalized_copy;
BossTwEffect sTwEffects_copy[150];
// z_demo_6k
Vec3f sDemo6kVelocity_copy;
// z_demo_du
int32_t D_8096CE94_copy;
// z_demo_kekkai
Vec3f demoKekkaiVel_copy;
// z_en_bw
int32_t sSlugGroup_copy;
// z_en_clear_tag
uint8_t sClearTagIsEffectInitialized_copy;
EnClearTagEffect sClearTagEffects_copy[CLEAR_TAG_EFFECT_MAX_COUNT];
// z_en_fr
EnFrPointers sEnFrPointers_copy;
// z_en_goma
uint8_t sSpawnNum_copy;
// z_en_insect
float D_80A7DEB0_copy;
int16_t D_80A7DEB4_copy;
int16_t D_80A7DEB8_copy;
// z_en_ishi
int16_t sRockRotSpeedX_copy;
int16_t sRockRotSpeedY_copy;
// z_en_niw
int16_t D_80AB85E0_copy;
uint8_t sLowerRiverSpawned_copy;
uint8_t sUpperRiverSpawned_copy;
// z_en_po_field
int32_t sEnPoFieldNumSpawned_copy;
Vec3s sEnPoFieldSpawnPositions_copy[10];
u8 sEnPoFieldSpawnSwitchFlags_copy[10];
// z_en_takara_man
uint8_t sTakaraIsInitialized_copy;
// z_en_xc
int32_t D_80B41D90_copy;
int32_t sEnXcFlameSpawned_copy;
int32_t D_80B41DA8_copy;
int32_t D_80B41DAC_copy;
// z_en_zf
int16_t D_80B4A1B0_copy;
int16_t D_80B4A1B4_copy;
int32_t D_80B5A468_copy;
int32_t D_80B5A494_copy;
int32_t D_80B5A4BC_copy;
uint8_t sKankyoIsSpawned_copy;
int16_t sTrailingFairies_copy;
// z_en_heishi1
uint32_t sHeishi1PlayerIsCaughtCopy;
//Misc static data
// z_map_exp
s16 sPlayerInitialPosX_copy;
s16 sPlayerInitialPosZ_copy;
s16 sPlayerInitialDirection_copy;
// code_800E(something. fill me in later)
u8 sOcarinaInpEnabled_copy;
s8 D_80130F10_copy;
u8 sCurOcarinaBtnVal_copy;
u8 sPrevOcarinaNoteVal_copy;
u8 sCurOcarinaBtnIdx_copy;
u8 sLearnSongLastBtn_copy;
f32 D_80130F24_copy;
f32 D_80130F28_copy;
s8 D_80130F2C_copy;
s8 D_80130F30_copy;
s8 D_80130F34_copy;
u8 sDisplayedNoteValue_copy;
u8 sPlaybackState_copy;
u32 D_80130F3C_copy;
u32 sNotePlaybackTimer_copy;
u16 sPlaybackNotePos_copy;
u16 sStaffPlaybackPos_copy;
u32 sCurOcarinaBtnPress_copy;
u32 D_8016BA10_copy;
u32 sPrevOcarinaBtnPress_copy;
s32 D_8016BA18_copy;
s32 D_8016BA1C_copy;
u8 sCurOcarinaSong_copy[8];
u8 sOcarinaSongAppendPos_copy;
u8 sOcarinaHasStartedSong_copy;
u8 sOcarinaSongNoteStartIdx_copy;
u8 sOcarinaSongCnt_copy;
u16 sOcarinaAvailSongs_copy;
u8 sStaffPlayingPos_copy;
u16 sLearnSongPos_copy[0x10];
u16 D_8016BA50_copy[0x10];
u16 D_8016BA70_copy[0x10];
u8 sLearnSongExpectedNote_copy[0x10];
OcarinaNote D_8016BAA0_copy;
u8 sAudioHasMalonBgm_copy;
f32 sAudioMalonBgmDist_copy;
// Message_PAL
s16 sOcarinaNoteBufPos_copy;
s16 sOcarinaNoteBufLen_copy;
u8 sOcarinaNoteBuf_copy[12];
u8 D_8014B2F4_copy;
u8 sTextboxSkipped_copy;
u16 sNextTextId_copy;
s16 sLastPlayedSong_copy;
s16 sHasSunsSong_copy;
s16 sMessageHasSetSfx_copy;
u16 sOcarinaSongBitFlags_copy;
} SaveStateInfo;
class SaveState {
friend class SaveStateMgr;
public:
SaveState(std::shared_ptr<SaveStateMgr> mgr, unsigned int slot);
private:
unsigned int slot;
std::shared_ptr<SaveStateMgr> saveStateMgr;
std::shared_ptr<SaveStateInfo> info;
void Save(void);
void Load(void);
void BackupSeqScriptState(void);
void LoadSeqScriptState(void);
void BackupCameraData(void);
void LoadCameraData(void);
void SaveOnePointDemoData(void);
void LoadOnePointDemoData(void);
void SaveOverlayStaticData(void);
void LoadOverlayStaticData(void);
void SaveMiscCodeData(void);
void LoadMiscCodeData(void);
SaveStateInfo* GetSaveStateInfo(void);
};
SaveStateMgr::SaveStateMgr() {
this->SetCurrentSlot(0);
}
SaveStateMgr::~SaveStateMgr() {
this->states.clear();
}
SaveState::SaveState(std::shared_ptr<SaveStateMgr> mgr, unsigned int slot) : saveStateMgr(mgr), slot(slot), info(nullptr) {
this->info = std::make_shared<SaveStateInfo>();
}
void SaveState::BackupSeqScriptState(void) {
for (unsigned int i = 0; i < 4; i++) {
info->seqScriptStateCopy[i].value = gAudioContext.seqPlayers[i].scriptState.value;
info->seqScriptStateCopy[i].remLoopIters[0] = gAudioContext.seqPlayers[i].scriptState.remLoopIters[0];
info->seqScriptStateCopy[i].remLoopIters[1] = gAudioContext.seqPlayers[i].scriptState.remLoopIters[1];
info->seqScriptStateCopy[i].remLoopIters[2] = gAudioContext.seqPlayers[i].scriptState.remLoopIters[2];
info->seqScriptStateCopy[i].remLoopIters[3] = gAudioContext.seqPlayers[i].scriptState.remLoopIters[3];
info->seqScriptStateCopy[i].depth = gAudioContext.seqPlayers[i].scriptState.depth;
info->seqScriptStateCopy[i].pc = (u8*)((uintptr_t)gAudioContext.seqPlayers[i].scriptState.pc - (uintptr_t)gAudioHeap);
info->seqScriptStateCopy[i].stack[0] =
(u8*)((uintptr_t)gAudioContext.seqPlayers[i].scriptState.stack[0] - (uintptr_t)gAudioHeap);
info->seqScriptStateCopy[i].stack[1] =
(u8*)((uintptr_t)gAudioContext.seqPlayers[i].scriptState.stack[1] - (uintptr_t)gAudioHeap);
info->seqScriptStateCopy[i].stack[2] =
(u8*)((uintptr_t)gAudioContext.seqPlayers[i].scriptState.stack[2] - (uintptr_t)gAudioHeap);
info->seqScriptStateCopy[i].stack[3] =
(u8*)((uintptr_t)gAudioContext.seqPlayers[i].scriptState.stack[3] - (uintptr_t)gAudioHeap);
}
}
void SaveState::LoadSeqScriptState(void) {
for (unsigned int i = 0; i < 4; i++) {
gAudioContext.seqPlayers[i].scriptState.value = info->seqScriptStateCopy[i].value;
gAudioContext.seqPlayers[i].scriptState.remLoopIters[0] = info->seqScriptStateCopy[i].remLoopIters[0];
gAudioContext.seqPlayers[i].scriptState.remLoopIters[1] = info->seqScriptStateCopy[i].remLoopIters[1];
gAudioContext.seqPlayers[i].scriptState.remLoopIters[2] = info->seqScriptStateCopy[i].remLoopIters[2];
gAudioContext.seqPlayers[i].scriptState.remLoopIters[3] = info->seqScriptStateCopy[i].remLoopIters[3];
gAudioContext.seqPlayers[i].scriptState.depth = info->seqScriptStateCopy[i].depth;
gAudioContext.seqPlayers[i].scriptState.pc =
(u8*)((uintptr_t)info->seqScriptStateCopy[i].pc + (uintptr_t)gAudioHeap);
gAudioContext.seqPlayers[i].scriptState.stack[0] =
(u8*)((uintptr_t)info->seqScriptStateCopy[i].stack[0] + (uintptr_t)gAudioHeap);
gAudioContext.seqPlayers[i].scriptState.stack[1] =
(u8*)((uintptr_t)info->seqScriptStateCopy[i].stack[1] + (uintptr_t)gAudioHeap);
gAudioContext.seqPlayers[i].scriptState.stack[2] =
(u8*)((uintptr_t)info->seqScriptStateCopy[i].stack[2] + (uintptr_t)gAudioHeap);
gAudioContext.seqPlayers[i].scriptState.stack[3] =
(u8*)((uintptr_t)info->seqScriptStateCopy[i].stack[3] + (uintptr_t)gAudioHeap);
}
}
void SaveState::BackupCameraData(void) {
info->sInitRegs_copy = sInitRegs;
info->gDbgCamEnabled_copy = gDbgCamEnabled;
info->sNextUID_copy = sNextUID;
info->sCameraInterfaceFlags_copy = sCameraInterfaceFlags;
info->sCameraInterfaceAlpha_copy = sCameraInterfaceAlpha;
info->sCameraShrinkWindowVal_copy = sCameraShrinkWindowVal;
info->D_8011D3AC_copy = D_8011D3AC;
info->sDemo5PrevAction12Frame_copy = sDemo5PrevAction12Frame;
info->sDemo5PrevSfxFrame_copy = sDemo5PrevSfxFrame;
info->D_8011D3F0_copy = D_8011D3F0;
memcpy(info->D_8011D6AC_copy, D_8011D6AC, sizeof(info->D_8011D6AC_copy));
memcpy(info->D_8011D724_copy, D_8011D724, sizeof(info->D_8011D724_copy));
memcpy(info->D_8011D79C_copy, D_8011D79C, sizeof(info->D_8011D79C_copy));
memcpy(info->D_8011D83C_copy, D_8011D83C, sizeof(info->D_8011D83C_copy));
memcpy(info->D_8011D88C_copy, D_8011D88C, sizeof(info->D_8011D88C_copy));
memcpy(info->D_8011D8DC_copy, D_8011D8DC, sizeof(info->D_8011D8DC_copy));
memcpy(info->D_8011D954_copy, D_8011D954, sizeof(info->D_8011D954_copy));
memcpy(info->D_8011D9F4_copy, D_8011D9F4, sizeof(info->D_8011D9F4_copy));
info->depthPhase_copy = depthPhase;
info->screenPlanePhase_copy = screenPlanePhase;
info->sOOBTimer_copy = sOOBTimer;
info->D_8015CE50_copy = D_8015CE50;
info->D_8015CE54_copy = D_8015CE54;
memcpy(&info->D_8015CE58_copy, &D_8015CE58, sizeof(info->D_8015CE58_copy));
}
void SaveState::LoadCameraData(void) {
sInitRegs = info->sInitRegs_copy;
gDbgCamEnabled = info->gDbgCamEnabled_copy;
sDbgModeIdx = info->sDbgModeIdx_copy;
sNextUID = info->sNextUID_copy;
sCameraInterfaceAlpha = info->sCameraInterfaceAlpha_copy;
sCameraInterfaceFlags = info->sCameraInterfaceFlags_copy;
sCameraShrinkWindowVal = info->sCameraShrinkWindowVal_copy;
D_8011D3AC = info->D_8011D3AC_copy;
sDemo5PrevAction12Frame = info->sDemo5PrevAction12Frame_copy;
sDemo5PrevSfxFrame = info->sDemo5PrevSfxFrame_copy;
D_8011D3F0 = info->D_8011D3F0_copy;
memcpy(D_8011D6AC, info->D_8011D6AC_copy, sizeof(info->D_8011D6AC_copy));
memcpy(D_8011D724, info->D_8011D724_copy, sizeof(info->D_8011D724_copy));
memcpy(D_8011D79C, info->D_8011D79C_copy, sizeof(info->D_8011D79C_copy));
memcpy(D_8011D83C, info->D_8011D83C_copy, sizeof(info->D_8011D83C_copy));
memcpy(D_8011D88C, info->D_8011D88C_copy, sizeof(info->D_8011D88C_copy));
memcpy(D_8011D8DC, info->D_8011D8DC_copy, sizeof(info->D_8011D8DC_copy));
memcpy(D_8011D954, info->D_8011D954_copy, sizeof(info->D_8011D954_copy));
memcpy(D_8011D9F4, info->D_8011D9F4_copy, sizeof(info->D_8011D9F4_copy));
depthPhase = info->depthPhase_copy;
screenPlanePhase = info->screenPlanePhase_copy;
sOOBTimer = info->sOOBTimer_copy;
D_8015CE50 = info->D_8015CE50_copy;
D_8015CE54 = info->D_8015CE54_copy;
memcpy(&D_8015CE58, &info->D_8015CE58_copy, sizeof(info->D_8015CE58_copy));
}
void SaveState::SaveOnePointDemoData(void) {
info->sPrevFrameCs1100_copy = sPrevFrameCs1100;
memcpy(info->D_8012013C_copy, D_8012013C, sizeof(info->D_8012013C_copy));
memcpy(info->D_8012021C_copy, D_8012021C, sizeof(info->D_8012021C_copy));
memcpy(info->D_801204D4_copy, D_801204D4, sizeof(info->D_801204D4_copy));
memcpy(info->D_801205B4_copy, D_801205B4, sizeof(info->D_801205B4_copy));
memcpy(info->D_801208EC_copy, D_801208EC, sizeof(info->D_801208EC_copy));
memcpy(info->D_80120964_copy, D_80120964, sizeof(info->D_80120964_copy));
memcpy(info->D_801209B4_copy, D_801209B4, sizeof(info->D_801209B4_copy));
memcpy(info->D_80120ACC_copy, D_80120ACC, sizeof(info->D_80120ACC_copy));
memcpy(info->D_80120B94_copy, D_80120B94, sizeof(info->D_80120B94_copy));
memcpy(info->D_80120D4C_copy, D_80120D4C, sizeof(info->D_80120D4C_copy));
memcpy(info->D_80120FA4_copy, D_80120FA4, sizeof(info->D_80120FA4_copy));
memcpy(info->D_80121184_copy, D_80121184, sizeof(info->D_80121184_copy));
memcpy(info->D_801211D4_copy, D_801211D4, sizeof(info->D_801211D4_copy));
memcpy(info->D_8012133C_copy, D_8012133C, sizeof(info->D_8012133C_copy));
memcpy(info->D_801213B4_copy, D_801213B4, sizeof(info->D_801213B4_copy));
memcpy(info->D_8012151C_copy, D_8012151C, sizeof(info->D_8012151C_copy));
memcpy(info->D_8012156C_copy, D_8012156C, sizeof(info->D_8012156C_copy));
memcpy(info->D_801215BC_copy, D_801215BC, sizeof(info->D_801215BC_copy));
memcpy(info->D_80121C24_copy, D_80121C24, sizeof(info->D_80121C24_copy));
memcpy(info->D_80121D3C_copy, D_80121D3C, sizeof(info->D_80121D3C_copy));
memcpy(info->D_80121F1C_copy, D_80121F1C, sizeof(info->D_80121F1C_copy));
memcpy(info->D_80121FBC_copy, D_80121FBC, sizeof(info->D_80121FBC_copy));
memcpy(info->D_801220D4_copy, D_801220D4, sizeof(info->D_801220D4_copy));
memcpy(info->D_80122714_copy, D_80122714, sizeof(info->D_80122714_copy));
memcpy(info->D_80122CB4_copy, D_80122CB4, sizeof(info->D_80122CB4_copy));
memcpy(info->D_80122D04_copy, D_80122D04, sizeof(info->D_80122D04_copy));
memcpy(info->D_80122E44_copy, D_80122E44, sizeof(info->D_80122E44_copy));
memcpy(info->D_8012313C_copy, D_8012313C, sizeof(info->D_8012313C_copy));
memcpy(info->D_801231B4_copy, D_801231B4, sizeof(info->D_801231B4_copy));
memcpy(info->D_80123254_copy, D_80123254, sizeof(info->D_80123254_copy));
memcpy(info->D_801232A4_copy, D_801232A4, sizeof(info->D_801232A4_copy));
memcpy(info->D_80123894_copy, D_80123894, sizeof(info->D_80123894_copy));
memcpy(info->D_8012390C_copy, D_8012390C, sizeof(info->D_8012390C_copy));
memcpy(info->D_8012395C_copy, D_8012395C, sizeof(info->D_8012395C_copy));
memcpy(info->D_801239D4_copy, D_801239D4, sizeof(info->D_801239D4_copy));
}
void SaveState::LoadOnePointDemoData(void) {
sPrevFrameCs1100 = info->sPrevFrameCs1100_copy;
memcpy(D_8012013C, info->D_8012013C_copy, sizeof(info->D_8012013C_copy));
memcpy(D_8012021C, info->D_8012021C_copy, sizeof(info->D_8012021C_copy));
memcpy(D_801204D4, info->D_801204D4_copy, sizeof(info->D_801204D4_copy));
memcpy(D_801205B4, info->D_801205B4_copy, sizeof(info->D_801205B4_copy));
memcpy(D_801208EC, info->D_801208EC_copy, sizeof(info->D_801208EC_copy));
memcpy(D_80120964, info->D_80120964_copy, sizeof(info->D_80120964_copy));
memcpy(D_801209B4, info->D_801209B4_copy, sizeof(info->D_801209B4_copy));
memcpy(D_80120ACC, info->D_80120ACC_copy, sizeof(info->D_80120ACC_copy));
memcpy(D_80120B94, info->D_80120B94_copy, sizeof(info->D_80120B94_copy));
memcpy(D_80120D4C, info->D_80120D4C_copy, sizeof(info->D_80120D4C_copy));
memcpy(D_80120FA4, info->D_80120FA4_copy, sizeof(info->D_80120FA4_copy));
memcpy(D_80121184, info->D_80121184_copy, sizeof(info->D_80121184_copy));
memcpy(D_801211D4, info->D_801211D4_copy, sizeof(info->D_801211D4_copy));
memcpy(D_8012133C, info->D_8012133C_copy, sizeof(info->D_8012133C_copy));
memcpy(D_801213B4, info->D_801213B4_copy, sizeof(info->D_801213B4_copy));
memcpy(D_8012151C, info->D_8012151C_copy, sizeof(info->D_8012151C_copy));
memcpy(D_8012156C, info->D_8012156C_copy, sizeof(info->D_8012156C_copy));
memcpy(D_801215BC, info->D_801215BC_copy, sizeof(info->D_801215BC_copy));
memcpy(D_80121C24, info->D_80121C24_copy, sizeof(info->D_80121C24_copy));
memcpy(D_80121D3C, info->D_80121D3C_copy, sizeof(info->D_80121D3C_copy));
memcpy(D_80121F1C, info->D_80121F1C_copy, sizeof(info->D_80121F1C_copy));
memcpy(D_80121FBC, info->D_80121FBC_copy, sizeof(info->D_80121FBC_copy));
memcpy(D_801220D4, info->D_801220D4_copy, sizeof(info->D_801220D4_copy));
memcpy(D_80122714, info->D_80122714_copy, sizeof(info->D_80122714_copy));
memcpy(D_80122CB4, info->D_80122CB4_copy, sizeof(info->D_80122CB4_copy));
memcpy(D_80122D04, info->D_80122D04_copy, sizeof(info->D_80122D04_copy));
memcpy(D_80122E44, info->D_80122E44_copy, sizeof(info->D_80122E44_copy));
memcpy(D_8012313C, info->D_8012313C_copy, sizeof(info->D_8012313C_copy));
memcpy(D_801231B4, info->D_801231B4_copy, sizeof(info->D_801231B4_copy));
memcpy(D_80123254, info->D_80123254_copy, sizeof(info->D_80123254_copy));
memcpy(D_801232A4, info->D_801232A4_copy, sizeof(info->D_801232A4_copy));
memcpy(D_80123894, info->D_80123894_copy, sizeof(info->D_80123894_copy));
memcpy(D_8012390C, info->D_8012390C_copy, sizeof(info->D_8012390C_copy));
memcpy(D_8012395C, info->D_8012395C_copy, sizeof(info->D_8012395C_copy));
memcpy(D_801239D4, info->D_801239D4_copy, sizeof(info->D_801239D4_copy));
}
void SaveState::SaveOverlayStaticData(void) {
info->sBgDdanKdVelocity_copy = sBgDdanKdVelocity;
info->sBgDdanKdAccel_copy = sBgDdanKdAccel;
info->sBgDodoagoFirstExplosiveFlag_copy = sBgDodoagoFirstExplosiveFlag;
info->sBgDodoagoDisableBombCatcher_copy = sBgDodoagoDisableBombCatcher;
info->sBgDodoagoTimer_copy = sBgDodoagoTimer;
info->D_80880F30_copy = D_80880F30;
info->D_80881014_copy = D_80881014;
info->D_8088BFC0_copy = D_8088BFC0;
info->sBgMoriHineriNextCamIdx_copy = sBgMoriHineriNextCamIdx;
info->sBgPoEventBlocksAtRest_copy = sBgPoEventBlocksAtRest;
info->sBgPoEventPuzzleState_copy = sBgPoEventPuzzleState;
info->sBgPoEventblockPushDist_copy = sBgPoEventblockPushDist;
info->D_808A9508_copy = D_808A9508;
info->D_808B85D0_copy = D_808B85D0;
info->sBossGanonSeed1_copy = sBossGanonSeed1;
info->sBossGanonSeed2_copy = sBossGanonSeed2;
info->sBossGanonSeed3_copy = sBossGanonSeed3;
info->sBossGanonGanondorf_copy = sBossGanonGanondorf;
info->sBossGanonZelda_copy = sBossGanonZelda;
info->sBossGanonCape_copy = sBossGanonCape;
memcpy(info->sBossGanonEffectBuf_copy, sBossGanonEffectBuf, sizeof(info->sBossGanonEffectBuf_copy));
info->D_8090EB20_copy = D_8090EB20;
info->D_80910638_copy = D_80910638;
info->sBossGanon2Zelda_copy = sBossGanon2Zelda;
info->D_8090EB30_copy = D_8090EB30;
info->sBossGanon2Seed1_copy = sBossGanon2Seed1;
info->sBossGanon2Seed2_copy = sBossGanon2Seed2;
info->sBossGanon2Seed3_copy = sBossGanon2Seed3;
memcpy(info->D_809105D8_copy, D_809105D8, sizeof(D_809105D8));
memcpy(info->D_80910608_copy, D_80910608, sizeof(D_80910608));
memcpy(info->sBossGanon2Particles_copy, sBossGanon2Particles, sizeof(sBossGanon2Particles));
info->sTwInitalized_copy = sTwInitalized;
memcpy(info->sTwEffects_copy, sTwEffects, sizeof(sTwEffects));
info->sDemo6kVelocity_copy = sDemo6kVelocity;
info->D_8096CE94_copy = D_8096CE94;
info->demoKekkaiVel_copy = demoKekkaiVel;
info->sSlugGroup_copy = sSlugGroup;
info->sClearTagIsEffectInitialized_copy = sClearTagIsEffectsInitialized;
memcpy(info->sClearTagEffects_copy, sClearTagEffects, sizeof(sClearTagEffects));
memcpy(&info->sEnFrPointers_copy, &sEnFrPointers, sizeof(info->sEnFrPointers_copy));
info->sSpawnNum_copy = sSpawnNum;
info->D_80A7DEB0_copy = D_80A7DEB0;
info->D_80A7DEB4_copy = D_80A7DEB4;
info->D_80A7DEB8_copy = D_80A7DEB8;
info->sRockRotSpeedX_copy = sRockRotSpeedX;
info->sRockRotSpeedY_copy = sRockRotSpeedY;
info->D_80AB85E0_copy = D_80AB85E0;
info->sLowerRiverSpawned_copy = sLowerRiverSpawned;
info->sUpperRiverSpawned_copy = sUpperRiverSpawned;
info->sEnPoFieldNumSpawned_copy = sEnPoFieldNumSpawned;
memcpy(info->sEnPoFieldSpawnPositions_copy, sEnPoFieldSpawnPositions, sizeof(info->sEnPoFieldSpawnPositions_copy));
memcpy(info->sEnPoFieldSpawnSwitchFlags_copy, sEnPoFieldSpawnSwitchFlags, sizeof(info->sEnPoFieldSpawnSwitchFlags_copy));
info->sTakaraIsInitialized_copy = sTakaraIsInitialized;
info->D_80B41D90_copy = D_80B41D90;
info->sEnXcFlameSpawned_copy = sEnXcFlameSpawned;
info->D_80B41DA8_copy = D_80B41DA8;
info->D_80B41DAC_copy = D_80B41DAC;
info->D_80B4A1B0_copy = D_80B4A1B0;
info->D_80B4A1B4_copy = D_80B4A1B4;
info->D_80B5A468_copy = D_80B5A468;
info->D_80B5A494_copy = D_80B5A494;
info->D_80B5A4BC_copy = D_80B5A4BC;
info->sKankyoIsSpawned_copy = sKankyoIsSpawned;
info->sTrailingFairies_copy = sTrailingFairies;
info->sHeishi1PlayerIsCaughtCopy = sHeishi1PlayerIsCaught;
}
void SaveState::LoadOverlayStaticData(void) {
sBgDdanKdVelocity = info->sBgDdanKdVelocity_copy;
sBgDdanKdAccel = info->sBgDdanKdAccel_copy;
sBgDodoagoFirstExplosiveFlag = info->sBgDodoagoFirstExplosiveFlag_copy;
sBgDodoagoDisableBombCatcher = info->sBgDodoagoDisableBombCatcher_copy;
sBgDodoagoTimer = info->sBgDodoagoTimer_copy;
D_80880F30 = info->D_80880F30_copy;
D_80881014 = info->D_80881014_copy;
D_8088BFC0 = info->D_8088BFC0_copy;
sBgMoriHineriNextCamIdx = info->sBgMoriHineriNextCamIdx_copy;
sBgPoEventBlocksAtRest = info->sBgPoEventBlocksAtRest_copy;
sBgPoEventPuzzleState = info->sBgPoEventPuzzleState_copy;
sBgPoEventblockPushDist = info->sBgPoEventblockPushDist_copy;
D_808A9508 = info->D_808A9508_copy;
D_808B85D0 = info->D_808B85D0_copy;
sBossGanonSeed1 = info->sBossGanonSeed1_copy;
sBossGanonSeed2 = info->sBossGanonSeed2_copy;
sBossGanonSeed3 = info->sBossGanonSeed3_copy;
sBossGanonGanondorf = info->sBossGanonGanondorf_copy;
sBossGanonZelda = info->sBossGanonZelda_copy;
sBossGanonCape = info->sBossGanonCape_copy;
memcpy(sBossGanonEffectBuf, info->sBossGanonEffectBuf_copy, sizeof(info->sBossGanonEffectBuf_copy));
D_8090EB20 = info->D_8090EB20_copy;
D_80910638 = info->D_80910638_copy;
sBossGanon2Zelda = info->sBossGanon2Zelda_copy;
D_8090EB30 = info->D_8090EB30_copy;
sBossGanon2Seed1 = info->sBossGanon2Seed1_copy;
sBossGanon2Seed2 = info->sBossGanon2Seed2_copy;
sBossGanon2Seed3 = info->sBossGanon2Seed3_copy;
memcpy(D_809105D8, info->D_809105D8_copy, sizeof(D_809105D8));
memcpy(D_80910608, info->D_80910608_copy, sizeof(D_80910608));
memcpy(sBossGanon2Particles, info->sBossGanon2Particles_copy, sizeof(sBossGanon2Particles));
sTwInitalized = info->sTwInitalized_copy;
memcpy(sTwEffects, info->sTwEffects_copy, sizeof(sTwEffects));
sDemo6kVelocity = info->sDemo6kVelocity_copy;
D_8096CE94 = info->D_8096CE94_copy;
demoKekkaiVel = info->demoKekkaiVel_copy;
sSlugGroup = info->sSlugGroup_copy;
sClearTagIsEffectsInitialized = info->sClearTagIsEffectInitialized_copy;
memcpy(sClearTagEffects, info->sClearTagEffects_copy, sizeof(sClearTagEffects));
D_80A7DEB0 = info->D_80A7DEB0_copy;
D_80A7DEB4 = info->D_80A7DEB4_copy;
D_80A7DEB8 = info->D_80A7DEB8_copy;
sRockRotSpeedX = info->sRockRotSpeedX_copy;
sRockRotSpeedY = info->sRockRotSpeedY_copy;
D_80AB85E0 = info->D_80AB85E0_copy;
sLowerRiverSpawned = info->sLowerRiverSpawned_copy;
sUpperRiverSpawned = info->sUpperRiverSpawned_copy;
sEnPoFieldNumSpawned = info->sEnPoFieldNumSpawned_copy;
memcpy(sEnPoFieldSpawnPositions, info->sEnPoFieldSpawnPositions_copy, sizeof(info->sEnPoFieldSpawnPositions_copy));
memcpy(sEnPoFieldSpawnSwitchFlags, info->sEnPoFieldSpawnSwitchFlags_copy, sizeof(info->sEnPoFieldSpawnSwitchFlags_copy));
sTakaraIsInitialized = info->sTakaraIsInitialized_copy;
D_80B41D90 = info->D_80B41D90_copy;
sEnXcFlameSpawned = info->sEnXcFlameSpawned_copy;
D_80B41DA8 = info->D_80B41DA8_copy;
D_80B41DAC = info->D_80B41DAC_copy;
D_80B4A1B0 = info->D_80B4A1B0_copy;
D_80B4A1B4 = info->D_80B4A1B4_copy;
D_80B5A468 = info->D_80B5A468_copy;
D_80B5A494 = info->D_80B5A494_copy;
D_80B5A4BC = info->D_80B5A4BC_copy;
sKankyoIsSpawned = info->sKankyoIsSpawned_copy;
sTrailingFairies = info->sTrailingFairies_copy;
sHeishi1PlayerIsCaught = info->sHeishi1PlayerIsCaughtCopy;
}
void SaveState::SaveMiscCodeData(void) {
info->gGameOverTimer_copy = gGameOverTimer;
info->gTimeIncrement_copy = gTimeIncrement;
info->sLoadedMarkDataTableCopy = sLoadedMarkDataTable;
info->sPlayerInitialPosX_copy = sPlayerInitialPosX;
info->sPlayerInitialPosZ_copy = sPlayerInitialPosZ;
info->sPlayerInitialDirection_copy = sPlayerInitialDirection;
info->sOcarinaInpEnabled_copy = sOcarinaInpEnabled;
info->D_80130F10_copy = D_80130F10;
info->sCurOcarinaBtnVal_copy = sCurOcarinaBtnVal;
info->sPrevOcarinaNoteVal_copy = sPrevOcarinaNoteVal;
info->sCurOcarinaBtnIdx_copy = sCurOcarinaBtnIdx;
info->sLearnSongLastBtn_copy = sLearnSongLastBtn;
info->D_80130F24_copy = D_80130F24;
info->D_80130F28_copy = D_80130F28;
info->D_80130F2C_copy = D_80130F2C;
info->D_80130F30_copy = D_80130F30;
info->D_80130F34_copy = D_80130F34;
info->sPlaybackState_copy = sPlaybackState;
info->D_80130F3C_copy = D_80130F3C;
info->sNotePlaybackTimer_copy = sNotePlaybackTimer;
info->sPlaybackNotePos_copy = sPlaybackNotePos;
info->sStaffPlaybackPos_copy = sStaffPlaybackPos;
info->sCurOcarinaBtnPress_copy = sCurOcarinaBtnPress;
info->D_8016BA10_copy = D_8016BA10;
info->sPrevOcarinaBtnPress_copy = sPrevOcarinaBtnPress;
info->D_8016BA18_copy = D_8016BA18;
info->D_8016BA1C_copy = D_8016BA1C;
memcpy(info->sCurOcarinaSong_copy, sCurOcarinaSong, sizeof(sCurOcarinaSong));
info->sOcarinaSongAppendPos_copy = sOcarinaSongAppendPos;
info->sOcarinaHasStartedSong_copy = sOcarinaHasStartedSong;
info->sOcarinaSongNoteStartIdx_copy = sOcarinaSongNoteStartIdx;
info->sOcarinaSongCnt_copy = sOcarinaSongCnt;
info->sOcarinaAvailSongs_copy = sOcarinaAvailSongs;
info->sStaffPlayingPos_copy = sStaffPlayingPos;
memcpy(info->sLearnSongPos_copy, sLearnSongPos, sizeof(sLearnSongPos));
memcpy(info->D_8016BA50_copy, D_8016BA50, sizeof(D_8016BA50));
memcpy(info->D_8016BA70_copy, D_8016BA70, sizeof(D_8016BA70));
memcpy(info->sLearnSongExpectedNote_copy, sLearnSongExpectedNote, sizeof(sLearnSongExpectedNote));
memcpy(&info->D_8016BAA0_copy, &D_8016BAA0, sizeof(D_8016BAA0));
info->sAudioHasMalonBgm_copy = sAudioHasMalonBgm;
info->sAudioMalonBgmDist_copy = sAudioMalonBgmDist;
info->sDisplayedNoteValue_copy = sDisplayedNoteValue;
info->sOcarinaNoteBufPos_copy = sOcarinaNoteBufPos;
info->sOcarinaNoteBufLen_copy = sOcarinaNoteBufLen;
memcpy(info->sOcarinaNoteBuf_copy, sOcarinaNoteBuf, sizeof(sOcarinaNoteBuf));
info->D_8014B2F4_copy = D_8014B2F4;
info->sTextboxSkipped_copy = sTextboxSkipped;
info->sNextTextId_copy = sNextTextId;
info->sLastPlayedSong_copy = sLastPlayedSong;
info->sHasSunsSong_copy = sHasSunsSong;
info->sMessageHasSetSfx_copy = sMessageHasSetSfx;
info->sOcarinaSongBitFlags_copy = sOcarinaSongBitFlags;
}
void SaveState::LoadMiscCodeData(void) {
gGameOverTimer = info->gGameOverTimer_copy;
gTimeIncrement = info->gTimeIncrement_copy;
sLoadedMarkDataTable = info->sLoadedMarkDataTableCopy;
sPlayerInitialPosX = info->sPlayerInitialPosX_copy;
sPlayerInitialPosZ = info->sPlayerInitialPosZ_copy;
sPlayerInitialDirection = info->sPlayerInitialDirection_copy;
sOcarinaInpEnabled = info->sOcarinaInpEnabled_copy;
D_80130F10 = info->D_80130F10_copy;
sCurOcarinaBtnVal = info->sCurOcarinaBtnVal_copy;
sPrevOcarinaNoteVal = info->sPrevOcarinaNoteVal_copy;
sCurOcarinaBtnIdx = info->sCurOcarinaBtnIdx_copy;
sLearnSongLastBtn = info->sLearnSongLastBtn_copy;
D_80130F24 = info->D_80130F24_copy;
D_80130F28 = info->D_80130F28_copy;
D_80130F2C = info->D_80130F2C_copy;
D_80130F30 = info->D_80130F30_copy;
D_80130F34 = info->D_80130F34_copy;
sPlaybackState = info->sPlaybackState_copy;
D_80130F3C = info->D_80130F3C_copy;
sNotePlaybackTimer = info->sNotePlaybackTimer_copy;
sPlaybackNotePos = info->sPlaybackNotePos_copy;
sStaffPlaybackPos = info->sStaffPlaybackPos_copy;
sCurOcarinaBtnPress = info->sCurOcarinaBtnPress_copy;
D_8016BA10 = info->D_8016BA10_copy;
sPrevOcarinaBtnPress = info->sPrevOcarinaBtnPress_copy;
D_8016BA18 = info->D_8016BA18_copy;
D_8016BA1C = info->D_8016BA1C_copy;
memcpy(sCurOcarinaSong, info->sCurOcarinaSong_copy, sizeof(sCurOcarinaSong));
sOcarinaSongAppendPos = info->sOcarinaSongAppendPos_copy;
sOcarinaHasStartedSong = info->sOcarinaHasStartedSong_copy;
sOcarinaSongNoteStartIdx = info->sOcarinaSongNoteStartIdx_copy;
sOcarinaSongCnt = info->sOcarinaSongCnt_copy;
sOcarinaAvailSongs = info->sOcarinaAvailSongs_copy;
sStaffPlayingPos = info->sStaffPlayingPos_copy;
memcpy(info->sLearnSongPos_copy, info->sLearnSongPos_copy, sizeof(sLearnSongPos));
memcpy(info->D_8016BA50_copy, info->D_8016BA50_copy, sizeof(D_8016BA50));
memcpy(info->D_8016BA70_copy, info->D_8016BA70_copy, sizeof(D_8016BA70));
memcpy(info->sLearnSongExpectedNote_copy, info->sLearnSongExpectedNote_copy, sizeof(sLearnSongExpectedNote));
memcpy(&D_8016BAA0, &info->D_8016BAA0_copy, sizeof(D_8016BAA0));
sAudioHasMalonBgm = info->sAudioHasMalonBgm_copy;
sAudioMalonBgmDist = info->sAudioMalonBgmDist_copy;
sDisplayedNoteValue = info->sDisplayedNoteValue_copy;
sOcarinaNoteBufPos = info->sOcarinaNoteBufPos_copy;
sOcarinaNoteBufLen = info->sOcarinaNoteBufLen_copy;
memcpy(sOcarinaNoteBuf, info->sOcarinaNoteBuf_copy, sizeof(sOcarinaNoteBuf));
D_8014B2F4 = info->D_8014B2F4_copy;
sTextboxSkipped = info->sTextboxSkipped_copy;
sNextTextId = info->sNextTextId_copy;
sLastPlayedSong = info->sLastPlayedSong_copy;
sHasSunsSong = info->sHasSunsSong_copy;
sMessageHasSetSfx = info->sMessageHasSetSfx_copy;
sOcarinaSongBitFlags = info->sOcarinaSongBitFlags_copy;
}
extern "C" void ProcessSaveStateRequests(void) {
OTRGlobals::Instance->gSaveStateMgr->ProcessSaveStateRequests();
}
void SaveStateMgr::SetCurrentSlot(unsigned int slot) {
SohImGui::GetGameOverlay()->TextDrawNotification(1.0f, true, "slot %u set", slot);
this->currentSlot = slot;
}
unsigned int SaveStateMgr::GetCurrentSlot(void) {
return this->currentSlot;
}
void SaveStateMgr::ProcessSaveStateRequests(void) {
while (!this->requests.empty()) {
const auto& request = this->requests.front();
switch (request.type) {
case RequestType::SAVE:
if (!this->states.contains(request.slot)) {
this->states[request.slot] = std::make_shared<SaveState>(OTRGlobals::Instance->gSaveStateMgr, request.slot);
}
this->states[request.slot]->Save();
SohImGui::GetGameOverlay()->TextDrawNotification(1.0f, true, "saved state %u", request.slot);
break;
case RequestType::LOAD:
if (this->states.contains(request.slot)) {
this->states[request.slot]->Load();
SohImGui::GetGameOverlay()->TextDrawNotification(1.0f, true, "loaded state %u", request.slot);
} else {
SPDLOG_ERROR("Invalid SaveState slot: {}", request.type);
}
break;
[[unlikely]] default:
SPDLOG_ERROR("Invalid SaveState request type: {}", request.type);
break;
}
this->requests.pop();
}
}
SaveStateReturn SaveStateMgr::AddRequest(const SaveStateRequest request) {
if (gPlayState == nullptr) {
SPDLOG_ERROR("[SOH] Can not save or load a state outside of \"GamePlay\"");
SohImGui::GetGameOverlay()->TextDrawNotification(1.0f, true, "states not available here", request.slot);
return SaveStateReturn::FAIL_WRONG_GAMESTATE;
}
switch (request.type) {
case RequestType::SAVE:
requests.push(request);
return SaveStateReturn::SUCCESS;
case RequestType::LOAD:
if (states.contains(request.slot)) {
requests.push(request);
return SaveStateReturn::SUCCESS;
} else {
SPDLOG_ERROR("Invalid SaveState slot: {}", request.type);
SohImGui::GetGameOverlay()->TextDrawNotification(1.0f, true, "state slot %u empty", request.slot);
return SaveStateReturn::FAIL_INVALID_SLOT;
}
[[unlikely]] default:
SPDLOG_ERROR("Invalid SaveState request type: {}", request.type);
return SaveStateReturn::FAIL_BAD_REQUEST;
}
}
void SaveState::Save(void) {
std::unique_lock<std::mutex> Lock(audio.mutex);
memcpy(&info->sysHeapCopy, gSystemHeap, SYSTEM_HEAP_SIZE /* sizeof(gSystemHeap) */);
memcpy(&info->audioHeapCopy, gAudioHeap, AUDIO_HEAP_SIZE /* sizeof(gAudioContext) */);
memcpy(&info->audioContextCopy, &gAudioContext, sizeof(AudioContext));
memcpy(&info->unk_D_8016E750Copy, D_8016E750, sizeof(info->unk_D_8016E750Copy));
BackupSeqScriptState();
memcpy(info->gActiveSoundsCopy, gActiveSounds, sizeof(gActiveSounds));
memcpy(&info->gSoundBankMutedCopy, gSoundBankMuted, sizeof(info->gSoundBankMutedCopy));
info->D_801333F0_copy = D_801333F0;
info->gAudioSfxSwapOff_copy = gAudioSfxSwapOff;
memcpy(&info->gAudioSfxSwapSource_copy, gAudioSfxSwapSource,
sizeof(info->gAudioSfxSwapSource_copy));
memcpy(&info->gAudioSfxSwapTarget_copy, gAudioSfxSwapTarget,
sizeof(info->gAudioSfxSwapTarget_copy));
memcpy(&info->gAudioSfxSwapMode_copy, gAudioSfxSwapMode,
sizeof(info->gAudioSfxSwapMode_copy));
info->D_801755D0_copy = D_801755D0;
memcpy(&info->saveContextCopy, &gSaveContext, sizeof(gSaveContext));
memcpy(&info->gameInfoCopy, gGameInfo, sizeof(*gGameInfo));
memcpy(&info->lightBufferCopy, &sLightsBuffer, sizeof(sLightsBuffer));
memcpy(&info->mtxStackCopy, sMatrixStack, sizeof(MtxF) * 20);
memcpy(&info->currentMtxCopy, sCurrentMatrix, sizeof(MtxF));
//Various static data
info->blueWarpTimerCopy = sWarpTimerTarget;
BackupCameraData();
SaveOnePointDemoData();
SaveOverlayStaticData();
SaveMiscCodeData();
}
void SaveState::Load(void) {
std::unique_lock<std::mutex> Lock(audio.mutex);
memcpy(gSystemHeap, &info->sysHeapCopy, SYSTEM_HEAP_SIZE);
memcpy(gAudioHeap, &info->audioHeapCopy, AUDIO_HEAP_SIZE);
memcpy(&gAudioContext, &info->audioContextCopy, sizeof(AudioContext));
memcpy(D_8016E750, &info->unk_D_8016E750Copy, sizeof(info->unk_D_8016E750Copy));
LoadSeqScriptState();
memcpy(&gSaveContext, &info->saveContextCopy, sizeof(gSaveContext));
memcpy(gGameInfo, &info->gameInfoCopy, sizeof(*gGameInfo));
memcpy(&sLightsBuffer, &info->lightBufferCopy, sizeof(sLightsBuffer));
memcpy(sMatrixStack, &info->mtxStackCopy, sizeof(MtxF) * 20);
memcpy(sCurrentMatrix, &info->currentMtxCopy, sizeof(MtxF));
sWarpTimerTarget = info->blueWarpTimerCopy;
memcpy(gActiveSounds, info->gActiveSoundsCopy, sizeof(gActiveSounds));
memcpy(gSoundBankMuted, &info->gSoundBankMutedCopy, sizeof(info->gSoundBankMutedCopy));
D_801333F0 = info->D_801333F0_copy;
gAudioSfxSwapOff = info->gAudioSfxSwapOff_copy;
memcpy(gAudioSfxSwapSource, &info->gAudioSfxSwapSource_copy,
sizeof(info->gAudioSfxSwapSource_copy));
memcpy(gAudioSfxSwapTarget, &info->gAudioSfxSwapTarget_copy,
sizeof(info->gAudioSfxSwapTarget_copy));
memcpy(gAudioSfxSwapMode, &info->gAudioSfxSwapMode_copy,
sizeof(info->gAudioSfxSwapMode_copy));
//Various static data
D_801755D0 = info->D_801755D0_copy;
LoadCameraData();
LoadOnePointDemoData();
LoadOverlayStaticData();
LoadMiscCodeData();
}