3 Copyright (C) 2010-2011 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 //#include "serverobject.h"
28 #include "content_sao.h"
30 #include "content_mapnode.h" // For content_mapnode_get_new_name
31 #include "voxelalgorithms.h"
33 #include "settings.h" // For g_settings
34 #include "main.h" // For g_profiler
37 /////////////////// Mapgen V6 perlin noise default values
38 NoiseParams nparams_v6_def_terrain_base =
39 {-AVERAGE_MUD_AMOUNT, 20.0, v3f(250.0, 250.0, 250.0), 82341, 5, 0.6};
40 NoiseParams nparams_v6_def_terrain_higher =
41 {20.0, 16.0, v3f(500.0, 500.0, 500.0), 85039, 5, 0.6};
42 NoiseParams nparams_v6_def_steepness =
43 {0.85, 0.5, v3f(125.0, 125.0, 125.0), -932, 5, 0.7};
44 NoiseParams nparams_v6_def_height_select =
45 {0.5, 1.0, v3f(250.0, 250.0, 250.0), 4213, 5, 0.69};
46 NoiseParams nparams_v6_def_trees =
47 {0.0, 1.0, v3f(125.0, 125.0, 125.0), 2, 4, 0.66};
48 NoiseParams nparams_v6_def_mud =
49 {AVERAGE_MUD_AMOUNT, 2.0, v3f(200.0, 200.0, 200.0), 91013, 3, 0.55};
50 NoiseParams nparams_v6_def_beach =
51 {0.0, 1.0, v3f(250.0, 250.0, 250.0), 59420, 3, 0.50};
52 NoiseParams nparams_v6_def_biome =
53 {0.0, 1.0, v3f(250.0, 250.0, 250.0), 9130, 3, 0.50};
54 NoiseParams nparams_v6_def_cave =
55 {6.0, 6.0, v3f(250.0, 250.0, 250.0), 34329, 3, 0.50};
57 /////////////////// Mapgen V7 perlin noise default values
58 NoiseParams nparams_v7_def_terrain =
59 {10.0, 12.0, v3f(350., 350., 350.), 82341, 5, 0.6}; //terrain
60 NoiseParams nparams_v7_def_bgroup =
61 {0.5, 1/(2*1.6), v3f(350., 350., 350.), 5923, 2, 0.60}; //0 to 1
62 NoiseParams nparams_v7_def_heat =
63 {25.0, 50.0, v3f(500., 500., 500.), 35293, 1, 0.00}; //-25 to 75
64 NoiseParams nparams_v7_def_humidity =
65 {50, 100/(2*1.6), v3f(750., 750., 750.), 12094, 2, 0.60}; //0 to 100
68 ///////////////////////////////////////////////////////////////////////////////
71 MapgenV7::MapgenV7(BiomeDefManager *biomedef, int mapgenid, MapgenV7Params *params) {
72 this->generating = false;
74 this->biomedef = biomedef;
75 this->ndef = biomedef->ndef;
77 this->seed = (int)params->seed;
78 this->csize = v3s16(1, 1, 1) * params->chunksize * MAP_BLOCKSIZE;
79 this->water_level = params->water_level;
81 noise_terrain = new Noise(params->np_terrain, seed, csize.X, csize.Y);
82 noise_bgroup = new Noise(params->np_bgroup, seed, csize.X, csize.Y);
83 noise_heat = new Noise(params->np_heat, seed, csize.X, csize.Y);
84 noise_humidity = new Noise(params->np_humidity, seed, csize.X, csize.Y);
87 n_air = MapNode(ndef->getId("mapgen_air"));
88 n_water = MapNode(ndef->getId("mapgen_water_source"));
89 n_lava = MapNode(ndef->getId("mapgen_lava_source"));
93 MapgenV7::~MapgenV7() {
97 delete noise_humidity;
101 void MapgenV7::makeChunk(BlockMakeData *data) {
105 assert(data->vmanip);
106 assert(data->nodedef);
107 assert(data->blockpos_requested.X >= data->blockpos_min.X &&
108 data->blockpos_requested.Y >= data->blockpos_min.Y &&
109 data->blockpos_requested.Z >= data->blockpos_min.Z);
110 assert(data->blockpos_requested.X <= data->blockpos_max.X &&
111 data->blockpos_requested.Y <= data->blockpos_max.Y &&
112 data->blockpos_requested.Z <= data->blockpos_max.Z);
114 this->generating = true;
117 this->vmanip = data->vmanip;
118 v3s16 em = vmanip->m_area.getExtent();
119 this->ystride = em.X;
120 this->zstride = em.Y * em.X;
122 node_min = (data->blockpos_min) * MAP_BLOCKSIZE;
123 node_max = (data->blockpos_max + v3s16(1, 1, 1)) * MAP_BLOCKSIZE - v3s16(1, 1, 1);
124 v3s16 full_node_min = (data->blockpos_min - 1) * MAP_BLOCKSIZE;
125 v3s16 full_node_max = (data->blockpos_max + 2) * MAP_BLOCKSIZE - v3s16(1,1,1);
132 TimeTaker timer("Generating terrain");
133 map_terrain = noise_terrain->perlinMap2D(x, z);
134 map_bgroup = noise_bgroup->perlinMap2D(x, z);
135 map_heat = noise_heat->perlinMap2D(x, z);
136 map_humidity = noise_humidity->perlinMap2D(x, z);
138 noise_bgroup->transformNoiseMap();
139 noise_heat->transformNoiseMap();
140 noise_humidity->transformNoiseMap();
143 for (z = node_min.Z; z <= node_max.Z; z++) {
144 for (x = node_min.X; x <= node_max.X; x++) {
145 Biome *biome = biomedef->getBiome(map_bgroup[i], map_heat[i], map_humidity[i]);
146 biome->genColumn(this, x, z, y1, y2);
154 //add blobs of dirt and gravel underground
156 updateLiquid(full_node_min, full_node_max);
157 updateLighting(node_min, node_max);
159 this->generating = false;
163 void MapgenV7::updateLiquid(v3s16 nmin, v3s16 nmax) {
164 bool isliquid, wasliquid;
167 for (s16 z = nmin.Z; z <= nmax.Z; z++) {
168 for (s16 x = nmin.X; x <= nmax.X; x++) {
171 v3s16 em = vmanip->m_area.getExtent();
172 i = vmanip->m_area.index(v3s16(p2d.X, nmax.Y, p2d.Y));
174 for (s16 y = nmax.Y; y >= nmin.Y; y--) {
175 isliquid = ndef->get(vmanip->m_data[i]).isLiquid();
176 //there was a change between liquid and nonliquid, add to queue
177 if (isliquid != wasliquid)
178 data->transforming_liquid.push_back(v3s16(p2d.X, y, p2d.Y));
180 wasliquid = isliquid;
181 vmanip->m_area.add_y(em, i, -1);
188 void MapgenV7::updateLighting(v3s16 nmin, v3s16 nmax) {
189 enum LightBank banks[2] = {LIGHTBANK_DAY, LIGHTBANK_NIGHT};
191 VoxelArea a(nmin - v3s16(1,0,1) * MAP_BLOCKSIZE,
192 nmax + v3s16(1,0,1) * MAP_BLOCKSIZE);
193 bool block_is_underground = (water_level > nmax.Y);
194 bool sunlight = !block_is_underground;
196 ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update", SPT_AVG);
197 for (int i = 0; i < 2; i++) {
198 enum LightBank bank = banks[i];
199 core::map<v3s16, bool> light_sources;
200 core::map<v3s16, u8> unlight_from;
202 voxalgo::clearLightAndCollectSources(*vmanip, a, bank, ndef,
203 light_sources, unlight_from);
204 voxalgo::propagateSunlight(*vmanip, a, sunlight, light_sources, ndef);
205 //printf("light_sources: %d\t\tunlight_from: %d\n", light_sources.size(), unlight_from.size());
206 vmanip->unspreadLight(bank, unlight_from, light_sources, ndef);
207 vmanip->spreadLight(bank, light_sources, ndef);
212 Biome *MapgenV7::getBiomeAtPoint(v3s16 p) {
213 float bgroup = NoisePerlin2D(noise_bgroup->np, p.X, p.Y, seed);
214 float heat = NoisePerlin2D(noise_heat->np, p.X, p.Y, seed);
215 float humidity = NoisePerlin2D(noise_humidity->np, p.X, p.Y, seed);
216 return biomedef->getBiome(bgroup, heat, humidity);
220 //FIXME: This assumes y == 0, that is, always in a non-hell/non-sky biome
221 int MapgenV7::getGroundLevelAtPoint(v2s16 p) {
222 float terrain = NoisePerlin2D(noise_terrain->np, p.X, p.Y, seed);
223 Biome *biome = getBiomeAtPoint(v3s16(p.X, p.Y, 0));
224 return biome->getSurfaceHeight(terrain);
228 /////////////////////////////// Emerge Manager ////////////////////////////////
232 EmergeManager::EmergeManager(IGameDef *gamedef, BiomeDefManager *bdef,
233 MapgenParams *mgparams) {
234 //the order of these assignments is pretty important
235 this->biomedef = bdef ? bdef : new BiomeDefManager(gamedef);
236 this->params = mgparams;
238 this->mapgen = getMapgen();
242 EmergeManager::~EmergeManager() {
248 Mapgen *EmergeManager::getMapgen() {
250 switch (params->mg_version) {
252 mapgen = new MapgenV6(0, (MapgenV6Params *)params);
255 mapgen = new MapgenV7(biomedef, 0, (MapgenV7Params *)params);
258 errorstream << "EmergeManager: Unsupported mapgen version "
259 << params->mg_version << ", falling back to V6" << std::endl;
260 params->mg_version = 6;
261 mapgen = new MapgenV6(0, (MapgenV6Params *)params);
268 void EmergeManager::addBlockToQueue() {
273 int EmergeManager::getGroundLevelAtPoint(v2s16 p) {
276 return mapgen->getGroundLevelAtPoint(p);
280 bool EmergeManager::isBlockUnderground(v3s16 blockpos) {
282 v2s16 p = v2s16((blockpos.X * MAP_BLOCKSIZE) + MAP_BLOCKSIZE / 2,
283 (blockpos.Y * MAP_BLOCKSIZE) + MAP_BLOCKSIZE / 2);
284 int ground_level = getGroundLevelAtPoint(p);
285 return blockpos.Y * (MAP_BLOCKSIZE + 1) <= min(water_level, ground_level);
288 //yuck, but then again, should i bother being accurate?
289 //the height of the nodes in a single block is quite variable
290 return blockpos.Y * (MAP_BLOCKSIZE + 1) <= params->water_level;
294 u32 EmergeManager::getBlockSeed(v3s16 p) {
295 return (u32)(params->seed & 0xFFFFFFFF) +
302 MapgenParams *MapgenParams::createMapgenParams(int mgver) {
305 return new MapgenV6Params();
307 return new MapgenV7Params();
308 default: //instead of complaining, default to 6
309 return new MapgenV6Params();
314 MapgenParams *MapgenParams::getParamsFromSettings(Settings *settings) {
315 int mg_version = settings->getS16("mg_version");
316 MapgenParams *mgparams = MapgenParams::createMapgenParams(mg_version);
317 mgparams->mg_version = mg_version;
318 mgparams->seed = settings->getU64(settings == g_settings ? "fixed_map_seed" : "seed");
319 mgparams->water_level = settings->getS16("water_level");
320 mgparams->chunksize = settings->getS16("chunksize");
321 mgparams->flags = settings->getS32("mg_flags");
323 switch (mg_version) {
326 MapgenV6Params *v6params = (MapgenV6Params *)mgparams;
328 v6params->freq_desert = settings->getFloat("mgv6_freq_desert");
329 v6params->freq_beach = settings->getFloat("mgv6_freq_beach");
330 v6params->np_terrain_base = settings->getNoiseParams("mgv6_np_terrain_base");
331 v6params->np_terrain_higher = settings->getNoiseParams("mgv6_np_terrain_higher");
332 v6params->np_steepness = settings->getNoiseParams("mgv6_np_steepness");
333 v6params->np_height_select = settings->getNoiseParams("mgv6_np_height_select");
334 v6params->np_trees = settings->getNoiseParams("mgv6_np_trees");
335 v6params->np_mud = settings->getNoiseParams("mgv6_np_mud");
336 v6params->np_beach = settings->getNoiseParams("mgv6_np_beach");
337 v6params->np_biome = settings->getNoiseParams("mgv6_np_biome");
338 v6params->np_cave = settings->getNoiseParams("mgv6_np_cave");
340 if (!v6params->np_terrain_base || !v6params->np_terrain_higher ||
341 !v6params->np_steepness || !v6params->np_height_select ||
342 !v6params->np_trees || !v6params->np_mud ||
343 !v6params->np_beach || !v6params->np_biome || !v6params->np_cave) {
352 MapgenV7Params *v7params = (MapgenV7Params *)mgparams;
354 v7params->np_terrain = settings->getNoiseParams("mgv7_np_terrain");
355 v7params->np_bgroup = settings->getNoiseParams("mgv7_np_bgroup");
356 v7params->np_heat = settings->getNoiseParams("mgv7_np_heat");
357 v7params->np_humidity = settings->getNoiseParams("mgv7_np_humidity");
359 if (!v7params->np_terrain || !v7params->np_bgroup ||
360 !v7params->np_heat || !v7params->np_humidity) {
377 /////////////////////////////////// legacy static functions for farmesh
380 s16 Mapgen::find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision) {
381 //just need to return something
387 bool Mapgen::get_have_beach(u64 seed, v2s16 p2d) {
388 double sandnoise = noise2d_perlin(
389 0.2+(float)p2d.X/250, 0.7+(float)p2d.Y/250,
390 seed+59420, 3, 0.50);
392 return (sandnoise > 0.15);
396 double Mapgen::tree_amount_2d(u64 seed, v2s16 p) {
397 double noise = noise2d_perlin(
398 0.5+(float)p.X/125, 0.5+(float)p.Y/125,
400 double zeroval = -0.39;
404 return 0.04 * (noise-zeroval) / (1.0-zeroval);
408 #if 0 /// BIG COMMENT
413 Some helper functions for the map generator
417 // Returns Y one under area minimum if not found
418 static s16 find_ground_level(VoxelManipulator &vmanip, v2s16 p2d,
419 INodeDefManager *ndef)
421 v3s16 em = vmanip.m_area.getExtent();
422 s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
423 s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
424 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
426 for(y=y_nodes_max; y>=y_nodes_min; y--)
428 MapNode &n = vmanip.m_data[i];
429 if(ndef->get(n).walkable)
432 vmanip.m_area.add_y(em, i, -1);
437 return y_nodes_min - 1;
441 // Returns Y one under area minimum if not found
442 static s16 find_ground_level_clever(VoxelManipulator &vmanip, v2s16 p2d,
443 INodeDefManager *ndef)
445 if(!vmanip.m_area.contains(v3s16(p2d.X, vmanip.m_area.MaxEdge.Y, p2d.Y)))
446 return vmanip.m_area.MinEdge.Y-1;
447 v3s16 em = vmanip.m_area.getExtent();
448 s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
449 s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
450 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
452 content_t c_tree = ndef->getId("mapgen_tree");
453 content_t c_leaves = ndef->getId("mapgen_leaves");
454 for(y=y_nodes_max; y>=y_nodes_min; y--)
456 MapNode &n = vmanip.m_data[i];
457 if(ndef->get(n).walkable
458 && n.getContent() != c_tree
459 && n.getContent() != c_leaves)
462 vmanip.m_area.add_y(em, i, -1);
467 return y_nodes_min - 1;
471 // Returns Y one under area minimum if not found
472 static s16 find_stone_level(VoxelManipulator &vmanip, v2s16 p2d,
473 INodeDefManager *ndef)
475 v3s16 em = vmanip.m_area.getExtent();
476 s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
477 s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
478 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
480 content_t c_stone = ndef->getId("mapgen_stone");
481 content_t c_desert_stone = ndef->getId("mapgen_desert_stone");
482 for(y=y_nodes_max; y>=y_nodes_min; y--)
484 MapNode &n = vmanip.m_data[i];
485 content_t c = n.getContent();
486 if(c != CONTENT_IGNORE && (
487 c == c_stone || c == c_desert_stone))
490 vmanip.m_area.add_y(em, i, -1);
495 return y_nodes_min - 1;
502 static void make_papyrus(VoxelManipulator &vmanip, v3s16 p0,
503 INodeDefManager *ndef)
505 MapNode papyrusnode(ndef->getId("mapgen_papyrus"));
507 s16 trunk_h = myrand_range(2, 3);
509 for(s16 ii=0; ii<trunk_h; ii++)
511 if(vmanip.m_area.contains(p1))
512 vmanip.m_data[vmanip.m_area.index(p1)] = papyrusnode;
517 static void make_cactus(VoxelManipulator &vmanip, v3s16 p0,
518 INodeDefManager *ndef)
520 MapNode cactusnode(ndef->getId("mapgen_cactus"));
524 for(s16 ii=0; ii<trunk_h; ii++)
526 if(vmanip.m_area.contains(p1))
527 vmanip.m_data[vmanip.m_area.index(p1)] = cactusnode;
535 Dungeon making routines
538 #define VMANIP_FLAG_DUNGEON_INSIDE VOXELFLAG_CHECKED1
539 #define VMANIP_FLAG_DUNGEON_PRESERVE VOXELFLAG_CHECKED2
540 #define VMANIP_FLAG_DUNGEON_UNTOUCHABLE (\
541 VMANIP_FLAG_DUNGEON_INSIDE|VMANIP_FLAG_DUNGEON_PRESERVE)
543 static void make_room1(VoxelManipulator &vmanip, v3s16 roomsize, v3s16 roomplace,
544 INodeDefManager *ndef)
547 for(s16 z=0; z<roomsize.Z; z++)
548 for(s16 y=0; y<roomsize.Y; y++)
551 v3s16 p = roomplace + v3s16(0,y,z);
552 if(vmanip.m_area.contains(p) == false)
554 u32 vi = vmanip.m_area.index(p);
555 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
557 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
560 v3s16 p = roomplace + v3s16(roomsize.X-1,y,z);
561 if(vmanip.m_area.contains(p) == false)
563 u32 vi = vmanip.m_area.index(p);
564 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
566 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
571 for(s16 x=0; x<roomsize.X; x++)
572 for(s16 y=0; y<roomsize.Y; y++)
575 v3s16 p = roomplace + v3s16(x,y,0);
576 if(vmanip.m_area.contains(p) == false)
578 u32 vi = vmanip.m_area.index(p);
579 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
581 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
584 v3s16 p = roomplace + v3s16(x,y,roomsize.Z-1);
585 if(vmanip.m_area.contains(p) == false)
587 u32 vi = vmanip.m_area.index(p);
588 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
590 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
594 // Make +-Y walls (floor and ceiling)
595 for(s16 z=0; z<roomsize.Z; z++)
596 for(s16 x=0; x<roomsize.X; x++)
599 v3s16 p = roomplace + v3s16(x,0,z);
600 if(vmanip.m_area.contains(p) == false)
602 u32 vi = vmanip.m_area.index(p);
603 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
605 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
608 v3s16 p = roomplace + v3s16(x,roomsize.Y-1,z);
609 if(vmanip.m_area.contains(p) == false)
611 u32 vi = vmanip.m_area.index(p);
612 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
614 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
619 for(s16 z=1; z<roomsize.Z-1; z++)
620 for(s16 y=1; y<roomsize.Y-1; y++)
621 for(s16 x=1; x<roomsize.X-1; x++)
623 v3s16 p = roomplace + v3s16(x,y,z);
624 if(vmanip.m_area.contains(p) == false)
626 u32 vi = vmanip.m_area.index(p);
627 vmanip.m_flags[vi] |= VMANIP_FLAG_DUNGEON_UNTOUCHABLE;
628 vmanip.m_data[vi] = MapNode(CONTENT_AIR);
632 static void make_fill(VoxelManipulator &vmanip, v3s16 place, v3s16 size,
633 u8 avoid_flags, MapNode n, u8 or_flags)
635 for(s16 z=0; z<size.Z; z++)
636 for(s16 y=0; y<size.Y; y++)
637 for(s16 x=0; x<size.X; x++)
639 v3s16 p = place + v3s16(x,y,z);
640 if(vmanip.m_area.contains(p) == false)
642 u32 vi = vmanip.m_area.index(p);
643 if(vmanip.m_flags[vi] & avoid_flags)
645 vmanip.m_flags[vi] |= or_flags;
646 vmanip.m_data[vi] = n;
650 static void make_hole1(VoxelManipulator &vmanip, v3s16 place,
651 INodeDefManager *ndef)
653 make_fill(vmanip, place, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
654 VMANIP_FLAG_DUNGEON_INSIDE);
657 static void make_door1(VoxelManipulator &vmanip, v3s16 doorplace, v3s16 doordir,
658 INodeDefManager *ndef)
660 make_hole1(vmanip, doorplace, ndef);
661 // Place torch (for testing)
662 //vmanip.m_data[vmanip.m_area.index(doorplace)] = MapNode(ndef->getId("mapgen_torch"));
665 static v3s16 rand_ortho_dir(PseudoRandom &random)
667 if(random.next()%2==0)
668 return random.next()%2 ? v3s16(-1,0,0) : v3s16(1,0,0);
670 return random.next()%2 ? v3s16(0,0,-1) : v3s16(0,0,1);
673 static v3s16 turn_xz(v3s16 olddir, int t)
693 static v3s16 random_turn(PseudoRandom &random, v3s16 olddir)
695 int turn = random.range(0,2);
704 dir = turn_xz(olddir, 0);
707 dir = turn_xz(olddir, 1);
711 static void make_corridor(VoxelManipulator &vmanip, v3s16 doorplace,
712 v3s16 doordir, v3s16 &result_place, v3s16 &result_dir,
713 PseudoRandom &random, INodeDefManager *ndef)
715 make_hole1(vmanip, doorplace, ndef);
716 v3s16 p0 = doorplace;
720 length = random.range(1,13);
722 length = random.range(1,6);
723 length = random.range(1,13);
724 u32 partlength = random.range(1,13);
727 if(random.next()%2 == 0 && partlength >= 3)
728 make_stairs = random.next()%2 ? 1 : -1;
729 for(u32 i=0; i<length; i++)
735 /*// If already empty
736 if(vmanip.getNodeNoExNoEmerge(p).getContent()
738 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
743 if(vmanip.m_area.contains(p) == true
744 && vmanip.m_area.contains(p+v3s16(0,1,0)) == true)
748 make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,5,3),
749 VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(ndef->getId("mapgen_cobble")), 0);
750 make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
751 VMANIP_FLAG_DUNGEON_INSIDE);
752 make_fill(vmanip, p-dir, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
753 VMANIP_FLAG_DUNGEON_INSIDE);
757 make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,4,3),
758 VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(ndef->getId("mapgen_cobble")), 0);
759 make_hole1(vmanip, p, ndef);
760 /*make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
761 VMANIP_FLAG_DUNGEON_INSIDE);*/
768 // Can't go here, turn away
769 dir = turn_xz(dir, random.range(0,1));
770 make_stairs = -make_stairs;
772 partlength = random.range(1,length);
777 if(partcount >= partlength)
781 dir = random_turn(random, dir);
783 partlength = random.range(1,length);
786 if(random.next()%2 == 0 && partlength >= 3)
787 make_stairs = random.next()%2 ? 1 : -1;
798 RoomWalker(VoxelManipulator &vmanip_, v3s16 pos, PseudoRandom &random,
799 INodeDefManager *ndef):
810 m_dir = rand_ortho_dir(m_random);
813 void setPos(v3s16 pos)
818 void setDir(v3s16 dir)
823 bool findPlaceForDoor(v3s16 &result_place, v3s16 &result_dir)
825 for(u32 i=0; i<100; i++)
827 v3s16 p = m_pos + m_dir;
828 v3s16 p1 = p + v3s16(0,1,0);
829 if(vmanip.m_area.contains(p) == false
830 || vmanip.m_area.contains(p1) == false
836 if(vmanip.getNodeNoExNoEmerge(p).getContent()
837 == m_ndef->getId("mapgen_cobble")
838 && vmanip.getNodeNoExNoEmerge(p1).getContent()
839 == m_ndef->getId("mapgen_cobble"))
841 // Found wall, this is a good place!
844 // Randomize next direction
849 Determine where to move next
851 // Jump one up if the actual space is there
852 if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).getContent()
853 == m_ndef->getId("mapgen_cobble")
854 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
856 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,2,0)).getContent()
859 // Jump one down if the actual space is there
860 if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
861 == m_ndef->getId("mapgen_cobble")
862 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).getContent()
864 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,-1,0)).getContent()
867 // Check if walking is now possible
868 if(vmanip.getNodeNoExNoEmerge(p).getContent()
870 || vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
873 // Cannot continue walking here
883 bool findPlaceForRoomDoor(v3s16 roomsize, v3s16 &result_doorplace,
884 v3s16 &result_doordir, v3s16 &result_roomplace)
886 for(s16 trycount=0; trycount<30; trycount++)
890 bool r = findPlaceForDoor(doorplace, doordir);
894 // X east, Z north, Y up
896 if(doordir == v3s16(1,0,0)) // X+
897 roomplace = doorplace +
898 v3s16(0,-1,m_random.range(-roomsize.Z+2,-2));
899 if(doordir == v3s16(-1,0,0)) // X-
900 roomplace = doorplace +
901 v3s16(-roomsize.X+1,-1,m_random.range(-roomsize.Z+2,-2));
902 if(doordir == v3s16(0,0,1)) // Z+
903 roomplace = doorplace +
904 v3s16(m_random.range(-roomsize.X+2,-2),-1,0);
905 if(doordir == v3s16(0,0,-1)) // Z-
906 roomplace = doorplace +
907 v3s16(m_random.range(-roomsize.X+2,-2),-1,-roomsize.Z+1);
910 if(doordir == v3s16(1,0,0)) // X+
911 roomplace = doorplace + v3s16(0,-1,-roomsize.Z/2);
912 if(doordir == v3s16(-1,0,0)) // X-
913 roomplace = doorplace + v3s16(-roomsize.X+1,-1,-roomsize.Z/2);
914 if(doordir == v3s16(0,0,1)) // Z+
915 roomplace = doorplace + v3s16(-roomsize.X/2,-1,0);
916 if(doordir == v3s16(0,0,-1)) // Z-
917 roomplace = doorplace + v3s16(-roomsize.X/2,-1,-roomsize.Z+1);
922 for(s16 z=1; z<roomsize.Z-1; z++)
923 for(s16 y=1; y<roomsize.Y-1; y++)
924 for(s16 x=1; x<roomsize.X-1; x++)
926 v3s16 p = roomplace + v3s16(x,y,z);
927 if(vmanip.m_area.contains(p) == false)
932 if(vmanip.m_flags[vmanip.m_area.index(p)]
933 & VMANIP_FLAG_DUNGEON_INSIDE)
944 result_doorplace = doorplace;
945 result_doordir = doordir;
946 result_roomplace = roomplace;
953 VoxelManipulator &vmanip;
956 PseudoRandom &m_random;
957 INodeDefManager *m_ndef;
960 static void make_dungeon1(VoxelManipulator &vmanip, PseudoRandom &random,
961 INodeDefManager *ndef)
963 v3s16 areasize = vmanip.m_area.getExtent();
968 Find place for first room
971 for(u32 i=0; i<100; i++)
973 roomsize = v3s16(random.range(4,8),random.range(4,6),random.range(4,8));
974 roomplace = vmanip.m_area.MinEdge + v3s16(
975 random.range(0,areasize.X-roomsize.X-1),
976 random.range(0,areasize.Y-roomsize.Y-1),
977 random.range(0,areasize.Z-roomsize.Z-1));
979 Check that we're not putting the room to an unknown place,
980 otherwise it might end up floating in the air
983 for(s16 z=1; z<roomsize.Z-1; z++)
984 for(s16 y=1; y<roomsize.Y-1; y++)
985 for(s16 x=1; x<roomsize.X-1; x++)
987 v3s16 p = roomplace + v3s16(x,y,z);
988 u32 vi = vmanip.m_area.index(p);
989 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_INSIDE)
994 if(vmanip.m_data[vi].getContent() == CONTENT_IGNORE)
1008 Stores the center position of the last room made, so that
1009 a new corridor can be started from the last room instead of
1010 the new room, if chosen so.
1012 v3s16 last_room_center = roomplace+v3s16(roomsize.X/2,1,roomsize.Z/2);
1014 u32 room_count = random.range(2,7);
1015 for(u32 i=0; i<room_count; i++)
1017 // Make a room to the determined place
1018 make_room1(vmanip, roomsize, roomplace, ndef);
1020 v3s16 room_center = roomplace + v3s16(roomsize.X/2,1,roomsize.Z/2);
1022 // Place torch at room center (for testing)
1023 //vmanip.m_data[vmanip.m_area.index(room_center)] = MapNode(ndef->getId("mapgen_torch"));
1025 // Quit if last room
1026 if(i == room_count-1)
1029 // Determine walker start position
1031 bool start_in_last_room = (random.range(0,2)!=0);
1032 //bool start_in_last_room = true;
1034 v3s16 walker_start_place;
1036 if(start_in_last_room)
1038 walker_start_place = last_room_center;
1042 walker_start_place = room_center;
1043 // Store center of current room as the last one
1044 last_room_center = room_center;
1047 // Create walker and find a place for a door
1048 RoomWalker walker(vmanip, walker_start_place, random, ndef);
1051 bool r = walker.findPlaceForDoor(doorplace, doordir);
1055 if(random.range(0,1)==0)
1057 make_door1(vmanip, doorplace, doordir, ndef);
1059 // Don't actually make a door
1060 doorplace -= doordir;
1062 // Make a random corridor starting from the door
1064 v3s16 corridor_end_dir;
1065 make_corridor(vmanip, doorplace, doordir, corridor_end,
1066 corridor_end_dir, random, ndef);
1068 // Find a place for a random sized room
1069 roomsize = v3s16(random.range(4,8),random.range(4,6),random.range(4,8));
1070 walker.setPos(corridor_end);
1071 walker.setDir(corridor_end_dir);
1072 r = walker.findPlaceForRoomDoor(roomsize, doorplace, doordir, roomplace);
1076 if(random.range(0,1)==0)
1078 make_door1(vmanip, doorplace, doordir, ndef);
1080 // Don't actually make a door
1081 roomplace -= doordir;
1088 static void make_nc(VoxelManipulator &vmanip, PseudoRandom &random,
1089 INodeDefManager *ndef)
1093 s32 r = random.range(0, 3);
1095 dir = v3s16( 1, 0, 0);
1099 dir = v3s16(-1, 0, 0);
1103 dir = v3s16( 0, 0, 1);
1107 dir = v3s16( 0, 0,-1);
1110 v3s16 p = vmanip.m_area.MinEdge + v3s16(
1111 16+random.range(0,15),
1112 16+random.range(0,15),
1113 16+random.range(0,15));
1114 vmanip.m_data[vmanip.m_area.index(p)] = MapNode(ndef->getId("mapgen_nyancat"), facedir_i);
1115 u32 length = random.range(3,15);
1116 for(u32 j=0; j<length; j++)
1119 vmanip.m_data[vmanip.m_area.index(p)] = MapNode(ndef->getId("mapgen_nyancat_rainbow"));
1125 Noise functions. Make sure seed is mangled differently in each one.
1130 Scaling the output of the noise function affects the overdrive of the
1131 contour function, which affects the shape of the output considerably.
1133 #define CAVE_NOISE_SCALE 12.0
1134 //#define CAVE_NOISE_SCALE 10.0
1135 //#define CAVE_NOISE_SCALE 7.5
1136 //#define CAVE_NOISE_SCALE 5.0
1137 //#define CAVE_NOISE_SCALE 1.0
1139 //#define CAVE_NOISE_THRESHOLD (2.5/CAVE_NOISE_SCALE)
1140 #define CAVE_NOISE_THRESHOLD (1.5/CAVE_NOISE_SCALE)
1142 NoiseParams get_cave_noise1_params(u64 seed)
1144 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.7,
1145 200, CAVE_NOISE_SCALE);*/
1146 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.7,
1147 100, CAVE_NOISE_SCALE);*/
1148 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.6,
1149 100, CAVE_NOISE_SCALE);*/
1150 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.3,
1151 100, CAVE_NOISE_SCALE);*/
1152 return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.5,
1153 50, CAVE_NOISE_SCALE);
1154 //return NoiseParams(NOISE_CONSTANT_ONE);
1157 NoiseParams get_cave_noise2_params(u64 seed)
1159 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.7,
1160 200, CAVE_NOISE_SCALE);*/
1161 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.7,
1162 100, CAVE_NOISE_SCALE);*/
1163 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.3,
1164 100, CAVE_NOISE_SCALE);*/
1165 return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.5,
1166 50, CAVE_NOISE_SCALE);
1167 //return NoiseParams(NOISE_CONSTANT_ONE);
1170 NoiseParams get_ground_noise1_params(u64 seed)
1172 return NoiseParams(NOISE_PERLIN, seed+983240, 4,
1176 NoiseParams get_ground_crumbleness_params(u64 seed)
1178 return NoiseParams(NOISE_PERLIN, seed+34413, 3,
1182 NoiseParams get_ground_wetness_params(u64 seed)
1184 return NoiseParams(NOISE_PERLIN, seed+32474, 4,
1188 bool is_cave(u64 seed, v3s16 p)
1190 double d1 = noise3d_param(get_cave_noise1_params(seed), p.X,p.Y,p.Z);
1191 double d2 = noise3d_param(get_cave_noise2_params(seed), p.X,p.Y,p.Z);
1192 return d1*d2 > CAVE_NOISE_THRESHOLD;
1196 Ground density noise shall be interpreted by using this.
1198 TODO: No perlin noises here, they should be outsourced
1200 NOTE: The speed of these actually isn't terrible
1202 bool val_is_ground(double ground_noise1_val, v3s16 p, u64 seed)
1204 //return ((double)p.Y < ground_noise1_val);
1206 double f = 0.55 + noise2d_perlin(
1207 0.5+(float)p.X/250, 0.5+(float)p.Z/250,
1208 seed+920381, 3, 0.45);
1213 double h = WATER_LEVEL + 10 * noise2d_perlin(
1214 0.5+(float)p.X/250, 0.5+(float)p.Z/250,
1215 seed+84174, 4, 0.5);
1218 return ((double)p.Y - h < ground_noise1_val * f);
1222 Queries whether a position is ground or not.
1224 bool is_ground(u64 seed, v3s16 p)
1226 double val1 = noise3d_param(get_ground_noise1_params(seed), p.X,p.Y,p.Z);
1227 return val_is_ground(val1, p, seed);
1231 // Amount of trees per area in nodes
1232 double tree_amount_2d(u64 seed, v2s16 p)
1234 /*double noise = noise2d_perlin(
1235 0.5+(float)p.X/250, 0.5+(float)p.Y/250,
1237 double noise = noise2d_perlin(
1238 0.5+(float)p.X/125, 0.5+(float)p.Y/125,
1240 double zeroval = -0.39;
1244 return 0.04 * (noise-zeroval) / (1.0-zeroval);
1248 double surface_humidity_2d(u64 seed, v2s16 p)
1250 double noise = noise2d_perlin(
1251 0.5+(float)p.X/500, 0.5+(float)p.Y/500,
1252 seed+72384, 4, 0.66);
1253 noise = (noise + 1.0)/2.0;
1262 Incrementally find ground level from 3d noise
1264 s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision)
1266 // Start a bit fuzzy to make averaging lower precision values
1268 s16 level = myrand_range(-precision/2, precision/2);
1269 s16 dec[] = {31000, 100, 20, 4, 1, 0};
1271 for(i = 1; dec[i] != 0 && precision <= dec[i]; i++)
1273 // First find non-ground by going upwards
1274 // Don't stop in caves.
1276 s16 max = level+dec[i-1]*2;
1277 v3s16 p(p2d.X, level, p2d.Y);
1278 for(; p.Y < max; p.Y += dec[i])
1280 if(!is_ground(seed, p))
1287 // Then find ground by going downwards from there.
1288 // Go in caves, too, when precision is 1.
1290 s16 min = level-dec[i-1]*2;
1291 v3s16 p(p2d.X, level, p2d.Y);
1292 for(; p.Y>min; p.Y-=dec[i])
1294 bool ground = is_ground(seed, p);
1295 /*if(dec[i] == 1 && is_cave(seed, p))
1306 // This is more like the actual ground level
1307 level += dec[i-1]/2;
1312 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1314 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p)
1316 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1317 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1319 a += find_ground_level_from_noise(seed,
1320 v2s16(node_min.X, node_min.Y), p);
1321 a += find_ground_level_from_noise(seed,
1322 v2s16(node_min.X, node_max.Y), p);
1323 a += find_ground_level_from_noise(seed,
1324 v2s16(node_max.X, node_max.Y), p);
1325 a += find_ground_level_from_noise(seed,
1326 v2s16(node_max.X, node_min.Y), p);
1327 a += find_ground_level_from_noise(seed,
1328 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p);
1333 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1335 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p)
1337 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1338 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1341 a = MYMAX(a, find_ground_level_from_noise(seed,
1342 v2s16(node_min.X, node_min.Y), p));
1343 a = MYMAX(a, find_ground_level_from_noise(seed,
1344 v2s16(node_min.X, node_max.Y), p));
1345 a = MYMAX(a, find_ground_level_from_noise(seed,
1346 v2s16(node_max.X, node_max.Y), p));
1347 a = MYMAX(a, find_ground_level_from_noise(seed,
1348 v2s16(node_min.X, node_min.Y), p));
1350 a = MYMAX(a, find_ground_level_from_noise(seed,
1351 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
1352 // Side middle points
1353 a = MYMAX(a, find_ground_level_from_noise(seed,
1354 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
1355 a = MYMAX(a, find_ground_level_from_noise(seed,
1356 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
1357 a = MYMAX(a, find_ground_level_from_noise(seed,
1358 v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1359 a = MYMAX(a, find_ground_level_from_noise(seed,
1360 v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1364 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1366 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p)
1368 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1369 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1372 a = MYMIN(a, find_ground_level_from_noise(seed,
1373 v2s16(node_min.X, node_min.Y), p));
1374 a = MYMIN(a, find_ground_level_from_noise(seed,
1375 v2s16(node_min.X, node_max.Y), p));
1376 a = MYMIN(a, find_ground_level_from_noise(seed,
1377 v2s16(node_max.X, node_max.Y), p));
1378 a = MYMIN(a, find_ground_level_from_noise(seed,
1379 v2s16(node_min.X, node_min.Y), p));
1381 a = MYMIN(a, find_ground_level_from_noise(seed,
1382 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
1383 // Side middle points
1384 a = MYMIN(a, find_ground_level_from_noise(seed,
1385 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
1386 a = MYMIN(a, find_ground_level_from_noise(seed,
1387 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
1388 a = MYMIN(a, find_ground_level_from_noise(seed,
1389 v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1390 a = MYMIN(a, find_ground_level_from_noise(seed,
1391 v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1396 // Required by mapgen.h
1397 bool block_is_underground(u64 seed, v3s16 blockpos)
1399 /*s16 minimum_groundlevel = (s16)get_sector_minimum_ground_level(
1400 seed, v2s16(blockpos.X, blockpos.Z));*/
1401 // Nah, this is just a heuristic, just return something
1402 s16 minimum_groundlevel = WATER_LEVEL;
1404 if(blockpos.Y*MAP_BLOCKSIZE + MAP_BLOCKSIZE <= minimum_groundlevel)
1410 #define AVERAGE_MUD_AMOUNT 4
1412 double base_rock_level_2d(u64 seed, v2s16 p)
1414 // The base ground level
1415 double base = (double)WATER_LEVEL - (double)AVERAGE_MUD_AMOUNT
1416 + 20. * noise2d_perlin(
1417 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1418 seed+82341, 5, 0.6);
1420 /*// A bit hillier one
1421 double base2 = WATER_LEVEL - 4.0 + 40. * noise2d_perlin(
1422 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1423 seed+93413, 6, 0.69);
1427 // Higher ground level
1428 double higher = (double)WATER_LEVEL + 20. + 16. * noise2d_perlin(
1429 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
1430 seed+85039, 5, 0.6);
1431 //higher = 30; // For debugging
1433 // Limit higher to at least base
1437 // Steepness factor of cliffs
1438 double b = 0.85 + 0.5 * noise2d_perlin(
1439 0.5+(float)p.X/125., 0.5+(float)p.Y/125.,
1441 b = rangelim(b, 0.0, 1000.0);
1444 b = rangelim(b, 0.5, 1000.0);
1445 // Values 1.5...100 give quite horrible looking slopes
1446 if(b > 1.5 && b < 100.0){
1452 //dstream<<"b="<<b<<std::endl;
1456 // Offset to more low
1457 double a_off = -0.20;
1458 // High/low selector
1459 /*double a = 0.5 + b * (a_off + noise2d_perlin(
1460 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
1461 seed+4213, 6, 0.7));*/
1462 double a = (double)0.5 + b * (a_off + noise2d_perlin(
1463 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1464 seed+4213, 5, 0.69));
1466 a = rangelim(a, 0.0, 1.0);
1468 //dstream<<"a="<<a<<std::endl;
1470 double h = base*(1.0-a) + higher*a;
1477 s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision)
1479 return base_rock_level_2d(seed, p2d) + AVERAGE_MUD_AMOUNT;
1482 double get_mud_add_amount(u64 seed, v2s16 p)
1484 return ((float)AVERAGE_MUD_AMOUNT + 2.0 * noise2d_perlin(
1485 0.5+(float)p.X/200, 0.5+(float)p.Y/200,
1486 seed+91013, 3, 0.55));
1489 bool get_have_beach(u64 seed, v2s16 p2d)
1491 // Determine whether to have sand here
1492 double sandnoise = noise2d_perlin(
1493 0.2+(float)p2d.X/250, 0.7+(float)p2d.Y/250,
1494 seed+59420, 3, 0.50);
1496 return (sandnoise > 0.15);
1505 BiomeType get_biome(u64 seed, v2s16 p2d)
1507 // Just do something very simple as for now
1508 double d = noise2d_perlin(
1509 0.6+(float)p2d.X/250, 0.2+(float)p2d.Y/250,
1510 seed+9130, 3, 0.50);
1513 if(d > 0.35 && (noise2d( p2d.X, p2d.Y, int(seed) ) + 1.0) > ( 0.45 - d ) * 20.0 )
1518 u32 get_blockseed(u64 seed, v3s16 p)
1520 s32 x=p.X, y=p.Y, z=p.Z;
1521 return (u32)(seed%0x100000000ULL) + z*38134234 + y*42123 + x*23;
1524 #define VMANIP_FLAG_CAVE VOXELFLAG_CHECKED1
1526 void make_block(BlockMakeData *data)
1530 //dstream<<"makeBlock: no-op"<<std::endl;
1534 assert(data->vmanip);
1535 assert(data->nodedef);
1536 assert(data->blockpos_requested.X >= data->blockpos_min.X &&
1537 data->blockpos_requested.Y >= data->blockpos_min.Y &&
1538 data->blockpos_requested.Z >= data->blockpos_min.Z);
1539 assert(data->blockpos_requested.X <= data->blockpos_max.X &&
1540 data->blockpos_requested.Y <= data->blockpos_max.Y &&
1541 data->blockpos_requested.Z <= data->blockpos_max.Z);
1543 INodeDefManager *ndef = data->nodedef;
1545 // Hack: use minimum block coordinates for old code that assumes
1547 v3s16 blockpos = data->blockpos_requested;
1549 /*dstream<<"makeBlock(): ("<<blockpos.X<<","<<blockpos.Y<<","
1550 <<blockpos.Z<<")"<<std::endl;*/
1552 v3s16 blockpos_min = data->blockpos_min;
1553 v3s16 blockpos_max = data->blockpos_max;
1554 v3s16 blockpos_full_min = blockpos_min - v3s16(1,1,1);
1555 v3s16 blockpos_full_max = blockpos_max + v3s16(1,1,1);
1557 ManualMapVoxelManipulator &vmanip = *(data->vmanip);
1558 // Area of central chunk
1559 v3s16 node_min = blockpos_min*MAP_BLOCKSIZE;
1560 v3s16 node_max = (blockpos_max+v3s16(1,1,1))*MAP_BLOCKSIZE-v3s16(1,1,1);
1561 // Full allocated area
1562 v3s16 full_node_min = (blockpos_min-1)*MAP_BLOCKSIZE;
1563 v3s16 full_node_max = (blockpos_max+2)*MAP_BLOCKSIZE-v3s16(1,1,1);
1565 v3s16 central_area_size = node_max - node_min + v3s16(1,1,1);
1567 const s16 max_spread_amount = MAP_BLOCKSIZE;
1569 int volume_blocks = (blockpos_max.X - blockpos_min.X + 1)
1570 * (blockpos_max.Y - blockpos_min.Y + 1)
1571 * (blockpos_max.Z - blockpos_max.Z + 1);
1573 int volume_nodes = volume_blocks *
1574 MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
1576 // Generated surface area
1577 //double gen_area_nodes = MAP_BLOCKSIZE*MAP_BLOCKSIZE * rel_volume;
1579 // Horribly wrong heuristic, but better than nothing
1580 bool block_is_underground = (WATER_LEVEL > node_max.Y);
1583 Create a block-specific seed
1585 u32 blockseed = get_blockseed(data->seed, full_node_min);
1588 Cache some ground type values for speed
1591 // Creates variables c_name=id and n_name=node
1592 #define CONTENT_VARIABLE(ndef, name)\
1593 content_t c_##name = ndef->getId("mapgen_" #name);\
1594 MapNode n_##name(c_##name);
1595 // Default to something else if was CONTENT_IGNORE
1596 #define CONTENT_VARIABLE_FALLBACK(name, dname)\
1597 if(c_##name == CONTENT_IGNORE){\
1598 c_##name = c_##dname;\
1599 n_##name = n_##dname;\
1602 CONTENT_VARIABLE(ndef, stone);
1603 CONTENT_VARIABLE(ndef, air);
1604 CONTENT_VARIABLE(ndef, water_source);
1605 CONTENT_VARIABLE(ndef, dirt);
1606 CONTENT_VARIABLE(ndef, sand);
1607 CONTENT_VARIABLE(ndef, gravel);
1608 CONTENT_VARIABLE(ndef, clay);
1609 CONTENT_VARIABLE(ndef, lava_source);
1610 CONTENT_VARIABLE(ndef, cobble);
1611 CONTENT_VARIABLE(ndef, mossycobble);
1612 CONTENT_VARIABLE(ndef, dirt_with_grass);
1613 CONTENT_VARIABLE(ndef, junglegrass);
1614 CONTENT_VARIABLE(ndef, stone_with_coal);
1615 CONTENT_VARIABLE(ndef, stone_with_iron);
1616 CONTENT_VARIABLE(ndef, mese);
1617 CONTENT_VARIABLE(ndef, desert_sand);
1618 CONTENT_VARIABLE_FALLBACK(desert_sand, sand);
1619 CONTENT_VARIABLE(ndef, desert_stone);
1620 CONTENT_VARIABLE_FALLBACK(desert_stone, stone);
1622 // Maximum height of the stone surface and obstacles.
1623 // This is used to guide the cave generation
1624 s16 stone_surface_max_y = 0;
1627 Generate general ground level to full area
1631 TimeTaker timer1("Generating ground level");
1633 for(s16 x=node_min.X; x<=node_max.X; x++)
1634 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1637 v2s16 p2d = v2s16(x,z);
1640 Skip of already generated
1643 v3s16 p(p2d.X, node_min.Y, p2d.Y);
1644 if(vmanip.m_data[vmanip.m_area.index(p)].d != CONTENT_AIR)
1648 // Ground height at this point
1649 float surface_y_f = 0.0;
1651 // Use perlin noise for ground height
1652 surface_y_f = base_rock_level_2d(data->seed, p2d);
1654 /*// Experimental stuff
1656 float a = highlands_level_2d(data->seed, p2d);
1661 // Convert to integer
1662 s16 surface_y = (s16)surface_y_f;
1665 if(surface_y > stone_surface_max_y)
1666 stone_surface_max_y = surface_y;
1668 BiomeType bt = get_biome(data->seed, p2d);
1670 Fill ground with stone
1673 // Use fast index incrementing
1674 v3s16 em = vmanip.m_area.getExtent();
1675 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
1676 for(s16 y=node_min.Y; y<=node_max.Y; y++)
1678 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE){
1680 if(y > WATER_LEVEL && bt == BT_DESERT)
1681 vmanip.m_data[i] = n_desert_stone;
1683 vmanip.m_data[i] = n_stone;
1684 } else if(y <= WATER_LEVEL){
1685 vmanip.m_data[i] = MapNode(c_water_source);
1687 vmanip.m_data[i] = MapNode(c_air);
1690 vmanip.m_area.add_y(em, i, 1);
1698 // Limit dirt flow area by 1 because mud is flown into neighbors.
1699 assert(central_area_size.X == central_area_size.Z);
1700 s16 mudflow_minpos = 0-max_spread_amount+1;
1701 s16 mudflow_maxpos = central_area_size.X+max_spread_amount-2;
1704 Loop this part, it will make stuff look older and newer nicely
1707 const u32 age_loops = 2;
1708 for(u32 i_age=0; i_age<age_loops; i_age++)
1710 /******************************
1711 BEGINNING OF AGING LOOP
1712 ******************************/
1717 //TimeTaker timer1("caves");
1720 Make caves (this code is relatively horrible)
1722 double cave_amount = 6.0 + 6.0 * noise2d_perlin(
1723 0.5+(double)node_min.X/250, 0.5+(double)node_min.Y/250,
1724 data->seed+34329, 3, 0.50);
1725 cave_amount = MYMAX(0.0, cave_amount);
1726 u32 caves_count = cave_amount * volume_nodes / 50000;
1727 u32 bruises_count = 1;
1728 PseudoRandom ps(blockseed+21343);
1729 PseudoRandom ps2(blockseed+1032);
1730 if(ps.range(1, 6) == 1)
1731 bruises_count = ps.range(0, ps.range(0, 2));
1732 if(get_biome(data->seed, v2s16(node_min.X, node_min.Y)) == BT_DESERT){
1736 for(u32 jj=0; jj<caves_count+bruises_count; jj++)
1738 bool large_cave = (jj >= caves_count);
1739 s16 min_tunnel_diameter = 2;
1740 s16 max_tunnel_diameter = ps.range(2,6);
1741 int dswitchint = ps.range(1,14);
1742 u16 tunnel_routepoints = 0;
1743 int part_max_length_rs = 0;
1745 part_max_length_rs = ps.range(2,4);
1746 tunnel_routepoints = ps.range(5, ps.range(15,30));
1747 min_tunnel_diameter = 5;
1748 max_tunnel_diameter = ps.range(7, ps.range(8,24));
1750 part_max_length_rs = ps.range(2,9);
1751 tunnel_routepoints = ps.range(10, ps.range(15,30));
1753 bool large_cave_is_flat = (ps.range(0,1) == 0);
1755 v3f main_direction(0,0,0);
1757 // Allowed route area size in nodes
1758 v3s16 ar = central_area_size;
1760 // Area starting point in nodes
1761 v3s16 of = node_min;
1764 //(this should be more than the maximum radius of the tunnel)
1765 //s16 insure = 5; // Didn't work with max_d = 20
1767 s16 more = max_spread_amount - max_tunnel_diameter/2 - insure;
1768 ar += v3s16(1,0,1) * more * 2;
1769 of -= v3s16(1,0,1) * more;
1771 s16 route_y_min = 0;
1772 // Allow half a diameter + 7 over stone surface
1773 s16 route_y_max = -of.Y + stone_surface_max_y + max_tunnel_diameter/2 + 7;
1775 /*// If caves, don't go through surface too often
1776 if(large_cave == false)
1777 route_y_max -= ps.range(0, max_tunnel_diameter*2);*/
1779 // Limit maximum to area
1780 route_y_max = rangelim(route_y_max, 0, ar.Y-1);
1784 /*// Minimum is at y=0
1785 route_y_min = -of.Y - 0;*/
1786 // Minimum is at y=max_tunnel_diameter/4
1787 //route_y_min = -of.Y + max_tunnel_diameter/4;
1788 //s16 min = -of.Y + max_tunnel_diameter/4;
1789 //s16 min = -of.Y + 0;
1791 if(node_min.Y < WATER_LEVEL && node_max.Y > WATER_LEVEL)
1793 min = WATER_LEVEL - max_tunnel_diameter/3 - of.Y;
1794 route_y_max = WATER_LEVEL + max_tunnel_diameter/3 - of.Y;
1796 route_y_min = ps.range(min, min + max_tunnel_diameter);
1797 route_y_min = rangelim(route_y_min, 0, route_y_max);
1800 /*dstream<<"route_y_min = "<<route_y_min
1801 <<", route_y_max = "<<route_y_max<<std::endl;*/
1803 s16 route_start_y_min = route_y_min;
1804 s16 route_start_y_max = route_y_max;
1806 // Start every 4th cave from surface when applicable
1807 /*bool coming_from_surface = false;
1808 if(node_min.Y <= 0 && node_max.Y >= 0){
1809 coming_from_surface = (jj % 4 == 0 && large_cave == false);
1810 if(coming_from_surface)
1811 route_start_y_min = -of.Y + stone_surface_max_y + 10;
1814 route_start_y_min = rangelim(route_start_y_min, 0, ar.Y-1);
1815 route_start_y_max = rangelim(route_start_y_max, route_start_y_min, ar.Y-1);
1817 // Randomize starting position
1819 (float)(ps.next()%ar.X)+0.5,
1820 (float)(ps.range(route_start_y_min, route_start_y_max))+0.5,
1821 (float)(ps.next()%ar.Z)+0.5
1824 v3s16 startp(orp.X, orp.Y, orp.Z);
1827 MapNode airnode(CONTENT_AIR);
1828 MapNode waternode(c_water_source);
1829 MapNode lavanode(c_lava_source);
1832 Generate some tunnel starting from orp
1835 for(u16 j=0; j<tunnel_routepoints; j++)
1837 if(j%dswitchint==0 && large_cave == false)
1839 main_direction = v3f(
1840 ((float)(ps.next()%20)-(float)10)/10,
1841 ((float)(ps.next()%20)-(float)10)/30,
1842 ((float)(ps.next()%20)-(float)10)/10
1844 main_direction *= (float)ps.range(0, 10)/10;
1848 s16 min_d = min_tunnel_diameter;
1849 s16 max_d = max_tunnel_diameter;
1850 s16 rs = ps.range(min_d, max_d);
1852 // Every second section is rough
1853 bool randomize_xz = (ps2.range(1,2) == 1);
1859 rs*part_max_length_rs,
1860 rs*part_max_length_rs/2,
1861 rs*part_max_length_rs
1867 rs*part_max_length_rs,
1868 ps.range(1, rs*part_max_length_rs),
1869 rs*part_max_length_rs
1876 (float)(ps.next()%(maxlen.X*1))-(float)maxlen.X/2,
1877 (float)(ps.next()%(maxlen.Y*1))-(float)maxlen.Y/2,
1878 (float)(ps.next()%(maxlen.Z*1))-(float)maxlen.Z/2
1881 // Jump downward sometimes
1882 if(!large_cave && ps.range(0,12) == 0)
1885 (float)(ps.next()%(maxlen.X*1))-(float)maxlen.X/2,
1886 (float)(ps.next()%(maxlen.Y*2))-(float)maxlen.Y*2/2,
1887 (float)(ps.next()%(maxlen.Z*1))-(float)maxlen.Z/2
1893 s16 h = find_ground_level_clever(vmanip,
1894 v2s16(p.X, p.Z), ndef);
1895 route_y_min = h - rs/3;
1896 route_y_max = h + rs;
1899 vec += main_direction;
1904 else if(rp.X >= ar.X)
1906 if(rp.Y < route_y_min)
1908 else if(rp.Y >= route_y_max)
1909 rp.Y = route_y_max-1;
1912 else if(rp.Z >= ar.Z)
1916 for(float f=0; f<1.0; f+=1.0/vec.getLength())
1918 v3f fp = orp + vec * f;
1919 fp.X += 0.1*ps.range(-10,10);
1920 fp.Z += 0.1*ps.range(-10,10);
1921 v3s16 cp(fp.X, fp.Y, fp.Z);
1926 d0 += ps.range(-1,1);
1927 d1 += ps.range(-1,1);
1929 for(s16 z0=d0; z0<=d1; z0++)
1931 s16 si = rs/2 - MYMAX(0, abs(z0)-rs/7-1);
1932 for(s16 x0=-si-ps.range(0,1); x0<=si-1+ps.range(0,1); x0++)
1934 s16 maxabsxz = MYMAX(abs(x0), abs(z0));
1935 s16 si2 = rs/2 - MYMAX(0, maxabsxz-rs/7-1);
1936 for(s16 y0=-si2; y0<=si2; y0++)
1938 /*// Make better floors in small caves
1939 if(y0 <= -rs/2 && rs<=7)
1941 if(large_cave_is_flat){
1942 // Make large caves not so tall
1943 if(rs > 7 && abs(y0) >= rs/3)
1953 if(vmanip.m_area.contains(p) == false)
1956 u32 i = vmanip.m_area.index(p);
1960 if(full_node_min.Y < WATER_LEVEL &&
1961 full_node_max.Y > WATER_LEVEL){
1962 if(p.Y <= WATER_LEVEL)
1963 vmanip.m_data[i] = waternode;
1965 vmanip.m_data[i] = airnode;
1966 } else if(full_node_max.Y < WATER_LEVEL){
1967 if(p.Y < startp.Y - 2)
1968 vmanip.m_data[i] = lavanode;
1970 vmanip.m_data[i] = airnode;
1972 vmanip.m_data[i] = airnode;
1975 // Don't replace air or water or lava or ignore
1976 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE ||
1977 vmanip.m_data[i].getContent() == CONTENT_AIR ||
1978 vmanip.m_data[i].getContent() == c_water_source ||
1979 vmanip.m_data[i].getContent() == c_lava_source)
1982 vmanip.m_data[i] = airnode;
1985 vmanip.m_flags[i] |= VMANIP_FLAG_CAVE;
2003 TimeTaker timer1("add mud");
2006 Add mud to the central chunk
2009 for(s16 x=node_min.X; x<=node_max.X; x++)
2010 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2012 // Node position in 2d
2013 v2s16 p2d = v2s16(x,z);
2015 // Randomize mud amount
2016 s16 mud_add_amount = get_mud_add_amount(data->seed, p2d) / 2.0 + 0.5;
2018 // Find ground level
2019 s16 surface_y = find_stone_level(vmanip, p2d, ndef);
2020 // Handle area not found
2021 if(surface_y == vmanip.m_area.MinEdge.Y - 1)
2024 MapNode addnode(c_dirt);
2025 BiomeType bt = get_biome(data->seed, p2d);
2028 addnode = MapNode(c_desert_sand);
2030 if(bt == BT_DESERT && surface_y + mud_add_amount <= WATER_LEVEL+1){
2031 addnode = MapNode(c_sand);
2032 } else if(mud_add_amount <= 0){
2033 mud_add_amount = 1 - mud_add_amount;
2034 addnode = MapNode(c_gravel);
2035 } else if(bt == BT_NORMAL && get_have_beach(data->seed, p2d) &&
2036 surface_y + mud_add_amount <= WATER_LEVEL+2){
2037 addnode = MapNode(c_sand);
2040 if(bt == BT_DESERT){
2042 mud_add_amount = MYMAX(0, mud_add_amount - (surface_y - 20)/5);
2047 If topmost node is grass, change it to mud.
2048 It might be if it was flown to there from a neighboring
2049 chunk and then converted.
2052 u32 i = vmanip.m_area.index(v3s16(p2d.X, surface_y, p2d.Y));
2053 MapNode *n = &vmanip.m_data[i];
2054 if(n->getContent() == c_dirt_with_grass)
2055 *n = MapNode(c_dirt);
2063 v3s16 em = vmanip.m_area.getExtent();
2064 s16 y_start = surface_y+1;
2065 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
2066 for(s16 y=y_start; y<=node_max.Y; y++)
2068 if(mudcount >= mud_add_amount)
2071 MapNode &n = vmanip.m_data[i];
2075 vmanip.m_area.add_y(em, i, 1);
2085 Add blobs of dirt and gravel underground
2087 if(get_biome(data->seed, v2s16(node_min.X, node_min.Y)) == BT_NORMAL)
2089 PseudoRandom pr(blockseed+983);
2090 for(int i=0; i<volume_nodes/10/10/10; i++)
2092 bool only_fill_cave = (myrand_range(0,1) != 0);
2099 pr.range(node_min.X, node_max.X)-size.X/2,
2100 pr.range(node_min.Y, node_max.Y)-size.Y/2,
2101 pr.range(node_min.Z, node_max.Z)-size.Z/2
2104 if(p0.Y > -32 && pr.range(0,1) == 0)
2105 n1 = MapNode(c_dirt);
2107 n1 = MapNode(c_gravel);
2108 for(int x1=0; x1<size.X; x1++)
2109 for(int y1=0; y1<size.Y; y1++)
2110 for(int z1=0; z1<size.Z; z1++)
2112 v3s16 p = p0 + v3s16(x1,y1,z1);
2113 u32 i = vmanip.m_area.index(p);
2114 if(!vmanip.m_area.contains(i))
2116 // Cancel if not stone and not cave air
2117 if(vmanip.m_data[i].getContent() != c_stone &&
2118 !(vmanip.m_flags[i] & VMANIP_FLAG_CAVE))
2120 if(only_fill_cave && !(vmanip.m_flags[i] & VMANIP_FLAG_CAVE))
2122 vmanip.m_data[i] = n1;
2130 TimeTaker timer1("flow mud");
2133 Flow mud away from steep edges
2136 // Iterate a few times
2137 for(s16 k=0; k<3; k++)
2140 for(s16 x=mudflow_minpos; x<=mudflow_maxpos; x++)
2141 for(s16 z=mudflow_minpos; z<=mudflow_maxpos; z++)
2143 // Invert coordinates every 2nd iteration
2146 x = mudflow_maxpos - (x-mudflow_minpos);
2147 z = mudflow_maxpos - (z-mudflow_minpos);
2150 // Node position in 2d
2151 v2s16 p2d = v2s16(node_min.X, node_min.Z) + v2s16(x,z);
2153 v3s16 em = vmanip.m_area.getExtent();
2154 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
2157 while(y >= node_min.Y)
2164 for(; y>=node_min.Y; y--)
2166 n = &vmanip.m_data[i];
2167 //if(content_walkable(n->d))
2169 if(n->getContent() == c_dirt ||
2170 n->getContent() == c_dirt_with_grass ||
2171 n->getContent() == c_gravel)
2174 vmanip.m_area.add_y(em, i, -1);
2177 // Stop if out of area
2178 //if(vmanip.m_area.contains(i) == false)
2182 /*// If not mud, do nothing to it
2183 MapNode *n = &vmanip.m_data[i];
2184 if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS)
2187 if(n->getContent() == c_dirt ||
2188 n->getContent() == c_dirt_with_grass)
2190 // Make it exactly mud
2191 n->setContent(c_dirt);
2194 Don't flow it if the stuff under it is not mud
2198 vmanip.m_area.add_y(em, i2, -1);
2199 // Cancel if out of area
2200 if(vmanip.m_area.contains(i2) == false)
2202 MapNode *n2 = &vmanip.m_data[i2];
2203 if(n2->getContent() != c_dirt &&
2204 n2->getContent() != c_dirt_with_grass)
2209 /*s16 recurse_count = 0;
2213 v3s16(0,0,1), // back
2214 v3s16(1,0,0), // right
2215 v3s16(0,0,-1), // front
2216 v3s16(-1,0,0), // left
2219 // Theck that upper is air or doesn't exist.
2220 // Cancel dropping if upper keeps it in place
2222 vmanip.m_area.add_y(em, i3, 1);
2223 if(vmanip.m_area.contains(i3) == true
2224 && ndef->get(vmanip.m_data[i3]).walkable)
2231 for(u32 di=0; di<4; di++)
2233 v3s16 dirp = dirs4[di];
2236 vmanip.m_area.add_p(em, i2, dirp);
2237 // Fail if out of area
2238 if(vmanip.m_area.contains(i2) == false)
2240 // Check that side is air
2241 MapNode *n2 = &vmanip.m_data[i2];
2242 if(ndef->get(*n2).walkable)
2244 // Check that under side is air
2245 vmanip.m_area.add_y(em, i2, -1);
2246 if(vmanip.m_area.contains(i2) == false)
2248 n2 = &vmanip.m_data[i2];
2249 if(ndef->get(*n2).walkable)
2251 /*// Check that under that is air (need a drop of 2)
2252 vmanip.m_area.add_y(em, i2, -1);
2253 if(vmanip.m_area.contains(i2) == false)
2255 n2 = &vmanip.m_data[i2];
2256 if(content_walkable(n2->d))
2258 // Loop further down until not air
2259 bool dropped_to_unknown = false;
2261 vmanip.m_area.add_y(em, i2, -1);
2262 n2 = &vmanip.m_data[i2];
2263 // if out of known area
2264 if(vmanip.m_area.contains(i2) == false
2265 || n2->getContent() == CONTENT_IGNORE){
2266 dropped_to_unknown = true;
2269 }while(ndef->get(*n2).walkable == false);
2270 // Loop one up so that we're in air
2271 vmanip.m_area.add_y(em, i2, 1);
2272 n2 = &vmanip.m_data[i2];
2274 bool old_is_water = (n->getContent() == c_water_source);
2275 // Move mud to new place
2276 if(!dropped_to_unknown) {
2278 // Set old place to be air (or water)
2280 *n = MapNode(c_water_source);
2282 *n = MapNode(CONTENT_AIR);
2298 /***********************
2300 ************************/
2303 Add top and bottom side of water to transforming_liquid queue
2306 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2307 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2312 bool water_found = false;
2313 // Use fast index incrementing
2314 v3s16 em = vmanip.m_area.getExtent();
2315 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
2316 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
2318 if(y == full_node_max.Y){
2320 (vmanip.m_data[i].getContent() == c_water_source ||
2321 vmanip.m_data[i].getContent() == c_lava_source);
2323 else if(water_found == false)
2325 if(vmanip.m_data[i].getContent() == c_water_source ||
2326 vmanip.m_data[i].getContent() == c_lava_source)
2328 v3s16 p = v3s16(p2d.X, y, p2d.Y);
2329 data->transforming_liquid.push_back(p);
2335 // This can be done because water_found can only
2336 // turn to true and end up here after going through
2338 if(vmanip.m_data[i+1].getContent() != c_water_source ||
2339 vmanip.m_data[i+1].getContent() != c_lava_source)
2341 v3s16 p = v3s16(p2d.X, y+1, p2d.Y);
2342 data->transforming_liquid.push_back(p);
2343 water_found = false;
2347 vmanip.m_area.add_y(em, i, -1);
2356 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2357 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2359 // Node position in 2d
2360 v2s16 p2d = v2s16(x,z);
2363 Find the lowest surface to which enough light ends up
2366 Basically just wait until not air and not leaves.
2370 v3s16 em = vmanip.m_area.getExtent();
2371 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
2373 // Go to ground level
2374 for(y=node_max.Y; y>=full_node_min.Y; y--)
2376 MapNode &n = vmanip.m_data[i];
2377 if(ndef->get(n).param_type != CPT_LIGHT
2378 || ndef->get(n).liquid_type != LIQUID_NONE)
2380 vmanip.m_area.add_y(em, i, -1);
2382 if(y >= full_node_min.Y)
2385 surface_y = full_node_min.Y;
2388 u32 i = vmanip.m_area.index(p2d.X, surface_y, p2d.Y);
2389 MapNode *n = &vmanip.m_data[i];
2390 if(n->getContent() == c_dirt){
2391 // Well yeah, this can't be overground...
2392 if(surface_y < WATER_LEVEL - 20)
2394 n->setContent(c_dirt_with_grass);
2401 assert(central_area_size.X == central_area_size.Z);
2403 // Divide area into parts
2405 s16 sidelen = central_area_size.X / div;
2406 double area = sidelen * sidelen;
2407 for(s16 x0=0; x0<div; x0++)
2408 for(s16 z0=0; z0<div; z0++)
2410 // Center position of part of division
2412 node_min.X + sidelen/2 + sidelen*x0,
2413 node_min.Z + sidelen/2 + sidelen*z0
2415 // Minimum edge of part of division
2417 node_min.X + sidelen*x0,
2418 node_min.Z + sidelen*z0
2420 // Maximum edge of part of division
2422 node_min.X + sidelen + sidelen*x0 - 1,
2423 node_min.Z + sidelen + sidelen*z0 - 1
2426 u32 tree_count = area * tree_amount_2d(data->seed, p2d_center);
2427 // Put trees in random places on part of division
2428 for(u32 i=0; i<tree_count; i++)
2430 s16 x = myrand_range(p2d_min.X, p2d_max.X);
2431 s16 z = myrand_range(p2d_min.Y, p2d_max.Y);
2432 s16 y = find_ground_level(vmanip, v2s16(x,z), ndef);
2433 // Don't make a tree under water level
2436 // Don't make a tree so high that it doesn't fit
2437 if(y > node_max.Y - 6)
2441 Trees grow only on mud and grass
2444 u32 i = vmanip.m_area.index(v3s16(p));
2445 MapNode *n = &vmanip.m_data[i];
2446 if(n->getContent() != c_dirt
2447 && n->getContent() != c_dirt_with_grass)
2452 treegen::make_tree(vmanip, p, false, ndef);
2459 Make base ground level
2462 for(s16 x=node_min.X; x<=node_max.X; x++)
2463 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2468 // Use fast index incrementing
2469 v3s16 em = vmanip.m_area.getExtent();
2470 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
2471 for(s16 y=node_min.Y; y<=node_max.Y; y++)
2473 // Only modify places that have no content
2474 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE)
2476 // First priority: make air and water.
2477 // This avoids caves inside water.
2478 if(all_is_ground_except_caves == false
2479 && val_is_ground(noisebuf_ground.get(x,y,z),
2480 v3s16(x,y,z), data->seed) == false)
2482 if(y <= WATER_LEVEL)
2483 vmanip.m_data[i] = n_water_source;
2485 vmanip.m_data[i] = n_air;
2487 else if(noisebuf_cave.get(x,y,z) > CAVE_NOISE_THRESHOLD)
2488 vmanip.m_data[i] = n_air;
2490 vmanip.m_data[i] = n_stone;
2493 vmanip->m_area.add_y(em, i, 1);
2499 Add mud and sand and others underground (in place of stone)
2502 for(s16 x=node_min.X; x<=node_max.X; x++)
2503 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2508 // Use fast index incrementing
2509 v3s16 em = vmanip.m_area.getExtent();
2510 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
2511 for(s16 y=node_max.Y; y>=node_min.Y; y--)
2513 if(vmanip.m_data[i].getContent() == c_stone)
2515 if(noisebuf_ground_crumbleness.get(x,y,z) > 1.3)
2517 if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
2518 vmanip.m_data[i] = n_dirt;
2520 vmanip.m_data[i] = n_sand;
2522 else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.7)
2524 if(noisebuf_ground_wetness.get(x,y,z) < -0.6)
2525 vmanip.m_data[i] = n_gravel;
2527 else if(noisebuf_ground_crumbleness.get(x,y,z) <
2528 -3.0 + MYMIN(0.1 * sqrt((float)MYMAX(0, -y)), 1.5))
2530 vmanip.m_data[i] = n_lava_source;
2531 for(s16 x1=-1; x1<=1; x1++)
2532 for(s16 y1=-1; y1<=1; y1++)
2533 for(s16 z1=-1; z1<=1; z1++)
2534 data->transforming_liquid.push_back(
2535 v3s16(p2d.X+x1, y+y1, p2d.Y+z1));
2539 vmanip->m_area.add_y(em, i, -1);
2548 //if(node_min.Y < approx_groundlevel)
2549 //if(myrand() % 3 == 0)
2550 //if(myrand() % 3 == 0 && node_min.Y < approx_groundlevel)
2551 //if(myrand() % 100 == 0 && node_min.Y < approx_groundlevel)
2552 //float dungeon_rarity = g_settings.getFloat("dungeon_rarity");
2553 float dungeon_rarity = 0.02;
2554 if(((noise3d(blockpos.X,blockpos.Y,blockpos.Z,data->seed)+1.0)/2.0)
2556 && node_min.Y < approx_groundlevel)
2558 // Dungeon generator doesn't modify places which have this set
2559 vmanip->clearFlag(VMANIP_FLAG_DUNGEON_INSIDE
2560 | VMANIP_FLAG_DUNGEON_PRESERVE);
2562 // Set all air and water to be untouchable to make dungeons open
2563 // to caves and open air
2564 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2565 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2570 // Use fast index incrementing
2571 v3s16 em = vmanip.m_area.getExtent();
2572 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
2573 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
2575 if(vmanip.m_data[i].getContent() == CONTENT_AIR)
2576 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
2577 else if(vmanip.m_data[i].getContent() == c_water_source)
2578 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
2579 vmanip->m_area.add_y(em, i, -1);
2584 PseudoRandom random(blockseed+2);
2587 make_dungeon1(vmanip, random, ndef);
2589 // Convert some cobble to mossy cobble
2590 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2591 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2596 // Use fast index incrementing
2597 v3s16 em = vmanip.m_area.getExtent();
2598 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
2599 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
2601 // (noisebuf not used because it doesn't contain the
2603 double wetness = noise3d_param(
2604 get_ground_wetness_params(data->seed), x,y,z);
2605 double d = noise3d_perlin((float)x/2.5,
2606 (float)y/2.5,(float)z/2.5,
2608 if(vmanip.m_data[i].getContent() == c_cobble)
2612 vmanip.m_data[i].setContent(c_mossycobble);
2615 /*else if(vmanip.m_flags[i] & VMANIP_FLAG_DUNGEON_INSIDE)
2618 vmanip.m_data[i].setContent(c_dirt);
2620 vmanip->m_area.add_y(em, i, -1);
2630 PseudoRandom ncrandom(blockseed+9324342);
2631 if(ncrandom.range(0, 1000) == 0 && blockpos.Y <= -3)
2633 make_nc(vmanip, ncrandom, ndef);
2638 Add top and bottom side of water to transforming_liquid queue
2641 for(s16 x=node_min.X; x<=node_max.X; x++)
2642 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2647 bool water_found = false;
2648 // Use fast index incrementing
2649 v3s16 em = vmanip.m_area.getExtent();
2650 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
2651 for(s16 y=node_max.Y; y>=node_min.Y; y--)
2653 if(water_found == false)
2655 if(vmanip.m_data[i].getContent() == c_water_source)
2657 v3s16 p = v3s16(p2d.X, y, p2d.Y);
2658 data->transforming_liquid.push_back(p);
2664 // This can be done because water_found can only
2665 // turn to true and end up here after going through
2667 if(vmanip.m_data[i+1].getContent() != c_water_source)
2669 v3s16 p = v3s16(p2d.X, y+1, p2d.Y);
2670 data->transforming_liquid.push_back(p);
2671 water_found = false;
2675 vmanip->m_area.add_y(em, i, -1);
2681 If close to ground level
2684 //if(abs(approx_ground_depth) < 30)
2685 if(minimum_ground_depth < 5 && maximum_ground_depth > -5)
2691 for(s16 x=node_min.X; x<=node_max.X; x++)
2692 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2697 bool possibly_have_sand = get_have_beach(data->seed, p2d);
2698 bool have_sand = false;
2699 u32 current_depth = 0;
2700 bool air_detected = false;
2701 bool water_detected = false;
2702 bool have_clay = false;
2704 // Use fast index incrementing
2705 s16 start_y = node_max.Y+2;
2706 v3s16 em = vmanip.m_area.getExtent();
2707 u32 i = vmanip.m_area.index(v3s16(p2d.X, start_y, p2d.Y));
2708 for(s16 y=start_y; y>=node_min.Y-3; y--)
2710 if(vmanip.m_data[i].getContent() == c_water_source)
2711 water_detected = true;
2712 if(vmanip.m_data[i].getContent() == CONTENT_AIR)
2713 air_detected = true;
2715 if((vmanip.m_data[i].getContent() == c_stone
2716 || vmanip.m_data[i].getContent() == c_dirt_with_grass
2717 || vmanip.m_data[i].getContent() == c_dirt
2718 || vmanip.m_data[i].getContent() == c_sand
2719 || vmanip.m_data[i].getContent() == c_gravel
2720 ) && (air_detected || water_detected))
2722 if(current_depth == 0 && y <= WATER_LEVEL+2
2723 && possibly_have_sand)
2726 if(current_depth < 4)
2730 vmanip.m_data[i] = MapNode(c_sand);
2733 else if(current_depth==0 && !water_detected
2734 && y >= WATER_LEVEL && air_detected)
2735 vmanip.m_data[i] = MapNode(c_dirt_with_grass);
2738 vmanip.m_data[i] = MapNode(c_dirt);
2742 if(vmanip.m_data[i].getContent() == c_dirt
2743 || vmanip.m_data[i].getContent() == c_dirt_with_grass)
2744 vmanip.m_data[i] = MapNode(c_stone);
2749 if(current_depth >= 8)
2752 else if(current_depth != 0)
2755 vmanip->m_area.add_y(em, i, -1);
2761 Calculate some stuff
2764 float surface_humidity = surface_humidity_2d(data->seed, p2d_center);
2765 bool is_jungle = surface_humidity > 0.75;
2767 u32 tree_count = gen_area_nodes * tree_amount_2d(data->seed, p2d_center);
2774 PseudoRandom treerandom(blockseed);
2775 // Put trees in random places on part of division
2776 for(u32 i=0; i<tree_count; i++)
2778 s16 x = treerandom.range(node_min.X, node_max.X);
2779 s16 z = treerandom.range(node_min.Z, node_max.Z);
2780 //s16 y = find_ground_level(vmanip, v2s16(x,z));
2781 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
2782 // Don't make a tree under water level
2785 // Make sure tree fits (only trees whose starting point is
2786 // at this block are added)
2787 if(y < node_min.Y || y > node_max.Y)
2790 Find exact ground level
2794 for(; p.Y >= y-6; p.Y--)
2796 u32 i = vmanip->m_area.index(p);
2797 MapNode *n = &vmanip->m_data[i];
2798 if(n->getContent() != CONTENT_AIR && n->getContent() != c_water_source && n->getContent() != CONTENT_IGNORE)
2804 // If not found, handle next one
2809 u32 i = vmanip->m_area.index(p);
2810 MapNode *n = &vmanip->m_data[i];
2812 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass && n->getContent() != c_sand)
2815 // Papyrus grows only on mud and in water
2816 if(n->getContent() == c_dirt && y <= WATER_LEVEL)
2819 make_papyrus(vmanip, p, ndef);
2821 // Trees grow only on mud and grass, on land
2822 else if((n->getContent() == c_dirt || n->getContent() == c_dirt_with_grass) && y > WATER_LEVEL + 2)
2825 //if(surface_humidity_2d(data->seed, v2s16(x, y)) < 0.5)
2826 if(is_jungle == false)
2829 if(myrand_range(0,4) != 0)
2830 is_apple_tree = false;
2832 is_apple_tree = noise2d_perlin(
2833 0.5+(float)p.X/100, 0.5+(float)p.Z/100,
2834 data->seed+342902, 3, 0.45) > 0.2;
2835 make_tree(vmanip, p, is_apple_tree, ndef);
2838 make_jungletree(vmanip, p, ndef);
2840 // Cactii grow only on sand, on land
2841 else if(n->getContent() == c_sand && y > WATER_LEVEL + 2)
2844 make_cactus(vmanip, p, ndef);
2854 PseudoRandom grassrandom(blockseed);
2855 for(u32 i=0; i<surface_humidity*5*tree_count; i++)
2857 s16 x = grassrandom.range(node_min.X, node_max.X);
2858 s16 z = grassrandom.range(node_min.Z, node_max.Z);
2859 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
2862 if(y < node_min.Y || y > node_max.Y)
2865 Find exact ground level
2869 for(; p.Y >= y-6; p.Y--)
2871 u32 i = vmanip->m_area.index(p);
2872 MapNode *n = &vmanip->m_data[i];
2873 if(data->nodedef->get(*n).is_ground_content)
2879 // If not found, handle next one
2883 if(vmanip.m_area.contains(p) == false)
2885 if(vmanip.m_data[vmanip.m_area.index(p)].getContent() != CONTENT_AIR)
2888 if(vmanip.m_area.contains(p))
2889 vmanip.m_data[vmanip.m_area.index(p)] = c_dirt;
2891 if(vmanip.m_area.contains(p))
2892 vmanip.m_data[vmanip.m_area.index(p)] = c_junglegrass;
2898 Add some kind of random stones
2901 u32 random_stone_count = gen_area_nodes *
2902 randomstone_amount_2d(data->seed, p2d_center);
2903 // Put in random places on part of division
2904 for(u32 i=0; i<random_stone_count; i++)
2906 s16 x = myrand_range(node_min.X, node_max.X);
2907 s16 z = myrand_range(node_min.Z, node_max.Z);
2908 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
2909 // Don't add under water level
2910 /*if(y < WATER_LEVEL)
2912 // Don't add if doesn't belong to this block
2913 if(y < node_min.Y || y > node_max.Y)
2918 u32 i = vmanip->m_area.index(v3s16(p));
2919 MapNode *n = &vmanip->m_data[i];
2920 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass)
2923 // Will be placed one higher
2926 make_randomstone(vmanip, p);
2935 u32 large_stone_count = gen_area_nodes *
2936 largestone_amount_2d(data->seed, p2d_center);
2937 //u32 large_stone_count = 1;
2938 // Put in random places on part of division
2939 for(u32 i=0; i<large_stone_count; i++)
2941 s16 x = myrand_range(node_min.X, node_max.X);
2942 s16 z = myrand_range(node_min.Z, node_max.Z);
2943 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
2944 // Don't add under water level
2945 /*if(y < WATER_LEVEL)
2947 // Don't add if doesn't belong to this block
2948 if(y < node_min.Y || y > node_max.Y)
2953 u32 i = vmanip->m_area.index(v3s16(p));
2954 MapNode *n = &vmanip->m_data[i];
2955 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass)
2958 // Will be placed one lower
2961 make_largestone(vmanip, p);
2971 PseudoRandom mineralrandom(blockseed);
2976 for(s16 i=0; i<approx_ground_depth/4; i++)
2978 if(mineralrandom.next()%50 == 0)
2980 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2981 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2982 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2983 for(u16 i=0; i<27; i++)
2985 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2986 u32 vi = vmanip.m_area.index(p);
2987 if(vmanip.m_data[vi].getContent() == c_stone)
2988 if(mineralrandom.next()%8 == 0)
2989 vmanip.m_data[vi] = MapNode(c_mese);
2998 u16 a = mineralrandom.range(0,15);
3000 u16 amount = 20 * a/1000;
3001 for(s16 i=0; i<amount; i++)
3003 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
3004 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
3005 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
3007 u8 base_content = c_stone;
3008 MapNode new_content(CONTENT_IGNORE);
3011 if(noisebuf_ground_crumbleness.get(x,y+5,z) < -0.1)
3013 new_content = MapNode(c_stone_with_coal);
3017 if(noisebuf_ground_wetness.get(x,y+5,z) > 0.0)
3018 new_content = MapNode(c_stone_with_iron);
3019 /*if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
3020 vmanip.m_data[i] = MapNode(c_dirt);
3022 vmanip.m_data[i] = MapNode(c_sand);*/
3024 /*else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.1)
3028 if(new_content.getContent() != CONTENT_IGNORE)
3030 for(u16 i=0; i<27; i++)
3032 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
3033 u32 vi = vmanip.m_area.index(p);
3034 if(vmanip.m_data[vi].getContent() == base_content)
3036 if(mineralrandom.next()%sparseness == 0)
3037 vmanip.m_data[vi] = new_content;
3046 //for(s16 i=0; i < MYMAX(0, 50 - abs(node_min.Y+8 - (-30))); i++)
3047 //for(s16 i=0; i<50; i++)
3048 u16 coal_amount = 30;
3049 u16 coal_rareness = 60 / coal_amount;
3050 if(coal_rareness == 0)
3052 if(mineralrandom.next()%coal_rareness == 0)
3054 u16 a = mineralrandom.next() % 16;
3055 u16 amount = coal_amount * a*a*a / 1000;
3056 for(s16 i=0; i<amount; i++)
3058 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
3059 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
3060 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
3061 for(u16 i=0; i<27; i++)
3063 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
3064 u32 vi = vmanip.m_area.index(p);
3065 if(vmanip.m_data[vi].getContent() == c_stone)
3066 if(mineralrandom.next()%8 == 0)
3067 vmanip.m_data[vi] = MapNode(c_stone_with_coal);
3074 u16 iron_amount = 8;
3075 u16 iron_rareness = 60 / iron_amount;
3076 if(iron_rareness == 0)
3078 if(mineralrandom.next()%iron_rareness == 0)
3080 u16 a = mineralrandom.next() % 16;
3081 u16 amount = iron_amount * a*a*a / 1000;
3082 for(s16 i=0; i<amount; i++)
3084 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
3085 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
3086 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
3087 for(u16 i=0; i<27; i++)
3089 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
3090 u32 vi = vmanip.m_area.index(p);
3091 if(vmanip.m_data[vi].getContent() == c_stone)
3092 if(mineralrandom.next()%8 == 0)
3093 vmanip.m_data[vi] = MapNode(c_stone_with_iron);
3104 ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update",
3106 //VoxelArea a(node_min, node_max);
3107 VoxelArea a(node_min-v3s16(1,0,1)*MAP_BLOCKSIZE,
3108 node_max+v3s16(1,0,1)*MAP_BLOCKSIZE);
3109 /*VoxelArea a(node_min-v3s16(1,0,1)*MAP_BLOCKSIZE/2,
3110 node_max+v3s16(1,0,1)*MAP_BLOCKSIZE/2);*/
3111 enum LightBank banks[2] = {LIGHTBANK_DAY, LIGHTBANK_NIGHT};
3112 for(int i=0; i<2; i++)
3114 enum LightBank bank = banks[i];
3116 core::map<v3s16, bool> light_sources;
3117 core::map<v3s16, u8> unlight_from;
3119 voxalgo::clearLightAndCollectSources(vmanip, a, bank, ndef,
3120 light_sources, unlight_from);
3122 bool inexistent_top_provides_sunlight = !block_is_underground;
3123 voxalgo::SunlightPropagateResult res = voxalgo::propagateSunlight(
3124 vmanip, a, inexistent_top_provides_sunlight,
3125 light_sources, ndef);
3126 // TODO: Do stuff according to bottom_sunlight_valid
3128 vmanip.unspreadLight(bank, unlight_from, light_sources, ndef);
3130 vmanip.spreadLight(bank, light_sources, ndef);
3135 #endif ///BIG COMMENT
3137 BlockMakeData::BlockMakeData():
3144 BlockMakeData::~BlockMakeData()
3149 //}; // namespace mapgen