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. */
2023-02-23 09:48:11 +00:00
# include "gamecontext.h"
2022-05-23 15:47:48 +00:00
# include <vector>
2011-08-31 11:56:04 +00:00
2020-09-26 19:41:58 +00:00
# include "teeinfo.h"
2020-03-11 00:58:50 +00:00
# include <antibot/antibot_data.h>
2022-04-22 23:04:48 +00:00
# include <base/logger.h>
2020-09-26 19:41:58 +00:00
# include <base/math.h>
2023-02-23 09:48:11 +00:00
# include <base/system.h>
2010-05-29 07:25:38 +00:00
# include <engine/console.h>
2018-06-19 12:45:53 +00:00
# include <engine/engine.h>
2020-09-26 19:41:58 +00:00
# include <engine/map.h>
2018-08-16 19:42:10 +00:00
# include <engine/server/server.h>
2020-09-26 19:41:58 +00:00
# include <engine/shared/config.h>
2015-07-14 20:08:29 +00:00
# include <engine/shared/datafile.h>
2022-11-14 07:04:34 +00:00
# include <engine/shared/json.h>
2015-07-14 20:08:29 +00:00
# include <engine/shared/linereader.h>
2021-01-09 13:40:30 +00:00
# include <engine/shared/memheap.h>
2015-07-14 20:08:29 +00:00
# include <engine/storage.h>
2022-06-16 16:06:35 +00:00
2010-05-29 07:25:38 +00:00
# include <game/collision.h>
2014-03-12 23:31:50 +00:00
# include <game/gamecore.h>
2022-06-16 16:06:35 +00:00
# include <game/mapitems.h>
2020-09-26 19:41:58 +00:00
# include <game/version.h>
2008-08-14 18:42:47 +00:00
2020-04-16 08:46:43 +00:00
# include <game/generated/protocol7.h>
# include <game/generated/protocolglue.h>
2021-01-09 14:18:52 +00:00
# include "entities/character.h"
2011-04-09 06:41:31 +00:00
# include "gamemodes/DDRace.h"
2023-11-16 10:39:55 +00:00
# include "gamemodes/mod.h"
2021-01-09 14:37:02 +00:00
# include "player.h"
2010-08-23 19:37:27 +00:00
# include "score.h"
2022-04-22 23:04:48 +00:00
// Not thread-safe!
class CClientChatLogger : public ILogger
{
CGameContext * m_pGameServer ;
int m_ClientID ;
2022-05-01 09:13:30 +00:00
ILogger * m_pOuterLogger ;
2022-04-22 23:04:48 +00:00
public :
2022-05-01 09:13:30 +00:00
CClientChatLogger ( CGameContext * pGameServer , int ClientID , ILogger * pOuterLogger ) :
2022-04-22 23:04:48 +00:00
m_pGameServer ( pGameServer ) ,
2022-05-01 09:13:30 +00:00
m_ClientID ( ClientID ) ,
m_pOuterLogger ( pOuterLogger )
2022-04-22 23:04:48 +00:00
{
}
void Log ( const CLogMessage * pMessage ) override ;
} ;
void CClientChatLogger : : Log ( const CLogMessage * pMessage )
{
2022-05-01 09:13:30 +00:00
if ( str_comp ( pMessage - > m_aSystem , " chatresp " ) = = 0 )
{
2022-06-13 19:43:05 +00:00
if ( m_Filter . Filters ( pMessage ) )
{
return ;
}
2022-05-01 09:13:30 +00:00
m_pGameServer - > SendChatTarget ( m_ClientID , pMessage - > Message ( ) ) ;
}
else
{
m_pOuterLogger - > Log ( pMessage ) ;
}
2022-04-22 23:04:48 +00:00
}
2010-05-29 07:25:38 +00:00
enum
{
RESET ,
NO_RESET
} ;
2008-08-14 18:42:47 +00:00
2010-05-29 07:25:38 +00:00
void CGameContext : : Construct ( int Resetting )
2008-08-14 18:42:47 +00:00
{
2021-07-22 19:49:26 +00:00
m_Resetting = false ;
2010-05-29 07:25:38 +00:00
m_pServer = 0 ;
2011-04-13 18:37:12 +00:00
2020-10-26 14:14:07 +00:00
for ( auto & pPlayer : m_apPlayers )
pPlayer = 0 ;
2011-04-13 18:37:12 +00:00
2022-03-27 11:31:07 +00:00
mem_zero ( & m_aLastPlayerInput , sizeof ( m_aLastPlayerInput ) ) ;
mem_zero ( & m_aPlayerHasInput , sizeof ( m_aPlayerHasInput ) ) ;
2010-05-29 07:25:38 +00:00
m_pController = 0 ;
2021-07-22 19:49:26 +00:00
m_aVoteCommand [ 0 ] = 0 ;
2020-07-01 12:02:47 +00:00
m_VoteType = VOTE_TYPE_UNKNOWN ;
2010-05-29 07:25:38 +00:00
m_VoteCloseTime = 0 ;
m_pVoteOptionFirst = 0 ;
m_pVoteOptionLast = 0 ;
2011-03-26 21:06:29 +00:00
m_NumVoteOptions = 0 ;
2014-03-04 01:48:58 +00:00
m_LastMapVote = 0 ;
2010-05-29 07:25:38 +00:00
2020-06-21 22:45:17 +00:00
m_SqlRandomMapResult = nullptr ;
2021-06-29 20:32:21 +00:00
m_pScore = nullptr ;
m_NumMutes = 0 ;
m_NumVoteMutes = 0 ;
2023-07-15 14:09:10 +00:00
m_LatestLog = 0 ;
mem_zero ( & m_aLogs , sizeof ( m_aLogs ) ) ;
2022-11-29 10:47:36 +00:00
2020-09-26 19:41:58 +00:00
if ( Resetting = = NO_RESET )
2022-02-09 16:07:02 +00:00
{
m_NonEmptySince = 0 ;
2010-05-29 07:25:38 +00:00
m_pVoteOptionHeap = new CHeap ( ) ;
2022-02-09 16:07:02 +00:00
}
2021-06-29 20:32:21 +00:00
2015-07-14 20:08:29 +00:00
m_aDeleteTempfile [ 0 ] = 0 ;
2017-09-12 12:58:44 +00:00
m_TeeHistorianActive = false ;
2010-05-29 07:25:38 +00:00
}
2021-06-29 20:32:21 +00:00
void CGameContext : : Destruct ( int Resetting )
2010-05-29 07:25:38 +00:00
{
2021-06-29 20:32:21 +00:00
for ( auto & pPlayer : m_apPlayers )
delete pPlayer ;
if ( Resetting = = NO_RESET )
delete m_pVoteOptionHeap ;
if ( m_pScore )
{
delete m_pScore ;
m_pScore = nullptr ;
}
2010-05-29 07:25:38 +00:00
}
CGameContext : : CGameContext ( )
{
Construct ( NO_RESET ) ;
2008-09-23 07:43:41 +00:00
}
2021-07-22 19:49:26 +00:00
CGameContext : : CGameContext ( int Reset )
{
Construct ( Reset ) ;
}
2010-05-29 07:25:38 +00:00
CGameContext : : ~ CGameContext ( )
2008-09-23 07:43:41 +00:00
{
2021-07-22 19:49:26 +00:00
Destruct ( m_Resetting ? RESET : NO_RESET ) ;
2008-08-14 18:42:47 +00:00
}
2010-05-29 07:25:38 +00:00
void CGameContext : : Clear ( )
2008-08-14 18:42:47 +00:00
{
2010-05-29 07:25:38 +00:00
CHeap * pVoteOptionHeap = m_pVoteOptionHeap ;
2011-03-26 16:44:34 +00:00
CVoteOptionServer * pVoteOptionFirst = m_pVoteOptionFirst ;
CVoteOptionServer * pVoteOptionLast = m_pVoteOptionLast ;
2011-03-26 21:06:29 +00:00
int NumVoteOptions = m_NumVoteOptions ;
2010-05-29 07:25:38 +00:00
CTuningParams Tuning = m_Tuning ;
2021-07-22 19:49:26 +00:00
m_Resetting = true ;
this - > ~ CGameContext ( ) ;
new ( this ) CGameContext ( RESET ) ;
2010-05-29 07:25:38 +00:00
m_pVoteOptionHeap = pVoteOptionHeap ;
m_pVoteOptionFirst = pVoteOptionFirst ;
m_pVoteOptionLast = pVoteOptionLast ;
2011-03-26 21:06:29 +00:00
m_NumVoteOptions = NumVoteOptions ;
2010-05-29 07:25:38 +00:00
m_Tuning = Tuning ;
2008-08-14 18:42:47 +00:00
}
2017-09-12 12:58:44 +00:00
void CGameContext : : TeeHistorianWrite ( const void * pData , int DataSize , void * pUser )
{
CGameContext * pSelf = ( CGameContext * ) pUser ;
2017-10-13 00:48:42 +00:00
aio_write ( pSelf - > m_pTeeHistorianFile , pData , DataSize ) ;
2017-09-12 12:58:44 +00:00
}
2017-09-13 20:35:09 +00:00
void CGameContext : : CommandCallback ( int ClientID , int FlagMask , const char * pCmd , IConsole : : IResult * pResult , void * pUser )
{
CGameContext * pSelf = ( CGameContext * ) pUser ;
if ( pSelf - > m_TeeHistorianActive )
{
pSelf - > m_TeeHistorian . RecordConsoleCommand ( ClientID , FlagMask , pCmd , pResult ) ;
}
}
2022-05-18 08:45:31 +00:00
CNetObj_PlayerInput CGameContext : : GetLastPlayerInput ( int ClientID ) const
{
dbg_assert ( 0 < = ClientID & & ClientID < MAX_CLIENTS , " invalid ClientID " ) ;
return m_aLastPlayerInput [ ClientID ] ;
}
2011-02-12 10:40:36 +00:00
class CCharacter * CGameContext : : GetPlayerChar ( int ClientID )
2008-10-20 23:00:46 +00:00
{
2011-02-12 10:40:36 +00:00
if ( ClientID < 0 | | ClientID > = MAX_CLIENTS | | ! m_apPlayers [ ClientID ] )
2008-10-20 23:00:46 +00:00
return 0 ;
2011-02-12 10:40:36 +00:00
return m_apPlayers [ ClientID ] - > GetCharacter ( ) ;
2008-10-20 23:00:46 +00:00
}
2018-03-24 13:00:41 +00:00
bool CGameContext : : EmulateBug ( int Bug )
{
return m_MapBugs . Contains ( Bug ) ;
}
2020-05-13 20:27:49 +00:00
void CGameContext : : FillAntibot ( CAntibotRoundData * pData )
2020-03-11 00:58:50 +00:00
{
if ( ! pData - > m_Map . m_pTiles )
{
Collision ( ) - > FillAntibot ( & pData - > m_Map ) ;
}
pData - > m_Tick = Server ( ) - > Tick ( ) ;
mem_zero ( pData - > m_aCharacters , sizeof ( pData - > m_aCharacters ) ) ;
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
{
CAntibotCharacterData * pChar = & pData - > m_aCharacters [ i ] ;
2020-10-26 14:14:07 +00:00
for ( auto & LatestInput : pChar - > m_aLatestInputs )
2020-03-11 00:58:50 +00:00
{
2020-10-26 14:14:07 +00:00
LatestInput . m_TargetX = - 1 ;
LatestInput . m_TargetY = - 1 ;
2020-03-11 00:58:50 +00:00
}
pChar - > m_Alive = false ;
pChar - > m_Pause = false ;
pChar - > m_Team = - 1 ;
pChar - > m_Pos = vec2 ( - 1 , - 1 ) ;
pChar - > m_Vel = vec2 ( 0 , 0 ) ;
pChar - > m_Angle = - 1 ;
pChar - > m_HookedPlayer = - 1 ;
pChar - > m_SpawnTick = - 1 ;
pChar - > m_WeaponChangeTick = - 1 ;
if ( m_apPlayers [ i ] )
{
str_copy ( pChar - > m_aName , Server ( ) - > ClientName ( i ) , sizeof ( pChar - > m_aName ) ) ;
CCharacter * pGameChar = m_apPlayers [ i ] - > GetCharacter ( ) ;
pChar - > m_Alive = ( bool ) pGameChar ;
pChar - > m_Pause = m_apPlayers [ i ] - > IsPaused ( ) ;
pChar - > m_Team = m_apPlayers [ i ] - > GetTeam ( ) ;
if ( pGameChar )
{
pGameChar - > FillAntibot ( pChar ) ;
}
}
}
}
2023-01-24 08:27:29 +00:00
void CGameContext : : CreateDamageInd ( vec2 Pos , float Angle , int Amount , CClientMask Mask )
2008-08-14 18:42:47 +00:00
{
2022-11-06 09:48:06 +00:00
float a = 3 * pi / 2 + Angle ;
2008-08-14 18:42:47 +00:00
//float a = get_angle(dir);
2020-09-26 19:41:58 +00:00
float s = a - pi / 3 ;
float e = a + pi / 3 ;
2010-05-29 07:25:38 +00:00
for ( int i = 0 ; i < Amount ; i + + )
2008-08-14 18:42:47 +00:00
{
2022-11-06 09:47:41 +00:00
float f = mix ( s , e , ( i + 1 ) / ( float ) ( Amount + 2 ) ) ;
2023-02-10 18:34:57 +00:00
CNetEvent_DamageInd * pEvent = m_Events . Create < CNetEvent_DamageInd > ( Mask ) ;
2011-02-12 10:40:36 +00:00
if ( pEvent )
2008-08-14 18:42:47 +00:00
{
2011-02-12 10:40:36 +00:00
pEvent - > m_X = ( int ) Pos . x ;
pEvent - > m_Y = ( int ) Pos . y ;
2020-09-26 19:41:58 +00:00
pEvent - > m_Angle = ( int ) ( f * 256.0f ) ;
2008-08-14 18:42:47 +00:00
}
}
}
2023-01-24 08:27:29 +00:00
void CGameContext : : CreateHammerHit ( vec2 Pos , CClientMask Mask )
2008-10-17 11:23:21 +00:00
{
// create the event
2023-02-10 18:34:57 +00:00
CNetEvent_HammerHit * pEvent = m_Events . Create < CNetEvent_HammerHit > ( Mask ) ;
2011-02-12 10:40:36 +00:00
if ( pEvent )
2008-10-17 11:23:21 +00:00
{
2011-02-12 10:40:36 +00:00
pEvent - > m_X = ( int ) Pos . x ;
pEvent - > m_Y = ( int ) Pos . y ;
2008-10-17 11:23:21 +00:00
}
}
2023-01-24 08:27:29 +00:00
void CGameContext : : CreateExplosion ( vec2 Pos , int Owner , int Weapon , bool NoDamage , int ActivatedTeam , CClientMask Mask )
2008-08-14 18:42:47 +00:00
{
// create the event
2023-02-10 18:34:57 +00:00
CNetEvent_Explosion * pEvent = m_Events . Create < CNetEvent_Explosion > ( Mask ) ;
2011-02-12 10:40:36 +00:00
if ( pEvent )
2008-08-14 18:42:47 +00:00
{
2011-02-12 10:40:36 +00:00
pEvent - > m_X = ( int ) Pos . x ;
pEvent - > m_Y = ( int ) Pos . y ;
2008-08-14 18:42:47 +00:00
}
2014-04-13 14:41:02 +00:00
2019-04-24 20:36:47 +00:00
// deal damage
2022-11-09 22:07:15 +00:00
CEntity * apEnts [ MAX_CLIENTS ] ;
2019-04-24 20:36:47 +00:00
float Radius = 135.0f ;
float InnerRadius = 48.0f ;
2022-11-09 22:07:15 +00:00
int Num = m_World . FindEntities ( Pos , Radius , apEnts , MAX_CLIENTS , CGameWorld : : ENTTYPE_CHARACTER ) ;
2023-01-24 08:27:29 +00:00
CClientMask TeamMask = CClientMask ( ) . set ( ) ;
2019-04-24 20:36:47 +00:00
for ( int i = 0 ; i < Num ; i + + )
{
2022-11-09 22:07:15 +00:00
auto * pChr = static_cast < CCharacter * > ( apEnts [ i ] ) ;
vec2 Diff = pChr - > m_Pos - Pos ;
2020-09-26 19:41:58 +00:00
vec2 ForceDir ( 0 , 1 ) ;
2019-04-24 20:36:47 +00:00
float l = length ( Diff ) ;
if ( l )
ForceDir = normalize ( Diff ) ;
2020-09-26 19:41:58 +00:00
l = 1 - clamp ( ( l - InnerRadius ) / ( Radius - InnerRadius ) , 0.0f , 1.0f ) ;
2019-04-24 20:36:47 +00:00
float Strength ;
2020-09-26 19:41:58 +00:00
if ( Owner = = - 1 | | ! m_apPlayers [ Owner ] | | ! m_apPlayers [ Owner ] - > m_TuneZone )
2019-04-24 20:36:47 +00:00
Strength = Tuning ( ) - > m_ExplosionStrength ;
else
Strength = TuningList ( ) [ m_apPlayers [ Owner ] - > m_TuneZone ] . m_ExplosionStrength ;
2018-04-04 17:48:46 +00:00
2019-04-24 20:36:47 +00:00
float Dmg = Strength * l ;
2020-09-26 19:41:58 +00:00
if ( ! ( int ) Dmg )
continue ;
2018-04-04 17:48:46 +00:00
2022-11-09 22:07:15 +00:00
if ( ( GetPlayerChar ( Owner ) ? ! GetPlayerChar ( Owner ) - > GrenadeHitDisabled ( ) : g_Config . m_SvHit ) | | NoDamage | | Owner = = pChr - > GetPlayer ( ) - > GetCID ( ) )
2019-04-24 20:36:47 +00:00
{
2022-11-09 22:07:15 +00:00
if ( Owner ! = - 1 & & pChr - > IsAlive ( ) & & ! pChr - > CanCollide ( Owner ) )
2020-09-26 19:41:58 +00:00
continue ;
2022-11-09 22:07:15 +00:00
if ( Owner = = - 1 & & ActivatedTeam ! = - 1 & & pChr - > IsAlive ( ) & & pChr - > Team ( ) ! = ActivatedTeam )
2020-09-26 19:41:58 +00:00
continue ;
2018-04-04 17:48:46 +00:00
2019-04-24 20:36:47 +00:00
// Explode at most once per team
2022-11-09 22:07:15 +00:00
int PlayerTeam = pChr - > Team ( ) ;
2022-07-08 13:31:58 +00:00
if ( ( GetPlayerChar ( Owner ) ? GetPlayerChar ( Owner ) - > GrenadeHitDisabled ( ) : ! g_Config . m_SvHit ) | | NoDamage )
2019-04-24 20:36:47 +00:00
{
2023-05-24 11:34:15 +00:00
if ( PlayerTeam = = TEAM_SUPER )
continue ;
2023-01-24 08:27:29 +00:00
if ( ! TeamMask . test ( PlayerTeam ) )
2020-09-26 19:41:58 +00:00
continue ;
2023-01-24 08:27:29 +00:00
TeamMask . reset ( PlayerTeam ) ;
2018-04-04 18:03:05 +00:00
}
2008-08-14 18:42:47 +00:00
2022-11-09 22:07:15 +00:00
pChr - > TakeDamage ( ForceDir * Dmg * 2 , ( int ) Dmg , Owner , Weapon ) ;
2019-04-24 20:36:47 +00:00
}
2008-08-14 18:42:47 +00:00
}
2019-04-24 20:36:47 +00:00
}
2008-08-14 18:42:47 +00:00
2023-01-24 08:27:29 +00:00
void CGameContext : : CreatePlayerSpawn ( vec2 Pos , CClientMask Mask )
2008-08-14 18:42:47 +00:00
{
// create the event
2023-02-10 18:34:57 +00:00
CNetEvent_Spawn * pEvent = m_Events . Create < CNetEvent_Spawn > ( Mask ) ;
2022-06-30 22:36:32 +00:00
if ( pEvent )
2008-08-14 18:42:47 +00:00
{
2022-06-30 22:36:32 +00:00
pEvent - > m_X = ( int ) Pos . x ;
pEvent - > m_Y = ( int ) Pos . y ;
2008-08-14 18:42:47 +00:00
}
}
2023-01-24 08:27:29 +00:00
void CGameContext : : CreateDeath ( vec2 Pos , int ClientID , CClientMask Mask )
2008-08-14 18:42:47 +00:00
{
// create the event
2023-02-10 18:34:57 +00:00
CNetEvent_Death * pEvent = m_Events . Create < CNetEvent_Death > ( Mask ) ;
2011-02-12 10:40:36 +00:00
if ( pEvent )
2008-08-14 18:42:47 +00:00
{
2011-02-12 10:40:36 +00:00
pEvent - > m_X = ( int ) Pos . x ;
pEvent - > m_Y = ( int ) Pos . y ;
pEvent - > m_ClientID = ClientID ;
2008-08-14 18:42:47 +00:00
}
}
2023-01-24 08:27:29 +00:00
void CGameContext : : CreateSound ( vec2 Pos , int Sound , CClientMask Mask )
2008-08-14 18:42:47 +00:00
{
2020-09-26 19:41:58 +00:00
if ( Sound < 0 )
2008-08-14 18:42:47 +00:00
return ;
// create a sound
2023-02-10 18:34:57 +00:00
CNetEvent_SoundWorld * pEvent = m_Events . Create < CNetEvent_SoundWorld > ( Mask ) ;
2011-02-12 10:40:36 +00:00
if ( pEvent )
2008-08-14 18:42:47 +00:00
{
2011-02-12 10:40:36 +00:00
pEvent - > m_X = ( int ) Pos . x ;
pEvent - > m_Y = ( int ) Pos . y ;
pEvent - > m_SoundID = Sound ;
2008-08-14 18:42:47 +00:00
}
}
2010-05-29 07:25:38 +00:00
void CGameContext : : CreateSoundGlobal ( int Sound , int Target )
2008-08-14 18:42:47 +00:00
{
2020-09-26 19:41:58 +00:00
if ( Sound < 0 )
2008-08-14 18:42:47 +00:00
return ;
2010-05-29 07:25:38 +00:00
CNetMsg_Sv_SoundGlobal Msg ;
2011-02-12 10:40:36 +00:00
Msg . m_SoundID = Sound ;
2011-12-29 12:56:24 +00:00
if ( Target = = - 2 )
Server ( ) - > SendPackMsg ( & Msg , MSGFLAG_NOSEND , - 1 ) ;
else
{
int Flag = MSGFLAG_VITAL ;
if ( Target ! = - 1 )
Flag | = MSGFLAG_NORECORD ;
Server ( ) - > SendPackMsg ( & Msg , Flag , Target ) ;
}
2008-08-14 18:42:47 +00:00
}
2023-05-04 21:34:57 +00:00
bool CGameContext : : SnapLaserObject ( const CSnapContext & Context , int SnapID , const vec2 & To , const vec2 & From , int StartTick , int Owner , int LaserType , int Subtype , int SwitchNumber )
2023-02-10 20:04:59 +00:00
{
if ( Context . GetClientVersion ( ) > = VERSION_DDNET_MULTI_LASER )
{
2023-02-10 18:34:57 +00:00
CNetObj_DDNetLaser * pObj = Server ( ) - > SnapNewItem < CNetObj_DDNetLaser > ( SnapID ) ;
2023-02-10 20:04:59 +00:00
if ( ! pObj )
return false ;
pObj - > m_ToX = ( int ) To . x ;
pObj - > m_ToY = ( int ) To . y ;
pObj - > m_FromX = ( int ) From . x ;
pObj - > m_FromY = ( int ) From . y ;
pObj - > m_StartTick = StartTick ;
pObj - > m_Owner = Owner ;
pObj - > m_Type = LaserType ;
2023-05-04 21:34:57 +00:00
pObj - > m_Subtype = Subtype ;
pObj - > m_SwitchNumber = SwitchNumber ;
2023-09-19 21:22:15 +00:00
pObj - > m_Flags = 0 ;
2023-02-10 20:04:59 +00:00
}
else
{
2023-02-10 18:34:57 +00:00
CNetObj_Laser * pObj = Server ( ) - > SnapNewItem < CNetObj_Laser > ( SnapID ) ;
2023-02-10 20:04:59 +00:00
if ( ! pObj )
return false ;
pObj - > m_X = ( int ) To . x ;
pObj - > m_Y = ( int ) To . y ;
pObj - > m_FromX = ( int ) From . x ;
pObj - > m_FromY = ( int ) From . y ;
pObj - > m_StartTick = StartTick ;
}
return true ;
}
2023-05-04 21:34:57 +00:00
bool CGameContext : : SnapPickup ( const CSnapContext & Context , int SnapID , const vec2 & Pos , int Type , int SubType , int SwitchNumber )
2023-02-10 20:09:27 +00:00
{
if ( Context . IsSixup ( ) )
{
protocol7 : : CNetObj_Pickup * pPickup = Server ( ) - > SnapNewItem < protocol7 : : CNetObj_Pickup > ( SnapID ) ;
if ( ! pPickup )
return false ;
pPickup - > m_X = ( int ) Pos . x ;
pPickup - > m_Y = ( int ) Pos . y ;
if ( Type = = POWERUP_WEAPON )
pPickup - > m_Type = SubType = = WEAPON_SHOTGUN ? protocol7 : : PICKUP_SHOTGUN : SubType = = WEAPON_GRENADE ? protocol7 : : PICKUP_GRENADE : protocol7 : : PICKUP_LASER ;
else if ( Type = = POWERUP_NINJA )
pPickup - > m_Type = protocol7 : : PICKUP_NINJA ;
}
2023-05-04 21:34:57 +00:00
else if ( Context . GetClientVersion ( ) > = VERSION_DDNET_ENTITY_NETOBJS )
{
CNetObj_DDNetPickup * pPickup = Server ( ) - > SnapNewItem < CNetObj_DDNetPickup > ( SnapID ) ;
if ( ! pPickup )
return false ;
pPickup - > m_X = ( int ) Pos . x ;
pPickup - > m_Y = ( int ) Pos . y ;
pPickup - > m_Type = Type ;
pPickup - > m_Subtype = SubType ;
pPickup - > m_SwitchNumber = SwitchNumber ;
}
2023-02-10 20:09:27 +00:00
else
{
CNetObj_Pickup * pPickup = Server ( ) - > SnapNewItem < CNetObj_Pickup > ( SnapID ) ;
if ( ! pPickup )
return false ;
pPickup - > m_X = ( int ) Pos . x ;
pPickup - > m_Y = ( int ) Pos . y ;
pPickup - > m_Type = Type ;
if ( Context . GetClientVersion ( ) < VERSION_DDNET_WEAPON_SHIELDS )
{
if ( Type > = POWERUP_ARMOR_SHOTGUN & & Type < = POWERUP_ARMOR_LASER )
{
pPickup - > m_Type = POWERUP_ARMOR ;
}
}
pPickup - > m_Subtype = SubType ;
}
return true ;
}
2020-08-04 17:14:37 +00:00
void CGameContext : : CallVote ( int ClientID , const char * pDesc , const char * pCmd , const char * pReason , const char * pChatmsg , const char * pSixupDesc )
2014-02-19 20:22:36 +00:00
{
// check if a vote is already running
if ( m_VoteCloseTime )
return ;
2021-06-23 05:05:49 +00:00
int64_t Now = Server ( ) - > Tick ( ) ;
2014-02-19 20:22:36 +00:00
CPlayer * pPlayer = m_apPlayers [ ClientID ] ;
2014-05-18 23:57:52 +00:00
if ( ! pPlayer )
return ;
2020-08-04 17:14:37 +00:00
SendChat ( - 1 , CGameContext : : CHAT_ALL , pChatmsg , - 1 , CHAT_SIX ) ;
if ( ! pSixupDesc )
pSixupDesc = pDesc ;
2020-09-30 14:48:42 +00:00
m_VoteCreator = ClientID ;
2020-08-04 17:14:37 +00:00
StartVote ( pDesc , pCmd , pReason , pSixupDesc ) ;
2014-02-19 20:22:36 +00:00
pPlayer - > m_Vote = 1 ;
pPlayer - > m_VotePos = m_VotePos = 1 ;
pPlayer - > m_LastVoteCall = Now ;
}
2020-06-22 15:08:08 +00:00
void CGameContext : : SendChatTarget ( int To , const char * pText , int Flags )
2009-01-11 14:28:35 +00:00
{
2010-05-29 07:25:38 +00:00
CNetMsg_Sv_Chat Msg ;
Msg . m_Team = 0 ;
2011-02-12 10:40:36 +00:00
Msg . m_ClientID = - 1 ;
2010-05-29 07:25:38 +00:00
Msg . m_pMessage = pText ;
2020-06-24 15:50:22 +00:00
2020-06-24 16:22:41 +00:00
if ( g_Config . m_SvDemoChat )
2023-02-03 18:05:57 +00:00
Server ( ) - > SendPackMsg ( & Msg , MSGFLAG_VITAL | MSGFLAG_NOSEND , SERVER_DEMO_CLIENT ) ;
2020-06-24 16:22:41 +00:00
2020-06-24 15:50:22 +00:00
if ( To = = - 1 )
{
2022-02-21 15:33:51 +00:00
for ( int i = 0 ; i < Server ( ) - > MaxClients ( ) ; i + + )
2020-06-24 15:50:22 +00:00
{
if ( ! ( ( Server ( ) - > IsSixup ( i ) & & ( Flags & CHAT_SIXUP ) ) | |
2020-09-26 19:41:58 +00:00
( ! Server ( ) - > IsSixup ( i ) & & ( Flags & CHAT_SIX ) ) ) )
2020-06-24 15:50:22 +00:00
continue ;
2020-09-26 19:41:58 +00:00
Server ( ) - > SendPackMsg ( & Msg , MSGFLAG_VITAL | MSGFLAG_NORECORD , i ) ;
2020-06-24 15:50:22 +00:00
}
}
2014-09-26 00:40:58 +00:00
else
2020-06-24 15:50:22 +00:00
{
if ( ! ( ( Server ( ) - > IsSixup ( To ) & & ( Flags & CHAT_SIXUP ) ) | |
2020-09-26 19:41:58 +00:00
( ! Server ( ) - > IsSixup ( To ) & & ( Flags & CHAT_SIX ) ) ) )
2020-06-24 15:50:22 +00:00
return ;
2020-09-26 19:41:58 +00:00
Server ( ) - > SendPackMsg ( & Msg , MSGFLAG_VITAL | MSGFLAG_NORECORD , To ) ;
2020-06-24 15:50:22 +00:00
}
2009-01-11 14:28:35 +00:00
}
2014-07-26 12:46:31 +00:00
void CGameContext : : SendChatTeam ( int Team , const char * pText )
{
2020-09-26 19:41:58 +00:00
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
2023-11-15 20:28:19 +00:00
if ( m_apPlayers [ i ] ! = nullptr & & GetDDRaceTeam ( i ) = = Team )
2014-07-26 12:46:31 +00:00
SendChatTarget ( i , pText ) ;
}
2020-06-12 13:25:58 +00:00
void CGameContext : : SendChat ( int ChatterClientID , int Team , const char * pText , int SpamProtectionClientID , int Flags )
2008-08-14 18:42:47 +00:00
{
2011-02-13 05:35:13 +00:00
if ( SpamProtectionClientID > = 0 & & SpamProtectionClientID < MAX_CLIENTS )
2011-02-23 21:39:53 +00:00
if ( ProcessSpamProtection ( SpamProtectionClientID ) )
2010-11-10 21:42:29 +00:00
return ;
2011-04-09 06:41:31 +00:00
char aBuf [ 256 ] , aText [ 256 ] ;
2010-11-19 16:57:53 +00:00
str_copy ( aText , pText , sizeof ( aText ) ) ;
2011-02-12 10:40:36 +00:00
if ( ChatterClientID > = 0 & & ChatterClientID < MAX_CLIENTS )
2011-02-13 05:35:13 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " %d:%d:%s: %s " , ChatterClientID , Team , Server ( ) - > ClientName ( ChatterClientID ) , aText ) ;
else if ( ChatterClientID = = - 2 )
2010-11-19 16:57:53 +00:00
{
str_format ( aBuf , sizeof ( aBuf ) , " ### %s " , aText ) ;
str_copy ( aText , aBuf , sizeof ( aText ) ) ;
2011-02-13 05:35:13 +00:00
ChatterClientID = - 1 ;
2010-11-19 16:57:53 +00:00
}
2008-08-14 18:42:47 +00:00
else
2010-11-19 16:57:53 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " *** %s " , aText ) ;
2022-06-02 07:36:31 +00:00
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , Team ! = CHAT_ALL ? " teamchat " : " chat " , aBuf ) ;
2008-08-14 18:42:47 +00:00
2010-05-29 07:25:38 +00:00
if ( Team = = CHAT_ALL )
2008-08-14 18:42:47 +00:00
{
2010-05-29 07:25:38 +00:00
CNetMsg_Sv_Chat Msg ;
Msg . m_Team = 0 ;
2011-02-12 10:40:36 +00:00
Msg . m_ClientID = ChatterClientID ;
2011-04-09 06:41:31 +00:00
Msg . m_pMessage = aText ;
2013-12-22 17:30:13 +00:00
// pack one for the recording only
2014-09-26 00:40:58 +00:00
if ( g_Config . m_SvDemoChat )
2023-02-03 18:05:57 +00:00
Server ( ) - > SendPackMsg ( & Msg , MSGFLAG_VITAL | MSGFLAG_NOSEND , SERVER_DEMO_CLIENT ) ;
2013-12-22 17:30:13 +00:00
// send to the clients
2022-02-21 15:33:51 +00:00
for ( int i = 0 ; i < Server ( ) - > MaxClients ( ) ; i + + )
2013-12-22 17:30:13 +00:00
{
2020-06-30 15:57:49 +00:00
if ( ! m_apPlayers [ i ] )
continue ;
2020-06-12 19:22:54 +00:00
bool Send = ( Server ( ) - > IsSixup ( i ) & & ( Flags & CHAT_SIXUP ) ) | |
2020-09-26 19:41:58 +00:00
( ! Server ( ) - > IsSixup ( i ) & & ( Flags & CHAT_SIX ) ) ;
2020-06-12 19:22:54 +00:00
2020-06-30 15:57:49 +00:00
if ( ! m_apPlayers [ i ] - > m_DND & & Send )
2020-09-26 19:41:58 +00:00
Server ( ) - > SendPackMsg ( & Msg , MSGFLAG_VITAL | MSGFLAG_NORECORD , i ) ;
2013-12-22 17:30:13 +00:00
}
2022-11-29 10:47:36 +00:00
2023-11-19 21:36:47 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " Chat: %s " , aText ) ;
2022-11-29 10:47:36 +00:00
LogEvent ( aBuf , ChatterClientID ) ;
2008-08-14 18:42:47 +00:00
}
else
{
2023-11-15 20:28:19 +00:00
CTeamsCore * pTeams = & m_pController - > Teams ( ) . m_Core ;
2010-05-29 07:25:38 +00:00
CNetMsg_Sv_Chat Msg ;
Msg . m_Team = 1 ;
2011-02-12 10:40:36 +00:00
Msg . m_ClientID = ChatterClientID ;
2011-04-09 06:41:31 +00:00
Msg . m_pMessage = aText ;
2011-04-13 18:37:12 +00:00
2009-06-15 13:01:04 +00:00
// pack one for the recording only
2014-09-26 00:40:58 +00:00
if ( g_Config . m_SvDemoChat )
2023-02-03 18:05:57 +00:00
Server ( ) - > SendPackMsg ( & Msg , MSGFLAG_VITAL | MSGFLAG_NOSEND , SERVER_DEMO_CLIENT ) ;
2011-01-29 00:59:50 +00:00
2009-06-15 13:01:04 +00:00
// send to the clients
2022-02-21 15:33:51 +00:00
for ( int i = 0 ; i < Server ( ) - > MaxClients ( ) ; i + + )
2008-08-14 18:42:47 +00:00
{
2020-09-26 19:41:58 +00:00
if ( m_apPlayers [ i ] ! = 0 )
{
if ( Team = = CHAT_SPEC )
{
if ( m_apPlayers [ i ] - > GetTeam ( ) = = CHAT_SPEC )
{
Server ( ) - > SendPackMsg ( & Msg , MSGFLAG_VITAL | MSGFLAG_NORECORD , i ) ;
2010-10-06 20:35:19 +00:00
}
2020-09-26 19:41:58 +00:00
}
else
{
2022-06-30 22:36:32 +00:00
if ( pTeams - > Team ( i ) = = Team & & m_apPlayers [ i ] - > GetTeam ( ) ! = CHAT_SPEC )
2020-09-26 19:41:58 +00:00
{
Server ( ) - > SendPackMsg ( & Msg , MSGFLAG_VITAL | MSGFLAG_NORECORD , i ) ;
2010-10-06 20:35:19 +00:00
}
}
}
2008-08-14 18:42:47 +00:00
}
}
}
2021-12-21 22:22:26 +00:00
void CGameContext : : SendStartWarning ( int ClientID , const char * pMessage )
{
CCharacter * pChr = GetPlayerChar ( ClientID ) ;
if ( pChr & & pChr - > m_LastStartWarning < Server ( ) - > Tick ( ) - 3 * Server ( ) - > TickSpeed ( ) )
{
SendChatTarget ( ClientID , pMessage ) ;
2022-01-26 11:24:54 +00:00
pChr - > m_LastStartWarning = Server ( ) - > Tick ( ) ;
2021-12-21 22:22:26 +00:00
}
}
2023-06-11 11:24:02 +00:00
void CGameContext : : SendEmoticon ( int ClientID , int Emoticon , int TargetClientID )
2008-08-14 18:42:47 +00:00
{
2010-05-29 07:25:38 +00:00
CNetMsg_Sv_Emoticon Msg ;
2011-02-12 10:40:36 +00:00
Msg . m_ClientID = ClientID ;
2010-05-29 07:25:38 +00:00
Msg . m_Emoticon = Emoticon ;
2023-06-11 11:24:02 +00:00
Server ( ) - > SendPackMsg ( & Msg , MSGFLAG_VITAL , TargetClientID ) ;
2008-08-14 18:42:47 +00:00
}
2011-02-12 10:40:36 +00:00
void CGameContext : : SendWeaponPickup ( int ClientID , int Weapon )
2008-08-14 18:42:47 +00:00
{
2010-05-29 07:25:38 +00:00
CNetMsg_Sv_WeaponPickup Msg ;
Msg . m_Weapon = Weapon ;
2011-02-12 10:40:36 +00:00
Server ( ) - > SendPackMsg ( & Msg , MSGFLAG_VITAL , ClientID ) ;
2008-08-14 18:42:47 +00:00
}
2021-01-09 13:05:54 +00:00
void CGameContext : : SendMotd ( int ClientID )
{
CNetMsg_Sv_Motd Msg ;
Msg . m_pMessage = g_Config . m_SvMotd ;
Server ( ) - > SendPackMsg ( & Msg , MSGFLAG_VITAL , ClientID ) ;
}
void CGameContext : : SendSettings ( int ClientID )
{
2023-09-04 12:03:56 +00:00
protocol7 : : CNetMsg_Sv_ServerSettings Msg ;
Msg . m_KickVote = g_Config . m_SvVoteKick ;
Msg . m_KickMin = g_Config . m_SvVoteKickMin ;
Msg . m_SpecVote = g_Config . m_SvVoteSpectate ;
Msg . m_TeamLock = 0 ;
Msg . m_TeamBalance = 0 ;
Msg . m_PlayerSlots = g_Config . m_SvMaxClients - g_Config . m_SvSpectatorSlots ;
Server ( ) - > SendPackMsg ( & Msg , MSGFLAG_VITAL | MSGFLAG_NORECORD , ClientID ) ;
2021-01-09 13:05:54 +00:00
}
2018-03-07 16:22:41 +00:00
void CGameContext : : SendBroadcast ( const char * pText , int ClientID , bool IsImportant )
2008-08-14 18:42:47 +00:00
{
2010-05-29 07:25:38 +00:00
CNetMsg_Sv_Broadcast Msg ;
Msg . m_pMessage = pText ;
2018-03-07 16:22:41 +00:00
2018-03-07 17:10:57 +00:00
if ( ClientID = = - 1 )
2018-03-07 16:22:41 +00:00
{
2018-08-22 20:27:01 +00:00
dbg_assert ( IsImportant , " broadcast messages to all players must be important " ) ;
2018-03-07 16:22:41 +00:00
Server ( ) - > SendPackMsg ( & Msg , MSGFLAG_VITAL , ClientID ) ;
2020-10-26 14:14:07 +00:00
for ( auto & pPlayer : m_apPlayers )
2018-03-07 16:22:41 +00:00
{
2020-10-26 14:14:07 +00:00
if ( pPlayer )
2018-03-07 16:22:41 +00:00
{
2020-10-26 14:14:07 +00:00
pPlayer - > m_LastBroadcastImportance = true ;
pPlayer - > m_LastBroadcast = Server ( ) - > Tick ( ) ;
2018-03-07 16:22:41 +00:00
}
}
return ;
}
2018-03-07 17:10:57 +00:00
if ( ! m_apPlayers [ ClientID ] )
2018-03-07 16:22:41 +00:00
return ;
2018-03-15 21:35:25 +00:00
if ( ! IsImportant & & m_apPlayers [ ClientID ] - > m_LastBroadcastImportance & & m_apPlayers [ ClientID ] - > m_LastBroadcast > Server ( ) - > Tick ( ) - Server ( ) - > TickSpeed ( ) * 10 )
2018-03-07 16:22:41 +00:00
return ;
2011-02-12 10:40:36 +00:00
Server ( ) - > SendPackMsg ( & Msg , MSGFLAG_VITAL , ClientID ) ;
2018-03-07 16:22:41 +00:00
m_apPlayers [ ClientID ] - > m_LastBroadcast = Server ( ) - > Tick ( ) ;
m_apPlayers [ ClientID ] - > m_LastBroadcastImportance = IsImportant ;
2008-08-14 18:42:47 +00:00
}
2020-08-04 17:14:37 +00:00
void CGameContext : : StartVote ( const char * pDesc , const char * pCommand , const char * pReason , const char * pSixupDesc )
2008-09-24 14:47:03 +00:00
{
// reset votes
2010-05-29 07:25:38 +00:00
m_VoteEnforce = VOTE_ENFORCE_UNKNOWN ;
2011-12-26 09:15:43 +00:00
m_VoteEnforcer = - 1 ;
2020-10-26 14:14:07 +00:00
for ( auto & pPlayer : m_apPlayers )
2008-09-24 14:47:03 +00:00
{
2020-10-26 14:14:07 +00:00
if ( pPlayer )
2010-05-29 07:25:38 +00:00
{
2020-10-26 14:14:07 +00:00
pPlayer - > m_Vote = 0 ;
pPlayer - > m_VotePos = 0 ;
2010-05-29 07:25:38 +00:00
}
2008-09-24 14:47:03 +00:00
}
2011-04-13 18:37:12 +00:00
2008-09-24 14:47:03 +00:00
// start vote
2014-05-19 00:23:01 +00:00
m_VoteCloseTime = time_get ( ) + time_freq ( ) * g_Config . m_SvVoteTime ;
2010-05-29 07:25:38 +00:00
str_copy ( m_aVoteDescription , pDesc , sizeof ( m_aVoteDescription ) ) ;
2020-08-04 17:14:37 +00:00
str_copy ( m_aSixupVoteDescription , pSixupDesc , sizeof ( m_aSixupVoteDescription ) ) ;
2010-05-29 07:25:38 +00:00
str_copy ( m_aVoteCommand , pCommand , sizeof ( m_aVoteCommand ) ) ;
2011-03-25 09:26:59 +00:00
str_copy ( m_aVoteReason , pReason , sizeof ( m_aVoteReason ) ) ;
2010-05-29 07:25:38 +00:00
SendVoteSet ( - 1 ) ;
m_VoteUpdate = true ;
2008-09-24 14:47:03 +00:00
}
2010-05-29 07:25:38 +00:00
void CGameContext : : EndVote ( )
2008-09-25 12:41:37 +00:00
{
2010-05-29 07:25:38 +00:00
m_VoteCloseTime = 0 ;
SendVoteSet ( - 1 ) ;
2008-09-25 12:41:37 +00:00
}
2011-02-12 10:40:36 +00:00
void CGameContext : : SendVoteSet ( int ClientID )
2008-09-24 14:47:03 +00:00
{
2020-07-01 12:02:47 +00:00
: : CNetMsg_Sv_VoteSet Msg6 ;
protocol7 : : CNetMsg_Sv_VoteSet Msg7 ;
Msg7 . m_ClientID = m_VoteCreator ;
2010-05-29 07:25:38 +00:00
if ( m_VoteCloseTime )
2008-09-24 14:47:03 +00:00
{
2020-09-26 19:41:58 +00:00
Msg6 . m_Timeout = Msg7 . m_Timeout = ( m_VoteCloseTime - time_get ( ) ) / time_freq ( ) ;
2020-08-04 17:14:37 +00:00
Msg6 . m_pDescription = m_aVoteDescription ;
Msg7 . m_pDescription = m_aSixupVoteDescription ;
2020-07-01 12:02:47 +00:00
Msg6 . m_pReason = Msg7 . m_pReason = m_aVoteReason ;
int & Type = ( Msg7 . m_Type = protocol7 : : VOTE_UNKNOWN ) ;
if ( IsKickVote ( ) )
Type = protocol7 : : VOTE_START_KICK ;
else if ( IsSpecVote ( ) )
Type = protocol7 : : VOTE_START_SPEC ;
else if ( IsOptionVote ( ) )
Type = protocol7 : : VOTE_START_OP ;
2008-09-24 14:47:03 +00:00
}
else
{
2020-07-01 12:02:47 +00:00
Msg6 . m_Timeout = Msg7 . m_Timeout = 0 ;
Msg6 . m_pDescription = Msg7 . m_pDescription = " " ;
Msg6 . m_pReason = Msg7 . m_pReason = " " ;
int & Type = ( Msg7 . m_Type = protocol7 : : VOTE_UNKNOWN ) ;
if ( m_VoteEnforce = = VOTE_ENFORCE_NO | | m_VoteEnforce = = VOTE_ENFORCE_NO_ADMIN )
Type = protocol7 : : VOTE_END_FAIL ;
else if ( m_VoteEnforce = = VOTE_ENFORCE_YES | | m_VoteEnforce = = VOTE_ENFORCE_YES_ADMIN )
Type = protocol7 : : VOTE_END_PASS ;
else if ( m_VoteEnforce = = VOTE_ENFORCE_ABORT )
Type = protocol7 : : VOTE_END_ABORT ;
if ( m_VoteEnforce = = VOTE_ENFORCE_NO_ADMIN | | m_VoteEnforce = = VOTE_ENFORCE_YES_ADMIN )
Msg7 . m_ClientID = - 1 ;
}
if ( ClientID = = - 1 )
{
2022-02-21 15:33:51 +00:00
for ( int i = 0 ; i < Server ( ) - > MaxClients ( ) ; i + + )
2020-07-01 12:02:47 +00:00
{
if ( ! m_apPlayers [ i ] )
continue ;
if ( ! Server ( ) - > IsSixup ( i ) )
Server ( ) - > SendPackMsg ( & Msg6 , MSGFLAG_VITAL , i ) ;
else
Server ( ) - > SendPackMsg ( & Msg7 , MSGFLAG_VITAL , i ) ;
}
}
else
{
if ( ! Server ( ) - > IsSixup ( ClientID ) )
Server ( ) - > SendPackMsg ( & Msg6 , MSGFLAG_VITAL , ClientID ) ;
else
Server ( ) - > SendPackMsg ( & Msg7 , MSGFLAG_VITAL , ClientID ) ;
2008-09-24 14:47:03 +00:00
}
}
2011-02-12 10:40:36 +00:00
void CGameContext : : SendVoteStatus ( int ClientID , int Total , int Yes , int No )
2008-09-24 14:47:03 +00:00
{
2021-02-07 14:46:58 +00:00
if ( ClientID = = - 1 )
{
for ( int i = 0 ; i < MAX_CLIENTS ; + + i )
if ( Server ( ) - > ClientIngame ( i ) )
SendVoteStatus ( i , Total , Yes , No ) ;
return ;
}
2020-09-26 19:41:58 +00:00
if ( Total > VANILLA_MAX_CLIENTS & & m_apPlayers [ ClientID ] & & m_apPlayers [ ClientID ] - > GetClientVersion ( ) < = VERSION_DDRACE )
2014-01-02 20:23:27 +00:00
{
2022-11-06 09:47:41 +00:00
Yes = ( Yes * VANILLA_MAX_CLIENTS ) / ( float ) Total ;
No = ( No * VANILLA_MAX_CLIENTS ) / ( float ) Total ;
2014-01-02 20:23:27 +00:00
Total = VANILLA_MAX_CLIENTS ;
}
2010-05-29 07:25:38 +00:00
CNetMsg_Sv_VoteStatus Msg = { 0 } ;
Msg . m_Total = Total ;
Msg . m_Yes = Yes ;
Msg . m_No = No ;
2020-09-26 19:41:58 +00:00
Msg . m_Pass = Total - ( Yes + No ) ;
2010-05-29 07:25:38 +00:00
2011-02-12 10:40:36 +00:00
Server ( ) - > SendPackMsg ( & Msg , MSGFLAG_VITAL , ClientID ) ;
2010-05-29 07:25:38 +00:00
}
2011-02-12 10:40:36 +00:00
void CGameContext : : AbortVoteKickOnDisconnect ( int ClientID )
2010-05-29 07:25:38 +00:00
{
2018-07-25 08:29:05 +00:00
if ( m_VoteCloseTime & & ( ( str_startswith ( m_aVoteCommand , " kick " ) & & str_toint ( & m_aVoteCommand [ 5 ] ) = = ClientID ) | |
2020-09-26 19:41:58 +00:00
( str_startswith ( m_aVoteCommand , " set_team " ) & & str_toint ( & m_aVoteCommand [ 9 ] ) = = ClientID ) ) )
2020-07-01 12:02:47 +00:00
m_VoteEnforce = VOTE_ENFORCE_ABORT ;
2010-05-29 07:25:38 +00:00
}
void CGameContext : : CheckPureTuning ( )
{
// might not be created yet during start up
if ( ! m_pController )
return ;
2011-04-13 18:37:12 +00:00
2020-09-26 19:41:58 +00:00
if ( str_comp ( m_pController - > m_pGameType , " DM " ) = = 0 | |
str_comp ( m_pController - > m_pGameType , " TDM " ) = = 0 | |
str_comp ( m_pController - > m_pGameType , " CTF " ) = = 0 )
2008-09-24 14:47:03 +00:00
{
2011-01-29 00:59:50 +00:00
CTuningParams p ;
if ( mem_comp ( & p , & m_Tuning , sizeof ( p ) ) ! = 0 )
2008-09-24 14:47:03 +00:00
{
2010-08-17 22:06:00 +00:00
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " server " , " resetting tuning due to pure server " ) ;
2011-01-29 00:59:50 +00:00
m_Tuning = p ;
2008-09-24 14:47:03 +00:00
}
2011-04-13 18:37:12 +00:00
}
2008-09-24 14:47:03 +00:00
}
2014-03-12 23:31:50 +00:00
void CGameContext : : SendTuningParams ( int ClientID , int Zone )
2008-10-21 17:26:32 +00:00
{
2020-09-26 19:41:58 +00:00
if ( ClientID = = - 1 )
2014-03-29 13:54:43 +00:00
{
2017-04-22 17:04:16 +00:00
for ( int i = 0 ; i < MAX_CLIENTS ; + + i )
{
2020-09-26 19:41:58 +00:00
if ( m_apPlayers [ i ] )
2014-03-29 13:54:43 +00:00
{
2017-04-22 17:04:16 +00:00
if ( m_apPlayers [ i ] - > GetCharacter ( ) )
2014-03-29 13:54:43 +00:00
{
2020-09-26 19:41:58 +00:00
if ( m_apPlayers [ i ] - > GetCharacter ( ) - > m_TuneZone = = Zone )
2014-03-29 13:54:43 +00:00
SendTuningParams ( i , Zone ) ;
2017-04-22 17:04:16 +00:00
}
2020-09-26 19:41:58 +00:00
else if ( m_apPlayers [ i ] - > m_TuneZone = = Zone )
2017-04-22 17:04:16 +00:00
{
SendTuningParams ( i , Zone ) ;
2014-03-29 13:54:43 +00:00
}
}
2017-04-22 17:04:16 +00:00
}
return ;
2014-03-29 13:54:43 +00:00
}
2015-07-09 00:08:14 +00:00
2010-05-29 07:25:38 +00:00
CheckPureTuning ( ) ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
CMsgPacker Msg ( NETMSGTYPE_SV_TUNEPARAMS ) ;
2014-03-12 23:31:50 +00:00
int * pParams = 0 ;
2020-09-26 19:41:58 +00:00
if ( Zone = = 0 )
2014-03-12 23:31:50 +00:00
pParams = ( int * ) & m_Tuning ;
else
2017-07-26 01:58:00 +00:00
pParams = ( int * ) & ( m_aTuningList [ Zone ] ) ;
2014-06-26 15:37:06 +00:00
2022-06-13 14:57:53 +00:00
for ( unsigned i = 0 ; i < sizeof ( m_Tuning ) / sizeof ( int ) ; i + + )
2017-04-22 17:04:16 +00:00
{
2020-09-26 19:41:58 +00:00
if ( m_apPlayers [ ClientID ] & & m_apPlayers [ ClientID ] - > GetCharacter ( ) )
2014-02-19 20:55:37 +00:00
{
2020-09-25 14:41:17 +00:00
if ( ( i = = 30 ) // laser_damage is removed from 0.7
& & ( Server ( ) - > IsSixup ( ClientID ) ) )
2020-09-25 14:25:59 +00:00
{
continue ;
}
2020-09-25 14:41:17 +00:00
else if ( ( i = = 31 ) // collision
& & ( m_apPlayers [ ClientID ] - > GetCharacter ( ) - > NeededFaketuning ( ) & FAKETUNE_SOLO | | m_apPlayers [ ClientID ] - > GetCharacter ( ) - > NeededFaketuning ( ) & FAKETUNE_NOCOLL ) )
2014-02-19 20:55:37 +00:00
{
2017-04-22 17:04:16 +00:00
Msg . AddInt ( 0 ) ;
}
2020-09-26 19:41:58 +00:00
else if ( ( i = = 32 ) // hooking
& & ( m_apPlayers [ ClientID ] - > GetCharacter ( ) - > NeededFaketuning ( ) & FAKETUNE_SOLO | | m_apPlayers [ ClientID ] - > GetCharacter ( ) - > NeededFaketuning ( ) & FAKETUNE_NOHOOK ) )
2017-04-22 17:04:16 +00:00
{
Msg . AddInt ( 0 ) ;
}
2020-09-26 19:41:58 +00:00
else if ( ( i = = 3 ) // ground jump impulse
& & m_apPlayers [ ClientID ] - > GetCharacter ( ) - > NeededFaketuning ( ) & FAKETUNE_NOJUMP )
2017-04-22 17:04:16 +00:00
{
Msg . AddInt ( 0 ) ;
}
2020-09-26 19:41:58 +00:00
else if ( ( i = = 33 ) // jetpack
& & ! ( m_apPlayers [ ClientID ] - > GetCharacter ( ) - > NeededFaketuning ( ) & FAKETUNE_JETPACK ) )
2017-04-22 17:04:16 +00:00
{
Msg . AddInt ( 0 ) ;
}
2020-09-26 19:41:58 +00:00
else if ( ( i = = 36 ) // hammer hit
& & m_apPlayers [ ClientID ] - > GetCharacter ( ) - > NeededFaketuning ( ) & FAKETUNE_NOHAMMER )
2017-04-22 17:04:16 +00:00
{
Msg . AddInt ( 0 ) ;
2014-02-19 21:30:57 +00:00
}
2014-02-19 20:55:37 +00:00
else
2017-04-22 17:04:16 +00:00
{
Msg . AddInt ( pParams [ i ] ) ;
}
2014-02-19 20:55:37 +00:00
}
2017-04-22 17:04:16 +00:00
else
Msg . AddInt ( pParams [ i ] ) ; // if everything is normal just send true tunings
}
Server ( ) - > SendMsg ( & Msg , MSGFLAG_VITAL , ClientID ) ;
2008-10-21 17:26:32 +00:00
}
2015-07-09 00:08:14 +00:00
2021-09-14 20:11:22 +00:00
void CGameContext : : OnPreTickTeehistorian ( )
{
2021-10-17 17:27:35 +00:00
if ( ! m_TeeHistorianActive )
return ;
2021-09-14 20:11:22 +00:00
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
{
if ( m_apPlayers [ i ] ! = nullptr )
2023-11-15 20:28:19 +00:00
m_TeeHistorian . RecordPlayerTeam ( i , GetDDRaceTeam ( i ) ) ;
2021-09-15 18:03:14 +00:00
else
m_TeeHistorian . RecordPlayerTeam ( i , 0 ) ;
2021-09-14 20:11:22 +00:00
}
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
{
2023-11-15 20:28:19 +00:00
m_TeeHistorian . RecordTeamPractice ( i , m_pController - > Teams ( ) . IsPractice ( i ) ) ;
2021-09-14 20:11:22 +00:00
}
}
2010-05-29 07:25:38 +00:00
void CGameContext : : OnTick ( )
2008-08-14 18:42:47 +00:00
{
2010-05-29 07:25:38 +00:00
// check tuning
CheckPureTuning ( ) ;
2017-09-12 12:58:44 +00:00
if ( m_TeeHistorianActive )
{
2017-10-13 00:48:42 +00:00
int Error = aio_error ( m_pTeeHistorianFile ) ;
2017-10-10 02:07:38 +00:00
if ( Error )
{
dbg_msg ( " teehistorian " , " error writing to file, err=%d " , Error ) ;
2017-10-13 00:25:50 +00:00
Server ( ) - > SetErrorShutdown ( " teehistorian io error " ) ;
2017-10-10 02:07:38 +00:00
}
2017-09-12 12:58:44 +00:00
if ( ! m_TeeHistorian . Starting ( ) )
{
m_TeeHistorian . EndInputs ( ) ;
m_TeeHistorian . EndTick ( ) ;
}
m_TeeHistorian . BeginTick ( Server ( ) - > Tick ( ) ) ;
m_TeeHistorian . BeginPlayers ( ) ;
}
2010-05-29 07:25:38 +00:00
// copy tuning
2022-06-30 22:36:32 +00:00
m_World . m_Core . m_aTuning [ 0 ] = m_Tuning ;
2010-05-29 07:25:38 +00:00
m_World . Tick ( ) ;
2008-08-14 18:42:47 +00:00
2023-09-05 22:44:21 +00:00
UpdatePlayerMaps ( ) ;
2008-08-14 18:42:47 +00:00
//if(world.paused) // make sure that the game object always updates
2010-05-29 07:25:38 +00:00
m_pController - > Tick ( ) ;
2011-04-13 18:37:12 +00:00
2008-08-14 18:42:47 +00:00
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
{
2010-05-29 07:25:38 +00:00
if ( m_apPlayers [ i ] )
2011-03-10 09:08:14 +00:00
{
2014-10-26 18:39:42 +00:00
// send vote options
ProgressVoteOptions ( i ) ;
2010-05-29 07:25:38 +00:00
m_apPlayers [ i ] - > Tick ( ) ;
2011-03-10 09:08:14 +00:00
m_apPlayers [ i ] - > PostTick ( ) ;
}
2008-08-14 18:42:47 +00:00
}
2011-04-13 18:37:12 +00:00
2020-10-26 14:14:07 +00:00
for ( auto & pPlayer : m_apPlayers )
2016-03-04 21:55:12 +00:00
{
2020-10-26 14:14:07 +00:00
if ( pPlayer )
pPlayer - > PostPostTick ( ) ;
2016-03-04 21:55:12 +00:00
}
2008-09-24 14:47:03 +00:00
// update voting
2010-05-29 07:25:38 +00:00
if ( m_VoteCloseTime )
2008-09-24 14:47:03 +00:00
{
2008-10-21 17:26:32 +00:00
// abort the kick-vote on player-leave
2020-07-01 12:02:47 +00:00
if ( m_VoteEnforce = = VOTE_ENFORCE_ABORT )
2008-09-24 14:47:03 +00:00
{
2010-05-29 07:25:38 +00:00
SendChat ( - 1 , CGameContext : : CHAT_ALL , " Vote aborted " ) ;
EndVote ( ) ;
2008-10-21 17:26:32 +00:00
}
else
{
2010-05-29 07:25:38 +00:00
int Total = 0 , Yes = 0 , No = 0 ;
2015-07-08 15:03:22 +00:00
bool Veto = false , VetoStop = false ;
2010-05-29 07:25:38 +00:00
if ( m_VoteUpdate )
2008-09-24 14:47:03 +00:00
{
2010-05-29 07:25:38 +00:00
// count votes
2019-05-01 11:54:51 +00:00
char aaBuf [ MAX_CLIENTS ] [ NETADDR_MAXSTRSIZE ] = { { 0 } } , * pIP = NULL ;
bool SinglePlayer = true ;
2010-05-29 07:25:38 +00:00
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
2019-05-01 11:54:51 +00:00
{
2010-05-29 07:25:38 +00:00
if ( m_apPlayers [ i ] )
2019-05-01 11:54:51 +00:00
{
2011-03-28 18:11:28 +00:00
Server ( ) - > GetClientAddr ( i , aaBuf [ i ] , NETADDR_MAXSTRSIZE ) ;
2019-05-01 11:54:51 +00:00
if ( ! pIP )
pIP = aaBuf [ i ] ;
2019-05-01 19:57:14 +00:00
else if ( SinglePlayer & & str_comp ( pIP , aaBuf [ i ] ) )
2019-05-01 11:54:51 +00:00
SinglePlayer = false ;
}
}
2020-12-23 09:00:38 +00:00
// remember checked players, only the first player with a specific ip will be handled
bool aVoteChecked [ MAX_CLIENTS ] = { false } ;
2021-06-23 05:05:49 +00:00
int64_t Now = Server ( ) - > Tick ( ) ;
2010-05-29 07:25:38 +00:00
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
2008-10-21 17:26:32 +00:00
{
2020-12-23 09:00:38 +00:00
if ( ! m_apPlayers [ i ] | | aVoteChecked [ i ] )
2010-05-29 07:25:38 +00:00
continue ;
2011-04-09 06:41:31 +00:00
2020-07-01 12:02:47 +00:00
if ( ( IsKickVote ( ) | | IsSpecVote ( ) ) & & ( m_apPlayers [ i ] - > GetTeam ( ) = = TEAM_SPECTATORS | |
2020-09-26 19:41:58 +00:00
( GetPlayerChar ( m_VoteCreator ) & & GetPlayerChar ( i ) & &
GetPlayerChar ( m_VoteCreator ) - > Team ( ) ! = GetPlayerChar ( i ) - > Team ( ) ) ) )
2010-05-29 07:25:38 +00:00
continue ;
2011-04-13 18:37:12 +00:00
2022-12-22 23:06:29 +00:00
if ( m_apPlayers [ i ] - > IsAfk ( ) & & i ! = m_VoteCreator )
2013-08-18 01:27:30 +00:00
continue ;
2018-12-12 09:41:28 +00:00
// can't vote in kick and spec votes in the beginning after joining
2020-07-01 12:02:47 +00:00
if ( ( IsKickVote ( ) | | IsSpecVote ( ) ) & & Now < m_apPlayers [ i ] - > m_FirstVoteTick )
2018-12-11 09:29:34 +00:00
continue ;
2018-08-16 19:42:10 +00:00
// connecting clients with spoofed ips can clog slots without being ingame
2023-01-02 10:10:05 +00:00
if ( ! Server ( ) - > ClientIngame ( i ) )
2018-08-16 19:42:10 +00:00
continue ;
2016-09-05 09:38:11 +00:00
// don't count votes by blacklisted clients
2019-05-01 11:54:51 +00:00
if ( g_Config . m_SvDnsblVote & & ! m_pServer - > DnsblWhite ( i ) & & ! SinglePlayer )
2016-09-05 09:38:11 +00:00
continue ;
2022-04-01 16:32:51 +00:00
int CurVote = m_apPlayers [ i ] - > m_Vote ;
int CurVotePos = m_apPlayers [ i ] - > m_VotePos ;
2011-04-13 18:37:12 +00:00
2020-12-12 19:43:18 +00:00
// only allow IPs to vote once, but keep veto ability
2020-12-23 09:00:38 +00:00
// check for more players with the same ip (only use the vote of the one who voted first)
for ( int j = i + 1 ; j < MAX_CLIENTS ; j + + )
2010-05-29 07:25:38 +00:00
{
2020-12-23 09:00:38 +00:00
if ( ! m_apPlayers [ j ] | | aVoteChecked [ j ] | | str_comp ( aaBuf [ j ] , aaBuf [ i ] ) ! = 0 )
continue ;
2020-12-12 19:43:18 +00:00
2020-12-23 09:00:38 +00:00
// count the latest vote by this ip
2022-04-01 16:32:51 +00:00
if ( CurVotePos < m_apPlayers [ j ] - > m_VotePos )
2020-12-23 09:00:38 +00:00
{
2022-04-01 16:32:51 +00:00
CurVote = m_apPlayers [ j ] - > m_Vote ;
CurVotePos = m_apPlayers [ j ] - > m_VotePos ;
2010-05-29 07:25:38 +00:00
}
2020-12-23 09:00:38 +00:00
aVoteChecked [ j ] = true ;
2020-12-12 19:43:18 +00:00
}
2015-07-08 15:03:22 +00:00
2020-12-23 09:00:38 +00:00
Total + + ;
2022-04-01 16:32:51 +00:00
if ( CurVote > 0 )
2020-12-23 09:00:38 +00:00
Yes + + ;
2022-04-01 16:32:51 +00:00
else if ( CurVote < 0 )
2020-12-23 09:00:38 +00:00
No + + ;
2016-01-27 01:14:46 +00:00
// veto right for players who have been active on server for long and who're not afk
2020-12-23 09:00:38 +00:00
if ( ! IsKickVote ( ) & & ! IsSpecVote ( ) & & g_Config . m_SvVoteVetoTime )
2015-07-08 15:03:22 +00:00
{
2020-12-28 10:53:16 +00:00
// look through all players with same IP again, including the current player
for ( int j = i ; j < MAX_CLIENTS ; j + + )
2020-12-23 09:00:38 +00:00
{
2020-12-28 10:53:16 +00:00
// no need to check ip address of current player
if ( i ! = j & & ( ! m_apPlayers [ j ] | | str_comp ( aaBuf [ j ] , aaBuf [ i ] ) ! = 0 ) )
2020-12-23 09:00:38 +00:00
continue ;
2022-12-22 23:06:29 +00:00
if ( m_apPlayers [ j ] & & ! m_apPlayers [ j ] - > IsAfk ( ) & & m_apPlayers [ j ] - > GetTeam ( ) ! = TEAM_SPECTATORS & &
2020-12-23 09:00:38 +00:00
( ( Server ( ) - > Tick ( ) - m_apPlayers [ j ] - > m_JoinTick ) / ( Server ( ) - > TickSpeed ( ) * 60 ) > g_Config . m_SvVoteVetoTime | |
( m_apPlayers [ j ] - > GetCharacter ( ) & & m_apPlayers [ j ] - > GetCharacter ( ) - > m_DDRaceState = = DDRACE_STARTED & &
( Server ( ) - > Tick ( ) - m_apPlayers [ j ] - > GetCharacter ( ) - > m_StartTime ) / ( Server ( ) - > TickSpeed ( ) * 60 ) > g_Config . m_SvVoteVetoTime ) ) )
{
2022-04-01 16:32:51 +00:00
if ( CurVote = = 0 )
2020-12-23 09:00:38 +00:00
Veto = true ;
2022-04-01 16:32:51 +00:00
else if ( CurVote < 0 )
2020-12-23 09:00:38 +00:00
VetoStop = true ;
break ;
}
}
2015-07-08 15:03:22 +00:00
}
2008-10-21 17:26:32 +00:00
}
2010-05-29 07:25:38 +00:00
2014-08-12 11:41:57 +00:00
if ( g_Config . m_SvVoteMaxTotal & & Total > g_Config . m_SvVoteMaxTotal & &
2020-09-26 19:41:58 +00:00
( IsKickVote ( ) | | IsSpecVote ( ) ) )
2014-03-22 18:53:43 +00:00
Total = g_Config . m_SvVoteMaxTotal ;
2019-07-08 21:08:42 +00:00
if ( ( Yes > Total / ( 100.0f / g_Config . m_SvVoteYesPercentage ) ) & & ! Veto )
2018-01-13 21:22:55 +00:00
m_VoteEnforce = VOTE_ENFORCE_YES ;
2019-07-08 21:08:42 +00:00
else if ( No > = Total - Total / ( 100.0f / g_Config . m_SvVoteYesPercentage ) )
2010-05-29 07:25:38 +00:00
m_VoteEnforce = VOTE_ENFORCE_NO ;
2011-02-12 20:31:42 +00:00
2015-07-08 15:03:22 +00:00
if ( VetoStop )
m_VoteEnforce = VOTE_ENFORCE_NO ;
2019-07-08 21:08:42 +00:00
m_VoteWillPass = Yes > ( Yes + No ) / ( 100.0f / g_Config . m_SvVoteYesPercentage ) ;
2008-09-24 14:47:03 +00:00
}
2011-04-09 06:41:31 +00:00
2018-01-13 15:46:31 +00:00
if ( time_get ( ) > m_VoteCloseTime & & ! g_Config . m_SvVoteMajority )
2015-07-08 15:03:22 +00:00
m_VoteEnforce = ( m_VoteWillPass & & ! Veto ) ? VOTE_ENFORCE_YES : VOTE_ENFORCE_NO ;
2011-04-13 23:27:49 +00:00
2019-03-21 01:57:22 +00:00
// / Ensure minimum time for vote to end when moderating.
if ( m_VoteEnforce = = VOTE_ENFORCE_YES & & ! ( PlayerModerating ( ) & &
2020-09-26 19:41:58 +00:00
( IsKickVote ( ) | | IsSpecVote ( ) ) & & time_get ( ) < m_VoteCloseTime ) )
2010-05-29 07:25:38 +00:00
{
2019-03-21 01:57:22 +00:00
Server ( ) - > SetRconCID ( IServer : : RCON_CID_VOTE ) ;
Console ( ) - > ExecuteLine ( m_aVoteCommand ) ;
Server ( ) - > SetRconCID ( IServer : : RCON_CID_SERV ) ;
EndVote ( ) ;
2020-07-12 07:34:36 +00:00
SendChat ( - 1 , CGameContext : : CHAT_ALL , " Vote passed " , - 1 , CHAT_SIX ) ;
2019-03-21 01:57:22 +00:00
2020-07-01 12:02:47 +00:00
if ( m_apPlayers [ m_VoteCreator ] & & ! IsKickVote ( ) & & ! IsSpecVote ( ) )
2019-03-21 01:57:22 +00:00
m_apPlayers [ m_VoteCreator ] - > m_LastVoteCall = 0 ;
2010-05-29 07:25:38 +00:00
}
2010-10-11 11:10:39 +00:00
else if ( m_VoteEnforce = = VOTE_ENFORCE_YES_ADMIN )
{
2011-11-08 11:06:09 +00:00
Console ( ) - > ExecuteLine ( m_aVoteCommand , m_VoteEnforcer ) ;
2023-01-28 12:40:21 +00:00
SendChat ( - 1 , CGameContext : : CHAT_ALL , " Vote passed enforced by authorized player " , - 1 , CHAT_SIX ) ;
2010-10-11 11:10:39 +00:00
EndVote ( ) ;
}
else if ( m_VoteEnforce = = VOTE_ENFORCE_NO_ADMIN )
{
EndVote ( ) ;
2023-01-28 12:40:21 +00:00
SendChat ( - 1 , CGameContext : : CHAT_ALL , " Vote failed enforced by authorized player " , - 1 , CHAT_SIX ) ;
2010-10-11 11:10:39 +00:00
}
2011-04-09 06:41:31 +00:00
//else if(m_VoteEnforce == VOTE_ENFORCE_NO || time_get() > m_VoteCloseTime)
2011-02-12 20:31:42 +00:00
else if ( m_VoteEnforce = = VOTE_ENFORCE_NO | | ( time_get ( ) > m_VoteCloseTime & & g_Config . m_SvVoteMajority ) )
2010-05-29 07:25:38 +00:00
{
EndVote ( ) ;
2015-07-08 15:03:22 +00:00
if ( VetoStop | | ( m_VoteWillPass & & Veto ) )
2020-07-12 07:34:36 +00:00
SendChat ( - 1 , CGameContext : : CHAT_ALL , " Vote failed because of veto. Find an empty server instead " , - 1 , CHAT_SIX ) ;
2015-07-08 15:03:22 +00:00
else
2020-07-12 07:34:36 +00:00
SendChat ( - 1 , CGameContext : : CHAT_ALL , " Vote failed " , - 1 , CHAT_SIX ) ;
2010-05-29 07:25:38 +00:00
}
else if ( m_VoteUpdate )
{
m_VoteUpdate = false ;
2021-02-07 14:46:58 +00:00
SendVoteStatus ( - 1 , Total , Yes , No ) ;
2010-05-29 07:25:38 +00:00
}
}
}
2011-02-23 21:39:53 +00:00
for ( int i = 0 ; i < m_NumMutes ; i + + )
{
if ( m_aMutes [ i ] . m_Expire < = Server ( ) - > Tick ( ) )
{
m_NumMutes - - ;
m_aMutes [ i ] = m_aMutes [ m_NumMutes ] ;
}
}
2019-03-28 22:35:47 +00:00
for ( int i = 0 ; i < m_NumVoteMutes ; i + + )
{
if ( m_aVoteMutes [ i ] . m_Expire < = Server ( ) - > Tick ( ) )
{
m_NumVoteMutes - - ;
m_aVoteMutes [ i ] = m_aVoteMutes [ m_NumVoteMutes ] ;
}
}
2010-11-22 20:43:22 +00:00
2011-02-23 21:39:53 +00:00
if ( Server ( ) - > Tick ( ) % ( g_Config . m_SvAnnouncementInterval * Server ( ) - > TickSpeed ( ) * 60 ) = = 0 )
2010-11-22 20:43:22 +00:00
{
2022-06-30 22:36:32 +00:00
const char * pLine = Server ( ) - > GetAnnouncementLine ( g_Config . m_SvAnnouncementFileName ) ;
if ( pLine )
SendChat ( - 1 , CGameContext : : CHAT_ALL , pLine ) ;
2011-02-23 21:39:53 +00:00
}
2022-05-01 23:54:29 +00:00
for ( auto & Switcher : Switchers ( ) )
2020-05-27 15:49:07 +00:00
{
2022-05-01 23:54:29 +00:00
for ( int j = 0 ; j < MAX_CLIENTS ; + + j )
2010-11-22 20:43:22 +00:00
{
2022-06-30 22:36:32 +00:00
if ( Switcher . m_aEndTick [ j ] < = Server ( ) - > Tick ( ) & & Switcher . m_aType [ j ] = = TILE_SWITCHTIMEDOPEN )
2010-11-22 20:43:22 +00:00
{
2022-06-30 22:36:32 +00:00
Switcher . m_aStatus [ j ] = false ;
Switcher . m_aEndTick [ j ] = 0 ;
Switcher . m_aType [ j ] = TILE_SWITCHCLOSE ;
2022-05-01 23:54:29 +00:00
}
2022-06-30 22:36:32 +00:00
else if ( Switcher . m_aEndTick [ j ] < = Server ( ) - > Tick ( ) & & Switcher . m_aType [ j ] = = TILE_SWITCHTIMEDCLOSE )
2022-05-01 23:54:29 +00:00
{
2022-06-30 22:36:32 +00:00
Switcher . m_aStatus [ j ] = true ;
Switcher . m_aEndTick [ j ] = 0 ;
Switcher . m_aType [ j ] = TILE_SWITCHOPEN ;
2010-11-22 20:43:22 +00:00
}
}
2020-05-27 15:49:07 +00:00
}
2010-11-22 20:43:22 +00:00
2020-12-08 11:03:43 +00:00
if ( m_SqlRandomMapResult ! = nullptr & & m_SqlRandomMapResult - > m_Completed )
2020-06-21 22:45:17 +00:00
{
2020-12-08 11:03:43 +00:00
if ( m_SqlRandomMapResult - > m_Success )
2020-06-21 22:45:17 +00:00
{
if ( PlayerExists ( m_SqlRandomMapResult - > m_ClientID ) & & m_SqlRandomMapResult - > m_aMessage [ 0 ] ! = ' \0 ' )
SendChatTarget ( m_SqlRandomMapResult - > m_ClientID , m_SqlRandomMapResult - > m_aMessage ) ;
2021-09-13 09:47:47 +00:00
if ( m_SqlRandomMapResult - > m_aMap [ 0 ] ! = ' \0 ' )
2020-04-23 19:34:55 +00:00
Server ( ) - > ChangeMap ( m_SqlRandomMapResult - > m_aMap ) ;
2020-06-21 22:45:17 +00:00
else
m_LastMapVote = 0 ;
}
m_SqlRandomMapResult = nullptr ;
}
2021-08-14 10:40:11 +00:00
// Record player position at the end of the tick
if ( m_TeeHistorianActive )
{
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
{
if ( m_apPlayers [ i ] & & m_apPlayers [ i ] - > GetCharacter ( ) )
{
CNetObj_CharacterCore Char ;
m_apPlayers [ i ] - > GetCharacter ( ) - > GetCore ( ) . Write ( & Char ) ;
m_TeeHistorian . RecordPlayer ( i , & Char ) ;
}
else
{
m_TeeHistorian . RecordDeadPlayer ( i ) ;
}
}
m_TeeHistorian . EndPlayers ( ) ;
m_TeeHistorian . BeginInputs ( ) ;
}
// Warning: do not put code in this function directly above or below this comment
2010-05-29 07:25:38 +00:00
}
2022-06-30 21:52:30 +00:00
static int PlayerFlags_SevenToSix ( int Flags )
{
int Six = 0 ;
if ( Flags & protocol7 : : PLAYERFLAG_CHATTING )
Six | = PLAYERFLAG_CHATTING ;
if ( Flags & protocol7 : : PLAYERFLAG_SCOREBOARD )
Six | = PLAYERFLAG_SCOREBOARD ;
if ( Flags & protocol7 : : PLAYERFLAG_AIM )
Six | = PLAYERFLAG_AIM ;
return Six ;
}
2010-05-29 07:25:38 +00:00
// Server hooks
2022-06-30 21:52:30 +00:00
void CGameContext : : OnClientPrepareInput ( int ClientID , void * pInput )
{
auto * pPlayerInput = ( CNetObj_PlayerInput * ) pInput ;
if ( Server ( ) - > IsSixup ( ClientID ) )
pPlayerInput - > m_PlayerFlags = PlayerFlags_SevenToSix ( pPlayerInput - > m_PlayerFlags ) ;
}
2010-05-29 07:25:38 +00:00
void CGameContext : : OnClientDirectInput ( int ClientID , void * pInput )
{
if ( ! m_World . m_Paused )
m_apPlayers [ ClientID ] - > OnDirectInput ( ( CNetObj_PlayerInput * ) pInput ) ;
2017-09-12 12:58:44 +00:00
2020-09-23 14:52:50 +00:00
int Flags = ( ( CNetObj_PlayerInput * ) pInput ) - > m_PlayerFlags ;
if ( ( Flags & 256 ) | | ( Flags & 512 ) )
{
Server ( ) - > Kick ( ClientID , " please update your client or use DDNet client " ) ;
}
2010-05-29 07:25:38 +00:00
}
void CGameContext : : OnClientPredictedInput ( int ClientID , void * pInput )
{
2022-03-27 11:31:07 +00:00
// early return if no input at all has been sent by a player
if ( pInput = = nullptr & & ! m_aPlayerHasInput [ ClientID ] )
return ;
// set to last sent input when no new input has been sent
CNetObj_PlayerInput * pApplyInput = ( CNetObj_PlayerInput * ) pInput ;
if ( pApplyInput = = nullptr )
{
pApplyInput = & m_aLastPlayerInput [ ClientID ] ;
}
2010-05-29 07:25:38 +00:00
if ( ! m_World . m_Paused )
2022-03-27 11:31:07 +00:00
m_apPlayers [ ClientID ] - > OnPredictedInput ( pApplyInput ) ;
2010-05-29 07:25:38 +00:00
}
2019-01-29 19:32:11 +00:00
void CGameContext : : OnClientPredictedEarlyInput ( int ClientID , void * pInput )
{
2022-03-27 11:31:07 +00:00
// early return if no input at all has been sent by a player
if ( pInput = = nullptr & & ! m_aPlayerHasInput [ ClientID ] )
return ;
// set to last sent input when no new input has been sent
CNetObj_PlayerInput * pApplyInput = ( CNetObj_PlayerInput * ) pInput ;
if ( pApplyInput = = nullptr )
{
pApplyInput = & m_aLastPlayerInput [ ClientID ] ;
}
else
{
// Store input in this function and not in `OnClientPredictedInput`,
// because this function is called on all inputs, while
// `OnClientPredictedInput` is only called on the first input of each
// tick.
mem_copy ( & m_aLastPlayerInput [ ClientID ] , pApplyInput , sizeof ( m_aLastPlayerInput [ ClientID ] ) ) ;
m_aPlayerHasInput [ ClientID ] = true ;
}
2019-01-29 19:32:11 +00:00
if ( ! m_World . m_Paused )
2022-03-27 11:31:07 +00:00
m_apPlayers [ ClientID ] - > OnPredictedEarlyInput ( pApplyInput ) ;
2021-01-28 21:12:39 +00:00
if ( m_TeeHistorianActive )
{
2022-03-27 11:31:07 +00:00
m_TeeHistorian . RecordPlayerInput ( ClientID , m_apPlayers [ ClientID ] - > GetUniqueCID ( ) , pApplyInput ) ;
2021-01-28 21:12:39 +00:00
}
2019-01-29 19:32:11 +00:00
}
2015-04-18 20:29:28 +00:00
struct CVoteOptionServer * CGameContext : : GetVoteOption ( int Index )
2014-10-26 18:39:42 +00:00
{
CVoteOptionServer * pCurrent ;
2020-09-26 19:41:58 +00:00
for ( pCurrent = m_pVoteOptionFirst ;
Index > 0 & & pCurrent ;
Index - - , pCurrent = pCurrent - > m_pNext )
;
2014-10-26 18:39:42 +00:00
2020-09-26 19:41:58 +00:00
if ( Index > 0 )
2014-10-26 18:39:42 +00:00
return 0 ;
return pCurrent ;
}
void CGameContext : : ProgressVoteOptions ( int ClientID )
{
CPlayer * pPl = m_apPlayers [ ClientID ] ;
2020-09-26 19:41:58 +00:00
if ( pPl - > m_SendVoteIndex = = - 1 )
2014-10-27 12:34:29 +00:00
return ; // we didn't start sending options yet
2014-10-26 18:39:42 +00:00
2020-09-26 19:41:58 +00:00
if ( pPl - > m_SendVoteIndex > m_NumVoteOptions )
2014-10-27 12:34:29 +00:00
return ; // shouldn't happen / fail silently
2014-10-26 18:39:42 +00:00
int VotesLeft = m_NumVoteOptions - pPl - > m_SendVoteIndex ;
2019-04-26 19:36:49 +00:00
int NumVotesToSend = minimum ( g_Config . m_SvSendVotesPerTick , VotesLeft ) ;
2014-10-26 18:39:42 +00:00
2020-09-26 19:41:58 +00:00
if ( ! VotesLeft )
2014-10-26 18:39:42 +00:00
{
// player has up to date vote option list
return ;
}
// build vote option list msg
int CurIndex = 0 ;
CNetMsg_Sv_VoteOptionListAdd OptionMsg ;
OptionMsg . m_pDescription0 = " " ;
OptionMsg . m_pDescription1 = " " ;
OptionMsg . m_pDescription2 = " " ;
OptionMsg . m_pDescription3 = " " ;
OptionMsg . m_pDescription4 = " " ;
OptionMsg . m_pDescription5 = " " ;
OptionMsg . m_pDescription6 = " " ;
OptionMsg . m_pDescription7 = " " ;
OptionMsg . m_pDescription8 = " " ;
OptionMsg . m_pDescription9 = " " ;
OptionMsg . m_pDescription10 = " " ;
OptionMsg . m_pDescription11 = " " ;
OptionMsg . m_pDescription12 = " " ;
OptionMsg . m_pDescription13 = " " ;
OptionMsg . m_pDescription14 = " " ;
// get current vote option by index
CVoteOptionServer * pCurrent = GetVoteOption ( pPl - > m_SendVoteIndex ) ;
2015-06-02 09:55:16 +00:00
while ( CurIndex < NumVotesToSend & & pCurrent ! = NULL )
2014-10-26 18:39:42 +00:00
{
switch ( CurIndex )
{
2020-09-26 19:41:58 +00:00
case 0 : OptionMsg . m_pDescription0 = pCurrent - > m_aDescription ; break ;
case 1 : OptionMsg . m_pDescription1 = pCurrent - > m_aDescription ; break ;
case 2 : OptionMsg . m_pDescription2 = pCurrent - > m_aDescription ; break ;
case 3 : OptionMsg . m_pDescription3 = pCurrent - > m_aDescription ; break ;
case 4 : OptionMsg . m_pDescription4 = pCurrent - > m_aDescription ; break ;
case 5 : OptionMsg . m_pDescription5 = pCurrent - > m_aDescription ; break ;
case 6 : OptionMsg . m_pDescription6 = pCurrent - > m_aDescription ; break ;
case 7 : OptionMsg . m_pDescription7 = pCurrent - > m_aDescription ; break ;
case 8 : OptionMsg . m_pDescription8 = pCurrent - > m_aDescription ; break ;
case 9 : OptionMsg . m_pDescription9 = pCurrent - > m_aDescription ; break ;
case 10 : OptionMsg . m_pDescription10 = pCurrent - > m_aDescription ; break ;
case 11 : OptionMsg . m_pDescription11 = pCurrent - > m_aDescription ; break ;
case 12 : OptionMsg . m_pDescription12 = pCurrent - > m_aDescription ; break ;
case 13 : OptionMsg . m_pDescription13 = pCurrent - > m_aDescription ; break ;
case 14 : OptionMsg . m_pDescription14 = pCurrent - > m_aDescription ; break ;
2014-10-26 18:39:42 +00:00
}
CurIndex + + ;
pCurrent = pCurrent - > m_pNext ;
}
// send msg
OptionMsg . m_NumOptions = NumVotesToSend ;
Server ( ) - > SendPackMsg ( & OptionMsg , MSGFLAG_VITAL , ClientID ) ;
pPl - > m_SendVoteIndex + = NumVotesToSend ;
}
2011-02-12 10:40:36 +00:00
void CGameContext : : OnClientEnter ( int ClientID )
2010-05-29 07:25:38 +00:00
{
2022-02-07 11:16:37 +00:00
if ( m_TeeHistorianActive )
{
m_TeeHistorian . RecordPlayerReady ( ClientID ) ;
}
2021-01-13 00:59:29 +00:00
m_pController - > OnPlayerConnect ( m_apPlayers [ ClientID ] ) ;
2020-06-16 15:54:01 +00:00
if ( Server ( ) - > IsSixup ( ClientID ) )
{
2020-06-21 14:22:38 +00:00
{
protocol7 : : CNetMsg_Sv_GameInfo Msg ;
Msg . m_GameFlags = protocol7 : : GAMEFLAG_RACE ;
Msg . m_MatchCurrent = 1 ;
Msg . m_MatchNum = 0 ;
Msg . m_ScoreLimit = 0 ;
Msg . m_TimeLimit = 0 ;
2020-09-26 19:41:58 +00:00
Server ( ) - > SendPackMsg ( & Msg , MSGFLAG_VITAL | MSGFLAG_NORECORD , ClientID ) ;
2020-06-21 14:22:38 +00:00
}
// /team is essential
{
protocol7 : : CNetMsg_Sv_CommandInfoRemove Msg ;
2022-06-30 22:36:32 +00:00
Msg . m_pName = " team " ;
2020-09-26 19:41:58 +00:00
Server ( ) - > SendPackMsg ( & Msg , MSGFLAG_VITAL | MSGFLAG_NORECORD , ClientID ) ;
2020-06-21 14:22:38 +00:00
}
2020-06-16 17:10:07 +00:00
for ( const IConsole : : CCommandInfo * pCmd = Console ( ) - > FirstCommandInfo ( IConsole : : ACCESS_LEVEL_USER , CFGFLAG_CHAT ) ;
pCmd ; pCmd = pCmd - > NextCommandInfo ( IConsole : : ACCESS_LEVEL_USER , CFGFLAG_CHAT ) )
{
2022-03-22 22:39:58 +00:00
if ( ! str_comp_nocase ( pCmd - > m_pName , " w " ) | | ! str_comp_nocase ( pCmd - > m_pName , " whisper " ) )
2020-06-21 14:22:38 +00:00
continue ;
const char * pName = pCmd - > m_pName ;
2022-03-22 22:39:58 +00:00
if ( ! str_comp_nocase ( pCmd - > m_pName , " r " ) )
2020-06-21 14:22:38 +00:00
pName = " rescue " ;
2020-06-16 17:10:07 +00:00
protocol7 : : CNetMsg_Sv_CommandInfo Msg ;
2022-06-30 22:36:32 +00:00
Msg . m_pName = pName ;
Msg . m_pArgsFormat = pCmd - > m_pParams ;
Msg . m_pHelpText = pCmd - > m_pHelp ;
2020-09-26 19:41:58 +00:00
Server ( ) - > SendPackMsg ( & Msg , MSGFLAG_VITAL | MSGFLAG_NORECORD , ClientID ) ;
2020-06-16 17:10:07 +00:00
}
2020-06-16 15:54:01 +00:00
}
2018-12-17 13:55:58 +00:00
{
int Empty = - 1 ;
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
{
if ( ! Server ( ) - > ClientIngame ( i ) )
{
Empty = i ;
break ;
}
}
CNetMsg_Sv_Chat Msg ;
Msg . m_Team = 0 ;
Msg . m_ClientID = Empty ;
Msg . m_pMessage = " Do you know someone who uses a bot? Please report them to the moderators. " ;
m_apPlayers [ ClientID ] - > m_EligibleForFinishCheck = time_get ( ) ;
2020-09-26 19:41:58 +00:00
Server ( ) - > SendPackMsg ( & Msg , MSGFLAG_VITAL | MSGFLAG_NORECORD , ClientID ) ;
2018-12-17 13:55:58 +00:00
}
2021-12-14 05:50:30 +00:00
IServer : : CClientInfo Info ;
Handle `CServer::GetClientInfo` return to fix use of undefined value
```
/home/runner/work/ddnet/ddnet/src/engine/server/server.cpp:790:2: error: Undefined or garbage value returned to caller [clang-analyzer-core.uninitialized.UndefReturn,-warnings-as-errors]
return Info.m_DDNetVersion;
^
/home/runner/work/ddnet/ddnet/src/engine/server/server.cpp:785:5: note: Assuming 'ClientID' is not equal to SERVER_DEMO_CLIENT
if(ClientID == SERVER_DEMO_CLIENT)
^
/home/runner/work/ddnet/ddnet/src/engine/server/server.cpp:785:2: note: Taking false branch
if(ClientID == SERVER_DEMO_CLIENT)
^
/home/runner/work/ddnet/ddnet/src/engine/server/server.cpp:789:2: note: Calling 'CServer::GetClientInfo'
GetClientInfo(ClientID, &Info);
^
/home/runner/work/ddnet/ddnet/src/engine/server/server.cpp:646:13: note: Assuming 'ClientID' is >= 0
dbg_assert(ClientID >= 0 && ClientID < MAX_CLIENTS, "client_id is not valid");
^
/home/runner/work/ddnet/ddnet/src/base/tl/../system.h:58:38: note: expanded from macro 'dbg_assert'
#define dbg_assert(test, msg) assert(test)
^
/usr/include/assert.h:93:27: note: expanded from macro 'assert'
(static_cast <bool> (expr) \
^
/home/runner/work/ddnet/ddnet/src/engine/server/server.cpp:646:13: note: Left side of '&&' is true
dbg_assert(ClientID >= 0 && ClientID < MAX_CLIENTS, "client_id is not valid");
^
/home/runner/work/ddnet/ddnet/src/engine/server/server.cpp:646:30: note: Assuming 'ClientID' is < MAX_CLIENTS
dbg_assert(ClientID >= 0 && ClientID < MAX_CLIENTS, "client_id is not valid");
^
/home/runner/work/ddnet/ddnet/src/base/tl/../system.h:58:38: note: expanded from macro 'dbg_assert'
#define dbg_assert(test, msg) assert(test)
^
/usr/include/assert.h:93:27: note: expanded from macro 'assert'
(static_cast <bool> (expr) \
^
/home/runner/work/ddnet/ddnet/src/engine/server/server.cpp:646:2: note: '?' condition is true
dbg_assert(ClientID >= 0 && ClientID < MAX_CLIENTS, "client_id is not valid");
^
/home/runner/work/ddnet/ddnet/src/base/tl/../system.h:58:31: note: expanded from macro 'dbg_assert'
#define dbg_assert(test, msg) assert(test)
^
/usr/include/assert.h:93:7: note: expanded from macro 'assert'
(static_cast <bool> (expr) \
^
/home/runner/work/ddnet/ddnet/src/engine/server/server.cpp:647:13: note: 'pInfo' is not equal to null
dbg_assert(pInfo != 0, "info can not be null");
^
/home/runner/work/ddnet/ddnet/src/base/tl/../system.h:58:38: note: expanded from macro 'dbg_assert'
#define dbg_assert(test, msg) assert(test)
^
/usr/include/assert.h:93:27: note: expanded from macro 'assert'
(static_cast <bool> (expr) \
^
/home/runner/work/ddnet/ddnet/src/engine/server/server.cpp:647:2: note: '?' condition is true
dbg_assert(pInfo != 0, "info can not be null");
^
/home/runner/work/ddnet/ddnet/src/base/tl/../system.h:58:31: note: expanded from macro 'dbg_assert'
#define dbg_assert(test, msg) assert(test)
^
/usr/include/assert.h:93:7: note: expanded from macro 'assert'
(static_cast <bool> (expr) \
^
/home/runner/work/ddnet/ddnet/src/engine/server/server.cpp:649:5: note: Assuming field 'm_State' is not equal to STATE_INGAME
if(m_aClients[ClientID].m_State == CClient::STATE_INGAME)
^
/home/runner/work/ddnet/ddnet/src/engine/server/server.cpp:649:2: note: Taking false branch
if(m_aClients[ClientID].m_State == CClient::STATE_INGAME)
^
/home/runner/work/ddnet/ddnet/src/engine/server/server.cpp:667:2: note: Returning without writing to 'pInfo->m_DDNetVersion'
return 0;
^
/home/runner/work/ddnet/ddnet/src/engine/server/server.cpp:789:2: note: Returning from 'CServer::GetClientInfo'
GetClientInfo(ClientID, &Info);
^
/home/runner/work/ddnet/ddnet/src/engine/server/server.cpp:790:2: note: Undefined or garbage value returned to caller
return Info.m_DDNetVersion;
^
```
2022-07-31 10:53:26 +00:00
if ( Server ( ) - > GetClientInfo ( ClientID , & Info ) & & Info . m_GotDDNetVersion )
2021-12-14 05:50:30 +00:00
{
if ( OnClientDDNetVersionKnown ( ClientID ) )
return ; // kicked
}
2017-06-06 03:51:12 +00:00
if ( ! Server ( ) - > ClientPrevIngame ( ClientID ) )
2011-01-20 20:25:09 +00:00
{
2020-09-26 19:41:58 +00:00
if ( g_Config . m_SvWelcome [ 0 ] ! = 0 )
SendChatTarget ( ClientID , g_Config . m_SvWelcome ) ;
2011-12-31 17:16:40 +00:00
2022-03-03 21:56:32 +00:00
if ( g_Config . m_SvShowOthersDefault > SHOW_OTHERS_OFF )
2013-10-20 21:22:49 +00:00
{
2020-09-26 19:41:58 +00:00
if ( g_Config . m_SvShowOthers )
2022-08-10 13:51:46 +00:00
SendChatTarget ( ClientID , " You can see other players. To disable this use DDNet client and type /showothers " ) ;
2013-10-20 21:22:49 +00:00
2020-09-20 10:16:25 +00:00
m_apPlayers [ ClientID ] - > m_ShowOthers = g_Config . m_SvShowOthersDefault ;
2013-10-20 21:22:49 +00:00
}
2011-01-20 20:25:09 +00:00
}
2010-05-29 07:25:38 +00:00
m_VoteUpdate = true ;
2011-08-26 18:03:30 +00:00
2014-03-28 11:52:03 +00:00
// send active vote
if ( m_VoteCloseTime )
SendVoteSet ( ClientID ) ;
2019-11-04 14:33:17 +00:00
Server ( ) - > ExpireServerInfo ( ) ;
2020-03-29 02:36:38 +00:00
2020-06-10 16:12:10 +00:00
CPlayer * pNewPlayer = m_apPlayers [ ClientID ] ;
2022-03-27 11:31:07 +00:00
mem_zero ( & m_aLastPlayerInput [ ClientID ] , sizeof ( m_aLastPlayerInput [ ClientID ] ) ) ;
m_aPlayerHasInput [ ClientID ] = false ;
2020-06-15 13:37:09 +00:00
// new info for others
protocol7 : : CNetMsg_Sv_ClientInfo NewClientInfoMsg ;
NewClientInfoMsg . m_ClientID = ClientID ;
NewClientInfoMsg . m_Local = 0 ;
NewClientInfoMsg . m_Team = pNewPlayer - > GetTeam ( ) ;
NewClientInfoMsg . m_pName = Server ( ) - > ClientName ( ClientID ) ;
NewClientInfoMsg . m_pClan = Server ( ) - > ClientClan ( ClientID ) ;
NewClientInfoMsg . m_Country = Server ( ) - > ClientCountry ( ClientID ) ;
NewClientInfoMsg . m_Silent = false ;
for ( int p = 0 ; p < 6 ; p + + )
{
NewClientInfoMsg . m_apSkinPartNames [ p ] = pNewPlayer - > m_TeeInfos . m_apSkinPartNames [ p ] ;
NewClientInfoMsg . m_aUseCustomColors [ p ] = pNewPlayer - > m_TeeInfos . m_aUseCustomColors [ p ] ;
NewClientInfoMsg . m_aSkinPartColors [ p ] = pNewPlayer - > m_TeeInfos . m_aSkinPartColors [ p ] ;
}
2020-04-16 08:46:43 +00:00
// update client infos (others before local)
2022-02-21 15:33:51 +00:00
for ( int i = 0 ; i < Server ( ) - > MaxClients ( ) ; + + i )
2020-03-29 02:36:38 +00:00
{
if ( i = = ClientID | | ! m_apPlayers [ i ] | | ! Server ( ) - > ClientIngame ( i ) )
continue ;
2020-06-10 16:12:10 +00:00
CPlayer * pPlayer = m_apPlayers [ i ] ;
2020-04-13 12:19:07 +00:00
if ( Server ( ) - > IsSixup ( i ) )
2020-09-26 19:41:58 +00:00
Server ( ) - > SendPackMsg ( & NewClientInfoMsg , MSGFLAG_VITAL | MSGFLAG_NORECORD , i ) ;
2020-03-29 02:36:38 +00:00
if ( Server ( ) - > IsSixup ( ClientID ) )
{
// existing infos for new player
2020-06-14 17:32:14 +00:00
protocol7 : : CNetMsg_Sv_ClientInfo ClientInfoMsg ;
ClientInfoMsg . m_ClientID = i ;
ClientInfoMsg . m_Local = 0 ;
ClientInfoMsg . m_Team = pPlayer - > GetTeam ( ) ;
ClientInfoMsg . m_pName = Server ( ) - > ClientName ( i ) ;
ClientInfoMsg . m_pClan = Server ( ) - > ClientClan ( i ) ;
ClientInfoMsg . m_Country = Server ( ) - > ClientCountry ( i ) ;
ClientInfoMsg . m_Silent = 0 ;
for ( int p = 0 ; p < 6 ; p + + )
{
ClientInfoMsg . m_apSkinPartNames [ p ] = pPlayer - > m_TeeInfos . m_apSkinPartNames [ p ] ;
ClientInfoMsg . m_aUseCustomColors [ p ] = pPlayer - > m_TeeInfos . m_aUseCustomColors [ p ] ;
ClientInfoMsg . m_aSkinPartColors [ p ] = pPlayer - > m_TeeInfos . m_aSkinPartColors [ p ] ;
}
2020-09-26 19:41:58 +00:00
Server ( ) - > SendPackMsg ( & ClientInfoMsg , MSGFLAG_VITAL | MSGFLAG_NORECORD , ClientID ) ;
2020-03-29 02:36:38 +00:00
}
}
// local info
if ( Server ( ) - > IsSixup ( ClientID ) )
{
2020-06-15 13:37:09 +00:00
NewClientInfoMsg . m_Local = 1 ;
2020-09-26 19:41:58 +00:00
Server ( ) - > SendPackMsg ( & NewClientInfoMsg , MSGFLAG_VITAL | MSGFLAG_NORECORD , ClientID ) ;
2020-03-29 02:36:38 +00:00
}
2021-12-18 10:19:35 +00:00
// initial chat delay
if ( g_Config . m_SvChatInitialDelay ! = 0 & & m_apPlayers [ ClientID ] - > m_JoinTick > m_NonEmptySince + 10 * Server ( ) - > TickSpeed ( ) )
{
2023-09-22 10:43:36 +00:00
char aBuf [ 128 ] ;
2021-12-18 10:19:35 +00:00
NETADDR Addr ;
Server ( ) - > GetClientAddr ( ClientID , & Addr ) ;
2023-11-19 21:36:47 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " This server has an initial chat delay, you will need to wait %d seconds before talking. " , g_Config . m_SvChatInitialDelay ) ;
2023-09-22 10:43:36 +00:00
SendChatTarget ( ClientID , aBuf ) ;
2021-12-20 22:20:46 +00:00
Mute ( & Addr , g_Config . m_SvChatInitialDelay , Server ( ) - > ClientName ( ClientID ) , " Initial chat delay " , true ) ;
2021-12-18 10:19:35 +00:00
}
2022-11-29 10:47:36 +00:00
LogEvent ( " Connect " , ClientID ) ;
2010-05-29 07:25:38 +00:00
}
2021-02-07 15:03:31 +00:00
bool CGameContext : : OnClientDataPersist ( int ClientID , void * pData )
2010-05-29 07:25:38 +00:00
{
2021-02-07 15:03:31 +00:00
CPersistentClientData * pPersistent = ( CPersistentClientData * ) pData ;
if ( ! m_apPlayers [ ClientID ] )
{
return false ;
}
pPersistent - > m_IsSpectator = m_apPlayers [ ClientID ] - > GetTeam ( ) = = TEAM_SPECTATORS ;
2022-12-22 23:06:29 +00:00
pPersistent - > m_IsAfk = m_apPlayers [ ClientID ] - > IsAfk ( ) ;
2021-02-07 15:03:31 +00:00
return true ;
}
void CGameContext : : OnClientConnected ( int ClientID , void * pData )
{
CPersistentClientData * pPersistentData = ( CPersistentClientData * ) pData ;
bool Spec = false ;
2022-12-22 23:06:29 +00:00
bool Afk = true ;
2021-02-07 15:03:31 +00:00
if ( pPersistentData )
{
Spec = pPersistentData - > m_IsSpectator ;
2022-12-22 23:06:29 +00:00
Afk = pPersistentData - > m_IsAfk ;
2021-02-07 15:03:31 +00:00
}
2016-01-19 22:52:28 +00:00
{
bool Empty = true ;
2020-10-26 14:14:07 +00:00
for ( auto & pPlayer : m_apPlayers )
2016-01-19 22:52:28 +00:00
{
2023-01-02 10:10:05 +00:00
// connecting clients with spoofed ips can clog slots without being ingame
if ( pPlayer & & Server ( ) - > ClientIngame ( pPlayer - > GetCID ( ) ) )
2016-01-19 22:52:28 +00:00
{
Empty = false ;
break ;
}
}
if ( Empty )
{
m_NonEmptySince = Server ( ) - > Tick ( ) ;
}
}
2010-05-29 07:25:38 +00:00
// Check which team the player should be on
2021-02-07 15:03:31 +00:00
const int StartTeam = ( Spec | | g_Config . m_SvTournamentMode ) ? TEAM_SPECTATORS : m_pController - > GetAutoTeam ( ClientID ) ;
2010-05-29 07:25:38 +00:00
2021-12-18 10:20:22 +00:00
if ( m_apPlayers [ ClientID ] )
2014-08-18 21:50:24 +00:00
delete m_apPlayers [ ClientID ] ;
2022-03-27 11:31:07 +00:00
m_apPlayers [ ClientID ] = new ( ClientID ) CPlayer ( this , NextUniqueClientID , ClientID , StartTeam ) ;
2023-10-30 18:43:35 +00:00
m_apPlayers [ ClientID ] - > SetInitialAfk ( Afk ) ;
2022-03-27 11:31:07 +00:00
NextUniqueClientID + = 1 ;
2011-04-13 18:37:12 +00:00
2021-01-09 13:05:54 +00:00
SendMotd ( ClientID ) ;
SendSettings ( ClientID ) ;
2020-06-16 15:19:53 +00:00
2019-11-04 14:33:17 +00:00
Server ( ) - > ExpireServerInfo ( ) ;
2010-05-29 07:25:38 +00:00
}
2011-02-14 18:41:32 +00:00
void CGameContext : : OnClientDrop ( int ClientID , const char * pReason )
2010-05-29 07:25:38 +00:00
{
2022-11-29 10:47:36 +00:00
LogEvent ( " Disconnect " , ClientID ) ;
2011-02-12 10:40:36 +00:00
AbortVoteKickOnDisconnect ( ClientID ) ;
2021-01-12 20:03:20 +00:00
m_pController - > OnPlayerDisconnect ( m_apPlayers [ ClientID ] , pReason ) ;
2011-02-12 10:40:36 +00:00
delete m_apPlayers [ ClientID ] ;
m_apPlayers [ ClientID ] = 0 ;
2011-04-13 18:37:12 +00:00
2010-05-29 07:25:38 +00:00
m_VoteUpdate = true ;
2011-03-10 09:08:14 +00:00
// update spectator modes
2020-10-26 14:14:07 +00:00
for ( auto & pPlayer : m_apPlayers )
2011-03-10 09:08:14 +00:00
{
2020-10-26 14:14:07 +00:00
if ( pPlayer & & pPlayer - > m_SpectatorID = = ClientID )
pPlayer - > m_SpectatorID = SPEC_FREEVIEW ;
2011-03-10 09:08:14 +00:00
}
2013-10-18 09:42:35 +00:00
// update conversation targets
2020-10-26 14:14:07 +00:00
for ( auto & pPlayer : m_apPlayers )
2013-10-18 09:42:35 +00:00
{
2020-10-26 14:14:07 +00:00
if ( pPlayer & & pPlayer - > m_LastWhisperTo = = ClientID )
pPlayer - > m_LastWhisperTo = - 1 ;
2013-10-18 09:42:35 +00:00
}
2019-11-04 14:33:17 +00:00
2020-06-16 16:24:43 +00:00
protocol7 : : CNetMsg_Sv_ClientDrop Msg ;
Msg . m_ClientID = ClientID ;
Msg . m_pReason = pReason ;
Msg . m_Silent = false ;
2020-09-26 19:41:58 +00:00
Server ( ) - > SendPackMsg ( & Msg , MSGFLAG_VITAL | MSGFLAG_NORECORD , - 1 ) ;
2020-06-16 16:24:43 +00:00
2019-11-04 14:33:17 +00:00
Server ( ) - > ExpireServerInfo ( ) ;
2010-05-29 07:25:38 +00:00
}
2023-08-25 12:26:09 +00:00
void CGameContext : : TeehistorianRecordAntibot ( const void * pData , int DataSize )
{
if ( m_TeeHistorianActive )
{
m_TeeHistorian . RecordAntibot ( pData , DataSize ) ;
}
}
2023-06-15 19:00:14 +00:00
void CGameContext : : TeehistorianRecordPlayerJoin ( int ClientID , bool Sixup )
2017-09-13 20:35:09 +00:00
{
if ( m_TeeHistorianActive )
{
2020-06-19 20:06:39 +00:00
m_TeeHistorian . RecordPlayerJoin ( ClientID , ! Sixup ? CTeeHistorian : : PROTOCOL_6 : CTeeHistorian : : PROTOCOL_7 ) ;
2017-09-13 20:35:09 +00:00
}
}
2023-06-15 19:00:14 +00:00
void CGameContext : : TeehistorianRecordPlayerDrop ( int ClientID , const char * pReason )
2017-09-13 20:35:09 +00:00
{
if ( m_TeeHistorianActive )
{
m_TeeHistorian . RecordPlayerDrop ( ClientID , pReason ) ;
}
}
2023-08-15 20:42:09 +00:00
void CGameContext : : TeehistorianRecordPlayerRejoin ( int ClientID )
{
if ( m_TeeHistorianActive )
{
m_TeeHistorian . RecordPlayerRejoin ( ClientID ) ;
}
}
2021-02-11 11:42:26 +00:00
bool CGameContext : : OnClientDDNetVersionKnown ( int ClientID )
2020-05-22 15:58:41 +00:00
{
IServer : : CClientInfo Info ;
Handle `CServer::GetClientInfo` return to fix use of undefined value
```
/home/runner/work/ddnet/ddnet/src/engine/server/server.cpp:790:2: error: Undefined or garbage value returned to caller [clang-analyzer-core.uninitialized.UndefReturn,-warnings-as-errors]
return Info.m_DDNetVersion;
^
/home/runner/work/ddnet/ddnet/src/engine/server/server.cpp:785:5: note: Assuming 'ClientID' is not equal to SERVER_DEMO_CLIENT
if(ClientID == SERVER_DEMO_CLIENT)
^
/home/runner/work/ddnet/ddnet/src/engine/server/server.cpp:785:2: note: Taking false branch
if(ClientID == SERVER_DEMO_CLIENT)
^
/home/runner/work/ddnet/ddnet/src/engine/server/server.cpp:789:2: note: Calling 'CServer::GetClientInfo'
GetClientInfo(ClientID, &Info);
^
/home/runner/work/ddnet/ddnet/src/engine/server/server.cpp:646:13: note: Assuming 'ClientID' is >= 0
dbg_assert(ClientID >= 0 && ClientID < MAX_CLIENTS, "client_id is not valid");
^
/home/runner/work/ddnet/ddnet/src/base/tl/../system.h:58:38: note: expanded from macro 'dbg_assert'
#define dbg_assert(test, msg) assert(test)
^
/usr/include/assert.h:93:27: note: expanded from macro 'assert'
(static_cast <bool> (expr) \
^
/home/runner/work/ddnet/ddnet/src/engine/server/server.cpp:646:13: note: Left side of '&&' is true
dbg_assert(ClientID >= 0 && ClientID < MAX_CLIENTS, "client_id is not valid");
^
/home/runner/work/ddnet/ddnet/src/engine/server/server.cpp:646:30: note: Assuming 'ClientID' is < MAX_CLIENTS
dbg_assert(ClientID >= 0 && ClientID < MAX_CLIENTS, "client_id is not valid");
^
/home/runner/work/ddnet/ddnet/src/base/tl/../system.h:58:38: note: expanded from macro 'dbg_assert'
#define dbg_assert(test, msg) assert(test)
^
/usr/include/assert.h:93:27: note: expanded from macro 'assert'
(static_cast <bool> (expr) \
^
/home/runner/work/ddnet/ddnet/src/engine/server/server.cpp:646:2: note: '?' condition is true
dbg_assert(ClientID >= 0 && ClientID < MAX_CLIENTS, "client_id is not valid");
^
/home/runner/work/ddnet/ddnet/src/base/tl/../system.h:58:31: note: expanded from macro 'dbg_assert'
#define dbg_assert(test, msg) assert(test)
^
/usr/include/assert.h:93:7: note: expanded from macro 'assert'
(static_cast <bool> (expr) \
^
/home/runner/work/ddnet/ddnet/src/engine/server/server.cpp:647:13: note: 'pInfo' is not equal to null
dbg_assert(pInfo != 0, "info can not be null");
^
/home/runner/work/ddnet/ddnet/src/base/tl/../system.h:58:38: note: expanded from macro 'dbg_assert'
#define dbg_assert(test, msg) assert(test)
^
/usr/include/assert.h:93:27: note: expanded from macro 'assert'
(static_cast <bool> (expr) \
^
/home/runner/work/ddnet/ddnet/src/engine/server/server.cpp:647:2: note: '?' condition is true
dbg_assert(pInfo != 0, "info can not be null");
^
/home/runner/work/ddnet/ddnet/src/base/tl/../system.h:58:31: note: expanded from macro 'dbg_assert'
#define dbg_assert(test, msg) assert(test)
^
/usr/include/assert.h:93:7: note: expanded from macro 'assert'
(static_cast <bool> (expr) \
^
/home/runner/work/ddnet/ddnet/src/engine/server/server.cpp:649:5: note: Assuming field 'm_State' is not equal to STATE_INGAME
if(m_aClients[ClientID].m_State == CClient::STATE_INGAME)
^
/home/runner/work/ddnet/ddnet/src/engine/server/server.cpp:649:2: note: Taking false branch
if(m_aClients[ClientID].m_State == CClient::STATE_INGAME)
^
/home/runner/work/ddnet/ddnet/src/engine/server/server.cpp:667:2: note: Returning without writing to 'pInfo->m_DDNetVersion'
return 0;
^
/home/runner/work/ddnet/ddnet/src/engine/server/server.cpp:789:2: note: Returning from 'CServer::GetClientInfo'
GetClientInfo(ClientID, &Info);
^
/home/runner/work/ddnet/ddnet/src/engine/server/server.cpp:790:2: note: Undefined or garbage value returned to caller
return Info.m_DDNetVersion;
^
```
2022-07-31 10:53:26 +00:00
dbg_assert ( Server ( ) - > GetClientInfo ( ClientID , & Info ) , " failed to get client info " ) ;
2020-05-22 15:58:41 +00:00
int ClientVersion = Info . m_DDNetVersion ;
dbg_msg ( " ddnet " , " cid=%d version=%d " , ClientID , ClientVersion ) ;
if ( m_TeeHistorianActive )
{
if ( Info . m_pConnectionID & & Info . m_pDDNetVersionStr )
{
m_TeeHistorian . RecordDDNetVersion ( ClientID , * Info . m_pConnectionID , ClientVersion , Info . m_pDDNetVersionStr ) ;
}
else
{
m_TeeHistorian . RecordDDNetVersionOld ( ClientID , ClientVersion ) ;
}
}
2021-02-11 11:42:26 +00:00
// Autoban known bot versions.
if ( g_Config . m_SvBannedVersions [ 0 ] ! = ' \0 ' & & IsVersionBanned ( ClientVersion ) )
{
Server ( ) - > Kick ( ClientID , " unsupported client " ) ;
return true ;
}
2020-05-22 15:58:41 +00:00
CPlayer * pPlayer = m_apPlayers [ ClientID ] ;
if ( ClientVersion > = VERSION_DDNET_GAMETICK )
pPlayer - > m_TimerType = g_Config . m_SvDefaultTimerType ;
2020-05-27 17:45:30 +00:00
// First update the teams state.
2023-11-15 20:28:19 +00:00
m_pController - > Teams ( ) . SendTeamsState ( ClientID ) ;
2020-05-22 15:58:41 +00:00
2020-05-27 17:45:30 +00:00
// Then send records.
2020-05-22 15:58:41 +00:00
SendRecord ( ClientID ) ;
2020-05-27 17:45:30 +00:00
// And report correct tunings.
2022-06-13 14:58:56 +00:00
if ( ClientVersion < VERSION_DDNET_EARLY_VERSION )
2020-05-22 15:58:41 +00:00
SendTuningParams ( ClientID , pPlayer - > m_TuneZone ) ;
2020-05-27 17:45:30 +00:00
// Tell old clients to update.
if ( ClientVersion < VERSION_DDNET_UPDATER_FIXED & & g_Config . m_SvClientSuggestionOld [ 0 ] ! = ' \0 ' )
2020-05-22 15:58:41 +00:00
SendBroadcast ( g_Config . m_SvClientSuggestionOld , ClientID ) ;
2020-05-27 17:45:30 +00:00
// Tell known bot clients that they're botting and we know it.
if ( ( ( ClientVersion > = 15 & & ClientVersion < 100 ) | | ClientVersion = = 502 ) & & g_Config . m_SvClientSuggestionBot [ 0 ] ! = ' \0 ' )
2020-05-22 15:58:41 +00:00
SendBroadcast ( g_Config . m_SvClientSuggestionBot , ClientID ) ;
2021-02-11 11:42:26 +00:00
return false ;
2020-05-22 15:58:41 +00:00
}
2022-06-30 22:36:32 +00:00
void * CGameContext : : PreProcessMsg ( int * pMsgID , CUnpacker * pUnpacker , int ClientID )
2010-05-29 07:25:38 +00:00
{
2022-06-30 22:36:32 +00:00
if ( Server ( ) - > IsSixup ( ClientID ) & & * pMsgID < OFFSET_UUID )
2017-09-13 20:35:09 +00:00
{
2022-06-30 22:36:32 +00:00
void * pRawMsg = m_NetObjHandler7 . SecureUnpackMsg ( * pMsgID , pUnpacker ) ;
2020-03-29 02:36:38 +00:00
if ( ! pRawMsg )
2020-04-16 08:46:43 +00:00
return 0 ;
2020-03-29 02:36:38 +00:00
2020-06-10 16:12:10 +00:00
CPlayer * pPlayer = m_apPlayers [ ClientID ] ;
static char s_aRawMsg [ 1024 ] ;
2022-06-30 22:36:32 +00:00
if ( * pMsgID = = protocol7 : : NETMSGTYPE_CL_SAY )
2017-10-13 14:25:26 +00:00
{
2020-06-10 16:12:10 +00:00
protocol7 : : CNetMsg_Cl_Say * pMsg7 = ( protocol7 : : CNetMsg_Cl_Say * ) pRawMsg ;
// Should probably use a placement new to start the lifetime of the object to avoid future weirdness
: : CNetMsg_Cl_Say * pMsg = ( : : CNetMsg_Cl_Say * ) s_aRawMsg ;
2020-04-16 08:46:43 +00:00
2020-06-12 13:14:56 +00:00
if ( pMsg7 - > m_Target > = 0 )
{
2020-07-12 22:28:47 +00:00
if ( ProcessSpamProtection ( ClientID ) )
return 0 ;
2020-06-12 13:14:56 +00:00
// Should we maybe recraft the message so that it can go through the usual path?
WhisperID ( ClientID , pMsg7 - > m_Target , pMsg7 - > m_pMessage ) ;
return 0 ;
}
2020-04-16 08:46:43 +00:00
2020-06-10 16:12:10 +00:00
pMsg - > m_Team = pMsg7 - > m_Mode = = protocol7 : : CHAT_TEAM ;
2020-04-16 08:46:43 +00:00
pMsg - > m_pMessage = pMsg7 - > m_pMessage ;
}
2022-06-30 22:36:32 +00:00
else if ( * pMsgID = = protocol7 : : NETMSGTYPE_CL_STARTINFO )
2020-06-10 16:12:10 +00:00
{
protocol7 : : CNetMsg_Cl_StartInfo * pMsg7 = ( protocol7 : : CNetMsg_Cl_StartInfo * ) pRawMsg ;
: : CNetMsg_Cl_StartInfo * pMsg = ( : : CNetMsg_Cl_StartInfo * ) s_aRawMsg ;
pMsg - > m_pName = pMsg7 - > m_pName ;
pMsg - > m_pClan = pMsg7 - > m_pClan ;
pMsg - > m_Country = pMsg7 - > m_Country ;
CTeeInfo Info ( pMsg7 - > m_apSkinPartNames , pMsg7 - > m_aUseCustomColors , pMsg7 - > m_aSkinPartColors ) ;
Info . FromSixup ( ) ;
pPlayer - > m_TeeInfos = Info ;
2020-06-18 15:10:05 +00:00
2022-06-30 22:36:32 +00:00
str_copy ( s_aRawMsg + sizeof ( * pMsg ) , Info . m_aSkinName , sizeof ( s_aRawMsg ) - sizeof ( * pMsg ) ) ;
2020-06-18 15:10:05 +00:00
pMsg - > m_pSkin = s_aRawMsg + sizeof ( * pMsg ) ;
pMsg - > m_UseCustomColor = pPlayer - > m_TeeInfos . m_UseCustomColor ;
pMsg - > m_ColorBody = pPlayer - > m_TeeInfos . m_ColorBody ;
pMsg - > m_ColorFeet = pPlayer - > m_TeeInfos . m_ColorFeet ;
2020-06-10 16:12:10 +00:00
}
2022-06-30 22:36:32 +00:00
else if ( * pMsgID = = protocol7 : : NETMSGTYPE_CL_SKINCHANGE )
2020-06-10 16:12:10 +00:00
{
protocol7 : : CNetMsg_Cl_SkinChange * pMsg = ( protocol7 : : CNetMsg_Cl_SkinChange * ) pRawMsg ;
if ( g_Config . m_SvSpamprotection & & pPlayer - > m_LastChangeInfo & &
pPlayer - > m_LastChangeInfo + Server ( ) - > TickSpeed ( ) * g_Config . m_SvInfoChangeDelay > Server ( ) - > Tick ( ) )
2020-09-26 19:41:58 +00:00
return 0 ;
2020-06-10 16:12:10 +00:00
2020-06-24 13:25:35 +00:00
pPlayer - > m_LastChangeInfo = Server ( ) - > Tick ( ) ;
2020-06-10 16:12:10 +00:00
CTeeInfo Info ( pMsg - > m_apSkinPartNames , pMsg - > m_aUseCustomColors , pMsg - > m_aSkinPartColors ) ;
Info . FromSixup ( ) ;
pPlayer - > m_TeeInfos = Info ;
2020-04-16 08:46:43 +00:00
2020-06-14 17:32:14 +00:00
protocol7 : : CNetMsg_Sv_SkinChange Msg ;
Msg . m_ClientID = ClientID ;
for ( int p = 0 ; p < 6 ; p + + )
{
Msg . m_apSkinPartNames [ p ] = pMsg - > m_apSkinPartNames [ p ] ;
Msg . m_aSkinPartColors [ p ] = pMsg - > m_aSkinPartColors [ p ] ;
Msg . m_aUseCustomColors [ p ] = pMsg - > m_aUseCustomColors [ p ] ;
}
2020-09-26 19:41:58 +00:00
Server ( ) - > SendPackMsg ( & Msg , MSGFLAG_VITAL | MSGFLAG_NORECORD , - 1 ) ;
2020-06-14 17:32:14 +00:00
2020-06-10 16:12:10 +00:00
return 0 ;
}
2022-06-30 22:36:32 +00:00
else if ( * pMsgID = = protocol7 : : NETMSGTYPE_CL_SETSPECTATORMODE )
2020-06-12 20:53:41 +00:00
{
protocol7 : : CNetMsg_Cl_SetSpectatorMode * pMsg7 = ( protocol7 : : CNetMsg_Cl_SetSpectatorMode * ) pRawMsg ;
: : CNetMsg_Cl_SetSpectatorMode * pMsg = ( : : CNetMsg_Cl_SetSpectatorMode * ) s_aRawMsg ;
if ( pMsg7 - > m_SpecMode = = protocol7 : : SPEC_FREEVIEW )
pMsg - > m_SpectatorID = SPEC_FREEVIEW ;
else if ( pMsg7 - > m_SpecMode = = protocol7 : : SPEC_PLAYER )
pMsg - > m_SpectatorID = pMsg7 - > m_SpectatorID ;
else
pMsg - > m_SpectatorID = SPEC_FREEVIEW ; // Probably not needed
}
2022-06-30 22:36:32 +00:00
else if ( * pMsgID = = protocol7 : : NETMSGTYPE_CL_SETTEAM )
2020-06-16 15:19:53 +00:00
{
protocol7 : : CNetMsg_Cl_SetTeam * pMsg7 = ( protocol7 : : CNetMsg_Cl_SetTeam * ) pRawMsg ;
: : CNetMsg_Cl_SetTeam * pMsg = ( : : CNetMsg_Cl_SetTeam * ) s_aRawMsg ;
pMsg - > m_Team = pMsg7 - > m_Team ;
}
2022-06-30 22:36:32 +00:00
else if ( * pMsgID = = protocol7 : : NETMSGTYPE_CL_COMMAND )
2020-06-16 17:10:07 +00:00
{
protocol7 : : CNetMsg_Cl_Command * pMsg7 = ( protocol7 : : CNetMsg_Cl_Command * ) pRawMsg ;
: : CNetMsg_Cl_Say * pMsg = ( : : CNetMsg_Cl_Say * ) s_aRawMsg ;
2022-06-30 22:36:32 +00:00
str_format ( s_aRawMsg + sizeof ( * pMsg ) , sizeof ( s_aRawMsg ) - sizeof ( * pMsg ) , " /%s %s " , pMsg7 - > m_pName , pMsg7 - > m_pArguments ) ;
2020-06-16 17:10:07 +00:00
pMsg - > m_pMessage = s_aRawMsg + sizeof ( * pMsg ) ;
dbg_msg ( " debug " , " line='%s' " , s_aRawMsg + sizeof ( * pMsg ) ) ;
pMsg - > m_Team = 0 ;
2022-06-30 22:36:32 +00:00
* pMsgID = NETMSGTYPE_CL_SAY ;
2020-06-16 17:10:07 +00:00
return s_aRawMsg ;
}
2022-06-30 22:36:32 +00:00
else if ( * pMsgID = = protocol7 : : NETMSGTYPE_CL_CALLVOTE )
2020-06-20 11:22:46 +00:00
{
protocol7 : : CNetMsg_Cl_CallVote * pMsg7 = ( protocol7 : : CNetMsg_Cl_CallVote * ) pRawMsg ;
: : CNetMsg_Cl_CallVote * pMsg = ( : : CNetMsg_Cl_CallVote * ) s_aRawMsg ;
int Authed = Server ( ) - > GetAuthedState ( ClientID ) ;
if ( pMsg7 - > m_Force )
{
2022-06-30 22:36:32 +00:00
str_format ( s_aRawMsg , sizeof ( s_aRawMsg ) , " force_vote \" %s \" \" %s \" \" %s \" " , pMsg7 - > m_pType , pMsg7 - > m_pValue , pMsg7 - > m_pReason ) ;
2020-06-20 11:22:46 +00:00
Console ( ) - > SetAccessLevel ( Authed = = AUTHED_ADMIN ? IConsole : : ACCESS_LEVEL_ADMIN : Authed = = AUTHED_MOD ? IConsole : : ACCESS_LEVEL_MOD : IConsole : : ACCESS_LEVEL_HELPER ) ;
Console ( ) - > ExecuteLine ( s_aRawMsg , ClientID , false ) ;
Console ( ) - > SetAccessLevel ( IConsole : : ACCESS_LEVEL_ADMIN ) ;
return 0 ;
}
2022-06-30 22:36:32 +00:00
pMsg - > m_pValue = pMsg7 - > m_pValue ;
pMsg - > m_pReason = pMsg7 - > m_pReason ;
pMsg - > m_pType = pMsg7 - > m_pType ;
2020-06-20 11:22:46 +00:00
}
2022-06-30 22:36:32 +00:00
else if ( * pMsgID = = protocol7 : : NETMSGTYPE_CL_EMOTICON )
2020-06-23 09:24:09 +00:00
{
protocol7 : : CNetMsg_Cl_Emoticon * pMsg7 = ( protocol7 : : CNetMsg_Cl_Emoticon * ) pRawMsg ;
: : CNetMsg_Cl_Emoticon * pMsg = ( : : CNetMsg_Cl_Emoticon * ) s_aRawMsg ;
pMsg - > m_Emoticon = pMsg7 - > m_Emoticon ;
}
2022-06-30 22:36:32 +00:00
else if ( * pMsgID = = protocol7 : : NETMSGTYPE_CL_VOTE )
2020-07-07 10:16:53 +00:00
{
protocol7 : : CNetMsg_Cl_Vote * pMsg7 = ( protocol7 : : CNetMsg_Cl_Vote * ) pRawMsg ;
: : CNetMsg_Cl_Vote * pMsg = ( : : CNetMsg_Cl_Vote * ) s_aRawMsg ;
pMsg - > m_Vote = pMsg7 - > m_Vote ;
}
2020-06-10 16:12:10 +00:00
2022-06-30 22:36:32 +00:00
* pMsgID = Msg_SevenToSix ( * pMsgID ) ;
2020-06-10 16:12:10 +00:00
return s_aRawMsg ;
2020-04-16 08:46:43 +00:00
}
2020-06-10 16:12:10 +00:00
else
2022-06-30 22:36:32 +00:00
return m_NetObjHandler . SecureUnpackMsg ( * pMsgID , pUnpacker ) ;
2020-04-16 08:46:43 +00:00
}
2020-09-18 15:37:27 +00:00
void CGameContext : : CensorMessage ( char * pCensoredMessage , const char * pMessage , int Size )
{
str_copy ( pCensoredMessage , pMessage , Size ) ;
2022-05-23 20:35:21 +00:00
for ( auto & Item : m_vCensorlist )
2020-09-18 15:37:27 +00:00
{
2020-10-04 15:25:14 +00:00
char * pCurLoc = pCensoredMessage ;
do
{
2022-05-23 20:35:21 +00:00
pCurLoc = ( char * ) str_utf8_find_nocase ( pCurLoc , Item . c_str ( ) ) ;
2020-10-04 15:25:14 +00:00
if ( pCurLoc )
{
2022-09-02 12:32:39 +00:00
for ( int i = 0 ; i < ( int ) Item . length ( ) ; i + + )
{
pCurLoc [ i ] = ' * ' ;
}
2020-10-04 15:25:14 +00:00
pCurLoc + + ;
}
} while ( pCurLoc ) ;
2020-09-18 15:37:27 +00:00
}
}
2020-04-16 08:46:43 +00:00
void CGameContext : : OnMessage ( int MsgID , CUnpacker * pUnpacker , int ClientID )
{
if ( m_TeeHistorianActive )
{
if ( m_NetObjHandler . TeeHistorianRecordMsg ( MsgID ) )
{
m_TeeHistorian . RecordPlayerMessage ( ClientID , pUnpacker - > CompleteData ( ) , pUnpacker - > CompleteSize ( ) ) ;
2017-10-13 14:25:26 +00:00
}
2017-09-13 20:35:09 +00:00
}
2020-06-10 16:12:10 +00:00
void * pRawMsg = PreProcessMsg ( & MsgID , pUnpacker , ClientID ) ;
2020-06-21 22:06:33 +00:00
if ( ! pRawMsg )
return ;
2013-03-23 14:59:27 +00:00
if ( Server ( ) - > ClientIngame ( ClientID ) )
2010-05-29 07:25:38 +00:00
{
2023-09-08 17:22:32 +00:00
switch ( MsgID )
{
case NETMSGTYPE_CL_SAY :
2023-08-15 20:17:06 +00:00
OnSayNetMessage ( static_cast < CNetMsg_Cl_Say * > ( pRawMsg ) , ClientID , pUnpacker ) ;
2023-09-08 17:22:32 +00:00
break ;
case NETMSGTYPE_CL_CALLVOTE :
2023-08-15 20:12:24 +00:00
OnCallVoteNetMessage ( static_cast < CNetMsg_Cl_CallVote * > ( pRawMsg ) , ClientID ) ;
2023-09-08 17:22:32 +00:00
break ;
case NETMSGTYPE_CL_VOTE :
2023-08-15 20:12:24 +00:00
OnVoteNetMessage ( static_cast < CNetMsg_Cl_Vote * > ( pRawMsg ) , ClientID ) ;
2023-09-08 17:22:32 +00:00
break ;
case NETMSGTYPE_CL_SETTEAM :
2023-08-15 20:23:01 +00:00
OnSetTeamNetMessage ( static_cast < CNetMsg_Cl_SetTeam * > ( pRawMsg ) , ClientID ) ;
2023-09-08 17:22:32 +00:00
break ;
case NETMSGTYPE_CL_ISDDNETLEGACY :
2023-09-08 17:02:59 +00:00
OnIsDDNetLegacyNetMessage ( static_cast < CNetMsg_Cl_IsDDNetLegacy * > ( pRawMsg ) , ClientID , pUnpacker ) ;
2023-09-08 17:22:32 +00:00
break ;
case NETMSGTYPE_CL_SHOWOTHERSLEGACY :
2023-09-08 17:02:59 +00:00
OnShowOthersLegacyNetMessage ( static_cast < CNetMsg_Cl_ShowOthersLegacy * > ( pRawMsg ) , ClientID ) ;
2023-09-08 17:22:32 +00:00
break ;
case NETMSGTYPE_CL_SHOWOTHERS :
2023-09-08 17:02:59 +00:00
OnShowOthersNetMessage ( static_cast < CNetMsg_Cl_ShowOthers * > ( pRawMsg ) , ClientID ) ;
2023-09-08 17:22:32 +00:00
break ;
case NETMSGTYPE_CL_SHOWDISTANCE :
2023-09-08 17:02:59 +00:00
OnShowDistanceNetMessage ( static_cast < CNetMsg_Cl_ShowDistance * > ( pRawMsg ) , ClientID ) ;
2023-09-08 17:22:32 +00:00
break ;
case NETMSGTYPE_CL_SETSPECTATORMODE :
2023-09-08 17:02:59 +00:00
OnSetSpectatorModeNetMessage ( static_cast < CNetMsg_Cl_SetSpectatorMode * > ( pRawMsg ) , ClientID ) ;
2023-09-08 17:22:32 +00:00
break ;
case NETMSGTYPE_CL_CHANGEINFO :
2023-08-15 20:45:28 +00:00
OnChangeInfoNetMessage ( static_cast < CNetMsg_Cl_ChangeInfo * > ( pRawMsg ) , ClientID ) ;
2023-09-08 17:22:32 +00:00
break ;
case NETMSGTYPE_CL_EMOTICON :
2023-08-15 21:27:41 +00:00
OnEmoticonNetMessage ( static_cast < CNetMsg_Cl_Emoticon * > ( pRawMsg ) , ClientID ) ;
2023-09-08 17:22:32 +00:00
break ;
case NETMSGTYPE_CL_KILL :
2023-09-08 17:02:59 +00:00
OnKillNetMessage ( static_cast < CNetMsg_Cl_Kill * > ( pRawMsg ) , ClientID ) ;
2023-09-08 17:22:32 +00:00
break ;
default :
break ;
}
2010-05-29 07:25:38 +00:00
}
2020-09-26 19:41:58 +00:00
if ( MsgID = = NETMSGTYPE_CL_STARTINFO )
2010-05-29 07:25:38 +00:00
{
2023-08-15 21:50:41 +00:00
OnStartInfoNetMessage ( static_cast < CNetMsg_Cl_StartInfo * > ( pRawMsg ) , ClientID ) ;
2010-05-29 07:25:38 +00:00
}
}
2011-01-29 00:59:50 +00:00
2023-08-15 20:17:06 +00:00
void CGameContext : : OnSayNetMessage ( const CNetMsg_Cl_Say * pMsg , int ClientID , const CUnpacker * pUnpacker )
{
if ( ! str_utf8_check ( pMsg - > m_pMessage ) )
{
return ;
}
CPlayer * pPlayer = m_apPlayers [ ClientID ] ;
bool Check = ! pPlayer - > m_NotEligibleForFinish & & pPlayer - > m_EligibleForFinishCheck + 10 * time_freq ( ) > = time_get ( ) ;
if ( Check & & str_comp ( pMsg - > m_pMessage , " xd sure chillerbot.png is lyfe " ) = = 0 & & pMsg - > m_Team = = 0 )
{
if ( m_TeeHistorianActive )
{
m_TeeHistorian . RecordPlayerMessage ( ClientID , pUnpacker - > CompleteData ( ) , pUnpacker - > CompleteSize ( ) ) ;
}
pPlayer - > m_NotEligibleForFinish = true ;
dbg_msg ( " hack " , " bot detected, cid=%d " , ClientID ) ;
return ;
}
int Team = pMsg - > m_Team ;
// trim right and set maximum length to 256 utf8-characters
int Length = 0 ;
const char * p = pMsg - > m_pMessage ;
const char * pEnd = 0 ;
while ( * p )
{
const char * pStrOld = p ;
int Code = str_utf8_decode ( & p ) ;
// check if unicode is not empty
if ( ! str_utf8_isspace ( Code ) )
{
pEnd = 0 ;
}
else if ( pEnd = = 0 )
pEnd = pStrOld ;
if ( + + Length > = 256 )
{
* ( const_cast < char * > ( p ) ) = 0 ;
break ;
}
}
if ( pEnd ! = 0 )
* ( const_cast < char * > ( pEnd ) ) = 0 ;
// drop empty and autocreated spam messages (more than 32 characters per second)
if ( Length = = 0 | | ( pMsg - > m_pMessage [ 0 ] ! = ' / ' & & ( g_Config . m_SvSpamprotection & & pPlayer - > m_LastChat & & pPlayer - > m_LastChat + Server ( ) - > TickSpeed ( ) * ( ( 31 + Length ) / 32 ) > Server ( ) - > Tick ( ) ) ) )
return ;
2023-11-15 20:28:19 +00:00
int GameTeam = GetDDRaceTeam ( pPlayer - > GetCID ( ) ) ;
2023-08-15 20:17:06 +00:00
if ( Team )
Team = ( ( pPlayer - > GetTeam ( ) = = TEAM_SPECTATORS ) ? CHAT_SPEC : GameTeam ) ;
else
Team = CHAT_ALL ;
if ( pMsg - > m_pMessage [ 0 ] = = ' / ' )
{
if ( str_startswith_nocase ( pMsg - > m_pMessage + 1 , " w " ) )
{
char aWhisperMsg [ 256 ] ;
str_copy ( aWhisperMsg , pMsg - > m_pMessage + 3 , 256 ) ;
Whisper ( pPlayer - > GetCID ( ) , aWhisperMsg ) ;
}
else if ( str_startswith_nocase ( pMsg - > m_pMessage + 1 , " whisper " ) )
{
char aWhisperMsg [ 256 ] ;
str_copy ( aWhisperMsg , pMsg - > m_pMessage + 9 , 256 ) ;
Whisper ( pPlayer - > GetCID ( ) , aWhisperMsg ) ;
}
else if ( str_startswith_nocase ( pMsg - > m_pMessage + 1 , " c " ) )
{
char aWhisperMsg [ 256 ] ;
str_copy ( aWhisperMsg , pMsg - > m_pMessage + 3 , 256 ) ;
Converse ( pPlayer - > GetCID ( ) , aWhisperMsg ) ;
}
else if ( str_startswith_nocase ( pMsg - > m_pMessage + 1 , " converse " ) )
{
char aWhisperMsg [ 256 ] ;
str_copy ( aWhisperMsg , pMsg - > m_pMessage + 10 , 256 ) ;
Converse ( pPlayer - > GetCID ( ) , aWhisperMsg ) ;
}
else
{
if ( g_Config . m_SvSpamprotection & & ! str_startswith ( pMsg - > m_pMessage + 1 , " timeout " ) & & pPlayer - > m_aLastCommands [ 0 ] & & pPlayer - > m_aLastCommands [ 0 ] + Server ( ) - > TickSpeed ( ) > Server ( ) - > Tick ( ) & & pPlayer - > m_aLastCommands [ 1 ] & & pPlayer - > m_aLastCommands [ 1 ] + Server ( ) - > TickSpeed ( ) > Server ( ) - > Tick ( ) & & pPlayer - > m_aLastCommands [ 2 ] & & pPlayer - > m_aLastCommands [ 2 ] + Server ( ) - > TickSpeed ( ) > Server ( ) - > Tick ( ) & & pPlayer - > m_aLastCommands [ 3 ] & & pPlayer - > m_aLastCommands [ 3 ] + Server ( ) - > TickSpeed ( ) > Server ( ) - > Tick ( ) )
return ;
int64_t Now = Server ( ) - > Tick ( ) ;
pPlayer - > m_aLastCommands [ pPlayer - > m_LastCommandPos ] = Now ;
pPlayer - > m_LastCommandPos = ( pPlayer - > m_LastCommandPos + 1 ) % 4 ;
Console ( ) - > SetFlagMask ( CFGFLAG_CHAT ) ;
int Authed = Server ( ) - > GetAuthedState ( ClientID ) ;
if ( Authed )
Console ( ) - > SetAccessLevel ( Authed = = AUTHED_ADMIN ? IConsole : : ACCESS_LEVEL_ADMIN : Authed = = AUTHED_MOD ? IConsole : : ACCESS_LEVEL_MOD : IConsole : : ACCESS_LEVEL_HELPER ) ;
else
Console ( ) - > SetAccessLevel ( IConsole : : ACCESS_LEVEL_USER ) ;
{
CClientChatLogger Logger ( this , ClientID , log_get_scope_logger ( ) ) ;
CLogScope Scope ( & Logger ) ;
Console ( ) - > ExecuteLine ( pMsg - > m_pMessage + 1 , ClientID , false ) ;
}
// m_apPlayers[ClientID] can be NULL, if the player used a
// timeout code and replaced another client.
char aBuf [ 256 ] ;
str_format ( aBuf , sizeof ( aBuf ) , " %d used %s " , ClientID , pMsg - > m_pMessage ) ;
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_DEBUG , " chat-command " , aBuf ) ;
Console ( ) - > SetAccessLevel ( IConsole : : ACCESS_LEVEL_ADMIN ) ;
Console ( ) - > SetFlagMask ( CFGFLAG_SERVER ) ;
}
}
else
{
pPlayer - > UpdatePlaytime ( ) ;
char aCensoredMessage [ 256 ] ;
CensorMessage ( aCensoredMessage , pMsg - > m_pMessage , sizeof ( aCensoredMessage ) ) ;
SendChat ( ClientID , Team , aCensoredMessage , ClientID ) ;
}
}
2023-08-15 20:12:24 +00:00
void CGameContext : : OnCallVoteNetMessage ( const CNetMsg_Cl_CallVote * pMsg , int ClientID )
{
if ( RateLimitPlayerVote ( ClientID ) | | m_VoteCloseTime )
return ;
m_apPlayers [ ClientID ] - > UpdatePlaytime ( ) ;
m_VoteType = VOTE_TYPE_UNKNOWN ;
char aChatmsg [ 512 ] = { 0 } ;
char aDesc [ VOTE_DESC_LENGTH ] = { 0 } ;
char aSixupDesc [ VOTE_DESC_LENGTH ] = { 0 } ;
char aCmd [ VOTE_CMD_LENGTH ] = { 0 } ;
char aReason [ VOTE_REASON_LENGTH ] = " No reason given " ;
if ( ! str_utf8_check ( pMsg - > m_pType ) | | ! str_utf8_check ( pMsg - > m_pReason ) | | ! str_utf8_check ( pMsg - > m_pValue ) )
{
return ;
}
if ( pMsg - > m_pReason [ 0 ] )
{
str_copy ( aReason , pMsg - > m_pReason , sizeof ( aReason ) ) ;
}
if ( str_comp_nocase ( pMsg - > m_pType , " option " ) = = 0 )
{
int Authed = Server ( ) - > GetAuthedState ( ClientID ) ;
CVoteOptionServer * pOption = m_pVoteOptionFirst ;
while ( pOption )
{
if ( str_comp_nocase ( pMsg - > m_pValue , pOption - > m_aDescription ) = = 0 )
{
if ( ! Console ( ) - > LineIsValid ( pOption - > m_aCommand ) )
{
SendChatTarget ( ClientID , " Invalid option " ) ;
return ;
}
if ( ( str_find ( pOption - > m_aCommand , " sv_map " ) ! = 0 | | str_find ( pOption - > m_aCommand , " change_map " ) ! = 0 | | str_find ( pOption - > m_aCommand , " random_map " ) ! = 0 | | str_find ( pOption - > m_aCommand , " random_unfinished_map " ) ! = 0 ) & & RateLimitPlayerMapVote ( ClientID ) )
{
return ;
}
str_format ( aChatmsg , sizeof ( aChatmsg ) , " '%s' called vote to change server option '%s' (%s) " , Server ( ) - > ClientName ( ClientID ) ,
pOption - > m_aDescription , aReason ) ;
str_copy ( aDesc , pOption - > m_aDescription ) ;
if ( ( str_endswith ( pOption - > m_aCommand , " random_map " ) | | str_endswith ( pOption - > m_aCommand , " random_unfinished_map " ) ) & & str_length ( aReason ) = = 1 & & aReason [ 0 ] > = ' 0 ' & & aReason [ 0 ] < = ' 5 ' )
{
int Stars = aReason [ 0 ] - ' 0 ' ;
str_format ( aCmd , sizeof ( aCmd ) , " %s %d " , pOption - > m_aCommand , Stars ) ;
}
else
{
str_copy ( aCmd , pOption - > m_aCommand ) ;
}
m_LastMapVote = time_get ( ) ;
break ;
}
pOption = pOption - > m_pNext ;
}
if ( ! pOption )
{
if ( Authed ! = AUTHED_ADMIN ) // allow admins to call any vote they want
{
str_format ( aChatmsg , sizeof ( aChatmsg ) , " '%s' isn't an option on this server " , pMsg - > m_pValue ) ;
SendChatTarget ( ClientID , aChatmsg ) ;
return ;
}
else
{
str_format ( aChatmsg , sizeof ( aChatmsg ) , " '%s' called vote to change server option '%s' " , Server ( ) - > ClientName ( ClientID ) , pMsg - > m_pValue ) ;
str_copy ( aDesc , pMsg - > m_pValue ) ;
str_copy ( aCmd , pMsg - > m_pValue ) ;
}
}
m_VoteType = VOTE_TYPE_OPTION ;
}
else if ( str_comp_nocase ( pMsg - > m_pType , " kick " ) = = 0 )
{
int Authed = Server ( ) - > GetAuthedState ( ClientID ) ;
2023-11-18 12:09:13 +00:00
if ( ! g_Config . m_SvVoteKick & & ! Authed ) // allow admins to call kick votes even if they are forbidden
{
SendChatTarget ( ClientID , " Server does not allow voting to kick players " ) ;
2023-08-15 20:12:24 +00:00
return ;
2023-11-18 12:09:13 +00:00
}
if ( ! Authed & & time_get ( ) < m_apPlayers [ ClientID ] - > m_Last_KickVote + ( time_freq ( ) * g_Config . m_SvVoteKickDelay ) )
2023-08-15 20:12:24 +00:00
{
str_format ( aChatmsg , sizeof ( aChatmsg ) , " There's a %d second wait time between kick votes for each player please wait %d second(s) " ,
g_Config . m_SvVoteKickDelay ,
2023-11-18 12:09:13 +00:00
( int ) ( ( m_apPlayers [ ClientID ] - > m_Last_KickVote + g_Config . m_SvVoteKickDelay * time_freq ( ) - time_get ( ) ) / time_freq ( ) ) ) ;
2023-08-15 20:12:24 +00:00
SendChatTarget ( ClientID , aChatmsg ) ;
return ;
}
if ( g_Config . m_SvVoteKickMin & & ! GetDDRaceTeam ( ClientID ) )
{
char aaAddresses [ MAX_CLIENTS ] [ NETADDR_MAXSTRSIZE ] = { { 0 } } ;
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
{
if ( m_apPlayers [ i ] )
{
Server ( ) - > GetClientAddr ( i , aaAddresses [ i ] , NETADDR_MAXSTRSIZE ) ;
}
}
int NumPlayers = 0 ;
for ( int i = 0 ; i < MAX_CLIENTS ; + + i )
{
if ( m_apPlayers [ i ] & & m_apPlayers [ i ] - > GetTeam ( ) ! = TEAM_SPECTATORS & & ! GetDDRaceTeam ( i ) )
{
NumPlayers + + ;
for ( int j = 0 ; j < i ; j + + )
{
if ( m_apPlayers [ j ] & & m_apPlayers [ j ] - > GetTeam ( ) ! = TEAM_SPECTATORS & & ! GetDDRaceTeam ( j ) )
{
if ( str_comp ( aaAddresses [ i ] , aaAddresses [ j ] ) = = 0 )
{
NumPlayers - - ;
break ;
}
}
}
}
}
if ( NumPlayers < g_Config . m_SvVoteKickMin )
{
str_format ( aChatmsg , sizeof ( aChatmsg ) , " Kick voting requires %d players " , g_Config . m_SvVoteKickMin ) ;
SendChatTarget ( ClientID , aChatmsg ) ;
return ;
}
}
int KickID = str_toint ( pMsg - > m_pValue ) ;
if ( KickID < 0 | | KickID > = MAX_CLIENTS | | ! m_apPlayers [ KickID ] )
{
SendChatTarget ( ClientID , " Invalid client id to kick " ) ;
return ;
}
if ( KickID = = ClientID )
{
SendChatTarget ( ClientID , " You can't kick yourself " ) ;
return ;
}
if ( ! Server ( ) - > ReverseTranslate ( KickID , ClientID ) )
{
return ;
}
int KickedAuthed = Server ( ) - > GetAuthedState ( KickID ) ;
if ( KickedAuthed > Authed )
{
SendChatTarget ( ClientID , " You can't kick authorized players " ) ;
char aBufKick [ 128 ] ;
str_format ( aBufKick , sizeof ( aBufKick ) , " '%s' called for vote to kick you " , Server ( ) - > ClientName ( ClientID ) ) ;
SendChatTarget ( KickID , aBufKick ) ;
return ;
}
// Don't allow kicking if a player has no character
if ( ! GetPlayerChar ( ClientID ) | | ! GetPlayerChar ( KickID ) | | GetDDRaceTeam ( ClientID ) ! = GetDDRaceTeam ( KickID ) )
{
SendChatTarget ( ClientID , " You can kick only your team member " ) ;
return ;
}
str_format ( aChatmsg , sizeof ( aChatmsg ) , " '%s' called for vote to kick '%s' (%s) " , Server ( ) - > ClientName ( ClientID ) , Server ( ) - > ClientName ( KickID ) , aReason ) ;
str_format ( aSixupDesc , sizeof ( aSixupDesc ) , " %2d: %s " , KickID , Server ( ) - > ClientName ( KickID ) ) ;
if ( ! GetDDRaceTeam ( ClientID ) )
{
if ( ! g_Config . m_SvVoteKickBantime )
{
str_format ( aCmd , sizeof ( aCmd ) , " kick %d Kicked by vote " , KickID ) ;
str_format ( aDesc , sizeof ( aDesc ) , " Kick '%s' " , Server ( ) - > ClientName ( KickID ) ) ;
}
else
{
char aAddrStr [ NETADDR_MAXSTRSIZE ] = { 0 } ;
Server ( ) - > GetClientAddr ( KickID , aAddrStr , sizeof ( aAddrStr ) ) ;
str_format ( aCmd , sizeof ( aCmd ) , " ban %s %d Banned by vote " , aAddrStr , g_Config . m_SvVoteKickBantime ) ;
str_format ( aDesc , sizeof ( aDesc ) , " Ban '%s' " , Server ( ) - > ClientName ( KickID ) ) ;
}
}
else
{
str_format ( aCmd , sizeof ( aCmd ) , " uninvite %d %d; set_team_ddr %d 0 " , KickID , GetDDRaceTeam ( KickID ) , KickID ) ;
str_format ( aDesc , sizeof ( aDesc ) , " Move '%s' to team 0 " , Server ( ) - > ClientName ( KickID ) ) ;
}
m_apPlayers [ ClientID ] - > m_Last_KickVote = time_get ( ) ;
m_VoteType = VOTE_TYPE_KICK ;
m_VoteVictim = KickID ;
}
else if ( str_comp_nocase ( pMsg - > m_pType , " spectate " ) = = 0 )
{
if ( ! g_Config . m_SvVoteSpectate )
{
SendChatTarget ( ClientID , " Server does not allow voting to move players to spectators " ) ;
return ;
}
int SpectateID = str_toint ( pMsg - > m_pValue ) ;
if ( SpectateID < 0 | | SpectateID > = MAX_CLIENTS | | ! m_apPlayers [ SpectateID ] | | m_apPlayers [ SpectateID ] - > GetTeam ( ) = = TEAM_SPECTATORS )
{
SendChatTarget ( ClientID , " Invalid client id to move " ) ;
return ;
}
if ( SpectateID = = ClientID )
{
SendChatTarget ( ClientID , " You can't move yourself " ) ;
return ;
}
if ( ! Server ( ) - > ReverseTranslate ( SpectateID , ClientID ) )
{
return ;
}
if ( ! GetPlayerChar ( ClientID ) | | ! GetPlayerChar ( SpectateID ) | | GetDDRaceTeam ( ClientID ) ! = GetDDRaceTeam ( SpectateID ) )
{
SendChatTarget ( ClientID , " You can only move your team member to spectators " ) ;
return ;
}
str_format ( aSixupDesc , sizeof ( aSixupDesc ) , " %2d: %s " , SpectateID , Server ( ) - > ClientName ( SpectateID ) ) ;
if ( g_Config . m_SvPauseable & & g_Config . m_SvVotePause )
{
str_format ( aChatmsg , sizeof ( aChatmsg ) , " '%s' called for vote to pause '%s' for %d seconds (%s) " , Server ( ) - > ClientName ( ClientID ) , Server ( ) - > ClientName ( SpectateID ) , g_Config . m_SvVotePauseTime , aReason ) ;
str_format ( aDesc , sizeof ( aDesc ) , " Pause '%s' (%ds) " , Server ( ) - > ClientName ( SpectateID ) , g_Config . m_SvVotePauseTime ) ;
str_format ( aCmd , sizeof ( aCmd ) , " uninvite %d %d; force_pause %d %d " , SpectateID , GetDDRaceTeam ( SpectateID ) , SpectateID , g_Config . m_SvVotePauseTime ) ;
}
else
{
str_format ( aChatmsg , sizeof ( aChatmsg ) , " '%s' called for vote to move '%s' to spectators (%s) " , Server ( ) - > ClientName ( ClientID ) , Server ( ) - > ClientName ( SpectateID ) , aReason ) ;
str_format ( aDesc , sizeof ( aDesc ) , " Move '%s' to spectators " , Server ( ) - > ClientName ( SpectateID ) ) ;
str_format ( aCmd , sizeof ( aCmd ) , " uninvite %d %d; set_team %d -1 %d " , SpectateID , GetDDRaceTeam ( SpectateID ) , SpectateID , g_Config . m_SvVoteSpectateRejoindelay ) ;
}
m_VoteType = VOTE_TYPE_SPECTATE ;
m_VoteVictim = SpectateID ;
}
if ( aCmd [ 0 ] & & str_comp_nocase ( aCmd , " info " ) ! = 0 )
CallVote ( ClientID , aDesc , aCmd , aReason , aChatmsg , aSixupDesc [ 0 ] ? aSixupDesc : 0 ) ;
}
void CGameContext : : OnVoteNetMessage ( const CNetMsg_Cl_Vote * pMsg , int ClientID )
{
if ( ! m_VoteCloseTime )
return ;
CPlayer * pPlayer = m_apPlayers [ ClientID ] ;
if ( g_Config . m_SvSpamprotection & & pPlayer - > m_LastVoteTry & & pPlayer - > m_LastVoteTry + Server ( ) - > TickSpeed ( ) * 3 > Server ( ) - > Tick ( ) )
return ;
int64_t Now = Server ( ) - > Tick ( ) ;
pPlayer - > m_LastVoteTry = Now ;
pPlayer - > UpdatePlaytime ( ) ;
if ( ! pMsg - > m_Vote )
return ;
pPlayer - > m_Vote = pMsg - > m_Vote ;
pPlayer - > m_VotePos = + + m_VotePos ;
m_VoteUpdate = true ;
2023-09-15 11:58:30 +00:00
CNetMsg_Sv_YourVote Msg = { pMsg - > m_Vote } ;
Server ( ) - > SendPackMsg ( & Msg , MSGFLAG_VITAL , ClientID ) ;
2023-08-15 20:12:24 +00:00
}
2023-08-15 20:23:01 +00:00
void CGameContext : : OnSetTeamNetMessage ( const CNetMsg_Cl_SetTeam * pMsg , int ClientID )
{
2023-08-15 20:44:37 +00:00
if ( m_World . m_Paused )
return ;
2023-08-15 20:23:01 +00:00
CPlayer * pPlayer = m_apPlayers [ ClientID ] ;
if ( pPlayer - > GetTeam ( ) = = pMsg - > m_Team | | ( g_Config . m_SvSpamprotection & & pPlayer - > m_LastSetTeam & & pPlayer - > m_LastSetTeam + Server ( ) - > TickSpeed ( ) * g_Config . m_SvTeamChangeDelay > Server ( ) - > Tick ( ) ) )
return ;
// Kill Protection
CCharacter * pChr = pPlayer - > GetCharacter ( ) ;
if ( pChr )
{
int CurrTime = ( Server ( ) - > Tick ( ) - pChr - > m_StartTime ) / Server ( ) - > TickSpeed ( ) ;
if ( g_Config . m_SvKillProtection ! = 0 & & CurrTime > = ( 60 * g_Config . m_SvKillProtection ) & & pChr - > m_DDRaceState = = DDRACE_STARTED )
{
SendChatTarget ( ClientID , " Kill Protection enabled. If you really want to join the spectators, first type /kill " ) ;
return ;
}
}
if ( pPlayer - > m_TeamChangeTick > Server ( ) - > Tick ( ) )
{
pPlayer - > m_LastSetTeam = Server ( ) - > Tick ( ) ;
int TimeLeft = ( pPlayer - > m_TeamChangeTick - Server ( ) - > Tick ( ) ) / Server ( ) - > TickSpeed ( ) ;
char aTime [ 32 ] ;
str_time ( ( int64_t ) TimeLeft * 100 , TIME_HOURS , aTime , sizeof ( aTime ) ) ;
char aBuf [ 128 ] ;
str_format ( aBuf , sizeof ( aBuf ) , " Time to wait before changing team: %s " , aTime ) ;
SendBroadcast ( aBuf , ClientID ) ;
return ;
}
// Switch team on given client and kill/respawn them
if ( m_pController - > CanJoinTeam ( pMsg - > m_Team , ClientID ) )
{
if ( pPlayer - > IsPaused ( ) )
SendChatTarget ( ClientID , " Use /pause first then you can kill " ) ;
else
{
if ( pPlayer - > GetTeam ( ) = = TEAM_SPECTATORS | | pMsg - > m_Team = = TEAM_SPECTATORS )
m_VoteUpdate = true ;
m_pController - > DoTeamChange ( pPlayer , pMsg - > m_Team ) ;
pPlayer - > m_TeamChangeTick = Server ( ) - > Tick ( ) ;
}
}
else
{
char aBuf [ 128 ] ;
str_format ( aBuf , sizeof ( aBuf ) , " Only %d active players are allowed " , Server ( ) - > MaxClients ( ) - g_Config . m_SvSpectatorSlots ) ;
SendBroadcast ( aBuf , ClientID ) ;
}
}
2023-09-08 17:02:59 +00:00
void CGameContext : : OnIsDDNetLegacyNetMessage ( const CNetMsg_Cl_IsDDNetLegacy * pMsg , int ClientID , CUnpacker * pUnpacker )
{
IServer : : CClientInfo Info ;
if ( Server ( ) - > GetClientInfo ( ClientID , & Info ) & & Info . m_GotDDNetVersion )
{
return ;
}
int DDNetVersion = pUnpacker - > GetInt ( ) ;
if ( pUnpacker - > Error ( ) | | DDNetVersion < 0 )
{
DDNetVersion = VERSION_DDRACE ;
}
Server ( ) - > SetClientDDNetVersion ( ClientID , DDNetVersion ) ;
OnClientDDNetVersionKnown ( ClientID ) ;
}
void CGameContext : : OnShowOthersLegacyNetMessage ( const CNetMsg_Cl_ShowOthersLegacy * pMsg , int ClientID )
{
if ( g_Config . m_SvShowOthers & & ! g_Config . m_SvShowOthersDefault )
{
CPlayer * pPlayer = m_apPlayers [ ClientID ] ;
pPlayer - > m_ShowOthers = pMsg - > m_Show ;
}
}
void CGameContext : : OnShowOthersNetMessage ( const CNetMsg_Cl_ShowOthers * pMsg , int ClientID )
{
if ( g_Config . m_SvShowOthers & & ! g_Config . m_SvShowOthersDefault )
{
CPlayer * pPlayer = m_apPlayers [ ClientID ] ;
pPlayer - > m_ShowOthers = pMsg - > m_Show ;
}
}
void CGameContext : : OnShowDistanceNetMessage ( const CNetMsg_Cl_ShowDistance * pMsg , int ClientID )
{
CPlayer * pPlayer = m_apPlayers [ ClientID ] ;
pPlayer - > m_ShowDistance = vec2 ( pMsg - > m_X , pMsg - > m_Y ) ;
}
void CGameContext : : OnSetSpectatorModeNetMessage ( const CNetMsg_Cl_SetSpectatorMode * pMsg , int ClientID )
{
if ( m_World . m_Paused )
return ;
int SpectatorID = clamp ( pMsg - > m_SpectatorID , ( int ) SPEC_FOLLOW , MAX_CLIENTS - 1 ) ;
if ( SpectatorID > = 0 )
if ( ! Server ( ) - > ReverseTranslate ( SpectatorID , ClientID ) )
return ;
CPlayer * pPlayer = m_apPlayers [ ClientID ] ;
if ( ( g_Config . m_SvSpamprotection & & pPlayer - > m_LastSetSpectatorMode & & pPlayer - > m_LastSetSpectatorMode + Server ( ) - > TickSpeed ( ) / 4 > Server ( ) - > Tick ( ) ) )
return ;
pPlayer - > m_LastSetSpectatorMode = Server ( ) - > Tick ( ) ;
pPlayer - > UpdatePlaytime ( ) ;
if ( SpectatorID > = 0 & & ( ! m_apPlayers [ SpectatorID ] | | m_apPlayers [ SpectatorID ] - > GetTeam ( ) = = TEAM_SPECTATORS ) )
SendChatTarget ( ClientID , " Invalid spectator id used " ) ;
else
pPlayer - > m_SpectatorID = SpectatorID ;
}
2023-08-15 20:45:28 +00:00
void CGameContext : : OnChangeInfoNetMessage ( const CNetMsg_Cl_ChangeInfo * pMsg , int ClientID )
{
CPlayer * pPlayer = m_apPlayers [ ClientID ] ;
if ( g_Config . m_SvSpamprotection & & pPlayer - > m_LastChangeInfo & & pPlayer - > m_LastChangeInfo + Server ( ) - > TickSpeed ( ) * g_Config . m_SvInfoChangeDelay > Server ( ) - > Tick ( ) )
return ;
bool SixupNeedsUpdate = false ;
if ( ! str_utf8_check ( pMsg - > m_pName ) | | ! str_utf8_check ( pMsg - > m_pClan ) | | ! str_utf8_check ( pMsg - > m_pSkin ) )
{
return ;
}
pPlayer - > m_LastChangeInfo = Server ( ) - > Tick ( ) ;
pPlayer - > UpdatePlaytime ( ) ;
// set infos
if ( Server ( ) - > WouldClientNameChange ( ClientID , pMsg - > m_pName ) & & ! ProcessSpamProtection ( ClientID ) )
{
char aOldName [ MAX_NAME_LENGTH ] ;
str_copy ( aOldName , Server ( ) - > ClientName ( ClientID ) , sizeof ( aOldName ) ) ;
Server ( ) - > SetClientName ( ClientID , pMsg - > m_pName ) ;
char aChatText [ 256 ] ;
str_format ( aChatText , sizeof ( aChatText ) , " '%s' changed name to '%s' " , aOldName , Server ( ) - > ClientName ( ClientID ) ) ;
SendChat ( - 1 , CGameContext : : CHAT_ALL , aChatText ) ;
// reload scores
Score ( ) - > PlayerData ( ClientID ) - > Reset ( ) ;
m_apPlayers [ ClientID ] - > m_Score . reset ( ) ;
Score ( ) - > LoadPlayerData ( ClientID ) ;
SixupNeedsUpdate = true ;
LogEvent ( " Name change " , ClientID ) ;
}
2023-11-25 17:10:24 +00:00
if ( Server ( ) - > WouldClientClanChange ( ClientID , pMsg - > m_pClan ) )
{
2023-08-15 20:45:28 +00:00
SixupNeedsUpdate = true ;
2023-11-25 17:10:24 +00:00
Server ( ) - > SetClientClan ( ClientID , pMsg - > m_pClan ) ;
}
2023-08-15 20:45:28 +00:00
if ( Server ( ) - > ClientCountry ( ClientID ) ! = pMsg - > m_Country )
SixupNeedsUpdate = true ;
Server ( ) - > SetClientCountry ( ClientID , pMsg - > m_Country ) ;
str_copy ( pPlayer - > m_TeeInfos . m_aSkinName , pMsg - > m_pSkin , sizeof ( pPlayer - > m_TeeInfos . m_aSkinName ) ) ;
pPlayer - > m_TeeInfos . m_UseCustomColor = pMsg - > m_UseCustomColor ;
pPlayer - > m_TeeInfos . m_ColorBody = pMsg - > m_ColorBody ;
pPlayer - > m_TeeInfos . m_ColorFeet = pMsg - > m_ColorFeet ;
if ( ! Server ( ) - > IsSixup ( ClientID ) )
pPlayer - > m_TeeInfos . ToSixup ( ) ;
if ( SixupNeedsUpdate )
{
protocol7 : : CNetMsg_Sv_ClientDrop Drop ;
Drop . m_ClientID = ClientID ;
Drop . m_pReason = " " ;
Drop . m_Silent = true ;
protocol7 : : CNetMsg_Sv_ClientInfo Info ;
Info . m_ClientID = ClientID ;
Info . m_pName = Server ( ) - > ClientName ( ClientID ) ;
Info . m_Country = pMsg - > m_Country ;
Info . m_pClan = pMsg - > m_pClan ;
Info . m_Local = 0 ;
Info . m_Silent = true ;
Info . m_Team = pPlayer - > GetTeam ( ) ;
for ( int p = 0 ; p < 6 ; p + + )
{
Info . m_apSkinPartNames [ p ] = pPlayer - > m_TeeInfos . m_apSkinPartNames [ p ] ;
Info . m_aSkinPartColors [ p ] = pPlayer - > m_TeeInfos . m_aSkinPartColors [ p ] ;
Info . m_aUseCustomColors [ p ] = pPlayer - > m_TeeInfos . m_aUseCustomColors [ p ] ;
}
for ( int i = 0 ; i < Server ( ) - > MaxClients ( ) ; i + + )
{
if ( i ! = ClientID )
{
Server ( ) - > SendPackMsg ( & Drop , MSGFLAG_VITAL | MSGFLAG_NORECORD , i ) ;
Server ( ) - > SendPackMsg ( & Info , MSGFLAG_VITAL | MSGFLAG_NORECORD , i ) ;
}
}
}
else
{
protocol7 : : CNetMsg_Sv_SkinChange Msg ;
Msg . m_ClientID = ClientID ;
for ( int p = 0 ; p < 6 ; p + + )
{
Msg . m_apSkinPartNames [ p ] = pPlayer - > m_TeeInfos . m_apSkinPartNames [ p ] ;
Msg . m_aSkinPartColors [ p ] = pPlayer - > m_TeeInfos . m_aSkinPartColors [ p ] ;
Msg . m_aUseCustomColors [ p ] = pPlayer - > m_TeeInfos . m_aUseCustomColors [ p ] ;
}
Server ( ) - > SendPackMsg ( & Msg , MSGFLAG_VITAL | MSGFLAG_NORECORD , - 1 ) ;
}
Server ( ) - > ExpireServerInfo ( ) ;
}
2023-08-15 21:27:41 +00:00
void CGameContext : : OnEmoticonNetMessage ( const CNetMsg_Cl_Emoticon * pMsg , int ClientID )
{
2023-09-08 17:02:59 +00:00
if ( m_World . m_Paused )
return ;
2023-08-15 21:27:41 +00:00
CPlayer * pPlayer = m_apPlayers [ ClientID ] ;
auto & & CheckPreventEmote = [ & ] ( int64_t LastEmote , int64_t DelayInMs ) {
return ( LastEmote * ( int64_t ) 1000 ) + ( int64_t ) Server ( ) - > TickSpeed ( ) * DelayInMs > ( ( int64_t ) Server ( ) - > Tick ( ) * ( int64_t ) 1000 ) ;
} ;
if ( g_Config . m_SvSpamprotection & & CheckPreventEmote ( ( int64_t ) pPlayer - > m_LastEmote , ( int64_t ) g_Config . m_SvEmoticonMsDelay ) )
return ;
CCharacter * pChr = pPlayer - > GetCharacter ( ) ;
// player needs a character to send emotes
if ( ! pChr )
return ;
pPlayer - > m_LastEmote = Server ( ) - > Tick ( ) ;
pPlayer - > UpdatePlaytime ( ) ;
// check if the global emoticon is prevented and emotes are only send to nearby players
if ( g_Config . m_SvSpamprotection & & CheckPreventEmote ( ( int64_t ) pPlayer - > m_LastEmoteGlobal , ( int64_t ) g_Config . m_SvGlobalEmoticonMsDelay ) )
{
for ( int i = 0 ; i < MAX_CLIENTS ; + + i )
{
if ( m_apPlayers [ i ] & & pChr - > CanSnapCharacter ( i ) & & pChr - > IsSnappingCharacterInView ( i ) )
{
SendEmoticon ( ClientID , pMsg - > m_Emoticon , i ) ;
}
}
}
else
{
// else send emoticons to all players
pPlayer - > m_LastEmoteGlobal = Server ( ) - > Tick ( ) ;
SendEmoticon ( ClientID , pMsg - > m_Emoticon , - 1 ) ;
}
if ( g_Config . m_SvEmotionalTees & & pPlayer - > m_EyeEmoteEnabled )
{
int EmoteType = EMOTE_NORMAL ;
switch ( pMsg - > m_Emoticon )
{
case EMOTICON_EXCLAMATION :
case EMOTICON_GHOST :
case EMOTICON_QUESTION :
case EMOTICON_WTF :
EmoteType = EMOTE_SURPRISE ;
break ;
case EMOTICON_DOTDOT :
case EMOTICON_DROP :
case EMOTICON_ZZZ :
EmoteType = EMOTE_BLINK ;
break ;
case EMOTICON_EYES :
case EMOTICON_HEARTS :
case EMOTICON_MUSIC :
EmoteType = EMOTE_HAPPY ;
break ;
case EMOTICON_OOP :
case EMOTICON_SORRY :
case EMOTICON_SUSHI :
EmoteType = EMOTE_PAIN ;
break ;
case EMOTICON_DEVILTEE :
case EMOTICON_SPLATTEE :
case EMOTICON_ZOMG :
EmoteType = EMOTE_ANGRY ;
break ;
default :
break ;
}
pChr - > SetEmote ( EmoteType , Server ( ) - > Tick ( ) + 2 * Server ( ) - > TickSpeed ( ) ) ;
}
}
2023-09-08 17:02:59 +00:00
void CGameContext : : OnKillNetMessage ( const CNetMsg_Cl_Kill * pMsg , int ClientID )
{
if ( m_World . m_Paused )
return ;
if ( m_VoteCloseTime & & m_VoteCreator = = ClientID & & GetDDRaceTeam ( ClientID ) & & ( IsKickVote ( ) | | IsSpecVote ( ) ) )
{
SendChatTarget ( ClientID , " You are running a vote please try again after the vote is done! " ) ;
return ;
}
CPlayer * pPlayer = m_apPlayers [ ClientID ] ;
if ( pPlayer - > m_LastKill & & pPlayer - > m_LastKill + Server ( ) - > TickSpeed ( ) * g_Config . m_SvKillDelay > Server ( ) - > Tick ( ) )
return ;
if ( pPlayer - > IsPaused ( ) )
return ;
CCharacter * pChr = pPlayer - > GetCharacter ( ) ;
if ( ! pChr )
return ;
// Kill Protection
int CurrTime = ( Server ( ) - > Tick ( ) - pChr - > m_StartTime ) / Server ( ) - > TickSpeed ( ) ;
if ( g_Config . m_SvKillProtection ! = 0 & & CurrTime > = ( 60 * g_Config . m_SvKillProtection ) & & pChr - > m_DDRaceState = = DDRACE_STARTED )
{
SendChatTarget ( ClientID , " Kill Protection enabled. If you really want to kill, type /kill " ) ;
return ;
}
pPlayer - > m_LastKill = Server ( ) - > Tick ( ) ;
pPlayer - > KillCharacter ( WEAPON_SELF ) ;
pPlayer - > Respawn ( ) ;
}
2023-08-15 21:50:41 +00:00
void CGameContext : : OnStartInfoNetMessage ( const CNetMsg_Cl_StartInfo * pMsg , int ClientID )
{
CPlayer * pPlayer = m_apPlayers [ ClientID ] ;
if ( pPlayer - > m_IsReady )
return ;
if ( ! str_utf8_check ( pMsg - > m_pName ) )
{
Server ( ) - > Kick ( ClientID , " name is not valid utf8 " ) ;
return ;
}
if ( ! str_utf8_check ( pMsg - > m_pClan ) )
{
Server ( ) - > Kick ( ClientID , " clan is not valid utf8 " ) ;
return ;
}
if ( ! str_utf8_check ( pMsg - > m_pSkin ) )
{
Server ( ) - > Kick ( ClientID , " skin is not valid utf8 " ) ;
return ;
}
pPlayer - > m_LastChangeInfo = Server ( ) - > Tick ( ) ;
// set start infos
Server ( ) - > SetClientName ( ClientID , pMsg - > m_pName ) ;
// trying to set client name can delete the player object, check if it still exists
if ( ! m_apPlayers [ ClientID ] )
{
return ;
}
Server ( ) - > SetClientClan ( ClientID , pMsg - > m_pClan ) ;
2023-11-25 17:10:24 +00:00
// trying to set client clan can delete the player object, check if it still exists
if ( ! m_apPlayers [ ClientID ] )
{
return ;
}
2023-08-15 21:50:41 +00:00
Server ( ) - > SetClientCountry ( ClientID , pMsg - > m_Country ) ;
str_copy ( pPlayer - > m_TeeInfos . m_aSkinName , pMsg - > m_pSkin , sizeof ( pPlayer - > m_TeeInfos . m_aSkinName ) ) ;
pPlayer - > m_TeeInfos . m_UseCustomColor = pMsg - > m_UseCustomColor ;
pPlayer - > m_TeeInfos . m_ColorBody = pMsg - > m_ColorBody ;
pPlayer - > m_TeeInfos . m_ColorFeet = pMsg - > m_ColorFeet ;
if ( ! Server ( ) - > IsSixup ( ClientID ) )
pPlayer - > m_TeeInfos . ToSixup ( ) ;
// send clear vote options
CNetMsg_Sv_VoteClearOptions ClearMsg ;
Server ( ) - > SendPackMsg ( & ClearMsg , MSGFLAG_VITAL , ClientID ) ;
// begin sending vote options
pPlayer - > m_SendVoteIndex = 0 ;
// send tuning parameters to client
SendTuningParams ( ClientID , pPlayer - > m_TuneZone ) ;
// client is ready to enter
pPlayer - > m_IsReady = true ;
CNetMsg_Sv_ReadyToEnter m ;
Server ( ) - > SendPackMsg ( & m , MSGFLAG_VITAL | MSGFLAG_FLUSH , ClientID ) ;
Server ( ) - > ExpireServerInfo ( ) ;
}
2011-08-13 00:11:06 +00:00
void CGameContext : : ConTuneParam ( IConsole : : IResult * pResult , void * pUserData )
2010-05-29 07:25:38 +00:00
{
CGameContext * pSelf = ( CGameContext * ) pUserData ;
const char * pParamName = pResult - > GetString ( 0 ) ;
2022-08-09 14:43:20 +00:00
char aBuf [ 256 ] ;
2022-08-09 14:52:20 +00:00
if ( pResult - > NumArguments ( ) = = 2 )
2010-05-29 07:25:38 +00:00
{
2022-08-09 14:52:20 +00:00
float NewValue = pResult - > GetFloat ( 1 ) ;
if ( pSelf - > Tuning ( ) - > Set ( pParamName , NewValue ) & & pSelf - > Tuning ( ) - > Get ( pParamName , & NewValue ) )
{
str_format ( aBuf , sizeof ( aBuf ) , " %s changed to %.2f " , pParamName , NewValue ) ;
pSelf - > SendTuningParams ( - 1 ) ;
}
else
{
str_format ( aBuf , sizeof ( aBuf ) , " No such tuning parameter: %s " , pParamName ) ;
}
2010-05-29 07:25:38 +00:00
}
else
2022-08-09 14:43:20 +00:00
{
2022-08-09 14:52:20 +00:00
float Value ;
if ( pSelf - > Tuning ( ) - > Get ( pParamName , & Value ) )
{
str_format ( aBuf , sizeof ( aBuf ) , " %s %.2f " , pParamName , Value ) ;
}
else
{
str_format ( aBuf , sizeof ( aBuf ) , " No such tuning parameter: %s " , pParamName ) ;
}
2022-08-09 14:43:20 +00:00
}
2022-08-09 14:52:20 +00:00
pSelf - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " tuning " , aBuf ) ;
2010-05-29 07:25:38 +00:00
}
2018-12-20 08:18:22 +00:00
void CGameContext : : ConToggleTuneParam ( IConsole : : IResult * pResult , void * pUserData )
{
CGameContext * pSelf = ( CGameContext * ) pUserData ;
const char * pParamName = pResult - > GetString ( 0 ) ;
float OldValue ;
2022-08-09 14:43:20 +00:00
char aBuf [ 256 ] ;
2018-12-20 08:18:22 +00:00
if ( ! pSelf - > Tuning ( ) - > Get ( pParamName , & OldValue ) )
{
2022-08-09 14:43:20 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " No such tuning parameter: %s " , pParamName ) ;
pSelf - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " tuning " , aBuf ) ;
2018-12-20 08:18:22 +00:00
return ;
}
2023-02-28 20:31:40 +00:00
float NewValue = absolute ( OldValue - pResult - > GetFloat ( 1 ) ) < 0.0001f ? pResult - > GetFloat ( 2 ) : pResult - > GetFloat ( 1 ) ;
2018-12-20 08:18:22 +00:00
pSelf - > Tuning ( ) - > Set ( pParamName , NewValue ) ;
2022-08-09 14:49:05 +00:00
pSelf - > Tuning ( ) - > Get ( pParamName , & NewValue ) ;
2018-12-20 08:18:22 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " %s changed to %.2f " , pParamName , NewValue ) ;
pSelf - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " tuning " , aBuf ) ;
pSelf - > SendTuningParams ( - 1 ) ;
}
2011-08-13 00:11:06 +00:00
void CGameContext : : ConTuneReset ( IConsole : : IResult * pResult , void * pUserData )
2010-05-29 07:25:38 +00:00
{
CGameContext * pSelf = ( CGameContext * ) pUserData ;
2022-08-09 14:47:04 +00:00
if ( pResult - > NumArguments ( ) )
{
const char * pParamName = pResult - > GetString ( 0 ) ;
float DefaultValue = 0.0f ;
char aBuf [ 256 ] ;
CTuningParams TuningParams ;
2022-08-09 14:49:05 +00:00
if ( TuningParams . Get ( pParamName , & DefaultValue ) & & pSelf - > Tuning ( ) - > Set ( pParamName , DefaultValue ) & & pSelf - > Tuning ( ) - > Get ( pParamName , & DefaultValue ) )
2022-08-09 14:47:04 +00:00
{
str_format ( aBuf , sizeof ( aBuf ) , " %s reset to %.2f " , pParamName , DefaultValue ) ;
pSelf - > SendTuningParams ( - 1 ) ;
}
else
{
str_format ( aBuf , sizeof ( aBuf ) , " No such tuning parameter: %s " , pParamName ) ;
}
pSelf - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " tuning " , aBuf ) ;
}
else
{
pSelf - > ResetTuning ( ) ;
pSelf - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " tuning " , " Tuning reset " ) ;
}
2010-05-29 07:25:38 +00:00
}
2022-08-09 14:34:07 +00:00
void CGameContext : : ConTunes ( IConsole : : IResult * pResult , void * pUserData )
2010-05-29 07:25:38 +00:00
{
CGameContext * pSelf = ( CGameContext * ) pUserData ;
2010-08-17 22:06:00 +00:00
char aBuf [ 256 ] ;
2023-10-06 10:26:33 +00:00
for ( int i = 0 ; i < CTuningParams : : Num ( ) ; i + + )
2010-05-29 07:25:38 +00:00
{
2022-08-09 14:34:52 +00:00
float Value ;
pSelf - > Tuning ( ) - > Get ( i , & Value ) ;
2022-08-09 15:05:28 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " %s %.2f " , CTuningParams : : Name ( i ) , Value ) ;
2011-08-13 00:11:06 +00:00
pSelf - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " tuning " , aBuf ) ;
2010-05-29 07:25:38 +00:00
}
}
2014-03-12 23:31:50 +00:00
void CGameContext : : ConTuneZone ( IConsole : : IResult * pResult , void * pUserData )
{
CGameContext * pSelf = ( CGameContext * ) pUserData ;
int List = pResult - > GetInteger ( 0 ) ;
const char * pParamName = pResult - > GetString ( 1 ) ;
float NewValue = pResult - > GetFloat ( 2 ) ;
2015-07-09 00:08:14 +00:00
2020-09-26 19:41:58 +00:00
if ( List > = 0 & & List < NUM_TUNEZONES )
2014-03-12 23:31:50 +00:00
{
2022-08-09 14:43:20 +00:00
char aBuf [ 256 ] ;
2022-08-09 14:49:05 +00:00
if ( pSelf - > TuningList ( ) [ List ] . Set ( pParamName , NewValue ) & & pSelf - > TuningList ( ) [ List ] . Get ( pParamName , & NewValue ) )
2014-03-12 23:31:50 +00:00
{
str_format ( aBuf , sizeof ( aBuf ) , " %s in zone %d changed to %.2f " , pParamName , List , NewValue ) ;
2014-03-29 13:54:43 +00:00
pSelf - > SendTuningParams ( - 1 , List ) ;
2014-03-12 23:31:50 +00:00
}
else
2022-08-09 14:43:20 +00:00
{
str_format ( aBuf , sizeof ( aBuf ) , " No such tuning parameter: %s " , pParamName ) ;
}
pSelf - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " tuning " , aBuf ) ;
2014-03-12 23:31:50 +00:00
}
}
void CGameContext : : ConTuneDumpZone ( IConsole : : IResult * pResult , void * pUserData )
{
CGameContext * pSelf = ( CGameContext * ) pUserData ;
int List = pResult - > GetInteger ( 0 ) ;
char aBuf [ 256 ] ;
2020-09-26 19:41:58 +00:00
if ( List > = 0 & & List < NUM_TUNEZONES )
2014-03-12 23:31:50 +00:00
{
2023-10-06 10:26:33 +00:00
for ( int i = 0 ; i < CTuningParams : : Num ( ) ; i + + )
2014-03-23 17:56:07 +00:00
{
2022-08-09 14:34:52 +00:00
float Value ;
pSelf - > TuningList ( ) [ List ] . Get ( i , & Value ) ;
2022-08-09 15:05:28 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " zone %d: %s %.2f " , List , CTuningParams : : Name ( i ) , Value ) ;
2014-03-23 17:56:07 +00:00
pSelf - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " tuning " , aBuf ) ;
}
2014-03-12 23:31:50 +00:00
}
}
void CGameContext : : ConTuneResetZone ( IConsole : : IResult * pResult , void * pUserData )
{
CGameContext * pSelf = ( CGameContext * ) pUserData ;
CTuningParams TuningParams ;
2020-09-26 19:41:58 +00:00
if ( pResult - > NumArguments ( ) )
2014-03-12 23:31:50 +00:00
{
int List = pResult - > GetInteger ( 0 ) ;
2020-09-26 19:41:58 +00:00
if ( List > = 0 & & List < NUM_TUNEZONES )
2014-03-12 23:31:50 +00:00
{
2014-03-23 17:56:07 +00:00
pSelf - > TuningList ( ) [ List ] = TuningParams ;
2014-03-12 23:31:50 +00:00
char aBuf [ 256 ] ;
2018-07-10 09:29:02 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " Tunezone %d reset " , List ) ;
2014-03-12 23:31:50 +00:00
pSelf - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " tuning " , aBuf ) ;
2014-03-29 13:54:43 +00:00
pSelf - > SendTuningParams ( - 1 , List ) ;
2014-03-12 23:31:50 +00:00
}
}
else
{
2020-09-26 19:41:58 +00:00
for ( int i = 0 ; i < NUM_TUNEZONES ; i + + )
2014-03-29 13:54:43 +00:00
{
2020-09-26 19:41:58 +00:00
* ( pSelf - > TuningList ( ) + i ) = TuningParams ;
2014-03-29 13:54:43 +00:00
pSelf - > SendTuningParams ( - 1 , i ) ;
}
2018-07-10 09:29:02 +00:00
pSelf - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " tuning " , " All Tunezones reset " ) ;
2014-03-12 23:31:50 +00:00
}
}
void CGameContext : : ConTuneSetZoneMsgEnter ( IConsole : : IResult * pResult , void * pUserData )
{
CGameContext * pSelf = ( CGameContext * ) pUserData ;
2020-09-26 19:41:58 +00:00
if ( pResult - > NumArguments ( ) )
2014-03-12 23:31:50 +00:00
{
int List = pResult - > GetInteger ( 0 ) ;
2020-09-26 19:41:58 +00:00
if ( List > = 0 & & List < NUM_TUNEZONES )
2014-03-12 23:31:50 +00:00
{
2017-07-26 01:58:00 +00:00
str_copy ( pSelf - > m_aaZoneEnterMsg [ List ] , pResult - > GetString ( 1 ) , sizeof ( pSelf - > m_aaZoneEnterMsg [ List ] ) ) ;
2014-03-12 23:31:50 +00:00
}
}
}
void CGameContext : : ConTuneSetZoneMsgLeave ( IConsole : : IResult * pResult , void * pUserData )
{
CGameContext * pSelf = ( CGameContext * ) pUserData ;
2020-09-26 19:41:58 +00:00
if ( pResult - > NumArguments ( ) )
2014-03-12 23:31:50 +00:00
{
int List = pResult - > GetInteger ( 0 ) ;
2020-09-26 19:41:58 +00:00
if ( List > = 0 & & List < NUM_TUNEZONES )
2014-03-12 23:31:50 +00:00
{
2017-07-26 01:58:00 +00:00
str_copy ( pSelf - > m_aaZoneLeaveMsg [ List ] , pResult - > GetString ( 1 ) , sizeof ( pSelf - > m_aaZoneLeaveMsg [ List ] ) ) ;
2014-03-12 23:31:50 +00:00
}
}
}
2018-05-01 10:38:33 +00:00
void CGameContext : : ConMapbug ( IConsole : : IResult * pResult , void * pUserData )
{
CGameContext * pSelf = ( CGameContext * ) pUserData ;
const char * pMapBugName = pResult - > GetString ( 0 ) ;
if ( pSelf - > m_pController )
{
pSelf - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " mapbugs " , " can't add map bugs after the game started " ) ;
return ;
}
switch ( pSelf - > m_MapBugs . Update ( pMapBugName ) )
{
case MAPBUGUPDATE_OK :
break ;
case MAPBUGUPDATE_OVERRIDDEN :
pSelf - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " mapbugs " , " map-internal setting overridden by database " ) ;
break ;
case MAPBUGUPDATE_NOTFOUND :
2020-09-26 19:41:58 +00:00
{
char aBuf [ 64 ] ;
str_format ( aBuf , sizeof ( aBuf ) , " unknown map bug '%s', ignoring " , pMapBugName ) ;
pSelf - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " mapbugs " , aBuf ) ;
}
break ;
2018-05-01 10:38:33 +00:00
default :
dbg_assert ( 0 , " unreachable " ) ;
}
}
2015-07-22 21:31:50 +00:00
void CGameContext : : ConSwitchOpen ( IConsole : : IResult * pResult , void * pUserData )
{
CGameContext * pSelf = ( CGameContext * ) pUserData ;
int Switch = pResult - > GetInteger ( 0 ) ;
2022-06-02 18:52:11 +00:00
if ( in_range ( Switch , ( int ) pSelf - > Switchers ( ) . size ( ) - 1 ) )
2015-07-22 21:31:50 +00:00
{
2022-02-13 19:57:27 +00:00
pSelf - > Switchers ( ) [ Switch ] . m_Initial = false ;
2015-07-22 21:31:50 +00:00
char aBuf [ 256 ] ;
str_format ( aBuf , sizeof ( aBuf ) , " switch %d opened by default " , Switch ) ;
pSelf - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " server " , aBuf ) ;
}
}
2012-01-09 23:49:31 +00:00
void CGameContext : : ConPause ( IConsole : : IResult * pResult , void * pUserData )
{
CGameContext * pSelf = ( CGameContext * ) pUserData ;
pSelf - > m_World . m_Paused ^ = 1 ;
}
2011-08-13 00:11:06 +00:00
void CGameContext : : ConChangeMap ( IConsole : : IResult * pResult , void * pUserData )
2010-05-29 07:25:38 +00:00
{
CGameContext * pSelf = ( CGameContext * ) pUserData ;
2010-11-17 11:50:01 +00:00
pSelf - > m_pController - > ChangeMap ( pResult - > NumArguments ( ) ? pResult - > GetString ( 0 ) : " " ) ;
2010-05-29 07:25:38 +00:00
}
2013-12-06 23:15:56 +00:00
void CGameContext : : ConRandomMap ( IConsole : : IResult * pResult , void * pUserData )
{
CGameContext * pSelf = ( CGameContext * ) pUserData ;
2014-10-10 22:41:56 +00:00
2019-08-27 16:33:37 +00:00
int Stars = pResult - > NumArguments ( ) ? pResult - > GetInteger ( 0 ) : - 1 ;
2013-12-06 23:15:56 +00:00
2020-05-26 21:22:16 +00:00
pSelf - > m_pScore - > RandomMap ( pSelf - > m_VoteCreator , Stars ) ;
2013-12-06 23:15:56 +00:00
}
2014-06-20 20:40:23 +00:00
void CGameContext : : ConRandomUnfinishedMap ( IConsole : : IResult * pResult , void * pUserData )
{
CGameContext * pSelf = ( CGameContext * ) pUserData ;
2014-10-10 22:41:56 +00:00
2019-08-27 16:33:37 +00:00
int Stars = pResult - > NumArguments ( ) ? pResult - > GetInteger ( 0 ) : - 1 ;
2014-10-10 22:41:56 +00:00
2020-05-28 13:29:14 +00:00
pSelf - > m_pScore - > RandomUnfinishedMap ( pSelf - > m_VoteCreator , Stars ) ;
2014-06-20 20:40:23 +00:00
}
2011-08-13 00:11:06 +00:00
void CGameContext : : ConRestart ( IConsole : : IResult * pResult , void * pUserData )
2010-05-29 07:25:38 +00:00
{
CGameContext * pSelf = ( CGameContext * ) pUserData ;
if ( pResult - > NumArguments ( ) )
pSelf - > m_pController - > DoWarmup ( pResult - > GetInteger ( 0 ) ) ;
else
pSelf - > m_pController - > StartRound ( ) ;
}
2011-08-13 00:11:06 +00:00
void CGameContext : : ConBroadcast ( IConsole : : IResult * pResult , void * pUserData )
2010-05-29 07:25:38 +00:00
{
CGameContext * pSelf = ( CGameContext * ) pUserData ;
2014-04-18 22:40:21 +00:00
char aBuf [ 1024 ] ;
str_copy ( aBuf , pResult - > GetString ( 0 ) , sizeof ( aBuf ) ) ;
int i , j ;
for ( i = 0 , j = 0 ; aBuf [ i ] ; i + + , j + + )
{
2020-09-26 19:41:58 +00:00
if ( aBuf [ i ] = = ' \\ ' & & aBuf [ i + 1 ] = = ' n ' )
2014-04-18 22:40:21 +00:00
{
aBuf [ j ] = ' \n ' ;
i + + ;
}
2020-09-26 19:41:58 +00:00
else if ( i ! = j )
2014-04-18 22:40:21 +00:00
{
aBuf [ j ] = aBuf [ i ] ;
}
}
aBuf [ j ] = ' \0 ' ;
pSelf - > SendBroadcast ( aBuf , - 1 ) ;
2010-05-29 07:25:38 +00:00
}
2011-08-13 00:11:06 +00:00
void CGameContext : : ConSay ( IConsole : : IResult * pResult , void * pUserData )
2010-05-29 07:25:38 +00:00
{
CGameContext * pSelf = ( CGameContext * ) pUserData ;
pSelf - > SendChat ( - 1 , CGameContext : : CHAT_ALL , pResult - > GetString ( 0 ) ) ;
}
2011-08-13 00:11:06 +00:00
void CGameContext : : ConSetTeam ( IConsole : : IResult * pResult , void * pUserData )
2010-05-29 07:25:38 +00:00
{
CGameContext * pSelf = ( CGameContext * ) pUserData ;
2020-09-26 19:41:58 +00:00
int ClientID = clamp ( pResult - > GetInteger ( 0 ) , 0 , ( int ) MAX_CLIENTS - 1 ) ;
2010-05-29 07:25:38 +00:00
int Team = clamp ( pResult - > GetInteger ( 1 ) , - 1 , 1 ) ;
2020-09-26 19:41:58 +00:00
int Delay = pResult - > NumArguments ( ) > 2 ? pResult - > GetInteger ( 2 ) : 0 ;
2011-12-30 21:47:26 +00:00
if ( ! pSelf - > m_apPlayers [ ClientID ] )
return ;
2011-04-13 18:37:12 +00:00
2010-08-17 22:06:00 +00:00
char aBuf [ 256 ] ;
2011-02-12 10:40:36 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " moved client %d to team %d " , ClientID , Team ) ;
2010-08-17 22:06:00 +00:00
pSelf - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " server " , aBuf ) ;
2010-11-21 22:25:30 +00:00
2018-07-09 22:08:57 +00:00
pSelf - > m_apPlayers [ ClientID ] - > Pause ( CPlayer : : PAUSE_NONE , false ) ; // reset /spec and /pause to allow rejoin
2020-09-26 19:41:58 +00:00
pSelf - > m_apPlayers [ ClientID ] - > m_TeamChangeTick = pSelf - > Server ( ) - > Tick ( ) + pSelf - > Server ( ) - > TickSpeed ( ) * Delay * 60 ;
2021-01-12 20:01:00 +00:00
pSelf - > m_pController - > DoTeamChange ( pSelf - > m_apPlayers [ ClientID ] , Team ) ;
2013-07-28 21:43:27 +00:00
if ( Team = = TEAM_SPECTATORS )
2017-04-08 23:16:48 +00:00
pSelf - > m_apPlayers [ ClientID ] - > Pause ( CPlayer : : PAUSE_NONE , true ) ;
2010-05-29 07:25:38 +00:00
}
2011-08-13 00:11:06 +00:00
void CGameContext : : ConSetTeamAll ( IConsole : : IResult * pResult , void * pUserData )
2011-01-06 12:37:28 +00:00
{
CGameContext * pSelf = ( CGameContext * ) pUserData ;
int Team = clamp ( pResult - > GetInteger ( 0 ) , - 1 , 1 ) ;
2011-04-13 18:37:12 +00:00
2011-01-06 12:37:28 +00:00
char aBuf [ 256 ] ;
2011-12-30 21:30:28 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " All players were moved to the %s " , pSelf - > m_pController - > GetTeamName ( Team ) ) ;
pSelf - > SendChat ( - 1 , CGameContext : : CHAT_ALL , aBuf ) ;
2011-04-13 18:37:12 +00:00
2020-10-26 14:14:07 +00:00
for ( auto & pPlayer : pSelf - > m_apPlayers )
if ( pPlayer )
2021-01-12 20:01:00 +00:00
pSelf - > m_pController - > DoTeamChange ( pPlayer , Team , false ) ;
2011-09-04 09:13:30 +00:00
}
2011-08-13 00:11:06 +00:00
void CGameContext : : ConAddVote ( IConsole : : IResult * pResult , void * pUserData )
2010-05-29 07:25:38 +00:00
{
CGameContext * pSelf = ( CGameContext * ) pUserData ;
2011-03-25 08:49:21 +00:00
const char * pDescription = pResult - > GetString ( 0 ) ;
const char * pCommand = pResult - > GetString ( 1 ) ;
2011-03-26 21:06:29 +00:00
2020-10-17 22:05:59 +00:00
pSelf - > AddVote ( pDescription , pCommand ) ;
}
void CGameContext : : AddVote ( const char * pDescription , const char * pCommand )
{
if ( m_NumVoteOptions = = MAX_VOTE_OPTIONS )
2011-03-26 21:06:29 +00:00
{
2020-10-17 22:05:59 +00:00
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " server " , " maximum number of vote options reached " ) ;
2011-03-26 21:06:29 +00:00
return ;
}
2011-04-13 18:37:12 +00:00
2010-10-25 16:30:35 +00:00
// check for valid option
2020-10-17 22:05:59 +00:00
if ( ! Console ( ) - > LineIsValid ( pCommand ) | | str_length ( pCommand ) > = VOTE_CMD_LENGTH )
2010-10-25 16:30:35 +00:00
{
char aBuf [ 256 ] ;
2011-03-26 16:44:34 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " skipped invalid command '%s' " , pCommand ) ;
2020-10-17 22:05:59 +00:00
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " server " , aBuf ) ;
2011-03-26 16:44:34 +00:00
return ;
}
2020-11-05 10:47:07 +00:00
while ( * pDescription = = ' ' )
2011-04-05 18:06:41 +00:00
pDescription + + ;
if ( str_length ( pDescription ) > = VOTE_DESC_LENGTH | | * pDescription = = 0 )
2011-03-26 16:44:34 +00:00
{
char aBuf [ 256 ] ;
str_format ( aBuf , sizeof ( aBuf ) , " skipped invalid option '%s' " , pDescription ) ;
2020-10-17 22:05:59 +00:00
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " server " , aBuf ) ;
2010-10-25 16:30:35 +00:00
return ;
}
2011-04-13 18:37:12 +00:00
2011-03-25 08:49:21 +00:00
// check for duplicate entry
2020-10-17 22:05:59 +00:00
CVoteOptionServer * pOption = m_pVoteOptionFirst ;
2010-11-20 18:30:52 +00:00
while ( pOption )
{
2011-03-25 10:49:35 +00:00
if ( str_comp_nocase ( pDescription , pOption - > m_aDescription ) = = 0 )
2010-11-20 18:30:52 +00:00
{
char aBuf [ 256 ] ;
2011-03-25 08:49:21 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " option '%s' already exists " , pDescription ) ;
2020-10-17 22:05:59 +00:00
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " server " , aBuf ) ;
2010-11-20 18:30:52 +00:00
return ;
}
pOption = pOption - > m_pNext ;
}
2011-04-13 18:37:12 +00:00
2011-03-25 08:49:21 +00:00
// add the option
2020-10-17 22:05:59 +00:00
+ + m_NumVoteOptions ;
2011-03-25 08:49:21 +00:00
int Len = str_length ( pCommand ) ;
2011-04-13 18:37:12 +00:00
2021-05-27 17:35:20 +00:00
pOption = ( CVoteOptionServer * ) m_pVoteOptionHeap - > Allocate ( sizeof ( CVoteOptionServer ) + Len , alignof ( CVoteOptionServer ) ) ;
2010-05-29 07:25:38 +00:00
pOption - > m_pNext = 0 ;
2020-10-17 22:05:59 +00:00
pOption - > m_pPrev = m_pVoteOptionLast ;
2010-05-29 07:25:38 +00:00
if ( pOption - > m_pPrev )
pOption - > m_pPrev - > m_pNext = pOption ;
2020-10-17 22:05:59 +00:00
m_pVoteOptionLast = pOption ;
if ( ! m_pVoteOptionFirst )
m_pVoteOptionFirst = pOption ;
2011-04-13 18:37:12 +00:00
2011-03-25 08:49:21 +00:00
str_copy ( pOption - > m_aDescription , pDescription , sizeof ( pOption - > m_aDescription ) ) ;
2020-09-26 19:41:58 +00:00
mem_copy ( pOption - > m_aCommand , pCommand , Len + 1 ) ;
2010-05-29 07:25:38 +00:00
}
2011-08-13 00:11:06 +00:00
void CGameContext : : ConRemoveVote ( IConsole : : IResult * pResult , void * pUserData )
2011-03-25 10:49:35 +00:00
{
CGameContext * pSelf = ( CGameContext * ) pUserData ;
const char * pDescription = pResult - > GetString ( 0 ) ;
2011-04-13 18:37:12 +00:00
2011-03-25 10:49:35 +00:00
// check for valid option
2011-03-26 16:44:34 +00:00
CVoteOptionServer * pOption = pSelf - > m_pVoteOptionFirst ;
2011-03-25 10:49:35 +00:00
while ( pOption )
{
if ( str_comp_nocase ( pDescription , pOption - > m_aDescription ) = = 0 )
break ;
pOption = pOption - > m_pNext ;
}
if ( ! pOption )
{
char aBuf [ 256 ] ;
str_format ( aBuf , sizeof ( aBuf ) , " option '%s' does not exist " , pDescription ) ;
2011-08-13 00:11:06 +00:00
pSelf - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " server " , aBuf ) ;
2011-03-25 10:49:35 +00:00
return ;
}
2011-04-04 14:58:53 +00:00
2014-10-27 12:34:29 +00:00
// start reloading vote option list
// clear vote options
CNetMsg_Sv_VoteClearOptions VoteClearOptionsMsg ;
pSelf - > Server ( ) - > SendPackMsg ( & VoteClearOptionsMsg , MSGFLAG_VITAL , - 1 ) ;
// reset sending of vote options
2020-10-26 14:14:07 +00:00
for ( auto & pPlayer : pSelf - > m_apPlayers )
2014-10-27 12:34:29 +00:00
{
2020-10-26 14:14:07 +00:00
if ( pPlayer )
pPlayer - > m_SendVoteIndex = 0 ;
2014-10-27 12:34:29 +00:00
}
2011-04-13 18:37:12 +00:00
2011-03-25 10:49:35 +00:00
// TODO: improve this
// remove the option
2011-03-26 21:06:29 +00:00
- - pSelf - > m_NumVoteOptions ;
2011-03-25 10:49:35 +00:00
2011-03-25 11:06:45 +00:00
CHeap * pVoteOptionHeap = new CHeap ( ) ;
2011-03-26 16:44:34 +00:00
CVoteOptionServer * pVoteOptionFirst = 0 ;
CVoteOptionServer * pVoteOptionLast = 0 ;
2011-03-26 21:06:29 +00:00
int NumVoteOptions = pSelf - > m_NumVoteOptions ;
2011-03-26 16:44:34 +00:00
for ( CVoteOptionServer * pSrc = pSelf - > m_pVoteOptionFirst ; pSrc ; pSrc = pSrc - > m_pNext )
2011-03-25 10:49:35 +00:00
{
if ( pSrc = = pOption )
continue ;
// copy option
int Len = str_length ( pSrc - > m_aCommand ) ;
2011-03-26 16:44:34 +00:00
CVoteOptionServer * pDst = ( CVoteOptionServer * ) pVoteOptionHeap - > Allocate ( sizeof ( CVoteOptionServer ) + Len ) ;
2011-03-25 10:49:35 +00:00
pDst - > m_pNext = 0 ;
pDst - > m_pPrev = pVoteOptionLast ;
if ( pDst - > m_pPrev )
pDst - > m_pPrev - > m_pNext = pDst ;
pVoteOptionLast = pDst ;
if ( ! pVoteOptionFirst )
pVoteOptionFirst = pDst ;
2011-04-13 18:37:12 +00:00
2011-03-25 10:49:35 +00:00
str_copy ( pDst - > m_aDescription , pSrc - > m_aDescription , sizeof ( pDst - > m_aDescription ) ) ;
2020-09-26 19:41:58 +00:00
mem_copy ( pDst - > m_aCommand , pSrc - > m_aCommand , Len + 1 ) ;
2011-03-25 11:06:45 +00:00
}
// clean up
delete pSelf - > m_pVoteOptionHeap ;
2011-03-25 10:49:35 +00:00
pSelf - > m_pVoteOptionHeap = pVoteOptionHeap ;
pSelf - > m_pVoteOptionFirst = pVoteOptionFirst ;
pSelf - > m_pVoteOptionLast = pVoteOptionLast ;
2011-03-26 21:06:29 +00:00
pSelf - > m_NumVoteOptions = NumVoteOptions ;
2010-05-29 07:25:38 +00:00
}
2011-08-13 00:11:06 +00:00
void CGameContext : : ConForceVote ( IConsole : : IResult * pResult , void * pUserData )
2011-03-25 11:06:45 +00:00
{
CGameContext * pSelf = ( CGameContext * ) pUserData ;
const char * pType = pResult - > GetString ( 0 ) ;
const char * pValue = pResult - > GetString ( 1 ) ;
2011-03-26 15:24:12 +00:00
const char * pReason = pResult - > NumArguments ( ) > 2 & & pResult - > GetString ( 2 ) [ 0 ] ? pResult - > GetString ( 2 ) : " No reason given " ;
2011-03-25 11:06:45 +00:00
char aBuf [ 128 ] = { 0 } ;
if ( str_comp_nocase ( pType , " option " ) = = 0 )
{
2011-03-26 16:44:34 +00:00
CVoteOptionServer * pOption = pSelf - > m_pVoteOptionFirst ;
2011-03-25 11:06:45 +00:00
while ( pOption )
{
if ( str_comp_nocase ( pValue , pOption - > m_aDescription ) = = 0 )
{
2020-11-25 01:50:10 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " authorized player forced server option '%s' (%s) " , pValue , pReason ) ;
2020-07-12 07:34:36 +00:00
pSelf - > SendChatTarget ( - 1 , aBuf , CHAT_SIX ) ;
2011-08-13 00:11:06 +00:00
pSelf - > Console ( ) - > ExecuteLine ( pOption - > m_aCommand ) ;
2011-03-25 11:06:45 +00:00
break ;
}
pOption = pOption - > m_pNext ;
}
2011-04-13 18:37:12 +00:00
2011-03-25 11:06:45 +00:00
if ( ! pOption )
{
str_format ( aBuf , sizeof ( aBuf ) , " '%s' isn't an option on this server " , pValue ) ;
2011-08-13 00:11:06 +00:00
pSelf - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " server " , aBuf ) ;
2011-03-25 11:06:45 +00:00
return ;
}
}
else if ( str_comp_nocase ( pType , " kick " ) = = 0 )
{
int KickID = str_toint ( pValue ) ;
if ( KickID < 0 | | KickID > = MAX_CLIENTS | | ! pSelf - > m_apPlayers [ KickID ] )
{
2011-08-13 00:11:06 +00:00
pSelf - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " server " , " Invalid client id to kick " ) ;
2011-03-25 11:06:45 +00:00
return ;
}
2020-09-26 19:41:58 +00:00
if ( ! g_Config . m_SvVoteKickBantime )
2011-03-25 11:06:45 +00:00
{
str_format ( aBuf , sizeof ( aBuf ) , " kick %d %s " , KickID , pReason ) ;
2011-08-13 00:11:06 +00:00
pSelf - > Console ( ) - > ExecuteLine ( aBuf ) ;
2011-03-25 11:06:45 +00:00
}
else
{
2011-03-28 18:11:28 +00:00
char aAddrStr [ NETADDR_MAXSTRSIZE ] = { 0 } ;
pSelf - > Server ( ) - > GetClientAddr ( KickID , aAddrStr , sizeof ( aAddrStr ) ) ;
str_format ( aBuf , sizeof ( aBuf ) , " ban %s %d %s " , aAddrStr , g_Config . m_SvVoteKickBantime , pReason ) ;
2011-08-13 00:11:06 +00:00
pSelf - > Console ( ) - > ExecuteLine ( aBuf ) ;
2011-03-25 11:06:45 +00:00
}
}
2011-03-26 15:56:59 +00:00
else if ( str_comp_nocase ( pType , " spectate " ) = = 0 )
{
int SpectateID = str_toint ( pValue ) ;
if ( SpectateID < 0 | | SpectateID > = MAX_CLIENTS | | ! pSelf - > m_apPlayers [ SpectateID ] | | pSelf - > m_apPlayers [ SpectateID ] - > GetTeam ( ) = = TEAM_SPECTATORS )
{
2011-08-13 00:11:06 +00:00
pSelf - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " server " , " Invalid client id to move " ) ;
2011-03-26 15:56:59 +00:00
return ;
}
2011-04-13 18:37:12 +00:00
2019-02-27 18:46:01 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " '%s' was moved to spectator (%s) " , pSelf - > Server ( ) - > ClientName ( SpectateID ) , pReason ) ;
2011-07-10 11:02:13 +00:00
pSelf - > SendChatTarget ( - 1 , aBuf ) ;
2011-05-25 10:05:32 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " set_team %d -1 %d " , SpectateID , g_Config . m_SvVoteSpectateRejoindelay ) ;
2011-03-26 15:56:59 +00:00
pSelf - > Console ( ) - > ExecuteLine ( aBuf ) ;
}
2011-03-25 11:06:45 +00:00
}
2011-08-13 00:11:06 +00:00
void CGameContext : : ConClearVotes ( IConsole : : IResult * pResult , void * pUserData )
2011-01-21 19:46:00 +00:00
{
CGameContext * pSelf = ( CGameContext * ) pUserData ;
CNetMsg_Sv_VoteClearOptions VoteClearOptionsMsg ;
pSelf - > Server ( ) - > SendPackMsg ( & VoteClearOptionsMsg , MSGFLAG_VITAL , - 1 ) ;
pSelf - > m_pVoteOptionHeap - > Reset ( ) ;
pSelf - > m_pVoteOptionFirst = 0 ;
pSelf - > m_pVoteOptionLast = 0 ;
2011-03-26 21:06:29 +00:00
pSelf - > m_NumVoteOptions = 0 ;
2014-10-26 18:39:42 +00:00
// reset sending of vote options
2020-10-26 14:14:07 +00:00
for ( auto & pPlayer : pSelf - > m_apPlayers )
2014-10-26 18:39:42 +00:00
{
2020-10-26 14:14:07 +00:00
if ( pPlayer )
pPlayer - > m_SendVoteIndex = 0 ;
2014-10-26 18:39:42 +00:00
}
2011-01-21 19:46:00 +00:00
}
2020-10-17 22:05:59 +00:00
struct CMapNameItem
{
2021-09-13 08:06:34 +00:00
char m_aName [ IO_MAX_PATH_LENGTH - 4 ] ;
2020-10-17 22:05:59 +00:00
bool operator < ( const CMapNameItem & Other ) const { return str_comp_nocase ( m_aName , Other . m_aName ) < 0 ; }
} ;
void CGameContext : : ConAddMapVotes ( IConsole : : IResult * pResult , void * pUserData )
{
CGameContext * pSelf = ( CGameContext * ) pUserData ;
2022-06-15 17:34:41 +00:00
std : : vector < CMapNameItem > vMapList ;
pSelf - > Storage ( ) - > ListDirectory ( IStorage : : TYPE_ALL , " maps " , MapScan , & vMapList ) ;
std : : sort ( vMapList . begin ( ) , vMapList . end ( ) ) ;
2020-10-17 22:05:59 +00:00
2022-06-15 17:34:41 +00:00
for ( auto & Item : vMapList )
2020-10-17 22:05:59 +00:00
{
char aDescription [ 64 ] ;
2022-05-23 15:47:48 +00:00
str_format ( aDescription , sizeof ( aDescription ) , " Map: %s " , Item . m_aName ) ;
2020-10-17 22:05:59 +00:00
2021-09-13 08:06:34 +00:00
char aCommand [ IO_MAX_PATH_LENGTH * 2 + 10 ] ;
char aMapEscaped [ IO_MAX_PATH_LENGTH * 2 ] ;
2020-10-26 10:28:04 +00:00
char * pDst = aMapEscaped ;
2022-05-23 15:47:48 +00:00
str_escape ( & pDst , Item . m_aName , aMapEscaped + sizeof ( aMapEscaped ) ) ;
2020-10-26 10:28:04 +00:00
str_format ( aCommand , sizeof ( aCommand ) , " change_map \" %s \" " , aMapEscaped ) ;
2020-10-17 22:05:59 +00:00
pSelf - > AddVote ( aDescription , aCommand ) ;
}
pSelf - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " server " , " added maps to votes " ) ;
}
int CGameContext : : MapScan ( const char * pName , int IsDir , int DirType , void * pUserData )
{
if ( IsDir | | ! str_endswith ( pName , " .map " ) )
return 0 ;
CMapNameItem Item ;
2022-05-23 15:47:48 +00:00
str_truncate ( Item . m_aName , sizeof ( Item . m_aName ) , pName , str_length ( pName ) - str_length ( " .map " ) ) ;
static_cast < std : : vector < CMapNameItem > * > ( pUserData ) - > push_back ( Item ) ;
2020-10-17 22:05:59 +00:00
return 0 ;
}
2011-08-13 00:11:06 +00:00
void CGameContext : : ConVote ( IConsole : : IResult * pResult , void * pUserData )
2010-05-29 07:25:38 +00:00
{
CGameContext * pSelf = ( CGameContext * ) pUserData ;
2012-01-26 21:17:26 +00:00
2010-05-29 07:25:38 +00:00
if ( str_comp_nocase ( pResult - > GetString ( 0 ) , " yes " ) = = 0 )
2018-01-18 15:17:23 +00:00
pSelf - > ForceVote ( pResult - > m_ClientID , true ) ;
2010-05-29 07:25:38 +00:00
else if ( str_comp_nocase ( pResult - > GetString ( 0 ) , " no " ) = = 0 )
2018-01-18 15:17:23 +00:00
pSelf - > ForceVote ( pResult - > m_ClientID , false ) ;
2010-05-29 07:25:38 +00:00
}
2023-09-26 00:24:00 +00:00
void CGameContext : : ConVotes ( IConsole : : IResult * pResult , void * pUserData )
{
CGameContext * pSelf = ( CGameContext * ) pUserData ;
int Page = pResult - > NumArguments ( ) > 0 ? pResult - > GetInteger ( 0 ) : 0 ;
static const int s_EntriesPerPage = 20 ;
const int Start = Page * s_EntriesPerPage ;
const int End = ( Page + 1 ) * s_EntriesPerPage ;
char aBuf [ 512 ] ;
int Count = 0 ;
for ( CVoteOptionServer * pOption = pSelf - > m_pVoteOptionFirst ; pOption ; pOption = pOption - > m_pNext , Count + + )
{
if ( Count < Start | | Count > = End )
{
continue ;
}
2023-09-26 10:13:49 +00:00
str_copy ( aBuf , " add_vote \" " ) ;
char * pDst = aBuf + str_length ( aBuf ) ;
str_escape ( & pDst , pOption - > m_aDescription , aBuf + sizeof ( aBuf ) ) ;
str_append ( aBuf , " \" \" " ) ;
pDst = aBuf + str_length ( aBuf ) ;
str_escape ( & pDst , pOption - > m_aCommand , aBuf + sizeof ( aBuf ) ) ;
str_append ( aBuf , " \" " ) ;
2023-09-26 00:24:00 +00:00
pSelf - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " votes " , aBuf ) ;
}
str_format ( aBuf , sizeof ( aBuf ) , " %d %s, showing entries %d - %d " , Count , Count = = 1 ? " vote " : " votes " , Start , End - 1 ) ;
pSelf - > Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " votes " , aBuf ) ;
}
2010-05-29 07:25:38 +00:00
void CGameContext : : ConchainSpecialMotdupdate ( 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 ( ) )
{
CGameContext * pSelf = ( CGameContext * ) pUserData ;
2021-01-09 13:05:54 +00:00
pSelf - > SendMotd ( - 1 ) ;
2010-05-29 07:25:38 +00:00
}
}
2023-09-04 12:03:56 +00:00
void CGameContext : : ConchainSettingUpdate ( IConsole : : IResult * pResult , void * pUserData , IConsole : : FCommandCallback pfnCallback , void * pCallbackUserData )
{
pfnCallback ( pResult , pCallbackUserData ) ;
if ( pResult - > NumArguments ( ) )
{
CGameContext * pSelf = ( CGameContext * ) pUserData ;
pSelf - > SendSettings ( - 1 ) ;
}
}
2010-05-29 07:25:38 +00:00
void CGameContext : : OnConsoleInit ( )
{
m_pServer = Kernel ( ) - > RequestInterface < IServer > ( ) ;
2021-01-10 12:47:07 +00:00
m_pConfig = Kernel ( ) - > RequestInterface < IConfigManager > ( ) - > Values ( ) ;
2010-05-29 07:25:38 +00:00
m_pConsole = Kernel ( ) - > RequestInterface < IConsole > ( ) ;
2018-06-19 12:45:53 +00:00
m_pEngine = Kernel ( ) - > RequestInterface < IEngine > ( ) ;
2017-10-13 00:25:50 +00:00
m_pStorage = Kernel ( ) - > RequestInterface < IStorage > ( ) ;
2010-09-16 22:40:44 +00:00
2022-08-09 14:52:20 +00:00
Console ( ) - > Register ( " tune " , " s[tuning] ?i[value] " , CFGFLAG_SERVER | CFGFLAG_GAME , ConTuneParam , this , " Tune variable to value or show current value " ) ;
2020-09-26 19:41:58 +00:00
Console ( ) - > Register ( " toggle_tune " , " s[tuning] i[value 1] i[value 2] " , CFGFLAG_SERVER | CFGFLAG_GAME , ConToggleTuneParam , this , " Toggle tune variable " ) ;
2022-08-09 14:47:04 +00:00
Console ( ) - > Register ( " tune_reset " , " ?s[tuning] " , CFGFLAG_SERVER , ConTuneReset , this , " Reset all or one tuning variable to default " ) ;
2022-08-09 14:34:07 +00:00
Console ( ) - > Register ( " tunes " , " " , CFGFLAG_SERVER , ConTunes , this , " List all tuning variables and their values " ) ;
2020-09-26 19:41:58 +00:00
Console ( ) - > Register ( " tune_zone " , " i[zone] s[tuning] i[value] " , CFGFLAG_SERVER | CFGFLAG_GAME , ConTuneZone , this , " Tune in zone a variable to value " ) ;
2020-10-11 14:27:28 +00:00
Console ( ) - > Register ( " tune_zone_dump " , " i[zone] " , CFGFLAG_SERVER , ConTuneDumpZone , this , " Dump zone tuning in zone x " ) ;
2020-10-17 15:29:33 +00:00
Console ( ) - > Register ( " tune_zone_reset " , " ?i[zone] " , CFGFLAG_SERVER , ConTuneResetZone , this , " reset zone tuning in zone x or in all zones " ) ;
2020-10-11 13:59:57 +00:00
Console ( ) - > Register ( " tune_zone_enter " , " i[zone] r[message] " , CFGFLAG_SERVER | CFGFLAG_GAME , ConTuneSetZoneMsgEnter , this , " which message to display on zone enter; use 0 for normal area " ) ;
2020-10-17 15:29:33 +00:00
Console ( ) - > Register ( " tune_zone_leave " , " i[zone] r[message] " , CFGFLAG_SERVER | CFGFLAG_GAME , ConTuneSetZoneMsgLeave , this , " which message to display on zone leave; use 0 for normal area " ) ;
2022-10-13 09:51:18 +00:00
Console ( ) - > Register ( " mapbug " , " s[mapbug] " , CFGFLAG_SERVER | CFGFLAG_GAME , ConMapbug , this , " Enable map compatibility mode using the specified bug (example: grenade-doubleexplosion@ddnet.tw) " ) ;
2020-09-26 19:41:58 +00:00
Console ( ) - > Register ( " switch_open " , " i[switch] " , CFGFLAG_SERVER | CFGFLAG_GAME , ConSwitchOpen , this , " Whether a switch is deactivated by default (otherwise activated) " ) ;
2012-04-12 00:09:31 +00:00
Console ( ) - > Register ( " pause_game " , " " , CFGFLAG_SERVER , ConPause , this , " Pause/unpause game " ) ;
2020-09-26 19:41:58 +00:00
Console ( ) - > Register ( " change_map " , " ?r[map] " , CFGFLAG_SERVER | CFGFLAG_STORE , ConChangeMap , this , " Change map " ) ;
2015-12-28 15:14:52 +00:00
Console ( ) - > Register ( " random_map " , " ?i[stars] " , CFGFLAG_SERVER , ConRandomMap , this , " Random map " ) ;
Console ( ) - > Register ( " random_unfinished_map " , " ?i[stars] " , CFGFLAG_SERVER , ConRandomUnfinishedMap , this , " Random unfinished map " ) ;
2020-09-26 19:41:58 +00:00
Console ( ) - > Register ( " restart " , " ?i[seconds] " , CFGFLAG_SERVER | CFGFLAG_STORE , ConRestart , this , " Restart in x seconds (0 = abort) " ) ;
2015-12-28 15:14:52 +00:00
Console ( ) - > Register ( " broadcast " , " r[message] " , CFGFLAG_SERVER , ConBroadcast , this , " Broadcast message " ) ;
Console ( ) - > Register ( " say " , " r[message] " , CFGFLAG_SERVER , ConSay , this , " Say in chat " ) ;
Console ( ) - > Register ( " set_team " , " i[id] i[team-id] ?i[delay in minutes] " , CFGFLAG_SERVER , ConSetTeam , this , " Set team of player to team " ) ;
Console ( ) - > Register ( " set_team_all " , " i[team-id] " , CFGFLAG_SERVER , ConSetTeamAll , this , " Set team of all players to team " ) ;
2011-07-14 20:07:21 +00:00
2015-12-28 15:14:52 +00:00
Console ( ) - > Register ( " add_vote " , " s[name] r[command] " , CFGFLAG_SERVER , ConAddVote , this , " Add a voting option " ) ;
2020-10-04 09:40:38 +00:00
Console ( ) - > Register ( " remove_vote " , " r[name] " , CFGFLAG_SERVER , ConRemoveVote , this , " remove a voting option " ) ;
2015-12-28 15:14:52 +00:00
Console ( ) - > Register ( " force_vote " , " s[name] s[command] ?r[reason] " , CFGFLAG_SERVER , ConForceVote , this , " Force a voting option " ) ;
2011-07-14 20:07:21 +00:00
Console ( ) - > Register ( " clear_votes " , " " , CFGFLAG_SERVER , ConClearVotes , this , " Clears the voting options " ) ;
2020-10-17 22:05:59 +00:00
Console ( ) - > Register ( " add_map_votes " , " " , CFGFLAG_SERVER , ConAddMapVotes , this , " Automatically adds voting options for all maps " ) ;
2015-12-28 15:14:52 +00:00
Console ( ) - > Register ( " vote " , " r['yes'|'no'] " , CFGFLAG_SERVER , ConVote , this , " Force a vote to yes/no " ) ;
2023-09-26 00:24:00 +00:00
Console ( ) - > Register ( " votes " , " ?i[page] " , CFGFLAG_SERVER , ConVotes , this , " Show all votes (page 0 by default, 20 entries per page) " ) ;
2020-03-11 00:58:50 +00:00
Console ( ) - > Register ( " dump_antibot " , " " , CFGFLAG_SERVER , ConDumpAntibot , this , " Dumps the antibot status " ) ;
2023-11-19 03:41:56 +00:00
Console ( ) - > Register ( " antibot " , " r[command] " , CFGFLAG_SERVER , ConAntibot , this , " Sends a command to the antibot " ) ;
2010-05-29 07:25:38 +00:00
Console ( ) - > Chain ( " sv_motd " , ConchainSpecialMotdupdate , this ) ;
2010-10-10 22:40:07 +00:00
2023-09-04 12:03:56 +00:00
Console ( ) - > Chain ( " sv_vote_kick " , ConchainSettingUpdate , this ) ;
Console ( ) - > Chain ( " sv_vote_kick_min " , ConchainSettingUpdate , this ) ;
Console ( ) - > Chain ( " sv_vote_spectate " , ConchainSettingUpdate , this ) ;
Console ( ) - > Chain ( " sv_spectator_slots " , ConchainSettingUpdate , this ) ;
Console ( ) - > Chain ( " sv_max_clients " , ConchainSettingUpdate , this ) ;
2020-09-26 19:41:58 +00:00
# define CONSOLE_COMMAND(name, params, flags, callback, userdata, help) m_pConsole->Register(name, params, flags, callback, userdata, help);
# include <game/ddracecommands.h>
# define CHAT_COMMAND(name, params, flags, callback, userdata, help) m_pConsole->Register(name, params, flags, callback, userdata, help);
2021-01-11 21:54:08 +00:00
# include <game/ddracechat.h>
2010-05-29 07:25:38 +00:00
}
2023-08-25 12:52:37 +00:00
void CGameContext : : OnInit ( const void * pPersistentData )
2010-05-29 07:25:38 +00:00
{
2023-08-25 12:52:37 +00:00
const CPersistentData * pPersistent = ( const CPersistentData * ) pPersistentData ;
2010-05-29 07:25:38 +00:00
m_pServer = Kernel ( ) - > RequestInterface < IServer > ( ) ;
2021-01-10 12:47:07 +00:00
m_pConfig = Kernel ( ) - > RequestInterface < IConfigManager > ( ) - > Values ( ) ;
2010-05-29 07:25:38 +00:00
m_pConsole = Kernel ( ) - > RequestInterface < IConsole > ( ) ;
2018-06-19 12:45:53 +00:00
m_pEngine = Kernel ( ) - > RequestInterface < IEngine > ( ) ;
2017-10-13 00:25:50 +00:00
m_pStorage = Kernel ( ) - > RequestInterface < IStorage > ( ) ;
2020-05-13 20:27:49 +00:00
m_pAntibot = Kernel ( ) - > RequestInterface < IAntibot > ( ) ;
2010-05-29 07:25:38 +00:00
m_World . SetGameServer ( this ) ;
m_Events . SetGameServer ( this ) ;
2011-04-13 18:37:12 +00:00
2017-09-12 12:58:44 +00:00
m_GameUuid = RandomUuid ( ) ;
2017-09-13 20:35:09 +00:00
Console ( ) - > SetTeeHistorianCommandCallback ( CommandCallback , this ) ;
2017-09-12 12:58:44 +00:00
2021-06-23 05:05:49 +00:00
uint64_t aSeed [ 2 ] ;
2020-05-26 08:59:49 +00:00
secure_random_fill ( aSeed , sizeof ( aSeed ) ) ;
m_Prng . Seed ( aSeed ) ;
2020-05-25 13:08:24 +00:00
m_World . m_Core . m_pPrng = & m_Prng ;
2015-07-14 20:08:29 +00:00
DeleteTempfile ( ) ;
2010-05-29 07:25:38 +00:00
for ( int i = 0 ; i < NUM_NETOBJTYPES ; i + + )
Server ( ) - > SnapSetStaticsize ( i , m_NetObjHandler . GetObjSize ( i ) ) ;
m_Layers . Init ( Kernel ( ) ) ;
m_Collision . Init ( & m_Layers ) ;
2023-09-05 23:08:01 +00:00
m_World . m_pTuningList = m_aTuningList ;
2022-05-01 23:54:29 +00:00
m_World . m_Core . InitSwitchers ( m_Collision . m_HighestSwitchNumber ) ;
2010-05-29 07:25:38 +00:00
2021-12-20 14:00:21 +00:00
char aMapName [ IO_MAX_PATH_LENGTH ] ;
2018-03-24 13:00:41 +00:00
int MapSize ;
2018-06-05 19:22:40 +00:00
SHA256_DIGEST MapSha256 ;
2018-03-24 13:00:41 +00:00
int MapCrc ;
2018-06-05 19:22:40 +00:00
Server ( ) - > GetMapInfo ( aMapName , sizeof ( aMapName ) , & MapSize , & MapSha256 , & MapCrc ) ;
2020-10-10 20:06:47 +00:00
m_MapBugs = GetMapBugs ( aMapName , MapSize , MapSha256 ) ;
2018-03-24 13:00:41 +00:00
2014-03-12 23:31:50 +00:00
// Reset Tunezones
CTuningParams TuningParams ;
2020-09-26 19:41:58 +00:00
for ( int i = 0 ; i < NUM_TUNEZONES ; i + + )
2014-03-12 23:31:50 +00:00
{
2014-03-23 18:31:28 +00:00
TuningList ( ) [ i ] = TuningParams ;
TuningList ( ) [ i ] . Set ( " gun_curvature " , 0 ) ;
TuningList ( ) [ i ] . Set ( " gun_speed " , 1400 ) ;
TuningList ( ) [ i ] . Set ( " shotgun_curvature " , 0 ) ;
TuningList ( ) [ i ] . Set ( " shotgun_speed " , 500 ) ;
TuningList ( ) [ i ] . Set ( " shotgun_speeddiff " , 0 ) ;
2014-03-12 23:31:50 +00:00
}
2014-03-23 18:31:28 +00:00
2020-09-26 19:41:58 +00:00
for ( int i = 0 ; i < NUM_TUNEZONES ; i + + )
2014-03-12 23:31:50 +00:00
{
2017-07-26 01:58:00 +00:00
// Send no text by default when changing tune zones.
m_aaZoneEnterMsg [ i ] [ 0 ] = 0 ;
m_aaZoneLeaveMsg [ i ] [ 0 ] = 0 ;
2014-03-12 23:31:50 +00:00
}
2011-05-30 20:05:28 +00:00
// Reset Tuning
2011-09-02 18:37:03 +00:00
if ( g_Config . m_SvTuneReset )
{
ResetTuning ( ) ;
}
2011-09-05 11:55:47 +00:00
else
{
Tuning ( ) - > Set ( " gun_speed " , 1400 ) ;
Tuning ( ) - > Set ( " gun_curvature " , 0 ) ;
Tuning ( ) - > Set ( " shotgun_speed " , 500 ) ;
Tuning ( ) - > Set ( " shotgun_speeddiff " , 0 ) ;
Tuning ( ) - > Set ( " shotgun_curvature " , 0 ) ;
}
2011-09-02 18:37:03 +00:00
if ( g_Config . m_SvDDRaceTuneReset )
{
g_Config . m_SvHit = 1 ;
g_Config . m_SvEndlessDrag = 0 ;
g_Config . m_SvOldLaser = 0 ;
2013-11-24 18:23:58 +00:00
g_Config . m_SvOldTeleportHook = 0 ;
g_Config . m_SvOldTeleportWeapons = 0 ;
2014-04-04 22:35:18 +00:00
g_Config . m_SvTeleportHoldHook = 0 ;
2022-02-19 14:20:32 +00:00
g_Config . m_SvTeam = SV_TEAM_ALLOWED ;
2022-03-03 21:56:32 +00:00
g_Config . m_SvShowOthersDefault = SHOW_OTHERS_OFF ;
2015-07-22 21:31:50 +00:00
2022-05-01 23:54:29 +00:00
for ( auto & Switcher : Switchers ( ) )
Switcher . m_Initial = true ;
2011-09-02 18:37:03 +00:00
}
2011-05-30 20:05:28 +00:00
2016-05-02 19:35:32 +00:00
Console ( ) - > ExecuteFile ( g_Config . m_SvResetFile , - 1 ) ;
2013-07-21 21:42:08 +00:00
2015-07-15 12:02:21 +00:00
LoadMapSettings ( ) ;
2018-05-01 10:38:33 +00:00
m_MapBugs . Dump ( ) ;
2020-06-30 18:22:17 +00:00
if ( g_Config . m_SvSoloServer )
{
2022-02-19 14:20:32 +00:00
g_Config . m_SvTeam = SV_TEAM_FORCED_SOLO ;
2022-03-03 21:56:32 +00:00
g_Config . m_SvShowOthersDefault = SHOW_OTHERS_ON ;
2020-06-30 18:22:17 +00:00
Tuning ( ) - > Set ( " player_collision " , 0 ) ;
Tuning ( ) - > Set ( " player_hooking " , 0 ) ;
2020-09-26 19:41:58 +00:00
for ( int i = 0 ; i < NUM_TUNEZONES ; i + + )
2020-06-30 18:22:17 +00:00
{
TuningList ( ) [ i ] . Set ( " player_collision " , 0 ) ;
TuningList ( ) [ i ] . Set ( " player_hooking " , 0 ) ;
}
}
2023-11-16 10:39:55 +00:00
if ( ! str_comp ( Config ( ) - > m_SvGametype , " mod " ) )
m_pController = new CGameControllerMod ( this ) ;
else
m_pController = new CGameControllerDDRace ( this ) ;
2017-10-10 00:39:29 +00:00
2020-09-18 15:37:27 +00:00
const char * pCensorFilename = " censorlist.txt " ;
2021-12-17 20:58:28 +00:00
IOHANDLE File = Storage ( ) - > OpenFile ( pCensorFilename , IOFLAG_READ | IOFLAG_SKIP_BOM , IStorage : : TYPE_ALL ) ;
2020-09-18 15:37:27 +00:00
if ( ! File )
{
dbg_msg ( " censorlist " , " failed to open '%s' " , pCensorFilename ) ;
}
else
{
CLineReader LineReader ;
LineReader . Init ( File ) ;
char * pLine ;
while ( ( pLine = LineReader . Get ( ) ) )
{
2022-05-23 20:35:21 +00:00
m_vCensorlist . emplace_back ( pLine ) ;
2020-09-18 15:37:27 +00:00
}
io_close ( File ) ;
}
2017-09-12 12:58:44 +00:00
m_TeeHistorianActive = g_Config . m_SvTeeHistorian ;
if ( m_TeeHistorianActive )
{
char aGameUuid [ UUID_MAXSTRSIZE ] ;
FormatUuid ( m_GameUuid , aGameUuid , sizeof ( aGameUuid ) ) ;
2021-09-13 08:06:34 +00:00
char aFilename [ IO_MAX_PATH_LENGTH ] ;
2017-09-12 12:58:44 +00:00
str_format ( aFilename , sizeof ( aFilename ) , " teehistorian/%s.teehistorian " , aGameUuid ) ;
2022-03-20 11:57:50 +00:00
IOHANDLE THFile = Storage ( ) - > OpenFile ( aFilename , IOFLAG_WRITE , IStorage : : TYPE_SAVE ) ;
if ( ! THFile )
2017-09-12 12:58:44 +00:00
{
dbg_msg ( " teehistorian " , " failed to open '%s' " , aFilename ) ;
2017-10-13 00:25:50 +00:00
Server ( ) - > SetErrorShutdown ( " teehistorian open error " ) ;
return ;
2017-09-12 12:58:44 +00:00
}
else
{
dbg_msg ( " teehistorian " , " recording to '%s' " , aFilename ) ;
}
2022-03-20 11:57:50 +00:00
m_pTeeHistorianFile = aio_new ( THFile ) ;
2017-09-12 12:58:44 +00:00
char aVersion [ 128 ] ;
2018-03-01 15:50:29 +00:00
if ( GIT_SHORTREV_HASH )
{
str_format ( aVersion , sizeof ( aVersion ) , " %s (%s) " , GAME_VERSION , GIT_SHORTREV_HASH ) ;
}
else
{
2022-10-27 19:28:49 +00:00
str_copy ( aVersion , GAME_VERSION ) ;
2018-03-01 15:50:29 +00:00
}
2017-09-12 12:58:44 +00:00
CTeeHistorian : : CGameInfo GameInfo ;
GameInfo . m_GameUuid = m_GameUuid ;
GameInfo . m_pServerVersion = aVersion ;
GameInfo . m_StartTime = time ( 0 ) ;
2020-05-25 13:08:24 +00:00
GameInfo . m_pPrngDescription = m_Prng . Description ( ) ;
2017-09-12 12:58:44 +00:00
GameInfo . m_pServerName = g_Config . m_SvName ;
2020-08-29 12:14:37 +00:00
GameInfo . m_ServerPort = Server ( ) - > Port ( ) ;
2017-09-27 17:38:54 +00:00
GameInfo . m_pGameType = m_pController - > m_pGameType ;
2017-09-12 12:58:44 +00:00
2017-09-13 20:35:09 +00:00
GameInfo . m_pConfig = & g_Config ;
GameInfo . m_pTuning = Tuning ( ) ;
2017-11-18 02:08:16 +00:00
GameInfo . m_pUuids = & g_UuidManager ;
2017-09-13 20:35:09 +00:00
2017-09-12 12:58:44 +00:00
GameInfo . m_pMapName = aMapName ;
2018-03-24 13:00:41 +00:00
GameInfo . m_MapSize = MapSize ;
2018-06-05 19:22:40 +00:00
GameInfo . m_MapSha256 = MapSha256 ;
2018-03-24 13:00:41 +00:00
GameInfo . m_MapCrc = MapCrc ;
2017-09-12 12:58:44 +00:00
2023-08-25 14:29:12 +00:00
if ( pPersistent )
{
GameInfo . m_HavePrevGameUuid = true ;
GameInfo . m_PrevGameUuid = pPersistent - > m_PrevGameUuid ;
}
else
{
GameInfo . m_HavePrevGameUuid = false ;
mem_zero ( & GameInfo . m_PrevGameUuid , sizeof ( GameInfo . m_PrevGameUuid ) ) ;
}
2017-09-12 12:58:44 +00:00
m_TeeHistorian . Reset ( & GameInfo , TeeHistorianWrite , this ) ;
2018-01-28 02:13:05 +00:00
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
{
int Level = Server ( ) - > GetAuthedState ( i ) ;
if ( Level )
{
m_TeeHistorian . RecordAuthInitial ( i , Level , Server ( ) - > GetAuthName ( i ) ) ;
}
}
2017-09-12 12:58:44 +00:00
}
2020-07-04 17:53:27 +00:00
if ( ! m_pScore )
{
m_pScore = new CScore ( this , ( ( CServer * ) Server ( ) ) - > DbPool ( ) ) ;
}
2011-04-09 06:41:31 +00:00
2010-05-29 07:25:38 +00:00
// create all entities from the game layer
2022-12-12 23:06:14 +00:00
CreateAllEntities ( true ) ;
if ( GIT_SHORTREV_HASH )
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " git-revision " , GIT_SHORTREV_HASH ) ;
2023-08-27 15:35:13 +00:00
m_pAntibot - > RoundStart ( this ) ;
2022-12-12 23:06:14 +00:00
}
void CGameContext : : CreateAllEntities ( bool Initial )
{
2022-12-13 21:11:53 +00:00
const CMapItemLayerTilemap * pTileMap = m_Layers . GameLayer ( ) ;
const CTile * pTiles = static_cast < CTile * > ( Kernel ( ) - > RequestInterface < IMap > ( ) - > GetData ( pTileMap - > m_Data ) ) ;
2011-04-13 18:37:12 +00:00
2022-12-13 21:11:53 +00:00
const CTile * pFront = nullptr ;
2010-10-10 22:40:07 +00:00
if ( m_Layers . FrontLayer ( ) )
2022-12-13 21:11:53 +00:00
pFront = static_cast < CTile * > ( Kernel ( ) - > RequestInterface < IMap > ( ) - > GetData ( m_Layers . FrontLayer ( ) - > m_Front ) ) ;
const CSwitchTile * pSwitch = nullptr ;
2010-11-13 13:22:19 +00:00
if ( m_Layers . SwitchLayer ( ) )
2022-12-13 21:11:53 +00:00
pSwitch = static_cast < CSwitchTile * > ( Kernel ( ) - > RequestInterface < IMap > ( ) - > GetData ( m_Layers . SwitchLayer ( ) - > m_Switch ) ) ;
2010-08-20 20:40:12 +00:00
2010-05-29 07:25:38 +00:00
for ( int y = 0 ; y < pTileMap - > m_Height ; y + + )
{
for ( int x = 0 ; x < pTileMap - > m_Width ; x + + )
{
2022-12-13 21:52:01 +00:00
const int Index = y * pTileMap - > m_Width + x ;
2011-04-13 18:37:12 +00:00
2022-12-13 21:52:01 +00:00
// Game layer
2010-12-01 23:33:02 +00:00
{
2022-12-13 21:52:01 +00:00
const int GameIndex = pTiles [ Index ] . m_Index ;
if ( GameIndex = = TILE_OLDLASER )
{
g_Config . m_SvOldLaser = 1 ;
dbg_msg ( " game_layer " , " found old laser tile " ) ;
}
else if ( GameIndex = = TILE_NPC )
{
m_Tuning . Set ( " player_collision " , 0 ) ;
dbg_msg ( " game_layer " , " found no collision tile " ) ;
}
else if ( GameIndex = = TILE_EHOOK )
{
g_Config . m_SvEndlessDrag = 1 ;
dbg_msg ( " game_layer " , " found unlimited hook time tile " ) ;
}
else if ( GameIndex = = TILE_NOHIT )
{
g_Config . m_SvHit = 0 ;
dbg_msg ( " game_layer " , " found no weapons hitting others tile " ) ;
}
else if ( GameIndex = = TILE_NPH )
{
m_Tuning . Set ( " player_hooking " , 0 ) ;
dbg_msg ( " game_layer " , " found no player hooking tile " ) ;
}
else if ( GameIndex > = ENTITY_OFFSET )
{
m_pController - > OnEntity ( GameIndex - ENTITY_OFFSET , x , y , LAYER_GAME , pTiles [ Index ] . m_Flags , Initial ) ;
}
2010-08-20 20:40:12 +00:00
}
2011-04-09 06:41:31 +00:00
2010-10-10 22:40:07 +00:00
if ( pFront )
2010-08-20 20:40:12 +00:00
{
2022-12-13 21:52:01 +00:00
const int FrontIndex = pFront [ Index ] . m_Index ;
if ( FrontIndex = = TILE_OLDLASER )
2011-01-29 00:59:50 +00:00
{
2010-12-01 22:45:04 +00:00
g_Config . m_SvOldLaser = 1 ;
2020-10-26 08:57:41 +00:00
dbg_msg ( " front_layer " , " found old laser tile " ) ;
2011-01-29 00:59:50 +00:00
}
2022-12-13 21:52:01 +00:00
else if ( FrontIndex = = TILE_NPC )
2011-01-29 00:59:50 +00:00
{
m_Tuning . Set ( " player_collision " , 0 ) ;
2020-10-26 08:57:41 +00:00
dbg_msg ( " front_layer " , " found no collision tile " ) ;
2011-01-29 00:59:50 +00:00
}
2022-12-13 21:52:01 +00:00
else if ( FrontIndex = = TILE_EHOOK )
2011-01-29 00:59:50 +00:00
{
2010-08-28 19:34:21 +00:00
g_Config . m_SvEndlessDrag = 1 ;
2020-10-26 08:57:41 +00:00
dbg_msg ( " front_layer " , " found unlimited hook time tile " ) ;
2011-01-29 00:59:50 +00:00
}
2022-12-13 21:52:01 +00:00
else if ( FrontIndex = = TILE_NOHIT )
2011-01-29 00:59:50 +00:00
{
2010-08-28 19:34:21 +00:00
g_Config . m_SvHit = 0 ;
2020-10-26 08:57:41 +00:00
dbg_msg ( " front_layer " , " found no weapons hitting others tile " ) ;
2011-01-29 00:59:50 +00:00
}
2022-12-13 21:52:01 +00:00
else if ( FrontIndex = = TILE_NPH )
2011-01-29 00:59:50 +00:00
{
m_Tuning . Set ( " player_hooking " , 0 ) ;
2020-10-26 08:57:41 +00:00
dbg_msg ( " front_layer " , " found no player hooking tile " ) ;
2011-01-29 00:59:50 +00:00
}
2022-12-13 21:52:01 +00:00
else if ( FrontIndex > = ENTITY_OFFSET )
2010-08-20 20:40:12 +00:00
{
2022-12-13 21:52:01 +00:00
m_pController - > OnEntity ( FrontIndex - ENTITY_OFFSET , x , y , LAYER_FRONT , pFront [ Index ] . m_Flags , Initial ) ;
2010-11-13 13:22:19 +00:00
}
}
2022-12-13 21:52:01 +00:00
2010-11-13 13:22:19 +00:00
if ( pSwitch )
{
2022-12-13 21:52:01 +00:00
const int SwitchType = pSwitch [ Index ] . m_Type ;
2013-08-22 22:45:48 +00:00
// TODO: Add off by default door here
2022-12-13 21:52:01 +00:00
// if(SwitchType == TILE_DOOR_OFF)
if ( SwitchType > = ENTITY_OFFSET )
2010-11-13 13:22:19 +00:00
{
2022-12-13 21:52:01 +00:00
m_pController - > OnEntity ( SwitchType - ENTITY_OFFSET , x , y , LAYER_SWITCH , pSwitch [ Index ] . m_Flags , Initial , pSwitch [ Index ] . m_Number ) ;
2010-08-20 20:40:12 +00:00
}
2010-05-29 07:25:38 +00:00
}
}
}
}
2015-07-14 20:08:29 +00:00
void CGameContext : : DeleteTempfile ( )
{
if ( m_aDeleteTempfile [ 0 ] ! = 0 )
{
2017-10-13 00:25:50 +00:00
Storage ( ) - > RemoveFile ( m_aDeleteTempfile , IStorage : : TYPE_SAVE ) ;
2015-07-14 20:08:29 +00:00
m_aDeleteTempfile [ 0 ] = 0 ;
}
}
void CGameContext : : OnMapChange ( char * pNewMapName , int MapNameSize )
{
2021-12-20 14:00:21 +00:00
char aConfig [ IO_MAX_PATH_LENGTH ] ;
2015-07-14 20:08:29 +00:00
str_format ( aConfig , sizeof ( aConfig ) , " maps/%s.cfg " , g_Config . m_SvMap ) ;
2021-12-17 20:58:28 +00:00
IOHANDLE File = Storage ( ) - > OpenFile ( aConfig , IOFLAG_READ | IOFLAG_SKIP_BOM , IStorage : : TYPE_ALL ) ;
2015-07-14 20:08:29 +00:00
if ( ! File )
{
// No map-specific config, just return.
return ;
}
CLineReader LineReader ;
LineReader . Init ( File ) ;
2022-05-23 21:03:52 +00:00
std : : vector < char * > vLines ;
2015-07-14 20:08:29 +00:00
char * pLine ;
int TotalLength = 0 ;
while ( ( pLine = LineReader . Get ( ) ) )
{
int Length = str_length ( pLine ) + 1 ;
2018-04-09 09:56:39 +00:00
char * pCopy = ( char * ) malloc ( Length ) ;
2015-07-14 20:08:29 +00:00
mem_copy ( pCopy , pLine , Length ) ;
2022-05-23 21:03:52 +00:00
vLines . push_back ( pCopy ) ;
2015-07-14 20:08:29 +00:00
TotalLength + = Length ;
}
2017-07-08 11:38:27 +00:00
io_close ( File ) ;
2015-07-14 20:08:29 +00:00
2020-10-12 14:07:29 +00:00
char * pSettings = ( char * ) malloc ( maximum ( 1 , TotalLength ) ) ;
2015-07-14 20:08:29 +00:00
int Offset = 0 ;
2022-05-23 21:03:52 +00:00
for ( auto & Line : vLines )
2015-07-14 20:08:29 +00:00
{
2022-05-23 21:03:52 +00:00
int Length = str_length ( Line ) + 1 ;
mem_copy ( pSettings + Offset , Line , Length ) ;
2015-07-15 09:38:42 +00:00
Offset + = Length ;
2022-05-23 21:03:52 +00:00
free ( Line ) ;
2015-07-14 20:08:29 +00:00
}
CDataFileReader Reader ;
2017-10-13 00:25:50 +00:00
Reader . Open ( Storage ( ) , pNewMapName , IStorage : : TYPE_ALL ) ;
2015-07-14 20:08:29 +00:00
CDataFileWriter Writer ;
int SettingsIndex = Reader . NumData ( ) ;
2015-08-27 13:46:51 +00:00
bool FoundInfo = false ;
2015-07-14 20:08:29 +00:00
for ( int i = 0 ; i < Reader . NumItems ( ) ; i + + )
{
int TypeID ;
int ItemID ;
2022-11-12 19:04:21 +00:00
void * pData = Reader . GetItem ( i , & TypeID , & ItemID ) ;
2017-08-28 16:06:19 +00:00
int Size = Reader . GetItemSize ( i ) ;
2015-07-14 20:08:29 +00:00
CMapItemInfoSettings MapInfo ;
if ( TypeID = = MAPITEMTYPE_INFO & & ItemID = = 0 )
{
2015-08-27 13:46:51 +00:00
FoundInfo = true ;
2015-07-14 20:08:29 +00:00
if ( Size > = ( int ) sizeof ( CMapItemInfoSettings ) )
{
2022-11-12 19:04:21 +00:00
CMapItemInfoSettings * pInfo = ( CMapItemInfoSettings * ) pData ;
2015-08-21 21:02:50 +00:00
if ( pInfo - > m_Settings > - 1 )
2015-07-14 20:08:29 +00:00
{
2015-08-21 21:02:50 +00:00
SettingsIndex = pInfo - > m_Settings ;
char * pMapSettings = ( char * ) Reader . GetData ( SettingsIndex ) ;
2017-08-30 06:36:17 +00:00
int DataSize = Reader . GetDataSize ( SettingsIndex ) ;
2015-08-27 14:20:56 +00:00
if ( DataSize = = TotalLength & & mem_comp ( pSettings , pMapSettings , DataSize ) = = 0 )
2015-08-21 21:02:50 +00:00
{
// Configs coincide, no need to update map.
2020-10-12 14:07:29 +00:00
free ( pSettings ) ;
2015-08-21 21:02:50 +00:00
return ;
}
Reader . UnloadData ( pInfo - > m_Settings ) ;
}
else
{
MapInfo = * pInfo ;
MapInfo . m_Settings = SettingsIndex ;
2022-11-12 19:04:21 +00:00
pData = & MapInfo ;
2015-08-21 21:02:50 +00:00
Size = sizeof ( MapInfo ) ;
2015-07-14 20:08:29 +00:00
}
}
else
{
2022-11-12 19:04:21 +00:00
* ( CMapItemInfo * ) & MapInfo = * ( CMapItemInfo * ) pData ;
2015-07-14 20:08:29 +00:00
MapInfo . m_Settings = SettingsIndex ;
2022-11-12 19:04:21 +00:00
pData = & MapInfo ;
2015-07-14 20:08:29 +00:00
Size = sizeof ( MapInfo ) ;
}
}
Writer . AddItem ( TypeID , ItemID , Size , pData ) ;
}
2015-08-27 13:46:51 +00:00
if ( ! FoundInfo )
{
CMapItemInfoSettings Info ;
Info . m_Version = 1 ;
Info . m_Author = - 1 ;
Info . m_MapVersion = - 1 ;
Info . m_Credits = - 1 ;
Info . m_License = - 1 ;
Info . m_Settings = SettingsIndex ;
Writer . AddItem ( MAPITEMTYPE_INFO , 0 , sizeof ( Info ) , & Info ) ;
}
2015-07-14 20:08:29 +00:00
for ( int i = 0 ; i < Reader . NumData ( ) | | i = = SettingsIndex ; i + + )
{
if ( i = = SettingsIndex )
{
Writer . AddData ( TotalLength , pSettings ) ;
continue ;
}
2023-07-07 23:43:46 +00:00
const void * pData = Reader . GetData ( i ) ;
2017-08-30 06:36:17 +00:00
int Size = Reader . GetDataSize ( i ) ;
2015-07-14 20:08:29 +00:00
Writer . AddData ( Size , pData ) ;
Reader . UnloadData ( i ) ;
}
dbg_msg ( " mapchange " , " imported settings " ) ;
2020-10-12 14:07:29 +00:00
free ( pSettings ) ;
2015-07-14 20:08:29 +00:00
Reader . Close ( ) ;
2021-12-20 14:00:21 +00:00
char aTemp [ IO_MAX_PATH_LENGTH ] ;
2023-10-14 09:40:18 +00:00
Writer . Open ( Storage ( ) , IStorage : : FormatTmpPath ( aTemp , sizeof ( aTemp ) , pNewMapName ) ) ;
2015-07-14 20:08:29 +00:00
Writer . Finish ( ) ;
str_copy ( pNewMapName , aTemp , MapNameSize ) ;
str_copy ( m_aDeleteTempfile , aTemp , sizeof ( m_aDeleteTempfile ) ) ;
}
2023-08-25 12:52:37 +00:00
void CGameContext : : OnShutdown ( void * pPersistentData )
2010-05-29 07:25:38 +00:00
{
2023-08-25 12:52:37 +00:00
CPersistentData * pPersistent = ( CPersistentData * ) pPersistentData ;
2023-08-25 14:29:12 +00:00
if ( pPersistent )
{
pPersistent - > m_PrevGameUuid = m_GameUuid ;
}
2020-05-13 20:27:49 +00:00
Antibot ( ) - > RoundEnd ( ) ;
2017-09-12 12:58:44 +00:00
if ( m_TeeHistorianActive )
{
m_TeeHistorian . Finish ( ) ;
2017-10-13 00:48:42 +00:00
aio_close ( m_pTeeHistorianFile ) ;
aio_wait ( m_pTeeHistorianFile ) ;
int Error = aio_error ( m_pTeeHistorianFile ) ;
2017-10-10 02:07:38 +00:00
if ( Error )
{
dbg_msg ( " teehistorian " , " error closing file, err=%d " , Error ) ;
2017-10-13 00:25:50 +00:00
Server ( ) - > SetErrorShutdown ( " teehistorian close error " ) ;
2017-10-10 02:07:38 +00:00
}
2017-10-13 00:48:42 +00:00
aio_free ( m_pTeeHistorianFile ) ;
2017-09-12 12:58:44 +00:00
}
2015-07-14 20:08:29 +00:00
DeleteTempfile ( ) ;
2023-07-28 10:11:47 +00:00
Console ( ) - > ResetGameSettings ( ) ;
2010-10-27 10:14:26 +00:00
Collision ( ) - > Dest ( ) ;
2010-05-29 07:25:38 +00:00
delete m_pController ;
m_pController = 0 ;
Clear ( ) ;
2008-08-14 18:42:47 +00:00
}
2011-07-13 20:38:32 +00:00
void CGameContext : : LoadMapSettings ( )
{
IMap * pMap = Kernel ( ) - > RequestInterface < IMap > ( ) ;
int Start , Num ;
pMap - > GetType ( MAPITEMTYPE_INFO , & Start , & Num ) ;
for ( int i = Start ; i < Start + Num ; i + + )
{
int ItemID ;
2023-02-20 22:38:54 +00:00
CMapItemInfoSettings * pItem = ( CMapItemInfoSettings * ) pMap - > GetItem ( i , nullptr , & ItemID ) ;
2017-08-28 16:06:19 +00:00
int ItemSize = pMap - > GetItemSize ( i ) ;
2011-07-13 20:38:32 +00:00
if ( ! pItem | | ItemID ! = 0 )
continue ;
if ( ItemSize < ( int ) sizeof ( CMapItemInfoSettings ) )
break ;
if ( ! ( pItem - > m_Settings > - 1 ) )
break ;
2017-08-30 06:36:17 +00:00
int Size = pMap - > GetDataSize ( pItem - > m_Settings ) ;
2011-07-13 20:38:32 +00:00
char * pSettings = ( char * ) pMap - > GetData ( pItem - > m_Settings ) ;
char * pNext = pSettings ;
while ( pNext < pSettings + Size )
{
int StrSize = str_length ( pNext ) + 1 ;
2015-07-15 12:02:21 +00:00
Console ( ) - > ExecuteLine ( pNext , IConsole : : CLIENT_ID_GAME ) ;
2011-07-13 20:38:32 +00:00
pNext + = StrSize ;
}
pMap - > UnloadData ( pItem - > m_Settings ) ;
2015-08-21 21:02:50 +00:00
break ;
2011-07-13 20:38:32 +00:00
}
2015-07-15 12:02:21 +00:00
2021-12-20 14:00:21 +00:00
char aBuf [ IO_MAX_PATH_LENGTH ] ;
2015-07-15 12:02:21 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " maps/%s.map.cfg " , g_Config . m_SvMap ) ;
Console ( ) - > ExecuteFile ( aBuf , IConsole : : CLIENT_ID_NO_GAME ) ;
2011-07-13 20:38:32 +00:00
}
2011-02-12 10:40:36 +00:00
void CGameContext : : OnSnap ( int ClientID )
2008-08-14 18:42:47 +00:00
{
2012-01-08 23:49:20 +00:00
// add tuning to demo
CTuningParams StandardTuning ;
2022-08-25 15:02:40 +00:00
if ( Server ( ) - > IsRecording ( ClientID > - 1 ? ClientID : MAX_CLIENTS ) & & mem_comp ( & StandardTuning , & m_Tuning , sizeof ( CTuningParams ) ) ! = 0 )
2012-01-08 23:49:20 +00:00
{
CMsgPacker Msg ( NETMSGTYPE_SV_TUNEPARAMS ) ;
int * pParams = ( int * ) & m_Tuning ;
2020-09-26 19:41:58 +00:00
for ( unsigned i = 0 ; i < sizeof ( m_Tuning ) / sizeof ( int ) ; i + + )
2012-01-08 23:49:20 +00:00
Msg . AddInt ( pParams [ i ] ) ;
2020-09-26 19:41:58 +00:00
Server ( ) - > SendMsg ( & Msg , MSGFLAG_RECORD | MSGFLAG_NOSEND , ClientID ) ;
2012-01-08 23:49:20 +00:00
}
2021-10-25 00:34:28 +00:00
m_pController - > Snap ( ClientID ) ;
2020-10-26 14:14:07 +00:00
for ( auto & pPlayer : m_apPlayers )
2008-08-14 18:42:47 +00:00
{
2020-10-26 14:14:07 +00:00
if ( pPlayer )
pPlayer - > Snap ( ClientID ) ;
2008-08-14 18:42:47 +00:00
}
2014-09-26 01:20:47 +00:00
if ( ClientID > - 1 )
2016-09-20 19:40:40 +00:00
m_apPlayers [ ClientID ] - > FakeSnap ( ) ;
2021-10-21 20:39:54 +00:00
m_World . Snap ( ClientID ) ;
m_Events . Snap ( ClientID ) ;
2008-08-14 18:42:47 +00:00
}
2010-05-29 07:25:38 +00:00
void CGameContext : : OnPreSnap ( ) { }
void CGameContext : : OnPostSnap ( )
{
m_Events . Clear ( ) ;
}
2023-09-05 22:44:21 +00:00
void CGameContext : : UpdatePlayerMaps ( )
{
const auto DistCompare = [ ] ( std : : pair < float , int > a , std : : pair < float , int > b ) - > bool {
return ( a . first < b . first ) ;
} ;
if ( Server ( ) - > Tick ( ) % g_Config . m_SvMapUpdateRate ! = 0 )
return ;
std : : pair < float , int > Dist [ MAX_CLIENTS ] ;
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
{
if ( ! Server ( ) - > ClientIngame ( i ) )
continue ;
if ( Server ( ) - > GetClientVersion ( i ) > = VERSION_DDNET_OLD )
continue ;
int * pMap = Server ( ) - > GetIdMap ( i ) ;
// compute distances
for ( int j = 0 ; j < MAX_CLIENTS ; j + + )
{
Dist [ j ] . second = j ;
if ( j = = i )
continue ;
if ( ! Server ( ) - > ClientIngame ( j ) | | ! m_apPlayers [ j ] )
{
Dist [ j ] . first = 1e10 ;
continue ;
}
CCharacter * pChr = m_apPlayers [ j ] - > GetCharacter ( ) ;
if ( ! pChr )
{
Dist [ j ] . first = 1e9 ;
continue ;
}
if ( ! pChr - > CanSnapCharacter ( i ) )
Dist [ j ] . first = 1e8 ;
else
Dist [ j ] . first = length_squared ( m_apPlayers [ i ] - > m_ViewPos - pChr - > GetPos ( ) ) ;
}
// always send the player themselves, even if all in same position
Dist [ i ] . first = - 1 ;
std : : nth_element ( & Dist [ 0 ] , & Dist [ VANILLA_MAX_CLIENTS - 1 ] , & Dist [ MAX_CLIENTS ] , DistCompare ) ;
int Index = 1 ; // exclude self client id
for ( int j = 0 ; j < VANILLA_MAX_CLIENTS - 1 ; j + + )
{
pMap [ j + 1 ] = - 1 ; // also fill player with empty name to say chat msgs
if ( Dist [ j ] . second = = i | | Dist [ j ] . first > 5e9 f )
continue ;
pMap [ Index + + ] = Dist [ j ] . second ;
}
// sort by real client ids, guarantee order on distance changes, O(Nlog(N)) worst case
// sort just clients in game always except first (self client id) and last (fake client id) indexes
std : : sort ( & pMap [ 1 ] , & pMap [ minimum ( Index , VANILLA_MAX_CLIENTS - 1 ) ] ) ;
}
}
2021-02-08 21:26:26 +00:00
bool CGameContext : : IsClientReady ( int ClientID ) const
2011-03-15 08:58:57 +00:00
{
2022-01-22 16:34:23 +00:00
return m_apPlayers [ ClientID ] & & m_apPlayers [ ClientID ] - > m_IsReady ;
2011-03-15 08:58:57 +00:00
}
2021-02-08 21:26:26 +00:00
bool CGameContext : : IsClientPlayer ( int ClientID ) const
2011-03-20 14:33:49 +00:00
{
2021-02-07 15:03:31 +00:00
return m_apPlayers [ ClientID ] & & m_apPlayers [ ClientID ] - > GetTeam ( ) ! = TEAM_SPECTATORS ;
2011-03-20 14:33:49 +00:00
}
2021-02-08 21:26:26 +00:00
CUuid CGameContext : : GameUuid ( ) const { return m_GameUuid ; }
const char * CGameContext : : GameType ( ) const { return m_pController & & m_pController - > m_pGameType ? m_pController - > m_pGameType : " " ; }
const char * CGameContext : : Version ( ) const { return GAME_VERSION ; }
const char * CGameContext : : NetVersion ( ) const { return GAME_NETVERSION ; }
2010-05-29 07:25:38 +00:00
IGameServer * CreateGameServer ( ) { return new CGameContext ; }
2010-09-17 09:34:13 +00:00
2011-02-13 05:35:13 +00:00
void CGameContext : : OnSetAuthed ( int ClientID , int Level )
2011-01-29 00:59:50 +00:00
{
2011-02-13 05:35:13 +00:00
if ( m_apPlayers [ ClientID ] )
2011-01-29 00:59:50 +00:00
{
2011-08-13 00:11:06 +00:00
char aBuf [ 512 ] , aIP [ NETADDR_MAXSTRSIZE ] ;
2017-06-06 03:51:12 +00:00
Server ( ) - > GetClientAddr ( ClientID , aIP , sizeof ( aIP ) ) ;
2011-07-20 00:41:11 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " ban %s %d Banned by vote " , aIP , g_Config . m_SvVoteKickBantime ) ;
2019-02-08 18:43:07 +00:00
if ( ! str_comp_nocase ( m_aVoteCommand , aBuf ) & & Level > Server ( ) - > GetAuthedState ( m_VoteCreator ) )
2011-01-29 00:59:50 +00:00
{
2011-12-26 09:15:43 +00:00
m_VoteEnforce = CGameContext : : VOTE_ENFORCE_NO_ADMIN ;
2019-02-27 18:46:01 +00:00
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " CGameContext " , " Vote aborted by authorized login. " ) ;
2011-01-29 00:59:50 +00:00
}
}
2018-01-28 02:13:05 +00:00
if ( m_TeeHistorianActive )
{
if ( Level )
{
m_TeeHistorian . RecordAuthLogin ( ClientID , Level , Server ( ) - > GetAuthName ( ClientID ) ) ;
}
else
{
m_TeeHistorian . RecordAuthLogout ( ClientID ) ;
}
}
2011-01-29 00:59:50 +00:00
}
2011-02-27 08:07:57 +00:00
void CGameContext : : SendRecord ( int ClientID )
{
2021-02-24 22:40:11 +00:00
CNetMsg_Sv_Record Msg ;
CNetMsg_Sv_RecordLegacy MsgLegacy ;
MsgLegacy . m_PlayerTimeBest = Msg . m_PlayerTimeBest = Score ( ) - > PlayerData ( ClientID ) - > m_BestTime * 100.0f ;
MsgLegacy . m_ServerTimeBest = Msg . m_ServerTimeBest = m_pController - > m_CurrentRecord * 100.0f ; //TODO: finish this
Server ( ) - > SendPackMsg ( & Msg , MSGFLAG_VITAL , ClientID ) ;
if ( ! Server ( ) - > IsSixup ( ClientID ) & & GetClientVersion ( ClientID ) < VERSION_DDNET_MSG_LEGACY )
{
Server ( ) - > SendPackMsg ( & MsgLegacy , MSGFLAG_VITAL , ClientID ) ;
}
2011-02-23 07:43:05 +00:00
}
2011-02-27 08:07:57 +00:00
2022-12-12 22:32:45 +00:00
bool CGameContext : : ProcessSpamProtection ( int ClientID , bool RespectChatInitialDelay )
2011-02-27 08:07:57 +00:00
{
2011-09-07 23:02:09 +00:00
if ( ! m_apPlayers [ ClientID ] )
2022-12-12 22:32:45 +00:00
return false ;
2020-09-26 19:41:58 +00:00
if ( g_Config . m_SvSpamprotection & & m_apPlayers [ ClientID ] - > m_LastChat & & m_apPlayers [ ClientID ] - > m_LastChat + Server ( ) - > TickSpeed ( ) * g_Config . m_SvChatDelay > Server ( ) - > Tick ( ) )
2022-12-12 22:32:45 +00:00
return true ;
2021-03-01 18:54:18 +00:00
else if ( g_Config . m_SvDnsblChat & & Server ( ) - > DnsblBlack ( ClientID ) )
{
SendChatTarget ( ClientID , " Players are not allowed to chat from VPNs at this time " ) ;
2022-12-12 22:32:45 +00:00
return true ;
2021-03-01 18:54:18 +00:00
}
2011-02-27 08:07:57 +00:00
else
2011-04-09 06:41:31 +00:00
m_apPlayers [ ClientID ] - > m_LastChat = Server ( ) - > Tick ( ) ;
2021-03-01 18:54:18 +00:00
2011-02-27 08:07:57 +00:00
NETADDR Addr ;
Server ( ) - > GetClientAddr ( ClientID , & Addr ) ;
2023-09-22 10:43:36 +00:00
CMute Muted ;
int Expires = 0 ;
for ( int i = 0 ; i < m_NumMutes & & Expires < = 0 ; i + + )
2011-02-27 08:07:57 +00:00
{
2021-12-18 10:19:35 +00:00
if ( ! net_addr_comp_noport ( & Addr , & m_aMutes [ i ] . m_Addr ) )
2021-03-01 18:44:59 +00:00
{
2021-12-18 10:19:35 +00:00
if ( RespectChatInitialDelay | | m_aMutes [ i ] . m_InitialChatDelay )
2023-09-22 10:43:36 +00:00
{
Muted = m_aMutes [ i ] ;
Expires = ( m_aMutes [ i ] . m_Expire - Server ( ) - > Tick ( ) ) / Server ( ) - > TickSpeed ( ) ;
}
2021-03-01 18:44:59 +00:00
}
2011-02-27 08:07:57 +00:00
}
2023-09-22 10:43:36 +00:00
if ( Expires > 0 )
2011-02-27 08:07:57 +00:00
{
char aBuf [ 128 ] ;
2023-09-22 10:43:36 +00:00
if ( Muted . m_InitialChatDelay )
2023-11-19 21:36:47 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " This server has an initial chat delay, you will be able to talk in %d seconds. " , Expires ) ;
2023-09-22 10:43:36 +00:00
else
2023-11-19 21:36:47 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " You are not permitted to talk for the next %d seconds. " , Expires ) ;
2011-02-27 08:07:57 +00:00
SendChatTarget ( ClientID , aBuf ) ;
2022-12-12 22:32:45 +00:00
return true ;
2011-02-27 08:07:57 +00:00
}
2022-03-20 13:12:19 +00:00
if ( g_Config . m_SvSpamMuteDuration & & ( m_apPlayers [ ClientID ] - > m_ChatScore + = g_Config . m_SvChatPenalty ) > g_Config . m_SvChatThreshold )
2011-02-27 08:07:57 +00:00
{
2018-10-08 18:29:33 +00:00
Mute ( & Addr , g_Config . m_SvSpamMuteDuration , Server ( ) - > ClientName ( ClientID ) ) ;
2011-02-27 08:07:57 +00:00
m_apPlayers [ ClientID ] - > m_ChatScore = 0 ;
2022-12-12 22:32:45 +00:00
return true ;
2011-02-27 08:07:57 +00:00
}
2022-12-12 22:32:45 +00:00
return false ;
2011-02-27 08:07:57 +00:00
}
2011-04-19 19:44:02 +00:00
int CGameContext : : GetDDRaceTeam ( int ClientID )
{
2023-11-15 20:28:19 +00:00
return m_pController - > Teams ( ) . m_Core . Team ( ClientID ) ;
2011-04-19 19:44:02 +00:00
}
2011-05-30 20:05:28 +00:00
void CGameContext : : ResetTuning ( )
{
CTuningParams TuningParams ;
m_Tuning = TuningParams ;
Tuning ( ) - > Set ( " gun_speed " , 1400 ) ;
Tuning ( ) - > Set ( " gun_curvature " , 0 ) ;
Tuning ( ) - > Set ( " shotgun_speed " , 500 ) ;
Tuning ( ) - > Set ( " shotgun_speeddiff " , 0 ) ;
Tuning ( ) - > Set ( " shotgun_curvature " , 0 ) ;
SendTuningParams ( - 1 ) ;
}
2013-08-09 13:04:20 +00:00
bool CheckClientID2 ( int ClientID )
{
2022-01-22 16:34:23 +00:00
return ClientID > = 0 & & ClientID < MAX_CLIENTS ;
2013-08-09 13:04:20 +00:00
}
void CGameContext : : Whisper ( int ClientID , char * pStr )
{
2013-08-10 01:40:59 +00:00
if ( ProcessSpamProtection ( ClientID ) )
return ;
2013-08-09 13:04:20 +00:00
pStr = str_skip_whitespaces ( pStr ) ;
2022-12-12 22:25:55 +00:00
char * pName ;
2013-08-12 21:02:39 +00:00
int Victim ;
2022-12-12 22:32:45 +00:00
bool Error = false ;
2013-08-12 21:02:39 +00:00
2013-08-09 13:04:20 +00:00
// add token
if ( * pStr = = ' " ' )
{
pStr + + ;
2020-04-28 06:54:24 +00:00
pName = pStr ;
char * pDst = pStr ; // we might have to process escape data
2022-02-14 23:12:52 +00:00
while ( true )
2013-08-09 13:04:20 +00:00
{
if ( pStr [ 0 ] = = ' " ' )
2021-11-27 19:55:55 +00:00
{
2013-08-09 13:04:20 +00:00
break ;
2021-11-27 19:55:55 +00:00
}
2013-08-09 13:04:20 +00:00
else if ( pStr [ 0 ] = = ' \\ ' )
{
if ( pStr [ 1 ] = = ' \\ ' )
pStr + + ; // skip due to escape
else if ( pStr [ 1 ] = = ' " ' )
pStr + + ; // skip due to escape
}
else if ( pStr [ 0 ] = = 0 )
2021-11-27 19:55:55 +00:00
{
2022-12-12 22:32:45 +00:00
Error = true ;
2021-11-27 19:55:55 +00:00
break ;
}
2013-08-09 13:04:20 +00:00
2020-04-28 06:54:24 +00:00
* pDst = * pStr ;
pDst + + ;
2013-08-09 13:04:20 +00:00
pStr + + ;
}
2021-11-27 19:55:55 +00:00
if ( ! Error )
{
// write null termination
* pDst = 0 ;
2020-04-28 06:54:24 +00:00
2021-11-27 19:55:55 +00:00
pStr + + ;
2013-08-12 21:02:39 +00:00
2021-11-27 19:55:55 +00:00
for ( Victim = 0 ; Victim < MAX_CLIENTS ; Victim + + )
if ( str_comp ( pName , Server ( ) - > ClientName ( Victim ) ) = = 0 )
break ;
}
2013-08-09 13:04:20 +00:00
}
else
{
pName = pStr ;
2022-02-14 23:12:52 +00:00
while ( true )
2013-08-09 13:04:20 +00:00
{
2013-08-10 02:30:59 +00:00
if ( pStr [ 0 ] = = 0 )
{
2022-12-12 22:32:45 +00:00
Error = true ;
2013-08-10 02:30:59 +00:00
break ;
}
2013-08-09 13:04:20 +00:00
if ( pStr [ 0 ] = = ' ' )
{
2013-08-12 21:02:39 +00:00
pStr [ 0 ] = 0 ;
for ( Victim = 0 ; Victim < MAX_CLIENTS ; Victim + + )
2020-09-26 19:41:58 +00:00
if ( str_comp ( pName , Server ( ) - > ClientName ( Victim ) ) = = 0 )
2013-08-12 21:02:39 +00:00
break ;
pStr [ 0 ] = ' ' ;
2020-09-26 19:41:58 +00:00
if ( Victim < MAX_CLIENTS )
2013-08-12 21:02:39 +00:00
break ;
2013-08-09 13:04:20 +00:00
}
pStr + + ;
}
}
if ( pStr [ 0 ] ! = ' ' )
{
2022-12-12 22:32:45 +00:00
Error = true ;
2013-08-09 13:04:20 +00:00
}
* pStr = 0 ;
pStr + + ;
2020-09-26 19:41:58 +00:00
if ( Error )
2013-08-09 13:04:20 +00:00
{
2023-01-28 12:40:21 +00:00
SendChatTarget ( ClientID , " Invalid whisper " ) ;
2013-08-09 13:04:20 +00:00
return ;
}
2020-09-26 19:41:58 +00:00
if ( Victim > = MAX_CLIENTS | | ! CheckClientID2 ( Victim ) )
2013-08-09 13:04:20 +00:00
{
2023-01-28 12:40:21 +00:00
char aBuf [ 256 ] ;
2013-08-09 13:04:20 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " No player with name \" %s \" found " , pName ) ;
SendChatTarget ( ClientID , aBuf ) ;
return ;
}
2023-01-28 12:40:21 +00:00
WhisperID ( ClientID , Victim , pStr ) ;
2013-10-18 09:42:35 +00:00
}
2020-06-12 13:14:56 +00:00
void CGameContext : : WhisperID ( int ClientID , int VictimID , const char * pMessage )
2013-10-18 09:42:35 +00:00
{
2020-05-22 15:58:41 +00:00
if ( ! CheckClientID2 ( ClientID ) )
2013-10-18 09:42:35 +00:00
return ;
2020-05-22 15:58:41 +00:00
if ( ! CheckClientID2 ( VictimID ) )
2013-10-18 09:42:35 +00:00
return ;
2020-05-22 15:58:41 +00:00
if ( m_apPlayers [ ClientID ] )
2014-05-18 23:57:52 +00:00
m_apPlayers [ ClientID ] - > m_LastWhisperTo = VictimID ;
2013-10-18 09:42:35 +00:00
2020-09-18 15:37:27 +00:00
char aCensoredMessage [ 256 ] ;
CensorMessage ( aCensoredMessage , pMessage , sizeof ( aCensoredMessage ) ) ;
2013-10-18 09:42:35 +00:00
char aBuf [ 256 ] ;
2020-06-12 13:14:56 +00:00
if ( Server ( ) - > IsSixup ( ClientID ) )
{
protocol7 : : CNetMsg_Sv_Chat Msg ;
Msg . m_ClientID = ClientID ;
Msg . m_Mode = protocol7 : : CHAT_WHISPER ;
2020-09-18 15:37:27 +00:00
Msg . m_pMessage = aCensoredMessage ;
2020-06-12 13:14:56 +00:00
Msg . m_TargetID = VictimID ;
2020-09-26 19:41:58 +00:00
Server ( ) - > SendPackMsg ( & Msg , MSGFLAG_VITAL | MSGFLAG_NORECORD , ClientID ) ;
2020-06-12 13:14:56 +00:00
}
else if ( GetClientVersion ( ClientID ) > = VERSION_DDNET_WHISPER )
2014-01-30 15:49:15 +00:00
{
CNetMsg_Sv_Chat Msg ;
Msg . m_Team = CHAT_WHISPER_SEND ;
Msg . m_ClientID = VictimID ;
2020-09-18 15:37:27 +00:00
Msg . m_pMessage = aCensoredMessage ;
2014-09-26 00:40:58 +00:00
if ( g_Config . m_SvDemoChat )
Server ( ) - > SendPackMsg ( & Msg , MSGFLAG_VITAL , ClientID ) ;
else
2020-09-26 19:41:58 +00:00
Server ( ) - > SendPackMsg ( & Msg , MSGFLAG_VITAL | MSGFLAG_NORECORD , ClientID ) ;
2014-09-26 00:40:58 +00:00
}
else
2014-01-30 15:49:15 +00:00
{
2020-09-18 15:37:27 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " [→ %s] %s " , Server ( ) - > ClientName ( VictimID ) , aCensoredMessage ) ;
2014-01-30 15:49:15 +00:00
SendChatTarget ( ClientID , aBuf ) ;
}
2013-08-09 13:04:20 +00:00
2020-06-12 13:14:56 +00:00
if ( Server ( ) - > IsSixup ( VictimID ) )
{
protocol7 : : CNetMsg_Sv_Chat Msg ;
Msg . m_ClientID = ClientID ;
Msg . m_Mode = protocol7 : : CHAT_WHISPER ;
2020-09-18 15:37:27 +00:00
Msg . m_pMessage = aCensoredMessage ;
2020-06-12 13:14:56 +00:00
Msg . m_TargetID = VictimID ;
2020-09-26 19:41:58 +00:00
Server ( ) - > SendPackMsg ( & Msg , MSGFLAG_VITAL | MSGFLAG_NORECORD , VictimID ) ;
2020-06-12 13:14:56 +00:00
}
else if ( GetClientVersion ( VictimID ) > = VERSION_DDNET_WHISPER )
2014-01-30 15:49:15 +00:00
{
CNetMsg_Sv_Chat Msg2 ;
Msg2 . m_Team = CHAT_WHISPER_RECV ;
Msg2 . m_ClientID = ClientID ;
2020-09-18 15:37:27 +00:00
Msg2 . m_pMessage = aCensoredMessage ;
2014-09-26 00:40:58 +00:00
if ( g_Config . m_SvDemoChat )
Server ( ) - > SendPackMsg ( & Msg2 , MSGFLAG_VITAL , VictimID ) ;
else
2020-09-26 19:41:58 +00:00
Server ( ) - > SendPackMsg ( & Msg2 , MSGFLAG_VITAL | MSGFLAG_NORECORD , VictimID ) ;
2014-09-26 00:40:58 +00:00
}
else
2014-01-30 15:49:15 +00:00
{
2020-09-18 15:37:27 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " [← %s] %s " , Server ( ) - > ClientName ( ClientID ) , aCensoredMessage ) ;
2014-01-30 15:49:15 +00:00
SendChatTarget ( VictimID , aBuf ) ;
}
2013-08-09 13:04:20 +00:00
}
2013-10-18 09:42:35 +00:00
void CGameContext : : Converse ( int ClientID , char * pStr )
{
CPlayer * pPlayer = m_apPlayers [ ClientID ] ;
2020-09-26 19:41:58 +00:00
if ( ! pPlayer )
2013-10-18 09:42:35 +00:00
return ;
2014-04-23 22:43:49 +00:00
if ( ProcessSpamProtection ( ClientID ) )
return ;
2020-09-26 19:41:58 +00:00
if ( pPlayer - > m_LastWhisperTo < 0 )
2013-10-18 09:42:35 +00:00
SendChatTarget ( ClientID , " You do not have an ongoing conversation. Whisper to someone to start one " ) ;
else
{
WhisperID ( ClientID , pPlayer - > m_LastWhisperTo , pStr ) ;
}
}
2019-02-04 19:46:42 +00:00
2019-02-11 17:52:40 +00:00
bool CGameContext : : IsVersionBanned ( int Version )
2019-02-04 19:46:42 +00:00
{
char aVersion [ 16 ] ;
2023-08-20 11:03:01 +00:00
str_from_int ( Version , aVersion ) ;
2019-02-04 19:46:42 +00:00
2019-02-11 17:52:40 +00:00
return str_in_list ( g_Config . m_SvBannedVersions , " , " , aVersion ) ;
2019-02-04 19:46:42 +00:00
}
2013-12-31 05:13:57 +00:00
2017-03-21 10:24:44 +00:00
void CGameContext : : List ( int ClientID , const char * pFilter )
2013-12-31 05:13:57 +00:00
{
2017-03-21 10:24:44 +00:00
int Total = 0 ;
char aBuf [ 256 ] ;
int Bufcnt = 0 ;
2020-09-26 19:41:58 +00:00
if ( pFilter [ 0 ] )
2017-03-21 10:24:44 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " Listing players with \" %s \" in name: " , pFilter ) ;
2013-12-31 05:13:57 +00:00
else
2023-01-28 13:18:02 +00:00
str_copy ( aBuf , " Listing all players: " ) ;
2017-03-21 10:24:44 +00:00
SendChatTarget ( ClientID , aBuf ) ;
2013-12-31 05:13:57 +00:00
for ( int i = 0 ; i < MAX_CLIENTS ; i + + )
{
if ( m_apPlayers [ i ] )
{
2017-03-21 10:24:44 +00:00
Total + + ;
const char * pName = Server ( ) - > ClientName ( i ) ;
2021-06-28 20:51:14 +00:00
if ( str_utf8_find_nocase ( pName , pFilter ) = = NULL )
2013-12-31 05:13:57 +00:00
continue ;
2020-09-26 19:41:58 +00:00
if ( Bufcnt + str_length ( pName ) + 4 > 256 )
2013-12-31 05:13:57 +00:00
{
2017-03-21 10:24:44 +00:00
SendChatTarget ( ClientID , aBuf ) ;
Bufcnt = 0 ;
2013-12-31 05:13:57 +00:00
}
2020-09-26 19:41:58 +00:00
if ( Bufcnt ! = 0 )
2013-12-31 05:13:57 +00:00
{
2017-03-21 10:24:44 +00:00
str_format ( & aBuf [ Bufcnt ] , sizeof ( aBuf ) - Bufcnt , " , %s " , pName ) ;
Bufcnt + = 2 + str_length ( pName ) ;
2013-12-31 05:13:57 +00:00
}
else
{
2022-10-27 19:28:49 +00:00
str_copy ( & aBuf [ Bufcnt ] , pName , sizeof ( aBuf ) - Bufcnt ) ;
2017-03-21 10:24:44 +00:00
Bufcnt + = str_length ( pName ) ;
2013-12-31 05:13:57 +00:00
}
}
}
2020-09-26 19:41:58 +00:00
if ( Bufcnt ! = 0 )
2017-03-21 10:24:44 +00:00
SendChatTarget ( ClientID , aBuf ) ;
str_format ( aBuf , sizeof ( aBuf ) , " %d players online " , Total ) ;
SendChatTarget ( ClientID , aBuf ) ;
2013-12-31 05:13:57 +00:00
}
2017-06-06 05:31:56 +00:00
2021-02-08 21:26:26 +00:00
int CGameContext : : GetClientVersion ( int ClientID ) const
2019-12-21 13:35:09 +00:00
{
2022-07-30 08:57:46 +00:00
return Server ( ) - > GetClientVersion ( ClientID ) ;
2017-06-06 05:31:56 +00:00
}
2018-01-05 11:04:06 +00:00
2023-01-24 08:27:29 +00:00
CClientMask CGameContext : : ClientsMaskExcludeClientVersionAndHigher ( int Version )
2022-06-25 09:16:59 +00:00
{
2023-01-24 08:27:29 +00:00
CClientMask Mask ;
2022-06-25 09:16:59 +00:00
for ( int i = 0 ; i < MAX_CLIENTS ; + + i )
{
if ( GetClientVersion ( i ) > = Version )
continue ;
2023-01-24 08:27:29 +00:00
Mask . set ( i ) ;
2022-06-25 09:16:59 +00:00
}
return Mask ;
}
2021-02-08 21:26:26 +00:00
bool CGameContext : : PlayerModerating ( ) const
2018-01-05 11:04:06 +00:00
{
2022-01-23 17:56:37 +00:00
return std : : any_of ( std : : begin ( m_apPlayers ) , std : : end ( m_apPlayers ) , [ ] ( const CPlayer * pPlayer ) { return pPlayer & & pPlayer - > m_Moderating ; } ) ;
2018-01-05 11:04:06 +00:00
}
2018-01-18 15:17:23 +00:00
void CGameContext : : ForceVote ( int EnforcerID , bool Success )
{
// check if there is a vote running
2018-01-25 18:33:40 +00:00
if ( ! m_VoteCloseTime )
2018-01-18 15:17:23 +00:00
return ;
2018-10-07 22:59:07 +00:00
2018-01-18 15:17:23 +00:00
m_VoteEnforce = Success ? CGameContext : : VOTE_ENFORCE_YES_ADMIN : CGameContext : : VOTE_ENFORCE_NO_ADMIN ;
m_VoteEnforcer = EnforcerID ;
2018-10-07 22:59:07 +00:00
2018-01-18 15:17:23 +00:00
char aBuf [ 256 ] ;
2018-01-18 17:41:37 +00:00
const char * pOption = Success ? " yes " : " no " ;
2018-04-07 14:51:17 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " authorized player forced vote %s " , pOption ) ;
2018-01-18 15:17:23 +00:00
SendChatTarget ( - 1 , aBuf ) ;
2018-01-18 17:30:38 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " forcing vote %s " , pOption ) ;
2018-01-18 15:17:23 +00:00
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_STANDARD , " server " , aBuf ) ;
}
2020-06-14 08:44:14 +00:00
bool CGameContext : : RateLimitPlayerVote ( int ClientID )
{
2021-06-23 05:05:49 +00:00
int64_t Now = Server ( ) - > Tick ( ) ;
int64_t TickSpeed = Server ( ) - > TickSpeed ( ) ;
2020-06-14 08:44:14 +00:00
CPlayer * pPlayer = m_apPlayers [ ClientID ] ;
if ( g_Config . m_SvRconVote & & ! Server ( ) - > GetAuthedState ( ClientID ) )
{
SendChatTarget ( ClientID , " You can only vote after logging in. " ) ;
return true ;
}
2020-07-07 21:08:46 +00:00
if ( g_Config . m_SvDnsblVote & & Server ( ) - > DistinctClientCount ( ) > 1 )
2020-06-14 08:44:14 +00:00
{
2020-07-07 21:08:46 +00:00
if ( m_pServer - > DnsblPending ( ClientID ) )
{
2020-07-08 20:02:36 +00:00
SendChatTarget ( ClientID , " You are not allowed to vote because we're currently checking for VPNs. Try again in ~30 seconds. " ) ;
2020-07-07 21:08:46 +00:00
return true ;
}
else if ( m_pServer - > DnsblBlack ( ClientID ) )
{
2020-07-08 20:02:31 +00:00
SendChatTarget ( ClientID , " You are not allowed to vote because you appear to be using a VPN. Try connecting without a VPN or contacting an admin if you think this is a mistake. " ) ;
2020-07-07 21:08:46 +00:00
return true ;
}
2020-06-14 08:44:14 +00:00
}
if ( g_Config . m_SvSpamprotection & & pPlayer - > m_LastVoteTry & & pPlayer - > m_LastVoteTry + TickSpeed * 3 > Now )
return true ;
pPlayer - > m_LastVoteTry = Now ;
if ( m_VoteCloseTime )
{
SendChatTarget ( ClientID , " Wait for current vote to end before calling a new one. " ) ;
return true ;
}
if ( Now < pPlayer - > m_FirstVoteTick )
{
char aBuf [ 64 ] ;
str_format ( aBuf , sizeof ( aBuf ) , " You must wait %d seconds before making your first vote. " , ( int ) ( ( pPlayer - > m_FirstVoteTick - Now ) / TickSpeed ) + 1 ) ;
SendChatTarget ( ClientID , aBuf ) ;
return true ;
}
int TimeLeft = pPlayer - > m_LastVoteCall + TickSpeed * g_Config . m_SvVoteDelay - Now ;
if ( pPlayer - > m_LastVoteCall & & TimeLeft > 0 )
{
char aChatmsg [ 64 ] ;
str_format ( aChatmsg , sizeof ( aChatmsg ) , " You must wait %d seconds before making another vote. " , ( int ) ( TimeLeft / TickSpeed ) + 1 ) ;
SendChatTarget ( ClientID , aChatmsg ) ;
return true ;
}
NETADDR Addr ;
Server ( ) - > GetClientAddr ( ClientID , & Addr ) ;
int VoteMuted = 0 ;
for ( int i = 0 ; i < m_NumVoteMutes & & ! VoteMuted ; i + + )
if ( ! net_addr_comp_noport ( & Addr , & m_aVoteMutes [ i ] . m_Addr ) )
VoteMuted = ( m_aVoteMutes [ i ] . m_Expire - Server ( ) - > Tick ( ) ) / Server ( ) - > TickSpeed ( ) ;
2021-06-22 20:45:30 +00:00
for ( int i = 0 ; i < m_NumMutes & & VoteMuted = = 0 ; i + + )
{
if ( ! net_addr_comp_noport ( & Addr , & m_aMutes [ i ] . m_Addr ) )
VoteMuted = ( m_aMutes [ i ] . m_Expire - Server ( ) - > Tick ( ) ) / Server ( ) - > TickSpeed ( ) ;
}
2020-06-14 08:44:14 +00:00
if ( VoteMuted > 0 )
{
char aChatmsg [ 64 ] ;
str_format ( aChatmsg , sizeof ( aChatmsg ) , " You are not permitted to vote for the next %d seconds. " , VoteMuted ) ;
SendChatTarget ( ClientID , aChatmsg ) ;
return true ;
}
return false ;
}
bool CGameContext : : RateLimitPlayerMapVote ( int ClientID )
{
if ( ! Server ( ) - > GetAuthedState ( ClientID ) & & time_get ( ) < m_LastMapVote + ( time_freq ( ) * g_Config . m_SvVoteMapTimeDelay ) )
{
char aChatmsg [ 512 ] = { 0 } ;
str_format ( aChatmsg , sizeof ( aChatmsg ) , " There's a %d second delay between map-votes, please wait %d seconds. " ,
2020-09-26 19:41:58 +00:00
g_Config . m_SvVoteMapTimeDelay , ( int ) ( ( m_LastMapVote + g_Config . m_SvVoteMapTimeDelay * time_freq ( ) - time_get ( ) ) / time_freq ( ) ) ) ;
2020-06-14 08:44:14 +00:00
SendChatTarget ( ClientID , aChatmsg ) ;
return true ;
}
return false ;
}
2022-11-14 07:04:34 +00:00
void CGameContext : : OnUpdatePlayerServerInfo ( char * aBuf , int BufSize , int ID )
{
2023-03-05 14:18:08 +00:00
if ( BufSize < = 0 )
return ;
aBuf [ 0 ] = ' \0 ' ;
2022-11-14 07:04:34 +00:00
if ( ! m_apPlayers [ ID ] )
return ;
char aCSkinName [ 64 ] ;
CTeeInfo & TeeInfo = m_apPlayers [ ID ] - > m_TeeInfos ;
char aJsonSkin [ 400 ] ;
aJsonSkin [ 0 ] = ' \0 ' ;
if ( ! Server ( ) - > IsSixup ( ID ) )
{
// 0.6
if ( TeeInfo . m_UseCustomColor )
{
str_format ( aJsonSkin , sizeof ( aJsonSkin ) ,
" \" name \" : \" %s \" , "
" \" color_body \" :%d, "
" \" color_feet \" :%d " ,
EscapeJson ( aCSkinName , sizeof ( aCSkinName ) , TeeInfo . m_aSkinName ) ,
TeeInfo . m_ColorBody ,
TeeInfo . m_ColorFeet ) ;
}
else
{
str_format ( aJsonSkin , sizeof ( aJsonSkin ) ,
" \" name \" : \" %s \" " ,
EscapeJson ( aCSkinName , sizeof ( aCSkinName ) , TeeInfo . m_aSkinName ) ) ;
}
}
else
{
const char * apPartNames [ protocol7 : : NUM_SKINPARTS ] = { " body " , " marking " , " decoration " , " hands " , " feet " , " eyes " } ;
char aPartBuf [ 64 ] ;
for ( int i = 0 ; i < protocol7 : : NUM_SKINPARTS ; + + i )
{
str_format ( aPartBuf , sizeof ( aPartBuf ) ,
" %s \" %s \" :{ "
" \" name \" : \" %s \" " ,
i = = 0 ? " " : " , " ,
apPartNames [ i ] ,
EscapeJson ( aCSkinName , sizeof ( aCSkinName ) , TeeInfo . m_apSkinPartNames [ i ] ) ) ;
2023-06-13 19:06:48 +00:00
str_append ( aJsonSkin , aPartBuf ) ;
2022-11-14 07:04:34 +00:00
if ( TeeInfo . m_aUseCustomColors [ i ] )
{
str_format ( aPartBuf , sizeof ( aPartBuf ) ,
2023-03-05 14:35:41 +00:00
" , \" color \" :%d " ,
2022-11-14 07:04:34 +00:00
TeeInfo . m_aSkinPartColors [ i ] ) ;
2023-06-13 19:06:48 +00:00
str_append ( aJsonSkin , aPartBuf ) ;
2022-11-14 07:04:34 +00:00
}
2023-06-13 19:06:48 +00:00
str_append ( aJsonSkin , " } " ) ;
2022-11-14 07:04:34 +00:00
}
}
str_format ( aBuf , BufSize ,
" , \" skin \" :{ "
" %s "
" }, "
" \" afk \" :%s, "
" \" team \" :%d " ,
aJsonSkin ,
2022-12-22 23:06:29 +00:00
JsonBool ( m_apPlayers [ ID ] - > IsAfk ( ) ) ,
2022-11-14 07:04:34 +00:00
m_apPlayers [ ID ] - > GetTeam ( ) ) ;
}