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 NoiseParams nparams_mtdefault =
38 {10.0, 12.0, v3f(350., 350., 350.), 82341, 5, 0.6}; //terrain
39 NoiseParams nparams_def_bgroup =
40 {0.5, 1/(2*1.6), v3f(350., 350., 350.), 5923, 2, 0.60}; //0 to 1
41 NoiseParams nparams_def_heat =
42 {25.0, 50.0, v3f(500., 500., 500.), 35293, 1, 0.00}; //-25 to 75
43 NoiseParams nparams_def_humidity =
44 {50, 100/(2*1.6), v3f(750., 750., 750.), 12094, 2, 0.60}; //0 to 100
47 ///////////////////////////////////////////////////////////////////////////////
50 Mapgen::Mapgen(BiomeDefManager *biomedef) {
51 Mapgen(0, 0, biomedef);
55 Mapgen::Mapgen(BiomeDefManager *biomedef, int mapgenid, u64 seed) {
56 initMapgen(biomedef, mapgenid, seed,
57 &nparams_mtdefault, &nparams_def_bgroup,
58 &nparams_def_heat, &nparams_def_humidity);
62 Mapgen::Mapgen(BiomeDefManager *biomedef, int mapgenid, u64 seed,
63 NoiseParams *np_terrain, NoiseParams *np_bgroup,
64 NoiseParams *np_heat, NoiseParams *np_humidity) {
65 initMapgen(biomedef, mapgenid, seed,
66 np_terrain, np_bgroup, np_heat, np_humidity);
69 void Mapgen::initMapgen(BiomeDefManager *biomedef, int mapgenid, u64 seed,
70 NoiseParams *np_terrain, NoiseParams *np_bgroup,
71 NoiseParams *np_heat, NoiseParams *np_humidity) {
72 this->generating = false;
74 this->seed = (int)seed;
75 this->biomedef = biomedef;
76 this->csize = v3s16(5, 5, 5) * MAP_BLOCKSIZE; /////////////////get this from config!
77 this->water_level = g_settings->getS16("default_water_level"); ////fix this!
79 this->np_terrain = np_terrain;
80 this->np_bgroup = np_bgroup;
81 this->np_heat = np_heat;
82 this->np_humidity = np_humidity;
83 noise_terrain = new Noise(np_terrain, seed, csize.X, csize.Y);
84 noise_bgroup = new Noise(np_bgroup, seed, csize.X, csize.Y);
85 noise_heat = new Noise(np_heat, seed, csize.X, csize.Y);
86 noise_humidity = new Noise(np_humidity, seed, csize.X, csize.Y);
88 this->ndef = biomedef->ndef;
89 n_air = MapNode(ndef->getId("mapgen_air"));
90 n_water = MapNode(ndef->getId("mapgen_water_source"));
91 n_lava = MapNode(ndef->getId("mapgen_lava_source"));
99 delete noise_humidity;
103 void Mapgen::makeChunk(BlockMakeData *data) {
107 //printf("generating...\n");//////////////
109 assert(data->vmanip);
110 assert(data->nodedef);
111 assert(data->blockpos_requested.X >= data->blockpos_min.X &&
112 data->blockpos_requested.Y >= data->blockpos_min.Y &&
113 data->blockpos_requested.Z >= data->blockpos_min.Z);
114 assert(data->blockpos_requested.X <= data->blockpos_max.X &&
115 data->blockpos_requested.Y <= data->blockpos_max.Y &&
116 data->blockpos_requested.Z <= data->blockpos_max.Z);
118 this->generating = true;
121 this->vmanip = data->vmanip;
122 v3s16 em = vmanip->m_area.getExtent();
123 this->ystride = em.X;
124 this->zstride = em.Y * em.X;
126 node_min = (data->blockpos_min) * MAP_BLOCKSIZE;
127 node_max = (data->blockpos_max + v3s16(1, 1, 1)) * MAP_BLOCKSIZE - v3s16(1, 1, 1);
128 v3s16 full_node_min = (data->blockpos_min - 1) * MAP_BLOCKSIZE;
129 v3s16 full_node_max = (data->blockpos_max + 2) * MAP_BLOCKSIZE - v3s16(1,1,1);
135 //printf("full_node_min.X: %d | full_node_min.Z: %d | MinEdge: %d | MaxEdge: %d\n", node_min.X, node_min.Z, vmanip->m_area.MinEdge.X, vmanip->m_area.MinEdge.Z);
136 TimeTaker timer("Generating terrain");
137 map_terrain = noise_terrain->perlinMap2D(x, z);
138 map_bgroup = noise_bgroup->perlinMap2D(x, z);
139 map_heat = noise_heat->perlinMap2D(x, z);
140 map_humidity = noise_humidity->perlinMap2D(x, z);
142 noise_bgroup->transformNoiseMap();
143 noise_heat->transformNoiseMap();
144 noise_humidity->transformNoiseMap();
147 for (z = node_min.Z; z <= node_max.Z; z++) {
148 for (x = node_min.X; x <= node_max.X; x++) {
149 Biome *biome = biomedef->getBiome(map_bgroup[i], map_heat[i], map_humidity[i]);
150 biome->genColumn(this, x, z, y1, y2);
158 //add blobs of dirt and gravel underground
160 updateLiquid(full_node_min, full_node_max);
161 updateLighting(node_min, node_max);
163 this->generating = false;
164 //printf("generated block (%d, %d) to (%d, %d)\n", node_min.X, node_min.Y, node_max.X, node_max.Y);//////////
168 void Mapgen::updateLiquid(v3s16 node_min, v3s16 node_max) {
169 bool isliquid, wasliquid;
172 for (s16 z = node_min.Z; z <= node_max.Z; z++) {
173 for (s16 x = node_min.X; x <= node_max.X; x++) {
176 v3s16 em = vmanip->m_area.getExtent();
177 i = vmanip->m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
179 for (s16 y = node_max.Y; y >= node_min.Y; y--) {
180 isliquid = ndef->get(vmanip->m_data[i]).isLiquid();
181 //there was a change between liquid and nonliquid, add to queue
182 if (isliquid != wasliquid)
183 data->transforming_liquid.push_back(v3s16(p2d.X, y, p2d.Y));
185 wasliquid = isliquid;
186 vmanip->m_area.add_y(em, i, -1);
193 void Mapgen::updateLighting(v3s16 node_min, v3s16 node_max) {
194 enum LightBank banks[2] = {LIGHTBANK_DAY, LIGHTBANK_NIGHT};
196 VoxelArea a(node_min - v3s16(1,0,1) * MAP_BLOCKSIZE,
197 node_max + v3s16(1,0,1) * MAP_BLOCKSIZE);
198 bool block_is_underground = (water_level > node_max.Y);
199 bool sunlight = !block_is_underground;
201 ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update", SPT_AVG);
202 for (int i = 0; i < 2; i++) {
203 enum LightBank bank = banks[i];
204 core::map<v3s16, bool> light_sources;
205 core::map<v3s16, u8> unlight_from;
207 voxalgo::clearLightAndCollectSources(*vmanip, a, bank, ndef,
208 light_sources, unlight_from);
209 voxalgo::propagateSunlight(*vmanip, a, sunlight, light_sources, ndef);
210 printf("light_sources: %d\t\tunlight_from: %d\n", light_sources.size(), unlight_from.size());
211 vmanip->unspreadLight(bank, unlight_from, light_sources, ndef);
212 vmanip->spreadLight(bank, light_sources, ndef);
217 /*class EmergeManager {
221 BiomeDefManager *biomedef;
223 //mapgen objects here
225 void addBlockToQueue();
228 //mapgen helper methods
229 int getGroundLevelAtPoint(u64 mseed, v2s16 p);
230 bool isBlockUnderground(u64 mseed, v3s16 blockpos);
231 u32 getBlockSeed(u64 mseed, v3s16 p);
234 EmergeManager::EmergeManager(IGameDef *gamedef) {
236 this->water_level = 0;
237 this->np_terrain = &nparams_mtdefault;
238 this->np_bgroup = &nparams_def_bgroup;
239 this->np_heat = &nparams_def_heat;
240 this->np_humidity = &nparams_def_humidity;
242 this->biomedef = new BiomeDefManager(gamedef);
246 EmergeManager::~EmergeManager() {
251 void EmergeManager::addBlockToQueue() {
256 Biome *EmergeManager::getBiomeAtPoint(v3s16 p) {
257 float bgroup = NoisePerlin2D(np_bgroup, p.X, p.Y, seed);
258 float heat = NoisePerlin2D(np_heat, p.X, p.Y, seed);
259 float humidity = NoisePerlin2D(np_humidity, p.X, p.Y, seed);
260 return biomedef->getBiome(bgroup, heat, humidity);
264 //FIXME: This assumes y == 0, that is, always in a non-hell/non-sky biome
265 int EmergeManager::getGroundLevelAtPoint(v2s16 p) {
266 float terrain = NoisePerlin2D(np_terrain, p.X, p.Y, seed);
267 Biome *biome = getBiomeAtPoint(v3s16(p.X, p.Y, 0));
268 return biome->getSurfaceHeight(terrain);
272 bool EmergeManager::isBlockUnderground(v3s16 blockpos) {
274 v2s16 p = v2s16((blockpos.X * MAP_BLOCKSIZE) + MAP_BLOCKSIZE / 2,
275 (blockpos.Y * MAP_BLOCKSIZE) + MAP_BLOCKSIZE / 2);
276 int ground_level = getGroundLevelAtPoint(p);
277 return blockpos.Y * (MAP_BLOCKSIZE + 1) <= min(water_level, ground_level);
280 //yuck, but then again, should i bother being accurate?
281 //the height of the nodes in a single block is quite variable
282 return false; //blockpos.Y * (MAP_BLOCKSIZE + 1) <= water_level;
286 u32 EmergeManager::getBlockSeed(v3s16 p) {
287 return (u32)(seed & 0xFFFFFFFF) +
294 /////////////////////////////////// legacy static functions for farmesh
297 s16 Mapgen::find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision) {
298 //just need to return something
304 bool Mapgen::get_have_beach(u64 seed, v2s16 p2d) {
305 double sandnoise = noise2d_perlin(
306 0.2+(float)p2d.X/250, 0.7+(float)p2d.Y/250,
307 seed+59420, 3, 0.50);
309 return (sandnoise > 0.15);
313 double Mapgen::tree_amount_2d(u64 seed, v2s16 p) {
314 double noise = noise2d_perlin(
315 0.5+(float)p.X/125, 0.5+(float)p.Y/125,
317 double zeroval = -0.39;
321 return 0.04 * (noise-zeroval) / (1.0-zeroval);
325 #if 0 /// BIG COMMENT
330 Some helper functions for the map generator
334 // Returns Y one under area minimum if not found
335 static s16 find_ground_level(VoxelManipulator &vmanip, v2s16 p2d,
336 INodeDefManager *ndef)
338 v3s16 em = vmanip.m_area.getExtent();
339 s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
340 s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
341 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
343 for(y=y_nodes_max; y>=y_nodes_min; y--)
345 MapNode &n = vmanip.m_data[i];
346 if(ndef->get(n).walkable)
349 vmanip.m_area.add_y(em, i, -1);
354 return y_nodes_min - 1;
358 // Returns Y one under area minimum if not found
359 static s16 find_ground_level_clever(VoxelManipulator &vmanip, v2s16 p2d,
360 INodeDefManager *ndef)
362 if(!vmanip.m_area.contains(v3s16(p2d.X, vmanip.m_area.MaxEdge.Y, p2d.Y)))
363 return vmanip.m_area.MinEdge.Y-1;
364 v3s16 em = vmanip.m_area.getExtent();
365 s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
366 s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
367 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
369 content_t c_tree = ndef->getId("mapgen_tree");
370 content_t c_leaves = ndef->getId("mapgen_leaves");
371 for(y=y_nodes_max; y>=y_nodes_min; y--)
373 MapNode &n = vmanip.m_data[i];
374 if(ndef->get(n).walkable
375 && n.getContent() != c_tree
376 && n.getContent() != c_leaves)
379 vmanip.m_area.add_y(em, i, -1);
384 return y_nodes_min - 1;
388 // Returns Y one under area minimum if not found
389 static s16 find_stone_level(VoxelManipulator &vmanip, v2s16 p2d,
390 INodeDefManager *ndef)
392 v3s16 em = vmanip.m_area.getExtent();
393 s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
394 s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
395 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
397 content_t c_stone = ndef->getId("mapgen_stone");
398 content_t c_desert_stone = ndef->getId("mapgen_desert_stone");
399 for(y=y_nodes_max; y>=y_nodes_min; y--)
401 MapNode &n = vmanip.m_data[i];
402 content_t c = n.getContent();
403 if(c != CONTENT_IGNORE && (
404 c == c_stone || c == c_desert_stone))
407 vmanip.m_area.add_y(em, i, -1);
412 return y_nodes_min - 1;
419 static void make_papyrus(VoxelManipulator &vmanip, v3s16 p0,
420 INodeDefManager *ndef)
422 MapNode papyrusnode(ndef->getId("mapgen_papyrus"));
424 s16 trunk_h = myrand_range(2, 3);
426 for(s16 ii=0; ii<trunk_h; ii++)
428 if(vmanip.m_area.contains(p1))
429 vmanip.m_data[vmanip.m_area.index(p1)] = papyrusnode;
434 static void make_cactus(VoxelManipulator &vmanip, v3s16 p0,
435 INodeDefManager *ndef)
437 MapNode cactusnode(ndef->getId("mapgen_cactus"));
441 for(s16 ii=0; ii<trunk_h; ii++)
443 if(vmanip.m_area.contains(p1))
444 vmanip.m_data[vmanip.m_area.index(p1)] = cactusnode;
452 Dungeon making routines
455 #define VMANIP_FLAG_DUNGEON_INSIDE VOXELFLAG_CHECKED1
456 #define VMANIP_FLAG_DUNGEON_PRESERVE VOXELFLAG_CHECKED2
457 #define VMANIP_FLAG_DUNGEON_UNTOUCHABLE (\
458 VMANIP_FLAG_DUNGEON_INSIDE|VMANIP_FLAG_DUNGEON_PRESERVE)
460 static void make_room1(VoxelManipulator &vmanip, v3s16 roomsize, v3s16 roomplace,
461 INodeDefManager *ndef)
464 for(s16 z=0; z<roomsize.Z; z++)
465 for(s16 y=0; y<roomsize.Y; y++)
468 v3s16 p = roomplace + v3s16(0,y,z);
469 if(vmanip.m_area.contains(p) == false)
471 u32 vi = vmanip.m_area.index(p);
472 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
474 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
477 v3s16 p = roomplace + v3s16(roomsize.X-1,y,z);
478 if(vmanip.m_area.contains(p) == false)
480 u32 vi = vmanip.m_area.index(p);
481 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
483 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
488 for(s16 x=0; x<roomsize.X; x++)
489 for(s16 y=0; y<roomsize.Y; y++)
492 v3s16 p = roomplace + v3s16(x,y,0);
493 if(vmanip.m_area.contains(p) == false)
495 u32 vi = vmanip.m_area.index(p);
496 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
498 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
501 v3s16 p = roomplace + v3s16(x,y,roomsize.Z-1);
502 if(vmanip.m_area.contains(p) == false)
504 u32 vi = vmanip.m_area.index(p);
505 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
507 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
511 // Make +-Y walls (floor and ceiling)
512 for(s16 z=0; z<roomsize.Z; z++)
513 for(s16 x=0; x<roomsize.X; x++)
516 v3s16 p = roomplace + v3s16(x,0,z);
517 if(vmanip.m_area.contains(p) == false)
519 u32 vi = vmanip.m_area.index(p);
520 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
522 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
525 v3s16 p = roomplace + v3s16(x,roomsize.Y-1,z);
526 if(vmanip.m_area.contains(p) == false)
528 u32 vi = vmanip.m_area.index(p);
529 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
531 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
536 for(s16 z=1; z<roomsize.Z-1; z++)
537 for(s16 y=1; y<roomsize.Y-1; y++)
538 for(s16 x=1; x<roomsize.X-1; x++)
540 v3s16 p = roomplace + v3s16(x,y,z);
541 if(vmanip.m_area.contains(p) == false)
543 u32 vi = vmanip.m_area.index(p);
544 vmanip.m_flags[vi] |= VMANIP_FLAG_DUNGEON_UNTOUCHABLE;
545 vmanip.m_data[vi] = MapNode(CONTENT_AIR);
549 static void make_fill(VoxelManipulator &vmanip, v3s16 place, v3s16 size,
550 u8 avoid_flags, MapNode n, u8 or_flags)
552 for(s16 z=0; z<size.Z; z++)
553 for(s16 y=0; y<size.Y; y++)
554 for(s16 x=0; x<size.X; x++)
556 v3s16 p = place + v3s16(x,y,z);
557 if(vmanip.m_area.contains(p) == false)
559 u32 vi = vmanip.m_area.index(p);
560 if(vmanip.m_flags[vi] & avoid_flags)
562 vmanip.m_flags[vi] |= or_flags;
563 vmanip.m_data[vi] = n;
567 static void make_hole1(VoxelManipulator &vmanip, v3s16 place,
568 INodeDefManager *ndef)
570 make_fill(vmanip, place, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
571 VMANIP_FLAG_DUNGEON_INSIDE);
574 static void make_door1(VoxelManipulator &vmanip, v3s16 doorplace, v3s16 doordir,
575 INodeDefManager *ndef)
577 make_hole1(vmanip, doorplace, ndef);
578 // Place torch (for testing)
579 //vmanip.m_data[vmanip.m_area.index(doorplace)] = MapNode(ndef->getId("mapgen_torch"));
582 static v3s16 rand_ortho_dir(PseudoRandom &random)
584 if(random.next()%2==0)
585 return random.next()%2 ? v3s16(-1,0,0) : v3s16(1,0,0);
587 return random.next()%2 ? v3s16(0,0,-1) : v3s16(0,0,1);
590 static v3s16 turn_xz(v3s16 olddir, int t)
610 static v3s16 random_turn(PseudoRandom &random, v3s16 olddir)
612 int turn = random.range(0,2);
621 dir = turn_xz(olddir, 0);
624 dir = turn_xz(olddir, 1);
628 static void make_corridor(VoxelManipulator &vmanip, v3s16 doorplace,
629 v3s16 doordir, v3s16 &result_place, v3s16 &result_dir,
630 PseudoRandom &random, INodeDefManager *ndef)
632 make_hole1(vmanip, doorplace, ndef);
633 v3s16 p0 = doorplace;
637 length = random.range(1,13);
639 length = random.range(1,6);
640 length = random.range(1,13);
641 u32 partlength = random.range(1,13);
644 if(random.next()%2 == 0 && partlength >= 3)
645 make_stairs = random.next()%2 ? 1 : -1;
646 for(u32 i=0; i<length; i++)
652 /*// If already empty
653 if(vmanip.getNodeNoExNoEmerge(p).getContent()
655 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
660 if(vmanip.m_area.contains(p) == true
661 && vmanip.m_area.contains(p+v3s16(0,1,0)) == true)
665 make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,5,3),
666 VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(ndef->getId("mapgen_cobble")), 0);
667 make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
668 VMANIP_FLAG_DUNGEON_INSIDE);
669 make_fill(vmanip, p-dir, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
670 VMANIP_FLAG_DUNGEON_INSIDE);
674 make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,4,3),
675 VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(ndef->getId("mapgen_cobble")), 0);
676 make_hole1(vmanip, p, ndef);
677 /*make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
678 VMANIP_FLAG_DUNGEON_INSIDE);*/
685 // Can't go here, turn away
686 dir = turn_xz(dir, random.range(0,1));
687 make_stairs = -make_stairs;
689 partlength = random.range(1,length);
694 if(partcount >= partlength)
698 dir = random_turn(random, dir);
700 partlength = random.range(1,length);
703 if(random.next()%2 == 0 && partlength >= 3)
704 make_stairs = random.next()%2 ? 1 : -1;
715 RoomWalker(VoxelManipulator &vmanip_, v3s16 pos, PseudoRandom &random,
716 INodeDefManager *ndef):
727 m_dir = rand_ortho_dir(m_random);
730 void setPos(v3s16 pos)
735 void setDir(v3s16 dir)
740 bool findPlaceForDoor(v3s16 &result_place, v3s16 &result_dir)
742 for(u32 i=0; i<100; i++)
744 v3s16 p = m_pos + m_dir;
745 v3s16 p1 = p + v3s16(0,1,0);
746 if(vmanip.m_area.contains(p) == false
747 || vmanip.m_area.contains(p1) == false
753 if(vmanip.getNodeNoExNoEmerge(p).getContent()
754 == m_ndef->getId("mapgen_cobble")
755 && vmanip.getNodeNoExNoEmerge(p1).getContent()
756 == m_ndef->getId("mapgen_cobble"))
758 // Found wall, this is a good place!
761 // Randomize next direction
766 Determine where to move next
768 // Jump one up if the actual space is there
769 if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).getContent()
770 == m_ndef->getId("mapgen_cobble")
771 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
773 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,2,0)).getContent()
776 // Jump one down if the actual space is there
777 if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
778 == m_ndef->getId("mapgen_cobble")
779 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).getContent()
781 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,-1,0)).getContent()
784 // Check if walking is now possible
785 if(vmanip.getNodeNoExNoEmerge(p).getContent()
787 || vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
790 // Cannot continue walking here
800 bool findPlaceForRoomDoor(v3s16 roomsize, v3s16 &result_doorplace,
801 v3s16 &result_doordir, v3s16 &result_roomplace)
803 for(s16 trycount=0; trycount<30; trycount++)
807 bool r = findPlaceForDoor(doorplace, doordir);
811 // X east, Z north, Y up
813 if(doordir == v3s16(1,0,0)) // X+
814 roomplace = doorplace +
815 v3s16(0,-1,m_random.range(-roomsize.Z+2,-2));
816 if(doordir == v3s16(-1,0,0)) // X-
817 roomplace = doorplace +
818 v3s16(-roomsize.X+1,-1,m_random.range(-roomsize.Z+2,-2));
819 if(doordir == v3s16(0,0,1)) // Z+
820 roomplace = doorplace +
821 v3s16(m_random.range(-roomsize.X+2,-2),-1,0);
822 if(doordir == v3s16(0,0,-1)) // Z-
823 roomplace = doorplace +
824 v3s16(m_random.range(-roomsize.X+2,-2),-1,-roomsize.Z+1);
827 if(doordir == v3s16(1,0,0)) // X+
828 roomplace = doorplace + v3s16(0,-1,-roomsize.Z/2);
829 if(doordir == v3s16(-1,0,0)) // X-
830 roomplace = doorplace + v3s16(-roomsize.X+1,-1,-roomsize.Z/2);
831 if(doordir == v3s16(0,0,1)) // Z+
832 roomplace = doorplace + v3s16(-roomsize.X/2,-1,0);
833 if(doordir == v3s16(0,0,-1)) // Z-
834 roomplace = doorplace + v3s16(-roomsize.X/2,-1,-roomsize.Z+1);
839 for(s16 z=1; z<roomsize.Z-1; z++)
840 for(s16 y=1; y<roomsize.Y-1; y++)
841 for(s16 x=1; x<roomsize.X-1; x++)
843 v3s16 p = roomplace + v3s16(x,y,z);
844 if(vmanip.m_area.contains(p) == false)
849 if(vmanip.m_flags[vmanip.m_area.index(p)]
850 & VMANIP_FLAG_DUNGEON_INSIDE)
861 result_doorplace = doorplace;
862 result_doordir = doordir;
863 result_roomplace = roomplace;
870 VoxelManipulator &vmanip;
873 PseudoRandom &m_random;
874 INodeDefManager *m_ndef;
877 static void make_dungeon1(VoxelManipulator &vmanip, PseudoRandom &random,
878 INodeDefManager *ndef)
880 v3s16 areasize = vmanip.m_area.getExtent();
885 Find place for first room
888 for(u32 i=0; i<100; i++)
890 roomsize = v3s16(random.range(4,8),random.range(4,6),random.range(4,8));
891 roomplace = vmanip.m_area.MinEdge + v3s16(
892 random.range(0,areasize.X-roomsize.X-1),
893 random.range(0,areasize.Y-roomsize.Y-1),
894 random.range(0,areasize.Z-roomsize.Z-1));
896 Check that we're not putting the room to an unknown place,
897 otherwise it might end up floating in the air
900 for(s16 z=1; z<roomsize.Z-1; z++)
901 for(s16 y=1; y<roomsize.Y-1; y++)
902 for(s16 x=1; x<roomsize.X-1; x++)
904 v3s16 p = roomplace + v3s16(x,y,z);
905 u32 vi = vmanip.m_area.index(p);
906 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_INSIDE)
911 if(vmanip.m_data[vi].getContent() == CONTENT_IGNORE)
925 Stores the center position of the last room made, so that
926 a new corridor can be started from the last room instead of
927 the new room, if chosen so.
929 v3s16 last_room_center = roomplace+v3s16(roomsize.X/2,1,roomsize.Z/2);
931 u32 room_count = random.range(2,7);
932 for(u32 i=0; i<room_count; i++)
934 // Make a room to the determined place
935 make_room1(vmanip, roomsize, roomplace, ndef);
937 v3s16 room_center = roomplace + v3s16(roomsize.X/2,1,roomsize.Z/2);
939 // Place torch at room center (for testing)
940 //vmanip.m_data[vmanip.m_area.index(room_center)] = MapNode(ndef->getId("mapgen_torch"));
943 if(i == room_count-1)
946 // Determine walker start position
948 bool start_in_last_room = (random.range(0,2)!=0);
949 //bool start_in_last_room = true;
951 v3s16 walker_start_place;
953 if(start_in_last_room)
955 walker_start_place = last_room_center;
959 walker_start_place = room_center;
960 // Store center of current room as the last one
961 last_room_center = room_center;
964 // Create walker and find a place for a door
965 RoomWalker walker(vmanip, walker_start_place, random, ndef);
968 bool r = walker.findPlaceForDoor(doorplace, doordir);
972 if(random.range(0,1)==0)
974 make_door1(vmanip, doorplace, doordir, ndef);
976 // Don't actually make a door
977 doorplace -= doordir;
979 // Make a random corridor starting from the door
981 v3s16 corridor_end_dir;
982 make_corridor(vmanip, doorplace, doordir, corridor_end,
983 corridor_end_dir, random, ndef);
985 // Find a place for a random sized room
986 roomsize = v3s16(random.range(4,8),random.range(4,6),random.range(4,8));
987 walker.setPos(corridor_end);
988 walker.setDir(corridor_end_dir);
989 r = walker.findPlaceForRoomDoor(roomsize, doorplace, doordir, roomplace);
993 if(random.range(0,1)==0)
995 make_door1(vmanip, doorplace, doordir, ndef);
997 // Don't actually make a door
998 roomplace -= doordir;
1005 static void make_nc(VoxelManipulator &vmanip, PseudoRandom &random,
1006 INodeDefManager *ndef)
1010 s32 r = random.range(0, 3);
1012 dir = v3s16( 1, 0, 0);
1016 dir = v3s16(-1, 0, 0);
1020 dir = v3s16( 0, 0, 1);
1024 dir = v3s16( 0, 0,-1);
1027 v3s16 p = vmanip.m_area.MinEdge + v3s16(
1028 16+random.range(0,15),
1029 16+random.range(0,15),
1030 16+random.range(0,15));
1031 vmanip.m_data[vmanip.m_area.index(p)] = MapNode(ndef->getId("mapgen_nyancat"), facedir_i);
1032 u32 length = random.range(3,15);
1033 for(u32 j=0; j<length; j++)
1036 vmanip.m_data[vmanip.m_area.index(p)] = MapNode(ndef->getId("mapgen_nyancat_rainbow"));
1042 Noise functions. Make sure seed is mangled differently in each one.
1047 Scaling the output of the noise function affects the overdrive of the
1048 contour function, which affects the shape of the output considerably.
1050 #define CAVE_NOISE_SCALE 12.0
1051 //#define CAVE_NOISE_SCALE 10.0
1052 //#define CAVE_NOISE_SCALE 7.5
1053 //#define CAVE_NOISE_SCALE 5.0
1054 //#define CAVE_NOISE_SCALE 1.0
1056 //#define CAVE_NOISE_THRESHOLD (2.5/CAVE_NOISE_SCALE)
1057 #define CAVE_NOISE_THRESHOLD (1.5/CAVE_NOISE_SCALE)
1059 NoiseParams get_cave_noise1_params(u64 seed)
1061 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.7,
1062 200, CAVE_NOISE_SCALE);*/
1063 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.7,
1064 100, CAVE_NOISE_SCALE);*/
1065 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.6,
1066 100, CAVE_NOISE_SCALE);*/
1067 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.3,
1068 100, CAVE_NOISE_SCALE);*/
1069 return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.5,
1070 50, CAVE_NOISE_SCALE);
1071 //return NoiseParams(NOISE_CONSTANT_ONE);
1074 NoiseParams get_cave_noise2_params(u64 seed)
1076 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.7,
1077 200, CAVE_NOISE_SCALE);*/
1078 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.7,
1079 100, CAVE_NOISE_SCALE);*/
1080 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.3,
1081 100, CAVE_NOISE_SCALE);*/
1082 return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.5,
1083 50, CAVE_NOISE_SCALE);
1084 //return NoiseParams(NOISE_CONSTANT_ONE);
1087 NoiseParams get_ground_noise1_params(u64 seed)
1089 return NoiseParams(NOISE_PERLIN, seed+983240, 4,
1093 NoiseParams get_ground_crumbleness_params(u64 seed)
1095 return NoiseParams(NOISE_PERLIN, seed+34413, 3,
1099 NoiseParams get_ground_wetness_params(u64 seed)
1101 return NoiseParams(NOISE_PERLIN, seed+32474, 4,
1105 bool is_cave(u64 seed, v3s16 p)
1107 double d1 = noise3d_param(get_cave_noise1_params(seed), p.X,p.Y,p.Z);
1108 double d2 = noise3d_param(get_cave_noise2_params(seed), p.X,p.Y,p.Z);
1109 return d1*d2 > CAVE_NOISE_THRESHOLD;
1113 Ground density noise shall be interpreted by using this.
1115 TODO: No perlin noises here, they should be outsourced
1117 NOTE: The speed of these actually isn't terrible
1119 bool val_is_ground(double ground_noise1_val, v3s16 p, u64 seed)
1121 //return ((double)p.Y < ground_noise1_val);
1123 double f = 0.55 + noise2d_perlin(
1124 0.5+(float)p.X/250, 0.5+(float)p.Z/250,
1125 seed+920381, 3, 0.45);
1130 double h = WATER_LEVEL + 10 * noise2d_perlin(
1131 0.5+(float)p.X/250, 0.5+(float)p.Z/250,
1132 seed+84174, 4, 0.5);
1135 return ((double)p.Y - h < ground_noise1_val * f);
1139 Queries whether a position is ground or not.
1141 bool is_ground(u64 seed, v3s16 p)
1143 double val1 = noise3d_param(get_ground_noise1_params(seed), p.X,p.Y,p.Z);
1144 return val_is_ground(val1, p, seed);
1148 // Amount of trees per area in nodes
1149 double tree_amount_2d(u64 seed, v2s16 p)
1151 /*double noise = noise2d_perlin(
1152 0.5+(float)p.X/250, 0.5+(float)p.Y/250,
1154 double noise = noise2d_perlin(
1155 0.5+(float)p.X/125, 0.5+(float)p.Y/125,
1157 double zeroval = -0.39;
1161 return 0.04 * (noise-zeroval) / (1.0-zeroval);
1165 double surface_humidity_2d(u64 seed, v2s16 p)
1167 double noise = noise2d_perlin(
1168 0.5+(float)p.X/500, 0.5+(float)p.Y/500,
1169 seed+72384, 4, 0.66);
1170 noise = (noise + 1.0)/2.0;
1179 Incrementally find ground level from 3d noise
1181 s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision)
1183 // Start a bit fuzzy to make averaging lower precision values
1185 s16 level = myrand_range(-precision/2, precision/2);
1186 s16 dec[] = {31000, 100, 20, 4, 1, 0};
1188 for(i = 1; dec[i] != 0 && precision <= dec[i]; i++)
1190 // First find non-ground by going upwards
1191 // Don't stop in caves.
1193 s16 max = level+dec[i-1]*2;
1194 v3s16 p(p2d.X, level, p2d.Y);
1195 for(; p.Y < max; p.Y += dec[i])
1197 if(!is_ground(seed, p))
1204 // Then find ground by going downwards from there.
1205 // Go in caves, too, when precision is 1.
1207 s16 min = level-dec[i-1]*2;
1208 v3s16 p(p2d.X, level, p2d.Y);
1209 for(; p.Y>min; p.Y-=dec[i])
1211 bool ground = is_ground(seed, p);
1212 /*if(dec[i] == 1 && is_cave(seed, p))
1223 // This is more like the actual ground level
1224 level += dec[i-1]/2;
1229 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1231 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p)
1233 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1234 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1236 a += find_ground_level_from_noise(seed,
1237 v2s16(node_min.X, node_min.Y), p);
1238 a += find_ground_level_from_noise(seed,
1239 v2s16(node_min.X, node_max.Y), p);
1240 a += find_ground_level_from_noise(seed,
1241 v2s16(node_max.X, node_max.Y), p);
1242 a += find_ground_level_from_noise(seed,
1243 v2s16(node_max.X, node_min.Y), p);
1244 a += find_ground_level_from_noise(seed,
1245 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p);
1250 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1252 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p)
1254 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1255 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1258 a = MYMAX(a, find_ground_level_from_noise(seed,
1259 v2s16(node_min.X, node_min.Y), p));
1260 a = MYMAX(a, find_ground_level_from_noise(seed,
1261 v2s16(node_min.X, node_max.Y), p));
1262 a = MYMAX(a, find_ground_level_from_noise(seed,
1263 v2s16(node_max.X, node_max.Y), p));
1264 a = MYMAX(a, find_ground_level_from_noise(seed,
1265 v2s16(node_min.X, node_min.Y), p));
1267 a = MYMAX(a, find_ground_level_from_noise(seed,
1268 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
1269 // Side middle points
1270 a = MYMAX(a, find_ground_level_from_noise(seed,
1271 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
1272 a = MYMAX(a, find_ground_level_from_noise(seed,
1273 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
1274 a = MYMAX(a, find_ground_level_from_noise(seed,
1275 v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1276 a = MYMAX(a, find_ground_level_from_noise(seed,
1277 v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1281 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1283 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p)
1285 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1286 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1289 a = MYMIN(a, find_ground_level_from_noise(seed,
1290 v2s16(node_min.X, node_min.Y), p));
1291 a = MYMIN(a, find_ground_level_from_noise(seed,
1292 v2s16(node_min.X, node_max.Y), p));
1293 a = MYMIN(a, find_ground_level_from_noise(seed,
1294 v2s16(node_max.X, node_max.Y), p));
1295 a = MYMIN(a, find_ground_level_from_noise(seed,
1296 v2s16(node_min.X, node_min.Y), p));
1298 a = MYMIN(a, find_ground_level_from_noise(seed,
1299 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
1300 // Side middle points
1301 a = MYMIN(a, find_ground_level_from_noise(seed,
1302 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
1303 a = MYMIN(a, find_ground_level_from_noise(seed,
1304 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
1305 a = MYMIN(a, find_ground_level_from_noise(seed,
1306 v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1307 a = MYMIN(a, find_ground_level_from_noise(seed,
1308 v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1313 // Required by mapgen.h
1314 bool block_is_underground(u64 seed, v3s16 blockpos)
1316 /*s16 minimum_groundlevel = (s16)get_sector_minimum_ground_level(
1317 seed, v2s16(blockpos.X, blockpos.Z));*/
1318 // Nah, this is just a heuristic, just return something
1319 s16 minimum_groundlevel = WATER_LEVEL;
1321 if(blockpos.Y*MAP_BLOCKSIZE + MAP_BLOCKSIZE <= minimum_groundlevel)
1327 #define AVERAGE_MUD_AMOUNT 4
1329 double base_rock_level_2d(u64 seed, v2s16 p)
1331 // The base ground level
1332 double base = (double)WATER_LEVEL - (double)AVERAGE_MUD_AMOUNT
1333 + 20. * noise2d_perlin(
1334 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1335 seed+82341, 5, 0.6);
1337 /*// A bit hillier one
1338 double base2 = WATER_LEVEL - 4.0 + 40. * noise2d_perlin(
1339 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1340 seed+93413, 6, 0.69);
1344 // Higher ground level
1345 double higher = (double)WATER_LEVEL + 20. + 16. * noise2d_perlin(
1346 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
1347 seed+85039, 5, 0.6);
1348 //higher = 30; // For debugging
1350 // Limit higher to at least base
1354 // Steepness factor of cliffs
1355 double b = 0.85 + 0.5 * noise2d_perlin(
1356 0.5+(float)p.X/125., 0.5+(float)p.Y/125.,
1358 b = rangelim(b, 0.0, 1000.0);
1361 b = rangelim(b, 0.5, 1000.0);
1362 // Values 1.5...100 give quite horrible looking slopes
1363 if(b > 1.5 && b < 100.0){
1369 //dstream<<"b="<<b<<std::endl;
1373 // Offset to more low
1374 double a_off = -0.20;
1375 // High/low selector
1376 /*double a = 0.5 + b * (a_off + noise2d_perlin(
1377 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
1378 seed+4213, 6, 0.7));*/
1379 double a = (double)0.5 + b * (a_off + noise2d_perlin(
1380 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1381 seed+4213, 5, 0.69));
1383 a = rangelim(a, 0.0, 1.0);
1385 //dstream<<"a="<<a<<std::endl;
1387 double h = base*(1.0-a) + higher*a;
1394 s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision)
1396 return base_rock_level_2d(seed, p2d) + AVERAGE_MUD_AMOUNT;
1399 double get_mud_add_amount(u64 seed, v2s16 p)
1401 return ((float)AVERAGE_MUD_AMOUNT + 2.0 * noise2d_perlin(
1402 0.5+(float)p.X/200, 0.5+(float)p.Y/200,
1403 seed+91013, 3, 0.55));
1406 bool get_have_beach(u64 seed, v2s16 p2d)
1408 // Determine whether to have sand here
1409 double sandnoise = noise2d_perlin(
1410 0.2+(float)p2d.X/250, 0.7+(float)p2d.Y/250,
1411 seed+59420, 3, 0.50);
1413 return (sandnoise > 0.15);
1422 BiomeType get_biome(u64 seed, v2s16 p2d)
1424 // Just do something very simple as for now
1425 double d = noise2d_perlin(
1426 0.6+(float)p2d.X/250, 0.2+(float)p2d.Y/250,
1427 seed+9130, 3, 0.50);
1430 if(d > 0.35 && (noise2d( p2d.X, p2d.Y, int(seed) ) + 1.0) > ( 0.45 - d ) * 20.0 )
1435 u32 get_blockseed(u64 seed, v3s16 p)
1437 s32 x=p.X, y=p.Y, z=p.Z;
1438 return (u32)(seed%0x100000000ULL) + z*38134234 + y*42123 + x*23;
1441 #define VMANIP_FLAG_CAVE VOXELFLAG_CHECKED1
1443 void make_block(BlockMakeData *data)
1447 //dstream<<"makeBlock: no-op"<<std::endl;
1451 assert(data->vmanip);
1452 assert(data->nodedef);
1453 assert(data->blockpos_requested.X >= data->blockpos_min.X &&
1454 data->blockpos_requested.Y >= data->blockpos_min.Y &&
1455 data->blockpos_requested.Z >= data->blockpos_min.Z);
1456 assert(data->blockpos_requested.X <= data->blockpos_max.X &&
1457 data->blockpos_requested.Y <= data->blockpos_max.Y &&
1458 data->blockpos_requested.Z <= data->blockpos_max.Z);
1460 INodeDefManager *ndef = data->nodedef;
1462 // Hack: use minimum block coordinates for old code that assumes
1464 v3s16 blockpos = data->blockpos_requested;
1466 /*dstream<<"makeBlock(): ("<<blockpos.X<<","<<blockpos.Y<<","
1467 <<blockpos.Z<<")"<<std::endl;*/
1469 v3s16 blockpos_min = data->blockpos_min;
1470 v3s16 blockpos_max = data->blockpos_max;
1471 v3s16 blockpos_full_min = blockpos_min - v3s16(1,1,1);
1472 v3s16 blockpos_full_max = blockpos_max + v3s16(1,1,1);
1474 ManualMapVoxelManipulator &vmanip = *(data->vmanip);
1475 // Area of central chunk
1476 v3s16 node_min = blockpos_min*MAP_BLOCKSIZE;
1477 v3s16 node_max = (blockpos_max+v3s16(1,1,1))*MAP_BLOCKSIZE-v3s16(1,1,1);
1478 // Full allocated area
1479 v3s16 full_node_min = (blockpos_min-1)*MAP_BLOCKSIZE;
1480 v3s16 full_node_max = (blockpos_max+2)*MAP_BLOCKSIZE-v3s16(1,1,1);
1482 v3s16 central_area_size = node_max - node_min + v3s16(1,1,1);
1484 const s16 max_spread_amount = MAP_BLOCKSIZE;
1486 int volume_blocks = (blockpos_max.X - blockpos_min.X + 1)
1487 * (blockpos_max.Y - blockpos_min.Y + 1)
1488 * (blockpos_max.Z - blockpos_max.Z + 1);
1490 int volume_nodes = volume_blocks *
1491 MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
1493 // Generated surface area
1494 //double gen_area_nodes = MAP_BLOCKSIZE*MAP_BLOCKSIZE * rel_volume;
1496 // Horribly wrong heuristic, but better than nothing
1497 bool block_is_underground = (WATER_LEVEL > node_max.Y);
1500 Create a block-specific seed
1502 u32 blockseed = get_blockseed(data->seed, full_node_min);
1505 Cache some ground type values for speed
1508 // Creates variables c_name=id and n_name=node
1509 #define CONTENT_VARIABLE(ndef, name)\
1510 content_t c_##name = ndef->getId("mapgen_" #name);\
1511 MapNode n_##name(c_##name);
1512 // Default to something else if was CONTENT_IGNORE
1513 #define CONTENT_VARIABLE_FALLBACK(name, dname)\
1514 if(c_##name == CONTENT_IGNORE){\
1515 c_##name = c_##dname;\
1516 n_##name = n_##dname;\
1519 CONTENT_VARIABLE(ndef, stone);
1520 CONTENT_VARIABLE(ndef, air);
1521 CONTENT_VARIABLE(ndef, water_source);
1522 CONTENT_VARIABLE(ndef, dirt);
1523 CONTENT_VARIABLE(ndef, sand);
1524 CONTENT_VARIABLE(ndef, gravel);
1525 CONTENT_VARIABLE(ndef, clay);
1526 CONTENT_VARIABLE(ndef, lava_source);
1527 CONTENT_VARIABLE(ndef, cobble);
1528 CONTENT_VARIABLE(ndef, mossycobble);
1529 CONTENT_VARIABLE(ndef, dirt_with_grass);
1530 CONTENT_VARIABLE(ndef, junglegrass);
1531 CONTENT_VARIABLE(ndef, stone_with_coal);
1532 CONTENT_VARIABLE(ndef, stone_with_iron);
1533 CONTENT_VARIABLE(ndef, mese);
1534 CONTENT_VARIABLE(ndef, desert_sand);
1535 CONTENT_VARIABLE_FALLBACK(desert_sand, sand);
1536 CONTENT_VARIABLE(ndef, desert_stone);
1537 CONTENT_VARIABLE_FALLBACK(desert_stone, stone);
1539 // Maximum height of the stone surface and obstacles.
1540 // This is used to guide the cave generation
1541 s16 stone_surface_max_y = 0;
1544 Generate general ground level to full area
1548 TimeTaker timer1("Generating ground level");
1550 for(s16 x=node_min.X; x<=node_max.X; x++)
1551 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1554 v2s16 p2d = v2s16(x,z);
1557 Skip of already generated
1560 v3s16 p(p2d.X, node_min.Y, p2d.Y);
1561 if(vmanip.m_data[vmanip.m_area.index(p)].d != CONTENT_AIR)
1565 // Ground height at this point
1566 float surface_y_f = 0.0;
1568 // Use perlin noise for ground height
1569 surface_y_f = base_rock_level_2d(data->seed, p2d);
1571 /*// Experimental stuff
1573 float a = highlands_level_2d(data->seed, p2d);
1578 // Convert to integer
1579 s16 surface_y = (s16)surface_y_f;
1582 if(surface_y > stone_surface_max_y)
1583 stone_surface_max_y = surface_y;
1585 BiomeType bt = get_biome(data->seed, p2d);
1587 Fill ground with stone
1590 // Use fast index incrementing
1591 v3s16 em = vmanip.m_area.getExtent();
1592 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
1593 for(s16 y=node_min.Y; y<=node_max.Y; y++)
1595 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE){
1597 if(y > WATER_LEVEL && bt == BT_DESERT)
1598 vmanip.m_data[i] = n_desert_stone;
1600 vmanip.m_data[i] = n_stone;
1601 } else if(y <= WATER_LEVEL){
1602 vmanip.m_data[i] = MapNode(c_water_source);
1604 vmanip.m_data[i] = MapNode(c_air);
1607 vmanip.m_area.add_y(em, i, 1);
1615 // Limit dirt flow area by 1 because mud is flown into neighbors.
1616 assert(central_area_size.X == central_area_size.Z);
1617 s16 mudflow_minpos = 0-max_spread_amount+1;
1618 s16 mudflow_maxpos = central_area_size.X+max_spread_amount-2;
1621 Loop this part, it will make stuff look older and newer nicely
1624 const u32 age_loops = 2;
1625 for(u32 i_age=0; i_age<age_loops; i_age++)
1627 /******************************
1628 BEGINNING OF AGING LOOP
1629 ******************************/
1634 //TimeTaker timer1("caves");
1637 Make caves (this code is relatively horrible)
1639 double cave_amount = 6.0 + 6.0 * noise2d_perlin(
1640 0.5+(double)node_min.X/250, 0.5+(double)node_min.Y/250,
1641 data->seed+34329, 3, 0.50);
1642 cave_amount = MYMAX(0.0, cave_amount);
1643 u32 caves_count = cave_amount * volume_nodes / 50000;
1644 u32 bruises_count = 1;
1645 PseudoRandom ps(blockseed+21343);
1646 PseudoRandom ps2(blockseed+1032);
1647 if(ps.range(1, 6) == 1)
1648 bruises_count = ps.range(0, ps.range(0, 2));
1649 if(get_biome(data->seed, v2s16(node_min.X, node_min.Y)) == BT_DESERT){
1653 for(u32 jj=0; jj<caves_count+bruises_count; jj++)
1655 bool large_cave = (jj >= caves_count);
1656 s16 min_tunnel_diameter = 2;
1657 s16 max_tunnel_diameter = ps.range(2,6);
1658 int dswitchint = ps.range(1,14);
1659 u16 tunnel_routepoints = 0;
1660 int part_max_length_rs = 0;
1662 part_max_length_rs = ps.range(2,4);
1663 tunnel_routepoints = ps.range(5, ps.range(15,30));
1664 min_tunnel_diameter = 5;
1665 max_tunnel_diameter = ps.range(7, ps.range(8,24));
1667 part_max_length_rs = ps.range(2,9);
1668 tunnel_routepoints = ps.range(10, ps.range(15,30));
1670 bool large_cave_is_flat = (ps.range(0,1) == 0);
1672 v3f main_direction(0,0,0);
1674 // Allowed route area size in nodes
1675 v3s16 ar = central_area_size;
1677 // Area starting point in nodes
1678 v3s16 of = node_min;
1681 //(this should be more than the maximum radius of the tunnel)
1682 //s16 insure = 5; // Didn't work with max_d = 20
1684 s16 more = max_spread_amount - max_tunnel_diameter/2 - insure;
1685 ar += v3s16(1,0,1) * more * 2;
1686 of -= v3s16(1,0,1) * more;
1688 s16 route_y_min = 0;
1689 // Allow half a diameter + 7 over stone surface
1690 s16 route_y_max = -of.Y + stone_surface_max_y + max_tunnel_diameter/2 + 7;
1692 /*// If caves, don't go through surface too often
1693 if(large_cave == false)
1694 route_y_max -= ps.range(0, max_tunnel_diameter*2);*/
1696 // Limit maximum to area
1697 route_y_max = rangelim(route_y_max, 0, ar.Y-1);
1701 /*// Minimum is at y=0
1702 route_y_min = -of.Y - 0;*/
1703 // Minimum is at y=max_tunnel_diameter/4
1704 //route_y_min = -of.Y + max_tunnel_diameter/4;
1705 //s16 min = -of.Y + max_tunnel_diameter/4;
1706 //s16 min = -of.Y + 0;
1708 if(node_min.Y < WATER_LEVEL && node_max.Y > WATER_LEVEL)
1710 min = WATER_LEVEL - max_tunnel_diameter/3 - of.Y;
1711 route_y_max = WATER_LEVEL + max_tunnel_diameter/3 - of.Y;
1713 route_y_min = ps.range(min, min + max_tunnel_diameter);
1714 route_y_min = rangelim(route_y_min, 0, route_y_max);
1717 /*dstream<<"route_y_min = "<<route_y_min
1718 <<", route_y_max = "<<route_y_max<<std::endl;*/
1720 s16 route_start_y_min = route_y_min;
1721 s16 route_start_y_max = route_y_max;
1723 // Start every 4th cave from surface when applicable
1724 /*bool coming_from_surface = false;
1725 if(node_min.Y <= 0 && node_max.Y >= 0){
1726 coming_from_surface = (jj % 4 == 0 && large_cave == false);
1727 if(coming_from_surface)
1728 route_start_y_min = -of.Y + stone_surface_max_y + 10;
1731 route_start_y_min = rangelim(route_start_y_min, 0, ar.Y-1);
1732 route_start_y_max = rangelim(route_start_y_max, route_start_y_min, ar.Y-1);
1734 // Randomize starting position
1736 (float)(ps.next()%ar.X)+0.5,
1737 (float)(ps.range(route_start_y_min, route_start_y_max))+0.5,
1738 (float)(ps.next()%ar.Z)+0.5
1741 v3s16 startp(orp.X, orp.Y, orp.Z);
1744 MapNode airnode(CONTENT_AIR);
1745 MapNode waternode(c_water_source);
1746 MapNode lavanode(c_lava_source);
1749 Generate some tunnel starting from orp
1752 for(u16 j=0; j<tunnel_routepoints; j++)
1754 if(j%dswitchint==0 && large_cave == false)
1756 main_direction = v3f(
1757 ((float)(ps.next()%20)-(float)10)/10,
1758 ((float)(ps.next()%20)-(float)10)/30,
1759 ((float)(ps.next()%20)-(float)10)/10
1761 main_direction *= (float)ps.range(0, 10)/10;
1765 s16 min_d = min_tunnel_diameter;
1766 s16 max_d = max_tunnel_diameter;
1767 s16 rs = ps.range(min_d, max_d);
1769 // Every second section is rough
1770 bool randomize_xz = (ps2.range(1,2) == 1);
1776 rs*part_max_length_rs,
1777 rs*part_max_length_rs/2,
1778 rs*part_max_length_rs
1784 rs*part_max_length_rs,
1785 ps.range(1, rs*part_max_length_rs),
1786 rs*part_max_length_rs
1793 (float)(ps.next()%(maxlen.X*1))-(float)maxlen.X/2,
1794 (float)(ps.next()%(maxlen.Y*1))-(float)maxlen.Y/2,
1795 (float)(ps.next()%(maxlen.Z*1))-(float)maxlen.Z/2
1798 // Jump downward sometimes
1799 if(!large_cave && ps.range(0,12) == 0)
1802 (float)(ps.next()%(maxlen.X*1))-(float)maxlen.X/2,
1803 (float)(ps.next()%(maxlen.Y*2))-(float)maxlen.Y*2/2,
1804 (float)(ps.next()%(maxlen.Z*1))-(float)maxlen.Z/2
1810 s16 h = find_ground_level_clever(vmanip,
1811 v2s16(p.X, p.Z), ndef);
1812 route_y_min = h - rs/3;
1813 route_y_max = h + rs;
1816 vec += main_direction;
1821 else if(rp.X >= ar.X)
1823 if(rp.Y < route_y_min)
1825 else if(rp.Y >= route_y_max)
1826 rp.Y = route_y_max-1;
1829 else if(rp.Z >= ar.Z)
1833 for(float f=0; f<1.0; f+=1.0/vec.getLength())
1835 v3f fp = orp + vec * f;
1836 fp.X += 0.1*ps.range(-10,10);
1837 fp.Z += 0.1*ps.range(-10,10);
1838 v3s16 cp(fp.X, fp.Y, fp.Z);
1843 d0 += ps.range(-1,1);
1844 d1 += ps.range(-1,1);
1846 for(s16 z0=d0; z0<=d1; z0++)
1848 s16 si = rs/2 - MYMAX(0, abs(z0)-rs/7-1);
1849 for(s16 x0=-si-ps.range(0,1); x0<=si-1+ps.range(0,1); x0++)
1851 s16 maxabsxz = MYMAX(abs(x0), abs(z0));
1852 s16 si2 = rs/2 - MYMAX(0, maxabsxz-rs/7-1);
1853 for(s16 y0=-si2; y0<=si2; y0++)
1855 /*// Make better floors in small caves
1856 if(y0 <= -rs/2 && rs<=7)
1858 if(large_cave_is_flat){
1859 // Make large caves not so tall
1860 if(rs > 7 && abs(y0) >= rs/3)
1870 if(vmanip.m_area.contains(p) == false)
1873 u32 i = vmanip.m_area.index(p);
1877 if(full_node_min.Y < WATER_LEVEL &&
1878 full_node_max.Y > WATER_LEVEL){
1879 if(p.Y <= WATER_LEVEL)
1880 vmanip.m_data[i] = waternode;
1882 vmanip.m_data[i] = airnode;
1883 } else if(full_node_max.Y < WATER_LEVEL){
1884 if(p.Y < startp.Y - 2)
1885 vmanip.m_data[i] = lavanode;
1887 vmanip.m_data[i] = airnode;
1889 vmanip.m_data[i] = airnode;
1892 // Don't replace air or water or lava or ignore
1893 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE ||
1894 vmanip.m_data[i].getContent() == CONTENT_AIR ||
1895 vmanip.m_data[i].getContent() == c_water_source ||
1896 vmanip.m_data[i].getContent() == c_lava_source)
1899 vmanip.m_data[i] = airnode;
1902 vmanip.m_flags[i] |= VMANIP_FLAG_CAVE;
1920 TimeTaker timer1("add mud");
1923 Add mud to the central chunk
1926 for(s16 x=node_min.X; x<=node_max.X; x++)
1927 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1929 // Node position in 2d
1930 v2s16 p2d = v2s16(x,z);
1932 // Randomize mud amount
1933 s16 mud_add_amount = get_mud_add_amount(data->seed, p2d) / 2.0 + 0.5;
1935 // Find ground level
1936 s16 surface_y = find_stone_level(vmanip, p2d, ndef);
1937 // Handle area not found
1938 if(surface_y == vmanip.m_area.MinEdge.Y - 1)
1941 MapNode addnode(c_dirt);
1942 BiomeType bt = get_biome(data->seed, p2d);
1945 addnode = MapNode(c_desert_sand);
1947 if(bt == BT_DESERT && surface_y + mud_add_amount <= WATER_LEVEL+1){
1948 addnode = MapNode(c_sand);
1949 } else if(mud_add_amount <= 0){
1950 mud_add_amount = 1 - mud_add_amount;
1951 addnode = MapNode(c_gravel);
1952 } else if(bt == BT_NORMAL && get_have_beach(data->seed, p2d) &&
1953 surface_y + mud_add_amount <= WATER_LEVEL+2){
1954 addnode = MapNode(c_sand);
1957 if(bt == BT_DESERT){
1959 mud_add_amount = MYMAX(0, mud_add_amount - (surface_y - 20)/5);
1964 If topmost node is grass, change it to mud.
1965 It might be if it was flown to there from a neighboring
1966 chunk and then converted.
1969 u32 i = vmanip.m_area.index(v3s16(p2d.X, surface_y, p2d.Y));
1970 MapNode *n = &vmanip.m_data[i];
1971 if(n->getContent() == c_dirt_with_grass)
1972 *n = MapNode(c_dirt);
1980 v3s16 em = vmanip.m_area.getExtent();
1981 s16 y_start = surface_y+1;
1982 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
1983 for(s16 y=y_start; y<=node_max.Y; y++)
1985 if(mudcount >= mud_add_amount)
1988 MapNode &n = vmanip.m_data[i];
1992 vmanip.m_area.add_y(em, i, 1);
2002 Add blobs of dirt and gravel underground
2004 if(get_biome(data->seed, v2s16(node_min.X, node_min.Y)) == BT_NORMAL)
2006 PseudoRandom pr(blockseed+983);
2007 for(int i=0; i<volume_nodes/10/10/10; i++)
2009 bool only_fill_cave = (myrand_range(0,1) != 0);
2016 pr.range(node_min.X, node_max.X)-size.X/2,
2017 pr.range(node_min.Y, node_max.Y)-size.Y/2,
2018 pr.range(node_min.Z, node_max.Z)-size.Z/2
2021 if(p0.Y > -32 && pr.range(0,1) == 0)
2022 n1 = MapNode(c_dirt);
2024 n1 = MapNode(c_gravel);
2025 for(int x1=0; x1<size.X; x1++)
2026 for(int y1=0; y1<size.Y; y1++)
2027 for(int z1=0; z1<size.Z; z1++)
2029 v3s16 p = p0 + v3s16(x1,y1,z1);
2030 u32 i = vmanip.m_area.index(p);
2031 if(!vmanip.m_area.contains(i))
2033 // Cancel if not stone and not cave air
2034 if(vmanip.m_data[i].getContent() != c_stone &&
2035 !(vmanip.m_flags[i] & VMANIP_FLAG_CAVE))
2037 if(only_fill_cave && !(vmanip.m_flags[i] & VMANIP_FLAG_CAVE))
2039 vmanip.m_data[i] = n1;
2047 TimeTaker timer1("flow mud");
2050 Flow mud away from steep edges
2053 // Iterate a few times
2054 for(s16 k=0; k<3; k++)
2057 for(s16 x=mudflow_minpos; x<=mudflow_maxpos; x++)
2058 for(s16 z=mudflow_minpos; z<=mudflow_maxpos; z++)
2060 // Invert coordinates every 2nd iteration
2063 x = mudflow_maxpos - (x-mudflow_minpos);
2064 z = mudflow_maxpos - (z-mudflow_minpos);
2067 // Node position in 2d
2068 v2s16 p2d = v2s16(node_min.X, node_min.Z) + v2s16(x,z);
2070 v3s16 em = vmanip.m_area.getExtent();
2071 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
2074 while(y >= node_min.Y)
2081 for(; y>=node_min.Y; y--)
2083 n = &vmanip.m_data[i];
2084 //if(content_walkable(n->d))
2086 if(n->getContent() == c_dirt ||
2087 n->getContent() == c_dirt_with_grass ||
2088 n->getContent() == c_gravel)
2091 vmanip.m_area.add_y(em, i, -1);
2094 // Stop if out of area
2095 //if(vmanip.m_area.contains(i) == false)
2099 /*// If not mud, do nothing to it
2100 MapNode *n = &vmanip.m_data[i];
2101 if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS)
2104 if(n->getContent() == c_dirt ||
2105 n->getContent() == c_dirt_with_grass)
2107 // Make it exactly mud
2108 n->setContent(c_dirt);
2111 Don't flow it if the stuff under it is not mud
2115 vmanip.m_area.add_y(em, i2, -1);
2116 // Cancel if out of area
2117 if(vmanip.m_area.contains(i2) == false)
2119 MapNode *n2 = &vmanip.m_data[i2];
2120 if(n2->getContent() != c_dirt &&
2121 n2->getContent() != c_dirt_with_grass)
2126 /*s16 recurse_count = 0;
2130 v3s16(0,0,1), // back
2131 v3s16(1,0,0), // right
2132 v3s16(0,0,-1), // front
2133 v3s16(-1,0,0), // left
2136 // Theck that upper is air or doesn't exist.
2137 // Cancel dropping if upper keeps it in place
2139 vmanip.m_area.add_y(em, i3, 1);
2140 if(vmanip.m_area.contains(i3) == true
2141 && ndef->get(vmanip.m_data[i3]).walkable)
2148 for(u32 di=0; di<4; di++)
2150 v3s16 dirp = dirs4[di];
2153 vmanip.m_area.add_p(em, i2, dirp);
2154 // Fail if out of area
2155 if(vmanip.m_area.contains(i2) == false)
2157 // Check that side is air
2158 MapNode *n2 = &vmanip.m_data[i2];
2159 if(ndef->get(*n2).walkable)
2161 // Check that under side is air
2162 vmanip.m_area.add_y(em, i2, -1);
2163 if(vmanip.m_area.contains(i2) == false)
2165 n2 = &vmanip.m_data[i2];
2166 if(ndef->get(*n2).walkable)
2168 /*// Check that under that is air (need a drop of 2)
2169 vmanip.m_area.add_y(em, i2, -1);
2170 if(vmanip.m_area.contains(i2) == false)
2172 n2 = &vmanip.m_data[i2];
2173 if(content_walkable(n2->d))
2175 // Loop further down until not air
2176 bool dropped_to_unknown = false;
2178 vmanip.m_area.add_y(em, i2, -1);
2179 n2 = &vmanip.m_data[i2];
2180 // if out of known area
2181 if(vmanip.m_area.contains(i2) == false
2182 || n2->getContent() == CONTENT_IGNORE){
2183 dropped_to_unknown = true;
2186 }while(ndef->get(*n2).walkable == false);
2187 // Loop one up so that we're in air
2188 vmanip.m_area.add_y(em, i2, 1);
2189 n2 = &vmanip.m_data[i2];
2191 bool old_is_water = (n->getContent() == c_water_source);
2192 // Move mud to new place
2193 if(!dropped_to_unknown) {
2195 // Set old place to be air (or water)
2197 *n = MapNode(c_water_source);
2199 *n = MapNode(CONTENT_AIR);
2215 /***********************
2217 ************************/
2220 Add top and bottom side of water to transforming_liquid queue
2223 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2224 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2229 bool water_found = false;
2230 // Use fast index incrementing
2231 v3s16 em = vmanip.m_area.getExtent();
2232 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
2233 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
2235 if(y == full_node_max.Y){
2237 (vmanip.m_data[i].getContent() == c_water_source ||
2238 vmanip.m_data[i].getContent() == c_lava_source);
2240 else if(water_found == false)
2242 if(vmanip.m_data[i].getContent() == c_water_source ||
2243 vmanip.m_data[i].getContent() == c_lava_source)
2245 v3s16 p = v3s16(p2d.X, y, p2d.Y);
2246 data->transforming_liquid.push_back(p);
2252 // This can be done because water_found can only
2253 // turn to true and end up here after going through
2255 if(vmanip.m_data[i+1].getContent() != c_water_source ||
2256 vmanip.m_data[i+1].getContent() != c_lava_source)
2258 v3s16 p = v3s16(p2d.X, y+1, p2d.Y);
2259 data->transforming_liquid.push_back(p);
2260 water_found = false;
2264 vmanip.m_area.add_y(em, i, -1);
2273 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2274 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2276 // Node position in 2d
2277 v2s16 p2d = v2s16(x,z);
2280 Find the lowest surface to which enough light ends up
2283 Basically just wait until not air and not leaves.
2287 v3s16 em = vmanip.m_area.getExtent();
2288 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
2290 // Go to ground level
2291 for(y=node_max.Y; y>=full_node_min.Y; y--)
2293 MapNode &n = vmanip.m_data[i];
2294 if(ndef->get(n).param_type != CPT_LIGHT
2295 || ndef->get(n).liquid_type != LIQUID_NONE)
2297 vmanip.m_area.add_y(em, i, -1);
2299 if(y >= full_node_min.Y)
2302 surface_y = full_node_min.Y;
2305 u32 i = vmanip.m_area.index(p2d.X, surface_y, p2d.Y);
2306 MapNode *n = &vmanip.m_data[i];
2307 if(n->getContent() == c_dirt){
2308 // Well yeah, this can't be overground...
2309 if(surface_y < WATER_LEVEL - 20)
2311 n->setContent(c_dirt_with_grass);
2318 assert(central_area_size.X == central_area_size.Z);
2320 // Divide area into parts
2322 s16 sidelen = central_area_size.X / div;
2323 double area = sidelen * sidelen;
2324 for(s16 x0=0; x0<div; x0++)
2325 for(s16 z0=0; z0<div; z0++)
2327 // Center position of part of division
2329 node_min.X + sidelen/2 + sidelen*x0,
2330 node_min.Z + sidelen/2 + sidelen*z0
2332 // Minimum edge of part of division
2334 node_min.X + sidelen*x0,
2335 node_min.Z + sidelen*z0
2337 // Maximum edge of part of division
2339 node_min.X + sidelen + sidelen*x0 - 1,
2340 node_min.Z + sidelen + sidelen*z0 - 1
2343 u32 tree_count = area * tree_amount_2d(data->seed, p2d_center);
2344 // Put trees in random places on part of division
2345 for(u32 i=0; i<tree_count; i++)
2347 s16 x = myrand_range(p2d_min.X, p2d_max.X);
2348 s16 z = myrand_range(p2d_min.Y, p2d_max.Y);
2349 s16 y = find_ground_level(vmanip, v2s16(x,z), ndef);
2350 // Don't make a tree under water level
2353 // Don't make a tree so high that it doesn't fit
2354 if(y > node_max.Y - 6)
2358 Trees grow only on mud and grass
2361 u32 i = vmanip.m_area.index(v3s16(p));
2362 MapNode *n = &vmanip.m_data[i];
2363 if(n->getContent() != c_dirt
2364 && n->getContent() != c_dirt_with_grass)
2369 treegen::make_tree(vmanip, p, false, ndef);
2376 Make base ground level
2379 for(s16 x=node_min.X; x<=node_max.X; x++)
2380 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2385 // Use fast index incrementing
2386 v3s16 em = vmanip.m_area.getExtent();
2387 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
2388 for(s16 y=node_min.Y; y<=node_max.Y; y++)
2390 // Only modify places that have no content
2391 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE)
2393 // First priority: make air and water.
2394 // This avoids caves inside water.
2395 if(all_is_ground_except_caves == false
2396 && val_is_ground(noisebuf_ground.get(x,y,z),
2397 v3s16(x,y,z), data->seed) == false)
2399 if(y <= WATER_LEVEL)
2400 vmanip.m_data[i] = n_water_source;
2402 vmanip.m_data[i] = n_air;
2404 else if(noisebuf_cave.get(x,y,z) > CAVE_NOISE_THRESHOLD)
2405 vmanip.m_data[i] = n_air;
2407 vmanip.m_data[i] = n_stone;
2410 vmanip->m_area.add_y(em, i, 1);
2416 Add mud and sand and others underground (in place of stone)
2419 for(s16 x=node_min.X; x<=node_max.X; x++)
2420 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2425 // Use fast index incrementing
2426 v3s16 em = vmanip.m_area.getExtent();
2427 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
2428 for(s16 y=node_max.Y; y>=node_min.Y; y--)
2430 if(vmanip.m_data[i].getContent() == c_stone)
2432 if(noisebuf_ground_crumbleness.get(x,y,z) > 1.3)
2434 if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
2435 vmanip.m_data[i] = n_dirt;
2437 vmanip.m_data[i] = n_sand;
2439 else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.7)
2441 if(noisebuf_ground_wetness.get(x,y,z) < -0.6)
2442 vmanip.m_data[i] = n_gravel;
2444 else if(noisebuf_ground_crumbleness.get(x,y,z) <
2445 -3.0 + MYMIN(0.1 * sqrt((float)MYMAX(0, -y)), 1.5))
2447 vmanip.m_data[i] = n_lava_source;
2448 for(s16 x1=-1; x1<=1; x1++)
2449 for(s16 y1=-1; y1<=1; y1++)
2450 for(s16 z1=-1; z1<=1; z1++)
2451 data->transforming_liquid.push_back(
2452 v3s16(p2d.X+x1, y+y1, p2d.Y+z1));
2456 vmanip->m_area.add_y(em, i, -1);
2465 //if(node_min.Y < approx_groundlevel)
2466 //if(myrand() % 3 == 0)
2467 //if(myrand() % 3 == 0 && node_min.Y < approx_groundlevel)
2468 //if(myrand() % 100 == 0 && node_min.Y < approx_groundlevel)
2469 //float dungeon_rarity = g_settings.getFloat("dungeon_rarity");
2470 float dungeon_rarity = 0.02;
2471 if(((noise3d(blockpos.X,blockpos.Y,blockpos.Z,data->seed)+1.0)/2.0)
2473 && node_min.Y < approx_groundlevel)
2475 // Dungeon generator doesn't modify places which have this set
2476 vmanip->clearFlag(VMANIP_FLAG_DUNGEON_INSIDE
2477 | VMANIP_FLAG_DUNGEON_PRESERVE);
2479 // Set all air and water to be untouchable to make dungeons open
2480 // to caves and open air
2481 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2482 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2487 // Use fast index incrementing
2488 v3s16 em = vmanip.m_area.getExtent();
2489 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
2490 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
2492 if(vmanip.m_data[i].getContent() == CONTENT_AIR)
2493 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
2494 else if(vmanip.m_data[i].getContent() == c_water_source)
2495 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
2496 vmanip->m_area.add_y(em, i, -1);
2501 PseudoRandom random(blockseed+2);
2504 make_dungeon1(vmanip, random, ndef);
2506 // Convert some cobble to mossy cobble
2507 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2508 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2513 // Use fast index incrementing
2514 v3s16 em = vmanip.m_area.getExtent();
2515 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
2516 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
2518 // (noisebuf not used because it doesn't contain the
2520 double wetness = noise3d_param(
2521 get_ground_wetness_params(data->seed), x,y,z);
2522 double d = noise3d_perlin((float)x/2.5,
2523 (float)y/2.5,(float)z/2.5,
2525 if(vmanip.m_data[i].getContent() == c_cobble)
2529 vmanip.m_data[i].setContent(c_mossycobble);
2532 /*else if(vmanip.m_flags[i] & VMANIP_FLAG_DUNGEON_INSIDE)
2535 vmanip.m_data[i].setContent(c_dirt);
2537 vmanip->m_area.add_y(em, i, -1);
2547 PseudoRandom ncrandom(blockseed+9324342);
2548 if(ncrandom.range(0, 1000) == 0 && blockpos.Y <= -3)
2550 make_nc(vmanip, ncrandom, ndef);
2555 Add top and bottom side of water to transforming_liquid queue
2558 for(s16 x=node_min.X; x<=node_max.X; x++)
2559 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2564 bool water_found = false;
2565 // Use fast index incrementing
2566 v3s16 em = vmanip.m_area.getExtent();
2567 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
2568 for(s16 y=node_max.Y; y>=node_min.Y; y--)
2570 if(water_found == false)
2572 if(vmanip.m_data[i].getContent() == c_water_source)
2574 v3s16 p = v3s16(p2d.X, y, p2d.Y);
2575 data->transforming_liquid.push_back(p);
2581 // This can be done because water_found can only
2582 // turn to true and end up here after going through
2584 if(vmanip.m_data[i+1].getContent() != c_water_source)
2586 v3s16 p = v3s16(p2d.X, y+1, p2d.Y);
2587 data->transforming_liquid.push_back(p);
2588 water_found = false;
2592 vmanip->m_area.add_y(em, i, -1);
2598 If close to ground level
2601 //if(abs(approx_ground_depth) < 30)
2602 if(minimum_ground_depth < 5 && maximum_ground_depth > -5)
2608 for(s16 x=node_min.X; x<=node_max.X; x++)
2609 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2614 bool possibly_have_sand = get_have_beach(data->seed, p2d);
2615 bool have_sand = false;
2616 u32 current_depth = 0;
2617 bool air_detected = false;
2618 bool water_detected = false;
2619 bool have_clay = false;
2621 // Use fast index incrementing
2622 s16 start_y = node_max.Y+2;
2623 v3s16 em = vmanip.m_area.getExtent();
2624 u32 i = vmanip.m_area.index(v3s16(p2d.X, start_y, p2d.Y));
2625 for(s16 y=start_y; y>=node_min.Y-3; y--)
2627 if(vmanip.m_data[i].getContent() == c_water_source)
2628 water_detected = true;
2629 if(vmanip.m_data[i].getContent() == CONTENT_AIR)
2630 air_detected = true;
2632 if((vmanip.m_data[i].getContent() == c_stone
2633 || vmanip.m_data[i].getContent() == c_dirt_with_grass
2634 || vmanip.m_data[i].getContent() == c_dirt
2635 || vmanip.m_data[i].getContent() == c_sand
2636 || vmanip.m_data[i].getContent() == c_gravel
2637 ) && (air_detected || water_detected))
2639 if(current_depth == 0 && y <= WATER_LEVEL+2
2640 && possibly_have_sand)
2643 if(current_depth < 4)
2647 vmanip.m_data[i] = MapNode(c_sand);
2650 else if(current_depth==0 && !water_detected
2651 && y >= WATER_LEVEL && air_detected)
2652 vmanip.m_data[i] = MapNode(c_dirt_with_grass);
2655 vmanip.m_data[i] = MapNode(c_dirt);
2659 if(vmanip.m_data[i].getContent() == c_dirt
2660 || vmanip.m_data[i].getContent() == c_dirt_with_grass)
2661 vmanip.m_data[i] = MapNode(c_stone);
2666 if(current_depth >= 8)
2669 else if(current_depth != 0)
2672 vmanip->m_area.add_y(em, i, -1);
2678 Calculate some stuff
2681 float surface_humidity = surface_humidity_2d(data->seed, p2d_center);
2682 bool is_jungle = surface_humidity > 0.75;
2684 u32 tree_count = gen_area_nodes * tree_amount_2d(data->seed, p2d_center);
2691 PseudoRandom treerandom(blockseed);
2692 // Put trees in random places on part of division
2693 for(u32 i=0; i<tree_count; i++)
2695 s16 x = treerandom.range(node_min.X, node_max.X);
2696 s16 z = treerandom.range(node_min.Z, node_max.Z);
2697 //s16 y = find_ground_level(vmanip, v2s16(x,z));
2698 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
2699 // Don't make a tree under water level
2702 // Make sure tree fits (only trees whose starting point is
2703 // at this block are added)
2704 if(y < node_min.Y || y > node_max.Y)
2707 Find exact ground level
2711 for(; p.Y >= y-6; p.Y--)
2713 u32 i = vmanip->m_area.index(p);
2714 MapNode *n = &vmanip->m_data[i];
2715 if(n->getContent() != CONTENT_AIR && n->getContent() != c_water_source && n->getContent() != CONTENT_IGNORE)
2721 // If not found, handle next one
2726 u32 i = vmanip->m_area.index(p);
2727 MapNode *n = &vmanip->m_data[i];
2729 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass && n->getContent() != c_sand)
2732 // Papyrus grows only on mud and in water
2733 if(n->getContent() == c_dirt && y <= WATER_LEVEL)
2736 make_papyrus(vmanip, p, ndef);
2738 // Trees grow only on mud and grass, on land
2739 else if((n->getContent() == c_dirt || n->getContent() == c_dirt_with_grass) && y > WATER_LEVEL + 2)
2742 //if(surface_humidity_2d(data->seed, v2s16(x, y)) < 0.5)
2743 if(is_jungle == false)
2746 if(myrand_range(0,4) != 0)
2747 is_apple_tree = false;
2749 is_apple_tree = noise2d_perlin(
2750 0.5+(float)p.X/100, 0.5+(float)p.Z/100,
2751 data->seed+342902, 3, 0.45) > 0.2;
2752 make_tree(vmanip, p, is_apple_tree, ndef);
2755 make_jungletree(vmanip, p, ndef);
2757 // Cactii grow only on sand, on land
2758 else if(n->getContent() == c_sand && y > WATER_LEVEL + 2)
2761 make_cactus(vmanip, p, ndef);
2771 PseudoRandom grassrandom(blockseed);
2772 for(u32 i=0; i<surface_humidity*5*tree_count; i++)
2774 s16 x = grassrandom.range(node_min.X, node_max.X);
2775 s16 z = grassrandom.range(node_min.Z, node_max.Z);
2776 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
2779 if(y < node_min.Y || y > node_max.Y)
2782 Find exact ground level
2786 for(; p.Y >= y-6; p.Y--)
2788 u32 i = vmanip->m_area.index(p);
2789 MapNode *n = &vmanip->m_data[i];
2790 if(data->nodedef->get(*n).is_ground_content)
2796 // If not found, handle next one
2800 if(vmanip.m_area.contains(p) == false)
2802 if(vmanip.m_data[vmanip.m_area.index(p)].getContent() != CONTENT_AIR)
2805 if(vmanip.m_area.contains(p))
2806 vmanip.m_data[vmanip.m_area.index(p)] = c_dirt;
2808 if(vmanip.m_area.contains(p))
2809 vmanip.m_data[vmanip.m_area.index(p)] = c_junglegrass;
2815 Add some kind of random stones
2818 u32 random_stone_count = gen_area_nodes *
2819 randomstone_amount_2d(data->seed, p2d_center);
2820 // Put in random places on part of division
2821 for(u32 i=0; i<random_stone_count; i++)
2823 s16 x = myrand_range(node_min.X, node_max.X);
2824 s16 z = myrand_range(node_min.Z, node_max.Z);
2825 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
2826 // Don't add under water level
2827 /*if(y < WATER_LEVEL)
2829 // Don't add if doesn't belong to this block
2830 if(y < node_min.Y || y > node_max.Y)
2835 u32 i = vmanip->m_area.index(v3s16(p));
2836 MapNode *n = &vmanip->m_data[i];
2837 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass)
2840 // Will be placed one higher
2843 make_randomstone(vmanip, p);
2852 u32 large_stone_count = gen_area_nodes *
2853 largestone_amount_2d(data->seed, p2d_center);
2854 //u32 large_stone_count = 1;
2855 // Put in random places on part of division
2856 for(u32 i=0; i<large_stone_count; i++)
2858 s16 x = myrand_range(node_min.X, node_max.X);
2859 s16 z = myrand_range(node_min.Z, node_max.Z);
2860 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
2861 // Don't add under water level
2862 /*if(y < WATER_LEVEL)
2864 // Don't add if doesn't belong to this block
2865 if(y < node_min.Y || y > node_max.Y)
2870 u32 i = vmanip->m_area.index(v3s16(p));
2871 MapNode *n = &vmanip->m_data[i];
2872 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass)
2875 // Will be placed one lower
2878 make_largestone(vmanip, p);
2888 PseudoRandom mineralrandom(blockseed);
2893 for(s16 i=0; i<approx_ground_depth/4; i++)
2895 if(mineralrandom.next()%50 == 0)
2897 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2898 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2899 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2900 for(u16 i=0; i<27; i++)
2902 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2903 u32 vi = vmanip.m_area.index(p);
2904 if(vmanip.m_data[vi].getContent() == c_stone)
2905 if(mineralrandom.next()%8 == 0)
2906 vmanip.m_data[vi] = MapNode(c_mese);
2915 u16 a = mineralrandom.range(0,15);
2917 u16 amount = 20 * a/1000;
2918 for(s16 i=0; i<amount; i++)
2920 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2921 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2922 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2924 u8 base_content = c_stone;
2925 MapNode new_content(CONTENT_IGNORE);
2928 if(noisebuf_ground_crumbleness.get(x,y+5,z) < -0.1)
2930 new_content = MapNode(c_stone_with_coal);
2934 if(noisebuf_ground_wetness.get(x,y+5,z) > 0.0)
2935 new_content = MapNode(c_stone_with_iron);
2936 /*if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
2937 vmanip.m_data[i] = MapNode(c_dirt);
2939 vmanip.m_data[i] = MapNode(c_sand);*/
2941 /*else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.1)
2945 if(new_content.getContent() != CONTENT_IGNORE)
2947 for(u16 i=0; i<27; i++)
2949 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2950 u32 vi = vmanip.m_area.index(p);
2951 if(vmanip.m_data[vi].getContent() == base_content)
2953 if(mineralrandom.next()%sparseness == 0)
2954 vmanip.m_data[vi] = new_content;
2963 //for(s16 i=0; i < MYMAX(0, 50 - abs(node_min.Y+8 - (-30))); i++)
2964 //for(s16 i=0; i<50; i++)
2965 u16 coal_amount = 30;
2966 u16 coal_rareness = 60 / coal_amount;
2967 if(coal_rareness == 0)
2969 if(mineralrandom.next()%coal_rareness == 0)
2971 u16 a = mineralrandom.next() % 16;
2972 u16 amount = coal_amount * a*a*a / 1000;
2973 for(s16 i=0; i<amount; i++)
2975 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2976 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2977 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2978 for(u16 i=0; i<27; i++)
2980 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2981 u32 vi = vmanip.m_area.index(p);
2982 if(vmanip.m_data[vi].getContent() == c_stone)
2983 if(mineralrandom.next()%8 == 0)
2984 vmanip.m_data[vi] = MapNode(c_stone_with_coal);
2991 u16 iron_amount = 8;
2992 u16 iron_rareness = 60 / iron_amount;
2993 if(iron_rareness == 0)
2995 if(mineralrandom.next()%iron_rareness == 0)
2997 u16 a = mineralrandom.next() % 16;
2998 u16 amount = iron_amount * a*a*a / 1000;
2999 for(s16 i=0; i<amount; i++)
3001 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
3002 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
3003 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
3004 for(u16 i=0; i<27; i++)
3006 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
3007 u32 vi = vmanip.m_area.index(p);
3008 if(vmanip.m_data[vi].getContent() == c_stone)
3009 if(mineralrandom.next()%8 == 0)
3010 vmanip.m_data[vi] = MapNode(c_stone_with_iron);
3021 ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update",
3023 //VoxelArea a(node_min, node_max);
3024 VoxelArea a(node_min-v3s16(1,0,1)*MAP_BLOCKSIZE,
3025 node_max+v3s16(1,0,1)*MAP_BLOCKSIZE);
3026 /*VoxelArea a(node_min-v3s16(1,0,1)*MAP_BLOCKSIZE/2,
3027 node_max+v3s16(1,0,1)*MAP_BLOCKSIZE/2);*/
3028 enum LightBank banks[2] = {LIGHTBANK_DAY, LIGHTBANK_NIGHT};
3029 for(int i=0; i<2; i++)
3031 enum LightBank bank = banks[i];
3033 core::map<v3s16, bool> light_sources;
3034 core::map<v3s16, u8> unlight_from;
3036 voxalgo::clearLightAndCollectSources(vmanip, a, bank, ndef,
3037 light_sources, unlight_from);
3039 bool inexistent_top_provides_sunlight = !block_is_underground;
3040 voxalgo::SunlightPropagateResult res = voxalgo::propagateSunlight(
3041 vmanip, a, inexistent_top_provides_sunlight,
3042 light_sources, ndef);
3043 // TODO: Do stuff according to bottom_sunlight_valid
3045 vmanip.unspreadLight(bank, unlight_from, light_sources, ndef);
3047 vmanip.spreadLight(bank, light_sources, ndef);
3052 #endif ///BIG COMMENT
3054 BlockMakeData::BlockMakeData():
3061 BlockMakeData::~BlockMakeData()
3066 //}; // namespace mapgen