From ab32d51871248e0fbf6758a425eda2256712d519 Mon Sep 17 00:00:00 2001 From: citrons Date: Wed, 11 Oct 2023 23:58:12 -0500 Subject: initial commit --- save.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 save.c (limited to 'save.c') diff --git a/save.c b/save.c new file mode 100644 index 0000000..13c2368 --- /dev/null +++ b/save.c @@ -0,0 +1,130 @@ +#include + +#include "world.h" +#include "die.h" + +typedef char filename[4096]; + +#define MAGIC 0xBEE10D5 +#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; +} -- cgit v1.2.3