Quake II RTX doxygen  1.0 dev
main.c
Go to the documentation of this file.
1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3 Copyright (C) 2019, NVIDIA CORPORATION. All rights reserved.
4 
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 // cl_main.c -- client main loop
20 
21 #include "client.h"
22 
23 cvar_t *rcon_address;
24 
25 cvar_t *cl_noskins;
26 cvar_t *cl_footsteps;
27 cvar_t *cl_timeout;
28 cvar_t *cl_predict;
29 cvar_t *cl_gun;
30 cvar_t *cl_gunalpha;
31 cvar_t *cl_maxfps;
32 cvar_t *cl_async;
33 cvar_t *r_maxfps;
34 cvar_t *cl_autopause;
35 
36 cvar_t *cl_kickangles;
37 cvar_t *cl_rollhack;
38 cvar_t *cl_noglow;
39 cvar_t *cl_nolerp;
40 
41 #ifdef _DEBUG
42 cvar_t *cl_shownet;
43 cvar_t *cl_showmiss;
44 cvar_t *cl_showclamp;
45 #endif
46 
50 
54 cvar_t *cl_chat_sound;
58 
62 
63 cvar_t *cl_gibs;
64 #if USE_FPS
65 cvar_t *cl_updaterate;
66 #endif
67 
68 cvar_t *cl_protocol;
69 
70 cvar_t *gender_auto;
71 
72 cvar_t *cl_vwep;
73 
74 cvar_t *cl_cinematics;
75 
76 //
77 // userinfo
78 //
79 cvar_t *info_password;
81 cvar_t *info_name;
82 cvar_t *info_skin;
83 cvar_t *info_rate;
84 cvar_t *info_fov;
85 cvar_t *info_msg;
86 cvar_t *info_hand;
87 cvar_t *info_gender;
88 cvar_t *info_uf;
89 
90 #if USE_REF == REF_GL
91 extern cvar_t *gl_modulate_world;
92 extern cvar_t *gl_modulate_entities;
93 extern cvar_t *gl_brightness;
94 #endif
95 
96 extern cvar_t *fs_shareware;
97 
100 
101 centity_t cl_entities[MAX_EDICTS];
102 
103 // used for executing stringcmds
104 cmdbuf_t cl_cmdbuf;
105 char cl_cmdbuf_text[MAX_STRING_CHARS];
106 
107 //======================================================================
108 
109 typedef enum {
115 } requestType_t;
116 
117 typedef struct {
119  netadr_t adr;
120  unsigned time;
121 } request_t;
122 
123 #define MAX_REQUESTS 64
124 #define REQUEST_MASK (MAX_REQUESTS - 1)
125 
127 static unsigned nextRequest;
128 
129 static request_t *CL_AddRequest(const netadr_t *adr, requestType_t type)
130 {
131  request_t *r;
132 
134  r->adr = *adr;
135  r->type = type;
136  r->time = cls.realtime;
137 
138  return r;
139 }
140 
142 {
143  request_t *r;
144  int i, count;
145 
146  count = MAX_REQUESTS;
147  if (count > nextRequest)
148  count = nextRequest;
149 
150  // find the most recent request sent to this address
151  for (i = 0; i < count; i++) {
152  r = &clientRequests[(nextRequest - i - 1) & REQUEST_MASK];
153  if (!r->type) {
154  continue;
155  }
156  if (r->adr.type == NA_BROADCAST) {
157  if (cls.realtime - r->time > 3000) {
158  continue;
159  }
160  if (!NET_IsLanAddress(&net_from)) {
161  continue;
162  }
163  } else {
164  if (cls.realtime - r->time > 6000) {
165  break;
166  }
167  if (!NET_IsEqualBaseAdr(&net_from, &r->adr)) {
168  continue;
169  }
170  }
171 
172  return r;
173  }
174 
175  return NULL;
176 }
177 
178 //======================================================================
179 
180 static void CL_UpdateGunSetting(void)
181 {
182  int nogun;
183 
184  if (!cls.netchan) {
185  return;
186  }
187  if (cls.serverProtocol < PROTOCOL_VERSION_R1Q2) {
188  return;
189  }
190 
191  if (cl_player_model->integer == CL_PLAYER_MODEL_DISABLED || info_hand->integer == 2) {
192  nogun = 1;
193  } else {
194  nogun = 0;
195  }
196 
197  MSG_WriteByte(clc_setting);
198  MSG_WriteShort(CLS_NOGUN);
199  MSG_WriteShort(nogun);
200  MSG_FlushTo(&cls.netchan->message);
201 }
202 
203 static void CL_UpdateGibSetting(void)
204 {
205  if (!cls.netchan) {
206  return;
207  }
208  if (cls.serverProtocol != PROTOCOL_VERSION_Q2PRO) {
209  return;
210  }
211 
212  MSG_WriteByte(clc_setting);
213  MSG_WriteShort(CLS_NOGIBS);
214  MSG_WriteShort(!cl_gibs->integer);
215  MSG_FlushTo(&cls.netchan->message);
216 }
217 
218 static void CL_UpdateFootstepsSetting(void)
219 {
220  if (!cls.netchan) {
221  return;
222  }
223  if (cls.serverProtocol != PROTOCOL_VERSION_Q2PRO) {
224  return;
225  }
226 
227  MSG_WriteByte(clc_setting);
228  MSG_WriteShort(CLS_NOFOOTSTEPS);
229  MSG_WriteShort(!cl_footsteps->integer);
230  MSG_FlushTo(&cls.netchan->message);
231 }
232 
233 static void CL_UpdatePredictSetting(void)
234 {
235  if (!cls.netchan) {
236  return;
237  }
238  if (cls.serverProtocol != PROTOCOL_VERSION_Q2PRO) {
239  return;
240  }
241 
242  MSG_WriteByte(clc_setting);
243  MSG_WriteShort(CLS_NOPREDICT);
244  MSG_WriteShort(!cl_predict->integer);
245  MSG_FlushTo(&cls.netchan->message);
246 }
247 
248 #if USE_FPS
249 static void CL_UpdateRateSetting(void)
250 {
251  if (!cls.netchan) {
252  return;
253  }
254  if (cls.serverProtocol != PROTOCOL_VERSION_Q2PRO) {
255  return;
256  }
257 
258  MSG_WriteByte(clc_setting);
259  MSG_WriteShort(CLS_FPS);
260  MSG_WriteShort(cl_updaterate->integer);
261  MSG_FlushTo(&cls.netchan->message);
262 }
263 #endif
264 
266 {
267  int rec;
268 
269  if (!cls.netchan) {
270  return;
271  }
272  if (cls.serverProtocol < PROTOCOL_VERSION_R1Q2) {
273  return;
274  }
275 
276  if (cls.demo.recording) {
277  rec = 1;
278  } else {
279  rec = 0;
280  }
281 
282 #if USE_CLIENT_GTV
283  if (cls.gtv.state == ca_active) {
284  rec |= 1;
285  }
286 #endif
287 
288  MSG_WriteByte(clc_setting);
289  MSG_WriteShort(CLS_RECORDING);
290  MSG_WriteShort(rec);
291  MSG_FlushTo(&cls.netchan->message);
292 }
293 
294 /*
295 ===================
296 CL_ClientCommand
297 ===================
298 */
299 void CL_ClientCommand(const char *string)
300 {
301  if (!cls.netchan) {
302  return;
303  }
304 
305  Com_DDPrintf("%s: %s\n", __func__, string);
306 
307  MSG_WriteByte(clc_stringcmd);
308  MSG_WriteString(string);
309  MSG_FlushTo(&cls.netchan->message);
310 }
311 
312 /*
313 ===================
314 CL_ForwardToServer
315 
316 adds the current command line as a clc_stringcmd to the client message.
317 things like godmode, noclip, etc, are commands directed to the server,
318 so when they are typed in at the console, they will need to be forwarded.
319 ===================
320 */
321 qboolean CL_ForwardToServer(void)
322 {
323  char *cmd;
324 
325  cmd = Cmd_Argv(0);
326  if (cls.state != ca_active || *cmd == '-' || *cmd == '+') {
327  return qfalse;
328  }
329 
331  return qtrue;
332 }
333 
334 /*
335 ==================
336 CL_ForwardToServer_f
337 ==================
338 */
339 static void CL_ForwardToServer_f(void)
340 {
341  if (cls.state < ca_connected) {
342  Com_Printf("Can't \"%s\", not connected\n", Cmd_Argv(0));
343  return;
344  }
345 
346  if (cls.demo.playback) {
347  return;
348  }
349 
350  // don't forward the first argument
351  if (Cmd_Argc() > 1) {
353  }
354 }
355 
356 /*
357 ==================
358 CL_Pause_f
359 ==================
360 */
361 static void CL_Pause_f(void)
362 {
363 #if USE_MVD_CLIENT
364  if (sv_running->integer == ss_broadcast) {
365  Cbuf_InsertText(&cmd_buffer, "mvdpause @@\n");
366  return;
367  }
368 #endif
369 
370  // activate manual pause
371  if (cl_paused->integer == 2) {
372  Cvar_Set("cl_paused", "0");
373  } else {
374  Cvar_Set("cl_paused", "2");
375  }
376 
378 }
379 
380 /*
381 =================
382 CL_CheckForResend
383 
384 Resend a connect message if the last one has timed out
385 =================
386 */
388 {
389  char tail[MAX_QPATH];
390  char userinfo[MAX_INFO_STRING];
391  int maxmsglen;
392 
393  if (cls.demo.playback) {
394  return;
395  }
396 
397  // if the local server is running and we aren't
398  // then connect
399  if (cls.state < ca_connecting && sv_running->integer > ss_loading) {
400  strcpy(cls.servername, "localhost");
401  cls.serverAddress.type = NA_LOOPBACK;
402  cls.serverProtocol = cl_protocol->integer;
403  if (cls.serverProtocol < PROTOCOL_VERSION_DEFAULT ||
404  cls.serverProtocol > PROTOCOL_VERSION_Q2PRO) {
405  cls.serverProtocol = PROTOCOL_VERSION_Q2PRO;
406  }
407 
408  // we don't need a challenge on the localhost
411  cls.connect_count = 0;
412 
413  cls.passive = qfalse;
414 
415  Con_Popup(qtrue);
416  UI_OpenMenu(UIMENU_NONE);
417  }
418 
419  // resend if we haven't gotten a reply yet
421  return;
422  }
423 
425  return;
426  }
427 
428  cls.connect_time = cls.realtime; // for retransmit requests
429  cls.connect_count++;
430 
431  if (cls.state == ca_challenging) {
432  Com_Printf("Requesting challenge... %i\n", cls.connect_count);
433  OOB_PRINT(NS_CLIENT, &cls.serverAddress, "getchallenge\n");
434  return;
435  }
436 
437  //
438  // We have gotten a challenge from the server, so try and connect.
439  //
440  Com_Printf("Requesting connection... %i\n", cls.connect_count);
441 
443 
444  // use maximum allowed msglen for loopback
445  maxmsglen = net_maxmsglen->integer;
446  if (NET_IsLocalAddress(&cls.serverAddress)) {
447  maxmsglen = MAX_PACKETLEN_WRITABLE;
448  }
449 
450  // add protocol dependent stuff
451  switch (cls.serverProtocol) {
452  case PROTOCOL_VERSION_R1Q2:
453  Q_snprintf(tail, sizeof(tail), " %d %d",
454  maxmsglen, PROTOCOL_VERSION_R1Q2_CURRENT);
455  cls.quakePort = net_qport->integer & 0xff;
456  break;
457  case PROTOCOL_VERSION_Q2PRO:
458  Q_snprintf(tail, sizeof(tail), " %d %d %d %d",
459  maxmsglen, net_chantype->integer, USE_ZLIB,
460  PROTOCOL_VERSION_Q2PRO_CURRENT);
461  cls.quakePort = net_qport->integer & 0xff;
462  break;
463  default:
464  tail[0] = 0;
465  cls.quakePort = net_qport->integer;
466  break;
467  }
468 
469  Cvar_BitInfo(userinfo, CVAR_USERINFO);
470  Netchan_OutOfBand(NS_CLIENT, &cls.serverAddress,
471  "connect %i %i %i \"%s\"%s\n", cls.serverProtocol, cls.quakePort,
472  cls.challenge, userinfo, tail);
473 }
474 
475 static void CL_RecentIP_g(genctx_t *ctx)
476 {
477  netadr_t *a;
478  int i, j;
479 
481  if (j < 0) {
482  j = 0;
483  }
484  for (i = cls.recent_head - 1; i >= j; i--) {
485  a = &cls.recent_addr[i & RECENT_MASK];
486  if (a->type) {
488  }
489  }
490 }
491 
492 static void CL_Connect_c(genctx_t *ctx, int argnum)
493 {
494  if (argnum == 1) {
495  CL_RecentIP_g(ctx);
496  Com_Address_g(ctx);
497  } else if (argnum == 2) {
498  if (!ctx->partial[0] || (ctx->partial[0] == '3' && !ctx->partial[1])) {
499  Prompt_AddMatch(ctx, "34");
500  Prompt_AddMatch(ctx, "35");
501  Prompt_AddMatch(ctx, "36");
502  }
503  }
504 }
505 
506 /*
507 ================
508 CL_Connect_f
509 
510 ================
511 */
512 static void CL_Connect_f(void)
513 {
514  char *server, *p;
515  netadr_t address;
516  int protocol;
517  int argc = Cmd_Argc();
518 
519  if (fs_shareware->integer)
520  {
521  Com_EPrintf("Multiplayer is not supported in the shareware version of the game.\n");
522  return;
523  }
524 
525  if (argc < 2) {
526 usage:
527  Com_Printf("Usage: %s <server> [34|35|36]\n", Cmd_Argv(0));
528  return;
529  }
530 
531  if (argc > 2) {
532  protocol = atoi(Cmd_Argv(2));
533  if (protocol < PROTOCOL_VERSION_DEFAULT ||
534  protocol > PROTOCOL_VERSION_Q2PRO) {
535  goto usage;
536  }
537  } else {
538  protocol = cl_protocol->integer;
539  if (!protocol) {
540  protocol = PROTOCOL_VERSION_Q2PRO;
541  }
542  }
543 
544  server = Cmd_Argv(1);
545 
546  // support quake2://<address>[/] scheme
547  if (!Q_strncasecmp(server, "quake2://", 9)) {
548  server += 9;
549  if ((p = strchr(server, '/')) != NULL) {
550  *p = 0;
551  }
552  }
553 
554  if (!NET_StringToAdr(server, &address, PORT_SERVER)) {
555  Com_Printf("Bad server address\n");
556  return;
557  }
558 
559  // copy early to avoid potential cmd_argv[1] clobbering
560  Q_strlcpy(cls.servername, server, sizeof(cls.servername));
561 
562  // if running a local server, kill it and reissue
563  SV_Shutdown("Server was killed.\n", ERR_DISCONNECT);
564 
565  NET_Config(NET_CLIENT);
566 
567  CL_Disconnect(ERR_RECONNECT);
568 
569  cls.serverAddress = address;
570  cls.serverProtocol = protocol;
571  cls.protocolVersion = 0;
572  cls.passive = qfalse;
575  cls.connect_count = 0;
576 
577  Con_Popup(qtrue);
578 
580 
581  Cvar_Set("timedemo", "0");
582 }
583 
584 static void CL_FollowIP_f(void)
585 {
586  netadr_t *a;
587  int i, j;
588 
589  if (Cmd_Argc() > 1) {
590  // optional second argument references less recent address
591  j = atoi(Cmd_Argv(1)) + 1;
592  clamp(j, 1, RECENT_ADDR);
593  } else {
594  j = 1;
595  }
596 
597  i = cls.recent_head - j;
598  if (i < 0) {
599  Com_Printf("No IP address to follow.\n");
600  return;
601  }
602 
603  a = &cls.recent_addr[i & RECENT_MASK];
604  if (a->type) {
605  char *s = NET_AdrToString(a);
606  Com_Printf("Following %s...\n", s);
607  Cbuf_InsertText(cmd_current, va("connect %s\n", s));
608  }
609 }
610 
611 static void CL_PassiveConnect_f(void)
612 {
613  netadr_t address;
614 
615  if (cls.passive) {
616  cls.passive = qfalse;
617  Com_Printf("No longer listening for passive connections.\n");
618  return;
619  }
620 
621  // if running a local server, kill it and reissue
622  SV_Shutdown("Server was killed.\n", ERR_DISCONNECT);
623 
624  NET_Config(NET_CLIENT);
625 
626  CL_Disconnect(ERR_RECONNECT);
627 
628  if (!NET_GetAddress(NS_CLIENT, &address)) {
629  return;
630  }
631 
632  cls.passive = qtrue;
633  Com_Printf("Listening for passive connections at %s.\n",
634  NET_AdrToString(&address));
635 }
636 
637 void CL_SendRcon(const netadr_t *adr, const char *pass, const char *cmd)
638 {
639  NET_Config(NET_CLIENT);
640 
641  CL_AddRequest(adr, REQ_RCON);
642 
643  Netchan_OutOfBand(NS_CLIENT, adr, "rcon \"%s\" %s", pass, cmd);
644 }
645 
646 
647 /*
648 =====================
649 CL_Rcon_f
650 
651  Send the rest of the command line over as
652  an unconnected command.
653 =====================
654 */
655 static void CL_Rcon_f(void)
656 {
657  netadr_t address;
658 
659  if (Cmd_Argc() < 2) {
660  Com_Printf("Usage: %s <command>\n", Cmd_Argv(0));
661  return;
662  }
663 
664  if (!rcon_password->string[0]) {
665  Com_Printf("You must set 'rcon_password' before "
666  "issuing an rcon command.\n");
667  return;
668  }
669 
670  if (!cls.netchan) {
671  if (!rcon_address->string[0]) {
672  Com_Printf("You must either be connected, "
673  "or set the 'rcon_address' cvar "
674  "to issue rcon commands.\n");
675  return;
676  }
677  if (!NET_StringToAdr(rcon_address->string, &address, PORT_SERVER)) {
678  Com_Printf("Bad address: %s\n", rcon_address->string);
679  return;
680  }
681  } else {
682  address = cls.netchan->remote_address;
683  }
684 
685  CL_SendRcon(&address, rcon_password->string, Cmd_RawArgs());
686 }
687 
688 static void CL_Rcon_c(genctx_t *ctx, int argnum)
689 {
690  Com_Generic_c(ctx, argnum - 1);
691 }
692 
693 /*
694 =====================
695 CL_ClearState
696 
697 =====================
698 */
699 void CL_ClearState(void)
700 {
701  S_StopAllSounds();
702  CL_ClearEffects();
703 #if USE_LIGHTSTYLES
704  CL_ClearLightStyles();
705 #endif
706  CL_ClearTEnts();
708 
709  // wipe the entire cl structure
710  BSP_Free(cl.bsp);
711  memset(&cl, 0, sizeof(cl));
712  memset(&cl_entities, 0, sizeof(cl_entities));
713 
714  if (cls.state > ca_connected) {
718  }
719 
720  // unprotect game cvar
721  fs_game->flags &= ~CVAR_ROM;
722 
723 #if USE_REF == REF_GL
724  // unprotect our custom modulate cvars
725  if(gl_modulate_world) gl_modulate_world->flags &= ~CVAR_CHEAT;
726  if(gl_modulate_entities) gl_modulate_entities->flags &= ~CVAR_CHEAT;
727  if(gl_brightness) gl_brightness->flags &= ~CVAR_CHEAT;
728 #endif
729 }
730 
731 /*
732 =====================
733 CL_Disconnect
734 
735 Goes from a connected state to full screen console state
736 Sends a disconnect message to the server
737 This is also called on Com_Error, so it shouldn't cause any errors
738 =====================
739 */
740 void CL_Disconnect(error_type_t type)
741 {
742  if (!cls.state) {
743  return;
744  }
745 
746  SCR_EndLoadingPlaque(); // get rid of loading plaque
747 
748  SCR_ClearChatHUD_f(); // clear chat HUD on server change
749 
751  EXEC_TRIGGER(cl_disconnectcmd);
752  }
753 
754 #if 0
755  if (cls.ref_initialized) {
756  R_CinematicSetPalette(NULL);
757  }
758 #endif
759 
760  //cls.connect_time = 0;
761  //cls.connect_count = 0;
762  cls.passive = qfalse;
763 #if USE_ICMP
764  cls.errorReceived = qfalse;
765 #endif
766 
767  if (cls.netchan) {
768  // send a disconnect message to the server
769  MSG_WriteByte(clc_stringcmd);
770  MSG_WriteData("disconnect", 11);
771 
772  cls.netchan->Transmit(cls.netchan, msg_write.cursize, msg_write.data, 3);
773 
775 
777  cls.netchan = NULL;
778  }
779 
780  // stop playback and/or recording
781  CL_CleanupDemos();
782 
783  // stop download
785 
786  CL_ClearState();
787 
788  CL_GTV_Suspend();
789 
792 
793  if (type == ERR_DISCONNECT) {
794  UI_OpenMenu(UIMENU_DEFAULT);
795  } else {
796  UI_OpenMenu(UIMENU_NONE);
797  }
798 
800 
802 }
803 
804 /*
805 ================
806 CL_Disconnect_f
807 ================
808 */
809 static void CL_Disconnect_f(void)
810 {
811  if (cls.state > ca_disconnected) {
812  Com_Error(ERR_DISCONNECT, "Disconnected from server");
813  }
814 }
815 
816 static void CL_ServerStatus_c(genctx_t *ctx, int argnum)
817 {
818  if (argnum == 1) {
819  CL_RecentIP_g(ctx);
820  Com_Address_g(ctx);
821  }
822 }
823 
824 /*
825 ================
826 CL_ServerStatus_f
827 ================
828 */
829 static void CL_ServerStatus_f(void)
830 {
831  char *s;
832  netadr_t adr;
833  neterr_t ret;
834 
835  if (Cmd_Argc() < 2) {
836  if (!cls.netchan) {
837  Com_Printf("Usage: %s [address]\n", Cmd_Argv(0));
838  return;
839  }
840  adr = cls.netchan->remote_address;
841  } else {
842  s = Cmd_Argv(1);
843  if (!NET_StringToAdr(s, &adr, PORT_SERVER)) {
844  Com_Printf("Bad address: %s\n", s);
845  return;
846  }
847  }
848 
850 
851  NET_Config(NET_CLIENT);
852 
853  ret = OOB_PRINT(NS_CLIENT, &adr, "status");
854  if (ret == NET_ERROR) {
855  Com_Printf("%s to %s\n", NET_ErrorString(), NET_AdrToString(&adr));
856  }
857 }
858 
859 /*
860 ====================
861 SortPlayers
862 ====================
863 */
864 static int SortPlayers(const void *v1, const void *v2)
865 {
866  const playerStatus_t *p1 = (const playerStatus_t *)v1;
867  const playerStatus_t *p2 = (const playerStatus_t *)v2;
868 
869  return p2->score - p1->score;
870 }
871 
872 /*
873 ====================
874 CL_ParseStatusResponse
875 ====================
876 */
877 static void CL_ParseStatusResponse(serverStatus_t *status, const char *string)
878 {
879  playerStatus_t *player;
880  const char *s;
881  size_t infolen;
882 
883  // parse '\n' terminated infostring
884  s = Q_strchrnul(string, '\n');
885 
886  // due to off-by-one error in the original version of Info_SetValueForKey,
887  // some servers produce infostrings up to 512 characters long. work this
888  // bug around by cutting off the last character(s).
889  infolen = s - string;
890  if (infolen >= MAX_INFO_STRING)
891  infolen = MAX_INFO_STRING - 1;
892 
893  // copy infostring off
894  memcpy(status->infostring, string, infolen);
895  status->infostring[infolen] = 0;
896 
897  if (!Info_Validate(status->infostring))
898  strcpy(status->infostring, "\\hostname\\badinfo");
899 
900  // parse optional player list
901  status->numPlayers = 0;
902  while (status->numPlayers < MAX_STATUS_PLAYERS) {
903  player = &status->players[status->numPlayers];
904  player->score = atoi(COM_Parse(&s));
905  player->ping = atoi(COM_Parse(&s));
906  Q_strlcpy(player->name, COM_Parse(&s), sizeof(player->name));
907  if (!s)
908  break;
909  status->numPlayers++;
910  }
911 
912  // sort players by frags
913  qsort(status->players, status->numPlayers,
914  sizeof(status->players[0]), SortPlayers);
915 }
916 
917 static void CL_DumpStatusResponse(const serverStatus_t *status)
918 {
919  int i;
920 
921  Com_Printf("Status response from %s\n\n", NET_AdrToString(&net_from));
922 
923  Info_Print(status->infostring);
924 
925  Com_Printf("\nNum Score Ping Name\n");
926  for (i = 0; i < status->numPlayers; i++) {
927  Com_Printf("%3i %5i %4i %s\n", i + 1,
928  status->players[i].score,
929  status->players[i].ping,
930  status->players[i].name);
931  }
932 }
933 
934 /*
935 ====================
936 CL_ParsePrintMessage
937 ====================
938 */
939 static void CL_ParsePrintMessage(void)
940 {
941  char string[MAX_NET_STRING];
942  serverStatus_t status;
943  request_t *r;
944 
945  MSG_ReadString(string, sizeof(string));
946 
947  r = CL_FindRequest();
948  if (r) {
949  switch (r->type) {
950  case REQ_STATUS_CL:
951  CL_ParseStatusResponse(&status, string);
952  CL_DumpStatusResponse(&status);
953  break;
954 #if USE_UI
955  case REQ_STATUS_UI:
956  CL_ParseStatusResponse(&status, string);
957  UI_StatusEvent(&status);
958  break;
959 #endif
960  case REQ_RCON:
961  Com_Printf("%s", string);
962  return; // rcon may come in multiple packets
963 
964  default:
965  return;
966  }
967 
968  if (r->adr.type != NA_BROADCAST)
969  r->type = REQ_FREE;
970  return;
971  }
972 
973  // finally, check is this is response from the server we are connecting to
974  // and if so, start channenge cycle again
975  if ((cls.state == ca_challenging || cls.state == ca_connecting) &&
976  NET_IsEqualBaseAdr(&net_from, &cls.serverAddress)) {
977  Com_Printf("%s", string);
979  //cls.connect_count = 0;
980  return;
981  }
982 
983  Com_DPrintf("%s: dropped unrequested packet\n", __func__);
984 }
985 
986 /*
987 =================
988 CL_ParseInfoMessage
989 
990 Handle a reply from a ping
991 =================
992 */
993 static void CL_ParseInfoMessage(void)
994 {
995  char string[MAX_QPATH];
996  request_t *r;
997 
998  r = CL_FindRequest();
999  if (!r)
1000  return;
1001  if (r->type != REQ_INFO)
1002  return;
1003 
1004  MSG_ReadString(string, sizeof(string));
1005  Com_Printf("%s", string);
1006  if (r->adr.type != NA_BROADCAST)
1007  r->type = REQ_FREE;
1008 }
1009 
1010 /*
1011 ====================
1012 CL_Packet_f
1013 
1014 packet <destination> <contents>
1015 
1016 Contents allows \n escape character
1017 ====================
1018 */
1019 /*
1020 void CL_Packet_f (void)
1021 {
1022  char send[2048];
1023  int i, l;
1024  char *in, *out;
1025  netadr_t adr;
1026 
1027  if (Cmd_Argc() != 3)
1028  {
1029  Com_Printf ("packet <destination> <contents>\n");
1030  return;
1031  }
1032 
1033  if (!NET_StringToAdr (Cmd_Argv(1), &adr))
1034  {
1035  Com_Printf ("Bad address\n");
1036  return;
1037  }
1038  if (!adr.port)
1039  adr.port = BigShort (PORT_SERVER);
1040 
1041  in = Cmd_Argv(2);
1042  out = send+4;
1043  send[0] = send[1] = send[2] = send[3] = (char)0xff;
1044 
1045  l = strlen (in);
1046  for (i=0; i<l; i++)
1047  {
1048  if (in[i] == '\\' && in[i+1] == 'n')
1049  {
1050  *out++ = '\n';
1051  i++;
1052  }
1053  else
1054  *out++ = in[i];
1055  }
1056  *out = 0;
1057 
1058  NET_SendPacket (NS_CLIENT, out-send, send, &adr);
1059 }
1060 */
1061 
1062 /*
1063 =================
1064 CL_Changing_f
1065 
1066 Just sent as a hint to the client that they should
1067 drop to full console
1068 =================
1069 */
1070 static void CL_Changing_f(void)
1071 {
1072  int i, j;
1073  char *s;
1074 
1075  if (cls.state < ca_connected) {
1076  return;
1077  }
1078 
1079  if (cls.demo.recording)
1080  CL_Stop_f();
1081 
1082  S_StopAllSounds();
1083 
1084  Com_Printf("Changing map...\n");
1085 
1086  if (!cls.demo.playback) {
1087  EXEC_TRIGGER(cl_changemapcmd);
1088  Cmd_ExecTrigger("#cl_changelevel");
1089  }
1090 
1092 
1093  cls.state = ca_connected; // not active anymore, but not disconnected
1094  cl.mapname[0] = 0;
1095  cl.configstrings[CS_NAME][0] = 0;
1096 
1097  CL_CheckForPause();
1098 
1100 
1101  // parse additional parameters
1102  j = Cmd_Argc();
1103  for (i = 1; i < j; i++) {
1104  s = Cmd_Argv(i);
1105  if (!strncmp(s, "map=", 4)) {
1106  Q_strlcpy(cl.mapname, s + 4, sizeof(cl.mapname));
1107  }
1108  }
1109 
1110  SCR_UpdateScreen();
1111 }
1112 
1113 
1114 /*
1115 =================
1116 CL_Reconnect_f
1117 
1118 The server is changing levels
1119 =================
1120 */
1121 static void CL_Reconnect_f(void)
1122 {
1123  if (cls.state >= ca_precached) {
1124  CL_Disconnect(ERR_RECONNECT);
1125  }
1126 
1127  if (cls.state >= ca_connected) {
1129 
1130  if (cls.demo.playback) {
1131  return;
1132  }
1133  if (cls.download.file) {
1134  return; // if we are downloading, we don't change!
1135  }
1136 
1137  Com_Printf("Reconnecting...\n");
1138 
1139  CL_ClientCommand("new");
1140  return;
1141  }
1142 
1143  // issued manually at console
1144  if (cls.serverAddress.type == NA_UNSPECIFIED) {
1145  Com_Printf("No server to reconnect to.\n");
1146  return;
1147  }
1148  if (cls.serverAddress.type == NA_LOOPBACK) {
1149  Com_Printf("Can not reconnect to loopback.\n");
1150  return;
1151  }
1152 
1153  Com_Printf("Reconnecting...\n");
1154 
1157  cls.connect_count = 0;
1158 
1159  SCR_UpdateScreen();
1160 }
1161 
1162 #ifdef USE_UI
1163 /*
1164 =================
1165 CL_SendStatusRequest
1166 =================
1167 */
1168 void CL_SendStatusRequest(const netadr_t *address)
1169 {
1170  NET_Config(NET_CLIENT);
1171 
1172  CL_AddRequest(address, REQ_STATUS_UI);
1173 
1174  OOB_PRINT(NS_CLIENT, address, "status");
1175 }
1176 #endif
1177 
1178 /*
1179 =================
1180 CL_PingServers_f
1181 =================
1182 */
1183 static void CL_PingServers_f(void)
1184 {
1185  netadr_t address;
1186  cvar_t *var;
1187  int i;
1188 
1189  NET_Config(NET_CLIENT);
1190 
1191  // send a broadcast packet
1192  memset(&address, 0, sizeof(address));
1193  address.type = NA_BROADCAST;
1194  address.port = BigShort(PORT_SERVER);
1195 
1196  Com_DPrintf("Pinging broadcast...\n");
1197  CL_AddRequest(&address, REQ_INFO);
1198 
1199  OOB_PRINT(NS_CLIENT, &address, "info 34");
1200 
1201  // send a packet to each address book entry
1202  for (i = 0; i < 64; i++) {
1203  var = Cvar_FindVar(va("adr%i", i));
1204  if (!var)
1205  break;
1206 
1207  if (!var->string[0])
1208  continue;
1209 
1210  if (!NET_StringToAdr(var->string, &address, PORT_SERVER)) {
1211  Com_Printf("Bad address: %s\n", var->string);
1212  continue;
1213  }
1214 
1215  Com_DPrintf("Pinging %s...\n", var->string);
1216  CL_AddRequest(&address, REQ_INFO);
1217 
1218  OOB_PRINT(NS_CLIENT, &address, "info 34");
1219  }
1220 }
1221 
1222 /*
1223 =================
1224 CL_Skins_f
1225 
1226 Load or download any custom player skins and models
1227 =================
1228 */
1229 static void CL_Skins_f(void)
1230 {
1231  int i;
1232  char *s;
1233  clientinfo_t *ci;
1234 
1235  if (cls.state < ca_loading) {
1236  Com_Printf("Must be in a level to load skins.\n");
1237  return;
1238  }
1239 
1241 
1242  for (i = 0; i < MAX_CLIENTS; i++) {
1243  s = cl.configstrings[CS_PLAYERSKINS + i];
1244  if (!s[0])
1245  continue;
1246  ci = &cl.clientinfo[i];
1247  CL_LoadClientinfo(ci, s);
1248  if (!ci->model_name[0] || !ci->skin_name[0])
1249  ci = &cl.baseclientinfo;
1250  Com_Printf("client %d: %s --> %s/%s\n", i, s,
1251  ci->model_name, ci->skin_name);
1252  SCR_UpdateScreen();
1253  }
1254 }
1255 
1256 static void cl_noskins_changed(cvar_t *self)
1257 {
1258  int i;
1259  char *s;
1260  clientinfo_t *ci;
1261 
1262  if (cls.state < ca_loading) {
1263  return;
1264  }
1265 
1266  for (i = 0; i < MAX_CLIENTS; i++) {
1267  s = cl.configstrings[CS_PLAYERSKINS + i];
1268  if (!s[0])
1269  continue;
1270  ci = &cl.clientinfo[i];
1271  CL_LoadClientinfo(ci, s);
1272  }
1273 }
1274 
1275 static void cl_vwep_changed(cvar_t *self)
1276 {
1277  if (cls.state < ca_loading) {
1278  return;
1279  }
1280 
1282  cl_noskins_changed(self);
1283 }
1284 
1285 static void CL_Name_g(genctx_t *ctx)
1286 {
1287  int i;
1288  clientinfo_t *ci;
1289  char buffer[MAX_CLIENT_NAME];
1290 
1291  if (cls.state < ca_loading) {
1292  return;
1293  }
1294 
1295  for (i = 0; i < MAX_CLIENTS; i++) {
1296  ci = &cl.clientinfo[i];
1297  if (!ci->name[0]) {
1298  continue;
1299  }
1300  Q_strlcpy(buffer, ci->name, sizeof(buffer));
1301  if (COM_strclr(buffer) && !Prompt_AddMatch(ctx, buffer)) {
1302  break;
1303  }
1304  }
1305 }
1306 
1307 
1308 /*
1309 =================
1310 CL_ConnectionlessPacket
1311 
1312 Responses to broadcasts, etc
1313 =================
1314 */
1315 static void CL_ConnectionlessPacket(void)
1316 {
1317  char string[MAX_STRING_CHARS];
1318  char *s, *c;
1319  int i, j, k;
1320  size_t len;
1321 
1322  MSG_BeginReading();
1323  MSG_ReadLong(); // skip the -1
1324 
1325  len = MSG_ReadStringLine(string, sizeof(string));
1326  if (len >= sizeof(string)) {
1327  Com_DPrintf("Oversize message received. Ignored.\n");
1328  return;
1329  }
1330 
1331  Cmd_TokenizeString(string, qfalse);
1332 
1333  c = Cmd_Argv(0);
1334 
1335  Com_DPrintf("%s: %s\n", NET_AdrToString(&net_from), string);
1336 
1337  // challenge from the server we are connecting to
1338  if (!strcmp(c, "challenge")) {
1339  int mask = 0;
1340 
1341  if (cls.state < ca_challenging) {
1342  Com_DPrintf("Challenge received while not connecting. Ignored.\n");
1343  return;
1344  }
1345  if (!NET_IsEqualBaseAdr(&net_from, &cls.serverAddress)) {
1346  Com_DPrintf("Challenge from different address. Ignored.\n");
1347  return;
1348  }
1349  if (cls.state > ca_challenging) {
1350  Com_DPrintf("Dup challenge received. Ignored.\n");
1351  return;
1352  }
1353 
1354  cls.challenge = atoi(Cmd_Argv(1));
1356  cls.connect_time -= CONNECT_INSTANT; // fire immediately
1357  //cls.connect_count = 0;
1358 
1359  // parse additional parameters
1360  j = Cmd_Argc();
1361  for (i = 2; i < j; i++) {
1362  s = Cmd_Argv(i);
1363  if (!strncmp(s, "p=", 2)) {
1364  s += 2;
1365  while (*s) {
1366  k = strtoul(s, &s, 10);
1367  if (k == PROTOCOL_VERSION_R1Q2) {
1368  mask |= 1;
1369  } else if (k == PROTOCOL_VERSION_Q2PRO) {
1370  mask |= 2;
1371  }
1372  s = strchr(s, ',');
1373  if (s == NULL) {
1374  break;
1375  }
1376  s++;
1377  }
1378  }
1379  }
1380 
1381  // choose supported protocol
1382  switch (cls.serverProtocol) {
1383  case PROTOCOL_VERSION_Q2PRO:
1384  if (mask & 2) {
1385  break;
1386  }
1387  cls.serverProtocol = PROTOCOL_VERSION_R1Q2;
1388  case PROTOCOL_VERSION_R1Q2:
1389  if (mask & 1) {
1390  break;
1391  }
1392  default:
1393  cls.serverProtocol = PROTOCOL_VERSION_DEFAULT;
1394  break;
1395  }
1396  Com_DPrintf("Selected protocol %d\n", cls.serverProtocol);
1397 
1399  return;
1400  }
1401 
1402  // server connection
1403  if (!strcmp(c, "client_connect")) {
1404  netchan_type_t type;
1405  int anticheat = 0;
1406  char mapname[MAX_QPATH];
1407  qboolean got_server = qfalse;
1408 
1409  if (cls.state < ca_connecting) {
1410  Com_DPrintf("Connect received while not connecting. Ignored.\n");
1411  return;
1412  }
1413  if (!NET_IsEqualBaseAdr(&net_from, &cls.serverAddress)) {
1414  Com_DPrintf("Connect from different address. Ignored.\n");
1415  return;
1416  }
1417  if (cls.state > ca_connecting) {
1418  Com_DPrintf("Dup connect received. Ignored.\n");
1419  return;
1420  }
1421 
1422  if (cls.serverProtocol == PROTOCOL_VERSION_Q2PRO) {
1423  type = NETCHAN_NEW;
1424  } else {
1425  type = NETCHAN_OLD;
1426  }
1427 
1428  mapname[0] = 0;
1429 
1430  // parse additional parameters
1431  j = Cmd_Argc();
1432  for (i = 1; i < j; i++) {
1433  s = Cmd_Argv(i);
1434  if (!strncmp(s, "ac=", 3)) {
1435  s += 3;
1436  if (*s) {
1437  anticheat = atoi(s);
1438  }
1439  } else if (!strncmp(s, "nc=", 3)) {
1440  s += 3;
1441  if (*s) {
1442  type = atoi(s);
1443  if (type != NETCHAN_OLD && type != NETCHAN_NEW) {
1444  Com_Error(ERR_DISCONNECT,
1445  "Server returned invalid netchan type");
1446  }
1447  }
1448  } else if (!strncmp(s, "map=", 4)) {
1449  Q_strlcpy(mapname, s + 4, sizeof(mapname));
1450  } else if (!strncmp(s, "dlserver=", 9)) {
1451  if (!got_server) {
1452  HTTP_SetServer(s + 9);
1453  got_server = qtrue;
1454  }
1455  }
1456  }
1457 
1458  if (!got_server) {
1459  HTTP_SetServer(NULL);
1460  }
1461 
1462  Com_Printf("Connected to %s (protocol %d).\n",
1464  if (cls.netchan) {
1465  // this may happen after svc_reconnect
1467  }
1468  cls.netchan = Netchan_Setup(NS_CLIENT, type, &cls.serverAddress,
1469  cls.quakePort, 1024, cls.serverProtocol);
1470 
1471 #if USE_AC_CLIENT
1472  if (anticheat) {
1473  MSG_WriteByte(clc_nop);
1474  MSG_FlushTo(&cls.netchan->message);
1475  cls.netchan->Transmit(cls.netchan, 0, NULL, 3);
1476  S_StopAllSounds();
1477  cls.connect_count = -1;
1478  Com_Printf("Loading anticheat, this may take a few moments...\n");
1479  SCR_UpdateScreen();
1480  if (!Sys_GetAntiCheatAPI()) {
1481  Com_Printf("Trying to connect without anticheat.\n");
1482  } else {
1483  Com_LPrintf(PRINT_NOTICE, "Anticheat loaded successfully.\n");
1484  }
1485  }
1486 #else
1487  if (anticheat >= 2) {
1488  Com_Printf("Anticheat required by server, "
1489  "but no anticheat support linked in.\n");
1490  }
1491 #endif
1492 
1493  CL_ClientCommand("new");
1495  cls.connect_count = 0;
1496  strcpy(cl.mapname, mapname); // for levelshot screen
1497  return;
1498  }
1499 
1500  if (!strcmp(c, "passive_connect")) {
1501  if (!cls.passive) {
1502  Com_DPrintf("Passive connect received while not connecting. Ignored.\n");
1503  return;
1504  }
1505  s = NET_AdrToString(&net_from);
1506  Com_Printf("Received passive connect from %s.\n", s);
1507 
1509  cls.serverProtocol = cl_protocol->integer;
1510  Q_strlcpy(cls.servername, s, sizeof(cls.servername));
1511  cls.passive = qfalse;
1512 
1515  cls.connect_count = 0;
1516 
1518  return;
1519  }
1520 
1521  // print command from somewhere
1522  if (!strcmp(c, "print")) {
1524  return;
1525  }
1526 
1527  // server responding to a status broadcast
1528  if (!strcmp(c, "info")) {
1530  return;
1531  }
1532 
1533  Com_DPrintf("Unknown connectionless packet command.\n");
1534 }
1535 
1536 /*
1537 =================
1538 CL_PacketEvent
1539 =================
1540 */
1541 static void CL_PacketEvent(void)
1542 {
1543  //
1544  // remote command packet
1545  //
1546  if (*(int *)msg_read.data == -1) {
1548  return;
1549  }
1550 
1551  if (cls.state < ca_connected) {
1552  return;
1553  }
1554 
1555  if (!cls.netchan) {
1556  return; // dump it if not connected
1557  }
1558 
1559  if (msg_read.cursize < 8) {
1560  Com_DPrintf("%s: runt packet\n", NET_AdrToString(&net_from));
1561  return;
1562  }
1563 
1564  //
1565  // packet from server
1566  //
1567  if (!NET_IsEqualAdr(&net_from, &cls.netchan->remote_address)) {
1568  Com_DPrintf("%s: sequenced packet without connection\n",
1570  return;
1571  }
1572 
1573  if (!cls.netchan->Process(cls.netchan))
1574  return; // wasn't accepted for some reason
1575 
1576 #if USE_ICMP
1577  cls.errorReceived = qfalse; // don't drop
1578 #endif
1579 
1581 
1582  // if recording demo, write the message out
1583  if (cls.demo.recording && !cls.demo.paused && CL_FRAMESYNC) {
1585  }
1586 
1587  // if running GTV server, transmit to client
1588  CL_GTV_Transmit();
1589 
1590  if (!cls.netchan)
1591  return; // might have disconnected
1592 
1593 #ifdef _DEBUG
1594  CL_AddNetgraph();
1595 #endif
1596 
1597  SCR_LagSample();
1598 }
1599 
1600 #if USE_ICMP
1601 void CL_ErrorEvent(netadr_t *from)
1602 {
1603  UI_ErrorEvent(from);
1604 
1605  //
1606  // error packet from server
1607  //
1608  if (cls.state < ca_connected) {
1609  return;
1610  }
1611  if (!cls.netchan) {
1612  return; // dump it if not connected
1613  }
1614  if (!NET_IsEqualBaseAdr(from, &cls.netchan->remote_address)) {
1615  return;
1616  }
1617  if (from->port && from->port != cls.netchan->remote_address.port) {
1618  return;
1619  }
1620 
1621  cls.errorReceived = qtrue; // drop connection soon
1622 }
1623 #endif
1624 
1625 
1626 //=============================================================================
1627 
1628 /*
1629 ==============
1630 CL_FixUpGender_f
1631 ==============
1632 */
1633 static void CL_FixUpGender(void)
1634 {
1635  char *p;
1636  char sk[MAX_QPATH];
1637 
1638  Q_strlcpy(sk, info_skin->string, sizeof(sk));
1639  if ((p = strchr(sk, '/')) != NULL)
1640  *p = 0;
1641  if (Q_stricmp(sk, "male") == 0 || Q_stricmp(sk, "cyborg") == 0)
1642  Cvar_Set("gender", "male");
1643  else if (Q_stricmp(sk, "female") == 0 || Q_stricmp(sk, "crackhor") == 0)
1644  Cvar_Set("gender", "female");
1645  else
1646  Cvar_Set("gender", "none");
1647  info_gender->modified = qfalse;
1648 }
1649 
1650 void CL_UpdateUserinfo(cvar_t *var, from_t from)
1651 {
1652  int i;
1653 
1654  if (var == info_skin && from > FROM_CONSOLE && gender_auto->integer) {
1655  CL_FixUpGender();
1656  }
1657 
1658  if (!cls.netchan) {
1659  return;
1660  }
1661 
1662  if (cls.serverProtocol != PROTOCOL_VERSION_Q2PRO) {
1663  // transmit at next oportunity
1664  cls.userinfo_modified = MAX_PACKET_USERINFOS;
1665  goto done;
1666  }
1667 
1668  if (cls.userinfo_modified == MAX_PACKET_USERINFOS) {
1669  // can't hold any more
1670  goto done;
1671  }
1672 
1673  // check for the same variable being modified twice
1674  for (i = 0; i < cls.userinfo_modified; i++) {
1675  if (cls.userinfo_updates[i] == var) {
1676  Com_DDPrintf("%s: %u: %s [DUP]\n",
1677  __func__, com_framenum, var->name);
1678  return;
1679  }
1680  }
1681 
1683 
1684 done:
1685  Com_DDPrintf("%s: %u: %s [%d]\n",
1686  __func__, com_framenum, var->name, cls.userinfo_modified);
1687 }
1688 
1689 /*
1690 ==============
1691 CL_Userinfo_f
1692 ==============
1693 */
1694 static void CL_Userinfo_f(void)
1695 {
1696  char userinfo[MAX_INFO_STRING];
1697 
1698  Cvar_BitInfo(userinfo, CVAR_USERINFO);
1699 
1700  Com_Printf("User info settings:\n");
1701  Info_Print(userinfo);
1702 }
1703 
1704 /*
1705 =================
1706 CL_RestartSound_f
1707 
1708 Restart the sound subsystem so it can pick up
1709 new parameters and flush all sounds
1710 =================
1711 */
1712 static void CL_RestartSound_f(void)
1713 {
1714  S_Shutdown();
1715  S_Init();
1717 }
1718 
1719 /*
1720 =================
1721 CL_PlaySound_f
1722 
1723 Moved here from sound code so that command is always registered.
1724 =================
1725 */
1726 static void CL_PlaySound_c(genctx_t *ctx, int state)
1727 {
1728  FS_File_g("sound", "*.wav", FS_SEARCH_SAVEPATH | FS_SEARCH_BYFILTER | FS_SEARCH_STRIPEXT, ctx);
1729 }
1730 
1731 static void CL_PlaySound_f(void)
1732 {
1733  int i;
1734  char name[MAX_QPATH];
1735 
1736  if (Cmd_Argc() < 2) {
1737  Com_Printf("Usage: %s <sound> [...]\n", Cmd_Argv(0));
1738  return;
1739  }
1740 
1741  for (i = 1; i < Cmd_Argc(); i++) {
1742  Cmd_ArgvBuffer(i, name, sizeof(name));
1743  COM_DefaultExtension(name, ".wav", sizeof(name));
1744  S_StartLocalSound(name);
1745  }
1746 }
1747 
1749 
1750 /*
1751 =================
1752 CL_Begin
1753 
1754 Called after all downloads are done. Not used for demos.
1755 =================
1756 */
1757 void CL_Begin(void)
1758 {
1759 #if USE_REF == REF_GL
1760  if (!Q_stricmp(cl.gamedir, "gloom")) {
1761  // cheat protect our custom modulate cvars
1762  gl_modulate_world->flags |= CVAR_CHEAT;
1763  gl_modulate_entities->flags |= CVAR_CHEAT;
1764  gl_brightness->flags |= CVAR_CHEAT;
1765  }
1766 #endif
1767 
1768  Cvar_FixCheats();
1769 
1770  CL_PrepRefresh();
1776 
1777 #if USE_FPS
1778  CL_UpdateRateSetting();
1779 #endif
1780 
1781  CL_ClientCommand(va("begin %i\n", precache_spawncount));
1782 
1789 }
1790 
1791 /*
1792 =================
1793 CL_Precache_f
1794 
1795 The server will send this command right
1796 before allowing the client into the server
1797 =================
1798 */
1799 static void CL_Precache_f(void)
1800 {
1801  if (cls.state < ca_connected) {
1802  return;
1803  }
1804 
1805  cls.state = ca_loading;
1807 
1808  S_StopAllSounds();
1809 
1811 
1812  // demos use different precache sequence
1813  if (cls.demo.playback) {
1815  CL_PrepRefresh();
1820  return;
1821  }
1822 
1823  precache_spawncount = atoi(Cmd_Argv(1));
1824 
1827 
1828  if (cls.state != ca_precached) {
1830  }
1831 }
1832 
1833 typedef struct {
1834  list_t entry;
1835  unsigned hits;
1836  char match[1];
1837 } ignore_t;
1838 
1839 static list_t cl_ignores;
1840 
1841 static ignore_t *find_ignore(const char *match)
1842 {
1843  ignore_t *ignore;
1844 
1845  LIST_FOR_EACH(ignore_t, ignore, &cl_ignores, entry) {
1846  if (!strcmp(ignore->match, match)) {
1847  return ignore;
1848  }
1849  }
1850 
1851  return NULL;
1852 }
1853 
1854 static void list_ignores(void)
1855 {
1856  ignore_t *ignore;
1857 
1858  if (LIST_EMPTY(&cl_ignores)) {
1859  Com_Printf("No ignore filters.\n");
1860  return;
1861  }
1862 
1863  Com_Printf("Current ignore filters:\n");
1864  LIST_FOR_EACH(ignore_t, ignore, &cl_ignores, entry) {
1865  Com_Printf("\"%s\" (%u hit%s)\n", ignore->match,
1866  ignore->hits, ignore->hits == 1 ? "" : "s");
1867  }
1868 }
1869 
1870 static void add_ignore(const char *match)
1871 {
1872  ignore_t *ignore;
1873  size_t matchlen;
1874 
1875  // don't create the same ignore twice
1876  if (find_ignore(match)) {
1877  return;
1878  }
1879 
1880  matchlen = strlen(match);
1881  if (matchlen < 3) {
1882  Com_Printf("Match string \"%s\" is too short.\n", match);
1883  return;
1884  }
1885 
1886  ignore = Z_Malloc(sizeof(*ignore) + matchlen);
1887  ignore->hits = 0;
1888  memcpy(ignore->match, match, matchlen + 1);
1889  List_Append(&cl_ignores, &ignore->entry);
1890 }
1891 
1892 static void remove_ignore(const char *match)
1893 {
1894  ignore_t *ignore;
1895 
1896  ignore = find_ignore(match);
1897  if (!ignore) {
1898  Com_Printf("Can't find ignore filter \"%s\"\n", match);
1899  return;
1900  }
1901 
1902  List_Remove(&ignore->entry);
1903  Z_Free(ignore);
1904 }
1905 
1906 static void remove_all_ignores(void)
1907 {
1908  ignore_t *ignore, *next;
1909  int count = 0;
1910 
1911  LIST_FOR_EACH_SAFE(ignore_t, ignore, next, &cl_ignores, entry) {
1912  Z_Free(ignore);
1913  count++;
1914  }
1915 
1916  Com_Printf("Removed %d ignore filter%s.\n", count, count == 1 ? "" : "s");
1917  List_Init(&cl_ignores);
1918 }
1919 
1920 static void CL_IgnoreText_f(void)
1921 {
1922  if (Cmd_Argc() == 1) {
1923  list_ignores();
1924  return;
1925  }
1926 
1928 }
1929 
1930 static void CL_UnIgnoreText_f(void)
1931 {
1932  if (Cmd_Argc() == 1) {
1933  list_ignores();
1934  return;
1935  }
1936 
1937  if (LIST_EMPTY(&cl_ignores)) {
1938  Com_Printf("No ignore filters.\n");
1939  return;
1940  }
1941 
1942  if (!strcmp(Cmd_Argv(1), "all")) {
1944  return;
1945  }
1946 
1948 }
1949 
1950 static void CL_IgnoreNick_c(genctx_t *ctx, int argnum)
1951 {
1952  if (argnum == 1) {
1953  CL_Name_g(ctx);
1954  }
1955 }
1956 
1957 // properly escapes any special characters in nickname
1958 static size_t parse_ignore_nick(int argnum, char *buffer)
1959 {
1960  char temp[MAX_CLIENT_NAME];
1961  char *p, *s;
1962  int c;
1963  size_t len;
1964 
1965  Cmd_ArgvBuffer(argnum, temp, sizeof(temp));
1966 
1967  s = temp;
1968  p = buffer;
1969  len = 0;
1970  while (*s) {
1971  c = *s++;
1972  c &= 127;
1973  if (c == '?') {
1974  *p++ = '\\';
1975  *p++ = '?';
1976  len += 2;
1977  } else if (c == '*') {
1978  *p++ = '\\';
1979  *p++ = '*';
1980  len += 2;
1981  } else if (c == '\\') {
1982  *p++ = '\\';
1983  *p++ = '\\';
1984  len += 2;
1985  } else if (Q_isprint(c)) {
1986  *p++ = c;
1987  len++;
1988  }
1989  }
1990 
1991  *p = 0;
1992 
1993  return len;
1994 }
1995 
1996 static void CL_IgnoreNick_f(void)
1997 {
1998  char nick[MAX_CLIENT_NAME * 2];
1999  char match[MAX_CLIENT_NAME * 3];
2000 
2001  if (Cmd_Argc() == 1) {
2002  list_ignores();
2003  return;
2004  }
2005 
2006  if (!parse_ignore_nick(1, nick)) {
2007  return;
2008  }
2009 
2010  Q_snprintf(match, sizeof(match), "%s: *", nick);
2011  add_ignore(match);
2012 
2013  Q_snprintf(match, sizeof(match), "(%s): *", nick);
2014  add_ignore(match);
2015 }
2016 
2017 static void CL_UnIgnoreNick_f(void)
2018 {
2019  char nick[MAX_CLIENT_NAME * 2];
2020  char match[MAX_CLIENT_NAME * 3];
2021 
2022  if (Cmd_Argc() == 1) {
2023  list_ignores();
2024  return;
2025  }
2026 
2027  if (!parse_ignore_nick(1, nick)) {
2028  return;
2029  }
2030 
2031  Q_snprintf(match, sizeof(match), "%s: *", nick);
2032  remove_ignore(match);
2033 
2034  Q_snprintf(match, sizeof(match), "(%s): *", nick);
2035  remove_ignore(match);
2036 }
2037 
2038 /*
2039 =================
2040 CL_CheckForIgnore
2041 =================
2042 */
2043 qboolean CL_CheckForIgnore(const char *s)
2044 {
2045  char buffer[MAX_STRING_CHARS];
2046  ignore_t *ignore;
2047 
2048  if (LIST_EMPTY(&cl_ignores)) {
2049  return qfalse;
2050  }
2051 
2052  Q_strlcpy(buffer, s, sizeof(buffer));
2053  COM_strclr(buffer);
2054 
2055  LIST_FOR_EACH(ignore_t, ignore, &cl_ignores, entry) {
2056  if (Com_WildCmp(ignore->match, buffer)) {
2057  ignore->hits++;
2058  return qtrue;
2059  }
2060  }
2061 
2062  return qfalse;
2063 }
2064 
2065 static void CL_DumpClients_f(void)
2066 {
2067  int i;
2068 
2069  if (cls.state != ca_active) {
2070  Com_Printf("Must be in a level to dump.\n");
2071  return;
2072  }
2073 
2074  for (i = 0; i < MAX_CLIENTS; i++) {
2075  if (!cl.clientinfo[i].name[0]) {
2076  continue;
2077  }
2078 
2079  Com_Printf("%3i: %s\n", i, cl.clientinfo[i].name);
2080  }
2081 }
2082 
2083 static void dump_program(const char *text, const char *name)
2084 {
2085  char buffer[MAX_OSPATH];
2086 
2087  if (cls.state != ca_active) {
2088  Com_Printf("Must be in a level to dump.\n");
2089  return;
2090  }
2091 
2092  if (Cmd_Argc() != 2) {
2093  Com_Printf("Usage: %s <filename>\n", Cmd_Argv(0));
2094  return;
2095  }
2096 
2097  if (!*text) {
2098  Com_Printf("No %s to dump.\n", name);
2099  return;
2100  }
2101 
2102  if (FS_EasyWriteFile(buffer, sizeof(buffer), FS_MODE_WRITE | FS_FLAG_TEXT,
2103  "layouts/", Cmd_Argv(1), ".txt", text, strlen(text))) {
2104  Com_Printf("Dumped %s program to %s.\n", name, buffer);
2105  }
2106 }
2107 
2108 static void CL_DumpStatusbar_f(void)
2109 {
2110  dump_program(cl.configstrings[CS_STATUSBAR], "status bar");
2111 }
2112 
2113 static void CL_DumpLayout_f(void)
2114 {
2115  dump_program(cl.layout, "layout");
2116 }
2117 
2118 static const cmd_option_t o_writeconfig[] = {
2119  { "a", "aliases", "write aliases" },
2120  { "b", "bindings", "write bindings" },
2121  { "c", "cvars", "write archived cvars" },
2122  { "h", "help", "display this help message" },
2123  { "m", "modified", "write modified cvars" },
2124  { NULL }
2125 };
2126 
2127 static void CL_WriteConfig_c(genctx_t *ctx, int argnum)
2128 {
2129  Cmd_Option_c(o_writeconfig, Cmd_Config_g, ctx, argnum);
2130 }
2131 
2132 /*
2133 ===============
2134 CL_WriteConfig_f
2135 ===============
2136 */
2137 static void CL_WriteConfig_f(void)
2138 {
2139  char buffer[MAX_OSPATH];
2140  qboolean aliases = qfalse, bindings = qfalse, modified = qfalse;
2141  int c, mask = 0;
2142  qhandle_t f;
2143 
2144  while ((c = Cmd_ParseOptions(o_writeconfig)) != -1) {
2145  switch (c) {
2146  case 'a':
2147  aliases = qtrue;
2148  break;
2149  case 'b':
2150  bindings = qtrue;
2151  break;
2152  case 'c':
2153  mask |= CVAR_ARCHIVE;
2154  break;
2155  case 'h':
2156  Cmd_PrintUsage(o_writeconfig, "<filename>");
2157  Com_Printf("Save current configuration into file.\n");
2159  return;
2160  case 'm':
2161  modified = qtrue;
2162  mask = ~0;
2163  break;
2164  default:
2165  return;
2166  }
2167  }
2168 
2169  if (!cmd_optarg[0]) {
2170  Com_Printf("Missing filename argument.\n");
2171  Cmd_PrintHint();
2172  return;
2173  }
2174 
2175  if (!aliases && !bindings && !mask) {
2176  bindings = qtrue;
2177  mask = CVAR_ARCHIVE;
2178  }
2179 
2180  f = FS_EasyOpenFile(buffer, sizeof(buffer), FS_MODE_WRITE | FS_FLAG_TEXT,
2181  "configs/", cmd_optarg, ".cfg");
2182  if (!f) {
2183  return;
2184  }
2185 
2186  FS_FPrintf(f, "// generated by q2pro\n");
2187 
2188  if (bindings) {
2189  FS_FPrintf(f, "\n// key bindings\n");
2190  Key_WriteBindings(f);
2191  }
2192  if (aliases) {
2193  FS_FPrintf(f, "\n// command aliases\n");
2194  Cmd_WriteAliases(f);
2195  }
2196  if (mask) {
2197  FS_FPrintf(f, "\n//%s cvars\n", modified ? "modified" : "archived");
2198  Cvar_WriteVariables(f, mask, modified);
2199  }
2200 
2201  FS_FCloseFile(f);
2202 
2203  Com_Printf("Wrote %s.\n", buffer);
2204 }
2205 
2206 static void CL_Say_c(genctx_t *ctx, int argnum)
2207 {
2208  CL_Name_g(ctx);
2209 }
2210 
2211 static size_t CL_Mapname_m(char *buffer, size_t size)
2212 {
2213  return Q_strlcpy(buffer, cl.mapname, size);
2214 }
2215 
2216 static size_t CL_Server_m(char *buffer, size_t size)
2217 {
2218  return Q_strlcpy(buffer, cls.servername, size);
2219 }
2220 
2221 static size_t CL_Ups_m(char *buffer, size_t size)
2222 {
2223  vec3_t vel;
2224 
2225  if (cl.frame.clientNum == CLIENTNUM_NONE) {
2226  if (size) {
2227  *buffer = 0;
2228  }
2229  return 0;
2230  }
2231 
2232  if (!cls.demo.playback && cl.frame.clientNum == cl.clientNum &&
2233  cl_predict->integer) {
2234  VectorCopy(cl.predicted_velocity, vel);
2235  } else {
2236  VectorScale(cl.frame.ps.pmove.velocity, 0.125f, vel);
2237  }
2238 
2239  return Q_scnprintf(buffer, size, "%d", (int)VectorLength(vel));
2240 }
2241 
2242 static size_t CL_Timer_m(char *buffer, size_t size)
2243 {
2244  int hour, min, sec;
2245 
2246  sec = cl.time / 1000;
2247  min = sec / 60; sec %= 60;
2248  hour = min / 60; min %= 60;
2249 
2250  if (hour) {
2251  return Q_scnprintf(buffer, size, "%i:%i:%02i", hour, min, sec);
2252  }
2253  return Q_scnprintf(buffer, size, "%i:%02i", min, sec);
2254 }
2255 
2256 static size_t CL_DemoPos_m(char *buffer, size_t size)
2257 {
2258  int sec, min, framenum;
2259 
2260  if (cls.demo.playback)
2261  framenum = cls.demo.frames_read;
2262  else
2263 #if USE_MVD_CLIENT
2264  if (MVD_GetDemoPercent(NULL, &framenum) == -1)
2265 #endif
2266  framenum = 0;
2267 
2268  sec = framenum / 10; framenum %= 10;
2269  min = sec / 60; sec %= 60;
2270 
2271  return Q_scnprintf(buffer, size,
2272  "%d:%02d.%d", min, sec, framenum);
2273 }
2274 
2275 static size_t CL_Fps_m(char *buffer, size_t size)
2276 {
2277  return Q_scnprintf(buffer, size, "%i", C_FPS);
2278 }
2279 
2280 static size_t R_Fps_m(char *buffer, size_t size)
2281 {
2282  return Q_scnprintf(buffer, size, "%i", R_FPS);
2283 }
2284 
2285 static size_t CL_Mps_m(char *buffer, size_t size)
2286 {
2287  return Q_scnprintf(buffer, size, "%i", C_MPS);
2288 }
2289 
2290 static size_t CL_Pps_m(char *buffer, size_t size)
2291 {
2292  return Q_scnprintf(buffer, size, "%i", C_PPS);
2293 }
2294 
2295 static size_t CL_Ping_m(char *buffer, size_t size)
2296 {
2297  return Q_scnprintf(buffer, size, "%i", cls.measure.ping);
2298 }
2299 
2300 static size_t CL_Lag_m(char *buffer, size_t size)
2301 {
2302  return Q_scnprintf(buffer, size, "%.2f%%", cls.netchan ?
2303  ((float)cls.netchan->total_dropped /
2304  cls.netchan->total_received) * 100.0f : 0);
2305 }
2306 
2307 static size_t CL_Health_m(char *buffer, size_t size)
2308 {
2309  return Q_scnprintf(buffer, size, "%i", cl.frame.ps.stats[STAT_HEALTH]);
2310 }
2311 
2312 static size_t CL_Ammo_m(char *buffer, size_t size)
2313 {
2314  return Q_scnprintf(buffer, size, "%i", cl.frame.ps.stats[STAT_AMMO]);
2315 }
2316 
2317 static size_t CL_Armor_m(char *buffer, size_t size)
2318 {
2319  return Q_scnprintf(buffer, size, "%i", cl.frame.ps.stats[STAT_ARMOR]);
2320 }
2321 
2322 static size_t CL_WeaponModel_m(char *buffer, size_t size)
2323 {
2324  return Q_scnprintf(buffer, size, "%s",
2325  cl.configstrings[cl.frame.ps.gunindex + CS_MODELS]);
2326 }
2327 
2328 static size_t CL_Cluster_m(char *buffer, size_t size)
2329 {
2330  return Q_scnprintf(buffer, size, "%i", cl.refdef.feedback.viewcluster);
2331 }
2332 
2333 static size_t CL_ClusterThere_m(char *buffer, size_t size)
2334 {
2335  return Q_scnprintf(buffer, size, "%i", cl.refdef.feedback.lookatcluster);
2336 }
2337 
2338 static size_t CL_NumLightPolys_m(char *buffer, size_t size)
2339 {
2340  return Q_scnprintf(buffer, size, "%i", cl.refdef.feedback.num_light_polys);
2341 }
2342 
2343 static size_t CL_Material_m(char *buffer, size_t size)
2344 {
2345  return Q_scnprintf(buffer, size, "%s", cl.refdef.feedback.view_material);
2346 }
2347 
2348 static size_t CL_Material_Override_m(char *buffer, size_t size)
2349 {
2350  return Q_scnprintf(buffer, size, "%s", cl.refdef.feedback.view_material_override);
2351 }
2352 
2353 static size_t CL_ViewPos_m(char *buffer, size_t size)
2354 {
2355  return Q_scnprintf(buffer, size, "(%.1f, %.1f, %.1f)", cl.refdef.vieworg[0], cl.refdef.vieworg[1], cl.refdef.vieworg[2]);
2356 }
2357 
2358 static size_t CL_ViewDir_m(char *buffer, size_t size)
2359 {
2360  return Q_scnprintf(buffer, size, "(%.3f, %.3f, %.3f)", cl.v_forward[0], cl.v_forward[1], cl.v_forward[2]);
2361 }
2362 
2363 static size_t CL_HdrColor_m(char *buffer, size_t size)
2364 {
2365  const float* color = cl.refdef.feedback.hdr_color;
2366  return Q_scnprintf(buffer, size, "(%.5f, %.5f, %.5f)", color[0], color[1], color[2]);
2367 }
2368 
2369 static size_t CL_ResolutionScale_m(char *buffer, size_t size)
2370 {
2371  return Q_scnprintf(buffer, size, "%d", cl.refdef.feedback.resolution_scale);
2372 }
2373 
2375 {
2376  return C_FPS;
2377 }
2378 
2380 {
2381  return cl.refdef.feedback.resolution_scale;
2382 }
2383 
2384 /*
2385 ===============
2386 CL_WriteConfig
2387 
2388 Writes key bindings and archived cvars to config.cfg
2389 ===============
2390 */
2391 void CL_WriteConfig(void)
2392 {
2393  qhandle_t f;
2394  qerror_t ret;
2395 
2396  ret = FS_FOpenFile(COM_CONFIG_CFG, &f, FS_MODE_WRITE | FS_FLAG_TEXT);
2397  if (!f) {
2398  Com_EPrintf("Couldn't open %s for writing: %s\n",
2399  COM_CONFIG_CFG, Q_ErrorString(ret));
2400  return;
2401  }
2402 
2403  FS_FPrintf(f, "// generated by " APPLICATION ", do not modify\n");
2404 
2405  Key_WriteBindings(f);
2406  Cvar_WriteVariables(f, CVAR_ARCHIVE, qfalse);
2407 
2408  FS_FCloseFile(f);
2409 }
2410 
2411 /*
2412 ====================
2413 CL_RestartFilesystem
2414 
2415 Flush caches and restart the VFS.
2416 ====================
2417 */
2418 void CL_RestartFilesystem(qboolean total)
2419 {
2420  int cls_state;
2421 
2422  if (!cl_running->integer) {
2423  FS_Restart(total);
2424  return;
2425  }
2426 
2427  Com_DPrintf("%s(%d)\n", __func__, total);
2428 
2429  // temporary switch to loading state
2430  cls_state = cls.state;
2431  if (cls.state >= ca_precached) {
2432  cls.state = ca_loading;
2433  }
2434 
2435  Con_Popup(qfalse);
2436 
2437  UI_Shutdown();
2438 
2439  S_StopAllSounds();
2440  S_FreeAllSounds();
2441 
2442  // write current config before changing game directory
2443  CL_WriteConfig();
2444 
2445  if (cls.ref_initialized) {
2446  R_Shutdown(qfalse);
2447 
2448  FS_Restart(total);
2449 
2450  R_Init(qfalse);
2451 
2454  UI_Init();
2455  } else {
2456  FS_Restart(total);
2457  }
2458 
2459  if (cls_state == ca_disconnected) {
2460  UI_OpenMenu(UIMENU_DEFAULT);
2461  } else if (cls_state >= ca_loading && cls_state <= ca_active) {
2463  CL_PrepRefresh();
2467  } else if (cls_state == ca_cinematic) {
2468  cl.image_precache[0] = R_RegisterPic2(cl.mapname);
2469  }
2470 
2472 
2473  // switch back to original state
2474  cls.state = cls_state;
2475 
2476  Con_Close(qfalse);
2477 
2479 
2480  cvar_modified &= ~CVAR_FILES;
2481 }
2482 
2483 void CL_RestartRefresh(qboolean total)
2484 {
2485  int cls_state;
2486 
2487  if (!cls.ref_initialized) {
2488  return;
2489  }
2490 
2491  // temporary switch to loading state
2492  cls_state = cls.state;
2493  if (cls.state >= ca_precached) {
2494  cls.state = ca_loading;
2495  }
2496 
2497  Con_Popup(qfalse);
2498 
2499  S_StopAllSounds();
2500 
2501  if (total) {
2502  IN_Shutdown();
2504  CL_InitRefresh();
2505  IN_Init();
2506  } else {
2507  UI_Shutdown();
2508  R_Shutdown(qfalse);
2509  R_Init(qfalse);
2512  UI_Init();
2513  }
2514 
2515  if (cls_state == ca_disconnected) {
2516  UI_OpenMenu(UIMENU_DEFAULT);
2517  } else if (cls_state >= ca_loading && cls_state <= ca_active) {
2519  CL_PrepRefresh();
2521  } else if (cls_state == ca_cinematic) {
2522  cl.image_precache[0] = R_RegisterPic2(cl.mapname);
2523  }
2524 
2525  // switch back to original state
2526  cls.state = cls_state;
2527 
2528  Con_Close(qfalse);
2529 
2531 
2532  cvar_modified &= ~CVAR_FILES;
2533 }
2534 
2535 /*
2536 ====================
2537 CL_ReloadRefresh
2538 
2539 Flush caches and reload all models and textures.
2540 ====================
2541 */
2542 static void CL_ReloadRefresh_f(void)
2543 {
2544  CL_RestartRefresh(qfalse);
2545 }
2546 
2547 /*
2548 ====================
2549 CL_RestartRefresh
2550 
2551 Perform complete restart of the renderer subsystem.
2552 ====================
2553 */
2554 static void CL_RestartRefresh_f(void)
2555 {
2556  CL_RestartRefresh(qtrue);
2557 }
2558 
2559 // execute string in server command buffer
2560 static void exec_server_string(cmdbuf_t *buf, const char *text)
2561 {
2562  char *s;
2563 
2564  Cmd_TokenizeString(text, qtrue);
2565 
2566  // execute the command line
2567  if (!Cmd_Argc()) {
2568  return; // no tokens
2569  }
2570 
2571  Com_DPrintf("stufftext: %s\n", text);
2572 
2573  s = Cmd_Argv(0);
2574 
2575  // handle private client commands
2576  if (!strcmp(s, "changing")) {
2577  CL_Changing_f();
2578  return;
2579  }
2580  if (!strcmp(s, "precache")) {
2581  CL_Precache_f();
2582  return;
2583  }
2584 
2585  // forbid nearly every command from demos
2586  if (cls.demo.playback) {
2587  if (strcmp(s, "play")) {
2588  return;
2589  }
2590  }
2591 
2592  // execute regular commands
2593  Cmd_ExecuteCommand(buf);
2594 }
2595 
2596 static void cl_player_model_changed(cvar_t *self)
2597 {
2599 }
2600 
2601 static void info_hand_changed(cvar_t *self)
2602 {
2604 }
2605 
2606 static void cl_gibs_changed(cvar_t *self)
2607 {
2609 }
2610 
2611 static void cl_footsteps_changed(cvar_t *self)
2612 {
2614 }
2615 
2616 static void cl_predict_changed(cvar_t *self)
2617 {
2619 }
2620 
2621 #if USE_FPS
2622 static void cl_updaterate_changed(cvar_t *self)
2623 {
2624  CL_UpdateRateSetting();
2625 }
2626 #endif
2627 
2628 static void cl_sync_changed(cvar_t *self)
2629 {
2631 }
2632 
2633 // allow downloads to be permanently disabled as a
2634 // protection measure from malicious (or just stupid) servers
2635 // that force downloads by stuffing commands
2636 static void cl_allow_download_changed(cvar_t *self)
2637 {
2638  if (self->integer == -1) {
2639  self->flags |= CVAR_ROM;
2640  }
2641 }
2642 
2643 // ugly hack for compatibility
2644 static void cl_chat_sound_changed(cvar_t *self)
2645 {
2646  if (!*self->string)
2647  self->integer = 0;
2648  else if (!Q_stricmp(self->string, "misc/talk.wav"))
2649  self->integer = 1;
2650  else if (!Q_stricmp(self->string, "misc/talk1.wav"))
2651  self->integer = 2;
2652  else if (!self->integer && !COM_IsUint(self->string))
2653  self->integer = 1;
2654 }
2655 
2656 static const cmdreg_t c_client[] = {
2657  { "cmd", CL_ForwardToServer_f },
2658  { "pause", CL_Pause_f },
2659  { "pingservers", CL_PingServers_f },
2660  { "skins", CL_Skins_f },
2661  { "userinfo", CL_Userinfo_f },
2662  { "snd_restart", CL_RestartSound_f },
2663  { "play", CL_PlaySound_f, CL_PlaySound_c },
2664  //{ "changing", CL_Changing_f },
2665  { "disconnect", CL_Disconnect_f },
2666  { "connect", CL_Connect_f, CL_Connect_c },
2667  { "followip", CL_FollowIP_f },
2668  { "passive", CL_PassiveConnect_f },
2669  { "reconnect", CL_Reconnect_f },
2670  { "rcon", CL_Rcon_f, CL_Rcon_c },
2671  //{ "precache", CL_Precache_f },
2672  { "serverstatus", CL_ServerStatus_f, CL_ServerStatus_c },
2673  { "ignoretext", CL_IgnoreText_f },
2674  { "unignoretext", CL_UnIgnoreText_f },
2675  { "ignorenick", CL_IgnoreNick_f, CL_IgnoreNick_c },
2676  { "unignorenick", CL_UnIgnoreNick_f, CL_IgnoreNick_c },
2677  { "dumpclients", CL_DumpClients_f },
2678  { "dumpstatusbar", CL_DumpStatusbar_f },
2679  { "dumplayout", CL_DumpLayout_f },
2680  { "writeconfig", CL_WriteConfig_f, CL_WriteConfig_c },
2681 // { "msgtab", CL_Msgtab_f, CL_Msgtab_g },
2682  { "vid_restart", CL_RestartRefresh_f },
2683  { "r_reload", CL_ReloadRefresh_f },
2684 
2685  //
2686  // forward to server commands
2687  //
2688  // the only thing this does is allow command completion
2689  // to work -- all unknown commands are automatically
2690  // forwarded to the server
2691  { "say", NULL, CL_Say_c },
2692  { "say_team", NULL, CL_Say_c },
2693 
2694  { "wave" }, { "inven" }, { "kill" }, { "use" },
2695  { "drop" }, { "info" }, { "prog" },
2696  { "give" }, { "god" }, { "notarget" }, { "noclip" },
2697  { "invuse" }, { "invprev" }, { "invnext" }, { "invdrop" },
2698  { "weapnext" }, { "weapprev" },
2699 
2700  { NULL }
2701 };
2702 
2703 /*
2704 =================
2705 CL_InitLocal
2706 =================
2707 */
2708 static void CL_InitLocal(void)
2709 {
2710  cvar_t *var;
2711  int i;
2712 
2715 
2716  CL_RegisterInput();
2717  CL_InitDemos();
2718  LOC_Init();
2719  CL_InitAscii();
2720  CL_InitEffects();
2721  CL_InitTEnts();
2722  CL_InitDownloads();
2723  CL_GTV_Init();
2724 
2725  List_Init(&cl_ignores);
2726 
2728 
2729  for (i = 0; i < MAX_LOCAL_SERVERS; i++) {
2730  var = Cvar_Get(va("adr%i", i), "", CVAR_ARCHIVE);
2731  var->generator = Com_Address_g;
2732  }
2733 
2734  //
2735  // register our variables
2736  //
2737  cl_gunalpha = Cvar_Get("cl_gunalpha", "1", 0);
2738  cl_footsteps = Cvar_Get("cl_footsteps", "1", 0);
2740  cl_noskins = Cvar_Get("cl_noskins", "0", 0);
2741  cl_noskins->changed = cl_noskins_changed;
2742  cl_predict = Cvar_Get("cl_predict", "1", 0);
2743  cl_predict->changed = cl_predict_changed;
2744  cl_kickangles = Cvar_Get("cl_kickangles", "1", CVAR_CHEAT);
2745  cl_maxfps = Cvar_Get("cl_maxfps", "60", 0);
2746  cl_maxfps->changed = cl_sync_changed;
2747  cl_async = Cvar_Get("cl_async", "1", 0);
2748  cl_async->changed = cl_sync_changed;
2749  r_maxfps = Cvar_Get("r_maxfps", "0", 0);
2750  r_maxfps->changed = cl_sync_changed;
2751  cl_autopause = Cvar_Get("cl_autopause", "1", 0);
2752  cl_rollhack = Cvar_Get("cl_rollhack", "1", 0);
2753  cl_noglow = Cvar_Get("cl_noglow", "0", 0);
2754  cl_nolerp = Cvar_Get("cl_nolerp", "0", 0);
2755 
2756  // hack for timedemo
2757  com_timedemo->changed = cl_sync_changed;
2758 
2760 
2761 #ifdef _DEBUG
2762  cl_shownet = Cvar_Get("cl_shownet", "0", 0);
2763  cl_showmiss = Cvar_Get("cl_showmiss", "0", 0);
2764  cl_showclamp = Cvar_Get("showclamp", "0", 0);
2765 #endif
2766 
2767  cl_timeout = Cvar_Get("cl_timeout", "120", 0);
2768 
2769  rcon_address = Cvar_Get("rcon_address", "", CVAR_PRIVATE);
2770  rcon_address->generator = Com_Address_g;
2771 
2772  cl_player_model = Cvar_Get("cl_player_model", va("%d", CL_PLAYER_MODEL_FIRST_PERSON), CVAR_ARCHIVE);
2774  cl_thirdperson_angle = Cvar_Get("cl_thirdperson_angle", "0", 0);
2775  cl_thirdperson_range = Cvar_Get("cl_thirdperson_range", "60", 0);
2776 
2777  cl_disable_particles = Cvar_Get("cl_disable_particles", "0", 0);
2778  cl_disable_explosions = Cvar_Get("cl_disable_explosions", "0", 0);
2779  cl_explosion_sprites = Cvar_Get("cl_explosion_sprites", "1", 0);
2780  cl_explosion_frametime = Cvar_Get("cl_explosion_frametime", "20", 0);
2781  cl_gibs = Cvar_Get("cl_gibs", "1", 0);
2782  cl_gibs->changed = cl_gibs_changed;
2783 
2784 #if USE_FPS
2785  cl_updaterate = Cvar_Get("cl_updaterate", "0", 0);
2786  cl_updaterate->changed = cl_updaterate_changed;
2787 #endif
2788 
2789  cl_chat_notify = Cvar_Get("cl_chat_notify", "1", 0);
2790  cl_chat_sound = Cvar_Get("cl_chat_sound", "1", 0);
2793  cl_chat_filter = Cvar_Get("cl_chat_filter", "0", 0);
2794 
2795  cl_disconnectcmd = Cvar_Get("cl_disconnectcmd", "", 0);
2796  cl_changemapcmd = Cvar_Get("cl_changemapcmd", "", 0);
2797  cl_beginmapcmd = Cvar_Get("cl_beginmapcmd", "", 0);
2798 
2799  cl_protocol = Cvar_Get("cl_protocol", "0", 0);
2800 
2801  gender_auto = Cvar_Get("gender_auto", "1", CVAR_ARCHIVE);
2802 
2803  cl_vwep = Cvar_Get("cl_vwep", "1", CVAR_ARCHIVE);
2804  cl_vwep->changed = cl_vwep_changed;
2805 
2806  cl_cinematics = Cvar_Get("cl_cinematics", "1", CVAR_ARCHIVE);
2807 
2810 
2811  //
2812  // userinfo
2813  //
2814  info_password = Cvar_Get("password", "", CVAR_USERINFO);
2815  info_spectator = Cvar_Get("spectator", "0", CVAR_USERINFO);
2816  info_name = Cvar_Get("name", "Player", CVAR_USERINFO | CVAR_ARCHIVE);
2817  info_skin = Cvar_Get("skin", "male/grunt", CVAR_USERINFO | CVAR_ARCHIVE);
2818  info_rate = Cvar_Get("rate", "5000", CVAR_USERINFO | CVAR_ARCHIVE);
2819  info_msg = Cvar_Get("msg", "1", CVAR_USERINFO | CVAR_ARCHIVE);
2820  info_hand = Cvar_Get("hand", "0", CVAR_USERINFO | CVAR_ARCHIVE);
2821  info_hand->changed = info_hand_changed;
2822  info_fov = Cvar_Get("fov", "75", CVAR_USERINFO | CVAR_ARCHIVE);
2823  info_gender = Cvar_Get("gender", "male", CVAR_USERINFO | CVAR_ARCHIVE);
2824  info_gender->modified = qfalse; // clear this so we know when user sets it manually
2825  info_uf = Cvar_Get("uf", "", CVAR_USERINFO);
2826 
2827  // Generate a random user name to avoid new users being kicked out of MP servers.
2828  // The default quake2 config files set the user name to "Player", same as the cvar initialization above.
2829  if (Q_strcasecmp(info_name->string, "Player") == 0)
2830  {
2831  int random_number = rand() % 10000;
2832  char buf[MAX_CLIENT_NAME];
2833  Q_snprintf(buf, sizeof(buf), "Player-%04d", random_number);
2834  Cvar_Set("name", buf);
2835  }
2836 
2837  //
2838  // macros
2839  //
2840  Cmd_AddMacro("cl_mapname", CL_Mapname_m);
2841  Cmd_AddMacro("cl_server", CL_Server_m);
2842  Cmd_AddMacro("cl_timer", CL_Timer_m);
2843  Cmd_AddMacro("cl_demopos", CL_DemoPos_m);
2844  Cmd_AddMacro("cl_ups", CL_Ups_m);
2845  Cmd_AddMacro("cl_fps", CL_Fps_m);
2846  Cmd_AddMacro("r_fps", R_Fps_m);
2847  Cmd_AddMacro("cl_mps", CL_Mps_m); // moves per second
2848  Cmd_AddMacro("cl_pps", CL_Pps_m); // packets per second
2849  Cmd_AddMacro("cl_ping", CL_Ping_m);
2850  Cmd_AddMacro("cl_lag", CL_Lag_m);
2851  Cmd_AddMacro("cl_health", CL_Health_m);
2852  Cmd_AddMacro("cl_ammo", CL_Ammo_m);
2853  Cmd_AddMacro("cl_armor", CL_Armor_m);
2854  Cmd_AddMacro("cl_weaponmodel", CL_WeaponModel_m);
2855  Cmd_AddMacro("cl_cluster", CL_Cluster_m);
2856  Cmd_AddMacro("cl_clusterthere", CL_ClusterThere_m);
2857  Cmd_AddMacro("cl_lightpolys", CL_NumLightPolys_m);
2858  Cmd_AddMacro("cl_material", CL_Material_m);
2859  Cmd_AddMacro("cl_material_override", CL_Material_Override_m);
2860  Cmd_AddMacro("cl_viewpos", CL_ViewPos_m);
2861  Cmd_AddMacro("cl_viewdir", CL_ViewDir_m);
2862  Cmd_AddMacro("cl_hdr_color", CL_HdrColor_m);
2863  Cmd_AddMacro("cl_resolution_scale", CL_ResolutionScale_m);
2864 }
2865 
2866 /*
2867 ==================
2868 CL_CheatsOK
2869 ==================
2870 */
2871 qboolean CL_CheatsOK(void)
2872 {
2873  // can cheat when disconnected or playing a demo
2875  return qtrue;
2876 
2877  // can't cheat on remote servers
2878  if (!sv_running->integer)
2879  return qfalse;
2880 
2881  // developer option
2882  if (Cvar_VariableInteger("cheats"))
2883  return qtrue;
2884 
2885  // single player can cheat
2886  if (cls.state > ca_connected && cl.maxclients == 1)
2887  return qtrue;
2888 
2889 #if USE_MVD_CLIENT
2890  // can cheat when playing MVD
2891  if (MVD_GetDemoPercent(NULL, NULL) != -1)
2892  return qtrue;
2893 #endif
2894 
2895  return qfalse;
2896 }
2897 
2898 //============================================================================
2899 
2900 /*
2901 ==================
2902 CL_Activate
2903 ==================
2904 */
2905 void CL_Activate(active_t active)
2906 {
2907  if (cls.active != active) {
2908  Com_DDDPrintf("%s: %u\n", __func__, active);
2909  cls.active = active;
2910  cls.disable_screen = 0;
2911  Key_ClearStates();
2912  IN_Activate();
2913  S_Activate();
2915  }
2916 }
2917 
2918 static void CL_SetClientTime(void)
2919 {
2920  int prevtime;
2921 
2922  if (com_timedemo->integer) {
2923  cl.time = cl.servertime;
2924  cl.lerpfrac = 1.0f;
2925 #if USE_FPS
2926  cl.keytime = cl.keyservertime;
2927  cl.keylerpfrac = 1.0f;
2928 #endif
2929  return;
2930  }
2931 
2932  prevtime = cl.servertime - CL_FRAMETIME;
2933  if (cl.time > cl.servertime) {
2934  SHOWCLAMP(1, "high clamp %i\n", cl.time - cl.servertime);
2935  cl.time = cl.servertime;
2936  cl.lerpfrac = 1.0f;
2937  } else if (cl.time < prevtime) {
2938  SHOWCLAMP(1, "low clamp %i\n", prevtime - cl.time);
2939  cl.time = prevtime;
2940  cl.lerpfrac = 0;
2941  } else {
2942  cl.lerpfrac = (cl.time - prevtime) * CL_1_FRAMETIME;
2943  }
2944 
2945  SHOWCLAMP(2, "time %d %d, lerpfrac %.3f\n",
2947 
2948 #if USE_FPS
2949  prevtime = cl.keyservertime - BASE_FRAMETIME;
2950  if (cl.keytime > cl.keyservertime) {
2951  SHOWCLAMP(1, "high keyclamp %i\n", cl.keytime - cl.keyservertime);
2952  cl.keytime = cl.keyservertime;
2953  cl.keylerpfrac = 1.0f;
2954  } else if (cl.keytime < prevtime) {
2955  SHOWCLAMP(1, "low keyclamp %i\n", prevtime - cl.keytime);
2956  cl.keytime = prevtime;
2957  cl.keylerpfrac = 0;
2958  } else {
2959  cl.keylerpfrac = (cl.keytime - prevtime) * BASE_1_FRAMETIME;
2960  }
2961 
2962  SHOWCLAMP(2, "keytime %d %d keylerpfrac %.3f\n",
2963  cl.keytime, cl.keyservertime, cl.keylerpfrac);
2964 #endif
2965 }
2966 
2967 static void CL_MeasureStats(void)
2968 {
2969  int i;
2970 
2971  if (com_localTime - cls.measure.time < 1000) {
2972  return;
2973  }
2974 
2975  // measure average ping
2976  if (cls.netchan) {
2977  int ack = cls.netchan->incoming_acknowledged;
2978  int ping = 0;
2979  int j, k = 0;
2980 
2981  i = ack - 16 + 1;
2982  if (i < cl.initialSeq) {
2983  i = cl.initialSeq;
2984  }
2985  for (j = i; j <= ack; j++) {
2986  client_history_t *h = &cl.history[j & CMD_MASK];
2987  if (h->rcvd > h->sent) {
2988  ping += h->rcvd - h->sent;
2989  k++;
2990  }
2991  }
2992 
2993  cls.measure.ping = k ? ping / k : 0;
2994  }
2995 
2996  // measure main/refresh frame counts
2997  for (i = 0; i < 4; i++) {
2998  cls.measure.fps[i] = cls.measure.frames[i];
2999  cls.measure.frames[i] = 0;
3000  }
3001 
3003 }
3004 
3005 #if USE_AUTOREPLY
3006 static void CL_CheckForReply(void)
3007 {
3008  if (!cl.reply_delta) {
3009  return;
3010  }
3011 
3012  if (cls.realtime - cl.reply_time < cl.reply_delta) {
3013  return;
3014  }
3015 
3016  CL_ClientCommand(va("say \"%s\"", com_version->string));
3017 
3018  cl.reply_delta = 0;
3019 }
3020 #endif
3021 
3022 static void CL_CheckTimeout(void)
3023 {
3024  unsigned delta;
3025 
3026  if (NET_IsLocalAddress(&cls.netchan->remote_address)) {
3027  return;
3028  }
3029 
3030 #if USE_ICMP
3031  if (cls.errorReceived) {
3032  delta = 5000;
3033  if (com_localTime - cls.netchan->last_received > delta) {
3034  Com_Error(ERR_DISCONNECT, "Server connection was reset.");
3035  }
3036  }
3037 #endif
3038 
3039  delta = cl_timeout->value * 1000;
3040  if (delta && com_localTime - cls.netchan->last_received > delta) {
3041  // timeoutcount saves debugger
3042  if (++cl.timeoutcount > 5) {
3043  Com_Error(ERR_DISCONNECT, "Server connection timed out.");
3044  }
3045  } else {
3046  cl.timeoutcount = 0;
3047  }
3048 }
3049 
3050 /*
3051 =================
3052 CL_CheckForPause
3053 
3054 =================
3055 */
3057 {
3058  if (cls.state != ca_active) {
3059  // only pause when active
3060  Cvar_Set("cl_paused", "0");
3061  Cvar_Set("sv_paused", "0");
3062  return;
3063  }
3064 
3065  if (cls.key_dest & (KEY_CONSOLE | KEY_MENU)) {
3066  // only pause in single player
3067  if (cl_paused->integer == 0 && cl_autopause->integer) {
3068  Cvar_Set("cl_paused", "1");
3069  }
3070  } else if (cl_paused->integer == 1) {
3071  // only resume after automatic pause
3072  Cvar_Set("cl_paused", "0");
3073  }
3074 
3075  // hack for demo playback pause/unpause
3076  if (cls.demo.playback) {
3077  // don't pause when running timedemo!
3078  if (cl_paused->integer && !com_timedemo->integer) {
3079  if (!sv_paused->integer) {
3080  Cvar_Set("sv_paused", "1");
3081  IN_Activate();
3082  }
3083  } else {
3084  if (sv_paused->integer) {
3085  Cvar_Set("sv_paused", "0");
3086  IN_Activate();
3087  }
3088  }
3089  }
3090 }
3091 
3092 typedef enum {
3101 } sync_mode_t;
3102 
3103 #ifdef _DEBUG
3104 static const char *const sync_names[] = {
3105  "SYNC_FULL",
3106  "SYNC_MAXFPS",
3107  "SYNC_SLEEP_10",
3108  "SYNC_SLEEP_60",
3109  "SYNC_SLEEP_VIDEO",
3110  "ASYNC_VIDEO",
3111  "ASYNC_MAXFPS",
3112  "ASYNC_FULL"
3113 };
3114 #endif
3115 
3119 
3120 static inline int fps_to_msec(int fps)
3121 {
3122 #if 0
3123  return (1000 + fps / 2) / fps;
3124 #else
3125  return 1000 / fps;
3126 #endif
3127 }
3128 
3129 /*
3130 ==================
3131 CL_UpdateFrameTimes
3132 
3133 Called whenever async/fps cvars change, but not every frame
3134 ==================
3135 */
3137 {
3138  if (!cls.state) {
3139  return; // not yet fully initialized
3140  }
3141 
3142  // check if video driver supports syncing to vertical retrace
3143  if (cl_async->integer > 1 && !(r_config.flags & QVF_VIDEOSYNC)) {
3144  Cvar_Reset(cl_async);
3145  }
3146 
3147  if (com_timedemo->integer) {
3148  // timedemo just runs at full speed
3149  ref_msec = phys_msec = main_msec = 0;
3150  sync_mode = SYNC_FULL;
3151  } else if (cls.active == ACT_MINIMIZED) {
3152  // run at 10 fps if minimized
3153  ref_msec = phys_msec = 0;
3154  main_msec = fps_to_msec(10);
3156  } else if (cls.active == ACT_RESTORED || cls.state != ca_active) {
3157  // run at 60 fps if not active
3158  ref_msec = phys_msec = 0;
3159  if (cl_async->integer > 1) {
3160  main_msec = 0;
3162  } else {
3163  main_msec = fps_to_msec(60);
3165  }
3166  } else if (cl_async->integer > 0) {
3167  // run physics and refresh separately
3169  if (cl_async->integer > 1) {
3170  ref_msec = 0;
3172  } else if (r_maxfps->integer) {
3175  } else {
3176  ref_msec = 1;
3178  }
3179  main_msec = 0;
3180  } else {
3181  // everything ticks in sync with refresh
3182  phys_msec = ref_msec = 0;
3183  if (cl_maxfps->integer) {
3186  } else {
3187  main_msec = 1;
3188  sync_mode = SYNC_FULL;
3189  }
3190  }
3191 
3192  Com_DDDPrintf("%s: mode=%s main_msec=%d ref_msec=%d, phys_msec=%d\n",
3193  __func__, sync_names[sync_mode], main_msec, ref_msec, phys_msec);
3194 
3196 }
3197 
3198 /*
3199 ==================
3200 CL_Frame
3201 
3202 ==================
3203 */
3204 unsigned CL_Frame(unsigned msec)
3205 {
3206  qboolean phys_frame, ref_frame;
3207 
3208  time_after_ref = time_before_ref = 0;
3209 
3210  if (!cl_running->integer) {
3211  return UINT_MAX;
3212  }
3213 
3214  main_extra += msec;
3215  cls.realtime += msec;
3216 
3217  CL_ProcessEvents();
3218 
3219  ref_frame = phys_frame = qtrue;
3220  switch (sync_mode) {
3221  case SYNC_FULL:
3222  // timedemo just runs at full speed
3223  break;
3224  case SYNC_SLEEP_10:
3225  // don't run refresh at all
3226  ref_frame = qfalse;
3227  // fall through
3228  case SYNC_SLEEP_60:
3229  // run at limited fps if not active
3230  if (main_extra < main_msec) {
3231  return main_msec - main_extra;
3232  }
3233  break;
3234  case SYNC_SLEEP_VIDEO:
3235  // wait for vertical retrace if not active
3236  VID_VideoWait();
3237  break;
3238  case ASYNC_VIDEO:
3239  case ASYNC_MAXFPS:
3240  case ASYNC_FULL:
3241  // run physics and refresh separately
3243  if (phys_extra < phys_msec) {
3244  phys_frame = qfalse;
3245  } else if (phys_extra > phys_msec * 4) {
3247  }
3248 
3249  if (sync_mode == ASYNC_VIDEO) {
3250  // sync refresh to vertical retrace
3251  ref_frame = VID_VideoSync();
3252  } else {
3253  ref_extra += main_extra;
3254  if (ref_extra < ref_msec) {
3255  ref_frame = qfalse;
3256  } else if (ref_extra > ref_msec * 4) {
3257  ref_extra = ref_msec;
3258  }
3259  }
3260  break;
3261  case SYNC_MAXFPS:
3262  // everything ticks in sync with refresh
3263  if (main_extra < main_msec) {
3264  if (!cl.sendPacketNow) {
3265  return 0;
3266  }
3267  ref_frame = qfalse;
3268  }
3269  break;
3270  }
3271 
3272  Com_DDDDPrintf("main_extra=%d ref_frame=%d ref_extra=%d "
3273  "phys_frame=%d phys_extra=%d\n",
3274  main_extra, ref_frame, ref_extra,
3275  phys_frame, phys_extra);
3276 
3277  // decide the simulation time
3278  cls.frametime = main_extra * 0.001f;
3279 
3280  if (cls.frametime > 1.0 / 5)
3281  cls.frametime = 1.0 / 5;
3282 
3283  if (!sv_paused->integer) {
3284  cl.time += main_extra;
3285 #if USE_FPS
3286  cl.keytime += main_extra;
3287 #endif
3288  }
3289 
3290  // read next demo frame
3291  if (cls.demo.playback)
3293 
3294  // calculate local time
3295  if (cls.state == ca_active && !sv_paused->integer)
3296  CL_SetClientTime();
3297 
3298 #if USE_AUTOREPLY
3299  // check for version reply
3300  CL_CheckForReply();
3301 #endif
3302 
3303  // resend a connection request if necessary
3305 
3306  // read user intentions
3308 
3309  // finalize pending cmd
3310  phys_frame |= cl.sendPacketNow;
3311  if (phys_frame) {
3312  CL_FinalizeCmd();
3313  phys_extra -= phys_msec;
3314  M_FRAMES++;
3315 
3316  // don't let the time go too far off
3317  // this can happen due to cl.sendPacketNow
3318  if (phys_extra < -phys_msec * 4) {
3319  phys_extra = 0;
3320  }
3321  }
3322 
3323  // send pending cmds
3324  CL_SendCmd();
3325 
3326  // predict all unacknowledged movements
3328 
3329  Con_RunConsole();
3330 
3332 
3333  if (ref_frame) {
3334  // update the screen
3335  if (host_speeds->integer)
3336  time_before_ref = Sys_Milliseconds();
3337 
3338  SCR_UpdateScreen();
3339 
3340  if (host_speeds->integer)
3341  time_after_ref = Sys_Milliseconds();
3342 
3343  ref_extra -= ref_msec;
3344  R_FRAMES++;
3345 
3346 run_fx:
3347  // update audio after the 3D view was drawn
3348  S_Update();
3349 
3350  // advance local effects for next frame
3351 #if USE_DLIGHTS
3352  CL_RunDLights();
3353 #endif
3354 
3355 #if USE_LIGHTSTYLES
3356  CL_RunLightStyles();
3357 #endif
3358  SCR_RunCinematic();
3359  } else if (sync_mode == SYNC_SLEEP_10) {
3360  // force audio and effects update if not rendering
3362  goto run_fx;
3363  }
3364 
3365  // check connection timeout
3366  if (cls.netchan)
3367  CL_CheckTimeout();
3368 
3369  C_FRAMES++;
3370 
3371  CL_MeasureStats();
3372 
3373  cls.framecount++;
3374 
3375  main_extra = 0;
3376  return 0;
3377 }
3378 
3379 /*
3380 ============
3381 CL_ProcessEvents
3382 ============
3383 */
3384 qboolean CL_ProcessEvents(void)
3385 {
3386  if (!cl_running->integer) {
3387  return qfalse;
3388  }
3389 
3390  CL_RunRefresh();
3391 
3392  IN_Frame();
3393 
3394  NET_GetPackets(NS_CLIENT, CL_PacketEvent);
3395 
3396  // process console and stuffed commands
3399 
3401 
3402  CL_GTV_Run();
3403 
3404  return cl.sendPacketNow;
3405 }
3406 
3407 //============================================================================
3408 
3409 /*
3410 ====================
3411 CL_Init
3412 ====================
3413 */
3414 void CL_Init(void)
3415 {
3416  if (dedicated->integer) {
3417  return; // nothing running on the client
3418  }
3419 
3420  if (cl_running->integer) {
3421  return;
3422  }
3423 
3424  // all archived variables will now be loaded
3425 
3426  // start with full screen console
3427  cls.key_dest = KEY_CONSOLE;
3428 
3429 #ifdef _WIN32
3430  CL_InitRefresh();
3431  S_Init(); // sound must be initialized after window is created
3432 #else
3433  S_Init();
3434  CL_InitRefresh();
3435 #endif
3436 
3437  CL_InitLocal();
3438  IN_Init();
3439 
3440 #if USE_ZLIB
3441  if (inflateInit2(&cls.z, -MAX_WBITS) != Z_OK) {
3442  Com_Error(ERR_FATAL, "%s: inflateInit2() failed", __func__);
3443  }
3444 #endif
3445 
3447 
3448  HTTP_Init();
3449 
3450  UI_OpenMenu(UIMENU_DEFAULT);
3451 
3452  Con_PostInit();
3453  Con_RunConsole();
3454 
3455  cl_cmdbuf.from = FROM_STUFFTEXT;
3456  cl_cmdbuf.text = cl_cmdbuf_text;
3457  cl_cmdbuf.maxsize = sizeof(cl_cmdbuf_text);
3459 
3460  Cvar_Set("cl_running", "1");
3461 }
3462 
3463 /*
3464 ===============
3465 CL_Shutdown
3466 
3467 FIXME: this is a callback from Com_Quit and Com_Error. It would be better
3468 to run quit through here before the final handoff to the sys code.
3469 ===============
3470 */
3471 void CL_Shutdown(void)
3472 {
3473  static qboolean isdown = qfalse;
3474 
3475  if (isdown) {
3476  Com_Printf("CL_Shutdown: recursive shutdown\n");
3477  return;
3478  }
3479  isdown = qtrue;
3480 
3481  if (!cl_running || !cl_running->integer) {
3482  return;
3483  }
3484 
3485  CL_GTV_Shutdown();
3486 
3487  CL_Disconnect(ERR_FATAL);
3488 
3489 #if USE_ZLIB
3490  inflateEnd(&cls.z);
3491 #endif
3492 
3493  HTTP_Shutdown();
3494  S_Shutdown();
3495  IN_Shutdown();
3496  Con_Shutdown();
3498  CL_WriteConfig();
3499 
3500  memset(&cls, 0, sizeof(cls));
3501 
3502  Cvar_Set("cl_running", "0");
3503 
3504  isdown = qfalse;
3505 }
3506 
CL_DumpStatusResponse
static void CL_DumpStatusResponse(const serverStatus_t *status)
Definition: main.c:917
CL_Shutdown
void CL_Shutdown(void)
Definition: main.c:3471
FS_Restart
void FS_Restart(qboolean total)
Definition: files.c:3556
client_state_s::frame
server_frame_t frame
Definition: client.h:212
CL_Armor_m
static size_t CL_Armor_m(char *buffer, size_t size)
Definition: main.c:2317
CL_SetClientTime
static void CL_SetClientTime(void)
Definition: main.c:2918
SYNC_SLEEP_10
@ SYNC_SLEEP_10
Definition: main.c:3095
SV_Shutdown
void SV_Shutdown(const char *finalmsg, error_type_t type)
Definition: main.c:2252
CL_ViewPos_m
static size_t CL_ViewPos_m(char *buffer, size_t size)
Definition: main.c:2353
CL_Health_m
static size_t CL_Health_m(char *buffer, size_t size)
Definition: main.c:2307
MAX_REQUESTS
#define MAX_REQUESTS
Definition: main.c:123
HTTP_RunDownloads
void HTTP_RunDownloads(void)
Definition: http.c:941
LOC_FreeLocations
void LOC_FreeLocations(void)
Definition: locs.c:122
client_state_s::bsp
bsp_t * bsp
Definition: client.h:300
client_static_s::connect_time
unsigned connect_time
Definition: client.h:411
REQ_FREE
@ REQ_FREE
Definition: main.c:110
client_state_s::configstrings
char configstrings[MAX_CONFIGSTRINGS][MAX_QPATH]
Definition: client.h:289
dump_program
static void dump_program(const char *text, const char *name)
Definition: main.c:2083
CL_NumLightPolys_m
static size_t CL_NumLightPolys_m(char *buffer, size_t size)
Definition: main.c:2338
Cvar_Set
cvar_t * Cvar_Set(const char *var_name, const char *value)
Definition: cvar.c:466
FS_EasyOpenFile
qhandle_t FS_EasyOpenFile(char *buf, size_t size, unsigned mode, const char *dir, const char *name, const char *ext)
Definition: files.c:1846
CL_PacketEvent
static void CL_PacketEvent(void)
Definition: main.c:1541
r_config
refcfg_t r_config
Definition: main.c:24
CL_SendCmd
void CL_SendCmd(void)
Definition: input.c:1166
CL_UpdateFootstepsSetting
static void CL_UpdateFootstepsSetting(void)
Definition: main.c:218
client_static_s::passive
qboolean passive
Definition: client.h:413
cvar_modified
int cvar_modified
Definition: cvar.c:32
cl_disable_particles
cvar_t * cl_disable_particles
Definition: main.c:51
msg_read
sizebuf_t msg_read
Definition: msg.c:37
CL_GTV_Suspend
void CL_GTV_Suspend(void)
Definition: gtv.c:269
client_static_s::quakePort
int quakePort
Definition: client.h:419
client_state_s::servertime
int servertime
Definition: client.h:214
client_state_s::image_precache
qhandle_t image_precache[MAX_IMAGES]
Definition: client.h:306
LOAD_SOUNDS
@ LOAD_SOUNDS
Definition: client.h:612
Sys_GetAntiCheatAPI
qboolean Sys_GetAntiCheatAPI(void)
Definition: ac.c:31
CL_Begin
void CL_Begin(void)
Definition: main.c:1757
CL_Init
void CL_Init(void)
Definition: main.c:3414
cl_cinematics
cvar_t * cl_cinematics
Definition: main.c:74
UI_StatusEvent
void UI_StatusEvent(const serverStatus_t *status)
Definition: servers.c:206
request_t
Definition: main.c:117
CL_Ping_m
static size_t CL_Ping_m(char *buffer, size_t size)
Definition: main.c:2295
cl_noskins_changed
static void cl_noskins_changed(cvar_t *self)
Definition: main.c:1256
NET_AdrToString
char * NET_AdrToString(const netadr_t *a)
Definition: net.c:257
client_static_s::playback
qhandle_t playback
Definition: client.h:453
gl_modulate_world
cvar_t * gl_modulate_world
Definition: main.c:43
cmd_optarg
char * cmd_optarg
Definition: cmd.c:848
CL_ParseInfoMessage
static void CL_ParseInfoMessage(void)
Definition: main.c:993
Cvar_BitInfo
size_t Cvar_BitInfo(char *info, int bit)
Definition: cvar.c:1109
Info_Validate
qboolean Info_Validate(const char *s)
Definition: shared.c:1040
Q_strncasecmp
int Q_strncasecmp(const char *s1, const char *s2, size_t n)
Definition: shared.c:642
RECENT_ADDR
#define RECENT_ADDR
Definition: client.h:431
Q_snprintf
size_t Q_snprintf(char *dest, size_t size, const char *fmt,...)
Definition: shared.c:846
cl_allow_download_changed
static void cl_allow_download_changed(cvar_t *self)
Definition: main.c:2636
CL_Precache_f
static void CL_Precache_f(void)
Definition: main.c:1799
cl_player_model_changed
static void cl_player_model_changed(cvar_t *self)
Definition: main.c:2596
client_static_s::demo
struct client_static_s::@3 demo
client_static_s::file
qhandle_t file
Definition: client.h:443
CL_UnIgnoreText_f
static void CL_UnIgnoreText_f(void)
Definition: main.c:1930
CL_ProcessEvents
qboolean CL_ProcessEvents(void)
Definition: main.c:3384
CL_ClusterThere_m
static size_t CL_ClusterThere_m(char *buffer, size_t size)
Definition: main.c:2333
client_static_s
Definition: client.h:374
CL_SendRcon
void CL_SendRcon(const netadr_t *adr, const char *pass, const char *cmd)
Definition: main.c:637
client_static_s::buffer
sizebuf_t buffer
Definition: client.h:466
CL_RegisterVWepModels
void CL_RegisterVWepModels(void)
Definition: precache.c:269
MSG_BeginReading
void MSG_BeginReading(void)
Definition: msg.c:1437
CL_RegisterInput
void CL_RegisterInput(void)
Definition: input.c:707
client_state_s::v_forward
vec3_t v_forward
Definition: client.h:258
cl_changemapcmd
cvar_t * cl_changemapcmd
Definition: main.c:60
CL_InitTEnts
void CL_InitTEnts(void)
Definition: tent.c:1467
CL_ForwardToServer
qboolean CL_ForwardToServer(void)
Definition: main.c:321
info_uf
cvar_t * info_uf
Definition: main.c:88
cl_timeout
cvar_t * cl_timeout
Definition: main.c:27
fs_shareware
cvar_t * fs_shareware
Definition: files.c:204
cmd_current
cmdbuf_t * cmd_current
Definition: cmd.c:52
R_FRAMES
#define R_FRAMES
Definition: client.h:398
CL_Stop_f
void CL_Stop_f(void)
Definition: demo.c:268
S_StopAllSounds
void S_StopAllSounds(void)
Definition: main.c:932
R_Fps_m
static size_t R_Fps_m(char *buffer, size_t size)
Definition: main.c:2280
Cvar_Get
cvar_t * Cvar_Get(const char *var_name, const char *var_value, int flags)
Definition: cvar.c:257
client_static_s::key_dest
keydest_t key_dest
Definition: client.h:376
Q_ErrorString
const char * Q_ErrorString(qerror_t error)
Definition: error.c:51
CL_1_FRAMETIME
#define CL_1_FRAMETIME
Definition: client.h:162
c
statCounters_t c
Definition: main.c:30
cl_explosion_sprites
cvar_t * cl_explosion_sprites
Definition: main.c:56
IN_Activate
void IN_Activate(void)
Definition: input.c:117
Netchan_Setup
netchan_t * Netchan_Setup(netsrc_t sock, netchan_type_t type, const netadr_t *adr, int qport, size_t maxpacketlen, int protocol)
Definition: chan.c:835
cl_thirdperson_angle
cvar_t * cl_thirdperson_angle
Definition: main.c:48
CL_RestartFilesystem
void CL_RestartFilesystem(qboolean total)
Definition: main.c:2418
CL_ClearTEnts
void CL_ClearTEnts(void)
Definition: tent.c:1459
Con_RunConsole
void Con_RunConsole(void)
Definition: console.c:982
CL_Say_c
static void CL_Say_c(genctx_t *ctx, int argnum)
Definition: main.c:2206
CL_Mapname_m
static size_t CL_Mapname_m(char *buffer, size_t size)
Definition: main.c:2211
net_maxmsglen
cvar_t * net_maxmsglen
Definition: chan.c:99
CL_GetFps
int CL_GetFps()
Definition: main.c:2374
Netchan_OutOfBand
void Netchan_OutOfBand(netsrc_t sock, const netadr_t *address, const char *format,...)
Definition: chan.c:140
SCR_UpdateScreen
void SCR_UpdateScreen(void)
Definition: screen.c:2142
SYNC_SLEEP_VIDEO
@ SYNC_SLEEP_VIDEO
Definition: main.c:3097
sync_mode_t
sync_mode_t
Definition: main.c:3092
cl_gibs_changed
static void cl_gibs_changed(cvar_t *self)
Definition: main.c:2606
ca_disconnected
@ ca_disconnected
Definition: client.h:334
CL_Timer_m
static size_t CL_Timer_m(char *buffer, size_t size)
Definition: main.c:2242
client_state_s::predicted_velocity
vec3_t predicted_velocity
Definition: client.h:195
ignore_t::entry
list_t entry
Definition: main.c:1834
ca_active
@ ca_active
Definition: client.h:340
cl_cmdbuf_text
char cl_cmdbuf_text[MAX_STRING_CHARS]
Definition: main.c:105
Cmd_ExecTrigger
void Cmd_ExecTrigger(const char *string)
Definition: cmd.c:576
CL_Userinfo_f
static void CL_Userinfo_f(void)
Definition: main.c:1694
info_rate
cvar_t * info_rate
Definition: main.c:83
FS_FPrintf
ssize_t FS_FPrintf(qhandle_t f, const char *format,...)
Definition: files.c:2039
CL_GTV_Shutdown
void CL_GTV_Shutdown(void)
Definition: gtv.c:587
find_ignore
static ignore_t * find_ignore(const char *match)
Definition: main.c:1841
net_chantype
cvar_t * net_chantype
Definition: chan.c:100
HTTP_SetServer
void HTTP_SetServer(const char *url)
Definition: http.c:477
remove_all_ignores
static void remove_all_ignores(void)
Definition: main.c:1906
client_static_s::state
connstate_t state
Definition: client.h:375
UI_Init
void UI_Init(void)
Definition: ui.c:627
CL_InitRefresh
void CL_InitRefresh(void)
Definition: refresh.c:289
client_state_s::gamedir
char gamedir[MAX_QPATH]
Definition: client.h:277
Cmd_Config_g
void Cmd_Config_g(genctx_t *ctx)
Definition: cmd.c:1805
ca_connected
@ ca_connected
Definition: client.h:337
CL_Disconnect
void CL_Disconnect(error_type_t type)
Definition: main.c:740
client_state_s::lerpfrac
float lerpfrac
Definition: client.h:246
client_static_s::ref_initialized
qboolean ref_initialized
Definition: client.h:380
gender_auto
cvar_t * gender_auto
Definition: main.c:70
info_fov
cvar_t * info_fov
Definition: main.c:84
sv_paused
cvar_t * sv_paused
Definition: common.c:96
R_Shutdown
void R_Shutdown(qboolean total)
Definition: main.c:280
remove_ignore
static void remove_ignore(const char *match)
Definition: main.c:1892
client_static_s::active
active_t active
Definition: client.h:378
IN_Init
void IN_Init(void)
Definition: input.c:210
client_static_s::frames
int frames[4]
Definition: client.h:403
cl_chat_sound
cvar_t * cl_chat_sound
Definition: main.c:54
Cmd_PrintUsage
void Cmd_PrintUsage(const cmd_option_t *opt, const char *suffix)
Definition: cmd.c:1143
CL_UpdateBlendSetting
void CL_UpdateBlendSetting(void)
Definition: view.c:292
CL_GTV_Run
void CL_GTV_Run(void)
Definition: gtv.c:488
client_static_s::connect_count
int connect_count
Definition: client.h:412
CL_IgnoreNick_f
static void CL_IgnoreNick_f(void)
Definition: main.c:1996
info_password
cvar_t * info_password
Definition: main.c:79
CL_Lag_m
static size_t CL_Lag_m(char *buffer, size_t size)
Definition: main.c:2300
info_hand_changed
static void info_hand_changed(cvar_t *self)
Definition: main.c:2601
HTTP_Init
void HTTP_Init(void)
Definition: http.c:436
CL_CheckForIgnore
qboolean CL_CheckForIgnore(const char *s)
Definition: main.c:2043
CL_WriteConfig_c
static void CL_WriteConfig_c(genctx_t *ctx, int argnum)
Definition: main.c:2127
CL_ServerStatus_c
static void CL_ServerStatus_c(genctx_t *ctx, int argnum)
Definition: main.c:816
net_qport
cvar_t * net_qport
Definition: chan.c:98
ASYNC_MAXFPS
@ ASYNC_MAXFPS
Definition: main.c:3099
client_static_s::time
unsigned time
Definition: client.h:402
main_extra
static int main_extra
Definition: main.c:3117
CL_DumpClients_f
static void CL_DumpClients_f(void)
Definition: main.c:2065
SCR_EndLoadingPlaque
void SCR_EndLoadingPlaque(void)
Definition: screen.c:1456
CL_UpdateCmd
void CL_UpdateCmd(int msec)
Definition: input.c:655
Cbuf_InsertText
void Cbuf_InsertText(cmdbuf_t *buf, const char *text)
Definition: cmd.c:128
Cmd_TokenizeString
void Cmd_TokenizeString(const char *text, qboolean macroExpand)
Definition: cmd.c:1399
CL_LoadDownloadIgnores
void CL_LoadDownloadIgnores(void)
Definition: download.c:173
SYNC_FULL
@ SYNC_FULL
Definition: main.c:3093
SCR_RunCinematic
void SCR_RunCinematic(void)
Definition: cin.c:429
UI_ErrorEvent
void UI_ErrorEvent(netadr_t *from)
Definition: servers.c:319
LOAD_NONE
@ LOAD_NONE
Definition: client.h:607
CL_RecentIP_g
static void CL_RecentIP_g(genctx_t *ctx)
Definition: main.c:475
Cmd_RawArgsFrom
char * Cmd_RawArgsFrom(int from)
Definition: cmd.c:1021
MSG_WriteByte
void MSG_WriteByte(int c)
Definition: msg.c:107
LOC_Init
void LOC_Init(void)
Definition: locs.c:376
com_timedemo
cvar_t * com_timedemo
Definition: common.c:97
Cmd_Argv
char * Cmd_Argv(int arg)
Definition: cmd.c:899
CL_InitAscii
void CL_InitAscii(void)
Definition: ascii.c:370
Sys_Milliseconds
unsigned Sys_Milliseconds(void)
Definition: system.c:644
info_msg
cvar_t * info_msg
Definition: main.c:85
cl_vwep
cvar_t * cl_vwep
Definition: main.c:72
cl_chat_notify
cvar_t * cl_chat_notify
Definition: main.c:53
UI_Frame
void UI_Frame(int msec)
Definition: servers.c:681
Cmd_Argc
int Cmd_Argc(void)
Definition: cmd.c:889
add_ignore
static void add_ignore(const char *match)
Definition: main.c:1870
nextRequest
static unsigned nextRequest
Definition: main.c:127
CL_InitDownloads
void CL_InitDownloads(void)
Definition: download.c:937
Prompt_AddMatch
qboolean Prompt_AddMatch(genctx_t *ctx, const char *s)
Definition: prompt.c:149
CL_Connect_c
static void CL_Connect_c(genctx_t *ctx, int argnum)
Definition: main.c:492
Q_strchrnul
char * Q_strchrnul(const char *s, int c)
Definition: shared.c:879
net_from
netadr_t net_from
Definition: net.c:90
client_static_s::fps
int fps[4]
Definition: client.h:404
CL_Pps_m
static size_t CL_Pps_m(char *buffer, size_t size)
Definition: main.c:2290
r_maxfps
cvar_t * r_maxfps
Definition: main.c:33
CL_PLAYER_MODEL_DISABLED
#define CL_PLAYER_MODEL_DISABLED
Definition: client.h:553
client_static_s::recording
qhandle_t recording
Definition: client.h:454
Cmd_ExecuteCommand
void Cmd_ExecuteCommand(cmdbuf_t *buf)
Definition: cmd.c:1645
CL_IgnoreText_f
static void CL_IgnoreText_f(void)
Definition: main.c:1920
CL_FollowIP_f
static void CL_FollowIP_f(void)
Definition: main.c:584
cl_gibs
cvar_t * cl_gibs
Definition: main.c:63
CL_RegisterBspModels
void CL_RegisterBspModels(void)
Definition: precache.c:226
CL_Disconnect_f
static void CL_Disconnect_f(void)
Definition: main.c:809
CL_FixUpGender
static void CL_FixUpGender(void)
Definition: main.c:1633
CL_Activate
void CL_Activate(active_t active)
Definition: main.c:2905
CL_PlaySound_f
static void CL_PlaySound_f(void)
Definition: main.c:1731
FS_FOpenFile
ssize_t FS_FOpenFile(const char *name, qhandle_t *f, unsigned mode)
Definition: files.c:1692
cl_nolerp
cvar_t * cl_nolerp
Definition: main.c:39
R_Init
qboolean R_Init(qboolean total)
Definition: main.c:234
client_static_s::userinfo_updates
cvar_t * userinfo_updates[MAX_PACKET_USERINFOS]
Definition: client.h:384
cmd_buffer
cmdbuf_t cmd_buffer
Definition: cmd.c:49
CL_PlaySound_c
static void CL_PlaySound_c(genctx_t *ctx, int state)
Definition: main.c:1726
rcon_password
cvar_t * rcon_password
Definition: common.c:114
cl_protocol
cvar_t * cl_protocol
Definition: main.c:68
Com_Generic_c
void Com_Generic_c(genctx_t *ctx, int argnum)
Definition: common.c:748
clientinfo_s::name
char name[MAX_QPATH]
Definition: client.h:113
client_state_s::sendPacketNow
qboolean sendPacketNow
Definition: client.h:180
NET_GetPackets
void NET_GetPackets(netsrc_t sock, void(*packet_cb)(void))
Definition: net.c:895
client_static_s::challenge
int challenge
Definition: client.h:425
ca_precached
@ ca_precached
Definition: client.h:339
client_state_s::refdef
refdef_t refdef
Definition: client.h:253
com_version
cvar_t * com_version
Definition: common.c:84
Cmd_ArgsFrom
char * Cmd_ArgsFrom(int from)
Definition: cmd.c:981
HTTP_Shutdown
void HTTP_Shutdown(void)
Definition: http.c:458
CL_ClientCommand
void CL_ClientCommand(const char *string)
Definition: main.c:299
ref_extra
static int ref_extra
Definition: main.c:3117
Com_Error
void Com_Error(error_type_t type, const char *fmt,...)
Definition: g_main.c:258
BSP_Free
void BSP_Free(bsp_t *bsp)
Definition: bsp.c:932
client_state_s::clientNum
int clientNum
Definition: client.h:278
dedicated
cvar_t * dedicated
Definition: g_main.c:46
CL_GTV_Init
void CL_GTV_Init(void)
Definition: gtv.c:580
gl_modulate_entities
cvar_t * gl_modulate_entities
Definition: main.c:50
R_FPS
#define R_FPS
Definition: client.h:394
CL_ShutdownRefresh
void CL_ShutdownRefresh(void)
Definition: refresh.c:375
S_Shutdown
void S_Shutdown(void)
Definition: main.c:241
ignore_t::match
char match[1]
Definition: main.c:1836
CL_RestartRefresh_f
static void CL_RestartRefresh_f(void)
Definition: main.c:2554
M_FRAMES
#define M_FRAMES
Definition: client.h:399
cl_async
cvar_t * cl_async
Definition: main.c:32
list_ignores
static void list_ignores(void)
Definition: main.c:1854
Cmd_ParseOptions
int Cmd_ParseOptions(const cmd_option_t *opt)
Definition: cmd.c:1057
SCR_RegisterMedia
void SCR_RegisterMedia(void)
Definition: screen.c:1297
msg_write
sizebuf_t msg_write
Definition: msg.c:34
NET_ErrorString
const char * NET_ErrorString(void)
Definition: net.c:659
CL_Fps_m
static size_t CL_Fps_m(char *buffer, size_t size)
Definition: main.c:2275
client_static_s::frames_read
int frames_read
Definition: client.h:461
cl_footsteps_changed
static void cl_footsteps_changed(cvar_t *self)
Definition: main.c:2611
client_static_s::userinfo_modified
int userinfo_modified
Definition: client.h:383
CL_DemoFrame
void CL_DemoFrame(int msec)
Definition: demo.c:1223
cl_disconnectcmd
cvar_t * cl_disconnectcmd
Definition: main.c:59
SCR_LagSample
void SCR_LagSample(void)
Definition: screen.c:537
va
char * va(const char *format,...)
Definition: shared.c:429
FS_File_g
void FS_File_g(const char *path, const char *ext, unsigned flags, genctx_t *ctx)
Definition: files.c:2954
Z_Free
void Z_Free(void *ptr)
Definition: zone.c:147
REQ_RCON
@ REQ_RCON
Definition: main.c:114
CL_ConnectionlessPacket
static void CL_ConnectionlessPacket(void)
Definition: main.c:1315
SortPlayers
static int SortPlayers(const void *v1, const void *v2)
Definition: main.c:864
CL_ClearEffects
void CL_ClearEffects(void)
Definition: effects.c:2067
request_t::time
unsigned time
Definition: main.c:120
client_static_s::serverProtocol
int serverProtocol
Definition: client.h:422
client_state_s::layout
char layout[MAX_NET_STRING]
Definition: client.h:269
CL_Ups_m
static size_t CL_Ups_m(char *buffer, size_t size)
Definition: main.c:2221
cl_cmdbuf
cmdbuf_t cl_cmdbuf
Definition: main.c:104
cl_gun
cvar_t * cl_gun
Definition: main.c:29
Cmd_Register
void Cmd_Register(const cmdreg_t *reg)
Definition: cmd.c:1572
cl_chat_filter
cvar_t * cl_chat_filter
Definition: main.c:55
clientinfo_s::model_name
char model_name[MAX_QPATH]
Definition: client.h:116
MSG_ReadLong
int MSG_ReadLong(void)
Definition: msg.c:1517
requestType_t
requestType_t
Definition: main.c:109
CONNECT_DELAY
#define CONNECT_DELAY
Definition: client.h:327
CL_PLAYER_MODEL_FIRST_PERSON
#define CL_PLAYER_MODEL_FIRST_PERSON
Definition: client.h:555
CL_DemoPos_m
static size_t CL_DemoPos_m(char *buffer, size_t size)
Definition: main.c:2256
main_msec
static int main_msec
Definition: main.c:3116
CL_HdrColor_m
static size_t CL_HdrColor_m(char *buffer, size_t size)
Definition: main.c:2363
Com_Address_g
void Com_Address_g(genctx_t *ctx)
Definition: common.c:729
CL_ResolutionScale_m
static size_t CL_ResolutionScale_m(char *buffer, size_t size)
Definition: main.c:2369
S_Init
void S_Init(void)
Definition: main.c:148
cl_explosion_frametime
cvar_t * cl_explosion_frametime
Definition: main.c:57
phys_extra
static int phys_extra
Definition: main.c:3117
client_state_s::baseclientinfo
clientinfo_t baseclientinfo
Definition: client.h:309
CL_UnIgnoreNick_f
static void CL_UnIgnoreNick_f(void)
Definition: main.c:2017
cl_noglow
cvar_t * cl_noglow
Definition: main.c:38
client_state_s::time
int time
Definition: client.h:244
CL_ClearState
void CL_ClearState(void)
Definition: main.c:699
client_history_t::sent
unsigned sent
Definition: client.h:123
ASYNC_FULL
@ ASYNC_FULL
Definition: main.c:3100
cl_player_model
cvar_t * cl_player_model
Definition: main.c:47
CL_Skins_f
static void CL_Skins_f(void)
Definition: main.c:1229
fs_game
cvar_t * fs_game
Definition: files.c:202
CL_Server_m
static size_t CL_Server_m(char *buffer, size_t size)
Definition: main.c:2216
Cvar_VariableInteger
int Cvar_VariableInteger(const char *var_name)
Definition: cvar.c:105
CL_InitDemos
void CL_InitDemos(void)
Definition: demo.c:1273
NET_StringToAdr
qboolean NET_StringToAdr(const char *s, netadr_t *a, int default_port)
Definition: net.c:332
CL_PredictMovement
void CL_PredictMovement(void)
Definition: predict.c:175
client_static_s::servername
char servername[MAX_OSPATH]
Definition: client.h:410
NET_Config
void NET_Config(netflag_t flag)
Definition: net.c:1312
Q_strlcpy
size_t Q_strlcpy(char *dst, const char *src, size_t size)
Definition: shared.c:715
Com_LPrintf
void Com_LPrintf(print_type_t type, const char *fmt,...)
Definition: g_main.c:242
Con_Close
void Con_Close(qboolean force)
Definition: console.c:124
CL_UpdateGibSetting
static void CL_UpdateGibSetting(void)
Definition: main.c:203
C_MPS
#define C_MPS
Definition: client.h:395
request_t::type
requestType_t type
Definition: main.c:118
cl_entities
centity_t cl_entities[MAX_EDICTS]
Definition: main.c:101
Info_Print
void Info_Print(const char *infostring)
Definition: shared.c:1235
ASYNC_VIDEO
@ ASYNC_VIDEO
Definition: main.c:3098
CL_PingServers_f
static void CL_PingServers_f(void)
Definition: main.c:1183
MSG_WriteShort
void MSG_WriteShort(int c)
Definition: msg.c:125
request_t::adr
netadr_t adr
Definition: main.c:119
CL_IgnoreNick_c
static void CL_IgnoreNick_c(genctx_t *ctx, int argnum)
Definition: main.c:1950
client_state_s::clientinfo
clientinfo_t clientinfo[MAX_CLIENTS]
Definition: client.h:308
CL_ParseStatusResponse
static void CL_ParseStatusResponse(serverStatus_t *status, const char *string)
Definition: main.c:877
UI_Shutdown
void UI_Shutdown(void)
Definition: ui.c:674
CL_Mps_m
static size_t CL_Mps_m(char *buffer, size_t size)
Definition: main.c:2285
UI_OpenMenu
void UI_OpenMenu(uiMenu_t type)
Definition: ui.c:208
client_state_s::mapname
char mapname[MAX_QPATH]
Definition: client.h:290
CL_WriteConfig_f
static void CL_WriteConfig_f(void)
Definition: main.c:2137
cl_autopause
cvar_t * cl_autopause
Definition: main.c:34
CL_CheckForPause
void CL_CheckForPause(void)
Definition: main.c:3056
CL_CheatsOK
qboolean CL_CheatsOK(void)
Definition: main.c:2871
com_localTime
unsigned com_localTime
Definition: common.c:123
REQ_STATUS_CL
@ REQ_STATUS_CL
Definition: main.c:111
centity_s
Definition: client.h:85
cl_noskins
cvar_t * cl_noskins
Definition: main.c:25
cl_vwep_changed
static void cl_vwep_changed(cvar_t *self)
Definition: main.c:1275
NET_GetAddress
qboolean NET_GetAddress(netsrc_t sock, netadr_t *adr)
Definition: net.c:1358
CL_GetResolutionScale
int CL_GetResolutionScale()
Definition: main.c:2379
server_frame_t::clientNum
int clientNum
Definition: client.h:138
REQUEST_MASK
#define REQUEST_MASK
Definition: main.c:124
Q_strcasecmp
int Q_strcasecmp(const char *s1, const char *s2)
Definition: shared.c:666
client_static_s::frametime
float frametime
Definition: client.h:390
Con_PostInit
void Con_PostInit(void)
Definition: console.c:479
phys_msec
static int phys_msec
Definition: main.c:3116
CL_Material_m
static size_t CL_Material_m(char *buffer, size_t size)
Definition: main.c:2343
S_StartLocalSound
void S_StartLocalSound(const char *sound)
Definition: main.c:911
CL_Frame
unsigned CL_Frame(unsigned msec)
Definition: main.c:3204
info_name
cvar_t * info_name
Definition: main.c:81
COM_IsUint
qboolean COM_IsUint(const char *s)
Definition: shared.c:330
exec_server_string
static void exec_server_string(cmdbuf_t *buf, const char *text)
Definition: main.c:2560
CL_ReloadRefresh_f
static void CL_ReloadRefresh_f(void)
Definition: main.c:2542
ca_cinematic
@ ca_cinematic
Definition: client.h:341
MSG_WriteString
void MSG_WriteString(const char *string)
Definition: msg.c:160
cl_chat_sound_changed
static void cl_chat_sound_changed(cvar_t *self)
Definition: main.c:2644
IN_Frame
void IN_Frame(void)
Definition: input.c:140
CL_WriteConfig
void CL_WriteConfig(void)
Definition: main.c:2391
client_state_s
Definition: client.h:174
client_state_s::timeoutcount
int timeoutcount
Definition: client.h:175
CL_PrepRefresh
void CL_PrepRefresh(void)
Definition: precache.c:333
CL_RequestNextDownload
void CL_RequestNextDownload(void)
Definition: download.c:735
CL_WriteDemoMessage
qboolean CL_WriteDemoMessage(sizebuf_t *buf)
Definition: demo.c:41
Cvar_FixCheats
void Cvar_FixCheats(void)
Definition: cvar.c:601
client_static_s::recent_addr
netadr_t recent_addr[RECENT_ADDR]
Definition: client.h:434
CL_CheckForResend
void CL_CheckForResend(void)
Definition: main.c:387
cl_ignores
static list_t cl_ignores
Definition: main.c:1839
client_state_s::initialSeq
int initialSeq
Definition: client.h:187
cl_footsteps
cvar_t * cl_footsteps
Definition: main.c:26
ca_challenging
@ ca_challenging
Definition: client.h:335
Cvar_ClampInteger
int Cvar_ClampInteger(cvar_t *var, int min, int max)
Definition: cvar.c:549
client_history_t::rcvd
unsigned rcvd
Definition: client.h:124
client_static_s::download
struct client_static_s::@2 download
MSG_ReadString
size_t MSG_ReadString(char *dest, size_t size)
Definition: msg.c:1531
client_static_s::ping
int ping
Definition: client.h:405
CL_FindRequest
static request_t * CL_FindRequest(void)
Definition: main.c:141
CL_DumpStatusbar_f
static void CL_DumpStatusbar_f(void)
Definition: main.c:2108
server_frame_t::ps
player_state_t ps
Definition: client.h:137
CL_FRAMETIME
#define CL_FRAMETIME
Definition: client.h:161
cl_predict
cvar_t * cl_predict
Definition: main.c:28
cl_rollhack
cvar_t * cl_rollhack
Definition: main.c:37
CL_UpdatePredictSetting
static void CL_UpdatePredictSetting(void)
Definition: main.c:233
S_FreeAllSounds
void S_FreeAllSounds(void)
Definition: main.c:226
CL_CalcViewValues
void CL_CalcViewValues(void)
Definition: entities.c:1251
S_Activate
void S_Activate(void)
Definition: main.c:272
CL_Connect_f
static void CL_Connect_f(void)
Definition: main.c:512
Key_WriteBindings
void Key_WriteBindings(qhandle_t f)
Definition: keys.c:475
S_Update
void S_Update(void)
Definition: main.c:1080
client_static_s::recent_head
int recent_head
Definition: client.h:435
CL_FinalizeCmd
void CL_FinalizeCmd(void)
Definition: input.c:790
cl_disable_explosions
cvar_t * cl_disable_explosions
Definition: main.c:52
client_static_s::measure
struct client_static_s::@1 measure
info_gender
cvar_t * info_gender
Definition: main.c:87
Cbuf_Execute
void Cbuf_Execute(cmdbuf_t *buf)
Definition: cmd.c:152
client_history_t
Definition: client.h:122
Cmd_ArgvBuffer
size_t Cmd_ArgvBuffer(int arg, char *buffer, size_t size)
Definition: cmd.c:912
client.h
SYNC_MAXFPS
@ SYNC_MAXFPS
Definition: main.c:3094
CL_RegisterSounds
void CL_RegisterSounds(void)
Definition: precache.c:203
Cmd_PrintHelp
void Cmd_PrintHelp(const cmd_option_t *opt)
Definition: cmd.c:1160
Cmd_Option_c
void Cmd_Option_c(const cmd_option_t *opt, xgenerator_t g, genctx_t *ctx, int argnum)
Definition: cmd.c:1183
CL_ParsePrintMessage
static void CL_ParsePrintMessage(void)
Definition: main.c:939
cl_predict_changed
static void cl_predict_changed(cvar_t *self)
Definition: main.c:2616
cl_sync_changed
static void cl_sync_changed(cvar_t *self)
Definition: main.c:2628
client_static_s::disable_screen
unsigned disable_screen
Definition: client.h:381
Cmd_PrintHint
void Cmd_PrintHint(void)
Definition: cmd.c:1178
CL_ResetPrecacheCheck
void CL_ResetPrecacheCheck(void)
Definition: download.c:897
REQ_INFO
@ REQ_INFO
Definition: main.c:113
CL_Rcon_c
static void CL_Rcon_c(genctx_t *ctx, int argnum)
Definition: main.c:688
clientinfo_s::skin_name
char skin_name[MAX_QPATH]
Definition: client.h:117
Con_Popup
void Con_Popup(qboolean force)
Definition: console.c:152
CL_RestartSound_f
static void CL_RestartSound_f(void)
Definition: main.c:1712
fps_to_msec
static int fps_to_msec(int fps)
Definition: main.c:3120
allow_download
cvar_t * allow_download
Definition: common.c:105
CL_RunRefresh
void CL_RunRefresh(void)
Definition: refresh.c:232
CL_ForwardToServer_f
static void CL_ForwardToServer_f(void)
Definition: main.c:339
parse_ignore_nick
static size_t parse_ignore_nick(int argnum, char *buffer)
Definition: main.c:1958
CL_UpdateFrameTimes
void CL_UpdateFrameTimes(void)
Definition: main.c:3136
o_writeconfig
static const cmd_option_t o_writeconfig[]
Definition: main.c:2118
ca_connecting
@ ca_connecting
Definition: client.h:336
cls
client_static_t cls
Definition: main.c:98
SCR_ClearChatHUD_f
void SCR_ClearChatHUD_f(void)
Definition: screen.c:897
cl_maxfps
cvar_t * cl_maxfps
Definition: main.c:31
CL_Changing_f
static void CL_Changing_f(void)
Definition: main.c:1070
ignore_t
Definition: main.c:1833
client_static_s::realtime
unsigned realtime
Definition: client.h:389
SCR_BeginLoadingPlaque
void SCR_BeginLoadingPlaque(void)
Definition: screen.c:1424
ignore_t::hits
unsigned hits
Definition: main.c:1835
SHOWCLAMP
#define SHOWCLAMP(...)
Definition: client.h:532
ca_loading
@ ca_loading
Definition: client.h:338
Cmd_AddMacro
void Cmd_AddMacro(const char *name, xmacro_t function)
Definition: cmd.c:770
COM_Parse
char * COM_Parse(const char **data_p)
Definition: shared.c:455
sv_running
cvar_t * sv_running
Definition: common.c:95
info_skin
cvar_t * info_skin
Definition: main.c:82
Cvar_FindVar
cvar_t * Cvar_FindVar(const char *var_name)
Definition: cvar.c:45
CL_CleanupDownloads
void CL_CleanupDownloads(void)
Definition: download.c:136
FS_EasyWriteFile
qboolean FS_EasyWriteFile(char *buf, size_t size, unsigned mode, const char *dir, const char *name, const char *ext, const void *data, size_t len)
Definition: files.c:1960
COM_DefaultExtension
size_t COM_DefaultExtension(char *path, const char *ext, size_t size)
Definition: shared.c:279
color
static vec4_t color
Definition: mesh.c:33
client_state_s::history
client_history_t history[CMD_BACKUP]
Definition: client.h:186
CL_UpdateGunSetting
static void CL_UpdateGunSetting(void)
Definition: main.c:180
CL_LoadState
void CL_LoadState(load_state_t state)
Definition: console.c:541
CL_LoadClientinfo
void CL_LoadClientinfo(clientinfo_t *ci, const char *s)
Definition: precache.c:104
cl
client_state_t cl
Definition: main.c:99
CONNECT_FAST
#define CONNECT_FAST
Definition: client.h:330
Netchan_Close
void Netchan_Close(netchan_t *netchan)
Definition: chan.c:866
rcon_address
cvar_t * rcon_address
Definition: main.c:23
CL_Ammo_m
static size_t CL_Ammo_m(char *buffer, size_t size)
Definition: main.c:2312
MSG_ReadStringLine
size_t MSG_ReadStringLine(char *dest, size_t size)
Definition: msg.c:1553
C_FPS
#define C_FPS
Definition: client.h:393
FS_FCloseFile
void FS_FCloseFile(qhandle_t f)
Definition: files.c:759
CL_WeaponModel_m
static size_t CL_WeaponModel_m(char *buffer, size_t size)
Definition: main.c:2322
LOC_LoadLocations
void LOC_LoadLocations(void)
Definition: locs.c:59
CL_Pause_f
static void CL_Pause_f(void)
Definition: main.c:361
cl_kickangles
cvar_t * cl_kickangles
Definition: main.c:36
CONNECT_INSTANT
#define CONNECT_INSTANT
Definition: client.h:329
client_static_s::serverAddress
netadr_t serverAddress
Definition: client.h:409
CL_AddRequest
static request_t * CL_AddRequest(const netadr_t *adr, requestType_t type)
Definition: main.c:129
RECENT_MASK
#define RECENT_MASK
Definition: client.h:432
CL_MeasureStats
static void CL_MeasureStats(void)
Definition: main.c:2967
CL_Material_Override_m
static size_t CL_Material_Override_m(char *buffer, size_t size)
Definition: main.c:2348
CL_Reconnect_f
static void CL_Reconnect_f(void)
Definition: main.c:1121
LOAD_MAP
@ LOAD_MAP
Definition: client.h:608
client_state_s::maxclients
int maxclients
Definition: client.h:279
CL_CleanupDemos
void CL_CleanupDemos(void)
Definition: demo.c:1179
CL_PassiveConnect_f
static void CL_PassiveConnect_f(void)
Definition: main.c:611
client_static_s::protocolVersion
int protocolVersion
Definition: client.h:423
Key_ClearStates
void Key_ClearStates(void)
Definition: keys.c:875
gl_brightness
cvar_t * gl_brightness
Definition: main.c:45
cl_thirdperson_range
cvar_t * cl_thirdperson_range
Definition: main.c:49
CL_UpdateUserinfo
void CL_UpdateUserinfo(cvar_t *var, from_t from)
Definition: main.c:1650
cl_beginmapcmd
cvar_t * cl_beginmapcmd
Definition: main.c:61
info_hand
cvar_t * info_hand
Definition: main.c:86
precache_spawncount
static int precache_spawncount
Definition: main.c:1748
CL_Name_g
static void CL_Name_g(genctx_t *ctx)
Definition: main.c:1285
CL_GTV_Transmit
void CL_GTV_Transmit(void)
Definition: gtv.c:278
sync_mode
static sync_mode_t sync_mode
Definition: main.c:3118
SYNC_SLEEP_60
@ SYNC_SLEEP_60
Definition: main.c:3096
CL_RestartRefresh
void CL_RestartRefresh(qboolean total)
Definition: main.c:2483
Q_scnprintf
size_t Q_scnprintf(char *dest, size_t size, const char *fmt,...)
Definition: shared.c:867
Con_Shutdown
void Con_Shutdown(void)
Definition: console.c:491
REQ_STATUS_UI
@ REQ_STATUS_UI
Definition: main.c:112
client_static_s::framecount
int framecount
Definition: client.h:388
CL_ViewDir_m
static size_t CL_ViewDir_m(char *buffer, size_t size)
Definition: main.c:2358
com_framenum
unsigned com_framenum
Definition: common.c:121
client_static_s::netchan
netchan_t * netchan
Definition: client.h:421
IN_Shutdown
void IN_Shutdown(void)
Definition: input.c:173
clientRequests
static request_t clientRequests[MAX_REQUESTS]
Definition: main.c:126
CL_DumpLayout_f
static void CL_DumpLayout_f(void)
Definition: main.c:2113
CL_ParseServerMessage
void CL_ParseServerMessage(void)
Definition: parse.c:1168
VID_VideoWait
void VID_VideoWait(void)
Definition: glimp.c:496
Con_RegisterMedia
void Con_RegisterMedia(void)
Definition: console.c:628
CL_Rcon_f
static void CL_Rcon_f(void)
Definition: main.c:655
CL_CheckTimeout
static void CL_CheckTimeout(void)
Definition: main.c:3022
CL_Cluster_m
static size_t CL_Cluster_m(char *buffer, size_t size)
Definition: main.c:2328
C_PPS
#define C_PPS
Definition: client.h:396
cl_gunalpha
cvar_t * cl_gunalpha
Definition: main.c:30
CL_ServerStatus_f
static void CL_ServerStatus_f(void)
Definition: main.c:829
SZ_Clear
void SZ_Clear(sizebuf_t *buf)
Definition: sizebuf.c:40
CL_FRAMESYNC
#define CL_FRAMESYNC
Definition: client.h:164
ref_msec
static int ref_msec
Definition: main.c:3116
clientinfo_s
Definition: client.h:112
CL_UpdateRecordingSetting
void CL_UpdateRecordingSetting(void)
Definition: main.c:265
VID_VideoSync
qboolean VID_VideoSync(void)
Definition: glimp.c:500
CL_InitLocal
static void CL_InitLocal(void)
Definition: main.c:2708
C_FRAMES
#define C_FRAMES
Definition: client.h:397
CL_InitEffects
void CL_InitEffects(void)
Definition: effects.c:2075
COM_strclr
size_t COM_strclr(char *s)
Definition: shared.c:398
client_static_s::paused
qboolean paused
Definition: client.h:468
Cmd_RawArgs
char * Cmd_RawArgs(void)
Definition: cmd.c:951
c_client
static const cmdreg_t c_client[]
Definition: main.c:2656
info_spectator
cvar_t * info_spectator
Definition: main.c:80