コード例 #1
0
ファイル: g_cmds.c プロジェクト: j0ki/racesow
/*
* Cmd_Say_f
*/
void Cmd_Say_f( edict_t *ent, qboolean arg0, qboolean checkflood )
{
	char *p;
	char text[2048];

	if( checkflood )
	{
		if( CheckFlood( ent, qfalse ) )
			return;
	}

	if( ent->r.client && ent->r.client->muted & 1 )
		return;

	if( trap_Cmd_Argc() < 2 && !arg0 )
		return;

	text[0] = 0;

	if( arg0 )
	{
		Q_strncatz( text, trap_Cmd_Argv( 0 ), sizeof( text ) );
		Q_strncatz( text, " ", sizeof( text ) );
		Q_strncatz( text, trap_Cmd_Args(), sizeof( text ) );
	}
	else
	{
		p = trap_Cmd_Args();

		if( *p == '"' )
		{
			if( p[strlen( p )-1] == '"' )
				p[strlen( p )-1] = 0;
			p++;
		}
		Q_strncatz( text, p, sizeof( text ) );
	}

	// don't let text be too long for malicious reasons
	if( strlen( text ) > 150 )
		text[150] = 0;

	G_ChatMsg( NULL, ent, qfalse, "%s", text );

	// racesow
	RS_ircSendMessage( va( "%s", COM_RemoveColorTokens(( ent->r.client->netname ) )),
			va( "%s", COM_RemoveColorTokens(( text)) ) );
	// !racesow
}
コード例 #2
0
ファイル: p_client.cpp プロジェクト: Clever-Boy/qfusion
/*
* G_SanitizeUserString
*/
static int G_SanitizeUserString( char *string, size_t size )
{
	static char *colorless = NULL;
	static size_t colorless_size = 0;
	int i, c_ascii;

	// life is hard, UTF-8 will have to go
	strip_highchars( string );

	COM_SanitizeColorString( va( "%s", string ), string, size, -1, COLOR_WHITE );

	Q_trim( string );

	if( colorless_size < strlen( string ) + 1 )
	{
		colorless_size = strlen( string ) + 1;

		G_Free( colorless );
		colorless = ( char * )G_Malloc( colorless_size );
	}

	Q_strncpyz( colorless, COM_RemoveColorTokens( string ), colorless_size );

	// require at least one non-whitespace ascii char in the string
	// (this will upset people who would like to have a name entirely in a non-latin
	// script, but it makes damn sure you can't get an empty name by exploiting some
	// utf-8 decoder quirk)
	c_ascii = 0;
	for( i = 0; colorless[i]; i++ )
		if( colorless[i] > 32 && colorless[i] < 127 )
			c_ascii++;

	return c_ascii;
}
コード例 #3
0
/*
* TV_Upstream_AutoRecordName
*/
static const char *TV_Upstream_AutoRecordName( upstream_t *upstream, char *name, size_t name_size )
{
	const char *gametype;
	char datetime[32];
	char matchname[MAX_CONFIGSTRING_CHARS];
	time_t long_time;
	struct tm *newtime;

	// date & time
	time( &long_time );
	newtime = localtime( &long_time );

	Q_snprintfz( datetime, sizeof( datetime ), "%04d-%02d-%02d_%02d-%02d", newtime->tm_year + 1900,
		newtime->tm_mon+1, newtime->tm_mday, newtime->tm_hour, newtime->tm_min );

	Q_strncpyz( matchname, upstream->configstrings[CS_MATCHNAME], sizeof( matchname ) );
	if( matchname[0] != '\0')
	{
		char *t = strstr( matchname, " vs " );
		if( t )
			memcpy( t, "_vs_", strlen( "_vs_" ) );
		Q_strncpyz( matchname, COM_RemoveJunkChars( COM_RemoveColorTokens( matchname ) ), sizeof( matchname ) );
	}

	// combine
	gametype = upstream->configstrings[CS_GAMETYPENAME];
	Q_snprintfz( name, name_size, "%s_%s_%s%s%s_auto%04i", datetime, gametype,
		upstream->levelname, matchname[0] ? "_" : "", matchname, (int)brandom( 0, 9999 ) );

	return name;
}
コード例 #4
0
ファイル: g_awards.cpp プロジェクト: Clever-Boy/qfusion
void G_PlayerAward( edict_t *ent, const char *awardMsg )
{
	edict_t *other;
	char cmd[MAX_STRING_CHARS];
	gameaward_t *ga;
	int i, size;
	score_stats_t *stats;

	if( !awardMsg || !awardMsg[0] || !ent->r.client )
		return;

	Q_snprintfz( cmd, sizeof( cmd ), "aw \"%s\"", awardMsg );
	trap_GameCmd( ent, cmd );

	if( dedicated->integer )
		G_Printf( "%s", COM_RemoveColorTokens( va( "%s receives a '%s' award.\n", ent->r.client->netname, awardMsg ) ) );

	ent->r.client->level.stats.awards++;
	teamlist[ent->s.team].stats.awards++;
	G_Gametype_ScoreEvent( ent->r.client, "award", awardMsg );

	stats = &ent->r.client->level.stats;
	if( !stats->awardAllocator )
		stats->awardAllocator = LinearAllocator( sizeof( gameaward_t ), 0, _G_LevelMalloc, _G_LevelFree );

	// ch : this doesnt work for race right?
	if( GS_MatchState() == MATCH_STATE_PLAYTIME || GS_MatchState() == MATCH_STATE_POSTMATCH )
	{
		// ch : we store this locally to send to MM
		// first check if we already have this one on the clients list
		size = LA_Size( stats->awardAllocator );
		ga = NULL;
		for( i = 0; i < size; i++ )
		{
			ga = ( gameaward_t * )LA_Pointer( stats->awardAllocator, i );
			if( !strncmp( ga->name, awardMsg, sizeof(ga->name)-1 ) )
				break;
		}

		if( i >= size )
		{
			ga = ( gameaward_t * )LA_Alloc( stats->awardAllocator );
			memset( ga, 0, sizeof(*ga) );
			ga->name = G_RegisterLevelString( awardMsg );
		}

		if( ga )
			ga->count++;
	}

	// add it to every player who's chasing this player
	for( other = game.edicts + 1; PLAYERNUM( other ) < gs.maxclients; other++ )
	{
		if( !other->r.client || !other->r.inuse || !other->r.client->resp.chase.active )
			continue;

		if( other->r.client->resp.chase.target == ENTNUM( ent ) )
			trap_GameCmd( other, cmd );
	}
}
コード例 #5
0
ファイル: tvm_client.c プロジェクト: cfr/qfusion
/*
* TVM_ClientBegin
* 
* called when a client has finished connecting, and is ready
* to be placed into the game. This will happen every level load.
*/
void TVM_ClientBegin( tvm_relay_t *relay, edict_t *ent )
{
	edict_t *spot, *other;
	int i, specs;
	char hostname[MAX_CONFIGSTRING_CHARS];

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

	//TVM_Printf( "Begin: %s\n", ent->r.client->pers.netname );

	ent->r.client->pers.connecting = false;

	spot = TVM_SelectSpawnPoint( ent );
	if( spot )
	{
		VectorCopy( spot->s.origin, ent->s.origin );
		VectorCopy( spot->s.origin, ent->s.old_origin );
		VectorCopy( spot->s.angles, ent->s.angles );
		VectorCopy( spot->s.origin, ent->r.client->ps.pmove.origin );
		VectorCopy( spot->s.angles, ent->r.client->ps.viewangles );
	}
	else
	{
		VectorClear( ent->s.origin );
		VectorClear( ent->s.old_origin );
		VectorClear( ent->s.angles );
		VectorClear( ent->r.client->ps.pmove.origin );
		VectorClear( ent->r.client->ps.viewangles );
	}

	ent->s.teleported = true;
	// set the delta angle
	for( i = 0; i < 3; i++ )
		ent->r.client->ps.pmove.delta_angles[i] = ANGLE2SHORT( ent->s.angles[i] ) - ent->r.client->pers.cmd_angles[i];

	specs = 0;
	for( i = 0; i < relay->local_maxclients; i++ )
	{
		other = relay->local_edicts + i;
		if( other == ent )
			continue;
		if( !other->r.inuse || !other->r.client )
			continue;
		if( trap_GetClientState( relay, PLAYERNUM( other ) ) != CS_SPAWNED )
			continue;
		specs++;
	}

	Q_strncpyz( hostname, relay->configStrings[CS_HOSTNAME], sizeof( hostname ) );
	TVM_PrintMsg( relay, ent, S_COLOR_ORANGE "Welcome to %s! There %s currently %i spectator%s on this channel.\n",
		COM_RemoveColorTokens( hostname ), (specs == 1 ? "is" : "are"), specs, (specs == 1 ? "" : "s") );

	TVM_PrintMsg( relay, ent, S_COLOR_ORANGE "For more information about chase camera modes type 'chase help' at console.\n" );

	if( ent->r.client->chase.active )
		TVM_ChaseClientEndSnapFrame( ent );
	else
		TVM_ClientEndSnapFrame( ent );
}
コード例 #6
0
ファイル: addon_string.cpp プロジェクト: Kaperstone/warsow
static asstring_t *objectString_RemoveColorTokens( asstring_t *self )
{
	const char *s;

	if( !self->len )
		return objectString_FactoryBuffer( NULL, 0 );

	s = COM_RemoveColorTokens( self->buffer );
	return objectString_FactoryBuffer( s, strlen(s) );
}
コード例 #7
0
ファイル: mlist.c プロジェクト: Clever-Boy/qfusion
/*
* ML_AddMap
* Handles assigning memory for map and adding it to the list
* in alphabetical order
*/
static void ML_AddMap( const char *filename, const char *fullname )
{
	mapinfo_t *map;
	char *buffer;
	char fullname_[MAX_CONFIGSTRING_CHARS];

	if( !ML_ValidateFilename( filename ) )
		return;

	if( !strcmp(filename, "ui") )
		return;

	if( !fullname )
	{
		ML_GetFullnameFromMap( filename, fullname_, sizeof( fullname_ ) );
		fullname = fullname_;
	}

	if( !ML_ValidateFullname( fullname ) && *fullname )	// allow empty fullnames
		return;

	if( !strcmp(fullname, "ui") )
		return;

	ml_flush = true;	// tell everyone that maplist has changed
	buffer = ( char* )Mem_ZoneMalloc( sizeof( mapinfo_t ) + strlen( filename ) + 1 + strlen( fullname ) + 1 );

	map = ( mapinfo_t * )buffer;
	buffer += sizeof( mapinfo_t );

	map->filename = buffer;
	strcpy( map->filename, filename );
	COM_StripExtension( map->filename );
	buffer += strlen( filename ) + 1;

	map->fullname = buffer;
	strcpy( map->fullname, fullname );
	COM_RemoveColorTokens( map->fullname );
	Q_strlwr( map->fullname );

	Trie_Insert( mlist_filenames_trie, map->filename, map );
	Trie_Insert( mlist_fullnames_trie, map->fullname, map );

	map->next = maplist;
	maplist = map;
}
コード例 #8
0
ファイル: cg_cmds.c プロジェクト: hettoo/racesow
/*
* CG_SC_AutoRecordName
*/
static const char *CG_SC_AutoRecordName( void )
{
	time_t long_time;
	struct tm *newtime;
	static char name[MAX_STRING_CHARS];
	char mapname[MAX_CONFIGSTRING_CHARS];
	const char *cleanplayername, *cleanplayername2;

	// get date from system
	time( &long_time );
	newtime = localtime( &long_time );

	if( cg.view.POVent <= 0 )
	{
		cleanplayername2 = "";
	}
	else
	{
		// remove color tokens from player names (doh)
		cleanplayername = COM_RemoveColorTokens( cgs.clientInfo[cg.view.POVent-1].name );

		// remove junk chars from player names for files
		cleanplayername2 = COM_RemoveJunkChars( cleanplayername );
	}

	// lowercase mapname
	Q_strncpyz( mapname, cgs.configStrings[CS_MAPNAME], sizeof( mapname ) );
	Q_strlwr( mapname );

	// make file name
	// duel_year-month-day_hour-min_map_player
	Q_snprintfz( name, sizeof( name ), "%s_%04d-%02d-%02d_%02d-%02d_%s_%s_%04i",
		gs.gametypeName,
		newtime->tm_year + 1900, newtime->tm_mon+1, newtime->tm_mday,
		newtime->tm_hour, newtime->tm_min,
		mapname,
		cleanplayername2,
		(int)brandom( 0, 9999 )
		);

	return name;
}
コード例 #9
0
ファイル: mlist.c プロジェクト: Clever-Boy/qfusion
/*
* ML_GetFullnameFromMap
* Get fullname of map from file or worldspawn (slow)
*/
static void ML_GetFullnameFromMap( const char *filename, char *fullname, size_t len )
{
	char *buffer;

	*fullname = '\0';

	// Try and load fullname from a file
	FS_LoadFile( va( "maps/%s.txt", filename ), ( void ** )&buffer, NULL, 0 );
	if( buffer )
	{
		char *line = buffer;
		Q_strncpyz( fullname, COM_Parse( &line ), len );
		FS_FreeFile( buffer );
		return;
	}

	// Try and load fullname from worldspawn
	CM_LoadMapMessage( va( "maps/%s.bsp", filename ), fullname, len );
	COM_RemoveColorTokens( fullname );
}
コード例 #10
0
ファイル: g_awards.c プロジェクト: Racenet/racesow
void G_PlayerAward( edict_t *ent, const char *awardMsg )
{
	edict_t *other, *third;

	if( !awardMsg || !awardMsg[0] || !ent->r.client )
		return;

	trap_GameCmd( ent, va( "aw \"%s\"", awardMsg ) );

	if( dedicated->integer )
		G_Printf( "%s", COM_RemoveColorTokens( va( "%s receives a '%s' award.\n", ent->r.client->netname, awardMsg ) ) );

	ent->r.client->level.stats.awards++;
	teamlist[ent->s.team].stats.awards++;
	G_Gametype_ScoreEvent( ent->r.client, "award", awardMsg );

	// add it to every player who's chasing this player
	for( other = game.edicts + 1; PLAYERNUM( other ) < gs.maxclients; other++ )
	{
		if( !other->r.client || !other->r.inuse || !other->r.client->resp.chase.active )
			continue;

		if( other->r.client->resp.chase.target == ent->s.number )
		{
			trap_GameCmd( other, va( "aw \"%s\"", awardMsg ) );
			
			// someone could also be chase-caming the guy in the chasecam
			for( third = game.edicts + 1; PLAYERNUM( third ) < gs.maxclients; third++ )
			{
				if( !third->r.client || !third->r.inuse || !third->r.client->resp.chase.active )
					continue;

				if( third->r.client->resp.chase.target == other->s.number )
					trap_GameCmd( third, va( "aw \"%s\"", awardMsg ) );
			}
		}
	}
}
コード例 #11
0
ファイル: tv_downstream.c プロジェクト: Kaperstone/warsow
/*
* TV_Downstream_FixName
* 
* Make name valid, so it's not used by anyone else or so. See G_SetName
* Client can be given, so conflict with that client's name won't matter
* The returned value will be overwritten by the next call to this function
*/
char *TV_Downstream_FixName( const char *original_name, client_t *client )
{
	const char *invalid_prefixes[] = { "console", "[team]", "[spec]", "[bot]", "[coach]", "[tv]", NULL };
	client_t *other;
	static char name[MAX_NAME_BYTES];
	char colorless[MAX_NAME_BYTES];
	int i, trynum, trylen;
	int c_ascii;
	int maxchars;

	// we allow NULL to be passed for name
	if( !original_name )
		original_name = "";

	Q_strncpyz( name, original_name, sizeof( name ) );

	// life is hard, UTF-8 will have to go
	strip_highchars( name );

	COM_SanitizeColorString( va( "%s", name ), name, sizeof( name ), -1, COLOR_WHITE );

	// remove leading whitespace
	while( name[0] == ' ' )
		memmove( name, name + 1, strlen( name ) );

	// remove trailing whitespace
	while( strlen( name ) && name[strlen(name)-1] == ' ' )
		name[strlen(name)-1] = '\0';

	Q_strncpyz( colorless, COM_RemoveColorTokens( name ), sizeof( colorless ) );

	maxchars = MAX_NAME_CHARS;
	if( client && client->tv )
		maxchars = min( maxchars + 10, MAX_NAME_BYTES-1 );

	// require at least one non-whitespace ascii char in the name
	// (this will upset people who would like to have a name entirely in a non-latin
	// script, but it makes damn sure you can't get an empty name by exploiting some
	// utf-8 decoder quirk)
	c_ascii = 0;
	for( i = 0; colorless[i]; i++ )
		if( colorless[i] > 32 && colorless[i] < 127 )
			c_ascii++;

	if( !c_ascii )
	{
		Q_strncpyz( name, "Player", sizeof( name ) );
		Q_strncpyz( colorless, COM_RemoveColorTokens( name ), sizeof( colorless ) );
	}

	for( i = 0; invalid_prefixes[i] != NULL; i++ )
	{
		if( !Q_strnicmp( colorless, invalid_prefixes[i], strlen( invalid_prefixes[i] ) ) )
		{
			Q_strncpyz( name, "Player", sizeof( name ) );
			Q_strncpyz( colorless, COM_RemoveColorTokens( name ), sizeof( colorless ) );
		}
	}

	trynum = 1;
	do
	{
		for( i = 0, other = tvs.clients; i < tv_maxclients->integer; i++, other++ )
		{
			if( ( client && other == client ) || other->state == CS_FREE || other->state == CS_ZOMBIE )
				continue;

			// if nick is already in use, try with (number) appended
			if( !Q_stricmp( colorless, COM_RemoveColorTokens( other->name ) ) )
			{
				if( trynum != 1 )  // remove last try
					name[strlen( name ) - strlen( va( "%s(%i)", S_COLOR_WHITE, trynum-1 ) )] = 0;

				// make sure there is enough space for the postfix
				trylen = strlen( va( "%s(%i)", S_COLOR_WHITE, trynum ) );
				if( (int)strlen( colorless ) + trylen > maxchars )
				{
					COM_SanitizeColorString( va( "%s", name ), name, sizeof( name ),
						maxchars - trylen, COLOR_WHITE );
					Q_strncpyz( colorless, COM_RemoveColorTokens( name ), sizeof( colorless ) );
				}

				// add the postfix
				Q_strncatz( name, va( "%s(%i)", S_COLOR_WHITE, trynum ), sizeof( name ) );
				Q_strncpyz( colorless, COM_RemoveColorTokens( name ), sizeof( colorless ) );

				// go trough all clients again
				trynum++;
				break;
			}
		}
	}
	while( i != tv_maxclients->integer && trynum <= MAX_CLIENTS );

	return name;
}
コード例 #12
0
ファイル: g_chase.cpp プロジェクト: MGXRace/racesow
/*
* G_ChasePlayer
*/
void G_ChasePlayer( edict_t *ent, const char *name, bool teamonly, int followmode )
{
	int i;
	edict_t *e;
	gclient_t *client;
	int targetNum = -1;
	int oldTarget;
	bool can_follow = true;
	char colorlessname[MAX_NAME_BYTES];

	client = ent->r.client;

	oldTarget = client->resp.chase.target;

	if( teamonly && !client->teamstate.is_coach )
		can_follow = false;

	if( !can_follow && followmode )
	{
		G_PrintMsg( ent, "Chasecam follow mode unavailable\n" );
		followmode = false;
	}

	if( ent->r.client->resp.chase.followmode && !followmode )
		G_PrintMsg( ent, "Disabling chasecam follow mode\n" );

	// always disable chasing as a start
	memset( &client->resp.chase, 0, sizeof( chasecam_t ) );

	// locate the requested target
	if( name && name[0] )
	{
		// find it by player names
		for( e = game.edicts + 1; PLAYERNUM( e ) < gs.maxclients; e++ )
		{
			if( !G_Chase_IsValidTarget( ent, e, teamonly ) )
				continue;

			Q_strncpyz( colorlessname, COM_RemoveColorTokens( e->r.client->netname ), sizeof(colorlessname) );

			if( !Q_stricmp( COM_RemoveColorTokens( name ), colorlessname ) )
			{
				targetNum = PLAYERNUM( e );
				break;
			}
		}

		// didn't find it by name, try by numbers
		if( targetNum == -1 )
		{
			i = atoi( name );
			if( i >= 0 && i < gs.maxclients )
			{
				e = game.edicts + 1 + i;
				if( G_Chase_IsValidTarget( ent, e, teamonly ) )
					targetNum = PLAYERNUM( e );
			}
		}

		if( targetNum == -1 )
			G_PrintMsg( ent, "Requested chasecam target is not available\n" );
	}

	// try to reuse old target if we didn't find a valid one
	if( targetNum == -1 && oldTarget > 0 && oldTarget < gs.maxclients )
	{
		e = game.edicts + 1 + oldTarget;
		if( G_Chase_IsValidTarget( ent, e, teamonly ) )
			targetNum = PLAYERNUM( e );
	}

	// if we still don't have a target, just pick the first valid one
	if( targetNum == -1 )
	{
		for( e = game.edicts + 1; PLAYERNUM( e ) < gs.maxclients; e++ )
		{
			if( !G_Chase_IsValidTarget( ent, e, teamonly ) )
				continue;

			targetNum = PLAYERNUM( e );
			break;
		}
	}

	// make the client a ghost
	G_GhostClient( ent );
	if( targetNum != -1 )
	{
		// we found a target, set up the chasecam
		client->resp.chase.target = targetNum + 1;
		client->resp.chase.teamonly = teamonly;
		client->resp.chase.followmode = followmode;
		G_Chase_SetChaseActive( ent, true );
	}
	else
	{
		// stay as observer
		if( !teamonly )
			ent->movetype = MOVETYPE_NOCLIP;
		client->level.showscores = false;
		G_Chase_SetChaseActive( ent, false );
		G_CenterPrintMsg( ent, "No one to chase" );
	}
}
コード例 #13
0
ファイル: sv_oob.c プロジェクト: futurepneu/racemod
/**
 * Responds to a Steam server query.
 *
 * @param s       query string
 * @param socket  response socket
 * @param address response address
 * @param inmsg   message for arguments
 * @return whether the request was handled as a Steam query
 */
bool SV_SteamServerQuery( const char *s, const socket_t *socket, const netadr_t *address, msg_t *inmsg )
{
#if APP_STEAMID
	if( sv.state < ss_loading || sv.state > ss_game )
		return false; // server not running

	if( ( !sv_public->integer && !NET_IsLANAddress( address ) ) || ( sv_maxclients->integer == 1 ) )
		return false;

	if( !strcmp( s, "i" ) )
	{
		// ping
		const char pingResponse[] = "j00000000000000";
		Netchan_OutOfBand( socket, address, sizeof( pingResponse ), ( const uint8_t * )pingResponse );
		return true;
	}

	if( !strcmp( s, "W" ) || !strcmp( s, "U\xFF\xFF\xFF\xFF" ) )
	{
		// challenge - security feature, but since we don't send multiple packets always return 0
		const uint8_t challengeResponse[] = { 'A', 0, 0, 0, 0 };
		Netchan_OutOfBand( socket, address, sizeof( challengeResponse ), ( const uint8_t * )challengeResponse );
		return true;
	}

	if( !strcmp( s, "TSource Engine Query" ) )
	{
		// server info
		char hostname[MAX_INFO_VALUE];
		char gamedir[MAX_QPATH];
		char gamename[128];
		char version[32];
		char tags[MAX_STEAMQUERY_TAG_STRING];
		int i, players = 0, bots = 0, maxclients = 0;
		int flags = 0x80 | 0x01; // game port | game ID containing app ID
		client_t *cl;
		msg_t msg;
		uint8_t msgbuf[MAX_STEAMQUERY_PACKETLEN - sizeof( int32_t )];

		if( sv_showInfoQueries->integer )
			Com_Printf( "Steam Info Packet %s\n", NET_AddressToString( address ) );

		Q_strncpyz( hostname, COM_RemoveColorTokens( sv_hostname->string ), sizeof( hostname ) );
		if( !hostname[0] )
			Q_strncpyz( hostname, sv_hostname->dvalue, sizeof( hostname ) );
		Q_strncpyz( gamedir, FS_GameDirectory(), sizeof( gamedir ) );

		Q_strncpyz( gamename, APPLICATION, sizeof( gamename ) );
		if( Cvar_Value( "g_instagib" ) )
			Q_strncatz( gamename, " IG", sizeof( gamename ) );
		if( sv.configstrings[CS_GAMETYPETITLE][0] || sv.configstrings[CS_GAMETYPENAME][0] )
		{
			Q_strncatz( gamename, " ", sizeof( gamename ) );
			Q_strncatz( gamename,
				sv.configstrings[sv.configstrings[CS_GAMETYPETITLE][0] ? CS_GAMETYPETITLE : CS_GAMETYPENAME],
				sizeof( gamename ) );
		}

		for( i = 0; i < sv_maxclients->integer; i++ )
		{
			cl = &svs.clients[i];
			if( cl->state >= CS_CONNECTED )
			{
				if( cl->tvclient ) // exclude TV from the max players count
					continue;
				if( cl->edict->r.svflags & SVF_FAKECLIENT )
					bots++;
				players++;
			}
			maxclients++;
		}

		Q_snprintfz( version, sizeof( version ), "%i.%i.0.0", APP_VERSION_MAJOR, APP_VERSION_MINOR );

		SV_GetSteamTags( tags );
		if( tags[0] )
			flags |= 0x20;

		MSG_Init( &msg, msgbuf, sizeof( msgbuf ) );
		MSG_WriteByte( &msg, 'I' );
		MSG_WriteByte( &msg, APP_PROTOCOL_VERSION );
		MSG_WriteString( &msg, hostname );
		MSG_WriteString( &msg, sv.mapname );
		MSG_WriteString( &msg, gamedir );
		MSG_WriteString( &msg, gamename );
		MSG_WriteShort( &msg, 0 ); // app ID specified later
		MSG_WriteByte( &msg, min( players, 99 ) );
		MSG_WriteByte( &msg, min( maxclients, 99 ) );
		MSG_WriteByte( &msg, min( bots, 99 ) );
		MSG_WriteByte( &msg, ( dedicated && dedicated->integer ) ? 'd' : 'l' );
		MSG_WriteByte( &msg, STEAMQUERY_OS );
		MSG_WriteByte( &msg, Cvar_String( "password" )[0] ? 1 : 0 );
		MSG_WriteByte( &msg, 0 ); // VAC insecure
		MSG_WriteString( &msg, version );
		MSG_WriteByte( &msg, flags );
		// port
		MSG_WriteShort( &msg, sv_port->integer );
		// tags
		if( flags & 0x20 )
			MSG_WriteString( &msg, tags );
		// 64-bit game ID - needed to specify app ID
		MSG_WriteLong( &msg, APP_STEAMID & 0xffffff );
		MSG_WriteLong( &msg, 0 );
		Netchan_OutOfBand( socket, address, msg.cursize, msg.data );
		return true;
	}

	if( s[0] == 'U' )
	{
		// players
		msg_t msg;
		uint8_t msgbuf[MAX_STEAMQUERY_PACKETLEN - sizeof( int32_t )];
		int i, players = 0;
		client_t *cl;
		char name[MAX_NAME_BYTES];
		unsigned int time = Sys_Milliseconds();

		if( sv_showInfoQueries->integer )
			Com_Printf( "Steam Players Packet %s\n", NET_AddressToString( address ) );

		MSG_Init( &msg, msgbuf, sizeof( msgbuf ) );
		MSG_WriteByte( &msg, 'D' );
		MSG_WriteByte( &msg, 0 );

		for( i = 0; i < sv_maxclients->integer; i++ )
		{
			cl = &svs.clients[i];
			if( ( cl->state < CS_CONNECTED ) || cl->tvclient )
				continue;

			Q_strncpyz( name, COM_RemoveColorTokens( cl->name ), sizeof( name ) );
			if( ( msg.cursize + 10 + strlen( name ) ) > sizeof( msgbuf ) )
				break;

			MSG_WriteByte( &msg, i );
			MSG_WriteString( &msg, name );
			MSG_WriteLong( &msg, cl->edict->r.client->r.frags );
			MSG_WriteFloat( &msg, ( float )( time - cl->lastconnect ) * 0.001f );

			players++;
			if( players == 99 )
				break;
		}

		msgbuf[1] = players;
		Netchan_OutOfBand( socket, address, msg.cursize, msg.data );
		return true;
	}

	if( !strcmp( s, "s" ) )
	{
		// master server query, terminated by \n, followed by the challenge
		int i;
		bool fromMaster = false;
		int challenge;
		char gamedir[MAX_QPATH], basedir[MAX_QPATH], tags[MAX_STEAMQUERY_TAG_STRING];
		int players = 0, bots = 0, maxclients = 0;
		client_t *cl;
		char msg[MAX_STEAMQUERY_PACKETLEN];

		for( i = 0; i < MAX_MASTERS; i++ )
		{
			if( sv_masters[i].steam && NET_CompareAddress( address, &sv_masters[i].address ) )
			{
				fromMaster = true;
				break;
			}
		}
		if( !fromMaster )
			return true;

		if( sv_showInfoQueries->integer )
			Com_Printf( "Steam Master Server Info Packet %s\n", NET_AddressToString( address ) );

		challenge = MSG_ReadLong( inmsg );

		Q_strncpyz( gamedir, FS_GameDirectory(), sizeof( gamedir ) );
		Q_strncpyz( basedir, FS_BaseGameDirectory(), sizeof( basedir ) );
		SV_GetSteamTags( tags );

		for( i = 0; i < sv_maxclients->integer; i++ )
		{
			cl = &svs.clients[i];
			if( cl->state >= CS_CONNECTED )
			{
				if( cl->tvclient ) // exclude TV from the max players count
					continue;
				if( cl->edict->r.svflags & SVF_FAKECLIENT )
					bots++;
				players++;
			}
			maxclients++;
		}

		Q_snprintfz( msg, sizeof( msg ),
			"0\n\\protocol\\7\\challenge\\%i" // protocol must be 7 to match Source
			"\\players\\%i\\max\\%i\\bots\\%i"
			"\\gamedir\\%s\\map\\%s"
			"\\password\\%i\\os\\%c"
			"\\lan\\%i\\region\\255"
			"%s%s"
			"\\type\\%c\\secure\\0"
			"\\version\\%i.%i.0.0"
			"\\product\\%s\n",
			challenge,
			min( players, 99 ), min( maxclients, 99 ), min( bots, 99 ),
			gamedir, sv.mapname,
			Cvar_String( "password" )[0] ? 1 : 0, STEAMQUERY_OS,
			sv_public->integer ? 0 : 1,
			tags[0] ? "\\gametype\\" /* legacy - "gametype", not "tags" */ : "", tags,
			( dedicated && dedicated->integer ) ? 'd' : 'l',
			APP_VERSION_MAJOR, APP_VERSION_MINOR,
			basedir );
		NET_SendPacket( socket, ( const uint8_t * )msg, strlen( msg ), address );

		return true;
	}

	if( s[0] == 'O' )
	{
		// out of date message
		static bool printed = false;
		if( !printed )
		{
			int i;
			for( i = 0; i < MAX_MASTERS; i++ )
			{
				if( sv_masters[i].steam && NET_CompareAddress( address, &sv_masters[i].address ) )
				{
					Com_Printf( "Server is out of date and cannot be added to the Steam master servers.\n" );
					printed = true;
					return true;
				}
			}
		}
		return true;
	}
#endif

	return false;
}
コード例 #14
0
ファイル: ui_menu.c プロジェクト: Kaperstone/warsow
/*
* UI_DrawConnectScreen
*/
void UI_DrawConnectScreen( const char *serverName, const char *rejectmessage, int downloadType, const char *downloadFilename,
						  float downloadPercent, int downloadSpeed, int connectCount, qboolean demoplaying, qboolean backGround )
{
	qboolean localhost, design = qfalse;
	char str[MAX_QPATH];
	int x, y, xoffset, yoffset, width, height;
	unsigned int maxwidth;
	qboolean downloadFromWeb;
	char hostName[MAX_CONFIGSTRING_CHARS], mapname[MAX_CONFIGSTRING_CHARS], mapmessage[MAX_CONFIGSTRING_CHARS],
		gametype[MAX_CONFIGSTRING_CHARS], gametypeTitle[MAX_CONFIGSTRING_CHARS],
		gametypeVersion[MAX_CONFIGSTRING_CHARS], gametypeAuthor[MAX_CONFIGSTRING_CHARS],
		matchName[MAX_CONFIGSTRING_CHARS];

	uis.demoplaying = demoplaying;

	//trap_S_StopBackgroundTrack();

	localhost = (qboolean)( !serverName || !serverName[0] || !Q_stricmp( serverName, "localhost" ) );

	trap_GetConfigString( CS_MAPNAME, mapname, sizeof( mapname ) );
	trap_GetConfigString( CS_MESSAGE, mapmessage, sizeof( mapmessage ) );

	if( backGround )
	{
		Q_snprintfz( str, sizeof( str ), UI_SHADER_BACKGROUND, uis.backgroundNum );
		trap_R_DrawStretchPic( 0, 0, uis.vidWidth, uis.vidHeight, 0, 0, 1, 1, colorWhite, trap_R_RegisterPic( str ) );
	}

	//
	// not yet connected
	//

	x = 64;
	y = 64;
	xoffset = yoffset = 0;

	if( demoplaying )
		Q_snprintfz( str, sizeof( str ), "Loading demo: %s", serverName );
	else if( localhost )
		Q_strncpyz( str, "Loading...", sizeof( str ) );
	else if( mapname[0] )
		Q_snprintfz( str, sizeof( str ), "Connecting to %s", serverName );
	else
		Q_snprintfz( str, sizeof( str ), "Awaiting connection... %i", connectCount );

	trap_SCR_DrawString( x + xoffset, y + yoffset, ALIGN_LEFT_TOP, str, uis.fontSystemBig, colorWhite );
	yoffset += trap_SCR_strHeight( uis.fontSystemBig );

	if( design && !rejectmessage )
		rejectmessage = "Connection was interrupted because the weather sux :P";

	if( rejectmessage )
	{
		x = uis.vidWidth / 2;
		y = uis.vidHeight / 3;

		height = trap_SCR_strHeight( uis.fontSystemMedium ) * 4;
		Q_strncpyz( str, "Refused: ", sizeof( str ) );
		width = max( trap_SCR_strWidth( str, uis.fontSystemMedium, 0 ), trap_SCR_strWidth( rejectmessage, uis.fontSystemSmall, 0 ) );
		width += 32 * 2;

		xoffset = UISCR_HorizontalAlignOffset( ALIGN_CENTER_MIDDLE, width );
		yoffset = UISCR_VerticalAlignOffset( ALIGN_CENTER_MIDDLE, height );

		UI_DrawBox( x + xoffset, y + yoffset, width, height, colorWarsowOrange, colorWhite, NULL, colorDkGrey );

		yoffset += trap_SCR_strHeight( uis.fontSystemMedium );
		xoffset += 32;

		trap_SCR_DrawString( x + xoffset, y + yoffset, ALIGN_LEFT_TOP, str, uis.fontSystemMedium, colorWhite );
		yoffset += trap_SCR_strHeight( uis.fontSystemMedium );

		trap_SCR_DrawString( x + xoffset, y + yoffset, ALIGN_LEFT_TOP, rejectmessage, uis.fontSystemSmall, colorBlack );

		return;
	}

	if( mapname[0] )
	{
		char levelshot[MAX_QPATH];
		struct shader_s *levelshotShader;
		qboolean isDefaultlevelshot = qtrue;

		//
		// connected
		//

		x = 64;
		y = uis.vidHeight - 300;
		xoffset = yoffset = 0;
		width = uis.vidWidth;
		height = 200;

		UI_DrawBox( x + xoffset, y + yoffset, width, height, colorWarsowPurple, colorWhite, NULL, colorDkGrey );
		xoffset += 16;
		yoffset += 16 + 4;

		maxwidth = uis.vidWidth - ( x + xoffset );

		trap_GetConfigString( CS_HOSTNAME, hostName, sizeof( hostName ) );
		trap_GetConfigString( CS_GAMETYPENAME, gametype, sizeof( gametype ) );
		trap_GetConfigString( CS_GAMETYPETITLE, gametypeTitle, sizeof( gametypeTitle ) );
		trap_GetConfigString( CS_GAMETYPEVERSION, gametypeVersion, sizeof( gametypeVersion ) );
		trap_GetConfigString( CS_GAMETYPEAUTHOR, gametypeAuthor, sizeof( gametypeAuthor ) );
		trap_GetConfigString( CS_MATCHNAME, matchName, sizeof( matchName ) );

		Q_snprintfz( levelshot, sizeof( levelshot ), "levelshots/%s.jpg", mapname );

		levelshotShader = trap_R_RegisterLevelshot( levelshot, uis.whiteShader, &isDefaultlevelshot );

		if( !isDefaultlevelshot )
		{
			int lw, lh, lx, ly;

			lh = height - 8;
			lw = lh * ( 4.0f/3.0f );
			lx = uis.vidWidth - lw;
			ly = y + 4;

			trap_R_DrawStretchPic( lx, ly, lw, lh, 0, 0, 1, 1, colorWhite, levelshotShader );
		}

		if( !localhost && !demoplaying )
		{
			Q_snprintfz( str, sizeof( str ), "Server: %s", hostName );
			trap_SCR_DrawStringWidth( x + xoffset, y + yoffset, ALIGN_LEFT_TOP, str, maxwidth, uis.fontSystemSmall, colorWhite );
			yoffset += trap_SCR_strHeight( uis.fontSystemSmall ) + 8;
		}

		if( mapmessage[0] && Q_stricmp( mapname, mapmessage ) )
		{
			Q_snprintfz( str, sizeof( str ), "Level: "S_COLOR_ORANGE"%s", COM_RemoveColorTokens( mapmessage ) );
			trap_SCR_DrawStringWidth( x + xoffset, y + yoffset, ALIGN_LEFT_TOP, str, maxwidth, uis.fontSystemSmall, colorWhite );
			yoffset += trap_SCR_strHeight( uis.fontSystemSmall ) + 8;
		}

		Q_snprintfz( str, sizeof( str ), "Map: %s", mapname );
		trap_SCR_DrawStringWidth( x + xoffset, y + yoffset, ALIGN_LEFT_TOP, str, maxwidth, uis.fontSystemSmall, colorWhite );
		yoffset += trap_SCR_strHeight( uis.fontSystemSmall ) + 8;

		if( matchName[0] )
		{
			Q_snprintfz( str, sizeof( str ), "Match: %s", matchName );
			trap_SCR_DrawStringWidth( x + xoffset, y + yoffset, ALIGN_LEFT_TOP, str, maxwidth, uis.fontSystemSmall, colorWhite );
			yoffset += trap_SCR_strHeight( uis.fontSystemSmall ) + 8;
		}
		yoffset += trap_SCR_strHeight( uis.fontSystemSmall ) + 8;

		Q_snprintfz( str, sizeof( str ), "Gametype: "S_COLOR_ORANGE"%s", COM_RemoveColorTokens( gametypeTitle ) );
		trap_SCR_DrawStringWidth( x + xoffset, y + yoffset, ALIGN_LEFT_TOP, str, maxwidth, uis.fontSystemSmall, colorWhite );
		yoffset += trap_SCR_strHeight( uis.fontSystemSmall ) + 8;

		Q_snprintfz( str, sizeof( str ), "Version: %s", COM_RemoveColorTokens( gametypeVersion ) );
		trap_SCR_DrawStringWidth( x + xoffset, y + yoffset, ALIGN_LEFT_TOP, str, maxwidth, uis.fontSystemSmall, colorWhite );
		yoffset += trap_SCR_strHeight( uis.fontSystemSmall ) + 8;

		Q_snprintfz( str, sizeof( str ), "Author: %s", gametypeAuthor );
		trap_SCR_DrawStringWidth( x + xoffset, y + yoffset, ALIGN_LEFT_TOP, str, maxwidth, uis.fontSystemSmall, colorWhite );
		yoffset += trap_SCR_strHeight( uis.fontSystemSmall ) + 8;
	}

	// downloading

	if( design && !downloadFilename )
	{
		downloadFilename = "http://www.warsow.net/autoupdate/basewsw/map_wdm9a.pk3";
		downloadType = 2;
		downloadPercent = 65.8;
		downloadSpeed = 325;
	}

	if( downloadType && downloadFilename )
	{
		size_t len;
		const char *s;

		downloadFromWeb = ( downloadType == 2 );

		x = uis.vidWidth / 2;
		y = uis.vidHeight / 3;
		width = 400;
		height = 128 - trap_SCR_strHeight( uis.fontSystemSmall );
		if( uis.vidWidth <= width )
			width = uis.vidWidth - 64;

		maxwidth = width - 48;

		xoffset = UISCR_HorizontalAlignOffset( ALIGN_CENTER_MIDDLE, width );
		yoffset = UISCR_VerticalAlignOffset( ALIGN_CENTER_MIDDLE, height );

		// adjust the box size for the extra number of lines needed to draw the file path
		s = downloadFilename;
		while( ( len = trap_SCR_StrlenForWidth( s, uis.fontSystemSmall, maxwidth ) ) > 0 )
		{
			s += len;
			height += trap_SCR_strHeight( uis.fontSystemSmall );
		}

		UI_DrawBox( x + xoffset, y + yoffset, width, height, colorWarsowPurple, colorWhite, NULL, colorDkGrey );

		xoffset += 24;
		yoffset += 24;

		trap_SCR_DrawStringWidth( x + xoffset, y + yoffset, ALIGN_LEFT_TOP, downloadFromWeb ? "Downloading from web" : "Downloading from server", maxwidth, uis.fontSystemSmall, colorWhite );
		yoffset += trap_SCR_strHeight( uis.fontSystemSmall );

		s = downloadFilename;
		while( ( len = trap_SCR_DrawStringWidth( x + xoffset, y + yoffset, ALIGN_LEFT_TOP, s, maxwidth, uis.fontSystemSmall, colorWhite ) ) > 0 )
		{
			s += len;
			yoffset += trap_SCR_strHeight( uis.fontSystemSmall );
		}

		yoffset += 16;

		UI_DrawPicBar( x + xoffset, y + yoffset, maxwidth, 24, ALIGN_LEFT_TOP, downloadPercent, trap_R_RegisterPic( "gfx/ui/progressbar" ),colorDkGrey, colorOrange );
		Q_snprintfz( str, sizeof( str ), "%3.1f%c", downloadPercent, '%' );
		trap_SCR_DrawStringWidth( x + xoffset + 12, y + yoffset + 12, ALIGN_LEFT_MIDDLE, str, maxwidth, uis.fontSystemSmall, colorWhite );
		Q_snprintfz( str, sizeof( str ), "%ik/s", downloadSpeed );
		trap_SCR_DrawStringWidth( x + xoffset + maxwidth - 12, y + yoffset + 12, ALIGN_RIGHT_MIDDLE, str, maxwidth, uis.fontSystemSmall, colorWhite );

		yoffset += 24 + 8;
	}
}
コード例 #15
0
ファイル: sv_ccmds.c プロジェクト: Racenet/racesow
/*
* SV_Status_f
*/
void SV_Status_f( void )
{
	int i, j, l;
	client_t *cl;
	const char *s;
	int ping;
	if( !svs.clients )
	{
		Com_Printf( "No server running.\n" );
		return;
	}
	Com_Printf( "map              : %s\n", sv.mapname );

	Com_Printf( "num score ping name            lastmsg address               port   rate  \n" );
	Com_Printf( "--- ----- ---- --------------- ------- --------------------- ------ ------\n" );
	for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ )
	{
		if( !cl->state )
			continue;
		Com_Printf( "%3i ", i );
		Com_Printf( "%5i ", cl->edict->r.client->r.frags );

		if( cl->state == CS_CONNECTED )
			Com_Printf( "CNCT " );
		else if( cl->state == CS_ZOMBIE )
			Com_Printf( "ZMBI " );
		else if( cl->state == CS_CONNECTING )
			Com_Printf( "AWAI " );
		else
		{
			ping = cl->ping < 9999 ? cl->ping : 9999;
			Com_Printf( "%4i ", ping );
		}

		s = COM_RemoveColorTokens( cl->name );
		Com_Printf( "%s", s );
		l = 16 - (int)strlen( s );
		for( j = 0; j < l; j++ )
			Com_Printf( " " );

		Com_Printf( "%7i ", svs.realtime - cl->lastPacketReceivedTime );

		s = NET_AddressToString( &cl->netchan.remoteAddress );
		Com_Printf( "%s", s );
		l = 22 - (int)strlen( s );
		for( j = 0; j < l; j++ )
			Com_Printf( " " );

		Com_Printf( "%5i", cl->netchan.game_port );
#ifndef RATEKILLED
		// wsw : jal : print real rate in use
		Com_Printf( "  " );
		if( cl->edict && ( cl->edict->r.svflags & SVF_FAKECLIENT ) )
			Com_Printf( "BOT" );
		else if( cl->rate == 99999 )
			Com_Printf( "LAN" );
		else
			Com_Printf( "%5i", cl->rate );
#endif
		Com_Printf( " " );
		if( cl->mv )
			Com_Printf( "MV" );
		Com_Printf( "\n" );
	}
	Com_Printf( "\n" );
}
コード例 #16
0
ファイル: p_client.cpp プロジェクト: Clever-Boy/qfusion
/*
* G_MoveClientToTV
*
* Sends cmd to connect to a non-full TV server with round robin balancing
*/
void G_MoveClientToTV( edict_t *ent )
{
	int i;
	gclient_t *client, *best;
	static int last_tv = 0;
	bool isIPv6;
	char ip[MAX_INFO_VALUE];
	int port;
	const char *p;

	if( !ent->r.client ) {
		return;
	}
	if( ent->r.svflags & SVF_FAKECLIENT ) {
		return;
	}
	if( ent->r.client->isTV ) {
		return;
	}

	best = NULL;
	for( i = 0; i < gs.maxclients; i++ ) {
		client = &game.clients[(last_tv + 1 + i) % gs.maxclients];
		if( !client->isTV || client->connecting ) {
			// not a TV or not ready yet
			continue;
		}
		if( client->tv.numclients == client->tv.maxclients ) {
			// full
			continue;
		}
		if( !client->tv.channel ) {
			// invalid userinfo/channel number
			continue;
		}
		best = client;
		break;
	}

	if( !best ) {
		G_PrintMsg( ent, "Could not find a free TV server\n" );
		return;
	}

	Q_strncpyz( ip, best->ip, sizeof( ip ) );

	// check IP type
	p = strstr( ip, "::" );
	isIPv6 = p != NULL;

	// strip port number from address string
	p = strrchr( ip, ':' );
	if( p != NULL ) {
		ip[p - ip] = '\0';
	}

	port = isIPv6 ? best->tv.port6 : best->tv.port;

	last_tv = best - game.clients;
	trap_GameCmd( ent, va( "memo tv_moveto \"%s\" %s:%hu#%i", COM_RemoveColorTokens( best->netname ), ip, port, best->tv.channel ) );
}
コード例 #17
0
ファイル: cg_democams.cpp プロジェクト: Picmip/qfusion
void CG_Democam_DrawCenterSubtitle( int y, unsigned int maxwidth, struct qfontface_s *font, char *text ) {
	char *ptr, *s, *t, c, d;
	int x = cgs.vidWidth / 2;

	if( !text || !text[0] ) {
		return;
	}

	int shadowOffset = 2 * cgs.vidHeight / 600;
	if( !shadowOffset ) {
		shadowOffset = 1;
	}

	if( !maxwidth || trap_SCR_strWidth( text, font, 0 ) <= maxwidth ) {
		trap_SCR_DrawStringWidth( x + shadowOffset, y + shadowOffset, ALIGN_CENTER_TOP, COM_RemoveColorTokens( text ), maxwidth, font, colorBlack );
		trap_SCR_DrawStringWidth( x, y, ALIGN_CENTER_TOP, text, maxwidth, font, colorWhite );
		return;
	}

	t = s = ptr = text;
	while( *s ) {
		while( *s && *s != ' ' && *s != '\n' )
			s++;

		if( ( !*s || *s == '\n' ) && trap_SCR_strWidth( ptr, font, 0 ) < maxwidth ) { // new line or end of text, in both cases force write
			c = *s;
			*s = 0;
			trap_SCR_DrawStringWidth( x + shadowOffset, y + shadowOffset, ALIGN_CENTER_TOP, COM_RemoveColorTokens( ptr ), maxwidth, font, colorBlack );
			trap_SCR_DrawStringWidth( x, y, ALIGN_CENTER_TOP, ptr, maxwidth, font, colorWhite );
			*s = c;

			if( !*s ) {
				break;
			}

			t = s;
			s++;
			ptr = s;
		} else {
			c = *s;
			*s = 0;

			if( trap_SCR_strWidth( ptr, font, 0 ) < maxwidth ) {
				*s = c;
				t = s;
				s++;
				continue;
			}

			*s = c;
			d = *t;
			*t = 0;
			trap_SCR_DrawStringWidth( x + shadowOffset, y + shadowOffset, ALIGN_CENTER_TOP, COM_RemoveColorTokens( ptr ), maxwidth, font, colorBlack );
			trap_SCR_DrawStringWidth( x, y, ALIGN_CENTER_TOP, ptr, maxwidth, font, colorWhite );
			*t = d;
			s = t;
			s++;
			ptr = s;
		}

		y += trap_SCR_FontHeight( font );
	}
}
コード例 #18
0
/**
 * Responds to a Steam server query.
 *
 * @param s       query string
 * @param socket  response socket
 * @param address response address
 * @param inmsg   message for arguments
 * @return whether the request was handled as a Steam query
 */
bool TV_Downstream_SteamServerQuery( const char *s, const socket_t *socket, const netadr_t *address, msg_t *inmsg )
{
#if APP_STEAMID
	if( ( !tv_public->integer && !NET_IsLANAddress( address ) ) || ( tv_maxclients->integer == 1 ) )
		return false;

	if( !strcmp( s, "i" ) )
	{
		// ping
		const char pingResponse[] = "j00000000000000";
		Netchan_OutOfBand( socket, address, sizeof( pingResponse ), ( const uint8_t * )pingResponse );
		return true;
	}

	if( !strcmp( s, "TSource Engine Query" ) )
	{
		// server info
		char hostname[MAX_INFO_VALUE];
		char gamedir[MAX_QPATH];
		char version[32];
		int i, count = 0;
		msg_t msg;
		uint8_t msgbuf[MAX_STEAMQUERY_PACKETLEN - sizeof( int32_t )];

		Q_strncpyz( hostname, COM_RemoveColorTokens( tv_name->string ), sizeof( hostname ) );
		if( !hostname[0] )
			Q_strncpyz( hostname, tv_name->dvalue, sizeof( hostname ) );
		Q_strncpyz( gamedir, FS_GameDirectory(), sizeof( gamedir ) );

		for( i = 0; i < tv_maxclients->integer; i++ )
		{
			if( tvs.clients[i].state >= CS_CONNECTED )
			{
				count++;
				if( count == 99 )
					break;
			}
		}

		Q_snprintfz( version, sizeof( version ), "%i.%i.0.0", APP_VERSION_MAJOR, APP_VERSION_MINOR );

		MSG_Init( &msg, msgbuf, sizeof( msgbuf ) );
		MSG_WriteByte( &msg, 'I' );
		MSG_WriteByte( &msg, APP_PROTOCOL_VERSION );
		MSG_WriteString( &msg, hostname );
		MSG_WriteString( &msg, "" ); // no map
		MSG_WriteString( &msg, gamedir );
		MSG_WriteString( &msg, APPLICATION " TV" );
		MSG_WriteShort( &msg, 0 ); // app ID specified later
		MSG_WriteByte( &msg, count );
		MSG_WriteByte( &msg, min( tv_maxclients->integer, 99 ) );
		MSG_WriteByte( &msg, 0 ); // no bots
		MSG_WriteByte( &msg, 'p' );
		MSG_WriteByte( &msg, STEAMQUERY_OS );
		MSG_WriteByte( &msg, tv_password->string[0] ? 1 : 0 );
		MSG_WriteByte( &msg, 0 ); // VAC insecure
		MSG_WriteString( &msg, version );
		MSG_WriteByte( &msg, 0x40 | 0x1 ); // spectator data | game ID containing app ID
		// spectator data
		MSG_WriteShort( &msg, tv_port->integer );
		MSG_WriteString( &msg, hostname );
		// 64-bit game ID - needed to specify app ID
		MSG_WriteLong( &msg, APP_STEAMID & 0xffffff );
		MSG_WriteLong( &msg, 0 );
		Netchan_OutOfBand( socket, address, msg.cursize, msg.data );
		return true;
	}

	if( !strcmp( s, "s" ) )
	{
		// master server query, terminated by \n, followed by the challenge
		bool isSteamMaster = false;
		int challenge;
		char gamedir[MAX_QPATH], basedir[MAX_QPATH];
		int i, count = 0;
		char msg[MAX_STEAMQUERY_PACKETLEN];

		if( !TV_Downstream_IsMaster( address, &isSteamMaster ) || !isSteamMaster )
			return true;

		challenge = MSG_ReadLong( inmsg );

		Q_strncpyz( gamedir, FS_GameDirectory(), sizeof( gamedir ) );
		Q_strncpyz( basedir, FS_BaseGameDirectory(), sizeof( basedir ) );

		for( i = 0; i < tv_maxclients->integer; i++ )
		{
			if( tvs.clients[i].state >= CS_CONNECTED )
			{
				count++;
				if( count == 99 )
					break;
			}
		}

		Q_snprintfz( msg, sizeof( msg ),
			"0\n\\protocol\\7\\challenge\\%i" // protocol must be 7 to match Source
			"\\players\\%i\\max\\%i\\bots\\0"
			"\\gamedir\\%s"
			"\\password\\%i\\os\\%c"
			"\\lan\\%i\\region\\255"
			"\\type\\p\\secure\\0"
			"\\version\\%i.%i.0.0"
			"\\product\\%s\n",
			challenge, 
			count, min( tv_maxclients->integer, 99 ),
			gamedir,
			tv_password->string[0] ? 1 : 0, STEAMQUERY_OS,
			tv_public->integer ? 0 : 1,
			APP_VERSION_MAJOR, APP_VERSION_MINOR,
			basedir );
		NET_SendPacket( socket, ( const uint8_t * )msg, strlen( msg ), address );

		return true;
	}

	if( s[0] == 'O' )
	{
		// out of date message
		static bool printed = false;
		if( !printed )
		{
			bool isSteamMaster = false;
			if( TV_Downstream_IsMaster( address, &isSteamMaster ) && isSteamMaster )
			{
				Com_Printf( "Server is out of date and cannot be added to the Steam master servers.\n" );
				printed = true;
			}
		}
		return true;
	}
#endif

	return false;
}
コード例 #19
0
ファイル: p_client.cpp プロジェクト: Clever-Boy/qfusion
/*
* G_SetName
*/
static void G_SetName( edict_t *ent, const char *original_name )
{
	const char *invalid_prefixes[] = { "console", "[team]", "[spec]", "[bot]", "[coach]", "[tv]", NULL };
	edict_t *other;
	char name[MAX_NAME_BYTES];
	char colorless[MAX_NAME_BYTES];
	int i, trynum, trylen;
	int c_ascii;
	int maxchars;

	if( !ent->r.client )
		return;

	// we allow NULL to be passed for name
	if( !original_name )
		original_name = "";

	Q_strncpyz( name, original_name, sizeof( name ) );

	c_ascii = G_SanitizeUserString( name, sizeof( name ) );
	if( !c_ascii )
		Q_strncpyz( name, "Player", sizeof( name ) );
	Q_strncpyz( colorless, COM_RemoveColorTokens( name ), sizeof( colorless ) );

	if( !( ent->r.svflags & SVF_FAKECLIENT ) )
	{
		for( i = 0; invalid_prefixes[i] != NULL; i++ )
		{
			if( !Q_strnicmp( colorless, invalid_prefixes[i], strlen( invalid_prefixes[i] ) ) )
			{
				Q_strncpyz( name, "Player", sizeof( name ) );
				Q_strncpyz( colorless, COM_RemoveColorTokens( name ), sizeof( colorless ) );
				break;
			}
		}
	}

	maxchars = MAX_NAME_CHARS;
	if( ent->r.client->isTV )
		maxchars = min( maxchars + 10, MAX_NAME_BYTES-1 );

	// Limit the name to MAX_NAME_CHARS printable characters
	// (non-ascii utf-8 sequences are currently counted as 2 or more each, sorry)
	COM_SanitizeColorString( va( "%s", name ), name, sizeof( name ),
		maxchars, COLOR_WHITE );
	Q_strncpyz( colorless, COM_RemoveColorTokens( name ), sizeof( colorless ) );

	trynum = 1;
	do
	{
		for( i = 0; i < gs.maxclients; i++ )
		{
			other = game.edicts + 1 + i;
			if( !other->r.inuse || !other->r.client || other == ent )
				continue;

			// if nick is already in use, try with (number) appended
			if( !Q_stricmp( colorless, COM_RemoveColorTokens( other->r.client->netname ) ) )
			{
				if( trynum != 1 )  // remove last try
					name[strlen( name ) - strlen( va( "%s(%i)", S_COLOR_WHITE, trynum-1 ) )] = 0;

				// make sure there is enough space for the postfix
				trylen = strlen( va( "%s(%i)", S_COLOR_WHITE, trynum ) );
				if( (int)strlen( colorless ) + trylen > maxchars )
				{
					COM_SanitizeColorString( va( "%s", name ), name, sizeof( name ),
						maxchars - trylen, COLOR_WHITE );
					Q_strncpyz( colorless, COM_RemoveColorTokens( name ), sizeof( colorless ) );
				}

				// add the postfix
				Q_strncatz( name, va( "%s(%i)", S_COLOR_WHITE, trynum ), sizeof( name ) );
				Q_strncpyz( colorless, COM_RemoveColorTokens( name ), sizeof( colorless ) );

				// go trough all clients again
				trynum++;
				break;
			}
		}
	}
	while( i != gs.maxclients && trynum <= MAX_CLIENTS );

	Q_strncpyz( ent->r.client->netname, name, sizeof( ent->r.client->netname ) );
}
コード例 #20
0
ファイル: p_client.cpp プロジェクト: Clever-Boy/qfusion
/*
* G_SetClan
*/
static void G_SetClan( edict_t *ent, const char *original_clan )
{
	const char *invalid_values[] = { "console", "spec", "bot", "coach", "tv", NULL };
	char clan[MAX_CLANNAME_BYTES];
	char colorless[MAX_CLANNAME_BYTES];
	int i;
	int c_ascii;
	int maxchars;

	if( !ent->r.client )
		return;

	// we allow NULL to be passed for clan name
	if( ent->r.svflags & SVF_FAKECLIENT )
		original_clan = "BOT";
	else if( !original_clan )
		original_clan = "";

	Q_strncpyz( clan, original_clan, sizeof( clan ) );
	COM_Compress( clan );

	c_ascii = G_SanitizeUserString( clan, sizeof( clan ) );
	if( !c_ascii )
		clan[0] = colorless[0] = '\0';
	else
		Q_strncpyz( colorless, COM_RemoveColorTokens( clan ), sizeof( colorless ) );

	if( !( ent->r.svflags & SVF_FAKECLIENT ) )
	{
		for( i = 0; invalid_values[i] != NULL; i++ )
		{
			if( !Q_strnicmp( colorless, invalid_values[i], strlen( invalid_values[i] ) ) )
			{
				clan[0] = colorless[0] = '\0';
				break;
			}
		}
	}

	// clan names can not contain spaces
	Q_chrreplace( clan, ' ', '_' );

	// clan names can not start with an ampersand
	{
		char *t;
		int len;

		t = clan;
		while( *t == '&' ) t++;
		len = strlen( clan ) - (t - clan);
		if( clan != t )
			memmove( clan, t, len + 1 );
	}

	maxchars = MAX_CLANNAME_CHARS;

	// Limit the name to MAX_NAME_CHARS printable characters
	// (non-ascii utf-8 sequences are currently counted as 2 or more each, sorry)
	COM_SanitizeColorString( va( "%s", clan ), clan, sizeof( clan ), maxchars, COLOR_WHITE );

	Q_strncpyz( ent->r.client->clanname, clan, sizeof( ent->r.client->clanname ) );
}
コード例 #21
0
/*
* G_Match_Autorecord_Start
*/
void G_Match_Autorecord_Start( void )
{
	int team, i, playerCount;

	G_Match_SetAutorecordState( "start" );

	// do not start autorecording if all playing clients are bots
	for( playerCount = 0, team = TEAM_PLAYERS; team < GS_MAX_TEAMS; team++ )
	{
		// add our team info to the string
		for( i = 0; i < teamlist[team].numplayers; i++ )
		{
			if( game.edicts[ teamlist[team].playerIndices[i] ].r.svflags & SVF_FAKECLIENT )
				continue;

			playerCount++;
			break; // we only need one for this check
		}
	}

	if( playerCount && g_autorecord->integer )
	{
		char datetime[17], players[MAX_STRING_CHARS];
		time_t long_time;
		struct tm *newtime;

		// date & time
		time( &long_time );
		newtime = localtime( &long_time );

		Q_snprintfz( datetime, sizeof( datetime ), "%04d-%02d-%02d_%02d-%02d", newtime->tm_year + 1900,
			newtime->tm_mon+1, newtime->tm_mday, newtime->tm_hour, newtime->tm_min );

		// list of players
		Q_strncpyz( players, trap_GetConfigString( CS_MATCHNAME ), sizeof( players ) );
		if( players[0] == '\0' )
		{
			if( GS_InvidualGameType() )
			{
				const char *netname;
				int team;
				edict_t *ent;

				for( team = TEAM_ALPHA; team < GS_MAX_TEAMS; team++ )
				{
					if( !teamlist[team].numplayers )
						continue;
					ent = game.edicts + teamlist[team].playerIndices[0];
					netname = ent->r.client->netname;
					Q_strncatz( players, netname, sizeof( players ) );
					if( team != GS_MAX_TEAMS - 1 )
						Q_strncatz( players, " vs ", sizeof( players ) );
				}
			}
		}

		if( players[0] != '\0' )
		{
			char *t = strstr( players, " vs " );
			if( t )
				memcpy( t, "_vs_", strlen( "_vs_" ) );
			Q_strncpyz( players, COM_RemoveJunkChars( COM_RemoveColorTokens( players ) ), sizeof( players ) );
		}

		// combine
		Q_snprintfz( level.autorecord_name, sizeof( level.autorecord_name ), "%s_%s_%s%s%s_auto%04i", 
			datetime, gs.gametypeName, level.mapname, players[0] == '\0' ? "" : "_", players, (int)brandom( 1, 9999 ) );

		trap_Cmd_ExecuteText( EXEC_APPEND, va( "serverrecord %s\n", level.autorecord_name ) );
	}
}
コード例 #22
0
ファイル: tvm_chase.c プロジェクト: Clever-Boy/qfusion
void TVM_ChasePlayer( edict_t *ent, char *name, int followmode )
{
	int i;
	edict_t *e;
	gclient_t *client;
	int targetNum = -1;
	int oldTarget;
	bool can_follow = true;
	char colorlessname[MAX_NAME_BYTES];

	client = ent->r.client;

	oldTarget = client->chase.target;
	if( oldTarget < 0 )
		oldTarget = 0;

	if( !can_follow && followmode )
	{
		TVM_PrintMsg( ent->relay, ent, "Chasecam follow mode unavailable\n" );
		followmode = false;
	}

	if( ent->r.client->chase.followmode && !followmode )
		TVM_PrintMsg( ent->relay, ent, "Disabling chasecam follow mode\n" );

	// always disable chasing as a start
	memset( &client->chase, 0, sizeof( chasecam_t ) );

	// locate the requested target
	if( name && name[0] )
	{
		// find it by player names
		for( e = ent->relay->edicts + 1; PLAYERNUM( e ) < ent->relay->maxclients; e++ )
		{
			if( !TVM_Chase_IsValidTarget( ent, e ) )
				continue;

			Q_strncpyz( colorlessname, COM_RemoveColorTokens( e->r.client->pers.netname ), sizeof(colorlessname) );

			if( !Q_stricmp( COM_RemoveColorTokens( name ), colorlessname ) )
			{
				targetNum = PLAYERNUM( e );
				break;
			}
		}

		// didn't find it by name, try by numbers
		if( targetNum == -1 )
		{
			i = atoi( name );
			if( i >= 0 && i < ent->relay->maxclients )
			{
				e = ent->relay->edicts + 1 + i;
				if( TVM_Chase_IsValidTarget( ent, e ) )
					targetNum = PLAYERNUM( e );
			}
		}

		if( targetNum == -1 )
			TVM_PrintMsg( ent->relay, ent, "Requested chasecam target is not available\n" );
	}

	// try to reuse old target if we didn't find a valid one
	if( targetNum == -1 && oldTarget > 0 && oldTarget <= ent->relay->maxclients )
	{
		e = ent->relay->edicts + 1 + oldTarget;
		if( TVM_Chase_IsValidTarget( ent, e ) )
			targetNum = PLAYERNUM( e );
	}

	// if we still don't have a target, just pick the first valid one
	if( targetNum == -1 )
	{
		for( e = ent->relay->edicts + 1; PLAYERNUM( e ) < ent->relay->maxclients; e++ )
		{
			if( !TVM_Chase_IsValidTarget( ent, e ) )
				continue;

			targetNum = PLAYERNUM( e );
			break;
		}
	}

	// make the client a ghost
	TVM_GhostClient( ent );
	if( targetNum != -1 )
	{
		// we found a target, set up the chasecam
		client->chase.target = targetNum + 1;
		client->chase.followmode = followmode;
		TVM_Chase_SetChaseActive( ent, true );
	}
	else
	{
		// stay as observer
		ent->movetype = MOVETYPE_NOCLIP;
		TVM_SpectatorMode( ent );
		TVM_CenterPrintMsg( ent->relay, ent, "No one to chase" );
	}
}