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())
84 sao->getAttachment(&id, &bone, &dummy, &dummy, &force_visible);
85 ServerActiveObject *ao = env->getActiveObject(id);
87 ao->getAttachment(&id, &bone, &dummy, &dummy, &force_visible);
89 ao = env->getActiveObject(id);
91 return dynamic_cast<LuaEntitySAO *>(ao);
94 void RemoteClient::GetNextBlocks (
95 ServerEnvironment *env,
96 EmergeManager * emerge,
98 std::vector<PrioritySortedBlockTransfer> &dest)
101 m_nothing_to_send_pause_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 u16 max_simul_sends_usually = m_max_simul_sends;
144 Check the time from last addNode/removeNode.
146 Decrease send rate if player is building stuff.
148 m_time_from_building += dtime;
149 if (m_time_from_building < m_min_time_from_building) {
150 max_simul_sends_usually
151 = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
155 Number of blocks sending + number of blocks selected for sending
157 u32 num_blocks_selected = m_blocks_sending.size();
160 next time d will be continued from the d from which the nearest
161 unsent block was found this time.
163 This is because not necessarily any of the blocks found this
164 time are actually sent.
166 s32 new_nearest_unsent_d = -1;
168 // Get view range and camera fov (radians) from the client
169 s16 wanted_range = sao->getWantedRange() + 1;
170 float camera_fov = sao->getFov();
173 Get the starting value of the block finder radius.
175 if (m_last_center != center) {
176 m_nearest_unsent_d = 0;
177 m_last_center = center;
179 // reset the unsent distance if the view angle has changed more that 10% of the fov
180 // (this matches isBlockInSight which allows for an extra 10%)
181 if (camera_dir.dotProduct(m_last_camera_dir) < std::cos(camera_fov * 0.1f)) {
182 m_nearest_unsent_d = 0;
183 m_last_camera_dir = camera_dir;
185 if (m_nearest_unsent_d > 0) {
186 // make sure any blocks modified since the last time we sent blocks are resent
187 for (const v3s16 &p : m_blocks_modified) {
188 m_nearest_unsent_d = std::min(m_nearest_unsent_d, center.getDistanceFrom(p));
191 m_blocks_modified.clear();
193 s16 d_start = m_nearest_unsent_d;
195 // Distrust client-sent FOV and get server-set player object property
196 // zoom FOV (degrees) as a check to avoid hacked clients using FOV to load
198 // (zoom is disabled by value 0)
199 float prop_zoom_fov = sao->getZoomFOV() < 0.001f ?
201 std::max(camera_fov, sao->getZoomFOV() * core::DEGTORAD);
203 const s16 full_d_max = std::min(adjustDist(m_max_send_distance, prop_zoom_fov),
205 const s16 d_opt = std::min(adjustDist(m_block_optimize_distance, prop_zoom_fov),
207 const s16 d_blocks_in_sight = full_d_max * BS * MAP_BLOCKSIZE;
209 s16 d_max_gen = std::min(adjustDist(m_max_gen_distance, prop_zoom_fov),
212 s16 d_max = full_d_max;
214 // Don't loop very much at a time
215 s16 max_d_increment_at_time = 2;
216 if (d_max > d_start + max_d_increment_at_time)
217 d_max = d_start + max_d_increment_at_time;
219 // cos(angle between velocity and camera) * |velocity|
220 // Limit to 0.0f in case player moves backwards.
221 f32 dot = rangelim(camera_dir.dotProduct(playerspeed), 0.0f, 300.0f);
223 // Reduce the field of view when a player moves and looks forward.
224 // limit max fov effect to 50%, 60% at 20n/s fly speed
225 camera_fov = camera_fov / (1 + dot / 300.0f);
227 s32 nearest_emerged_d = -1;
228 s32 nearest_emergefull_d = -1;
229 s32 nearest_sent_d = -1;
230 //bool queue_is_full = false;
232 const v3s16 cam_pos_nodes = floatToInt(camera_pos, BS);
235 for (d = d_start; d <= d_max; d++) {
237 Get the border/face dot coordinates of a "d-radiused"
240 std::vector<v3s16> list = FacePositionCache::getFacePositions(d);
242 std::vector<v3s16>::iterator li;
243 for (li = list.begin(); li != list.end(); ++li) {
244 v3s16 p = *li + center;
248 - Don't allow too many simultaneous transfers
249 - EXCEPT when the blocks are very close
251 Also, don't send blocks that are already flying.
254 // Start with the usual maximum
255 u16 max_simul_dynamic = max_simul_sends_usually;
257 // If block is very close, allow full maximum
258 if (d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
259 max_simul_dynamic = m_max_simul_sends;
261 // Don't select too many blocks for sending
262 if (num_blocks_selected >= max_simul_dynamic) {
263 //queue_is_full = true;
264 goto queue_full_break;
267 // Don't send blocks that are currently being transferred
268 if (m_blocks_sending.find(p) != m_blocks_sending.end())
272 Do not go over max mapgen limit
274 if (blockpos_over_max_limit(p))
277 // If this is true, inexistent block will be made from scratch
278 bool generate = d <= d_max_gen;
281 Don't generate or send if not in sight
282 FIXME This only works if the client uses a small enough
283 FOV setting. The default of 72 degrees is fine.
284 Also retrieve a smaller view cone in the direction of the player's
286 (0.1 is about 4 degrees)
289 if (!(isBlockInSight(p, camera_pos, camera_dir, camera_fov,
290 d_blocks_in_sight, &dist) ||
291 (playerspeed.getLength() > 1.0f * BS &&
292 isBlockInSight(p, camera_pos, playerspeeddir, 0.1f,
293 d_blocks_in_sight)))) {
298 Check if map has this block
300 MapBlock *block = env->getMap().getBlockNoCreateNoEx(p);
302 // First: Reset usage timer, this block will be of use in the future.
303 block->resetUsageTimer();
307 Don't send already sent blocks
309 if (m_blocks_sent.find(p) != m_blocks_sent.end())
312 bool block_not_found = false;
314 // Check whether the block exists (with data)
315 if (!block->isGenerated())
316 block_not_found = true;
319 If block is not close, don't send it unless it is near
322 Block is near ground level if night-time mesh
323 differs from day-time mesh.
326 if (!block->getIsUnderground() && !block->getDayNightDiff())
330 if (m_occ_cull && !block_not_found &&
331 env->getMap().isBlockOccluded(block, cam_pos_nodes)) {
337 If block has been marked to not exist on disk (dummy) or is
338 not generated and generating new ones is not wanted, skip block.
340 if (!generate && block_not_found) {
346 Add inexistent block to emerge queue.
348 if (block == NULL || block_not_found) {
349 if (emerge->enqueueBlockEmerge(peer_id, p, generate)) {
350 if (nearest_emerged_d == -1)
351 nearest_emerged_d = d;
353 if (nearest_emergefull_d == -1)
354 nearest_emergefull_d = d;
355 goto queue_full_break;
362 if (nearest_sent_d == -1)
366 Add block to send queue
368 PrioritySortedBlockTransfer q((float)dist, p, peer_id);
372 num_blocks_selected += 1;
377 // If nothing was found for sending and nothing was queued for
378 // emerging, continue next time browsing from here
379 if (nearest_emerged_d != -1) {
380 new_nearest_unsent_d = nearest_emerged_d;
381 } else if (nearest_emergefull_d != -1) {
382 new_nearest_unsent_d = nearest_emergefull_d;
384 if (d > full_d_max) {
385 new_nearest_unsent_d = 0;
386 m_nothing_to_send_pause_timer = 2.0f;
388 if (nearest_sent_d != -1)
389 new_nearest_unsent_d = nearest_sent_d;
391 new_nearest_unsent_d = d;
395 if (new_nearest_unsent_d != -1)
396 m_nearest_unsent_d = new_nearest_unsent_d;
399 void RemoteClient::GotBlock(v3s16 p)
401 if (m_blocks_sending.find(p) != m_blocks_sending.end()) {
402 m_blocks_sending.erase(p);
403 // only add to sent blocks if it actually was sending
404 // (it might have been modified since)
405 m_blocks_sent.insert(p);
407 m_excess_gotblocks++;
411 void RemoteClient::SentBlock(v3s16 p)
413 if (m_blocks_sending.find(p) == m_blocks_sending.end())
414 m_blocks_sending[p] = 0.0f;
416 infostream<<"RemoteClient::SentBlock(): Sent block"
417 " already in m_blocks_sending"<<std::endl;
420 void RemoteClient::SetBlockNotSent(v3s16 p)
422 m_nothing_to_send_pause_timer = 0;
424 // remove the block from sending and sent sets,
425 // and mark as modified if found
426 if (m_blocks_sending.erase(p) + m_blocks_sent.erase(p) > 0)
427 m_blocks_modified.insert(p);
430 void RemoteClient::SetBlocksNotSent(std::map<v3s16, MapBlock*> &blocks)
432 m_nothing_to_send_pause_timer = 0;
434 for (auto &block : blocks) {
435 v3s16 p = block.first;
436 // remove the block from sending and sent sets,
437 // and mark as modified if found
438 if (m_blocks_sending.erase(p) + m_blocks_sent.erase(p) > 0)
439 m_blocks_modified.insert(p);
443 void RemoteClient::notifyEvent(ClientStateEvent event)
445 std::ostringstream myerror;
449 //intentionally do nothing
454 m_state = CS_HelloSent;
457 m_state = CS_Disconnecting;
462 /* GotInit2 SetDefinitionsSent SetMediaSent */
464 myerror << "Created: Invalid client state transition! " << event;
465 throw ClientStateError(myerror.str());
469 /* don't do anything if in denied state */
475 m_state = CS_AwaitingInit2;
479 m_state = CS_Disconnecting;
486 myerror << "HelloSent: Invalid client state transition! " << event;
487 throw ClientStateError(myerror.str());
490 case CS_AwaitingInit2:
494 confirmSerializationVersion();
495 m_state = CS_InitDone;
498 m_state = CS_Disconnecting;
504 /* Init SetDefinitionsSent SetMediaSent */
506 myerror << "InitSent: Invalid client state transition! " << event;
507 throw ClientStateError(myerror.str());
514 case CSE_SetDefinitionsSent:
515 m_state = CS_DefinitionsSent;
518 m_state = CS_Disconnecting;
524 /* Init GotInit2 SetMediaSent */
526 myerror << "InitDone: Invalid client state transition! " << event;
527 throw ClientStateError(myerror.str());
530 case CS_DefinitionsSent:
533 case CSE_SetClientReady:
537 m_state = CS_Disconnecting;
542 /* Init GotInit2 SetDefinitionsSent */
544 myerror << "DefinitionsSent: Invalid client state transition! " << event;
545 throw ClientStateError(myerror.str());
555 m_state = CS_Disconnecting;
557 case CSE_SudoSuccess:
558 m_state = CS_SudoMode;
561 /* Init GotInit2 SetDefinitionsSent SetMediaSent SetDenied */
563 myerror << "Active: Invalid client state transition! " << event;
564 throw ClientStateError(myerror.str());
575 m_state = CS_Disconnecting;
581 myerror << "Active: Invalid client state transition! " << event;
582 throw ClientStateError(myerror.str());
586 case CS_Disconnecting:
587 /* we are already disconnecting */
592 void RemoteClient::resetChosenMech()
595 srp_verifier_delete((SRPVerifier *) auth_data);
598 chosen_mech = AUTH_MECHANISM_NONE;
601 u64 RemoteClient::uptime() const
603 return porting::getTimeS() - m_connection_time;
606 ClientInterface::ClientInterface(const std::shared_ptr<con::Connection> & con)
610 m_print_info_timer(0.0f)
614 ClientInterface::~ClientInterface()
620 RecursiveMutexAutoLock clientslock(m_clients_mutex);
622 for (auto &client_it : m_clients) {
624 delete client_it.second;
629 std::vector<session_t> ClientInterface::getClientIDs(ClientState min_state)
631 std::vector<session_t> reply;
632 RecursiveMutexAutoLock clientslock(m_clients_mutex);
634 for (const auto &m_client : m_clients) {
635 if (m_client.second->getState() >= min_state)
636 reply.push_back(m_client.second->peer_id);
642 void ClientInterface::markBlockposAsNotSent(const v3s16 &pos)
644 RecursiveMutexAutoLock clientslock(m_clients_mutex);
645 for (const auto &client : m_clients) {
646 if (client.second->getState() >= CS_Active)
647 client.second->SetBlockNotSent(pos);
652 * Verify if user limit was reached.
653 * User limit count all clients from HelloSent state (MT protocol user) to Active state
654 * @return true if user limit was reached
656 bool ClientInterface::isUserLimitReached()
658 return getClientIDs(CS_HelloSent).size() >= g_settings->getU16("max_users");
661 void ClientInterface::step(float dtime)
663 m_print_info_timer += dtime;
664 if (m_print_info_timer >= 30.0f) {
665 m_print_info_timer = 0.0f;
670 void ClientInterface::UpdatePlayerList()
673 std::vector<session_t> clients = getClientIDs();
674 m_clients_names.clear();
676 if (!clients.empty())
677 infostream<<"Players:"<<std::endl;
679 for (session_t i : clients) {
680 RemotePlayer *player = m_env->getPlayer(i);
685 infostream << "* " << player->getName() << "\t";
688 RecursiveMutexAutoLock clientslock(m_clients_mutex);
689 RemoteClient* client = lockedGetClientNoEx(i);
691 client->PrintInfo(infostream);
694 m_clients_names.emplace_back(player->getName());
699 void ClientInterface::send(session_t peer_id, u8 channelnum,
700 NetworkPacket *pkt, bool reliable)
702 m_con->Send(peer_id, channelnum, pkt, reliable);
705 void ClientInterface::sendToAll(NetworkPacket *pkt)
707 RecursiveMutexAutoLock clientslock(m_clients_mutex);
708 for (auto &client_it : m_clients) {
709 RemoteClient *client = client_it.second;
711 if (client->net_proto_version != 0) {
712 m_con->Send(client->peer_id,
713 clientCommandFactoryTable[pkt->getCommand()].channel, pkt,
714 clientCommandFactoryTable[pkt->getCommand()].reliable);
719 RemoteClient* ClientInterface::getClientNoEx(session_t peer_id, ClientState state_min)
721 RecursiveMutexAutoLock clientslock(m_clients_mutex);
722 RemoteClientMap::const_iterator n = m_clients.find(peer_id);
723 // The client may not exist; clients are immediately removed if their
724 // access is denied, and this event occurs later then.
725 if (n == m_clients.end())
728 if (n->second->getState() >= state_min)
734 RemoteClient* ClientInterface::lockedGetClientNoEx(session_t peer_id, ClientState state_min)
736 RemoteClientMap::const_iterator n = m_clients.find(peer_id);
737 // The client may not exist; clients are immediately removed if their
738 // access is denied, and this event occurs later then.
739 if (n == m_clients.end())
742 if (n->second->getState() >= state_min)
748 ClientState ClientInterface::getClientState(session_t peer_id)
750 RecursiveMutexAutoLock clientslock(m_clients_mutex);
751 RemoteClientMap::const_iterator n = m_clients.find(peer_id);
752 // The client may not exist; clients are immediately removed if their
753 // access is denied, and this event occurs later then.
754 if (n == m_clients.end())
757 return n->second->getState();
760 void ClientInterface::setPlayerName(session_t peer_id, const std::string &name)
762 RecursiveMutexAutoLock clientslock(m_clients_mutex);
763 RemoteClientMap::iterator n = m_clients.find(peer_id);
764 // The client may not exist; clients are immediately removed if their
765 // access is denied, and this event occurs later then.
766 if (n != m_clients.end())
767 n->second->setName(name);
770 void ClientInterface::DeleteClient(session_t peer_id)
772 RecursiveMutexAutoLock conlock(m_clients_mutex);
775 RemoteClientMap::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())
782 Mark objects to be not known by the client
784 //TODO this should be done by client destructor!!!
785 RemoteClient *client = n->second;
787 for (u16 id : client->m_known_objects) {
789 ServerActiveObject* obj = m_env->getActiveObject(id);
791 if(obj && obj->m_known_by_count > 0)
792 obj->m_known_by_count--;
796 delete m_clients[peer_id];
797 m_clients.erase(peer_id);
800 void ClientInterface::CreateClient(session_t peer_id)
802 RecursiveMutexAutoLock conlock(m_clients_mutex);
805 RemoteClientMap::iterator n = m_clients.find(peer_id);
806 // The client shouldn't already exist
807 if (n != m_clients.end()) return;
810 RemoteClient *client = new RemoteClient();
811 client->peer_id = peer_id;
812 m_clients[client->peer_id] = client;
815 void ClientInterface::event(session_t peer_id, ClientStateEvent event)
818 RecursiveMutexAutoLock clientlock(m_clients_mutex);
821 RemoteClientMap::iterator n = m_clients.find(peer_id);
823 // No client to deliver event
824 if (n == m_clients.end())
826 n->second->notifyEvent(event);
829 if ((event == CSE_SetClientReady) ||
830 (event == CSE_Disconnect) ||
831 (event == CSE_SetDenied))
837 u16 ClientInterface::getProtocolVersion(session_t peer_id)
839 RecursiveMutexAutoLock conlock(m_clients_mutex);
842 RemoteClientMap::iterator n = m_clients.find(peer_id);
844 // No client to get version
845 if (n == m_clients.end())
848 return n->second->net_proto_version;
851 void ClientInterface::setClientVersion(session_t peer_id, u8 major, u8 minor, u8 patch,
852 const std::string &full)
854 RecursiveMutexAutoLock conlock(m_clients_mutex);
857 RemoteClientMap::iterator n = m_clients.find(peer_id);
859 // No client to set versions
860 if (n == m_clients.end())
863 n->second->setVersionInfo(major, minor, patch, full);