3 Copyright (C) 2010-2015 celeron55, Perttu Ahola <celeron55@gmail.com>
4 Copyright (C) 2013-2016 kwolekr, Ryan Kwolek <kwolekr@minetest.net>
5 Copyright (C) 2015-2017 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.
30 #include "content_sao.h"
33 #include "voxelalgorithms.h"
38 #include "serialization.h"
39 #include "util/serialize.h"
40 #include "util/numeric.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"
52 #include "dungeongen.h"
54 FlagDesc flagdesc_mapgen[] = {
56 {"dungeons", MG_DUNGEONS},
58 {"decorations", MG_DECORATIONS},
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},
82 static MapgenDesc g_reg_mapgens[] = {
94 ARRLEN(g_reg_mapgens) == MAPGEN_INVALID,
95 registered_mapgens_is_wrong_size);
106 Mapgen::Mapgen(int mapgenid, MapgenParams *params, EmergeManager *emerge) :
107 gennotify(emerge->gen_notify_on, &emerge->gen_notify_on_deco_ids)
110 water_level = params->water_level;
111 mapgen_limit = params->mapgen_limit;
112 flags = params->flags;
113 csize = v3s16(1, 1, 1) * (params->chunksize * MAP_BLOCKSIZE);
116 We are losing half our entropy by doing this, but it is necessary to
117 preserve reverse compatibility. If the top half of our current 64 bit
118 seeds ever starts getting used, existing worlds will break due to a
119 different hash outcome and no way to differentiate between versions.
121 A solution could be to add a new bit to designate that the top half of
122 the seed value should be used, essentially a 1-bit version code, but
123 this would require increasing the total size of a seed to 9 bytes (yuck)
125 It's probably okay if this never gets fixed. 4.2 billion possibilities
126 ought to be enough for anyone.
128 seed = (s32)params->seed;
139 MapgenType Mapgen::getMapgenType(const std::string &mgname)
141 for (size_t i = 0; i != ARRLEN(g_reg_mapgens); i++) {
142 if (mgname == g_reg_mapgens[i].name)
143 return (MapgenType)i;
146 return MAPGEN_INVALID;
150 const char *Mapgen::getMapgenName(MapgenType mgtype)
152 size_t index = (size_t)mgtype;
153 if (index == MAPGEN_INVALID || index >= ARRLEN(g_reg_mapgens))
156 return g_reg_mapgens[index].name;
160 Mapgen *Mapgen::createMapgen(MapgenType mgtype, int mgid,
161 MapgenParams *params, EmergeManager *emerge)
164 case MAPGEN_CARPATHIAN:
165 return new MapgenCarpathian(mgid, (MapgenCarpathianParams *)params, emerge);
167 return new MapgenFlat(mgid, (MapgenFlatParams *)params, emerge);
169 return new MapgenFractal(mgid, (MapgenFractalParams *)params, emerge);
170 case MAPGEN_SINGLENODE:
171 return new MapgenSinglenode(mgid, (MapgenSinglenodeParams *)params, emerge);
173 return new MapgenV5(mgid, (MapgenV5Params *)params, emerge);
175 return new MapgenV6(mgid, (MapgenV6Params *)params, emerge);
177 return new MapgenV7(mgid, (MapgenV7Params *)params, emerge);
179 return new MapgenValleys(mgid, (MapgenValleysParams *)params, emerge);
186 MapgenParams *Mapgen::createMapgenParams(MapgenType mgtype)
189 case MAPGEN_CARPATHIAN:
190 return new MapgenCarpathianParams;
192 return new MapgenFlatParams;
194 return new MapgenFractalParams;
195 case MAPGEN_SINGLENODE:
196 return new MapgenSinglenodeParams;
198 return new MapgenV5Params;
200 return new MapgenV6Params;
202 return new MapgenV7Params;
204 return new MapgenValleysParams;
211 void Mapgen::getMapgenNames(std::vector<const char *> *mgnames, bool include_hidden)
213 for (u32 i = 0; i != ARRLEN(g_reg_mapgens); i++) {
214 if (include_hidden || g_reg_mapgens[i].is_user_visible)
215 mgnames->push_back(g_reg_mapgens[i].name);
220 u32 Mapgen::getBlockSeed(v3s16 p, s32 seed)
229 u32 Mapgen::getBlockSeed2(v3s16 p, s32 seed)
231 u32 n = 1619 * p.X + 31337 * p.Y + 52591 * p.Z + 1013 * seed;
233 return (n * (n * n * 60493 + 19990303) + 1376312589);
237 // Returns Y one under area minimum if not found
238 s16 Mapgen::findGroundLevelFull(v2s16 p2d)
240 const v3s16 &em = vm->m_area.getExtent();
241 s16 y_nodes_max = vm->m_area.MaxEdge.Y;
242 s16 y_nodes_min = vm->m_area.MinEdge.Y;
243 u32 i = vm->m_area.index(p2d.X, y_nodes_max, p2d.Y);
246 for (y = y_nodes_max; y >= y_nodes_min; y--) {
247 MapNode &n = vm->m_data[i];
248 if (ndef->get(n).walkable)
251 vm->m_area.add_y(em, i, -1);
253 return (y >= y_nodes_min) ? y : y_nodes_min - 1;
257 // Returns -MAX_MAP_GENERATION_LIMIT if not found
258 s16 Mapgen::findGroundLevel(v2s16 p2d, s16 ymin, s16 ymax)
260 const v3s16 &em = vm->m_area.getExtent();
261 u32 i = vm->m_area.index(p2d.X, ymax, p2d.Y);
264 for (y = ymax; y >= ymin; y--) {
265 MapNode &n = vm->m_data[i];
266 if (ndef->get(n).walkable)
269 vm->m_area.add_y(em, i, -1);
271 return (y >= ymin) ? y : -MAX_MAP_GENERATION_LIMIT;
275 // Returns -MAX_MAP_GENERATION_LIMIT if not found or if ground is found first
276 s16 Mapgen::findLiquidSurface(v2s16 p2d, s16 ymin, s16 ymax)
278 const v3s16 &em = vm->m_area.getExtent();
279 u32 i = vm->m_area.index(p2d.X, ymax, p2d.Y);
282 for (y = ymax; y >= ymin; y--) {
283 MapNode &n = vm->m_data[i];
284 if (ndef->get(n).walkable)
285 return -MAX_MAP_GENERATION_LIMIT;
286 else if (ndef->get(n).isLiquid())
289 vm->m_area.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;
311 inline bool Mapgen::isLiquidHorizontallyFlowable(u32 vi, v3s16 em)
314 vm->m_area.add_x(em, vi_neg_x, -1);
315 if (vm->m_data[vi_neg_x].getContent() != CONTENT_IGNORE) {
316 const ContentFeatures &c_nx = ndef->get(vm->m_data[vi_neg_x]);
317 if (c_nx.floodable && !c_nx.isLiquid())
321 vm->m_area.add_x(em, vi_pos_x, +1);
322 if (vm->m_data[vi_pos_x].getContent() != CONTENT_IGNORE) {
323 const ContentFeatures &c_px = ndef->get(vm->m_data[vi_pos_x]);
324 if (c_px.floodable && !c_px.isLiquid())
328 vm->m_area.add_z(em, vi_neg_z, -1);
329 if (vm->m_data[vi_neg_z].getContent() != CONTENT_IGNORE) {
330 const ContentFeatures &c_nz = ndef->get(vm->m_data[vi_neg_z]);
331 if (c_nz.floodable && !c_nz.isLiquid())
335 vm->m_area.add_z(em, vi_pos_z, +1);
336 if (vm->m_data[vi_pos_z].getContent() != CONTENT_IGNORE) {
337 const ContentFeatures &c_pz = ndef->get(vm->m_data[vi_pos_z]);
338 if (c_pz.floodable && !c_pz.isLiquid())
344 void Mapgen::updateLiquid(UniqueQueue<v3s16> *trans_liquid, v3s16 nmin, v3s16 nmax)
346 bool isignored, isliquid, wasignored, wasliquid, waschecked, waspushed;
347 const v3s16 &em = vm->m_area.getExtent();
349 for (s16 z = nmin.Z + 1; z <= nmax.Z - 1; z++)
350 for (s16 x = nmin.X + 1; x <= nmax.X - 1; x++) {
356 u32 vi = vm->m_area.index(x, nmax.Y, z);
357 for (s16 y = nmax.Y; y >= nmin.Y; y--) {
358 isignored = vm->m_data[vi].getContent() == CONTENT_IGNORE;
359 isliquid = ndef->get(vm->m_data[vi]).isLiquid();
361 if (isignored || wasignored || isliquid == wasliquid) {
362 // Neither topmost node of liquid column nor topmost node below column
365 } else if (isliquid) {
366 // This is the topmost node in the column
367 bool ispushed = false;
368 if (isLiquidHorizontallyFlowable(vi, em)) {
369 trans_liquid->push_back(v3s16(x, y, z));
372 // Remember waschecked and waspushed to avoid repeated
373 // checks/pushes in case the column consists of only this node
375 waspushed = ispushed;
377 // This is the topmost node below a liquid column
379 vm->m_area.add_y(em, vi_above, 1);
380 if (!waspushed && (ndef->get(vm->m_data[vi]).floodable ||
381 (!waschecked && isLiquidHorizontallyFlowable(vi_above, em)))) {
382 // Push back the lowest node in the column which is one
383 // node above this one
384 trans_liquid->push_back(v3s16(x, y + 1, z));
388 wasliquid = isliquid;
389 wasignored = isignored;
390 vm->m_area.add_y(em, vi, -1);
396 void Mapgen::setLighting(u8 light, v3s16 nmin, v3s16 nmax)
398 ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update", SPT_AVG);
399 VoxelArea a(nmin, nmax);
401 for (int z = a.MinEdge.Z; z <= a.MaxEdge.Z; z++) {
402 for (int y = a.MinEdge.Y; y <= a.MaxEdge.Y; y++) {
403 u32 i = vm->m_area.index(a.MinEdge.X, y, z);
404 for (int x = a.MinEdge.X; x <= a.MaxEdge.X; x++, i++)
405 vm->m_data[i].param1 = light;
411 void Mapgen::lightSpread(VoxelArea &a, v3s16 p, u8 light)
413 if (light <= 1 || !a.contains(p))
416 u32 vi = vm->m_area.index(p);
417 MapNode &n = vm->m_data[vi];
419 // Decay light in each of the banks separately
420 u8 light_day = light & 0x0F;
424 u8 light_night = light & 0xF0;
428 // Bail out only if we have no more light from either bank to propogate, or
429 // we hit a solid block that light cannot pass through.
430 if ((light_day <= (n.param1 & 0x0F) &&
431 light_night <= (n.param1 & 0xF0)) ||
432 !ndef->get(n).light_propagates)
435 // Since this recursive function only terminates when there is no light from
436 // either bank left, we need to take the max of both banks into account for
437 // the case where spreading has stopped for one light bank but not the other.
438 light = MYMAX(light_day, n.param1 & 0x0F) |
439 MYMAX(light_night, n.param1 & 0xF0);
443 lightSpread(a, p + v3s16(0, 0, 1), light);
444 lightSpread(a, p + v3s16(0, 1, 0), light);
445 lightSpread(a, p + v3s16(1, 0, 0), light);
446 lightSpread(a, p - v3s16(0, 0, 1), light);
447 lightSpread(a, p - v3s16(0, 1, 0), light);
448 lightSpread(a, p - v3s16(1, 0, 0), light);
452 void Mapgen::calcLighting(v3s16 nmin, v3s16 nmax, v3s16 full_nmin, v3s16 full_nmax,
453 bool propagate_shadow)
455 ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update", SPT_AVG);
456 //TimeTaker t("updateLighting");
458 propagateSunlight(nmin, nmax, propagate_shadow);
459 spreadLight(full_nmin, full_nmax);
461 //printf("updateLighting: %dms\n", t.stop());
465 void Mapgen::propagateSunlight(v3s16 nmin, v3s16 nmax, bool propagate_shadow)
467 //TimeTaker t("propagateSunlight");
468 VoxelArea a(nmin, nmax);
469 bool block_is_underground = (water_level >= nmax.Y);
470 const v3s16 &em = vm->m_area.getExtent();
472 // NOTE: Direct access to the low 4 bits of param1 is okay here because,
473 // by definition, sunlight will never be in the night lightbank.
475 for (int z = a.MinEdge.Z; z <= a.MaxEdge.Z; z++) {
476 for (int x = a.MinEdge.X; x <= a.MaxEdge.X; x++) {
477 // see if we can get a light value from the overtop
478 u32 i = vm->m_area.index(x, a.MaxEdge.Y + 1, z);
479 if (vm->m_data[i].getContent() == CONTENT_IGNORE) {
480 if (block_is_underground)
482 } else if ((vm->m_data[i].param1 & 0x0F) != LIGHT_SUN &&
486 vm->m_area.add_y(em, i, -1);
488 for (int y = a.MaxEdge.Y; y >= a.MinEdge.Y; y--) {
489 MapNode &n = vm->m_data[i];
490 if (!ndef->get(n).sunlight_propagates)
492 n.param1 = LIGHT_SUN;
493 vm->m_area.add_y(em, i, -1);
497 //printf("propagateSunlight: %dms\n", t.stop());
501 void Mapgen::spreadLight(v3s16 nmin, v3s16 nmax)
503 //TimeTaker t("spreadLight");
504 VoxelArea a(nmin, nmax);
506 for (int z = a.MinEdge.Z; z <= a.MaxEdge.Z; z++) {
507 for (int y = a.MinEdge.Y; y <= a.MaxEdge.Y; y++) {
508 u32 i = vm->m_area.index(a.MinEdge.X, y, z);
509 for (int x = a.MinEdge.X; x <= a.MaxEdge.X; x++, i++) {
510 MapNode &n = vm->m_data[i];
511 if (n.getContent() == CONTENT_IGNORE)
514 const ContentFeatures &cf = ndef->get(n);
515 if (!cf.light_propagates)
518 // TODO(hmmmmm): Abstract away direct param1 accesses with a
519 // wrapper, but something lighter than MapNode::get/setLight
521 u8 light_produced = cf.light_source;
523 n.param1 = light_produced | (light_produced << 4);
527 lightSpread(a, v3s16(x, y, z + 1), light);
528 lightSpread(a, v3s16(x, y + 1, z ), light);
529 lightSpread(a, v3s16(x + 1, y, z ), light);
530 lightSpread(a, v3s16(x, y, z - 1), light);
531 lightSpread(a, v3s16(x, y - 1, z ), light);
532 lightSpread(a, v3s16(x - 1, y, z ), light);
538 //printf("spreadLight: %dms\n", t.stop());
546 MapgenBasic::MapgenBasic(int mapgenid, MapgenParams *params, EmergeManager *emerge)
547 : Mapgen(mapgenid, params, emerge)
549 this->m_emerge = emerge;
550 this->m_bmgr = emerge->biomemgr;
552 //// Here, 'stride' refers to the number of elements needed to skip to index
553 //// an adjacent element for that coordinate in noise/height/biome maps
554 //// (*not* vmanip content map!)
556 // Note there is no X stride explicitly defined. Items adjacent in the X
557 // coordinate are assumed to be adjacent in memory as well (i.e. stride of 1).
559 // Number of elements to skip to get to the next Y coordinate
560 this->ystride = csize.X;
562 // Number of elements to skip to get to the next Z coordinate
563 this->zstride = csize.X * csize.Y;
565 // Z-stride value for maps oversized for 1-down overgeneration
566 this->zstride_1d = csize.X * (csize.Y + 1);
568 // Z-stride value for maps oversized for 1-up 1-down overgeneration
569 this->zstride_1u1d = csize.X * (csize.Y + 2);
571 //// Allocate heightmap
572 this->heightmap = new s16[csize.X * csize.Z];
574 //// Initialize biome generator
575 // TODO(hmmmm): should we have a way to disable biomemanager biomes?
576 biomegen = m_bmgr->createBiomeGen(BIOMEGEN_ORIGINAL, params->bparams, csize);
577 biomemap = biomegen->biomemap;
579 //// Look up some commonly used content
580 c_stone = ndef->getId("mapgen_stone");
581 c_desert_stone = ndef->getId("mapgen_desert_stone");
582 c_sandstone = ndef->getId("mapgen_sandstone");
583 c_water_source = ndef->getId("mapgen_water_source");
584 c_river_water_source = ndef->getId("mapgen_river_water_source");
585 c_lava_source = ndef->getId("mapgen_lava_source");
587 // Fall back to more basic content if not defined
588 // river_water_source cannot fallback to water_source because river water
589 // needs to be non-renewable and have a short flow range.
590 if (c_desert_stone == CONTENT_IGNORE)
591 c_desert_stone = c_stone;
592 if (c_sandstone == CONTENT_IGNORE)
593 c_sandstone = c_stone;
595 //// Content used for dungeon generation
596 c_cobble = ndef->getId("mapgen_cobble");
597 c_mossycobble = ndef->getId("mapgen_mossycobble");
598 c_stair_cobble = ndef->getId("mapgen_stair_cobble");
599 c_stair_desert_stone = ndef->getId("mapgen_stair_desert_stone");
600 c_sandstonebrick = ndef->getId("mapgen_sandstonebrick");
601 c_stair_sandstone_block = ndef->getId("mapgen_stair_sandstone_block");
603 // Fall back to more basic content if not defined
604 if (c_mossycobble == CONTENT_IGNORE)
605 c_mossycobble = c_cobble;
606 if (c_stair_cobble == CONTENT_IGNORE)
607 c_stair_cobble = c_cobble;
608 if (c_stair_desert_stone == CONTENT_IGNORE)
609 c_stair_desert_stone = c_desert_stone;
610 if (c_sandstonebrick == CONTENT_IGNORE)
611 c_sandstonebrick = c_sandstone;
612 if (c_stair_sandstone_block == CONTENT_IGNORE)
613 c_stair_sandstone_block = c_sandstonebrick;
617 MapgenBasic::~MapgenBasic()
624 void MapgenBasic::generateBiomes(MgStoneType *mgstone_type,
625 content_t *biome_stone, s16 biome_zero_level)
627 // can't generate biomes without a biome generator!
631 const v3s16 &em = vm->m_area.getExtent();
633 MgStoneType stone_type = MGSTONE_OTHER;
634 content_t c_biome_stone = c_stone;
636 noise_filler_depth->perlinMap2D(node_min.X, node_min.Z);
638 for (s16 z = node_min.Z; z <= node_max.Z; z++)
639 for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
643 u16 depth_water_top = 0;
644 u16 depth_riverbed = 0;
645 u32 vi = vm->m_area.index(x, node_max.Y, z);
647 // Check node at base of mapchunk above, either a node of a previously
648 // generated mapchunk or if not, a node of overgenerated base terrain.
649 content_t c_above = vm->m_data[vi + em.X].getContent();
650 bool air_above = c_above == CONTENT_AIR;
651 bool river_water_above = c_above == c_river_water_source;
652 bool water_above = c_above == c_water_source || river_water_above;
654 biomemap[index] = BIOME_NONE;
656 // If there is air or water above enable top/filler placement, otherwise force
657 // nplaced to stone level by setting a number exceeding any possible filler depth.
658 u16 nplaced = (air_above || water_above) ? 0 : U16_MAX;
660 for (s16 y = node_max.Y; y >= node_min.Y; y--) {
661 content_t c = vm->m_data[vi].getContent();
663 // Biome is recalculated each time an upper surface is detected while
664 // working down a column. The selected biome then remains in effect for
665 // all nodes below until the next surface and biome recalculation.
666 // Biome is recalculated:
667 // 1. At the surface of stone below air or water.
668 // 2. At the surface of water below air.
669 // 3. When stone or water is detected but biome has not yet been calculated.
670 bool is_stone_surface = (c == c_stone) &&
671 (air_above || water_above || !biome);
673 bool is_water_surface =
674 (c == c_water_source || c == c_river_water_source) &&
675 (air_above || !biome);
677 if (is_stone_surface || is_water_surface) {
678 // Limit to +-MAX MAP GENERATION LIMIT to work with biome y_min / y_max.
679 s32 relative_y = rangelim(y - biome_zero_level,
680 -MAX_MAP_GENERATION_LIMIT, MAX_MAP_GENERATION_LIMIT);
681 biome = biomegen->getBiomeAtIndex(index, relative_y);
683 if (biomemap[index] == BIOME_NONE && is_stone_surface)
684 biomemap[index] = biome->index;
686 depth_top = biome->depth_top;
687 base_filler = MYMAX(depth_top +
688 biome->depth_filler +
689 noise_filler_depth->result[index], 0.f);
690 depth_water_top = biome->depth_water_top;
691 depth_riverbed = biome->depth_riverbed;
693 // Detect stone type for dungeons during every biome calculation.
694 // If none detected the last selected biome stone is chosen.
695 if (biome->c_stone == c_stone)
696 stone_type = MGSTONE_STONE;
697 else if (biome->c_stone == c_desert_stone)
698 stone_type = MGSTONE_DESERT_STONE;
699 else if (biome->c_stone == c_sandstone)
700 stone_type = MGSTONE_SANDSTONE;
702 c_biome_stone = biome->c_stone;
706 content_t c_below = vm->m_data[vi - em.X].getContent();
708 // If the node below isn't solid, make this node stone, so that
709 // any top/filler nodes above are structurally supported.
710 // This is done by aborting the cycle of top/filler placement
711 // immediately by forcing nplaced to stone level.
712 if (c_below == CONTENT_AIR
713 || c_below == c_water_source
714 || c_below == c_river_water_source)
717 if (river_water_above) {
718 if (nplaced < depth_riverbed) {
719 vm->m_data[vi] = MapNode(biome->c_riverbed);
722 nplaced = U16_MAX; // Disable top/filler placement
723 river_water_above = false;
725 } else if (nplaced < depth_top) {
726 vm->m_data[vi] = MapNode(biome->c_top);
728 } else if (nplaced < base_filler) {
729 vm->m_data[vi] = MapNode(biome->c_filler);
732 vm->m_data[vi] = MapNode(biome->c_stone);
737 } else if (c == c_water_source) {
738 vm->m_data[vi] = MapNode((y > (s32)(water_level - depth_water_top))
739 ? biome->c_water_top : biome->c_water);
740 nplaced = 0; // Enable top/filler placement for next surface
743 } else if (c == c_river_water_source) {
744 vm->m_data[vi] = MapNode(biome->c_river_water);
745 nplaced = 0; // Enable riverbed placement for next surface
748 river_water_above = true;
749 } else if (c == CONTENT_AIR) {
750 nplaced = 0; // Enable top/filler placement for next surface
753 } else { // Possible various nodes overgenerated from neighbouring mapchunks
754 nplaced = U16_MAX; // Disable top/filler placement
759 vm->m_area.add_y(em, vi, -1);
763 *mgstone_type = stone_type;
764 *biome_stone = c_biome_stone;
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 u32 vi = vm->m_area.index(x, full_node_max.Y, z);
784 content_t c_full_max = vm->m_data[vi].getContent();
787 if (c_full_max == CONTENT_AIR) {
788 y_start = full_node_max.Y - 1;
789 } else if (c_full_max == CONTENT_IGNORE) {
790 vi = vm->m_area.index(x, node_max.Y + 1, z);
791 content_t c_max = vm->m_data[vi].getContent();
793 if (c_max == CONTENT_AIR)
794 y_start = node_max.Y;
801 vi = vm->m_area.index(x, y_start, z);
802 for (s16 y = y_start; y >= node_min.Y - 1; y--) {
803 if (vm->m_data[vi].getContent() != CONTENT_AIR)
806 vm->m_area.add_y(em, vi, -1);
809 content_t c = vm->m_data[vi].getContent();
810 if (!ndef->get(c).buildable_to && c != CONTENT_IGNORE && c != biome->c_dust) {
811 vm->m_area.add_y(em, vi, 1);
812 vm->m_data[vi] = MapNode(biome->c_dust);
818 void MapgenBasic::generateCaves(s16 max_stone_y, s16 large_cave_depth)
820 if (max_stone_y < node_min.Y)
823 CavesNoiseIntersection caves_noise(ndef, m_bmgr, csize,
824 &np_cave1, &np_cave2, seed, cave_width);
826 caves_noise.generateCaves(vm, node_min, node_max, biomemap);
828 if (node_max.Y > large_cave_depth)
831 PseudoRandom ps(blockseed + 21343);
832 u32 bruises_count = ps.range(0, 2);
833 for (u32 i = 0; i < bruises_count; i++) {
834 CavesRandomWalk cave(ndef, &gennotify, seed, water_level,
835 c_water_source, CONTENT_IGNORE, lava_depth);
837 cave.makeCave(vm, node_min, node_max, &ps, true, max_stone_y, heightmap);
842 bool MapgenBasic::generateCaverns(s16 max_stone_y)
844 if (node_min.Y > max_stone_y || node_min.Y > cavern_limit)
847 CavernsNoise caverns_noise(ndef, csize, &np_cavern,
848 seed, cavern_limit, cavern_taper, cavern_threshold);
850 return caverns_noise.generateCaverns(vm, node_min, node_max);
854 void MapgenBasic::generateDungeons(s16 max_stone_y,
855 MgStoneType stone_type, content_t biome_stone)
857 if (max_stone_y < node_min.Y)
863 dp.c_water = c_water_source;
864 dp.c_river_water = c_river_water_source;
866 dp.only_in_ground = true;
867 dp.corridor_len_min = 1;
868 dp.corridor_len_max = 13;
871 dp.y_min = -MAX_MAP_GENERATION_LIMIT;
872 dp.y_max = MAX_MAP_GENERATION_LIMIT;
874 dp.np_density = nparams_dungeon_density;
875 dp.np_alt_wall = nparams_dungeon_alt_wall;
877 switch (stone_type) {
880 dp.c_wall = c_cobble;
881 dp.c_alt_wall = c_mossycobble;
882 dp.c_stair = c_stair_cobble;
884 dp.diagonal_dirs = false;
885 dp.holesize = v3s16(1, 2, 1);
886 dp.room_size_min = v3s16(4, 4, 4);
887 dp.room_size_max = v3s16(8, 6, 8);
888 dp.room_size_large_min = v3s16(8, 8, 8);
889 dp.room_size_large_max = v3s16(16, 16, 16);
890 dp.notifytype = GENNOTIFY_DUNGEON;
892 case MGSTONE_DESERT_STONE:
893 dp.c_wall = c_desert_stone;
894 dp.c_alt_wall = CONTENT_IGNORE;
895 dp.c_stair = c_stair_desert_stone;
897 dp.diagonal_dirs = true;
898 dp.holesize = v3s16(2, 3, 2);
899 dp.room_size_min = v3s16(6, 9, 6);
900 dp.room_size_max = v3s16(10, 11, 10);
901 dp.room_size_large_min = v3s16(10, 13, 10);
902 dp.room_size_large_max = v3s16(18, 21, 18);
903 dp.notifytype = GENNOTIFY_TEMPLE;
905 case MGSTONE_SANDSTONE:
906 dp.c_wall = c_sandstonebrick;
907 dp.c_alt_wall = CONTENT_IGNORE;
908 dp.c_stair = c_stair_sandstone_block;
910 dp.diagonal_dirs = false;
911 dp.holesize = v3s16(2, 2, 2);
912 dp.room_size_min = v3s16(6, 4, 6);
913 dp.room_size_max = v3s16(10, 6, 10);
914 dp.room_size_large_min = v3s16(10, 8, 10);
915 dp.room_size_large_max = v3s16(18, 16, 18);
916 dp.notifytype = GENNOTIFY_DUNGEON;
919 dp.c_wall = biome_stone;
920 dp.c_alt_wall = biome_stone;
921 dp.c_stair = biome_stone;
923 dp.diagonal_dirs = false;
924 dp.holesize = v3s16(1, 2, 1);
925 dp.room_size_min = v3s16(4, 4, 4);
926 dp.room_size_max = v3s16(8, 6, 8);
927 dp.room_size_large_min = v3s16(8, 8, 8);
928 dp.room_size_large_max = v3s16(16, 16, 16);
929 dp.notifytype = GENNOTIFY_DUNGEON;
933 DungeonGen dgen(ndef, &gennotify, &dp);
934 dgen.generate(vm, blockseed, full_node_min, full_node_max);
939 //// GenerateNotifier
942 GenerateNotifier::GenerateNotifier()
947 GenerateNotifier::GenerateNotifier(u32 notify_on,
948 std::set<u32> *notify_on_deco_ids)
950 m_notify_on = notify_on;
951 m_notify_on_deco_ids = notify_on_deco_ids;
955 void GenerateNotifier::setNotifyOn(u32 notify_on)
957 m_notify_on = notify_on;
961 void GenerateNotifier::setNotifyOnDecoIds(std::set<u32> *notify_on_deco_ids)
963 m_notify_on_deco_ids = notify_on_deco_ids;
967 bool GenerateNotifier::addEvent(GenNotifyType type, v3s16 pos, u32 id)
969 if (!(m_notify_on & (1 << type)))
972 if (type == GENNOTIFY_DECORATION &&
973 m_notify_on_deco_ids->find(id) == m_notify_on_deco_ids->end())
980 m_notify_events.push_back(gne);
986 void GenerateNotifier::getEvents(
987 std::map<std::string, std::vector<v3s16> > &event_map,
990 std::list<GenNotifyEvent>::iterator it;
992 for (it = m_notify_events.begin(); it != m_notify_events.end(); ++it) {
993 GenNotifyEvent &gn = *it;
994 std::string name = (gn.type == GENNOTIFY_DECORATION) ?
995 "decoration#"+ itos(gn.id) :
996 flagdesc_gennotify[gn.type].name;
998 event_map[name].push_back(gn.pos);
1002 m_notify_events.clear();
1011 MapgenParams::~MapgenParams()
1017 void MapgenParams::readParams(const Settings *settings)
1019 std::string seed_str;
1020 const char *seed_name = (settings == g_settings) ? "fixed_map_seed" : "seed";
1022 if (settings->getNoEx(seed_name, seed_str)) {
1023 if (!seed_str.empty())
1024 seed = read_seed(seed_str.c_str());
1026 myrand_bytes(&seed, sizeof(seed));
1029 std::string mg_name;
1030 if (settings->getNoEx("mg_name", mg_name)) {
1031 mgtype = Mapgen::getMapgenType(mg_name);
1032 if (mgtype == MAPGEN_INVALID)
1033 mgtype = MAPGEN_DEFAULT;
1036 settings->getS16NoEx("water_level", water_level);
1037 settings->getS16NoEx("mapgen_limit", mapgen_limit);
1038 settings->getS16NoEx("chunksize", chunksize);
1039 settings->getFlagStrNoEx("mg_flags", flags, flagdesc_mapgen);
1042 bparams = BiomeManager::createBiomeParams(BIOMEGEN_ORIGINAL);
1044 bparams->readParams(settings);
1045 bparams->seed = seed;
1050 void MapgenParams::writeParams(Settings *settings) const
1052 settings->set("mg_name", Mapgen::getMapgenName(mgtype));
1053 settings->setU64("seed", seed);
1054 settings->setS16("water_level", water_level);
1055 settings->setS16("mapgen_limit", mapgen_limit);
1056 settings->setS16("chunksize", chunksize);
1057 settings->setFlagStr("mg_flags", flags, flagdesc_mapgen, U32_MAX);
1060 bparams->writeParams(settings);
1063 // Calculate edges of outermost generated mapchunks (less than
1064 // 'mapgen_limit'), and corresponding exact limits for SAO entities.
1065 void MapgenParams::calcMapgenEdges()
1067 if (m_mapgen_edges_calculated)
1070 // Central chunk offset, in blocks
1071 s16 ccoff_b = -chunksize / 2;
1072 // Chunksize, in nodes
1073 s32 csize_n = chunksize * MAP_BLOCKSIZE;
1074 // Minp/maxp of central chunk, in nodes
1075 s16 ccmin = ccoff_b * MAP_BLOCKSIZE;
1076 s16 ccmax = ccmin + csize_n - 1;
1077 // Fullminp/fullmaxp of central chunk, in nodes
1078 s16 ccfmin = ccmin - MAP_BLOCKSIZE;
1079 s16 ccfmax = ccmax + MAP_BLOCKSIZE;
1080 // Effective mapgen limit, in blocks
1081 // Uses same calculation as ServerMap::blockpos_over_mapgen_limit(v3s16 p)
1082 s16 mapgen_limit_b = rangelim(mapgen_limit,
1083 0, MAX_MAP_GENERATION_LIMIT) / MAP_BLOCKSIZE;
1084 // Effective mapgen limits, in nodes
1085 s16 mapgen_limit_min = -mapgen_limit_b * MAP_BLOCKSIZE;
1086 s16 mapgen_limit_max = (mapgen_limit_b + 1) * MAP_BLOCKSIZE - 1;
1087 // Number of complete chunks from central chunk fullminp/fullmaxp
1088 // to effective mapgen limits.
1089 s16 numcmin = MYMAX((ccfmin - mapgen_limit_min) / csize_n, 0);
1090 s16 numcmax = MYMAX((mapgen_limit_max - ccfmax) / csize_n, 0);
1091 // Mapgen edges, in nodes
1092 mapgen_edge_min = ccmin - numcmin * csize_n;
1093 mapgen_edge_max = ccmax + numcmax * csize_n;
1094 // SAO position limits, in Irrlicht units
1095 m_sao_limit_min = mapgen_edge_min * BS - 3.0f;
1096 m_sao_limit_max = mapgen_edge_max * BS + 3.0f;
1098 m_mapgen_edges_calculated = true;
1102 bool MapgenParams::saoPosOverLimit(const v3f &p)
1104 if (!m_mapgen_edges_calculated)
1107 return p.X < m_sao_limit_min ||
1108 p.X > m_sao_limit_max ||
1109 p.Y < m_sao_limit_min ||
1110 p.Y > m_sao_limit_max ||
1111 p.Z < m_sao_limit_min ||
1112 p.Z > m_sao_limit_max;
1116 s32 MapgenParams::getSpawnRangeMax()
1120 return MYMIN(-mapgen_edge_min, mapgen_edge_max);