2010-11-20 10:37:14 +00:00
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
/* If you are missing that file, acquire a complete release at teeworlds.com. */
2017-03-12 13:49:18 +00:00
# define _WIN32_WINNT 0x0501
2021-01-26 20:22:32 +00:00
# include "server.h"
2011-07-31 11:17:38 +00:00
# include <base/math.h>
2010-05-29 07:25:38 +00:00
# include <base/system.h>
2011-02-27 14:03:57 +00:00
# include <engine/config.h>
# include <engine/console.h>
# include <engine/engine.h>
# include <engine/map.h>
# include <engine/masterserver.h>
# include <engine/server.h>
# include <engine/storage.h>
2010-05-29 07:25:38 +00:00
# include <engine/shared/compression.h>
# include <engine/shared/config.h>
# include <engine/shared/datafile.h>
2010-09-12 10:16:51 +00:00
# include <engine/shared/demo.h>
2011-07-30 11:40:01 +00:00
# include <engine/shared/econ.h>
2020-09-26 19:41:58 +00:00
# include <engine/shared/fifo.h>
2011-07-30 16:29:40 +00:00
# include <engine/shared/filecollection.h>
2011-12-29 22:36:53 +00:00
# include <engine/shared/netban.h>
2011-02-27 14:03:57 +00:00
# include <engine/shared/network.h>
# include <engine/shared/packer.h>
# include <engine/shared/protocol.h>
2017-05-21 23:07:13 +00:00
# include <engine/shared/protocol_ex.h>
2011-02-27 14:03:57 +00:00
# include <engine/shared/snapshot.h>
2010-05-29 07:25:38 +00:00
# include <mastersrv/mastersrv.h>
2021-12-21 22:05:44 +00:00
# include <game/version.h>
2011-04-26 09:51:02 +00:00
// DDRace
# include <engine/shared/linereader.h>
2020-09-26 19:41:58 +00:00
# include <vector>
2020-06-19 21:52:13 +00:00
# include <zlib.h>
2011-04-26 09:51:02 +00:00
2021-01-26 20:22:32 +00:00
# include "databases/connection.h"
# include "databases/connection_pool.h"
2010-05-29 07:25:38 +00:00
# include "register.h"
2011-04-13 18:37:12 +00:00
# if defined(CONF_FAMILY_WINDOWS)
2020-09-26 19:41:58 +00:00
# define WIN32_LEAN_AND_MEAN
# include <windows.h>
2010-05-29 07:25:38 +00:00
# endif
CSnapIDPool : : CSnapIDPool ( )
{
Reset ( ) ;
}
void CSnapIDPool : : Reset ( )
{
for ( int i = 0 ; i < MAX_IDS ; i + + )
{
2020-09-26 19:41:58 +00:00
m_aIDs [ i ] . m_Next = i + 1 ;
2010-05-29 07:25:38 +00:00
m_aIDs [ i ] . m_State = 0 ;
}
2011-04-13 18:37:12 +00:00
2020-09-26 19:41:58 +00:00
m_aIDs [ MAX_IDS - 1 ] . m_Next = - 1 ;
2010-05-29 07:25:38 +00:00
m_FirstFree = 0 ;
m_FirstTimed = - 1 ;
m_LastTimed = - 1 ;
m_Usage = 0 ;
m_InUsage = 0 ;
}
void CSnapIDPool : : RemoveFirstTimeout ( )
{
int NextTimed = m_aIDs [ m_FirstTimed ] . m_Next ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
// add it to the free list
m_aIDs [ m_FirstTimed ] . m_Next = m_FirstFree ;
m_aIDs [ m_FirstTimed ] . m_State = 0 ;
m_FirstFree = m_FirstTimed ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
// remove it from the timed list
m_FirstTimed = NextTimed ;
if ( m_FirstTimed = = - 1 )
m_LastTimed = - 1 ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
m_Usage - - ;
}
int CSnapIDPool : : NewID ( )
{
2021-06-23 05:05:49 +00:00
int64_t Now = time_get ( ) ;
2010-05-29 07:25:38 +00:00
// process timed ids
while ( m_FirstTimed ! = - 1 & & m_aIDs [ m_FirstTimed ] . m_Timeout < Now )
RemoveFirstTimeout ( ) ;
2011-04-13 18:37:12 +00:00
2011-02-12 10:40:36 +00:00
int ID = m_FirstFree ;
if ( ID = = - 1 )
2022-01-04 23:11:42 +00:00
{
dbg_msg ( " server " , " invalid id " ) ;
2011-02-12 10:40:36 +00:00
return ID ;
2022-01-04 23:11:42 +00:00
}
2010-05-29 07:25:38 +00:00
m_FirstFree = m_aIDs [ m_FirstFree ] . m_Next ;
2011-02-12 10:40:36 +00:00
m_aIDs [ ID ] . m_State = 1 ;
2010-05-29 07:25:38 +00:00
m_Usage + + ;
m_InUsage + + ;
2011-02-12 10:40:36 +00:00
return ID ;
2010-05-29 07:25:38 +00:00
}
void CSnapIDPool : : TimeoutIDs ( )
{
// process timed ids
while ( m_FirstTimed ! = - 1 )
RemoveFirstTimeout ( ) ;
}
2011-02-12 10:40:36 +00:00
void CSnapIDPool : : FreeID ( int ID )
2010-05-29 07:25:38 +00:00
{
2011-02-12 10:40:36 +00:00
if ( ID < 0 )
2010-12-16 02:29:08 +00:00
return ;
2018-07-10 09:29:02 +00:00
dbg_assert ( m_aIDs [ ID ] . m_State = = 1 , " id is not allocated " ) ;
2010-05-29 07:25:38 +00:00
m_InUsage - - ;
2011-02-12 10:40:36 +00:00
m_aIDs [ ID ] . m_State = 2 ;
2020-09-26 19:41:58 +00:00
m_aIDs [ ID ] . m_Timeout = time_get ( ) + time_freq ( ) * 5 ;
2011-02-12 10:40:36 +00:00
m_aIDs [ ID ] . m_Next = - 1 ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
if ( m_LastTimed ! = - 1 )
{
2011-02-12 10:40:36 +00:00
m_aIDs [ m_LastTimed ] . m_Next = ID ;
m_LastTimed = ID ;
2010-05-29 07:25:38 +00:00
}
else
{
2011-02-12 10:40:36 +00:00
m_FirstTimed = ID ;
m_LastTimed = ID ;
2010-05-29 07:25:38 +00:00
}
}
2011-04-13 18:37:12 +00:00
2017-03-21 10:24:44 +00:00
void CServerBan : : InitServerBan ( IConsole * pConsole , IStorage * pStorage , CServer * pServer )
2011-12-29 22:36:53 +00:00
{
CNetBan : : Init ( pConsole , pStorage ) ;
m_pServer = pServer ;
// overwrites base command, todo: improve this
2020-09-26 19:41:58 +00:00
Console ( ) - > Register ( " ban " , " s[ip|id] ?i[minutes] r[reason] " , CFGFLAG_SERVER | CFGFLAG_STORE , ConBanExt , this , " Ban player with ip/client id for x minutes for any reason " ) ;
Console ( ) - > Register ( " ban_region " , " s[region] s[ip|id] ?i[minutes] r[reason] " , CFGFLAG_SERVER | CFGFLAG_STORE , ConBanRegion , this , " Ban player in a region " ) ;
Console ( ) - > Register ( " ban_region_range " , " s[region] s[first ip] s[last ip] ?i[minutes] r[reason] " , CFGFLAG_SERVER | CFGFLAG_STORE , ConBanRegionRange , this , " Ban range in a region " ) ;
2011-12-29 22:36:53 +00:00
}
template < class T >
int CServerBan : : BanExt ( T * pBanPool , const typename T : : CDataType * pData , int Seconds , const char * pReason )
{
// validate address
if ( Server ( ) - > m_RconClientID > = 0 & & Server ( ) - > m_RconClientID < MAX_CLIENTS & &
Server ( ) - > m_aClients [ Server ( ) - > m_RconClientID ] . m_State ! = CServer : : CClient : : STATE_EMPTY )
{
if ( NetMatch ( pData , Server ( ) - > m_NetServer . ClientAddr ( Server ( ) - > m_RconClientID ) ) )
{
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " net_ban " , " ban error (you can't ban yourself) " ) ;
return - 1 ;
}
for ( int i = 0 ; i < MAX_CLIENTS ; + + i )
{
if ( i = = Server ( ) - > m_RconClientID | | Server ( ) - > m_aClients [ i ] . m_State = = CServer : : CClient : : STATE_EMPTY )
continue ;
if ( Server ( ) - > m_aClients [ i ] . m_Authed > = Server ( ) - > m_RconAuthLevel & & NetMatch ( pData , Server ( ) - > m_NetServer . ClientAddr ( i ) ) )
{
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " net_ban " , " ban error (command denied) " ) ;
return - 1 ;
}
}
}
2011-12-31 11:11:48 +00:00
else if ( Server ( ) - > m_RconClientID = = IServer : : RCON_CID_VOTE )
{
for ( int i = 0 ; i < MAX_CLIENTS ; + + i )
{
if ( Server ( ) - > m_aClients [ i ] . m_State = = CServer : : CClient : : STATE_EMPTY )
continue ;
2019-03-02 10:50:33 +00:00
if ( Server ( ) - > m_aClients [ i ] . m_Authed ! = AUTHED_NO & & NetMatch ( pData , Server ( ) - > m_NetServer . ClientAddr ( i ) ) )
2011-12-31 11:11:48 +00:00
{
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " net_ban " , " ban error (command denied) " ) ;
return - 1 ;
}
}
}
2011-12-29 22:36:53 +00:00
int Result = Ban ( pBanPool , pData , Seconds , pReason ) ;
if ( Result ! = 0 )
return Result ;
// drop banned clients
2011-12-30 18:35:57 +00:00
typename T : : CDataType Data = * pData ;
2011-12-29 22:36:53 +00:00
for ( int i = 0 ; i < MAX_CLIENTS ; + + i )
{
if ( Server ( ) - > m_aClients [ i ] . m_State = = CServer : : CClient : : STATE_EMPTY )
continue ;
if ( NetMatch ( & Data , Server ( ) - > m_NetServer . ClientAddr ( i ) ) )
{
CNetHash NetHash ( & Data ) ;
char aBuf [ 256 ] ;
MakeBanInfo ( pBanPool - > Find ( & Data , & NetHash ) , aBuf , sizeof ( aBuf ) , MSGTYPE_PLAYER ) ;
Server ( ) - > m_NetServer . Drop ( i , aBuf ) ;
}
}
return Result ;
}
int CServerBan : : BanAddr ( const NETADDR * pAddr , int Seconds , const char * pReason )
{
return BanExt ( & m_BanAddrPool , pAddr , Seconds , pReason ) ;
}
int CServerBan : : BanRange ( const CNetRange * pRange , int Seconds , const char * pReason )
{
if ( pRange - > IsValid ( ) )
return BanExt ( & m_BanRangePool , pRange , Seconds , pReason ) ;
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " net_ban " , " ban failed (invalid range) " ) ;
return - 1 ;
}
void CServerBan : : ConBanExt ( IConsole : : IResult * pResult , void * pUser )
{
CServerBan * pThis = static_cast < CServerBan * > ( pUser ) ;
const char * pStr = pResult - > GetString ( 0 ) ;
2021-10-20 18:26:44 +00:00
int Minutes = pResult - > NumArguments ( ) > 1 ? clamp ( pResult - > GetInteger ( 1 ) , 0 , 525600 ) : 10 ;
const char * pReason = pResult - > NumArguments ( ) > 2 ? pResult - > GetString ( 2 ) : " Follow the server rules. Type /rules into the chat. " ;
2011-12-29 22:36:53 +00:00
2019-02-27 19:24:31 +00:00
if ( str_isallnum ( pStr ) )
2011-12-29 22:36:53 +00:00
{
int ClientID = str_toint ( pStr ) ;
if ( ClientID < 0 | | ClientID > = MAX_CLIENTS | | pThis - > Server ( ) - > m_aClients [ ClientID ] . m_State = = CServer : : CClient : : STATE_EMPTY )
pThis - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " net_ban " , " ban error (invalid client id) " ) ;
else
2020-09-26 19:41:58 +00:00
pThis - > BanAddr ( pThis - > Server ( ) - > m_NetServer . ClientAddr ( ClientID ) , Minutes * 60 , pReason ) ;
2011-12-29 22:36:53 +00:00
}
else
ConBan ( pResult , pUser ) ;
}
2020-08-19 09:38:49 +00:00
void CServerBan : : ConBanRegion ( IConsole : : IResult * pResult , void * pUser )
{
const char * pRegion = pResult - > GetString ( 0 ) ;
2020-08-19 11:07:55 +00:00
if ( str_comp_nocase ( pRegion , g_Config . m_SvRegionName ) )
2020-08-19 09:38:49 +00:00
return ;
pResult - > RemoveArgument ( 0 ) ;
ConBanExt ( pResult , pUser ) ;
}
2011-12-29 22:36:53 +00:00
2020-08-19 11:07:55 +00:00
void CServerBan : : ConBanRegionRange ( IConsole : : IResult * pResult , void * pUser )
{
CServerBan * pServerBan = static_cast < CServerBan * > ( pUser ) ;
const char * pRegion = pResult - > GetString ( 0 ) ;
if ( str_comp_nocase ( pRegion , g_Config . m_SvRegionName ) )
return ;
pResult - > RemoveArgument ( 0 ) ;
ConBanRange ( pResult , static_cast < CNetBan * > ( pServerBan ) ) ;
}
2010-05-29 07:25:38 +00:00
void CServer : : CClient : : Reset ( )
{
// reset input
2020-10-26 14:14:07 +00:00
for ( auto & Input : m_aInputs )
Input . m_GameTick = - 1 ;
2010-05-29 07:25:38 +00:00
m_CurrentInput = 0 ;
mem_zero ( & m_LatestInput , sizeof ( m_LatestInput ) ) ;
m_Snapshots . PurgeAll ( ) ;
m_LastAckedSnapshot = - 1 ;
m_LastInputTick = - 1 ;
m_SnapRate = CClient : : SNAPRATE_INIT ;
m_Score = 0 ;
2016-11-18 14:00:42 +00:00
m_NextMapChunk = 0 ;
2019-04-03 13:07:05 +00:00
m_Flags = 0 ;
2010-05-29 07:25:38 +00:00
}
2020-09-26 19:41:58 +00:00
CServer : : CServer ( ) :
m_Register ( false ) , m_RegSixup ( true )
2010-05-29 07:25:38 +00:00
{
2021-12-15 00:32:13 +00:00
m_pConfig = & g_Config ;
2014-12-02 14:44:54 +00:00
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
m_aDemoRecorder [ i ] = CDemoRecorder ( & m_SnapshotDelta , true ) ;
m_aDemoRecorder [ MAX_CLIENTS ] = CDemoRecorder ( & m_SnapshotDelta , false ) ;
2014-09-26 00:05:22 +00:00
2010-05-29 07:25:38 +00:00
m_TickSpeed = SERVER_TICK_SPEED ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
m_pGameServer = 0 ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
m_CurrentGameTick = 0 ;
2020-07-07 08:23:04 +00:00
m_RunServer = UNINITIALIZED ;
2010-05-29 07:25:38 +00:00
2021-12-08 17:41:16 +00:00
m_aShutdownReason [ 0 ] = 0 ;
2021-12-21 11:23:17 +00:00
for ( int i = SIX ; i < = SIXUP ; i + + )
2020-06-19 21:52:13 +00:00
{
m_apCurrentMapData [ i ] = 0 ;
m_aCurrentMapSize [ i ] = 0 ;
}
2011-04-13 18:37:12 +00:00
2020-04-23 17:02:10 +00:00
m_MapReload = false ;
2015-10-22 15:27:30 +00:00
m_ReloadedWhenEmpty = false ;
2021-12-21 11:23:17 +00:00
m_aCurrentMap [ 0 ] = ' \0 ' ;
2010-05-29 07:25:38 +00:00
2011-12-31 11:11:48 +00:00
m_RconClientID = IServer : : RCON_CID_SERV ;
2011-07-05 19:54:10 +00:00
m_RconAuthLevel = AUTHED_ADMIN ;
2010-09-12 11:52:25 +00:00
2013-07-30 23:31:53 +00:00
m_RconRestrict = - 1 ;
2016-01-22 15:02:40 +00:00
m_ServerInfoFirstRequest = 0 ;
m_ServerInfoNumRequests = 0 ;
2019-11-03 00:53:50 +00:00
m_ServerInfoNeedsUpdate = false ;
2016-01-22 15:02:40 +00:00
2017-12-20 15:56:34 +00:00
# ifdef CONF_FAMILY_UNIX
m_ConnLoggingSocketCreated = false ;
# endif
2020-07-04 17:53:27 +00:00
m_pConnectionPool = new CDbConnectionPool ( ) ;
2015-11-23 21:49:18 +00:00
2017-10-13 00:25:50 +00:00
m_aErrorShutdownReason [ 0 ] = 0 ;
2010-05-29 07:25:38 +00:00
Init ( ) ;
}
2020-11-11 16:21:02 +00:00
CServer : : ~ CServer ( )
{
for ( auto & pCurrentMapData : m_apCurrentMapData )
{
if ( pCurrentMapData )
free ( pCurrentMapData ) ;
}
delete m_pConnectionPool ;
}
2020-10-14 14:42:35 +00:00
bool CServer : : IsClientNameAvailable ( int ClientID , const char * pNameRequest )
2010-05-29 07:25:38 +00:00
{
2012-07-08 09:40:23 +00:00
// check for empty names
2020-10-14 14:42:35 +00:00
if ( ! pNameRequest [ 0 ] )
return false ;
2011-03-15 10:23:49 +00:00
2016-07-08 14:38:05 +00:00
// check for names starting with /, as they can be abused to make people
// write chat commands
2020-10-14 14:42:35 +00:00
if ( pNameRequest [ 0 ] = = ' / ' )
return false ;
2016-07-08 14:38:05 +00:00
2015-12-16 19:15:43 +00:00
// make sure that two clients don't have the same name
2010-05-29 07:25:38 +00:00
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
2015-12-18 12:17:45 +00:00
{
2010-05-29 07:25:38 +00:00
if ( i ! = ClientID & & m_aClients [ i ] . m_State > = CClient : : STATE_READY )
{
2020-10-14 14:42:35 +00:00
if ( str_utf8_comp_confusable ( pNameRequest , m_aClients [ i ] . m_aName ) = = 0 )
return false ;
2010-05-29 07:25:38 +00:00
}
2015-12-18 12:17:45 +00:00
}
2010-05-29 07:25:38 +00:00
2020-10-14 14:42:35 +00:00
return true ;
2010-05-29 07:25:38 +00:00
}
2020-10-14 14:42:35 +00:00
bool CServer : : SetClientNameImpl ( int ClientID , const char * pNameRequest , bool Set )
2010-05-29 07:25:38 +00:00
{
2020-10-14 14:42:35 +00:00
dbg_assert ( 0 < = ClientID & & ClientID < MAX_CLIENTS , " invalid client id " ) ;
if ( m_aClients [ ClientID ] . m_State < CClient : : STATE_READY )
return false ;
2011-04-13 18:37:12 +00:00
2020-12-19 10:20:52 +00:00
CNameBan * pBanned = IsNameBanned ( pNameRequest , m_aNameBans . base_ptr ( ) , m_aNameBans . size ( ) ) ;
if ( pBanned )
2018-03-06 17:41:18 +00:00
{
2020-12-19 10:20:52 +00:00
if ( m_aClients [ ClientID ] . m_State = = CClient : : STATE_READY & & Set )
2018-03-06 17:41:18 +00:00
{
2020-12-19 10:20:52 +00:00
char aBuf [ 256 ] ;
if ( pBanned - > m_aReason [ 0 ] )
{
str_format ( aBuf , sizeof ( aBuf ) , " Kicked (your name is banned: %s) " , pBanned - > m_aReason ) ;
}
else
2018-03-12 22:29:46 +00:00
{
2020-12-19 10:20:52 +00:00
str_copy ( aBuf , " Kicked (your name is banned) " , sizeof ( aBuf ) ) ;
2018-03-12 22:29:46 +00:00
}
2020-12-19 10:20:52 +00:00
Kick ( ClientID , aBuf ) ;
2018-03-06 17:41:18 +00:00
}
2020-12-19 10:20:52 +00:00
return false ;
2018-03-06 17:41:18 +00:00
}
2020-10-14 14:42:35 +00:00
// trim the name
char aTrimmedName [ MAX_NAME_LENGTH ] ;
str_copy ( aTrimmedName , str_utf8_skip_whitespaces ( pNameRequest ) , sizeof ( aTrimmedName ) ) ;
str_utf8_trim_right ( aTrimmedName ) ;
2010-05-29 07:25:38 +00:00
char aNameTry [ MAX_NAME_LENGTH ] ;
2020-10-14 14:42:35 +00:00
str_copy ( aNameTry , aTrimmedName , sizeof ( aNameTry ) ) ;
if ( ! IsClientNameAvailable ( ClientID , aNameTry ) )
2010-05-29 07:25:38 +00:00
{
// auto rename
for ( int i = 1 ; ; i + + )
{
2021-12-20 01:34:02 +00:00
str_format ( aNameTry , sizeof ( aNameTry ) , " (%d)%s " , i , aTrimmedName ) ;
2020-10-14 14:42:35 +00:00
if ( IsClientNameAvailable ( ClientID , aNameTry ) )
2010-05-29 07:25:38 +00:00
break ;
}
}
2020-10-14 14:42:35 +00:00
bool Changed = str_comp ( m_aClients [ ClientID ] . m_aName , aNameTry ) ! = 0 ;
if ( Set )
{
// set the client name
str_copy ( m_aClients [ ClientID ] . m_aName , aNameTry , MAX_NAME_LENGTH ) ;
}
return Changed ;
}
bool CServer : : WouldClientNameChange ( int ClientID , const char * pNameRequest )
{
return SetClientNameImpl ( ClientID , pNameRequest , false ) ;
}
void CServer : : SetClientName ( int ClientID , const char * pName )
{
SetClientNameImpl ( ClientID , pName , true ) ;
2010-05-29 07:25:38 +00:00
}
2011-03-15 10:23:49 +00:00
void CServer : : SetClientClan ( int ClientID , const char * pClan )
{
if ( ClientID < 0 | | ClientID > = MAX_CLIENTS | | m_aClients [ ClientID ] . m_State < CClient : : STATE_READY | | ! pClan )
return ;
2011-04-13 18:37:12 +00:00
2011-03-15 10:23:49 +00:00
str_copy ( m_aClients [ ClientID ] . m_aClan , pClan , MAX_CLAN_LENGTH ) ;
}
void CServer : : SetClientCountry ( int ClientID , int Country )
2010-05-29 07:25:38 +00:00
{
if ( ClientID < 0 | | ClientID > = MAX_CLIENTS | | m_aClients [ ClientID ] . m_State < CClient : : STATE_READY )
return ;
2011-04-13 18:37:12 +00:00
2011-03-15 10:23:49 +00:00
m_aClients [ ClientID ] . m_Country = Country ;
2010-05-29 07:25:38 +00:00
}
void CServer : : SetClientScore ( int ClientID , int Score )
{
if ( ClientID < 0 | | ClientID > = MAX_CLIENTS | | m_aClients [ ClientID ] . m_State < CClient : : STATE_READY )
return ;
2019-11-04 14:33:17 +00:00
if ( m_aClients [ ClientID ] . m_Score ! = Score )
ExpireServerInfo ( ) ;
2010-05-29 07:25:38 +00:00
m_aClients [ ClientID ] . m_Score = Score ;
}
2019-04-03 13:07:05 +00:00
void CServer : : SetClientFlags ( int ClientID , int Flags )
{
if ( ClientID < 0 | | ClientID > = MAX_CLIENTS | | m_aClients [ ClientID ] . m_State < CClient : : STATE_READY )
return ;
if ( Flags > m_aClients [ ClientID ] . m_Flags )
m_aClients [ ClientID ] . m_Flags = Flags ;
}
2010-05-29 07:25:38 +00:00
void CServer : : Kick ( int ClientID , const char * pReason )
{
2010-09-12 10:07:10 +00:00
if ( ClientID < 0 | | ClientID > = MAX_CLIENTS | | m_aClients [ ClientID ] . m_State = = CClient : : STATE_EMPTY )
2010-09-12 11:52:25 +00:00
{
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " server " , " invalid client id to kick " ) ;
2010-05-29 07:25:38 +00:00
return ;
2010-09-12 11:52:25 +00:00
}
2011-02-12 10:40:36 +00:00
else if ( m_RconClientID = = ClientID )
2010-09-12 11:52:25 +00:00
{
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " server " , " you can't kick yourself " ) ;
2015-07-09 00:08:14 +00:00
return ;
2010-09-12 10:07:10 +00:00
}
2011-07-05 19:54:10 +00:00
else if ( m_aClients [ ClientID ] . m_Authed > m_RconAuthLevel )
{
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " server " , " kick command denied " ) ;
2015-07-09 00:08:14 +00:00
return ;
2011-07-05 19:54:10 +00:00
}
2011-04-13 18:37:12 +00:00
2010-09-12 10:07:10 +00:00
m_NetServer . Drop ( ClientID , pReason ) ;
2010-05-29 07:25:38 +00:00
}
2019-02-06 12:06:28 +00:00
void CServer : : Ban ( int ClientID , int Seconds , const char * pReason )
2019-02-04 22:09:14 +00:00
{
NETADDR Addr ;
GetClientAddr ( ClientID , & Addr ) ;
2019-02-06 12:06:28 +00:00
m_NetServer . NetBan ( ) - > BanAddr ( & Addr , Seconds , pReason ) ;
2019-02-04 22:09:14 +00:00
}
2010-05-29 07:25:38 +00:00
/*int CServer::Tick()
{
return m_CurrentGameTick ;
} */
2021-06-23 05:05:49 +00:00
int64_t CServer : : TickStartTime ( int Tick )
2010-05-29 07:25:38 +00:00
{
2020-09-26 19:41:58 +00:00
return m_GameStartTime + ( time_freq ( ) * Tick ) / SERVER_TICK_SPEED ;
2010-05-29 07:25:38 +00:00
}
/*int CServer::TickSpeed()
{
return SERVER_TICK_SPEED ;
} */
int CServer : : Init ( )
{
2020-10-26 14:14:07 +00:00
for ( auto & Client : m_aClients )
2010-05-29 07:25:38 +00:00
{
2020-10-26 14:14:07 +00:00
Client . m_State = CClient : : STATE_EMPTY ;
Client . m_aName [ 0 ] = 0 ;
Client . m_aClan [ 0 ] = 0 ;
Client . m_Country = - 1 ;
Client . m_Snapshots . Init ( ) ;
Client . m_Traffic = 0 ;
Client . m_TrafficSince = 0 ;
Client . m_ShowIps = false ;
Client . m_AuthKey = - 1 ;
Client . m_Latency = 0 ;
Client . m_Sixup = false ;
2010-05-29 07:25:38 +00:00
}
m_CurrentGameTick = 0 ;
2010-12-06 02:27:35 +00:00
m_AnnouncementLastLine = 0 ;
2011-04-09 06:41:31 +00:00
memset ( m_aPrevStates , CClient : : STATE_EMPTY , MAX_CLIENTS * sizeof ( int ) ) ;
2010-05-29 07:25:38 +00:00
return 0 ;
}
2011-12-31 11:11:48 +00:00
void CServer : : SetRconCID ( int ClientID )
{
m_RconClientID = ClientID ;
}
2021-02-08 21:26:26 +00:00
int CServer : : GetAuthedState ( int ClientID ) const
2010-06-02 02:42:17 +00:00
{
2010-10-10 13:36:58 +00:00
return m_aClients [ ClientID ] . m_Authed ;
2010-06-02 02:42:17 +00:00
}
2021-02-08 21:26:26 +00:00
const char * CServer : : GetAuthName ( int ClientID ) const
2018-01-28 02:13:05 +00:00
{
int Key = m_aClients [ ClientID ] . m_AuthKey ;
if ( Key = = - 1 )
{
return 0 ;
}
return m_AuthManager . KeyIdent ( Key ) ;
}
2021-02-08 21:26:26 +00:00
int CServer : : GetClientInfo ( int ClientID , CClientInfo * pInfo ) const
2010-05-29 07:25:38 +00:00
{
dbg_assert ( ClientID > = 0 & & ClientID < MAX_CLIENTS , " client_id is not valid " ) ;
dbg_assert ( pInfo ! = 0 , " info can not be null " ) ;
if ( m_aClients [ ClientID ] . m_State = = CClient : : STATE_INGAME )
{
pInfo - > m_pName = m_aClients [ ClientID ] . m_aName ;
pInfo - > m_Latency = m_aClients [ ClientID ] . m_Latency ;
2020-05-22 15:58:41 +00:00
pInfo - > m_GotDDNetVersion = m_aClients [ ClientID ] . m_DDNetVersionSettled ;
pInfo - > m_DDNetVersion = m_aClients [ ClientID ] . m_DDNetVersion > = 0 ? m_aClients [ ClientID ] . m_DDNetVersion : VERSION_VANILLA ;
if ( m_aClients [ ClientID ] . m_GotDDNetVersionPacket )
{
pInfo - > m_pConnectionID = & m_aClients [ ClientID ] . m_ConnectionID ;
pInfo - > m_pDDNetVersionStr = m_aClients [ ClientID ] . m_aDDNetVersionStr ;
}
else
{
pInfo - > m_pConnectionID = 0 ;
pInfo - > m_pDDNetVersionStr = 0 ;
}
2010-05-29 07:25:38 +00:00
return 1 ;
}
return 0 ;
}
2020-05-22 15:58:41 +00:00
void CServer : : SetClientDDNetVersion ( int ClientID , int DDNetVersion )
{
dbg_assert ( ClientID > = 0 & & ClientID < MAX_CLIENTS , " client_id is not valid " ) ;
if ( m_aClients [ ClientID ] . m_State = = CClient : : STATE_INGAME )
{
m_aClients [ ClientID ] . m_DDNetVersion = DDNetVersion ;
m_aClients [ ClientID ] . m_DDNetVersionSettled = true ;
}
}
2021-02-08 21:26:26 +00:00
void CServer : : GetClientAddr ( int ClientID , char * pAddrStr , int Size ) const
2010-05-29 07:25:38 +00:00
{
if ( ClientID > = 0 & & ClientID < MAX_CLIENTS & & m_aClients [ ClientID ] . m_State = = CClient : : STATE_INGAME )
2011-12-29 22:36:53 +00:00
net_addr_str ( m_NetServer . ClientAddr ( ClientID ) , pAddrStr , Size , false ) ;
2010-05-29 07:25:38 +00:00
}
2011-04-13 18:37:12 +00:00
2021-02-08 21:26:26 +00:00
const char * CServer : : ClientName ( int ClientID ) const
2010-05-29 07:25:38 +00:00
{
2011-02-12 10:40:36 +00:00
if ( ClientID < 0 | | ClientID > = MAX_CLIENTS | | m_aClients [ ClientID ] . m_State = = CServer : : CClient : : STATE_EMPTY )
2011-04-16 16:41:44 +00:00
return " (invalid) " ;
2011-03-15 10:23:49 +00:00
if ( m_aClients [ ClientID ] . m_State = = CServer : : CClient : : STATE_INGAME )
return m_aClients [ ClientID ] . m_aName ;
else
2011-04-16 16:41:44 +00:00
return " (connecting) " ;
2011-03-15 10:23:49 +00:00
}
2021-02-08 21:26:26 +00:00
const char * CServer : : ClientClan ( int ClientID ) const
2011-03-15 10:23:49 +00:00
{
if ( ClientID < 0 | | ClientID > = MAX_CLIENTS | | m_aClients [ ClientID ] . m_State = = CServer : : CClient : : STATE_EMPTY )
return " " ;
if ( m_aClients [ ClientID ] . m_State = = CServer : : CClient : : STATE_INGAME )
return m_aClients [ ClientID ] . m_aClan ;
else
return " " ;
}
2021-02-08 21:26:26 +00:00
int CServer : : ClientCountry ( int ClientID ) const
2011-03-15 10:23:49 +00:00
{
if ( ClientID < 0 | | ClientID > = MAX_CLIENTS | | m_aClients [ ClientID ] . m_State = = CServer : : CClient : : STATE_EMPTY )
return - 1 ;
if ( m_aClients [ ClientID ] . m_State = = CServer : : CClient : : STATE_INGAME )
return m_aClients [ ClientID ] . m_Country ;
else
return - 1 ;
}
2010-05-29 07:25:38 +00:00
2021-02-08 21:26:26 +00:00
bool CServer : : ClientIngame ( int ClientID ) const
2010-05-29 07:25:38 +00:00
{
return ClientID > = 0 & & ClientID < MAX_CLIENTS & & m_aClients [ ClientID ] . m_State = = CServer : : CClient : : STATE_INGAME ;
}
2021-02-08 21:26:26 +00:00
bool CServer : : ClientAuthed ( int ClientID ) const
2018-04-03 08:27:19 +00:00
{
return ClientID > = 0 & & ClientID < MAX_CLIENTS & & m_aClients [ ClientID ] . m_Authed ;
}
2020-08-29 12:14:37 +00:00
int CServer : : Port ( ) const
{
return m_NetServer . Address ( ) . port ;
}
2011-12-04 15:51:33 +00:00
int CServer : : MaxClients ( ) const
{
return m_NetServer . MaxClients ( ) ;
}
2021-02-08 21:26:26 +00:00
int CServer : : ClientCount ( ) const
2018-10-07 22:59:07 +00:00
{
int ClientCount = 0 ;
2021-02-08 21:26:26 +00:00
for ( const auto & Client : m_aClients )
2018-10-07 22:59:07 +00:00
{
2020-10-26 14:14:07 +00:00
if ( Client . m_State ! = CClient : : STATE_EMPTY )
2018-10-07 22:59:07 +00:00
{
ClientCount + + ;
}
}
return ClientCount ;
}
2021-02-08 21:26:26 +00:00
int CServer : : DistinctClientCount ( ) const
2018-10-07 22:59:07 +00:00
{
NETADDR aAddresses [ MAX_CLIENTS ] ;
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
{
if ( m_aClients [ i ] . m_State ! = CClient : : STATE_EMPTY )
{
GetClientAddr ( i , & aAddresses [ i ] ) ;
}
}
int ClientCount = 0 ;
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
{
if ( m_aClients [ i ] . m_State ! = CClient : : STATE_EMPTY )
{
ClientCount + + ;
2018-10-08 17:56:49 +00:00
for ( int j = 0 ; j < i ; j + + )
2018-10-07 22:59:07 +00:00
{
2018-10-08 16:56:51 +00:00
if ( ! net_addr_comp_noport ( & aAddresses [ i ] , & aAddresses [ j ] ) )
2018-10-07 22:59:07 +00:00
{
ClientCount - - ;
break ;
}
}
}
}
return ClientCount ;
}
2020-04-13 13:34:53 +00:00
static inline bool RepackMsg ( const CMsgPacker * pMsg , CPacker & Packer , bool Sixup )
{
int MsgId = pMsg - > m_MsgID ;
Packer . Reset ( ) ;
2020-12-23 00:25:04 +00:00
if ( Sixup & & ! pMsg - > m_NoTranslate )
2020-04-13 13:34:53 +00:00
{
2020-12-23 00:25:04 +00:00
if ( pMsg - > m_System )
2020-04-13 13:34:53 +00:00
{
2020-12-23 00:25:04 +00:00
if ( MsgId > = OFFSET_UUID )
;
else if ( MsgId > = NETMSG_MAP_CHANGE & & MsgId < = NETMSG_MAP_DATA )
;
else if ( MsgId > = NETMSG_CON_READY & & MsgId < = NETMSG_INPUTTIMING )
MsgId + = 1 ;
else if ( MsgId = = NETMSG_RCON_LINE )
MsgId = 13 ;
else if ( MsgId > = NETMSG_AUTH_CHALLANGE & & MsgId < = NETMSG_AUTH_RESULT )
MsgId + = 4 ;
else if ( MsgId > = NETMSG_PING & & MsgId < = NETMSG_ERROR )
MsgId + = 4 ;
else if ( MsgId > = NETMSG_RCON_CMD_ADD & & MsgId < = NETMSG_RCON_CMD_REM )
MsgId - = 11 ;
2020-04-13 13:34:53 +00:00
else
{
2020-12-23 00:25:04 +00:00
dbg_msg ( " net " , " DROP send sys %d " , MsgId ) ;
return true ;
2020-04-13 13:34:53 +00:00
}
}
2020-12-23 00:25:04 +00:00
else
{
if ( MsgId > = 0 & & MsgId < OFFSET_UUID )
MsgId = Msg_SixToSeven ( MsgId ) ;
if ( MsgId < 0 )
return true ;
}
}
2020-04-13 13:34:53 +00:00
2020-12-23 00:25:04 +00:00
if ( MsgId < OFFSET_UUID )
{
2020-09-26 19:41:58 +00:00
Packer . AddInt ( ( MsgId < < 1 ) | ( pMsg - > m_System ? 1 : 0 ) ) ;
2020-04-13 13:34:53 +00:00
}
2020-12-23 00:25:04 +00:00
else
2020-04-13 13:34:53 +00:00
{
2020-09-26 19:41:58 +00:00
Packer . AddInt ( ( 0 < < 1 ) | ( pMsg - > m_System ? 1 : 0 ) ) ; // NETMSG_EX, NETMSGTYPE_EX
2020-04-13 13:34:53 +00:00
g_UuidManager . PackUuid ( MsgId , & Packer ) ;
}
Packer . AddRaw ( pMsg - > Data ( ) , pMsg - > Size ( ) ) ;
return false ;
}
2011-02-12 10:40:36 +00:00
int CServer : : SendMsg ( CMsgPacker * pMsg , int Flags , int ClientID )
2010-05-29 07:25:38 +00:00
{
CNetChunk Packet ;
if ( ! pMsg )
return - 1 ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
mem_zero ( & Packet , sizeof ( CNetChunk ) ) ;
2020-09-26 19:41:58 +00:00
if ( Flags & MSGFLAG_VITAL )
2010-05-29 07:25:38 +00:00
Packet . m_Flags | = NETSENDFLAG_VITAL ;
2020-09-26 19:41:58 +00:00
if ( Flags & MSGFLAG_FLUSH )
2010-05-29 07:25:38 +00:00
Packet . m_Flags | = NETSENDFLAG_FLUSH ;
2011-04-13 18:37:12 +00:00
2020-06-10 16:12:10 +00:00
if ( ClientID < 0 )
2014-09-26 00:05:22 +00:00
{
2020-06-10 16:12:10 +00:00
CPacker Pack6 , Pack7 ;
if ( RepackMsg ( pMsg , Pack6 , false ) )
return - 1 ;
if ( RepackMsg ( pMsg , Pack7 , true ) )
return - 1 ;
2010-05-29 07:25:38 +00:00
2020-06-10 16:12:10 +00:00
// write message to demo recorder
2020-09-26 19:41:58 +00:00
if ( ! ( Flags & MSGFLAG_NORECORD ) )
2020-06-10 16:12:10 +00:00
m_aDemoRecorder [ MAX_CLIENTS ] . RecordMessage ( Pack6 . Data ( ) , Pack6 . Size ( ) ) ;
2020-09-26 19:41:58 +00:00
if ( ! ( Flags & MSGFLAG_NOSEND ) )
2010-05-29 07:25:38 +00:00
{
2020-06-10 16:12:10 +00:00
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
{
2010-05-29 07:25:38 +00:00
if ( m_aClients [ i ] . m_State = = CClient : : STATE_INGAME )
{
2020-10-27 17:57:14 +00:00
CPacker * pPack = m_aClients [ i ] . m_Sixup ? & Pack7 : & Pack6 ;
Packet . m_pData = pPack - > Data ( ) ;
Packet . m_DataSize = pPack - > Size ( ) ;
2010-05-29 07:25:38 +00:00
Packet . m_ClientID = i ;
2021-06-24 18:32:41 +00:00
if ( Antibot ( ) - > OnEngineServerMessage ( i , Packet . m_pData , Packet . m_DataSize , Flags ) )
{
continue ;
}
2010-05-29 07:25:38 +00:00
m_NetServer . Send ( & Packet ) ;
}
2020-06-10 16:12:10 +00:00
}
2010-05-29 07:25:38 +00:00
}
2020-06-10 16:12:10 +00:00
}
else
{
CPacker Pack ;
if ( RepackMsg ( pMsg , Pack , m_aClients [ ClientID ] . m_Sixup ) )
return - 1 ;
Packet . m_ClientID = ClientID ;
Packet . m_pData = Pack . Data ( ) ;
Packet . m_DataSize = Pack . Size ( ) ;
2021-06-24 18:32:41 +00:00
if ( Antibot ( ) - > OnEngineServerMessage ( ClientID , Packet . m_pData , Packet . m_DataSize , Flags ) )
{
return 0 ;
}
2020-09-26 19:41:58 +00:00
if ( ! ( Flags & MSGFLAG_NORECORD ) )
2020-06-10 16:12:10 +00:00
{
m_aDemoRecorder [ ClientID ] . RecordMessage ( Pack . Data ( ) , Pack . Size ( ) ) ;
m_aDemoRecorder [ MAX_CLIENTS ] . RecordMessage ( Pack . Data ( ) , Pack . Size ( ) ) ;
}
2020-09-26 19:41:58 +00:00
if ( ! ( Flags & MSGFLAG_NOSEND ) )
2010-05-29 07:25:38 +00:00
m_NetServer . Send ( & Packet ) ;
}
2020-06-10 16:12:10 +00:00
2010-05-29 07:25:38 +00:00
return 0 ;
}
2020-05-13 20:27:49 +00:00
void CServer : : SendMsgRaw ( int ClientID , const void * pData , int Size , int Flags )
{
CNetChunk Packet ;
mem_zero ( & Packet , sizeof ( CNetChunk ) ) ;
Packet . m_ClientID = ClientID ;
Packet . m_pData = pData ;
Packet . m_DataSize = Size ;
Packet . m_Flags = 0 ;
2020-09-26 19:41:58 +00:00
if ( Flags & MSGFLAG_VITAL )
2020-05-13 20:27:49 +00:00
{
Packet . m_Flags | = NETSENDFLAG_VITAL ;
}
2020-09-26 19:41:58 +00:00
if ( Flags & MSGFLAG_FLUSH )
2020-05-13 20:27:49 +00:00
{
Packet . m_Flags | = NETSENDFLAG_FLUSH ;
}
m_NetServer . Send ( & Packet ) ;
}
2010-05-29 07:25:38 +00:00
void CServer : : DoSnapshot ( )
{
GameServer ( ) - > OnPreSnap ( ) ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
// create snapshot for demo recording
2014-09-26 00:05:22 +00:00
if ( m_aDemoRecorder [ MAX_CLIENTS ] . IsRecording ( ) )
2010-05-29 07:25:38 +00:00
{
char aData [ CSnapshot : : MAX_SIZE ] ;
int SnapshotSize ;
// build snap and possibly add some messages
m_SnapshotBuilder . Init ( ) ;
GameServer ( ) - > OnSnap ( - 1 ) ;
SnapshotSize = m_SnapshotBuilder . Finish ( aData ) ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
// write snapshot
2021-01-17 16:18:08 +00:00
m_aDemoRecorder [ MAX_CLIENTS ] . RecordSnapshot ( Tick ( ) , aData , SnapshotSize ) ;
2010-05-29 07:25:38 +00:00
}
// create snapshots for all clients
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
{
2018-07-10 09:29:02 +00:00
// client must be ingame to receive snapshots
2010-05-29 07:25:38 +00:00
if ( m_aClients [ i ] . m_State ! = CClient : : STATE_INGAME )
continue ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
// this client is trying to recover, don't spam snapshots
2020-09-26 19:41:58 +00:00
if ( m_aClients [ i ] . m_SnapRate = = CClient : : SNAPRATE_RECOVER & & ( Tick ( ) % 50 ) ! = 0 )
2010-05-29 07:25:38 +00:00
continue ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
// this client is trying to recover, don't spam snapshots
2020-09-26 19:41:58 +00:00
if ( m_aClients [ i ] . m_SnapRate = = CClient : : SNAPRATE_INIT & & ( Tick ( ) % 10 ) ! = 0 )
2010-05-29 07:25:38 +00:00
continue ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
{
char aData [ CSnapshot : : MAX_SIZE ] ;
2020-09-26 19:41:58 +00:00
CSnapshot * pData = ( CSnapshot * ) aData ; // Fix compiler warning for strict-aliasing
2010-05-29 07:25:38 +00:00
char aDeltaData [ CSnapshot : : MAX_SIZE ] ;
char aCompData [ CSnapshot : : MAX_SIZE ] ;
int SnapshotSize ;
int Crc ;
2020-10-27 17:57:14 +00:00
static CSnapshot s_EmptySnap ;
CSnapshot * pDeltashot = & s_EmptySnap ;
2010-05-29 07:25:38 +00:00
int DeltashotSize ;
int DeltaTick = - 1 ;
int DeltaSize ;
2020-03-29 02:36:38 +00:00
m_SnapshotBuilder . Init ( m_aClients [ i ] . m_Sixup ) ;
2010-05-29 07:25:38 +00:00
GameServer ( ) - > OnSnap ( i ) ;
// finish snapshot
2010-06-09 16:24:38 +00:00
SnapshotSize = m_SnapshotBuilder . Finish ( pData ) ;
2014-09-26 00:05:22 +00:00
if ( m_aDemoRecorder [ i ] . IsRecording ( ) )
2014-12-02 01:32:07 +00:00
{
// write snapshot
2021-01-17 16:18:08 +00:00
m_aDemoRecorder [ i ] . RecordSnapshot ( Tick ( ) , aData , SnapshotSize ) ;
2014-12-02 01:32:07 +00:00
}
2014-09-26 00:05:22 +00:00
2010-06-09 16:24:38 +00:00
Crc = pData - > Crc ( ) ;
2010-05-29 07:25:38 +00:00
// remove old snapshos
// keep 3 seconds worth of snapshots
2020-09-26 19:41:58 +00:00
m_aClients [ i ] . m_Snapshots . PurgeUntil ( m_CurrentGameTick - SERVER_TICK_SPEED * 3 ) ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
// save it the snapshot
2010-06-09 16:24:38 +00:00
m_aClients [ i ] . m_Snapshots . Add ( m_CurrentGameTick , time_get ( ) , SnapshotSize , pData , 0 ) ;
2011-04-13 18:37:12 +00:00
2018-07-10 09:29:02 +00:00
// find snapshot that we can perform delta against
2020-10-27 17:57:14 +00:00
s_EmptySnap . Clear ( ) ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
{
DeltashotSize = m_aClients [ i ] . m_Snapshots . Get ( m_aClients [ i ] . m_LastAckedSnapshot , 0 , & pDeltashot , 0 ) ;
if ( DeltashotSize > = 0 )
DeltaTick = m_aClients [ i ] . m_LastAckedSnapshot ;
else
{
// no acked package found, force client to recover rate
if ( m_aClients [ i ] . m_SnapRate = = CClient : : SNAPRATE_FULL )
m_aClients [ i ] . m_SnapRate = CClient : : SNAPRATE_RECOVER ;
}
}
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
// create delta
2020-04-16 08:46:43 +00:00
m_SnapshotDelta . SetStaticsize ( protocol7 : : NETEVENTTYPE_SOUNDWORLD , m_aClients [ i ] . m_Sixup ) ;
m_SnapshotDelta . SetStaticsize ( protocol7 : : NETEVENTTYPE_DAMAGE , m_aClients [ i ] . m_Sixup ) ;
2010-06-09 16:24:38 +00:00
DeltaSize = m_SnapshotDelta . CreateDelta ( pDeltashot , pData , aDeltaData ) ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
if ( DeltaSize )
{
// compress it
int SnapshotSize ;
const int MaxSize = MAX_SNAPSHOT_PACKSIZE ;
int NumPackets ;
2017-09-16 17:30:08 +00:00
SnapshotSize = CVariableInt : : Compress ( aDeltaData , DeltaSize , aCompData , sizeof ( aCompData ) ) ;
2020-09-26 19:41:58 +00:00
NumPackets = ( SnapshotSize + MaxSize - 1 ) / MaxSize ;
2011-04-13 18:37:12 +00:00
2017-09-16 17:30:08 +00:00
for ( int n = 0 , Left = SnapshotSize ; Left > 0 ; n + + )
2010-05-29 07:25:38 +00:00
{
int Chunk = Left < MaxSize ? Left : MaxSize ;
Left - = Chunk ;
if ( NumPackets = = 1 )
{
2012-08-09 08:30:04 +00:00
CMsgPacker Msg ( NETMSG_SNAPSINGLE , true ) ;
2010-05-29 07:25:38 +00:00
Msg . AddInt ( m_CurrentGameTick ) ;
2020-09-26 19:41:58 +00:00
Msg . AddInt ( m_CurrentGameTick - DeltaTick ) ;
2010-05-29 07:25:38 +00:00
Msg . AddInt ( Crc ) ;
Msg . AddInt ( Chunk ) ;
2020-09-26 19:41:58 +00:00
Msg . AddRaw ( & aCompData [ n * MaxSize ] , Chunk ) ;
2012-08-09 08:30:04 +00:00
SendMsg ( & Msg , MSGFLAG_FLUSH , i ) ;
2010-05-29 07:25:38 +00:00
}
else
{
2012-08-09 08:30:04 +00:00
CMsgPacker Msg ( NETMSG_SNAP , true ) ;
2010-05-29 07:25:38 +00:00
Msg . AddInt ( m_CurrentGameTick ) ;
2020-09-26 19:41:58 +00:00
Msg . AddInt ( m_CurrentGameTick - DeltaTick ) ;
2010-05-29 07:25:38 +00:00
Msg . AddInt ( NumPackets ) ;
2011-04-13 18:37:12 +00:00
Msg . AddInt ( n ) ;
2010-05-29 07:25:38 +00:00
Msg . AddInt ( Crc ) ;
Msg . AddInt ( Chunk ) ;
2020-09-26 19:41:58 +00:00
Msg . AddRaw ( & aCompData [ n * MaxSize ] , Chunk ) ;
2012-08-09 08:30:04 +00:00
SendMsg ( & Msg , MSGFLAG_FLUSH , i ) ;
2010-05-29 07:25:38 +00:00
}
}
}
else
{
2012-08-09 08:30:04 +00:00
CMsgPacker Msg ( NETMSG_SNAPEMPTY , true ) ;
2010-05-29 07:25:38 +00:00
Msg . AddInt ( m_CurrentGameTick ) ;
2020-09-26 19:41:58 +00:00
Msg . AddInt ( m_CurrentGameTick - DeltaTick ) ;
2012-08-09 08:30:04 +00:00
SendMsg ( & Msg , MSGFLAG_FLUSH , i ) ;
2010-05-29 07:25:38 +00:00
}
}
}
GameServer ( ) - > OnPostSnap ( ) ;
}
2015-08-23 15:51:28 +00:00
int CServer : : ClientRejoinCallback ( int ClientID , void * pUser )
{
CServer * pThis = ( CServer * ) pUser ;
pThis - > m_aClients [ ClientID ] . m_Authed = AUTHED_NO ;
2017-03-06 11:35:09 +00:00
pThis - > m_aClients [ ClientID ] . m_AuthKey = - 1 ;
2015-08-23 15:51:28 +00:00
pThis - > m_aClients [ ClientID ] . m_pRconCmdToSend = 0 ;
2021-12-14 05:50:30 +00:00
pThis - > m_aClients [ ClientID ] . m_DDNetVersion = VERSION_NONE ;
pThis - > m_aClients [ ClientID ] . m_GotDDNetVersionPacket = false ;
pThis - > m_aClients [ ClientID ] . m_DDNetVersionSettled = false ;
2015-08-23 15:51:28 +00:00
pThis - > m_aClients [ ClientID ] . Reset ( ) ;
pThis - > SendMap ( ClientID ) ;
return 0 ;
}
2018-05-09 21:50:25 +00:00
int CServer : : NewClientNoAuthCallback ( int ClientID , void * pUser )
2015-08-13 08:58:47 +00:00
{
CServer * pThis = ( CServer * ) pUser ;
2016-09-05 09:38:11 +00:00
pThis - > m_aClients [ ClientID ] . m_DnsblState = CClient : : DNSBL_STATE_NONE ;
2018-05-09 21:50:25 +00:00
pThis - > m_aClients [ ClientID ] . m_State = CClient : : STATE_CONNECTING ;
pThis - > m_aClients [ ClientID ] . m_aName [ 0 ] = 0 ;
pThis - > m_aClients [ ClientID ] . m_aClan [ 0 ] = 0 ;
pThis - > m_aClients [ ClientID ] . m_Country = - 1 ;
pThis - > m_aClients [ ClientID ] . m_Authed = AUTHED_NO ;
pThis - > m_aClients [ ClientID ] . m_AuthKey = - 1 ;
pThis - > m_aClients [ ClientID ] . m_AuthTries = 0 ;
pThis - > m_aClients [ ClientID ] . m_pRconCmdToSend = 0 ;
2019-04-29 19:39:14 +00:00
pThis - > m_aClients [ ClientID ] . m_ShowIps = false ;
2021-12-14 05:50:30 +00:00
pThis - > m_aClients [ ClientID ] . m_DDNetVersion = VERSION_NONE ;
pThis - > m_aClients [ ClientID ] . m_GotDDNetVersionPacket = false ;
pThis - > m_aClients [ ClientID ] . m_DDNetVersionSettled = false ;
2018-05-09 21:50:25 +00:00
pThis - > m_aClients [ ClientID ] . Reset ( ) ;
2015-08-13 08:58:47 +00:00
2019-06-03 19:52:14 +00:00
pThis - > SendCapabilities ( ClientID ) ;
2015-08-13 08:58:47 +00:00
pThis - > SendMap ( ClientID ) ;
2017-12-20 15:56:34 +00:00
# if defined(CONF_FAMILY_UNIX)
pThis - > SendConnLoggingCommand ( OPEN_SESSION , pThis - > m_NetServer . ClientAddr ( ClientID ) ) ;
# endif
2015-08-13 08:58:47 +00:00
return 0 ;
}
2010-05-29 07:25:38 +00:00
2020-03-29 02:36:38 +00:00
int CServer : : NewClientCallback ( int ClientID , void * pUser , bool Sixup )
2010-05-29 07:25:38 +00:00
{
CServer * pThis = ( CServer * ) pUser ;
2020-05-22 15:58:41 +00:00
pThis - > m_aClients [ ClientID ] . m_State = CClient : : STATE_PREAUTH ;
2016-09-05 09:38:11 +00:00
pThis - > m_aClients [ ClientID ] . m_DnsblState = CClient : : DNSBL_STATE_NONE ;
2011-02-12 10:40:36 +00:00
pThis - > m_aClients [ ClientID ] . m_aName [ 0 ] = 0 ;
pThis - > m_aClients [ ClientID ] . m_aClan [ 0 ] = 0 ;
2011-03-15 10:23:49 +00:00
pThis - > m_aClients [ ClientID ] . m_Country = - 1 ;
2011-07-05 19:54:10 +00:00
pThis - > m_aClients [ ClientID ] . m_Authed = AUTHED_NO ;
2017-03-06 11:35:09 +00:00
pThis - > m_aClients [ ClientID ] . m_AuthKey = - 1 ;
2011-02-12 10:40:36 +00:00
pThis - > m_aClients [ ClientID ] . m_AuthTries = 0 ;
2011-07-14 20:07:21 +00:00
pThis - > m_aClients [ ClientID ] . m_pRconCmdToSend = 0 ;
2013-08-04 16:09:28 +00:00
pThis - > m_aClients [ ClientID ] . m_Traffic = 0 ;
pThis - > m_aClients [ ClientID ] . m_TrafficSince = 0 ;
2019-04-29 19:39:14 +00:00
pThis - > m_aClients [ ClientID ] . m_ShowIps = false ;
2021-12-14 05:50:30 +00:00
pThis - > m_aClients [ ClientID ] . m_DDNetVersion = VERSION_NONE ;
pThis - > m_aClients [ ClientID ] . m_GotDDNetVersionPacket = false ;
pThis - > m_aClients [ ClientID ] . m_DDNetVersionSettled = false ;
2013-12-31 05:13:57 +00:00
memset ( & pThis - > m_aClients [ ClientID ] . m_Addr , 0 , sizeof ( NETADDR ) ) ;
2011-02-12 10:40:36 +00:00
pThis - > m_aClients [ ClientID ] . Reset ( ) ;
2020-05-13 20:27:49 +00:00
2020-06-19 20:06:39 +00:00
pThis - > GameServer ( ) - > OnClientEngineJoin ( ClientID , Sixup ) ;
2020-07-01 12:11:37 +00:00
pThis - > Antibot ( ) - > OnEngineClientJoin ( ClientID , Sixup ) ;
2017-12-20 15:56:34 +00:00
2020-03-29 02:36:38 +00:00
pThis - > m_aClients [ ClientID ] . m_Sixup = Sixup ;
2017-12-20 15:56:34 +00:00
# if defined(CONF_FAMILY_UNIX)
pThis - > SendConnLoggingCommand ( OPEN_SESSION , pThis - > m_NetServer . ClientAddr ( ClientID ) ) ;
# endif
2010-05-29 07:25:38 +00:00
return 0 ;
}
2016-09-05 09:38:11 +00:00
void CServer : : InitDnsbl ( int ClientID )
{
NETADDR Addr = * m_NetServer . ClientAddr ( ClientID ) ;
//TODO: support ipv6
2017-11-23 14:47:38 +00:00
if ( Addr . type ! = NETTYPE_IPV4 )
2016-09-05 09:38:11 +00:00
return ;
// build dnsbl host lookup
char aBuf [ 256 ] ;
2021-12-14 23:28:51 +00:00
if ( Config ( ) - > m_SvDnsblKey [ 0 ] = = ' \0 ' )
2017-11-23 14:47:38 +00:00
{
2016-09-05 09:38:11 +00:00
// without key
2021-12-14 23:28:51 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " %d.%d.%d.%d.%s " , Addr . ip [ 3 ] , Addr . ip [ 2 ] , Addr . ip [ 1 ] , Addr . ip [ 0 ] , Config ( ) - > m_SvDnsblHost ) ;
2017-11-23 14:47:38 +00:00
}
2016-09-05 09:38:11 +00:00
else
2017-11-23 14:47:38 +00:00
{
2016-09-05 09:38:11 +00:00
// with key
2021-12-14 23:28:51 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " %s.%d.%d.%d.%d.%s " , Config ( ) - > m_SvDnsblKey , Addr . ip [ 3 ] , Addr . ip [ 2 ] , Addr . ip [ 1 ] , Addr . ip [ 0 ] , Config ( ) - > m_SvDnsblHost ) ;
2017-11-23 14:47:38 +00:00
}
2016-09-05 09:38:11 +00:00
IEngine * pEngine = Kernel ( ) - > RequestInterface < IEngine > ( ) ;
2017-11-23 14:47:38 +00:00
pEngine - > AddJob ( m_aClients [ ClientID ] . m_pDnsblLookup = std : : make_shared < CHostLookup > ( aBuf , NETTYPE_IPV4 ) ) ;
2018-08-24 12:24:33 +00:00
m_aClients [ ClientID ] . m_DnsblState = CClient : : DNSBL_STATE_PENDING ;
2016-09-05 09:38:11 +00:00
}
2017-12-20 15:56:34 +00:00
# ifdef CONF_FAMILY_UNIX
2020-09-26 19:41:58 +00:00
void CServer : : SendConnLoggingCommand ( CONN_LOGGING_CMD Cmd , const NETADDR * pAddr )
2017-12-20 15:56:34 +00:00
{
2021-12-14 23:28:51 +00:00
if ( ! Config ( ) - > m_SvConnLoggingServer [ 0 ] | | ! m_ConnLoggingSocketCreated )
2017-12-20 15:56:34 +00:00
return ;
// pack the data and send it
unsigned char aData [ 23 ] = { 0 } ;
aData [ 0 ] = Cmd ;
mem_copy ( & aData [ 1 ] , & pAddr - > type , 4 ) ;
mem_copy ( & aData [ 5 ] , pAddr - > ip , 16 ) ;
mem_copy ( & aData [ 21 ] , & pAddr - > port , 2 ) ;
2017-12-20 15:56:44 +00:00
net_unix_send ( m_ConnLoggingSocket , & m_ConnLoggingDestAddr , aData , sizeof ( aData ) ) ;
2017-12-20 15:56:34 +00:00
}
# endif
2011-02-12 10:40:36 +00:00
int CServer : : DelClientCallback ( int ClientID , const char * pReason , void * pUser )
2010-05-29 07:25:38 +00:00
{
CServer * pThis = ( CServer * ) pUser ;
2011-04-13 18:37:12 +00:00
2011-03-28 18:11:28 +00:00
char aAddrStr [ NETADDR_MAXSTRSIZE ] ;
2011-12-29 22:36:53 +00:00
net_addr_str ( pThis - > m_NetServer . ClientAddr ( ClientID ) , aAddrStr , sizeof ( aAddrStr ) , true ) ;
2017-04-17 10:13:58 +00:00
2010-08-17 22:06:00 +00:00
char aBuf [ 256 ] ;
2019-04-04 17:16:10 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " client dropped. cid=%d addr=<{%s}> reason='%s' " , ClientID , aAddrStr , pReason ) ;
2010-08-17 22:06:00 +00:00
pThis - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_ADDINFO , " server " , aBuf ) ;
2010-05-29 07:25:38 +00:00
// notify the mod about the drop
2011-02-12 10:40:36 +00:00
if ( pThis - > m_aClients [ ClientID ] . m_State > = CClient : : STATE_READY )
2011-02-14 18:41:32 +00:00
pThis - > GameServer ( ) - > OnClientDrop ( ClientID , pReason ) ;
2011-04-13 18:37:12 +00:00
2011-02-12 10:40:36 +00:00
pThis - > m_aClients [ ClientID ] . m_State = CClient : : STATE_EMPTY ;
pThis - > m_aClients [ ClientID ] . m_aName [ 0 ] = 0 ;
pThis - > m_aClients [ ClientID ] . m_aClan [ 0 ] = 0 ;
2011-03-15 10:23:49 +00:00
pThis - > m_aClients [ ClientID ] . m_Country = - 1 ;
2011-07-05 19:54:10 +00:00
pThis - > m_aClients [ ClientID ] . m_Authed = AUTHED_NO ;
2017-03-06 11:35:09 +00:00
pThis - > m_aClients [ ClientID ] . m_AuthKey = - 1 ;
2011-02-12 10:40:36 +00:00
pThis - > m_aClients [ ClientID ] . m_AuthTries = 0 ;
2011-08-13 00:11:06 +00:00
pThis - > m_aClients [ ClientID ] . m_pRconCmdToSend = 0 ;
2013-08-04 16:09:28 +00:00
pThis - > m_aClients [ ClientID ] . m_Traffic = 0 ;
pThis - > m_aClients [ ClientID ] . m_TrafficSince = 0 ;
2019-04-29 19:39:14 +00:00
pThis - > m_aClients [ ClientID ] . m_ShowIps = false ;
2011-02-13 05:35:13 +00:00
pThis - > m_aPrevStates [ ClientID ] = CClient : : STATE_EMPTY ;
2011-02-12 10:40:36 +00:00
pThis - > m_aClients [ ClientID ] . m_Snapshots . PurgeAll ( ) ;
2020-06-17 09:58:04 +00:00
pThis - > m_aClients [ ClientID ] . m_Sixup = false ;
2017-09-13 20:35:09 +00:00
pThis - > GameServer ( ) - > OnClientEngineDrop ( ClientID , pReason ) ;
2020-05-13 20:27:49 +00:00
pThis - > Antibot ( ) - > OnEngineClientDrop ( ClientID , pReason ) ;
2017-12-20 15:56:34 +00:00
# if defined(CONF_FAMILY_UNIX)
pThis - > SendConnLoggingCommand ( CLOSE_SESSION , pThis - > m_NetServer . ClientAddr ( ClientID ) ) ;
# endif
2010-05-29 07:25:38 +00:00
return 0 ;
}
2017-07-24 19:43:55 +00:00
void CServer : : SendRconType ( int ClientID , bool UsernameReq )
{
2012-08-09 08:30:04 +00:00
CMsgPacker Msg ( NETMSG_RCONTYPE , true ) ;
2017-07-24 19:43:55 +00:00
Msg . AddInt ( UsernameReq ) ;
2012-08-09 08:30:04 +00:00
SendMsg ( & Msg , MSGFLAG_VITAL , ClientID ) ;
2017-07-24 19:43:55 +00:00
}
2018-06-05 19:22:40 +00:00
void CServer : : GetMapInfo ( char * pMapName , int MapNameSize , int * pMapSize , SHA256_DIGEST * pMapSha256 , int * pMapCrc )
2017-09-12 12:58:44 +00:00
{
str_copy ( pMapName , GetMapName ( ) , MapNameSize ) ;
2020-06-19 21:52:13 +00:00
* pMapSize = m_aCurrentMapSize [ SIX ] ;
* pMapSha256 = m_aCurrentMapSha256 [ SIX ] ;
* pMapCrc = m_aCurrentMapCrc [ SIX ] ;
2017-09-12 12:58:44 +00:00
}
2019-06-03 19:52:14 +00:00
void CServer : : SendCapabilities ( int ClientID )
{
2012-08-09 08:30:04 +00:00
CMsgPacker Msg ( NETMSG_CAPABILITIES , true ) ;
2019-06-03 19:52:14 +00:00
Msg . AddInt ( SERVERCAP_CURVERSION ) ; // version
2021-11-17 20:00:37 +00:00
Msg . AddInt ( SERVERCAPFLAG_DDNET | SERVERCAPFLAG_CHATTIMEOUTCODE | SERVERCAPFLAG_ANYPLAYERFLAG | SERVERCAPFLAG_PINGEX | SERVERCAPFLAG_ALLOWDUMMY ) ; // flags
2012-08-09 08:30:04 +00:00
SendMsg ( & Msg , MSGFLAG_VITAL , ClientID ) ;
2019-06-03 19:52:14 +00:00
}
2011-02-12 10:40:36 +00:00
void CServer : : SendMap ( int ClientID )
2010-05-29 07:25:38 +00:00
{
2020-06-19 21:52:13 +00:00
int Sixup = IsSixup ( ClientID ) ;
2018-06-05 19:22:40 +00:00
{
2012-08-09 08:30:04 +00:00
CMsgPacker Msg ( NETMSG_MAP_DETAILS , true ) ;
2018-06-05 19:22:40 +00:00
Msg . AddString ( GetMapName ( ) , 0 ) ;
2020-06-19 21:52:13 +00:00
Msg . AddRaw ( & m_aCurrentMapSha256 [ Sixup ] . data , sizeof ( m_aCurrentMapSha256 [ Sixup ] . data ) ) ;
Msg . AddInt ( m_aCurrentMapCrc [ Sixup ] ) ;
Msg . AddInt ( m_aCurrentMapSize [ Sixup ] ) ;
2012-08-09 08:30:04 +00:00
SendMsg ( & Msg , MSGFLAG_VITAL , ClientID ) ;
2018-06-05 19:22:40 +00:00
}
{
2012-08-09 08:30:04 +00:00
CMsgPacker Msg ( NETMSG_MAP_CHANGE , true ) ;
2018-06-05 19:22:40 +00:00
Msg . AddString ( GetMapName ( ) , 0 ) ;
2020-06-19 21:52:13 +00:00
Msg . AddInt ( m_aCurrentMapCrc [ Sixup ] ) ;
Msg . AddInt ( m_aCurrentMapSize [ Sixup ] ) ;
if ( Sixup )
2020-03-29 02:36:38 +00:00
{
2021-12-14 23:28:51 +00:00
Msg . AddInt ( Config ( ) - > m_SvMapWindow ) ;
2020-09-26 19:41:58 +00:00
Msg . AddInt ( 1024 - 128 ) ;
2020-06-19 21:52:13 +00:00
Msg . AddRaw ( m_aCurrentMapSha256 [ Sixup ] . data , sizeof ( m_aCurrentMapSha256 [ Sixup ] . data ) ) ;
2020-03-29 02:36:38 +00:00
}
2020-09-26 19:41:58 +00:00
SendMsg ( & Msg , MSGFLAG_VITAL | MSGFLAG_FLUSH , ClientID ) ;
2018-06-05 19:22:40 +00:00
}
2016-11-18 14:00:42 +00:00
m_aClients [ ClientID ] . m_NextMapChunk = 0 ;
}
void CServer : : SendMapData ( int ClientID , int Chunk )
{
2020-06-19 21:52:13 +00:00
int Sixup = IsSixup ( ClientID ) ;
2020-09-26 19:41:58 +00:00
unsigned int ChunkSize = 1024 - 128 ;
2016-11-18 14:00:42 +00:00
unsigned int Offset = Chunk * ChunkSize ;
int Last = 0 ;
// drop faulty map data requests
2020-06-19 21:52:13 +00:00
if ( Chunk < 0 | | Offset > m_aCurrentMapSize [ Sixup ] )
2016-11-18 14:00:42 +00:00
return ;
2020-09-26 19:41:58 +00:00
if ( Offset + ChunkSize > = m_aCurrentMapSize [ Sixup ] )
2016-11-18 14:00:42 +00:00
{
2020-09-26 19:41:58 +00:00
ChunkSize = m_aCurrentMapSize [ Sixup ] - Offset ;
2016-11-18 14:00:42 +00:00
Last = 1 ;
}
2020-06-17 09:58:04 +00:00
CMsgPacker Msg ( NETMSG_MAP_DATA , true ) ;
2020-06-19 21:52:13 +00:00
if ( ! Sixup )
2020-03-29 02:36:38 +00:00
{
Msg . AddInt ( Last ) ;
2020-06-19 21:52:13 +00:00
Msg . AddInt ( m_aCurrentMapCrc [ SIX ] ) ;
2020-03-29 02:36:38 +00:00
Msg . AddInt ( Chunk ) ;
Msg . AddInt ( ChunkSize ) ;
}
2020-06-19 21:52:13 +00:00
Msg . AddRaw ( & m_apCurrentMapData [ Sixup ] [ Offset ] , ChunkSize ) ;
2020-09-26 19:41:58 +00:00
SendMsg ( & Msg , MSGFLAG_VITAL | MSGFLAG_FLUSH , ClientID ) ;
2016-11-18 14:00:42 +00:00
2021-12-14 23:28:51 +00:00
if ( Config ( ) - > m_Debug )
2016-11-18 14:00:42 +00:00
{
char aBuf [ 256 ] ;
str_format ( aBuf , sizeof ( aBuf ) , " sending chunk %d with size %d " , Chunk , ChunkSize ) ;
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_DEBUG , " server " , aBuf ) ;
}
2010-05-29 07:25:38 +00:00
}
2011-03-15 08:58:57 +00:00
void CServer : : SendConnectionReady ( int ClientID )
{
2012-08-09 08:30:04 +00:00
CMsgPacker Msg ( NETMSG_CON_READY , true ) ;
2020-09-26 19:41:58 +00:00
SendMsg ( & Msg , MSGFLAG_VITAL | MSGFLAG_FLUSH , ClientID ) ;
2010-05-29 07:25:38 +00:00
}
2011-02-12 10:40:36 +00:00
void CServer : : SendRconLine ( int ClientID , const char * pLine )
2010-05-29 07:25:38 +00:00
{
2012-08-09 08:30:04 +00:00
CMsgPacker Msg ( NETMSG_RCON_LINE , true ) ;
2010-05-29 07:25:38 +00:00
Msg . AddString ( pLine , 512 ) ;
2012-08-09 08:30:04 +00:00
SendMsg ( & Msg , MSGFLAG_VITAL , ClientID ) ;
2010-05-29 07:25:38 +00:00
}
2021-03-08 00:08:38 +00:00
void CServer : : SendRconLineAuthed ( const char * pLine , void * pUser , ColorRGBA PrintColor )
2010-05-29 07:25:38 +00:00
{
CServer * pThis = ( CServer * ) pUser ;
2021-10-15 10:15:39 +00:00
static int s_ReentryGuard = 0 ;
2010-05-29 07:25:38 +00:00
int i ;
2011-04-13 18:37:12 +00:00
2020-10-27 17:57:14 +00:00
if ( s_ReentryGuard )
2020-09-26 19:41:58 +00:00
return ;
2020-10-27 17:57:14 +00:00
s_ReentryGuard + + ;
2011-04-13 18:37:12 +00:00
2019-04-04 17:16:10 +00:00
const char * pStart = str_find ( pLine , " <{ " ) ;
const char * pEnd = pStart = = NULL ? NULL : str_find ( pStart + 2 , " }> " ) ;
const char * pLineWithoutIps ;
char aLine [ 512 ] ;
char aLineWithoutIps [ 512 ] ;
aLine [ 0 ] = ' \0 ' ;
aLineWithoutIps [ 0 ] = ' \0 ' ;
if ( pStart = = NULL | | pEnd = = NULL )
{
pLineWithoutIps = pLine ;
}
else
{
str_append ( aLine , pLine , pStart - pLine + 1 ) ;
2020-09-27 08:07:26 +00:00
str_append ( aLine , pStart + 2 , pStart - pLine + pEnd - pStart - 1 ) ;
2019-04-04 17:16:10 +00:00
str_append ( aLine , pEnd + 2 , sizeof ( aLine ) ) ;
str_append ( aLineWithoutIps , pLine , pStart - pLine + 1 ) ;
str_append ( aLineWithoutIps , " XXX " , sizeof ( aLineWithoutIps ) ) ;
str_append ( aLineWithoutIps , pEnd + 2 , sizeof ( aLineWithoutIps ) ) ;
pLine = aLine ;
pLineWithoutIps = aLineWithoutIps ;
}
2010-05-29 07:25:38 +00:00
for ( i = 0 ; i < MAX_CLIENTS ; i + + )
{
2013-07-30 23:31:53 +00:00
if ( pThis - > m_aClients [ i ] . m_State ! = CClient : : STATE_EMPTY & & pThis - > m_aClients [ i ] . m_Authed > = pThis - > m_RconAuthLevel & & ( pThis - > m_RconRestrict = = - 1 | | pThis - > m_RconRestrict = = i ) )
2019-04-04 17:16:10 +00:00
pThis - > SendRconLine ( i , pThis - > m_aClients [ i ] . m_ShowIps ? pLine : pLineWithoutIps ) ;
2010-05-29 07:25:38 +00:00
}
2011-04-13 18:37:12 +00:00
2020-10-27 17:57:14 +00:00
s_ReentryGuard - - ;
2010-05-29 07:25:38 +00:00
}
2011-07-14 20:07:21 +00:00
void CServer : : SendRconCmdAdd ( const IConsole : : CCommandInfo * pCommandInfo , int ClientID )
{
2012-08-09 08:30:04 +00:00
CMsgPacker Msg ( NETMSG_RCON_CMD_ADD , true ) ;
2011-07-30 16:19:15 +00:00
Msg . AddString ( pCommandInfo - > m_pName , IConsole : : TEMPCMD_NAME_LENGTH ) ;
Msg . AddString ( pCommandInfo - > m_pHelp , IConsole : : TEMPCMD_HELP_LENGTH ) ;
2015-12-28 15:14:52 +00:00
Msg . AddString ( pCommandInfo - > m_pParams , IConsole : : TEMPCMD_PARAMS_LENGTH ) ;
2012-08-09 08:30:04 +00:00
SendMsg ( & Msg , MSGFLAG_VITAL , ClientID ) ;
2011-07-14 20:07:21 +00:00
}
void CServer : : SendRconCmdRem ( const IConsole : : CCommandInfo * pCommandInfo , int ClientID )
{
2012-08-09 08:30:04 +00:00
CMsgPacker Msg ( NETMSG_RCON_CMD_REM , true ) ;
2011-07-14 20:07:21 +00:00
Msg . AddString ( pCommandInfo - > m_pName , 256 ) ;
2012-08-09 08:30:04 +00:00
SendMsg ( & Msg , MSGFLAG_VITAL , ClientID ) ;
2011-07-14 20:07:21 +00:00
}
void CServer : : UpdateClientRconCommands ( )
{
int ClientID = Tick ( ) % MAX_CLIENTS ;
2011-08-11 08:59:14 +00:00
2011-07-14 20:07:21 +00:00
if ( m_aClients [ ClientID ] . m_State ! = CClient : : STATE_EMPTY & & m_aClients [ ClientID ] . m_Authed )
{
2015-10-23 00:33:10 +00:00
int ConsoleAccessLevel = m_aClients [ ClientID ] . m_Authed = = AUTHED_ADMIN ? IConsole : : ACCESS_LEVEL_ADMIN : m_aClients [ ClientID ] . m_Authed = = AUTHED_MOD ? IConsole : : ACCESS_LEVEL_MOD : IConsole : : ACCESS_LEVEL_HELPER ;
2011-07-14 20:07:21 +00:00
for ( int i = 0 ; i < MAX_RCONCMD_SEND & & m_aClients [ ClientID ] . m_pRconCmdToSend ; + + i )
{
SendRconCmdAdd ( m_aClients [ ClientID ] . m_pRconCmdToSend , ClientID ) ;
m_aClients [ ClientID ] . m_pRconCmdToSend = m_aClients [ ClientID ] . m_pRconCmdToSend - > NextCommandInfo ( ConsoleAccessLevel , CFGFLAG_SERVER ) ;
}
}
}
2020-04-13 13:47:56 +00:00
static inline int MsgFromSixup ( int Msg , bool System )
{
if ( System )
{
if ( Msg = = NETMSG_INFO )
;
2020-06-16 14:55:37 +00:00
else if ( Msg > = 14 & & Msg < = 15 )
Msg + = 11 ;
2020-04-13 13:47:56 +00:00
else if ( Msg > = 18 & & Msg < = 28 )
Msg = NETMSG_READY + Msg - 18 ;
2020-12-23 00:25:04 +00:00
else if ( Msg < OFFSET_UUID )
2020-04-13 13:47:56 +00:00
return - 1 ;
}
return Msg ;
}
2010-05-29 07:25:38 +00:00
void CServer : : ProcessClientPacket ( CNetChunk * pPacket )
{
2011-02-12 10:40:36 +00:00
int ClientID = pPacket - > m_ClientID ;
2010-05-29 07:25:38 +00:00
CUnpacker Unpacker ;
Unpacker . Reset ( pPacket - > m_pData , pPacket - > m_DataSize ) ;
2012-08-09 08:30:04 +00:00
CMsgPacker Packer ( NETMSG_EX , true ) ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
// unpack msgid and system flag
2017-05-21 23:07:13 +00:00
int Msg ;
bool Sys ;
CUuid Uuid ;
2011-04-13 18:37:12 +00:00
2017-05-21 23:07:13 +00:00
int Result = UnpackMessageID ( & Msg , & Sys , & Uuid , & Unpacker , & Packer ) ;
if ( Result = = UNPACKMESSAGE_ERROR )
{
2010-05-29 07:25:38 +00:00
return ;
2017-05-21 23:07:13 +00:00
}
2011-04-13 18:37:12 +00:00
2020-04-13 13:47:56 +00:00
if ( m_aClients [ ClientID ] . m_Sixup & & ( Msg = MsgFromSixup ( Msg , Sys ) ) < 0 )
{
return ;
}
2021-12-14 23:28:51 +00:00
if ( Config ( ) - > m_SvNetlimit & & Msg ! = NETMSG_REQUEST_MAP_DATA )
2013-08-04 02:24:03 +00:00
{
2021-06-23 05:05:49 +00:00
int64_t Now = time_get ( ) ;
int64_t Diff = Now - m_aClients [ ClientID ] . m_TrafficSince ;
2021-12-14 23:28:51 +00:00
float Alpha = Config ( ) - > m_SvNetlimitAlpha / 100.0f ;
float Limit = ( float ) Config ( ) - > m_SvNetlimit * 1024 / time_freq ( ) ;
2013-08-04 02:37:15 +00:00
2020-09-26 19:41:58 +00:00
if ( m_aClients [ ClientID ] . m_Traffic > Limit )
2013-08-04 02:24:03 +00:00
{
2013-11-23 19:19:30 +00:00
m_NetServer . NetBan ( ) - > BanAddr ( & pPacket - > m_Address , 600 , " Stressing network " ) ;
2013-08-04 15:50:12 +00:00
return ;
2013-08-04 02:24:03 +00:00
}
2020-09-26 19:41:58 +00:00
if ( Diff > 100 )
2013-08-04 02:24:03 +00:00
{
2019-07-08 21:08:42 +00:00
m_aClients [ ClientID ] . m_Traffic = ( Alpha * ( ( float ) pPacket - > m_DataSize / Diff ) ) + ( 1.0f - Alpha ) * m_aClients [ ClientID ] . m_Traffic ;
2013-08-04 15:50:12 +00:00
m_aClients [ ClientID ] . m_TrafficSince = Now ;
2013-08-04 02:24:03 +00:00
}
}
2017-05-21 23:07:13 +00:00
if ( Result = = UNPACKMESSAGE_ANSWER )
{
2012-08-09 08:30:04 +00:00
SendMsg ( & Packer , MSGFLAG_VITAL , ClientID ) ;
2017-05-21 23:07:13 +00:00
}
2011-03-15 08:58:57 +00:00
if ( Sys )
2010-05-29 07:25:38 +00:00
{
2011-03-15 08:58:57 +00:00
// system message
2020-05-22 15:58:41 +00:00
if ( Msg = = NETMSG_CLIENTVER )
2010-05-29 07:25:38 +00:00
{
2020-09-26 19:41:58 +00:00
if ( ( pPacket - > m_Flags & NET_CHUNKFLAG_VITAL ) ! = 0 & & m_aClients [ ClientID ] . m_State = = CClient : : STATE_PREAUTH )
2020-05-22 15:58:41 +00:00
{
CUuid * pConnectionID = ( CUuid * ) Unpacker . GetRaw ( sizeof ( * pConnectionID ) ) ;
int DDNetVersion = Unpacker . GetInt ( ) ;
const char * pDDNetVersionStr = Unpacker . GetString ( CUnpacker : : SANITIZE_CC ) ;
if ( Unpacker . Error ( ) | | ! str_utf8_check ( pDDNetVersionStr ) | | DDNetVersion < 0 )
{
return ;
}
m_aClients [ ClientID ] . m_ConnectionID = * pConnectionID ;
m_aClients [ ClientID ] . m_DDNetVersion = DDNetVersion ;
str_copy ( m_aClients [ ClientID ] . m_aDDNetVersionStr , pDDNetVersionStr , sizeof ( m_aClients [ ClientID ] . m_aDDNetVersionStr ) ) ;
m_aClients [ ClientID ] . m_DDNetVersionSettled = true ;
m_aClients [ ClientID ] . m_GotDDNetVersionPacket = true ;
m_aClients [ ClientID ] . m_State = CClient : : STATE_AUTH ;
}
}
else if ( Msg = = NETMSG_INFO )
{
2020-09-26 19:41:58 +00:00
if ( ( pPacket - > m_Flags & NET_CHUNKFLAG_VITAL ) ! = 0 & & ( m_aClients [ ClientID ] . m_State = = CClient : : STATE_PREAUTH | | m_aClients [ ClientID ] . m_State = = CClient : : STATE_AUTH ) )
2010-05-29 07:25:38 +00:00
{
2011-03-15 08:58:57 +00:00
const char * pVersion = Unpacker . GetString ( CUnpacker : : SANITIZE_CC ) ;
2016-01-27 00:48:19 +00:00
if ( ! str_utf8_check ( pVersion ) )
2016-01-27 00:24:02 +00:00
{
return ;
}
2020-03-29 02:36:38 +00:00
if ( str_comp ( pVersion , GameServer ( ) - > NetVersion ( ) ) ! = 0 & & str_comp ( pVersion , " 0.7 802f1be60a05665f " ) ! = 0 )
2011-03-15 08:58:57 +00:00
{
// wrong version
char aReason [ 256 ] ;
str_format ( aReason , sizeof ( aReason ) , " Wrong version. Server is running '%s' and client '%s' " , GameServer ( ) - > NetVersion ( ) , pVersion ) ;
m_NetServer . Drop ( ClientID , aReason ) ;
return ;
}
2011-04-13 18:37:12 +00:00
2011-03-15 08:58:57 +00:00
const char * pPassword = Unpacker . GetString ( CUnpacker : : SANITIZE_CC ) ;
2016-01-27 00:48:19 +00:00
if ( ! str_utf8_check ( pPassword ) )
2016-01-27 00:24:02 +00:00
{
return ;
}
2021-12-14 23:28:51 +00:00
if ( Config ( ) - > m_Password [ 0 ] ! = 0 & & str_comp ( Config ( ) - > m_Password , pPassword ) ! = 0 )
2011-03-15 08:58:57 +00:00
{
// wrong password
m_NetServer . Drop ( ClientID , " Wrong password " ) ;
return ;
}
2011-04-09 06:41:31 +00:00
// reserved slot
2021-12-14 23:28:51 +00:00
if ( ClientID > = ( Config ( ) - > m_SvMaxClients - Config ( ) - > m_SvReservedSlots ) & & Config ( ) - > m_SvReservedSlotsPass [ 0 ] ! = 0 & & str_comp ( Config ( ) - > m_SvReservedSlotsPass , pPassword ) ! = 0 )
2011-04-09 06:41:31 +00:00
{
m_NetServer . Drop ( ClientID , " This server is full " ) ;
return ;
}
2011-04-13 23:27:49 +00:00
2015-01-27 22:13:47 +00:00
m_aClients [ ClientID ] . m_State = CClient : : STATE_CONNECTING ;
2017-07-24 19:43:55 +00:00
SendRconType ( ClientID , m_AuthManager . NumNonDefaultKeys ( ) > 0 ) ;
2019-06-03 19:52:14 +00:00
SendCapabilities ( ClientID ) ;
2015-01-27 22:13:47 +00:00
SendMap ( ClientID ) ;
2010-10-11 01:50:43 +00:00
}
2010-05-29 07:25:38 +00:00
}
2011-03-15 08:58:57 +00:00
else if ( Msg = = NETMSG_REQUEST_MAP_DATA )
2010-05-29 07:25:38 +00:00
{
2020-09-26 19:41:58 +00:00
if ( ( pPacket - > m_Flags & NET_CHUNKFLAG_VITAL ) = = 0 | | m_aClients [ ClientID ] . m_State < CClient : : STATE_CONNECTING )
2015-03-19 08:57:47 +00:00
return ;
2013-02-08 12:12:50 +00:00
2020-03-29 02:36:38 +00:00
if ( m_aClients [ ClientID ] . m_Sixup )
{
2021-12-14 23:28:51 +00:00
for ( int i = 0 ; i < Config ( ) - > m_SvMapWindow ; i + + )
2020-09-04 13:45:49 +00:00
{
SendMapData ( ClientID , m_aClients [ ClientID ] . m_NextMapChunk + + ) ;
}
2020-03-29 02:36:38 +00:00
return ;
}
2011-03-15 08:58:57 +00:00
int Chunk = Unpacker . GetInt ( ) ;
2021-12-14 23:28:51 +00:00
if ( Chunk ! = m_aClients [ ClientID ] . m_NextMapChunk | | ! Config ( ) - > m_SvFastDownload )
2012-04-13 23:30:18 +00:00
{
2016-11-18 14:00:42 +00:00
SendMapData ( ClientID , Chunk ) ;
2011-03-15 08:58:57 +00:00
return ;
}
2011-04-13 18:37:12 +00:00
2016-11-18 14:00:42 +00:00
if ( Chunk = = 0 )
2011-03-15 08:58:57 +00:00
{
2021-12-14 23:28:51 +00:00
for ( int i = 0 ; i < Config ( ) - > m_SvMapWindow ; i + + )
2016-11-18 14:00:42 +00:00
{
SendMapData ( ClientID , i ) ;
}
2010-07-29 19:55:33 +00:00
}
2021-12-14 23:28:51 +00:00
SendMapData ( ClientID , Config ( ) - > m_SvMapWindow + m_aClients [ ClientID ] . m_NextMapChunk ) ;
2016-11-18 14:00:42 +00:00
m_aClients [ ClientID ] . m_NextMapChunk + + ;
2011-03-15 08:58:57 +00:00
}
else if ( Msg = = NETMSG_READY )
{
2021-02-07 15:03:31 +00:00
if ( ( pPacket - > m_Flags & NET_CHUNKFLAG_VITAL ) ! = 0 & & ( m_aClients [ ClientID ] . m_State = = CClient : : STATE_CONNECTING ) )
2010-05-29 07:25:38 +00:00
{
2011-03-28 18:11:28 +00:00
char aAddrStr [ NETADDR_MAXSTRSIZE ] ;
2011-12-29 22:36:53 +00:00
net_addr_str ( m_NetServer . ClientAddr ( ClientID ) , aAddrStr , sizeof ( aAddrStr ) , true ) ;
2011-04-13 18:37:12 +00:00
2011-03-15 08:58:57 +00:00
char aBuf [ 256 ] ;
2020-09-26 19:41:58 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " player is ready. ClientID=%d addr=<{%s}> secure=%s " , ClientID , aAddrStr , m_NetServer . HasSecurityToken ( ClientID ) ? " yes " : " no " ) ;
2011-03-15 08:58:57 +00:00
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_ADDINFO , " server " , aBuf ) ;
2021-02-07 15:03:31 +00:00
void * pPersistentData = 0 ;
if ( m_aClients [ ClientID ] . m_HasPersistentData )
{
pPersistentData = m_aClients [ ClientID ] . m_pPersistentData ;
m_aClients [ ClientID ] . m_HasPersistentData = false ;
}
2011-03-15 08:58:57 +00:00
m_aClients [ ClientID ] . m_State = CClient : : STATE_READY ;
2021-02-07 15:03:31 +00:00
GameServer ( ) - > OnClientConnected ( ClientID , pPersistentData ) ;
2010-05-29 07:25:38 +00:00
}
2015-08-23 15:01:01 +00:00
SendConnectionReady ( ClientID ) ;
2011-03-15 08:58:57 +00:00
}
else if ( Msg = = NETMSG_ENTERGAME )
{
2020-09-26 19:41:58 +00:00
if ( ( pPacket - > m_Flags & NET_CHUNKFLAG_VITAL ) ! = 0 & & m_aClients [ ClientID ] . m_State = = CClient : : STATE_READY & & GameServer ( ) - > IsClientReady ( ClientID ) )
2010-05-29 07:25:38 +00:00
{
2011-03-28 18:11:28 +00:00
char aAddrStr [ NETADDR_MAXSTRSIZE ] ;
2011-12-29 22:36:53 +00:00
net_addr_str ( m_NetServer . ClientAddr ( ClientID ) , aAddrStr , sizeof ( aAddrStr ) , true ) ;
2011-04-13 18:37:12 +00:00
2011-03-15 08:58:57 +00:00
char aBuf [ 256 ] ;
2020-06-23 15:30:57 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " player has entered the game. ClientID=%d addr=<{%s}> sixup=%d " , ClientID , aAddrStr , IsSixup ( ClientID ) ) ;
2011-03-15 08:58:57 +00:00
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " server " , aBuf ) ;
m_aClients [ ClientID ] . m_State = CClient : : STATE_INGAME ;
2020-06-16 12:41:30 +00:00
if ( IsSixup ( ClientID ) )
{
CMsgPacker Msg ( 4 , true , true ) ; //NETMSG_SERVERINFO //TODO: Import the shared protocol from 7 aswell
GetServerInfoSixup ( & Msg , - 1 , false ) ;
2020-09-26 19:41:58 +00:00
SendMsg ( & Msg , MSGFLAG_VITAL | MSGFLAG_FLUSH , ClientID ) ;
2020-06-16 12:41:30 +00:00
}
2011-03-15 08:58:57 +00:00
GameServer ( ) - > OnClientEnter ( ClientID ) ;
2010-09-06 02:59:02 +00:00
}
2011-03-15 08:58:57 +00:00
}
else if ( Msg = = NETMSG_INPUT )
{
CClient : : CInput * pInput ;
2021-06-23 05:05:49 +00:00
int64_t TagTime ;
2011-04-13 18:37:12 +00:00
2011-03-15 08:58:57 +00:00
m_aClients [ ClientID ] . m_LastAckedSnapshot = Unpacker . GetInt ( ) ;
int IntendedTick = Unpacker . GetInt ( ) ;
int Size = Unpacker . GetInt ( ) ;
2011-04-13 18:37:12 +00:00
2011-03-15 08:58:57 +00:00
// check for errors
2020-09-26 19:41:58 +00:00
if ( Unpacker . Error ( ) | | Size / 4 > MAX_INPUT_SIZE )
2011-03-15 08:58:57 +00:00
return ;
2010-08-22 16:06:20 +00:00
2011-03-15 08:58:57 +00:00
if ( m_aClients [ ClientID ] . m_LastAckedSnapshot > 0 )
m_aClients [ ClientID ] . m_SnapRate = CClient : : SNAPRATE_FULL ;
2011-04-13 18:37:12 +00:00
2011-03-15 08:58:57 +00:00
if ( m_aClients [ ClientID ] . m_Snapshots . Get ( m_aClients [ ClientID ] . m_LastAckedSnapshot , & TagTime , 0 , 0 ) > = 0 )
2020-09-26 19:41:58 +00:00
m_aClients [ ClientID ] . m_Latency = ( int ) ( ( ( time_get ( ) - TagTime ) * 1000 ) / time_freq ( ) ) ;
2010-08-22 16:06:20 +00:00
2011-03-15 08:58:57 +00:00
// add message to report the input timing
// skip packets that are old
if ( IntendedTick > m_aClients [ ClientID ] . m_LastInputTick )
{
2020-09-26 19:41:58 +00:00
int TimeLeft = ( ( TickStartTime ( IntendedTick ) - time_get ( ) ) * 1000 ) / time_freq ( ) ;
2011-04-13 18:37:12 +00:00
2012-08-09 08:30:04 +00:00
CMsgPacker Msg ( NETMSG_INPUTTIMING , true ) ;
2011-03-15 08:58:57 +00:00
Msg . AddInt ( IntendedTick ) ;
Msg . AddInt ( TimeLeft ) ;
2012-08-09 08:30:04 +00:00
SendMsg ( & Msg , 0 , ClientID ) ;
2011-03-15 08:58:57 +00:00
}
2010-09-06 02:59:02 +00:00
2011-03-15 08:58:57 +00:00
m_aClients [ ClientID ] . m_LastInputTick = IntendedTick ;
2010-10-10 13:36:58 +00:00
2011-03-15 08:58:57 +00:00
pInput = & m_aClients [ ClientID ] . m_aInputs [ m_aClients [ ClientID ] . m_CurrentInput ] ;
2011-04-13 18:37:12 +00:00
2011-03-15 08:58:57 +00:00
if ( IntendedTick < = Tick ( ) )
2020-09-26 19:41:58 +00:00
IntendedTick = Tick ( ) + 1 ;
2010-10-10 13:36:58 +00:00
2011-03-15 08:58:57 +00:00
pInput - > m_GameTick = IntendedTick ;
2011-04-13 18:37:12 +00:00
2020-09-26 19:41:58 +00:00
for ( int i = 0 ; i < Size / 4 ; i + + )
2011-03-15 08:58:57 +00:00
pInput - > m_aData [ i ] = Unpacker . GetInt ( ) ;
2011-04-13 18:37:12 +00:00
2020-09-26 19:41:58 +00:00
mem_copy ( m_aClients [ ClientID ] . m_LatestInput . m_aData , pInput - > m_aData , MAX_INPUT_SIZE * sizeof ( int ) ) ;
2011-04-13 18:37:12 +00:00
2011-03-15 08:58:57 +00:00
m_aClients [ ClientID ] . m_CurrentInput + + ;
m_aClients [ ClientID ] . m_CurrentInput % = 200 ;
2011-04-13 18:37:12 +00:00
2011-03-15 08:58:57 +00:00
// call the mod with the fresh input data
if ( m_aClients [ ClientID ] . m_State = = CClient : : STATE_INGAME )
GameServer ( ) - > OnClientDirectInput ( ClientID , m_aClients [ ClientID ] . m_LatestInput . m_aData ) ;
}
else if ( Msg = = NETMSG_RCON_CMD )
{
const char * pCmd = Unpacker . GetString ( ) ;
2016-01-27 00:48:19 +00:00
if ( ! str_utf8_check ( pCmd ) )
2016-01-27 00:24:02 +00:00
{
return ;
}
2013-12-31 05:13:57 +00:00
if ( Unpacker . Error ( ) = = 0 & & ! str_comp ( pCmd , " crashmeplx " ) )
{
2020-05-22 15:58:41 +00:00
int Version = m_aClients [ ClientID ] . m_DDNetVersion ;
2020-09-26 19:41:58 +00:00
if ( GameServer ( ) - > PlayerExists ( ClientID ) & & Version < VERSION_DDNET_OLD )
2020-05-22 15:58:41 +00:00
{
m_aClients [ ClientID ] . m_DDNetVersion = VERSION_DDNET_OLD ;
}
}
2020-09-26 19:41:58 +00:00
else if ( ( pPacket - > m_Flags & NET_CHUNKFLAG_VITAL ) ! = 0 & & Unpacker . Error ( ) = = 0 & & m_aClients [ ClientID ] . m_Authed )
2010-05-29 07:25:38 +00:00
{
2020-09-26 19:41:58 +00:00
if ( GameServer ( ) - > PlayerExists ( ClientID ) )
2014-08-22 11:54:13 +00:00
{
char aBuf [ 256 ] ;
str_format ( aBuf , sizeof ( aBuf ) , " ClientID=%d rcon='%s' " , ClientID , pCmd ) ;
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_ADDINFO , " server " , aBuf ) ;
m_RconClientID = ClientID ;
m_RconAuthLevel = m_aClients [ ClientID ] . m_Authed ;
2015-10-23 00:33:10 +00:00
Console ( ) - > SetAccessLevel ( m_aClients [ ClientID ] . m_Authed = = AUTHED_ADMIN ? IConsole : : ACCESS_LEVEL_ADMIN : m_aClients [ ClientID ] . m_Authed = = AUTHED_MOD ? IConsole : : ACCESS_LEVEL_MOD : m_aClients [ ClientID ] . m_Authed = = AUTHED_HELPER ? IConsole : : ACCESS_LEVEL_HELPER : IConsole : : ACCESS_LEVEL_USER ) ;
2014-08-22 11:54:13 +00:00
Console ( ) - > ExecuteLineFlag ( pCmd , CFGFLAG_SERVER , ClientID ) ;
Console ( ) - > SetAccessLevel ( IConsole : : ACCESS_LEVEL_ADMIN ) ;
m_RconClientID = IServer : : RCON_CID_SERV ;
m_RconAuthLevel = AUTHED_ADMIN ;
}
2010-10-10 13:36:58 +00:00
}
2011-03-15 08:58:57 +00:00
}
else if ( Msg = = NETMSG_RCON_AUTH )
{
2020-06-16 14:55:37 +00:00
const char * pName = " " ;
if ( ! IsSixup ( ClientID ) )
pName = Unpacker . GetString ( CUnpacker : : SANITIZE_CC ) ; // login name, now used
2017-03-02 15:16:29 +00:00
const char * pPw = Unpacker . GetString ( CUnpacker : : SANITIZE_CC ) ;
2017-03-04 20:06:22 +00:00
if ( ! str_utf8_check ( pPw ) | | ! str_utf8_check ( pName ) )
2016-01-27 00:24:02 +00:00
{
return ;
}
2010-10-12 07:31:47 +00:00
2020-09-26 19:41:58 +00:00
if ( ( pPacket - > m_Flags & NET_CHUNKFLAG_VITAL ) ! = 0 & & Unpacker . Error ( ) = = 0 )
2011-03-15 08:58:57 +00:00
{
2015-10-26 23:33:26 +00:00
int AuthLevel = - 1 ;
2017-03-02 15:16:29 +00:00
int KeySlot = - 1 ;
2015-10-26 23:33:26 +00:00
2017-03-02 15:16:29 +00:00
if ( ! pName [ 0 ] )
2010-10-10 13:36:58 +00:00
{
2017-03-02 15:16:29 +00:00
if ( m_AuthManager . CheckKey ( ( KeySlot = m_AuthManager . DefaultKey ( AUTHED_ADMIN ) ) , pPw ) )
AuthLevel = AUTHED_ADMIN ;
else if ( m_AuthManager . CheckKey ( ( KeySlot = m_AuthManager . DefaultKey ( AUTHED_MOD ) ) , pPw ) )
AuthLevel = AUTHED_MOD ;
else if ( m_AuthManager . CheckKey ( ( KeySlot = m_AuthManager . DefaultKey ( AUTHED_HELPER ) ) , pPw ) )
AuthLevel = AUTHED_HELPER ;
}
else
{
KeySlot = m_AuthManager . FindKey ( pName ) ;
if ( m_AuthManager . CheckKey ( KeySlot , pPw ) )
AuthLevel = m_AuthManager . KeyLevel ( KeySlot ) ;
2010-05-29 07:25:38 +00:00
}
2015-10-26 23:33:26 +00:00
if ( AuthLevel ! = - 1 )
2011-07-05 19:54:10 +00:00
{
2015-10-26 23:33:26 +00:00
if ( m_aClients [ ClientID ] . m_Authed ! = AuthLevel )
2014-08-22 11:54:13 +00:00
{
2020-06-16 14:55:37 +00:00
if ( ! IsSixup ( ClientID ) )
{
CMsgPacker Msg ( NETMSG_RCON_AUTH_STATUS , true ) ;
2020-09-26 19:41:58 +00:00
Msg . AddInt ( 1 ) ; //authed
Msg . AddInt ( 1 ) ; //cmdlist
2020-06-16 14:55:37 +00:00
SendMsg ( & Msg , MSGFLAG_VITAL , ClientID ) ;
}
else
{
CMsgPacker Msg ( 11 , true , true ) ; //NETMSG_RCON_AUTH_ON
SendMsg ( & Msg , MSGFLAG_VITAL , ClientID ) ;
}
2014-08-22 11:54:13 +00:00
2017-03-06 19:11:23 +00:00
m_aClients [ ClientID ] . m_Authed = AuthLevel ; // Keeping m_Authed around is unwise...
2017-03-02 15:16:29 +00:00
m_aClients [ ClientID ] . m_AuthKey = KeySlot ;
2020-06-16 14:55:37 +00:00
int SendRconCmds = IsSixup ( ClientID ) ? true : Unpacker . GetInt ( ) ;
2014-08-22 11:54:13 +00:00
if ( Unpacker . Error ( ) = = 0 & & SendRconCmds )
2015-10-26 23:33:26 +00:00
// AUTHED_ADMIN - AuthLevel gets the proper IConsole::ACCESS_LEVEL_<x>
m_aClients [ ClientID ] . m_pRconCmdToSend = Console ( ) - > FirstCommandInfo ( AUTHED_ADMIN - AuthLevel , CFGFLAG_SERVER ) ;
2014-08-22 11:54:13 +00:00
char aBuf [ 256 ] ;
2017-03-02 15:16:29 +00:00
const char * pIdent = m_AuthManager . KeyIdent ( KeySlot ) ;
2020-09-26 19:41:58 +00:00
switch ( AuthLevel )
{
case AUTHED_ADMIN :
{
SendRconLine ( ClientID , " Admin authentication successful. Full remote console access granted. " ) ;
str_format ( aBuf , sizeof ( aBuf ) , " ClientID=%d authed with key=%s (admin) " , ClientID , pIdent ) ;
break ;
}
case AUTHED_MOD :
2015-10-26 23:33:26 +00:00
{
2020-09-26 19:41:58 +00:00
SendRconLine ( ClientID , " Moderator authentication successful. Limited remote console access granted. " ) ;
str_format ( aBuf , sizeof ( aBuf ) , " ClientID=%d authed with key=%s (moderator) " , ClientID , pIdent ) ;
break ;
}
case AUTHED_HELPER :
{
SendRconLine ( ClientID , " Helper authentication successful. Limited remote console access granted. " ) ;
str_format ( aBuf , sizeof ( aBuf ) , " ClientID=%d authed with key=%s (helper) " , ClientID , pIdent ) ;
break ;
}
2015-10-26 23:33:26 +00:00
}
2014-08-22 11:54:13 +00:00
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " server " , aBuf ) ;
// DDRace
2015-10-27 01:00:15 +00:00
GameServer ( ) - > OnSetAuthed ( ClientID , AuthLevel ) ;
2014-08-22 11:54:13 +00:00
}
2011-03-15 08:58:57 +00:00
}
2021-12-14 23:28:51 +00:00
else if ( Config ( ) - > m_SvRconMaxTries )
2011-03-15 08:58:57 +00:00
{
m_aClients [ ClientID ] . m_AuthTries + + ;
char aBuf [ 128 ] ;
2021-12-14 23:28:51 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " Wrong password %d/%d. " , m_aClients [ ClientID ] . m_AuthTries , Config ( ) - > m_SvRconMaxTries ) ;
2011-03-15 08:58:57 +00:00
SendRconLine ( ClientID , aBuf ) ;
2021-12-14 23:28:51 +00:00
if ( m_aClients [ ClientID ] . m_AuthTries > = Config ( ) - > m_SvRconMaxTries )
2010-10-11 01:50:43 +00:00
{
2021-12-14 23:28:51 +00:00
if ( ! Config ( ) - > m_SvRconBantime )
2011-03-15 08:58:57 +00:00
m_NetServer . Drop ( ClientID , " Too many remote console authentication tries " ) ;
else
2021-12-14 23:28:51 +00:00
m_ServerBan . BanAddr ( m_NetServer . ClientAddr ( ClientID ) , Config ( ) - > m_SvRconBantime * 60 , " Too many remote console authentication tries " ) ;
2010-10-11 01:50:43 +00:00
}
2010-05-29 07:25:38 +00:00
}
2011-03-15 08:58:57 +00:00
else
2010-05-29 07:25:38 +00:00
{
2011-03-15 08:58:57 +00:00
SendRconLine ( ClientID , " Wrong password. " ) ;
2011-01-19 14:39:04 +00:00
}
2011-08-13 00:11:06 +00:00
}
2010-05-29 07:25:38 +00:00
}
2011-03-15 08:58:57 +00:00
else if ( Msg = = NETMSG_PING )
{
2012-08-09 08:30:04 +00:00
CMsgPacker Msg ( NETMSG_PING_REPLY , true ) ;
SendMsg ( & Msg , 0 , ClientID ) ;
2010-05-29 07:25:38 +00:00
}
2021-04-23 21:29:01 +00:00
else if ( Msg = = NETMSG_PINGEX )
{
CUuid * pID = ( CUuid * ) Unpacker . GetRaw ( sizeof ( * pID ) ) ;
if ( Unpacker . Error ( ) )
{
return ;
}
CMsgPacker Msg ( NETMSG_PONGEX , true ) ;
Msg . AddRaw ( pID , sizeof ( * pID ) ) ;
SendMsg ( & Msg , MSGFLAG_FLUSH , ClientID ) ;
}
2010-05-29 07:25:38 +00:00
else
{
2021-12-14 23:28:51 +00:00
if ( Config ( ) - > m_Debug )
2011-03-15 08:58:57 +00:00
{
2021-09-14 17:53:35 +00:00
constexpr int MaxDumpedDataSize = 32 ;
char aBuf [ MaxDumpedDataSize * 3 + 1 ] ;
str_hex ( aBuf , sizeof ( aBuf ) , pPacket - > m_pData , minimum ( pPacket - > m_DataSize , MaxDumpedDataSize ) ) ;
2011-03-15 08:58:57 +00:00
char aBufMsg [ 256 ] ;
str_format ( aBufMsg , sizeof ( aBufMsg ) , " strange message ClientID=%d msg=%d data_size=%d " , ClientID , Msg , pPacket - > m_DataSize ) ;
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_DEBUG , " server " , aBufMsg ) ;
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_DEBUG , " server " , aBuf ) ;
}
2010-05-29 07:25:38 +00:00
}
2010-09-06 02:59:02 +00:00
}
2011-03-15 08:58:57 +00:00
else
{
// game message
2020-09-26 19:41:58 +00:00
if ( ( pPacket - > m_Flags & NET_CHUNKFLAG_VITAL ) ! = 0 & & m_aClients [ ClientID ] . m_State > = CClient : : STATE_READY )
2011-03-15 08:58:57 +00:00
GameServer ( ) - > OnMessage ( Msg , & Unpacker , ClientID ) ;
}
2010-05-29 07:25:38 +00:00
}
2011-04-13 18:37:12 +00:00
2020-06-16 12:41:30 +00:00
bool CServer : : RateLimitServerInfoConnless ( )
2016-01-22 15:02:40 +00:00
{
2019-06-11 16:12:41 +00:00
bool SendClients = true ;
2021-12-14 23:28:51 +00:00
if ( Config ( ) - > m_SvServerInfoPerSecond )
2016-01-22 15:02:40 +00:00
{
2021-12-14 23:28:51 +00:00
SendClients = m_ServerInfoNumRequests < = Config ( ) - > m_SvServerInfoPerSecond ;
2021-06-23 05:05:49 +00:00
const int64_t Now = Tick ( ) ;
2019-06-11 16:12:41 +00:00
if ( Now < = m_ServerInfoFirstRequest + TickSpeed ( ) )
{
m_ServerInfoNumRequests + + ;
}
else
{
m_ServerInfoNumRequests = 1 ;
m_ServerInfoFirstRequest = Now ;
}
2016-01-22 15:02:40 +00:00
}
2020-06-16 12:41:30 +00:00
return SendClients ;
}
void CServer : : SendServerInfoConnless ( const NETADDR * pAddr , int Token , int Type )
{
SendServerInfo ( pAddr , Token , Type , RateLimitServerInfoConnless ( ) ) ;
2016-01-22 15:02:40 +00:00
}
2019-11-04 00:06:09 +00:00
static inline int GetCacheIndex ( int Type , bool SendClient )
{
if ( Type = = SERVERINFO_INGAME )
Type = SERVERINFO_VANILLA ;
else if ( Type = = SERVERINFO_EXTENDED_MORE )
Type = SERVERINFO_EXTENDED ;
return Type * 2 + SendClient ;
}
2019-11-03 00:53:50 +00:00
CServer : : CCache : : CCache ( )
{
2020-10-27 17:57:14 +00:00
m_Cache . clear ( ) ;
2019-11-03 00:53:50 +00:00
}
CServer : : CCache : : ~ CCache ( )
{
Clear ( ) ;
}
2019-11-03 14:39:32 +00:00
CServer : : CCache : : CCacheChunk : : CCacheChunk ( const void * pData , int Size )
2019-11-02 23:33:30 +00:00
{
2019-11-03 17:31:05 +00:00
mem_copy ( m_aData , pData , Size ) ;
2019-11-03 14:39:32 +00:00
m_DataSize = Size ;
}
2019-11-02 23:33:30 +00:00
2019-11-03 14:39:32 +00:00
void CServer : : CCache : : AddChunk ( const void * pData , int Size )
2010-05-29 07:25:38 +00:00
{
2020-10-27 17:57:14 +00:00
m_Cache . emplace_back ( pData , Size ) ;
2019-11-02 23:33:30 +00:00
}
void CServer : : CCache : : Clear ( )
{
2020-10-27 17:57:14 +00:00
m_Cache . clear ( ) ;
2019-11-02 23:33:30 +00:00
}
void CServer : : CacheServerInfo ( CCache * pCache , int Type , bool SendClients )
2010-05-29 07:25:38 +00:00
{
2019-11-03 00:07:10 +00:00
pCache - > Clear ( ) ;
2017-03-29 10:56:13 +00:00
// One chance to improve the protocol!
2010-05-29 07:25:38 +00:00
CPacker p ;
char aBuf [ 128 ] ;
// count the players
2011-03-20 14:33:49 +00:00
int PlayerCount = 0 , ClientCount = 0 ;
2010-05-29 07:25:38 +00:00
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
{
if ( m_aClients [ i ] . m_State ! = CClient : : STATE_EMPTY )
2011-03-20 14:33:49 +00:00
{
if ( GameServer ( ) - > IsClientPlayer ( i ) )
PlayerCount + + ;
2011-04-13 18:37:12 +00:00
2011-03-20 14:33:49 +00:00
ClientCount + + ;
}
2010-05-29 07:25:38 +00:00
}
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
p . Reset ( ) ;
2020-09-26 19:41:58 +00:00
# define ADD_RAW(p, x) (p).AddRaw(x, sizeof(x))
# define ADD_INT(p, x) \
do \
{ \
str_format ( aBuf , sizeof ( aBuf ) , " %d " , x ) ; \
( p ) . AddString ( aBuf , 0 ) ; \
} while ( 0 )
2014-01-01 13:58:39 +00:00
2010-05-29 07:25:38 +00:00
p . AddString ( GameServer ( ) - > Version ( ) , 32 ) ;
2017-03-29 10:56:13 +00:00
if ( Type ! = SERVERINFO_VANILLA )
2013-12-31 05:13:57 +00:00
{
2021-12-14 23:28:51 +00:00
p . AddString ( Config ( ) - > m_SvName , 256 ) ;
2013-12-31 05:13:57 +00:00
}
else
{
2017-03-29 10:56:13 +00:00
if ( m_NetServer . MaxClients ( ) < = VANILLA_MAX_CLIENTS )
{
2021-12-14 23:28:51 +00:00
p . AddString ( Config ( ) - > m_SvName , 64 ) ;
2017-03-29 10:56:13 +00:00
}
2013-12-31 05:13:57 +00:00
else
{
2021-12-14 23:28:51 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " %s [%d/%d] " , Config ( ) - > m_SvName , ClientCount , m_NetServer . MaxClients ( ) ) ;
2013-12-31 05:13:57 +00:00
p . AddString ( aBuf , 64 ) ;
}
}
2010-10-10 13:36:58 +00:00
p . AddString ( GetMapName ( ) , 32 ) ;
2010-05-29 07:25:38 +00:00
2017-03-29 10:56:13 +00:00
if ( Type = = SERVERINFO_EXTENDED )
{
2020-06-19 21:52:13 +00:00
ADD_INT ( p , m_aCurrentMapCrc [ SIX ] ) ;
ADD_INT ( p , m_aCurrentMapSize [ SIX ] ) ;
2017-03-29 10:56:13 +00:00
}
2010-05-29 07:25:38 +00:00
// gametype
2011-02-16 11:31:47 +00:00
p . AddString ( GameServer ( ) - > GameType ( ) , 16 ) ;
2010-05-29 07:25:38 +00:00
// flags
2021-12-14 23:28:51 +00:00
ADD_INT ( p , Config ( ) - > m_Password [ 0 ] ? SERVER_FLAG_PASSWORD : 0 ) ;
2010-05-29 07:25:38 +00:00
2013-12-31 05:13:57 +00:00
int MaxClients = m_NetServer . MaxClients ( ) ;
2021-03-07 10:11:52 +00:00
// How many clients the used serverinfo protocol supports, has to be tracked
// separately to make sure we don't subtract the reserved slots from it
int MaxClientsProtocol = MAX_CLIENTS ;
2017-03-29 10:56:13 +00:00
if ( Type = = SERVERINFO_VANILLA | | Type = = SERVERINFO_INGAME )
2013-12-31 05:13:57 +00:00
{
2017-03-29 10:56:13 +00:00
if ( ClientCount > = VANILLA_MAX_CLIENTS )
2013-12-31 05:13:57 +00:00
{
2017-03-29 10:56:13 +00:00
if ( ClientCount < MaxClients )
2013-12-31 05:13:57 +00:00
ClientCount = VANILLA_MAX_CLIENTS - 1 ;
else
ClientCount = VANILLA_MAX_CLIENTS ;
}
2021-03-07 10:11:52 +00:00
MaxClientsProtocol = VANILLA_MAX_CLIENTS ;
2017-03-29 10:56:13 +00:00
if ( PlayerCount > ClientCount )
PlayerCount = ClientCount ;
2013-12-31 05:13:57 +00:00
}
2017-03-29 10:56:13 +00:00
ADD_INT ( p , PlayerCount ) ; // num players
2021-12-14 23:28:51 +00:00
ADD_INT ( p , minimum ( MaxClientsProtocol , maximum ( MaxClients - maximum ( Config ( ) - > m_SvSpectatorSlots , Config ( ) - > m_SvReservedSlots ) , PlayerCount ) ) ) ; // max players
2017-03-29 10:56:13 +00:00
ADD_INT ( p , ClientCount ) ; // num clients
2021-12-14 23:28:51 +00:00
ADD_INT ( p , minimum ( MaxClientsProtocol , maximum ( MaxClients - Config ( ) - > m_SvReservedSlots , ClientCount ) ) ) ; // max clients
2017-03-29 10:56:13 +00:00
if ( Type = = SERVERINFO_EXTENDED )
p . AddString ( " " , 0 ) ; // extra info, reserved
const void * pPrefix = p . Data ( ) ;
int PrefixSize = p . Size ( ) ;
2020-10-27 17:57:14 +00:00
CPacker q ;
2019-11-03 14:39:32 +00:00
int ChunksStored = 0 ;
int PlayersStored = 0 ;
2017-03-29 10:56:13 +00:00
2020-09-26 19:41:58 +00:00
# define SAVE(size) \
do \
{ \
2020-10-27 17:57:14 +00:00
pCache - > AddChunk ( q . Data ( ) , size ) ; \
2020-09-26 19:41:58 +00:00
ChunksStored + + ; \
} while ( 0 )
2017-03-29 10:56:13 +00:00
2020-09-26 19:41:58 +00:00
# define RESET() \
do \
{ \
2020-10-27 17:57:14 +00:00
q . Reset ( ) ; \
q . AddRaw ( pPrefix , PrefixSize ) ; \
2020-09-26 19:41:58 +00:00
} while ( 0 )
2013-12-31 05:13:57 +00:00
2017-03-29 10:56:13 +00:00
RESET ( ) ;
2013-12-31 05:13:57 +00:00
2017-03-29 10:56:13 +00:00
if ( Type = = SERVERINFO_64_LEGACY )
2020-10-27 17:57:14 +00:00
q . AddInt ( PlayersStored ) ; // offset
2013-12-31 05:13:57 +00:00
2017-03-29 10:56:13 +00:00
if ( ! SendClients )
2016-01-22 15:02:40 +00:00
{
2020-10-27 17:57:14 +00:00
SAVE ( q . Size ( ) ) ;
2016-01-22 15:02:40 +00:00
return ;
}
2017-03-29 10:56:13 +00:00
if ( Type = = SERVERINFO_EXTENDED )
{
2019-11-02 23:33:30 +00:00
pPrefix = " " ;
PrefixSize = 0 ;
2017-03-29 10:56:13 +00:00
}
int Remaining ;
switch ( Type )
{
case SERVERINFO_EXTENDED : Remaining = - 1 ; break ;
case SERVERINFO_64_LEGACY : Remaining = 24 ; break ;
case SERVERINFO_VANILLA : Remaining = VANILLA_MAX_CLIENTS ; break ;
case SERVERINFO_INGAME : Remaining = VANILLA_MAX_CLIENTS ; break ;
default : dbg_assert ( 0 , " caught earlier, unreachable " ) ; return ;
}
// Use the following strategy for sending:
// For vanilla, send the first 16 players.
// For legacy 64p, send 24 players per packet.
// For extended, send as much players as possible.
2010-05-29 07:25:38 +00:00
2017-03-29 10:56:13 +00:00
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
2010-05-29 07:25:38 +00:00
{
2014-01-09 20:08:50 +00:00
if ( m_aClients [ i ] . m_State ! = CClient : : STATE_EMPTY )
2010-05-29 07:25:38 +00:00
{
2017-03-29 10:56:13 +00:00
if ( Remaining = = 0 )
{
if ( Type = = SERVERINFO_VANILLA | | Type = = SERVERINFO_INGAME )
break ;
// Otherwise we're SERVERINFO_64_LEGACY.
2020-10-27 17:57:14 +00:00
SAVE ( q . Size ( ) ) ;
2017-03-29 10:56:13 +00:00
RESET ( ) ;
2020-10-27 17:57:14 +00:00
q . AddInt ( PlayersStored ) ; // offset
2017-03-29 10:56:13 +00:00
Remaining = 24 ;
}
if ( Remaining > 0 )
{
Remaining - - ;
}
2020-10-27 17:57:14 +00:00
int PreviousSize = q . Size ( ) ;
2017-03-29 10:56:13 +00:00
2020-10-27 17:57:14 +00:00
q . AddString ( ClientName ( i ) , MAX_NAME_LENGTH ) ; // client name
q . AddString ( ClientClan ( i ) , MAX_CLAN_LENGTH ) ; // client clan
2013-12-31 05:13:57 +00:00
2020-10-27 17:57:14 +00:00
ADD_INT ( q , m_aClients [ i ] . m_Country ) ; // client country
ADD_INT ( q , m_aClients [ i ] . m_Score ) ; // client score
ADD_INT ( q , GameServer ( ) - > IsClientPlayer ( i ) ? 1 : 0 ) ; // is player?
2017-03-29 10:56:13 +00:00
if ( Type = = SERVERINFO_EXTENDED )
2020-10-27 17:57:14 +00:00
q . AddString ( " " , 0 ) ; // extra info, reserved
2013-12-31 05:13:57 +00:00
2017-03-29 10:56:13 +00:00
if ( Type = = SERVERINFO_EXTENDED )
{
2020-10-27 17:57:14 +00:00
if ( q . Size ( ) > = NET_MAX_PAYLOAD - 18 ) // 8 bytes for type, 10 bytes for the largest token
2017-03-29 10:56:13 +00:00
{
// Retry current player.
i - - ;
2019-11-02 23:33:30 +00:00
SAVE ( PreviousSize ) ;
2017-03-29 10:56:13 +00:00
RESET ( ) ;
2020-10-27 17:57:14 +00:00
ADD_INT ( q , ChunksStored ) ;
q . AddString ( " " , 0 ) ; // extra info, reserved
2017-03-29 10:56:13 +00:00
continue ;
}
}
2019-11-03 14:39:32 +00:00
PlayersStored + + ;
2010-05-29 07:25:38 +00:00
}
}
2011-04-13 18:37:12 +00:00
2020-10-27 17:57:14 +00:00
SAVE ( q . Size ( ) ) ;
2020-09-26 19:41:58 +00:00
# undef SAVE
# undef RESET
# undef ADD_RAW
# undef ADD_INT
2010-05-29 07:25:38 +00:00
}
2020-06-16 12:41:30 +00:00
void CServer : : CacheServerInfoSixup ( CCache * pCache , bool SendClients )
{
pCache - > Clear ( ) ;
CPacker Packer ;
Packer . Reset ( ) ;
// Could be moved to a separate function and cached
// count the players
int PlayerCount = 0 , ClientCount = 0 ;
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
{
if ( m_aClients [ i ] . m_State ! = CClient : : STATE_EMPTY )
{
if ( GameServer ( ) - > IsClientPlayer ( i ) )
PlayerCount + + ;
ClientCount + + ;
}
}
2020-06-17 07:32:28 +00:00
char aVersion [ 32 ] ;
2020-06-23 15:58:31 +00:00
str_format ( aVersion , sizeof ( aVersion ) , " 0.7↔%s " , GameServer ( ) - > Version ( ) ) ;
2020-06-17 07:32:28 +00:00
Packer . AddString ( aVersion , 32 ) ;
2021-12-14 23:28:51 +00:00
Packer . AddString ( Config ( ) - > m_SvName , 64 ) ;
Packer . AddString ( Config ( ) - > m_SvHostname , 128 ) ;
2020-06-16 12:41:30 +00:00
Packer . AddString ( GetMapName ( ) , 32 ) ;
// gametype
Packer . AddString ( GameServer ( ) - > GameType ( ) , 16 ) ;
// flags
int Flags = SERVER_FLAG_TIMESCORE ;
2021-12-14 23:28:51 +00:00
if ( Config ( ) - > m_Password [ 0 ] ) // password set
2020-06-16 12:41:30 +00:00
Flags | = SERVER_FLAG_PASSWORD ;
Packer . AddInt ( Flags ) ;
int MaxClients = m_NetServer . MaxClients ( ) ;
2021-12-14 23:28:51 +00:00
Packer . AddInt ( Config ( ) - > m_SvSkillLevel ) ; // server skill level
2020-06-16 12:41:30 +00:00
Packer . AddInt ( PlayerCount ) ; // num players
2021-12-14 23:28:51 +00:00
Packer . AddInt ( maximum ( MaxClients - maximum ( Config ( ) - > m_SvSpectatorSlots , Config ( ) - > m_SvReservedSlots ) , PlayerCount ) ) ; // max players
2020-06-16 12:41:30 +00:00
Packer . AddInt ( ClientCount ) ; // num clients
2021-12-14 23:28:51 +00:00
Packer . AddInt ( maximum ( MaxClients - Config ( ) - > m_SvReservedSlots , ClientCount ) ) ; // max clients
2020-06-16 12:41:30 +00:00
if ( SendClients )
{
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
{
if ( m_aClients [ i ] . m_State ! = CClient : : STATE_EMPTY )
{
Packer . AddString ( ClientName ( i ) , MAX_NAME_LENGTH ) ; // client name
Packer . AddString ( ClientClan ( i ) , MAX_CLAN_LENGTH ) ; // client clan
Packer . AddInt ( m_aClients [ i ] . m_Country ) ; // client country
2020-06-20 08:53:44 +00:00
Packer . AddInt ( m_aClients [ i ] . m_Score = = - 9999 ? - 1 : - m_aClients [ i ] . m_Score ) ; // client score
2020-09-26 19:41:58 +00:00
Packer . AddInt ( GameServer ( ) - > IsClientPlayer ( i ) ? 0 : 1 ) ; // flag spectator=1, bot=2 (player=0)
2020-06-16 12:41:30 +00:00
}
}
}
pCache - > AddChunk ( Packer . Data ( ) , Packer . Size ( ) ) ;
}
2019-11-02 23:33:30 +00:00
void CServer : : SendServerInfo ( const NETADDR * pAddr , int Token , int Type , bool SendClients )
2010-05-29 07:25:38 +00:00
{
2019-11-02 23:33:30 +00:00
CPacker p ;
char aBuf [ 128 ] ;
p . Reset ( ) ;
2020-10-27 17:57:14 +00:00
CCache * pCache = & m_aServerInfoCache [ GetCacheIndex ( Type , SendClients ) ] ;
2019-11-02 23:33:30 +00:00
2020-09-26 19:41:58 +00:00
# define ADD_RAW(p, x) (p).AddRaw(x, sizeof(x))
# define ADD_INT(p, x) \
do \
{ \
str_format ( aBuf , sizeof ( aBuf ) , " %d " , x ) ; \
( p ) . AddString ( aBuf , 0 ) ; \
} while ( 0 )
2019-11-02 23:33:30 +00:00
CNetChunk Packet ;
Packet . m_ClientID = - 1 ;
Packet . m_Address = * pAddr ;
Packet . m_Flags = NETSENDFLAG_CONNLESS ;
2020-10-27 17:57:14 +00:00
for ( const auto & Chunk : pCache - > m_Cache )
2019-11-02 23:33:30 +00:00
{
p . Reset ( ) ;
if ( Type = = SERVERINFO_EXTENDED )
{
2020-10-27 17:57:14 +00:00
if ( & Chunk = = & pCache - > m_Cache . front ( ) )
2020-07-12 22:14:54 +00:00
p . AddRaw ( SERVERBROWSE_INFO_EXTENDED , sizeof ( SERVERBROWSE_INFO_EXTENDED ) ) ;
else
p . AddRaw ( SERVERBROWSE_INFO_EXTENDED_MORE , sizeof ( SERVERBROWSE_INFO_EXTENDED_MORE ) ) ;
2019-11-02 23:33:30 +00:00
ADD_INT ( p , Token ) ;
}
else if ( Type = = SERVERINFO_64_LEGACY )
2014-01-14 19:40:29 +00:00
{
2020-07-12 22:14:54 +00:00
ADD_RAW ( p , SERVERBROWSE_INFO_64_LEGACY ) ;
ADD_INT ( p , Token ) ;
}
2020-09-26 19:41:58 +00:00
else if ( Type = = SERVERINFO_VANILLA | | Type = = SERVERINFO_INGAME )
2020-07-12 22:14:54 +00:00
{
ADD_RAW ( p , SERVERBROWSE_INFO ) ;
ADD_INT ( p , Token ) ;
}
else
{
dbg_assert ( false , " unknown serverinfo type " ) ;
2014-01-14 19:40:29 +00:00
}
2019-11-02 23:33:30 +00:00
2019-11-03 17:31:05 +00:00
p . AddRaw ( Chunk . m_aData , Chunk . m_DataSize ) ;
2019-11-02 23:33:30 +00:00
Packet . m_pData = p . Data ( ) ;
Packet . m_DataSize = p . Size ( ) ;
m_NetServer . Send ( & Packet ) ;
2010-05-29 07:25:38 +00:00
}
}
2020-06-16 12:41:30 +00:00
void CServer : : GetServerInfoSixup ( CPacker * pPacker , int Token , bool SendClients )
{
if ( Token ! = - 1 )
{
pPacker - > Reset ( ) ;
pPacker - > AddRaw ( SERVERBROWSE_INFO , sizeof ( SERVERBROWSE_INFO ) ) ;
pPacker - > AddInt ( Token ) ;
}
SendClients = SendClients & & Token ! = - 1 ;
2020-10-27 17:57:14 +00:00
CCache : : CCacheChunk & FirstChunk = m_aSixupServerInfoCache [ SendClients ] . m_Cache . front ( ) ;
2020-06-16 12:41:30 +00:00
pPacker - > AddRaw ( FirstChunk . m_aData , FirstChunk . m_DataSize ) ;
}
2019-11-03 00:07:10 +00:00
void CServer : : ExpireServerInfo ( )
2010-05-29 07:25:38 +00:00
{
2019-11-03 00:07:10 +00:00
m_ServerInfoNeedsUpdate = true ;
}
void CServer : : UpdateServerInfo ( bool Resend )
{
2020-07-07 08:23:04 +00:00
if ( m_RunServer = = UNINITIALIZED )
return ;
2019-11-03 00:07:10 +00:00
for ( int i = 0 ; i < 3 ; i + + )
for ( int j = 0 ; j < 2 ; j + + )
2020-10-27 17:57:14 +00:00
CacheServerInfo ( & m_aServerInfoCache [ i * 2 + j ] , i , j ) ;
2019-11-03 00:07:10 +00:00
2020-06-16 12:41:30 +00:00
for ( int i = 0 ; i < 2 ; i + + )
2020-10-27 17:57:14 +00:00
CacheServerInfoSixup ( & m_aSixupServerInfoCache [ i ] , i ) ;
2020-06-16 12:41:30 +00:00
2019-11-03 00:07:10 +00:00
if ( Resend )
2010-05-29 07:25:38 +00:00
{
2019-11-03 00:07:10 +00:00
for ( int i = 0 ; i < MAX_CLIENTS ; + + i )
2014-01-14 19:40:29 +00:00
{
2019-11-03 00:07:10 +00:00
if ( m_aClients [ i ] . m_State ! = CClient : : STATE_EMPTY )
{
2020-06-16 12:41:30 +00:00
if ( ! IsSixup ( i ) )
SendServerInfo ( m_NetServer . ClientAddr ( i ) , - 1 , SERVERINFO_INGAME , false ) ;
else
{
CMsgPacker Msg ( 4 , true , true ) ; //NETMSG_SERVERINFO //TODO: Import the shared protocol from 7 aswell
GetServerInfoSixup ( & Msg , - 1 , false ) ;
2020-09-26 19:41:58 +00:00
SendMsg ( & Msg , MSGFLAG_VITAL | MSGFLAG_FLUSH , i ) ;
2020-06-16 12:41:30 +00:00
}
2019-11-03 00:07:10 +00:00
}
2014-01-14 19:40:29 +00:00
}
2010-05-29 07:25:38 +00:00
}
2019-11-03 00:07:10 +00:00
m_ServerInfoNeedsUpdate = false ;
}
2010-05-29 07:25:38 +00:00
2020-09-13 21:23:50 +00:00
void CServer : : PumpNetwork ( bool PacketWaiting )
2010-05-29 07:25:38 +00:00
{
CNetChunk Packet ;
2020-06-16 12:41:30 +00:00
SECURITY_TOKEN ResponseToken ;
2010-05-29 07:25:38 +00:00
m_NetServer . Update ( ) ;
2011-04-13 18:37:12 +00:00
2020-09-13 21:23:50 +00:00
if ( PacketWaiting )
2010-05-29 07:25:38 +00:00
{
2020-09-13 21:23:50 +00:00
// process packets
while ( m_NetServer . Recv ( & Packet , & ResponseToken ) )
2010-05-29 07:25:38 +00:00
{
2020-09-13 21:23:50 +00:00
if ( Packet . m_ClientID = = - 1 )
2020-06-16 12:41:30 +00:00
{
2020-09-13 21:23:50 +00:00
// stateless
if ( ! ( Packet . m_Flags & NETSENDFLAG_CONNLESS ) )
{
m_RegSixup . FeedToken ( Packet . m_Address , ResponseToken ) ;
continue ;
}
2020-06-16 12:41:30 +00:00
2021-12-14 23:28:51 +00:00
if ( ResponseToken ! = NET_SECURITY_TOKEN_UNKNOWN & & Config ( ) - > m_SvSixup & &
2020-09-13 21:23:50 +00:00
m_RegSixup . RegisterProcessPacket ( & Packet , ResponseToken ) )
continue ;
if ( ResponseToken = = NET_SECURITY_TOKEN_UNKNOWN & & m_Register . RegisterProcessPacket ( & Packet ) )
continue ;
2020-06-16 12:41:30 +00:00
2010-05-29 07:25:38 +00:00
{
2020-09-13 21:23:50 +00:00
int ExtraToken = 0 ;
int Type = - 1 ;
if ( Packet . m_DataSize > = ( int ) sizeof ( SERVERBROWSE_GETINFO ) + 1 & &
mem_comp ( Packet . m_pData , SERVERBROWSE_GETINFO , sizeof ( SERVERBROWSE_GETINFO ) ) = = 0 )
2017-03-29 10:56:13 +00:00
{
2020-09-13 21:23:50 +00:00
if ( Packet . m_Flags & NETSENDFLAG_EXTENDED )
{
Type = SERVERINFO_EXTENDED ;
ExtraToken = ( Packet . m_aExtraData [ 0 ] < < 8 ) | Packet . m_aExtraData [ 1 ] ;
}
else
Type = SERVERINFO_VANILLA ;
2017-03-29 10:56:13 +00:00
}
2020-09-13 21:23:50 +00:00
else if ( Packet . m_DataSize > = ( int ) sizeof ( SERVERBROWSE_GETINFO_64_LEGACY ) + 1 & &
mem_comp ( Packet . m_pData , SERVERBROWSE_GETINFO_64_LEGACY , sizeof ( SERVERBROWSE_GETINFO_64_LEGACY ) ) = = 0 )
{
Type = SERVERINFO_64_LEGACY ;
}
2021-12-14 23:28:51 +00:00
if ( Type = = SERVERINFO_VANILLA & & ResponseToken ! = NET_SECURITY_TOKEN_UNKNOWN & & Config ( ) - > m_SvSixup )
2020-09-13 21:23:50 +00:00
{
CUnpacker Unpacker ;
Unpacker . Reset ( ( unsigned char * ) Packet . m_pData + sizeof ( SERVERBROWSE_GETINFO ) , Packet . m_DataSize - sizeof ( SERVERBROWSE_GETINFO ) ) ;
int SrvBrwsToken = Unpacker . GetInt ( ) ;
if ( Unpacker . Error ( ) )
continue ;
2020-06-16 12:41:30 +00:00
2020-09-13 21:23:50 +00:00
CPacker Packer ;
CNetChunk Response ;
2020-06-16 12:41:30 +00:00
2020-09-13 21:23:50 +00:00
GetServerInfoSixup ( & Packer , SrvBrwsToken , RateLimitServerInfoConnless ( ) ) ;
2020-06-16 12:41:30 +00:00
2020-09-13 21:23:50 +00:00
Response . m_ClientID = - 1 ;
Response . m_Address = Packet . m_Address ;
Response . m_Flags = NETSENDFLAG_CONNLESS ;
Response . m_pData = Packer . Data ( ) ;
Response . m_DataSize = Packer . Size ( ) ;
m_NetServer . SendConnlessSixup ( & Response , ResponseToken ) ;
}
else if ( Type ! = - 1 )
{
int Token = ( ( unsigned char * ) Packet . m_pData ) [ sizeof ( SERVERBROWSE_GETINFO ) ] ;
Token | = ExtraToken < < 8 ;
SendServerInfoConnless ( & Packet . m_Address , Token , Type ) ;
}
2013-12-31 05:13:57 +00:00
}
2010-05-29 07:25:38 +00:00
}
2020-09-13 21:23:50 +00:00
else
{
2021-06-24 18:32:41 +00:00
int GameFlags = 0 ;
if ( Packet . m_Flags & NET_CHUNKFLAG_VITAL )
{
GameFlags | = MSGFLAG_VITAL ;
}
if ( Antibot ( ) - > OnEngineClientMessage ( Packet . m_ClientID , Packet . m_pData , Packet . m_DataSize , GameFlags ) )
{
continue ;
}
2020-09-13 21:23:50 +00:00
ProcessClientPacket ( & Packet ) ;
}
2017-09-13 20:35:09 +00:00
}
2010-05-29 07:25:38 +00:00
}
2021-06-24 18:32:41 +00:00
{
unsigned char aBuffer [ NET_MAX_PAYLOAD ] ;
int Flags ;
CNetChunk Packet ;
mem_zero ( & Packet , sizeof ( Packet ) ) ;
Packet . m_pData = aBuffer ;
while ( Antibot ( ) - > OnEngineSimulateClientMessage ( & Packet . m_ClientID , aBuffer , sizeof ( aBuffer ) , & Packet . m_DataSize , & Flags ) )
{
Packet . m_Flags = 0 ;
if ( Flags & MSGFLAG_VITAL )
{
Packet . m_Flags | = NET_CHUNKFLAG_VITAL ;
}
ProcessClientPacket ( & Packet ) ;
}
}
2012-04-13 23:30:18 +00:00
2011-12-29 22:36:53 +00:00
m_ServerBan . Update ( ) ;
2011-07-30 11:40:01 +00:00
m_Econ . Update ( ) ;
2010-05-29 07:25:38 +00:00
}
2021-12-14 23:26:15 +00:00
const char * CServer : : GetMapName ( ) const
2010-10-10 13:36:58 +00:00
{
// get the name of the map without his path
2021-12-14 23:28:51 +00:00
const char * pMapShortName = & Config ( ) - > m_SvMap [ 0 ] ;
for ( int i = 0 ; i < str_length ( Config ( ) - > m_SvMap ) - 1 ; i + + )
2010-10-10 13:36:58 +00:00
{
2021-12-14 23:28:51 +00:00
if ( Config ( ) - > m_SvMap [ i ] = = ' / ' | | Config ( ) - > m_SvMap [ i ] = = ' \\ ' )
pMapShortName = & Config ( ) - > m_SvMap [ i + 1 ] ;
2010-10-10 13:36:58 +00:00
}
return pMapShortName ;
}
2020-04-23 19:34:55 +00:00
void CServer : : ChangeMap ( const char * pMap )
{
str_copy ( Config ( ) - > m_SvMap , pMap , sizeof ( Config ( ) - > m_SvMap ) ) ;
m_MapReload = str_comp ( Config ( ) - > m_SvMap , m_aCurrentMap ) ! = 0 ;
}
2010-05-29 07:25:38 +00:00
int CServer : : LoadMap ( const char * pMapName )
{
2021-12-21 11:23:17 +00:00
char aBuf [ IO_MAX_PATH_LENGTH ] ;
2010-05-29 07:25:38 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " maps/%s.map " , pMapName ) ;
2015-07-14 20:08:29 +00:00
GameServer ( ) - > OnMapChange ( aBuf , sizeof ( aBuf ) ) ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
if ( ! m_pMap - > Load ( aBuf ) )
return 0 ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
// stop recording when we change map
2020-09-26 19:41:58 +00:00
for ( int i = 0 ; i < MAX_CLIENTS + 1 ; i + + )
2014-09-26 00:05:22 +00:00
{
2019-01-14 21:13:49 +00:00
if ( ! m_aDemoRecorder [ i ] . IsRecording ( ) )
continue ;
2014-09-26 00:05:22 +00:00
m_aDemoRecorder [ i ] . Stop ( ) ;
// remove tmp demos
if ( i < MAX_CLIENTS )
{
char aPath [ 256 ] ;
2020-08-27 16:54:44 +00:00
str_format ( aPath , sizeof ( aPath ) , " demos/%s_%d_%d_tmp.demo " , m_aCurrentMap , m_NetServer . Address ( ) . port , i ) ;
2014-09-26 00:05:22 +00:00
Storage ( ) - > RemoveFile ( aPath , IStorage : : TYPE_SAVE ) ;
}
}
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
// reinit snapshot ids
m_IDPool . TimeoutIDs ( ) ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
// get the crc of the map
2020-06-19 21:52:13 +00:00
m_aCurrentMapSha256 [ SIX ] = m_pMap - > Sha256 ( ) ;
m_aCurrentMapCrc [ SIX ] = m_pMap - > Crc ( ) ;
2010-08-17 22:06:00 +00:00
char aBufMsg [ 256 ] ;
2018-06-05 19:22:40 +00:00
char aSha256 [ SHA256_MAXSTRSIZE ] ;
2020-06-19 21:52:13 +00:00
sha256_str ( m_aCurrentMapSha256 [ SIX ] , aSha256 , sizeof ( aSha256 ) ) ;
2018-06-05 19:22:40 +00:00
str_format ( aBufMsg , sizeof ( aBufMsg ) , " %s sha256 is %s " , aBuf , aSha256 ) ;
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_ADDINFO , " server " , aBufMsg ) ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
str_copy ( m_aCurrentMap , pMapName , sizeof ( m_aCurrentMap ) ) ;
2011-04-13 18:37:12 +00:00
2011-08-02 10:14:11 +00:00
// load complete map into memory for download
2010-05-29 07:25:38 +00:00
{
2010-10-06 21:07:35 +00:00
IOHANDLE File = Storage ( ) - > OpenFile ( aBuf , IOFLAG_READ , IStorage : : TYPE_ALL ) ;
2020-06-19 21:52:13 +00:00
m_aCurrentMapSize [ SIX ] = ( unsigned int ) io_length ( File ) ;
free ( m_apCurrentMapData [ SIX ] ) ;
m_apCurrentMapData [ SIX ] = ( unsigned char * ) malloc ( m_aCurrentMapSize [ SIX ] ) ;
io_read ( File , m_apCurrentMapData [ SIX ] , m_aCurrentMapSize [ SIX ] ) ;
2010-05-29 07:25:38 +00:00
io_close ( File ) ;
}
2011-01-20 20:25:09 +00:00
2020-06-19 21:52:13 +00:00
// load sixup version of the map
2021-12-14 23:28:51 +00:00
if ( Config ( ) - > m_SvSixup )
2020-06-19 21:52:13 +00:00
{
str_format ( aBuf , sizeof ( aBuf ) , " maps7/%s.map " , pMapName ) ;
IOHANDLE File = Storage ( ) - > OpenFile ( aBuf , IOFLAG_READ , IStorage : : TYPE_ALL ) ;
if ( ! File )
{
2021-12-14 23:28:51 +00:00
Config ( ) - > m_SvSixup = 0 ;
2021-12-21 11:23:17 +00:00
str_format ( aBufMsg , sizeof ( aBufMsg ) , " couldn't load map %s " , aBuf ) ;
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_ADDINFO , " sixup " , aBufMsg ) ;
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_ADDINFO , " sixup " , " disabling 0.7 compatibility " ) ;
2020-06-19 21:52:13 +00:00
}
else
{
m_aCurrentMapSize [ SIXUP ] = ( unsigned int ) io_length ( File ) ;
free ( m_apCurrentMapData [ SIXUP ] ) ;
m_apCurrentMapData [ SIXUP ] = ( unsigned char * ) malloc ( m_aCurrentMapSize [ SIXUP ] ) ;
io_read ( File , m_apCurrentMapData [ SIXUP ] , m_aCurrentMapSize [ SIXUP ] ) ;
io_close ( File ) ;
m_aCurrentMapSha256 [ SIXUP ] = sha256 ( m_apCurrentMapData [ SIXUP ] , m_aCurrentMapSize [ SIXUP ] ) ;
m_aCurrentMapCrc [ SIXUP ] = crc32 ( 0 , m_apCurrentMapData [ SIXUP ] , m_aCurrentMapSize [ SIXUP ] ) ;
sha256_str ( m_aCurrentMapSha256 [ SIXUP ] , aSha256 , sizeof ( aSha256 ) ) ;
str_format ( aBufMsg , sizeof ( aBufMsg ) , " %s sha256 is %s " , aBuf , aSha256 ) ;
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_ADDINFO , " sixup " , aBufMsg ) ;
}
}
2021-12-21 11:23:17 +00:00
if ( ! Config ( ) - > m_SvSixup & & m_apCurrentMapData [ SIXUP ] )
{
free ( m_apCurrentMapData [ SIXUP ] ) ;
m_apCurrentMapData [ SIXUP ] = 0 ;
}
2020-06-19 21:52:13 +00:00
2020-09-26 19:41:58 +00:00
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
2011-01-20 20:25:09 +00:00
m_aPrevStates [ i ] = m_aClients [ i ] . m_State ;
2010-05-29 07:25:38 +00:00
return 1 ;
}
2021-01-10 12:47:07 +00:00
void CServer : : InitRegister ( CNetServer * pNetServer , IEngineMasterServer * pMasterServer , CConfig * pConfig , IConsole * pConsole )
2010-05-29 07:25:38 +00:00
{
2021-01-10 12:47:07 +00:00
m_Register . Init ( pNetServer , pMasterServer , pConfig , pConsole ) ;
m_RegSixup . Init ( pNetServer , pMasterServer , pConfig , pConsole ) ;
2010-05-29 07:25:38 +00:00
}
int CServer : : Run ( )
{
2020-07-07 08:23:04 +00:00
if ( m_RunServer = = UNINITIALIZED )
m_RunServer = RUNNING ;
2017-03-02 15:16:29 +00:00
m_AuthManager . Init ( ) ;
2021-12-14 23:28:51 +00:00
if ( Config ( ) - > m_Debug )
2017-05-21 23:07:13 +00:00
{
g_UuidManager . DebugDump ( ) ;
}
2021-12-14 23:28:51 +00:00
m_PrintCBIndex = Console ( ) - > RegisterPrintCallback ( Config ( ) - > m_ConsoleOutputLevel , SendRconLineAuthed , this ) ;
2010-05-29 07:25:38 +00:00
2021-02-07 15:03:31 +00:00
{
int Size = GameServer ( ) - > PersistentClientDataSize ( ) ;
for ( auto & Client : m_aClients )
{
2021-04-21 07:45:58 +00:00
Client . m_HasPersistentData = false ;
2021-02-07 15:03:31 +00:00
Client . m_pPersistentData = malloc ( Size ) ;
}
}
2010-05-29 07:25:38 +00:00
// load map
2021-12-14 23:28:51 +00:00
if ( ! LoadMap ( Config ( ) - > m_SvMap ) )
2010-05-29 07:25:38 +00:00
{
2021-12-14 23:28:51 +00:00
dbg_msg ( " server " , " failed to load map. mapname='%s' " , Config ( ) - > m_SvMap ) ;
2010-05-29 07:25:38 +00:00
return - 1 ;
}
2011-04-13 18:37:12 +00:00
2021-12-14 23:28:51 +00:00
if ( Config ( ) - > m_SvSqliteFile [ 0 ] ! = ' \0 ' )
2020-07-07 17:29:44 +00:00
{
2021-11-28 12:33:47 +00:00
auto pSqliteConn = CreateSqliteConnection ( Config ( ) - > m_SvSqliteFile , true ) ;
2020-07-07 17:29:44 +00:00
2021-12-14 23:28:51 +00:00
if ( Config ( ) - > m_SvUseSQL )
2020-07-07 17:29:44 +00:00
{
2021-11-28 12:33:47 +00:00
DbPool ( ) - > RegisterDatabase ( std : : move ( pSqliteConn ) , CDbConnectionPool : : WRITE_BACKUP ) ;
2020-07-07 17:29:44 +00:00
}
else
{
2021-11-28 12:33:47 +00:00
auto pCopy = std : : unique_ptr < IDbConnection > ( pSqliteConn - > Copy ( ) ) ;
DbPool ( ) - > RegisterDatabase ( std : : move ( pSqliteConn ) , CDbConnectionPool : : READ ) ;
2020-07-07 17:29:44 +00:00
DbPool ( ) - > RegisterDatabase ( std : : move ( pCopy ) , CDbConnectionPool : : WRITE ) ;
}
}
2010-05-29 07:25:38 +00:00
// start server
NETADDR BindAddr ;
2021-12-14 23:28:51 +00:00
int NetType = Config ( ) - > m_SvIpv4Only ? NETTYPE_IPV4 : NETTYPE_ALL ;
2018-12-17 19:05:50 +00:00
2021-12-14 23:28:51 +00:00
if ( ! Config ( ) - > m_Bindaddr [ 0 ] | | net_host_lookup ( Config ( ) - > m_Bindaddr , & BindAddr , NetType ) ! = 0 )
2010-05-29 07:25:38 +00:00
mem_zero ( & BindAddr , sizeof ( BindAddr ) ) ;
2011-04-13 18:37:12 +00:00
2020-07-09 16:01:52 +00:00
BindAddr . type = NetType ;
2020-04-14 10:11:50 +00:00
2021-12-14 23:28:51 +00:00
int Port = Config ( ) - > m_SvPort ;
for ( BindAddr . port = Port ! = 0 ? Port : 8303 ; ! m_NetServer . Open ( BindAddr , & m_ServerBan , Config ( ) - > m_SvMaxClients , Config ( ) - > m_SvMaxClientsPerIP , 0 ) ; BindAddr . port + + )
2010-05-29 07:25:38 +00:00
{
2020-09-26 19:41:58 +00:00
if ( Port ! = 0 | | BindAddr . port > = 8310 )
2020-06-30 17:01:57 +00:00
{
2020-07-09 16:01:52 +00:00
dbg_msg ( " server " , " couldn't open socket. port %d might already be in use " , BindAddr . port ) ;
2020-06-30 17:01:57 +00:00
return - 1 ;
}
}
2020-07-09 16:01:52 +00:00
2020-09-26 19:41:58 +00:00
if ( Port = = 0 )
2020-07-09 16:01:52 +00:00
dbg_msg ( " server " , " using port %d " , BindAddr . port ) ;
# if defined(CONF_UPNP)
m_UPnP . Open ( BindAddr ) ;
# endif
2010-05-29 07:25:38 +00:00
2015-08-23 15:51:28 +00:00
m_NetServer . SetCallbacks ( NewClientCallback , NewClientNoAuthCallback , ClientRejoinCallback , DelClientCallback , this ) ;
2011-04-13 18:37:12 +00:00
2021-01-10 12:47:07 +00:00
m_Econ . Init ( Config ( ) , Console ( ) , & m_ServerBan ) ;
2011-07-02 06:36:14 +00:00
2016-05-02 21:36:21 +00:00
# if defined(CONF_FAMILY_UNIX)
2021-12-14 23:28:51 +00:00
m_Fifo . Init ( Console ( ) , Config ( ) - > m_SvInputFifo , CFGFLAG_SERVER ) ;
2016-05-02 21:36:21 +00:00
# endif
2010-08-17 22:06:00 +00:00
char aBuf [ 256 ] ;
2021-12-14 23:28:51 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " server name is '%s' " , Config ( ) - > m_SvName ) ;
2010-08-17 22:06:00 +00:00
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " server " , aBuf ) ;
2011-04-13 18:37:12 +00:00
2020-05-13 20:27:49 +00:00
Antibot ( ) - > Init ( ) ;
2010-05-29 07:25:38 +00:00
GameServer ( ) - > OnInit ( ) ;
2017-10-13 00:25:50 +00:00
if ( ErrorShutdown ( ) )
{
2020-07-07 08:23:04 +00:00
m_RunServer = STOPPING ;
2017-10-13 00:25:50 +00:00
}
2021-12-21 22:05:44 +00:00
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " server " , " version " GAME_RELEASE_VERSION " on " CONF_PLATFORM_STRING " " CONF_ARCH_STRING ) ;
if ( GIT_SHORTREV_HASH )
{
char aBuf [ 64 ] ;
str_format ( aBuf , sizeof ( aBuf ) , " git revision hash: %s " , GIT_SHORTREV_HASH ) ;
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " server " , aBuf ) ;
}
2010-05-29 07:25:38 +00:00
2010-08-07 18:22:25 +00:00
// process pending commands
2011-08-13 00:11:06 +00:00
m_pConsole - > StoreCommands ( false ) ;
2010-08-07 18:22:25 +00:00
2017-03-04 20:16:02 +00:00
if ( m_AuthManager . IsGenerated ( ) )
2015-06-21 17:46:55 +00:00
{
dbg_msg ( " server " , " +-------------------------+ " ) ;
2021-12-14 23:28:51 +00:00
dbg_msg ( " server " , " | rcon password: '%s' | " , Config ( ) - > m_SvRconPassword ) ;
2015-06-21 17:46:55 +00:00
dbg_msg ( " server " , " +-------------------------+ " ) ;
}
2010-05-29 07:25:38 +00:00
// start game
{
2014-11-24 21:31:13 +00:00
bool NonActive = false ;
2020-09-13 21:23:50 +00:00
bool PacketWaiting = false ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
m_GameStartTime = time_get ( ) ;
2011-04-13 18:37:12 +00:00
2019-11-03 00:07:10 +00:00
UpdateServerInfo ( ) ;
2020-07-07 08:23:04 +00:00
while ( m_RunServer < STOPPING )
2010-05-29 07:25:38 +00:00
{
2014-11-24 21:31:13 +00:00
if ( NonActive )
2020-09-13 21:23:50 +00:00
PumpNetwork ( PacketWaiting ) ;
2014-11-24 21:31:13 +00:00
2014-11-09 23:08:50 +00:00
set_new_tick ( ) ;
2014-11-24 21:31:13 +00:00
2021-06-23 05:05:49 +00:00
int64_t t = time_get ( ) ;
2010-05-29 07:25:38 +00:00
int NewTicks = 0 ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
// load new map TODO: don't poll this
2020-04-23 17:02:10 +00:00
if ( m_MapReload )
2010-05-29 07:25:38 +00:00
{
2020-04-23 17:02:10 +00:00
m_MapReload = false ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
// load map
2021-12-14 23:28:51 +00:00
if ( LoadMap ( Config ( ) - > m_SvMap ) )
2010-05-29 07:25:38 +00:00
{
// new map loaded
2021-02-07 15:03:31 +00:00
// ask the game to for the data it wants to persist past a map change
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
{
if ( m_aClients [ i ] . m_State = = CClient : : STATE_INGAME )
{
m_aClients [ i ] . m_HasPersistentData = GameServer ( ) - > OnClientDataPersist ( i , m_aClients [ i ] . m_pPersistentData ) ;
}
}
2010-05-29 07:25:38 +00:00
GameServer ( ) - > OnShutdown ( ) ;
2011-04-13 18:37:12 +00:00
2017-04-17 10:13:58 +00:00
for ( int ClientID = 0 ; ClientID < MAX_CLIENTS ; ClientID + + )
2010-05-29 07:25:38 +00:00
{
2017-04-17 10:13:58 +00:00
if ( m_aClients [ ClientID ] . m_State < = CClient : : STATE_AUTH )
2010-05-29 07:25:38 +00:00
continue ;
2011-04-13 18:37:12 +00:00
2017-04-17 10:13:58 +00:00
SendMap ( ClientID ) ;
2021-02-07 15:03:31 +00:00
bool HasPersistentData = m_aClients [ ClientID ] . m_HasPersistentData ;
2017-04-17 10:13:58 +00:00
m_aClients [ ClientID ] . Reset ( ) ;
2021-02-07 15:03:31 +00:00
m_aClients [ ClientID ] . m_HasPersistentData = HasPersistentData ;
2017-04-17 10:13:58 +00:00
m_aClients [ ClientID ] . m_State = CClient : : STATE_CONNECTING ;
2010-05-29 07:25:38 +00:00
}
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
m_GameStartTime = time_get ( ) ;
m_CurrentGameTick = 0 ;
2016-01-22 16:53:46 +00:00
m_ServerInfoFirstRequest = 0 ;
2010-05-29 07:25:38 +00:00
Kernel ( ) - > ReregisterInterface ( GameServer ( ) ) ;
GameServer ( ) - > OnInit ( ) ;
2017-10-13 00:25:50 +00:00
if ( ErrorShutdown ( ) )
{
break ;
}
2019-11-03 00:07:10 +00:00
UpdateServerInfo ( true ) ;
2010-05-29 07:25:38 +00:00
}
else
{
2021-12-14 23:28:51 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " failed to load map. mapname='%s' " , Config ( ) - > m_SvMap ) ;
2010-08-17 22:06:00 +00:00
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " server " , aBuf ) ;
2021-12-14 23:28:51 +00:00
str_copy ( Config ( ) - > m_SvMap , m_aCurrentMap , sizeof ( Config ( ) - > m_SvMap ) ) ;
2010-05-29 07:25:38 +00:00
}
}
2011-04-13 18:37:12 +00:00
2016-09-05 09:38:11 +00:00
// handle dnsbl
2021-12-14 23:28:51 +00:00
if ( Config ( ) - > m_SvDnsbl )
2016-09-05 09:38:11 +00:00
{
2020-09-26 19:41:58 +00:00
for ( int ClientID = 0 ; ClientID < MAX_CLIENTS ; ClientID + + )
2016-09-05 09:38:11 +00:00
{
2020-09-26 19:41:58 +00:00
if ( m_aClients [ ClientID ] . m_State = = CClient : : STATE_EMPTY )
2016-09-05 09:38:11 +00:00
continue ;
2020-09-26 19:41:58 +00:00
if ( m_aClients [ ClientID ] . m_DnsblState = = CClient : : DNSBL_STATE_NONE )
2016-09-05 09:38:11 +00:00
{
// initiate dnsbl lookup
2017-04-17 10:13:58 +00:00
InitDnsbl ( ClientID ) ;
2016-09-05 09:38:11 +00:00
}
2020-09-26 19:41:58 +00:00
else if ( m_aClients [ ClientID ] . m_DnsblState = = CClient : : DNSBL_STATE_PENDING & &
m_aClients [ ClientID ] . m_pDnsblLookup - > Status ( ) = = IJob : : STATE_DONE )
2016-09-05 09:38:11 +00:00
{
2020-09-26 19:41:58 +00:00
if ( m_aClients [ ClientID ] . m_pDnsblLookup - > m_Result ! = 0 )
2016-09-05 09:38:11 +00:00
{
// entry not found -> whitelisted
2017-04-17 10:13:58 +00:00
m_aClients [ ClientID ] . m_DnsblState = CClient : : DNSBL_STATE_WHITELISTED ;
2016-09-05 09:38:11 +00:00
}
else
{
// entry found -> blacklisted
2017-04-17 10:13:58 +00:00
m_aClients [ ClientID ] . m_DnsblState = CClient : : DNSBL_STATE_BLACKLISTED ;
2016-09-05 09:38:11 +00:00
// console output
char aAddrStr [ NETADDR_MAXSTRSIZE ] ;
2017-04-17 10:13:58 +00:00
net_addr_str ( m_NetServer . ClientAddr ( ClientID ) , aAddrStr , sizeof ( aAddrStr ) , true ) ;
2016-09-05 09:38:11 +00:00
char aBuf [ 256 ] ;
2017-04-17 10:13:58 +00:00
2020-09-26 19:41:58 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " ClientID=%d addr=<{%s}> secure=%s blacklisted " , ClientID , aAddrStr , m_NetServer . HasSecurityToken ( ClientID ) ? " yes " : " no " ) ;
2018-10-07 22:59:07 +00:00
2016-09-05 09:38:11 +00:00
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_ADDINFO , " dnsbl " , aBuf ) ;
}
}
2020-09-26 19:41:58 +00:00
if ( m_aClients [ ClientID ] . m_DnsblState = = CClient : : DNSBL_STATE_BLACKLISTED & &
2021-12-14 23:28:51 +00:00
Config ( ) - > m_SvDnsblBan )
2020-09-26 19:41:58 +00:00
m_NetServer . NetBan ( ) - > BanAddr ( m_NetServer . ClientAddr ( ClientID ) , 60 * 10 , " VPN detected, try connecting without. Contact admin if mistaken " ) ;
2016-09-05 09:38:11 +00:00
}
}
2020-09-26 19:41:58 +00:00
while ( t > TickStartTime ( m_CurrentGameTick + 1 ) )
2010-05-29 07:25:38 +00:00
{
2021-09-14 20:11:22 +00:00
GameServer ( ) - > OnPreTickTeehistorian ( ) ;
2019-01-29 19:32:11 +00:00
for ( int c = 0 ; c < MAX_CLIENTS ; c + + )
if ( m_aClients [ c ] . m_State = = CClient : : STATE_INGAME )
2020-10-26 14:14:07 +00:00
for ( auto & Input : m_aClients [ c ] . m_aInputs )
if ( Input . m_GameTick = = Tick ( ) + 1 )
GameServer ( ) - > OnClientPredictedEarlyInput ( c , Input . m_aData ) ;
2019-01-29 19:32:11 +00:00
2010-05-29 07:25:38 +00:00
m_CurrentGameTick + + ;
NewTicks + + ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
// apply new input
for ( int c = 0 ; c < MAX_CLIENTS ; c + + )
{
2014-01-15 15:52:22 +00:00
if ( m_aClients [ c ] . m_State ! = CClient : : STATE_INGAME )
2010-05-29 07:25:38 +00:00
continue ;
2020-10-26 14:14:07 +00:00
for ( auto & Input : m_aClients [ c ] . m_aInputs )
2010-05-29 07:25:38 +00:00
{
2020-10-26 14:14:07 +00:00
if ( Input . m_GameTick = = Tick ( ) )
2010-05-29 07:25:38 +00:00
{
2020-10-26 14:14:07 +00:00
GameServer ( ) - > OnClientPredictedInput ( c , Input . m_aData ) ;
2010-05-29 07:25:38 +00:00
break ;
}
}
}
GameServer ( ) - > OnTick ( ) ;
2017-10-13 00:25:50 +00:00
if ( ErrorShutdown ( ) )
{
break ;
}
2010-05-29 07:25:38 +00:00
}
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
// snap game
if ( NewTicks )
{
2021-12-14 23:28:51 +00:00
if ( Config ( ) - > m_SvHighBandwidth | | ( m_CurrentGameTick % 2 ) = = 0 )
2010-05-29 07:25:38 +00:00
DoSnapshot ( ) ;
2011-07-14 20:07:21 +00:00
UpdateClientRconCommands ( ) ;
2018-12-17 19:05:50 +00:00
# if defined(CONF_FAMILY_UNIX)
2018-12-20 08:17:31 +00:00
m_Fifo . Update ( ) ;
2018-12-17 19:05:50 +00:00
# endif
2010-05-29 07:25:38 +00:00
}
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
// master server stuff
2011-07-06 23:48:00 +00:00
m_Register . RegisterUpdate ( m_NetServer . NetType ( ) ) ;
2021-12-14 23:28:51 +00:00
if ( Config ( ) - > m_SvSixup )
2020-06-19 19:08:16 +00:00
m_RegSixup . RegisterUpdate ( m_NetServer . NetType ( ) ) ;
2011-04-13 18:37:12 +00:00
2019-11-03 00:07:10 +00:00
if ( m_ServerInfoNeedsUpdate )
UpdateServerInfo ( ) ;
2019-11-02 23:33:30 +00:00
2020-05-15 22:39:17 +00:00
Antibot ( ) - > OnEngineTick ( ) ;
2014-11-24 21:31:13 +00:00
if ( ! NonActive )
2020-09-13 21:23:50 +00:00
PumpNetwork ( PacketWaiting ) ;
2011-04-13 18:37:12 +00:00
2014-11-24 21:31:13 +00:00
NonActive = true ;
2014-01-15 15:52:22 +00:00
2020-10-26 14:14:07 +00:00
for ( auto & Client : m_aClients )
if ( Client . m_State ! = CClient : : STATE_EMPTY )
2014-01-15 15:52:22 +00:00
NonActive = false ;
2014-01-14 23:02:19 +00:00
// wait for incoming data
2020-09-26 19:41:58 +00:00
if ( NonActive )
2014-08-15 12:32:21 +00:00
{
2021-12-14 23:28:51 +00:00
if ( Config ( ) - > m_SvReloadWhenEmpty = = 1 )
2015-10-22 15:51:02 +00:00
{
2015-10-22 15:27:30 +00:00
m_MapReload = true ;
2021-12-14 23:28:51 +00:00
Config ( ) - > m_SvReloadWhenEmpty = 0 ;
2015-10-22 15:51:02 +00:00
}
2021-12-14 23:28:51 +00:00
else if ( Config ( ) - > m_SvReloadWhenEmpty = = 2 & & ! m_ReloadedWhenEmpty )
2015-10-22 15:51:02 +00:00
{
2015-10-22 15:27:30 +00:00
m_MapReload = true ;
m_ReloadedWhenEmpty = true ;
}
2021-12-14 23:28:51 +00:00
if ( Config ( ) - > m_SvShutdownWhenEmpty )
2020-07-07 08:23:04 +00:00
m_RunServer = STOPPING ;
2014-08-15 12:32:21 +00:00
else
2020-09-13 21:23:50 +00:00
PacketWaiting = net_socket_read_wait ( m_NetServer . Socket ( ) , 1000000 ) ;
2014-08-15 12:32:21 +00:00
}
2014-01-15 15:52:22 +00:00
else
2014-11-11 12:00:02 +00:00
{
2015-10-22 15:27:30 +00:00
m_ReloadedWhenEmpty = false ;
2014-11-11 12:00:02 +00:00
set_new_tick ( ) ;
2021-06-23 05:05:49 +00:00
int64_t t = time_get ( ) ;
2020-09-26 19:41:58 +00:00
int x = ( TickStartTime ( m_CurrentGameTick + 1 ) - t ) * 1000000 / time_freq ( ) + 1 ;
2014-11-15 17:14:20 +00:00
2020-09-13 21:23:50 +00:00
PacketWaiting = x > 0 ? net_socket_read_wait ( m_NetServer . Socket ( ) , x ) : true ;
2014-11-11 12:00:02 +00:00
}
2010-05-29 07:25:38 +00:00
}
}
2017-10-13 00:25:50 +00:00
const char * pDisconnectReason = " Server shutdown " ;
2021-12-08 17:41:16 +00:00
if ( m_aShutdownReason [ 0 ] )
pDisconnectReason = m_aShutdownReason ;
2017-10-13 00:25:50 +00:00
if ( ErrorShutdown ( ) )
{
2020-06-18 18:43:19 +00:00
dbg_msg ( " server " , " shutdown from game server (%s) " , m_aErrorShutdownReason ) ;
2017-10-13 00:25:50 +00:00
pDisconnectReason = m_aErrorShutdownReason ;
}
2010-05-29 07:25:38 +00:00
// disconnect all clients on shutdown
for ( int i = 0 ; i < MAX_CLIENTS ; + + i )
{
if ( m_aClients [ i ] . m_State ! = CClient : : STATE_EMPTY )
2017-10-13 00:25:50 +00:00
m_NetServer . Drop ( i , pDisconnectReason ) ;
2010-05-29 07:25:38 +00:00
}
2016-05-02 21:36:21 +00:00
m_Econ . Shutdown ( ) ;
# if defined(CONF_FAMILY_UNIX)
m_Fifo . Shutdown ( ) ;
# endif
2020-07-04 17:53:27 +00:00
GameServer ( ) - > OnShutdown ( ) ;
2010-05-29 07:25:38 +00:00
m_pMap - > Unload ( ) ;
2020-07-04 17:53:27 +00:00
DbPool ( ) - > OnShutdown ( ) ;
2015-11-23 21:49:18 +00:00
2020-09-26 19:41:58 +00:00
# if defined(CONF_UPNP)
2020-04-19 13:14:21 +00:00
m_UPnP . Shutdown ( ) ;
# endif
2015-11-23 21:49:18 +00:00
2021-03-09 10:44:19 +00:00
for ( auto & Client : m_aClients )
{
free ( Client . m_pPersistentData ) ;
}
2017-10-13 00:25:50 +00:00
return ErrorShutdown ( ) ;
2010-05-29 07:25:38 +00:00
}
2020-10-17 15:29:33 +00:00
void CServer : : ConTestingCommands ( CConsole : : IResult * pResult , void * pUser )
{
2021-12-14 23:28:51 +00:00
CConsole * pThis = static_cast < CConsole * > ( pUser ) ;
2020-10-17 15:29:33 +00:00
char aBuf [ 128 ] ;
2021-12-14 23:28:51 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " Value: %d " , pThis - > Config ( ) - > m_SvTestingCommands ) ;
pThis - > Print ( CConsole : : OUTPUT_LEVEL_STANDARD , " console " , aBuf ) ;
2020-10-17 15:29:33 +00:00
}
void CServer : : ConRescue ( CConsole : : IResult * pResult , void * pUser )
{
2021-12-14 23:28:51 +00:00
CConsole * pThis = static_cast < CConsole * > ( pUser ) ;
2020-10-17 15:29:33 +00:00
char aBuf [ 128 ] ;
2021-12-14 23:28:51 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " Value: %d " , pThis - > Config ( ) - > m_SvRescue ) ;
pThis - > Print ( CConsole : : OUTPUT_LEVEL_STANDARD , " console " , aBuf ) ;
2020-10-17 15:29:33 +00:00
}
2011-08-13 00:11:06 +00:00
void CServer : : ConKick ( IConsole : : IResult * pResult , void * pUser )
2010-05-29 07:25:38 +00:00
{
2011-08-13 00:11:06 +00:00
if ( pResult - > NumArguments ( ) > 1 )
2010-10-09 18:19:58 +00:00
{
char aBuf [ 128 ] ;
2011-08-13 00:11:06 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " Kicked (%s) " , pResult - > GetString ( 1 ) ) ;
( ( CServer * ) pUser ) - > Kick ( pResult - > GetInteger ( 0 ) , aBuf ) ;
2010-10-09 18:19:58 +00:00
}
else
2011-08-13 00:11:06 +00:00
( ( CServer * ) pUser ) - > Kick ( pResult - > GetInteger ( 0 ) , " Kicked by console " ) ;
2010-05-29 07:25:38 +00:00
}
2019-04-03 13:07:05 +00:00
void CServer : : ConStatus ( IConsole : : IResult * pResult , void * pUser )
2010-05-29 07:25:38 +00:00
{
char aBuf [ 1024 ] ;
2011-03-28 18:11:28 +00:00
char aAddrStr [ NETADDR_MAXSTRSIZE ] ;
2017-03-21 10:24:44 +00:00
CServer * pThis = static_cast < CServer * > ( pUser ) ;
2020-01-24 00:55:09 +00:00
const char * pName = pResult - > NumArguments ( ) = = 1 ? pResult - > GetString ( 0 ) : " " ;
2010-05-29 07:25:38 +00:00
2011-12-29 22:36:53 +00:00
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
2010-05-29 07:25:38 +00:00
{
2019-04-03 13:07:05 +00:00
if ( pThis - > m_aClients [ i ] . m_State = = CClient : : STATE_EMPTY )
continue ;
2020-01-24 00:55:09 +00:00
if ( ! str_utf8_find_nocase ( pThis - > m_aClients [ i ] . m_aName , pName ) )
continue ;
2019-04-03 13:07:05 +00:00
net_addr_str ( pThis - > m_NetServer . ClientAddr ( i ) , aAddrStr , sizeof ( aAddrStr ) , true ) ;
if ( pThis - > m_aClients [ i ] . m_State = = CClient : : STATE_INGAME )
2010-05-29 07:25:38 +00:00
{
2019-04-03 13:07:05 +00:00
char aDnsblStr [ 64 ] ;
aDnsblStr [ 0 ] = ' \0 ' ;
2021-12-14 23:28:51 +00:00
if ( pThis - > Config ( ) - > m_SvDnsbl )
2019-04-03 13:07:05 +00:00
{
const char * pDnsblStr = pThis - > m_aClients [ i ] . m_DnsblState = = CClient : : DNSBL_STATE_WHITELISTED ? " white " :
2020-09-26 19:41:58 +00:00
pThis - > m_aClients [ i ] . m_DnsblState = = CClient : : DNSBL_STATE_BLACKLISTED ? " black " :
pThis - > m_aClients [ i ] . m_DnsblState = = CClient : : DNSBL_STATE_PENDING ? " pending " : " n/a " ;
2019-04-03 13:07:05 +00:00
str_format ( aDnsblStr , sizeof ( aDnsblStr ) , " dnsbl=%s " , pDnsblStr ) ;
}
char aAuthStr [ 128 ] ;
aAuthStr [ 0 ] = ' \0 ' ;
if ( pThis - > m_aClients [ i ] . m_AuthKey > = 0 )
2012-07-29 10:17:16 +00:00
{
2019-03-02 10:50:33 +00:00
const char * pAuthStr = pThis - > m_aClients [ i ] . m_Authed = = AUTHED_ADMIN ? " (Admin) " :
2020-09-26 19:41:58 +00:00
pThis - > m_aClients [ i ] . m_Authed = = AUTHED_MOD ? " (Mod) " :
pThis - > m_aClients [ i ] . m_Authed = = AUTHED_HELPER ? " (Helper) " : " " ;
2019-04-03 13:07:05 +00:00
str_format ( aAuthStr , sizeof ( aAuthStr ) , " key=%s %s " , pThis - > m_AuthManager . KeyIdent ( pThis - > m_aClients [ i ] . m_AuthKey ) , pAuthStr ) ;
2017-04-17 10:13:58 +00:00
}
2019-04-03 13:07:05 +00:00
2021-01-15 21:39:18 +00:00
const char * pClientPrefix = " " ;
2021-01-15 18:26:40 +00:00
if ( pThis - > m_aClients [ i ] . m_Sixup )
{
2021-01-15 21:39:18 +00:00
pClientPrefix = " 0.7: " ;
2021-01-15 18:26:40 +00:00
}
2021-01-15 21:39:18 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " id=%d addr=<{%s}> name='%s' client=%s%d secure=%s flags=%d%s%s " ,
i , aAddrStr , pThis - > m_aClients [ i ] . m_aName , pClientPrefix , pThis - > m_aClients [ i ] . m_DDNetVersion ,
2019-04-03 13:07:05 +00:00
pThis - > m_NetServer . HasSecurityToken ( i ) ? " yes " : " no " , pThis - > m_aClients [ i ] . m_Flags , aDnsblStr , aAuthStr ) ;
}
else
{
2019-04-04 17:16:10 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " id=%d addr=<{%s}> connecting " , i , aAddrStr ) ;
2010-05-29 07:25:38 +00:00
}
2019-04-29 23:01:43 +00:00
pThis - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " server " , aBuf ) ;
2010-05-29 07:25:38 +00:00
}
}
2017-03-02 15:16:29 +00:00
static int GetAuthLevel ( const char * pLevel )
{
int Level = - 1 ;
if ( ! str_comp_nocase ( pLevel , " admin " ) )
2019-03-02 10:50:33 +00:00
Level = AUTHED_ADMIN ;
2017-03-02 15:16:29 +00:00
else if ( ! str_comp_nocase_num ( pLevel , " mod " , 3 ) )
2019-03-02 10:50:33 +00:00
Level = AUTHED_MOD ;
2017-03-02 15:16:29 +00:00
else if ( ! str_comp_nocase ( pLevel , " helper " ) )
2019-03-02 10:50:33 +00:00
Level = AUTHED_HELPER ;
2017-03-02 15:16:29 +00:00
return Level ;
}
2017-03-06 17:02:19 +00:00
void CServer : : AuthRemoveKey ( int KeySlot )
{
int NewKeySlot = KeySlot ;
int OldKeySlot = m_AuthManager . RemoveKey ( KeySlot ) ;
LogoutKey ( KeySlot , " key removal " ) ;
// Update indices.
if ( OldKeySlot ! = NewKeySlot )
{
2020-10-26 14:14:07 +00:00
for ( auto & Client : m_aClients )
if ( Client . m_AuthKey = = OldKeySlot )
Client . m_AuthKey = NewKeySlot ;
2017-03-06 17:02:19 +00:00
}
}
2017-03-02 15:16:29 +00:00
void CServer : : ConAuthAdd ( IConsole : : IResult * pResult , void * pUser )
{
CServer * pThis = ( CServer * ) pUser ;
CAuthManager * pManager = & pThis - > m_AuthManager ;
const char * pIdent = pResult - > GetString ( 0 ) ;
const char * pLevel = pResult - > GetString ( 1 ) ;
const char * pPw = pResult - > GetString ( 2 ) ;
int Level = GetAuthLevel ( pLevel ) ;
if ( Level = = - 1 )
{
pThis - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " auth " , " level can be one of { \" admin \" , \" mod(erator) \" , \" helper \" } " ) ;
return ;
}
2017-07-24 19:43:55 +00:00
bool NeedUpdate = ! pManager - > NumNonDefaultKeys ( ) ;
2017-03-04 20:16:02 +00:00
if ( pManager - > AddKey ( pIdent , pPw , Level ) < 0 )
pThis - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " auth " , " ident already exists " ) ;
else
2017-07-24 19:43:55 +00:00
{
if ( NeedUpdate )
pThis - > SendRconType ( - 1 , true ) ;
2017-03-04 20:16:02 +00:00
pThis - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " auth " , " key added " ) ;
2017-07-24 19:43:55 +00:00
}
2017-03-02 15:16:29 +00:00
}
void CServer : : ConAuthAddHashed ( IConsole : : IResult * pResult , void * pUser )
{
CServer * pThis = ( CServer * ) pUser ;
CAuthManager * pManager = & pThis - > m_AuthManager ;
const char * pIdent = pResult - > GetString ( 0 ) ;
const char * pLevel = pResult - > GetString ( 1 ) ;
const char * pPw = pResult - > GetString ( 2 ) ;
const char * pSalt = pResult - > GetString ( 3 ) ;
int Level = GetAuthLevel ( pLevel ) ;
if ( Level = = - 1 )
{
pThis - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " auth " , " level can be one of { \" admin \" , \" mod(erator) \" , \" helper \" } " ) ;
return ;
}
2019-04-06 00:46:56 +00:00
MD5_DIGEST Hash ;
2017-03-02 15:16:29 +00:00
unsigned char aSalt [ SALT_BYTES ] ;
2019-04-06 00:46:56 +00:00
if ( md5_from_str ( & Hash , pPw ) )
2017-03-06 11:59:47 +00:00
{
2017-03-06 14:18:52 +00:00
pThis - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " auth " , " Malformed password hash " ) ;
2017-03-06 11:59:47 +00:00
return ;
}
2017-03-06 19:11:23 +00:00
if ( str_hex_decode ( aSalt , sizeof ( aSalt ) , pSalt ) )
2017-03-06 11:59:47 +00:00
{
2017-03-06 14:18:52 +00:00
pThis - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " auth " , " Malformed salt hash " ) ;
2017-03-06 11:59:47 +00:00
return ;
}
2017-03-02 15:16:29 +00:00
2017-07-24 19:43:55 +00:00
bool NeedUpdate = ! pManager - > NumNonDefaultKeys ( ) ;
2019-04-06 00:46:56 +00:00
if ( pManager - > AddKeyHash ( pIdent , Hash , aSalt , Level ) < 0 )
2017-03-04 20:16:02 +00:00
pThis - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " auth " , " ident already exists " ) ;
else
2017-07-24 19:43:55 +00:00
{
if ( NeedUpdate )
pThis - > SendRconType ( - 1 , true ) ;
2017-03-04 20:16:02 +00:00
pThis - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " auth " , " key added " ) ;
2017-07-24 19:43:55 +00:00
}
2017-03-02 15:16:29 +00:00
}
void CServer : : ConAuthUpdate ( IConsole : : IResult * pResult , void * pUser )
{
CServer * pThis = ( CServer * ) pUser ;
CAuthManager * pManager = & pThis - > m_AuthManager ;
const char * pIdent = pResult - > GetString ( 0 ) ;
const char * pLevel = pResult - > GetString ( 1 ) ;
const char * pPw = pResult - > GetString ( 2 ) ;
int KeySlot = pManager - > FindKey ( pIdent ) ;
2017-03-06 19:11:23 +00:00
if ( KeySlot = = - 1 )
{
2017-03-02 15:16:29 +00:00
pThis - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " auth " , " ident couldn't be found " ) ;
return ;
}
int Level = GetAuthLevel ( pLevel ) ;
if ( Level = = - 1 )
{
pThis - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " auth " , " level can be one of { \" admin \" , \" mod(erator) \" , \" helper \" } " ) ;
return ;
}
pManager - > UpdateKey ( KeySlot , pPw , Level ) ;
2017-07-24 19:43:55 +00:00
pThis - > LogoutKey ( KeySlot , " key update " ) ;
2017-03-02 15:16:29 +00:00
pThis - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " auth " , " key updated " ) ;
}
void CServer : : ConAuthUpdateHashed ( IConsole : : IResult * pResult , void * pUser )
{
CServer * pThis = ( CServer * ) pUser ;
CAuthManager * pManager = & pThis - > m_AuthManager ;
const char * pIdent = pResult - > GetString ( 0 ) ;
const char * pLevel = pResult - > GetString ( 1 ) ;
const char * pPw = pResult - > GetString ( 2 ) ;
const char * pSalt = pResult - > GetString ( 3 ) ;
int KeySlot = pManager - > FindKey ( pIdent ) ;
2017-03-06 19:11:23 +00:00
if ( KeySlot = = - 1 )
{
2017-03-02 15:16:29 +00:00
pThis - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " auth " , " ident couldn't be found " ) ;
return ;
}
int Level = GetAuthLevel ( pLevel ) ;
if ( Level = = - 1 )
{
pThis - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " auth " , " level can be one of { \" admin \" , \" mod(erator) \" , \" helper \" } " ) ;
return ;
}
2019-04-06 00:46:56 +00:00
MD5_DIGEST Hash ;
2017-03-02 15:16:29 +00:00
unsigned char aSalt [ SALT_BYTES ] ;
2019-04-06 00:46:56 +00:00
if ( md5_from_str ( & Hash , pPw ) )
2017-03-06 11:59:47 +00:00
{
2017-03-06 14:18:52 +00:00
pThis - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " auth " , " Malformed password hash " ) ;
2017-03-06 11:59:47 +00:00
return ;
}
2017-03-06 19:11:23 +00:00
if ( str_hex_decode ( aSalt , sizeof ( aSalt ) , pSalt ) )
2017-03-06 11:59:47 +00:00
{
2017-03-06 14:18:52 +00:00
pThis - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " auth " , " Malformed salt hash " ) ;
2017-03-06 11:59:47 +00:00
return ;
}
2017-03-02 15:16:29 +00:00
2019-04-06 00:46:56 +00:00
pManager - > UpdateKeyHash ( KeySlot , Hash , aSalt , Level ) ;
2017-03-02 15:16:29 +00:00
pThis - > LogoutKey ( KeySlot , " key update " ) ;
pThis - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " auth " , " key updated " ) ;
}
void CServer : : ConAuthRemove ( IConsole : : IResult * pResult , void * pUser )
{
CServer * pThis = ( CServer * ) pUser ;
CAuthManager * pManager = & pThis - > m_AuthManager ;
const char * pIdent = pResult - > GetString ( 0 ) ;
int KeySlot = pManager - > FindKey ( pIdent ) ;
2017-03-06 19:11:23 +00:00
if ( KeySlot = = - 1 )
{
2017-03-02 15:16:29 +00:00
pThis - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " auth " , " ident couldn't be found " ) ;
return ;
}
2017-03-06 17:02:19 +00:00
pThis - > AuthRemoveKey ( KeySlot ) ;
2017-07-24 19:43:55 +00:00
if ( ! pManager - > NumNonDefaultKeys ( ) )
pThis - > SendRconType ( - 1 , false ) ;
2017-03-02 15:16:29 +00:00
pThis - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " auth " , " key removed, all users logged out " ) ;
}
static void ListKeysCallback ( const char * pIdent , int Level , void * pUser )
{
2017-03-06 19:11:23 +00:00
static const char LSTRING [ ] [ 10 ] = { " helper " , " moderator " , " admin " } ;
2017-03-02 15:16:29 +00:00
char aBuf [ 256 ] ;
2017-03-06 19:11:23 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " %s %s " , pIdent , LSTRING [ Level - 1 ] ) ;
2017-03-02 15:16:29 +00:00
( ( CServer * ) pUser ) - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " auth " , aBuf ) ;
}
void CServer : : ConAuthList ( IConsole : : IResult * pResult , void * pUser )
{
CServer * pThis = ( CServer * ) pUser ;
CAuthManager * pManager = & pThis - > m_AuthManager ;
pManager - > ListKeys ( ListKeysCallback , pThis ) ;
}
2018-03-06 17:41:18 +00:00
void CServer : : ConNameBan ( IConsole : : IResult * pResult , void * pUser )
{
CServer * pThis = ( CServer * ) pUser ;
2020-10-11 12:25:31 +00:00
char aBuf [ 256 ] ;
2018-03-06 17:41:18 +00:00
const char * pName = pResult - > GetString ( 0 ) ;
2019-03-03 17:29:33 +00:00
const char * pReason = pResult - > NumArguments ( ) > 3 ? pResult - > GetString ( 3 ) : " " ;
int Distance = pResult - > NumArguments ( ) > 1 ? pResult - > GetInteger ( 1 ) : str_length ( pName ) / 3 ;
2019-03-11 13:48:45 +00:00
int IsSubstring = pResult - > NumArguments ( ) > 2 ? pResult - > GetInteger ( 2 ) : 0 ;
2018-10-07 22:59:07 +00:00
2018-03-06 17:41:18 +00:00
for ( int i = 0 ; i < pThis - > m_aNameBans . size ( ) ; i + + )
{
CNameBan * pBan = & pThis - > m_aNameBans [ i ] ;
if ( str_comp ( pBan - > m_aName , pName ) = = 0 )
{
2019-03-11 13:48:45 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " changed name='%s' distance=%d old_distance=%d is_substring=%d old_is_substring=%d reason='%s' old_reason='%s' " , pName , Distance , pBan - > m_Distance , IsSubstring , pBan - > m_IsSubstring , pReason , pBan - > m_aReason ) ;
2018-03-06 17:41:18 +00:00
pThis - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " name_ban " , aBuf ) ;
pBan - > m_Distance = Distance ;
2019-03-11 13:48:45 +00:00
pBan - > m_IsSubstring = IsSubstring ;
2019-03-19 21:54:16 +00:00
str_copy ( pBan - > m_aReason , pReason , sizeof ( pBan - > m_aReason ) ) ;
2018-03-06 17:41:18 +00:00
return ;
}
}
2018-03-12 18:05:49 +00:00
2019-03-11 13:48:45 +00:00
pThis - > m_aNameBans . add ( CNameBan ( pName , Distance , IsSubstring , pReason ) ) ;
str_format ( aBuf , sizeof ( aBuf ) , " added name='%s' distance=%d is_substring=%d reason='%s' " , pName , Distance , IsSubstring , pReason ) ;
2018-03-06 17:41:18 +00:00
pThis - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " name_ban " , aBuf ) ;
}
void CServer : : ConNameUnban ( IConsole : : IResult * pResult , void * pUser )
{
CServer * pThis = ( CServer * ) pUser ;
const char * pName = pResult - > GetString ( 0 ) ;
for ( int i = 0 ; i < pThis - > m_aNameBans . size ( ) ; i + + )
{
CNameBan * pBan = & pThis - > m_aNameBans [ i ] ;
if ( str_comp ( pBan - > m_aName , pName ) = = 0 )
{
2020-10-11 12:25:31 +00:00
char aBuf [ 128 ] ;
2019-03-11 13:48:45 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " removed name='%s' distance=%d is_substring=%d reason='%s' " , pBan - > m_aName , pBan - > m_Distance , pBan - > m_IsSubstring , pBan - > m_aReason ) ;
2018-03-06 17:41:18 +00:00
pThis - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " name_ban " , aBuf ) ;
pThis - > m_aNameBans . remove_index ( i ) ;
}
}
}
void CServer : : ConNameBans ( IConsole : : IResult * pResult , void * pUser )
{
CServer * pThis = ( CServer * ) pUser ;
for ( int i = 0 ; i < pThis - > m_aNameBans . size ( ) ; i + + )
{
CNameBan * pBan = & pThis - > m_aNameBans [ i ] ;
2020-10-11 12:25:31 +00:00
char aBuf [ 128 ] ;
2019-03-11 13:48:45 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " name='%s' distance=%d is_substring=%d reason='%s' " , pBan - > m_aName , pBan - > m_Distance , pBan - > m_IsSubstring , pBan - > m_aReason ) ;
2018-03-06 17:41:18 +00:00
pThis - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " name_ban " , aBuf ) ;
}
}
2011-08-13 00:11:06 +00:00
void CServer : : ConShutdown ( IConsole : : IResult * pResult , void * pUser )
2010-05-29 07:25:38 +00:00
{
2021-12-08 17:41:16 +00:00
CServer * pThis = static_cast < CServer * > ( pUser ) ;
pThis - > m_RunServer = STOPPING ;
const char * pReason = pResult - > GetString ( 0 ) ;
if ( pReason [ 0 ] )
{
str_copy ( pThis - > m_aShutdownReason , pReason , sizeof ( pThis - > m_aShutdownReason ) ) ;
}
2010-05-29 07:25:38 +00:00
}
2011-07-22 21:17:16 +00:00
void CServer : : DemoRecorder_HandleAutoStart ( )
{
2021-12-14 23:28:51 +00:00
if ( Config ( ) - > m_SvAutoDemoRecord )
2011-07-22 21:17:16 +00:00
{
2014-09-26 00:05:22 +00:00
m_aDemoRecorder [ MAX_CLIENTS ] . Stop ( ) ;
2021-09-13 08:06:34 +00:00
char aFilename [ IO_MAX_PATH_LENGTH ] ;
2011-07-22 21:17:16 +00:00
char aDate [ 20 ] ;
str_timestamp ( aDate , sizeof ( aDate ) ) ;
str_format ( aFilename , sizeof ( aFilename ) , " demos/%s_%s.demo " , " auto/autorecord " , aDate ) ;
2020-06-19 21:52:13 +00:00
m_aDemoRecorder [ MAX_CLIENTS ] . Start ( Storage ( ) , m_pConsole , aFilename , GameServer ( ) - > NetVersion ( ) , m_aCurrentMap , & m_aCurrentMapSha256 [ SIX ] , m_aCurrentMapCrc [ SIX ] , " server " , m_aCurrentMapSize [ SIX ] , m_apCurrentMapData [ SIX ] ) ;
2021-12-14 23:28:51 +00:00
if ( Config ( ) - > m_SvAutoDemoMax )
2011-07-22 21:17:16 +00:00
{
// clean up auto recorded demos
CFileCollection AutoDemos ;
2021-12-14 23:28:51 +00:00
AutoDemos . Init ( Storage ( ) , " demos/server " , " autorecord " , " .demo " , Config ( ) - > m_SvAutoDemoMax ) ;
2011-07-22 21:17:16 +00:00
}
}
}
2012-01-08 23:49:20 +00:00
bool CServer : : DemoRecorder_IsRecording ( )
{
2014-09-26 00:05:22 +00:00
return m_aDemoRecorder [ MAX_CLIENTS ] . IsRecording ( ) ;
}
void CServer : : SaveDemo ( int ClientID , float Time )
{
if ( IsRecording ( ClientID ) )
{
2017-07-08 11:38:27 +00:00
m_aDemoRecorder [ ClientID ] . Stop ( ) ;
2014-09-26 00:05:22 +00:00
// rename the demo
2021-09-13 08:06:34 +00:00
char aOldFilename [ IO_MAX_PATH_LENGTH ] ;
char aNewFilename [ IO_MAX_PATH_LENGTH ] ;
2020-08-27 16:54:44 +00:00
str_format ( aOldFilename , sizeof ( aOldFilename ) , " demos/%s_%d_%d_tmp.demo " , m_aCurrentMap , m_NetServer . Address ( ) . port , ClientID ) ;
2014-09-26 00:05:22 +00:00
str_format ( aNewFilename , sizeof ( aNewFilename ) , " demos/%s_%s_%5.2f.demo " , m_aCurrentMap , m_aClients [ ClientID ] . m_aName , Time ) ;
Storage ( ) - > RenameFile ( aOldFilename , aNewFilename , IStorage : : TYPE_SAVE ) ;
}
}
void CServer : : StartRecord ( int ClientID )
{
2021-12-14 23:28:51 +00:00
if ( Config ( ) - > m_SvPlayerDemoRecord )
2014-09-26 00:05:22 +00:00
{
2021-09-13 08:06:34 +00:00
char aFilename [ IO_MAX_PATH_LENGTH ] ;
2020-08-27 16:54:44 +00:00
str_format ( aFilename , sizeof ( aFilename ) , " demos/%s_%d_%d_tmp.demo " , m_aCurrentMap , m_NetServer . Address ( ) . port , ClientID ) ;
2020-06-19 21:52:13 +00:00
m_aDemoRecorder [ ClientID ] . Start ( Storage ( ) , Console ( ) , aFilename , GameServer ( ) - > NetVersion ( ) , m_aCurrentMap , & m_aCurrentMapSha256 [ SIX ] , m_aCurrentMapCrc [ SIX ] , " server " , m_aCurrentMapSize [ SIX ] , m_apCurrentMapData [ SIX ] ) ;
2014-09-26 00:05:22 +00:00
}
}
void CServer : : StopRecord ( int ClientID )
{
if ( IsRecording ( ClientID ) )
{
m_aDemoRecorder [ ClientID ] . Stop ( ) ;
2021-09-13 08:06:34 +00:00
char aFilename [ IO_MAX_PATH_LENGTH ] ;
2020-08-27 16:54:44 +00:00
str_format ( aFilename , sizeof ( aFilename ) , " demos/%s_%d_%d_tmp.demo " , m_aCurrentMap , m_NetServer . Address ( ) . port , ClientID ) ;
2014-09-26 00:05:22 +00:00
Storage ( ) - > RemoveFile ( aFilename , IStorage : : TYPE_SAVE ) ;
}
}
bool CServer : : IsRecording ( int ClientID )
{
return m_aDemoRecorder [ ClientID ] . IsRecording ( ) ;
2012-01-08 23:49:20 +00:00
}
2010-05-29 07:25:38 +00:00
void CServer : : ConRecord ( IConsole : : IResult * pResult , void * pUser )
{
2017-03-21 10:24:44 +00:00
CServer * pServer = ( CServer * ) pUser ;
2021-09-13 08:06:34 +00:00
char aFilename [ IO_MAX_PATH_LENGTH ] ;
2010-12-07 23:42:32 +00:00
if ( pResult - > NumArguments ( ) )
str_format ( aFilename , sizeof ( aFilename ) , " demos/%s.demo " , pResult - > GetString ( 0 ) ) ;
else
{
char aDate [ 20 ] ;
str_timestamp ( aDate , sizeof ( aDate ) ) ;
str_format ( aFilename , sizeof ( aFilename ) , " demos/demo_%s.demo " , aDate ) ;
}
2020-06-19 21:52:13 +00:00
pServer - > m_aDemoRecorder [ MAX_CLIENTS ] . Start ( pServer - > Storage ( ) , pServer - > Console ( ) , aFilename , pServer - > GameServer ( ) - > NetVersion ( ) , pServer - > m_aCurrentMap , & pServer - > m_aCurrentMapSha256 [ SIX ] , pServer - > m_aCurrentMapCrc [ SIX ] , " server " , pServer - > m_aCurrentMapSize [ SIX ] , pServer - > m_apCurrentMapData [ SIX ] ) ;
2010-05-29 07:25:38 +00:00
}
2011-08-13 00:11:06 +00:00
void CServer : : ConStopRecord ( IConsole : : IResult * pResult , void * pUser )
2010-05-29 07:25:38 +00:00
{
2014-09-26 00:05:22 +00:00
( ( CServer * ) pUser ) - > m_aDemoRecorder [ MAX_CLIENTS ] . Stop ( ) ;
2010-05-29 07:25:38 +00:00
}
2011-08-13 00:11:06 +00:00
void CServer : : ConMapReload ( IConsole : : IResult * pResult , void * pUser )
2010-05-30 12:01:11 +00:00
{
2020-04-23 17:02:10 +00:00
( ( CServer * ) pUser ) - > m_MapReload = true ;
2010-05-30 12:01:11 +00:00
}
2011-12-26 21:07:57 +00:00
void CServer : : ConLogout ( IConsole : : IResult * pResult , void * pUser )
{
CServer * pServer = ( CServer * ) pUser ;
2011-12-29 23:07:17 +00:00
if ( pServer - > m_RconClientID > = 0 & & pServer - > m_RconClientID < MAX_CLIENTS & &
pServer - > m_aClients [ pServer - > m_RconClientID ] . m_State ! = CServer : : CClient : : STATE_EMPTY )
{
2017-03-02 15:16:29 +00:00
pServer - > LogoutClient ( pServer - > m_RconClientID , " " ) ;
2011-12-29 23:07:17 +00:00
}
2011-12-26 21:07:57 +00:00
}
2019-04-04 17:16:10 +00:00
void CServer : : ConShowIps ( IConsole : : IResult * pResult , void * pUser )
{
CServer * pServer = ( CServer * ) pUser ;
if ( pServer - > m_RconClientID > = 0 & & pServer - > m_RconClientID < MAX_CLIENTS & &
pServer - > m_aClients [ pServer - > m_RconClientID ] . m_State ! = CServer : : CClient : : STATE_EMPTY )
{
if ( pResult - > NumArguments ( ) )
{
pServer - > m_aClients [ pServer - > m_RconClientID ] . m_ShowIps = pResult - > GetInteger ( 0 ) ;
}
else
{
2019-08-01 18:24:30 +00:00
char aStr [ 9 ] ;
str_format ( aStr , sizeof ( aStr ) , " Value: %d " , pServer - > m_aClients [ pServer - > m_RconClientID ] . m_ShowIps ) ;
char aBuf [ 32 ] ;
pServer - > SendRconLine ( pServer - > m_RconClientID , pServer - > Console ( ) - > Format ( aBuf , sizeof ( aBuf ) , " server " , aStr ) ) ;
2019-04-04 17:16:10 +00:00
}
}
}
2015-12-17 21:04:38 +00:00
void CServer : : ConAddSqlServer ( IConsole : : IResult * pResult , void * pUserData )
2015-11-23 21:49:18 +00:00
{
CServer * pSelf = ( CServer * ) pUserData ;
2021-12-14 23:28:51 +00:00
if ( ! pSelf - > Config ( ) - > m_SvUseSQL )
return ;
2020-09-26 19:41:58 +00:00
if ( pResult - > NumArguments ( ) ! = 7 & & pResult - > NumArguments ( ) ! = 8 )
2015-11-23 21:49:18 +00:00
{
2015-12-20 15:07:32 +00:00
pSelf - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " server " , " 7 or 8 arguments are required " ) ;
2015-11-23 21:49:18 +00:00
return ;
}
2015-12-19 17:26:09 +00:00
bool ReadOnly ;
2020-09-26 19:41:58 +00:00
if ( str_comp_nocase ( pResult - > GetString ( 0 ) , " w " ) = = 0 )
2015-12-19 17:26:09 +00:00
ReadOnly = false ;
2020-09-26 19:41:58 +00:00
else if ( str_comp_nocase ( pResult - > GetString ( 0 ) , " r " ) = = 0 )
2015-12-19 17:26:09 +00:00
ReadOnly = true ;
else
{
pSelf - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " server " , " choose either 'r' for SqlReadServer or 'w' for SqlWriteServer " ) ;
return ;
}
2015-12-17 21:04:38 +00:00
2018-04-24 21:07:51 +00:00
bool SetUpDb = pResult - > NumArguments ( ) = = 8 ? pResult - > GetInteger ( 7 ) : true ;
2015-12-20 15:07:32 +00:00
2021-11-28 12:33:47 +00:00
auto pMysqlConn = CreateMysqlConnection (
2020-09-26 19:41:58 +00:00
pResult - > GetString ( 1 ) , pResult - > GetString ( 2 ) , pResult - > GetString ( 3 ) ,
pResult - > GetString ( 4 ) , pResult - > GetString ( 5 ) , pResult - > GetInteger ( 6 ) ,
2021-11-28 12:33:47 +00:00
SetUpDb ) ;
2015-12-17 21:04:38 +00:00
2021-11-28 12:33:47 +00:00
if ( ! pMysqlConn )
2021-01-26 20:22:32 +00:00
{
pSelf - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " server " , " can't add MySQL server: compiled without MySQL support " ) ;
return ;
}
2020-07-04 17:53:27 +00:00
char aBuf [ 512 ] ;
str_format ( aBuf , sizeof ( aBuf ) ,
2021-01-26 20:22:32 +00:00
" Added new Sql%sServer: DB: '%s' Prefix: '%s' User: '%s' IP: <{%s}> Port: %d " ,
2020-09-26 19:41:58 +00:00
ReadOnly ? " Read " : " Write " ,
pResult - > GetString ( 1 ) , pResult - > GetString ( 2 ) , pResult - > GetString ( 3 ) ,
pResult - > GetString ( 5 ) , pResult - > GetInteger ( 6 ) ) ;
2020-07-04 17:53:27 +00:00
pSelf - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " server " , aBuf ) ;
2021-11-28 12:33:47 +00:00
pSelf - > DbPool ( ) - > RegisterDatabase ( std : : move ( pMysqlConn ) , ReadOnly ? CDbConnectionPool : : READ : CDbConnectionPool : : WRITE ) ;
2015-11-23 21:49:18 +00:00
}
2015-12-17 21:04:38 +00:00
void CServer : : ConDumpSqlServers ( IConsole : : IResult * pResult , void * pUserData )
2015-11-23 21:49:18 +00:00
{
CServer * pSelf = ( CServer * ) pUserData ;
2020-08-03 14:18:22 +00:00
if ( str_comp_nocase ( pResult - > GetString ( 0 ) , " w " ) = = 0 )
{
pSelf - > DbPool ( ) - > Print ( pSelf - > Console ( ) , CDbConnectionPool : : WRITE ) ;
pSelf - > DbPool ( ) - > Print ( pSelf - > Console ( ) , CDbConnectionPool : : WRITE_BACKUP ) ;
}
else if ( str_comp_nocase ( pResult - > GetString ( 0 ) , " r " ) = = 0 )
{
pSelf - > DbPool ( ) - > Print ( pSelf - > Console ( ) , CDbConnectionPool : : READ ) ;
}
2015-12-19 17:26:09 +00:00
else
{
pSelf - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " server " , " choose either 'r' for SqlReadServer or 'w' for SqlWriteServer " ) ;
return ;
}
2015-11-23 21:49:18 +00:00
}
2010-05-29 07:25:38 +00:00
void CServer : : ConchainSpecialInfoupdate ( IConsole : : IResult * pResult , void * pUserData , IConsole : : FCommandCallback pfnCallback , void * pCallbackUserData )
{
2011-08-13 00:11:06 +00:00
pfnCallback ( pResult , pCallbackUserData ) ;
2010-05-29 07:25:38 +00:00
if ( pResult - > NumArguments ( ) )
2013-09-04 14:44:04 +00:00
{
2021-12-14 23:28:51 +00:00
CServer * pThis = static_cast < CServer * > ( pUserData ) ;
str_clean_whitespaces ( pThis - > Config ( ) - > m_SvName ) ;
pThis - > UpdateServerInfo ( true ) ;
2013-09-04 14:44:04 +00:00
}
2010-05-29 07:25:38 +00:00
}
2010-06-03 12:48:32 +00:00
void CServer : : ConchainMaxclientsperipUpdate ( IConsole : : IResult * pResult , void * pUserData , IConsole : : FCommandCallback pfnCallback , void * pCallbackUserData )
{
2011-08-13 00:11:06 +00:00
pfnCallback ( pResult , pCallbackUserData ) ;
2010-06-03 12:48:32 +00:00
if ( pResult - > NumArguments ( ) )
( ( CServer * ) pUserData ) - > m_NetServer . SetMaxClientsPerIP ( pResult - > GetInteger ( 0 ) ) ;
}
2015-10-23 00:33:10 +00:00
void CServer : : ConchainCommandAccessUpdate ( IConsole : : IResult * pResult , void * pUserData , IConsole : : FCommandCallback pfnCallback , void * pCallbackUserData )
2011-07-14 20:07:21 +00:00
{
if ( pResult - > NumArguments ( ) = = 2 )
{
CServer * pThis = static_cast < CServer * > ( pUserData ) ;
const IConsole : : CCommandInfo * pInfo = pThis - > Console ( ) - > GetCommandInfo ( pResult - > GetString ( 0 ) , CFGFLAG_SERVER , false ) ;
2011-08-01 10:11:10 +00:00
int OldAccessLevel = 0 ;
2011-07-14 20:07:21 +00:00
if ( pInfo )
OldAccessLevel = pInfo - > GetAccessLevel ( ) ;
pfnCallback ( pResult , pCallbackUserData ) ;
if ( pInfo & & OldAccessLevel ! = pInfo - > GetAccessLevel ( ) )
{
for ( int i = 0 ; i < MAX_CLIENTS ; + + i )
{
2015-10-23 00:33:10 +00:00
if ( pThis - > m_aClients [ i ] . m_State = = CServer : : CClient : : STATE_EMPTY | |
2020-09-26 19:41:58 +00:00
( pInfo - > GetAccessLevel ( ) > AUTHED_ADMIN - pThis - > m_aClients [ i ] . m_Authed & & AUTHED_ADMIN - pThis - > m_aClients [ i ] . m_Authed < OldAccessLevel ) | |
( pInfo - > GetAccessLevel ( ) < AUTHED_ADMIN - pThis - > m_aClients [ i ] . m_Authed & & AUTHED_ADMIN - pThis - > m_aClients [ i ] . m_Authed > OldAccessLevel ) | |
( pThis - > m_aClients [ i ] . m_pRconCmdToSend & & str_comp ( pResult - > GetString ( 0 ) , pThis - > m_aClients [ i ] . m_pRconCmdToSend - > m_pName ) > = 0 ) )
2011-07-14 20:07:21 +00:00
continue ;
2015-10-23 00:33:10 +00:00
if ( OldAccessLevel < pInfo - > GetAccessLevel ( ) )
2011-07-14 20:07:21 +00:00
pThis - > SendRconCmdAdd ( pInfo , i ) ;
else
pThis - > SendRconCmdRem ( pInfo , i ) ;
}
}
}
else
pfnCallback ( pResult , pCallbackUserData ) ;
}
2011-07-30 11:40:01 +00:00
void CServer : : ConchainConsoleOutputLevelUpdate ( IConsole : : IResult * pResult , void * pUserData , IConsole : : FCommandCallback pfnCallback , void * pCallbackUserData )
{
pfnCallback ( pResult , pCallbackUserData ) ;
if ( pResult - > NumArguments ( ) = = 1 )
{
CServer * pThis = static_cast < CServer * > ( pUserData ) ;
pThis - > Console ( ) - > SetPrintOutputLevel ( pThis - > m_PrintCBIndex , pResult - > GetInteger ( 0 ) ) ;
}
}
2017-03-02 15:16:29 +00:00
void CServer : : LogoutClient ( int ClientID , const char * pReason )
2015-10-26 23:33:26 +00:00
{
2020-06-16 14:55:37 +00:00
if ( ! IsSixup ( ClientID ) )
{
CMsgPacker Msg ( NETMSG_RCON_AUTH_STATUS , true ) ;
2020-09-26 19:41:58 +00:00
Msg . AddInt ( 0 ) ; //authed
Msg . AddInt ( 0 ) ; //cmdlist
2020-06-16 14:55:37 +00:00
SendMsg ( & Msg , MSGFLAG_VITAL , ClientID ) ;
}
else
{
CMsgPacker Msg ( 12 , true , true ) ; //NETMSG_RCON_AUTH_OFF
SendMsg ( & Msg , MSGFLAG_VITAL , ClientID ) ;
}
2017-03-02 15:16:29 +00:00
m_aClients [ ClientID ] . m_AuthTries = 0 ;
m_aClients [ ClientID ] . m_pRconCmdToSend = 0 ;
char aBuf [ 64 ] ;
2017-03-06 19:11:23 +00:00
if ( * pReason )
{
str_format ( aBuf , sizeof ( aBuf ) , " Logged out by %s. " , pReason ) ;
2017-03-02 15:16:29 +00:00
SendRconLine ( ClientID , aBuf ) ;
2017-03-06 19:11:23 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " ClientID=%d with key=%s logged out by %s " , ClientID , m_AuthManager . KeyIdent ( m_aClients [ ClientID ] . m_AuthKey ) , pReason ) ;
2015-10-26 23:33:26 +00:00
}
2017-03-06 19:11:23 +00:00
else
{
2017-03-02 15:16:29 +00:00
SendRconLine ( ClientID , " Logout successful. " ) ;
2017-03-06 19:11:23 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " ClientID=%d with key=%s logged out " , ClientID , m_AuthManager . KeyIdent ( m_aClients [ ClientID ] . m_AuthKey ) ) ;
2017-03-02 15:16:29 +00:00
}
m_aClients [ ClientID ] . m_Authed = AUTHED_NO ;
m_aClients [ ClientID ] . m_AuthKey = - 1 ;
2018-01-28 02:13:05 +00:00
GameServer ( ) - > OnSetAuthed ( ClientID , AUTHED_NO ) ;
2017-03-02 15:16:29 +00:00
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " server " , aBuf ) ;
}
void CServer : : LogoutKey ( int Key , const char * pReason )
{
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
if ( m_aClients [ i ] . m_AuthKey = = Key )
LogoutClient ( i , pReason ) ;
2015-10-26 23:33:26 +00:00
}
2018-02-26 17:01:02 +00:00
void CServer : : ConchainRconPasswordChangeGeneric ( int Level , const char * pCurrent , IConsole : : IResult * pResult )
2014-09-16 19:14:31 +00:00
{
if ( pResult - > NumArguments ( ) = = 1 )
{
2017-03-06 17:02:19 +00:00
int KeySlot = m_AuthManager . DefaultKey ( Level ) ;
2018-02-26 17:01:02 +00:00
const char * pNew = pResult - > GetString ( 0 ) ;
if ( str_comp ( pCurrent , pNew ) = = 0 )
2017-03-04 07:58:02 +00:00
{
2018-02-26 17:01:02 +00:00
return ;
}
if ( KeySlot = = - 1 & & pNew [ 0 ] )
{
m_AuthManager . AddDefaultKey ( Level , pNew ) ;
2017-03-04 07:58:02 +00:00
}
2017-03-06 19:11:23 +00:00
else if ( KeySlot > = 0 )
2017-03-04 07:58:02 +00:00
{
2018-02-26 17:01:02 +00:00
if ( ! pNew [ 0 ] )
2017-03-06 17:02:19 +00:00
{
AuthRemoveKey ( KeySlot ) ;
// Already logs users out.
}
2017-03-04 20:06:22 +00:00
else
2017-03-06 17:02:19 +00:00
{
2018-02-26 17:01:02 +00:00
m_AuthManager . UpdateKey ( KeySlot , pNew , Level ) ;
2017-03-06 17:02:19 +00:00
LogoutKey ( KeySlot , " key update " ) ;
}
2017-03-04 07:58:02 +00:00
}
2014-09-16 19:14:31 +00:00
}
}
2017-03-06 17:02:19 +00:00
void CServer : : ConchainRconPasswordChange ( IConsole : : IResult * pResult , void * pUserData , IConsole : : FCommandCallback pfnCallback , void * pCallbackUserData )
2014-09-16 19:14:31 +00:00
{
2021-12-14 23:28:51 +00:00
CServer * pThis = static_cast < CServer * > ( pUserData ) ;
pThis - > ConchainRconPasswordChangeGeneric ( AUTHED_ADMIN , pThis - > Config ( ) - > m_SvRconPassword , pResult ) ;
2014-09-16 19:14:31 +00:00
pfnCallback ( pResult , pCallbackUserData ) ;
2017-03-06 17:02:19 +00:00
}
2017-03-02 15:16:29 +00:00
2017-03-06 17:02:19 +00:00
void CServer : : ConchainRconModPasswordChange ( IConsole : : IResult * pResult , void * pUserData , IConsole : : FCommandCallback pfnCallback , void * pCallbackUserData )
{
2021-12-14 23:28:51 +00:00
CServer * pThis = static_cast < CServer * > ( pUserData ) ;
pThis - > ConchainRconPasswordChangeGeneric ( AUTHED_MOD , pThis - > Config ( ) - > m_SvRconModPassword , pResult ) ;
2017-03-06 17:02:19 +00:00
pfnCallback ( pResult , pCallbackUserData ) ;
2014-09-16 19:14:31 +00:00
}
2015-10-23 00:33:10 +00:00
void CServer : : ConchainRconHelperPasswordChange ( IConsole : : IResult * pResult , void * pUserData , IConsole : : FCommandCallback pfnCallback , void * pCallbackUserData )
{
2021-12-14 23:28:51 +00:00
CServer * pThis = static_cast < CServer * > ( pUserData ) ;
pThis - > ConchainRconPasswordChangeGeneric ( AUTHED_HELPER , pThis - > Config ( ) - > m_SvRconHelperPassword , pResult ) ;
2015-10-23 00:33:10 +00:00
pfnCallback ( pResult , pCallbackUserData ) ;
2014-09-16 19:14:31 +00:00
}
2020-04-23 17:02:10 +00:00
void CServer : : ConchainMapUpdate ( IConsole : : IResult * pResult , void * pUserData , IConsole : : FCommandCallback pfnCallback , void * pCallbackUserData )
{
pfnCallback ( pResult , pCallbackUserData ) ;
if ( pResult - > NumArguments ( ) > = 1 )
{
CServer * pThis = static_cast < CServer * > ( pUserData ) ;
pThis - > m_MapReload = str_comp ( pThis - > Config ( ) - > m_SvMap , pThis - > m_aCurrentMap ) ! = 0 ;
}
}
2021-12-21 11:23:17 +00:00
void CServer : : ConchainSixupUpdate ( IConsole : : IResult * pResult , void * pUserData , IConsole : : FCommandCallback pfnCallback , void * pCallbackUserData )
{
pfnCallback ( pResult , pCallbackUserData ) ;
CServer * pThis = static_cast < CServer * > ( pUserData ) ;
if ( pResult - > NumArguments ( ) > = 1 & & pThis - > m_aCurrentMap [ 0 ] ! = ' \0 ' )
pThis - > m_MapReload | = ( pThis - > m_apCurrentMapData [ SIXUP ] ! = 0 ) ! = ( pResult - > GetInteger ( 0 ) ! = 0 ) ;
}
2017-12-20 15:56:34 +00:00
# if defined(CONF_FAMILY_UNIX)
void CServer : : ConchainConnLoggingServerChange ( IConsole : : IResult * pResult , void * pUserData , IConsole : : FCommandCallback pfnCallback , void * pCallbackUserData )
{
pfnCallback ( pResult , pCallbackUserData ) ;
if ( pResult - > NumArguments ( ) = = 1 )
{
CServer * pServer = ( CServer * ) pUserData ;
// open socket to send new connections
if ( ! pServer - > m_ConnLoggingSocketCreated )
{
2017-12-20 15:56:44 +00:00
pServer - > m_ConnLoggingSocket = net_unix_create_unnamed ( ) ;
2017-12-20 15:56:34 +00:00
if ( pServer - > m_ConnLoggingSocket = = - 1 )
{
pServer - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " server " , " Failed to created socket for communication with the connection logging server. " ) ;
}
else
{
pServer - > m_ConnLoggingSocketCreated = true ;
}
}
// set the destination address for the connection logging
2017-12-20 15:56:44 +00:00
net_unix_set_addr ( & pServer - > m_ConnLoggingDestAddr , pResult - > GetString ( 0 ) ) ;
2017-12-20 15:56:34 +00:00
}
}
# endif
2010-05-29 07:25:38 +00:00
void CServer : : RegisterCommands ( )
{
m_pConsole = Kernel ( ) - > RequestInterface < IConsole > ( ) ;
2012-03-04 11:47:09 +00:00
m_pGameServer = Kernel ( ) - > RequestInterface < IGameServer > ( ) ;
m_pMap = Kernel ( ) - > RequestInterface < IEngineMap > ( ) ;
m_pStorage = Kernel ( ) - > RequestInterface < IStorage > ( ) ;
2020-05-13 20:27:49 +00:00
m_pAntibot = Kernel ( ) - > RequestInterface < IEngineAntibot > ( ) ;
2011-04-13 18:37:12 +00:00
2012-03-04 11:47:09 +00:00
// register console commands
2015-12-28 15:14:52 +00:00
Console ( ) - > Register ( " kick " , " i[id] ?r[reason] " , CFGFLAG_SERVER , ConKick , this , " Kick player with specified id for any reason " ) ;
2020-01-24 00:55:09 +00:00
Console ( ) - > Register ( " status " , " ?r[name] " , CFGFLAG_SERVER , ConStatus , this , " List players containing name or all players " ) ;
2021-12-08 17:41:16 +00:00
Console ( ) - > Register ( " shutdown " , " ?r[reason] " , CFGFLAG_SERVER , ConShutdown , this , " Shut down " ) ;
2011-12-29 23:07:17 +00:00
Console ( ) - > Register ( " logout " , " " , CFGFLAG_SERVER , ConLogout , this , " Logout of rcon " ) ;
2019-04-04 17:16:10 +00:00
Console ( ) - > Register ( " show_ips " , " ?i[show] " , CFGFLAG_SERVER , ConShowIps , this , " Show IP addresses in rcon commands (1 = on, 0 = off) " ) ;
2010-05-29 07:25:38 +00:00
2020-09-26 19:41:58 +00:00
Console ( ) - > Register ( " record " , " ?s[file] " , CFGFLAG_SERVER | CFGFLAG_STORE , ConRecord , this , " Record to a file " ) ;
2011-07-14 20:07:21 +00:00
Console ( ) - > Register ( " stoprecord " , " " , CFGFLAG_SERVER , ConStopRecord , this , " Stop recording " ) ;
2011-04-13 18:37:12 +00:00
2011-07-14 20:07:21 +00:00
Console ( ) - > Register ( " reload " , " " , CFGFLAG_SERVER , ConMapReload , this , " Reload the map " ) ;
2011-08-13 00:11:06 +00:00
2020-09-26 19:41:58 +00:00
Console ( ) - > Register ( " add_sqlserver " , " s['r'|'w'] s[Database] s[Prefix] s[User] s[Password] s[IP] i[Port] ?i[SetUpDatabase ?] " , CFGFLAG_SERVER | CFGFLAG_NONTEEHISTORIC , ConAddSqlServer , this , " add a sqlserver " ) ;
2016-01-17 16:57:38 +00:00
Console ( ) - > Register ( " dump_sqlservers " , " s['r'|'w'] " , CFGFLAG_SERVER , ConDumpSqlServers , this , " dumps all sqlservers readservers = r, writeservers = w " ) ;
2015-11-23 21:49:18 +00:00
2020-10-04 09:40:38 +00:00
Console ( ) - > Register ( " auth_add " , " s[ident] s[level] r[pw] " , CFGFLAG_SERVER | CFGFLAG_NONTEEHISTORIC , ConAuthAdd , this , " Add a rcon key " ) ;
2020-09-26 19:41:58 +00:00
Console ( ) - > Register ( " auth_add_p " , " s[ident] s[level] s[hash] s[salt] " , CFGFLAG_SERVER | CFGFLAG_NONTEEHISTORIC , ConAuthAddHashed , this , " Add a prehashed rcon key " ) ;
2020-10-04 09:40:38 +00:00
Console ( ) - > Register ( " auth_change " , " s[ident] s[level] r[pw] " , CFGFLAG_SERVER | CFGFLAG_NONTEEHISTORIC , ConAuthUpdate , this , " Update a rcon key " ) ;
2020-09-26 19:41:58 +00:00
Console ( ) - > Register ( " auth_change_p " , " s[ident] s[level] s[hash] s[salt] " , CFGFLAG_SERVER | CFGFLAG_NONTEEHISTORIC , ConAuthUpdateHashed , this , " Update a rcon key with prehashed data " ) ;
Console ( ) - > Register ( " auth_remove " , " s[ident] " , CFGFLAG_SERVER | CFGFLAG_NONTEEHISTORIC , ConAuthRemove , this , " Remove a rcon key " ) ;
2017-03-06 19:11:23 +00:00
Console ( ) - > Register ( " auth_list " , " " , CFGFLAG_SERVER , ConAuthList , this , " List all rcon keys " ) ;
2017-03-02 15:16:29 +00:00
2020-11-05 08:32:14 +00:00
Console ( ) - > Register ( " name_ban " , " s[name] ?i[distance] ?i[is_substring] ?r[reason] " , CFGFLAG_SERVER , ConNameBan , this , " Ban a certain nickname " ) ;
Console ( ) - > Register ( " name_unban " , " s[name] " , CFGFLAG_SERVER , ConNameUnban , this , " Unban a certain nickname " ) ;
2018-03-06 17:41:18 +00:00
Console ( ) - > Register ( " name_bans " , " " , CFGFLAG_SERVER , ConNameBans , this , " List all name bans " ) ;
2010-05-29 07:25:38 +00:00
Console ( ) - > Chain ( " sv_name " , ConchainSpecialInfoupdate , this ) ;
Console ( ) - > Chain ( " password " , ConchainSpecialInfoupdate , this ) ;
2010-06-03 12:48:32 +00:00
Console ( ) - > Chain ( " sv_max_clients_per_ip " , ConchainMaxclientsperipUpdate , this ) ;
2015-10-23 00:33:10 +00:00
Console ( ) - > Chain ( " access_level " , ConchainCommandAccessUpdate , this ) ;
2011-07-30 11:40:01 +00:00
Console ( ) - > Chain ( " console_output_level " , ConchainConsoleOutputLevelUpdate , this ) ;
2015-07-09 00:08:14 +00:00
2014-09-16 19:14:31 +00:00
Console ( ) - > Chain ( " sv_rcon_password " , ConchainRconPasswordChange , this ) ;
Console ( ) - > Chain ( " sv_rcon_mod_password " , ConchainRconModPasswordChange , this ) ;
2015-10-23 00:33:10 +00:00
Console ( ) - > Chain ( " sv_rcon_helper_password " , ConchainRconHelperPasswordChange , this ) ;
2020-04-23 17:02:10 +00:00
Console ( ) - > Chain ( " sv_map " , ConchainMapUpdate , this ) ;
2021-12-21 11:23:17 +00:00
Console ( ) - > Chain ( " sv_sixup " , ConchainSixupUpdate , this ) ;
2012-03-04 11:47:09 +00:00
2017-12-20 15:56:34 +00:00
# if defined(CONF_FAMILY_UNIX)
Console ( ) - > Chain ( " sv_conn_logging_server " , ConchainConnLoggingServerChange , this ) ;
# endif
2012-03-04 11:47:09 +00:00
// register console commands in sub parts
2012-08-16 22:03:53 +00:00
m_ServerBan . InitServerBan ( Console ( ) , Storage ( ) , this ) ;
2012-03-04 11:47:09 +00:00
m_pGameServer - > OnConsoleInit ( ) ;
2011-04-13 18:37:12 +00:00
}
2010-05-29 07:25:38 +00:00
int CServer : : SnapNewID ( )
{
return m_IDPool . NewID ( ) ;
}
void CServer : : SnapFreeID ( int ID )
{
m_IDPool . FreeID ( ID ) ;
}
2011-02-12 10:40:36 +00:00
void * CServer : : SnapNewItem ( int Type , int ID , int Size )
2010-05-29 07:25:38 +00:00
{
2020-06-12 20:53:41 +00:00
if ( Type > 0xffff )
2017-05-21 23:07:13 +00:00
{
g_UuidManager . GetUuid ( Type ) ;
}
dbg_assert ( ID > = 0 & & ID < = 0xffff , " incorrect id " ) ;
2011-04-13 18:37:12 +00:00
return ID < 0 ? 0 : m_SnapshotBuilder . NewItem ( Type , ID , Size ) ;
2010-05-29 07:25:38 +00:00
}
void CServer : : SnapSetStaticsize ( int ItemType , int Size )
{
m_SnapshotDelta . SetStaticsize ( ItemType , Size ) ;
}
static CServer * CreateServer ( ) { return new CServer ( ) ; }
int main ( int argc , const char * * argv ) // ignore_convention
{
2021-11-21 17:16:14 +00:00
cmdline_fix ( & argc , & argv ) ;
2017-09-03 08:37:24 +00:00
bool Silent = false ;
2010-05-29 07:25:38 +00:00
for ( int i = 1 ; i < argc ; i + + ) // ignore_convention
{
if ( str_comp ( " -s " , argv [ i ] ) = = 0 | | str_comp ( " --silent " , argv [ i ] ) = = 0 ) // ignore_convention
{
2017-09-03 08:37:24 +00:00
Silent = true ;
# if defined(CONF_FAMILY_WINDOWS)
2010-05-29 07:25:38 +00:00
ShowWindow ( GetConsoleWindow ( ) , SW_HIDE ) ;
2017-09-03 08:37:24 +00:00
# endif
2010-05-29 07:25:38 +00:00
break ;
}
}
2017-09-03 08:37:24 +00:00
2015-06-21 17:46:55 +00:00
if ( secure_random_init ( ) ! = 0 )
{
dbg_msg ( " secure " , " could not initialize secure RNG " ) ;
return - 1 ;
}
2021-01-26 20:22:32 +00:00
if ( MysqlInit ( ) ! = 0 )
{
dbg_msg ( " mysql " , " failed to initialize MySQL library " ) ;
return - 1 ;
}
2015-06-21 17:46:55 +00:00
2010-05-29 07:25:38 +00:00
CServer * pServer = CreateServer ( ) ;
IKernel * pKernel = IKernel : : Create ( ) ;
// create the components
2018-10-07 10:47:32 +00:00
IEngine * pEngine = CreateEngine ( " DDNet " , Silent , 2 ) ;
2010-05-29 07:25:38 +00:00
IEngineMap * pEngineMap = CreateEngineMap ( ) ;
IGameServer * pGameServer = CreateGameServer ( ) ;
2020-09-26 19:41:58 +00:00
IConsole * pConsole = CreateConsole ( CFGFLAG_SERVER | CFGFLAG_ECON ) ;
2010-05-29 07:25:38 +00:00
IEngineMasterServer * pEngineMasterServer = CreateEngineMasterServer ( ) ;
2012-01-09 00:38:45 +00:00
IStorage * pStorage = CreateStorage ( " Teeworlds " , IStorage : : STORAGETYPE_SERVER , argc , argv ) ; // ignore_convention
2021-01-10 12:47:07 +00:00
IConfigManager * pConfigManager = CreateConfigManager ( ) ;
2020-05-13 20:27:49 +00:00
IEngineAntibot * pEngineAntibot = CreateEngineAntibot ( ) ;
2011-04-13 18:37:12 +00:00
2021-01-10 12:47:07 +00:00
pServer - > InitRegister ( & pServer - > m_NetServer , pEngineMasterServer , pConfigManager - > Values ( ) , pConsole ) ;
2010-05-29 07:25:38 +00:00
{
bool RegisterFail = false ;
2017-07-21 17:46:31 +00:00
RegisterFail = RegisterFail | | ! pKernel - > RegisterInterface ( pServer ) ;
2011-02-27 14:03:57 +00:00
RegisterFail = RegisterFail | | ! pKernel - > RegisterInterface ( pEngine ) ;
2019-04-11 10:21:42 +00:00
RegisterFail = RegisterFail | | ! pKernel - > RegisterInterface ( pEngineMap ) ; // register as both
2020-09-26 19:41:58 +00:00
RegisterFail = RegisterFail | | ! pKernel - > RegisterInterface ( static_cast < IMap * > ( pEngineMap ) , false ) ;
2010-05-29 07:25:38 +00:00
RegisterFail = RegisterFail | | ! pKernel - > RegisterInterface ( pGameServer ) ;
RegisterFail = RegisterFail | | ! pKernel - > RegisterInterface ( pConsole ) ;
RegisterFail = RegisterFail | | ! pKernel - > RegisterInterface ( pStorage ) ;
2021-01-10 12:47:07 +00:00
RegisterFail = RegisterFail | | ! pKernel - > RegisterInterface ( pConfigManager ) ;
2019-04-11 10:21:42 +00:00
RegisterFail = RegisterFail | | ! pKernel - > RegisterInterface ( pEngineMasterServer ) ; // register as both
2020-09-26 19:41:58 +00:00
RegisterFail = RegisterFail | | ! pKernel - > RegisterInterface ( static_cast < IMasterServer * > ( pEngineMasterServer ) , false ) ;
2020-05-13 20:27:49 +00:00
RegisterFail = RegisterFail | | ! pKernel - > RegisterInterface ( pEngineAntibot ) ;
2020-09-26 19:41:58 +00:00
RegisterFail = RegisterFail | | ! pKernel - > RegisterInterface ( static_cast < IAntibot * > ( pEngineAntibot ) , false ) ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
if ( RegisterFail )
2017-07-21 17:46:31 +00:00
{
delete pKernel ;
2010-05-29 07:25:38 +00:00
return - 1 ;
2017-07-21 17:46:31 +00:00
}
2010-05-29 07:25:38 +00:00
}
2011-04-13 18:37:12 +00:00
2011-03-05 10:46:24 +00:00
pEngine - > Init ( ) ;
2021-01-10 12:47:07 +00:00
pConfigManager - > Init ( ) ;
2021-01-10 13:02:54 +00:00
pConsole - > Init ( ) ;
2011-02-27 14:03:57 +00:00
pEngineMasterServer - > Init ( ) ;
2010-05-29 07:25:38 +00:00
pEngineMasterServer - > Load ( ) ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
// register all console commands
pServer - > RegisterCommands ( ) ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
// execute autoexec file
2017-07-08 11:38:27 +00:00
IOHANDLE File = pStorage - > OpenFile ( AUTOEXEC_SERVER_FILE , IOFLAG_READ , IStorage : : TYPE_ALL ) ;
if ( File )
2015-08-12 11:49:16 +00:00
{
2017-07-08 11:38:27 +00:00
io_close ( File ) ;
2015-08-12 11:49:16 +00:00
pConsole - > ExecuteFile ( AUTOEXEC_SERVER_FILE ) ;
}
else // fallback
{
pConsole - > ExecuteFile ( AUTOEXEC_FILE ) ;
}
2010-05-29 07:25:38 +00:00
// parse the command line arguments
if ( argc > 1 ) // ignore_convention
2020-09-26 19:41:58 +00:00
pConsole - > ParseArguments ( argc - 1 , & argv [ 1 ] ) ; // ignore_convention
2010-08-10 22:31:42 +00:00
2020-10-17 15:29:33 +00:00
pConsole - > Register ( " sv_test_cmds " , " " , CFGFLAG_SERVER , CServer : : ConTestingCommands , pConsole , " Turns testing commands aka cheats on/off (setting only works in initial config) " ) ;
pConsole - > Register ( " sv_rescue " , " " , CFGFLAG_SERVER , CServer : : ConRescue , pConsole , " Allow /rescue command so players can teleport themselves out of freeze (setting only works in initial config) " ) ;
2011-02-27 14:03:57 +00:00
pEngine - > InitLogfile ( ) ;
2013-07-29 19:03:59 +00:00
2010-05-29 07:25:38 +00:00
// run the server
2011-02-27 14:03:57 +00:00
dbg_msg ( " server " , " starting... " ) ;
2019-07-10 13:59:55 +00:00
int Ret = pServer - > Run ( ) ;
2011-04-13 18:37:12 +00:00
2021-01-26 20:22:32 +00:00
MysqlUninit ( ) ;
2010-05-29 07:25:38 +00:00
// free
delete pKernel ;
2017-10-10 01:33:54 +00:00
2021-11-21 17:16:14 +00:00
cmdline_free ( argc , argv ) ;
2019-07-10 13:59:55 +00:00
return Ret ;
2010-05-29 07:25:38 +00:00
}
2011-04-09 06:41:31 +00:00
// DDRace
2021-02-08 21:26:26 +00:00
void CServer : : GetClientAddr ( int ClientID , NETADDR * pAddr ) const
2011-04-09 06:41:31 +00:00
{
2017-03-06 19:11:23 +00:00
if ( ClientID > = 0 & & ClientID < MAX_CLIENTS & & m_aClients [ ClientID ] . m_State = = CClient : : STATE_INGAME )
{
2012-02-02 23:16:22 +00:00
* pAddr = * m_NetServer . ClientAddr ( ClientID ) ;
2011-12-31 22:00:00 +00:00
}
2011-04-09 06:41:31 +00:00
}
2017-06-06 03:51:12 +00:00
const char * CServer : : GetAnnouncementLine ( char const * pFileName )
2010-11-22 10:59:25 +00:00
{
2021-12-17 20:58:28 +00:00
IOHANDLE File = m_pStorage - > OpenFile ( pFileName , IOFLAG_READ | IOFLAG_SKIP_BOM , IStorage : : TYPE_ALL ) ;
2017-07-08 11:38:27 +00:00
if ( ! File )
return 0 ;
2020-10-27 17:57:14 +00:00
std : : vector < char * > Lines ;
2017-07-08 11:38:27 +00:00
char * pLine ;
2020-10-27 17:57:14 +00:00
CLineReader Reader ;
Reader . Init ( File ) ;
while ( ( pLine = Reader . Get ( ) ) )
2017-07-08 11:38:27 +00:00
if ( str_length ( pLine ) )
2020-09-26 19:41:58 +00:00
if ( pLine [ 0 ] ! = ' # ' )
2020-10-27 17:57:14 +00:00
Lines . push_back ( pLine ) ;
2021-10-17 20:50:59 +00:00
if ( Lines . empty ( ) )
{
return 0 ;
}
else if ( Lines . size ( ) = = 1 )
2010-11-22 10:59:25 +00:00
{
2017-07-08 11:38:27 +00:00
m_AnnouncementLastLine = 0 ;
}
2021-12-14 23:28:51 +00:00
else if ( ! Config ( ) - > m_SvAnnouncementRandom )
2017-07-08 11:38:27 +00:00
{
2020-10-27 17:57:14 +00:00
if ( + + m_AnnouncementLastLine > = Lines . size ( ) )
m_AnnouncementLastLine % = Lines . size ( ) ;
2017-07-08 11:38:27 +00:00
}
else
{
unsigned Rand ;
do
2021-10-17 20:50:59 +00:00
{
2020-10-27 17:57:14 +00:00
Rand = rand ( ) % Lines . size ( ) ;
2021-10-17 20:50:59 +00:00
} while ( Rand = = m_AnnouncementLastLine ) ;
2011-04-09 06:41:31 +00:00
2017-07-08 11:38:27 +00:00
m_AnnouncementLastLine = Rand ;
2010-11-22 10:59:25 +00:00
}
2017-07-08 11:38:27 +00:00
io_close ( File ) ;
2020-10-27 17:57:14 +00:00
return Lines [ m_AnnouncementLastLine ] ;
2010-11-22 10:59:25 +00:00
}
2010-12-19 05:25:01 +00:00
2017-10-13 00:25:50 +00:00
int * CServer : : GetIdMap ( int ClientID )
2013-12-31 05:13:57 +00:00
{
2020-10-27 17:57:14 +00:00
return m_aIdMap + VANILLA_MAX_CLIENTS * ClientID ;
2013-12-31 05:13:57 +00:00
}
2017-06-06 03:51:12 +00:00
2017-10-13 00:25:50 +00:00
bool CServer : : SetTimedOut ( int ClientID , int OrigID )
{
2020-09-26 19:41:58 +00:00
if ( ! m_NetServer . SetTimedOut ( ClientID , OrigID ) )
2017-06-06 03:51:12 +00:00
{
return false ;
}
2020-06-20 16:50:14 +00:00
m_aClients [ ClientID ] . m_Sixup = m_aClients [ OrigID ] . m_Sixup ;
2021-01-17 16:44:48 +00:00
if ( m_aClients [ OrigID ] . m_Authed ! = AUTHED_NO )
{
LogoutClient ( ClientID , " Timeout Protection " ) ;
}
2017-06-06 03:51:12 +00:00
DelClientCallback ( OrigID , " Timeout Protection used " , this ) ;
2019-03-02 10:50:33 +00:00
m_aClients [ ClientID ] . m_Authed = AUTHED_NO ;
2019-07-25 23:39:53 +00:00
m_aClients [ ClientID ] . m_Flags = m_aClients [ OrigID ] . m_Flags ;
2021-12-14 05:50:30 +00:00
m_aClients [ ClientID ] . m_DDNetVersion = m_aClients [ OrigID ] . m_DDNetVersion ;
m_aClients [ ClientID ] . m_GotDDNetVersionPacket = m_aClients [ OrigID ] . m_GotDDNetVersionPacket ;
m_aClients [ ClientID ] . m_DDNetVersionSettled = m_aClients [ OrigID ] . m_DDNetVersionSettled ;
2017-06-06 03:51:12 +00:00
return true ;
}
2017-10-13 00:25:50 +00:00
void CServer : : SetErrorShutdown ( const char * pReason )
{
str_copy ( m_aErrorShutdownReason , pReason , sizeof ( m_aErrorShutdownReason ) ) ;
}