diff options
author | Stanislaw Halik <sthalik@misaki.pl> | 2024-01-20 21:45:12 +0100 |
---|---|---|
committer | Stanislaw Halik <sthalik@misaki.pl> | 2024-01-20 21:45:12 +0100 |
commit | 82ff8045a633e064e145616041c272b7c9e9cd30 (patch) | |
tree | e8d000e7ab6bc0a00be034f1e605c8faee298aef | |
parent | a16964cc466bc2e174007b9dfa21a2cb35d63315 (diff) |
w
-rw-r--r-- | serialize/savegame.cpp | 87 | ||||
-rw-r--r-- | src/world.hpp | 2 |
2 files changed, 63 insertions, 26 deletions
diff --git a/serialize/savegame.cpp b/serialize/savegame.cpp index 501a152c..4cd7ef6a 100644 --- a/serialize/savegame.cpp +++ b/serialize/savegame.cpp @@ -2,8 +2,10 @@ #include "compat/defs.hpp" #include "compat/strerror.hpp" #include "compat/int-hash.hpp" -#include "loader/loader.hpp" +#include "compat/exception.hpp" + #include "src/world.hpp" +#include "loader/loader.hpp" #include "atlas-type.hpp" #include "src/anim-atlas.hpp" @@ -33,18 +35,6 @@ namespace floormat::Serialize { namespace { -using tilemeta = uint8_t; -using atlasid = uint32_t; -using chunksiz = uint32_t; -using proto_t = uint32_t; - -constexpr inline proto_t proto_version = 20; -constexpr inline auto file_magic = ".floormat.save"_s; -constexpr inline auto chunk_magic = (uint16_t)0xdead; -constexpr inline auto object_magic = (uint16_t)0xb00b; -constexpr inline auto atlas_magic = (uint16_t)0xbeef; -constexpr inline auto null_atlas = (atlasid)-1; - struct FILE_raii final { FILE_raii(FILE* s) noexcept : s{s} {} @@ -57,13 +47,19 @@ private: using floormat::Hash::fnvhash_buf; +struct string_hasher +{ + inline size_t operator()(StringView s) const + { + return fnvhash_buf(s.data(), s.size()); + } +}; + template<typename T> T& non_const(const T& value) { return const_cast<T&>(value); } template<typename T> T& non_const(T& value) = delete; template<typename T> T& non_const(T&& value) = delete; template<typename T> T& non_const(const T&& value) = delete; -constexpr size_t vector_initial_size = 128, hash_initial_size = vector_initial_size*2; - struct buffer { std::unique_ptr<char[]> data; @@ -97,6 +93,18 @@ struct serialized_chunk template<typename Derived> struct visitor_ { + using tilemeta = uint8_t; + using atlasid = uint32_t; + using chunksiz = uint32_t; + using proto_t = uint32_t; + + static constexpr inline proto_t proto_version = 20; + static constexpr inline auto file_magic = ".floormat.save"_s; + static constexpr inline auto chunk_magic = (uint16_t)0xdead; + static constexpr inline auto object_magic = (uint16_t)0xb00b; + static constexpr inline auto atlas_magic = (uint16_t)0xbeef; + static constexpr inline auto null_atlas = (atlasid)-1; + template<typename T, typename F> CORRADE_ALWAYS_INLINE void do_visit_nonconst(const T& value, F&& fun) { @@ -172,13 +180,7 @@ struct visitor_ } }; -struct string_hasher -{ - inline size_t operator()(StringView s) const - { - return fnvhash_buf(s.data(), s.size()); - } -}; +constexpr size_t vector_initial_size = 128, hash_initial_size = vector_initial_size*2; struct writer final : visitor_<writer> { @@ -269,7 +271,7 @@ struct writer final : visitor_<writer> case atlas_type::none: break; } fm_abort("invalid atlas type '%d'", (int)type); - + ok: do_visit(intern_string(name), f); } @@ -464,6 +466,12 @@ ok: } }; +struct reader final : visitor_<reader> +{ + class world& w; + reader(class world& w) : w{w} {} +}; + void my_fwrite(FILE_raii& f, const buffer& buf, char(&errbuf)[128]) { auto len = ::fwrite(&buf.data[0], buf.size, 1, f); @@ -528,10 +536,39 @@ void world::serialize(StringView filename) } } -class world world::deserialize(StringView filename) +class world world::deserialize(StringView filename) noexcept(false) { - (void)filename; + char errbuf[128]; + buffer buf; + + fm_soft_assert(filename.flags() & StringViewFlag::NullTerminated); + FILE_raii f = ::fopen(filename.data(), "rb"); + { + if (!f) + fm_throw("fopen(\"{}\", \"r\"): {}"_cf, filename, get_error_string(errbuf)); + if (int ret = ::fseek(f, 0, SEEK_END); ret != 0) + fm_throw("fseek(SEEK_END): {}"_cf, get_error_string(errbuf)); + size_t len; + if (auto len_ = ::ftell(f); len_ >= 0) + len = (size_t)len_; + else + fm_throw("ftell: {}"_cf, get_error_string(errbuf)); + if (int ret = ::fseek(f, 0, SEEK_SET); ret != 0) + fm_throw("fseek(SEEK_SET): {}"_cf, get_error_string(errbuf)); + auto buf_ = std::make_unique<char[]>(len+1); + if (auto ret = ::fread(&buf_[0], 1, len+1, f); ret != len) + fm_throw("fread short read: {}"_cf, get_error_string(errbuf)); + + buf.data = std::move(buf_); + buf.size = len; + } + + class world w; + struct reader reader(w); + r.deserialize_world(buf); + fm_assert("todo" && false); + return w; } } // namespace floormat diff --git a/src/world.hpp b/src/world.hpp index 4ffac90d..88927166 100644 --- a/src/world.hpp +++ b/src/world.hpp @@ -69,7 +69,7 @@ public: const auto& chunks() const noexcept { return _chunks; } void serialize(StringView filename); - static world deserialize(StringView filename); + static world deserialize(StringView filename) noexcept(false); void set_collect_threshold(size_t value) { _collect_every = value; } size_t collect_threshold() const noexcept { return _collect_every; } auto frame_no() const { return _current_frame; } |