From 250e0817fedc6e9337debe07bf64a19bd7e0baa8 Mon Sep 17 00:00:00 2001 From: Stanislaw Halik Date: Tue, 9 Apr 2024 01:37:57 +0200 Subject: w --- serialize/savegame.cpp | 276 ++++++++++++++++++++++++------------------------- 1 file changed, 134 insertions(+), 142 deletions(-) (limited to 'serialize/savegame.cpp') diff --git a/serialize/savegame.cpp b/serialize/savegame.cpp index d583f1ec..63ed3182 100644 --- a/serialize/savegame.cpp +++ b/serialize/savegame.cpp @@ -87,7 +87,7 @@ struct object_header_s { object_id& id; object_type& type; - chunk_coords_& ch; + chunk* const& ch; local_coords& tile; }; @@ -96,11 +96,11 @@ struct critter_header_s uint16_t& offset_frac; }; -template +using proto_t = uint16_t; + +template struct visitor_ { - using proto_t = uint16_t; - // ---------- proto versions ---------- // 19: see old-savegame.cpp // 20: complete rewrite @@ -118,6 +118,8 @@ struct visitor_ const proto_t& PROTO; // NOLINT(*-avoid-const-or-ref-data-members) + static constexpr bool IsWriter = IsWriter_; + using tilemeta = uint8_t; using atlasid = uint32_t; using chunksiz = uint32_t; @@ -130,37 +132,38 @@ struct visitor_ fm_DECLARE_DELETED_COPY_ASSIGNMENT(visitor_); fm_DECLARE_DELETED_MOVE_ASSIGNMENT(visitor_); - template - [[deprecated]] - CORRADE_ALWAYS_INLINE void do_visit(T&& value, F&& fun) // todo! remove it - { - static_cast(*this).visit(value, fun); - } + template using qual2 = std::__conditional_t; + template using qual = std::__conditional_t; + + using o_object = qual2; + using o_critter = qual2; + using o_scenery = qual2; + using o_light = qual2; + using o_sc_g = qual2; + using o_sc_door = qual2; template requires (std::is_arithmetic_v && std::is_fundamental_v) - static void visit(T& x, F&& f) - { - f(x); - } + static void visit(qual& x, F&& f) { f(x); } template - void visit(Math::Vector& x, F&& f) + void visit(qual>& x, F&& f) { for (uint32_t i = 0; i < N; i++) - do_visit(x.data()[i], f); + self.visit(x.data()[i], f); } template requires std::is_enum_v - void visit(E& x, F&& f) + void visit(qual& x, F&& f) { - auto* ptr = const_cast*>(reinterpret_cast*>(&x)); - visit(*ptr, f); + using U = std::underlying_type_t; + qual& ptr = const_cast(reinterpret_cast(&x)); + visit(ptr, f); } - template - void visit_object_header(object_proto& obj, object_header_s& s, F&& f) + template + void visit_object_header(o_object& obj, const object_header_s& s, F&& f) { visit(s.id, f); fm_soft_assert(s.id != 0); @@ -172,11 +175,11 @@ struct visitor_ case object_type::none: case object_type::COUNT: std::unreachable(); case object_type::light: - static_cast(*this).visit(obj.atlas, atlas_type::vobj, f); + self.visit(obj.atlas, atlas_type::vobj, f); break; case object_type::scenery: case object_type::critter: - static_cast(*this).visit(obj.atlas, atlas_type::anim, f); + self.visit(obj.atlas, atlas_type::anim, f); break; } fm_debug_assert(obj.atlas); @@ -209,7 +212,7 @@ struct visitor_ do_visit(c.wall_west(), f); } - template static void visit(chunk_coords_& coord, F&& f) + template static void visit(qual& coord, F&& f) { f(coord.x); f(coord.y); @@ -220,59 +223,19 @@ struct visitor_ flag_playable = 1 << 0, }; - - template - void visit(critter_proto& obj, critter_header_s& s, F&& f) - { - self.visit(obj.name, f); - - if (PROTO >= 22) [[likely]] - visit(obj.speed, f); - fm_soft_assert(obj.speed >= 0); - - if (PROTO >= 24) [[likely]] - visit(s.offset_frac, f); - else - { - static_assert(std::is_same_v); - Vector2us foo1; - do_visit(foo1, f); - auto foo2 = Vector2(foo1)*(1.f/65535); - auto foo3 = foo2.length()*32768; - visit(s.offset_frac, f); - } - - constexpr struct { - uint8_t bits; - bool(*getter)(const critter&); - void(*setter)(critter&, bool); - } pairs[] = { - { flag_playable, - [](const critter& sc) { return !!sc.playable; }, - [](critter& sc, bool value) { sc.playable = value; } - }, - }; - - uint8_t flags = 0; - for (auto [bits, getter, setter] : pairs) - flags |= bits * getter(obj); - do_visit(flags, f); - for (auto [bits, getter, setter] : pairs) - setter(obj, flags & bits); - } - enum : uint8_t { flag_active = 1 << 0, flag_closing = 1 << 1, flag_interactive = 1 << 2, }; - template void visit(generic_scenery_proto& s, F&& f) + template + void visit_scenery_proto_(o_sc_g& s, F&& f) { constexpr struct { uint8_t bits; - bool(*getter)(const generic_scenery&); - void(*setter)(generic_scenery&, bool); + bool(*getter)(const T&); + void(*setter)(T&, bool); } pairs[] = { { flag_active, [](const auto& sc) { return !!sc.active; }, @@ -292,12 +255,13 @@ struct visitor_ setter(s, flags & bits); } - template void visit(door_scenery& s, F&& f) + template + void visit_scenery_proto_(o_sc_door& s, F&& f) { constexpr struct { uint8_t bits; - bool(*getter)(const door_scenery&); - void(*setter)(door_scenery&, bool); + bool(*getter)(const T&); + void(*setter)(T&, bool); } pairs[] = { { flag_active, [](const auto& sc) { return !!sc.active; }, @@ -321,55 +285,43 @@ struct visitor_ setter(s, flags & bits); } - template void visit(scenery& obj, F&& f) + template + void visit_object_proto(o_critter& obj, critter_header_s& s, F&& f) { - auto sc_type = obj.scenery_type(); - do_visit(sc_type, f); - if (sc_type != obj.scenery_type()) - obj.subtype = scenery::subtype_from_scenery_type(obj.id, *obj.c, sc_type); + self.visit(obj.name, f); - std::visit( - [&](T& x) { return do_visit(x, f); }, - obj.subtype - ); + if (PROTO >= 22) [[likely]] + visit(obj.speed, f); + fm_soft_assert(obj.speed >= 0); + + if (PROTO >= 24) [[likely]] + visit(s.offset_frac, f); + else + { + Vector2us foo1; + visit(foo1, f); + s.offset_frac = 0; + } + visit(obj.playable, f); } - template void visit(light& obj, F&& f) + template + void visit_object_proto(o_light& s, F&& f) { - do_visit(obj.max_distance, f); - do_visit(obj.color, f); - auto falloff = obj.falloff; - do_visit(falloff, f); - obj.falloff = falloff; - - constexpr struct { - uint8_t bits; - bool(*getter)(const light&); - void(*setter)(light&, bool); - } pairs[] = { - { 1 << 0, - [](const light& sc) { return !!sc.enabled; }, - [](light& sc, bool value) { sc.enabled = value; } - }, - }; - - uint8_t flags = 0; - for (auto [bits, getter, setter] : pairs) - flags |= bits * getter(obj); - do_visit(flags, f); - for (auto [bits, getter, setter] : pairs) - setter(obj, flags & bits); + visit(s.max_distance, f); + visit(s.color, f); + visit(s.falloff, f); + visit(s.enabled, f); } }; constexpr size_t vector_initial_size = 128, hash_initial_size = vector_initial_size*2; -struct writer final : visitor_ +struct writer final : visitor_ { + using visitor_::visit; static const proto_t fake_proto; - const world& w; - struct serialized_atlas { [[maybe_unused]] buffer buf; @@ -383,6 +335,8 @@ struct writer final : visitor_ chunk* c; }; + const world& w; + std::vector string_array{}; tsl::robin_map string_map{hash_initial_size}; @@ -419,8 +373,6 @@ struct writer final : visitor_ } }; - using visitor_::visit; - template void visit(std::shared_ptr& a, atlas_type type, F&& f) { @@ -439,10 +391,40 @@ struct writer final : visitor_ } template - void visit(object& obj, F&& f, chunk_coords_ ch) + void write_scenery(const scenery& obj, F&& f) // todo! replace scenery::subtype with inheritance! { - visit_object_internal(obj, f, obj.id, obj.type(), ch); - zzz; + auto sc_type = obj.scenery_type(); + visit(sc_type, f); + std::visit( + [&](auto& subtype) { visit_scenery_proto_(subtype, f); }, + obj.subtype + ); + } + + template + void serialize_object(o_object& obj, chunk* c, F&& f) + { + auto id = obj.id; + auto type = obj.type(); + auto tile = obj.coord.local(); + const object_header_s s{ + .id = id, + .type = type, + .ch = c, + .tile = tile, + }; + visit_object_header(obj, s, f); + switch (type) + { + case object_type::none: + case object_type::COUNT: + break; + case object_type::critter: visit_object_proto(static_cast(obj), f); goto ok; + case object_type::light: visit_object_proto(static_cast(obj), f); goto ok; + case object_type::scenery: write_scenery(static_cast(obj), f); goto ok; + } + fm_assert(false); +ok: void(); } template @@ -533,7 +515,8 @@ struct writer final : visitor_ fm_assert(obj != nullptr); if (obj->ephemeral) continue; - do_visit(object_magic, f); // todo move before all objects + auto magic = object_magic; + visit(magic, f); visit(*obj, f, c.coord()); } } @@ -559,10 +542,10 @@ struct writer final : visitor_ if (num_idempotent) { INT num = highbit | INT(num_idempotent); - do_visit(num, f); + visit(num, f); } - do_visit(a, f); + visit(a, f); i += num_idempotent; fm_debug_assert(i <= TILE_COUNT); @@ -574,8 +557,9 @@ struct writer final : visitor_ { static_assert(null == 127 && highbit == 128); static_assert(null == 0x7fffffff && highbit == 0x80000000); - do_visit(chunk_magic, f); - do_visit(c.coord(), f); + auto magic = chunk_magic; + visit(magic, f); + visit(c.coord(), f); for (uint32_t i = 0; i < TILE_COUNT; i++) serialize_tile_([&](uint32_t index) { return maybe_intern_atlas(c[index].ground_atlas(), atlas_type::ground); @@ -626,9 +610,9 @@ struct writer final : visitor_ auto nstrings = (uint32_t)string_array.size(), natlases = (uint32_t)atlas_array.size(), nchunks = (uint32_t)chunk_array.size(); - do_visit(nstrings, f); - do_visit(natlases, f); - do_visit(nchunks, f); + visit(nstrings, f); + visit(natlases, f); + visit(nchunks, f); } void serialize_strings_() @@ -691,7 +675,7 @@ void my_fwrite(FILE_raii& f, const buffer& buf, char(&errbuf)[128]) fm_abort("fwrite: %s", get_error_string(errbuf, error).data()); } -const visitor_::proto_t writer::fake_proto = proto_version; +const proto_t writer::fake_proto = proto_version; } // namespace @@ -751,8 +735,10 @@ template<> struct atlas_from_type { using Type = wall_atlas; } template<> struct atlas_from_type { using Type = anim_atlas; }; template<> struct atlas_from_type { using Type = anim_atlas; }; -struct reader final : visitor_ +struct reader final : visitor_ { + using visitor_::visit; + struct atlas_pair { void* atlas; @@ -770,8 +756,6 @@ struct reader final : visitor_ reader(class world& w, loader_policy asset_policy) : visitor_{PROTO = (proto_t)-1}, w{w}, asset_policy{asset_policy} {} - using visitor_::visit; - struct byte_reader { binary_reader& s; @@ -821,31 +805,39 @@ struct reader final : visitor_ } template - void visit(std::shared_ptr& obj, F&& f, chunk_coords_ ch) + void read_object(std::shared_ptr& obj, F&& f) { + fm_assert(!obj); + object_id id = 0; + object_type type = object_type::none; + local_coords tile; + + object_header_s s{ + .id = id, + .type = type, + .tile = tile, + }; - object_header_s s{}; - visit_object_header(*obj, s, f); - zzz; + object_proto p_o; + visit_object_header(p_o, s, f); - switch (type) + switch (p_o.type) { - default: fm_throw("invalid object type {}"_cf, type_); case object_type::none: case object_type::COUNT: break; - case object_type::light: - obj = w.make_unconnected_object(); break; - case object_type::critter: - obj = w.make_unconnected_object(); break; - case object_type::scenery: - obj = w.make_unconnected_object(); break; + case object_type::critter: { + critter_proto p_c; + static_cast(p_c) = p_o; + obj = w.make_object<>(); + goto ok; } + } + fm_throw("invalid sc_type {}"_cf, (int)p_o.type); - if (PROTO >= 21) [[likely]] +ok: if (PROTO >= 21) [[likely]] fm_soft_assert(object_counter >= id); - - if (PROTO == 20) [[unlikely]] + else if (PROTO == 20) [[unlikely]] object_counter = Math::max(object_counter, id); } @@ -960,7 +952,7 @@ struct reader final : visitor_ void deserialize_objects_(chunk& c, byte_reader& r) { uint32_t count; - do_visit(count, r); + visit(count, r); for (uint32_t i = 0; i < count; i++) { @@ -976,7 +968,7 @@ struct reader final : visitor_ auto ch = c.coord(); auto pos = obj->coord.local(); auto coord = global_coords { ch, pos }; - w.do_make_object(obj, coord, false); + w.do_make_object(obj, , false); } c.sort_objects(); @@ -992,7 +984,7 @@ struct reader final : visitor_ fm_soft_assert(magic == chunk_magic); chunk_coords_ coord; - do_visit(coord, r); + visit(coord, r); auto& c = w[coord]; for (uint32_t i = 0; i < TILE_COUNT; i++) -- cgit v1.2.3