mirror of
				https://github.com/luanti-org/luanti.git
				synced 2025-11-04 01:05:48 +01:00 
			
		
		
		
	Use node lighting for liquid spreading
This commit modifies the liquid transforming procedure to light and unlight nodes instead of whole map blocks.
This commit is contained in:
		
							
								
								
									
										23
									
								
								src/map.cpp
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								src/map.cpp
									
									
									
									
									
								
							@@ -824,10 +824,15 @@ void Map::addNodeAndUpdate(v3s16 p, MapNode n,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Set the node on the map
 | 
			
		||||
	// Ignore light (because calling voxalgo::update_lighting_nodes)
 | 
			
		||||
	n.setLight(LIGHTBANK_DAY, 0, ndef);
 | 
			
		||||
	n.setLight(LIGHTBANK_NIGHT, 0, ndef);
 | 
			
		||||
	setNode(p, n);
 | 
			
		||||
 | 
			
		||||
	// Update lighting
 | 
			
		||||
	voxalgo::update_lighting_node(this, ndef, p, oldnode, modified_blocks);
 | 
			
		||||
	std::vector<std::pair<v3s16, MapNode> > oldnodes;
 | 
			
		||||
	oldnodes.push_back(std::pair<v3s16, MapNode>(p, oldnode));
 | 
			
		||||
	voxalgo::update_lighting_nodes(this, ndef, oldnodes, modified_blocks);
 | 
			
		||||
 | 
			
		||||
	for(std::map<v3s16, MapBlock*>::iterator
 | 
			
		||||
			i = modified_blocks.begin();
 | 
			
		||||
@@ -1224,7 +1229,9 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> &modified_blocks)
 | 
			
		||||
	std::deque<v3s16> must_reflow;
 | 
			
		||||
 | 
			
		||||
	// List of MapBlocks that will require a lighting update (due to lava)
 | 
			
		||||
	std::map<v3s16, MapBlock *> lighting_modified_blocks;
 | 
			
		||||
	std::map<v3s16, MapBlock *> lighting_modified_blocks2;
 | 
			
		||||
 | 
			
		||||
	std::vector<std::pair<v3s16, MapNode> > changed_nodes;
 | 
			
		||||
 | 
			
		||||
	u32 liquid_loop_max = g_settings->getS32("liquid_loop_max");
 | 
			
		||||
	u32 loop_max = liquid_loop_max;
 | 
			
		||||
@@ -1457,6 +1464,10 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> &modified_blocks)
 | 
			
		||||
		}
 | 
			
		||||
		n0.setContent(new_node_content);
 | 
			
		||||
 | 
			
		||||
		// Ignore light (because calling voxalgo::update_lighting_nodes)
 | 
			
		||||
		n0.setLight(LIGHTBANK_DAY, 0, nodemgr);
 | 
			
		||||
		n0.setLight(LIGHTBANK_NIGHT, 0, nodemgr);
 | 
			
		||||
 | 
			
		||||
		// Find out whether there is a suspect for this action
 | 
			
		||||
		std::string suspect;
 | 
			
		||||
		if (m_gamedef->rollback())
 | 
			
		||||
@@ -1484,9 +1495,10 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> &modified_blocks)
 | 
			
		||||
		if (block != NULL) {
 | 
			
		||||
			modified_blocks[blockpos] =  block;
 | 
			
		||||
			// If new or old node emits light, MapBlock requires lighting update
 | 
			
		||||
			if (nodemgr->get(n0).light_source != 0 ||
 | 
			
		||||
			/*if (nodemgr->get(n0).light_source != 0 ||
 | 
			
		||||
					nodemgr->get(n00).light_source != 0)
 | 
			
		||||
				lighting_modified_blocks[block->getPos()] = block;
 | 
			
		||||
				lighting_modified_blocks[block->getPos()] = block;*/
 | 
			
		||||
			changed_nodes.push_back(std::pair<v3s16, MapNode>(p0, n00));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
@@ -1515,7 +1527,8 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> &modified_blocks)
 | 
			
		||||
	for (std::deque<v3s16>::iterator iter = must_reflow.begin(); iter != must_reflow.end(); ++iter)
 | 
			
		||||
		m_transforming_liquid.push_back(*iter);
 | 
			
		||||
 | 
			
		||||
	updateLighting(lighting_modified_blocks, modified_blocks);
 | 
			
		||||
	//updateLighting(lighting_modified_blocks, modified_blocks);
 | 
			
		||||
	voxalgo::update_lighting_nodes(this, nodemgr, changed_nodes, modified_blocks);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	/* ----------------------------------------------------------------------
 | 
			
		||||
 
 | 
			
		||||
@@ -583,144 +583,153 @@ bool isSunlightAbove(Map *map, v3s16 pos, INodeDefManager *ndef)
 | 
			
		||||
 | 
			
		||||
static const LightBank banks[] = { LIGHTBANK_DAY, LIGHTBANK_NIGHT };
 | 
			
		||||
 | 
			
		||||
void update_lighting_node(Map *map, INodeDefManager *ndef, v3s16 p,
 | 
			
		||||
	MapNode oldnode, std::map<v3s16, MapBlock*> & modified_blocks)
 | 
			
		||||
void update_lighting_nodes(Map *map, INodeDefManager *ndef,
 | 
			
		||||
	std::vector<std::pair<v3s16, MapNode> > &oldnodes,
 | 
			
		||||
	std::map<v3s16, MapBlock*> & modified_blocks)
 | 
			
		||||
{
 | 
			
		||||
	// For node getter functions
 | 
			
		||||
	bool is_valid_position;
 | 
			
		||||
 | 
			
		||||
	// Get position and block of the changed node
 | 
			
		||||
	relative_v3 rel_pos;
 | 
			
		||||
	mapblock_v3 block_pos;
 | 
			
		||||
	getNodeBlockPosWithOffset(p, block_pos, rel_pos);
 | 
			
		||||
	MapBlock *block = map->getBlockNoCreateNoEx(block_pos);
 | 
			
		||||
	if (block == NULL || block->isDummy()) {
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Process each light bank separately
 | 
			
		||||
	for (s32 i = 0; i < 2; i++) {
 | 
			
		||||
		// Get the new node
 | 
			
		||||
		MapNode n = block->getNodeNoCheck(rel_pos, &is_valid_position);
 | 
			
		||||
		if (!is_valid_position) {
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		LightBank bank = banks[i];
 | 
			
		||||
		UnlightQueue disappearing_lights(256);
 | 
			
		||||
		ReLightQueue light_sources(256);
 | 
			
		||||
		// For each changed node process sunlight and initialize
 | 
			
		||||
		for (std::vector<std::pair<v3s16, MapNode> >::iterator it =
 | 
			
		||||
				oldnodes.begin(); it < oldnodes.end(); it++) {
 | 
			
		||||
			// Get position and block of the changed node
 | 
			
		||||
			v3s16 p = it->first;
 | 
			
		||||
			relative_v3 rel_pos;
 | 
			
		||||
			mapblock_v3 block_pos;
 | 
			
		||||
			getNodeBlockPosWithOffset(p, block_pos, rel_pos);
 | 
			
		||||
			MapBlock *block = map->getBlockNoCreateNoEx(block_pos);
 | 
			
		||||
			if (block == NULL || block->isDummy()) {
 | 
			
		||||
				continue;
 | 
			
		||||
			}
 | 
			
		||||
			// Get the new node
 | 
			
		||||
			MapNode n = block->getNodeNoCheck(rel_pos, &is_valid_position);
 | 
			
		||||
			if (!is_valid_position) {
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		// Light of the old node
 | 
			
		||||
		u8 old_light = oldnode.getLight(bank, ndef);
 | 
			
		||||
			// Light of the old node
 | 
			
		||||
			u8 old_light = it->second.getLight(bank, ndef);
 | 
			
		||||
 | 
			
		||||
		// Add the block of the added node to modified_blocks
 | 
			
		||||
		modified_blocks[block_pos] = block;
 | 
			
		||||
			// Add the block of the added node to modified_blocks
 | 
			
		||||
			modified_blocks[block_pos] = block;
 | 
			
		||||
 | 
			
		||||
		// Get new light level of the node
 | 
			
		||||
		u8 new_light = 0;
 | 
			
		||||
		if (ndef->get(n).light_propagates) {
 | 
			
		||||
			if (bank == LIGHTBANK_DAY && ndef->get(n).sunlight_propagates
 | 
			
		||||
			// Get new light level of the node
 | 
			
		||||
			u8 new_light = 0;
 | 
			
		||||
			if (ndef->get(n).light_propagates) {
 | 
			
		||||
				if (bank == LIGHTBANK_DAY && ndef->get(n).sunlight_propagates
 | 
			
		||||
					&& isSunlightAbove(map, p, ndef)) {
 | 
			
		||||
				new_light = LIGHT_SUN;
 | 
			
		||||
			} else {
 | 
			
		||||
				new_light = ndef->get(n).light_source;
 | 
			
		||||
				for (int i = 0; i < 6; i++) {
 | 
			
		||||
					v3s16 p2 = p + neighbor_dirs[i];
 | 
			
		||||
					bool is_valid;
 | 
			
		||||
					MapNode n2 = map->getNodeNoEx(p2, &is_valid);
 | 
			
		||||
					if (is_valid) {
 | 
			
		||||
						u8 spread = n2.getLight(bank, ndef);
 | 
			
		||||
						// If the neighbor is at least as bright as
 | 
			
		||||
						// this node then its light is not from
 | 
			
		||||
						// this node.
 | 
			
		||||
						// Its light can spread to this node.
 | 
			
		||||
						if (spread > new_light && spread >= old_light) {
 | 
			
		||||
							new_light = spread - 1;
 | 
			
		||||
					new_light = LIGHT_SUN;
 | 
			
		||||
				} else {
 | 
			
		||||
					new_light = ndef->get(n).light_source;
 | 
			
		||||
					for (int i = 0; i < 6; i++) {
 | 
			
		||||
						v3s16 p2 = p + neighbor_dirs[i];
 | 
			
		||||
						bool is_valid;
 | 
			
		||||
						MapNode n2 = map->getNodeNoEx(p2, &is_valid);
 | 
			
		||||
						if (is_valid) {
 | 
			
		||||
							u8 spread = n2.getLight(bank, ndef);
 | 
			
		||||
							// If the neighbor is at least as bright as
 | 
			
		||||
							// this node then its light is not from
 | 
			
		||||
							// this node.
 | 
			
		||||
							// Its light can spread to this node.
 | 
			
		||||
							if (spread > new_light && spread >= old_light) {
 | 
			
		||||
								new_light = spread - 1;
 | 
			
		||||
							}
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				// If this is an opaque node, it still can emit light.
 | 
			
		||||
				new_light = ndef->get(n).light_source;
 | 
			
		||||
			}
 | 
			
		||||
		} else {
 | 
			
		||||
			// If this is an opaque node, it still can emit light.
 | 
			
		||||
			new_light = ndef->get(n).light_source;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		ReLightQueue light_sources(256);
 | 
			
		||||
			if (new_light > 0) {
 | 
			
		||||
				light_sources.push(new_light, rel_pos, block_pos, block, 6);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
		if (new_light > 0) {
 | 
			
		||||
			light_sources.push(new_light, rel_pos, block_pos, block, 6);
 | 
			
		||||
		}
 | 
			
		||||
			if (new_light < old_light) {
 | 
			
		||||
				// The node became opaque or doesn't provide as much
 | 
			
		||||
				// light as the previous one, so it must be unlighted.
 | 
			
		||||
 | 
			
		||||
		if (new_light < old_light) {
 | 
			
		||||
			// The node became opaque or doesn't provide as much
 | 
			
		||||
			// light as the previous one, so it must be unlighted.
 | 
			
		||||
			LightQueue disappearing_lights(256);
 | 
			
		||||
				// Add to unlight queue
 | 
			
		||||
				n.setLight(bank, 0, ndef);
 | 
			
		||||
				block->setNodeNoCheck(rel_pos, n);
 | 
			
		||||
				disappearing_lights.push(old_light, rel_pos, block_pos, block,
 | 
			
		||||
					6);
 | 
			
		||||
 | 
			
		||||
			// Add to unlight queue
 | 
			
		||||
			n.setLight(bank, 0, ndef);
 | 
			
		||||
			block->setNodeNoCheck(rel_pos, n);
 | 
			
		||||
			disappearing_lights.push(old_light, rel_pos, block_pos, block, 6);
 | 
			
		||||
				// Remove sunlight, if there was any
 | 
			
		||||
				if (bank == LIGHTBANK_DAY && old_light == LIGHT_SUN) {
 | 
			
		||||
					for (s16 y = p.Y - 1;; y--) {
 | 
			
		||||
						v3s16 n2pos(p.X, y, p.Z);
 | 
			
		||||
 | 
			
		||||
			// Remove sunlight, if there was any
 | 
			
		||||
			if (bank == LIGHTBANK_DAY && old_light == LIGHT_SUN) {
 | 
			
		||||
				for (s16 y = p.Y - 1;; y--) {
 | 
			
		||||
					v3s16 n2pos(p.X, y, p.Z);
 | 
			
		||||
						MapNode n2;
 | 
			
		||||
 | 
			
		||||
					MapNode n2;
 | 
			
		||||
						n2 = map->getNodeNoEx(n2pos, &is_valid_position);
 | 
			
		||||
						if (!is_valid_position)
 | 
			
		||||
							break;
 | 
			
		||||
 | 
			
		||||
					n2 = map->getNodeNoEx(n2pos, &is_valid_position);
 | 
			
		||||
					if (!is_valid_position)
 | 
			
		||||
						break;
 | 
			
		||||
 | 
			
		||||
					// If this node doesn't have sunlight, the nodes below
 | 
			
		||||
					// it don't have too.
 | 
			
		||||
					if (n2.getLight(LIGHTBANK_DAY, ndef) != LIGHT_SUN) {
 | 
			
		||||
						break;
 | 
			
		||||
						// If this node doesn't have sunlight, the nodes below
 | 
			
		||||
						// it don't have too.
 | 
			
		||||
						if (n2.getLight(LIGHTBANK_DAY, ndef) != LIGHT_SUN) {
 | 
			
		||||
							break;
 | 
			
		||||
						}
 | 
			
		||||
						// Remove sunlight and add to unlight queue.
 | 
			
		||||
						n2.setLight(LIGHTBANK_DAY, 0, ndef);
 | 
			
		||||
						map->setNode(n2pos, n2);
 | 
			
		||||
						relative_v3 rel_pos2;
 | 
			
		||||
						mapblock_v3 block_pos2;
 | 
			
		||||
						getNodeBlockPosWithOffset(n2pos, block_pos2, rel_pos2);
 | 
			
		||||
						MapBlock *block2 = map->getBlockNoCreateNoEx(
 | 
			
		||||
							block_pos2);
 | 
			
		||||
						disappearing_lights.push(LIGHT_SUN, rel_pos2,
 | 
			
		||||
							block_pos2, block2,
 | 
			
		||||
							4 /* The node above caused the change */);
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			} else if (new_light > old_light) {
 | 
			
		||||
				// It is sure that the node provides more light than the previous
 | 
			
		||||
				// one, unlighting is not necessary.
 | 
			
		||||
				// Propagate sunlight
 | 
			
		||||
				if (bank == LIGHTBANK_DAY && new_light == LIGHT_SUN) {
 | 
			
		||||
					for (s16 y = p.Y - 1;; y--) {
 | 
			
		||||
						v3s16 n2pos(p.X, y, p.Z);
 | 
			
		||||
 | 
			
		||||
						MapNode n2;
 | 
			
		||||
 | 
			
		||||
						n2 = map->getNodeNoEx(n2pos, &is_valid_position);
 | 
			
		||||
						if (!is_valid_position)
 | 
			
		||||
							break;
 | 
			
		||||
 | 
			
		||||
						// This should not happen, but if the node has sunlight
 | 
			
		||||
						// then the iteration should stop.
 | 
			
		||||
						if (n2.getLight(LIGHTBANK_DAY, ndef) == LIGHT_SUN) {
 | 
			
		||||
							break;
 | 
			
		||||
						}
 | 
			
		||||
						// If the node terminates sunlight, stop.
 | 
			
		||||
						if (!ndef->get(n2).sunlight_propagates) {
 | 
			
		||||
							break;
 | 
			
		||||
						}
 | 
			
		||||
						relative_v3 rel_pos2;
 | 
			
		||||
						mapblock_v3 block_pos2;
 | 
			
		||||
						getNodeBlockPosWithOffset(n2pos, block_pos2, rel_pos2);
 | 
			
		||||
						MapBlock *block2 = map->getBlockNoCreateNoEx(
 | 
			
		||||
							block_pos2);
 | 
			
		||||
						// Mark node for lighting.
 | 
			
		||||
						light_sources.push(LIGHT_SUN, rel_pos2, block_pos2,
 | 
			
		||||
							block2, 4);
 | 
			
		||||
					}
 | 
			
		||||
					// Remove sunlight and add to unlight queue.
 | 
			
		||||
					n2.setLight(LIGHTBANK_DAY, 0, ndef);
 | 
			
		||||
					map->setNode(n2pos, n2);
 | 
			
		||||
					relative_v3 rel_pos2;
 | 
			
		||||
					mapblock_v3 block_pos2;
 | 
			
		||||
					getNodeBlockPosWithOffset(n2pos, block_pos2, rel_pos2);
 | 
			
		||||
					MapBlock *block2 = map->getBlockNoCreateNoEx(block_pos2);
 | 
			
		||||
					disappearing_lights.push(LIGHT_SUN, rel_pos2, block_pos2,
 | 
			
		||||
						block2, 4 /* The node above caused the change */);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			// Remove lights
 | 
			
		||||
			unspreadLight(map, ndef, bank, disappearing_lights, light_sources,
 | 
			
		||||
				modified_blocks);
 | 
			
		||||
		} else if (new_light > old_light) {
 | 
			
		||||
			// It is sure that the node provides more light than the previous
 | 
			
		||||
			// one, unlighting is not necessary.
 | 
			
		||||
			// Propagate sunlight
 | 
			
		||||
			if (bank == LIGHTBANK_DAY && new_light == LIGHT_SUN) {
 | 
			
		||||
				for (s16 y = p.Y - 1;; y--) {
 | 
			
		||||
					v3s16 n2pos(p.X, y, p.Z);
 | 
			
		||||
 | 
			
		||||
					MapNode n2;
 | 
			
		||||
 | 
			
		||||
					n2 = map->getNodeNoEx(n2pos, &is_valid_position);
 | 
			
		||||
					if (!is_valid_position)
 | 
			
		||||
						break;
 | 
			
		||||
 | 
			
		||||
					// This should not happen, but if the node has sunlight
 | 
			
		||||
					// then the iteration should stop.
 | 
			
		||||
					if (n2.getLight(LIGHTBANK_DAY, ndef) == LIGHT_SUN) {
 | 
			
		||||
						break;
 | 
			
		||||
					}
 | 
			
		||||
					// If the node terminates sunlight, stop.
 | 
			
		||||
					if (!ndef->get(n2).sunlight_propagates) {
 | 
			
		||||
						break;
 | 
			
		||||
					}
 | 
			
		||||
					relative_v3 rel_pos2;
 | 
			
		||||
					mapblock_v3 block_pos2;
 | 
			
		||||
					getNodeBlockPosWithOffset(n2pos, block_pos2, rel_pos2);
 | 
			
		||||
					MapBlock *block2 = map->getBlockNoCreateNoEx(block_pos2);
 | 
			
		||||
					// Mark node for lighting.
 | 
			
		||||
					light_sources.push(LIGHT_SUN, rel_pos2, block_pos2, block2,
 | 
			
		||||
						4);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		// Remove lights
 | 
			
		||||
		unspreadLight(map, ndef, bank, disappearing_lights, light_sources,
 | 
			
		||||
			modified_blocks);
 | 
			
		||||
		// Initialize light values for light spreading.
 | 
			
		||||
		for (u8 i = 0; i <= LIGHT_SUN; i++) {
 | 
			
		||||
			const std::vector<ChangingLight> &lights = light_sources.lights[i];
 | 
			
		||||
 
 | 
			
		||||
@@ -58,18 +58,19 @@ SunlightPropagateResult propagateSunlight(VoxelManipulator &v, VoxelArea a,
 | 
			
		||||
/*!
 | 
			
		||||
 * Updates the lighting on the map.
 | 
			
		||||
 * The result will be correct only if
 | 
			
		||||
 * no nodes were changed except the given one.
 | 
			
		||||
 * no nodes were changed except the given ones.
 | 
			
		||||
 * Before calling this procedure make sure that all new nodes on
 | 
			
		||||
 * the map have zero light level!
 | 
			
		||||
 *
 | 
			
		||||
 * \param p position of the changed node
 | 
			
		||||
 * \param oldnode this node was overwritten on the map
 | 
			
		||||
 * \param oldnodes contains the MapNodes that were replaced by the new
 | 
			
		||||
 * MapNodes and their positions
 | 
			
		||||
 * \param modified_blocks output, contains all map blocks that
 | 
			
		||||
 * the function modified
 | 
			
		||||
 */
 | 
			
		||||
void update_lighting_node(
 | 
			
		||||
void update_lighting_nodes(
 | 
			
		||||
	Map *map,
 | 
			
		||||
	INodeDefManager *ndef,
 | 
			
		||||
	v3s16 p,
 | 
			
		||||
	MapNode oldnode,
 | 
			
		||||
	std::vector<std::pair<v3s16, MapNode> > &oldnodes,
 | 
			
		||||
	std::map<v3s16, MapBlock*> &modified_blocks);
 | 
			
		||||
 | 
			
		||||
} // namespace voxalgo
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user