More work

This commit is contained in:
louist103 2022-04-26 18:56:40 -04:00
commit 1dc99609de
5 changed files with 311 additions and 36 deletions

View file

@ -307,15 +307,175 @@ static bool EntranceHandler(const std::vector<std::string>& args) {
}
static bool SaveStateHandler(const std::vector<std::string>& args) {
SaveState::Save(0);
return CMD_SUCCESS;
const SaveStateReturn rtn = SaveState::Save(gCurrentSlot);
switch (rtn) {
case SaveStateReturn::SUCCESS:
INFO("[SOH] Saved state to slot %u", gCurrentSlot);
return CMD_SUCCESS;
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<std::string>& args) {
SaveState::Load(0);
return CMD_SUCCESS;
const SaveStateReturn rtn = SaveState::Load(gCurrentSlot);
switch (rtn) {
case SaveStateReturn::SUCCESS:
INFO("[SOH] Loaded state from slot %u", gCurrentSlot);
return CMD_SUCCESS;
case SaveStateReturn::FAIL_INVALID_SLOT:
ERROR("[SOH] Invalid State Slot Number (%u)", gCurrentSlot);
return CMD_FAILED;
case SaveStateReturn::FAIL_STATE_EMPTY:
ERROR("[SOH] State Slot (%u) is empty", gCurrentSlot);
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) {
if (args.size() != 2) {
ERROR("[SOH] Unexpected arguments passed");
return CMD_FAILED;
}
int slot;
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;
}
gCurrentSlot = slot;
INFO("[SOH] Slot %u selected", gCurrentSlot);
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_FLOAT 1
@ -433,6 +593,19 @@ void DebugConsole_Init(void) {
CMD_REGISTER("save_state", { SaveStateHandler, "Save 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", {
{ "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();
}

View file

@ -2,20 +2,20 @@
#include "GameVersions.h"
#include <variables.h>
#include <cstdio> // std::sprintf
//#include "global.h"
//#include <soh/OTRGlobals.h>
std::array<SaveState*, 3> gSaveStates;
//TODO is there a better way?
unsigned int gCurrentSlot = 0;
static std::array<SaveState*, SaveState::SAVE_SLOT_MAX + 1> gSaveStates;
SaveState::SaveState() {
}
#if 0
SaveState::~SaveState() {
}
#endif
SaveState::SaveState(){}
SaveState::~SaveState() {}
void SaveState::Init(void) {
gSaveStates[0] = nullptr;
@ -23,17 +23,105 @@ void SaveState::Init(void) {
gSaveStates[2] = nullptr;
}
void SaveState::WriteHeader(SaveStateHeader& header) {
//OTRGlobals::Instance->context->GetResourceManager()->GetGameVersion();
// header.gameVersion = ResourceMgr_GetGameVersion();
void SaveState::SetHeader(SaveStateHeader& header) {
header.stateMagic = 0x07151129;
//TODO state version ENUM;
header.stateVersion = 0;
}
extern "C" MtxF* sMatrixStack; // "Matrix_stack"
extern "C" MtxF* sCurrentMatrix; // "Matrix_now"
extern "C" LightsBuffer sLightsBuffer;
SaveStateReturn SaveState::Delete(const unsigned int slot) {
if (slot > SAVE_SLOT_MAX) {
return SaveStateReturn::FAIL_INVALID_SLOT;
}
if (gSaveStates[slot] != nullptr) {
delete gSaveStates[slot];
gSaveStates[slot] = nullptr;
}
return SaveStateReturn::SUCCESS;
}
extern "C" SaveStateReturn SaveState::Save(unsigned int slot) {
if (slot > 2) {
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 SaveState;
if (gSaveStates[slot] == nullptr) {
fclose(inFile);
return SaveStateReturn::FAIL_NO_MEMORY;
}
}
std::fseek(inFile, 0, SEEK_SET);
std::fread(gSaveStates[slot], sizeof(SaveState), 1, inFile);
std::fclose(inFile);
//TODO version system
//if (gSaveStates[slot]->stateHeader.stateVersion != 0) {
// return SaveStateReturn::FAIL_INVALID_STATE;
//}
return SaveStateReturn::SUCCESS;
}
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) {
if (slot > SaveState::SAVE_SLOT_MAX) {
return SaveStateReturn::FAIL_INVALID_SLOT;
}
if (gSaveStates[slot] == nullptr) {
@ -43,8 +131,7 @@ extern "C" SaveStateReturn SaveState::Save(unsigned int slot) {
}
}
gSaveStates[slot]->stateHeader.gameVersion = 0;
gSaveStates[slot]->stateHeader.stateVersion = 0;
SaveState::SetHeader(gSaveStates[slot]->stateHeader);
memcpy(&gSaveStates[slot]->sysHeapCopy, &gSystemHeap, 1024 * 1024 * 4 /* sizeof(gSystemHeap) */);
memcpy(&gSaveStates[slot]->saveContextCopy, &gSaveContext, sizeof(gSaveContext));
@ -53,14 +140,15 @@ extern "C" SaveStateReturn SaveState::Save(unsigned int slot) {
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(unsigned int slot) {
if (slot > 2) {
SaveStateReturn SaveState::Load(const unsigned int slot) {
if (slot > SaveState::SAVE_SLOT_MAX) {
return SaveStateReturn::FAIL_INVALID_SLOT;
}
if (gSaveStates[slot] == nullptr) {
@ -73,10 +161,11 @@ SaveStateReturn SaveState::Load(unsigned int slot) {
memcpy(&gSystemHeap, &gSaveStates[slot]->sysHeapCopy, 1024 * 1024 * 4);
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(&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

View file

@ -23,27 +23,39 @@ enum class SaveStateReturn {
FAIL_INVALID_SLOT,
FAIL_NO_MEMORY,
FAIL_STATE_EMPTY,
FAIL_FILE_NOT_FOUND,
FAIL_FILE_NOT_OPENED,
FAIL_INVALID_MAGIC,
FAIL_INVALID_SIZE,
};
typedef struct SaveStateHeader {
uint32_t stateMagic;
uint32_t stateVersion;
uint32_t gameVersion;
//uint32_t gameVersion;
} SaveStateHeader;
extern unsigned int gCurrentSlot;
class SaveState {
public:
static constexpr unsigned int SAVE_SLOT_MAX = 2;
SaveState();
~SaveState() = delete;
~SaveState();
SaveState& operator=(const SaveState& rhs) = delete;
SaveState(const SaveState& rhs) = delete;
void Init(void);
static SaveStateReturn Save(unsigned int slot);
static SaveStateReturn Load(unsigned int slot);
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);
private:
static void WriteHeader(SaveStateHeader& header);
static void ReadHeader(SaveStateHeader& header);
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;
@ -53,6 +65,7 @@ class SaveState {
std::array<MtxF,20> mtxStackCopy; // always 20 matricies
MtxF currentMtxCopy;
uint32_t rngSeed;
int16_t blueWarpTimerCopy; /* From door_warp_1 */
};

View file

@ -421,7 +421,7 @@ void Gameplay_Update(GlobalContext* globalCtx) {
input = globalCtx->state.input;
if ((SREG(1) < 0) || (DREG(0) != 0)) {
if ((SREG(1) < 0) || (DREG(0) != 0)) {
SREG(1) = 0;
ZeldaArena_Display();
}

View file

@ -53,7 +53,7 @@ static InitChainEntry sInitChain[] = {
ICHAIN_F32(uncullZoneDownward, 4000, ICHAIN_STOP),
};
static s16 sWarpTimerTarget;
s16 sWarpTimerTarget;
void DoorWarp1_SetupAction(DoorWarp1* this, DoorWarp1ActionFunc actionFunc) {
this->actionFunc = actionFunc;