Ejemplo n.º 1
0
/*
	Goes recursively through the neighbours of the node.

	Alters only transparent nodes.

	If the lighting of the neighbour is lower than the lighting of
	the node was (before changing it to 0 at the step before), the
	lighting of the neighbour is set to 0 and then the same stuff
	repeats for the neighbour.

	The ending nodes of the routine are stored in light_sources.
	This is useful when a light is removed. In such case, this
	routine can be called for the light node and then again for
	light_sources to re-light the area without the removed light.

	values of from_nodes are lighting values.
*/
void VoxelManipulator::unspreadLight(enum LightBank bank,
		std::map<v3s16, u8> & from_nodes,
		std::set<v3s16> & light_sources, INodeDefManager *nodemgr)
{
	if(from_nodes.empty())
		return;

	for(std::map<v3s16, u8>::iterator j = from_nodes.begin();
		j != from_nodes.end(); ++j)
	{
		unspreadLight(bank, j->first, j->second, light_sources, nodemgr);
	}
}
Ejemplo n.º 2
0
/*
	Goes recursively through the neighbours of the node.

	Alters only transparent nodes.

	If the lighting of the neighbour is lower than the lighting of
	the node was (before changing it to 0 at the step before), the
	lighting of the neighbour is set to 0 and then the same stuff
	repeats for the neighbour.

	The ending nodes of the routine are stored in light_sources.
	This is useful when a light is removed. In such case, this
	routine can be called for the light node and then again for
	light_sources to re-light the area without the removed light.

	values of from_nodes are lighting values.
*/
void VoxelManipulator::unspreadLight(enum LightBank bank,
		core::map<v3s16, u8> & from_nodes,
		core::map<v3s16, bool> & light_sources, INodeDefManager *nodemgr)
{
	if(from_nodes.size() == 0)
		return;
	
	core::map<v3s16, u8>::Iterator j;
	j = from_nodes.getIterator();

	for(; j.atEnd() == false; j++)
	{
		v3s16 pos = j.getNode()->getKey();
		
		//MapNode &n = m_data[m_area.index(pos)];
		
		u8 oldlight = j.getNode()->getValue();

		unspreadLight(bank, pos, oldlight, light_sources, nodemgr);
	}
}
Ejemplo n.º 3
0
void VoxelManipulator::unspreadLight(enum LightBank bank, v3s16 p, u8 oldlight,
		std::set<v3s16> & light_sources, INodeDefManager *nodemgr)
{
	v3s16 dirs[6] = {
		v3s16(0,0,1), // back
		v3s16(0,1,0), // top
		v3s16(1,0,0), // right
		v3s16(0,0,-1), // front
		v3s16(0,-1,0), // bottom
		v3s16(-1,0,0), // left
	};

	VoxelArea voxel_area(p - v3s16(1,1,1), p + v3s16(1,1,1));
	addArea(voxel_area);

	// Loop through 6 neighbors
	for(u16 i=0; i<6; i++)
	{
		// Get the position of the neighbor node
		v3s16 n2pos = p + dirs[i];

		u32 n2i = m_area.index(n2pos);

		if(m_flags[n2i] & VOXELFLAG_NO_DATA)
			continue;

		MapNode &n2 = m_data[n2i];

		/*
			If the neighbor is dimmer than what was specified
			as oldlight (the light of the previous node)
		*/
		u8 light2 = n2.getLight(bank, nodemgr);
		if(light2 < oldlight)
		{
			/*
				And the neighbor is transparent and it has some light
			*/
			if(nodemgr->get(n2).light_propagates && light2 != 0)
			{
				/*
					Set light to 0 and add to queue
				*/

				n2.setLight(bank, 0, nodemgr);

				unspreadLight(bank, n2pos, light2, light_sources, nodemgr);

				/*
					Remove from light_sources if it is there
					NOTE: This doesn't happen nearly at all
				*/
				/*if(light_sources.find(n2pos))
				{
					std::cout<<"Removed from light_sources"<<std::endl;
					light_sources.remove(n2pos);
				}*/
			}
		}
		else{
			light_sources.insert(n2pos);
		}
	}
}
Ejemplo n.º 4
0
/*
	Goes recursively through the neighbours of the node.

	Alters only transparent nodes.

	If the lighting of the neighbour is lower than the lighting of
	the node was (before changing it to 0 at the step before), the
	lighting of the neighbour is set to 0 and then the same stuff
	repeats for the neighbour.

	The ending nodes of the routine are stored in light_sources.
	This is useful when a light is removed. In such case, this
	routine can be called for the light node and then again for
	light_sources to re-light the area without the removed light.

	values of from_nodes are lighting values.
*/
void VoxelManipulator::unspreadLight(enum LightBank bank,
		core::map<v3s16, u8> & from_nodes,
		core::map<v3s16, bool> & light_sources)
{
	v3s16 dirs[6] = {
		v3s16(0,0,1), // back
		v3s16(0,1,0), // top
		v3s16(1,0,0), // right
		v3s16(0,0,-1), // front
		v3s16(0,-1,0), // bottom
		v3s16(-1,0,0), // left
	};
	
	if(from_nodes.size() == 0)
		return;
	
	core::map<v3s16, u8> unlighted_nodes;
	core::map<v3s16, u8>::Iterator j;
	j = from_nodes.getIterator();

	for(; j.atEnd() == false; j++)
	{
		v3s16 pos = j.getNode()->getKey();
		
		emerge(VoxelArea(pos - v3s16(1,1,1), pos + v3s16(1,1,1)));

		//MapNode &n = m_data[m_area.index(pos)];
		
		u8 oldlight = j.getNode()->getValue();
		
		// Loop through 6 neighbors
		for(u16 i=0; i<6; i++)
		{
			// Get the position of the neighbor node
			v3s16 n2pos = pos + dirs[i];
			
			u32 n2i = m_area.index(n2pos);

			if(m_flags[n2i] & VOXELFLAG_INEXISTENT)
				continue;

			MapNode &n2 = m_data[n2i];
			
			/*
				If the neighbor is dimmer than what was specified
				as oldlight (the light of the previous node)
			*/
			if(n2.getLight(bank, nodemgr) < oldlight)
			{
				/*
					And the neighbor is transparent and it has some light
				*/
				if(nodemgr->get(n2).light_propagates && n2.getLight(bank, nodemgr) != 0)
				{
					/*
						Set light to 0 and add to queue
					*/

					u8 current_light = n2.getLight(bank, nodemgr);
					n2.setLight(bank, 0);

					unlighted_nodes.insert(n2pos, current_light);
					
					/*
						Remove from light_sources if it is there
						NOTE: This doesn't happen nearly at all
					*/
					/*if(light_sources.find(n2pos))
					{
						std::cout<<"Removed from light_sources"<<std::endl;
						light_sources.remove(n2pos);
					}*/
				}
			}
			else{
				light_sources.insert(n2pos, true);
			}
		}
	}

	/*dstream<<"unspreadLight(): Changed block "
			<<blockchangecount<<" times"
			<<" for "<<from_nodes.size()<<" nodes"
			<<std::endl;*/
	
	if(unlighted_nodes.size() > 0)
		unspreadLight(bank, unlighted_nodes, light_sources);
}
Ejemplo n.º 5
0
u32 Map::updateLighting(concurrent_map<v3POS, MapBlock*> & a_blocks,
                        std::map<v3POS, MapBlock*> & modified_blocks, unsigned int max_cycle_ms) {
	INodeDefManager *nodemgr = m_gamedef->ndef();

	int ret = 0;
	int loopcount = 0;

	TimeTaker timer("updateLighting");

	// For debugging
	//bool debug=true;
	//u32 count_was = modified_blocks.size();

	//std::unordered_set<v3POS, v3POSHash, v3POSEqual> light_sources;
	//std::unordered_map<v3POS, u8, v3POSHash, v3POSEqual> unlight_from_day, unlight_from_night;
	std::set<v3POS> light_sources;
	std::map<v3POS, u8> unlight_from_day, unlight_from_night;
	unordered_map_v3POS<int> processed;


	int num_bottom_invalid = 0;

	//MutexAutoLock lock2(m_update_lighting_mutex);

#if !ENABLE_THREADS
	auto lock = m_nothread_locker.lock_unique_rec();
#endif

	{
		//TimeTaker t("updateLighting: first stuff");

		u32 end_ms = porting::getTimeMs() + max_cycle_ms;
		for(auto i = a_blocks.begin();
		        i != a_blocks.end(); ++i) {

			auto block = getBlockNoCreateNoEx(i->first);

			for(;;) {
				// Don't bother with dummy blocks.
				if(!block || block->isDummy())
					break;

				auto lock = block->try_lock_unique_rec();
				if (!lock->owns_lock())
					break; // may cause dark areas
				v3POS pos = block->getPos();
				if (processed.count(pos) && processed[pos] <= i->first.Y ) {
					break;
				}
				++loopcount;
				processed[pos] = i->first.Y;
				v3POS posnodes = block->getPosRelative();
				//modified_blocks[pos] = block;

				block->setLightingExpired(true);
				block->lighting_broken = true;

				/*
					Clear all light from block
				*/
				for(s16 z = 0; z < MAP_BLOCKSIZE; z++)
					for(s16 x = 0; x < MAP_BLOCKSIZE; x++)
						for(s16 y = 0; y < MAP_BLOCKSIZE; y++) {
							v3POS p(x, y, z);
							bool is_valid_position;
							MapNode n = block->getNode(p, &is_valid_position);
							if (!is_valid_position) {
								/* This would happen when dealing with a
								   dummy block.
								*/
								infostream << "updateLighting(): InvalidPositionException"
								           << std::endl;
								continue;
							}
							u8 oldlight_day = n.getLight(LIGHTBANK_DAY, nodemgr);
							u8 oldlight_night = n.getLight(LIGHTBANK_NIGHT, nodemgr);
							n.setLight(LIGHTBANK_DAY, 0, nodemgr);
							n.setLight(LIGHTBANK_NIGHT, 0, nodemgr);
							block->setNode(p, n);

							// If node sources light, add to list
							//u8 source = nodemgr->get(n).light_source;
							if(nodemgr->get(n).light_source)
								light_sources.insert(p + posnodes);

							v3POS p_map = p + posnodes;
							// Collect borders for unlighting
							if(x == 0 || x == MAP_BLOCKSIZE - 1
							        || y == 0 || y == MAP_BLOCKSIZE - 1
							        || z == 0 || z == MAP_BLOCKSIZE - 1) {
								if(oldlight_day)
									unlight_from_day[p_map] = oldlight_day;
								if(oldlight_night)
									unlight_from_night[p_map] = oldlight_night;
							}


						}

				lock->unlock();

				bool bottom_valid = propagateSunlight(pos, light_sources);

				if(!bottom_valid)
					num_bottom_invalid++;

				pos.Y--;
				block = getBlockNoCreateNoEx(pos);
			}

			if (porting::getTimeMs() > end_ms) {
				++ret;
				break;
			}
		}

	}

	{
		//TimeTaker timer("updateLighting: unspreadLight");
		unspreadLight(LIGHTBANK_DAY, unlight_from_day, light_sources, modified_blocks);
		unspreadLight(LIGHTBANK_NIGHT, unlight_from_night, light_sources, modified_blocks);
	}

	{
		//TimeTaker timer("updateLighting: spreadLight");
		spreadLight(LIGHTBANK_DAY, light_sources, modified_blocks, porting::getTimeMs() + max_cycle_ms * 10);
		spreadLight(LIGHTBANK_NIGHT, light_sources, modified_blocks, porting::getTimeMs() + max_cycle_ms * 10);
	}

	for (auto & i : processed) {
		a_blocks.erase(i.first);
		MapBlock *block = getBlockNoCreateNoEx(i.first);
		if(!block)
			continue;
		block->setLightingExpired(false);
		block->lighting_broken = false;
	}

	g_profiler->add("Server: light blocks", loopcount);

	return ret;

}