LCOV - code coverage report
Current view: top level - src - mapgen_v5.cpp (source / functions) Hit Total Coverage
Test: report Lines: 1 322 0.3 %
Date: 2015-07-11 18:23:49 Functions: 2 15 13.3 %

          Line data    Source code
       1             : /*
       2             : Minetest
       3             : Copyright (C) 2010-2013 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
       4             : 
       5             : This program is free software; you can redistribute it and/or modify
       6             : it under the terms of the GNU Lesser General Public License as published by
       7             : the Free Software Foundation; either version 2.1 of the License, or
       8             : (at your option) any later version.
       9             : 
      10             : This program is distributed in the hope that it will be useful,
      11             : but WITHOUT ANY WARRANTY; without even the implied warranty of
      12             : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13             : GNU Lesser General Public License for more details.
      14             : 
      15             : You should have received a copy of the GNU Lesser General Public License along
      16             : with this program; if not, write to the Free Software Foundation, Inc.,
      17             : 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
      18             : */
      19             : 
      20             : 
      21             : #include "mapgen.h"
      22             : #include "voxel.h"
      23             : #include "noise.h"
      24             : #include "mapblock.h"
      25             : #include "mapnode.h"
      26             : #include "map.h"
      27             : #include "content_sao.h"
      28             : #include "nodedef.h"
      29             : #include "voxelalgorithms.h"
      30             : #include "profiler.h"
      31             : #include "settings.h" // For g_settings
      32             : #include "emerge.h"
      33             : #include "dungeongen.h"
      34             : #include "cavegen.h"
      35             : #include "treegen.h"
      36             : #include "mg_biome.h"
      37             : #include "mg_ore.h"
      38             : #include "mg_decoration.h"
      39             : #include "mapgen_v5.h"
      40             : #include "util/directiontables.h"
      41             : 
      42             : 
      43             : FlagDesc flagdesc_mapgen_v5[] = {
      44             :         {NULL,         0}
      45             : };
      46             : 
      47             : 
      48           0 : MapgenV5::MapgenV5(int mapgenid, MapgenParams *params, EmergeManager *emerge)
      49           0 :         : Mapgen(mapgenid, params, emerge)
      50             : {
      51           0 :         this->m_emerge = emerge;
      52           0 :         this->bmgr     = emerge->biomemgr;
      53             : 
      54             :         // amount of elements to skip for the next index
      55             :         // for noise/height/biome maps (not vmanip)
      56           0 :         this->ystride = csize.X;
      57           0 :         this->zstride = csize.X * (csize.Y + 2);
      58             : 
      59           0 :         this->biomemap  = new u8[csize.X * csize.Z];
      60           0 :         this->heightmap = new s16[csize.X * csize.Z];
      61           0 :         this->heatmap   = NULL;
      62           0 :         this->humidmap  = NULL;
      63             : 
      64           0 :         MapgenV5Params *sp = (MapgenV5Params *)params->sparams;
      65           0 :         this->spflags      = sp->spflags;
      66             : 
      67             :         // Terrain noise
      68           0 :         noise_filler_depth = new Noise(&sp->np_filler_depth, seed, csize.X, csize.Z);
      69           0 :         noise_factor       = new Noise(&sp->np_factor,       seed, csize.X, csize.Z);
      70           0 :         noise_height       = new Noise(&sp->np_height,       seed, csize.X, csize.Z);
      71             : 
      72             :         // 3D terrain noise
      73           0 :         noise_cave1  = new Noise(&sp->np_cave1,  seed, csize.X, csize.Y + 2, csize.Z);
      74           0 :         noise_cave2  = new Noise(&sp->np_cave2,  seed, csize.X, csize.Y + 2, csize.Z);
      75           0 :         noise_ground = new Noise(&sp->np_ground, seed, csize.X, csize.Y + 2, csize.Z);
      76             : 
      77             :         // Biome noise
      78           0 :         noise_heat           = new Noise(&params->np_biome_heat,           seed, csize.X, csize.Z);
      79           0 :         noise_humidity       = new Noise(&params->np_biome_humidity,       seed, csize.X, csize.Z);
      80           0 :         noise_heat_blend     = new Noise(&params->np_biome_heat_blend,     seed, csize.X, csize.Z);
      81           0 :         noise_humidity_blend = new Noise(&params->np_biome_humidity_blend, seed, csize.X, csize.Z);
      82             : 
      83             :         //// Resolve nodes to be used
      84           0 :         INodeDefManager *ndef = emerge->ndef;
      85             : 
      86           0 :         c_stone                = ndef->getId("mapgen_stone");
      87           0 :         c_water_source         = ndef->getId("mapgen_water_source");
      88           0 :         c_lava_source          = ndef->getId("mapgen_lava_source");
      89           0 :         c_desert_stone         = ndef->getId("mapgen_desert_stone");
      90           0 :         c_ice                  = ndef->getId("mapgen_ice");
      91           0 :         c_sandstone            = ndef->getId("mapgen_sandstone");
      92             : 
      93           0 :         c_cobble               = ndef->getId("mapgen_cobble");
      94           0 :         c_stair_cobble         = ndef->getId("mapgen_stair_cobble");
      95           0 :         c_mossycobble          = ndef->getId("mapgen_mossycobble");
      96           0 :         c_sandstonebrick       = ndef->getId("mapgen_sandstonebrick");
      97           0 :         c_stair_sandstonebrick = ndef->getId("mapgen_stair_sandstonebrick");
      98             : 
      99           0 :         if (c_ice == CONTENT_IGNORE)
     100           0 :                 c_ice = CONTENT_AIR;
     101           0 :         if (c_mossycobble == CONTENT_IGNORE)
     102           0 :                 c_mossycobble = c_cobble;
     103           0 :         if (c_stair_cobble == CONTENT_IGNORE)
     104           0 :                 c_stair_cobble = c_cobble;
     105           0 :         if (c_sandstonebrick == CONTENT_IGNORE)
     106           0 :                 c_sandstonebrick = c_sandstone;
     107           0 :         if (c_stair_sandstonebrick == CONTENT_IGNORE)
     108           0 :                 c_stair_sandstonebrick = c_sandstone;
     109           0 : }
     110             : 
     111             : 
     112           0 : MapgenV5::~MapgenV5()
     113             : {
     114           0 :         delete noise_filler_depth;
     115           0 :         delete noise_factor;
     116           0 :         delete noise_height;
     117           0 :         delete noise_cave1;
     118           0 :         delete noise_cave2;
     119           0 :         delete noise_ground;
     120             : 
     121           0 :         delete noise_heat;
     122           0 :         delete noise_humidity;
     123           0 :         delete noise_heat_blend;
     124           0 :         delete noise_humidity_blend;
     125             : 
     126           0 :         delete[] heightmap;
     127           0 :         delete[] biomemap;
     128           0 : }
     129             : 
     130             : 
     131           0 : MapgenV5Params::MapgenV5Params()
     132             : {
     133           0 :         spflags = 0;
     134             : 
     135           0 :         np_filler_depth = NoiseParams(0, 1,  v3f(150, 150, 150), 261,    4, 0.7,  2.0);
     136           0 :         np_factor       = NoiseParams(0, 1,  v3f(250, 250, 250), 920381, 3, 0.45, 2.0);
     137           0 :         np_height       = NoiseParams(0, 10, v3f(250, 250, 250), 84174,  4, 0.5,  2.0);
     138           0 :         np_cave1        = NoiseParams(0, 12, v3f(50,  50,  50),  52534,  4, 0.5,  2.0);
     139           0 :         np_cave2        = NoiseParams(0, 12, v3f(50,  50,  50),  10325,  4, 0.5,  2.0);
     140           0 :         np_ground       = NoiseParams(0, 40, v3f(80,  80,  80),  983240, 4, 0.55, 2.0, NOISE_FLAG_EASED);
     141           0 : }
     142             : 
     143             : 
     144             : //#define CAVE_NOISE_SCALE 12.0
     145             : //#define CAVE_NOISE_THRESHOLD (1.5/CAVE_NOISE_SCALE) = 0.125
     146             : 
     147             : 
     148           0 : void MapgenV5Params::readParams(const Settings *settings)
     149             : {
     150           0 :         settings->getFlagStrNoEx("mgv5_spflags", spflags, flagdesc_mapgen_v5);
     151             : 
     152           0 :         settings->getNoiseParams("mgv5_np_filler_depth", np_filler_depth);
     153           0 :         settings->getNoiseParams("mgv5_np_factor",       np_factor);
     154           0 :         settings->getNoiseParams("mgv5_np_height",       np_height);
     155           0 :         settings->getNoiseParams("mgv5_np_cave1",        np_cave1);
     156           0 :         settings->getNoiseParams("mgv5_np_cave2",        np_cave2);
     157           0 :         settings->getNoiseParams("mgv5_np_ground",       np_ground);
     158           0 : }
     159             : 
     160             : 
     161           0 : void MapgenV5Params::writeParams(Settings *settings) const
     162             : {
     163           0 :         settings->setFlagStr("mgv5_spflags", spflags, flagdesc_mapgen_v5, (u32)-1);
     164             : 
     165           0 :         settings->setNoiseParams("mgv5_np_filler_depth", np_filler_depth);
     166           0 :         settings->setNoiseParams("mgv5_np_factor",       np_factor);
     167           0 :         settings->setNoiseParams("mgv5_np_height",       np_height);
     168           0 :         settings->setNoiseParams("mgv5_np_cave1",        np_cave1);
     169           0 :         settings->setNoiseParams("mgv5_np_cave2",        np_cave2);
     170           0 :         settings->setNoiseParams("mgv5_np_ground",       np_ground);
     171           0 : }
     172             : 
     173             : 
     174           0 : int MapgenV5::getGroundLevelAtPoint(v2s16 p)
     175             : {
     176             :         //TimeTaker t("getGroundLevelAtPoint", NULL, PRECISION_MICRO);
     177             : 
     178           0 :         float f = 0.55 + NoisePerlin2D(&noise_factor->np, p.X, p.Y, seed);
     179           0 :         if (f < 0.01)
     180           0 :                 f = 0.01;
     181           0 :         else if (f >= 1.0)
     182           0 :                 f *= 1.6;
     183           0 :         float h = NoisePerlin2D(&noise_height->np, p.X, p.Y, seed);
     184             : 
     185           0 :         s16 search_top = water_level + 15;
     186           0 :         s16 search_base = water_level;
     187             : 
     188           0 :         s16 level = -31000;
     189           0 :         for (s16 y = search_top; y >= search_base; y--) {
     190           0 :                 float n_ground = NoisePerlin3D(&noise_ground->np, p.X, y, p.Y, seed);
     191           0 :                 if (n_ground * f > y - h) {
     192           0 :                         if (y >= search_top - 7)
     193           0 :                                 break;
     194             :                         else
     195           0 :                                 level = y;
     196           0 :                                 break;
     197             :                 }
     198             :         }
     199             : 
     200             :         //printf("getGroundLevelAtPoint: %dus\n", t.stop());
     201           0 :         return level;
     202             : }
     203             : 
     204             : 
     205           0 : void MapgenV5::makeChunk(BlockMakeData *data)
     206             : {
     207             :         // Pre-conditions
     208             :         assert(data->vmanip);
     209             :         assert(data->nodedef);
     210             :         assert(data->blockpos_requested.X >= data->blockpos_min.X &&
     211             :                 data->blockpos_requested.Y >= data->blockpos_min.Y &&
     212             :                 data->blockpos_requested.Z >= data->blockpos_min.Z);
     213             :         assert(data->blockpos_requested.X <= data->blockpos_max.X &&
     214             :                 data->blockpos_requested.Y <= data->blockpos_max.Y &&
     215             :                 data->blockpos_requested.Z <= data->blockpos_max.Z);
     216             : 
     217           0 :         generating = true;
     218           0 :         vm   = data->vmanip;
     219           0 :         ndef = data->nodedef;
     220             :         //TimeTaker t("makeChunk");
     221             : 
     222           0 :         v3s16 blockpos_min = data->blockpos_min;
     223           0 :         v3s16 blockpos_max = data->blockpos_max;
     224           0 :         node_min = blockpos_min * MAP_BLOCKSIZE;
     225           0 :         node_max = (blockpos_max + v3s16(1, 1, 1)) * MAP_BLOCKSIZE - v3s16(1, 1, 1);
     226           0 :         full_node_min = (blockpos_min - 1) * MAP_BLOCKSIZE;
     227           0 :         full_node_max = (blockpos_max + 2) * MAP_BLOCKSIZE - v3s16(1, 1, 1);
     228             : 
     229             :         // Create a block-specific seed
     230           0 :         blockseed = getBlockSeed2(full_node_min, seed);
     231             : 
     232             :         // Make some noise
     233           0 :         calculateNoise();
     234             : 
     235             :         // Generate base terrain
     236           0 :         s16 stone_surface_max_y = generateBaseTerrain();
     237             : 
     238             :         // Create heightmap
     239           0 :         updateHeightmap(node_min, node_max);
     240             : 
     241             :         // Create biomemap at heightmap surface
     242           0 :         bmgr->calcBiomes(csize.X, csize.Z, noise_heat->result,
     243           0 :                 noise_humidity->result, heightmap, biomemap);
     244             : 
     245             :         // Actually place the biome-specific nodes
     246           0 :         MgStoneType stone_type = generateBiomes(noise_heat->result, noise_humidity->result);
     247             : 
     248             :         // Generate caves
     249           0 :         if ((flags & MG_CAVES) && (stone_surface_max_y >= node_min.Y))
     250           0 :                 generateCaves(stone_surface_max_y);
     251             : 
     252             :         // Generate dungeons and desert temples
     253           0 :         if ((flags & MG_DUNGEONS) && (stone_surface_max_y >= node_min.Y)) {
     254           0 :                 DungeonParams dp;
     255             : 
     256           0 :                 dp.np_rarity  = nparams_dungeon_rarity;
     257           0 :                 dp.np_density = nparams_dungeon_density;
     258           0 :                 dp.np_wetness = nparams_dungeon_wetness;
     259           0 :                 dp.c_water    = c_water_source;
     260           0 :                 if (stone_type == STONE) {
     261           0 :                         dp.c_cobble = c_cobble;
     262           0 :                         dp.c_moss   = c_mossycobble;
     263           0 :                         dp.c_stair  = c_stair_cobble;
     264             : 
     265           0 :                         dp.diagonal_dirs = false;
     266           0 :                         dp.mossratio     = 3.0;
     267           0 :                         dp.holesize      = v3s16(1, 2, 1);
     268           0 :                         dp.roomsize      = v3s16(0, 0, 0);
     269           0 :                         dp.notifytype    = GENNOTIFY_DUNGEON;
     270           0 :                 } else if (stone_type == DESERT_STONE) {
     271           0 :                         dp.c_cobble = c_desert_stone;
     272           0 :                         dp.c_moss   = c_desert_stone;
     273           0 :                         dp.c_stair  = c_desert_stone;
     274             : 
     275           0 :                         dp.diagonal_dirs = true;
     276           0 :                         dp.mossratio     = 0.0;
     277           0 :                         dp.holesize      = v3s16(2, 3, 2);
     278           0 :                         dp.roomsize      = v3s16(2, 5, 2);
     279           0 :                         dp.notifytype    = GENNOTIFY_TEMPLE;
     280           0 :                 } else if (stone_type == SANDSTONE) {
     281           0 :                         dp.c_cobble = c_sandstonebrick;
     282           0 :                         dp.c_moss   = c_sandstonebrick;
     283           0 :                         dp.c_stair  = c_sandstonebrick;
     284             : 
     285           0 :                         dp.diagonal_dirs = false;
     286           0 :                         dp.mossratio     = 0.0;
     287           0 :                         dp.holesize      = v3s16(2, 2, 2);
     288           0 :                         dp.roomsize      = v3s16(2, 0, 2);
     289           0 :                         dp.notifytype    = GENNOTIFY_DUNGEON;
     290             :                 }
     291             : 
     292           0 :                 DungeonGen dgen(this, &dp);
     293           0 :                 dgen.generate(blockseed, full_node_min, full_node_max);
     294             :         }
     295             : 
     296             :         // Generate the registered decorations
     297           0 :         m_emerge->decomgr->placeAllDecos(this, blockseed, node_min, node_max);
     298             : 
     299             :         // Generate the registered ores
     300           0 :         m_emerge->oremgr->placeAllOres(this, blockseed, node_min, node_max);
     301             : 
     302             :         // Sprinkle some dust on top after everything else was generated
     303           0 :         dustTopNodes();
     304             : 
     305             :         //printf("makeChunk: %dms\n", t.stop());
     306             : 
     307             :         // Add top and bottom side of water to transforming_liquid queue
     308           0 :         updateLiquid(&data->transforming_liquid, full_node_min, full_node_max);
     309             : 
     310             :         // Calculate lighting
     311           0 :         if (flags & MG_LIGHT) {
     312           0 :                 calcLighting(node_min - v3s16(0, 1, 0), node_max + v3s16(0, 1, 0),
     313           0 :                         full_node_min, full_node_max);
     314             :         }
     315             : 
     316           0 :         this->generating = false;
     317           0 : }
     318             : 
     319             : 
     320           0 : void MapgenV5::calculateNoise()
     321             : {
     322             :         //TimeTaker t("calculateNoise", NULL, PRECISION_MICRO);
     323           0 :         int x = node_min.X;
     324           0 :         int y = node_min.Y - 1;
     325           0 :         int z = node_min.Z;
     326             : 
     327           0 :         noise_factor->perlinMap2D(x, z);
     328           0 :         noise_height->perlinMap2D(x, z);
     329           0 :         noise_ground->perlinMap3D(x, y, z);
     330             : 
     331           0 :         if (flags & MG_CAVES) {
     332           0 :                 noise_cave1->perlinMap3D(x, y, z);
     333           0 :                 noise_cave2->perlinMap3D(x, y, z);
     334             :         }
     335             : 
     336           0 :         noise_filler_depth->perlinMap2D(x, z);
     337           0 :         noise_heat->perlinMap2D(x, z);
     338           0 :         noise_humidity->perlinMap2D(x, z);
     339           0 :         noise_heat_blend->perlinMap2D(x, z);
     340           0 :         noise_humidity_blend->perlinMap2D(x, z);
     341             : 
     342           0 :         for (s32 i = 0; i < csize.X * csize.Z; i++) {
     343           0 :                 noise_heat->result[i] += noise_heat_blend->result[i];
     344           0 :                 noise_humidity->result[i] += noise_humidity_blend->result[i];
     345             :         }
     346             : 
     347           0 :         heatmap = noise_heat->result;
     348           0 :         humidmap = noise_humidity->result;
     349             :         //printf("calculateNoise: %dus\n", t.stop());
     350           0 : }
     351             : 
     352             : 
     353             : //bool is_cave(u32 index) {
     354             : //      double d1 = contour(noise_cave1->result[index]);
     355             : //      double d2 = contour(noise_cave2->result[index]);
     356             : //      return d1*d2 > CAVE_NOISE_THRESHOLD;
     357             : //}
     358             : 
     359             : //bool val_is_ground(v3s16 p, u32 index, u32 index2d) {
     360             : //      double f = 0.55 + noise_factor->result[index2d];
     361             : //      if(f < 0.01)
     362             : //              f = 0.01;
     363             : //      else if(f >= 1.0)
     364             : //              f *= 1.6;
     365             : //      double h = WATER_LEVEL + 10 * noise_height->result[index2d];
     366             : //      return (noise_ground->result[index] * f > (double)p.Y - h);
     367             : //}
     368             : 
     369             : 
     370           0 : int MapgenV5::generateBaseTerrain()
     371             : {
     372           0 :         u32 index = 0;
     373           0 :         u32 index2d = 0;
     374           0 :         int stone_surface_max_y = -MAP_GENERATION_LIMIT;
     375             : 
     376           0 :         for (s16 z=node_min.Z; z<=node_max.Z; z++) {
     377           0 :                 for (s16 y=node_min.Y - 1; y<=node_max.Y + 1; y++) {
     378           0 :                         u32 i = vm->m_area.index(node_min.X, y, z);
     379           0 :                         for (s16 x=node_min.X; x<=node_max.X; x++, i++, index++, index2d++) {
     380           0 :                                 if (vm->m_data[i].getContent() != CONTENT_IGNORE)
     381           0 :                                         continue;
     382             : 
     383           0 :                                 float f = 0.55 + noise_factor->result[index2d];
     384           0 :                                 if (f < 0.01)
     385           0 :                                         f = 0.01;
     386           0 :                                 else if (f >= 1.0)
     387           0 :                                         f *= 1.6;
     388           0 :                                 float h = noise_height->result[index2d];
     389             : 
     390           0 :                                 if (noise_ground->result[index] * f < y - h) {
     391           0 :                                         if (y <= water_level)
     392           0 :                                                 vm->m_data[i] = MapNode(c_water_source);
     393             :                                         else
     394           0 :                                                 vm->m_data[i] = MapNode(CONTENT_AIR);
     395             :                                 } else {
     396           0 :                                         vm->m_data[i] = MapNode(c_stone);
     397           0 :                                         if (y > stone_surface_max_y)
     398           0 :                                                 stone_surface_max_y = y;
     399             :                                 }
     400             :                         }
     401           0 :                         index2d -= ystride;
     402             :                 }
     403           0 :                 index2d += ystride;
     404             :         }
     405             : 
     406           0 :         return stone_surface_max_y;
     407             : }
     408             : 
     409             : 
     410           0 : MgStoneType MapgenV5::generateBiomes(float *heat_map, float *humidity_map)
     411             : {
     412           0 :         v3s16 em = vm->m_area.getExtent();
     413           0 :         u32 index = 0;
     414           0 :         MgStoneType stone_type = STONE;
     415             : 
     416           0 :         for (s16 z = node_min.Z; z <= node_max.Z; z++)
     417           0 :         for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
     418           0 :                 Biome *biome = NULL;
     419           0 :                 u16 depth_top = 0;
     420           0 :                 u16 base_filler = 0;
     421           0 :                 u16 depth_water_top = 0;
     422           0 :                 u32 vi = vm->m_area.index(x, node_max.Y, z);
     423             : 
     424             :                 // Check node at base of mapchunk above, either a node of a previously
     425             :                 // generated mapchunk or if not, a node of overgenerated base terrain.
     426           0 :                 content_t c_above = vm->m_data[vi + em.X].getContent();
     427           0 :                 bool air_above = c_above == CONTENT_AIR;
     428           0 :                 bool water_above = c_above == c_water_source;
     429             : 
     430             :                 // If there is air or water above enable top/filler placement, otherwise force
     431             :                 // nplaced to stone level by setting a number exceeding any possible filler depth.
     432           0 :                 u16 nplaced = (air_above || water_above) ? 0 : (u16)-1;
     433             : 
     434           0 :                 for (s16 y = node_max.Y; y >= node_min.Y; y--) {
     435           0 :                         content_t c = vm->m_data[vi].getContent();
     436             : 
     437             :                         // Biome is recalculated each time an upper surface is detected while
     438             :                         // working down a column. The selected biome then remains in effect for
     439             :                         // all nodes below until the next surface and biome recalculation.
     440             :                         // Biome is recalculated:
     441             :                         // 1. At the surface of stone below air or water.
     442             :                         // 2. At the surface of water below air.
     443             :                         // 3. When stone or water is detected but biome has not yet been calculated.
     444           0 :                         if ((c == c_stone && (air_above || water_above || !biome)) ||
     445           0 :                                         (c == c_water_source && (air_above || !biome))) {
     446           0 :                                 biome = bmgr->getBiome(heat_map[index], humidity_map[index], y);
     447           0 :                                 depth_top = biome->depth_top;
     448           0 :                                 base_filler = MYMAX(depth_top + biome->depth_filler
     449           0 :                                                 + noise_filler_depth->result[index], 0);
     450           0 :                                 depth_water_top = biome->depth_water_top;
     451             : 
     452             :                                 // Detect stone type for dungeons during every biome calculation.
     453             :                                 // This is more efficient than detecting per-node and will not
     454             :                                 // miss any desert stone or sandstone biomes.
     455           0 :                                 if (biome->c_stone == c_desert_stone)
     456           0 :                                         stone_type = DESERT_STONE;
     457           0 :                                 else if (biome->c_stone == c_sandstone)
     458           0 :                                         stone_type = SANDSTONE;
     459             :                         }
     460             : 
     461           0 :                         if (c == c_stone) {
     462           0 :                                 content_t c_below = vm->m_data[vi - em.X].getContent();
     463             : 
     464             :                                 // If the node below isn't solid, make this node stone, so that
     465             :                                 // any top/filler nodes above are structurally supported.
     466             :                                 // This is done by aborting the cycle of top/filler placement
     467             :                                 // immediately by forcing nplaced to stone level.
     468           0 :                                 if (c_below == CONTENT_AIR || c_below == c_water_source)
     469           0 :                                         nplaced = (u16)-1;
     470             : 
     471           0 :                                 if (nplaced < depth_top) {
     472           0 :                                         vm->m_data[vi] = MapNode(biome->c_top);
     473           0 :                                         nplaced++;
     474           0 :                                 } else if (nplaced < base_filler) {
     475           0 :                                         vm->m_data[vi] = MapNode(biome->c_filler);
     476           0 :                                         nplaced++;
     477             :                                 } else {
     478           0 :                                         vm->m_data[vi] = MapNode(biome->c_stone);
     479             :                                 }
     480             : 
     481           0 :                                 air_above = false;
     482           0 :                                 water_above = false;
     483           0 :                         } else if (c == c_water_source) {
     484           0 :                                 vm->m_data[vi] = MapNode((y > (s32)(water_level - depth_water_top)) ?
     485           0 :                                                 biome->c_water_top : biome->c_water);
     486           0 :                                 nplaced = 0;  // Enable top/filler placement for next surface
     487           0 :                                 air_above = false;
     488           0 :                                 water_above = true;
     489           0 :                         } else if (c == CONTENT_AIR) {
     490           0 :                                 nplaced = 0;  // Enable top/filler placement for next surface
     491           0 :                                 air_above = true;
     492           0 :                                 water_above = false;
     493             :                         } else {  // Possible various nodes overgenerated from neighbouring mapchunks
     494           0 :                                 nplaced = (u16)-1;  // Disable top/filler placement
     495           0 :                                 air_above = false;
     496           0 :                                 water_above = false;
     497             :                         }
     498             : 
     499           0 :                         vm->m_area.add_y(em, vi, -1);
     500             :                 }
     501             :         }
     502             : 
     503           0 :         return stone_type;
     504             : }
     505             : 
     506             : 
     507           0 : void MapgenV5::generateCaves(int max_stone_y)
     508             : {
     509           0 :         if (max_stone_y >= node_min.Y) {
     510           0 :                 u32 index = 0;
     511             : 
     512           0 :                 for (s16 z = node_min.Z; z <= node_max.Z; z++)
     513           0 :                 for (s16 y = node_min.Y - 1; y <= node_max.Y + 1; y++) {
     514           0 :                         u32 i = vm->m_area.index(node_min.X, y, z);
     515           0 :                         for (s16 x = node_min.X; x <= node_max.X; x++, i++, index++) {
     516           0 :                                 float d1 = contour(noise_cave1->result[index]);
     517           0 :                                 float d2 = contour(noise_cave2->result[index]);
     518           0 :                                 if (d1*d2 > 0.125) {
     519           0 :                                         content_t c = vm->m_data[i].getContent();
     520           0 :                                         if (!ndef->get(c).is_ground_content || c == CONTENT_AIR)
     521           0 :                                                 continue;
     522             : 
     523           0 :                                         vm->m_data[i] = MapNode(CONTENT_AIR);
     524             :                                 }
     525             :                         }
     526             :                 }
     527             :         }
     528             : 
     529           0 :         if (node_max.Y > LARGE_CAVE_DEPTH)
     530           0 :                 return;
     531             : 
     532           0 :         PseudoRandom ps(blockseed + 21343);
     533           0 :         u32 bruises_count = (ps.range(1, 4) == 1) ? ps.range(1, 2) : 0;
     534           0 :         for (u32 i = 0; i < bruises_count; i++) {
     535           0 :                 CaveV5 cave(this, &ps);
     536           0 :                 cave.makeCave(node_min, node_max, max_stone_y);
     537             :         }
     538             : }
     539             : 
     540             : 
     541           0 : void MapgenV5::dustTopNodes()
     542             : {
     543           0 :         if (node_max.Y < water_level)
     544           0 :                 return;
     545             : 
     546           0 :         v3s16 em = vm->m_area.getExtent();
     547           0 :         u32 index = 0;
     548             : 
     549           0 :         for (s16 z = node_min.Z; z <= node_max.Z; z++)
     550           0 :         for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
     551           0 :                 Biome *biome = (Biome *)bmgr->getRaw(biomemap[index]);
     552             : 
     553           0 :                 if (biome->c_dust == CONTENT_IGNORE)
     554           0 :                         continue;
     555             : 
     556           0 :                 u32 vi = vm->m_area.index(x, full_node_max.Y, z);
     557           0 :                 content_t c_full_max = vm->m_data[vi].getContent();
     558             :                 s16 y_start;
     559             : 
     560           0 :                 if (c_full_max == CONTENT_AIR) {
     561           0 :                         y_start = full_node_max.Y - 1;
     562           0 :                 } else if (c_full_max == CONTENT_IGNORE) {
     563           0 :                         vi = vm->m_area.index(x, node_max.Y + 1, z);
     564           0 :                         content_t c_max = vm->m_data[vi].getContent();
     565             : 
     566           0 :                         if (c_max == CONTENT_AIR)
     567           0 :                                 y_start = node_max.Y;
     568             :                         else
     569           0 :                                 continue;
     570             :                 } else {
     571           0 :                         continue;
     572             :                 }
     573             : 
     574           0 :                 vi = vm->m_area.index(x, y_start, z);
     575           0 :                 for (s16 y = y_start; y >= node_min.Y - 1; y--) {
     576           0 :                         if (vm->m_data[vi].getContent() != CONTENT_AIR)
     577           0 :                                 break;
     578             : 
     579           0 :                         vm->m_area.add_y(em, vi, -1);
     580             :                 }
     581             : 
     582           0 :                 content_t c = vm->m_data[vi].getContent();
     583           0 :                 if (!ndef->get(c).buildable_to && c != CONTENT_IGNORE && c != biome->c_dust) {
     584           0 :                         vm->m_area.add_y(em, vi, 1);
     585           0 :                         vm->m_data[vi] = MapNode(biome->c_dust);
     586             :                 }
     587             :         }
     588           3 : }
     589             : 

Generated by: LCOV version 1.11