diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /common/netmessages.cpp | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'common/netmessages.cpp')
| -rw-r--r-- | common/netmessages.cpp | 2069 |
1 files changed, 2069 insertions, 0 deletions
diff --git a/common/netmessages.cpp b/common/netmessages.cpp new file mode 100644 index 0000000..699f483 --- /dev/null +++ b/common/netmessages.cpp @@ -0,0 +1,2069 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "netmessages.h" +#include "bitbuf.h" +#include "const.h" +#include "../engine/net_chan.h" +#include "mathlib/mathlib.h" +#include "networkstringtabledefs.h" +#include "../engine/event_system.h" +#include "../engine/dt.h" +#include "tier0/vprof.h" +#include "convar.h" + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +// XXX(JohnS): This is no longer used, but we're keeping it so we can check if old network streams set it to work around +// missing information in the older SVC_VoiceInit packet. See SVC_VoiceInit::ReadFromBuffer +ConVar sv_use_steam_voice( "sv_use_steam_voice", "0", FCVAR_HIDDEN | FCVAR_REPLICATED, + "Deprecated - placeholder convar for handling old network streams that " + "had an incomplete SVC_VoiceInit packet. Use \"sv_voicecodec steam\"" ); + +static char s_text[1024]; + +const char *CLC_VoiceData::ToString(void) const +{ + Q_snprintf(s_text, sizeof(s_text), "%s: %i bytes", GetName(), Bits2Bytes(m_nLength) ); + return s_text; +} + +bool CLC_VoiceData::WriteToBuffer( bf_write &buffer ) +{ + buffer.WriteUBitLong( GetType(), NETMSG_TYPE_BITS ); + + m_nLength = m_DataOut.GetNumBitsWritten(); + + buffer.WriteWord( m_nLength ); // length in bits + + //Send this client's XUID (only needed on the 360) +#if defined ( _X360 ) + buffer.WriteLongLong( m_xuid ); +#endif + + return buffer.WriteBits( m_DataOut.GetBasePointer(), m_nLength ); +} + +bool CLC_VoiceData::ReadFromBuffer( bf_read &buffer ) +{ + VPROF( "CLC_VoiceData::ReadFromBuffer" ); + + m_nLength = buffer.ReadWord(); // length in bits + +#if defined ( _X360 ) + m_xuid = buffer.ReadLongLong(); +#endif + + m_DataIn = buffer; + + return buffer.SeekRelative( m_nLength ); +} + +const char *CLC_Move::ToString(void) const +{ + Q_snprintf(s_text, sizeof(s_text), "%s: backup %i, new %i, bytes %i", GetName(), + m_nNewCommands, m_nBackupCommands, Bits2Bytes(m_nLength) ); + return s_text; +} + +bool CLC_Move::WriteToBuffer( bf_write &buffer ) +{ + buffer.WriteUBitLong( GetType(), NETMSG_TYPE_BITS ); + m_nLength = m_DataOut.GetNumBitsWritten(); + + buffer.WriteUBitLong( m_nNewCommands, NUM_NEW_COMMAND_BITS ); + buffer.WriteUBitLong( m_nBackupCommands, NUM_BACKUP_COMMAND_BITS ); + + buffer.WriteWord( m_nLength ); + + return buffer.WriteBits( m_DataOut.GetData(), m_nLength ); +} + +bool CLC_Move::ReadFromBuffer( bf_read &buffer ) +{ + VPROF( "CLC_Move::ReadFromBuffer" ); + + m_nNewCommands = buffer.ReadUBitLong( NUM_NEW_COMMAND_BITS ); + m_nBackupCommands = buffer.ReadUBitLong( NUM_BACKUP_COMMAND_BITS ); + m_nLength = buffer.ReadWord(); + m_DataIn = buffer; + return buffer.SeekRelative( m_nLength ); +} + +const char *CLC_ClientInfo::ToString(void) const +{ + Q_snprintf(s_text, sizeof(s_text), "%s: SendTableCRC %i", GetName(), + m_nSendTableCRC ); + return s_text; +} + +bool CLC_ClientInfo::WriteToBuffer( bf_write &buffer ) +{ + buffer.WriteUBitLong( GetType(), NETMSG_TYPE_BITS ); + + buffer.WriteLong( m_nServerCount ); + buffer.WriteLong( m_nSendTableCRC ); + buffer.WriteOneBit( m_bIsHLTV?1:0 ); + buffer.WriteLong( m_nFriendsID ); + buffer.WriteString( m_FriendsName ); + + for ( int i=0; i<MAX_CUSTOM_FILES; i++ ) + { + if ( m_nCustomFiles[i] != 0 ) + { + buffer.WriteOneBit( 1 ); + buffer.WriteUBitLong( m_nCustomFiles[i], 32 ); + } + else + { + buffer.WriteOneBit( 0 ); + } + } + +#if defined( REPLAY_ENABLED ) + buffer.WriteOneBit( m_bIsReplay?1:0 ); +#endif + + return !buffer.IsOverflowed(); +} + +bool CLC_ClientInfo::ReadFromBuffer( bf_read &buffer ) +{ + VPROF( "CLC_ClientInfo::ReadFromBuffer" ); + + m_nServerCount = buffer.ReadLong(); + m_nSendTableCRC = buffer.ReadLong(); + m_bIsHLTV = buffer.ReadOneBit()!=0; + m_nFriendsID = buffer.ReadLong(); + buffer.ReadString( m_FriendsName, sizeof(m_FriendsName) ); + + for ( int i=0; i<MAX_CUSTOM_FILES; i++ ) + { + if ( buffer.ReadOneBit() != 0 ) + { + m_nCustomFiles[i] = buffer.ReadUBitLong( 32 ); + } + else + { + m_nCustomFiles[i] = 0; + } + } + +#if defined( REPLAY_ENABLED ) + m_bIsReplay = buffer.ReadOneBit()!=0; +#endif + + return !buffer.IsOverflowed(); +} + +bool CLC_BaselineAck::WriteToBuffer( bf_write &buffer ) +{ + buffer.WriteUBitLong( GetType(), NETMSG_TYPE_BITS ); + buffer.WriteLong( m_nBaselineTick ); + buffer.WriteUBitLong( m_nBaselineNr, 1 ); + return !buffer.IsOverflowed(); +} + +bool CLC_BaselineAck::ReadFromBuffer( bf_read &buffer ) +{ + VPROF( "CLC_BaselineAck::ReadFromBuffer" ); + + m_nBaselineTick = buffer.ReadLong(); + m_nBaselineNr = buffer.ReadUBitLong( 1 ); + return !buffer.IsOverflowed(); +} + +const char *CLC_BaselineAck::ToString(void) const +{ + Q_snprintf(s_text, sizeof(s_text), "%s: tick %i", GetName(), m_nBaselineTick ); + return s_text; +} + +bool CLC_ListenEvents::WriteToBuffer( bf_write &buffer ) +{ + buffer.WriteUBitLong( GetType(), NETMSG_TYPE_BITS ); + + int count = MAX_EVENT_NUMBER / 32; + for ( int i = 0; i < count; ++i ) + { + buffer.WriteUBitLong( m_EventArray.GetDWord( i ), 32 ); + } + + return !buffer.IsOverflowed(); +} + +bool CLC_ListenEvents::ReadFromBuffer( bf_read &buffer ) +{ + VPROF( "CLC_ListenEvents::ReadFromBuffer" ); + + int count = MAX_EVENT_NUMBER / 32; + for ( int i = 0; i < count; ++i ) + { + m_EventArray.SetDWord( i, buffer.ReadUBitLong( 32 ) ); + } + + return !buffer.IsOverflowed(); +} + +const char *CLC_ListenEvents::ToString(void) const +{ + int count = 0; + + for ( int i = 0; i<MAX_EVENT_NUMBER; i++ ) + { + if ( m_EventArray.Get( i ) ) + count++; + } + + Q_snprintf(s_text, sizeof(s_text), "%s: registered events %i", GetName(), count ); + return s_text; +} + + +bool CLC_RespondCvarValue::WriteToBuffer( bf_write &buffer ) +{ + buffer.WriteUBitLong( GetType(), NETMSG_TYPE_BITS ); + + buffer.WriteSBitLong( m_iCookie, 32 ); + buffer.WriteSBitLong( m_eStatusCode, 4 ); + + buffer.WriteString( m_szCvarName ); + buffer.WriteString( m_szCvarValue ); + + return !buffer.IsOverflowed(); +} + +bool CLC_RespondCvarValue::ReadFromBuffer( bf_read &buffer ) +{ + VPROF( "CLC_RespondCvarValue::ReadFromBuffer" ); + + m_iCookie = buffer.ReadSBitLong( 32 ); + m_eStatusCode = (EQueryCvarValueStatus)buffer.ReadSBitLong( 4 ); + + // Read the name. + buffer.ReadString( m_szCvarNameBuffer, sizeof( m_szCvarNameBuffer ) ); + m_szCvarName = m_szCvarNameBuffer; + + // Read the value. + buffer.ReadString( m_szCvarValueBuffer, sizeof( m_szCvarValueBuffer ) ); + m_szCvarValue = m_szCvarValueBuffer; + + return !buffer.IsOverflowed(); +} + +const char *CLC_RespondCvarValue::ToString(void) const +{ + Q_snprintf( s_text, sizeof(s_text), "%s: status: %d, value: %s, cookie: %d", GetName(), m_eStatusCode, m_szCvarValue, m_iCookie ); + return s_text; +} + + + +const char *g_MostCommonPathIDs[] = +{ + "GAME", + "MOD" +}; + +const char *g_MostCommonPrefixes[] = +{ + "materials", + "models", + "sounds", + "scripts" +}; + +static int FindCommonPathID( const char *pPathID ) +{ + for ( int i=0; i < ARRAYSIZE( g_MostCommonPathIDs ); i++ ) + { + if ( V_stricmp( pPathID, g_MostCommonPathIDs[i] ) == 0 ) + return i; + } + return -1; +} + +static int FindCommonPrefix( const char *pStr ) +{ + for ( int i=0; i < ARRAYSIZE( g_MostCommonPrefixes ); i++ ) + { + if ( V_stristr( pStr, g_MostCommonPrefixes[i] ) == pStr ) + { + int iNextChar = V_strlen( g_MostCommonPrefixes[i] ); + if ( pStr[iNextChar] == '/' || pStr[iNextChar] == '\\' ) + return i; + } + } + return -1; +} + + +bool CLC_FileCRCCheck::WriteToBuffer( bf_write &buffer ) +{ + buffer.WriteUBitLong( GetType(), NETMSG_TYPE_BITS ); + + // Reserved for future use. + buffer.WriteOneBit( 0 ); + + // Just write a couple bits for the path ID if it's one of the common ones. + int iCode = FindCommonPathID( m_szPathID ); + if ( iCode == -1 ) + { + buffer.WriteUBitLong( 0, 2 ); + buffer.WriteString( m_szPathID ); + } + else + { + buffer.WriteUBitLong( iCode+1, 2 ); + } + + iCode = FindCommonPrefix( m_szFilename ); + if ( iCode == -1 ) + { + buffer.WriteUBitLong( 0, 3 ); + buffer.WriteChar( 1 ); // so we can detect the new message version + buffer.WriteString( m_szFilename ); + } + else + { + buffer.WriteUBitLong( iCode+1, 3 ); + buffer.WriteChar( 1 ); // so we can detect the new message version + buffer.WriteString( &m_szFilename[ V_strlen(g_MostCommonPrefixes[iCode])+1 ] ); + } + + buffer.WriteBits( &m_MD5.bits, sizeof(m_MD5.bits)*8 ); + buffer.WriteUBitLong( m_CRCIOs, 32 ); + buffer.WriteUBitLong( m_eFileHashType, 32 ); + buffer.WriteUBitLong( m_cbFileLen, 32 ); + buffer.WriteUBitLong( m_nPackFileNumber, 32 ); + buffer.WriteUBitLong( m_PackFileID, 32 ); + buffer.WriteUBitLong( m_nFileFraction, 32 ); + return !buffer.IsOverflowed(); +} + +bool CLC_FileCRCCheck::ReadFromBuffer( bf_read &buffer ) +{ + VPROF( "CLC_FileCRCCheck::ReadFromBuffer" ); + + // Reserved for future use. + buffer.ReadOneBit(); + + // Read the path ID. + int iCode = buffer.ReadUBitLong( 2 ); + if ( iCode == 0 ) + { + buffer.ReadString( m_szPathID, sizeof( m_szPathID ) ); + } + else if ( (iCode-1) < ARRAYSIZE( g_MostCommonPathIDs ) ) + { + V_strncpy( m_szPathID, g_MostCommonPathIDs[iCode-1], sizeof( m_szPathID ) ); + } + else + { + Assert( !"Invalid path ID code in CLC_FileCRCCheck" ); + return false; + } + + // Prefix string + iCode = buffer.ReadUBitLong( 3 ); + + // Read filename, and check for the new message format version? + char szTemp[ MAX_PATH ]; + int c = buffer.ReadChar(); + bool bNewVersion = false; + if ( c == 1 ) + { + bNewVersion = true; + buffer.ReadString( szTemp, sizeof( szTemp ) ); + } + else + { + szTemp[0] = (char)c; + buffer.ReadString( szTemp+1, sizeof( szTemp)-1 ); + } + if ( iCode == 0 ) + { + V_strcpy_safe( m_szFilename, szTemp ); + } + else if ( (iCode-1) < ARRAYSIZE( g_MostCommonPrefixes ) ) + { + V_sprintf_safe( m_szFilename, "%s%c%s", g_MostCommonPrefixes[iCode-1], CORRECT_PATH_SEPARATOR, szTemp ); + } + else + { + Assert( !"Invalid prefix code in CLC_FileCRCCheck." ); + return false; + } + + if ( bNewVersion ) + { + buffer.ReadBits( &m_MD5.bits, sizeof(m_MD5.bits)*8 ); + m_CRCIOs = buffer.ReadUBitLong( 32 ); + m_eFileHashType = buffer.ReadUBitLong( 32 ); + m_cbFileLen = buffer.ReadUBitLong( 32 ); + m_nPackFileNumber = buffer.ReadUBitLong( 32 ); + m_PackFileID = buffer.ReadUBitLong( 32 ); + m_nFileFraction = buffer.ReadUBitLong( 32 ); + } + else + { + /* m_CRC */ buffer.ReadUBitLong( 32 ); + m_CRCIOs = buffer.ReadUBitLong( 32 ); + m_eFileHashType = buffer.ReadUBitLong( 32 ); + } + + return !buffer.IsOverflowed(); +} + +const char *CLC_FileCRCCheck::ToString(void) const +{ + V_snprintf( s_text, sizeof(s_text), "%s: path: %s, file: %s", GetName(), m_szPathID, m_szFilename ); + return s_text; +} + +bool CLC_FileMD5Check::WriteToBuffer( bf_write &buffer ) +{ + buffer.WriteUBitLong( GetType(), NETMSG_TYPE_BITS ); + + // Reserved for future use. + buffer.WriteOneBit( 0 ); + + // Just write a couple bits for the path ID if it's one of the common ones. + int iCode = FindCommonPathID( m_szPathID ); + if ( iCode == -1 ) + { + buffer.WriteUBitLong( 0, 2 ); + buffer.WriteString( m_szPathID ); + } + else + { + buffer.WriteUBitLong( iCode+1, 2 ); + } + + iCode = FindCommonPrefix( m_szFilename ); + if ( iCode == -1 ) + { + buffer.WriteUBitLong( 0, 3 ); + buffer.WriteString( m_szFilename ); + } + else + { + buffer.WriteUBitLong( iCode+1, 3 ); + buffer.WriteString( &m_szFilename[ V_strlen(g_MostCommonPrefixes[iCode])+1 ] ); + } + + buffer.WriteBytes( m_MD5.bits, MD5_DIGEST_LENGTH ); + return !buffer.IsOverflowed(); +} + +bool CLC_FileMD5Check::ReadFromBuffer( bf_read &buffer ) +{ + VPROF( "CLC_FileMD5Check::ReadFromBuffer" ); + + // Reserved for future use. + buffer.ReadOneBit(); + + // Read the path ID. + int iCode = buffer.ReadUBitLong( 2 ); + if ( iCode == 0 ) + { + buffer.ReadString( m_szPathID, sizeof( m_szPathID ) ); + } + else if ( (iCode-1) < ARRAYSIZE( g_MostCommonPathIDs ) ) + { + V_strncpy( m_szPathID, g_MostCommonPathIDs[iCode-1], sizeof( m_szPathID ) ); + } + else + { + Assert( !"Invalid path ID code in CLC_FileMD5Check" ); + return false; + } + + // Read the filename. + iCode = buffer.ReadUBitLong( 3 ); + if ( iCode == 0 ) + { + buffer.ReadString( m_szFilename, sizeof( m_szFilename ) ); + } + else if ( (iCode-1) < ARRAYSIZE( g_MostCommonPrefixes ) ) + { + char szTemp[MAX_PATH]; + buffer.ReadString( szTemp, sizeof( szTemp ) ); + V_snprintf( m_szFilename, sizeof( m_szFilename ), "%s%c%s", g_MostCommonPrefixes[iCode-1], CORRECT_PATH_SEPARATOR, szTemp ); + } + else + { + Assert( !"Invalid prefix code in CLC_FileMD5Check." ); + return false; + } + + buffer.ReadBytes( m_MD5.bits, MD5_DIGEST_LENGTH ); + + return !buffer.IsOverflowed(); +} + +const char *CLC_FileMD5Check::ToString(void) const +{ + V_snprintf( s_text, sizeof(s_text), "%s: path: %s, file: %s", GetName(), m_szPathID, m_szFilename ); + return s_text; +} + +#if defined( REPLAY_ENABLED ) +bool CLC_SaveReplay::WriteToBuffer( bf_write &buffer ) +{ + buffer.WriteUBitLong( GetType(), NETMSG_TYPE_BITS ); + buffer.WriteString( m_szFilename ); + buffer.WriteUBitLong( m_nStartSendByte, sizeof( m_nStartSendByte ) ); + buffer.WriteFloat( m_flPostDeathRecordTime ); + return !buffer.IsOverflowed(); +} + +bool CLC_SaveReplay::ReadFromBuffer( bf_read &buffer ) +{ + buffer.ReadString( m_szFilename, sizeof( m_szFilename ) ); + m_nStartSendByte = buffer.ReadUBitLong( sizeof( m_nStartSendByte ) ); + m_flPostDeathRecordTime = buffer.ReadFloat(); + return !buffer.IsOverflowed(); +} + +const char *CLC_SaveReplay::ToString() const +{ + V_snprintf( s_text, sizeof( s_text ), "%s: filename: %s, start byte: %i, post death record time: %f", GetName(), m_szFilename, m_nStartSendByte, m_flPostDeathRecordTime ); + return s_text; +} +#endif + + +// +// CmdKeyValues message +// + +Base_CmdKeyValues::Base_CmdKeyValues( KeyValues *pKeyValues /* = NULL */ ) : + m_pKeyValues( pKeyValues ) +{ +} + +Base_CmdKeyValues::~Base_CmdKeyValues() +{ + if ( m_pKeyValues ) + m_pKeyValues->deleteThis(); + m_pKeyValues = NULL; +} + +bool Base_CmdKeyValues::WriteToBuffer( bf_write &buffer ) +{ + Assert( m_pKeyValues ); + if ( !m_pKeyValues ) + return false; + + buffer.WriteUBitLong( GetType(), NETMSG_TYPE_BITS ); + + CUtlBuffer bufData; + if ( !m_pKeyValues->WriteAsBinary( bufData ) ) + { + Assert( false ); + return false; + } + + // Note how many we're sending + int numBytes = bufData.TellMaxPut(); + buffer.WriteLong( numBytes ); + buffer.WriteBits( bufData.Base(), numBytes * 8 ); + + return !buffer.IsOverflowed(); +} + +bool Base_CmdKeyValues::ReadFromBuffer( bf_read &buffer ) +{ + VPROF( "Base_CmdKeyValues::ReadFromBuffer" ); + + if ( !m_pKeyValues ) + m_pKeyValues = new KeyValues( "" ); + + m_pKeyValues->Clear(); + + int numBytes = buffer.ReadLong(); + if ( numBytes <= 0 || numBytes > buffer.GetNumBytesLeft() ) + { + return false; // don't read past the end of the buffer + } + + void *pvBuffer = malloc( numBytes ); + if ( !pvBuffer ) + { + return false; + } + + buffer.ReadBits( pvBuffer, numBytes * 8 ); + + CUtlBuffer bufRead( pvBuffer, numBytes, CUtlBuffer::READ_ONLY ); + if ( !m_pKeyValues->ReadAsBinary( bufRead ) ) + { + Assert( false ); + free( pvBuffer ); + return false; + } + + free( pvBuffer ); + return !buffer.IsOverflowed(); +} + +const char * Base_CmdKeyValues::ToString(void) const +{ + Q_snprintf( s_text, sizeof(s_text), "%s: %s", + GetName(), m_pKeyValues ? m_pKeyValues->GetName() : "<<null>>" ); + return s_text; +} + +CLC_CmdKeyValues::CLC_CmdKeyValues( KeyValues *pKeyValues /* = NULL */ ) : Base_CmdKeyValues( pKeyValues ) +{ +} + +bool CLC_CmdKeyValues::WriteToBuffer( bf_write &buffer ) +{ + return Base_CmdKeyValues::WriteToBuffer( buffer ); +} + +bool CLC_CmdKeyValues::ReadFromBuffer( bf_read &buffer ) +{ + return Base_CmdKeyValues::ReadFromBuffer( buffer ); +} + +const char *CLC_CmdKeyValues::ToString(void) const +{ + return Base_CmdKeyValues::ToString(); +} + +SVC_CmdKeyValues::SVC_CmdKeyValues( KeyValues *pKeyValues /* = NULL */ ) : Base_CmdKeyValues( pKeyValues ) +{ +} + +bool SVC_CmdKeyValues::WriteToBuffer( bf_write &buffer ) +{ + return Base_CmdKeyValues::WriteToBuffer( buffer ); +} + +bool SVC_CmdKeyValues::ReadFromBuffer( bf_read &buffer ) +{ + return Base_CmdKeyValues::ReadFromBuffer( buffer ); +} + +const char *SVC_CmdKeyValues::ToString(void) const +{ + return Base_CmdKeyValues::ToString(); +} + + +// +// SVC_Print message +// + +bool SVC_Print::WriteToBuffer( bf_write &buffer ) +{ + buffer.WriteUBitLong( GetType(), NETMSG_TYPE_BITS ); + return buffer.WriteString( m_szText ? m_szText : " svc_print NULL" ); +} + +bool SVC_Print::ReadFromBuffer( bf_read &buffer ) +{ + VPROF( "SVC_Print::ReadFromBuffer" ); + + m_szText = m_szTextBuffer; + + return buffer.ReadString(m_szTextBuffer, sizeof(m_szTextBuffer) ); +} + +const char *SVC_Print::ToString(void) const +{ + Q_snprintf(s_text, sizeof(s_text), "%s: \"%s\"", GetName(), m_szText ); + return s_text; +} + +bool NET_StringCmd::WriteToBuffer( bf_write &buffer ) +{ + buffer.WriteUBitLong( GetType(), NETMSG_TYPE_BITS ); + return buffer.WriteString( m_szCommand ? m_szCommand : " NET_StringCmd NULL" ); +} + +bool NET_StringCmd::ReadFromBuffer( bf_read &buffer ) +{ + VPROF( "NET_StringCmd::ReadFromBuffer" ); + + m_szCommand = m_szCommandBuffer; + + return buffer.ReadString(m_szCommandBuffer, sizeof(m_szCommandBuffer) ); +} + +const char *NET_StringCmd::ToString(void) const +{ + Q_snprintf(s_text, sizeof(s_text), "%s: \"%s\"", GetName(), m_szCommand ); + return s_text; +} + +bool SVC_ServerInfo::WriteToBuffer( bf_write &buffer ) +{ + buffer.WriteUBitLong( GetType(), NETMSG_TYPE_BITS ); + buffer.WriteShort ( m_nProtocol ); + buffer.WriteLong ( m_nServerCount ); + buffer.WriteOneBit( m_bIsHLTV?1:0); + buffer.WriteOneBit( m_bIsDedicated?1:0); + buffer.WriteLong ( 0xffffffff ); // Used to be client.dll CRC. This was far before signed binaries, VAC, and cross-platform play + buffer.WriteWord ( m_nMaxClasses ); + buffer.WriteBytes( m_nMapMD5.bits, MD5_DIGEST_LENGTH ); // To prevent cheating with hacked maps + buffer.WriteByte ( m_nPlayerSlot ); + buffer.WriteByte ( m_nMaxClients ); + buffer.WriteFloat ( m_fTickInterval ); + buffer.WriteChar ( m_cOS ); + buffer.WriteString( m_szGameDir ); + buffer.WriteString( m_szMapName ); + buffer.WriteString( m_szSkyName ); + buffer.WriteString( m_szHostName ); + +#if defined( REPLAY_ENABLED ) + buffer.WriteOneBit( m_bIsReplay?1:0); +#endif + + return !buffer.IsOverflowed(); +} + +bool SVC_ServerInfo::ReadFromBuffer( bf_read &buffer ) +{ + VPROF( "SVC_ServerInfo::ReadFromBuffer" ); + + m_szGameDir = m_szGameDirBuffer; + m_szMapName = m_szMapNameBuffer; + m_szSkyName = m_szSkyNameBuffer; + m_szHostName = m_szHostNameBuffer; + + m_nProtocol = buffer.ReadShort(); + m_nServerCount = buffer.ReadLong(); + m_bIsHLTV = buffer.ReadOneBit()!=0; + m_bIsDedicated = buffer.ReadOneBit()!=0; + buffer.ReadLong(); // Legacy client CRC. + m_nMaxClasses = buffer.ReadWord(); + + // Prevent cheating with hacked maps + if ( m_nProtocol > PROTOCOL_VERSION_17 ) + { + buffer.ReadBytes( m_nMapMD5.bits, MD5_DIGEST_LENGTH ); + } + else + { + m_nMapCRC = buffer.ReadLong(); + } + + m_nPlayerSlot = buffer.ReadByte(); + m_nMaxClients = buffer.ReadByte(); + m_fTickInterval = buffer.ReadFloat(); + m_cOS = buffer.ReadChar(); + buffer.ReadString( m_szGameDirBuffer, sizeof(m_szGameDirBuffer) ); + buffer.ReadString( m_szMapNameBuffer, sizeof(m_szMapNameBuffer) ); + buffer.ReadString( m_szSkyNameBuffer, sizeof(m_szSkyNameBuffer) ); + buffer.ReadString( m_szHostNameBuffer, sizeof(m_szHostNameBuffer) ); + +#if defined( REPLAY_ENABLED ) + // Only attempt to read the 'replay' bit if the net channel's protocol + // version is greater or equal than the protocol version for replay's release. + // INetChannel::GetProtocolVersion() will return PROTOCOL_VERSION for + // a regular net channel, or the network protocol version from the demo + // file, if we're playing back a demo. + if ( m_NetChannel->GetProtocolVersion() >= PROTOCOL_VERSION_REPLAY ) + { + m_bIsReplay = buffer.ReadOneBit() != 0; + } +#endif + + return !buffer.IsOverflowed(); +} + +const char *SVC_ServerInfo::ToString(void) const +{ + Q_snprintf(s_text, sizeof(s_text), "%s: game \"%s\", map \"%s\", max %i", GetName(), m_szGameDir, m_szMapName, m_nMaxClients ); + return s_text; +} + +bool NET_SignonState::WriteToBuffer( bf_write &buffer ) +{ + buffer.WriteUBitLong( GetType(), NETMSG_TYPE_BITS ); + buffer.WriteByte( m_nSignonState ); + buffer.WriteLong( m_nSpawnCount ); + + return !buffer.IsOverflowed(); +} + +bool NET_SignonState::ReadFromBuffer( bf_read &buffer ) +{ + VPROF( "NET_SignonState::ReadFromBuffer" ); + + m_nSignonState = buffer.ReadByte(); + m_nSpawnCount = buffer.ReadLong(); + + return !buffer.IsOverflowed(); +} + +const char *NET_SignonState::ToString(void) const +{ + Q_snprintf(s_text, sizeof(s_text), "%s: state %i, count %i", GetName(), m_nSignonState, m_nSpawnCount ); + return s_text; +} + +bool SVC_BSPDecal::WriteToBuffer( bf_write &buffer ) +{ + buffer.WriteUBitLong( GetType(), NETMSG_TYPE_BITS ); + buffer.WriteBitVec3Coord( m_Pos ); + buffer.WriteUBitLong( m_nDecalTextureIndex, MAX_DECAL_INDEX_BITS ); + + if ( m_nEntityIndex != 0) + { + buffer.WriteOneBit( 1 ); + buffer.WriteUBitLong( m_nEntityIndex, MAX_EDICT_BITS ); + buffer.WriteUBitLong( m_nModelIndex, SP_MODEL_INDEX_BITS ); + } + else + { + buffer.WriteOneBit( 0 ); + } + buffer.WriteOneBit( m_bLowPriority ? 1 : 0 ); + + return !buffer.IsOverflowed(); +} + +bool SVC_BSPDecal::ReadFromBuffer( bf_read &buffer ) +{ + VPROF( "SVC_BSPDecal::ReadFromBuffer" ); + + buffer.ReadBitVec3Coord( m_Pos ); + m_nDecalTextureIndex = buffer.ReadUBitLong( MAX_DECAL_INDEX_BITS ); + + if ( buffer.ReadOneBit() != 0 ) + { + m_nEntityIndex = buffer.ReadUBitLong( MAX_EDICT_BITS ); + m_nModelIndex = buffer.ReadUBitLong( SP_MODEL_INDEX_BITS ); + } + else + { + m_nEntityIndex = 0; + m_nModelIndex = 0; + } + m_bLowPriority = buffer.ReadOneBit() ? true : false; + + return !buffer.IsOverflowed(); +} + +const char *SVC_BSPDecal::ToString(void) const +{ + Q_snprintf(s_text, sizeof(s_text), "%s: tex %i, ent %i, mod %i lowpriority %i", + GetName(), m_nDecalTextureIndex, m_nEntityIndex, m_nModelIndex, m_bLowPriority ? 1 : 0 ); + return s_text; +} + +bool SVC_SetView::WriteToBuffer( bf_write &buffer ) +{ + buffer.WriteUBitLong( GetType(), NETMSG_TYPE_BITS ); + buffer.WriteUBitLong( m_nEntityIndex, MAX_EDICT_BITS ); + return !buffer.IsOverflowed(); +} + +bool SVC_SetView::ReadFromBuffer( bf_read &buffer ) +{ + VPROF( "SVC_SetView::ReadFromBuffer" ); + + m_nEntityIndex = buffer.ReadUBitLong( MAX_EDICT_BITS ); + return !buffer.IsOverflowed(); +} + +const char *SVC_SetView::ToString(void) const +{ + Q_snprintf(s_text, sizeof(s_text), "%s: view entity %i", GetName(), m_nEntityIndex ); + return s_text; +} + +bool SVC_FixAngle::WriteToBuffer( bf_write &buffer ) +{ + buffer.WriteUBitLong( GetType(), NETMSG_TYPE_BITS ); + buffer.WriteOneBit( m_bRelative ? 1 : 0 ); + buffer.WriteBitAngle( m_Angle.x, 16 ); + buffer.WriteBitAngle( m_Angle.y, 16 ); + buffer.WriteBitAngle( m_Angle.z, 16 ); + return !buffer.IsOverflowed(); +} + +bool SVC_FixAngle::ReadFromBuffer( bf_read &buffer ) +{ + VPROF( "SVC_FixAngle::ReadFromBuffer" ); + + m_bRelative = buffer.ReadOneBit() != 0; + m_Angle.x = buffer.ReadBitAngle( 16 ); + m_Angle.y = buffer.ReadBitAngle( 16 ); + m_Angle.z = buffer.ReadBitAngle( 16 ); + return !buffer.IsOverflowed(); +} + +const char *SVC_FixAngle::ToString(void) const +{ + Q_snprintf(s_text, sizeof(s_text), "%s: %s %.1f %.1f %.1f ", GetName(), m_bRelative?"relative":"absolute", + m_Angle[0], m_Angle[1], m_Angle[2] ); + return s_text; +} + +bool SVC_CrosshairAngle::WriteToBuffer( bf_write &buffer ) +{ + buffer.WriteUBitLong( GetType(), NETMSG_TYPE_BITS ); + buffer.WriteBitAngle( m_Angle.x, 16 ); + buffer.WriteBitAngle( m_Angle.y, 16 ); + buffer.WriteBitAngle( m_Angle.z, 16 ); + return !buffer.IsOverflowed(); +} + +bool SVC_CrosshairAngle::ReadFromBuffer( bf_read &buffer ) +{ + VPROF( "SVC_CrosshairAngle::ReadFromBuffer" ); + + m_Angle.x = buffer.ReadBitAngle( 16 ); + m_Angle.y = buffer.ReadBitAngle( 16 ); + m_Angle.z = buffer.ReadBitAngle( 16 ); + return !buffer.IsOverflowed(); +} + +const char *SVC_CrosshairAngle::ToString(void) const +{ + Q_snprintf(s_text, sizeof(s_text), "%s: (%.1f %.1f %.1f)", GetName(), m_Angle[0], m_Angle[1], m_Angle[2] ); + return s_text; +} + +bool SVC_VoiceInit::WriteToBuffer( bf_write &buffer ) +{ + buffer.WriteUBitLong( GetType(), NETMSG_TYPE_BITS ); + buffer.WriteString( m_szVoiceCodec ); + buffer.WriteByte( /* Legacy Quality Field */ 255 ); + buffer.WriteShort( m_nSampleRate ); + return !buffer.IsOverflowed(); +} + +bool SVC_VoiceInit::ReadFromBuffer( bf_read &buffer ) +{ + VPROF( "SVC_VoiceInit::ReadFromBuffer" ); + + buffer.ReadString( m_szVoiceCodec, sizeof(m_szVoiceCodec) ); + unsigned char nLegacyQuality = buffer.ReadByte(); + if ( nLegacyQuality == 255 ) + { + // v2 packet + m_nSampleRate = buffer.ReadShort(); + } + else + { + // v1 packet + // + // Hacky workaround for v1 packets not actually indicating if we were using steam voice -- we've kept the steam + // voice separate convar that was in use at the time as replicated&hidden, and if whatever network stream we're + // interpreting sets it, lie about the subsequent voice init's codec & sample rate. + if ( sv_use_steam_voice.GetBool() ) + { + Msg( "Legacy SVC_VoiceInit - got a set for sv_use_steam_voice convar, assuming Steam voice\n" ); + V_strncpy( m_szVoiceCodec, "steam", sizeof( m_szVoiceCodec ) ); + // Legacy steam voice can always be parsed as auto sample rate. + m_nSampleRate = 0; + } + else if ( V_strncasecmp( m_szVoiceCodec, "vaudio_celt", sizeof( m_szVoiceCodec ) ) == 0 ) + { + // Legacy rate vaudio_celt always selected during v1 packet era + m_nSampleRate = 22050; + } + else + { + // Legacy rate everything but CELT always selected during v1 packet era + m_nSampleRate = 11025; + } + } + + return !buffer.IsOverflowed(); +} + +const char *SVC_VoiceInit::ToString(void) const +{ + Q_snprintf( s_text, sizeof(s_text), "%s: codec \"%s\", sample rate %i", GetName(), m_szVoiceCodec, m_nSampleRate ); + return s_text; +} + +bool SVC_VoiceData::WriteToBuffer( bf_write &buffer ) +{ + buffer.WriteUBitLong( GetType(), NETMSG_TYPE_BITS ); + buffer.WriteByte( m_nFromClient ); + buffer.WriteByte( m_bProximity ); + buffer.WriteWord( m_nLength ); + + if ( IsX360() ) + { + buffer.WriteLongLong( m_xuid ); + } + + return buffer.WriteBits( m_DataOut, m_nLength ); +} + +bool SVC_VoiceData::ReadFromBuffer( bf_read &buffer ) +{ + VPROF( "SVC_VoiceData::ReadFromBuffer" ); + + m_nFromClient = buffer.ReadByte(); + m_bProximity = !!buffer.ReadByte(); + m_nLength = buffer.ReadWord(); + + if ( IsX360() ) + { + m_xuid = buffer.ReadLongLong(); + } + + m_DataIn = buffer; + return buffer.SeekRelative( m_nLength ); +} + +const char *SVC_VoiceData::ToString(void) const +{ + Q_snprintf(s_text, sizeof(s_text), "%s: client %i, bytes %i", GetName(), m_nFromClient, Bits2Bytes(m_nLength) ); + return s_text; +} + +#define NET_TICK_SCALEUP 100000.0f + +bool NET_Tick::WriteToBuffer( bf_write &buffer ) +{ + buffer.WriteUBitLong( GetType(), NETMSG_TYPE_BITS ); + buffer.WriteLong( m_nTick ); +#if PROTOCOL_VERSION > 10 + buffer.WriteUBitLong( clamp( (int)( NET_TICK_SCALEUP * m_flHostFrameTime ), 0, 65535 ), 16 ); + buffer.WriteUBitLong( clamp( (int)( NET_TICK_SCALEUP * m_flHostFrameTimeStdDeviation ), 0, 65535 ), 16 ); +#endif + return !buffer.IsOverflowed(); +} + +bool NET_Tick::ReadFromBuffer( bf_read &buffer ) +{ + VPROF( "NET_Tick::ReadFromBuffer" ); + + m_nTick = buffer.ReadLong(); +#if PROTOCOL_VERSION > 10 + m_flHostFrameTime = (float)buffer.ReadUBitLong( 16 ) / NET_TICK_SCALEUP; + m_flHostFrameTimeStdDeviation = (float)buffer.ReadUBitLong( 16 ) / NET_TICK_SCALEUP; +#endif + return !buffer.IsOverflowed(); +} + +const char *NET_Tick::ToString(void) const +{ + Q_snprintf(s_text, sizeof(s_text), "%s: tick %i", GetName(), m_nTick ); + return s_text; +} + +bool SVC_UserMessage::WriteToBuffer( bf_write &buffer ) +{ + m_nLength = m_DataOut.GetNumBitsWritten(); + + Assert( m_nLength < (1 << NETMSG_LENGTH_BITS) ); + if ( m_nLength >= (1 << NETMSG_LENGTH_BITS) ) + return false; + + buffer.WriteUBitLong( GetType(), NETMSG_TYPE_BITS ); + buffer.WriteByte( m_nMsgType ); + buffer.WriteUBitLong( m_nLength, NETMSG_LENGTH_BITS ); // max 256 * 8 bits, see MAX_USER_MSG_DATA + + return buffer.WriteBits( m_DataOut.GetData(), m_nLength ); +} + +bool SVC_UserMessage::ReadFromBuffer( bf_read &buffer ) +{ + VPROF( "SVC_UserMessage::ReadFromBuffer" ); + m_nMsgType = buffer.ReadByte(); + m_nLength = buffer.ReadUBitLong( NETMSG_LENGTH_BITS ); // max 256 * 8 bits, see MAX_USER_MSG_DATA + m_DataIn = buffer; + return buffer.SeekRelative( m_nLength ); +} + +const char *SVC_UserMessage::ToString(void) const +{ + Q_snprintf(s_text, sizeof(s_text), "%s: type %i, bytes %i", GetName(), m_nMsgType, Bits2Bytes(m_nLength) ); + return s_text; +} + +bool SVC_SetPause::WriteToBuffer( bf_write &buffer ) +{ + buffer.WriteUBitLong( GetType(), NETMSG_TYPE_BITS ); + buffer.WriteOneBit( m_bPaused?1:0 ); + return !buffer.IsOverflowed(); +} + +bool SVC_SetPause::ReadFromBuffer( bf_read &buffer ) +{ + VPROF( "SVC_SetPause::ReadFromBuffer" ); + + m_bPaused = buffer.ReadOneBit() != 0; + return !buffer.IsOverflowed(); +} + +const char *SVC_SetPause::ToString(void) const +{ + Q_snprintf(s_text, sizeof(s_text), "%s: %s", GetName(), m_bPaused?"paused":"unpaused" ); + return s_text; +} + +bool SVC_SetPauseTimed::WriteToBuffer( bf_write &buffer ) +{ + buffer.WriteUBitLong( GetType(), NETMSG_TYPE_BITS ); + buffer.WriteOneBit( m_bPaused ? 1 : 0 ); + buffer.WriteFloat( m_flExpireTime ); + return !buffer.IsOverflowed(); +} + +bool SVC_SetPauseTimed::ReadFromBuffer( bf_read &buffer ) +{ + VPROF( "SVC_SetPauseTimed::ReadFromBuffer" ); + + m_bPaused = buffer.ReadOneBit() != 0; + m_flExpireTime = buffer.ReadFloat(); + return !buffer.IsOverflowed(); +} + +const char *SVC_SetPauseTimed::ToString( void ) const +{ + Q_snprintf( s_text, sizeof( s_text ), "%s: %s", GetName(), m_bPaused ? "paused" : "unpaused" ); + return s_text; +} + +bool NET_SetConVar::WriteToBuffer( bf_write &buffer ) +{ + buffer.WriteUBitLong( GetType(), NETMSG_TYPE_BITS ); + + int numvars = m_ConVars.Count(); + + // Note how many we're sending + buffer.WriteByte( numvars ); + + for (int i=0; i< numvars; i++ ) + { + cvar_t * var = &m_ConVars[i]; + buffer.WriteString( var->name ); + buffer.WriteString( var->value ); + } + + return !buffer.IsOverflowed(); +} + +bool NET_SetConVar::ReadFromBuffer( bf_read &buffer ) +{ + VPROF( "NET_SetConVar::ReadFromBuffer" ); + + int numvars = buffer.ReadByte(); + + m_ConVars.RemoveAll(); + + for (int i=0; i< numvars; i++ ) + { + cvar_t var; + buffer.ReadString( var.name, sizeof(var.name) ); + buffer.ReadString( var.value, sizeof(var.value) ); + m_ConVars.AddToTail( var ); + + } + return !buffer.IsOverflowed(); +} + +const char *NET_SetConVar::ToString(void) const +{ + Q_snprintf(s_text, sizeof(s_text), "%s: %i cvars, \"%s\"=\"%s\"", + GetName(), m_ConVars.Count(), + m_ConVars[0].name, m_ConVars[0].value ); + return s_text; +} + +bool SVC_UpdateStringTable::WriteToBuffer( bf_write &buffer ) +{ + buffer.WriteUBitLong( GetType(), NETMSG_TYPE_BITS ); + + m_nLength = m_DataOut.GetNumBitsWritten(); + + buffer.WriteUBitLong( m_nTableID, Q_log2( MAX_TABLES ) ); // TODO check bounds + + if ( m_nChangedEntries == 1 ) + { + buffer.WriteOneBit( 0 ); // only one entry changed + } + else + { + buffer.WriteOneBit( 1 ); + buffer.WriteWord( m_nChangedEntries ); // more entries changed + } + + buffer.WriteUBitLong( m_nLength, 20 ); + + return buffer.WriteBits( m_DataOut.GetData(), m_nLength ); +} + +bool SVC_UpdateStringTable::ReadFromBuffer( bf_read &buffer ) +{ + VPROF( "SVC_UpdateStringTable::ReadFromBuffer" ); + + m_nTableID = buffer.ReadUBitLong( Q_log2( MAX_TABLES ) ); + + if ( buffer.ReadOneBit() != 0 ) + { + m_nChangedEntries = buffer.ReadWord(); + } + else + { + m_nChangedEntries = 1; + } + + m_nLength = buffer.ReadUBitLong( 20 ); + m_DataIn = buffer; + return buffer.SeekRelative( m_nLength ); +} + +const char *SVC_UpdateStringTable::ToString(void) const +{ + Q_snprintf(s_text, sizeof(s_text), "%s: table %i, changed %i, bytes %i", GetName(), m_nTableID, m_nChangedEntries, Bits2Bytes(m_nLength) ); + return s_text; +} + +SVC_CreateStringTable::SVC_CreateStringTable() +{ + +} + +bool SVC_CreateStringTable::WriteToBuffer( bf_write &buffer ) +{ + buffer.WriteUBitLong( GetType(), NETMSG_TYPE_BITS ); + m_nLength = m_DataOut.GetNumBitsWritten(); + + /* + JASON: this code is no longer needed; the ':' is prepended to the table name at table creation time. + if ( m_bIsFilenames ) + { + // identifies a table that hosts filenames + buffer.WriteByte( ':' ); + } + */ + + buffer.WriteString( m_szTableName ); + buffer.WriteWord( m_nMaxEntries ); + int encodeBits = Q_log2( m_nMaxEntries ); + buffer.WriteUBitLong( m_nNumEntries, encodeBits+1 ); + buffer.WriteVarInt32( m_nLength ); // length in bits + + buffer.WriteOneBit( m_bUserDataFixedSize ? 1 : 0 ); + if ( m_bUserDataFixedSize ) + { + buffer.WriteUBitLong( m_nUserDataSize, 12 ); + buffer.WriteUBitLong( m_nUserDataSizeBits, 4 ); + } + + buffer.WriteOneBit( m_bDataCompressed ? 1 : 0 ); + return buffer.WriteBits( m_DataOut.GetData(), m_nLength ); +} + +bool SVC_CreateStringTable::ReadFromBuffer( bf_read &buffer ) +{ + VPROF( "SVC_CreateStringTable::ReadFromBuffer" ); + + char prefix = buffer.PeekUBitLong( 8 ); + if ( prefix == ':' ) + { + // table hosts filenames + m_bIsFilenames = true; + buffer.ReadByte(); + } + else + { + m_bIsFilenames = false; + } + + m_szTableName = m_szTableNameBuffer; + buffer.ReadString( m_szTableNameBuffer, sizeof(m_szTableNameBuffer) ); + m_nMaxEntries = buffer.ReadWord(); + int encodeBits = Q_log2( m_nMaxEntries ); + m_nNumEntries = buffer.ReadUBitLong( encodeBits+1 ); + if ( m_NetChannel->GetProtocolVersion() > PROTOCOL_VERSION_23 ) + m_nLength = buffer.ReadVarInt32(); + else + m_nLength = buffer.ReadUBitLong( NET_MAX_PAYLOAD_BITS_V23 + 3 ); + + m_bUserDataFixedSize = buffer.ReadOneBit() ? true : false; + if ( m_bUserDataFixedSize ) + { + m_nUserDataSize = buffer.ReadUBitLong( 12 ); + m_nUserDataSizeBits = buffer.ReadUBitLong( 4 ); + } + else + { + m_nUserDataSize = 0; + m_nUserDataSizeBits = 0; + } + + if ( m_pMessageHandler->GetDemoProtocolVersion() > PROTOCOL_VERSION_14 ) + { + m_bDataCompressed = buffer.ReadOneBit() != 0; + } + else + { + m_bDataCompressed = false; + } + + m_DataIn = buffer; + return buffer.SeekRelative( m_nLength ); +} + +const char *SVC_CreateStringTable::ToString(void) const +{ + Q_snprintf(s_text, sizeof(s_text), "%s: table %s, entries %i, bytes %i userdatasize %i userdatabits %i", + GetName(), m_szTableName, m_nNumEntries, Bits2Bytes(m_nLength), m_nUserDataSize, m_nUserDataSizeBits ); + return s_text; +} + +bool SVC_Sounds::WriteToBuffer( bf_write &buffer ) +{ + m_nLength = m_DataOut.GetNumBitsWritten(); + + buffer.WriteUBitLong( GetType(), NETMSG_TYPE_BITS ); + + Assert( m_nNumSounds > 0 ); + + if ( m_bReliableSound ) + { + // as single sound message is 32 bytes long maximum + buffer.WriteOneBit( 1 ); + buffer.WriteUBitLong( m_nLength, 8 ); + } + else + { + // a bunch of unreliable messages + buffer.WriteOneBit( 0 ); + buffer.WriteUBitLong( m_nNumSounds, 8 ); + buffer.WriteUBitLong( m_nLength, 16 ); + } + + return buffer.WriteBits( m_DataOut.GetData(), m_nLength ); +} + +bool SVC_Sounds::ReadFromBuffer( bf_read &buffer ) +{ + VPROF( "SVC_Sounds::ReadFromBuffer" ); + + m_bReliableSound = buffer.ReadOneBit() != 0; + + if ( m_bReliableSound ) + { + m_nNumSounds = 1; + m_nLength = buffer.ReadUBitLong( 8 ); + + } + else + { + m_nNumSounds = buffer.ReadUBitLong( 8 ); + m_nLength = buffer.ReadUBitLong( 16 ); + } + + m_DataIn = buffer; + return buffer.SeekRelative( m_nLength ); +} + +const char *SVC_Sounds::ToString(void) const +{ + Q_snprintf(s_text, sizeof(s_text), "%s: number %i,%s bytes %i", + GetName(), m_nNumSounds, m_bReliableSound?" reliable,":"", Bits2Bytes(m_nLength) ); + return s_text; +} + +bool SVC_Prefetch::WriteToBuffer( bf_write &buffer ) +{ + buffer.WriteUBitLong( GetType(), NETMSG_TYPE_BITS ); + + // Don't write type until we have more thanone + // buffer.WriteUBitLong( m_fType, 1 ); + buffer.WriteUBitLong( m_nSoundIndex, MAX_SOUND_INDEX_BITS ); + return !buffer.IsOverflowed(); +} + +bool SVC_Prefetch::ReadFromBuffer( bf_read &buffer ) +{ + VPROF( "SVC_Prefetch::ReadFromBuffer" ); + + m_fType = SOUND; // buffer.ReadUBitLong( 1 ); + if( m_pMessageHandler->GetDemoProtocolVersion() > 22 ) + { + m_nSoundIndex = buffer.ReadUBitLong( MAX_SOUND_INDEX_BITS ); + } + else + { + m_nSoundIndex = buffer.ReadUBitLong( 13 ); + } + + return !buffer.IsOverflowed(); +} + +const char *SVC_Prefetch::ToString(void) const +{ + Q_snprintf(s_text, sizeof(s_text), "%s: type %i index %i", + GetName(), + (int)m_fType, + (int)m_nSoundIndex ); + return s_text; +} + +bool SVC_TempEntities::WriteToBuffer( bf_write &buffer ) +{ + Assert( m_nNumEntries > 0 ); + + m_nLength = m_DataOut.GetNumBitsWritten(); + + buffer.WriteUBitLong( GetType(), NETMSG_TYPE_BITS ); + buffer.WriteUBitLong( m_nNumEntries, CEventInfo::EVENT_INDEX_BITS ); + buffer.WriteVarInt32( m_nLength ); + return buffer.WriteBits( m_DataOut.GetData(), m_nLength ); +} + +bool SVC_TempEntities::ReadFromBuffer( bf_read &buffer ) +{ + VPROF( "SVC_TempEntities::ReadFromBuffer" ); + + m_nNumEntries = buffer.ReadUBitLong( CEventInfo::EVENT_INDEX_BITS ); + if ( m_pMessageHandler->GetDemoProtocolVersion() > PROTOCOL_VERSION_23 ) + m_nLength = buffer.ReadVarInt32(); + else + m_nLength = buffer.ReadUBitLong( NET_MAX_PAYLOAD_BITS_V23 ); + + m_DataIn = buffer; + return buffer.SeekRelative( m_nLength ); +} + +const char *SVC_TempEntities::ToString(void) const +{ + Q_snprintf(s_text, sizeof(s_text), "%s: number %i, bytes %i", GetName(), m_nNumEntries, Bits2Bytes(m_nLength) ); + return s_text; +} + +bool SVC_ClassInfo::WriteToBuffer( bf_write &buffer ) +{ + if ( !m_bCreateOnClient ) + { + m_nNumServerClasses = m_Classes.Count(); // use number from list list + } + + buffer.WriteUBitLong( GetType(), NETMSG_TYPE_BITS ); + + buffer.WriteShort( m_nNumServerClasses ); + + int serverClassBits = Q_log2( m_nNumServerClasses ) + 1; + + buffer.WriteOneBit( m_bCreateOnClient?1:0 ); + + if ( m_bCreateOnClient ) + return !buffer.IsOverflowed(); + + for ( int i=0; i< m_nNumServerClasses; i++ ) + { + class_t * serverclass = &m_Classes[i]; + + buffer.WriteUBitLong( serverclass->classID, serverClassBits ); + buffer.WriteString( serverclass->classname ); + buffer.WriteString( serverclass->datatablename ); + } + + return !buffer.IsOverflowed(); +} + +bool SVC_ClassInfo::ReadFromBuffer( bf_read &buffer ) +{ + VPROF( "SVC_ClassInfo::ReadFromBuffer" ); + + m_Classes.RemoveAll(); + + m_nNumServerClasses = buffer.ReadShort(); + + int nServerClassBits = Q_log2( m_nNumServerClasses ) + 1; + + m_bCreateOnClient = buffer.ReadOneBit() != 0; + + if ( m_bCreateOnClient ) + { + return !buffer.IsOverflowed(); // stop here + } + + for ( int i=0; i<m_nNumServerClasses; i++ ) + { + class_t serverclass; + + serverclass.classID = buffer.ReadUBitLong( nServerClassBits ); + buffer.ReadString( serverclass.classname, sizeof(serverclass.classname) ); + buffer.ReadString( serverclass.datatablename, sizeof(serverclass.datatablename) ); + + m_Classes.AddToTail( serverclass ); + } + + return !buffer.IsOverflowed(); +} + +const char *SVC_ClassInfo::ToString(void) const +{ + Q_snprintf(s_text, sizeof(s_text), "%s: num %i, %s", GetName(), + m_nNumServerClasses, m_bCreateOnClient?"use client classes":"full update" ); + return s_text; +} + +/* +bool SVC_SpawnBaseline::WriteToBuffer( bf_write &buffer ) +{ + m_nLength = m_DataOut.GetNumBitsWritten(); + + buffer.WriteUBitLong( GetType(), NETMSG_TYPE_BITS ); + + buffer.WriteUBitLong( m_nEntityIndex, MAX_EDICT_BITS ); + + buffer.WriteUBitLong( m_nClassID, MAX_SERVER_CLASS_BITS ); + + buffer.WriteUBitLong( m_nLength, Q_log2(MAX_PACKEDENTITY_DATA<<3) ); // TODO see below + + return buffer.WriteBits( m_DataOut.GetData(), m_nLength ); +} + +bool SVC_SpawnBaseline::ReadFromBuffer( bf_read &buffer ) +{ + m_nEntityIndex = buffer.ReadUBitLong( MAX_EDICT_BITS ); + + m_nClassID = buffer.ReadUBitLong( MAX_SERVER_CLASS_BITS ); + + m_nLength = buffer.ReadUBitLong( Q_log2(MAX_PACKEDENTITY_DATA<<3) ); // TODO wrong, check bounds + + m_DataIn = buffer; + + return buffer.SeekRelative( m_nLength ); +} + +const char *SVC_SpawnBaseline::ToString(void) const +{ + static char text[256]; + Q_snprintf(text, sizeof(text), "%s: ent %i, class %i, bytes %i", + GetName(), m_nEntityIndex, m_nClassID, Bits2Bytes(m_nLength) ); + return text; +} */ + +bool SVC_GameEvent::WriteToBuffer( bf_write &buffer ) +{ + m_nLength = m_DataOut.GetNumBitsWritten(); + Assert( m_nLength < (1 << NETMSG_LENGTH_BITS) ); + if ( m_nLength >= (1 << NETMSG_LENGTH_BITS) ) + return false; + + buffer.WriteUBitLong( GetType(), NETMSG_TYPE_BITS ); + buffer.WriteUBitLong( m_nLength, NETMSG_LENGTH_BITS ); // max 8 * 256 bits + return buffer.WriteBits( m_DataOut.GetData(), m_nLength ); + +} + +bool SVC_GameEvent::ReadFromBuffer( bf_read &buffer ) +{ + VPROF( "SVC_GameEvent::ReadFromBuffer" ); + + m_nLength = buffer.ReadUBitLong( NETMSG_LENGTH_BITS ); // max 8 * 256 bits + m_DataIn = buffer; + return buffer.SeekRelative( m_nLength ); +} + +const char *SVC_GameEvent::ToString(void) const +{ + Q_snprintf(s_text, sizeof(s_text), "%s: bytes %i", GetName(), Bits2Bytes(m_nLength) ); + return s_text; +} + +bool SVC_SendTable::WriteToBuffer( bf_write &buffer ) +{ + m_nLength = m_DataOut.GetNumBitsWritten(); + + buffer.WriteUBitLong( GetType(), NETMSG_TYPE_BITS ); + buffer.WriteOneBit( m_bNeedsDecoder?1:0 ); + buffer.WriteShort( m_nLength ); + buffer.WriteBits( m_DataOut.GetData(), m_nLength ); + + return !buffer.IsOverflowed(); +} + +bool SVC_SendTable::ReadFromBuffer( bf_read &buffer ) +{ + VPROF( "SVC_SendTable::ReadFromBuffer" ); + + m_bNeedsDecoder = buffer.ReadOneBit() != 0; + m_nLength = buffer.ReadShort(); // TODO do we have a maximum length ? check that + + m_DataIn = buffer; + + return buffer.SeekRelative( m_nLength ); +} + +const char *SVC_SendTable::ToString(void) const +{ + Q_snprintf(s_text, sizeof(s_text), "%s: needs Decoder %s,bytes %i", + GetName(), m_bNeedsDecoder?"yes":"no", Bits2Bytes(m_nLength) ); + return s_text; +} + +bool SVC_EntityMessage::WriteToBuffer( bf_write &buffer ) +{ + m_nLength = m_DataOut.GetNumBitsWritten(); + Assert( m_nLength < (1 << NETMSG_LENGTH_BITS) ); + if ( m_nLength >= (1 << NETMSG_LENGTH_BITS) ) + return false; + + buffer.WriteUBitLong( GetType(), NETMSG_TYPE_BITS ); + buffer.WriteUBitLong( m_nEntityIndex, MAX_EDICT_BITS ); + buffer.WriteUBitLong( m_nClassID, MAX_SERVER_CLASS_BITS ); + buffer.WriteUBitLong( m_nLength, NETMSG_LENGTH_BITS ); // max 8 * 256 bits + + return buffer.WriteBits( m_DataOut.GetData(), m_nLength ); +} + +bool SVC_EntityMessage::ReadFromBuffer( bf_read &buffer ) +{ + VPROF( "SVC_EntityMessage::ReadFromBuffer" ); + + m_nEntityIndex = buffer.ReadUBitLong( MAX_EDICT_BITS ); + m_nClassID = buffer.ReadUBitLong( MAX_SERVER_CLASS_BITS ); + m_nLength = buffer.ReadUBitLong( NETMSG_LENGTH_BITS ); // max 8 * 256 bits + m_DataIn = buffer; + return buffer.SeekRelative( m_nLength ); +} + +const char *SVC_EntityMessage::ToString(void) const +{ + Q_snprintf(s_text, sizeof(s_text), "%s: entity %i, class %i, bytes %i", + GetName(), m_nEntityIndex, m_nClassID, Bits2Bytes(m_nLength) ); + return s_text; +} + +bool SVC_PacketEntities::WriteToBuffer( bf_write &buffer ) +{ + buffer.WriteUBitLong( GetType(), NETMSG_TYPE_BITS ); + + buffer.WriteUBitLong( m_nMaxEntries, MAX_EDICT_BITS ); + + buffer.WriteOneBit( m_bIsDelta?1:0 ); + + if ( m_bIsDelta ) + { + buffer.WriteLong( m_nDeltaFrom ); + } + + buffer.WriteUBitLong( m_nBaseline, 1 ); + + buffer.WriteUBitLong( m_nUpdatedEntries, MAX_EDICT_BITS ); + + buffer.WriteUBitLong( m_nLength, DELTASIZE_BITS ); + + buffer.WriteOneBit( m_bUpdateBaseline?1:0 ); + + buffer.WriteBits( m_DataOut.GetData(), m_nLength ); + + return !buffer.IsOverflowed(); +} + +bool SVC_PacketEntities::ReadFromBuffer( bf_read &buffer ) +{ + VPROF( "SVC_PacketEntities::ReadFromBuffer" ); + + m_nMaxEntries = buffer.ReadUBitLong( MAX_EDICT_BITS ); + + m_bIsDelta = buffer.ReadOneBit()!=0; + + if ( m_bIsDelta ) + { + m_nDeltaFrom = buffer.ReadLong(); + } + else + { + m_nDeltaFrom = -1; + } + + m_nBaseline = buffer.ReadUBitLong( 1 ); + + m_nUpdatedEntries = buffer.ReadUBitLong( MAX_EDICT_BITS ); + + m_nLength = buffer.ReadUBitLong( DELTASIZE_BITS ); + + m_bUpdateBaseline = buffer.ReadOneBit() != 0; + + m_DataIn = buffer; + + return buffer.SeekRelative( m_nLength ); +} + +const char *SVC_PacketEntities::ToString(void) const +{ + Q_snprintf(s_text, sizeof(s_text), "%s: delta %i, max %i, changed %i,%s bytes %i", + GetName(), m_nDeltaFrom, m_nMaxEntries, m_nUpdatedEntries, m_bUpdateBaseline?" BL update,":"", Bits2Bytes(m_nLength) ); + return s_text; +} + +SVC_Menu::SVC_Menu( DIALOG_TYPE type, KeyValues *data ) +{ + m_bReliable = true; + + m_Type = type; + m_MenuKeyValues = data->MakeCopy(); + m_iLength = -1; +} + +SVC_Menu::~SVC_Menu() +{ + if ( m_MenuKeyValues ) + { + m_MenuKeyValues->deleteThis(); + } +} + +bool SVC_Menu::WriteToBuffer( bf_write &buffer ) +{ + if ( !m_MenuKeyValues ) + { + return false; + } + + CUtlBuffer buf; + m_MenuKeyValues->WriteAsBinary( buf ); + + if ( buf.TellPut() > 4096 ) + { + Msg( "Too much menu data (4096 bytes max)\n" ); + return false; + } + + buffer.WriteUBitLong( GetType(), NETMSG_TYPE_BITS ); + buffer.WriteShort( m_Type ); + buffer.WriteWord( buf.TellPut() ); + buffer.WriteBytes( buf.Base(), buf.TellPut() ); + + return !buffer.IsOverflowed(); +} + +bool SVC_Menu::ReadFromBuffer( bf_read &buffer ) +{ + VPROF( "SVC_Menu::ReadFromBuffer" ); + + m_Type = (DIALOG_TYPE)buffer.ReadShort(); + m_iLength = buffer.ReadWord(); + + CUtlBuffer buf( 0, m_iLength ); + buffer.ReadBytes( buf.Base(), m_iLength ); + buf.SeekPut( CUtlBuffer::SEEK_HEAD, m_iLength ); + + if ( m_MenuKeyValues ) + { + m_MenuKeyValues->deleteThis(); + } + m_MenuKeyValues = new KeyValues( "menu" ); + Assert( m_MenuKeyValues ); + + m_MenuKeyValues->ReadAsBinary( buf ); + + return !buffer.IsOverflowed(); +} + +const char *SVC_Menu::ToString(void) const +{ + Q_snprintf(s_text, sizeof(s_text), "%s: %i \"%s\" (len:%i)", GetName(), + m_Type, m_MenuKeyValues ? m_MenuKeyValues->GetName() : "No KeyValues", m_iLength ); + return s_text; +} + +bool SVC_GameEventList::WriteToBuffer( bf_write &buffer ) +{ + Assert( m_nNumEvents > 0 ); + + m_nLength = m_DataOut.GetNumBitsWritten(); + + buffer.WriteUBitLong( GetType(), NETMSG_TYPE_BITS ); + buffer.WriteUBitLong( m_nNumEvents, MAX_EVENT_BITS ); + buffer.WriteUBitLong( m_nLength, 20 ); + return buffer.WriteBits( m_DataOut.GetData(), m_nLength ); +} + +bool SVC_GameEventList::ReadFromBuffer( bf_read &buffer ) +{ + VPROF( "SVC_GameEventList::ReadFromBuffer" ); + + m_nNumEvents = buffer.ReadUBitLong( MAX_EVENT_BITS ); + m_nLength = buffer.ReadUBitLong( 20 ); + m_DataIn = buffer; + return buffer.SeekRelative( m_nLength ); +} + +const char *SVC_GameEventList::ToString(void) const +{ + Q_snprintf(s_text, sizeof(s_text), "%s: number %i, bytes %i", GetName(), m_nNumEvents, Bits2Bytes(m_nLength) ); + return s_text; +} + +/////////////////////////////////////////////////////////////////////////////////////// +// Matchmaking messages: +/////////////////////////////////////////////////////////////////////////////////////// + +bool MM_Heartbeat::WriteToBuffer( bf_write &buffer ) +{ + buffer.WriteUBitLong( GetType(), NETMSG_TYPE_BITS ); + return !buffer.IsOverflowed(); +} + +bool MM_Heartbeat::ReadFromBuffer( bf_read &buffer ) +{ + return true; +} + +const char *MM_Heartbeat::ToString( void ) const +{ + Q_snprintf( s_text, sizeof( s_text ), "Heartbeat" ); + return s_text; +} + +bool MM_ClientInfo::WriteToBuffer( bf_write &buffer ) +{ + buffer.WriteUBitLong( GetType(), NETMSG_TYPE_BITS ); + buffer.WriteBytes( &m_xnaddr, sizeof( m_xnaddr ) ); + buffer.WriteLongLong( m_id ); // 64 bit + buffer.WriteByte( m_cPlayers ); + buffer.WriteByte( m_bInvited ); + for ( int i = 0; i < m_cPlayers; ++i ) + { + buffer.WriteLongLong( m_xuids[i] ); // 64 bit + buffer.WriteBytes( &m_cVoiceState, sizeof( m_cVoiceState ) ); + buffer.WriteLong( m_iTeam[i] ); + buffer.WriteByte( m_iControllers[i] ); + buffer.WriteString( m_szGamertags[i] ); + } + + return !buffer.IsOverflowed(); +} + +bool MM_ClientInfo::ReadFromBuffer( bf_read &buffer ) +{ + buffer.ReadBytes( &m_xnaddr, sizeof( m_xnaddr ) ); + m_id = buffer.ReadLongLong(); // 64 bit + m_cPlayers = buffer.ReadByte(); + m_bInvited = (buffer.ReadByte() != 0); + for ( int i = 0; i < m_cPlayers; ++i ) + { + m_xuids[i] = buffer.ReadLongLong(); // 64 bit + buffer.ReadBytes( &m_cVoiceState, sizeof( m_cVoiceState ) ); + m_iTeam[i] = buffer.ReadLong(); + m_iControllers[i] = buffer.ReadByte(); + buffer.ReadString( m_szGamertags[i], sizeof( m_szGamertags[i] ), true ); + } + + return !buffer.IsOverflowed(); +} + +const char *MM_ClientInfo::ToString( void ) const +{ + Q_snprintf( s_text, sizeof( s_text ), "Client Info: ID: %llu, Players: %d", m_id, m_cPlayers ); + return s_text; +} + +bool MM_RegisterResponse::WriteToBuffer( bf_write &buffer ) +{ + buffer.WriteUBitLong( GetType(), NETMSG_TYPE_BITS ); + return !buffer.IsOverflowed(); +} + +bool MM_RegisterResponse::ReadFromBuffer( bf_read &buffer ) +{ + return true; +} + +const char *MM_RegisterResponse::ToString( void ) const +{ + Q_snprintf( s_text, sizeof( s_text ), "Register Response" ); + return s_text; +} + +bool MM_Mutelist::WriteToBuffer( bf_write &buffer ) +{ + buffer.WriteUBitLong( GetType(), NETMSG_TYPE_BITS ); + + buffer.WriteLongLong( m_id ); + buffer.WriteByte( m_cPlayers ); + for ( int i = 0; i < m_cPlayers; ++i ) + { + buffer.WriteByte( m_cRemoteTalkers[i] ); + buffer.WriteLongLong( m_xuid[i] ); // 64 bit + buffer.WriteByte( m_cMuted[i] ); + for ( int j = 0; j < m_cMuted[i]; ++j ) + { + buffer.WriteLongLong( m_Muted[i][j] ); + } + } + return !buffer.IsOverflowed(); +} + +bool MM_Mutelist::ReadFromBuffer( bf_read &buffer ) +{ + m_id = buffer.ReadLongLong(); + m_cPlayers = buffer.ReadByte(); + for ( int i = 0; i < m_cPlayers; ++i ) + { + m_cRemoteTalkers[i] = buffer.ReadByte(); + m_xuid[i] = buffer.ReadLongLong(); // 64 bit + m_cMuted[i] = buffer.ReadByte(); + for ( int j = 0; j < m_cMuted[i]; ++j ) + { + m_Muted[i].AddToTail( buffer.ReadLongLong() ); + } + } + return !buffer.IsOverflowed(); +} + +const char *MM_Mutelist::ToString( void ) const +{ + Q_snprintf( s_text, sizeof( s_text ), "Mutelist" ); + return s_text; +} + +bool MM_Checkpoint::WriteToBuffer( bf_write &buffer ) +{ + buffer.WriteUBitLong( GetType(), NETMSG_TYPE_BITS ); + buffer.WriteByte( m_Checkpoint ); + return !buffer.IsOverflowed(); +} + +bool MM_Checkpoint::ReadFromBuffer( bf_read &buffer ) +{ + m_Checkpoint = buffer.ReadByte(); + return !buffer.IsOverflowed(); +} + +const char *MM_Checkpoint::ToString( void ) const +{ + Q_snprintf( s_text, sizeof( s_text ), "Checkpoint: %d", m_Checkpoint ); + return s_text; +} + +// NOTE: This message is not network-endian compliant, due to the +// transmission of structures instead of their component parts +bool MM_JoinResponse::WriteToBuffer( bf_write &buffer ) +{ + buffer.WriteUBitLong( GetType(), NETMSG_TYPE_BITS ); + buffer.WriteLong( m_ResponseType ); + buffer.WriteLongLong( m_id ); // 64 bit + buffer.WriteLongLong( m_Nonce ); // 64 bit + buffer.WriteLong( m_SessionFlags ); + buffer.WriteLong( m_nOwnerId ); + buffer.WriteLong( m_iTeam ); + buffer.WriteLong( m_nTotalTeams ); + buffer.WriteByte( m_PropertyCount ); + buffer.WriteByte( m_ContextCount ); + for ( int i = 0; i < m_PropertyCount; ++i ) + { + buffer.WriteBytes( &m_SessionProperties[i], sizeof( XUSER_PROPERTY ) ); + } + for ( int i = 0; i < m_ContextCount; ++i ) + { + buffer.WriteBytes( &m_SessionContexts[i], sizeof( XUSER_CONTEXT ) ); + } + + return !buffer.IsOverflowed(); +} + +bool MM_JoinResponse::ReadFromBuffer( bf_read &buffer ) +{ + m_ResponseType = buffer.ReadLong(); + m_id = buffer.ReadLongLong(); // 64 bit + m_Nonce = buffer.ReadLongLong(); // 64 bit + m_SessionFlags = buffer.ReadLong(); + m_nOwnerId = buffer.ReadLong(); + m_iTeam = buffer.ReadLong(); + m_nTotalTeams = buffer.ReadLong(); + m_PropertyCount = buffer.ReadByte(); + m_ContextCount = buffer.ReadByte(); + XUSER_PROPERTY prop; + m_SessionProperties.RemoveAll(); + for ( int i = 0; i < m_PropertyCount; ++i ) + { + buffer.ReadBytes( &prop, sizeof( XUSER_PROPERTY ) ); + m_SessionProperties.AddToTail( prop ); + } + XUSER_CONTEXT ctx; + m_SessionContexts.RemoveAll(); + for ( int i = 0; i < m_ContextCount; ++i ) + { + buffer.ReadBytes( &ctx, sizeof( XUSER_CONTEXT ) ); + m_SessionContexts.AddToTail( ctx ); + } + + return !buffer.IsOverflowed(); +} + +const char *MM_JoinResponse::ToString( void ) const +{ + Q_snprintf( s_text, sizeof( s_text ), "ID: %llu, Nonce: %llu, Flags: %u", m_id, m_Nonce, m_SessionFlags ); + return s_text; +} + +// NOTE: This message is not network-endian compliant, due to the +// transmission of structures instead of their component parts +bool MM_Migrate::WriteToBuffer( bf_write &buffer ) +{ + Assert( IsX360() ); + + buffer.WriteUBitLong( GetType(), NETMSG_TYPE_BITS ); + buffer.WriteByte( m_MsgType ); + buffer.WriteLongLong( m_Id ); + buffer.WriteBytes( &m_sessionId, sizeof( m_sessionId ) ); + buffer.WriteBytes( &m_xnaddr, sizeof( m_xnaddr ) ); + buffer.WriteBytes( &m_key, sizeof( m_key ) ); + return !buffer.IsOverflowed(); +} + +bool MM_Migrate::ReadFromBuffer( bf_read &buffer ) +{ + Assert( IsX360() ); + + m_MsgType = buffer.ReadByte(); + m_Id = buffer.ReadLongLong(); + buffer.ReadBytes( &m_sessionId, sizeof( m_sessionId ) ); + buffer.ReadBytes( &m_xnaddr, sizeof( m_xnaddr ) ); + buffer.ReadBytes( &m_key, sizeof( m_key ) ); + return !buffer.IsOverflowed(); +} + +const char *MM_Migrate::ToString( void ) const +{ + Q_snprintf( s_text, sizeof( s_text ), "Migrate Message" ); + return s_text; +} + + +bool SVC_GetCvarValue::WriteToBuffer( bf_write &buffer ) +{ + buffer.WriteUBitLong( GetType(), NETMSG_TYPE_BITS ); + + buffer.WriteSBitLong( m_iCookie, 32 ); + buffer.WriteString( m_szCvarName ); + + return !buffer.IsOverflowed(); +} + +bool SVC_GetCvarValue::ReadFromBuffer( bf_read &buffer ) +{ + VPROF( "SVC_GetCvarValue::ReadFromBuffer" ); + + m_iCookie = buffer.ReadSBitLong( 32 ); + buffer.ReadString( m_szCvarNameBuffer, sizeof( m_szCvarNameBuffer ) ); + m_szCvarName = m_szCvarNameBuffer; + + return !buffer.IsOverflowed(); +} + +const char *SVC_GetCvarValue::ToString(void) const +{ + Q_snprintf( s_text, sizeof(s_text), "%s: cvar: %s, cookie: %d", GetName(), m_szCvarName, m_iCookie ); + return s_text; +} + |