BYTEARRAY CGameProtocol :: SEND_W3GS_GAMELOADED_OTHERS( unsigned char PID ) { BYTEARRAY packet; if( PID != 255 ) { packet.push_back( W3GS_HEADER_CONSTANT ); // W3GS header constant packet.push_back( W3GS_GAMELOADED_OTHERS ); // W3GS_GAMELOADED_OTHERS packet.push_back( 0 ); // packet length will be assigned later packet.push_back( 0 ); // packet length will be assigned later packet.push_back( PID ); // PID AssignLength( packet ); } else CONSOLE_Print( "[GAMEPROTO] invalid parameters passed to SEND_W3GS_GAMELOADED_OTHERS" ); // DEBUG_Print( "SENT W3GS_GAMELOADED_OTHERS" ); // DEBUG_Print( packet ); return packet; }
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" ); // DEBUG_Print( "SENT SID_AUTH_ACCOUNTLOGONPROOF" ); // DEBUG_Print( packet ); return packet; }
bool CUDPSocket :: Broadcast( uint16_t port, BYTEARRAY message ) { if( m_Socket == INVALID_SOCKET || m_HasError ) return false; struct sockaddr_in sin; sin.sin_family = AF_INET; sin.sin_addr.s_addr = m_BroadcastTarget.s_addr; sin.sin_port = htons( port ); string MessageString = string( message.begin( ), message.end( ) ); if( sendto( m_Socket, MessageString.c_str( ), MessageString.size( ), 0, (struct sockaddr *)&sin, sizeof( sin ) ) == -1 ) { //CONSOLE_Print( "[UDPSOCKET] failed to broadcast packet (port " + UTIL_ToString( port ) + ", size " + UTIL_ToString( MessageString.size( ) ) + " bytes)" ); return false; } return true; }
BYTEARRAY CPUBProtocol :: SendBotCreateSavedGame( const string& gamename, const string& savefilename, BYTEARRAY nMagicNumber, const string& owner, const string& saveData ) { BYTEARRAY packet; packet.push_back( PUB_HEADER_CONSTANT ); packet.push_back( PUB_CREATE_SAVEDGAME ); packet.push_back( 0 ); packet.push_back( 0 ); UTIL_AppendByteArray(packet, gamename, true); UTIL_AppendByteArray(packet, savefilename, true); UTIL_AppendByteArray(packet, nMagicNumber); UTIL_AppendByteArray(packet, owner, true); UTIL_AppendByteArray(packet, saveData, false); AssignLength(packet); return packet; }
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" ); // DEBUG_Print( "SENT SID_PING" ); // DEBUG_Print( packet ); return packet; }
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; }
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" ); // DEBUG_Print( "SENT SID_AUTH_ACCOUNTLOGON" ); // DEBUG_Print( packet ); return packet; }
BYTEARRAY CGameProtocol :: SEND_W3GS_PLAYERLEAVE_OTHERS( unsigned char PID, uint32_t leftCode ) { BYTEARRAY packet; if( PID != 255 ) { packet.push_back( W3GS_HEADER_CONSTANT ); // W3GS header constant packet.push_back( W3GS_PLAYERLEAVE_OTHERS ); // W3GS_PLAYERLEAVE_OTHERS packet.push_back( 0 ); // packet length will be assigned later packet.push_back( 0 ); // packet length will be assigned later packet.push_back( PID ); // PID UTIL_AppendByteArray( packet, leftCode, false ); // left code (see PLAYERLEAVE_ constants in gameprotocol.h) AssignLength( packet ); } else CONSOLE_Print( "[GAMEPROTO] invalid parameters passed to SEND_W3GS_PLAYERLEAVE_OTHERS" ); // DEBUG_Print( "SENT W3GS_PLAYERLEAVE_OTHERS" ); // DEBUG_Print( packet ); return packet; }
BYTEARRAY CBNETProtocol :: SEND_SID_JOINCHANNEL( string channel ) { unsigned char NoCreateJoin[] = { 2, 0, 0, 0 }; unsigned char FirstJoin[] = { 1, 0, 0, 0 }; BYTEARRAY packet; packet.push_back( BNET_HEADER_CONSTANT ); // BNET header constant packet.push_back( SID_JOINCHANNEL ); // SID_JOINCHANNEL packet.push_back( 0 ); // packet length will be assigned later packet.push_back( 0 ); // packet length will be assigned later if( channel.size( ) > 0 ) UTIL_AppendByteArray( packet, NoCreateJoin, 4 ); // flags for no create join else UTIL_AppendByteArray( packet, FirstJoin, 4 ); // flags for first join UTIL_AppendByteArrayFast( packet, channel ); AssignLength( packet ); return packet; }
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( ); }
bool CBNETProtocol :: RECEIVE_SID_AUTH_INFO( BYTEARRAY data ) { // DEBUG_Print( "RECEIVED SID_AUTH_INFO" ); // DEBUG_Print( data ); // 2 bytes -> Header // 2 bytes -> Length // 4 bytes -> LogonType // 4 bytes -> ServerToken // 4 bytes -> ??? // 8 bytes -> MPQFileTime // null terminated string -> IX86VerFileName // null terminated string -> ValueStringFormula if( ValidateLength( data ) && data.size( ) >= 25 ) { m_LogonType = BYTEARRAY( data.begin( ) + 4, data.begin( ) + 8 ); m_ServerToken = BYTEARRAY( data.begin( ) + 8, data.begin( ) + 12 ); m_MPQFileTime = BYTEARRAY( data.begin( ) + 16, data.begin( ) + 24 ); m_IX86VerFileName = UTIL_ExtractCString( data, 24 ); m_ValueStringFormula = UTIL_ExtractCString( data, m_IX86VerFileName.size( ) + 25 ); return true; } return false; }
BYTEARRAY CGameProtocol :: SEND_W3GS_START_LAG( vector<CGamePlayer *> players, bool loadInGame ) { BYTEARRAY packet; unsigned char NumLaggers = 0; for( vector<CGamePlayer*> :: iterator i = players.begin(); i != players.end(); ++i ) { if( loadInGame ) { if( !(*i)->GetFinishedLoading() ) ++NumLaggers; } else { if( (*i)->GetLagging() ) ++NumLaggers; } } if( NumLaggers > 0 ) { packet.push_back( W3GS_HEADER_CONSTANT ); // W3GS header constant packet.push_back( W3GS_START_LAG ); // W3GS_START_LAG packet.push_back( 0 ); // packet length will be assigned later packet.push_back( 0 ); // packet length will be assigned later packet.push_back( NumLaggers ); for( vector<CGamePlayer*>::iterator i = players.begin(); i != players.end(); ++i ) { if( loadInGame ) { if( !(*i)->GetFinishedLoading() ) { packet.push_back( (*i)->GetPID() ); UTIL_AppendByteArray( packet, static_cast<uint32_t>(0), false ); } } else { if( (*i)->GetLagging() ) { packet.push_back( (*i)->GetPID() ); UTIL_AppendByteArray( packet, GetTicks() - (*i)->GetStartedLaggingTicks(), false ); } } } AssignLength( packet ); } else cout << "[GAMEPROTO] no laggers passed to SEND_W3GS_START_LAG\n"; return packet; }
BYTEARRAY CGameProtocol :: SEND_W3GS_INCOMING_ACTION( queue<CIncomingAction *> actions, uint16_t sendInterval ) { BYTEARRAY packet; packet.push_back( W3GS_HEADER_CONSTANT ); // W3GS header constant packet.push_back( W3GS_INCOMING_ACTION ); // W3GS_INCOMING_ACTION packet.push_back( 0 ); // packet length will be assigned later packet.push_back( 0 ); // packet length will be assigned later UTIL_AppendByteArray( packet, sendInterval, false ); // 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_ACTION" ); // DEBUG_Print( packet ); return packet; }
CIncomingJoinPlayer *CGameProtocol :: RECEIVE_W3GS_REQJOIN( BYTEARRAY data ) { // DEBUG_Print( "RECEIVED W3GS_REQJOIN" ); // DEBUG_Print( data ); // 2 bytes -> Header // 2 bytes -> Length // 4 bytes -> Host Counter (Game ID) // 4 bytes -> Entry Key (used in LAN) // 1 byte -> ??? // 2 bytes -> Listen Port // 4 bytes -> Peer Key // null terminated string -> Name // 4 bytes -> ??? // 2 bytes -> InternalPort (???) // 4 bytes -> InternalIP if( ValidateLength( data ) && data.size( ) >= 20 ) { uint32_t HostCounter = UTIL_ByteArrayToUInt32( data, false, 4 ); BYTEARRAY Name = UTIL_ExtractCString( data, 19 ); if( !Name.empty( ) && data.size( ) >= Name.size( ) + 30 ) { BYTEARRAY InternalIP = BYTEARRAY( data.begin( ) + Name.size( ) + 26, data.begin( ) + Name.size( ) + 30 ); return new CIncomingJoinPlayer( HostCounter, string( Name.begin( ), Name.end( ) ), InternalIP ); } } return NULL; }
BYTEARRAY CPUBProtocol :: SendLobbyPlayers( const string& gamename, const string& bot_ip, uint16_t gameport, vector<CGamePlayer>& nPlayers ) { BYTEARRAY packet; packet.push_back( PUB_HEADER_CONSTANT ); // Auth header 1 byte packet.push_back( PUB_GAMEPLAYERS ); // 1 byte packet.push_back( 0 ); // 1 byte packet.push_back( 0 ); // 1 byte UTIL_AppendByteArray( packet, gameport, false); UTIL_AppendByteArray( packet, bot_ip, true); UTIL_AppendByteArray( packet, gamename, true); packet.push_back( nPlayers.size() ); for (vector<CGamePlayer>::iterator i = nPlayers.begin(); i != nPlayers.end(); ++i) UTIL_AppendByteArray( packet, (*i).GetName(), true ); AssignLength(packet); return 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 ) > 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 CPotentialPlayer :: Update( void *fd ) { if( m_DeleteMe ) return true; if( !m_Socket ) return false; 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 while( Bytes.size( ) >= 4 ) { if( Bytes[0] == W3GS_HEADER_CONSTANT || Bytes[0] == GPS_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 ) { if( Bytes[0] == W3GS_HEADER_CONSTANT && Bytes[1] == CGameProtocol :: W3GS_REQJOIN ) { delete m_IncomingJoinPlayer; m_IncomingJoinPlayer = m_Protocol->RECEIVE_W3GS_REQJOIN( BYTEARRAY( Bytes.begin( ), Bytes.begin( ) + Length ) ); if( m_IncomingJoinPlayer ) m_Game->EventPlayerJoined( this, m_IncomingJoinPlayer ); // this is the packet which interests us for now, the remaining is left for CGamePlayer *RecvBuffer = RecvBuffer->substr( Length ); Bytes = BYTEARRAY( Bytes.begin( ) + Length, Bytes.end( ) ); break; } *RecvBuffer = RecvBuffer->substr( Length ); Bytes = BYTEARRAY( Bytes.begin( ) + Length, Bytes.end( ) ); } else break; } } } // don't call DoSend here because some other players may not have updated yet and may generate a packet for this player // also m_Socket may have been set to NULL during ProcessPackets but we're banking on the fact that m_DeleteMe has been set to true as well so it'll short circuit before dereferencing return m_DeleteMe || !m_Socket->GetConnected( ) || m_Socket->HasError( ); }
BYTEARRAY CPUBProtocol :: SendAllGameInfo( vector<CGame*> & nGameInfo ) { BYTEARRAY packet; packet.push_back( PUB_HEADER_CONSTANT ); // Auth header 1 byte packet.push_back( PUB_ALLGAMEINFO ); // 1 byte packet.push_back( 0 ); // 1 byte packet.push_back( 0 ); // 1 byte UTIL_AppendByteArray( packet, (uint16_t)nGameInfo.size(), false); for (vector<CGame*>::iterator i = nGameInfo.begin(); i != nGameInfo.end(); ++i) { UTIL_AppendByteArray( packet, (*i)->getName(), true ); UTIL_AppendByteArray( packet, GetTime() - (*i)->getStartedTime(), false ); } AssignLength(packet); return packet; }
void CReplay :: AddTimeSlot( uint16_t timeIncrement, queue<CIncomingAction *> actions ) { BYTEARRAY Block; Block.push_back( REPLAY_TIMESLOT ); UTIL_AppendByteArray( Block, (uint16_t)0, false ); UTIL_AppendByteArray( Block, timeIncrement, 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_Blocks.push( Block ); }
BYTEARRAY CBNETProtocol :: SEND_SID_GETADVLISTEX( string gameName ) { unsigned char MapFilter1[] = { 255, 3, 0, 0 }; unsigned char MapFilter2[] = { 255, 3, 0, 0 }; unsigned char MapFilter3[] = { 0, 0, 0, 0 }; unsigned char NumGames[] = { 1, 0, 0, 0 }; BYTEARRAY packet; packet.push_back( BNET_HEADER_CONSTANT ); // BNET header constant packet.push_back( SID_GETADVLISTEX ); // SID_GETADVLISTEX packet.push_back( 0 ); // packet length will be assigned later packet.push_back( 0 ); // packet length will be assigned later UTIL_AppendByteArray( packet, MapFilter1, 4 ); // Map Filter UTIL_AppendByteArray( packet, MapFilter2, 4 ); // Map Filter UTIL_AppendByteArray( packet, MapFilter3, 4 ); // Map Filter UTIL_AppendByteArray( packet, NumGames, 4 ); // maximum number of games to list UTIL_AppendByteArrayFast( packet, gameName ); // Game Name packet.push_back( 0 ); // Game Password is NULL packet.push_back( 0 ); // Game Stats is NULL AssignLength( packet ); return packet; }
uint32_t CGameProtocol :: RECEIVE_W3GS_LEAVEGAME( BYTEARRAY data ) { // DEBUG_Print( "RECEIVED W3GS_LEAVEGAME" ); // DEBUG_Print( data ); // 2 bytes -> Header // 2 bytes -> Length // 4 bytes -> Reason if( ValidateLength( data ) && data.size( ) >= 8 ) return UTIL_ByteArrayToUInt32( data, false, 4 ); return 0; }
BYTEARRAY CBNETProtocol :: SEND_SID_AUTH_INFO( unsigned char ver, bool TFT, uint32_t localeID, string countryAbbrev, string country ) { unsigned char ProtocolID[] = { 0, 0, 0, 0 }; unsigned char PlatformID[] = { 54, 56, 88, 73 }; // "IX86" unsigned char ProductID_ROC[] = { 51, 82, 65, 87 }; // "WAR3" unsigned char ProductID_TFT[] = { 80, 88, 51, 87 }; // "W3XP" unsigned char Version[] = { ver, 0, 0, 0 }; unsigned char Language[] = { 83, 85, 110, 101 }; // "enUS" unsigned char LocalIP[] = { 127, 0, 0, 1 }; unsigned char TimeZoneBias[] = { 44, 1, 0, 0 }; // 300 minutes (GMT -0500) BYTEARRAY packet; packet.push_back( BNET_HEADER_CONSTANT ); // BNET header constant packet.push_back( SID_AUTH_INFO ); // SID_AUTH_INFO packet.push_back( 0 ); // packet length will be assigned later packet.push_back( 0 ); // packet length will be assigned later UTIL_AppendByteArray( packet, ProtocolID, 4 ); // Protocol ID UTIL_AppendByteArray( packet, PlatformID, 4 ); // Platform ID 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, Language, 4 ); // Language (hardcoded as enUS to ensure battle.net sends the bot messages in English) UTIL_AppendByteArray( packet, LocalIP, 4 ); // Local IP for NAT compatibility UTIL_AppendByteArray( packet, TimeZoneBias, 4 ); // Time Zone Bias UTIL_AppendByteArray( packet, localeID, false ); // Locale ID UTIL_AppendByteArray( packet, localeID, false ); // Language ID (copying the locale ID should be sufficient since we don't care about sublanguages) UTIL_AppendByteArrayFast( packet, countryAbbrev ); // Country Abbreviation UTIL_AppendByteArrayFast( packet, country ); // Country AssignLength( packet ); // DEBUG_Print( "SENT SID_AUTH_INFO" ); // DEBUG_Print( packet ); return packet; }
BYTEARRAY CPUBProtocol :: SendVersionFailed( vector<CUpdaterFile>& nNotCompareFiles, const string& nDownloadUrl, uint32_t allSize ) { BYTEARRAY packet; packet.push_back( PUB_HEADER_CONSTANT ); packet.push_back( PUB_VERSION_FAILED ); packet.push_back( 0 ); // assign later packet.push_back( 0 ); // assign later UTIL_AppendByteArray( packet, (uint16_t)nNotCompareFiles.size(), false ); UTIL_AppendByteArray( packet, (uint32_t)allSize, false ); UTIL_AppendByteArray( packet, nDownloadUrl, true ); for ( vector<CUpdaterFile>::iterator i = nNotCompareFiles.begin(); i != nNotCompareFiles.end(); ++i ) { UTIL_AppendByteArray( packet, (uint32_t)(*i).getSize(), false ); UTIL_AppendByteArray( packet, (uint32_t)(*i).getSizeComp(), false ); UTIL_AppendByteArray( packet, (*i).getName(), true ); } AssignLength(packet); return packet; }
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; }
CIncomingChatEvent *CBNETProtocol :: RECEIVE_SID_CHATEVENT( BYTEARRAY data ) { // DEBUG_Print( "RECEIVED SID_CHATEVENT" ); // DEBUG_Print( data ); // 2 bytes -> Header // 2 bytes -> Length // 4 bytes -> EventID // 4 bytes -> UserFlags // 4 bytes -> Ping // 12 bytes -> ??? // null terminated string -> User // null terminated string -> Message if( ValidateLength( data ) && data.size( ) >= 29 ) { BYTEARRAY EventID = BYTEARRAY( data.begin( ) + 4, data.begin( ) + 8 ); BYTEARRAY UserFlags = BYTEARRAY( data.begin( ) + 8, data.begin( ) + 12 ); BYTEARRAY Ping = BYTEARRAY( data.begin( ) + 12, data.begin( ) + 16 ); BYTEARRAY User = UTIL_ExtractCString( data, 28 ); BYTEARRAY Message = UTIL_ExtractCString( data, User.size( ) + 29 ); switch( UTIL_ByteArrayToUInt32( EventID, false ) ) { case CBNETProtocol :: EID_SHOWUSER: case CBNETProtocol :: EID_JOIN: case CBNETProtocol :: EID_LEAVE: case CBNETProtocol :: EID_WHISPER: case CBNETProtocol :: EID_TALK: case CBNETProtocol :: EID_BROADCAST: case CBNETProtocol :: EID_CHANNEL: case CBNETProtocol :: EID_USERFLAGS: case CBNETProtocol :: EID_WHISPERSENT: case CBNETProtocol :: EID_CHANNELFULL: case CBNETProtocol :: EID_CHANNELDOESNOTEXIST: case CBNETProtocol :: EID_CHANNELRESTRICTED: case CBNETProtocol :: EID_INFO: case CBNETProtocol :: EID_ERROR: case CBNETProtocol :: EID_EMOTE: return new CIncomingChatEvent( (CBNETProtocol :: IncomingChatEvent)UTIL_ByteArrayToUInt32( EventID, false ), UTIL_ByteArrayToUInt32( UserFlags, false ), UTIL_ByteArrayToUInt32( Ping, false ), string( User.begin( ), User.end( ) ), string( Message.begin( ), Message.end( ) ) ); } } return NULL; }
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; }
bool CBNETProtocol :: RECEIVE_SID_ENTERCHAT( BYTEARRAY data ) { // DEBUG_Print( "RECEIVED SID_ENTERCHAT" ); // DEBUG_Print( data ); // 2 bytes -> Header // 2 bytes -> Length // null terminated string -> UniqueName if( ValidateLength( data ) && data.size( ) >= 5 ) { m_UniqueName = UTIL_ExtractCString( data, 4 ); return true; } return false; }
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; }
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 CReplay :: AddChatMessage( unsigned char PID, unsigned char flags, uint32_t chatMode, string message ) { BYTEARRAY Block; Block.push_back( REPLAY_CHATMESSAGE ); Block.push_back( PID ); UTIL_AppendByteArray( Block, (uint16_t)0, false ); Block.push_back( flags ); UTIL_AppendByteArray( Block, chatMode, false ); UTIL_AppendByteArrayFast( Block, message ); // assign length BYTEARRAY LengthBytes = UTIL_CreateByteArray( (uint16_t)( Block.size( ) - 4 ), false ); Block[2] = LengthBytes[0]; Block[3] = LengthBytes[1]; m_CompiledBlocks += string( Block.begin( ), Block.end( ) ); }