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 from the client
196 s16 wanted_range = sao->getWantedRange() + 1;
197 float camera_fov = sao->getFov();
199 const s16 full_d_max = std::min(adjustDist(m_max_send_distance, camera_fov), wanted_range);
200 const s16 d_opt = std::min(adjustDist(m_block_optimize_distance, camera_fov), wanted_range);
201 const s16 d_blocks_in_sight = full_d_max * BS * MAP_BLOCKSIZE;
202 //infostream << "Fov from client " << camera_fov << " full_d_max " << full_d_max << std::endl;
204 s16 d_max = full_d_max;
205 s16 d_max_gen = std::min(adjustDist(m_max_gen_distance, camera_fov), wanted_range);
207 // Don't loop very much at a time, adjust with distance,
208 // do more work per RTT with greater distances.
209 s16 max_d_increment_at_time = full_d_max / 9 + 1;
210 if (d_max > d_start + max_d_increment_at_time)
211 d_max = d_start + max_d_increment_at_time;
213 // cos(angle between velocity and camera) * |velocity|
214 // Limit to 0.0f in case player moves backwards.
215 f32 dot = rangelim(camera_dir.dotProduct(playerspeed), 0.0f, 300.0f);
217 // Reduce the field of view when a player moves and looks forward.
218 // limit max fov effect to 50%, 60% at 20n/s fly speed
219 camera_fov = camera_fov / (1 + dot / 300.0f);
221 s32 nearest_emerged_d = -1;
222 s32 nearest_emergefull_d = -1;
223 s32 nearest_sent_d = -1;
224 //bool queue_is_full = false;
226 const v3s16 cam_pos_nodes = floatToInt(camera_pos, BS);
229 for (d = d_start; d <= d_max; d++) {
231 Get the border/face dot coordinates of a "d-radiused"
234 std::vector<v3s16> list = FacePositionCache::getFacePositions(d);
236 std::vector<v3s16>::iterator li;
237 for (li = list.begin(); li != list.end(); ++li) {
238 v3s16 p = *li + center;
242 - Don't allow too many simultaneous transfers
243 - EXCEPT when the blocks are very close
245 Also, don't send blocks that are already flying.
248 // Start with the usual maximum
249 u16 max_simul_dynamic = max_simul_sends_usually;
251 // If block is very close, allow full maximum
252 if (d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
253 max_simul_dynamic = m_max_simul_sends;
255 // Don't select too many blocks for sending
256 if (num_blocks_selected >= max_simul_dynamic) {
257 //queue_is_full = true;
258 goto queue_full_break;
261 // Don't send blocks that are currently being transferred
262 if (m_blocks_sending.find(p) != m_blocks_sending.end())
266 Do not go over max mapgen limit
268 if (blockpos_over_max_limit(p))
271 // If this is true, inexistent block will be made from scratch
272 bool generate = d <= d_max_gen;
275 Don't generate or send if not in sight
276 FIXME This only works if the client uses a small enough
277 FOV setting. The default of 72 degrees is fine.
278 Also retrieve a smaller view cone in the direction of the player's
280 (0.1 is about 4 degrees)
283 if (!(isBlockInSight(p, camera_pos, camera_dir, camera_fov,
284 d_blocks_in_sight, &dist) ||
285 (playerspeed.getLength() > 1.0f * BS &&
286 isBlockInSight(p, camera_pos, playerspeeddir, 0.1f,
287 d_blocks_in_sight)))) {
292 Don't send already sent blocks
294 if (m_blocks_sent.find(p) != m_blocks_sent.end())
298 Check if map has this block
300 MapBlock *block = env->getMap().getBlockNoCreateNoEx(p);
302 bool surely_not_found_on_disk = false;
303 bool block_is_invalid = false;
305 // Reset usage timer, this block will be of use in the future.
306 block->resetUsageTimer();
308 // Block is dummy if data doesn't exist.
309 // It means it has been not found from disk and not generated
310 if (block->isDummy()) {
311 surely_not_found_on_disk = true;
314 if (!block->isGenerated())
315 block_is_invalid = true;
318 If block is not close, don't send it unless it is near
321 Block is near ground level if night-time mesh
322 differs from day-time mesh.
325 if (!block->getDayNightDiff())
329 if (m_occ_cull && !block_is_invalid &&
330 env->getMap().isBlockOccluded(block, cam_pos_nodes)) {
336 If block has been marked to not exist on disk (dummy)
337 and generating new ones is not wanted, skip block.
339 if (!generate && surely_not_found_on_disk) {
345 Add inexistent block to emerge queue.
347 if (block == NULL || surely_not_found_on_disk || block_is_invalid) {
348 if (emerge->enqueueBlockEmerge(peer_id, p, generate)) {
349 if (nearest_emerged_d == -1)
350 nearest_emerged_d = d;
352 if (nearest_emergefull_d == -1)
353 nearest_emergefull_d = d;
354 goto queue_full_break;
361 if (nearest_sent_d == -1)
365 Add block to send queue
367 PrioritySortedBlockTransfer q((float)dist, p, peer_id);
371 num_blocks_selected += 1;
376 // If nothing was found for sending and nothing was queued for
377 // emerging, continue next time browsing from here
378 if (nearest_emerged_d != -1) {
379 new_nearest_unsent_d = nearest_emerged_d;
380 } else if (nearest_emergefull_d != -1) {
381 new_nearest_unsent_d = nearest_emergefull_d;
383 if (d > full_d_max) {
384 new_nearest_unsent_d = 0;
385 m_nothing_to_send_pause_timer = 2.0f;
387 if (nearest_sent_d != -1)
388 new_nearest_unsent_d = nearest_sent_d;
390 new_nearest_unsent_d = d;
394 if (new_nearest_unsent_d != -1)
395 m_nearest_unsent_d = new_nearest_unsent_d;
398 void RemoteClient::GotBlock(v3s16 p)
400 if (m_blocks_modified.find(p) == m_blocks_modified.end()) {
401 if (m_blocks_sending.find(p) != m_blocks_sending.end())
402 m_blocks_sending.erase(p);
404 m_excess_gotblocks++;
406 m_blocks_sent.insert(p);
410 void RemoteClient::SentBlock(v3s16 p)
412 if (m_blocks_modified.find(p) != m_blocks_modified.end())
413 m_blocks_modified.erase(p);
415 if (m_blocks_sending.find(p) == m_blocks_sending.end())
416 m_blocks_sending[p] = 0.0f;
418 infostream<<"RemoteClient::SentBlock(): Sent block"
419 " already in m_blocks_sending"<<std::endl;
422 void RemoteClient::SetBlockNotSent(v3s16 p)
424 m_nearest_unsent_d = 0;
425 m_nothing_to_send_pause_timer = 0;
427 if (m_blocks_sending.find(p) != m_blocks_sending.end())
428 m_blocks_sending.erase(p);
429 if (m_blocks_sent.find(p) != m_blocks_sent.end())
430 m_blocks_sent.erase(p);
431 m_blocks_modified.insert(p);
434 void RemoteClient::SetBlocksNotSent(std::map<v3s16, MapBlock*> &blocks)
436 m_nearest_unsent_d = 0;
437 m_nothing_to_send_pause_timer = 0;
439 for (auto &block : blocks) {
440 v3s16 p = block.first;
441 m_blocks_modified.insert(p);
443 if (m_blocks_sending.find(p) != m_blocks_sending.end())
444 m_blocks_sending.erase(p);
445 if (m_blocks_sent.find(p) != m_blocks_sent.end())
446 m_blocks_sent.erase(p);
450 void RemoteClient::notifyEvent(ClientStateEvent event)
452 std::ostringstream myerror;
456 //intentionally do nothing
461 m_state = CS_HelloSent;
464 m_state = CS_AwaitingInit2;
467 m_state = CS_Disconnecting;
472 /* GotInit2 SetDefinitionsSent SetMediaSent */
474 myerror << "Created: Invalid client state transition! " << event;
475 throw ClientStateError(myerror.str());
479 /* don't do anything if in denied state */
485 m_state = CS_AwaitingInit2;
486 if (chosen_mech == AUTH_MECHANISM_SRP ||
487 chosen_mech == AUTH_MECHANISM_LEGACY_PASSWORD)
488 srp_verifier_delete((SRPVerifier *) auth_data);
489 chosen_mech = AUTH_MECHANISM_NONE;
492 m_state = CS_Disconnecting;
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 myerror << "HelloSent: Invalid client state transition! " << event;
503 throw ClientStateError(myerror.str());
506 case CS_AwaitingInit2:
510 confirmSerializationVersion();
511 m_state = CS_InitDone;
514 m_state = CS_Disconnecting;
520 /* Init SetDefinitionsSent SetMediaSent */
522 myerror << "InitSent: Invalid client state transition! " << event;
523 throw ClientStateError(myerror.str());
530 case CSE_SetDefinitionsSent:
531 m_state = CS_DefinitionsSent;
534 m_state = CS_Disconnecting;
540 /* Init GotInit2 SetMediaSent */
542 myerror << "InitDone: Invalid client state transition! " << event;
543 throw ClientStateError(myerror.str());
546 case CS_DefinitionsSent:
549 case CSE_SetClientReady:
553 m_state = CS_Disconnecting;
558 /* Init GotInit2 SetDefinitionsSent */
560 myerror << "DefinitionsSent: Invalid client state transition! " << event;
561 throw ClientStateError(myerror.str());
571 m_state = CS_Disconnecting;
573 case CSE_SudoSuccess:
574 m_state = CS_SudoMode;
575 if (chosen_mech == AUTH_MECHANISM_SRP)
576 srp_verifier_delete((SRPVerifier *) auth_data);
577 chosen_mech = AUTH_MECHANISM_NONE;
579 /* Init GotInit2 SetDefinitionsSent SetMediaSent SetDenied */
581 myerror << "Active: Invalid client state transition! " << event;
582 throw ClientStateError(myerror.str());
593 m_state = CS_Disconnecting;
599 myerror << "Active: Invalid client state transition! " << event;
600 throw ClientStateError(myerror.str());
604 case CS_Disconnecting:
605 /* we are already disconnecting */
610 u64 RemoteClient::uptime() const
612 return porting::getTimeS() - m_connection_time;
615 ClientInterface::ClientInterface(const std::shared_ptr<con::Connection> & con)
619 m_print_info_timer(0.0f)
623 ClientInterface::~ClientInterface()
629 MutexAutoLock clientslock(m_clients_mutex);
631 for (auto &client_it : m_clients) {
633 delete client_it.second;
638 std::vector<session_t> ClientInterface::getClientIDs(ClientState min_state)
640 std::vector<session_t> reply;
641 MutexAutoLock clientslock(m_clients_mutex);
643 for (const auto &m_client : m_clients) {
644 if (m_client.second->getState() >= min_state)
645 reply.push_back(m_client.second->peer_id);
651 void ClientInterface::markBlockposAsNotSent(const v3s16 &pos)
653 MutexAutoLock clientslock(m_clients_mutex);
654 for (const auto &client : m_clients) {
655 if (client.second->getState() >= CS_Active)
656 client.second->SetBlockNotSent(pos);
661 * Verify if user limit was reached.
662 * User limit count all clients from HelloSent state (MT protocol user) to Active state
663 * @return true if user limit was reached
665 bool ClientInterface::isUserLimitReached()
667 return getClientIDs(CS_HelloSent).size() >= g_settings->getU16("max_users");
670 void ClientInterface::step(float dtime)
672 m_print_info_timer += dtime;
673 if (m_print_info_timer >= 30.0f) {
674 m_print_info_timer = 0.0f;
679 void ClientInterface::UpdatePlayerList()
682 std::vector<session_t> clients = getClientIDs();
683 m_clients_names.clear();
686 if (!clients.empty())
687 infostream<<"Players:"<<std::endl;
689 for (session_t i : clients) {
690 RemotePlayer *player = m_env->getPlayer(i);
695 infostream << "* " << player->getName() << "\t";
698 MutexAutoLock clientslock(m_clients_mutex);
699 RemoteClient* client = lockedGetClientNoEx(i);
701 client->PrintInfo(infostream);
704 m_clients_names.emplace_back(player->getName());
709 void ClientInterface::send(session_t peer_id, u8 channelnum,
710 NetworkPacket *pkt, bool reliable)
712 m_con->Send(peer_id, channelnum, pkt, reliable);
715 void ClientInterface::sendToAll(NetworkPacket *pkt)
717 MutexAutoLock clientslock(m_clients_mutex);
718 for (auto &client_it : m_clients) {
719 RemoteClient *client = client_it.second;
721 if (client->net_proto_version != 0) {
722 m_con->Send(client->peer_id,
723 clientCommandFactoryTable[pkt->getCommand()].channel, pkt,
724 clientCommandFactoryTable[pkt->getCommand()].reliable);
729 void ClientInterface::sendToAllCompat(NetworkPacket *pkt, NetworkPacket *legacypkt,
732 MutexAutoLock clientslock(m_clients_mutex);
733 for (auto &client_it : m_clients) {
734 RemoteClient *client = client_it.second;
735 NetworkPacket *pkt_to_send = nullptr;
737 if (client->net_proto_version >= min_proto_ver) {
739 } else if (client->net_proto_version != 0) {
740 pkt_to_send = legacypkt;
742 warningstream << "Client with unhandled version to handle: '"
743 << client->net_proto_version << "'";
747 m_con->Send(client->peer_id,
748 clientCommandFactoryTable[pkt_to_send->getCommand()].channel,
750 clientCommandFactoryTable[pkt_to_send->getCommand()].reliable);
754 RemoteClient* ClientInterface::getClientNoEx(session_t peer_id, ClientState state_min)
756 MutexAutoLock clientslock(m_clients_mutex);
757 RemoteClientMap::const_iterator n = m_clients.find(peer_id);
758 // The client may not exist; clients are immediately removed if their
759 // access is denied, and this event occurs later then.
760 if (n == m_clients.end())
763 if (n->second->getState() >= state_min)
769 RemoteClient* ClientInterface::lockedGetClientNoEx(session_t peer_id, ClientState state_min)
771 RemoteClientMap::const_iterator n = m_clients.find(peer_id);
772 // The client may not exist; clients are immediately removed if their
773 // access is denied, and this event occurs later then.
774 if (n == m_clients.end())
777 if (n->second->getState() >= state_min)
783 ClientState ClientInterface::getClientState(session_t peer_id)
785 MutexAutoLock clientslock(m_clients_mutex);
786 RemoteClientMap::const_iterator n = m_clients.find(peer_id);
787 // The client may not exist; clients are immediately removed if their
788 // access is denied, and this event occurs later then.
789 if (n == m_clients.end())
792 return n->second->getState();
795 void ClientInterface::setPlayerName(session_t peer_id, const std::string &name)
797 MutexAutoLock clientslock(m_clients_mutex);
798 RemoteClientMap::iterator n = m_clients.find(peer_id);
799 // The client may not exist; clients are immediately removed if their
800 // access is denied, and this event occurs later then.
801 if (n != m_clients.end())
802 n->second->setName(name);
805 void ClientInterface::DeleteClient(session_t peer_id)
807 MutexAutoLock conlock(m_clients_mutex);
810 RemoteClientMap::iterator n = m_clients.find(peer_id);
811 // The client may not exist; clients are immediately removed if their
812 // access is denied, and this event occurs later then.
813 if (n == m_clients.end())
817 Mark objects to be not known by the client
819 //TODO this should be done by client destructor!!!
820 RemoteClient *client = n->second;
822 for (u16 id : client->m_known_objects) {
824 ServerActiveObject* obj = m_env->getActiveObject(id);
826 if(obj && obj->m_known_by_count > 0)
827 obj->m_known_by_count--;
831 delete m_clients[peer_id];
832 m_clients.erase(peer_id);
835 void ClientInterface::CreateClient(session_t peer_id)
837 MutexAutoLock conlock(m_clients_mutex);
840 RemoteClientMap::iterator n = m_clients.find(peer_id);
841 // The client shouldn't already exist
842 if (n != m_clients.end()) return;
845 RemoteClient *client = new RemoteClient();
846 client->peer_id = peer_id;
847 m_clients[client->peer_id] = client;
850 void ClientInterface::event(session_t peer_id, ClientStateEvent event)
853 MutexAutoLock clientlock(m_clients_mutex);
856 RemoteClientMap::iterator n = m_clients.find(peer_id);
858 // No client to deliver event
859 if (n == m_clients.end())
861 n->second->notifyEvent(event);
864 if ((event == CSE_SetClientReady) ||
865 (event == CSE_Disconnect) ||
866 (event == CSE_SetDenied))
872 u16 ClientInterface::getProtocolVersion(session_t peer_id)
874 MutexAutoLock conlock(m_clients_mutex);
877 RemoteClientMap::iterator n = m_clients.find(peer_id);
879 // No client to get version
880 if (n == m_clients.end())
883 return n->second->net_proto_version;
886 void ClientInterface::setClientVersion(session_t peer_id, u8 major, u8 minor, u8 patch,
887 const std::string &full)
889 MutexAutoLock conlock(m_clients_mutex);
892 RemoteClientMap::iterator n = m_clients.find(peer_id);
894 // No client to set versions
895 if (n == m_clients.end())
898 n->second->setVersionInfo(major, minor, patch, full);