3 Copyright (C) 2010-2013 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
36 #include "mapgen_v6.h"
38 FlagDesc flagdesc_mapgen[] = {
41 {"dungeons", MG_DUNGEONS},
42 {"v6_forests", MGV6_FORESTS},
43 {"v6_biome_blend", MGV6_BIOME_BLEND},
48 ///////////////////////////////////////////////////////////////////////////////
52 bool MapgenV6Params::readParams(Settings *settings) {
53 freq_desert = settings->getFloat("mgv6_freq_desert");
54 freq_beach = settings->getFloat("mgv6_freq_beach");
56 np_terrain_base = settings->getNoiseParams("mgv6_np_terrain_base");
57 np_terrain_higher = settings->getNoiseParams("mgv6_np_terrain_higher");
58 np_steepness = settings->getNoiseParams("mgv6_np_steepness");
59 np_height_select = settings->getNoiseParams("mgv6_np_height_select");
60 np_trees = settings->getNoiseParams("mgv6_np_trees");
61 np_mud = settings->getNoiseParams("mgv6_np_mud");
62 np_beach = settings->getNoiseParams("mgv6_np_beach");
63 np_biome = settings->getNoiseParams("mgv6_np_biome");
64 np_cave = settings->getNoiseParams("mgv6_np_cave");
67 np_terrain_base && np_terrain_higher && np_steepness &&
68 np_height_select && np_trees && np_mud &&
69 np_beach && np_biome && np_cave;
74 void MapgenV6Params::writeParams(Settings *settings) {
75 settings->setFloat("mgv6_freq_desert", freq_desert);
76 settings->setFloat("mgv6_freq_beach", freq_beach);
78 settings->setNoiseParams("mgv6_np_terrain_base", np_terrain_base);
79 settings->setNoiseParams("mgv6_np_terrain_higher", np_terrain_higher);
80 settings->setNoiseParams("mgv6_np_steepness", np_steepness);
81 settings->setNoiseParams("mgv6_np_height_select", np_height_select);
82 settings->setNoiseParams("mgv6_np_trees", np_trees);
83 settings->setNoiseParams("mgv6_np_mud", np_mud);
84 settings->setNoiseParams("mgv6_np_beach", np_beach);
85 settings->setNoiseParams("mgv6_np_biome", np_biome);
86 settings->setNoiseParams("mgv6_np_cave", np_cave);
90 /////////////////////////////////// legacy static functions for farmesh
93 s16 Mapgen::find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision) {
94 //just need to return something
100 bool Mapgen::get_have_beach(u64 seed, v2s16 p2d) {
101 double sandnoise = noise2d_perlin(
102 0.2+(float)p2d.X/250, 0.7+(float)p2d.Y/250,
103 seed+59420, 3, 0.50);
105 return (sandnoise > 0.15);
109 double Mapgen::tree_amount_2d(u64 seed, v2s16 p) {
110 double noise = noise2d_perlin(
111 0.5+(float)p.X/125, 0.5+(float)p.Y/125,
113 double zeroval = -0.39;
117 return 0.04 * (noise-zeroval) / (1.0-zeroval);
121 #if 0 /// BIG COMMENT
126 Some helper functions for the map generator
130 // Returns Y one under area minimum if not found
131 static s16 find_ground_level(VoxelManipulator &vmanip, v2s16 p2d,
132 INodeDefManager *ndef)
134 v3s16 em = vmanip.m_area.getExtent();
135 s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
136 s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
137 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
139 for(y=y_nodes_max; y>=y_nodes_min; y--)
141 MapNode &n = vmanip.m_data[i];
142 if(ndef->get(n).walkable)
145 vmanip.m_area.add_y(em, i, -1);
150 return y_nodes_min - 1;
154 // Returns Y one under area minimum if not found
155 static s16 find_ground_level_clever(VoxelManipulator &vmanip, v2s16 p2d,
156 INodeDefManager *ndef)
158 if(!vmanip.m_area.contains(v3s16(p2d.X, vmanip.m_area.MaxEdge.Y, p2d.Y)))
159 return vmanip.m_area.MinEdge.Y-1;
160 v3s16 em = vmanip.m_area.getExtent();
161 s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
162 s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
163 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
165 content_t c_tree = ndef->getId("mapgen_tree");
166 content_t c_leaves = ndef->getId("mapgen_leaves");
167 for(y=y_nodes_max; y>=y_nodes_min; y--)
169 MapNode &n = vmanip.m_data[i];
170 if(ndef->get(n).walkable
171 && n.getContent() != c_tree
172 && n.getContent() != c_leaves)
175 vmanip.m_area.add_y(em, i, -1);
180 return y_nodes_min - 1;
184 // Returns Y one under area minimum if not found
185 static s16 find_stone_level(VoxelManipulator &vmanip, v2s16 p2d,
186 INodeDefManager *ndef)
188 v3s16 em = vmanip.m_area.getExtent();
189 s16 y_nodes_max = vmanip.m_area.MaxEdge.Y;
190 s16 y_nodes_min = vmanip.m_area.MinEdge.Y;
191 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_nodes_max, p2d.Y));
193 content_t c_stone = ndef->getId("mapgen_stone");
194 content_t c_desert_stone = ndef->getId("mapgen_desert_stone");
195 for(y=y_nodes_max; y>=y_nodes_min; y--)
197 MapNode &n = vmanip.m_data[i];
198 content_t c = n.getContent();
199 if(c != CONTENT_IGNORE && (
200 c == c_stone || c == c_desert_stone))
203 vmanip.m_area.add_y(em, i, -1);
208 return y_nodes_min - 1;
215 static void make_papyrus(VoxelManipulator &vmanip, v3s16 p0,
216 INodeDefManager *ndef)
218 MapNode papyrusnode(ndef->getId("mapgen_papyrus"));
220 s16 trunk_h = myrand_range(2, 3);
222 for(s16 ii=0; ii<trunk_h; ii++)
224 if(vmanip.m_area.contains(p1))
225 vmanip.m_data[vmanip.m_area.index(p1)] = papyrusnode;
230 static void make_cactus(VoxelManipulator &vmanip, v3s16 p0,
231 INodeDefManager *ndef)
233 MapNode cactusnode(ndef->getId("mapgen_cactus"));
237 for(s16 ii=0; ii<trunk_h; ii++)
239 if(vmanip.m_area.contains(p1))
240 vmanip.m_data[vmanip.m_area.index(p1)] = cactusnode;
249 static void make_nc(VoxelManipulator &vmanip, PseudoRandom &random,
250 INodeDefManager *ndef)
254 s32 r = random.range(0, 3);
256 dir = v3s16( 1, 0, 0);
260 dir = v3s16(-1, 0, 0);
264 dir = v3s16( 0, 0, 1);
268 dir = v3s16( 0, 0,-1);
271 v3s16 p = vmanip.m_area.MinEdge + v3s16(
272 16+random.range(0,15),
273 16+random.range(0,15),
274 16+random.range(0,15));
275 vmanip.m_data[vmanip.m_area.index(p)] = MapNode(ndef->getId("mapgen_nyancat"), facedir_i);
276 u32 length = random.range(3,15);
277 for(u32 j=0; j<length; j++)
280 vmanip.m_data[vmanip.m_area.index(p)] = MapNode(ndef->getId("mapgen_nyancat_rainbow"));
286 Noise functions. Make sure seed is mangled differently in each one.
291 Scaling the output of the noise function affects the overdrive of the
292 contour function, which affects the shape of the output considerably.
294 #define CAVE_NOISE_SCALE 12.0
295 //#define CAVE_NOISE_SCALE 10.0
296 //#define CAVE_NOISE_SCALE 7.5
297 //#define CAVE_NOISE_SCALE 5.0
298 //#define CAVE_NOISE_SCALE 1.0
300 //#define CAVE_NOISE_THRESHOLD (2.5/CAVE_NOISE_SCALE)
301 #define CAVE_NOISE_THRESHOLD (1.5/CAVE_NOISE_SCALE)
303 NoiseParams get_cave_noise1_params(u64 seed)
305 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.7,
306 200, CAVE_NOISE_SCALE);*/
307 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.7,
308 100, CAVE_NOISE_SCALE);*/
309 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.6,
310 100, CAVE_NOISE_SCALE);*/
311 /*return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 5, 0.3,
312 100, CAVE_NOISE_SCALE);*/
313 return NoiseParams(NOISE_PERLIN_CONTOUR, seed+52534, 4, 0.5,
314 50, CAVE_NOISE_SCALE);
315 //return NoiseParams(NOISE_CONSTANT_ONE);
318 NoiseParams get_cave_noise2_params(u64 seed)
320 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.7,
321 200, CAVE_NOISE_SCALE);*/
322 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.7,
323 100, CAVE_NOISE_SCALE);*/
324 /*return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 5, 0.3,
325 100, CAVE_NOISE_SCALE);*/
326 return NoiseParams(NOISE_PERLIN_CONTOUR_FLIP_YZ, seed+10325, 4, 0.5,
327 50, CAVE_NOISE_SCALE);
328 //return NoiseParams(NOISE_CONSTANT_ONE);
331 NoiseParams get_ground_noise1_params(u64 seed)
333 return NoiseParams(NOISE_PERLIN, seed+983240, 4,
337 NoiseParams get_ground_crumbleness_params(u64 seed)
339 return NoiseParams(NOISE_PERLIN, seed+34413, 3,
343 NoiseParams get_ground_wetness_params(u64 seed)
345 return NoiseParams(NOISE_PERLIN, seed+32474, 4,
349 bool is_cave(u64 seed, v3s16 p)
351 double d1 = noise3d_param(get_cave_noise1_params(seed), p.X,p.Y,p.Z);
352 double d2 = noise3d_param(get_cave_noise2_params(seed), p.X,p.Y,p.Z);
353 return d1*d2 > CAVE_NOISE_THRESHOLD;
357 Ground density noise shall be interpreted by using this.
359 TODO: No perlin noises here, they should be outsourced
361 NOTE: The speed of these actually isn't terrible
363 bool val_is_ground(double ground_noise1_val, v3s16 p, u64 seed)
365 //return ((double)p.Y < ground_noise1_val);
367 double f = 0.55 + noise2d_perlin(
368 0.5+(float)p.X/250, 0.5+(float)p.Z/250,
369 seed+920381, 3, 0.45);
374 double h = WATER_LEVEL + 10 * noise2d_perlin(
375 0.5+(float)p.X/250, 0.5+(float)p.Z/250,
379 return ((double)p.Y - h < ground_noise1_val * f);
383 Queries whether a position is ground or not.
385 bool is_ground(u64 seed, v3s16 p)
387 double val1 = noise3d_param(get_ground_noise1_params(seed), p.X,p.Y,p.Z);
388 return val_is_ground(val1, p, seed);
392 // Amount of trees per area in nodes
393 double tree_amount_2d(u64 seed, v2s16 p)
395 /*double noise = noise2d_perlin(
396 0.5+(float)p.X/250, 0.5+(float)p.Y/250,
398 double noise = noise2d_perlin(
399 0.5+(float)p.X/125, 0.5+(float)p.Y/125,
401 double zeroval = -0.39;
405 return 0.04 * (noise-zeroval) / (1.0-zeroval);
409 double surface_humidity_2d(u64 seed, v2s16 p)
411 double noise = noise2d_perlin(
412 0.5+(float)p.X/500, 0.5+(float)p.Y/500,
413 seed+72384, 4, 0.66);
414 noise = (noise + 1.0)/2.0;
423 Incrementally find ground level from 3d noise
425 s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision)
427 // Start a bit fuzzy to make averaging lower precision values
429 s16 level = myrand_range(-precision/2, precision/2);
430 s16 dec[] = {31000, 100, 20, 4, 1, 0};
432 for(i = 1; dec[i] != 0 && precision <= dec[i]; i++)
434 // First find non-ground by going upwards
435 // Don't stop in caves.
437 s16 max = level+dec[i-1]*2;
438 v3s16 p(p2d.X, level, p2d.Y);
439 for(; p.Y < max; p.Y += dec[i])
441 if(!is_ground(seed, p))
448 // Then find ground by going downwards from there.
449 // Go in caves, too, when precision is 1.
451 s16 min = level-dec[i-1]*2;
452 v3s16 p(p2d.X, level, p2d.Y);
453 for(; p.Y>min; p.Y-=dec[i])
455 bool ground = is_ground(seed, p);
456 /*if(dec[i] == 1 && is_cave(seed, p))
467 // This is more like the actual ground level
473 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p=4);
475 double get_sector_average_ground_level(u64 seed, v2s16 sectorpos, double p)
477 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
478 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
480 a += find_ground_level_from_noise(seed,
481 v2s16(node_min.X, node_min.Y), p);
482 a += find_ground_level_from_noise(seed,
483 v2s16(node_min.X, node_max.Y), p);
484 a += find_ground_level_from_noise(seed,
485 v2s16(node_max.X, node_max.Y), p);
486 a += find_ground_level_from_noise(seed,
487 v2s16(node_max.X, node_min.Y), p);
488 a += find_ground_level_from_noise(seed,
489 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p);
494 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
496 double get_sector_maximum_ground_level(u64 seed, v2s16 sectorpos, double p)
498 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
499 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
502 a = MYMAX(a, find_ground_level_from_noise(seed,
503 v2s16(node_min.X, node_min.Y), p));
504 a = MYMAX(a, find_ground_level_from_noise(seed,
505 v2s16(node_min.X, node_max.Y), p));
506 a = MYMAX(a, find_ground_level_from_noise(seed,
507 v2s16(node_max.X, node_max.Y), p));
508 a = MYMAX(a, find_ground_level_from_noise(seed,
509 v2s16(node_min.X, node_min.Y), p));
511 a = MYMAX(a, find_ground_level_from_noise(seed,
512 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
513 // Side middle points
514 a = MYMAX(a, find_ground_level_from_noise(seed,
515 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
516 a = MYMAX(a, find_ground_level_from_noise(seed,
517 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
518 a = MYMAX(a, find_ground_level_from_noise(seed,
519 v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
520 a = MYMAX(a, find_ground_level_from_noise(seed,
521 v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
525 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p=4);
527 double get_sector_minimum_ground_level(u64 seed, v2s16 sectorpos, double p)
529 v2s16 node_min = sectorpos*MAP_BLOCKSIZE;
530 v2s16 node_max = (sectorpos+v2s16(1,1))*MAP_BLOCKSIZE-v2s16(1,1);
533 a = MYMIN(a, find_ground_level_from_noise(seed,
534 v2s16(node_min.X, node_min.Y), p));
535 a = MYMIN(a, find_ground_level_from_noise(seed,
536 v2s16(node_min.X, node_max.Y), p));
537 a = MYMIN(a, find_ground_level_from_noise(seed,
538 v2s16(node_max.X, node_max.Y), p));
539 a = MYMIN(a, find_ground_level_from_noise(seed,
540 v2s16(node_min.X, node_min.Y), p));
542 a = MYMIN(a, find_ground_level_from_noise(seed,
543 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y+MAP_BLOCKSIZE/2), p));
544 // Side middle points
545 a = MYMIN(a, find_ground_level_from_noise(seed,
546 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_min.Y), p));
547 a = MYMIN(a, find_ground_level_from_noise(seed,
548 v2s16(node_min.X+MAP_BLOCKSIZE/2, node_max.Y), p));
549 a = MYMIN(a, find_ground_level_from_noise(seed,
550 v2s16(node_min.X, node_min.Y+MAP_BLOCKSIZE/2), p));
551 a = MYMIN(a, find_ground_level_from_noise(seed,
552 v2s16(node_max.X, node_min.Y+MAP_BLOCKSIZE/2), p));
557 // Required by mapgen.h
558 bool block_is_underground(u64 seed, v3s16 blockpos)
560 /*s16 minimum_groundlevel = (s16)get_sector_minimum_ground_level(
561 seed, v2s16(blockpos.X, blockpos.Z));*/
562 // Nah, this is just a heuristic, just return something
563 s16 minimum_groundlevel = WATER_LEVEL;
565 if(blockpos.Y*MAP_BLOCKSIZE + MAP_BLOCKSIZE <= minimum_groundlevel)
571 #define AVERAGE_MUD_AMOUNT 4
573 double base_rock_level_2d(u64 seed, v2s16 p)
575 // The base ground level
576 double base = (double)WATER_LEVEL - (double)AVERAGE_MUD_AMOUNT
577 + 20. * noise2d_perlin(
578 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
581 /*// A bit hillier one
582 double base2 = WATER_LEVEL - 4.0 + 40. * noise2d_perlin(
583 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
584 seed+93413, 6, 0.69);
588 // Higher ground level
589 double higher = (double)WATER_LEVEL + 20. + 16. * noise2d_perlin(
590 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
592 //higher = 30; // For debugging
594 // Limit higher to at least base
598 // Steepness factor of cliffs
599 double b = 0.85 + 0.5 * noise2d_perlin(
600 0.5+(float)p.X/125., 0.5+(float)p.Y/125.,
602 b = rangelim(b, 0.0, 1000.0);
605 b = rangelim(b, 0.5, 1000.0);
606 // Values 1.5...100 give quite horrible looking slopes
607 if(b > 1.5 && b < 100.0){
613 //dstream<<"b="<<b<<std::endl;
617 // Offset to more low
618 double a_off = -0.20;
620 /*double a = 0.5 + b * (a_off + noise2d_perlin(
621 0.5+(float)p.X/500., 0.5+(float)p.Y/500.,
622 seed+4213, 6, 0.7));*/
623 double a = (double)0.5 + b * (a_off + noise2d_perlin(
624 0.5+(float)p.X/250., 0.5+(float)p.Y/250.,
625 seed+4213, 5, 0.69));
627 a = rangelim(a, 0.0, 1.0);
629 //dstream<<"a="<<a<<std::endl;
631 double h = base*(1.0-a) + higher*a;
638 s16 find_ground_level_from_noise(u64 seed, v2s16 p2d, s16 precision)
640 return base_rock_level_2d(seed, p2d) + AVERAGE_MUD_AMOUNT;
643 double get_mud_add_amount(u64 seed, v2s16 p)
645 return ((float)AVERAGE_MUD_AMOUNT + 2.0 * noise2d_perlin(
646 0.5+(float)p.X/200, 0.5+(float)p.Y/200,
647 seed+91013, 3, 0.55));
650 bool get_have_beach(u64 seed, v2s16 p2d)
652 // Determine whether to have sand here
653 double sandnoise = noise2d_perlin(
654 0.2+(float)p2d.X/250, 0.7+(float)p2d.Y/250,
655 seed+59420, 3, 0.50);
657 return (sandnoise > 0.15);
666 BiomeType get_biome(u64 seed, v2s16 p2d)
668 // Just do something very simple as for now
669 double d = noise2d_perlin(
670 0.6+(float)p2d.X/250, 0.2+(float)p2d.Y/250,
674 if(d > 0.35 && (noise2d( p2d.X, p2d.Y, int(seed) ) + 1.0) > ( 0.45 - d ) * 20.0 )
679 u32 get_blockseed(u64 seed, v3s16 p)
681 s32 x=p.X, y=p.Y, z=p.Z;
682 return (u32)(seed%0x100000000ULL) + z*38134234 + y*42123 + x*23;
685 #define VMANIP_FLAG_CAVE VOXELFLAG_CHECKED1
687 void make_block(BlockMakeData *data)
691 //dstream<<"makeBlock: no-op"<<std::endl;
695 assert(data->vmanip);
696 assert(data->nodedef);
697 assert(data->blockpos_requested.X >= data->blockpos_min.X &&
698 data->blockpos_requested.Y >= data->blockpos_min.Y &&
699 data->blockpos_requested.Z >= data->blockpos_min.Z);
700 assert(data->blockpos_requested.X <= data->blockpos_max.X &&
701 data->blockpos_requested.Y <= data->blockpos_max.Y &&
702 data->blockpos_requested.Z <= data->blockpos_max.Z);
704 INodeDefManager *ndef = data->nodedef;
706 // Hack: use minimum block coordinates for old code that assumes
708 v3s16 blockpos = data->blockpos_requested;
710 /*dstream<<"makeBlock(): ("<<blockpos.X<<","<<blockpos.Y<<","
711 <<blockpos.Z<<")"<<std::endl;*/
713 v3s16 blockpos_min = data->blockpos_min;
714 v3s16 blockpos_max = data->blockpos_max;
715 v3s16 blockpos_full_min = blockpos_min - v3s16(1,1,1);
716 v3s16 blockpos_full_max = blockpos_max + v3s16(1,1,1);
718 ManualMapVoxelManipulator &vmanip = *(data->vmanip);
719 // Area of central chunk
720 v3s16 node_min = blockpos_min*MAP_BLOCKSIZE;
721 v3s16 node_max = (blockpos_max+v3s16(1,1,1))*MAP_BLOCKSIZE-v3s16(1,1,1);
722 // Full allocated area
723 v3s16 full_node_min = (blockpos_min-1)*MAP_BLOCKSIZE;
724 v3s16 full_node_max = (blockpos_max+2)*MAP_BLOCKSIZE-v3s16(1,1,1);
726 v3s16 central_area_size = node_max - node_min + v3s16(1,1,1);
728 const s16 max_spread_amount = MAP_BLOCKSIZE;
730 int volume_blocks = (blockpos_max.X - blockpos_min.X + 1)
731 * (blockpos_max.Y - blockpos_min.Y + 1)
732 * (blockpos_max.Z - blockpos_max.Z + 1);
734 int volume_nodes = volume_blocks *
735 MAP_BLOCKSIZE*MAP_BLOCKSIZE*MAP_BLOCKSIZE;
737 // Generated surface area
738 //double gen_area_nodes = MAP_BLOCKSIZE*MAP_BLOCKSIZE * rel_volume;
740 // Horribly wrong heuristic, but better than nothing
741 bool block_is_underground = (WATER_LEVEL > node_max.Y);
744 Create a block-specific seed
746 u32 blockseed = get_blockseed(data->seed, full_node_min);
749 Cache some ground type values for speed
752 // Creates variables c_name=id and n_name=node
753 #define CONTENT_VARIABLE(ndef, name)\
754 content_t c_##name = ndef->getId("mapgen_" #name);\
755 MapNode n_##name(c_##name);
756 // Default to something else if was CONTENT_IGNORE
757 #define CONTENT_VARIABLE_FALLBACK(name, dname)\
758 if(c_##name == CONTENT_IGNORE){\
759 c_##name = c_##dname;\
760 n_##name = n_##dname;\
763 CONTENT_VARIABLE(ndef, stone);
764 CONTENT_VARIABLE(ndef, air);
765 CONTENT_VARIABLE(ndef, water_source);
766 CONTENT_VARIABLE(ndef, dirt);
767 CONTENT_VARIABLE(ndef, sand);
768 CONTENT_VARIABLE(ndef, gravel);
769 CONTENT_VARIABLE(ndef, clay);
770 CONTENT_VARIABLE(ndef, lava_source);
771 CONTENT_VARIABLE(ndef, cobble);
772 CONTENT_VARIABLE(ndef, mossycobble);
773 CONTENT_VARIABLE(ndef, dirt_with_grass);
774 CONTENT_VARIABLE(ndef, junglegrass);
775 CONTENT_VARIABLE(ndef, stone_with_coal);
776 CONTENT_VARIABLE(ndef, stone_with_iron);
777 CONTENT_VARIABLE(ndef, mese);
778 CONTENT_VARIABLE(ndef, desert_sand);
779 CONTENT_VARIABLE_FALLBACK(desert_sand, sand);
780 CONTENT_VARIABLE(ndef, desert_stone);
781 CONTENT_VARIABLE_FALLBACK(desert_stone, stone);
783 // Maximum height of the stone surface and obstacles.
784 // This is used to guide the cave generation
785 s16 stone_surface_max_y = 0;
788 Generate general ground level to full area
792 TimeTaker timer1("Generating ground level");
794 for(s16 x=node_min.X; x<=node_max.X; x++)
795 for(s16 z=node_min.Z; z<=node_max.Z; z++)
798 v2s16 p2d = v2s16(x,z);
801 Skip of already generated
804 v3s16 p(p2d.X, node_min.Y, p2d.Y);
805 if(vmanip.m_data[vmanip.m_area.index(p)].d != CONTENT_AIR)
809 // Ground height at this point
810 float surface_y_f = 0.0;
812 // Use perlin noise for ground height
813 surface_y_f = base_rock_level_2d(data->seed, p2d);
815 /*// Experimental stuff
817 float a = highlands_level_2d(data->seed, p2d);
822 // Convert to integer
823 s16 surface_y = (s16)surface_y_f;
826 if(surface_y > stone_surface_max_y)
827 stone_surface_max_y = surface_y;
829 BiomeType bt = get_biome(data->seed, p2d);
831 Fill ground with stone
834 // Use fast index incrementing
835 v3s16 em = vmanip.m_area.getExtent();
836 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
837 for(s16 y=node_min.Y; y<=node_max.Y; y++)
839 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE){
841 if(y > WATER_LEVEL && bt == BT_DESERT)
842 vmanip.m_data[i] = n_desert_stone;
844 vmanip.m_data[i] = n_stone;
845 } else if(y <= WATER_LEVEL){
846 vmanip.m_data[i] = MapNode(c_water_source);
848 vmanip.m_data[i] = MapNode(c_air);
851 vmanip.m_area.add_y(em, i, 1);
859 // Limit dirt flow area by 1 because mud is flown into neighbors.
860 assert(central_area_size.X == central_area_size.Z);
861 s16 mudflow_minpos = 0-max_spread_amount+1;
862 s16 mudflow_maxpos = central_area_size.X+max_spread_amount-2;
865 Loop this part, it will make stuff look older and newer nicely
868 const u32 age_loops = 2;
869 for(u32 i_age=0; i_age<age_loops; i_age++)
871 /******************************
872 BEGINNING OF AGING LOOP
873 ******************************/
878 //TimeTaker timer1("caves");
881 Make caves (this code is relatively horrible)
883 double cave_amount = 6.0 + 6.0 * noise2d_perlin(
884 0.5+(double)node_min.X/250, 0.5+(double)node_min.Y/250,
885 data->seed+34329, 3, 0.50);
886 cave_amount = MYMAX(0.0, cave_amount);
887 u32 caves_count = cave_amount * volume_nodes / 50000;
888 u32 bruises_count = 1;
889 PseudoRandom ps(blockseed+21343);
890 PseudoRandom ps2(blockseed+1032);
891 if(ps.range(1, 6) == 1)
892 bruises_count = ps.range(0, ps.range(0, 2));
893 if(get_biome(data->seed, v2s16(node_min.X, node_min.Y)) == BT_DESERT){
897 for(u32 jj=0; jj<caves_count+bruises_count; jj++)
899 bool large_cave = (jj >= caves_count);
900 s16 min_tunnel_diameter = 2;
901 s16 max_tunnel_diameter = ps.range(2,6);
902 int dswitchint = ps.range(1,14);
903 u16 tunnel_routepoints = 0;
904 int part_max_length_rs = 0;
906 part_max_length_rs = ps.range(2,4);
907 tunnel_routepoints = ps.range(5, ps.range(15,30));
908 min_tunnel_diameter = 5;
909 max_tunnel_diameter = ps.range(7, ps.range(8,24));
911 part_max_length_rs = ps.range(2,9);
912 tunnel_routepoints = ps.range(10, ps.range(15,30));
914 bool large_cave_is_flat = (ps.range(0,1) == 0);
916 v3f main_direction(0,0,0);
918 // Allowed route area size in nodes
919 v3s16 ar = central_area_size;
921 // Area starting point in nodes
925 //(this should be more than the maximum radius of the tunnel)
926 //s16 insure = 5; // Didn't work with max_d = 20
928 s16 more = max_spread_amount - max_tunnel_diameter/2 - insure;
929 ar += v3s16(1,0,1) * more * 2;
930 of -= v3s16(1,0,1) * more;
933 // Allow half a diameter + 7 over stone surface
934 s16 route_y_max = -of.Y + stone_surface_max_y + max_tunnel_diameter/2 + 7;
936 /*// If caves, don't go through surface too often
937 if(large_cave == false)
938 route_y_max -= ps.range(0, max_tunnel_diameter*2);*/
940 // Limit maximum to area
941 route_y_max = rangelim(route_y_max, 0, ar.Y-1);
945 /*// Minimum is at y=0
946 route_y_min = -of.Y - 0;*/
947 // Minimum is at y=max_tunnel_diameter/4
948 //route_y_min = -of.Y + max_tunnel_diameter/4;
949 //s16 min = -of.Y + max_tunnel_diameter/4;
950 //s16 min = -of.Y + 0;
952 if(node_min.Y < WATER_LEVEL && node_max.Y > WATER_LEVEL)
954 min = WATER_LEVEL - max_tunnel_diameter/3 - of.Y;
955 route_y_max = WATER_LEVEL + max_tunnel_diameter/3 - of.Y;
957 route_y_min = ps.range(min, min + max_tunnel_diameter);
958 route_y_min = rangelim(route_y_min, 0, route_y_max);
961 /*dstream<<"route_y_min = "<<route_y_min
962 <<", route_y_max = "<<route_y_max<<std::endl;*/
964 s16 route_start_y_min = route_y_min;
965 s16 route_start_y_max = route_y_max;
967 // Start every 4th cave from surface when applicable
968 /*bool coming_from_surface = false;
969 if(node_min.Y <= 0 && node_max.Y >= 0){
970 coming_from_surface = (jj % 4 == 0 && large_cave == false);
971 if(coming_from_surface)
972 route_start_y_min = -of.Y + stone_surface_max_y + 10;
975 route_start_y_min = rangelim(route_start_y_min, 0, ar.Y-1);
976 route_start_y_max = rangelim(route_start_y_max, route_start_y_min, ar.Y-1);
978 // Randomize starting position
980 (float)(ps.next()%ar.X)+0.5,
981 (float)(ps.range(route_start_y_min, route_start_y_max))+0.5,
982 (float)(ps.next()%ar.Z)+0.5
985 v3s16 startp(orp.X, orp.Y, orp.Z);
988 MapNode airnode(CONTENT_AIR);
989 MapNode waternode(c_water_source);
990 MapNode lavanode(c_lava_source);
993 Generate some tunnel starting from orp
996 for(u16 j=0; j<tunnel_routepoints; j++)
998 if(j%dswitchint==0 && large_cave == false)
1000 main_direction = v3f(
1001 ((float)(ps.next()%20)-(float)10)/10,
1002 ((float)(ps.next()%20)-(float)10)/30,
1003 ((float)(ps.next()%20)-(float)10)/10
1005 main_direction *= (float)ps.range(0, 10)/10;
1009 s16 min_d = min_tunnel_diameter;
1010 s16 max_d = max_tunnel_diameter;
1011 s16 rs = ps.range(min_d, max_d);
1013 // Every second section is rough
1014 bool randomize_xz = (ps2.range(1,2) == 1);
1020 rs*part_max_length_rs,
1021 rs*part_max_length_rs/2,
1022 rs*part_max_length_rs
1028 rs*part_max_length_rs,
1029 ps.range(1, rs*part_max_length_rs),
1030 rs*part_max_length_rs
1037 (float)(ps.next()%(maxlen.X*1))-(float)maxlen.X/2,
1038 (float)(ps.next()%(maxlen.Y*1))-(float)maxlen.Y/2,
1039 (float)(ps.next()%(maxlen.Z*1))-(float)maxlen.Z/2
1042 // Jump downward sometimes
1043 if(!large_cave && ps.range(0,12) == 0)
1046 (float)(ps.next()%(maxlen.X*1))-(float)maxlen.X/2,
1047 (float)(ps.next()%(maxlen.Y*2))-(float)maxlen.Y*2/2,
1048 (float)(ps.next()%(maxlen.Z*1))-(float)maxlen.Z/2
1054 s16 h = find_ground_level_clever(vmanip,
1055 v2s16(p.X, p.Z), ndef);
1056 route_y_min = h - rs/3;
1057 route_y_max = h + rs;
1060 vec += main_direction;
1065 else if(rp.X >= ar.X)
1067 if(rp.Y < route_y_min)
1069 else if(rp.Y >= route_y_max)
1070 rp.Y = route_y_max-1;
1073 else if(rp.Z >= ar.Z)
1077 for(float f=0; f<1.0; f+=1.0/vec.getLength())
1079 v3f fp = orp + vec * f;
1080 fp.X += 0.1*ps.range(-10,10);
1081 fp.Z += 0.1*ps.range(-10,10);
1082 v3s16 cp(fp.X, fp.Y, fp.Z);
1087 d0 += ps.range(-1,1);
1088 d1 += ps.range(-1,1);
1090 for(s16 z0=d0; z0<=d1; z0++)
1092 s16 si = rs/2 - MYMAX(0, abs(z0)-rs/7-1);
1093 for(s16 x0=-si-ps.range(0,1); x0<=si-1+ps.range(0,1); x0++)
1095 s16 maxabsxz = MYMAX(abs(x0), abs(z0));
1096 s16 si2 = rs/2 - MYMAX(0, maxabsxz-rs/7-1);
1097 for(s16 y0=-si2; y0<=si2; y0++)
1099 /*// Make better floors in small caves
1100 if(y0 <= -rs/2 && rs<=7)
1102 if(large_cave_is_flat){
1103 // Make large caves not so tall
1104 if(rs > 7 && abs(y0) >= rs/3)
1114 if(vmanip.m_area.contains(p) == false)
1117 u32 i = vmanip.m_area.index(p);
1121 if(full_node_min.Y < WATER_LEVEL &&
1122 full_node_max.Y > WATER_LEVEL){
1123 if(p.Y <= WATER_LEVEL)
1124 vmanip.m_data[i] = waternode;
1126 vmanip.m_data[i] = airnode;
1127 } else if(full_node_max.Y < WATER_LEVEL){
1128 if(p.Y < startp.Y - 2)
1129 vmanip.m_data[i] = lavanode;
1131 vmanip.m_data[i] = airnode;
1133 vmanip.m_data[i] = airnode;
1136 // Don't replace air or water or lava or ignore
1137 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE ||
1138 vmanip.m_data[i].getContent() == CONTENT_AIR ||
1139 vmanip.m_data[i].getContent() == c_water_source ||
1140 vmanip.m_data[i].getContent() == c_lava_source)
1143 vmanip.m_data[i] = airnode;
1146 vmanip.m_flags[i] |= VMANIP_FLAG_CAVE;
1164 TimeTaker timer1("add mud");
1167 Add mud to the central chunk
1170 for(s16 x=node_min.X; x<=node_max.X; x++)
1171 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1173 // Node position in 2d
1174 v2s16 p2d = v2s16(x,z);
1176 // Randomize mud amount
1177 s16 mud_add_amount = get_mud_add_amount(data->seed, p2d) / 2.0 + 0.5;
1179 // Find ground level
1180 s16 surface_y = find_stone_level(vmanip, p2d, ndef);
1181 // Handle area not found
1182 if(surface_y == vmanip.m_area.MinEdge.Y - 1)
1185 MapNode addnode(c_dirt);
1186 BiomeType bt = get_biome(data->seed, p2d);
1189 addnode = MapNode(c_desert_sand);
1191 if(bt == BT_DESERT && surface_y + mud_add_amount <= WATER_LEVEL+1){
1192 addnode = MapNode(c_sand);
1193 } else if(mud_add_amount <= 0){
1194 mud_add_amount = 1 - mud_add_amount;
1195 addnode = MapNode(c_gravel);
1196 } else if(bt == BT_NORMAL && get_have_beach(data->seed, p2d) &&
1197 surface_y + mud_add_amount <= WATER_LEVEL+2){
1198 addnode = MapNode(c_sand);
1201 if(bt == BT_DESERT){
1203 mud_add_amount = MYMAX(0, mud_add_amount - (surface_y - 20)/5);
1208 If topmost node is grass, change it to mud.
1209 It might be if it was flown to there from a neighboring
1210 chunk and then converted.
1213 u32 i = vmanip.m_area.index(v3s16(p2d.X, surface_y, p2d.Y));
1214 MapNode *n = &vmanip.m_data[i];
1215 if(n->getContent() == c_dirt_with_grass)
1216 *n = MapNode(c_dirt);
1224 v3s16 em = vmanip.m_area.getExtent();
1225 s16 y_start = surface_y+1;
1226 u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
1227 for(s16 y=y_start; y<=node_max.Y; y++)
1229 if(mudcount >= mud_add_amount)
1232 MapNode &n = vmanip.m_data[i];
1236 vmanip.m_area.add_y(em, i, 1);
1246 Add blobs of dirt and gravel underground
1248 if(get_biome(data->seed, v2s16(node_min.X, node_min.Y)) == BT_NORMAL)
1250 PseudoRandom pr(blockseed+983);
1251 for(int i=0; i<volume_nodes/10/10/10; i++)
1253 bool only_fill_cave = (myrand_range(0,1) != 0);
1260 pr.range(node_min.X, node_max.X)-size.X/2,
1261 pr.range(node_min.Y, node_max.Y)-size.Y/2,
1262 pr.range(node_min.Z, node_max.Z)-size.Z/2
1265 if(p0.Y > -32 && pr.range(0,1) == 0)
1266 n1 = MapNode(c_dirt);
1268 n1 = MapNode(c_gravel);
1269 for(int x1=0; x1<size.X; x1++)
1270 for(int y1=0; y1<size.Y; y1++)
1271 for(int z1=0; z1<size.Z; z1++)
1273 v3s16 p = p0 + v3s16(x1,y1,z1);
1274 u32 i = vmanip.m_area.index(p);
1275 if(!vmanip.m_area.contains(i))
1277 // Cancel if not stone and not cave air
1278 if(vmanip.m_data[i].getContent() != c_stone &&
1279 !(vmanip.m_flags[i] & VMANIP_FLAG_CAVE))
1281 if(only_fill_cave && !(vmanip.m_flags[i] & VMANIP_FLAG_CAVE))
1283 vmanip.m_data[i] = n1;
1291 TimeTaker timer1("flow mud");
1294 Flow mud away from steep edges
1297 // Iterate a few times
1298 for(s16 k=0; k<3; k++)
1301 for(s16 x=mudflow_minpos; x<=mudflow_maxpos; x++)
1302 for(s16 z=mudflow_minpos; z<=mudflow_maxpos; z++)
1304 // Invert coordinates every 2nd iteration
1307 x = mudflow_maxpos - (x-mudflow_minpos);
1308 z = mudflow_maxpos - (z-mudflow_minpos);
1311 // Node position in 2d
1312 v2s16 p2d = v2s16(node_min.X, node_min.Z) + v2s16(x,z);
1314 v3s16 em = vmanip.m_area.getExtent();
1315 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
1318 while(y >= node_min.Y)
1325 for(; y>=node_min.Y; y--)
1327 n = &vmanip.m_data[i];
1328 //if(content_walkable(n->d))
1330 if(n->getContent() == c_dirt ||
1331 n->getContent() == c_dirt_with_grass ||
1332 n->getContent() == c_gravel)
1335 vmanip.m_area.add_y(em, i, -1);
1338 // Stop if out of area
1339 //if(vmanip.m_area.contains(i) == false)
1343 /*// If not mud, do nothing to it
1344 MapNode *n = &vmanip.m_data[i];
1345 if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS)
1348 if(n->getContent() == c_dirt ||
1349 n->getContent() == c_dirt_with_grass)
1351 // Make it exactly mud
1352 n->setContent(c_dirt);
1355 Don't flow it if the stuff under it is not mud
1359 vmanip.m_area.add_y(em, i2, -1);
1360 // Cancel if out of area
1361 if(vmanip.m_area.contains(i2) == false)
1363 MapNode *n2 = &vmanip.m_data[i2];
1364 if(n2->getContent() != c_dirt &&
1365 n2->getContent() != c_dirt_with_grass)
1370 /*s16 recurse_count = 0;
1374 v3s16(0,0,1), // back
1375 v3s16(1,0,0), // right
1376 v3s16(0,0,-1), // front
1377 v3s16(-1,0,0), // left
1380 // Theck that upper is air or doesn't exist.
1381 // Cancel dropping if upper keeps it in place
1383 vmanip.m_area.add_y(em, i3, 1);
1384 if(vmanip.m_area.contains(i3) == true
1385 && ndef->get(vmanip.m_data[i3]).walkable)
1392 for(u32 di=0; di<4; di++)
1394 v3s16 dirp = dirs4[di];
1397 vmanip.m_area.add_p(em, i2, dirp);
1398 // Fail if out of area
1399 if(vmanip.m_area.contains(i2) == false)
1401 // Check that side is air
1402 MapNode *n2 = &vmanip.m_data[i2];
1403 if(ndef->get(*n2).walkable)
1405 // Check that under side is air
1406 vmanip.m_area.add_y(em, i2, -1);
1407 if(vmanip.m_area.contains(i2) == false)
1409 n2 = &vmanip.m_data[i2];
1410 if(ndef->get(*n2).walkable)
1412 /*// Check that under that is air (need a drop of 2)
1413 vmanip.m_area.add_y(em, i2, -1);
1414 if(vmanip.m_area.contains(i2) == false)
1416 n2 = &vmanip.m_data[i2];
1417 if(content_walkable(n2->d))
1419 // Loop further down until not air
1420 bool dropped_to_unknown = false;
1422 vmanip.m_area.add_y(em, i2, -1);
1423 n2 = &vmanip.m_data[i2];
1424 // if out of known area
1425 if(vmanip.m_area.contains(i2) == false
1426 || n2->getContent() == CONTENT_IGNORE){
1427 dropped_to_unknown = true;
1430 }while(ndef->get(*n2).walkable == false);
1431 // Loop one up so that we're in air
1432 vmanip.m_area.add_y(em, i2, 1);
1433 n2 = &vmanip.m_data[i2];
1435 bool old_is_water = (n->getContent() == c_water_source);
1436 // Move mud to new place
1437 if(!dropped_to_unknown) {
1439 // Set old place to be air (or water)
1441 *n = MapNode(c_water_source);
1443 *n = MapNode(CONTENT_AIR);
1459 /***********************
1461 ************************/
1464 Add top and bottom side of water to transforming_liquid queue
1467 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
1468 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
1473 bool water_found = false;
1474 // Use fast index incrementing
1475 v3s16 em = vmanip.m_area.getExtent();
1476 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
1477 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
1479 if(y == full_node_max.Y){
1481 (vmanip.m_data[i].getContent() == c_water_source ||
1482 vmanip.m_data[i].getContent() == c_lava_source);
1484 else if(water_found == false)
1486 if(vmanip.m_data[i].getContent() == c_water_source ||
1487 vmanip.m_data[i].getContent() == c_lava_source)
1489 v3s16 p = v3s16(p2d.X, y, p2d.Y);
1490 data->transforming_liquid.push_back(p);
1496 // This can be done because water_found can only
1497 // turn to true and end up here after going through
1499 if(vmanip.m_data[i+1].getContent() != c_water_source ||
1500 vmanip.m_data[i+1].getContent() != c_lava_source)
1502 v3s16 p = v3s16(p2d.X, y+1, p2d.Y);
1503 data->transforming_liquid.push_back(p);
1504 water_found = false;
1508 vmanip.m_area.add_y(em, i, -1);
1517 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
1518 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
1520 // Node position in 2d
1521 v2s16 p2d = v2s16(x,z);
1524 Find the lowest surface to which enough light ends up
1527 Basically just wait until not air and not leaves.
1531 v3s16 em = vmanip.m_area.getExtent();
1532 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
1534 // Go to ground level
1535 for(y=node_max.Y; y>=full_node_min.Y; y--)
1537 MapNode &n = vmanip.m_data[i];
1538 if(ndef->get(n).param_type != CPT_LIGHT
1539 || ndef->get(n).liquid_type != LIQUID_NONE)
1541 vmanip.m_area.add_y(em, i, -1);
1543 if(y >= full_node_min.Y)
1546 surface_y = full_node_min.Y;
1549 u32 i = vmanip.m_area.index(p2d.X, surface_y, p2d.Y);
1550 MapNode *n = &vmanip.m_data[i];
1551 if(n->getContent() == c_dirt){
1552 // Well yeah, this can't be overground...
1553 if(surface_y < WATER_LEVEL - 20)
1555 n->setContent(c_dirt_with_grass);
1562 assert(central_area_size.X == central_area_size.Z);
1564 PseudoRandom ps (blockseed);
1565 // Divide area into parts
1567 s16 sidelen = central_area_size.X / div;
1568 double area = sidelen * sidelen;
1569 for(s16 x0=0; x0<div; x0++)
1570 for(s16 z0=0; z0<div; z0++)
1572 // Center position of part of division
1574 node_min.X + sidelen/2 + sidelen*x0,
1575 node_min.Z + sidelen/2 + sidelen*z0
1577 // Minimum edge of part of division
1579 node_min.X + sidelen*x0,
1580 node_min.Z + sidelen*z0
1582 // Maximum edge of part of division
1584 node_min.X + sidelen + sidelen*x0 - 1,
1585 node_min.Z + sidelen + sidelen*z0 - 1
1588 u32 tree_count = area * tree_amount_2d(data->seed, p2d_center);
1589 // Put trees in random places on part of division
1590 for(u32 i=0; i<tree_count; i++)
1592 s16 x = ps.range(p2d_min.X, p2d_max.X);
1593 s16 z = ps.range(p2d_min.Y, p2d_max.Y);
1594 s16 y = find_ground_level(vmanip, v2s16(x,z), ndef);
1595 // Don't make a tree under water level
1598 // Don't make a tree so high that it doesn't fit
1599 if(y > node_max.Y - 6)
1603 Trees grow only on mud and grass
1606 u32 i = vmanip.m_area.index(v3s16(p));
1607 MapNode *n = &vmanip.m_data[i];
1608 if(n->getContent() != c_dirt
1609 && n->getContent() != c_dirt_with_grass)
1614 treegen::make_tree(vmanip, p, false, ndef, ps.next());
1621 Make base ground level
1624 for(s16 x=node_min.X; x<=node_max.X; x++)
1625 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1630 // Use fast index incrementing
1631 v3s16 em = vmanip.m_area.getExtent();
1632 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_min.Y, p2d.Y));
1633 for(s16 y=node_min.Y; y<=node_max.Y; y++)
1635 // Only modify places that have no content
1636 if(vmanip.m_data[i].getContent() == CONTENT_IGNORE)
1638 // First priority: make air and water.
1639 // This avoids caves inside water.
1640 if(all_is_ground_except_caves == false
1641 && val_is_ground(noisebuf_ground.get(x,y,z),
1642 v3s16(x,y,z), data->seed) == false)
1644 if(y <= WATER_LEVEL)
1645 vmanip.m_data[i] = n_water_source;
1647 vmanip.m_data[i] = n_air;
1649 else if(noisebuf_cave.get(x,y,z) > CAVE_NOISE_THRESHOLD)
1650 vmanip.m_data[i] = n_air;
1652 vmanip.m_data[i] = n_stone;
1655 vmanip->m_area.add_y(em, i, 1);
1661 Add mud and sand and others underground (in place of stone)
1664 for(s16 x=node_min.X; x<=node_max.X; x++)
1665 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1670 // Use fast index incrementing
1671 v3s16 em = vmanip.m_area.getExtent();
1672 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
1673 for(s16 y=node_max.Y; y>=node_min.Y; y--)
1675 if(vmanip.m_data[i].getContent() == c_stone)
1677 if(noisebuf_ground_crumbleness.get(x,y,z) > 1.3)
1679 if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
1680 vmanip.m_data[i] = n_dirt;
1682 vmanip.m_data[i] = n_sand;
1684 else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.7)
1686 if(noisebuf_ground_wetness.get(x,y,z) < -0.6)
1687 vmanip.m_data[i] = n_gravel;
1689 else if(noisebuf_ground_crumbleness.get(x,y,z) <
1690 -3.0 + MYMIN(0.1 * sqrt((float)MYMAX(0, -y)), 1.5))
1692 vmanip.m_data[i] = n_lava_source;
1693 for(s16 x1=-1; x1<=1; x1++)
1694 for(s16 y1=-1; y1<=1; y1++)
1695 for(s16 z1=-1; z1<=1; z1++)
1696 data->transforming_liquid.push_back(
1697 v3s16(p2d.X+x1, y+y1, p2d.Y+z1));
1701 vmanip->m_area.add_y(em, i, -1);
1710 //if(node_min.Y < approx_groundlevel)
1711 //if(myrand() % 3 == 0)
1712 //if(myrand() % 3 == 0 && node_min.Y < approx_groundlevel)
1713 //if(myrand() % 100 == 0 && node_min.Y < approx_groundlevel)
1714 //float dungeon_rarity = g_settings.getFloat("dungeon_rarity");
1715 float dungeon_rarity = 0.02;
1716 if(((noise3d(blockpos.X,blockpos.Y,blockpos.Z,data->seed)+1.0)/2.0)
1718 && node_min.Y < approx_groundlevel)
1720 // Dungeon generator doesn't modify places which have this set
1721 vmanip->clearFlag(VMANIP_FLAG_DUNGEON_INSIDE
1722 | VMANIP_FLAG_DUNGEON_PRESERVE);
1724 // Set all air and water to be untouchable to make dungeons open
1725 // to caves and open air
1726 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
1727 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
1732 // Use fast index incrementing
1733 v3s16 em = vmanip.m_area.getExtent();
1734 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
1735 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
1737 if(vmanip.m_data[i].getContent() == CONTENT_AIR)
1738 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
1739 else if(vmanip.m_data[i].getContent() == c_water_source)
1740 vmanip.m_flags[i] |= VMANIP_FLAG_DUNGEON_PRESERVE;
1741 vmanip->m_area.add_y(em, i, -1);
1746 PseudoRandom random(blockseed+2);
1749 make_dungeon1(vmanip, random, ndef);
1751 // Convert some cobble to mossy cobble
1752 for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
1753 for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
1758 // Use fast index incrementing
1759 v3s16 em = vmanip.m_area.getExtent();
1760 u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
1761 for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
1763 // (noisebuf not used because it doesn't contain the
1765 double wetness = noise3d_param(
1766 get_ground_wetness_params(data->seed), x,y,z);
1767 double d = noise3d_perlin((float)x/2.5,
1768 (float)y/2.5,(float)z/2.5,
1770 if(vmanip.m_data[i].getContent() == c_cobble)
1774 vmanip.m_data[i].setContent(c_mossycobble);
1777 /*else if(vmanip.m_flags[i] & VMANIP_FLAG_DUNGEON_INSIDE)
1780 vmanip.m_data[i].setContent(c_dirt);
1782 vmanip->m_area.add_y(em, i, -1);
1792 PseudoRandom ncrandom(blockseed+9324342);
1793 if(ncrandom.range(0, 1000) == 0 && blockpos.Y <= -3)
1795 make_nc(vmanip, ncrandom, ndef);
1800 Add top and bottom side of water to transforming_liquid queue
1803 for(s16 x=node_min.X; x<=node_max.X; x++)
1804 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1809 bool water_found = false;
1810 // Use fast index incrementing
1811 v3s16 em = vmanip.m_area.getExtent();
1812 u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
1813 for(s16 y=node_max.Y; y>=node_min.Y; y--)
1815 if(water_found == false)
1817 if(vmanip.m_data[i].getContent() == c_water_source)
1819 v3s16 p = v3s16(p2d.X, y, p2d.Y);
1820 data->transforming_liquid.push_back(p);
1826 // This can be done because water_found can only
1827 // turn to true and end up here after going through
1829 if(vmanip.m_data[i+1].getContent() != c_water_source)
1831 v3s16 p = v3s16(p2d.X, y+1, p2d.Y);
1832 data->transforming_liquid.push_back(p);
1833 water_found = false;
1837 vmanip->m_area.add_y(em, i, -1);
1843 If close to ground level
1846 //if(abs(approx_ground_depth) < 30)
1847 if(minimum_ground_depth < 5 && maximum_ground_depth > -5)
1853 for(s16 x=node_min.X; x<=node_max.X; x++)
1854 for(s16 z=node_min.Z; z<=node_max.Z; z++)
1859 bool possibly_have_sand = get_have_beach(data->seed, p2d);
1860 bool have_sand = false;
1861 u32 current_depth = 0;
1862 bool air_detected = false;
1863 bool water_detected = false;
1864 bool have_clay = false;
1866 // Use fast index incrementing
1867 s16 start_y = node_max.Y+2;
1868 v3s16 em = vmanip.m_area.getExtent();
1869 u32 i = vmanip.m_area.index(v3s16(p2d.X, start_y, p2d.Y));
1870 for(s16 y=start_y; y>=node_min.Y-3; y--)
1872 if(vmanip.m_data[i].getContent() == c_water_source)
1873 water_detected = true;
1874 if(vmanip.m_data[i].getContent() == CONTENT_AIR)
1875 air_detected = true;
1877 if((vmanip.m_data[i].getContent() == c_stone
1878 || vmanip.m_data[i].getContent() == c_dirt_with_grass
1879 || vmanip.m_data[i].getContent() == c_dirt
1880 || vmanip.m_data[i].getContent() == c_sand
1881 || vmanip.m_data[i].getContent() == c_gravel
1882 ) && (air_detected || water_detected))
1884 if(current_depth == 0 && y <= WATER_LEVEL+2
1885 && possibly_have_sand)
1888 if(current_depth < 4)
1892 vmanip.m_data[i] = MapNode(c_sand);
1895 else if(current_depth==0 && !water_detected
1896 && y >= WATER_LEVEL && air_detected)
1897 vmanip.m_data[i] = MapNode(c_dirt_with_grass);
1900 vmanip.m_data[i] = MapNode(c_dirt);
1904 if(vmanip.m_data[i].getContent() == c_dirt
1905 || vmanip.m_data[i].getContent() == c_dirt_with_grass)
1906 vmanip.m_data[i] = MapNode(c_stone);
1911 if(current_depth >= 8)
1914 else if(current_depth != 0)
1917 vmanip->m_area.add_y(em, i, -1);
1923 Calculate some stuff
1926 float surface_humidity = surface_humidity_2d(data->seed, p2d_center);
1927 bool is_jungle = surface_humidity > 0.75;
1929 u32 tree_count = gen_area_nodes * tree_amount_2d(data->seed, p2d_center);
1936 PseudoRandom treerandom(blockseed);
1937 // Put trees in random places on part of division
1938 for(u32 i=0; i<tree_count; i++)
1940 s16 x = treerandom.range(node_min.X, node_max.X);
1941 s16 z = treerandom.range(node_min.Z, node_max.Z);
1942 //s16 y = find_ground_level(vmanip, v2s16(x,z));
1943 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
1944 // Don't make a tree under water level
1947 // Make sure tree fits (only trees whose starting point is
1948 // at this block are added)
1949 if(y < node_min.Y || y > node_max.Y)
1952 Find exact ground level
1956 for(; p.Y >= y-6; p.Y--)
1958 u32 i = vmanip->m_area.index(p);
1959 MapNode *n = &vmanip->m_data[i];
1960 if(n->getContent() != CONTENT_AIR && n->getContent() != c_water_source && n->getContent() != CONTENT_IGNORE)
1966 // If not found, handle next one
1971 u32 i = vmanip->m_area.index(p);
1972 MapNode *n = &vmanip->m_data[i];
1974 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass && n->getContent() != c_sand)
1977 // Papyrus grows only on mud and in water
1978 if(n->getContent() == c_dirt && y <= WATER_LEVEL)
1981 make_papyrus(vmanip, p, ndef);
1983 // Trees grow only on mud and grass, on land
1984 else if((n->getContent() == c_dirt || n->getContent() == c_dirt_with_grass) && y > WATER_LEVEL + 2)
1987 //if(surface_humidity_2d(data->seed, v2s16(x, y)) < 0.5)
1988 if(is_jungle == false)
1991 if(myrand_range(0,4) != 0)
1992 is_apple_tree = false;
1994 is_apple_tree = noise2d_perlin(
1995 0.5+(float)p.X/100, 0.5+(float)p.Z/100,
1996 data->seed+342902, 3, 0.45) > 0.2;
1997 make_tree(vmanip, p, is_apple_tree, ndef);
2000 make_jungletree(vmanip, p, ndef);
2002 // Cactii grow only on sand, on land
2003 else if(n->getContent() == c_sand && y > WATER_LEVEL + 2)
2006 make_cactus(vmanip, p, ndef);
2016 PseudoRandom grassrandom(blockseed);
2017 for(u32 i=0; i<surface_humidity*5*tree_count; i++)
2019 s16 x = grassrandom.range(node_min.X, node_max.X);
2020 s16 z = grassrandom.range(node_min.Z, node_max.Z);
2021 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 4);
2024 if(y < node_min.Y || y > node_max.Y)
2027 Find exact ground level
2031 for(; p.Y >= y-6; p.Y--)
2033 u32 i = vmanip->m_area.index(p);
2034 MapNode *n = &vmanip->m_data[i];
2035 if(data->nodedef->get(*n).is_ground_content)
2041 // If not found, handle next one
2045 if(vmanip.m_area.contains(p) == false)
2047 if(vmanip.m_data[vmanip.m_area.index(p)].getContent() != CONTENT_AIR)
2050 if(vmanip.m_area.contains(p))
2051 vmanip.m_data[vmanip.m_area.index(p)] = c_dirt;
2053 if(vmanip.m_area.contains(p))
2054 vmanip.m_data[vmanip.m_area.index(p)] = c_junglegrass;
2060 Add some kind of random stones
2063 u32 random_stone_count = gen_area_nodes *
2064 randomstone_amount_2d(data->seed, p2d_center);
2065 // Put in random places on part of division
2066 for(u32 i=0; i<random_stone_count; i++)
2068 s16 x = myrand_range(node_min.X, node_max.X);
2069 s16 z = myrand_range(node_min.Z, node_max.Z);
2070 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
2071 // Don't add under water level
2072 /*if(y < WATER_LEVEL)
2074 // Don't add if doesn't belong to this block
2075 if(y < node_min.Y || y > node_max.Y)
2080 u32 i = vmanip->m_area.index(v3s16(p));
2081 MapNode *n = &vmanip->m_data[i];
2082 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass)
2085 // Will be placed one higher
2088 make_randomstone(vmanip, p);
2097 u32 large_stone_count = gen_area_nodes *
2098 largestone_amount_2d(data->seed, p2d_center);
2099 //u32 large_stone_count = 1;
2100 // Put in random places on part of division
2101 for(u32 i=0; i<large_stone_count; i++)
2103 s16 x = myrand_range(node_min.X, node_max.X);
2104 s16 z = myrand_range(node_min.Z, node_max.Z);
2105 s16 y = find_ground_level_from_noise(data->seed, v2s16(x,z), 1);
2106 // Don't add under water level
2107 /*if(y < WATER_LEVEL)
2109 // Don't add if doesn't belong to this block
2110 if(y < node_min.Y || y > node_max.Y)
2115 u32 i = vmanip->m_area.index(v3s16(p));
2116 MapNode *n = &vmanip->m_data[i];
2117 if(n->getContent() != c_dirt && n->getContent() != c_dirt_with_grass)
2120 // Will be placed one lower
2123 make_largestone(vmanip, p);
2133 PseudoRandom mineralrandom(blockseed);
2138 for(s16 i=0; i<approx_ground_depth/4; i++)
2140 if(mineralrandom.next()%50 == 0)
2142 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2143 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2144 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2145 for(u16 i=0; i<27; i++)
2147 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2148 u32 vi = vmanip.m_area.index(p);
2149 if(vmanip.m_data[vi].getContent() == c_stone)
2150 if(mineralrandom.next()%8 == 0)
2151 vmanip.m_data[vi] = MapNode(c_mese);
2160 u16 a = mineralrandom.range(0,15);
2162 u16 amount = 20 * a/1000;
2163 for(s16 i=0; i<amount; i++)
2165 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2166 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2167 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2169 u8 base_content = c_stone;
2170 MapNode new_content(CONTENT_IGNORE);
2173 if(noisebuf_ground_crumbleness.get(x,y+5,z) < -0.1)
2175 new_content = MapNode(c_stone_with_coal);
2179 if(noisebuf_ground_wetness.get(x,y+5,z) > 0.0)
2180 new_content = MapNode(c_stone_with_iron);
2181 /*if(noisebuf_ground_wetness.get(x,y,z) > 0.0)
2182 vmanip.m_data[i] = MapNode(c_dirt);
2184 vmanip.m_data[i] = MapNode(c_sand);*/
2186 /*else if(noisebuf_ground_crumbleness.get(x,y,z) > 0.1)
2190 if(new_content.getContent() != CONTENT_IGNORE)
2192 for(u16 i=0; i<27; i++)
2194 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2195 u32 vi = vmanip.m_area.index(p);
2196 if(vmanip.m_data[vi].getContent() == base_content)
2198 if(mineralrandom.next()%sparseness == 0)
2199 vmanip.m_data[vi] = new_content;
2208 //for(s16 i=0; i < MYMAX(0, 50 - abs(node_min.Y+8 - (-30))); i++)
2209 //for(s16 i=0; i<50; i++)
2210 u16 coal_amount = 30;
2211 u16 coal_rareness = 60 / coal_amount;
2212 if(coal_rareness == 0)
2214 if(mineralrandom.next()%coal_rareness == 0)
2216 u16 a = mineralrandom.next() % 16;
2217 u16 amount = coal_amount * a*a*a / 1000;
2218 for(s16 i=0; i<amount; i++)
2220 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2221 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2222 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2223 for(u16 i=0; i<27; i++)
2225 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2226 u32 vi = vmanip.m_area.index(p);
2227 if(vmanip.m_data[vi].getContent() == c_stone)
2228 if(mineralrandom.next()%8 == 0)
2229 vmanip.m_data[vi] = MapNode(c_stone_with_coal);
2236 u16 iron_amount = 8;
2237 u16 iron_rareness = 60 / iron_amount;
2238 if(iron_rareness == 0)
2240 if(mineralrandom.next()%iron_rareness == 0)
2242 u16 a = mineralrandom.next() % 16;
2243 u16 amount = iron_amount * a*a*a / 1000;
2244 for(s16 i=0; i<amount; i++)
2246 s16 x = mineralrandom.range(node_min.X+1, node_max.X-1);
2247 s16 y = mineralrandom.range(node_min.Y+1, node_max.Y-1);
2248 s16 z = mineralrandom.range(node_min.Z+1, node_max.Z-1);
2249 for(u16 i=0; i<27; i++)
2251 v3s16 p = v3s16(x,y,z) + g_27dirs[i];
2252 u32 vi = vmanip.m_area.index(p);
2253 if(vmanip.m_data[vi].getContent() == c_stone)
2254 if(mineralrandom.next()%8 == 0)
2255 vmanip.m_data[vi] = MapNode(c_stone_with_iron);
2266 ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update",
2268 //VoxelArea a(node_min, node_max);
2269 VoxelArea a(node_min-v3s16(1,0,1)*MAP_BLOCKSIZE,
2270 node_max+v3s16(1,0,1)*MAP_BLOCKSIZE);
2271 /*VoxelArea a(node_min-v3s16(1,0,1)*MAP_BLOCKSIZE/2,
2272 node_max+v3s16(1,0,1)*MAP_BLOCKSIZE/2);*/
2273 enum LightBank banks[2] = {LIGHTBANK_DAY, LIGHTBANK_NIGHT};
2274 for(int i=0; i<2; i++)
2276 enum LightBank bank = banks[i];
2278 core::map<v3s16, bool> light_sources;
2279 core::map<v3s16, u8> unlight_from;
2281 voxalgo::clearLightAndCollectSources(vmanip, a, bank, ndef,
2282 light_sources, unlight_from);
2284 bool inexistent_top_provides_sunlight = !block_is_underground;
2285 voxalgo::SunlightPropagateResult res = voxalgo::propagateSunlight(
2286 vmanip, a, inexistent_top_provides_sunlight,
2287 light_sources, ndef);
2288 // TODO: Do stuff according to bottom_sunlight_valid
2290 vmanip.unspreadLight(bank, unlight_from, light_sources, ndef);
2292 vmanip.spreadLight(bank, light_sources, ndef);
2297 #endif ///BIG COMMENT