#include "main.h" // For g_profiler
#include "emerge.h"
#include "dungeongen.h"
+#include "cavegen.h"
#include "treegen.h"
#include "mapgen_v6.h"
///////////////////////////////////////////////////////////////////////////////
-MapgenV6::MapgenV6(int mapgenid, MapgenV6Params *params) {
+MapgenV6::MapgenV6(int mapgenid, MapgenV6Params *params, EmergeManager *emerge) {
this->generating = false;
this->id = mapgenid;
+ this->emerge = emerge;
this->seed = (int)params->seed;
this->water_level = params->water_level;
this->freq_beach = params->freq_beach;
this->ystride = csize.X; //////fix this
-
- np_cave = params->np_cave;
- np_humidity = params->np_humidity;
- np_trees = params->np_trees;
- np_apple_trees = params->np_apple_trees;
-
- noise_terrain_base = new Noise(params->np_terrain_base, seed, csize.X, csize.Y);
- noise_terrain_higher = new Noise(params->np_terrain_higher, seed, csize.X, csize.Y);
- noise_steepness = new Noise(params->np_steepness, seed, csize.X, csize.Y);
- noise_height_select = new Noise(params->np_height_select, seed, csize.X, csize.Y);
- noise_mud = new Noise(params->np_mud, seed, csize.X, csize.Y);
- noise_beach = new Noise(params->np_beach, seed, csize.X, csize.Y);
- noise_biome = new Noise(params->np_biome, seed, csize.X, csize.Y);
+
+ np_cave = ¶ms->np_cave;
+ np_humidity = ¶ms->np_humidity;
+ np_trees = ¶ms->np_trees;
+ np_apple_trees = ¶ms->np_apple_trees;
+
+ noise_terrain_base = new Noise(¶ms->np_terrain_base, seed, csize.X, csize.Y);
+ noise_terrain_higher = new Noise(¶ms->np_terrain_higher, seed, csize.X, csize.Y);
+ noise_steepness = new Noise(¶ms->np_steepness, seed, csize.X, csize.Y);
+ noise_height_select = new Noise(¶ms->np_height_select, seed, csize.X, csize.Y);
+ noise_mud = new Noise(¶ms->np_mud, seed, csize.X, csize.Y);
+ noise_beach = new Noise(¶ms->np_beach, seed, csize.X, csize.Y);
+ noise_biome = new Noise(¶ms->np_biome, seed, csize.X, csize.Y);
}
//////////////////////// Some helper functions for the map generator
-// Returns Y one under area minimum if not found
-s16 MapgenV6::find_ground_level(v2s16 p2d) {
- v3s16 em = vm->m_area.getExtent();
- s16 y_nodes_max = vm->m_area.MaxEdge.Y;
- s16 y_nodes_min = vm->m_area.MinEdge.Y;
- u32 i = vm->m_area.index(p2d.X, y_nodes_max, p2d.Y);
- s16 y;
-
- for (y = y_nodes_max; y >= y_nodes_min; y--) {
- MapNode &n = vm->m_data[i];
- if(ndef->get(n).walkable)
- break;
-
- vm->m_area.add_y(em, i, -1);
- }
- return (y >= y_nodes_min) ? y : y_nodes_min - 1;
-}
// Returns Y one under area minimum if not found
s16 MapgenV6::find_stone_level(v2s16 p2d) {
v3s16 blockpos = data->blockpos_requested;
v3s16 blockpos_min = data->blockpos_min;
v3s16 blockpos_max = data->blockpos_max;
- v3s16 blockpos_full_min = blockpos_min - v3s16(1,1,1);
- v3s16 blockpos_full_max = blockpos_max + v3s16(1,1,1);
// Area of central chunk
node_min = blockpos_min*MAP_BLOCKSIZE;
// Generate general ground level to full area
stone_surface_max_y = generateGround();
+ generateExperimental();
+
const s16 max_spread_amount = MAP_BLOCKSIZE;
// Limit dirt flow area by 1 because mud is flown into neighbors.
s16 mudflow_minpos = -max_spread_amount + 1;
// Grow grass
growGrass();
- // Generate some trees
+ // Generate some trees, and add grass, if a jungle
if (flags & MG_TREES)
- placeTrees();
+ placeTreesAndJungleGrass();
+
+ // Generate the registered decorations
+ for (unsigned int i = 0; i != emerge->decorations.size(); i++) {
+ Decoration *deco = emerge->decorations[i];
+ deco->placeDeco(this, blockseed + i, node_min, node_max);
+ }
+
+ // Generate the registered ores
+ for (unsigned int i = 0; i != emerge->ores.size(); i++) {
+ Ore *ore = emerge->ores[i];
+ ore->placeOre(this, blockseed + i, node_min, node_max);
+ }
// Calculate lighting
- updateLighting(node_min, node_max);
+ if (!(flags & MG_NOLIGHT))
+ calcLighting(node_min - v3s16(1, 1, 1) * MAP_BLOCKSIZE,
+ node_max + v3s16(1, 0, 1) * MAP_BLOCKSIZE);
this->generating = false;
}
noise_height_select->perlinMap2D(
x + 0.5 * noise_height_select->np->spread.X,
z + 0.5 * noise_height_select->np->spread.Z);
- }
-
- if (!(flags & MG_FLAT)) {
+
noise_mud->perlinMap2D(
x + 0.5 * noise_mud->np->spread.X,
z + 0.5 * noise_mud->np->spread.Z);
noise_mud->transformNoiseMap();
}
+
noise_beach->perlinMap2D(
x + 0.2 * noise_beach->np->spread.X,
z + 0.7 * noise_beach->np->spread.Z);
}
-void MapgenV6::placeTrees() {
+void MapgenV6::placeTreesAndJungleGrass() {
//TimeTaker t("placeTrees");
+ if (node_max.Y < water_level)
+ return;
+
+ PseudoRandom grassrandom(blockseed + 53);
+ content_t c_junglegrass = ndef->getId("mapgen_junglegrass");
+ // if we don't have junglegrass, don't place cignore... that's bad
+ if (c_junglegrass == CONTENT_IGNORE)
+ c_junglegrass = CONTENT_AIR;
+ MapNode n_junglegrass(c_junglegrass);
+ v3s16 em = vm->m_area.getExtent();
// Divide area into parts
s16 div = 8;
s16 sidelen = central_area_size.X / div;
double area = sidelen * sidelen;
+ // N.B. We must add jungle grass first, since tree leaves will
+ // obstruct the ground, giving us a false ground level
for (s16 z0 = 0; z0 < div; z0++)
for (s16 x0 = 0; x0 < div; x0++) {
// Center position of part of division
// Amount of trees, jungle area
u32 tree_count = area * getTreeAmount(p2d_center);
- bool is_jungle = (flags & MGV6_JUNGLES) && (getHumidity(p2d_center) > 0.75);
- if (is_jungle)
- tree_count *= 4;
+
+ float humidity;
+ bool is_jungle = false;
+ if (flags & MGV6_JUNGLES) {
+ humidity = getHumidity(p2d_center);
+ if (humidity > 0.75) {
+ is_jungle = true;
+ tree_count *= 4;
+ }
+ }
+
+ // Add jungle grass
+ if (is_jungle) {
+ u32 grass_count = 5 * humidity * tree_count;
+ for (u32 i = 0; i < grass_count; i++) {
+ s16 x = grassrandom.range(p2d_min.X, p2d_max.X);
+ s16 z = grassrandom.range(p2d_min.Y, p2d_max.Y);
+
+ s16 y = findGroundLevelFull(v2s16(x, z)); ////////////////optimize this!
+ if (y < water_level || y < node_min.Y || y > node_max.Y)
+ continue;
+
+ u32 vi = vm->m_area.index(x, y, z);
+ // place on dirt_with_grass, since we know it is exposed to sunlight
+ if (vm->m_data[vi].getContent() == c_dirt_with_grass) {
+ vm->m_area.add_y(em, vi, 1);
+ vm->m_data[vi] = n_junglegrass;
+ }
+ }
+ }
// Put trees in random places on part of division
for (u32 i = 0; i < tree_count; i++) {
s16 x = myrand_range(p2d_min.X, p2d_max.X);
s16 z = myrand_range(p2d_min.Y, p2d_max.Y);
- s16 y = find_ground_level(v2s16(x, z)); ////////////////////optimize this!
+ s16 y = findGroundLevelFull(v2s16(x, z)); ////////////////////optimize this!
// Don't make a tree under water level
// Don't make a tree so high that it doesn't fit
if(y < water_level || y > node_max.Y - 6)
}
}
}
- //printf("placeTrees: %dms\n", t.stop());
+ //printf("placeTreesAndJungleGrass: %dms\n", t.stop());
}
void MapgenV6::generateCaves(int max_stone_y) {
- // 24ms @cs=8
- //TimeTaker timer1("caves");
-
- /*double cave_amount = 6.0 + 6.0 * noise2d_perlin(
- 0.5+(double)node_min.X/250, 0.5+(double)node_min.Y/250,
- data->seed+34329, 3, 0.50);*/
- const s16 max_spread_amount = MAP_BLOCKSIZE;
float cave_amount = NoisePerlin2D(np_cave, node_min.X, node_min.Y, seed);
-
+ int volume_nodes = (node_max.X - node_min.X + 1) *
+ (node_max.Y - node_min.Y + 1) * MAP_BLOCKSIZE;
cave_amount = MYMAX(0.0, cave_amount);
u32 caves_count = cave_amount * volume_nodes / 50000;
u32 bruises_count = 1;
bruises_count /= 3;
}
- for(u32 jj = 0; jj < caves_count + bruises_count; jj++) {
- /*int avg_height = (int)
- ((base_rock_level_2d(data->seed, v2s16(node_min.X, node_min.Z)) +
- base_rock_level_2d(data->seed, v2s16(node_max.X, node_max.Z))) / 2);
- if ((node_max.Y + node_min.Y) / 2 > avg_height)
- break;*/
-
- bool large_cave = (jj >= caves_count);
- s16 min_tunnel_diameter = 2;
- s16 max_tunnel_diameter = ps.range(2,6);
- int dswitchint = ps.range(1,14);
- u16 tunnel_routepoints = 0;
- int part_max_length_rs = 0;
- if(large_cave){
- part_max_length_rs = ps.range(2,4);
- tunnel_routepoints = ps.range(5, ps.range(15,30));
- min_tunnel_diameter = 5;
- max_tunnel_diameter = ps.range(7, ps.range(8,24));
- } else {
- part_max_length_rs = ps.range(2,9);
- tunnel_routepoints = ps.range(10, ps.range(15,30));
- }
- bool large_cave_is_flat = (ps.range(0,1) == 0);
-
- v3f main_direction(0,0,0);
+ for (u32 i = 0; i < caves_count + bruises_count; i++) {
+ bool large_cave = (i >= caves_count);
+ CaveV6 cave(this, &ps, &ps2, large_cave);
- // Allowed route area size in nodes
- v3s16 ar = central_area_size;
-
- // Area starting point in nodes
- v3s16 of = node_min;
-
- // Allow a bit more
- //(this should be more than the maximum radius of the tunnel)
- s16 insure = 10;
- s16 more = max_spread_amount - max_tunnel_diameter / 2 - insure;
- ar += v3s16(1,0,1) * more * 2;
- of -= v3s16(1,0,1) * more;
-
- s16 route_y_min = 0;
- // Allow half a diameter + 7 over stone surface
- s16 route_y_max = -of.Y + max_stone_y + max_tunnel_diameter/2 + 7;
-
- // Limit maximum to area
- route_y_max = rangelim(route_y_max, 0, ar.Y-1);
-
- if(large_cave)
- {
- s16 min = 0;
- if(node_min.Y < water_level && node_max.Y > water_level)
- {
- min = water_level - max_tunnel_diameter/3 - of.Y;
- route_y_max = water_level + max_tunnel_diameter/3 - of.Y;
- }
- route_y_min = ps.range(min, min + max_tunnel_diameter);
- route_y_min = rangelim(route_y_min, 0, route_y_max);
- }
-
- s16 route_start_y_min = route_y_min;
- s16 route_start_y_max = route_y_max;
-
- route_start_y_min = rangelim(route_start_y_min, 0, ar.Y-1);
- route_start_y_max = rangelim(route_start_y_max, route_start_y_min, ar.Y-1);
-
- // Randomize starting position
- v3f orp(
- (float)(ps.next()%ar.X)+0.5,
- (float)(ps.range(route_start_y_min, route_start_y_max))+0.5,
- (float)(ps.next()%ar.Z)+0.5
- );
-
- v3s16 startp(orp.X, orp.Y, orp.Z);
- startp += of;
-
- MapNode airnode(CONTENT_AIR);
- MapNode waternode(c_water_source);
- MapNode lavanode(c_lava_source);
-
- /*
- Generate some tunnel starting from orp
- */
-
- for(u16 j=0; j<tunnel_routepoints; j++)
- {
- if(j%dswitchint==0 && large_cave == false)
- {
- main_direction = v3f(
- ((float)(ps.next()%20)-(float)10)/10,
- ((float)(ps.next()%20)-(float)10)/30,
- ((float)(ps.next()%20)-(float)10)/10
- );
- main_direction *= (float)ps.range(0, 10)/10;
- }
-
- // Randomize size
- s16 min_d = min_tunnel_diameter;
- s16 max_d = max_tunnel_diameter;
- s16 rs = ps.range(min_d, max_d);
-
- // Every second section is rough
- bool randomize_xz = (ps2.range(1,2) == 1);
-
- v3s16 maxlen;
- if(large_cave)
- {
- maxlen = v3s16(
- rs*part_max_length_rs,
- rs*part_max_length_rs/2,
- rs*part_max_length_rs
- );
- }
- else
- {
- maxlen = v3s16(
- rs*part_max_length_rs,
- ps.range(1, rs*part_max_length_rs),
- rs*part_max_length_rs
- );
- }
-
- v3f vec;
-
- vec = v3f(
- (float)(ps.next()%(maxlen.X*1))-(float)maxlen.X/2,
- (float)(ps.next()%(maxlen.Y*1))-(float)maxlen.Y/2,
- (float)(ps.next()%(maxlen.Z*1))-(float)maxlen.Z/2
- );
-
- // Jump downward sometimes
- if(!large_cave && ps.range(0,12) == 0)
- {
- vec = v3f(
- (float)(ps.next()%(maxlen.X*1))-(float)maxlen.X/2,
- (float)(ps.next()%(maxlen.Y*2))-(float)maxlen.Y*2/2,
- (float)(ps.next()%(maxlen.Z*1))-(float)maxlen.Z/2
- );
- }
-
- /*if(large_cave){
- v3f p = orp + vec;
- s16 h = find_ground_level_clever(vmanip,
- v2s16(p.X, p.Z), ndef);
- route_y_min = h - rs/3;
- route_y_max = h + rs;
- }*/
-
- vec += main_direction;
-
- v3f rp = orp + vec;
- if(rp.X < 0)
- rp.X = 0;
- else if(rp.X >= ar.X)
- rp.X = ar.X-1;
- if(rp.Y < route_y_min)
- rp.Y = route_y_min;
- else if(rp.Y >= route_y_max)
- rp.Y = route_y_max-1;
- if(rp.Z < 0)
- rp.Z = 0;
- else if(rp.Z >= ar.Z)
- rp.Z = ar.Z-1;
- vec = rp - orp;
-
- for(float f=0; f<1.0; f+=1.0/vec.getLength())
- {
- v3f fp = orp + vec * f;
- fp.X += 0.1*ps.range(-10,10);
- fp.Z += 0.1*ps.range(-10,10);
- v3s16 cp(fp.X, fp.Y, fp.Z);
-
- s16 d0 = -rs/2;
- s16 d1 = d0 + rs;
- if(randomize_xz){
- d0 += ps.range(-1,1);
- d1 += ps.range(-1,1);
- }
- for(s16 z0=d0; z0<=d1; z0++)
- {
- s16 si = rs/2 - MYMAX(0, abs(z0)-rs/7-1);
- for(s16 x0=-si-ps.range(0,1); x0<=si-1+ps.range(0,1); x0++)
- {
- s16 maxabsxz = MYMAX(abs(x0), abs(z0));
- s16 si2 = rs/2 - MYMAX(0, maxabsxz-rs/7-1);
- for(s16 y0=-si2; y0<=si2; y0++)
- {
- /*// Make better floors in small caves
- if(y0 <= -rs/2 && rs<=7)
- continue;*/
- if (large_cave_is_flat) {
- // Make large caves not so tall
- if (rs > 7 && abs(y0) >= rs/3)
- continue;
- }
-
- s16 z = cp.Z + z0;
- s16 y = cp.Y + y0;
- s16 x = cp.X + x0;
- v3s16 p(x,y,z);
- p += of;
-
- if(vm->m_area.contains(p) == false)
- continue;
-
- u32 i = vm->m_area.index(p);
-
- if(large_cave) {
- if (full_node_min.Y < water_level &&
- full_node_max.Y > water_level) {
- if (p.Y <= water_level)
- vm->m_data[i] = waternode;
- else
- vm->m_data[i] = airnode;
- } else if (full_node_max.Y < water_level) {
- if (p.Y < startp.Y - 2)
- vm->m_data[i] = lavanode;
- else
- vm->m_data[i] = airnode;
- } else {
- vm->m_data[i] = airnode;
- }
- } else {
- // Don't replace air or water or lava or ignore
- if (vm->m_data[i].getContent() == CONTENT_IGNORE ||
- vm->m_data[i].getContent() == CONTENT_AIR ||
- vm->m_data[i].getContent() == c_water_source ||
- vm->m_data[i].getContent() == c_lava_source)
- continue;
-
- vm->m_data[i] = airnode;
-
- // Set tunnel flag
- vm->m_flags[i] |= VMANIP_FLAG_CAVE;
- }
- }
- }
- }
- }
- orp = rp;
- }
+ cave.makeCave(node_min, node_max, max_stone_y);
}
}