-
- }
-
- }//timer1
-#endif
-
-#if 1
- {
- // 15ms @cs=8
- TimeTaker timer1("add mud");
-
- /*
- Add mud to the central chunk
- */
-
- for(s16 x=node_min.X; x<=node_max.X; x++)
- for(s16 z=node_min.Z; z<=node_max.Z; z++)
- {
- // Node position in 2d
- v2s16 p2d = v2s16(x,z);
-
- // Randomize mud amount
- s16 mud_add_amount = get_mud_add_amount(data->seed, p2d) / 2.0 + 0.5;
-
- // Find ground level
- s16 surface_y = find_stone_level(vmanip, p2d, ndef);
- // Handle area not found
- if(surface_y == vmanip.m_area.MinEdge.Y - 1)
- continue;
-
- MapNode addnode(c_dirt);
- BiomeType bt = get_biome(data->seed, p2d);
-
- if(bt == BT_DESERT)
- addnode = MapNode(c_desert_sand);
-
- if(bt == BT_DESERT && surface_y + mud_add_amount <= water_level+1){
- addnode = MapNode(c_sand);
- } else if(mud_add_amount <= 0){
- mud_add_amount = 1 - mud_add_amount;
- addnode = MapNode(c_gravel);
- } else if(bt == BT_NORMAL && get_have_beach(data->seed, p2d) &&
- surface_y + mud_add_amount <= water_level+2){
- addnode = MapNode(c_sand);
- }
-
- if(bt == BT_DESERT){
- if(surface_y > 20){
- mud_add_amount = MYMAX(0, mud_add_amount - (surface_y - 20)/5);
- }
- }
-
- /*
- If topmost node is grass, change it to mud.
- It might be if it was flown to there from a neighboring
- chunk and then converted.
- */
- {
- u32 i = vmanip.m_area.index(v3s16(p2d.X, surface_y, p2d.Y));
- MapNode *n = &vmanip.m_data[i];
- if(n->getContent() == c_dirt_with_grass)
- *n = MapNode(c_dirt);
- }
-
- /*
- Add mud on ground
- */
- {
- s16 mudcount = 0;
- v3s16 em = vmanip.m_area.getExtent();
- s16 y_start = surface_y+1;
- u32 i = vmanip.m_area.index(v3s16(p2d.X, y_start, p2d.Y));
- for(s16 y=y_start; y<=node_max.Y; y++)
- {
- if(mudcount >= mud_add_amount)
- break;
-
- MapNode &n = vmanip.m_data[i];
- n = addnode;
- mudcount++;
-
- vmanip.m_area.add_y(em, i, 1);
- }
- }
-
- }
-
- }//timer1
-#endif
-
- /*
- Add blobs of dirt and gravel underground
- */
- if(get_biome(data->seed, v2s16(node_min.X, node_min.Z)) == BT_NORMAL)
- {
- PseudoRandom pr(blockseed+983);
- for(int i=0; i<volume_nodes/10/10/10; i++)
- {
- bool only_fill_cave = (myrand_range(0,1) != 0);
- v3s16 size(
- pr.range(1, 8),
- pr.range(1, 8),
- pr.range(1, 8)
- );
- v3s16 p0(
- pr.range(node_min.X, node_max.X)-size.X/2,
- pr.range(node_min.Y, node_max.Y)-size.Y/2,
- pr.range(node_min.Z, node_max.Z)-size.Z/2
- );
- MapNode n1;
- if(p0.Y > -32 && pr.range(0,1) == 0)
- n1 = MapNode(c_dirt);
- else
- n1 = MapNode(c_gravel);
- for(int x1=0; x1<size.X; x1++)
- for(int y1=0; y1<size.Y; y1++)
- for(int z1=0; z1<size.Z; z1++)
- {
- v3s16 p = p0 + v3s16(x1,y1,z1);
- u32 i = vmanip.m_area.index(p);
- if(!vmanip.m_area.contains(i))
- continue;
- // Cancel if not stone and not cave air
- if(vmanip.m_data[i].getContent() != c_stone &&
- !(vmanip.m_flags[i] & VMANIP_FLAG_CAVE))
- continue;
- if(only_fill_cave && !(vmanip.m_flags[i] & VMANIP_FLAG_CAVE))
- continue;
- vmanip.m_data[i] = n1;
- }
- }
- }
-
-#if 1
- {
- // 340ms @cs=8
- TimeTaker timer1("flow mud");
-
- /*
- Flow mud away from steep edges
- */
-
- // Iterate a few times
- for(s16 k=0; k<3; k++)
- {
-
- for(s16 x=mudflow_minpos; x<=mudflow_maxpos; x++)
- for(s16 z=mudflow_minpos; z<=mudflow_maxpos; z++)
- {
- // Invert coordinates every 2nd iteration
- if(k%2 == 0)
- {
- x = mudflow_maxpos - (x-mudflow_minpos);
- z = mudflow_maxpos - (z-mudflow_minpos);
- }
-
- // Node position in 2d
- v2s16 p2d = v2s16(node_min.X, node_min.Z) + v2s16(x,z);
-
- v3s16 em = vmanip.m_area.getExtent();
- u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
- s16 y=node_max.Y;
-
- while(y >= node_min.Y)
- {
-
- for(;; y--)
- {
- MapNode *n = NULL;
- // Find mud
- for(; y>=node_min.Y; y--)
- {
- n = &vmanip.m_data[i];
- //if(content_walkable(n->d))
- // break;
- if(n->getContent() == c_dirt ||
- n->getContent() == c_dirt_with_grass ||
- n->getContent() == c_gravel)
- break;
-
- vmanip.m_area.add_y(em, i, -1);
- }
-
- // Stop if out of area
- //if(vmanip.m_area.contains(i) == false)
- if(y < node_min.Y)
- break;
-
- /*// If not mud, do nothing to it
- MapNode *n = &vmanip.m_data[i];
- if(n->d != CONTENT_MUD && n->d != CONTENT_GRASS)
- continue;*/
-
- if(n->getContent() == c_dirt ||
- n->getContent() == c_dirt_with_grass)
- {
- // Make it exactly mud
- n->setContent(c_dirt);
-
- /*
- Don't flow it if the stuff under it is not mud
- */
- {
- u32 i2 = i;
- vmanip.m_area.add_y(em, i2, -1);
- // Cancel if out of area
- if(vmanip.m_area.contains(i2) == false)
- continue;
- MapNode *n2 = &vmanip.m_data[i2];
- if(n2->getContent() != c_dirt &&
- n2->getContent() != c_dirt_with_grass)
- continue;
- }
- }
-
- /*s16 recurse_count = 0;
- mudflow_recurse:*/
-
- v3s16 dirs4[4] = {
- v3s16(0,0,1), // back
- v3s16(1,0,0), // right
- v3s16(0,0,-1), // front
- v3s16(-1,0,0), // left
- };
-
- // Theck that upper is air or doesn't exist.
- // Cancel dropping if upper keeps it in place
- u32 i3 = i;
- vmanip.m_area.add_y(em, i3, 1);
- if(vmanip.m_area.contains(i3) == true
- && ndef->get(vmanip.m_data[i3]).walkable)
- {
- continue;
- }
-
- // Drop mud on side
-
- for(u32 di=0; di<4; di++)
- {
- v3s16 dirp = dirs4[di];
- u32 i2 = i;
- // Move to side
- vmanip.m_area.add_p(em, i2, dirp);
- // Fail if out of area
- if(vmanip.m_area.contains(i2) == false)
- continue;
- // Check that side is air
- MapNode *n2 = &vmanip.m_data[i2];
- if(ndef->get(*n2).walkable)
- continue;
- // Check that under side is air
- vmanip.m_area.add_y(em, i2, -1);
- if(vmanip.m_area.contains(i2) == false)
- continue;
- n2 = &vmanip.m_data[i2];
- if(ndef->get(*n2).walkable)
- continue;
- /*// Check that under that is air (need a drop of 2)
- vmanip.m_area.add_y(em, i2, -1);
- if(vmanip.m_area.contains(i2) == false)
- continue;
- n2 = &vmanip.m_data[i2];
- if(content_walkable(n2->d))
- continue;*/
- // Loop further down until not air
- bool dropped_to_unknown = false;
- do{
- vmanip.m_area.add_y(em, i2, -1);
- n2 = &vmanip.m_data[i2];
- // if out of known area
- if(vmanip.m_area.contains(i2) == false
- || n2->getContent() == CONTENT_IGNORE){
- dropped_to_unknown = true;
- break;
- }
- }while(ndef->get(*n2).walkable == false);
- // Loop one up so that we're in air
- vmanip.m_area.add_y(em, i2, 1);
- n2 = &vmanip.m_data[i2];
-
- bool old_is_water = (n->getContent() == c_water_source);
- // Move mud to new place
- if(!dropped_to_unknown) {
- *n2 = *n;
- // Set old place to be air (or water)
- if(old_is_water)
- *n = MapNode(c_water_source);
- else
- *n = MapNode(CONTENT_AIR);
- }
-
- // Done
- break;
- }
- }
- }
- }
-
- }
-
- }//timer1
-#endif
-
- } // Aging loop
- /***********************
- END OF AGING LOOP
- ************************/
-
- /*
- Add top and bottom side of water to transforming_liquid queue
- */
-
- for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
- for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
- {
- // Node position
- v2s16 p2d(x,z);
- {
- bool water_found = false;
- // Use fast index incrementing
- v3s16 em = vmanip.m_area.getExtent();
- u32 i = vmanip.m_area.index(v3s16(p2d.X, full_node_max.Y, p2d.Y));
- for(s16 y=full_node_max.Y; y>=full_node_min.Y; y--)
- {
- if(y == full_node_max.Y){
- water_found =
- (vmanip.m_data[i].getContent() == c_water_source ||
- vmanip.m_data[i].getContent() == c_lava_source);
- }
- else if(water_found == false)
- {
- if(vmanip.m_data[i].getContent() == c_water_source ||
- vmanip.m_data[i].getContent() == c_lava_source)
- {
- v3s16 p = v3s16(p2d.X, y, p2d.Y);
- data->transforming_liquid.push_back(p);
- water_found = true;
- }
- }
- else
- {
- // This can be done because water_found can only
- // turn to true and end up here after going through
- // a single block.
- if(vmanip.m_data[i+1].getContent() != c_water_source ||
- vmanip.m_data[i+1].getContent() != c_lava_source)
- {
- v3s16 p = v3s16(p2d.X, y+1, p2d.Y);
- data->transforming_liquid.push_back(p);
- water_found = false;
- }
- }
-
- vmanip.m_area.add_y(em, i, -1);
- }
- }
- }
-
- /*
- Grow grass
- */
-
- for(s16 x=full_node_min.X; x<=full_node_max.X; x++)
- for(s16 z=full_node_min.Z; z<=full_node_max.Z; z++)
- {
- // Node position in 2d
- v2s16 p2d = v2s16(x,z);
-
- /*
- Find the lowest surface to which enough light ends up
- to make grass grow.
-
- Basically just wait until not air and not leaves.
- */
- s16 surface_y = 0;
- {
- v3s16 em = vmanip.m_area.getExtent();
- u32 i = vmanip.m_area.index(v3s16(p2d.X, node_max.Y, p2d.Y));
- s16 y;
- // Go to ground level
- for(y=node_max.Y; y>=full_node_min.Y; y--)
- {
- MapNode &n = vmanip.m_data[i];
- if(ndef->get(n).param_type != CPT_LIGHT
- || ndef->get(n).liquid_type != LIQUID_NONE)
- break;
- vmanip.m_area.add_y(em, i, -1);
- }
- if(y >= full_node_min.Y)
- surface_y = y;
- else
- surface_y = full_node_min.Y;
- }
-
- u32 i = vmanip.m_area.index(p2d.X, surface_y, p2d.Y);
- MapNode *n = &vmanip.m_data[i];
- if(n->getContent() == c_dirt){
- // Well yeah, this can't be overground...
- if(surface_y < water_level - 20)
- continue;
- n->setContent(c_dirt_with_grass);
- }
- }
-
- /*
- Generate some trees
- */
- assert(central_area_size.X == central_area_size.Z);
- if (flags & MG_TREES) {
- // Divide area into parts
- s16 div = 8;
- s16 sidelen = central_area_size.X / div;
- double area = sidelen * sidelen;
- for(s16 x0=0; x0<div; x0++)
- for(s16 z0=0; z0<div; z0++)
- {
- // Center position of part of division
- v2s16 p2d_center(
- node_min.X + sidelen/2 + sidelen*x0,
- node_min.Z + sidelen/2 + sidelen*z0
- );
- // Minimum edge of part of division
- v2s16 p2d_min(
- node_min.X + sidelen*x0,
- node_min.Z + sidelen*z0
- );
- // Maximum edge of part of division
- v2s16 p2d_max(
- node_min.X + sidelen + sidelen*x0 - 1,
- node_min.Z + sidelen + sidelen*z0 - 1
- );
- // Amount of trees
- u32 tree_count = area * tree_amount_2d(data->seed, p2d_center);
- // 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(vmanip, v2s16(x,z), ndef);
- // Don't make a tree under water level
- if(y < water_level)
- continue;
- // Don't make a tree so high that it doesn't fit
- if(y > node_max.Y - 6)
- continue;
- v3s16 p(x,y,z);
- /*
- Trees grow only on mud and grass
- */
- {
- u32 i = vmanip.m_area.index(v3s16(p));
- MapNode *n = &vmanip.m_data[i];
- if(n->getContent() != c_dirt
- && n->getContent() != c_dirt_with_grass)
- continue;
- }
- p.Y++;
- // Make a tree
- make_tree(vmanip, p, false, ndef);
- }
- }
- }
-
-
- /*
- Calculate lighting
- */
- {
- ScopeProfiler sp(g_profiler, "EmergeThread: mapgen lighting update",
- SPT_AVG);
- //VoxelArea a(node_min, node_max);
- VoxelArea a(node_min-v3s16(1,0,1)*MAP_BLOCKSIZE,
- node_max+v3s16(1,0,1)*MAP_BLOCKSIZE);
- /*VoxelArea a(node_min-v3s16(1,0,1)*MAP_BLOCKSIZE/2,
- node_max+v3s16(1,0,1)*MAP_BLOCKSIZE/2);*/
- enum LightBank banks[2] = {LIGHTBANK_DAY, LIGHTBANK_NIGHT};
- for(int i=0; i<2; i++)
- {
- enum LightBank bank = banks[i];
-
- core::map<v3s16, bool> light_sources;
- core::map<v3s16, u8> unlight_from;
-
- voxalgo::clearLightAndCollectSources(vmanip, a, bank, ndef,
- light_sources, unlight_from);
-
- bool inexistent_top_provides_sunlight = !block_is_underground;
- voxalgo::SunlightPropagateResult res = voxalgo::propagateSunlight(
- vmanip, a, inexistent_top_provides_sunlight,
- light_sources, ndef);
- // TODO: Do stuff according to bottom_sunlight_valid
-
- vmanip.unspreadLight(bank, unlight_from, light_sources, ndef);
-
- vmanip.spreadLight(bank, light_sources, ndef);
- }