Beispiel #1
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;
}
Beispiel #2
0
BYTEARRAY CBNETProtocol :: SEND_SID_AUTH_ACCOUNTLOGONPROOF( BYTEARRAY clientPasswordProof )
{
	BYTEARRAY packet;

	if( clientPasswordProof.size( ) == 20 )
	{
		packet.push_back( BNET_HEADER_CONSTANT );					// BNET header constant
		packet.push_back( SID_AUTH_ACCOUNTLOGONPROOF );				// SID_AUTH_ACCOUNTLOGONPROOF
		packet.push_back( 0 );										// packet length will be assigned later
		packet.push_back( 0 );										// packet length will be assigned later
		UTIL_AppendByteArrayFast( packet, clientPasswordProof );	// Client Password Proof
		AssignLength( packet );
	}
	else
		cout << "[BNETPROTO] invalid parameters passed to SEND_SID_AUTH_ACCOUNTLOGON\n";

	return packet;
}
Beispiel #3
0
BYTEARRAY CBNETProtocol :: SEND_SID_PING( BYTEARRAY pingValue )
{
	BYTEARRAY packet;

	if( pingValue.size() == 4 )
	{
		packet.push_back( BNET_HEADER_CONSTANT );		// BNET header constant
		packet.push_back( SID_PING );					// SID_PING
		packet.push_back( 0 );							// packet length will be assigned later
		packet.push_back( 0 );							// packet length will be assigned later
		UTIL_AppendByteArrayFast( packet, pingValue );	// Ping Value
		AssignLength( packet );
	}
	else
		cout << "[BNETPROTO] invalid parameters passed to SEND_SID_PING\n";

	return packet;
}
Beispiel #4
0
BYTEARRAY CBNETProtocol :: SEND_SID_AUTH_ACCOUNTLOGON( BYTEARRAY clientPublicKey, string accountName )
{
	BYTEARRAY packet;

	if( clientPublicKey.size( ) == 32 )
	{
		packet.push_back( BNET_HEADER_CONSTANT );				// BNET header constant
		packet.push_back( SID_AUTH_ACCOUNTLOGON );				// SID_AUTH_ACCOUNTLOGON
		packet.push_back( 0 );									// packet length will be assigned later
		packet.push_back( 0 );									// packet length will be assigned later
		UTIL_AppendByteArrayFast( packet, clientPublicKey );	// Client Key
		UTIL_AppendByteArrayFast( packet, accountName );		// Account Name
		AssignLength( packet );
	}
	else
		cout << "[BNETPROTO] invalid parameters passed to SEND_SID_AUTH_ACCOUNTLOGON\n";

	return packet;
}
Beispiel #5
0
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;
}
Beispiel #6
0
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;
}
Beispiel #7
0
bool CGameProtocol :: RECEIVE_W3GS_GAMEINFO ( BYTEARRAY data, unsigned char war3Version)
{
	uint32_t ProductID	= 1462982736;	// "W3XP"
	uint32_t Version = war3Version;

	if( ValidateLength( data ) && data.size( ) >= 16 )
	{
		if( UTIL_ByteArrayToUInt32( data, false, 4 ) == ProductID )
		{
			if( UTIL_ByteArrayToUInt32( data, false, 8 ) == Version )
			{
				if( UTIL_ByteArrayToUInt32( data, false, 12 ) == 0 )
					return true;
			}
		}
	}

	return false;

}
Beispiel #8
0
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;
}
string CPotentialPlayer :: GetExternalIPString( )
{
	BYTEARRAY IP;
	string EIP;
	if( m_Socket )
	{
		bool local=m_LAN;
		if (!m_LANSet)
		{
			IP=	m_Socket->GetIP( );
			if (IP.size()>=2)
			{
				if (IP[0]==10 && IP[1]==0)
					local=true;
				if (IP[0]==10 && IP[1]==1)
					local=true;
				if (IP[0]==192 && IP[1]==168)
					local=true;
				if (IP[0]==169 && IP[1]==254)
					local=true;
				if (IP[0]==8 && IP[1]==0)
					local=true;
				if (IP[0]==5)
					local=true;
			}
			if (UTIL_IsLocalIP(IP, m_Game->m_GHost->m_LocalAddresses))
				local = true;
			m_LANSet = true;
			m_LAN = local;
		}
		EIP=m_Socket->GetIPString( );
		if (local && !m_Game->m_Config->m_ExternalIP.empty())
		{
			EIP = m_Game->m_Config->m_ExternalIP;
		}
		return EIP;
	}

	return string( );
}
BYTEARRAY CBNETProtocol :: SEND_SID_PING( BYTEARRAY pingValue )
{
	BYTEARRAY packet;

	if( pingValue.size( ) == 4 )
	{
		packet.push_back( BNET_HEADER_CONSTANT );		// BNET header constant
		packet.push_back( SID_PING );					// SID_PING
		packet.push_back( 0 );							// packet length will be assigned later
		packet.push_back( 0 );							// packet length will be assigned later
		UTIL_AppendByteArrayFast( packet, pingValue );	// Ping Value
		AssignLength( packet );
	}
	else
	{
		CONSOLE_Print( "[BNETPROTO] invalid parameters passed to SEND_SID_PING" );
		forward(new CFwdData(FWD_GENERAL, "Invalid parameters passed to SEND_SID_PING", 6, 0));
	}

	// DEBUG_Print( "SENT SID_PING" );
	// DEBUG_Print( packet );
	return packet;
}
Beispiel #11
0
void CReplay :: AddTimeSlot2( queue<CIncomingAction *> actions )
{
	BYTEARRAY Block;
	Block.push_back( REPLAY_TIMESLOT2 );
	UTIL_AppendByteArray( Block, (uint16_t)0, false );
	UTIL_AppendByteArray( Block, (uint16_t)0, false );

	while( !actions.empty( ) )
	{
		CIncomingAction *Action = actions.front( );
		actions.pop( );
		Block.push_back( Action->GetPID( ) );
		UTIL_AppendByteArray( Block, (uint16_t)Action->GetAction( )->size( ), false );
		UTIL_AppendByteArrayFast( Block, *Action->GetAction( ) );
	}

	// assign length

	BYTEARRAY LengthBytes = UTIL_CreateByteArray( (uint16_t)( Block.size( ) - 3 ), false );
	Block[1] = LengthBytes[0];
	Block[2] = LengthBytes[1];
	m_CompiledBlocks += string( Block.begin( ), Block.end( ) );
}
BYTEARRAY CBNETProtocol :: SEND_SID_AUTH_ACCOUNTLOGONPROOF( BYTEARRAY clientPasswordProof )
{
	BYTEARRAY packet;

	if( clientPasswordProof.size( ) == 20 )
	{
		packet.push_back( BNET_HEADER_CONSTANT );					// BNET header constant
		packet.push_back( SID_AUTH_ACCOUNTLOGONPROOF );				// SID_AUTH_ACCOUNTLOGONPROOF
		packet.push_back( 0 );										// packet length will be assigned later
		packet.push_back( 0 );										// packet length will be assigned later
		UTIL_AppendByteArrayFast( packet, clientPasswordProof );	// Client Password Proof
		AssignLength( packet );
	}
	else
	{
		CONSOLE_Print( "[BNETPROTO] invalid parameters passed to SEND_SID_AUTH_ACCOUNTLOGON" );
		forward(new CFwdData(FWD_GENERAL, "Invalid parameters passed to SEND_SID_AUTH_ACCOUNTLOGON", 6, 0));
	}

	// DEBUG_Print( "SENT SID_AUTH_ACCOUNTLOGONPROOF" );
	// DEBUG_Print( packet );
	return packet;
}
BYTEARRAY CBNETProtocol :: SEND_SID_AUTH_ACCOUNTLOGON( BYTEARRAY clientPublicKey, string accountName )
{
	BYTEARRAY packet;

	if( clientPublicKey.size( ) == 32 )
	{
		packet.push_back( BNET_HEADER_CONSTANT );				// BNET header constant
		packet.push_back( SID_AUTH_ACCOUNTLOGON );				// SID_AUTH_ACCOUNTLOGON
		packet.push_back( 0 );									// packet length will be assigned later
		packet.push_back( 0 );									// packet length will be assigned later
		UTIL_AppendByteArrayFast( packet, clientPublicKey );	// Client Key
		UTIL_AppendByteArrayFast( packet, accountName );		// Account Name
		AssignLength( packet );
	}
	else
	{
		CONSOLE_Print( "[BNETPROTO] invalid parameters passed to SEND_SID_AUTH_ACCOUNTLOGON" );
		forward(new CFwdData(FWD_GENERAL, "Invalid parameters passed to SEND_SID_AUTH_ACCOUNTLOGON", 6, 0));
	}

	// DEBUG_Print( "SENT SID_AUTH_ACCOUNTLOGON" );
	// DEBUG_Print( packet );
	return packet;
}
Beispiel #14
0
BYTEARRAY CGameProtocol :: SEND_W3GS_CHAT_FROM_HOST( unsigned char fromPID, BYTEARRAY toPIDs, unsigned char flag, BYTEARRAY flagExtra, string message )
{
	BYTEARRAY packet;

	if( !toPIDs.empty( ) && !message.empty( ) && message.size( ) < 255 )
	{
		packet.push_back( W3GS_HEADER_CONSTANT );		// W3GS header constant
		packet.push_back( W3GS_CHAT_FROM_HOST );		// W3GS_CHAT_FROM_HOST
		packet.push_back( 0 );							// packet length will be assigned later
		packet.push_back( 0 );							// packet length will be assigned later
		packet.push_back( toPIDs.size( ) );				// number of receivers
		UTIL_AppendByteArrayFast( packet, toPIDs );		// receivers
		packet.push_back( fromPID );					// sender
		packet.push_back( flag );						// flag
		UTIL_AppendByteArrayFast( packet, flagExtra );	// extra flag
		UTIL_AppendByteArrayFast( packet, message );	// message
		AssignLength( packet );
	}
	else
		cout << "[GAMEPROTO] invalid parameters passed to SEND_W3GS_CHAT_FROM_HOST\n";

	
	return packet;
}
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;
	}
}
Beispiel #16
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;
	}
}
Beispiel #17
0
bool CAura::Update()
{
  uint32_t NumFDs = 0;

  // take every socket we own and throw it in one giant select statement so we can block on all sockets

  int32_t nfds = 0;
  fd_set fd, send_fd;
  FD_ZERO(&fd);
  FD_ZERO(&send_fd);

  // 1. the current game's server and player sockets

  if (m_CurrentGame)
    NumFDs += m_CurrentGame->SetFD(&fd, &send_fd, &nfds);

  // 2. all running games' player sockets

  for (auto & game : m_Games)
    NumFDs += game->SetFD(&fd, &send_fd, &nfds);

  // 3. all battle.net sockets

  for (auto & bnet : m_BNETs)
    NumFDs += bnet->SetFD(&fd, &send_fd, &nfds);

  // 4. irc socket

  if (m_IRC)
    NumFDs += m_IRC->SetFD(&fd, &send_fd, &nfds);

  // 5. reconnect socket

  if (m_ReconnectSocket->HasError())
  {
    Print("[AURA] GProxy++ reconnect listener error (" + m_ReconnectSocket->GetErrorString() + ")");
    return true;
  }
  else
  {
    m_ReconnectSocket->SetFD(&fd, &send_fd, &nfds);
    ++NumFDs;
  }

  // 6. reconnect sockets

  for (auto & socket : m_ReconnectSockets)
  {
    socket->SetFD(&fd, &send_fd, &nfds);
    ++NumFDs;
  }

  // before we call select we need to determine how long to block for
  // 50 ms is the hard maximum

  int64_t usecBlock = 50000;

  for (auto & game : m_Games)
  {
    if (game->GetNextTimedActionTicks() * 1000 < usecBlock)
      usecBlock = game->GetNextTimedActionTicks() * 1000;
  }

  struct timeval tv;
  tv.tv_sec = 0;
  tv.tv_usec = static_cast<long int>(usecBlock);

  struct timeval send_tv;
  send_tv.tv_sec = 0;
  send_tv.tv_usec = 0;

#ifdef WIN32
  select(1, &fd, nullptr, nullptr, &tv);
  select(1, nullptr, &send_fd, nullptr, &send_tv);
#else
  select(nfds + 1, &fd, nullptr, nullptr, &tv);
  select(nfds + 1, nullptr, &send_fd, nullptr, &send_tv);
#endif

  if (NumFDs == 0)
  {
    // we don't have any sockets (i.e. we aren't connected to battle.net and irc maybe due to a lost connection and there aren't any games running)
    // select will return immediately and we'll chew up the CPU if we let it loop so just sleep for 200ms to kill some time

    MILLISLEEP(200);
  }

  bool Exit = false;

  // update running games

  for (auto i = begin(m_Games); i != end(m_Games);)
  {
    if ((*i)->Update(&fd, &send_fd))
    {
      Print2("[AURA] deleting game [" + (*i)->GetGameName() + "]");
      EventGameDeleted(*i);
      delete *i;
      i = m_Games.erase(i);
    }
    else
    {
      (*i)->UpdatePost(&send_fd);
      ++i;
    }
  }

  // update current game

  if (m_CurrentGame)
  {
    if (m_CurrentGame->Update(&fd, &send_fd))
    {
      Print2("[AURA] deleting current game [" + m_CurrentGame->GetGameName() + "]");
      delete m_CurrentGame;
      m_CurrentGame = nullptr;

      for (auto & bnet : m_BNETs)
      {
        bnet->QueueGameUncreate();
        bnet->QueueEnterChat();
      }
    }
    else if (m_CurrentGame)
      m_CurrentGame->UpdatePost(&send_fd);
  }

  // update battle.net connections

  for (auto & bnet : m_BNETs)
  {
    if (bnet->Update(&fd, &send_fd))
      Exit = true;
  }

  // update irc

  if (m_IRC && m_IRC->Update(&fd, &send_fd))
    Exit = true;

  // update GProxy++ reliable reconnect sockets

  CTCPSocket *NewSocket = m_ReconnectSocket->Accept(&fd);

  if (NewSocket)
    m_ReconnectSockets.push_back(NewSocket);

  for (auto i = begin(m_ReconnectSockets); i != end(m_ReconnectSockets);)
  {
    if ((*i)->HasError() || !(*i)->GetConnected() || GetTime() - (*i)->GetLastRecv() >= 10)
    {
      delete *i;
      i = m_ReconnectSockets.erase(i);
      continue;
    }

    (*i)->DoRecv(&fd);
    string *RecvBuffer = (*i)->GetBytes();
    const BYTEARRAY Bytes = CreateByteArray((uint8_t *) RecvBuffer->c_str(), RecvBuffer->size());

    // a packet is at least 4 bytes

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

        const uint16_t Length = (uint16_t)(Bytes[3] << 8 | Bytes[2]);

        if (Bytes.size() >= Length)
        {
          if (Bytes[1] == CGPSProtocol::GPS_RECONNECT && Length == 13)
          {
            const uint32_t ReconnectKey = ByteArrayToUInt32(Bytes, false, 5);
            const uint32_t LastPacket = ByteArrayToUInt32(Bytes, false, 9);

            // look for a matching player in a running game

            CGamePlayer *Match = nullptr;

            for (auto & game : m_Games)
            {
              if (game->GetGameLoaded())
              {
                CGamePlayer *Player = game->GetPlayerFromPID(Bytes[4]);

                if (Player && Player->GetGProxy() && Player->GetGProxyReconnectKey() == ReconnectKey)
                {
                  Match = Player;
                  break;
                }
              }
            }

            if (Match)
            {
              // reconnect successful!

              *RecvBuffer = RecvBuffer->substr(Length);
              Match->EventGProxyReconnect(*i, LastPacket);
              i = m_ReconnectSockets.erase(i);
              continue;
            }
            else
            {
              (*i)->PutBytes(m_GPSProtocol->SEND_GPSS_REJECT(REJECTGPS_NOTFOUND));
              (*i)->DoSend(&send_fd);
              delete *i;
              i = m_ReconnectSockets.erase(i);
              continue;
            }
          }
          else
          {
            (*i)->PutBytes(m_GPSProtocol->SEND_GPSS_REJECT(REJECTGPS_INVALID));
            (*i)->DoSend(&send_fd);
            delete *i;
            i = m_ReconnectSockets.erase(i);
            continue;
          }
        }
        else
        {
          (*i)->PutBytes(m_GPSProtocol->SEND_GPSS_REJECT(REJECTGPS_INVALID));
          (*i)->DoSend(&send_fd);
          delete *i;
          i = m_ReconnectSockets.erase(i);
          continue;
        }
      }
      else
      {
        (*i)->PutBytes(m_GPSProtocol->SEND_GPSS_REJECT(REJECTGPS_INVALID));
        (*i)->DoSend(&send_fd);
        delete *i;
        i = m_ReconnectSockets.erase(i);
        continue;
      }
    }

    (*i)->DoSend(&send_fd);
    ++i;
  }

  return m_Exiting || Exit;
}
Beispiel #18
0
void CReplay :: BuildReplay( string gameName, string statString )
{
	CONSOLE_Print( "[REPLAY] building replay" );

	uint32_t LanguageID = 0x0012F8B0;

	BYTEARRAY Replay;
	Replay.push_back( 16 );															// Unknown (4.0)
	Replay.push_back( 1 );															// Unknown (4.0)
	Replay.push_back( 0 );															// Unknown (4.0)
	Replay.push_back( 0 );															// Unknown (4.0)
	Replay.push_back( 0 );															// Host RecordID (4.1)
	Replay.push_back( m_HostPID );													// Host PlayerID (4.1)
	UTIL_AppendByteArray( Replay, m_HostName );										// Host PlayerName (4.1)
	Replay.push_back( 1 );															// Host AdditionalSize (4.1)
	Replay.push_back( 0 );															// Host AdditionalData (4.1)
	UTIL_AppendByteArray( Replay, gameName );										// GameName (4.2)
	Replay.push_back( 0 );															// Null (4.0)
	UTIL_AppendByteArray( Replay, statString );										// StatString (4.3)
	UTIL_AppendByteArray( Replay, (uint32_t)m_Slots.size( ), false );				// PlayerCount (4.6)
	Replay.push_back( m_MapGameType );												// GameType (4.7)
	Replay.push_back( 32 );															// GameType (4.7)
	Replay.push_back( 73 );															// GameType (4.7)
	Replay.push_back( 0 );															// GameType (4.7)
	UTIL_AppendByteArray( Replay, LanguageID, false );								// LanguageID (4.8)

	// PlayerList (4.9)

	for( vector<ReplayPlayer> :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ )
	{
		if( (*i).first != m_HostPID )
		{
			Replay.push_back( 22 );													// Player RecordID (4.1)
			Replay.push_back( (*i).first );											// Player PlayerID (4.1)
			UTIL_AppendByteArray( Replay, (*i).second );							// Player PlayerName (4.1)
			Replay.push_back( 1 );													// Player AdditionalSize (4.1)
			Replay.push_back( 0 );													// Player AdditionalData (4.1)
			UTIL_AppendByteArray( Replay, (uint32_t)0, false );						// Unknown
		}
	}

	// GameStartRecord (4.10)

	Replay.push_back( 25 );															// RecordID (4.10)
	UTIL_AppendByteArray( Replay, (uint16_t)( 7 + m_Slots.size( ) * 9 ), false );	// Size (4.10)
	Replay.push_back( m_Slots.size( ) );											// NumSlots (4.10)

	for( unsigned char i = 0; i < m_Slots.size( ); i++ )
		UTIL_AppendByteArray( Replay, m_Slots[i].GetByteArray( ) );

	UTIL_AppendByteArray( Replay, m_RandomSeed, false );							// RandomSeed (4.10)
	Replay.push_back( m_SelectMode );												// SelectMode (4.10)
	Replay.push_back( m_StartSpotCount );											// StartSpotCount (4.10)

	// ReplayData (5.0)

	Replay.push_back( REPLAY_FIRSTSTARTBLOCK );
	UTIL_AppendByteArray( Replay, (uint32_t)1, false );
	Replay.push_back( REPLAY_SECONDSTARTBLOCK );
	UTIL_AppendByteArray( Replay, (uint32_t)1, false );

	// leavers during loading need to be stored between the second and third start blocks

	while( !m_LoadingBlocks.empty( ) )
	{
		UTIL_AppendByteArray( Replay, m_LoadingBlocks.front( ) );
		m_LoadingBlocks.pop( );
	}

	Replay.push_back( REPLAY_THIRDSTARTBLOCK );
	UTIL_AppendByteArray( Replay, (uint32_t)1, false );

	// initialize replay length to zero
	// we'll accumulate the replay length as we iterate through the timeslots
	// this is necessary because we might be discarding some timeslots due to not enough checksums and the replay length needs to be accurate

	m_ReplayLength = 0;
	uint32_t TimeSlotsDiscarded = 0;

	while( !m_Blocks.empty( ) )
	{
		BYTEARRAY Block = m_Blocks.front( );
		m_Blocks.pop( );

		if( Block.size( ) >= 5 && Block[0] == REPLAY_TIMESLOT )
		{
			if( m_CheckSums.empty( ) )
			{
				TimeSlotsDiscarded++;
				continue;
			}

			// append timeslot

			UTIL_AppendByteArray( Replay, Block );

			// append checksum

			BYTEARRAY CheckSum;
			CheckSum.push_back( REPLAY_CHECKSUM );
			CheckSum.push_back( 4 );
			UTIL_AppendByteArray( CheckSum, m_CheckSums.front( ), false );
			m_CheckSums.pop( );
			UTIL_AppendByteArray( Replay, CheckSum );

			// accumulate replay length

			m_ReplayLength += UTIL_ByteArrayToUInt16( Block, false, 3 );
		}
		else
			UTIL_AppendByteArray( Replay, Block );
	}

	if( TimeSlotsDiscarded > 0 )
		CONSOLE_Print( "[REPLAY] ran out of checksums, discarded " + UTIL_ToString( TimeSlotsDiscarded ) + " timeslots" );

	// done

	m_Decompressed = string( Replay.begin( ), Replay.end( ) );
}
Beispiel #19
0
void CMap :: Load( CConfig *CFG, string nCFGFile )
{
	m_Valid = true;
	m_CFGFile = nCFGFile;
	m_GHost->UDPChatSend("|cfg "+nCFGFile);

	// load the map data

	m_MapLocalPath = CFG->GetString( "map_localpath", string( ) );
	m_MapData.clear( );

	if( !m_MapLocalPath.empty( ) )
		m_MapData = UTIL_FileRead( m_GHost->m_MapPath + m_MapLocalPath );

	// load the map MPQ

	string MapMPQFileName = m_GHost->m_MapPath + m_MapLocalPath;
	HANDLE MapMPQ;
	bool MapMPQReady = false;

	if( SFileOpenArchive( MapMPQFileName.c_str( ), 0, MPQ_OPEN_FORCE_MPQ_V1, &MapMPQ ) )
	{
		CONSOLE_Print( "[MAP] loading MPQ file [" + MapMPQFileName + "]" );
		MapMPQReady = true;
	}
	else
		CONSOLE_Print( "[MAP] warning - unable to load MPQ file [" + MapMPQFileName + "]" );

	// try to calculate map_size, map_info, map_crc, map_sha1

	BYTEARRAY MapSize;
	BYTEARRAY MapInfo;
	BYTEARRAY MapCRC;
	BYTEARRAY MapSHA1;

	if( !m_MapData.empty( ) )
	{
		m_GHost->m_SHA->Reset( );

		// calculate map_size

		MapSize = UTIL_CreateByteArray( (uint32_t)m_MapData.size( ), false );
		CONSOLE_Print( "[MAP] calculated map_size = " + UTIL_ToString( MapSize[0] ) + " " + UTIL_ToString( MapSize[1] ) + " " + UTIL_ToString( MapSize[2] ) + " " + UTIL_ToString( MapSize[3] ) );

		// calculate map_info (this is actually the CRC)

		MapInfo = UTIL_CreateByteArray( (uint32_t)m_GHost->m_CRC->FullCRC( (unsigned char *)m_MapData.c_str( ), m_MapData.size( ) ), false );
		CONSOLE_Print( "[MAP] calculated map_info = " + UTIL_ToString( MapInfo[0] ) + " " + UTIL_ToString( MapInfo[1] ) + " " + UTIL_ToString( MapInfo[2] ) + " " + UTIL_ToString( MapInfo[3] ) );

		// calculate map_crc (this is not the CRC) and map_sha1
		// a big thank you to Strilanc for figuring the map_crc algorithm out

		string CommonJ = UTIL_FileRead( m_GHost->m_MapCFGPath + "common.j" );

		if( CommonJ.empty( ) )
			CONSOLE_Print( "[MAP] unable to calculate map_crc/sha1 - unable to read file [" + m_GHost->m_MapCFGPath + "common.j]" );
		else
		{
			string BlizzardJ = UTIL_FileRead( m_GHost->m_MapCFGPath + "blizzard.j" );

			if( BlizzardJ.empty( ) )
				CONSOLE_Print( "[MAP] unable to calculate map_crc/sha1 - unable to read file [" + m_GHost->m_MapCFGPath + "blizzard.j]" );
			else
			{
				uint32_t Val = 0;

				// update: it's possible for maps to include their own copies of common.j and/or blizzard.j
				// this code now overrides the default copies if required

				bool OverrodeCommonJ = false;
				bool OverrodeBlizzardJ = false;

				if( MapMPQReady )
				{
					HANDLE SubFile;

					// override common.j

					if( SFileOpenFileEx( MapMPQ, "Scripts\\common.j", 0, &SubFile ) )
					{
						uint32_t FileLength = SFileGetFileSize( SubFile, NULL );

						if( FileLength > 0 && FileLength != 0xFFFFFFFF )
						{
							char *SubFileData = new char[FileLength];
							DWORD BytesRead = 0;

							if( SFileReadFile( SubFile, SubFileData, FileLength, &BytesRead ) )
							{
								CONSOLE_Print( "[MAP] overriding default common.j with map copy while calculating map_crc/sha1" );
								OverrodeCommonJ = true;
								Val = Val ^ XORRotateLeft( (unsigned char *)SubFileData, BytesRead );
								m_GHost->m_SHA->Update( (unsigned char *)SubFileData, BytesRead );
							}

							delete [] SubFileData;
						}

						SFileCloseFile( SubFile );
					}
				}

				if( !OverrodeCommonJ )
				{
					Val = Val ^ XORRotateLeft( (unsigned char *)CommonJ.c_str( ), CommonJ.size( ) );
					m_GHost->m_SHA->Update( (unsigned char *)CommonJ.c_str( ), CommonJ.size( ) );
				}

				if( MapMPQReady )
				{
					HANDLE SubFile;

					// override blizzard.j

					if( SFileOpenFileEx( MapMPQ, "Scripts\\blizzard.j", 0, &SubFile ) )
					{
						uint32_t FileLength = SFileGetFileSize( SubFile, NULL );

						if( FileLength > 0 && FileLength != 0xFFFFFFFF )
						{
							char *SubFileData = new char[FileLength];
							DWORD BytesRead = 0;

							if( SFileReadFile( SubFile, SubFileData, FileLength, &BytesRead ) )
							{
								CONSOLE_Print( "[MAP] overriding default blizzard.j with map copy while calculating map_crc/sha1" );
								OverrodeBlizzardJ = true;
								Val = Val ^ XORRotateLeft( (unsigned char *)SubFileData, BytesRead );
								m_GHost->m_SHA->Update( (unsigned char *)SubFileData, BytesRead );
							}

							delete [] SubFileData;
						}

						SFileCloseFile( SubFile );
					}
				}

				if( !OverrodeBlizzardJ )
				{
					Val = Val ^ XORRotateLeft( (unsigned char *)BlizzardJ.c_str( ), BlizzardJ.size( ) );
					m_GHost->m_SHA->Update( (unsigned char *)BlizzardJ.c_str( ), BlizzardJ.size( ) );
				}

				Val = ROTL( Val, 3 );
				Val = ROTL( Val ^ 0x03F1379E, 3 );
				m_GHost->m_SHA->Update( (unsigned char *)"\x9E\x37\xF1\x03", 4 );

				if( MapMPQReady )
				{
					vector<string> FileList;
					FileList.push_back( "war3map.j" );
					FileList.push_back( "scripts\\war3map.j" );
					FileList.push_back( "war3map.w3e" );
					FileList.push_back( "war3map.wpm" );
					FileList.push_back( "war3map.doo" );
					FileList.push_back( "war3map.w3u" );
					FileList.push_back( "war3map.w3b" );
					FileList.push_back( "war3map.w3d" );
					FileList.push_back( "war3map.w3a" );
					FileList.push_back( "war3map.w3q" );
					bool FoundScript = false;

					for( vector<string> :: iterator i = FileList.begin( ); i != FileList.end( ); i++ )
					{
						// don't use scripts\war3map.j if we've already used war3map.j (yes, some maps have both but only war3map.j is used)

						if( FoundScript && *i == "scripts\\war3map.j" )
							continue;

						HANDLE SubFile;

						if( SFileOpenFileEx( MapMPQ, (*i).c_str( ), 0, &SubFile ) )
						{
							uint32_t FileLength = SFileGetFileSize( SubFile, NULL );

							if( FileLength > 0 && FileLength != 0xFFFFFFFF )
							{
								char *SubFileData = new char[FileLength];
								DWORD BytesRead = 0;

								if( SFileReadFile( SubFile, SubFileData, FileLength, &BytesRead ) )
								{
									if( *i == "war3map.j" || *i == "scripts\\war3map.j" )
										FoundScript = true;

									Val = ROTL( Val ^ XORRotateLeft( (unsigned char *)SubFileData, BytesRead ), 3 );
									m_GHost->m_SHA->Update( (unsigned char *)SubFileData, BytesRead );
									// DEBUG_Print( "*** found: " + *i );
								}

								delete [] SubFileData;
							}

							SFileCloseFile( SubFile );
						}
						else
						{
							// DEBUG_Print( "*** not found: " + *i );
						}
					}

					if( !FoundScript )
						CONSOLE_Print( "[MAP] couldn't find war3map.j or scripts\\war3map.j in MPQ file, calculated map_crc/sha1 is probably wrong" );

					MapCRC = UTIL_CreateByteArray( Val, false );
					CONSOLE_Print( "[MAP] calculated map_crc = " + UTIL_ToString( MapCRC[0] ) + " " + UTIL_ToString( MapCRC[1] ) + " " + UTIL_ToString( MapCRC[2] ) + " " + UTIL_ToString( MapCRC[3] ) );
					m_GHost->m_SHA->Final( );
					unsigned char SHA1[20];
					memset( SHA1, 0, sizeof( unsigned char ) * 20 );
					m_GHost->m_SHA->GetHash( SHA1 );
					MapSHA1 = UTIL_CreateByteArray( SHA1, 20 );
					CONSOLE_Print( "[MAP] calculated map_sha1 = " + UTIL_ByteArrayToDecString( MapSHA1 ) );
				}
				else
					CONSOLE_Print( "[MAP] unable to calculate map_crc/sha1 - map MPQ file not loaded" );
			}
		}
	}
	else
		CONSOLE_Print( "[MAP] no map data available, using config file for map_size, map_info, map_crc, map_sha1" );

	// try to calculate map_width, map_height, map_slot<x>, map_numplayers, map_numteams

	BYTEARRAY MapWidth;
	BYTEARRAY MapHeight;
	uint32_t MapNumPlayers = 0;
	uint32_t MapNumTeams = 0;
	uint32_t MapFilterType = MAPFILTER_TYPE_SCENARIO;
	vector<CGameSlot> Slots;

	if( !m_MapData.empty( ) )
	{
		if( MapMPQReady )
		{
			HANDLE SubFile;

			if( SFileOpenFileEx( MapMPQ, "war3map.w3i", 0, &SubFile ) )
			{
				uint32_t FileLength = SFileGetFileSize( SubFile, NULL );

				if( FileLength > 0 && FileLength != 0xFFFFFFFF )
				{
					char *SubFileData = new char[FileLength];
					DWORD BytesRead = 0;

					if( SFileReadFile( SubFile, SubFileData, FileLength, &BytesRead ) )
					{
						istringstream ISS( string( SubFileData, BytesRead ) );

						// war3map.w3i format found at http://www.wc3campaigns.net/tools/specs/index.html by Zepir/PitzerMike

						string GarbageString;
						uint32_t FileFormat;
						uint32_t RawMapWidth;
						uint32_t RawMapHeight;
						uint32_t RawMapFlags;
						uint32_t RawMapNumPlayers;
						uint32_t RawMapNumTeams;

						ISS.read( (char *)&FileFormat, 4 );				// file format (18 = ROC, 25 = TFT)

						if( FileFormat == 18 || FileFormat == 25 )
						{
							ISS.seekg( 4, ios :: cur );					// number of saves
							ISS.seekg( 4, ios :: cur );					// editor version
							getline( ISS, GarbageString, '\0' );		// map name
							getline( ISS, GarbageString, '\0' );		// map author
							getline( ISS, GarbageString, '\0' );		// map description
							getline( ISS, GarbageString, '\0' );		// players recommended
							ISS.seekg( 32, ios :: cur );				// camera bounds
							ISS.seekg( 16, ios :: cur );				// camera bounds complements
							ISS.read( (char *)&RawMapWidth, 4 );		// map width
							ISS.read( (char *)&RawMapHeight, 4 );		// map height
							ISS.read( (char *)&RawMapFlags, 4 );		// flags
							ISS.seekg( 1, ios :: cur );					// map main ground type

							if( FileFormat == 18 )
								ISS.seekg( 4, ios :: cur );				// campaign background number
							else if( FileFormat == 25 )
							{
								ISS.seekg( 4, ios :: cur );				// loading screen background number
								getline( ISS, GarbageString, '\0' );	// path of custom loading screen model
							}

							getline( ISS, GarbageString, '\0' );		// map loading screen text
							getline( ISS, GarbageString, '\0' );		// map loading screen title
							getline( ISS, GarbageString, '\0' );		// map loading screen subtitle

							if( FileFormat == 18 )
								ISS.seekg( 4, ios :: cur );				// map loading screen number
							else if( FileFormat == 25 )
							{
								ISS.seekg( 4, ios :: cur );				// used game data set
								getline( ISS, GarbageString, '\0' );	// prologue screen path
							}

							getline( ISS, GarbageString, '\0' );		// prologue screen text
							getline( ISS, GarbageString, '\0' );		// prologue screen title
							getline( ISS, GarbageString, '\0' );		// prologue screen subtitle

							if( FileFormat == 25 )
							{
								ISS.seekg( 4, ios :: cur );				// uses terrain fog
								ISS.seekg( 4, ios :: cur );				// fog start z height
								ISS.seekg( 4, ios :: cur );				// fog end z height
								ISS.seekg( 4, ios :: cur );				// fog density
								ISS.seekg( 1, ios :: cur );				// fog red value
								ISS.seekg( 1, ios :: cur );				// fog green value
								ISS.seekg( 1, ios :: cur );				// fog blue value
								ISS.seekg( 1, ios :: cur );				// fog alpha value
								ISS.seekg( 4, ios :: cur );				// global weather id
								getline( ISS, GarbageString, '\0' );	// custom sound environment
								ISS.seekg( 1, ios :: cur );				// tileset id of the used custom light environment
								ISS.seekg( 1, ios :: cur );				// custom water tinting red value
								ISS.seekg( 1, ios :: cur );				// custom water tinting green value
								ISS.seekg( 1, ios :: cur );				// custom water tinting blue value
								ISS.seekg( 1, ios :: cur );				// custom water tinting alpha value
							}

							ISS.read( (char *)&RawMapNumPlayers, 4 );	// number of players
							uint32_t ClosedSlots = 0;

							for( uint32_t i = 0; i < RawMapNumPlayers; i++ )
							{
								CGameSlot Slot( 0, 255, SLOTSTATUS_OPEN, 0, 0, 1, SLOTRACE_RANDOM );
								uint32_t Colour;
								uint32_t Status;
								uint32_t Race;

								ISS.read( (char *)&Colour, 4 );			// colour
								Slot.SetColour( Colour );
								ISS.read( (char *)&Status, 4 );			// status

								if( Status == 1 )
									Slot.SetSlotStatus( SLOTSTATUS_OPEN );
								else if( Status == 2 )
								{
									Slot.SetSlotStatus( SLOTSTATUS_OCCUPIED );
									Slot.SetComputer( 1 );
									Slot.SetComputerType( SLOTCOMP_NORMAL );
								}
								else
								{
									Slot.SetSlotStatus( SLOTSTATUS_CLOSED );
									ClosedSlots++;
								}

								ISS.read( (char *)&Race, 4 );			// race

								if( Race == 1 )
									Slot.SetRace( SLOTRACE_HUMAN );
								else if( Race == 2 )
									Slot.SetRace( SLOTRACE_ORC );
								else if( Race == 3 )
									Slot.SetRace( SLOTRACE_UNDEAD );
								else if( Race == 4 )
									Slot.SetRace( SLOTRACE_NIGHTELF );
								else
									Slot.SetRace( SLOTRACE_RANDOM );

								ISS.seekg( 4, ios :: cur );				// fixed start position
								getline( ISS, GarbageString, '\0' );	// player name
								ISS.seekg( 4, ios :: cur );				// start position x
								ISS.seekg( 4, ios :: cur );				// start position y
								ISS.seekg( 4, ios :: cur );				// ally low priorities
								ISS.seekg( 4, ios :: cur );				// ally high priorities

								if( Slot.GetSlotStatus( ) != SLOTSTATUS_CLOSED )
									Slots.push_back( Slot );
							}

							ISS.read( (char *)&RawMapNumTeams, 4 );		// number of teams

							for( uint32_t i = 0; i < RawMapNumTeams; i++ )
							{
								uint32_t Flags;
								uint32_t PlayerMask;

								ISS.read( (char *)&Flags, 4 );			// flags
								ISS.read( (char *)&PlayerMask, 4 );		// player mask

								for( unsigned char j = 0; j < 12; j++ )
								{
									if( PlayerMask & 1 )
									{
										for( vector<CGameSlot> :: iterator k = Slots.begin( ); k != Slots.end( ); k++ )
										{
											if( (*k).GetColour( ) == j )
												(*k).SetTeam( i );
										}
									}

									PlayerMask >>= 1;
								}

								getline( ISS, GarbageString, '\0' );	// team name
							}

							MapWidth = UTIL_CreateByteArray( (uint16_t)RawMapWidth, false );
							CONSOLE_Print( "[MAP] calculated map_width = " + UTIL_ToString( MapWidth[0] ) + " " + UTIL_ToString( MapWidth[1] ) );
							MapHeight = UTIL_CreateByteArray( (uint16_t)RawMapHeight, false );
							CONSOLE_Print( "[MAP] calculated map_height = " + UTIL_ToString( MapHeight[0] ) + " " + UTIL_ToString( MapHeight[1] ) );
							MapNumPlayers = RawMapNumPlayers - ClosedSlots;
							CONSOLE_Print( "[MAP] calculated map_numplayers = " + UTIL_ToString( MapNumPlayers ) );
							MapNumTeams = RawMapNumTeams;
							CONSOLE_Print( "[MAP] calculated map_numteams = " + UTIL_ToString( MapNumTeams ) );
							CONSOLE_Print( "[MAP] found " + UTIL_ToString( Slots.size( ) ) + " slots" );

							BYTEARRAY b;
							string s;
							int k=0;
							if (false && m_LogAll)
								for( vector<CGameSlot> :: iterator i = Slots.begin( ); i != Slots.end( ); i++ )
								{
									k++;
									b =(*i).GetByteArray( );
									s = "map_slot"+UTIL_ToString(k)+" = ";
									for( unsigned int j = 0; j < b.size( ); j++ )
									{
										s= s+ UTIL_ToString((int)b[j]);
										if (j<b.size()-1)
											s=s+" ";
									}
									CONSOLE_Print( "[MAP] calculated " + s );
								}

							/* for( vector<CGameSlot> :: iterator i = Slots.begin( ); i != Slots.end( ); i++ )
								DEBUG_Print( (*i).GetByteArray( ) ); */

							// if it's a melee map...

							if( RawMapFlags & 4 )
							{
								CONSOLE_Print( "[MAP] found melee map, initializing slots" );

								// give each slot a different team and set the race to random

								unsigned char Team = 0;

								for( vector<CGameSlot> :: iterator i = Slots.begin( ); i != Slots.end( ); i++ )
								{
									(*i).SetTeam( Team++ );
									(*i).SetRace( SLOTRACE_RANDOM );
								}
								MapFilterType = MAPFILTER_TYPE_MELEE;
							}
						}
					}
					else
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;
}
string CPotentialPlayer :: GetExternalIPString( )
{
	BYTEARRAY IP;
	string EIP;
	if( m_Socket )
	{
		if( m_IncomingGarenaUser != NULL ) 
		{
			BYTEARRAY GarenaIP = GetGarenaIP( );
			return UTIL_ToString(GarenaIP[0]) + "." + UTIL_ToString(GarenaIP[1]) + "." + UTIL_ToString(GarenaIP[2]) + "." + UTIL_ToString(GarenaIP[3]);
		} else {	
			bool local=m_LAN;
			if (!m_LANSet)
			{				
				IP=	m_Socket->GetIP( );
				if (IP.size()>=2)
				{
					if (IP[0]==10)
					local=true;
					else if (IP[0]==192 && IP[1]==168)
					local=true;
					else if (IP[0]==169 && IP[1]==254)
					local=true;
					else if (IP[0]==172 && IP[1]==16)
					local=true;
					else if (IP[0]==172 && IP[1]==17)
					local=true;
					else if (IP[0]==172 && IP[1]==18)
					local=true;
					else if (IP[0]==172 && IP[1]==19)
					local=true;
					else if (IP[0]==172 && IP[1]==20)
					local=true;
					else if (IP[0]==172 && IP[1]==21)
					local=true;
					else if (IP[0]==172 && IP[1]==22)
					local=true;
					else if (IP[0]==172 && IP[1]==23)
					local=true;
					else if (IP[0]==172 && IP[1]==24)
					local=true;
					else if (IP[0]==172 && IP[1]==25)
					local=true;
					else if (IP[0]==172 && IP[1]==26)
					local=true;
					else if (IP[0]==172 && IP[1]==27)
					local=true;
					else if (IP[0]==172 && IP[1]==28)
					local=true;
					else if (IP[0]==172 && IP[1]==29)
					local=true;
					else if (IP[0]==172 && IP[1]==30)
					local=true;
					else if (IP[0]==172 && IP[1]==31)
					local=true;
				}
				if (UTIL_IsLocalIP(IP, m_Game->m_GHost->m_LocalAddresses))
					local = true;
				m_LANSet = true;
				m_LAN = local;
			}
			EIP=m_Socket->GetIPString( );
			if (local && m_Game->m_GHost->m_ExternalIP!="")
			{
			EIP=m_Game->m_GHost->m_ExternalIP;
			}
			if( !EIP.empty( ) && EIP != "0.0.0.0" )
				return EIP;
			else
				return m_CachedIP;
		}
	}
	return m_CachedIP;
}
Beispiel #22
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;
    }
}
Beispiel #23
0
bool CGamePlayer::Update(void *fd)
{
  const 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)
  {
    for (auto & bnet : m_Game->m_Aura->m_BNETs)
    {
      if (bnet->GetServer() == m_JoinedRealm)
      {
        if (m_Game->GetGameState() == GAME_PUBLIC || bnet->GetPvPGN())
          bnet->QueueChatCommand("/whois " + m_Name);
        else if (m_Game->GetGameState() == GAME_PRIVATE)
          bnet->QueueChatCommand("Spoof check by replying to this message with \"sc\" [ /r sc ]", m_Name, true, string());
      }
    }

    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 (Time - m_Socket->GetLastRecv() >= 30)
    m_Game->EventPlayerDisconnectTimedOut(this);

  // GProxy++ acks

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

  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 = CreateByteArray((uint8_t *) RecvBuffer->c_str(), RecvBuffer->size());
  uint32_t LengthProcessed = 0;

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

  CIncomingAction *Action;
  CIncomingChatPlayer *ChatPlayer;
  CIncomingMapSize *MapSize;
  uint32_t Pong;

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

    const uint16_t Length = ByteArrayToUInt16(Bytes, false, 2);
    const BYTEARRAY Data = BYTEARRAY(begin(Bytes), begin(Bytes) + Length);

    if (Bytes[0] == W3GS_HEADER_CONSTANT)
    {
      ++m_TotalPacketsReceived;

      if (Bytes.size() >= Length)
      {
        // byte 1 contains the packet ID

        switch (Bytes[1])
        {
          case CGameProtocol::W3GS_LEAVEGAME:
            m_Game->EventPlayerLeft(this, m_Protocol->RECEIVE_W3GS_LEAVEGAME(Data));
            break;

          case CGameProtocol::W3GS_GAMELOADED_SELF:
            if (m_Protocol->RECEIVE_W3GS_GAMELOADED_SELF(Data))
            {
              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(Data, 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:
            m_CheckSums.push(m_Protocol->RECEIVE_W3GS_OUTGOING_KEEPALIVE(Data));
            ++m_SyncCounter;
            m_Game->EventPlayerKeepAlive(this);
            break;

          case CGameProtocol::W3GS_CHAT_TO_HOST:
            ChatPlayer = m_Protocol->RECEIVE_W3GS_CHAT_TO_HOST(Data);

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

            delete ChatPlayer;
            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(Data);

            if (MapSize)
              m_Game->EventPlayerMapSize(this, MapSize);

            delete MapSize;
            break;

          case CGameProtocol::W3GS_PONG_TO_HOST:
            Pong = m_Protocol->RECEIVE_W3GS_PONG_TO_HOST(Data);

            // 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() > 10)
                    m_Pings.erase(begin(m_Pings));
                }
              }
            }

            m_Game->EventPlayerPongToHost(this);
            break;
        }

        LengthProcessed += Length;
        Bytes = BYTEARRAY(begin(Bytes) + Length, end(Bytes));
      }
      else
        break;
    }
    else if (Bytes[0] == GPS_HEADER_CONSTANT)
    {
      if (Length >= 4)
      {
        if (Bytes.size() >= Length)
        {
          if (Bytes[1] == CGPSProtocol::GPS_ACK && Data.size() == 8)
          {
            const uint32_t LastPacket = ByteArrayToUInt32(Data, false, 4);
            const 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)
          {
            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++");
          }
        }

        LengthProcessed += Length;
        Bytes = BYTEARRAY(begin(Bytes) + Length, end(Bytes));
      }
      else
        break;
    }
  }

  *RecvBuffer = RecvBuffer->substr(LengthProcessed);

  // 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();
    }
  }

  if (m_GProxy && m_Game->GetGameLoaded())
    return m_DeleteMe;

  return m_DeleteMe || m_Socket->HasError() || !m_Socket->GetConnected();
}
Beispiel #24
0
BYTEARRAY CBNETProtocol :: SEND_SID_STARTADVEX3( unsigned char state, BYTEARRAY mapGameType, BYTEARRAY mapFlags, BYTEARRAY mapWidth, BYTEARRAY mapHeight, string gameName, string hostName, uint32_t upTime, string mapPath, BYTEARRAY mapCRC, BYTEARRAY mapSHA1, uint32_t hostCounter )
{
    // todotodo: sort out how GameType works, the documentation is horrendous

    /*

    Game type tag: (read W3GS_GAMEINFO for this field)
     0x00000001 - Custom
     0x00000009 - Blizzard/Ladder
    Map author: (mask 0x00006000) can be combined
    *0x00002000 - Blizzard
     0x00004000 - Custom
    Battle type: (mask 0x00018000) cant be combined
     0x00000000 - Battle
    *0x00010000 - Scenario
    Map size: (mask 0x000E0000) can be combined with 2 nearest values
     0x00020000 - Small
     0x00040000 - Medium
    *0x00080000 - Huge
    Observers: (mask 0x00700000) cant be combined
     0x00100000 - Allowed observers
     0x00200000 - Observers on defeat
    *0x00400000 - No observers
    Flags:
     0x00000800 - Private game flag (not used in game list)

    */

    unsigned char Unknown[]		= { 255,  3,  0,  0 };
    unsigned char CustomGame[]	= {   0,  0,  0,  0 };

    string HostCounterString = UTIL_ToHexString( hostCounter );

    if( HostCounterString.size( ) < 8 )
        HostCounterString.insert( 0, 8 - HostCounterString.size( ), '0' );

    HostCounterString = string( HostCounterString.rbegin( ), HostCounterString.rend( ) );

    BYTEARRAY packet;

    // make the stat string

    BYTEARRAY StatString;
    UTIL_AppendByteArrayFast( StatString, mapFlags );
    StatString.push_back( 0 );
    UTIL_AppendByteArrayFast( StatString, mapWidth );
    UTIL_AppendByteArrayFast( StatString, mapHeight );
    UTIL_AppendByteArrayFast( StatString, mapCRC );
    UTIL_AppendByteArrayFast( StatString, mapPath );
    UTIL_AppendByteArrayFast( StatString, hostName );
    StatString.push_back( 0 );
    UTIL_AppendByteArrayFast( StatString, mapSHA1 );
    StatString = UTIL_EncodeStatString( StatString );

    if( mapGameType.size( ) == 4 && mapFlags.size( ) == 4 && mapWidth.size( ) == 2 && mapHeight.size( ) == 2 && !gameName.empty( ) && !hostName.empty( ) && !mapPath.empty( ) && mapCRC.size( ) == 4 && mapSHA1.size( ) == 20 && StatString.size( ) < 128 && HostCounterString.size( ) == 8 )
    {
        // make the rest of the packet

        packet.push_back( BNET_HEADER_CONSTANT );						// BNET header constant
        packet.push_back( SID_STARTADVEX3 );							// SID_STARTADVEX3
        packet.push_back( 0 );											// packet length will be assigned later
        packet.push_back( 0 );											// packet length will be assigned later
        packet.push_back( state );										// State (16 = public, 17 = private, 18 = close)
        packet.push_back( 0 );											// State continued...
        packet.push_back( 0 );											// State continued...
        packet.push_back( 0 );											// State continued...
        UTIL_AppendByteArray( packet, upTime, false );					// time since creation
        UTIL_AppendByteArrayFast( packet, mapGameType );				// Game Type, Parameter
        UTIL_AppendByteArray( packet, Unknown, 4 );						// ???
        UTIL_AppendByteArray( packet, CustomGame, 4 );					// Custom Game
        UTIL_AppendByteArrayFast( packet, gameName );					// Game Name
        packet.push_back( 0 );											// Game Password is NULL
        packet.push_back( 98 );											// Slots Free (ascii 98 = char 'b' = 11 slots free) - note: do not reduce this as this is the # of PID's Warcraft III will allocate
        UTIL_AppendByteArrayFast( packet, HostCounterString, false );	// Host Counter
        UTIL_AppendByteArrayFast( packet, StatString );					// Stat String
        packet.push_back( 0 );											// Stat String null terminator (the stat string is encoded to remove all even numbers i.e. zeros)
        AssignLength( packet );
    }
    else
        CONSOLE_Print( "[BNETPROTO] invalid parameters passed to SEND_SID_STARTADVEX3" );

    // DEBUG_Print( "SENT SID_STARTADVEX3" );
    // DEBUG_Print( packet );
    return packet;
}
Beispiel #25
0
void CReplay :: BuildReplay( string gameName, string statString, uint32_t war3Version, uint16_t buildNumber )
{
	m_War3Version = war3Version;
	m_BuildNumber = buildNumber;
	m_Flags = 32768;

	CONSOLE_Print( "[REPLAY] building replay" );

	uint32_t LanguageID = 0x0012F8B0;

	BYTEARRAY Replay;
	Replay.push_back( 16 );															// Unknown (4.0)
	Replay.push_back( 1 );															// Unknown (4.0)
	Replay.push_back( 0 );															// Unknown (4.0)
	Replay.push_back( 0 );															// Unknown (4.0)
	Replay.push_back( 0 );															// Host RecordID (4.1)
	Replay.push_back( m_HostPID );													// Host PlayerID (4.1)
	UTIL_AppendByteArrayFast( Replay, m_HostName );									// Host PlayerName (4.1)
	Replay.push_back( 1 );															// Host AdditionalSize (4.1)
	Replay.push_back( 0 );															// Host AdditionalData (4.1)
	UTIL_AppendByteArrayFast( Replay, gameName );									// GameName (4.2)
	Replay.push_back( 0 );															// Null (4.0)
	UTIL_AppendByteArrayFast( Replay, statString );									// StatString (4.3)
	UTIL_AppendByteArray( Replay, (uint32_t)m_Slots.size( ), false );				// PlayerCount (4.6)
	Replay.push_back( m_MapGameType );												// GameType (4.7)
	Replay.push_back( 32 );															// GameType (4.7)
	Replay.push_back( 73 );															// GameType (4.7)
	Replay.push_back( 0 );															// GameType (4.7)
	UTIL_AppendByteArray( Replay, LanguageID, false );								// LanguageID (4.8)

	// PlayerList (4.9)

	for( vector<PIDPlayer> :: iterator i = m_Players.begin( ); i != m_Players.end( ); i++ )
	{
		if( (*i).first != m_HostPID )
		{
			Replay.push_back( 22 );													// Player RecordID (4.1)
			Replay.push_back( (*i).first );											// Player PlayerID (4.1)
			UTIL_AppendByteArrayFast( Replay, (*i).second );						// Player PlayerName (4.1)
			Replay.push_back( 1 );													// Player AdditionalSize (4.1)
			Replay.push_back( 0 );													// Player AdditionalData (4.1)
			UTIL_AppendByteArray( Replay, (uint32_t)0, false );						// Unknown
		}
	}

	// GameStartRecord (4.10)

	Replay.push_back( 25 );															// RecordID (4.10)
	UTIL_AppendByteArray( Replay, (uint16_t)( 7 + m_Slots.size( ) * 9 ), false );	// Size (4.10)
	Replay.push_back( m_Slots.size( ) );											// NumSlots (4.10)

	for( unsigned char i = 0; i < m_Slots.size( ); i++ )
		UTIL_AppendByteArray( Replay, m_Slots[i].GetByteArray( ) );

	UTIL_AppendByteArray( Replay, m_RandomSeed, false );							// RandomSeed (4.10)
	Replay.push_back( m_SelectMode );												// SelectMode (4.10)
	Replay.push_back( m_StartSpotCount );											// StartSpotCount (4.10)

	// ReplayData (5.0)

	Replay.push_back( REPLAY_FIRSTSTARTBLOCK );
	UTIL_AppendByteArray( Replay, (uint32_t)1, false );
	Replay.push_back( REPLAY_SECONDSTARTBLOCK );
	UTIL_AppendByteArray( Replay, (uint32_t)1, false );

	// leavers during loading need to be stored between the second and third start blocks

	while( !m_LoadingBlocks.empty( ) )
	{
		UTIL_AppendByteArray( Replay, m_LoadingBlocks.front( ) );
		m_LoadingBlocks.pop( );
	}

	Replay.push_back( REPLAY_THIRDSTARTBLOCK );
	UTIL_AppendByteArray( Replay, (uint32_t)1, false );

	// initialize replay length to zero
	// we'll accumulate the replay length as we iterate through the timeslots
	// this is necessary because we might be discarding some timeslots due to not enough checksums and the replay length needs to be accurate

	m_ReplayLength = 0;
	uint32_t TimeSlotsDiscarded = 0;
	bool EndOfTimeSlots = false;

	while( !m_Blocks.empty( ) )
	{
		BYTEARRAY Block = m_Blocks.front( );
		m_Blocks.pop( );

		if( Block.size( ) >= 5 && Block[0] == REPLAY_TIMESLOT )
		{
			uint16_t TimeIncrement = UTIL_ByteArrayToUInt16( Block, false, 3 );

			if( TimeIncrement != 0 && m_CheckSums.empty( ) )
				EndOfTimeSlots = true;

			if( EndOfTimeSlots )
			{
				TimeSlotsDiscarded++;
				continue;
			}

			// append timeslot

			UTIL_AppendByteArrayFast( Replay, Block );

			// append checksum
			// todotodo: after experimenting, Strilanc discovered that checksums are NOT required in replays
			// we could optimize saving of replays by building a complete stream without waiting for checksums as the game progresses
			// alternatively, we could build that stream as the checksums were added if we wanted to keep them
			// rather than building it in one go right now, which might take a few hundred ms and cause a spike in other games

			if( TimeIncrement != 0 )
			{
				BYTEARRAY CheckSum;
				CheckSum.reserve( 6 );
				CheckSum.push_back( REPLAY_CHECKSUM );
				CheckSum.push_back( 4 );
				UTIL_AppendByteArray( CheckSum, m_CheckSums.front( ), false );
				m_CheckSums.pop( );
				UTIL_AppendByteArrayFast( Replay, CheckSum );
			}

			// accumulate replay length

			m_ReplayLength += TimeIncrement;
		}
		else
			UTIL_AppendByteArrayFast( Replay, Block );
	}

	if( TimeSlotsDiscarded > 0 )
		CONSOLE_Print( "[REPLAY] ran out of checksums, discarded " + UTIL_ToString( TimeSlotsDiscarded ) + " timeslots" );

	// done

	m_Decompressed = string( Replay.begin( ), Replay.end( ) );
}
Beispiel #26
0
BYTEARRAY CGameProtocol :: SEND_W3GS_INCOMING_ACTION2( queue<CIncomingAction *> actions )
{
	BYTEARRAY packet;
	packet.push_back( W3GS_HEADER_CONSTANT );				// W3GS header constant
	packet.push_back( W3GS_INCOMING_ACTION2 );				// W3GS_INCOMING_ACTION2
	packet.push_back( 0 );									// packet length will be assigned later
	packet.push_back( 0 );									// packet length will be assigned later
	packet.push_back( 0 );									// ??? (send interval?)
	packet.push_back( 0 );									// ??? (send interval?)

	// create subpacket

	if( !actions.empty( ) )
	{
		BYTEARRAY subpacket;

		while( !actions.empty( ) )
		{
			CIncomingAction *Action = actions.front( );
			actions.pop( );
			subpacket.push_back( Action->GetPID( ) );
			UTIL_AppendByteArray( subpacket, (uint16_t)Action->GetAction( )->size( ), false );
			UTIL_AppendByteArrayFast( subpacket, *Action->GetAction( ) );
		}

		// calculate crc (we only care about the first 2 bytes though)

		BYTEARRAY crc32 = UTIL_CreateByteArray( m_GHost->m_CRC->FullCRC( (unsigned char *)string( subpacket.begin( ), subpacket.end( ) ).c_str( ), subpacket.size( ) ), false );
		crc32.resize( 2 );

		// finish subpacket

		UTIL_AppendByteArrayFast( packet, crc32 );			// crc
		UTIL_AppendByteArrayFast( packet, subpacket );		// subpacket
	}

	AssignLength( packet );
	// DEBUG_Print( "SENT W3GS_INCOMING_ACTION2" );
	// DEBUG_Print( packet );
	return packet;
}
BYTEARRAY CPotentialPlayer :: GetExternalIP( )
{
	unsigned char Zeros[] = { 0, 0, 0, 0 };
	BYTEARRAY IP;

	if( m_Socket )
	{	
		if( m_IncomingGarenaUser != NULL )
			return GetGarenaIP( );
		else {
			bool local=false;
			IP=	m_Socket->GetIP( );
			if (IP.size()>=2)
			{
				if (IP[0]==10)
				local=true;
				else if (IP[0]==192 && IP[1]==168)
				local=true;
				else if (IP[0]==169 && IP[1]==254)
				local=true;
				else if (IP[0]==172 && IP[1]==16)
				local=true;
				else if (IP[0]==172 && IP[1]==17)
				local=true;
				else if (IP[0]==172 && IP[1]==18)
				local=true;
				else if (IP[0]==172 && IP[1]==19)
				local=true;
				else if (IP[0]==172 && IP[1]==20)
				local=true;
				else if (IP[0]==172 && IP[1]==21)
				local=true;
				else if (IP[0]==172 && IP[1]==22)
				local=true;
				else if (IP[0]==172 && IP[1]==23)
				local=true;
				else if (IP[0]==172 && IP[1]==24)
				local=true;
				else if (IP[0]==172 && IP[1]==25)
				local=true;
				else if (IP[0]==172 && IP[1]==26)
				local=true;
				else if (IP[0]==172 && IP[1]==27)
				local=true;
				else if (IP[0]==172 && IP[1]==28)
				local=true;
				else if (IP[0]==172 && IP[1]==29)
				local=true;
				else if (IP[0]==172 && IP[1]==30)
				local=true;
				else if (IP[0]==172 && IP[1]==31)
				local=true;
			}
			if (local && m_Game->m_GHost->m_ExternalIP!="")
			{
				IP=UTIL_CreateByteArray(m_Game->m_GHost->m_ExternalIPL,true);
			}
			return IP;
		}
	}

	return UTIL_CreateByteArray( Zeros, 4 );
}
Beispiel #28
0
BYTEARRAY CGameProtocol :: SEND_W3GS_GAMEINFO( bool TFT, unsigned char war3Version, BYTEARRAY mapGameType, BYTEARRAY mapFlags, BYTEARRAY mapWidth, BYTEARRAY mapHeight, string gameName, string hostName, uint32_t upTime, string mapPath, BYTEARRAY mapCRC, uint32_t slotsTotal, uint32_t slotsOpen, uint16_t port, uint32_t hostCounter, uint32_t entryKey )
{
	unsigned char ProductID_ROC[]	= {          51, 82, 65, 87 };	// "WAR3"
	unsigned char ProductID_TFT[]	= {          80, 88, 51, 87 };	// "W3XP"
	unsigned char Version[]			= { war3Version,  0,  0,  0 };
	unsigned char Unknown[]			= {           1,  0,  0,  0 };

	BYTEARRAY packet;

	if( mapGameType.size( ) == 4 && mapFlags.size( ) == 4 && mapWidth.size( ) == 2 && mapHeight.size( ) == 2 && !gameName.empty( ) && !hostName.empty( ) && !mapPath.empty( ) && mapCRC.size( ) == 4 )
	{
		// make the stat string

		BYTEARRAY StatString;
		UTIL_AppendByteArrayFast( StatString, mapFlags );
		StatString.push_back( 0 );
		UTIL_AppendByteArrayFast( StatString, mapWidth );
		UTIL_AppendByteArrayFast( StatString, mapHeight );
		UTIL_AppendByteArrayFast( StatString, mapCRC );
		UTIL_AppendByteArrayFast( StatString, mapPath );
		UTIL_AppendByteArrayFast( StatString, hostName );
		StatString.push_back( 0 );
		StatString = UTIL_EncodeStatString( StatString );

		// make the rest of the packet

		packet.push_back( W3GS_HEADER_CONSTANT );						// W3GS header constant
		packet.push_back( W3GS_GAMEINFO );								// W3GS_GAMEINFO
		packet.push_back( 0 );											// packet length will be assigned later
		packet.push_back( 0 );											// packet length will be assigned later

		if( TFT )
			UTIL_AppendByteArray( packet, ProductID_TFT, 4 );			// Product ID (TFT)
		else
			UTIL_AppendByteArray( packet, ProductID_ROC, 4 );			// Product ID (ROC)

		UTIL_AppendByteArray( packet, Version, 4 );						// Version
		UTIL_AppendByteArray( packet, hostCounter, false );				// Host Counter
		UTIL_AppendByteArray( packet, entryKey, false );				// Entry Key
		UTIL_AppendByteArrayFast( packet, gameName );					// Game Name
		packet.push_back( 0 );											// ??? (maybe game password)
		UTIL_AppendByteArrayFast( packet, StatString );					// Stat String
		packet.push_back( 0 );											// Stat String null terminator (the stat string is encoded to remove all even numbers i.e. zeros)
		UTIL_AppendByteArray( packet, slotsTotal, false );				// Slots Total
		UTIL_AppendByteArrayFast( packet, mapGameType );				// Game Type
		UTIL_AppendByteArray( packet, Unknown, 4 );						// ???
		UTIL_AppendByteArray( packet, slotsOpen, false );				// Slots Open
		UTIL_AppendByteArray( packet, upTime, false );					// time since creation
		UTIL_AppendByteArray( packet, port, false );					// port
		AssignLength( packet );
	}
	else
	{
		if(mapGameType.size( ) != 4) CONSOLE_Print( "[GAMEPROTO] invalid parameters passed to SEND_W3GS_GAMEINFO (mapGameType)" );
		else if(mapFlags.size( ) != 4) CONSOLE_Print( "[GAMEPROTO] invalid parameters passed to SEND_W3GS_GAMEINFO (mapFlags)" );
		else if(mapWidth.size( ) != 2) CONSOLE_Print( "[GAMEPROTO] invalid parameters passed to SEND_W3GS_GAMEINFO (mapWidth)" );
		else if(mapHeight.size( ) != 2) CONSOLE_Print( "[GAMEPROTO] invalid parameters passed to SEND_W3GS_GAMEINFO (mapHeight)" );
		else if(gameName.empty( ))  CONSOLE_Print( "[GAMEPROTO] invalid parameters passed to SEND_W3GS_GAMEINFO (gameName)" );
		else if(hostName.empty( )) CONSOLE_Print( "[GAMEPROTO] invalid parameters passed to SEND_W3GS_GAMEINFO (hostName)" );
		else if(mapPath.empty( ))  CONSOLE_Print( "[GAMEPROTO] invalid parameters passed to SEND_W3GS_GAMEINFO (mapPath)" );
		else if(mapCRC.size( ) != 4) CONSOLE_Print( "[GAMEPROTO] invalid parameters passed to SEND_W3GS_GAMEINFO (CRC)" );
		else  CONSOLE_Print( "[GAMEPROTO] invalid parameters passed to SEND_W3GS_GAMEINFO (unknown)" );
		
	}

	// DEBUG_Print( "SENT W3GS_GAMEINFO" );
	// DEBUG_Print( packet );
	return packet;
}
Beispiel #29
0
void DEBUG_Print( BYTEARRAY b , uint32_t level )
{
	if(level>debug_level)
		return ;

	switch(level)
	{
		case DEBUG_LEVEL_PACKET_RECV:
			cout << "<<<IN\n" ;
			break;
		case DEBUG_LEVEL_PACKET_SEND:
			cout << "   OUT>>>\n" ;
			break;
		default :
			cout << level << "\n" ;
			break;
	}

	unsigned int i = 0;
	while( i < b.size( ) )
	{
		switch(level)
		{
			case DEBUG_LEVEL_PACKET_RECV:
				cout << "" ;
				break;
			case DEBUG_LEVEL_PACKET_SEND:
				cout << "   " ;
				break;
			default :
				cout << level << ">" ;
				break;
		}

		unsigned int j;
		for( j = 0; j < 8; j++ )
		{
			if(j+i < b.size( ))
				cout << setfill('0') << setw(2) << hex << (int)b[i+j] << " ";
			else
				cout << "   ";
		}
		cout << " ";
		for( j = 8; j < 16; j++ )
		{
			if(j+i < b.size( ))
				cout << setfill('0') << setw(2) << hex << (int)b[i+j] << " ";
			else
				cout << "   ";
		}
		cout << "  ";

		for( j = 0; j < 16 && i < b.size( ); j++,i++ )
		{
			if(j % 8 == 0)
				cout << " ";
			if((int)b[i] >= 32 && (int)b[i] < 127)
				cout << b[i];
			else
				cout << ".";
		}
		cout << endl;
	}
}