diff options
Diffstat (limited to 'serialize')
-rw-r--r-- | serialize/world-impl.hpp | 6 | ||||
-rw-r--r-- | serialize/world-reader.cpp | 39 | ||||
-rw-r--r-- | serialize/world-writer.cpp | 35 |
3 files changed, 74 insertions, 6 deletions
diff --git a/serialize/world-impl.hpp b/serialize/world-impl.hpp index 0756250c..b44ec6b4 100644 --- a/serialize/world-impl.hpp +++ b/serialize/world-impl.hpp @@ -20,7 +20,8 @@ * 5) Serialize scenery pixel offset. * 6) Serialize scenery bboxes. * 7) Serialize scenery bbox_size offset. - * 8) Scenery replaced with entities. + * 8) Entity subtypes. + * 9) Interned strings. */ namespace floormat { @@ -45,8 +46,9 @@ constexpr inline size_t atlas_name_max = 128; constexpr inline auto null_atlas = (atlasid)-1LL; constexpr inline size_t character_name_max = 128; +constexpr inline size_t string_max = 512; -constexpr inline proto_t proto_version = 8; +constexpr inline proto_t proto_version = 9; constexpr inline proto_t min_proto_version = 1; constexpr inline auto chunk_magic = (uint16_t)~0xc0d3; constexpr inline auto scenery_magic = (uint16_t)~0xb00b; diff --git a/serialize/world-reader.cpp b/serialize/world-reader.cpp index 61c3984c..9e62cd54 100644 --- a/serialize/world-reader.cpp +++ b/serialize/world-reader.cpp @@ -25,11 +25,14 @@ private: const std::shared_ptr<tile_atlas>& 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); + std::vector<String> strings; std::vector<scenery_proto> sceneries; std::vector<std::shared_ptr<tile_atlas>> atlases; world* _world; @@ -114,6 +117,17 @@ void reader_state::read_sceneries(reader_t& s) fm_soft_assert(i == sz); } +void reader_state::read_strings(reader_t& s) +{ + uint32_t size; size << s; + strings.reserve(size); + for (auto i = 0_uz; i < size; i++) + { + auto str = s.read_asciiz_string<string_max>(); + strings.emplace_back(StringView{str}); + } +} + const std::shared_ptr<tile_atlas>& reader_state::lookup_atlas(atlasid id) { if (id < atlases.size()) @@ -130,6 +144,12 @@ const scenery_proto& reader_state::lookup_scenery(atlasid id) 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 @@ -229,8 +249,21 @@ void reader_state::read_chunks(reader_t& s) offset_frac[0] << s; offset_frac[1] << s; SET_CHUNK_SIZE(); - const auto name = s.read_asciiz_string<character_name_max>(); - proto.name = StringView{name.buf, name.len, StringViewFlag::Global|StringViewFlag::NullTerminated}; + + if (PROTO >= 9) [[likely]] + { + uint32_t id; id << s; + auto name = lookup_string(id); + fm_soft_assert(name.size() < character_name_max); + proto.name = name; + } + else + { + auto [buf, len] = s.read_asciiz_string<character_name_max>(); + auto name = StringView{buf, len}; + proto.name = name; + } + if (!(id & meta_short_scenery_bit)) read_offsets(s, proto); SET_CHUNK_SIZE(); @@ -336,6 +369,8 @@ void reader_state::deserialize_world(ArrayView<const char> buf) read_atlases(s); if (PROTO >= 3) [[likely]] read_sceneries(s); + if (PROTO >= 9) [[likely]] + read_strings(s); if (PROTO >= 8) [[likely]] entity_counter << s; read_chunks(s); diff --git a/serialize/world-writer.cpp b/serialize/world-writer.cpp index 4bf7315f..99ae0b61 100644 --- a/serialize/world-writer.cpp +++ b/serialize/world-writer.cpp @@ -16,7 +16,7 @@ #include <cstring> #include <vector> #include <algorithm> -#include <Corrade/Containers/StringView.h> +#include <Corrade/Containers/StringStlHash.h> #include <Corrade/Utility/Path.h> using namespace floormat; @@ -53,20 +53,23 @@ private: atlasid intern_atlas(const tile_image_proto& img); atlasid maybe_intern_atlas(const tile_image_proto& img); scenery_pair intern_scenery(const scenery& sc, bool create); + uint32_t intern_string(StringView name); void serialize_new_scenery(const chunk& c, writer_t& s); void serialize_chunk(const chunk& c, chunk_coords coord); void serialize_atlases(); void serialize_scenery(); + void serialize_strings(); void load_scenery_1(const serialized_scenery& s); void load_scenery(); const world* _world; - std::vector<char> atlas_buf, scenery_buf, chunk_buf, file_buf; + std::vector<char> atlas_buf, scenery_buf, chunk_buf, file_buf, string_buf; std::vector<std::vector<char>> chunk_bufs; std::unordered_map<const void*, interned_atlas> tile_images; std::unordered_map<const void*, std::vector<interned_scenery>> scenery_map; + std::unordered_map<StringView, uint32_t> string_map; atlasid scenery_map_size = 0; }; @@ -80,6 +83,13 @@ writer_state::writer_state(const world& world) : _world{&world} chunk_bufs.reserve(world.chunks().size()); atlas_buf.reserve(atlas_name_max * 64); scenery_map.reserve(64); + string_map.reserve(64); +} + +uint32_t writer_state::intern_string(StringView name) +{ + auto [kv, fresh] = string_map.try_emplace(name, string_map.size()); + return kv->second; } atlasid writer_state::intern_atlas(const tile_image_proto& img) @@ -285,6 +295,24 @@ void writer_state::serialize_scenery() scenery_buf.resize(s.bytes_written()); } +void writer_state::serialize_strings() +{ + static_assert(character_name_max <= string_max); + auto len = 0_uz; + for (const auto& [k, v] : string_map) + { + fm_assert(k.size()+1 < string_max); + len += k.size()+1; + } + string_buf.resize(sizeof(uint32_t) + len); + auto s = binary_writer{string_buf.begin()}; + s << (uint32_t)string_map.size(); + for (const auto& [k, v] : string_map) + s.write_asciiz_string(k); + fm_assert(s.bytes_written() == sizeof(uint32_t) + len); + fm_assert(s.bytes_written() == string_buf.size()); +} + const auto def_char_bbox_size = character_proto{}.bbox_size; const auto def_char_pass = character_proto{}.pass; @@ -471,6 +499,7 @@ ArrayView<const char> writer_state::serialize_world() } serialize_atlases(); serialize_scenery(); + serialize_strings(); using proto_t = std::decay_t<decltype(proto_version)>; fm_assert(_world->size() <= int_max<chunksiz>); @@ -481,6 +510,7 @@ ArrayView<const char> writer_state::serialize_world() len += sizeof(proto_t); len += atlas_buf.size(); len += scenery_buf.size(); + len += string_buf.size(); len += sizeof(object_id); len += sizeof(chunksiz); for (const auto& buf : chunk_bufs) @@ -505,6 +535,7 @@ ArrayView<const char> writer_state::serialize_world() copy_int((proto_t)proto_version); copy(atlas_buf); copy(scenery_buf); + copy(string_buf); copy_int((object_id)_world->entity_counter()); copy_int((chunksiz)_world->size()); for (const auto& buf : chunk_bufs) |