summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorStanislaw Halik <sthalik@misaki.pl>2023-03-17 19:23:14 +0100
committerStanislaw Halik <sthalik@misaki.pl>2023-03-17 23:23:12 +0100
commit1d4b76f4429334b8d1a18cb50a9ceea04c10443e (patch)
tree1c37a8034b7eb541c66cb9c4f7f56449db1984a5
parent8c9175cc8e09fc1a714cab93860e9c533667f6c4 (diff)
a
-rw-r--r--serialize/binary-reader.hpp2
-rw-r--r--serialize/binary-reader.inl3
-rw-r--r--serialize/world-reader.cpp85
-rw-r--r--serialize/world-writer.cpp91
-rw-r--r--src/character.cpp1
-rw-r--r--src/chunk.cpp3
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}