summaryrefslogtreecommitdiffhomepage
path: root/serialize/world-reader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'serialize/world-reader.cpp')
-rw-r--r--serialize/world-reader.cpp105
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;
}