summaryrefslogtreecommitdiffhomepage
path: root/serialize
diff options
context:
space:
mode:
Diffstat (limited to 'serialize')
-rw-r--r--serialize/world-impl.hpp6
-rw-r--r--serialize/world-reader.cpp39
-rw-r--r--serialize/world-writer.cpp35
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)