mirror of
https://github.com/zhenyan121/Cubed.git
synced 2026-08-08 17:57:02 +08:00
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:
@@ -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 <imgui.h>
|
||||
@@ -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();
|
||||
|
||||
@@ -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<unsigned>(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<double>(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<unsigned int> 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<float>(CavePath::step_max())) *
|
||||
CavePath::step_len();
|
||||
return static_cast<int>(
|
||||
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
|
||||
@@ -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<int>(std::floor((center.x - rad) / CHUNK_SIZE));
|
||||
int max_cx =
|
||||
static_cast<int>(std::floor((center.x + rad) / CHUNK_SIZE));
|
||||
int min_cz =
|
||||
static_cast<int>(std::floor((center.z - rad) / CHUNK_SIZE));
|
||||
int max_cz =
|
||||
static_cast<int>(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<PathPoint>& 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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 <typename F>
|
||||
void carve_worm(const std::vector<PathPoint>& 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<int>(std::floor(center.x - rad_xz));
|
||||
int max_x = static_cast<int>(std::floor(center.x + rad_xz));
|
||||
int min_z = static_cast<int>(std::floor(center.z - rad_xz));
|
||||
int max_z = static_cast<int>(std::floor(center.z + rad_xz));
|
||||
int min_y = static_cast<int>(std::floor(center.y - rad_y));
|
||||
int max_y = static_cast<int>(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<float>(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<float>(wx) - point.pos.x;
|
||||
for (int wz = min_z; wz <= max_z; ++wz) {
|
||||
float dz = static_cast<float>(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<PathPoint>& points, const ChunkPos& chunk_pos,
|
||||
std::function<void(int /*x*/, int /*y*/, int /*z*/)> 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<int>(std::floor(center.x - rad_xz));
|
||||
int max_x = static_cast<int>(std::floor(center.x + rad_xz));
|
||||
int min_z = static_cast<int>(std::floor(center.z - rad_xz));
|
||||
int max_z = static_cast<int>(std::floor(center.z + rad_xz));
|
||||
int min_y = static_cast<int>(std::floor(center.y - rad_y));
|
||||
int max_y = static_cast<int>(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<float>(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<float>(wx) - point.pos.x;
|
||||
for (int wz = min_z; wz <= max_z; ++wz) {
|
||||
float dz = static_cast<float>(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<int>(std::floor((center.x - rad) / CHUNK_SIZE));
|
||||
int max_cx =
|
||||
static_cast<int>(std::floor((center.x + rad) / CHUNK_SIZE));
|
||||
int min_cz =
|
||||
static_cast<int>(std::floor((center.z - rad) / CHUNK_SIZE));
|
||||
int max_cz =
|
||||
static_cast<int>(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<PathPoint>& 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
|
||||
@@ -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<unsigned>(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<double>(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<unsigned> 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<float>(RiverPath::step_max())) *
|
||||
RiverPath::step_len();
|
||||
return static_cast<int>(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
|
||||
@@ -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<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_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
|
||||
Reference in New Issue
Block a user