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