Beispiel #1
0
void MapgenV6::growGrass() // Add surface nodes
{
	MapNode n_dirt_with_grass(c_dirt_with_grass);
	MapNode n_dirt_with_snow(c_dirt_with_snow);
	MapNode n_snowblock(c_snowblock);
	MapNode n_snow(c_snow);
	MapNode n_dirt(c_dirt);
	v3s16 em = vm->m_area.getExtent();

	u32 index = 0;
	for (s16 z = full_node_min.Z; z <= full_node_max.Z; z++)
	for (s16 x = full_node_min.X; x <= full_node_max.X; x++, index++) {
		// 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;
		{
			u32 i = vm->m_area.index(x, node_max.Y, z);
			s16 y;
			// Go to ground level
			for (y = node_max.Y; y >= full_node_min.Y; y--) {
				MapNode &n = vm->m_data[i];
				if (ndef->get(n).param_type != CPT_LIGHT ||
						ndef->get(n).liquid_type != LIQUID_NONE ||
						n.getContent() == c_ice)
					break;
				vm->m_area.add_y(em, i, -1);
			}
			surface_y = (y >= full_node_min.Y) ? y : full_node_min.Y;
		}

		BiomeV6Type bt = getBiome(index, v3POS(x, surface_y, z));
		u32 i = vm->m_area.index(x, surface_y, z);
		content_t c = vm->m_data[i].getContent();
		if (m_emerge->env->m_use_weather && c == c_dirt) {
			int heat = m_emerge->env->getServerMap().updateBlockHeat(m_emerge->env, v3POS(x, surface_y, z), nullptr, &heat_cache);
			vm->m_data[i] = (heat < -10 ? n_dirt_with_snow : (heat < -5 || heat > 50) ? n_dirt : n_dirt_with_grass);
		} else
		if (surface_y >= water_level - 20) {
			if (bt == BT_TAIGA && c == c_dirt) {
				vm->m_data[i] = n_snowblock;
				vm->m_area.add_y(em, i, -1);
				vm->m_data[i] = n_dirt_with_snow;
			} else if (bt == BT_TUNDRA) {
				if (c == c_dirt) {
					vm->m_data[i] = n_dirt_with_snow;
				} else if (c == c_stone && surface_y < node_max.Y) {
					vm->m_area.add_y(em, i, 1);
					vm->m_data[i] = n_snow;
				}
			} else if (c == c_dirt) {
				vm->m_data[i] = n_dirt_with_grass;
			}
		}
	}
}
Beispiel #2
0
	virtual void trigger(ServerEnvironment *env, v3POS p, MapNode n,
	                     u32 active_object_count, u32 active_object_count_wider, MapNode neighbor, bool activate) {
		ServerMap *map = &env->getServerMap();
		if (map->transforming_liquid_size() > map->m_liquid_step_flow)
			return;
		if (   map->getNodeTry(p - v3POS(0,  1, 0 )).getContent() != CONTENT_AIR  // below
		        && map->getNodeTry(p - v3POS(1,  0, 0 )).getContent() != CONTENT_AIR  // right
		        && map->getNodeTry(p - v3POS(-1, 0, 0 )).getContent() != CONTENT_AIR  // left
		        && map->getNodeTry(p - v3POS(0,  0, 1 )).getContent() != CONTENT_AIR  // back
		        && map->getNodeTry(p - v3POS(0,  0, -1)).getContent() != CONTENT_AIR  // front
		   )
			return;
		map->transforming_liquid_push_back(p);
	}
Beispiel #3
0
void MapgenV6::addMud()
{
	// 15ms @cs=8
	//TimeTaker timer1("add mud");
	MapNode n_dirt(c_dirt), n_gravel(c_gravel);
	MapNode n_sand(c_sand), n_desert_sand(c_desert_sand);
	MapNode addnode;

	u32 index = 0;
	for (s16 z = node_min.Z; z <= node_max.Z; z++)
	for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
		// Randomize mud amount
		s16 mud_add_amount = getMudAmount(index) / 2.0 + 0.5;

		// Find ground level
		s16 surface_y = find_stone_level(v2s16(x, z)); /////////////////optimize this!

		// Handle area not found
		if (surface_y == vm->m_area.MinEdge.Y - 1)
			continue;

		BiomeV6Type bt = getBiome(v3POS(x, surface_y, z));
		addnode = (bt == BT_DESERT) ? n_desert_sand : n_dirt;

		if (bt == BT_DESERT && surface_y + mud_add_amount <= water_level + 1) {
			addnode = n_sand;
		} else if (mud_add_amount <= 0) {
			mud_add_amount = 1 - mud_add_amount;
			addnode = n_gravel;
		} else if (bt != BT_DESERT && getHaveBeach(index) &&
				surface_y + mud_add_amount <= water_level + 2) {
			addnode = n_sand;
		}

		if ((bt == BT_DESERT || bt == BT_TUNDRA) && 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 = vm->m_area.index(x, surface_y, z);
		if (vm->m_data[i].getContent() == c_dirt_with_grass)
			vm->m_data[i] = n_dirt;*/

		// Add mud on ground
		s16 mudcount = 0;
		v3s16 em = vm->m_area.getExtent();
		s16 y_start = surface_y + 1;
		u32 i = vm->m_area.index(x, y_start, z);
		for (s16 y = y_start; y <= node_max.Y; y++) {
			if (mudcount >= mud_add_amount)
				break;

			vm->m_data[i] = addnode;
			mudcount++;

			vm->m_area.add_y(em, i, 1);
		}
	}
}
Beispiel #4
0
CircuitElement::CircuitElement(u32 element_id) :
	m_pos(v3POS(0, 0, 0)), m_prev_input_state(0), m_current_input_state(0),
	m_next_input_state(0), m_current_output_state(0) {
	m_element_id = element_id;
	for(int i = 0; i < 6; ++i) {
		m_faces[i].is_connected = false;
	}
}
Beispiel #5
0
int MapgenIndev::generateGround() {
    //TimeTaker timer1("Generating ground level");
    MapNode n_air(CONTENT_AIR), n_water_source(c_water_source);
    MapNode n_stone(c_stone), n_desert_stone(c_desert_stone);
    MapNode n_ice(c_ice), n_dirt(c_dirt),n_sand(c_sand), n_gravel(c_gravel), n_lava_source(c_lava_source);
    int stone_surface_max_y = -MAX_MAP_GENERATION_LIMIT;
    u32 index = 0;

    for (s16 z = node_min.Z; z <= node_max.Z; z++)
        for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
            // Surface height
            s16 surface_y = (s16)baseTerrainLevelFromMap(index);

            // Log it
            if (surface_y > stone_surface_max_y)
                stone_surface_max_y = surface_y;

            auto bt = getBiome(index, v3POS(x, surface_y, z));

            s16 heat = m_emerge->env->m_use_weather ? m_emerge->env->getServerMap().updateBlockHeat(m_emerge->env, v3POS(x,node_max.Y,z), nullptr, &heat_cache) : 0;

            // Fill ground with stone
            v3POS em = vm->m_area.getExtent();
            u32 i = vm->m_area.index(x, node_min.Y, z);

            for (s16 y = node_min.Y; y <= node_max.Y; y++) {
                if (!vm->m_data[i]) {

                    if (y <= surface_y) {
                        int index3 = (z - node_min.Z) * zstride + (y - node_min.Y) * ystride + (x - node_min.X) * xstride;
                        if (cave_noise_threshold && noise_cave_indev->result[index3] > cave_noise_threshold) {
                            vm->m_data[i] = n_air;
                        } else {
                            auto n = (y > water_level - surface_y && bt == BT_DESERT) ? n_desert_stone : layers_get(index3);
                            bool protect = n.getContent() != CONTENT_AIR;
                            if (cave_noise_threshold && noise_cave_indev->result[index3] > cave_noise_threshold - 50) {
                                vm->m_data[i] = protect ? n_stone : n; //cave shell without layers
                                protect = true;
                            } else {
                                vm->m_data[i] = n;
                            }
                            if (protect)
                                vm->m_flags[i] |= VOXELFLAG_CHECKED2; // no cave liquid
                        }
                    } else if (y <= water_level) {
                        vm->m_data[i] = (heat < 0 && y > heat/3) ? n_ice : n_water_source;
                        if (liquid_pressure && y <= 0)
                            vm->m_data[i].addLevel(m_emerge->ndef, water_level - y, 1);
                    } else {
                        vm->m_data[i] = n_air;
                    }
                }
                vm->m_area.add_y(em, i, 1);
            }
        }

    return stone_surface_max_y;
}
Beispiel #6
0
	virtual void trigger(ServerEnvironment *env, v3POS p, MapNode n,
	                     u32 active_object_count, u32 active_object_count_wider, MapNode neighbor, bool activate) {
		ServerMap *map = &env->getServerMap();
		INodeDefManager *ndef = env->getGameDef()->ndef();
		float heat = map->updateBlockHeat(env, p);
		content_t c = map->getNodeTry(p - v3POS(0,  -1, 0 )).getContent(); // top
		int melt = ((ItemGroupList) ndef->get(n).groups)["melt"];
		if (heat >= melt + 1 && (activate || heat >= melt + 40 ||
		                         ((myrand_range(heat, melt + 40)) >= (c == CONTENT_AIR ? melt + 10 : melt + 20)))) {
			if (ndef->get(n.getContent()).liquid_type == LIQUID_FLOWING || ndef->get(n.getContent()).liquid_type == LIQUID_SOURCE) {
				c = map->getNodeTry(p - v3POS(0,  1, 0 )).getContent(); // below
				if (c == CONTENT_AIR || c == CONTENT_IGNORE)
					return; // do not melt when falling (dirt->dirt_with_grass on air)
			}
			n.freeze_melt(ndef, +1);
			map->setNode(p, n);
			env->nodeUpdate(p, 2); //enable after making FAST nodeupdate
		}
	}
Beispiel #7
0
void Map::copy_27_blocks_to_vm(MapBlock * block, VoxelManipulator & vmanip) {

	v3POS blockpos = block->getPos();
	v3POS blockpos_nodes = blockpos * MAP_BLOCKSIZE;

	// Allocate this block + neighbors
	vmanip.clear();
	VoxelArea voxel_area(blockpos_nodes - v3POS(1, 1, 1) * MAP_BLOCKSIZE,
	                     blockpos_nodes + v3POS(1, 1, 1) * MAP_BLOCKSIZE * 2 - v3POS(1, 1, 1));
	vmanip.addArea(voxel_area);

	block->copyTo(vmanip);

	auto * map = block->getParent();

	for(u16 i = 0; i < 26; i++) {
		v3POS bp = blockpos + g_26dirs[i];
		MapBlock *b = map->getBlockNoCreateNoEx(bp);
		if(b)
			b->copyTo(vmanip);
	}

}
Beispiel #8
0
int MapgenV6::generateGround()
{
	//TimeTaker timer1("Generating ground level");
	MapNode n_air(CONTENT_AIR), n_water_source(c_water_source);
	MapNode n_stone(c_stone), n_desert_stone(c_desert_stone);
	MapNode n_ice(c_ice);
	int stone_surface_max_y = -MAX_MAP_GENERATION_LIMIT;

	u32 index = 0;
	for (s16 z = node_min.Z; z <= node_max.Z; z++)
	for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
		// Surface height
		s16 surface_y = (s16)baseTerrainLevelFromMap(index);

		// Log it
		if (surface_y > stone_surface_max_y)
			stone_surface_max_y = surface_y;

		BiomeV6Type bt = getBiome(v3POS(x, node_min.Y, z));
		s16 heat = m_emerge->env->m_use_weather ? m_emerge->env->getServerMap().updateBlockHeat(m_emerge->env, v3POS(x,node_max.Y,z), nullptr, &heat_cache) : 0;

		// Fill ground with stone
		v3s16 em = vm->m_area.getExtent();
		u32 i = vm->m_area.index(x, node_min.Y, z);
		for (s16 y = node_min.Y; y <= node_max.Y; y++) {
			if (vm->m_data[i].getContent() == CONTENT_IGNORE) {
				if (y <= surface_y) {
					vm->m_data[i] = (y >= MGV6_DESERT_STONE_BASE - surface_y
							&& bt == BT_DESERT) ?
						n_desert_stone : n_stone;
				} else if (y <= water_level) {
					vm->m_data[i] = ((heat < 0 && y > heat/3) || (y >= MGV6_ICE_BASE
							&& bt == BT_TUNDRA)) ?
						n_ice : n_water_source;
					if (liquid_pressure && y <= 0)
						vm->m_data[i].addLevel(m_emerge->ndef, water_level - y, 1);
				} else {
					vm->m_data[i] = n_air;
				}
			}
			vm->m_area.add_y(em, i, 1);
		}
	}

	return stone_surface_max_y;
}
Beispiel #9
0
int Mapgen_features::float_islands_generate(const v3POS & node_min, const v3POS & node_max, int min_y, MMVManip *vm) {
    int generated = 0;
    if (node_min.Y < min_y) return generated;
    // originally from http://forum.minetest.net/viewtopic.php?id=4776
    float RAR = 0.8 * farscale(0.4, node_min.Y); // 0.4; // Island rarity in chunk layer. -0.4 = thick layer with holes, 0 = 50%, 0.4 = desert rarity, 0.7 = very rare.
    float AMPY = 24; // 24; // Amplitude of island centre y variation.
    float TGRAD = 24; // 24; // Noise gradient to create top surface. Tallness of island top.
    float BGRAD = 24; // 24; // Noise gradient to create bottom surface. Tallness of island bottom.

    v3POS p0(node_min.X, node_min.Y, node_min.Z);

    float xl = node_max.X - node_min.X;
    float yl = node_max.Y - node_min.Y;
    float zl = node_max.Z - node_min.Z;
    u32 zstride = xl + y_offset;
    float midy = node_min.Y + yl * 0.5;
    u32 index = 0;
    for (int z1 = 0; z1 <= zl; ++z1)
        for (int y1 = 0; y1 <= yl; ++y1)
            for (int x1 = 0; x1 <= xl; ++x1, ++index) {
                int y = y1 + node_min.Y;
                u32 index2d = z1 * zstride + x1;
                float noise3 = noise_float_islands3->result[index2d];
                float pmidy = midy + noise3 / 1.5 * AMPY;
                float noise1 = noise_float_islands1->result[index];
                float offset = y > pmidy ? (y - pmidy) / TGRAD : (pmidy - y) / BGRAD;
                float noise1off = noise1 - offset - RAR;
                if (noise1off > 0 && noise1off < 0.7) {
                    float noise2 = noise_float_islands2->result[index];
                    if (noise2 - noise1off > -0.7) {
                        v3POS p = p0 + v3POS(x1, y1, z1);
                        u32 i = vm->m_area.index(p);
                        if (!vm->m_area.contains(i))
                            continue;
                        // Cancel if not  air
                        if (vm->m_data[i].getContent() != CONTENT_AIR)
                            continue;
                        vm->m_data[i] = layers_get(index);
                        ++generated;
                    }
                }
            }
    return generated;
}
Beispiel #10
0
	virtual void trigger(ServerEnvironment *env, v3POS p, MapNode n,
	                     u32 active_object_count, u32 active_object_count_wider, MapNode neighbor, bool activate) {
		ServerMap *map = &env->getServerMap();
		INodeDefManager *ndef = env->getGameDef()->ndef();

		float heat = map->updateBlockHeat(env, p);
		//heater = rare
		content_t c = map->getNodeTry(p - v3POS(0,  -1, 0 )).getContent(); // top
		//more chance to freeze if air at top
		static int water_level = g_settings->getS16("water_level");
		bool top_liquid = ndef->get(n).liquid_type > LIQUID_NONE && p.Y > water_level;
		int freeze = ((ItemGroupList) ndef->get(n).groups)["freeze"];
		if (heat <= freeze - 1 && ((!top_liquid && (activate || (heat <= freeze - 50))) || heat <= freeze - 50 ||
		                           (myrand_range(freeze - 50, heat) <= (freeze + (top_liquid ? -42 : c == CONTENT_AIR ? -10 : -40))))) {
			content_t c_self = n.getContent();
			// making freeze not annoying, do not freeze random blocks in center of ocean
			// todo: any block not water (dont freeze _source near _flowing)
			bool allow = activate || heat < freeze - 40;
			// todo: make for(...)
			if (!allow) {
				c = map->getNodeTry(p - v3POS(0,  1, 0 )).getContent(); // below
				if (c == CONTENT_AIR || c == CONTENT_IGNORE)
					if (ndef->get(n.getContent()).liquid_type == LIQUID_FLOWING || ndef->get(n.getContent()).liquid_type == LIQUID_SOURCE)
						return; // do not freeze when falling
				if (c != c_self && c != CONTENT_IGNORE) allow = 1;
				if (!allow) {
					c = map->getNodeTry(p - v3POS(1,  0, 0 )).getContent(); // right
					if (c != c_self && c != CONTENT_IGNORE) allow = 1;
					if (!allow) {
						c = map->getNodeTry(p - v3POS(-1, 0, 0 )).getContent(); // left
						if (c != c_self && c != CONTENT_IGNORE) allow = 1;
						if (!allow) {
							c = map->getNodeTry(p - v3POS(0,  0, 1 )).getContent(); // back
							if (c != c_self && c != CONTENT_IGNORE) allow = 1;
							if (!allow) {
								c = map->getNodeTry(p - v3POS(0,  0, -1)).getContent(); // front
								if (c != c_self && c != CONTENT_IGNORE) allow = 1;
							}
						}
					}
				}
			}
			if (allow) {
				n.freeze_melt(ndef, -1);
				map->setNode(p, n);
			}
		}
	}
Beispiel #11
0
void MapgenV7::generateBaseTerrain(s16 *stone_surface_min_y, s16 *stone_surface_max_y)
{
	MapNode n_air(CONTENT_AIR);
	MapNode n_stone(c_stone);
	MapNode n_water(c_water_source);
	MapNode n_ice(c_ice);

	v3s16 em = vm->m_area.getExtent();
	s16 surface_min_y = MAX_MAP_GENERATION_LIMIT;
	s16 surface_max_y = -MAX_MAP_GENERATION_LIMIT;
	u32 index = 0;

	for (s16 z = node_min.Z; z <= node_max.Z; z++)
	for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
		float surface_height = baseTerrainLevelFromMap(index);
		s16 surface_y = (s16)surface_height;

		heightmap[index]       = surface_y;
		ridge_heightmap[index] = surface_y;

		if (surface_y < surface_min_y)
			surface_min_y = surface_y;

		if (surface_y > surface_max_y)
			surface_max_y = surface_y;

		s16 heat = m_emerge->env->m_use_weather ? m_emerge->env->getServerMap().updateBlockHeat(m_emerge->env, v3POS(x,node_max.Y,z), nullptr, &heat_cache) : 0;

		u32 i = vm->m_area.index(x, node_min.Y - 1, z);
		for (s16 y = node_min.Y - 1; y <= node_max.Y + 1; y++) {
			if (vm->m_data[i].getContent() == CONTENT_IGNORE) {
				if (y <= surface_y) {

					int index3 = (z - node_min.Z) * zstride +
						(y - node_min.Y + 1) * ystride +
						(x - node_min.X);

					vm->m_data[i] = layers_get(index3);
				}
				else if (y <= water_level)
				{
					vm->m_data[i] = (heat < 0 && y > heat/3) ? n_ice : n_water;
					if (liquid_pressure && y <= 0)
						vm->m_data[i].addLevel(m_emerge->ndef, water_level - y, 1);
				}
				else
					vm->m_data[i] = n_air;
			}
			vm->m_area.add_y(em, i, 1);
		}
	}

	*stone_surface_min_y = surface_min_y;
	*stone_surface_max_y = surface_max_y;
}
Beispiel #12
0
bool Map::propagateSunlight(v3POS pos, std::set<v3POS> & light_sources,
                            bool remove_light) {
	MapBlock *block = getBlockNoCreateNoEx(pos);

	INodeDefManager *nodemgr = m_gamedef->ndef();

	// Whether the sunlight at the top of the bottom block is valid
	bool block_below_is_valid = true;

	v3POS pos_relative = block->getPosRelative();

	for(s16 x = 0; x < MAP_BLOCKSIZE; ++x) {
		for(s16 z = 0; z < MAP_BLOCKSIZE; ++z) {
			bool no_sunlight = false;

			// Check if node above block has sunlight

			MapNode n = getNode(pos_relative + v3POS(x, MAP_BLOCKSIZE, z));
			if (n) {
				if(n.getLight(LIGHTBANK_DAY, m_gamedef->ndef()) != LIGHT_SUN) {
					no_sunlight = true;
				}
			} else {

				// NOTE: This makes over-ground roofed places sunlighted
				// Assume sunlight, unless is_underground==true
				if(block->getIsUnderground()) {
					no_sunlight = true;
				} else {
					MapNode n = block->getNode(v3POS(x, MAP_BLOCKSIZE - 1, z));
					if(n && m_gamedef->ndef()->get(n).sunlight_propagates == false)
						no_sunlight = true;
				}
				// NOTE: As of now, this just would make everything dark.
				// No sunlight here
				//no_sunlight = true;
			}

			s16 y = MAP_BLOCKSIZE - 1;

			// This makes difference to diminishing in water.
			//bool stopped_to_solid_object = false;

			u8 current_light = no_sunlight ? 0 : LIGHT_SUN;

			for(; y >= 0; --y) {
				v3POS pos(x, y, z);
				MapNode n = block->getNode(pos);

				if(current_light == 0) {
					// Do nothing
				} else if(current_light == LIGHT_SUN && nodemgr->get(n).sunlight_propagates) {
					// Do nothing: Sunlight is continued
				} else if(nodemgr->get(n).light_propagates == false) {
					// A solid object is on the way.
					//stopped_to_solid_object = true;

					// Light stops.
					current_light = 0;
				} else {
					// Diminish light
					current_light = diminish_light(current_light);
				}

				u8 old_light = n.getLight(LIGHTBANK_DAY, nodemgr);

				if(current_light > old_light || remove_light) {
					n.setLight(LIGHTBANK_DAY, current_light, nodemgr);
					block->setNode(pos, n);
				}

				if(diminish_light(current_light) != 0) {
					light_sources.insert(pos_relative + pos);
				}

			}

			// Whether or not the block below should see LIGHT_SUN
			bool sunlight_should_go_down = (current_light == LIGHT_SUN);

			/*
				If the block below hasn't already been marked invalid:

				Check if the node below the block has proper sunlight at top.
				If not, the block below is invalid.

				Ignore non-transparent nodes as they always have no light
			*/

			if(block_below_is_valid) {
				MapNode n = getNode(pos_relative + v3POS(x, -1, z));
				if (n) {
					if(nodemgr->get(n).light_propagates) {
						if(n.getLight(LIGHTBANK_DAY, nodemgr) == LIGHT_SUN
						        && sunlight_should_go_down == false)
							block_below_is_valid = false;
						else if(n.getLight(LIGHTBANK_DAY, nodemgr) != LIGHT_SUN
						        && sunlight_should_go_down == true)
							block_below_is_valid = false;
					}
				} else {
					// Just no block below, no need to panic.
				}
			}
		}
	}

	return block_below_is_valid;
}
Beispiel #13
0
int MapgenMath::generateTerrain() {

	MapNode n_ice(c_ice);
	u32 index = 0;
	v3POS em = vm->m_area.getExtent();
	auto zstride_1d = csize.X * (csize.Y + 1);
	/* debug
	v3f vec0 = (v3f(node_min.X, node_min.Y, node_min.Z) - center) * scale ;
	errorstream << " X=" << node_min.X << " Y=" << node_min.Y << " Z=" << node_min.Z
	            //<< " N="<< mengersponge(vec0.X, vec0.Y, vec0.Z, distance, iterations)
	            << " N=" << (*func)(vec0.X, vec0.Y, vec0.Z, distance, iterations)
	            << " Sc=" << scale << " gen=" << params["generator"].asString() << " J=" << Json::FastWriter().write(params) << std::endl;
	*/
	//errorstream << Json::StyledWriter().write( mg_params->params ).c_str()<< std::endl;
	//errorstream << " iterations="<<iterations<< " scale="<<scale <<" invert="<<invert<< std::endl;

#if USE_MANDELBULBER
	v3f vec0(node_min.X, node_min.Y, node_min.Z);
	vec0 = (vec0 - center) * scale;
	/*
		errorstream << " X=" << node_min.X << " Y=" << node_min.Y << " Z=" << node_min.Z
		            << " N=" << Compute<normal_mode>(CVector3(vec0.X, vec0.Y, vec0.Z), mg_params->par)
		            //<<" F="<< Compute<fake_AO>(CVector3(node_min.X,node_min.Y,node_min.Z), par)
		            //<<" L="<<node_min.getLength()<< " -="<<node_min.getLength() - Compute<normal_mode>(CVector3(node_min.X,node_min.Y,node_min.Z), par)
		            << " Sc=" << scale << " internal=" << internal
		            << std::endl;
	*/
#endif

	double d = 0;
	for (s16 z = node_min.Z; z <= node_max.Z; z++) {
		for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
			s16 heat = m_emerge->env->m_use_weather ? m_emerge->env->getServerMap().updateBlockHeat(m_emerge->env, v3POS(x,node_max.Y,z), nullptr, &heat_cache) : 0;

			u32 i = vm->m_area.index(x, node_min.Y, z);
			for (s16 y = node_min.Y; y <= node_max.Y; y++) {
				v3f vec = (v3f(x, y, z) - center) * scale ;
				if (invert_xy)
					std::swap(vec.X, vec.Y);
				if (invert_yz)
					std::swap(vec.Y, vec.Z);

#if USE_MANDELBULBER
				if (!internal)
					d = Compute<normal_mode>(CVector3(vec.X, vec.Y, vec.Z), mg_params->par);
				else
#endif
				if (internal)
					d = (*func)(vec.X, vec.Y, vec.Z, scale.X, iterations);
				if ((!invert && d > 0) || (invert && d == 0)  ) {
					if (!vm->m_data[i]) {
						//vm->m_data[i] = (y > water_level + biome->filler) ?
						//     MapNode(biome->c_filler) : n_stone;
						if (invert) {
							int index3 = (z - node_min.Z) * zstride_1d +
								(y - node_min.Y) * ystride +
								(x - node_min.X);
							vm->m_data[i] = Mapgen_features::layers_get(index3);
						} else {
							vm->m_data[i] = layers_get(d, result_max);
						}
//						vm->m_data[i] = (y > water_level + biome->filler) ?
//						     MapNode(biome->c_filler) : layers_get(d, result_max);

					}
				} else if (y <= water_level) {
					vm->m_data[i] = (heat < 0 && y > heat/3) ? n_ice : n_water;
				} else {
					vm->m_data[i] = n_air;
				}
				vm->m_area.add_y(em, i, 1);
			}
		}
	}
	return 0;
}
Beispiel #14
0
};

struct NodeNeighbor {
	MapNode node;
	NeighborType type;
	v3POS pos;
	content_t content;
	bool liquid; //can liquid
	bool infinity;
	int weight;
	int drop; //drop by liquid
};

const v3POS liquid_flow_dirs[7] = {
	// +right, +top, +back
	v3POS( 0, -1, 0), // 0 bottom
	v3POS( 0, 0, 0), // 1 self
	v3POS( 0, 0, 1), // 2 back
	v3POS( 0, 0, -1), // 3 front
	v3POS( 1, 0, 0), // 4 right
	v3POS(-1, 0, 0), // 5 left
	v3POS( 0, 1, 0)  // 6 top
};

// when looking around we must first check self node for correct type definitions
const s8 liquid_explore_map[7] = {1, 0, 6, 2, 3, 4, 5};
const s8 liquid_random_map[4][7] = {
	{0, 1, 2, 3, 4, 5, 6},
	{0, 1, 4, 3, 5, 2, 6},
	{0, 1, 3, 5, 4, 2, 6},
	{0, 1, 5, 3, 2, 4, 6}
Beispiel #15
0
MgStoneType MapgenV7::generateBiomes(float *heat_map, float *humidity_map)
{
	v3s16 em = vm->m_area.getExtent();
	u32 index = 0;
	MgStoneType stone_type = STONE;

	for (s16 z = node_min.Z; z <= node_max.Z; z++)
	for (s16 x = node_min.X; x <= node_max.X; x++, index++) {
		Biome *biome = NULL;
		u16 depth_top = 0;
		u16 base_filler = 0;
		u16 depth_water_top = 0;
		u32 vi = vm->m_area.index(x, node_max.Y, z);

		// Check node at base of mapchunk above, either a node of a previously
		// generated mapchunk or if not, a node of overgenerated base terrain.
		content_t c_above = vm->m_data[vi + em.X].getContent();
		bool air_above = c_above == CONTENT_AIR;
		bool water_above = c_above == c_water_source;

		// If there is air or water above enable top/filler placement, otherwise force
		// nplaced to stone level by setting a number exceeding any possible filler depth.
		u16 nplaced = (air_above || water_above) ? 0 : U16_MAX;

		s16 heat = m_emerge->env->m_use_weather ? m_emerge->env->getServerMap().updateBlockHeat(m_emerge->env, v3POS(x,node_max.Y,z), NULL, &heat_cache) : 0;

		for (s16 y = node_max.Y; y >= node_min.Y; y--) {
			content_t c = vm->m_data[vi].getContent();

			bool cc_stone = (c != CONTENT_AIR && c != c_water_source && c != CONTENT_IGNORE);

			// Biome is recalculated each time an upper surface is detected while
			// working down a column. The selected biome then remains in effect for
			// all nodes below until the next surface and biome recalculation.
			// Biome is recalculated:
			// 1. At the surface of stone below air or water.
			// 2. At the surface of water below air.
			// 3. When stone or water is detected but biome has not yet been calculated.
			if ((cc_stone && (air_above || water_above || !biome)) ||
					(c == c_water_source && (air_above || !biome))) {
				biome = bmgr->getBiome(heat_map[index], humidity_map[index], y);
				depth_top = biome->depth_top;
				base_filler = MYMAX(depth_top + biome->depth_filler
						+ noise_filler_depth->result[index], 0);
				depth_water_top = biome->depth_water_top;

				// Detect stone type for dungeons during every biome calculation.
				// This is more efficient than detecting per-node and will not
				// miss any desert stone or sandstone biomes.
				if (biome->c_stone == c_desert_stone)
					stone_type = DESERT_STONE;
				else if (biome->c_stone == c_sandstone)
					stone_type = SANDSTONE;
			}

			if (cc_stone && biome && (c == biome->c_ice || c == biome->c_water || c == biome->c_water_top))
				cc_stone = false;

			if (cc_stone) {
				content_t c_below = vm->m_data[vi - em.X].getContent();

				// If the node below isn't solid, make this node stone, so that
				// any top/filler nodes above are structurally supported.
				// This is done by aborting the cycle of top/filler placement
				// immediately by forcing nplaced to stone level.
				if (c_below == CONTENT_AIR || c_below == c_water_source)
					nplaced = U16_MAX;

				if (nplaced < depth_top) {
					vm->m_data[vi] = MapNode(
								((y < water_level) /* && (biome->c_top == c_dirt_with_grass)*/ )
									? biome->c_top
									: heat < -3
										? biome->c_top_cold
										: biome->c_top);

					nplaced++;
				} else if (nplaced < base_filler) {
					vm->m_data[vi] = MapNode(biome->c_filler);
					nplaced++;
				} else if (nplaced < (depth_top+base_filler+depth_water_top)){
					vm->m_data[vi] = MapNode(biome->c_stone);
				}

				air_above = false;
				water_above = false;
			} else if (c == c_water_source) {
				bool ice = heat < 0 && y > water_level + heat/4;
				vm->m_data[vi] = MapNode((y > (s32)(water_level - depth_water_top)) ?
						(ice ? biome->c_ice : biome->c_water_top) : ice ? biome->c_ice : biome->c_water);
				nplaced = 0;  // Enable top/filler placement for next surface
				air_above = false;
				water_above = true;
			} else if (c == CONTENT_AIR) {
				nplaced = 0;  // Enable top/filler placement for next surface
				air_above = true;
				water_above = false;
			} else {  // Possible various nodes overgenerated from neighbouring mapchunks
				nplaced = U16_MAX;  // Disable top/filler placement
				air_above = false;
				water_above = false;
			}

			vm->m_area.add_y(em, vi, -1);
		}
	}

	return stone_type;
}
Beispiel #16
0
void MapgenV7::generateRidgeTerrain()
{
	if (node_max.Y < water_level)
		return;

	MapNode n_water(c_water_source);
	MapNode n_ice(c_ice);
	MapNode n_air(CONTENT_AIR);
	u32 index = 0;
	float width = 0.2; // TODO: figure out acceptable perlin noise values

	for (s16 z = node_min.Z; z <= node_max.Z; z++)
	for (s16 y = node_min.Y - 1; y <= node_max.Y + 1; y++) {
		u32 vi = vm->m_area.index(node_min.X, y, z);
		for (s16 x = node_min.X; x <= node_max.X; x++, index++, vi++) {
			int j = (z - node_min.Z) * csize.X + (x - node_min.X);

			if (heightmap[j] < water_level - 16)
				continue;

			float uwatern = noise_ridge_uwater->result[j] * 2;
			if (fabs(uwatern) > width)
				continue;

			float altitude = y - water_level;
			float height_mod = (altitude + 17) / 2.5;
			float width_mod  = width - fabs(uwatern);
			float nridge = noise_ridge->result[index] * MYMAX(altitude, 0) / 7.0;

			if (nridge + width_mod * height_mod < 0.6)
				continue;

			if (y < ridge_heightmap[j])
				ridge_heightmap[j] = y - 1;

			s16 heat = m_emerge->env->m_use_weather ? m_emerge->env->getServerMap().updateBlockHeat(m_emerge->env, v3POS(x,node_max.Y,z), NULL, &heat_cache) : 0;
			MapNode n_water_or_ice = (heat < 0 && y > water_level + heat/4) ? n_ice : n_water;

			vm->m_data[vi] = (y > water_level) ? n_air : n_water_or_ice;
		}
	}
}
Beispiel #17
0
int RemoteClient::GetNextBlocks (
		ServerEnvironment *env,
		EmergeManager * emerge,
		float dtime,
		double m_uptime,
		std::vector<PrioritySortedBlockTransfer> &dest)
{
	DSTACK(FUNCTION_NAME);

	auto lock = lock_unique_rec();
	if (!lock->owns_lock())
		return 0;

	// Increment timers
	m_nothing_to_send_pause_timer -= dtime;
	m_nearest_unsent_reset_timer += dtime;
	m_time_from_building += dtime;

	if (m_nearest_unsent_reset) {
		m_nearest_unsent_reset = 0;
		m_nearest_unsent_reset_timer = 999;
		m_nothing_to_send_pause_timer = 0;
		m_time_from_building = 999;
	}

	if(m_nothing_to_send_pause_timer >= 0)
		return 0;

	Player *player = env->getPlayer(peer_id);
	// This can happen sometimes; clients and players are not in perfect sync.
	if(player == NULL)
		return 0;

	v3f playerpos = player->getPosition();
	v3f playerspeed = player->getSpeed();
	if(playerspeed.getLength() > 1000.0*BS) //cheater or bug, ignore him
		return 0;
	v3f playerspeeddir(0,0,0);
	if(playerspeed.getLength() > 1.0*BS)
		playerspeeddir = playerspeed / playerspeed.getLength();
	// Predict to next block
	v3f playerpos_predicted = playerpos + playerspeeddir*MAP_BLOCKSIZE*BS;

	v3s16 center_nodepos = floatToInt(playerpos_predicted, BS);

	v3s16 center = getNodeBlockPos(center_nodepos);

	// Camera position and direction
	v3f camera_pos = player->getEyePosition();
	v3f camera_dir = v3f(0,0,1);
	camera_dir.rotateYZBy(player->getPitch());
	camera_dir.rotateXZBy(player->getYaw());

	//infostream<<"camera_dir=("<<camera_dir<<")"<< " camera_pos="<<camera_pos<<std::endl;

	/*
		Get the starting value of the block finder radius.
	*/

	if(m_last_center != center)
	{
		m_last_center = center;
		m_nearest_unsent_reset_timer = 999;
	}

	if (m_last_direction.getDistanceFrom(camera_dir)>0.4) { // 1 = 90deg
		m_last_direction = camera_dir;
		m_nearest_unsent_reset_timer = 999;
	}

	/*infostream<<"m_nearest_unsent_reset_timer="
			<<m_nearest_unsent_reset_timer<<std::endl;*/

	// Reset periodically to workaround for some bugs or stuff
	if(m_nearest_unsent_reset_timer > 120.0)
	{
		m_nearest_unsent_reset_timer = 0;
		m_nearest_unsent_d = 0;
		m_nearest_unsent_reset = 0;
		//infostream<<"Resetting m_nearest_unsent_d for "<<peer_id<<std::endl;
	}

	//s16 last_nearest_unsent_d = m_nearest_unsent_d;
	s16 d_start = m_nearest_unsent_d;

	//infostream<<"d_start="<<d_start<<std::endl;

	static const u16 max_simul_sends_setting = g_settings->getU16
			("max_simultaneous_block_sends_per_client");
	static const u16 max_simul_sends_usually = max_simul_sends_setting;

	/*
		Check the time from last addNode/removeNode.

		Decrease send rate if player is building stuff.
	*/
	static const auto full_block_send_enable_min_time_from_building = g_settings->getFloat("full_block_send_enable_min_time_from_building");
	if(m_time_from_building < full_block_send_enable_min_time_from_building)
	{
		/*
		max_simul_sends_usually
			= LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
		*/
		if(d_start<=1)
			d_start=2;
		m_nearest_unsent_reset_timer = 999; //magical number more than ^ other number 120 - need to reset d on next iteration
	}

	/*
		Number of blocks sending + number of blocks selected for sending
	*/
	u32 num_blocks_selected = 0;
	u32 num_blocks_sending = 0;

	/*
		next time d will be continued from the d from which the nearest
		unsent block was found this time.

		This is because not necessarily any of the blocks found this
		time are actually sent.
	*/
	s32 new_nearest_unsent_d = -1;

	static const auto max_block_send_distance = g_settings->getS16("max_block_send_distance");
	s16 full_d_max = max_block_send_distance;
	if (wanted_range) {
		s16 wanted_blocks = wanted_range / MAP_BLOCKSIZE + 1;
		if (wanted_blocks < full_d_max)
			full_d_max = wanted_blocks;
	}

	s16 d_max = full_d_max;
	static const s16 d_max_gen = g_settings->getS16("max_block_generate_distance");

	// Don't loop very much at a time
	s16 max_d_increment_at_time = 10;
	if(d_max > d_start + max_d_increment_at_time)
		d_max = d_start + max_d_increment_at_time;
	/*if(d_max_gen > d_start+2)
		d_max_gen = d_start+2;*/

	//infostream<<"Starting from "<<d_start<<std::endl;

	s32 nearest_emerged_d = -1;
	s32 nearest_emergefull_d = -1;
	s32 nearest_sent_d = -1;
	//bool queue_is_full = false;

	f32 speed_in_blocks = (playerspeed/(MAP_BLOCKSIZE*BS)).getLength();


	int blocks_occlusion_culled = 0;
	static const bool server_occlusion = g_settings->getBool("server_occlusion");
	bool occlusion_culling_enabled = server_occlusion;

	auto cam_pos_nodes = floatToInt(playerpos, BS);

	auto nodemgr = env->getGameDef()->getNodeDefManager();
	MapNode n;
	{
#if !ENABLE_THREADS
		auto lock = env->getServerMap().m_nothread_locker.lock_shared_rec();
#endif
		n = env->getMap().getNodeTry(cam_pos_nodes);
	}

	if(n && nodemgr->get(n).solidness == 2)
		occlusion_culling_enabled = false;

	unordered_map_v3POS<bool> occlude_cache;


	s16 d;
	for(d = d_start; d <= d_max; d++) {
		/*errorstream<<"checking d="<<d<<" for "
				<<server->getPlayerName(peer_id)<<std::endl;*/
		//infostream<<"RemoteClient::SendBlocks(): d="<<d<<" d_start="<<d_start<<" d_max="<<d_max<<" d_max_gen="<<d_max_gen<<std::endl;

		std::vector<v3POS> list;
		if (d > 2 && d == d_start && m_nearest_unsent_reset_timer != 999) { // oops, again magic number from up ^
			list.push_back(v3POS(0,0,0));
		}

		bool can_skip = d > 1;
		// Fast fall/move optimize. speed_in_blocks now limited to 6.4
		if (speed_in_blocks>0.8 && d <= 2) {
			can_skip = false;
			if (d == 0) {
				for(s16 addn = 0; addn < (speed_in_blocks+1)*2; ++addn)
					list.push_back(floatToInt(playerspeeddir*addn, 1));
			} else if (d == 1) {
				for(s16 addn = 0; addn < (speed_in_blocks+1)*1.5; ++addn) {
					list.push_back(floatToInt(playerspeeddir*addn, 1) + v3POS( 0,  0,  1)); // back
					list.push_back(floatToInt(playerspeeddir*addn, 1) + v3POS( -1, 0,  0)); // left
					list.push_back(floatToInt(playerspeeddir*addn, 1) + v3POS( 1,  0,  0)); // right
					list.push_back(floatToInt(playerspeeddir*addn, 1) + v3POS( 0,  0, -1)); // front
				}
			} else if (d == 2) {
				for(s16 addn = 0; addn < (speed_in_blocks+1)*1.5; ++addn) {
					list.push_back(floatToInt(playerspeeddir*addn, 1) + v3POS( -1, 0,  1)); // back left
					list.push_back(floatToInt(playerspeeddir*addn, 1) + v3POS( 1,  0,  1)); // left right
					list.push_back(floatToInt(playerspeeddir*addn, 1) + v3POS( -1, 0, -1)); // right left
					list.push_back(floatToInt(playerspeeddir*addn, 1) + v3POS( 1,  0, -1)); // front right
				}
			}
		} else {
		/*
			Get the border/face dot coordinates of a "d-radiused"
			box
		*/
			list = FacePositionCache::getFacePositions(d);
		}


		for(auto li=list.begin(); li!=list.end(); ++li)
		{
			v3POS p = *li + center;

			/*
				Send throttling
				- Don't allow too many simultaneous transfers
				- EXCEPT when the blocks are very close

				Also, don't send blocks that are already flying.
			*/

			// Start with the usual maximum
			u16 max_simul_dynamic = max_simul_sends_usually;

			// If block is very close, allow full maximum
			if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
				max_simul_dynamic = max_simul_sends_setting;

			// Don't select too many blocks for sending
			if (num_blocks_selected + num_blocks_sending >= max_simul_dynamic) {
				//queue_is_full = true;
				goto queue_full_break;
			}

			/*
				Do not go over-limit
			*/
			if (blockpos_over_limit(p))
				continue;

			// If this is true, inexistent block will be made from scratch
			bool generate = d <= d_max_gen;

			{
				/*// Limit the generating area vertically to 2/3
				if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
					generate = false;*/

				/* maybe good idea (if not use block culling) but brokes far (25+) area generate by flooding emergequeue with no generate blocks
				// Limit the send area vertically to 1/2
				if(can_skip && abs(p.Y - center.Y) > full_d_max / 2)
					generate = false;
				*/
			}


			//infostream<<"d="<<d<<std::endl;
			/*
				Don't generate or send if not in sight
				FIXME This only works if the client uses a small enough
				FOV setting. The default of 72 degrees is fine.
			*/

			float camera_fov = ((fov+5)*M_PI/180) * 4./3.;
			if(can_skip && isBlockInSight(p, camera_pos, camera_dir, camera_fov, 10000*BS) == false)
			{
				continue;
			}

			/*
				Don't send already sent blocks
			*/
			unsigned int block_sent = 0;
			{
				auto lock = m_blocks_sent.lock_shared_rec();
				block_sent = m_blocks_sent.find(p) != m_blocks_sent.end() ? m_blocks_sent.get(p) : 0;
			}
			if(block_sent > 0 && (/* (block_overflow && d>1) || */ block_sent + (d <= 2 ? 1 : d*d*d) > m_uptime)) {
				continue;
			}

			/*
				Check if map has this block
			*/

			MapBlock *block;
			{
#if !ENABLE_THREADS
			auto lock = env->getServerMap().m_nothread_locker.lock_shared_rec();
#endif

			block = env->getMap().getBlockNoCreateNoEx(p);
			}

			bool surely_not_found_on_disk = false;
			bool block_is_invalid = false;
			if(block != NULL)
			{

				if (d > 3 && block->content_only == CONTENT_AIR) {
					continue;
				}

				if (block_sent > 0 && block_sent >= block->m_changed_timestamp) {
					continue;
				}

		if (occlusion_culling_enabled) {
			ScopeProfiler sp(g_profiler, "SMap: Occusion calls");
			//Occlusion culling
			auto cpn = p*MAP_BLOCKSIZE;

			// No occlusion culling when free_move is on and camera is
			// inside ground
			cpn += v3POS(MAP_BLOCKSIZE/2, MAP_BLOCKSIZE/2, MAP_BLOCKSIZE/2);

			float step = 1;
			float stepfac = 1.3;
			float startoff = 5;
			float endoff = -MAP_BLOCKSIZE;
			v3POS spn = cam_pos_nodes + v3POS(0,0,0);
			s16 bs2 = MAP_BLOCKSIZE/2 + 1;
			u32 needed_count = 1;
#if !ENABLE_THREADS
			auto lock = env->getServerMap().m_nothread_locker.lock_shared_rec();
#endif
			//VERY BAD COPYPASTE FROM clientmap.cpp!
			if( d >= 1 &&
				occlusion_culling_enabled &&
				isOccluded(&env->getMap(), spn, cpn + v3POS(0,0,0),
					step, stepfac, startoff, endoff, needed_count, nodemgr, occlude_cache) &&
				isOccluded(&env->getMap(), spn, cpn + v3POS(bs2,bs2,bs2),
					step, stepfac, startoff, endoff, needed_count, nodemgr, occlude_cache) &&
				isOccluded(&env->getMap(), spn, cpn + v3POS(bs2,bs2,-bs2),
					step, stepfac, startoff, endoff, needed_count, nodemgr, occlude_cache) &&
				isOccluded(&env->getMap(), spn, cpn + v3POS(bs2,-bs2,bs2),
					step, stepfac, startoff, endoff, needed_count, nodemgr, occlude_cache) &&
				isOccluded(&env->getMap(), spn, cpn + v3POS(bs2,-bs2,-bs2),
					step, stepfac, startoff, endoff, needed_count, nodemgr, occlude_cache) &&
				isOccluded(&env->getMap(), spn, cpn + v3POS(-bs2,bs2,bs2),
					step, stepfac, startoff, endoff, needed_count, nodemgr, occlude_cache) &&
				isOccluded(&env->getMap(), spn, cpn + v3POS(-bs2,bs2,-bs2),
					step, stepfac, startoff, endoff, needed_count, nodemgr, occlude_cache) &&
				isOccluded(&env->getMap(), spn, cpn + v3POS(-bs2,-bs2,bs2),
					step, stepfac, startoff, endoff, needed_count, nodemgr, occlude_cache) &&
				isOccluded(&env->getMap(), spn, cpn + v3POS(-bs2,-bs2,-bs2),
					step, stepfac, startoff, endoff, needed_count, nodemgr, occlude_cache)
			)
			{
				//infostream<<" occlusion player="<<cam_pos_nodes<<" d="<<d<<" block="<<cpn<<" total="<<blocks_occlusion_culled<<"/"<<num_blocks_selected<<std::endl;
				g_profiler->add("SMap: Occlusion skip", 1);
				blocks_occlusion_culled++;
				continue;
			}
		}

				// Reset usage timer, this block will be of use in the future.
				block->resetUsageTimer();

				if (block->getLightingExpired()) {
					//env->getServerMap().lighting_modified_blocks.set(p, nullptr);
					env->getServerMap().lighting_modified_add(p, d);
				}

				if (block->lighting_broken > 0 && (block_sent || d > 0))
					continue;

				// Block is valid if lighting is up-to-date and data exists
				if(block->isValid() == false)
				{
					block_is_invalid = true;
				}

				if(block->isGenerated() == false)
				{
					continue;
				}

				/*
					If block is not close, don't send it unless it is near
					ground level.

					Block is near ground level if night-time mesh
					differs from day-time mesh.
				*/
/*
				if(d >= 4)
				{
					if(block->getDayNightDiff() == false)
						continue;
				}
*/
			}

			/*
				If block has been marked to not exist on disk (dummy)
				and generating new ones is not wanted, skip block.
			*/
			if(generate == false && surely_not_found_on_disk == true)
			{
				// get next one.
				continue;
			}

			/*
				Add inexistent block to emerge queue.
			*/
			if(block == NULL || surely_not_found_on_disk || block_is_invalid)
			{
				//infostream<<"start gen d="<<d<<" p="<<p<<" notfound="<<surely_not_found_on_disk<<" invalid="<< block_is_invalid<<" block="<<block<<" generate="<<generate<<std::endl;

				if (emerge->enqueueBlockEmerge(peer_id, p, generate)) {
					if (nearest_emerged_d == -1)
						nearest_emerged_d = d;
				} else {
					if (nearest_emergefull_d == -1)
						nearest_emergefull_d = d;
					goto queue_full_break;
				}

				// get next one.
				continue;
			}

			if(nearest_sent_d == -1)
				nearest_sent_d = d;

			/*
				Add block to send queue
			*/

			PrioritySortedBlockTransfer q((float)d, p, peer_id);

			dest.push_back(q);

			num_blocks_selected += 1;
		}
	}
queue_full_break:

	//infostream<<"Stopped at "<<d<<" d_start="<<d_start<< " d_max="<<d_max<<" nearest_emerged_d="<<nearest_emerged_d<<" nearest_emergefull_d="<<nearest_emergefull_d<< " new_nearest_unsent_d="<<new_nearest_unsent_d<< " sel="<<num_blocks_selected<< "+"<<num_blocks_sending << " culled=" << blocks_occlusion_culled <<" cEN="<<occlusion_culling_enabled<<std::endl;
	num_blocks_selected += num_blocks_sending;
	if(!num_blocks_selected && d_start <= d) {
		//new_nearest_unsent_d = 0;
		m_nothing_to_send_pause_timer = 1.0;
	}
		

	// If nothing was found for sending and nothing was queued for
	// emerging, continue next time browsing from here
	if(nearest_emerged_d != -1){
		new_nearest_unsent_d = nearest_emerged_d;
	} else if(nearest_emergefull_d != -1){
		new_nearest_unsent_d = nearest_emergefull_d;
	} else {
		if(d > full_d_max){
			new_nearest_unsent_d = 0;
			m_nothing_to_send_pause_timer = 1.0;
		} else {
			if(nearest_sent_d != -1)
				new_nearest_unsent_d = nearest_sent_d;
			else
				new_nearest_unsent_d = d;
		}
	}

	if(new_nearest_unsent_d != -1)
		m_nearest_unsent_d = new_nearest_unsent_d;
	return num_blocks_selected - num_blocks_sending;
}
Beispiel #18
0
void CircuitElement::findConnectedWithFace(std::vector <std::pair <std::list<CircuitElement>::iterator, u8> >& connected,
        Map* map, INodeDefManager* ndef, v3POS pos, u8 face,
        std::map<v3POS, std::list<CircuitElement>::iterator>& pos_to_iterator,
        bool connected_faces[6]) {
	static v3POS directions[6] = {v3POS(0, 1, 0),
	                              v3POS(0, -1, 0),
	                              v3POS(1, 0, 0),
	                              v3POS(-1, 0, 0),
	                              v3POS(0, 0, 1),
	                              v3POS(0, 0, -1),
	                             };
	// First - wire pos, second - acceptable faces
	std::queue <std::pair <v3POS, u8> > q;
	v3POS current_pos, next_pos;
	MapNode next_node, current_node;
	// used[pos] = or of all faces, that are already processed
	std::map <v3POS, u8> used;
	u8 face_id = FACE_TO_SHIFT(face);
	connected_faces[face_id] = true;
	used[pos] = face;
	current_node = map->getNodeNoEx(pos);
	const ContentFeatures& first_node_features = ndef->get(current_node);
	face = rotateFace(current_node, first_node_features, face);
	face_id = FACE_TO_SHIFT(face);

	current_pos = pos + directions[face_id];
	current_node = map->getNodeNoEx(current_pos);
	const ContentFeatures& current_node_features = ndef->get(current_node);
	u8 real_face = revRotateFace(current_node, current_node_features, face);
	u8 real_face_id = FACE_TO_SHIFT(real_face);

	if(current_node_features.is_wire || current_node_features.is_wire_connector) {
		q.push(std::make_pair(current_pos, current_node_features.wire_connections[real_face_id]));

		while(!q.empty()) {
			current_pos = q.front().first;
			u8 acceptable_faces = q.front().second;
			q.pop();
			current_node = map->getNodeNoEx(current_pos);
			const ContentFeatures& current_node_features = ndef->get(current_node);

			for(int i = 0; i < 6; ++i) {
				u8 real_face = revRotateFace(current_node, current_node_features, SHIFT_TO_FACE(i));
				if(acceptable_faces & real_face) {
					used[current_pos] |= real_face;
					next_pos = current_pos + directions[i];
					next_node = map->getNodeNoEx(next_pos);
					const ContentFeatures& node_features = ndef->get(next_node);
					u8 next_real_face = revRotateFace(next_node, node_features, OPPOSITE_FACE(SHIFT_TO_FACE(i)));
					u8 next_real_shift = FACE_TO_SHIFT(next_real_face);

					// If start element, mark some of it's faces
					if(next_pos == pos) {
						connected_faces[next_real_shift] = true;
					}

					auto next_used_iterator = used.find(next_pos);
					bool is_part_of_circuit = node_features.is_wire_connector || node_features.is_circuit_element ||
						(node_features.is_wire && (next_node.getContent() == current_node.getContent()));
					bool not_used = (next_used_iterator == used.end()) ||
						!(next_used_iterator->second & next_real_face);

					if(is_part_of_circuit && not_used) {
						if(node_features.is_circuit_element) {
							connected.push_back(std::make_pair(pos_to_iterator[next_pos], next_real_shift));
						} else {
							q.push(std::make_pair(next_pos, node_features.wire_connections[next_real_shift]));
						}

						if(next_used_iterator != used.end()) {
							next_used_iterator->second |= next_real_face;
						} else {
							used[next_pos] = next_real_face;
						}
					}
				}
			}
		}
	} else if(current_node_features.is_circuit_element) {
		connected.push_back(std::make_pair(pos_to_iterator[current_pos], OPPOSITE_SHIFT(real_face_id)));
	}
}
Beispiel #19
0
void MapgenV6::placeTreesAndJungleGrass()
{
	//TimeTaker t("placeTrees");

	PseudoRandom grassrandom(blockseed + 53);

	content_t c_sand            = ndef->getId("mapgen_sand");

	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
		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
		);

		// Get biome at center position of part of division
		BiomeV6Type bt = getBiome(v3POS(p2d_center.X, node_min.Y, p2d_center.Y));

		// Amount of trees
		float humidity = getHumidity(v3POS(p2d_center.X, node_max.Y, p2d_center.Y));
		s32 tree_count;
		if (bt == BT_JUNGLE || bt == BT_TAIGA || bt == BT_NORMAL) {
			tree_count = area * getTreeAmount(p2d_center) * ((humidity + 1)/2.0);
			if (bt == BT_JUNGLE)
				tree_count *= 4;
		} else {
			tree_count = 0;
		}

		if (node_max.Y < water_level)
			tree_count /= 2;

		// Add jungle grass
		if (bt == BT_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);
/* wtf
				int mapindex = central_area_size.X * (z - node_min.Z)
								+ (x - node_min.X);
				s16 y = heightmap[mapindex];
*/
				s16 y = findGroundLevelFull(v2s16(x, z));
				if (y < water_level)
					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 (s32 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);
/* wtf
			int mapindex = central_area_size.X * (z - node_min.Z)
							+ (x - node_min.X);
			s16 y = heightmap[mapindex];
*/
			s16 y = findGroundLevelFull(v2s16(x, z));

			// Don't make a tree under water level
			// 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 and snowblock
			{
				u32 i = vm->m_area.index(p);
				content_t c = vm->m_data[i].getContent();
				if (c != c_dirt &&
						c != c_dirt_with_grass &&
						c != c_dirt_with_snow &&
						c != c_snowblock &&
						(y >= water_level || c != c_sand))
					continue;
			}
			p.Y++;

			// Make a tree
			if (y < water_level) {
				if (y < water_level - 20) // do not spawn trees in lakes
					treegen::make_cavetree(*vm, p, bt == BT_JUNGLE, ndef, myrand());
			} else if (bt == BT_JUNGLE) {
				treegen::make_jungletree(*vm, p, ndef, myrand());
			} else if (bt == BT_TAIGA) {
				treegen::make_pine_tree(*vm, p - v3s16(0, 1, 0), ndef, myrand());
			} else if (bt == BT_NORMAL) {
				bool is_apple_tree = (myrand_range(0, 3) == 0) &&
							getHaveAppleTree(v2s16(x, z));
				treegen::make_tree(*vm, p, is_apple_tree, ndef, myrand());
			}
		}
	}
	//printf("placeTreesAndJungleGrass: %dms\n", t.stop());
}
Beispiel #20
0
void MinimapUpdateThread::getMap(v3POS pos, s16 size, s16 scan_height, bool is_radar) {
	v3POS p(pos.X - size / 2, pos.Y, pos.Z - size / 2);

	v3POS blockpos_player, relpos;
	getNodeBlockPosWithOffset(pos, blockpos_player, relpos);

	for (s16 x = 0; x < size; x++)
		for (s16 z = 0; z < size; z++) {
			auto mmpixel = &data->minimap_scan[x + z * size];
			mmpixel->air_count = 0;
			mmpixel->id = CONTENT_AIR;

			v3POS pos(p.X + x, p.Y, p.Z + z);
			v3POS blockpos_max, blockpos_min;
			getNodeBlockPosWithOffset(v3POS(pos.X, pos.Y - scan_height / 2, pos.Z), blockpos_min, relpos);
			getNodeBlockPosWithOffset(v3POS(pos.X, pos.Y + scan_height / 2, pos.Z), blockpos_max, relpos);

			s16 pixel_height = 0;
			s16 height = scan_height - MAP_BLOCKSIZE;

			v2POS top_block_xz(blockpos_max.X, blockpos_max.Z);

			if (!getmap_cache.count(top_block_xz)) {
				getmap_cache.emplace(std::piecewise_construct, std::forward_as_tuple(top_block_xz), std::forward_as_tuple());
				auto & vec = getmap_cache[top_block_xz];

/* simple:
				for (auto i = blockpos_max.Y; i > blockpos_min.Y - 1; --i) {
					auto it = m_blocks_cache.find(v3POS(blockpos_max.X, i, blockpos_max.Z));
					if (it == m_blocks_cache.end())
						continue;
					vec.emplace(i, it->second);
				}
*/
				int c = 0;
				for (auto i = blockpos_player.Y; i > blockpos_min.Y - 1; --i) {
					auto it = m_blocks_cache.find(v3POS(blockpos_max.X, i, blockpos_max.Z));
					if (it == m_blocks_cache.end())
						continue;
					vec.emplace(c++, it->second);
				}
				for (auto i = blockpos_max.Y; i > blockpos_player.Y; --i) {
					auto it = m_blocks_cache.find(v3POS(blockpos_max.X, i, blockpos_max.Z));
					if (it == m_blocks_cache.end())
						continue;
					vec.emplace(c++, it->second);
				}
			}

			//simple: for (auto & mmblock : getmap_cache[top_block_xz]) {
			for (auto & it : getmap_cache[top_block_xz]) {
				auto & mmblock = it.second;
				auto pixel = &mmblock->data[relpos.Z * MAP_BLOCKSIZE + relpos.X];
				mmpixel->air_count += pixel->air_count;
				if (pixel->id != CONTENT_AIR) {
					pixel_height = height + pixel->height;
					mmpixel->id = pixel->id;
					mmpixel->height = pixel_height;
					if (!is_radar)
						break;
				}
				height -= MAP_BLOCKSIZE;
			}
		}
}