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