]> git.lizzy.rs Git - dragonfireclient.git/blob - src/mapgen/mapgen_v6.cpp
Randomwalk caves: Add parameters for number, proportion flooded. Allow small caves...
[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 "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 flowed 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         const v3s16 &em = vm->m_area.getExtent();
777         static const v3s16 dirs4[4] = {
778                 v3s16(0, 0, 1), // Back
779                 v3s16(1, 0, 0), // Right
780                 v3s16(0, 0, -1), // Front
781                 v3s16(-1, 0, 0), // Left
782         };
783         
784         // Iterate twice
785         for (s16 k = 0; k < 2; k++) {
786                 for (s16 z = mudflow_minpos; z <= mudflow_maxpos; z++)
787                 for (s16 x = mudflow_minpos; x <= mudflow_maxpos; x++) {
788                         // Node column position
789                         v2s16 p2d;
790                         // Invert coordinates on second iteration to process columns in
791                         // opposite order, to avoid a directional bias.
792                         if (k == 1)
793                                 p2d = v2s16(node_max.X, node_max.Z) - v2s16(x, z);
794                         else
795                                 p2d = v2s16(node_min.X, node_min.Z) + v2s16(x, z);
796
797                         s16 y = node_max.Y;
798
799                         while (y >= node_min.Y) {
800                                 for (;; y--) {
801                                         u32 i = vm->m_area.index(p2d.X, y, p2d.Y);
802                                         MapNode *n = nullptr;
803
804                                         // Find next mud node in mapchunk column
805                                         for (; y >= node_min.Y; y--) {
806                                                 n = &vm->m_data[i];
807                                                 if (n->getContent() == c_dirt ||
808                                                                 n->getContent() == c_dirt_with_grass ||
809                                                                 n->getContent() == c_gravel)
810                                                         break;
811
812                                                 VoxelArea::add_y(em, i, -1);
813                                         }
814                                         if (y < node_min.Y)
815                                                 // No mud found in mapchunk column, process the next column
816                                                 break;
817
818                                         if (n->getContent() == c_dirt || n->getContent() == c_dirt_with_grass) {
819                                                 // Convert dirt_with_grass to dirt
820                                                 n->setContent(c_dirt);
821                                                 // Don't flow mud if the stuff under it is not mud,
822                                                 // to leave at least 1 node of mud.
823                                                 u32 i2 = i;
824                                                 VoxelArea::add_y(em, i2, -1);
825                                                 MapNode *n2 = &vm->m_data[i2];
826                                                 if (n2->getContent() != c_dirt &&
827                                                                 n2->getContent() != c_dirt_with_grass)
828                                                         // Find next mud node in column
829                                                         continue;
830                                         }
831
832                                         // Check if node above is walkable. If so, cancel
833                                         // flowing as if node above keeps it in place.
834                                         u32 i3 = i;
835                                         VoxelArea::add_y(em, i3, 1);
836                                         MapNode *n3 = &vm->m_data[i3];
837                                         if (ndef->get(*n3).walkable)
838                                                 // Find next mud node in column
839                                                 continue;
840
841                                         // Drop mud on one side
842                                         for (const v3s16 &dirp : dirs4) {
843                                                 u32 i2 = i;
844                                                 // Move to side
845                                                 VoxelArea::add_p(em, i2, dirp);
846                                                 // Check that side is air
847                                                 MapNode *n2 = &vm->m_data[i2];
848                                                 if (ndef->get(*n2).walkable)
849                                                         continue;
850
851                                                 // Check that under side is air
852                                                 VoxelArea::add_y(em, i2, -1);
853                                                 n2 = &vm->m_data[i2];
854                                                 if (ndef->get(*n2).walkable)
855                                                         continue;
856
857                                                 // Loop further down until not air
858                                                 s16 y2 = y - 1; // y of i2
859                                                 bool dropped_to_unknown = false;
860                                                 do {
861                                                         y2--;
862                                                         VoxelArea::add_y(em, i2, -1);
863                                                         n2 = &vm->m_data[i2];
864                                                         // If out of area or in ungenerated world
865                                                         if (y2 < full_node_min.Y || n2->getContent() == CONTENT_IGNORE) {
866                                                                 dropped_to_unknown = true;
867                                                                 break;
868                                                         }
869                                                 } while (!ndef->get(*n2).walkable);
870
871                                                 if (!dropped_to_unknown) {
872                                                         // Move up one so that we're in air
873                                                         VoxelArea::add_y(em, i2, 1);
874                                                         // Move mud to new place, and if outside mapchunk remove
875                                                         // any decorations above removed or placed mud.
876                                                         moveMud(i, i2, i3, p2d, em);
877                                                 }
878                                                 // Done, find next mud node in column
879                                                 break;
880                                         }
881                                 }
882                         }
883                 }
884         }
885 }
886
887
888 void MapgenV6::moveMud(u32 remove_index, u32 place_index,
889         u32 above_remove_index, v2s16 pos, v3s16 em)
890 {
891         MapNode n_air(CONTENT_AIR);
892         // Copy mud from old place to new place
893         vm->m_data[place_index] = vm->m_data[remove_index];
894         // Set old place to be air
895         vm->m_data[remove_index] = n_air;
896         // Outside the mapchunk decorations may need to be removed if above removed
897         // mud or if half-buried in placed mud. Placed mud is to the side of pos so
898         // use 'pos.X >= node_max.X' etc.
899         if (pos.X >= node_max.X || pos.X <= node_min.X ||
900                         pos.Y >= node_max.Z || pos.Y <= node_min.Z) {
901                 // 'above remove' node is above removed mud. If it is not air, water or
902                 // 'ignore' it is a decoration that needs removing. Also search upwards
903                 // to remove a possible stacked decoration.
904                 // Check for 'ignore' because stacked decorations can penetrate into
905                 // 'ignore' nodes above the mapchunk.
906                 while (vm->m_area.contains(above_remove_index) &&
907                                 vm->m_data[above_remove_index].getContent() != CONTENT_AIR &&
908                                 vm->m_data[above_remove_index].getContent() != c_water_source &&
909                                 vm->m_data[above_remove_index].getContent() != CONTENT_IGNORE) {
910                         vm->m_data[above_remove_index] = n_air;
911                         VoxelArea::add_y(em, above_remove_index, 1);
912                 }
913                 // Mud placed may have partially-buried a stacked decoration, search
914                 // above and remove.
915                 VoxelArea::add_y(em, place_index, 1);
916                 while (vm->m_area.contains(place_index) &&
917                                 vm->m_data[place_index].getContent() != CONTENT_AIR &&
918                                 vm->m_data[place_index].getContent() != c_water_source &&
919                                 vm->m_data[place_index].getContent() != CONTENT_IGNORE) {
920                         vm->m_data[place_index] = n_air;
921                         VoxelArea::add_y(em, place_index, 1);
922                 }
923         }
924 }
925
926
927 void MapgenV6::placeTreesAndJungleGrass()
928 {
929         //TimeTaker t("placeTrees");
930         if (node_max.Y < water_level)
931                 return;
932
933         PseudoRandom grassrandom(blockseed + 53);
934         content_t c_junglegrass = ndef->getId("mapgen_junglegrass");
935         // if we don't have junglegrass, don't place cignore... that's bad
936         if (c_junglegrass == CONTENT_IGNORE)
937                 c_junglegrass = CONTENT_AIR;
938         MapNode n_junglegrass(c_junglegrass);
939         const v3s16 &em = vm->m_area.getExtent();
940
941         // Divide area into parts
942         s16 div = 8;
943         s16 sidelen = central_area_size.X / div;
944         double area = sidelen * sidelen;
945
946         // N.B.  We must add jungle grass first, since tree leaves will
947         // obstruct the ground, giving us a false ground level
948         for (s16 z0 = 0; z0 < div; z0++)
949         for (s16 x0 = 0; x0 < div; x0++) {
950                 // Center position of part of division
951                 v2s16 p2d_center(
952                         node_min.X + sidelen / 2 + sidelen * x0,
953                         node_min.Z + sidelen / 2 + sidelen * z0
954                 );
955                 // Minimum edge of part of division
956                 v2s16 p2d_min(
957                         node_min.X + sidelen * x0,
958                         node_min.Z + sidelen * z0
959                 );
960                 // Maximum edge of part of division
961                 v2s16 p2d_max(
962                         node_min.X + sidelen + sidelen * x0 - 1,
963                         node_min.Z + sidelen + sidelen * z0 - 1
964                 );
965
966                 // Get biome at center position of part of division
967                 BiomeV6Type bt = getBiome(p2d_center);
968
969                 // Amount of trees
970                 u32 tree_count;
971                 if (bt == BT_JUNGLE || bt == BT_TAIGA || bt == BT_NORMAL) {
972                         tree_count = area * getTreeAmount(p2d_center);
973                         if (bt == BT_JUNGLE)
974                                 tree_count *= 4;
975                 } else {
976                         tree_count = 0;
977                 }
978
979                 // Add jungle grass
980                 if (bt == BT_JUNGLE) {
981                         float humidity = getHumidity(p2d_center);
982                         u32 grass_count = 5 * humidity * tree_count;
983                         for (u32 i = 0; i < grass_count; i++) {
984                                 s16 x = grassrandom.range(p2d_min.X, p2d_max.X);
985                                 s16 z = grassrandom.range(p2d_min.Y, p2d_max.Y);
986                                 int mapindex = central_area_size.X * (z - node_min.Z)
987                                                                 + (x - node_min.X);
988                                 s16 y = heightmap[mapindex];
989                                 if (y < water_level)
990                                         continue;
991
992                                 u32 vi = vm->m_area.index(x, y, z);
993                                 // place on dirt_with_grass, since we know it is exposed to sunlight
994                                 if (vm->m_data[vi].getContent() == c_dirt_with_grass) {
995                                         VoxelArea::add_y(em, vi, 1);
996                                         vm->m_data[vi] = n_junglegrass;
997                                 }
998                         }
999                 }
1000
1001                 // Put trees in random places on part of division
1002                 for (u32 i = 0; i < tree_count; i++) {
1003                         s16 x = myrand_range(p2d_min.X, p2d_max.X);
1004                         s16 z = myrand_range(p2d_min.Y, p2d_max.Y);
1005                         int mapindex = central_area_size.X * (z - node_min.Z)
1006                                                         + (x - node_min.X);
1007                         s16 y = heightmap[mapindex];
1008                         // Don't make a tree under water level
1009                         // Don't make a tree so high that it doesn't fit
1010                         if (y < water_level || y > node_max.Y - 6)
1011                                 continue;
1012
1013                         v3s16 p(x, y, z);
1014                         // Trees grow only on mud and grass
1015                         {
1016                                 u32 i = vm->m_area.index(p);
1017                                 content_t c = vm->m_data[i].getContent();
1018                                 if (c != c_dirt &&
1019                                                 c != c_dirt_with_grass &&
1020                                                 c != c_dirt_with_snow)
1021                                         continue;
1022                         }
1023                         p.Y++;
1024
1025                         // Make a tree
1026                         if (bt == BT_JUNGLE) {
1027                                 treegen::make_jungletree(*vm, p, ndef, myrand());
1028                         } else if (bt == BT_TAIGA) {
1029                                 treegen::make_pine_tree(*vm, p - v3s16(0, 1, 0), ndef, myrand());
1030                         } else if (bt == BT_NORMAL) {
1031                                 bool is_apple_tree = (myrand_range(0, 3) == 0) &&
1032                                                         getHaveAppleTree(v2s16(x, z));
1033                                 treegen::make_tree(*vm, p, is_apple_tree, ndef, myrand());
1034                         }
1035                 }
1036         }
1037         //printf("placeTreesAndJungleGrass: %dms\n", t.stop());
1038 }
1039
1040
1041 void MapgenV6::growGrass() // Add surface nodes
1042 {
1043         MapNode n_dirt_with_grass(c_dirt_with_grass);
1044         MapNode n_dirt_with_snow(c_dirt_with_snow);
1045         MapNode n_snowblock(c_snowblock);
1046         MapNode n_snow(c_snow);
1047         const v3s16 &em = vm->m_area.getExtent();
1048
1049         u32 index = 0;
1050         for (s16 z = full_node_min.Z; z <= full_node_max.Z; z++)
1051         for (s16 x = full_node_min.X; x <= full_node_max.X; x++, index++) {
1052                 // Find the lowest surface to which enough light ends up to make
1053                 // grass grow.  Basically just wait until not air and not leaves.
1054                 s16 surface_y = 0;
1055                 {
1056                         u32 i = vm->m_area.index(x, node_max.Y, z);
1057                         s16 y;
1058                         // Go to ground level
1059                         for (y = node_max.Y; y >= full_node_min.Y; y--) {
1060                                 MapNode &n = vm->m_data[i];
1061                                 if (ndef->get(n).param_type != CPT_LIGHT ||
1062                                                 ndef->get(n).liquid_type != LIQUID_NONE ||
1063                                                 n.getContent() == c_ice)
1064                                         break;
1065                                 VoxelArea::add_y(em, i, -1);
1066                         }
1067                         surface_y = (y >= full_node_min.Y) ? y : full_node_min.Y;
1068                 }
1069
1070                 BiomeV6Type bt = getBiome(index, v2s16(x, z));
1071                 u32 i = vm->m_area.index(x, surface_y, z);
1072                 content_t c = vm->m_data[i].getContent();
1073                 if (surface_y >= water_level - 20) {
1074                         if (bt == BT_TAIGA && c == c_dirt) {
1075                                 vm->m_data[i] = n_dirt_with_snow;
1076                         } else if (bt == BT_TUNDRA) {
1077                                 if (c == c_dirt) {
1078                                         vm->m_data[i] = n_snowblock;
1079                                         VoxelArea::add_y(em, i, -1);
1080                                         vm->m_data[i] = n_dirt_with_snow;
1081                                 } else if (c == c_stone && surface_y < node_max.Y) {
1082                                         VoxelArea::add_y(em, i, 1);
1083                                         vm->m_data[i] = n_snowblock;
1084                                 }
1085                         } else if (c == c_dirt) {
1086                                 vm->m_data[i] = n_dirt_with_grass;
1087                         }
1088                 }
1089         }
1090 }
1091
1092
1093 void MapgenV6::generateCaves(int max_stone_y)
1094 {
1095         float cave_amount = NoisePerlin2D(np_cave, node_min.X, node_min.Y, seed);
1096         int volume_nodes = (node_max.X - node_min.X + 1) *
1097                                            (node_max.Y - node_min.Y + 1) * MAP_BLOCKSIZE;
1098         cave_amount = MYMAX(0.0, cave_amount);
1099         u32 caves_count = cave_amount * volume_nodes / 50000;
1100         u32 bruises_count = 1;
1101         PseudoRandom ps(blockseed + 21343);
1102         PseudoRandom ps2(blockseed + 1032);
1103
1104         if (ps.range(1, 6) == 1)
1105                 bruises_count = ps.range(0, ps.range(0, 2));
1106
1107         if (getBiome(v2s16(node_min.X, node_min.Z)) == BT_DESERT) {
1108                 caves_count   /= 3;
1109                 bruises_count /= 3;
1110         }
1111
1112         for (u32 i = 0; i < caves_count + bruises_count; i++) {
1113                 CavesV6 cave(ndef, &gennotify, water_level, c_water_source, c_lava_source);
1114
1115                 bool large_cave = (i >= caves_count);
1116                 cave.makeCave(vm, node_min, node_max, &ps, &ps2,
1117                         large_cave, max_stone_y, heightmap);
1118         }
1119 }