aboutsummaryrefslogtreecommitdiff
path: root/src/shared/world.hh
diff options
context:
space:
mode:
authorNicolas James <Eele1Ephe7uZahRie@tutanota.com>2025-02-12 18:05:18 +1100
committerNicolas James <Eele1Ephe7uZahRie@tutanota.com>2025-02-12 18:05:18 +1100
commit1cc08c51eb4b0f95c30c0a98ad1fc5ad3459b2df (patch)
tree222dfcd07a1e40716127a347bbfd7119ce3d0984 /src/shared/world.hh
initial commit
Diffstat (limited to 'src/shared/world.hh')
-rw-r--r--src/shared/world.hh224
1 files changed, 224 insertions, 0 deletions
diff --git a/src/shared/world.hh b/src/shared/world.hh
new file mode 100644
index 0000000..3969992
--- /dev/null
+++ b/src/shared/world.hh
@@ -0,0 +1,224 @@
+#ifndef SHARED_WORLD_HH_
+#define SHARED_WORLD_HH_
+
+#include <algorithm>
+#include <array>
+#include <exception>
+#include <functional>
+#include <istream>
+#include <memory>
+#include <random>
+#include <type_traits>
+#include <vector>
+
+#include <boost/functional/hash.hpp>
+#include <glm/glm.hpp>
+
+#include "shared/math.hh"
+#include "shared/net/proto.hh"
+#include "shared/shared.hh"
+
+namespace shared {
+namespace world {
+
+class block {
+public:
+ enum class type : std::uint8_t {
+ air, // zero means air which means don't render
+ dirt, // atlas should start from here
+ grass,
+ sand,
+ sandstone,
+ stone,
+ cobblestone,
+ wood,
+ leaves,
+ water,
+ shrub,
+ snow,
+ cactus,
+ dead_shrub,
+ snowy_wood,
+ snowy_leaves,
+ snowy_shrub,
+ };
+ enum class visibility { solid, partial, translucent, invisible };
+
+public:
+ type type;
+
+public:
+ static constexpr enum block::visibility
+ get_visibility(const enum block::type type) noexcept {
+ switch (type) {
+ case type::air:
+ return visibility::invisible;
+ case type::shrub:
+ case type::dead_shrub:
+ case type::leaves:
+ case type::snowy_leaves:
+ case type::snowy_shrub:
+ return visibility::partial;
+ case type::water:
+ return visibility::translucent;
+ default:
+ break;
+ }
+ return visibility::solid;
+ }
+ static constexpr bool is_tangible(const enum block::type type) noexcept {
+ switch (type) {
+ case type::air:
+ case type::shrub:
+ case type::dead_shrub:
+ case type::snowy_shrub:
+ return false;
+ default:
+ break;
+ }
+ return true;
+ }
+ static constexpr bool is_collidable(const enum block::type type) noexcept {
+ switch (type) {
+ case type::air:
+ case type::shrub:
+ case type::dead_shrub:
+ case type::snowy_shrub:
+ case type::water:
+ return false;
+ default:
+ break;
+ }
+ return true;
+ }
+ static constexpr bool is_liquid(const enum block::type type) noexcept {
+ switch (type) {
+ case type::water:
+ return true;
+ default:
+ break;
+ }
+ return false;
+ }
+ static constexpr bool is_replaceable(const enum block::type type) noexcept {
+ switch (type) {
+ case type::water:
+ case type::air:
+ return true;
+ default:
+ break;
+ }
+ return false;
+ }
+ static constexpr bool is_removable(const enum block::type type) noexcept {
+ switch (type) {
+ case type::water:
+ case type::air:
+ return false;
+ default:
+ break;
+ }
+ return true;
+ }
+ static constexpr float get_friction(const enum block::type type) noexcept {
+ switch (type) {
+ case type::water:
+ return 20.0f;
+ case type::air:
+ case type::shrub:
+ case type::dead_shrub:
+ case type::snowy_shrub:
+ return 0.1f;
+ default:
+ break;
+ }
+ return 10.0f;
+ }
+
+public:
+ block(const enum block::type t = type::air) noexcept : type(t) {}
+
+ operator enum block::type() const noexcept { return this->type; }
+};
+
+class chunk {
+public:
+ static constexpr int WIDTH = 16;
+ static constexpr int HEIGHT = 256;
+ static constexpr int VOLUME = WIDTH * WIDTH * HEIGHT;
+
+ // Stuff for unordered_map.
+ static std::size_t hash(const shared::math::coords& c) noexcept {
+ std::size_t seed = 0;
+ boost::hash_combine(seed, boost::hash_value(c.x));
+ boost::hash_combine(seed, boost::hash_value(c.z));
+ return seed;
+ }
+ static std::size_t equal(const shared::math::coords& a,
+ const shared::math::coords& b) noexcept {
+ return a == b;
+ }
+ using map = std::unordered_map<shared::math::coords, shared::world::chunk,
+ decltype(&shared::world::chunk::hash),
+ decltype(&shared::world::chunk::equal)>;
+
+protected:
+ shared::math::coords pos;
+ std::array<block, VOLUME> blocks; // Use get_block for 3d index access.
+
+public:
+ using block_array = decltype(chunk::blocks);
+ enum class biome { desert, islands, ocean, plains, forest, tundra, alpine };
+
+ static bool is_outside_chunk(const glm::ivec3& v) noexcept {
+ return (std::min(v.x, v.z) < 0) || (std::max(v.x, v.z) >= WIDTH) ||
+ (std::clamp(v.y, 0, HEIGHT - 1) != v.y);
+ }
+ static shared::math::coords
+ get_normalised_chunk(const shared::math::coords& coords, const int x,
+ const int z) noexcept {
+ return coords + shared::math::coords{(x >= WIDTH) - (x < 0),
+ (z >= WIDTH) - (z < 0)};
+ }
+ static std::pair<unsigned short, unsigned short>
+ get_normalised_coords(const int x, const int z) noexcept {
+ return {x + WIDTH * ((x < 0) - (x >= WIDTH)),
+ z + WIDTH * ((z < 0) - (z >= WIDTH))};
+ }
+ static glm::ivec3 get_normalised_coords(const glm::ivec3& c) noexcept {
+ const auto [x, z] = get_normalised_coords(c.x, c.z);
+ return {x, c.y, z};
+ }
+ static block_array
+ make_blocks_from_chunk(const proto::chunk& chunk) noexcept;
+
+public:
+ static unsigned long get_3d_index(const glm::ivec3& v) noexcept {
+#ifndef NDEBUG
+ if (is_outside_chunk(v)) {
+ throw std::range_error("bad chunk block coordinate access");
+ }
+#endif
+ return static_cast<unsigned long>(v.x +
+ (WIDTH * (v.y + (HEIGHT * v.z))));
+ }
+
+public:
+ // If a third non-std::nullopt argument is provided, we use those blocks
+ // instead of what we might have otherwise generated.
+ chunk(const std::uint64_t& seed, const shared::math::coords& coords,
+ const std::optional<block_array> blocks = std::nullopt) noexcept;
+
+ shared::math::coords get_pos() const noexcept { return this->pos; }
+ block get_block(const glm::ivec3& v) const noexcept {
+ return this->blocks[get_3d_index(v)];
+ }
+ block& get_block(const glm::ivec3& v) noexcept {
+ return this->blocks[get_3d_index(v)];
+ }
+};
+
+} // namespace world
+} // namespace shared
+
+#endif