mirror of
https://github.com/zhenyan121/Cubed.git
synced 2026-06-21 18:17:03 +08:00
fix: add thread safety for cave and river path mutexes
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -104,6 +104,7 @@ private:
|
||||
|
||||
void submit_new_chunks();
|
||||
void poll_finished_chunks();
|
||||
void wait_all_chunk_tasks();
|
||||
|
||||
public:
|
||||
World();
|
||||
|
||||
@@ -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 <typename F> auto enqueue(F&& f) {
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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<LookBlock>&
|
||||
@@ -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<ChunkPos, Chunk>& 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<ChunkPos, Chunk>& 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<milliseconds>(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));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user