diff --git a/src/clientiface.h b/src/clientiface.h index 291ccd401..5335fa644 100644 --- a/src/clientiface.h +++ b/src/clientiface.h @@ -274,6 +274,11 @@ public: u32 getSendingCount() const { return m_blocks_sending.size(); } + bool isBlockSent(v3s16 p) const + { + return m_blocks_sent.find(p) != m_blocks_sent.end(); + } + // Increments timeouts and removes timed-out blocks from list // NOTE: This doesn't fix the server-not-sending-block bug // because it is related to emerging, not sending. diff --git a/src/map.h b/src/map.h index 7e1624e60..712a0a51a 100644 --- a/src/map.h +++ b/src/map.h @@ -76,7 +76,6 @@ struct MapEditEvent v3s16 p; MapNode n = CONTENT_AIR; std::set modified_blocks; - u16 already_known_by_peer = 0; MapEditEvent() = default; diff --git a/src/server.cpp b/src/server.cpp index 04338df57..37aad4bce 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -868,20 +868,20 @@ void Server::AsyncRunStep(bool initial_step) // Players far away from the change are stored here. // Instead of sending the changes, MapBlocks are set not sent // for them. - std::vector far_players; + std::unordered_set far_players; switch (event->type) { case MEET_ADDNODE: case MEET_SWAPNODE: prof.add("MEET_ADDNODE", 1); - sendAddNode(event->p, event->n, event->already_known_by_peer, - &far_players, disable_single_change_sending ? 5 : 30, + sendAddNode(event->p, event->n, &far_players, + disable_single_change_sending ? 5 : 30, event->type == MEET_ADDNODE); break; case MEET_REMOVENODE: prof.add("MEET_REMOVENODE", 1); - sendRemoveNode(event->p, event->already_known_by_peer, - &far_players, disable_single_change_sending ? 5 : 30); + sendRemoveNode(event->p, &far_players, + disable_single_change_sending ? 5 : 30); break; case MEET_BLOCK_NODE_METADATA_CHANGED: infostream << "Server: MEET_BLOCK_NODE_METADATA_CHANGED" << std::endl; @@ -2079,76 +2079,81 @@ void Server::fadeSound(s32 handle, float step, float gain) } } -void Server::sendRemoveNode(v3s16 p, u16 ignore_id, - std::vector *far_players, float far_d_nodes) +void Server::sendRemoveNode(v3s16 p, std::unordered_set *far_players, + float far_d_nodes) { - float maxd = far_d_nodes*BS; + float maxd = far_d_nodes * BS; v3f p_f = intToFloat(p, BS); + v3s16 block_pos = getNodeBlockPos(p); NetworkPacket pkt(TOCLIENT_REMOVENODE, 6); pkt << p; std::vector clients = m_clients.getClientIDs(); - for (session_t client_id : clients) { - if (far_players) { - // Get player - if (RemotePlayer *player = m_env->getPlayer(client_id)) { - PlayerSAO *sao = player->getPlayerSAO(); - if (!sao) - continue; + m_clients.lock(); - // If player is far away, only set modified blocks not sent - v3f player_pos = sao->getBasePosition(); - if (player_pos.getDistanceFrom(p_f) > maxd) { - far_players->push_back(client_id); - continue; - } - } + for (session_t client_id : clients) { + RemoteClient *client = m_clients.lockedGetClientNoEx(client_id); + if (!client) + continue; + + RemotePlayer *player = m_env->getPlayer(client_id); + PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr; + + // If player is far away, only set modified blocks not sent + if (!client->isBlockSent(block_pos) || (sao && + sao->getBasePosition().getDistanceFrom(p_f) > maxd)) { + if (far_players) + far_players->emplace(client_id); + else + client->SetBlockNotSent(block_pos); + continue; } // Send as reliable m_clients.send(client_id, 0, &pkt, true); } + + m_clients.unlock(); } -void Server::sendAddNode(v3s16 p, MapNode n, u16 ignore_id, - std::vector *far_players, float far_d_nodes, - bool remove_metadata) +void Server::sendAddNode(v3s16 p, MapNode n, std::unordered_set *far_players, + float far_d_nodes, bool remove_metadata) { - float maxd = far_d_nodes*BS; + float maxd = far_d_nodes * BS; v3f p_f = intToFloat(p, BS); + v3s16 block_pos = getNodeBlockPos(p); + + NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1); + pkt << p << n.param0 << n.param1 << n.param2 + << (u8) (remove_metadata ? 0 : 1); std::vector clients = m_clients.getClientIDs(); - for (const session_t client_id : clients) { - if (far_players) { - // Get player - if (RemotePlayer *player = m_env->getPlayer(client_id)) { - PlayerSAO *sao = player->getPlayerSAO(); - if (!sao) - continue; + m_clients.lock(); - // If player is far away, only set modified blocks not sent - v3f player_pos = sao->getBasePosition(); - if(player_pos.getDistanceFrom(p_f) > maxd) { - far_players->push_back(client_id); - continue; - } - } - } + for (session_t client_id : clients) { + RemoteClient *client = m_clients.lockedGetClientNoEx(client_id); + if (!client) + continue; - NetworkPacket pkt(TOCLIENT_ADDNODE, 6 + 2 + 1 + 1 + 1); - m_clients.lock(); - RemoteClient* client = m_clients.lockedGetClientNoEx(client_id); - if (client) { - pkt << p << n.param0 << n.param1 << n.param2 - << (u8) (remove_metadata ? 0 : 1); + RemotePlayer *player = m_env->getPlayer(client_id); + PlayerSAO *sao = player ? player->getPlayerSAO() : nullptr; + + // If player is far away, only set modified blocks not sent + if (!client->isBlockSent(block_pos) || (sao && + sao->getBasePosition().getDistanceFrom(p_f) > maxd)) { + if (far_players) + far_players->emplace(client_id); + else + client->SetBlockNotSent(block_pos); + continue; } - m_clients.unlock(); // Send as reliable - if (pkt.getSize() > 0) - m_clients.send(client_id, 0, &pkt, true); + m_clients.send(client_id, 0, &pkt, true); } + + m_clients.unlock(); } void Server::SendBlockNoLock(session_t peer_id, MapBlock *block, u8 ver, diff --git a/src/server.h b/src/server.h index 8ac61aaad..751eaa5f2 100644 --- a/src/server.h +++ b/src/server.h @@ -416,11 +416,11 @@ private: far_d_nodes are ignored and their peer_ids are added to far_players */ // Envlock and conlock should be locked when calling these - void sendRemoveNode(v3s16 p, u16 ignore_id=0, - std::vector *far_players=NULL, float far_d_nodes=100); - void sendAddNode(v3s16 p, MapNode n, u16 ignore_id=0, - std::vector *far_players=NULL, float far_d_nodes=100, - bool remove_metadata=true); + void sendRemoveNode(v3s16 p, std::unordered_set *far_players = nullptr, + float far_d_nodes = 100); + void sendAddNode(v3s16 p, MapNode n, + std::unordered_set *far_players = nullptr, + float far_d_nodes = 100, bool remove_metadata = true); // Environment and Connection must be locked when called void SendBlockNoLock(session_t peer_id, MapBlock *block, u8 ver, u16 net_proto_version);