refactor: cave and river (#22)

* refactor(chunk): add ChunkInfo and switch to shared_mutex for chunk access

Introduced ChunkInfo struct to expose chunk metadata (position, seed, biome). Replaced std::mutex with std::shared_mutex for chunk map to allow concurrent read access. Added World::get_chunk_info() method. Temporarily disabled cave/river cleanup and debug biome reporting.

* refactor(cave,river,chunk): use ChunkPos as key for paths and track cave existence

* refactor(gameplay): use deterministic origin-based cave and river generation

Compute cave and river paths on-the-fly per chunk from a deterministic origin instead of storing them globally. Remove concurrent hash map storage, shared mutexes, and related cleanup methods. This simplifies concurrency and reduces memory overhead.

* refactor(world): remove unused chunk generation progress tracking
This commit is contained in:
zhenyan121
2026-06-22 16:43:22 +08:00
committed by GitHub
parent 7ffc349eb3
commit 7ecdab08fc
19 changed files with 318 additions and 374 deletions

View File

@@ -1,31 +1,25 @@
#pragma once
#include "Cubed/gameplay/cave_path.hpp"
#include "Cubed/constants.hpp"
#include "Cubed/gameplay/path.hpp"
#include <shared_mutex>
#include <tbb/concurrent_hash_map.h>
namespace Cubed {
class CaveCarver {
using CaveHashMap = tbb::concurrent_hash_map<unsigned, CavePath>;
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<unsigned> m_world_seed{0};
std::atomic<float> m_cave_probability{DEFAULT_CAVE_PROBABILITY};
};
} // namespace Cubed

View File

@@ -16,8 +16,6 @@ public:
CavePath(unsigned int chunk_seed, unsigned world_seed,
const glm::vec3& start_pos);
const std::vector<PathPoint>& 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<PathPoint> m_points;
ChunkPosSet m_pending_chunks;
void collect_path_points();
void precompute_chunk_coverage();
};
} // namespace Cubed

View File

@@ -10,6 +10,15 @@
#include <mutex>
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<bool> m_gening{false};
std::atomic<bool> m_temp_chunk{false};
bool m_has_cave{false};
std::atomic<BiomeType> 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

View File

@@ -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 <atomic>
@@ -62,9 +61,6 @@ private:
unsigned m_chunk_seed = 0;
void make_biome_builder();
void
carve_worm(const std::vector<PathPoint>& points, const ChunkPos& chunk_pos,
std::function<void(int /*x*/, int /*y*/, int /*z*/)> on_hit);
};
} // namespace Cubed

View File

@@ -0,0 +1,8 @@
#pragma once
#include <glm/glm.hpp>
struct PathOrigin {
bool exists;
glm::vec3 pos;
unsigned seed;
};

View File

@@ -16,8 +16,6 @@ public:
RiverPath(unsigned int chunk_seed, unsigned world_seed,
const glm::vec3& start_pos);
const std::vector<PathPoint>& 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;

View File

@@ -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 <glm/glm.hpp>
#include <shared_mutex>
#include <tbb/concurrent_hash_map.h>
namespace Cubed {
class RiverWorm {
using RiverHashMap = tbb::concurrent_hash_map<unsigned, RiverPath>;
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<unsigned> m_world_seed{0};
Random m_random;
float m_probability = 0.01f;
std::shared_mutex m_paths_mutex;
std::atomic<float> m_probability{0.01f};
};
}; // namespace Cubed

View File

@@ -10,6 +10,7 @@
#include <condition_variable>
#include <mutex>
#include <optional>
#include <shared_mutex>
#include <thread>
#include <unordered_map>
#include <unordered_set>
@@ -67,7 +68,7 @@ private:
std::atomic<TickType> 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<bool> m_could_gen{true};
std::atomic<bool> m_tick_running{true};
std::atomic<int> m_rendering_distance{24};
std::atomic<float> m_chunk_gen_fraction{0.0f};
std::atomic<int> m_pool_threads{0};
std::atomic<int> m_max_threads{1};
std::atomic<TickType> 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<ChunkPos>&,
const ChunkPosSet&);
@@ -118,7 +117,7 @@ public:
const std::optional<LookBlock>&
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