summaryrefslogtreecommitdiffhomepage
path: root/serialize
diff options
context:
space:
mode:
authorStanislaw Halik <sthalik@misaki.pl>2024-04-13 12:26:26 +0200
committerStanislaw Halik <sthalik@misaki.pl>2024-04-13 12:26:26 +0200
commitcb13eb86db3593e723ce06c48a5cb2c94505d6ae (patch)
tree9b56825b1debc908dc999feace69645eb56eb2f8 /serialize
parent2c042d30d96827941e5052d4eca0cc03965cacc8 (diff)
use inheritance for scenery, not std::variant
It's still WIP because creating scenery has to branch on all subtypes. This needs to be taken care of generically in `world::make_object()`.
Diffstat (limited to 'serialize')
-rw-r--r--serialize/old-savegame.cpp29
-rw-r--r--serialize/savegame.cpp56
2 files changed, 55 insertions, 30 deletions
diff --git a/serialize/old-savegame.cpp b/serialize/old-savegame.cpp
index 46b83590..31136798 100644
--- a/serialize/old-savegame.cpp
+++ b/serialize/old-savegame.cpp
@@ -186,7 +186,7 @@ bool read_object_flags(binary_reader<T>& s, U& e)
}
else if constexpr(tag == object_type::critter)
{
- e.playable = !!(flags & 1 << 2);
+ e.playable = !!(flags & 1 << 2);
}
else
{
@@ -355,7 +355,7 @@ void reader_state::read_chunks(reader_t& s)
}
uint32_t object_count = 0;
if (PROTO >= 8) [[likely]]
- object_count << s;
+ object_count << s;
SET_CHUNK_SIZE();
@@ -482,6 +482,7 @@ void reader_state::read_chunks(reader_t& s)
uint16_t delta_; delta_ << s;
sc.delta = uint32_t(sc.delta) * 65536u;
}
+ _world->make_object<generic_scenery, false>(oid, {ch, local}, *val, sc);
}
else if (const auto* val = std::get_if<door_scenery_proto>(&sc.subtype))
{
@@ -490,10 +491,11 @@ void reader_state::read_chunks(reader_t& s)
uint16_t delta_; delta_ << s;
sc.delta = uint32_t(sc.delta) * 65536u;
}
+ _world->make_object<door_scenery, false>(oid, {ch, local}, *val, sc);
}
+ else
+ fm_soft_assert(false);
}
- auto e = _world->make_object<scenery, false>(oid, {ch, local}, sc);
- (void)e;
break;
}
case object_type::light: {
@@ -564,10 +566,12 @@ void reader_state::read_old_scenery(reader_t& s, chunk_coords_ ch, size_t i)
atlasid id; id << s;
const bool exact = id & meta_short_scenery_bit_;
const auto r = rotation(id >> sizeof(id)*8-1-rotation_BITS & rotation_MASK);
+ const global_coords coord{ch, local_coords{i}};
id &= ~scenery_id_flag_mask_;
auto sc = lookup_scenery(id);
- (void)sc.atlas->group(r);
sc.r = r;
+ (void)sc.atlas->group(r);
+
if (!exact)
{
if (read_object_flags(s, sc))
@@ -589,6 +593,7 @@ void reader_state::read_old_scenery(reader_t& s, chunk_coords_ ch, size_t i)
sc.bbox_offset[0] << s;
sc.bbox_offset[1] << s;
}
+
if (auto* val = std::get_if<generic_scenery_proto>(&sc.subtype))
{
if (val->active)
@@ -625,10 +630,18 @@ void reader_state::read_old_scenery(reader_t& s, chunk_coords_ ch, size_t i)
}
}
}
+ else
+ fm_soft_assert(false);
+ }
+ else
+ {
+ if (auto* val = std::get_if<generic_scenery_proto>(&sc.subtype))
+ auto e = _world->make_object<generic_scenery, false>(_world->make_id(), coord, *val, sc);
+ else if (auto* val = std::get_if<door_scenery_proto>(&sc.subtype))
+ auto e = _world->make_object<door_scenery, false>(_world->make_id(), coord, *val, sc);
+ else
+ fm_soft_assert(false);
}
- global_coords coord{ch, local_coords{i}};
- auto e = _world->make_object<scenery, false>(_world->make_id(), coord, sc);
- (void)e;
}
void reader_state::deserialize_world(ArrayView<const char> buf, proto_t proto)
diff --git a/serialize/savegame.cpp b/serialize/savegame.cpp
index b152fb31..4bc1c7ad 100644
--- a/serialize/savegame.cpp
+++ b/serialize/savegame.cpp
@@ -412,12 +412,16 @@ struct writer final : visitor_<writer, true>
template<typename F> void write_scenery_proto(const scenery& obj, F&& f) // todo! replace scenery::subtype with inheritance!
{
auto sc_type = obj.scenery_type();
- fm_debug_assert(sc_type != scenery_type::none);
+ fm_debug_assert(sc_type != scenery_type::none && sc_type < scenery_type::COUNT);
visit(sc_type, f);
- std::visit(
- [&](auto& subtype) { visit_scenery_proto(subtype, f); },
- obj.subtype
- );
+ switch (sc_type)
+ {
+ case scenery_type::generic: visit_scenery_proto(static_cast<const generic_scenery&>(obj), f); break;
+ case scenery_type::door: visit_scenery_proto(static_cast<const door_scenery&>(obj), f); break;
+ case scenery_type::none:
+ case scenery_type::COUNT:
+ std::unreachable();
+ }
}
template<typename F> void write_object(o_object& obj, chunk* c, F&& f)
@@ -815,10 +819,16 @@ struct reader final : visitor_<reader, false>
}
}
- template<typename F> void visit_object_proto(o_scenery& obj, std::nullptr_t, F&& f)
+ template<typename F>
+ void read_scenery(std::shared_ptr<scenery>& ret, const object_proto& pʹ, const object_header_s& h, F&& f)
{
+ const auto coord = global_coords{h.ch->coord(), h.tile};
auto sc_type = scenery_type::none;
visit(sc_type, f);
+
+ scenery_proto sc;
+ static_cast<object_proto&>(sc) = pʹ;
+
switch (sc_type)
{
case scenery_type::none:
@@ -827,19 +837,20 @@ struct reader final : visitor_<reader, false>
case scenery_type::generic: {
generic_scenery_proto p;
visit_scenery_proto(p, f);
- obj.subtype = move(p);
- goto ok;
+ sc.subtype = move(p); // todo! extract into make_scenery()
+ ret = w.make_object<generic_scenery>(h.id, coord, move(p), move(sc));
+ return;
}
case scenery_type::door: {
door_scenery_proto p;
visit_scenery_proto(p, f);
- obj.subtype = move(p);
- goto ok;
+ sc.subtype = move(p);
+ ret = w.make_object<door_scenery>(h.id, coord, move(p), move(sc));
+ return;
}
}
+
fm_throw("invalid sc_type {}"_cf, (int)sc_type);
-ok:
- void();
}
template<typename Obj, typename Proto, typename Header>
@@ -856,7 +867,7 @@ ok:
return w.make_object<Obj>(h0.id, coord, move(p));
}
- template<typename F> [[nodiscard]] std::shared_ptr<object> read_object(chunk* ch, F&& f)
+ template<typename F> void read_object(chunk* ch, F&& f)
{
std::shared_ptr<object> obj;
object_id id = 0;
@@ -870,8 +881,8 @@ ok:
.tile = tile,
};
- object_proto pʹ;
- visit_object_header(pʹ, s, f);
+ object_proto p;
+ visit_object_header(p, s, f);
switch (type)
{
@@ -883,17 +894,20 @@ ok:
critter_header_s h{
.offset_frac = offset_frac,
};
- obj = make_object<critter, critter_proto, critter_header_s>(s, move(pʹ), move(h), f);
+ obj = make_object<critter, critter_proto, critter_header_s>(s, move(p), move(h), f);
goto ok;
}
case object_type::light:
- obj = make_object<light, light_proto, std::nullptr_t>(s, move(pʹ), {}, f);
+ obj = make_object<light, light_proto, std::nullptr_t>(s, move(p), {}, f);
goto ok;
- case object_type::scenery:
- obj = make_object<scenery, scenery_proto, std::nullptr_t>(s, move(pʹ), {}, f);
+ case object_type::scenery: {
+ std::shared_ptr<scenery> objʹ;
+ read_scenery(objʹ, move(p), s, f);
+ obj = move(objʹ);
goto ok;
}
- fm_throw("invalid sc_type {}"_cf, (int)type);
+ }
+ fm_throw("invalid object_type {}"_cf, (int)type);
ok:
fm_assert(obj);
fm_debug_assert(obj->c == ch);
@@ -905,8 +919,6 @@ ok:
fm_soft_assert(object_counter >= id);
else if (PROTO == 20) [[unlikely]]
object_counter = Math::max(object_counter, id);
-
- return obj;
}
bool deserialize_header_(binary_reader<const char*>& s, ArrayView<const char> buf)