]> git.lizzy.rs Git - dragonfireclient.git/blob - src/mapgen/mapgen_v6.cpp
Node definition manager refactor (#7016)
[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 "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         const NodeDefManager *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         np_terrain_base   (-4,   20.0, v3f(250.0, 250.0, 250.0), 82341,  5, 0.6,  2.0),
150         np_terrain_higher (20,   16.0, v3f(500.0, 500.0, 500.0), 85039,  5, 0.6,  2.0),
151         np_steepness      (0.85, 0.5,  v3f(125.0, 125.0, 125.0), -932,   5, 0.7,  2.0),
152         np_height_select  (0,    1.0,  v3f(250.0, 250.0, 250.0), 4213,   5, 0.69, 2.0),
153         np_mud            (4,    2.0,  v3f(200.0, 200.0, 200.0), 91013,  3, 0.55, 2.0),
154         np_beach          (0,    1.0,  v3f(250.0, 250.0, 250.0), 59420,  3, 0.50, 2.0),
155         np_biome          (0,    1.0,  v3f(500.0, 500.0, 500.0), 9130,   3, 0.50, 2.0),
156         np_cave           (6,    6.0,  v3f(250.0, 250.0, 250.0), 34329,  3, 0.50, 2.0),
157         np_humidity       (0.5,  0.5,  v3f(500.0, 500.0, 500.0), 72384,  3, 0.50, 2.0),
158         np_trees          (0,    1.0,  v3f(125.0, 125.0, 125.0), 2,      4, 0.66, 2.0),
159         np_apple_trees    (0,    1.0,  v3f(100.0, 100.0, 100.0), 342902, 3, 0.45, 2.0)
160 {
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         }
459
460         if (d > freq_desert)
461                 return BT_DESERT;
462
463         if ((spflags & MGV6_BIOMEBLEND) && (d > freq_desert - 0.10) &&
464                         ((noise2d(p.X, p.Y, seed) + 1.0) > (freq_desert - d) * 20.0))
465                 return BT_DESERT;
466
467         if ((spflags & MGV6_JUNGLES) && h > 0.75)
468                 return BT_JUNGLE;
469
470         return BT_NORMAL;
471
472 }
473
474
475 u32 MapgenV6::get_blockseed(u64 seed, v3s16 p)
476 {
477         s32 x = p.X, y = p.Y, z = p.Z;
478         return (u32)(seed % 0x100000000ULL) + z * 38134234 + y * 42123 + x * 23;
479 }
480
481
482 //////////////////////// Map generator
483
484 void MapgenV6::makeChunk(BlockMakeData *data)
485 {
486         // Pre-conditions
487         assert(data->vmanip);
488         assert(data->nodedef);
489         assert(data->blockpos_requested.X >= data->blockpos_min.X &&
490                 data->blockpos_requested.Y >= data->blockpos_min.Y &&
491                 data->blockpos_requested.Z >= data->blockpos_min.Z);
492         assert(data->blockpos_requested.X <= data->blockpos_max.X &&
493                 data->blockpos_requested.Y <= data->blockpos_max.Y &&
494                 data->blockpos_requested.Z <= data->blockpos_max.Z);
495
496         this->generating = true;
497         this->vm   = data->vmanip;
498         this->ndef = data->nodedef;
499
500         // Hack: use minimum block coords for old code that assumes a single block
501         v3s16 blockpos_min = data->blockpos_min;
502         v3s16 blockpos_max = data->blockpos_max;
503
504         // Area of central chunk
505         node_min = blockpos_min * MAP_BLOCKSIZE;
506         node_max = (blockpos_max + v3s16(1, 1, 1)) * MAP_BLOCKSIZE - v3s16(1, 1, 1);
507
508         // Full allocated area
509         full_node_min = (blockpos_min - 1) * MAP_BLOCKSIZE;
510         full_node_max = (blockpos_max + 2) * MAP_BLOCKSIZE - v3s16(1, 1, 1);
511
512         central_area_size = node_max - node_min + v3s16(1, 1, 1);
513         assert(central_area_size.X == central_area_size.Z);
514
515         // Create a block-specific seed
516         blockseed = get_blockseed(data->seed, full_node_min);
517
518         // Make some noise
519         calculateNoise();
520
521         // Maximum height of the stone surface and obstacles.
522         // This is used to guide the cave generation
523         s16 stone_surface_max_y;
524
525         // Generate general ground level to full area
526         stone_surface_max_y = generateGround();
527
528         // Create initial heightmap to limit caves
529         updateHeightmap(node_min, node_max);
530
531         const s16 max_spread_amount = MAP_BLOCKSIZE;
532         // Limit dirt flow area by 1 because mud is flown into neighbors.
533         s16 mudflow_minpos = -max_spread_amount + 1;
534         s16 mudflow_maxpos = central_area_size.X + max_spread_amount - 2;
535
536         // Loop this part, it will make stuff look older and newer nicely
537         const u32 age_loops = 2;
538         for (u32 i_age = 0; i_age < age_loops; i_age++) { // Aging loop
539                 // Make caves (this code is relatively horrible)
540                 if (flags & MG_CAVES)
541                         generateCaves(stone_surface_max_y);
542
543                 // Add mud to the central chunk
544                 addMud();
545
546                 // Flow mud away from steep edges
547                 if (spflags & MGV6_MUDFLOW)
548                         flowMud(mudflow_minpos, mudflow_maxpos);
549
550         }
551
552         // Update heightmap after mudflow
553         updateHeightmap(node_min, node_max);
554
555         // Add dungeons
556         if ((flags & MG_DUNGEONS) && (stone_surface_max_y >= node_min.Y)) {
557                 DungeonParams dp;
558
559                 dp.seed             = seed;
560                 dp.c_water          = c_water_source;
561                 dp.c_river_water    = c_water_source;
562
563                 dp.only_in_ground   = true;
564                 dp.corridor_len_min = 1;
565                 dp.corridor_len_max = 13;
566                 dp.rooms_min        = 2;
567                 dp.rooms_max        = 16;
568                 dp.y_min            = -MAX_MAP_GENERATION_LIMIT;
569                 dp.y_max            = MAX_MAP_GENERATION_LIMIT;
570
571                 dp.np_density
572                         = NoiseParams(0.9, 0.5, v3f(500.0, 500.0, 500.0), 0, 2, 0.8, 2.0);
573                 dp.np_alt_wall
574                         = NoiseParams(-0.4, 1.0, v3f(40.0, 40.0, 40.0), 32474, 6, 1.1, 2.0);
575
576                 if (getBiome(0, v2s16(node_min.X, node_min.Z)) == BT_DESERT) {
577                         dp.c_wall              = c_desert_stone;
578                         dp.c_alt_wall          = CONTENT_IGNORE;
579                         dp.c_stair             = c_stair_desert_stone;
580
581                         dp.diagonal_dirs       = true;
582                         dp.holesize            = v3s16(2, 3, 2);
583                         dp.room_size_min       = v3s16(6, 9, 6);
584                         dp.room_size_max       = v3s16(10, 11, 10);
585                         dp.room_size_large_min = v3s16(10, 13, 10);
586                         dp.room_size_large_max = v3s16(18, 21, 18);
587                         dp.notifytype          = GENNOTIFY_TEMPLE;
588                 } else {
589                         dp.c_wall              = c_cobble;
590                         dp.c_alt_wall          = c_mossycobble;
591                         dp.c_stair             = c_stair_cobble;
592
593                         dp.diagonal_dirs       = false;
594                         dp.holesize            = v3s16(1, 2, 1);
595                         dp.room_size_min       = v3s16(4, 4, 4);
596                         dp.room_size_max       = v3s16(8, 6, 8);
597                         dp.room_size_large_min = v3s16(8, 8, 8);
598                         dp.room_size_large_max = v3s16(16, 16, 16);
599                         dp.notifytype          = GENNOTIFY_DUNGEON;
600                 }
601
602                 DungeonGen dgen(ndef, &gennotify, &dp);
603                 dgen.generate(vm, blockseed, full_node_min, full_node_max);
604         }
605
606         // Add top and bottom side of water to transforming_liquid queue
607         updateLiquid(&data->transforming_liquid, full_node_min, full_node_max);
608
609         // Add surface nodes
610         growGrass();
611
612         // Generate some trees, and add grass, if a jungle
613         if (spflags & MGV6_TREES)
614                 placeTreesAndJungleGrass();
615
616         // Generate the registered decorations
617         if (flags & MG_DECORATIONS)
618                 m_emerge->decomgr->placeAllDecos(this, blockseed, node_min, node_max);
619
620         // Generate the registered ores
621         m_emerge->oremgr->placeAllOres(this, blockseed, node_min, node_max);
622
623         // Calculate lighting
624         if (flags & MG_LIGHT)
625                 calcLighting(node_min - v3s16(1, 1, 1) * MAP_BLOCKSIZE,
626                         node_max + v3s16(1, 0, 1) * MAP_BLOCKSIZE,
627                         full_node_min, full_node_max);
628
629         this->generating = false;
630 }
631
632
633 void MapgenV6::calculateNoise()
634 {
635         int x = node_min.X;
636         int z = node_min.Z;
637         int fx = full_node_min.X;
638         int fz = full_node_min.Z;
639
640         if (!(spflags & MGV6_FLAT)) {
641                 noise_terrain_base->perlinMap2D_PO(x, 0.5, z, 0.5);
642                 noise_terrain_higher->perlinMap2D_PO(x, 0.5, z, 0.5);
643                 noise_steepness->perlinMap2D_PO(x, 0.5, z, 0.5);
644                 noise_height_select->perlinMap2D_PO(x, 0.5, z, 0.5);
645                 noise_mud->perlinMap2D_PO(x, 0.5, z, 0.5);
646         }
647
648         noise_beach->perlinMap2D_PO(x, 0.2, z, 0.7);
649
650         noise_biome->perlinMap2D_PO(fx, 0.6, fz, 0.2);
651         noise_humidity->perlinMap2D_PO(fx, 0.0, fz, 0.0);
652         // Humidity map does not need range limiting 0 to 1,
653         // only humidity at point does
654 }
655
656
657 int MapgenV6::generateGround()
658 {
659         //TimeTaker timer1("Generating ground level");
660         MapNode n_air(CONTENT_AIR), n_water_source(c_water_source);
661         MapNode n_stone(c_stone), n_desert_stone(c_desert_stone);
662         MapNode n_ice(c_ice);
663         int stone_surface_max_y = -MAX_MAP_GENERATION_LIMIT;
664
665         u32 index = 0;
666         for (s16 z = node_min.Z; z <= node_max.Z; z++)
667         for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
668                 // Surface height
669                 s16 surface_y = (s16)baseTerrainLevelFromMap(index);
670
671                 // Log it
672                 if (surface_y > stone_surface_max_y)
673                         stone_surface_max_y = surface_y;
674
675                 BiomeV6Type bt = getBiome(v2s16(x, z));
676
677                 // Fill ground with stone
678                 const v3s16 &em = vm->m_area.getExtent();
679                 u32 i = vm->m_area.index(x, node_min.Y, z);
680                 for (s16 y = node_min.Y; y <= node_max.Y; y++) {
681                         if (vm->m_data[i].getContent() == CONTENT_IGNORE) {
682                                 if (y <= surface_y) {
683                                         vm->m_data[i] = (y >= MGV6_DESERT_STONE_BASE
684                                                         && bt == BT_DESERT) ?
685                                                 n_desert_stone : n_stone;
686                                 } else if (y <= water_level) {
687                                         vm->m_data[i] = (y >= MGV6_ICE_BASE
688                                                         && bt == BT_TUNDRA) ?
689                                                 n_ice : n_water_source;
690                                 } else {
691                                         vm->m_data[i] = n_air;
692                                 }
693                         }
694                         vm->m_area.add_y(em, i, 1);
695                 }
696         }
697
698         return stone_surface_max_y;
699 }
700
701
702 void MapgenV6::addMud()
703 {
704         // 15ms @cs=8
705         //TimeTaker timer1("add mud");
706         MapNode n_dirt(c_dirt), n_gravel(c_gravel);
707         MapNode n_sand(c_sand), n_desert_sand(c_desert_sand);
708         MapNode addnode;
709
710         u32 index = 0;
711         for (s16 z = node_min.Z; z <= node_max.Z; z++)
712         for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
713                 // Randomize mud amount
714                 s16 mud_add_amount = getMudAmount(index) / 2.0 + 0.5;
715
716                 // Find ground level
717                 s16 surface_y = find_stone_level(v2s16(x, z)); /////////////////optimize this!
718
719                 // Handle area not found
720                 if (surface_y == vm->m_area.MinEdge.Y - 1)
721                         continue;
722
723                 BiomeV6Type bt = getBiome(v2s16(x, z));
724                 addnode = (bt == BT_DESERT) ? n_desert_sand : n_dirt;
725
726                 if (bt == BT_DESERT && surface_y + mud_add_amount <= water_level + 1) {
727                         addnode = n_sand;
728                 } else if (mud_add_amount <= 0) {
729                         mud_add_amount = 1 - mud_add_amount;
730                         addnode = n_gravel;
731                 } else if (bt != BT_DESERT && getHaveBeach(index) &&
732                                 surface_y + mud_add_amount <= water_level + 2) {
733                         addnode = n_sand;
734                 }
735
736                 if ((bt == BT_DESERT || bt == BT_TUNDRA) && surface_y > 20)
737                         mud_add_amount = MYMAX(0, mud_add_amount - (surface_y - 20) / 5);
738
739                 /* If topmost node is grass, change it to mud.  It might be if it was
740                 // flown to there from a neighboring chunk and then converted.
741                 u32 i = vm->m_area.index(x, surface_y, z);
742                 if (vm->m_data[i].getContent() == c_dirt_with_grass)
743                         vm->m_data[i] = n_dirt;*/
744
745                 // Add mud on ground
746                 s16 mudcount = 0;
747                 const v3s16 &em = vm->m_area.getExtent();
748                 s16 y_start = surface_y + 1;
749                 u32 i = vm->m_area.index(x, y_start, z);
750                 for (s16 y = y_start; y <= node_max.Y; y++) {
751                         if (mudcount >= mud_add_amount)
752                                 break;
753
754                         vm->m_data[i] = addnode;
755                         mudcount++;
756
757                         vm->m_area.add_y(em, i, 1);
758                 }
759         }
760 }
761
762
763 void MapgenV6::flowMud(s16 &mudflow_minpos, s16 &mudflow_maxpos)
764 {
765         // 340ms @cs=8
766         //TimeTaker timer1("flow mud");
767
768         // Iterate a few times
769         for (s16 k = 0; k < 3; k++) {
770                 for (s16 z = mudflow_minpos; z <= mudflow_maxpos; z++)
771                 for (s16 x = mudflow_minpos; x <= mudflow_maxpos; x++) {
772                         // Invert coordinates every 2nd iteration
773                         if (k % 2 == 0) {
774                                 x = mudflow_maxpos - (x - mudflow_minpos);
775                                 z = mudflow_maxpos - (z - mudflow_minpos);
776                         }
777
778                         // Node position in 2d
779                         v2s16 p2d = v2s16(node_min.X, node_min.Z) + v2s16(x, z);
780
781                         const v3s16 &em = vm->m_area.getExtent();
782                         u32 i = vm->m_area.index(p2d.X, node_max.Y, p2d.Y);
783                         s16 y = node_max.Y;
784
785                         while (y >= node_min.Y) {
786
787                         for (;; y--) {
788                                 MapNode *n = NULL;
789                                 // Find mud
790                                 for (; y >= node_min.Y; y--) {
791                                         n = &vm->m_data[i];
792                                         if (n->getContent() == c_dirt ||
793                                                         n->getContent() == c_dirt_with_grass ||
794                                                         n->getContent() == c_gravel)
795                                                 break;
796
797                                         vm->m_area.add_y(em, i, -1);
798                                 }
799
800                                 // Stop if out of area
801                                 //if(vmanip.m_area.contains(i) == false)
802                                 if (y < node_min.Y)
803                                         break;
804
805                                 if (n->getContent() == c_dirt ||
806                                                 n->getContent() == c_dirt_with_grass) {
807                                         // Make it exactly mud
808                                         n->setContent(c_dirt);
809
810                                         // Don't flow it if the stuff under it is not mud
811                                         {
812                                                 u32 i2 = i;
813                                                 vm->m_area.add_y(em, i2, -1);
814                                                 // Cancel if out of area
815                                                 if (!vm->m_area.contains(i2))
816                                                         continue;
817                                                 MapNode *n2 = &vm->m_data[i2];
818                                                 if (n2->getContent() != c_dirt &&
819                                                                 n2->getContent() != c_dirt_with_grass)
820                                                         continue;
821                                         }
822                                 }
823
824                                 v3s16 dirs4[4] = {
825                                         v3s16(0, 0, 1), // back
826                                         v3s16(1, 0, 0), // right
827                                         v3s16(0, 0, -1), // front
828                                         v3s16(-1, 0, 0), // left
829                                 };
830
831                                 // Check that upper is walkable. Cancel
832                                 // dropping if upper keeps it in place.
833                                 u32 i3 = i;
834                                 vm->m_area.add_y(em, i3, 1);
835                                 MapNode *n3 = NULL;
836
837                                 if (vm->m_area.contains(i3)) {
838                                         n3 = &vm->m_data[i3];
839                                         if (ndef->get(*n3).walkable)
840                                                 continue;
841                                 }
842
843                                 // Drop mud on side
844                                 for (const v3s16 &dirp : dirs4) {
845                                         u32 i2 = i;
846                                         // Move to side
847                                         vm->m_area.add_p(em, i2, dirp);
848                                         // Fail if out of area
849                                         if (!vm->m_area.contains(i2))
850                                                 continue;
851                                         // Check that side is air
852                                         MapNode *n2 = &vm->m_data[i2];
853                                         if (ndef->get(*n2).walkable)
854                                                 continue;
855                                         // Check that under side is air
856                                         vm->m_area.add_y(em, i2, -1);
857                                         if (!vm->m_area.contains(i2))
858                                                 continue;
859                                         n2 = &vm->m_data[i2];
860                                         if (ndef->get(*n2).walkable)
861                                                 continue;
862                                         // Loop further down until not air
863                                         bool dropped_to_unknown = false;
864                                         do {
865                                                 vm->m_area.add_y(em, i2, -1);
866                                                 n2 = &vm->m_data[i2];
867                                                 // if out of known area
868                                                 if (!vm->m_area.contains(i2) ||
869                                                                 n2->getContent() == CONTENT_IGNORE) {
870                                                         dropped_to_unknown = true;
871                                                         break;
872                                                 }
873                                         } while (!ndef->get(*n2).walkable);
874                                         // Loop one up so that we're in air
875                                         vm->m_area.add_y(em, i2, 1);
876
877                                         // Move mud to new place. Outside mapchunk remove
878                                         // any decorations above removed or placed mud.
879                                         if (!dropped_to_unknown)
880                                                 moveMud(i, i2, i3, p2d, em);
881
882                                         // Done
883                                         break;
884                                 }
885                         }
886                         }
887                 }
888         }
889 }
890
891
892 void MapgenV6::moveMud(u32 remove_index, u32 place_index,
893         u32 above_remove_index, v2s16 pos, v3s16 em)
894 {
895         MapNode n_air(CONTENT_AIR);
896         // Copy mud from old place to new place
897         vm->m_data[place_index] = vm->m_data[remove_index];
898         // Set old place to be air
899         vm->m_data[remove_index] = n_air;
900         // Outside the mapchunk decorations may need to be removed if above removed
901         // mud or if half-buried in placed mud. Placed mud is to the side of pos so
902         // use 'pos.X >= node_max.X' etc.
903         if (pos.X >= node_max.X || pos.X <= node_min.X ||
904                         pos.Y >= node_max.Z || pos.Y <= node_min.Z) {
905                 // 'above remove' node is above removed mud. If it is not air, water or
906                 // 'ignore' it is a decoration that needs removing. Also search upwards
907                 // to remove a possible stacked decoration.
908                 // Check for 'ignore' because stacked decorations can penetrate into
909                 // 'ignore' nodes above the mapchunk.
910                 while (vm->m_area.contains(above_remove_index) &&
911                                 vm->m_data[above_remove_index].getContent() != CONTENT_AIR &&
912                                 vm->m_data[above_remove_index].getContent() != c_water_source &&
913                                 vm->m_data[above_remove_index].getContent() != CONTENT_IGNORE) {
914                         vm->m_data[above_remove_index] = n_air;
915                         vm->m_area.add_y(em, above_remove_index, 1);
916                 }
917                 // Mud placed may have partially-buried a stacked decoration, search
918                 // above and remove.
919                 vm->m_area.add_y(em, place_index, 1);
920                 while (vm->m_area.contains(place_index) &&
921                                 vm->m_data[place_index].getContent() != CONTENT_AIR &&
922                                 vm->m_data[place_index].getContent() != c_water_source &&
923                                 vm->m_data[place_index].getContent() != CONTENT_IGNORE) {
924                         vm->m_data[place_index] = n_air;
925                         vm->m_area.add_y(em, place_index, 1);
926                 }
927         }
928 }
929
930
931 void MapgenV6::placeTreesAndJungleGrass()
932 {
933         //TimeTaker t("placeTrees");
934         if (node_max.Y < water_level)
935                 return;
936
937         PseudoRandom grassrandom(blockseed + 53);
938         content_t c_junglegrass = ndef->getId("mapgen_junglegrass");
939         // if we don't have junglegrass, don't place cignore... that's bad
940         if (c_junglegrass == CONTENT_IGNORE)
941                 c_junglegrass = CONTENT_AIR;
942         MapNode n_junglegrass(c_junglegrass);
943         const v3s16 &em = vm->m_area.getExtent();
944
945         // Divide area into parts
946         s16 div = 8;
947         s16 sidelen = central_area_size.X / div;
948         double area = sidelen * sidelen;
949
950         // N.B.  We must add jungle grass first, since tree leaves will
951         // obstruct the ground, giving us a false ground level
952         for (s16 z0 = 0; z0 < div; z0++)
953         for (s16 x0 = 0; x0 < div; x0++) {
954                 // Center position of part of division
955                 v2s16 p2d_center(
956                         node_min.X + sidelen / 2 + sidelen * x0,
957                         node_min.Z + sidelen / 2 + sidelen * z0
958                 );
959                 // Minimum edge of part of division
960                 v2s16 p2d_min(
961                         node_min.X + sidelen * x0,
962                         node_min.Z + sidelen * z0
963                 );
964                 // Maximum edge of part of division
965                 v2s16 p2d_max(
966                         node_min.X + sidelen + sidelen * x0 - 1,
967                         node_min.Z + sidelen + sidelen * z0 - 1
968                 );
969
970                 // Get biome at center position of part of division
971                 BiomeV6Type bt = getBiome(p2d_center);
972
973                 // Amount of trees
974                 u32 tree_count;
975                 if (bt == BT_JUNGLE || bt == BT_TAIGA || bt == BT_NORMAL) {
976                         tree_count = area * getTreeAmount(p2d_center);
977                         if (bt == BT_JUNGLE)
978                                 tree_count *= 4;
979                 } else {
980                         tree_count = 0;
981                 }
982
983                 // Add jungle grass
984                 if (bt == BT_JUNGLE) {
985                         float humidity = getHumidity(p2d_center);
986                         u32 grass_count = 5 * humidity * tree_count;
987                         for (u32 i = 0; i < grass_count; i++) {
988                                 s16 x = grassrandom.range(p2d_min.X, p2d_max.X);
989                                 s16 z = grassrandom.range(p2d_min.Y, p2d_max.Y);
990                                 int mapindex = central_area_size.X * (z - node_min.Z)
991                                                                 + (x - node_min.X);
992                                 s16 y = heightmap[mapindex];
993                                 if (y < water_level)
994                                         continue;
995
996                                 u32 vi = vm->m_area.index(x, y, z);
997                                 // place on dirt_with_grass, since we know it is exposed to sunlight
998                                 if (vm->m_data[vi].getContent() == c_dirt_with_grass) {
999                                         vm->m_area.add_y(em, vi, 1);
1000                                         vm->m_data[vi] = n_junglegrass;
1001                                 }
1002                         }
1003                 }
1004
1005                 // Put trees in random places on part of division
1006                 for (u32 i = 0; i < tree_count; i++) {
1007                         s16 x = myrand_range(p2d_min.X, p2d_max.X);
1008                         s16 z = myrand_range(p2d_min.Y, p2d_max.Y);
1009                         int mapindex = central_area_size.X * (z - node_min.Z)
1010                                                         + (x - node_min.X);
1011                         s16 y = heightmap[mapindex];
1012                         // Don't make a tree under water level
1013                         // Don't make a tree so high that it doesn't fit
1014                         if (y < water_level || y > node_max.Y - 6)
1015                                 continue;
1016
1017                         v3s16 p(x, y, z);
1018                         // Trees grow only on mud and grass
1019                         {
1020                                 u32 i = vm->m_area.index(p);
1021                                 content_t c = vm->m_data[i].getContent();
1022                                 if (c != c_dirt &&
1023                                                 c != c_dirt_with_grass &&
1024                                                 c != c_dirt_with_snow)
1025                                         continue;
1026                         }
1027                         p.Y++;
1028
1029                         // Make a tree
1030                         if (bt == BT_JUNGLE) {
1031                                 treegen::make_jungletree(*vm, p, ndef, myrand());
1032                         } else if (bt == BT_TAIGA) {
1033                                 treegen::make_pine_tree(*vm, p - v3s16(0, 1, 0), ndef, myrand());
1034                         } else if (bt == BT_NORMAL) {
1035                                 bool is_apple_tree = (myrand_range(0, 3) == 0) &&
1036                                                         getHaveAppleTree(v2s16(x, z));
1037                                 treegen::make_tree(*vm, p, is_apple_tree, ndef, myrand());
1038                         }
1039                 }
1040         }
1041         //printf("placeTreesAndJungleGrass: %dms\n", t.stop());
1042 }
1043
1044
1045 void MapgenV6::growGrass() // Add surface nodes
1046 {
1047         MapNode n_dirt_with_grass(c_dirt_with_grass);
1048         MapNode n_dirt_with_snow(c_dirt_with_snow);
1049         MapNode n_snowblock(c_snowblock);
1050         MapNode n_snow(c_snow);
1051         const v3s16 &em = vm->m_area.getExtent();
1052
1053         u32 index = 0;
1054         for (s16 z = full_node_min.Z; z <= full_node_max.Z; z++)
1055         for (s16 x = full_node_min.X; x <= full_node_max.X; x++, index++) {
1056                 // Find the lowest surface to which enough light ends up to make
1057                 // grass grow.  Basically just wait until not air and not leaves.
1058                 s16 surface_y = 0;
1059                 {
1060                         u32 i = vm->m_area.index(x, node_max.Y, z);
1061                         s16 y;
1062                         // Go to ground level
1063                         for (y = node_max.Y; y >= full_node_min.Y; y--) {
1064                                 MapNode &n = vm->m_data[i];
1065                                 if (ndef->get(n).param_type != CPT_LIGHT ||
1066                                                 ndef->get(n).liquid_type != LIQUID_NONE ||
1067                                                 n.getContent() == c_ice)
1068                                         break;
1069                                 vm->m_area.add_y(em, i, -1);
1070                         }
1071                         surface_y = (y >= full_node_min.Y) ? y : full_node_min.Y;
1072                 }
1073
1074                 BiomeV6Type bt = getBiome(index, v2s16(x, z));
1075                 u32 i = vm->m_area.index(x, surface_y, z);
1076                 content_t c = vm->m_data[i].getContent();
1077                 if (surface_y >= water_level - 20) {
1078                         if (bt == BT_TAIGA && c == c_dirt) {
1079                                 vm->m_data[i] = n_dirt_with_snow;
1080                         } else if (bt == BT_TUNDRA) {
1081                                 if (c == c_dirt) {
1082                                         vm->m_data[i] = n_snowblock;
1083                                         vm->m_area.add_y(em, i, -1);
1084                                         vm->m_data[i] = n_dirt_with_snow;
1085                                 } else if (c == c_stone && surface_y < node_max.Y) {
1086                                         vm->m_area.add_y(em, i, 1);
1087                                         vm->m_data[i] = n_snowblock;
1088                                 }
1089                         } else if (c == c_dirt) {
1090                                 vm->m_data[i] = n_dirt_with_grass;
1091                         }
1092                 }
1093         }
1094 }
1095
1096
1097 void MapgenV6::generateCaves(int max_stone_y)
1098 {
1099         float cave_amount = NoisePerlin2D(np_cave, node_min.X, node_min.Y, seed);
1100         int volume_nodes = (node_max.X - node_min.X + 1) *
1101                                            (node_max.Y - node_min.Y + 1) * MAP_BLOCKSIZE;
1102         cave_amount = MYMAX(0.0, cave_amount);
1103         u32 caves_count = cave_amount * volume_nodes / 50000;
1104         u32 bruises_count = 1;
1105         PseudoRandom ps(blockseed + 21343);
1106         PseudoRandom ps2(blockseed + 1032);
1107
1108         if (ps.range(1, 6) == 1)
1109                 bruises_count = ps.range(0, ps.range(0, 2));
1110
1111         if (getBiome(v2s16(node_min.X, node_min.Z)) == BT_DESERT) {
1112                 caves_count   /= 3;
1113                 bruises_count /= 3;
1114         }
1115
1116         for (u32 i = 0; i < caves_count + bruises_count; i++) {
1117                 CavesV6 cave(ndef, &gennotify, water_level, c_water_source, c_lava_source);
1118
1119                 bool large_cave = (i >= caves_count);
1120                 cave.makeCave(vm, node_min, node_max, &ps, &ps2,
1121                         large_cave, max_stone_y, heightmap);
1122         }
1123 }