⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sv_rankings.c

📁 3D 游戏界的大牛人 John Carmack 终于放出了 Q3 的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	GR_STATUS			join_status;
	GR_STATUS			cleanup_status;
	
	assert( gr_login != NULL );
	assert( cbf_arg != NULL );

	Com_DPrintf( "SV_RankUserCBF( %08X, %08X );\n", gr_login, cbf_arg );
	
	ranked_player = (ranked_player_t*)cbf_arg;
	assert(ranked_player);
	assert( ranked_player->context );
	
	switch( gr_login->status )
	{
		case GR_STATUS_OK:
			// attempt to join the game, proceed to SV_RankJoinGameCBF
			join_status = GRankJoinGameAsync
				( 
					ranked_player->context,
					s_rankings_game_id,
					SV_RankJoinGameCBF,
					cbf_arg,
					GR_OPT_END
				);

			if( join_status != GR_STATUS_PENDING )
			{
				SV_RankError( "SV_RankUserCBF: Expected GR_STATUS_PENDING "
					"from GRankJoinGameAsync, got %s", 
					SV_RankStatusString( join_status ) );
			}
			break;
		case GR_STATUS_NOUSER:
			Com_DPrintf( "SV_RankUserCBF: Got status %s\n",
				SV_RankStatusString( gr_login->status ) );
			ranked_player->final_status = QGR_STATUS_NO_USER;
			break;
		case GR_STATUS_BADPASSWORD:
			Com_DPrintf( "SV_RankUserCBF: Got status %s\n",
				SV_RankStatusString( gr_login->status ) );
			ranked_player->final_status = QGR_STATUS_BAD_PASSWORD;
			break;
		case GR_STATUS_TIMEOUT:
			Com_DPrintf( "SV_RankUserCBF: Got status %s\n",
				SV_RankStatusString( gr_login->status ) );
			ranked_player->final_status = QGR_STATUS_TIMEOUT;
			break;
		default:
			Com_DPrintf( "SV_RankUserCBF: Unexpected status %s\n",
				SV_RankStatusString( gr_login->status ) );
			ranked_player->final_status = QGR_STATUS_ERROR;
			break;
	}

	if( ranked_player->final_status != QGR_STATUS_NEW )
	{
		// login or create failed, so clean up before the next attempt
		cleanup_status = GRankCleanupAsync
			(
				ranked_player->context,
				0,
				SV_RankCleanupCBF,
				(void*)ranked_player,
				GR_OPT_END
			);
			
		if( cleanup_status != GR_STATUS_PENDING )
		{
			SV_RankError( "SV_RankUserCBF: Expected GR_STATUS_PENDING "
				"from GRankCleanupAsync, got %s", 
				SV_RankStatusString( cleanup_status ) );
			SV_RankCloseContext( ranked_player );
		}
	}
}

/*
================
SV_RankJoinGameCBF
================
*/
static void SV_RankJoinGameCBF( GR_JOINGAME* gr_joingame, void* cbf_arg )
{
	ranked_player_t*	ranked_player;
	GR_MATCH			match;
	GR_STATUS           cleanup_status;

	assert( gr_joingame != NULL );
	assert( cbf_arg != NULL );
	
	Com_DPrintf( "SV_RankJoinGameCBF( %08X, %08X );\n", gr_joingame, cbf_arg );
	
	ranked_player = (ranked_player_t*)cbf_arg;

	assert( ranked_player );
	assert( ranked_player->context != 0 );
	
	if( gr_joingame->status == GR_STATUS_OK )
	{
		int i;
		// save user id
		ranked_player->player_id = gr_joingame->player_id;
		memcpy(ranked_player->token,gr_joingame->token,
			sizeof(GR_PLAYER_TOKEN)) ;
		match = GRankStartMatch( ranked_player->context );
		ranked_player->match = match.match;
		ranked_player->grank = gr_joingame->rank;

		// find the index and call SV_RankUserValidate
		for (i=0;i<sv_maxclients->value;i++)
			if ( ranked_player == &s_ranked_players[i] )
				SV_RankUserValidate(i,NULL,NULL,0, gr_joingame->rank,ranked_player->name);
	}
	else
	{
		//GRand handle join game failure
		SV_RankError( "SV_RankJoinGameCBF: Unexpected status %s",
			SV_RankStatusString( gr_joingame->status ) );
		
		cleanup_status = GRankCleanupAsync
			(
				ranked_player->context,
				0,
				SV_RankCleanupCBF,
				cbf_arg,
				GR_OPT_END
			);
		
		if( cleanup_status != GR_STATUS_PENDING )
		{
			SV_RankError( "SV_RankJoinGameCBF: Expected "
				"GR_STATUS_PENDING from GRankCleanupAsync, got %s", 
				SV_RankStatusString( cleanup_status ) );
			SV_RankCloseContext( ranked_player );
		}
	}		
}

/*
================
SV_RankSendReportsCBF
================
*/
static void SV_RankSendReportsCBF( GR_STATUS* status, void* cbf_arg )
{
	ranked_player_t*	ranked_player;
	GR_CONTEXT			context;
	GR_STATUS			cleanup_status;

	assert( status != NULL );
	// NULL cbf_arg means server is sending match reports
	
	Com_DPrintf( "SV_RankSendReportsCBF( %08X, %08X );\n", status, cbf_arg );
	
	ranked_player = (ranked_player_t*)cbf_arg;
	if( ranked_player == NULL )
	{
		Com_DPrintf( "SV_RankSendReportsCBF: server\n" );
		context = s_server_context;
	}
	else
	{
		Com_DPrintf( "SV_RankSendReportsCBF: player\n" );
		context = ranked_player->context;
	}

	//assert( context != 0 );
	if( *status != GR_STATUS_OK )
	{
		SV_RankError( "SV_RankSendReportsCBF: Unexpected status %s",
			SV_RankStatusString( *status ) );
	}
	
	if( context == 0 )
	{
		Com_DPrintf( "SV_RankSendReportsCBF: WARNING: context == 0" );
		SV_RankCloseContext( ranked_player );
	}
	else
	{
		cleanup_status = GRankCleanupAsync
			(
				context,
				0,
				SV_RankCleanupCBF,
				cbf_arg,
				GR_OPT_END
			);
		
		if( cleanup_status != GR_STATUS_PENDING )
		{
			SV_RankError( "SV_RankSendReportsCBF: Expected "
				"GR_STATUS_PENDING from GRankCleanupAsync, got %s", 
				SV_RankStatusString( cleanup_status ) );
			SV_RankCloseContext( ranked_player );
		}
	}
}

/*
================
SV_RankCleanupCBF
================
*/
static void SV_RankCleanupCBF( GR_STATUS* status, void* cbf_arg )
{
	ranked_player_t*	ranked_player;
	ranked_player = (ranked_player_t*)cbf_arg;

	assert( status != NULL );
	// NULL cbf_arg means server is cleaning up

	Com_DPrintf( "SV_RankCleanupCBF( %08X, %08X );\n", status, cbf_arg );
	
	if( *status != GR_STATUS_OK )
	{
		SV_RankError( "SV_RankCleanupCBF: Unexpected status %s",
			SV_RankStatusString( *status ) );
	}

	SV_RankCloseContext( ranked_player );
}

/*
================
SV_RankCloseContext
================
*/
static void SV_RankCloseContext( ranked_player_t* ranked_player )
{
	if( ranked_player == NULL )
	{
		// server cleanup
		if( s_server_context == 0 )
		{
			return;
		}
		s_server_context = 0;
		s_server_match = 0;
	}
	else
	{
		// player cleanup
		if( s_ranked_players == NULL )
		{
			return;
		}
		if( ranked_player->context == 0 )
		{
			return;
		}
		ranked_player->context = 0;
		ranked_player->match = 0;
		ranked_player->player_id = 0;
		memset( ranked_player->token, 0, sizeof(GR_PLAYER_TOKEN) );
		ranked_player->grank_status = ranked_player->final_status;
		ranked_player->final_status = QGR_STATUS_NEW;
		ranked_player->name[0] = '\0';
	}

	assert( s_rankings_contexts > 0 );
	s_rankings_contexts--;
	Com_DPrintf( "SV_RankCloseContext: s_rankings_contexts = %d\n", 
		s_rankings_contexts );

	if( s_rankings_contexts == 0 )
	{
		GRankLogLevel( GRLOG_OFF );
		
		if( s_ranked_players != NULL )
		{
			Z_Free( s_ranked_players );
			s_ranked_players = NULL;
		}

		s_rankings_active = qfalse;
		Cvar_Set( "sv_rankingsActive", "0" );
	}
}

/*
================
SV_RankAsciiEncode

Encodes src_len bytes of binary data from the src buffer as ASCII text, 
using 6 bits per character. The result string is null-terminated and 
stored in the dest buffer.

The dest buffer must be at least (src_len * 4) / 3 + 2 bytes in length.

Returns the length of the result string, not including the null.
================
*/
static int SV_RankAsciiEncode( char* dest, const unsigned char* src, 
	int src_len )
{
	unsigned char	bin[3];
	unsigned char	txt[4];
	int				dest_len = 0;
	int				i;
	int				j;
	int				num_chars;

	assert( dest != NULL );
	assert( src != NULL );
	
	for( i = 0; i < src_len; i += 3 )
	{
		// read three bytes of input
		for( j = 0; j < 3; j++ )
		{
			bin[j] = (i + j < src_len) ? src[i + j] : 0;
		}

		// get four 6-bit values from three bytes
		txt[0] = bin[0] >> 2;
		txt[1] = ((bin[0] << 4) | (bin[1] >> 4)) & 63;
		txt[2] = ((bin[1] << 2) | (bin[2] >> 6)) & 63;
		txt[3] = bin[2] & 63;

		// store ASCII encoding of 6-bit values
		num_chars = (i + 2 < src_len) ? 4 : ((src_len - i) * 4) / 3 + 1;
		for( j = 0; j < num_chars; j++ )
		{
			dest[dest_len++] = s_ascii_encoding[txt[j]];
		}
	}
	
	dest[dest_len] = '\0';

	return dest_len;
}

/*
================
SV_RankAsciiDecode

Decodes src_len characters of ASCII text from the src buffer, stores 
the binary result in the dest buffer.

The dest buffer must be at least (src_len * 3) / 4 bytes in length.

Returns the length of the binary result, or zero for invalid input.
================
*/
static int SV_RankAsciiDecode( unsigned char* dest, const char* src, 
	int src_len )
{
	static unsigned char	s_inverse_encoding[256];
	static char				s_init = 0;
	
	unsigned char	bin[3];
	unsigned char	txt[4];
	int				dest_len = 0;
	int				i;
	int				j;
	int				num_bytes;
	
	assert( dest != NULL );
	assert( src != NULL );

	if( !s_init )
	{
		// initialize lookup table for decoding
		memset( s_inverse_encoding, 255, sizeof(s_inverse_encoding) );
		for( i = 0; i < 64; i++ )
		{
			s_inverse_encoding[s_ascii_encoding[i]] = i;
		}
		s_init = 1;
	}
	
	for( i = 0; i < src_len; i += 4 )
	{
		// read four characters of input, decode them to 6-bit values
		for( j = 0; j < 4; j++ )
		{
			txt[j] = (i + j < src_len) ? s_inverse_encoding[src[i + j]] : 0;
			if (txt[j] == 255)
			{
				return 0; // invalid input character
			}
		}
		
		// get three bytes from four 6-bit values
		bin[0] = (txt[0] << 2) | (txt[1] >> 4);
		bin[1] = (txt[1] << 4) | (txt[2] >> 2);
		bin[2] = (txt[2] << 6) | txt[3];

		// store binary data
		num_bytes = (i + 3 < src_len) ? 3 : ((src_len - i) * 3) / 4;
		for( j = 0; j < num_bytes; j++ )
		{
			dest[dest_len++] = bin[j];
		}
	}

	return dest_len;
}

/*
================
SV_RankEncodeGameID
================
*/
static void SV_RankEncodeGameID( uint64_t game_id, char* result, 
	int len )
{
	assert( result != NULL );

	if( len < ( ( sizeof(game_id) * 4) / 3 + 2) )
	{
		Com_DPrintf( "SV_RankEncodeGameID: result buffer too small\n" );
		result[0] = '\0';
	}
	else
	{
		qint64 gameid = LittleLong64(*(qint64*)&game_id);
		SV_RankAsciiEncode( result, (unsigned char*)&gameid, 
			sizeof(qint64) );
	}
}

/*
================
SV_RankDecodePlayerID
================
*/
static uint64_t SV_RankDecodePlayerID( const char* string )
{
	unsigned char	buffer[9];
	int len;
	qint64	player_id;

	assert( string != NULL );
	
	len = strlen (string) ;
	Com_DPrintf( "SV_RankDecodePlayerID: string length %d\n",len );
	SV_RankAsciiDecode( buffer, string, len );
	player_id = LittleLong64(*(qint64*)buffer);
	return *(uint64_t*)&player_id;
}

/*
================
SV_RankDecodePlayerKey
================
*/
static void SV_RankDecodePlayerKey( const char* string, GR_PLAYER_TOKEN key )
{
	unsigned char	buffer[1400];
	int len;
	assert( string != NULL );

	len = strlen (string) ;
	Com_DPrintf( "SV_RankDecodePlayerKey: string length %d\n",len );
	
	memset(key,0,sizeof(GR_PLAYER_TOKEN));
	memset(buffer,0,sizeof(buffer));
	memcpy( key, buffer, SV_RankAsciiDecode( buffer, string, len ) );
}

/*
================
SV_RankStatusString
================
*/
static char* SV_RankStatusString( GR_STATUS status )
{
	switch( status )
	{
		case GR_STATUS_OK:				return "GR_STATUS_OK";
		case GR_STATUS_ERROR:			return "GR_STATUS_ERROR";
		case GR_STATUS_BADPARAMS:		return "GR_STATUS_BADPARAMS";
		case GR_STATUS_NETWORK:			return "GR_STATUS_NETWORK";
		case GR_STATUS_NOUSER:			return "GR_STATUS_NOUSER";
		case GR_STATUS_BADPASSWORD:		return "GR_STATUS_BADPASSWORD";
		case GR_STATUS_BADGAME:			return "GR_STATUS_BADGAME";
		case GR_STATUS_PENDING:			return "GR_STATUS_PENDING";
		case GR_STATUS_BADDOMAIN:		return "GR_STATUS_BADDOMAIN";
		case GR_STATUS_DOMAINLOCK:		return "GR_STATUS_DOMAINLOCK";
		case GR_STATUS_TIMEOUT:			return "GR_STATUS_TIMEOUT";
		case GR_STATUS_INVALIDUSER:	    return "GR_STATUS_INVALIDUSER";
		case GR_STATUS_INVALIDCONTEXT:	return "GR_STATUS_INVALIDCONTEXT";
		default:						return "(UNKNOWN)";
	}
}

/*
================
SV_RankError
================
*/
static void SV_RankError( const char* fmt, ... )
{
	va_list	arg_ptr;
	char	text[1024];

	va_start( arg_ptr, fmt );
	vsprintf( text, fmt, arg_ptr );
	va_end( arg_ptr );

	Com_DPrintf( "****************************************\n" );
	Com_DPrintf( "SV_RankError: %s\n", text );
	Com_DPrintf( "****************************************\n" );

	s_rankings_active = qfalse;
	Cvar_Set( "sv_rankingsActive", "0" );
	// FIXME - attempt clean shutdown?
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -