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 // Distrust client-sent FOV and get server-set player object property
200 // zoom FOV (degrees) as a check to avoid hacked clients using FOV to load
202 float prop_zoom_fov = sao->getZoomFOV() * core::DEGTORAD;
204 const s16 full_d_max = std::min(adjustDist(m_max_send_distance, prop_zoom_fov),
206 const s16 d_opt = std::min(adjustDist(m_block_optimize_distance, prop_zoom_fov),
208 const s16 d_blocks_in_sight = full_d_max * BS * MAP_BLOCKSIZE;
210 s16 d_max = full_d_max;
211 s16 d_max_gen = std::min(adjustDist(m_max_gen_distance, prop_zoom_fov),
214 // Don't loop very much at a time, adjust with distance,
215 // do more work per RTT with greater distances.
216 s16 max_d_increment_at_time = full_d_max / 9 + 1;
217 if (d_max > d_start + max_d_increment_at_time)
218 d_max = d_start + max_d_increment_at_time;
220 // cos(angle between velocity and camera) * |velocity|
221 // Limit to 0.0f in case player moves backwards.
222 f32 dot = rangelim(camera_dir.dotProduct(playerspeed), 0.0f, 300.0f);
224 // Reduce the field of view when a player moves and looks forward.
225 // limit max fov effect to 50%, 60% at 20n/s fly speed
226 camera_fov = camera_fov / (1 + dot / 300.0f);
228 s32 nearest_emerged_d = -1;
229 s32 nearest_emergefull_d = -1;
230 s32 nearest_sent_d = -1;
231 //bool queue_is_full = false;
233 const v3s16 cam_pos_nodes = floatToInt(camera_pos, BS);
236 for (d = d_start; d <= d_max; d++) {
238 Get the border/face dot coordinates of a "d-radiused"
241 std::vector<v3s16> list = FacePositionCache::getFacePositions(d);
243 std::vector<v3s16>::iterator li;
244 for (li = list.begin(); li != list.end(); ++li) {
245 v3s16 p = *li + center;
249 - Don't allow too many simultaneous transfers
250 - EXCEPT when the blocks are very close
252 Also, don't send blocks that are already flying.
255 // Start with the usual maximum
256 u16 max_simul_dynamic = max_simul_sends_usually;
258 // If block is very close, allow full maximum
259 if (d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
260 max_simul_dynamic = m_max_simul_sends;
262 // Don't select too many blocks for sending
263 if (num_blocks_selected >= max_simul_dynamic) {
264 //queue_is_full = true;
265 goto queue_full_break;
268 // Don't send blocks that are currently being transferred
269 if (m_blocks_sending.find(p) != m_blocks_sending.end())
273 Do not go over max mapgen limit
275 if (blockpos_over_max_limit(p))
278 // If this is true, inexistent block will be made from scratch
279 bool generate = d <= d_max_gen;
282 Don't generate or send if not in sight
283 FIXME This only works if the client uses a small enough
284 FOV setting. The default of 72 degrees is fine.
285 Also retrieve a smaller view cone in the direction of the player's
287 (0.1 is about 4 degrees)
290 if (!(isBlockInSight(p, camera_pos, camera_dir, camera_fov,
291 d_blocks_in_sight, &dist) ||
292 (playerspeed.getLength() > 1.0f * BS &&
293 isBlockInSight(p, camera_pos, playerspeeddir, 0.1f,
294 d_blocks_in_sight)))) {
299 Don't send already sent blocks
301 if (m_blocks_sent.find(p) != m_blocks_sent.end())
305 Check if map has this block
307 MapBlock *block = env->getMap().getBlockNoCreateNoEx(p);
309 bool surely_not_found_on_disk = false;
310 bool block_is_invalid = false;
312 // Reset usage timer, this block will be of use in the future.
313 block->resetUsageTimer();
315 // Block is dummy if data doesn't exist.
316 // It means it has been not found from disk and not generated
317 if (block->isDummy()) {
318 surely_not_found_on_disk = true;
321 if (!block->isGenerated())
322 block_is_invalid = true;
325 If block is not close, don't send it unless it is near
328 Block is near ground level if night-time mesh
329 differs from day-time mesh.
332 if (!block->getDayNightDiff())
336 if (m_occ_cull && !block_is_invalid &&
337 env->getMap().isBlockOccluded(block, cam_pos_nodes)) {
343 If block has been marked to not exist on disk (dummy)
344 and generating new ones is not wanted, skip block.
346 if (!generate && surely_not_found_on_disk) {
352 Add inexistent block to emerge queue.
354 if (block == NULL || surely_not_found_on_disk || block_is_invalid) {
355 if (emerge->enqueueBlockEmerge(peer_id, p, generate)) {
356 if (nearest_emerged_d == -1)
357 nearest_emerged_d = d;
359 if (nearest_emergefull_d == -1)
360 nearest_emergefull_d = d;
361 goto queue_full_break;
368 if (nearest_sent_d == -1)
372 Add block to send queue
374 PrioritySortedBlockTransfer q((float)dist, p, peer_id);
378 num_blocks_selected += 1;
383 // If nothing was found for sending and nothing was queued for
384 // emerging, continue next time browsing from here
385 if (nearest_emerged_d != -1) {
386 new_nearest_unsent_d = nearest_emerged_d;
387 } else if (nearest_emergefull_d != -1) {
388 new_nearest_unsent_d = nearest_emergefull_d;
390 if (d > full_d_max) {
391 new_nearest_unsent_d = 0;
392 m_nothing_to_send_pause_timer = 2.0f;
394 if (nearest_sent_d != -1)
395 new_nearest_unsent_d = nearest_sent_d;
397 new_nearest_unsent_d = d;
401 if (new_nearest_unsent_d != -1)
402 m_nearest_unsent_d = new_nearest_unsent_d;
405 void RemoteClient::GotBlock(v3s16 p)
407 if (m_blocks_modified.find(p) == m_blocks_modified.end()) {
408 if (m_blocks_sending.find(p) != m_blocks_sending.end())
409 m_blocks_sending.erase(p);
411 m_excess_gotblocks++;
413 m_blocks_sent.insert(p);
417 void RemoteClient::SentBlock(v3s16 p)
419 if (m_blocks_modified.find(p) != m_blocks_modified.end())
420 m_blocks_modified.erase(p);
422 if (m_blocks_sending.find(p) == m_blocks_sending.end())
423 m_blocks_sending[p] = 0.0f;
425 infostream<<"RemoteClient::SentBlock(): Sent block"
426 " already in m_blocks_sending"<<std::endl;
429 void RemoteClient::SetBlockNotSent(v3s16 p)
431 m_nearest_unsent_d = 0;
432 m_nothing_to_send_pause_timer = 0;
434 if (m_blocks_sending.find(p) != m_blocks_sending.end())
435 m_blocks_sending.erase(p);
436 if (m_blocks_sent.find(p) != m_blocks_sent.end())
437 m_blocks_sent.erase(p);
438 m_blocks_modified.insert(p);
441 void RemoteClient::SetBlocksNotSent(std::map<v3s16, MapBlock*> &blocks)
443 m_nearest_unsent_d = 0;
444 m_nothing_to_send_pause_timer = 0;
446 for (auto &block : blocks) {
447 v3s16 p = block.first;
448 m_blocks_modified.insert(p);
450 if (m_blocks_sending.find(p) != m_blocks_sending.end())
451 m_blocks_sending.erase(p);
452 if (m_blocks_sent.find(p) != m_blocks_sent.end())
453 m_blocks_sent.erase(p);
457 void RemoteClient::notifyEvent(ClientStateEvent event)
459 std::ostringstream myerror;
463 //intentionally do nothing
468 m_state = CS_HelloSent;
471 m_state = CS_AwaitingInit2;
474 m_state = CS_Disconnecting;
479 /* GotInit2 SetDefinitionsSent SetMediaSent */
481 myerror << "Created: Invalid client state transition! " << event;
482 throw ClientStateError(myerror.str());
486 /* don't do anything if in denied state */
492 m_state = CS_AwaitingInit2;
493 if (chosen_mech == AUTH_MECHANISM_SRP ||
494 chosen_mech == AUTH_MECHANISM_LEGACY_PASSWORD)
495 srp_verifier_delete((SRPVerifier *) auth_data);
496 chosen_mech = AUTH_MECHANISM_NONE;
499 m_state = CS_Disconnecting;
503 if (chosen_mech == AUTH_MECHANISM_SRP ||
504 chosen_mech == AUTH_MECHANISM_LEGACY_PASSWORD)
505 srp_verifier_delete((SRPVerifier *) auth_data);
506 chosen_mech = AUTH_MECHANISM_NONE;
509 myerror << "HelloSent: Invalid client state transition! " << event;
510 throw ClientStateError(myerror.str());
513 case CS_AwaitingInit2:
517 confirmSerializationVersion();
518 m_state = CS_InitDone;
521 m_state = CS_Disconnecting;
527 /* Init SetDefinitionsSent SetMediaSent */
529 myerror << "InitSent: Invalid client state transition! " << event;
530 throw ClientStateError(myerror.str());
537 case CSE_SetDefinitionsSent:
538 m_state = CS_DefinitionsSent;
541 m_state = CS_Disconnecting;
547 /* Init GotInit2 SetMediaSent */
549 myerror << "InitDone: Invalid client state transition! " << event;
550 throw ClientStateError(myerror.str());
553 case CS_DefinitionsSent:
556 case CSE_SetClientReady:
560 m_state = CS_Disconnecting;
565 /* Init GotInit2 SetDefinitionsSent */
567 myerror << "DefinitionsSent: Invalid client state transition! " << event;
568 throw ClientStateError(myerror.str());
578 m_state = CS_Disconnecting;
580 case CSE_SudoSuccess:
581 m_state = CS_SudoMode;
582 if (chosen_mech == AUTH_MECHANISM_SRP)
583 srp_verifier_delete((SRPVerifier *) auth_data);
584 chosen_mech = AUTH_MECHANISM_NONE;
586 /* Init GotInit2 SetDefinitionsSent SetMediaSent SetDenied */
588 myerror << "Active: Invalid client state transition! " << event;
589 throw ClientStateError(myerror.str());
600 m_state = CS_Disconnecting;
606 myerror << "Active: Invalid client state transition! " << event;
607 throw ClientStateError(myerror.str());
611 case CS_Disconnecting:
612 /* we are already disconnecting */
617 u64 RemoteClient::uptime() const
619 return porting::getTimeS() - m_connection_time;
622 ClientInterface::ClientInterface(const std::shared_ptr<con::Connection> & con)
626 m_print_info_timer(0.0f)
630 ClientInterface::~ClientInterface()
636 MutexAutoLock clientslock(m_clients_mutex);
638 for (auto &client_it : m_clients) {
640 delete client_it.second;
645 std::vector<session_t> ClientInterface::getClientIDs(ClientState min_state)
647 std::vector<session_t> reply;
648 MutexAutoLock clientslock(m_clients_mutex);
650 for (const auto &m_client : m_clients) {
651 if (m_client.second->getState() >= min_state)
652 reply.push_back(m_client.second->peer_id);
658 void ClientInterface::markBlockposAsNotSent(const v3s16 &pos)
660 MutexAutoLock clientslock(m_clients_mutex);
661 for (const auto &client : m_clients) {
662 if (client.second->getState() >= CS_Active)
663 client.second->SetBlockNotSent(pos);
668 * Verify if user limit was reached.
669 * User limit count all clients from HelloSent state (MT protocol user) to Active state
670 * @return true if user limit was reached
672 bool ClientInterface::isUserLimitReached()
674 return getClientIDs(CS_HelloSent).size() >= g_settings->getU16("max_users");
677 void ClientInterface::step(float dtime)
679 m_print_info_timer += dtime;
680 if (m_print_info_timer >= 30.0f) {
681 m_print_info_timer = 0.0f;
686 void ClientInterface::UpdatePlayerList()
689 std::vector<session_t> clients = getClientIDs();
690 m_clients_names.clear();
693 if (!clients.empty())
694 infostream<<"Players:"<<std::endl;
696 for (session_t i : clients) {
697 RemotePlayer *player = m_env->getPlayer(i);
702 infostream << "* " << player->getName() << "\t";
705 MutexAutoLock clientslock(m_clients_mutex);
706 RemoteClient* client = lockedGetClientNoEx(i);
708 client->PrintInfo(infostream);
711 m_clients_names.emplace_back(player->getName());
716 void ClientInterface::send(session_t peer_id, u8 channelnum,
717 NetworkPacket *pkt, bool reliable)
719 m_con->Send(peer_id, channelnum, pkt, reliable);
722 void ClientInterface::sendToAll(NetworkPacket *pkt)
724 MutexAutoLock clientslock(m_clients_mutex);
725 for (auto &client_it : m_clients) {
726 RemoteClient *client = client_it.second;
728 if (client->net_proto_version != 0) {
729 m_con->Send(client->peer_id,
730 clientCommandFactoryTable[pkt->getCommand()].channel, pkt,
731 clientCommandFactoryTable[pkt->getCommand()].reliable);
736 void ClientInterface::sendToAllCompat(NetworkPacket *pkt, NetworkPacket *legacypkt,
739 MutexAutoLock clientslock(m_clients_mutex);
740 for (auto &client_it : m_clients) {
741 RemoteClient *client = client_it.second;
742 NetworkPacket *pkt_to_send = nullptr;
744 if (client->net_proto_version >= min_proto_ver) {
746 } else if (client->net_proto_version != 0) {
747 pkt_to_send = legacypkt;
749 warningstream << "Client with unhandled version to handle: '"
750 << client->net_proto_version << "'";
754 m_con->Send(client->peer_id,
755 clientCommandFactoryTable[pkt_to_send->getCommand()].channel,
757 clientCommandFactoryTable[pkt_to_send->getCommand()].reliable);
761 RemoteClient* ClientInterface::getClientNoEx(session_t peer_id, ClientState state_min)
763 MutexAutoLock clientslock(m_clients_mutex);
764 RemoteClientMap::const_iterator n = m_clients.find(peer_id);
765 // The client may not exist; clients are immediately removed if their
766 // access is denied, and this event occurs later then.
767 if (n == m_clients.end())
770 if (n->second->getState() >= state_min)
776 RemoteClient* ClientInterface::lockedGetClientNoEx(session_t peer_id, ClientState state_min)
778 RemoteClientMap::const_iterator n = m_clients.find(peer_id);
779 // The client may not exist; clients are immediately removed if their
780 // access is denied, and this event occurs later then.
781 if (n == m_clients.end())
784 if (n->second->getState() >= state_min)
790 ClientState ClientInterface::getClientState(session_t peer_id)
792 MutexAutoLock clientslock(m_clients_mutex);
793 RemoteClientMap::const_iterator n = m_clients.find(peer_id);
794 // The client may not exist; clients are immediately removed if their
795 // access is denied, and this event occurs later then.
796 if (n == m_clients.end())
799 return n->second->getState();
802 void ClientInterface::setPlayerName(session_t peer_id, const std::string &name)
804 MutexAutoLock clientslock(m_clients_mutex);
805 RemoteClientMap::iterator n = m_clients.find(peer_id);
806 // The client may not exist; clients are immediately removed if their
807 // access is denied, and this event occurs later then.
808 if (n != m_clients.end())
809 n->second->setName(name);
812 void ClientInterface::DeleteClient(session_t peer_id)
814 MutexAutoLock conlock(m_clients_mutex);
817 RemoteClientMap::iterator n = m_clients.find(peer_id);
818 // The client may not exist; clients are immediately removed if their
819 // access is denied, and this event occurs later then.
820 if (n == m_clients.end())
824 Mark objects to be not known by the client
826 //TODO this should be done by client destructor!!!
827 RemoteClient *client = n->second;
829 for (u16 id : client->m_known_objects) {
831 ServerActiveObject* obj = m_env->getActiveObject(id);
833 if(obj && obj->m_known_by_count > 0)
834 obj->m_known_by_count--;
838 delete m_clients[peer_id];
839 m_clients.erase(peer_id);
842 void ClientInterface::CreateClient(session_t peer_id)
844 MutexAutoLock conlock(m_clients_mutex);
847 RemoteClientMap::iterator n = m_clients.find(peer_id);
848 // The client shouldn't already exist
849 if (n != m_clients.end()) return;
852 RemoteClient *client = new RemoteClient();
853 client->peer_id = peer_id;
854 m_clients[client->peer_id] = client;
857 void ClientInterface::event(session_t peer_id, ClientStateEvent event)
860 MutexAutoLock clientlock(m_clients_mutex);
863 RemoteClientMap::iterator n = m_clients.find(peer_id);
865 // No client to deliver event
866 if (n == m_clients.end())
868 n->second->notifyEvent(event);
871 if ((event == CSE_SetClientReady) ||
872 (event == CSE_Disconnect) ||
873 (event == CSE_SetDenied))
879 u16 ClientInterface::getProtocolVersion(session_t peer_id)
881 MutexAutoLock conlock(m_clients_mutex);
884 RemoteClientMap::iterator n = m_clients.find(peer_id);
886 // No client to get version
887 if (n == m_clients.end())
890 return n->second->net_proto_version;
893 void ClientInterface::setClientVersion(session_t peer_id, u8 major, u8 minor, u8 patch,
894 const std::string &full)
896 MutexAutoLock conlock(m_clients_mutex);
899 RemoteClientMap::iterator n = m_clients.find(peer_id);
901 // No client to set versions
902 if (n == m_clients.end())
905 n->second->setVersionInfo(major, minor, patch, full);