diff --git a/include/Cubed/gameplay/cave_carver.hpp b/include/Cubed/gameplay/cave_carver.hpp index cbfea66..0f61bd2 100644 --- a/include/Cubed/gameplay/cave_carver.hpp +++ b/include/Cubed/gameplay/cave_carver.hpp @@ -17,11 +17,13 @@ public: int cave_sum() const; float& cave_probability(); + std::shared_mutex& path_mutex(); private: CaveHashMap m_paths; unsigned m_seed = 0; Random m_random; float m_cave_probability = 0.035f; + std::shared_mutex m_path_mutex; }; } // namespace Cubed diff --git a/include/Cubed/gameplay/river_worm.hpp b/include/Cubed/gameplay/river_worm.hpp index c2c4fa2..ae6b994 100644 --- a/include/Cubed/gameplay/river_worm.hpp +++ b/include/Cubed/gameplay/river_worm.hpp @@ -12,6 +12,7 @@ class RiverWorm { public: RiverWorm(); + ~RiverWorm(); RiverHashMap& paths(); void init(unsigned world_seed); void reload(unsigned world_seed); @@ -21,12 +22,14 @@ public: int river_sum() const; float& river_probability(); + std::shared_mutex& paths_mutex(); private: RiverHashMap m_paths; unsigned m_seed = 0; Random m_random; float m_probability = 0.01f; + std::shared_mutex m_paths_mutex; }; }; // namespace Cubed \ No newline at end of file diff --git a/include/Cubed/gameplay/world.hpp b/include/Cubed/gameplay/world.hpp index d24d413..38a0f64 100644 --- a/include/Cubed/gameplay/world.hpp +++ b/include/Cubed/gameplay/world.hpp @@ -104,6 +104,7 @@ private: void submit_new_chunks(); void poll_finished_chunks(); + void wait_all_chunk_tasks(); public: World(); diff --git a/include/Cubed/tools/thread_pool.hpp b/include/Cubed/tools/thread_pool.hpp index 0741d3f..49a3184 100644 --- a/include/Cubed/tools/thread_pool.hpp +++ b/include/Cubed/tools/thread_pool.hpp @@ -48,7 +48,14 @@ public: for (auto& w : m_workers) { w.request_stop(); } + m_cv.notify_all(); + + for (auto& w : m_workers) { + if (w.joinable()) { + w.join(); + } + } } template auto enqueue(F&& f) { diff --git a/src/gameplay/cave_carver.cpp b/src/gameplay/cave_carver.cpp index 2527a2f..ef4a7f9 100644 --- a/src/gameplay/cave_carver.cpp +++ b/src/gameplay/cave_carver.cpp @@ -63,5 +63,5 @@ void CaveCarver::cleanup_finished_caves() { 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; } } // namespace Cubed \ No newline at end of file diff --git a/src/gameplay/chunk_generator.cpp b/src/gameplay/chunk_generator.cpp index 1bb6b5e..4af079f 100644 --- a/src/gameplay/chunk_generator.cpp +++ b/src/gameplay/chunk_generator.cpp @@ -723,19 +723,23 @@ void ChunkGenerator::generate_cave() { 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) { - for (auto& [id, path] : paths) { - - carve_worm(path.points(), chunk_pos, [&](int x, int y, int z) -> void { - int idx = Chunk::index(x, y, z); - if (blocks[idx] == 7) - return; - if (y < WORLD_SIZE_Y - 1 && blocks[Chunk::index(x, y + 1, z)] == 7) - return; - blocks[idx] = 0; - }); - if (!m_chunk.is_temp_chunk()) { - path.clear_chunk(chunk_pos); + carve_worm(path.points(), chunk_pos, + [&](int x, int y, int z) -> void { + int idx = Chunk::index(x, y, z); + if (blocks[idx] == 7) + return; + if (y < WORLD_SIZE_Y - 1 && + blocks[Chunk::index(x, y + 1, z)] == 7) + return; + blocks[idx] = 0; + }); + if (!m_chunk.is_temp_chunk()) { + path.clear_chunk(chunk_pos); + } } } } @@ -746,29 +750,33 @@ void ChunkGenerator::generate_river() { auto& paths = river_worm.paths(); const auto& chunk_pos = m_chunk.chunk_pos(); auto& blocks = m_chunk.blocks(); - bool is_river = false; - - for (auto& [id, path] : paths) { - if ((m_chunk.biome() == BiomeType::DESERT) || - (m_chunk.biome() == BiomeType::OCEAN)) { - path.clear_chunk(chunk_pos); - continue; - } - carve_worm(path.points(), chunk_pos, [&](int x, int y, int z) -> void { - int idx = Chunk::index(x, y, z); - if (y > SEA_LEVEL) { - blocks[idx] = 0; - return; + { + 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); + } + continue; } - is_river = true; - if (blocks[idx] == 0) { - return; + carve_worm(path.points(), chunk_pos, + [&](int x, int y, int z) -> void { + int idx = Chunk::index(x, y, z); + if (y > SEA_LEVEL) { + blocks[idx] = 0; + return; + } + is_river = true; + if (blocks[idx] == 0) { + return; + } + blocks[idx] = 7; + }); + if (!m_chunk.is_temp_chunk()) { + path.clear_chunk(chunk_pos); } - blocks[idx] = 7; - }); - if (!m_chunk.is_temp_chunk()) { - path.clear_chunk(chunk_pos); } } diff --git a/src/gameplay/river_worm.cpp b/src/gameplay/river_worm.cpp index a480ce1..1e5ef93 100644 --- a/src/gameplay/river_worm.cpp +++ b/src/gameplay/river_worm.cpp @@ -4,7 +4,7 @@ namespace Cubed { RiverWorm::RiverWorm() {} - +RiverWorm::~RiverWorm() {} RiverWorm::RiverHashMap& RiverWorm::paths() { return m_paths; } void RiverWorm::init(unsigned world_seed) { @@ -60,5 +60,6 @@ void RiverWorm::cleanup_finished_rivers() { 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; } } // namespace Cubed \ No newline at end of file diff --git a/src/gameplay/world.cpp b/src/gameplay/world.cpp index 70a3962..a1028ed 100644 --- a/src/gameplay/world.cpp +++ b/src/gameplay/world.cpp @@ -21,6 +21,9 @@ World::World() {} World::~World() { stop_gen_thread(); stop_server_thread(); + wait_all_chunk_tasks(); + m_gen_thread_pool.reset(); + m_chunks.clear(); { std::lock_guard lk(m_delete_vbo_mutex); @@ -38,6 +41,12 @@ World::~World() { } } +void World::wait_all_chunk_tasks() { + for (auto& [pos, task] : new_chunks) { + task.future.get(); + } +} + bool World::can_move(const AABB& player_box) const { return true; } const std::optional& @@ -158,21 +167,26 @@ void World::gen_chunks_internal() { new_chunks.emplace(pos, Chunk(*this, pos)); } auto t1 = system_clock::now(); - parallel_do(*m_gen_thread_pool, temp_neighbor.begin(), temp_neighbor.end(), - m_gen_thread_pool->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()); - }); + { + std::scoped_lock lock{m_cave_carcer.path_mutex(), + m_river_worm.paths_mutex()}; + parallel_do(*m_gen_thread_pool, temp_neighbor.begin(), + temp_neighbor.end(), m_gen_thread_pool->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_cave_carcer.cleanup_finished_caves(); - m_river_worm.cleanup_finished_rivers(); m_chunk_gen_fraction = 1.0f; submit_new_chunks(); m_chunk_gen_finished = true; @@ -209,10 +223,6 @@ void World::compute_required_chunks(ChunkPosSet& required_chunks, for (int dz = -radius; dz <= radius; ++dz) { if (dx * dx + dz * dz <= r2) { ChunkPos pos{chunk_x + dx, chunk_z + dz}; - auto it = required_chunks.find(pos); - if (it != required_chunks.end()) { - continue; - } temp_neighbor.emplace_back(pos, Chunk(*this, pos)); } }