diff options
Diffstat (limited to 'save.c')
| -rw-r--r-- | save.c | 130 |
1 files changed, 130 insertions, 0 deletions
@@ -0,0 +1,130 @@ +#include <SDL.h> + +#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; +} |
