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
40 MapgenV7Params mg_def_params_v7 = {
44 MG_TREES | MG_CAVES | MG_DUNGEONS,
45 &nparams_v7_def_terrain,
46 &nparams_v7_def_bgroup,
48 &nparams_v7_def_humidity
52 ///////////////////////////////////////////////////////////////////////////////
55 MapgenV7::MapgenV7(BiomeDefManager *biomedef, int mapgenid, MapgenV7Params *params) {
56 this->generating = false;
58 this->biomedef = biomedef;
60 this->seed = params->seed;
61 this->csize = v3s16(1, 1, 1) * params->chunksize * MAP_BLOCKSIZE; /////////////////get this from config!
62 this->water_level = params->water_level;
64 //g_settings->getS16("default_water_level");
67 this->np_terrain = np_terrain;
68 this->np_bgroup = np_bgroup;
69 this->np_heat = np_heat;
70 this->np_humidity = np_humidity;
72 noise_terrain = new Noise(params->np_terrain, seed, csize.X, csize.Y);
73 noise_bgroup = new Noise(params->np_bgroup, seed, csize.X, csize.Y);
74 noise_heat = new Noise(params->np_heat, seed, csize.X, csize.Y);
75 noise_humidity = new Noise(params->np_humidity, seed, csize.X, csize.Y);
77 this->ndef = biomedef->ndef;
78 n_air = MapNode(ndef->getId("mapgen_air"));
79 n_water = MapNode(ndef->getId("mapgen_water_source"));
80 n_lava = MapNode(ndef->getId("mapgen_lava_source"));
84 MapgenV7::~MapgenV7() {
88 delete noise_humidity;
92 void MapgenV7::makeChunk(BlockMakeData *data) {
97 assert(data->nodedef);
98 assert(data->blockpos_requested.X >= data->blockpos_min.X &&
99 data->blockpos_requested.Y >= data->blockpos_min.Y &&
100 data->blockpos_requested.Z >= data->blockpos_min.Z);
101 assert(data->blockpos_requested.X <= data->blockpos_max.X &&
102 data->blockpos_requested.Y <= data->blockpos_max.Y &&
103 data->blockpos_requested.Z <= data->blockpos_max.Z);
105 this->generating = true;
108 this->vmanip = data->vmanip;
109 v3s16 em = vmanip->m_area.getExtent();
110 this->ystride = em.X;
111 this->zstride = em.Y * em.X;
113 node_min = (data->blockpos_min) * MAP_BLOCKSIZE;
114 node_max = (data->blockpos_max + v3s16(1, 1, 1)) * MAP_BLOCKSIZE - v3s16(1, 1, 1);
115 v3s16 full_node_min = (data->blockpos_min - 1) * MAP_BLOCKSIZE;
116 v3s16 full_node_max = (data->blockpos_max + 2) * MAP_BLOCKSIZE - v3s16(1,1,1);
123 TimeTaker timer("Generating terrain");
124 map_terrain = noise_terrain->perlinMap2D(x, z);
125 map_bgroup = noise_bgroup->perlinMap2D(x, z);
126 map_heat = noise_heat->perlinMap2D(x, z);
127 map_humidity = noise_humidity->perlinMap2D(x, z);
129 noise_bgroup->transformNoiseMap();
130 noise_heat->transformNoiseMap();
131 noise_humidity->transformNoiseMap();
134 for (z = node_min.Z; z <= node_max.Z; z++) {
135 for (x = node_min.X; x <= node_max.X; x++) {
136 Biome *biome = biomedef->getBiome(map_bgroup[i], map_heat[i], map_humidity[i]);
137 biome->genColumn(this, x, z, y1, y2);
145 //add blobs of dirt and gravel underground
147 updateLiquid(full_node_min, full_node_max);
148 updateLighting(node_min, node_max);
150 this->generating = false;
154 void MapgenV7::updateLiquid(v3s16 nmin, v3s16 nmax) {
155 bool isliquid, wasliquid;
158 for (s16 z = nmin.Z; z <= nmax.Z; z++) {
159 for (s16 x = nmin.X; x <= nmax.X; x++) {
162 v3s16 em = vmanip->m_area.getExtent();
163 i = vmanip->m_area.index(v3s16(p2d.X, nmax.Y, p2d.Y));
165 for (s16 y = nmax.Y; y >= nmin.Y; y--) {
166 isliquid = ndef->get(vmanip->m_data[i]).isLiquid();
167 //there was a change between liquid and nonliquid, add to queue
168 if (isliquid != wasliquid)
169 data->transforming_liquid.push_back(v3s16(p2d.X, y, p2d.Y));
171 wasliquid = isliquid;
172 vmanip->m_area.add_y(em, i, -1);
179 void MapgenV7::updateLighting(v3s16 nmin, v3s16 nmax) {
180 enum LightBank banks[2] = {LIGHTBANK_DAY, LIGHTBANK_NIGHT};
182 VoxelArea a(nmin - v3s16(1,0,1) * MAP_BLOCKSIZE,
183 nmax + v3s16(1,0,1) * MAP_BLOCKSIZE);
184 bool block_is_underground = (water_level > nmax.Y);
185 bool sunlight = !block_is_underground;
187 ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update", SPT_AVG);
188 for (int i = 0; i < 2; i++) {
189 enum LightBank bank = banks[i];
190 core::map<v3s16, bool> light_sources;
191 core::map<v3s16, u8> unlight_from;
193 voxalgo::clearLightAndCollectSources(*vmanip, a, bank, ndef,
194 light_sources, unlight_from);
195 voxalgo::propagateSunlight(*vmanip, a, sunlight, light_sources, ndef);
196 //printf("light_sources: %d\t\tunlight_from: %d\n", light_sources.size(), unlight_from.size());
197 vmanip->unspreadLight(bank, unlight_from, light_sources, ndef);
198 vmanip->spreadLight(bank, light_sources, ndef);
203 EmergeManager::EmergeManager(IGameDef *gamedef, int mg_version) {
204 this->mg_version = mg_version;
205 this->biomedef = new BiomeDefManager(gamedef);
212 EmergeManager::~EmergeManager() {
218 Mapgen *EmergeManager::getMapgen() {
220 switch (mg_version) {
222 mapgen = new MapgenV6(0, params);
225 mapgen = new MapgenV7(biomedef, 0, params);
228 errorstream << "EmergeManager: Unsupported mapgen version "
229 << mg_version << ", falling back to V6" << std::endl;
231 mapgen = new MapgenV6(0, mgv6params);
238 void EmergeManager::setMapgenParams() {
242 switch (mg_version) {
244 params = new MapgenV6Params();
247 params = new MapgenV7Params();
249 default: //////do something here!
255 void EmergeManager::addBlockToQueue() {
260 Biome *EmergeManager::getBiomeAtPoint(v3s16 p) {
261 float bgroup = NoisePerlin2D(np_bgroup, p.X, p.Y, seed);
262 float heat = NoisePerlin2D(np_heat, p.X, p.Y, seed);
263 float humidity = NoisePerlin2D(np_humidity, p.X, p.Y, seed);
264 return biomedef->getBiome(bgroup, heat, humidity);
268 //FIXME: This assumes y == 0, that is, always in a non-hell/non-sky biome
269 int EmergeManager::getGroundLevelAtPoint(v2s16 p) {
270 float terrain = NoisePerlin2D(np_terrain, p.X, p.Y, seed);
271 Biome *biome = getBiomeAtPoint(v3s16(p.X, p.Y, 0));
272 return biome->getSurfaceHeight(terrain);
276 bool EmergeManager::isBlockUnderground(v3s16 blockpos) {
278 v2s16 p = v2s16((blockpos.X * MAP_BLOCKSIZE) + MAP_BLOCKSIZE / 2,
279 (blockpos.Y * MAP_BLOCKSIZE) + MAP_BLOCKSIZE / 2);
280 int ground_level = getGroundLevelAtPoint(p);
281 return blockpos.Y * (MAP_BLOCKSIZE + 1) <= min(water_level, ground_level);
284 //yuck, but then again, should i bother being accurate?
285 //the height of the nodes in a single block is quite variable
286 return blockpos.Y * (MAP_BLOCKSIZE + 1) <= water_level;
290 u32 EmergeManager::getBlockSeed(v3s16 p) {
291 return (u32)(seed & 0xFFFFFFFF) +
298 /////////////////////////////////// legacy static functions for farmesh
301 s16 Mapgen::find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision) {
302 //just need to return something
308 bool Mapgen::get_have_beach(u64 seed, v2s16 p2d) {
309 double sandnoise = noise2d_perlin(
310 0.2+(float)p2d.X/250, 0.7+(float)p2d.Y/250,
311 seed+59420, 3, 0.50);
313 return (sandnoise > 0.15);
317 double Mapgen::tree_amount_2d(u64 seed, v2s16 p) {
318 double noise = noise2d_perlin(
319 0.5+(float)p.X/125, 0.5+(float)p.Y/125,
321 double zeroval = -0.39;
325 return 0.04 * (noise-zeroval) / (1.0-zeroval);
329 #if 0 /// BIG COMMENT
334 Some helper functions for the map generator
338 // Returns Y one under area minimum if not found
339 static s16 find_ground_level(VoxelManipulator &vmanip, v2s16 p2d,
340 INodeDefManager *ndef)
342 v3s16 em = vmanip.m_area.getExtent();
343 s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
344 s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
345 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
347 for(y=y_nodes_max; y>=y_nodes_min; y--)
349 MapNode &n = vmanip.m_data[i];
350 if(ndef->get(n).walkable)
353 vmanip.m_area.add_y(em, i, -1);
358 return y_nodes_min - 1;
362 // Returns Y one under area minimum if not found
363 static s16 find_ground_level_clever(VoxelManipulator &vmanip, v2s16 p2d,
364 INodeDefManager *ndef)
366 if(!vmanip.m_area.contains(v3s16(p2d.X, vmanip.m_area.MaxEdge.Y, p2d.Y)))
367 return vmanip.m_area.MinEdge.Y-1;
368 v3s16 em = vmanip.m_area.getExtent();
369 s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
370 s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
371 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
373 content_t c_tree = ndef->getId("mapgen_tree");
374 content_t c_leaves = ndef->getId("mapgen_leaves");
375 for(y=y_nodes_max; y>=y_nodes_min; y--)
377 MapNode &n = vmanip.m_data[i];
378 if(ndef->get(n).walkable
379 && n.getContent() != c_tree
380 && n.getContent() != c_leaves)
383 vmanip.m_area.add_y(em, i, -1);
388 return y_nodes_min - 1;
392 // Returns Y one under area minimum if not found
393 static s16 find_stone_level(VoxelManipulator &vmanip, v2s16 p2d,
394 INodeDefManager *ndef)
396 v3s16 em = vmanip.m_area.getExtent();
397 s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
398 s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
399 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
401 content_t c_stone = ndef->getId("mapgen_stone");
402 content_t c_desert_stone = ndef->getId("mapgen_desert_stone");
403 for(y=y_nodes_max; y>=y_nodes_min; y--)
405 MapNode &n = vmanip.m_data[i];
406 content_t c = n.getContent();
407 if(c != CONTENT_IGNORE && (
408 c == c_stone || c == c_desert_stone))
411 vmanip.m_area.add_y(em, i, -1);
416 return y_nodes_min - 1;
423 static void make_papyrus(VoxelManipulator &vmanip, v3s16 p0,
424 INodeDefManager *ndef)
426 MapNode papyrusnode(ndef->getId("mapgen_papyrus"));
428 s16 trunk_h = myrand_range(2, 3);
430 for(s16 ii=0; ii<trunk_h; ii++)
432 if(vmanip.m_area.contains(p1))
433 vmanip.m_data[vmanip.m_area.index(p1)] = papyrusnode;
438 static void make_cactus(VoxelManipulator &vmanip, v3s16 p0,
439 INodeDefManager *ndef)
441 MapNode cactusnode(ndef->getId("mapgen_cactus"));
445 for(s16 ii=0; ii<trunk_h; ii++)
447 if(vmanip.m_area.contains(p1))
448 vmanip.m_data[vmanip.m_area.index(p1)] = cactusnode;
456 Dungeon making routines
459 #define VMANIP_FLAG_DUNGEON_INSIDE VOXELFLAG_CHECKED1
460 #define VMANIP_FLAG_DUNGEON_PRESERVE VOXELFLAG_CHECKED2
461 #define VMANIP_FLAG_DUNGEON_UNTOUCHABLE (\
462 VMANIP_FLAG_DUNGEON_INSIDE|VMANIP_FLAG_DUNGEON_PRESERVE)
464 static void make_room1(VoxelManipulator &vmanip, v3s16 roomsize, v3s16 roomplace,
465 INodeDefManager *ndef)
468 for(s16 z=0; z<roomsize.Z; z++)
469 for(s16 y=0; y<roomsize.Y; y++)
472 v3s16 p = roomplace + v3s16(0,y,z);
473 if(vmanip.m_area.contains(p) == false)
475 u32 vi = vmanip.m_area.index(p);
476 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
478 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
481 v3s16 p = roomplace + v3s16(roomsize.X-1,y,z);
482 if(vmanip.m_area.contains(p) == false)
484 u32 vi = vmanip.m_area.index(p);
485 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
487 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
492 for(s16 x=0; x<roomsize.X; x++)
493 for(s16 y=0; y<roomsize.Y; y++)
496 v3s16 p = roomplace + v3s16(x,y,0);
497 if(vmanip.m_area.contains(p) == false)
499 u32 vi = vmanip.m_area.index(p);
500 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
502 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
505 v3s16 p = roomplace + v3s16(x,y,roomsize.Z-1);
506 if(vmanip.m_area.contains(p) == false)
508 u32 vi = vmanip.m_area.index(p);
509 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
511 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
515 // Make +-Y walls (floor and ceiling)
516 for(s16 z=0; z<roomsize.Z; z++)
517 for(s16 x=0; x<roomsize.X; x++)
520 v3s16 p = roomplace + v3s16(x,0,z);
521 if(vmanip.m_area.contains(p) == false)
523 u32 vi = vmanip.m_area.index(p);
524 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
526 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
529 v3s16 p = roomplace + v3s16(x,roomsize.Y-1,z);
530 if(vmanip.m_area.contains(p) == false)
532 u32 vi = vmanip.m_area.index(p);
533 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
535 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
540 for(s16 z=1; z<roomsize.Z-1; z++)
541 for(s16 y=1; y<roomsize.Y-1; y++)
542 for(s16 x=1; x<roomsize.X-1; x++)
544 v3s16 p = roomplace + v3s16(x,y,z);
545 if(vmanip.m_area.contains(p) == false)
547 u32 vi = vmanip.m_area.index(p);
548 vmanip.m_flags[vi] |= VMANIP_FLAG_DUNGEON_UNTOUCHABLE;
549 vmanip.m_data[vi] = MapNode(CONTENT_AIR);
553 static void make_fill(VoxelManipulator &vmanip, v3s16 place, v3s16 size,
554 u8 avoid_flags, MapNode n, u8 or_flags)
556 for(s16 z=0; z<size.Z; z++)
557 for(s16 y=0; y<size.Y; y++)
558 for(s16 x=0; x<size.X; x++)
560 v3s16 p = place + v3s16(x,y,z);
561 if(vmanip.m_area.contains(p) == false)
563 u32 vi = vmanip.m_area.index(p);
564 if(vmanip.m_flags[vi] & avoid_flags)
566 vmanip.m_flags[vi] |= or_flags;
567 vmanip.m_data[vi] = n;
571 static void make_hole1(VoxelManipulator &vmanip, v3s16 place,
572 INodeDefManager *ndef)
574 make_fill(vmanip, place, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
575 VMANIP_FLAG_DUNGEON_INSIDE);
578 static void make_door1(VoxelManipulator &vmanip, v3s16 doorplace, v3s16 doordir,
579 INodeDefManager *ndef)
581 make_hole1(vmanip, doorplace, ndef);
582 // Place torch (for testing)
583 //vmanip.m_data[vmanip.m_area.index(doorplace)] = MapNode(ndef->getId("mapgen_torch"));
586 static v3s16 rand_ortho_dir(PseudoRandom &random)
588 if(random.next()%2==0)
589 return random.next()%2 ? v3s16(-1,0,0) : v3s16(1,0,0);
591 return random.next()%2 ? v3s16(0,0,-1) : v3s16(0,0,1);
594 static v3s16 turn_xz(v3s16 olddir, int t)
614 static v3s16 random_turn(PseudoRandom &random, v3s16 olddir)
616 int turn = random.range(0,2);
625 dir = turn_xz(olddir, 0);
628 dir = turn_xz(olddir, 1);
632 static void make_corridor(VoxelManipulator &vmanip, v3s16 doorplace,
633 v3s16 doordir, v3s16 &result_place, v3s16 &result_dir,
634 PseudoRandom &random, INodeDefManager *ndef)
636 make_hole1(vmanip, doorplace, ndef);
637 v3s16 p0 = doorplace;
641 length = random.range(1,13);
643 length = random.range(1,6);
644 length = random.range(1,13);
645 u32 partlength = random.range(1,13);
648 if(random.next()%2 == 0 && partlength >= 3)
649 make_stairs = random.next()%2 ? 1 : -1;
650 for(u32 i=0; i<length; i++)
656 /*// If already empty
657 if(vmanip.getNodeNoExNoEmerge(p).getContent()
659 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
664 if(vmanip.m_area.contains(p) == true
665 && vmanip.m_area.contains(p+v3s16(0,1,0)) == true)
669 make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,5,3),
670 VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(ndef->getId("mapgen_cobble")), 0);
671 make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
672 VMANIP_FLAG_DUNGEON_INSIDE);
673 make_fill(vmanip, p-dir, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
674 VMANIP_FLAG_DUNGEON_INSIDE);
678 make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,4,3),
679 VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(ndef->getId("mapgen_cobble")), 0);
680 make_hole1(vmanip, p, ndef);
681 /*make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
682 VMANIP_FLAG_DUNGEON_INSIDE);*/
689 // Can't go here, turn away
690 dir = turn_xz(dir, random.range(0,1));
691 make_stairs = -make_stairs;
693 partlength = random.range(1,length);
698 if(partcount >= partlength)
702 dir = random_turn(random, dir);
704 partlength = random.range(1,length);
707 if(random.next()%2 == 0 && partlength >= 3)
708 make_stairs = random.next()%2 ? 1 : -1;
719 RoomWalker(VoxelManipulator &vmanip_, v3s16 pos, PseudoRandom &random,
720 INodeDefManager *ndef):
731 m_dir = rand_ortho_dir(m_random);
734 void setPos(v3s16 pos)
739 void setDir(v3s16 dir)
744 bool findPlaceForDoor(v3s16 &result_place, v3s16 &result_dir)
746 for(u32 i=0; i<100; i++)
748 v3s16 p = m_pos + m_dir;
749 v3s16 p1 = p + v3s16(0,1,0);
750 if(vmanip.m_area.contains(p) == false
751 || vmanip.m_area.contains(p1) == false
757 if(vmanip.getNodeNoExNoEmerge(p).getContent()
758 == m_ndef->getId("mapgen_cobble")
759 && vmanip.getNodeNoExNoEmerge(p1).getContent()
760 == m_ndef->getId("mapgen_cobble"))
762 // Found wall, this is a good place!
765 // Randomize next direction
770 Determine where to move next
772 // Jump one up if the actual space is there
773 if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).getContent()
774 == m_ndef->getId("mapgen_cobble")
775 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
777 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,2,0)).getContent()
780 // Jump one down if the actual space is there
781 if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
782 == m_ndef->getId("mapgen_cobble")
783 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).getContent()
785 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,-1,0)).getContent()
788 // Check if walking is now possible
789 if(vmanip.getNodeNoExNoEmerge(p).getContent()
791 || vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
794 // Cannot continue walking here
804 bool findPlaceForRoomDoor(v3s16 roomsize, v3s16 &result_doorplace,
805 v3s16 &result_doordir, v3s16 &result_roomplace)
807 for(s16 trycount=0; trycount<30; trycount++)
811 bool r = findPlaceForDoor(doorplace, doordir);
815 // X east, Z north, Y up
817 if(doordir == v3s16(1,0,0)) // X+
818 roomplace = doorplace +
819 v3s16(0,-1,m_random.range(-roomsize.Z+2,-2));
820 if(doordir == v3s16(-1,0,0)) // X-
821 roomplace = doorplace +
822 v3s16(-roomsize.X+1,-1,m_random.range(-roomsize.Z+2,-2));
823 if(doordir == v3s16(0,0,1)) // Z+
824 roomplace = doorplace +
825 v3s16(m_random.range(-roomsize.X+2,-2),-1,0);
826 if(doordir == v3s16(0,0,-1)) // Z-
827 roomplace = doorplace +
828 v3s16(m_random.range(-roomsize.X+2,-2),-1,-roomsize.Z+1);
831 if(doordir == v3s16(1,0,0)) // X+
832 roomplace = doorplace + v3s16(0,-1,-roomsize.Z/2);
833 if(doordir == v3s16(-1,0,0)) // X-
834 roomplace = doorplace + v3s16(-roomsize.X+1,-1,-roomsize.Z/2);
835 if(doordir == v3s16(0,0,1)) // Z+
836 roomplace = doorplace + v3s16(-roomsize.X/2,-1,0);
837 if(doordir == v3s16(0,0,-1)) // Z-
838 roomplace = doorplace + v3s16(-roomsize.X/2,-1,-roomsize.Z+1);
843 for(s16 z=1; z<roomsize.Z-1; z++)
844 for(s16 y=1; y<roomsize.Y-1; y++)
845 for(s16 x=1; x<roomsize.X-1; x++)
847 v3s16 p = roomplace + v3s16(x,y,z);
848 if(vmanip.m_area.contains(p) == false)
853 if(vmanip.m_flags[vmanip.m_area.index(p)]
854 & VMANIP_FLAG_DUNGEON_INSIDE)
865 result_doorplace = doorplace;
866 result_doordir = doordir;
867 result_roomplace = roomplace;
874 VoxelManipulator &vmanip;
877 PseudoRandom &m_random;
878 INodeDefManager *m_ndef;
881 static void make_dungeon1(VoxelManipulator &vmanip, PseudoRandom &random,
882 INodeDefManager *ndef)
884 v3s16 areasize = vmanip.m_area.getExtent();
889 Find place for first room
892 for(u32 i=0; i<100; i++)
894 roomsize = v3s16(random.range(4,8),random.range(4,6),random.range(4,8));
895 roomplace = vmanip.m_area.MinEdge + v3s16(
896 random.range(0,areasize.X-roomsize.X-1),
897 random.range(0,areasize.Y-roomsize.Y-1),
898 random.range(0,areasize.Z-roomsize.Z-1));
900 Check that we're not putting the room to an unknown place,
901 otherwise it might end up floating in the air
904 for(s16 z=1; z<roomsize.Z-1; z++)
905 for(s16 y=1; y<roomsize.Y-1; y++)
906 for(s16 x=1; x<roomsize.X-1; x++)
908 v3s16 p = roomplace + v3s16(x,y,z);
909 u32 vi = vmanip.m_area.index(p);
910 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_INSIDE)
915 if(vmanip.m_data[vi].getContent() == CONTENT_IGNORE)
929 Stores the center position of the last room made, so that
930 a new corridor can be started from the last room instead of
931 the new room, if chosen so.
933 v3s16 last_room_center = roomplace+v3s16(roomsize.X/2,1,roomsize.Z/2);
935 u32 room_count = random.range(2,7);
936 for(u32 i=0; i<room_count; i++)
938 // Make a room to the determined place
939 make_room1(vmanip, roomsize, roomplace, ndef);
941 v3s16 room_center = roomplace + v3s16(roomsize.X/2,1,roomsize.Z/2);
943 // Place torch at room center (for testing)
944 //vmanip.m_data[vmanip.m_area.index(room_center)] = MapNode(ndef->getId("mapgen_torch"));
947 if(i == room_count-1)
950 // Determine walker start position
952 bool start_in_last_room = (random.range(0,2)!=0);
953 //bool start_in_last_room = true;
955 v3s16 walker_start_place;
957 if(start_in_last_room)
959 walker_start_place = last_room_center;
963 walker_start_place = room_center;
964 // Store center of current room as the last one
965 last_room_center = room_center;
968 // Create walker and find a place for a door
969 RoomWalker walker(vmanip, walker_start_place, random, ndef);
972 bool r = walker.findPlaceForDoor(doorplace, doordir);
976 if(random.range(0,1)==0)
978 make_door1(vmanip, doorplace, doordir, ndef);
980 // Don't actually make a door
981 doorplace -= doordir;
983 // Make a random corridor starting from the door
985 v3s16 corridor_end_dir;
986 make_corridor(vmanip, doorplace, doordir, corridor_end,
987 corridor_end_dir, random, ndef);
989 // Find a place for a random sized room
990 roomsize = v3s16(random.range(4,8),random.range(4,6),random.range(4,8));
991 walker.setPos(corridor_end);
992 walker.setDir(corridor_end_dir);
993 r = walker.findPlaceForRoomDoor(roomsize, doorplace, doordir, roomplace);
997 if(random.range(0,1)==0)
999 make_door1(vmanip, doorplace, doordir, ndef);
1001 // Don't actually make a door
1002 roomplace -= doordir;
1009 static void make_nc(VoxelManipulator &vmanip, PseudoRandom &random,
1010 INodeDefManager *ndef)
1014 s32 r = random.range(0, 3);
1016 dir = v3s16( 1, 0, 0);
1020 dir = v3s16(-1, 0, 0);
1024 dir = v3s16( 0, 0, 1);
1028 dir = v3s16( 0, 0,-1);
1031 v3s16 p = vmanip.m_area.MinEdge + v3s16(
1032 16+random.range(0,15),
1033 16+random.range(0,15),
1034 16+random.range(0,15));
1035 vmanip.m_data[vmanip.m_area.index(p)] = MapNode(ndef->getId("mapgen_nyancat"), facedir_i);
1036 u32 length = random.range(3,15);
1037 for(u32 j=0; j<length; j++)
1040 vmanip.m_data[vmanip.m_area.index(p)] = MapNode(ndef->getId("mapgen_nyancat_rainbow"));
1046 Noise functions. Make sure seed is mangled differently in each one.
1051 Scaling the output of the noise function affects the overdrive of the
1052 contour function, which affects the shape of the output considerably.
1054 #define CAVE_NOISE_SCALE 12.0
1055 //#define CAVE_NOISE_SCALE 10.0
1056 //#define CAVE_NOISE_SCALE 7.5
1057 //#define CAVE_NOISE_SCALE 5.0
1058 //#define CAVE_NOISE_SCALE 1.0
1060 //#define CAVE_NOISE_THRESHOLD (2.5/CAVE_NOISE_SCALE)
1061 #define CAVE_NOISE_THRESHOLD (1.5/CAVE_NOISE_SCALE)
1063 NoiseParams get_cave_noise1_params(u64 seed)
1065 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.7,
1066 200, CAVE_NOISE_SCALE);*/
1067 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.7,
1068 100, CAVE_NOISE_SCALE);*/
1069 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.6,
1070 100, CAVE_NOISE_SCALE);*/
1071 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.3,
1072 100, CAVE_NOISE_SCALE);*/
1073 return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.5,
1074 50, CAVE_NOISE_SCALE);
1075 //return NoiseParams(NOISE_CONSTANT_ONE);
1078 NoiseParams get_cave_noise2_params(u64 seed)
1080 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.7,
1081 200, CAVE_NOISE_SCALE);*/
1082 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.7,
1083 100, CAVE_NOISE_SCALE);*/
1084 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.3,
1085 100, CAVE_NOISE_SCALE);*/
1086 return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.5,
1087 50, CAVE_NOISE_SCALE);
1088 //return NoiseParams(NOISE_CONSTANT_ONE);
1091 NoiseParams get_ground_noise1_params(u64 seed)
1093 return NoiseParams(NOISE_PERLIN, seed+983240, 4,
1097 NoiseParams get_ground_crumbleness_params(u64 seed)
1099 return NoiseParams(NOISE_PERLIN, seed+34413, 3,
1103 NoiseParams get_ground_wetness_params(u64 seed)
1105 return NoiseParams(NOISE_PERLIN, seed+32474, 4,
1109 bool is_cave(u64 seed, v3s16 p)
1111 double d1 = noise3d_param(get_cave_noise1_params(seed), p.X,p.Y,p.Z);
1112 double d2 = noise3d_param(get_cave_noise2_params(seed), p.X,p.Y,p.Z);
1113 return d1*d2 > CAVE_NOISE_THRESHOLD;
1117 Ground density noise shall be interpreted by using this.
1119 TODO: No perlin noises here, they should be outsourced
1121 NOTE: The speed of these actually isn't terrible
1123 bool val_is_ground(double ground_noise1_val, v3s16 p, u64 seed)
1125 //return ((double)p.Y < ground_noise1_val);
1127 double f = 0.55 + noise2d_perlin(
1128 0.5+(float)p.X/250, 0.5+(float)p.Z/250,
1129 seed+920381, 3, 0.45);
1134 double h = WATER_LEVEL + 10 * noise2d_perlin(
1135 0.5+(float)p.X/250, 0.5+(float)p.Z/250,
1136 seed+84174, 4, 0.5);
1139 return ((double)p.Y - h < ground_noise1_val * f);
1143 Queries whether a position is ground or not.
1145 bool is_ground(u64 seed, v3s16 p)
1147 double val1 = noise3d_param(get_ground_noise1_params(seed), p.X,p.Y,p.Z);
1148 return val_is_ground(val1, p, seed);
1152 // Amount of trees per area in nodes
1153 double tree_amount_2d(u64 seed, v2s16 p)
1155 /*double noise = noise2d_perlin(
1156 0.5+(float)p.X/250, 0.5+(float)p.Y/250,
1158 double noise = noise2d_perlin(
1159 0.5+(float)p.X/125, 0.5+(float)p.Y/125,
1161 double zeroval = -0.39;
1165 return 0.04 * (noise-zeroval) / (1.0-zeroval);
1169 double surface_humidity_2d(u64 seed, v2s16 p)
1171 double noise = noise2d_perlin(
1172 0.5+(float)p.X/500, 0.5+(float)p.Y/500,
1173 seed+72384, 4, 0.66);
1174 noise = (noise + 1.0)/2.0;
1183 Incrementally find ground level from 3d noise
1185 s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision)
1187 // Start a bit fuzzy to make averaging lower precision values
1189 s16 level = myrand_range(-precision/2, precision/2);
1190 s16 dec[] = {31000, 100, 20, 4, 1, 0};
1192 for(i = 1; dec[i] != 0 && precision <= dec[i]; i++)
1194 // First find non-ground by going upwards
1195 // Don't stop in caves.
1197 s16 max = level+dec[i-1]*2;
1198 v3s16 p(p2d.X, level, p2d.Y);
1199 for(; p.Y < max; p.Y += dec[i])
1201 if(!is_ground(seed, p))
1208 // Then find ground by going downwards from there.
1209 // Go in caves, too, when precision is 1.
1211 s16 min = level-dec[i-1]*2;
1212 v3s16 p(p2d.X, level, p2d.Y);
1213 for(; p.Y>min; p.Y-=dec[i])
1215 bool ground = is_ground(seed, p);
1216 /*if(dec[i] == 1 && is_cave(seed, p))
1227 // This is more like the actual ground level
1228 level += dec[i-1]/2;
1233 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1235 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p)
1237 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1238 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1240 a += find_ground_level_from_noise(seed,
1241 v2s16(node_min.X, node_min.Y), p);
1242 a += find_ground_level_from_noise(seed,
1243 v2s16(node_min.X, node_max.Y), p);
1244 a += find_ground_level_from_noise(seed,
1245 v2s16(node_max.X, node_max.Y), p);
1246 a += find_ground_level_from_noise(seed,
1247 v2s16(node_max.X, node_min.Y), p);
1248 a += find_ground_level_from_noise(seed,
1249 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p);
1254 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1256 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p)
1258 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1259 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1262 a = MYMAX(a, find_ground_level_from_noise(seed,
1263 v2s16(node_min.X, node_min.Y), p));
1264 a = MYMAX(a, find_ground_level_from_noise(seed,
1265 v2s16(node_min.X, node_max.Y), p));
1266 a = MYMAX(a, find_ground_level_from_noise(seed,
1267 v2s16(node_max.X, node_max.Y), p));
1268 a = MYMAX(a, find_ground_level_from_noise(seed,
1269 v2s16(node_min.X, node_min.Y), p));
1271 a = MYMAX(a, find_ground_level_from_noise(seed,
1272 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
1273 // Side middle points
1274 a = MYMAX(a, find_ground_level_from_noise(seed,
1275 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
1276 a = MYMAX(a, find_ground_level_from_noise(seed,
1277 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
1278 a = MYMAX(a, find_ground_level_from_noise(seed,
1279 v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1280 a = MYMAX(a, find_ground_level_from_noise(seed,
1281 v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1285 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1287 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p)
1289 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1290 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1293 a = MYMIN(a, find_ground_level_from_noise(seed,
1294 v2s16(node_min.X, node_min.Y), p));
1295 a = MYMIN(a, find_ground_level_from_noise(seed,
1296 v2s16(node_min.X, node_max.Y), p));
1297 a = MYMIN(a, find_ground_level_from_noise(seed,
1298 v2s16(node_max.X, node_max.Y), p));
1299 a = MYMIN(a, find_ground_level_from_noise(seed,
1300 v2s16(node_min.X, node_min.Y), p));
1302 a = MYMIN(a, find_ground_level_from_noise(seed,
1303 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
1304 // Side middle points
1305 a = MYMIN(a, find_ground_level_from_noise(seed,
1306 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
1307 a = MYMIN(a, find_ground_level_from_noise(seed,
1308 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
1309 a = MYMIN(a, find_ground_level_from_noise(seed,
1310 v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1311 a = MYMIN(a, find_ground_level_from_noise(seed,
1312 v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1317 // Required by mapgen.h
1318 bool block_is_underground(u64 seed, v3s16 blockpos)
1320 /*s16 minimum_groundlevel = (s16)get_sector_minimum_ground_level(
1321 seed, v2s16(blockpos.X, blockpos.Z));*/
1322 // Nah, this is just a heuristic, just return something
1323 s16 minimum_groundlevel = WATER_LEVEL;
1325 if(blockpos.Y*MAP_BLOCKSIZE + MAP_BLOCKSIZE <= minimum_groundlevel)
1331 #define AVERAGE_MUD_AMOUNT 4
1333 double base_rock_level_2d(u64 seed, v2s16 p)
1335 // The base ground level
1336 double base = (double)WATER_LEVEL - (double)AVERAGE_MUD_AMOUNT
1337 + 20. * noise2d_perlin(
1338 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1339 seed+82341, 5, 0.6);
1341 /*// A bit hillier one
1342 double base2 = WATER_LEVEL - 4.0 + 40. * noise2d_perlin(
1343 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1344 seed+93413, 6, 0.69);
1348 // Higher ground level
1349 double higher = (double)WATER_LEVEL + 20. + 16. * noise2d_perlin(
1350 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
1351 seed+85039, 5, 0.6);
1352 //higher = 30; // For debugging
1354 // Limit higher to at least base
1358 // Steepness factor of cliffs
1359 double b = 0.85 + 0.5 * noise2d_perlin(
1360 0.5+(float)p.X/125., 0.5+(float)p.Y/125.,
1362 b = rangelim(b, 0.0, 1000.0);
1365 b = rangelim(b, 0.5, 1000.0);
1366 // Values 1.5...100 give quite horrible looking slopes
1367 if(b > 1.5 && b < 100.0){
1373 //dstream<<"b="<<b<<std::endl;
1377 // Offset to more low
1378 double a_off = -0.20;
1379 // High/low selector
1380 /*double a = 0.5 + b * (a_off + noise2d_perlin(
1381 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
1382 seed+4213, 6, 0.7));*/
1383 double a = (double)0.5 + b * (a_off + noise2d_perlin(
1384 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1385 seed+4213, 5, 0.69));
1387 a = rangelim(a, 0.0, 1.0);
1389 //dstream<<"a="<<a<<std::endl;
1391 double h = base*(1.0-a) + higher*a;
1398 s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision)
1400 return base_rock_level_2d(seed, p2d) + AVERAGE_MUD_AMOUNT;
1403 double get_mud_add_amount(u64 seed, v2s16 p)
1405 return ((float)AVERAGE_MUD_AMOUNT + 2.0 * noise2d_perlin(
1406 0.5+(float)p.X/200, 0.5+(float)p.Y/200,
1407 seed+91013, 3, 0.55));
1410 bool get_have_beach(u64 seed, v2s16 p2d)
1412 // Determine whether to have sand here
1413 double sandnoise = noise2d_perlin(
1414 0.2+(float)p2d.X/250, 0.7+(float)p2d.Y/250,
1415 seed+59420, 3, 0.50);
1417 return (sandnoise > 0.15);
1426 BiomeType get_biome(u64 seed, v2s16 p2d)
1428 // Just do something very simple as for now
1429 double d = noise2d_perlin(
1430 0.6+(float)p2d.X/250, 0.2+(float)p2d.Y/250,
1431 seed+9130, 3, 0.50);
1434 if(d > 0.35 && (noise2d( p2d.X, p2d.Y, int(seed) ) + 1.0) > ( 0.45 - d ) * 20.0 )
1439 u32 get_blockseed(u64 seed, v3s16 p)
1441 s32 x=p.X, y=p.Y, z=p.Z;
1442 return (u32)(seed%0x100000000ULL) + z*38134234 + y*42123 + x*23;
1445 #define VMANIP_FLAG_CAVE VOXELFLAG_CHECKED1
1447 void make_block(BlockMakeData *data)
1451 //dstream<<"makeBlock: no-op"<<std::endl;
1455 assert(data->vmanip);
1456 assert(data->nodedef);
1457 assert(data->blockpos_requested.X >= data->blockpos_min.X &&
1458 data->blockpos_requested.Y >= data->blockpos_min.Y &&
1459 data->blockpos_requested.Z >= data->blockpos_min.Z);
1460 assert(data->blockpos_requested.X <= data->blockpos_max.X &&
1461 data->blockpos_requested.Y <= data->blockpos_max.Y &&
1462 data->blockpos_requested.Z <= data->blockpos_max.Z);
1464 INodeDefManager *ndef = data->nodedef;
1466 // Hack: use minimum block coordinates for old code that assumes
1468 v3s16 blockpos = data->blockpos_requested;
1470 /*dstream<<"makeBlock(): ("<<blockpos.X<<","<<blockpos.Y<<","
1471 <<blockpos.Z<<")"<<std::endl;*/
1473 v3s16 blockpos_min = data->blockpos_min;
1474 v3s16 blockpos_max = data->blockpos_max;
1475 v3s16 blockpos_full_min = blockpos_min - v3s16(1,1,1);
1476 v3s16 blockpos_full_max = blockpos_max + v3s16(1,1,1);
1478 ManualMapVoxelManipulator &vmanip = *(data->vmanip);
1479 // Area of central chunk
1480 v3s16 node_min = blockpos_min*MAP_BLOCKSIZE;
1481 v3s16 node_max = (blockpos_max+v3s16(1,1,1))*MAP_BLOCKSIZE-v3s16(1,1,1);
1482 // Full allocated area
1483 v3s16 full_node_min = (blockpos_min-1)*MAP_BLOCKSIZE;
1484 v3s16 full_node_max = (blockpos_max+2)*MAP_BLOCKSIZE-v3s16(1,1,1);
1486 v3s16 central_area_size = node_max - node_min + v3s16(1,1,1);
1488 const s16 max_spread_amount = MAP_BLOCKSIZE;
1490 int volume_blocks = (blockpos_max.X - blockpos_min.X + 1)
1491 * (blockpos_max.Y - blockpos_min.Y + 1)
1492 * (blockpos_max.Z - blockpos_max.Z + 1);
1494 int volume_nodes = volume_blocks *
1495 MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
1497 // Generated surface area
1498 //double gen_area_nodes = MAP_BLOCKSIZE*MAP_BLOCKSIZE * rel_volume;
1500 // Horribly wrong heuristic, but better than nothing
1501 bool block_is_underground = (WATER_LEVEL > node_max.Y);
1504 Create a block-specific seed
1506 u32 blockseed = get_blockseed(data->seed, full_node_min);
1509 Cache some ground type values for speed
1512 // Creates variables c_name=id and n_name=node
1513 #define CONTENT_VARIABLE(ndef, name)\
1514 content_t c_##name = ndef->getId("mapgen_" #name);\
1515 MapNode n_##name(c_##name);
1516 // Default to something else if was CONTENT_IGNORE
1517 #define CONTENT_VARIABLE_FALLBACK(name, dname)\
1518 if(c_##name == CONTENT_IGNORE){\
1519 c_##name = c_##dname;\
1520 n_##name = n_##dname;\
1523 CONTENT_VARIABLE(ndef, stone);
1524 CONTENT_VARIABLE(ndef, air);
1525 CONTENT_VARIABLE(ndef, water_source);
1526 CONTENT_VARIABLE(ndef, dirt);
1527 CONTENT_VARIABLE(ndef, sand);
1528 CONTENT_VARIABLE(ndef, gravel);
1529 CONTENT_VARIABLE(ndef, clay);
1530 CONTENT_VARIABLE(ndef, lava_source);
1531 CONTENT_VARIABLE(ndef, cobble);
1532 CONTENT_VARIABLE(ndef, mossycobble);
1533 CONTENT_VARIABLE(ndef, dirt_with_grass);
1534 CONTENT_VARIABLE(ndef, junglegrass);
1535 CONTENT_VARIABLE(ndef, stone_with_coal);
1536 CONTENT_VARIABLE(ndef, stone_with_iron);
1537 CONTENT_VARIABLE(ndef, mese);
1538 CONTENT_VARIABLE(ndef, desert_sand);
1539 CONTENT_VARIABLE_FALLBACK(desert_sand, sand);
1540 CONTENT_VARIABLE(ndef, desert_stone);
1541 CONTENT_VARIABLE_FALLBACK(desert_stone, stone);
1543 // Maximum height of the stone surface and obstacles.
1544 // This is used to guide the cave generation
1545 s16 stone_surface_max_y = 0;
1548 Generate general ground level to full area
1552 TimeTaker timer1("Generating ground level");
1554 for(s16 x=node_min.X; x<=node_max.X; x++)
1555 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1558 v2s16 p2d = v2s16(x,z);
1561 Skip of already generated
1564 v3s16 p(p2d.X, node_min.Y, p2d.Y);
1565 if(vmanip.m_data[vmanip.m_area.index(p)].d != CONTENT_AIR)
1569 // Ground height at this point
1570 float surface_y_f = 0.0;
1572 // Use perlin noise for ground height
1573 surface_y_f = base_rock_level_2d(data->seed, p2d);
1575 /*// Experimental stuff
1577 float a = highlands_level_2d(data->seed, p2d);
1582 // Convert to integer
1583 s16 surface_y = (s16)surface_y_f;
1586 if(surface_y > stone_surface_max_y)
1587 stone_surface_max_y = surface_y;
1589 BiomeType bt = get_biome(data->seed, p2d);
1591 Fill ground with stone
1594 // Use fast index incrementing
1595 v3s16 em = vmanip.m_area.getExtent();
1596 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
1597 for(s16 y=node_min.Y; y<=node_max.Y; y++)
1599 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE){
1601 if(y > WATER_LEVEL && bt == BT_DESERT)
1602 vmanip.m_data[i] = n_desert_stone;
1604 vmanip.m_data[i] = n_stone;
1605 } else if(y <= WATER_LEVEL){
1606 vmanip.m_data[i] = MapNode(c_water_source);
1608 vmanip.m_data[i] = MapNode(c_air);
1611 vmanip.m_area.add_y(em, i, 1);
1619 // Limit dirt flow area by 1 because mud is flown into neighbors.
1620 assert(central_area_size.X == central_area_size.Z);
1621 s16 mudflow_minpos = 0-max_spread_amount+1;
1622 s16 mudflow_maxpos = central_area_size.X+max_spread_amount-2;
1625 Loop this part, it will make stuff look older and newer nicely
1628 const u32 age_loops = 2;
1629 for(u32 i_age=0; i_age<age_loops; i_age++)
1631 /******************************
1632 BEGINNING OF AGING LOOP
1633 ******************************/
1638 //TimeTaker timer1("caves");
1641 Make caves (this code is relatively horrible)
1643 double cave_amount = 6.0 + 6.0 * noise2d_perlin(
1644 0.5+(double)node_min.X/250, 0.5+(double)node_min.Y/250,
1645 data->seed+34329, 3, 0.50);
1646 cave_amount = MYMAX(0.0, cave_amount);
1647 u32 caves_count = cave_amount * volume_nodes / 50000;
1648 u32 bruises_count = 1;
1649 PseudoRandom ps(blockseed+21343);
1650 PseudoRandom ps2(blockseed+1032);
1651 if(ps.range(1, 6) == 1)
1652 bruises_count = ps.range(0, ps.range(0, 2));
1653 if(get_biome(data->seed, v2s16(node_min.X, node_min.Y)) == BT_DESERT){
1657 for(u32 jj=0; jj<caves_count+bruises_count; jj++)
1659 bool large_cave = (jj >= caves_count);
1660 s16 min_tunnel_diameter = 2;
1661 s16 max_tunnel_diameter = ps.range(2,6);
1662 int dswitchint = ps.range(1,14);
1663 u16 tunnel_routepoints = 0;
1664 int part_max_length_rs = 0;
1666 part_max_length_rs = ps.range(2,4);
1667 tunnel_routepoints = ps.range(5, ps.range(15,30));
1668 min_tunnel_diameter = 5;
1669 max_tunnel_diameter = ps.range(7, ps.range(8,24));
1671 part_max_length_rs = ps.range(2,9);
1672 tunnel_routepoints = ps.range(10, ps.range(15,30));
1674 bool large_cave_is_flat = (ps.range(0,1) == 0);
1676 v3f main_direction(0,0,0);
1678 // Allowed route area size in nodes
1679 v3s16 ar = central_area_size;
1681 // Area starting point in nodes
1682 v3s16 of = node_min;
1685 //(this should be more than the maximum radius of the tunnel)
1686 //s16 insure = 5; // Didn't work with max_d = 20
1688 s16 more = max_spread_amount - max_tunnel_diameter/2 - insure;
1689 ar += v3s16(1,0,1) * more * 2;
1690 of -= v3s16(1,0,1) * more;
1692 s16 route_y_min = 0;
1693 // Allow half a diameter + 7 over stone surface
1694 s16 route_y_max = -of.Y + stone_surface_max_y + max_tunnel_diameter/2 + 7;
1696 /*// If caves, don't go through surface too often
1697 if(large_cave == false)
1698 route_y_max -= ps.range(0, max_tunnel_diameter*2);*/
1700 // Limit maximum to area
1701 route_y_max = rangelim(route_y_max, 0, ar.Y-1);
1705 /*// Minimum is at y=0
1706 route_y_min = -of.Y - 0;*/
1707 // Minimum is at y=max_tunnel_diameter/4
1708 //route_y_min = -of.Y + max_tunnel_diameter/4;
1709 //s16 min = -of.Y + max_tunnel_diameter/4;
1710 //s16 min = -of.Y + 0;
1712 if(node_min.Y < WATER_LEVEL && node_max.Y > WATER_LEVEL)
1714 min = WATER_LEVEL - max_tunnel_diameter/3 - of.Y;
1715 route_y_max = WATER_LEVEL + max_tunnel_diameter/3 - of.Y;
1717 route_y_min = ps.range(min, min + max_tunnel_diameter);
1718 route_y_min = rangelim(route_y_min, 0, route_y_max);
1721 /*dstream<<"route_y_min = "<<route_y_min
1722 <<", route_y_max = "<<route_y_max<<std::endl;*/
1724 s16 route_start_y_min = route_y_min;
1725 s16 route_start_y_max = route_y_max;
1727 // Start every 4th cave from surface when applicable
1728 /*bool coming_from_surface = false;
1729 if(node_min.Y <= 0 && node_max.Y >= 0){
1730 coming_from_surface = (jj % 4 == 0 && large_cave == false);
1731 if(coming_from_surface)
1732 route_start_y_min = -of.Y + stone_surface_max_y + 10;
1735 route_start_y_min = rangelim(route_start_y_min, 0, ar.Y-1);
1736 route_start_y_max = rangelim(route_start_y_max, route_start_y_min, ar.Y-1);
1738 // Randomize starting position
1740 (float)(ps.next()%ar.X)+0.5,
1741 (float)(ps.range(route_start_y_min, route_start_y_max))+0.5,
1742 (float)(ps.next()%ar.Z)+0.5
1745 v3s16 startp(orp.X, orp.Y, orp.Z);
1748 MapNode airnode(CONTENT_AIR);
1749 MapNode waternode(c_water_source);
1750 MapNode lavanode(c_lava_source);
1753 Generate some tunnel starting from orp
1756 for(u16 j=0; j<tunnel_routepoints; j++)
1758 if(j%dswitchint==0 && large_cave == false)
1760 main_direction = v3f(
1761 ((float)(ps.next()%20)-(float)10)/10,
1762 ((float)(ps.next()%20)-(float)10)/30,
1763 ((float)(ps.next()%20)-(float)10)/10
1765 main_direction *= (float)ps.range(0, 10)/10;
1769 s16 min_d = min_tunnel_diameter;
1770 s16 max_d = max_tunnel_diameter;
1771 s16 rs = ps.range(min_d, max_d);
1773 // Every second section is rough
1774 bool randomize_xz = (ps2.range(1,2) == 1);
1780 rs*part_max_length_rs,
1781 rs*part_max_length_rs/2,
1782 rs*part_max_length_rs
1788 rs*part_max_length_rs,
1789 ps.range(1, rs*part_max_length_rs),
1790 rs*part_max_length_rs
1797 (float)(ps.next()%(maxlen.X*1))-(float)maxlen.X/2,
1798 (float)(ps.next()%(maxlen.Y*1))-(float)maxlen.Y/2,
1799 (float)(ps.next()%(maxlen.Z*1))-(float)maxlen.Z/2
1802 // Jump downward sometimes
1803 if(!large_cave && ps.range(0,12) == 0)
1806 (float)(ps.next()%(maxlen.X*1))-(float)maxlen.X/2,
1807 (float)(ps.next()%(maxlen.Y*2))-(float)maxlen.Y*2/2,
1808 (float)(ps.next()%(maxlen.Z*1))-(float)maxlen.Z/2
1814 s16 h = find_ground_level_clever(vmanip,
1815 v2s16(p.X, p.Z), ndef);
1816 route_y_min = h - rs/3;
1817 route_y_max = h + rs;
1820 vec += main_direction;
1825 else if(rp.X >= ar.X)
1827 if(rp.Y < route_y_min)
1829 else if(rp.Y >= route_y_max)
1830 rp.Y = route_y_max-1;
1833 else if(rp.Z >= ar.Z)
1837 for(float f=0; f<1.0; f+=1.0/vec.getLength())
1839 v3f fp = orp + vec * f;
1840 fp.X += 0.1*ps.range(-10,10);
1841 fp.Z += 0.1*ps.range(-10,10);
1842 v3s16 cp(fp.X, fp.Y, fp.Z);
1847 d0 += ps.range(-1,1);
1848 d1 += ps.range(-1,1);
1850 for(s16 z0=d0; z0<=d1; z0++)
1852 s16 si = rs/2 - MYMAX(0, abs(z0)-rs/7-1);
1853 for(s16 x0=-si-ps.range(0,1); x0<=si-1+ps.range(0,1); x0++)
1855 s16 maxabsxz = MYMAX(abs(x0), abs(z0));
1856 s16 si2 = rs/2 - MYMAX(0, maxabsxz-rs/7-1);
1857 for(s16 y0=-si2; y0<=si2; y0++)
1859 /*// Make better floors in small caves
1860 if(y0 <= -rs/2 && rs<=7)
1862 if(large_cave_is_flat){
1863 // Make large caves not so tall
1864 if(rs > 7 && abs(y0) >= rs/3)
1874 if(vmanip.m_area.contains(p) == false)
1877 u32 i = vmanip.m_area.index(p);
1881 if(full_node_min.Y < WATER_LEVEL &&
1882 full_node_max.Y > WATER_LEVEL){
1883 if(p.Y <= WATER_LEVEL)
1884 vmanip.m_data[i] = waternode;
1886 vmanip.m_data[i] = airnode;
1887 } else if(full_node_max.Y < WATER_LEVEL){
1888 if(p.Y < startp.Y - 2)
1889 vmanip.m_data[i] = lavanode;
1891 vmanip.m_data[i] = airnode;
1893 vmanip.m_data[i] = airnode;
1896 // Don't replace air or water or lava or ignore
1897 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE ||
1898 vmanip.m_data[i].getContent() == CONTENT_AIR ||
1899 vmanip.m_data[i].getContent() == c_water_source ||
1900 vmanip.m_data[i].getContent() == c_lava_source)
1903 vmanip.m_data[i] = airnode;
1906 vmanip.m_flags[i] |= VMANIP_FLAG_CAVE;
1924 TimeTaker timer1("add mud");
1927 Add mud to the central chunk
1930 for(s16 x=node_min.X; x<=node_max.X; x++)
1931 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1933 // Node position in 2d
1934 v2s16 p2d = v2s16(x,z);
1936 // Randomize mud amount
1937 s16 mud_add_amount = get_mud_add_amount(data->seed, p2d) / 2.0 + 0.5;
1939 // Find ground level
1940 s16 surface_y = find_stone_level(vmanip, p2d, ndef);
1941 // Handle area not found
1942 if(surface_y == vmanip.m_area.MinEdge.Y - 1)
1945 MapNode addnode(c_dirt);
1946 BiomeType bt = get_biome(data->seed, p2d);
1949 addnode = MapNode(c_desert_sand);
1951 if(bt == BT_DESERT && surface_y + mud_add_amount <= WATER_LEVEL+1){
1952 addnode = MapNode(c_sand);
1953 } else if(mud_add_amount <= 0){
1954 mud_add_amount = 1 - mud_add_amount;
1955 addnode = MapNode(c_gravel);
1956 } else if(bt == BT_NORMAL && get_have_beach(data->seed, p2d) &&
1957 surface_y + mud_add_amount <= WATER_LEVEL+2){
1958 addnode = MapNode(c_sand);
1961 if(bt == BT_DESERT){
1963 mud_add_amount = MYMAX(0, mud_add_amount - (surface_y - 20)/5);
1968 If topmost node is grass, change it to mud.
1969 It might be if it was flown to there from a neighboring
1970 chunk and then converted.
1973 u32 i = vmanip.m_area.index(v3s16(p2d.X, surface_y, p2d.Y));
1974 MapNode *n = &vmanip.m_data[i];
1975 if(n->getContent() == c_dirt_with_grass)
1976 *n = MapNode(c_dirt);
1984 v3s16 em = vmanip.m_area.getExtent();
1985 s16 y_start = surface_y+1;
1986 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
1987 for(s16 y=y_start; y<=node_max.Y; y++)
1989 if(mudcount >= mud_add_amount)
1992 MapNode &n = vmanip.m_data[i];
1996 vmanip.m_area.add_y(em, i, 1);
2006 Add blobs of dirt and gravel underground
2008 if(get_biome(data->seed, v2s16(node_min.X, node_min.Y)) == BT_NORMAL)
2010 PseudoRandom pr(blockseed+983);
2011 for(int i=0; i<volume_nodes/10/10/10; i++)
2013 bool only_fill_cave = (myrand_range(0,1) != 0);
2020 pr.range(node_min.X, node_max.X)-size.X/2,
2021 pr.range(node_min.Y, node_max.Y)-size.Y/2,
2022 pr.range(node_min.Z, node_max.Z)-size.Z/2
2025 if(p0.Y > -32 && pr.range(0,1) == 0)
2026 n1 = MapNode(c_dirt);
2028 n1 = MapNode(c_gravel);
2029 for(int x1=0; x1<size.X; x1++)
2030 for(int y1=0; y1<size.Y; y1++)
2031 for(int z1=0; z1<size.Z; z1++)
2033 v3s16 p = p0 + v3s16(x1,y1,z1);
2034 u32 i = vmanip.m_area.index(p);
2035 if(!vmanip.m_area.contains(i))
2037 // Cancel if not stone and not cave air
2038 if(vmanip.m_data[i].getContent() != c_stone &&
2039 !(vmanip.m_flags[i] & VMANIP_FLAG_CAVE))
2041 if(only_fill_cave && !(vmanip.m_flags[i] & VMANIP_FLAG_CAVE))
2043 vmanip.m_data[i] = n1;
2051 TimeTaker timer1("flow mud");
2054 Flow mud away from steep edges
2057 // Iterate a few times
2058 for(s16 k=0; k<3; k++)
2061 for(s16 x=mudflow_minpos; x<=mudflow_maxpos; x++)
2062 for(s16 z=mudflow_minpos; z<=mudflow_maxpos; z++)
2064 // Invert coordinates every 2nd iteration
2067 x = mudflow_maxpos - (x-mudflow_minpos);
2068 z = mudflow_maxpos - (z-mudflow_minpos);
2071 // Node position in 2d
2072 v2s16 p2d = v2s16(node_min.X, node_min.Z) + v2s16(x,z);
2074 v3s16 em = vmanip.m_area.getExtent();
2075 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
2078 while(y >= node_min.Y)
2085 for(; y>=node_min.Y; y--)
2087 n = &vmanip.m_data[i];
2088 //if(content_walkable(n->d))
2090 if(n->getContent() == c_dirt ||
2091 n->getContent() == c_dirt_with_grass ||
2092 n->getContent() == c_gravel)
2095 vmanip.m_area.add_y(em, i, -1);
2098 // Stop if out of area
2099 //if(vmanip.m_area.contains(i) == false)
2103 /*// If not mud, do nothing to it
2104 MapNode *n = &vmanip.m_data[i];
2105 if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS)
2108 if(n->getContent() == c_dirt ||
2109 n->getContent() == c_dirt_with_grass)
2111 // Make it exactly mud
2112 n->setContent(c_dirt);
2115 Don't flow it if the stuff under it is not mud
2119 vmanip.m_area.add_y(em, i2, -1);
2120 // Cancel if out of area
2121 if(vmanip.m_area.contains(i2) == false)
2123 MapNode *n2 = &vmanip.m_data[i2];
2124 if(n2->getContent() != c_dirt &&
2125 n2->getContent() != c_dirt_with_grass)
2130 /*s16 recurse_count = 0;
2134 v3s16(0,0,1), // back
2135 v3s16(1,0,0), // right
2136 v3s16(0,0,-1), // front
2137 v3s16(-1,0,0), // left
2140 // Theck that upper is air or doesn't exist.
2141 // Cancel dropping if upper keeps it in place
2143 vmanip.m_area.add_y(em, i3, 1);
2144 if(vmanip.m_area.contains(i3) == true
2145 && ndef->get(vmanip.m_data[i3]).walkable)
2152 for(u32 di=0; di<4; di++)
2154 v3s16 dirp = dirs4[di];
2157 vmanip.m_area.add_p(em, i2, dirp);
2158 // Fail if out of area
2159 if(vmanip.m_area.contains(i2) == false)
2161 // Check that side is air
2162 MapNode *n2 = &vmanip.m_data[i2];
2163 if(ndef->get(*n2).walkable)
2165 // Check that under side is air
2166 vmanip.m_area.add_y(em, i2, -1);
2167 if(vmanip.m_area.contains(i2) == false)
2169 n2 = &vmanip.m_data[i2];
2170 if(ndef->get(*n2).walkable)
2172 /*// Check that under that is air (need a drop of 2)
2173 vmanip.m_area.add_y(em, i2, -1);
2174 if(vmanip.m_area.contains(i2) == false)
2176 n2 = &vmanip.m_data[i2];
2177 if(content_walkable(n2->d))
2179 // Loop further down until not air
2180 bool dropped_to_unknown = false;
2182 vmanip.m_area.add_y(em, i2, -1);
2183 n2 = &vmanip.m_data[i2];
2184 // if out of known area
2185 if(vmanip.m_area.contains(i2) == false
2186 || n2->getContent() == CONTENT_IGNORE){
2187 dropped_to_unknown = true;
2190 }while(ndef->get(*n2).walkable == false);
2191 // Loop one up so that we're in air
2192 vmanip.m_area.add_y(em, i2, 1);
2193 n2 = &vmanip.m_data[i2];
2195 bool old_is_water = (n->getContent() == c_water_source);
2196 // Move mud to new place
2197 if(!dropped_to_unknown) {
2199 // Set old place to be air (or water)
2201 *n = MapNode(c_water_source);
2203 *n = MapNode(CONTENT_AIR);
2219 /***********************
2221 ************************/
2224 Add top and bottom side of water to transforming_liquid queue
2227 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2228 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2233 bool water_found = false;
2234 // Use fast index incrementing
2235 v3s16 em = vmanip.m_area.getExtent();
2236 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
2237 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
2239 if(y == full_node_max.Y){
2241 (vmanip.m_data[i].getContent() == c_water_source ||
2242 vmanip.m_data[i].getContent() == c_lava_source);
2244 else if(water_found == false)
2246 if(vmanip.m_data[i].getContent() == c_water_source ||
2247 vmanip.m_data[i].getContent() == c_lava_source)
2249 v3s16 p = v3s16(p2d.X, y, p2d.Y);
2250 data->transforming_liquid.push_back(p);
2256 // This can be done because water_found can only
2257 // turn to true and end up here after going through
2259 if(vmanip.m_data[i+1].getContent() != c_water_source ||
2260 vmanip.m_data[i+1].getContent() != c_lava_source)
2262 v3s16 p = v3s16(p2d.X, y+1, p2d.Y);
2263 data->transforming_liquid.push_back(p);
2264 water_found = false;
2268 vmanip.m_area.add_y(em, i, -1);
2277 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2278 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2280 // Node position in 2d
2281 v2s16 p2d = v2s16(x,z);
2284 Find the lowest surface to which enough light ends up
2287 Basically just wait until not air and not leaves.
2291 v3s16 em = vmanip.m_area.getExtent();
2292 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
2294 // Go to ground level
2295 for(y=node_max.Y; y>=full_node_min.Y; y--)
2297 MapNode &n = vmanip.m_data[i];
2298 if(ndef->get(n).param_type != CPT_LIGHT
2299 || ndef->get(n).liquid_type != LIQUID_NONE)
2301 vmanip.m_area.add_y(em, i, -1);
2303 if(y >= full_node_min.Y)
2306 surface_y = full_node_min.Y;
2309 u32 i = vmanip.m_area.index(p2d.X, surface_y, p2d.Y);
2310 MapNode *n = &vmanip.m_data[i];
2311 if(n->getContent() == c_dirt){
2312 // Well yeah, this can't be overground...
2313 if(surface_y < WATER_LEVEL - 20)
2315 n->setContent(c_dirt_with_grass);
2322 assert(central_area_size.X == central_area_size.Z);
2324 // Divide area into parts
2326 s16 sidelen = central_area_size.X / div;
2327 double area = sidelen * sidelen;
2328 for(s16 x0=0; x0<div; x0++)
2329 for(s16 z0=0; z0<div; z0++)
2331 // Center position of part of division
2333 node_min.X + sidelen/2 + sidelen*x0,
2334 node_min.Z + sidelen/2 + sidelen*z0
2336 // Minimum edge of part of division
2338 node_min.X + sidelen*x0,
2339 node_min.Z + sidelen*z0
2341 // Maximum edge of part of division
2343 node_min.X + sidelen + sidelen*x0 - 1,
2344 node_min.Z + sidelen + sidelen*z0 - 1
2347 u32 tree_count = area * tree_amount_2d(data->seed, p2d_center);
2348 // Put trees in random places on part of division
2349 for(u32 i=0; i<tree_count; i++)
2351 s16 x = myrand_range(p2d_min.X, p2d_max.X);
2352 s16 z = myrand_range(p2d_min.Y, p2d_max.Y);
2353 s16 y = find_ground_level(vmanip, v2s16(x,z), ndef);
2354 // Don't make a tree under water level
2357 // Don't make a tree so high that it doesn't fit
2358 if(y > node_max.Y - 6)
2362 Trees grow only on mud and grass
2365 u32 i = vmanip.m_area.index(v3s16(p));
2366 MapNode *n = &vmanip.m_data[i];
2367 if(n->getContent() != c_dirt
2368 && n->getContent() != c_dirt_with_grass)
2373 treegen::make_tree(vmanip, p, false, ndef);
2380 Make base ground level
2383 for(s16 x=node_min.X; x<=node_max.X; x++)
2384 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2389 // Use fast index incrementing
2390 v3s16 em = vmanip.m_area.getExtent();
2391 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
2392 for(s16 y=node_min.Y; y<=node_max.Y; y++)
2394 // Only modify places that have no content
2395 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE)
2397 // First priority: make air and water.
2398 // This avoids caves inside water.
2399 if(all_is_ground_except_caves == false
2400 && val_is_ground(noisebuf_ground.get(x,y,z),
2401 v3s16(x,y,z), data->seed) == false)
2403 if(y <= WATER_LEVEL)
2404 vmanip.m_data[i] = n_water_source;
2406 vmanip.m_data[i] = n_air;
2408 else if(noisebuf_cave.get(x,y,z) > CAVE_NOISE_THRESHOLD)
2409 vmanip.m_data[i] = n_air;
2411 vmanip.m_data[i] = n_stone;
2414 vmanip->m_area.add_y(em, i, 1);
2420 Add mud and sand and others underground (in place of stone)
2423 for(s16 x=node_min.X; x<=node_max.X; x++)
2424 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2429 // Use fast index incrementing
2430 v3s16 em = vmanip.m_area.getExtent();
2431 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
2432 for(s16 y=node_max.Y; y>=node_min.Y; y--)
2434 if(vmanip.m_data[i].getContent() == c_stone)
2436 if(noisebuf_ground_crumbleness.get(x,y,z) > 1.3)
2438 if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
2439 vmanip.m_data[i] = n_dirt;
2441 vmanip.m_data[i] = n_sand;
2443 else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.7)
2445 if(noisebuf_ground_wetness.get(x,y,z) < -0.6)
2446 vmanip.m_data[i] = n_gravel;
2448 else if(noisebuf_ground_crumbleness.get(x,y,z) <
2449 -3.0 + MYMIN(0.1 * sqrt((float)MYMAX(0, -y)), 1.5))
2451 vmanip.m_data[i] = n_lava_source;
2452 for(s16 x1=-1; x1<=1; x1++)
2453 for(s16 y1=-1; y1<=1; y1++)
2454 for(s16 z1=-1; z1<=1; z1++)
2455 data->transforming_liquid.push_back(
2456 v3s16(p2d.X+x1, y+y1, p2d.Y+z1));
2460 vmanip->m_area.add_y(em, i, -1);
2469 //if(node_min.Y < approx_groundlevel)
2470 //if(myrand() % 3 == 0)
2471 //if(myrand() % 3 == 0 && node_min.Y < approx_groundlevel)
2472 //if(myrand() % 100 == 0 && node_min.Y < approx_groundlevel)
2473 //float dungeon_rarity = g_settings.getFloat("dungeon_rarity");
2474 float dungeon_rarity = 0.02;
2475 if(((noise3d(blockpos.X,blockpos.Y,blockpos.Z,data->seed)+1.0)/2.0)
2477 && node_min.Y < approx_groundlevel)
2479 // Dungeon generator doesn't modify places which have this set
2480 vmanip->clearFlag(VMANIP_FLAG_DUNGEON_INSIDE
2481 | VMANIP_FLAG_DUNGEON_PRESERVE);
2483 // Set all air and water to be untouchable to make dungeons open
2484 // to caves and open air
2485 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2486 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2491 // Use fast index incrementing
2492 v3s16 em = vmanip.m_area.getExtent();
2493 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
2494 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
2496 if(vmanip.m_data[i].getContent() == CONTENT_AIR)
2497 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
2498 else if(vmanip.m_data[i].getContent() == c_water_source)
2499 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
2500 vmanip->m_area.add_y(em, i, -1);
2505 PseudoRandom random(blockseed+2);
2508 make_dungeon1(vmanip, random, ndef);
2510 // Convert some cobble to mossy cobble
2511 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2512 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2517 // Use fast index incrementing
2518 v3s16 em = vmanip.m_area.getExtent();
2519 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
2520 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
2522 // (noisebuf not used because it doesn't contain the
2524 double wetness = noise3d_param(
2525 get_ground_wetness_params(data->seed), x,y,z);
2526 double d = noise3d_perlin((float)x/2.5,
2527 (float)y/2.5,(float)z/2.5,
2529 if(vmanip.m_data[i].getContent() == c_cobble)
2533 vmanip.m_data[i].setContent(c_mossycobble);
2536 /*else if(vmanip.m_flags[i] & VMANIP_FLAG_DUNGEON_INSIDE)
2539 vmanip.m_data[i].setContent(c_dirt);
2541 vmanip->m_area.add_y(em, i, -1);
2551 PseudoRandom ncrandom(blockseed+9324342);
2552 if(ncrandom.range(0, 1000) == 0 && blockpos.Y <= -3)
2554 make_nc(vmanip, ncrandom, ndef);
2559 Add top and bottom side of water to transforming_liquid queue
2562 for(s16 x=node_min.X; x<=node_max.X; x++)
2563 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2568 bool water_found = false;
2569 // Use fast index incrementing
2570 v3s16 em = vmanip.m_area.getExtent();
2571 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
2572 for(s16 y=node_max.Y; y>=node_min.Y; y--)
2574 if(water_found == false)
2576 if(vmanip.m_data[i].getContent() == c_water_source)
2578 v3s16 p = v3s16(p2d.X, y, p2d.Y);
2579 data->transforming_liquid.push_back(p);
2585 // This can be done because water_found can only
2586 // turn to true and end up here after going through
2588 if(vmanip.m_data[i+1].getContent() != c_water_source)
2590 v3s16 p = v3s16(p2d.X, y+1, p2d.Y);
2591 data->transforming_liquid.push_back(p);
2592 water_found = false;
2596 vmanip->m_area.add_y(em, i, -1);
2602 If close to ground level
2605 //if(abs(approx_ground_depth) < 30)
2606 if(minimum_ground_depth < 5 && maximum_ground_depth > -5)
2612 for(s16 x=node_min.X; x<=node_max.X; x++)
2613 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2618 bool possibly_have_sand = get_have_beach(data->seed, p2d);
2619 bool have_sand = false;
2620 u32 current_depth = 0;
2621 bool air_detected = false;
2622 bool water_detected = false;
2623 bool have_clay = false;
2625 // Use fast index incrementing
2626 s16 start_y = node_max.Y+2;
2627 v3s16 em = vmanip.m_area.getExtent();
2628 u32 i = vmanip.m_area.index(v3s16(p2d.X, start_y, p2d.Y));
2629 for(s16 y=start_y; y>=node_min.Y-3; y--)
2631 if(vmanip.m_data[i].getContent() == c_water_source)
2632 water_detected = true;
2633 if(vmanip.m_data[i].getContent() == CONTENT_AIR)
2634 air_detected = true;
2636 if((vmanip.m_data[i].getContent() == c_stone
2637 || vmanip.m_data[i].getContent() == c_dirt_with_grass
2638 || vmanip.m_data[i].getContent() == c_dirt
2639 || vmanip.m_data[i].getContent() == c_sand
2640 || vmanip.m_data[i].getContent() == c_gravel
2641 ) && (air_detected || water_detected))
2643 if(current_depth == 0 && y <= WATER_LEVEL+2
2644 && possibly_have_sand)
2647 if(current_depth < 4)
2651 vmanip.m_data[i] = MapNode(c_sand);
2654 else if(current_depth==0 && !water_detected
2655 && y >= WATER_LEVEL && air_detected)
2656 vmanip.m_data[i] = MapNode(c_dirt_with_grass);
2659 vmanip.m_data[i] = MapNode(c_dirt);
2663 if(vmanip.m_data[i].getContent() == c_dirt
2664 || vmanip.m_data[i].getContent() == c_dirt_with_grass)
2665 vmanip.m_data[i] = MapNode(c_stone);
2670 if(current_depth >= 8)
2673 else if(current_depth != 0)
2676 vmanip->m_area.add_y(em, i, -1);
2682 Calculate some stuff
2685 float surface_humidity = surface_humidity_2d(data->seed, p2d_center);
2686 bool is_jungle = surface_humidity > 0.75;
2688 u32 tree_count = gen_area_nodes * tree_amount_2d(data->seed, p2d_center);
2695 PseudoRandom treerandom(blockseed);
2696 // Put trees in random places on part of division
2697 for(u32 i=0; i<tree_count; i++)
2699 s16 x = treerandom.range(node_min.X, node_max.X);
2700 s16 z = treerandom.range(node_min.Z, node_max.Z);
2701 //s16 y = find_ground_level(vmanip, v2s16(x,z));
2702 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
2703 // Don't make a tree under water level
2706 // Make sure tree fits (only trees whose starting point is
2707 // at this block are added)
2708 if(y < node_min.Y || y > node_max.Y)
2711 Find exact ground level
2715 for(; p.Y >= y-6; p.Y--)
2717 u32 i = vmanip->m_area.index(p);
2718 MapNode *n = &vmanip->m_data[i];
2719 if(n->getContent() != CONTENT_AIR && n->getContent() != c_water_source && n->getContent() != CONTENT_IGNORE)
2725 // If not found, handle next one
2730 u32 i = vmanip->m_area.index(p);
2731 MapNode *n = &vmanip->m_data[i];
2733 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass && n->getContent() != c_sand)
2736 // Papyrus grows only on mud and in water
2737 if(n->getContent() == c_dirt && y <= WATER_LEVEL)
2740 make_papyrus(vmanip, p, ndef);
2742 // Trees grow only on mud and grass, on land
2743 else if((n->getContent() == c_dirt || n->getContent() == c_dirt_with_grass) && y > WATER_LEVEL + 2)
2746 //if(surface_humidity_2d(data->seed, v2s16(x, y)) < 0.5)
2747 if(is_jungle == false)
2750 if(myrand_range(0,4) != 0)
2751 is_apple_tree = false;
2753 is_apple_tree = noise2d_perlin(
2754 0.5+(float)p.X/100, 0.5+(float)p.Z/100,
2755 data->seed+342902, 3, 0.45) > 0.2;
2756 make_tree(vmanip, p, is_apple_tree, ndef);
2759 make_jungletree(vmanip, p, ndef);
2761 // Cactii grow only on sand, on land
2762 else if(n->getContent() == c_sand && y > WATER_LEVEL + 2)
2765 make_cactus(vmanip, p, ndef);
2775 PseudoRandom grassrandom(blockseed);
2776 for(u32 i=0; i<surface_humidity*5*tree_count; i++)
2778 s16 x = grassrandom.range(node_min.X, node_max.X);
2779 s16 z = grassrandom.range(node_min.Z, node_max.Z);
2780 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
2783 if(y < node_min.Y || y > node_max.Y)
2786 Find exact ground level
2790 for(; p.Y >= y-6; p.Y--)
2792 u32 i = vmanip->m_area.index(p);
2793 MapNode *n = &vmanip->m_data[i];
2794 if(data->nodedef->get(*n).is_ground_content)
2800 // If not found, handle next one
2804 if(vmanip.m_area.contains(p) == false)
2806 if(vmanip.m_data[vmanip.m_area.index(p)].getContent() != CONTENT_AIR)
2809 if(vmanip.m_area.contains(p))
2810 vmanip.m_data[vmanip.m_area.index(p)] = c_dirt;
2812 if(vmanip.m_area.contains(p))
2813 vmanip.m_data[vmanip.m_area.index(p)] = c_junglegrass;
2819 Add some kind of random stones
2822 u32 random_stone_count = gen_area_nodes *
2823 randomstone_amount_2d(data->seed, p2d_center);
2824 // Put in random places on part of division
2825 for(u32 i=0; i<random_stone_count; i++)
2827 s16 x = myrand_range(node_min.X, node_max.X);
2828 s16 z = myrand_range(node_min.Z, node_max.Z);
2829 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
2830 // Don't add under water level
2831 /*if(y < WATER_LEVEL)
2833 // Don't add if doesn't belong to this block
2834 if(y < node_min.Y || y > node_max.Y)
2839 u32 i = vmanip->m_area.index(v3s16(p));
2840 MapNode *n = &vmanip->m_data[i];
2841 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass)
2844 // Will be placed one higher
2847 make_randomstone(vmanip, p);
2856 u32 large_stone_count = gen_area_nodes *
2857 largestone_amount_2d(data->seed, p2d_center);
2858 //u32 large_stone_count = 1;
2859 // Put in random places on part of division
2860 for(u32 i=0; i<large_stone_count; i++)
2862 s16 x = myrand_range(node_min.X, node_max.X);
2863 s16 z = myrand_range(node_min.Z, node_max.Z);
2864 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
2865 // Don't add under water level
2866 /*if(y < WATER_LEVEL)
2868 // Don't add if doesn't belong to this block
2869 if(y < node_min.Y || y > node_max.Y)
2874 u32 i = vmanip->m_area.index(v3s16(p));
2875 MapNode *n = &vmanip->m_data[i];
2876 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass)
2879 // Will be placed one lower
2882 make_largestone(vmanip, p);
2892 PseudoRandom mineralrandom(blockseed);
2897 for(s16 i=0; i<approx_ground_depth/4; i++)
2899 if(mineralrandom.next()%50 == 0)
2901 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2902 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2903 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2904 for(u16 i=0; i<27; i++)
2906 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2907 u32 vi = vmanip.m_area.index(p);
2908 if(vmanip.m_data[vi].getContent() == c_stone)
2909 if(mineralrandom.next()%8 == 0)
2910 vmanip.m_data[vi] = MapNode(c_mese);
2919 u16 a = mineralrandom.range(0,15);
2921 u16 amount = 20 * a/1000;
2922 for(s16 i=0; i<amount; i++)
2924 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2925 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2926 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2928 u8 base_content = c_stone;
2929 MapNode new_content(CONTENT_IGNORE);
2932 if(noisebuf_ground_crumbleness.get(x,y+5,z) < -0.1)
2934 new_content = MapNode(c_stone_with_coal);
2938 if(noisebuf_ground_wetness.get(x,y+5,z) > 0.0)
2939 new_content = MapNode(c_stone_with_iron);
2940 /*if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
2941 vmanip.m_data[i] = MapNode(c_dirt);
2943 vmanip.m_data[i] = MapNode(c_sand);*/
2945 /*else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.1)
2949 if(new_content.getContent() != CONTENT_IGNORE)
2951 for(u16 i=0; i<27; i++)
2953 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2954 u32 vi = vmanip.m_area.index(p);
2955 if(vmanip.m_data[vi].getContent() == base_content)
2957 if(mineralrandom.next()%sparseness == 0)
2958 vmanip.m_data[vi] = new_content;
2967 //for(s16 i=0; i < MYMAX(0, 50 - abs(node_min.Y+8 - (-30))); i++)
2968 //for(s16 i=0; i<50; i++)
2969 u16 coal_amount = 30;
2970 u16 coal_rareness = 60 / coal_amount;
2971 if(coal_rareness == 0)
2973 if(mineralrandom.next()%coal_rareness == 0)
2975 u16 a = mineralrandom.next() % 16;
2976 u16 amount = coal_amount * a*a*a / 1000;
2977 for(s16 i=0; i<amount; i++)
2979 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2980 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2981 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2982 for(u16 i=0; i<27; i++)
2984 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2985 u32 vi = vmanip.m_area.index(p);
2986 if(vmanip.m_data[vi].getContent() == c_stone)
2987 if(mineralrandom.next()%8 == 0)
2988 vmanip.m_data[vi] = MapNode(c_stone_with_coal);
2995 u16 iron_amount = 8;
2996 u16 iron_rareness = 60 / iron_amount;
2997 if(iron_rareness == 0)
2999 if(mineralrandom.next()%iron_rareness == 0)
3001 u16 a = mineralrandom.next() % 16;
3002 u16 amount = iron_amount * a*a*a / 1000;
3003 for(s16 i=0; i<amount; i++)
3005 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
3006 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
3007 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
3008 for(u16 i=0; i<27; i++)
3010 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
3011 u32 vi = vmanip.m_area.index(p);
3012 if(vmanip.m_data[vi].getContent() == c_stone)
3013 if(mineralrandom.next()%8 == 0)
3014 vmanip.m_data[vi] = MapNode(c_stone_with_iron);
3025 ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update",
3027 //VoxelArea a(node_min, node_max);
3028 VoxelArea a(node_min-v3s16(1,0,1)*MAP_BLOCKSIZE,
3029 node_max+v3s16(1,0,1)*MAP_BLOCKSIZE);
3030 /*VoxelArea a(node_min-v3s16(1,0,1)*MAP_BLOCKSIZE/2,
3031 node_max+v3s16(1,0,1)*MAP_BLOCKSIZE/2);*/
3032 enum LightBank banks[2] = {LIGHTBANK_DAY, LIGHTBANK_NIGHT};
3033 for(int i=0; i<2; i++)
3035 enum LightBank bank = banks[i];
3037 core::map<v3s16, bool> light_sources;
3038 core::map<v3s16, u8> unlight_from;
3040 voxalgo::clearLightAndCollectSources(vmanip, a, bank, ndef,
3041 light_sources, unlight_from);
3043 bool inexistent_top_provides_sunlight = !block_is_underground;
3044 voxalgo::SunlightPropagateResult res = voxalgo::propagateSunlight(
3045 vmanip, a, inexistent_top_provides_sunlight,
3046 light_sources, ndef);
3047 // TODO: Do stuff according to bottom_sunlight_valid
3049 vmanip.unspreadLight(bank, unlight_from, light_sources, ndef);
3051 vmanip.spreadLight(bank, light_sources, ndef);
3056 #endif ///BIG COMMENT
3058 BlockMakeData::BlockMakeData():
3065 BlockMakeData::~BlockMakeData()
3070 //}; // namespace mapgen