diff options
| author | Nicolas James <Eele1Ephe7uZahRie@tutanota.com> | 2025-02-12 18:05:18 +1100 |
|---|---|---|
| committer | Nicolas James <Eele1Ephe7uZahRie@tutanota.com> | 2025-02-12 18:05:18 +1100 |
| commit | 1cc08c51eb4b0f95c30c0a98ad1fc5ad3459b2df (patch) | |
| tree | 222dfcd07a1e40716127a347bbfd7119ce3d0984 /src/shared/world.hh | |
initial commit
Diffstat (limited to 'src/shared/world.hh')
| -rw-r--r-- | src/shared/world.hh | 224 |
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 |
