void CPotentialPlayer :: ProcessPackets( ) { if( !m_Socket ) return; // 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 ) { // the only packet we care about as a potential player is W3GS_REQJOIN, ignore everything else switch( Packet->GetID( ) ) { case CGameProtocol :: W3GS_REQJOIN: delete m_IncomingJoinPlayer; m_IncomingJoinPlayer = m_Protocol->RECEIVE_W3GS_REQJOIN( Packet->GetData( ) ); if( m_IncomingJoinPlayer && !m_Banned ) m_Game->EventPlayerJoined( this, m_IncomingJoinPlayer ); // don't continue looping because there may be more packets waiting and this parent class doesn't handle them // EventPlayerJoined creates the new player, NULLs the socket, and sets the delete flag on this object so it'll be deleted shortly // any unprocessed packets will be copied to the new CGamePlayer in the constructor or discarded if we get deleted because the game is full delete Packet; return; } } else if( Packet->GetPacketType( ) == GCBI_HEADER_CONSTANT ) { // if( Packet->GetID( ) == CGCBIProtocol :: GCBI_INIT && m_Game->m_GHost->IsLocal( GetExternalIPString( ) ) ) if( Packet->GetID( ) == CGCBIProtocol :: GCBI_INIT ) { delete m_IncomingGarenaUser; m_IncomingGarenaUser = m_Game->m_GHost->m_GCBIProtocol->RECEIVE_GCBI_INIT( Packet->GetData( ) ); string RoomID = UTIL_ToString(m_IncomingGarenaUser->GetRoomID( )); m_RoomName = m_Game->m_GHost->GetRoomName( string( RoomID.begin( ), RoomID.end( ) ) ); CONSOLE_Print( "[GCBI] Garena user detected; userid=" + UTIL_ToString( m_IncomingGarenaUser->GetUserID( ) ) + ", roomid=" + RoomID + ", RoomName=" + m_RoomName + ", experience=" + UTIL_ToString( m_IncomingGarenaUser->GetUserExp( ) ) + ", country=" + m_IncomingGarenaUser->GetCountryCode( ) ); } } delete Packet; } }
void CBNLSClient :: ProcessPackets( ) { while( !m_Packets.empty( ) ) { CCommandPacket *Packet = m_Packets.front( ); m_Packets.pop( ); if( Packet->GetID( ) == CBNLSProtocol :: BNLS_WARDEN ) { BYTEARRAY WardenResponse = m_Protocol->RECEIVE_BNLS_WARDEN( Packet->GetData( ) ); if( !WardenResponse.empty( ) ) m_WardenResponses.push( WardenResponse ); } delete Packet; } }
void CBNLSClient :: ProcessPackets( ) { while( !m_Packets.isEmpty( ) ) { CCommandPacket *Packet = m_Packets.front( ); m_Packets.dequeue( ); if( Packet->GetID( ) == CBNLSProtocol :: BNLS_WARDEN ) { QByteArray WardenResponse = m_Protocol->RECEIVE_BNLS_WARDEN( Packet->GetData( ) ); if( !WardenResponse.isEmpty( ) ) emit newWardenResponse(WardenResponse); } delete Packet; } }
void CPotentialPlayer :: ProcessPackets( ) { if( !m_Socket ) return; // 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 ) { // the only packet we care about as a potential player is W3GS_REQJOIN, ignore everything else switch( Packet->GetID( ) ) { case CGameProtocol :: W3GS_REQJOIN: delete m_IncomingJoinPlayer; m_IncomingJoinPlayer = m_Protocol->RECEIVE_W3GS_REQJOIN( Packet->GetData( ) ); if( m_IncomingJoinPlayer ) m_Game->EventPlayerJoined( this, m_IncomingJoinPlayer ); // don't continue looping because there may be more packets waiting and this parent class doesn't handle them // EventPlayerJoined creates the new player, NULLs the socket, and sets the delete flag on this object so it'll be deleted shortly // any unprocessed packets will be copied to the new CGamePlayer in the constructor or discarded if we get deleted because the game is full delete Packet; return; } } delete Packet; } }
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; } }
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 ) 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_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; } }
void CGProxy::processLocalPackets() { if(!m_LocalSocket || m_LocalSocket->state() != QTcpSocket::ConnectedState) return; while( !m_LocalPackets.empty( ) ) { CCommandPacket *Packet = m_LocalPackets.front( ); m_LocalPackets.pop_front( ); QByteArray Data = Packet->GetData( ); QDataStream ds(Data); ds.setByteOrder(QDataStream::LittleEndian); if( Packet->GetPacketType( ) == W3GS_HEADER_CONSTANT ) { if( Packet->GetID( ) == CGameProtocol :: W3GS_REQJOIN ) { if( Data.size( ) >= 20 ) { quint32 HostCounter; quint32 EntryKey; quint8 Unknown; quint16 ListenPort; quint32 PeerKey; QString Name; QByteArray Remainder; ds.skipRawData(4); ds >> HostCounter; ds >> EntryKey; ds >> Unknown; ds >> ListenPort; ds >> PeerKey; Name = CGameProtocol::ExtractString(ds); Remainder = QByteArray(Data.begin() + Name.size() + 20, Data.size() - (Name.size() + 20)); if(Remainder.size( ) == 18) { bool GameFound = false; for(QVector<CGameInfo*>::iterator i = games.begin( ); i != games.end( ); ++i) { if((*i)->GetUniqueGameID() == EntryKey) { m_RemoteSocket->reset(); m_RemoteSocket->setSocketOption(QAbstractSocket::LowDelayOption, 1); m_RemoteSocket->connectToHost((*i)->GetIP(), (*i)->GetPort()); if(!m_RemoteSocket->waitForConnected(3000)) { qDebug() << "[GPROXY] player requested to join an expired game. removing from list."; m_RequesterSocket->writeDatagram(m_GameProtocol->SEND_W3GS_DECREATEGAME((*i)->GetUniqueGameID()), QHostAddress::Broadcast, 6112); delete (*i); games.erase(i); break; } m_LastConnectionAttemptTime = GetTime(); m_RemoteServerIP = (*i)->GetIP(); m_GameIsReliable = (*i)->GetReliable(); m_GameStarted = false; QByteArray DataRewritten; QDataStream ds(&DataRewritten, QIODevice::ReadWrite); ds.setByteOrder(QDataStream::LittleEndian); ds << (quint8)W3GS_HEADER_CONSTANT; ds << (quint8)Packet->GetID(); ds << (quint16)0; ds << (*i)->GetHostCounter(); ds << (*i)->GetEntryKey(); ds << (quint8)Unknown; ds << (quint16)ListenPort; ds << (quint32)PeerKey; ds.writeRawData(Name.toUtf8(), Name.length()); ds << (quint8)0; ds.writeRawData(Remainder.data(), Remainder.length()); CGameProtocol::AssignLength(DataRewritten); Data = DataRewritten; GameFound = true; emit joinedGame((*i)->GetIP(), (*i)->GetGameName()); break; } } if(!GameFound) { qDebug() << "[GPROXY] local player requested unknown game (expired?) sending decreate."; m_RequesterSocket->writeDatagram(m_GameProtocol->SEND_W3GS_DECREATEGAME(EntryKey), QHostAddress::Broadcast, 6112); m_LocalSocket->disconnectFromHost(); } } else qDebug() << "[GPROXY] received invalid join request from local player (invalid remainder)"; } else qDebug() << "[GPROXY] received invalid join request from local player (too short)"; } else if(Packet->GetID( ) == CGameProtocol :: W3GS_LEAVEGAME)
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; } }
void CBNET :: ProcessPackets( ) { CIncomingGameHost* GameHost = NULL; CIncomingChatEvent* ChatEvent = NULL; BYTEARRAY WardenData; vector<CIncomingFriendList*> Friends; vector<CIncomingClanList*> Clans; // process all the received packets in the m_Packets queue // this normally means sending some kind of response while( !m_Packets.empty() ) { CCommandPacket* Packet = m_Packets.front(); m_Packets.pop(); if( Packet->GetPacketType() == BNET_HEADER_CONSTANT ) { switch( Packet->GetID() ) { case CBNETProtocol :: SID_NULL: // warning: we do not respond to NULL packets with a NULL packet of our own // this is because PVPGN servers are programmed to respond to NULL packets so it will create a vicious cycle of useless traffic // official battle.net servers do not respond to NULL packets m_Protocol->RECEIVE_SID_NULL( Packet->GetData() ); break; case CBNETProtocol :: SID_GETADVLISTEX: GameHost = m_Protocol->RECEIVE_SID_GETADVLISTEX( Packet->GetData() ); if( GameHost ) cout << "[BNET: " << m_ServerAlias << "] joining game [" << GameHost->GetGameName() << "]\n"; delete GameHost; GameHost = NULL; break; case CBNETProtocol :: SID_ENTERCHAT: if( m_Protocol->RECEIVE_SID_ENTERCHAT( Packet->GetData() ) ) { cout << "[BNET: " << m_ServerAlias << "] joining channel [" << m_FirstChannel << "]\n"; m_InChat = true; m_Socket->PutBytes( m_Protocol->SEND_SID_JOINCHANNEL(m_FirstChannel) ); } break; case CBNETProtocol :: SID_CHATEVENT: ChatEvent = m_Protocol->RECEIVE_SID_CHATEVENT( Packet->GetData() ); if( ChatEvent ) ProcessChatEvent( ChatEvent ); delete ChatEvent; ChatEvent = NULL; break; case CBNETProtocol :: SID_CHECKAD: m_Protocol->RECEIVE_SID_CHECKAD( Packet->GetData() ); break; case CBNETProtocol :: SID_STARTADVEX3: if( m_Protocol->RECEIVE_SID_STARTADVEX3( Packet->GetData() ) ) { m_InChat = false; m_GHost->EventBNETGameRefreshed( this ); } else { cout << "[BNET: " << m_ServerAlias << "] startadvex3 failed\n"; m_GHost->EventBNETGameRefreshFailed( this ); } break; case CBNETProtocol :: SID_PING: m_Socket->PutBytes( m_Protocol->SEND_SID_PING( m_Protocol->RECEIVE_SID_PING( Packet->GetData() ) ) ); break; case CBNETProtocol :: SID_AUTH_INFO: if( m_Protocol->RECEIVE_SID_AUTH_INFO( Packet->GetData() ) ) { if( m_BNCSUtil->HELP_SID_AUTH_CHECK( m_GHost->m_TFT, m_GHost->m_Warcraft3Path, m_CDKeyROC, m_CDKeyTFT, m_Protocol->GetValueStringFormulaString(), m_Protocol->GetIX86VerFileNameString(), m_Protocol->GetClientToken(), m_Protocol->GetServerToken() ) ) { // override the exe information generated by bncsutil if specified in the config file // apparently this is useful for pvpgn users if( m_EXEVersion.size() == 4 ) { cout << "[BNET: " << m_ServerAlias << "] using custom exe version bnet_custom_exeversion = " << m_EXEVersion[0] << " " << m_EXEVersion[1] << " " + m_EXEVersion[2] << " " << m_EXEVersion[3] << '\n'; m_BNCSUtil->SetEXEVersion( m_EXEVersion ); } if( m_EXEVersionHash.size() == 4 ) { cout << "[BNET: " << m_ServerAlias << "] using custom exe version hash bnet_custom_exeversionhash = " << m_EXEVersionHash[0] << " " << m_EXEVersionHash[1] << " " << m_EXEVersionHash[2] << " " << m_EXEVersionHash[3] << '\n'; m_BNCSUtil->SetEXEVersionHash( m_EXEVersionHash ); } if( m_GHost->m_TFT ) cout << "[BNET: " << m_ServerAlias << "] attempting to auth as Warcraft III: The Frozen Throne\n"; else cout << "[BNET: " << m_ServerAlias << "] attempting to auth as Warcraft III: Reign of Chaos\n"; m_Socket->PutBytes( m_Protocol->SEND_SID_AUTH_CHECK( m_GHost->m_TFT, m_Protocol->GetClientToken(), m_BNCSUtil->GetEXEVersion(), m_BNCSUtil->GetEXEVersionHash(), m_BNCSUtil->GetKeyInfoROC(), m_BNCSUtil->GetKeyInfoTFT(), m_BNCSUtil->GetEXEInfo(), "GHost" ) ); } else { cout << "[BNET: " << m_ServerAlias << "] logon failed - bncsutil key hash failed (check your Warcraft 3 path and cd keys), disconnecting\n"; m_Socket->Disconnect( ); delete Packet; return; } } break; case CBNETProtocol :: SID_AUTH_CHECK: if( m_Protocol->RECEIVE_SID_AUTH_CHECK( Packet->GetData() ) ) { // cd keys accepted cout << "[BNET: " << m_ServerAlias << "] cd keys accepted\n"; m_BNCSUtil->HELP_SID_AUTH_ACCOUNTLOGON( ); m_Socket->PutBytes( m_Protocol->SEND_SID_AUTH_ACCOUNTLOGON(m_BNCSUtil->GetClientKey(), m_UserName) ); } else { // cd keys not accepted switch( UTIL_ByteArrayToUInt32( m_Protocol->GetKeyState( ), false ) ) { case CBNETProtocol :: KR_ROC_KEY_IN_USE: cout << "[BNET: " << m_ServerAlias << "] logon failed - ROC CD key in use by user [" << m_Protocol->GetKeyStateDescription() << "], disconnecting\n"; break; case CBNETProtocol :: KR_TFT_KEY_IN_USE: cout << "[BNET: " << m_ServerAlias << "] logon failed - TFT CD key in use by user [" + m_Protocol->GetKeyStateDescription() << "], disconnecting\n"; break; case CBNETProtocol :: KR_OLD_GAME_VERSION: cout << "[BNET: " << m_ServerAlias << "] logon failed - game version is too old, disconnecting\n"; break; case CBNETProtocol :: KR_INVALID_VERSION: cout << "[BNET: " << m_ServerAlias << "] logon failed - game version is invalid, disconnecting\n"; break; default: cout << "[BNET: " << m_ServerAlias << "] logon failed - cd keys not accepted, disconnecting\n"; break; } m_Socket->Disconnect( ); delete Packet; return; } break; case CBNETProtocol :: SID_AUTH_ACCOUNTLOGON: if( m_Protocol->RECEIVE_SID_AUTH_ACCOUNTLOGON( Packet->GetData( ) ) ) { cout << "[BNET: " << m_ServerAlias << "] username [" << m_UserName << "] accepted\n"; if( m_PasswordHashType == "pvpgn" ) { // pvpgn logon cout << "[BNET: " << m_ServerAlias << "] using pvpgn logon type (for pvpgn servers only)\n"; m_BNCSUtil->HELP_PvPGNPasswordHash( m_UserPassword ); m_Socket->PutBytes( m_Protocol->SEND_SID_AUTH_ACCOUNTLOGONPROOF( m_BNCSUtil->GetPvPGNPasswordHash() ) ); } else { // battle.net logon cout << "[BNET: " << m_ServerAlias << "] using battle.net logon type (for official battle.net servers only)\n"; m_BNCSUtil->HELP_SID_AUTH_ACCOUNTLOGONPROOF( m_Protocol->GetSalt( ), m_Protocol->GetServerPublicKey() ); m_Socket->PutBytes( m_Protocol->SEND_SID_AUTH_ACCOUNTLOGONPROOF( m_BNCSUtil->GetM1() ) ); } } else { cout << "[BNET: " << m_ServerAlias << "] logon failed - invalid username, disconnecting\n"; m_Socket->Disconnect( ); delete Packet; return; } break; case CBNETProtocol :: SID_AUTH_ACCOUNTLOGONPROOF: if( m_Protocol->RECEIVE_SID_AUTH_ACCOUNTLOGONPROOF( Packet->GetData() ) ) { // logon successful cout << "[BNET: " << m_ServerAlias << "] logon successful\n"; m_LoggedIn = true; m_GHost->EventBNETLoggedIn( this ); m_Socket->PutBytes( m_Protocol->SEND_SID_NETGAMEPORT(m_GHost->m_HostPort) ); m_Socket->PutBytes( m_Protocol->SEND_SID_ENTERCHAT() ); m_Socket->PutBytes( m_Protocol->SEND_SID_FRIENDSLIST() ); m_Socket->PutBytes( m_Protocol->SEND_SID_CLANMEMBERLIST() ); } else { cout << "[BNET: " << m_ServerAlias << "] logon failed - invalid password, disconnecting\n"; // try to figure out if the user might be using the wrong logon type since too many people are confused by this string Server = m_Server; transform( Server.begin( ), Server.end( ), Server.begin( ), (int(*)(int))(int(*)(int))tolower ); if( m_PasswordHashType == "pvpgn" && ( Server == "useast.battle.net" || Server == "uswest.battle.net" || Server == "asia.battle.net" || Server == "europe.battle.net" ) ) cout << "[BNET: " << m_ServerAlias << "] it looks like you're trying to connect to a battle.net server using a pvpgn logon type, check your config file's \"battle.net custom data\" section\n"; else if( m_PasswordHashType != "pvpgn" && ( Server != "useast.battle.net" && Server != "uswest.battle.net" && Server != "asia.battle.net" && Server != "europe.battle.net" ) ) cout << "[BNET: " << m_ServerAlias << "] it looks like you're trying to connect to a pvpgn server using a battle.net logon type, check your config file's \"battle.net custom data\" section\n"; m_Socket->Disconnect( ); delete Packet; return; } break; case CBNETProtocol :: SID_FRIENDSLIST: Friends = m_Protocol->RECEIVE_SID_FRIENDSLIST( Packet->GetData() ); for( vector<CIncomingFriendList*>::iterator i = m_Friends.begin(); i != m_Friends.end(); ++i ) delete *i; m_Friends = Friends; break; case CBNETProtocol :: SID_CLANMEMBERLIST: vector<CIncomingClanList *> Clans = m_Protocol->RECEIVE_SID_CLANMEMBERLIST( Packet->GetData( ) ); for( vector<CIncomingClanList*>::iterator i = m_Clans.begin(); i != m_Clans.end(); ++i ) delete *i; m_Clans = Clans; break; } } delete Packet; } }