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.
22 #include "clientiface.h"
23 #include "remoteplayer.h"
26 #include "network/connection.h"
27 #include "serverenvironment.h"
30 #include "content_sao.h" // TODO this is used for cleanup of only
32 #include "network/serveropcodes.h"
34 #include "face_position_cache.h"
36 const char *ClientInterface::statenames[] = {
51 std::string ClientInterface::state2Name(ClientState state)
53 return statenames[state];
56 void RemoteClient::ResendBlockIfOnWire(v3s16 p)
58 // if this block is on wire, mark it for sending again as soon as possible
59 if (m_blocks_sending.find(p) != m_blocks_sending.end()) {
64 void RemoteClient::GetNextBlocks (
65 ServerEnvironment *env,
66 EmergeManager * emerge,
68 std::vector<PrioritySortedBlockTransfer> &dest)
70 DSTACK(FUNCTION_NAME);
74 m_nothing_to_send_pause_timer -= dtime;
75 m_nearest_unsent_reset_timer += dtime;
77 if(m_nothing_to_send_pause_timer >= 0)
80 RemotePlayer *player = env->getPlayer(peer_id);
81 // This can happen sometimes; clients and players are not in perfect sync.
85 PlayerSAO *sao = player->getPlayerSAO();
89 // Won't send anything if already sending
90 if(m_blocks_sending.size() >= g_settings->getU16
91 ("max_simultaneous_block_sends_per_client"))
93 //infostream<<"Not sending any blocks, Queue full."<<std::endl;
97 v3f playerpos = sao->getBasePosition();
98 v3f playerspeed = player->getSpeed();
99 v3f playerspeeddir(0,0,0);
100 if(playerspeed.getLength() > 1.0*BS)
101 playerspeeddir = playerspeed / playerspeed.getLength();
102 // Predict to next block
103 v3f playerpos_predicted = playerpos + playerspeeddir*MAP_BLOCKSIZE*BS;
105 v3s16 center_nodepos = floatToInt(playerpos_predicted, BS);
107 v3s16 center = getNodeBlockPos(center_nodepos);
109 // Camera position and direction
110 v3f camera_pos = sao->getEyePosition();
111 v3f camera_dir = v3f(0,0,1);
112 camera_dir.rotateYZBy(sao->getPitch());
113 camera_dir.rotateXZBy(sao->getYaw());
115 /*infostream<<"camera_dir=("<<camera_dir.X<<","<<camera_dir.Y<<","
116 <<camera_dir.Z<<")"<<std::endl;*/
119 Get the starting value of the block finder radius.
122 if(m_last_center != center)
124 m_nearest_unsent_d = 0;
125 m_last_center = center;
128 /*infostream<<"m_nearest_unsent_reset_timer="
129 <<m_nearest_unsent_reset_timer<<std::endl;*/
131 // Reset periodically to workaround for some bugs or stuff
132 if(m_nearest_unsent_reset_timer > 20.0)
134 m_nearest_unsent_reset_timer = 0;
135 m_nearest_unsent_d = 0;
136 //infostream<<"Resetting m_nearest_unsent_d for "
137 // <<server->getPlayerName(peer_id)<<std::endl;
140 //s16 last_nearest_unsent_d = m_nearest_unsent_d;
141 s16 d_start = m_nearest_unsent_d;
143 //infostream<<"d_start="<<d_start<<std::endl;
145 u16 max_simul_sends_setting = g_settings->getU16
146 ("max_simultaneous_block_sends_per_client");
147 u16 max_simul_sends_usually = max_simul_sends_setting;
150 Check the time from last addNode/removeNode.
152 Decrease send rate if player is building stuff.
154 m_time_from_building += dtime;
155 if(m_time_from_building < g_settings->getFloat(
156 "full_block_send_enable_min_time_from_building"))
158 max_simul_sends_usually
159 = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
163 Number of blocks sending + number of blocks selected for sending
165 u32 num_blocks_selected = m_blocks_sending.size();
168 next time d will be continued from the d from which the nearest
169 unsent block was found this time.
171 This is because not necessarily any of the blocks found this
172 time are actually sent.
174 s32 new_nearest_unsent_d = -1;
176 // get view range and camera fov from the client
177 s16 wanted_range = sao->getWantedRange();
178 float camera_fov = sao->getFov();
179 // if FOV, wanted_range are not available (old client), fall back to old default
180 if (wanted_range <= 0) wanted_range = 1000;
181 if (camera_fov <= 0) camera_fov = (72.0*M_PI/180) * 4./3.;
183 const s16 full_d_max = MYMIN(g_settings->getS16("max_block_send_distance"), wanted_range);
184 const s16 d_opt = MYMIN(g_settings->getS16("block_send_optimize_distance"), wanted_range);
185 const s16 d_blocks_in_sight = full_d_max * BS * MAP_BLOCKSIZE;
186 //infostream << "Fov from client " << camera_fov << " full_d_max " << full_d_max << std::endl;
188 s16 d_max = full_d_max;
189 s16 d_max_gen = MYMIN(g_settings->getS16("max_block_generate_distance"), wanted_range);
191 // Don't loop very much at a time
192 s16 max_d_increment_at_time = 2;
193 if(d_max > d_start + max_d_increment_at_time)
194 d_max = d_start + max_d_increment_at_time;
196 s32 nearest_emerged_d = -1;
197 s32 nearest_emergefull_d = -1;
198 s32 nearest_sent_d = -1;
199 //bool queue_is_full = false;
201 const v3s16 cam_pos_nodes = floatToInt(camera_pos, BS);
202 const bool occ_cull = g_settings->getBool("server_side_occlusion_culling");
205 for(d = d_start; d <= d_max; d++) {
207 Get the border/face dot coordinates of a "d-radiused"
210 std::vector<v3s16> list = FacePositionCache::getFacePositions(d);
212 std::vector<v3s16>::iterator li;
213 for(li = list.begin(); li != list.end(); ++li) {
214 v3s16 p = *li + center;
218 - Don't allow too many simultaneous transfers
219 - EXCEPT when the blocks are very close
221 Also, don't send blocks that are already flying.
224 // Start with the usual maximum
225 u16 max_simul_dynamic = max_simul_sends_usually;
227 // If block is very close, allow full maximum
228 if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
229 max_simul_dynamic = max_simul_sends_setting;
231 // Don't select too many blocks for sending
232 if (num_blocks_selected >= max_simul_dynamic) {
233 //queue_is_full = true;
234 goto queue_full_break;
237 // Don't send blocks that are currently being transferred
238 if (m_blocks_sending.find(p) != m_blocks_sending.end())
242 Do not go over max mapgen limit
244 if (blockpos_over_max_limit(p))
247 // If this is true, inexistent block will be made from scratch
248 bool generate = d <= d_max_gen;
251 Don't generate or send if not in sight
252 FIXME This only works if the client uses a small enough
253 FOV setting. The default of 72 degrees is fine.
257 if (!isBlockInSight(p, camera_pos, camera_dir, camera_fov, d_blocks_in_sight, &dist)) {
262 Don't send already sent blocks
265 if(m_blocks_sent.find(p) != m_blocks_sent.end())
272 Check if map has this block
274 MapBlock *block = env->getMap().getBlockNoCreateNoEx(p);
276 bool surely_not_found_on_disk = false;
277 bool block_is_invalid = false;
280 // Reset usage timer, this block will be of use in the future.
281 block->resetUsageTimer();
283 // Block is dummy if data doesn't exist.
284 // It means it has been not found from disk and not generated
287 surely_not_found_on_disk = true;
290 if(block->isGenerated() == false)
291 block_is_invalid = true;
294 If block is not close, don't send it unless it is near
297 Block is near ground level if night-time mesh
298 differs from day-time mesh.
302 if(block->getDayNightDiff() == false)
306 if (occ_cull && !block_is_invalid &&
307 env->getMap().isBlockOccluded(block, cam_pos_nodes)) {
313 If block has been marked to not exist on disk (dummy)
314 and generating new ones is not wanted, skip block.
316 if(generate == false && surely_not_found_on_disk == true)
323 Add inexistent block to emerge queue.
325 if(block == NULL || surely_not_found_on_disk || block_is_invalid)
327 if (emerge->enqueueBlockEmerge(peer_id, p, generate)) {
328 if (nearest_emerged_d == -1)
329 nearest_emerged_d = d;
331 if (nearest_emergefull_d == -1)
332 nearest_emergefull_d = d;
333 goto queue_full_break;
340 if(nearest_sent_d == -1)
344 Add block to send queue
346 PrioritySortedBlockTransfer q((float)dist, p, peer_id);
350 num_blocks_selected += 1;
355 // If nothing was found for sending and nothing was queued for
356 // emerging, continue next time browsing from here
357 if(nearest_emerged_d != -1){
358 new_nearest_unsent_d = nearest_emerged_d;
359 } else if(nearest_emergefull_d != -1){
360 new_nearest_unsent_d = nearest_emergefull_d;
363 new_nearest_unsent_d = 0;
364 m_nothing_to_send_pause_timer = 2.0;
366 if(nearest_sent_d != -1)
367 new_nearest_unsent_d = nearest_sent_d;
369 new_nearest_unsent_d = d;
373 if(new_nearest_unsent_d != -1)
374 m_nearest_unsent_d = new_nearest_unsent_d;
377 void RemoteClient::GotBlock(v3s16 p)
379 if (m_blocks_modified.find(p) == m_blocks_modified.end()) {
380 if (m_blocks_sending.find(p) != m_blocks_sending.end())
381 m_blocks_sending.erase(p);
383 m_excess_gotblocks++;
385 m_blocks_sent.insert(p);
389 void RemoteClient::SentBlock(v3s16 p)
391 if (m_blocks_modified.find(p) != m_blocks_modified.end())
392 m_blocks_modified.erase(p);
394 if(m_blocks_sending.find(p) == m_blocks_sending.end())
395 m_blocks_sending[p] = 0.0;
397 infostream<<"RemoteClient::SentBlock(): Sent block"
398 " already in m_blocks_sending"<<std::endl;
401 void RemoteClient::SetBlockNotSent(v3s16 p)
403 m_nearest_unsent_d = 0;
404 m_nothing_to_send_pause_timer = 0;
406 if(m_blocks_sending.find(p) != m_blocks_sending.end())
407 m_blocks_sending.erase(p);
408 if(m_blocks_sent.find(p) != m_blocks_sent.end())
409 m_blocks_sent.erase(p);
410 m_blocks_modified.insert(p);
413 void RemoteClient::SetBlocksNotSent(std::map<v3s16, MapBlock*> &blocks)
415 m_nearest_unsent_d = 0;
416 m_nothing_to_send_pause_timer = 0;
418 for(std::map<v3s16, MapBlock*>::iterator
420 i != blocks.end(); ++i)
423 m_blocks_modified.insert(p);
425 if(m_blocks_sending.find(p) != m_blocks_sending.end())
426 m_blocks_sending.erase(p);
427 if(m_blocks_sent.find(p) != m_blocks_sent.end())
428 m_blocks_sent.erase(p);
432 void RemoteClient::notifyEvent(ClientStateEvent event)
434 std::ostringstream myerror;
438 //intentionally do nothing
443 m_state = CS_HelloSent;
446 m_state = CS_AwaitingInit2;
449 m_state = CS_Disconnecting;
454 /* GotInit2 SetDefinitionsSent SetMediaSent */
456 myerror << "Created: Invalid client state transition! " << event;
457 throw ClientStateError(myerror.str());
461 /* don't do anything if in denied state */
467 m_state = CS_AwaitingInit2;
468 if ((chosen_mech == AUTH_MECHANISM_SRP)
469 || (chosen_mech == AUTH_MECHANISM_LEGACY_PASSWORD))
470 srp_verifier_delete((SRPVerifier *) auth_data);
471 chosen_mech = AUTH_MECHANISM_NONE;
474 m_state = CS_Disconnecting;
478 if ((chosen_mech == AUTH_MECHANISM_SRP)
479 || (chosen_mech == AUTH_MECHANISM_LEGACY_PASSWORD))
480 srp_verifier_delete((SRPVerifier *) auth_data);
481 chosen_mech = AUTH_MECHANISM_NONE;
484 myerror << "HelloSent: Invalid client state transition! " << event;
485 throw ClientStateError(myerror.str());
488 case CS_AwaitingInit2:
492 confirmSerializationVersion();
493 m_state = CS_InitDone;
496 m_state = CS_Disconnecting;
502 /* Init SetDefinitionsSent SetMediaSent */
504 myerror << "InitSent: Invalid client state transition! " << event;
505 throw ClientStateError(myerror.str());
512 case CSE_SetDefinitionsSent:
513 m_state = CS_DefinitionsSent;
516 m_state = CS_Disconnecting;
522 /* Init GotInit2 SetMediaSent */
524 myerror << "InitDone: Invalid client state transition! " << event;
525 throw ClientStateError(myerror.str());
528 case CS_DefinitionsSent:
531 case CSE_SetClientReady:
535 m_state = CS_Disconnecting;
540 /* Init GotInit2 SetDefinitionsSent */
542 myerror << "DefinitionsSent: Invalid client state transition! " << event;
543 throw ClientStateError(myerror.str());
553 m_state = CS_Disconnecting;
555 case CSE_SudoSuccess:
556 m_state = CS_SudoMode;
557 if ((chosen_mech == AUTH_MECHANISM_SRP)
558 || (chosen_mech == AUTH_MECHANISM_LEGACY_PASSWORD))
559 srp_verifier_delete((SRPVerifier *) auth_data);
560 chosen_mech = AUTH_MECHANISM_NONE;
562 /* Init GotInit2 SetDefinitionsSent SetMediaSent SetDenied */
564 myerror << "Active: Invalid client state transition! " << event;
565 throw ClientStateError(myerror.str());
576 m_state = CS_Disconnecting;
582 myerror << "Active: Invalid client state transition! " << event;
583 throw ClientStateError(myerror.str());
587 case CS_Disconnecting:
588 /* we are already disconnecting */
593 u32 RemoteClient::uptime()
595 return porting::getTime(PRECISION_SECONDS) - m_connection_time;
598 ClientInterface::ClientInterface(con::Connection* con)
602 m_print_info_timer(0.0)
606 ClientInterface::~ClientInterface()
612 MutexAutoLock clientslock(m_clients_mutex);
614 for (UNORDERED_MAP<u16, RemoteClient*>::iterator i = m_clients.begin();
615 i != m_clients.end(); ++i) {
622 std::vector<u16> ClientInterface::getClientIDs(ClientState min_state)
624 std::vector<u16> reply;
625 MutexAutoLock clientslock(m_clients_mutex);
627 for(UNORDERED_MAP<u16, RemoteClient*>::iterator i = m_clients.begin();
628 i != m_clients.end(); ++i) {
629 if (i->second->getState() >= min_state)
630 reply.push_back(i->second->peer_id);
636 void ClientInterface::step(float dtime)
638 m_print_info_timer += dtime;
639 if(m_print_info_timer >= 30.0)
641 m_print_info_timer = 0.0;
646 void ClientInterface::UpdatePlayerList()
649 std::vector<u16> clients = getClientIDs();
650 m_clients_names.clear();
654 infostream<<"Players:"<<std::endl;
656 for (std::vector<u16>::iterator i = clients.begin(); i != clients.end(); ++i) {
657 RemotePlayer *player = m_env->getPlayer(*i);
662 infostream << "* " << player->getName() << "\t";
665 MutexAutoLock clientslock(m_clients_mutex);
666 RemoteClient* client = lockedGetClientNoEx(*i);
668 client->PrintInfo(infostream);
671 m_clients_names.push_back(player->getName());
676 void ClientInterface::send(u16 peer_id, u8 channelnum,
677 NetworkPacket* pkt, bool reliable)
679 m_con->Send(peer_id, channelnum, pkt, reliable);
682 void ClientInterface::sendToAll(NetworkPacket *pkt)
684 MutexAutoLock clientslock(m_clients_mutex);
685 for (UNORDERED_MAP<u16, RemoteClient*>::iterator i = m_clients.begin();
686 i != m_clients.end(); ++i) {
687 RemoteClient *client = i->second;
689 if (client->net_proto_version != 0) {
690 m_con->Send(client->peer_id,
691 clientCommandFactoryTable[pkt->getCommand()].channel, pkt,
692 clientCommandFactoryTable[pkt->getCommand()].reliable);
697 RemoteClient* ClientInterface::getClientNoEx(u16 peer_id, ClientState state_min)
699 MutexAutoLock clientslock(m_clients_mutex);
700 UNORDERED_MAP<u16, RemoteClient*>::iterator n = m_clients.find(peer_id);
701 // The client may not exist; clients are immediately removed if their
702 // access is denied, and this event occurs later then.
703 if (n == m_clients.end())
706 if (n->second->getState() >= state_min)
712 RemoteClient* ClientInterface::lockedGetClientNoEx(u16 peer_id, ClientState state_min)
714 UNORDERED_MAP<u16, RemoteClient*>::iterator n = m_clients.find(peer_id);
715 // The client may not exist; clients are immediately removed if their
716 // access is denied, and this event occurs later then.
717 if (n == m_clients.end())
720 if (n->second->getState() >= state_min)
726 ClientState ClientInterface::getClientState(u16 peer_id)
728 MutexAutoLock clientslock(m_clients_mutex);
729 UNORDERED_MAP<u16, RemoteClient*>::iterator n = m_clients.find(peer_id);
730 // The client may not exist; clients are immediately removed if their
731 // access is denied, and this event occurs later then.
732 if (n == m_clients.end())
735 return n->second->getState();
738 void ClientInterface::setPlayerName(u16 peer_id,std::string name)
740 MutexAutoLock clientslock(m_clients_mutex);
741 UNORDERED_MAP<u16, RemoteClient*>::iterator n = m_clients.find(peer_id);
742 // The client may not exist; clients are immediately removed if their
743 // access is denied, and this event occurs later then.
744 if (n != m_clients.end())
745 n->second->setName(name);
748 void ClientInterface::DeleteClient(u16 peer_id)
750 MutexAutoLock conlock(m_clients_mutex);
753 UNORDERED_MAP<u16, RemoteClient*>::iterator n = m_clients.find(peer_id);
754 // The client may not exist; clients are immediately removed if their
755 // access is denied, and this event occurs later then.
756 if (n == m_clients.end())
760 Mark objects to be not known by the client
762 //TODO this should be done by client destructor!!!
763 RemoteClient *client = n->second;
765 for(std::set<u16>::iterator
766 i = client->m_known_objects.begin();
767 i != client->m_known_objects.end(); ++i)
771 ServerActiveObject* obj = m_env->getActiveObject(id);
773 if(obj && obj->m_known_by_count > 0)
774 obj->m_known_by_count--;
778 delete m_clients[peer_id];
779 m_clients.erase(peer_id);
782 void ClientInterface::CreateClient(u16 peer_id)
784 MutexAutoLock conlock(m_clients_mutex);
787 UNORDERED_MAP<u16, RemoteClient*>::iterator n = m_clients.find(peer_id);
788 // The client shouldn't already exist
789 if (n != m_clients.end()) return;
792 RemoteClient *client = new RemoteClient();
793 client->peer_id = peer_id;
794 m_clients[client->peer_id] = client;
797 void ClientInterface::event(u16 peer_id, ClientStateEvent event)
800 MutexAutoLock clientlock(m_clients_mutex);
803 UNORDERED_MAP<u16, RemoteClient*>::iterator n = m_clients.find(peer_id);
805 // No client to deliver event
806 if (n == m_clients.end())
808 n->second->notifyEvent(event);
811 if ((event == CSE_SetClientReady) ||
812 (event == CSE_Disconnect) ||
813 (event == CSE_SetDenied))
819 u16 ClientInterface::getProtocolVersion(u16 peer_id)
821 MutexAutoLock conlock(m_clients_mutex);
824 UNORDERED_MAP<u16, RemoteClient*>::iterator n = m_clients.find(peer_id);
826 // No client to get version
827 if (n == m_clients.end())
830 return n->second->net_proto_version;
833 void ClientInterface::setClientVersion(u16 peer_id, u8 major, u8 minor, u8 patch, std::string full)
835 MutexAutoLock conlock(m_clients_mutex);
838 UNORDERED_MAP<u16, RemoteClient*>::iterator n = m_clients.find(peer_id);
840 // No client to set versions
841 if (n == m_clients.end())
844 n->second->setVersionInfo(major,minor,patch,full);