diff options
author | Stanislaw Halik <sthalik@misaki.pl> | 2023-03-17 19:23:14 +0100 |
---|---|---|
committer | Stanislaw Halik <sthalik@misaki.pl> | 2023-03-17 23:23:12 +0100 |
commit | 1d4b76f4429334b8d1a18cb50a9ceea04c10443e (patch) | |
tree | 1c37a8034b7eb541c66cb9c4f7f56449db1984a5 | |
parent | 8c9175cc8e09fc1a714cab93860e9c533667f6c4 (diff) |
a
-rw-r--r-- | serialize/binary-reader.hpp | 2 | ||||
-rw-r--r-- | serialize/binary-reader.inl | 3 | ||||
-rw-r--r-- | serialize/world-reader.cpp | 85 | ||||
-rw-r--r-- | serialize/world-writer.cpp | 91 | ||||
-rw-r--r-- | src/character.cpp | 1 | ||||
-rw-r--r-- | src/chunk.cpp | 3 |
6 files changed, 118 insertions, 67 deletions
diff --git a/serialize/binary-reader.hpp b/serialize/binary-reader.hpp index 96af8bf1..3c71c7fc 100644 --- a/serialize/binary-reader.hpp +++ b/serialize/binary-reader.hpp @@ -49,7 +49,7 @@ template<string_input_iterator It, serializable T> constexpr void operator<<(T& x, binary_reader<It>& reader) noexcept(false); template<string_input_iterator It, serializable T> -constexpr binary_reader<It>& operator>>(binary_reader<It>& reader, T& x) noexcept(false); +constexpr void operator>>(binary_reader<It>& reader, T& x) noexcept(false); template<string_input_iterator It> binary_reader(It&& begin, It&& end) -> binary_reader<std::decay_t<It>>; diff --git a/serialize/binary-reader.inl b/serialize/binary-reader.inl index 73be97d9..9e27f1a0 100644 --- a/serialize/binary-reader.inl +++ b/serialize/binary-reader.inl @@ -49,10 +49,9 @@ constexpr void binary_reader<It>::assert_end() noexcept(false) } template<string_input_iterator It, serializable T> -constexpr binary_reader<It>& operator>>(binary_reader<It>& reader, T& x) noexcept(false) +constexpr void operator>>(binary_reader<It>& reader, T& x) noexcept(false) { x = reader.template read<T>(); - return reader; } template<string_input_iterator It, serializable T> diff --git a/serialize/world-reader.cpp b/serialize/world-reader.cpp index da39fe17..b38c16b4 100644 --- a/serialize/world-reader.cpp +++ b/serialize/world-reader.cpp @@ -54,10 +54,9 @@ void reader_state::read_atlases(reader_t& s) } template<typename T, entity_subtype U> -bool read_scenery_flags(binary_reader<T>& s, U& e) +bool read_entity_flags(binary_reader<T>& s, U& e) { constexpr auto tag = entity_type_<U>::value; - static_assert(tag != entity_type::none); std::uint8_t flags; flags << s; e.pass = pass_mode(flags & pass_mask); if (e.type != tag) @@ -100,7 +99,7 @@ void reader_state::read_sceneries(reader_t& s) atlasid id; id << s; fm_soft_assert(id < sz); fm_soft_assert(!sceneries[id]); - bool short_frame = read_scenery_flags(s, sc); + bool short_frame = read_entity_flags(s, sc); fm_debug_assert(sc.atlas != nullptr); if (short_frame) sc.frame = s.read<std::uint8_t>(); @@ -187,7 +186,7 @@ void reader_state::read_chunks(reader_t& s) sc.r = r; if (!exact) { - if (read_scenery_flags(s, sc)) + if (read_entity_flags(s, sc)) sc.frame = s.read<std::uint8_t>(); else sc.frame << s; @@ -219,12 +218,82 @@ void reader_state::read_chunks(reader_t& s) c.add_entity_unsorted(e); } } + if (PROTO < 8) [[unlikely]] + c.sort_entities(); + + std::uint32_t entity_count; entity_count << s; + for (auto i = 0_uz; i < entity_count; i++) + { + std::uint64_t _id; _id << s; + const auto oid = _id & (1ULL << 60)-1; + fm_soft_assert(oid != 0); + static_assert(entity_type_BITS == 3); + const auto type = entity_type(_id >> 61); + const auto local = local_coords{s.read<std::uint8_t>()}; + constexpr auto read_offsets = [](auto& s, auto& e) { + s >> e.offset[0]; + s >> e.offset[1]; + s >> e.bbox_offset[0]; + s >> e.bbox_offset[1]; + s >> e.bbox_size[0]; + s >> e.bbox_size[1]; + }; + switch (type) + { + case entity_type::character: { + character_proto proto; + std::uint8_t id; id << s; + proto.frame = read_entity_flags(s, proto) ? s.read<std::uint8_t>() : s.read<std::uint16_t>(); + proto.r = rotation(id >> sizeof(id)*8-1-rotation_BITS & rotation_MASK); + Vector2s offset_frac; + offset_frac[0] << s; + offset_frac[1] << s; + const auto name = s.read_asciiz_string<character_name_max>(); + proto.name = StringView{name.buf, name.len, StringViewFlag::Global|StringViewFlag::NullTerminated}; + if (id & meta_long_scenery_bit) + read_offsets(s, proto); + auto C = _world->make_entity<character>(oid, {ch, local}, proto); + c.add_entity_unsorted(C); + break; + } + case entity_type::scenery: { + atlasid id; id << s; + 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; + auto sc = lookup_scenery(id); + (void)sc.atlas->group(r); + sc.r = r; + if (!exact) + { + if (read_entity_flags(s, sc)) + sc.frame = s.read<std::uint8_t>(); + else + sc.frame << s; + read_offsets(s, sc); + if (sc.active) + sc.delta << s; + } + global_coords coord{ch, local_coords{i}}; + auto e = _world->make_entity<scenery>(oid, coord, sc); + c.add_entity_unsorted(e); + break; + } + default: + fm_throw("invalid_entity_type '{}'"_cf, (int)type); + } + } + c.sort_entities(); + + fm_assert(c.is_scenery_modified()); + fm_assert(c.is_passability_modified()); } } void reader_state::deserialize_world(ArrayView<const char> buf) { + fm_assert(_world != nullptr); auto s = binary_reader{buf}; if (!!::memcmp(s.read<std::size(file_magic)-1>().data(), file_magic, std::size(file_magic)-1)) fm_throw("bad magic"_cf); @@ -234,13 +303,17 @@ void reader_state::deserialize_world(ArrayView<const char> buf) fm_throw("bad proto version '{}' (should be between '{}' and '{}')"_cf, (std::size_t)proto, (std::size_t)min_proto_version, (std::size_t)proto_version); PROTO = proto; - if (PROTO >= 8) - _world->set_entity_counter(s.read<std::uint64_t>()); read_atlases(s); if (PROTO >= 3) read_sceneries(s); read_chunks(s); + if (PROTO >= 8) + { + fm_assert(_world->entity_counter() == 0); + _world->set_entity_counter(s.read<std::uint64_t>()); + } s.assert_end(); + _world = nullptr; } } // namespace diff --git a/serialize/world-writer.cpp b/serialize/world-writer.cpp index 9351856f..3bfad5e1 100644 --- a/serialize/world-writer.cpp +++ b/serialize/world-writer.cpp @@ -68,9 +68,8 @@ private: }; constexpr auto tile_size = sizeof(tilemeta) + (sizeof(atlasid) + sizeof(variant_t)) * 3 + sizeof(scenery); - -constexpr auto chunkbuf_size = - sizeof(chunk_magic) + sizeof(chunk_coords) + tile_size * TILE_COUNT; +constexpr auto chunkbuf_size = sizeof(chunk_magic) + sizeof(chunk_coords) + tile_size * TILE_COUNT; +constexpr auto entity_size = std::max(sizeof(character), sizeof(scenery)); #ifdef __GNUG__ #pragma GCC diagnostic push @@ -145,10 +144,10 @@ scenery_pair writer_state::intern_scenery(const scenery& sc, bool create) fm_assert(s.sc_type == proto.sc_type); s.r = proto.r; s.interactive = proto.interactive; - s.active = proto.active; + s.active = proto.active; s.closing = proto.closing; s.pass = proto.pass; - if (x.s->proto.frame == s.frame) + if (s == proto) { if (x.index != null_atlas) return { x.s, x.index, true }; @@ -186,7 +185,6 @@ void write_entity_flags(binary_writer<T>& s, const U& e) fm_assert((pass & pass_mask) == pass); flags |= pass; constexpr auto tag = entity_type_<U>::value; - static_assert(tag != entity_type::none); if (e.type != tag) fm_abort("invalid entity type '%d'", (int)e.type); if constexpr(tag == entity_type::scenery) @@ -298,10 +296,12 @@ void writer_state::serialize_scenery() scenery_buf.resize(s.bytes_written()); } +const auto def_char_bbox_size = character_proto{}.bbox_size; +const auto def_char_pass = character_proto{}.pass; + void writer_state::serialize_chunk(const chunk& c, chunk_coords coord) { fm_assert(chunk_buf.empty()); - constexpr std::size_t entity_size = std::max(sizeof(character), sizeof(scenery)); chunk_buf.resize(chunkbuf_size + sizeof(std::uint32_t) + entity_size*c.entities().size()); auto s = binary_writer{chunk_buf.begin()}; @@ -319,27 +319,19 @@ void writer_state::serialize_chunk(const chunk& c, chunk_coords coord) auto img_g = maybe_intern_atlas(ground); auto img_n = maybe_intern_atlas(wall_north); auto img_w = maybe_intern_atlas(wall_west); - //auto [sc, img_s, sc_exact] = maybe_intern_scenery(scenery, true); tilemeta flags = {}; flags |= meta_ground * (img_g != null_atlas); flags |= meta_wall_n * (img_n != null_atlas); flags |= meta_wall_w * (img_w != null_atlas); - //flags |= meta_scenery * (img_s != null_atlas); - - //flags |= pass_mode_(x.passability); - s << flags; -#ifndef FM_NO_DEBUG constexpr auto check_atlas = [](const tile_image_proto& x) { - if (x.atlas) - fm_assert(x.variant < x.atlas->num_tiles()); + fm_assert(!x.atlas || x.variant < x.atlas->num_tiles()); }; check_atlas(ground); check_atlas(wall_north); check_atlas(wall_west); -#endif if (img_g != null_atlas) s << img_g, s << ground.variant; @@ -361,20 +353,28 @@ void writer_state::serialize_chunk(const chunk& c, chunk_coords coord) oid |= (std::uint64_t)e.type << 64 - entity_type_BITS; s << oid; const auto local = e.coord.local(); - s << local.x; - s << local.y; - s << e.offset[0]; - s << e.offset[1]; - s << e.bbox_size[0]; - s << e.bbox_size[1]; - s << e.bbox_offset[0]; - s << e.bbox_offset[1]; + s << local.to_index(); + constexpr auto write_offsets = [](auto& s, const auto& e) { + s << e.offset[0]; + s << e.offset[1]; + s << e.bbox_offset[0]; + s << e.bbox_offset[1]; + s << e.bbox_size[0]; + s << e.bbox_size[1]; + }; switch (e.type) { default: fm_abort("invalid entity type '%d'", (int)e.type); case entity_type::character: { const auto& C = static_cast<const character&>(e); + std::uint8_t id = 0; + const auto sc_exact = + C.offset.isZero() && C.bbox_offset.isZero() && + C.bbox_size == def_char_bbox_size; + id |= meta_long_scenery_bit * sc_exact; + id |= static_cast<decltype(id)>(C.r) << sizeof(id)*8-1-rotation_BITS; + s << id; write_entity_flags(s, C); if (C.frame <= 0xff) s << (std::uint8_t)C.frame; @@ -384,26 +384,32 @@ void writer_state::serialize_chunk(const chunk& c, chunk_coords coord) s << C.offset_frac[1]; fm_assert(C.name.size() < character_name_max); s.write_asciiz_string(C.name); + if (!sc_exact) + write_offsets(s, C); break; } case entity_type::scenery: { const auto& sc = static_cast<const scenery&>(e); auto [ss, img_s, sc_exact] = intern_scenery(sc, true); + sc_exact = sc_exact && + e.offset.isZero() && e.bbox_offset.isZero() && e.bbox_size.isZero() && + !sc.active && !sc.closing && !sc.interactive; fm_assert(img_s != null_atlas); atlasid id = img_s; static_assert(rotation_BITS == 3); fm_assert((id & (1 << 16-3-1)-1) == id); id |= meta_long_scenery_bit * sc_exact; - id |= atlasid(sc.r) << sizeof(atlasid)*8-1-rotation_BITS; + id |= static_cast<decltype(id)>(sc.r) << sizeof(id)*8-1-rotation_BITS; s << id; if (!sc_exact) { - fm_assert(sc.active || sc.delta == 0); write_entity_flags(s, sc); + fm_assert(sc.active || sc.delta == 0); if (sc.frame <= 0xff) s << (std::uint8_t)sc.frame; else s << sc.frame; + write_offsets(s, sc); if (sc.active) s << sc.delta; } @@ -412,37 +418,6 @@ void writer_state::serialize_chunk(const chunk& c, chunk_coords coord) } } -#if 0 - if (img_s != null_atlas) - { - atlasid id = img_s; - fm_assert(!(id & ~((1 << 16-3-1)-1))); - id |= meta_long_scenery_bit * sc_exact; - id |= atlasid(scenery.r) << sizeof(atlasid)*8-1-rotation_BITS; - s << id; - if (!sc_exact) - { - fm_assert(scenery.active || scenery.delta == 0); - write_entity_flags(s, scenery); - if (scenery.frame <= 0xff) - s << (std::uint8_t)scenery.frame; - else - s << scenery.frame; - s << scenery.offset[0]; - s << scenery.offset[1]; - - s << scenery.bbox_size[0]; - s << scenery.bbox_size[1]; - - s << scenery.bbox_offset[0]; - s << scenery.bbox_offset[1]; - - if (scenery.active) - s << scenery.delta; - } - } -#endif - const auto nbytes = s.bytes_written(); fm_assert(nbytes <= chunkbuf_size); @@ -461,6 +436,7 @@ void writer_state::serialize_chunk(const chunk& c, chunk_coords coord) ArrayView<const char> writer_state::serialize_world() { + fm_assert(_world != nullptr); load_scenery(); for (const auto& [_, c] : _world->chunks()) @@ -523,6 +499,7 @@ ArrayView<const char> writer_state::serialize_world() copy_int((chunksiz)_world->size()); for (const auto& buf : chunk_bufs) copy(buf); + _world = nullptr; return {file_buf.data(), file_buf.size()}; } diff --git a/src/character.cpp b/src/character.cpp index c16fce35..ed9ce4fa 100644 --- a/src/character.cpp +++ b/src/character.cpp @@ -53,6 +53,7 @@ constexpr auto arrows_to_dir(bool L, bool R, bool U, bool D) character::character(std::uint64_t id, struct chunk& c, entity_type type, const character_proto& proto) : entity{id, c, type}, + name{proto.name}, playable{proto.playable} { atlas = loader.anim_atlas("npc-walk", loader.ANIM_PATH); diff --git a/src/chunk.cpp b/src/chunk.cpp index 351848d0..a99facf6 100644 --- a/src/chunk.cpp +++ b/src/chunk.cpp @@ -86,7 +86,8 @@ void chunk::mark_modified() noexcept { mark_ground_modified(); mark_walls_modified(); - mark_scenery_modified(); + mark_scenery_modified(false); + mark_passability_modified(); } chunk::chunk(struct world& w) noexcept : _world{&w} |