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 MapgenV7::MapgenV7(BiomeDefManager *biomedef, int mapgenid, u64 seed) {
56 init(biomedef, mapgenid, seed,
57 &nparams_mtdefault, &nparams_def_bgroup,
58 &nparams_def_heat, &nparams_def_humidity);
62 MapgenV7::MapgenV7(BiomeDefManager *biomedef, int mapgenid, u64 seed,
63 NoiseParams *np_terrain, NoiseParams *np_bgroup,
64 NoiseParams *np_heat, NoiseParams *np_humidity) {
65 init(biomedef, mapgenid, seed,
66 np_terrain, np_bgroup, np_heat, np_humidity);
69 void MapgenV7::init(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!
78 this->ystride = csize.X;
80 this->np_terrain = np_terrain;
81 this->np_bgroup = np_bgroup;
82 this->np_heat = np_heat;
83 this->np_humidity = np_humidity;
84 noise_terrain = new Noise(np_terrain, seed, csize.X, csize.Y);
85 noise_bgroup = new Noise(np_bgroup, seed, csize.X, csize.Y);
86 noise_heat = new Noise(np_heat, seed, csize.X, csize.Y);
87 noise_humidity = new Noise(np_humidity, seed, csize.X, csize.Y);
89 this->ndef = biomedef->ndef;
90 n_air = MapNode(ndef->getId("mapgen_air"));
91 n_water = MapNode(ndef->getId("mapgen_water_source"));
92 n_lava = MapNode(ndef->getId("mapgen_lava_source"));
96 MapgenV7::~MapgenV7() {
100 delete noise_humidity;
104 void MapgenV7::makeChunk(BlockMakeData *data) {
108 assert(data->vmanip);
109 assert(data->nodedef);
110 assert(data->blockpos_requested.X >= data->blockpos_min.X &&
111 data->blockpos_requested.Y >= data->blockpos_min.Y &&
112 data->blockpos_requested.Z >= data->blockpos_min.Z);
113 assert(data->blockpos_requested.X <= data->blockpos_max.X &&
114 data->blockpos_requested.Y <= data->blockpos_max.Y &&
115 data->blockpos_requested.Z <= data->blockpos_max.Z);
117 this->generating = true;
120 this->vmanip = data->vmanip;
121 v3s16 em = vmanip->m_area.getExtent();
122 this->ystride = em.X;
123 this->zstride = em.Y * em.X;
125 if (node_max.X - node_min.X != 80)
126 printf("uhoh, diff = %d, ystride = %d\n", node_max.X - node_min.X, ystride);
128 node_min = (data->blockpos_min) * MAP_BLOCKSIZE;
129 node_max = (data->blockpos_max + v3s16(1, 1, 1)) * MAP_BLOCKSIZE - v3s16(1, 1, 1);
130 v3s16 full_node_min = (data->blockpos_min - 1) * MAP_BLOCKSIZE;
131 v3s16 full_node_max = (data->blockpos_max + 2) * MAP_BLOCKSIZE - v3s16(1,1,1);
138 TimeTaker timer("Generating terrain");
139 map_terrain = noise_terrain->perlinMap2D(x, z);
140 map_bgroup = noise_bgroup->perlinMap2D(x, z);
141 map_heat = noise_heat->perlinMap2D(x, z);
142 map_humidity = noise_humidity->perlinMap2D(x, z);
144 noise_bgroup->transformNoiseMap();
145 noise_heat->transformNoiseMap();
146 noise_humidity->transformNoiseMap();
149 for (z = node_min.Z; z <= node_max.Z; z++) {
150 for (x = node_min.X; x <= node_max.X; x++) {
151 Biome *biome = biomedef->getBiome(map_bgroup[i], map_heat[i], map_humidity[i]);
152 biome->genColumn(this, x, z, y1, y2);
160 //add blobs of dirt and gravel underground
162 updateLiquid(full_node_min, full_node_max);
163 updateLighting(node_min, node_max);
165 this->generating = false;
169 void MapgenV7::updateLiquid(v3s16 node_min, v3s16 node_max) {
170 bool isliquid, wasliquid;
173 for (s16 z = node_min.Z; z <= node_max.Z; z++) {
174 for (s16 x = node_min.X; x <= node_max.X; x++) {
177 v3s16 em = vmanip->m_area.getExtent();
178 i = vmanip->m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
180 for (s16 y = node_max.Y; y >= node_min.Y; y--) {
181 isliquid = ndef->get(vmanip->m_data[i]).isLiquid();
182 //there was a change between liquid and nonliquid, add to queue
183 if (isliquid != wasliquid)
184 data->transforming_liquid.push_back(v3s16(p2d.X, y, p2d.Y));
186 wasliquid = isliquid;
187 vmanip->m_area.add_y(em, i, -1);
194 void MapgenV7::updateLighting(v3s16 node_min, v3s16 node_max) {
195 enum LightBank banks[2] = {LIGHTBANK_DAY, LIGHTBANK_NIGHT};
197 VoxelArea a(node_min - v3s16(1,0,1) * MAP_BLOCKSIZE,
198 node_max + v3s16(1,0,1) * MAP_BLOCKSIZE);
199 bool block_is_underground = (water_level > node_max.Y);
200 bool sunlight = !block_is_underground;
202 ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update", SPT_AVG);
203 for (int i = 0; i < 2; i++) {
204 enum LightBank bank = banks[i];
205 core::map<v3s16, bool> light_sources;
206 core::map<v3s16, u8> unlight_from;
208 voxalgo::clearLightAndCollectSources(*vmanip, a, bank, ndef,
209 light_sources, unlight_from);
210 voxalgo::propagateSunlight(*vmanip, a, sunlight, light_sources, ndef);
211 //printf("light_sources: %d\t\tunlight_from: %d\n", light_sources.size(), unlight_from.size());
212 vmanip->unspreadLight(bank, unlight_from, light_sources, ndef);
213 vmanip->spreadLight(bank, light_sources, ndef);
218 EmergeManager::EmergeManager(IGameDef *gamedef) {
220 this->water_level = 0;
221 this->np_terrain = &nparams_mtdefault;
222 this->np_bgroup = &nparams_def_bgroup;
223 this->np_heat = &nparams_def_heat;
224 this->np_humidity = &nparams_def_humidity;
226 this->biomedef = new BiomeDefManager(gamedef);
230 EmergeManager::~EmergeManager() {
235 void EmergeManager::addBlockToQueue() {
240 Biome *EmergeManager::getBiomeAtPoint(v3s16 p) {
241 float bgroup = NoisePerlin2D(np_bgroup, p.X, p.Y, seed);
242 float heat = NoisePerlin2D(np_heat, p.X, p.Y, seed);
243 float humidity = NoisePerlin2D(np_humidity, p.X, p.Y, seed);
244 return biomedef->getBiome(bgroup, heat, humidity);
248 //FIXME: This assumes y == 0, that is, always in a non-hell/non-sky biome
249 int EmergeManager::getGroundLevelAtPoint(v2s16 p) {
250 float terrain = NoisePerlin2D(np_terrain, p.X, p.Y, seed);
251 Biome *biome = getBiomeAtPoint(v3s16(p.X, p.Y, 0));
252 return biome->getSurfaceHeight(terrain);
256 bool EmergeManager::isBlockUnderground(v3s16 blockpos) {
258 v2s16 p = v2s16((blockpos.X * MAP_BLOCKSIZE) + MAP_BLOCKSIZE / 2,
259 (blockpos.Y * MAP_BLOCKSIZE) + MAP_BLOCKSIZE / 2);
260 int ground_level = getGroundLevelAtPoint(p);
261 return blockpos.Y * (MAP_BLOCKSIZE + 1) <= min(water_level, ground_level);
264 //yuck, but then again, should i bother being accurate?
265 //the height of the nodes in a single block is quite variable
266 return blockpos.Y * (MAP_BLOCKSIZE + 1) <= water_level;
270 u32 EmergeManager::getBlockSeed(v3s16 p) {
271 return (u32)(seed & 0xFFFFFFFF) +
278 /////////////////////////////////// legacy static functions for farmesh
281 s16 Mapgen::find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision) {
282 //just need to return something
288 bool Mapgen::get_have_beach(u64 seed, v2s16 p2d) {
289 double sandnoise = noise2d_perlin(
290 0.2+(float)p2d.X/250, 0.7+(float)p2d.Y/250,
291 seed+59420, 3, 0.50);
293 return (sandnoise > 0.15);
297 double Mapgen::tree_amount_2d(u64 seed, v2s16 p) {
298 double noise = noise2d_perlin(
299 0.5+(float)p.X/125, 0.5+(float)p.Y/125,
301 double zeroval = -0.39;
305 return 0.04 * (noise-zeroval) / (1.0-zeroval);
309 #if 0 /// BIG COMMENT
314 Some helper functions for the map generator
318 // Returns Y one under area minimum if not found
319 static s16 find_ground_level(VoxelManipulator &vmanip, v2s16 p2d,
320 INodeDefManager *ndef)
322 v3s16 em = vmanip.m_area.getExtent();
323 s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
324 s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
325 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
327 for(y=y_nodes_max; y>=y_nodes_min; y--)
329 MapNode &n = vmanip.m_data[i];
330 if(ndef->get(n).walkable)
333 vmanip.m_area.add_y(em, i, -1);
338 return y_nodes_min - 1;
342 // Returns Y one under area minimum if not found
343 static s16 find_ground_level_clever(VoxelManipulator &vmanip, v2s16 p2d,
344 INodeDefManager *ndef)
346 if(!vmanip.m_area.contains(v3s16(p2d.X, vmanip.m_area.MaxEdge.Y, p2d.Y)))
347 return vmanip.m_area.MinEdge.Y-1;
348 v3s16 em = vmanip.m_area.getExtent();
349 s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
350 s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
351 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
353 content_t c_tree = ndef->getId("mapgen_tree");
354 content_t c_leaves = ndef->getId("mapgen_leaves");
355 for(y=y_nodes_max; y>=y_nodes_min; y--)
357 MapNode &n = vmanip.m_data[i];
358 if(ndef->get(n).walkable
359 && n.getContent() != c_tree
360 && n.getContent() != c_leaves)
363 vmanip.m_area.add_y(em, i, -1);
368 return y_nodes_min - 1;
372 // Returns Y one under area minimum if not found
373 static s16 find_stone_level(VoxelManipulator &vmanip, v2s16 p2d,
374 INodeDefManager *ndef)
376 v3s16 em = vmanip.m_area.getExtent();
377 s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
378 s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
379 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
381 content_t c_stone = ndef->getId("mapgen_stone");
382 content_t c_desert_stone = ndef->getId("mapgen_desert_stone");
383 for(y=y_nodes_max; y>=y_nodes_min; y--)
385 MapNode &n = vmanip.m_data[i];
386 content_t c = n.getContent();
387 if(c != CONTENT_IGNORE && (
388 c == c_stone || c == c_desert_stone))
391 vmanip.m_area.add_y(em, i, -1);
396 return y_nodes_min - 1;
403 static void make_papyrus(VoxelManipulator &vmanip, v3s16 p0,
404 INodeDefManager *ndef)
406 MapNode papyrusnode(ndef->getId("mapgen_papyrus"));
408 s16 trunk_h = myrand_range(2, 3);
410 for(s16 ii=0; ii<trunk_h; ii++)
412 if(vmanip.m_area.contains(p1))
413 vmanip.m_data[vmanip.m_area.index(p1)] = papyrusnode;
418 static void make_cactus(VoxelManipulator &vmanip, v3s16 p0,
419 INodeDefManager *ndef)
421 MapNode cactusnode(ndef->getId("mapgen_cactus"));
425 for(s16 ii=0; ii<trunk_h; ii++)
427 if(vmanip.m_area.contains(p1))
428 vmanip.m_data[vmanip.m_area.index(p1)] = cactusnode;
436 Dungeon making routines
439 #define VMANIP_FLAG_DUNGEON_INSIDE VOXELFLAG_CHECKED1
440 #define VMANIP_FLAG_DUNGEON_PRESERVE VOXELFLAG_CHECKED2
441 #define VMANIP_FLAG_DUNGEON_UNTOUCHABLE (\
442 VMANIP_FLAG_DUNGEON_INSIDE|VMANIP_FLAG_DUNGEON_PRESERVE)
444 static void make_room1(VoxelManipulator &vmanip, v3s16 roomsize, v3s16 roomplace,
445 INodeDefManager *ndef)
448 for(s16 z=0; z<roomsize.Z; z++)
449 for(s16 y=0; y<roomsize.Y; y++)
452 v3s16 p = roomplace + v3s16(0,y,z);
453 if(vmanip.m_area.contains(p) == false)
455 u32 vi = vmanip.m_area.index(p);
456 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
458 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
461 v3s16 p = roomplace + v3s16(roomsize.X-1,y,z);
462 if(vmanip.m_area.contains(p) == false)
464 u32 vi = vmanip.m_area.index(p);
465 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
467 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
472 for(s16 x=0; x<roomsize.X; x++)
473 for(s16 y=0; y<roomsize.Y; y++)
476 v3s16 p = roomplace + v3s16(x,y,0);
477 if(vmanip.m_area.contains(p) == false)
479 u32 vi = vmanip.m_area.index(p);
480 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
482 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
485 v3s16 p = roomplace + v3s16(x,y,roomsize.Z-1);
486 if(vmanip.m_area.contains(p) == false)
488 u32 vi = vmanip.m_area.index(p);
489 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
491 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
495 // Make +-Y walls (floor and ceiling)
496 for(s16 z=0; z<roomsize.Z; z++)
497 for(s16 x=0; x<roomsize.X; x++)
500 v3s16 p = roomplace + v3s16(x,0,z);
501 if(vmanip.m_area.contains(p) == false)
503 u32 vi = vmanip.m_area.index(p);
504 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
506 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
509 v3s16 p = roomplace + v3s16(x,roomsize.Y-1,z);
510 if(vmanip.m_area.contains(p) == false)
512 u32 vi = vmanip.m_area.index(p);
513 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_UNTOUCHABLE)
515 vmanip.m_data[vi] = MapNode(ndef->getId("mapgen_cobble"));
520 for(s16 z=1; z<roomsize.Z-1; z++)
521 for(s16 y=1; y<roomsize.Y-1; y++)
522 for(s16 x=1; x<roomsize.X-1; x++)
524 v3s16 p = roomplace + v3s16(x,y,z);
525 if(vmanip.m_area.contains(p) == false)
527 u32 vi = vmanip.m_area.index(p);
528 vmanip.m_flags[vi] |= VMANIP_FLAG_DUNGEON_UNTOUCHABLE;
529 vmanip.m_data[vi] = MapNode(CONTENT_AIR);
533 static void make_fill(VoxelManipulator &vmanip, v3s16 place, v3s16 size,
534 u8 avoid_flags, MapNode n, u8 or_flags)
536 for(s16 z=0; z<size.Z; z++)
537 for(s16 y=0; y<size.Y; y++)
538 for(s16 x=0; x<size.X; x++)
540 v3s16 p = place + v3s16(x,y,z);
541 if(vmanip.m_area.contains(p) == false)
543 u32 vi = vmanip.m_area.index(p);
544 if(vmanip.m_flags[vi] & avoid_flags)
546 vmanip.m_flags[vi] |= or_flags;
547 vmanip.m_data[vi] = n;
551 static void make_hole1(VoxelManipulator &vmanip, v3s16 place,
552 INodeDefManager *ndef)
554 make_fill(vmanip, place, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
555 VMANIP_FLAG_DUNGEON_INSIDE);
558 static void make_door1(VoxelManipulator &vmanip, v3s16 doorplace, v3s16 doordir,
559 INodeDefManager *ndef)
561 make_hole1(vmanip, doorplace, ndef);
562 // Place torch (for testing)
563 //vmanip.m_data[vmanip.m_area.index(doorplace)] = MapNode(ndef->getId("mapgen_torch"));
566 static v3s16 rand_ortho_dir(PseudoRandom &random)
568 if(random.next()%2==0)
569 return random.next()%2 ? v3s16(-1,0,0) : v3s16(1,0,0);
571 return random.next()%2 ? v3s16(0,0,-1) : v3s16(0,0,1);
574 static v3s16 turn_xz(v3s16 olddir, int t)
594 static v3s16 random_turn(PseudoRandom &random, v3s16 olddir)
596 int turn = random.range(0,2);
605 dir = turn_xz(olddir, 0);
608 dir = turn_xz(olddir, 1);
612 static void make_corridor(VoxelManipulator &vmanip, v3s16 doorplace,
613 v3s16 doordir, v3s16 &result_place, v3s16 &result_dir,
614 PseudoRandom &random, INodeDefManager *ndef)
616 make_hole1(vmanip, doorplace, ndef);
617 v3s16 p0 = doorplace;
621 length = random.range(1,13);
623 length = random.range(1,6);
624 length = random.range(1,13);
625 u32 partlength = random.range(1,13);
628 if(random.next()%2 == 0 && partlength >= 3)
629 make_stairs = random.next()%2 ? 1 : -1;
630 for(u32 i=0; i<length; i++)
636 /*// If already empty
637 if(vmanip.getNodeNoExNoEmerge(p).getContent()
639 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
644 if(vmanip.m_area.contains(p) == true
645 && vmanip.m_area.contains(p+v3s16(0,1,0)) == true)
649 make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,5,3),
650 VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(ndef->getId("mapgen_cobble")), 0);
651 make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
652 VMANIP_FLAG_DUNGEON_INSIDE);
653 make_fill(vmanip, p-dir, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
654 VMANIP_FLAG_DUNGEON_INSIDE);
658 make_fill(vmanip, p+v3s16(-1,-1,-1), v3s16(3,4,3),
659 VMANIP_FLAG_DUNGEON_UNTOUCHABLE, MapNode(ndef->getId("mapgen_cobble")), 0);
660 make_hole1(vmanip, p, ndef);
661 /*make_fill(vmanip, p, v3s16(1,2,1), 0, MapNode(CONTENT_AIR),
662 VMANIP_FLAG_DUNGEON_INSIDE);*/
669 // Can't go here, turn away
670 dir = turn_xz(dir, random.range(0,1));
671 make_stairs = -make_stairs;
673 partlength = random.range(1,length);
678 if(partcount >= partlength)
682 dir = random_turn(random, dir);
684 partlength = random.range(1,length);
687 if(random.next()%2 == 0 && partlength >= 3)
688 make_stairs = random.next()%2 ? 1 : -1;
699 RoomWalker(VoxelManipulator &vmanip_, v3s16 pos, PseudoRandom &random,
700 INodeDefManager *ndef):
711 m_dir = rand_ortho_dir(m_random);
714 void setPos(v3s16 pos)
719 void setDir(v3s16 dir)
724 bool findPlaceForDoor(v3s16 &result_place, v3s16 &result_dir)
726 for(u32 i=0; i<100; i++)
728 v3s16 p = m_pos + m_dir;
729 v3s16 p1 = p + v3s16(0,1,0);
730 if(vmanip.m_area.contains(p) == false
731 || vmanip.m_area.contains(p1) == false
737 if(vmanip.getNodeNoExNoEmerge(p).getContent()
738 == m_ndef->getId("mapgen_cobble")
739 && vmanip.getNodeNoExNoEmerge(p1).getContent()
740 == m_ndef->getId("mapgen_cobble"))
742 // Found wall, this is a good place!
745 // Randomize next direction
750 Determine where to move next
752 // Jump one up if the actual space is there
753 if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).getContent()
754 == m_ndef->getId("mapgen_cobble")
755 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
757 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,2,0)).getContent()
760 // Jump one down if the actual space is there
761 if(vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
762 == m_ndef->getId("mapgen_cobble")
763 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,0,0)).getContent()
765 && vmanip.getNodeNoExNoEmerge(p+v3s16(0,-1,0)).getContent()
768 // Check if walking is now possible
769 if(vmanip.getNodeNoExNoEmerge(p).getContent()
771 || vmanip.getNodeNoExNoEmerge(p+v3s16(0,1,0)).getContent()
774 // Cannot continue walking here
784 bool findPlaceForRoomDoor(v3s16 roomsize, v3s16 &result_doorplace,
785 v3s16 &result_doordir, v3s16 &result_roomplace)
787 for(s16 trycount=0; trycount<30; trycount++)
791 bool r = findPlaceForDoor(doorplace, doordir);
795 // X east, Z north, Y up
797 if(doordir == v3s16(1,0,0)) // X+
798 roomplace = doorplace +
799 v3s16(0,-1,m_random.range(-roomsize.Z+2,-2));
800 if(doordir == v3s16(-1,0,0)) // X-
801 roomplace = doorplace +
802 v3s16(-roomsize.X+1,-1,m_random.range(-roomsize.Z+2,-2));
803 if(doordir == v3s16(0,0,1)) // Z+
804 roomplace = doorplace +
805 v3s16(m_random.range(-roomsize.X+2,-2),-1,0);
806 if(doordir == v3s16(0,0,-1)) // Z-
807 roomplace = doorplace +
808 v3s16(m_random.range(-roomsize.X+2,-2),-1,-roomsize.Z+1);
811 if(doordir == v3s16(1,0,0)) // X+
812 roomplace = doorplace + v3s16(0,-1,-roomsize.Z/2);
813 if(doordir == v3s16(-1,0,0)) // X-
814 roomplace = doorplace + v3s16(-roomsize.X+1,-1,-roomsize.Z/2);
815 if(doordir == v3s16(0,0,1)) // Z+
816 roomplace = doorplace + v3s16(-roomsize.X/2,-1,0);
817 if(doordir == v3s16(0,0,-1)) // Z-
818 roomplace = doorplace + v3s16(-roomsize.X/2,-1,-roomsize.Z+1);
823 for(s16 z=1; z<roomsize.Z-1; z++)
824 for(s16 y=1; y<roomsize.Y-1; y++)
825 for(s16 x=1; x<roomsize.X-1; x++)
827 v3s16 p = roomplace + v3s16(x,y,z);
828 if(vmanip.m_area.contains(p) == false)
833 if(vmanip.m_flags[vmanip.m_area.index(p)]
834 & VMANIP_FLAG_DUNGEON_INSIDE)
845 result_doorplace = doorplace;
846 result_doordir = doordir;
847 result_roomplace = roomplace;
854 VoxelManipulator &vmanip;
857 PseudoRandom &m_random;
858 INodeDefManager *m_ndef;
861 static void make_dungeon1(VoxelManipulator &vmanip, PseudoRandom &random,
862 INodeDefManager *ndef)
864 v3s16 areasize = vmanip.m_area.getExtent();
869 Find place for first room
872 for(u32 i=0; i<100; i++)
874 roomsize = v3s16(random.range(4,8),random.range(4,6),random.range(4,8));
875 roomplace = vmanip.m_area.MinEdge + v3s16(
876 random.range(0,areasize.X-roomsize.X-1),
877 random.range(0,areasize.Y-roomsize.Y-1),
878 random.range(0,areasize.Z-roomsize.Z-1));
880 Check that we're not putting the room to an unknown place,
881 otherwise it might end up floating in the air
884 for(s16 z=1; z<roomsize.Z-1; z++)
885 for(s16 y=1; y<roomsize.Y-1; y++)
886 for(s16 x=1; x<roomsize.X-1; x++)
888 v3s16 p = roomplace + v3s16(x,y,z);
889 u32 vi = vmanip.m_area.index(p);
890 if(vmanip.m_flags[vi] & VMANIP_FLAG_DUNGEON_INSIDE)
895 if(vmanip.m_data[vi].getContent() == CONTENT_IGNORE)
909 Stores the center position of the last room made, so that
910 a new corridor can be started from the last room instead of
911 the new room, if chosen so.
913 v3s16 last_room_center = roomplace+v3s16(roomsize.X/2,1,roomsize.Z/2);
915 u32 room_count = random.range(2,7);
916 for(u32 i=0; i<room_count; i++)
918 // Make a room to the determined place
919 make_room1(vmanip, roomsize, roomplace, ndef);
921 v3s16 room_center = roomplace + v3s16(roomsize.X/2,1,roomsize.Z/2);
923 // Place torch at room center (for testing)
924 //vmanip.m_data[vmanip.m_area.index(room_center)] = MapNode(ndef->getId("mapgen_torch"));
927 if(i == room_count-1)
930 // Determine walker start position
932 bool start_in_last_room = (random.range(0,2)!=0);
933 //bool start_in_last_room = true;
935 v3s16 walker_start_place;
937 if(start_in_last_room)
939 walker_start_place = last_room_center;
943 walker_start_place = room_center;
944 // Store center of current room as the last one
945 last_room_center = room_center;
948 // Create walker and find a place for a door
949 RoomWalker walker(vmanip, walker_start_place, random, ndef);
952 bool r = walker.findPlaceForDoor(doorplace, doordir);
956 if(random.range(0,1)==0)
958 make_door1(vmanip, doorplace, doordir, ndef);
960 // Don't actually make a door
961 doorplace -= doordir;
963 // Make a random corridor starting from the door
965 v3s16 corridor_end_dir;
966 make_corridor(vmanip, doorplace, doordir, corridor_end,
967 corridor_end_dir, random, ndef);
969 // Find a place for a random sized room
970 roomsize = v3s16(random.range(4,8),random.range(4,6),random.range(4,8));
971 walker.setPos(corridor_end);
972 walker.setDir(corridor_end_dir);
973 r = walker.findPlaceForRoomDoor(roomsize, doorplace, doordir, roomplace);
977 if(random.range(0,1)==0)
979 make_door1(vmanip, doorplace, doordir, ndef);
981 // Don't actually make a door
982 roomplace -= doordir;
989 static void make_nc(VoxelManipulator &vmanip, PseudoRandom &random,
990 INodeDefManager *ndef)
994 s32 r = random.range(0, 3);
996 dir = v3s16( 1, 0, 0);
1000 dir = v3s16(-1, 0, 0);
1004 dir = v3s16( 0, 0, 1);
1008 dir = v3s16( 0, 0,-1);
1011 v3s16 p = vmanip.m_area.MinEdge + v3s16(
1012 16+random.range(0,15),
1013 16+random.range(0,15),
1014 16+random.range(0,15));
1015 vmanip.m_data[vmanip.m_area.index(p)] = MapNode(ndef->getId("mapgen_nyancat"), facedir_i);
1016 u32 length = random.range(3,15);
1017 for(u32 j=0; j<length; j++)
1020 vmanip.m_data[vmanip.m_area.index(p)] = MapNode(ndef->getId("mapgen_nyancat_rainbow"));
1026 Noise functions. Make sure seed is mangled differently in each one.
1031 Scaling the output of the noise function affects the overdrive of the
1032 contour function, which affects the shape of the output considerably.
1034 #define CAVE_NOISE_SCALE 12.0
1035 //#define CAVE_NOISE_SCALE 10.0
1036 //#define CAVE_NOISE_SCALE 7.5
1037 //#define CAVE_NOISE_SCALE 5.0
1038 //#define CAVE_NOISE_SCALE 1.0
1040 //#define CAVE_NOISE_THRESHOLD (2.5/CAVE_NOISE_SCALE)
1041 #define CAVE_NOISE_THRESHOLD (1.5/CAVE_NOISE_SCALE)
1043 NoiseParams get_cave_noise1_params(u64 seed)
1045 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.7,
1046 200, CAVE_NOISE_SCALE);*/
1047 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.7,
1048 100, CAVE_NOISE_SCALE);*/
1049 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.6,
1050 100, CAVE_NOISE_SCALE);*/
1051 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.3,
1052 100, CAVE_NOISE_SCALE);*/
1053 return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.5,
1054 50, CAVE_NOISE_SCALE);
1055 //return NoiseParams(NOISE_CONSTANT_ONE);
1058 NoiseParams get_cave_noise2_params(u64 seed)
1060 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.7,
1061 200, CAVE_NOISE_SCALE);*/
1062 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.7,
1063 100, CAVE_NOISE_SCALE);*/
1064 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.3,
1065 100, CAVE_NOISE_SCALE);*/
1066 return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.5,
1067 50, CAVE_NOISE_SCALE);
1068 //return NoiseParams(NOISE_CONSTANT_ONE);
1071 NoiseParams get_ground_noise1_params(u64 seed)
1073 return NoiseParams(NOISE_PERLIN, seed+983240, 4,
1077 NoiseParams get_ground_crumbleness_params(u64 seed)
1079 return NoiseParams(NOISE_PERLIN, seed+34413, 3,
1083 NoiseParams get_ground_wetness_params(u64 seed)
1085 return NoiseParams(NOISE_PERLIN, seed+32474, 4,
1089 bool is_cave(u64 seed, v3s16 p)
1091 double d1 = noise3d_param(get_cave_noise1_params(seed), p.X,p.Y,p.Z);
1092 double d2 = noise3d_param(get_cave_noise2_params(seed), p.X,p.Y,p.Z);
1093 return d1*d2 > CAVE_NOISE_THRESHOLD;
1097 Ground density noise shall be interpreted by using this.
1099 TODO: No perlin noises here, they should be outsourced
1101 NOTE: The speed of these actually isn't terrible
1103 bool val_is_ground(double ground_noise1_val, v3s16 p, u64 seed)
1105 //return ((double)p.Y < ground_noise1_val);
1107 double f = 0.55 + noise2d_perlin(
1108 0.5+(float)p.X/250, 0.5+(float)p.Z/250,
1109 seed+920381, 3, 0.45);
1114 double h = WATER_LEVEL + 10 * noise2d_perlin(
1115 0.5+(float)p.X/250, 0.5+(float)p.Z/250,
1116 seed+84174, 4, 0.5);
1119 return ((double)p.Y - h < ground_noise1_val * f);
1123 Queries whether a position is ground or not.
1125 bool is_ground(u64 seed, v3s16 p)
1127 double val1 = noise3d_param(get_ground_noise1_params(seed), p.X,p.Y,p.Z);
1128 return val_is_ground(val1, p, seed);
1132 // Amount of trees per area in nodes
1133 double tree_amount_2d(u64 seed, v2s16 p)
1135 /*double noise = noise2d_perlin(
1136 0.5+(float)p.X/250, 0.5+(float)p.Y/250,
1138 double noise = noise2d_perlin(
1139 0.5+(float)p.X/125, 0.5+(float)p.Y/125,
1141 double zeroval = -0.39;
1145 return 0.04 * (noise-zeroval) / (1.0-zeroval);
1149 double surface_humidity_2d(u64 seed, v2s16 p)
1151 double noise = noise2d_perlin(
1152 0.5+(float)p.X/500, 0.5+(float)p.Y/500,
1153 seed+72384, 4, 0.66);
1154 noise = (noise + 1.0)/2.0;
1163 Incrementally find ground level from 3d noise
1165 s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision)
1167 // Start a bit fuzzy to make averaging lower precision values
1169 s16 level = myrand_range(-precision/2, precision/2);
1170 s16 dec[] = {31000, 100, 20, 4, 1, 0};
1172 for(i = 1; dec[i] != 0 && precision <= dec[i]; i++)
1174 // First find non-ground by going upwards
1175 // Don't stop in caves.
1177 s16 max = level+dec[i-1]*2;
1178 v3s16 p(p2d.X, level, p2d.Y);
1179 for(; p.Y < max; p.Y += dec[i])
1181 if(!is_ground(seed, p))
1188 // Then find ground by going downwards from there.
1189 // Go in caves, too, when precision is 1.
1191 s16 min = level-dec[i-1]*2;
1192 v3s16 p(p2d.X, level, p2d.Y);
1193 for(; p.Y>min; p.Y-=dec[i])
1195 bool ground = is_ground(seed, p);
1196 /*if(dec[i] == 1 && is_cave(seed, p))
1207 // This is more like the actual ground level
1208 level += dec[i-1]/2;
1213 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1215 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p)
1217 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1218 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1220 a += find_ground_level_from_noise(seed,
1221 v2s16(node_min.X, node_min.Y), p);
1222 a += find_ground_level_from_noise(seed,
1223 v2s16(node_min.X, node_max.Y), p);
1224 a += find_ground_level_from_noise(seed,
1225 v2s16(node_max.X, node_max.Y), p);
1226 a += find_ground_level_from_noise(seed,
1227 v2s16(node_max.X, node_min.Y), p);
1228 a += find_ground_level_from_noise(seed,
1229 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p);
1234 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1236 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p)
1238 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1239 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1242 a = MYMAX(a, find_ground_level_from_noise(seed,
1243 v2s16(node_min.X, node_min.Y), p));
1244 a = MYMAX(a, find_ground_level_from_noise(seed,
1245 v2s16(node_min.X, node_max.Y), p));
1246 a = MYMAX(a, find_ground_level_from_noise(seed,
1247 v2s16(node_max.X, node_max.Y), p));
1248 a = MYMAX(a, find_ground_level_from_noise(seed,
1249 v2s16(node_min.X, node_min.Y), p));
1251 a = MYMAX(a, find_ground_level_from_noise(seed,
1252 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
1253 // Side middle points
1254 a = MYMAX(a, find_ground_level_from_noise(seed,
1255 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
1256 a = MYMAX(a, find_ground_level_from_noise(seed,
1257 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
1258 a = MYMAX(a, find_ground_level_from_noise(seed,
1259 v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1260 a = MYMAX(a, find_ground_level_from_noise(seed,
1261 v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1265 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
1267 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p)
1269 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
1270 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
1273 a = MYMIN(a, find_ground_level_from_noise(seed,
1274 v2s16(node_min.X, node_min.Y), p));
1275 a = MYMIN(a, find_ground_level_from_noise(seed,
1276 v2s16(node_min.X, node_max.Y), p));
1277 a = MYMIN(a, find_ground_level_from_noise(seed,
1278 v2s16(node_max.X, node_max.Y), p));
1279 a = MYMIN(a, find_ground_level_from_noise(seed,
1280 v2s16(node_min.X, node_min.Y), p));
1282 a = MYMIN(a, find_ground_level_from_noise(seed,
1283 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
1284 // Side middle points
1285 a = MYMIN(a, find_ground_level_from_noise(seed,
1286 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
1287 a = MYMIN(a, find_ground_level_from_noise(seed,
1288 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
1289 a = MYMIN(a, find_ground_level_from_noise(seed,
1290 v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1291 a = MYMIN(a, find_ground_level_from_noise(seed,
1292 v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
1297 // Required by mapgen.h
1298 bool block_is_underground(u64 seed, v3s16 blockpos)
1300 /*s16 minimum_groundlevel = (s16)get_sector_minimum_ground_level(
1301 seed, v2s16(blockpos.X, blockpos.Z));*/
1302 // Nah, this is just a heuristic, just return something
1303 s16 minimum_groundlevel = WATER_LEVEL;
1305 if(blockpos.Y*MAP_BLOCKSIZE + MAP_BLOCKSIZE <= minimum_groundlevel)
1311 #define AVERAGE_MUD_AMOUNT 4
1313 double base_rock_level_2d(u64 seed, v2s16 p)
1315 // The base ground level
1316 double base = (double)WATER_LEVEL - (double)AVERAGE_MUD_AMOUNT
1317 + 20. * noise2d_perlin(
1318 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1319 seed+82341, 5, 0.6);
1321 /*// A bit hillier one
1322 double base2 = WATER_LEVEL - 4.0 + 40. * noise2d_perlin(
1323 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1324 seed+93413, 6, 0.69);
1328 // Higher ground level
1329 double higher = (double)WATER_LEVEL + 20. + 16. * noise2d_perlin(
1330 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
1331 seed+85039, 5, 0.6);
1332 //higher = 30; // For debugging
1334 // Limit higher to at least base
1338 // Steepness factor of cliffs
1339 double b = 0.85 + 0.5 * noise2d_perlin(
1340 0.5+(float)p.X/125., 0.5+(float)p.Y/125.,
1342 b = rangelim(b, 0.0, 1000.0);
1345 b = rangelim(b, 0.5, 1000.0);
1346 // Values 1.5...100 give quite horrible looking slopes
1347 if(b > 1.5 && b < 100.0){
1353 //dstream<<"b="<<b<<std::endl;
1357 // Offset to more low
1358 double a_off = -0.20;
1359 // High/low selector
1360 /*double a = 0.5 + b * (a_off + noise2d_perlin(
1361 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
1362 seed+4213, 6, 0.7));*/
1363 double a = (double)0.5 + b * (a_off + noise2d_perlin(
1364 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
1365 seed+4213, 5, 0.69));
1367 a = rangelim(a, 0.0, 1.0);
1369 //dstream<<"a="<<a<<std::endl;
1371 double h = base*(1.0-a) + higher*a;
1378 s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision)
1380 return base_rock_level_2d(seed, p2d) + AVERAGE_MUD_AMOUNT;
1383 double get_mud_add_amount(u64 seed, v2s16 p)
1385 return ((float)AVERAGE_MUD_AMOUNT + 2.0 * noise2d_perlin(
1386 0.5+(float)p.X/200, 0.5+(float)p.Y/200,
1387 seed+91013, 3, 0.55));
1390 bool get_have_beach(u64 seed, v2s16 p2d)
1392 // Determine whether to have sand here
1393 double sandnoise = noise2d_perlin(
1394 0.2+(float)p2d.X/250, 0.7+(float)p2d.Y/250,
1395 seed+59420, 3, 0.50);
1397 return (sandnoise > 0.15);
1406 BiomeType get_biome(u64 seed, v2s16 p2d)
1408 // Just do something very simple as for now
1409 double d = noise2d_perlin(
1410 0.6+(float)p2d.X/250, 0.2+(float)p2d.Y/250,
1411 seed+9130, 3, 0.50);
1414 if(d > 0.35 && (noise2d( p2d.X, p2d.Y, int(seed) ) + 1.0) > ( 0.45 - d ) * 20.0 )
1419 u32 get_blockseed(u64 seed, v3s16 p)
1421 s32 x=p.X, y=p.Y, z=p.Z;
1422 return (u32)(seed%0x100000000ULL) + z*38134234 + y*42123 + x*23;
1425 #define VMANIP_FLAG_CAVE VOXELFLAG_CHECKED1
1427 void make_block(BlockMakeData *data)
1431 //dstream<<"makeBlock: no-op"<<std::endl;
1435 assert(data->vmanip);
1436 assert(data->nodedef);
1437 assert(data->blockpos_requested.X >= data->blockpos_min.X &&
1438 data->blockpos_requested.Y >= data->blockpos_min.Y &&
1439 data->blockpos_requested.Z >= data->blockpos_min.Z);
1440 assert(data->blockpos_requested.X <= data->blockpos_max.X &&
1441 data->blockpos_requested.Y <= data->blockpos_max.Y &&
1442 data->blockpos_requested.Z <= data->blockpos_max.Z);
1444 INodeDefManager *ndef = data->nodedef;
1446 // Hack: use minimum block coordinates for old code that assumes
1448 v3s16 blockpos = data->blockpos_requested;
1450 /*dstream<<"makeBlock(): ("<<blockpos.X<<","<<blockpos.Y<<","
1451 <<blockpos.Z<<")"<<std::endl;*/
1453 v3s16 blockpos_min = data->blockpos_min;
1454 v3s16 blockpos_max = data->blockpos_max;
1455 v3s16 blockpos_full_min = blockpos_min - v3s16(1,1,1);
1456 v3s16 blockpos_full_max = blockpos_max + v3s16(1,1,1);
1458 ManualMapVoxelManipulator &vmanip = *(data->vmanip);
1459 // Area of central chunk
1460 v3s16 node_min = blockpos_min*MAP_BLOCKSIZE;
1461 v3s16 node_max = (blockpos_max+v3s16(1,1,1))*MAP_BLOCKSIZE-v3s16(1,1,1);
1462 // Full allocated area
1463 v3s16 full_node_min = (blockpos_min-1)*MAP_BLOCKSIZE;
1464 v3s16 full_node_max = (blockpos_max+2)*MAP_BLOCKSIZE-v3s16(1,1,1);
1466 v3s16 central_area_size = node_max - node_min + v3s16(1,1,1);
1468 const s16 max_spread_amount = MAP_BLOCKSIZE;
1470 int volume_blocks = (blockpos_max.X - blockpos_min.X + 1)
1471 * (blockpos_max.Y - blockpos_min.Y + 1)
1472 * (blockpos_max.Z - blockpos_max.Z + 1);
1474 int volume_nodes = volume_blocks *
1475 MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
1477 // Generated surface area
1478 //double gen_area_nodes = MAP_BLOCKSIZE*MAP_BLOCKSIZE * rel_volume;
1480 // Horribly wrong heuristic, but better than nothing
1481 bool block_is_underground = (WATER_LEVEL > node_max.Y);
1484 Create a block-specific seed
1486 u32 blockseed = get_blockseed(data->seed, full_node_min);
1489 Cache some ground type values for speed
1492 // Creates variables c_name=id and n_name=node
1493 #define CONTENT_VARIABLE(ndef, name)\
1494 content_t c_##name = ndef->getId("mapgen_" #name);\
1495 MapNode n_##name(c_##name);
1496 // Default to something else if was CONTENT_IGNORE
1497 #define CONTENT_VARIABLE_FALLBACK(name, dname)\
1498 if(c_##name == CONTENT_IGNORE){\
1499 c_##name = c_##dname;\
1500 n_##name = n_##dname;\
1503 CONTENT_VARIABLE(ndef, stone);
1504 CONTENT_VARIABLE(ndef, air);
1505 CONTENT_VARIABLE(ndef, water_source);
1506 CONTENT_VARIABLE(ndef, dirt);
1507 CONTENT_VARIABLE(ndef, sand);
1508 CONTENT_VARIABLE(ndef, gravel);
1509 CONTENT_VARIABLE(ndef, clay);
1510 CONTENT_VARIABLE(ndef, lava_source);
1511 CONTENT_VARIABLE(ndef, cobble);
1512 CONTENT_VARIABLE(ndef, mossycobble);
1513 CONTENT_VARIABLE(ndef, dirt_with_grass);
1514 CONTENT_VARIABLE(ndef, junglegrass);
1515 CONTENT_VARIABLE(ndef, stone_with_coal);
1516 CONTENT_VARIABLE(ndef, stone_with_iron);
1517 CONTENT_VARIABLE(ndef, mese);
1518 CONTENT_VARIABLE(ndef, desert_sand);
1519 CONTENT_VARIABLE_FALLBACK(desert_sand, sand);
1520 CONTENT_VARIABLE(ndef, desert_stone);
1521 CONTENT_VARIABLE_FALLBACK(desert_stone, stone);
1523 // Maximum height of the stone surface and obstacles.
1524 // This is used to guide the cave generation
1525 s16 stone_surface_max_y = 0;
1528 Generate general ground level to full area
1532 TimeTaker timer1("Generating ground level");
1534 for(s16 x=node_min.X; x<=node_max.X; x++)
1535 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1538 v2s16 p2d = v2s16(x,z);
1541 Skip of already generated
1544 v3s16 p(p2d.X, node_min.Y, p2d.Y);
1545 if(vmanip.m_data[vmanip.m_area.index(p)].d != CONTENT_AIR)
1549 // Ground height at this point
1550 float surface_y_f = 0.0;
1552 // Use perlin noise for ground height
1553 surface_y_f = base_rock_level_2d(data->seed, p2d);
1555 /*// Experimental stuff
1557 float a = highlands_level_2d(data->seed, p2d);
1562 // Convert to integer
1563 s16 surface_y = (s16)surface_y_f;
1566 if(surface_y > stone_surface_max_y)
1567 stone_surface_max_y = surface_y;
1569 BiomeType bt = get_biome(data->seed, p2d);
1571 Fill ground with stone
1574 // Use fast index incrementing
1575 v3s16 em = vmanip.m_area.getExtent();
1576 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
1577 for(s16 y=node_min.Y; y<=node_max.Y; y++)
1579 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE){
1581 if(y > WATER_LEVEL && bt == BT_DESERT)
1582 vmanip.m_data[i] = n_desert_stone;
1584 vmanip.m_data[i] = n_stone;
1585 } else if(y <= WATER_LEVEL){
1586 vmanip.m_data[i] = MapNode(c_water_source);
1588 vmanip.m_data[i] = MapNode(c_air);
1591 vmanip.m_area.add_y(em, i, 1);
1599 // Limit dirt flow area by 1 because mud is flown into neighbors.
1600 assert(central_area_size.X == central_area_size.Z);
1601 s16 mudflow_minpos = 0-max_spread_amount+1;
1602 s16 mudflow_maxpos = central_area_size.X+max_spread_amount-2;
1605 Loop this part, it will make stuff look older and newer nicely
1608 const u32 age_loops = 2;
1609 for(u32 i_age=0; i_age<age_loops; i_age++)
1611 /******************************
1612 BEGINNING OF AGING LOOP
1613 ******************************/
1618 //TimeTaker timer1("caves");
1621 Make caves (this code is relatively horrible)
1623 double cave_amount = 6.0 + 6.0 * noise2d_perlin(
1624 0.5+(double)node_min.X/250, 0.5+(double)node_min.Y/250,
1625 data->seed+34329, 3, 0.50);
1626 cave_amount = MYMAX(0.0, cave_amount);
1627 u32 caves_count = cave_amount * volume_nodes / 50000;
1628 u32 bruises_count = 1;
1629 PseudoRandom ps(blockseed+21343);
1630 PseudoRandom ps2(blockseed+1032);
1631 if(ps.range(1, 6) == 1)
1632 bruises_count = ps.range(0, ps.range(0, 2));
1633 if(get_biome(data->seed, v2s16(node_min.X, node_min.Y)) == BT_DESERT){
1637 for(u32 jj=0; jj<caves_count+bruises_count; jj++)
1639 bool large_cave = (jj >= caves_count);
1640 s16 min_tunnel_diameter = 2;
1641 s16 max_tunnel_diameter = ps.range(2,6);
1642 int dswitchint = ps.range(1,14);
1643 u16 tunnel_routepoints = 0;
1644 int part_max_length_rs = 0;
1646 part_max_length_rs = ps.range(2,4);
1647 tunnel_routepoints = ps.range(5, ps.range(15,30));
1648 min_tunnel_diameter = 5;
1649 max_tunnel_diameter = ps.range(7, ps.range(8,24));
1651 part_max_length_rs = ps.range(2,9);
1652 tunnel_routepoints = ps.range(10, ps.range(15,30));
1654 bool large_cave_is_flat = (ps.range(0,1) == 0);
1656 v3f main_direction(0,0,0);
1658 // Allowed route area size in nodes
1659 v3s16 ar = central_area_size;
1661 // Area starting point in nodes
1662 v3s16 of = node_min;
1665 //(this should be more than the maximum radius of the tunnel)
1666 //s16 insure = 5; // Didn't work with max_d = 20
1668 s16 more = max_spread_amount - max_tunnel_diameter/2 - insure;
1669 ar += v3s16(1,0,1) * more * 2;
1670 of -= v3s16(1,0,1) * more;
1672 s16 route_y_min = 0;
1673 // Allow half a diameter + 7 over stone surface
1674 s16 route_y_max = -of.Y + stone_surface_max_y + max_tunnel_diameter/2 + 7;
1676 /*// If caves, don't go through surface too often
1677 if(large_cave == false)
1678 route_y_max -= ps.range(0, max_tunnel_diameter*2);*/
1680 // Limit maximum to area
1681 route_y_max = rangelim(route_y_max, 0, ar.Y-1);
1685 /*// Minimum is at y=0
1686 route_y_min = -of.Y - 0;*/
1687 // Minimum is at y=max_tunnel_diameter/4
1688 //route_y_min = -of.Y + max_tunnel_diameter/4;
1689 //s16 min = -of.Y + max_tunnel_diameter/4;
1690 //s16 min = -of.Y + 0;
1692 if(node_min.Y < WATER_LEVEL && node_max.Y > WATER_LEVEL)
1694 min = WATER_LEVEL - max_tunnel_diameter/3 - of.Y;
1695 route_y_max = WATER_LEVEL + max_tunnel_diameter/3 - of.Y;
1697 route_y_min = ps.range(min, min + max_tunnel_diameter);
1698 route_y_min = rangelim(route_y_min, 0, route_y_max);
1701 /*dstream<<"route_y_min = "<<route_y_min
1702 <<", route_y_max = "<<route_y_max<<std::endl;*/
1704 s16 route_start_y_min = route_y_min;
1705 s16 route_start_y_max = route_y_max;
1707 // Start every 4th cave from surface when applicable
1708 /*bool coming_from_surface = false;
1709 if(node_min.Y <= 0 && node_max.Y >= 0){
1710 coming_from_surface = (jj % 4 == 0 && large_cave == false);
1711 if(coming_from_surface)
1712 route_start_y_min = -of.Y + stone_surface_max_y + 10;
1715 route_start_y_min = rangelim(route_start_y_min, 0, ar.Y-1);
1716 route_start_y_max = rangelim(route_start_y_max, route_start_y_min, ar.Y-1);
1718 // Randomize starting position
1720 (float)(ps.next()%ar.X)+0.5,
1721 (float)(ps.range(route_start_y_min, route_start_y_max))+0.5,
1722 (float)(ps.next()%ar.Z)+0.5
1725 v3s16 startp(orp.X, orp.Y, orp.Z);
1728 MapNode airnode(CONTENT_AIR);
1729 MapNode waternode(c_water_source);
1730 MapNode lavanode(c_lava_source);
1733 Generate some tunnel starting from orp
1736 for(u16 j=0; j<tunnel_routepoints; j++)
1738 if(j%dswitchint==0 && large_cave == false)
1740 main_direction = v3f(
1741 ((float)(ps.next()%20)-(float)10)/10,
1742 ((float)(ps.next()%20)-(float)10)/30,
1743 ((float)(ps.next()%20)-(float)10)/10
1745 main_direction *= (float)ps.range(0, 10)/10;
1749 s16 min_d = min_tunnel_diameter;
1750 s16 max_d = max_tunnel_diameter;
1751 s16 rs = ps.range(min_d, max_d);
1753 // Every second section is rough
1754 bool randomize_xz = (ps2.range(1,2) == 1);
1760 rs*part_max_length_rs,
1761 rs*part_max_length_rs/2,
1762 rs*part_max_length_rs
1768 rs*part_max_length_rs,
1769 ps.range(1, rs*part_max_length_rs),
1770 rs*part_max_length_rs
1777 (float)(ps.next()%(maxlen.X*1))-(float)maxlen.X/2,
1778 (float)(ps.next()%(maxlen.Y*1))-(float)maxlen.Y/2,
1779 (float)(ps.next()%(maxlen.Z*1))-(float)maxlen.Z/2
1782 // Jump downward sometimes
1783 if(!large_cave && ps.range(0,12) == 0)
1786 (float)(ps.next()%(maxlen.X*1))-(float)maxlen.X/2,
1787 (float)(ps.next()%(maxlen.Y*2))-(float)maxlen.Y*2/2,
1788 (float)(ps.next()%(maxlen.Z*1))-(float)maxlen.Z/2
1794 s16 h = find_ground_level_clever(vmanip,
1795 v2s16(p.X, p.Z), ndef);
1796 route_y_min = h - rs/3;
1797 route_y_max = h + rs;
1800 vec += main_direction;
1805 else if(rp.X >= ar.X)
1807 if(rp.Y < route_y_min)
1809 else if(rp.Y >= route_y_max)
1810 rp.Y = route_y_max-1;
1813 else if(rp.Z >= ar.Z)
1817 for(float f=0; f<1.0; f+=1.0/vec.getLength())
1819 v3f fp = orp + vec * f;
1820 fp.X += 0.1*ps.range(-10,10);
1821 fp.Z += 0.1*ps.range(-10,10);
1822 v3s16 cp(fp.X, fp.Y, fp.Z);
1827 d0 += ps.range(-1,1);
1828 d1 += ps.range(-1,1);
1830 for(s16 z0=d0; z0<=d1; z0++)
1832 s16 si = rs/2 - MYMAX(0, abs(z0)-rs/7-1);
1833 for(s16 x0=-si-ps.range(0,1); x0<=si-1+ps.range(0,1); x0++)
1835 s16 maxabsxz = MYMAX(abs(x0), abs(z0));
1836 s16 si2 = rs/2 - MYMAX(0, maxabsxz-rs/7-1);
1837 for(s16 y0=-si2; y0<=si2; y0++)
1839 /*// Make better floors in small caves
1840 if(y0 <= -rs/2 && rs<=7)
1842 if(large_cave_is_flat){
1843 // Make large caves not so tall
1844 if(rs > 7 && abs(y0) >= rs/3)
1854 if(vmanip.m_area.contains(p) == false)
1857 u32 i = vmanip.m_area.index(p);
1861 if(full_node_min.Y < WATER_LEVEL &&
1862 full_node_max.Y > WATER_LEVEL){
1863 if(p.Y <= WATER_LEVEL)
1864 vmanip.m_data[i] = waternode;
1866 vmanip.m_data[i] = airnode;
1867 } else if(full_node_max.Y < WATER_LEVEL){
1868 if(p.Y < startp.Y - 2)
1869 vmanip.m_data[i] = lavanode;
1871 vmanip.m_data[i] = airnode;
1873 vmanip.m_data[i] = airnode;
1876 // Don't replace air or water or lava or ignore
1877 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE ||
1878 vmanip.m_data[i].getContent() == CONTENT_AIR ||
1879 vmanip.m_data[i].getContent() == c_water_source ||
1880 vmanip.m_data[i].getContent() == c_lava_source)
1883 vmanip.m_data[i] = airnode;
1886 vmanip.m_flags[i] |= VMANIP_FLAG_CAVE;
1904 TimeTaker timer1("add mud");
1907 Add mud to the central chunk
1910 for(s16 x=node_min.X; x<=node_max.X; x++)
1911 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1913 // Node position in 2d
1914 v2s16 p2d = v2s16(x,z);
1916 // Randomize mud amount
1917 s16 mud_add_amount = get_mud_add_amount(data->seed, p2d) / 2.0 + 0.5;
1919 // Find ground level
1920 s16 surface_y = find_stone_level(vmanip, p2d, ndef);
1921 // Handle area not found
1922 if(surface_y == vmanip.m_area.MinEdge.Y - 1)
1925 MapNode addnode(c_dirt);
1926 BiomeType bt = get_biome(data->seed, p2d);
1929 addnode = MapNode(c_desert_sand);
1931 if(bt == BT_DESERT && surface_y + mud_add_amount <= WATER_LEVEL+1){
1932 addnode = MapNode(c_sand);
1933 } else if(mud_add_amount <= 0){
1934 mud_add_amount = 1 - mud_add_amount;
1935 addnode = MapNode(c_gravel);
1936 } else if(bt == BT_NORMAL && get_have_beach(data->seed, p2d) &&
1937 surface_y + mud_add_amount <= WATER_LEVEL+2){
1938 addnode = MapNode(c_sand);
1941 if(bt == BT_DESERT){
1943 mud_add_amount = MYMAX(0, mud_add_amount - (surface_y - 20)/5);
1948 If topmost node is grass, change it to mud.
1949 It might be if it was flown to there from a neighboring
1950 chunk and then converted.
1953 u32 i = vmanip.m_area.index(v3s16(p2d.X, surface_y, p2d.Y));
1954 MapNode *n = &vmanip.m_data[i];
1955 if(n->getContent() == c_dirt_with_grass)
1956 *n = MapNode(c_dirt);
1964 v3s16 em = vmanip.m_area.getExtent();
1965 s16 y_start = surface_y+1;
1966 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
1967 for(s16 y=y_start; y<=node_max.Y; y++)
1969 if(mudcount >= mud_add_amount)
1972 MapNode &n = vmanip.m_data[i];
1976 vmanip.m_area.add_y(em, i, 1);
1986 Add blobs of dirt and gravel underground
1988 if(get_biome(data->seed, v2s16(node_min.X, node_min.Y)) == BT_NORMAL)
1990 PseudoRandom pr(blockseed+983);
1991 for(int i=0; i<volume_nodes/10/10/10; i++)
1993 bool only_fill_cave = (myrand_range(0,1) != 0);
2000 pr.range(node_min.X, node_max.X)-size.X/2,
2001 pr.range(node_min.Y, node_max.Y)-size.Y/2,
2002 pr.range(node_min.Z, node_max.Z)-size.Z/2
2005 if(p0.Y > -32 && pr.range(0,1) == 0)
2006 n1 = MapNode(c_dirt);
2008 n1 = MapNode(c_gravel);
2009 for(int x1=0; x1<size.X; x1++)
2010 for(int y1=0; y1<size.Y; y1++)
2011 for(int z1=0; z1<size.Z; z1++)
2013 v3s16 p = p0 + v3s16(x1,y1,z1);
2014 u32 i = vmanip.m_area.index(p);
2015 if(!vmanip.m_area.contains(i))
2017 // Cancel if not stone and not cave air
2018 if(vmanip.m_data[i].getContent() != c_stone &&
2019 !(vmanip.m_flags[i] & VMANIP_FLAG_CAVE))
2021 if(only_fill_cave && !(vmanip.m_flags[i] & VMANIP_FLAG_CAVE))
2023 vmanip.m_data[i] = n1;
2031 TimeTaker timer1("flow mud");
2034 Flow mud away from steep edges
2037 // Iterate a few times
2038 for(s16 k=0; k<3; k++)
2041 for(s16 x=mudflow_minpos; x<=mudflow_maxpos; x++)
2042 for(s16 z=mudflow_minpos; z<=mudflow_maxpos; z++)
2044 // Invert coordinates every 2nd iteration
2047 x = mudflow_maxpos - (x-mudflow_minpos);
2048 z = mudflow_maxpos - (z-mudflow_minpos);
2051 // Node position in 2d
2052 v2s16 p2d = v2s16(node_min.X, node_min.Z) + v2s16(x,z);
2054 v3s16 em = vmanip.m_area.getExtent();
2055 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
2058 while(y >= node_min.Y)
2065 for(; y>=node_min.Y; y--)
2067 n = &vmanip.m_data[i];
2068 //if(content_walkable(n->d))
2070 if(n->getContent() == c_dirt ||
2071 n->getContent() == c_dirt_with_grass ||
2072 n->getContent() == c_gravel)
2075 vmanip.m_area.add_y(em, i, -1);
2078 // Stop if out of area
2079 //if(vmanip.m_area.contains(i) == false)
2083 /*// If not mud, do nothing to it
2084 MapNode *n = &vmanip.m_data[i];
2085 if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS)
2088 if(n->getContent() == c_dirt ||
2089 n->getContent() == c_dirt_with_grass)
2091 // Make it exactly mud
2092 n->setContent(c_dirt);
2095 Don't flow it if the stuff under it is not mud
2099 vmanip.m_area.add_y(em, i2, -1);
2100 // Cancel if out of area
2101 if(vmanip.m_area.contains(i2) == false)
2103 MapNode *n2 = &vmanip.m_data[i2];
2104 if(n2->getContent() != c_dirt &&
2105 n2->getContent() != c_dirt_with_grass)
2110 /*s16 recurse_count = 0;
2114 v3s16(0,0,1), // back
2115 v3s16(1,0,0), // right
2116 v3s16(0,0,-1), // front
2117 v3s16(-1,0,0), // left
2120 // Theck that upper is air or doesn't exist.
2121 // Cancel dropping if upper keeps it in place
2123 vmanip.m_area.add_y(em, i3, 1);
2124 if(vmanip.m_area.contains(i3) == true
2125 && ndef->get(vmanip.m_data[i3]).walkable)
2132 for(u32 di=0; di<4; di++)
2134 v3s16 dirp = dirs4[di];
2137 vmanip.m_area.add_p(em, i2, dirp);
2138 // Fail if out of area
2139 if(vmanip.m_area.contains(i2) == false)
2141 // Check that side is air
2142 MapNode *n2 = &vmanip.m_data[i2];
2143 if(ndef->get(*n2).walkable)
2145 // Check that under side is air
2146 vmanip.m_area.add_y(em, i2, -1);
2147 if(vmanip.m_area.contains(i2) == false)
2149 n2 = &vmanip.m_data[i2];
2150 if(ndef->get(*n2).walkable)
2152 /*// Check that under that is air (need a drop of 2)
2153 vmanip.m_area.add_y(em, i2, -1);
2154 if(vmanip.m_area.contains(i2) == false)
2156 n2 = &vmanip.m_data[i2];
2157 if(content_walkable(n2->d))
2159 // Loop further down until not air
2160 bool dropped_to_unknown = false;
2162 vmanip.m_area.add_y(em, i2, -1);
2163 n2 = &vmanip.m_data[i2];
2164 // if out of known area
2165 if(vmanip.m_area.contains(i2) == false
2166 || n2->getContent() == CONTENT_IGNORE){
2167 dropped_to_unknown = true;
2170 }while(ndef->get(*n2).walkable == false);
2171 // Loop one up so that we're in air
2172 vmanip.m_area.add_y(em, i2, 1);
2173 n2 = &vmanip.m_data[i2];
2175 bool old_is_water = (n->getContent() == c_water_source);
2176 // Move mud to new place
2177 if(!dropped_to_unknown) {
2179 // Set old place to be air (or water)
2181 *n = MapNode(c_water_source);
2183 *n = MapNode(CONTENT_AIR);
2199 /***********************
2201 ************************/
2204 Add top and bottom side of water to transforming_liquid queue
2207 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2208 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2213 bool water_found = false;
2214 // Use fast index incrementing
2215 v3s16 em = vmanip.m_area.getExtent();
2216 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
2217 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
2219 if(y == full_node_max.Y){
2221 (vmanip.m_data[i].getContent() == c_water_source ||
2222 vmanip.m_data[i].getContent() == c_lava_source);
2224 else if(water_found == false)
2226 if(vmanip.m_data[i].getContent() == c_water_source ||
2227 vmanip.m_data[i].getContent() == c_lava_source)
2229 v3s16 p = v3s16(p2d.X, y, p2d.Y);
2230 data->transforming_liquid.push_back(p);
2236 // This can be done because water_found can only
2237 // turn to true and end up here after going through
2239 if(vmanip.m_data[i+1].getContent() != c_water_source ||
2240 vmanip.m_data[i+1].getContent() != c_lava_source)
2242 v3s16 p = v3s16(p2d.X, y+1, p2d.Y);
2243 data->transforming_liquid.push_back(p);
2244 water_found = false;
2248 vmanip.m_area.add_y(em, i, -1);
2257 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2258 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2260 // Node position in 2d
2261 v2s16 p2d = v2s16(x,z);
2264 Find the lowest surface to which enough light ends up
2267 Basically just wait until not air and not leaves.
2271 v3s16 em = vmanip.m_area.getExtent();
2272 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
2274 // Go to ground level
2275 for(y=node_max.Y; y>=full_node_min.Y; y--)
2277 MapNode &n = vmanip.m_data[i];
2278 if(ndef->get(n).param_type != CPT_LIGHT
2279 || ndef->get(n).liquid_type != LIQUID_NONE)
2281 vmanip.m_area.add_y(em, i, -1);
2283 if(y >= full_node_min.Y)
2286 surface_y = full_node_min.Y;
2289 u32 i = vmanip.m_area.index(p2d.X, surface_y, p2d.Y);
2290 MapNode *n = &vmanip.m_data[i];
2291 if(n->getContent() == c_dirt){
2292 // Well yeah, this can't be overground...
2293 if(surface_y < WATER_LEVEL - 20)
2295 n->setContent(c_dirt_with_grass);
2302 assert(central_area_size.X == central_area_size.Z);
2304 // Divide area into parts
2306 s16 sidelen = central_area_size.X / div;
2307 double area = sidelen * sidelen;
2308 for(s16 x0=0; x0<div; x0++)
2309 for(s16 z0=0; z0<div; z0++)
2311 // Center position of part of division
2313 node_min.X + sidelen/2 + sidelen*x0,
2314 node_min.Z + sidelen/2 + sidelen*z0
2316 // Minimum edge of part of division
2318 node_min.X + sidelen*x0,
2319 node_min.Z + sidelen*z0
2321 // Maximum edge of part of division
2323 node_min.X + sidelen + sidelen*x0 - 1,
2324 node_min.Z + sidelen + sidelen*z0 - 1
2327 u32 tree_count = area * tree_amount_2d(data->seed, p2d_center);
2328 // Put trees in random places on part of division
2329 for(u32 i=0; i<tree_count; i++)
2331 s16 x = myrand_range(p2d_min.X, p2d_max.X);
2332 s16 z = myrand_range(p2d_min.Y, p2d_max.Y);
2333 s16 y = find_ground_level(vmanip, v2s16(x,z), ndef);
2334 // Don't make a tree under water level
2337 // Don't make a tree so high that it doesn't fit
2338 if(y > node_max.Y - 6)
2342 Trees grow only on mud and grass
2345 u32 i = vmanip.m_area.index(v3s16(p));
2346 MapNode *n = &vmanip.m_data[i];
2347 if(n->getContent() != c_dirt
2348 && n->getContent() != c_dirt_with_grass)
2353 treegen::make_tree(vmanip, p, false, ndef);
2360 Make base ground level
2363 for(s16 x=node_min.X; x<=node_max.X; x++)
2364 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2369 // Use fast index incrementing
2370 v3s16 em = vmanip.m_area.getExtent();
2371 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
2372 for(s16 y=node_min.Y; y<=node_max.Y; y++)
2374 // Only modify places that have no content
2375 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE)
2377 // First priority: make air and water.
2378 // This avoids caves inside water.
2379 if(all_is_ground_except_caves == false
2380 && val_is_ground(noisebuf_ground.get(x,y,z),
2381 v3s16(x,y,z), data->seed) == false)
2383 if(y <= WATER_LEVEL)
2384 vmanip.m_data[i] = n_water_source;
2386 vmanip.m_data[i] = n_air;
2388 else if(noisebuf_cave.get(x,y,z) > CAVE_NOISE_THRESHOLD)
2389 vmanip.m_data[i] = n_air;
2391 vmanip.m_data[i] = n_stone;
2394 vmanip->m_area.add_y(em, i, 1);
2400 Add mud and sand and others underground (in place of stone)
2403 for(s16 x=node_min.X; x<=node_max.X; x++)
2404 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2409 // Use fast index incrementing
2410 v3s16 em = vmanip.m_area.getExtent();
2411 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
2412 for(s16 y=node_max.Y; y>=node_min.Y; y--)
2414 if(vmanip.m_data[i].getContent() == c_stone)
2416 if(noisebuf_ground_crumbleness.get(x,y,z) > 1.3)
2418 if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
2419 vmanip.m_data[i] = n_dirt;
2421 vmanip.m_data[i] = n_sand;
2423 else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.7)
2425 if(noisebuf_ground_wetness.get(x,y,z) < -0.6)
2426 vmanip.m_data[i] = n_gravel;
2428 else if(noisebuf_ground_crumbleness.get(x,y,z) <
2429 -3.0 + MYMIN(0.1 * sqrt((float)MYMAX(0, -y)), 1.5))
2431 vmanip.m_data[i] = n_lava_source;
2432 for(s16 x1=-1; x1<=1; x1++)
2433 for(s16 y1=-1; y1<=1; y1++)
2434 for(s16 z1=-1; z1<=1; z1++)
2435 data->transforming_liquid.push_back(
2436 v3s16(p2d.X+x1, y+y1, p2d.Y+z1));
2440 vmanip->m_area.add_y(em, i, -1);
2449 //if(node_min.Y < approx_groundlevel)
2450 //if(myrand() % 3 == 0)
2451 //if(myrand() % 3 == 0 && node_min.Y < approx_groundlevel)
2452 //if(myrand() % 100 == 0 && node_min.Y < approx_groundlevel)
2453 //float dungeon_rarity = g_settings.getFloat("dungeon_rarity");
2454 float dungeon_rarity = 0.02;
2455 if(((noise3d(blockpos.X,blockpos.Y,blockpos.Z,data->seed)+1.0)/2.0)
2457 && node_min.Y < approx_groundlevel)
2459 // Dungeon generator doesn't modify places which have this set
2460 vmanip->clearFlag(VMANIP_FLAG_DUNGEON_INSIDE
2461 | VMANIP_FLAG_DUNGEON_PRESERVE);
2463 // Set all air and water to be untouchable to make dungeons open
2464 // to caves and open air
2465 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2466 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2471 // Use fast index incrementing
2472 v3s16 em = vmanip.m_area.getExtent();
2473 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
2474 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
2476 if(vmanip.m_data[i].getContent() == CONTENT_AIR)
2477 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
2478 else if(vmanip.m_data[i].getContent() == c_water_source)
2479 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
2480 vmanip->m_area.add_y(em, i, -1);
2485 PseudoRandom random(blockseed+2);
2488 make_dungeon1(vmanip, random, ndef);
2490 // Convert some cobble to mossy cobble
2491 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
2492 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
2497 // Use fast index incrementing
2498 v3s16 em = vmanip.m_area.getExtent();
2499 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
2500 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
2502 // (noisebuf not used because it doesn't contain the
2504 double wetness = noise3d_param(
2505 get_ground_wetness_params(data->seed), x,y,z);
2506 double d = noise3d_perlin((float)x/2.5,
2507 (float)y/2.5,(float)z/2.5,
2509 if(vmanip.m_data[i].getContent() == c_cobble)
2513 vmanip.m_data[i].setContent(c_mossycobble);
2516 /*else if(vmanip.m_flags[i] & VMANIP_FLAG_DUNGEON_INSIDE)
2519 vmanip.m_data[i].setContent(c_dirt);
2521 vmanip->m_area.add_y(em, i, -1);
2531 PseudoRandom ncrandom(blockseed+9324342);
2532 if(ncrandom.range(0, 1000) == 0 && blockpos.Y <= -3)
2534 make_nc(vmanip, ncrandom, ndef);
2539 Add top and bottom side of water to transforming_liquid queue
2542 for(s16 x=node_min.X; x<=node_max.X; x++)
2543 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2548 bool water_found = false;
2549 // Use fast index incrementing
2550 v3s16 em = vmanip.m_area.getExtent();
2551 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
2552 for(s16 y=node_max.Y; y>=node_min.Y; y--)
2554 if(water_found == false)
2556 if(vmanip.m_data[i].getContent() == c_water_source)
2558 v3s16 p = v3s16(p2d.X, y, p2d.Y);
2559 data->transforming_liquid.push_back(p);
2565 // This can be done because water_found can only
2566 // turn to true and end up here after going through
2568 if(vmanip.m_data[i+1].getContent() != c_water_source)
2570 v3s16 p = v3s16(p2d.X, y+1, p2d.Y);
2571 data->transforming_liquid.push_back(p);
2572 water_found = false;
2576 vmanip->m_area.add_y(em, i, -1);
2582 If close to ground level
2585 //if(abs(approx_ground_depth) < 30)
2586 if(minimum_ground_depth < 5 && maximum_ground_depth > -5)
2592 for(s16 x=node_min.X; x<=node_max.X; x++)
2593 for(s16 z=node_min.Z; z<=node_max.Z; z++)
2598 bool possibly_have_sand = get_have_beach(data->seed, p2d);
2599 bool have_sand = false;
2600 u32 current_depth = 0;
2601 bool air_detected = false;
2602 bool water_detected = false;
2603 bool have_clay = false;
2605 // Use fast index incrementing
2606 s16 start_y = node_max.Y+2;
2607 v3s16 em = vmanip.m_area.getExtent();
2608 u32 i = vmanip.m_area.index(v3s16(p2d.X, start_y, p2d.Y));
2609 for(s16 y=start_y; y>=node_min.Y-3; y--)
2611 if(vmanip.m_data[i].getContent() == c_water_source)
2612 water_detected = true;
2613 if(vmanip.m_data[i].getContent() == CONTENT_AIR)
2614 air_detected = true;
2616 if((vmanip.m_data[i].getContent() == c_stone
2617 || vmanip.m_data[i].getContent() == c_dirt_with_grass
2618 || vmanip.m_data[i].getContent() == c_dirt
2619 || vmanip.m_data[i].getContent() == c_sand
2620 || vmanip.m_data[i].getContent() == c_gravel
2621 ) && (air_detected || water_detected))
2623 if(current_depth == 0 && y <= WATER_LEVEL+2
2624 && possibly_have_sand)
2627 if(current_depth < 4)
2631 vmanip.m_data[i] = MapNode(c_sand);
2634 else if(current_depth==0 && !water_detected
2635 && y >= WATER_LEVEL && air_detected)
2636 vmanip.m_data[i] = MapNode(c_dirt_with_grass);
2639 vmanip.m_data[i] = MapNode(c_dirt);
2643 if(vmanip.m_data[i].getContent() == c_dirt
2644 || vmanip.m_data[i].getContent() == c_dirt_with_grass)
2645 vmanip.m_data[i] = MapNode(c_stone);
2650 if(current_depth >= 8)
2653 else if(current_depth != 0)
2656 vmanip->m_area.add_y(em, i, -1);
2662 Calculate some stuff
2665 float surface_humidity = surface_humidity_2d(data->seed, p2d_center);
2666 bool is_jungle = surface_humidity > 0.75;
2668 u32 tree_count = gen_area_nodes * tree_amount_2d(data->seed, p2d_center);
2675 PseudoRandom treerandom(blockseed);
2676 // Put trees in random places on part of division
2677 for(u32 i=0; i<tree_count; i++)
2679 s16 x = treerandom.range(node_min.X, node_max.X);
2680 s16 z = treerandom.range(node_min.Z, node_max.Z);
2681 //s16 y = find_ground_level(vmanip, v2s16(x,z));
2682 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
2683 // Don't make a tree under water level
2686 // Make sure tree fits (only trees whose starting point is
2687 // at this block are added)
2688 if(y < node_min.Y || y > node_max.Y)
2691 Find exact ground level
2695 for(; p.Y >= y-6; p.Y--)
2697 u32 i = vmanip->m_area.index(p);
2698 MapNode *n = &vmanip->m_data[i];
2699 if(n->getContent() != CONTENT_AIR && n->getContent() != c_water_source && n->getContent() != CONTENT_IGNORE)
2705 // If not found, handle next one
2710 u32 i = vmanip->m_area.index(p);
2711 MapNode *n = &vmanip->m_data[i];
2713 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass && n->getContent() != c_sand)
2716 // Papyrus grows only on mud and in water
2717 if(n->getContent() == c_dirt && y <= WATER_LEVEL)
2720 make_papyrus(vmanip, p, ndef);
2722 // Trees grow only on mud and grass, on land
2723 else if((n->getContent() == c_dirt || n->getContent() == c_dirt_with_grass) && y > WATER_LEVEL + 2)
2726 //if(surface_humidity_2d(data->seed, v2s16(x, y)) < 0.5)
2727 if(is_jungle == false)
2730 if(myrand_range(0,4) != 0)
2731 is_apple_tree = false;
2733 is_apple_tree = noise2d_perlin(
2734 0.5+(float)p.X/100, 0.5+(float)p.Z/100,
2735 data->seed+342902, 3, 0.45) > 0.2;
2736 make_tree(vmanip, p, is_apple_tree, ndef);
2739 make_jungletree(vmanip, p, ndef);
2741 // Cactii grow only on sand, on land
2742 else if(n->getContent() == c_sand && y > WATER_LEVEL + 2)
2745 make_cactus(vmanip, p, ndef);
2755 PseudoRandom grassrandom(blockseed);
2756 for(u32 i=0; i<surface_humidity*5*tree_count; i++)
2758 s16 x = grassrandom.range(node_min.X, node_max.X);
2759 s16 z = grassrandom.range(node_min.Z, node_max.Z);
2760 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
2763 if(y < node_min.Y || y > node_max.Y)
2766 Find exact ground level
2770 for(; p.Y >= y-6; p.Y--)
2772 u32 i = vmanip->m_area.index(p);
2773 MapNode *n = &vmanip->m_data[i];
2774 if(data->nodedef->get(*n).is_ground_content)
2780 // If not found, handle next one
2784 if(vmanip.m_area.contains(p) == false)
2786 if(vmanip.m_data[vmanip.m_area.index(p)].getContent() != CONTENT_AIR)
2789 if(vmanip.m_area.contains(p))
2790 vmanip.m_data[vmanip.m_area.index(p)] = c_dirt;
2792 if(vmanip.m_area.contains(p))
2793 vmanip.m_data[vmanip.m_area.index(p)] = c_junglegrass;
2799 Add some kind of random stones
2802 u32 random_stone_count = gen_area_nodes *
2803 randomstone_amount_2d(data->seed, p2d_center);
2804 // Put in random places on part of division
2805 for(u32 i=0; i<random_stone_count; i++)
2807 s16 x = myrand_range(node_min.X, node_max.X);
2808 s16 z = myrand_range(node_min.Z, node_max.Z);
2809 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
2810 // Don't add under water level
2811 /*if(y < WATER_LEVEL)
2813 // Don't add if doesn't belong to this block
2814 if(y < node_min.Y || y > node_max.Y)
2819 u32 i = vmanip->m_area.index(v3s16(p));
2820 MapNode *n = &vmanip->m_data[i];
2821 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass)
2824 // Will be placed one higher
2827 make_randomstone(vmanip, p);
2836 u32 large_stone_count = gen_area_nodes *
2837 largestone_amount_2d(data->seed, p2d_center);
2838 //u32 large_stone_count = 1;
2839 // Put in random places on part of division
2840 for(u32 i=0; i<large_stone_count; i++)
2842 s16 x = myrand_range(node_min.X, node_max.X);
2843 s16 z = myrand_range(node_min.Z, node_max.Z);
2844 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
2845 // Don't add under water level
2846 /*if(y < WATER_LEVEL)
2848 // Don't add if doesn't belong to this block
2849 if(y < node_min.Y || y > node_max.Y)
2854 u32 i = vmanip->m_area.index(v3s16(p));
2855 MapNode *n = &vmanip->m_data[i];
2856 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass)
2859 // Will be placed one lower
2862 make_largestone(vmanip, p);
2872 PseudoRandom mineralrandom(blockseed);
2877 for(s16 i=0; i<approx_ground_depth/4; i++)
2879 if(mineralrandom.next()%50 == 0)
2881 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2882 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2883 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2884 for(u16 i=0; i<27; i++)
2886 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2887 u32 vi = vmanip.m_area.index(p);
2888 if(vmanip.m_data[vi].getContent() == c_stone)
2889 if(mineralrandom.next()%8 == 0)
2890 vmanip.m_data[vi] = MapNode(c_mese);
2899 u16 a = mineralrandom.range(0,15);
2901 u16 amount = 20 * a/1000;
2902 for(s16 i=0; i<amount; i++)
2904 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2905 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2906 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2908 u8 base_content = c_stone;
2909 MapNode new_content(CONTENT_IGNORE);
2912 if(noisebuf_ground_crumbleness.get(x,y+5,z) < -0.1)
2914 new_content = MapNode(c_stone_with_coal);
2918 if(noisebuf_ground_wetness.get(x,y+5,z) > 0.0)
2919 new_content = MapNode(c_stone_with_iron);
2920 /*if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
2921 vmanip.m_data[i] = MapNode(c_dirt);
2923 vmanip.m_data[i] = MapNode(c_sand);*/
2925 /*else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.1)
2929 if(new_content.getContent() != CONTENT_IGNORE)
2931 for(u16 i=0; i<27; i++)
2933 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2934 u32 vi = vmanip.m_area.index(p);
2935 if(vmanip.m_data[vi].getContent() == base_content)
2937 if(mineralrandom.next()%sparseness == 0)
2938 vmanip.m_data[vi] = new_content;
2947 //for(s16 i=0; i < MYMAX(0, 50 - abs(node_min.Y+8 - (-30))); i++)
2948 //for(s16 i=0; i<50; i++)
2949 u16 coal_amount = 30;
2950 u16 coal_rareness = 60 / coal_amount;
2951 if(coal_rareness == 0)
2953 if(mineralrandom.next()%coal_rareness == 0)
2955 u16 a = mineralrandom.next() % 16;
2956 u16 amount = coal_amount * a*a*a / 1000;
2957 for(s16 i=0; i<amount; i++)
2959 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2960 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2961 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2962 for(u16 i=0; i<27; i++)
2964 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2965 u32 vi = vmanip.m_area.index(p);
2966 if(vmanip.m_data[vi].getContent() == c_stone)
2967 if(mineralrandom.next()%8 == 0)
2968 vmanip.m_data[vi] = MapNode(c_stone_with_coal);
2975 u16 iron_amount = 8;
2976 u16 iron_rareness = 60 / iron_amount;
2977 if(iron_rareness == 0)
2979 if(mineralrandom.next()%iron_rareness == 0)
2981 u16 a = mineralrandom.next() % 16;
2982 u16 amount = iron_amount * a*a*a / 1000;
2983 for(s16 i=0; i<amount; i++)
2985 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2986 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2987 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2988 for(u16 i=0; i<27; i++)
2990 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2991 u32 vi = vmanip.m_area.index(p);
2992 if(vmanip.m_data[vi].getContent() == c_stone)
2993 if(mineralrandom.next()%8 == 0)
2994 vmanip.m_data[vi] = MapNode(c_stone_with_iron);
3005 ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update",
3007 //VoxelArea a(node_min, node_max);
3008 VoxelArea a(node_min-v3s16(1,0,1)*MAP_BLOCKSIZE,
3009 node_max+v3s16(1,0,1)*MAP_BLOCKSIZE);
3010 /*VoxelArea a(node_min-v3s16(1,0,1)*MAP_BLOCKSIZE/2,
3011 node_max+v3s16(1,0,1)*MAP_BLOCKSIZE/2);*/
3012 enum LightBank banks[2] = {LIGHTBANK_DAY, LIGHTBANK_NIGHT};
3013 for(int i=0; i<2; i++)
3015 enum LightBank bank = banks[i];
3017 core::map<v3s16, bool> light_sources;
3018 core::map<v3s16, u8> unlight_from;
3020 voxalgo::clearLightAndCollectSources(vmanip, a, bank, ndef,
3021 light_sources, unlight_from);
3023 bool inexistent_top_provides_sunlight = !block_is_underground;
3024 voxalgo::SunlightPropagateResult res = voxalgo::propagateSunlight(
3025 vmanip, a, inexistent_top_provides_sunlight,
3026 light_sources, ndef);
3027 // TODO: Do stuff according to bottom_sunlight_valid
3029 vmanip.unspreadLight(bank, unlight_from, light_sources, ndef);
3031 vmanip.spreadLight(bank, light_sources, ndef);
3036 #endif ///BIG COMMENT
3038 BlockMakeData::BlockMakeData():
3045 BlockMakeData::~BlockMakeData()
3050 //}; // namespace mapgen