#include #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; }