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);
101 Mapgen::Mapgen(int mapgenid, MapgenParams *params, EmergeManager *emerge) :
102 gennotify(emerge->gen_notify_on, &emerge->gen_notify_on_deco_ids)
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);
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.
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)
120 It's probably okay if this never gets fixed. 4.2 billion possibilities
121 ought to be enough for anyone.
123 seed = (s32)params->seed;
129 MapgenType Mapgen::getMapgenType(const std::string &mgname)
131 for (size_t i = 0; i != ARRLEN(g_reg_mapgens); i++) {
132 if (mgname == g_reg_mapgens[i].name)
133 return (MapgenType)i;
136 return MAPGEN_INVALID;
140 const char *Mapgen::getMapgenName(MapgenType mgtype)
142 size_t index = (size_t)mgtype;
143 if (index == MAPGEN_INVALID || index >= ARRLEN(g_reg_mapgens))
146 return g_reg_mapgens[index].name;
150 Mapgen *Mapgen::createMapgen(MapgenType mgtype, int mgid,
151 MapgenParams *params, EmergeManager *emerge)
154 case MAPGEN_CARPATHIAN:
155 return new MapgenCarpathian(mgid, (MapgenCarpathianParams *)params, emerge);
157 return new MapgenFlat(mgid, (MapgenFlatParams *)params, emerge);
159 return new MapgenFractal(mgid, (MapgenFractalParams *)params, emerge);
160 case MAPGEN_SINGLENODE:
161 return new MapgenSinglenode(mgid, (MapgenSinglenodeParams *)params, emerge);
163 return new MapgenV5(mgid, (MapgenV5Params *)params, emerge);
165 return new MapgenV6(mgid, (MapgenV6Params *)params, emerge);
167 return new MapgenV7(mgid, (MapgenV7Params *)params, emerge);
169 return new MapgenValleys(mgid, (MapgenValleysParams *)params, emerge);
176 MapgenParams *Mapgen::createMapgenParams(MapgenType mgtype)
179 case MAPGEN_CARPATHIAN:
180 return new MapgenCarpathianParams;
182 return new MapgenFlatParams;
184 return new MapgenFractalParams;
185 case MAPGEN_SINGLENODE:
186 return new MapgenSinglenodeParams;
188 return new MapgenV5Params;
190 return new MapgenV6Params;
192 return new MapgenV7Params;
194 return new MapgenValleysParams;
201 void Mapgen::getMapgenNames(std::vector<const char *> *mgnames, bool include_hidden)
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);
210 u32 Mapgen::getBlockSeed(v3s16 p, s32 seed)
219 u32 Mapgen::getBlockSeed2(v3s16 p, s32 seed)
221 u32 n = 1619 * p.X + 31337 * p.Y + 52591 * p.Z + 1013 * seed;
223 return (n * (n * n * 60493 + 19990303) + 1376312589);
227 // Returns Y one under area minimum if not found
228 s16 Mapgen::findGroundLevelFull(v2s16 p2d)
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);
236 for (y = y_nodes_max; y >= y_nodes_min; y--) {
237 MapNode &n = vm->m_data[i];
238 if (ndef->get(n).walkable)
241 vm->m_area.add_y(em, i, -1);
243 return (y >= y_nodes_min) ? y : y_nodes_min - 1;
247 // Returns -MAX_MAP_GENERATION_LIMIT if not found
248 s16 Mapgen::findGroundLevel(v2s16 p2d, s16 ymin, s16 ymax)
250 const v3s16 &em = vm->m_area.getExtent();
251 u32 i = vm->m_area.index(p2d.X, ymax, p2d.Y);
254 for (y = ymax; y >= ymin; y--) {
255 MapNode &n = vm->m_data[i];
256 if (ndef->get(n).walkable)
259 vm->m_area.add_y(em, i, -1);
261 return (y >= ymin) ? y : -MAX_MAP_GENERATION_LIMIT;
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)
268 const v3s16 &em = vm->m_area.getExtent();
269 u32 i = vm->m_area.index(p2d.X, ymax, p2d.Y);
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;
277 if (ndef->get(n).isLiquid())
280 vm->m_area.add_y(em, i, -1);
282 return (y >= ymin) ? y : -MAX_MAP_GENERATION_LIMIT;
286 void Mapgen::updateHeightmap(v3s16 nmin, v3s16 nmax)
291 //TimeTaker t("Mapgen::updateHeightmap", NULL, PRECISION_MICRO);
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);
297 heightmap[index] = y;
303 void Mapgen::getSurfaces(v2s16 p2d, s16 ymin, s16 ymax,
304 s16 *floors, s16 *ceilings, u16 *num_floors, u16 *num_ceilings)
308 const v3s16 &em = vm->m_area.getExtent();
310 bool is_walkable = false;
311 u32 vi = vm->m_area.index(p2d.X, ymax, p2d.Y);
312 MapNode mn_max = vm->m_data[vi];
313 bool walkable_above = ndef->get(mn_max).walkable;
314 vm->m_area.add_y(em, vi, -1);
316 for (s16 y = ymax - 1; y >= ymin; y--) {
317 MapNode mn = vm->m_data[vi];
318 is_walkable = ndef->get(mn).walkable;
320 if (is_walkable && !walkable_above) {
323 } else if (!is_walkable && walkable_above) {
324 ceilings[ceiling_i] = y + 1;
328 vm->m_area.add_y(em, vi, -1);
329 walkable_above = is_walkable;
332 *num_floors = floor_i;
333 *num_ceilings = ceiling_i;
337 inline bool Mapgen::isLiquidHorizontallyFlowable(u32 vi, v3s16 em)
340 vm->m_area.add_x(em, vi_neg_x, -1);
341 if (vm->m_data[vi_neg_x].getContent() != CONTENT_IGNORE) {
342 const ContentFeatures &c_nx = ndef->get(vm->m_data[vi_neg_x]);
343 if (c_nx.floodable && !c_nx.isLiquid())
347 vm->m_area.add_x(em, vi_pos_x, +1);
348 if (vm->m_data[vi_pos_x].getContent() != CONTENT_IGNORE) {
349 const ContentFeatures &c_px = ndef->get(vm->m_data[vi_pos_x]);
350 if (c_px.floodable && !c_px.isLiquid())
354 vm->m_area.add_z(em, vi_neg_z, -1);
355 if (vm->m_data[vi_neg_z].getContent() != CONTENT_IGNORE) {
356 const ContentFeatures &c_nz = ndef->get(vm->m_data[vi_neg_z]);
357 if (c_nz.floodable && !c_nz.isLiquid())
361 vm->m_area.add_z(em, vi_pos_z, +1);
362 if (vm->m_data[vi_pos_z].getContent() != CONTENT_IGNORE) {
363 const ContentFeatures &c_pz = ndef->get(vm->m_data[vi_pos_z]);
364 if (c_pz.floodable && !c_pz.isLiquid())
370 void Mapgen::updateLiquid(UniqueQueue<v3s16> *trans_liquid, v3s16 nmin, v3s16 nmax)
372 bool isignored, isliquid, wasignored, wasliquid, waschecked, waspushed;
373 const v3s16 &em = vm->m_area.getExtent();
375 for (s16 z = nmin.Z + 1; z <= nmax.Z - 1; z++)
376 for (s16 x = nmin.X + 1; x <= nmax.X - 1; x++) {
382 u32 vi = vm->m_area.index(x, nmax.Y, z);
383 for (s16 y = nmax.Y; y >= nmin.Y; y--) {
384 isignored = vm->m_data[vi].getContent() == CONTENT_IGNORE;
385 isliquid = ndef->get(vm->m_data[vi]).isLiquid();
387 if (isignored || wasignored || isliquid == wasliquid) {
388 // Neither topmost node of liquid column nor topmost node below column
391 } else if (isliquid) {
392 // This is the topmost node in the column
393 bool ispushed = false;
394 if (isLiquidHorizontallyFlowable(vi, em)) {
395 trans_liquid->push_back(v3s16(x, y, z));
398 // Remember waschecked and waspushed to avoid repeated
399 // checks/pushes in case the column consists of only this node
401 waspushed = ispushed;
403 // This is the topmost node below a liquid column
405 vm->m_area.add_y(em, vi_above, 1);
406 if (!waspushed && (ndef->get(vm->m_data[vi]).floodable ||
407 (!waschecked && isLiquidHorizontallyFlowable(vi_above, em)))) {
408 // Push back the lowest node in the column which is one
409 // node above this one
410 trans_liquid->push_back(v3s16(x, y + 1, z));
414 wasliquid = isliquid;
415 wasignored = isignored;
416 vm->m_area.add_y(em, vi, -1);
422 void Mapgen::setLighting(u8 light, v3s16 nmin, v3s16 nmax)
424 ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update", SPT_AVG);
425 VoxelArea a(nmin, nmax);
427 for (int z = a.MinEdge.Z; z <= a.MaxEdge.Z; z++) {
428 for (int y = a.MinEdge.Y; y <= a.MaxEdge.Y; y++) {
429 u32 i = vm->m_area.index(a.MinEdge.X, y, z);
430 for (int x = a.MinEdge.X; x <= a.MaxEdge.X; x++, i++)
431 vm->m_data[i].param1 = light;
437 void Mapgen::lightSpread(VoxelArea &a, v3s16 p, u8 light)
439 if (light <= 1 || !a.contains(p))
442 u32 vi = vm->m_area.index(p);
443 MapNode &n = vm->m_data[vi];
445 // Decay light in each of the banks separately
446 u8 light_day = light & 0x0F;
450 u8 light_night = light & 0xF0;
454 // Bail out only if we have no more light from either bank to propogate, or
455 // we hit a solid block that light cannot pass through.
456 if ((light_day <= (n.param1 & 0x0F) &&
457 light_night <= (n.param1 & 0xF0)) ||
458 !ndef->get(n).light_propagates)
461 // Since this recursive function only terminates when there is no light from
462 // either bank left, we need to take the max of both banks into account for
463 // the case where spreading has stopped for one light bank but not the other.
464 light = MYMAX(light_day, n.param1 & 0x0F) |
465 MYMAX(light_night, n.param1 & 0xF0);
469 lightSpread(a, p + v3s16(0, 0, 1), light);
470 lightSpread(a, p + v3s16(0, 1, 0), light);
471 lightSpread(a, p + v3s16(1, 0, 0), light);
472 lightSpread(a, p - v3s16(0, 0, 1), light);
473 lightSpread(a, p - v3s16(0, 1, 0), light);
474 lightSpread(a, p - v3s16(1, 0, 0), light);
478 void Mapgen::calcLighting(v3s16 nmin, v3s16 nmax, v3s16 full_nmin, v3s16 full_nmax,
479 bool propagate_shadow)
481 ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update", SPT_AVG);
482 //TimeTaker t("updateLighting");
484 propagateSunlight(nmin, nmax, propagate_shadow);
485 spreadLight(full_nmin, full_nmax);
487 //printf("updateLighting: %dms\n", t.stop());
491 void Mapgen::propagateSunlight(v3s16 nmin, v3s16 nmax, bool propagate_shadow)
493 //TimeTaker t("propagateSunlight");
494 VoxelArea a(nmin, nmax);
495 bool block_is_underground = (water_level >= nmax.Y);
496 const v3s16 &em = vm->m_area.getExtent();
498 // NOTE: Direct access to the low 4 bits of param1 is okay here because,
499 // by definition, sunlight will never be in the night lightbank.
501 for (int z = a.MinEdge.Z; z <= a.MaxEdge.Z; z++) {
502 for (int x = a.MinEdge.X; x <= a.MaxEdge.X; x++) {
503 // see if we can get a light value from the overtop
504 u32 i = vm->m_area.index(x, a.MaxEdge.Y + 1, z);
505 if (vm->m_data[i].getContent() == CONTENT_IGNORE) {
506 if (block_is_underground)
508 } else if ((vm->m_data[i].param1 & 0x0F) != LIGHT_SUN &&
512 vm->m_area.add_y(em, i, -1);
514 for (int y = a.MaxEdge.Y; y >= a.MinEdge.Y; y--) {
515 MapNode &n = vm->m_data[i];
516 if (!ndef->get(n).sunlight_propagates)
518 n.param1 = LIGHT_SUN;
519 vm->m_area.add_y(em, i, -1);
523 //printf("propagateSunlight: %dms\n", t.stop());
527 void Mapgen::spreadLight(v3s16 nmin, v3s16 nmax)
529 //TimeTaker t("spreadLight");
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 lightSpread(a, v3s16(x, y, z + 1), light);
554 lightSpread(a, v3s16(x, y + 1, z ), light);
555 lightSpread(a, v3s16(x + 1, y, z ), light);
556 lightSpread(a, v3s16(x, y, z - 1), light);
557 lightSpread(a, v3s16(x, y - 1, z ), light);
558 lightSpread(a, v3s16(x - 1, y, z ), light);
564 //printf("spreadLight: %dms\n", t.stop());
572 MapgenBasic::MapgenBasic(int mapgenid, MapgenParams *params, EmergeManager *emerge)
573 : Mapgen(mapgenid, params, emerge)
575 this->m_emerge = emerge;
576 this->m_bmgr = emerge->biomemgr;
578 //// Here, 'stride' refers to the number of elements needed to skip to index
579 //// an adjacent element for that coordinate in noise/height/biome maps
580 //// (*not* vmanip content map!)
582 // Note there is no X stride explicitly defined. Items adjacent in the X
583 // coordinate are assumed to be adjacent in memory as well (i.e. stride of 1).
585 // Number of elements to skip to get to the next Y coordinate
586 this->ystride = csize.X;
588 // Number of elements to skip to get to the next Z coordinate
589 this->zstride = csize.X * csize.Y;
591 // Z-stride value for maps oversized for 1-down overgeneration
592 this->zstride_1d = csize.X * (csize.Y + 1);
594 // Z-stride value for maps oversized for 1-up 1-down overgeneration
595 this->zstride_1u1d = csize.X * (csize.Y + 2);
597 //// Allocate heightmap
598 this->heightmap = new s16[csize.X * csize.Z];
600 //// Initialize biome generator
601 // TODO(hmmmm): should we have a way to disable biomemanager biomes?
602 biomegen = m_bmgr->createBiomeGen(BIOMEGEN_ORIGINAL, params->bparams, csize);
603 biomemap = biomegen->biomemap;
605 //// Look up some commonly used content
606 c_stone = ndef->getId("mapgen_stone");
607 c_desert_stone = ndef->getId("mapgen_desert_stone");
608 c_sandstone = ndef->getId("mapgen_sandstone");
609 c_water_source = ndef->getId("mapgen_water_source");
610 c_river_water_source = ndef->getId("mapgen_river_water_source");
611 c_lava_source = ndef->getId("mapgen_lava_source");
613 // Fall back to more basic content if not defined
614 // river_water_source cannot fallback to water_source because river water
615 // needs to be non-renewable and have a short flow range.
616 if (c_desert_stone == CONTENT_IGNORE)
617 c_desert_stone = c_stone;
618 if (c_sandstone == CONTENT_IGNORE)
619 c_sandstone = c_stone;
621 //// Content used for dungeon generation
622 c_cobble = ndef->getId("mapgen_cobble");
623 c_mossycobble = ndef->getId("mapgen_mossycobble");
624 c_stair_cobble = ndef->getId("mapgen_stair_cobble");
625 c_stair_desert_stone = ndef->getId("mapgen_stair_desert_stone");
626 c_sandstonebrick = ndef->getId("mapgen_sandstonebrick");
627 c_stair_sandstone_block = ndef->getId("mapgen_stair_sandstone_block");
629 // Fall back to more basic content if not defined
630 if (c_mossycobble == CONTENT_IGNORE)
631 c_mossycobble = c_cobble;
632 if (c_stair_cobble == CONTENT_IGNORE)
633 c_stair_cobble = c_cobble;
634 if (c_stair_desert_stone == CONTENT_IGNORE)
635 c_stair_desert_stone = c_desert_stone;
636 if (c_sandstonebrick == CONTENT_IGNORE)
637 c_sandstonebrick = c_sandstone;
638 if (c_stair_sandstone_block == CONTENT_IGNORE)
639 c_stair_sandstone_block = c_sandstonebrick;
643 MapgenBasic::~MapgenBasic()
650 void MapgenBasic::generateBiomes(MgStoneType *mgstone_type,
651 content_t *biome_stone)
653 // can't generate biomes without a biome generator!
657 const v3s16 &em = vm->m_area.getExtent();
659 MgStoneType stone_type = MGSTONE_OTHER;
660 content_t c_biome_stone = c_stone;
662 noise_filler_depth->perlinMap2D(node_min.X, node_min.Z);
664 for (s16 z = node_min.Z; z <= node_max.Z; z++)
665 for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
669 u16 depth_water_top = 0;
670 u16 depth_riverbed = 0;
671 s16 biome_y_min = -MAX_MAP_GENERATION_LIMIT;
672 u32 vi = vm->m_area.index(x, node_max.Y, z);
674 // Check node at base of mapchunk above, either a node of a previously
675 // generated mapchunk or if not, a node of overgenerated base terrain.
676 content_t c_above = vm->m_data[vi + em.X].getContent();
677 bool air_above = c_above == CONTENT_AIR;
678 bool river_water_above = c_above == c_river_water_source;
679 bool water_above = c_above == c_water_source || river_water_above;
681 biomemap[index] = BIOME_NONE;
683 // If there is air or water above enable top/filler placement, otherwise force
684 // nplaced to stone level by setting a number exceeding any possible filler depth.
685 u16 nplaced = (air_above || water_above) ? 0 : U16_MAX;
687 for (s16 y = node_max.Y; y >= node_min.Y; y--) {
688 content_t c = vm->m_data[vi].getContent();
689 // Biome is (re)calculated:
690 // 1. At the surface of stone below air or water.
691 // 2. At the surface of water below air.
692 // 3. When stone or water is detected but biome has not yet been calculated.
693 // 4. When stone or water is detected just below a biome's lower limit.
694 bool is_stone_surface = (c == c_stone) &&
695 (air_above || water_above || !biome || y < biome_y_min); // 1, 3, 4
697 bool is_water_surface =
698 (c == c_water_source || c == c_river_water_source) &&
699 (air_above || !biome || y < biome_y_min); // 2, 3, 4
701 if (is_stone_surface || is_water_surface) {
702 // (Re)calculate biome
703 biome = biomegen->getBiomeAtIndex(index, y);
705 if (biomemap[index] == BIOME_NONE && is_stone_surface)
706 biomemap[index] = biome->index;
708 depth_top = biome->depth_top;
709 base_filler = MYMAX(depth_top +
710 biome->depth_filler +
711 noise_filler_depth->result[index], 0.0f);
712 depth_water_top = biome->depth_water_top;
713 depth_riverbed = biome->depth_riverbed;
714 biome_y_min = biome->y_min;
716 // Detect stone type for dungeons during every biome calculation.
717 // If none detected the last selected biome stone is chosen.
718 if (biome->c_stone == c_stone)
719 stone_type = MGSTONE_STONE;
720 else if (biome->c_stone == c_desert_stone)
721 stone_type = MGSTONE_DESERT_STONE;
722 else if (biome->c_stone == c_sandstone)
723 stone_type = MGSTONE_SANDSTONE;
725 c_biome_stone = biome->c_stone;
729 content_t c_below = vm->m_data[vi - em.X].getContent();
731 // If the node below isn't solid, make this node stone, so that
732 // any top/filler nodes above are structurally supported.
733 // This is done by aborting the cycle of top/filler placement
734 // immediately by forcing nplaced to stone level.
735 if (c_below == CONTENT_AIR
736 || c_below == c_water_source
737 || c_below == c_river_water_source)
740 if (river_water_above) {
741 if (nplaced < depth_riverbed) {
742 vm->m_data[vi] = MapNode(biome->c_riverbed);
745 nplaced = U16_MAX; // Disable top/filler placement
746 river_water_above = false;
748 } else if (nplaced < depth_top) {
749 vm->m_data[vi] = MapNode(biome->c_top);
751 } else if (nplaced < base_filler) {
752 vm->m_data[vi] = MapNode(biome->c_filler);
755 vm->m_data[vi] = MapNode(biome->c_stone);
756 nplaced = U16_MAX; // Disable top/filler placement
761 } else if (c == c_water_source) {
762 vm->m_data[vi] = MapNode((y > (s32)(water_level - depth_water_top))
763 ? biome->c_water_top : biome->c_water);
764 nplaced = 0; // Enable top/filler placement for next surface
767 } else if (c == c_river_water_source) {
768 vm->m_data[vi] = MapNode(biome->c_river_water);
769 nplaced = 0; // Enable riverbed placement for next surface
772 river_water_above = true;
773 } else if (c == CONTENT_AIR) {
774 nplaced = 0; // Enable top/filler placement for next surface
777 } else { // Possible various nodes overgenerated from neighbouring mapchunks
778 nplaced = U16_MAX; // Disable top/filler placement
783 vm->m_area.add_y(em, vi, -1);
787 *mgstone_type = stone_type;
788 *biome_stone = c_biome_stone;
792 void MapgenBasic::dustTopNodes()
794 if (node_max.Y < water_level)
797 const v3s16 &em = vm->m_area.getExtent();
800 for (s16 z = node_min.Z; z <= node_max.Z; z++)
801 for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
802 Biome *biome = (Biome *)m_bmgr->getRaw(biomemap[index]);
804 if (biome->c_dust == CONTENT_IGNORE)
807 u32 vi = vm->m_area.index(x, full_node_max.Y, z);
808 content_t c_full_max = vm->m_data[vi].getContent();
811 if (c_full_max == CONTENT_AIR) {
812 y_start = full_node_max.Y - 1;
813 } else if (c_full_max == CONTENT_IGNORE) {
814 vi = vm->m_area.index(x, node_max.Y + 1, z);
815 content_t c_max = vm->m_data[vi].getContent();
817 if (c_max == CONTENT_AIR)
818 y_start = node_max.Y;
825 vi = vm->m_area.index(x, y_start, z);
826 for (s16 y = y_start; y >= node_min.Y - 1; y--) {
827 if (vm->m_data[vi].getContent() != CONTENT_AIR)
830 vm->m_area.add_y(em, vi, -1);
833 content_t c = vm->m_data[vi].getContent();
834 if (!ndef->get(c).buildable_to && c != CONTENT_IGNORE && c != biome->c_dust) {
835 vm->m_area.add_y(em, vi, 1);
836 vm->m_data[vi] = MapNode(biome->c_dust);
842 void MapgenBasic::generateCaves(s16 max_stone_y, s16 large_cave_depth)
844 if (max_stone_y < node_min.Y)
847 CavesNoiseIntersection caves_noise(ndef, m_bmgr, csize,
848 &np_cave1, &np_cave2, seed, cave_width);
850 caves_noise.generateCaves(vm, node_min, node_max, biomemap);
852 if (node_max.Y > large_cave_depth)
855 PseudoRandom ps(blockseed + 21343);
856 u32 bruises_count = ps.range(0, 2);
857 for (u32 i = 0; i < bruises_count; i++) {
858 CavesRandomWalk cave(ndef, &gennotify, seed, water_level,
859 c_water_source, CONTENT_IGNORE, lava_depth);
861 cave.makeCave(vm, node_min, node_max, &ps, true, max_stone_y, heightmap);
866 bool MapgenBasic::generateCaverns(s16 max_stone_y)
868 if (node_min.Y > max_stone_y || node_min.Y > cavern_limit)
871 CavernsNoise caverns_noise(ndef, csize, &np_cavern,
872 seed, cavern_limit, cavern_taper, cavern_threshold);
874 return caverns_noise.generateCaverns(vm, node_min, node_max);
878 void MapgenBasic::generateDungeons(s16 max_stone_y,
879 MgStoneType stone_type, content_t biome_stone)
881 if (max_stone_y < node_min.Y)
887 dp.c_water = c_water_source;
888 dp.c_river_water = c_river_water_source;
890 dp.only_in_ground = true;
891 dp.corridor_len_min = 1;
892 dp.corridor_len_max = 13;
895 dp.y_min = -MAX_MAP_GENERATION_LIMIT;
896 dp.y_max = MAX_MAP_GENERATION_LIMIT;
898 dp.np_density = nparams_dungeon_density;
899 dp.np_alt_wall = nparams_dungeon_alt_wall;
901 switch (stone_type) {
904 dp.c_wall = c_cobble;
905 dp.c_alt_wall = c_mossycobble;
906 dp.c_stair = c_stair_cobble;
908 dp.diagonal_dirs = false;
909 dp.holesize = v3s16(1, 2, 1);
910 dp.room_size_min = v3s16(4, 4, 4);
911 dp.room_size_max = v3s16(8, 6, 8);
912 dp.room_size_large_min = v3s16(8, 8, 8);
913 dp.room_size_large_max = v3s16(16, 16, 16);
914 dp.notifytype = GENNOTIFY_DUNGEON;
916 case MGSTONE_DESERT_STONE:
917 dp.c_wall = c_desert_stone;
918 dp.c_alt_wall = CONTENT_IGNORE;
919 dp.c_stair = c_stair_desert_stone;
921 dp.diagonal_dirs = true;
922 dp.holesize = v3s16(2, 3, 2);
923 dp.room_size_min = v3s16(6, 9, 6);
924 dp.room_size_max = v3s16(10, 11, 10);
925 dp.room_size_large_min = v3s16(10, 13, 10);
926 dp.room_size_large_max = v3s16(18, 21, 18);
927 dp.notifytype = GENNOTIFY_TEMPLE;
929 case MGSTONE_SANDSTONE:
930 dp.c_wall = c_sandstonebrick;
931 dp.c_alt_wall = CONTENT_IGNORE;
932 dp.c_stair = c_stair_sandstone_block;
934 dp.diagonal_dirs = false;
935 dp.holesize = v3s16(2, 2, 2);
936 dp.room_size_min = v3s16(6, 4, 6);
937 dp.room_size_max = v3s16(10, 6, 10);
938 dp.room_size_large_min = v3s16(10, 8, 10);
939 dp.room_size_large_max = v3s16(18, 16, 18);
940 dp.notifytype = GENNOTIFY_DUNGEON;
943 dp.c_wall = biome_stone;
944 dp.c_alt_wall = biome_stone;
945 dp.c_stair = biome_stone;
947 dp.diagonal_dirs = false;
948 dp.holesize = v3s16(1, 2, 1);
949 dp.room_size_min = v3s16(4, 4, 4);
950 dp.room_size_max = v3s16(8, 6, 8);
951 dp.room_size_large_min = v3s16(8, 8, 8);
952 dp.room_size_large_max = v3s16(16, 16, 16);
953 dp.notifytype = GENNOTIFY_DUNGEON;
957 DungeonGen dgen(ndef, &gennotify, &dp);
958 dgen.generate(vm, blockseed, full_node_min, full_node_max);
963 //// GenerateNotifier
966 GenerateNotifier::GenerateNotifier(u32 notify_on,
967 std::set<u32> *notify_on_deco_ids)
969 m_notify_on = notify_on;
970 m_notify_on_deco_ids = notify_on_deco_ids;
974 void GenerateNotifier::setNotifyOn(u32 notify_on)
976 m_notify_on = notify_on;
980 void GenerateNotifier::setNotifyOnDecoIds(std::set<u32> *notify_on_deco_ids)
982 m_notify_on_deco_ids = notify_on_deco_ids;
986 bool GenerateNotifier::addEvent(GenNotifyType type, v3s16 pos, u32 id)
988 if (!(m_notify_on & (1 << type)))
991 if (type == GENNOTIFY_DECORATION &&
992 m_notify_on_deco_ids->find(id) == m_notify_on_deco_ids->end())
999 m_notify_events.push_back(gne);
1005 void GenerateNotifier::getEvents(
1006 std::map<std::string, std::vector<v3s16> > &event_map,
1009 std::list<GenNotifyEvent>::iterator it;
1011 for (it = m_notify_events.begin(); it != m_notify_events.end(); ++it) {
1012 GenNotifyEvent &gn = *it;
1013 std::string name = (gn.type == GENNOTIFY_DECORATION) ?
1014 "decoration#"+ itos(gn.id) :
1015 flagdesc_gennotify[gn.type].name;
1017 event_map[name].push_back(gn.pos);
1021 m_notify_events.clear();
1030 MapgenParams::~MapgenParams()
1036 void MapgenParams::readParams(const Settings *settings)
1038 std::string seed_str;
1039 const char *seed_name = (settings == g_settings) ? "fixed_map_seed" : "seed";
1041 if (settings->getNoEx(seed_name, seed_str)) {
1042 if (!seed_str.empty())
1043 seed = read_seed(seed_str.c_str());
1045 myrand_bytes(&seed, sizeof(seed));
1048 std::string mg_name;
1049 if (settings->getNoEx("mg_name", mg_name)) {
1050 mgtype = Mapgen::getMapgenType(mg_name);
1051 if (mgtype == MAPGEN_INVALID)
1052 mgtype = MAPGEN_DEFAULT;
1055 settings->getS16NoEx("water_level", water_level);
1056 settings->getS16NoEx("mapgen_limit", mapgen_limit);
1057 settings->getS16NoEx("chunksize", chunksize);
1058 settings->getFlagStrNoEx("mg_flags", flags, flagdesc_mapgen);
1061 bparams = BiomeManager::createBiomeParams(BIOMEGEN_ORIGINAL);
1063 bparams->readParams(settings);
1064 bparams->seed = seed;
1069 void MapgenParams::writeParams(Settings *settings) const
1071 settings->set("mg_name", Mapgen::getMapgenName(mgtype));
1072 settings->setU64("seed", seed);
1073 settings->setS16("water_level", water_level);
1074 settings->setS16("mapgen_limit", mapgen_limit);
1075 settings->setS16("chunksize", chunksize);
1076 settings->setFlagStr("mg_flags", flags, flagdesc_mapgen, U32_MAX);
1079 bparams->writeParams(settings);
1082 // Calculate edges of outermost generated mapchunks (less than
1083 // 'mapgen_limit'), and corresponding exact limits for SAO entities.
1084 void MapgenParams::calcMapgenEdges()
1086 if (m_mapgen_edges_calculated)
1089 // Central chunk offset, in blocks
1090 s16 ccoff_b = -chunksize / 2;
1091 // Chunksize, in nodes
1092 s32 csize_n = chunksize * MAP_BLOCKSIZE;
1093 // Minp/maxp of central chunk, in nodes
1094 s16 ccmin = ccoff_b * MAP_BLOCKSIZE;
1095 s16 ccmax = ccmin + csize_n - 1;
1096 // Fullminp/fullmaxp of central chunk, in nodes
1097 s16 ccfmin = ccmin - MAP_BLOCKSIZE;
1098 s16 ccfmax = ccmax + MAP_BLOCKSIZE;
1099 // Effective mapgen limit, in blocks
1100 // Uses same calculation as ServerMap::blockpos_over_mapgen_limit(v3s16 p)
1101 s16 mapgen_limit_b = rangelim(mapgen_limit,
1102 0, MAX_MAP_GENERATION_LIMIT) / MAP_BLOCKSIZE;
1103 // Effective mapgen limits, in nodes
1104 s16 mapgen_limit_min = -mapgen_limit_b * MAP_BLOCKSIZE;
1105 s16 mapgen_limit_max = (mapgen_limit_b + 1) * MAP_BLOCKSIZE - 1;
1106 // Number of complete chunks from central chunk fullminp/fullmaxp
1107 // to effective mapgen limits.
1108 s16 numcmin = MYMAX((ccfmin - mapgen_limit_min) / csize_n, 0);
1109 s16 numcmax = MYMAX((mapgen_limit_max - ccfmax) / csize_n, 0);
1110 // Mapgen edges, in nodes
1111 mapgen_edge_min = ccmin - numcmin * csize_n;
1112 mapgen_edge_max = ccmax + numcmax * csize_n;
1113 // SAO position limits, in Irrlicht units
1114 m_sao_limit_min = mapgen_edge_min * BS - 3.0f;
1115 m_sao_limit_max = mapgen_edge_max * BS + 3.0f;
1117 m_mapgen_edges_calculated = true;
1121 bool MapgenParams::saoPosOverLimit(const v3f &p)
1123 if (!m_mapgen_edges_calculated)
1126 return p.X < m_sao_limit_min ||
1127 p.X > m_sao_limit_max ||
1128 p.Y < m_sao_limit_min ||
1129 p.Y > m_sao_limit_max ||
1130 p.Z < m_sao_limit_min ||
1131 p.Z > m_sao_limit_max;
1135 s32 MapgenParams::getSpawnRangeMax()
1139 return MYMIN(-mapgen_edge_min, mapgen_edge_max);