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->getLookPitch());
138 camera_dir.rotateXZBy(sao->getRotation().Y);
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 // (zoom is disabled by value 0)
203 float prop_zoom_fov = sao->getZoomFOV() < 0.001f ?
205 std::max(camera_fov, sao->getZoomFOV() * core::DEGTORAD);
207 const s16 full_d_max = std::min(adjustDist(m_max_send_distance, prop_zoom_fov),
209 const s16 d_opt = std::min(adjustDist(m_block_optimize_distance, prop_zoom_fov),
211 const s16 d_blocks_in_sight = full_d_max * BS * MAP_BLOCKSIZE;
213 s16 d_max = full_d_max;
214 s16 d_max_gen = std::min(adjustDist(m_max_gen_distance, prop_zoom_fov),
217 // Don't loop very much at a time, adjust with distance,
218 // do more work per RTT with greater distances.
219 s16 max_d_increment_at_time = full_d_max / 9 + 1;
220 if (d_max > d_start + max_d_increment_at_time)
221 d_max = d_start + max_d_increment_at_time;
223 // cos(angle between velocity and camera) * |velocity|
224 // Limit to 0.0f in case player moves backwards.
225 f32 dot = rangelim(camera_dir.dotProduct(playerspeed), 0.0f, 300.0f);
227 // Reduce the field of view when a player moves and looks forward.
228 // limit max fov effect to 50%, 60% at 20n/s fly speed
229 camera_fov = camera_fov / (1 + dot / 300.0f);
231 s32 nearest_emerged_d = -1;
232 s32 nearest_emergefull_d = -1;
233 s32 nearest_sent_d = -1;
234 //bool queue_is_full = false;
236 const v3s16 cam_pos_nodes = floatToInt(camera_pos, BS);
239 for (d = d_start; d <= d_max; d++) {
241 Get the border/face dot coordinates of a "d-radiused"
244 std::vector<v3s16> list = FacePositionCache::getFacePositions(d);
246 std::vector<v3s16>::iterator li;
247 for (li = list.begin(); li != list.end(); ++li) {
248 v3s16 p = *li + center;
252 - Don't allow too many simultaneous transfers
253 - EXCEPT when the blocks are very close
255 Also, don't send blocks that are already flying.
258 // Start with the usual maximum
259 u16 max_simul_dynamic = max_simul_sends_usually;
261 // If block is very close, allow full maximum
262 if (d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
263 max_simul_dynamic = m_max_simul_sends;
265 // Don't select too many blocks for sending
266 if (num_blocks_selected >= max_simul_dynamic) {
267 //queue_is_full = true;
268 goto queue_full_break;
271 // Don't send blocks that are currently being transferred
272 if (m_blocks_sending.find(p) != m_blocks_sending.end())
276 Do not go over max mapgen limit
278 if (blockpos_over_max_limit(p))
281 // If this is true, inexistent block will be made from scratch
282 bool generate = d <= d_max_gen;
285 Don't generate or send if not in sight
286 FIXME This only works if the client uses a small enough
287 FOV setting. The default of 72 degrees is fine.
288 Also retrieve a smaller view cone in the direction of the player's
290 (0.1 is about 4 degrees)
293 if (!(isBlockInSight(p, camera_pos, camera_dir, camera_fov,
294 d_blocks_in_sight, &dist) ||
295 (playerspeed.getLength() > 1.0f * BS &&
296 isBlockInSight(p, camera_pos, playerspeeddir, 0.1f,
297 d_blocks_in_sight)))) {
302 Don't send already sent blocks
304 if (m_blocks_sent.find(p) != m_blocks_sent.end())
308 Check if map has this block
310 MapBlock *block = env->getMap().getBlockNoCreateNoEx(p);
312 bool surely_not_found_on_disk = false;
313 bool block_is_invalid = false;
315 // Reset usage timer, this block will be of use in the future.
316 block->resetUsageTimer();
318 // Block is dummy if data doesn't exist.
319 // It means it has been not found from disk and not generated
320 if (block->isDummy()) {
321 surely_not_found_on_disk = true;
324 if (!block->isGenerated())
325 block_is_invalid = true;
328 If block is not close, don't send it unless it is near
331 Block is near ground level if night-time mesh
332 differs from day-time mesh.
335 if (!block->getIsUnderground() && !block->getDayNightDiff())
339 if (m_occ_cull && !block_is_invalid &&
340 env->getMap().isBlockOccluded(block, cam_pos_nodes)) {
346 If block has been marked to not exist on disk (dummy)
347 and generating new ones is not wanted, skip block.
349 if (!generate && surely_not_found_on_disk) {
355 Add inexistent block to emerge queue.
357 if (block == NULL || surely_not_found_on_disk || block_is_invalid) {
358 if (emerge->enqueueBlockEmerge(peer_id, p, generate)) {
359 if (nearest_emerged_d == -1)
360 nearest_emerged_d = d;
362 if (nearest_emergefull_d == -1)
363 nearest_emergefull_d = d;
364 goto queue_full_break;
371 if (nearest_sent_d == -1)
375 Add block to send queue
377 PrioritySortedBlockTransfer q((float)dist, p, peer_id);
381 num_blocks_selected += 1;
386 // If nothing was found for sending and nothing was queued for
387 // emerging, continue next time browsing from here
388 if (nearest_emerged_d != -1) {
389 new_nearest_unsent_d = nearest_emerged_d;
390 } else if (nearest_emergefull_d != -1) {
391 new_nearest_unsent_d = nearest_emergefull_d;
393 if (d > full_d_max) {
394 new_nearest_unsent_d = 0;
395 m_nothing_to_send_pause_timer = 2.0f;
397 if (nearest_sent_d != -1)
398 new_nearest_unsent_d = nearest_sent_d;
400 new_nearest_unsent_d = d;
404 if (new_nearest_unsent_d != -1)
405 m_nearest_unsent_d = new_nearest_unsent_d;
408 void RemoteClient::GotBlock(v3s16 p)
410 if (m_blocks_modified.find(p) == m_blocks_modified.end()) {
411 if (m_blocks_sending.find(p) != m_blocks_sending.end())
412 m_blocks_sending.erase(p);
414 m_excess_gotblocks++;
416 m_blocks_sent.insert(p);
420 void RemoteClient::SentBlock(v3s16 p)
422 if (m_blocks_modified.find(p) != m_blocks_modified.end())
423 m_blocks_modified.erase(p);
425 if (m_blocks_sending.find(p) == m_blocks_sending.end())
426 m_blocks_sending[p] = 0.0f;
428 infostream<<"RemoteClient::SentBlock(): Sent block"
429 " already in m_blocks_sending"<<std::endl;
432 void RemoteClient::SetBlockNotSent(v3s16 p)
434 m_nearest_unsent_d = 0;
435 m_nothing_to_send_pause_timer = 0;
437 if (m_blocks_sending.find(p) != m_blocks_sending.end())
438 m_blocks_sending.erase(p);
439 if (m_blocks_sent.find(p) != m_blocks_sent.end())
440 m_blocks_sent.erase(p);
441 m_blocks_modified.insert(p);
444 void RemoteClient::SetBlocksNotSent(std::map<v3s16, MapBlock*> &blocks)
446 m_nearest_unsent_d = 0;
447 m_nothing_to_send_pause_timer = 0;
449 for (auto &block : blocks) {
450 v3s16 p = block.first;
451 m_blocks_modified.insert(p);
453 if (m_blocks_sending.find(p) != m_blocks_sending.end())
454 m_blocks_sending.erase(p);
455 if (m_blocks_sent.find(p) != m_blocks_sent.end())
456 m_blocks_sent.erase(p);
460 void RemoteClient::notifyEvent(ClientStateEvent event)
462 std::ostringstream myerror;
466 //intentionally do nothing
471 m_state = CS_HelloSent;
474 m_state = CS_AwaitingInit2;
477 m_state = CS_Disconnecting;
482 /* GotInit2 SetDefinitionsSent SetMediaSent */
484 myerror << "Created: Invalid client state transition! " << event;
485 throw ClientStateError(myerror.str());
489 /* don't do anything if in denied state */
495 m_state = CS_AwaitingInit2;
496 if (chosen_mech == AUTH_MECHANISM_SRP ||
497 chosen_mech == AUTH_MECHANISM_LEGACY_PASSWORD)
498 srp_verifier_delete((SRPVerifier *) auth_data);
499 chosen_mech = AUTH_MECHANISM_NONE;
502 m_state = CS_Disconnecting;
506 if (chosen_mech == AUTH_MECHANISM_SRP ||
507 chosen_mech == AUTH_MECHANISM_LEGACY_PASSWORD)
508 srp_verifier_delete((SRPVerifier *) auth_data);
509 chosen_mech = AUTH_MECHANISM_NONE;
512 myerror << "HelloSent: Invalid client state transition! " << event;
513 throw ClientStateError(myerror.str());
516 case CS_AwaitingInit2:
520 confirmSerializationVersion();
521 m_state = CS_InitDone;
524 m_state = CS_Disconnecting;
530 /* Init SetDefinitionsSent SetMediaSent */
532 myerror << "InitSent: Invalid client state transition! " << event;
533 throw ClientStateError(myerror.str());
540 case CSE_SetDefinitionsSent:
541 m_state = CS_DefinitionsSent;
544 m_state = CS_Disconnecting;
550 /* Init GotInit2 SetMediaSent */
552 myerror << "InitDone: Invalid client state transition! " << event;
553 throw ClientStateError(myerror.str());
556 case CS_DefinitionsSent:
559 case CSE_SetClientReady:
563 m_state = CS_Disconnecting;
568 /* Init GotInit2 SetDefinitionsSent */
570 myerror << "DefinitionsSent: Invalid client state transition! " << event;
571 throw ClientStateError(myerror.str());
581 m_state = CS_Disconnecting;
583 case CSE_SudoSuccess:
584 m_state = CS_SudoMode;
585 if (chosen_mech == AUTH_MECHANISM_SRP)
586 srp_verifier_delete((SRPVerifier *) auth_data);
587 chosen_mech = AUTH_MECHANISM_NONE;
589 /* Init GotInit2 SetDefinitionsSent SetMediaSent SetDenied */
591 myerror << "Active: Invalid client state transition! " << event;
592 throw ClientStateError(myerror.str());
603 m_state = CS_Disconnecting;
609 myerror << "Active: Invalid client state transition! " << event;
610 throw ClientStateError(myerror.str());
614 case CS_Disconnecting:
615 /* we are already disconnecting */
620 u64 RemoteClient::uptime() const
622 return porting::getTimeS() - m_connection_time;
625 ClientInterface::ClientInterface(const std::shared_ptr<con::Connection> & con)
629 m_print_info_timer(0.0f)
633 ClientInterface::~ClientInterface()
639 RecursiveMutexAutoLock clientslock(m_clients_mutex);
641 for (auto &client_it : m_clients) {
643 delete client_it.second;
648 std::vector<session_t> ClientInterface::getClientIDs(ClientState min_state)
650 std::vector<session_t> reply;
651 RecursiveMutexAutoLock clientslock(m_clients_mutex);
653 for (const auto &m_client : m_clients) {
654 if (m_client.second->getState() >= min_state)
655 reply.push_back(m_client.second->peer_id);
661 void ClientInterface::markBlockposAsNotSent(const v3s16 &pos)
663 RecursiveMutexAutoLock clientslock(m_clients_mutex);
664 for (const auto &client : m_clients) {
665 if (client.second->getState() >= CS_Active)
666 client.second->SetBlockNotSent(pos);
671 * Verify if user limit was reached.
672 * User limit count all clients from HelloSent state (MT protocol user) to Active state
673 * @return true if user limit was reached
675 bool ClientInterface::isUserLimitReached()
677 return getClientIDs(CS_HelloSent).size() >= g_settings->getU16("max_users");
680 void ClientInterface::step(float dtime)
682 m_print_info_timer += dtime;
683 if (m_print_info_timer >= 30.0f) {
684 m_print_info_timer = 0.0f;
689 void ClientInterface::UpdatePlayerList()
692 std::vector<session_t> clients = getClientIDs();
693 m_clients_names.clear();
696 if (!clients.empty())
697 infostream<<"Players:"<<std::endl;
699 for (session_t i : clients) {
700 RemotePlayer *player = m_env->getPlayer(i);
705 infostream << "* " << player->getName() << "\t";
708 RecursiveMutexAutoLock clientslock(m_clients_mutex);
709 RemoteClient* client = lockedGetClientNoEx(i);
711 client->PrintInfo(infostream);
714 m_clients_names.emplace_back(player->getName());
719 void ClientInterface::send(session_t peer_id, u8 channelnum,
720 NetworkPacket *pkt, bool reliable)
722 m_con->Send(peer_id, channelnum, pkt, reliable);
725 void ClientInterface::sendToAll(NetworkPacket *pkt)
727 RecursiveMutexAutoLock clientslock(m_clients_mutex);
728 for (auto &client_it : m_clients) {
729 RemoteClient *client = client_it.second;
731 if (client->net_proto_version != 0) {
732 m_con->Send(client->peer_id,
733 clientCommandFactoryTable[pkt->getCommand()].channel, pkt,
734 clientCommandFactoryTable[pkt->getCommand()].reliable);
739 void ClientInterface::sendToAllCompat(NetworkPacket *pkt, NetworkPacket *legacypkt,
742 RecursiveMutexAutoLock clientslock(m_clients_mutex);
743 for (auto &client_it : m_clients) {
744 RemoteClient *client = client_it.second;
745 NetworkPacket *pkt_to_send = nullptr;
747 if (client->net_proto_version >= min_proto_ver) {
749 } else if (client->net_proto_version != 0) {
750 pkt_to_send = legacypkt;
752 warningstream << "Client with unhandled version to handle: '"
753 << client->net_proto_version << "'";
757 m_con->Send(client->peer_id,
758 clientCommandFactoryTable[pkt_to_send->getCommand()].channel,
760 clientCommandFactoryTable[pkt_to_send->getCommand()].reliable);
764 RemoteClient* ClientInterface::getClientNoEx(session_t peer_id, ClientState state_min)
766 RecursiveMutexAutoLock clientslock(m_clients_mutex);
767 RemoteClientMap::const_iterator n = m_clients.find(peer_id);
768 // The client may not exist; clients are immediately removed if their
769 // access is denied, and this event occurs later then.
770 if (n == m_clients.end())
773 if (n->second->getState() >= state_min)
779 RemoteClient* ClientInterface::lockedGetClientNoEx(session_t peer_id, ClientState state_min)
781 RemoteClientMap::const_iterator n = m_clients.find(peer_id);
782 // The client may not exist; clients are immediately removed if their
783 // access is denied, and this event occurs later then.
784 if (n == m_clients.end())
787 if (n->second->getState() >= state_min)
793 ClientState ClientInterface::getClientState(session_t peer_id)
795 RecursiveMutexAutoLock clientslock(m_clients_mutex);
796 RemoteClientMap::const_iterator n = m_clients.find(peer_id);
797 // The client may not exist; clients are immediately removed if their
798 // access is denied, and this event occurs later then.
799 if (n == m_clients.end())
802 return n->second->getState();
805 void ClientInterface::setPlayerName(session_t peer_id, const std::string &name)
807 RecursiveMutexAutoLock clientslock(m_clients_mutex);
808 RemoteClientMap::iterator n = m_clients.find(peer_id);
809 // The client may not exist; clients are immediately removed if their
810 // access is denied, and this event occurs later then.
811 if (n != m_clients.end())
812 n->second->setName(name);
815 void ClientInterface::DeleteClient(session_t peer_id)
817 RecursiveMutexAutoLock conlock(m_clients_mutex);
820 RemoteClientMap::iterator n = m_clients.find(peer_id);
821 // The client may not exist; clients are immediately removed if their
822 // access is denied, and this event occurs later then.
823 if (n == m_clients.end())
827 Mark objects to be not known by the client
829 //TODO this should be done by client destructor!!!
830 RemoteClient *client = n->second;
832 for (u16 id : client->m_known_objects) {
834 ServerActiveObject* obj = m_env->getActiveObject(id);
836 if(obj && obj->m_known_by_count > 0)
837 obj->m_known_by_count--;
841 delete m_clients[peer_id];
842 m_clients.erase(peer_id);
845 void ClientInterface::CreateClient(session_t peer_id)
847 RecursiveMutexAutoLock conlock(m_clients_mutex);
850 RemoteClientMap::iterator n = m_clients.find(peer_id);
851 // The client shouldn't already exist
852 if (n != m_clients.end()) return;
855 RemoteClient *client = new RemoteClient();
856 client->peer_id = peer_id;
857 m_clients[client->peer_id] = client;
860 void ClientInterface::event(session_t peer_id, ClientStateEvent event)
863 RecursiveMutexAutoLock clientlock(m_clients_mutex);
866 RemoteClientMap::iterator n = m_clients.find(peer_id);
868 // No client to deliver event
869 if (n == m_clients.end())
871 n->second->notifyEvent(event);
874 if ((event == CSE_SetClientReady) ||
875 (event == CSE_Disconnect) ||
876 (event == CSE_SetDenied))
882 u16 ClientInterface::getProtocolVersion(session_t peer_id)
884 RecursiveMutexAutoLock conlock(m_clients_mutex);
887 RemoteClientMap::iterator n = m_clients.find(peer_id);
889 // No client to get version
890 if (n == m_clients.end())
893 return n->second->net_proto_version;
896 void ClientInterface::setClientVersion(session_t peer_id, u8 major, u8 minor, u8 patch,
897 const std::string &full)
899 RecursiveMutexAutoLock conlock(m_clients_mutex);
902 RemoteClientMap::iterator n = m_clients.find(peer_id);
904 // No client to set versions
905 if (n == m_clients.end())
908 n->second->setVersionInfo(major, minor, patch, full);