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