]> git.lizzy.rs Git - dragonfireclient.git/blobdiff - src/clientiface.cpp
Fix double free caused by CGUITTFont code
[dragonfireclient.git] / src / clientiface.cpp
index 8e469cafbb7aad97e0eedc080f357a8e0f17ea99..797afd3c1492e7137550b5167f9f8f0cd93a7751 100644 (file)
@@ -27,7 +27,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "serverenvironment.h"
 #include "map.h"
 #include "emerge.h"
-#include "content_sao.h"              // TODO this is used for cleanup of only
+#include "server/luaentity_sao.h"
+#include "server/player_sao.h"
 #include "log.h"
 #include "util/srp.h"
 #include "face_position_cache.h"
@@ -79,10 +80,11 @@ LuaEntitySAO *getAttachedObject(PlayerSAO *sao, ServerEnvironment *env)
        int id;
        std::string bone;
        v3f dummy;
-       sao->getAttachment(&id, &bone, &dummy, &dummy);
+       bool force_visible;
+       sao->getAttachment(&id, &bone, &dummy, &dummy, &force_visible);
        ServerActiveObject *ao = env->getActiveObject(id);
        while (id && ao) {
-               ao->getAttachment(&id, &bone, &dummy, &dummy);
+               ao->getAttachment(&id, &bone, &dummy, &dummy, &force_visible);
                if (id)
                        ao = env->getActiveObject(id);
        }
@@ -97,7 +99,6 @@ void RemoteClient::GetNextBlocks (
 {
        // Increment timers
        m_nothing_to_send_pause_timer -= dtime;
-       m_nearest_unsent_reset_timer += dtime;
 
        if (m_nothing_to_send_pause_timer >= 0)
                return;
@@ -134,36 +135,8 @@ void RemoteClient::GetNextBlocks (
        // Camera position and direction
        v3f camera_pos = sao->getEyePosition();
        v3f camera_dir = v3f(0,0,1);
-       camera_dir.rotateYZBy(sao->getPitch());
-       camera_dir.rotateXZBy(sao->getYaw());
-
-       /*infostream<<"camera_dir=("<<camera_dir.X<<","<<camera_dir.Y<<","
-                       <<camera_dir.Z<<")"<<std::endl;*/
-
-       /*
-               Get the starting value of the block finder radius.
-       */
-
-       if (m_last_center != center) {
-               m_nearest_unsent_d = 0;
-               m_last_center = center;
-       }
-
-       /*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 > 20.0f) {
-               m_nearest_unsent_reset_timer = 0.0f;
-               m_nearest_unsent_d = 0;
-               //infostream<<"Resetting m_nearest_unsent_d for "
-               //              <<server->getPlayerName(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;
+       camera_dir.rotateYZBy(sao->getLookPitch());
+       camera_dir.rotateXZBy(sao->getRotation().Y);
 
        u16 max_simul_sends_usually = m_max_simul_sends;
 
@@ -192,21 +165,54 @@ void RemoteClient::GetNextBlocks (
        */
        s32 new_nearest_unsent_d = -1;
 
-       // get view range and camera fov from the client
+       // Get view range and camera fov (radians) from the client
        s16 wanted_range = sao->getWantedRange() + 1;
        float camera_fov = sao->getFov();
 
-       const s16 full_d_max = std::min(adjustDist(m_max_send_distance, camera_fov), wanted_range);
-       const s16 d_opt = std::min(adjustDist(m_block_optimize_distance, camera_fov), wanted_range);
+       /*
+               Get the starting value of the block finder radius.
+       */
+       if (m_last_center != center) {
+               m_nearest_unsent_d = 0;
+               m_last_center = center;
+       }
+       // reset the unsent distance if the view angle has changed more that 10% of the fov
+       // (this matches isBlockInSight which allows for an extra 10%)
+       if (camera_dir.dotProduct(m_last_camera_dir) < std::cos(camera_fov * 0.1f)) {
+               m_nearest_unsent_d = 0;
+               m_last_camera_dir = camera_dir;
+       }
+       if (m_nearest_unsent_d > 0) {
+               // make sure any blocks modified since the last time we sent blocks are resent
+               for (const v3s16 &p : m_blocks_modified) {
+                       m_nearest_unsent_d = std::min(m_nearest_unsent_d, center.getDistanceFrom(p));
+               }
+       }
+       m_blocks_modified.clear();
+
+       s16 d_start = m_nearest_unsent_d;
+
+       // Distrust client-sent FOV and get server-set player object property
+       // zoom FOV (degrees) as a check to avoid hacked clients using FOV to load
+       // distant world.
+       // (zoom is disabled by value 0)
+       float prop_zoom_fov = sao->getZoomFOV() < 0.001f ?
+               0.0f :
+               std::max(camera_fov, sao->getZoomFOV() * core::DEGTORAD);
+
+       const s16 full_d_max = std::min(adjustDist(m_max_send_distance, prop_zoom_fov),
+               wanted_range);
+       const s16 d_opt = std::min(adjustDist(m_block_optimize_distance, prop_zoom_fov),
+               wanted_range);
        const s16 d_blocks_in_sight = full_d_max * BS * MAP_BLOCKSIZE;
-       infostream << "Fov from client " << camera_fov << " full_d_max " << full_d_max << std::endl;
+
+       s16 d_max_gen = std::min(adjustDist(m_max_gen_distance, prop_zoom_fov),
+               wanted_range);
 
        s16 d_max = full_d_max;
-       s16 d_max_gen = std::min(adjustDist(m_max_gen_distance, camera_fov), wanted_range);
 
-       // Don't loop very much at a time, adjust with distance,
-       // do more work per RTT with greater distances.
-       s16 max_d_increment_at_time = full_d_max / 9 + 1;
+       // Don't loop very much at a time
+       s16 max_d_increment_at_time = 2;
        if (d_max > d_start + max_d_increment_at_time)
                d_max = d_start + max_d_increment_at_time;
 
@@ -299,20 +305,14 @@ void RemoteClient::GetNextBlocks (
                        */
                        MapBlock *block = env->getMap().getBlockNoCreateNoEx(p);
 
-                       bool surely_not_found_on_disk = false;
-                       bool block_is_invalid = false;
+                       bool block_not_found = false;
                        if (block) {
                                // Reset usage timer, this block will be of use in the future.
                                block->resetUsageTimer();
 
-                               // Block is dummy if data doesn't exist.
-                               // It means it has been not found from disk and not generated
-                               if (block->isDummy()) {
-                                       surely_not_found_on_disk = true;
-                               }
-
-                               if (!block->isGenerated())
-                                       block_is_invalid = true;
+                               // Check whether the block exists (with data)
+                               if (block->isDummy() || !block->isGenerated())
+                                       block_not_found = true;
 
                                /*
                                        If block is not close, don't send it unless it is near
@@ -322,21 +322,21 @@ void RemoteClient::GetNextBlocks (
                                        differs from day-time mesh.
                                */
                                if (d >= d_opt) {
-                                       if (!block->getDayNightDiff())
+                                       if (!block->getIsUnderground() && !block->getDayNightDiff())
                                                continue;
                                }
 
-                               if (m_occ_cull && !block_is_invalid &&
+                               if (m_occ_cull && !block_not_found &&
                                                env->getMap().isBlockOccluded(block, cam_pos_nodes)) {
                                        continue;
                                }
                        }
 
                        /*
-                               If block has been marked to not exist on disk (dummy)
-                               and generating new ones is not wanted, skip block.
+                               If block has been marked to not exist on disk (dummy) or is
+                               not generated and generating new ones is not wanted, skip block.
                        */
-                       if (!generate && surely_not_found_on_disk) {
+                       if (!generate && block_not_found) {
                                // get next one.
                                continue;
                        }
@@ -344,7 +344,7 @@ void RemoteClient::GetNextBlocks (
                        /*
                                Add inexistent block to emerge queue.
                        */
-                       if (block == NULL || surely_not_found_on_disk || block_is_invalid) {
+                       if (block == NULL || block_not_found) {
                                if (emerge->enqueueBlockEmerge(peer_id, p, generate)) {
                                        if (nearest_emerged_d == -1)
                                                nearest_emerged_d = d;
@@ -397,21 +397,18 @@ void RemoteClient::GetNextBlocks (
 
 void RemoteClient::GotBlock(v3s16 p)
 {
-       if (m_blocks_modified.find(p) == m_blocks_modified.end()) {
-               if (m_blocks_sending.find(p) != m_blocks_sending.end())
-                       m_blocks_sending.erase(p);
-               else
-                       m_excess_gotblocks++;
-
+       if (m_blocks_sending.find(p) != m_blocks_sending.end()) {
+               m_blocks_sending.erase(p);
+               // only add to sent blocks if it actually was sending
+               // (it might have been modified since)
                m_blocks_sent.insert(p);
+       } else {
+               m_excess_gotblocks++;
        }
 }
 
 void RemoteClient::SentBlock(v3s16 p)
 {
-       if (m_blocks_modified.find(p) != m_blocks_modified.end())
-               m_blocks_modified.erase(p);
-
        if (m_blocks_sending.find(p) == m_blocks_sending.end())
                m_blocks_sending[p] = 0.0f;
        else
@@ -421,29 +418,24 @@ void RemoteClient::SentBlock(v3s16 p)
 
 void RemoteClient::SetBlockNotSent(v3s16 p)
 {
-       m_nearest_unsent_d = 0;
        m_nothing_to_send_pause_timer = 0;
 
-       if (m_blocks_sending.find(p) != m_blocks_sending.end())
-               m_blocks_sending.erase(p);
-       if (m_blocks_sent.find(p) != m_blocks_sent.end())
-               m_blocks_sent.erase(p);
-       m_blocks_modified.insert(p);
+       // remove the block from sending and sent sets,
+       // and mark as modified if found
+       if (m_blocks_sending.erase(p) + m_blocks_sent.erase(p) > 0)
+               m_blocks_modified.insert(p);
 }
 
 void RemoteClient::SetBlocksNotSent(std::map<v3s16, MapBlock*> &blocks)
 {
-       m_nearest_unsent_d = 0;
        m_nothing_to_send_pause_timer = 0;
 
        for (auto &block : blocks) {
                v3s16 p = block.first;
-               m_blocks_modified.insert(p);
-
-               if (m_blocks_sending.find(p) != m_blocks_sending.end())
-                       m_blocks_sending.erase(p);
-               if (m_blocks_sent.find(p) != m_blocks_sent.end())
-                       m_blocks_sent.erase(p);
+               // remove the block from sending and sent sets,
+               // and mark as modified if found
+               if (m_blocks_sending.erase(p) + m_blocks_sent.erase(p) > 0)
+                       m_blocks_modified.insert(p);
        }
 }
 
@@ -460,9 +452,6 @@ void RemoteClient::notifyEvent(ClientStateEvent event)
                case CSE_Hello:
                        m_state = CS_HelloSent;
                        break;
-               case CSE_InitLegacy:
-                       m_state = CS_AwaitingInit2;
-                       break;
                case CSE_Disconnect:
                        m_state = CS_Disconnecting;
                        break;
@@ -626,7 +615,7 @@ ClientInterface::~ClientInterface()
                Delete clients
        */
        {
-               MutexAutoLock clientslock(m_clients_mutex);
+               RecursiveMutexAutoLock clientslock(m_clients_mutex);
 
                for (auto &client_it : m_clients) {
                        // Delete client
@@ -638,7 +627,7 @@ ClientInterface::~ClientInterface()
 std::vector<session_t> ClientInterface::getClientIDs(ClientState min_state)
 {
        std::vector<session_t> reply;
-       MutexAutoLock clientslock(m_clients_mutex);
+       RecursiveMutexAutoLock clientslock(m_clients_mutex);
 
        for (const auto &m_client : m_clients) {
                if (m_client.second->getState() >= min_state)
@@ -648,6 +637,15 @@ std::vector<session_t> ClientInterface::getClientIDs(ClientState min_state)
        return reply;
 }
 
+void ClientInterface::markBlockposAsNotSent(const v3s16 &pos)
+{
+       RecursiveMutexAutoLock clientslock(m_clients_mutex);
+       for (const auto &client : m_clients) {
+               if (client.second->getState() >= CS_Active)
+                       client.second->SetBlockNotSent(pos);
+       }
+}
+
 /**
  * Verify if user limit was reached.
  * User limit count all clients from HelloSent state (MT protocol user) to Active state
@@ -686,7 +684,7 @@ void ClientInterface::UpdatePlayerList()
                        infostream << "* " << player->getName() << "\t";
 
                        {
-                               MutexAutoLock clientslock(m_clients_mutex);
+                               RecursiveMutexAutoLock clientslock(m_clients_mutex);
                                RemoteClient* client = lockedGetClientNoEx(i);
                                if (client)
                                        client->PrintInfo(infostream);
@@ -705,7 +703,7 @@ void ClientInterface::send(session_t peer_id, u8 channelnum,
 
 void ClientInterface::sendToAll(NetworkPacket *pkt)
 {
-       MutexAutoLock clientslock(m_clients_mutex);
+       RecursiveMutexAutoLock clientslock(m_clients_mutex);
        for (auto &client_it : m_clients) {
                RemoteClient *client = client_it.second;
 
@@ -720,7 +718,7 @@ void ClientInterface::sendToAll(NetworkPacket *pkt)
 void ClientInterface::sendToAllCompat(NetworkPacket *pkt, NetworkPacket *legacypkt,
                u16 min_proto_ver)
 {
-       MutexAutoLock clientslock(m_clients_mutex);
+       RecursiveMutexAutoLock clientslock(m_clients_mutex);
        for (auto &client_it : m_clients) {
                RemoteClient *client = client_it.second;
                NetworkPacket *pkt_to_send = nullptr;
@@ -744,7 +742,7 @@ void ClientInterface::sendToAllCompat(NetworkPacket *pkt, NetworkPacket *legacyp
 
 RemoteClient* ClientInterface::getClientNoEx(session_t peer_id, ClientState state_min)
 {
-       MutexAutoLock clientslock(m_clients_mutex);
+       RecursiveMutexAutoLock clientslock(m_clients_mutex);
        RemoteClientMap::const_iterator n = m_clients.find(peer_id);
        // The client may not exist; clients are immediately removed if their
        // access is denied, and this event occurs later then.
@@ -773,7 +771,7 @@ RemoteClient* ClientInterface::lockedGetClientNoEx(session_t peer_id, ClientStat
 
 ClientState ClientInterface::getClientState(session_t peer_id)
 {
-       MutexAutoLock clientslock(m_clients_mutex);
+       RecursiveMutexAutoLock clientslock(m_clients_mutex);
        RemoteClientMap::const_iterator n = m_clients.find(peer_id);
        // The client may not exist; clients are immediately removed if their
        // access is denied, and this event occurs later then.
@@ -785,7 +783,7 @@ ClientState ClientInterface::getClientState(session_t peer_id)
 
 void ClientInterface::setPlayerName(session_t peer_id, const std::string &name)
 {
-       MutexAutoLock clientslock(m_clients_mutex);
+       RecursiveMutexAutoLock clientslock(m_clients_mutex);
        RemoteClientMap::iterator n = m_clients.find(peer_id);
        // The client may not exist; clients are immediately removed if their
        // access is denied, and this event occurs later then.
@@ -795,7 +793,7 @@ void ClientInterface::setPlayerName(session_t peer_id, const std::string &name)
 
 void ClientInterface::DeleteClient(session_t peer_id)
 {
-       MutexAutoLock conlock(m_clients_mutex);
+       RecursiveMutexAutoLock conlock(m_clients_mutex);
 
        // Error check
        RemoteClientMap::iterator n = m_clients.find(peer_id);
@@ -825,7 +823,7 @@ void ClientInterface::DeleteClient(session_t peer_id)
 
 void ClientInterface::CreateClient(session_t peer_id)
 {
-       MutexAutoLock conlock(m_clients_mutex);
+       RecursiveMutexAutoLock conlock(m_clients_mutex);
 
        // Error check
        RemoteClientMap::iterator n = m_clients.find(peer_id);
@@ -841,7 +839,7 @@ void ClientInterface::CreateClient(session_t peer_id)
 void ClientInterface::event(session_t peer_id, ClientStateEvent event)
 {
        {
-               MutexAutoLock clientlock(m_clients_mutex);
+               RecursiveMutexAutoLock clientlock(m_clients_mutex);
 
                // Error check
                RemoteClientMap::iterator n = m_clients.find(peer_id);
@@ -862,7 +860,7 @@ void ClientInterface::event(session_t peer_id, ClientStateEvent event)
 
 u16 ClientInterface::getProtocolVersion(session_t peer_id)
 {
-       MutexAutoLock conlock(m_clients_mutex);
+       RecursiveMutexAutoLock conlock(m_clients_mutex);
 
        // Error check
        RemoteClientMap::iterator n = m_clients.find(peer_id);
@@ -877,7 +875,7 @@ u16 ClientInterface::getProtocolVersion(session_t peer_id)
 void ClientInterface::setClientVersion(session_t peer_id, u8 major, u8 minor, u8 patch,
                const std::string &full)
 {
-       MutexAutoLock conlock(m_clients_mutex);
+       RecursiveMutexAutoLock conlock(m_clients_mutex);
 
        // Error check
        RemoteClientMap::iterator n = m_clients.find(peer_id);