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
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.
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.
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.
31 #include "content_sao.h"
34 #include "voxelalgorithms.h"
39 #include "serialization.h"
40 #include "util/serialize.h"
41 #include "util/numeric.h"
42 #include "util/directiontables.h"
45 #include "mapgen_carpathian.h"
46 #include "mapgen_flat.h"
47 #include "mapgen_fractal.h"
48 #include "mapgen_v5.h"
49 #include "mapgen_v6.h"
50 #include "mapgen_v7.h"
51 #include "mapgen_valleys.h"
52 #include "mapgen_singlenode.h"
54 #include "dungeongen.h"
56 FlagDesc flagdesc_mapgen[] = {
58 {"dungeons", MG_DUNGEONS},
60 {"decorations", MG_DECORATIONS},
61 {"biomes", MG_BIOMES},
65 FlagDesc flagdesc_gennotify[] = {
66 {"dungeon", 1 << GENNOTIFY_DUNGEON},
67 {"temple", 1 << GENNOTIFY_TEMPLE},
68 {"cave_begin", 1 << GENNOTIFY_CAVE_BEGIN},
69 {"cave_end", 1 << GENNOTIFY_CAVE_END},
70 {"large_cave_begin", 1 << GENNOTIFY_LARGECAVE_BEGIN},
71 {"large_cave_end", 1 << GENNOTIFY_LARGECAVE_END},
72 {"decoration", 1 << GENNOTIFY_DECORATION},
85 // Order used here defines the order of appearence in mainmenu.
86 // v6 always last to discourage selection.
87 // Special mapgens flat, fractal, singlenode, next to last. Of these, singlenode
88 // last to discourage selection.
89 // Of the remaining, v5 last due to age, v7 first due to being the default.
90 // The order of 'enum MapgenType' in mapgen.h must match this order.
91 static MapgenDesc g_reg_mapgens[] = {
103 ARRLEN(g_reg_mapgens) == MAPGEN_INVALID,
104 registered_mapgens_is_wrong_size);
110 Mapgen::Mapgen(int mapgenid, MapgenParams *params, EmergeManager *emerge) :
111 gennotify(emerge->gen_notify_on, &emerge->gen_notify_on_deco_ids)
114 water_level = params->water_level;
115 mapgen_limit = params->mapgen_limit;
116 flags = params->flags;
117 csize = v3s16(1, 1, 1) * (params->chunksize * MAP_BLOCKSIZE);
120 We are losing half our entropy by doing this, but it is necessary to
121 preserve reverse compatibility. If the top half of our current 64 bit
122 seeds ever starts getting used, existing worlds will break due to a
123 different hash outcome and no way to differentiate between versions.
125 A solution could be to add a new bit to designate that the top half of
126 the seed value should be used, essentially a 1-bit version code, but
127 this would require increasing the total size of a seed to 9 bytes (yuck)
129 It's probably okay if this never gets fixed. 4.2 billion possibilities
130 ought to be enough for anyone.
132 seed = (s32)params->seed;
138 MapgenType Mapgen::getMapgenType(const std::string &mgname)
140 for (size_t i = 0; i != ARRLEN(g_reg_mapgens); i++) {
141 if (mgname == g_reg_mapgens[i].name)
142 return (MapgenType)i;
145 return MAPGEN_INVALID;
149 const char *Mapgen::getMapgenName(MapgenType mgtype)
151 size_t index = (size_t)mgtype;
152 if (index == MAPGEN_INVALID || index >= ARRLEN(g_reg_mapgens))
155 return g_reg_mapgens[index].name;
159 Mapgen *Mapgen::createMapgen(MapgenType mgtype, MapgenParams *params,
160 EmergeManager *emerge)
163 case MAPGEN_CARPATHIAN:
164 return new MapgenCarpathian((MapgenCarpathianParams *)params, emerge);
166 return new MapgenFlat((MapgenFlatParams *)params, emerge);
168 return new MapgenFractal((MapgenFractalParams *)params, emerge);
169 case MAPGEN_SINGLENODE:
170 return new MapgenSinglenode((MapgenSinglenodeParams *)params, emerge);
172 return new MapgenV5((MapgenV5Params *)params, emerge);
174 return new MapgenV6((MapgenV6Params *)params, emerge);
176 return new MapgenV7((MapgenV7Params *)params, emerge);
178 return new MapgenValleys((MapgenValleysParams *)params, emerge);
185 MapgenParams *Mapgen::createMapgenParams(MapgenType mgtype)
188 case MAPGEN_CARPATHIAN:
189 return new MapgenCarpathianParams;
191 return new MapgenFlatParams;
193 return new MapgenFractalParams;
194 case MAPGEN_SINGLENODE:
195 return new MapgenSinglenodeParams;
197 return new MapgenV5Params;
199 return new MapgenV6Params;
201 return new MapgenV7Params;
203 return new MapgenValleysParams;
210 void Mapgen::getMapgenNames(std::vector<const char *> *mgnames, bool include_hidden)
212 for (u32 i = 0; i != ARRLEN(g_reg_mapgens); i++) {
213 if (include_hidden || g_reg_mapgens[i].is_user_visible)
214 mgnames->push_back(g_reg_mapgens[i].name);
219 u32 Mapgen::getBlockSeed(v3s16 p, s32 seed)
228 u32 Mapgen::getBlockSeed2(v3s16 p, s32 seed)
230 u32 n = 1619 * p.X + 31337 * p.Y + 52591 * p.Z + 1013 * seed;
232 return (n * (n * n * 60493 + 19990303) + 1376312589);
236 // Returns Y one under area minimum if not found
237 s16 Mapgen::findGroundLevelFull(v2s16 p2d)
239 const v3s16 &em = vm->m_area.getExtent();
240 s16 y_nodes_max = vm->m_area.MaxEdge.Y;
241 s16 y_nodes_min = vm->m_area.MinEdge.Y;
242 u32 i = vm->m_area.index(p2d.X, y_nodes_max, p2d.Y);
245 for (y = y_nodes_max; y >= y_nodes_min; y--) {
246 MapNode &n = vm->m_data[i];
247 if (ndef->get(n).walkable)
250 VoxelArea::add_y(em, i, -1);
252 return (y >= y_nodes_min) ? y : y_nodes_min - 1;
256 // Returns -MAX_MAP_GENERATION_LIMIT if not found
257 s16 Mapgen::findGroundLevel(v2s16 p2d, s16 ymin, s16 ymax)
259 const v3s16 &em = vm->m_area.getExtent();
260 u32 i = vm->m_area.index(p2d.X, ymax, p2d.Y);
263 for (y = ymax; y >= ymin; y--) {
264 MapNode &n = vm->m_data[i];
265 if (ndef->get(n).walkable)
268 VoxelArea::add_y(em, i, -1);
270 return (y >= ymin) ? y : -MAX_MAP_GENERATION_LIMIT;
274 // Returns -MAX_MAP_GENERATION_LIMIT if not found or if ground is found first
275 s16 Mapgen::findLiquidSurface(v2s16 p2d, s16 ymin, s16 ymax)
277 const v3s16 &em = vm->m_area.getExtent();
278 u32 i = vm->m_area.index(p2d.X, ymax, p2d.Y);
281 for (y = ymax; y >= ymin; y--) {
282 MapNode &n = vm->m_data[i];
283 if (ndef->get(n).walkable)
284 return -MAX_MAP_GENERATION_LIMIT;
286 if (ndef->get(n).isLiquid())
289 VoxelArea::add_y(em, i, -1);
291 return (y >= ymin) ? y : -MAX_MAP_GENERATION_LIMIT;
295 void Mapgen::updateHeightmap(v3s16 nmin, v3s16 nmax)
300 //TimeTaker t("Mapgen::updateHeightmap", NULL, PRECISION_MICRO);
302 for (s16 z = nmin.Z; z <= nmax.Z; z++) {
303 for (s16 x = nmin.X; x <= nmax.X; x++, index++) {
304 s16 y = findGroundLevel(v2s16(x, z), nmin.Y, nmax.Y);
306 heightmap[index] = y;
312 void Mapgen::getSurfaces(v2s16 p2d, s16 ymin, s16 ymax,
313 std::vector<s16> &floors, std::vector<s16> &ceilings)
315 const v3s16 &em = vm->m_area.getExtent();
317 bool is_walkable = false;
318 u32 vi = vm->m_area.index(p2d.X, ymax, p2d.Y);
319 MapNode mn_max = vm->m_data[vi];
320 bool walkable_above = ndef->get(mn_max).walkable;
321 VoxelArea::add_y(em, vi, -1);
323 for (s16 y = ymax - 1; y >= ymin; y--) {
324 MapNode mn = vm->m_data[vi];
325 is_walkable = ndef->get(mn).walkable;
327 if (is_walkable && !walkable_above) {
329 } else if (!is_walkable && walkable_above) {
330 ceilings.push_back(y + 1);
333 VoxelArea::add_y(em, vi, -1);
334 walkable_above = is_walkable;
339 inline bool Mapgen::isLiquidHorizontallyFlowable(u32 vi, v3s16 em)
342 VoxelArea::add_x(em, vi_neg_x, -1);
343 if (vm->m_data[vi_neg_x].getContent() != CONTENT_IGNORE) {
344 const ContentFeatures &c_nx = ndef->get(vm->m_data[vi_neg_x]);
345 if (c_nx.floodable && !c_nx.isLiquid())
349 VoxelArea::add_x(em, vi_pos_x, +1);
350 if (vm->m_data[vi_pos_x].getContent() != CONTENT_IGNORE) {
351 const ContentFeatures &c_px = ndef->get(vm->m_data[vi_pos_x]);
352 if (c_px.floodable && !c_px.isLiquid())
356 VoxelArea::add_z(em, vi_neg_z, -1);
357 if (vm->m_data[vi_neg_z].getContent() != CONTENT_IGNORE) {
358 const ContentFeatures &c_nz = ndef->get(vm->m_data[vi_neg_z]);
359 if (c_nz.floodable && !c_nz.isLiquid())
363 VoxelArea::add_z(em, vi_pos_z, +1);
364 if (vm->m_data[vi_pos_z].getContent() != CONTENT_IGNORE) {
365 const ContentFeatures &c_pz = ndef->get(vm->m_data[vi_pos_z]);
366 if (c_pz.floodable && !c_pz.isLiquid())
372 void Mapgen::updateLiquid(UniqueQueue<v3s16> *trans_liquid, v3s16 nmin, v3s16 nmax)
374 bool isignored, isliquid, wasignored, wasliquid, waschecked, waspushed;
375 const v3s16 &em = vm->m_area.getExtent();
377 for (s16 z = nmin.Z + 1; z <= nmax.Z - 1; z++)
378 for (s16 x = nmin.X + 1; x <= nmax.X - 1; x++) {
384 u32 vi = vm->m_area.index(x, nmax.Y, z);
385 for (s16 y = nmax.Y; y >= nmin.Y; y--) {
386 isignored = vm->m_data[vi].getContent() == CONTENT_IGNORE;
387 isliquid = ndef->get(vm->m_data[vi]).isLiquid();
389 if (isignored || wasignored || isliquid == wasliquid) {
390 // Neither topmost node of liquid column nor topmost node below column
393 } else if (isliquid) {
394 // This is the topmost node in the column
395 bool ispushed = false;
396 if (isLiquidHorizontallyFlowable(vi, em)) {
397 trans_liquid->push_back(v3s16(x, y, z));
400 // Remember waschecked and waspushed to avoid repeated
401 // checks/pushes in case the column consists of only this node
403 waspushed = ispushed;
405 // This is the topmost node below a liquid column
407 VoxelArea::add_y(em, vi_above, 1);
408 if (!waspushed && (ndef->get(vm->m_data[vi]).floodable ||
409 (!waschecked && isLiquidHorizontallyFlowable(vi_above, em)))) {
410 // Push back the lowest node in the column which is one
411 // node above this one
412 trans_liquid->push_back(v3s16(x, y + 1, z));
416 wasliquid = isliquid;
417 wasignored = isignored;
418 VoxelArea::add_y(em, vi, -1);
424 void Mapgen::setLighting(u8 light, v3s16 nmin, v3s16 nmax)
426 ScopeProfiler sp(g_profiler, "EmergeThread: update lighting", SPT_AVG);
427 VoxelArea a(nmin, nmax);
429 for (int z = a.MinEdge.Z; z <= a.MaxEdge.Z; z++) {
430 for (int y = a.MinEdge.Y; y <= a.MaxEdge.Y; y++) {
431 u32 i = vm->m_area.index(a.MinEdge.X, y, z);
432 for (int x = a.MinEdge.X; x <= a.MaxEdge.X; x++, i++)
433 vm->m_data[i].param1 = light;
439 void Mapgen::lightSpread(VoxelArea &a, std::queue<std::pair<v3s16, u8>> &queue,
440 const v3s16 &p, u8 light)
442 if (light <= 1 || !a.contains(p))
445 u32 vi = vm->m_area.index(p);
446 MapNode &n = vm->m_data[vi];
448 // Decay light in each of the banks separately
449 u8 light_day = light & 0x0F;
453 u8 light_night = light & 0xF0;
457 // Bail out only if we have no more light from either bank to propogate, or
458 // we hit a solid block that light cannot pass through.
459 if ((light_day <= (n.param1 & 0x0F) &&
460 light_night <= (n.param1 & 0xF0)) ||
461 !ndef->get(n).light_propagates)
464 // Since this recursive function only terminates when there is no light from
465 // either bank left, we need to take the max of both banks into account for
466 // the case where spreading has stopped for one light bank but not the other.
467 light = MYMAX(light_day, n.param1 & 0x0F) |
468 MYMAX(light_night, n.param1 & 0xF0);
473 queue.emplace(p, light);
477 void Mapgen::calcLighting(v3s16 nmin, v3s16 nmax, v3s16 full_nmin, v3s16 full_nmax,
478 bool propagate_shadow)
480 ScopeProfiler sp(g_profiler, "EmergeThread: update lighting", SPT_AVG);
481 //TimeTaker t("updateLighting");
483 propagateSunlight(nmin, nmax, propagate_shadow);
484 spreadLight(full_nmin, full_nmax);
486 //printf("updateLighting: %dms\n", t.stop());
490 void Mapgen::propagateSunlight(v3s16 nmin, v3s16 nmax, bool propagate_shadow)
492 //TimeTaker t("propagateSunlight");
493 VoxelArea a(nmin, nmax);
494 bool block_is_underground = (water_level >= nmax.Y);
495 const v3s16 &em = vm->m_area.getExtent();
497 // NOTE: Direct access to the low 4 bits of param1 is okay here because,
498 // by definition, sunlight will never be in the night lightbank.
500 for (int z = a.MinEdge.Z; z <= a.MaxEdge.Z; z++) {
501 for (int x = a.MinEdge.X; x <= a.MaxEdge.X; x++) {
502 // see if we can get a light value from the overtop
503 u32 i = vm->m_area.index(x, a.MaxEdge.Y + 1, z);
504 if (vm->m_data[i].getContent() == CONTENT_IGNORE) {
505 if (block_is_underground)
507 } else if ((vm->m_data[i].param1 & 0x0F) != LIGHT_SUN &&
511 VoxelArea::add_y(em, i, -1);
513 for (int y = a.MaxEdge.Y; y >= a.MinEdge.Y; y--) {
514 MapNode &n = vm->m_data[i];
515 if (!ndef->get(n).sunlight_propagates)
517 n.param1 = LIGHT_SUN;
518 VoxelArea::add_y(em, i, -1);
522 //printf("propagateSunlight: %dms\n", t.stop());
526 void Mapgen::spreadLight(const v3s16 &nmin, const v3s16 &nmax)
528 //TimeTaker t("spreadLight");
529 std::queue<std::pair<v3s16, u8>> queue;
530 VoxelArea a(nmin, nmax);
532 for (int z = a.MinEdge.Z; z <= a.MaxEdge.Z; z++) {
533 for (int y = a.MinEdge.Y; y <= a.MaxEdge.Y; y++) {
534 u32 i = vm->m_area.index(a.MinEdge.X, y, z);
535 for (int x = a.MinEdge.X; x <= a.MaxEdge.X; x++, i++) {
536 MapNode &n = vm->m_data[i];
537 if (n.getContent() == CONTENT_IGNORE)
540 const ContentFeatures &cf = ndef->get(n);
541 if (!cf.light_propagates)
544 // TODO(hmmmmm): Abstract away direct param1 accesses with a
545 // wrapper, but something lighter than MapNode::get/setLight
547 u8 light_produced = cf.light_source;
549 n.param1 = light_produced | (light_produced << 4);
553 const v3s16 p(x, y, z);
554 // spread to all 6 neighbor nodes
555 for (const auto &dir : g_6dirs)
556 lightSpread(a, queue, p + dir, light);
562 while (!queue.empty()) {
563 const auto &i = queue.front();
564 // spread to all 6 neighbor nodes
565 for (const auto &dir : g_6dirs)
566 lightSpread(a, queue, i.first + dir, i.second);
570 //printf("spreadLight: %lums\n", t.stop());
578 MapgenBasic::MapgenBasic(int mapgenid, MapgenParams *params, EmergeManager *emerge)
579 : Mapgen(mapgenid, params, emerge)
581 this->m_emerge = emerge;
582 this->m_bmgr = emerge->biomemgr;
584 //// Here, 'stride' refers to the number of elements needed to skip to index
585 //// an adjacent element for that coordinate in noise/height/biome maps
586 //// (*not* vmanip content map!)
588 // Note there is no X stride explicitly defined. Items adjacent in the X
589 // coordinate are assumed to be adjacent in memory as well (i.e. stride of 1).
591 // Number of elements to skip to get to the next Y coordinate
592 this->ystride = csize.X;
594 // Number of elements to skip to get to the next Z coordinate
595 this->zstride = csize.X * csize.Y;
597 // Z-stride value for maps oversized for 1-down overgeneration
598 this->zstride_1d = csize.X * (csize.Y + 1);
600 // Z-stride value for maps oversized for 1-up 1-down overgeneration
601 this->zstride_1u1d = csize.X * (csize.Y + 2);
603 //// Allocate heightmap
604 this->heightmap = new s16[csize.X * csize.Z];
606 //// Initialize biome generator
607 biomegen = m_bmgr->createBiomeGen(BIOMEGEN_ORIGINAL, params->bparams, csize);
608 biomemap = biomegen->biomemap;
610 //// Look up some commonly used content
611 c_stone = ndef->getId("mapgen_stone");
612 c_water_source = ndef->getId("mapgen_water_source");
613 c_river_water_source = ndef->getId("mapgen_river_water_source");
614 c_lava_source = ndef->getId("mapgen_lava_source");
615 c_cobble = ndef->getId("mapgen_cobble");
617 // Fall back to more basic content if not defined.
618 // Lava falls back to water as both are suitable as cave liquids.
619 if (c_lava_source == CONTENT_IGNORE)
620 c_lava_source = c_water_source;
624 MapgenBasic::~MapgenBasic()
631 void MapgenBasic::generateBiomes()
633 // can't generate biomes without a biome generator!
637 const v3s16 &em = vm->m_area.getExtent();
640 noise_filler_depth->perlinMap2D(node_min.X, node_min.Z);
642 for (s16 z = node_min.Z; z <= node_max.Z; z++)
643 for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
645 biome_t water_biome_index = 0;
648 u16 depth_water_top = 0;
649 u16 depth_riverbed = 0;
650 s16 biome_y_min = -MAX_MAP_GENERATION_LIMIT;
651 u32 vi = vm->m_area.index(x, node_max.Y, z);
653 // Check node at base of mapchunk above, either a node of a previously
654 // generated mapchunk or if not, a node of overgenerated base terrain.
655 content_t c_above = vm->m_data[vi + em.X].getContent();
656 bool air_above = c_above == CONTENT_AIR;
657 bool river_water_above = c_above == c_river_water_source;
658 bool water_above = c_above == c_water_source || river_water_above;
660 biomemap[index] = BIOME_NONE;
662 // If there is air or water above enable top/filler placement, otherwise force
663 // nplaced to stone level by setting a number exceeding any possible filler depth.
664 u16 nplaced = (air_above || water_above) ? 0 : U16_MAX;
666 for (s16 y = node_max.Y; y >= node_min.Y; y--) {
667 content_t c = vm->m_data[vi].getContent();
668 // Biome is (re)calculated:
669 // 1. At the surface of stone below air or water.
670 // 2. At the surface of water below air.
671 // 3. When stone or water is detected but biome has not yet been calculated.
672 // 4. When stone or water is detected just below a biome's lower limit.
673 bool is_stone_surface = (c == c_stone) &&
674 (air_above || water_above || !biome || y < biome_y_min); // 1, 3, 4
676 bool is_water_surface =
677 (c == c_water_source || c == c_river_water_source) &&
678 (air_above || !biome || y < biome_y_min); // 2, 3, 4
680 if (is_stone_surface || is_water_surface) {
681 // (Re)calculate biome
682 biome = biomegen->getBiomeAtIndex(index, v3s16(x, y, z));
684 // Add biome to biomemap at first stone surface detected
685 if (biomemap[index] == BIOME_NONE && is_stone_surface)
686 biomemap[index] = biome->index;
688 // Store biome of first water surface detected, as a fallback
689 // entry for the biomemap.
690 if (water_biome_index == 0 && is_water_surface)
691 water_biome_index = biome->index;
693 depth_top = biome->depth_top;
694 base_filler = MYMAX(depth_top +
695 biome->depth_filler +
696 noise_filler_depth->result[index], 0.0f);
697 depth_water_top = biome->depth_water_top;
698 depth_riverbed = biome->depth_riverbed;
699 biome_y_min = biome->min_pos.Y;
703 content_t c_below = vm->m_data[vi - em.X].getContent();
705 // If the node below isn't solid, make this node stone, so that
706 // any top/filler nodes above are structurally supported.
707 // This is done by aborting the cycle of top/filler placement
708 // immediately by forcing nplaced to stone level.
709 if (c_below == CONTENT_AIR
710 || c_below == c_water_source
711 || c_below == c_river_water_source)
714 if (river_water_above) {
715 if (nplaced < depth_riverbed) {
716 vm->m_data[vi] = MapNode(biome->c_riverbed);
719 nplaced = U16_MAX; // Disable top/filler placement
720 river_water_above = false;
722 } else if (nplaced < depth_top) {
723 vm->m_data[vi] = MapNode(biome->c_top);
725 } else if (nplaced < base_filler) {
726 vm->m_data[vi] = MapNode(biome->c_filler);
729 vm->m_data[vi] = MapNode(biome->c_stone);
730 nplaced = U16_MAX; // Disable top/filler placement
735 } else if (c == c_water_source) {
736 vm->m_data[vi] = MapNode((y > (s32)(water_level - depth_water_top))
737 ? biome->c_water_top : biome->c_water);
738 nplaced = 0; // Enable top/filler placement for next surface
741 } else if (c == c_river_water_source) {
742 vm->m_data[vi] = MapNode(biome->c_river_water);
743 nplaced = 0; // Enable riverbed placement for next surface
746 river_water_above = true;
747 } else if (c == CONTENT_AIR) {
748 nplaced = 0; // Enable top/filler placement for next surface
751 } else { // Possible various nodes overgenerated from neighbouring mapchunks
752 nplaced = U16_MAX; // Disable top/filler placement
757 VoxelArea::add_y(em, vi, -1);
759 // If no stone surface detected in mapchunk column and a water surface
760 // biome fallback exists, add it to the biomemap. This avoids water
761 // surface decorations failing in deep water.
762 if (biomemap[index] == BIOME_NONE && water_biome_index != 0)
763 biomemap[index] = water_biome_index;
768 void MapgenBasic::dustTopNodes()
770 if (node_max.Y < water_level)
773 const v3s16 &em = vm->m_area.getExtent();
776 for (s16 z = node_min.Z; z <= node_max.Z; z++)
777 for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
778 Biome *biome = (Biome *)m_bmgr->getRaw(biomemap[index]);
780 if (biome->c_dust == CONTENT_IGNORE)
783 // Check if mapchunk above has generated, if so, drop dust from 16 nodes
784 // above current mapchunk top, above decorations that will extend above
785 // the current mapchunk. If the mapchunk above has not generated, it
786 // will provide this required dust when it does.
787 u32 vi = vm->m_area.index(x, full_node_max.Y, z);
788 content_t c_full_max = vm->m_data[vi].getContent();
791 if (c_full_max == CONTENT_AIR) {
792 y_start = full_node_max.Y - 1;
793 } else if (c_full_max == CONTENT_IGNORE) {
794 vi = vm->m_area.index(x, node_max.Y + 1, z);
795 content_t c_max = vm->m_data[vi].getContent();
797 if (c_max == CONTENT_AIR)
798 y_start = node_max.Y;
805 vi = vm->m_area.index(x, y_start, z);
806 for (s16 y = y_start; y >= node_min.Y - 1; y--) {
807 if (vm->m_data[vi].getContent() != CONTENT_AIR)
810 VoxelArea::add_y(em, vi, -1);
813 content_t c = vm->m_data[vi].getContent();
814 NodeDrawType dtype = ndef->get(c).drawtype;
815 // Only place on cubic, walkable, non-dust nodes.
816 // Dust check needed due to avoid double layer of dust caused by
817 // dropping dust from 16 nodes above mapchunk top.
818 if ((dtype == NDT_NORMAL ||
819 dtype == NDT_ALLFACES ||
820 dtype == NDT_ALLFACES_OPTIONAL ||
821 dtype == NDT_GLASSLIKE ||
822 dtype == NDT_GLASSLIKE_FRAMED ||
823 dtype == NDT_GLASSLIKE_FRAMED_OPTIONAL) &&
824 ndef->get(c).walkable && c != biome->c_dust) {
825 VoxelArea::add_y(em, vi, 1);
826 vm->m_data[vi] = MapNode(biome->c_dust);
832 void MapgenBasic::generateCavesNoiseIntersection(s16 max_stone_y)
834 // cave_width >= 10 is used to disable generation and avoid the intensive
835 // 3D noise calculations. Tunnels already have zero width when cave_width > 1.
836 if (node_min.Y > max_stone_y || cave_width >= 10.0f)
839 CavesNoiseIntersection caves_noise(ndef, m_bmgr, csize,
840 &np_cave1, &np_cave2, seed, cave_width);
842 caves_noise.generateCaves(vm, node_min, node_max, biomemap);
846 void MapgenBasic::generateCavesRandomWalk(s16 max_stone_y, s16 large_cave_ymax)
848 if (node_min.Y > max_stone_y)
851 PseudoRandom ps(blockseed + 21343);
852 // Small randomwalk caves
853 u32 num_small_caves = ps.range(small_cave_num_min, small_cave_num_max);
855 for (u32 i = 0; i < num_small_caves; i++) {
856 CavesRandomWalk cave(ndef, &gennotify, seed, water_level,
857 c_water_source, c_lava_source, large_cave_flooded, biomegen);
858 cave.makeCave(vm, node_min, node_max, &ps, false, max_stone_y, heightmap);
861 if (node_max.Y > large_cave_ymax)
864 // Large randomwalk caves below 'large_cave_ymax'.
865 // 'large_cave_ymax' can differ from the 'large_cave_depth' mapgen parameter,
866 // it is set to world base to disable large caves in or near caverns.
867 u32 num_large_caves = ps.range(large_cave_num_min, large_cave_num_max);
869 for (u32 i = 0; i < num_large_caves; i++) {
870 CavesRandomWalk cave(ndef, &gennotify, seed, water_level,
871 c_water_source, c_lava_source, large_cave_flooded, biomegen);
872 cave.makeCave(vm, node_min, node_max, &ps, true, max_stone_y, heightmap);
877 bool MapgenBasic::generateCavernsNoise(s16 max_stone_y)
879 if (node_min.Y > max_stone_y || node_min.Y > cavern_limit)
882 CavernsNoise caverns_noise(ndef, csize, &np_cavern,
883 seed, cavern_limit, cavern_taper, cavern_threshold);
885 return caverns_noise.generateCaverns(vm, node_min, node_max);
889 void MapgenBasic::generateDungeons(s16 max_stone_y)
891 if (node_min.Y > max_stone_y || node_min.Y > dungeon_ymax ||
892 node_max.Y < dungeon_ymin)
895 u16 num_dungeons = std::fmax(std::floor(
896 NoisePerlin3D(&np_dungeons, node_min.X, node_min.Y, node_min.Z, seed)), 0.0f);
897 if (num_dungeons == 0)
900 PseudoRandom ps(blockseed + 70033);
905 NoiseParams(-0.4, 1.0, v3f(40.0, 40.0, 40.0), 32474, 6, 1.1, 2.0);
908 dp.only_in_ground = true;
909 dp.num_dungeons = num_dungeons;
910 dp.notifytype = GENNOTIFY_DUNGEON;
911 dp.num_rooms = ps.range(2, 16);
912 dp.room_size_min = v3s16(5, 5, 5);
913 dp.room_size_max = v3s16(12, 6, 12);
914 dp.room_size_large_min = v3s16(12, 6, 12);
915 dp.room_size_large_max = v3s16(16, 16, 16);
916 dp.large_room_chance = (ps.range(1, 4) == 1) ? 8 : 0;
917 dp.diagonal_dirs = ps.range(1, 8) == 1;
918 // Diagonal corridors must have 'hole' width >=2 to be passable
919 u8 holewidth = (dp.diagonal_dirs) ? 2 : ps.range(1, 2);
920 dp.holesize = v3s16(holewidth, 3, holewidth);
921 dp.corridor_len_min = 1;
922 dp.corridor_len_max = 13;
924 // Get biome at mapchunk midpoint
925 v3s16 chunk_mid = node_min + (node_max - node_min) / v3s16(2, 2, 2);
926 Biome *biome = (Biome *)biomegen->getBiomeAtPoint(chunk_mid);
928 // Use biome-defined dungeon nodes if defined
929 if (biome->c_dungeon != CONTENT_IGNORE) {
930 dp.c_wall = biome->c_dungeon;
931 // If 'node_dungeon_alt' is not defined by biome, it and dp.c_alt_wall
932 // become CONTENT_IGNORE which skips the alt wall node placement loop in
934 dp.c_alt_wall = biome->c_dungeon_alt;
935 // Stairs fall back to 'c_dungeon' if not defined by biome
936 dp.c_stair = (biome->c_dungeon_stair != CONTENT_IGNORE) ?
937 biome->c_dungeon_stair : biome->c_dungeon;
938 // Fallback to using cobble mapgen alias if defined
939 } else if (c_cobble != CONTENT_IGNORE) {
940 dp.c_wall = c_cobble;
941 dp.c_alt_wall = CONTENT_IGNORE;
942 dp.c_stair = c_cobble;
943 // Fallback to using biome-defined stone
945 dp.c_wall = biome->c_stone;
946 dp.c_alt_wall = CONTENT_IGNORE;
947 dp.c_stair = biome->c_stone;
950 DungeonGen dgen(ndef, &gennotify, &dp);
951 dgen.generate(vm, blockseed, full_node_min, full_node_max);
956 //// GenerateNotifier
959 GenerateNotifier::GenerateNotifier(u32 notify_on,
960 std::set<u32> *notify_on_deco_ids)
962 m_notify_on = notify_on;
963 m_notify_on_deco_ids = notify_on_deco_ids;
967 void GenerateNotifier::setNotifyOn(u32 notify_on)
969 m_notify_on = notify_on;
973 void GenerateNotifier::setNotifyOnDecoIds(std::set<u32> *notify_on_deco_ids)
975 m_notify_on_deco_ids = notify_on_deco_ids;
979 bool GenerateNotifier::addEvent(GenNotifyType type, v3s16 pos, u32 id)
981 if (!(m_notify_on & (1 << type)))
984 if (type == GENNOTIFY_DECORATION &&
985 m_notify_on_deco_ids->find(id) == m_notify_on_deco_ids->end())
992 m_notify_events.push_back(gne);
998 void GenerateNotifier::getEvents(
999 std::map<std::string, std::vector<v3s16> > &event_map)
1001 std::list<GenNotifyEvent>::iterator it;
1003 for (it = m_notify_events.begin(); it != m_notify_events.end(); ++it) {
1004 GenNotifyEvent &gn = *it;
1005 std::string name = (gn.type == GENNOTIFY_DECORATION) ?
1006 "decoration#"+ itos(gn.id) :
1007 flagdesc_gennotify[gn.type].name;
1009 event_map[name].push_back(gn.pos);
1014 void GenerateNotifier::clearEvents()
1016 m_notify_events.clear();
1025 MapgenParams::~MapgenParams()
1031 void MapgenParams::readParams(const Settings *settings)
1033 std::string seed_str;
1034 const char *seed_name = (settings == g_settings) ? "fixed_map_seed" : "seed";
1036 if (settings->getNoEx(seed_name, seed_str)) {
1037 if (!seed_str.empty())
1038 seed = read_seed(seed_str.c_str());
1040 myrand_bytes(&seed, sizeof(seed));
1043 std::string mg_name;
1044 if (settings->getNoEx("mg_name", mg_name)) {
1045 mgtype = Mapgen::getMapgenType(mg_name);
1046 if (mgtype == MAPGEN_INVALID)
1047 mgtype = MAPGEN_DEFAULT;
1050 settings->getS16NoEx("water_level", water_level);
1051 settings->getS16NoEx("mapgen_limit", mapgen_limit);
1052 settings->getS16NoEx("chunksize", chunksize);
1053 settings->getFlagStrNoEx("mg_flags", flags, flagdesc_mapgen);
1056 bparams = BiomeManager::createBiomeParams(BIOMEGEN_ORIGINAL);
1058 bparams->readParams(settings);
1059 bparams->seed = seed;
1064 void MapgenParams::writeParams(Settings *settings) const
1066 settings->set("mg_name", Mapgen::getMapgenName(mgtype));
1067 settings->setU64("seed", seed);
1068 settings->setS16("water_level", water_level);
1069 settings->setS16("mapgen_limit", mapgen_limit);
1070 settings->setS16("chunksize", chunksize);
1071 settings->setFlagStr("mg_flags", flags, flagdesc_mapgen, U32_MAX);
1074 bparams->writeParams(settings);
1078 // Calculate exact edges of the outermost mapchunks that are within the
1079 // set 'mapgen_limit'.
1080 void MapgenParams::calcMapgenEdges()
1082 // Central chunk offset, in blocks
1083 s16 ccoff_b = -chunksize / 2;
1084 // Chunksize, in nodes
1085 s32 csize_n = chunksize * MAP_BLOCKSIZE;
1086 // Minp/maxp of central chunk, in nodes
1087 s16 ccmin = ccoff_b * MAP_BLOCKSIZE;
1088 s16 ccmax = ccmin + csize_n - 1;
1089 // Fullminp/fullmaxp of central chunk, in nodes
1090 s16 ccfmin = ccmin - MAP_BLOCKSIZE;
1091 s16 ccfmax = ccmax + MAP_BLOCKSIZE;
1092 // Effective mapgen limit, in blocks
1093 // Uses same calculation as ServerMap::blockpos_over_mapgen_limit(v3s16 p)
1094 s16 mapgen_limit_b = rangelim(mapgen_limit,
1095 0, MAX_MAP_GENERATION_LIMIT) / MAP_BLOCKSIZE;
1096 // Effective mapgen limits, in nodes
1097 s16 mapgen_limit_min = -mapgen_limit_b * MAP_BLOCKSIZE;
1098 s16 mapgen_limit_max = (mapgen_limit_b + 1) * MAP_BLOCKSIZE - 1;
1099 // Number of complete chunks from central chunk fullminp/fullmaxp
1100 // to effective mapgen limits.
1101 s16 numcmin = MYMAX((ccfmin - mapgen_limit_min) / csize_n, 0);
1102 s16 numcmax = MYMAX((mapgen_limit_max - ccfmax) / csize_n, 0);
1103 // Mapgen edges, in nodes
1104 mapgen_edge_min = ccmin - numcmin * csize_n;
1105 mapgen_edge_max = ccmax + numcmax * csize_n;
1107 m_mapgen_edges_calculated = true;
1111 s32 MapgenParams::getSpawnRangeMax()
1113 if (!m_mapgen_edges_calculated)
1116 return MYMIN(-mapgen_edge_min, mapgen_edge_max);