/* Lights neighbors of from_nodes, collects all them and then goes on recursively. NOTE: This is faster on small areas but will overflow the stack on large areas. Thus it is not used. */ void VoxelManipulator::spreadLight(enum LightBank bank, core::map<v3s16, bool> & from_nodes) { if(from_nodes.size() == 0) return; core::map<v3s16, bool> lighted_nodes; core::map<v3s16, bool>::Iterator j; j = from_nodes.getIterator(); for(; j.atEnd() == false; j++) { v3s16 pos = j.getNode()->getKey(); spreadLight(bank, pos); } }
/* Lights neighbors of from_nodes, collects all them and then goes on recursively. */ void VoxelManipulator::spreadLight(enum LightBank bank, std::set<v3s16> & from_nodes, INodeDefManager *nodemgr) { const 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.empty()) return; std::set<v3s16> lighted_nodes; for(std::set<v3s16>::iterator j = from_nodes.begin(); j != from_nodes.end(); ++j) { v3s16 pos = *j; VoxelArea voxel_area(pos - v3s16(1,1,1), pos + v3s16(1,1,1)); addArea(voxel_area); u32 i = m_area.index(pos); if(m_flags[i] & VOXELFLAG_NO_DATA) continue; MapNode &n = m_data[i]; u8 oldlight = n.getLight(bank, nodemgr); u8 newlight = diminish_light(oldlight); // Loop through 6 neighbors for(u16 i=0; i<6; i++) { // Get the position of the neighbor node v3s16 n2pos = pos + dirs[i]; try { u32 n2i = m_area.index(n2pos); if(m_flags[n2i] & VOXELFLAG_NO_DATA) continue; MapNode &n2 = m_data[n2i]; u8 light2 = n2.getLight(bank, nodemgr); /* If the neighbor is brighter than the current node, add to list (it will light up this node on its turn) */ if(light2 > undiminish_light(oldlight)) { lighted_nodes.insert(n2pos); } /* If the neighbor is dimmer than how much light this node would spread on it, add to list */ if(light2 < newlight) { if(nodemgr->get(n2).light_propagates) { n2.setLight(bank, newlight, nodemgr); lighted_nodes.insert(n2pos); } } } catch(InvalidPositionException &e) { continue; } } } /*dstream<<"spreadLight(): Changed block " <<blockchangecount<<" times" <<" for "<<from_nodes.size()<<" nodes" <<std::endl;*/ if(!lighted_nodes.empty()) spreadLight(bank, lighted_nodes, nodemgr); }
void VoxelManipulator::spreadLight(enum LightBank bank, v3s16 p, INodeDefManager *nodemgr) { const 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); u32 i = m_area.index(p); if(m_flags[i] & VOXELFLAG_NO_DATA) return; MapNode &n = m_data[i]; u8 oldlight = n.getLight(bank, nodemgr); u8 newlight = diminish_light(oldlight); // 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]; u8 light2 = n2.getLight(bank, nodemgr); /* If the neighbor is brighter than the current node, add to list (it will light up this node on its turn) */ if(light2 > undiminish_light(oldlight)) { spreadLight(bank, n2pos, nodemgr); } /* If the neighbor is dimmer than how much light this node would spread on it, add to list */ if(light2 < newlight) { if(nodemgr->get(n2).light_propagates) { n2.setLight(bank, newlight, nodemgr); spreadLight(bank, n2pos, nodemgr); } } } }
/* Lights neighbors of from_nodes, collects all them and then goes on recursively. */ void VoxelManipulator::spreadLight(enum LightBank bank, core::map<v3s16, bool> & from_nodes, INodeDefManager *nodemgr) { const 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, bool> lighted_nodes; core::map<v3s16, bool>::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))); u32 i = m_area.index(pos); if(m_flags[i] & VOXELFLAG_INEXISTENT) continue; MapNode &n = m_data[i]; u8 oldlight = n.getLight(bank, nodemgr); u8 newlight = diminish_light(oldlight); // Loop through 6 neighbors for(u16 i=0; i<6; i++) { // Get the position of the neighbor node v3s16 n2pos = pos + dirs[i]; try { u32 n2i = m_area.index(n2pos); if(m_flags[n2i] & VOXELFLAG_INEXISTENT) continue; MapNode &n2 = m_data[n2i]; u8 light2 = n2.getLight(bank, nodemgr); /* If the neighbor is brighter than the current node, add to list (it will light up this node on its turn) */ if(light2 > undiminish_light(oldlight)) { lighted_nodes.insert(n2pos, true); } /* If the neighbor is dimmer than how much light this node would spread on it, add to list */ if(light2 < newlight) { if(nodemgr->get(n2).light_propagates) { n2.setLight(bank, newlight, nodemgr); lighted_nodes.insert(n2pos, true); } } } catch(InvalidPositionException &e) { continue; } } } /*dstream<<"spreadLight(): Changed block " <<blockchangecount<<" times" <<" for "<<from_nodes.size()<<" nodes" <<std::endl;*/ if(lighted_nodes.size() > 0) spreadLight(bank, lighted_nodes, nodemgr); }
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; }