From a8fa9fe920d4ed48ed1b88a6e585cdbff648039e Mon Sep 17 00:00:00 2001 From: untodesu Date: Sun, 16 Mar 2025 20:18:16 +0500 Subject: Improved terrain generation - features! [1/2] - @reglnk asked me to commit this early to experiment with this weird-ass heightmap bug that messes with tree placement --- game/shared/CMakeLists.txt | 2 ++ game/shared/chunk.cc | 11 ++++++++++ game/shared/chunk.hh | 6 ++++++ game/shared/dimension.cc | 22 ++++++++++---------- game/shared/dimension.hh | 6 +++++- game/shared/feature.cc | 51 ++++++++++++++++++++++++++++++++++++++++++++++ game/shared/feature.hh | 18 ++++++++++++++++ game/shared/types.hh | 10 ++++----- 8 files changed, 109 insertions(+), 17 deletions(-) create mode 100644 game/shared/feature.cc create mode 100644 game/shared/feature.hh (limited to 'game/shared') diff --git a/game/shared/CMakeLists.txt b/game/shared/CMakeLists.txt index cd3eed4..b0cd086 100644 --- a/game/shared/CMakeLists.txt +++ b/game/shared/CMakeLists.txt @@ -12,6 +12,8 @@ add_library(shared STATIC "${CMAKE_CURRENT_LIST_DIR}/dimension.hh" "${CMAKE_CURRENT_LIST_DIR}/factory.cc" "${CMAKE_CURRENT_LIST_DIR}/factory.hh" + "${CMAKE_CURRENT_LIST_DIR}/feature.cc" + "${CMAKE_CURRENT_LIST_DIR}/feature.hh" "${CMAKE_CURRENT_LIST_DIR}/game_items.cc" "${CMAKE_CURRENT_LIST_DIR}/game_items.hh" "${CMAKE_CURRENT_LIST_DIR}/game_voxels.cc" diff --git a/game/shared/chunk.cc b/game/shared/chunk.cc index c996973..17fdcc1 100644 --- a/game/shared/chunk.cc +++ b/game/shared/chunk.cc @@ -8,6 +8,7 @@ Chunk::Chunk(entt::entity entity, Dimension *dimension) m_entity = entity; m_dimension = dimension; m_voxels.fill(NULL_VOXEL_ID); + m_biome = BIOME_VOID; } voxel_id Chunk::get_voxel(const local_pos &lpos) const @@ -44,6 +45,16 @@ void Chunk::set_voxels(const VoxelStorage &voxels) m_voxels = voxels; } +unsigned int Chunk::get_biome(void) const +{ + return m_biome; +} + +void Chunk::set_biome(unsigned int biome) +{ + m_biome = biome; +} + entt::entity Chunk::get_entity(void) const { return m_entity; diff --git a/game/shared/chunk.hh b/game/shared/chunk.hh index 506d867..560d3a7 100644 --- a/game/shared/chunk.hh +++ b/game/shared/chunk.hh @@ -5,6 +5,8 @@ #include "shared/types.hh" #include "shared/voxel_storage.hh" +constexpr static unsigned int BIOME_VOID = 0U; + class Dimension; class Chunk final { @@ -21,6 +23,9 @@ public: const VoxelStorage &get_voxels(void) const; void set_voxels(const VoxelStorage &voxels); + unsigned int get_biome(void) const; + void set_biome(unsigned int biome); + entt::entity get_entity(void) const; Dimension *get_dimension(void) const; @@ -28,6 +33,7 @@ private: entt::entity m_entity; Dimension *m_dimension; VoxelStorage m_voxels; + unsigned int m_biome; }; #endif /* SHARED_CHUNK_HH */ diff --git a/game/shared/dimension.cc b/game/shared/dimension.cc index 378779c..2377214 100644 --- a/game/shared/dimension.cc +++ b/game/shared/dimension.cc @@ -13,7 +13,7 @@ Dimension::Dimension(const char *name, float gravity) Dimension::~Dimension(void) { - for(const auto it : m_hashmap) + for(const auto it : m_chunkmap) delete it.second; entities.clear(); chunks.clear(); @@ -31,9 +31,9 @@ float Dimension::get_gravity(void) const Chunk *Dimension::create_chunk(const chunk_pos &cpos) { - auto it = m_hashmap.find(cpos); + auto it = m_chunkmap.find(cpos); - if(it != m_hashmap.cend()) { + if(it != m_chunkmap.cend()) { // Chunk already exists return it->second; } @@ -52,7 +52,7 @@ Chunk *Dimension::create_chunk(const chunk_pos &cpos) globals::dispatcher.trigger(event); - return m_hashmap.insert_or_assign(cpos, std::move(chunk)).first->second; + return m_chunkmap.insert_or_assign(cpos, std::move(chunk)).first->second; } Chunk *Dimension::find_chunk(entt::entity entity) const @@ -64,8 +64,8 @@ Chunk *Dimension::find_chunk(entt::entity entity) const Chunk *Dimension::find_chunk(const chunk_pos &cpos) const { - auto it = m_hashmap.find(cpos); - if(it != m_hashmap.cend()) + auto it = m_chunkmap.find(cpos); + if(it != m_chunkmap.cend()) return it->second; return nullptr; } @@ -74,18 +74,18 @@ void Dimension::remove_chunk(entt::entity entity) { if(chunks.valid(entity)) { auto &component = chunks.get(entity); - m_hashmap.erase(component.cpos); + m_chunkmap.erase(component.cpos); chunks.destroy(entity); } } void Dimension::remove_chunk(const chunk_pos &cpos) { - auto it = m_hashmap.find(cpos); + auto it = m_chunkmap.find(cpos); - if(it != m_hashmap.cend()) { + if(it != m_chunkmap.cend()) { chunks.destroy(it->second->get_entity()); - m_hashmap.erase(it); + m_chunkmap.erase(it); } } @@ -93,7 +93,7 @@ void Dimension::remove_chunk(Chunk *chunk) { if(chunk) { const auto &component = chunks.get(chunk->get_entity()); - m_hashmap.erase(component.cpos); + m_chunkmap.erase(component.cpos); chunks.destroy(chunk->get_entity()); } } diff --git a/game/shared/dimension.hh b/game/shared/dimension.hh index eb6f896..8806115 100644 --- a/game/shared/dimension.hh +++ b/game/shared/dimension.hh @@ -2,12 +2,16 @@ #define SHARED_DIMENSION_HH 1 #pragma once +#include "shared/const.hh" #include "shared/types.hh" class Chunk; class Config; class VoxelStorage; +using dimension_entropy_map = std::array; +using dimension_height_map = std::array; + class Dimension { public: explicit Dimension(const char *name, float gravity); @@ -43,7 +47,7 @@ public: private: std::string m_name; - emhash8::HashMap m_hashmap; + emhash8::HashMap m_chunkmap; float m_gravity; }; diff --git a/game/shared/feature.cc b/game/shared/feature.cc new file mode 100644 index 0000000..6f884b2 --- /dev/null +++ b/game/shared/feature.cc @@ -0,0 +1,51 @@ +#include "shared/pch.hh" +#include "shared/feature.hh" + +#include "shared/chunk.hh" +#include "shared/coord.hh" +#include "shared/dimension.hh" +#include "shared/voxel_storage.hh" + +void Feature::place(const voxel_pos &vpos, Dimension *dimension, bool overwrite) const +{ + for(const auto &it : (*this)) { + auto it_vpos = vpos + it.first; + auto it_cpos = coord::to_chunk(it_vpos); + + if(auto chunk = dimension->create_chunk(it_cpos)) { + auto it_lpos = coord::to_local(it_vpos); + auto it_index = coord::to_index(it_lpos); + + if(chunk->get_voxel(it_index) && !overwrite) { + // There is something in the way + // and the called intentionally requested + // we do not force feature to overwrite voxels + continue; + } + + chunk->set_voxel(it.second, it_index); + } + } +} + +void Feature::place(const voxel_pos &vpos, const chunk_pos &cpos, VoxelStorage &voxels, bool overwrite) const +{ + for(const auto &it : (*this)) { + auto it_vpos = vpos + it.first; + auto it_cpos = coord::to_chunk(it_vpos); + + if(it_cpos == cpos) { + auto it_lpos = coord::to_local(it_vpos); + auto it_index = coord::to_index(it_lpos); + + if(voxels[it_index] && !overwrite) { + // There is something in the way + // and the called intentionally requested + // we do not force feature to overwrite voxels + continue; + } + + voxels[it_index] = it.second; + } + } +} diff --git a/game/shared/feature.hh b/game/shared/feature.hh new file mode 100644 index 0000000..eb7cf2a --- /dev/null +++ b/game/shared/feature.hh @@ -0,0 +1,18 @@ +#ifndef SHARED_FEATURE_HH +#define SHARED_FEATURE_HH 1 +#pragma once + +#include "shared/types.hh" + +class Dimension; +class VoxelStorage; + +class Feature final : public std::vector> { +public: + explicit Feature(void) = default; + virtual ~Feature(void) = default; + void place(const voxel_pos &vpos, Dimension *dimension, bool overwrite = false) const; + void place(const voxel_pos &vpos, const chunk_pos &cpos, VoxelStorage &voxels, bool overwrite = false) const; +}; + +#endif /* SHARED_FEATURE_HH */ diff --git a/game/shared/types.hh b/game/shared/types.hh index dace85e..a107e54 100644 --- a/game/shared/types.hh +++ b/game/shared/types.hh @@ -14,9 +14,9 @@ using chunk_pos = glm::vec<3, std::int32_t>; using local_pos = glm::vec<3, std::int16_t>; using voxel_pos = glm::vec<3, std::int64_t>; -// A special 2D chunk coordinate used by world generation code -// to cache things like 2D noise and terrain heightmap for performance reasons -using worldgen_chunk_pos = glm::vec<2, chunk_pos::value_type>; +using chunk_pos_xz = glm::vec<2, chunk_pos::value_type>; +using local_pos_xz = glm::vec<2, local_pos::value_type>; +using voxel_pos_xz = glm::vec<2, local_pos::value_type>; template<> struct std::hash final { @@ -31,8 +31,8 @@ struct std::hash final { }; template<> -struct std::hash final { - constexpr inline std::size_t operator()(const worldgen_chunk_pos &cwpos) const +struct std::hash final { + constexpr inline std::size_t operator()(const chunk_pos_xz &cwpos) const { std::size_t value = 0; value ^= cwpos.x * 73856093; -- cgit