mirror of
https://github.com/HarbourMasters/2ship2harkinian.git
synced 2024-11-23 05:59:40 +00:00
Add support for json save files (#54)
This commit is contained in:
parent
f068674d77
commit
ae257f15a2
1
.gitignore
vendored
1
.gitignore
vendored
@ -4,6 +4,7 @@
|
||||
logs
|
||||
*.nix
|
||||
shipofharkinian.json
|
||||
*.sav
|
||||
.envrc
|
||||
imgui.ini
|
||||
|
||||
|
330
mm/2s2h/BenJsonConversions.hpp
Normal file
330
mm/2s2h/BenJsonConversions.hpp
Normal file
@ -0,0 +1,330 @@
|
||||
#ifndef BenJsonConversions_hpp
|
||||
#define BenJsonConversions_hpp
|
||||
|
||||
#include "z64.h"
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
void to_json(json& j, const ItemEquips& itemEquips) {
|
||||
j = json{
|
||||
{ "buttonItems", itemEquips.buttonItems },
|
||||
{ "cButtonSlots", itemEquips.cButtonSlots },
|
||||
{ "equipment", itemEquips.equipment },
|
||||
};
|
||||
}
|
||||
|
||||
void from_json(const json& j, ItemEquips& itemEquips) {
|
||||
j.at("equipment").get_to(itemEquips.equipment);
|
||||
// buttonItems and cButtonSlots are arrays of arrays, so we need to manually parse them
|
||||
for (int x = 0; x < 4; x++) {
|
||||
for (int y = 0; y < 4; y++) {
|
||||
itemEquips.buttonItems[x][y] = j.at("buttonItems")[x][y].get<u8>();
|
||||
itemEquips.cButtonSlots[x][y] = j.at("cButtonSlots")[x][y].get<u8>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void to_json(json& j, const Inventory& inventory) {
|
||||
j = json{
|
||||
{ "items", inventory.items },
|
||||
{ "ammo", inventory.ammo },
|
||||
{ "upgrades", inventory.upgrades },
|
||||
{ "questItems", inventory.questItems },
|
||||
{ "dungeonItems", inventory.dungeonItems },
|
||||
{ "dungeonKeys", inventory.dungeonKeys },
|
||||
{ "defenseHearts", inventory.defenseHearts },
|
||||
{ "strayFairies", inventory.strayFairies },
|
||||
{ "dekuPlaygroundPlayerName", inventory.dekuPlaygroundPlayerName },
|
||||
};
|
||||
}
|
||||
|
||||
void from_json(const json& j, Inventory& inventory) {
|
||||
j.at("items").get_to(inventory.items);
|
||||
j.at("ammo").get_to(inventory.ammo);
|
||||
j.at("upgrades").get_to(inventory.upgrades);
|
||||
j.at("questItems").get_to(inventory.questItems);
|
||||
j.at("dungeonItems").get_to(inventory.dungeonItems);
|
||||
j.at("dungeonKeys").get_to(inventory.dungeonKeys);
|
||||
j.at("defenseHearts").get_to(inventory.defenseHearts);
|
||||
j.at("strayFairies").get_to(inventory.strayFairies);
|
||||
// dekuPlaygroundPlayerName is an array of char arrays, so we need to manually parse it
|
||||
for (int i = 0; i < 3; i++) {
|
||||
std::string name = j.at("dekuPlaygroundPlayerName")[i].get<std::string>();
|
||||
for (int j = 0; j < 8; j++) {
|
||||
inventory.dekuPlaygroundPlayerName[i][j] = name[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void to_json(json& j, const PermanentSceneFlags& permanentSceneFlags) {
|
||||
j = json{
|
||||
{ "chest", permanentSceneFlags.chest },
|
||||
{ "switch0", permanentSceneFlags.switch0 },
|
||||
{ "switch1", permanentSceneFlags.switch1 },
|
||||
{ "clearedRoom", permanentSceneFlags.clearedRoom },
|
||||
{ "collectible", permanentSceneFlags.collectible },
|
||||
{ "unk_14", permanentSceneFlags.unk_14 },
|
||||
{ "rooms", permanentSceneFlags.rooms },
|
||||
};
|
||||
}
|
||||
|
||||
void from_json(const json& j, PermanentSceneFlags& permanentSceneFlags) {
|
||||
j.at("chest").get_to(permanentSceneFlags.chest);
|
||||
j.at("switch0").get_to(permanentSceneFlags.switch0);
|
||||
j.at("switch1").get_to(permanentSceneFlags.switch1);
|
||||
j.at("clearedRoom").get_to(permanentSceneFlags.clearedRoom);
|
||||
j.at("collectible").get_to(permanentSceneFlags.collectible);
|
||||
j.at("unk_14").get_to(permanentSceneFlags.unk_14);
|
||||
j.at("rooms").get_to(permanentSceneFlags.rooms);
|
||||
}
|
||||
|
||||
void to_json(json& j, const SavePlayerData& savePlayerData) {
|
||||
j = json{
|
||||
{ "newf", savePlayerData.newf },
|
||||
{ "threeDayResetCount", savePlayerData.threeDayResetCount },
|
||||
{ "playerName", savePlayerData.playerName },
|
||||
{ "healthCapacity", savePlayerData.healthCapacity },
|
||||
{ "health", savePlayerData.health },
|
||||
{ "magicLevel", savePlayerData.magicLevel },
|
||||
{ "magic", savePlayerData.magic },
|
||||
{ "rupees", savePlayerData.rupees },
|
||||
{ "swordHealth", savePlayerData.swordHealth },
|
||||
{ "tatlTimer", savePlayerData.tatlTimer },
|
||||
{ "isMagicAcquired", savePlayerData.isMagicAcquired },
|
||||
{ "isDoubleMagicAcquired", savePlayerData.isDoubleMagicAcquired },
|
||||
{ "doubleDefense", savePlayerData.doubleDefense },
|
||||
{ "unk_1F", savePlayerData.unk_1F },
|
||||
{ "unk_20", savePlayerData.unk_20 },
|
||||
{ "owlActivationFlags", savePlayerData.owlActivationFlags },
|
||||
{ "unk_24", savePlayerData.unk_24 },
|
||||
{ "savedSceneId", savePlayerData.savedSceneId },
|
||||
};
|
||||
}
|
||||
|
||||
void from_json(const json& j, SavePlayerData& savePlayerData) {
|
||||
// newf is an array of chars, so we need to manually parse it
|
||||
std::string newf = j.at("newf").get<std::string>();
|
||||
for (int i = 0; i < 6; i++) {
|
||||
savePlayerData.newf[i] = newf[i];
|
||||
}
|
||||
j.at("threeDayResetCount").get_to(savePlayerData.threeDayResetCount);
|
||||
std::string playerName = j.at("playerName").get<std::string>();
|
||||
for (int i = 0; i < 8; i++) {
|
||||
savePlayerData.playerName[i] = playerName[i];
|
||||
}
|
||||
j.at("healthCapacity").get_to(savePlayerData.healthCapacity);
|
||||
j.at("health").get_to(savePlayerData.health);
|
||||
j.at("magicLevel").get_to(savePlayerData.magicLevel);
|
||||
j.at("magic").get_to(savePlayerData.magic);
|
||||
j.at("rupees").get_to(savePlayerData.rupees);
|
||||
j.at("swordHealth").get_to(savePlayerData.swordHealth);
|
||||
j.at("tatlTimer").get_to(savePlayerData.tatlTimer);
|
||||
j.at("isMagicAcquired").get_to(savePlayerData.isMagicAcquired);
|
||||
j.at("isDoubleMagicAcquired").get_to(savePlayerData.isDoubleMagicAcquired);
|
||||
j.at("doubleDefense").get_to(savePlayerData.doubleDefense);
|
||||
j.at("unk_1F").get_to(savePlayerData.unk_1F);
|
||||
j.at("unk_20").get_to(savePlayerData.unk_20);
|
||||
j.at("owlActivationFlags").get_to(savePlayerData.owlActivationFlags);
|
||||
j.at("unk_24").get_to(savePlayerData.unk_24);
|
||||
j.at("savedSceneId").get_to(savePlayerData.savedSceneId);
|
||||
}
|
||||
|
||||
void to_json(json& j, const Vec3s& vec) {
|
||||
j = json{
|
||||
{ "x", vec.x },
|
||||
{ "y", vec.y },
|
||||
{ "z", vec.z },
|
||||
};
|
||||
}
|
||||
|
||||
void from_json(const json& j, Vec3s& vec) {
|
||||
j.at("x").get_to(vec.x);
|
||||
j.at("y").get_to(vec.y);
|
||||
j.at("z").get_to(vec.z);
|
||||
}
|
||||
|
||||
void to_json(json& j, const HorseData& horseData) {
|
||||
j = json{
|
||||
{ "sceneId", horseData.sceneId },
|
||||
{ "pos", horseData.pos },
|
||||
{ "yaw", horseData.yaw },
|
||||
};
|
||||
}
|
||||
|
||||
void from_json(const json& j, HorseData& horseData) {
|
||||
j.at("sceneId").get_to(horseData.sceneId);
|
||||
j.at("pos").get_to(horseData.pos);
|
||||
j.at("yaw").get_to(horseData.yaw);
|
||||
}
|
||||
|
||||
void to_json(json& j, const SaveInfo& saveInfo) {
|
||||
j = json{
|
||||
{ "playerData", saveInfo.playerData },
|
||||
{ "equips", saveInfo.equips },
|
||||
{ "inventory", saveInfo.inventory },
|
||||
{ "permanentSceneFlags", saveInfo.permanentSceneFlags },
|
||||
{ "unk_DF4", saveInfo.unk_DF4 },
|
||||
{ "dekuPlaygroundHighScores", saveInfo.dekuPlaygroundHighScores },
|
||||
{ "pictoFlags0", saveInfo.pictoFlags0 },
|
||||
{ "pictoFlags1", saveInfo.pictoFlags1 },
|
||||
{ "unk_E5C", saveInfo.unk_E5C },
|
||||
{ "unk_E60", saveInfo.unk_E60 },
|
||||
{ "unk_E64", saveInfo.unk_E64 },
|
||||
{ "scenesVisible", saveInfo.scenesVisible },
|
||||
{ "skullTokenCount", saveInfo.skullTokenCount },
|
||||
{ "unk_EA0", saveInfo.unk_EA0 },
|
||||
{ "unk_EA4", saveInfo.unk_EA4 },
|
||||
{ "unk_EA8", saveInfo.unk_EA8 },
|
||||
{ "stolenItems", saveInfo.stolenItems },
|
||||
{ "unk_EB4", saveInfo.unk_EB4 },
|
||||
{ "highScores", saveInfo.highScores },
|
||||
{ "weekEventReg", saveInfo.weekEventReg },
|
||||
{ "regionsVisited", saveInfo.regionsVisited },
|
||||
{ "worldMapCloudVisibility", saveInfo.worldMapCloudVisibility },
|
||||
{ "unk_F40", saveInfo.unk_F40 },
|
||||
{ "scarecrowSpawnSongSet", saveInfo.scarecrowSpawnSongSet },
|
||||
{ "scarecrowSpawnSong", saveInfo.scarecrowSpawnSong },
|
||||
{ "bombersCaughtNum", saveInfo.bombersCaughtNum },
|
||||
{ "bombersCaughtOrder", saveInfo.bombersCaughtOrder },
|
||||
{ "lotteryCodes", saveInfo.lotteryCodes },
|
||||
{ "spiderHouseMaskOrder", saveInfo.spiderHouseMaskOrder },
|
||||
{ "bomberCode", saveInfo.bomberCode },
|
||||
{ "horseData", saveInfo.horseData },
|
||||
{ "checksum", saveInfo.checksum },
|
||||
};
|
||||
}
|
||||
|
||||
void from_json(const json& j, SaveInfo& saveInfo) {
|
||||
j.at("playerData").get_to(saveInfo.playerData);
|
||||
j.at("equips").get_to(saveInfo.equips);
|
||||
j.at("inventory").get_to(saveInfo.inventory);
|
||||
j.at("permanentSceneFlags").get_to(saveInfo.permanentSceneFlags);
|
||||
j.at("unk_DF4").get_to(saveInfo.unk_DF4);
|
||||
j.at("dekuPlaygroundHighScores").get_to(saveInfo.dekuPlaygroundHighScores);
|
||||
j.at("pictoFlags0").get_to(saveInfo.pictoFlags0);
|
||||
j.at("pictoFlags1").get_to(saveInfo.pictoFlags1);
|
||||
j.at("unk_E5C").get_to(saveInfo.unk_E5C);
|
||||
j.at("unk_E60").get_to(saveInfo.unk_E60);
|
||||
j.at("unk_E64").get_to(saveInfo.unk_E64);
|
||||
j.at("scenesVisible").get_to(saveInfo.scenesVisible);
|
||||
j.at("skullTokenCount").get_to(saveInfo.skullTokenCount);
|
||||
j.at("unk_EA0").get_to(saveInfo.unk_EA0);
|
||||
j.at("unk_EA4").get_to(saveInfo.unk_EA4);
|
||||
j.at("unk_EA8").get_to(saveInfo.unk_EA8);
|
||||
j.at("stolenItems").get_to(saveInfo.stolenItems);
|
||||
j.at("unk_EB4").get_to(saveInfo.unk_EB4);
|
||||
j.at("highScores").get_to(saveInfo.highScores);
|
||||
j.at("weekEventReg").get_to(saveInfo.weekEventReg);
|
||||
j.at("regionsVisited").get_to(saveInfo.regionsVisited);
|
||||
j.at("worldMapCloudVisibility").get_to(saveInfo.worldMapCloudVisibility);
|
||||
j.at("unk_F40").get_to(saveInfo.unk_F40);
|
||||
j.at("scarecrowSpawnSongSet").get_to(saveInfo.scarecrowSpawnSongSet);
|
||||
j.at("scarecrowSpawnSong").get_to(saveInfo.scarecrowSpawnSong);
|
||||
j.at("bombersCaughtNum").get_to(saveInfo.bombersCaughtNum);
|
||||
j.at("bombersCaughtOrder").get_to(saveInfo.bombersCaughtOrder);
|
||||
// lotteryCodes is an array of arrays, so we need to manually parse it
|
||||
for (int x = 0; x < 3; x++) {
|
||||
for (int y = 0; y < 3; y++) {
|
||||
saveInfo.lotteryCodes[x][y] = j.at("lotteryCodes")[x][y].get<s8>();
|
||||
}
|
||||
}
|
||||
j.at("spiderHouseMaskOrder").get_to(saveInfo.spiderHouseMaskOrder);
|
||||
j.at("bomberCode").get_to(saveInfo.bomberCode);
|
||||
j.at("horseData").get_to(saveInfo.horseData);
|
||||
j.at("checksum").get_to(saveInfo.checksum);
|
||||
}
|
||||
|
||||
void to_json(json& j, const Save& save) {
|
||||
j = json{
|
||||
{ "entrance", save.entrance },
|
||||
{ "equippedMask", save.equippedMask },
|
||||
{ "isFirstCycle", save.isFirstCycle },
|
||||
{ "unk_06", save.unk_06 },
|
||||
{ "linkAge", save.linkAge },
|
||||
{ "cutsceneIndex", save.cutsceneIndex },
|
||||
{ "time", save.time },
|
||||
{ "owlSaveLocation", save.owlSaveLocation },
|
||||
{ "isNight", save.isNight },
|
||||
{ "timeSpeedOffset", save.timeSpeedOffset },
|
||||
{ "day", save.day },
|
||||
{ "eventDayCount", save.eventDayCount },
|
||||
{ "playerForm", save.playerForm },
|
||||
{ "snowheadCleared", save.snowheadCleared },
|
||||
{ "hasTatl", save.hasTatl },
|
||||
{ "isOwlSave", save.isOwlSave },
|
||||
{ "saveInfo", save.saveInfo },
|
||||
};
|
||||
}
|
||||
|
||||
void from_json(const json& j, Save& save) {
|
||||
j.at("entrance").get_to(save.entrance);
|
||||
j.at("equippedMask").get_to(save.equippedMask);
|
||||
j.at("isFirstCycle").get_to(save.isFirstCycle);
|
||||
j.at("unk_06").get_to(save.unk_06);
|
||||
j.at("linkAge").get_to(save.linkAge);
|
||||
j.at("cutsceneIndex").get_to(save.cutsceneIndex);
|
||||
j.at("time").get_to(save.time);
|
||||
j.at("owlSaveLocation").get_to(save.owlSaveLocation);
|
||||
j.at("isNight").get_to(save.isNight);
|
||||
j.at("timeSpeedOffset").get_to(save.timeSpeedOffset);
|
||||
j.at("day").get_to(save.day);
|
||||
j.at("eventDayCount").get_to(save.eventDayCount);
|
||||
j.at("playerForm").get_to(save.playerForm);
|
||||
j.at("snowheadCleared").get_to(save.snowheadCleared);
|
||||
j.at("hasTatl").get_to(save.hasTatl);
|
||||
j.at("isOwlSave").get_to(save.isOwlSave);
|
||||
j.at("saveInfo").get_to(save.saveInfo);
|
||||
}
|
||||
|
||||
void to_json(json& j, const SaveContext& saveContext) {
|
||||
j = json{
|
||||
{ "save", saveContext.save },
|
||||
{ "eventInf", saveContext.eventInf },
|
||||
{ "unk_1014", saveContext.unk_1014 },
|
||||
{ "bButtonStatus", saveContext.bButtonStatus },
|
||||
{ "jinxTimer", saveContext.jinxTimer },
|
||||
{ "rupeeAccumulator", saveContext.rupeeAccumulator },
|
||||
{ "bottleTimerStates", saveContext.bottleTimerStates },
|
||||
{ "bottleTimerStartOsTimes", saveContext.bottleTimerStartOsTimes },
|
||||
{ "bottleTimerTimeLimits", saveContext.bottleTimerTimeLimits },
|
||||
{ "bottleTimerCurTimes", saveContext.bottleTimerCurTimes },
|
||||
{ "bottleTimerPausedOsTimes", saveContext.bottleTimerPausedOsTimes },
|
||||
{ "pictoPhotoI5", saveContext.pictoPhotoI5 },
|
||||
};
|
||||
}
|
||||
|
||||
void from_json(const json& j, SaveContext& saveContext) {
|
||||
j.at("save").get_to(saveContext.save);
|
||||
j.at("eventInf").get_to(saveContext.eventInf);
|
||||
j.at("unk_1014").get_to(saveContext.unk_1014);
|
||||
j.at("bButtonStatus").get_to(saveContext.bButtonStatus);
|
||||
j.at("jinxTimer").get_to(saveContext.jinxTimer);
|
||||
j.at("rupeeAccumulator").get_to(saveContext.rupeeAccumulator);
|
||||
j.at("bottleTimerStates").get_to(saveContext.bottleTimerStates);
|
||||
j.at("bottleTimerStartOsTimes").get_to(saveContext.bottleTimerStartOsTimes);
|
||||
j.at("bottleTimerTimeLimits").get_to(saveContext.bottleTimerTimeLimits);
|
||||
j.at("bottleTimerCurTimes").get_to(saveContext.bottleTimerCurTimes);
|
||||
j.at("bottleTimerPausedOsTimes").get_to(saveContext.bottleTimerPausedOsTimes);
|
||||
j.at("pictoPhotoI5").get_to(saveContext.pictoPhotoI5);
|
||||
}
|
||||
|
||||
void to_json(json& j, const SaveOptions& saveOptions) {
|
||||
j = json{
|
||||
{ "optionId", saveOptions.optionId },
|
||||
{ "language", saveOptions.language },
|
||||
{ "audioSetting", saveOptions.audioSetting },
|
||||
{ "languageSetting", saveOptions.languageSetting },
|
||||
{ "zTargetSetting", saveOptions.zTargetSetting },
|
||||
};
|
||||
}
|
||||
|
||||
void from_json(const json& j, SaveOptions& saveOptions) {
|
||||
j.at("optionId").get_to(saveOptions.optionId);
|
||||
j.at("language").get_to(saveOptions.language);
|
||||
j.at("audioSetting").get_to(saveOptions.audioSetting);
|
||||
j.at("languageSetting").get_to(saveOptions.languageSetting);
|
||||
j.at("zTargetSetting").get_to(saveOptions.zTargetSetting);
|
||||
}
|
||||
|
||||
#endif // BenJsonConversions_hpp
|
@ -30,6 +30,7 @@
|
||||
#include "z64.h"
|
||||
#include "macros.h"
|
||||
#include <Utils/StringHelper.h>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#include <Fast3D/gfx_pc.h>
|
||||
#include <Fast3D/gfx_rendering_api.h>
|
||||
@ -51,6 +52,7 @@ CrowdControl* CrowdControl::Instance;
|
||||
|
||||
#include <libultraship/libultraship.h>
|
||||
#include <BenGui.hpp>
|
||||
#include "BenJsonConversions.hpp"
|
||||
|
||||
#include "Enhancements/controls/SohInputEditorWindow.h"
|
||||
|
||||
@ -1384,3 +1386,193 @@ extern "C" int Controller_ShouldRumble(size_t slot) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// This entire thing is temporary until we have a more robust save system that
|
||||
// supports backwards compatability, migrations, threaded saving, save sections, etc.
|
||||
typedef enum FlashSlotFile {
|
||||
/* -1 */ FLASH_SLOT_FILE_UNAVAILABLE = -1,
|
||||
/* 0 */ FLASH_SLOT_FILE_1_NEW_CYCLE,
|
||||
/* 1 */ FLASH_SLOT_FILE_1_NEW_CYCLE_BACKUP,
|
||||
/* 2 */ FLASH_SLOT_FILE_2_NEW_CYCLE,
|
||||
/* 3 */ FLASH_SLOT_FILE_2_NEW_CYCLE_BACKUP,
|
||||
/* 4 */ FLASH_SLOT_FILE_1_OWL_SAVE,
|
||||
/* 5 */ FLASH_SLOT_FILE_1_OWL_SAVE_BACKUP,
|
||||
/* 6 */ FLASH_SLOT_FILE_2_OWL_SAVE,
|
||||
/* 7 */ FLASH_SLOT_FILE_2_OWL_SAVE_BACKUP,
|
||||
/* 8 */ FLASH_SLOT_FILE_SRAM_HEADER,
|
||||
/* 9 */ FLASH_SLOT_FILE_SRAM_HEADER_BACKUP,
|
||||
} FlashSlotFile;
|
||||
|
||||
#define GET_NEWF(save, index) (save.saveInfo.playerData.newf[index])
|
||||
#define IS_VALID_FILE(save) \
|
||||
((GET_NEWF(save, 0) == 'Z') && (GET_NEWF(save, 1) == 'E') && \
|
||||
(GET_NEWF(save, 2) == 'L') && (GET_NEWF(save, 3) == 'D') && \
|
||||
(GET_NEWF(save, 4) == 'A') && (GET_NEWF(save, 5) == '3'))
|
||||
|
||||
const std::filesystem::path savesFolderPath(LUS::Context::GetPathRelativeToAppDirectory("Save"));
|
||||
|
||||
void WriteSaveFile(std::filesystem::path fileName, nlohmann::json j) {
|
||||
const std::filesystem::path filePath = savesFolderPath / fileName;
|
||||
|
||||
if (!std::filesystem::exists(savesFolderPath)) {
|
||||
std::filesystem::create_directory(savesFolderPath);
|
||||
}
|
||||
|
||||
std::ofstream o(filePath);
|
||||
o << std::setw(4) << j << std::endl;
|
||||
o.close();
|
||||
}
|
||||
|
||||
void DeleteSaveFile(std::filesystem::path fileName) {
|
||||
const std::filesystem::path filePath = savesFolderPath / fileName;
|
||||
|
||||
if (std::filesystem::exists(filePath)) {
|
||||
std::filesystem::remove(filePath);
|
||||
}
|
||||
}
|
||||
|
||||
int ReadSaveFile(std::filesystem::path fileName, nlohmann::json& j) {
|
||||
const std::filesystem::path filePath = savesFolderPath / fileName;
|
||||
|
||||
if (!std::filesystem::exists(filePath)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::ifstream i(filePath);
|
||||
i >> j;
|
||||
i.close();
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" void BenSysFlashrom_WriteData(u8* saveBuffer, u32 pageNum, u32 pageCount) {
|
||||
FlashSlotFile flashSlotFile = FLASH_SLOT_FILE_UNAVAILABLE;
|
||||
bool isBackup = false;
|
||||
for (u32 i = 0; i < ARRAY_COUNT(gFlashSaveStartPages) - 1; i++) {
|
||||
if (pageNum == gFlashSaveStartPages[i]) {
|
||||
flashSlotFile = static_cast<FlashSlotFile>(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (flashSlotFile == FLASH_SLOT_FILE_UNAVAILABLE) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (flashSlotFile) {
|
||||
case FLASH_SLOT_FILE_1_NEW_CYCLE_BACKUP:
|
||||
case FLASH_SLOT_FILE_2_NEW_CYCLE_BACKUP:
|
||||
isBackup = true;
|
||||
// fallthrough
|
||||
case FLASH_SLOT_FILE_1_NEW_CYCLE:
|
||||
case FLASH_SLOT_FILE_2_NEW_CYCLE: {
|
||||
Save save;
|
||||
memcpy(&save, saveBuffer, sizeof(Save));
|
||||
|
||||
std::string fileName = "save_" + std::to_string(flashSlotFile) + ".sav";
|
||||
if (isBackup) fileName += ".bak";
|
||||
|
||||
if (IS_VALID_FILE(save)) {
|
||||
WriteSaveFile(fileName, save);
|
||||
} else {
|
||||
DeleteSaveFile(fileName);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FLASH_SLOT_FILE_1_OWL_SAVE_BACKUP:
|
||||
case FLASH_SLOT_FILE_2_OWL_SAVE_BACKUP:
|
||||
isBackup = true;
|
||||
// fallthrough
|
||||
case FLASH_SLOT_FILE_1_OWL_SAVE:
|
||||
case FLASH_SLOT_FILE_2_OWL_SAVE: {
|
||||
SaveContext saveContext;
|
||||
memcpy(&saveContext, saveBuffer, sizeof(SaveContext));
|
||||
|
||||
std::string fileName = "save_" + std::to_string(flashSlotFile) + ".sav";
|
||||
if (isBackup) fileName += ".bak";
|
||||
|
||||
if (IS_VALID_FILE(saveContext.save)) {
|
||||
WriteSaveFile(fileName, saveContext);
|
||||
} else {
|
||||
DeleteSaveFile(fileName);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FLASH_SLOT_FILE_SRAM_HEADER_BACKUP:
|
||||
case FLASH_SLOT_FILE_SRAM_HEADER: {
|
||||
SaveOptions saveOptions;
|
||||
memcpy(&saveOptions, saveBuffer, sizeof(SaveOptions));
|
||||
|
||||
std::string fileName = "global.sav";
|
||||
WriteSaveFile(fileName, saveOptions);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" s32 BenSysFlashrom_ReadData(void* saveBuffer, u32 pageNum, u32 pageCount) {
|
||||
FlashSlotFile flashSlotFile = FLASH_SLOT_FILE_UNAVAILABLE;
|
||||
bool isBackup = false;
|
||||
for (u32 i = 0; i < ARRAY_COUNT(gFlashSaveStartPages) - 1; i++) {
|
||||
if (pageNum == gFlashSaveStartPages[i]) {
|
||||
flashSlotFile = static_cast<FlashSlotFile>(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (flashSlotFile == FLASH_SLOT_FILE_UNAVAILABLE) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
switch (flashSlotFile) {
|
||||
case FLASH_SLOT_FILE_1_NEW_CYCLE_BACKUP:
|
||||
case FLASH_SLOT_FILE_2_NEW_CYCLE_BACKUP:
|
||||
isBackup = true;
|
||||
// fallthrough
|
||||
case FLASH_SLOT_FILE_1_NEW_CYCLE:
|
||||
case FLASH_SLOT_FILE_2_NEW_CYCLE: {
|
||||
std::string fileName = "save_" + std::to_string(flashSlotFile) + ".sav";
|
||||
if (isBackup) fileName += ".bak";
|
||||
|
||||
nlohmann::json j;
|
||||
int result = ReadSaveFile(fileName, j);
|
||||
if (result != 0) return result;
|
||||
|
||||
Save save = j;
|
||||
|
||||
memcpy(saveBuffer, &save, sizeof(Save));
|
||||
return result;
|
||||
}
|
||||
case FLASH_SLOT_FILE_1_OWL_SAVE_BACKUP:
|
||||
case FLASH_SLOT_FILE_2_OWL_SAVE_BACKUP:
|
||||
isBackup = true;
|
||||
// fallthrough
|
||||
case FLASH_SLOT_FILE_1_OWL_SAVE:
|
||||
case FLASH_SLOT_FILE_2_OWL_SAVE: {
|
||||
std::string fileName = "save_" + std::to_string(flashSlotFile) + ".sav";
|
||||
if (isBackup) fileName += ".bak";
|
||||
|
||||
nlohmann::json j;
|
||||
int result = ReadSaveFile(fileName, j);
|
||||
if (result != 0) return result;
|
||||
|
||||
SaveContext saveContext = j;
|
||||
|
||||
memcpy(saveBuffer, &saveContext, sizeof(SaveContext));
|
||||
return result;
|
||||
}
|
||||
case FLASH_SLOT_FILE_SRAM_HEADER:
|
||||
case FLASH_SLOT_FILE_SRAM_HEADER_BACKUP: {
|
||||
std::string fileName = "global.sav";
|
||||
|
||||
nlohmann::json j;
|
||||
int result = ReadSaveFile(fileName, j);
|
||||
if (result != 0) return result;
|
||||
|
||||
SaveOptions saveOptions = j;
|
||||
|
||||
memcpy(saveBuffer, &saveOptions, sizeof(SaveOptions));
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -125,6 +125,8 @@ void Overlay_DisplayText_Seconds(int seconds, const char* text);
|
||||
|
||||
void Gfx_RegisterBlendedTexture(const char* name, u8* mask, u8* replacement);
|
||||
void CheckTracker_OnMessageClose();
|
||||
void BenSysFlashrom_WriteData(u8* addr, u32 pageNum, u32 pageCount);
|
||||
s32 BenSysFlashrom_ReadData(void* addr, u32 pageNum, u32 pageCount);
|
||||
|
||||
int32_t GetGIID(uint32_t itemID);
|
||||
#endif
|
||||
|
@ -124,7 +124,7 @@ source_group("include" FILES ${Header_Files__include})
|
||||
# }}}
|
||||
|
||||
# m (root)
|
||||
file(GLOB soh__ RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "2s2h/*.c" "2s2h/*.cpp" "2s2h/*.h")
|
||||
file(GLOB soh__ RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "2s2h/*.c" "2s2h/*.cpp" "2s2h/*.h" "2s2h/*.hpp")
|
||||
source_group("2s2h" FILES ${soh__})
|
||||
|
||||
file(GLOB_RECURSE libultra_headers RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
|
@ -1685,7 +1685,7 @@ void Sram_UpdateWriteToFlashOwlSave(SramContext* sramCtx);
|
||||
|
||||
extern u32 gSramSlotOffsets[];
|
||||
extern u8 gAmmoItems[];
|
||||
extern s32 gFlashSaveStartPages[];
|
||||
extern s32 gFlashSaveStartPages[10];
|
||||
extern s32 gFlashSaveNumPages[];
|
||||
extern s32 gFlashSpecialSaveNumPages[];
|
||||
extern s32 gFlashOwlSaveStartPages[];
|
||||
|
@ -386,6 +386,9 @@ void* osViGetCurrentFramebuffer(void) {
|
||||
OSPiHandle* osFlashInit(void) {
|
||||
}
|
||||
void osFlashReadId(u32* t, u32* v) {
|
||||
// We're faking these so the flashrom system will continue to work
|
||||
*t = 0x11118001; // FLASH_TYPE_MAGIC
|
||||
*v = 0x00C20000; // FLASH_VERSION_MX_PROTO_A
|
||||
}
|
||||
s32 osFlashSectorErase(u32 page) {
|
||||
}
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "z64thread.h"
|
||||
#include "sys_flashrom.h"
|
||||
#include "PR/os_internal_flash.h"
|
||||
#include "BenPort.h"
|
||||
|
||||
OSMesgQueue sFlashromMesgQueue;
|
||||
OSMesg sFlashromMesg[1];
|
||||
@ -78,6 +79,10 @@ s32 SysFlashrom_InitFlash(void) {
|
||||
}
|
||||
|
||||
s32 SysFlashrom_ReadData(void* addr, u32 pageNum, u32 pageCount) {
|
||||
// #region 2S2H [Port] Redirect to our own read function
|
||||
return BenSysFlashrom_ReadData(addr, pageNum, pageCount);
|
||||
// #endregion
|
||||
|
||||
OSIoMesg msg;
|
||||
|
||||
if (!SysFlashrom_IsInit()) {
|
||||
@ -201,25 +206,27 @@ s32 SysFlashrom_WriteData(void* addr, u32 pageNum, u32 pageCount) {
|
||||
}
|
||||
|
||||
void SysFlashrom_ThreadEntry(void* arg) {
|
||||
#if 0
|
||||
FlashromRequest* req = (FlashromRequest*)arg;
|
||||
|
||||
switch (req->requestType) {
|
||||
case FLASHROM_REQUEST_WRITE:
|
||||
req->response = SysFlashrom_WriteData(req->addr, req->pageNum, req->pageCount);
|
||||
osSendMesg(&req->messageQueue, (OSMesg)req->response, OS_MESG_BLOCK);
|
||||
osSendMesg(&req->messageQueue, OS_MESG_32(req->response), OS_MESG_BLOCK);
|
||||
break;
|
||||
|
||||
case FLASHROM_REQUEST_READ:
|
||||
req->response = SysFlashrom_ReadData(req->addr, req->pageNum, req->pageCount);
|
||||
osSendMesg(&req->messageQueue, (OSMesg)req->response, OS_MESG_BLOCK);
|
||||
osSendMesg(&req->messageQueue, OS_MESG_32(req->response), OS_MESG_BLOCK);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void SysFlashrom_WriteDataAsync(u8* addr, u32 pageNum, u32 pageCount) {
|
||||
#if 0
|
||||
// #region 2S2H [Port] Redirect to our own write function
|
||||
BenSysFlashrom_WriteData(addr, pageNum, pageCount);
|
||||
return;
|
||||
// #endregion
|
||||
|
||||
FlashromRequest* req = &sFlashromRequest;
|
||||
if (SysFlashrom_IsInit()) {
|
||||
req->requestType = FLASHROM_REQUEST_WRITE;
|
||||
@ -233,28 +240,34 @@ void SysFlashrom_WriteDataAsync(u8* addr, u32 pageNum, u32 pageCount) {
|
||||
STACK_TOP(sSysFlashromStack), Z_PRIORITY_FLASHROM);
|
||||
osStartThread(&sSysFlashromThread);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
s32 SysFlashrom_IsBusy(void) {
|
||||
return 0;
|
||||
//OSMesgQueue* queue = &sFlashromRequest.messageQueue;
|
||||
//
|
||||
//if (!SysFlashrom_IsInit()) {
|
||||
// return -1;
|
||||
//}
|
||||
//return MQ_IS_FULL(queue);
|
||||
// #region 2S2H [Port] This is only checked in 3 places in which we always want to tell it we've "started working"
|
||||
// Eventually we should probably have this call into BenPort and check if a save is in progress
|
||||
return 1;
|
||||
// #endregion
|
||||
|
||||
OSMesgQueue* queue = &sFlashromRequest.messageQueue;
|
||||
|
||||
if (!SysFlashrom_IsInit()) {
|
||||
return -1;
|
||||
}
|
||||
return MQ_IS_FULL(queue);
|
||||
}
|
||||
|
||||
s32 SysFlashrom_AwaitResult(void) {
|
||||
// #region 2S2H [Port] Currently all of our save writes/reads are synchronous, so we don't need to wait for anything
|
||||
return 0;
|
||||
//if (!SysFlashrom_IsInit()) {
|
||||
// return -1;
|
||||
//}
|
||||
//osRecvMesg(&sFlashromRequest.messageQueue, NULL, OS_MESG_BLOCK);
|
||||
//osDestroyThread(&sSysFlashromThread);
|
||||
//StackCheck_Cleanup(&sSysFlashromStackInfo);
|
||||
//return sFlashromRequest.response;
|
||||
// #endregion
|
||||
|
||||
if (!SysFlashrom_IsInit()) {
|
||||
return -1;
|
||||
}
|
||||
osRecvMesg(&sFlashromRequest.messageQueue, NULL, OS_MESG_BLOCK);
|
||||
osDestroyThread(&sSysFlashromThread);
|
||||
StackCheck_Cleanup(&sSysFlashromStackInfo);
|
||||
return sFlashromRequest.response;
|
||||
}
|
||||
|
||||
void SysFlashrom_WriteDataSync(void* addr, u32 pageNum, u32 pageCount) {
|
||||
|
@ -49,8 +49,7 @@ void Setup_SetRegs(void) {
|
||||
|
||||
void Setup_InitImpl(SetupState* this) {
|
||||
SysFlashrom_InitFlash();
|
||||
// BENTODO: this doesn't crash but was stubbed in minibuild? probably just for debug purposes
|
||||
// SaveContext_Init();
|
||||
SaveContext_Init();
|
||||
Setup_SetRegs();
|
||||
|
||||
STOP_GAMESTATE(&this->state);
|
||||
|
@ -300,7 +300,7 @@ u8 gAmmoItems[ITEM_NUM_SLOTS] = {
|
||||
};
|
||||
|
||||
// Stores flash start page number
|
||||
s32 gFlashSaveStartPages[] = {
|
||||
s32 gFlashSaveStartPages[10] = {
|
||||
0, // File 1 New Cycle Save
|
||||
0x40, // File 1 New Cycle Save Backup
|
||||
0x80, // File 2 New Cycle Save
|
||||
@ -667,6 +667,10 @@ void Sram_IncrementDay(void) {
|
||||
}
|
||||
|
||||
u16 Sram_CalcChecksum(void* data, size_t count) {
|
||||
// #region 2S2H [Port] I'm not really sure what this is doing or how to port it, for now always return the same
|
||||
return 1;
|
||||
// #endregion
|
||||
|
||||
u8* dataPtr = data;
|
||||
u16 chkSum = 0;
|
||||
|
||||
|
@ -145,9 +145,6 @@ void ConsoleLogo_Main(GameState* thisx) {
|
||||
// #region 2S2H [Debug] Eventually we'll get rid of this
|
||||
if (CVarGetInteger("gDebugEnabled", 0)) {
|
||||
gSaveContext.gameMode = GAMEMODE_NORMAL;
|
||||
gSaveContext.nextDayTime = NEXT_TIME_NONE;
|
||||
gSaveContext.nextTransitionType = TRANS_NEXT_TYPE_DEFAULT;
|
||||
gSaveContext.prevHudVisibility = HUD_VISIBILITY_ALL;
|
||||
SET_NEXT_GAMESTATE(&this->state, MapSelect_Init, sizeof(MapSelectState));
|
||||
// #endregion
|
||||
} else {
|
||||
|
Loading…
Reference in New Issue
Block a user