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 "content_sao.h" // TODO this is used for cleanup of only
33 #include "face_position_cache.h"
35 const char *ClientInterface::statenames[] = {
50 std::string ClientInterface::state2Name(ClientState state)
52 return statenames[state];
55 RemoteClient::RemoteClient() :
56 m_max_simul_sends(g_settings->getU16("max_simultaneous_block_sends_per_client")),
57 m_min_time_from_building(
58 g_settings->getFloat("full_block_send_enable_min_time_from_building")),
59 m_max_send_distance(g_settings->getS16("max_block_send_distance")),
60 m_block_optimize_distance(g_settings->getS16("block_send_optimize_distance")),
61 m_max_gen_distance(g_settings->getS16("max_block_generate_distance")),
62 m_occ_cull(g_settings->getBool("server_side_occlusion_culling"))
66 void RemoteClient::ResendBlockIfOnWire(v3s16 p)
68 // if this block is on wire, mark it for sending again as soon as possible
69 if (m_blocks_sending.find(p) != m_blocks_sending.end()) {
74 LuaEntitySAO *getAttachedObject(PlayerSAO *sao, ServerEnvironment *env)
76 if (!sao->isAttached())
82 sao->getAttachment(&id, &bone, &dummy, &dummy);
83 ServerActiveObject *ao = env->getActiveObject(id);
85 ao->getAttachment(&id, &bone, &dummy, &dummy);
87 ao = env->getActiveObject(id);
89 return dynamic_cast<LuaEntitySAO *>(ao);
92 void RemoteClient::GetNextBlocks (
93 ServerEnvironment *env,
94 EmergeManager * emerge,
96 std::vector<PrioritySortedBlockTransfer> &dest)
99 m_nothing_to_send_pause_timer -= dtime;
100 m_nearest_unsent_reset_timer += dtime;
102 if (m_nothing_to_send_pause_timer >= 0)
105 RemotePlayer *player = env->getPlayer(peer_id);
106 // This can happen sometimes; clients and players are not in perfect sync.
110 PlayerSAO *sao = player->getPlayerSAO();
114 // Won't send anything if already sending
115 if (m_blocks_sending.size() >= m_max_simul_sends) {
116 //infostream<<"Not sending any blocks, Queue full."<<std::endl;
120 v3f playerpos = sao->getBasePosition();
121 // if the player is attached, get the velocity from the attached object
122 LuaEntitySAO *lsao = getAttachedObject(sao, env);
123 const v3f &playerspeed = lsao? lsao->getVelocity() : player->getSpeed();
124 v3f playerspeeddir(0,0,0);
125 if (playerspeed.getLength() > 1.0f * BS)
126 playerspeeddir = playerspeed / playerspeed.getLength();
127 // Predict to next block
128 v3f playerpos_predicted = playerpos + playerspeeddir * (MAP_BLOCKSIZE * BS);
130 v3s16 center_nodepos = floatToInt(playerpos_predicted, BS);
132 v3s16 center = getNodeBlockPos(center_nodepos);
134 // Camera position and direction
135 v3f camera_pos = sao->getEyePosition();
136 v3f camera_dir = v3f(0,0,1);
137 camera_dir.rotateYZBy(sao->getPitch());
138 camera_dir.rotateXZBy(sao->getYaw());
140 /*infostream<<"camera_dir=("<<camera_dir.X<<","<<camera_dir.Y<<","
141 <<camera_dir.Z<<")"<<std::endl;*/
144 Get the starting value of the block finder radius.
147 if (m_last_center != center) {
148 m_nearest_unsent_d = 0;
149 m_last_center = center;
152 /*infostream<<"m_nearest_unsent_reset_timer="
153 <<m_nearest_unsent_reset_timer<<std::endl;*/
155 // Reset periodically to workaround for some bugs or stuff
156 if (m_nearest_unsent_reset_timer > 20.0f) {
157 m_nearest_unsent_reset_timer = 0.0f;
158 m_nearest_unsent_d = 0;
159 //infostream<<"Resetting m_nearest_unsent_d for "
160 // <<server->getPlayerName(peer_id)<<std::endl;
163 //s16 last_nearest_unsent_d = m_nearest_unsent_d;
164 s16 d_start = m_nearest_unsent_d;
166 //infostream<<"d_start="<<d_start<<std::endl;
168 u16 max_simul_sends_usually = m_max_simul_sends;
171 Check the time from last addNode/removeNode.
173 Decrease send rate if player is building stuff.
175 m_time_from_building += dtime;
176 if (m_time_from_building < m_min_time_from_building) {
177 max_simul_sends_usually
178 = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
182 Number of blocks sending + number of blocks selected for sending
184 u32 num_blocks_selected = m_blocks_sending.size();
187 next time d will be continued from the d from which the nearest
188 unsent block was found this time.
190 This is because not necessarily any of the blocks found this
191 time are actually sent.
193 s32 new_nearest_unsent_d = -1;
195 // Get view range and camera fov (radians) from the client
196 s16 wanted_range = sao->getWantedRange() + 1;
197 float camera_fov = sao->getFov();
199 // If below the heuristic zoom threshold (see adjustDist() in numeric.cpp)
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 // 0.888 radians is slightly larger than the zoom threshold of 1.775 / 2
205 if (camera_fov < 0.888f) {
206 float prop_zoom_fov = sao->getZoomFOV();
207 // If zoom is disabled by value 0
208 if (prop_zoom_fov < 0.001f)
211 // Degrees -> radians
212 camera_fov = prop_zoom_fov * core::DEGTORAD;
215 const s16 full_d_max = std::min(adjustDist(m_max_send_distance, camera_fov),
217 const s16 d_opt = std::min(adjustDist(m_block_optimize_distance, camera_fov),
219 const s16 d_blocks_in_sight = full_d_max * BS * MAP_BLOCKSIZE;
221 s16 d_max = full_d_max;
222 s16 d_max_gen = std::min(adjustDist(m_max_gen_distance, camera_fov),
225 // Don't loop very much at a time, adjust with distance,
226 // do more work per RTT with greater distances.
227 s16 max_d_increment_at_time = full_d_max / 9 + 1;
228 if (d_max > d_start + max_d_increment_at_time)
229 d_max = d_start + max_d_increment_at_time;
231 // cos(angle between velocity and camera) * |velocity|
232 // Limit to 0.0f in case player moves backwards.
233 f32 dot = rangelim(camera_dir.dotProduct(playerspeed), 0.0f, 300.0f);
235 // Reduce the field of view when a player moves and looks forward.
236 // limit max fov effect to 50%, 60% at 20n/s fly speed
237 camera_fov = camera_fov / (1 + dot / 300.0f);
239 s32 nearest_emerged_d = -1;
240 s32 nearest_emergefull_d = -1;
241 s32 nearest_sent_d = -1;
242 //bool queue_is_full = false;
244 const v3s16 cam_pos_nodes = floatToInt(camera_pos, BS);
247 for (d = d_start; d <= d_max; d++) {
249 Get the border/face dot coordinates of a "d-radiused"
252 std::vector<v3s16> list = FacePositionCache::getFacePositions(d);
254 std::vector<v3s16>::iterator li;
255 for (li = list.begin(); li != list.end(); ++li) {
256 v3s16 p = *li + center;
260 - Don't allow too many simultaneous transfers
261 - EXCEPT when the blocks are very close
263 Also, don't send blocks that are already flying.
266 // Start with the usual maximum
267 u16 max_simul_dynamic = max_simul_sends_usually;
269 // If block is very close, allow full maximum
270 if (d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
271 max_simul_dynamic = m_max_simul_sends;
273 // Don't select too many blocks for sending
274 if (num_blocks_selected >= max_simul_dynamic) {
275 //queue_is_full = true;
276 goto queue_full_break;
279 // Don't send blocks that are currently being transferred
280 if (m_blocks_sending.find(p) != m_blocks_sending.end())
284 Do not go over max mapgen limit
286 if (blockpos_over_max_limit(p))
289 // If this is true, inexistent block will be made from scratch
290 bool generate = d <= d_max_gen;
293 Don't generate or send if not in sight
294 FIXME This only works if the client uses a small enough
295 FOV setting. The default of 72 degrees is fine.
296 Also retrieve a smaller view cone in the direction of the player's
298 (0.1 is about 4 degrees)
301 if (!(isBlockInSight(p, camera_pos, camera_dir, camera_fov,
302 d_blocks_in_sight, &dist) ||
303 (playerspeed.getLength() > 1.0f * BS &&
304 isBlockInSight(p, camera_pos, playerspeeddir, 0.1f,
305 d_blocks_in_sight)))) {
310 Don't send already sent blocks
312 if (m_blocks_sent.find(p) != m_blocks_sent.end())
316 Check if map has this block
318 MapBlock *block = env->getMap().getBlockNoCreateNoEx(p);
320 bool surely_not_found_on_disk = false;
321 bool block_is_invalid = false;
323 // Reset usage timer, this block will be of use in the future.
324 block->resetUsageTimer();
326 // Block is dummy if data doesn't exist.
327 // It means it has been not found from disk and not generated
328 if (block->isDummy()) {
329 surely_not_found_on_disk = true;
332 if (!block->isGenerated())
333 block_is_invalid = true;
336 If block is not close, don't send it unless it is near
339 Block is near ground level if night-time mesh
340 differs from day-time mesh.
343 if (!block->getDayNightDiff())
347 if (m_occ_cull && !block_is_invalid &&
348 env->getMap().isBlockOccluded(block, cam_pos_nodes)) {
354 If block has been marked to not exist on disk (dummy)
355 and generating new ones is not wanted, skip block.
357 if (!generate && surely_not_found_on_disk) {
363 Add inexistent block to emerge queue.
365 if (block == NULL || surely_not_found_on_disk || block_is_invalid) {
366 if (emerge->enqueueBlockEmerge(peer_id, p, generate)) {
367 if (nearest_emerged_d == -1)
368 nearest_emerged_d = d;
370 if (nearest_emergefull_d == -1)
371 nearest_emergefull_d = d;
372 goto queue_full_break;
379 if (nearest_sent_d == -1)
383 Add block to send queue
385 PrioritySortedBlockTransfer q((float)dist, p, peer_id);
389 num_blocks_selected += 1;
394 // If nothing was found for sending and nothing was queued for
395 // emerging, continue next time browsing from here
396 if (nearest_emerged_d != -1) {
397 new_nearest_unsent_d = nearest_emerged_d;
398 } else if (nearest_emergefull_d != -1) {
399 new_nearest_unsent_d = nearest_emergefull_d;
401 if (d > full_d_max) {
402 new_nearest_unsent_d = 0;
403 m_nothing_to_send_pause_timer = 2.0f;
405 if (nearest_sent_d != -1)
406 new_nearest_unsent_d = nearest_sent_d;
408 new_nearest_unsent_d = d;
412 if (new_nearest_unsent_d != -1)
413 m_nearest_unsent_d = new_nearest_unsent_d;
416 void RemoteClient::GotBlock(v3s16 p)
418 if (m_blocks_modified.find(p) == m_blocks_modified.end()) {
419 if (m_blocks_sending.find(p) != m_blocks_sending.end())
420 m_blocks_sending.erase(p);
422 m_excess_gotblocks++;
424 m_blocks_sent.insert(p);
428 void RemoteClient::SentBlock(v3s16 p)
430 if (m_blocks_modified.find(p) != m_blocks_modified.end())
431 m_blocks_modified.erase(p);
433 if (m_blocks_sending.find(p) == m_blocks_sending.end())
434 m_blocks_sending[p] = 0.0f;
436 infostream<<"RemoteClient::SentBlock(): Sent block"
437 " already in m_blocks_sending"<<std::endl;
440 void RemoteClient::SetBlockNotSent(v3s16 p)
442 m_nearest_unsent_d = 0;
443 m_nothing_to_send_pause_timer = 0;
445 if (m_blocks_sending.find(p) != m_blocks_sending.end())
446 m_blocks_sending.erase(p);
447 if (m_blocks_sent.find(p) != m_blocks_sent.end())
448 m_blocks_sent.erase(p);
449 m_blocks_modified.insert(p);
452 void RemoteClient::SetBlocksNotSent(std::map<v3s16, MapBlock*> &blocks)
454 m_nearest_unsent_d = 0;
455 m_nothing_to_send_pause_timer = 0;
457 for (auto &block : blocks) {
458 v3s16 p = block.first;
459 m_blocks_modified.insert(p);
461 if (m_blocks_sending.find(p) != m_blocks_sending.end())
462 m_blocks_sending.erase(p);
463 if (m_blocks_sent.find(p) != m_blocks_sent.end())
464 m_blocks_sent.erase(p);
468 void RemoteClient::notifyEvent(ClientStateEvent event)
470 std::ostringstream myerror;
474 //intentionally do nothing
479 m_state = CS_HelloSent;
482 m_state = CS_AwaitingInit2;
485 m_state = CS_Disconnecting;
490 /* GotInit2 SetDefinitionsSent SetMediaSent */
492 myerror << "Created: Invalid client state transition! " << event;
493 throw ClientStateError(myerror.str());
497 /* don't do anything if in denied state */
503 m_state = CS_AwaitingInit2;
504 if (chosen_mech == AUTH_MECHANISM_SRP ||
505 chosen_mech == AUTH_MECHANISM_LEGACY_PASSWORD)
506 srp_verifier_delete((SRPVerifier *) auth_data);
507 chosen_mech = AUTH_MECHANISM_NONE;
510 m_state = CS_Disconnecting;
514 if (chosen_mech == AUTH_MECHANISM_SRP ||
515 chosen_mech == AUTH_MECHANISM_LEGACY_PASSWORD)
516 srp_verifier_delete((SRPVerifier *) auth_data);
517 chosen_mech = AUTH_MECHANISM_NONE;
520 myerror << "HelloSent: Invalid client state transition! " << event;
521 throw ClientStateError(myerror.str());
524 case CS_AwaitingInit2:
528 confirmSerializationVersion();
529 m_state = CS_InitDone;
532 m_state = CS_Disconnecting;
538 /* Init SetDefinitionsSent SetMediaSent */
540 myerror << "InitSent: Invalid client state transition! " << event;
541 throw ClientStateError(myerror.str());
548 case CSE_SetDefinitionsSent:
549 m_state = CS_DefinitionsSent;
552 m_state = CS_Disconnecting;
558 /* Init GotInit2 SetMediaSent */
560 myerror << "InitDone: Invalid client state transition! " << event;
561 throw ClientStateError(myerror.str());
564 case CS_DefinitionsSent:
567 case CSE_SetClientReady:
571 m_state = CS_Disconnecting;
576 /* Init GotInit2 SetDefinitionsSent */
578 myerror << "DefinitionsSent: Invalid client state transition! " << event;
579 throw ClientStateError(myerror.str());
589 m_state = CS_Disconnecting;
591 case CSE_SudoSuccess:
592 m_state = CS_SudoMode;
593 if (chosen_mech == AUTH_MECHANISM_SRP)
594 srp_verifier_delete((SRPVerifier *) auth_data);
595 chosen_mech = AUTH_MECHANISM_NONE;
597 /* Init GotInit2 SetDefinitionsSent SetMediaSent SetDenied */
599 myerror << "Active: Invalid client state transition! " << event;
600 throw ClientStateError(myerror.str());
611 m_state = CS_Disconnecting;
617 myerror << "Active: Invalid client state transition! " << event;
618 throw ClientStateError(myerror.str());
622 case CS_Disconnecting:
623 /* we are already disconnecting */
628 u64 RemoteClient::uptime() const
630 return porting::getTimeS() - m_connection_time;
633 ClientInterface::ClientInterface(const std::shared_ptr<con::Connection> & con)
637 m_print_info_timer(0.0f)
641 ClientInterface::~ClientInterface()
647 MutexAutoLock clientslock(m_clients_mutex);
649 for (auto &client_it : m_clients) {
651 delete client_it.second;
656 std::vector<session_t> ClientInterface::getClientIDs(ClientState min_state)
658 std::vector<session_t> reply;
659 MutexAutoLock clientslock(m_clients_mutex);
661 for (const auto &m_client : m_clients) {
662 if (m_client.second->getState() >= min_state)
663 reply.push_back(m_client.second->peer_id);
669 void ClientInterface::markBlockposAsNotSent(const v3s16 &pos)
671 MutexAutoLock clientslock(m_clients_mutex);
672 for (const auto &client : m_clients) {
673 if (client.second->getState() >= CS_Active)
674 client.second->SetBlockNotSent(pos);
679 * Verify if user limit was reached.
680 * User limit count all clients from HelloSent state (MT protocol user) to Active state
681 * @return true if user limit was reached
683 bool ClientInterface::isUserLimitReached()
685 return getClientIDs(CS_HelloSent).size() >= g_settings->getU16("max_users");
688 void ClientInterface::step(float dtime)
690 m_print_info_timer += dtime;
691 if (m_print_info_timer >= 30.0f) {
692 m_print_info_timer = 0.0f;
697 void ClientInterface::UpdatePlayerList()
700 std::vector<session_t> clients = getClientIDs();
701 m_clients_names.clear();
704 if (!clients.empty())
705 infostream<<"Players:"<<std::endl;
707 for (session_t i : clients) {
708 RemotePlayer *player = m_env->getPlayer(i);
713 infostream << "* " << player->getName() << "\t";
716 MutexAutoLock clientslock(m_clients_mutex);
717 RemoteClient* client = lockedGetClientNoEx(i);
719 client->PrintInfo(infostream);
722 m_clients_names.emplace_back(player->getName());
727 void ClientInterface::send(session_t peer_id, u8 channelnum,
728 NetworkPacket *pkt, bool reliable)
730 m_con->Send(peer_id, channelnum, pkt, reliable);
733 void ClientInterface::sendToAll(NetworkPacket *pkt)
735 MutexAutoLock clientslock(m_clients_mutex);
736 for (auto &client_it : m_clients) {
737 RemoteClient *client = client_it.second;
739 if (client->net_proto_version != 0) {
740 m_con->Send(client->peer_id,
741 clientCommandFactoryTable[pkt->getCommand()].channel, pkt,
742 clientCommandFactoryTable[pkt->getCommand()].reliable);
747 void ClientInterface::sendToAllCompat(NetworkPacket *pkt, NetworkPacket *legacypkt,
750 MutexAutoLock clientslock(m_clients_mutex);
751 for (auto &client_it : m_clients) {
752 RemoteClient *client = client_it.second;
753 NetworkPacket *pkt_to_send = nullptr;
755 if (client->net_proto_version >= min_proto_ver) {
757 } else if (client->net_proto_version != 0) {
758 pkt_to_send = legacypkt;
760 warningstream << "Client with unhandled version to handle: '"
761 << client->net_proto_version << "'";
765 m_con->Send(client->peer_id,
766 clientCommandFactoryTable[pkt_to_send->getCommand()].channel,
768 clientCommandFactoryTable[pkt_to_send->getCommand()].reliable);
772 RemoteClient* ClientInterface::getClientNoEx(session_t peer_id, ClientState state_min)
774 MutexAutoLock clientslock(m_clients_mutex);
775 RemoteClientMap::const_iterator n = m_clients.find(peer_id);
776 // The client may not exist; clients are immediately removed if their
777 // access is denied, and this event occurs later then.
778 if (n == m_clients.end())
781 if (n->second->getState() >= state_min)
787 RemoteClient* ClientInterface::lockedGetClientNoEx(session_t peer_id, ClientState state_min)
789 RemoteClientMap::const_iterator n = m_clients.find(peer_id);
790 // The client may not exist; clients are immediately removed if their
791 // access is denied, and this event occurs later then.
792 if (n == m_clients.end())
795 if (n->second->getState() >= state_min)
801 ClientState ClientInterface::getClientState(session_t peer_id)
803 MutexAutoLock clientslock(m_clients_mutex);
804 RemoteClientMap::const_iterator n = m_clients.find(peer_id);
805 // The client may not exist; clients are immediately removed if their
806 // access is denied, and this event occurs later then.
807 if (n == m_clients.end())
810 return n->second->getState();
813 void ClientInterface::setPlayerName(session_t peer_id, const std::string &name)
815 MutexAutoLock clientslock(m_clients_mutex);
816 RemoteClientMap::iterator n = m_clients.find(peer_id);
817 // The client may not exist; clients are immediately removed if their
818 // access is denied, and this event occurs later then.
819 if (n != m_clients.end())
820 n->second->setName(name);
823 void ClientInterface::DeleteClient(session_t peer_id)
825 MutexAutoLock conlock(m_clients_mutex);
828 RemoteClientMap::iterator n = m_clients.find(peer_id);
829 // The client may not exist; clients are immediately removed if their
830 // access is denied, and this event occurs later then.
831 if (n == m_clients.end())
835 Mark objects to be not known by the client
837 //TODO this should be done by client destructor!!!
838 RemoteClient *client = n->second;
840 for (u16 id : client->m_known_objects) {
842 ServerActiveObject* obj = m_env->getActiveObject(id);
844 if(obj && obj->m_known_by_count > 0)
845 obj->m_known_by_count--;
849 delete m_clients[peer_id];
850 m_clients.erase(peer_id);
853 void ClientInterface::CreateClient(session_t peer_id)
855 MutexAutoLock conlock(m_clients_mutex);
858 RemoteClientMap::iterator n = m_clients.find(peer_id);
859 // The client shouldn't already exist
860 if (n != m_clients.end()) return;
863 RemoteClient *client = new RemoteClient();
864 client->peer_id = peer_id;
865 m_clients[client->peer_id] = client;
868 void ClientInterface::event(session_t peer_id, ClientStateEvent event)
871 MutexAutoLock clientlock(m_clients_mutex);
874 RemoteClientMap::iterator n = m_clients.find(peer_id);
876 // No client to deliver event
877 if (n == m_clients.end())
879 n->second->notifyEvent(event);
882 if ((event == CSE_SetClientReady) ||
883 (event == CSE_Disconnect) ||
884 (event == CSE_SetDenied))
890 u16 ClientInterface::getProtocolVersion(session_t peer_id)
892 MutexAutoLock conlock(m_clients_mutex);
895 RemoteClientMap::iterator n = m_clients.find(peer_id);
897 // No client to get version
898 if (n == m_clients.end())
901 return n->second->net_proto_version;
904 void ClientInterface::setClientVersion(session_t peer_id, u8 major, u8 minor, u8 patch,
905 const std::string &full)
907 MutexAutoLock conlock(m_clients_mutex);
910 RemoteClientMap::iterator n = m_clients.find(peer_id);
912 // No client to set versions
913 if (n == m_clients.end())
916 n->second->setVersionInfo(major, minor, patch, full);