mirror of
https://github.com/HarbourMasters/Shipwright.git
synced 2025-08-22 14:23:44 -07:00
OOP Go Brrr
This commit is contained in:
parent
87e6c040e2
commit
786c0c2801
7 changed files with 248 additions and 455 deletions
|
@ -95,7 +95,7 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||||
<ClCompile>
|
<ClCompile>
|
||||||
<WarningLevel>TurnOffAllWarnings</WarningLevel>
|
<WarningLevel>EnableAllWarnings</WarningLevel>
|
||||||
<SDLCheck>false</SDLCheck>
|
<SDLCheck>false</SDLCheck>
|
||||||
<PreprocessorDefinitions>NOINCLUDE_GAME_PRINTF;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;ENABLE_OPENGL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
<PreprocessorDefinitions>NOINCLUDE_GAME_PRINTF;WIN32;_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;ENABLE_OPENGL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||||
<ConformanceMode>true</ConformanceMode>
|
<ConformanceMode>true</ConformanceMode>
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include "soh/OTRGlobals.h"
|
||||||
|
|
||||||
|
|
||||||
#define Path _Path
|
#define Path _Path
|
||||||
|
@ -307,47 +308,38 @@ static bool EntranceHandler(const std::vector<std::string>& args) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool SaveStateHandler(const std::vector<std::string>& args) {
|
static bool SaveStateHandler(const std::vector<std::string>& args) {
|
||||||
const SaveStateReturn rtn = SaveState::RequestSaveState(gCurrentSlot);
|
unsigned int slot = OTRGlobals::Instance->gSaveStateMgr->GetCurrentSlot();
|
||||||
|
const SaveStateReturn rtn = OTRGlobals::Instance->gSaveStateMgr->AddRequest({ slot, RequestType::SAVE });
|
||||||
|
|
||||||
switch (rtn) {
|
switch (rtn) {
|
||||||
case SaveStateReturn::SUCCESS:
|
case SaveStateReturn::SUCCESS:
|
||||||
INFO("[SOH] Saved state to slot %u", gCurrentSlot);
|
INFO("[SOH] Saved state to slot %u", slot);
|
||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
case SaveStateReturn::FAIL_INVALID_SLOT:
|
case SaveStateReturn::FAIL_INVALID_SLOT:
|
||||||
ERROR("[SOH] Invalid State Slot Number (%u)", gCurrentSlot);
|
ERROR("[SOH] Invalid State Slot Number (%u)", slot);
|
||||||
return CMD_FAILED;
|
return CMD_FAILED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool LoadStateHandler(const std::vector<std::string>& args) {
|
static bool LoadStateHandler(const std::vector<std::string>& args) {
|
||||||
const SaveStateReturn rtn = SaveState::RequestLoadState(gCurrentSlot);
|
unsigned int slot = OTRGlobals::Instance->gSaveStateMgr->GetCurrentSlot();
|
||||||
|
const SaveStateReturn rtn = OTRGlobals::Instance->gSaveStateMgr->AddRequest({ slot, RequestType::LOAD });
|
||||||
|
|
||||||
switch (rtn) {
|
switch (rtn) {
|
||||||
case SaveStateReturn::SUCCESS:
|
case SaveStateReturn::SUCCESS:
|
||||||
INFO("[SOH] Loaded state from slot %u", gCurrentSlot);
|
INFO("[SOH] Loaded state from slot %u", slot);
|
||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
case SaveStateReturn::FAIL_INVALID_SLOT:
|
case SaveStateReturn::FAIL_INVALID_SLOT:
|
||||||
ERROR("[SOH] Invalid State Slot Number (%u)", gCurrentSlot);
|
ERROR("[SOH] Invalid State Slot Number (%u)", slot);
|
||||||
return CMD_FAILED;
|
return CMD_FAILED;
|
||||||
case SaveStateReturn::FAIL_STATE_EMPTY:
|
case SaveStateReturn::FAIL_STATE_EMPTY:
|
||||||
ERROR("[SOH] State Slot (%u) is empty", gCurrentSlot);
|
ERROR("[SOH] State Slot (%u) is empty", slot);
|
||||||
return CMD_FAILED;
|
return CMD_FAILED;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool StateSlotCycleHandler(const std::vector<std::string>& args) {
|
|
||||||
if (gCurrentSlot == SaveState::SAVE_SLOT_MAX) {
|
|
||||||
gCurrentSlot = 0;
|
|
||||||
INFO("[SOH] Slot 0 selected");
|
|
||||||
} else {
|
|
||||||
gCurrentSlot++;
|
|
||||||
INFO("[SOH] Slot %u selected", gCurrentSlot);
|
|
||||||
}
|
|
||||||
return CMD_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool StateSlotSelectHandler(const std::vector<std::string>& args) {
|
static bool StateSlotSelectHandler(const std::vector<std::string>& args) {
|
||||||
if (args.size() != 2) {
|
if (args.size() != 2) {
|
||||||
ERROR("[SOH] Unexpected arguments passed");
|
ERROR("[SOH] Unexpected arguments passed");
|
||||||
|
@ -362,118 +354,16 @@ static bool StateSlotSelectHandler(const std::vector<std::string>& args) {
|
||||||
return CMD_FAILED;
|
return CMD_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (slot < 0 || slot > SaveState::SAVE_SLOT_MAX) {
|
if (slot < 0) {
|
||||||
ERROR("[SOH] Invalid slot passed. Slot must be between 0 and 2");
|
ERROR("[SOH] Invalid slot passed. Slot must be between 0 and 2");
|
||||||
return CMD_FAILED;
|
return CMD_FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
gCurrentSlot = slot;
|
OTRGlobals::Instance->gSaveStateMgr->SetCurrentSlot(slot);
|
||||||
INFO("[SOH] Slot %u selected", gCurrentSlot);
|
INFO("[SOH] Slot %u selected", OTRGlobals::Instance->gSaveStateMgr->GetCurrentSlot());
|
||||||
return CMD_SUCCESS;
|
return CMD_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool StateDeleteHandler(const std::vector<std::string>& args) {
|
|
||||||
int slot = gCurrentSlot;
|
|
||||||
|
|
||||||
if (args.size() == 2) {
|
|
||||||
|
|
||||||
try {
|
|
||||||
slot = std::stoi(args[1], nullptr, 10);
|
|
||||||
} catch (std::invalid_argument const& ex) {
|
|
||||||
ERROR("[SOH] SaveState slot value must be a number.");
|
|
||||||
return CMD_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (slot < 0 || slot > SaveState::SAVE_SLOT_MAX) {
|
|
||||||
ERROR("[SOH] Invalid slot passed. Slot must be between 0 and 2");
|
|
||||||
return CMD_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
SaveState::Delete(slot);
|
|
||||||
|
|
||||||
return CMD_SUCCESS;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool StateExportHandler(const std::vector<std::string>& args) {
|
|
||||||
int slot = gCurrentSlot;
|
|
||||||
|
|
||||||
if (args.size() == 2) {
|
|
||||||
|
|
||||||
try {
|
|
||||||
slot = std::stoi(args[1], nullptr, 10);
|
|
||||||
} catch (std::invalid_argument const& ex) {
|
|
||||||
ERROR("[SOH] SaveState slot value must be a number.");
|
|
||||||
return CMD_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (slot < 0 || slot > SaveState::SAVE_SLOT_MAX) {
|
|
||||||
ERROR("[SOH] Invalid slot passed. Slot must be between 0 and 2");
|
|
||||||
return CMD_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
const SaveStateReturn rtn = SaveState::Export(slot);
|
|
||||||
|
|
||||||
switch (rtn) {
|
|
||||||
case SaveStateReturn::SUCCESS:
|
|
||||||
INFO("[SOH] Exported slot %u", slot);
|
|
||||||
return CMD_SUCCESS;
|
|
||||||
case SaveStateReturn::FAIL_FILE_NOT_OPENED:
|
|
||||||
ERROR("[SOH] Could not open file for writing");
|
|
||||||
return CMD_FAILED;
|
|
||||||
case SaveStateReturn::FAIL_INVALID_SLOT:
|
|
||||||
ERROR("[SOH] Invalid State Slot Number %u", slot);
|
|
||||||
return CMD_FAILED;
|
|
||||||
case SaveStateReturn::FAIL_STATE_EMPTY:
|
|
||||||
ERROR("[SOH] SaveState slot %u empty", slot);
|
|
||||||
return CMD_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool StateImportHandler(const std::vector<std::string>& args) {
|
|
||||||
int slot = gCurrentSlot;
|
|
||||||
|
|
||||||
if (args.size() == 2) {
|
|
||||||
|
|
||||||
try {
|
|
||||||
slot = std::stoi(args[1], nullptr, 10);
|
|
||||||
} catch (std::invalid_argument const& ex) {
|
|
||||||
ERROR("[SOH] SaveState slot value must be a number.");
|
|
||||||
return CMD_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (slot < 0 || slot > SaveState::SAVE_SLOT_MAX) {
|
|
||||||
ERROR("[SOH] Invalid slot passed. Slot must be between 0 and 2");
|
|
||||||
return CMD_FAILED;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const SaveStateReturn rtn = SaveState::Import(slot);
|
|
||||||
|
|
||||||
switch (rtn) {
|
|
||||||
case SaveStateReturn::SUCCESS:
|
|
||||||
INFO("[SOH] Imported slot %u", slot);
|
|
||||||
return CMD_SUCCESS;
|
|
||||||
case SaveStateReturn::FAIL_FILE_NOT_OPENED:
|
|
||||||
ERROR("[SOH] Could not open file for reading");
|
|
||||||
return CMD_FAILED;
|
|
||||||
case SaveStateReturn::FAIL_NO_MEMORY:
|
|
||||||
ERROR("[SOH] Could not allocate memory for Slot Number %u", slot);
|
|
||||||
return CMD_FAILED;
|
|
||||||
case SaveStateReturn::FAIL_STATE_EMPTY:
|
|
||||||
ERROR("[SOH] SaveState slot %u empty", slot);
|
|
||||||
return CMD_FAILED;
|
|
||||||
case SaveStateReturn::FAIL_INVALID_MAGIC:
|
|
||||||
ERROR("[SOH] Invalid magic number in file");
|
|
||||||
return CMD_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#define VARTYPE_INTEGER 0
|
#define VARTYPE_INTEGER 0
|
||||||
#define VARTYPE_FLOAT 1
|
#define VARTYPE_FLOAT 1
|
||||||
#define VARTYPE_STRING 2
|
#define VARTYPE_STRING 2
|
||||||
|
@ -590,19 +480,9 @@ void DebugConsole_Init(void) {
|
||||||
|
|
||||||
CMD_REGISTER("save_state", { SaveStateHandler, "Save a state." });
|
CMD_REGISTER("save_state", { SaveStateHandler, "Save a state." });
|
||||||
CMD_REGISTER("load_state", { LoadStateHandler, "Load a state." });
|
CMD_REGISTER("load_state", { LoadStateHandler, "Load a state." });
|
||||||
CMD_REGISTER("cycle_state", { StateSlotCycleHandler, "Cycle through states.",});
|
|
||||||
CMD_REGISTER("clear_state", { StateDeleteHandler, "Clear a save slot", {
|
|
||||||
{ "Slot number", ArgumentType::NUMBER, true },
|
|
||||||
} });
|
|
||||||
CMD_REGISTER("set_slot", { StateSlotSelectHandler, "Selects a SaveState slot", {
|
CMD_REGISTER("set_slot", { StateSlotSelectHandler, "Selects a SaveState slot", {
|
||||||
{ "Slot number", ArgumentType::NUMBER, }
|
{ "Slot number", ArgumentType::NUMBER, }
|
||||||
} });
|
} });
|
||||||
CMD_REGISTER("export_state", { StateExportHandler, "Exports a SaveState to a file", {
|
|
||||||
{ "Slot number", ArgumentType::NUMBER, true },
|
|
||||||
} });
|
|
||||||
CMD_REGISTER("import_state", { StateImportHandler, "Imports a SaveState to a file", {
|
|
||||||
{ "Slot number", ArgumentType::NUMBER, true },
|
|
||||||
} });
|
|
||||||
DebugConsole_LoadCVars();
|
DebugConsole_LoadCVars();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,172 +1,135 @@
|
||||||
#include "savestates.h"
|
#include "savestates.h"
|
||||||
|
|
||||||
#include "GameVersions.h"
|
#include "GameVersions.h"
|
||||||
#include <variables.h>
|
|
||||||
|
|
||||||
#include <cstdio> // std::sprintf
|
#include <cstdio> // std::sprintf
|
||||||
#include <mutex>
|
|
||||||
|
|
||||||
#include "soh/OTRAudio.h"
|
#include "spdlog/spdlog.h"
|
||||||
//#include "spdlog/spdlog.h"
|
|
||||||
|
|
||||||
//#include "global.h"
|
#include <soh/OTRGlobals.h>
|
||||||
//#include <soh/OTRGlobals.h>
|
|
||||||
|
|
||||||
|
#include "z64.h"
|
||||||
|
#include "z64save.h"
|
||||||
|
#include <variables.h>
|
||||||
|
#include <functions.h>
|
||||||
|
#include "z64map_mark.h"
|
||||||
|
|
||||||
//TODO is there a better way?
|
// FROM z_lights.c
|
||||||
unsigned int gCurrentSlot = 0;
|
// I didn't feel like moving it into a header file.
|
||||||
|
#define LIGHTS_BUFFER_SIZE 32
|
||||||
|
|
||||||
static std::array<SaveStateInfo*, SaveState::SAVE_SLOT_MAX + 1> gSaveStates;
|
typedef struct {
|
||||||
|
/* 0x000 */ s32 numOccupied;
|
||||||
|
/* 0x004 */ s32 searchIndex;
|
||||||
|
/* 0x008 */ LightNode buf[LIGHTS_BUFFER_SIZE];
|
||||||
|
} LightsBuffer; // size = 0x188
|
||||||
|
|
||||||
|
typedef struct SaveStateInfo {
|
||||||
|
SaveStateHeader stateHeader;
|
||||||
|
|
||||||
|
unsigned char sysHeapCopy[SYSTEM_HEAP_SIZE];
|
||||||
|
unsigned char audioHeapCopy[AUDIO_HEAP_SIZE];
|
||||||
|
|
||||||
SaveState::SaveState(){}
|
SaveContext saveContextCopy;
|
||||||
SaveState::~SaveState() {}
|
GameInfo gameInfoCopy;
|
||||||
|
LightsBuffer lightBufferCopy;
|
||||||
|
AudioContext audioContextCopy;
|
||||||
|
std::array<MtxF, 20> mtxStackCopy; // always 20 matricies
|
||||||
|
MtxF currentMtxCopy;
|
||||||
|
uint32_t rngSeed;
|
||||||
|
int16_t blueWarpTimerCopy; /* From door_warp_1 */
|
||||||
|
|
||||||
void SaveState::Init(void) {
|
std::array<SeqScriptState, 4> seqScriptStateCopy; // Unrelocated
|
||||||
gSaveStates[0] = nullptr;
|
// std::array<u8, 4> seqIdCopy;
|
||||||
gSaveStates[1] = nullptr;
|
std::array<unk_D_8016E750, 4> unk_D_8016E750Copy;
|
||||||
gSaveStates[2] = nullptr;
|
|
||||||
|
ActiveSound gActiveSoundsCopy[7][MAX_CHANNELS_PER_BANK];
|
||||||
|
std::array<u8, 7> gSoundBankMutedCopy;
|
||||||
|
u8 D_801333F0_copy;
|
||||||
|
u8 gAudioSfxSwapOff_copy;
|
||||||
|
std::array<u16, 10> gAudioSfxSwapSource_copy;
|
||||||
|
std::array<u16, 10> gAudioSfxSwapTarget_copy;
|
||||||
|
std::array<u8, 10> gAudioSfxSwapMode_copy;
|
||||||
|
void (*D_801755D0_copy)(void);
|
||||||
|
MapMarkData** sLoadedMarkDataTableCopy;
|
||||||
|
} 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);
|
||||||
|
|
||||||
|
SaveStateInfo* GetSaveStateInfo(void);
|
||||||
|
};
|
||||||
|
|
||||||
|
SaveStateMgr::SaveStateMgr() {
|
||||||
|
this->SetCurrentSlot(0);
|
||||||
|
}
|
||||||
|
SaveStateMgr::~SaveStateMgr() {
|
||||||
|
this->states.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SaveState::SetHeader(SaveStateHeader& header) {
|
SaveState::SaveState(std::shared_ptr<SaveStateMgr> mgr, unsigned int slot) : saveStateMgr(mgr), slot(slot), info(nullptr) {
|
||||||
header.stateMagic = 0x07151129;
|
this->info = std::make_shared<SaveStateInfo>();
|
||||||
//TODO state version ENUM;
|
|
||||||
header.stateVersion = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SaveStateReturn SaveState::Delete(const unsigned int slot) {
|
void SaveState::BackupSeqScriptState(void) {
|
||||||
if (slot > SAVE_SLOT_MAX) {
|
|
||||||
return SaveStateReturn::FAIL_INVALID_SLOT;
|
|
||||||
}
|
|
||||||
if (gSaveStates[slot] != nullptr) {
|
|
||||||
delete gSaveStates[slot];
|
|
||||||
gSaveStates[slot] = nullptr;
|
|
||||||
}
|
|
||||||
return SaveStateReturn::SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
SaveStateReturn SaveState::Export(const unsigned int slot) {
|
|
||||||
if (slot > SAVE_SLOT_MAX) {
|
|
||||||
return SaveStateReturn::FAIL_INVALID_SLOT;
|
|
||||||
}
|
|
||||||
if (gSaveStates[slot] == nullptr) {
|
|
||||||
return SaveStateReturn::FAIL_STATE_EMPTY;
|
|
||||||
}
|
|
||||||
|
|
||||||
char outFileName[20];
|
|
||||||
std::sprintf(outFileName, "SOH_STATE_%u.state", gCurrentSlot);
|
|
||||||
|
|
||||||
FILE* outFile = fopen(outFileName, "wb+");
|
|
||||||
|
|
||||||
if (outFile == nullptr) {
|
|
||||||
return SaveStateReturn::FAIL_FILE_NOT_OPENED;
|
|
||||||
}
|
|
||||||
|
|
||||||
SaveState::SetHeader(gSaveStates[slot]->stateHeader);
|
|
||||||
std::fwrite(gSaveStates[slot], sizeof(SaveState), 1, outFile);
|
|
||||||
std::fclose(outFile);
|
|
||||||
|
|
||||||
return SaveStateReturn::SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
SaveStateReturn SaveState::Import(const unsigned int slot) {
|
|
||||||
if (slot > SAVE_SLOT_MAX) {
|
|
||||||
return SaveStateReturn::FAIL_INVALID_SLOT;
|
|
||||||
}
|
|
||||||
|
|
||||||
char inFileName[20];
|
|
||||||
std::sprintf(inFileName, "SOH_STATE_%u.state", gCurrentSlot);
|
|
||||||
|
|
||||||
FILE* inFile = std::fopen(inFileName, "rb");
|
|
||||||
|
|
||||||
if (inFile == nullptr) {
|
|
||||||
return SaveStateReturn::FAIL_FILE_NOT_OPENED;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::fseek(inFile, 0, SEEK_END);
|
|
||||||
const size_t inFileSize = std::ftell(inFile);
|
|
||||||
|
|
||||||
if (inFileSize != sizeof(SaveState)) {
|
|
||||||
std::fclose(inFile);
|
|
||||||
return SaveStateReturn::FAIL_INVALID_SIZE;
|
|
||||||
}
|
|
||||||
std::fseek(inFile, 0, SEEK_SET);
|
|
||||||
|
|
||||||
SaveStateHeader tempHeader;
|
|
||||||
std::fread(&tempHeader, sizeof(SaveStateHeader), 1, inFile);
|
|
||||||
|
|
||||||
if (tempHeader.stateMagic != 0x07151129) {
|
|
||||||
std::fclose(inFile);
|
|
||||||
return SaveStateReturn::FAIL_INVALID_MAGIC;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gSaveStates[slot] == nullptr) {
|
|
||||||
gSaveStates[slot] = new SaveStateInfo;
|
|
||||||
if (gSaveStates[slot] == nullptr) {
|
|
||||||
fclose(inFile);
|
|
||||||
return SaveStateReturn::FAIL_NO_MEMORY;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::fseek(inFile, 0, SEEK_SET);
|
|
||||||
std::fread(gSaveStates[slot], sizeof(SaveStateInfo), 1, inFile);
|
|
||||||
std::fclose(inFile);
|
|
||||||
//TODO version system
|
|
||||||
//if (gSaveStates[slot]->stateHeader.stateVersion != 0) {
|
|
||||||
// return SaveStateReturn::FAIL_INVALID_STATE;
|
|
||||||
//}
|
|
||||||
|
|
||||||
return SaveStateReturn::SUCCESS;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void SaveState::BackupSeqScriptState(SaveStateInfo* state) {
|
|
||||||
for (unsigned int i = 0; i < 4; i++) {
|
for (unsigned int i = 0; i < 4; i++) {
|
||||||
state->seqScriptStateCopy[i].value = gAudioContext.seqPlayers[i].scriptState.value;
|
info->seqScriptStateCopy[i].value = gAudioContext.seqPlayers[i].scriptState.value;
|
||||||
|
|
||||||
state->seqScriptStateCopy[i].remLoopIters[0] = gAudioContext.seqPlayers[i].scriptState.remLoopIters[0];
|
info->seqScriptStateCopy[i].remLoopIters[0] = gAudioContext.seqPlayers[i].scriptState.remLoopIters[0];
|
||||||
state->seqScriptStateCopy[i].remLoopIters[1] = gAudioContext.seqPlayers[i].scriptState.remLoopIters[1];
|
info->seqScriptStateCopy[i].remLoopIters[1] = gAudioContext.seqPlayers[i].scriptState.remLoopIters[1];
|
||||||
state->seqScriptStateCopy[i].remLoopIters[2] = gAudioContext.seqPlayers[i].scriptState.remLoopIters[2];
|
info->seqScriptStateCopy[i].remLoopIters[2] = gAudioContext.seqPlayers[i].scriptState.remLoopIters[2];
|
||||||
state->seqScriptStateCopy[i].remLoopIters[3] = gAudioContext.seqPlayers[i].scriptState.remLoopIters[3];
|
info->seqScriptStateCopy[i].remLoopIters[3] = gAudioContext.seqPlayers[i].scriptState.remLoopIters[3];
|
||||||
|
|
||||||
state->seqScriptStateCopy[i].depth = gAudioContext.seqPlayers[i].scriptState.depth;
|
info->seqScriptStateCopy[i].depth = gAudioContext.seqPlayers[i].scriptState.depth;
|
||||||
|
|
||||||
state->seqScriptStateCopy[i].pc = (u8*)((uintptr_t)gAudioContext.seqPlayers[i].scriptState.pc - (uintptr_t)gAudioHeap);
|
info->seqScriptStateCopy[i].pc = (u8*)((uintptr_t)gAudioContext.seqPlayers[i].scriptState.pc - (uintptr_t)gAudioHeap);
|
||||||
|
|
||||||
state->seqScriptStateCopy[i].stack[0] =
|
info->seqScriptStateCopy[i].stack[0] =
|
||||||
(u8*)((uintptr_t)gAudioContext.seqPlayers[i].scriptState.stack[0] - (uintptr_t)gAudioHeap);
|
(u8*)((uintptr_t)gAudioContext.seqPlayers[i].scriptState.stack[0] - (uintptr_t)gAudioHeap);
|
||||||
state->seqScriptStateCopy[i].stack[1] =
|
info->seqScriptStateCopy[i].stack[1] =
|
||||||
(u8*)((uintptr_t)gAudioContext.seqPlayers[i].scriptState.stack[1] - (uintptr_t)gAudioHeap);
|
(u8*)((uintptr_t)gAudioContext.seqPlayers[i].scriptState.stack[1] - (uintptr_t)gAudioHeap);
|
||||||
state->seqScriptStateCopy[i].stack[2] =
|
info->seqScriptStateCopy[i].stack[2] =
|
||||||
(u8*)((uintptr_t)gAudioContext.seqPlayers[i].scriptState.stack[2] - (uintptr_t)gAudioHeap);
|
(u8*)((uintptr_t)gAudioContext.seqPlayers[i].scriptState.stack[2] - (uintptr_t)gAudioHeap);
|
||||||
state->seqScriptStateCopy[i].stack[3] =
|
info->seqScriptStateCopy[i].stack[3] =
|
||||||
(u8*)((uintptr_t)gAudioContext.seqPlayers[i].scriptState.stack[3] - (uintptr_t)gAudioHeap);
|
(u8*)((uintptr_t)gAudioContext.seqPlayers[i].scriptState.stack[3] - (uintptr_t)gAudioHeap);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SaveState::LoadSeqScriptState(SaveStateInfo* state) {
|
void SaveState::LoadSeqScriptState(void) {
|
||||||
for (unsigned int i = 0; i < 4; i++) {
|
for (unsigned int i = 0; i < 4; i++) {
|
||||||
gAudioContext.seqPlayers[i].scriptState.value = state->seqScriptStateCopy[i].value;
|
gAudioContext.seqPlayers[i].scriptState.value = info->seqScriptStateCopy[i].value;
|
||||||
|
|
||||||
gAudioContext.seqPlayers[i].scriptState.remLoopIters[0] = state->seqScriptStateCopy[i].remLoopIters[0];
|
gAudioContext.seqPlayers[i].scriptState.remLoopIters[0] = info->seqScriptStateCopy[i].remLoopIters[0];
|
||||||
gAudioContext.seqPlayers[i].scriptState.remLoopIters[1] = state->seqScriptStateCopy[i].remLoopIters[1];
|
gAudioContext.seqPlayers[i].scriptState.remLoopIters[1] = info->seqScriptStateCopy[i].remLoopIters[1];
|
||||||
gAudioContext.seqPlayers[i].scriptState.remLoopIters[2] = state->seqScriptStateCopy[i].remLoopIters[2];
|
gAudioContext.seqPlayers[i].scriptState.remLoopIters[2] = info->seqScriptStateCopy[i].remLoopIters[2];
|
||||||
gAudioContext.seqPlayers[i].scriptState.remLoopIters[3] = state->seqScriptStateCopy[i].remLoopIters[3];
|
gAudioContext.seqPlayers[i].scriptState.remLoopIters[3] = info->seqScriptStateCopy[i].remLoopIters[3];
|
||||||
|
|
||||||
gAudioContext.seqPlayers[i].scriptState.depth = state->seqScriptStateCopy[i].depth;
|
gAudioContext.seqPlayers[i].scriptState.depth = info->seqScriptStateCopy[i].depth;
|
||||||
|
|
||||||
gAudioContext.seqPlayers[i].scriptState.pc =
|
gAudioContext.seqPlayers[i].scriptState.pc =
|
||||||
(u8*)((uintptr_t)state->seqScriptStateCopy[i].pc + (uintptr_t)gAudioHeap);
|
(u8*)((uintptr_t)info->seqScriptStateCopy[i].pc + (uintptr_t)gAudioHeap);
|
||||||
|
|
||||||
gAudioContext.seqPlayers[i].scriptState.stack[0] =
|
gAudioContext.seqPlayers[i].scriptState.stack[0] =
|
||||||
(u8*)((uintptr_t)state->seqScriptStateCopy[i].stack[0] + (uintptr_t)gAudioHeap);
|
(u8*)((uintptr_t)info->seqScriptStateCopy[i].stack[0] + (uintptr_t)gAudioHeap);
|
||||||
gAudioContext.seqPlayers[i].scriptState.stack[1] =
|
gAudioContext.seqPlayers[i].scriptState.stack[1] =
|
||||||
(u8*)((uintptr_t)state->seqScriptStateCopy[i].stack[1] + (uintptr_t)gAudioHeap);
|
(u8*)((uintptr_t)info->seqScriptStateCopy[i].stack[1] + (uintptr_t)gAudioHeap);
|
||||||
gAudioContext.seqPlayers[i].scriptState.stack[2] =
|
gAudioContext.seqPlayers[i].scriptState.stack[2] =
|
||||||
(u8*)((uintptr_t)state->seqScriptStateCopy[i].stack[2] + (uintptr_t)gAudioHeap);
|
(u8*)((uintptr_t)info->seqScriptStateCopy[i].stack[2] + (uintptr_t)gAudioHeap);
|
||||||
gAudioContext.seqPlayers[i].scriptState.stack[3] =
|
gAudioContext.seqPlayers[i].scriptState.stack[3] =
|
||||||
(u8*)((uintptr_t)state->seqScriptStateCopy[i].stack[3] + (uintptr_t)gAudioHeap);
|
(u8*)((uintptr_t)info->seqScriptStateCopy[i].stack[3] + (uintptr_t)gAudioHeap);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -175,136 +138,137 @@ extern "C" MtxF* sMatrixStack;
|
||||||
extern "C" MtxF* sCurrentMatrix;
|
extern "C" MtxF* sCurrentMatrix;
|
||||||
extern "C" LightsBuffer sLightsBuffer;
|
extern "C" LightsBuffer sLightsBuffer;
|
||||||
extern "C" s16 sWarpTimerTarget;
|
extern "C" s16 sWarpTimerTarget;
|
||||||
|
extern "C" MapMarkData** sLoadedMarkDataTable;
|
||||||
std::queue<SaveStateRequest> SaveState::requests;
|
|
||||||
|
|
||||||
extern "C" void ProcessSaveStateRequests(void) {
|
extern "C" void ProcessSaveStateRequests(void) {
|
||||||
SaveState::ProcessSaveStateRequestsImpl();
|
OTRGlobals::Instance->gSaveStateMgr->ProcessSaveStateRequests();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SaveState::ProcessSaveStateRequestsImpl(void) {
|
void SaveStateMgr::SetCurrentSlot(unsigned int slot) {
|
||||||
while (!requests.empty()) {
|
this->currentSlot = slot;
|
||||||
if (requests.front().type == RequestType::SAVE) {
|
}
|
||||||
SaveState::Save(requests.front().slot);
|
|
||||||
} else if (requests.front().type == RequestType::LOAD) {
|
unsigned int SaveStateMgr::GetCurrentSlot(void) {
|
||||||
SaveState::Load(requests.front().slot);
|
return this->currentSlot;
|
||||||
} else {
|
}
|
||||||
// SPDLOG_ERROR("Invalid Request type for SaveState: {}", requests.front().type);
|
|
||||||
|
void SaveStateMgr::ProcessSaveStateRequests(void) {
|
||||||
|
std::unique_lock<std::mutex> Lock(this->mutex);
|
||||||
|
|
||||||
|
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();
|
||||||
|
break;
|
||||||
|
case RequestType::LOAD:
|
||||||
|
if (this->states.contains(request.slot)) {
|
||||||
|
this->states[request.slot]->Load();
|
||||||
|
} else {
|
||||||
|
//TODO log invalid state
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
[[unlikely]] default:
|
||||||
|
//TODO fix logging
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
requests.pop();
|
this->requests.pop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SaveStateReturn SaveState::RequestSaveState(const unsigned int slot) {
|
SaveStateReturn SaveStateMgr::AddRequest(const SaveStateRequest request) {
|
||||||
if (slot > SaveState::SAVE_SLOT_MAX) {
|
std::unique_lock<std::mutex> Lock(this->mutex);
|
||||||
return SaveStateReturn::FAIL_INVALID_SLOT;
|
|
||||||
}
|
|
||||||
if (gSaveStates[slot] == nullptr) {
|
|
||||||
gSaveStates[slot] = new SaveStateInfo;
|
|
||||||
if (gSaveStates[slot] == nullptr) {
|
|
||||||
return SaveStateReturn::FAIL_NO_MEMORY;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SaveState::requests.push({ slot, RequestType::SAVE });
|
switch (request.type) {
|
||||||
return SaveStateReturn::SUCCESS;
|
case RequestType::SAVE:
|
||||||
|
requests.push(request);
|
||||||
|
break;
|
||||||
|
case RequestType::LOAD:
|
||||||
|
if (states.contains(request.slot)) {
|
||||||
|
requests.push(request);
|
||||||
|
} else {
|
||||||
|
return SaveStateReturn::FAIL_INVALID_SLOT;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
[[unlikely]] default:
|
||||||
|
//TODO fix logging
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
requests.push(request);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void SaveState::Save(const unsigned int slot) {
|
void SaveState::Save(void) {
|
||||||
std::unique_lock<std::mutex> Lock(audio.mutex);
|
//this->SetHeader();
|
||||||
|
|
||||||
|
memcpy(&info->sysHeapCopy, gSystemHeap, SYSTEM_HEAP_SIZE /* sizeof(gSystemHeap) */);
|
||||||
|
memcpy(&info->audioHeapCopy, gAudioHeap, AUDIO_HEAP_SIZE /* sizeof(gAudioContext) */);
|
||||||
|
|
||||||
SaveState::SetHeader(gSaveStates[slot]->stateHeader);
|
memcpy(&info->audioContextCopy, &gAudioContext, sizeof(AudioContext));
|
||||||
|
memcpy(&info->unk_D_8016E750Copy, D_8016E750, sizeof(info->unk_D_8016E750Copy));
|
||||||
|
BackupSeqScriptState();
|
||||||
|
|
||||||
memcpy(&gSaveStates[slot]->sysHeapCopy, gSystemHeap, SYSTEM_HEAP_SIZE /* sizeof(gSystemHeap) */);
|
memcpy(info->gActiveSoundsCopy, gActiveSounds, sizeof(gActiveSounds));
|
||||||
memcpy(&gSaveStates[slot]->audioHeapCopy, gAudioHeap, AUDIO_HEAP_SIZE /* sizeof(gAudioContext) */);
|
memcpy(&info->gSoundBankMutedCopy, gSoundBankMuted, sizeof(info->gSoundBankMutedCopy));
|
||||||
|
|
||||||
memcpy(&gSaveStates[slot]->audioContextCopy, &gAudioContext, sizeof(AudioContext));
|
info->D_801333F0_copy = D_801333F0;
|
||||||
memcpy(&gSaveStates[slot]->unk_D_8016E750Copy, D_8016E750, sizeof(gSaveStates[slot]->unk_D_8016E750Copy));
|
info->gAudioSfxSwapOff_copy = gAudioSfxSwapOff;
|
||||||
BackupSeqScriptState(gSaveStates[slot]);
|
|
||||||
|
|
||||||
memcpy(gSaveStates[slot]->gActiveSoundsCopy, gActiveSounds, sizeof(gActiveSounds));
|
memcpy(&info->gAudioSfxSwapSource_copy, gAudioSfxSwapSource,
|
||||||
memcpy(&gSaveStates[slot]->gSoundBankMutedCopy, gSoundBankMuted, sizeof(gSaveStates[0]->gSoundBankMutedCopy));
|
sizeof(info->gAudioSfxSwapSource_copy));
|
||||||
gSaveStates[slot]->D_801333F0_copy = D_801333F0;
|
memcpy(&info->gAudioSfxSwapTarget_copy, gAudioSfxSwapTarget,
|
||||||
gSaveStates[slot]->gAudioSfxSwapOff_copy = gAudioSfxSwapOff;
|
sizeof(info->gAudioSfxSwapTarget_copy));
|
||||||
|
memcpy(&info->gAudioSfxSwapMode_copy, gAudioSfxSwapMode,
|
||||||
|
sizeof(info->gAudioSfxSwapMode_copy));
|
||||||
|
|
||||||
memcpy(&gSaveStates[slot]->gAudioSfxSwapSource_copy, gAudioSfxSwapSource,
|
info->D_801755D0_copy = D_801755D0;
|
||||||
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;
|
memcpy(&info->saveContextCopy, &gSaveContext, sizeof(gSaveContext));
|
||||||
|
memcpy(&info->gameInfoCopy, gGameInfo, sizeof(*gGameInfo));
|
||||||
|
memcpy(&info->lightBufferCopy, &sLightsBuffer, sizeof(sLightsBuffer));
|
||||||
// gSaveStates[slot]->seqIdCopy[0] = gAudioContext.seqPlayers[0].seqId;
|
memcpy(&info->mtxStackCopy, &sMatrixStack, sizeof(MtxF) * 20);
|
||||||
// gSaveStates[slot]->seqIdCopy[1] = gAudioContext.seqPlayers[1].seqId;
|
memcpy(&info->currentMtxCopy, &sCurrentMatrix, sizeof(MtxF));
|
||||||
// gSaveStates[slot]->seqIdCopy[2] = gAudioContext.seqPlayers[2].seqId;
|
info->blueWarpTimerCopy = sWarpTimerTarget;
|
||||||
// gSaveStates[slot]->seqIdCopy[3] = gAudioContext.seqPlayers[3].seqId;
|
info->sLoadedMarkDataTableCopy = sLoadedMarkDataTable;
|
||||||
|
|
||||||
|
|
||||||
memcpy(&gSaveStates[slot]->saveContextCopy, &gSaveContext, sizeof(gSaveContext));
|
|
||||||
memcpy(&gSaveStates[slot]->gameInfoCopy, gGameInfo, sizeof(*gGameInfo));
|
|
||||||
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;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SaveStateReturn SaveState::RequestLoadState(const unsigned int slot) {
|
void SaveState::Load(void) {
|
||||||
if (slot > SaveState::SAVE_SLOT_MAX) {
|
memcpy(gSystemHeap, &info->sysHeapCopy, SYSTEM_HEAP_SIZE);
|
||||||
return SaveStateReturn::FAIL_INVALID_SLOT;
|
memcpy(gAudioHeap, &info->audioHeapCopy, AUDIO_HEAP_SIZE);
|
||||||
}
|
|
||||||
if (gSaveStates[slot] == nullptr) {
|
|
||||||
return SaveStateReturn::FAIL_STATE_EMPTY;
|
|
||||||
}
|
|
||||||
|
|
||||||
SaveState::requests.push({ slot, RequestType::LOAD });
|
memcpy(&gAudioContext, &info->audioContextCopy, sizeof(AudioContext));
|
||||||
return SaveStateReturn::SUCCESS;
|
memcpy(D_8016E750, &info->unk_D_8016E750Copy, sizeof(info->unk_D_8016E750Copy));
|
||||||
}
|
LoadSeqScriptState();
|
||||||
|
|
||||||
void SaveState::Load(const unsigned int slot) {
|
|
||||||
|
|
||||||
std::unique_lock<std::mutex> Lock(audio.mutex);
|
|
||||||
|
|
||||||
|
|
||||||
|
memcpy(&gSaveContext, &info->saveContextCopy, sizeof(gSaveContext));
|
||||||
//gSaveStates[slot]->stateHeader.gameVersion = 0;
|
memcpy(gGameInfo, &info->gameInfoCopy, sizeof(*gGameInfo));
|
||||||
//gSaveStates[slot]->stateHeader.stateVersion = 0;
|
memcpy(&sLightsBuffer, &info->lightBufferCopy, sizeof(sLightsBuffer));
|
||||||
|
memcpy(&sMatrixStack, &info->mtxStackCopy, sizeof(MtxF) * 20);
|
||||||
memcpy(gSystemHeap, &gSaveStates[slot]->sysHeapCopy, SYSTEM_HEAP_SIZE);
|
memcpy(&sCurrentMatrix, &info->currentMtxCopy, sizeof(MtxF));
|
||||||
memcpy(gAudioHeap, &gSaveStates[slot]->audioHeapCopy, AUDIO_HEAP_SIZE);
|
sWarpTimerTarget = info->blueWarpTimerCopy;
|
||||||
|
|
||||||
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(&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
|
//TODO RNG seed
|
||||||
|
|
||||||
memcpy(gActiveSounds, gSaveStates[slot]->gActiveSoundsCopy, sizeof(gActiveSounds));
|
memcpy(gActiveSounds, info->gActiveSoundsCopy, sizeof(gActiveSounds));
|
||||||
memcpy(gSoundBankMuted, &gSaveStates[slot]->gSoundBankMutedCopy, sizeof(gSaveStates[0]->gSoundBankMutedCopy));
|
memcpy(gSoundBankMuted, &info->gSoundBankMutedCopy, sizeof(info->gSoundBankMutedCopy));
|
||||||
D_801333F0 = gSaveStates[slot]->D_801333F0_copy;
|
D_801333F0 = info->D_801333F0_copy;
|
||||||
gAudioSfxSwapOff = gSaveStates[slot]->gAudioSfxSwapOff_copy;
|
gAudioSfxSwapOff = info->gAudioSfxSwapOff_copy;
|
||||||
|
|
||||||
memcpy(gAudioSfxSwapSource, &gSaveStates[slot]->gAudioSfxSwapSource_copy,
|
memcpy(gAudioSfxSwapSource, &info->gAudioSfxSwapSource_copy,
|
||||||
sizeof(&gSaveStates[slot]->gAudioSfxSwapSource_copy));
|
sizeof(info->gAudioSfxSwapSource_copy));
|
||||||
memcpy(gAudioSfxSwapTarget, &gSaveStates[slot]->gAudioSfxSwapTarget_copy,
|
memcpy(gAudioSfxSwapTarget, &info->gAudioSfxSwapTarget_copy,
|
||||||
sizeof(&gSaveStates[slot]->gAudioSfxSwapTarget_copy));
|
sizeof(info->gAudioSfxSwapTarget_copy));
|
||||||
memcpy(gAudioSfxSwapMode, &gSaveStates[slot]->gAudioSfxSwapMode_copy,
|
memcpy(gAudioSfxSwapMode, &info->gAudioSfxSwapMode_copy,
|
||||||
sizeof(&gSaveStates[slot]->gAudioSfxSwapMode_copy));
|
sizeof(info->gAudioSfxSwapMode_copy));
|
||||||
|
Audio_ResetSounds();
|
||||||
|
Audio_SendCmd
|
||||||
|
|
||||||
D_801755D0 = gSaveStates[slot]->D_801755D0_copy;
|
D_801755D0 = info->D_801755D0_copy;
|
||||||
|
sLoadedMarkDataTable = info->sLoadedMarkDataTableCopy;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,33 +1,22 @@
|
||||||
#ifndef SAVE_STATES_H
|
#ifndef SAVE_STATES_H
|
||||||
#define SAVE_STATES_H
|
#define SAVE_STATES_H
|
||||||
#include "z64.h"
|
|
||||||
#include "z64save.h"
|
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
|
#include <unordered_map>
|
||||||
// FROM z_lights.c
|
#include <memory>
|
||||||
// I didn't feel like moving it into a header file.
|
#include <mutex>
|
||||||
#define LIGHTS_BUFFER_SIZE 32
|
|
||||||
//#define LIGHTS_BUFFER_SIZE 1024 // Kill me
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
/* 0x000 */ s32 numOccupied;
|
|
||||||
/* 0x004 */ s32 searchIndex;
|
|
||||||
/* 0x008 */ LightNode buf[LIGHTS_BUFFER_SIZE];
|
|
||||||
} LightsBuffer; // size = 0x188
|
|
||||||
|
|
||||||
|
|
||||||
enum class SaveStateReturn {
|
enum class SaveStateReturn {
|
||||||
SUCCESS,
|
SUCCESS,
|
||||||
FAIL_INVALID_SLOT,
|
FAIL_INVALID_SLOT,
|
||||||
FAIL_NO_MEMORY,
|
FAIL_NO_MEMORY,
|
||||||
FAIL_STATE_EMPTY,
|
FAIL_STATE_EMPTY,
|
||||||
FAIL_FILE_NOT_FOUND,
|
FAIL_FILE_NOT_FOUND,
|
||||||
FAIL_FILE_NOT_OPENED,
|
FAIL_FILE_NOT_OPENED,
|
||||||
FAIL_INVALID_MAGIC,
|
FAIL_INVALID_MAGIC,
|
||||||
FAIL_INVALID_SIZE,
|
FAIL_INVALID_SIZE,
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct SaveStateHeader {
|
typedef struct SaveStateHeader {
|
||||||
|
@ -41,78 +30,34 @@ enum class RequestType {
|
||||||
LOAD,
|
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<MtxF, 20> mtxStackCopy; // always 20 matricies
|
|
||||||
MtxF currentMtxCopy;
|
|
||||||
uint32_t rngSeed;
|
|
||||||
int16_t blueWarpTimerCopy; /* From door_warp_1 */
|
|
||||||
|
|
||||||
std::array<SeqScriptState, 4> seqScriptStateCopy; // Unrelocated
|
|
||||||
// std::array<u8, 4> seqIdCopy;
|
|
||||||
std::array<unk_D_8016E750, 4> unk_D_8016E750Copy;
|
|
||||||
|
|
||||||
ActiveSound gActiveSoundsCopy[7][MAX_CHANNELS_PER_BANK];
|
|
||||||
std::array<u8, 7> gSoundBankMutedCopy;
|
|
||||||
u8 D_801333F0_copy;
|
|
||||||
u8 gAudioSfxSwapOff_copy;
|
|
||||||
std::array<u16, 10> gAudioSfxSwapSource_copy;
|
|
||||||
std::array<u16, 10> gAudioSfxSwapTarget_copy;
|
|
||||||
std::array<u8, 10> gAudioSfxSwapMode_copy;
|
|
||||||
void (*D_801755D0_copy)(void);
|
|
||||||
} SaveStateInfo;
|
|
||||||
|
|
||||||
extern unsigned int gCurrentSlot;
|
|
||||||
|
|
||||||
typedef struct SaveStateRequest {
|
typedef struct SaveStateRequest {
|
||||||
unsigned int slot;
|
unsigned int slot;
|
||||||
RequestType type;
|
RequestType type;
|
||||||
} SaveStateRequest;
|
} SaveStateRequest;
|
||||||
|
|
||||||
class SaveState {
|
class SaveStateMgr {
|
||||||
public:
|
friend class SaveState;
|
||||||
static constexpr unsigned int SAVE_SLOT_MAX = 2;
|
|
||||||
|
|
||||||
static std::queue <SaveStateRequest> requests;
|
|
||||||
|
|
||||||
SaveState();
|
|
||||||
~SaveState();
|
|
||||||
|
|
||||||
SaveState& operator=(const SaveState& rhs) = delete;
|
|
||||||
SaveState(const SaveState& rhs) = delete;
|
|
||||||
|
|
||||||
void Init(void);
|
|
||||||
|
|
||||||
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:
|
private:
|
||||||
static void Save(const unsigned int slot);
|
unsigned int currentSlot;
|
||||||
static void Load(const unsigned int slot);
|
std::unordered_map<unsigned int, std::shared_ptr<SaveState>> states;
|
||||||
static void SetHeader(SaveStateHeader& header);
|
std::queue <SaveStateRequest> requests;
|
||||||
static void GetHeader(SaveStateHeader& header);
|
std::mutex mutex;
|
||||||
static void BackupSeqScriptState(SaveStateInfo* state);
|
|
||||||
static void LoadSeqScriptState(SaveStateInfo* state);
|
|
||||||
|
|
||||||
SaveStateInfo saveStateInfo;
|
public:
|
||||||
|
|
||||||
|
SaveStateReturn AddRequest(const SaveStateRequest request);
|
||||||
|
SaveStateMgr();
|
||||||
|
~SaveStateMgr();
|
||||||
|
|
||||||
|
void SetCurrentSlot(unsigned int slot);
|
||||||
|
unsigned int GetCurrentSlot(void);
|
||||||
|
|
||||||
|
SaveStateMgr& operator=(const SaveStateMgr& rhs) = delete;
|
||||||
|
SaveStateMgr(const SaveStateMgr& rhs) = delete;
|
||||||
|
|
||||||
|
void ProcessSaveStateRequests(void);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
extern std::shared_ptr<SaveStateMgr> gSaveStateMgr;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -37,7 +37,9 @@
|
||||||
OTRGlobals* OTRGlobals::Instance;
|
OTRGlobals* OTRGlobals::Instance;
|
||||||
|
|
||||||
OTRGlobals::OTRGlobals() {
|
OTRGlobals::OTRGlobals() {
|
||||||
|
|
||||||
context = Ship::GlobalCtx2::CreateInstance("Ship of Harkinian");
|
context = Ship::GlobalCtx2::CreateInstance("Ship of Harkinian");
|
||||||
|
gSaveStateMgr = std::make_shared<SaveStateMgr>();
|
||||||
context->GetWindow()->Init();
|
context->GetWindow()->Init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,15 +6,17 @@
|
||||||
#include "GlobalCtx2.h"
|
#include "GlobalCtx2.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
#include "Enhancements/savestates.h"
|
||||||
class OTRGlobals
|
class OTRGlobals
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static OTRGlobals* Instance;
|
static OTRGlobals* Instance;
|
||||||
|
|
||||||
std::shared_ptr<Ship::GlobalCtx2> context;
|
std::shared_ptr<Ship::GlobalCtx2> context;
|
||||||
|
std::shared_ptr<SaveStateMgr> gSaveStateMgr;
|
||||||
|
|
||||||
OTRGlobals();
|
OTRGlobals();
|
||||||
~OTRGlobals();
|
~OTRGlobals();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,7 @@ static MapMarkDataOverlay sMapMarkDataOvl = {
|
||||||
gMapMarkDataTable,
|
gMapMarkDataTable,
|
||||||
};
|
};
|
||||||
|
|
||||||
static MapMarkData** sLoadedMarkDataTable;
|
MapMarkData** sLoadedMarkDataTable;
|
||||||
|
|
||||||
void MapMark_Init(GlobalContext* globalCtx) {
|
void MapMark_Init(GlobalContext* globalCtx) {
|
||||||
MapMarkDataOverlay* overlay = &sMapMarkDataOvl;
|
MapMarkDataOverlay* overlay = &sMapMarkDataOvl;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue