X-Git-Url: http://git.localhorst.tv/?a=blobdiff_plain;f=src%2Fio%2FWorldSave.cpp;h=ce7c71d35ea55c19d85b85b56b0a3f7d8e83db01;hb=e3e598182da7d1639de83f473a55bf6a585b3c61;hp=d90bce1654c4c5b0e1745043e328e8746d3e92c2;hpb=ede25c0a2f59e21521d1cd962e6ea9d78169ca12;p=blank.git diff --git a/src/io/WorldSave.cpp b/src/io/WorldSave.cpp index d90bce1..ce7c71d 100644 --- a/src/io/WorldSave.cpp +++ b/src/io/WorldSave.cpp @@ -1,13 +1,16 @@ #include "WorldSave.hpp" #include "filesystem.hpp" +#include "TokenStreamReader.hpp" #include +#include #include #include #include #include #include +#include using namespace std; @@ -16,7 +19,9 @@ namespace blank { WorldSave::WorldSave(const string &path) : root_path(path) -, conf_path(path + "world.conf") +, world_conf_path(path + "world.conf") +, gen_conf_path(path + "gen.conf") +, player_path(path + "player/") , chunk_path(path + "chunks/%d/%d/%d.gz") , chunk_bufsiz(chunk_path.length() + 3 * std::numeric_limits::digits10) , chunk_buf(new char[chunk_bufsiz]) { @@ -25,69 +30,145 @@ WorldSave::WorldSave(const string &path) bool WorldSave::Exists() const noexcept { - return is_dir(root_path) && is_file(conf_path); + return is_dir(root_path) && is_file(world_conf_path); } void WorldSave::Read(World::Config &conf) const { - cout << "reading world save" << endl; - - ifstream in(conf_path); - if (!in) { + ifstream is(world_conf_path); + if (!is) { throw runtime_error("failed to open world config"); } + TokenStreamReader in(is); + + string name; + while (in.HasMore()) { + in.ReadIdentifier(name); + in.Skip(Token::EQUALS); + if (name == "spawn") { + in.ReadVec(conf.spawn); + } + if (in.HasMore() && in.Peek().type == Token::SEMICOLON) { + in.Skip(Token::SEMICOLON); + } + } + + if (is.bad()) { + throw runtime_error("IO error reading world config"); + } +} - constexpr char spaces[] = "\n\r\t "; +void WorldSave::Write(const World::Config &conf) const { + if (!make_dirs(root_path)) { + throw runtime_error("failed to create world save directory"); + } - string line; - while (getline(in, line)) { - if (line.empty() || line[0] == '#') continue; - auto equals_pos = line.find_first_of('='); + ofstream out(world_conf_path); + out << "spawn = " << conf.spawn << ';' << endl; + out.close(); - auto name_begin = line.find_first_not_of(spaces, 0, sizeof(spaces)); - auto name_end = equals_pos - 1; - while (name_end > name_begin && isspace(line[name_end])) { - --name_end; - } + if (!out) { + throw runtime_error("failed to write world config"); + } +} - auto value_begin = line.find_first_not_of(spaces, equals_pos + 1, sizeof(spaces)); - auto value_end = line.length() - 1; - while (value_end > value_begin && isspace(line[value_end])) { - --value_end; - } - string name(line, name_begin, name_end - name_begin + 1); - string value(line, value_begin, value_end - value_begin + 1); +void WorldSave::Read(Generator::Config &conf) const { + ifstream is(gen_conf_path); + if (!is) { + throw runtime_error("failed to open generator config"); + } + TokenStreamReader in(is); + string name; + while (in.HasMore()) { + in.ReadIdentifier(name); + in.Skip(Token::EQUALS); if (name == "seed") { - conf.gen.seed = stoul(value); - } else { - throw runtime_error("unknown world option: " + name); + in.ReadNumber(conf.seed); + } + if (in.HasMore() && in.Peek().type == Token::SEMICOLON) { + in.Skip(Token::SEMICOLON); } } - if (in.bad()) { - throw runtime_error("IO error reading world config"); + + if (is.bad()) { + throw runtime_error("IO error reading generator config"); } } -void WorldSave::Write(const World::Config &conf) const { - cout << "writing world save" << endl; - +void WorldSave::Write(const Generator::Config &conf) const { if (!make_dirs(root_path)) { throw runtime_error("failed to create world save directory"); } - ofstream out(conf_path); - out << "seed = " << conf.gen.seed << endl; + ofstream out(gen_conf_path); + out << "seed = " << conf.seed << ';' << endl; out.close(); if (!out) { - throw runtime_error("failed to write world config"); + throw runtime_error("failed to write generator config"); } } -bool WorldSave::Exists(const Chunk::Pos &pos) const noexcept { +bool WorldSave::Exists(const Player &player) const { + return is_file(PlayerPath(player)); +} + +void WorldSave::Read(Player &player) const { + ifstream is(PlayerPath(player)); + TokenStreamReader in(is); + string name; + EntityState state; + while (in.HasMore()) { + in.ReadIdentifier(name); + in.Skip(Token::EQUALS); + if (name == "chunk") { + in.ReadVec(state.pos.chunk); + } else if (name == "position") { + in.ReadVec(state.pos.block); + } else if (name == "orientation") { + in.ReadQuat(state.orient); + } else if (name == "pitch") { + state.pitch = in.GetFloat(); + } else if (name == "yaw") { + state.yaw = in.GetFloat(); + } else if (name == "slot") { + int slot; + in.ReadNumber(slot); + player.SetInventorySlot(slot); + } + if (in.HasMore() && in.Peek().type == Token::SEMICOLON) { + in.Skip(Token::SEMICOLON); + } + } + player.GetEntity().SetState(state); + player.Update(0); +} + +void WorldSave::Write(const Player &player) const { + if (!make_dirs(player_path)) { + throw runtime_error("failed to create player save directory"); + } + const EntityState &state = player.GetEntity().GetState(); + ofstream out(PlayerPath(player)); + out << "chunk = " << state.pos.chunk << ';' << endl; + out << "position = " << state.pos.block << ';' << endl; + out << "orientation = " << state.orient << ';' << endl; + out << "pitch = " << state.pitch << ';' << endl; + out << "yaw = " << state.yaw << ';' << endl; + out << "slot = " << player.GetInventorySlot() << ';' << endl; +} + +string WorldSave::PlayerPath(const Player &player) const { + // TODO: this is potentially dangerous, server and client should + // provide a sanitized name for storage + return player_path + player.Name(); +} + + +bool WorldSave::Exists(const ExactLocation::Coarse &pos) const noexcept { return is_file(ChunkPath(pos)); } @@ -103,7 +184,8 @@ void WorldSave::Read(Chunk &chunk) const { if (gzclose(file) != Z_OK) { throw runtime_error("failed to read chunk file"); } - chunk.InvalidateModel(); + chunk.ScanActive(); + chunk.InvalidateMesh(); chunk.ClearSave(); } @@ -137,7 +219,7 @@ void WorldSave::Write(Chunk &chunk) const { } -const char *WorldSave::ChunkPath(const Chunk::Pos &pos) const { +const char *WorldSave::ChunkPath(const ExactLocation::Coarse &pos) const { snprintf(chunk_buf.get(), chunk_bufsiz, chunk_path.c_str(), pos.x, pos.y, pos.z); return chunk_buf.get(); }