summaryrefslogtreecommitdiffhomepage
path: root/serialize/savegame.cpp
diff options
context:
space:
mode:
authorStanislaw Halik <sthalik@misaki.pl>2024-04-09 01:37:57 +0200
committerStanislaw Halik <sthalik@misaki.pl>2024-04-09 01:37:57 +0200
commit250e0817fedc6e9337debe07bf64a19bd7e0baa8 (patch)
tree84a215affadc135f2bedc70268701bcf6b248b84 /serialize/savegame.cpp
parenteea5eafd6a004a2d7242c46646c98701e7fc0af2 (diff)
w
Diffstat (limited to 'serialize/savegame.cpp')
-rw-r--r--serialize/savegame.cpp276
1 files changed, 134 insertions, 142 deletions
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<typename Derived>
+using proto_t = uint16_t;
+
+template<typename Derived, bool IsWriter_>
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<typename T, typename F>
- [[deprecated]]
- CORRADE_ALWAYS_INLINE void do_visit(T&& value, F&& fun) // todo! remove it
- {
- static_cast<Derived&>(*this).visit(value, fun);
- }
+ template<typename T, typename U> using qual2 = std::__conditional_t<IsWriter, const T, U>;
+ template<typename T> using qual = std::__conditional_t<IsWriter, const T, T>;
+
+ using o_object = qual2<object, object_proto>;
+ using o_critter = qual2<critter, critter_proto>;
+ using o_scenery = qual2<scenery, scenery_proto>;
+ using o_light = qual2<light, light_proto>;
+ using o_sc_g = qual2<generic_scenery, generic_scenery_proto>;
+ using o_sc_door = qual2<door_scenery, door_scenery_proto>;
template<typename T, typename F>
requires (std::is_arithmetic_v<T> && std::is_fundamental_v<T>)
- static void visit(T& x, F&& f)
- {
- f(x);
- }
+ static void visit(qual<T>& x, F&& f) { f(x); }
template<typename T, size_t N, typename F>
- void visit(Math::Vector<N, T>& x, F&& f)
+ void visit(qual<Math::Vector<N, T>>& x, F&& f)
{
for (uint32_t i = 0; i < N; i++)
- do_visit(x.data()[i], f);
+ self.visit(x.data()[i], f);
}
template<typename E, typename F>
requires std::is_enum_v<E>
- void visit(E& x, F&& f)
+ void visit(qual<E>& x, F&& f)
{
- auto* ptr = const_cast<std::underlying_type_t<E>*>(reinterpret_cast<const std::underlying_type_t<E>*>(&x));
- visit(*ptr, f);
+ using U = std::underlying_type_t<E>;
+ qual<U>& ptr = const_cast<U*>(reinterpret_cast<const U*>(&x));
+ visit(ptr, f);
}
- template<typename F>
- void visit_object_header(object_proto& obj, object_header_s& s, F&& f)
+ template<typename F, typename T>
+ 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<Derived&>(*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<Derived&>(*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<typename F> static void visit(chunk_coords_& coord, F&& f)
+ template<typename F> static void visit(qual<chunk_coords_>& coord, F&& f)
{
f(coord.x);
f(coord.y);
@@ -220,59 +223,19 @@ struct visitor_
flag_playable = 1 << 0,
};
-
- template<typename F>
- 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<uint16_t, decltype(critter::offset_frac_)>);
- 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<typename F> void visit(generic_scenery_proto& s, F&& f)
+ template<typename F, typename T>
+ 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<typename F> void visit(door_scenery& s, F&& f)
+ template<typename F, typename T>
+ 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<typename F> void visit(scenery& obj, F&& f)
+ template<typename F, typename T>
+ 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(
- [&]<typename T>(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<typename F> void visit(light& obj, F&& f)
+ template<typename F, typename T>
+ 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_<writer>
+struct writer final : visitor_<writer, true>
{
+ using visitor_<writer, true>::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_<writer>
chunk* c;
};
+ const world& w;
+
std::vector<StringView> string_array{};
tsl::robin_map<StringView, uint32_t, string_hasher> string_map{hash_initial_size};
@@ -419,8 +373,6 @@ struct writer final : visitor_<writer>
}
};
- using visitor_<writer>::visit;
-
template<typename F>
void visit(std::shared_ptr<anim_atlas>& a, atlas_type type, F&& f)
{
@@ -439,10 +391,40 @@ struct writer final : visitor_<writer>
}
template<typename F>
- 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<typename F>
+ 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<const critter&>(obj), f); goto ok;
+ case object_type::light: visit_object_proto(static_cast<const light&>(obj), f); goto ok;
+ case object_type::scenery: write_scenery(static_cast<const scenery&>(obj), f); goto ok;
+ }
+ fm_assert(false);
+ok: void();
}
template<typename F>
@@ -533,7 +515,8 @@ struct writer final : visitor_<writer>
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_<writer>
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_<writer>
{
static_assert(null<uint8_t> == 127 && highbit<uint8_t> == 128);
static_assert(null<uint32_t> == 0x7fffffff && highbit<uint32_t> == 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_<writer>
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_<writer>::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<atlas_type::wall> { using Type = wall_atlas; }
template<> struct atlas_from_type<atlas_type::anim> { using Type = anim_atlas; };
template<> struct atlas_from_type<atlas_type::vobj> { using Type = anim_atlas; };
-struct reader final : visitor_<reader>
+struct reader final : visitor_<reader, false>
{
+ using visitor_<reader, false>::visit;
+
struct atlas_pair
{
void* atlas;
@@ -770,8 +756,6 @@ struct reader final : visitor_<reader>
reader(class world& w, loader_policy asset_policy) : visitor_{PROTO = (proto_t)-1}, w{w}, asset_policy{asset_policy} {}
- using visitor_<reader>::visit;
-
struct byte_reader
{
binary_reader<const char*>& s;
@@ -821,31 +805,39 @@ struct reader final : visitor_<reader>
}
template<typename F>
- void visit(std::shared_ptr<object>& obj, F&& f, chunk_coords_ ch)
+ void read_object(std::shared_ptr<object>& 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<light>(); break;
- case object_type::critter:
- obj = w.make_unconnected_object<critter>(); break;
- case object_type::scenery:
- obj = w.make_unconnected_object<scenery>(); break;
+ case object_type::critter: {
+ critter_proto p_c;
+ static_cast<object_proto&>(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_<reader>
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_<reader>
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_<reader>
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++)