diff options
author | Stanislaw Halik <sthalik@misaki.pl> | 2024-01-20 19:10:38 +0100 |
---|---|---|
committer | Stanislaw Halik <sthalik@misaki.pl> | 2024-01-20 19:10:38 +0100 |
commit | 214dc62745acde41b5180a3dc7eef4d51c5c9548 (patch) | |
tree | 3a704910aeb02e7483fab164e08feb477577cb30 | |
parent | c1b6ef1161af8afc2900880bdbec04c51f64a179 (diff) |
w
-rw-r--r-- | serialize/savegame.cpp | 6 | ||||
-rw-r--r-- | serialize/world-reader.cpp | 571 |
2 files changed, 6 insertions, 571 deletions
diff --git a/serialize/savegame.cpp b/serialize/savegame.cpp index 5eee17f2..beb319db 100644 --- a/serialize/savegame.cpp +++ b/serialize/savegame.cpp @@ -527,4 +527,10 @@ void world::serialize(StringView filename) } } +class world world::deserialize(StringView filename) +{ + (void)filename; + fm_assert("todo" && false); +} + } // namespace floormat diff --git a/serialize/world-reader.cpp b/serialize/world-reader.cpp deleted file mode 100644 index a4f33b94..00000000 --- a/serialize/world-reader.cpp +++ /dev/null @@ -1,571 +0,0 @@ -#include "compat/assert.hpp" -#include "src/world.hpp" -#include <Corrade/Containers/StringView.h> -#if 0 -#include "binary-reader.inl" -#include "src/scenery.hpp" -#include "src/critter.hpp" -#include "src/light.hpp" -#include "loader/loader.hpp" -#include "loader/scenery.hpp" -#include "src/ground-atlas.hpp" -#include "src/anim-atlas.hpp" -#include "src/chunk-scenery.hpp" -#include "compat/strerror.hpp" -#include <cerrno> -#include <cstring> -#include <memory> -#include <vector> - -namespace { - -using namespace floormat; -using namespace floormat::Serialize; - -constexpr inline atlasid meta_short_scenery_bit_ = highbits<atlasid, 1, 0>; -constexpr inline atlasid meta_rotation_bits_ = highbits<atlasid, rotation_BITS, 1>; -constexpr inline atlasid scenery_id_flag_mask_ = meta_short_scenery_bit_ | meta_rotation_bits_; -constexpr inline atlasid scenery_id_max_ = int_traits<atlasid>::max & ~scenery_id_flag_mask_; - -struct reader_state final { - explicit reader_state(world& world) noexcept; - void deserialize_world(ArrayView<const char> buf); - -private: - using reader_t = binary_reader<decltype(ArrayView<const char>{}.cbegin())>; - - StringView lookup_atlas(atlasid id); - const scenery_proto& lookup_scenery(atlasid id); - StringView lookup_string(uint32_t idx); - void read_atlases(reader_t& reader); - void read_sceneries(reader_t& reader); - void read_strings(reader_t& reader); - void read_chunks(reader_t& reader); - void read_old_scenery(reader_t& s, chunk_coords_ ch, size_t i); - void preload_chunks(); - - std::vector<String> strings; - std::vector<scenery_proto> sceneries; - std::vector<String> atlases; - world* _world; - uint16_t PROTO = proto_version; - - Array<chunk::object_draw_order> draw_array; - Array<std::array<chunk::vertex, 4>> draw_vertexes; - Array<std::array<UnsignedShort, 6>> draw_indexes; -}; - -reader_state::reader_state(world& world) noexcept : _world{&world} {} - -void reader_state::read_atlases(reader_t& s) -{ - const auto N = s.read<atlasid>(); - atlases.reserve(N); - for (atlasid i = 0; i < N; i++) - { - Vector2ub size; - size[0] << s; - size[1] << s; - const auto& [buf, len] = s.read_asciiz_string<atlas_name_max>(); - atlases.push_back({buf, len}); - } -} - -template<typename T, object_subtype U> -bool read_object_flags(binary_reader<T>& s, U& e) -{ - constexpr auto tag = object_type_<U>::value; - uint8_t flags; flags << s; - e.pass = pass_mode(flags & pass_mask); - if (e.type != tag) - fm_throw("invalid object type '{}'"_cf, (int)e.type); - if constexpr(tag == object_type::generic_scenery) - { - e.active = !!(flags & 1 << 2); - e.interactive = !!(flags & 1 << 4); - } - else if constexpr(tag == object_type::door) - { - e.active = !!(flags & 1 << 2); - e.closing = !!(flags & 1 << 3); - e.interactive = !!(flags & 1 << 4); - } - else if constexpr(tag == object_type::critter) - { - e.playable = !!(flags & 1 << 2); - } - else - { - static_assert(tag == object_type::none); - static_assert(tag != object_type::none); - } - return flags & 1 << 7; -} - -void reader_state::read_sceneries(reader_t& s) -{ - (void)loader.sceneries(); - - uint16_t magic; magic << s; - if (magic != scenery_magic) - fm_throw("bad scenery magic"_cf); - atlasid sz; sz << s; - fm_soft_assert(sz < scenery_id_max_); - sceneries.resize(sz); - - auto i = 0uz; - while (i < sz) - { - uint8_t num; num << s; - fm_soft_assert(num > 0); - auto str = s.read_asciiz_string<atlas_name_max>(); - auto sc = loader.scenery(str); - for (auto n = 0uz; n < num; n++) - { - atlasid id; id << s; - fm_soft_assert(id < sz); - fm_soft_assert(!sceneries[id]); - bool short_frame = read_object_flags(s, sc); - fm_debug_assert(sc.atlas != nullptr); - if (short_frame) - sc.frame = s.read<uint8_t>(); - else - sc.frame << s; - fm_soft_assert(sc.frame < sc.atlas->info().nframes); - sceneries[id] = sc; - } - i += num; - } - fm_soft_assert(i == sz); -} - -void reader_state::read_strings(reader_t& s) -{ - uint32_t size; size << s; - strings.reserve(size); - for (auto i = 0uz; i < size; i++) - { - auto str = s.read_asciiz_string<string_max>(); - strings.emplace_back(StringView{str}); - } -} - -StringView reader_state::lookup_atlas(atlasid id) -{ - if (id < atlases.size()) - return atlases[id]; - else - fm_throw("no such atlas: '{}'"_cf, id); -} - -const scenery_proto& reader_state::lookup_scenery(atlasid id) -{ - if (id < sceneries.size()) - return sceneries[id]; - else - fm_throw("no such scenery: '{}'"_cf, id); -} - -StringView reader_state::lookup_string(uint32_t idx) -{ - fm_soft_assert(idx < strings.size()); - return strings[idx]; -} - -#ifndef FM_NO_DEBUG -# define SET_CHUNK_SIZE() do { nbytes_read = s.bytes_read() - nbytes_start; } while (false) -#else -# define SET_CHUNK_SIZE() void() -#endif - -void reader_state::read_chunks(reader_t& s) -{ - Array<typename chunk::object_draw_order> array; - const auto N = s.read<chunksiz>(); -#ifndef FM_NO_DEBUG - [[maybe_unused]] size_t nbytes_read = 0; -#endif - - for (auto k = 0uz; k < N; k++) - { - const auto nbytes_start = s.bytes_read(); - - std::decay_t<decltype(chunk_magic)> magic; - magic << s; - if (magic != chunk_magic) - fm_throw("bad chunk magic"_cf); - chunk_coords_ ch; - ch.x << s; - ch.y << s; - if (PROTO >= 10) [[likely]] - ch.z << s; - auto& c = (*_world)[ch]; - c.mark_modified(); - for (auto i = 0uz; i < TILE_COUNT; i++) - { - SET_CHUNK_SIZE(); - const tilemeta flags = s.read<tilemeta>(); - - if (PROTO >= 11) [[likely]] - if (flags & meta_rle) - { - auto j = flags & 0x7fuz; - i += j; - continue; - } - - tile_ref t = c[i]; - using uchar = uint8_t; - const auto make_atlas = [&]<typename T>() -> image_proto_<T> { - atlasid id; - if (PROTO < 8) [[unlikely]] - id = flags & meta_short_atlasid_ ? atlasid{s.read<uchar>()} : s.read<atlasid>(); - else - id << s; - variant_t v; - if (PROTO >= 2) [[likely]] - v << s; - else - v = flags & meta_short_variant_ - ? s.read<uint8_t>() - : uint8_t(s.read<uint16_t>()); - auto name = lookup_atlas(id); - if constexpr(std::is_same_v<ground_atlas, T>) - { - auto atlas = loader.ground_atlas(name, loader_policy::warn); - fm_soft_assert(v < atlas->num_tiles()); - return { atlas, v }; - } - else if (std::is_same_v<wall_atlas, T>) - { - auto atlas = loader.wall_atlas(name, true); - return { atlas, v }; - } - else - std::unreachable(); - }; - SET_CHUNK_SIZE(); - //t.passability() = pass_mode(flags & pass_mask); - if (flags & meta_ground) - t.ground() = make_atlas.operator()<ground_atlas>(); - if (flags & meta_wall_n) - t.wall_north() = make_atlas.operator()<wall_atlas>(); - if (flags & meta_wall_w) - t.wall_west() = make_atlas.operator()<wall_atlas>(); - if (PROTO >= 3 && PROTO < 8) [[unlikely]] - if (flags & meta_scenery_) - read_old_scenery(s, ch, i); - SET_CHUNK_SIZE(); - } - uint32_t object_count = 0; - if (PROTO >= 8) [[likely]] - object_count << s; - - SET_CHUNK_SIZE(); - - for (auto i = 0uz; i < object_count; i++) - { - object_id oid; - object_type type; - if (PROTO >= 18) [[likely]] - { - oid << s; - fm_soft_assert((oid & lowbits<collision_data_BITS, object_id>) == oid); - type = object_type(s.read<std::underlying_type_t<object_type>>()); - fm_soft_assert(type < object_type::COUNT); - } - else - { - object_id _id; _id << s; - oid = _id & lowbits<60, object_id>; - fm_soft_assert(oid != 0); - type = object_type(_id >> 61); - } - const auto local = local_coords{s.read<uint8_t>()}; - - Vector2b offset; - if (PROTO >= 14) [[likely]] - { - offset[0] << s; - offset[1] << s; - } - constexpr auto read_bbox = [](auto& s, auto& e) { - s >> e.bbox_offset[0]; - s >> e.bbox_offset[1]; - s >> e.bbox_size[0]; - s >> e.bbox_size[1]; - }; - SET_CHUNK_SIZE(); - switch (type) - { - case object_type::door { - ...; // todo - } - case object_type::critter: { - critter_proto proto; - proto.offset = offset; - uint8_t id; id << s; - proto.r = rotation(id >> sizeof(id)*8-1-rotation_BITS & rotation_MASK); - if (read_object_flags(s, proto)) - proto.frame = s.read<uint8_t>(); - else - proto.frame << s; - Vector2us offset_frac; - offset_frac[0] << s; - offset_frac[1] << s; - if (PROTO < 17) [[unlikely]] - offset_frac = {}; - const bool exact = id & meta_short_scenery_bit_; - SET_CHUNK_SIZE(); - - if (PROTO >= 9) [[likely]] - { - uint32_t id; id << s; - auto name = lookup_string(id); - fm_soft_assert(name.size() < critter_name_max); - proto.name = name; - } - else - { - auto [buf, len] = s.read_asciiz_string<critter_name_max>(); - auto name = StringView{buf, len}; - proto.name = name; - } - if (!exact) - { - if (PROTO < 14) [[unlikely]] - { - s >> proto.offset[0]; - s >> proto.offset[1]; - } - read_bbox(s, proto); - } - SET_CHUNK_SIZE(); - auto e = _world->make_object<critter, false>(oid, {ch, local}, proto); - e->offset_frac = offset_frac; - (void)e; - break; - } - case object_type::generic_scenery: { - atlasid id; id << s; - bool exact; - rotation r; - if (PROTO >= 19) [[likely]] - { - uint8_t bits; bits << s; - exact = bits & meta_short_scenery_bit; - r = rotation(bits >> sizeof(bits)*8-1-rotation_BITS & rotation_MASK); - } - else - { - exact = id & meta_short_scenery_bit_; - r = rotation(id >> sizeof(id)*8-1-rotation_BITS & rotation_MASK); - id &= ~scenery_id_flag_mask_; - } - auto sc = lookup_scenery(id); - sc.offset = offset; - (void)sc.atlas->group(r); - sc.r = r; - if (!exact) - { - if (read_object_flags(s, sc)) - sc.frame = s.read<uint8_t>(); - else - sc.frame << s; - (void)sc.atlas->frame(sc.r, sc.frame); - if (PROTO < 14) [[unlikely]] - { - s >> sc.offset[0]; - s >> sc.offset[1]; - } - read_bbox(s, sc); - if (sc.active) - sc.delta << s; - } - auto e = _world->make_object<scenery, false>(oid, {ch, local}, sc); - (void)e; - break; - } - case object_type::light: { - light_proto proto; - proto.offset = offset; - - uint8_t flags; flags << s; - const bool exact = flags & 1; - proto.r = rotation((flags >> 1) & lowbits<rotation_BITS>); - bool enabled; - if (PROTO >= 16) [[likely]] - { - proto.falloff = light_falloff((flags >> 4) & lowbits<light_falloff_BITS>); - enabled = (flags >> 7) & 1; - } - else - { - proto.falloff = light_falloff((flags >> 4) & lowbits<2>); - enabled = (flags >> 6) & 1; - } - s >> proto.max_distance; - for (auto i = 0uz; i < 3; i++) - s >> proto.color[i]; - if (PROTO >= 15) [[likely]] - s >> proto.color[3]; - if (!exact) - { - uint16_t frame; frame << s; - auto pass = pass_mode((frame >> 14) & lowbits<2>); - frame &= lowbits<14, uint16_t>; - proto.pass = pass; - proto.frame = frame; - read_bbox(s, proto); - } - SET_CHUNK_SIZE(); - auto L = _world->make_object<light, false>(oid, {ch, local}, proto); - L->enabled = enabled; - (void)L; - break; - } - default: - fm_throw("invalid_object_type '{}'"_cf, (int)type); - } - } - - SET_CHUNK_SIZE(); - fm_assert(c.is_scenery_modified()); - fm_assert(c.is_passability_modified()); - c.sort_objects(); - } -} - -void reader_state::preload_chunks() -{ - for (auto& [coord, _] : _world->chunks()) - { - auto* c = _world->at(coord); - fm_assert(c); - c->ensure_ground_mesh(); - c->ensure_wall_mesh(); - c->ensure_scenery_mesh({ draw_array, draw_vertexes, draw_indexes }); - c->ensure_passability(); - } -} - -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); - id &= ~scenery_id_flag_mask_; - auto sc = lookup_scenery(id); - (void)sc.atlas->group(r); - sc.r = r; - if (!exact) - { - if (read_object_flags(s, sc)) - sc.frame = s.read<uint8_t>(); - else - sc.frame << s; - if (PROTO >= 5) [[likely]] - { - sc.offset[0] << s; - sc.offset[1] << s; - } - if (PROTO >= 6) [[likely]] - { - sc.bbox_size[0] << s; - sc.bbox_size[1] << s; - } - if (PROTO >= 7) [[likely]] - { - sc.bbox_offset[0] << s; - sc.bbox_offset[1] << s; - } - if (sc.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}}; - auto e = _world->make_object<scenery, false>(_world->make_id(), coord, sc); - (void)e; -} - -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); - proto_t proto; - proto << s; - if (!(proto >= min_proto_version && proto <= proto_version)) - fm_throw("bad proto version '{}' (should be between '{}' and '{}')"_cf, - (size_t)proto, (size_t)min_proto_version, (size_t)proto_version); - PROTO = proto; - fm_assert(PROTO > 0); - object_id object_counter = world::object_counter_init; - read_atlases(s); - if (PROTO >= 3) [[likely]] - read_sceneries(s); - if (PROTO >= 9) [[likely]] - read_strings(s); - if (PROTO >= 8) [[likely]] - object_counter << s; - read_chunks(s); - s.assert_end(); - if (PROTO >= 8) [[likely]] - fm_assert(_world->object_counter() == world::object_counter_init); - if (PROTO >= 13) [[likely]] - _world->set_object_counter(object_counter); - else if (PROTO >= 8) [[likely]] - _world->set_object_counter(std::max(world::object_counter_init, object_counter)); - preload_chunks(); - _world = nullptr; -} - -} // namespace - -namespace floormat { - -world world::deserialize(StringView filename) -{ - char errbuf[128]; - fm_soft_assert(filename.flags() & StringViewFlag::NullTerminated); - FILE_raii f = ::fopen(filename.data(), "rb"); - if (!f) - fm_throw("fopen(\"{}\", \"r\"): {}"_cf, filename, get_error_string(errbuf)); - if (int ret = ::fseek(f, 0, SEEK_END); ret != 0) - fm_throw("fseek(SEEK_END): {}"_cf, get_error_string(errbuf)); - size_t len; - if (auto len_ = ::ftell(f); len_ >= 0) - len = (size_t)len_; - else - fm_throw("ftell: {}"_cf, get_error_string(errbuf)); - if (int ret = ::fseek(f, 0, SEEK_SET); ret != 0) - fm_throw("fseek(SEEK_SET): {}"_cf, get_error_string(errbuf)); - auto buf_ = std::make_unique<char[]>(len); - - if (auto ret = ::fread(&buf_[0], 1, len, f); ret != len) - fm_throw("fread short read: {}"_cf, get_error_string(errbuf)); - - world w; - reader_state s{w}; - s.deserialize_world({buf_.get(), len}); - return w; -} - -} // namespace floormat - -#endif - -namespace floormat { - -class world world::deserialize(StringView filename) -{ - (void)filename; - fm_assert("todo" && false); -} - -} // namespace floormat |