//========= Copyright 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 #include #include #include #include #include "qlimits.h" #include "mathlib/vector.h" #include #include #include #include "protocol.h" #include #include #include #include #include #include "proto_version.h" #if !defined( _X360 ) #include "xbox/xboxstubs.h" #endif class SendTable; class KeyValue; class KeyValues; class INetMessageHandler; class IServerMessageHandler; class IClientMessageHandler; #define DECLARE_BASE_MESSAGE( msgtype ) \ public: \ bool ReadFromBuffer( bf_read &buffer ); \ bool WriteToBuffer( bf_write &buffer ); \ const char *ToString() const; \ int GetType() const { return msgtype; } \ const char *GetName() const { return #msgtype;}\ #define DECLARE_NET_MESSAGE( name ) \ DECLARE_BASE_MESSAGE( net_##name ); \ INetMessageHandler *m_pMessageHandler; \ bool Process() { return m_pMessageHandler->Process##name( this ); }\ #define DECLARE_SVC_MESSAGE( name ) \ DECLARE_BASE_MESSAGE( svc_##name ); \ IServerMessageHandler *m_pMessageHandler;\ bool Process() { return m_pMessageHandler->Process##name( this ); }\ #define DECLARE_CLC_MESSAGE( name ) \ DECLARE_BASE_MESSAGE( clc_##name ); \ IClientMessageHandler *m_pMessageHandler;\ bool Process() { return m_pMessageHandler->Process##name( this ); }\ #define DECLARE_MM_MESSAGE( name ) \ DECLARE_BASE_MESSAGE( mm_##name ); \ IMatchmakingMessageHandler *m_pMessageHandler;\ bool Process() { return m_pMessageHandler->Process##name( this ); }\ class CNetMessage : public INetMessage { public: CNetMessage() { m_bReliable = true; m_NetChannel = NULL; } virtual ~CNetMessage() {}; virtual int GetGroup() const { return INetChannelInfo::GENERIC; } INetChannel *GetNetChannel() const { return m_NetChannel; } virtual void SetReliable( bool state) {m_bReliable = state;}; virtual bool IsReliable() const { return m_bReliable; }; virtual void SetNetChannel(INetChannel * netchan) { m_NetChannel = netchan; } virtual bool Process() { Assert( 0 ); return false; }; // no handler set protected: bool m_bReliable; // true if message should be send reliable INetChannel *m_NetChannel; // netchannel this message is from/for }; /////////////////////////////////////////////////////////////////////////////////////// // bidirectional net messages: /////////////////////////////////////////////////////////////////////////////////////// class NET_SetConVar : public CNetMessage { DECLARE_NET_MESSAGE( SetConVar ); int GetGroup() const { return INetChannelInfo::STRINGCMD; } NET_SetConVar() {} NET_SetConVar( const char * name, const char * value) { cvar_t localCvar; Q_strncpy( localCvar.name, name, MAX_OSPATH ); Q_strncpy( localCvar.value, value, MAX_OSPATH ); m_ConVars.AddToTail( localCvar ); } public: typedef struct cvar_s { char name[MAX_OSPATH]; char value[MAX_OSPATH]; } cvar_t; CUtlVector m_ConVars; }; class NET_StringCmd : public CNetMessage { DECLARE_NET_MESSAGE( StringCmd ); int GetGroup() const { return INetChannelInfo::STRINGCMD; } NET_StringCmd() { m_szCommand = NULL; }; NET_StringCmd(const char *cmd) { m_szCommand = cmd; }; public: const char *m_szCommand; // execute this command private: char m_szCommandBuffer[1024]; // buffer for received messages }; class NET_Tick : public CNetMessage { DECLARE_NET_MESSAGE( Tick ); NET_Tick() { m_bReliable = false; #if PROTOCOL_VERSION > 10 m_flHostFrameTime = 0; m_flHostFrameTimeStdDeviation = 0; #endif }; NET_Tick( int tick, float hostFrametime, float hostFrametime_stddeviation ) { m_bReliable = false; m_nTick = tick; #if PROTOCOL_VERSION > 10 m_flHostFrameTime = hostFrametime; m_flHostFrameTimeStdDeviation = hostFrametime_stddeviation; #else NOTE_UNUSED( hostFrametime ); NOTE_UNUSED( hostFrametime_stddeviation ); #endif }; public: int m_nTick; #if PROTOCOL_VERSION > 10 float m_flHostFrameTime; float m_flHostFrameTimeStdDeviation; #endif }; class NET_SignonState : public CNetMessage { DECLARE_NET_MESSAGE( SignonState ); int GetGroup() const { return INetChannelInfo::SIGNON; } NET_SignonState() {}; NET_SignonState( int state, int spawncount ) { m_nSignonState = state; m_nSpawnCount = spawncount; }; public: int m_nSignonState; // See SIGNONSTATE_ defines int m_nSpawnCount; // server spawn count (session number) }; /////////////////////////////////////////////////////////////////////////////////////// // Client messages: /////////////////////////////////////////////////////////////////////////////////////// class CLC_ClientInfo : public CNetMessage { DECLARE_CLC_MESSAGE( ClientInfo ); public: CRC32_t m_nSendTableCRC; int m_nServerCount; bool m_bIsHLTV; #if defined( REPLAY_ENABLED ) bool m_bIsReplay; #endif uint32 m_nFriendsID; char m_FriendsName[MAX_PLAYER_NAME_LENGTH]; CRC32_t m_nCustomFiles[MAX_CUSTOM_FILES]; }; class CLC_Move : public CNetMessage { DECLARE_CLC_MESSAGE( Move ); int GetGroup() const { return INetChannelInfo::MOVE; } CLC_Move() { m_bReliable = false; } public: int m_nBackupCommands; int m_nNewCommands; int m_nLength; bf_read m_DataIn; bf_write m_DataOut; }; class CLC_VoiceData : public CNetMessage { DECLARE_CLC_MESSAGE( VoiceData ); int GetGroup() const { return INetChannelInfo::VOICE; } CLC_VoiceData() { m_bReliable = false; }; public: int m_nLength; bf_read m_DataIn; bf_write m_DataOut; uint64 m_xuid; }; class CLC_BaselineAck : public CNetMessage { DECLARE_CLC_MESSAGE( BaselineAck ); CLC_BaselineAck() {}; CLC_BaselineAck(int tick, int baseline ) { m_nBaselineTick = tick; m_nBaselineNr = baseline; } int GetGroup() const { return INetChannelInfo::ENTITIES; } public: int m_nBaselineTick; // sequence number of baseline int m_nBaselineNr; // 0 or 1 }; class CLC_ListenEvents : public CNetMessage { DECLARE_CLC_MESSAGE( ListenEvents ); int GetGroup() const { return INetChannelInfo::SIGNON; } public: CBitVec m_EventArray; }; #if defined( REPLAY_ENABLED ) class CLC_SaveReplay : public CNetMessage { DECLARE_CLC_MESSAGE( SaveReplay ); CLC_SaveReplay() {} int m_nStartSendByte; char m_szFilename[ MAX_OSPATH ]; float m_flPostDeathRecordTime; }; #endif class CLC_RespondCvarValue : public CNetMessage { public: DECLARE_CLC_MESSAGE( RespondCvarValue ); QueryCvarCookie_t m_iCookie; const char *m_szCvarName; const char *m_szCvarValue; // The sender sets this, and it automatically points it at m_szCvarNameBuffer when receiving. EQueryCvarValueStatus m_eStatusCode; private: char m_szCvarNameBuffer[256]; char m_szCvarValueBuffer[256]; }; class CLC_FileCRCCheck : public CNetMessage { public: DECLARE_CLC_MESSAGE( FileCRCCheck ); char m_szPathID[MAX_PATH]; char m_szFilename[MAX_PATH]; MD5Value_t m_MD5; CRC32_t m_CRCIOs; int m_eFileHashType; int m_cbFileLen; int m_nPackFileNumber; int m_PackFileID; int m_nFileFraction; }; class CLC_FileMD5Check : public CNetMessage { public: DECLARE_CLC_MESSAGE( FileMD5Check ); char m_szPathID[MAX_PATH]; char m_szFilename[MAX_PATH]; MD5Value_t m_MD5; }; class Base_CmdKeyValues : public CNetMessage { protected: explicit Base_CmdKeyValues( KeyValues *pKeyValues = NULL ); // takes ownership ~Base_CmdKeyValues(); public: KeyValues * GetKeyValues() const { return m_pKeyValues; } public: bool ReadFromBuffer( bf_read &buffer ); bool WriteToBuffer( bf_write &buffer ); const char * ToString() const; protected: KeyValues *m_pKeyValues; }; class CLC_CmdKeyValues : public Base_CmdKeyValues { public: DECLARE_CLC_MESSAGE( CmdKeyValues ); public: explicit CLC_CmdKeyValues( KeyValues *pKeyValues = NULL ); // takes ownership }; class SVC_CmdKeyValues : public Base_CmdKeyValues { public: DECLARE_SVC_MESSAGE( CmdKeyValues ); public: explicit SVC_CmdKeyValues( KeyValues *pKeyValues = NULL ); // takes ownership }; /////////////////////////////////////////////////////////////////////////////////////// // server messages: /////////////////////////////////////////////////////////////////////////////////////// class SVC_Print : public CNetMessage { DECLARE_SVC_MESSAGE( Print ); SVC_Print() { m_bReliable = false; m_szText = NULL; }; SVC_Print(const char * text) { m_bReliable = false; m_szText = text; }; public: const char *m_szText; // show this text private: char m_szTextBuffer[2048]; // buffer for received messages }; class SVC_ServerInfo : public CNetMessage { DECLARE_SVC_MESSAGE( ServerInfo ); int GetGroup() const { return INetChannelInfo::SIGNON; } public: // member vars are public for faster handling int m_nProtocol; // protocol version int m_nServerCount; // number of changelevels since server start bool m_bIsDedicated; // dedicated server ? bool m_bIsHLTV; // HLTV server ? #if defined( REPLAY_ENABLED ) bool m_bIsReplay; // Replay server ? #endif char m_cOS; // L = linux, W = Win32 CRC32_t m_nMapCRC; // server map CRC (only used by older demos) MD5Value_t m_nMapMD5; // server map MD5 int m_nMaxClients; // max number of clients on server int m_nMaxClasses; // max number of server classes int m_nPlayerSlot; // our client slot number float m_fTickInterval;// server tick interval const char *m_szGameDir; // game directory eg "tf2" const char *m_szMapName; // name of current map const char *m_szSkyName; // name of current skybox const char *m_szHostName; // server name private: char m_szGameDirBuffer[MAX_OSPATH];// game directory eg "tf2" char m_szMapNameBuffer[MAX_OSPATH];// name of current map char m_szSkyNameBuffer[MAX_OSPATH];// name of current skybox char m_szHostNameBuffer[MAX_OSPATH];// name of current skybox }; class SVC_SendTable : public CNetMessage { DECLARE_SVC_MESSAGE( SendTable ); int GetGroup() const { return INetChannelInfo::SIGNON; } public: bool m_bNeedsDecoder; int m_nLength; bf_read m_DataIn; bf_write m_DataOut; }; class SVC_ClassInfo : public CNetMessage { DECLARE_SVC_MESSAGE( ClassInfo ); int GetGroup() const { return INetChannelInfo::SIGNON; } SVC_ClassInfo() {}; SVC_ClassInfo( bool createFromSendTables, int numClasses ) { m_bCreateOnClient = createFromSendTables; m_nNumServerClasses = numClasses; }; public: typedef struct class_s { int classID; char datatablename[256]; char classname[256]; } class_t; bool m_bCreateOnClient; // if true, client creates own SendTables & classinfos from game.dll CUtlVector m_Classes; int m_nNumServerClasses; }; class SVC_SetPause : public CNetMessage { DECLARE_SVC_MESSAGE( SetPause ); SVC_SetPause() {} SVC_SetPause( bool state, float end = -1.f ) { m_bPaused = state; } public: bool m_bPaused; // true or false, what else }; class SVC_SetPauseTimed : public CNetMessage { DECLARE_SVC_MESSAGE( SetPauseTimed ); SVC_SetPauseTimed() {} SVC_SetPauseTimed( bool bState, float flExpireTime = -1.f ) { m_bPaused = bState; m_flExpireTime = flExpireTime; } public: bool m_bPaused; float m_flExpireTime; }; class CNetworkStringTable; class SVC_CreateStringTable : public CNetMessage { DECLARE_SVC_MESSAGE( CreateStringTable ); int GetGroup() const { return INetChannelInfo::SIGNON; } public: SVC_CreateStringTable(); public: const char *m_szTableName; int m_nMaxEntries; int m_nNumEntries; bool m_bUserDataFixedSize; int m_nUserDataSize; int m_nUserDataSizeBits; bool m_bIsFilenames; int m_nLength; bf_read m_DataIn; bf_write m_DataOut; bool m_bDataCompressed; private: char m_szTableNameBuffer[256]; }; class SVC_UpdateStringTable : public CNetMessage { DECLARE_SVC_MESSAGE( UpdateStringTable ); int GetGroup() const { return INetChannelInfo::STRINGTABLE; } public: int m_nTableID; // table to be updated int m_nChangedEntries; // number of how many entries has changed int m_nLength; // data length in bits bf_read m_DataIn; bf_write m_DataOut; }; // SVC_VoiceInit // v2 - 2017/02/07 // - Can detect v2 packets by nLegacyQuality == 255 and presence of additional nSampleRate field. // - Added nSampleRate field. Previously, nSampleRate was hard-coded per codec type. ::ReadFromBuffer does a // one-time conversion of these old types (which can no longer change) // - Marked quality field as deprecated. This was already being ignored. v2 clients send 255 // - Prior to this the sv_use_steam_voice convar was used to switch to steam voice. With this, we properly set // szVoiceCodec to "steam". See ::ReadFromBuffer for shim to fallback to the convar for old streams. // - We no longer pass "svc_voiceinit NULL" as szVoiceCodec if it is not selected, just the empty string. Nothing // used this that I could find. class SVC_VoiceInit : public CNetMessage { DECLARE_SVC_MESSAGE( VoiceInit ); int GetGroup() const { return INetChannelInfo::SIGNON; } SVC_VoiceInit() : m_nSampleRate( 0 ) { V_memset( m_szVoiceCodec, 0, sizeof( m_szVoiceCodec ) ); } SVC_VoiceInit( const char * codec, int nSampleRate ) : m_nSampleRate( nSampleRate ) { V_strncpy( m_szVoiceCodec, codec ? codec : "", sizeof( m_szVoiceCodec ) ); } public: // Used voice codec for voice_init. // // This used to be a DLL name, then became a whitelisted list of codecs. char m_szVoiceCodec[MAX_OSPATH]; // DEPRECATED: // // This field used to be a custom quality setting, but it was not honored for a long time: codecs use their own // pre-configured quality settings. We never sent anything besides 5, which was then ignored for some codecs. // // New clients always set 255 here, old clients probably send 5. This could be re-purposed in the future, but beware // that very old demos may have non-5 values. It would take more archaeology to determine how to properly interpret // those packets -- they're probably using settings we simply don't support any longer. // // int m_nQuality; // The sample rate we are using int m_nSampleRate; }; class SVC_VoiceData : public CNetMessage { DECLARE_SVC_MESSAGE( VoiceData ); int GetGroup() const { return INetChannelInfo::VOICE; } SVC_VoiceData() { m_bReliable = false; } public: int m_nFromClient; // client who has spoken bool m_bProximity; int m_nLength; // data length in bits uint64 m_xuid; // X360 player ID bf_read m_DataIn; void *m_DataOut; }; class SVC_Sounds : public CNetMessage { DECLARE_SVC_MESSAGE( Sounds ); int GetGroup() const { return INetChannelInfo::SOUNDS; } public: bool m_bReliableSound; int m_nNumSounds; int m_nLength; bf_read m_DataIn; bf_write m_DataOut; }; class SVC_Prefetch : public CNetMessage { DECLARE_SVC_MESSAGE( Prefetch ); int GetGroup() const { return INetChannelInfo::SOUNDS; } enum { SOUND = 0, }; public: unsigned short m_fType; unsigned short m_nSoundIndex; }; class SVC_SetView : public CNetMessage { DECLARE_SVC_MESSAGE( SetView ); SVC_SetView() {} SVC_SetView( int entity ) { m_nEntityIndex = entity; } public: int m_nEntityIndex; }; class SVC_FixAngle: public CNetMessage { DECLARE_SVC_MESSAGE( FixAngle ); SVC_FixAngle() { m_bReliable = false; }; SVC_FixAngle( bool bRelative, QAngle angle ) { m_bReliable = false; m_bRelative = bRelative; m_Angle = angle; } public: bool m_bRelative; QAngle m_Angle; }; class SVC_CrosshairAngle : public CNetMessage { DECLARE_SVC_MESSAGE( CrosshairAngle ); SVC_CrosshairAngle() {} SVC_CrosshairAngle( QAngle angle ) { m_Angle = angle; } public: QAngle m_Angle; }; class SVC_BSPDecal : public CNetMessage { DECLARE_SVC_MESSAGE( BSPDecal ); public: Vector m_Pos; int m_nDecalTextureIndex; int m_nEntityIndex; int m_nModelIndex; bool m_bLowPriority; }; class SVC_GameEvent : public CNetMessage { DECLARE_SVC_MESSAGE( GameEvent ); int GetGroup() const { return INetChannelInfo::EVENTS; } public: int m_nLength; // data length in bits bf_read m_DataIn; bf_write m_DataOut; }; class SVC_UserMessage: public CNetMessage { DECLARE_SVC_MESSAGE( UserMessage ); SVC_UserMessage() { m_bReliable = false; } int GetGroup() const { return INetChannelInfo::USERMESSAGES; } public: int m_nMsgType; int m_nLength; // data length in bits bf_read m_DataIn; bf_write m_DataOut; }; class SVC_EntityMessage : public CNetMessage { DECLARE_SVC_MESSAGE( EntityMessage ); SVC_EntityMessage() { m_bReliable = false; } int GetGroup() const { return INetChannelInfo::ENTMESSAGES ; } public: int m_nEntityIndex; int m_nClassID; int m_nLength; // data length in bits bf_read m_DataIn; bf_write m_DataOut; }; /* class SVC_SpawnBaseline: public CNetMessage { DECLARE_SVC_MESSAGE( SpawnBaseline ); int GetGroup() const { return INetChannelInfo::SIGNON; } public: int m_nEntityIndex; int m_nClassID; int m_nLength; bf_read m_DataIn; bf_write m_DataOut; }; */ class SVC_PacketEntities: public CNetMessage { DECLARE_SVC_MESSAGE( PacketEntities ); int GetGroup() const { return INetChannelInfo::ENTITIES ; } public: int m_nMaxEntries; int m_nUpdatedEntries; bool m_bIsDelta; bool m_bUpdateBaseline; int m_nBaseline; int m_nDeltaFrom; int m_nLength; bf_read m_DataIn; bf_write m_DataOut; }; class SVC_TempEntities: public CNetMessage { DECLARE_SVC_MESSAGE( TempEntities ); SVC_TempEntities() { m_bReliable = false; } int GetGroup() const { return INetChannelInfo::EVENTS; } int m_nNumEntries; int m_nLength; bf_read m_DataIn; bf_write m_DataOut; }; class SVC_Menu : public CNetMessage { public: DECLARE_SVC_MESSAGE( Menu ); SVC_Menu() { m_bReliable = true; m_Type = DIALOG_MENU; m_MenuKeyValues = NULL; }; SVC_Menu( DIALOG_TYPE type, KeyValues *data ); ~SVC_Menu(); KeyValues *m_MenuKeyValues; DIALOG_TYPE m_Type; int m_iLength; }; class SVC_GameEventList : public CNetMessage { public: DECLARE_SVC_MESSAGE( GameEventList ); int m_nNumEvents; int m_nLength; bf_read m_DataIn; bf_write m_DataOut; }; /////////////////////////////////////////////////////////////////////////////////////// // Matchmaking messages: /////////////////////////////////////////////////////////////////////////////////////// class MM_Heartbeat : public CNetMessage { public: DECLARE_MM_MESSAGE( Heartbeat ); }; class MM_ClientInfo : public CNetMessage { public: DECLARE_MM_MESSAGE( ClientInfo ); XNADDR m_xnaddr; // xbox net address uint64 m_id; // machine ID uint64 m_xuids[MAX_PLAYERS_PER_CLIENT]; byte m_cVoiceState[MAX_PLAYERS_PER_CLIENT]; bool m_bInvited; char m_cPlayers; char m_iControllers[MAX_PLAYERS_PER_CLIENT]; char m_iTeam[MAX_PLAYERS_PER_CLIENT]; char m_szGamertags[MAX_PLAYERS_PER_CLIENT][MAX_PLAYER_NAME_LENGTH]; }; class MM_RegisterResponse : public CNetMessage { public: DECLARE_MM_MESSAGE( RegisterResponse ); }; class MM_Mutelist : public CNetMessage { public: DECLARE_MM_MESSAGE( Mutelist ); uint64 m_id; byte m_cPlayers; byte m_cRemoteTalkers[MAX_PLAYERS_PER_CLIENT]; XUID m_xuid[MAX_PLAYERS_PER_CLIENT]; byte m_cMuted[MAX_PLAYERS_PER_CLIENT]; CUtlVector< XUID > m_Muted[MAX_PLAYERS_PER_CLIENT]; }; class MM_Checkpoint : public CNetMessage { public: DECLARE_MM_MESSAGE( Checkpoint ); enum eCheckpoint { CHECKPOINT_CHANGETEAM, CHECKPOINT_GAME_LOBBY, CHECKPOINT_PREGAME, CHECKPOINT_LOADING_COMPLETE, CHECKPOINT_CONNECT, CHECKPOINT_SESSION_DISCONNECT, CHECKPOINT_REPORT_STATS, CHECKPOINT_REPORTING_COMPLETE, CHECKPOINT_POSTGAME, }; byte m_Checkpoint; }; // NOTE: The following messages are not network-endian compliant, due to the // transmission of structures instead of their component parts class MM_JoinResponse : public CNetMessage { public: DECLARE_MM_MESSAGE( JoinResponse ); MM_JoinResponse() { m_ContextCount = 0; m_PropertyCount = 0; } enum { JOINRESPONSE_APPROVED, JOINRESPONSE_APPROVED_JOINGAME, JOINRESPONSE_SESSIONFULL, JOINRESPONSE_NOTHOSTING, JOINRESPONSE_MODIFY_SESSION, }; uint m_ResponseType; // host info uint64 m_id; // Host's machine ID uint64 m_Nonce; // Session nonce uint m_SessionFlags; uint m_nOwnerId; int m_iTeam; int m_nTotalTeams; int m_PropertyCount; int m_ContextCount; CUtlVector< XUSER_PROPERTY >m_SessionProperties; CUtlVector< XUSER_CONTEXT >m_SessionContexts; }; class MM_Migrate : public CNetMessage { public: DECLARE_MM_MESSAGE( Migrate ); enum eMsgType { MESSAGE_HOSTING, MESSAGE_MIGRATED, MESSAGE_STANDBY, }; byte m_MsgType; uint64 m_Id; XNKID m_sessionId; XNADDR m_xnaddr; XNKEY m_key; }; class SVC_GetCvarValue : public CNetMessage { public: DECLARE_SVC_MESSAGE( GetCvarValue ); QueryCvarCookie_t m_iCookie; const char *m_szCvarName; // The sender sets this, and it automatically points it at m_szCvarNameBuffer when receiving. private: char m_szCvarNameBuffer[256]; }; #endif // NETMESSAGES_H