3 Copyright (C) 2010-2014 celeron55, Perttu Ahola <celeron55@gmail.com>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 #include "clientiface.h"
22 #include "network/connection.h"
23 #include "network/serveropcodes.h"
24 #include "remoteplayer.h"
27 #include "serverenvironment.h"
30 #include "server/luaentity_sao.h"
31 #include "server/player_sao.h"
34 #include "face_position_cache.h"
36 const char *ClientInterface::statenames[] = {
51 std::string ClientInterface::state2Name(ClientState state)
53 return statenames[state];
56 RemoteClient::RemoteClient() :
57 m_max_simul_sends(g_settings->getU16("max_simultaneous_block_sends_per_client")),
58 m_min_time_from_building(
59 g_settings->getFloat("full_block_send_enable_min_time_from_building")),
60 m_max_send_distance(g_settings->getS16("max_block_send_distance")),
61 m_block_optimize_distance(g_settings->getS16("block_send_optimize_distance")),
62 m_max_gen_distance(g_settings->getS16("max_block_generate_distance")),
63 m_occ_cull(g_settings->getBool("server_side_occlusion_culling"))
67 void RemoteClient::ResendBlockIfOnWire(v3s16 p)
69 // if this block is on wire, mark it for sending again as soon as possible
70 if (m_blocks_sending.find(p) != m_blocks_sending.end()) {
75 LuaEntitySAO *getAttachedObject(PlayerSAO *sao, ServerEnvironment *env)
77 if (!sao->isAttached())
83 sao->getAttachment(&id, &bone, &dummy, &dummy);
84 ServerActiveObject *ao = env->getActiveObject(id);
86 ao->getAttachment(&id, &bone, &dummy, &dummy);
88 ao = env->getActiveObject(id);
90 return dynamic_cast<LuaEntitySAO *>(ao);
93 void RemoteClient::GetNextBlocks (
94 ServerEnvironment *env,
95 EmergeManager * emerge,
97 std::vector<PrioritySortedBlockTransfer> &dest)
100 m_nothing_to_send_pause_timer -= dtime;
101 m_nearest_unsent_reset_timer += dtime;
103 if (m_nothing_to_send_pause_timer >= 0)
106 RemotePlayer *player = env->getPlayer(peer_id);
107 // This can happen sometimes; clients and players are not in perfect sync.
111 PlayerSAO *sao = player->getPlayerSAO();
115 // Won't send anything if already sending
116 if (m_blocks_sending.size() >= m_max_simul_sends) {
117 //infostream<<"Not sending any blocks, Queue full."<<std::endl;
121 v3f playerpos = sao->getBasePosition();
122 // if the player is attached, get the velocity from the attached object
123 LuaEntitySAO *lsao = getAttachedObject(sao, env);
124 const v3f &playerspeed = lsao? lsao->getVelocity() : player->getSpeed();
125 v3f playerspeeddir(0,0,0);
126 if (playerspeed.getLength() > 1.0f * BS)
127 playerspeeddir = playerspeed / playerspeed.getLength();
128 // Predict to next block
129 v3f playerpos_predicted = playerpos + playerspeeddir * (MAP_BLOCKSIZE * BS);
131 v3s16 center_nodepos = floatToInt(playerpos_predicted, BS);
133 v3s16 center = getNodeBlockPos(center_nodepos);
135 // Camera position and direction
136 v3f camera_pos = sao->getEyePosition();
137 v3f camera_dir = v3f(0,0,1);
138 camera_dir.rotateYZBy(sao->getLookPitch());
139 camera_dir.rotateXZBy(sao->getRotation().Y);
141 /*infostream<<"camera_dir=("<<camera_dir.X<<","<<camera_dir.Y<<","
142 <<camera_dir.Z<<")"<<std::endl;*/
145 Get the starting value of the block finder radius.
148 if (m_last_center != center) {
149 m_nearest_unsent_d = 0;
150 m_last_center = center;
153 /*infostream<<"m_nearest_unsent_reset_timer="
154 <<m_nearest_unsent_reset_timer<<std::endl;*/
156 // Reset periodically to workaround for some bugs or stuff
157 if (m_nearest_unsent_reset_timer > 20.0f) {
158 m_nearest_unsent_reset_timer = 0.0f;
159 m_nearest_unsent_d = 0;
160 //infostream<<"Resetting m_nearest_unsent_d for "
161 // <<server->getPlayerName(peer_id)<<std::endl;
164 //s16 last_nearest_unsent_d = m_nearest_unsent_d;
165 s16 d_start = m_nearest_unsent_d;
167 //infostream<<"d_start="<<d_start<<std::endl;
169 u16 max_simul_sends_usually = m_max_simul_sends;
172 Check the time from last addNode/removeNode.
174 Decrease send rate if player is building stuff.
176 m_time_from_building += dtime;
177 if (m_time_from_building < m_min_time_from_building) {
178 max_simul_sends_usually
179 = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
183 Number of blocks sending + number of blocks selected for sending
185 u32 num_blocks_selected = m_blocks_sending.size();
188 next time d will be continued from the d from which the nearest
189 unsent block was found this time.
191 This is because not necessarily any of the blocks found this
192 time are actually sent.
194 s32 new_nearest_unsent_d = -1;
196 // Get view range and camera fov (radians) from the client
197 s16 wanted_range = sao->getWantedRange() + 1;
198 float camera_fov = sao->getFov();
200 // Distrust client-sent FOV and get server-set player object property
201 // zoom FOV (degrees) as a check to avoid hacked clients using FOV to load
203 // (zoom is disabled by value 0)
204 float prop_zoom_fov = sao->getZoomFOV() < 0.001f ?
206 std::max(camera_fov, sao->getZoomFOV() * core::DEGTORAD);
208 const s16 full_d_max = std::min(adjustDist(m_max_send_distance, prop_zoom_fov),
210 const s16 d_opt = std::min(adjustDist(m_block_optimize_distance, prop_zoom_fov),
212 const s16 d_blocks_in_sight = full_d_max * BS * MAP_BLOCKSIZE;
214 s16 d_max = full_d_max;
215 s16 d_max_gen = std::min(adjustDist(m_max_gen_distance, prop_zoom_fov),
218 // Don't loop very much at a time, adjust with distance,
219 // do more work per RTT with greater distances.
220 s16 max_d_increment_at_time = full_d_max / 9 + 1;
221 if (d_max > d_start + max_d_increment_at_time)
222 d_max = d_start + max_d_increment_at_time;
224 // cos(angle between velocity and camera) * |velocity|
225 // Limit to 0.0f in case player moves backwards.
226 f32 dot = rangelim(camera_dir.dotProduct(playerspeed), 0.0f, 300.0f);
228 // Reduce the field of view when a player moves and looks forward.
229 // limit max fov effect to 50%, 60% at 20n/s fly speed
230 camera_fov = camera_fov / (1 + dot / 300.0f);
232 s32 nearest_emerged_d = -1;
233 s32 nearest_emergefull_d = -1;
234 s32 nearest_sent_d = -1;
235 //bool queue_is_full = false;
237 const v3s16 cam_pos_nodes = floatToInt(camera_pos, BS);
240 for (d = d_start; d <= d_max; d++) {
242 Get the border/face dot coordinates of a "d-radiused"
245 std::vector<v3s16> list = FacePositionCache::getFacePositions(d);
247 std::vector<v3s16>::iterator li;
248 for (li = list.begin(); li != list.end(); ++li) {
249 v3s16 p = *li + center;
253 - Don't allow too many simultaneous transfers
254 - EXCEPT when the blocks are very close
256 Also, don't send blocks that are already flying.
259 // Start with the usual maximum
260 u16 max_simul_dynamic = max_simul_sends_usually;
262 // If block is very close, allow full maximum
263 if (d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
264 max_simul_dynamic = m_max_simul_sends;
266 // Don't select too many blocks for sending
267 if (num_blocks_selected >= max_simul_dynamic) {
268 //queue_is_full = true;
269 goto queue_full_break;
272 // Don't send blocks that are currently being transferred
273 if (m_blocks_sending.find(p) != m_blocks_sending.end())
277 Do not go over max mapgen limit
279 if (blockpos_over_max_limit(p))
282 // If this is true, inexistent block will be made from scratch
283 bool generate = d <= d_max_gen;
286 Don't generate or send if not in sight
287 FIXME This only works if the client uses a small enough
288 FOV setting. The default of 72 degrees is fine.
289 Also retrieve a smaller view cone in the direction of the player's
291 (0.1 is about 4 degrees)
294 if (!(isBlockInSight(p, camera_pos, camera_dir, camera_fov,
295 d_blocks_in_sight, &dist) ||
296 (playerspeed.getLength() > 1.0f * BS &&
297 isBlockInSight(p, camera_pos, playerspeeddir, 0.1f,
298 d_blocks_in_sight)))) {
303 Don't send already sent blocks
305 if (m_blocks_sent.find(p) != m_blocks_sent.end())
309 Check if map has this block
311 MapBlock *block = env->getMap().getBlockNoCreateNoEx(p);
313 bool surely_not_found_on_disk = false;
314 bool block_is_invalid = false;
316 // Reset usage timer, this block will be of use in the future.
317 block->resetUsageTimer();
319 // Block is dummy if data doesn't exist.
320 // It means it has been not found from disk and not generated
321 if (block->isDummy()) {
322 surely_not_found_on_disk = true;
325 if (!block->isGenerated())
326 block_is_invalid = true;
329 If block is not close, don't send it unless it is near
332 Block is near ground level if night-time mesh
333 differs from day-time mesh.
336 if (!block->getIsUnderground() && !block->getDayNightDiff())
340 if (m_occ_cull && !block_is_invalid &&
341 env->getMap().isBlockOccluded(block, cam_pos_nodes)) {
347 If block has been marked to not exist on disk (dummy) or is
348 not generated and generating new ones is not wanted, skip block.
350 if (!generate && (surely_not_found_on_disk || block_is_invalid)) {
356 Add inexistent block to emerge queue.
358 if (block == NULL || surely_not_found_on_disk || block_is_invalid) {
359 if (emerge->enqueueBlockEmerge(peer_id, p, generate)) {
360 if (nearest_emerged_d == -1)
361 nearest_emerged_d = d;
363 if (nearest_emergefull_d == -1)
364 nearest_emergefull_d = d;
365 goto queue_full_break;
372 if (nearest_sent_d == -1)
376 Add block to send queue
378 PrioritySortedBlockTransfer q((float)dist, p, peer_id);
382 num_blocks_selected += 1;
387 // If nothing was found for sending and nothing was queued for
388 // emerging, continue next time browsing from here
389 if (nearest_emerged_d != -1) {
390 new_nearest_unsent_d = nearest_emerged_d;
391 } else if (nearest_emergefull_d != -1) {
392 new_nearest_unsent_d = nearest_emergefull_d;
394 if (d > full_d_max) {
395 new_nearest_unsent_d = 0;
396 m_nothing_to_send_pause_timer = 2.0f;
398 if (nearest_sent_d != -1)
399 new_nearest_unsent_d = nearest_sent_d;
401 new_nearest_unsent_d = d;
405 if (new_nearest_unsent_d != -1)
406 m_nearest_unsent_d = new_nearest_unsent_d;
409 void RemoteClient::GotBlock(v3s16 p)
411 if (m_blocks_modified.find(p) == m_blocks_modified.end()) {
412 if (m_blocks_sending.find(p) != m_blocks_sending.end())
413 m_blocks_sending.erase(p);
415 m_excess_gotblocks++;
417 m_blocks_sent.insert(p);
421 void RemoteClient::SentBlock(v3s16 p)
423 if (m_blocks_modified.find(p) != m_blocks_modified.end())
424 m_blocks_modified.erase(p);
426 if (m_blocks_sending.find(p) == m_blocks_sending.end())
427 m_blocks_sending[p] = 0.0f;
429 infostream<<"RemoteClient::SentBlock(): Sent block"
430 " already in m_blocks_sending"<<std::endl;
433 void RemoteClient::SetBlockNotSent(v3s16 p)
435 m_nearest_unsent_d = 0;
436 m_nothing_to_send_pause_timer = 0;
438 if (m_blocks_sending.find(p) != m_blocks_sending.end())
439 m_blocks_sending.erase(p);
440 if (m_blocks_sent.find(p) != m_blocks_sent.end())
441 m_blocks_sent.erase(p);
442 m_blocks_modified.insert(p);
445 void RemoteClient::SetBlocksNotSent(std::map<v3s16, MapBlock*> &blocks)
447 m_nearest_unsent_d = 0;
448 m_nothing_to_send_pause_timer = 0;
450 for (auto &block : blocks) {
451 v3s16 p = block.first;
452 m_blocks_modified.insert(p);
454 if (m_blocks_sending.find(p) != m_blocks_sending.end())
455 m_blocks_sending.erase(p);
456 if (m_blocks_sent.find(p) != m_blocks_sent.end())
457 m_blocks_sent.erase(p);
461 void RemoteClient::notifyEvent(ClientStateEvent event)
463 std::ostringstream myerror;
467 //intentionally do nothing
472 m_state = CS_HelloSent;
475 m_state = CS_AwaitingInit2;
478 m_state = CS_Disconnecting;
483 /* GotInit2 SetDefinitionsSent SetMediaSent */
485 myerror << "Created: Invalid client state transition! " << event;
486 throw ClientStateError(myerror.str());
490 /* don't do anything if in denied state */
496 m_state = CS_AwaitingInit2;
497 if (chosen_mech == AUTH_MECHANISM_SRP ||
498 chosen_mech == AUTH_MECHANISM_LEGACY_PASSWORD)
499 srp_verifier_delete((SRPVerifier *) auth_data);
500 chosen_mech = AUTH_MECHANISM_NONE;
503 m_state = CS_Disconnecting;
507 if (chosen_mech == AUTH_MECHANISM_SRP ||
508 chosen_mech == AUTH_MECHANISM_LEGACY_PASSWORD)
509 srp_verifier_delete((SRPVerifier *) auth_data);
510 chosen_mech = AUTH_MECHANISM_NONE;
513 myerror << "HelloSent: Invalid client state transition! " << event;
514 throw ClientStateError(myerror.str());
517 case CS_AwaitingInit2:
521 confirmSerializationVersion();
522 m_state = CS_InitDone;
525 m_state = CS_Disconnecting;
531 /* Init SetDefinitionsSent SetMediaSent */
533 myerror << "InitSent: Invalid client state transition! " << event;
534 throw ClientStateError(myerror.str());
541 case CSE_SetDefinitionsSent:
542 m_state = CS_DefinitionsSent;
545 m_state = CS_Disconnecting;
551 /* Init GotInit2 SetMediaSent */
553 myerror << "InitDone: Invalid client state transition! " << event;
554 throw ClientStateError(myerror.str());
557 case CS_DefinitionsSent:
560 case CSE_SetClientReady:
564 m_state = CS_Disconnecting;
569 /* Init GotInit2 SetDefinitionsSent */
571 myerror << "DefinitionsSent: Invalid client state transition! " << event;
572 throw ClientStateError(myerror.str());
582 m_state = CS_Disconnecting;
584 case CSE_SudoSuccess:
585 m_state = CS_SudoMode;
586 if (chosen_mech == AUTH_MECHANISM_SRP)
587 srp_verifier_delete((SRPVerifier *) auth_data);
588 chosen_mech = AUTH_MECHANISM_NONE;
590 /* Init GotInit2 SetDefinitionsSent SetMediaSent SetDenied */
592 myerror << "Active: Invalid client state transition! " << event;
593 throw ClientStateError(myerror.str());
604 m_state = CS_Disconnecting;
610 myerror << "Active: Invalid client state transition! " << event;
611 throw ClientStateError(myerror.str());
615 case CS_Disconnecting:
616 /* we are already disconnecting */
621 u64 RemoteClient::uptime() const
623 return porting::getTimeS() - m_connection_time;
626 ClientInterface::ClientInterface(const std::shared_ptr<con::Connection> & con)
630 m_print_info_timer(0.0f)
634 ClientInterface::~ClientInterface()
640 RecursiveMutexAutoLock clientslock(m_clients_mutex);
642 for (auto &client_it : m_clients) {
644 delete client_it.second;
649 std::vector<session_t> ClientInterface::getClientIDs(ClientState min_state)
651 std::vector<session_t> reply;
652 RecursiveMutexAutoLock clientslock(m_clients_mutex);
654 for (const auto &m_client : m_clients) {
655 if (m_client.second->getState() >= min_state)
656 reply.push_back(m_client.second->peer_id);
662 void ClientInterface::markBlockposAsNotSent(const v3s16 &pos)
664 RecursiveMutexAutoLock clientslock(m_clients_mutex);
665 for (const auto &client : m_clients) {
666 if (client.second->getState() >= CS_Active)
667 client.second->SetBlockNotSent(pos);
672 * Verify if user limit was reached.
673 * User limit count all clients from HelloSent state (MT protocol user) to Active state
674 * @return true if user limit was reached
676 bool ClientInterface::isUserLimitReached()
678 return getClientIDs(CS_HelloSent).size() >= g_settings->getU16("max_users");
681 void ClientInterface::step(float dtime)
683 m_print_info_timer += dtime;
684 if (m_print_info_timer >= 30.0f) {
685 m_print_info_timer = 0.0f;
690 void ClientInterface::UpdatePlayerList()
693 std::vector<session_t> clients = getClientIDs();
694 m_clients_names.clear();
697 if (!clients.empty())
698 infostream<<"Players:"<<std::endl;
700 for (session_t i : clients) {
701 RemotePlayer *player = m_env->getPlayer(i);
706 infostream << "* " << player->getName() << "\t";
709 RecursiveMutexAutoLock clientslock(m_clients_mutex);
710 RemoteClient* client = lockedGetClientNoEx(i);
712 client->PrintInfo(infostream);
715 m_clients_names.emplace_back(player->getName());
720 void ClientInterface::send(session_t peer_id, u8 channelnum,
721 NetworkPacket *pkt, bool reliable)
723 m_con->Send(peer_id, channelnum, pkt, reliable);
726 void ClientInterface::sendToAll(NetworkPacket *pkt)
728 RecursiveMutexAutoLock clientslock(m_clients_mutex);
729 for (auto &client_it : m_clients) {
730 RemoteClient *client = client_it.second;
732 if (client->net_proto_version != 0) {
733 m_con->Send(client->peer_id,
734 clientCommandFactoryTable[pkt->getCommand()].channel, pkt,
735 clientCommandFactoryTable[pkt->getCommand()].reliable);
740 void ClientInterface::sendToAllCompat(NetworkPacket *pkt, NetworkPacket *legacypkt,
743 RecursiveMutexAutoLock clientslock(m_clients_mutex);
744 for (auto &client_it : m_clients) {
745 RemoteClient *client = client_it.second;
746 NetworkPacket *pkt_to_send = nullptr;
748 if (client->net_proto_version >= min_proto_ver) {
750 } else if (client->net_proto_version != 0) {
751 pkt_to_send = legacypkt;
753 warningstream << "Client with unhandled version to handle: '"
754 << client->net_proto_version << "'";
758 m_con->Send(client->peer_id,
759 clientCommandFactoryTable[pkt_to_send->getCommand()].channel,
761 clientCommandFactoryTable[pkt_to_send->getCommand()].reliable);
765 RemoteClient* ClientInterface::getClientNoEx(session_t peer_id, ClientState state_min)
767 RecursiveMutexAutoLock clientslock(m_clients_mutex);
768 RemoteClientMap::const_iterator n = m_clients.find(peer_id);
769 // The client may not exist; clients are immediately removed if their
770 // access is denied, and this event occurs later then.
771 if (n == m_clients.end())
774 if (n->second->getState() >= state_min)
780 RemoteClient* ClientInterface::lockedGetClientNoEx(session_t peer_id, ClientState state_min)
782 RemoteClientMap::const_iterator n = m_clients.find(peer_id);
783 // The client may not exist; clients are immediately removed if their
784 // access is denied, and this event occurs later then.
785 if (n == m_clients.end())
788 if (n->second->getState() >= state_min)
794 ClientState ClientInterface::getClientState(session_t peer_id)
796 RecursiveMutexAutoLock clientslock(m_clients_mutex);
797 RemoteClientMap::const_iterator n = m_clients.find(peer_id);
798 // The client may not exist; clients are immediately removed if their
799 // access is denied, and this event occurs later then.
800 if (n == m_clients.end())
803 return n->second->getState();
806 void ClientInterface::setPlayerName(session_t peer_id, const std::string &name)
808 RecursiveMutexAutoLock clientslock(m_clients_mutex);
809 RemoteClientMap::iterator n = m_clients.find(peer_id);
810 // The client may not exist; clients are immediately removed if their
811 // access is denied, and this event occurs later then.
812 if (n != m_clients.end())
813 n->second->setName(name);
816 void ClientInterface::DeleteClient(session_t peer_id)
818 RecursiveMutexAutoLock conlock(m_clients_mutex);
821 RemoteClientMap::iterator n = m_clients.find(peer_id);
822 // The client may not exist; clients are immediately removed if their
823 // access is denied, and this event occurs later then.
824 if (n == m_clients.end())
828 Mark objects to be not known by the client
830 //TODO this should be done by client destructor!!!
831 RemoteClient *client = n->second;
833 for (u16 id : client->m_known_objects) {
835 ServerActiveObject* obj = m_env->getActiveObject(id);
837 if(obj && obj->m_known_by_count > 0)
838 obj->m_known_by_count--;
842 delete m_clients[peer_id];
843 m_clients.erase(peer_id);
846 void ClientInterface::CreateClient(session_t peer_id)
848 RecursiveMutexAutoLock conlock(m_clients_mutex);
851 RemoteClientMap::iterator n = m_clients.find(peer_id);
852 // The client shouldn't already exist
853 if (n != m_clients.end()) return;
856 RemoteClient *client = new RemoteClient();
857 client->peer_id = peer_id;
858 m_clients[client->peer_id] = client;
861 void ClientInterface::event(session_t peer_id, ClientStateEvent event)
864 RecursiveMutexAutoLock clientlock(m_clients_mutex);
867 RemoteClientMap::iterator n = m_clients.find(peer_id);
869 // No client to deliver event
870 if (n == m_clients.end())
872 n->second->notifyEvent(event);
875 if ((event == CSE_SetClientReady) ||
876 (event == CSE_Disconnect) ||
877 (event == CSE_SetDenied))
883 u16 ClientInterface::getProtocolVersion(session_t peer_id)
885 RecursiveMutexAutoLock conlock(m_clients_mutex);
888 RemoteClientMap::iterator n = m_clients.find(peer_id);
890 // No client to get version
891 if (n == m_clients.end())
894 return n->second->net_proto_version;
897 void ClientInterface::setClientVersion(session_t peer_id, u8 major, u8 minor, u8 patch,
898 const std::string &full)
900 RecursiveMutexAutoLock conlock(m_clients_mutex);
903 RemoteClientMap::iterator n = m_clients.find(peer_id);
905 // No client to set versions
906 if (n == m_clients.end())
909 n->second->setVersionInfo(major, minor, patch, full);