summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorStanislaw Halik <sthalik@misaki.pl>2023-04-06 10:08:04 +0200
committerStanislaw Halik <sthalik@misaki.pl>2023-04-06 10:08:04 +0200
commit9703532543d528757e4635f0eb5c91ccb4c2e300 (patch)
treebf30bb6980d382a202df38365ff00a0d6a0e8eb2
parent6799cc5c195562ca36b73e8aec259cc9caf49e2c (diff)
a
-rw-r--r--serialize/world-impl.hpp3
-rw-r--r--serialize/world-reader.cpp8
-rw-r--r--serialize/world-writer.cpp10
-rw-r--r--src/camera-offset.cpp1
-rw-r--r--src/global-coords.hpp20
-rw-r--r--src/world.cpp30
-rw-r--r--src/world.hpp33
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)
{