📄 sv_rankings.c
字号:
/*
===========================================================================
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 + -