csgo-2018-source/common/netmessages.h

558 lines
18 KiB
C
Raw Permalink Normal View History

2021-07-25 12:11:47 +08:00
//========= Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#ifndef NETMESSAGES_H
#define NETMESSAGES_H
#ifdef _WIN32
#pragma once
#pragma warning(disable : 4100) // unreferenced formal parameter
#endif
#include <inetmessage.h>
#include <checksum_crc.h>
#include <checksum_md5.h>
#include <const.h>
#include <utlvector.h>
#include "qlimits.h"
#include "mathlib/vector.h"
#include <soundflags.h>
#include <bitbuf.h>
#include <inetchannel.h>
#include "protocol.h"
#include <inetmsghandler.h>
#include <igameevents.h>
#include <bitvec.h>
#include "networksystem/inetworksystem.h"
#include <engine/iserverplugin.h>
#include <color.h>
#include <tier0/tslist.h>
#include <tier1/utldelegate.h>
#include "tier1/utlstring.h"
#include "tier1/tokenset.h"
#include "netmessages_signon.h"
// eliminates a conflict with TYPE_BOOL in OSX
#ifdef TYPE_BOOL
#undef TYPE_BOOL
#endif
#include "netmessages.pb.h"
#if !defined( _X360 )
#include "xbox/xboxstubs.h"
#endif
template< int msgType, typename PB_OBJECT_TYPE, int groupType = INetChannelInfo::GENERIC, bool bReliable = true >
class CNetMessagePB : public INetMessage, public PB_OBJECT_TYPE
{
public:
typedef CNetMessagePB< msgType, PB_OBJECT_TYPE, groupType, bReliable > MyType_t;
typedef PB_OBJECT_TYPE PBType_t;
static const int sk_Type = msgType;
CNetMessagePB() :
m_bReliable( bReliable )
{
}
virtual ~CNetMessagePB()
{
}
virtual bool ReadFromBuffer( bf_read &buffer )
{
int size = buffer.ReadVarInt32();
if ( size < 0 || size > NET_MAX_PAYLOAD )
{
return false;
}
// Check its valid
if ( size > buffer.GetNumBytesLeft() )
{
return false;
}
// If the read buffer is byte aligned, we can parse right out of it
if ( ( buffer.GetNumBitsRead() % 8 ) == 0 )
{
bool parseResult = PB_OBJECT_TYPE::ParseFromArray( buffer.GetBasePointer() + buffer.GetNumBytesRead(), size );
buffer.SeekRelative( size * 8 );
return parseResult;
}
// otherwise we have to do a temp allocation so we can read it all shifted
#ifdef NET_SHOW_UNALIGNED_MSGS
DevMsg("Warning: unaligned read of protobuf message %s (%d bytes)\n", PB_OBJECT_TYPE::GetTypeName().c_str(), size );
#endif
void *parseBuffer = stackalloc( size );
if ( !buffer.ReadBytes( parseBuffer, size ) )
{
return false;
}
if ( ! PB_OBJECT_TYPE::ParseFromArray( parseBuffer, size ) )
{
return false;
}
return true;
}
virtual bool WriteToBuffer( bf_write &buffer ) const
{
if ( !PB_OBJECT_TYPE::IsInitialized() )
{
Msg("WriteToBuffer Message %s is not initialized! Probably missing required fields!\n", PB_OBJECT_TYPE::GetTypeName().c_str() );
}
int size = PB_OBJECT_TYPE::ByteSize();
// If the write is byte aligned we can go direct
if ( ( buffer.GetNumBitsWritten() % 8 ) == 0 )
{
int sizeWithHeader = size + 1 + buffer.ByteSizeVarInt32( GetType() ) + buffer.ByteSizeVarInt32( size );
if ( buffer.GetNumBytesLeft() >= sizeWithHeader )
{
buffer.WriteVarInt32( GetType() );
buffer.WriteVarInt32( size );
if ( !PB_OBJECT_TYPE::SerializeWithCachedSizesToArray( ( google::protobuf::uint8 * )buffer.GetData() + buffer.GetNumBytesWritten() ) )
{
return false;
}
// Tell the buffer we just splatted into it
buffer.SeekToBit( buffer.GetNumBitsWritten() + ( size * 8 ) );
return true;
}
// Won't fit
return false;
}
// otherwise we have to do a temp allocation so we can write it all shifted
#ifdef NET_SHOW_UNALIGNED_MSGS
DevMsg("Warning: unaligned write of protobuf message %s (%d bytes)\n", PB_OBJECT_TYPE::GetTypeName().c_str(), size );
#endif
void *serializeBuffer = stackalloc( size );
if ( ! PB_OBJECT_TYPE::SerializeWithCachedSizesToArray( ( google::protobuf::uint8 * )serializeBuffer ) )
{
return false;
}
buffer.WriteVarInt32( GetType() );
buffer.WriteVarInt32( size );
return buffer.WriteBytes( serializeBuffer, size );
}
virtual const char *ToString() const
{
m_toString = PB_OBJECT_TYPE::DebugString();
return m_toString.c_str();
}
virtual int GetType() const
{
return msgType;
}
virtual size_t GetSize() const
{
return sizeof( *this );
}
virtual const char *GetName() const
{
if ( s_typeName.empty() )
{
s_typeName = PB_OBJECT_TYPE::GetTypeName();
}
return s_typeName.c_str();
}
virtual int GetGroup() const
{
return groupType;
}
virtual void SetReliable( bool state )
{
m_bReliable = state;
}
virtual bool IsReliable() const
{
return m_bReliable;
}
virtual INetMessage *Clone() const
{
MyType_t *pClone = new MyType_t;
pClone->CopyFrom( *this );
pClone->m_bReliable = m_bReliable;
return pClone;
}
protected:
bool m_bReliable; // true if message should be sent reliable
mutable std::string m_toString; // cached copy of ToString()
static std::string s_typeName;
};
template< int msgType, typename PB_OBJECT_TYPE, int groupType , bool bReliable >
std::string CNetMessagePB< msgType, PB_OBJECT_TYPE, groupType , bReliable >::s_typeName;
class CNetMessageBinder
{
public:
CNetMessageBinder()
: m_pBind( NULL )
{
}
~CNetMessageBinder()
{
delete m_pBind;
}
template< class _N >
void Bind( INetChannel *pNetChannel, CUtlDelegate< bool ( const typename _N::PBType_t & obj ) > handler )
{
delete m_pBind;
m_pBind = new BindParams<_N>( pNetChannel, handler );
}
void Unbind()
{
delete m_pBind;
m_pBind = NULL;
}
bool IsBound() const
{
return m_pBind != NULL;
}
private:
template < class _N >
struct BindParams : public INetMessageBinder
{
BindParams( INetChannel *pNetChannel, CUtlDelegate< bool ( const typename _N::PBType_t & obj ) > handler )
: m_NetChannel( pNetChannel )
, m_handler( handler )
{
if ( m_NetChannel )
{
m_NetChannel->RegisterMessage( this );
}
}
virtual ~BindParams()
{
if ( m_NetChannel )
{
m_NetChannel->UnregisterMessage( this );
}
}
virtual int GetType( void ) const
{
return _N::sk_Type;
}
virtual void SetNetChannel(INetChannel * netchan)
{
if( m_NetChannel != netchan )
{
if( m_NetChannel )
m_NetChannel->UnregisterMessage( this );
m_NetChannel = netchan;
if( m_NetChannel )
m_NetChannel->RegisterMessage( this );
}
}
virtual INetMessage *CreateFromBuffer( bf_read &buffer )
{
INetMessage *pMsg = new typename _N::MyType_t;
if ( !pMsg->ReadFromBuffer( buffer ) )
{
delete pMsg;
return NULL;
}
return pMsg;
}
virtual bool Process( const INetMessage &src )
{
const typename _N::MyType_t &typedSrc = static_cast< const typename _N::MyType_t & >( src );
Assert( m_handler );
if( m_handler )
{
return m_handler( static_cast< typename _N::PBType_t const & >( typedSrc ) );
}
return false;
}
INetChannel *m_NetChannel; // netchannel this message is from/for
CUtlDelegate< bool ( const typename _N::PBType_t & obj ) > m_handler;
};
INetMessageBinder *m_pBind;
};
///////////////////////////////////////////////////////////////////////////////////////
// bidirectional net messages:
///////////////////////////////////////////////////////////////////////////////////////
class CNETMsg_Tick_t : public CNetMessagePB< net_Tick, CNETMsg_Tick >
{
public:
static float FrametimeToFloat( uint32 frametime ) { return ( float )frametime / 1000000.0f; }
CNETMsg_Tick_t( int tick, float host_computationtime, float host_computationtime_stddeviation, float host_framestarttime_std_deviation )
{
SetReliable( false );
set_tick( tick );
set_host_computationtime( MIN( ( uint32 )( 1000000.0 * host_computationtime ), 1000000u ) );
set_host_computationtime_std_deviation( MIN( ( uint32 )( 1000000.0 * host_computationtime_stddeviation ), 1000000u ) );
set_host_framestarttime_std_deviation( MIN( ( uint32 )( 1000000.0 * host_framestarttime_std_deviation ), 1000000u ) );
}
};
class CNETMsg_StringCmd_t : public CNetMessagePB< net_StringCmd, CNETMsg_StringCmd, INetChannelInfo::STRINGCMD >
{
public:
CNETMsg_StringCmd_t( const char *command )
{
set_command( command );
}
};
class CNETMsg_PlayerAvatarData_t : public CNetMessagePB< net_PlayerAvatarData, CNETMsg_PlayerAvatarData, INetChannelInfo::PAINTMAP >
{
// 12 KB player avatar 64x64 rgb only no alpha
// WARNING-WARNING-WARNING
// This message is extremely large for our net channels
// and must be pumped through special fragmented waiting list
// via chunk-based ack mechanism!
// See: INetChannel::EnqueueVeryLargeAsyncTransfer
// WARNING-WARNING-WARNING
public:
CNETMsg_PlayerAvatarData_t() {}
CNETMsg_PlayerAvatarData_t( uint32 unAccountID, void const *pvData, uint32 cbData )
{
set_accountid( unAccountID );
set_rgb( ( const char * ) pvData, cbData );
}
};
class CNETMsg_SignonState_t : public CNetMessagePB< net_SignonState, CNETMsg_SignonState, INetChannelInfo::SIGNON >
{
public:
CNETMsg_SignonState_t( int state, int spawncount )
{
set_signon_state( state );
set_spawn_count( spawncount );
set_num_server_players( 0 );
}
};
inline void NetMsgSetCVarUsingDictionary( CMsg_CVars::CVar *convar, char const * name, char const * value )
{
convar->set_value( value );
if ( 0 ) ( void ) 0;
/** Removed for partner depot **/
else
{
#ifdef _DEBUG
DevWarning( "Missing dictionary entry for cvar '%s'\n", name );
#endif
convar->set_name( name );
}
}
inline void NetMsgExpandCVarUsingDictionary( CMsg_CVars::CVar *convar )
{
if ( convar->has_name() )
return;
switch ( convar->dictionary_name() )
{
case 0: return;
/** Removed for partner depot **/
default:
DevWarning( "Invalid dictionary entry for cvar # %d\n", convar->dictionary_name() );
convar->set_name( "undefined" );
break;
}
}
inline const char * NetMsgGetCVarUsingDictionary( CMsg_CVars::CVar const &convar )
{
if ( convar.has_name() )
return convar.name().c_str();
switch ( convar.dictionary_name() )
{
case 0: return "";
/** Removed for partner depot **/
default:
DevWarning( "Invalid dictionary entry for cvar # %d\n", convar.dictionary_name() );
return "undefined";
}
}
class CNETMsg_SetConVar_t : public CNetMessagePB< net_SetConVar, CNETMsg_SetConVar, INetChannelInfo::STRINGCMD >
{
public:
CNETMsg_SetConVar_t() {}
CNETMsg_SetConVar_t( const char * name, const char * value )
{
AddToTail( name, value );
}
void AddToTail( const char * name, const char * value )
{
NetMsgSetCVarUsingDictionary( mutable_convars()->add_cvars(), name, value );
}
};
typedef CNetMessagePB< net_NOP, CNETMsg_NOP > CNETMsg_NOP_t;
typedef CNetMessagePB< net_Disconnect, CNETMsg_Disconnect > CNETMsg_Disconnect_t;
typedef CNetMessagePB< net_File, CNETMsg_File > CNETMsg_File_t;
typedef CNetMessagePB< net_SplitScreenUser, CNETMsg_SplitScreenUser > CNETMsg_SplitScreenUser_t;
///////////////////////////////////////////////////////////////////////////////////////
// Client messages: Sent from the client to the server
///////////////////////////////////////////////////////////////////////////////////////
typedef CNetMessagePB< clc_SplitPlayerConnect, CCLCMsg_SplitPlayerConnect > CCLCMsg_SplitPlayerConnect_t;
typedef CNetMessagePB< clc_Move, CCLCMsg_Move, INetChannelInfo::MOVE, false > CCLCMsg_Move_t;
typedef CNetMessagePB< clc_ClientInfo, CCLCMsg_ClientInfo > CCLCMsg_ClientInfo_t;
typedef CNetMessagePB< clc_VoiceData, CCLCMsg_VoiceData, INetChannelInfo::VOICE, false > CCLCMsg_VoiceData_t;
typedef CNetMessagePB< clc_BaselineAck, CCLCMsg_BaselineAck > CCLCMsg_BaselineAck_t;
typedef CNetMessagePB< clc_ListenEvents, CCLCMsg_ListenEvents > CCLCMsg_ListenEvents_t;
typedef CNetMessagePB< clc_RespondCvarValue, CCLCMsg_RespondCvarValue > CCLCMsg_RespondCvarValue_t;
typedef CNetMessagePB< clc_LoadingProgress, CCLCMsg_LoadingProgress > CCLCMsg_LoadingProgress_t;
typedef CNetMessagePB< clc_CmdKeyValues, CCLCMsg_CmdKeyValues > CCLCMsg_CmdKeyValues_t;
typedef CNetMessagePB< clc_HltvReplay, CCLCMsg_HltvReplay > CCLCMsg_HltvReplay_t;
class CCLCMsg_FileCRCCheck_t : public CNetMessagePB< clc_FileCRCCheck, CCLCMsg_FileCRCCheck >
{
public:
// Warning: These routines may use the va() function...
static void SetPath( CCLCMsg_FileCRCCheck& msg, const char *path );
static const char *GetPath( const CCLCMsg_FileCRCCheck& msg );
static void SetFileName( CCLCMsg_FileCRCCheck& msg, const char *fileName );
static const char *GetFileName( const CCLCMsg_FileCRCCheck& msg );
};
///////////////////////////////////////////////////////////////////////////////////////
// Server messages: Sent from the server to the client
///////////////////////////////////////////////////////////////////////////////////////
typedef CNetMessagePB< svc_ServerInfo, CSVCMsg_ServerInfo, INetChannelInfo::SIGNON > CSVCMsg_ServerInfo_t;
typedef CNetMessagePB< svc_ClassInfo, CSVCMsg_ClassInfo, INetChannelInfo::SIGNON > CSVCMsg_ClassInfo_t;
typedef CNetMessagePB< svc_SendTable, CSVCMsg_SendTable, INetChannelInfo::SIGNON > CSVCMsg_SendTable_t;
typedef CNetMessagePB< svc_Print, CSVCMsg_Print, INetChannelInfo::GENERIC, false > CSVCMsg_Print_t;
typedef CNetMessagePB< svc_SetPause, CSVCMsg_SetPause > CSVCMsg_SetPause_t;
typedef CNetMessagePB< svc_SetView, CSVCMsg_SetView > CSVCMsg_SetView_t;
typedef CNetMessagePB< svc_CreateStringTable, CSVCMsg_CreateStringTable, INetChannelInfo::SIGNON > CSVCMsg_CreateStringTable_t;
typedef CNetMessagePB< svc_UpdateStringTable, CSVCMsg_UpdateStringTable, INetChannelInfo::STRINGTABLE > CSVCMsg_UpdateStringTable_t;
typedef CNetMessagePB< svc_VoiceInit, CSVCMsg_VoiceInit, INetChannelInfo::SIGNON > CSVCMsg_VoiceInit_t;
typedef CNetMessagePB< svc_VoiceData, CSVCMsg_VoiceData, INetChannelInfo::VOICE, false > CSVCMsg_VoiceData_t;
typedef CNetMessagePB< svc_FixAngle, CSVCMsg_FixAngle, INetChannelInfo::GENERIC, false > CSVCMsg_FixAngle_t;
typedef CNetMessagePB< svc_Prefetch, CSVCMsg_Prefetch, INetChannelInfo::SOUNDS > CSVCMsg_Prefetch_t;
typedef CNetMessagePB< svc_CrosshairAngle, CSVCMsg_CrosshairAngle > CSVCMsg_CrosshairAngle_t;
typedef CNetMessagePB< svc_BSPDecal, CSVCMsg_BSPDecal > CSVCMsg_BSPDecal_t;
typedef CNetMessagePB< svc_SplitScreen, CSVCMsg_SplitScreen > CSVCMsg_SplitScreen_t;
typedef CNetMessagePB< svc_GetCvarValue, CSVCMsg_GetCvarValue > CSVCMsg_GetCvarValue_t;
typedef CNetMessagePB< svc_Menu, CSVCMsg_Menu, INetChannelInfo::GENERIC, false > CSVCMsg_Menu_t;
typedef CNetMessagePB< svc_UserMessage, CSVCMsg_UserMessage, INetChannelInfo::USERMESSAGES, false > CSVCMsg_UserMessage_t;
typedef CNetMessagePB< svc_PaintmapData, CSVCMsg_PaintmapData, INetChannelInfo::PAINTMAP > CSVCMsg_PaintmapData_t;
typedef CNetMessagePB< svc_GameEvent, CSVCMsg_GameEvent, INetChannelInfo::EVENTS > CSVCMsg_GameEvent_t;
typedef CNetMessagePB< svc_GameEventList, CSVCMsg_GameEventList > CSVCMsg_GameEventList_t;
typedef CNetMessagePB< svc_TempEntities, CSVCMsg_TempEntities, INetChannelInfo::TEMPENTS, false > CSVCMsg_TempEntities_t;
typedef CNetMessagePB< svc_PacketEntities, CSVCMsg_PacketEntities, INetChannelInfo::ENTITIES > CSVCMsg_PacketEntities_t;
typedef CNetMessagePB< svc_Sounds, CSVCMsg_Sounds, INetChannelInfo::SOUNDS > CSVCMsg_Sounds_t;
typedef CNetMessagePB< svc_EntityMessage, CSVCMsg_EntityMsg, INetChannelInfo::ENTMESSAGES, false > CSVCMsg_EntityMsg_t;
typedef CNetMessagePB< svc_CmdKeyValues, CSVCMsg_CmdKeyValues > CSVCMsg_CmdKeyValues_t;
typedef CNetMessagePB< svc_EncryptedData, CSVCMsg_EncryptedData, INetChannelInfo::ENCRYPTED > CSVCMsg_EncryptedData_t;
typedef CNetMessagePB< svc_HltvReplay, CSVCMsg_HltvReplay, INetChannelInfo::ENTITIES > CSVCMsg_HltvReplay_t;
typedef CNetMessagePB< svc_Broadcast_Command, CSVCMsg_Broadcast_Command, INetChannelInfo::STRINGCMD > CSVCMsg_Broadcast_Command_t;
///////////////////////////////////////////////////////////////////////////////////////
// Utility classes
///////////////////////////////////////////////////////////////////////////////////////
class CmdKeyValuesHelper
{
public:
static void CLCMsg_SetKeyValues( CCLCMsg_CmdKeyValues& msg, const KeyValues *keyValues );
static KeyValues* CLCMsg_GetKeyValues ( const CCLCMsg_CmdKeyValues& msg );
static void SVCMsg_SetKeyValues( CSVCMsg_CmdKeyValues& msg, const KeyValues *keyValues );
static KeyValues *SVCMsg_GetKeyValues ( const CSVCMsg_CmdKeyValues& msg );
};
class INetChannel;
class CmdEncryptedDataMessageCodec
{
public:
static bool SVCMsg_EncryptedData_EncryptMessage( CSVCMsg_EncryptedData_t &msgEncryptedResult, INetMessage *pMsgPlaintextInput, char const *key );
static bool SVCMsg_EncryptedData_Process( CSVCMsg_EncryptedData const &msgEncryptedInput, INetChannel *pProcessingChannel, char const *key );
};
//////////////////////////////////////////////////////////////////////////
// Helper class to share network buffers in the entire process
//////////////////////////////////////////////////////////////////////////
class net_scratchbuffer_t
{
public:
net_scratchbuffer_t()
{
m_pBufferNetMaxMessage = sm_NetScratchBuffers.Get();
if ( !m_pBufferNetMaxMessage )
m_pBufferNetMaxMessage = new buffer_t;
}
~net_scratchbuffer_t()
{
sm_NetScratchBuffers.PutObject( m_pBufferNetMaxMessage );
}
byte * GetBuffer() const
{
return m_pBufferNetMaxMessage->buf;
}
int Size() const
{
return NET_MAX_MESSAGE;
}
private:
struct buffer_t { byte buf[ NET_MAX_MESSAGE ]; };
buffer_t *m_pBufferNetMaxMessage; // buffer that is allocated and returned to shared pool
private:
net_scratchbuffer_t( const net_scratchbuffer_t& ); // FORBID
net_scratchbuffer_t& operator=( const net_scratchbuffer_t& ); // FORBID
static CTSPool< buffer_t > sm_NetScratchBuffers;
};
#endif // NETMESSAGES_H