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

📄 sv_rankings.c

📁 3D 游戏界的大牛人 John Carmack 终于放出了 Q3 的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
===========================================================================
Copyright (C) 1999-2005 Id Software, Inc.

This file is part of Quake III Arena source code.

Quake III Arena source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.

Quake III Arena source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Foobar; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
===========================================================================
*/
// sv_rankings.c -- global rankings interface

#include "server.h"
#include "..\rankings\1.0\gr\grapi.h"
#include "..\rankings\1.0\gr\grlog.h"

typedef struct
{
	GR_CONTEXT		context;
	uint64_t        game_id;
	uint64_t		match;
	uint64_t		player_id;
	GR_PLAYER_TOKEN     token;
	grank_status_t	grank_status;
	grank_status_t	final_status;	// status to set after cleanup
	uint32_t        grank;          // global rank
	char			name[32];
} ranked_player_t;

static int				s_rankings_contexts = 0;
static qboolean			s_rankings_active = qfalse;
static GR_CONTEXT		s_server_context = 0;
static uint64_t			s_server_match = 0;
static char*			s_rankings_game_key = NULL;
static uint64_t			s_rankings_game_id = 0;
static ranked_player_t*	s_ranked_players = NULL;
static qboolean			s_server_quitting = qfalse;
static const char		s_ascii_encoding[] = 
							"0123456789abcdef"
							"ghijklmnopqrstuv"
							"wxyzABCDEFGHIJKL"
							"MNOPQRSTUVWXYZ[]";

// private functions
static void		SV_RankNewGameCBF( GR_NEWGAME* gr_newgame, void* cbf_arg );
static void		SV_RankUserCBF( GR_LOGIN* gr_login, void* cbf_arg );
static void		SV_RankJoinGameCBF( GR_JOINGAME* gr_joingame, void* cbf_arg );
static void		SV_RankSendReportsCBF( GR_STATUS* gr_status, void* cbf_arg );
static void		SV_RankCleanupCBF( GR_STATUS* gr_status, void* cbf_arg );
static void		SV_RankCloseContext( ranked_player_t* ranked_player );
static int		SV_RankAsciiEncode( char* dest, const unsigned char* src, 
					int src_len );
static int		SV_RankAsciiDecode( unsigned char* dest, const char* src, 
					int src_len );
static void		SV_RankEncodeGameID( uint64_t game_id, char* result, 
					int len );
static uint64_t	SV_RankDecodePlayerID( const char* string );
static void		SV_RankDecodePlayerKey( const char* string, GR_PLAYER_TOKEN key );
static char*	SV_RankStatusString( GR_STATUS status );
static void		SV_RankError( const char* fmt, ... );
static char     SV_RankGameKey[64];

/*
================
SV_RankBegin
================
*/
void SV_RankBegin( char *gamekey )
{
	GR_INIT		init;
	GR_STATUS	status;

	assert( s_rankings_contexts == 0 );
	assert( !s_rankings_active );
	assert( s_ranked_players == NULL );

	if( sv_enableRankings->integer == 0 || Cvar_VariableValue( "g_gametype" ) == GT_SINGLE_PLAYER )
	{
		s_rankings_active = qfalse;
		if( sv_rankingsActive->integer == 1 )
		{
			Cvar_Set( "sv_rankingsActive", "0" );
		}
		return;
	}

	// only allow official game key on pure servers
	if( strcmp(gamekey, GR_GAMEKEY) == 0 )
	{
/*
		if( Cvar_VariableValue("sv_pure") != 1 )
		{
			Cvar_Set( "sv_enableRankings", "0" );
			return;
		}
*/

		// substitute game-specific game key
		switch( (int)Cvar_VariableValue("g_gametype") )
		{
		case GT_FFA:
			gamekey = "Q3 Free For All";
			break;
		case GT_TOURNAMENT:
			gamekey = "Q3 Tournament";
			break;
		case GT_TEAM:
			gamekey = "Q3 Team Deathmatch";
			break;
		case GT_CTF:
			gamekey = "Q3 Capture the Flag";
			break;
		case GT_1FCTF:
			gamekey = "Q3 One Flag CTF";
			break;
		case GT_OBELISK:
			gamekey = "Q3 Overload";
			break;
		case GT_HARVESTER:
			gamekey = "Q3 Harvester";
			break;
		default:
			break;
		}
	}
	s_rankings_game_key = gamekey;

	// initialize rankings
	GRankLogLevel( GRLOG_OFF );
	memset(SV_RankGameKey,0,sizeof(SV_RankGameKey));
	strncpy(SV_RankGameKey,gamekey,sizeof(SV_RankGameKey)-1);
	init = GRankInit( 1, SV_RankGameKey, GR_OPT_POLL, GR_OPT_END );
	s_server_context = init.context;
	s_rankings_contexts++;
	Com_DPrintf( "SV_RankBegin(); GR_GAMEKEY is %s\n", gamekey );
	Com_DPrintf( "SV_RankBegin(); s_rankings_contexts=%d\n",s_rankings_contexts );
	Com_DPrintf( "SV_RankBegin(); s_server_context=%d\n",init.context );

	// new game
	if(!strlen(Cvar_VariableString( "sv_leagueName" )))
	{
		status = GRankNewGameAsync
			( 			
				s_server_context, 
				SV_RankNewGameCBF, 
				NULL, 
				GR_OPT_LEAGUENAME,
				(void*)(Cvar_VariableString( "sv_leagueName" )),
				GR_OPT_END 
			);
	}
	else
	{
		status = GRankNewGameAsync
			( 			
				s_server_context, 
				SV_RankNewGameCBF, 
				NULL, 
				GR_OPT_END 
			);
	}
		
	if( status != GR_STATUS_PENDING )
	{
		SV_RankError( "SV_RankBegin: Expected GR_STATUS_PENDING, got %s", 
			SV_RankStatusString( status ) );
		return;
	}

	// logging
	if( com_developer->value )
	{
		GRankLogLevel( GRLOG_TRACE );
	}
	
	// allocate rankings info for each player
	s_ranked_players = Z_Malloc( sv_maxclients->value * 
		sizeof(ranked_player_t) );
	memset( (void*)s_ranked_players, 0 ,sv_maxclients->value 
		* sizeof(ranked_player_t));
}

/*
================
SV_RankEnd
================
*/
void SV_RankEnd( void )
{
	GR_STATUS	status;
	int			i;
	
	Com_DPrintf( "SV_RankEnd();\n" );

	if( !s_rankings_active )
	{
		// cleanup after error during game
		if( s_ranked_players != NULL )
		{
			for( i = 0; i < sv_maxclients->value; i++ )
			{
				if( s_ranked_players[i].context != 0 )
				{
					SV_RankCloseContext( &(s_ranked_players[i]) );
				}
			}
		}
		if( s_server_context != 0 )
		{
			SV_RankCloseContext( NULL );
		}

		return;
	}

	for( i = 0; i < sv_maxclients->value; i++ )
	{
		if( s_ranked_players[i].grank_status == QGR_STATUS_ACTIVE )
		{
			SV_RankUserLogout( i );
			Com_DPrintf( "SV_RankEnd: SV_RankUserLogout %d\n",i );
		}
	}

	assert( s_server_context != 0 );
	
	// send match reports, proceed to SV_RankSendReportsCBF
	status = GRankSendReportsAsync
		( 
			s_server_context,
			0,
			SV_RankSendReportsCBF,
			NULL, 
			GR_OPT_END
		);
			
	if( status != GR_STATUS_PENDING )
	{
		SV_RankError( "SV_RankEnd: Expected GR_STATUS_PENDING, got %s", 
			SV_RankStatusString( status ) );
	}

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

/*
================
SV_RankPoll
================
*/
void SV_RankPoll( void )
{
	GRankPoll();
}

/*
================
SV_RankCheckInit
================
*/
qboolean SV_RankCheckInit( void )
{
	return (s_rankings_contexts > 0);
}

/*
================
SV_RankActive
================
*/
qboolean SV_RankActive( void )
{
	return s_rankings_active;
}

/*
=================
SV_RankUserStatus
=================
*/
grank_status_t SV_RankUserStatus( int index )
{
	if( !s_rankings_active )
	{
		return GR_STATUS_ERROR;
	}

	assert( s_ranked_players != NULL );
	assert( index >= 0 );
	assert( index < sv_maxclients->value );

	return s_ranked_players[index].grank_status;
}

/*
================
SV_RankUserGRank
================
*/
int SV_RankUserGrank( int index )
{
	if( !s_rankings_active )
	{
		return 0;
	}

	assert( s_ranked_players != NULL );
	assert( index >= 0 );
	assert( index < sv_maxclients->value );

	return s_ranked_players[index].grank;
}

/*
================
SV_RankUserReset
================
*/
void SV_RankUserReset( int index )
{
	if( !s_rankings_active )
	{
		return;
	}

	assert( s_ranked_players != NULL );
	assert( index >= 0 );
	assert( index < sv_maxclients->value );

	switch( s_ranked_players[index].grank_status )
	{
	case QGR_STATUS_SPECTATOR:
	case QGR_STATUS_NO_USER:
	case QGR_STATUS_BAD_PASSWORD:
	case QGR_STATUS_USER_EXISTS:
	case QGR_STATUS_NO_MEMBERSHIP:
	case QGR_STATUS_TIMEOUT:
	case QGR_STATUS_ERROR:
		s_ranked_players[index].grank_status = QGR_STATUS_NEW;
		break;
	default:
		break;
	}
}

/*
================
SV_RankUserSpectate
================
*/
void SV_RankUserSpectate( int index )
{
	if( !s_rankings_active )
	{
		return;
	}

	assert( s_ranked_players != NULL );
	assert( index >= 0 );
	assert( index < sv_maxclients->value );

	// GRANK_FIXME - check current status?
	s_ranked_players[index].grank_status = QGR_STATUS_SPECTATOR;
}

/*
================
SV_RankUserCreate
================
*/
void SV_RankUserCreate( int index, char* username, char* password, 
	char* email )
{
	GR_INIT		init;
	GR_STATUS	status;

	assert( index >= 0 );
	assert( index < sv_maxclients->value );
	assert( username != NULL );
	assert( password != NULL );
	assert( email != NULL );
	assert( s_ranked_players );
	assert( s_ranked_players[index].grank_status != QGR_STATUS_ACTIVE );
	
	Com_DPrintf( "SV_RankUserCreate( %d, %s, \"****\", %s );\n", index, 
		username, email );

	if( !s_rankings_active )
	{
		Com_DPrintf( "SV_RankUserCreate: Not ready to create\n" );
		s_ranked_players[index].grank_status = QGR_STATUS_ERROR;
		return;
	}
	
	if( s_ranked_players[index].grank_status == QGR_STATUS_ACTIVE )
	{
		Com_DPrintf( "SV_RankUserCreate: Got Create from active player\n" );
		return;
	}
	
	// get a separate context for the new user
	init = GRankInit( 0, SV_RankGameKey, GR_OPT_POLL, GR_OPT_END );
	s_ranked_players[index].context = init.context;
	s_rankings_contexts++;
	Com_DPrintf( "SV_RankUserCreate(); s_rankings_contexts=%d\n",s_rankings_contexts );
	Com_DPrintf( "SV_RankUserCreate(); s_ranked_players[%d].context=%d\n",index,init.context );
	
	// attempt to create a new account, proceed to SV_RankUserCBF
	status = GRankUserCreateAsync
		( 
			s_ranked_players[index].context, 
			username, 
			password, 
			email, 
			SV_RankUserCBF, 
			(void*)&s_ranked_players[index], 
			GR_OPT_END
		);

	if( status == GR_STATUS_PENDING )
	{
		s_ranked_players[index].grank_status = QGR_STATUS_PENDING;
		s_ranked_players[index].final_status = QGR_STATUS_NEW;
	}
	else
	{
		SV_RankError( "SV_RankUserCreate: Expected GR_STATUS_PENDING, got %s", 
			SV_RankStatusString( status ) );
	}
}

/*
================
SV_RankUserLogin
================
*/
void SV_RankUserLogin( int index, char* username, char* password )
{
	GR_INIT		init;
	GR_STATUS	status;

	assert( index >= 0 );
	assert( index < sv_maxclients->value );
	assert( username != NULL );
	assert( password != NULL );
	assert( s_ranked_players );
	assert( s_ranked_players[index].grank_status != QGR_STATUS_ACTIVE );

	Com_DPrintf( "SV_RankUserLogin( %d, %s, \"****\" );\n", index, username );

	if( !s_rankings_active )
	{
		Com_DPrintf( "SV_RankUserLogin: Not ready for login\n" );
		s_ranked_players[index].grank_status = QGR_STATUS_ERROR;
		return;
	}
	
	if( s_ranked_players[index].grank_status == QGR_STATUS_ACTIVE )
	{
		Com_DPrintf( "SV_RankUserLogin: Got Login from active player\n" );
		return;
	}
	
	// get a separate context for the new user
	init = GRankInit( 0, SV_RankGameKey, GR_OPT_POLL, GR_OPT_END );
	s_ranked_players[index].context = init.context;
	s_rankings_contexts++;
	Com_DPrintf( "SV_RankUserLogin(); s_rankings_contexts=%d\n",s_rankings_contexts );
	Com_DPrintf( "SV_RankUserLogin(); s_ranked_players[%d].context=%d\n",index,init.context );
	
	// login user, proceed to SV_RankUserCBF
	status = GRankUserLoginAsync
		(
			s_ranked_players[index].context, 
			username, 
			password, 
			SV_RankUserCBF, 
			(void*)&s_ranked_players[index], 
			GR_OPT_END 
		);

	if( status == GR_STATUS_PENDING )
	{
		s_ranked_players[index].grank_status = QGR_STATUS_PENDING;
		s_ranked_players[index].final_status = QGR_STATUS_NEW;
	}
	else
	{
		SV_RankError( "SV_RankUserLogin: Expected GR_STATUS_PENDING, got %s", 
			SV_RankStatusString( status )  );
	}
}

/*
===================
SV_RankUserValidate
===================
*/
qboolean SV_RankUserValidate( int index, const char* player_id, const char* key, int token_len, int rank, char* name )
{
	GR_INIT		init;

⌨️ 快捷键说明

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