Quake II RTX doxygen  1.0 dev
user.c
Go to the documentation of this file.
1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
3 
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13 
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18 // sv_user.c -- server code for moving users
19 
20 #include "server.h"
21 
22 /*
23 ============================================================
24 
25 USER STRINGCMD EXECUTION
26 
27 sv_client and sv_player will be valid.
28 ============================================================
29 */
30 
31 /*
32 ================
33 SV_CreateBaselines
34 
35 Entity baselines are used to compress the update messages
36 to the clients -- only the fields that differ from the
37 baseline will be transmitted
38 ================
39 */
40 static void create_baselines(void)
41 {
42  int i;
43  edict_t *ent;
44  entity_packed_t *base, **chunk;
45 
46  // clear baselines from previous level
47  for (i = 0; i < SV_BASELINES_CHUNKS; i++) {
48  base = sv_client->baselines[i];
49  if (!base) {
50  continue;
51  }
52  memset(base, 0, sizeof(*base) * SV_BASELINES_PER_CHUNK);
53  }
54 
55  for (i = 1; i < sv_client->pool->num_edicts; i++) {
56  ent = EDICT_POOL(sv_client, i);
57 
58  if ((g_features->integer & GMF_PROPERINUSE) && !ent->inuse) {
59  continue;
60  }
61 
62  if (!ES_INUSE(&ent->s)) {
63  continue;
64  }
65 
66  ent->s.number = i;
67 
68  chunk = &sv_client->baselines[i >> SV_BASELINES_SHIFT];
69  if (*chunk == NULL) {
70  *chunk = SV_Mallocz(sizeof(*base) * SV_BASELINES_PER_CHUNK);
71  }
72 
73  base = *chunk + (i & SV_BASELINES_MASK);
74  MSG_PackEntity(base, &ent->s, Q2PRO_SHORTANGLES(sv_client, i));
75 
76 #if USE_MVD_CLIENT
77  if (sv.state == ss_broadcast) {
78  // spectators only need to know about inline BSP models
79  if (base->solid != PACKED_BSP)
80  base->solid = 0;
81  } else
82 #endif
83  if (sv_client->esFlags & MSG_ES_LONGSOLID) {
84  base->solid = sv.entities[i].solid32;
85  }
86  }
87 }
88 
89 static void write_plain_configstrings(void)
90 {
91  int i;
92  char *string;
93  size_t length;
94 
95  // write a packet full of data
96  string = sv_client->configstrings;
97  for (i = 0; i < MAX_CONFIGSTRINGS; i++, string += MAX_QPATH) {
98  if (!string[0]) {
99  continue;
100  }
101  length = strlen(string);
102  if (length > MAX_QPATH) {
103  length = MAX_QPATH;
104  }
105  // check if this configstring will overflow
106  if (msg_write.cursize + length + 64 > sv_client->netchan->maxpacketlen) {
108  }
109 
110  MSG_WriteByte(svc_configstring);
111  MSG_WriteShort(i);
112  MSG_WriteData(string, length);
113  MSG_WriteByte(0);
114  }
115 
117 }
118 
119 static void write_baseline(entity_packed_t *base)
120 {
121  msgEsFlags_t flags = sv_client->esFlags | MSG_ES_FORCE;
122 
123  if (Q2PRO_SHORTANGLES(sv_client, base->number)) {
124  flags |= MSG_ES_SHORTANGLES;
125  }
126 
127  MSG_WriteDeltaEntity(NULL, base, flags);
128 }
129 
130 static void write_plain_baselines(void)
131 {
132  int i, j;
133  entity_packed_t *base;
134 
135  // write a packet full of data
136  for (i = 0; i < SV_BASELINES_CHUNKS; i++) {
137  base = sv_client->baselines[i];
138  if (!base) {
139  continue;
140  }
141  for (j = 0; j < SV_BASELINES_PER_CHUNK; j++) {
142  if (base->number) {
143  // check if this baseline will overflow
144  if (msg_write.cursize + 64 > sv_client->netchan->maxpacketlen) {
146  }
147 
148  MSG_WriteByte(svc_spawnbaseline);
149  write_baseline(base);
150  }
151  base++;
152  }
153  }
154 
156 }
157 
158 #if USE_ZLIB
159 
160 static void write_compressed_gamestate(void)
161 {
162  sizebuf_t *buf = &sv_client->netchan->message;
163  entity_packed_t *base;
164  int i, j;
165  size_t length;
166  uint8_t *patch;
167  char *string;
168 
169  MSG_WriteByte(svc_gamestate);
170 
171  // write configstrings
172  string = sv_client->configstrings;
173  for (i = 0; i < MAX_CONFIGSTRINGS; i++, string += MAX_QPATH) {
174  if (!string[0]) {
175  continue;
176  }
177  length = strlen(string);
178  if (length > MAX_QPATH) {
179  length = MAX_QPATH;
180  }
181 
182  MSG_WriteShort(i);
183  MSG_WriteData(string, length);
184  MSG_WriteByte(0);
185  }
186  MSG_WriteShort(MAX_CONFIGSTRINGS); // end of configstrings
187 
188  // write baselines
189  for (i = 0; i < SV_BASELINES_CHUNKS; i++) {
190  base = sv_client->baselines[i];
191  if (!base) {
192  continue;
193  }
194  for (j = 0; j < SV_BASELINES_PER_CHUNK; j++) {
195  if (base->number) {
196  write_baseline(base);
197  }
198  base++;
199  }
200  }
201  MSG_WriteShort(0); // end of baselines
202 
203  SZ_WriteByte(buf, svc_zpacket);
204  patch = SZ_GetSpace(buf, 2);
205  SZ_WriteShort(buf, msg_write.cursize);
206 
207  deflateReset(&svs.z);
208  svs.z.next_in = msg_write.data;
209  svs.z.avail_in = (uInt)msg_write.cursize;
210  svs.z.next_out = buf->data + buf->cursize;
211  svs.z.avail_out = (uInt)(buf->maxsize - buf->cursize);
213 
214  if (deflate(&svs.z, Z_FINISH) != Z_STREAM_END) {
215  SV_DropClient(sv_client, "deflate() failed on gamestate");
216  return;
217  }
218 
219  SV_DPrintf(0, "%s: comp: %lu into %lu\n",
220  sv_client->name, svs.z.total_in, svs.z.total_out);
221 
222  patch[0] = svs.z.total_out & 255;
223  patch[1] = (svs.z.total_out >> 8) & 255;
224  buf->cursize += svs.z.total_out;
225 }
226 
227 static inline int z_flush(byte *buffer)
228 {
229  int ret;
230 
231  ret = deflate(&svs.z, Z_FINISH);
232  if (ret != Z_STREAM_END) {
233  return ret;
234  }
235 
236  SV_DPrintf(0, "%s: comp: %lu into %lu\n",
237  sv_client->name, svs.z.total_in, svs.z.total_out);
238 
239  MSG_WriteByte(svc_zpacket);
240  MSG_WriteShort(svs.z.total_out);
241  MSG_WriteShort(svs.z.total_in);
242  MSG_WriteData(buffer, svs.z.total_out);
243 
245 
246  return ret;
247 }
248 
249 static inline void z_reset(byte *buffer)
250 {
251  deflateReset(&svs.z);
252  svs.z.next_out = buffer;
253  svs.z.avail_out = (uInt)(sv_client->netchan->maxpacketlen - 5);
254 }
255 
256 static void write_compressed_configstrings(void)
257 {
258  int i;
259  size_t length;
260  byte buffer[MAX_PACKETLEN_WRITABLE];
261  char *string;
262 
263  z_reset(buffer);
264 
265  // write a packet full of data
266  string = sv_client->configstrings;
267  for (i = 0; i < MAX_CONFIGSTRINGS; i++, string += MAX_QPATH) {
268  if (!string[0]) {
269  continue;
270  }
271  length = strlen(string);
272  if (length > MAX_QPATH) {
273  length = MAX_QPATH;
274  }
275 
276  // check if this configstring will overflow
277  if (svs.z.avail_out < length + 32) {
278  // then flush compressed data
279  if (z_flush(buffer) != Z_STREAM_END) {
280  goto fail;
281  }
282  z_reset(buffer);
283  }
284 
285  MSG_WriteByte(svc_configstring);
286  MSG_WriteShort(i);
287  MSG_WriteData(string, length);
288  MSG_WriteByte(0);
289 
290  svs.z.next_in = msg_write.data;
291  svs.z.avail_in = (uInt)msg_write.cursize;
293 
294  if (deflate(&svs.z, Z_SYNC_FLUSH) != Z_OK) {
295  goto fail;
296  }
297  }
298 
299  // finally flush all remaining compressed data
300  if (z_flush(buffer) != Z_STREAM_END) {
301 fail:
302  SV_DropClient(sv_client, "deflate() failed on configstrings");
303  }
304 }
305 
306 #endif // USE_ZLIB
307 
308 static void stuff_cmds(list_t *list)
309 {
310  stuffcmd_t *stuff;
311 
312  LIST_FOR_EACH(stuffcmd_t, stuff, list, entry) {
314  MSG_WriteData(stuff->string, stuff->len);
315  MSG_WriteByte('\n');
316  MSG_WriteByte(0);
318  }
319 }
320 
321 static void stuff_junk(void)
322 {
323  static const char junkchars[] =
324  "!~#``&'()*`+,-./~01~2`3`4~5`67`89:~<=`>?@~ab~c"
325  "d`ef~j~k~lm`no~pq`rst`uv`w``x`yz[`\\]^_`|~";
326  char junk[8][16];
327  int i, j, k;
328 
329  for (i = 0; i < 8; i++) {
330  for (j = 0; j < 15; j++) {
331  k = rand_byte() % (sizeof(junkchars) - 1);
332  junk[i][j] = junkchars[k];
333  }
334  junk[i][15] = 0;
335  }
336 
337  strcpy(sv_client->reconnect_var, junk[2]);
338  strcpy(sv_client->reconnect_val, junk[3]);
339 
340  SV_ClientCommand(sv_client, "set %s set\n", junk[0]);
341  SV_ClientCommand(sv_client, "$%s %s connect\n", junk[0], junk[1]);
342  if (rand_byte() & 1) {
343  SV_ClientCommand(sv_client, "$%s %s %s\n", junk[0], junk[2], junk[3]);
344  SV_ClientCommand(sv_client, "$%s %s %s\n", junk[0], junk[4],
345  sv_force_reconnect->string);
346  SV_ClientCommand(sv_client, "$%s %s %s\n", junk[0], junk[5], junk[6]);
347  } else {
348  SV_ClientCommand(sv_client, "$%s %s %s\n", junk[0], junk[4],
349  sv_force_reconnect->string);
350  SV_ClientCommand(sv_client, "$%s %s %s\n", junk[0], junk[5], junk[6]);
351  SV_ClientCommand(sv_client, "$%s %s %s\n", junk[0], junk[2], junk[3]);
352  }
353  SV_ClientCommand(sv_client, "$%s %s \"\"\n", junk[0], junk[0]);
354  SV_ClientCommand(sv_client, "$%s $%s\n", junk[1], junk[4]);
355 }
356 
357 /*
358 ================
359 SV_New_f
360 
361 Sends the first message from the server to a connected client.
362 This will be sent on the initial connection and upon each server load.
363 ================
364 */
365 void SV_New_f(void)
366 {
367  clstate_t oldstate;
368 
369  Com_DPrintf("New() from %s\n", sv_client->name);
370 
371  oldstate = sv_client->state;
372  if (sv_client->state < cs_connected) {
373  Com_DPrintf("Going from cs_assigned to cs_connected for %s\n",
374  sv_client->name);
376  sv_client->lastmessage = svs.realtime; // don't timeout
377  time(&sv_client->connect_time);
378  } else if (sv_client->state > cs_connected) {
379  Com_DPrintf("New not valid -- already primed\n");
380  return;
381  }
382 
383  // stuff some junk, drop them and expect them to be back soon
384  if (sv_force_reconnect->string[0] && !sv_client->reconnect_var[0] &&
385  !NET_IsLocalAddress(&sv_client->netchan->remote_address)) {
386  stuff_junk();
387  SV_DropClient(sv_client, NULL);
388  return;
389  }
390 
392 
393  //
394  // serverdata needs to go over for all types of servers
395  // to make sure the protocol is right, and to set the gamedir
396  //
397 
398  // create baselines for this client
400 
401  // send the serverdata
402  MSG_WriteByte(svc_serverdata);
405  MSG_WriteByte(0); // no attract loop
407  if (sv.state == ss_pic || sv.state == ss_cinematic)
408  MSG_WriteShort(-1);
409  else
411  MSG_WriteString(&sv_client->configstrings[CS_NAME * MAX_QPATH]);
412 
413  // send protocol specific stuff
414  switch (sv_client->protocol) {
415  case PROTOCOL_VERSION_R1Q2:
416  MSG_WriteByte(0); // not enhanced
418  MSG_WriteByte(0); // no advanced deltas
419  MSG_WriteByte(sv_client->pmp.strafehack);
420  break;
421  case PROTOCOL_VERSION_Q2PRO:
424  MSG_WriteByte(sv_client->pmp.strafehack);
425  MSG_WriteByte(sv_client->pmp.qwmode);
426  if (sv_client->version >= PROTOCOL_VERSION_Q2PRO_WATERJUMP_HACK) {
427  MSG_WriteByte(sv_client->pmp.waterhack);
428  }
429  break;
430  default:
431  break;
432  }
433 
435 
437 
438  // send version string request
439  if (oldstate == cs_assigned) {
440  SV_ClientCommand(sv_client, "cmd \177c version $version\n"
441 #if USE_AC_SERVER
442  "cmd \177c actoken $actoken\n"
443 #endif
444  );
446  }
447 
448  // send reconnect var request
449  if (sv_force_reconnect->string[0] && !sv_client->reconnected) {
450  SV_ClientCommand(sv_client, "cmd \177c connect $%s\n",
452  }
453 
454  Com_DPrintf("Going from cs_connected to cs_primed for %s\n",
455  sv_client->name);
457 
458  memset(&sv_client->lastcmd, 0, sizeof(sv_client->lastcmd));
459 
460  if (sv.state == ss_pic || sv.state == ss_cinematic)
461  return;
462 
463 #if USE_ZLIB
464  if (sv_client->has_zlib) {
465  if (sv_client->netchan->type == NETCHAN_NEW) {
466  write_compressed_gamestate();
467  } else {
468  // FIXME: Z_SYNC_FLUSH is not efficient for baselines
469  write_compressed_configstrings();
471  }
472  } else
473 #endif // USE_ZLIB
474  {
477  }
478 
479  // send next command
480  SV_ClientCommand(sv_client, "precache %i\n", sv_client->spawncount);
481 }
482 
483 /*
484 ==================
485 SV_Begin_f
486 ==================
487 */
488 void SV_Begin_f(void)
489 {
490  Com_DPrintf("Begin() from %s\n", sv_client->name);
491 
492  // handle the case of a level changing while a client was connecting
493  if (sv_client->state < cs_primed) {
494  Com_DPrintf("Begin not valid -- not yet primed\n");
495  SV_New_f();
496  return;
497  }
498  if (sv_client->state > cs_primed) {
499  Com_DPrintf("Begin not valid -- already spawned\n");
500  return;
501  }
502 
503  if (!sv_client->version_string) {
504  SV_DropClient(sv_client, "!failed version probe");
505  return;
506  }
507 
508  if (sv_force_reconnect->string[0] && !sv_client->reconnected) {
509  SV_DropClient(sv_client, "!failed to reconnect");
510  return;
511  }
512 
513  if (!AC_ClientBegin(sv_client)) {
514  return;
515  }
516 
517  Com_DPrintf("Going from cs_primed to cs_spawned for %s\n",
518  sv_client->name);
520  sv_client->send_delta = 0;
521  sv_client->command_msec = 1800;
523  sv_client->http_download = qfalse;
524 
526 
528 
529  // call the game begin function
530  ge->ClientBegin(sv_player);
531 
533 
534  // The server needs to complete the autosave after the client has connected.
535  // See SV_Map (commands.c) for more information.
537  {
538  SV_AutoSaveEnd();
539  sv_pending_autosave = qfalse;
540  }
541 }
542 
543 //=============================================================================
544 
546 {
547  if (client->download) {
548  Z_Free(client->download);
549  client->download = NULL;
550  }
551  if (client->downloadname) {
552  Z_Free(client->downloadname);
553  client->downloadname = NULL;
554  }
555  client->downloadsize = 0;
556  client->downloadcount = 0;
557  client->downloadcmd = 0;
558  client->downloadpending = qfalse;
559 }
560 
561 /*
562 ==================
563 SV_NextDownload_f
564 ==================
565 */
566 static void SV_NextDownload_f(void)
567 {
568  if (!sv_client->download)
569  return;
570 
571  sv_client->downloadpending = qtrue;
572 }
573 
574 /*
575 ==================
576 SV_BeginDownload_f
577 ==================
578 */
579 static void SV_BeginDownload_f(void)
580 {
581  char name[MAX_QPATH];
582  byte *download;
583  int downloadcmd;
584  ssize_t downloadsize, maxdownloadsize, result;
585  int offset = 0;
586  cvar_t *allow;
587  size_t len;
588  qhandle_t f;
589 
590  len = Cmd_ArgvBuffer(1, name, sizeof(name));
591  if (len >= MAX_QPATH) {
592  goto fail1;
593  }
594 
595  // hack for 'status' command
596  if (!strcmp(name, "http")) {
597  sv_client->http_download = qtrue;
598  return;
599  }
600 
601  len = FS_NormalizePath(name, name);
602 
603  if (Cmd_Argc() > 2)
604  offset = atoi(Cmd_Argv(2)); // downloaded offset
605 
606  // hacked by zoid to allow more conrol over download
607  // first off, no .. or global allow check
608  if (!allow_download->integer
609  // check for empty paths
610  || !len
611  // check for illegal negative offsets
612  || offset < 0
613  // don't allow anything with .. path
614  || strstr(name, "..")
615  // leading dots, slashes, etc are no good
616  || !Q_ispath(name[0])
617  // trailing dots, slashes, etc are no good
618  || !Q_ispath(name[len - 1])
619  // MUST be in a subdirectory
620  || !strchr(name, '/')) {
621  Com_DPrintf("Refusing download of %s to %s\n", name, sv_client->name);
622  goto fail1;
623  }
624 
625  if (FS_pathcmpn(name, CONST_STR_LEN("players/")) == 0) {
626  allow = allow_download_players;
627  } else if (FS_pathcmpn(name, CONST_STR_LEN("models/")) == 0 ||
628  FS_pathcmpn(name, CONST_STR_LEN("sprites/")) == 0) {
629  allow = allow_download_models;
630  } else if (FS_pathcmpn(name, CONST_STR_LEN("sound/")) == 0) {
631  allow = allow_download_sounds;
632  } else if (FS_pathcmpn(name, CONST_STR_LEN("maps/")) == 0) {
633  allow = allow_download_maps;
634  } else if (FS_pathcmpn(name, CONST_STR_LEN("textures/")) == 0 ||
635  FS_pathcmpn(name, CONST_STR_LEN("env/")) == 0) {
636  allow = allow_download_textures;
637  } else if (FS_pathcmpn(name, CONST_STR_LEN("pics/")) == 0) {
638  allow = allow_download_pics;
639  } else {
640  allow = allow_download_others;
641  }
642 
643  if (!allow->integer) {
644  Com_DPrintf("Refusing download of %s to %s\n", name, sv_client->name);
645  goto fail1;
646  }
647 
648  if (sv_client->download) {
649  Com_DPrintf("Closing existing download for %s (should not happen)\n", sv_client->name);
651  }
652 
653  f = 0;
654  downloadcmd = svc_download;
655 
656 #if USE_ZLIB
657  // prefer raw deflate stream from .pkz if supported
658  if (sv_client->protocol == PROTOCOL_VERSION_Q2PRO &&
659  sv_client->version >= PROTOCOL_VERSION_Q2PRO_ZLIB_DOWNLOADS &&
660  sv_client->has_zlib && offset == 0) {
661  downloadsize = FS_FOpenFile(name, &f, FS_MODE_READ | FS_FLAG_DEFLATE);
662  if (f) {
663  Com_DPrintf("Serving compressed download to %s\n", sv_client->name);
664  downloadcmd = svc_zdownload;
665  }
666  }
667 #endif
668 
669  if (!f) {
670  downloadsize = FS_FOpenFile(name, &f, FS_MODE_READ);
671  if (!f) {
672  Com_DPrintf("Couldn't download %s to %s\n", name, sv_client->name);
673  goto fail1;
674  }
675  }
676 
677  maxdownloadsize = MAX_LOADFILE;
678 #if 0
679  if (sv_max_download_size->integer) {
680  maxdownloadsize = Cvar_ClampInteger(sv_max_download_size, 1, MAX_LOADFILE);
681  }
682 #endif
683 
684  if (downloadsize == 0) {
685  Com_DPrintf("Refusing empty download of %s to %s\n", name, sv_client->name);
686  goto fail2;
687  }
688 
689  if (downloadsize > maxdownloadsize) {
690  Com_DPrintf("Refusing oversize download of %s to %s\n", name, sv_client->name);
691  goto fail2;
692  }
693 
694  if (offset > downloadsize) {
695  Com_DPrintf("Refusing download, %s has wrong version of %s (%d > %d)\n",
696  sv_client->name, name, offset, (int)downloadsize);
697  SV_ClientPrintf(sv_client, PRINT_HIGH, "File size differs from server.\n"
698  "Please delete the corresponding .tmp file from your system.\n");
699  goto fail2;
700  }
701 
702  if (offset == downloadsize) {
703  Com_DPrintf("Refusing download, %s already has %s (%d bytes)\n",
704  sv_client->name, name, offset);
705  FS_FCloseFile(f);
706  MSG_WriteByte(svc_download);
707  MSG_WriteShort(0);
708  MSG_WriteByte(100);
710  return;
711  }
712 
713  download = SV_Malloc(downloadsize);
714  result = FS_Read(download, downloadsize, f);
715  if (result != downloadsize) {
716  Com_DPrintf("Couldn't download %s to %s\n", name, sv_client->name);
717  goto fail3;
718  }
719 
720  FS_FCloseFile(f);
721 
722  sv_client->download = download;
723  sv_client->downloadsize = downloadsize;
724  sv_client->downloadcount = offset;
726  sv_client->downloadcmd = downloadcmd;
727  sv_client->downloadpending = qtrue;
728 
729  Com_DPrintf("Downloading %s to %s\n", name, sv_client->name);
730  return;
731 
732 fail3:
733  Z_Free(download);
734 fail2:
735  FS_FCloseFile(f);
736 fail1:
737  MSG_WriteByte(svc_download);
738  MSG_WriteShort(-1);
739  MSG_WriteByte(0);
741 }
742 
743 static void SV_StopDownload_f(void)
744 {
745  int percent;
746 
747  if (!sv_client->download)
748  return;
749 
750  percent = sv_client->downloadcount * 100 / sv_client->downloadsize;
751 
752  MSG_WriteByte(svc_download);
753  MSG_WriteShort(-1);
754  MSG_WriteByte(percent);
756 
757  Com_DPrintf("Download of %s to %s stopped by user request\n",
761 }
762 
763 //============================================================================
764 
765 // special hack for end game screen in coop mode
766 static void SV_NextServer_f(void)
767 {
768  char nextserver[MAX_QPATH];
769  char* v = Cvar_VariableString("nextserver");
770  Q_strlcpy(nextserver, v, sizeof(nextserver));
771  Cvar_Set("nextserver", "");
772 
773  if (sv.state != ss_pic && sv.state != ss_cinematic)
774  return; // can't nextserver while playing a normal game
775 
776  if (Cvar_VariableInteger("deathmatch"))
777  return;
778 
779  sv.name[0] = 0; // make sure another doesn't sneak in
780 
781  if (!nextserver[0])
782  {
783  if (Cvar_VariableInteger("coop"))
784  Cbuf_AddText(&cmd_buffer, "gamemap \"*base1\"\n");
785  else
786  Cbuf_AddText(&cmd_buffer, "killserver\n");
787  }
788  else
789  {
790  Cbuf_AddText(&cmd_buffer, nextserver);
791  Cbuf_AddText(&cmd_buffer, "\n");
792  }
793 }
794 
795 // the client is going to disconnect, so remove the connection immediately
796 static void SV_Disconnect_f(void)
797 {
798  SV_DropClient(sv_client, "!?disconnected");
799  SV_RemoveClient(sv_client); // don't bother with zombie state
800 }
801 
802 // dumps the serverinfo info string
803 static void SV_ShowServerInfo_f(void)
804 {
805  char serverinfo[MAX_INFO_STRING];
806 
807  Cvar_BitInfo(serverinfo, CVAR_SERVERINFO);
808 
810  Info_Print(serverinfo);
811  Com_EndRedirect();
812 }
813 
814 // dumps misc protocol info
815 static void SV_ShowMiscInfo_f(void)
816 {
819  Com_EndRedirect();
820 }
821 
822 static void SV_NoGameData_f(void)
823 {
824  sv_client->nodata ^= 1;
826 }
827 
828 static void SV_Lag_f(void)
829 {
830  client_t *cl;
831 
832  if (Cmd_Argc() > 1) {
834  cl = SV_GetPlayer(Cmd_Argv(1), qtrue);
835  Com_EndRedirect();
836  if (!cl) {
837  return;
838  }
839  } else {
840  cl = sv_client;
841  }
842 
843  SV_ClientPrintf(sv_client, PRINT_HIGH,
844  "Lag stats for: %s\n"
845  "RTT (min/avg/max): %d/%d/%d ms\n"
846  "Server to client PL: %.2f%% (approx)\n"
847  "Client to server PL: %.2f%%\n",
848  cl->name, cl->min_ping, AVG_PING(cl), cl->max_ping,
849  PL_S2C(cl), PL_C2S(cl));
850 }
851 
852 #if USE_PACKETDUP
853 static void SV_PacketdupHack_f(void)
854 {
855  int numdups = sv_client->numpackets - 1;
856 
857  if (Cmd_Argc() > 1) {
858  numdups = atoi(Cmd_Argv(1));
859  if (numdups < 0 || numdups > sv_packetdup_hack->integer) {
860  SV_ClientPrintf(sv_client, PRINT_HIGH,
861  "Packetdup of %d is not allowed on this server.\n", numdups);
862  return;
863  }
864 
865  sv_client->numpackets = numdups + 1;
866  }
867 
868  SV_ClientPrintf(sv_client, PRINT_HIGH,
869  "Server is sending %d duplicate packet%s to you.\n",
870  numdups, numdups == 1 ? "" : "s");
871 }
872 #endif
873 
874 static void SV_CvarResult_f(void)
875 {
876  char *c, *v;
877 
878  c = Cmd_Argv(1);
879  if (!strcmp(c, "version")) {
880  if (!sv_client->version_string) {
881  v = Cmd_RawArgsFrom(2);
882  if (COM_DEDICATED) {
883  Com_Printf("%s[%s]: %s\n", sv_client->name,
884  NET_AdrToString(&sv_client->netchan->remote_address), v);
885  }
887  }
888  } else if (!strcmp(c, "connect")) {
889  if (sv_client->reconnect_var[0]) {
890  if (!strcmp(Cmd_Argv(2), sv_client->reconnect_val)) {
891  sv_client->reconnected = qtrue;
892  }
893  }
894  } else if (!strcmp(c, "actoken")) {
896  } else if (!strcmp(c, "console")) {
897  if (sv_client->console_queries > 0) {
898  Com_Printf("%s[%s]: \"%s\" is \"%s\"\n", sv_client->name,
899  NET_AdrToString(&sv_client->netchan->remote_address),
900  Cmd_Argv(2), Cmd_RawArgsFrom(3));
902  }
903  }
904 }
905 
906 static void SV_AC_List_f(void)
907 {
909  AC_List_f();
910  Com_EndRedirect();
911 }
912 
913 static void SV_AC_Info_f(void)
914 {
916  AC_Info_f();
917  Com_EndRedirect();
918 }
919 
920 static const ucmd_t ucmds[] = {
921  // auto issued
922  { "new", SV_New_f },
923  { "begin", SV_Begin_f },
924  { "baselines", NULL },
925  { "configstrings", NULL },
926  { "nextserver", SV_NextServer_f },
927  { "disconnect", SV_Disconnect_f },
928 
929  // issued by hand at client consoles
930  { "info", SV_ShowServerInfo_f },
931  { "sinfo", SV_ShowMiscInfo_f },
932 
933  { "download", SV_BeginDownload_f },
934  { "nextdl", SV_NextDownload_f },
935  { "stopdl", SV_StopDownload_f },
936 
937  { "\177c", SV_CvarResult_f },
938  { "nogamedata", SV_NoGameData_f },
939  { "lag", SV_Lag_f },
940 #if USE_PACKETDUP
941  { "packetdup", SV_PacketdupHack_f },
942 #endif
943  { "aclist", SV_AC_List_f },
944  { "acinfo", SV_AC_Info_f },
945 
946  { NULL, NULL }
947 };
948 
949 static void handle_filtercmd(filtercmd_t *filter)
950 {
951  size_t len;
952 
953  switch (filter->action) {
954  case FA_PRINT:
955  MSG_WriteByte(svc_print);
956  MSG_WriteByte(PRINT_HIGH);
957  break;
958  case FA_STUFF:
960  break;
961  case FA_KICK:
962  SV_DropClient(sv_client, filter->comment[0] ?
963  filter->comment : "issued banned command");
964  // fall through
965  default:
966  return;
967  }
968 
969  len = strlen(filter->comment);
970  MSG_WriteData(filter->comment, len);
971  MSG_WriteByte('\n');
972  MSG_WriteByte(0);
973 
975 }
976 
977 /*
978 ==================
979 SV_ExecuteUserCommand
980 ==================
981 */
982 static void SV_ExecuteUserCommand(const char *s)
983 {
984  const ucmd_t *u;
985  filtercmd_t *filter;
986  char *c;
987 
988  Cmd_TokenizeString(s, qfalse);
990 
991  c = Cmd_Argv(0);
992  if (!c[0]) {
993  return;
994  }
995 
996  if ((u = Com_Find(ucmds, c)) != NULL) {
997  if (u->func) {
998  u->func();
999  }
1000  return;
1001  }
1002 
1003  if (sv.state == ss_pic || sv.state == ss_cinematic) {
1004  return;
1005  }
1006 
1007  if (sv_client->state != cs_spawned && !sv_allow_unconnected_cmds->integer) {
1008  return;
1009  }
1010 
1011  LIST_FOR_EACH(filtercmd_t, filter, &sv_filterlist, entry) {
1012  if (!Q_stricmp(filter->string, c)) {
1013  handle_filtercmd(filter);
1014  return;
1015  }
1016  }
1017 
1018  if (!strcmp(c, "say") || !strcmp(c, "say_team")) {
1019  // don't timeout. only chat commands count as activity.
1021  }
1022 
1023  ge->ClientCommand(sv_player);
1024 }
1025 
1026 /*
1027 ===========================================================================
1028 
1029 USER CMD EXECUTION
1030 
1031 ===========================================================================
1032 */
1033 
1034 static qboolean moveIssued;
1035 static int stringCmdCount;
1037 
1038 /*
1039 ==================
1040 SV_ClientThink
1041 ==================
1042 */
1043 static inline void SV_ClientThink(usercmd_t *cmd)
1044 {
1045  usercmd_t *old = &sv_client->lastcmd;
1046 
1047  sv_client->command_msec -= cmd->msec;
1048  sv_client->num_moves++;
1049 
1050  if (sv_client->command_msec < 0 && sv_enforcetime->integer) {
1051  Com_DPrintf("commandMsec underflow from %s: %d\n",
1053  return;
1054  }
1055 
1056  if (cmd->buttons != old->buttons
1057  || cmd->forwardmove != old->forwardmove
1058  || cmd->sidemove != old->sidemove
1059  || cmd->upmove != old->upmove) {
1060  // don't timeout
1062  }
1063 
1064  ge->ClientThink(sv_player, cmd);
1065 }
1066 
1067 static void SV_SetLastFrame(int lastframe)
1068 {
1069  client_frame_t *frame;
1070 
1071  if (lastframe > 0) {
1072  if (lastframe >= sv_client->framenum)
1073  return; // ignore invalid acks
1074 
1075  if (lastframe <= sv_client->lastframe)
1076  return; // ignore duplicate acks
1077 
1078  if (sv_client->framenum - lastframe <= UPDATE_BACKUP) {
1079  frame = &sv_client->frames[lastframe & UPDATE_MASK];
1080 
1081  if (frame->number == lastframe) {
1082  // save time for ping calc
1083  if (frame->sentTime <= com_eventTime)
1084  frame->latency = com_eventTime - frame->sentTime;
1085  }
1086  }
1087 
1088  // count valid ack
1090  }
1091 
1092  sv_client->lastframe = lastframe;
1093 }
1094 
1095 /*
1096 ==================
1097 SV_OldClientExecuteMove
1098 ==================
1099 */
1100 static void SV_OldClientExecuteMove(void)
1101 {
1102  usercmd_t oldest, oldcmd, newcmd;
1103  int lastframe;
1104  int net_drop;
1105 
1106  if (moveIssued) {
1107  SV_DropClient(sv_client, "multiple clc_move commands in packet");
1108  return; // someone is trying to cheat...
1109  }
1110 
1111  moveIssued = qtrue;
1112 
1113  if (sv_client->protocol == PROTOCOL_VERSION_DEFAULT) {
1114  MSG_ReadByte(); // skip over checksum
1115  }
1116 
1117  lastframe = MSG_ReadLong();
1118 
1119  // read all cmds
1120  if (sv_client->protocol == PROTOCOL_VERSION_R1Q2 &&
1121  sv_client->version >= PROTOCOL_VERSION_R1Q2_UCMD) {
1122  MSG_ReadDeltaUsercmd_Hacked(NULL, &oldest);
1123  MSG_ReadDeltaUsercmd_Hacked(&oldest, &oldcmd);
1124  MSG_ReadDeltaUsercmd_Hacked(&oldcmd, &newcmd);
1125  } else {
1126  MSG_ReadDeltaUsercmd(NULL, &oldest);
1127  MSG_ReadDeltaUsercmd(&oldest, &oldcmd);
1128  MSG_ReadDeltaUsercmd(&oldcmd, &newcmd);
1129  }
1130 
1131  if (sv_client->state != cs_spawned) {
1132  SV_SetLastFrame(-1);
1133  return;
1134  }
1135 
1136  SV_SetLastFrame(lastframe);
1137 
1138  net_drop = sv_client->netchan->dropped;
1139  if (net_drop > 2) {
1140  sv_client->frameflags |= FF_CLIENTPRED;
1141  }
1142 
1143  if (net_drop < 20) {
1144  // run lastcmd multiple times if no backups available
1145  while (net_drop > 2) {
1147  net_drop--;
1148  }
1149 
1150  // run backup cmds
1151  if (net_drop > 1)
1152  SV_ClientThink(&oldest);
1153  if (net_drop > 0)
1154  SV_ClientThink(&oldcmd);
1155  }
1156 
1157  // run new cmd
1158  SV_ClientThink(&newcmd);
1159 
1160  sv_client->lastcmd = newcmd;
1161 }
1162 
1163 /*
1164 ==================
1165 SV_NewClientExecuteMove
1166 ==================
1167 */
1168 static void SV_NewClientExecuteMove(int c)
1169 {
1170  usercmd_t cmds[MAX_PACKET_FRAMES][MAX_PACKET_USERCMDS];
1171  usercmd_t *lastcmd, *cmd;
1172  int lastframe;
1173  int numCmds[MAX_PACKET_FRAMES], numDups;
1174  int i, j, lightlevel;
1175  int net_drop;
1176 
1177  if (moveIssued) {
1178  SV_DropClient(sv_client, "multiple clc_move commands in packet");
1179  return; // someone is trying to cheat...
1180  }
1181 
1182  moveIssued = qtrue;
1183 
1184  numDups = c >> SVCMD_BITS;
1185  c &= SVCMD_MASK;
1186 
1187  if (numDups >= MAX_PACKET_FRAMES) {
1188  SV_DropClient(sv_client, "too many frames in packet");
1189  return;
1190  }
1191 
1192  if (c == clc_move_nodelta) {
1193  lastframe = -1;
1194  } else {
1195  lastframe = MSG_ReadLong();
1196  }
1197 
1198  lightlevel = MSG_ReadByte();
1199 
1200  // read all cmds
1201  lastcmd = NULL;
1202  for (i = 0; i <= numDups; i++) {
1203  numCmds[i] = MSG_ReadBits(5);
1204  if (numCmds[i] == -1) {
1205  SV_DropClient(sv_client, "read past end of message");
1206  return;
1207  }
1208  if (numCmds[i] >= MAX_PACKET_USERCMDS) {
1209  SV_DropClient(sv_client, "too many usercmds in frame");
1210  return;
1211  }
1212  for (j = 0; j < numCmds[i]; j++) {
1213  if (msg_read.readcount > msg_read.cursize) {
1214  SV_DropClient(sv_client, "read past end of message");
1215  return;
1216  }
1217  cmd = &cmds[i][j];
1219  cmd->lightlevel = lightlevel;
1220  lastcmd = cmd;
1221  }
1222  }
1223 
1224  if (sv_client->state != cs_spawned) {
1225  SV_SetLastFrame(-1);
1226  return;
1227  }
1228 
1229  SV_SetLastFrame(lastframe);
1230 
1231  if (q_unlikely(!lastcmd)) {
1232  return; // should never happen
1233  }
1234 
1235  net_drop = sv_client->netchan->dropped;
1236  if (net_drop > numDups) {
1237  sv_client->frameflags |= FF_CLIENTPRED;
1238  }
1239 
1240  if (net_drop < 20) {
1241  // run lastcmd multiple times if no backups available
1242  while (net_drop > numDups) {
1244  net_drop--;
1245  }
1246 
1247  // run backup cmds, if any
1248  while (net_drop > 0) {
1249  i = numDups - net_drop;
1250  for (j = 0; j < numCmds[i]; j++) {
1251  SV_ClientThink(&cmds[i][j]);
1252  }
1253  net_drop--;
1254  }
1255 
1256  }
1257 
1258  // run new cmds
1259  for (j = 0; j < numCmds[numDups]; j++) {
1260  SV_ClientThink(&cmds[numDups][j]);
1261  }
1262 
1263  sv_client->lastcmd = *lastcmd;
1264 }
1265 
1266 /*
1267 =================
1268 SV_UpdateUserinfo
1269 
1270 Ensures that userinfo is valid and name is properly set.
1271 =================
1272 */
1273 static void SV_UpdateUserinfo(void)
1274 {
1275  char *s;
1276 
1277  if (!sv_client->userinfo[0]) {
1278  SV_DropClient(sv_client, "empty userinfo");
1279  return;
1280  }
1281 
1282  if (!Info_Validate(sv_client->userinfo)) {
1283  SV_DropClient(sv_client, "malformed userinfo");
1284  return;
1285  }
1286 
1287  // validate name
1288  s = Info_ValueForKey(sv_client->userinfo, "name");
1289  s[MAX_CLIENT_NAME - 1] = 0;
1290  if (COM_IsWhite(s) || (sv_client->name[0] && strcmp(sv_client->name, s) &&
1292  if (!sv_client->name[0]) {
1293  SV_DropClient(sv_client, "malformed name");
1294  return;
1295  }
1297  SV_DropClient(sv_client, "oversize userinfo");
1298  return;
1299  }
1300  if (COM_IsWhite(s))
1301  SV_ClientPrintf(sv_client, PRINT_HIGH, "You can't have an empty name.\n");
1302  else
1303  SV_ClientPrintf(sv_client, PRINT_HIGH, "You can't change your name too often.\n");
1304  SV_ClientCommand(sv_client, "set name \"%s\"\n", sv_client->name);
1305  }
1306 
1308 }
1309 
1310 static void SV_ParseFullUserinfo(void)
1311 {
1312  size_t len;
1313 
1314  // malicious users may try sending too many userinfo updates
1315  if (userinfoUpdateCount >= MAX_PACKET_USERINFOS) {
1316  Com_DPrintf("Too many userinfos from %s\n", sv_client->name);
1317  MSG_ReadString(NULL, 0);
1318  return;
1319  }
1320 
1322  if (len >= sizeof(sv_client->userinfo)) {
1323  SV_DropClient(sv_client, "oversize userinfo");
1324  return;
1325  }
1326 
1327  Com_DDPrintf("%s(%s): %s [%d]\n", __func__,
1329 
1332 }
1333 
1334 static void SV_ParseDeltaUserinfo(void)
1335 {
1336  char key[MAX_INFO_KEY], value[MAX_INFO_VALUE];
1337  size_t len;
1338 
1339  // malicious users may try sending too many userinfo updates
1340  if (userinfoUpdateCount >= MAX_PACKET_USERINFOS) {
1341  Com_DPrintf("Too many userinfos from %s\n", sv_client->name);
1342  MSG_ReadString(NULL, 0);
1343  MSG_ReadString(NULL, 0);
1344  return;
1345  }
1346 
1347  // optimize by combining multiple delta updates into one (hack)
1348  while (1) {
1349  len = MSG_ReadString(key, sizeof(key));
1350  if (len >= sizeof(key)) {
1351  SV_DropClient(sv_client, "oversize delta key");
1352  return;
1353  }
1354 
1355  len = MSG_ReadString(value, sizeof(value));
1356  if (len >= sizeof(value)) {
1357  SV_DropClient(sv_client, "oversize delta value");
1358  return;
1359  }
1360 
1361  if (userinfoUpdateCount < MAX_PACKET_USERINFOS) {
1362  if (!Info_SetValueForKey(sv_client->userinfo, key, value)) {
1363  SV_DropClient(sv_client, "malformed userinfo");
1364  return;
1365  }
1366 
1367  Com_DDPrintf("%s(%s): %s %s [%d]\n", __func__,
1368  sv_client->name, key, value, userinfoUpdateCount);
1369 
1371  } else {
1372  Com_DPrintf("Too many userinfos from %s\n", sv_client->name);
1373  }
1374 
1375  if (msg_read.readcount >= msg_read.cursize)
1376  break; // end of message
1377 
1378  if (msg_read.data[msg_read.readcount] != clc_userinfo_delta)
1379  break; // not delta userinfo
1380 
1381  msg_read.readcount++;
1382  }
1383 
1385 }
1386 
1387 #if USE_FPS
1388 void SV_AlignKeyFrames(client_t *client)
1389 {
1390  int framediv = sv.framediv / client->framediv;
1391  int framenum = sv.framenum / client->framediv;
1392  int frameofs = framenum % framediv;
1393  int newnum = frameofs + Q_align(client->framenum, framediv);
1394 
1395  Com_DPrintf("[%d] align %d --> %d (num = %d, div = %d, ofs = %d)\n",
1396  sv.framenum, client->framenum, newnum, framenum, framediv, frameofs);
1397  client->framenum = newnum;
1398 }
1399 
1400 static void set_client_fps(int value)
1401 {
1402  int framediv, framerate;
1403 
1404  // 0 means highest
1405  if (!value)
1406  value = sv.framerate;
1407 
1408  framediv = value / BASE_FRAMERATE;
1409 
1410  clamp(framediv, 1, MAX_FRAMEDIV);
1411 
1412  framediv = sv.framediv / Q_gcd(sv.framediv, framediv);
1413  framerate = sv.framerate / framediv;
1414 
1415  Com_DPrintf("[%d] client div=%d, server div=%d, rate=%d\n",
1416  sv.framenum, framediv, sv.framediv, framerate);
1417 
1418  sv_client->framediv = framediv;
1419 
1421 
1422  // save for status inspection
1423  sv_client->settings[CLS_FPS] = framerate;
1424 
1425  MSG_WriteByte(svc_setting);
1426  MSG_WriteLong(SVS_FPS);
1427  MSG_WriteLong(framerate);
1429 }
1430 #endif
1431 
1432 static void SV_ParseClientSetting(void)
1433 {
1434  int idx, value;
1435 
1436  idx = MSG_ReadShort();
1437  value = MSG_ReadShort();
1438 
1439  Com_DDPrintf("%s(%s): [%d] = %d\n", __func__, sv_client->name, idx, value);
1440 
1441  if (idx < 0 || idx >= CLS_MAX)
1442  return;
1443 
1444  sv_client->settings[idx] = value;
1445 
1446 #if USE_FPS
1447  if (idx == CLS_FPS && sv_client->protocol == PROTOCOL_VERSION_Q2PRO)
1448  set_client_fps(value);
1449 #endif
1450 }
1451 
1452 static void SV_ParseClientCommand(void)
1453 {
1454  char buffer[MAX_STRING_CHARS];
1455  size_t len;
1456 
1457  len = MSG_ReadString(buffer, sizeof(buffer));
1458  if (len >= sizeof(buffer)) {
1459  SV_DropClient(sv_client, "oversize stringcmd");
1460  return;
1461  }
1462 
1463  // malicious users may try using too many string commands
1464  if (stringCmdCount >= MAX_PACKET_STRINGCMDS) {
1465  Com_DPrintf("Too many stringcmds from %s\n", sv_client->name);
1466  return;
1467  }
1468 
1469  Com_DDPrintf("%s(%s): %s\n", __func__, sv_client->name, buffer);
1470 
1471  SV_ExecuteUserCommand(buffer);
1472  stringCmdCount++;
1473 }
1474 
1475 /*
1476 ===================
1477 SV_ExecuteClientMessage
1478 
1479 The current net_message is parsed for the given client
1480 ===================
1481 */
1483 {
1484  int c;
1485 
1486  X86_PUSH_FPCW;
1487  X86_SINGLE_FPCW;
1488 
1489  sv_client = client;
1491 
1492  // only allow one move command
1493  moveIssued = qfalse;
1494  stringCmdCount = 0;
1495  userinfoUpdateCount = 0;
1496 
1497  while (1) {
1498  if (msg_read.readcount > msg_read.cursize) {
1499  SV_DropClient(client, "read past end of message");
1500  break;
1501  }
1502 
1503  c = MSG_ReadByte();
1504  if (c == -1)
1505  break;
1506 
1507  switch (c & SVCMD_MASK) {
1508  default:
1509 badbyte:
1510  SV_DropClient(client, "unknown command byte");
1511  break;
1512 
1513  case clc_nop:
1514  break;
1515 
1516  case clc_userinfo:
1518  break;
1519 
1520  case clc_move:
1522  break;
1523 
1524  case clc_stringcmd:
1526  break;
1527 
1528  case clc_setting:
1529  if (client->protocol < PROTOCOL_VERSION_R1Q2)
1530  goto badbyte;
1531 
1533  break;
1534 
1535  case clc_move_nodelta:
1536  case clc_move_batched:
1537  if (client->protocol != PROTOCOL_VERSION_Q2PRO)
1538  goto badbyte;
1539 
1541  break;
1542 
1543  case clc_userinfo_delta:
1544  if (client->protocol != PROTOCOL_VERSION_Q2PRO)
1545  goto badbyte;
1546 
1548  break;
1549  }
1550 
1551  if (client->state <= cs_zombie)
1552  break; // disconnect command
1553  }
1554 
1555  sv_client = NULL;
1556  sv_player = NULL;
1557 
1558  X86_POP_FPCW;
1559 }
1560 
client_s::lastframe
int lastframe
Definition: server.h:290
sv_enforcetime
cvar_t * sv_enforcetime
Definition: main.c:37
server_t::framenum
int framenum
Definition: server.h:155
SV_OldClientExecuteMove
static void SV_OldClientExecuteMove(void)
Definition: user.c:1100
sv_pending_autosave
qboolean sv_pending_autosave
Definition: main.c:35
client_s::version_string
char * version_string
Definition: server.h:282
moveIssued
static qboolean moveIssued
Definition: user.c:1034
stuffcmd_t::string
char string[1]
Definition: server.h:407
SV_BASELINES_MASK
#define SV_BASELINES_MASK
Definition: server.h:70
stuffcmd_t
Definition: server.h:404
filtercmd_t::action
filteraction_t action
Definition: server.h:421
Cvar_Set
cvar_t * Cvar_Set(const char *var_name, const char *value)
Definition: cvar.c:466
SV_Disconnect_f
static void SV_Disconnect_f(void)
Definition: user.c:796
cs_spawned
@ cs_spawned
Definition: server.h:192
msg_read
sizebuf_t msg_read
Definition: msg.c:37
SV_ParseClientSetting
static void SV_ParseClientSetting(void)
Definition: user.c:1432
allow_download_players
cvar_t * allow_download_players
Definition: common.c:106
svs
server_static_t svs
Definition: init.c:21
NET_AdrToString
char * NET_AdrToString(const netadr_t *a)
Definition: net.c:257
SV_StopDownload_f
static void SV_StopDownload_f(void)
Definition: user.c:743
Cvar_BitInfo
size_t Cvar_BitInfo(char *info, int bit)
Definition: cvar.c:1109
SV_BASELINES_CHUNKS
#define SV_BASELINES_CHUNKS
Definition: server.h:71
Info_Validate
qboolean Info_Validate(const char *s)
Definition: shared.c:1040
client_s::send_delta
unsigned send_delta
Definition: server.h:312
SV_CloseDownload
void SV_CloseDownload(client_t *client)
Definition: user.c:545
FS_Read
ssize_t FS_Read(void *buf, size_t len, qhandle_t f)
Definition: files.c:1547
client_s::protocol
int protocol
Definition: server.h:324
PL_C2S
#define PL_C2S(cl)
Definition: server.h:244
SV_ShowServerInfo_f
static void SV_ShowServerInfo_f(void)
Definition: user.c:803
client_s::downloadname
char * downloadname
Definition: server.h:318
write_baseline
static void write_baseline(entity_packed_t *base)
Definition: user.c:119
client_s::has_zlib
qboolean has_zlib
Definition: server.h:267
client_s::state
clstate_t state
Definition: server.h:260
PL_S2C
#define PL_S2C(cl)
Definition: server.h:242
MSG_CLEAR
#define MSG_CLEAR
Definition: server.h:215
client_s::number
int number
Definition: server.h:262
MSG_ReadDeltaUsercmd_Enhanced
void MSG_ReadDeltaUsercmd_Enhanced(const usercmd_t *from, usercmd_t *to, int version)
Definition: msg.c:1773
SV_NoGameData_f
static void SV_NoGameData_f(void)
Definition: user.c:822
MSG_RELIABLE
#define MSG_RELIABLE
Definition: server.h:214
client_s::gamedir
char * gamedir
Definition: server.h:344
sv_force_reconnect
cvar_t * sv_force_reconnect
Definition: main.c:51
AC_ClientToken
void AC_ClientToken(client_t *cl, const char *token)
Definition: ac.c:1143
client_s::spawncount
int spawncount
Definition: server.h:348
MSG_ReadDeltaUsercmd
void MSG_ReadDeltaUsercmd(const usercmd_t *from, usercmd_t *to)
Definition: msg.c:1607
client_s::slot
int slot
Definition: server.h:347
userinfoUpdateCount
static int userinfoUpdateCount
Definition: user.c:1036
SV_BASELINES_SHIFT
#define SV_BASELINES_SHIFT
Definition: server.h:68
client_s::downloadcount
int downloadcount
Definition: server.h:317
SZ_WriteByte
void SZ_WriteByte(sizebuf_t *sb, int c)
Definition: sizebuf.c:82
SZ_WriteShort
void SZ_WriteShort(sizebuf_t *sb, int c)
Definition: sizebuf.c:90
clstate_t
clstate_t
Definition: server.h:185
SV_NextServer_f
static void SV_NextServer_f(void)
Definition: user.c:766
Cmd_TokenizeString
void Cmd_TokenizeString(const char *text, qboolean macroExpand)
Definition: cmd.c:1399
SV_NewClientExecuteMove
static void SV_NewClientExecuteMove(int c)
Definition: user.c:1168
server_entity_t::solid32
int solid32
Definition: server.h:112
sv_client
client_t * sv_client
Definition: main.c:32
client_s::suppress_count
int suppress_count
Definition: server.h:311
Cmd_RawArgsFrom
char * Cmd_RawArgsFrom(int from)
Definition: cmd.c:1021
MSG_WriteByte
void MSG_WriteByte(int c)
Definition: msg.c:107
Cmd_Argv
char * Cmd_Argv(int arg)
Definition: cmd.c:899
svc_stufftext
#define svc_stufftext
Definition: g_local.h:41
Cmd_Argc
int Cmd_Argc(void)
Definition: cmd.c:889
SV_ClientAddMessage
void SV_ClientAddMessage(client_t *client, int flags)
Definition: send.c:399
stuff_junk
static void stuff_junk(void)
Definition: user.c:321
SV_UserinfoChanged
void SV_UserinfoChanged(client_t *cl)
Definition: main.c:1927
SV_AlignKeyFrames
#define SV_AlignKeyFrames(client)
Definition: server.h:698
SV_SetLastFrame
static void SV_SetLastFrame(int lastframe)
Definition: user.c:1067
MSG_ReadBits
int MSG_ReadBits(int bits)
Definition: msg.c:1718
SV_Malloc
#define SV_Malloc(size)
Definition: server.h:54
FS_FOpenFile
ssize_t FS_FOpenFile(const char *name, qhandle_t *f, unsigned mode)
Definition: files.c:1692
cmd_buffer
cmdbuf_t cmd_buffer
Definition: cmd.c:49
ES_INUSE
#define ES_INUSE(s)
Definition: server.h:718
client_s::console_queries
int console_queries
Definition: server.h:285
client_s::nodata
qboolean nodata
Definition: server.h:266
SZ_GetSpace
void * SZ_GetSpace(sizebuf_t *buf, size_t len)
Definition: sizebuf.c:48
MSG_PackEntity
void MSG_PackEntity(entity_packed_t *out, const entity_state_t *in, qboolean short_angles)
Definition: msg.c:468
EDICT_POOL
#define EDICT_POOL(c, n)
Definition: server.h:171
allow_download_maps
cvar_t * allow_download_maps
Definition: common.c:109
allow_download_textures
cvar_t * allow_download_textures
Definition: common.c:110
AC_ClientAnnounce
void AC_ClientAnnounce(client_t *cl)
Definition: ac.c:1070
write_plain_configstrings
static void write_plain_configstrings(void)
Definition: user.c:89
client_s::download
byte * download
Definition: server.h:315
handle_filtercmd
static void handle_filtercmd(filtercmd_t *filter)
Definition: user.c:949
client_s::downloadpending
qboolean downloadpending
Definition: server.h:320
sv
server_t sv
Definition: init.c:22
client_s::baselines
entity_packed_t * baselines[SV_BASELINES_CHUNKS]
Definition: server.h:340
SV_CopyString
#define SV_CopyString(s)
Definition: server.h:56
filtercmd_t
Definition: server.h:419
client_s::downloadcmd
int downloadcmd
Definition: server.h:319
msg_write
sizebuf_t msg_write
Definition: msg.c:34
SV_ParseDeltaUserinfo
static void SV_ParseDeltaUserinfo(void)
Definition: user.c:1334
client_s::frames
client_frame_t frames[UPDATE_BACKUP]
Definition: server.h:301
client_s::lastactivity
unsigned lastactivity
Definition: server.h:289
Com_EndRedirect
void Com_EndRedirect(void)
Definition: common.c:172
Cbuf_AddText
void Cbuf_AddText(cmdbuf_t *buf, const char *text)
Definition: cmd.c:95
Info_ValueForKey
char * Info_ValueForKey(const char *s, const char *key)
Definition: shared.c:945
Z_Free
void Z_Free(void *ptr)
Definition: zone.c:147
client_s::lastcmd
usercmd_t lastcmd
Definition: server.h:291
AC_ClientBegin
qboolean AC_ClientBegin(client_t *cl)
Definition: ac.c:1020
MSG_ReadLong
int MSG_ReadLong(void)
Definition: msg.c:1517
MSG_WriteDeltaEntity
void MSG_WriteDeltaEntity(const entity_packed_t *from, const entity_packed_t *to, msgEsFlags_t flags)
Definition: msg.c:505
SV_NextDownload_f
static void SV_NextDownload_f(void)
Definition: user.c:566
cs_zombie
@ cs_zombie
Definition: server.h:187
SV_ClientCommand
void SV_ClientCommand(client_t *client, const char *fmt,...)
Definition: send.c:185
sv_allow_unconnected_cmds
cvar_t * sv_allow_unconnected_cmds
Definition: main.c:97
Cvar_VariableInteger
int Cvar_VariableInteger(const char *var_name)
Definition: cvar.c:105
SV_AutoSaveEnd
void SV_AutoSaveEnd(void)
Definition: save.c:516
client_s::num_moves
int num_moves
Definition: server.h:294
client_frame_t::sentTime
unsigned sentTime
Definition: server.h:107
Q_strlcpy
size_t Q_strlcpy(char *dst, const char *src, size_t size)
Definition: shared.c:715
FA_STUFF
@ FA_STUFF
Definition: server.h:413
ucmds
static const ucmd_t ucmds[]
Definition: user.c:920
client_s::reconnect_val
char reconnect_val[16]
Definition: server.h:284
client_s::lastmessage
unsigned lastmessage
Definition: server.h:288
COM_IsWhite
qboolean COM_IsWhite(const char *s)
Definition: shared.c:366
SV_New_f
void SV_New_f(void)
Definition: user.c:365
client_frame_t::latency
int latency
Definition: server.h:108
client_s::version
int version
Definition: server.h:325
Info_Print
void Info_Print(const char *infostring)
Definition: shared.c:1235
client_frame_t
Definition: server.h:99
MSG_WriteShort
void MSG_WriteShort(int c)
Definition: msg.c:125
ge
game_export_t * ge
Definition: game.c:22
client_s::connect_time
time_t connect_time
Definition: server.h:361
SV_DropClient
void SV_DropClient(client_t *client, const char *reason)
Definition: main.c:212
SV_ShowMiscInfo_f
static void SV_ShowMiscInfo_f(void)
Definition: user.c:815
SV_Begin_f
void SV_Begin_f(void)
Definition: user.c:488
client_s::command_msec
int command_msec
Definition: server.h:292
SV_PrintMiscInfo
void SV_PrintMiscInfo(void)
Definition: commands.c:777
cl
client_state_t cl
Definition: main.c:99
SV_ExecuteUserCommand
static void SV_ExecuteUserCommand(const char *s)
Definition: user.c:982
client_frame_t::number
int number
Definition: server.h:100
client_s::http_download
qboolean http_download
Definition: server.h:272
allow_download_sounds
cvar_t * allow_download_sounds
Definition: common.c:108
SV_CvarResult_f
static void SV_CvarResult_f(void)
Definition: user.c:874
client_s::reconnect_var
char reconnect_var[16]
Definition: server.h:283
SV_ParseClientCommand
static void SV_ParseClientCommand(void)
Definition: user.c:1452
MSG_WriteString
void MSG_WriteString(const char *string)
Definition: msg.c:160
MSG_ReadDeltaUsercmd_Hacked
void MSG_ReadDeltaUsercmd_Hacked(const usercmd_t *from, usercmd_t *to)
Definition: msg.c:1649
c
statCounters_t c
Definition: main.c:30
allow_download_others
cvar_t * allow_download_others
Definition: common.c:112
MSG_WriteLong
void MSG_WriteLong(int c)
Definition: msg.c:144
cs_assigned
@ cs_assigned
Definition: server.h:189
sv_filterlist
list_t sv_filterlist
write_plain_baselines
static void write_plain_baselines(void)
Definition: user.c:130
Q2PRO_SHORTANGLES
#define Q2PRO_SHORTANGLES(c, e)
Definition: server.h:179
Cvar_ClampInteger
int Cvar_ClampInteger(cvar_t *var, int min, int max)
Definition: cvar.c:549
client_s::settings
int settings[CLS_MAX]
Definition: server.h:326
g_features
cvar_t * g_features
Definition: main.c:99
MSG_ReadString
size_t MSG_ReadString(char *dest, size_t size)
Definition: msg.c:1531
server_static_s::realtime
unsigned realtime
Definition: server.h:454
SV_Lag_f
static void SV_Lag_f(void)
Definition: user.c:828
SV_ExecuteClientMessage
void SV_ExecuteClientMessage(client_t *client)
Definition: user.c:1482
filtercmd_t::comment
char * comment
Definition: server.h:422
client_s::pool
edict_pool_t * pool
Definition: server.h:345
allow_download_pics
cvar_t * allow_download_pics
Definition: common.c:111
Cmd_ArgvBuffer
size_t Cmd_ArgvBuffer(int arg, char *buffer, size_t size)
Definition: cmd.c:912
SV_AC_List_f
static void SV_AC_List_f(void)
Definition: user.c:906
cs_primed
@ cs_primed
Definition: server.h:191
SV_ClientPrintf
void SV_ClientPrintf(client_t *client, int level, const char *fmt,...)
Definition: send.c:121
server_t::state
server_state_t state
Definition: server.h:146
filtercmd_t::string
char string[1]
Definition: server.h:423
allow_download
cvar_t * allow_download
Definition: common.c:105
sv_player
edict_t * sv_player
Definition: main.c:33
SV_AC_Info_f
static void SV_AC_Info_f(void)
Definition: user.c:913
client_s::frameflags
unsigned frameflags
Definition: server.h:307
client_s
Definition: server.h:256
client_s::netchan
netchan_t * netchan
Definition: server.h:357
SV_Mallocz
#define SV_Mallocz(size)
Definition: server.h:55
SV_BeginDownload_f
static void SV_BeginDownload_f(void)
Definition: user.c:579
client_s::downloadsize
int downloadsize
Definition: server.h:316
Cvar_VariableString
char * Cvar_VariableString(const char *var_name)
Definition: cvar.c:122
client_s::numpackets
int numpackets
Definition: server.h:358
FS_FCloseFile
void FS_FCloseFile(qhandle_t f)
Definition: files.c:759
allow_download_models
cvar_t * allow_download_models
Definition: common.c:107
client_s::reconnected
qboolean reconnected
Definition: server.h:265
SV_DPrintf
#define SV_DPrintf(...)
Definition: server.h:65
MSG_ReadByte
int MSG_ReadByte(void)
Definition: msg.c:1475
AC_Info_f
void AC_Info_f(void)
Definition: ac.c:1549
SV_UpdateUserinfo
static void SV_UpdateUserinfo(void)
Definition: user.c:1273
Info_SetValueForKey
qboolean Info_SetValueForKey(char *s, const char *key, const char *value)
Definition: shared.c:1137
SV_BASELINES_PER_CHUNK
#define SV_BASELINES_PER_CHUNK
Definition: server.h:69
FA_PRINT
@ FA_PRINT
Definition: server.h:412
sv_cmdlist_begin
list_t sv_cmdlist_begin
server_t::entities
server_entity_t entities[MAX_EDICTS]
Definition: server.h:166
server.h
SV_RemoveClient
void SV_RemoveClient(client_t *client)
Definition: main.c:107
AVG_PING
#define AVG_PING(cl)
Definition: server.h:246
stuffcmd_t::len
int len
Definition: server.h:406
client_s::ratelimit_namechange
ratelimit_t ratelimit_namechange
Definition: server.h:279
client_s::userinfo
char userinfo[MAX_INFO_STRING]
Definition: server.h:275
client_s::configstrings
char * configstrings
Definition: server.h:343
sv_cmdlist_connect
list_t sv_cmdlist_connect
client_s::framenum
int framenum
Definition: server.h:303
cs_connected
@ cs_connected
Definition: server.h:190
SV_RateLimited
qboolean SV_RateLimited(ratelimit_t *r)
Definition: main.c:265
stringCmdCount
static int stringCmdCount
Definition: user.c:1035
server_t::name
char name[MAX_QPATH]
Definition: server.h:160
FS_NormalizePath
size_t FS_NormalizePath(char *out, const char *in)
Definition: files.c:331
stuff_cmds
static void stuff_cmds(list_t *list)
Definition: user.c:308
client_s::pmp
pmoveParams_t pmp
Definition: server.h:328
create_baselines
static void create_baselines(void)
Definition: user.c:40
client_s::esFlags
msgEsFlags_t esFlags
Definition: server.h:329
SZ_Clear
void SZ_Clear(sizebuf_t *buf)
Definition: sizebuf.c:40
client_s::frames_acked
unsigned frames_acked
Definition: server.h:302
com_eventTime
unsigned com_eventTime
Definition: common.c:122
SV_ClientRedirect
#define SV_ClientRedirect()
Definition: server.h:584
SV_GetPlayer
client_t * SV_GetPlayer(const char *s, qboolean partial)
Definition: commands.c:127
FA_KICK
@ FA_KICK
Definition: server.h:414
MSG_ReadShort
int MSG_ReadShort(void)
Definition: msg.c:1489
SV_ClientThink
static void SV_ClientThink(usercmd_t *cmd)
Definition: user.c:1043
AC_List_f
void AC_List_f(void)
Definition: ac.c:1490
client_s::name
char name[MAX_CLIENT_NAME]
Definition: server.h:276
client_s::edict
edict_t * edict
Definition: server.h:261
SV_ParseFullUserinfo
static void SV_ParseFullUserinfo(void)
Definition: user.c:1310