SAO limits: Allow SAOs to exist outside the set 'mapgen limit'
[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                 vm->m_area.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                 vm->m_area.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                 vm->m_area.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         vm->m_area.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                 vm->m_area.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         vm->m_area.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         vm->m_area.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         vm->m_area.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         vm->m_area.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                                 vm->m_area.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                         vm->m_area.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                         vm->m_area.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                                 vm->m_area.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(MgStoneType *mgstone_type,
644         content_t *biome_stone)
645 {
646         // can't generate biomes without a biome generator!
647         assert(biomegen);
648         assert(biomemap);
649
650         const v3s16 &em = vm->m_area.getExtent();
651         u32 index = 0;
652         MgStoneType stone_type = MGSTONE_OTHER;
653         content_t c_biome_stone = c_stone;
654
655         noise_filler_depth->perlinMap2D(node_min.X, node_min.Z);
656
657         for (s16 z = node_min.Z; z <= node_max.Z; z++)
658         for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
659                 Biome *biome = NULL;
660                 u16 depth_top = 0;
661                 u16 base_filler = 0;
662                 u16 depth_water_top = 0;
663                 u16 depth_riverbed = 0;
664                 s16 biome_y_min = -MAX_MAP_GENERATION_LIMIT;
665                 u32 vi = vm->m_area.index(x, node_max.Y, z);
666
667                 // Check node at base of mapchunk above, either a node of a previously
668                 // generated mapchunk or if not, a node of overgenerated base terrain.
669                 content_t c_above = vm->m_data[vi + em.X].getContent();
670                 bool air_above = c_above == CONTENT_AIR;
671                 bool river_water_above = c_above == c_river_water_source;
672                 bool water_above = c_above == c_water_source || river_water_above;
673
674                 biomemap[index] = BIOME_NONE;
675
676                 // If there is air or water above enable top/filler placement, otherwise force
677                 // nplaced to stone level by setting a number exceeding any possible filler depth.
678                 u16 nplaced = (air_above || water_above) ? 0 : U16_MAX;
679
680                 for (s16 y = node_max.Y; y >= node_min.Y; y--) {
681                         content_t c = vm->m_data[vi].getContent();
682                         // Biome is (re)calculated:
683                         // 1. At the surface of stone below air or water.
684                         // 2. At the surface of water below air.
685                         // 3. When stone or water is detected but biome has not yet been calculated.
686                         // 4. When stone or water is detected just below a biome's lower limit.
687                         bool is_stone_surface = (c == c_stone) &&
688                                 (air_above || water_above || !biome || y < biome_y_min); // 1, 3, 4
689
690                         bool is_water_surface =
691                                 (c == c_water_source || c == c_river_water_source) &&
692                                 (air_above || !biome || y < biome_y_min); // 2, 3, 4
693
694                         if (is_stone_surface || is_water_surface) {
695                                 // (Re)calculate biome
696                                 biome = biomegen->getBiomeAtIndex(index, y);
697
698                                 if (biomemap[index] == BIOME_NONE && is_stone_surface)
699                                         biomemap[index] = biome->index;
700
701                                 depth_top = biome->depth_top;
702                                 base_filler = MYMAX(depth_top +
703                                         biome->depth_filler +
704                                         noise_filler_depth->result[index], 0.0f);
705                                 depth_water_top = biome->depth_water_top;
706                                 depth_riverbed = biome->depth_riverbed;
707                                 biome_y_min = biome->y_min;
708
709                                 // Detect stone type for dungeons during every biome calculation.
710                                 // If none detected the last selected biome stone is chosen.
711                                 if (biome->c_stone == c_stone)
712                                         stone_type = MGSTONE_STONE;
713                                 else if (biome->c_stone == c_desert_stone)
714                                         stone_type = MGSTONE_DESERT_STONE;
715                                 else if (biome->c_stone == c_sandstone)
716                                         stone_type = MGSTONE_SANDSTONE;
717
718                                 c_biome_stone = biome->c_stone;
719                         }
720
721                         if (c == c_stone) {
722                                 content_t c_below = vm->m_data[vi - em.X].getContent();
723
724                                 // If the node below isn't solid, make this node stone, so that
725                                 // any top/filler nodes above are structurally supported.
726                                 // This is done by aborting the cycle of top/filler placement
727                                 // immediately by forcing nplaced to stone level.
728                                 if (c_below == CONTENT_AIR
729                                                 || c_below == c_water_source
730                                                 || c_below == c_river_water_source)
731                                         nplaced = U16_MAX;
732
733                                 if (river_water_above) {
734                                         if (nplaced < depth_riverbed) {
735                                                 vm->m_data[vi] = MapNode(biome->c_riverbed);
736                                                 nplaced++;
737                                         } else {
738                                                 nplaced = U16_MAX;  // Disable top/filler placement
739                                                 river_water_above = false;
740                                         }
741                                 } else if (nplaced < depth_top) {
742                                         vm->m_data[vi] = MapNode(biome->c_top);
743                                         nplaced++;
744                                 } else if (nplaced < base_filler) {
745                                         vm->m_data[vi] = MapNode(biome->c_filler);
746                                         nplaced++;
747                                 } else {
748                                         vm->m_data[vi] = MapNode(biome->c_stone);
749                                         nplaced = U16_MAX;  // Disable top/filler placement
750                                 }
751
752                                 air_above = false;
753                                 water_above = false;
754                         } else if (c == c_water_source) {
755                                 vm->m_data[vi] = MapNode((y > (s32)(water_level - depth_water_top))
756                                                 ? biome->c_water_top : biome->c_water);
757                                 nplaced = 0;  // Enable top/filler placement for next surface
758                                 air_above = false;
759                                 water_above = true;
760                         } else if (c == c_river_water_source) {
761                                 vm->m_data[vi] = MapNode(biome->c_river_water);
762                                 nplaced = 0;  // Enable riverbed placement for next surface
763                                 air_above = false;
764                                 water_above = true;
765                                 river_water_above = true;
766                         } else if (c == CONTENT_AIR) {
767                                 nplaced = 0;  // Enable top/filler placement for next surface
768                                 air_above = true;
769                                 water_above = false;
770                         } else {  // Possible various nodes overgenerated from neighbouring mapchunks
771                                 nplaced = U16_MAX;  // Disable top/filler placement
772                                 air_above = false;
773                                 water_above = false;
774                         }
775
776                         vm->m_area.add_y(em, vi, -1);
777                 }
778         }
779
780         *mgstone_type = stone_type;
781         *biome_stone = c_biome_stone;
782 }
783
784
785 void MapgenBasic::dustTopNodes()
786 {
787         if (node_max.Y < water_level)
788                 return;
789
790         const v3s16 &em = vm->m_area.getExtent();
791         u32 index = 0;
792
793         for (s16 z = node_min.Z; z <= node_max.Z; z++)
794         for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
795                 Biome *biome = (Biome *)m_bmgr->getRaw(biomemap[index]);
796
797                 if (biome->c_dust == CONTENT_IGNORE)
798                         continue;
799
800                 u32 vi = vm->m_area.index(x, full_node_max.Y, z);
801                 content_t c_full_max = vm->m_data[vi].getContent();
802                 s16 y_start;
803
804                 if (c_full_max == CONTENT_AIR) {
805                         y_start = full_node_max.Y - 1;
806                 } else if (c_full_max == CONTENT_IGNORE) {
807                         vi = vm->m_area.index(x, node_max.Y + 1, z);
808                         content_t c_max = vm->m_data[vi].getContent();
809
810                         if (c_max == CONTENT_AIR)
811                                 y_start = node_max.Y;
812                         else
813                                 continue;
814                 } else {
815                         continue;
816                 }
817
818                 vi = vm->m_area.index(x, y_start, z);
819                 for (s16 y = y_start; y >= node_min.Y - 1; y--) {
820                         if (vm->m_data[vi].getContent() != CONTENT_AIR)
821                                 break;
822
823                         vm->m_area.add_y(em, vi, -1);
824                 }
825
826                 content_t c = vm->m_data[vi].getContent();
827                 NodeDrawType dtype = ndef->get(c).drawtype;
828                 // Only place on walkable cubic non-liquid nodes
829                 // Dust check needed due to vertical overgeneration
830                 if ((dtype == NDT_NORMAL ||
831                                 dtype == NDT_ALLFACES_OPTIONAL ||
832                                 dtype == NDT_GLASSLIKE_FRAMED_OPTIONAL ||
833                                 dtype == NDT_GLASSLIKE ||
834                                 dtype == NDT_GLASSLIKE_FRAMED ||
835                                 dtype == NDT_ALLFACES) &&
836                                 ndef->get(c).walkable && c != biome->c_dust) {
837                         vm->m_area.add_y(em, vi, 1);
838                         vm->m_data[vi] = MapNode(biome->c_dust);
839                 }
840         }
841 }
842
843
844 void MapgenBasic::generateCaves(s16 max_stone_y, s16 large_cave_depth)
845 {
846         if (max_stone_y < node_min.Y)
847                 return;
848
849         CavesNoiseIntersection caves_noise(ndef, m_bmgr, csize,
850                 &np_cave1, &np_cave2, seed, cave_width);
851
852         caves_noise.generateCaves(vm, node_min, node_max, biomemap);
853
854         if (node_max.Y > large_cave_depth)
855                 return;
856
857         PseudoRandom ps(blockseed + 21343);
858         u32 bruises_count = ps.range(0, 2);
859         for (u32 i = 0; i < bruises_count; i++) {
860                 CavesRandomWalk cave(ndef, &gennotify, seed, water_level,
861                         c_water_source, CONTENT_IGNORE, lava_depth);
862
863                 cave.makeCave(vm, node_min, node_max, &ps, true, max_stone_y, heightmap);
864         }
865 }
866
867
868 bool MapgenBasic::generateCaverns(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         MgStoneType stone_type, content_t biome_stone)
882 {
883         if (max_stone_y < node_min.Y)
884                 return;
885
886         DungeonParams dp;
887
888         dp.seed             = seed;
889
890         dp.only_in_ground   = true;
891         dp.corridor_len_min = 1;
892         dp.corridor_len_max = 13;
893         dp.rooms_min        = 2;
894         dp.rooms_max        = 16;
895         dp.y_min            = -MAX_MAP_GENERATION_LIMIT;
896         dp.y_max            = MAX_MAP_GENERATION_LIMIT;
897
898         dp.np_density       = nparams_dungeon_density;
899         dp.np_alt_wall      = nparams_dungeon_alt_wall;
900
901         switch (stone_type) {
902         default:
903         case MGSTONE_STONE:
904                 dp.c_wall              = c_cobble;
905                 dp.c_alt_wall          = c_mossycobble;
906                 dp.c_stair             = c_stair_cobble;
907
908                 dp.diagonal_dirs       = false;
909                 dp.holesize            = v3s16(1, 2, 1);
910                 dp.room_size_min       = v3s16(4, 4, 4);
911                 dp.room_size_max       = v3s16(8, 6, 8);
912                 dp.room_size_large_min = v3s16(8, 8, 8);
913                 dp.room_size_large_max = v3s16(16, 16, 16);
914                 dp.notifytype          = GENNOTIFY_DUNGEON;
915                 break;
916         case MGSTONE_DESERT_STONE:
917                 dp.c_wall              = c_desert_stone;
918                 dp.c_alt_wall          = CONTENT_IGNORE;
919                 dp.c_stair             = c_stair_desert_stone;
920
921                 dp.diagonal_dirs       = true;
922                 dp.holesize            = v3s16(2, 3, 2);
923                 dp.room_size_min       = v3s16(6, 9, 6);
924                 dp.room_size_max       = v3s16(10, 11, 10);
925                 dp.room_size_large_min = v3s16(10, 13, 10);
926                 dp.room_size_large_max = v3s16(18, 21, 18);
927                 dp.notifytype          = GENNOTIFY_TEMPLE;
928                 break;
929         case MGSTONE_SANDSTONE:
930                 dp.c_wall              = c_sandstonebrick;
931                 dp.c_alt_wall          = CONTENT_IGNORE;
932                 dp.c_stair             = c_stair_sandstone_block;
933
934                 dp.diagonal_dirs       = false;
935                 dp.holesize            = v3s16(2, 2, 2);
936                 dp.room_size_min       = v3s16(6, 4, 6);
937                 dp.room_size_max       = v3s16(10, 6, 10);
938                 dp.room_size_large_min = v3s16(10, 8, 10);
939                 dp.room_size_large_max = v3s16(18, 16, 18);
940                 dp.notifytype          = GENNOTIFY_DUNGEON;
941                 break;
942         case MGSTONE_OTHER:
943                 dp.c_wall              = biome_stone;
944                 dp.c_alt_wall          = biome_stone;
945                 dp.c_stair             = biome_stone;
946
947                 dp.diagonal_dirs       = false;
948                 dp.holesize            = v3s16(1, 2, 1);
949                 dp.room_size_min       = v3s16(4, 4, 4);
950                 dp.room_size_max       = v3s16(8, 6, 8);
951                 dp.room_size_large_min = v3s16(8, 8, 8);
952                 dp.room_size_large_max = v3s16(16, 16, 16);
953                 dp.notifytype          = GENNOTIFY_DUNGEON;
954                 break;
955         }
956
957         DungeonGen dgen(ndef, &gennotify, &dp);
958         dgen.generate(vm, blockseed, full_node_min, full_node_max);
959 }
960
961
962 ////
963 //// GenerateNotifier
964 ////
965
966 GenerateNotifier::GenerateNotifier(u32 notify_on,
967         std::set<u32> *notify_on_deco_ids)
968 {
969         m_notify_on = notify_on;
970         m_notify_on_deco_ids = notify_on_deco_ids;
971 }
972
973
974 void GenerateNotifier::setNotifyOn(u32 notify_on)
975 {
976         m_notify_on = notify_on;
977 }
978
979
980 void GenerateNotifier::setNotifyOnDecoIds(std::set<u32> *notify_on_deco_ids)
981 {
982         m_notify_on_deco_ids = notify_on_deco_ids;
983 }
984
985
986 bool GenerateNotifier::addEvent(GenNotifyType type, v3s16 pos, u32 id)
987 {
988         if (!(m_notify_on & (1 << type)))
989                 return false;
990
991         if (type == GENNOTIFY_DECORATION &&
992                 m_notify_on_deco_ids->find(id) == m_notify_on_deco_ids->end())
993                 return false;
994
995         GenNotifyEvent gne;
996         gne.type = type;
997         gne.pos  = pos;
998         gne.id   = id;
999         m_notify_events.push_back(gne);
1000
1001         return true;
1002 }
1003
1004
1005 void GenerateNotifier::getEvents(
1006         std::map<std::string, std::vector<v3s16> > &event_map,
1007         bool peek_events)
1008 {
1009         std::list<GenNotifyEvent>::iterator it;
1010
1011         for (it = m_notify_events.begin(); it != m_notify_events.end(); ++it) {
1012                 GenNotifyEvent &gn = *it;
1013                 std::string name = (gn.type == GENNOTIFY_DECORATION) ?
1014                         "decoration#"+ itos(gn.id) :
1015                         flagdesc_gennotify[gn.type].name;
1016
1017                 event_map[name].push_back(gn.pos);
1018         }
1019
1020         if (!peek_events)
1021                 m_notify_events.clear();
1022 }
1023
1024
1025 ////
1026 //// MapgenParams
1027 ////
1028
1029
1030 MapgenParams::~MapgenParams()
1031 {
1032         delete bparams;
1033 }
1034
1035
1036 void MapgenParams::readParams(const Settings *settings)
1037 {
1038         std::string seed_str;
1039         const char *seed_name = (settings == g_settings) ? "fixed_map_seed" : "seed";
1040
1041         if (settings->getNoEx(seed_name, seed_str)) {
1042                 if (!seed_str.empty())
1043                         seed = read_seed(seed_str.c_str());
1044                 else
1045                         myrand_bytes(&seed, sizeof(seed));
1046         }
1047
1048         std::string mg_name;
1049         if (settings->getNoEx("mg_name", mg_name)) {
1050                 mgtype = Mapgen::getMapgenType(mg_name);
1051                 if (mgtype == MAPGEN_INVALID)
1052                         mgtype = MAPGEN_DEFAULT;
1053         }
1054
1055         settings->getS16NoEx("water_level", water_level);
1056         settings->getS16NoEx("mapgen_limit", mapgen_limit);
1057         settings->getS16NoEx("chunksize", chunksize);
1058         settings->getFlagStrNoEx("mg_flags", flags, flagdesc_mapgen);
1059
1060         delete bparams;
1061         bparams = BiomeManager::createBiomeParams(BIOMEGEN_ORIGINAL);
1062         if (bparams) {
1063                 bparams->readParams(settings);
1064                 bparams->seed = seed;
1065         }
1066 }
1067
1068
1069 void MapgenParams::writeParams(Settings *settings) const
1070 {
1071         settings->set("mg_name", Mapgen::getMapgenName(mgtype));
1072         settings->setU64("seed", seed);
1073         settings->setS16("water_level", water_level);
1074         settings->setS16("mapgen_limit", mapgen_limit);
1075         settings->setS16("chunksize", chunksize);
1076         settings->setFlagStr("mg_flags", flags, flagdesc_mapgen, U32_MAX);
1077
1078         if (bparams)
1079                 bparams->writeParams(settings);
1080 }
1081
1082
1083 // Calculate exact edges of the outermost mapchunks that are within the
1084 // set 'mapgen_limit'.
1085 void MapgenParams::calcMapgenEdges()
1086 {
1087         // Central chunk offset, in blocks
1088         s16 ccoff_b = -chunksize / 2;
1089         // Chunksize, in nodes
1090         s32 csize_n = chunksize * MAP_BLOCKSIZE;
1091         // Minp/maxp of central chunk, in nodes
1092         s16 ccmin = ccoff_b * MAP_BLOCKSIZE;
1093         s16 ccmax = ccmin + csize_n - 1;
1094         // Fullminp/fullmaxp of central chunk, in nodes
1095         s16 ccfmin = ccmin - MAP_BLOCKSIZE;
1096         s16 ccfmax = ccmax + MAP_BLOCKSIZE;
1097         // Effective mapgen limit, in blocks
1098         // Uses same calculation as ServerMap::blockpos_over_mapgen_limit(v3s16 p)
1099         s16 mapgen_limit_b = rangelim(mapgen_limit,
1100                 0, MAX_MAP_GENERATION_LIMIT) / MAP_BLOCKSIZE;
1101         // Effective mapgen limits, in nodes
1102         s16 mapgen_limit_min = -mapgen_limit_b * MAP_BLOCKSIZE;
1103         s16 mapgen_limit_max = (mapgen_limit_b + 1) * MAP_BLOCKSIZE - 1;
1104         // Number of complete chunks from central chunk fullminp/fullmaxp
1105         // to effective mapgen limits.
1106         s16 numcmin = MYMAX((ccfmin - mapgen_limit_min) / csize_n, 0);
1107         s16 numcmax = MYMAX((mapgen_limit_max - ccfmax) / csize_n, 0);
1108         // Mapgen edges, in nodes
1109         mapgen_edge_min = ccmin - numcmin * csize_n;
1110         mapgen_edge_max = ccmax + numcmax * csize_n;
1111
1112         m_mapgen_edges_calculated = true;
1113 }
1114
1115
1116 s32 MapgenParams::getSpawnRangeMax()
1117 {
1118         if (!m_mapgen_edges_calculated)
1119                 calcMapgenEdges();
1120
1121         return MYMIN(-mapgen_edge_min, mapgen_edge_max);
1122 }