Avoid crash caused by, and improve, 'findSpawnPos()' (#8728)
[oweals/minetest.git] / src / mapgen / mapgen_v6.cpp
1 /*
2 Minetest
3 Copyright (C) 2010-2018 celeron55, Perttu Ahola <celeron55@gmail.com>
4 Copyright (C) 2013-2018 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
5 Copyright (C) 2014-2018 paramat
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License along
18 with this program; if not, write to the Free Software Foundation, Inc.,
19 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 */
21
22
23 #include <cmath>
24 #include "mapgen.h"
25 #include "voxel.h"
26 #include "noise.h"
27 #include "mapblock.h"
28 #include "mapnode.h"
29 #include "map.h"
30 //#include "serverobject.h"
31 #include "content_sao.h"
32 #include "nodedef.h"
33 #include "voxelalgorithms.h"
34 //#include "profiler.h" // For TimeTaker
35 #include "settings.h" // For g_settings
36 #include "emerge.h"
37 #include "dungeongen.h"
38 #include "cavegen.h"
39 #include "treegen.h"
40 #include "mg_ore.h"
41 #include "mg_decoration.h"
42 #include "mapgen_v6.h"
43
44
45 FlagDesc flagdesc_mapgen_v6[] = {
46         {"jungles",    MGV6_JUNGLES},
47         {"biomeblend", MGV6_BIOMEBLEND},
48         {"mudflow",    MGV6_MUDFLOW},
49         {"snowbiomes", MGV6_SNOWBIOMES},
50         {"flat",       MGV6_FLAT},
51         {"trees",      MGV6_TREES},
52         {NULL,         0}
53 };
54
55
56 /////////////////////////////////////////////////////////////////////////////
57
58
59 MapgenV6::MapgenV6(MapgenV6Params *params, EmergeManager *emerge)
60         : Mapgen(MAPGEN_V6, params, emerge)
61 {
62         m_emerge = emerge;
63         ystride = csize.X;
64
65         heightmap = new s16[csize.X * csize.Z];
66
67         spflags      = params->spflags;
68         freq_desert  = params->freq_desert;
69         freq_beach   = params->freq_beach;
70         dungeon_ymin = params->dungeon_ymin;
71         dungeon_ymax = params->dungeon_ymax;
72
73         np_cave        = &params->np_cave;
74         np_humidity    = &params->np_humidity;
75         np_trees       = &params->np_trees;
76         np_apple_trees = &params->np_apple_trees;
77
78         np_dungeons = NoiseParams(0.9, 0.5, v3f(500.0, 500.0, 500.0), 0, 2, 0.8, 2.0);
79
80         //// Create noise objects
81         noise_terrain_base   = new Noise(&params->np_terrain_base,   seed, csize.X, csize.Y);
82         noise_terrain_higher = new Noise(&params->np_terrain_higher, seed, csize.X, csize.Y);
83         noise_steepness      = new Noise(&params->np_steepness,      seed, csize.X, csize.Y);
84         noise_height_select  = new Noise(&params->np_height_select,  seed, csize.X, csize.Y);
85         noise_mud            = new Noise(&params->np_mud,            seed, csize.X, csize.Y);
86         noise_beach          = new Noise(&params->np_beach,          seed, csize.X, csize.Y);
87         noise_biome          = new Noise(&params->np_biome,          seed,
88                         csize.X + 2 * MAP_BLOCKSIZE, csize.Y + 2 * MAP_BLOCKSIZE);
89         noise_humidity       = new Noise(&params->np_humidity,       seed,
90                         csize.X + 2 * MAP_BLOCKSIZE, csize.Y + 2 * MAP_BLOCKSIZE);
91
92         //// Resolve nodes to be used
93         const NodeDefManager *ndef = emerge->ndef;
94
95         c_stone           = ndef->getId("mapgen_stone");
96         c_dirt            = ndef->getId("mapgen_dirt");
97         c_dirt_with_grass = ndef->getId("mapgen_dirt_with_grass");
98         c_sand            = ndef->getId("mapgen_sand");
99         c_water_source    = ndef->getId("mapgen_water_source");
100         c_lava_source     = ndef->getId("mapgen_lava_source");
101         c_gravel          = ndef->getId("mapgen_gravel");
102         c_desert_stone    = ndef->getId("mapgen_desert_stone");
103         c_desert_sand     = ndef->getId("mapgen_desert_sand");
104         c_dirt_with_snow  = ndef->getId("mapgen_dirt_with_snow");
105         c_snow            = ndef->getId("mapgen_snow");
106         c_snowblock       = ndef->getId("mapgen_snowblock");
107         c_ice             = ndef->getId("mapgen_ice");
108
109         if (c_gravel == CONTENT_IGNORE)
110                 c_gravel = c_stone;
111         if (c_desert_stone == CONTENT_IGNORE)
112                 c_desert_stone = c_stone;
113         if (c_desert_sand == CONTENT_IGNORE)
114                 c_desert_sand = c_sand;
115         if (c_dirt_with_snow == CONTENT_IGNORE)
116                 c_dirt_with_snow = c_dirt_with_grass;
117         if (c_snow == CONTENT_IGNORE)
118                 c_snow = CONTENT_AIR;
119         if (c_snowblock == CONTENT_IGNORE)
120                 c_snowblock = c_dirt_with_grass;
121         if (c_ice == CONTENT_IGNORE)
122                 c_ice = c_water_source;
123
124         c_cobble             = ndef->getId("mapgen_cobble");
125         c_mossycobble        = ndef->getId("mapgen_mossycobble");
126         c_stair_cobble       = ndef->getId("mapgen_stair_cobble");
127         c_stair_desert_stone = ndef->getId("mapgen_stair_desert_stone");
128
129         if (c_mossycobble == CONTENT_IGNORE)
130                 c_mossycobble = c_cobble;
131         if (c_stair_cobble == CONTENT_IGNORE)
132                 c_stair_cobble = c_cobble;
133         if (c_stair_desert_stone == CONTENT_IGNORE)
134                 c_stair_desert_stone = c_desert_stone;
135 }
136
137
138 MapgenV6::~MapgenV6()
139 {
140         delete noise_terrain_base;
141         delete noise_terrain_higher;
142         delete noise_steepness;
143         delete noise_height_select;
144         delete noise_mud;
145         delete noise_beach;
146         delete noise_biome;
147         delete noise_humidity;
148
149         delete[] heightmap;
150 }
151
152
153 MapgenV6Params::MapgenV6Params():
154         np_terrain_base   (-4,   20.0, v3f(250.0, 250.0, 250.0), 82341,  5, 0.6,  2.0),
155         np_terrain_higher (20,   16.0, v3f(500.0, 500.0, 500.0), 85039,  5, 0.6,  2.0),
156         np_steepness      (0.85, 0.5,  v3f(125.0, 125.0, 125.0), -932,   5, 0.7,  2.0),
157         np_height_select  (0,    1.0,  v3f(250.0, 250.0, 250.0), 4213,   5, 0.69, 2.0),
158         np_mud            (4,    2.0,  v3f(200.0, 200.0, 200.0), 91013,  3, 0.55, 2.0),
159         np_beach          (0,    1.0,  v3f(250.0, 250.0, 250.0), 59420,  3, 0.50, 2.0),
160         np_biome          (0,    1.0,  v3f(500.0, 500.0, 500.0), 9130,   3, 0.50, 2.0),
161         np_cave           (6,    6.0,  v3f(250.0, 250.0, 250.0), 34329,  3, 0.50, 2.0),
162         np_humidity       (0.5,  0.5,  v3f(500.0, 500.0, 500.0), 72384,  3, 0.50, 2.0),
163         np_trees          (0,    1.0,  v3f(125.0, 125.0, 125.0), 2,      4, 0.66, 2.0),
164         np_apple_trees    (0,    1.0,  v3f(100.0, 100.0, 100.0), 342902, 3, 0.45, 2.0)
165 {
166 }
167
168
169 void MapgenV6Params::readParams(const Settings *settings)
170 {
171         settings->getFlagStrNoEx("mgv6_spflags", spflags, flagdesc_mapgen_v6);
172         settings->getFloatNoEx("mgv6_freq_desert", freq_desert);
173         settings->getFloatNoEx("mgv6_freq_beach",  freq_beach);
174         settings->getS16NoEx("mgv6_dungeon_ymin",  dungeon_ymin);
175         settings->getS16NoEx("mgv6_dungeon_ymax",  dungeon_ymax);
176
177         settings->getNoiseParams("mgv6_np_terrain_base",   np_terrain_base);
178         settings->getNoiseParams("mgv6_np_terrain_higher", np_terrain_higher);
179         settings->getNoiseParams("mgv6_np_steepness",      np_steepness);
180         settings->getNoiseParams("mgv6_np_height_select",  np_height_select);
181         settings->getNoiseParams("mgv6_np_mud",            np_mud);
182         settings->getNoiseParams("mgv6_np_beach",          np_beach);
183         settings->getNoiseParams("mgv6_np_biome",          np_biome);
184         settings->getNoiseParams("mgv6_np_cave",           np_cave);
185         settings->getNoiseParams("mgv6_np_humidity",       np_humidity);
186         settings->getNoiseParams("mgv6_np_trees",          np_trees);
187         settings->getNoiseParams("mgv6_np_apple_trees",    np_apple_trees);
188 }
189
190
191 void MapgenV6Params::writeParams(Settings *settings) const
192 {
193         settings->setFlagStr("mgv6_spflags", spflags, flagdesc_mapgen_v6, U32_MAX);
194         settings->setFloat("mgv6_freq_desert", freq_desert);
195         settings->setFloat("mgv6_freq_beach",  freq_beach);
196         settings->setS16("mgv6_dungeon_ymin",  dungeon_ymin);
197         settings->setS16("mgv6_dungeon_ymax",  dungeon_ymax);
198
199         settings->setNoiseParams("mgv6_np_terrain_base",   np_terrain_base);
200         settings->setNoiseParams("mgv6_np_terrain_higher", np_terrain_higher);
201         settings->setNoiseParams("mgv6_np_steepness",      np_steepness);
202         settings->setNoiseParams("mgv6_np_height_select",  np_height_select);
203         settings->setNoiseParams("mgv6_np_mud",            np_mud);
204         settings->setNoiseParams("mgv6_np_beach",          np_beach);
205         settings->setNoiseParams("mgv6_np_biome",          np_biome);
206         settings->setNoiseParams("mgv6_np_cave",           np_cave);
207         settings->setNoiseParams("mgv6_np_humidity",       np_humidity);
208         settings->setNoiseParams("mgv6_np_trees",          np_trees);
209         settings->setNoiseParams("mgv6_np_apple_trees",    np_apple_trees);
210 }
211
212
213 //////////////////////// Some helper functions for the map generator
214
215 // Returns Y one under area minimum if not found
216 s16 MapgenV6::find_stone_level(v2s16 p2d)
217 {
218         const v3s16 &em = vm->m_area.getExtent();
219         s16 y_nodes_max = vm->m_area.MaxEdge.Y;
220         s16 y_nodes_min = vm->m_area.MinEdge.Y;
221         u32 i = vm->m_area.index(p2d.X, y_nodes_max, p2d.Y);
222         s16 y;
223
224         for (y = y_nodes_max; y >= y_nodes_min; y--) {
225                 content_t c = vm->m_data[i].getContent();
226                 if (c != CONTENT_IGNORE && (c == c_stone || c == c_desert_stone))
227                         break;
228
229                 VoxelArea::add_y(em, i, -1);
230         }
231         return (y >= y_nodes_min) ? y : y_nodes_min - 1;
232 }
233
234
235 // Required by mapgen.h
236 bool MapgenV6::block_is_underground(u64 seed, v3s16 blockpos)
237 {
238         /*s16 minimum_groundlevel = (s16)get_sector_minimum_ground_level(
239                         seed, v2s16(blockpos.X, blockpos.Z));*/
240         // Nah, this is just a heuristic, just return something
241         s16 minimum_groundlevel = water_level;
242
243         if(blockpos.Y * MAP_BLOCKSIZE + MAP_BLOCKSIZE <= minimum_groundlevel)
244                 return true;
245
246         return false;
247 }
248
249
250 //////////////////////// Base terrain height functions
251
252 float MapgenV6::baseTerrainLevel(float terrain_base, float terrain_higher,
253         float steepness, float height_select)
254 {
255         float base   = 1 + terrain_base;
256         float higher = 1 + terrain_higher;
257
258         // Limit higher ground level to at least base
259         if(higher < base)
260                 higher = base;
261
262         // Steepness factor of cliffs
263         float b = steepness;
264         b = rangelim(b, 0.0, 1000.0);
265         b = 5 * b * b * b * b * b * b * b;
266         b = rangelim(b, 0.5, 1000.0);
267
268         // Values 1.5...100 give quite horrible looking slopes
269         if (b > 1.5 && b < 100.0)
270                 b = (b < 10.0) ? 1.5 : 100.0;
271
272         float a_off = -0.20; // Offset to more low
273         float a = 0.5 + b * (a_off + height_select);
274         a = rangelim(a, 0.0, 1.0); // Limit
275
276         return base * (1.0 - a) + higher * a;
277 }
278
279
280 float MapgenV6::baseTerrainLevelFromNoise(v2s16 p)
281 {
282         if (spflags & MGV6_FLAT)
283                 return water_level;
284
285         float terrain_base   = NoisePerlin2D_PO(&noise_terrain_base->np,
286                                                         p.X, 0.5, p.Y, 0.5, seed);
287         float terrain_higher = NoisePerlin2D_PO(&noise_terrain_higher->np,
288                                                         p.X, 0.5, p.Y, 0.5, seed);
289         float steepness      = NoisePerlin2D_PO(&noise_steepness->np,
290                                                         p.X, 0.5, p.Y, 0.5, seed);
291         float height_select  = NoisePerlin2D_PO(&noise_height_select->np,
292                                                         p.X, 0.5, p.Y, 0.5, seed);
293
294         return baseTerrainLevel(terrain_base, terrain_higher,
295                                                         steepness, height_select);
296 }
297
298
299 float MapgenV6::baseTerrainLevelFromMap(v2s16 p)
300 {
301         int index = (p.Y - node_min.Z) * ystride + (p.X - node_min.X);
302         return baseTerrainLevelFromMap(index);
303 }
304
305
306 float MapgenV6::baseTerrainLevelFromMap(int index)
307 {
308         if (spflags & MGV6_FLAT)
309                 return water_level;
310
311         float terrain_base   = noise_terrain_base->result[index];
312         float terrain_higher = noise_terrain_higher->result[index];
313         float steepness      = noise_steepness->result[index];
314         float height_select  = noise_height_select->result[index];
315
316         return baseTerrainLevel(terrain_base, terrain_higher,
317                                                         steepness, height_select);
318 }
319
320
321 s16 MapgenV6::find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision)
322 {
323         return baseTerrainLevelFromNoise(p2d) + MGV6_AVERAGE_MUD_AMOUNT;
324 }
325
326
327 int MapgenV6::getGroundLevelAtPoint(v2s16 p)
328 {
329         return baseTerrainLevelFromNoise(p) + MGV6_AVERAGE_MUD_AMOUNT;
330 }
331
332
333 int MapgenV6::getSpawnLevelAtPoint(v2s16 p)
334 {
335         s16 level_at_point = baseTerrainLevelFromNoise(p) + MGV6_AVERAGE_MUD_AMOUNT;
336         if (level_at_point <= water_level ||
337                         level_at_point > water_level + 16)
338                 return MAX_MAP_GENERATION_LIMIT;  // Unsuitable spawn point
339
340         return level_at_point;
341 }
342
343
344 //////////////////////// Noise functions
345
346 float MapgenV6::getMudAmount(v2s16 p)
347 {
348         int index = (p.Y - node_min.Z) * ystride + (p.X - node_min.X);
349         return getMudAmount(index);
350 }
351
352
353 bool MapgenV6::getHaveBeach(v2s16 p)
354 {
355         int index = (p.Y - node_min.Z) * ystride + (p.X - node_min.X);
356         return getHaveBeach(index);
357 }
358
359
360 BiomeV6Type MapgenV6::getBiome(v2s16 p)
361 {
362         int index = (p.Y - full_node_min.Z) * (ystride + 2 * MAP_BLOCKSIZE)
363                         + (p.X - full_node_min.X);
364         return getBiome(index, p);
365 }
366
367
368 float MapgenV6::getHumidity(v2s16 p)
369 {
370         /*double noise = noise2d_perlin(
371                 0.5+(float)p.X/500, 0.5+(float)p.Y/500,
372                 seed+72384, 4, 0.66);
373         noise = (noise + 1.0)/2.0;*/
374
375         int index = (p.Y - full_node_min.Z) * (ystride + 2 * MAP_BLOCKSIZE)
376                         + (p.X - full_node_min.X);
377         float noise = noise_humidity->result[index];
378
379         if (noise < 0.0)
380                 noise = 0.0;
381         if (noise > 1.0)
382                 noise = 1.0;
383         return noise;
384 }
385
386
387 float MapgenV6::getTreeAmount(v2s16 p)
388 {
389         /*double noise = noise2d_perlin(
390                         0.5+(float)p.X/125, 0.5+(float)p.Y/125,
391                         seed+2, 4, 0.66);*/
392
393         float noise = NoisePerlin2D(np_trees, p.X, p.Y, seed);
394         float zeroval = -0.39;
395         if (noise < zeroval)
396                 return 0;
397
398         return 0.04 * (noise - zeroval) / (1.0 - zeroval);
399 }
400
401
402 bool MapgenV6::getHaveAppleTree(v2s16 p)
403 {
404         /*is_apple_tree = noise2d_perlin(
405                 0.5+(float)p.X/100, 0.5+(float)p.Z/100,
406                 data->seed+342902, 3, 0.45) > 0.2;*/
407
408         float noise = NoisePerlin2D(np_apple_trees, p.X, p.Y, seed);
409
410         return noise > 0.2;
411 }
412
413
414 float MapgenV6::getMudAmount(int index)
415 {
416         if (spflags & MGV6_FLAT)
417                 return MGV6_AVERAGE_MUD_AMOUNT;
418
419         /*return ((float)AVERAGE_MUD_AMOUNT + 2.0 * noise2d_perlin(
420                         0.5+(float)p.X/200, 0.5+(float)p.Y/200,
421                         seed+91013, 3, 0.55));*/
422
423         return noise_mud->result[index];
424 }
425
426
427 bool MapgenV6::getHaveBeach(int index)
428 {
429         // Determine whether to have sand here
430         /*double sandnoise = noise2d_perlin(
431                         0.2+(float)p2d.X/250, 0.7+(float)p2d.Y/250,
432                         seed+59420, 3, 0.50);*/
433
434         float sandnoise = noise_beach->result[index];
435         return (sandnoise > freq_beach);
436 }
437
438
439 BiomeV6Type MapgenV6::getBiome(int index, v2s16 p)
440 {
441         // Just do something very simple as for now
442         /*double d = noise2d_perlin(
443                         0.6+(float)p2d.X/250, 0.2+(float)p2d.Y/250,
444                         seed+9130, 3, 0.50);*/
445
446         float d = noise_biome->result[index];
447         float h = noise_humidity->result[index];
448
449         if (spflags & MGV6_SNOWBIOMES) {
450                 float blend = (spflags & MGV6_BIOMEBLEND) ? noise2d(p.X, p.Y, seed) / 40 : 0;
451
452                 if (d > MGV6_FREQ_HOT + blend) {
453                         if (h > MGV6_FREQ_JUNGLE + blend)
454                                 return BT_JUNGLE;
455
456                         return BT_DESERT;
457                 }
458
459                 if (d < MGV6_FREQ_SNOW + blend) {
460                         if (h > MGV6_FREQ_TAIGA + blend)
461                                 return BT_TAIGA;
462
463                         return BT_TUNDRA;
464                 }
465
466                 return BT_NORMAL;
467         }
468
469         if (d > freq_desert)
470                 return BT_DESERT;
471
472         if ((spflags & MGV6_BIOMEBLEND) && (d > freq_desert - 0.10) &&
473                         ((noise2d(p.X, p.Y, seed) + 1.0) > (freq_desert - d) * 20.0))
474                 return BT_DESERT;
475
476         if ((spflags & MGV6_JUNGLES) && h > 0.75)
477                 return BT_JUNGLE;
478
479         return BT_NORMAL;
480
481 }
482
483
484 u32 MapgenV6::get_blockseed(u64 seed, v3s16 p)
485 {
486         s32 x = p.X, y = p.Y, z = p.Z;
487         return (u32)(seed % 0x100000000ULL) + z * 38134234 + y * 42123 + x * 23;
488 }
489
490
491 //////////////////////// Map generator
492
493 void MapgenV6::makeChunk(BlockMakeData *data)
494 {
495         // Pre-conditions
496         assert(data->vmanip);
497         assert(data->nodedef);
498         assert(data->blockpos_requested.X >= data->blockpos_min.X &&
499                 data->blockpos_requested.Y >= data->blockpos_min.Y &&
500                 data->blockpos_requested.Z >= data->blockpos_min.Z);
501         assert(data->blockpos_requested.X <= data->blockpos_max.X &&
502                 data->blockpos_requested.Y <= data->blockpos_max.Y &&
503                 data->blockpos_requested.Z <= data->blockpos_max.Z);
504
505         this->generating = true;
506         this->vm   = data->vmanip;
507         this->ndef = data->nodedef;
508
509         // Hack: use minimum block coords for old code that assumes a single block
510         v3s16 blockpos_min = data->blockpos_min;
511         v3s16 blockpos_max = data->blockpos_max;
512
513         // Area of central chunk
514         node_min = blockpos_min * MAP_BLOCKSIZE;
515         node_max = (blockpos_max + v3s16(1, 1, 1)) * MAP_BLOCKSIZE - v3s16(1, 1, 1);
516
517         // Full allocated area
518         full_node_min = (blockpos_min - 1) * MAP_BLOCKSIZE;
519         full_node_max = (blockpos_max + 2) * MAP_BLOCKSIZE - v3s16(1, 1, 1);
520
521         central_area_size = node_max - node_min + v3s16(1, 1, 1);
522         assert(central_area_size.X == central_area_size.Z);
523
524         // Create a block-specific seed
525         blockseed = get_blockseed(data->seed, full_node_min);
526
527         // Make some noise
528         calculateNoise();
529
530         // Maximum height of the stone surface and obstacles.
531         // This is used to guide the cave generation
532         s16 stone_surface_max_y;
533
534         // Generate general ground level to full area
535         stone_surface_max_y = generateGround();
536
537         // Create initial heightmap to limit caves
538         updateHeightmap(node_min, node_max);
539
540         const s16 max_spread_amount = MAP_BLOCKSIZE;
541         // Limit dirt flow area by 1 because mud is flown into neighbors.
542         s16 mudflow_minpos = -max_spread_amount + 1;
543         s16 mudflow_maxpos = central_area_size.X + max_spread_amount - 2;
544
545         // Loop this part, it will make stuff look older and newer nicely
546         const u32 age_loops = 2;
547         for (u32 i_age = 0; i_age < age_loops; i_age++) { // Aging loop
548                 // Make caves (this code is relatively horrible)
549                 if (flags & MG_CAVES)
550                         generateCaves(stone_surface_max_y);
551
552                 // Add mud to the central chunk
553                 addMud();
554
555                 // Flow mud away from steep edges
556                 if (spflags & MGV6_MUDFLOW)
557                         flowMud(mudflow_minpos, mudflow_maxpos);
558
559         }
560
561         // Update heightmap after mudflow
562         updateHeightmap(node_min, node_max);
563
564         // Add dungeons
565         if ((flags & MG_DUNGEONS) && stone_surface_max_y >= node_min.Y &&
566                         full_node_min.Y >= dungeon_ymin && full_node_max.Y <= dungeon_ymax) {
567                 u16 num_dungeons = std::fmax(std::floor(
568                         NoisePerlin3D(&np_dungeons, node_min.X, node_min.Y, node_min.Z, seed)), 0.0f);
569
570                 if (num_dungeons >= 1) {
571                         PseudoRandom ps(blockseed + 4713);
572
573                         DungeonParams dp;
574
575                         dp.seed              = seed;
576                         dp.num_dungeons      = num_dungeons;
577                         dp.only_in_ground    = true;
578                         dp.corridor_len_min  = 1;
579                         dp.corridor_len_max  = 13;
580                         dp.num_rooms         = ps.range(2, 16);
581                         dp.large_room_chance = (ps.range(1, 4) == 1) ? 1 : 0;
582
583                         dp.np_alt_wall
584                                 = NoiseParams(-0.4, 1.0, v3f(40.0, 40.0, 40.0), 32474, 6, 1.1, 2.0);
585
586                         if (getBiome(0, v2s16(node_min.X, node_min.Z)) == BT_DESERT) {
587                                 dp.c_wall              = c_desert_stone;
588                                 dp.c_alt_wall          = CONTENT_IGNORE;
589                                 dp.c_stair             = c_stair_desert_stone;
590
591                                 dp.diagonal_dirs       = true;
592                                 dp.holesize            = v3s16(2, 3, 2);
593                                 dp.room_size_min       = v3s16(6, 9, 6);
594                                 dp.room_size_max       = v3s16(10, 11, 10);
595                                 dp.room_size_large_min = v3s16(10, 13, 10);
596                                 dp.room_size_large_max = v3s16(18, 21, 18);
597                                 dp.notifytype          = GENNOTIFY_TEMPLE;
598                         } else {
599                                 dp.c_wall              = c_cobble;
600                                 dp.c_alt_wall          = c_mossycobble;
601                                 dp.c_stair             = c_stair_cobble;
602
603                                 dp.diagonal_dirs       = false;
604                                 dp.holesize            = v3s16(1, 2, 1);
605                                 dp.room_size_min       = v3s16(4, 4, 4);
606                                 dp.room_size_max       = v3s16(8, 6, 8);
607                                 dp.room_size_large_min = v3s16(8, 8, 8);
608                                 dp.room_size_large_max = v3s16(16, 16, 16);
609                                 dp.notifytype          = GENNOTIFY_DUNGEON;
610                         }
611
612                         DungeonGen dgen(ndef, &gennotify, &dp);
613                         dgen.generate(vm, blockseed, full_node_min, full_node_max);
614                 }
615         }
616
617         // Add top and bottom side of water to transforming_liquid queue
618         updateLiquid(&data->transforming_liquid, full_node_min, full_node_max);
619
620         // Add surface nodes
621         growGrass();
622
623         // Generate some trees, and add grass, if a jungle
624         if (spflags & MGV6_TREES)
625                 placeTreesAndJungleGrass();
626
627         // Generate the registered decorations
628         if (flags & MG_DECORATIONS)
629                 m_emerge->decomgr->placeAllDecos(this, blockseed, node_min, node_max);
630
631         // Generate the registered ores
632         m_emerge->oremgr->placeAllOres(this, blockseed, node_min, node_max);
633
634         // Calculate lighting
635         if (flags & MG_LIGHT)
636                 calcLighting(node_min - v3s16(1, 1, 1) * MAP_BLOCKSIZE,
637                         node_max + v3s16(1, 0, 1) * MAP_BLOCKSIZE,
638                         full_node_min, full_node_max);
639
640         this->generating = false;
641 }
642
643
644 void MapgenV6::calculateNoise()
645 {
646         int x = node_min.X;
647         int z = node_min.Z;
648         int fx = full_node_min.X;
649         int fz = full_node_min.Z;
650
651         if (!(spflags & MGV6_FLAT)) {
652                 noise_terrain_base->perlinMap2D_PO(x, 0.5, z, 0.5);
653                 noise_terrain_higher->perlinMap2D_PO(x, 0.5, z, 0.5);
654                 noise_steepness->perlinMap2D_PO(x, 0.5, z, 0.5);
655                 noise_height_select->perlinMap2D_PO(x, 0.5, z, 0.5);
656                 noise_mud->perlinMap2D_PO(x, 0.5, z, 0.5);
657         }
658
659         noise_beach->perlinMap2D_PO(x, 0.2, z, 0.7);
660
661         noise_biome->perlinMap2D_PO(fx, 0.6, fz, 0.2);
662         noise_humidity->perlinMap2D_PO(fx, 0.0, fz, 0.0);
663         // Humidity map does not need range limiting 0 to 1,
664         // only humidity at point does
665 }
666
667
668 int MapgenV6::generateGround()
669 {
670         //TimeTaker timer1("Generating ground level");
671         MapNode n_air(CONTENT_AIR), n_water_source(c_water_source);
672         MapNode n_stone(c_stone), n_desert_stone(c_desert_stone);
673         MapNode n_ice(c_ice);
674         int stone_surface_max_y = -MAX_MAP_GENERATION_LIMIT;
675
676         u32 index = 0;
677         for (s16 z = node_min.Z; z <= node_max.Z; z++)
678         for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
679                 // Surface height
680                 s16 surface_y = (s16)baseTerrainLevelFromMap(index);
681
682                 // Log it
683                 if (surface_y > stone_surface_max_y)
684                         stone_surface_max_y = surface_y;
685
686                 BiomeV6Type bt = getBiome(v2s16(x, z));
687
688                 // Fill ground with stone
689                 const v3s16 &em = vm->m_area.getExtent();
690                 u32 i = vm->m_area.index(x, node_min.Y, z);
691                 for (s16 y = node_min.Y; y <= node_max.Y; y++) {
692                         if (vm->m_data[i].getContent() == CONTENT_IGNORE) {
693                                 if (y <= surface_y) {
694                                         vm->m_data[i] = (y >= MGV6_DESERT_STONE_BASE
695                                                         && bt == BT_DESERT) ?
696                                                 n_desert_stone : n_stone;
697                                 } else if (y <= water_level) {
698                                         vm->m_data[i] = (y >= MGV6_ICE_BASE
699                                                         && bt == BT_TUNDRA) ?
700                                                 n_ice : n_water_source;
701                                 } else {
702                                         vm->m_data[i] = n_air;
703                                 }
704                         }
705                         VoxelArea::add_y(em, i, 1);
706                 }
707         }
708
709         return stone_surface_max_y;
710 }
711
712
713 void MapgenV6::addMud()
714 {
715         // 15ms @cs=8
716         //TimeTaker timer1("add mud");
717         MapNode n_dirt(c_dirt), n_gravel(c_gravel);
718         MapNode n_sand(c_sand), n_desert_sand(c_desert_sand);
719         MapNode addnode;
720
721         u32 index = 0;
722         for (s16 z = node_min.Z; z <= node_max.Z; z++)
723         for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
724                 // Randomize mud amount
725                 s16 mud_add_amount = getMudAmount(index) / 2.0 + 0.5;
726
727                 // Find ground level
728                 s16 surface_y = find_stone_level(v2s16(x, z)); /////////////////optimize this!
729
730                 // Handle area not found
731                 if (surface_y == vm->m_area.MinEdge.Y - 1)
732                         continue;
733
734                 BiomeV6Type bt = getBiome(v2s16(x, z));
735                 addnode = (bt == BT_DESERT) ? n_desert_sand : n_dirt;
736
737                 if (bt == BT_DESERT && surface_y + mud_add_amount <= water_level + 1) {
738                         addnode = n_sand;
739                 } else if (mud_add_amount <= 0) {
740                         mud_add_amount = 1 - mud_add_amount;
741                         addnode = n_gravel;
742                 } else if (bt != BT_DESERT && getHaveBeach(index) &&
743                                 surface_y + mud_add_amount <= water_level + 2) {
744                         addnode = n_sand;
745                 }
746
747                 if ((bt == BT_DESERT || bt == BT_TUNDRA) && surface_y > 20)
748                         mud_add_amount = MYMAX(0, mud_add_amount - (surface_y - 20) / 5);
749
750                 /* If topmost node is grass, change it to mud.  It might be if it was
751                 // flown to there from a neighboring chunk and then converted.
752                 u32 i = vm->m_area.index(x, surface_y, z);
753                 if (vm->m_data[i].getContent() == c_dirt_with_grass)
754                         vm->m_data[i] = n_dirt;*/
755
756                 // Add mud on ground
757                 s16 mudcount = 0;
758                 const v3s16 &em = vm->m_area.getExtent();
759                 s16 y_start = surface_y + 1;
760                 u32 i = vm->m_area.index(x, y_start, z);
761                 for (s16 y = y_start; y <= node_max.Y; y++) {
762                         if (mudcount >= mud_add_amount)
763                                 break;
764
765                         vm->m_data[i] = addnode;
766                         mudcount++;
767
768                         VoxelArea::add_y(em, i, 1);
769                 }
770         }
771 }
772
773
774 void MapgenV6::flowMud(s16 &mudflow_minpos, s16 &mudflow_maxpos)
775 {
776         // 340ms @cs=8
777         //TimeTaker timer1("flow mud");
778
779         // Iterate a few times
780         for (s16 k = 0; k < 3; k++) {
781                 for (s16 z = mudflow_minpos; z <= mudflow_maxpos; z++)
782                 for (s16 x = mudflow_minpos; x <= mudflow_maxpos; x++) {
783                         // Invert coordinates every 2nd iteration
784                         if (k % 2 == 0) {
785                                 x = mudflow_maxpos - (x - mudflow_minpos);
786                                 z = mudflow_maxpos - (z - mudflow_minpos);
787                         }
788
789                         // Node position in 2d
790                         v2s16 p2d = v2s16(node_min.X, node_min.Z) + v2s16(x, z);
791
792                         const v3s16 &em = vm->m_area.getExtent();
793                         u32 i = vm->m_area.index(p2d.X, node_max.Y, p2d.Y);
794                         s16 y = node_max.Y;
795
796                         while (y >= node_min.Y) {
797
798                         for (;; y--) {
799                                 MapNode *n = NULL;
800                                 // Find mud
801                                 for (; y >= node_min.Y; y--) {
802                                         n = &vm->m_data[i];
803                                         if (n->getContent() == c_dirt ||
804                                                         n->getContent() == c_dirt_with_grass ||
805                                                         n->getContent() == c_gravel)
806                                                 break;
807
808                                         VoxelArea::add_y(em, i, -1);
809                                 }
810
811                                 // Stop if out of area
812                                 //if(vmanip.m_area.contains(i) == false)
813                                 if (y < node_min.Y)
814                                         break;
815
816                                 if (n->getContent() == c_dirt ||
817                                                 n->getContent() == c_dirt_with_grass) {
818                                         // Make it exactly mud
819                                         n->setContent(c_dirt);
820
821                                         // Don't flow it if the stuff under it is not mud
822                                         {
823                                                 u32 i2 = i;
824                                                 VoxelArea::add_y(em, i2, -1);
825                                                 // Cancel if out of area
826                                                 if (!vm->m_area.contains(i2))
827                                                         continue;
828                                                 MapNode *n2 = &vm->m_data[i2];
829                                                 if (n2->getContent() != c_dirt &&
830                                                                 n2->getContent() != c_dirt_with_grass)
831                                                         continue;
832                                         }
833                                 }
834
835                                 static const v3s16 dirs4[4] = {
836                                         v3s16(0, 0, 1), // back
837                                         v3s16(1, 0, 0), // right
838                                         v3s16(0, 0, -1), // front
839                                         v3s16(-1, 0, 0), // left
840                                 };
841
842                                 // Check that upper is walkable. Cancel
843                                 // dropping if upper keeps it in place.
844                                 u32 i3 = i;
845                                 VoxelArea::add_y(em, i3, 1);
846                                 MapNode *n3 = NULL;
847
848                                 if (vm->m_area.contains(i3)) {
849                                         n3 = &vm->m_data[i3];
850                                         if (ndef->get(*n3).walkable)
851                                                 continue;
852                                 }
853
854                                 // Drop mud on side
855                                 for (const v3s16 &dirp : dirs4) {
856                                         u32 i2 = i;
857                                         // Move to side
858                                         VoxelArea::add_p(em, i2, dirp);
859                                         // Fail if out of area
860                                         if (!vm->m_area.contains(i2))
861                                                 continue;
862                                         // Check that side is air
863                                         MapNode *n2 = &vm->m_data[i2];
864                                         if (ndef->get(*n2).walkable)
865                                                 continue;
866                                         // Check that under side is air
867                                         VoxelArea::add_y(em, i2, -1);
868                                         if (!vm->m_area.contains(i2))
869                                                 continue;
870                                         n2 = &vm->m_data[i2];
871                                         if (ndef->get(*n2).walkable)
872                                                 continue;
873                                         // Loop further down until not air
874                                         bool dropped_to_unknown = false;
875                                         do {
876                                                 VoxelArea::add_y(em, i2, -1);
877                                                 n2 = &vm->m_data[i2];
878                                                 // if out of known area
879                                                 if (!vm->m_area.contains(i2) ||
880                                                                 n2->getContent() == CONTENT_IGNORE) {
881                                                         dropped_to_unknown = true;
882                                                         break;
883                                                 }
884                                         } while (!ndef->get(*n2).walkable);
885                                         // Loop one up so that we're in air
886                                         VoxelArea::add_y(em, i2, 1);
887
888                                         // Move mud to new place. Outside mapchunk remove
889                                         // any decorations above removed or placed mud.
890                                         if (!dropped_to_unknown)
891                                                 moveMud(i, i2, i3, p2d, em);
892
893                                         // Done
894                                         break;
895                                 }
896                         }
897                         }
898                 }
899         }
900 }
901
902
903 void MapgenV6::moveMud(u32 remove_index, u32 place_index,
904         u32 above_remove_index, v2s16 pos, v3s16 em)
905 {
906         MapNode n_air(CONTENT_AIR);
907         // Copy mud from old place to new place
908         vm->m_data[place_index] = vm->m_data[remove_index];
909         // Set old place to be air
910         vm->m_data[remove_index] = n_air;
911         // Outside the mapchunk decorations may need to be removed if above removed
912         // mud or if half-buried in placed mud. Placed mud is to the side of pos so
913         // use 'pos.X >= node_max.X' etc.
914         if (pos.X >= node_max.X || pos.X <= node_min.X ||
915                         pos.Y >= node_max.Z || pos.Y <= node_min.Z) {
916                 // 'above remove' node is above removed mud. If it is not air, water or
917                 // 'ignore' it is a decoration that needs removing. Also search upwards
918                 // to remove a possible stacked decoration.
919                 // Check for 'ignore' because stacked decorations can penetrate into
920                 // 'ignore' nodes above the mapchunk.
921                 while (vm->m_area.contains(above_remove_index) &&
922                                 vm->m_data[above_remove_index].getContent() != CONTENT_AIR &&
923                                 vm->m_data[above_remove_index].getContent() != c_water_source &&
924                                 vm->m_data[above_remove_index].getContent() != CONTENT_IGNORE) {
925                         vm->m_data[above_remove_index] = n_air;
926                         VoxelArea::add_y(em, above_remove_index, 1);
927                 }
928                 // Mud placed may have partially-buried a stacked decoration, search
929                 // above and remove.
930                 VoxelArea::add_y(em, place_index, 1);
931                 while (vm->m_area.contains(place_index) &&
932                                 vm->m_data[place_index].getContent() != CONTENT_AIR &&
933                                 vm->m_data[place_index].getContent() != c_water_source &&
934                                 vm->m_data[place_index].getContent() != CONTENT_IGNORE) {
935                         vm->m_data[place_index] = n_air;
936                         VoxelArea::add_y(em, place_index, 1);
937                 }
938         }
939 }
940
941
942 void MapgenV6::placeTreesAndJungleGrass()
943 {
944         //TimeTaker t("placeTrees");
945         if (node_max.Y < water_level)
946                 return;
947
948         PseudoRandom grassrandom(blockseed + 53);
949         content_t c_junglegrass = ndef->getId("mapgen_junglegrass");
950         // if we don't have junglegrass, don't place cignore... that's bad
951         if (c_junglegrass == CONTENT_IGNORE)
952                 c_junglegrass = CONTENT_AIR;
953         MapNode n_junglegrass(c_junglegrass);
954         const v3s16 &em = vm->m_area.getExtent();
955
956         // Divide area into parts
957         s16 div = 8;
958         s16 sidelen = central_area_size.X / div;
959         double area = sidelen * sidelen;
960
961         // N.B.  We must add jungle grass first, since tree leaves will
962         // obstruct the ground, giving us a false ground level
963         for (s16 z0 = 0; z0 < div; z0++)
964         for (s16 x0 = 0; x0 < div; x0++) {
965                 // Center position of part of division
966                 v2s16 p2d_center(
967                         node_min.X + sidelen / 2 + sidelen * x0,
968                         node_min.Z + sidelen / 2 + sidelen * z0
969                 );
970                 // Minimum edge of part of division
971                 v2s16 p2d_min(
972                         node_min.X + sidelen * x0,
973                         node_min.Z + sidelen * z0
974                 );
975                 // Maximum edge of part of division
976                 v2s16 p2d_max(
977                         node_min.X + sidelen + sidelen * x0 - 1,
978                         node_min.Z + sidelen + sidelen * z0 - 1
979                 );
980
981                 // Get biome at center position of part of division
982                 BiomeV6Type bt = getBiome(p2d_center);
983
984                 // Amount of trees
985                 u32 tree_count;
986                 if (bt == BT_JUNGLE || bt == BT_TAIGA || bt == BT_NORMAL) {
987                         tree_count = area * getTreeAmount(p2d_center);
988                         if (bt == BT_JUNGLE)
989                                 tree_count *= 4;
990                 } else {
991                         tree_count = 0;
992                 }
993
994                 // Add jungle grass
995                 if (bt == BT_JUNGLE) {
996                         float humidity = getHumidity(p2d_center);
997                         u32 grass_count = 5 * humidity * tree_count;
998                         for (u32 i = 0; i < grass_count; i++) {
999                                 s16 x = grassrandom.range(p2d_min.X, p2d_max.X);
1000                                 s16 z = grassrandom.range(p2d_min.Y, p2d_max.Y);
1001                                 int mapindex = central_area_size.X * (z - node_min.Z)
1002                                                                 + (x - node_min.X);
1003                                 s16 y = heightmap[mapindex];
1004                                 if (y < water_level)
1005                                         continue;
1006
1007                                 u32 vi = vm->m_area.index(x, y, z);
1008                                 // place on dirt_with_grass, since we know it is exposed to sunlight
1009                                 if (vm->m_data[vi].getContent() == c_dirt_with_grass) {
1010                                         VoxelArea::add_y(em, vi, 1);
1011                                         vm->m_data[vi] = n_junglegrass;
1012                                 }
1013                         }
1014                 }
1015
1016                 // Put trees in random places on part of division
1017                 for (u32 i = 0; i < tree_count; i++) {
1018                         s16 x = myrand_range(p2d_min.X, p2d_max.X);
1019                         s16 z = myrand_range(p2d_min.Y, p2d_max.Y);
1020                         int mapindex = central_area_size.X * (z - node_min.Z)
1021                                                         + (x - node_min.X);
1022                         s16 y = heightmap[mapindex];
1023                         // Don't make a tree under water level
1024                         // Don't make a tree so high that it doesn't fit
1025                         if (y < water_level || y > node_max.Y - 6)
1026                                 continue;
1027
1028                         v3s16 p(x, y, z);
1029                         // Trees grow only on mud and grass
1030                         {
1031                                 u32 i = vm->m_area.index(p);
1032                                 content_t c = vm->m_data[i].getContent();
1033                                 if (c != c_dirt &&
1034                                                 c != c_dirt_with_grass &&
1035                                                 c != c_dirt_with_snow)
1036                                         continue;
1037                         }
1038                         p.Y++;
1039
1040                         // Make a tree
1041                         if (bt == BT_JUNGLE) {
1042                                 treegen::make_jungletree(*vm, p, ndef, myrand());
1043                         } else if (bt == BT_TAIGA) {
1044                                 treegen::make_pine_tree(*vm, p - v3s16(0, 1, 0), ndef, myrand());
1045                         } else if (bt == BT_NORMAL) {
1046                                 bool is_apple_tree = (myrand_range(0, 3) == 0) &&
1047                                                         getHaveAppleTree(v2s16(x, z));
1048                                 treegen::make_tree(*vm, p, is_apple_tree, ndef, myrand());
1049                         }
1050                 }
1051         }
1052         //printf("placeTreesAndJungleGrass: %dms\n", t.stop());
1053 }
1054
1055
1056 void MapgenV6::growGrass() // Add surface nodes
1057 {
1058         MapNode n_dirt_with_grass(c_dirt_with_grass);
1059         MapNode n_dirt_with_snow(c_dirt_with_snow);
1060         MapNode n_snowblock(c_snowblock);
1061         MapNode n_snow(c_snow);
1062         const v3s16 &em = vm->m_area.getExtent();
1063
1064         u32 index = 0;
1065         for (s16 z = full_node_min.Z; z <= full_node_max.Z; z++)
1066         for (s16 x = full_node_min.X; x <= full_node_max.X; x++, index++) {
1067                 // Find the lowest surface to which enough light ends up to make
1068                 // grass grow.  Basically just wait until not air and not leaves.
1069                 s16 surface_y = 0;
1070                 {
1071                         u32 i = vm->m_area.index(x, node_max.Y, z);
1072                         s16 y;
1073                         // Go to ground level
1074                         for (y = node_max.Y; y >= full_node_min.Y; y--) {
1075                                 MapNode &n = vm->m_data[i];
1076                                 if (ndef->get(n).param_type != CPT_LIGHT ||
1077                                                 ndef->get(n).liquid_type != LIQUID_NONE ||
1078                                                 n.getContent() == c_ice)
1079                                         break;
1080                                 VoxelArea::add_y(em, i, -1);
1081                         }
1082                         surface_y = (y >= full_node_min.Y) ? y : full_node_min.Y;
1083                 }
1084
1085                 BiomeV6Type bt = getBiome(index, v2s16(x, z));
1086                 u32 i = vm->m_area.index(x, surface_y, z);
1087                 content_t c = vm->m_data[i].getContent();
1088                 if (surface_y >= water_level - 20) {
1089                         if (bt == BT_TAIGA && c == c_dirt) {
1090                                 vm->m_data[i] = n_dirt_with_snow;
1091                         } else if (bt == BT_TUNDRA) {
1092                                 if (c == c_dirt) {
1093                                         vm->m_data[i] = n_snowblock;
1094                                         VoxelArea::add_y(em, i, -1);
1095                                         vm->m_data[i] = n_dirt_with_snow;
1096                                 } else if (c == c_stone && surface_y < node_max.Y) {
1097                                         VoxelArea::add_y(em, i, 1);
1098                                         vm->m_data[i] = n_snowblock;
1099                                 }
1100                         } else if (c == c_dirt) {
1101                                 vm->m_data[i] = n_dirt_with_grass;
1102                         }
1103                 }
1104         }
1105 }
1106
1107
1108 void MapgenV6::generateCaves(int max_stone_y)
1109 {
1110         float cave_amount = NoisePerlin2D(np_cave, node_min.X, node_min.Y, seed);
1111         int volume_nodes = (node_max.X - node_min.X + 1) *
1112                                            (node_max.Y - node_min.Y + 1) * MAP_BLOCKSIZE;
1113         cave_amount = MYMAX(0.0, cave_amount);
1114         u32 caves_count = cave_amount * volume_nodes / 50000;
1115         u32 bruises_count = 1;
1116         PseudoRandom ps(blockseed + 21343);
1117         PseudoRandom ps2(blockseed + 1032);
1118
1119         if (ps.range(1, 6) == 1)
1120                 bruises_count = ps.range(0, ps.range(0, 2));
1121
1122         if (getBiome(v2s16(node_min.X, node_min.Z)) == BT_DESERT) {
1123                 caves_count   /= 3;
1124                 bruises_count /= 3;
1125         }
1126
1127         for (u32 i = 0; i < caves_count + bruises_count; i++) {
1128                 CavesV6 cave(ndef, &gennotify, water_level, c_water_source, c_lava_source);
1129
1130                 bool large_cave = (i >= caves_count);
1131                 cave.makeCave(vm, node_min, node_max, &ps, &ps2,
1132                         large_cave, max_stone_y, heightmap);
1133         }
1134 }