00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "client.h"
00025 #include <limits.h>
00026
00027 cvar_t *cl_nodelta;
00028 cvar_t *cl_debugMove;
00029
00030 cvar_t *cl_noprint;
00031 cvar_t *cl_motd;
00032
00033 cvar_t *rcon_client_password;
00034 cvar_t *rconAddress;
00035
00036 cvar_t *cl_timeout;
00037 cvar_t *cl_maxpackets;
00038 cvar_t *cl_packetdup;
00039 cvar_t *cl_timeNudge;
00040 cvar_t *cl_showTimeDelta;
00041 cvar_t *cl_freezeDemo;
00042
00043 cvar_t *cl_shownet;
00044 cvar_t *cl_showSend;
00045 cvar_t *cl_timedemo;
00046 cvar_t *cl_avidemo;
00047 cvar_t *cl_forceavidemo;
00048
00049 cvar_t *cl_freelook;
00050 cvar_t *cl_sensitivity;
00051
00052 cvar_t *cl_mouseAccel;
00053 cvar_t *cl_showMouseRate;
00054
00055 cvar_t *m_pitch;
00056 cvar_t *m_yaw;
00057 cvar_t *m_forward;
00058 cvar_t *m_side;
00059 cvar_t *m_filter;
00060
00061 cvar_t *cl_activeAction;
00062
00063 cvar_t *cl_motdString;
00064
00065 cvar_t *cl_allowDownload;
00066 cvar_t *cl_conXOffset;
00067 cvar_t *cl_inGameVideo;
00068
00069 cvar_t *cl_serverStatusResendTime;
00070 cvar_t *cl_trn;
00071
00072 clientActive_t cl;
00073 clientConnection_t clc;
00074 clientStatic_t cls;
00075 vm_t *cgvm;
00076
00077
00078 refexport_t re;
00079
00080 ping_t cl_pinglist[MAX_PINGREQUESTS];
00081
00082 typedef struct serverStatus_s
00083 {
00084 char string[BIG_INFO_STRING];
00085 netadr_t address;
00086 int time, startTime;
00087 qboolean pending;
00088 qboolean print;
00089 qboolean retrieved;
00090 } serverStatus_t;
00091
00092 serverStatus_t cl_serverStatusList[MAX_SERVERSTATUSREQUESTS];
00093 int serverStatusCount;
00094
00095 #if defined __USEA3D && defined __A3D_GEOM
00096 void hA3Dg_ExportRenderGeom (refexport_t *incoming_re);
00097 #endif
00098
00099 extern void SV_BotFrame( int time );
00100 void CL_CheckForResend( void );
00101 void CL_ShowIP_f(void);
00102 void CL_ServerStatus_f(void);
00103 void CL_ServerStatusResponse( netadr_t from, msg_t *msg );
00104
00105
00106
00107
00108
00109
00110
00111
00112 void CL_CDDialog( void ) {
00113 cls.cddialog = qtrue;
00114 }
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133 void CL_AddReliableCommand( const char *cmd ) {
00134 int index;
00135
00136
00137
00138 if ( clc.reliableSequence - clc.reliableAcknowledge > MAX_RELIABLE_COMMANDS ) {
00139 Com_Error( ERR_DROP, "Client command overflow" );
00140 }
00141 clc.reliableSequence++;
00142 index = clc.reliableSequence & ( MAX_RELIABLE_COMMANDS - 1 );
00143 Q_strncpyz( clc.reliableCommands[ index ], cmd, sizeof( clc.reliableCommands[ index ] ) );
00144 }
00145
00146
00147
00148
00149
00150
00151 void CL_ChangeReliableCommand( void ) {
00152 int r, index, l;
00153
00154 r = clc.reliableSequence - (random() * 5);
00155 index = clc.reliableSequence & ( MAX_RELIABLE_COMMANDS - 1 );
00156 l = strlen(clc.reliableCommands[ index ]);
00157 if ( l >= MAX_STRING_CHARS - 1 ) {
00158 l = MAX_STRING_CHARS - 2;
00159 }
00160 clc.reliableCommands[ index ][ l ] = '\n';
00161 clc.reliableCommands[ index ][ l+1 ] = '\0';
00162 }
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179 void CL_WriteDemoMessage ( msg_t *msg, int headerBytes ) {
00180 int len, swlen;
00181
00182
00183 len = clc.serverMessageSequence;
00184 swlen = LittleLong( len );
00185 FS_Write (&swlen, 4, clc.demofile);
00186
00187
00188 len = msg->cursize - headerBytes;
00189 swlen = LittleLong(len);
00190 FS_Write (&swlen, 4, clc.demofile);
00191 FS_Write ( msg->data + headerBytes, len, clc.demofile );
00192 }
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202 void CL_StopRecord_f( void ) {
00203 int len;
00204
00205 if ( !clc.demorecording ) {
00206 Com_Printf ("Not recording a demo.\n");
00207 return;
00208 }
00209
00210
00211 len = -1;
00212 FS_Write (&len, 4, clc.demofile);
00213 FS_Write (&len, 4, clc.demofile);
00214 FS_FCloseFile (clc.demofile);
00215 clc.demofile = 0;
00216 clc.demorecording = qfalse;
00217 clc.spDemoRecording = qfalse;
00218 Com_Printf ("Stopped demo.\n");
00219 }
00220
00221
00222
00223
00224
00225
00226 void CL_DemoFilename( int number, char *fileName ) {
00227 int a,b,c,d;
00228
00229 if ( number < 0 || number > 9999 ) {
00230 Com_sprintf( fileName, MAX_OSPATH, "demo9999.tga" );
00231 return;
00232 }
00233
00234 a = number / 1000;
00235 number -= a*1000;
00236 b = number / 100;
00237 number -= b*100;
00238 c = number / 10;
00239 number -= c*10;
00240 d = number;
00241
00242 Com_sprintf( fileName, MAX_OSPATH, "demo%i%i%i%i"
00243 , a, b, c, d );
00244 }
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255 static char demoName[MAX_QPATH];
00256 void CL_Record_f( void ) {
00257 char name[MAX_OSPATH];
00258 byte bufData[MAX_MSGLEN];
00259 msg_t buf;
00260 int i;
00261 int len;
00262 entityState_t *ent;
00263 entityState_t nullstate;
00264 char *s;
00265
00266 if ( Cmd_Argc() > 2 ) {
00267 Com_Printf ("record <demoname>\n");
00268 return;
00269 }
00270
00271 if ( clc.demorecording ) {
00272 if (!clc.spDemoRecording) {
00273 Com_Printf ("Already recording.\n");
00274 }
00275 return;
00276 }
00277
00278 if ( cls.state != CA_ACTIVE ) {
00279 Com_Printf ("You must be in a level to record.\n");
00280 return;
00281 }
00282
00283
00284 if ( !Cvar_VariableValue( "g_synchronousClients" ) ) {
00285 Com_Printf (S_COLOR_YELLOW "WARNING: You should set 'g_synchronousClients 1' for smoother demo recording\n");
00286 }
00287
00288 if ( Cmd_Argc() == 2 ) {
00289 s = Cmd_Argv(1);
00290 Q_strncpyz( demoName, s, sizeof( demoName ) );
00291 Com_sprintf (name, sizeof(name), "demos/%s.dm_%d", demoName, PROTOCOL_VERSION );
00292 } else {
00293 int number;
00294
00295
00296 for ( number = 0 ; number <= 9999 ; number++ ) {
00297 CL_DemoFilename( number, demoName );
00298 Com_sprintf (name, sizeof(name), "demos/%s.dm_%d", demoName, PROTOCOL_VERSION );
00299
00300 len = FS_ReadFile( name, NULL );
00301 if ( len <= 0 ) {
00302 break;
00303 }
00304 }
00305 }
00306
00307
00308
00309 Com_Printf ("recording to %s.\n", name);
00310 clc.demofile = FS_FOpenFileWrite( name );
00311 if ( !clc.demofile ) {
00312 Com_Printf ("ERROR: couldn't open.\n");
00313 return;
00314 }
00315 clc.demorecording = qtrue;
00316 if (Cvar_VariableValue("ui_recordSPDemo")) {
00317 clc.spDemoRecording = qtrue;
00318 } else {
00319 clc.spDemoRecording = qfalse;
00320 }
00321
00322
00323 Q_strncpyz( clc.demoName, demoName, sizeof( clc.demoName ) );
00324
00325
00326 clc.demowaiting = qtrue;
00327
00328
00329 MSG_Init (&buf, bufData, sizeof(bufData));
00330 MSG_Bitstream(&buf);
00331
00332
00333 MSG_WriteLong( &buf, clc.reliableSequence );
00334
00335 MSG_WriteByte (&buf, svc_gamestate);
00336 MSG_WriteLong (&buf, clc.serverCommandSequence );
00337
00338
00339 for ( i = 0 ; i < MAX_CONFIGSTRINGS ; i++ ) {
00340 if ( !cl.gameState.stringOffsets[i] ) {
00341 continue;
00342 }
00343 s = cl.gameState.stringData + cl.gameState.stringOffsets[i];
00344 MSG_WriteByte (&buf, svc_configstring);
00345 MSG_WriteShort (&buf, i);
00346 MSG_WriteBigString (&buf, s);
00347 }
00348
00349
00350 Com_Memset (&nullstate, 0, sizeof(nullstate));
00351 for ( i = 0; i < MAX_GENTITIES ; i++ ) {
00352 ent = &cl.entityBaselines[i];
00353 if ( !ent->number ) {
00354 continue;
00355 }
00356 MSG_WriteByte (&buf, svc_baseline);
00357 MSG_WriteDeltaEntity (&buf, &nullstate, ent, qtrue );
00358 }
00359
00360 MSG_WriteByte( &buf, svc_EOF );
00361
00362
00363
00364
00365 MSG_WriteLong(&buf, clc.clientNum);
00366
00367 MSG_WriteLong(&buf, clc.checksumFeed);
00368
00369
00370 MSG_WriteByte( &buf, svc_EOF );
00371
00372
00373 len = LittleLong( clc.serverMessageSequence - 1 );
00374 FS_Write (&len, 4, clc.demofile);
00375
00376 len = LittleLong (buf.cursize);
00377 FS_Write (&len, 4, clc.demofile);
00378 FS_Write (buf.data, buf.cursize, clc.demofile);
00379
00380
00381 }
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396 void CL_DemoCompleted( void ) {
00397 if (cl_timedemo && cl_timedemo->integer) {
00398 int time;
00399
00400 time = Sys_Milliseconds() - clc.timeDemoStart;
00401 if ( time > 0 ) {
00402 Com_Printf ("%i frames, %3.1f seconds: %3.1f fps\n", clc.timeDemoFrames,
00403 time/1000.0, clc.timeDemoFrames*1000.0 / time);
00404 }
00405 }
00406
00407 CL_Disconnect( qtrue );
00408 CL_NextDemo();
00409 }
00410
00411
00412
00413
00414
00415
00416 void CL_ReadDemoMessage( void ) {
00417 int r;
00418 msg_t buf;
00419 byte bufData[ MAX_MSGLEN ];
00420 int s;
00421
00422 if ( !clc.demofile ) {
00423 CL_DemoCompleted ();
00424 return;
00425 }
00426
00427
00428 r = FS_Read( &s, 4, clc.demofile);
00429 if ( r != 4 ) {
00430 CL_DemoCompleted ();
00431 return;
00432 }
00433 clc.serverMessageSequence = LittleLong( s );
00434
00435
00436 MSG_Init( &buf, bufData, sizeof( bufData ) );
00437
00438
00439 r = FS_Read (&buf.cursize, 4, clc.demofile);
00440 if ( r != 4 ) {
00441 CL_DemoCompleted ();
00442 return;
00443 }
00444 buf.cursize = LittleLong( buf.cursize );
00445 if ( buf.cursize == -1 ) {
00446 CL_DemoCompleted ();
00447 return;
00448 }
00449 if ( buf.cursize > buf.maxsize ) {
00450 Com_Error (ERR_DROP, "CL_ReadDemoMessage: demoMsglen > MAX_MSGLEN");
00451 }
00452 r = FS_Read( buf.data, buf.cursize, clc.demofile );
00453 if ( r != buf.cursize ) {
00454 Com_Printf( "Demo file was truncated.\n");
00455 CL_DemoCompleted ();
00456 return;
00457 }
00458
00459 clc.lastPacketTime = cls.realtime;
00460 buf.readcount = 0;
00461 CL_ParseServerMessage( &buf );
00462 }
00463
00464
00465
00466
00467
00468
00469 static void CL_WalkDemoExt(char *arg, char *name, int *demofile)
00470 {
00471 int i = 0;
00472 *demofile = 0;
00473 while(demo_protocols[i])
00474 {
00475 Com_sprintf (name, MAX_OSPATH, "demos/%s.dm_%d", arg, demo_protocols[i]);
00476 FS_FOpenFileRead( name, demofile, qtrue );
00477 if (*demofile)
00478 {
00479 Com_Printf("Demo file: %s\n", name);
00480 break;
00481 }
00482 else
00483 Com_Printf("Not found: %s\n", name);
00484 i++;
00485 }
00486 }
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496 void CL_PlayDemo_f( void ) {
00497 char name[MAX_OSPATH];
00498 char *arg, *ext_test;
00499 int protocol, i;
00500 char retry[MAX_OSPATH];
00501
00502 if (Cmd_Argc() != 2) {
00503 Com_Printf ("playdemo <demoname>\n");
00504 return;
00505 }
00506
00507
00508 Cvar_Set( "sv_killserver", "1" );
00509
00510 CL_Disconnect( qtrue );
00511
00512
00513 arg = Cmd_Argv(1);
00514
00515
00516 ext_test = arg + strlen(arg) - 6;
00517 if ((strlen(arg) > 6) && (ext_test[0] == '.') && ((ext_test[1] == 'd') || (ext_test[1] == 'D')) && ((ext_test[2] == 'm') || (ext_test[2] == 'M')) && (ext_test[3] == '_'))
00518 {
00519 protocol = atoi(ext_test+4);
00520 i=0;
00521 while(demo_protocols[i])
00522 {
00523 if (demo_protocols[i] == protocol)
00524 break;
00525 i++;
00526 }
00527 if (demo_protocols[i])
00528 {
00529 Com_sprintf (name, sizeof(name), "demos/%s", arg);
00530 FS_FOpenFileRead( name, &clc.demofile, qtrue );
00531 } else {
00532 Com_Printf("Protocol %d not supported for demos\n", protocol);
00533 Q_strncpyz(retry, arg, sizeof(retry));
00534 retry[strlen(retry)-6] = 0;
00535 CL_WalkDemoExt( retry, name, &clc.demofile );
00536 }
00537 } else {
00538 CL_WalkDemoExt( arg, name, &clc.demofile );
00539 }
00540
00541 if (!clc.demofile) {
00542 Com_Error( ERR_DROP, "couldn't open %s", name);
00543 return;
00544 }
00545 Q_strncpyz( clc.demoName, Cmd_Argv(1), sizeof( clc.demoName ) );
00546
00547 Con_Close();
00548
00549 cls.state = CA_CONNECTED;
00550 clc.demoplaying = qtrue;
00551 Q_strncpyz( cls.servername, Cmd_Argv(1), sizeof( cls.servername ) );
00552
00553
00554 while ( cls.state >= CA_CONNECTED && cls.state < CA_PRIMED ) {
00555 CL_ReadDemoMessage();
00556 }
00557
00558
00559 clc.firstDemoFrameSkipped = qfalse;
00560 }
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570 void CL_StartDemoLoop( void ) {
00571
00572 Cbuf_AddText ("d1\n");
00573 cls.keyCatchers = 0;
00574 }
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584 void CL_NextDemo( void ) {
00585 char v[MAX_STRING_CHARS];
00586
00587 Q_strncpyz( v, Cvar_VariableString ("nextdemo"), sizeof(v) );
00588 v[MAX_STRING_CHARS-1] = 0;
00589 Com_DPrintf("CL_NextDemo: %s\n", v );
00590 if (!v[0]) {
00591 return;
00592 }
00593
00594 Cvar_Set ("nextdemo","");
00595 Cbuf_AddText (v);
00596 Cbuf_AddText ("\n");
00597 Cbuf_Execute();
00598 }
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608 void CL_ShutdownAll(void) {
00609
00610
00611 S_DisableSounds();
00612
00613 CL_ShutdownCGame();
00614
00615 CL_ShutdownUI();
00616
00617
00618 if ( re.Shutdown ) {
00619 re.Shutdown( qfalse );
00620 }
00621
00622 cls.uiStarted = qfalse;
00623 cls.cgameStarted = qfalse;
00624 cls.rendererStarted = qfalse;
00625 cls.soundRegistered = qfalse;
00626 }
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637 void CL_FlushMemory( void ) {
00638
00639
00640 CL_ShutdownAll();
00641
00642
00643 if ( !com_sv_running->integer ) {
00644
00645 Hunk_Clear();
00646
00647 CM_ClearMap();
00648 }
00649 else {
00650
00651 Hunk_ClearToMark();
00652 }
00653
00654 CL_StartHunkUsers();
00655 }
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666 void CL_MapLoading( void ) {
00667 if ( !com_cl_running->integer ) {
00668 return;
00669 }
00670
00671 Con_Close();
00672 cls.keyCatchers = 0;
00673
00674
00675 if ( cls.state >= CA_CONNECTED && !Q_stricmp( cls.servername, "localhost" ) ) {
00676 cls.state = CA_CONNECTED;
00677 Com_Memset( cls.updateInfoString, 0, sizeof( cls.updateInfoString ) );
00678 Com_Memset( clc.serverMessage, 0, sizeof( clc.serverMessage ) );
00679 Com_Memset( &cl.gameState, 0, sizeof( cl.gameState ) );
00680 clc.lastPacketSentTime = -9999;
00681 SCR_UpdateScreen();
00682 } else {
00683
00684 Cvar_Set( "nextmap", "" );
00685 CL_Disconnect( qtrue );
00686 Q_strncpyz( cls.servername, "localhost", sizeof(cls.servername) );
00687 cls.state = CA_CHALLENGING;
00688 cls.keyCatchers = 0;
00689 SCR_UpdateScreen();
00690 clc.connectTime = -RETRANSMIT_TIMEOUT;
00691 NET_StringToAdr( cls.servername, &clc.serverAddress);
00692
00693
00694 CL_CheckForResend();
00695 }
00696 }
00697
00698
00699
00700
00701
00702
00703
00704
00705 void CL_ClearState (void) {
00706
00707
00708
00709 Com_Memset( &cl, 0, sizeof( cl ) );
00710 }
00711
00712
00713
00714
00715
00716
00717
00718
00719
00720
00721
00722
00723 void CL_Disconnect( qboolean showMainMenu ) {
00724 if ( !com_cl_running || !com_cl_running->integer ) {
00725 return;
00726 }
00727
00728
00729 Cvar_Set("r_uiFullScreen", "1");
00730
00731 if ( clc.demorecording ) {
00732 CL_StopRecord_f ();
00733 }
00734
00735 if (clc.download) {
00736 FS_FCloseFile( clc.download );
00737 clc.download = 0;
00738 }
00739 *clc.downloadTempName = *clc.downloadName = 0;
00740 Cvar_Set( "cl_downloadName", "" );
00741
00742 if ( clc.demofile ) {
00743 FS_FCloseFile( clc.demofile );
00744 clc.demofile = 0;
00745 }
00746
00747 if ( uivm && showMainMenu ) {
00748 VM_Call( uivm, UI_SET_ACTIVE_MENU, UIMENU_NONE );
00749 }
00750
00751 SCR_StopCinematic ();
00752 S_ClearSoundBuffer();
00753
00754
00755
00756 if ( cls.state >= CA_CONNECTED ) {
00757 CL_AddReliableCommand( "disconnect" );
00758 CL_WritePacket();
00759 CL_WritePacket();
00760 CL_WritePacket();
00761 }
00762
00763 CL_ClearState ();
00764
00765
00766 Com_Memset( &clc, 0, sizeof( clc ) );
00767
00768 cls.state = CA_DISCONNECTED;
00769
00770
00771 Cvar_Set( "sv_cheats", "1" );
00772
00773
00774 cl_connectedToPureServer = qfalse;
00775 }
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786
00787 void CL_ForwardCommandToServer( const char *string ) {
00788 char *cmd;
00789
00790 cmd = Cmd_Argv(0);
00791
00792
00793 if ( cmd[0] == '-' ) {
00794 return;
00795 }
00796
00797 if ( clc.demoplaying || cls.state < CA_CONNECTED || cmd[0] == '+' ) {
00798 Com_Printf ("Unknown command \"%s\"\n", cmd);
00799 return;
00800 }
00801
00802 if ( Cmd_Argc() > 1 ) {
00803 CL_AddReliableCommand( string );
00804 } else {
00805 CL_AddReliableCommand( cmd );
00806 }
00807 }
00808
00809
00810
00811
00812
00813
00814
00815 void CL_RequestMotd( void ) {
00816 char info[MAX_INFO_STRING];
00817
00818 if ( !cl_motd->integer ) {
00819 return;
00820 }
00821 Com_Printf( "Resolving %s\n", UPDATE_SERVER_NAME );
00822 if ( !NET_StringToAdr( UPDATE_SERVER_NAME, &cls.updateServer ) ) {
00823 Com_Printf( "Couldn't resolve address\n" );
00824 return;
00825 }
00826 cls.updateServer.port = BigShort( PORT_UPDATE );
00827 Com_Printf( "%s resolved to %i.%i.%i.%i:%i\n", UPDATE_SERVER_NAME,
00828 cls.updateServer.ip[0], cls.updateServer.ip[1],
00829 cls.updateServer.ip[2], cls.updateServer.ip[3],
00830 BigShort( cls.updateServer.port ) );
00831
00832 info[0] = 0;
00833
00834
00835
00836
00837
00838 Com_sprintf( cls.updateChallenge, sizeof( cls.updateChallenge ), "%i", ((rand() << 16) ^ rand()) ^ Com_Milliseconds());
00839
00840 Info_SetValueForKey( info, "challenge", cls.updateChallenge );
00841 Info_SetValueForKey( info, "renderer", cls.glconfig.renderer_string );
00842 Info_SetValueForKey( info, "version", com_version->string );
00843
00844 NET_OutOfBandPrint( NS_CLIENT, cls.updateServer, "getmotd \"%s\"\n", info );
00845 }
00846
00847
00848
00849
00850
00851
00852
00853
00854
00855
00856
00857
00858
00859
00860
00861
00862
00863
00864
00865
00866
00867
00868
00869
00870
00871
00872
00873
00874
00875
00876
00877
00878
00879
00880
00881
00882
00883
00884
00885 void CL_RequestAuthorization( void ) {
00886 char nums[64];
00887 int i, j, l;
00888 cvar_t *fs;
00889
00890 if ( !cls.authorizeServer.port ) {
00891 Com_Printf( "Resolving %s\n", AUTHORIZE_SERVER_NAME );
00892 if ( !NET_StringToAdr( AUTHORIZE_SERVER_NAME, &cls.authorizeServer ) ) {
00893 Com_Printf( "Couldn't resolve address\n" );
00894 return;
00895 }
00896
00897 cls.authorizeServer.port = BigShort( PORT_AUTHORIZE );
00898 Com_Printf( "%s resolved to %i.%i.%i.%i:%i\n", AUTHORIZE_SERVER_NAME,
00899 cls.authorizeServer.ip[0], cls.authorizeServer.ip[1],
00900 cls.authorizeServer.ip[2], cls.authorizeServer.ip[3],
00901 BigShort( cls.authorizeServer.port ) );
00902 }
00903 if ( cls.authorizeServer.type == NA_BAD ) {
00904 return;
00905 }
00906
00907 if ( Cvar_VariableValue( "fs_restrict" ) ) {
00908 Q_strncpyz( nums, "demota", sizeof( nums ) );
00909 } else {
00910
00911 j = 0;
00912 l = strlen( cl_cdkey );
00913 if ( l > 32 ) {
00914 l = 32;
00915 }
00916 for ( i = 0 ; i < l ; i++ ) {
00917 if ( ( cl_cdkey[i] >= '0' && cl_cdkey[i] <= '9' )
00918 || ( cl_cdkey[i] >= 'a' && cl_cdkey[i] <= 'z' )
00919 || ( cl_cdkey[i] >= 'A' && cl_cdkey[i] <= 'Z' )
00920 ) {
00921 nums[j] = cl_cdkey[i];
00922 j++;
00923 }
00924 }
00925 nums[j] = 0;
00926 }
00927
00928 fs = Cvar_Get ("cl_anonymous", "0", CVAR_INIT|CVAR_SYSTEMINFO );
00929
00930 NET_OutOfBandPrint(NS_CLIENT, cls.authorizeServer, va("getKeyAuthorize %i %s", fs->integer, nums) );
00931 }
00932
00933
00934
00935
00936
00937
00938
00939
00940
00941
00942
00943
00944
00945
00946 void CL_ForwardToServer_f( void ) {
00947 if ( cls.state != CA_ACTIVE || clc.demoplaying ) {
00948 Com_Printf ("Not connected to a server.\n");
00949 return;
00950 }
00951
00952
00953 if ( Cmd_Argc() > 1 ) {
00954 CL_AddReliableCommand( Cmd_Args() );
00955 }
00956 }
00957
00958
00959
00960
00961
00962
00963
00964
00965 void CL_Setenv_f( void ) {
00966 int argc = Cmd_Argc();
00967
00968 if ( argc > 2 ) {
00969 char buffer[1024];
00970 int i;
00971
00972 strcpy( buffer, Cmd_Argv(1) );
00973 strcat( buffer, "=" );
00974
00975 for ( i = 2; i < argc; i++ ) {
00976 strcat( buffer, Cmd_Argv( i ) );
00977 strcat( buffer, " " );
00978 }
00979
00980 putenv( buffer );
00981 } else if ( argc == 2 ) {
00982 char *env = getenv( Cmd_Argv(1) );
00983
00984 if ( env ) {
00985 Com_Printf( "%s=%s\n", Cmd_Argv(1), env );
00986 } else {
00987 Com_Printf( "%s undefined\n", Cmd_Argv(1), env );
00988 }
00989 }
00990 }
00991
00992
00993
00994
00995
00996
00997
00998 void CL_Disconnect_f( void ) {
00999 SCR_StopCinematic();
01000 Cvar_Set("ui_singlePlayerActive", "0");
01001 if ( cls.state != CA_DISCONNECTED && cls.state != CA_CINEMATIC ) {
01002 Com_Error (ERR_DISCONNECT, "Disconnected from server");
01003 }
01004 }
01005
01006
01007
01008
01009
01010
01011
01012
01013 void CL_Reconnect_f( void ) {
01014 if ( !strlen( cls.servername ) || !strcmp( cls.servername, "localhost" ) ) {
01015 Com_Printf( "Can't reconnect to localhost.\n" );
01016 return;
01017 }
01018 Cvar_Set("ui_singlePlayerActive", "0");
01019 Cbuf_AddText( va("connect %s\n", cls.servername ) );
01020 }
01021
01022
01023
01024
01025
01026
01027
01028 void CL_Connect_f( void ) {
01029 char *server;
01030
01031 if ( Cmd_Argc() != 2 ) {
01032 Com_Printf( "usage: connect [server]\n");
01033 return;
01034 }
01035
01036 Cvar_Set("ui_singlePlayerActive", "0");
01037
01038
01039 CL_RequestMotd();
01040
01041
01042 clc.serverMessage[0] = 0;
01043
01044 server = Cmd_Argv (1);
01045
01046 if ( com_sv_running->integer && !strcmp( server, "localhost" ) ) {
01047
01048 SV_Shutdown( "Server quit\n" );
01049 }
01050
01051
01052 Cvar_Set( "sv_killserver", "1" );
01053 SV_Frame( 0 );
01054
01055 CL_Disconnect( qtrue );
01056 Con_Close();
01057
01058
01059
01060
01061
01062 Q_strncpyz( cls.servername, server, sizeof(cls.servername) );
01063
01064 if (!NET_StringToAdr( cls.servername, &clc.serverAddress) ) {
01065 Com_Printf ("Bad server address\n");
01066 cls.state = CA_DISCONNECTED;
01067 return;
01068 }
01069 if (clc.serverAddress.port == 0) {
01070 clc.serverAddress.port = BigShort( PORT_SERVER );
01071 }
01072 Com_Printf( "%s resolved to %i.%i.%i.%i:%i\n", cls.servername,
01073 clc.serverAddress.ip[0], clc.serverAddress.ip[1],
01074 clc.serverAddress.ip[2], clc.serverAddress.ip[3],
01075 BigShort( clc.serverAddress.port ) );
01076
01077
01078
01079 if ( NET_IsLocalAddress( clc.serverAddress ) ) {
01080 cls.state = CA_CHALLENGING;
01081 } else {
01082 cls.state = CA_CONNECTING;
01083 }
01084
01085 cls.keyCatchers = 0;
01086 clc.connectTime = -99999;
01087 clc.connectPacketCount = 0;
01088
01089
01090 Cvar_Set( "cl_currentServerAddress", server );
01091 }
01092
01093
01094
01095
01096
01097
01098
01099
01100
01101
01102 void CL_Rcon_f( void ) {
01103 char message[1024];
01104 netadr_t to;
01105
01106 if ( !rcon_client_password->string ) {
01107 Com_Printf ("You must set 'rconpassword' before\n"
01108 "issuing an rcon command.\n");
01109 return;
01110 }
01111
01112 message[0] = -1;
01113 message[1] = -1;
01114 message[2] = -1;
01115 message[3] = -1;
01116 message[4] = 0;
01117
01118 strcat (message, "rcon ");
01119
01120 strcat (message, rcon_client_password->string);
01121 strcat (message, " ");
01122
01123
01124 strcat (message, Cmd_Cmd()+5);
01125
01126 if ( cls.state >= CA_CONNECTED ) {
01127 to = clc.netchan.remoteAddress;
01128 } else {
01129 if (!strlen(rconAddress->string)) {
01130 Com_Printf ("You must either be connected,\n"
01131 "or set the 'rconAddress' cvar\n"
01132 "to issue rcon commands\n");
01133
01134 return;
01135 }
01136 NET_StringToAdr (rconAddress->string, &to);
01137 if (to.port == 0) {
01138 to.port = BigShort (PORT_SERVER);
01139 }
01140 }
01141
01142 NET_SendPacket (NS_CLIENT, strlen(message)+1, message, to);
01143 }
01144
01145
01146
01147
01148
01149
01150 void CL_SendPureChecksums( void ) {
01151 const char *pChecksums;
01152 char cMsg[MAX_INFO_VALUE];
01153 int i;
01154
01155
01156 pChecksums = FS_ReferencedPakPureChecksums();
01157
01158
01159
01160 Com_sprintf(cMsg, sizeof(cMsg), "Yf ");
01161 Q_strcat(cMsg, sizeof(cMsg), va("%d ", cl.serverId) );
01162 Q_strcat(cMsg, sizeof(cMsg), pChecksums);
01163 for (i = 0; i < 2; i++) {
01164 cMsg[i] += 10;
01165 }
01166 CL_AddReliableCommand( cMsg );
01167 }
01168
01169
01170
01171
01172
01173
01174 void CL_ResetPureClientAtServer( void ) {
01175 CL_AddReliableCommand( va("vdr") );
01176 }
01177
01178
01179
01180
01181
01182
01183
01184
01185
01186
01187
01188 void CL_Vid_Restart_f( void ) {
01189
01190
01191 S_StopAllSounds();
01192
01193 CL_ShutdownUI();
01194
01195 CL_ShutdownCGame();
01196
01197 CL_ShutdownRef();
01198
01199 CL_ResetPureClientAtServer();
01200
01201 FS_ClearPakReferences( FS_UI_REF | FS_CGAME_REF );
01202
01203 FS_ConditionalRestart( clc.checksumFeed );
01204
01205 cls.rendererStarted = qfalse;
01206 cls.uiStarted = qfalse;
01207 cls.cgameStarted = qfalse;
01208 cls.soundRegistered = qfalse;
01209
01210
01211 Cvar_Set( "cl_paused", "0" );
01212
01213
01214 if ( !com_sv_running->integer ) {
01215
01216 Hunk_Clear();
01217 }
01218 else {
01219
01220 Hunk_ClearToMark();
01221 }
01222
01223
01224 CL_InitRef();
01225
01226
01227 CL_StartHunkUsers();
01228
01229
01230 if ( cls.state > CA_CONNECTED && cls.state != CA_CINEMATIC ) {
01231 cls.cgameStarted = qtrue;
01232 CL_InitCGame();
01233
01234 CL_SendPureChecksums();
01235 }
01236 }
01237
01238
01239
01240
01241
01242
01243
01244
01245
01246
01247 void CL_Snd_Restart_f( void ) {
01248 S_Shutdown();
01249 S_Init();
01250
01251 CL_Vid_Restart_f();
01252 }
01253
01254
01255
01256
01257
01258
01259
01260 void CL_OpenedPK3List_f( void ) {
01261 Com_Printf("Opened PK3 Names: %s\n", FS_LoadedPakNames());
01262 }
01263
01264
01265
01266
01267
01268
01269 void CL_ReferencedPK3List_f( void ) {
01270 Com_Printf("Referenced PK3 Names: %s\n", FS_ReferencedPakNames());
01271 }
01272
01273
01274
01275
01276
01277
01278 void CL_Configstrings_f( void ) {
01279 int i;
01280 int ofs;
01281
01282 if ( cls.state != CA_ACTIVE ) {
01283 Com_Printf( "Not connected to a server.\n");
01284 return;
01285 }
01286
01287 for ( i = 0 ; i < MAX_CONFIGSTRINGS ; i++ ) {
01288 ofs = cl.gameState.stringOffsets[ i ];
01289 if ( !ofs ) {
01290 continue;
01291 }
01292 Com_Printf( "%4i: %s\n", i, cl.gameState.stringData + ofs );
01293 }
01294 }
01295
01296
01297
01298
01299
01300
01301 void CL_Clientinfo_f( void ) {
01302 Com_Printf( "--------- Client Information ---------\n" );
01303 Com_Printf( "state: %i\n", cls.state );
01304 Com_Printf( "Server: %s\n", cls.servername );
01305 Com_Printf ("User info settings:\n");
01306 Info_Print( Cvar_InfoString( CVAR_USERINFO ) );
01307 Com_Printf( "--------------------------------------\n" );
01308 }
01309
01310
01311
01312
01313
01314
01315
01316
01317
01318
01319
01320 void CL_DownloadsComplete( void ) {
01321
01322
01323 if (clc.downloadRestart) {
01324 clc.downloadRestart = qfalse;
01325
01326 FS_Restart(clc.checksumFeed);
01327
01328
01329 CL_AddReliableCommand( "donedl" );
01330
01331
01332
01333 return;
01334 }
01335
01336
01337 cls.state = CA_LOADING;
01338
01339
01340 Com_EventLoop();
01341
01342
01343
01344 if ( cls.state != CA_LOADING ) {
01345 return;
01346 }
01347
01348
01349 Cvar_Set("r_uiFullScreen", "0");
01350
01351
01352
01353
01354
01355 CL_FlushMemory();
01356
01357
01358 cls.cgameStarted = qtrue;
01359 CL_InitCGame();
01360
01361
01362 CL_SendPureChecksums();
01363
01364 CL_WritePacket();
01365 CL_WritePacket();
01366 CL_WritePacket();
01367 }
01368
01369
01370
01371
01372
01373
01374
01375
01376
01377 void CL_BeginDownload( const char *localName, const char *remoteName ) {
01378
01379 Com_DPrintf("***** CL_BeginDownload *****\n"
01380 "Localname: %s\n"
01381 "Remotename: %s\n"
01382 "****************************\n", localName, remoteName);
01383
01384 Q_strncpyz ( clc.downloadName, localName, sizeof(clc.downloadName) );
01385 Com_sprintf( clc.downloadTempName, sizeof(clc.downloadTempName), "%s.tmp", localName );
01386
01387
01388 Cvar_Set( "cl_downloadName", remoteName );
01389 Cvar_Set( "cl_downloadSize", "0" );
01390 Cvar_Set( "cl_downloadCount", "0" );
01391 Cvar_SetValue( "cl_downloadTime", cls.realtime );
01392
01393 clc.downloadBlock = 0;
01394 clc.downloadCount = 0;
01395
01396 CL_AddReliableCommand( va("download %s", remoteName) );
01397 }
01398
01399
01400
01401
01402
01403
01404
01405
01406 void CL_NextDownload(void) {
01407 char *s;
01408 char *remoteName, *localName;
01409
01410
01411 if (*clc.downloadList) {
01412 s = clc.downloadList;
01413
01414
01415
01416
01417 if (*s == '@')
01418 s++;
01419 remoteName = s;
01420
01421 if ( (s = strchr(s, '@')) == NULL ) {
01422 CL_DownloadsComplete();
01423 return;
01424 }
01425
01426 *s++ = 0;
01427 localName = s;
01428 if ( (s = strchr(s, '@')) != NULL )
01429 *s++ = 0;
01430 else
01431 s = localName + strlen(localName);
01432
01433 CL_BeginDownload( localName, remoteName );
01434
01435 clc.downloadRestart = qtrue;
01436
01437
01438 memmove( clc.downloadList, s, strlen(s) + 1);
01439
01440 return;
01441 }
01442
01443 CL_DownloadsComplete();
01444 }
01445
01446
01447
01448
01449
01450
01451
01452
01453
01454 void CL_InitDownloads(void) {
01455 char missingfiles[1024];
01456
01457 if ( !cl_allowDownload->integer )
01458 {
01459
01460
01461 if (FS_ComparePaks( missingfiles, sizeof( missingfiles ), qfalse ) )
01462 {
01463
01464
01465 Com_Printf( "\nWARNING: You are missing some files referenced by the server:\n%s"
01466 "You might not be able to join the game\n"
01467 "Go to the setting menu to turn on autodownload, or get the file elsewhere\n\n", missingfiles );
01468 }
01469 }
01470 else if ( FS_ComparePaks( clc.downloadList, sizeof( clc.downloadList ) , qtrue ) ) {
01471
01472 Com_Printf("Need paks: %s\n", clc.downloadList );
01473
01474 if ( *clc.downloadList ) {
01475
01476 cls.state = CA_CONNECTED;
01477 CL_NextDownload();
01478 return;
01479 }
01480
01481 }
01482
01483 CL_DownloadsComplete();
01484 }
01485
01486
01487
01488
01489
01490
01491
01492
01493 void CL_CheckForResend( void ) {
01494 int port, i;
01495 char info[MAX_INFO_STRING];
01496 char data[MAX_INFO_STRING];
01497
01498
01499 if ( clc.demoplaying ) {
01500 return;
01501 }
01502
01503
01504 if ( cls.state != CA_CONNECTING && cls.state != CA_CHALLENGING ) {
01505 return;
01506 }
01507
01508 if ( cls.realtime - clc.connectTime < RETRANSMIT_TIMEOUT ) {
01509 return;
01510 }
01511
01512 clc.connectTime = cls.realtime;
01513 clc.connectPacketCount++;
01514
01515
01516 switch ( cls.state ) {
01517 case CA_CONNECTING:
01518
01519 if ( !Sys_IsLANAddress( clc.serverAddress ) ) {
01520 CL_RequestAuthorization();
01521 }
01522 NET_OutOfBandPrint(NS_CLIENT, clc.serverAddress, "getchallenge");
01523 break;
01524
01525 case CA_CHALLENGING:
01526
01527 port = Cvar_VariableValue ("net_qport");
01528
01529 Q_strncpyz( info, Cvar_InfoString( CVAR_USERINFO ), sizeof( info ) );
01530 Info_SetValueForKey( info, "protocol", va("%i", PROTOCOL_VERSION ) );
01531 Info_SetValueForKey( info, "qport", va("%i", port ) );
01532 Info_SetValueForKey( info, "challenge", va("%i", clc.challenge ) );
01533
01534 strcpy(data, "connect ");
01535
01536
01537 data[8] = '"';
01538
01539 for(i=0;i<strlen(info);i++) {
01540 data[9+i] = info[i];
01541 }
01542 data[9+i] = '"';
01543 data[10+i] = 0;
01544
01545
01546 NET_OutOfBandData( NS_CLIENT, clc.serverAddress, &data[0], i+10 );
01547
01548
01549 cvar_modifiedFlags &= ~CVAR_USERINFO;
01550 break;
01551
01552 default:
01553 Com_Error( ERR_FATAL, "CL_CheckForResend: bad cls.state" );
01554 }
01555 }
01556
01557
01558
01559
01560
01561
01562
01563
01564
01565
01566
01567 void CL_DisconnectPacket( netadr_t from ) {
01568 if ( cls.state < CA_AUTHORIZING ) {
01569 return;
01570 }
01571
01572
01573 if ( !NET_CompareAdr( from, clc.netchan.remoteAddress ) ) {
01574 return;
01575 }
01576
01577
01578
01579 if ( cls.realtime - clc.lastPacketTime < 3000 ) {
01580 return;
01581 }
01582
01583
01584 Com_Printf( "Server disconnected for unknown reason\n" );
01585 Cvar_Set("com_errorMessage", "Server disconnected for unknown reason\n" );
01586 CL_Disconnect( qtrue );
01587 }
01588
01589
01590
01591
01592
01593
01594
01595
01596 void CL_MotdPacket( netadr_t from ) {
01597 char *challenge;
01598 char *info;
01599
01600
01601 if ( !NET_CompareAdr( from, cls.updateServer ) ) {
01602 return;
01603 }
01604
01605 info = Cmd_Argv(1);
01606
01607
01608 challenge = Info_ValueForKey( info, "challenge" );
01609 if ( strcmp( challenge, cls.updateChallenge ) ) {
01610 return;
01611 }
01612
01613 challenge = Info_ValueForKey( info, "motd" );
01614
01615 Q_strncpyz( cls.updateInfoString, info, sizeof( cls.updateInfoString ) );
01616 Cvar_Set( "cl_motdString", challenge );
01617 }
01618
01619
01620
01621
01622
01623
01624 void CL_InitServerInfo( serverInfo_t *server, serverAddress_t *address ) {
01625 server->adr.type = NA_IP;
01626 server->adr.ip[0] = address->ip[0];
01627 server->adr.ip[1] = address->ip[1];
01628 server->adr.ip[2] = address->ip[2];
01629 server->adr.ip[3] = address->ip[3];
01630 server->adr.port = address->port;
01631 server->clients = 0;
01632 server->hostName[0] = '\0';
01633 server->mapName[0] = '\0';
01634 server->maxClients = 0;
01635 server->maxPing = 0;
01636 server->minPing = 0;
01637 server->ping = -1;
01638 server->game[0] = '\0';
01639 server->gameType = 0;
01640 server->netType = 0;
01641 }
01642
01643 #define MAX_SERVERSPERPACKET 256
01644
01645
01646
01647
01648
01649
01650 void CL_ServersResponsePacket( netadr_t from, msg_t *msg ) {
01651 int i, count, max, total;
01652 serverAddress_t addresses[MAX_SERVERSPERPACKET];
01653 int numservers;
01654 byte* buffptr;
01655 byte* buffend;
01656
01657 Com_Printf("CL_ServersResponsePacket\n");
01658
01659 if (cls.numglobalservers == -1) {
01660
01661 cls.numglobalservers = 0;
01662 cls.numGlobalServerAddresses = 0;
01663 }
01664
01665 if (cls.nummplayerservers == -1) {
01666 cls.nummplayerservers = 0;
01667 }
01668
01669
01670 numservers = 0;
01671 buffptr = msg->data;
01672 buffend = buffptr + msg->cursize;
01673 while (buffptr+1 < buffend) {
01674
01675 do {
01676 if (*buffptr++ == '\\')
01677 break;
01678 }
01679 while (buffptr < buffend);
01680
01681 if ( buffptr >= buffend - 6 ) {
01682 break;
01683 }
01684
01685
01686 addresses[numservers].ip[0] = *buffptr++;
01687 addresses[numservers].ip[1] = *buffptr++;
01688 addresses[numservers].ip[2] = *buffptr++;
01689 addresses[numservers].ip[3] = *buffptr++;
01690
01691
01692 addresses[numservers].port = (*buffptr++)<<8;
01693 addresses[numservers].port += *buffptr++;
01694 addresses[numservers].port = BigShort( addresses[numservers].port );
01695
01696
01697 if (*buffptr != '\\') {
01698 break;
01699 }
01700
01701 Com_DPrintf( "server: %d ip: %d.%d.%d.%d:%d\n",numservers,
01702 addresses[numservers].ip[0],
01703 addresses[numservers].ip[1],
01704 addresses[numservers].ip[2],
01705 addresses[numservers].ip[3],
01706 addresses[numservers].port );
01707
01708 numservers++;
01709 if (numservers >= MAX_SERVERSPERPACKET) {
01710 break;
01711 }
01712
01713
01714 if (buffptr[1] == 'E' && buffptr[2] == 'O' && buffptr[3] == 'T') {
01715 break;
01716 }
01717 }
01718
01719 if (cls.masterNum == 0) {
01720 count = cls.numglobalservers;
01721 max = MAX_GLOBAL_SERVERS;
01722 } else {
01723 count = cls.nummplayerservers;
01724 max = MAX_OTHER_SERVERS;
01725 }
01726
01727 for (i = 0; i < numservers && count < max; i++) {
01728
01729 serverInfo_t *server = (cls.masterNum == 0) ? &cls.globalServers[count] : &cls.mplayerServers[count];
01730
01731 CL_InitServerInfo( server, &addresses[i] );
01732
01733 count++;
01734 }
01735
01736
01737 if (cls.masterNum == 0) {
01738 if ( cls.numGlobalServerAddresses < MAX_GLOBAL_SERVERS ) {
01739
01740 for (; i < numservers && count >= max; i++) {
01741 serverAddress_t *addr;
01742
01743 addr = &cls.globalServerAddresses[cls.numGlobalServerAddresses++];
01744 addr->ip[0] = addresses[i].ip[0];
01745 addr->ip[1] = addresses[i].ip[1];
01746 addr->ip[2] = addresses[i].ip[2];
01747 addr->ip[3] = addresses[i].ip[3];
01748 addr->port = addresses[i].port;
01749 }
01750 }
01751 }
01752
01753 if (cls.masterNum == 0) {
01754 cls.numglobalservers = count;
01755 total = count + cls.numGlobalServerAddresses;
01756 } else {
01757 cls.nummplayerservers = count;
01758 total = count;
01759 }
01760
01761 Com_Printf("%d servers parsed (total %d)\n", numservers, total);
01762 }
01763
01764
01765
01766
01767
01768
01769
01770
01771 void CL_ConnectionlessPacket( netadr_t from, msg_t *msg ) {
01772 char *s;
01773 char *c;
01774
01775 MSG_BeginReadingOOB( msg );
01776 MSG_ReadLong( msg );
01777
01778 s = MSG_ReadStringLine( msg );
01779
01780 Cmd_TokenizeString( s );
01781
01782 c = Cmd_Argv(0);
01783
01784 Com_DPrintf ("CL packet %s: %s\n", NET_AdrToString(from), c);
01785
01786
01787 if ( !Q_stricmp(c, "challengeResponse") ) {
01788 if ( cls.state != CA_CONNECTING ) {
01789 Com_Printf( "Unwanted challenge response received. Ignored.\n" );
01790 } else {
01791
01792 clc.challenge = atoi(Cmd_Argv(1));
01793 cls.state = CA_CHALLENGING;
01794 clc.connectPacketCount = 0;
01795 clc.connectTime = -99999;
01796
01797
01798
01799 clc.serverAddress = from;
01800 Com_DPrintf ("challengeResponse: %d\n", clc.challenge);
01801 }
01802 return;
01803 }
01804
01805
01806 if ( !Q_stricmp(c, "connectResponse") ) {
01807 if ( cls.state >= CA_CONNECTED ) {
01808 Com_Printf ("Dup connect received. Ignored.\n");
01809 return;
01810 }
01811 if ( cls.state != CA_CHALLENGING ) {
01812 Com_Printf ("connectResponse packet while not connecting. Ignored.\n");
01813 return;
01814 }
01815 if ( !NET_CompareBaseAdr( from, clc.serverAddress ) ) {
01816 Com_Printf( "connectResponse from a different address. Ignored.\n" );
01817 Com_Printf( "%s should have been %s\n", NET_AdrToString( from ),
01818 NET_AdrToString( clc.serverAddress ) );
01819 return;
01820 }
01821 Netchan_Setup (NS_CLIENT, &clc.netchan, from, Cvar_VariableValue( "net_qport" ) );
01822 cls.state = CA_CONNECTED;
01823 clc.lastPacketSentTime = -9999;
01824 return;
01825 }
01826
01827
01828 if ( !Q_stricmp(c, "infoResponse") ) {
01829 CL_ServerInfoPacket( from, msg );
01830 return;
01831 }
01832
01833
01834 if ( !Q_stricmp(c, "statusResponse") ) {
01835 CL_ServerStatusResponse( from, msg );
01836 return;
01837 }
01838
01839
01840
01841 if (!Q_stricmp(c, "disconnect")) {
01842 CL_DisconnectPacket( from );
01843 return;
01844 }
01845
01846
01847 if ( !Q_stricmp(c, "echo") ) {
01848 NET_OutOfBandPrint( NS_CLIENT, from, "%s", Cmd_Argv(1) );
01849 return;
01850 }
01851
01852
01853 if ( !Q_stricmp(c, "keyAuthorize") ) {
01854
01855 return;
01856 }
01857
01858
01859 if ( !Q_stricmp(c, "motd") ) {
01860 CL_MotdPacket( from );
01861 return;
01862 }
01863
01864
01865 if ( !Q_stricmp(c, "print") ) {
01866 s = MSG_ReadString( msg );
01867 Q_strncpyz( clc.serverMessage, s, sizeof( clc.serverMessage ) );
01868 Com_Printf( "%s", s );
01869 return;
01870 }
01871
01872
01873 if ( !Q_strncmp(c, "getserversResponse", 18) ) {
01874 CL_ServersResponsePacket( from, msg );
01875 return;
01876 }
01877
01878 Com_DPrintf ("Unknown connectionless packet command.\n");
01879 }
01880
01881
01882
01883
01884
01885
01886
01887
01888
01889 void CL_PacketEvent( netadr_t from, msg_t *msg ) {
01890 int headerBytes;
01891
01892 clc.lastPacketTime = cls.realtime;
01893
01894 if ( msg->cursize >= 4 && *(int *)msg->data == -1 ) {
01895 CL_ConnectionlessPacket( from, msg );
01896 return;
01897 }
01898
01899 if ( cls.state < CA_CONNECTED ) {
01900 return;
01901 }
01902
01903 if ( msg->cursize < 4 ) {
01904 Com_Printf ("%s: Runt packet\n",NET_AdrToString( from ));
01905 return;
01906 }
01907
01908
01909
01910
01911 if ( !NET_CompareAdr( from, clc.netchan.remoteAddress ) ) {
01912 Com_DPrintf ("%s:sequenced packet without connection\n"
01913 ,NET_AdrToString( from ) );
01914
01915 return;
01916 }
01917
01918 if (!CL_Netchan_Process( &clc.netchan, msg) ) {
01919 return;
01920 }
01921
01922
01923 headerBytes = msg->readcount;
01924
01925
01926
01927
01928 clc.serverMessageSequence = LittleLong( *(int *)msg->data );
01929
01930 clc.lastPacketTime = cls.realtime;
01931 CL_ParseServerMessage( msg );
01932
01933
01934
01935
01936
01937 if ( clc.demorecording && !clc.demowaiting ) {
01938 CL_WriteDemoMessage( msg, headerBytes );
01939 }
01940 }
01941
01942
01943
01944
01945
01946
01947
01948 void CL_CheckTimeout( void ) {
01949
01950
01951
01952 if ( ( !cl_paused->integer || !sv_paused->integer )
01953 && cls.state >= CA_CONNECTED && cls.state != CA_CINEMATIC
01954 && cls.realtime - clc.lastPacketTime > cl_timeout->value*1000) {
01955 if (++cl.timeoutcount > 5) {
01956 Com_Printf ("\nServer connection timed out.\n");
01957 CL_Disconnect( qtrue );
01958 return;
01959 }
01960 } else {
01961 cl.timeoutcount = 0;
01962 }
01963 }
01964
01965
01966
01967
01968
01969
01970
01971
01972
01973
01974 void CL_CheckUserinfo( void ) {
01975
01976 if ( cls.state < CA_CHALLENGING ) {
01977 return;
01978 }
01979
01980 if ( cl_paused->integer ) {
01981 return;
01982 }
01983
01984 if ( cvar_modifiedFlags & CVAR_USERINFO ) {
01985 cvar_modifiedFlags &= ~CVAR_USERINFO;
01986 CL_AddReliableCommand( va("userinfo \"%s\"", Cvar_InfoString( CVAR_USERINFO ) ) );
01987 }
01988
01989 }
01990
01991
01992
01993
01994
01995
01996
01997 void CL_Frame ( int msec ) {
01998
01999 if ( !com_cl_running->integer ) {
02000 return;
02001 }
02002
02003 if ( cls.cddialog ) {
02004
02005 cls.cddialog = qfalse;
02006 VM_Call( uivm, UI_SET_ACTIVE_MENU, UIMENU_NEED_CD );
02007 } else if ( cls.state == CA_DISCONNECTED && !( cls.keyCatchers & KEYCATCH_UI )
02008 && !com_sv_running->integer ) {
02009
02010 S_StopAllSounds();
02011 VM_Call( uivm, UI_SET_ACTIVE_MENU, UIMENU_MAIN );
02012 }
02013
02014
02015 if ( cl_avidemo->integer && msec) {
02016
02017 if ( cls.state == CA_ACTIVE || cl_forceavidemo->integer) {
02018 Cbuf_ExecuteText( EXEC_NOW, "screenshot silent\n" );
02019 }
02020
02021 msec = (1000 / cl_avidemo->integer) * com_timescale->value;
02022 if (msec == 0) {
02023 msec = 1;
02024 }
02025 }
02026
02027
02028 cls.realFrametime = msec;
02029
02030
02031 cls.frametime = msec;
02032
02033 cls.realtime += cls.frametime;
02034
02035 if ( cl_timegraph->integer ) {
02036 SCR_DebugGraph ( cls.realFrametime * 0.25, 0 );
02037 }
02038
02039
02040 CL_CheckUserinfo();
02041
02042
02043
02044 CL_CheckTimeout();
02045
02046
02047 CL_SendCmd();
02048
02049
02050 CL_CheckForResend();
02051
02052
02053 CL_SetCGameTime();
02054
02055
02056 SCR_UpdateScreen();
02057
02058
02059 S_Update();
02060
02061
02062 SCR_RunCinematic();
02063
02064 Con_RunConsole();
02065
02066 cls.framecount++;
02067 }
02068
02069
02070
02071
02072
02073
02074
02075
02076
02077
02078
02079 void QDECL CL_RefPrintf( int print_level, const char *fmt, ...) {
02080 va_list argptr;
02081 char msg[MAXPRINTMSG];
02082
02083 va_start (argptr,fmt);
02084 Q_vsnprintf (msg, sizeof(msg), fmt, argptr);
02085 va_end (argptr);
02086
02087 if ( print_level == PRINT_ALL ) {
02088 Com_Printf ("%s", msg);
02089 } else if ( print_level == PRINT_WARNING ) {
02090 Com_Printf (S_COLOR_YELLOW "%s", msg);
02091 } else if ( print_level == PRINT_DEVELOPER ) {
02092 Com_DPrintf (S_COLOR_RED "%s", msg);
02093 }
02094 }
02095
02096
02097
02098
02099
02100
02101
02102
02103 void CL_ShutdownRef( void ) {
02104 if ( !re.Shutdown ) {
02105 return;
02106 }
02107 re.Shutdown( qtrue );
02108 Com_Memset( &re, 0, sizeof( re ) );
02109 }
02110
02111
02112
02113
02114
02115
02116 void CL_InitRenderer( void ) {
02117
02118 re.BeginRegistration( &cls.glconfig );
02119
02120
02121 cls.charSetShader = re.RegisterShader( "gfx/2d/bigchars" );
02122 cls.whiteShader = re.RegisterShader( "white" );
02123 cls.consoleShader = re.RegisterShader( "console" );
02124 g_console_field_width = cls.glconfig.vidWidth / SMALLCHAR_WIDTH - 2;
02125 g_consoleField.widthInChars = g_console_field_width;
02126 }
02127
02128
02129
02130
02131
02132
02133
02134
02135
02136 void CL_StartHunkUsers( void ) {
02137 if (!com_cl_running) {
02138 return;
02139 }
02140
02141 if ( !com_cl_running->integer ) {
02142 return;
02143 }
02144
02145 if ( !cls.rendererStarted ) {
02146 cls.rendererStarted = qtrue;
02147 CL_InitRenderer();
02148 }
02149
02150 if ( !cls.soundStarted ) {
02151 cls.soundStarted = qtrue;
02152 S_Init();
02153 }
02154
02155 if ( !cls.soundRegistered ) {
02156 cls.soundRegistered = qtrue;
02157 S_BeginRegistration();
02158 }
02159
02160 if ( !cls.uiStarted ) {
02161 cls.uiStarted = qtrue;
02162 CL_InitUI();
02163 }
02164 }
02165
02166
02167
02168
02169
02170
02171 void *CL_RefMalloc( int size ) {
02172 return Z_TagMalloc( size, TAG_RENDERER );
02173 }
02174
02175 int CL_ScaledMilliseconds(void) {
02176 return Sys_Milliseconds()*com_timescale->value;
02177 }
02178
02179
02180
02181
02182
02183
02184 void CL_InitRef( void ) {
02185 refimport_t ri;
02186 refexport_t *ret;
02187
02188 Com_Printf( "----- Initializing Renderer ----\n" );
02189
02190 ri.Cmd_AddCommand = Cmd_AddCommand;
02191 ri.Cmd_RemoveCommand = Cmd_RemoveCommand;
02192 ri.Cmd_Argc = Cmd_Argc;
02193 ri.Cmd_Argv = Cmd_Argv;
02194 ri.Cmd_ExecuteText = Cbuf_ExecuteText;
02195 ri.Printf = CL_RefPrintf;
02196 ri.Error = Com_Error;
02197 ri.Milliseconds = CL_ScaledMilliseconds;
02198 ri.Malloc = CL_RefMalloc;
02199 ri.Free = Z_Free;
02200 #ifdef HUNK_DEBUG
02201 ri.Hunk_AllocDebug = Hunk_AllocDebug;
02202 #else
02203 ri.Hunk_Alloc = Hunk_Alloc;
02204 #endif
02205 ri.Hunk_AllocateTempMemory = Hunk_AllocateTempMemory;
02206 ri.Hunk_FreeTempMemory = Hunk_FreeTempMemory;
02207 ri.CM_DrawDebugSurface = CM_DrawDebugSurface;
02208 ri.FS_ReadFile = FS_ReadFile;
02209 ri.FS_FreeFile = FS_FreeFile;
02210 ri.FS_WriteFile = FS_WriteFile;
02211 ri.FS_FreeFileList = FS_FreeFileList;
02212 ri.FS_ListFiles = FS_ListFiles;
02213 ri.FS_FileIsInPAK = FS_FileIsInPAK;
02214 ri.FS_FileExists = FS_FileExists;
02215 ri.Cvar_Get = Cvar_Get;
02216 ri.Cvar_Set = Cvar_Set;
02217
02218
02219
02220 ri.CIN_UploadCinematic = CIN_UploadCinematic;
02221 ri.CIN_PlayCinematic = CIN_PlayCinematic;
02222 ri.CIN_RunCinematic = CIN_RunCinematic;
02223
02224 ret = GetRefAPI( REF_API_VERSION, &ri );
02225
02226 #if defined __USEA3D && defined __A3D_GEOM
02227 hA3Dg_ExportRenderGeom (ret);
02228 #endif
02229
02230 Com_Printf( "-------------------------------\n");
02231
02232 if ( !ret ) {
02233 Com_Error (ERR_FATAL, "Couldn't initialize refresh" );
02234 }
02235
02236 re = *ret;
02237
02238
02239 Cvar_Set( "cl_paused", "0" );
02240 }
02241
02242
02243
02244
02245
02246 void CL_SetModel_f( void ) {
02247 char *arg;
02248 char name[256];
02249
02250 arg = Cmd_Argv( 1 );
02251 if (arg[0]) {
02252 Cvar_Set( "model", arg );
02253 Cvar_Set( "headmodel", arg );
02254 } else {
02255 Cvar_VariableStringBuffer( "model", name, sizeof(name) );
02256 Com_Printf("model is set to %s\n", name);
02257 }
02258 }
02259
02260
02261
02262
02263
02264
02265 void CL_Init( void ) {
02266 Com_Printf( "----- Client Initialization -----\n" );
02267
02268 Con_Init ();
02269
02270 CL_ClearState ();
02271
02272 cls.state = CA_DISCONNECTED;
02273
02274 cls.realtime = 0;
02275
02276 CL_InitInput ();
02277
02278
02279
02280
02281 cl_noprint = Cvar_Get( "cl_noprint", "0", 0 );
02282 cl_motd = Cvar_Get ("cl_motd", "1", 0);
02283
02284 cl_timeout = Cvar_Get ("cl_timeout", "200", 0);
02285
02286 cl_timeNudge = Cvar_Get ("cl_timeNudge", "0", CVAR_TEMP );
02287 cl_shownet = Cvar_Get ("cl_shownet", "0", CVAR_TEMP );
02288 cl_showSend = Cvar_Get ("cl_showSend", "0", CVAR_TEMP );
02289 cl_showTimeDelta = Cvar_Get ("cl_showTimeDelta", "0", CVAR_TEMP );
02290 cl_freezeDemo = Cvar_Get ("cl_freezeDemo", "0", CVAR_TEMP );
02291 rcon_client_password = Cvar_Get ("rconPassword", "", CVAR_TEMP );
02292 cl_activeAction = Cvar_Get( "activeAction", "", CVAR_TEMP );
02293
02294 cl_timedemo = Cvar_Get ("timedemo", "0", 0);
02295 cl_avidemo = Cvar_Get ("cl_avidemo", "0", 0);
02296 cl_forceavidemo = Cvar_Get ("cl_forceavidemo", "0", 0);
02297
02298 rconAddress = Cvar_Get ("rconAddress", "", 0);
02299
02300 cl_yawspeed = Cvar_Get ("cl_yawspeed", "140", CVAR_ARCHIVE);
02301 cl_pitchspeed = Cvar_Get ("cl_pitchspeed", "140", CVAR_ARCHIVE);
02302 cl_anglespeedkey = Cvar_Get ("cl_anglespeedkey", "1.5", 0);
02303
02304 cl_maxpackets = Cvar_Get ("cl_maxpackets", "30", CVAR_ARCHIVE );
02305 cl_packetdup = Cvar_Get ("cl_packetdup", "1", CVAR_ARCHIVE );
02306
02307 cl_run = Cvar_Get ("cl_run", "1", CVAR_ARCHIVE);
02308 cl_sensitivity = Cvar_Get ("sensitivity", "5", CVAR_ARCHIVE);
02309 cl_mouseAccel = Cvar_Get ("cl_mouseAccel", "0", CVAR_ARCHIVE);
02310 cl_freelook = Cvar_Get( "cl_freelook", "1", CVAR_ARCHIVE );
02311
02312 cl_showMouseRate = Cvar_Get ("cl_showmouserate", "0", 0);
02313
02314 cl_allowDownload = Cvar_Get ("cl_allowDownload", "0", CVAR_ARCHIVE);
02315
02316 cl_conXOffset = Cvar_Get ("cl_conXOffset", "0", 0);
02317 #ifdef MACOS_X
02318
02319 cl_inGameVideo = Cvar_Get ("r_inGameVideo", "0", CVAR_ARCHIVE);
02320 #else
02321 cl_inGameVideo = Cvar_Get ("r_inGameVideo", "1", CVAR_ARCHIVE);
02322 #endif
02323
02324 cl_serverStatusResendTime = Cvar_Get ("cl_serverStatusResendTime", "750", 0);
02325
02326
02327
02328 Cvar_Get ("cg_autoswitch", "1", CVAR_ARCHIVE);
02329
02330 m_pitch = Cvar_Get ("m_pitch", "0.022", CVAR_ARCHIVE);
02331 m_yaw = Cvar_Get ("m_yaw", "0.022", CVAR_ARCHIVE);
02332 m_forward = Cvar_Get ("m_forward", "0.25", CVAR_ARCHIVE);
02333 m_side = Cvar_Get ("m_side", "0.25", CVAR_ARCHIVE);
02334 #ifdef MACOS_X
02335
02336 m_filter = Cvar_Get ("m_filter", "1", CVAR_ARCHIVE);
02337 #else
02338 m_filter = Cvar_Get ("m_filter", "0", CVAR_ARCHIVE);
02339 #endif
02340
02341 cl_motdString = Cvar_Get( "cl_motdString", "", CVAR_ROM );
02342
02343 Cvar_Get( "cl_maxPing", "800", CVAR_ARCHIVE );
02344
02345
02346
02347 Cvar_Get ("name", "UnnamedPlayer", CVAR_USERINFO | CVAR_ARCHIVE );
02348 Cvar_Get ("rate", "3000", CVAR_USERINFO | CVAR_ARCHIVE );
02349 Cvar_Get ("snaps", "20", CVAR_USERINFO | CVAR_ARCHIVE );
02350 Cvar_Get ("model", "sarge", CVAR_USERINFO | CVAR_ARCHIVE );
02351 Cvar_Get ("headmodel", "sarge", CVAR_USERINFO | CVAR_ARCHIVE );
02352 Cvar_Get ("team_model", "james", CVAR_USERINFO | CVAR_ARCHIVE );
02353 Cvar_Get ("team_headmodel", "*james", CVAR_USERINFO | CVAR_ARCHIVE );
02354 Cvar_Get ("g_redTeam", "Stroggs", CVAR_SERVERINFO | CVAR_ARCHIVE);
02355 Cvar_Get ("g_blueTeam", "Pagans", CVAR_SERVERINFO | CVAR_ARCHIVE);
02356 Cvar_Get ("color1", "4", CVAR_USERINFO | CVAR_ARCHIVE );
02357 Cvar_Get ("color2", "5", CVAR_USERINFO | CVAR_ARCHIVE );
02358 Cvar_Get ("handicap", "100", CVAR_USERINFO | CVAR_ARCHIVE );
02359 Cvar_Get ("teamtask", "0", CVAR_USERINFO );
02360 Cvar_Get ("sex", "male", CVAR_USERINFO | CVAR_ARCHIVE );
02361 Cvar_Get ("cl_anonymous", "0", CVAR_USERINFO | CVAR_ARCHIVE );
02362
02363 Cvar_Get ("password", "", CVAR_USERINFO);
02364 Cvar_Get ("cg_predictItems", "1", CVAR_USERINFO | CVAR_ARCHIVE );
02365
02366
02367
02368 Cvar_Get ("cg_viewsize", "100", CVAR_ARCHIVE );
02369
02370
02371
02372
02373 Cmd_AddCommand ("cmd", CL_ForwardToServer_f);
02374 Cmd_AddCommand ("configstrings", CL_Configstrings_f);
02375 Cmd_AddCommand ("clientinfo", CL_Clientinfo_f);
02376 Cmd_AddCommand ("snd_restart", CL_Snd_Restart_f);
02377 Cmd_AddCommand ("vid_restart", CL_Vid_Restart_f);
02378 Cmd_AddCommand ("disconnect", CL_Disconnect_f);
02379 Cmd_AddCommand ("record", CL_Record_f);
02380 Cmd_AddCommand ("demo", CL_PlayDemo_f);
02381 Cmd_AddCommand ("cinematic", CL_PlayCinematic_f);
02382 Cmd_AddCommand ("stoprecord", CL_StopRecord_f);
02383 Cmd_AddCommand ("connect", CL_Connect_f);
02384 Cmd_AddCommand ("reconnect", CL_Reconnect_f);
02385 Cmd_AddCommand ("localservers", CL_LocalServers_f);
02386 Cmd_AddCommand ("globalservers", CL_GlobalServers_f);
02387 Cmd_AddCommand ("rcon", CL_Rcon_f);
02388 Cmd_AddCommand ("setenv", CL_Setenv_f );
02389 Cmd_AddCommand ("ping", CL_Ping_f );
02390 Cmd_AddCommand ("serverstatus", CL_ServerStatus_f );
02391 Cmd_AddCommand ("showip", CL_ShowIP_f );
02392 Cmd_AddCommand ("fs_openedList", CL_OpenedPK3List_f );
02393 Cmd_AddCommand ("fs_referencedList", CL_ReferencedPK3List_f );
02394 Cmd_AddCommand ("model", CL_SetModel_f );
02395 CL_InitRef();
02396
02397 SCR_Init ();
02398
02399 Cbuf_Execute ();
02400
02401 Cvar_Set( "cl_running", "1" );
02402
02403 Com_Printf( "----- Client Initialization Complete -----\n" );
02404 }
02405
02406
02407
02408
02409
02410
02411
02412
02413 void CL_Shutdown( void ) {
02414 static qboolean recursive = qfalse;
02415
02416 Com_Printf( "----- CL_Shutdown -----\n" );
02417
02418 if ( recursive ) {
02419 printf ("recursive shutdown\n");
02420 return;
02421 }
02422 recursive = qtrue;
02423
02424 CL_Disconnect( qtrue );
02425
02426 S_Shutdown();
02427 CL_ShutdownRef();
02428
02429 CL_ShutdownUI();
02430
02431 Cmd_RemoveCommand ("cmd");
02432 Cmd_RemoveCommand ("configstrings");
02433 Cmd_RemoveCommand ("userinfo");
02434 Cmd_RemoveCommand ("snd_restart");
02435 Cmd_RemoveCommand ("vid_restart");
02436 Cmd_RemoveCommand ("disconnect");
02437 Cmd_RemoveCommand ("record");
02438 Cmd_RemoveCommand ("demo");
02439 Cmd_RemoveCommand ("cinematic");
02440 Cmd_RemoveCommand ("stoprecord");
02441 Cmd_RemoveCommand ("connect");
02442 Cmd_RemoveCommand ("localservers");
02443 Cmd_RemoveCommand ("globalservers");
02444 Cmd_RemoveCommand ("rcon");
02445 Cmd_RemoveCommand ("setenv");
02446 Cmd_RemoveCommand ("ping");
02447 Cmd_RemoveCommand ("serverstatus");
02448 Cmd_RemoveCommand ("showip");
02449 Cmd_RemoveCommand ("model");
02450
02451 Cvar_Set( "cl_running", "0" );
02452
02453 recursive = qfalse;
02454
02455 Com_Memset( &cls, 0, sizeof( cls ) );
02456
02457 Com_Printf( "-----------------------\n" );
02458
02459 }
02460
02461 static void CL_SetServerInfo(serverInfo_t *server, const char *info, int ping) {
02462 if (server) {
02463 if (info) {
02464 server->clients = atoi(Info_ValueForKey(info, "clients"));
02465 Q_strncpyz(server->hostName,Info_ValueForKey(info, "hostname"), MAX_NAME_LENGTH);
02466 Q_strncpyz(server->mapName, Info_ValueForKey(info, "mapname"), MAX_NAME_LENGTH);
02467 server->maxClients = atoi(Info_ValueForKey(info, "sv_maxclients"));
02468 Q_strncpyz(server->game,Info_ValueForKey(info, "game"), MAX_NAME_LENGTH);
02469 server->gameType = atoi(Info_ValueForKey(info, "gametype"));
02470 server->netType = atoi(Info_ValueForKey(info, "nettype"));
02471 server->minPing = atoi(Info_ValueForKey(info, "minping"));
02472 server->maxPing = atoi(Info_ValueForKey(info, "maxping"));
02473 server->punkbuster = atoi(Info_ValueForKey(info, "punkbuster"));
02474 }
02475 server->ping = ping;
02476 }
02477 }
02478
02479 static void CL_SetServerInfoByAddress(netadr_t from, const char *info, int ping) {
02480 int i;
02481
02482 for (i = 0; i < MAX_OTHER_SERVERS; i++) {
02483 if (NET_CompareAdr(from, cls.localServers[i].adr)) {
02484 CL_SetServerInfo(&cls.localServers[i], info, ping);
02485 }
02486 }
02487
02488 for (i = 0; i < MAX_OTHER_SERVERS; i++) {
02489 if (NET_CompareAdr(from, cls.mplayerServers[i].adr)) {
02490 CL_SetServerInfo(&cls.mplayerServers[i], info, ping);
02491 }
02492 }
02493
02494 for (i = 0; i < MAX_GLOBAL_SERVERS; i++) {
02495 if (NET_CompareAdr(from, cls.globalServers[i].adr)) {
02496 CL_SetServerInfo(&cls.globalServers[i], info, ping);
02497 }
02498 }
02499
02500 for (i = 0; i < MAX_OTHER_SERVERS; i++) {
02501 if (NET_CompareAdr(from, cls.favoriteServers[i].adr)) {
02502 CL_SetServerInfo(&cls.favoriteServers[i], info, ping);
02503 }
02504 }
02505
02506 }
02507
02508
02509
02510
02511
02512
02513 void CL_ServerInfoPacket( netadr_t from, msg_t *msg ) {
02514 int i, type;
02515 char info[MAX_INFO_STRING];
02516 char* str;
02517 char *infoString;
02518 int prot;
02519
02520 infoString = MSG_ReadString( msg );
02521
02522
02523 prot = atoi( Info_ValueForKey( infoString, "protocol" ) );
02524 if ( prot != PROTOCOL_VERSION ) {
02525 Com_DPrintf( "Different protocol info packet: %s\n", infoString );
02526 return;
02527 }
02528
02529
02530 for (i=0; i<MAX_PINGREQUESTS; i++)
02531 {
02532 if ( cl_pinglist[i].adr.port && !cl_pinglist[i].time && NET_CompareAdr( from, cl_pinglist[i].adr ) )
02533 {
02534
02535 cl_pinglist[i].time = cls.realtime - cl_pinglist[i].start + 1;
02536 Com_DPrintf( "ping time %dms from %s\n", cl_pinglist[i].time, NET_AdrToString( from ) );
02537
02538
02539 Q_strncpyz( cl_pinglist[i].info, infoString, sizeof( cl_pinglist[i].info ) );
02540
02541
02542
02543 switch (from.type)
02544 {
02545 case NA_BROADCAST:
02546 case NA_IP:
02547 str = "udp";
02548 type = 1;
02549 break;
02550
02551 case NA_IPX:
02552 case NA_BROADCAST_IPX:
02553 str = "ipx";
02554 type = 2;
02555 break;
02556
02557 default:
02558 str = "???";
02559 type = 0;
02560 break;
02561 }
02562 Info_SetValueForKey( cl_pinglist[i].info, "nettype", va("%d", type) );
02563 CL_SetServerInfoByAddress(from, infoString, cl_pinglist[i].time);
02564
02565 return;
02566 }
02567 }
02568
02569
02570 if (cls.pingUpdateSource != AS_LOCAL) {
02571 return;
02572 }
02573
02574 for ( i = 0 ; i < MAX_OTHER_SERVERS ; i++ ) {
02575
02576 if ( cls.localServers[i].adr.port == 0 ) {
02577 break;
02578 }
02579
02580
02581 if ( NET_CompareAdr( from, cls.localServers[i].adr ) ) {
02582 return;
02583 }
02584 }
02585
02586 if ( i == MAX_OTHER_SERVERS ) {
02587 Com_DPrintf( "MAX_OTHER_SERVERS hit, dropping infoResponse\n" );
02588 return;
02589 }
02590
02591
02592 cls.numlocalservers = i+1;
02593 cls.localServers[i].adr = from;
02594 cls.localServers[i].clients = 0;
02595 cls.localServers[i].hostName[0] = '\0';
02596 cls.localServers[i].mapName[0] = '\0';
02597 cls.localServers[i].maxClients = 0;
02598 cls.localServers[i].maxPing = 0;
02599 cls.localServers[i].minPing = 0;
02600 cls.localServers[i].ping = -1;
02601 cls.localServers[i].game[0] = '\0';
02602 cls.localServers[i].gameType = 0;
02603 cls.localServers[i].netType = from.type;
02604 cls.localServers[i].punkbuster = 0;
02605
02606 Q_strncpyz( info, MSG_ReadString( msg ), MAX_INFO_STRING );
02607 if (strlen(info)) {
02608 if (info[strlen(info)-1] != '\n') {
02609 strncat(info, "\n", sizeof(info));
02610 }
02611 Com_Printf( "%s: %s", NET_AdrToString( from ), info );
02612 }
02613 }
02614
02615
02616
02617
02618
02619
02620 serverStatus_t *CL_GetServerStatus( netadr_t from ) {
02621 serverStatus_t *serverStatus;
02622 int i, oldest, oldestTime;
02623
02624 serverStatus = NULL;
02625 for (i = 0; i < MAX_SERVERSTATUSREQUESTS; i++) {
02626 if ( NET_CompareAdr( from, cl_serverStatusList[i].address ) ) {
02627 return &cl_serverStatusList[i];
02628 }
02629 }
02630 for (i = 0; i < MAX_SERVERSTATUSREQUESTS; i++) {
02631 if ( cl_serverStatusList[i].retrieved ) {
02632 return &cl_serverStatusList[i];
02633 }
02634 }
02635 oldest = -1;
02636 oldestTime = 0;
02637 for (i = 0; i < MAX_SERVERSTATUSREQUESTS; i++) {
02638 if (oldest == -1 || cl_serverStatusList[i].startTime < oldestTime) {
02639 oldest = i;
02640 oldestTime = cl_serverStatusList[i].startTime;
02641 }
02642 }
02643 if (oldest != -1) {
02644 return &cl_serverStatusList[oldest];
02645 }
02646 serverStatusCount++;
02647 return &cl_serverStatusList[serverStatusCount & (MAX_SERVERSTATUSREQUESTS-1)];
02648 }
02649
02650
02651
02652
02653
02654
02655 int CL_ServerStatus( char *serverAddress, char *serverStatusString, int maxLen ) {
02656 int i;
02657 netadr_t to;
02658 serverStatus_t *serverStatus;
02659
02660
02661 if ( !serverAddress ) {
02662 for (i = 0; i < MAX_SERVERSTATUSREQUESTS; i++) {
02663 cl_serverStatusList[i].address.port = 0;
02664 cl_serverStatusList[i].retrieved = qtrue;
02665 }
02666 return qfalse;
02667 }
02668
02669 if ( !NET_StringToAdr( serverAddress, &to ) ) {
02670 return qfalse;
02671 }
02672 serverStatus = CL_GetServerStatus( to );
02673
02674 if ( !serverStatusString ) {
02675 serverStatus->retrieved = qtrue;
02676 return qfalse;
02677 }
02678
02679
02680 if ( NET_CompareAdr( to, serverStatus->address) ) {
02681
02682 if (!serverStatus->pending) {
02683 Q_strncpyz(serverStatusString, serverStatus->string, maxLen);
02684 serverStatus->retrieved = qtrue;
02685 serverStatus->startTime = 0;
02686 return qtrue;
02687 }
02688
02689 else if ( serverStatus->startTime < Com_Milliseconds() - cl_serverStatusResendTime->integer ) {
02690 serverStatus->print = qfalse;
02691 serverStatus->pending = qtrue;
02692 serverStatus->retrieved = qfalse;
02693 serverStatus->time = 0;
02694 serverStatus->startTime = Com_Milliseconds();
02695 NET_OutOfBandPrint( NS_CLIENT, to, "getstatus" );
02696 return qfalse;
02697 }
02698 }
02699
02700 else if ( serverStatus->retrieved ) {
02701 serverStatus->address = to;
02702 serverStatus->print = qfalse;
02703 serverStatus->pending = qtrue;
02704 serverStatus->retrieved = qfalse;
02705 serverStatus->startTime = Com_Milliseconds();
02706 serverStatus->time = 0;
02707 NET_OutOfBandPrint( NS_CLIENT, to, "getstatus" );
02708 return qfalse;
02709 }
02710 return qfalse;
02711 }
02712
02713
02714
02715
02716
02717
02718 void CL_ServerStatusResponse( netadr_t from, msg_t *msg ) {
02719 char *s;
02720 char info[MAX_INFO_STRING];
02721 int i, l, score, ping;
02722 int len;
02723 serverStatus_t *serverStatus;
02724
02725 serverStatus = NULL;
02726 for (i = 0; i < MAX_SERVERSTATUSREQUESTS; i++) {
02727 if ( NET_CompareAdr( from, cl_serverStatusList[i].address ) ) {
02728 serverStatus = &cl_serverStatusList[i];
02729 break;
02730 }
02731 }
02732
02733 if (!serverStatus) {
02734 return;
02735 }
02736
02737 s = MSG_ReadStringLine( msg );
02738
02739 len = 0;
02740 Com_sprintf(&serverStatus->string[len], sizeof(serverStatus->string)-len, "%s", s);
02741
02742 if (serverStatus->print) {
02743 Com_Printf("Server settings:\n");
02744
02745 while (*s) {
02746 for (i = 0; i < 2 && *s; i++) {
02747 if (*s == '\\')
02748 s++;
02749 l = 0;
02750 while (*s) {
02751 info[l++] = *s;
02752 if (l >= MAX_INFO_STRING-1)
02753 break;
02754 s++;
02755 if (*s == '\\') {
02756 break;
02757 }
02758 }
02759 info[l] = '\0';
02760 if (i) {
02761 Com_Printf("%s\n", info);
02762 }
02763 else {
02764 Com_Printf("%-24s", info);
02765 }
02766 }
02767 }
02768 }
02769
02770 len = strlen(serverStatus->string);
02771 Com_sprintf(&serverStatus->string[len], sizeof(serverStatus->string)-len, "\\");
02772
02773 if (serverStatus->print) {
02774 Com_Printf("\nPlayers:\n");
02775 Com_Printf("num: score: ping: name:\n");
02776 }
02777 for (i = 0, s = MSG_ReadStringLine( msg ); *s; s = MSG_ReadStringLine( msg ), i++) {
02778
02779 len = strlen(serverStatus->string);
02780 Com_sprintf(&serverStatus->string[len], sizeof(serverStatus->string)-len, "\\%s", s);
02781
02782 if (serverStatus->print) {
02783 score = ping = 0;
02784 sscanf(s, "%d %d", &score, &ping);
02785 s = strchr(s, ' ');
02786 if (s)
02787 s = strchr(s+1, ' ');
02788 if (s)
02789 s++;
02790 else
02791 s = "unknown";
02792 Com_Printf("%-2d %-3d %-3d %s\n", i, score, ping, s );
02793 }
02794 }
02795 len = strlen(serverStatus->string);
02796 Com_sprintf(&serverStatus->string[len], sizeof(serverStatus->string)-len, "\\");
02797
02798 serverStatus->time = Com_Milliseconds();
02799 serverStatus->address = from;
02800 serverStatus->pending = qfalse;
02801 if (serverStatus->print) {
02802 serverStatus->retrieved = qtrue;
02803 }
02804 }
02805
02806
02807
02808
02809
02810
02811 void CL_LocalServers_f( void ) {
02812 char *message;
02813 int i, j;
02814 netadr_t to;
02815
02816 Com_Printf( "Scanning for servers on the local network...\n");
02817
02818
02819 cls.numlocalservers = 0;
02820 cls.pingUpdateSource = AS_LOCAL;
02821
02822 for (i = 0; i < MAX_OTHER_SERVERS; i++) {
02823 qboolean b = cls.localServers[i].visible;
02824 Com_Memset(&cls.localServers[i], 0, sizeof(cls.localServers[i]));
02825 cls.localServers[i].visible = b;
02826 }
02827 Com_Memset( &to, 0, sizeof( to ) );
02828
02829
02830
02831
02832 message = "\377\377\377\377getinfo xxx";
02833
02834
02835 for ( i = 0 ; i < 2 ; i++ ) {
02836
02837
02838
02839 for ( j = 0 ; j < NUM_SERVER_PORTS ; j++ ) {
02840 to.port = BigShort( (short)(PORT_SERVER + j) );
02841
02842 to.type = NA_BROADCAST;
02843 NET_SendPacket( NS_CLIENT, strlen( message ), message, to );
02844
02845 to.type = NA_BROADCAST_IPX;
02846 NET_SendPacket( NS_CLIENT, strlen( message ), message, to );
02847 }
02848 }
02849 }
02850
02851
02852
02853
02854
02855
02856 void CL_GlobalServers_f( void ) {
02857 netadr_t to;
02858 int i;
02859 int count;
02860 char *buffptr;
02861 char command[1024];
02862
02863 if ( Cmd_Argc() < 3) {
02864 Com_Printf( "usage: globalservers <master# 0-1> <protocol> [keywords]\n");
02865 return;
02866 }
02867
02868 cls.masterNum = atoi( Cmd_Argv(1) );
02869
02870 Com_Printf( "Requesting servers from the master...\n");
02871
02872
02873
02874
02875 if( cls.masterNum == 1 ) {
02876 NET_StringToAdr( MASTER_SERVER_NAME, &to );
02877 cls.nummplayerservers = -1;
02878 cls.pingUpdateSource = AS_MPLAYER;
02879 }
02880 else {
02881 NET_StringToAdr( MASTER_SERVER_NAME, &to );
02882 cls.numglobalservers = -1;
02883 cls.pingUpdateSource = AS_GLOBAL;
02884 }
02885 to.type = NA_IP;
02886 to.port = BigShort(PORT_MASTER);
02887
02888 sprintf( command, "getservers %s", Cmd_Argv(2) );
02889
02890
02891 buffptr = command + strlen( command );
02892 count = Cmd_Argc();
02893 for (i=3; i<count; i++)
02894 buffptr += sprintf( buffptr, " %s", Cmd_Argv(i) );
02895
02896
02897 if ( Cvar_VariableValue( "fs_restrict" ) ) {
02898 buffptr += sprintf( buffptr, " demo" );
02899 }
02900
02901 NET_OutOfBandPrint( NS_SERVER, to, command );
02902 }
02903
02904
02905
02906
02907
02908
02909
02910 void CL_GetPing( int n, char *buf, int buflen, int *pingtime )
02911 {
02912 const char *str;
02913 int time;
02914 int maxPing;
02915
02916 if (!cl_pinglist[n].adr.port)
02917 {
02918
02919 buf[0] = '\0';
02920 *pingtime = 0;
02921 return;
02922 }
02923
02924 str = NET_AdrToString( cl_pinglist[n].adr );
02925 Q_strncpyz( buf, str, buflen );
02926
02927 time = cl_pinglist[n].time;
02928 if (!time)
02929 {
02930
02931 time = cls.realtime - cl_pinglist[n].start;
02932 maxPing = Cvar_VariableIntegerValue( "cl_maxPing" );
02933 if( maxPing < 100 ) {
02934 maxPing = 100;
02935 }
02936 if (time < maxPing)
02937 {
02938
02939 time = 0;
02940 }
02941 }
02942
02943 CL_SetServerInfoByAddress(cl_pinglist[n].adr, cl_pinglist[n].info, cl_pinglist[n].time);
02944
02945 *pingtime = time;
02946 }
02947
02948
02949
02950
02951
02952
02953 void CL_UpdateServerInfo( int n )
02954 {
02955 if (!cl_pinglist[n].adr.port)
02956 {
02957 return;
02958 }
02959
02960 CL_SetServerInfoByAddress(cl_pinglist[n].adr, cl_pinglist[n].info, cl_pinglist[n].time );
02961 }
02962
02963
02964
02965
02966
02967
02968 void CL_GetPingInfo( int n, char *buf, int buflen )
02969 {
02970 if (!cl_pinglist[n].adr.port)
02971 {
02972
02973 if (buflen)
02974 buf[0] = '\0';
02975 return;
02976 }
02977
02978 Q_strncpyz( buf, cl_pinglist[n].info, buflen );
02979 }
02980
02981
02982
02983
02984
02985
02986 void CL_ClearPing( int n )
02987 {
02988 if (n < 0 || n >= MAX_PINGREQUESTS)
02989 return;
02990
02991 cl_pinglist[n].adr.port = 0;
02992 }
02993
02994
02995
02996
02997
02998
02999 int CL_GetPingQueueCount( void )
03000 {
03001 int i;
03002 int count;
03003 ping_t* pingptr;
03004
03005 count = 0;
03006 pingptr = cl_pinglist;
03007
03008 for (i=0; i<MAX_PINGREQUESTS; i++, pingptr++ ) {
03009 if (pingptr->adr.port) {
03010 count++;
03011 }
03012 }
03013
03014 return (count);
03015 }
03016
03017
03018
03019
03020
03021
03022 ping_t* CL_GetFreePing( void )
03023 {
03024 ping_t* pingptr;
03025 ping_t* best;
03026 int oldest;
03027 int i;
03028 int time;
03029
03030 pingptr = cl_pinglist;
03031 for (i=0; i<MAX_PINGREQUESTS; i++, pingptr++ )
03032 {
03033
03034 if (pingptr->adr.port)
03035 {
03036 if (!pingptr->time)
03037 {
03038 if (cls.realtime - pingptr->start < 500)
03039 {
03040
03041 continue;
03042 }
03043 }
03044 else if (pingptr->time < 500)
03045 {
03046
03047 continue;
03048 }
03049 }
03050
03051
03052 pingptr->adr.port = 0;
03053 return (pingptr);
03054 }
03055
03056
03057 pingptr = cl_pinglist;
03058 best = cl_pinglist;
03059 oldest = INT_MIN;
03060 for (i=0; i<MAX_PINGREQUESTS; i++, pingptr++ )
03061 {
03062
03063 time = cls.realtime - pingptr->start;
03064 if (time > oldest)
03065 {
03066 oldest = time;
03067 best = pingptr;
03068 }
03069 }
03070
03071 return (best);
03072 }
03073
03074
03075
03076
03077
03078
03079 void CL_Ping_f( void ) {
03080 netadr_t to;
03081 ping_t* pingptr;
03082 char* server;
03083
03084 if ( Cmd_Argc() != 2 ) {
03085 Com_Printf( "usage: ping [server]\n");
03086 return;
03087 }
03088
03089 Com_Memset( &to, 0, sizeof(netadr_t) );
03090
03091 server = Cmd_Argv(1);
03092
03093 if ( !NET_StringToAdr( server, &to ) ) {
03094 return;
03095 }
03096
03097 pingptr = CL_GetFreePing();
03098
03099 memcpy( &pingptr->adr, &to, sizeof (netadr_t) );
03100 pingptr->start = cls.realtime;
03101 pingptr->time = 0;
03102
03103 CL_SetServerInfoByAddress(pingptr->adr, NULL, 0);
03104
03105 NET_OutOfBandPrint( NS_CLIENT, to, "getinfo xxx" );
03106 }
03107
03108
03109
03110
03111
03112
03113 qboolean CL_UpdateVisiblePings_f(int source) {
03114 int slots, i;
03115 char buff[MAX_STRING_CHARS];
03116 int pingTime;
03117 int max;
03118 qboolean status = qfalse;
03119
03120 if (source < 0 || source > AS_FAVORITES) {
03121 return qfalse;
03122 }
03123
03124 cls.pingUpdateSource = source;
03125
03126 slots = CL_GetPingQueueCount();
03127 if (slots < MAX_PINGREQUESTS) {
03128 serverInfo_t *server = NULL;
03129
03130 max = (source == AS_GLOBAL) ? MAX_GLOBAL_SERVERS : MAX_OTHER_SERVERS;
03131 switch (source) {
03132 case AS_LOCAL :
03133 server = &cls.localServers[0];
03134 max = cls.numlocalservers;
03135 break;
03136 case AS_MPLAYER :
03137 server = &cls.mplayerServers[0];
03138 max = cls.nummplayerservers;
03139 break;
03140 case AS_GLOBAL :
03141 server = &cls.globalServers[0];
03142 max = cls.numglobalservers;
03143 break;
03144 case AS_FAVORITES :
03145 server = &cls.favoriteServers[0];
03146 max = cls.numfavoriteservers;
03147 break;
03148 }
03149 for (i = 0; i < max; i++) {
03150 if (server[i].visible) {
03151 if (server[i].ping == -1) {
03152 int j;
03153
03154 if (slots >= MAX_PINGREQUESTS) {
03155 break;
03156 }
03157 for (j = 0; j < MAX_PINGREQUESTS; j++) {
03158 if (!cl_pinglist[j].adr.port) {
03159 continue;
03160 }
03161 if (NET_CompareAdr( cl_pinglist[j].adr, server[i].adr)) {
03162
03163 break;
03164 }
03165 }
03166 if (j >= MAX_PINGREQUESTS) {
03167 status = qtrue;
03168 for (j = 0; j < MAX_PINGREQUESTS; j++) {
03169 if (!cl_pinglist[j].adr.port) {
03170 break;
03171 }
03172 }
03173 memcpy(&cl_pinglist[j].adr, &server[i].adr, sizeof(netadr_t));
03174 cl_pinglist[j].start = cls.realtime;
03175 cl_pinglist[j].time = 0;
03176 NET_OutOfBandPrint( NS_CLIENT, cl_pinglist[j].adr, "getinfo xxx" );
03177 slots++;
03178 }
03179 }
03180
03181
03182 else if (server[i].ping == 0) {
03183
03184 if (source == AS_GLOBAL) {
03185
03186 if ( cls.numGlobalServerAddresses > 0 ) {
03187
03188 cls.numGlobalServerAddresses--;
03189 CL_InitServerInfo(&server[i], &cls.globalServerAddresses[cls.numGlobalServerAddresses]);
03190
03191 }
03192 }
03193 }
03194 }
03195 }
03196 }
03197
03198 if (slots) {
03199 status = qtrue;
03200 }
03201 for (i = 0; i < MAX_PINGREQUESTS; i++) {
03202 if (!cl_pinglist[i].adr.port) {
03203 continue;
03204 }
03205 CL_GetPing( i, buff, MAX_STRING_CHARS, &pingTime );
03206 if (pingTime != 0) {
03207 CL_ClearPing(i);
03208 status = qtrue;
03209 }
03210 }
03211
03212 return status;
03213 }
03214
03215
03216
03217
03218
03219
03220 void CL_ServerStatus_f(void) {
03221 netadr_t to;
03222 char *server;
03223 serverStatus_t *serverStatus;
03224
03225 Com_Memset( &to, 0, sizeof(netadr_t) );
03226
03227 if ( Cmd_Argc() != 2 ) {
03228 if ( cls.state != CA_ACTIVE || clc.demoplaying ) {
03229 Com_Printf ("Not connected to a server.\n");
03230 Com_Printf( "Usage: serverstatus [server]\n");
03231 return;
03232 }
03233 server = cls.servername;
03234 }
03235 else {
03236 server = Cmd_Argv(1);
03237 }
03238
03239 if ( !NET_StringToAdr( server, &to ) ) {
03240 return;
03241 }
03242
03243 NET_OutOfBandPrint( NS_CLIENT, to, "getstatus" );
03244
03245 serverStatus = CL_GetServerStatus( to );
03246 serverStatus->address = to;
03247 serverStatus->print = qtrue;
03248 serverStatus->pending = qtrue;
03249 }
03250
03251
03252
03253
03254
03255
03256 void CL_ShowIP_f(void) {
03257 Sys_ShowIP();
03258 }
03259
03260
03261
03262
03263
03264
03265 qboolean CL_CDKeyValidate( const char *key, const char *checksum ) {
03266 char ch;
03267 byte sum;
03268 char chs[3];
03269 int i, len;
03270
03271 len = strlen(key);
03272 if( len != CDKEY_LEN ) {
03273 return qfalse;
03274 }
03275
03276 if( checksum && strlen( checksum ) != CDCHKSUM_LEN ) {
03277 return qfalse;
03278 }
03279
03280 sum = 0;
03281
03282 for (i = 0; i < len; i++) {
03283 ch = *key++;
03284 if (ch>='a' && ch<='z') {
03285 ch -= 32;
03286 }
03287 switch( ch ) {
03288 case '2':
03289 case '3':
03290 case '7':
03291 case 'A':
03292 case 'B':
03293 case 'C':
03294 case 'D':
03295 case 'G':
03296 case 'H':
03297 case 'J':
03298 case 'L':
03299 case 'P':
03300 case 'R':
03301 case 'S':
03302 case 'T':
03303 case 'W':
03304 sum += ch;
03305 continue;
03306 default:
03307 return qfalse;
03308 }
03309 }
03310
03311 sprintf(chs, "%02x", sum);
03312
03313 if (checksum && !Q_stricmp(chs, checksum)) {
03314 return qtrue;
03315 }
03316
03317 if (!checksum) {
03318 return qtrue;
03319 }
03320
03321 return qfalse;
03322 }
03323
03324