Biomemap: Simplify code of recent commit (#7398)
[oweals/minetest.git] / src / mapgen / mapgen.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) 2015-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 #include "mapgen.h"
23 #include "voxel.h"
24 #include "noise.h"
25 #include "gamedef.h"
26 #include "mg_biome.h"
27 #include "mapblock.h"
28 #include "mapnode.h"
29 #include "map.h"
30 #include "content_sao.h"
31 #include "nodedef.h"
32 #include "emerge.h"
33 #include "voxelalgorithms.h"
34 #include "porting.h"
35 #include "profiler.h"
36 #include "settings.h"
37 #include "treegen.h"
38 #include "serialization.h"
39 #include "util/serialize.h"
40 #include "util/numeric.h"
41 #include "filesys.h"
42 #include "log.h"
43 #include "mapgen_carpathian.h"
44 #include "mapgen_flat.h"
45 #include "mapgen_fractal.h"
46 #include "mapgen_v5.h"
47 #include "mapgen_v6.h"
48 #include "mapgen_v7.h"
49 #include "mapgen_valleys.h"
50 #include "mapgen_singlenode.h"
51 #include "cavegen.h"
52 #include "dungeongen.h"
53
54 FlagDesc flagdesc_mapgen[] = {
55         {"caves",       MG_CAVES},
56         {"dungeons",    MG_DUNGEONS},
57         {"light",       MG_LIGHT},
58         {"decorations", MG_DECORATIONS},
59         {NULL,       0}
60 };
61
62 FlagDesc flagdesc_gennotify[] = {
63         {"dungeon",          1 << GENNOTIFY_DUNGEON},
64         {"temple",           1 << GENNOTIFY_TEMPLE},
65         {"cave_begin",       1 << GENNOTIFY_CAVE_BEGIN},
66         {"cave_end",         1 << GENNOTIFY_CAVE_END},
67         {"large_cave_begin", 1 << GENNOTIFY_LARGECAVE_BEGIN},
68         {"large_cave_end",   1 << GENNOTIFY_LARGECAVE_END},
69         {"decoration",       1 << GENNOTIFY_DECORATION},
70         {NULL,               0}
71 };
72
73 struct MapgenDesc {
74         const char *name;
75         bool is_user_visible;
76 };
77
78 ////
79 //// Built-in mapgens
80 ////
81
82 static MapgenDesc g_reg_mapgens[] = {
83         {"v5",         true},
84         {"v6",         true},
85         {"v7",         true},
86         {"flat",       true},
87         {"fractal",    true},
88         {"valleys",    true},
89         {"singlenode", true},
90         {"carpathian", true},
91 };
92
93 STATIC_ASSERT(
94         ARRLEN(g_reg_mapgens) == MAPGEN_INVALID,
95         registered_mapgens_is_wrong_size);
96
97 ////
98 //// Mapgen
99 ////
100
101 Mapgen::Mapgen(int mapgenid, MapgenParams *params, EmergeManager *emerge) :
102         gennotify(emerge->gen_notify_on, &emerge->gen_notify_on_deco_ids)
103 {
104         id           = mapgenid;
105         water_level  = params->water_level;
106         mapgen_limit = params->mapgen_limit;
107         flags        = params->flags;
108         csize        = v3s16(1, 1, 1) * (params->chunksize * MAP_BLOCKSIZE);
109
110         /*
111                 We are losing half our entropy by doing this, but it is necessary to
112                 preserve reverse compatibility.  If the top half of our current 64 bit
113                 seeds ever starts getting used, existing worlds will break due to a
114                 different hash outcome and no way to differentiate between versions.
115
116                 A solution could be to add a new bit to designate that the top half of
117                 the seed value should be used, essentially a 1-bit version code, but
118                 this would require increasing the total size of a seed to 9 bytes (yuck)
119
120                 It's probably okay if this never gets fixed.  4.2 billion possibilities
121                 ought to be enough for anyone.
122         */
123         seed = (s32)params->seed;
124
125         ndef      = emerge->ndef;
126 }
127
128
129 MapgenType Mapgen::getMapgenType(const std::string &mgname)
130 {
131         for (size_t i = 0; i != ARRLEN(g_reg_mapgens); i++) {
132                 if (mgname == g_reg_mapgens[i].name)
133                         return (MapgenType)i;
134         }
135
136         return MAPGEN_INVALID;
137 }
138
139
140 const char *Mapgen::getMapgenName(MapgenType mgtype)
141 {
142         size_t index = (size_t)mgtype;
143         if (index == MAPGEN_INVALID || index >= ARRLEN(g_reg_mapgens))
144                 return "invalid";
145
146         return g_reg_mapgens[index].name;
147 }
148
149
150 Mapgen *Mapgen::createMapgen(MapgenType mgtype, int mgid,
151         MapgenParams *params, EmergeManager *emerge)
152 {
153         switch (mgtype) {
154         case MAPGEN_CARPATHIAN:
155                 return new MapgenCarpathian(mgid, (MapgenCarpathianParams *)params, emerge);
156         case MAPGEN_FLAT:
157                 return new MapgenFlat(mgid, (MapgenFlatParams *)params, emerge);
158         case MAPGEN_FRACTAL:
159                 return new MapgenFractal(mgid, (MapgenFractalParams *)params, emerge);
160         case MAPGEN_SINGLENODE:
161                 return new MapgenSinglenode(mgid, (MapgenSinglenodeParams *)params, emerge);
162         case MAPGEN_V5:
163                 return new MapgenV5(mgid, (MapgenV5Params *)params, emerge);
164         case MAPGEN_V6:
165                 return new MapgenV6(mgid, (MapgenV6Params *)params, emerge);
166         case MAPGEN_V7:
167                 return new MapgenV7(mgid, (MapgenV7Params *)params, emerge);
168         case MAPGEN_VALLEYS:
169                 return new MapgenValleys(mgid, (MapgenValleysParams *)params, emerge);
170         default:
171                 return NULL;
172         }
173 }
174
175
176 MapgenParams *Mapgen::createMapgenParams(MapgenType mgtype)
177 {
178         switch (mgtype) {
179         case MAPGEN_CARPATHIAN:
180                 return new MapgenCarpathianParams;
181         case MAPGEN_FLAT:
182                 return new MapgenFlatParams;
183         case MAPGEN_FRACTAL:
184                 return new MapgenFractalParams;
185         case MAPGEN_SINGLENODE:
186                 return new MapgenSinglenodeParams;
187         case MAPGEN_V5:
188                 return new MapgenV5Params;
189         case MAPGEN_V6:
190                 return new MapgenV6Params;
191         case MAPGEN_V7:
192                 return new MapgenV7Params;
193         case MAPGEN_VALLEYS:
194                 return new MapgenValleysParams;
195         default:
196                 return NULL;
197         }
198 }
199
200
201 void Mapgen::getMapgenNames(std::vector<const char *> *mgnames, bool include_hidden)
202 {
203         for (u32 i = 0; i != ARRLEN(g_reg_mapgens); i++) {
204                 if (include_hidden || g_reg_mapgens[i].is_user_visible)
205                         mgnames->push_back(g_reg_mapgens[i].name);
206         }
207 }
208
209
210 u32 Mapgen::getBlockSeed(v3s16 p, s32 seed)
211 {
212         return (u32)seed   +
213                 p.Z * 38134234 +
214                 p.Y * 42123    +
215                 p.X * 23;
216 }
217
218
219 u32 Mapgen::getBlockSeed2(v3s16 p, s32 seed)
220 {
221         u32 n = 1619 * p.X + 31337 * p.Y + 52591 * p.Z + 1013 * seed;
222         n = (n >> 13) ^ n;
223         return (n * (n * n * 60493 + 19990303) + 1376312589);
224 }
225
226
227 // Returns Y one under area minimum if not found
228 s16 Mapgen::findGroundLevelFull(v2s16 p2d)
229 {
230         const v3s16 &em = vm->m_area.getExtent();
231         s16 y_nodes_max = vm->m_area.MaxEdge.Y;
232         s16 y_nodes_min = vm->m_area.MinEdge.Y;
233         u32 i = vm->m_area.index(p2d.X, y_nodes_max, p2d.Y);
234         s16 y;
235
236         for (y = y_nodes_max; y >= y_nodes_min; y--) {
237                 MapNode &n = vm->m_data[i];
238                 if (ndef->get(n).walkable)
239                         break;
240
241                 VoxelArea::add_y(em, i, -1);
242         }
243         return (y >= y_nodes_min) ? y : y_nodes_min - 1;
244 }
245
246
247 // Returns -MAX_MAP_GENERATION_LIMIT if not found
248 s16 Mapgen::findGroundLevel(v2s16 p2d, s16 ymin, s16 ymax)
249 {
250         const v3s16 &em = vm->m_area.getExtent();
251         u32 i = vm->m_area.index(p2d.X, ymax, p2d.Y);
252         s16 y;
253
254         for (y = ymax; y >= ymin; y--) {
255                 MapNode &n = vm->m_data[i];
256                 if (ndef->get(n).walkable)
257                         break;
258
259                 VoxelArea::add_y(em, i, -1);
260         }
261         return (y >= ymin) ? y : -MAX_MAP_GENERATION_LIMIT;
262 }
263
264
265 // Returns -MAX_MAP_GENERATION_LIMIT if not found or if ground is found first
266 s16 Mapgen::findLiquidSurface(v2s16 p2d, s16 ymin, s16 ymax)
267 {
268         const v3s16 &em = vm->m_area.getExtent();
269         u32 i = vm->m_area.index(p2d.X, ymax, p2d.Y);
270         s16 y;
271
272         for (y = ymax; y >= ymin; y--) {
273                 MapNode &n = vm->m_data[i];
274                 if (ndef->get(n).walkable)
275                         return -MAX_MAP_GENERATION_LIMIT;
276
277                 if (ndef->get(n).isLiquid())
278                         break;
279
280                 VoxelArea::add_y(em, i, -1);
281         }
282         return (y >= ymin) ? y : -MAX_MAP_GENERATION_LIMIT;
283 }
284
285
286 void Mapgen::updateHeightmap(v3s16 nmin, v3s16 nmax)
287 {
288         if (!heightmap)
289                 return;
290
291         //TimeTaker t("Mapgen::updateHeightmap", NULL, PRECISION_MICRO);
292         int index = 0;
293         for (s16 z = nmin.Z; z <= nmax.Z; z++) {
294                 for (s16 x = nmin.X; x <= nmax.X; x++, index++) {
295                         s16 y = findGroundLevel(v2s16(x, z), nmin.Y, nmax.Y);
296
297                         heightmap[index] = y;
298                 }
299         }
300 }
301
302
303 void Mapgen::getSurfaces(v2s16 p2d, s16 ymin, s16 ymax,
304         std::vector<s16> &floors, std::vector<s16> &ceilings)
305 {
306         const v3s16 &em = vm->m_area.getExtent();
307
308         bool is_walkable = false;
309         u32 vi = vm->m_area.index(p2d.X, ymax, p2d.Y);
310         MapNode mn_max = vm->m_data[vi];
311         bool walkable_above = ndef->get(mn_max).walkable;
312         VoxelArea::add_y(em, vi, -1);
313
314         for (s16 y = ymax - 1; y >= ymin; y--) {
315                 MapNode mn = vm->m_data[vi];
316                 is_walkable = ndef->get(mn).walkable;
317
318                 if (is_walkable && !walkable_above) {
319                         floors.push_back(y);
320                 } else if (!is_walkable && walkable_above) {
321                         ceilings.push_back(y + 1);
322                 }
323
324                 VoxelArea::add_y(em, vi, -1);
325                 walkable_above = is_walkable;
326         }
327 }
328
329
330 inline bool Mapgen::isLiquidHorizontallyFlowable(u32 vi, v3s16 em)
331 {
332         u32 vi_neg_x = vi;
333         VoxelArea::add_x(em, vi_neg_x, -1);
334         if (vm->m_data[vi_neg_x].getContent() != CONTENT_IGNORE) {
335                 const ContentFeatures &c_nx = ndef->get(vm->m_data[vi_neg_x]);
336                 if (c_nx.floodable && !c_nx.isLiquid())
337                         return true;
338         }
339         u32 vi_pos_x = vi;
340         VoxelArea::add_x(em, vi_pos_x, +1);
341         if (vm->m_data[vi_pos_x].getContent() != CONTENT_IGNORE) {
342                 const ContentFeatures &c_px = ndef->get(vm->m_data[vi_pos_x]);
343                 if (c_px.floodable && !c_px.isLiquid())
344                         return true;
345         }
346         u32 vi_neg_z = vi;
347         VoxelArea::add_z(em, vi_neg_z, -1);
348         if (vm->m_data[vi_neg_z].getContent() != CONTENT_IGNORE) {
349                 const ContentFeatures &c_nz = ndef->get(vm->m_data[vi_neg_z]);
350                 if (c_nz.floodable && !c_nz.isLiquid())
351                         return true;
352         }
353         u32 vi_pos_z = vi;
354         VoxelArea::add_z(em, vi_pos_z, +1);
355         if (vm->m_data[vi_pos_z].getContent() != CONTENT_IGNORE) {
356                 const ContentFeatures &c_pz = ndef->get(vm->m_data[vi_pos_z]);
357                 if (c_pz.floodable && !c_pz.isLiquid())
358                         return true;
359         }
360         return false;
361 }
362
363 void Mapgen::updateLiquid(UniqueQueue<v3s16> *trans_liquid, v3s16 nmin, v3s16 nmax)
364 {
365         bool isignored, isliquid, wasignored, wasliquid, waschecked, waspushed;
366         const v3s16 &em  = vm->m_area.getExtent();
367
368         for (s16 z = nmin.Z + 1; z <= nmax.Z - 1; z++)
369         for (s16 x = nmin.X + 1; x <= nmax.X - 1; x++) {
370                 wasignored = true;
371                 wasliquid = false;
372                 waschecked = false;
373                 waspushed = false;
374
375                 u32 vi = vm->m_area.index(x, nmax.Y, z);
376                 for (s16 y = nmax.Y; y >= nmin.Y; y--) {
377                         isignored = vm->m_data[vi].getContent() == CONTENT_IGNORE;
378                         isliquid = ndef->get(vm->m_data[vi]).isLiquid();
379
380                         if (isignored || wasignored || isliquid == wasliquid) {
381                                 // Neither topmost node of liquid column nor topmost node below column
382                                 waschecked = false;
383                                 waspushed = false;
384                         } else if (isliquid) {
385                                 // This is the topmost node in the column
386                                 bool ispushed = false;
387                                 if (isLiquidHorizontallyFlowable(vi, em)) {
388                                         trans_liquid->push_back(v3s16(x, y, z));
389                                         ispushed = true;
390                                 }
391                                 // Remember waschecked and waspushed to avoid repeated
392                                 // checks/pushes in case the column consists of only this node
393                                 waschecked = true;
394                                 waspushed = ispushed;
395                         } else {
396                                 // This is the topmost node below a liquid column
397                                 u32 vi_above = vi;
398                                 VoxelArea::add_y(em, vi_above, 1);
399                                 if (!waspushed && (ndef->get(vm->m_data[vi]).floodable ||
400                                                 (!waschecked && isLiquidHorizontallyFlowable(vi_above, em)))) {
401                                         // Push back the lowest node in the column which is one
402                                         // node above this one
403                                         trans_liquid->push_back(v3s16(x, y + 1, z));
404                                 }
405                         }
406
407                         wasliquid = isliquid;
408                         wasignored = isignored;
409                         VoxelArea::add_y(em, vi, -1);
410                 }
411         }
412 }
413
414
415 void Mapgen::setLighting(u8 light, v3s16 nmin, v3s16 nmax)
416 {
417         ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update", SPT_AVG);
418         VoxelArea a(nmin, nmax);
419
420         for (int z = a.MinEdge.Z; z <= a.MaxEdge.Z; z++) {
421                 for (int y = a.MinEdge.Y; y <= a.MaxEdge.Y; y++) {
422                         u32 i = vm->m_area.index(a.MinEdge.X, y, z);
423                         for (int x = a.MinEdge.X; x <= a.MaxEdge.X; x++, i++)
424                                 vm->m_data[i].param1 = light;
425                 }
426         }
427 }
428
429
430 void Mapgen::lightSpread(VoxelArea &a, v3s16 p, u8 light)
431 {
432         if (light <= 1 || !a.contains(p))
433                 return;
434
435         u32 vi = vm->m_area.index(p);
436         MapNode &n = vm->m_data[vi];
437
438         // Decay light in each of the banks separately
439         u8 light_day = light & 0x0F;
440         if (light_day > 0)
441                 light_day -= 0x01;
442
443         u8 light_night = light & 0xF0;
444         if (light_night > 0)
445                 light_night -= 0x10;
446
447         // Bail out only if we have no more light from either bank to propogate, or
448         // we hit a solid block that light cannot pass through.
449         if ((light_day  <= (n.param1 & 0x0F) &&
450                 light_night <= (n.param1 & 0xF0)) ||
451                 !ndef->get(n).light_propagates)
452                 return;
453
454         // Since this recursive function only terminates when there is no light from
455         // either bank left, we need to take the max of both banks into account for
456         // the case where spreading has stopped for one light bank but not the other.
457         light = MYMAX(light_day, n.param1 & 0x0F) |
458                         MYMAX(light_night, n.param1 & 0xF0);
459
460         n.param1 = light;
461
462         lightSpread(a, p + v3s16(0, 0, 1), light);
463         lightSpread(a, p + v3s16(0, 1, 0), light);
464         lightSpread(a, p + v3s16(1, 0, 0), light);
465         lightSpread(a, p - v3s16(0, 0, 1), light);
466         lightSpread(a, p - v3s16(0, 1, 0), light);
467         lightSpread(a, p - v3s16(1, 0, 0), light);
468 }
469
470
471 void Mapgen::calcLighting(v3s16 nmin, v3s16 nmax, v3s16 full_nmin, v3s16 full_nmax,
472         bool propagate_shadow)
473 {
474         ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update", SPT_AVG);
475         //TimeTaker t("updateLighting");
476
477         propagateSunlight(nmin, nmax, propagate_shadow);
478         spreadLight(full_nmin, full_nmax);
479
480         //printf("updateLighting: %dms\n", t.stop());
481 }
482
483
484 void Mapgen::propagateSunlight(v3s16 nmin, v3s16 nmax, bool propagate_shadow)
485 {
486         //TimeTaker t("propagateSunlight");
487         VoxelArea a(nmin, nmax);
488         bool block_is_underground = (water_level >= nmax.Y);
489         const v3s16 &em = vm->m_area.getExtent();
490
491         // NOTE: Direct access to the low 4 bits of param1 is okay here because,
492         // by definition, sunlight will never be in the night lightbank.
493
494         for (int z = a.MinEdge.Z; z <= a.MaxEdge.Z; z++) {
495                 for (int x = a.MinEdge.X; x <= a.MaxEdge.X; x++) {
496                         // see if we can get a light value from the overtop
497                         u32 i = vm->m_area.index(x, a.MaxEdge.Y + 1, z);
498                         if (vm->m_data[i].getContent() == CONTENT_IGNORE) {
499                                 if (block_is_underground)
500                                         continue;
501                         } else if ((vm->m_data[i].param1 & 0x0F) != LIGHT_SUN &&
502                                         propagate_shadow) {
503                                 continue;
504                         }
505                         VoxelArea::add_y(em, i, -1);
506
507                         for (int y = a.MaxEdge.Y; y >= a.MinEdge.Y; y--) {
508                                 MapNode &n = vm->m_data[i];
509                                 if (!ndef->get(n).sunlight_propagates)
510                                         break;
511                                 n.param1 = LIGHT_SUN;
512                                 VoxelArea::add_y(em, i, -1);
513                         }
514                 }
515         }
516         //printf("propagateSunlight: %dms\n", t.stop());
517 }
518
519
520 void Mapgen::spreadLight(v3s16 nmin, v3s16 nmax)
521 {
522         //TimeTaker t("spreadLight");
523         VoxelArea a(nmin, nmax);
524
525         for (int z = a.MinEdge.Z; z <= a.MaxEdge.Z; z++) {
526                 for (int y = a.MinEdge.Y; y <= a.MaxEdge.Y; y++) {
527                         u32 i = vm->m_area.index(a.MinEdge.X, y, z);
528                         for (int x = a.MinEdge.X; x <= a.MaxEdge.X; x++, i++) {
529                                 MapNode &n = vm->m_data[i];
530                                 if (n.getContent() == CONTENT_IGNORE)
531                                         continue;
532
533                                 const ContentFeatures &cf = ndef->get(n);
534                                 if (!cf.light_propagates)
535                                         continue;
536
537                                 // TODO(hmmmmm): Abstract away direct param1 accesses with a
538                                 // wrapper, but something lighter than MapNode::get/setLight
539
540                                 u8 light_produced = cf.light_source;
541                                 if (light_produced)
542                                         n.param1 = light_produced | (light_produced << 4);
543
544                                 u8 light = n.param1;
545                                 if (light) {
546                                         lightSpread(a, v3s16(x,     y,     z + 1), light);
547                                         lightSpread(a, v3s16(x,     y + 1, z    ), light);
548                                         lightSpread(a, v3s16(x + 1, y,     z    ), light);
549                                         lightSpread(a, v3s16(x,     y,     z - 1), light);
550                                         lightSpread(a, v3s16(x,     y - 1, z    ), light);
551                                         lightSpread(a, v3s16(x - 1, y,     z    ), light);
552                                 }
553                         }
554                 }
555         }
556
557         //printf("spreadLight: %dms\n", t.stop());
558 }
559
560
561 ////
562 //// MapgenBasic
563 ////
564
565 MapgenBasic::MapgenBasic(int mapgenid, MapgenParams *params, EmergeManager *emerge)
566         : Mapgen(mapgenid, params, emerge)
567 {
568         this->m_emerge = emerge;
569         this->m_bmgr   = emerge->biomemgr;
570
571         //// Here, 'stride' refers to the number of elements needed to skip to index
572         //// an adjacent element for that coordinate in noise/height/biome maps
573         //// (*not* vmanip content map!)
574
575         // Note there is no X stride explicitly defined.  Items adjacent in the X
576         // coordinate are assumed to be adjacent in memory as well (i.e. stride of 1).
577
578         // Number of elements to skip to get to the next Y coordinate
579         this->ystride = csize.X;
580
581         // Number of elements to skip to get to the next Z coordinate
582         this->zstride = csize.X * csize.Y;
583
584         // Z-stride value for maps oversized for 1-down overgeneration
585         this->zstride_1d = csize.X * (csize.Y + 1);
586
587         // Z-stride value for maps oversized for 1-up 1-down overgeneration
588         this->zstride_1u1d = csize.X * (csize.Y + 2);
589
590         //// Allocate heightmap
591         this->heightmap = new s16[csize.X * csize.Z];
592
593         //// Initialize biome generator
594         // TODO(hmmmm): should we have a way to disable biomemanager biomes?
595         biomegen = m_bmgr->createBiomeGen(BIOMEGEN_ORIGINAL, params->bparams, csize);
596         biomemap = biomegen->biomemap;
597
598         //// Look up some commonly used content
599         c_stone              = ndef->getId("mapgen_stone");
600         c_desert_stone       = ndef->getId("mapgen_desert_stone");
601         c_sandstone          = ndef->getId("mapgen_sandstone");
602         c_water_source       = ndef->getId("mapgen_water_source");
603         c_river_water_source = ndef->getId("mapgen_river_water_source");
604         c_lava_source        = ndef->getId("mapgen_lava_source");
605
606         // Fall back to more basic content if not defined
607         // river_water_source cannot fallback to water_source because river water
608         // needs to be non-renewable and have a short flow range.
609         if (c_desert_stone == CONTENT_IGNORE)
610                 c_desert_stone = c_stone;
611         if (c_sandstone == CONTENT_IGNORE)
612                 c_sandstone = c_stone;
613
614         //// Content used for dungeon generation
615         c_cobble                = ndef->getId("mapgen_cobble");
616         c_mossycobble           = ndef->getId("mapgen_mossycobble");
617         c_stair_cobble          = ndef->getId("mapgen_stair_cobble");
618         c_stair_desert_stone    = ndef->getId("mapgen_stair_desert_stone");
619         c_sandstonebrick        = ndef->getId("mapgen_sandstonebrick");
620         c_stair_sandstone_block = ndef->getId("mapgen_stair_sandstone_block");
621
622         // Fall back to more basic content if not defined
623         if (c_mossycobble == CONTENT_IGNORE)
624                 c_mossycobble = c_cobble;
625         if (c_stair_cobble == CONTENT_IGNORE)
626                 c_stair_cobble = c_cobble;
627         if (c_stair_desert_stone == CONTENT_IGNORE)
628                 c_stair_desert_stone = c_desert_stone;
629         if (c_sandstonebrick == CONTENT_IGNORE)
630                 c_sandstonebrick = c_sandstone;
631         if (c_stair_sandstone_block == CONTENT_IGNORE)
632                 c_stair_sandstone_block = c_sandstonebrick;
633 }
634
635
636 MapgenBasic::~MapgenBasic()
637 {
638         delete biomegen;
639         delete []heightmap;
640 }
641
642
643 void MapgenBasic::generateBiomes()
644 {
645         // can't generate biomes without a biome generator!
646         assert(biomegen);
647         assert(biomemap);
648
649         const v3s16 &em = vm->m_area.getExtent();
650         u32 index = 0;
651
652         noise_filler_depth->perlinMap2D(node_min.X, node_min.Z);
653
654         for (s16 z = node_min.Z; z <= node_max.Z; z++)
655         for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
656                 Biome *biome = NULL;
657                 u16 depth_top = 0;
658                 u16 base_filler = 0;
659                 u16 depth_water_top = 0;
660                 u16 depth_riverbed = 0;
661                 s16 biome_y_min = -MAX_MAP_GENERATION_LIMIT;
662                 u32 vi = vm->m_area.index(x, node_max.Y, z);
663
664                 // Check node at base of mapchunk above, either a node of a previously
665                 // generated mapchunk or if not, a node of overgenerated base terrain.
666                 content_t c_above = vm->m_data[vi + em.X].getContent();
667                 bool air_above = c_above == CONTENT_AIR;
668                 bool river_water_above = c_above == c_river_water_source;
669                 bool water_above = c_above == c_water_source || river_water_above;
670
671                 biomemap[index] = BIOME_NONE;
672
673                 // If there is air or water above enable top/filler placement, otherwise force
674                 // nplaced to stone level by setting a number exceeding any possible filler depth.
675                 u16 nplaced = (air_above || water_above) ? 0 : U16_MAX;
676
677                 for (s16 y = node_max.Y; y >= node_min.Y; y--) {
678                         content_t c = vm->m_data[vi].getContent();
679                         // Biome is (re)calculated:
680                         // 1. At the surface of stone below air or water.
681                         // 2. At the surface of water below air.
682                         // 3. When stone or water is detected but biome has not yet been calculated.
683                         // 4. When stone or water is detected just below a biome's lower limit.
684                         bool is_stone_surface = (c == c_stone) &&
685                                 (air_above || water_above || !biome || y < biome_y_min); // 1, 3, 4
686
687                         bool is_water_surface =
688                                 (c == c_water_source || c == c_river_water_source) &&
689                                 (air_above || !biome || y < biome_y_min); // 2, 3, 4
690
691                         if (is_stone_surface || is_water_surface) {
692                                 // (Re)calculate biome
693                                 biome = biomegen->getBiomeAtIndex(index, v3s16(x, y, z));
694
695                                 // Add biome to biomemap at first stone surface detected
696                                 if (biomemap[index] == BIOME_NONE && is_stone_surface)
697                                         biomemap[index] = biome->index;
698
699                                 depth_top = biome->depth_top;
700                                 base_filler = MYMAX(depth_top +
701                                         biome->depth_filler +
702                                         noise_filler_depth->result[index], 0.0f);
703                                 depth_water_top = biome->depth_water_top;
704                                 depth_riverbed = biome->depth_riverbed;
705                                 biome_y_min = biome->min_pos.Y;
706                         }
707
708                         if (c == c_stone) {
709                                 content_t c_below = vm->m_data[vi - em.X].getContent();
710
711                                 // If the node below isn't solid, make this node stone, so that
712                                 // any top/filler nodes above are structurally supported.
713                                 // This is done by aborting the cycle of top/filler placement
714                                 // immediately by forcing nplaced to stone level.
715                                 if (c_below == CONTENT_AIR
716                                                 || c_below == c_water_source
717                                                 || c_below == c_river_water_source)
718                                         nplaced = U16_MAX;
719
720                                 if (river_water_above) {
721                                         if (nplaced < depth_riverbed) {
722                                                 vm->m_data[vi] = MapNode(biome->c_riverbed);
723                                                 nplaced++;
724                                         } else {
725                                                 nplaced = U16_MAX;  // Disable top/filler placement
726                                                 river_water_above = false;
727                                         }
728                                 } else if (nplaced < depth_top) {
729                                         vm->m_data[vi] = MapNode(biome->c_top);
730                                         nplaced++;
731                                 } else if (nplaced < base_filler) {
732                                         vm->m_data[vi] = MapNode(biome->c_filler);
733                                         nplaced++;
734                                 } else {
735                                         vm->m_data[vi] = MapNode(biome->c_stone);
736                                         nplaced = U16_MAX;  // Disable top/filler placement
737                                 }
738
739                                 air_above = false;
740                                 water_above = false;
741                         } else if (c == c_water_source) {
742                                 vm->m_data[vi] = MapNode((y > (s32)(water_level - depth_water_top))
743                                                 ? biome->c_water_top : biome->c_water);
744                                 nplaced = 0;  // Enable top/filler placement for next surface
745                                 air_above = false;
746                                 water_above = true;
747                         } else if (c == c_river_water_source) {
748                                 vm->m_data[vi] = MapNode(biome->c_river_water);
749                                 nplaced = 0;  // Enable riverbed placement for next surface
750                                 air_above = false;
751                                 water_above = true;
752                                 river_water_above = true;
753                         } else if (c == CONTENT_AIR) {
754                                 nplaced = 0;  // Enable top/filler placement for next surface
755                                 air_above = true;
756                                 water_above = false;
757                         } else {  // Possible various nodes overgenerated from neighbouring mapchunks
758                                 nplaced = U16_MAX;  // Disable top/filler placement
759                                 air_above = false;
760                                 water_above = false;
761                         }
762
763                         VoxelArea::add_y(em, vi, -1);
764                 }
765                 // If no stone surface was detected in this mapchunk column the biomemap
766                 // will be empty for this (x, z) position. Add the currently active
767                 // biome to the biomemap, or if biome is NULL calculate it for this
768                 // position and add it.
769                 if (biomemap[index] == BIOME_NONE) {
770                         if (!biome)
771                                 biome = biomegen->getBiomeAtIndex(
772                                         index, v3s16(x, node_min.Y, z));
773                         biomemap[index] = biome->index;
774                 }
775         }
776 }
777
778
779 void MapgenBasic::dustTopNodes()
780 {
781         if (node_max.Y < water_level)
782                 return;
783
784         const v3s16 &em = vm->m_area.getExtent();
785         u32 index = 0;
786
787         for (s16 z = node_min.Z; z <= node_max.Z; z++)
788         for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
789                 Biome *biome = (Biome *)m_bmgr->getRaw(biomemap[index]);
790
791                 if (biome->c_dust == CONTENT_IGNORE)
792                         continue;
793
794                 u32 vi = vm->m_area.index(x, full_node_max.Y, z);
795                 content_t c_full_max = vm->m_data[vi].getContent();
796                 s16 y_start;
797
798                 if (c_full_max == CONTENT_AIR) {
799                         y_start = full_node_max.Y - 1;
800                 } else if (c_full_max == CONTENT_IGNORE) {
801                         vi = vm->m_area.index(x, node_max.Y + 1, z);
802                         content_t c_max = vm->m_data[vi].getContent();
803
804                         if (c_max == CONTENT_AIR)
805                                 y_start = node_max.Y;
806                         else
807                                 continue;
808                 } else {
809                         continue;
810                 }
811
812                 vi = vm->m_area.index(x, y_start, z);
813                 for (s16 y = y_start; y >= node_min.Y - 1; y--) {
814                         if (vm->m_data[vi].getContent() != CONTENT_AIR)
815                                 break;
816
817                         VoxelArea::add_y(em, vi, -1);
818                 }
819
820                 content_t c = vm->m_data[vi].getContent();
821                 NodeDrawType dtype = ndef->get(c).drawtype;
822                 // Only place on walkable cubic non-liquid nodes
823                 // Dust check needed due to vertical overgeneration
824                 if ((dtype == NDT_NORMAL ||
825                                 dtype == NDT_ALLFACES_OPTIONAL ||
826                                 dtype == NDT_GLASSLIKE_FRAMED_OPTIONAL ||
827                                 dtype == NDT_GLASSLIKE ||
828                                 dtype == NDT_GLASSLIKE_FRAMED ||
829                                 dtype == NDT_ALLFACES) &&
830                                 ndef->get(c).walkable && c != biome->c_dust) {
831                         VoxelArea::add_y(em, vi, 1);
832                         vm->m_data[vi] = MapNode(biome->c_dust);
833                 }
834         }
835 }
836
837
838 void MapgenBasic::generateCavesNoiseIntersection(s16 max_stone_y)
839 {
840         if (node_min.Y > max_stone_y)
841                 return;
842
843         CavesNoiseIntersection caves_noise(ndef, m_bmgr, csize,
844                 &np_cave1, &np_cave2, seed, cave_width);
845
846         caves_noise.generateCaves(vm, node_min, node_max, biomemap);
847 }
848
849
850 void MapgenBasic::generateCavesRandomWalk(s16 max_stone_y, s16 large_cave_depth)
851 {
852         if (node_min.Y > max_stone_y || node_max.Y > large_cave_depth)
853                 return;
854
855         PseudoRandom ps(blockseed + 21343);
856         u32 bruises_count = ps.range(0, 2);
857
858         for (u32 i = 0; i < bruises_count; i++) {
859                 CavesRandomWalk cave(ndef, &gennotify, seed, water_level,
860                         c_water_source, c_lava_source, lava_depth, biomegen);
861
862                 cave.makeCave(vm, node_min, node_max, &ps, true, max_stone_y,
863                         heightmap);
864         }
865 }
866
867
868 bool MapgenBasic::generateCavernsNoise(s16 max_stone_y)
869 {
870         if (node_min.Y > max_stone_y || node_min.Y > cavern_limit)
871                 return false;
872
873         CavernsNoise caverns_noise(ndef, csize, &np_cavern,
874                 seed, cavern_limit, cavern_taper, cavern_threshold);
875
876         return caverns_noise.generateCaverns(vm, node_min, node_max);
877 }
878
879
880 void MapgenBasic::generateDungeons(s16 max_stone_y)
881 {
882         if (max_stone_y < node_min.Y)
883                 return;
884
885         // Get biome at mapchunk midpoint
886         v3s16 chunk_mid = node_min + (node_max - node_min) / v3s16(2, 2, 2);
887         Biome *biome = (Biome *)biomegen->getBiomeAtPoint(chunk_mid);
888
889         DungeonParams dp;
890
891         dp.seed             = seed;
892         dp.only_in_ground   = true;
893         dp.corridor_len_min = 1;
894         dp.corridor_len_max = 13;
895         dp.rooms_min        = 2;
896         dp.rooms_max        = 16;
897
898         dp.np_density       = nparams_dungeon_density;
899         dp.np_alt_wall      = nparams_dungeon_alt_wall;
900
901         // Biome-defined dungeon nodes
902         if (biome->c_dungeon != CONTENT_IGNORE) {
903                 dp.c_wall              = biome->c_dungeon;
904                 // If 'node_dungeon_alt' is not defined by biome, it and dp.c_alt_wall
905                 // become CONTENT_IGNORE which skips the alt wall node placement loop in
906                 // dungeongen.cpp.
907                 dp.c_alt_wall          = biome->c_dungeon_alt;
908                 // Stairs fall back to 'c_dungeon' if not defined by biome
909                 dp.c_stair = (biome->c_dungeon_stair != CONTENT_IGNORE) ?
910                         biome->c_dungeon_stair : biome->c_dungeon;
911
912                 dp.diagonal_dirs       = false;
913                 dp.holesize            = v3s16(2, 2, 2);
914                 dp.room_size_min       = v3s16(6, 4, 6);
915                 dp.room_size_max       = v3s16(10, 6, 10);
916                 dp.room_size_large_min = v3s16(10, 8, 10);
917                 dp.room_size_large_max = v3s16(18, 16, 18);
918                 dp.notifytype          = GENNOTIFY_DUNGEON;
919
920         // Otherwise classic behaviour
921         } else if (biome->c_stone == c_stone) {
922                 dp.c_wall              = c_cobble;
923                 dp.c_alt_wall          = c_mossycobble;
924                 dp.c_stair             = c_stair_cobble;
925
926                 dp.diagonal_dirs       = false;
927                 dp.holesize            = v3s16(1, 2, 1);
928                 dp.room_size_min       = v3s16(4, 4, 4);
929                 dp.room_size_max       = v3s16(8, 6, 8);
930                 dp.room_size_large_min = v3s16(8, 8, 8);
931                 dp.room_size_large_max = v3s16(16, 16, 16);
932                 dp.notifytype          = GENNOTIFY_DUNGEON;
933
934         } else if (biome->c_stone == c_desert_stone) {
935                 dp.c_wall              = c_desert_stone;
936                 dp.c_alt_wall          = CONTENT_IGNORE;
937                 dp.c_stair             = c_stair_desert_stone;
938
939                 dp.diagonal_dirs       = true;
940                 dp.holesize            = v3s16(2, 3, 2);
941                 dp.room_size_min       = v3s16(6, 9, 6);
942                 dp.room_size_max       = v3s16(10, 11, 10);
943                 dp.room_size_large_min = v3s16(10, 13, 10);
944                 dp.room_size_large_max = v3s16(18, 21, 18);
945                 dp.notifytype          = GENNOTIFY_TEMPLE;
946
947         } else if (biome->c_stone == c_sandstone) {
948                 dp.c_wall              = c_sandstonebrick;
949                 dp.c_alt_wall          = CONTENT_IGNORE;
950                 dp.c_stair             = c_stair_sandstone_block;
951
952                 dp.diagonal_dirs       = false;
953                 dp.holesize            = v3s16(2, 2, 2);
954                 dp.room_size_min       = v3s16(6, 4, 6);
955                 dp.room_size_max       = v3s16(10, 6, 10);
956                 dp.room_size_large_min = v3s16(10, 8, 10);
957                 dp.room_size_large_max = v3s16(18, 16, 18);
958                 dp.notifytype          = GENNOTIFY_DUNGEON;
959
960         // Fallback to using biome 'node_stone'
961         } else {
962                 dp.c_wall              = biome->c_stone;
963                 dp.c_alt_wall          = CONTENT_IGNORE;
964                 dp.c_stair             = biome->c_stone;
965
966                 dp.diagonal_dirs       = false;
967                 dp.holesize            = v3s16(2, 2, 2);
968                 dp.room_size_min       = v3s16(6, 4, 6);
969                 dp.room_size_max       = v3s16(10, 6, 10);
970                 dp.room_size_large_min = v3s16(10, 8, 10);
971                 dp.room_size_large_max = v3s16(18, 16, 18);
972                 dp.notifytype          = GENNOTIFY_DUNGEON;
973         }
974
975         DungeonGen dgen(ndef, &gennotify, &dp);
976         dgen.generate(vm, blockseed, full_node_min, full_node_max);
977 }
978
979
980 ////
981 //// GenerateNotifier
982 ////
983
984 GenerateNotifier::GenerateNotifier(u32 notify_on,
985         std::set<u32> *notify_on_deco_ids)
986 {
987         m_notify_on = notify_on;
988         m_notify_on_deco_ids = notify_on_deco_ids;
989 }
990
991
992 void GenerateNotifier::setNotifyOn(u32 notify_on)
993 {
994         m_notify_on = notify_on;
995 }
996
997
998 void GenerateNotifier::setNotifyOnDecoIds(std::set<u32> *notify_on_deco_ids)
999 {
1000         m_notify_on_deco_ids = notify_on_deco_ids;
1001 }
1002
1003
1004 bool GenerateNotifier::addEvent(GenNotifyType type, v3s16 pos, u32 id)
1005 {
1006         if (!(m_notify_on & (1 << type)))
1007                 return false;
1008
1009         if (type == GENNOTIFY_DECORATION &&
1010                 m_notify_on_deco_ids->find(id) == m_notify_on_deco_ids->end())
1011                 return false;
1012
1013         GenNotifyEvent gne;
1014         gne.type = type;
1015         gne.pos  = pos;
1016         gne.id   = id;
1017         m_notify_events.push_back(gne);
1018
1019         return true;
1020 }
1021
1022
1023 void GenerateNotifier::getEvents(
1024         std::map<std::string, std::vector<v3s16> > &event_map)
1025 {
1026         std::list<GenNotifyEvent>::iterator it;
1027
1028         for (it = m_notify_events.begin(); it != m_notify_events.end(); ++it) {
1029                 GenNotifyEvent &gn = *it;
1030                 std::string name = (gn.type == GENNOTIFY_DECORATION) ?
1031                         "decoration#"+ itos(gn.id) :
1032                         flagdesc_gennotify[gn.type].name;
1033
1034                 event_map[name].push_back(gn.pos);
1035         }
1036 }
1037
1038
1039 void GenerateNotifier::clearEvents()
1040 {
1041         m_notify_events.clear();
1042 }
1043
1044
1045 ////
1046 //// MapgenParams
1047 ////
1048
1049
1050 MapgenParams::~MapgenParams()
1051 {
1052         delete bparams;
1053 }
1054
1055
1056 void MapgenParams::readParams(const Settings *settings)
1057 {
1058         std::string seed_str;
1059         const char *seed_name = (settings == g_settings) ? "fixed_map_seed" : "seed";
1060
1061         if (settings->getNoEx(seed_name, seed_str)) {
1062                 if (!seed_str.empty())
1063                         seed = read_seed(seed_str.c_str());
1064                 else
1065                         myrand_bytes(&seed, sizeof(seed));
1066         }
1067
1068         std::string mg_name;
1069         if (settings->getNoEx("mg_name", mg_name)) {
1070                 mgtype = Mapgen::getMapgenType(mg_name);
1071                 if (mgtype == MAPGEN_INVALID)
1072                         mgtype = MAPGEN_DEFAULT;
1073         }
1074
1075         settings->getS16NoEx("water_level", water_level);
1076         settings->getS16NoEx("mapgen_limit", mapgen_limit);
1077         settings->getS16NoEx("chunksize", chunksize);
1078         settings->getFlagStrNoEx("mg_flags", flags, flagdesc_mapgen);
1079
1080         delete bparams;
1081         bparams = BiomeManager::createBiomeParams(BIOMEGEN_ORIGINAL);
1082         if (bparams) {
1083                 bparams->readParams(settings);
1084                 bparams->seed = seed;
1085         }
1086 }
1087
1088
1089 void MapgenParams::writeParams(Settings *settings) const
1090 {
1091         settings->set("mg_name", Mapgen::getMapgenName(mgtype));
1092         settings->setU64("seed", seed);
1093         settings->setS16("water_level", water_level);
1094         settings->setS16("mapgen_limit", mapgen_limit);
1095         settings->setS16("chunksize", chunksize);
1096         settings->setFlagStr("mg_flags", flags, flagdesc_mapgen, U32_MAX);
1097
1098         if (bparams)
1099                 bparams->writeParams(settings);
1100 }
1101
1102
1103 // Calculate exact edges of the outermost mapchunks that are within the
1104 // set 'mapgen_limit'.
1105 void MapgenParams::calcMapgenEdges()
1106 {
1107         // Central chunk offset, in blocks
1108         s16 ccoff_b = -chunksize / 2;
1109         // Chunksize, in nodes
1110         s32 csize_n = chunksize * MAP_BLOCKSIZE;
1111         // Minp/maxp of central chunk, in nodes
1112         s16 ccmin = ccoff_b * MAP_BLOCKSIZE;
1113         s16 ccmax = ccmin + csize_n - 1;
1114         // Fullminp/fullmaxp of central chunk, in nodes
1115         s16 ccfmin = ccmin - MAP_BLOCKSIZE;
1116         s16 ccfmax = ccmax + MAP_BLOCKSIZE;
1117         // Effective mapgen limit, in blocks
1118         // Uses same calculation as ServerMap::blockpos_over_mapgen_limit(v3s16 p)
1119         s16 mapgen_limit_b = rangelim(mapgen_limit,
1120                 0, MAX_MAP_GENERATION_LIMIT) / MAP_BLOCKSIZE;
1121         // Effective mapgen limits, in nodes
1122         s16 mapgen_limit_min = -mapgen_limit_b * MAP_BLOCKSIZE;
1123         s16 mapgen_limit_max = (mapgen_limit_b + 1) * MAP_BLOCKSIZE - 1;
1124         // Number of complete chunks from central chunk fullminp/fullmaxp
1125         // to effective mapgen limits.
1126         s16 numcmin = MYMAX((ccfmin - mapgen_limit_min) / csize_n, 0);
1127         s16 numcmax = MYMAX((mapgen_limit_max - ccfmax) / csize_n, 0);
1128         // Mapgen edges, in nodes
1129         mapgen_edge_min = ccmin - numcmin * csize_n;
1130         mapgen_edge_max = ccmax + numcmax * csize_n;
1131
1132         m_mapgen_edges_calculated = true;
1133 }
1134
1135
1136 s32 MapgenParams::getSpawnRangeMax()
1137 {
1138         if (!m_mapgen_edges_calculated)
1139                 calcMapgenEdges();
1140
1141         return MYMIN(-mapgen_edge_min, mapgen_edge_max);
1142 }