//====== Copyright ©, Valve Corporation, All rights reserved. ======= // // Purpose: Holds the CMsgBase_t class // //============================================================================= #ifndef GCMSGBASE_H #define GCMSGBASE_H #ifdef _WIN32 #pragma once #endif #include "tier1/tsmultimempool.h" #include "gclogger.h" #include "gcconstants.h" #include "refcount.h" namespace GCSDK { class CNetPacket; // used for message types in GCSDK where we don't have the actual enum typedef uint32 MsgType_t; const uint32 k_EMsgProtoBufFlag = 0x80000000; //extern ConVar g_ConVarMsgErrorDump; extern CThreadSafeMultiMemoryPool g_MemPoolMsg; enum EMsgFormatType { k_EMsgFormatTypeStruct = 0, k_EMsgFormatTypeClientStruct = 1, k_EMsgFormatTypeClientStructDeprecated = 2, k_EMsgFormatTypeProtocolBuffer = 3 }; // // Interface that the CNetPacket wrappers for both old/new inter-server // message formats must implement. // class IMsgNetPacket : public CRefCount { public: virtual EMsgFormatType GetEMsgFormatType() const = 0; virtual CNetPacket *GetCNetPacket() const = 0; virtual uint8 *PubData() const = 0; virtual uint CubData() const = 0; // // Inter-server or client messages in both old/new formats // virtual MsgType_t GetEMsg() const = 0; virtual JobID_t GetSourceJobID() const = 0; virtual JobID_t GetTargetJobID() const = 0; virtual void SetTargetJobID( JobID_t ulJobID ) = 0; // // Client messages only in the old format, optional in any msg in the new format // virtual CSteamID GetSteamID() const = 0; virtual void SetSteamID( CSteamID steamID ) = 0; // Inter-gc messages only virtual AppId_t GetSourceAppID() const = 0; virtual void SetSourceAppID( AppId_t appId ) = 0; // // The name of the job type to route this message to. ProtoBuf messages only // virtual bool BHasTargetJobName() const = 0; virtual const char *GetTargetJobName() const = 0; protected: // Needed due to CRefCount inheritance which makes this not a pure interface class virtual ~IMsgNetPacket() {} }; IMsgNetPacket *IMsgNetPacketFromCNetPacket( CNetPacket *pNetPacket ); // Wrapper around IMsgNetPacket which auto-releases class CIMsgNetPacketAutoRelease { public: CIMsgNetPacketAutoRelease( CNetPacket *pNetPacket ) { m_pMsgNetPacket = IMsgNetPacketFromCNetPacket( pNetPacket ); } ~CIMsgNetPacketAutoRelease() { SAFE_RELEASE( m_pMsgNetPacket ); } void Replace( CNetPacket *pNetPacket, bool bIsClientMsg ) { SAFE_RELEASE( m_pMsgNetPacket ); m_pMsgNetPacket = IMsgNetPacketFromCNetPacket( pNetPacket ); } IMsgNetPacket *Get() { return m_pMsgNetPacket; } IMsgNetPacket *operator->() { return m_pMsgNetPacket; } protected: void operator=( const CIMsgNetPacketAutoRelease &that ) { AssertMsg( false, "Not safe to copy since releases references on destruction" ); } CIMsgNetPacketAutoRelease( const CIMsgNetPacketAutoRelease &that ) { AssertMsg( false, "Not safe to copy since releases references on destruction" ); } IMsgNetPacket *m_pMsgNetPacket; }; //----------------------------------------------------------------------------- // Purpose: Helper class for incoming and outgoing network packets. // IMPORTANT: Note the distinction between pubData and cubData // (which refer to the message payload), and pubMsg and cubMsg // (which refer to the entire message, with the header). //----------------------------------------------------------------------------- template class CMsgBase_t { public: // Send constructor CMsgBase_t( uint32 cubStruct, uint32 cubReserve = 0 ); // copies data from pubPkt CMsgBase_t( const uint8 *pubPkt, uint32 cubPkt ); // Receive constructor - aliases pubPkt CMsgBase_t( uint32 cubHdr, uint32 cubStruct, uint8 *pubPkt, uint32 cubPkt/*, HCONNECTION hConnection = NULL*/ ); // set packet after using empty constructor void SetPacket( IMsgNetPacket *pNetPacket ); // Destructor virtual ~CMsgBase_t(); // Accessors uint8 *PubVarData() { return ( m_pubPkt + m_cubMsgHdr + m_cubStruct ); } const uint8 *PubVarData() const { return ( m_pubPkt + m_cubMsgHdr + m_cubStruct ); } uint32 CubVarData() const { if ( m_cubPkt >= ( m_cubMsgHdr + m_cubStruct ) ) return m_cubPkt - m_cubMsgHdr - m_cubStruct; else return 0; } uint8 *PubPkt() { return m_pubPkt; } const uint8 *PubPkt() const { return m_pubPkt; } uint32 CubPkt() const { return m_cubPkt; } MSG_HEADER_TYPE &Hdr() { return * ( MSG_HEADER_TYPE * ) ( m_pubPkt ); } const MSG_HEADER_TYPE &Hdr() const { return * ( MSG_HEADER_TYPE * ) ( m_pubPkt ); } uint32 CubHdr() const { return m_cubMsgHdr; } uint8* PubBody() { return m_pubBody; } const uint8* PubBody() const { return m_pubBody; } uint32 CubBody() const { return CubPkt() - CubHdr(); } // Add additional data int DubWriteCur() { return m_cubPkt - m_cubMsgHdr - m_cubStruct; } // Our current offset within the var data block void AddBoolData( bool bData ); void AddUint8Data( uint8 ubData ); void AddUintData( uint32 unData ); void AddIntData( int32 nData ); void AddInt16Data( int16 sData ); void AddUint16Data( uint16 usData ); void AddUint64Data( uint64 ulData ); void AddInt64Data( int64 lData ); void AddFloatData( float lData ); void AddVariableLenData( const void *pvData, uint cubLen ); void AddStrData( const char *pchIn ); template void AddStructure(T& structure ) ; // Read variable-length data (can also read manually using PubVarData(), CubVarData() void ResetReadPtr() { m_pubVarRead = PubVarData(); } uint8 *PubReadCur() { return m_pubVarRead; } const uint8 *PubReadCur() const { return m_pubVarRead; } uint32 CubReadRemaining() const { return (uint32)(m_pubPkt + m_cubPkt - m_pubVarRead); } void AdvanceReadPtr( int cubSkip ) { m_pubVarRead += cubSkip; } bool BReadBoolData( bool *pbData ); bool BReadUint8Data( uint8 *pbData ); bool BReadUintData( uint32 *punData ); bool BReadIntData( int32 *pnData ); bool BReadInt16Data( int16 *psData ); bool BReadUint16Data( uint16 *pusData ); bool BReadUint64Data( uint64 *pulData ); bool BReadInt64Data( int64 *plData ); bool BReadFloatData( float *pflData ); bool BReadVariableLenData( void *pvBuff, uint32 cubRead ); bool BReadStr( char *pchBuff, int cchBuff ); bool BReadStr( CUtlString *pstr ); template bool BReadStructure(T& structure) ; // returns pointer to data (and size of data in out ptr), and NULLs out own pointer; // caller now owns this memory and must free uint8 * DetachPkt( int * pcubPkt ) { Assert( pcubPkt ); *pcubPkt = m_cubPkt; uint8 * pRetVal = m_pubPkt; m_pubPkt = NULL; m_pubBody = NULL; m_cubPkt = 0; return pRetVal; } void ResetWritePtr() { m_cubPkt = m_cubMsgHdr + m_cubStruct; } uint32 GetWriteOffset() const { return m_cubPkt; } void SetWriteOffset( uint32 nWriteOffset ) { m_cubPkt = nWriteOffset; } // Called to set the JobID that will be expecting // a reply to this message. void ExpectingReply( JobID_t jobIDSource ) { Hdr().m_JobIDSource = jobIDSource; } bool BIsExpectingReply() const { return Hdr().m_JobIDSource != k_GIDNil; } // make sure the buffer can hold this extra amount of data void EnsurePacketSize( uint32 cubNewsize ); //HCONNECTION GetHConnection() const { return m_hConnection; } void ReportBufferOverflow(); void PacketDump(); // spews complete packet content to console protected: // Shared by send & receive uint8 *m_pubPkt; // Raw packet data uint8 *m_pubBody; // pointer to body; always equal to m_pubPkt + m_cubMsgHdr uint32 m_cubPkt; // Raw packet size const uint32 m_cubMsgHdr; // Size of our message header uint32 m_cubStruct; // Size of our message-specific struct //HCONNECTION m_hConnection; // Connection on which we received the message private: // stop people from hurting themselves CMsgBase_t( const CMsgBase_t &rhs ) {}; CMsgBase_t &operator=( const CMsgBase_t &rhs ) {}; bool m_bAlloced; // Did we allocate this buffer or does someone else own it // Receive only uint8 *m_pubVarRead; // Our current read pointer in the variable-length data }; template CMsgBase_t::CMsgBase_t( uint32 cubStruct, uint32 cubReserve ) : m_cubMsgHdr( sizeof( MSG_HEADER_TYPE ) ) { m_cubStruct = cubStruct; // Alloc a buffer m_cubPkt = m_cubMsgHdr + m_cubStruct; m_pubPkt = (uint8 *) g_MemPoolMsg.Alloc( m_cubPkt + cubReserve ); m_pubBody = m_pubPkt + m_cubMsgHdr; memset(m_pubPkt, 0, m_cubPkt ); m_bAlloced = true; m_pubVarRead = NULL; } template CMsgBase_t::CMsgBase_t( const uint8 *pubPkt, uint32 cubPkt ) : m_cubMsgHdr( 0 ) { m_cubStruct = 0; // Alloc a buffer m_cubPkt = cubPkt; m_pubPkt = (uint8 *) g_MemPoolMsg.Alloc( m_cubPkt ); m_pubBody = m_pubPkt + m_cubMsgHdr; Q_memcpy(m_pubPkt, pubPkt, cubPkt ); m_bAlloced = true; m_pubVarRead = NULL; } template CMsgBase_t::CMsgBase_t( uint32 cubHdr, uint32 cubStruct, uint8 *pubPkt, uint32 cubPkt ) : m_cubMsgHdr( cubHdr ) { Assert( cubHdr != 0 ); Assert( !cubPkt || ( cubPkt >= ( cubHdr + cubStruct ) ) ); m_cubStruct = cubStruct; m_pubPkt = pubPkt; m_pubBody = m_pubPkt + m_cubMsgHdr; m_cubPkt = cubPkt; m_bAlloced = false; m_pubVarRead = PubVarData(); } template CMsgBase_t::~CMsgBase_t() { // if we allocated memory, free it if ( m_bAlloced && m_pubPkt ) g_MemPoolMsg.Free( m_pubPkt ); } //----------------------------------------------------------------------------- // Purpose: ensure the packet can contain at least this much extra data // Input: cubExtraSize - the amount of bytes to have room for //----------------------------------------------------------------------------- template void CMsgBase_t::SetPacket( IMsgNetPacket *pNetPacket ) { m_pubPkt = pNetPacket->PubData(); m_pubBody = m_pubPkt + m_cubMsgHdr; m_cubPkt = pNetPacket->CubData(); Assert( !m_cubPkt || ( m_cubPkt >= ( m_cubMsgHdr + m_cubStruct ) ) ); m_bAlloced = false; m_pubVarRead = PubVarData(); } //----------------------------------------------------------------------------- // Purpose: ensure the packet can contain at least this much extra data // Input: cubExtraSize - the amount of bytes to have room for //----------------------------------------------------------------------------- template void CMsgBase_t::EnsurePacketSize( uint32 cubExtraSize ) { m_pubPkt = (uint8 *) g_MemPoolMsg.ReAlloc( m_pubPkt, m_cubPkt + cubExtraSize ); m_pubBody = m_pubPkt + m_cubMsgHdr; } //----------------------------------------------------------------------------- // Purpose: Appends a bool to the variable length data associated with this message // Input: bData - data to append //----------------------------------------------------------------------------- template void CMsgBase_t::AddBoolData( bool ubData ) { return AddUint8Data( static_cast< uint8 >( ubData ) ); } //----------------------------------------------------------------------------- // Purpose: Appends a uint8 to the variable length data associated with this message // Input: ubData - data to append //----------------------------------------------------------------------------- template void CMsgBase_t::AddUint8Data( uint8 ubData ) { EnsurePacketSize( sizeof( uint8 ) ); *( ( uint8 * ) ( m_pubPkt + m_cubPkt ) ) = ubData; m_cubPkt += sizeof( uint8 ); } //----------------------------------------------------------------------------- // Purpose: Appends a uint to the variable length data associated with this message // Input: unData - data to append //----------------------------------------------------------------------------- template void CMsgBase_t::AddUintData( uint32 unData ) { EnsurePacketSize( sizeof( uint32 ) ); *( ( uint32 * ) ( m_pubPkt + m_cubPkt ) ) = unData; m_cubPkt += sizeof( uint32 ); } //----------------------------------------------------------------------------- // Purpose: Appends an int to the variable length data associated with this message // Input: nData - data to append //----------------------------------------------------------------------------- template void CMsgBase_t::AddIntData( int32 nData ) { EnsurePacketSize( sizeof( int32 ) ); *( ( int32 * ) ( m_pubPkt + m_cubPkt ) ) = nData; m_cubPkt += sizeof( int32 ); } //----------------------------------------------------------------------------- // Purpose: Appends an int16 to the variable length data associated with this message // Input: nData - data to append //----------------------------------------------------------------------------- template void CMsgBase_t::AddInt16Data( int16 sData ) { EnsurePacketSize( sizeof( int16 ) ); *( ( int16 * ) ( m_pubPkt + m_cubPkt ) ) = sData; m_cubPkt += sizeof( int16 ); } //----------------------------------------------------------------------------- // Purpose: Appends an int16 to the variable length data associated with this message // Input: nData - data to append //----------------------------------------------------------------------------- template void CMsgBase_t::AddUint16Data( uint16 usData ) { EnsurePacketSize( sizeof( uint16 ) ); *( ( uint16 * ) ( m_pubPkt + m_cubPkt ) ) = usData; m_cubPkt += sizeof( uint16 ); } //----------------------------------------------------------------------------- // Purpose: Appends a uint64 to the variable length data associated with this message // Input: ulData - data to append //----------------------------------------------------------------------------- template void CMsgBase_t::AddUint64Data( uint64 ulData ) { EnsurePacketSize( sizeof( uint64 ) ); *( ( uint64 * ) ( m_pubPkt + m_cubPkt ) ) = ulData; m_cubPkt += sizeof( uint64 ); } //----------------------------------------------------------------------------- // Purpose: Appends an int64 to the variable length data associated with this message // Input: lData - data to append //----------------------------------------------------------------------------- template void CMsgBase_t::AddInt64Data( int64 lData ) { EnsurePacketSize( sizeof( int64 ) ); *( ( int64 * ) ( m_pubPkt + m_cubPkt ) ) = lData; m_cubPkt += sizeof( int64 ); } //----------------------------------------------------------------------------- // Purpose: Appends variable length data to this message. (Can be called // repeatedly to append multiple data blocks.) // Input: pvData - pointer to data to append // cubData - size of data to append //----------------------------------------------------------------------------- template void CMsgBase_t::AddVariableLenData( const void *pvData, uint cubLen ) { if ( cubLen > 0 ) { EnsurePacketSize( cubLen ); memcpy( ( m_pubPkt + m_cubPkt ), pvData, cubLen ); m_cubPkt += cubLen; } } //----------------------------------------------------------------------------- // Purpose: Appends a float to the variable length data associated with this message // Input: nData - data to append //----------------------------------------------------------------------------- template void CMsgBase_t::AddFloatData( float flData ) { EnsurePacketSize( sizeof( float ) ); *( ( float * ) ( m_pubPkt + m_cubPkt ) ) = flData; m_cubPkt += sizeof( float ); } //----------------------------------------------------------------------------- // Purpose: Appends a string to the variable-length portion of this message. // Input: pchIn - String to append to the message //----------------------------------------------------------------------------- template void CMsgBase_t::AddStrData( const char *pchIn ) { if ( !pchIn ) { Assert( pchIn ); // passing a null string here is a code bug return; } int cchIn = Q_strlen( pchIn ); EnsurePacketSize( cchIn + 1 ); Q_strncpy( ( char * ) ( m_pubPkt + m_cubPkt ), pchIn, cchIn + 1 ); m_cubPkt += ( cchIn + 1 ); } template template void CMsgBase_t::AddStructure( T& structure ) { EnsurePacketSize(sizeof(structure)) ; *( reinterpret_cast(m_pubPkt+m_cubPkt)) = structure ; m_cubPkt += sizeof(structure) ; } //----------------------------------------------------------------------------- // Purpose: Read a bool from the variable-length part of the message // Input: pbData - [return] The value we read goes here // Output: true if we were able to read, false if we overran the buffer //----------------------------------------------------------------------------- template bool CMsgBase_t::BReadBoolData( bool *pbData ) { return BReadUint8Data( ( uint8* ) pbData ); } //----------------------------------------------------------------------------- // Purpose: Read a uint8 from the variable-length part of the message // Input: pbData - [return] The value we read goes here // Output: true if we were able to read, false if we overran the buffer //----------------------------------------------------------------------------- template bool CMsgBase_t::BReadUint8Data( uint8 *pbData ) { if ( m_pubVarRead + sizeof( uint8 ) > m_pubPkt + m_cubPkt ) { ReportBufferOverflow(); return false; } *pbData = * ( ( uint8 * ) m_pubVarRead ); m_pubVarRead += sizeof( uint8 ); return true; } //----------------------------------------------------------------------------- // Purpose: Read a uint32 from the variable-length part of the message // Input: punData - [return] The value we read goes here // Output: true if we were able to read, false if we overran the buffer //----------------------------------------------------------------------------- template bool CMsgBase_t::BReadUintData( uint32 *punData ) { if ( m_pubVarRead + sizeof( uint32 ) > m_pubPkt + m_cubPkt ) { ReportBufferOverflow(); return false; } *punData = * ( ( uint32 * ) m_pubVarRead ); m_pubVarRead += sizeof( uint32 ); return true; } //----------------------------------------------------------------------------- // Purpose: Reads an int32 from the variable-length part of the message // Input: pnData - [return] The value we read goes here // Output: true if we were able to read, false if we overran the buffer //----------------------------------------------------------------------------- template bool CMsgBase_t::BReadIntData( int32 *pnData ) { if ( m_pubVarRead + sizeof( int32 ) > m_pubPkt + m_cubPkt ) { ReportBufferOverflow(); return false; } *pnData = * ( ( int32 * ) m_pubVarRead ); m_pubVarRead += sizeof( int32 ); return true; } //----------------------------------------------------------------------------- // Purpose: Reads an int16 from the variable-length part of the message // Input: pnData - [return] The value we read goes here // Output: true if we were able to read, false if we overran the buffer //----------------------------------------------------------------------------- template bool CMsgBase_t::BReadInt16Data( int16 *psData ) { if ( m_pubVarRead + sizeof( int16 ) > m_pubPkt + m_cubPkt ) { ReportBufferOverflow(); return false; } *psData = * ( ( int16 * ) m_pubVarRead ); m_pubVarRead += sizeof( int16 ); return true; } //----------------------------------------------------------------------------- // Purpose: Reads an uint16 from the variable-length part of the message // Input: pnData - [return] The value we read goes here // Output: true if we were able to read, false if we overran the buffer //----------------------------------------------------------------------------- template bool CMsgBase_t::BReadUint16Data( uint16 *pusData ) { if ( m_pubVarRead + sizeof( uint16 ) > m_pubPkt + m_cubPkt ) { ReportBufferOverflow(); return false; } *pusData = * ( ( uint16 * ) m_pubVarRead ); m_pubVarRead += sizeof( uint16 ); return true; } //----------------------------------------------------------------------------- // Purpose: Read a uint64 from the variable-length part of the message // Input: pulData - [return] The value we read goes here // Output: true if we were able to read, false if we overran the buffer //----------------------------------------------------------------------------- template bool CMsgBase_t::BReadUint64Data( uint64 *pulData ) { if ( m_pubVarRead + sizeof( uint64 ) > m_pubPkt + m_cubPkt ) { ReportBufferOverflow(); return false; } *pulData = * ( ( uint64 * ) m_pubVarRead ); m_pubVarRead += sizeof( uint64 ); return true; } //----------------------------------------------------------------------------- // Purpose: Reads an int64 from the variable-length part of the message // Input: plData - [return] The value we read goes here // Output: true if we were able to read, false if we overran the buffer //----------------------------------------------------------------------------- template bool CMsgBase_t::BReadInt64Data( int64 *plData ) { if ( m_pubVarRead + sizeof( int64 ) > m_pubPkt + m_cubPkt ) { ReportBufferOverflow(); return false; } *plData = * ( ( int64 * ) m_pubVarRead ); m_pubVarRead += sizeof( int64 ); return true; } //----------------------------------------------------------------------------- // Purpose: Reads a float from the variable-length part of the message // Input: pflData - [return] The value we read goes here // Output: true if we were able to read, false if we overran the buffer //----------------------------------------------------------------------------- template bool CMsgBase_t::BReadFloatData( float *pflData ) { if ( m_pubVarRead + sizeof( float ) > m_pubPkt + m_cubPkt ) { ReportBufferOverflow(); return false; } *pflData = * ( ( float * ) m_pubVarRead ); m_pubVarRead += sizeof( float ); return true; } //----------------------------------------------------------------------------- // Purpose: Reads a block of data from the variable-length part of the message // Input: pvBuff - [return] Buffer to copy the data into // cubRead - Amount of data to read // Output: true if we were able to read, false if we overran the buffer //----------------------------------------------------------------------------- template bool CMsgBase_t::BReadVariableLenData( void *pvBuff, uint32 cubRead ) { if ( m_pubVarRead + cubRead > m_pubPkt + m_cubPkt ) { ReportBufferOverflow(); return false; } Q_memcpy( pvBuff, m_pubVarRead, cubRead ); m_pubVarRead += cubRead; return true; } //----------------------------------------------------------------------------- // Purpose: Reads a string from the variable-length part of the message // Input: pchBuff - [return] Buffer to copy the string into // cchBuff - Size of the buffer // Output: true if we were able to read, false if we overran the buffer //----------------------------------------------------------------------------- template bool CMsgBase_t::BReadStr( char *pchBuff, int cchBuff ) { int cchRead = 0; int cchLeft = CubReadRemaining(); // get bytes left in message // search for string end in rest of message while ( cchRead < cchLeft ) { // if we hit the 0, stop if ( *(m_pubVarRead+cchRead) == 0 ) break; cchRead++; } cchRead++; // add the 0 // check if string fits into buffer and was found within packet bounds if ( ( cchRead > cchBuff ) || (cchRead > cchLeft) ) { // at least return an empty string since most code doesn't check the return value if ( cchBuff > 0 ) pchBuff[0] = 0; ReportBufferOverflow(); return false; } // copy the string to output buffer Q_memcpy( pchBuff, m_pubVarRead, cchRead ); m_pubVarRead += ( cchRead * sizeof( char ) ); return true; } //----------------------------------------------------------------------------- // Purpose: Reads a string from the variable-length part of the message // Input: pchString - [return] copied string // Output: true if we were able to read, false if we overran the buffer //----------------------------------------------------------------------------- template bool CMsgBase_t::BReadStr( CUtlString *pstr ) { if ( pstr == NULL ) return false; int cchRead = 0; int cchLeft = CubReadRemaining(); // get bytes left in message // search for string end in rest of message while ( cchRead < cchLeft ) { // if we hit the 0, stop if ( *(m_pubVarRead+cchRead) == 0 ) break; cchRead++; } cchRead++; // add the 0 // check if string was found within packet bounds if ( cchRead > cchLeft ) { ReportBufferOverflow(); return false; } // copy the string *pstr = (const char*)m_pubVarRead; m_pubVarRead += ( cchRead * sizeof( char ) ); return true; } template template bool CMsgBase_t::BReadStructure( T& structure ) { int cbLeft = CubReadRemaining() ; if( cbLeft >= sizeof(structure)) { structure = *( reinterpret_cast(m_pubVarRead)) ; m_pubVarRead += sizeof(structure) ; return true ; } return false ; } template void CMsgBase_t::PacketDump() { //if ( !g_ConVarMsgErrorDump.GetBool() ) // return; EmitInfo( SPEW_NETWORK, SPEW_NEVER, LOG_ALWAYS, "Packet dump: raw size %u, header size %u, body size %u, var size %u\n", m_cubPkt, m_cubMsgHdr, m_cubStruct, CubVarData() ); EmitInfo( SPEW_NETWORK, SPEW_NEVER, LOG_ALWAYS, "Header dump: %s\n", Hdr().GetHeaderDescription().String() ); EmitInfo( SPEW_NETWORK, SPEW_NEVER, LOG_ALWAYS, "Struct dump: %u bytes\n", m_cubStruct ); char szLine[100] = ""; char szText[32] = ""; for ( uint i=0; i 31 && nValue != '%' ) szText[nIndex] = nValue; else szText[nIndex] = '.'; if ( nIndex == 15 || i==(m_cubStruct-1)) { szText[nIndex+1] = '\n'; szText[nIndex+2] = 0; Q_strcat( szLine, "; ", sizeof(szLine) ); Q_strcat( szLine, szText, sizeof(szLine) ); EmitInfo( SPEW_NETWORK, SPEW_NEVER, LOG_ALWAYS, "%s", szLine ); szLine[0]=0; } } uint cubVarData = MIN( CubVarData(), 1024u ); EmitInfo( SPEW_NETWORK, SPEW_NEVER, LOG_ALWAYS, "VarData dump: %u bytes\n", cubVarData ); for ( uint i=0; i 31 && nValue != '%' ) szText[nIndex] = nValue; else szText[nIndex] = '.'; if ( nIndex == 15 || i==(cubVarData-1)) { szText[nIndex+1] = '\n'; szText[nIndex+2] = 0; Q_strcat( szLine, " ; ", sizeof(szLine) ); Q_strcat( szLine, szText, sizeof(szLine) ); EmitInfo( SPEW_NETWORK, SPEW_NEVER, LOG_ALWAYS, "%s", szLine ); szLine[0]=0; } } } template void CMsgBase_t::ReportBufferOverflow() { EmitWarning( SPEW_NETWORK, SPEW_ALWAYS, "Read buffer overflowed on incoming %s packet\n", Hdr().PchMsgName( ) ); PacketDump(); } } // namespace GCSDK #endif // GCMSGBASE_H