//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // //=============================================================================// #ifndef BASECLIENT_H #define BASECLIENT_H #ifdef _WIN32 #pragma once #endif #include #include #include #include #include #include #include #include #include #include "smartptr.h" #include "userid.h" #include "tier1/bitbuf.h" #include "steam/steamclientpublic.h" #include "tier1/utlarray.h" #include "netmessages.h" // class CClientFrame; class CBaseServer; class CClientFrame; struct player_info_s; class CFrameSnapshot; class CEventInfo; class CCommand; struct NetMessageCvar_t; class CHLTVServer; struct Spike_t { public: Spike_t() : m_nBits( 0 ) { m_szDesc[ 0 ] = 0; } char m_szDesc[ 64 ]; int m_nBits; }; class CNetworkStatTrace { public: CNetworkStatTrace() : m_nMinWarningBytes( 0 ), m_nStartBit( 0 ), m_nCurBit( 0 ) { } int m_nMinWarningBytes; int m_nStartBit; int m_nCurBit; CUtlVector< Spike_t > m_Records; }; class CBaseClient : public IGameEventListener2, public IClient { typedef struct CustomFile_s { CRC32_t crc; //file CRC unsigned int reqID; // download request ID } CustomFile_t; public: CBaseClient(); virtual ~CBaseClient(); public: int GetPlayerSlot() const { return m_nClientSlot; }; int GetUserID() const { return m_UserID; }; const USERID_t GetNetworkID() const; const char *GetClientName() const { return m_Name; }; INetChannel *GetNetChannel() { return m_NetChannel; }; IServer *GetServer() { return (IServer*)m_Server; }; CHLTVServer *GetHltvServer(); CHLTVServer *GetAnyConnectedHltvServer(); const char *GetUserSetting(const char *cvar) const; const char *GetNetworkIDString() const; uint64 GetClientXuid() const; const char *GetFriendsName() const { return m_FriendsName; } void UpdateName( const char *pszDefault ); virtual void Connect(const char * szName, int nUserID, INetChannel *pNetChannel, bool bFakePlayer, CrossPlayPlatform_t clientPlatform, const CMsg_CVars *pVecCvars = NULL ); virtual void Inactivate( void )OVERRIDE; virtual void Reconnect( void )OVERRIDE; virtual void Disconnect( const char *reason ) OVERRIDE; virtual bool CheckConnect( void ); virtual bool ChangeSplitscreenUser( int nSplitScreenUserSlot ); virtual void SetRate( int nRate, bool bForce ); virtual int GetRate( void ) const; virtual void SetUpdateRate( float fUpdateRate, bool bForce ); // override; virtual float GetUpdateRate( void ) const; // override; virtual void Clear( void ); virtual void DemoRestart( void ); // called when client started demo recording virtual int GetMaxAckTickCount() const; virtual bool ExecuteStringCommand( const char *s ); virtual bool SendNetMsg( INetMessage &msg, bool bForceReliable = false, bool bVoice = false ); virtual void ClientPrintf ( PRINTF_FORMAT_STRING const char *fmt, ...) FMTFUNCTION( 2, 3 ); virtual bool IsConnected( void ) const { return m_nSignonState >= SIGNONSTATE_CONNECTED; }; virtual bool IsSpawned( void ) const { return m_nSignonState >= SIGNONSTATE_NEW; }; virtual bool IsActive( void ) const { return m_nSignonState == SIGNONSTATE_FULL; }; virtual bool IsFakeClient( void ) const { return m_bFakePlayer; }; virtual bool IsHLTV( void ) const { return m_bIsHLTV; } #if defined( REPLAY_ENABLED ) virtual bool IsReplay( void ) const { return m_bIsReplay; } #else virtual bool IsReplay( void ) const { return false; } #endif // REPLAY_ENABLED // Is an actual human player or splitscreen player (not a bot and not a HLTV slot) virtual bool IsHumanPlayer() const; virtual bool IsHearingClient( int index ) const { return false; }; virtual bool IsProximityHearingClient( int index ) const { return false; }; virtual bool IsLowViolenceClient( void ) const { return m_bLowViolence; } virtual void SetMaxRoutablePayloadSize( int nMaxRoutablePayloadSize ); virtual bool IsSplitScreenUser( void ) const { return m_bSplitScreenUser; } virtual CrossPlayPlatform_t GetClientPlatform() const { return m_ClientPlatform; } public: // Message Handlers bool NETMsg_Tick( const CNETMsg_Tick& msg ); bool NETMsg_StringCmd( const CNETMsg_StringCmd& msg ); bool NETMsg_SignonState( const CNETMsg_SignonState& msg ); virtual bool NETMsg_PlayerAvatarData( const CNETMsg_PlayerAvatarData& msg ); virtual bool NETMsg_SetConVar( const CNETMsg_SetConVar& msg ); virtual bool CLCMsg_ClientInfo( const CCLCMsg_ClientInfo& msg ); virtual bool CLCMsg_Move( const CCLCMsg_Move& msg ) { Assert( 0 ); return true; } virtual bool CLCMsg_VoiceData( const CCLCMsg_VoiceData& msg ) { Assert( 0 ); return true; } bool CLCMsg_BaselineAck( const CCLCMsg_BaselineAck& msg ); virtual bool CLCMsg_ListenEvents( const CCLCMsg_ListenEvents& msg ); virtual bool CLCMsg_RespondCvarValue( const CCLCMsg_RespondCvarValue& msg ) { Assert( 0 ); return true; } bool CLCMsg_LoadingProgress( const CCLCMsg_LoadingProgress& msg ); bool CLCMsg_SplitPlayerConnect( const CCLCMsg_SplitPlayerConnect& msg ); virtual bool CLCMsg_FileCRCCheck( const CCLCMsg_FileCRCCheck& msg ) { Assert( 0 ); return true; } virtual bool CLCMsg_CmdKeyValues( const CCLCMsg_CmdKeyValues& msg ); virtual bool CLCMsg_HltvReplay( const CCLCMsg_HltvReplay &msg ) { return false; } virtual bool SVCMsg_UserMessage( const CSVCMsg_UserMessage &msg ) { return true; } enum { NETMSG_Tick, NETMSG_StringCmd, NETMSG_SetConVar, NETMSG_SignonState, NETMSG_ClientInfo, NETMSG_Move, NETMSG_VoiceData, NETMSG_BaselineAck, NETMSG_ListenEvents, NETMSG_RespondCvarValue, NETMSG_SplitPlayerConnect, NETMSG_FileCRCCheck, NETMSG_LoadingProgress, NETMSG_CmdKeyValues, NETMSG_PlayerAvatarData, NETMSG_HltvReplay, NETMSG_UserMessage, NETMSG_Max }; CUtlArray< CNetMessageBinder, NETMSG_Max > m_NetMessages; virtual void ConnectionStart(INetChannel *chan) OVERRIDE; virtual void ConnectionStop()OVERRIDE; public: // IGameEventListener virtual void FireGameEvent( IGameEvent *event ) OVERRIDE { FireGameEvent( event, false ); } void FireGameEvent( IGameEvent *event, bool bPassthrough ); int m_nDebugID; virtual int GetEventDebugID( void ); public: virtual bool UpdateAcknowledgedFramecount(int tick); virtual bool ShouldSendMessages( void ); virtual void UpdateSendState( void ); void ForceFullUpdate( void ) { UpdateAcknowledgedFramecount(-1); } virtual bool FillUserInfo( player_info_s &userInfo ); virtual void UpdateUserSettings(); virtual void WriteGameSounds(bf_write &buf, int nMaxSounds); virtual CClientFrame *GetDeltaFrame( int nTick ); virtual bool SendSnapshot( CClientFrame *pFrame ); virtual bool SendServerInfo( void ); virtual void OnSteamServerLogonSuccess( uint32 externalIP ); virtual bool SendSignonData( void ); virtual void SpawnPlayer( void ); virtual void ActivatePlayer( void ); virtual void SetName( const char * name ); virtual void SetUserCVar( const char *cvar, const char *value); virtual void FreeBaselines(); virtual bool IgnoreTempEntity( CEventInfo *event ); void SetSteamID( const CSteamID &steamID ); int GetSignonState() const { return m_nSignonState; } void SetSignonState( int nState ); bool IsTracing() const; void SetTraceThreshold( int nThreshold ); void TraceNetworkData( bf_write &msg, PRINTF_FORMAT_STRING char const *fmt, ... ) FMTFUNCTION( 3, 4 ); void TraceNetworkMsg( int nBits, PRINTF_FORMAT_STRING char const *fmt, ... ) FMTFUNCTION( 3, 4 ); bool IsFullyAuthenticated( void ) { return m_bFullyAuthenticated; } void SetFullyAuthenticated( void ) { m_bFullyAuthenticated = true; } void SplitScreenDisconnect( const CCommand &args ); void DisconnectSplitScreenUser( CBaseClient *pSplitClient ); void ApplyConVars( const CMsg_CVars& list, bool bCreateIfNotExisting ); void FillSignOnFullServerInfo( class CNETMsg_SignonState_t& state ); bool IsSplitScreenPartner( const CBaseClient *pOther ) const; virtual IClient *GetSplitScreenOwner() { return m_pAttachedTo; } virtual int GetNumPlayers(); virtual bool StartHltvReplay( const HltvReplayParams_t ¶ms ) OVERRIDE { return false; } // not implemented for most clients virtual void StopHltvReplay() OVERRIDE { } virtual int GetHltvReplayDelay() OVERRIDE { return 0; } virtual bool CanStartHltvReplay() OVERRIDE { return false; } virtual void ResetReplayRequestTime() OVERRIDE { } virtual CBaseClient *GetPropCullClient() { return this; } void OverrideSignonStateTransparent( int nState ){ m_nSignonState = nState; } protected: virtual bool ProcessSignonStateMsg(int state, int spawncount); virtual void PerformDisconnection( const char *pReason ); void OnPlayerAvatarDataChanged(); private: void OnRequestFullUpdate( char const *pchReason ); int GetAvailableSplitScreenSlot() const; void SendFullConnectEvent(); public: // One of the subservient split screen users? bool m_bSplitScreenUser; bool m_bSplitAllowFastDisconnect; int m_nSplitScreenPlayerSlot; CBaseClient *m_SplitScreenUsers[ MAX_SPLITSCREEN_CLIENTS ]; CBaseClient *m_pAttachedTo; // If this is a split screen user, this is the "master" bool m_bSplitPlayerDisconnecting; // Array index in svs.clients: int m_nClientSlot; // entity index of this client (different from clientSlot+1 in HLTV and Replay mode): int m_nEntityIndex; int m_UserID; // identifying number on server char m_Name[MAX_PLAYER_NAME_LENGTH]; // for printing to other people char m_GUID[SIGNED_GUID_LEN + 1]; // the clients CD key CNETMsg_PlayerAvatarData_t m_msgAvatarData; // Client avatar CSteamID m_SteamID; // This is valid when the client is authenticated uint32 m_nFriendsID; // client's friends' ID char m_FriendsName[MAX_PLAYER_NAME_LENGTH]; KeyValues *m_ConVars; // stores all client side convars bool m_bConVarsChanged; // true if convars updated and not changes process yet bool m_bSendServerInfo; // true if we need to send server info packet to start connect CBaseServer *m_Server; // pointer to server object bool m_bIsHLTV; // if this a HLTV proxy ? CHLTVServer *m_pHltvSlaveServer; #if defined( REPLAY_ENABLED ) bool m_bIsReplay; // if this is a Replay proxy ? #endif // Client sends this during connection, so we can see if // we need to send sendtable info or if the .dll matches CRC32_t m_nSendtableCRC; // a client can have couple of cutomized files distributed to all other players CustomFile_t m_nCustomFiles[MAX_CUSTOM_FILES]; int m_nFilesDownloaded; // counter of how many files we downloaded from this client //===== NETWORK ============ INetChannel *m_NetChannel; // The client's net connection. private: int m_nSignonState; // connection state public: int m_nDeltaTick; // -1 = no compression. This is where the server is creating the // compressed info from. int m_nStringTableAckTick; // Highest tick acked for string tables (usually m_nDeltaTick, except when it's -1) int m_nSignonTick; // tick the client got his signon data CSmartPtr m_pLastSnapshot; // last send snapshot int m_nLoadingProgress; // 0..100 progress, only valid during loading CFrameSnapshot *m_pBaseline; // current entity baselines as a snapshot int m_nBaselineUpdateTick; // last tick we send client a update baseline signal or -1 CBitVec m_BaselinesSent; // baselines sent with last update int m_nBaselineUsed; // 0/1 toggling flag, singaling client what baseline to use // This is used when we send out a nodelta packet to put the client in a state where we wait // until we get an ack from them on this packet. // This is for 3 reasons: // 1. A client requesting a nodelta packet means they're screwed so no point in deluging them with data. // Better to send the uncompressed data at a slow rate until we hear back from them (if at all). // 2. Since the nodelta packet deletes all client entities, we can't ever delta from a packet previous to it. // 3. It can eat up a lot of CPU on the server to keep building nodelta packets while waiting for // a client to get back on its feet. int m_nForceWaitForTick; bool m_bFakePlayer; // JAC: This client is a fake player controlled by the game DLL bool m_bReceivedPacket; // true, if client received a packet after the last send packet bool m_bLowViolence; // true if client is in low-violence mode (L4D server needs to know) bool m_bFullyAuthenticated; // The datagram is written to after every frame, but only cleared // when it is sent out to the client. overflow is tolerated. // Time when we should send next world state update ( datagram ) double m_fNextMessageTime; // Default time to wait for next message float m_fSnapshotInterval; CrossPlayPlatform_t m_ClientPlatform; // Keep these as class members instead of a local variable so that we don't reallocate the // strings and their buffers every time. CSVCMsg_TempEntities_t m_tempentsmsg; CSVCMsg_PacketEntities_t m_packetmsg; private: void StartTrace( bf_write &msg ); void EndTrace( bf_write &msg ); CNetworkStatTrace m_Trace; }; #endif // BASECLIENT_H