+void WorldSave::Write(const World::Config &conf) const {
+ cout << "writing world save" << endl;
+
+ if (!make_dirs(root_path)) {
+ throw runtime_error("failed to create world save directory");
+ }
+
+ ofstream out(conf_path);
+ out << "seed = " << conf.gen.seed << endl;
+ out.close();
+
+ if (!out) {
+ throw runtime_error("failed to write world config");
+ }
+}
+
+
+bool WorldSave::Exists(const Chunk::Pos &pos) const noexcept {
+ return is_file(ChunkPath(pos));
+}
+
+void WorldSave::Read(Chunk &chunk) const {
+ const char *path = ChunkPath(chunk.Position());
+ gzFile file = gzopen(path, "r");
+ if (!file) {
+ throw runtime_error("failed to open chunk file");
+ }
+ if (gzread(file, chunk.BlockData(), Chunk::BlockSize()) != Chunk::BlockSize()) {
+ throw runtime_error("failed to read chunk from file");
+ }
+ if (gzclose(file) != Z_OK) {
+ throw runtime_error("failed to read chunk file");
+ }
+ chunk.InvalidateModel();
+ chunk.ClearSave();
+}
+
+void WorldSave::Write(Chunk &chunk) const {
+ const char *path = ChunkPath(chunk.Position());
+ gzFile file = gzopen(path, "w");
+ if (!file) {
+ // check if it's because of a missing path component
+ if (errno != ENOENT) {
+ // nope, fatal
+ throw runtime_error(strerror(errno));
+ }
+ string dir_path(path);
+ dir_path.erase(dir_path.find_last_of("\\/"));
+ if (!make_dirs(dir_path)) {
+ throw runtime_error("failed to create dir for chunk file");
+ }
+ file = gzopen(path, "w");
+ if (!file) {
+ throw runtime_error("failed to open chunk file");
+ }
+ }
+ if (gzwrite(file, chunk.BlockData(), Chunk::BlockSize()) == 0) {
+ gzclose(file); // if this fails, it can't be helped
+ throw runtime_error("failed to write chunk to file");
+ }
+ if (gzclose(file) != Z_OK) {
+ throw runtime_error("failed to write chunk file");
+ }
+ chunk.ClearSave();
+}
+
+
+const char *WorldSave::ChunkPath(const Chunk::Pos &pos) const {
+ snprintf(chunk_buf.get(), chunk_bufsiz, chunk_path.c_str(), pos.x, pos.y, pos.z);
+ return chunk_buf.get();
+}
+