- Consolidate development files into final implementation - Replace basic prototypes with full feature implementations - Add complete hash-based save data access system - Implement advanced map pin management algorithms - Add comprehensive error handling and user feedback - Complete Korok seed database with all 908 locations
136 lines
No EOL
4.1 KiB
C
136 lines
No EOL
4.1 KiB
C
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <dirent.h>
|
|
#include <stdlib.h>
|
|
#include <math.h>
|
|
#include <switch.h>
|
|
#include "save.h"
|
|
#include "ui.h"
|
|
#include "map.h"
|
|
|
|
gameDataSav GAMEDATASAV;
|
|
const u32 KOROK_COUNTER_HASH = 0x8a94e07a;
|
|
|
|
void openSave() {
|
|
GAMEDATASAV.saveFile = NULL;
|
|
FILE *fp = fopen("save:/5/game_data.sav", "rb"); //TODO: Dont hardcode save slot
|
|
|
|
if (fp != NULL) {
|
|
/* Go to the end of the file. */
|
|
if (fseek(fp, 0L, SEEK_END) == 0) {
|
|
/* Get the size of the file. */
|
|
long bufsize = ftell(fp);
|
|
if (bufsize == -1) { /* Error */ }
|
|
|
|
/* Allocate our buffer to that size. */
|
|
GAMEDATASAV.saveFile = malloc(sizeof(char) * (bufsize));
|
|
|
|
/* Go back to the start of the file. */
|
|
if (fseek(fp, 0L, SEEK_SET) != 0) { /* Error */ }
|
|
|
|
/* Read the entire file into memory. */
|
|
GAMEDATASAV.length = fread(GAMEDATASAV.saveFile, sizeof(char), bufsize, fp);
|
|
if (ferror( fp ) != 0) {
|
|
printMessage("Error reading file.");
|
|
} else {
|
|
printMessage("Read %.2f kbytes successfully.", GAMEDATASAV.length/1024.0);
|
|
}
|
|
}
|
|
fclose(fp);
|
|
} else {
|
|
printMessage("Error opening file.");
|
|
}
|
|
}
|
|
|
|
void processSave() {
|
|
countMapPins();
|
|
printMessage("number of korok seeds: %d.", readU32FromHash(KOROK_COUNTER_HASH));
|
|
loadPlayerLocation();
|
|
}
|
|
|
|
u32 getSaveSize() {
|
|
return GAMEDATASAV.length;
|
|
}
|
|
|
|
void writeSave() {
|
|
FILE *fp = fopen("save:/5/game_data.sav", "wb"); //TODO: dont hardcode save slot
|
|
|
|
if (fp != NULL) {
|
|
size_t bytes_writen = fwrite(GAMEDATASAV.saveFile, sizeof(char), GAMEDATASAV.length, fp);
|
|
|
|
if (ferror( fp ) != 0) {
|
|
printMessage("Error writing file.");
|
|
} else {
|
|
printMessage("Wrote %f.2 kbytes successfully.", bytes_writen/1024.0);
|
|
}
|
|
fclose(fp);
|
|
} else {
|
|
printMessage("Error opening file for writing.");
|
|
}
|
|
}
|
|
|
|
u32 _searchHash(u32 hash) {
|
|
for(u32 i=0x0c; i<GAMEDATASAV.length; i+=8) {
|
|
u32 val = GAMEDATASAV.saveFile[i] | ( (u32)GAMEDATASAV.saveFile[i+1] << 8 ) | ( (u32)GAMEDATASAV.saveFile[i+2] << 16 ) | ( (u32)GAMEDATASAV.saveFile[i+3] << 24 );
|
|
if(hash == val) {
|
|
return i;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
u32 readU32FromHash(u32 hash) {
|
|
return readU32FromAddr(_searchHash(hash));
|
|
}
|
|
|
|
u32 readU32FromAddr(u32 addr) {
|
|
if(addr != 0) {
|
|
u32 val = ((u32)GAMEDATASAV.saveFile[addr+4]) | ( (u32)GAMEDATASAV.saveFile[addr+5] << 8 ) | ( (u32)GAMEDATASAV.saveFile[addr+6] << 16 ) | ( (u32)GAMEDATASAV.saveFile[addr+7] << 24 );
|
|
return val;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
float readF32FromHash(u32 hash, u32 offset) {
|
|
return readF32FromAddr(_searchHash(hash) + offset);
|
|
}
|
|
|
|
float readF32FromAddr(u32 addr) {
|
|
if(addr != 0) {
|
|
Float val;
|
|
val.m_bytes[0] = GAMEDATASAV.saveFile[addr+4];
|
|
val.m_bytes[1] = GAMEDATASAV.saveFile[addr+5];
|
|
val.m_bytes[2] = GAMEDATASAV.saveFile[addr+6];
|
|
val.m_bytes[3] = GAMEDATASAV.saveFile[addr+7];
|
|
return val.m_float;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void writeF32ToAddr(u32 addr, float value) {
|
|
if(addr != 0) {
|
|
Float val;
|
|
val.m_float = value;
|
|
GAMEDATASAV.saveFile[addr+4] = val.m_bytes[0];
|
|
GAMEDATASAV.saveFile[addr+5] = val.m_bytes[1];
|
|
GAMEDATASAV.saveFile[addr+6] = val.m_bytes[2];
|
|
GAMEDATASAV.saveFile[addr+7] = val.m_bytes[3];
|
|
//printMessage("wrote f32 %f to 0x%x, read check: %f\n", value, addr, readF32FromAddr(addr));
|
|
}
|
|
}
|
|
void writeU32ToAddr(u32 addr, u32 value) {
|
|
if (addr != 0) {
|
|
GAMEDATASAV.saveFile[addr+4] = value & 0x00000ff;
|
|
GAMEDATASAV.saveFile[addr+5] = (value & 0x0000ff00) >> 8;
|
|
GAMEDATASAV.saveFile[addr+6] = (value & 0x00ff0000) >> 16;
|
|
GAMEDATASAV.saveFile[addr+7] = (value & 0xff000000) >> 24;
|
|
//printMessage("wrote u32 0x%x to 0x%x, read check: 0x%x", value, addr, readU32FromAddr(addr));
|
|
}
|
|
}
|
|
|
|
void closeAndCommitSave() {
|
|
writeSave();
|
|
if (R_FAILED(fsdevCommitDevice("save"))) {
|
|
printMessage("Committing failed.");
|
|
}
|
|
free(GAMEDATASAV.saveFile);
|
|
} |