]> git.lizzy.rs Git - dragonfireclient.git/blob - src/mapgen/mapgen.cpp
Mapgen folder: Update and improve copyright information of files
[dragonfireclient.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         dp.c_water          = c_water_source;
890         dp.c_river_water    = c_river_water_source;
891
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         dp.y_min            = -MAX_MAP_GENERATION_LIMIT;
898         dp.y_max            = MAX_MAP_GENERATION_LIMIT;
899
900         dp.np_density       = nparams_dungeon_density;
901         dp.np_alt_wall      = nparams_dungeon_alt_wall;
902
903         switch (stone_type) {
904         default:
905         case MGSTONE_STONE:
906                 dp.c_wall              = c_cobble;
907                 dp.c_alt_wall          = c_mossycobble;
908                 dp.c_stair             = c_stair_cobble;
909
910                 dp.diagonal_dirs       = false;
911                 dp.holesize            = v3s16(1, 2, 1);
912                 dp.room_size_min       = v3s16(4, 4, 4);
913                 dp.room_size_max       = v3s16(8, 6, 8);
914                 dp.room_size_large_min = v3s16(8, 8, 8);
915                 dp.room_size_large_max = v3s16(16, 16, 16);
916                 dp.notifytype          = GENNOTIFY_DUNGEON;
917                 break;
918         case MGSTONE_DESERT_STONE:
919                 dp.c_wall              = c_desert_stone;
920                 dp.c_alt_wall          = CONTENT_IGNORE;
921                 dp.c_stair             = c_stair_desert_stone;
922
923                 dp.diagonal_dirs       = true;
924                 dp.holesize            = v3s16(2, 3, 2);
925                 dp.room_size_min       = v3s16(6, 9, 6);
926                 dp.room_size_max       = v3s16(10, 11, 10);
927                 dp.room_size_large_min = v3s16(10, 13, 10);
928                 dp.room_size_large_max = v3s16(18, 21, 18);
929                 dp.notifytype          = GENNOTIFY_TEMPLE;
930                 break;
931         case MGSTONE_SANDSTONE:
932                 dp.c_wall              = c_sandstonebrick;
933                 dp.c_alt_wall          = CONTENT_IGNORE;
934                 dp.c_stair             = c_stair_sandstone_block;
935
936                 dp.diagonal_dirs       = false;
937                 dp.holesize            = v3s16(2, 2, 2);
938                 dp.room_size_min       = v3s16(6, 4, 6);
939                 dp.room_size_max       = v3s16(10, 6, 10);
940                 dp.room_size_large_min = v3s16(10, 8, 10);
941                 dp.room_size_large_max = v3s16(18, 16, 18);
942                 dp.notifytype          = GENNOTIFY_DUNGEON;
943                 break;
944         case MGSTONE_OTHER:
945                 dp.c_wall              = biome_stone;
946                 dp.c_alt_wall          = biome_stone;
947                 dp.c_stair             = biome_stone;
948
949                 dp.diagonal_dirs       = false;
950                 dp.holesize            = v3s16(1, 2, 1);
951                 dp.room_size_min       = v3s16(4, 4, 4);
952                 dp.room_size_max       = v3s16(8, 6, 8);
953                 dp.room_size_large_min = v3s16(8, 8, 8);
954                 dp.room_size_large_max = v3s16(16, 16, 16);
955                 dp.notifytype          = GENNOTIFY_DUNGEON;
956                 break;
957         }
958
959         DungeonGen dgen(ndef, &gennotify, &dp);
960         dgen.generate(vm, blockseed, full_node_min, full_node_max);
961 }
962
963
964 ////
965 //// GenerateNotifier
966 ////
967
968 GenerateNotifier::GenerateNotifier(u32 notify_on,
969         std::set<u32> *notify_on_deco_ids)
970 {
971         m_notify_on = notify_on;
972         m_notify_on_deco_ids = notify_on_deco_ids;
973 }
974
975
976 void GenerateNotifier::setNotifyOn(u32 notify_on)
977 {
978         m_notify_on = notify_on;
979 }
980
981
982 void GenerateNotifier::setNotifyOnDecoIds(std::set<u32> *notify_on_deco_ids)
983 {
984         m_notify_on_deco_ids = notify_on_deco_ids;
985 }
986
987
988 bool GenerateNotifier::addEvent(GenNotifyType type, v3s16 pos, u32 id)
989 {
990         if (!(m_notify_on & (1 << type)))
991                 return false;
992
993         if (type == GENNOTIFY_DECORATION &&
994                 m_notify_on_deco_ids->find(id) == m_notify_on_deco_ids->end())
995                 return false;
996
997         GenNotifyEvent gne;
998         gne.type = type;
999         gne.pos  = pos;
1000         gne.id   = id;
1001         m_notify_events.push_back(gne);
1002
1003         return true;
1004 }
1005
1006
1007 void GenerateNotifier::getEvents(
1008         std::map<std::string, std::vector<v3s16> > &event_map,
1009         bool peek_events)
1010 {
1011         std::list<GenNotifyEvent>::iterator it;
1012
1013         for (it = m_notify_events.begin(); it != m_notify_events.end(); ++it) {
1014                 GenNotifyEvent &gn = *it;
1015                 std::string name = (gn.type == GENNOTIFY_DECORATION) ?
1016                         "decoration#"+ itos(gn.id) :
1017                         flagdesc_gennotify[gn.type].name;
1018
1019                 event_map[name].push_back(gn.pos);
1020         }
1021
1022         if (!peek_events)
1023                 m_notify_events.clear();
1024 }
1025
1026
1027 ////
1028 //// MapgenParams
1029 ////
1030
1031
1032 MapgenParams::~MapgenParams()
1033 {
1034         delete bparams;
1035 }
1036
1037
1038 void MapgenParams::readParams(const Settings *settings)
1039 {
1040         std::string seed_str;
1041         const char *seed_name = (settings == g_settings) ? "fixed_map_seed" : "seed";
1042
1043         if (settings->getNoEx(seed_name, seed_str)) {
1044                 if (!seed_str.empty())
1045                         seed = read_seed(seed_str.c_str());
1046                 else
1047                         myrand_bytes(&seed, sizeof(seed));
1048         }
1049
1050         std::string mg_name;
1051         if (settings->getNoEx("mg_name", mg_name)) {
1052                 mgtype = Mapgen::getMapgenType(mg_name);
1053                 if (mgtype == MAPGEN_INVALID)
1054                         mgtype = MAPGEN_DEFAULT;
1055         }
1056
1057         settings->getS16NoEx("water_level", water_level);
1058         settings->getS16NoEx("mapgen_limit", mapgen_limit);
1059         settings->getS16NoEx("chunksize", chunksize);
1060         settings->getFlagStrNoEx("mg_flags", flags, flagdesc_mapgen);
1061
1062         delete bparams;
1063         bparams = BiomeManager::createBiomeParams(BIOMEGEN_ORIGINAL);
1064         if (bparams) {
1065                 bparams->readParams(settings);
1066                 bparams->seed = seed;
1067         }
1068 }
1069
1070
1071 void MapgenParams::writeParams(Settings *settings) const
1072 {
1073         settings->set("mg_name", Mapgen::getMapgenName(mgtype));
1074         settings->setU64("seed", seed);
1075         settings->setS16("water_level", water_level);
1076         settings->setS16("mapgen_limit", mapgen_limit);
1077         settings->setS16("chunksize", chunksize);
1078         settings->setFlagStr("mg_flags", flags, flagdesc_mapgen, U32_MAX);
1079
1080         if (bparams)
1081                 bparams->writeParams(settings);
1082 }
1083
1084 // Calculate edges of outermost generated mapchunks (less than
1085 // 'mapgen_limit'), and corresponding exact limits for SAO entities.
1086 void MapgenParams::calcMapgenEdges()
1087 {
1088         if (m_mapgen_edges_calculated)
1089                 return;
1090
1091         // Central chunk offset, in blocks
1092         s16 ccoff_b = -chunksize / 2;
1093         // Chunksize, in nodes
1094         s32 csize_n = chunksize * MAP_BLOCKSIZE;
1095         // Minp/maxp of central chunk, in nodes
1096         s16 ccmin = ccoff_b * MAP_BLOCKSIZE;
1097         s16 ccmax = ccmin + csize_n - 1;
1098         // Fullminp/fullmaxp of central chunk, in nodes
1099         s16 ccfmin = ccmin - MAP_BLOCKSIZE;
1100         s16 ccfmax = ccmax + MAP_BLOCKSIZE;
1101         // Effective mapgen limit, in blocks
1102         // Uses same calculation as ServerMap::blockpos_over_mapgen_limit(v3s16 p)
1103         s16 mapgen_limit_b = rangelim(mapgen_limit,
1104                 0, MAX_MAP_GENERATION_LIMIT) / MAP_BLOCKSIZE;
1105         // Effective mapgen limits, in nodes
1106         s16 mapgen_limit_min = -mapgen_limit_b * MAP_BLOCKSIZE;
1107         s16 mapgen_limit_max = (mapgen_limit_b + 1) * MAP_BLOCKSIZE - 1;
1108         // Number of complete chunks from central chunk fullminp/fullmaxp
1109         // to effective mapgen limits.
1110         s16 numcmin = MYMAX((ccfmin - mapgen_limit_min) / csize_n, 0);
1111         s16 numcmax = MYMAX((mapgen_limit_max - ccfmax) / csize_n, 0);
1112         // Mapgen edges, in nodes
1113         mapgen_edge_min = ccmin - numcmin * csize_n;
1114         mapgen_edge_max = ccmax + numcmax * csize_n;
1115         // SAO position limits, in Irrlicht units
1116         m_sao_limit_min = mapgen_edge_min * BS - 3.0f;
1117         m_sao_limit_max = mapgen_edge_max * BS + 3.0f;
1118
1119         m_mapgen_edges_calculated = true;
1120 }
1121
1122
1123 bool MapgenParams::saoPosOverLimit(const v3f &p)
1124 {
1125         if (!m_mapgen_edges_calculated)
1126                 calcMapgenEdges();
1127
1128         return p.X < m_sao_limit_min ||
1129                 p.X > m_sao_limit_max ||
1130                 p.Y < m_sao_limit_min ||
1131                 p.Y > m_sao_limit_max ||
1132                 p.Z < m_sao_limit_min ||
1133                 p.Z > m_sao_limit_max;
1134 }
1135
1136
1137 s32 MapgenParams::getSpawnRangeMax()
1138 {
1139         calcMapgenEdges();
1140
1141         return MYMIN(-mapgen_edge_min, mapgen_edge_max);
1142 }