#include <SDL.h>
#include "world.h"
#include "die.h"
typedef char filename[4096];
#define MAGIC 0xBEE01D5
#define SCHEMA 0
static const char *pref_path() {
static char *path = NULL;
if (!path) path = SDL_GetPrefPath("citrons", "findgame");
sdl_error_assert(path);
return path;
}
static void get_chunk_filename(SDL_Point chunk_pos, filename name) {
int written = SDL_snprintf(name, sizeof(filename), "%schunk.%d.%d.dat",
pref_path(), chunk_pos.x, chunk_pos.y);
if (written >= sizeof(filename)) die("filename too large\n");
}
static void get_world_filename(filename name) {
int written = SDL_snprintf(
name, sizeof(filename), "%sworld.dat", pref_path());
if (written >= sizeof(filename)) die("filename too large\n");
}
static void write_header(SDL_RWops *file) {
Uint32 magic = MAGIC;
Uint32 schema = 0;
sdl_error_assert(SDL_RWwrite(file, &magic, sizeof(magic), 1));
sdl_error_assert(SDL_RWwrite(file, &schema, sizeof(schema), 1));
}
static void read_header(SDL_RWops *file) {
Uint32 magic;
Uint32 schema;
sdl_error_assert(SDL_RWread(file, &magic, sizeof(magic), 1));
if (magic != MAGIC) die("invalid save file");
sdl_error_assert(SDL_RWread(file, &schema, sizeof(schema), 1));
if (schema != SCHEMA) die("invalid save file");
}
void save_chunk(world *w, chunk *c) {
SDL_assert(c->loaded);
filename name;
get_chunk_filename(c->pos, name);
SDL_RWops *file = SDL_RWFromFile(name, "wb");
sdl_error_assert(file);
write_header(file);
sdl_error_assert(
SDL_RWwrite(file, c->tiles, sizeof(c->tiles), 1));
sdl_error_assert(SDL_RWclose(file) >= 0);
}
void save_world(world *w) {
filename name;
get_world_filename(name);
SDL_RWops *file = SDL_RWFromFile(name, "wb");
sdl_error_assert(file);
write_header(file);
sdl_error_assert(
SDL_RWwrite(file, &w->player.pos, sizeof(w->player.pos), 1));
sdl_error_assert(
SDL_RWwrite(file, &w->player.scores, sizeof(w->player.scores), 1));
sdl_error_assert(SDL_RWclose(file) >= 0);
for (int i = 0; i < MAX_CHUNKS; i++) {
if (w->chunks[i].loaded)
save_chunk(w, &w->chunks[i]);
}
}
SDL_bool is_chunk_saved(world *w, SDL_Point chunk_pos) {
filename name;
get_chunk_filename(chunk_pos, name);
SDL_RWops *file = SDL_RWFromFile(name, "a+b");
sdl_error_assert(file);
Sint64 len = SDL_RWseek(file, 0, RW_SEEK_END);
SDL_RWclose(file);
return len != 0;
}
SDL_bool load_saved_chunk(world *w, chunk *c) {
if (!is_chunk_saved(w, c->pos)) return SDL_FALSE;
filename name;
get_chunk_filename(c->pos, name);
SDL_RWops *file = SDL_RWFromFile(name, "rb");
read_header(file);
sdl_error_assert(
SDL_RWread(file, c->tiles, sizeof(c->tiles), 1));
SDL_RWclose(file);
return SDL_TRUE;
}
SDL_bool load_world(world *w) {
filename name;
get_world_filename(name);
SDL_RWops *file = SDL_RWFromFile(name, "a+b");
sdl_error_assert(file);
if (SDL_RWseek(file, 0, RW_SEEK_END) == 0) {
SDL_RWclose(file);
return SDL_FALSE;
}
SDL_RWseek(file, 0, RW_SEEK_SET);
read_header(file);
sdl_error_assert(
SDL_RWread(file, &w->player.pos, sizeof(w->player.pos), 1));
sdl_error_assert(
SDL_RWread(file, &w->player.scores, sizeof(w->player.scores), 1));
SDL_RWclose(file);
return SDL_TRUE;
}