|
@@ -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. |
|
|
LightQueue disappearing_lights(256); |
|
|
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. |
|
|
|
|
|
// 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 */); |
|
|
} |
|
|
// 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; |
|
|
} 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); |
|
|
} |
|
|
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]; |
|
|