mixed cmd(string args) { object player = this_player(); mixed replee = player->GetProperty("reply"); string ret = ""; string *tmp; ret += "Screen: \t\t"+identify(this_player()->GetScreen())+"\n"; ret += "Terminal: \t\t"+this_player()->GetTerminal()+"\n"; ret += "Brief mode: \t\t"+ ( (this_player()->GetBriefMode()) ? "on" : "off" )+"\n"; ret += "Cursefilter: \t\t"+ ( (this_player()->GetParanoia("cursefilter")) ? "on" : "off" )+"\n"; ret += "Channel message colors: "+ ( (this_player()->GetNoChanColors()) ? "off" : "on" )+"\n"; ret += "Playerkiller mode: \t"+ ( (this_player()->GetPK()) ? "on" : "off" )+"\n"; ret += "Mute mode: \t\t"+ GetMuted()+" \n"; ret += "Gag mode: \t\t"+ GetGagged()+" \n"; ret += "Wimpy mode: \t\t"+ ( (this_player()->GetWimpy()) ? "on" : "off" )+"\n"; #if efun_defined(compressedp) ret += "MCCP mode: \t\t"+(compressedp(this_player()) ? "on" : "off")+"\n"; #endif #if MINIMAP ret += "Minimap mode: \t\t"+ ( this_player()->GetProperty("minimapping") ? "on" : "off" )+"\n"; #endif ret += "Annoyblock: \t\t"+ ( (this_player()->GetAnnoyblock()) ? "on" : "off" )+"\n"; ret += "Reprompt mode: \t\t"+ ( this_player()->GetProperty("reprompt") ? "on" : "off" )+"\n"; ret += "Screenlock mode: \t"+ ( this_player()->GetProperty("screenlock") ? "on" : "off" )+"\n"; ret += "Timezone: \t\t"+ ( this_player()->GetProperty("timezone") ? this_player()->GetProperty("timezone") : "None specified" )+"\n"; #ifdef __GET_CHAR_IS_BUFFERED__ ret += "Charmode: \t\t"+ //( (query_charmode(player) > 0) ? "on" : "off" )+"\n"; ( (player->GetCharmode()) ? "on" : "off" )+"\n"; #endif ret += "Commandecho: \t\t"+ ( this_player()->GetProperty("commandecho") ? this_player()->GetProperty("commandecho") : "off" )+"\n"; #ifdef __DSLIB__ ret += "Keepalive mode: \t"+ ( this_player()->GetProperty("keepalive") ? this_player()->GetProperty("keepalive") : "off" )+"\n"; #endif if(creatorp(this_player())){ ret += "Homedir: \t\t"+user_path(this_player())+"\n"; if(this_player()->GetParanoia("homeroom")){ ret += "Homeroom: \t\t"+this_player()->GetParanoia("homeroom")+"\n"; } ret += "Debug mode: \t\t"+ ( (this_player()->GetProperty("debug")) ? "on" : "off" )+"\n"; ret += "Godmode: \t\t"+ ( (this_player()->GetGodMode()) ? "on" : "off" )+"\n"; ret += "Wizvision: \t\t"+ ( (this_player()->GetWizVision()) ? "on" : "off" )+"\n"; #if GRID ret += "Showgrid: \t\t"+ ( (this_player()->GetVisibleGrid()) ? "on" : "off" )+"\n"; ret += "Wizmap mode: \t\t"+ ( this_player()->GetProperty("wizmapping") ? "on" : "off" )+"\n"; ret += "Noclip mode: \t\t"+ ( this_player()->GetProperty("noclip") ? "on" : "off" )+"\n"; ret += "Anchor: \t\t"+ ( this_player()->GetAnchored() ? "on" : "off" )+"\n"; #endif } if(replee){ ret += "Reply target: \t\t"+replee+"\n"; } tmp = sort_array(explode(ret, "\n"),1); ret = implode(tmp, "\n"); write(ret); return 1; }
void CGamePlayer :: ProcessPackets( ) { if( !m_Socket ) return; CIncomingAction *Action = NULL; CIncomingChatPlayer *ChatPlayer = NULL; CIncomingMapSize *MapSize = NULL; bool HasMap = false; uint32_t CheckSum = 0; uint32_t Pong = 0; // process all the received packets in the m_Packets queue while( !m_Packets.empty( ) ) { CCommandPacket *Packet = m_Packets.front( ); m_Packets.pop( ); if( Packet->GetPacketType( ) == W3GS_HEADER_CONSTANT ) { switch( Packet->GetID( ) ) { case CGameProtocol :: W3GS_LEAVEGAME: m_Game->EventPlayerLeft( this, m_Protocol->RECEIVE_W3GS_LEAVEGAME( Packet->GetData( ) ) ); break; case CGameProtocol :: W3GS_GAMELOADED_SELF: if( m_Protocol->RECEIVE_W3GS_GAMELOADED_SELF( Packet->GetData( ) ) ) { if( !m_FinishedLoading && m_Game->GetGameLoading( ) ) { m_FinishedLoading = true; m_FinishedLoadingTicks = GetTicks( ); m_Game->EventPlayerLoaded( this ); } else { // we received two W3GS_GAMELOADED_SELF packets from this player! } } break; case CGameProtocol :: W3GS_OUTGOING_ACTION: Action = m_Protocol->RECEIVE_W3GS_OUTGOING_ACTION( Packet->GetData( ), m_PID ); if( Action ) { // don't delete Action here because the game is going to store it in a queue and delete it later m_Game->EventPlayerAction( this, Action ); } break; case CGameProtocol :: W3GS_OUTGOING_KEEPALIVE: CheckSum = m_Protocol->RECEIVE_W3GS_OUTGOING_KEEPALIVE( Packet->GetData( ) ); m_CheckSums.push( CheckSum ); ++m_SyncCounter; m_Game->EventPlayerKeepAlive( this, CheckSum ); break; case CGameProtocol :: W3GS_CHAT_TO_HOST: ChatPlayer = m_Protocol->RECEIVE_W3GS_CHAT_TO_HOST( Packet->GetData( ) ); if( ChatPlayer ) { // determine if we should auto-mute this player if( ChatPlayer->GetType( ) == CIncomingChatPlayer :: CTH_MESSAGE || ChatPlayer->GetType( ) == CIncomingChatPlayer :: CTH_MESSAGEEXTRA ) { if( m_Level <= 1 &&! GetMuted( ) ) { m_MuteMessages.push_back( GetTicks( ) ); if( m_MuteMessages.size( ) > 7 ) m_MuteMessages.erase( m_MuteMessages.begin( ) ); uint32_t RecentCount = 0; for( unsigned int i = 0; i < m_MuteMessages.size( ); ++i ) { if( GetTicks( ) - m_MuteMessages[i] < 5000 ) { RecentCount++; } } if( m_Game->m_OHBot->m_AutoMuteSpammer && RecentCount >= 7 ) { m_Count++; if( m_Count == 1 ) { SetMuted( true ); m_MutedAuto = true; m_Game->SendChat( m_PID, "["+m_Game->m_OHBot->m_BotManagerName+"] "+m_Game->m_OHBot->m_Language->SpamWarning( ) ); m_MuteMessages.clear( ); m_Game->SendAllChat( "["+m_Game->m_OHBot->m_BotManagerName+"] " + m_Game->m_OHBot->m_Language->UserWasMutedForReason( m_Name, "spamming" ) ); } if( m_Count == 2 ) { m_Game->SendAllChat( m_Game->m_OHBot->m_Language->UserIgnoerNotify( m_Name ) ); m_Game->SendChat( m_PID, "["+m_Game->m_OHBot->m_BotManagerName+"] "+m_Game->m_OHBot->m_Language->SpamWarning2( ) ); SetMuted( true ); m_Game->m_Pairedpenps.push_back( Pairedpenp( string(), m_Game->m_OHBot->m_DB->Threadedpenp( m_Name, "Spam" , m_Game->m_OHBot->m_BotManagerName, 1, "add" ) ) ); m_MutedAuto = true; m_Game->SendAllChat( "["+m_Game->m_OHBot->m_BotManagerName+"] " + m_Game->m_OHBot->m_Language->UserWasMutedForReason( m_Name, "spamming" ) ); } if( m_Count == 3 ) { m_Game->BanPlayerByPenality( m_Name, GetExternalIPString( ), m_Game->m_OHBot->m_BotManagerName, m_PenalityLevel, "Spam" ); SetMuted( true ); m_Game->SendAllChat( "["+m_Game->m_OHBot->m_BotManagerName+"] " + m_Game->m_OHBot->m_Language->UserWasMutedForReason( m_Name, "spamming" ) ); } } //we adding this condition not in the next condition to avoid a jump into ohbot.cpp to check if the message was a flame message or not if(m_Game->m_OHBot->m_FlameCheck && ( m_Name != "dolan" || m_Name != "Dolan" ) ) { //now check for flamers if( m_Game->m_OHBot->FlameCheck( ChatPlayer->GetMessage( ) ) ) { m_FlameMessages.push_back( GetTicks( ) ); if( m_FlameMessages.size( ) > 10 ) m_FlameMessages.erase( m_FlameMessages.begin( ) ); RecentCount = 0; for( unsigned int i = 0; i < m_FlameMessages.size( ); ++i ) { if( GetTicks( ) - m_FlameMessages[i] < 60000 ) RecentCount++; } if( RecentCount == 1 ) { m_Game->SendChat( m_PID, "["+m_Game->m_OHBot->m_BotManagerName+"] "+m_Game->m_OHBot->m_Language->FlameWarn ()); } if( RecentCount == 2 ) { m_Game->SendChat( m_PID, "["+m_Game->m_OHBot->m_BotManagerName+"] "+m_Game->m_OHBot->m_Language->FlameWarn2 () ); SetMuted( true ); m_MutedAuto = true; m_Game->SendAllChat( "["+m_Game->m_OHBot->m_BotManagerName+"] " + m_Game->m_OHBot->m_Language->UserWasMutedForReason( m_Name, "flaming" ) ); } if( RecentCount == 3 ) { m_Game->SendChat( m_PID, m_Game->m_OHBot->m_Language->FlameWarn3 () ); SetMuted( true ); m_Game->m_Pairedpenps.push_back( Pairedpenp( string(), m_Game->m_OHBot->m_DB->Threadedpenp( m_Name, "Flame/Insult" , m_Game->m_OHBot->m_BotManagerName, 1, "add" ) ) ); m_MutedAuto = true; m_Game->SendAllChat( "["+m_Game->m_OHBot->m_BotManagerName+"] " + m_Game->m_OHBot->m_Language->UserWasMutedForReason( m_Name, "flaming" ) ); } if( RecentCount == 4 ) { m_Game->BanPlayerByPenality( m_Name, GetExternalIPString( ), m_Game->m_OHBot->m_BotManagerName, m_PenalityLevel, "Flame/Insult" ); SetMuted( true ); m_Game->SendAllChat( "["+m_Game->m_OHBot->m_BotManagerName+"] " + m_Game->m_OHBot->m_Language->UserWasMutedForReason( m_Name, "flaming" ) ); } if( RecentCount == 5 ) { //some people simple dont understand the ban policy. m_Game->BanPlayerByPenality( m_Name, GetExternalIPString( ), m_Game->m_OHBot->m_BotManagerName, m_PenalityLevel, "Flame/Insult" ); SetMuted( true ); m_Game->SendAllChat( "["+m_Game->m_OHBot->m_BotManagerName+"] " + m_Game->m_OHBot->m_Language->UserWasMutedForReason( m_Name, "flaming" ) ); } } } } } m_Game->EventPlayerChatToHost( this, ChatPlayer ); } delete ChatPlayer; ChatPlayer = NULL; break; case CGameProtocol :: W3GS_DROPREQ: // todotodo: no idea what's in this packet if( !m_DropVote ) { m_DropVote = true; m_Game->EventPlayerDropRequest( this ); } break; case CGameProtocol :: W3GS_MAPSIZE: MapSize = m_Protocol->RECEIVE_W3GS_MAPSIZE( Packet->GetData( ), m_Game->m_OHBot->m_Map->GetMapSize( ) ); if( MapSize ) m_Game->EventPlayerMapSize( this, MapSize ); delete MapSize; MapSize = NULL; break; case CGameProtocol :: W3GS_PONG_TO_HOST: Pong = m_Protocol->RECEIVE_W3GS_PONG_TO_HOST( Packet->GetData( ) ); // we discard pong values of 1 // the client sends one of these when connecting plus we return 1 on error to kill two birds with one stone if( Pong != 1 ) { // we also discard pong values when we're downloading because they're almost certainly inaccurate // this statement also gives the player a 5 second grace period after downloading the map to allow queued (i.e. delayed) ping packets to be ignored if( !m_DownloadStarted || ( m_DownloadFinished && GetTime( ) - m_FinishedDownloadingTime >= 5 ) ) { // we also discard pong values when anyone else is downloading if we're configured to if( m_Game->m_OHBot->m_PingDuringDownloads || !m_Game->IsDownloading( ) ) { m_Pings.push_back( GetTicks( ) - Pong ); if( m_Pings.size( ) > 20 ) m_Pings.erase( m_Pings.begin( ) ); } } } m_Game->EventPlayerPongToHost( this, Pong ); break; } } else if( Packet->GetPacketType( ) == GPS_HEADER_CONSTANT ) { BYTEARRAY Data = Packet->GetData( ); if( Packet->GetID( ) == CGPSProtocol :: GPS_INIT ) { if( m_Game->m_OHBot->IsMode( BOT_MODE_GPROXY ) ) { m_GProxy = true; m_Socket->PutBytes( m_Game->m_OHBot->m_GPSProtocol->SEND_GPSS_INIT( m_Game->m_OHBot->m_ReconnectPort, m_PID, m_GProxyReconnectKey, m_Game->GetGProxyEmptyActions( ) ) ); //Log->Info( "[GAME: " + m_Game->GetGameName( ) + "] player [" + m_Name + "] is using GProxy++" ); } else { // todotodo: send notice that we're not permitting reconnects // note: GProxy++ should never send a GPS_INIT message if bot_reconnect = 0 because we don't advertise the game with invalid map dimensions // but it would be nice to cover this case anyway } } else if( Packet->GetID( ) == CGPSProtocol :: GPS_RECONNECT ) { // this is handled in ohbot.cpp } else if( Packet->GetID( ) == CGPSProtocol :: GPS_ACK && Data.size( ) == 8 ) { uint32_t LastPacket = UTIL_ByteArrayToUInt32( Data, false, 4 ); uint32_t PacketsAlreadyUnqueued = m_TotalPacketsSent - m_GProxyBuffer.size( ); if( LastPacket > PacketsAlreadyUnqueued ) { uint32_t PacketsToUnqueue = LastPacket - PacketsAlreadyUnqueued; if( PacketsToUnqueue > m_GProxyBuffer.size( ) ) PacketsToUnqueue = m_GProxyBuffer.size( ); while( PacketsToUnqueue > 0 ) { m_GProxyBuffer.pop( ); --PacketsToUnqueue; } } } } delete Packet; } }
bool CGamePlayer :: Update( void *fd ) { // wait 4 seconds after joining before sending the /whois or /w // if we send the /whois too early battle.net may not have caught up with where the player is and return erroneous results if( m_WhoisShouldBeSent && !m_Spoofed && !m_WhoisSent && !m_JoinedRealm.empty( ) && GetTime( ) - m_JoinTime >= 4 ) { // todotodo: we could get kicked from battle.net for sending a command with invalid characters, do some basic checking for( vector<CBNET *> :: iterator i = m_Game->m_OHBot->m_BNETs.begin( ); i != m_Game->m_OHBot->m_BNETs.end( ); ++i ) { if( (*i)->GetServer( ) == m_JoinedRealm ) { if( m_Game->GetGameState( ) == GAME_PUBLIC ) { if( (*i)->GetPasswordHashType( ) == "pvpgn" ) (*i)->QueueChatCommand( "/whereis " + m_Name ); else (*i)->QueueChatCommand( "/whois " + m_Name ); } else if( m_Game->GetGameState( ) == GAME_PRIVATE ) (*i)->QueueChatCommand( m_Game->m_OHBot->m_Language->SpoofCheckByReplying( ), m_Name, true ); } } m_WhoisSent = true; } // check for socket timeouts // if we don't receive anything from a player for 30 seconds we can assume they've dropped // this works because in the lobby we send pings every 5 seconds and expect a response to each one // and in the game the Warcraft 3 client sends keepalives frequently (at least once per second it looks like) if( m_Socket && GetTime( ) - m_Socket->GetLastRecv( ) >= 30 ) m_Game->EventPlayerDisconnectTimedOut( this ); // make sure we're not waiting too long for the first MAPSIZE packet /* if( m_ConnectionState == 1 && GetTicks( ) - m_ConnectionTime > 5000 && !m_Game->GetGameLoaded() && !m_Game->GetGameLoading() ) { Log->Info( "[DENY] Kicking player: MAPSIZE not received within five seconds" ); m_DeleteMe = true; SetLeftReason( "MAPSIZE not received within five seconds" ); SetLeftCode( PLAYERLEAVE_LOBBY ); m_Game->OpenSlot( m_Game->GetSIDFromPID( GetPID( ) ), false ); } */ // disconnect if the player is downloading too slowly // make this a bit dynamically, first 10 KB/s is a bit too low, increasing to 100KB/s //decreasing the checktime to 5 seconds // adding an actual playercheck how many players are ingame, if there less than 1 open slots we deny users with a download rate under 500KB/s if( m_DownloadStarted && !m_DownloadFinished && !m_Game->GetGameLoaded() && !m_Game->GetGameLoading() && GetLastMapPartSent( ) > 0 && m_Game->m_OHBot->m_KickSlowDownloader ) { uint32_t downloadingTime = GetTicks( ) - m_StartedDownloadingTicks; if( downloadingTime > 5000 && m_Level < 1) { if( GetLastMapPartAcked( ) / downloadingTime < 500 && m_Game->GetSlotsOccupied( ) <= 1 ) { m_DeleteMe = true; SetLeftReason( "download speed too low" ); SetLeftCode( PLAYERLEAVE_LOBBY ); m_Game->SendAllChat( m_Game->m_OHBot->m_Language->UserWasKickedForSlowDownloadRate( m_Name ) ); m_Game->OpenSlot( m_Game->GetSIDFromPID( GetPID( ) ), false ); } else if( GetLastMapPartAcked( ) / downloadingTime < 100 ) { m_DeleteMe = true; SetLeftReason( "download speed too low" ); SetLeftCode( PLAYERLEAVE_LOBBY ); m_Game->SendAllChat( m_Game->m_OHBot->m_Language->UserWasKickedForSlowDownloadRate( m_Name ) ); m_Game->OpenSlot( m_Game->GetSIDFromPID( GetPID( ) ), false ); } } } // unmute player if( GetMuted( ) && m_MutedAuto && GetTicks( ) - m_MutedTicks > 30000 ) { SetMuted( false ); m_Game->SendChat( m_PID, "["+m_Game->m_OHBot->m_BotManagerName+"] "+m_Game->m_OHBot->m_Language->UserWasAutomaticallyUnmuted( ) ); m_MuteMessages.clear( ); } // GProxy++ acks if( m_Game->m_OHBot->IsMode( BOT_MODE_GPROXY ) && m_GProxy && GetTime( ) - m_LastGProxyAckTime >= 10 ) { if( m_Socket ) m_Socket->PutBytes( m_Game->m_OHBot->m_GPSProtocol->SEND_GPSS_ACK( m_TotalPacketsReceived ) ); m_LastGProxyAckTime = GetTime( ); } // base class update CPotentialPlayer :: Update( fd ); bool Deleting; if( m_GProxy && m_Game->GetGameLoaded( ) ) Deleting = m_DeleteMe || m_Error; else Deleting = m_DeleteMe || m_Error || m_Socket->HasError( ) || !m_Socket->GetConnected( ); // try to find out why we're requesting deletion // in cases other than the ones covered here m_LeftReason should have been set when m_DeleteMe was set if( m_Error ) { m_Game->EventPlayerDisconnectPlayerError( this ); m_Socket->Reset( ); return Deleting; } if( m_Socket ) { if( m_Socket->HasError( ) ) { m_Game->EventPlayerDisconnectSocketError( this ); m_Socket->Reset( ); } else if( !m_Socket->GetConnected( ) ) { m_Game->EventPlayerDisconnectConnectionClosed( this ); m_Socket->Reset( ); } } return Deleting; }
void CGamePlayer :: ProcessPackets( ) { if( !m_Socket ) return; CIncomingAction *Action = NULL; CIncomingChatPlayer *ChatPlayer = NULL; CIncomingMapSize *MapSize = NULL; uint32_t CheckSum = 0; uint32_t Pong = 0; // process all the received packets in the m_Packets queue while( !m_Packets.empty( ) ) { CCommandPacket *Packet = m_Packets.front( ); m_Packets.pop( ); if( Packet->GetPacketType( ) == W3GS_HEADER_CONSTANT ) { switch( Packet->GetID( ) ) { case CGameProtocol :: W3GS_LEAVEGAME: m_Game->EventPlayerLeft( this, m_Protocol->RECEIVE_W3GS_LEAVEGAME( Packet->GetData( ) ) ); break; case CGameProtocol :: W3GS_GAMELOADED_SELF: if( m_Protocol->RECEIVE_W3GS_GAMELOADED_SELF( Packet->GetData( ) ) ) { if( !m_FinishedLoading && m_Game->GetGameLoading( ) ) { m_FinishedLoading = true; m_FinishedLoadingTicks = GetTicks( ); m_Game->EventPlayerLoaded( this ); } else { // we received two W3GS_GAMELOADED_SELF packets from this player! } } break; case CGameProtocol :: W3GS_OUTGOING_ACTION: Action = m_Protocol->RECEIVE_W3GS_OUTGOING_ACTION( Packet->GetData( ), m_PID ); if( Action ) m_Game->EventPlayerAction( this, Action ); // don't delete Action here because the game is going to store it in a queue and delete it later break; case CGameProtocol :: W3GS_OUTGOING_KEEPALIVE: CheckSum = m_Protocol->RECEIVE_W3GS_OUTGOING_KEEPALIVE( Packet->GetData( ) ); m_CheckSums.push( CheckSum ); m_SyncCounter++; m_Game->EventPlayerKeepAlive( this, CheckSum ); break; case CGameProtocol :: W3GS_CHAT_TO_HOST: ChatPlayer = m_Protocol->RECEIVE_W3GS_CHAT_TO_HOST( Packet->GetData( ) ); if( ChatPlayer ) { // determine if we should auto-mute this player if( ChatPlayer->GetType( ) == CIncomingChatPlayer :: CTH_MESSAGE || ChatPlayer->GetType( ) == CIncomingChatPlayer :: CTH_MESSAGEEXTRA ) { m_MuteMessages.push_back( GetTicks( ) ); if( m_MuteMessages.size( ) > 7 ) m_MuteMessages.erase( m_MuteMessages.begin( ) ); uint32_t RecentCount = 0; for( unsigned int i = 0; i < m_MuteMessages.size( ); ++i ) { if( GetTicks( ) - m_MuteMessages[i] < 7000 ) RecentCount++; } if( !GetMuted( ) && RecentCount >= 7 ) { SetMuted( true ); m_MutedAuto = true; m_Game->SendAllChat( "[" + m_Name + "] has been automatically muted for spamming. (You will be unmuted momentarily, but please do not spam again!)" ); m_MuteMessages.clear( ); } //now check for flamers if( m_Game->m_GHost->FlameCheck( ChatPlayer->GetMessage( ) ) ) { m_FlameMessages.push_back( GetTicks( ) ); if( m_FlameMessages.size( ) > 10 ) m_FlameMessages.erase( m_FlameMessages.begin( ) ); RecentCount = 0; for( unsigned int i = 0; i < m_FlameMessages.size( ); ++i ) { if( GetTicks( ) - m_FlameMessages[i] < 80000 ) RecentCount++; } if( RecentCount >= 4 ) { m_Game->SendAllChat( "Use "+string(1, m_Game->m_GHost->m_CommandTrigger)+"ignore <playername> to ignore players (for example, if they are flaming); partial names work. Don't flame back!" ); m_FlameMessages.clear( ); } else if( RecentCount >= 3 ) { m_Game->SendAllChat( "[Calm] has refilled [" + GetName() + "]'s cookie jar. [" + GetName() + "] now has three cookies (try "+string(1, m_Game->m_GHost->m_CommandTrigger)+"eat)!"); SetCookies(3); } } } m_Game->EventPlayerChatToHost( this, ChatPlayer ); } delete ChatPlayer; ChatPlayer = NULL; break; case CGameProtocol :: W3GS_DROPREQ: // todotodo: no idea what's in this packet if( !m_DropVote ) { m_DropVote = true; m_Game->EventPlayerDropRequest( this ); } break; case CGameProtocol :: W3GS_MAPSIZE: m_ConnectionState = 2; m_ConnectionTime = GetTicks( ); MapSize = m_Protocol->RECEIVE_W3GS_MAPSIZE( Packet->GetData( ), m_Game->m_GHost->m_Map->GetMapSize( ) ); if( MapSize ) m_Game->EventPlayerMapSize( this, MapSize ); delete MapSize; MapSize = NULL; break; case CGameProtocol :: W3GS_PONG_TO_HOST: Pong = m_Protocol->RECEIVE_W3GS_PONG_TO_HOST( Packet->GetData( ) ); // we discard pong values of 1 // the client sends one of these when connecting plus we return 1 on error to kill two birds with one stone if( Pong != 1 ) { // we also discard pong values when we're downloading because they're almost certainly inaccurate // this statement also gives the player a 5 second grace period after downloading the map to allow queued (i.e. delayed) ping packets to be ignored if( !m_DownloadStarted || ( m_DownloadFinished && GetTime( ) - m_FinishedDownloadingTime >= 5 ) ) { // we also discard pong values when anyone else is downloading if we're configured to if( m_Game->m_GHost->m_PingDuringDownloads || !m_Game->IsDownloading( ) ) { m_Pings.push_back( GetTicks( ) - Pong ); if( m_Pings.size( ) > 20 ) m_Pings.erase( m_Pings.begin( ) ); } } } m_Game->EventPlayerPongToHost( this, Pong ); break; } } else if( Packet->GetPacketType( ) == GPS_HEADER_CONSTANT ) { BYTEARRAY Data = Packet->GetData( ); if( Packet->GetID( ) == CGPSProtocol :: GPS_INIT ) { if( m_Game->m_GHost->m_Reconnect ) { m_GProxy = true; m_Socket->PutBytes( m_Game->m_GHost->m_GPSProtocol->SEND_GPSS_INIT( m_Game->m_GHost->m_ReconnectPort, m_PID, m_GProxyReconnectKey, m_Game->GetGProxyEmptyActions( ) ) ); CONSOLE_Print( "[GAME: " + m_Game->GetGameName( ) + "] player [" + m_Name + "] is using GProxy++" ); } else { // todotodo: send notice that we're not permitting reconnects // note: GProxy++ should never send a GPS_INIT message if bot_reconnect = 0 because we don't advertise the game with invalid map dimensions // but it would be nice to cover this case anyway } } else if( Packet->GetID( ) == CGPSProtocol :: GPS_RECONNECT ) { // this is handled in ghost.cpp } else if( Packet->GetID( ) == CGPSProtocol :: GPS_ACK && Data.size( ) == 8 ) { uint32_t LastPacket = UTIL_ByteArrayToUInt32( Data, false, 4 ); uint32_t PacketsAlreadyUnqueued = m_TotalPacketsSent - m_GProxyBuffer.size( ); if( LastPacket > PacketsAlreadyUnqueued ) { uint32_t PacketsToUnqueue = LastPacket - PacketsAlreadyUnqueued; if( PacketsToUnqueue > m_GProxyBuffer.size( ) ) PacketsToUnqueue = m_GProxyBuffer.size( ); while( PacketsToUnqueue > 0 ) { m_GProxyBuffer.pop( ); PacketsToUnqueue--; } } } } delete Packet; } }
bool CGamePlayer :: Update( void *fd ) { // wait 4 seconds after joining before sending the /whois or /w // if we send the /whois too early battle.net may not have caught up with where the player is and return erroneous results if( m_WhoisShouldBeSent && !m_Spoofed && !m_WhoisSent && !m_JoinedRealm.empty( ) && GetTime( ) - m_JoinTime >= 4 ) { // todotodo: we could get kicked from battle.net for sending a command with invalid characters, do some basic checking // check if we have this ip in our spoofed cached ip list bool isspoofed = m_Game->m_GHost->IsSpoofedIP(GetName(), GetExternalIPString()); if (isspoofed) { CONSOLE_Print("[OPT] Player "+GetName()+" is in the cached spoof checked list"); m_Game->AddToSpoofed(m_Game->m_Server, GetName(), false); } if (!isspoofed && GetExternalIPString()!="127.0.0.1") for( vector<CBNET *> :: iterator i = m_Game->m_GHost->m_BNETs.begin( ); i != m_Game->m_GHost->m_BNETs.end( ); i++ ) { if( (*i)->GetServer( ) == m_JoinedRealm ) { if( m_Game->GetGameState( ) == GAME_PUBLIC ) { if ((*i)->GetWhereis() || (*i)->GetPasswordHashType( ) == "pvpgn" ) (*i)->QueueChatCommand( "/whereis " + m_Name ); else (*i)->QueueChatCommand( "/whois " + m_Name ); } else if( m_Game->GetGameState( ) == GAME_PRIVATE ) (*i)->QueueChatCommand( m_Game->m_GHost->m_Language->SpoofCheckByReplying( ), m_Name, true ); } } m_WhoisSent = true; } // check for socket timeouts // if we don't receive anything from a player for 30 seconds we can assume they've dropped // this works because in the lobby we send pings every 5 seconds and expect a response to each one // and in the game the Warcraft 3 client sends keepalives frequently (at least once per second it looks like) if( m_Socket && GetTime( ) - m_Socket->GetLastRecv( ) >= 30 ) m_Game->EventPlayerDisconnectTimedOut( this ); // make sure we're not waiting too long for the first MAPSIZE packet if( m_ConnectionState == 1 && GetTicks( ) - m_ConnectionTime > m_Game->m_GHost->m_DenyMaxMapsizeTime && !m_Game->GetGameLoaded() && !m_Game->GetGameLoading() ) { CONSOLE_Print( "[DENY] Kicking player: MAPSIZE not received within a few seconds" ); m_DeleteMe = true; SetLeftReason( "MAPSIZE not received within a few seconds" ); SetLeftCode( PLAYERLEAVE_LOBBY ); m_Game->OpenSlot( m_Game->GetSIDFromPID( GetPID( ) ), false ); m_Game->m_GHost->DenyIP( GetExternalIPString( ), m_Game->m_GHost->m_DenyMapsizeDuration, "MAPSIZE not received within a few seconds" ); } // disconnect if the player is downloading too slowly if( m_DownloadStarted && !m_DownloadFinished && !m_Game->GetGameLoaded() && !m_Game->GetGameLoading() && GetLastMapPartSent( ) != 0 ) { uint32_t downloadingTime = GetTicks( ) - m_StartedDownloadingTicks; uint32_t Seconds = downloadingTime / 1000; uint32_t Rate = GetLastMapPartSent( ) / 1024; // Rate in miliseconds if (Seconds>0) Rate /= Seconds; if(!(m_Game->IsSafe(GetName()) || m_Game->IsAdmin(GetName()) || m_Game->IsRootAdmin(GetName()) || m_Game->IsOwner(GetName()) )){ // uint32_t iRate = (uint32_t)Rate; if ( m_Game->m_GHost->m_DLRateLimit != 0 ) if ( GetLastMapPartSent( ) <= 102400 ) if ( 0 < Rate && Rate < m_Game->m_GHost->m_DLRateLimit ){ m_Game->DelTempOwner( GetName() ); m_Game->SendAllChat( m_Game->m_GHost->m_Language->KickMsgForSlowDL( GetName( ) , UTIL_ToString( Rate ), UTIL_ToString(m_Game->m_GHost->m_DLRateLimit) ) ); m_Game->m_GHost->m_Callables.push_back( m_Game->m_GHost->m_DB->ThreadedBanAdd( GetJoinedRealm( ), GetName( ), GetExternalIPString(), m_Game->GetGameName( ), "AUTOBAN", "Slow internet", 1, 0 )); if ( m_Game->m_GHost->m_BlacklistSlowDLder && !m_Game->IsBlacklisted(m_Game->GetBannedNames( ),GetName( )) ) m_Game->AddBannedNames(GetName( )); m_DeleteMe = true; SetLeftReason( "kicked for downloading too slowly " + UTIL_ToString( Rate ) + " KB/s" ); SetLeftCode( PLAYERLEAVE_LOBBY ); m_Game->OpenSlot( m_Game->GetSIDFromPID( GetPID( ) ), false ); } if( downloadingTime > m_Game->m_GHost->m_DenyMaxDownloadTime ) { m_Game->DelTempOwner( GetName() ); m_Game->SendAllChat( m_Game->m_GHost->m_Language->KickMsgForSlowDL( GetName( ),"","" ) ); m_DeleteMe = true; SetLeftReason( "download time is too long" ); SetLeftCode( PLAYERLEAVE_LOBBY ); m_Game->OpenSlot( m_Game->GetSIDFromPID( GetPID( ) ), false ); m_Game->m_GHost->DenyIP( GetExternalIPString( ), m_Game->m_GHost->m_DenyDownloadDuration, "("+ GetName( ) +") rejected because download time is too long" ); } } } // unmute player if( GetMuted( ) && ( GetTicks( ) - m_MutedTicks > 60000 || ( m_MutedAuto && GetTicks( ) - m_MutedTicks > 15000 ) ) ) { SetMuted( false ); m_Game->SendAllChat( "[" + m_Name + "] has been automatically unmuted. (Don't spam or you'll be muted again!)" ); m_MuteMessages.clear( ); } // GProxy++ acks if( m_GProxy && GetTime( ) - m_LastGProxyAckTime >= 10 ) { if( m_Socket ) m_Socket->PutBytes( m_Game->m_GHost->m_GPSProtocol->SEND_GPSS_ACK( m_TotalPacketsReceived ) ); m_LastGProxyAckTime = GetTime( ); } // base class update CPotentialPlayer :: Update( fd ); bool Deleting; if( m_GProxy && m_Game->GetGameLoaded( ) ) Deleting = m_DeleteMe || m_Error; else Deleting = m_DeleteMe || m_Error || m_Socket->HasError( ) || !m_Socket->GetConnected( ); // try to find out why we're requesting deletion // in cases other than the ones covered here m_LeftReason should have been set when m_DeleteMe was set if( m_Error ){ m_Game->m_GHost->DenyIP( GetExternalIPString( ), 180000, "player error" ); m_Game->EventPlayerDisconnectPlayerError( this ); m_Socket->Reset( ); return Deleting; } if( m_Socket ) { if( m_Socket->HasError( ) ){ m_Game->EventPlayerDisconnectSocketError( this ); if( !m_GProxy ) m_Game->m_GHost->DenyIP( GetExternalIPString( ), 20000, "socket error" ); } else if( !m_Socket->GetConnected( ) ){ m_Game->EventPlayerDisconnectConnectionClosed( this ); if( !m_GProxy ) m_Game->m_GHost->DenyIP( GetExternalIPString( ), 30000, "connection closed" ); } } return Deleting; }