Ejemplo n.º 1
0
			void reset() {
				if(owns_lock()) {
					ptr->unlock();
					IsLock=false;
				}
				ptr=0;
			}
Ejemplo n.º 2
0
//TODO: REMOVE THIS func and use Map::getBlock
MapBlock* Map::getBlockNoCreateNoEx(v3POS p, bool trylock, bool nocache) {

#ifndef NDEBUG
	ScopeProfiler sp(g_profiler, "Map: getBlock");
#endif

#if !ENABLE_THREADS
	nocache = true; //very dirty hack. fix and remove. Also compare speed: no cache and cache with lock
#endif

	if (!nocache) {
#if ENABLE_THREADS && !HAVE_THREAD_LOCAL
		auto lock = try_shared_lock(m_block_cache_mutex, TRY_TO_LOCK);
		if(lock.owns_lock())
#endif
			if(m_block_cache && p == m_block_cache_p) {
#ifndef NDEBUG
				g_profiler->add("Map: getBlock cache hit", 1);
#endif
				return m_block_cache;
			}
	}

	MapBlockP block;
	{
		auto lock = trylock ? m_blocks.try_lock_shared_rec() : m_blocks.lock_shared_rec();
		if (!lock->owns_lock())
			return nullptr;
		auto n = m_blocks.find(p);
		if(n == m_blocks.end())
			return nullptr;
		block = n->second;
	}

	if (!nocache) {
#if ENABLE_THREADS && !HAVE_THREAD_LOCAL
		auto lock = unique_lock(m_block_cache_mutex, TRY_TO_LOCK);
		if(lock.owns_lock())
#endif
		{
			m_block_cache_p = p;
			m_block_cache = block;
		}
	}

	return block;
}
Ejemplo n.º 3
0
void LuaABM::trigger(ServerEnvironment *env, v3s16 p, MapNode n,
		u32 active_object_count, u32 active_object_count_wider, MapNode neighbor, bool activate)
{
	GameScripting *scriptIface = env->getScriptIface();
	auto _script_lock = RecursiveMutexAutoLock(scriptIface->m_luastackmutex, std::try_to_lock);
	if (!_script_lock.owns_lock()) {
		return;
	}
	scriptIface->realityCheck();

	lua_State *L = scriptIface->getStack();
	sanity_check(lua_checkstack(L, 20));
	StackUnroller stack_unroller(L);

	int error_handler = PUSH_ERROR_HANDLER(L);

	// Get registered_abms
	lua_getglobal(L, "core");
	lua_getfield(L, -1, "registered_abms");
	luaL_checktype(L, -1, LUA_TTABLE);
	lua_remove(L, -2); // Remove core

	// Get registered_abms[m_id]
	lua_pushnumber(L, m_id);
	lua_gettable(L, -2);
	if(lua_isnil(L, -1))
		//FATAL_ERROR("");
		return;
	lua_remove(L, -2); // Remove registered_abms

	scriptIface->setOriginFromTable(-1);

	// Call action
	luaL_checktype(L, -1, LUA_TTABLE);
	lua_getfield(L, -1, "action");
	luaL_checktype(L, -1, LUA_TFUNCTION);
	lua_remove(L, -2); // Remove registered_abms[m_id]
	push_v3s16(L, p);
	pushnode(L, n, env->getGameDef()->ndef());
	lua_pushnumber(L, active_object_count);
	lua_pushnumber(L, active_object_count_wider);
	pushnode(L, neighbor, env->getGameDef()->ndef());
	lua_pushboolean(L, activate);

	int result = lua_pcall(L, 6, 0, error_handler);
	if (result)
		scriptIface->scriptError(result, "LuaABM::trigger");

	lua_pop(L, 1); // Pop error handler
}
Ejemplo n.º 4
0
void LuaLBM::trigger(ServerEnvironment *env, v3s16 p, MapNode n)
{
	GameScripting *scriptIface = env->getScriptIface();
	auto _script_lock = RecursiveMutexAutoLock(scriptIface->m_luastackmutex, std::try_to_lock);
	if (!_script_lock.owns_lock()) {
		return;
	}
	scriptIface->realityCheck();

	lua_State *L = scriptIface->getStack();
	sanity_check(lua_checkstack(L, 20));
	StackUnroller stack_unroller(L);

	int error_handler = PUSH_ERROR_HANDLER(L);

	// Get registered_lbms
	lua_getglobal(L, "core");
	lua_getfield(L, -1, "registered_lbms");
	luaL_checktype(L, -1, LUA_TTABLE);
	lua_remove(L, -2); // Remove core

	// Get registered_lbms[m_id]
	lua_pushnumber(L, m_id);
	lua_gettable(L, -2);
	//FATAL_ERROR_IF(lua_isnil(L, -1), "Entry with given id not found in registered_lbms table");
	if (lua_isnil(L, -1)) {
		errorstream << "Entry with given id " << m_id << " not found in registered_lbms table" << std::endl;
		return;
	}
	lua_remove(L, -2); // Remove registered_lbms

	scriptIface->setOriginFromTable(-1);

	// Call action
	luaL_checktype(L, -1, LUA_TTABLE);
	lua_getfield(L, -1, "action");
	luaL_checktype(L, -1, LUA_TFUNCTION);
	lua_remove(L, -2); // Remove registered_lbms[m_id]
	push_v3s16(L, p);
	pushnode(L, n, env->getGameDef()->ndef());

	int result = lua_pcall(L, 2, 0, error_handler);
	if (result)
		scriptIface->scriptError(result, "LuaLBM::trigger");

	lua_pop(L, 1); // Pop error handler
}
Ejemplo n.º 5
0
MapNode MapBlock::getNodeParent(v3s16 p, bool *is_valid_position)
{
	if (isValidPosition(p) == false)
		return m_parent->getNodeTry(getPosRelative() + p);

	if (data == NULL) {
		if (is_valid_position)
			*is_valid_position = false;
		return MapNode(CONTENT_IGNORE);
	}
	auto lock = try_lock_shared_rec();
	if (!lock->owns_lock()) {
		if (is_valid_position)
			*is_valid_position = false;
		return MapNode(CONTENT_IGNORE);
	}

	if (is_valid_position)
		*is_valid_position = true;
	return data[p.Z*MAP_BLOCKSIZE*MAP_BLOCKSIZE + p.Y*MAP_BLOCKSIZE + p.X];
}
Ejemplo n.º 6
0
	~elliptics_unique_lock()
	{
		if (owns_lock())
			unlock();
	}
Ejemplo n.º 7
0
void ClientMap::updateDrawList(video::IVideoDriver* driver, float dtime, unsigned int max_cycle_ms)
{
    ScopeProfiler sp(g_profiler, "CM::updateDrawList()", SPT_AVG);
    //g_profiler->add("CM::updateDrawList() count", 1);
    TimeTaker timer_step("ClientMap::updateDrawList");

    INodeDefManager *nodemgr = m_gamedef->ndef();

    if (!m_drawlist_last)
        m_drawlist_current = !m_drawlist_current;
    auto & drawlist = m_drawlist_current ? m_drawlist_1 : m_drawlist_0;

    if (!max_cycle_ms)
        max_cycle_ms = 300/getControl().fps_wanted;

    m_camera_mutex.Lock();
    v3f camera_position = m_camera_position;
    f32 camera_fov = m_camera_fov;
    //v3s16 camera_offset = m_camera_offset;
    m_camera_mutex.Unlock();

    // Use a higher fov to accomodate faster camera movements.
    // Blocks are cropped better when they are drawn.
    // Or maybe they aren't? Well whatever.
    camera_fov *= 1.2;

    v3s16 cam_pos_nodes = floatToInt(camera_position, BS);
    v3s16 box_nodes_d = m_control.wanted_range * v3s16(1,1,1);
    v3s16 p_nodes_min = cam_pos_nodes - box_nodes_d;
    v3s16 p_nodes_max = cam_pos_nodes + box_nodes_d;
    // Take a fair amount as we will be dropping more out later
    // Umm... these additions are a bit strange but they are needed.
    v3s16 p_blocks_min(
        p_nodes_min.X / MAP_BLOCKSIZE - 3,
        p_nodes_min.Y / MAP_BLOCKSIZE - 3,
        p_nodes_min.Z / MAP_BLOCKSIZE - 3);
    v3s16 p_blocks_max(
        p_nodes_max.X / MAP_BLOCKSIZE + 1,
        p_nodes_max.Y / MAP_BLOCKSIZE + 1,
        p_nodes_max.Z / MAP_BLOCKSIZE + 1);

    // Number of blocks in rendering range
    u32 blocks_in_range = 0;
    // Number of blocks occlusion culled
    u32 blocks_occlusion_culled = 0;
    // Number of blocks in rendering range but don't have a mesh
    u32 blocks_in_range_without_mesh = 0;
    // Blocks that had mesh that would have been drawn according to
    // rendering range (if max blocks limit didn't kick in)
    u32 blocks_would_have_drawn = 0;
    // Blocks that were drawn and had a mesh
    u32 blocks_drawn = 0;
    // Blocks which had a corresponding meshbuffer for this pass
    //u32 blocks_had_pass_meshbuf = 0;
    // Blocks from which stuff was actually drawn
    //u32 blocks_without_stuff = 0;
    // Distance to farthest drawn block
    float farthest_drawn = 0;
    int m_mesh_queued = 0;

    bool free_move = g_settings->getBool("free_move");

    float range_max = 100000 * BS;
    if(m_control.range_all == false)
        range_max = m_control.wanted_range * BS;

    if (draw_nearest.empty()) {
        //ScopeProfiler sp(g_profiler, "CM::updateDrawList() make list", SPT_AVG);
        TimeTaker timer_step("ClientMap::updateDrawList make list");

        auto lock = m_blocks.try_lock_shared_rec();
        if (!lock->owns_lock())
            return;

        draw_nearest.clear();

        for(auto & ir : m_blocks) {
            auto bp = ir.first;

            if(m_control.range_all == false)
            {
                if(bp.X < p_blocks_min.X
                        || bp.X > p_blocks_max.X
                        || bp.Z > p_blocks_max.Z
                        || bp.Z < p_blocks_min.Z
                        || bp.Y < p_blocks_min.Y
                        || bp.Y > p_blocks_max.Y)
                    continue;
            }

            v3s16 blockpos_nodes = bp * MAP_BLOCKSIZE;
            // Block center position
            v3f blockpos(
                ((float)blockpos_nodes.X + MAP_BLOCKSIZE/2) * BS,
                ((float)blockpos_nodes.Y + MAP_BLOCKSIZE/2) * BS,
                ((float)blockpos_nodes.Z + MAP_BLOCKSIZE/2) * BS
            );

            f32 d = radius_box(blockpos, camera_position); //blockpos_relative.getLength();
            if (d> range_max)
                continue;
            int range = d / (MAP_BLOCKSIZE * BS);
            draw_nearest.emplace_back(std::make_pair(bp, range));
        }
    }

    const int maxq = 1000;

    // No occlusion culling when free_move is on and camera is
    // inside ground
    bool occlusion_culling_enabled = true;
    if(free_move) {
        MapNode n = getNodeNoEx(cam_pos_nodes);
        if(n.getContent() == CONTENT_IGNORE ||
                nodemgr->get(n).solidness == 2)
            occlusion_culling_enabled = false;
    }

    u32 calls = 0, end_ms = porting::getTimeMs() + u32(max_cycle_ms);

    std::unordered_map<v3POS, bool, v3POSHash, v3POSEqual> occlude_cache;

    while (!draw_nearest.empty()) {
        auto ir = draw_nearest.back();

        auto bp = ir.first;
        int range = ir.second;
        draw_nearest.pop_back();
        ++calls;

        //auto block = getBlockNoCreateNoEx(bp);
        auto block = m_blocks.get(bp);
        if (!block)
            continue;

        int mesh_step = getFarmeshStep(m_control, getNodeBlockPos(cam_pos_nodes), bp);
        /*
        	Compare block position to camera position, skip
        	if not seen on display
        */

        auto mesh = block->getMesh(mesh_step);
        if (mesh)
            mesh->updateCameraOffset(m_camera_offset);

        blocks_in_range++;

        auto smesh_size = block->mesh_size;
        /*
        	Ignore if mesh doesn't exist
        */
        {
            if(!mesh) {
                blocks_in_range_without_mesh++;
                if (m_mesh_queued < maxq || range <= 2) {
                    m_client->addUpdateMeshTask(bp, false);
                    ++m_mesh_queued;
                }
                continue;
            }
            if(mesh_step == mesh->step && block->getTimestamp() <= mesh->timestamp && !smesh_size) {
                blocks_in_range_without_mesh++;
                continue;
            }
        }

        /*
        	Occlusion culling
        */

        v3s16 cpn = bp * MAP_BLOCKSIZE;
        cpn += v3s16(MAP_BLOCKSIZE/2, MAP_BLOCKSIZE/2, MAP_BLOCKSIZE/2);

        float step = BS*1;
        float stepfac = 1.2;
        float startoff = BS*1;
        float endoff = -BS*MAP_BLOCKSIZE; //*1.42; //*1.42;
        v3s16 spn = cam_pos_nodes + v3s16(0,0,0);
        s16 bs2 = MAP_BLOCKSIZE/2 + 1;
        u32 needed_count = 1;
        if( range > 1 && smesh_size &&
                occlusion_culling_enabled &&
                isOccluded(this, spn, cpn + v3s16(0,0,0),
                           step, stepfac, startoff, endoff, needed_count, nodemgr, occlude_cache) &&
                isOccluded(this, spn, cpn + v3s16(bs2,bs2,bs2),
                           step, stepfac, startoff, endoff, needed_count, nodemgr, occlude_cache) &&
                isOccluded(this, spn, cpn + v3s16(bs2,bs2,-bs2),
                           step, stepfac, startoff, endoff, needed_count, nodemgr, occlude_cache) &&
                isOccluded(this, spn, cpn + v3s16(bs2,-bs2,bs2),
                           step, stepfac, startoff, endoff, needed_count, nodemgr, occlude_cache) &&
                isOccluded(this, spn, cpn + v3s16(bs2,-bs2,-bs2),
                           step, stepfac, startoff, endoff, needed_count, nodemgr, occlude_cache) &&
                isOccluded(this, spn, cpn + v3s16(-bs2,bs2,bs2),
                           step, stepfac, startoff, endoff, needed_count, nodemgr, occlude_cache) &&
                isOccluded(this, spn, cpn + v3s16(-bs2,bs2,-bs2),
                           step, stepfac, startoff, endoff, needed_count, nodemgr, occlude_cache) &&
                isOccluded(this, spn, cpn + v3s16(-bs2,-bs2,bs2),
                           step, stepfac, startoff, endoff, needed_count, nodemgr, occlude_cache) &&
                isOccluded(this, spn, cpn + v3s16(-bs2,-bs2,-bs2),
                           step, stepfac, startoff, endoff, needed_count, nodemgr, occlude_cache)
          )
        {
            blocks_occlusion_culled++;
            continue;
        }

        // This block is in range. Reset usage timer.
        block->resetUsageTimer();

        // Limit block count in case of a sudden increase
        blocks_would_have_drawn++;
        /*
        			if(blocks_drawn >= m_control.wanted_max_blocks
        					&& m_control.range_all == false
        					&& d > m_control.wanted_min_range * BS)
        				continue;
        */

        if (mesh_step != mesh->step && (m_mesh_queued < maxq*1.2 || range <= 2)) {
            m_client->addUpdateMeshTask(bp);
            ++m_mesh_queued;
        }
        if (block->getTimestamp() > mesh->timestamp + (smesh_size ? 0 : range >= 1 ? 60 : 5) && (m_mesh_queued < maxq*1.5 || range <= 2)) {
            m_client->addUpdateMeshTaskWithEdge(bp);
            ++m_mesh_queued;
        }

        if(!smesh_size)
            continue;

        mesh->incrementUsageTimer(dtime);

        // Add to set
        //block->refGrab();
        block->resetUsageTimer();
        drawlist.set(bp, block);

        blocks_drawn++;

        if(range * MAP_BLOCKSIZE > farthest_drawn)
            farthest_drawn = range * MAP_BLOCKSIZE;

        if (farthest_drawn > m_control.farthest_drawn)
            m_control.farthest_drawn = farthest_drawn;

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

    }
    m_drawlist_last = draw_nearest.size();

    //if (m_drawlist_last) infostream<<"breaked UDL "<<m_drawlist_last<<" collected="<<drawlist.size()<<" calls="<<calls<<" s="<<m_blocks.size()<<" maxms="<<max_cycle_ms<<" fw="<<getControl().fps_wanted<<" morems="<<porting::getTimeMs() - end_ms<< " meshq="<<m_mesh_queued<<" occache="<<occlude_cache.size()<<std::endl;

    if (m_drawlist_last)
        return;

    //for (auto & ir : *m_drawlist)
    //	ir.second->refDrop();

    auto m_drawlist_old = !m_drawlist_current ? &m_drawlist_1 : &m_drawlist_0;
    m_drawlist = m_drawlist_current ? &m_drawlist_1 : &m_drawlist_0;
    m_drawlist_old->clear();

    m_control.blocks_would_have_drawn = blocks_would_have_drawn;
    m_control.blocks_drawn = blocks_drawn;
    m_control.farthest_drawn = farthest_drawn;

    g_profiler->avg("CM: blocks total", m_blocks.size());
    g_profiler->avg("CM: blocks in range", blocks_in_range);
    g_profiler->avg("CM: blocks occlusion culled", blocks_occlusion_culled);
    if(blocks_in_range != 0)
        g_profiler->avg("CM: blocks in range without mesh (frac)",
                        (float)blocks_in_range_without_mesh/blocks_in_range);
    g_profiler->avg("CM: blocks drawn", blocks_drawn);
    g_profiler->avg("CM: farthest drawn", farthest_drawn);
    g_profiler->avg("CM: wanted max blocks", m_control.wanted_max_blocks);
}
Ejemplo n.º 8
0
Archivo: mutex.hpp Proyecto: go4and/lib
 ~unique_lock()
 {
     if(owns_lock())
         mutex_.unlock();
 }
Ejemplo n.º 9
0
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);
	}
}
Ejemplo n.º 10
0
			operator bool() const{ return owns_lock(); }
Ejemplo n.º 11
0
			~lock_guard(){if(owns_lock())ptr->unlock();}
Ejemplo n.º 12
0
int RemoteClient::GetNextBlocks (
		ServerEnvironment *env,
		EmergeManager * emerge,
		float dtime,
		double m_uptime,
		std::vector<PrioritySortedBlockTransfer> &dest)
{
	DSTACK(FUNCTION_NAME);

	auto lock = lock_unique_rec();
	if (!lock->owns_lock())
		return 0;

	// Increment timers
	m_nothing_to_send_pause_timer -= dtime;
	m_nearest_unsent_reset_timer += dtime;
	m_time_from_building += dtime;

	if (m_nearest_unsent_reset) {
		m_nearest_unsent_reset = 0;
		m_nearest_unsent_reset_timer = 999;
		m_nothing_to_send_pause_timer = 0;
		m_time_from_building = 999;
	}

	if(m_nothing_to_send_pause_timer >= 0)
		return 0;

	Player *player = env->getPlayer(peer_id);
	// This can happen sometimes; clients and players are not in perfect sync.
	if(player == NULL)
		return 0;

	v3f playerpos = player->getPosition();
	v3f playerspeed = player->getSpeed();
	if(playerspeed.getLength() > 1000.0*BS) //cheater or bug, ignore him
		return 0;
	v3f playerspeeddir(0,0,0);
	if(playerspeed.getLength() > 1.0*BS)
		playerspeeddir = playerspeed / playerspeed.getLength();
	// Predict to next block
	v3f playerpos_predicted = playerpos + playerspeeddir*MAP_BLOCKSIZE*BS;

	v3s16 center_nodepos = floatToInt(playerpos_predicted, BS);

	v3s16 center = getNodeBlockPos(center_nodepos);

	// Camera position and direction
	v3f camera_pos = player->getEyePosition();
	v3f camera_dir = v3f(0,0,1);
	camera_dir.rotateYZBy(player->getPitch());
	camera_dir.rotateXZBy(player->getYaw());

	//infostream<<"camera_dir=("<<camera_dir<<")"<< " camera_pos="<<camera_pos<<std::endl;

	/*
		Get the starting value of the block finder radius.
	*/

	if(m_last_center != center)
	{
		m_last_center = center;
		m_nearest_unsent_reset_timer = 999;
	}

	if (m_last_direction.getDistanceFrom(camera_dir)>0.4) { // 1 = 90deg
		m_last_direction = camera_dir;
		m_nearest_unsent_reset_timer = 999;
	}

	/*infostream<<"m_nearest_unsent_reset_timer="
			<<m_nearest_unsent_reset_timer<<std::endl;*/

	// Reset periodically to workaround for some bugs or stuff
	if(m_nearest_unsent_reset_timer > 120.0)
	{
		m_nearest_unsent_reset_timer = 0;
		m_nearest_unsent_d = 0;
		m_nearest_unsent_reset = 0;
		//infostream<<"Resetting m_nearest_unsent_d for "<<peer_id<<std::endl;
	}

	//s16 last_nearest_unsent_d = m_nearest_unsent_d;
	s16 d_start = m_nearest_unsent_d;

	//infostream<<"d_start="<<d_start<<std::endl;

	static const u16 max_simul_sends_setting = g_settings->getU16
			("max_simultaneous_block_sends_per_client");
	static const u16 max_simul_sends_usually = max_simul_sends_setting;

	/*
		Check the time from last addNode/removeNode.

		Decrease send rate if player is building stuff.
	*/
	static const auto full_block_send_enable_min_time_from_building = g_settings->getFloat("full_block_send_enable_min_time_from_building");
	if(m_time_from_building < full_block_send_enable_min_time_from_building)
	{
		/*
		max_simul_sends_usually
			= LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
		*/
		if(d_start<=1)
			d_start=2;
		m_nearest_unsent_reset_timer = 999; //magical number more than ^ other number 120 - need to reset d on next iteration
	}

	/*
		Number of blocks sending + number of blocks selected for sending
	*/
	u32 num_blocks_selected = 0;
	u32 num_blocks_sending = 0;

	/*
		next time d will be continued from the d from which the nearest
		unsent block was found this time.

		This is because not necessarily any of the blocks found this
		time are actually sent.
	*/
	s32 new_nearest_unsent_d = -1;

	static const auto max_block_send_distance = g_settings->getS16("max_block_send_distance");
	s16 full_d_max = max_block_send_distance;
	if (wanted_range) {
		s16 wanted_blocks = wanted_range / MAP_BLOCKSIZE + 1;
		if (wanted_blocks < full_d_max)
			full_d_max = wanted_blocks;
	}

	s16 d_max = full_d_max;
	static const s16 d_max_gen = g_settings->getS16("max_block_generate_distance");

	// Don't loop very much at a time
	s16 max_d_increment_at_time = 10;
	if(d_max > d_start + max_d_increment_at_time)
		d_max = d_start + max_d_increment_at_time;
	/*if(d_max_gen > d_start+2)
		d_max_gen = d_start+2;*/

	//infostream<<"Starting from "<<d_start<<std::endl;

	s32 nearest_emerged_d = -1;
	s32 nearest_emergefull_d = -1;
	s32 nearest_sent_d = -1;
	//bool queue_is_full = false;

	f32 speed_in_blocks = (playerspeed/(MAP_BLOCKSIZE*BS)).getLength();


	int blocks_occlusion_culled = 0;
	static const bool server_occlusion = g_settings->getBool("server_occlusion");
	bool occlusion_culling_enabled = server_occlusion;

	auto cam_pos_nodes = floatToInt(playerpos, BS);

	auto nodemgr = env->getGameDef()->getNodeDefManager();
	MapNode n;
	{
#if !ENABLE_THREADS
		auto lock = env->getServerMap().m_nothread_locker.lock_shared_rec();
#endif
		n = env->getMap().getNodeTry(cam_pos_nodes);
	}

	if(n && nodemgr->get(n).solidness == 2)
		occlusion_culling_enabled = false;

	unordered_map_v3POS<bool> occlude_cache;


	s16 d;
	for(d = d_start; d <= d_max; d++) {
		/*errorstream<<"checking d="<<d<<" for "
				<<server->getPlayerName(peer_id)<<std::endl;*/
		//infostream<<"RemoteClient::SendBlocks(): d="<<d<<" d_start="<<d_start<<" d_max="<<d_max<<" d_max_gen="<<d_max_gen<<std::endl;

		std::vector<v3POS> list;
		if (d > 2 && d == d_start && m_nearest_unsent_reset_timer != 999) { // oops, again magic number from up ^
			list.push_back(v3POS(0,0,0));
		}

		bool can_skip = d > 1;
		// Fast fall/move optimize. speed_in_blocks now limited to 6.4
		if (speed_in_blocks>0.8 && d <= 2) {
			can_skip = false;
			if (d == 0) {
				for(s16 addn = 0; addn < (speed_in_blocks+1)*2; ++addn)
					list.push_back(floatToInt(playerspeeddir*addn, 1));
			} else if (d == 1) {
				for(s16 addn = 0; addn < (speed_in_blocks+1)*1.5; ++addn) {
					list.push_back(floatToInt(playerspeeddir*addn, 1) + v3POS( 0,  0,  1)); // back
					list.push_back(floatToInt(playerspeeddir*addn, 1) + v3POS( -1, 0,  0)); // left
					list.push_back(floatToInt(playerspeeddir*addn, 1) + v3POS( 1,  0,  0)); // right
					list.push_back(floatToInt(playerspeeddir*addn, 1) + v3POS( 0,  0, -1)); // front
				}
			} else if (d == 2) {
				for(s16 addn = 0; addn < (speed_in_blocks+1)*1.5; ++addn) {
					list.push_back(floatToInt(playerspeeddir*addn, 1) + v3POS( -1, 0,  1)); // back left
					list.push_back(floatToInt(playerspeeddir*addn, 1) + v3POS( 1,  0,  1)); // left right
					list.push_back(floatToInt(playerspeeddir*addn, 1) + v3POS( -1, 0, -1)); // right left
					list.push_back(floatToInt(playerspeeddir*addn, 1) + v3POS( 1,  0, -1)); // front right
				}
			}
		} else {
		/*
			Get the border/face dot coordinates of a "d-radiused"
			box
		*/
			list = FacePositionCache::getFacePositions(d);
		}


		for(auto li=list.begin(); li!=list.end(); ++li)
		{
			v3POS p = *li + center;

			/*
				Send throttling
				- Don't allow too many simultaneous transfers
				- EXCEPT when the blocks are very close

				Also, don't send blocks that are already flying.
			*/

			// Start with the usual maximum
			u16 max_simul_dynamic = max_simul_sends_usually;

			// If block is very close, allow full maximum
			if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
				max_simul_dynamic = max_simul_sends_setting;

			// Don't select too many blocks for sending
			if (num_blocks_selected + num_blocks_sending >= max_simul_dynamic) {
				//queue_is_full = true;
				goto queue_full_break;
			}

			/*
				Do not go over-limit
			*/
			if (blockpos_over_limit(p))
				continue;

			// If this is true, inexistent block will be made from scratch
			bool generate = d <= d_max_gen;

			{
				/*// Limit the generating area vertically to 2/3
				if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
					generate = false;*/

				/* maybe good idea (if not use block culling) but brokes far (25+) area generate by flooding emergequeue with no generate blocks
				// Limit the send area vertically to 1/2
				if(can_skip && abs(p.Y - center.Y) > full_d_max / 2)
					generate = false;
				*/
			}


			//infostream<<"d="<<d<<std::endl;
			/*
				Don't generate or send if not in sight
				FIXME This only works if the client uses a small enough
				FOV setting. The default of 72 degrees is fine.
			*/

			float camera_fov = ((fov+5)*M_PI/180) * 4./3.;
			if(can_skip && isBlockInSight(p, camera_pos, camera_dir, camera_fov, 10000*BS) == false)
			{
				continue;
			}

			/*
				Don't send already sent blocks
			*/
			unsigned int block_sent = 0;
			{
				auto lock = m_blocks_sent.lock_shared_rec();
				block_sent = m_blocks_sent.find(p) != m_blocks_sent.end() ? m_blocks_sent.get(p) : 0;
			}
			if(block_sent > 0 && (/* (block_overflow && d>1) || */ block_sent + (d <= 2 ? 1 : d*d*d) > m_uptime)) {
				continue;
			}

			/*
				Check if map has this block
			*/

			MapBlock *block;
			{
#if !ENABLE_THREADS
			auto lock = env->getServerMap().m_nothread_locker.lock_shared_rec();
#endif

			block = env->getMap().getBlockNoCreateNoEx(p);
			}

			bool surely_not_found_on_disk = false;
			bool block_is_invalid = false;
			if(block != NULL)
			{

				if (d > 3 && block->content_only == CONTENT_AIR) {
					continue;
				}

				if (block_sent > 0 && block_sent >= block->m_changed_timestamp) {
					continue;
				}

		if (occlusion_culling_enabled) {
			ScopeProfiler sp(g_profiler, "SMap: Occusion calls");
			//Occlusion culling
			auto cpn = p*MAP_BLOCKSIZE;

			// No occlusion culling when free_move is on and camera is
			// inside ground
			cpn += v3POS(MAP_BLOCKSIZE/2, MAP_BLOCKSIZE/2, MAP_BLOCKSIZE/2);

			float step = 1;
			float stepfac = 1.3;
			float startoff = 5;
			float endoff = -MAP_BLOCKSIZE;
			v3POS spn = cam_pos_nodes + v3POS(0,0,0);
			s16 bs2 = MAP_BLOCKSIZE/2 + 1;
			u32 needed_count = 1;
#if !ENABLE_THREADS
			auto lock = env->getServerMap().m_nothread_locker.lock_shared_rec();
#endif
			//VERY BAD COPYPASTE FROM clientmap.cpp!
			if( d >= 1 &&
				occlusion_culling_enabled &&
				isOccluded(&env->getMap(), spn, cpn + v3POS(0,0,0),
					step, stepfac, startoff, endoff, needed_count, nodemgr, occlude_cache) &&
				isOccluded(&env->getMap(), spn, cpn + v3POS(bs2,bs2,bs2),
					step, stepfac, startoff, endoff, needed_count, nodemgr, occlude_cache) &&
				isOccluded(&env->getMap(), spn, cpn + v3POS(bs2,bs2,-bs2),
					step, stepfac, startoff, endoff, needed_count, nodemgr, occlude_cache) &&
				isOccluded(&env->getMap(), spn, cpn + v3POS(bs2,-bs2,bs2),
					step, stepfac, startoff, endoff, needed_count, nodemgr, occlude_cache) &&
				isOccluded(&env->getMap(), spn, cpn + v3POS(bs2,-bs2,-bs2),
					step, stepfac, startoff, endoff, needed_count, nodemgr, occlude_cache) &&
				isOccluded(&env->getMap(), spn, cpn + v3POS(-bs2,bs2,bs2),
					step, stepfac, startoff, endoff, needed_count, nodemgr, occlude_cache) &&
				isOccluded(&env->getMap(), spn, cpn + v3POS(-bs2,bs2,-bs2),
					step, stepfac, startoff, endoff, needed_count, nodemgr, occlude_cache) &&
				isOccluded(&env->getMap(), spn, cpn + v3POS(-bs2,-bs2,bs2),
					step, stepfac, startoff, endoff, needed_count, nodemgr, occlude_cache) &&
				isOccluded(&env->getMap(), spn, cpn + v3POS(-bs2,-bs2,-bs2),
					step, stepfac, startoff, endoff, needed_count, nodemgr, occlude_cache)
			)
			{
				//infostream<<" occlusion player="<<cam_pos_nodes<<" d="<<d<<" block="<<cpn<<" total="<<blocks_occlusion_culled<<"/"<<num_blocks_selected<<std::endl;
				g_profiler->add("SMap: Occlusion skip", 1);
				blocks_occlusion_culled++;
				continue;
			}
		}

				// Reset usage timer, this block will be of use in the future.
				block->resetUsageTimer();

				if (block->getLightingExpired()) {
					//env->getServerMap().lighting_modified_blocks.set(p, nullptr);
					env->getServerMap().lighting_modified_add(p, d);
				}

				if (block->lighting_broken > 0 && (block_sent || d > 0))
					continue;

				// Block is valid if lighting is up-to-date and data exists
				if(block->isValid() == false)
				{
					block_is_invalid = true;
				}

				if(block->isGenerated() == false)
				{
					continue;
				}

				/*
					If block is not close, don't send it unless it is near
					ground level.

					Block is near ground level if night-time mesh
					differs from day-time mesh.
				*/
/*
				if(d >= 4)
				{
					if(block->getDayNightDiff() == false)
						continue;
				}
*/
			}

			/*
				If block has been marked to not exist on disk (dummy)
				and generating new ones is not wanted, skip block.
			*/
			if(generate == false && surely_not_found_on_disk == true)
			{
				// get next one.
				continue;
			}

			/*
				Add inexistent block to emerge queue.
			*/
			if(block == NULL || surely_not_found_on_disk || block_is_invalid)
			{
				//infostream<<"start gen d="<<d<<" p="<<p<<" notfound="<<surely_not_found_on_disk<<" invalid="<< block_is_invalid<<" block="<<block<<" generate="<<generate<<std::endl;

				if (emerge->enqueueBlockEmerge(peer_id, p, generate)) {
					if (nearest_emerged_d == -1)
						nearest_emerged_d = d;
				} else {
					if (nearest_emergefull_d == -1)
						nearest_emergefull_d = d;
					goto queue_full_break;
				}

				// get next one.
				continue;
			}

			if(nearest_sent_d == -1)
				nearest_sent_d = d;

			/*
				Add block to send queue
			*/

			PrioritySortedBlockTransfer q((float)d, p, peer_id);

			dest.push_back(q);

			num_blocks_selected += 1;
		}
	}
queue_full_break:

	//infostream<<"Stopped at "<<d<<" d_start="<<d_start<< " d_max="<<d_max<<" nearest_emerged_d="<<nearest_emerged_d<<" nearest_emergefull_d="<<nearest_emergefull_d<< " new_nearest_unsent_d="<<new_nearest_unsent_d<< " sel="<<num_blocks_selected<< "+"<<num_blocks_sending << " culled=" << blocks_occlusion_culled <<" cEN="<<occlusion_culling_enabled<<std::endl;
	num_blocks_selected += num_blocks_sending;
	if(!num_blocks_selected && d_start <= d) {
		//new_nearest_unsent_d = 0;
		m_nothing_to_send_pause_timer = 1.0;
	}
		

	// If nothing was found for sending and nothing was queued for
	// emerging, continue next time browsing from here
	if(nearest_emerged_d != -1){
		new_nearest_unsent_d = nearest_emerged_d;
	} else if(nearest_emergefull_d != -1){
		new_nearest_unsent_d = nearest_emergefull_d;
	} else {
		if(d > full_d_max){
			new_nearest_unsent_d = 0;
			m_nothing_to_send_pause_timer = 1.0;
		} else {
			if(nearest_sent_d != -1)
				new_nearest_unsent_d = nearest_sent_d;
			else
				new_nearest_unsent_d = d;
		}
	}

	if(new_nearest_unsent_d != -1)
		m_nearest_unsent_d = new_nearest_unsent_d;
	return num_blocks_selected - num_blocks_sending;
}
Ejemplo n.º 13
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;

}
Ejemplo n.º 14
0
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;
}