diff options
-rw-r--r-- | serialize/world-impl.hpp | 3 | ||||
-rw-r--r-- | serialize/world-reader.cpp | 8 | ||||
-rw-r--r-- | serialize/world-writer.cpp | 10 | ||||
-rw-r--r-- | src/camera-offset.cpp | 1 | ||||
-rw-r--r-- | src/global-coords.hpp | 20 | ||||
-rw-r--r-- | src/world.cpp | 30 | ||||
-rw-r--r-- | src/world.hpp | 33 |
7 files changed, 71 insertions, 34 deletions
diff --git a/serialize/world-impl.hpp b/serialize/world-impl.hpp index b44ec6b4..a869e022 100644 --- a/serialize/world-impl.hpp +++ b/serialize/world-impl.hpp @@ -22,6 +22,7 @@ * 7) Serialize scenery bbox_size offset. * 8) Entity subtypes. * 9) Interned strings. + * 10) Chunk Z level. */ namespace floormat { @@ -48,7 +49,7 @@ 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 = 9; +constexpr inline proto_t proto_version = 10; 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 83a1d3f2..05add388 100644 --- a/serialize/world-reader.cpp +++ b/serialize/world-reader.cpp @@ -31,7 +31,7 @@ private: 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 read_old_scenery(reader_t& s, chunk_coords_ ch, size_t i); std::vector<String> strings; std::vector<scenery_proto> sceneries; @@ -173,9 +173,11 @@ void reader_state::read_chunks(reader_t& s) magic << s; if (magic != chunk_magic) fm_throw("bad chunk magic"_cf); - chunk_coords ch; + 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++) @@ -311,7 +313,7 @@ void reader_state::read_chunks(reader_t& s) } } -void reader_state::read_old_scenery(reader_t& s, chunk_coords ch, size_t i) +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; diff --git a/serialize/world-writer.cpp b/serialize/world-writer.cpp index 5fe835bf..13751fc4 100644 --- a/serialize/world-writer.cpp +++ b/serialize/world-writer.cpp @@ -56,7 +56,7 @@ private: 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_chunk(const chunk& c, chunk_coords_ coord); void serialize_atlases(); void serialize_scenery(); void serialize_strings(); @@ -74,7 +74,7 @@ private: }; constexpr auto tile_size = sizeof(tilemeta) + (sizeof(atlasid) + sizeof(variant_t)) * 3 + sizeof(scenery); -constexpr auto chunkbuf_size = sizeof(chunk_magic) + sizeof(chunk_coords) + tile_size * TILE_COUNT; +constexpr auto chunkbuf_size = sizeof(chunk_magic) + sizeof(chunk_coords_) + tile_size * TILE_COUNT; constexpr auto entity_size = std::max(sizeof(character), sizeof(scenery)) + character_name_max; writer_state::writer_state(const world& world) : _world{&world} @@ -398,7 +398,7 @@ void writer_state::serialize_new_scenery(const chunk& c, writer_t& s) } } -void writer_state::serialize_chunk(const chunk& c, chunk_coords coord) +void writer_state::serialize_chunk(const chunk& c, chunk_coords_ coord) { fm_assert(chunk_buf.empty()); const auto es_size = sizeof(uint32_t) + entity_size*c.entities().size(); @@ -407,6 +407,8 @@ void writer_state::serialize_chunk(const chunk& c, chunk_coords coord) auto s = binary_writer{chunk_buf.begin()}; s << chunk_magic << coord.x << coord.y; + fm_assert(coord.z >= -8 && coord.z < 8); + s << coord.z; for (auto i = 0uz; i < TILE_COUNT; i++) { @@ -496,7 +498,7 @@ ArrayView<const char> writer_state::serialize_world() if (c.empty(true)) fm_warn("chunk %hd:%hd is empty", pos.x, pos.y); #endif - serialize_chunk(c, pos); + serialize_chunk(c, pos); // todo } serialize_atlases(); serialize_scenery(); diff --git a/src/camera-offset.cpp b/src/camera-offset.cpp index 84dc6141..bf700138 100644 --- a/src/camera-offset.cpp +++ b/src/camera-offset.cpp @@ -12,6 +12,7 @@ with_shifted_camera_offset::with_shifted_camera_offset(tile_shader& shader, chun constexpr auto chunk_size = TILE_MAX_DIM20d*dTILE_SIZE; const auto offset = _camera + tile_shader::project(Vector3d(c) * chunk_size); + first.x -= 8; first.y -= 8; last.x += 8; last.y += 8; // Z levels const auto len_x = (float)(last.x - first.x), cx = (float)(c.x - first.x), cy = (float)(c.y - first.y); const float depth_offset = shader.depth_tile_size*(cy*TILE_MAX_DIM*len_x*TILE_MAX_DIM + cx*TILE_MAX_DIM); diff --git a/src/global-coords.hpp b/src/global-coords.hpp index d8f238f3..f0d73c6f 100644 --- a/src/global-coords.hpp +++ b/src/global-coords.hpp @@ -27,6 +27,17 @@ constexpr Vector2i chunk_coords::operator-(chunk_coords other) const noexcept return { Int{x} - other.x, Int{y} - other.y }; } +struct chunk_coords_ final { + int16_t x = 0, y = 0; + int8_t z = 0; + + explicit constexpr operator chunk_coords() const noexcept { return {x, y}; } + constexpr chunk_coords_(chunk_coords c) noexcept : x{c.x}, y{c.y} {} + constexpr chunk_coords_() noexcept = default; + constexpr chunk_coords_(int16_t x, int16_t y, int8_t z = 0) : x{x}, y{y}, z{z} {} + constexpr bool operator==(const chunk_coords_&) const noexcept = default; +}; + struct global_coords final { using u0 = std::integral_constant<uint32_t, (1<<15)>; using s0 = std::integral_constant<int32_t, int32_t(u0::value)>; @@ -35,7 +46,7 @@ struct global_coords final { uint32_t x = u0::value<<4|z0::value<<20, y = u0::value<<4; constexpr global_coords() noexcept = default; - constexpr global_coords(chunk_coords c, local_coords xy, int8_t z = 0) : + constexpr global_coords(chunk_coords c, local_coords xy, int8_t z) noexcept : x{ uint32_t((c.x + s0::value) << 4) | (xy.x & 0x0f) | uint32_t(((int)z + z0::value) & 0x0f) << 20 @@ -44,8 +55,11 @@ struct global_coords final { {} constexpr global_coords(uint32_t x, uint32_t y) noexcept : x{x}, y{y} {} constexpr global_coords(int32_t x, int32_t y, int8_t z = 0) noexcept : - x{uint32_t(x + (s0::value<<4)) | uint32_t(((z + z0::value) & 0x0f) << 20)}, - y{uint32_t(y + (s0::value<<4))} + x{uint32_t(x + (s0::value<<4)) | uint32_t(((z + z0::value) & 0x0f) << 20)}, + y{uint32_t(y + (s0::value<<4))} + {} + constexpr global_coords(chunk_coords_ c, local_coords xy) noexcept : + global_coords{chunk_coords{c.x, c.y}, xy, c.z} {} constexpr local_coords local() const noexcept; diff --git a/src/world.cpp b/src/world.cpp index 9d669e62..cdf8c087 100644 --- a/src/world.cpp +++ b/src/world.cpp @@ -1,11 +1,35 @@ #include "world.hpp" #include "chunk.hpp" #include "entity.hpp" +#include "compat/int-hash.hpp" + +using namespace floormat; + +size_t std::hash<chunk_coords_>::operator()(const chunk_coords_& coord) const noexcept +{ + std::size_t x = 0; + + x |= size_t(uint16_t(coord.y)) << 16; + x |= size_t(uint16_t(coord.x)); + if constexpr(sizeof(size_t) > 4) + x |= size_t(uint8_t(coord.z+8) & 0xf) << 20; + else + x ^= size_t(uint8_t(coord.z+8) & 0xf) * size_t(1664525); + + return int_hash(x); +} namespace floormat { world::world(world&& w) noexcept = default; +world::world(std::unordered_map<chunk_coords_, chunk>&& chunks) : + world{std::max(initial_capacity, size_t(1/max_load_factor * 2 * chunks.size()))} +{ + for (auto&& [coord, c] : chunks) + operator[](coord) = std::move(c); +} + world& world::operator=(world&& w) noexcept { if (&w != this) [[likely]] @@ -50,12 +74,12 @@ world::~world() noexcept _entities.clear(); } -world::world(size_t capacity) : _chunks{capacity, hasher} +world::world(size_t capacity) : _chunks{capacity} { _chunks.max_load_factor(max_load_factor); } -chunk& world::operator[](chunk_coords coord) noexcept +chunk& world::operator[](chunk_coords_ coord) noexcept { auto& [c, coord2] = _last_chunk; if (coord != coord2) @@ -70,7 +94,7 @@ auto world::operator[](global_coords pt) noexcept -> pair return { c, c[pt.local()] }; } -bool world::contains(chunk_coords c) const noexcept +bool world::contains(chunk_coords_ c) const noexcept { return _chunks.find(c) != _chunks.cend(); } diff --git a/src/world.hpp b/src/world.hpp index b057b854..98fa7f47 100644 --- a/src/world.hpp +++ b/src/world.hpp @@ -1,5 +1,4 @@ #pragma once -#include "compat/int-hash.hpp" #include "compat/defs.hpp" #include "chunk.hpp" #include "global-coords.hpp" @@ -8,6 +7,13 @@ #include <unordered_map> #include <memory> +namespace floormat { struct chunk_coords_; } + +template<> +struct std::hash<floormat::chunk_coords_> final { + floormat::size_t operator()(const floormat::chunk_coords_& coord) const noexcept; +}; + namespace floormat { struct entity; @@ -17,17 +23,14 @@ struct world final { private: struct chunk_tuple final { - static constexpr chunk_coords invalid_coords = { -1 << 15, -1 << 15 }; + static constexpr chunk_coords_ invalid_coords = { -1 << 15, -1 << 15, -8 }; chunk* c = nullptr; - chunk_coords pos = invalid_coords; + chunk_coords_ pos = invalid_coords; } _last_chunk; static constexpr size_t initial_capacity = 64; static constexpr float max_load_factor = .5; - static constexpr auto hasher = [](chunk_coords c) constexpr -> size_t { - return int_hash((size_t)c.y << 16 | (size_t)c.x); - }; - std::unordered_map<chunk_coords, chunk, decltype(hasher)> _chunks; + std::unordered_map<chunk_coords_, chunk> _chunks; std::unordered_map<object_id, std::weak_ptr<entity>> _entities; size_t _last_collection = 0; size_t _collect_every = 64; @@ -47,15 +50,13 @@ private: public: explicit world(); ~world() noexcept; + explicit world(std::unordered_map<chunk_coords_, chunk>&& chunks); struct pair final { chunk& c; tile_ref t; }; // NOLINT - template<typename Hash, typename Alloc, typename Pred> - explicit world(std::unordered_map<chunk_coords, chunk, Hash, Alloc, Pred>&& chunks); - - chunk& operator[](chunk_coords c) noexcept; + chunk& operator[](chunk_coords_ c) noexcept; pair operator[](global_coords pt) noexcept; - bool contains(chunk_coords c) const noexcept; + bool contains(chunk_coords_ c) const noexcept; void clear(); void collect(bool force = false); void maybe_collect(); @@ -95,14 +96,6 @@ public: fm_DECLARE_DEPRECATED_COPY_ASSIGNMENT(world); }; -template<typename Hash, typename Alloc, typename Pred> -world::world(std::unordered_map<chunk_coords, chunk, Hash, Alloc, Pred>&& chunks) : - world{std::max(initial_capacity, size_t(1/max_load_factor * 2 * chunks.size()))} -{ - for (auto&& [coord, c] : chunks) - operator[](coord) = std::move(c); -} - template<typename T> std::shared_ptr<T> world::find_entity(object_id id) { |