summaryrefslogtreecommitdiffhomepage
path: root/serialize
diff options
context:
space:
mode:
authorStanislaw Halik <sthalik@misaki.pl>2024-01-23 15:11:26 +0100
committerStanislaw Halik <sthalik@misaki.pl>2024-01-23 15:11:26 +0100
commitc554cdbc0cf894ccc6c330e0743649a4bdb34658 (patch)
tree80b5fa2e64136eb2740d9c9524daf92b8a447b3d /serialize
parent573f8f2bcbfd86119e00a13fedc5abf2bf7deafb (diff)
a
Diffstat (limited to 'serialize')
-rw-r--r--serialize/old-savegame.cpp49
-rw-r--r--serialize/savegame.cpp67
-rw-r--r--serialize/scenery.cpp51
3 files changed, 123 insertions, 44 deletions
diff --git a/serialize/old-savegame.cpp b/serialize/old-savegame.cpp
index d63447a4..8a050022 100644
--- a/serialize/old-savegame.cpp
+++ b/serialize/old-savegame.cpp
@@ -171,9 +171,17 @@ bool read_object_flags(binary_reader<T>& s, U& e)
fm_throw("invalid object type '{}'"_cf, (int)e.type);
if constexpr(tag == object_type::scenery)
{
- e.active = !!(flags & 1 << 2);
- e.closing = !!(flags & 1 << 3);
- e.interactive = !!(flags & 1 << 4);
+ if (auto* val = std::get_if<generic_scenery_proto>(&e.subtype))
+ {
+ val->active = !!(flags & 1 << 2);
+ val->interactive = !!(flags & 1 << 4);
+ }
+ else if (auto* val = std::get_if<door_scenery_proto>(&e.subtype))
+ {
+ val->active = !!(flags & 1 << 2);
+ val->closing = !!(flags & 1 << 3);
+ val->interactive = !!(flags & 1 << 4);
+ }
}
else if constexpr(tag == object_type::critter)
{
@@ -461,8 +469,16 @@ void reader_state::read_chunks(reader_t& s)
s >> sc.offset[1];
}
read_bbox(s, sc);
- if (sc.active)
- sc.delta << s;
+ if (const auto* val = std::get_if<generic_scenery_proto>(&sc.subtype))
+ {
+ if (val->active)
+ sc.delta << s;
+ }
+ else if (const auto* val = std::get_if<door_scenery_proto>(&sc.subtype))
+ {
+ if (val->active)
+ sc.delta << s;
+ }
}
auto e = _world->make_object<scenery, false>(oid, {ch, local}, sc);
(void)e;
@@ -561,12 +577,25 @@ 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 (sc.active)
+ if (auto* val = std::get_if<generic_scenery_proto>(&sc.subtype))
{
- if (PROTO >= 4) [[likely]]
- sc.delta << s;
- else
- sc.delta = (uint16_t)Math::clamp(int(s.read<float>() * 65535), 0, 65535);
+ if (val->active)
+ {
+ if (PROTO >= 4) [[likely]]
+ sc.delta << s;
+ else
+ sc.delta = (uint16_t)Math::clamp(int(s.read<float>() * 65535), 0, 65535);
+ }
+ }
+ else if (auto* val = std::get_if<door_scenery_proto>(&sc.subtype))
+ {
+ if (val->active)
+ {
+ if (PROTO >= 4) [[likely]]
+ sc.delta << s;
+ else
+ sc.delta = (uint16_t)Math::clamp(int(s.read<float>() * 65535), 0, 65535);
+ }
}
}
global_coords coord{ch, local_coords{i}};
diff --git a/serialize/savegame.cpp b/serialize/savegame.cpp
index e7d24195..a71118e8 100644
--- a/serialize/savegame.cpp
+++ b/serialize/savegame.cpp
@@ -148,7 +148,6 @@ struct visitor_
break;
case object_type::scenery:
case object_type::critter:
- case object_type::door_new:
static_cast<Derived&>(*this).visit(non_const(obj.atlas), atlas_type::anim, f);
break;
case object_type::none:
@@ -172,11 +171,9 @@ struct visitor_
switch (type)
{
- case object_type::door_new: fm_assert(false && "todo");
case object_type::critter: do_visit(static_cast<critter&>(obj), f); return;
case object_type::scenery: do_visit(static_cast<scenery&>(obj), f); return;
case object_type::light: do_visit(static_cast<light&>(obj), f); return;
- //case object_type::door: do_visit(static_cast<door&>(obj), f); return;
case object_type::COUNT:
case object_type::none:
break;
@@ -224,37 +221,71 @@ struct visitor_
setter(obj, flags & bits);
}
- template<typename F> void visit(scenery& obj, F&& f)
+ template<typename F> void visit(generic_scenery& s, F&& f)
{
- auto sc_type = obj.sc_type;
- do_visit(sc_type, f);
- obj.sc_type = sc_type;
+ constexpr struct {
+ uint8_t bits;
+ bool(*getter)(const generic_scenery&);
+ void(*setter)(generic_scenery&, bool);
+ } pairs[] = {
+ { 1 << 0,
+ [](const auto& sc) { return !!sc.active; },
+ [](auto& sc, bool value) { sc.active = value; }
+ },
+ { 1 << 2,
+ [](const auto& sc) { return !!sc.interactive; },
+ [](auto& sc, bool value) { sc.interactive = value; }
+ },
+ };
+ uint8_t flags = 0;
+ for (auto [bits, getter, setter] : pairs)
+ flags |= bits * getter(s);
+ do_visit(flags, f);
+ for (auto [bits, getter, setter] : pairs)
+ setter(s, flags & bits);
+ }
+
+ template<typename F> void visit(door_scenery& s, F&& f)
+ {
constexpr struct {
uint8_t bits;
- bool(*getter)(const scenery&);
- void(*setter)(scenery&, bool);
+ bool(*getter)(const door_scenery&);
+ void(*setter)(door_scenery&, bool);
} pairs[] = {
{ 1 << 0,
- [](const scenery& sc) { return !!sc.active; },
- [](scenery& sc, bool value) { sc.active = value; }
+ [](const auto& sc) { return !!sc.active; },
+ [](auto& sc, bool value) { sc.active = value; }
},
{ 1 << 1,
- [](const scenery& sc) { return !!sc.closing; },
- [](scenery& sc, bool value) { sc.closing = value; }
+ [](const auto& sc) { return !!sc.closing; },
+ [](auto& sc, bool value) { sc.closing = value; }
},
{ 1 << 2,
- [](const scenery& sc) { return !!sc.interactive; },
- [](scenery& sc, bool value) { sc.interactive = value; }
+ [](const auto& sc) { return !!sc.interactive; },
+ [](auto& sc, bool value) { sc.interactive = value; }
},
};
uint8_t flags = 0;
for (auto [bits, getter, setter] : pairs)
- flags |= bits * getter(obj);
+ flags |= bits * getter(s);
do_visit(flags, f);
for (auto [bits, getter, setter] : pairs)
- setter(obj, flags & bits);
+ setter(s, flags & bits);
+ }
+
+ template<typename F> void visit(scenery& obj, 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);
+
+ std::visit(
+ [&]<typename T>(T& x) { return do_visit(x, f); },
+ obj.subtype
+ );
}
template<typename F> void visit(light& obj, F&& f)
@@ -738,8 +769,6 @@ struct reader final : visitor_<reader>
case object_type::none:
case object_type::COUNT:
break;
- case object_type::door_new:
- fm_assert(false && "todo");
case object_type::light:
obj = w.make_unconnected_object<light>(); goto ok;
case object_type::critter:
diff --git a/serialize/scenery.cpp b/serialize/scenery.cpp
index 41b99218..158b4773 100644
--- a/serialize/scenery.cpp
+++ b/serialize/scenery.cpp
@@ -84,6 +84,8 @@ void adl_serializer<scenery_proto>::to_json(json& j, const scenery_proto& f)
{
fm_assert(f.atlas);
const scenery_proto default_scenery;
+ const generic_scenery_proto default_generic_scenery;
+ const door_scenery_proto default_door_scenery;
if (f.type != default_scenery.type)
j["type"] = f.type;
j["atlas-name"] = f.atlas->name();
@@ -93,10 +95,22 @@ void adl_serializer<scenery_proto>::to_json(json& j, const scenery_proto& f)
j["rotation"] = f.r;
if (f.pass != default_scenery.pass)
j["pass-mode"] = f.pass;
- if (f.active != default_scenery.active)
- j["active"] = f.active;
- if (f.interactive != default_scenery.interactive)
- j["interactive"] = f.interactive;
+ std::visit(overloaded {
+ [&](const generic_scenery_proto& x) {
+ if (x.active != default_generic_scenery.active)
+ j["active"] = x.active;
+ if (x.interactive != default_generic_scenery.interactive)
+ j["interactive"] = x.interactive;
+ },
+ [&](const door_scenery_proto& x) {
+ if (x.active != default_door_scenery.active)
+ j["active"] = x.active;
+ if (x.interactive != default_door_scenery.interactive)
+ j["interactive"] = x.interactive;
+ if (x.closing != default_door_scenery.closing)
+ j["closing"] = x.closing;
+ },
+ }, f.subtype);
if (f.offset != default_scenery.offset)
j["offset"] = Vector2i(f.offset);
if (f.bbox_offset != default_scenery.bbox_offset)
@@ -114,17 +128,19 @@ void adl_serializer<scenery_proto>::from_json(const json& j, scenery_proto& f)
value = j[s];
};
+ const generic_scenery_proto G;
+ const door_scenery_proto D;
+
StringView atlas_name = j["atlas-name"];
fm_soft_assert(!atlas_name.isEmpty());
f = {};
f.atlas = loader.anim_atlas(atlas_name, loader_::SCENERY_PATH);
-
auto type = scenery_type::generic; get("type", type);
auto frame = f.frame; get("frame", frame);
auto r = f.atlas->first_rotation(); get("rotation", r);
pass_mode pass = f.pass; get("pass-mode", pass);
- bool active = f.active; get("active", active);
- bool interactive = f.interactive; get("interactive", interactive);
+ bool active = G.active; get("active", active);
+ bool interactive = G.interactive; get("interactive", interactive);
auto offset = Vector2i(f.offset); get("offset", offset);
auto bbox_offset = Vector2i(f.bbox_offset); get("bbox-offset", bbox_offset);
auto bbox_size = Vector2ui(f.bbox_size); get("bbox-size", bbox_size);
@@ -136,32 +152,37 @@ void adl_serializer<scenery_proto>::from_json(const json& j, scenery_proto& f)
{
default:
fm_throw("unhandled scenery type '{}'"_cf, (unsigned)type);
- case scenery_type::generic:
+ case scenery_type::generic: {
+ auto s = generic_scenery_proto{};
f.type = object_type::scenery;
- f.sc_type = scenery_type::generic;
f.r = r;
f.frame = frame;
f.pass = pass;
- f.active = active;
- f.interactive = interactive;
+ s.active = active;
+ s.interactive = interactive;
f.offset = Vector2b(offset);
f.bbox_offset = Vector2b(bbox_offset);
f.bbox_size = Vector2ub(bbox_size);
+ f.subtype = s;
break;
- case scenery_type::door:
+ }
+ case scenery_type::door: {
fm_assert(f.atlas->info().fps > 0 && f.atlas->info().nframes > 0);
+ auto s = door_scenery_proto{};
f.type = object_type::scenery;
- f.sc_type = scenery_type::door;
f.r = r;
f.frame = uint16_t(f.atlas->group(r).frames.size()-1);
f.pass = pass_mode::blocked;
- f.interactive = true;
- f.closing = false;
+ s.active = false;
+ s.interactive = true;
+ s.closing = false;
f.offset = Vector2b(offset);
f.bbox_offset = Vector2b(bbox_offset);
f.bbox_size = Vector2ub(bbox_size);
+ f.subtype = s;
break;
}
+ }
}
void adl_serializer<serialized_scenery>::to_json(json& j, const serialized_scenery& val)