2022-05-20 11:52:19 +02:00
//=============================================================================//
//
// Purpose:
//
// $NoKeywords: $
//
//=============================================================================//
// server.cpp: implementation of the CServer class.
//
/////////////////////////////////////////////////////////////////////////////////
# include "core/stdafx.h"
# include "common/protocol.h"
2024-04-19 12:55:31 +02:00
# include "tier0/frametask.h"
2022-05-20 11:52:19 +02:00
# include "tier1/cvar.h"
2023-07-04 23:01:13 +02:00
# include "tier1/strtools.h"
2022-05-20 11:52:19 +02:00
# include "engine/server/sv_main.h"
# include "engine/server/server.h"
2022-07-01 10:29:27 +02:00
# include "networksystem/pylon.h"
2022-08-09 17:34:10 +02:00
# include "networksystem/bansystem.h"
2023-03-31 22:37:53 +02:00
# include "ebisusdk/EbisuSDK.h"
2022-08-09 17:18:07 +02:00
# include "public/edict.h"
2023-07-04 23:01:13 +02:00
# include "pluginsystem/pluginsystem.h"
2024-03-31 15:15:30 +02:00
# include "rtech/liveapi/liveapi.h"
2022-05-20 11:52:19 +02:00
2024-02-24 02:15:09 +01:00
//---------------------------------------------------------------------------------
// Console variables
//---------------------------------------------------------------------------------
ConVar sv_showconnecting ( " sv_showconnecting " , " 1 " , FCVAR_RELEASE , " Logs information about the connecting client to the console " ) ;
2024-04-12 22:06:31 +02:00
ConVar sv_pylonVisibility ( " sv_pylonVisibility " , " 0 " , FCVAR_RELEASE , " Determines the visibility to the Pylon master server. " , " 0 = Offline, 1 = Hidden, 2 = Public. " ) ;
ConVar sv_pylonRefreshRate ( " sv_pylonRefreshRate " , " 5.0 " , FCVAR_DEVELOPMENTONLY , " Pylon host refresh rate (seconds) . " ) ;
ConVar sv_globalBanlist ( " sv_globalBanlist " , " 1 " , FCVAR_RELEASE , " Determines whether or not to use the global banned list. " , false , 0.f , false , 0.f , " 0 = Disable, 1 = Enable. " ) ;
2024-02-24 02:15:09 +01:00
ConVar sv_banlistRefreshRate ( " sv_banlistRefreshRate " , " 30.0 " , FCVAR_DEVELOPMENTONLY , " Banned list refresh rate (seconds) . " , true, 1.f, false, 0.f) ;
static ConVar sv_validatePersonaName ( " sv_validatePersonaName " , " 1 " , FCVAR_RELEASE , " Validate the client's textual persona name on connect. " ) ;
static ConVar sv_minPersonaNameLength ( " sv_minPersonaNameLength " , " 4 " , FCVAR_RELEASE , " The minimum length of the client's textual persona name. " , true , 0.f , false , 0.f ) ;
static ConVar sv_maxPersonaNameLength ( " sv_maxPersonaNameLength " , " 16 " , FCVAR_RELEASE , " The maximum length of the client's textual persona name. " , true , 0.f , false , 0.f ) ;
2022-05-20 11:52:19 +02:00
//---------------------------------------------------------------------------------
// Purpose: Gets the number of human players on the server
// Output : int
//---------------------------------------------------------------------------------
int CServer : : GetNumHumanPlayers ( void ) const
{
int nHumans = 0 ;
for ( int i = 0 ; i < g_ServerGlobalVariables - > m_nMaxClients ; i + + )
{
2023-07-12 08:56:17 +02:00
CClient * pClient = g_pServer - > GetClient ( i ) ;
2022-05-20 11:52:19 +02:00
if ( ! pClient )
continue ;
if ( pClient - > IsHumanPlayer ( ) )
nHumans + + ;
}
return nHumans ;
}
//---------------------------------------------------------------------------------
// Purpose: Gets the number of fake clients on the server
// Output : int
//---------------------------------------------------------------------------------
int CServer : : GetNumFakeClients ( void ) const
{
int nBots = 0 ;
for ( int i = 0 ; i < g_ServerGlobalVariables - > m_nMaxClients ; i + + )
{
2023-07-12 08:56:17 +02:00
CClient * pClient = g_pServer - > GetClient ( i ) ;
2022-05-20 11:52:19 +02:00
if ( ! pClient )
continue ;
if ( pClient - > IsConnected ( ) & & pClient - > IsFakeClient ( ) )
nBots + + ;
}
return nBots ;
2023-02-12 15:20:11 +01:00
}
//---------------------------------------------------------------------------------
// Purpose: Gets the number of clients on the server
// Output : int
//---------------------------------------------------------------------------------
int CServer : : GetNumClients ( void ) const
{
int nClients = 0 ;
for ( int i = 0 ; i < g_ServerGlobalVariables - > m_nMaxClients ; i + + )
{
2023-07-12 08:56:17 +02:00
CClient * pClient = g_pServer - > GetClient ( i ) ;
2023-02-12 15:20:11 +01:00
if ( ! pClient )
continue ;
if ( pClient - > IsConnected ( ) )
nClients + + ;
}
return nClients ;
2022-05-20 11:52:19 +02:00
}
2023-12-29 23:06:49 +01:00
//---------------------------------------------------------------------------------
// Purpose: Rejects connection request and sends back a message
// Input : iSocket -
// *pChallenge -
// *szMessage -
//---------------------------------------------------------------------------------
void CServer : : RejectConnection ( int iSocket , netadr_t * pNetAdr , const char * szMessage )
{
2024-01-02 15:21:36 +01:00
CServer__RejectConnection ( this , iSocket , pNetAdr , szMessage ) ;
2023-12-29 23:06:49 +01:00
}
2022-05-20 20:14:39 +02:00
//---------------------------------------------------------------------------------
2023-04-29 20:36:29 +02:00
// Purpose: Initializes a CSVClient for a new net connection. This will only be called
// once for a player each game, not once for each level change.
// Input : *pServer -
2023-04-30 01:50:38 +02:00
// *pChallenge -
2023-04-29 20:36:29 +02:00
// Output : pointer to client instance on success, nullptr on failure
2022-05-20 20:14:39 +02:00
//---------------------------------------------------------------------------------
2023-04-29 20:36:29 +02:00
CClient * CServer : : ConnectClient ( CServer * pServer , user_creds_s * pChallenge )
2022-05-20 11:52:19 +02:00
{
2023-04-29 20:36:29 +02:00
if ( pServer - > m_State < server_state_t : : ss_active )
return nullptr ;
2023-04-01 01:51:39 +02:00
char * pszPersonaName = pChallenge - > personaName ;
uint64_t nNucleusID = pChallenge - > personaId ;
2022-11-03 02:38:49 +01:00
2023-04-22 20:30:53 +02:00
char pszAddresBuffer [ 128 ] ; // Render the client's address.
pChallenge - > netAdr . ToString ( pszAddresBuffer , sizeof ( pszAddresBuffer ) , true ) ;
2022-11-03 02:30:57 +01:00
2024-02-24 02:15:09 +01:00
const bool bEnableLogging = sv_showconnecting . GetBool ( ) ;
2023-04-30 01:29:54 +02:00
const int nPort = int ( ntohs ( pChallenge - > netAdr . GetPort ( ) ) ) ;
2022-11-03 02:30:57 +01:00
if ( bEnableLogging )
2023-08-21 19:12:29 +02:00
Msg ( eDLL_T : : SERVER , " Processing connectionless challenge for '[%s]:%i' ('%llu') \n " ,
2023-04-30 01:29:54 +02:00
pszAddresBuffer , nPort , nNucleusID ) ;
2022-11-03 02:30:57 +01:00
2023-07-19 02:16:06 +02:00
bool bValidName = false ;
if ( VALID_CHARSTAR ( pszPersonaName ) & &
V_IsValidUTF8 ( pszPersonaName ) )
{
2024-02-24 02:15:09 +01:00
if ( sv_validatePersonaName . GetBool ( ) & &
! IsValidPersonaName ( pszPersonaName , sv_minPersonaNameLength . GetInt ( ) , sv_maxPersonaNameLength . GetInt ( ) ) )
2023-07-19 02:16:06 +02:00
{
bValidName = false ;
}
else
{
bValidName = true ;
}
}
2023-03-31 22:37:53 +02:00
// Only proceed connection if the client's name is valid and UTF-8 encoded.
2023-07-19 02:16:06 +02:00
if ( ! bValidName )
2022-11-03 02:30:57 +01:00
{
2023-04-29 20:36:29 +02:00
pServer - > RejectConnection ( pServer - > m_Socket , & pChallenge - > netAdr , " #Valve_Reject_Invalid_Name " ) ;
2022-11-03 02:30:57 +01:00
if ( bEnableLogging )
2023-04-30 01:29:54 +02:00
Warning ( eDLL_T : : SERVER , " Connection rejected for '[%s]:%i' ('%llu' has an invalid name!) \n " ,
pszAddresBuffer , nPort , nNucleusID ) ;
2022-11-03 02:30:57 +01:00
2023-04-29 20:36:29 +02:00
return nullptr ;
2022-11-03 02:30:57 +01:00
}
2022-05-20 11:52:19 +02:00
2024-01-21 21:29:23 +01:00
if ( g_BanSystem . IsBanListValid ( ) )
2022-05-20 11:52:19 +02:00
{
2024-01-21 21:29:23 +01:00
if ( g_BanSystem . IsBanned ( pszAddresBuffer , nNucleusID ) )
2022-05-20 11:52:19 +02:00
{
2023-04-29 20:36:29 +02:00
pServer - > RejectConnection ( pServer - > m_Socket , & pChallenge - > netAdr , " #Valve_Reject_Banned " ) ;
2022-11-03 02:30:57 +01:00
if ( bEnableLogging )
2023-04-30 01:29:54 +02:00
Warning ( eDLL_T : : SERVER , " Connection rejected for '[%s]:%i' ('%llu' is banned from this server!) \n " ,
pszAddresBuffer , nPort , nNucleusID ) ;
2022-06-15 11:59:37 +02:00
2023-04-29 20:36:29 +02:00
return nullptr ;
2022-05-20 11:52:19 +02:00
}
}
2024-01-02 15:21:36 +01:00
CClient * pClient = CServer__ConnectClient ( pServer , pChallenge ) ;
2023-04-23 22:28:16 +01:00
2024-01-21 21:29:23 +01:00
for ( auto & callback : ! g_PluginSystem . GetConnectClientCallbacks ( ) )
2023-07-20 22:00:00 +02:00
{
2024-04-20 23:27:00 +02:00
if ( ! callback . Function ( ) ( pServer , pClient , pChallenge ) )
2023-07-20 22:00:00 +02:00
{
pClient - > Disconnect ( REP_MARK_BAD , " #Valve_Reject_Banned " ) ;
return nullptr ;
}
}
2023-04-29 21:01:59 +02:00
2024-02-24 02:15:09 +01:00
if ( pClient & & sv_globalBanlist . GetBool ( ) )
2022-05-20 11:52:19 +02:00
{
2023-04-30 11:31:05 +02:00
if ( ! pClient - > GetNetChan ( ) - > GetRemoteAddress ( ) . IsLoopback ( ) )
{
2024-03-10 02:13:15 +01:00
const string addressBufferCopy ( pszAddresBuffer ) ;
const string personaNameCopy ( pszPersonaName ) ;
std : : thread th ( SV_CheckForBanAndDisconnect , pClient , addressBufferCopy , nNucleusID , personaNameCopy , nPort ) ;
2023-04-30 11:31:05 +02:00
th . detach ( ) ;
}
2022-05-20 11:52:19 +02:00
}
2023-04-23 22:28:16 +01:00
2022-11-03 02:30:57 +01:00
return pClient ;
2022-08-30 12:07:09 +02:00
}
//---------------------------------------------------------------------------------
2023-12-29 23:06:49 +01:00
// Purpose: Sends netmessage to all active clients
// Input : *msg -
// onlyActive -
// reliable -
2022-08-30 12:07:09 +02:00
//---------------------------------------------------------------------------------
2023-12-29 23:06:49 +01:00
void CServer : : BroadcastMessage ( CNetMessage * const msg , const bool onlyActive , const bool reliable )
2022-08-30 12:07:09 +02:00
{
2024-01-02 15:21:36 +01:00
CServer__BroadcastMessage ( this , msg , onlyActive , reliable ) ;
2022-05-20 11:52:19 +02:00
}
2022-11-05 00:12:45 +01:00
//---------------------------------------------------------------------------------
2023-02-18 11:42:36 +01:00
// Purpose: Runs the server frame job
2022-11-05 00:12:45 +01:00
// Input : flFrameTime -
// bRunOverlays -
2023-12-29 23:06:49 +01:00
// bUpdateFrame -
2022-11-05 00:12:45 +01:00
//---------------------------------------------------------------------------------
2023-12-29 23:06:49 +01:00
void CServer : : FrameJob ( double flFrameTime , bool bRunOverlays , bool bUpdateFrame )
2022-11-05 00:12:45 +01:00
{
2024-01-02 15:21:36 +01:00
CServer__FrameJob ( flFrameTime , bRunOverlays , bUpdateFrame ) ;
2024-03-31 15:15:30 +02:00
LiveAPISystem ( ) - > RunFrame ( ) ;
2022-11-05 00:12:45 +01:00
}
2023-02-18 11:42:36 +01:00
//---------------------------------------------------------------------------------
// Purpose: Runs the server frame
// Input : *pServer -
//---------------------------------------------------------------------------------
void CServer : : RunFrame ( CServer * pServer )
{
2024-01-02 15:21:36 +01:00
CServer__RunFrame ( pServer ) ;
2023-02-18 11:42:36 +01:00
}
2022-05-20 11:52:19 +02:00
///////////////////////////////////////////////////////////////////////////////
2023-11-26 13:21:20 +01:00
void VServer : : Detour ( const bool bAttach ) const
2022-05-20 11:52:19 +02:00
{
2024-01-02 15:21:36 +01:00
DetourSetup ( & CServer__RunFrame , & CServer : : RunFrame , bAttach ) ;
DetourSetup ( & CServer__ConnectClient , & CServer : : ConnectClient , bAttach ) ;
DetourSetup ( & CServer__FrameJob , & CServer : : FrameJob , bAttach ) ;
2022-05-20 11:52:19 +02:00
}
///////////////////////////////////////////////////////////////////////////////
2023-12-30 02:51:02 +01:00
CServer * g_pServer = nullptr ;
CClientExtended CServer : : sm_ClientsExtended [ MAX_PLAYERS ] ;