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