From 29b7aea38b4284fb6ef1cee79d2074927bf0e3ee Mon Sep 17 00:00:00 2001 From: Riley Adams Date: Mon, 5 Jun 2023 05:59:22 -0400 Subject: [PATCH] Cavegen y biome check (#13472) --- src/mapgen/cavegen.cpp | 24 +++++++++++++++++++++++- src/mapgen/cavegen.h | 6 +++++- src/mapgen/mapgen.cpp | 24 +++++++++++++++++++----- src/mapgen/mg_biome.cpp | 32 ++++++++++++++++++++++++++++++++ src/mapgen/mg_biome.h | 4 ++++ 5 files changed, 83 insertions(+), 7 deletions(-) diff --git a/src/mapgen/cavegen.cpp b/src/mapgen/cavegen.cpp index 9ec7c7a64..47272142f 100644 --- a/src/mapgen/cavegen.cpp +++ b/src/mapgen/cavegen.cpp @@ -38,14 +38,16 @@ static NoiseParams nparams_caveliquids(0, 1, v3f(150.0, 150.0, 150.0), 776, 3, 0 //// CavesNoiseIntersection::CavesNoiseIntersection( - const NodeDefManager *nodedef, BiomeManager *biomemgr, v3s16 chunksize, + const NodeDefManager *nodedef, BiomeManager *biomemgr, BiomeGen *biomegen, v3s16 chunksize, NoiseParams *np_cave1, NoiseParams *np_cave2, s32 seed, float cave_width) { assert(nodedef); assert(biomemgr); + assert(biomegen); m_ndef = nodedef; m_bmgr = biomemgr; + m_bmgn = biomegen; m_csize = chunksize; m_cave_width = cave_width; @@ -80,6 +82,8 @@ void CavesNoiseIntersection::generateCaves(MMVManip *vm, const v3s16 &em = vm->m_area.getExtent(); u32 index2d = 0; // Biomemap index + s16 *biome_transitions = m_bmgn->getBiomeTransitions(); + for (s16 z = nmin.Z; z <= nmax.Z; z++) for (s16 x = nmin.X; x <= nmax.X; x++, index2d++) { bool column_is_open = false; // Is column open to overground @@ -96,6 +100,10 @@ void CavesNoiseIntersection::generateCaves(MMVManip *vm, u16 base_filler = depth_top + biome->depth_filler; u16 depth_riverbed = biome->depth_riverbed; u16 nplaced = 0; + + int cur_biome_depth = 0; + s16 biome_y_min = biome_transitions[cur_biome_depth]; + // Don't excavate the overgenerated stone at nmax.Y + 1, // this creates a 'roof' over the tunnel, preventing light in // tunnels at mapchunk borders when generating mapchunks upwards. @@ -103,6 +111,20 @@ void CavesNoiseIntersection::generateCaves(MMVManip *vm, for (s16 y = nmax.Y; y >= nmin.Y - 1; y--, index3d -= m_ystride, VoxelArea::add_y(em, vi, -1)) { + // We need this check to make sure that biomes don't generate too far down + if (y < biome_y_min) { + biome = m_bmgn->getBiomeAtIndex(index2d, v3s16(x, y, z)); + + // Finding the height of the next biome + // On first iteration this may loop a couple times after than it should just run once + while (y < biome_y_min) { + biome_y_min = biome_transitions[++cur_biome_depth]; + } + + /*if (x == nmin.X && z == nmin.Z) + printf("Cave: check @ %i -> %s -> again at %i\n", y, biome->name.c_str(), biome_y_min);*/ + } + content_t c = vm->m_data[vi].getContent(); if (c == CONTENT_AIR || c == biome->c_water_top || diff --git a/src/mapgen/cavegen.h b/src/mapgen/cavegen.h index 6bc267199..5cf2e530e 100644 --- a/src/mapgen/cavegen.h +++ b/src/mapgen/cavegen.h @@ -26,6 +26,8 @@ typedef u16 biome_t; // copy from mg_biome.h to avoid an unnecessary include class GenerateNotifier; +class BiomeGen; + /* CavesNoiseIntersection is a cave digging algorithm that carves smooth, web-like, continuous tunnels at points where the density of the intersection @@ -42,7 +44,7 @@ class CavesNoiseIntersection { public: CavesNoiseIntersection(const NodeDefManager *nodedef, - BiomeManager *biomemgr, v3s16 chunksize, NoiseParams *np_cave1, + BiomeManager *biomemgr, BiomeGen *biomegen, v3s16 chunksize, NoiseParams *np_cave1, NoiseParams *np_cave2, s32 seed, float cave_width); ~CavesNoiseIntersection(); @@ -52,6 +54,8 @@ private: const NodeDefManager *m_ndef; BiomeManager *m_bmgr; + BiomeGen *m_bmgn; + // configurable parameters v3s16 m_csize; float m_cave_width; diff --git a/src/mapgen/mapgen.cpp b/src/mapgen/mapgen.cpp index ce281e2c1..f4879078a 100644 --- a/src/mapgen/mapgen.cpp +++ b/src/mapgen/mapgen.cpp @@ -636,6 +636,8 @@ void MapgenBasic::generateBiomes() noise_filler_depth->perlinMap2D(node_min.X, node_min.Z); + s16 *biome_transitions = biomegen->getBiomeTransitions(); + for (s16 z = node_min.Z; z <= node_max.Z; z++) for (s16 x = node_min.X; x <= node_max.X; x++, index++) { Biome *biome = NULL; @@ -644,9 +646,11 @@ void MapgenBasic::generateBiomes() u16 base_filler = 0; u16 depth_water_top = 0; u16 depth_riverbed = 0; - s16 biome_y_min = -MAX_MAP_GENERATION_LIMIT; u32 vi = vm->m_area.index(x, node_max.Y, z); + int cur_biome_depth = 0; + s16 biome_y_min = biome_transitions[cur_biome_depth]; + // Check node at base of mapchunk above, either a node of a previously // generated mapchunk or if not, a node of overgenerated base terrain. content_t c_above = vm->m_data[vi + em.X].getContent(); @@ -675,8 +679,19 @@ void MapgenBasic::generateBiomes() (air_above || !biome || y < biome_y_min); // 2, 3, 4 if (is_stone_surface || is_water_surface) { - // (Re)calculate biome - biome = biomegen->getBiomeAtIndex(index, v3s16(x, y, z)); + if (!biome || y < biome_y_min) { + // (Re)calculate biome + biome = biomegen->getBiomeAtIndex(index, v3s16(x, y, z)); + + // Finding the height of the next biome + // On first iteration this may loop a couple times after than it should just run once + while (y < biome_y_min) { + biome_y_min = biome_transitions[++cur_biome_depth]; + } + + /*if (x == node_min.X && z == node_min.Z) + printf("Map: check @ %i -> %s -> again at %i\n", y, biome->name.c_str(), biome_y_min);*/ + } // Add biome to biomemap at first stone surface detected if (biomemap[index] == BIOME_NONE && is_stone_surface) @@ -693,7 +708,6 @@ void MapgenBasic::generateBiomes() noise_filler_depth->result[index], 0.0f); depth_water_top = biome->depth_water_top; depth_riverbed = biome->depth_riverbed; - biome_y_min = biome->min_pos.Y; } if (c == c_stone) { @@ -833,7 +847,7 @@ void MapgenBasic::generateCavesNoiseIntersection(s16 max_stone_y) if (node_min.Y > max_stone_y || cave_width >= 10.0f) return; - CavesNoiseIntersection caves_noise(ndef, m_bmgr, csize, + CavesNoiseIntersection caves_noise(ndef, m_bmgr, biomegen, csize, &np_cave1, &np_cave2, seed, cave_width); caves_noise.generateCaves(vm, node_min, node_max, biomemap); diff --git a/src/mapgen/mg_biome.cpp b/src/mapgen/mg_biome.cpp index 8b4c96cd5..5a4501693 100644 --- a/src/mapgen/mg_biome.cpp +++ b/src/mapgen/mg_biome.cpp @@ -147,18 +147,50 @@ BiomeGenOriginal::BiomeGenOriginal(BiomeManager *biomemgr, // fallback biome when biome generation (which calculates the biomemap IDs) // is disabled. memset(biomemap, 0, sizeof(biome_t) * m_csize.X * m_csize.Z); + + // Calculating the bounding position of each biome so we know when we might switch + // First gathering all heights where we might switch + std::vector temp_transition_heights; + temp_transition_heights.reserve(m_bmgr->getNumObjects() * 2); + for (size_t i = 0; i < m_bmgr->getNumObjects(); i++) { + Biome *b = (Biome *)m_bmgr->getRaw(i); + temp_transition_heights.push_back(b->max_pos.Y); + temp_transition_heights.push_back(b->min_pos.Y); + } + + // Sorting the biome transition points + std::sort(temp_transition_heights.begin(), temp_transition_heights.end(), std::greater()); + + // Getting rid of duplicate biome transition points + s16 last = temp_transition_heights[0]; + size_t out_pos = 1; + for (size_t i = 1; i < temp_transition_heights.size(); i++){ + if (temp_transition_heights[i] != last) { + last = temp_transition_heights[i]; + temp_transition_heights[out_pos++] = last; + } + } + + biome_transitions = new s16[out_pos]; + memcpy(biome_transitions, temp_transition_heights.data(), sizeof(s16) * out_pos); } BiomeGenOriginal::~BiomeGenOriginal() { delete []biomemap; + delete []biome_transitions; delete noise_heat; delete noise_humidity; delete noise_heat_blend; delete noise_humidity_blend; } +s16* BiomeGenOriginal::getBiomeTransitions() const +{ + return biome_transitions; +} + BiomeGen *BiomeGenOriginal::clone(BiomeManager *biomemgr) const { return new BiomeGenOriginal(biomemgr, m_params, m_csize); diff --git a/src/mapgen/mg_biome.h b/src/mapgen/mg_biome.h index c85afc3a0..567a0fe81 100644 --- a/src/mapgen/mg_biome.h +++ b/src/mapgen/mg_biome.h @@ -128,8 +128,11 @@ public: // Same as above, but uses a raw numeric index correlating to the (x,z) position. virtual Biome *getBiomeAtIndex(size_t index, v3s16 pos) const = 0; + virtual s16 *getBiomeTransitions() const = 0; + // Result of calcBiomes bulk computation. biome_t *biomemap = nullptr; + s16 *biome_transitions = nullptr; protected: BiomeManager *m_bmgr = nullptr; @@ -186,6 +189,7 @@ public: Biome *getBiomeAtIndex(size_t index, v3s16 pos) const; Biome *calcBiomeFromNoise(float heat, float humidity, v3s16 pos) const; + s16 *getBiomeTransitions() const; float *heatmap; float *humidmap;