Exemple #1
0
uint32_t CGameProtocol :: RECEIVE_W3GS_OUTGOING_KEEPALIVE( BYTEARRAY data )
{
	// DEBUG_Print( "RECEIVED W3GS_OUTGOING_KEEPALIVE" );
	// DEBUG_Print( data );

	// 2 bytes					-> Header
	// 2 bytes					-> Length
	// 1 byte					-> ???
	// 4 bytes					-> CheckSum??? (used in replays)

	if( ValidateLength( data ) && data.size( ) == 9 )
		return UTIL_ByteArrayToUInt32( data, false, 5 );

	return 0;
}
Exemple #2
0
CIncomingMapSize *CGameProtocol :: RECEIVE_W3GS_MAPSIZE( BYTEARRAY data, BYTEARRAY mapSize )
{
	// DEBUG_Print( "RECEIVED W3GS_MAPSIZE" );
	// DEBUG_Print( data );

	// 2 bytes					-> Header
	// 2 bytes					-> Length
	// 4 bytes					-> ???
	// 1 byte					-> SizeFlag (1 = have map, 3 = continue download)
	// 4 bytes					-> MapSize

	if( ValidateLength( data ) && data.size( ) >= 13 )
		return new CIncomingMapSize( data[8], UTIL_ByteArrayToUInt32( data, false, 9 ) );

	return NULL;
}
Exemple #3
0
uint32_t CGameProtocol :: RECEIVE_W3GS_MAPPARTOK( BYTEARRAY data )
{
	// DEBUG_Print( "RECEIVED W3GS_MAPPARTOK" );
	// DEBUG_Print( data );

	// 2 bytes					-> Header
	// 2 bytes					-> Length
	// 1 byte					-> SenderPID
	// 1 byte					-> ReceiverPID
	// 4 bytes					-> ???
	// 4 bytes					-> MapSize

	if( ValidateLength( data ) && data.size( ) >= 14 )
		return UTIL_ByteArrayToUInt32( data, false, 10 );

	return 0;
}
Exemple #4
0
uint32_t CGameProtocol :: RECEIVE_W3GS_PONG_TO_HOST( BYTEARRAY data )
{
	// DEBUG_Print( "RECEIVED W3GS_PONG_TO_HOST" );
	// DEBUG_Print( data );

	// 2 bytes					-> Header
	// 2 bytes					-> Length
	// 4 bytes					-> Pong

	// the pong value is just a copy of whatever was sent in SEND_W3GS_PING_FROM_HOST which was GetTicks( ) at the time of sending
	// so as long as we trust that the client isn't trying to fake us out and mess with the pong value we can find the round trip time by simple subtraction
	// (the subtraction is done elsewhere because the very first pong value seems to be 1 and we want to discard that one)

	if( ValidateLength( data ) && data.size( ) >= 8 )
		return UTIL_ByteArrayToUInt32( data, false, 4 );

	return 1;
}
bool CBNETProtocol :: RECEIVE_SID_AUTH_ACCOUNTLOGONPROOF( BYTEARRAY data )
{
	// DEBUG_Print( "RECEIVED SID_AUTH_ACCOUNTLOGONPROOF" );
	// DEBUG_Print( data );

	// 2 bytes					-> Header
	// 2 bytes					-> Length
	// 4 bytes					-> Status

	if( ValidateLength( data ) && data.size( ) >= 8 )
	{
		uint32_t Status = UTIL_ByteArrayToUInt32( BYTEARRAY( data.begin( ) + 4, data.begin( ) + 8 ), false );

		if( Status == 0 || Status == 0xE )
			return true;
	}

	return false;
}
bool CBNETProtocol :: RECEIVE_SID_LOGONRESPONSE( BYTEARRAY data )
{
	// DEBUG_Print( "RECEIVED SID_LOGONRESPONSE" );
	// DEBUG_Print( data );

	// 2 bytes					-> Header
	// 2 bytes					-> Length
	// 4 bytes					-> Status

	if( ValidateLength( data ) && data.size( ) >= 8 )
	{
		BYTEARRAY Status = BYTEARRAY( data.begin( ) + 4, data.begin( ) + 8 );

		if( UTIL_ByteArrayToUInt32( Status, false ) == 1 )
			return true;
	}

	return false;
}
CIncomingGameHost *CBNETProtocol :: RECEIVE_SID_GETADVLISTEX( BYTEARRAY data )
{
	// DEBUG_Print( "RECEIVED SID_GETADVLISTEX" );
	// DEBUG_Print( data );

	// 2 bytes					-> Header
	// 2 bytes					-> Length
	// 4 bytes					-> GamesFound
	// if( GamesFound > 0 )
	//		10 bytes			-> ???
	//		2 bytes				-> Port
	//		4 bytes				-> IP
	//		null term string	-> GameName
	//		2 bytes				-> ???
	//		8 bytes				-> HostCounter

	if( ValidateLength( data ) && data.size( ) >= 8 )
	{
		BYTEARRAY GamesFound = BYTEARRAY( data.begin( ) + 4, data.begin( ) + 8 );

		if( UTIL_ByteArrayToUInt32( GamesFound, false ) > 0 && data.size( ) >= 25 )
		{
			BYTEARRAY Port = BYTEARRAY( data.begin( ) + 18, data.begin( ) + 20 );
			BYTEARRAY IP = BYTEARRAY( data.begin( ) + 20, data.begin( ) + 24 );
			BYTEARRAY GameName = UTIL_ExtractCString( data, 24 );

			if( data.size( ) >= GameName.size( ) + 35 )
			{
				BYTEARRAY HostCounter;
				HostCounter.push_back( UTIL_ExtractHex( data, GameName.size( ) + 27, true ) );
				HostCounter.push_back( UTIL_ExtractHex( data, GameName.size( ) + 29, true ) );
				HostCounter.push_back( UTIL_ExtractHex( data, GameName.size( ) + 31, true ) );
				HostCounter.push_back( UTIL_ExtractHex( data, GameName.size( ) + 33, true ) );
				return new CIncomingGameHost(	IP,
												UTIL_ByteArrayToUInt16( Port, false ),
												string( GameName.begin( ), GameName.end( ) ),
												HostCounter );
			}
		}
	}

	return NULL;
}
bool CBNETProtocol :: RECEIVE_SID_AUTH_CHECK( BYTEARRAY data )
{
	// DEBUG_Print( "RECEIVED SID_AUTH_CHECK" );
	// DEBUG_Print( data );

	// 2 bytes					-> Header
	// 2 bytes					-> Length
	// 4 bytes					-> KeyState
	// null terminated string	-> KeyStateDescription

	if( ValidateLength( data ) && data.size( ) >= 9 )
	{
		m_KeyState = BYTEARRAY( data.begin( ) + 4, data.begin( ) + 8 );
		m_KeyStateDescription = UTIL_ExtractCString( data, 8 );

		if( UTIL_ByteArrayToUInt32( m_KeyState, false ) == KR_GOOD )
			return true;
	}

	return false;
}
Exemple #9
0
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;
    }
}
Exemple #10
0
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;
	}
}
CIncomingGameHost *CBNETProtocol :: RECEIVE_SID_GETADVLISTEX( BYTEARRAY data )
{
	// DEBUG_Print( "RECEIVED SID_GETADVLISTEX" );
	// DEBUG_Print( data );

	// 2 bytes					-> Header
	// 2 bytes					-> Length
	// 4 bytes					-> GamesFound
	// if( GamesFound > 0 )
	//		10 bytes			-> ???
	//		2 bytes				-> Port
	//		4 bytes				-> IP
	//		null term string	-> GameName
	//		2 bytes				-> ???
	//		8 bytes				-> HostCounter

	if( ValidateLength( data ) && data.size( ) >= 8 )
	{
		BYTEARRAY GamesFound = BYTEARRAY( data.begin( ) + 4, data.begin( ) + 8 );

/*
		if (UTIL_ByteArrayToUInt32( GamesFound, false )>1)
		{
			string sIP ="";
			string GN ="";
			uint32_t PR;
			uint32_t GF = UTIL_ByteArrayToUInt32( GamesFound, false );
			uint32_t Idx = 18;
			uint32_t Idx2 = 0;
			for (uint32_t i=0;i<GF;i++)
			{
				BYTEARRAY Port = BYTEARRAY( data.begin( ) + Idx, data.begin( ) + 2+Idx );
				BYTEARRAY IP = BYTEARRAY( data.begin( ) + 2+Idx, data.begin( ) + 6+Idx );
				BYTEARRAY GameName = UTIL_ExtractCString( data, 6+Idx );
				Idx2 = GameName.size( );
				Idx = Idx + Idx2+ 11;	
				GN = string( GameName.begin( ), GameName.end( ) );
				PR = UTIL_ByteArrayToUInt16( Port, false );
				CONSOLE_Print("[GHOST] Game "+UTIL_ToString(i)+ " "+ GN + " "+sIP+" "+UTIL_ToString(PR));
			}
		} 
		else
*/
		if( UTIL_ByteArrayToUInt32( GamesFound, false ) > 0 && data.size( ) >= 25 )
		{
			BYTEARRAY Port = BYTEARRAY( data.begin( ) + 18, data.begin( ) + 20 );
			BYTEARRAY IP = BYTEARRAY( data.begin( ) + 20, data.begin( ) + 24 );
			BYTEARRAY GameName = UTIL_ExtractCString( data, 24 );

			if( data.size( ) >= GameName.size( ) + 35 )
			{
				BYTEARRAY HostCounter;
				HostCounter.push_back( UTIL_ExtractHex( data, GameName.size( ) + 27, true ) );
				HostCounter.push_back( UTIL_ExtractHex( data, GameName.size( ) + 29, true ) );
				HostCounter.push_back( UTIL_ExtractHex( data, GameName.size( ) + 31, true ) );
				HostCounter.push_back( UTIL_ExtractHex( data, GameName.size( ) + 33, true ) );
				return new CIncomingGameHost(	IP,
												UTIL_ByteArrayToUInt16( Port, false ),
												string( GameName.begin( ), GameName.end( ) ),
												HostCounter );
			}
		}
	}

	return NULL;
}
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;
	}
}
Exemple #13
0
bool CGamePlayer :: Update( void *fd )
{
        uint32_t Time = GetTime( );
	
	// 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( ) && Time - 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_Aura->m_BNETs.begin( ); i != m_Game->m_Aura->m_BNETs.end( ); ++i )
		{
			if( (*i)->GetServer( ) == m_JoinedRealm )
			{
				if( m_Game->GetGameState( ) == GAME_PUBLIC || (*i)->GetPasswordHashType( ) == "pvpgn" )
					(*i)->QueueChatCommand( "/whois " + m_Name );
				else if( m_Game->GetGameState( ) == GAME_PRIVATE )
					(*i)->QueueChatCommand( m_Game->m_Aura->m_Language->SpoofCheckByReplying( ), m_Name, true, false );
			}
		}

		m_WhoisSent = true;
	}

	// check for socket timeouts
	// if we don't receive anything from a player for 35 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 && Time - m_Socket->GetLastRecv( ) >= 35 )
		m_Game->EventPlayerDisconnectTimedOut( this );

        // GProxy++ acks

	if( m_GProxy && Time - m_LastGProxyAckTime >= 10 )
	{
		if( m_Socket )
			m_Socket->PutBytes( m_Game->m_Aura->m_GPSProtocol->SEND_GPSS_ACK( m_TotalPacketsReceived ) );

		m_LastGProxyAckTime = Time;
	}

	// base class update

        if( m_Socket->GetConnected( ) )
            m_Socket->DoRecv( (fd_set *)fd );

	// extract as many packets as possible from the socket's receive buffer and process them

	string *RecvBuffer = m_Socket->GetBytes( );
	BYTEARRAY Bytes = UTIL_CreateByteArray( (unsigned char *)RecvBuffer->c_str( ), RecvBuffer->size( ) );

	// a packet is at least 4 bytes so loop as long as the buffer contains 4 bytes

	CIncomingAction *Action = NULL;
	CIncomingChatPlayer *ChatPlayer = NULL;
	CIncomingMapSize *MapSize = NULL;
	uint32_t CheckSum = 0, Pong = 0;

	while( Bytes.size( ) >= 4 )
	{
            if( Bytes[0] == W3GS_HEADER_CONSTANT )
            {
                // bytes 2 and 3 contain the length of the packet

                uint16_t Length = UTIL_ByteArrayToUInt16( Bytes, false, 2 );

                if( Length >= 4 )
                {
                        if( Bytes.size( ) >= Length )
                        {
                                // m_Packets.push( new CCommandPacket( Bytes[0], Bytes[1], BYTEARRAY( Bytes.begin( ), Bytes.begin( ) + Length ) ) );

                                    switch( Bytes[1] )
                                    {
                                    case CGameProtocol :: W3GS_LEAVEGAME:
                                            m_Game->EventPlayerLeft( this, m_Protocol->RECEIVE_W3GS_LEAVEGAME( BYTEARRAY( Bytes.begin( ), Bytes.begin( ) + Length ) ) );
                                            break;

                                    case CGameProtocol :: W3GS_GAMELOADED_SELF:
                                            if( m_Protocol->RECEIVE_W3GS_GAMELOADED_SELF( BYTEARRAY( Bytes.begin( ), Bytes.begin( ) + Length ) ) )
                                            {
                                                    if( !m_FinishedLoading )
                                                    {
                                                            m_FinishedLoading = true;
                                                            m_FinishedLoadingTicks = GetTicks( );
                                                            m_Game->EventPlayerLoaded( this );
                                                    }
                                            }

                                            break;

                                    case CGameProtocol :: W3GS_OUTGOING_ACTION:
                                            Action = m_Protocol->RECEIVE_W3GS_OUTGOING_ACTION( BYTEARRAY( Bytes.begin( ), Bytes.begin( ) + Length ), 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( BYTEARRAY( Bytes.begin( ), Bytes.begin( ) + Length ) );
                                            m_CheckSums.push( CheckSum );
                                            ++m_SyncCounter;
                                            m_Game->EventPlayerKeepAlive( );
                                            break;

                                    case CGameProtocol :: W3GS_CHAT_TO_HOST:
                                            ChatPlayer = m_Protocol->RECEIVE_W3GS_CHAT_TO_HOST( BYTEARRAY( Bytes.begin( ), Bytes.begin( ) + Length ) );

                                            if( ChatPlayer )
                                                    m_Game->EventPlayerChatToHost( this, ChatPlayer );

                                            delete ChatPlayer;
                                            ChatPlayer = NULL;
                                            break;

                                    case CGameProtocol :: W3GS_DROPREQ:
                                            if( !m_DropVote )
                                            {
                                                    m_DropVote = true;
                                                    m_Game->EventPlayerDropRequest( this );
                                            }

                                            break;

                                    case CGameProtocol :: W3GS_MAPSIZE:
                                            MapSize = m_Protocol->RECEIVE_W3GS_MAPSIZE( BYTEARRAY( Bytes.begin( ), Bytes.begin( ) + Length ), m_Game->m_Aura->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( BYTEARRAY( Bytes.begin( ), Bytes.begin( ) + Length ) );

                                            // 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->IsDownloading( ) )
                                                            {
                                                                    m_Pings.push_back( GetTicks( ) - Pong );

                                                                    if( m_Pings.size( ) > 20 )
                                                                            m_Pings.erase( m_Pings.begin( ) );
                                                            }
                                                    }
                                            }

                                            m_Game->EventPlayerPongToHost( this, Pong );
                                            break;
                                    }

                                    *RecvBuffer = RecvBuffer->substr( Length );
                                    Bytes = BYTEARRAY( Bytes.begin( ) + Length, Bytes.end( ) );
                            }
                            else
                                break;
                        }

                }
                else if( Bytes[0] == GPS_HEADER_CONSTANT )
                {
                    uint16_t Length = UTIL_ByteArrayToUInt16( Bytes, false, 2 );

                    if( Length >= 4 )
                    {
                        if( Bytes.size( ) >= Length )
                        {

                            BYTEARRAY Data = BYTEARRAY( Bytes.begin( ), Bytes.begin( ) + Length );

                            if( Bytes[1] == 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;
                                            }
                                    }
                            }
                            else if( Bytes[1] == CGPSProtocol :: GPS_INIT )
                            {
                                    if( m_Game->m_Aura->m_Reconnect )
                                    {
                                            m_GProxy = true;
                                            m_Socket->PutBytes( m_Game->m_Aura->m_GPSProtocol->SEND_GPSS_INIT( m_Game->m_Aura->m_ReconnectPort, m_PID, m_GProxyReconnectKey, m_Game->GetGProxyEmptyActions( ) ) );
                                            Print( "[GAME: " + m_Game->GetGameName( ) + "] player [" + m_Name + "] is using GProxy++" );
                                    }
                            }

                            *RecvBuffer = RecvBuffer->substr( Length );
                            Bytes = BYTEARRAY( Bytes.begin( ) + Length, Bytes.end( ) );
                        }
                        else
                            break;
                    }
            }
        }

        bool Deleting;

	if( m_GProxy && m_Game->GetGameLoaded( ) )
		Deleting = m_DeleteMe;
	else
		Deleting = m_DeleteMe || 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_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;
}