Main Page | Class Hierarchy | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

sv_rankings.c

Go to the documentation of this file.
00001 /*
00002 ===========================================================================
00003 Copyright (C) 1999-2005 Id Software, Inc.
00004 
00005 This file is part of Quake III Arena source code.
00006 
00007 Quake III Arena source code is free software; you can redistribute it
00008 and/or modify it under the terms of the GNU General Public License as
00009 published by the Free Software Foundation; either version 2 of the License,
00010 or (at your option) any later version.
00011 
00012 Quake III Arena source code is distributed in the hope that it will be
00013 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Foobar; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020 ===========================================================================
00021 */
00022 // sv_rankings.c -- global rankings interface
00023 
00024 #include "server.h"
00025 #include "..\rankings\1.0\gr\grapi.h"
00026 #include "..\rankings\1.0\gr\grlog.h"
00027 
00028 typedef struct
00029 {
00030     GR_CONTEXT      context;
00031     uint64_t        game_id;
00032     uint64_t        match;
00033     uint64_t        player_id;
00034     GR_PLAYER_TOKEN     token;
00035     grank_status_t  grank_status;
00036     grank_status_t  final_status;   // status to set after cleanup
00037     uint32_t        grank;          // global rank
00038     char            name[32];
00039 } ranked_player_t;
00040 
00041 static int              s_rankings_contexts = 0;
00042 static qboolean         s_rankings_active = qfalse;
00043 static GR_CONTEXT       s_server_context = 0;
00044 static uint64_t         s_server_match = 0;
00045 static char*            s_rankings_game_key = NULL;
00046 static uint64_t         s_rankings_game_id = 0;
00047 static ranked_player_t* s_ranked_players = NULL;
00048 static qboolean         s_server_quitting = qfalse;
00049 static const char       s_ascii_encoding[] = 
00050                             "0123456789abcdef"
00051                             "ghijklmnopqrstuv"
00052                             "wxyzABCDEFGHIJKL"
00053                             "MNOPQRSTUVWXYZ[]";
00054 
00055 // private functions
00056 static void     SV_RankNewGameCBF( GR_NEWGAME* gr_newgame, void* cbf_arg );
00057 static void     SV_RankUserCBF( GR_LOGIN* gr_login, void* cbf_arg );
00058 static void     SV_RankJoinGameCBF( GR_JOINGAME* gr_joingame, void* cbf_arg );
00059 static void     SV_RankSendReportsCBF( GR_STATUS* gr_status, void* cbf_arg );
00060 static void     SV_RankCleanupCBF( GR_STATUS* gr_status, void* cbf_arg );
00061 static void     SV_RankCloseContext( ranked_player_t* ranked_player );
00062 static int      SV_RankAsciiEncode( char* dest, const unsigned char* src, 
00063                     int src_len );
00064 static int      SV_RankAsciiDecode( unsigned char* dest, const char* src, 
00065                     int src_len );
00066 static void     SV_RankEncodeGameID( uint64_t game_id, char* result, 
00067                     int len );
00068 static uint64_t SV_RankDecodePlayerID( const char* string );
00069 static void     SV_RankDecodePlayerKey( const char* string, GR_PLAYER_TOKEN key );
00070 static char*    SV_RankStatusString( GR_STATUS status );
00071 static void     SV_RankError( const char* fmt, ... );
00072 static char     SV_RankGameKey[64];
00073 
00074 /*
00075 ================
00076 SV_RankBegin
00077 ================
00078 */
00079 void SV_RankBegin( char *gamekey )
00080 {
00081     GR_INIT     init;
00082     GR_STATUS   status;
00083 
00084     assert( s_rankings_contexts == 0 );
00085     assert( !s_rankings_active );
00086     assert( s_ranked_players == NULL );
00087 
00088     if( sv_enableRankings->integer == 0 || Cvar_VariableValue( "g_gametype" ) == GT_SINGLE_PLAYER )
00089     {
00090         s_rankings_active = qfalse;
00091         if( sv_rankingsActive->integer == 1 )
00092         {
00093             Cvar_Set( "sv_rankingsActive", "0" );
00094         }
00095         return;
00096     }
00097 
00098     // only allow official game key on pure servers
00099     if( strcmp(gamekey, GR_GAMEKEY) == 0 )
00100     {
00101 /*
00102         if( Cvar_VariableValue("sv_pure") != 1 )
00103         {
00104             Cvar_Set( "sv_enableRankings", "0" );
00105             return;
00106         }
00107 */
00108 
00109         // substitute game-specific game key
00110         switch( (int)Cvar_VariableValue("g_gametype") )
00111         {
00112         case GT_FFA:
00113             gamekey = "Q3 Free For All";
00114             break;
00115         case GT_TOURNAMENT:
00116             gamekey = "Q3 Tournament";
00117             break;
00118         case GT_TEAM:
00119             gamekey = "Q3 Team Deathmatch";
00120             break;
00121         case GT_CTF:
00122             gamekey = "Q3 Capture the Flag";
00123             break;
00124         case GT_1FCTF:
00125             gamekey = "Q3 One Flag CTF";
00126             break;
00127         case GT_OBELISK:
00128             gamekey = "Q3 Overload";
00129             break;
00130         case GT_HARVESTER:
00131             gamekey = "Q3 Harvester";
00132             break;
00133         default:
00134             break;
00135         }
00136     }
00137     s_rankings_game_key = gamekey;
00138 
00139     // initialize rankings
00140     GRankLogLevel( GRLOG_OFF );
00141     memset(SV_RankGameKey,0,sizeof(SV_RankGameKey));
00142     strncpy(SV_RankGameKey,gamekey,sizeof(SV_RankGameKey)-1);
00143     init = GRankInit( 1, SV_RankGameKey, GR_OPT_POLL, GR_OPT_END );
00144     s_server_context = init.context;
00145     s_rankings_contexts++;
00146     Com_DPrintf( "SV_RankBegin(); GR_GAMEKEY is %s\n", gamekey );
00147     Com_DPrintf( "SV_RankBegin(); s_rankings_contexts=%d\n",s_rankings_contexts );
00148     Com_DPrintf( "SV_RankBegin(); s_server_context=%d\n",init.context );
00149 
00150     // new game
00151     if(!strlen(Cvar_VariableString( "sv_leagueName" )))
00152     {
00153         status = GRankNewGameAsync
00154             (           
00155                 s_server_context, 
00156                 SV_RankNewGameCBF, 
00157                 NULL, 
00158                 GR_OPT_LEAGUENAME,
00159                 (void*)(Cvar_VariableString( "sv_leagueName" )),
00160                 GR_OPT_END 
00161             );
00162     }
00163     else
00164     {
00165         status = GRankNewGameAsync
00166             (           
00167                 s_server_context, 
00168                 SV_RankNewGameCBF, 
00169                 NULL, 
00170                 GR_OPT_END 
00171             );
00172     }
00173         
00174     if( status != GR_STATUS_PENDING )
00175     {
00176         SV_RankError( "SV_RankBegin: Expected GR_STATUS_PENDING, got %s", 
00177             SV_RankStatusString( status ) );
00178         return;
00179     }
00180 
00181     // logging
00182     if( com_developer->value )
00183     {
00184         GRankLogLevel( GRLOG_TRACE );
00185     }
00186     
00187     // allocate rankings info for each player
00188     s_ranked_players = Z_Malloc( sv_maxclients->value * 
00189         sizeof(ranked_player_t) );
00190     memset( (void*)s_ranked_players, 0 ,sv_maxclients->value 
00191         * sizeof(ranked_player_t));
00192 }
00193 
00194 /*
00195 ================
00196 SV_RankEnd
00197 ================
00198 */
00199 void SV_RankEnd( void )
00200 {
00201     GR_STATUS   status;
00202     int         i;
00203     
00204     Com_DPrintf( "SV_RankEnd();\n" );
00205 
00206     if( !s_rankings_active )
00207     {
00208         // cleanup after error during game
00209         if( s_ranked_players != NULL )
00210         {
00211             for( i = 0; i < sv_maxclients->value; i++ )
00212             {
00213                 if( s_ranked_players[i].context != 0 )
00214                 {
00215                     SV_RankCloseContext( &(s_ranked_players[i]) );
00216                 }
00217             }
00218         }
00219         if( s_server_context != 0 )
00220         {
00221             SV_RankCloseContext( NULL );
00222         }
00223 
00224         return;
00225     }
00226 
00227     for( i = 0; i < sv_maxclients->value; i++ )
00228     {
00229         if( s_ranked_players[i].grank_status == QGR_STATUS_ACTIVE )
00230         {
00231             SV_RankUserLogout( i );
00232             Com_DPrintf( "SV_RankEnd: SV_RankUserLogout %d\n",i );
00233         }
00234     }
00235 
00236     assert( s_server_context != 0 );
00237     
00238     // send match reports, proceed to SV_RankSendReportsCBF
00239     status = GRankSendReportsAsync
00240         ( 
00241             s_server_context,
00242             0,
00243             SV_RankSendReportsCBF,
00244             NULL, 
00245             GR_OPT_END
00246         );
00247             
00248     if( status != GR_STATUS_PENDING )
00249     {
00250         SV_RankError( "SV_RankEnd: Expected GR_STATUS_PENDING, got %s", 
00251             SV_RankStatusString( status ) );
00252     }
00253 
00254     s_rankings_active = qfalse;
00255     Cvar_Set( "sv_rankingsActive", "0" );
00256 }
00257 
00258 /*
00259 ================
00260 SV_RankPoll
00261 ================
00262 */
00263 void SV_RankPoll( void )
00264 {
00265     GRankPoll();
00266 }
00267 
00268 /*
00269 ================
00270 SV_RankCheckInit
00271 ================
00272 */
00273 qboolean SV_RankCheckInit( void )
00274 {
00275     return (s_rankings_contexts > 0);
00276 }
00277 
00278 /*
00279 ================
00280 SV_RankActive
00281 ================
00282 */
00283 qboolean SV_RankActive( void )
00284 {
00285     return s_rankings_active;
00286 }
00287 
00288 /*
00289 =================
00290 SV_RankUserStatus
00291 =================
00292 */
00293 grank_status_t SV_RankUserStatus( int index )
00294 {
00295     if( !s_rankings_active )
00296     {
00297         return GR_STATUS_ERROR;
00298     }
00299 
00300     assert( s_ranked_players != NULL );
00301     assert( index >= 0 );
00302     assert( index < sv_maxclients->value );
00303 
00304     return s_ranked_players[index].grank_status;
00305 }
00306 
00307 /*
00308 ================
00309 SV_RankUserGRank
00310 ================
00311 */
00312 int SV_RankUserGrank( int index )
00313 {
00314     if( !s_rankings_active )
00315     {
00316         return 0;
00317     }
00318 
00319     assert( s_ranked_players != NULL );
00320     assert( index >= 0 );
00321     assert( index < sv_maxclients->value );
00322 
00323     return s_ranked_players[index].grank;
00324 }
00325 
00326 /*
00327 ================
00328 SV_RankUserReset
00329 ================
00330 */
00331 void SV_RankUserReset( int index )
00332 {
00333     if( !s_rankings_active )
00334     {
00335         return;
00336     }
00337 
00338     assert( s_ranked_players != NULL );
00339     assert( index >= 0 );
00340     assert( index < sv_maxclients->value );
00341 
00342     switch( s_ranked_players[index].grank_status )
00343     {
00344     case QGR_STATUS_SPECTATOR:
00345     case QGR_STATUS_NO_USER:
00346     case QGR_STATUS_BAD_PASSWORD:
00347     case QGR_STATUS_USER_EXISTS:
00348     case QGR_STATUS_NO_MEMBERSHIP:
00349     case QGR_STATUS_TIMEOUT:
00350     case QGR_STATUS_ERROR:
00351         s_ranked_players[index].grank_status = QGR_STATUS_NEW;
00352         break;
00353     default:
00354         break;
00355     }
00356 }
00357 
00358 /*
00359 ================
00360 SV_RankUserSpectate
00361 ================
00362 */
00363 void SV_RankUserSpectate( int index )
00364 {
00365     if( !s_rankings_active )
00366     {
00367         return;
00368     }
00369 
00370     assert( s_ranked_players != NULL );
00371     assert( index >= 0 );
00372     assert( index < sv_maxclients->value );
00373 
00374     // GRANK_FIXME - check current status?
00375     s_ranked_players[index].grank_status = QGR_STATUS_SPECTATOR;
00376 }
00377 
00378 /*
00379 ================
00380 SV_RankUserCreate
00381 ================
00382 */
00383 void SV_RankUserCreate( int index, char* username, char* password, 
00384     char* email )
00385 {
00386     GR_INIT     init;
00387     GR_STATUS   status;
00388 
00389     assert( index >= 0 );
00390     assert( index < sv_maxclients->value );
00391     assert( username != NULL );
00392     assert( password != NULL );
00393     assert( email != NULL );
00394     assert( s_ranked_players );
00395     assert( s_ranked_players[index].grank_status != QGR_STATUS_ACTIVE );
00396     
00397     Com_DPrintf( "SV_RankUserCreate( %d, %s, \"****\", %s );\n", index, 
00398         username, email );
00399 
00400     if( !s_rankings_active )
00401     {
00402         Com_DPrintf( "SV_RankUserCreate: Not ready to create\n" );
00403         s_ranked_players[index].grank_status = QGR_STATUS_ERROR;
00404         return;
00405     }
00406     
00407     if( s_ranked_players[index].grank_status == QGR_STATUS_ACTIVE )
00408     {
00409         Com_DPrintf( "SV_RankUserCreate: Got Create from active player\n" );
00410         return;
00411     }
00412     
00413     // get a separate context for the new user
00414     init = GRankInit( 0, SV_RankGameKey, GR_OPT_POLL, GR_OPT_END );
00415     s_ranked_players[index].context = init.context;
00416     s_rankings_contexts++;
00417     Com_DPrintf( "SV_RankUserCreate(); s_rankings_contexts=%d\n",s_rankings_contexts );
00418     Com_DPrintf( "SV_RankUserCreate(); s_ranked_players[%d].context=%d\n",index,init.context );
00419     
00420     // attempt to create a new account, proceed to SV_RankUserCBF
00421     status = GRankUserCreateAsync
00422         ( 
00423             s_ranked_players[index].context, 
00424             username, 
00425             password, 
00426             email, 
00427             SV_RankUserCBF, 
00428             (void*)&s_ranked_players[index], 
00429             GR_OPT_END
00430         );
00431 
00432     if( status == GR_STATUS_PENDING )
00433     {
00434         s_ranked_players[index].grank_status = QGR_STATUS_PENDING;
00435         s_ranked_players[index].final_status = QGR_STATUS_NEW;
00436     }
00437     else
00438     {
00439         SV_RankError( "SV_RankUserCreate: Expected GR_STATUS_PENDING, got %s", 
00440             SV_RankStatusString( status ) );
00441     }
00442 }
00443 
00444 /*
00445 ================
00446 SV_RankUserLogin
00447 ================
00448 */
00449 void SV_RankUserLogin( int index, char* username, char* password )
00450 {
00451     GR_INIT     init;
00452     GR_STATUS   status;
00453 
00454     assert( index >= 0 );
00455     assert( index < sv_maxclients->value );
00456     assert( username != NULL );
00457     assert( password != NULL );
00458     assert( s_ranked_players );
00459     assert( s_ranked_players[index].grank_status != QGR_STATUS_ACTIVE );
00460 
00461     Com_DPrintf( "SV_RankUserLogin( %d, %s, \"****\" );\n", index, username );
00462 
00463     if( !s_rankings_active )
00464     {
00465         Com_DPrintf( "SV_RankUserLogin: Not ready for login\n" );
00466         s_ranked_players[index].grank_status = QGR_STATUS_ERROR;
00467         return;
00468     }
00469     
00470     if( s_ranked_players[index].grank_status == QGR_STATUS_ACTIVE )
00471     {
00472         Com_DPrintf( "SV_RankUserLogin: Got Login from active player\n" );
00473         return;
00474     }
00475     
00476     // get a separate context for the new user
00477     init = GRankInit( 0, SV_RankGameKey, GR_OPT_POLL, GR_OPT_END );
00478     s_ranked_players[index].context = init.context;
00479     s_rankings_contexts++;
00480     Com_DPrintf( "SV_RankUserLogin(); s_rankings_contexts=%d\n",s_rankings_contexts );
00481     Com_DPrintf( "SV_RankUserLogin(); s_ranked_players[%d].context=%d\n",index,init.context );
00482     
00483     // login user, proceed to SV_RankUserCBF
00484     status = GRankUserLoginAsync
00485         (
00486             s_ranked_players[index].context, 
00487             username, 
00488             password, 
00489             SV_RankUserCBF, 
00490             (void*)&s_ranked_players[index], 
00491             GR_OPT_END 
00492         );
00493 
00494     if( status == GR_STATUS_PENDING )
00495     {
00496         s_ranked_players[index].grank_status = QGR_STATUS_PENDING;
00497         s_ranked_players[index].final_status = QGR_STATUS_NEW;
00498     }
00499     else
00500     {
00501         SV_RankError( "SV_RankUserLogin: Expected GR_STATUS_PENDING, got %s", 
00502             SV_RankStatusString( status )  );
00503     }
00504 }
00505 
00506 /*
00507 ===================
00508 SV_RankUserValidate
00509 ===================
00510 */
00511 qboolean SV_RankUserValidate( int index, const char* player_id, const char* key, int token_len, int rank, char* name )
00512 {
00513     GR_INIT     init;
00514     GR_STATUS status;
00515     qboolean rVal;
00516     ranked_player_t* ranked_player;
00517     int i;
00518 
00519     assert( s_ranked_players );
00520     assert( s_ranked_players[index].grank_status != QGR_STATUS_ACTIVE );
00521 
00522     rVal = qfalse;
00523     
00524     if( !s_rankings_active )
00525     {
00526         Com_DPrintf( "SV_RankUserValidate: Not ready to validate\n" );
00527         s_ranked_players[index].grank_status = QGR_STATUS_ERROR;
00528         return rVal;
00529     }
00530     
00531     ranked_player = &(s_ranked_players[index]);
00532     
00533     if ( (player_id != NULL) && (key != NULL))
00534     {
00535         // the real player_id and key is set when SV_RankJoinGameCBF
00536         // is called we do this so that SV_RankUserValidate
00537         // can be shared by both server side login and client side login
00538         
00539         // for client side logined in players
00540         // server is creating GR_OPT_PLAYERCONTEXT
00541         init = GRankInit( 0, SV_RankGameKey, GR_OPT_POLL, GR_OPT_END );
00542         ranked_player->context   = init.context;
00543         s_rankings_contexts++;
00544         Com_DPrintf( "SV_RankUserValidate(); s_rankings_contexts=%d\n",s_rankings_contexts );
00545         Com_DPrintf( "SV_RankUserValidate(); s_ranked_players[%d].context=%d\n",index,init.context );
00546         
00547         // uudecode player id and player token
00548         ranked_player->player_id = SV_RankDecodePlayerID(player_id);
00549         Com_DPrintf( "SV_RankUserValidate(); ranked_player->player_id =%u\n", (uint32_t)ranked_player->player_id );
00550         SV_RankDecodePlayerKey(key, ranked_player->token);
00551         
00552         // save name and check for duplicates
00553         Q_strncpyz( ranked_player->name, name, sizeof(ranked_player->name) );
00554         for( i = 0; i < sv_maxclients->value; i++ )
00555         {
00556             if( (i != index) && (s_ranked_players[i].grank_status == QGR_STATUS_ACTIVE) && 
00557                 (strcmp( s_ranked_players[i].name, name ) == 0) )
00558             {
00559                 Com_DPrintf( "SV_RankUserValidate: Duplicate login\n" );
00560                 ranked_player->grank_status = QGR_STATUS_NO_USER;
00561                 ranked_player->final_status = QGR_STATUS_NEW;
00562                 ranked_player->grank = 0;
00563                 return qfalse;
00564             }
00565         }
00566 
00567         // then validate
00568         status  = GRankPlayerValidate(
00569                             s_server_context,
00570                             ranked_player->player_id, 
00571                             ranked_player->token,
00572                             token_len,
00573                             GR_OPT_PLAYERCONTEXT,
00574                             ranked_player->context,
00575                             GR_OPT_END);
00576     }
00577     else
00578     {
00579         // make server side login (bots) happy
00580         status = GR_STATUS_OK;
00581     }
00582 
00583     if (status == GR_STATUS_OK)
00584     {
00585         ranked_player->grank_status = QGR_STATUS_ACTIVE;
00586         ranked_player->final_status = QGR_STATUS_NEW;
00587         ranked_player->grank = rank;
00588         rVal = qtrue;
00589     }
00590     else if (status == GR_STATUS_INVALIDUSER)
00591     {
00592         ranked_player->grank_status = QGR_STATUS_INVALIDUSER;
00593         ranked_player->final_status = QGR_STATUS_NEW;
00594         ranked_player->grank = 0;
00595         rVal = qfalse;
00596     }
00597     else
00598     {
00599         SV_RankError( "SV_RankUserValidate: Unexpected status %s",
00600             SV_RankStatusString( status ) );
00601         s_ranked_players[index].grank_status = QGR_STATUS_ERROR;
00602         ranked_player->grank = 0;
00603     }
00604     
00605     return rVal;
00606 }
00607 
00608 /*
00609 ================
00610 SV_RankUserLogout
00611 ================
00612 */
00613 void SV_RankUserLogout( int index )
00614 {
00615     GR_STATUS   status;
00616     GR_STATUS   cleanup_status;
00617 
00618     if( !s_rankings_active )
00619     {
00620         return;
00621     }
00622 
00623     assert( index >= 0 );
00624     assert( index < sv_maxclients->value );
00625     assert( s_ranked_players );
00626 
00627     if( s_ranked_players[index].context == 0 ) {
00628         return;
00629     }
00630 
00631     Com_DPrintf( "SV_RankUserLogout( %d );\n", index );
00632 
00633     // masqueraded player may not be active yet, if they fail validation, 
00634     // but still they have a context needs to be cleaned 
00635     // what matters is the s_ranked_players[index].context
00636     
00637     // send reports, proceed to SV_RankSendReportsCBF
00638     status = GRankSendReportsAsync
00639         ( 
00640             s_ranked_players[index].context,
00641             0,
00642             SV_RankSendReportsCBF,
00643             (void*)&s_ranked_players[index], 
00644             GR_OPT_END
00645         );
00646         
00647     if( status == GR_STATUS_PENDING )
00648     {
00649         s_ranked_players[index].grank_status = QGR_STATUS_PENDING;
00650         s_ranked_players[index].final_status = QGR_STATUS_NEW;
00651     }
00652     else
00653     {
00654         SV_RankError( "SV_RankUserLogout: Expected GR_STATUS_PENDING, got %s", 
00655             SV_RankStatusString( status ) );
00656 
00657         cleanup_status = GRankCleanupAsync
00658             (
00659                 s_ranked_players[index].context,
00660                 0,
00661                 SV_RankCleanupCBF,
00662                 (void*)&s_ranked_players[index],
00663                 GR_OPT_END
00664             );
00665         
00666         if( cleanup_status != GR_STATUS_PENDING )
00667         {
00668             SV_RankError( "SV_RankUserLogout: Expected "
00669                 "GR_STATUS_PENDING from GRankCleanupAsync, got %s", 
00670                 SV_RankStatusString( cleanup_status ) );
00671             SV_RankCloseContext( &(s_ranked_players[index]) );
00672         }
00673     }
00674 }
00675 
00676 /*
00677 ================
00678 SV_RankReportInt
00679 ================
00680 */
00681 void SV_RankReportInt( int index1, int index2, int key, int value, 
00682     qboolean accum )
00683 {
00684     GR_STATUS   status;
00685     GR_CONTEXT  context;
00686     uint64_t    match;
00687     uint64_t    user1;
00688     uint64_t    user2;
00689     int         opt_accum;
00690 
00691     if( !s_rankings_active )
00692     {
00693         return;
00694     }
00695 
00696     assert( index1 >= -1 );
00697     assert( index1 < sv_maxclients->value );
00698     assert( index2 >= -1 );
00699     assert( index2 < sv_maxclients->value );
00700     assert( s_ranked_players );
00701 
00702 //  Com_DPrintf( "SV_RankReportInt( %d, %d, %d, %d, %d );\n", index1, index2, 
00703 //      key, value, accum );
00704 
00705     // get context, match, and player_id for player index1
00706     if( index1 == -1 )
00707     {
00708         context = s_server_context;
00709         match = s_server_match;
00710         user1 = 0;
00711     }
00712     else
00713     {
00714         if( s_ranked_players[index1].grank_status != QGR_STATUS_ACTIVE )
00715         {
00716             Com_DPrintf( "SV_RankReportInt: Expecting QGR_STATUS_ACTIVE"
00717                 " Got Unexpected status %d for player %d\n", 
00718                 s_ranked_players[index1].grank_status, index1 );
00719             return;
00720         }
00721     
00722         context = s_ranked_players[index1].context;
00723         match = s_ranked_players[index1].match;
00724         user1 = s_ranked_players[index1].player_id;
00725     }
00726 
00727     // get player_id for player index2
00728     if( index2 == -1 )
00729     {
00730         user2 = 0;
00731     }
00732     else
00733     {
00734         if( s_ranked_players[index2].grank_status != QGR_STATUS_ACTIVE )
00735         {
00736             Com_DPrintf( "SV_RankReportInt: Expecting QGR_STATUS_ACTIVE"
00737                 " Got Unexpected status %d for player %d\n", 
00738                 s_ranked_players[index2].grank_status, index2 );
00739             return;
00740         }
00741 
00742         user2 = s_ranked_players[index2].player_id;
00743     }
00744 
00745     opt_accum = accum ? GR_OPT_ACCUM : GR_OPT_END;
00746     
00747     status = GRankReportInt
00748         (
00749             context,
00750             match,
00751             user1, 
00752             user2,
00753             key,
00754             value,
00755             opt_accum,
00756             GR_OPT_END
00757         );
00758         
00759     if( status != GR_STATUS_OK )
00760     {
00761         SV_RankError( "SV_RankReportInt: Unexpected status %s",
00762             SV_RankStatusString( status ) );
00763     }
00764 
00765     if( user2 != 0 )
00766     {
00767         context = s_ranked_players[index2].context;
00768         match   = s_ranked_players[index2].match;
00769         
00770         status = GRankReportInt
00771             (
00772                 context,
00773                 match,
00774                 user1, 
00775                 user2,
00776                 key,
00777                 value,
00778                 opt_accum,
00779                 GR_OPT_END
00780             );
00781             
00782         if( status != GR_STATUS_OK )
00783         {
00784             SV_RankError( "SV_RankReportInt: Unexpected status %s",
00785                 SV_RankStatusString( status ) );
00786         }
00787     }
00788 }
00789 
00790 /*
00791 ================
00792 SV_RankReportStr
00793 ================
00794 */
00795 void SV_RankReportStr( int index1, int index2, int key, char* value )
00796 {
00797     GR_STATUS   status;
00798     GR_CONTEXT  context;
00799     uint64_t    match;
00800     uint64_t    user1;
00801     uint64_t    user2;
00802 
00803     if( !s_rankings_active )
00804     {
00805         return;
00806     }
00807 
00808     assert( index1 >= -1 );
00809     assert( index1 < sv_maxclients->value );
00810     assert( index2 >= -1 );
00811     assert( index2 < sv_maxclients->value );
00812     assert( s_ranked_players );
00813 
00814 //  Com_DPrintf( "SV_RankReportStr( %d, %d, %d, \"%s\" );\n", index1, index2, 
00815 //      key, value );
00816     
00817     // get context, match, and player_id for player index1
00818     if( index1 == -1 )
00819     {
00820         context = s_server_context;
00821         match = s_server_match;
00822         user1 = 0;
00823     }
00824     else
00825     {
00826         if( s_ranked_players[index1].grank_status != QGR_STATUS_ACTIVE )
00827         {
00828             Com_DPrintf( "SV_RankReportStr: Unexpected status %d\n", 
00829                 s_ranked_players[index1].grank_status );
00830             return;
00831         }
00832     
00833         context = s_ranked_players[index1].context;
00834         match = s_ranked_players[index1].match;
00835         user1 = s_ranked_players[index1].player_id;
00836     }
00837 
00838     // get player_id for player index2
00839     if( index2 == -1 )
00840     {
00841         user2 = 0;
00842     }
00843     else
00844     {
00845         if( s_ranked_players[index2].grank_status != QGR_STATUS_ACTIVE )
00846         {
00847             Com_DPrintf( "SV_RankReportStr: Unexpected status %d\n", 
00848                 s_ranked_players[index2].grank_status );
00849             return;
00850         }
00851 
00852         user2 = s_ranked_players[index2].player_id;
00853     }
00854 
00855     status = GRankReportStr
00856         (
00857             context,
00858             match,
00859             user1,
00860             user2,
00861             key,
00862             value,
00863             GR_OPT_END
00864         );
00865         
00866     if( status != GR_STATUS_OK )
00867     {
00868         SV_RankError( "SV_RankReportStr: Unexpected status %s",
00869             SV_RankStatusString( status ) );
00870     }
00871     
00872     if( user2 != 0 )
00873     {
00874         context = s_ranked_players[index2].context;
00875         match = s_ranked_players[index2].match;
00876         
00877         status = GRankReportStr
00878             (
00879                 context,
00880                 match,
00881                 user1, 
00882                 user2,
00883                 key,
00884                 value,
00885                 GR_OPT_END
00886             );
00887             
00888         if( status != GR_STATUS_OK )
00889         {
00890             SV_RankError( "SV_RankReportInt: Unexpected status %s",
00891                 SV_RankStatusString( status ) );
00892         }
00893     }
00894 }
00895 
00896 /*
00897 ================
00898 SV_RankQuit
00899 ================
00900 */
00901 void SV_RankQuit( void )
00902 {
00903     int i;
00904     int j = 0;  
00905     // yuck
00906     
00907     while( s_rankings_contexts > 1 )
00908     {
00909         assert(s_ranked_players);
00910         if( s_ranked_players != NULL )
00911         {
00912             for( i = 0; i < sv_maxclients->value; i++ )
00913             {
00914                 // check for players that weren't yet active in SV_RankEnd
00915                 if( s_ranked_players[i].grank_status == QGR_STATUS_ACTIVE )
00916                 {
00917                     SV_RankUserLogout( i );
00918                     Com_DPrintf( "SV_RankQuit: SV_RankUserLogout %d\n",i );
00919                 }
00920                 else
00921                 {
00922                     if( s_ranked_players[i].context )
00923                     {
00924                         GR_STATUS cleanup_status;
00925                         cleanup_status = GRankCleanupAsync
00926                             (
00927                                 s_ranked_players[i].context,
00928                                 0,
00929                                 SV_RankCleanupCBF,
00930                                 (void*)&(s_ranked_players[i]),
00931                                 GR_OPT_END
00932                             );
00933                         
00934                         if( cleanup_status != GR_STATUS_PENDING )
00935                         {
00936                             SV_RankError( "SV_RankQuit: Expected "
00937                                 "GR_STATUS_PENDING from GRankCleanupAsync, got %s", 
00938                                 SV_RankStatusString( cleanup_status ) );
00939                         }
00940                     }
00941                 }
00942             }
00943         }
00944         SV_RankPoll();
00945         
00946         // should've finished by now
00947         assert( (j++) < 68 );
00948     }
00949 }
00950 
00951 /*
00952 ==============================================================================
00953 
00954 Private Functions
00955 
00956 ==============================================================================
00957 */
00958 
00959 /*
00960 =================
00961 SV_RankNewGameCBF
00962 =================
00963 */
00964 static void SV_RankNewGameCBF( GR_NEWGAME* gr_newgame, void* cbf_arg )
00965 {
00966     GR_MATCH    match;
00967     int         i;
00968     
00969     assert( gr_newgame != NULL );
00970     assert( cbf_arg == NULL );
00971 
00972     Com_DPrintf( "SV_RankNewGameCBF( %08X, %08X );\n", gr_newgame, cbf_arg );
00973     
00974     if( gr_newgame->status == GR_STATUS_OK )
00975     {
00976         char info[MAX_INFO_STRING];
00977         char gameid[sizeof(s_ranked_players[i].game_id) * 4 / 3 + 2];
00978         
00979         // save game id
00980         s_rankings_game_id = gr_newgame->game_id;
00981         
00982         // encode gameid 
00983         memset(gameid,0,sizeof(gameid));
00984         SV_RankEncodeGameID(s_rankings_game_id,gameid,sizeof(gameid));
00985         
00986         // set CS_GRANK rankingsGameID to pass to client
00987         memset(info,0,sizeof(info));
00988         Info_SetValueForKey( info, "rankingsGameKey", s_rankings_game_key );
00989         Info_SetValueForKey( info, "rankingsGameID", gameid );
00990         SV_SetConfigstring( CS_GRANK, info );
00991 
00992         // initialize client status
00993         for( i = 0; i < sv_maxclients->value; i++ )
00994             s_ranked_players[i].grank_status = QGR_STATUS_NEW;
00995 
00996         // start new match
00997         match = GRankStartMatch( s_server_context );
00998         s_server_match = match.match;
00999 
01000         // ready to go
01001         s_rankings_active = qtrue;
01002         Cvar_Set( "sv_rankingsActive", "1" );
01003 
01004     }
01005     else if( gr_newgame->status == GR_STATUS_BADLEAGUE )
01006     {
01007         SV_RankError( "SV_RankNewGameCBF: Invalid League name\n" );
01008     }
01009     else
01010     {
01011         //GRank handle new game failure
01012         // force  SV_RankEnd() to run
01013         //SV_RankEnd();
01014         SV_RankError( "SV_RankNewGameCBF: Unexpected status %s", 
01015             SV_RankStatusString( gr_newgame->status ) );
01016     }
01017 }
01018 
01019 /*
01020 ================
01021 SV_RankUserCBF
01022 ================
01023 */
01024 static void SV_RankUserCBF( GR_LOGIN* gr_login, void* cbf_arg )
01025 {
01026     ranked_player_t*    ranked_player;
01027     GR_STATUS           join_status;
01028     GR_STATUS           cleanup_status;
01029     
01030     assert( gr_login != NULL );
01031     assert( cbf_arg != NULL );
01032 
01033     Com_DPrintf( "SV_RankUserCBF( %08X, %08X );\n", gr_login, cbf_arg );
01034     
01035     ranked_player = (ranked_player_t*)cbf_arg;
01036     assert(ranked_player);
01037     assert( ranked_player->context );
01038     
01039     switch( gr_login->status )
01040     {
01041         case GR_STATUS_OK:
01042             // attempt to join the game, proceed to SV_RankJoinGameCBF
01043             join_status = GRankJoinGameAsync
01044                 ( 
01045                     ranked_player->context,
01046                     s_rankings_game_id,
01047                     SV_RankJoinGameCBF,
01048                     cbf_arg,
01049                     GR_OPT_END
01050                 );
01051 
01052             if( join_status != GR_STATUS_PENDING )
01053             {
01054                 SV_RankError( "SV_RankUserCBF: Expected GR_STATUS_PENDING "
01055                     "from GRankJoinGameAsync, got %s", 
01056                     SV_RankStatusString( join_status ) );
01057             }
01058             break;
01059         case GR_STATUS_NOUSER:
01060             Com_DPrintf( "SV_RankUserCBF: Got status %s\n",
01061                 SV_RankStatusString( gr_login->status ) );
01062             ranked_player->final_status = QGR_STATUS_NO_USER;
01063             break;
01064         case GR_STATUS_BADPASSWORD:
01065             Com_DPrintf( "SV_RankUserCBF: Got status %s\n",
01066                 SV_RankStatusString( gr_login->status ) );
01067             ranked_player->final_status = QGR_STATUS_BAD_PASSWORD;
01068             break;
01069         case GR_STATUS_TIMEOUT:
01070             Com_DPrintf( "SV_RankUserCBF: Got status %s\n",
01071                 SV_RankStatusString( gr_login->status ) );
01072             ranked_player->final_status = QGR_STATUS_TIMEOUT;
01073             break;
01074         default:
01075             Com_DPrintf( "SV_RankUserCBF: Unexpected status %s\n",
01076                 SV_RankStatusString( gr_login->status ) );
01077             ranked_player->final_status = QGR_STATUS_ERROR;
01078             break;
01079     }
01080 
01081     if( ranked_player->final_status != QGR_STATUS_NEW )
01082     {
01083         // login or create failed, so clean up before the next attempt
01084         cleanup_status = GRankCleanupAsync
01085             (
01086                 ranked_player->context,
01087                 0,
01088                 SV_RankCleanupCBF,
01089                 (void*)ranked_player,
01090                 GR_OPT_END
01091             );
01092             
01093         if( cleanup_status != GR_STATUS_PENDING )
01094         {
01095             SV_RankError( "SV_RankUserCBF: Expected GR_STATUS_PENDING "
01096                 "from GRankCleanupAsync, got %s", 
01097                 SV_RankStatusString( cleanup_status ) );
01098             SV_RankCloseContext( ranked_player );
01099         }
01100     }
01101 }
01102 
01103 /*
01104 ================
01105 SV_RankJoinGameCBF
01106 ================
01107 */
01108 static void SV_RankJoinGameCBF( GR_JOINGAME* gr_joingame, void* cbf_arg )
01109 {
01110     ranked_player_t*    ranked_player;
01111     GR_MATCH            match;
01112     GR_STATUS           cleanup_status;
01113 
01114     assert( gr_joingame != NULL );
01115     assert( cbf_arg != NULL );
01116     
01117     Com_DPrintf( "SV_RankJoinGameCBF( %08X, %08X );\n", gr_joingame, cbf_arg );
01118     
01119     ranked_player = (ranked_player_t*)cbf_arg;
01120 
01121     assert( ranked_player );
01122     assert( ranked_player->context != 0 );
01123     
01124     if( gr_joingame->status == GR_STATUS_OK )
01125     {
01126         int i;
01127         // save user id
01128         ranked_player->player_id = gr_joingame->player_id;
01129         memcpy(ranked_player->token,gr_joingame->token,
01130             sizeof(GR_PLAYER_TOKEN)) ;
01131         match = GRankStartMatch( ranked_player->context );
01132         ranked_player->match = match.match;
01133         ranked_player->grank = gr_joingame->rank;
01134 
01135         // find the index and call SV_RankUserValidate
01136         for (i=0;i<sv_maxclients->value;i++)
01137             if ( ranked_player == &s_ranked_players[i] )
01138                 SV_RankUserValidate(i,NULL,NULL,0, gr_joingame->rank,ranked_player->name);
01139     }
01140     else
01141     {
01142         //GRand handle join game failure
01143         SV_RankError( "SV_RankJoinGameCBF: Unexpected status %s",
01144             SV_RankStatusString( gr_joingame->status ) );
01145         
01146         cleanup_status = GRankCleanupAsync
01147             (
01148                 ranked_player->context,
01149                 0,
01150                 SV_RankCleanupCBF,
01151                 cbf_arg,
01152                 GR_OPT_END
01153             );
01154         
01155         if( cleanup_status != GR_STATUS_PENDING )
01156         {
01157             SV_RankError( "SV_RankJoinGameCBF: Expected "
01158                 "GR_STATUS_PENDING from GRankCleanupAsync, got %s", 
01159                 SV_RankStatusString( cleanup_status ) );
01160             SV_RankCloseContext( ranked_player );
01161         }
01162     }       
01163 }
01164 
01165 /*
01166 ================
01167 SV_RankSendReportsCBF
01168 ================
01169 */
01170 static void SV_RankSendReportsCBF( GR_STATUS* status, void* cbf_arg )
01171 {
01172     ranked_player_t*    ranked_player;
01173     GR_CONTEXT          context;
01174     GR_STATUS           cleanup_status;
01175 
01176     assert( status != NULL );
01177     // NULL cbf_arg means server is sending match reports
01178     
01179     Com_DPrintf( "SV_RankSendReportsCBF( %08X, %08X );\n", status, cbf_arg );
01180     
01181     ranked_player = (ranked_player_t*)cbf_arg;
01182     if( ranked_player == NULL )
01183     {
01184         Com_DPrintf( "SV_RankSendReportsCBF: server\n" );
01185         context = s_server_context;
01186     }
01187     else
01188     {
01189         Com_DPrintf( "SV_RankSendReportsCBF: player\n" );
01190         context = ranked_player->context;
01191     }
01192 
01193     //assert( context != 0 );
01194     if( *status != GR_STATUS_OK )
01195     {
01196         SV_RankError( "SV_RankSendReportsCBF: Unexpected status %s",
01197             SV_RankStatusString( *status ) );
01198     }
01199     
01200     if( context == 0 )
01201     {
01202         Com_DPrintf( "SV_RankSendReportsCBF: WARNING: context == 0" );
01203         SV_RankCloseContext( ranked_player );
01204     }
01205     else
01206     {
01207         cleanup_status = GRankCleanupAsync
01208             (
01209                 context,
01210                 0,
01211                 SV_RankCleanupCBF,
01212                 cbf_arg,
01213                 GR_OPT_END
01214             );
01215         
01216         if( cleanup_status != GR_STATUS_PENDING )
01217         {
01218             SV_RankError( "SV_RankSendReportsCBF: Expected "
01219                 "GR_STATUS_PENDING from GRankCleanupAsync, got %s", 
01220                 SV_RankStatusString( cleanup_status ) );
01221             SV_RankCloseContext( ranked_player );
01222         }
01223     }
01224 }
01225 
01226 /*
01227 ================
01228 SV_RankCleanupCBF
01229 ================
01230 */
01231 static void SV_RankCleanupCBF( GR_STATUS* status, void* cbf_arg )
01232 {
01233     ranked_player_t*    ranked_player;
01234     ranked_player = (ranked_player_t*)cbf_arg;
01235 
01236     assert( status != NULL );
01237     // NULL cbf_arg means server is cleaning up
01238 
01239     Com_DPrintf( "SV_RankCleanupCBF( %08X, %08X );\n", status, cbf_arg );
01240     
01241     if( *status != GR_STATUS_OK )
01242     {
01243         SV_RankError( "SV_RankCleanupCBF: Unexpected status %s",
01244             SV_RankStatusString( *status ) );
01245     }
01246 
01247     SV_RankCloseContext( ranked_player );
01248 }
01249 
01250 /*
01251 ================
01252 SV_RankCloseContext
01253 ================
01254 */
01255 static void SV_RankCloseContext( ranked_player_t* ranked_player )
01256 {
01257     if( ranked_player == NULL )
01258     {
01259         // server cleanup
01260         if( s_server_context == 0 )
01261         {
01262             return;
01263         }
01264         s_server_context = 0;
01265         s_server_match = 0;
01266     }
01267     else
01268     {
01269         // player cleanup
01270         if( s_ranked_players == NULL )
01271         {
01272             return;
01273         }
01274         if( ranked_player->context == 0 )
01275         {
01276             return;
01277         }
01278         ranked_player->context = 0;
01279         ranked_player->match = 0;
01280         ranked_player->player_id = 0;
01281         memset( ranked_player->token, 0, sizeof(GR_PLAYER_TOKEN) );
01282         ranked_player->grank_status = ranked_player->final_status;
01283         ranked_player->final_status = QGR_STATUS_NEW;
01284         ranked_player->name[0] = '\0';
01285     }
01286 
01287     assert( s_rankings_contexts > 0 );
01288     s_rankings_contexts--;
01289     Com_DPrintf( "SV_RankCloseContext: s_rankings_contexts = %d\n", 
01290         s_rankings_contexts );
01291 
01292     if( s_rankings_contexts == 0 )
01293     {
01294         GRankLogLevel( GRLOG_OFF );
01295         
01296         if( s_ranked_players != NULL )
01297         {
01298             Z_Free( s_ranked_players );
01299             s_ranked_players = NULL;
01300         }
01301 
01302         s_rankings_active = qfalse;
01303         Cvar_Set( "sv_rankingsActive", "0" );
01304     }
01305 }
01306 
01307 /*
01308 ================
01309 SV_RankAsciiEncode
01310 
01311 Encodes src_len bytes of binary data from the src buffer as ASCII text, 
01312 using 6 bits per character. The result string is null-terminated and 
01313 stored in the dest buffer.
01314 
01315 The dest buffer must be at least (src_len * 4) / 3 + 2 bytes in length.
01316 
01317 Returns the length of the result string, not including the null.
01318 ================
01319 */
01320 static int SV_RankAsciiEncode( char* dest, const unsigned char* src, 
01321     int src_len )
01322 {
01323     unsigned char   bin[3];
01324     unsigned char   txt[4];
01325     int             dest_len = 0;
01326     int             i;
01327     int             j;
01328     int             num_chars;
01329 
01330     assert( dest != NULL );
01331     assert( src != NULL );
01332     
01333     for( i = 0; i < src_len; i += 3 )
01334     {
01335         // read three bytes of input
01336         for( j = 0; j < 3; j++ )
01337         {
01338             bin[j] = (i + j < src_len) ? src[i + j] : 0;
01339         }
01340 
01341         // get four 6-bit values from three bytes
01342         txt[0] = bin[0] >> 2;
01343         txt[1] = ((bin[0] << 4) | (bin[1] >> 4)) & 63;
01344         txt[2] = ((bin[1] << 2) | (bin[2] >> 6)) & 63;
01345         txt[3] = bin[2] & 63;
01346 
01347         // store ASCII encoding of 6-bit values
01348         num_chars = (i + 2 < src_len) ? 4 : ((src_len - i) * 4) / 3 + 1;
01349         for( j = 0; j < num_chars; j++ )
01350         {
01351             dest[dest_len++] = s_ascii_encoding[txt[j]];
01352         }
01353     }
01354     
01355     dest[dest_len] = '\0';
01356 
01357     return dest_len;
01358 }
01359 
01360 /*
01361 ================
01362 SV_RankAsciiDecode
01363 
01364 Decodes src_len characters of ASCII text from the src buffer, stores 
01365 the binary result in the dest buffer.
01366 
01367 The dest buffer must be at least (src_len * 3) / 4 bytes in length.
01368 
01369 Returns the length of the binary result, or zero for invalid input.
01370 ================
01371 */
01372 static int SV_RankAsciiDecode( unsigned char* dest, const char* src, 
01373     int src_len )
01374 {
01375     static unsigned char    s_inverse_encoding[256];
01376     static char             s_init = 0;
01377     
01378     unsigned char   bin[3];
01379     unsigned char   txt[4];
01380     int             dest_len = 0;
01381     int             i;
01382     int             j;
01383     int             num_bytes;
01384     
01385     assert( dest != NULL );
01386     assert( src != NULL );
01387 
01388     if( !s_init )
01389     {
01390         // initialize lookup table for decoding
01391         memset( s_inverse_encoding, 255, sizeof(s_inverse_encoding) );
01392         for( i = 0; i < 64; i++ )
01393         {
01394             s_inverse_encoding[s_ascii_encoding[i]] = i;
01395         }
01396         s_init = 1;
01397     }
01398     
01399     for( i = 0; i < src_len; i += 4 )
01400     {
01401         // read four characters of input, decode them to 6-bit values
01402         for( j = 0; j < 4; j++ )
01403         {
01404             txt[j] = (i + j < src_len) ? s_inverse_encoding[src[i + j]] : 0;
01405             if (txt[j] == 255)
01406             {
01407                 return 0; // invalid input character
01408             }
01409         }
01410         
01411         // get three bytes from four 6-bit values
01412         bin[0] = (txt[0] << 2) | (txt[1] >> 4);
01413         bin[1] = (txt[1] << 4) | (txt[2] >> 2);
01414         bin[2] = (txt[2] << 6) | txt[3];
01415 
01416         // store binary data
01417         num_bytes = (i + 3 < src_len) ? 3 : ((src_len - i) * 3) / 4;
01418         for( j = 0; j < num_bytes; j++ )
01419         {
01420             dest[dest_len++] = bin[j];
01421         }
01422     }
01423 
01424     return dest_len;
01425 }
01426 
01427 /*
01428 ================
01429 SV_RankEncodeGameID
01430 ================
01431 */
01432 static void SV_RankEncodeGameID( uint64_t game_id, char* result, 
01433     int len )
01434 {
01435     assert( result != NULL );
01436 
01437     if( len < ( ( sizeof(game_id) * 4) / 3 + 2) )
01438     {
01439         Com_DPrintf( "SV_RankEncodeGameID: result buffer too small\n" );
01440         result[0] = '\0';
01441     }
01442     else
01443     {
01444         qint64 gameid = LittleLong64(*(qint64*)&game_id);
01445         SV_RankAsciiEncode( result, (unsigned char*)&gameid, 
01446             sizeof(qint64) );
01447     }
01448 }
01449 
01450 /*
01451 ================
01452 SV_RankDecodePlayerID
01453 ================
01454 */
01455 static uint64_t SV_RankDecodePlayerID( const char* string )
01456 {
01457     unsigned char   buffer[9];
01458     int len;
01459     qint64  player_id;
01460 
01461     assert( string != NULL );
01462     
01463     len = strlen (string) ;
01464     Com_DPrintf( "SV_RankDecodePlayerID: string length %d\n",len );
01465     SV_RankAsciiDecode( buffer, string, len );
01466     player_id = LittleLong64(*(qint64*)buffer);
01467     return *(uint64_t*)&player_id;
01468 }
01469 
01470 /*
01471 ================
01472 SV_RankDecodePlayerKey
01473 ================
01474 */
01475 static void SV_RankDecodePlayerKey( const char* string, GR_PLAYER_TOKEN key )
01476 {
01477     unsigned char   buffer[1400];
01478     int len;
01479     assert( string != NULL );
01480 
01481     len = strlen (string) ;
01482     Com_DPrintf( "SV_RankDecodePlayerKey: string length %d\n",len );
01483     
01484     memset(key,0,sizeof(GR_PLAYER_TOKEN));
01485     memset(buffer,0,sizeof(buffer));
01486     memcpy( key, buffer, SV_RankAsciiDecode( buffer, string, len ) );
01487 }
01488 
01489 /*
01490 ================
01491 SV_RankStatusString
01492 ================
01493 */
01494 static char* SV_RankStatusString( GR_STATUS status )
01495 {
01496     switch( status )
01497     {
01498         case GR_STATUS_OK:              return "GR_STATUS_OK";
01499         case GR_STATUS_ERROR:           return "GR_STATUS_ERROR";
01500         case GR_STATUS_BADPARAMS:       return "GR_STATUS_BADPARAMS";
01501         case GR_STATUS_NETWORK:         return "GR_STATUS_NETWORK";
01502         case GR_STATUS_NOUSER:          return "GR_STATUS_NOUSER";
01503         case GR_STATUS_BADPASSWORD:     return "GR_STATUS_BADPASSWORD";
01504         case GR_STATUS_BADGAME:         return "GR_STATUS_BADGAME";
01505         case GR_STATUS_PENDING:         return "GR_STATUS_PENDING";
01506         case GR_STATUS_BADDOMAIN:       return "GR_STATUS_BADDOMAIN";
01507         case GR_STATUS_DOMAINLOCK:      return "GR_STATUS_DOMAINLOCK";
01508         case GR_STATUS_TIMEOUT:         return "GR_STATUS_TIMEOUT";
01509         case GR_STATUS_INVALIDUSER:     return "GR_STATUS_INVALIDUSER";
01510         case GR_STATUS_INVALIDCONTEXT:  return "GR_STATUS_INVALIDCONTEXT";
01511         default:                        return "(UNKNOWN)";
01512     }
01513 }
01514 
01515 /*
01516 ================
01517 SV_RankError
01518 ================
01519 */
01520 static void SV_RankError( const char* fmt, ... )
01521 {
01522     va_list arg_ptr;
01523     char    text[1024];
01524 
01525     va_start( arg_ptr, fmt );
01526     vsprintf( text, fmt, arg_ptr );
01527     va_end( arg_ptr );
01528 
01529     Com_DPrintf( "****************************************\n" );
01530     Com_DPrintf( "SV_RankError: %s\n", text );
01531     Com_DPrintf( "****************************************\n" );
01532 
01533     s_rankings_active = qfalse;
01534     Cvar_Set( "sv_rankingsActive", "0" );
01535     // FIXME - attempt clean shutdown?
01536 }
01537 

Generated on Thu Aug 25 12:37:57 2005 for Quake III Arena by  doxygen 1.3.9.1