diff options
Diffstat (limited to 'serialize/world-reader.cpp')
-rw-r--r-- | serialize/world-reader.cpp | 105 |
1 files changed, 100 insertions, 5 deletions
diff --git a/serialize/world-reader.cpp b/serialize/world-reader.cpp index 16a3afc1..d61a574a 100644 --- a/serialize/world-reader.cpp +++ b/serialize/world-reader.cpp @@ -3,10 +3,16 @@ #include "binary-reader.inl" #include "src/world.hpp" #include "loader/loader.hpp" +#include "loader/scenery.hpp" #include "src/tile-atlas.hpp" +#include "src/anim-atlas.hpp" #include <cstring> +#include <Corrade/Containers/StringStlHash.h> -namespace floormat::Serialize { +namespace { + +using namespace floormat; +using namespace floormat::Serialize; struct reader_state final { explicit reader_state(world& world) noexcept; @@ -15,16 +21,27 @@ struct reader_state final { private: using reader_t = binary_reader<decltype(ArrayView<const char>{}.cbegin())>; + void load_sceneries(); std::shared_ptr<tile_atlas> lookup_atlas(atlasid id); void read_atlases(reader_t& reader); + void read_sceneries(reader_t& reader); void read_chunks(reader_t& reader); std::unordered_map<atlasid, std::shared_ptr<tile_atlas>> atlases; + std::unordered_map<StringView, const serialized_scenery*> default_sceneries; + std::vector<scenery_proto> sceneries; world* _world; + std::uint16_t PROTO = (std::uint16_t)-1; }; reader_state::reader_state(world& world) noexcept : _world{&world} {} +void reader_state::load_sceneries() +{ + for (const serialized_scenery& s : loader.sceneries()) + default_sceneries[s.name] = &s; +} + void reader_state::read_atlases(reader_t& s) { const auto N = s.read<atlasid>(); @@ -39,6 +56,57 @@ void reader_state::read_atlases(reader_t& s) } } +template<typename T> +bool read_scenery_flags(binary_reader<T>& s, scenery& sc) +{ + std::uint8_t flags; s >> flags; + sc.passable = !!(flags & 1 << 0); + sc.blocks_view = !!(flags & 1 << 1); + sc.active = !!(flags & 1 << 2); + sc.closing = !!(flags & 1 << 3); + sc.interactive = !!(flags & 1 << 4); + return flags & 1 << 7; +} + +void reader_state::read_sceneries(reader_t& s) +{ + std::uint16_t magic; s >> magic; + if (magic != scenery_magic) + fm_abort("bad scenery magic"); + atlasid sz; s >> sz; + fm_assert(sz < scenery_id_max); + sceneries.resize(sz); + + std::size_t i = 0; + while (i < sz) + { + std::uint8_t num; s >> num; + fm_assert(num > 0); + auto str = s.read_asciiz_string<atlas_name_max>(); + auto it = default_sceneries.find(StringView{str.buf, str.len}); + if (it == default_sceneries.end()) + fm_abort("can't find scenery '%s'", str.buf); + for (std::size_t n = 0; n < num; n++) + { + atlasid id; s >> id; + fm_assert(id < sz); + scenery_proto sc = it->second->proto; + bool short_frame = read_scenery_flags(s, sc.frame); + fm_debug_assert(sc.atlas != nullptr); + if (short_frame) + sc.frame.frame = s.read<std::uint8_t>(); + else + s >> sc.frame.frame; + fm_assert(sc.frame.frame < sc.atlas->info().nframes); + sceneries[id] = sc; + } + i += num; + } + fm_assert(i == sz); + for (const scenery_proto& x : sceneries) + fm_assert(x.atlas != nullptr); +} + std::shared_ptr<tile_atlas> reader_state::lookup_atlas(atlasid id) { if (auto it = atlases.find(id); it != atlases.end()) @@ -51,7 +119,7 @@ void reader_state::read_chunks(reader_t& s) { const auto N = s.read<chunksiz>(); - for (std::size_t i = 0; i < N; i++) + for (std::size_t k = 0; k < N; k++) { std::decay_t<decltype(chunk_magic)> magic; s >> magic; @@ -74,12 +142,35 @@ void reader_state::read_chunks(reader_t& s) return { atlas, v }; }; + t.pass_mode() = pass_mode(flags & pass_mask); if (flags & meta_ground) t.ground() = make_atlas(); if (flags & meta_wall_n) t.wall_north() = make_atlas(); if (flags & meta_wall_w) t.wall_west() = make_atlas(); + if (PROTO >= 3) [[likely]] + if (flags & meta_scenery) + { + atlasid id; s >> id; + const bool exact = id & meta_long_scenery_bit; + const auto r = rotation(id >> sizeof(id)*8-1-rotation_BITS & rotation_MASK); + id &= ~scenery_id_flag_mask; + fm_assert(id < sceneries.size()); + auto sc = sceneries[id]; + (void)sc.atlas->group(r); + sc.frame.r = r; + if (!exact) + { + if (read_scenery_flags(s, sc.frame)) + sc.frame.frame = s.read<std::uint8_t>(); + else + s >> sc.frame.frame; + if (sc.frame.active) + s >> sc.frame.delta; + } + t.scenery() = sc; + } switch (auto x = pass_mode(flags & pass_mask)) { @@ -88,7 +179,7 @@ void reader_state::read_chunks(reader_t& s) case pass_ok: t.pass_mode() = x; break; - default: + default: [[unlikely]] fm_abort("bad pass mode '%zu' for tile %zu", i, (std::size_t)x); } } @@ -105,12 +196,16 @@ void reader_state::deserialize_world(ArrayView<const char> buf) if (!(proto >= min_proto_version && proto <= proto_version)) fm_abort("bad proto version '%zu' (should be between '%zu' and '%zu')", (std::size_t)proto, (std::size_t)min_proto_version, (std::size_t)proto_version); + PROTO = proto; + load_sceneries(); read_atlases(s); + if (PROTO >= 3) + read_sceneries(s); read_chunks(s); s.assert_end(); } -} // namespace floormat::Serialize +} // namespace namespace floormat { @@ -159,7 +254,7 @@ world world::deserialize(StringView filename) } world w; - Serialize::reader_state s{w}; + reader_state s{w}; s.deserialize_world({buf_.get(), len}); return w; } |