diff --git a/include/Cubed/constants.hpp b/include/Cubed/constants.hpp index aad82aa..f1e0f23 100644 --- a/include/Cubed/constants.hpp +++ b/include/Cubed/constants.hpp @@ -27,6 +27,9 @@ constexpr int SIZE_X = CHUNK_SIZE; constexpr int SIZE_Y = WORLD_SIZE_Y; constexpr int SIZE_Z = CHUNK_SIZE; constexpr int RESERVED_THREADS = 3; + +constexpr float DEFAULT_CAVE_PROBABILITY = 0.035f; + constexpr ChunkPos CHUNK_DIR[]{{1, 0}, {-1, 0}, {0, 1}, {0, -1}, {1, 1}, {-1, 1}, {1, -1}, {-1, -1}}; diff --git a/include/Cubed/dev_panel.hpp b/include/Cubed/dev_panel.hpp index 75d2c96..6f949fd 100644 --- a/include/Cubed/dev_panel.hpp +++ b/include/Cubed/dev_panel.hpp @@ -55,6 +55,7 @@ private: void show_time_table_bar(); void show_cave_table_bar(); void show_river_table_bar(); + void show_chunk_table_bar(); void show_settings_tab_item(); void show_world_tab_item(); void show_player_tab_item(); diff --git a/include/Cubed/gameplay/cave_carver.hpp b/include/Cubed/gameplay/cave_carver.hpp index e737f3f..b5bc764 100644 --- a/include/Cubed/gameplay/cave_carver.hpp +++ b/include/Cubed/gameplay/cave_carver.hpp @@ -1,31 +1,25 @@ #pragma once -#include "Cubed/gameplay/cave_path.hpp" +#include "Cubed/constants.hpp" +#include "Cubed/gameplay/path.hpp" -#include #include namespace Cubed { class CaveCarver { - using CaveHashMap = tbb::concurrent_hash_map; public: CaveCarver(); - CaveHashMap& paths(); + void init(unsigned world_seed); void reload(unsigned world_seed); - void add_path(const glm::vec3& pos, unsigned chunk_seed); - void try_to_add_path(const ChunkPos& pos, unsigned chunk_seed); - void cleanup_finished_caves(); - - int cave_sum() const; - float& cave_probability(); - std::shared_mutex& path_mutex(); + bool has_origin_fast(const ChunkPos& pos) const; + float cave_probability() const; + PathOrigin get_origin(const ChunkPos& origin_chunk) const; + int search_radius() const; + unsigned world_seed() const; private: - CaveHashMap m_paths; - unsigned m_seed = 0; - Random m_random; - float m_cave_probability = 0.035f; - std::shared_mutex m_path_mutex; + std::atomic m_world_seed{0}; + std::atomic m_cave_probability{DEFAULT_CAVE_PROBABILITY}; }; } // namespace Cubed diff --git a/include/Cubed/gameplay/cave_path.hpp b/include/Cubed/gameplay/cave_path.hpp index 60a32dd..36d95a5 100644 --- a/include/Cubed/gameplay/cave_path.hpp +++ b/include/Cubed/gameplay/cave_path.hpp @@ -16,8 +16,6 @@ public: CavePath(unsigned int chunk_seed, unsigned world_seed, const glm::vec3& start_pos); const std::vector& points() const; - void clear_chunk(const ChunkPos& pos); - bool is_finished() const; static float& radius_xz_min(); static float& radius_xz_max(); @@ -27,6 +25,7 @@ public: static float& delta_angle_max(); static int& step_min(); static int& step_max(); + static int step_len(); private: static inline float m_radius_xz_min = 5.0f; @@ -37,18 +36,16 @@ private: static inline float m_delta_angle_max = 5.0f; static inline int m_step_min = 10; static inline int m_step_max = 400; - + static inline float m_step_len = 4.0f; unsigned int m_seed = 0; float m_yaw = 0.0f; float m_pitch = 0.0f; int m_step = 0; - float m_step_len = 1.0f; + PathPoint m_start_path_point{{0.0f, 0.0f, 0.0f}, 0.0f, 0.0f}; Random m_random; std::vector m_points; - ChunkPosSet m_pending_chunks; void collect_path_points(); - void precompute_chunk_coverage(); }; } // namespace Cubed \ No newline at end of file diff --git a/include/Cubed/gameplay/chunk.hpp b/include/Cubed/gameplay/chunk.hpp index 166864b..0c80c9b 100644 --- a/include/Cubed/gameplay/chunk.hpp +++ b/include/Cubed/gameplay/chunk.hpp @@ -10,6 +10,15 @@ #include namespace Cubed { +struct ChunkInfo { + ChunkPos pos{0, 0}; + unsigned seed{0}; + BiomeType biome{BiomeType::NONE}; + unsigned first_random{0}; + bool has_cave_start{false}; + bool has_cave{false}; +}; + class World; // if want to use, do init_chunk(), gen_vertex_data() and class Chunk { @@ -26,6 +35,8 @@ private: std::atomic m_gening{false}; std::atomic m_temp_chunk{false}; + bool m_has_cave{false}; + std::atomic m_biome = BiomeType::PLAIN; std::mutex m_vertexs_data_mutex; @@ -50,7 +61,7 @@ private: unsigned m_seed = 0; BiomeConditions m_conditions; - + ChunkInfo m_info; void clear_dirty(); void gen_vertices(const OptionalBlockVectorArray& neighbor_block); void gen_cross_plane_vertices(int world_x, int world_y, int world_z, @@ -129,6 +140,7 @@ public: void set_chunk_block(int index, unsigned id); // ensure thread safe! void gen_chunk(); + bool is_temp_chunk() const; ChunkPos chunk_pos() const; BiomeType biome() const; @@ -138,6 +150,8 @@ public: World& world(); unsigned seed() const; BiomeConditions& conditions(); + ChunkInfo get_info() const; + bool& has_cave(); }; } // namespace Cubed \ No newline at end of file diff --git a/include/Cubed/gameplay/chunk_generator.hpp b/include/Cubed/gameplay/chunk_generator.hpp index 54ccd57..2cf5d04 100644 --- a/include/Cubed/gameplay/chunk_generator.hpp +++ b/include/Cubed/gameplay/chunk_generator.hpp @@ -4,7 +4,6 @@ #include "Cubed/gameplay/biome.hpp" #include "Cubed/gameplay/block.hpp" #include "Cubed/gameplay/builders/biome_builder.hpp" -#include "Cubed/gameplay/path_point.hpp" #include "Cubed/tools/cubed_random.hpp" #include @@ -62,9 +61,6 @@ private: unsigned m_chunk_seed = 0; void make_biome_builder(); - void - carve_worm(const std::vector& points, const ChunkPos& chunk_pos, - std::function on_hit); }; } // namespace Cubed \ No newline at end of file diff --git a/include/Cubed/gameplay/path.hpp b/include/Cubed/gameplay/path.hpp new file mode 100644 index 0000000..8eaf66d --- /dev/null +++ b/include/Cubed/gameplay/path.hpp @@ -0,0 +1,8 @@ +#pragma once +#include + +struct PathOrigin { + bool exists; + glm::vec3 pos; + unsigned seed; +}; \ No newline at end of file diff --git a/include/Cubed/gameplay/river.path.hpp b/include/Cubed/gameplay/river.path.hpp index cd3c215..8e44c15 100644 --- a/include/Cubed/gameplay/river.path.hpp +++ b/include/Cubed/gameplay/river.path.hpp @@ -16,8 +16,6 @@ public: RiverPath(unsigned int chunk_seed, unsigned world_seed, const glm::vec3& start_pos); const std::vector& points() const; - void clear_chunk(const ChunkPos& pos); - bool is_finished() const; static float& radius_xz_min(); static float& radius_xz_max(); @@ -27,6 +25,7 @@ public: static float& delta_angle_max(); static int& step_min(); static int& step_max(); + static float step_len(); private: static inline float m_radius_xz_min = 5.0f; @@ -37,13 +36,12 @@ private: static inline float m_delta_angle_max = 3.0f; static inline int m_step_min = 200; static inline int m_step_max = 400; - + static inline float m_step_len = 4.0f; unsigned int m_seed = 0; float m_yaw = 0.0f; float m_initial_yaw = 0.0f; float m_pitch = 0.0f; int m_step = 0; - float m_step_len = 1.0f; PathPoint m_start_path_point{{0.0f, 0.0f, 0.0f}, 0.0f, 0.0f}; Random m_random; diff --git a/include/Cubed/gameplay/river_worm.hpp b/include/Cubed/gameplay/river_worm.hpp index cdcdec8..44535aa 100644 --- a/include/Cubed/gameplay/river_worm.hpp +++ b/include/Cubed/gameplay/river_worm.hpp @@ -1,37 +1,32 @@ #pragma once #include "Cubed/gameplay/chunk_pos.hpp" -#include "Cubed/gameplay/river.path.hpp" +#include "Cubed/gameplay/path.hpp" #include "Cubed/tools/cubed_random.hpp" #include -#include #include - namespace Cubed { class RiverWorm { - using RiverHashMap = tbb::concurrent_hash_map; public: RiverWorm(); ~RiverWorm(); - RiverHashMap& paths(); + void init(unsigned world_seed); void reload(unsigned world_seed); - void add_path(const glm::vec3& pos, unsigned chunk_seed); - void try_to_add_path(const ChunkPos& pos, unsigned chunk_seed); - void cleanup_finished_rivers(); - int river_sum() const; - float& river_probability(); - std::shared_mutex& paths_mutex(); + PathOrigin get_origin(const ChunkPos& origin_chunk) const; + int search_radius() const; + unsigned world_seed() const; + + float river_probability() const; + bool has_origin_fast(const ChunkPos& pos) const; private: - RiverHashMap m_paths; - unsigned m_seed = 0; + std::atomic m_world_seed{0}; Random m_random; - float m_probability = 0.01f; - std::shared_mutex m_paths_mutex; + std::atomic m_probability{0.01f}; }; }; // namespace Cubed \ No newline at end of file diff --git a/include/Cubed/gameplay/world.hpp b/include/Cubed/gameplay/world.hpp index 1d22473..a789752 100644 --- a/include/Cubed/gameplay/world.hpp +++ b/include/Cubed/gameplay/world.hpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -67,7 +68,7 @@ private: std::atomic m_day_tick = 6000; - mutable std::mutex m_chunks_mutex; + mutable std::shared_mutex m_chunks_mutex; std::mutex m_gen_signal_mutex; std::mutex m_new_chunk_mutex; std::mutex m_delete_vbo_mutex; @@ -83,7 +84,6 @@ private: std::atomic m_could_gen{true}; std::atomic m_tick_running{true}; std::atomic m_rendering_distance{24}; - std::atomic m_chunk_gen_fraction{0.0f}; std::atomic m_pool_threads{0}; std::atomic m_max_threads{1}; std::atomic m_game_ticks{0}; @@ -100,8 +100,7 @@ private: void gen_chunks_internal(); void sync_player_pos(glm::vec3& player_pos); - void compute_required_chunks(ChunkPosSet& required_chunks, - ChunkPairVector& temp_neighbor); + void compute_required_chunks(ChunkPosSet& required_chunks); void sync_and_collect_missing_chunks(std::vector&, const ChunkPosSet&); @@ -118,7 +117,7 @@ public: const std::optional& get_look_block_pos(const std::string& name) const; - const Chunk* get_chunk(const ChunkPos& pos) const; + // const Chunk* get_chunk(const ChunkPos& pos) const; Player& get_player(const std::string& name); void init_world(); @@ -139,7 +138,6 @@ public: void rebuild_world(); - float chunk_gen_fraction() const; int rendering_distance() const; void rendering_distance(int rendering_distance); void start_gen_thread(); @@ -169,6 +167,7 @@ public: void change_pool_threads(int threads); int chunk_load_style() const; void set_chunk_load_style(int id); + ChunkInfo get_chunk_info(const glm::vec3& world_pos) const; }; } // namespace Cubed diff --git a/src/dev_panel.cpp b/src/dev_panel.cpp index 549b06f..c421a21 100644 --- a/src/dev_panel.cpp +++ b/src/dev_panel.cpp @@ -2,7 +2,9 @@ #include "Cubed/app.hpp" #include "Cubed/config.hpp" +#include "Cubed/gameplay/cave_path.hpp" #include "Cubed/gameplay/player.hpp" +#include "Cubed/gameplay/river.path.hpp" #include "Cubed/tools/log.hpp" #include @@ -33,8 +35,8 @@ constexpr int AMPLITUDE_MAX = 80; constexpr float TREE_FREQ_MIM = 0.001f; constexpr float TREE_FREQ_MAX = 0.3f; -constexpr float PATH_PROBABILITY_MIN = 0.005f; -constexpr float PATH_PROBABILITY_MAX = 0.1f; +// constexpr float PATH_PROBABILITY_MIN = 0.005f; +// constexpr float PATH_PROBABILITY_MAX = 0.1f; constexpr float RADIUS_XZ_MIN = 1.0f; constexpr float RADIUS_XZ_MAX = 50.0f; constexpr float RADIUS_Y_MIN = 1.0f; @@ -291,11 +293,11 @@ void DevPanel::show_time_table_bar() { } void DevPanel::show_cave_table_bar() { - auto& cave_carcer = m_app.world().cave_carcer(); + // auto& cave_carcer = m_app.world().cave_carcer(); - ImGui::Text("Total Cave Sum %d", cave_carcer.cave_sum()); - ImGui::SliderFloat("Cave Probability", &cave_carcer.cave_probability(), - PATH_PROBABILITY_MIN, PATH_PROBABILITY_MAX); + // ImGui::Text("Total Cave Sum %d", cave_carcer.cave_sum()); + // ImGui::SliderFloat("Cave Probability", &cave_carcer.cave_probability(), + // PATH_PROBABILITY_MIN, PATH_PROBABILITY_MAX); ImGui::SliderFloat("Radius XZ Min", &CavePath::radius_xz_min(), RADIUS_XZ_MIN, RADIUS_XZ_MAX); ImGui::SliderFloat("Radius XZ Max", &CavePath::radius_xz_max(), @@ -315,11 +317,11 @@ void DevPanel::show_cave_table_bar() { } void DevPanel::show_river_table_bar() { - auto& river_wrom = m_app.world().river_worm(); + // auto& river_wrom = m_app.world().river_worm(); - ImGui::Text("Total River Sum %d", river_wrom.river_sum()); - ImGui::SliderFloat("River Probability", &river_wrom.river_probability(), - PATH_PROBABILITY_MIN, PATH_PROBABILITY_MAX); + // ImGui::Text("Total River Sum %d", river_wrom.river_sum()); + // ImGui::SliderFloat("River Probability", &river_wrom.river_probability(), + // PATH_PROBABILITY_MIN, PATH_PROBABILITY_MAX); ImGui::SliderFloat("Radius XZ Min##river", &RiverPath::radius_xz_min(), RADIUS_XZ_MIN, RADIUS_XZ_MAX); ImGui::SliderFloat("Radius XZ Max##river", &RiverPath::radius_xz_max(), @@ -338,6 +340,20 @@ void DevPanel::show_river_table_bar() { PATH_STEP_MAX); } +void DevPanel::show_chunk_table_bar() { + auto& world = m_app.world(); + auto& player = world.get_player("TestPlayer"); + auto info = world.get_chunk_info(player.get_player_pos()); + + ImGui::Text("Chunk X: %d Z: %d Info", info.pos.x, info.pos.z); + ImGui::Text("Seed: %u", info.seed); + ImGui::Text("%s", ("Biome " + get_biome_str(info.biome)).c_str()); + ImGui::Text("First Random %u", info.first_random); + ImGui::Text("%s", + std::format("Has Cave Start {}", info.has_cave_start).c_str()); + ImGui::Text("%s", std::format("Has Cave {}", info.has_cave).c_str()); +} + void DevPanel::show_settings_tab_item() { if (ImGui::BeginTabItem("settings")) { if (ImGui::SliderFloat("FOV", &m_config.fov, 1.0f, 140.0f)) { @@ -505,13 +521,15 @@ void DevPanel::show_world_tab_item() { m_app.world().stop_gen_thread(); } } - ImGui::Text("Chunk Build Progress\n"); - ImGui::ProgressBar(m_app.world().chunk_gen_fraction()); + // ImGui::Text("Chunk Build Progress\n"); + // ImGui::ProgressBar(m_app.world().chunk_gen_fraction()); + show_chunk_table_bar(); if (ImGui::BeginTabBar("World Settings")) { if (ImGui::BeginTabItem("Time")) { show_time_table_bar(); ImGui::EndTabItem(); } + /* if (ImGui::BeginTabItem("Cave")) { show_cave_table_bar(); ImGui::EndTabItem(); @@ -519,11 +537,12 @@ void DevPanel::show_world_tab_item() { if (ImGui::BeginTabItem("River")) { show_river_table_bar(); ImGui::EndTabItem(); - } + }*/ if (ImGui::BeginTabItem("Biome")) { show_biome_table_bar(); ImGui::EndTabItem(); } + ImGui::EndTabBar(); } ImGui::EndTabItem(); diff --git a/src/gameplay/cave_carver.cpp b/src/gameplay/cave_carver.cpp index ef4a7f9..60582de 100644 --- a/src/gameplay/cave_carver.cpp +++ b/src/gameplay/cave_carver.cpp @@ -1,67 +1,55 @@ #include "Cubed/gameplay/cave_carver.hpp" #include "Cubed/constants.hpp" - +#include "Cubed/gameplay/cave_path.hpp" +#include "Cubed/tools/cubed_hash.hpp" +#include "Cubed/tools/cubed_random.hpp" namespace Cubed { CaveCarver::CaveCarver() {} -CaveCarver::CaveHashMap& CaveCarver::paths() { return m_paths; } - -void CaveCarver::init(unsigned world_seed) { - m_seed = world_seed; - m_random.init(m_seed); -} +void CaveCarver::init(unsigned world_seed) { m_world_seed = world_seed; } void CaveCarver::reload(unsigned world_seed) { - m_seed = world_seed; - m_paths.clear(); + + m_world_seed = world_seed; + init(world_seed); } -void CaveCarver::add_path(const glm::vec3& pos, unsigned chunk_seed) { - m_paths.emplace(chunk_seed, CavePath{chunk_seed, m_seed, pos}); +bool CaveCarver::has_origin_fast(const ChunkPos& pos) const { + unsigned h = HASH::combine_32(HASH::combine_32(pos.x, pos.z), m_world_seed); + + return (h & 0xFFFF) < static_cast(m_cave_probability * 0xFFFF); } -void CaveCarver::try_to_add_path(const ChunkPos& chunk_pos, - unsigned chunk_seed) { - { - CaveHashMap::const_accessor acc; - if (m_paths.find(acc, chunk_seed)) { - return; - } +PathOrigin CaveCarver::get_origin(const ChunkPos& origin_chunk) const { + // Quickly check if there is an origin point without constructing Random + if (!has_origin_fast(origin_chunk)) { + return {false, {}, 0}; } - + unsigned chunk_seed = + HASH::chunk_seed_hash(origin_chunk.x, origin_chunk.z, m_world_seed); Random random{chunk_seed}; - if (random.random_bool(static_cast(m_cave_probability))) { - const int CHUNK_MIN_X = chunk_pos.x * CHUNK_SIZE; - const int CHUNK_MIN_Z = chunk_pos.z * CHUNK_SIZE; - const int CHUNK_MAX_X = CHUNK_MIN_X + SIZE_X - 1; - const int CHUNK_MAX_Z = CHUNK_MIN_Z + SIZE_Z - 1; - const int CHUNK_MIN_Y = 0; - const int CHUNK_MAX_Y = SIZE_Y - 1; - int max_y = std::min(CHUNK_MAX_Y, 40); - int x = random.random_int(CHUNK_MIN_X, CHUNK_MAX_X); - int y = random.random_int(CHUNK_MIN_Y + 1, max_y); - int z = random.random_int(CHUNK_MIN_Z, CHUNK_MAX_Z); - add_path(glm::vec3{x, y, z}, chunk_seed); - } + const int CHUNK_MIN_X = origin_chunk.x * CHUNK_SIZE; + const int CHUNK_MIN_Z = origin_chunk.z * CHUNK_SIZE; + const int CHUNK_MAX_X = CHUNK_MIN_X + SIZE_X - 1; + const int CHUNK_MAX_Z = CHUNK_MIN_Z + SIZE_Z - 1; + const int CHUNK_MIN_Y = 0; + const int CHUNK_MAX_Y = SIZE_Y - 1; + int max_y = std::min(CHUNK_MAX_Y, 40); + int x = random.random_int(CHUNK_MIN_X, CHUNK_MAX_X); + int y = random.random_int(CHUNK_MIN_Y + 1, max_y); + int z = random.random_int(CHUNK_MIN_Z, CHUNK_MAX_Z); + return {true, {x, y, z}, chunk_seed}; } -void CaveCarver::cleanup_finished_caves() { - std::vector finished_keys; - - for (const auto& pair : m_paths) { - if (pair.second.is_finished()) { - finished_keys.push_back(pair.first); - } - } - - for (const auto& key : finished_keys) { - m_paths.erase(key); - } +int CaveCarver::search_radius() const { + float max_displacement = + 3.0f * std::sqrt(static_cast(CavePath::step_max())) * + CavePath::step_len(); + return static_cast( + std::ceil((max_displacement + CavePath::radius_xz_max()) / CHUNK_SIZE)); } - -int CaveCarver::cave_sum() const { return m_paths.size(); } -float& CaveCarver::cave_probability() { return m_cave_probability; } -std::shared_mutex& CaveCarver::path_mutex() { return m_path_mutex; } +unsigned CaveCarver::world_seed() const { return m_world_seed; } +float CaveCarver::cave_probability() const { return m_cave_probability; } } // namespace Cubed \ No newline at end of file diff --git a/src/gameplay/cave_path.cpp b/src/gameplay/cave_path.cpp index 5792f9a..bb3cbf5 100644 --- a/src/gameplay/cave_path.cpp +++ b/src/gameplay/cave_path.cpp @@ -1,6 +1,5 @@ #include "Cubed/gameplay/cave_path.hpp" -#include "Cubed/constants.hpp" #include "Cubed/tools/cubed_hash.hpp" #include "Cubed/tools/math_tools.hpp" @@ -21,15 +20,12 @@ CavePath::CavePath(unsigned int chunk_seed, unsigned world_seed, m_points.reserve(m_step + 1); m_points.push_back(m_start_path_point); collect_path_points(); - precompute_chunk_coverage(); } void CavePath::collect_path_points() { + for (int i = 0; i < m_step; i++) { - m_yaw = std::fmod(m_yaw, 360.0f); - if (m_yaw < 0.0f) - m_yaw += 360.0f; m_pitch = std::clamp(m_pitch, -90.0f, 90.0f); float dx = std::cos(glm::radians(m_pitch)) * @@ -58,30 +54,7 @@ void CavePath::collect_path_points() { } } -void CavePath::precompute_chunk_coverage() { - for (const auto& point : m_points) { - float rad = point.rad_xz; - const glm::vec3& center = point.pos; - - int min_cx = - static_cast(std::floor((center.x - rad) / CHUNK_SIZE)); - int max_cx = - static_cast(std::floor((center.x + rad) / CHUNK_SIZE)); - int min_cz = - static_cast(std::floor((center.z - rad) / CHUNK_SIZE)); - int max_cz = - static_cast(std::floor((center.z + rad) / CHUNK_SIZE)); - - for (int cx = min_cx; cx <= max_cx; ++cx) - for (int cz = min_cz; cz <= max_cz; ++cz) - m_pending_chunks.insert( - std::make_pair(ChunkPos{cx, cz}, false)); - } -} - -void CavePath::clear_chunk(const ChunkPos& pos) { m_pending_chunks.erase(pos); } const std::vector& CavePath::points() const { return m_points; } -bool CavePath::is_finished() const { return m_pending_chunks.empty(); } float& CavePath::radius_xz_min() { return m_radius_xz_min; } float& CavePath::radius_xz_max() { return m_radius_xz_max; } @@ -91,5 +64,5 @@ float& CavePath::delta_angle_min() { return m_delta_angle_min; } float& CavePath::delta_angle_max() { return m_delta_angle_max; } int& CavePath::step_min() { return m_step_min; } int& CavePath::step_max() { return m_step_max; } - +int CavePath::step_len() { return m_step_len; } } // namespace Cubed diff --git a/src/gameplay/chunk.cpp b/src/gameplay/chunk.cpp index 58f5758..9237d3a 100644 --- a/src/gameplay/chunk.cpp +++ b/src/gameplay/chunk.cpp @@ -24,7 +24,7 @@ Chunk::Chunk(Chunk&& other) noexcept m_world(other.m_world), m_heightmap(std::move(other.m_heightmap)), m_blocks(std::move(other.m_blocks)), m_vertex_data(std::move(other.m_vertex_data)), m_seed(other.m_seed), - m_conditions(other.m_conditions) {} + m_conditions(other.m_conditions), m_info(std::move(other.m_info)) {} Chunk& Chunk::operator=(Chunk&& other) noexcept { // Logger::info("other Chunk pos {} {} in Chunk& Chunk::operator=(Chunk&& @@ -41,6 +41,7 @@ Chunk& Chunk::operator=(Chunk&& other) noexcept { m_need_upload = other.m_need_upload.load(); m_seed = other.m_seed; m_conditions = other.m_conditions; + m_info = std::move(other.m_info); return *this; } @@ -269,6 +270,13 @@ unsigned Chunk::seed() const { BiomeConditions& Chunk::conditions() { return m_conditions; } +ChunkInfo Chunk::get_info() const { + if (m_gening) { + return ChunkInfo{}; + } + return m_info; +} + void Chunk::gen_vertices(const OptionalBlockVectorArray& neighbor_block) { static const glm::ivec3 DIR[6] = {{0, 0, 1}, {1, 0, 0}, {0, 0, -1}, {-1, 0, 0}, {0, 1, 0}, {0, -1, 0}}; @@ -488,9 +496,22 @@ void Chunk::gen_chunk() { neightbor_blocks[i] = neighbor[i].get_chunk_blocks(); } gen_vertex_data(neightbor_blocks); + + // collect chunk info for debugging + m_info.biome = m_biome; + m_info.pos = m_chunk_pos; + m_info.seed = m_seed; + Random r(m_seed); + unsigned first = r.engine()(); + m_info.first_random = first; + r.init(m_seed); + m_info.has_cave_start = r.random_bool(DEFAULT_CAVE_PROBABILITY); + m_info.has_cave = m_has_cave; } // Logger::info("Cross Sum {}", m_cross_vertices_sum.load()); bool Chunk::is_temp_chunk() const { return m_temp_chunk.load(); } +bool& Chunk::has_cave() { return m_has_cave; } + } // namespace Cubed diff --git a/src/gameplay/chunk_generator.cpp b/src/gameplay/chunk_generator.cpp index 4af079f..0868a13 100644 --- a/src/gameplay/chunk_generator.cpp +++ b/src/gameplay/chunk_generator.cpp @@ -7,7 +7,9 @@ #include "Cubed/gameplay/builders/plain_builder.hpp" #include "Cubed/gameplay/builders/river_builder.hpp" #include "Cubed/gameplay/builders/snowy_plain_builder.hpp" +#include "Cubed/gameplay/cave_path.hpp" #include "Cubed/gameplay/chunk.hpp" +#include "Cubed/gameplay/river.path.hpp" #include "Cubed/gameplay/tree.hpp" #include "Cubed/gameplay/world.hpp" #include "Cubed/tools/cubed_assert.hpp" @@ -16,6 +18,84 @@ #include "Cubed/tools/perlin_noise.hpp" namespace Cubed { +namespace { +template +void carve_worm(const std::vector& points, const ChunkPos& chunk_pos, + F&& on_hit) { + const int CHUNK_MIN_X = chunk_pos.x * CHUNK_SIZE; + const int CHUNK_MIN_Z = chunk_pos.z * CHUNK_SIZE; + const int CHUNK_MAX_X = CHUNK_MIN_X + SIZE_X - 1; + const int CHUNK_MAX_Z = CHUNK_MIN_Z + SIZE_Z - 1; + const int CHUNK_MIN_Y = 0; + const int CHUNK_MAX_Y = SIZE_Y - 1; + for (const auto& point : points) { + + const glm::vec3& center = point.pos; + float rad_xz = point.rad_xz; + float rad_y = point.rad_y; + + if (center.x + rad_xz < CHUNK_MIN_X || + center.x - rad_xz > CHUNK_MAX_X || + center.z + rad_xz < CHUNK_MIN_Z || + center.z - rad_xz > CHUNK_MAX_Z || center.y + rad_y < CHUNK_MIN_Y || + center.y - rad_y > CHUNK_MAX_Y) { + continue; + } + + int min_x = static_cast(std::floor(center.x - rad_xz)); + int max_x = static_cast(std::floor(center.x + rad_xz)); + int min_z = static_cast(std::floor(center.z - rad_xz)); + int max_z = static_cast(std::floor(center.z + rad_xz)); + int min_y = static_cast(std::floor(center.y - rad_y)); + int max_y = static_cast(std::floor(center.y + rad_y)); + + min_x = std::max(min_x, CHUNK_MIN_X); + max_x = std::min(max_x, CHUNK_MAX_X); + min_z = std::max(min_z, CHUNK_MIN_Z); + max_z = std::min(max_z, CHUNK_MAX_Z); + min_y = std::max(min_y, CHUNK_MIN_Y); + max_y = std::min(max_y, CHUNK_MAX_Y); + + glm::vec3 right_raw = + glm::cross(point.tangent, glm::vec3(0.0f, 1.0f, 0.0f)); + if (glm::dot(right_raw, right_raw) < 1e-6f) + right_raw = glm::cross(point.tangent, glm::vec3(1.0f, 0.0f, 0.0f)); + glm::vec3 right = glm::normalize(right_raw); + glm::vec3 up = glm::normalize(glm::cross(point.tangent, right)); + + float inv_a2 = 1.0f / (point.rad_xz * point.rad_xz); + float inv_b2 = 1.0f / (point.rad_y * point.rad_y); + + for (int wy = min_y; wy <= max_y; ++wy) { + if (wy == 0) + continue; + float dy = static_cast(wy) - point.pos.y; + + float vy_contrib = dy * up.y; + float vy2 = vy_contrib * vy_contrib * inv_b2; + if (vy2 >= 1.0f) + continue; + + for (int wx = min_x; wx <= max_x; ++wx) { + float dx = static_cast(wx) - point.pos.x; + for (int wz = min_z; wz <= max_z; ++wz) { + float dz = static_cast(wz) - point.pos.z; + glm::vec3 to_point(dx, dy, dz); + + float h = glm::dot(to_point, right); + float v = glm::dot(to_point, up); + + if (h * h * inv_a2 + v * v * inv_b2 > 1.0f) + continue; + int x = wx - CHUNK_MIN_X; + on_hit(x, wy, wz - CHUNK_MIN_Z); + } + } + } + } +} +} // namespace + using enum BiomeType; constexpr int BLEND_RADIUS = 8; @@ -642,94 +722,27 @@ void ChunkGenerator::make_biome_builder() { void ChunkGenerator::ocean_build() { m_biome_builder->ocean_water_build(); } -void ChunkGenerator::carve_worm( - const std::vector& points, const ChunkPos& chunk_pos, - std::function on_hit) { - const int CHUNK_MIN_X = chunk_pos.x * CHUNK_SIZE; - const int CHUNK_MIN_Z = chunk_pos.z * CHUNK_SIZE; - const int CHUNK_MAX_X = CHUNK_MIN_X + SIZE_X - 1; - const int CHUNK_MAX_Z = CHUNK_MIN_Z + SIZE_Z - 1; - const int CHUNK_MIN_Y = 0; - const int CHUNK_MAX_Y = SIZE_Y - 1; - for (const auto& point : points) { - - const glm::vec3& center = point.pos; - float rad_xz = point.rad_xz; - float rad_y = point.rad_y; - - if (center.x + rad_xz < CHUNK_MIN_X || - center.x - rad_xz > CHUNK_MAX_X || - center.z + rad_xz < CHUNK_MIN_Z || - center.z - rad_xz > CHUNK_MAX_Z || center.y + rad_y < CHUNK_MIN_Y || - center.y - rad_y > CHUNK_MAX_Y) { - continue; - } - - int min_x = static_cast(std::floor(center.x - rad_xz)); - int max_x = static_cast(std::floor(center.x + rad_xz)); - int min_z = static_cast(std::floor(center.z - rad_xz)); - int max_z = static_cast(std::floor(center.z + rad_xz)); - int min_y = static_cast(std::floor(center.y - rad_y)); - int max_y = static_cast(std::floor(center.y + rad_y)); - - min_x = std::max(min_x, CHUNK_MIN_X); - max_x = std::min(max_x, CHUNK_MAX_X); - min_z = std::max(min_z, CHUNK_MIN_Z); - max_z = std::min(max_z, CHUNK_MAX_Z); - min_y = std::max(min_y, CHUNK_MIN_Y); - max_y = std::min(max_y, CHUNK_MAX_Y); - - glm::vec3 right_raw = - glm::cross(point.tangent, glm::vec3(0.0f, 1.0f, 0.0f)); - if (glm::dot(right_raw, right_raw) < 1e-6f) - right_raw = glm::cross(point.tangent, glm::vec3(1.0f, 0.0f, 0.0f)); - glm::vec3 right = glm::normalize(right_raw); - glm::vec3 up = glm::normalize(glm::cross(point.tangent, right)); - - float inv_a2 = 1.0f / (point.rad_xz * point.rad_xz); - float inv_b2 = 1.0f / (point.rad_y * point.rad_y); - - for (int wy = min_y; wy <= max_y; ++wy) { - if (wy == 0) - continue; - float dy = static_cast(wy) - point.pos.y; - - float vy_contrib = dy * up.y; - float vy2 = vy_contrib * vy_contrib * inv_b2; - if (vy2 >= 1.0f) - continue; - - for (int wx = min_x; wx <= max_x; ++wx) { - float dx = static_cast(wx) - point.pos.x; - for (int wz = min_z; wz <= max_z; ++wz) { - float dz = static_cast(wz) - point.pos.z; - glm::vec3 to_point(dx, dy, dz); - - float h = glm::dot(to_point, right); - float v = glm::dot(to_point, up); - - if (h * h * inv_a2 + v * v * inv_b2 > 1.0f) - continue; - int x = wx - CHUNK_MIN_X; - on_hit(x, wy, wz - CHUNK_MIN_Z); - } - } - } - } -} - void ChunkGenerator::generate_cave() { - auto& cave_carver = m_chunk.world().cave_carcer(); - auto& paths = cave_carver.paths(); const auto& chunk_pos = m_chunk.chunk_pos(); auto& blocks = m_chunk.blocks(); - { - std::shared_lock lock(cave_carver.path_mutex()); - for (auto& [id, path] : paths) { + auto& carver = m_chunk.world().cave_carcer(); + + int search_r = carver.search_radius(); + for (int dx = -search_r; dx <= search_r; dx++) { + for (int dz = -search_r; dz <= search_r; dz++) { + ChunkPos origin_pos{chunk_pos.x + dx, chunk_pos.z + dz}; + auto origin = carver.get_origin(origin_pos); + if (!origin.exists) + continue; + + // Deterministically reconstruct this path (lightweight: only + // compute points, no storage). + CavePath path{origin.seed, carver.world_seed(), origin.pos}; carve_worm(path.points(), chunk_pos, [&](int x, int y, int z) -> void { int idx = Chunk::index(x, y, z); + m_chunk.has_cave() = true; if (blocks[idx] == 7) return; if (y < WORLD_SIZE_Y - 1 && @@ -737,30 +750,34 @@ void ChunkGenerator::generate_cave() { return; blocks[idx] = 0; }); - if (!m_chunk.is_temp_chunk()) { - path.clear_chunk(chunk_pos); - } } } } void ChunkGenerator::generate_river() { + if ((m_chunk.biome() == BiomeType::DESERT) || + (m_chunk.biome() == BiomeType::OCEAN)) { + return; + } auto& river_worm = m_chunk.world().river_worm(); - auto& paths = river_worm.paths(); + const auto& chunk_pos = m_chunk.chunk_pos(); auto& blocks = m_chunk.blocks(); bool is_river = false; - { - std::shared_lock lock(river_worm.paths_mutex()); - for (auto& [id, path] : paths) { - if ((m_chunk.biome() == BiomeType::DESERT) || - (m_chunk.biome() == BiomeType::OCEAN)) { - if (!m_chunk.is_temp_chunk()) { - path.clear_chunk(chunk_pos); - } + int search_r = river_worm.search_radius(); + + for (int dx = -search_r; dx <= search_r; dx++) { + for (int dz = -search_r; dz <= search_r; dz++) { + ChunkPos origin_pos{chunk_pos.x + dx, chunk_pos.z + dz}; + auto origin = river_worm.get_origin(origin_pos); + if (!origin.exists) continue; - } + + // Deterministically reconstruct this path (lightweight: only + // compute points, no storage). + RiverPath path{origin.seed, river_worm.world_seed(), origin.pos}; + carve_worm(path.points(), chunk_pos, [&](int x, int y, int z) -> void { int idx = Chunk::index(x, y, z); @@ -774,9 +791,6 @@ void ChunkGenerator::generate_river() { } blocks[idx] = 7; }); - if (!m_chunk.is_temp_chunk()) { - path.clear_chunk(chunk_pos); - } } } diff --git a/src/gameplay/player.cpp b/src/gameplay/player.cpp index af9debc..9bad20d 100644 --- a/src/gameplay/player.cpp +++ b/src/gameplay/player.cpp @@ -251,13 +251,6 @@ void Player::check_player_chunk_transition() { if (cur_pos != m_player_chunk_pos) { m_world.need_gen(); m_player_chunk_pos = cur_pos; - auto chunk = m_world.get_chunk(cur_pos); - if (chunk == nullptr) { - DebugCollector::get().report("biome", "Biome: Unknown"); - } else { - DebugCollector::get().report( - "biome", "Biome: " + get_biome_str(chunk->get_biome())); - } } } diff --git a/src/gameplay/river_path.cpp b/src/gameplay/river_path.cpp index 1d797e3..f4e6cfd 100644 --- a/src/gameplay/river_path.cpp +++ b/src/gameplay/river_path.cpp @@ -1,4 +1,3 @@ -#include "Cubed/constants.hpp" #include "Cubed/gameplay/river.path.hpp" #include "Cubed/tools/cubed_hash.hpp" #include "Cubed/tools/math_tools.hpp" @@ -24,16 +23,11 @@ RiverPath::RiverPath(unsigned int chunk_seed, unsigned world_seed, m_points.reserve(m_step + 1); m_points.push_back(m_start_path_point); collect_path_points(); - precompute_chunk_coverage(); } void RiverPath::collect_path_points() { for (int i = 0; i < m_step; i++) { - m_yaw = std::fmod(m_yaw, 360.0f); - if (m_yaw < 0.0f) - m_yaw += 360.0f; - float dx = std::cos(glm::radians(m_pitch)) * std::sin(glm::radians(m_yaw)) * m_step_len; float dy = std::sin(glm::radians(m_pitch)) * m_step_len; @@ -60,33 +54,7 @@ void RiverPath::collect_path_points() { } } -void RiverPath::precompute_chunk_coverage() { - for (const auto& point : m_points) { - float rad = point.rad_xz; - const glm::vec3& center = point.pos; - - int min_cx = - static_cast(std::floor((center.x - rad) / CHUNK_SIZE)); - int max_cx = - static_cast(std::floor((center.x + rad) / CHUNK_SIZE)); - int min_cz = - static_cast(std::floor((center.z - rad) / CHUNK_SIZE)); - int max_cz = - static_cast(std::floor((center.z + rad) / CHUNK_SIZE)); - - for (int cx = min_cx; cx <= max_cx; ++cx) - for (int cz = min_cz; cz <= max_cz; ++cz) - m_pending_chunks.insert( - std::make_pair(ChunkPos{cx, cz}, false)); - } -} - -void RiverPath::clear_chunk(const ChunkPos& pos) { - m_pending_chunks.erase(pos); -} const std::vector& RiverPath::points() const { return m_points; } -bool RiverPath::is_finished() const { return m_pending_chunks.empty(); } - float& RiverPath::radius_xz_min() { return m_radius_xz_min; } float& RiverPath::radius_xz_max() { return m_radius_xz_max; } float& RiverPath::radius_y_min() { return m_radius_y_min; } @@ -95,4 +63,5 @@ float& RiverPath::delta_angle_min() { return m_delta_angle_min; } float& RiverPath::delta_angle_max() { return m_delta_angle_max; } int& RiverPath::step_min() { return m_step_min; } int& RiverPath::step_max() { return m_step_max; } +float RiverPath::step_len() { return m_step_len; } } // namespace Cubed \ No newline at end of file diff --git a/src/gameplay/river_worm.cpp b/src/gameplay/river_worm.cpp index 1e5ef93..5a1010a 100644 --- a/src/gameplay/river_worm.cpp +++ b/src/gameplay/river_worm.cpp @@ -1,65 +1,59 @@ #include "Cubed/gameplay/river_worm.hpp" #include "Cubed/constants.hpp" - +#include "Cubed/gameplay/river.path.hpp" +#include "Cubed/tools/cubed_hash.hpp" namespace Cubed { RiverWorm::RiverWorm() {} RiverWorm::~RiverWorm() {} -RiverWorm::RiverHashMap& RiverWorm::paths() { return m_paths; } void RiverWorm::init(unsigned world_seed) { - m_seed = world_seed; + m_world_seed = world_seed; - m_random.init(m_seed); + m_random.init(m_world_seed); } void RiverWorm::reload(unsigned world_seed) { - m_seed = world_seed; - m_paths.clear(); + + m_world_seed = world_seed; + init(world_seed); } -void RiverWorm::add_path(const glm::vec3& pos, unsigned chunk_seed) { - m_paths.emplace(chunk_seed, RiverPath{chunk_seed, m_seed, pos}); +bool RiverWorm::has_origin_fast(const ChunkPos& pos) const { + unsigned h = HASH::combine_32(HASH::combine_32(pos.x, pos.z), m_world_seed); + + return (h & 0xFFFF) < static_cast(m_probability * 0xFFFF); } -void RiverWorm::try_to_add_path(const ChunkPos& chunk_pos, - unsigned chunk_seed) { - { - RiverHashMap::const_accessor acc; - if (m_paths.find(acc, chunk_seed)) { - return; - } +PathOrigin RiverWorm::get_origin(const ChunkPos& origin_chunk) const { + // Quickly check if there is an origin point without constructing Random + if (!has_origin_fast(origin_chunk)) { + return {false, {}, 0}; } + + unsigned chunk_seed = + HASH::chunk_seed_hash(origin_chunk.x, origin_chunk.z, m_world_seed); Random random{chunk_seed}; - if (random.random_bool(static_cast(m_probability))) { - const int CHUNK_MIN_X = chunk_pos.x * CHUNK_SIZE; - const int CHUNK_MIN_Z = chunk_pos.z * CHUNK_SIZE; - const int CHUNK_MAX_X = CHUNK_MIN_X + SIZE_X - 1; - const int CHUNK_MAX_Z = CHUNK_MIN_Z + SIZE_Z - 1; - int x = random.random_int(CHUNK_MIN_X, CHUNK_MAX_X); - int y = SEA_LEVEL + 2; - int z = random.random_int(CHUNK_MIN_Z, CHUNK_MAX_Z); - add_path(glm::vec3{x, y, z}, chunk_seed); - } + + const int CHUNK_MIN_X = origin_chunk.x * CHUNK_SIZE; + const int CHUNK_MIN_Z = origin_chunk.z * CHUNK_SIZE; + const int CHUNK_MAX_X = CHUNK_MIN_X + SIZE_X - 1; + const int CHUNK_MAX_Z = CHUNK_MIN_Z + SIZE_Z - 1; + int x = random.random_int(CHUNK_MIN_X, CHUNK_MAX_X); + int y = SEA_LEVEL + 2; + int z = random.random_int(CHUNK_MIN_Z, CHUNK_MAX_Z); + return {true, {x, y, z}, chunk_seed}; } -void RiverWorm::cleanup_finished_rivers() { - std::vector finished_keys; - - for (const auto& pair : m_paths) { - if (pair.second.is_finished()) { - finished_keys.push_back(pair.first); - } - } - - for (const auto& key : finished_keys) { - m_paths.erase(key); - } +int RiverWorm::search_radius() const { + float max_displacement = + 3.0f * std::sqrt(static_cast(RiverPath::step_max())) * + RiverPath::step_len(); + return static_cast(std::ceil( + (max_displacement + RiverPath::radius_xz_max()) / CHUNK_SIZE)); } - -int RiverWorm::river_sum() const { return m_paths.size(); } -float& RiverWorm::river_probability() { return m_probability; } -std::shared_mutex& RiverWorm::paths_mutex() { return m_paths_mutex; } +unsigned RiverWorm::world_seed() const { return m_world_seed; } +float RiverWorm::river_probability() const { return m_probability; } } // namespace Cubed \ No newline at end of file diff --git a/src/gameplay/world.cpp b/src/gameplay/world.cpp index b738fa9..338315b 100644 --- a/src/gameplay/world.cpp +++ b/src/gameplay/world.cpp @@ -63,7 +63,7 @@ World::get_look_block_pos(const std::string& name) const { return it->second.get_look_block_pos(); } - +/* const Chunk* World::get_chunk(const ChunkPos& pos) const { std::lock_guard lk(m_chunks_mutex); auto it = m_chunks.find(pos); @@ -71,7 +71,7 @@ const Chunk* World::get_chunk(const ChunkPos& pos) const { return nullptr; } return &it->second; -} +}*/ Player& World::get_player(const std::string& name) { auto it = m_players.find(HASH::str(name)); @@ -133,13 +133,10 @@ ChunkPos World::get_chunk_pos(int world_x, int world_z) { void World::gen_chunks_internal() { // Logger::info("gen_chunks_internal"); - m_chunk_gen_fraction = 0.0f; m_chunk_gen_finished = false; ChunkPosSet required_chunks; - ChunkPairVector temp_neighbor; - - compute_required_chunks(required_chunks, temp_neighbor); + compute_required_chunks(required_chunks); ASSERT_MSG(!required_chunks.empty(), "required chunks is empty!!"); @@ -148,43 +145,17 @@ void World::gen_chunks_internal() { sync_and_collect_missing_chunks(need_gen_chunks_pos, required_chunks); Logger::info("New Gen Chunks Sum: {}", need_gen_chunks_pos.size()); - Logger::info("Temp Chunks sum {}", temp_neighbor.size()); + if (need_gen_chunks_pos.empty()) { m_could_gen = true; - m_chunk_gen_fraction = 1.0f; + return; } - m_chunk_gen_fraction = 0.1f; for (auto& pos : need_gen_chunks_pos) { new_chunks.emplace(pos, Chunk(*this, pos)); } - auto t1 = system_clock::now(); - { - std::scoped_lock lock{m_cave_carcer.path_mutex(), - m_river_worm.paths_mutex()}; - auto pool_ptr = m_gen_thread_pool.load(); - if (!pool_ptr) { - return; - } - parallel_do(*pool_ptr, temp_neighbor.begin(), temp_neighbor.end(), - pool_ptr->thread_sum(), - [this](std::pair& new_chunk) { - auto& [pos, chunk] = new_chunk; - chunk.gen_phase_one(); - m_cave_carcer.try_to_add_path(pos, chunk.seed()); - m_river_worm.try_to_add_path(pos, chunk.seed()); - }); - m_cave_carcer.cleanup_finished_caves(); - m_river_worm.cleanup_finished_rivers(); - } - auto t2 = system_clock::now(); - Logger::info("Temp Neighbor Add Path Consum {}", - duration_cast(t2 - t1)); - m_chunk_gen_fraction = 0.9f; - - m_chunk_gen_fraction = 1.0f; submit_new_chunks(); m_chunk_gen_finished = true; } @@ -194,8 +165,7 @@ void World::sync_player_pos(glm::vec3& player_pos) { player_pos = m_gen_player_pos; } -void World::compute_required_chunks(ChunkPosSet& required_chunks, - ChunkPairVector& temp_neighbor) { +void World::compute_required_chunks(ChunkPosSet& required_chunks) { glm::vec3 player_pos; sync_player_pos(player_pos); @@ -213,17 +183,6 @@ void World::compute_required_chunks(ChunkPosSet& required_chunks, } } } - int max_path_len = std::max(CavePath::step_max(), RiverPath::step_max()); - radius = max_path_len / 2; - r2 = radius * radius; - for (int dx = -radius; dx <= radius; ++dx) { - for (int dz = -radius; dz <= radius; ++dz) { - if (dx * dx + dz * dz <= r2) { - ChunkPos pos{chunk_x + dx, chunk_z + dz}; - temp_neighbor.emplace_back(pos, Chunk(*this, pos)); - } - } - } } void World::sync_and_collect_missing_chunks( @@ -407,7 +366,7 @@ void World::need_gen() { int World::get_block(const glm::ivec3& block_pos) const { auto [chunk_x, chunk_z] = get_chunk_pos(block_pos.x, block_pos.z); - std::lock_guard lk(m_chunks_mutex); + std::shared_lock lk(m_chunks_mutex); auto it = m_chunks.find(ChunkPos{chunk_x, chunk_z}); if (it == m_chunks.end()) { @@ -425,7 +384,7 @@ int World::get_block(const glm::ivec3& block_pos) const { bool World::is_solid(const glm::ivec3& block_pos) const { auto [chunk_x, chunk_z] = get_chunk_pos(block_pos.x, block_pos.z); - std::lock_guard lk(m_chunks_mutex); + std::shared_lock lk(m_chunks_mutex); auto it = m_chunks.find(ChunkPos{chunk_x, chunk_z}); if (it == m_chunks.end()) { @@ -447,7 +406,7 @@ bool World::is_solid(const glm::ivec3& block_pos) const { bool World::can_pass_block(const glm::ivec3& block_pos) const { auto [chunk_x, chunk_z] = get_chunk_pos(block_pos.x, block_pos.z); - std::lock_guard lk(m_chunks_mutex); + std::shared_lock lk(m_chunks_mutex); auto it = m_chunks.find(ChunkPos{chunk_x, chunk_z}); if (it == m_chunks.end()) { @@ -465,7 +424,7 @@ bool World::can_pass_block(const glm::ivec3& block_pos) const { BlockType World::get_block_tpye(const glm::ivec3& block_pos) const { auto [chunk_x, chunk_z] = get_chunk_pos(block_pos.x, block_pos.z); - std::lock_guard lk(m_chunks_mutex); + std::shared_lock lk(m_chunks_mutex); auto it = m_chunks.find(ChunkPos{chunk_x, chunk_z}); if (it == m_chunks.end()) { @@ -629,7 +588,7 @@ void World::rebuild_world() { m_cave_carcer.reload(ChunkGenerator::seed()); m_river_worm.reload(ChunkGenerator::seed()); { - std::scoped_lock lk(m_chunks_mutex); + std::lock_guard lk(m_chunks_mutex); m_chunks.clear(); m_new_finished_chunk.clear(); } @@ -676,8 +635,6 @@ glm::vec3 World::sunlight_dir() const { return glm::normalize(-dir); } -float World::chunk_gen_fraction() const { return m_chunk_gen_fraction.load(); } - int World::rendering_distance() const { return m_rendering_distance.load(); } void World::rendering_distance(int rendering_distance) { @@ -732,4 +689,15 @@ void World::set_chunk_load_style(int id) { Logger::error("Can,t Find Chunk Load Style Id {}, Nothing Will Do", id); } +ChunkInfo World::get_chunk_info(const glm::vec3& world_pos) const { + ChunkPos pos = get_chunk_pos(world_pos.x, world_pos.z); + + std::shared_lock lock(m_chunks_mutex); + auto it = m_chunks.find(pos); + if (it == m_chunks.end()) { + return ChunkInfo{}; + } + return it->second.get_info(); +} + } // namespace Cubed \ No newline at end of file