/*
===================
Svcmd_ForceTeam_f

forceteam <player> <team>
===================
*/
static void Svcmd_ForceTeam_f( void )
{
  gclient_t *cl;
  char      str[ MAX_TOKEN_CHARS ];
  team_t    team;

  if( trap_Argc( ) != 3 )
  {
    G_Printf( "usage: forceteam <player> <team>\n" );
    return;
  }

  trap_Argv( 1, str, sizeof( str ) );
  cl = ClientForString( str );

  if( !cl )
    return;

  trap_Argv( 2, str, sizeof( str ) );
  team = G_TeamFromString( str );
  if( team == NUM_TEAMS )
  {
    G_Printf( "forceteam: invalid team \"%s\"\n", str );
    return;
  }
  G_ChangeTeam( &g_entities[ cl - level.clients ], team );
}
void G_namelog_restore( gclient_t *client )
{
  namelog_t *n = client->pers.namelog;

  G_ChangeTeam( g_entities + n->slot, n->team );
  client->ps.persistant[ PERS_SCORE ] = n->score;
  client->ps.persistant[ PERS_CREDIT ] = 0;
  G_AddCreditToClient( client, n->credits, qfalse );
}
Exemple #3
0
bool G_BotAdd( const char *name, team_t team, int skill, const char *behavior, bool filler )
{
	int clientNum;
	char userinfo[MAX_INFO_STRING];
	const char* s = 0;
	gentity_t *bot;
	bool autoname = false;
	bool okay;

	if ( !navMeshLoaded )
	{
		Log::Warn( "No Navigation Mesh file is available for this map" );
		return false;
	}

	// find what clientNum to use for bot
	clientNum = trap_BotAllocateClient();

	if ( clientNum < 0 )
	{
		Log::Warn( "no more slots for bot" );
		return false;
	}
	bot = &g_entities[ clientNum ];
	bot->r.svFlags |= SVF_BOT;
	bot->inuse = true;

	if ( !Q_stricmp( name, BOT_NAME_FROM_LIST ) )
	{
		name = G_BotSelectName( team );
		autoname = name != nullptr;
	}

	//default bot data
	okay = G_BotSetDefaults( clientNum, team, skill, behavior );

	// register user information
	userinfo[0] = '\0';
	Info_SetValueForKey( userinfo, "name", name ? name : "", false ); // allow defaulting
	Info_SetValueForKey( userinfo, "rate", "25000", false );
	Info_SetValueForKey( userinfo, "snaps", "20", false );
	if ( autoname )
	{
		Info_SetValueForKey( userinfo, "autoname", name, false );
	}

	//so we can connect if server is password protected
	if ( g_needpass.integer == 1 )
	{
		Info_SetValueForKey( userinfo, "password", g_password.string, false );
	}

	trap_SetUserinfo( clientNum, userinfo );

	// have it connect to the game as a normal client
	if ( ( s = ClientBotConnect( clientNum, true, team ) ) )
	{
		// won't let us join
		Log::Warn( s );
		okay = false;
	}

	if ( !okay )
	{
		G_BotDel( clientNum );
		return false;
	}

	if ( autoname )
	{
		G_BotNameUsed( team, name, true );
	}

	ClientBegin( clientNum );
	bot->pain = BotPain; // ClientBegin resets the pain function
	level.clients[clientNum].pers.isFillerBot = filler;
	G_ChangeTeam( bot, team );
	return true;
}
Exemple #4
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 #5
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 #6
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;
  gclient_t *client;
  char      userinfo[ MAX_INFO_STRING ];
  gentity_t *ent;
  char      guid[ 33 ];
  char      ip[ 16 ] = {""};
  char      reason[ MAX_STRING_CHARS ] = {""};
  int       i;
  int       retval = 0;

  ent = &g_entities[ clientNum ];

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

  value = Info_ValueForKey( userinfo, "cl_guid" );
  Q_strncpyz( guid, value, sizeof( guid ) );

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


  // IP filtering
  // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=500
  // recommanding PB based IP / GUID banning, the builtin system is pretty limited
  // check to see if they are on the banned IP list
  value = Info_ValueForKey( userinfo, "ip" );
  i = 0;
  while( *value && i < sizeof( ip ) - 2 )
  {
    if( *value != '.' && ( *value < '0' || *value > '9' ) )
      break;
    ip[ i++ ] = *value;
    value++;
  }
  ip[ i ] = '\0';
  if( G_FilterPacket( value ) )
    return "You are banned from this server.";

  // 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";

  // they can connect
  ent->client = level.clients + clientNum;
  client = ent->client;

  memset( client, 0, sizeof(*client) );

  // add guid to session so we don't have to keep parsing userinfo everywhere
  if( !guid[0] )
  {
    Q_strncpyz( client->pers.guid, "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
      sizeof( client->pers.guid ) );
  }
  else
  {
    Q_strncpyz( client->pers.guid, guid, sizeof( client->pers.guid ) );
  }
  Q_strncpyz( client->pers.ip, ip, sizeof( client->pers.ip ) );
  client->pers.adminLevel = G_admin_level( ent );

  client->pers.connected = CON_CONNECTING;

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

  G_ReadSessionData( client );

  if( firstTime )
    client->pers.firstConnect = qtrue;
  else
    client->pers.firstConnect = qfalse;

  // get and distribute relevent paramters
  ClientUserinfoChanged( clientNum );
  
  G_admin_set_adminname( ent );
  
  if( g_decolourLogfiles.integer )
  {
   char    decoloured[ MAX_STRING_CHARS ] = "";   
   if( g_decolourLogfiles.integer == 1 )
   {
     Com_sprintf( decoloured, sizeof(decoloured), " (\"%s^7\")", client->pers.netname );
     G_DecolorString( decoloured, decoloured );
     G_LogPrintfColoured( "ClientConnect: %i [%s] (%s) \"%s^7\"%s\n", clientNum,
        client->pers.ip, client->pers.guid, client->pers.netname, decoloured );
   }
   else
   {
      G_LogPrintf( "ClientConnect: %i [%s] (%s) \"%s^7\"%s\n", clientNum,
          client->pers.ip, client->pers.guid, client->pers.netname, decoloured );
   }
  }
  else
  {
    G_LogPrintf( "ClientConnect: %i [%s] (%s) \"%s^7\"\n", clientNum,
      client->pers.ip, client->pers.guid, client->pers.netname );
  }
  
  if( client->pers.adminLevel )
  { 
     G_LogPrintf( "ClientAuth: %i [%s] \"%s^7\" authenticated to admin level %i using GUID %s (^7%s)\n", clientNum, client->pers.ip, client->pers.netname, client->pers.adminLevel, client->pers.guid, client->pers.adminName );
  }

  // don't do the "xxx connected" messages if they were caried over from previous level
	
	retval = G_admin_global_check(userinfo);
	if((retval & GLOBAL_FORCESPEC) ||
	   (retval & GLOBAL_MUTE) ||
	   (retval & GLOBAL_DENYBUILD)){trap_SendServerCommand( -1, va( "print \"^3!global: ^7%s^7 has restrictions\n\"", client->pers.netname ) );}
	else if(retval & GLOBAL_WHITELIST){trap_SendServerCommand( -1, va( "print \"^3!global: ^7%s^7 is whitelisted\n\"", client->pers.netname ) );}	
	if(retval & GLOBAL_FORCESPEC){client->pers.specd = qtrue;}
	if(retval & GLOBAL_MUTE){client->pers.muted = qtrue;}
	if(retval & GLOBAL_DENYBUILD){client->pers.denyBuild = qtrue;}
	
  if( firstTime )
    trap_SendServerCommand( -1, va( "print \"%s" S_COLOR_WHITE " connected\n\"", client->pers.netname ) );

  // count current clients and rank for scoreboard
  CalculateRanks( );
  G_admin_namelog_update( client, qfalse );
  

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

  
  return NULL;
}
Exemple #7
0
/**
 * Add one bot into a team
 * @param name [string] bot's name
 * @param team [team_t] alien or human
 */
qboolean G_BotAdd( char *name, team_t team ) {
	int i;
	int clientNum;
	char userinfo[MAX_INFO_STRING];
	int reservedSlots = 0;
	gentity_t *ent;
    namelog_t *namelog;
    char name_s[ MAX_NAME_LENGTH ];
    char name_tmp_s[ MAX_NAME_LENGTH ] = "";
	
	reservedSlots = trap_Cvar_VariableIntegerValue( "sv_privateclients" );

	//If bot name does not contains [BOT], prepend it.
	if(g_bot_tagname.integer == 1) {
		G_DecolorString(name, name_s, MAX_NAME_LENGTH);
		if (! (Com_StringContains(name_s, "[BOT]", 0))) {
			if(team == TEAM_HUMANS) {
				strcat(name_tmp_s, "^4[BOT] ");
			} else if(team == TEAM_ALIENS) {
				strcat(name_tmp_s, "^1[BOT] ");
			}
			strcat(name_tmp_s, name);
			strcpy(name, name_tmp_s);
		}
	}
    // LEPE: check if no player/bot exists with that name	
    G_SanitiseString(name, name_s, sizeof(name_s) );
    for( namelog = level.namelogs; namelog; namelog = namelog->next ) {
        if( namelog->slot >= 0 ) {
            for( i = 0; i < MAX_NAMELOG_NAMES && namelog->name[ i ][ 0 ]; i++ ) {
                G_SanitiseString(namelog->name[ i ], name_tmp_s, sizeof(name_tmp_s) );
                if( i == namelog->nameOffset && namelog->slot > -1 && !strcmp( name_s, name_tmp_s ) ) {
                    trap_Print("Nick already exists\n");
                    return qfalse;
                }
            }
        }
    }
	// find what clientNum to use for bot
	// LEPE: clientNum calculation was modified to prevent player hijacking
        // We will assign slots from maxclients - 1 to maxclients - reservedSlots - 1
	clientNum = -1;
	for( i = level.maxclients - 1; i > level.maxclients - reservedSlots - 1; i-- ) {
		if( !g_entities[i].inuse ) {
			clientNum = i;
			break;
		}
	}
	if(clientNum == -1)
	{
		trap_Print("Error: Bots were not assigned correctly\n"); //LEPE
		return qfalse;
	}
	if(clientNum < level.maxclients - reservedSlots - 1) 
	{
		trap_Print("no more slots for bot\n");
		return qfalse;
	}
	
	ent = &g_entities[ clientNum ];
	ent->inuse = qtrue;
	ent->bot = (bot_t *)BG_Alloc( sizeof(bot_t) );
//	ent->bot->path.crumb = BG_Alloc( sizeof(level.paths) );
	
	ent->r.svFlags |= SVF_BOT;
	// register user information
	userinfo[0] = '\0';
	Info_SetValueForKey( userinfo, "name", name );
	Info_SetValueForKey( userinfo, "rate", "25000" ); //25000
	Info_SetValueForKey( userinfo, "snaps", "40" );
	//so we can connect if server is password protected
	if(g_needpass.integer == 1) {
		  Info_SetValueForKey( userinfo, "password", g_password.string);
	}
	trap_SetUserinfo( clientNum, userinfo );
	
	// have it connect to the game as a normal client
	if(ClientConnect(clientNum, qtrue) != NULL ) {
		G_Printf("Something weird happened. Bot was not added.");
		// won't let us join
		return qfalse;
	}
	ClientBegin( clientNum );
    G_BotDebug(ent, BOT_VERB_IMPORTANT, BOT_DEBUG_GENERAL, "Bot Added\n");
	G_ChangeTeam( ent, team );
	BotInit( ent );
    if(team == TEAM_HUMANS) {
		BotInitHuman( ent );
		level.humanBots++;
    } else if(team == TEAM_ALIENS) {
		BotInitAlien( ent );
		level.alienBots++;
	}
	//TODO: load profile
	return qtrue;
}