mirror of
https://github.com/HarbourMasters/Shipwright.git
synced 2025-08-22 14:23:44 -07:00
More work
This commit is contained in:
parent
105c507f0e
commit
1dc99609de
5 changed files with 311 additions and 36 deletions
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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,9 +131,8 @@ 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));
|
||||
memcpy(&gSaveStates[slot]->gameInfoCopy, gGameInfo, sizeof(*gGameInfo));
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
||||
};
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue