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; }
void PlayerSAO::step(float dtime, bool send_recommended) { if (!m_player) return; if(!m_properties_sent) { std::string str = getPropertyPacket(); // create message and add to list ActiveObjectMessage aom(getId(), true, str); m_messages_out.push(aom); m_properties_sent = true; } // If attached, check that our parent is still there. If it isn't, detach. if(m_attachment_parent_id && !isAttached()) { { auto lock = try_lock_unique_rec(); if (!lock->owns_lock()) goto NOLOCK1; m_attachment_parent_id = 0; m_attachment_bone = ""; m_attachment_position = v3f(0,0,0); m_attachment_rotation = v3f(0,0,0); } setBasePosition(m_last_good_position); ((Server*)m_env->getGameDef())->SendMovePlayer(m_peer_id); } NOLOCK1:; //dstream<<"PlayerSAO::step: dtime: "<<dtime<<std::endl; // Set lag pool maximums based on estimated lag const float LAG_POOL_MIN = 5.0; float lag_pool_max = m_env->getMaxLagEstimate() * 2.0; if(lag_pool_max < LAG_POOL_MIN) lag_pool_max = LAG_POOL_MIN; m_dig_pool.setMax(lag_pool_max); m_move_pool.setMax(lag_pool_max); // Increment cheat prevention timers m_dig_pool.add(dtime); m_move_pool.add(dtime); { auto lock = try_lock_unique_rec(); if (!lock->owns_lock()) goto NOLOCK2; m_time_from_last_punch += dtime; m_nocheat_dig_time += dtime; m_ms_from_last_respawn += dtime*1000; } NOLOCK2:; // Each frame, parent position is copied if the object is attached, otherwise it's calculated normally // If the object gets detached this comes into effect automatically from the last known origin if (isAttached()) { v3f pos = m_env->getActiveObject(m_attachment_parent_id)->getBasePosition(); m_last_good_position = pos; setBasePosition(pos); } if (!send_recommended) return; // If the object is attached client-side, don't waste bandwidth sending its position to clients if(m_position_not_sent && !isAttached()) { m_position_not_sent = false; float update_interval = m_env->getSendRecommendedInterval(); v3f pos, vel, acc; if(isAttached()) // Just in case we ever do send attachment position too pos = m_env->getActiveObject(m_attachment_parent_id)->getBasePosition(); else { pos = m_base_position + v3f(0,BS*1,0); vel = m_player->getSpeed(); } std::string str = gob_cmd_update_position( pos, vel, acc, m_yaw, true, false, update_interval ); // create message and add to list ActiveObjectMessage aom(getId(), false, str); m_messages_out.push(aom); } if (!m_armor_groups_sent) { m_armor_groups_sent = true; std::string str = gob_cmd_update_armor_groups( m_armor_groups); // create message and add to list ActiveObjectMessage aom(getId(), true, str); m_messages_out.push(aom); } if (!m_physics_override_sent) { auto lock = try_lock_unique_rec(); if (!lock->owns_lock()) goto NOLOCK3; m_physics_override_sent = true; std::string str = gob_cmd_update_physics_override(m_physics_override_speed, m_physics_override_jump, m_physics_override_gravity, m_physics_override_sneak, m_physics_override_sneak_glitch); // create message and add to list ActiveObjectMessage aom(getId(), true, str); m_messages_out.push(aom); } NOLOCK3:; if (!m_animation_sent) { auto lock = try_lock_unique_rec(); if (!lock->owns_lock()) goto NOLOCK4; m_animation_sent = true; std::string str = gob_cmd_update_animation( m_animation_range, m_animation_speed, m_animation_blend, m_animation_loop); // create message and add to list ActiveObjectMessage aom(getId(), true, str); m_messages_out.push(aom); } NOLOCK4:; if (!m_bone_position_sent) { m_bone_position_sent = true; for (UNORDERED_MAP<std::string, core::vector2d<v3f> >::const_iterator ii = m_bone_position.begin(); ii != m_bone_position.end(); ++ii) { std::string str = gob_cmd_update_bone_position((*ii).first, (*ii).second.X, (*ii).second.Y); // create message and add to list ActiveObjectMessage aom(getId(), true, str); m_messages_out.push(aom); } } if (!m_attachment_sent){ m_attachment_sent = true; std::string str = gob_cmd_update_attachment(m_attachment_parent_id, m_attachment_bone, m_attachment_position, m_attachment_rotation); // create message and add to list ActiveObjectMessage aom(getId(), true, str); m_messages_out.push(aom); } }
u32 Map::timerUpdate(float uptime, float unload_timeout, u32 max_loaded_blocks, unsigned int max_cycle_ms, std::vector<v3POS> *unloaded_blocks) { bool save_before_unloading = (mapType() == MAPTYPE_SERVER); // Profile modified reasons Profiler modprofiler; if (/*!m_blocks_update_last && */ m_blocks_delete->size() > 1000) { m_blocks_delete = (m_blocks_delete == &m_blocks_delete_1 ? &m_blocks_delete_2 : &m_blocks_delete_1); verbosestream << "Deleting blocks=" << m_blocks_delete->size() << std::endl; for (auto & ir : *m_blocks_delete) delete ir.first; m_blocks_delete->clear(); getBlockCacheFlush(); } u32 deleted_blocks_count = 0; u32 saved_blocks_count = 0; u32 block_count_all = 0; u32 n = 0, calls = 0, end_ms = porting::getTimeMs() + max_cycle_ms; std::vector<MapBlockP> blocks_delete; int save_started = 0; { auto lock = m_blocks.try_lock_shared_rec(); if (!lock->owns_lock()) return m_blocks_update_last; #if !ENABLE_THREADS auto lock_map = m_nothread_locker.try_lock_unique_rec(); if (!lock_map->owns_lock()) return m_blocks_update_last; #endif for(auto ir : m_blocks) { if (n++ < m_blocks_update_last) { continue; } else { m_blocks_update_last = 0; } ++calls; auto block = ir.second; if (!block) continue; { auto lock = block->try_lock_unique_rec(); if (!lock->owns_lock()) continue; if(block->getUsageTimer() > unload_timeout) { // block->refGet() <= 0 && v3POS p = block->getPos(); //infostream<<" deleting block p="<<p<<" ustimer="<<block->getUsageTimer() <<" to="<< unload_timeout<<" inc="<<(uptime - block->m_uptime_timer_last)<<" state="<<block->getModified()<<std::endl; // Save if modified if (block->getModified() != MOD_STATE_CLEAN && save_before_unloading) { //modprofiler.add(block->getModifiedReasonString(), 1); if(!save_started++) beginSave(); if (!saveBlock(block)) continue; saved_blocks_count++; } blocks_delete.push_back(block); if(unloaded_blocks) unloaded_blocks->push_back(p); deleted_blocks_count++; } else { #ifndef SERVER if (block->mesh_old) block->mesh_old = nullptr; #endif if (!block->m_uptime_timer_last) // not very good place, but minimum modifications block->m_uptime_timer_last = uptime - 0.1; block->incrementUsageTimer(uptime - block->m_uptime_timer_last); block->m_uptime_timer_last = uptime; block_count_all++; /*#ifndef SERVER if(block->refGet() == 0 && block->getUsageTimer() > g_settings->getFloat("unload_unused_meshes_timeout")) { if(block->mesh){ delete block->mesh; block->mesh = NULL; } } #endif*/ } } // block lock if (porting::getTimeMs() > end_ms) { m_blocks_update_last = n; break; } } } if(save_started) endSave(); if (!calls) m_blocks_update_last = 0; for (auto & block : blocks_delete) this->deleteBlock(block); // Finally delete the empty sectors if(deleted_blocks_count != 0) { if (m_blocks_update_last) infostream << "ServerMap: timerUpdate(): Blocks processed:" << calls << "/" << m_blocks.size() << " to " << m_blocks_update_last << std::endl; PrintInfo(infostream); // ServerMap/ClientMap: infostream << "Unloaded " << deleted_blocks_count << "/" << (block_count_all + deleted_blocks_count) << " blocks from memory"; infostream << " (deleteq1=" << m_blocks_delete_1.size() << " deleteq2=" << m_blocks_delete_2.size() << ")"; if(saved_blocks_count) infostream << ", of which " << saved_blocks_count << " were written"; /* infostream<<", "<<block_count_all<<" blocks in memory"; */ infostream << "." << std::endl; if(saved_blocks_count != 0) { PrintInfo(infostream); // ServerMap/ClientMap: //infostream<<"Blocks modified by: "<<std::endl; modprofiler.print(infostream); } } return m_blocks_update_last; }