LCOV - code coverage report
Current view: top level - src - clientiface.cpp (source / functions) Hit Total Coverage
Test: report Lines: 1 382 0.3 %
Date: 2015-07-11 18:23:49 Functions: 2 28 7.1 %

          Line data    Source code
       1             : /*
       2             : Minetest
       3             : Copyright (C) 2010-2014 celeron55, Perttu Ahola <celeron55@gmail.com>
       4             : 
       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.
       9             : 
      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.
      14             : 
      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.
      18             : */
      19             : 
      20             : #include <sstream>
      21             : 
      22             : #include "clientiface.h"
      23             : #include "util/numeric.h"
      24             : #include "util/mathconstants.h"
      25             : #include "player.h"
      26             : #include "settings.h"
      27             : #include "mapblock.h"
      28             : #include "network/connection.h"
      29             : #include "environment.h"
      30             : #include "map.h"
      31             : #include "emerge.h"
      32             : #include "serverobject.h"              // TODO this is used for cleanup of only
      33             : #include "log.h"
      34             : #include "util/srp.h"
      35             : 
      36             : const char *ClientInterface::statenames[] = {
      37             :         "Invalid",
      38             :         "Disconnecting",
      39             :         "Denied",
      40             :         "Created",
      41             :         "InitSent",
      42             :         "InitDone",
      43             :         "DefinitionsSent",
      44             :         "Active"
      45             : };
      46             : 
      47             : 
      48             : 
      49           0 : std::string ClientInterface::state2Name(ClientState state)
      50             : {
      51           0 :         return statenames[state];
      52             : }
      53             : 
      54           0 : void RemoteClient::ResendBlockIfOnWire(v3s16 p)
      55             : {
      56             :         // if this block is on wire, mark it for sending again as soon as possible
      57           0 :         if (m_blocks_sending.find(p) != m_blocks_sending.end()) {
      58           0 :                 SetBlockNotSent(p);
      59             :         }
      60           0 : }
      61             : 
      62           0 : void RemoteClient::GetNextBlocks (
      63             :                 ServerEnvironment *env,
      64             :                 EmergeManager * emerge,
      65             :                 float dtime,
      66             :                 std::vector<PrioritySortedBlockTransfer> &dest)
      67             : {
      68           0 :         DSTACK(__FUNCTION_NAME);
      69             : 
      70             : 
      71             :         // Increment timers
      72           0 :         m_nothing_to_send_pause_timer -= dtime;
      73           0 :         m_nearest_unsent_reset_timer += dtime;
      74             : 
      75           0 :         if(m_nothing_to_send_pause_timer >= 0)
      76           0 :                 return;
      77             : 
      78           0 :         Player *player = env->getPlayer(peer_id);
      79             :         // This can happen sometimes; clients and players are not in perfect sync.
      80           0 :         if(player == NULL)
      81           0 :                 return;
      82             : 
      83             :         // Won't send anything if already sending
      84           0 :         if(m_blocks_sending.size() >= g_settings->getU16
      85           0 :                         ("max_simultaneous_block_sends_per_client"))
      86             :         {
      87             :                 //infostream<<"Not sending any blocks, Queue full."<<std::endl;
      88           0 :                 return;
      89             :         }
      90             : 
      91           0 :         v3f playerpos = player->getPosition();
      92           0 :         v3f playerspeed = player->getSpeed();
      93           0 :         v3f playerspeeddir(0,0,0);
      94           0 :         if(playerspeed.getLength() > 1.0*BS)
      95           0 :                 playerspeeddir = playerspeed / playerspeed.getLength();
      96             :         // Predict to next block
      97           0 :         v3f playerpos_predicted = playerpos + playerspeeddir*MAP_BLOCKSIZE*BS;
      98             : 
      99           0 :         v3s16 center_nodepos = floatToInt(playerpos_predicted, BS);
     100             : 
     101           0 :         v3s16 center = getNodeBlockPos(center_nodepos);
     102             : 
     103             :         // Camera position and direction
     104           0 :         v3f camera_pos = player->getEyePosition();
     105           0 :         v3f camera_dir = v3f(0,0,1);
     106           0 :         camera_dir.rotateYZBy(player->getPitch());
     107           0 :         camera_dir.rotateXZBy(player->getYaw());
     108             : 
     109             :         /*infostream<<"camera_dir=("<<camera_dir.X<<","<<camera_dir.Y<<","
     110             :                         <<camera_dir.Z<<")"<<std::endl;*/
     111             : 
     112             :         /*
     113             :                 Get the starting value of the block finder radius.
     114             :         */
     115             : 
     116           0 :         if(m_last_center != center)
     117             :         {
     118           0 :                 m_nearest_unsent_d = 0;
     119           0 :                 m_last_center = center;
     120             :         }
     121             : 
     122             :         /*infostream<<"m_nearest_unsent_reset_timer="
     123             :                         <<m_nearest_unsent_reset_timer<<std::endl;*/
     124             : 
     125             :         // Reset periodically to workaround for some bugs or stuff
     126           0 :         if(m_nearest_unsent_reset_timer > 20.0)
     127             :         {
     128           0 :                 m_nearest_unsent_reset_timer = 0;
     129           0 :                 m_nearest_unsent_d = 0;
     130             :                 //infostream<<"Resetting m_nearest_unsent_d for "
     131             :                 //              <<server->getPlayerName(peer_id)<<std::endl;
     132             :         }
     133             : 
     134             :         //s16 last_nearest_unsent_d = m_nearest_unsent_d;
     135           0 :         s16 d_start = m_nearest_unsent_d;
     136             : 
     137             :         //infostream<<"d_start="<<d_start<<std::endl;
     138             : 
     139             :         u16 max_simul_sends_setting = g_settings->getU16
     140           0 :                         ("max_simultaneous_block_sends_per_client");
     141           0 :         u16 max_simul_sends_usually = max_simul_sends_setting;
     142             : 
     143             :         /*
     144             :                 Check the time from last addNode/removeNode.
     145             : 
     146             :                 Decrease send rate if player is building stuff.
     147             :         */
     148           0 :         m_time_from_building += dtime;
     149           0 :         if(m_time_from_building < g_settings->getFloat(
     150             :                                 "full_block_send_enable_min_time_from_building"))
     151             :         {
     152             :                 max_simul_sends_usually
     153           0 :                         = LIMITED_MAX_SIMULTANEOUS_BLOCK_SENDS;
     154             :         }
     155             : 
     156             :         /*
     157             :                 Number of blocks sending + number of blocks selected for sending
     158             :         */
     159           0 :         u32 num_blocks_selected = m_blocks_sending.size();
     160             : 
     161             :         /*
     162             :                 next time d will be continued from the d from which the nearest
     163             :                 unsent block was found this time.
     164             : 
     165             :                 This is because not necessarily any of the blocks found this
     166             :                 time are actually sent.
     167             :         */
     168           0 :         s32 new_nearest_unsent_d = -1;
     169             : 
     170           0 :         const s16 full_d_max = g_settings->getS16("max_block_send_distance");
     171           0 :         s16 d_max = full_d_max;
     172           0 :         s16 d_max_gen = g_settings->getS16("max_block_generate_distance");
     173             : 
     174             :         // Don't loop very much at a time
     175           0 :         s16 max_d_increment_at_time = 2;
     176           0 :         if(d_max > d_start + max_d_increment_at_time)
     177           0 :                 d_max = d_start + max_d_increment_at_time;
     178             : 
     179           0 :         s32 nearest_emerged_d = -1;
     180           0 :         s32 nearest_emergefull_d = -1;
     181           0 :         s32 nearest_sent_d = -1;
     182             :         //bool queue_is_full = false;
     183             : 
     184             :         s16 d;
     185           0 :         for(d = d_start; d <= d_max; d++) {
     186             :                 /*
     187             :                         Get the border/face dot coordinates of a "d-radiused"
     188             :                         box
     189             :                 */
     190           0 :                 std::vector<v3s16> list = FacePositionCache::getFacePositions(d);
     191             : 
     192           0 :                 std::vector<v3s16>::iterator li;
     193           0 :                 for(li = list.begin(); li != list.end(); ++li) {
     194           0 :                         v3s16 p = *li + center;
     195             : 
     196             :                         /*
     197             :                                 Send throttling
     198             :                                 - Don't allow too many simultaneous transfers
     199             :                                 - EXCEPT when the blocks are very close
     200             : 
     201             :                                 Also, don't send blocks that are already flying.
     202             :                         */
     203             : 
     204             :                         // Start with the usual maximum
     205           0 :                         u16 max_simul_dynamic = max_simul_sends_usually;
     206             : 
     207             :                         // If block is very close, allow full maximum
     208           0 :                         if(d <= BLOCK_SEND_DISABLE_LIMITS_MAX_D)
     209           0 :                                 max_simul_dynamic = max_simul_sends_setting;
     210             : 
     211             :                         // Don't select too many blocks for sending
     212           0 :                         if(num_blocks_selected >= max_simul_dynamic)
     213             :                         {
     214             :                                 //queue_is_full = true;
     215           0 :                                 goto queue_full_break;
     216             :                         }
     217             : 
     218             :                         // Don't send blocks that are currently being transferred
     219           0 :                         if(m_blocks_sending.find(p) != m_blocks_sending.end())
     220           0 :                                 continue;
     221             : 
     222             :                         /*
     223             :                                 Do not go over-limit
     224             :                         */
     225           0 :                         if(p.X < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
     226           0 :                         || p.X > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
     227           0 :                         || p.Y < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
     228           0 :                         || p.Y > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
     229           0 :                         || p.Z < -MAP_GENERATION_LIMIT / MAP_BLOCKSIZE
     230           0 :                         || p.Z > MAP_GENERATION_LIMIT / MAP_BLOCKSIZE)
     231           0 :                                 continue;
     232             : 
     233             :                         // If this is true, inexistent block will be made from scratch
     234           0 :                         bool generate = d <= d_max_gen;
     235             : 
     236             :                         {
     237             :                                 /*// Limit the generating area vertically to 2/3
     238             :                                 if(abs(p.Y - center.Y) > d_max_gen - d_max_gen / 3)
     239             :                                         generate = false;*/
     240             : 
     241             :                                 // Limit the send area vertically to 1/2
     242           0 :                                 if(abs(p.Y - center.Y) > full_d_max / 2)
     243           0 :                                         continue;
     244             :                         }
     245             : 
     246             :                         /*
     247             :                                 Don't generate or send if not in sight
     248             :                                 FIXME This only works if the client uses a small enough
     249             :                                 FOV setting. The default of 72 degrees is fine.
     250             :                         */
     251             : 
     252           0 :                         float camera_fov = (72.0*M_PI/180) * 4./3.;
     253           0 :                         if(isBlockInSight(p, camera_pos, camera_dir, camera_fov, 10000*BS) == false)
     254             :                         {
     255           0 :                                 continue;
     256             :                         }
     257             : 
     258             :                         /*
     259             :                                 Don't send already sent blocks
     260             :                         */
     261             :                         {
     262           0 :                                 if(m_blocks_sent.find(p) != m_blocks_sent.end())
     263             :                                 {
     264           0 :                                         continue;
     265             :                                 }
     266             :                         }
     267             : 
     268             :                         /*
     269             :                                 Check if map has this block
     270             :                         */
     271           0 :                         MapBlock *block = env->getMap().getBlockNoCreateNoEx(p);
     272             : 
     273           0 :                         bool surely_not_found_on_disk = false;
     274           0 :                         bool block_is_invalid = false;
     275           0 :                         if(block != NULL)
     276             :                         {
     277             :                                 // Reset usage timer, this block will be of use in the future.
     278           0 :                                 block->resetUsageTimer();
     279             : 
     280             :                                 // Block is dummy if data doesn't exist.
     281             :                                 // It means it has been not found from disk and not generated
     282           0 :                                 if(block->isDummy())
     283             :                                 {
     284           0 :                                         surely_not_found_on_disk = true;
     285             :                                 }
     286             : 
     287             :                                 // Block is valid if lighting is up-to-date and data exists
     288           0 :                                 if(block->isValid() == false)
     289             :                                 {
     290           0 :                                         block_is_invalid = true;
     291             :                                 }
     292             : 
     293           0 :                                 if(block->isGenerated() == false)
     294           0 :                                         block_is_invalid = true;
     295             : 
     296             :                                 /*
     297             :                                         If block is not close, don't send it unless it is near
     298             :                                         ground level.
     299             : 
     300             :                                         Block is near ground level if night-time mesh
     301             :                                         differs from day-time mesh.
     302             :                                 */
     303           0 :                                 if(d >= 4)
     304             :                                 {
     305           0 :                                         if(block->getDayNightDiff() == false)
     306           0 :                                                 continue;
     307             :                                 }
     308             :                         }
     309             : 
     310             :                         /*
     311             :                                 If block has been marked to not exist on disk (dummy)
     312             :                                 and generating new ones is not wanted, skip block.
     313             :                         */
     314           0 :                         if(generate == false && surely_not_found_on_disk == true)
     315             :                         {
     316             :                                 // get next one.
     317           0 :                                 continue;
     318             :                         }
     319             : 
     320             :                         /*
     321             :                                 Add inexistent block to emerge queue.
     322             :                         */
     323           0 :                         if(block == NULL || surely_not_found_on_disk || block_is_invalid)
     324             :                         {
     325           0 :                                 if (emerge->enqueueBlockEmerge(peer_id, p, generate)) {
     326           0 :                                         if (nearest_emerged_d == -1)
     327           0 :                                                 nearest_emerged_d = d;
     328             :                                 } else {
     329           0 :                                         if (nearest_emergefull_d == -1)
     330           0 :                                                 nearest_emergefull_d = d;
     331           0 :                                         goto queue_full_break;
     332             :                                 }
     333             : 
     334             :                                 // get next one.
     335           0 :                                 continue;
     336             :                         }
     337             : 
     338           0 :                         if(nearest_sent_d == -1)
     339           0 :                                 nearest_sent_d = d;
     340             : 
     341             :                         /*
     342             :                                 Add block to send queue
     343             :                         */
     344           0 :                         PrioritySortedBlockTransfer q((float)d, p, peer_id);
     345             : 
     346           0 :                         dest.push_back(q);
     347             : 
     348           0 :                         num_blocks_selected += 1;
     349             :                 }
     350             :         }
     351             : queue_full_break:
     352             : 
     353             :         // If nothing was found for sending and nothing was queued for
     354             :         // emerging, continue next time browsing from here
     355           0 :         if(nearest_emerged_d != -1){
     356           0 :                 new_nearest_unsent_d = nearest_emerged_d;
     357           0 :         } else if(nearest_emergefull_d != -1){
     358           0 :                 new_nearest_unsent_d = nearest_emergefull_d;
     359             :         } else {
     360           0 :                 if(d > g_settings->getS16("max_block_send_distance")){
     361           0 :                         new_nearest_unsent_d = 0;
     362           0 :                         m_nothing_to_send_pause_timer = 2.0;
     363             :                 } else {
     364           0 :                         if(nearest_sent_d != -1)
     365           0 :                                 new_nearest_unsent_d = nearest_sent_d;
     366             :                         else
     367           0 :                                 new_nearest_unsent_d = d;
     368             :                 }
     369             :         }
     370             : 
     371           0 :         if(new_nearest_unsent_d != -1)
     372           0 :                 m_nearest_unsent_d = new_nearest_unsent_d;
     373             : }
     374             : 
     375           0 : void RemoteClient::GotBlock(v3s16 p)
     376             : {
     377           0 :         if(m_blocks_sending.find(p) != m_blocks_sending.end())
     378           0 :                 m_blocks_sending.erase(p);
     379             :         else
     380             :         {
     381           0 :                 m_excess_gotblocks++;
     382             :         }
     383           0 :         m_blocks_sent.insert(p);
     384           0 : }
     385             : 
     386           0 : void RemoteClient::SentBlock(v3s16 p)
     387             : {
     388           0 :         if(m_blocks_sending.find(p) == m_blocks_sending.end())
     389           0 :                 m_blocks_sending[p] = 0.0;
     390             :         else
     391             :                 infostream<<"RemoteClient::SentBlock(): Sent block"
     392           0 :                                 " already in m_blocks_sending"<<std::endl;
     393           0 : }
     394             : 
     395           0 : void RemoteClient::SetBlockNotSent(v3s16 p)
     396             : {
     397           0 :         m_nearest_unsent_d = 0;
     398             : 
     399           0 :         if(m_blocks_sending.find(p) != m_blocks_sending.end())
     400           0 :                 m_blocks_sending.erase(p);
     401           0 :         if(m_blocks_sent.find(p) != m_blocks_sent.end())
     402           0 :                 m_blocks_sent.erase(p);
     403           0 : }
     404             : 
     405           0 : void RemoteClient::SetBlocksNotSent(std::map<v3s16, MapBlock*> &blocks)
     406             : {
     407           0 :         m_nearest_unsent_d = 0;
     408             : 
     409           0 :         for(std::map<v3s16, MapBlock*>::iterator
     410           0 :                         i = blocks.begin();
     411           0 :                         i != blocks.end(); ++i)
     412             :         {
     413           0 :                 v3s16 p = i->first;
     414             : 
     415           0 :                 if(m_blocks_sending.find(p) != m_blocks_sending.end())
     416           0 :                         m_blocks_sending.erase(p);
     417           0 :                 if(m_blocks_sent.find(p) != m_blocks_sent.end())
     418           0 :                         m_blocks_sent.erase(p);
     419             :         }
     420           0 : }
     421             : 
     422           0 : void RemoteClient::notifyEvent(ClientStateEvent event)
     423             : {
     424           0 :         std::ostringstream myerror;
     425           0 :         switch (m_state)
     426             :         {
     427             :         case CS_Invalid:
     428             :                 //intentionally do nothing
     429           0 :                 break;
     430             :         case CS_Created:
     431           0 :                 switch (event) {
     432             :                 case CSE_Hello:
     433           0 :                         m_state = CS_HelloSent;
     434           0 :                         break;
     435             :                 case CSE_InitLegacy:
     436           0 :                         m_state = CS_AwaitingInit2;
     437           0 :                         break;
     438             :                 case CSE_Disconnect:
     439           0 :                         m_state = CS_Disconnecting;
     440           0 :                         break;
     441             :                 case CSE_SetDenied:
     442           0 :                         m_state = CS_Denied;
     443           0 :                         break;
     444             :                 /* GotInit2 SetDefinitionsSent SetMediaSent */
     445             :                 default:
     446           0 :                         myerror << "Created: Invalid client state transition! " << event;
     447           0 :                         throw ClientStateError(myerror.str());
     448             :                 }
     449           0 :                 break;
     450             :         case CS_Denied:
     451             :                 /* don't do anything if in denied state */
     452           0 :                 break;
     453             :         case CS_HelloSent:
     454           0 :                 switch(event)
     455             :                 {
     456             :                 case CSE_AuthAccept:
     457           0 :                         m_state = CS_AwaitingInit2;
     458           0 :                         if ((chosen_mech == AUTH_MECHANISM_SRP)
     459           0 :                                         || (chosen_mech == AUTH_MECHANISM_LEGACY_PASSWORD))
     460           0 :                                 srp_verifier_delete((SRPVerifier *) auth_data);
     461           0 :                         chosen_mech = AUTH_MECHANISM_NONE;
     462           0 :                         break;
     463             :                 case CSE_Disconnect:
     464           0 :                         m_state = CS_Disconnecting;
     465           0 :                         break;
     466             :                 case CSE_SetDenied:
     467           0 :                         m_state = CS_Denied;
     468           0 :                         if ((chosen_mech == AUTH_MECHANISM_SRP)
     469           0 :                                         || (chosen_mech == AUTH_MECHANISM_LEGACY_PASSWORD))
     470           0 :                                 srp_verifier_delete((SRPVerifier *) auth_data);
     471           0 :                         chosen_mech = AUTH_MECHANISM_NONE;
     472           0 :                         break;
     473             :                 default:
     474           0 :                         myerror << "HelloSent: Invalid client state transition! " << event;
     475           0 :                         throw ClientStateError(myerror.str());
     476             :                 }
     477           0 :                 break;
     478             :         case CS_AwaitingInit2:
     479           0 :                 switch(event)
     480             :                 {
     481             :                 case CSE_GotInit2:
     482           0 :                         confirmSerializationVersion();
     483           0 :                         m_state = CS_InitDone;
     484           0 :                         break;
     485             :                 case CSE_Disconnect:
     486           0 :                         m_state = CS_Disconnecting;
     487           0 :                         break;
     488             :                 case CSE_SetDenied:
     489           0 :                         m_state = CS_Denied;
     490           0 :                         break;
     491             : 
     492             :                 /* Init SetDefinitionsSent SetMediaSent */
     493             :                 default:
     494           0 :                         myerror << "InitSent: Invalid client state transition! " << event;
     495           0 :                         throw ClientStateError(myerror.str());
     496             :                 }
     497           0 :                 break;
     498             : 
     499             :         case CS_InitDone:
     500           0 :                 switch(event)
     501             :                 {
     502             :                 case CSE_SetDefinitionsSent:
     503           0 :                         m_state = CS_DefinitionsSent;
     504           0 :                         break;
     505             :                 case CSE_Disconnect:
     506           0 :                         m_state = CS_Disconnecting;
     507           0 :                         break;
     508             :                 case CSE_SetDenied:
     509           0 :                         m_state = CS_Denied;
     510           0 :                         break;
     511             : 
     512             :                 /* Init GotInit2 SetMediaSent */
     513             :                 default:
     514           0 :                         myerror << "InitDone: Invalid client state transition! " << event;
     515           0 :                         throw ClientStateError(myerror.str());
     516             :                 }
     517           0 :                 break;
     518             :         case CS_DefinitionsSent:
     519           0 :                 switch(event)
     520             :                 {
     521             :                 case CSE_SetClientReady:
     522           0 :                         m_state = CS_Active;
     523           0 :                         break;
     524             :                 case CSE_Disconnect:
     525           0 :                         m_state = CS_Disconnecting;
     526           0 :                         break;
     527             :                 case CSE_SetDenied:
     528           0 :                         m_state = CS_Denied;
     529           0 :                         break;
     530             :                 /* Init GotInit2 SetDefinitionsSent */
     531             :                 default:
     532           0 :                         myerror << "DefinitionsSent: Invalid client state transition! " << event;
     533           0 :                         throw ClientStateError(myerror.str());
     534             :                 }
     535           0 :                 break;
     536             :         case CS_Active:
     537           0 :                 switch(event)
     538             :                 {
     539             :                 case CSE_SetDenied:
     540           0 :                         m_state = CS_Denied;
     541           0 :                         break;
     542             :                 case CSE_Disconnect:
     543           0 :                         m_state = CS_Disconnecting;
     544           0 :                         break;
     545             :                 case CSE_SudoSuccess:
     546           0 :                         m_state = CS_SudoMode;
     547           0 :                         if ((chosen_mech == AUTH_MECHANISM_SRP)
     548           0 :                                         || (chosen_mech == AUTH_MECHANISM_LEGACY_PASSWORD))
     549           0 :                                 srp_verifier_delete((SRPVerifier *) auth_data);
     550           0 :                         chosen_mech = AUTH_MECHANISM_NONE;
     551           0 :                         break;
     552             :                 /* Init GotInit2 SetDefinitionsSent SetMediaSent SetDenied */
     553             :                 default:
     554           0 :                         myerror << "Active: Invalid client state transition! " << event;
     555           0 :                         throw ClientStateError(myerror.str());
     556             :                         break;
     557             :                 }
     558           0 :                 break;
     559             :         case CS_SudoMode:
     560           0 :                 switch(event)
     561             :                 {
     562             :                 case CSE_SetDenied:
     563           0 :                         m_state = CS_Denied;
     564           0 :                         break;
     565             :                 case CSE_Disconnect:
     566           0 :                         m_state = CS_Disconnecting;
     567           0 :                         break;
     568             :                 case CSE_SudoLeave:
     569           0 :                         m_state = CS_Active;
     570           0 :                         break;
     571             :                 default:
     572           0 :                         myerror << "Active: Invalid client state transition! " << event;
     573           0 :                         throw ClientStateError(myerror.str());
     574             :                         break;
     575             :                 }
     576           0 :                 break;
     577             :         case CS_Disconnecting:
     578             :                 /* we are already disconnecting */
     579           0 :                 break;
     580             :         }
     581           0 : }
     582             : 
     583           0 : u32 RemoteClient::uptime()
     584             : {
     585           0 :         return getTime(PRECISION_SECONDS) - m_connection_time;
     586             : }
     587             : 
     588           0 : ClientInterface::ClientInterface(con::Connection* con)
     589             : :
     590             :         m_con(con),
     591             :         m_env(NULL),
     592           0 :         m_print_info_timer(0.0)
     593             : {
     594             : 
     595           0 : }
     596           0 : ClientInterface::~ClientInterface()
     597             : {
     598             :         /*
     599             :                 Delete clients
     600             :         */
     601             :         {
     602           0 :                 JMutexAutoLock clientslock(m_clients_mutex);
     603             : 
     604           0 :                 for(std::map<u16, RemoteClient*>::iterator
     605           0 :                         i = m_clients.begin();
     606           0 :                         i != m_clients.end(); ++i)
     607             :                 {
     608             : 
     609             :                         // Delete client
     610           0 :                         delete i->second;
     611             :                 }
     612             :         }
     613           0 : }
     614             : 
     615           0 : std::vector<u16> ClientInterface::getClientIDs(ClientState min_state)
     616             : {
     617           0 :         std::vector<u16> reply;
     618           0 :         JMutexAutoLock clientslock(m_clients_mutex);
     619             : 
     620           0 :         for(std::map<u16, RemoteClient*>::iterator
     621           0 :                 i = m_clients.begin();
     622           0 :                 i != m_clients.end(); ++i)
     623             :         {
     624           0 :                 if (i->second->getState() >= min_state)
     625           0 :                         reply.push_back(i->second->peer_id);
     626             :         }
     627             : 
     628           0 :         return reply;
     629             : }
     630             : 
     631           0 : std::vector<std::string> ClientInterface::getPlayerNames()
     632             : {
     633           0 :         return m_clients_names;
     634             : }
     635             : 
     636             : 
     637           0 : void ClientInterface::step(float dtime)
     638             : {
     639           0 :         m_print_info_timer += dtime;
     640           0 :         if(m_print_info_timer >= 30.0)
     641             :         {
     642           0 :                 m_print_info_timer = 0.0;
     643           0 :                 UpdatePlayerList();
     644             :         }
     645           0 : }
     646             : 
     647           0 : void ClientInterface::UpdatePlayerList()
     648             : {
     649           0 :         if (m_env != NULL)
     650             :                 {
     651           0 :                 std::vector<u16> clients = getClientIDs();
     652           0 :                 m_clients_names.clear();
     653             : 
     654             : 
     655           0 :                 if(!clients.empty())
     656           0 :                         infostream<<"Players:"<<std::endl;
     657             : 
     658           0 :                 for(std::vector<u16>::iterator
     659           0 :                         i = clients.begin();
     660           0 :                         i != clients.end(); ++i) {
     661           0 :                         Player *player = m_env->getPlayer(*i);
     662             : 
     663           0 :                         if (player == NULL)
     664           0 :                                 continue;
     665             : 
     666           0 :                         infostream << "* " << player->getName() << "\t";
     667             : 
     668             :                         {
     669           0 :                                 JMutexAutoLock clientslock(m_clients_mutex);
     670           0 :                                 RemoteClient* client = lockedGetClientNoEx(*i);
     671           0 :                                 if(client != NULL)
     672           0 :                                         client->PrintInfo(infostream);
     673             :                         }
     674             : 
     675           0 :                         m_clients_names.push_back(player->getName());
     676             :                 }
     677             :         }
     678           0 : }
     679             : 
     680           0 : void ClientInterface::send(u16 peer_id, u8 channelnum,
     681             :                 NetworkPacket* pkt, bool reliable)
     682             : {
     683           0 :         m_con->Send(peer_id, channelnum, pkt, reliable);
     684           0 : }
     685             : 
     686           0 : void ClientInterface::sendToAll(u16 channelnum,
     687             :                 NetworkPacket* pkt, bool reliable)
     688             : {
     689           0 :         JMutexAutoLock clientslock(m_clients_mutex);
     690           0 :         for(std::map<u16, RemoteClient*>::iterator
     691           0 :                 i = m_clients.begin();
     692           0 :                 i != m_clients.end(); ++i) {
     693           0 :                 RemoteClient *client = i->second;
     694             : 
     695           0 :                 if (client->net_proto_version != 0) {
     696           0 :                         m_con->Send(client->peer_id, channelnum, pkt, reliable);
     697             :                 }
     698             :         }
     699           0 : }
     700             : 
     701           0 : RemoteClient* ClientInterface::getClientNoEx(u16 peer_id, ClientState state_min)
     702             : {
     703           0 :         JMutexAutoLock clientslock(m_clients_mutex);
     704           0 :         std::map<u16, RemoteClient*>::iterator n;
     705           0 :         n = m_clients.find(peer_id);
     706             :         // The client may not exist; clients are immediately removed if their
     707             :         // access is denied, and this event occurs later then.
     708           0 :         if(n == m_clients.end())
     709           0 :                 return NULL;
     710             : 
     711           0 :         if (n->second->getState() >= state_min)
     712           0 :                 return n->second;
     713             :         else
     714           0 :                 return NULL;
     715             : }
     716             : 
     717           0 : RemoteClient* ClientInterface::lockedGetClientNoEx(u16 peer_id, ClientState state_min)
     718             : {
     719           0 :         std::map<u16, RemoteClient*>::iterator n;
     720           0 :         n = m_clients.find(peer_id);
     721             :         // The client may not exist; clients are immediately removed if their
     722             :         // access is denied, and this event occurs later then.
     723           0 :         if(n == m_clients.end())
     724           0 :                 return NULL;
     725             : 
     726           0 :         if (n->second->getState() >= state_min)
     727           0 :                 return n->second;
     728             :         else
     729           0 :                 return NULL;
     730             : }
     731             : 
     732           0 : ClientState ClientInterface::getClientState(u16 peer_id)
     733             : {
     734           0 :         JMutexAutoLock clientslock(m_clients_mutex);
     735           0 :         std::map<u16, RemoteClient*>::iterator n;
     736           0 :         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           0 :         if(n == m_clients.end())
     740           0 :                 return CS_Invalid;
     741             : 
     742           0 :         return n->second->getState();
     743             : }
     744             : 
     745           0 : void ClientInterface::setPlayerName(u16 peer_id,std::string name)
     746             : {
     747           0 :         JMutexAutoLock clientslock(m_clients_mutex);
     748           0 :         std::map<u16, RemoteClient*>::iterator n;
     749           0 :         n = m_clients.find(peer_id);
     750             :         // The client may not exist; clients are immediately removed if their
     751             :         // access is denied, and this event occurs later then.
     752           0 :         if(n != m_clients.end())
     753           0 :                 n->second->setName(name);
     754           0 : }
     755             : 
     756           0 : void ClientInterface::DeleteClient(u16 peer_id)
     757             : {
     758           0 :         JMutexAutoLock conlock(m_clients_mutex);
     759             : 
     760             :         // Error check
     761           0 :         std::map<u16, RemoteClient*>::iterator n;
     762           0 :         n = m_clients.find(peer_id);
     763             :         // The client may not exist; clients are immediately removed if their
     764             :         // access is denied, and this event occurs later then.
     765           0 :         if(n == m_clients.end())
     766           0 :                 return;
     767             : 
     768             :         /*
     769             :                 Mark objects to be not known by the client
     770             :         */
     771             :         //TODO this should be done by client destructor!!!
     772           0 :         RemoteClient *client = n->second;
     773             :         // Handle objects
     774           0 :         for(std::set<u16>::iterator
     775           0 :                         i = client->m_known_objects.begin();
     776           0 :                         i != client->m_known_objects.end(); ++i)
     777             :         {
     778             :                 // Get object
     779           0 :                 u16 id = *i;
     780           0 :                 ServerActiveObject* obj = m_env->getActiveObject(id);
     781             : 
     782           0 :                 if(obj && obj->m_known_by_count > 0)
     783           0 :                         obj->m_known_by_count--;
     784             :         }
     785             : 
     786             :         // Delete client
     787           0 :         delete m_clients[peer_id];
     788           0 :         m_clients.erase(peer_id);
     789             : }
     790             : 
     791           0 : void ClientInterface::CreateClient(u16 peer_id)
     792             : {
     793           0 :         JMutexAutoLock conlock(m_clients_mutex);
     794             : 
     795             :         // Error check
     796           0 :         std::map<u16, RemoteClient*>::iterator n;
     797           0 :         n = m_clients.find(peer_id);
     798             :         // The client shouldn't already exist
     799           0 :         if(n != m_clients.end()) return;
     800             : 
     801             :         // Create client
     802           0 :         RemoteClient *client = new RemoteClient();
     803           0 :         client->peer_id = peer_id;
     804           0 :         m_clients[client->peer_id] = client;
     805             : }
     806             : 
     807           0 : void ClientInterface::event(u16 peer_id, ClientStateEvent event)
     808             : {
     809             :         {
     810           0 :                 JMutexAutoLock clientlock(m_clients_mutex);
     811             : 
     812             :                 // Error check
     813           0 :                 std::map<u16, RemoteClient*>::iterator n;
     814           0 :                 n = m_clients.find(peer_id);
     815             : 
     816             :                 // No client to deliver event
     817           0 :                 if (n == m_clients.end())
     818           0 :                         return;
     819           0 :                 n->second->notifyEvent(event);
     820             :         }
     821             : 
     822           0 :         if ((event == CSE_SetClientReady) ||
     823           0 :                 (event == CSE_Disconnect)     ||
     824             :                 (event == CSE_SetDenied))
     825             :         {
     826           0 :                 UpdatePlayerList();
     827             :         }
     828             : }
     829             : 
     830           0 : u16 ClientInterface::getProtocolVersion(u16 peer_id)
     831             : {
     832           0 :         JMutexAutoLock conlock(m_clients_mutex);
     833             : 
     834             :         // Error check
     835           0 :         std::map<u16, RemoteClient*>::iterator n;
     836           0 :         n = m_clients.find(peer_id);
     837             : 
     838             :         // No client to get version
     839           0 :         if (n == m_clients.end())
     840           0 :                 return 0;
     841             : 
     842           0 :         return n->second->net_proto_version;
     843             : }
     844             : 
     845           0 : void ClientInterface::setClientVersion(u16 peer_id, u8 major, u8 minor, u8 patch, std::string full)
     846             : {
     847           0 :         JMutexAutoLock conlock(m_clients_mutex);
     848             : 
     849             :         // Error check
     850           0 :         std::map<u16, RemoteClient*>::iterator n;
     851           0 :         n = m_clients.find(peer_id);
     852             : 
     853             :         // No client to set versions
     854           0 :         if (n == m_clients.end())
     855           0 :                 return;
     856             : 
     857           0 :         n->second->setVersionInfo(major,minor,patch,full);
     858           3 : }

Generated by: LCOV version 1.11