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;
302 inline bool Mapgen::isLiquidHorizontallyFlowable(u32 vi, v3s16 em)
305 vm->m_area.add_x(em, vi_neg_x, -1);
306 if (vm->m_data[vi_neg_x].getContent() != CONTENT_IGNORE) {
307 const ContentFeatures &c_nx = ndef->get(vm->m_data[vi_neg_x]);
308 if (c_nx.floodable && !c_nx.isLiquid())
312 vm->m_area.add_x(em, vi_pos_x, +1);
313 if (vm->m_data[vi_pos_x].getContent() != CONTENT_IGNORE) {
314 const ContentFeatures &c_px = ndef->get(vm->m_data[vi_pos_x]);
315 if (c_px.floodable && !c_px.isLiquid())
319 vm->m_area.add_z(em, vi_neg_z, -1);
320 if (vm->m_data[vi_neg_z].getContent() != CONTENT_IGNORE) {
321 const ContentFeatures &c_nz = ndef->get(vm->m_data[vi_neg_z]);
322 if (c_nz.floodable && !c_nz.isLiquid())
326 vm->m_area.add_z(em, vi_pos_z, +1);
327 if (vm->m_data[vi_pos_z].getContent() != CONTENT_IGNORE) {
328 const ContentFeatures &c_pz = ndef->get(vm->m_data[vi_pos_z]);
329 if (c_pz.floodable && !c_pz.isLiquid())
335 void Mapgen::updateLiquid(UniqueQueue<v3s16> *trans_liquid, v3s16 nmin, v3s16 nmax)
337 bool isignored, isliquid, wasignored, wasliquid, waschecked, waspushed;
338 const v3s16 &em = vm->m_area.getExtent();
340 for (s16 z = nmin.Z + 1; z <= nmax.Z - 1; z++)
341 for (s16 x = nmin.X + 1; x <= nmax.X - 1; x++) {
347 u32 vi = vm->m_area.index(x, nmax.Y, z);
348 for (s16 y = nmax.Y; y >= nmin.Y; y--) {
349 isignored = vm->m_data[vi].getContent() == CONTENT_IGNORE;
350 isliquid = ndef->get(vm->m_data[vi]).isLiquid();
352 if (isignored || wasignored || isliquid == wasliquid) {
353 // Neither topmost node of liquid column nor topmost node below column
356 } else if (isliquid) {
357 // This is the topmost node in the column
358 bool ispushed = false;
359 if (isLiquidHorizontallyFlowable(vi, em)) {
360 trans_liquid->push_back(v3s16(x, y, z));
363 // Remember waschecked and waspushed to avoid repeated
364 // checks/pushes in case the column consists of only this node
366 waspushed = ispushed;
368 // This is the topmost node below a liquid column
370 vm->m_area.add_y(em, vi_above, 1);
371 if (!waspushed && (ndef->get(vm->m_data[vi]).floodable ||
372 (!waschecked && isLiquidHorizontallyFlowable(vi_above, em)))) {
373 // Push back the lowest node in the column which is one
374 // node above this one
375 trans_liquid->push_back(v3s16(x, y + 1, z));
379 wasliquid = isliquid;
380 wasignored = isignored;
381 vm->m_area.add_y(em, vi, -1);
387 void Mapgen::setLighting(u8 light, v3s16 nmin, v3s16 nmax)
389 ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update", SPT_AVG);
390 VoxelArea a(nmin, nmax);
392 for (int z = a.MinEdge.Z; z <= a.MaxEdge.Z; z++) {
393 for (int y = a.MinEdge.Y; y <= a.MaxEdge.Y; y++) {
394 u32 i = vm->m_area.index(a.MinEdge.X, y, z);
395 for (int x = a.MinEdge.X; x <= a.MaxEdge.X; x++, i++)
396 vm->m_data[i].param1 = light;
402 void Mapgen::lightSpread(VoxelArea &a, v3s16 p, u8 light)
404 if (light <= 1 || !a.contains(p))
407 u32 vi = vm->m_area.index(p);
408 MapNode &n = vm->m_data[vi];
410 // Decay light in each of the banks separately
411 u8 light_day = light & 0x0F;
415 u8 light_night = light & 0xF0;
419 // Bail out only if we have no more light from either bank to propogate, or
420 // we hit a solid block that light cannot pass through.
421 if ((light_day <= (n.param1 & 0x0F) &&
422 light_night <= (n.param1 & 0xF0)) ||
423 !ndef->get(n).light_propagates)
426 // Since this recursive function only terminates when there is no light from
427 // either bank left, we need to take the max of both banks into account for
428 // the case where spreading has stopped for one light bank but not the other.
429 light = MYMAX(light_day, n.param1 & 0x0F) |
430 MYMAX(light_night, n.param1 & 0xF0);
434 lightSpread(a, p + v3s16(0, 0, 1), light);
435 lightSpread(a, p + v3s16(0, 1, 0), light);
436 lightSpread(a, p + v3s16(1, 0, 0), light);
437 lightSpread(a, p - v3s16(0, 0, 1), light);
438 lightSpread(a, p - v3s16(0, 1, 0), light);
439 lightSpread(a, p - v3s16(1, 0, 0), light);
443 void Mapgen::calcLighting(v3s16 nmin, v3s16 nmax, v3s16 full_nmin, v3s16 full_nmax,
444 bool propagate_shadow)
446 ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update", SPT_AVG);
447 //TimeTaker t("updateLighting");
449 propagateSunlight(nmin, nmax, propagate_shadow);
450 spreadLight(full_nmin, full_nmax);
452 //printf("updateLighting: %dms\n", t.stop());
456 void Mapgen::propagateSunlight(v3s16 nmin, v3s16 nmax, bool propagate_shadow)
458 //TimeTaker t("propagateSunlight");
459 VoxelArea a(nmin, nmax);
460 bool block_is_underground = (water_level >= nmax.Y);
461 const v3s16 &em = vm->m_area.getExtent();
463 // NOTE: Direct access to the low 4 bits of param1 is okay here because,
464 // by definition, sunlight will never be in the night lightbank.
466 for (int z = a.MinEdge.Z; z <= a.MaxEdge.Z; z++) {
467 for (int x = a.MinEdge.X; x <= a.MaxEdge.X; x++) {
468 // see if we can get a light value from the overtop
469 u32 i = vm->m_area.index(x, a.MaxEdge.Y + 1, z);
470 if (vm->m_data[i].getContent() == CONTENT_IGNORE) {
471 if (block_is_underground)
473 } else if ((vm->m_data[i].param1 & 0x0F) != LIGHT_SUN &&
477 vm->m_area.add_y(em, i, -1);
479 for (int y = a.MaxEdge.Y; y >= a.MinEdge.Y; y--) {
480 MapNode &n = vm->m_data[i];
481 if (!ndef->get(n).sunlight_propagates)
483 n.param1 = LIGHT_SUN;
484 vm->m_area.add_y(em, i, -1);
488 //printf("propagateSunlight: %dms\n", t.stop());
492 void Mapgen::spreadLight(v3s16 nmin, v3s16 nmax)
494 //TimeTaker t("spreadLight");
495 VoxelArea a(nmin, nmax);
497 for (int z = a.MinEdge.Z; z <= a.MaxEdge.Z; z++) {
498 for (int y = a.MinEdge.Y; y <= a.MaxEdge.Y; y++) {
499 u32 i = vm->m_area.index(a.MinEdge.X, y, z);
500 for (int x = a.MinEdge.X; x <= a.MaxEdge.X; x++, i++) {
501 MapNode &n = vm->m_data[i];
502 if (n.getContent() == CONTENT_IGNORE)
505 const ContentFeatures &cf = ndef->get(n);
506 if (!cf.light_propagates)
509 // TODO(hmmmmm): Abstract away direct param1 accesses with a
510 // wrapper, but something lighter than MapNode::get/setLight
512 u8 light_produced = cf.light_source;
514 n.param1 = light_produced | (light_produced << 4);
518 lightSpread(a, v3s16(x, y, z + 1), light);
519 lightSpread(a, v3s16(x, y + 1, z ), light);
520 lightSpread(a, v3s16(x + 1, y, z ), light);
521 lightSpread(a, v3s16(x, y, z - 1), light);
522 lightSpread(a, v3s16(x, y - 1, z ), light);
523 lightSpread(a, v3s16(x - 1, y, z ), light);
529 //printf("spreadLight: %dms\n", t.stop());
537 MapgenBasic::MapgenBasic(int mapgenid, MapgenParams *params, EmergeManager *emerge)
538 : Mapgen(mapgenid, params, emerge)
540 this->m_emerge = emerge;
541 this->m_bmgr = emerge->biomemgr;
543 //// Here, 'stride' refers to the number of elements needed to skip to index
544 //// an adjacent element for that coordinate in noise/height/biome maps
545 //// (*not* vmanip content map!)
547 // Note there is no X stride explicitly defined. Items adjacent in the X
548 // coordinate are assumed to be adjacent in memory as well (i.e. stride of 1).
550 // Number of elements to skip to get to the next Y coordinate
551 this->ystride = csize.X;
553 // Number of elements to skip to get to the next Z coordinate
554 this->zstride = csize.X * csize.Y;
556 // Z-stride value for maps oversized for 1-down overgeneration
557 this->zstride_1d = csize.X * (csize.Y + 1);
559 // Z-stride value for maps oversized for 1-up 1-down overgeneration
560 this->zstride_1u1d = csize.X * (csize.Y + 2);
562 //// Allocate heightmap
563 this->heightmap = new s16[csize.X * csize.Z];
565 //// Initialize biome generator
566 // TODO(hmmmm): should we have a way to disable biomemanager biomes?
567 biomegen = m_bmgr->createBiomeGen(BIOMEGEN_ORIGINAL, params->bparams, csize);
568 biomemap = biomegen->biomemap;
570 //// Look up some commonly used content
571 c_stone = ndef->getId("mapgen_stone");
572 c_desert_stone = ndef->getId("mapgen_desert_stone");
573 c_sandstone = ndef->getId("mapgen_sandstone");
574 c_water_source = ndef->getId("mapgen_water_source");
575 c_river_water_source = ndef->getId("mapgen_river_water_source");
576 c_lava_source = ndef->getId("mapgen_lava_source");
578 // Fall back to more basic content if not defined
579 // river_water_source cannot fallback to water_source because river water
580 // needs to be non-renewable and have a short flow range.
581 if (c_desert_stone == CONTENT_IGNORE)
582 c_desert_stone = c_stone;
583 if (c_sandstone == CONTENT_IGNORE)
584 c_sandstone = c_stone;
586 //// Content used for dungeon generation
587 c_cobble = ndef->getId("mapgen_cobble");
588 c_mossycobble = ndef->getId("mapgen_mossycobble");
589 c_stair_cobble = ndef->getId("mapgen_stair_cobble");
590 c_stair_desert_stone = ndef->getId("mapgen_stair_desert_stone");
591 c_sandstonebrick = ndef->getId("mapgen_sandstonebrick");
592 c_stair_sandstone_block = ndef->getId("mapgen_stair_sandstone_block");
594 // Fall back to more basic content if not defined
595 if (c_mossycobble == CONTENT_IGNORE)
596 c_mossycobble = c_cobble;
597 if (c_stair_cobble == CONTENT_IGNORE)
598 c_stair_cobble = c_cobble;
599 if (c_stair_desert_stone == CONTENT_IGNORE)
600 c_stair_desert_stone = c_desert_stone;
601 if (c_sandstonebrick == CONTENT_IGNORE)
602 c_sandstonebrick = c_sandstone;
603 if (c_stair_sandstone_block == CONTENT_IGNORE)
604 c_stair_sandstone_block = c_sandstonebrick;
608 MapgenBasic::~MapgenBasic()
615 void MapgenBasic::generateBiomes(MgStoneType *mgstone_type,
616 content_t *biome_stone, s16 biome_zero_level)
618 // can't generate biomes without a biome generator!
622 const v3s16 &em = vm->m_area.getExtent();
624 MgStoneType stone_type = MGSTONE_OTHER;
625 content_t c_biome_stone = c_stone;
627 noise_filler_depth->perlinMap2D(node_min.X, node_min.Z);
629 for (s16 z = node_min.Z; z <= node_max.Z; z++)
630 for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
634 u16 depth_water_top = 0;
635 u16 depth_riverbed = 0;
636 s16 biome_y_min = -MAX_MAP_GENERATION_LIMIT;
637 u32 vi = vm->m_area.index(x, node_max.Y, z);
639 // Check node at base of mapchunk above, either a node of a previously
640 // generated mapchunk or if not, a node of overgenerated base terrain.
641 content_t c_above = vm->m_data[vi + em.X].getContent();
642 bool air_above = c_above == CONTENT_AIR;
643 bool river_water_above = c_above == c_river_water_source;
644 bool water_above = c_above == c_water_source || river_water_above;
646 biomemap[index] = BIOME_NONE;
648 // If there is air or water above enable top/filler placement, otherwise force
649 // nplaced to stone level by setting a number exceeding any possible filler depth.
650 u16 nplaced = (air_above || water_above) ? 0 : U16_MAX;
652 for (s16 y = node_max.Y; y >= node_min.Y; y--) {
653 content_t c = vm->m_data[vi].getContent();
654 // Biome is (re)calculated:
655 // 1. At the surface of stone below air or water.
656 // 2. At the surface of water below air.
657 // 3. When stone or water is detected but biome has not yet been calculated.
658 // 4. When stone or water is detected just below a biome's lower limit.
659 bool is_stone_surface = (c == c_stone) &&
660 (air_above || water_above || !biome || y < biome_y_min); // 1, 3, 4
662 bool is_water_surface =
663 (c == c_water_source || c == c_river_water_source) &&
664 (air_above || !biome || y < biome_y_min); // 2, 3, 4
666 if (is_stone_surface || is_water_surface) {
667 // (Re)calculate biome
668 // Limit to +-MAX MAP GENERATION LIMIT to work with biome y_min / y_max.
669 s32 relative_y = rangelim(y - biome_zero_level,
670 -MAX_MAP_GENERATION_LIMIT, MAX_MAP_GENERATION_LIMIT);
671 biome = biomegen->getBiomeAtIndex(index, relative_y);
673 if (biomemap[index] == BIOME_NONE && is_stone_surface)
674 biomemap[index] = biome->index;
676 depth_top = biome->depth_top;
677 base_filler = MYMAX(depth_top +
678 biome->depth_filler +
679 noise_filler_depth->result[index], 0.0f);
680 depth_water_top = biome->depth_water_top;
681 depth_riverbed = biome->depth_riverbed;
682 biome_y_min = rangelim(biome->y_min + biome_zero_level,
683 -MAX_MAP_GENERATION_LIMIT, MAX_MAP_GENERATION_LIMIT);
685 // Detect stone type for dungeons during every biome calculation.
686 // If none detected the last selected biome stone is chosen.
687 if (biome->c_stone == c_stone)
688 stone_type = MGSTONE_STONE;
689 else if (biome->c_stone == c_desert_stone)
690 stone_type = MGSTONE_DESERT_STONE;
691 else if (biome->c_stone == c_sandstone)
692 stone_type = MGSTONE_SANDSTONE;
694 c_biome_stone = biome->c_stone;
698 content_t c_below = vm->m_data[vi - em.X].getContent();
700 // If the node below isn't solid, make this node stone, so that
701 // any top/filler nodes above are structurally supported.
702 // This is done by aborting the cycle of top/filler placement
703 // immediately by forcing nplaced to stone level.
704 if (c_below == CONTENT_AIR
705 || c_below == c_water_source
706 || c_below == c_river_water_source)
709 if (river_water_above) {
710 if (nplaced < depth_riverbed) {
711 vm->m_data[vi] = MapNode(biome->c_riverbed);
714 nplaced = U16_MAX; // Disable top/filler placement
715 river_water_above = false;
717 } else if (nplaced < depth_top) {
718 vm->m_data[vi] = MapNode(biome->c_top);
720 } else if (nplaced < base_filler) {
721 vm->m_data[vi] = MapNode(biome->c_filler);
724 vm->m_data[vi] = MapNode(biome->c_stone);
729 } else if (c == c_water_source) {
730 vm->m_data[vi] = MapNode((y > (s32)(water_level - depth_water_top))
731 ? biome->c_water_top : biome->c_water);
732 nplaced = 0; // Enable top/filler placement for next surface
735 } else if (c == c_river_water_source) {
736 vm->m_data[vi] = MapNode(biome->c_river_water);
737 nplaced = 0; // Enable riverbed placement for next surface
740 river_water_above = true;
741 } else if (c == CONTENT_AIR) {
742 nplaced = 0; // Enable top/filler placement for next surface
745 } else { // Possible various nodes overgenerated from neighbouring mapchunks
746 nplaced = U16_MAX; // Disable top/filler placement
751 vm->m_area.add_y(em, vi, -1);
755 *mgstone_type = stone_type;
756 *biome_stone = c_biome_stone;
760 void MapgenBasic::dustTopNodes()
762 if (node_max.Y < water_level)
765 const v3s16 &em = vm->m_area.getExtent();
768 for (s16 z = node_min.Z; z <= node_max.Z; z++)
769 for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
770 Biome *biome = (Biome *)m_bmgr->getRaw(biomemap[index]);
772 if (biome->c_dust == CONTENT_IGNORE)
775 u32 vi = vm->m_area.index(x, full_node_max.Y, z);
776 content_t c_full_max = vm->m_data[vi].getContent();
779 if (c_full_max == CONTENT_AIR) {
780 y_start = full_node_max.Y - 1;
781 } else if (c_full_max == CONTENT_IGNORE) {
782 vi = vm->m_area.index(x, node_max.Y + 1, z);
783 content_t c_max = vm->m_data[vi].getContent();
785 if (c_max == CONTENT_AIR)
786 y_start = node_max.Y;
793 vi = vm->m_area.index(x, y_start, z);
794 for (s16 y = y_start; y >= node_min.Y - 1; y--) {
795 if (vm->m_data[vi].getContent() != CONTENT_AIR)
798 vm->m_area.add_y(em, vi, -1);
801 content_t c = vm->m_data[vi].getContent();
802 if (!ndef->get(c).buildable_to && c != CONTENT_IGNORE && c != biome->c_dust) {
803 vm->m_area.add_y(em, vi, 1);
804 vm->m_data[vi] = MapNode(biome->c_dust);
810 void MapgenBasic::generateCaves(s16 max_stone_y, s16 large_cave_depth)
812 if (max_stone_y < node_min.Y)
815 CavesNoiseIntersection caves_noise(ndef, m_bmgr, csize,
816 &np_cave1, &np_cave2, seed, cave_width);
818 caves_noise.generateCaves(vm, node_min, node_max, biomemap);
820 if (node_max.Y > large_cave_depth)
823 PseudoRandom ps(blockseed + 21343);
824 u32 bruises_count = ps.range(0, 2);
825 for (u32 i = 0; i < bruises_count; i++) {
826 CavesRandomWalk cave(ndef, &gennotify, seed, water_level,
827 c_water_source, CONTENT_IGNORE, lava_depth);
829 cave.makeCave(vm, node_min, node_max, &ps, true, max_stone_y, heightmap);
834 bool MapgenBasic::generateCaverns(s16 max_stone_y)
836 if (node_min.Y > max_stone_y || node_min.Y > cavern_limit)
839 CavernsNoise caverns_noise(ndef, csize, &np_cavern,
840 seed, cavern_limit, cavern_taper, cavern_threshold);
842 return caverns_noise.generateCaverns(vm, node_min, node_max);
846 void MapgenBasic::generateDungeons(s16 max_stone_y,
847 MgStoneType stone_type, content_t biome_stone)
849 if (max_stone_y < node_min.Y)
855 dp.c_water = c_water_source;
856 dp.c_river_water = c_river_water_source;
858 dp.only_in_ground = true;
859 dp.corridor_len_min = 1;
860 dp.corridor_len_max = 13;
863 dp.y_min = -MAX_MAP_GENERATION_LIMIT;
864 dp.y_max = MAX_MAP_GENERATION_LIMIT;
866 dp.np_density = nparams_dungeon_density;
867 dp.np_alt_wall = nparams_dungeon_alt_wall;
869 switch (stone_type) {
872 dp.c_wall = c_cobble;
873 dp.c_alt_wall = c_mossycobble;
874 dp.c_stair = c_stair_cobble;
876 dp.diagonal_dirs = false;
877 dp.holesize = v3s16(1, 2, 1);
878 dp.room_size_min = v3s16(4, 4, 4);
879 dp.room_size_max = v3s16(8, 6, 8);
880 dp.room_size_large_min = v3s16(8, 8, 8);
881 dp.room_size_large_max = v3s16(16, 16, 16);
882 dp.notifytype = GENNOTIFY_DUNGEON;
884 case MGSTONE_DESERT_STONE:
885 dp.c_wall = c_desert_stone;
886 dp.c_alt_wall = CONTENT_IGNORE;
887 dp.c_stair = c_stair_desert_stone;
889 dp.diagonal_dirs = true;
890 dp.holesize = v3s16(2, 3, 2);
891 dp.room_size_min = v3s16(6, 9, 6);
892 dp.room_size_max = v3s16(10, 11, 10);
893 dp.room_size_large_min = v3s16(10, 13, 10);
894 dp.room_size_large_max = v3s16(18, 21, 18);
895 dp.notifytype = GENNOTIFY_TEMPLE;
897 case MGSTONE_SANDSTONE:
898 dp.c_wall = c_sandstonebrick;
899 dp.c_alt_wall = CONTENT_IGNORE;
900 dp.c_stair = c_stair_sandstone_block;
902 dp.diagonal_dirs = false;
903 dp.holesize = v3s16(2, 2, 2);
904 dp.room_size_min = v3s16(6, 4, 6);
905 dp.room_size_max = v3s16(10, 6, 10);
906 dp.room_size_large_min = v3s16(10, 8, 10);
907 dp.room_size_large_max = v3s16(18, 16, 18);
908 dp.notifytype = GENNOTIFY_DUNGEON;
911 dp.c_wall = biome_stone;
912 dp.c_alt_wall = biome_stone;
913 dp.c_stair = biome_stone;
915 dp.diagonal_dirs = false;
916 dp.holesize = v3s16(1, 2, 1);
917 dp.room_size_min = v3s16(4, 4, 4);
918 dp.room_size_max = v3s16(8, 6, 8);
919 dp.room_size_large_min = v3s16(8, 8, 8);
920 dp.room_size_large_max = v3s16(16, 16, 16);
921 dp.notifytype = GENNOTIFY_DUNGEON;
925 DungeonGen dgen(ndef, &gennotify, &dp);
926 dgen.generate(vm, blockseed, full_node_min, full_node_max);
931 //// GenerateNotifier
934 GenerateNotifier::GenerateNotifier(u32 notify_on,
935 std::set<u32> *notify_on_deco_ids)
937 m_notify_on = notify_on;
938 m_notify_on_deco_ids = notify_on_deco_ids;
942 void GenerateNotifier::setNotifyOn(u32 notify_on)
944 m_notify_on = notify_on;
948 void GenerateNotifier::setNotifyOnDecoIds(std::set<u32> *notify_on_deco_ids)
950 m_notify_on_deco_ids = notify_on_deco_ids;
954 bool GenerateNotifier::addEvent(GenNotifyType type, v3s16 pos, u32 id)
956 if (!(m_notify_on & (1 << type)))
959 if (type == GENNOTIFY_DECORATION &&
960 m_notify_on_deco_ids->find(id) == m_notify_on_deco_ids->end())
967 m_notify_events.push_back(gne);
973 void GenerateNotifier::getEvents(
974 std::map<std::string, std::vector<v3s16> > &event_map,
977 std::list<GenNotifyEvent>::iterator it;
979 for (it = m_notify_events.begin(); it != m_notify_events.end(); ++it) {
980 GenNotifyEvent &gn = *it;
981 std::string name = (gn.type == GENNOTIFY_DECORATION) ?
982 "decoration#"+ itos(gn.id) :
983 flagdesc_gennotify[gn.type].name;
985 event_map[name].push_back(gn.pos);
989 m_notify_events.clear();
998 MapgenParams::~MapgenParams()
1004 void MapgenParams::readParams(const Settings *settings)
1006 std::string seed_str;
1007 const char *seed_name = (settings == g_settings) ? "fixed_map_seed" : "seed";
1009 if (settings->getNoEx(seed_name, seed_str)) {
1010 if (!seed_str.empty())
1011 seed = read_seed(seed_str.c_str());
1013 myrand_bytes(&seed, sizeof(seed));
1016 std::string mg_name;
1017 if (settings->getNoEx("mg_name", mg_name)) {
1018 mgtype = Mapgen::getMapgenType(mg_name);
1019 if (mgtype == MAPGEN_INVALID)
1020 mgtype = MAPGEN_DEFAULT;
1023 settings->getS16NoEx("water_level", water_level);
1024 settings->getS16NoEx("mapgen_limit", mapgen_limit);
1025 settings->getS16NoEx("chunksize", chunksize);
1026 settings->getFlagStrNoEx("mg_flags", flags, flagdesc_mapgen);
1029 bparams = BiomeManager::createBiomeParams(BIOMEGEN_ORIGINAL);
1031 bparams->readParams(settings);
1032 bparams->seed = seed;
1037 void MapgenParams::writeParams(Settings *settings) const
1039 settings->set("mg_name", Mapgen::getMapgenName(mgtype));
1040 settings->setU64("seed", seed);
1041 settings->setS16("water_level", water_level);
1042 settings->setS16("mapgen_limit", mapgen_limit);
1043 settings->setS16("chunksize", chunksize);
1044 settings->setFlagStr("mg_flags", flags, flagdesc_mapgen, U32_MAX);
1047 bparams->writeParams(settings);
1050 // Calculate edges of outermost generated mapchunks (less than
1051 // 'mapgen_limit'), and corresponding exact limits for SAO entities.
1052 void MapgenParams::calcMapgenEdges()
1054 if (m_mapgen_edges_calculated)
1057 // Central chunk offset, in blocks
1058 s16 ccoff_b = -chunksize / 2;
1059 // Chunksize, in nodes
1060 s32 csize_n = chunksize * MAP_BLOCKSIZE;
1061 // Minp/maxp of central chunk, in nodes
1062 s16 ccmin = ccoff_b * MAP_BLOCKSIZE;
1063 s16 ccmax = ccmin + csize_n - 1;
1064 // Fullminp/fullmaxp of central chunk, in nodes
1065 s16 ccfmin = ccmin - MAP_BLOCKSIZE;
1066 s16 ccfmax = ccmax + MAP_BLOCKSIZE;
1067 // Effective mapgen limit, in blocks
1068 // Uses same calculation as ServerMap::blockpos_over_mapgen_limit(v3s16 p)
1069 s16 mapgen_limit_b = rangelim(mapgen_limit,
1070 0, MAX_MAP_GENERATION_LIMIT) / MAP_BLOCKSIZE;
1071 // Effective mapgen limits, in nodes
1072 s16 mapgen_limit_min = -mapgen_limit_b * MAP_BLOCKSIZE;
1073 s16 mapgen_limit_max = (mapgen_limit_b + 1) * MAP_BLOCKSIZE - 1;
1074 // Number of complete chunks from central chunk fullminp/fullmaxp
1075 // to effective mapgen limits.
1076 s16 numcmin = MYMAX((ccfmin - mapgen_limit_min) / csize_n, 0);
1077 s16 numcmax = MYMAX((mapgen_limit_max - ccfmax) / csize_n, 0);
1078 // Mapgen edges, in nodes
1079 mapgen_edge_min = ccmin - numcmin * csize_n;
1080 mapgen_edge_max = ccmax + numcmax * csize_n;
1081 // SAO position limits, in Irrlicht units
1082 m_sao_limit_min = mapgen_edge_min * BS - 3.0f;
1083 m_sao_limit_max = mapgen_edge_max * BS + 3.0f;
1085 m_mapgen_edges_calculated = true;
1089 bool MapgenParams::saoPosOverLimit(const v3f &p)
1091 if (!m_mapgen_edges_calculated)
1094 return p.X < m_sao_limit_min ||
1095 p.X > m_sao_limit_max ||
1096 p.Y < m_sao_limit_min ||
1097 p.Y > m_sao_limit_max ||
1098 p.Z < m_sao_limit_min ||
1099 p.Z > m_sao_limit_max;
1103 s32 MapgenParams::getSpawnRangeMax()
1107 return MYMIN(-mapgen_edge_min, mapgen_edge_max);