Пример #1
0
/*
* ClientCommand
*/
void ClientCommand( edict_t *ent )
{
	char *cmd;
	int i;

	if( !ent->r.client || trap_GetClientState( PLAYERNUM( ent ) ) < CS_SPAWNED )
		return; // not fully in game yet

	cmd = trap_Cmd_Argv( 0 );

	if( Q_stricmp( cmd, "cvarinfo" ) ) // skip cvarinfo cmds because they are automatic responses
		G_Client_UpdateActivity( ent->r.client ); // activity detected

	for( i = 0; i < MAX_GAMECOMMANDS; i++ )
	{
		if( !g_Commands[i].name[0] )
			break;

		if( !Q_stricmp( g_Commands[i].name, cmd ) )
		{
			if( g_Commands[i].func )
				g_Commands[i].func( ent );
			else
				GT_asCallGameCommand( ent->r.client, cmd, trap_Cmd_Args(), trap_Cmd_Argc() - 1 );
			return;
		}
	}

	G_PrintMsg( ent, "Bad user command: %s\n", cmd );
}
Пример #2
0
/*
* ClientBegin
* called when a client has finished connecting, and is ready
* to be placed into the game.  This will happen every level load.
*/
void ClientBegin( edict_t *ent )
{
	gclient_t *client = ent->r.client;
	const char *mm_login;

	memset( &client->ucmd, 0, sizeof( client->ucmd ) );
	memset( &client->level, 0, sizeof( client->level ) );
	client->level.timeStamp = level.time;
	G_Client_UpdateActivity( client ); // activity detected

	client->team = TEAM_SPECTATOR;
	G_ClientRespawn( ent, true ); // respawn as ghost
	ent->movetype = MOVETYPE_NOCLIP; // allow freefly

	G_UpdatePlayerMatchMsg( ent );

	mm_login = Info_ValueForKey( client->userinfo, "cl_mm_login" );
	if( mm_login && *mm_login && client->mm_session > 0 ) {
		G_PrintMsg( NULL, "%s" S_COLOR_WHITE " (" S_COLOR_YELLOW "%s" S_COLOR_WHITE ") entered the game\n", client->netname, mm_login );
	}
	else {
		if( !level.gametype.disableObituaries || !(ent->r.svflags & SVF_FAKECLIENT ) )
			G_PrintMsg( NULL, "%s" S_COLOR_WHITE " entered the game\n", client->netname );
	}

	client->level.respawnCount = 0; // clear respawncount
	client->connecting = false;

	// schedule the next scoreboard update
	client->level.scoreboard_time = game.realtime + scoreboardInterval - ( game.realtime%scoreboardInterval );

	AI_EnemyAdded( ent );

	G_ClientEndSnapFrame( ent ); // make sure all view stuff is valid

	// let the gametype scripts now this client just entered the level
	G_Gametype_ScoreEvent( client, "enterGame", NULL );
}
Пример #3
0
/*
* ClientThink
*/
void ClientThink( edict_t *ent, usercmd_t *ucmd, int timeDelta )
{
	gclient_t *client;
	int i, j;
	static pmove_t pm;
	int delta, count;

	client = ent->r.client;

	client->ps.POVnum = ENTNUM( ent );
	client->ps.playerNum = PLAYERNUM( ent );

	// anti-lag
	if( ent->r.svflags & SVF_FAKECLIENT )
	{
		client->timeDelta = 0;
	}
	else
	{
		int nudge;
		int fixedNudge = ( game.snapFrameTime ) * 0.5; // fixme: find where this nudge comes from.

		// add smoothing to timeDelta between the last few ucmds and a small fine-tuning nudge.
		nudge = fixedNudge + g_antilag_timenudge->integer;
		timeDelta += nudge;
		clamp( timeDelta, -g_antilag_maxtimedelta->integer, 0 );

		// smooth using last valid deltas
		i = client->timeDeltasHead - 6;
		if( i < 0 ) i = 0;
		for( count = 0, delta = 0; i < client->timeDeltasHead; i++ )
		{
			if( client->timeDeltas[i & G_MAX_TIME_DELTAS_MASK] < 0 )
			{
				delta += client->timeDeltas[i & G_MAX_TIME_DELTAS_MASK];
				count++;
			}
		}

		if( !count )
			client->timeDelta = timeDelta;
		else
		{
			delta /= count;
			client->timeDelta = ( delta + timeDelta ) * 0.5;
		}

		client->timeDeltas[client->timeDeltasHead & G_MAX_TIME_DELTAS_MASK] = timeDelta;
		client->timeDeltasHead++;

#ifdef UCMDTIMENUDGE
		client->timeDelta += client->pers.ucmdTimeNudge;
#endif
	}

	clamp( client->timeDelta, -g_antilag_maxtimedelta->integer, 0 );

	// update activity if he touched any controls
	if( ucmd->forwardmove != 0 || ucmd->sidemove != 0 || ucmd->upmove != 0 || ( ucmd->buttons & ~BUTTON_BUSYICON ) != 0
		|| client->ucmd.angles[PITCH] != ucmd->angles[PITCH] || client->ucmd.angles[YAW] != ucmd->angles[YAW] )
		G_Client_UpdateActivity( client );

	client->ucmd = *ucmd;

	// can exit intermission after two seconds, not counting postmatch
	if( GS_MatchState() == MATCH_STATE_WAITEXIT && ( ucmd->buttons & BUTTON_ATTACK ) && game.serverTime > GS_MatchStartTime() + 2000 )
		level.exitNow = true;

	// (is this really needed?:only if not cared enough about ps in the rest of the code)
	// refresh player state position from the entity
	VectorCopy( ent->s.origin, client->ps.pmove.origin );
	VectorCopy( ent->velocity, client->ps.pmove.velocity );
	VectorCopy( ent->s.angles, client->ps.viewangles );

	client->ps.pmove.gravity = level.gravity;

	if( GS_MatchState() >= MATCH_STATE_POSTMATCH || GS_MatchPaused() 
		|| ( ent->movetype != MOVETYPE_PLAYER && ent->movetype != MOVETYPE_NOCLIP ) )
		client->ps.pmove.pm_type = PM_FREEZE;
	else if( ent->s.type == ET_GIB )
		client->ps.pmove.pm_type = PM_GIB;
	else if( ent->movetype == MOVETYPE_NOCLIP || client->isTV )
		client->ps.pmove.pm_type = PM_SPECTATOR;
	else
		client->ps.pmove.pm_type = PM_NORMAL;

	// set up for pmove
	memset( &pm, 0, sizeof( pmove_t ) );
	pm.playerState = &client->ps;

	if( !client->isTV )
		pm.cmd = *ucmd;

	if( memcmp( &client->old_pmove, &client->ps.pmove, sizeof( pmove_state_t ) ) )
		pm.snapinitial = true;

	// perform a pmove
	Pmove( &pm );

	// save results of pmove
	client->old_pmove = client->ps.pmove;

	// update the entity with the new position
	VectorCopy( client->ps.pmove.origin, ent->s.origin );
	VectorCopy( client->ps.pmove.velocity, ent->velocity );
	VectorCopy( client->ps.viewangles, ent->s.angles );
	ent->viewheight = client->ps.viewheight;
	VectorCopy( pm.mins, ent->r.mins );
	VectorCopy( pm.maxs, ent->r.maxs );

	ent->waterlevel = pm.waterlevel;
	ent->watertype = pm.watertype;
	if( pm.groundentity == -1 )
	{
		ent->groundentity = NULL;
	}
	else
	{
		G_AwardResetPlayerComboStats( ent );

		ent->groundentity = &game.edicts[pm.groundentity];
		ent->groundentity_linkcount = ent->groundentity->linkcount;
	}
	
	GClip_LinkEntity( ent );

	GS_AddLaserbeamPoint( &ent->r.client->resp.trail, &ent->r.client->ps, ucmd->serverTimeStamp );

	// Regeneration
	if( ent->r.client->ps.inventory[POWERUP_REGEN] > 0 && ent->health < 200)
	{
		ent->health += ( game.frametime * 0.001f ) * 10.0f;

		// Regen expires if health reaches 200
		if ( ent->health >= 199.0f )
			ent->r.client->ps.inventory[POWERUP_REGEN]--;
	}

	// fire touch functions
	if( ent->movetype != MOVETYPE_NOCLIP )
	{
		edict_t *other;

		// touch other objects
		for( i = 0; i < pm.numtouch; i++ )
		{
			other = &game.edicts[pm.touchents[i]];
			for( j = 0; j < i; j++ )
			{
				if( &game.edicts[pm.touchents[j]] == other )
					break;
			}
			if( j != i )
				continue; // duplicated

			// player can't touch projectiles, only projectiles can touch the player
			G_CallTouch( other, ent, NULL, 0 );
		}
	}

	ent->s.weapon = GS_ThinkPlayerWeapon( &client->ps, ucmd->buttons, ucmd->msec, client->timeDelta );

	if( G_IsDead( ent ) )
	{
		if( ent->deathTimeStamp + g_respawn_delay_min->integer <= level.time )
			client->resp.snap.buttons |= ucmd->buttons;
	}
	else if( client->ps.pmove.stats[PM_STAT_NOUSERCONTROL] <= 0 )
		client->resp.snap.buttons |= ucmd->buttons;

	// trigger the instashield
	if( GS_Instagib() && g_instashield->integer )
	{
		if( client->ps.pmove.pm_type == PM_NORMAL && pm.cmd.upmove < 0 &&
			client->resp.instashieldCharge == INSTA_SHIELD_MAX && 
			client->ps.inventory[POWERUP_SHELL] == 0 )
		{
			client->ps.inventory[POWERUP_SHELL] = client->resp.instashieldCharge;
			G_Sound( ent, CHAN_AUTO, trap_SoundIndex( GS_FindItemByTag( POWERUP_SHELL )->pickup_sound ), ATTN_NORM );
		}
	}	

	// 
	if( client->ps.pmove.pm_type == PM_NORMAL )
		client->level.stats.had_playtime = true;

	// generating plrkeys (optimized for net communication)
	ClientMakePlrkeys( client, ucmd );
}
Пример #4
0
/*
* ClientConnect
* Called when a player begins connecting to the server.
* The game can refuse entrance to a client by returning false.
* If the client is allowed, the connection process will continue
* and eventually get to ClientBegin()
* Changing levels will NOT cause this to be called again, but
* loadgames will.
*/
bool ClientConnect( edict_t *ent, char *userinfo, bool fakeClient, bool tvClient )
{
	char *value;

	assert( ent );
	assert( userinfo && Info_Validate( userinfo ) );
	assert( Info_ValueForKey( userinfo, "ip" ) && Info_ValueForKey( userinfo, "socket" ) );

	// verify that server gave us valid data
	if( !Info_Validate( userinfo ) )
	{
		Info_SetValueForKey( userinfo, "rejtype", va( "%i", DROP_TYPE_GENERAL ) );
		Info_SetValueForKey( userinfo, "rejflag", va( "%i", 0 ) );
		Info_SetValueForKey( userinfo, "rejmsg", "Invalid userinfo" );
		return false;
	}

	if( !Info_ValueForKey( userinfo, "ip" ) )
	{
		Info_SetValueForKey( userinfo, "rejtype", va( "%i", DROP_TYPE_GENERAL ) );
		Info_SetValueForKey( userinfo, "rejflag", va( "%i", 0 ) );
		Info_SetValueForKey( userinfo, "rejmsg", "Error: Server didn't provide client IP" );
		return false;
	}

	if( !Info_ValueForKey( userinfo, "ip" ) )
	{
		Info_SetValueForKey( userinfo, "rejtype", va( "%i", DROP_TYPE_GENERAL ) );
		Info_SetValueForKey( userinfo, "rejflag", va( "%i", 0 ) );
		Info_SetValueForKey( userinfo, "rejmsg", "Error: Server didn't provide client socket" );
		return false;
	}

	// check to see if they are on the banned IP list
	value = Info_ValueForKey( userinfo, "ip" );
	if( SV_FilterPacket( value ) )
	{
		Info_SetValueForKey( userinfo, "rejtype", va( "%i", DROP_TYPE_GENERAL ) );
		Info_SetValueForKey( userinfo, "rejflag", va( "%i", 0 ) );
		Info_SetValueForKey( userinfo, "rejmsg", "You're banned from this server" );
		return false;
	}

	// check for a password
	value = Info_ValueForKey( userinfo, "password" );
	if( !fakeClient && ( *password->string && ( !value || strcmp( password->string, value ) ) ) )
	{
		Info_SetValueForKey( userinfo, "rejtype", va( "%i", DROP_TYPE_PASSWORD ) );
		Info_SetValueForKey( userinfo, "rejflag", va( "%i", 0 ) );
		if( value && value[0] )
		{
			Info_SetValueForKey( userinfo, "rejmsg", "Incorrect password" );
		}
		else
		{
			Info_SetValueForKey( userinfo, "rejmsg", "Password required" );
		}
		return false;
	}

	// they can connect

	G_InitEdict( ent );
	ent->s.modelindex = 0;
	ent->r.solid = SOLID_NOT;
	ent->r.client = game.clients + PLAYERNUM( ent );
	ent->r.svflags = ( SVF_NOCLIENT | ( fakeClient ? SVF_FAKECLIENT : 0 ) );
	memset( ent->r.client, 0, sizeof( gclient_t ) );
	ent->r.client->ps.playerNum = PLAYERNUM( ent );
	ent->r.client->connecting = true;
	ent->r.client->isTV = tvClient == true;
	ent->r.client->team = TEAM_SPECTATOR;
	G_Client_UpdateActivity( ent->r.client ); // activity detected

	ClientUserinfoChanged( ent, userinfo );

	if( !fakeClient ) {
		char message[MAX_STRING_CHARS];

		Q_snprintfz( message, sizeof( message ), "%s%s connected", ent->r.client->netname, S_COLOR_WHITE );

		G_PrintMsg( NULL, "%s\n", message );

		G_Printf( "%s%s connected from %s\n", ent->r.client->netname, S_COLOR_WHITE, ent->r.client->ip );
	}

	// let the gametype scripts know this client just connected
	G_Gametype_ScoreEvent( ent->r.client, "connect", NULL );

	G_CallVotes_ResetClient( PLAYERNUM( ent ) );

	return true;
}