Exemple #1
0
/*
==================
Svcmd_KickNum_f

Kick a user off of the server
==================
*/
static void Svcmd_KickNum_f( void ) {
	gclient_t   *cl;
	int timeout = -1;
	const char    *ip;
	char userinfo[MAX_INFO_STRING];
	char sTimeout[MAX_TOKEN_CHARS];
	char name[MAX_TOKEN_CHARS];
	int clientNum;

	// make sure server is running
	if ( !G_Is_SV_Running() ) {
		G_Printf( "Server is not running.\n" );
		return;
	}

	if ( trap_Argc() < 2 || trap_Argc() > 3 ) {
		G_Printf( "Usage: kick <client number> [timeout]\n" );
		return;
	}

	if ( trap_Argc() == 3 ) {
		trap_Argv( 2, sTimeout, sizeof( sTimeout ) );
		timeout = atoi( sTimeout );
	} else {
		timeout = 300;
	}

	trap_Argv( 1, name, sizeof( name ) );
	clientNum = atoi( name );

	cl = G_GetPlayerByNum( clientNum );
	if ( !cl ) {
		return;
	}
	if ( cl->pers.localClient ) {
		G_Printf( "Cannot kick host player\n" );
		return;
	}

	trap_GetUserinfo( cl->ps.clientNum, userinfo, sizeof( userinfo ) );
	ip = Info_ValueForKey( userinfo, "ip" );
	// use engine banning system, mods may choose to use their own banlist
	if ( USE_ENGINE_BANLIST ) {

		// kick but dont ban bots, they arent that lame
		if ( ( g_entities[cl->ps.clientNum].r.svFlags & SVF_BOT ) ) {
			timeout = 0;
		}
		trap_DropClient( cl->ps.clientNum, "player kicked", timeout );
	} else {
		trap_DropClient( cl->ps.clientNum, "player kicked", 0 );

		// kick but dont ban bots, they arent that lame
		if ( !( g_entities[cl->ps.clientNum].r.svFlags & SVF_BOT ) ) {
			AddIPBan( ip );
		}
	}
}
Exemple #2
0
/*
* TVM_ClientUserInfoChanged
* 
* called whenever the player updates a userinfo variable.
* 
* The game can override any of the settings in place
* (forcing skins or names, etc) before copying it off.
*/
void TVM_ClientUserinfoChanged( tvm_relay_t *relay, edict_t *ent, char *userinfo )
{
	gclient_t *cl;
	char *s;

	assert( ent && ent->local && ent->r.client );

	cl = ent->r.client;

	// check for malformed or illegal info strings
	if( !Info_Validate( userinfo ) )
	{
		trap_DropClient( relay, PLAYERNUM( ent ), DROP_TYPE_GENERAL, "Error: Invalid userinfo" );
		return;
	}

	if( !Info_ValueForKey( userinfo, "name" ) )
	{
		trap_DropClient( relay, PLAYERNUM( ent ), DROP_TYPE_GENERAL, "Error: No name set" );
		return;
	}

	// set name, it's validated and possibly changed first
	Q_strncpyz( cl->pers.netname, Info_ValueForKey( userinfo, "name" ), sizeof( cl->pers.netname ) );

	// fov
	s = Info_ValueForKey( userinfo, "fov" );
	if( !s )
	{
		cl->pers.fov = 100;
	}
	else
	{
		cl->pers.fov = atoi( s );
		clamp( cl->pers.fov, 1, 140 );
	}

	s = Info_ValueForKey( userinfo, "zoomfov" );
	if( !s )
	{
		cl->pers.zoomfov = 30;
	}
	else
	{
		cl->pers.zoomfov = atoi( s );
		clamp( cl->pers.zoomfov, 1, 60 );
	}

	// save off the userinfo in case we want to check something later
	Q_strncpyz( cl->pers.userinfo, userinfo, sizeof( cl->pers.userinfo ) );
}
Exemple #3
0
static void Svcmd_EjectClient_f( void )
{
	char *reason, name[ MAX_STRING_CHARS ];

	if ( trap_Argc() < 2 )
	{
		G_Printf( "usage: eject <player|-1> <reason>\n" );
		return;
	}

	trap_Argv( 1, name, sizeof( name ) );
	reason = ConcatArgs( 2 );

	if ( atoi( name ) == -1 )
	{
		int i;

		for ( i = 0; i < level.maxclients; i++ )
		{
			if ( level.clients[ i ].pers.connected == CON_DISCONNECTED )
			{
				continue;
			}

			if ( level.clients[ i ].pers.localClient )
			{
				continue;
			}

			trap_DropClient( i, reason, 0 );
		}
	}
	else
	{
		gclient_t *cl = ClientForString( name );

		if ( !cl )
		{
			return;
		}

		if ( cl->pers.localClient )
		{
			G_Printf( "eject: cannot eject local clients\n" );
			return;
		}

		trap_DropClient( cl - level.clients, reason, 0 );
	}
}
Exemple #4
0
/*
===============
G_BotConnect
===============
*/
qboolean G_BotConnect( int clientNum, qboolean restart ) {
	bot_settings_t	settings;
	char			userinfo[MAX_INFO_STRING];

	trap_GetUserinfo( clientNum, userinfo, sizeof(userinfo) );

	Q_strncpyz( settings.characterfile, Info_ValueForKey( userinfo, "characterfile" ), sizeof(settings.characterfile) );
	settings.skill = atoi( Info_ValueForKey( userinfo, "skill" ) );
	Q_strncpyz( settings.team, Info_ValueForKey( userinfo, "team" ), sizeof(settings.team) );
	Q_strncpyz( settings.pclass, Info_ValueForKey( userinfo, "class" ), sizeof(settings.pclass) );

	if (!BotAISetupClient( clientNum, &settings )) {
		trap_DropClient( clientNum, "BotAISetupClient failed" );
		return qfalse;
	}

	if( restart && g_gametype.integer == GT_SINGLE_PLAYER ) {
		g_entities[clientNum].botDelayBegin = qtrue;
	}
	else {
		g_entities[clientNum].botDelayBegin = qfalse;
	}

	return qtrue;
}
Exemple #5
0
/*
=================
ClientInactivityTimer

Returns qfalse if the client is dropped
=================
*/
qboolean ClientInactivityTimer( gclient_t *client ) {
	if ( !g_inactivity.integer ) {
		// give everyone some time, so if the operator sets g_inactivity during
		// gameplay, everyone isn't kicked
		client->inactivityTime = level.time + 60 * 1000;
		client->inactivityWarning = qfalse;
	} else if ( client->pers.cmd.forwardmove ||
				client->pers.cmd.rightmove ||
				client->pers.cmd.upmove ||
				( client->pers.cmd.wbuttons & WBUTTON_ATTACK2 ) ||
				( client->pers.cmd.buttons & BUTTON_ATTACK ) ) {
		client->inactivityTime = level.time + g_inactivity.integer * 1000;
		client->inactivityWarning = qfalse;
	} else if ( !client->pers.localClient ) {
		if ( level.time > client->inactivityTime ) {
			trap_DropClient( client - level.clients, "Dropped due to inactivity" );
			return qfalse;
		}
		if ( level.time > client->inactivityTime - 10000 && !client->inactivityWarning ) {
			client->inactivityWarning = qtrue;
			trap_SendServerCommand( client - level.clients, "cp \"Ten seconds until inactivity drop!\n\"" );
		}
	}
	return qtrue;
}
void G_globalAction(gentity_t *ent, gentity_t *vic, globalType_t type, char *reason)
{
	if (!G_isPlayerConnected(vic))
		return;

	switch (type)
	{
		case GLOBAL_BAN:
			trap_DropClient(vic->client->ps.clientNum, va("banned by %s^7, reason: %s", (ent)
					? ent->client->pers.netname
					: "console", (*reason) ? reason : "banned by admin"));
			break;
		case GLOBAL_DENYBUILD:
			vic->client->pers.denyBuild = qtrue;
			break;
		case GLOBAL_FORCESPEC:
			vic->client->pers.forcespec = qtrue;
			break;
		case GLOBAL_HANDICAP:
			vic->client->pers.handicap = qtrue;
			break;
		case GLOBAL_MUTE:
			vic->client->pers.muted = qtrue;
			break;
		case GLOBAL_NONE:
			//uh?
			break;
	}
}
/*
==================
Svcmd_KickNum_f
Joe Kari: there was in server/sv_ccmds.c a note that mention "FIXME: move to game", so I move it to game...
Additionnaly, you can now provide a reason for kicking someone.
*
kicknum <client number> [reasons]
==================
*/
static void Svcmd_KickNum_f( void ) {
	char		arg[MAX_TOKEN_CHARS];
	int		clientNum;
	gclient_t	*cl;
	char		*reason;

	if ( trap_Argc() < 2 ) {
		G_Printf ( "Usage: kicknum <client number> [reasons]\n");
		return;
	}

	trap_Argv( 1, arg, sizeof( arg ) );
	clientNum = atoi( arg );
	
	if ( clientNum >= level.maxclients || clientNum < 0 ) {
		Com_Printf("client not found\n");
		return;
	}
		                
	cl = &level.clients[ clientNum ] ;
	if ( cl->pers.connected != CON_CONNECTED ) {
		Com_Printf("client not found\n");
		return;
	}
	
	if ( cl->pers.localClient ) {
		Com_Printf("Cannot kick host player\n");
		return;
	}
	
	if ( trap_Argc() > 2 ) {
		Q_strncpyz ( arg, "was kicked: ", sizeof(arg));
		reason = ConcatArgs( 2 ) ;
		Q_strcat( arg, sizeof(arg), reason);
		PushMinilogf( "KICK: %i > %s", clientNum, reason ) ;
		trap_DropClient( clientNum, arg );
	}
	else {
		PushMinilogf( "KICK: %i", clientNum ) ;
		trap_DropClient( clientNum, "was kicked" );
	}
	
	/* FIXME? adapt this part of the server code to the game code?
	cl->lastPacketTime = svs.time;	// in case there is a funny zombie
	*/
}
Exemple #8
0
// *** Player Kick ***
int G_Kick_v( gentity_t *ent, unsigned int dwVoteIndex, char *arg, char *arg2, qboolean fRefereeCmd ) {
	// Vote request (vote is being initiated)
	if( arg ) {
		int pid;

		if( !vote_allow_kick.integer && ent && !ent->client->sess.referee ) {
			G_voteDisableMessage(ent, arg);
			return G_INVALID;
		} else if( G_voteDescription(ent, fRefereeCmd, dwVoteIndex) ) {
			return G_INVALID;
		} else if( ( pid = ClientNumberFromString( ent, arg2 ) ) == -1 ) {
			return G_INVALID;
		}

		if( level.clients[ pid ].sess.referee ) {
			G_refPrintf( ent, "Can't vote to kick referees!" );
			return G_INVALID;
		}

		if(G_shrubbot_permission(&g_entities[pid], SBF_IMMUNITY)) {
			G_refPrintf( ent, "Can't vote to kick admins!" );
			return G_INVALID;
		}

		// pheno: prevent ettv slaves from being callvote kicked 
		if( level.clients[pid].sess.ettv &&
			( g_ettvFlags.integer & ETTV_IMMUNITY ) ) {
			G_refPrintf( ent, "Can't vote to kick ettv slaves!" );
			return G_INVALID;
		}

		if( !fRefereeCmd && ent ) {
			if( level.clients[ pid ].sess.sessionTeam != TEAM_SPECTATOR && level.clients[ pid ].sess.sessionTeam != ent->client->sess.sessionTeam ) {
				G_refPrintf( ent, "Can't vote to kick players on opposing team!" );
				return G_INVALID;
			}
		}

		Com_sprintf( level.voteInfo.vote_value, VOTE_MAXSTRING, "%d", pid );
		Com_sprintf( arg2, VOTE_MAXSTRING, "%s^7", level.clients[pid].pers.netname );

	// Vote action (vote has passed)
	} else {
		// Kick a player
		//trap_SendConsoleCommand( EXEC_APPEND, va( "clientkick %d\n", atoi( level.voteInfo.vote_value ) ) );
		// tjw: clientkick doesn't work in 2.60
		trap_DropClient(atoi(level.voteInfo.vote_value),
			"You have been kicked", 120);

		AP( va( "cp \"%s\n^3has been kicked!\n\"", level.clients[ atoi( level.voteInfo.vote_value ) ].pers.netname ) );
	}

	return G_OK;
}
Exemple #9
0
/*
===============
G_BotConnect
===============
*/
qboolean G_BotConnect( int clientNum, qboolean restart ) {
	bot_settings_t	settings;
	char			userinfo[MAX_INFO_STRING];

	trap_GetUserinfo( clientNum, userinfo, sizeof(userinfo) );

	Q_strncpyz( settings.characterfile, Info_ValueForKey( userinfo, "characterfile" ), sizeof(settings.characterfile) );
	settings.skill = atof( Info_ValueForKey( userinfo, "skill" ) );

	if (!BotAISetupClient( clientNum, &settings, restart )) {
		trap_DropClient( clientNum, "BotAISetupClient failed" );
		return qfalse;
	}

	return qtrue;
}
Exemple #10
0
/*
================
respawn
================
*/
void respawn( gentity_t *ent ) {
	gentity_t	*tent;

	//kick fragged bots from game
	if (IsBot(ent->client->ps.clientNum) ) {
		trap_DropClient( ent->client->ps.clientNum, "" );
		G_EndWave();	//check if the wave was won and handle it
		return;
	}

	CopyToBodyQue (ent);
	ClientSpawn(ent);

	// add a teleportation effect
	tent = G_TempEntity( ent->client->ps.origin, EV_PLAYER_TELEPORT_IN );
	tent->s.clientNum = ent->s.clientNum;
}
/*
* G_CheckNumBots
*/
static void G_CheckNumBots( void )
{
	edict_t	*ent;
	int desiredNumBots;

	if( level.spawnedTimeStamp + 5000 > game.realtime )
		return;

	// check sanity of g_numbots
	if( g_numbots->integer < 0 )
		trap_Cvar_Set( "g_numbots", "0" );

	if( g_numbots->integer > gs.maxclients )
		trap_Cvar_Set( "g_numbots", va( "%i", gs.maxclients ) );

	if( level.gametype.numBots > gs.maxclients )
		level.gametype.numBots = gs.maxclients;

	desiredNumBots = level.gametype.numBots ? level.gametype.numBots : g_numbots->integer;

	if( desiredNumBots < game.numBots )
	{
		// kick one bot
		for( ent = game.edicts + gs.maxclients; PLAYERNUM( ent ) >= 0; ent-- )
		{
			if( !ent->r.inuse || !( ent->r.svflags & SVF_FAKECLIENT ) )
				continue;
			if( AI_GetType( ent->ai ) == AI_ISBOT )
			{
				trap_DropClient( ent, DROP_TYPE_GENERAL, NULL );
				break;
			}
		}
		return;
	}

	if( desiredNumBots > game.numBots )
	{                                     // add a bot if there is room
		for( ent = game.edicts + 1; PLAYERNUM( ent ) < gs.maxclients && game.numBots < desiredNumBots; ent++ )
		{
			if( !ent->r.inuse && trap_GetClientState( PLAYERNUM( ent ) ) == CS_FREE )
				BOT_SpawnBot( NULL );
		}
	}
}
Exemple #12
0
/*
* Cmd_ConsoleKick_f
*/
static void Cmd_ConsoleKick_f( void )
{
	edict_t *ent;

	if( trap_Cmd_Argc() != 2 )
	{
		Com_Printf( "Usage: kick <id or name>\n" );
		return;
	}

	ent = G_PlayerForText( trap_Cmd_Argv( 1 ) );
	if( !ent )
	{
		Com_Printf( "No such player\n" );
		return;
	}

	trap_DropClient( ent, DROP_TYPE_NORECONNECT, "Kicked" );
}
Exemple #13
0
qboolean G_CensorName(char *testname, char *userinfo, int clientNum)
{
    char censoredName[MAX_NETNAME];
    char name[MAX_NETNAME];
    Q_strncpyz(name, testname, sizeof(name));
    SanitizeString(name, censoredName, qtrue);
    if (G_CensorText(censoredName, &censorNamesDictionary))
    {
        Q_strncpyz(testname, censoredName, sizeof(censoredName));
        if (g_censorPenalty.integer & CNSRPNLTY_KICK)
        {
            trap_DropClient(clientNum,
                            va("Name censor: Please change your name."),
                            0);
            return qtrue;
        }
    }
    return qfalse;
}
Exemple #14
0
/*
===============
G_BotConnect
===============
*/
qboolean G_BotConnect( int clientNum, qboolean restart ) {
	bot_settings_t	settings;
	char			userinfo[MAX_INFO_STRING];

	trap_GetUserinfo( clientNum, userinfo, sizeof(userinfo) );

	Q_strncpyz( settings.personalityfile, Info_ValueForKey( userinfo, "personality" ), sizeof(settings.personalityfile) );
	settings.skill = atof( Info_ValueForKey( userinfo, "skill" ) );
	Q_strncpyz( settings.team, Info_ValueForKey( userinfo, "team" ), sizeof(settings.team) );
	//[TABBot]
	settings.botType = atoi( Info_ValueForKey( userinfo, "bottype" ) );
	//[/TABBot]

	if (!BotAISetupClient( clientNum, &settings, restart )) {
		trap_DropClient( clientNum, "BotAISetupClient failed" );
		return qfalse;
	}

	return qtrue;
}
Exemple #15
0
//==========================================
//	BOT_RemoveBot
//	Remove a bot by name or all bots
//==========================================
void BOT_RemoveBot( const char *name )
{
	int i;
	bool freed = false;
	edict_t	*ent;

	for( i = 0, ent = game.edicts + 1; i < gs.maxclients; i++, ent++ )
	{
		if( !ent->r.inuse || AI_GetType( ent->ai ) != AI_ISBOT )
			continue;

		if( !Q_stricmp( ent->r.client->netname, name ) || !Q_stricmp( name, "all" ) )
		{
			trap_DropClient( ent, DROP_TYPE_GENERAL, NULL );
			freed = true;
		}
	}

	if( !freed && Q_stricmp( name, "all" ) )
		G_Printf( "BOT: %s not found\n", name );
}
Exemple #16
0
void G_BotDel( int clientNum )
{
	gentity_t *bot = &g_entities[clientNum];
	char userinfo[MAX_INFO_STRING];
	const char *autoname;

	if ( !( bot->r.svFlags & SVF_BOT ) || !bot->botMind )
	{
		Log::Warn( "'^7%s^7' is not a bot", bot->client->pers.netname );
		return;
	}

	trap_GetUserinfo( clientNum, userinfo, sizeof( userinfo ) );

	autoname = Info_ValueForKey( userinfo, "autoname" );
	if ( autoname && *autoname )
	{
		G_BotNameUsed( BotGetEntityTeam( bot ), autoname, false );
	}

	trap_SendServerCommand( -1, va( "print_tr %s %s", QQ( N_( "$1$^7 disconnected" ) ),
					Quote( bot->client->pers.netname ) ) );
	trap_DropClient( clientNum, "disconnected" );
}
Exemple #17
0
/*
===========
ClientUserInfoChanged

Called from ClientConnect when the player first connects and
directly by the server system when the player updates a userinfo variable.

The game can override any of the settings and call trap_SetUserinfo
if desired.
============
*/
char *ClientUserinfoChanged( int clientNum, qboolean forceName )
{
    gentity_t *ent;
    char      *s;
    char      model[ MAX_QPATH ];
    char      buffer[ MAX_QPATH ];
    char      filename[ MAX_QPATH ];
    char      oldname[ MAX_NAME_LENGTH ];
    char      newname[ MAX_NAME_LENGTH ];
    char      err[ MAX_STRING_CHARS ];
    qboolean  revertName = qfalse;
    gclient_t *client;
    char      userinfo[ MAX_INFO_STRING ];

    ent = g_entities + clientNum;
    client = ent->client;

    trap_GetUserinfo( clientNum, userinfo, sizeof( userinfo ) );

    // check for malformed or illegal info strings
    if( !Info_Validate(userinfo) )
    {
        trap_SendServerCommand( ent - g_entities,
                                "disconnect \"illegal or malformed userinfo\n\"" );
        trap_DropClient( ent - g_entities,
                         "dropped: illegal or malformed userinfo");
        return "Illegal or malformed userinfo";
    }
    // If their userinfo overflowed, tremded is in the process of disconnecting them.
    // If we send our own disconnect, it won't work, so just return to prevent crashes later
    //  in this function. This check must come after the Info_Validate call.
    else if( !userinfo[ 0 ] )
        return "Empty (overflowed) userinfo";

    // stickyspec toggle
    s = Info_ValueForKey( userinfo, "cg_stickySpec" );
    client->pers.stickySpec = atoi( s ) != 0;

    // set name
    Q_strncpyz( oldname, client->pers.netname, sizeof( oldname ) );
    s = Info_ValueForKey( userinfo, "name" );
    G_ClientCleanName( s, newname, sizeof( newname ) );

    if( strcmp( oldname, newname ) )
    {
        if( !forceName && client->pers.namelog->nameChangeTime &&
                level.time - client->pers.namelog->nameChangeTime <=
                g_minNameChangePeriod.value * 1000 )
        {
            trap_SendServerCommand( ent - g_entities, va(
                                        "print \"Name change spam protection (g_minNameChangePeriod = %d)\n\"",
                                        g_minNameChangePeriod.integer ) );
            revertName = qtrue;
        }
        else if( !forceName && g_maxNameChanges.integer > 0 &&
                 client->pers.namelog->nameChanges >= g_maxNameChanges.integer  )
        {
            trap_SendServerCommand( ent - g_entities, va(
                                        "print \"Maximum name changes reached (g_maxNameChanges = %d)\n\"",
                                        g_maxNameChanges.integer ) );
            revertName = qtrue;
        }
        else if( !forceName && client->pers.namelog->muted )
        {
            trap_SendServerCommand( ent - g_entities,
                                    "print \"You cannot change your name while you are muted\n\"" );
            revertName = qtrue;
        }
        else if( !G_admin_name_check( ent, newname, err, sizeof( err ) ) )
        {
            trap_SendServerCommand( ent - g_entities, va( "print \"%s\n\"", err ) );
            revertName = qtrue;
        }

        if( revertName )
        {
            Q_strncpyz( client->pers.netname, *oldname ? oldname : "UnnamedPlayer",
                        sizeof( client->pers.netname ) );
            Info_SetValueForKey( userinfo, "name", oldname );
            trap_SetUserinfo( clientNum, userinfo );
        }
        else
        {
            G_CensorString( client->pers.netname, newname,
                            sizeof( client->pers.netname ), ent );
            if( !forceName && client->pers.connected == CON_CONNECTED )
            {
                client->pers.namelog->nameChangeTime = level.time;
                client->pers.namelog->nameChanges++;
            }
            if( *oldname )
            {
                G_LogPrintf( "ClientRename: %i [%s] (%s) \"%s^7\" -> \"%s^7\" \"%c%s%c^7\"\n",
                             clientNum, client->pers.ip.str, client->pers.guid,
                             oldname, client->pers.netname,
                             DECOLOR_OFF, client->pers.netname, DECOLOR_ON );
            }
        }
        G_namelog_update_name( client );
    }

    if( client->pers.classSelection == PCL_NONE )
    {
        //This looks hacky and frankly it is. The clientInfo string needs to hold different
        //model details to that of the spawning class or the info change will not be
        //registered and an axis appears instead of the player model. There is zero chance
        //the player can spawn with the battlesuit, hence this choice.
        Com_sprintf( buffer, MAX_QPATH, "%s/%s",  BG_ClassConfig( PCL_HUMAN_BSUIT )->modelName,
                     BG_ClassConfig( PCL_HUMAN_BSUIT )->skinName );
    }
    else
    {
        Com_sprintf( buffer, MAX_QPATH, "%s/%s",  BG_ClassConfig( client->pers.classSelection )->modelName,
                     BG_ClassConfig( client->pers.classSelection )->skinName );

        //model segmentation
        Com_sprintf( filename, sizeof( filename ), "models/players/%s/animation.cfg",
                     BG_ClassConfig( client->pers.classSelection )->modelName );

        if( G_NonSegModel( filename ) )
            client->ps.persistant[ PERS_STATE ] |= PS_NONSEGMODEL;
        else
            client->ps.persistant[ PERS_STATE ] &= ~PS_NONSEGMODEL;
    }
    Q_strncpyz( model, buffer, sizeof( model ) );

    // wallwalk follow
    s = Info_ValueForKey( userinfo, "cg_wwFollow" );

    if( atoi( s ) )
        client->ps.persistant[ PERS_STATE ] |= PS_WALLCLIMBINGFOLLOW;
    else
        client->ps.persistant[ PERS_STATE ] &= ~PS_WALLCLIMBINGFOLLOW;

    // wallwalk toggle
    s = Info_ValueForKey( userinfo, "cg_wwToggle" );

    if( atoi( s ) )
        client->ps.persistant[ PERS_STATE ] |= PS_WALLCLIMBINGTOGGLE;
    else
        client->ps.persistant[ PERS_STATE ] &= ~PS_WALLCLIMBINGTOGGLE;

    // always sprint
    s = Info_ValueForKey( userinfo, "cg_sprintToggle" );

    if( atoi( s ) )
        client->ps.persistant[ PERS_STATE ] |= PS_SPRINTTOGGLE;
    else
        client->ps.persistant[ PERS_STATE ] &= ~PS_SPRINTTOGGLE;

    // fly speed
    s = Info_ValueForKey( userinfo, "cg_flySpeed" );

    if( *s )
        client->pers.flySpeed = atoi( s );
    else
        client->pers.flySpeed = BG_Class( PCL_NONE )->speed;

    // disable blueprint errors
    s = Info_ValueForKey( userinfo, "cg_disableBlueprintErrors" );

    if( atoi( s ) )
        client->pers.disableBlueprintErrors = qtrue;
    else
        client->pers.disableBlueprintErrors = qfalse;

    // teamInfo
    s = Info_ValueForKey( userinfo, "teamoverlay" );

    if( atoi( s ) != 0 )
    {
        // teamoverlay was enabled so we need an update
        if( client->pers.teamInfo == 0 )
            client->pers.teamInfo = 1;
    }
    else
        client->pers.teamInfo = 0;

    s = Info_ValueForKey( userinfo, "cg_unlagged" );
    if( !s[0] || atoi( s ) != 0 )
        client->pers.useUnlagged = qtrue;
    else
        client->pers.useUnlagged = qfalse;

    Q_strncpyz( client->pers.voice, Info_ValueForKey( userinfo, "voice" ),
                sizeof( client->pers.voice ) );

    // send over a subset of the userinfo keys so other clients can
    // print scoreboards, display models, and play custom sounds

    Com_sprintf( userinfo, sizeof( userinfo ),
                 "n\\%s\\t\\%i\\model\\%s\\ig\\%16s\\v\\%s",
                 client->pers.netname, client->pers.teamSelection, model,
                 Com_ClientListString( &client->sess.ignoreList ),
                 client->pers.voice );

    trap_SetConfigstring( CS_PLAYERS + clientNum, userinfo );

    /*G_LogPrintf( "ClientUserinfoChanged: %i %s\n", clientNum, userinfo );*/

    return NULL;
}
Exemple #18
0
/*
===========
ClientConnect

Called when a player begins connecting to the server.
Called again for every map change or tournement restart.

The session information will be valid after exit.

Return NULL if the client should be allowed, otherwise return
a string with the reason for denial.

Otherwise, the client will be sent the current gamestate
and will eventually get to ClientBegin.

firstTime will be qtrue the very first time a client connects
to the server machine, but qfalse on map changes and tournement
restarts.
============
*/
char *ClientConnect( int clientNum, qboolean firstTime )
{
    char      *value;
    char      *userInfoError;
    gclient_t *client;
    char      userinfo[ MAX_INFO_STRING ];
    gentity_t *ent;
    char      reason[ MAX_STRING_CHARS ] = {""};
    int       i;

    ent = &g_entities[ clientNum ];
    client = &level.clients[ clientNum ];

    // ignore if client already connected
    if( client->pers.connected != CON_DISCONNECTED )
        return NULL;

    ent->client = client;
    memset( client, 0, sizeof( *client ) );

    trap_GetUserinfo( clientNum, userinfo, sizeof( userinfo ) );

    value = Info_ValueForKey( userinfo, "cl_guid" );
    Q_strncpyz( client->pers.guid, value, sizeof( client->pers.guid ) );

    value = Info_ValueForKey( userinfo, "ip" );
    // check for local client
    if( !strcmp( value, "localhost" ) )
        client->pers.localClient = qtrue;
    G_AddressParse( value, &client->pers.ip );

    client->pers.admin = G_admin_admin( client->pers.guid );

    // check for admin ban
    if( G_admin_ban_check( ent, reason, sizeof( reason ) ) )
    {
        return va( "%s", reason );
    }

    // check for a password
    value = Info_ValueForKey( userinfo, "password" );

    if( g_password.string[ 0 ] && Q_stricmp( g_password.string, "none" ) &&
            strcmp( g_password.string, value ) != 0 )
        return "Invalid password";

    // add guid to session so we don't have to keep parsing userinfo everywhere
    for( i = 0; i < sizeof( client->pers.guid ) - 1 &&
            isxdigit( client->pers.guid[ i ] ); i++ );

    if( i < sizeof( client->pers.guid ) - 1 )
        return "Invalid GUID";

    for( i = 0; i < level.maxclients; i++ )
    {
        if( level.clients[ i ].pers.connected == CON_DISCONNECTED )
            continue;

        if( !Q_stricmp( client->pers.guid, level.clients[ i ].pers.guid ) )
        {
            if( !G_ClientIsLagging( level.clients + i ) )
            {
                trap_SendServerCommand( i, "cp \"Your GUID is not secure\"" );
                return "Duplicate GUID";
            }
            trap_DropClient( i, "Ghost" );
        }
    }

    client->pers.connected = CON_CONNECTING;

    // read or initialize the session data
    if( firstTime || level.newSession )
        G_InitSessionData( client, userinfo );

    G_ReadSessionData( client );

    // get and distribute relevent paramters
    G_namelog_connect( client );
    userInfoError = ClientUserinfoChanged( clientNum, qfalse );
    if( userInfoError != NULL )
        return userInfoError;

    G_LogPrintf( "ClientConnect: %i [%s] (%s) \"%s^7\" \"%c%s%c^7\"\n",
                 clientNum, client->pers.ip.str, client->pers.guid,
                 client->pers.netname,
                 DECOLOR_OFF, client->pers.netname, DECOLOR_ON );

    // don't do the "xxx connected" messages if they were caried over from previous level
    if( firstTime )
        trap_SendServerCommand( -1, va( "print \"%s" S_COLOR_WHITE " connected\n\"",
                                        client->pers.netname ) );

    if( client->pers.admin )
        G_admin_authlog( ent );

    // count current clients and rank for scoreboard
    CalculateRanks( );


    // if this is after !restart keepteams or !restart switchteams, apply said selection
    if ( client->sess.restartTeam != TEAM_NONE )
    {
        G_ChangeTeam( ent, client->sess.restartTeam );
        client->sess.restartTeam = TEAM_NONE;
    }


    return NULL;
}
Exemple #19
0
/**
 * Validate userinfo string
 * @autor: Nico
 */
static qboolean checkUserinfoString(int clientNum, char *userinfo) {
	size_t len                 = 0;
	int    count               = 0;
	int    i                   = 0;
	char   *ip                 = NULL;
	char   parsedIp[MAX_QPATH] = { 0 };
	char   *name               = NULL;

	// check for malformed or illegal info strings
	if (!Info_Validate(userinfo)) {
		// Nico, drop the client
		G_LogPrintf("Dropping client %d: forbidden character in userinfo\n", clientNum);
		trap_DropClient(clientNum, "^1You were kicked because of forbidden character in userinfo", 0);
		return qfalse;
	}
	// Nico, check userinfo length (from combinedfixes)
	len = strlen(userinfo);
	if (len > MAX_INFO_STRING - 44) {
		G_LogPrintf("Dropping client %d: oversized userinfo\n", clientNum);
		trap_DropClient(clientNum, "^1You were kicked because of oversized userinfo", 0);
		return qfalse;
	}

	// Nico, check userinfo leading backslash (from combinedfixes)
	if (userinfo[0] != '\\') {
		G_LogPrintf("Dropping client %d: malformed userinfo (missing leading backslash)\n", clientNum);
		trap_DropClient(clientNum, "^1You were kicked because of malformed userinfo", 0);
		return qfalse;
	}

	// Nico, check userinfo trailing backslash (from combinedfixes)
	if (len > 0 && userinfo[len - 1] == '\\') {
		G_LogPrintf("Dropping client %d: malformed userinfo (trailing backslash)\n", clientNum);
		trap_DropClient(clientNum, "^1You were kicked because of malformed userinfo", 0);
		return qfalse;
	}

	// Nico, make sure backslah number is even (from combinedfixes)
	for (i = 0; i < (int)len; ++i) {
		if (userinfo[i] == '\\') {
			count++;
		}
	}
	if (count % 2 != 0) {
		G_LogPrintf("Dropping client %d: malformed userinfo (odd number of backslash)\n", clientNum);
		trap_DropClient(clientNum, "^1You were kicked because of malformed userinfo", 0);
		return qfalse;
	}

	// Nico, make sure client ip is not empty or malformed (from combinedfixes)
	ip = Info_ValueForKey(userinfo, "ip");
	if (!strcmp(ip, "") || !getParsedIp(ip, parsedIp)) {
		G_LogPrintf("Dropping client %d: malformed userinfo (empty or malformed ip)\n", clientNum);
		trap_DropClient(clientNum, "^1You were kicked because of malformed userinfo", 0);
		return qfalse;
	}

	// Nico, make sure client name is not empty (from combinedfixes)
	name = Info_ValueForKey(userinfo, "name");
	if (!strcmp(name, "")) {
		G_LogPrintf("Dropping client %d: malformed userinfo (empty name)\n", clientNum);
		trap_DropClient(clientNum, "^1You were kicked because of malformed userinfo", 0);
		return qfalse;
	}

	// Nico, one ip in userinfo (from ETpub)
	count = 0;
	if (len > 4) {
		for (i = 0; userinfo[i + 3]; ++i) {
			if (userinfo[i] == '\\' && userinfo[i + 1] == 'i' &&
			    userinfo[i + 2] == 'p' && userinfo[i + 3] == '\\') {
				count++;
			}
		}
	}
	if (count > 1) {
		G_LogPrintf("Dropping client %d: malformed userinfo (too many IP fields)\n", clientNum);
		trap_DropClient(clientNum, "^1You were kicked because of malformed userinfo", 0);
		return qfalse;
	}

	// Nico, one cl_guid in userinfo (from ETpub)
	count = 0;
	if (len > 9) {
		for (i = 0; userinfo[i + 8]; ++i) {
			if (userinfo[i] == '\\' && userinfo[i + 1] == 'c' &&
			    userinfo[i + 2] == 'l' && userinfo[i + 3] == '_' &&
			    userinfo[i + 4] == 'g' && userinfo[i + 5] == 'u' &&
			    userinfo[i + 6] == 'i' && userinfo[i + 7] == 'd' &&
			    userinfo[i + 8] == '\\') {
				count++;
			}
		}
	}
	if (count > 1) {
		G_LogPrintf("Dropping client %d: malformed userinfo (too many cl_guid fields)\n", clientNum);
		trap_DropClient(clientNum, "^1You were kicked because of malformed userinfo", 0);
		return qfalse;
	}

	// Nico, one name in userinfo (from ETpub)
	count = 0;
	if (len > 6) {
		for (i = 0; userinfo[i + 5]; ++i) {
			if (userinfo[i] == '\\' && userinfo[i + 1] == 'n' &&
			    userinfo[i + 2] == 'a' && userinfo[i + 3] == 'm' &&
			    userinfo[i + 4] == 'e' && userinfo[i + 5] == '\\') {
				count++;
			}
		}
	}
	if (count > 1) {
		G_LogPrintf("Dropping client %d: malformed userinfo (too many name fields)\n", clientNum);
		trap_DropClient(clientNum, "^1You were kicked because of malformed userinfo", 0);
		return qfalse;
	}
	return qtrue;
}
Exemple #20
0
/*
==============
ClientThink

This will be called once for each client frame, which will
usually be a couple times for each server frame on fast clients.

If "g_synchronousClients 1" is set, this will be called exactly
once for each server frame, which makes for smooth demo recording.
==============
*/
void ClientThink_real(gentity_t * ent)
{
	gclient_t *client;
	pmove_t pm;
	int oldEventSequence;
	int msec;
	usercmd_t *ucmd;
	int bJumping = 0;

	client = ent->client;

	// don't think if the client is not yet connected (and thus not yet spawned in)
	if (client->pers.connected != CON_CONNECTED) {
		return;
	}
	// mark the time, so the connection sprite can be removed
	ucmd = &ent->client->pers.cmd;

	// sanity check the command time to prevent speedup cheating
	if (ucmd->serverTime > level.time + 200) {
		ucmd->serverTime = level.time + 200;
	}
	if (ucmd->serverTime < level.time - 1000) {
		ucmd->serverTime = level.time - 1000;
	}

	client->lastUpdateFrame = level.framenum;

	msec = ucmd->serverTime - client->ps.commandTime;
	// following others may result in bad times, but we still want
	// to check for follow toggles
	if (msec < 1 && client->sess.spectatorState != SPECTATOR_FOLLOW) {
		return;
	}
	if (msec > 200) {
		msec = 200;
	}

	if (pmove_msec.integer < 8) {
		trap_Cvar_Set("pmove_msec", "8");
	} else if (pmove_msec.integer > 33) {
		trap_Cvar_Set("pmove_msec", "33");
	}

	if (pmove_fixed.integer || client->pers.pmoveFixed) {
		ucmd->serverTime =
		    ((ucmd->serverTime + pmove_msec.integer - 1) / pmove_msec.integer) * pmove_msec.integer;
	}
	//
	// check for exiting intermission
	//
	if (level.intermissiontime) {
		ClientIntermissionThink(client);
		return;
	}
	// spectators don't do much
	if (client->sess.sessionTeam == TEAM_SPECTATOR) {
		if (client->sess.spectatorState == SPECTATOR_SCOREBOARD) {
			return;
		}
		SpectatorThink(ent, ucmd);
		return;
	}
	// check for inactivity timer, but never drop the local client of a non-dedicated server
	if (!ClientInactivityTimer(client)) {
		return;
	}
	// clear the rewards if time
	if (level.time > client->rewardTime) {
		client->ps.eFlags &=
		    ~(EF_AWARD_IMPRESSIVE | EF_AWARD_EXCELLENT | EF_AWARD_GAUNTLET | EF_AWARD_ASSIST | EF_AWARD_DEFEND |
		      EF_AWARD_CAP);
	}

	if (client->noclip) {
		client->ps.pm_type = PM_NOCLIP;
	} else if (client->ps.stats[STAT_HEALTH] <= 0) {
		client->ps.pm_type = PM_DEAD;
	} else {
		client->ps.pm_type = PM_NORMAL;
	}

	client->ps.gravity = g_gravity.value;

	// set speed
	client->ps.speed = g_speed.value;

	// set up for pmove
	oldEventSequence = client->ps.eventSequence;

	memset(&pm, 0, sizeof(pm));

	if (ent->flags & FL_FORCE_GESTURE) {
		ent->flags &= ~FL_FORCE_GESTURE;
		ent->client->pers.cmd.buttons |= BUTTON_GESTURE;
	}
	//Elder: 3rb Code moved to bg_pmove.c (resides in PM_Weapon)

	pm.ps = &client->ps;
	pm.cmd = *ucmd;

	if (pm.ps->pm_type == PM_DEAD) {
		pm.tracemask = MASK_PLAYERSOLID & ~CONTENTS_BODY;
	} else if (ent->r.svFlags & SVF_BOT) {
		pm.tracemask = MASK_PLAYERSOLID | CONTENTS_BOTCLIP;
	} else {
		pm.tracemask = MASK_PLAYERSOLID;
	}

// JBravo: fixing telefragging and shit during spawnig.  (Thanks NiceAss! :)
	if ((g_gametype.integer == GT_TEAMPLAY || g_gametype.integer == GT_TEAM) &&
	    ((ent->client->ps.stats[STAT_RQ3] & RQ3_PLAYERSOLID) != RQ3_PLAYERSOLID) && !level.lights_camera_action) {
		UnstickPlayer(ent);
	}
	if ((g_gametype.integer == GT_TEAMPLAY || g_gametype.integer == GT_TEAM) &&
	    ((ent->client->ps.stats[STAT_RQ3] & RQ3_PLAYERSOLID) != RQ3_PLAYERSOLID)) {
		pm.tracemask = MASK_PLAYERSOLID & ~CONTENTS_BODY;
	}

	pm.trace = trap_Trace;
	pm.pointcontents = trap_PointContents;
	pm.debugLevel = g_debugMove.integer;
	pm.noFootsteps = (g_dmflags.integer & DF_NO_FOOTSTEPS) > 0;

	pm.pmove_fixed = pmove_fixed.integer | client->pers.pmoveFixed;
	pm.pmove_msec = pmove_msec.integer;

	VectorCopy(client->ps.origin, client->oldOrigin);

// JBravo: setting lca in pm if appropriate
	if (g_RQ3_lca.integer == 1)
		pm.lca = qtrue;
	else
		pm.lca = qfalse;

	pm.predict = qtrue;

	Pmove(&pm);

	if ((pm.cmd.upmove > 10) &&
	    (pm.waterlevel == 0) &&
	    ent->s.groundEntityNum != ENTITYNUM_NONE && pm.ps->groundEntityNum == ENTITYNUM_NONE)
		bJumping = 1;

	// save results of pmove
	if (ent->client->ps.eventSequence != oldEventSequence) {
		ent->eventTime = level.time;
	}

	BG_PlayerStateToEntityState(&ent->client->ps, &ent->s, qtrue);
	SendPendingPredictableEvents(&ent->client->ps);

	if (!(ent->client->ps.eFlags & EF_FIRING)) {
		client->fireHeld = qfalse;	// for grapple
	}
	// use the snapped origin for linking so it matches client predicted versions
	VectorCopy(ent->s.pos.trBase, ent->r.currentOrigin);

	VectorCopy(pm.mins, ent->r.mins);
	VectorCopy(pm.maxs, ent->r.maxs);

	ent->waterlevel = pm.waterlevel;
	ent->watertype = pm.watertype;

	// execute client events
	ClientEvents(ent, oldEventSequence);

	// link entity now, after any personal teleporters have been used
	// JBravo: this call reactivates gibbed players.
	if (!ent->client->gibbed)
		trap_LinkEntity(ent);
	if (!ent->client->noclip) {
		G_TouchTriggers(ent);
	}
	// NOTE: now copy the exact origin over otherwise clients can be snapped into solid
	VectorCopy(ent->client->ps.origin, ent->r.currentOrigin);

	//test for solid areas in the AAS file
	BotTestAAS(ent->r.currentOrigin);

	// touch other objects
	ClientImpacts(ent, &pm);

	//Elder: someone added
	if (bJumping)
		JumpKick(ent);

	// save results of triggers and client events
	if (ent->client->ps.eventSequence != oldEventSequence) {
		ent->eventTime = level.time;
	}
	// swap and latch button actions
	client->oldbuttons = client->buttons;
	client->buttons = ucmd->buttons;
	client->latched_buttons |= client->buttons & ~client->oldbuttons;

	// check for respawning
	// JBravo: Lets make dead players into spectators.
	if (client->ps.stats[STAT_HEALTH] <= 0) {
		// wait for the attack button to be pressed
		if (level.time > client->respawnTime) {
			// forcerespawn is to prevent users from waiting out powerups
			if (g_forcerespawn.integer > 0 &&
			    (level.time - client->respawnTime) > g_forcerespawn.integer * 1000 &&
			    g_gametype.integer != GT_TEAMPLAY && g_gametype.integer != GT_CTF) {
				respawn(ent);
				return;
			}
			if ((g_gametype.integer == GT_TEAMPLAY || g_gametype.integer == GT_CTF) && level.time > client->respawnTime) {
				MakeSpectator(ent);
			}
			// pressing attack or use is the normal respawn method
			// JBravo: make'em spactate
			if (ucmd->buttons & (BUTTON_ATTACK | BUTTON_USE_HOLDABLE)) {
				if (g_gametype.integer == GT_TEAMPLAY || g_gametype.integer == GT_CTF) {
					MakeSpectator(ent);
				} else {
					respawn(ent);
				}
			}
		}
		return;
	}
// JBravo: Idle sounds
	if (g_RQ3_ppl_idletime.integer) {
		if (ucmd->forwardmove == 0 && ucmd->rightmove == 0) {
			if (client->idletime) {
				if (level.time >= client->idletime + (g_RQ3_ppl_idletime.integer * 1000)) {
					if (g_gametype.integer >= GT_TEAM && g_RQ3_idleaction.integer == 1 &&
						(ent->client->sess.sessionTeam == TEAM_RED || ent->client->sess.sessionTeam == TEAM_BLUE)) {
						trap_SendServerCommand( -1, va("print \"Removing %s^7 from his team for excessive Idling\n\"", 
								ent->client->pers.netname));
						trap_SendServerCommand(ent - g_entities, "stuff team none\n");
					} else if (g_gametype.integer >= GT_TEAM && g_RQ3_idleaction.integer == 2 &&
						(ent->client->sess.sessionTeam == TEAM_RED || ent->client->sess.sessionTeam == TEAM_BLUE)) {
						trap_SendServerCommand( -1, va("print \"Kicking %s^7 for excessive Idling\n\"", 
								ent->client->pers.netname));
						trap_DropClient(ent - g_entities, "Dropped due to excessive Idling");
					} else
						G_TempEntity(ent->r.currentOrigin, EV_INSANESOUND);
					client->idletime = 0;
				}
			} else {
				client->idletime = level.time;
			}
		} else {
			client->idletime = 0;
		}
	}
	// perform once-a-second actions
	ClientTimerActions(ent, msec);
}
Exemple #21
0
/*
===========
ClientConnect

Called when a player begins connecting to the server.
Called again for every map change or tournement restart.

The session information will be valid after exit.

Return nullptr if the client should be allowed, otherwise return
a string with the reason for denial.

Otherwise, the client will be sent the current gamestate
and will eventually get to ClientBegin.

firstTime will be true the very first time a client connects
to the server machine, but false on map changes and tournement
restarts.
============
*/
const char *ClientConnect( int clientNum, bool firstTime )
{
	const char      *value;
	const char      *userInfoError;
	gclient_t       *client;
	char            userinfo[ MAX_INFO_STRING ];
	char            pubkey[ RSA_STRING_LENGTH ];
	gentity_t       *ent;
	char            reason[ MAX_STRING_CHARS ] = { "" };
	int             i;
	const char      *country;

	ent = &g_entities[ clientNum ];
	client = &level.clients[ clientNum ];

	// ignore if client already connected
	if ( client->pers.connected != CON_DISCONNECTED )
	{
		return nullptr;
	}

	ent->client = client;
	memset( client, 0, sizeof( *client ) );

	trap_GetUserinfo( clientNum, userinfo, sizeof( userinfo ) );

	value = Info_ValueForKey( userinfo, "ip" );

	// check for local client
	if ( !strcmp( value, "localhost" ) )
	{
		client->pers.localClient = true;
	}

	G_AddressParse( value, &client->pers.ip );

	trap_GetPlayerPubkey( clientNum, pubkey, sizeof( pubkey ) );

	if ( strlen( pubkey ) != RSA_STRING_LENGTH - 1 )
	{
		return "Invalid pubkey key";
	}

	trap_GenFingerprint( pubkey, sizeof( pubkey ), client->pers.guid, sizeof( client->pers.guid ) );
	client->pers.admin = G_admin_admin( client->pers.guid );

	client->pers.pubkey_authenticated = false;

	if ( client->pers.admin )
	{
		Com_GMTime( &client->pers.admin->lastSeen );
	}

	// check for admin ban
	if ( G_admin_ban_check( ent, reason, sizeof( reason ) ) )
	{
		return va( "%s", reason ); // reason is local
	}

	// check for a password
	value = Info_ValueForKey( userinfo, "password" );

	if ( g_password.string[ 0 ] && Q_stricmp( g_password.string, "none" ) &&
	     strcmp( g_password.string, value ) != 0 )
	{
		return "Invalid password";
	}

	// if a player reconnects quickly after a disconnect, the client disconnect may never be called, thus flag can get lost in the ether
	if ( ent->inuse )
	{
		G_LogPrintf( "Forcing disconnect on active client: %i", (int)( ent - g_entities ) );
		// so lets just fix up anything that should happen on a disconnect
		ClientDisconnect( ent-g_entities );
	}

	for ( i = 0; i < level.maxclients; i++ )
	{
		if ( level.clients[ i ].pers.connected == CON_DISCONNECTED )
		{
			continue;
		}

		if ( !( g_entities[i].r.svFlags & SVF_BOT ) && !Q_stricmp( client->pers.guid, level.clients[ i ].pers.guid ) )
		{
			if ( !G_ClientIsLagging( level.clients + i ) )
			{
				trap_SendServerCommand( i, "cp \"Your GUID is not secure\"" );
				return "Duplicate GUID";
			}

			trap_DropClient( i, "Ghost" );
		}
	}

	client->pers.connected = CON_CONNECTING;

	// read or initialize the session data
	if ( firstTime )
	{
		G_InitSessionData( client, userinfo );
	}

	G_ReadSessionData( client );

	// get and distribute relevent paramters
	G_namelog_connect( client );
	userInfoError = ClientUserinfoChanged( clientNum, false );

	if ( userInfoError != nullptr )
	{
		return userInfoError;
	}

	G_LogPrintf( "ClientConnect: %i [%s] (%s) \"%s^7\" \"%s^7\"",
	             clientNum, client->pers.ip.str[0] ? client->pers.ip.str : "127.0.0.1", client->pers.guid,
	             client->pers.netname,
	             client->pers.netname );

	country = Info_ValueForKey( userinfo, "geoip" );
	Q_strncpyz( client->pers.country, country, sizeof( client->pers.country ) );

	G_SendClientPmoveParams(clientNum);

	// don't do the "xxx connected" messages if they were caried over from previous level
	if ( firstTime )
	{
		if ( g_geoip.integer && country && *country )
		{
			trap_SendServerCommand( -1, va( "print_tr %s %s %s", QQ( N_("$1$^7 connected from $2$") ),
			                                Quote( client->pers.netname ), Quote( country ) ) );
		}
		else
		{
			trap_SendServerCommand( -1, va( "print_tr %s %s", QQ( N_("$1$^7 connected") ),
			                                Quote( client->pers.netname ) ) );
		}
	}

	// count current clients and rank for scoreboard
	CalculateRanks();

	// if this is after !restart keepteams or !restart switchteams, apply said selection
	if ( client->sess.restartTeam != TEAM_NONE )
	{
		G_ChangeTeam( ent, client->sess.restartTeam );
		client->sess.restartTeam = TEAM_NONE;
	}

	return nullptr;
}
Exemple #22
0
/*
===========
ClientUserInfoChanged

Called from ClientConnect when the player first connects and
directly by the server system when the player updates a userinfo variable.

The game can override any of the settings and call trap_SetUserinfo
if desired.
============
*/
void ClientUserinfoChanged(int clientNum) {
	gentity_t *ent;
	char      *s;
	char      oldname[MAX_STRING_CHARS];
	char      userinfo[MAX_INFO_STRING];
	gclient_t *client;
	char      *ip   = NULL; // Nico, used to store client ip
	char      *rate   = NULL; // Nico, used to store client rate
	char      *snaps   = NULL; // Nico, used to store client snaps
	char      *name = NULL; // Nico, used to store client name
	char      oldAuthToken[MAX_QPATH]; // Nico, used to see if auth token was changed

	ent    = g_entities + clientNum;
	client = ent->client;

	client->ps.clientNum = clientNum;

	// Nico, flood protection
	if (ClientIsFlooding(ent)) {
		G_LogPrintf("Dropping client %d: flooded userinfo\n", clientNum);
		trap_DropClient(clientNum, "^1You were kicked because of flooded userinfo", 0);
		return;
	}

	trap_GetUserinfo(clientNum, userinfo, sizeof (userinfo));

	// Nico, perform security checks on userinfo string
	if (!checkUserinfoString(clientNum, userinfo)) {
		return;
	}

	if (g_developer.integer || *g_log.string || g_dedicated.integer) {
		G_Printf("Userinfo: %s\n", userinfo);
	}

	// check for local client
	ip = Info_ValueForKey(userinfo, "ip");
	Q_strncpyz(client->pers.ip, ip, IP_MAX_LENGTH);
	if (ip && !strcmp(ip, "localhost")) {
		client->pers.localClient = qtrue;
		level.fLocalHost         = qtrue;
		client->sess.referee     = RL_REFEREE;
	}

	// Nico, store rate and snaps
	rate = Info_ValueForKey(userinfo, "rate");
	client->pers.rate = atoi(rate);
	snaps = Info_ValueForKey(userinfo, "snaps");
	client->pers.snaps = atoi(snaps);

	// Nico, backup old auth token
	Q_strncpyz(oldAuthToken, client->pers.authToken, sizeof (oldAuthToken));

	s = Info_ValueForKey(userinfo, "cg_uinfo");
	sscanf(s, "%i %i %i %i %s %i %i %i %i %i %i %i %i %i",
	       &client->pers.clientFlags,
	       &client->pers.clientTimeNudge,
	       &client->pers.clientMaxPackets,

	       // Nico, max FPS
	       &client->pers.maxFPS,

	       // Nico, auth Token
	       (char *)&client->pers.authToken,

	       // Nico, load view angles on load
	       &client->pers.loadViewAngles,

		   // Nico, load weapon on load
	       &client->pers.loadWeapon,

	       // Nico, load position when player dies
	       &client->pers.autoLoad,

	       // Nico, cgaz
	       &client->pers.cgaz,

	       // Nico, hideme
	       &client->pers.hideme,

	       // Nico, client auto demo record setting
	       &client->pers.autoDemo,

	       // Nico, automatically load checkpoints
	       &client->pers.autoLoadCheckpoints,

	       // Nico, persistant specLock
	       (int *)&client->sess.specLocked,

	       // Nico, keep all demos
	       &client->pers.keepAllDemos

	       );

	// Nico, check if auth token was changed
	if (oldAuthToken[0] != '\0' &&
		Q_stricmp(oldAuthToken, client->pers.authToken) &&
		client->sess.logged) {
		// Nico, auth token was changed => logout player if he was logged in
		CP("cp \"You are no longer logged in!\n\"");
		G_LogPrintf("ClientUserinfoChanged: authToken changed for client %d, forcing logout\n", clientNum);
		ent->client->sess.logged = qfalse;
	}

	client->pers.autoActivate      = (client->pers.clientFlags & CGF_AUTOACTIVATE) ? PICKUP_TOUCH : PICKUP_ACTIVATE;
	client->pers.predictItemPickup = ((client->pers.clientFlags & CGF_PREDICTITEMS) != 0);

	if (client->pers.clientFlags & CGF_AUTORELOAD) {
		client->pers.bAutoReloadAux = qtrue;
		client->pmext.bAutoReload   = qtrue;
	} else {
		client->pers.bAutoReloadAux = qfalse;
		client->pmext.bAutoReload   = qfalse;
	}

	// Nico, pmove_fixed
	client->pers.pmoveFixed = client->pers.clientFlags & CGF_PMOVEFIXED;

	// Nico, autologin
	client->pers.autoLogin = client->pers.clientFlags & CGF_AUTOLOGIN;

	//
	// Nico, name handling
	//

	// Backup old name
	Q_strncpyz(oldname, client->pers.netname, sizeof (oldname));

	// Get new name from userinfo string
	name = Info_ValueForKey(userinfo, "name");

	// Clean the new name
	ClientCleanName(name, client->pers.netname, sizeof (client->pers.netname));

	// Check it's valid
	if (CheckName(client->pers.netname) != qtrue) {
		// Invalid name, restore old name
		Q_strncpyz(client->pers.netname, oldname, sizeof (client->pers.netname));
		Info_SetValueForKey(userinfo, "name", oldname);
		trap_SetUserinfo(clientNum, userinfo);
		CPx(clientNum, "print \"^1Invalid name, name change refused\n\"");
		G_LogPrintf("Client %d name change refused\n", clientNum);
	} else {
		// Name is valid
		// Now, check if name was changed or not
		if (client->pers.connected == CON_CONNECTED && strcmp(oldname, client->pers.netname) != 0) {
			// Name was changed
			// Now, check name changes limit
			if (g_maxNameChanges.integer > -1 && client->pers.nameChanges >= g_maxNameChanges.integer) {
				// Nico, limit reached, forbid name change
				Q_strncpyz(client->pers.netname, oldname, sizeof (client->pers.netname));
				Info_SetValueForKey(userinfo, "name", oldname);
				trap_SetUserinfo(clientNum, userinfo);
				CPx(clientNum, "print \"^1You had too many namechanges\n\"");
				G_LogPrintf("Client %d name change refused\n", clientNum);
				return;
			}
			client->pers.nameChanges++;
			trap_SendServerCommand(-1, va("print \"%s" S_COLOR_WHITE " renamed to %s\n\"", oldname, client->pers.netname));
		}
	}

	//
	// Nico, end of name handling
	//

	client->ps.stats[STAT_MAX_HEALTH] = client->pers.maxHealth;

	// To communicate it to cgame
	client->ps.stats[STAT_PLAYER_CLASS] = client->sess.playerType;
	// Gordon: Not needed any more as it's in clientinfo?

	// send over a subset of the userinfo keys so other clients can
	// print scoreboards, display models, and play custom sounds

	s = va("n\\%s\\t\\%i\\c\\%i\\w\\%i\\lw\\%i\\sw\\%i\\mu\\%i\\ref\\%i\\pm\\%i\\l\\%i\\h\\%i\\cc\\%i",
	       client->pers.netname,
	       client->sess.sessionTeam,
	       client->sess.playerType,
	       client->sess.playerWeapon,
	       client->sess.latchPlayerWeapon,
	       client->sess.latchPlayerWeapon2,
	       client->sess.muted ? 1 : 0,
	       client->sess.referee,
	       client->pers.pmoveFixed ? 1 : 0, // Nico, pmove_fixed
	       client->sess.logged ? 1 : 0, // Nico, login status
	       client->pers.hideme, // Nico, hideme
		   client->sess.countryCode// Nico, country code (GeoIP)
	       );

	trap_GetConfigstring(CS_PLAYERS + clientNum, oldname, sizeof (oldname));

	trap_SetConfigstring(CS_PLAYERS + clientNum, s);

	if (!Q_stricmp(oldname, s)) {
		return;
	}

	G_LogPrintf("ClientUserinfoChanged: %i %s\n", clientNum, s);
	G_DPrintf("ClientUserinfoChanged: %i :: %s\n", clientNum, s);
}
Exemple #23
0
void Svcmd_BanUser_f( void )
{
	char		str[MAX_TOKEN_CHARS];
	char		userInfo[MAX_TOKEN_CHARS];
	idFilter_t	id;
	int			playerNum;
	char		*ip;

	if ( trap_Argc() < 2 )
	{
		G_Printf("Usage: banUser <client ID> <reason for banning>\n");
		return;		
	}

	trap_Argv( 1, str, sizeof( str ) );

	playerNum = atoi(str);
	if ( playerNum > MAX_CLIENTS || playerNum < 0 || !g_entities[playerNum].client )
	{
		G_Printf("Error: Player ID wasn't valid.\n");
		return;			
	}
	
	trap_GetUserinfo( playerNum, userInfo, sizeof( userInfo ) );
	if ( !userInfo[0] )
		return;

	//get unique Ban ID
	id.playerID = atoul( Info_ValueForKey( userInfo, "sv_securityCode" ) );
	
	//Get player name and clean it of color tags
	Q_strncpyz( id.playerName, Q_CleanStr(Info_ValueForKey( userInfo, "name" )), sizeof( id.playerName ) );
	
	//get ban reason
	trap_Argv( 2, id.banReason, sizeof( id.banReason ) );

	if ( !id.banReason[0] )
		Q_strncpyz( id.banReason, "No reason given.", sizeof( id.banReason ) );

	AddID( &id );
	
	ip = g_entities[playerNum].client->pers.ip;

	UpdateIDBans();

	//Scooter's filter list
	if( Q_stricmp( ip, "localhost" )		//localhost
		&& Q_strncmp( ip, "10.", 3 )		//class A
		&& Q_strncmp( ip, "172.16.", 7 )	//class B
		&& Q_strncmp( ip, "192.168.", 8 )	//class C
		&& Q_strncmp( ip, "127.", 4 )		//loopback
		&& Q_strncmp( ip, "169.254.", 8 )	//link-local
		)
	{
		AddIP( ip );
		G_Printf( "User: %s ( %i - %s ) ^7was successfully banned.\n", Info_ValueForKey( userInfo, "name" ), playerNum, ip );
	}

	trap_DropClient( playerNum, "Banned from the server" );
	G_Printf( "User: %s ( %i ) ^7was successfully banned.\n", id.playerName, playerNum );
}
Exemple #24
0
/*
===========
ClientUserInfoChanged

Called from ClientConnect when the player first connects and
directly by the server system when the player updates a userinfo variable.

The game can override any of the settings and call trap_SetUserinfo
if desired.
============
*/
void ClientUserinfoChanged( int clientNum ) {
	gentity_t *ent;
	int		teamTask, teamLeader;
	char	*s;
	char	model[MAX_QPATH];
	char	headModel[MAX_QPATH];
	char	oldname[MAX_STRING_CHARS];
	gclient_t	*client;
	char	c1[MAX_INFO_STRING];
	char	c2[MAX_INFO_STRING];
	char	userinfo[MAX_INFO_STRING];

	ent = g_entities + clientNum;
	client = ent->client;

	trap_GetUserinfo( clientNum, userinfo, sizeof( userinfo ) );

	// check for malformed or illegal info strings
	if ( !Info_Validate(userinfo) ) {
		strcpy (userinfo, "\\name\\badinfo");
		// don't keep those clients and userinfo
		trap_DropClient(clientNum, "Invalid userinfo");
	}

	// check for local client
	s = Info_ValueForKey( userinfo, "ip" );
	if ( !strcmp( s, "localhost" ) ) {
		client->pers.localClient = qtrue;
	}

	// check the item prediction
	s = Info_ValueForKey( userinfo, "cg_predictItems" );
	if ( !atoi( s ) ) {
		client->pers.predictItemPickup = qfalse;
	} else {
		client->pers.predictItemPickup = qtrue;
	}

	// set name
	Q_strncpyz ( oldname, client->pers.netname, sizeof( oldname ) );
	s = Info_ValueForKey (userinfo, "name");
	ClientCleanName( s, client->pers.netname, sizeof(client->pers.netname) );

	if ( client->sess.sessionTeam == TEAM_SPECTATOR ) {
		if ( client->sess.spectatorState == SPECTATOR_SCOREBOARD ) {
			Q_strncpyz( client->pers.netname, "scoreboard", sizeof(client->pers.netname) );
		}
	}

	if ( client->pers.connected == CON_CONNECTED ) {
		if ( strcmp( oldname, client->pers.netname ) ) {
			trap_SendServerCommand( -1, va("print \"%s" S_COLOR_WHITE " renamed to %s\n\"", oldname, 
				client->pers.netname) );
		}
	}

	// set max health
#ifdef MISSIONPACK
	if (client->ps.powerups[PW_GUARD]) {
		client->pers.maxHealth = 200;
	} else {
		client->pers.maxHealth = ClientHandicap( client );
	}
#else
	client->pers.maxHealth = ClientHandicap( client );
#endif
	client->ps.stats[STAT_MAX_HEALTH] = client->pers.maxHealth;

	// set model
	if( g_gametype.integer >= GT_TEAM ) {
		Q_strncpyz( model, Info_ValueForKey (userinfo, "team_model"), sizeof( model ) );
		Q_strncpyz( headModel, Info_ValueForKey (userinfo, "team_headmodel"), sizeof( headModel ) );
	} else {
		Q_strncpyz( model, Info_ValueForKey (userinfo, "model"), sizeof( model ) );
		Q_strncpyz( headModel, Info_ValueForKey (userinfo, "headmodel"), sizeof( headModel ) );
	}

/*	NOTE: all client side now

	// team
	switch( team ) {
	case TEAM_RED:
		ForceClientSkin(client, model, "red");
//		ForceClientSkin(client, headModel, "red");
		break;
	case TEAM_BLUE:
		ForceClientSkin(client, model, "blue");
//		ForceClientSkin(client, headModel, "blue");
		break;
	}
	// don't ever use a default skin in teamplay, it would just waste memory
	// however bots will always join a team but they spawn in as spectator
	if ( g_gametype.integer >= GT_TEAM && team == TEAM_SPECTATOR) {
		ForceClientSkin(client, model, "red");
//		ForceClientSkin(client, headModel, "red");
	}
*/

#ifdef MISSIONPACK
	if (g_gametype.integer >= GT_TEAM) {
		client->pers.teamInfo = qtrue;
	} else {
		s = Info_ValueForKey( userinfo, "teamoverlay" );
		if ( ! *s || atoi( s ) != 0 ) {
			client->pers.teamInfo = qtrue;
		} else {
			client->pers.teamInfo = qfalse;
		}
	}
#else
	// teamInfo
	s = Info_ValueForKey( userinfo, "teamoverlay" );
	if ( ! *s || atoi( s ) != 0 ) {
		client->pers.teamInfo = qtrue;
	} else {
		client->pers.teamInfo = qfalse;
	}
#endif
	/*
	s = Info_ValueForKey( userinfo, "cg_pmove_fixed" );
	if ( !*s || atoi( s ) == 0 ) {
		client->pers.pmoveFixed = qfalse;
	}
	else {
		client->pers.pmoveFixed = qtrue;
	}
	*/

	// team task (0 = none, 1 = offence, 2 = defence)
	teamTask = atoi(Info_ValueForKey(userinfo, "teamtask"));
	// team Leader (1 = leader, 0 is normal player)
	teamLeader = client->sess.teamLeader;

	// colors
	strcpy(c1, Info_ValueForKey( userinfo, "color1" ));
	strcpy(c2, Info_ValueForKey( userinfo, "color2" ));

	// send over a subset of the userinfo keys so other clients can
	// print scoreboards, display models, and play custom sounds
	if (ent->r.svFlags & SVF_BOT)
	{
		s = va("n\\%s\\t\\%i\\model\\%s\\hmodel\\%s\\c1\\%s\\c2\\%s\\hc\\%i\\w\\%i\\l\\%i\\skill\\%s\\tt\\%d\\tl\\%d",
			client->pers.netname, client->sess.sessionTeam, model, headModel, c1, c2, 
			client->pers.maxHealth, client->sess.wins, client->sess.losses,
			Info_ValueForKey( userinfo, "skill" ), teamTask, teamLeader );
	}
	else
	{
		s = va("n\\%s\\t\\%i\\model\\%s\\hmodel\\%s\\c1\\%s\\c2\\%s\\hc\\%i\\w\\%i\\l\\%i\\tt\\%d\\tl\\%d",
			client->pers.netname, client->sess.sessionTeam, model, headModel, c1, c2, 
			client->pers.maxHealth, client->sess.wins, client->sess.losses, teamTask, teamLeader);
	}

	trap_SetConfigstring( CS_PLAYERS+clientNum, s );

	// this is not the userinfo, more like the configstring actually
	G_LogPrintf( "ClientUserinfoChanged: %i %s\n", clientNum, s );
}
Exemple #25
0
static void Svcmd_Kick_f( void ) {
	gclient_t	*cl;
	int			i;
	int			timeout = -1;
	char		sTimeout[MAX_TOKEN_CHARS];
	char		name[MAX_TOKEN_CHARS];

	// make sure server is running
	if ( !G_Is_SV_Running() ) {
		G_Printf( "Server is not running.\n" );
		return;
	}

	if ( trap_Argc() < 2 || trap_Argc() > 3 ) {
		G_Printf ("Usage: kick <player name> [timeout]\n");
		return;
	}

	if( trap_Argc() == 3 ) {
		trap_Argv( 2, sTimeout, sizeof( sTimeout ) );
		timeout = atoi( sTimeout );
	} else {
		timeout = 300;
	}

	trap_Argv(1, name, sizeof(name));
	cl = G_GetPlayerByName( name );//ClientForString( name );

	if ( !cl ) {
		if ( !Q_stricmp(name, "all") ) {
			for (i = 0, cl = level.clients; i < level.numConnectedClients; i++, cl++) {
		
				// dont kick localclients ...
				if ( cl->pers.localClient ) {
					continue;
				}

				if ( timeout != -1 ) {
					char *ip;
					char userinfo[MAX_INFO_STRING];
					
					trap_GetUserinfo( cl->ps.clientNum, userinfo, sizeof( userinfo ) );
					ip = Info_ValueForKey (userinfo, "ip");
					
					// use engine banning system, mods may choose to use their own banlist
					if (USE_ENGINE_BANLIST) { 
						
						// kick but dont ban bots, they arent that lame
						if ( (g_entities[cl->ps.clientNum].r.svFlags & SVF_BOT) ) {
							timeout = 0;
						}

						trap_DropClient(cl->ps.clientNum, "player kicked", timeout);
					} else {
						trap_DropClient(cl->ps.clientNum, "player kicked", 0);
						
						// kick but dont ban bots, they arent that lame
						if ( !(g_entities[cl->ps.clientNum].r.svFlags & SVF_BOT) )
							AddIPBan( ip );
					}

				} else {
					trap_DropClient(cl->ps.clientNum, "player kicked", 0);				
				}
			}
		}
#ifndef NO_BOT_SUPPORT
		else if ( !Q_stricmp(name, "allbots") ) {
			for (i = 0, cl = level.clients; i < level.numConnectedClients; i++, cl++) {
				if ( !(g_entities[cl->ps.clientNum].r.svFlags & SVF_BOT) ) {
					continue;
				}
				// kick but dont ban bots, they arent that lame
				trap_DropClient(cl->ps.clientNum, "player kicked", 0);
			}
		}
#endif
		return;
	} else {
		// dont kick localclients ...
		if ( cl->pers.localClient ) {
			G_Printf("Cannot kick host player\n");
			return;
		}

		if ( timeout != -1 ) {
			char *ip;
			char userinfo[MAX_INFO_STRING];
			
			trap_GetUserinfo( cl->ps.clientNum, userinfo, sizeof( userinfo ) );
			ip = Info_ValueForKey (userinfo, "ip");
			
			// use engine banning system, mods may choose to use their own banlist
			if (USE_ENGINE_BANLIST) { 
				
				// kick but dont ban bots, they arent that lame
				if ( (g_entities[cl->ps.clientNum].r.svFlags & SVF_BOT) ) {
					timeout = 0;
				}
				trap_DropClient(cl->ps.clientNum, "player kicked", timeout);
			} else {
				trap_DropClient(cl->ps.clientNum, "player kicked", 0);
				
				// kick but dont ban bots, they arent that lame
				if ( !(g_entities[cl->ps.clientNum].r.svFlags & SVF_BOT) )
					AddIPBan( ip );
			}

		} else {
			trap_DropClient(cl->ps.clientNum, "player kicked", 0);				
		}
	}
}
Exemple #26
0
/*
* ClientUserinfoChanged
* called whenever the player updates a userinfo variable.
* 
* The game can override any of the settings in place
* (forcing skins or names, etc) before copying it off.
*/
void ClientUserinfoChanged( edict_t *ent, char *userinfo )
{
	char *s;
	char oldname[MAX_INFO_VALUE];
	gclient_t *cl;

	int rgbcolor, i;

	assert( ent && ent->r.client );
	assert( userinfo && Info_Validate( userinfo ) );

	// check for malformed or illegal info strings
	if( !Info_Validate( userinfo ) )
	{
		trap_DropClient( ent, DROP_TYPE_GENERAL, "Error: Invalid userinfo" );
		return;
	}

	cl = ent->r.client;

	// ip
	s = Info_ValueForKey( userinfo, "ip" );
	if( !s )
	{
		trap_DropClient( ent, DROP_TYPE_GENERAL, "Error: Server didn't provide client IP" );
		return;
	}

	Q_strncpyz( cl->ip, s, sizeof( cl->ip ) );

	// socket
	s = Info_ValueForKey( userinfo, "socket" );
	if( !s )
	{
		trap_DropClient( ent, DROP_TYPE_GENERAL, "Error: Server didn't provide client socket" );
		return;
	}

	Q_strncpyz( cl->socket, s, sizeof( cl->socket ) );

	// color
	s = Info_ValueForKey( userinfo, "color" );
	if( s )
		rgbcolor = COM_ReadColorRGBString( s );
	else
		rgbcolor = -1;

	if( rgbcolor != -1 )
	{
		rgbcolor = COM_ValidatePlayerColor( rgbcolor );
		Vector4Set( cl->color, COLOR_R( rgbcolor ), COLOR_G( rgbcolor ), COLOR_B( rgbcolor ), 255 );
	}
	else
	{
		Vector4Set( cl->color, 255, 255, 255, 255 );
	}

	// set name, it's validated and possibly changed first
	Q_strncpyz( oldname, cl->netname, sizeof( oldname ) );
	G_SetName( ent, Info_ValueForKey( userinfo, "name" ) );
	if( oldname[0] && Q_stricmp( oldname, cl->netname ) && !cl->isTV && !CheckFlood( ent, false ) )
		G_PrintMsg( NULL, "%s%s is now known as %s%s\n", oldname, S_COLOR_WHITE, cl->netname, S_COLOR_WHITE );
	if( !Info_SetValueForKey( userinfo, "name", cl->netname ) )
	{
		trap_DropClient( ent, DROP_TYPE_GENERAL, "Error: Couldn't set userinfo (name)" );
		return;
	}

	// clan tag
	G_SetClan( ent, Info_ValueForKey( userinfo, "clan" ) );

	// handedness
	s = Info_ValueForKey( userinfo, "hand" );
	if( !s )
		cl->hand = 2;
	else
		cl->hand = bound( atoi( s ), 0, 2 );

	// handicap
	s = Info_ValueForKey( userinfo, "handicap" );
	if( s )
	{
		i = atoi( s );

		if( i > 90 || i < 0 )
		{
			G_PrintMsg( ent, "Handicap must be defined in the [0-90] range.\n" );
			cl->handicap = 0;
		}
		else
		{
			cl->handicap = i;
		}
	}

	s = Info_ValueForKey( userinfo, "cg_movementStyle" );
	if( s )
	{
		i = bound( atoi( s ), 0, GS_MAXBUNNIES - 1 );
		if( trap_GetClientState( PLAYERNUM(ent) ) < CS_SPAWNED )
		{
			if( i != cl->movestyle )
				cl->movestyle = cl->movestyle_latched = i;
		}
		else if( cl->movestyle_latched != cl->movestyle )
		{
			G_PrintMsg( ent, "A movement style change is already in progress. Please wait.\n" );
		}
		else if( i != cl->movestyle_latched )
		{
			cl->movestyle_latched = i;
			if( cl->movestyle_latched != cl->movestyle )
			{
				edict_t *switcher;

				switcher = G_Spawn();
				switcher->think = think_MoveTypeSwitcher;
				switcher->nextThink = level.time + 10000;
				switcher->s.ownerNum = ENTNUM( ent );
				G_PrintMsg( ent, "Movement style will change in 10 seconds.\n" );
			}
		}
	}

	// update the movement features depending on the movestyle
	if( !G_ISGHOSTING( ent ) && g_allow_bunny->integer )
	{
		if( cl->movestyle == GS_CLASSICBUNNY )
			cl->ps.pmove.stats[PM_STAT_FEATURES] &= ~PMFEAT_FWDBUNNY;
		else
			cl->ps.pmove.stats[PM_STAT_FEATURES] |= PMFEAT_FWDBUNNY;
	}

	s = Info_ValueForKey( userinfo, "cg_noAutohop" );
	if( s && s[0] )
	{
		if( atoi( s ) != 0 )
			cl->ps.pmove.stats[PM_STAT_FEATURES] &= ~PMFEAT_CONTINOUSJUMP;
		else
			cl->ps.pmove.stats[PM_STAT_FEATURES] |= PMFEAT_CONTINOUSJUMP;
	}

#ifdef UCMDTIMENUDGE
	s = Info_ValueForKey( userinfo, "cl_ucmdTimeNudge" );
	if( !s )
	{
		cl->ucmdTimeNudge = 0;
	}
	else
	{
		cl->ucmdTimeNudge = atoi( s );
		clamp( cl->ucmdTimeNudge, -MAX_UCMD_TIMENUDGE, MAX_UCMD_TIMENUDGE );
	}
#endif

	// mm session
	// TODO: remove the key after storing it to gclient_t !
	s = Info_ValueForKey( userinfo, "cl_mm_session" );
	cl->mm_session = ( s == NULL ) ? 0 : atoi( s );

	s = Info_ValueForKey( userinfo, "mmflags" );
	cl->mmflags = ( s == NULL ) ? 0 : strtoul( s, NULL, 10 );

	// tv
	if( cl->isTV )
	{
		s = Info_ValueForKey( userinfo, "tv_port" );
		cl->tv.port = s ? atoi( s ) : 0;

		s = Info_ValueForKey( userinfo, "tv_port6" );
		cl->tv.port6 = s ? atoi( s ) : 0;

		s = Info_ValueForKey( userinfo, "max_cl" );
		cl->tv.maxclients = s ? atoi( s ) : 0;

		s = Info_ValueForKey( userinfo, "num_cl" );
		cl->tv.numclients = s ? atoi( s ) : 0;

		s = Info_ValueForKey( userinfo, "chan" );
		cl->tv.channel = s ? atoi( s ) : 0;
	}

	if( !G_ISGHOSTING( ent ) && trap_GetClientState( PLAYERNUM( ent ) ) >= CS_SPAWNED )
		G_Client_AssignTeamSkin( ent, userinfo );

	// save off the userinfo in case we want to check something later
	Q_strncpyz( cl->userinfo, userinfo, sizeof( cl->userinfo ) );

	G_UpdatePlayerInfoString( PLAYERNUM( ent ) );
	G_UpdateMMPlayerInfoString( PLAYERNUM( ent ) );

	G_Gametype_ScoreEvent( cl, "userinfochanged", oldname );
}
Exemple #27
0
/**
Called from ClientConnect when the player first connects and
directly by the server system when the player updates a userinfo variable.

The game can override any of the settings and call trap_SetUserinfo
if desired.
*/
void ClientUserinfoChanged(int clientNum)
{
	gentity_t *ent;
	int		teamTask, teamLeader, team, health;
	char	*s;
	char	oldname[MAX_STRING_CHARS];
	gclient_t	*client;
	char	userinfo[MAX_INFO_STRING];
	char	*nameError;

	ent = g_entities + clientNum;
	client = ent->client;

	trap_GetUserinfo(clientNum, userinfo, sizeof(userinfo));

	// check for malformed or illegal info strings
	if (!Info_Validate(userinfo)) {
		strcpy (userinfo, "\\name\\badinfo");
		// don't keep those clients and userinfo
		trap_DropClient(clientNum, "Invalid userinfo");
	}

	// check for local client
	s = Info_ValueForKey(userinfo, "ip");
	if (!strcmp(s, "localhost")) {
		client->pers.localClient = qtrue;
	}

	// check the item prediction
	s = Info_ValueForKey(userinfo, "cg_predictItems");
	if (!atoi(s)) {
		client->pers.predictItemPickup = qfalse;
	} else {
		client->pers.predictItemPickup = qtrue;
	}

	// set name
	Q_strncpyz(oldname, client->pers.netname, sizeof(oldname));
	s = Info_ValueForKey(userinfo, "name");
	nameError = ClientCleanName(s, client->pers.netname, sizeof client->pers.netname);

	if (client->pers.connected == CON_CONNECTED && strcmp(oldname, s)) {
		if (client->pers.muted) {
			ClientPrint(ent, "You cannot change your name while you are muted.");
		} else if (nameError) {
			ClientPrint(ent, "%s", nameError);
		} else {
			G_LogPrintf("%s ^7renamed to %s\n", oldname, client->pers.netname);
		}

		if (nameError || client->pers.muted) {
			Q_strncpyz(client->pers.netname, oldname, sizeof client->pers.netname);
		}
	}

	if (client->sess.sessionTeam == TEAM_SPECTATOR) {
		if (client->sess.spectatorState == SPECTATOR_SCOREBOARD) {
			Q_strncpyz(client->pers.netname, "scoreboard", sizeof(client->pers.netname));
		}
	}

	// set max health
	health = atoi(Info_ValueForKey(userinfo, "handicap"));
	client->pers.maxHealth = health;
	if (client->pers.maxHealth < 1 || client->pers.maxHealth > 100) {
		client->pers.maxHealth = 100;
	}
	client->ps.stats[STAT_MAX_HEALTH] = client->pers.maxHealth;

	// bots set their team a few frames later
	if (g_gametype.integer >= GT_TEAM && g_entities[clientNum].r.svFlags & SVF_BOT) {
		s = Info_ValueForKey(userinfo, "team");
		if (!Q_stricmp(s, "red") || !Q_stricmp(s, "r")) {
			team = TEAM_RED;
		} else if (!Q_stricmp(s, "blue") || !Q_stricmp(s, "b")) {
			team = TEAM_BLUE;
		} else {
			// pick the team with the least number of players
			team = PickTeam(clientNum);
		}
	}
	else {
		team = client->sess.sessionTeam;
	}

	// team task (0 = none, 1 = offence, 2 = defence)
	teamTask = atoi(Info_ValueForKey(userinfo, "teamtask"));
	// team Leader (1 = leader, 0 is normal player)
	teamLeader = client->sess.teamLeader;

	// send over a subset of the userinfo keys so other clients can
	// print scoreboards, display models, and play custom sounds
	if (ent->r.svFlags & SVF_BOT) {
		s = va("n\\%s\\t\\%i\\hc\\%i\\w\\%i\\l\\%i\\skill\\%s\\tt\\%d\\tl\\%d",
			client->pers.netname, team, client->pers.maxHealth,
			client->sess.wins, client->sess.losses,
			Info_ValueForKey(userinfo, "skill"), teamTask, teamLeader);
	}
	else {
		s = va("n\\%s\\t\\%i\\s\\%d\\r\\%i\\hc\\%i\\w\\%i\\l\\%i\\tt\\%d\\tl\\%d",
			client->pers.netname, team, client->sess.specOnly,
			client->pers.ready, client->pers.maxHealth,
			client->sess.wins, client->sess.losses, teamTask, teamLeader);
	}

	trap_SetConfigstring(CS_PLAYERS+clientNum, s);

	// this is not the userinfo, more like the configstring actually
	G_LogPrintf("ClientUserinfoChanged: %i %s\n", clientNum, s);
}