1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (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.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19 */
20 // sv_user.c -- server code for moving users
21
22 #include "qwsvdef.h"
23
24 edict_t *sv_player;
25
26 usercmd_t cmd;
27
28 cvar_t cl_rollspeed = {"cl_rollspeed", "200"};
29 cvar_t cl_rollangle = {"cl_rollangle", "2.0"};
30 cvar_t sv_spectalk = {"sv_spectalk", "1"};
31
32 cvar_t sv_mapcheck = {"sv_mapcheck", "1"};
33
34 extern vec3_t player_mins;
35
36 extern int fp_messages, fp_persecond, fp_secondsdead;
37 extern char fp_msg[];
38 extern cvar_t pausable;
39
40 /*
41 ============================================================
42
43 USER STRINGCMD EXECUTION
44
45 host_client and sv_player will be valid.
46 ============================================================
47 */
48
49 /*
50 ================
51 SV_New_f
52
53 Sends the first message from the server to a connected client.
54 This will be sent on the initial connection and upon each server load.
55 ================
56 */
SV_New_f(void)57 void SV_New_f (void)
58 {
59 char *gamedir;
60 int playernum;
61
62 if (host_client->state == cs_spawned)
63 return;
64
65 host_client->state = cs_connected;
66 host_client->connection_started = realtime;
67
68 // send the info about the new client to all connected clients
69 // SV_FullClientUpdate (host_client, &sv.reliable_datagram);
70 // host_client->sendinfo = true;
71
72 gamedir = Info_ValueForKey (svs.info, "*gamedir");
73 if (!gamedir[0])
74 gamedir = "qw";
75
76 //NOTE: This doesn't go through ClientReliableWrite since it's before the user
77 //spawns. These functions are written to not overflow
78 if (host_client->num_backbuf) {
79 Con_Printf("WARNING %s: [SV_New] Back buffered (%d0, clearing", host_client->name, host_client->netchan.message.cursize);
80 host_client->num_backbuf = 0;
81 SZ_Clear(&host_client->netchan.message);
82 }
83
84 // send the serverdata
85 MSG_WriteByte (&host_client->netchan.message, svc_serverdata);
86 MSG_WriteLong (&host_client->netchan.message, PROTOCOL_VERSION);
87 MSG_WriteLong (&host_client->netchan.message, svs.spawncount);
88 MSG_WriteString (&host_client->netchan.message, gamedir);
89
90 playernum = NUM_FOR_EDICT(host_client->edict)-1;
91 if (host_client->spectator)
92 playernum |= 128;
93 MSG_WriteByte (&host_client->netchan.message, playernum);
94
95 // send full levelname
96 MSG_WriteString (&host_client->netchan.message, PR_GetString(sv.edicts->v.message));
97
98 // send the movevars
99 MSG_WriteFloat(&host_client->netchan.message, movevars.gravity);
100 MSG_WriteFloat(&host_client->netchan.message, movevars.stopspeed);
101 MSG_WriteFloat(&host_client->netchan.message, movevars.maxspeed);
102 MSG_WriteFloat(&host_client->netchan.message, movevars.spectatormaxspeed);
103 MSG_WriteFloat(&host_client->netchan.message, movevars.accelerate);
104 MSG_WriteFloat(&host_client->netchan.message, movevars.airaccelerate);
105 MSG_WriteFloat(&host_client->netchan.message, movevars.wateraccelerate);
106 MSG_WriteFloat(&host_client->netchan.message, movevars.friction);
107 MSG_WriteFloat(&host_client->netchan.message, movevars.waterfriction);
108 MSG_WriteFloat(&host_client->netchan.message, movevars.entgravity);
109
110 // send music
111 MSG_WriteByte (&host_client->netchan.message, svc_cdtrack);
112 MSG_WriteByte (&host_client->netchan.message, sv.edicts->v.sounds);
113
114 // send server info string
115 MSG_WriteByte (&host_client->netchan.message, svc_stufftext);
116 MSG_WriteString (&host_client->netchan.message, va("fullserverinfo \"%s\"\n", svs.info) );
117 }
118
119 /*
120 ==================
121 SV_Soundlist_f
122 ==================
123 */
SV_Soundlist_f(void)124 void SV_Soundlist_f (void)
125 {
126 char **s;
127 int n;
128
129 if (host_client->state != cs_connected)
130 {
131 Con_Printf ("soundlist not valid -- allready spawned\n");
132 return;
133 }
134
135 // handle the case of a level changing while a client was connecting
136 if ( atoi(Cmd_Argv(1)) != svs.spawncount )
137 {
138 Con_Printf ("SV_Soundlist_f from different level\n");
139 SV_New_f ();
140 return;
141 }
142
143 n = atoi(Cmd_Argv(2));
144
145 //NOTE: This doesn't go through ClientReliableWrite since it's before the user
146 //spawns. These functions are written to not overflow
147 if (host_client->num_backbuf) {
148 Con_Printf("WARNING %s: [SV_Soundlist] Back buffered (%d0, clearing", host_client->name, host_client->netchan.message.cursize);
149 host_client->num_backbuf = 0;
150 SZ_Clear(&host_client->netchan.message);
151 }
152
153 MSG_WriteByte (&host_client->netchan.message, svc_soundlist);
154 MSG_WriteByte (&host_client->netchan.message, n);
155 for (s = sv.sound_precache+1 + n ;
156 *s && host_client->netchan.message.cursize < (MAX_MSGLEN/2);
157 s++, n++)
158 MSG_WriteString (&host_client->netchan.message, *s);
159
160 MSG_WriteByte (&host_client->netchan.message, 0);
161
162 // next msg
163 if (*s)
164 MSG_WriteByte (&host_client->netchan.message, n);
165 else
166 MSG_WriteByte (&host_client->netchan.message, 0);
167 }
168
169 /*
170 ==================
171 SV_Modellist_f
172 ==================
173 */
SV_Modellist_f(void)174 void SV_Modellist_f (void)
175 {
176 char **s;
177 int n;
178
179 if (host_client->state != cs_connected)
180 {
181 Con_Printf ("modellist not valid -- allready spawned\n");
182 return;
183 }
184
185 // handle the case of a level changing while a client was connecting
186 if ( atoi(Cmd_Argv(1)) != svs.spawncount )
187 {
188 Con_Printf ("SV_Modellist_f from different level\n");
189 SV_New_f ();
190 return;
191 }
192
193 n = atoi(Cmd_Argv(2));
194
195 //NOTE: This doesn't go through ClientReliableWrite since it's before the user
196 //spawns. These functions are written to not overflow
197 if (host_client->num_backbuf) {
198 Con_Printf("WARNING %s: [SV_Modellist] Back buffered (%d0, clearing", host_client->name, host_client->netchan.message.cursize);
199 host_client->num_backbuf = 0;
200 SZ_Clear(&host_client->netchan.message);
201 }
202
203 MSG_WriteByte (&host_client->netchan.message, svc_modellist);
204 MSG_WriteByte (&host_client->netchan.message, n);
205 for (s = sv.model_precache+1+n ;
206 *s && host_client->netchan.message.cursize < (MAX_MSGLEN/2);
207 s++, n++)
208 MSG_WriteString (&host_client->netchan.message, *s);
209 MSG_WriteByte (&host_client->netchan.message, 0);
210
211 // next msg
212 if (*s)
213 MSG_WriteByte (&host_client->netchan.message, n);
214 else
215 MSG_WriteByte (&host_client->netchan.message, 0);
216 }
217
218 /*
219 ==================
220 SV_PreSpawn_f
221 ==================
222 */
SV_PreSpawn_f(void)223 void SV_PreSpawn_f (void)
224 {
225 unsigned buf;
226 unsigned check;
227
228 if (host_client->state != cs_connected)
229 {
230 Con_Printf ("prespawn not valid -- allready spawned\n");
231 return;
232 }
233
234 // handle the case of a level changing while a client was connecting
235 if ( atoi(Cmd_Argv(1)) != svs.spawncount )
236 {
237 Con_Printf ("SV_PreSpawn_f from different level\n");
238 SV_New_f ();
239 return;
240 }
241
242 buf = atoi(Cmd_Argv(2));
243 if (buf >= sv.num_signon_buffers)
244 buf = 0;
245
246 if (!buf) {
247 // should be three numbers following containing checksums
248 check = atoi(Cmd_Argv(3));
249
250 // Con_DPrintf("Client check = %d\n", check);
251
252 if (sv_mapcheck.value && check != sv.worldmodel->checksum &&
253 check != sv.worldmodel->checksum2) {
254 SV_ClientPrintf (host_client, PRINT_HIGH,
255 "Map model file does not match (%s), %i != %i/%i.\n"
256 "You may need a new version of the map, or the proper install files.\n",
257 sv.modelname, check, sv.worldmodel->checksum, sv.worldmodel->checksum2);
258 SV_DropClient (host_client);
259 return;
260 }
261 host_client->checksum = check;
262 }
263
264 //NOTE: This doesn't go through ClientReliableWrite since it's before the user
265 //spawns. These functions are written to not overflow
266 if (host_client->num_backbuf) {
267 Con_Printf("WARNING %s: [SV_PreSpawn] Back buffered (%d0, clearing", host_client->name, host_client->netchan.message.cursize);
268 host_client->num_backbuf = 0;
269 SZ_Clear(&host_client->netchan.message);
270 }
271
272 SZ_Write (&host_client->netchan.message,
273 sv.signon_buffers[buf],
274 sv.signon_buffer_size[buf]);
275
276 buf++;
277 if (buf == sv.num_signon_buffers)
278 { // all done prespawning
279 MSG_WriteByte (&host_client->netchan.message, svc_stufftext);
280 MSG_WriteString (&host_client->netchan.message, va("cmd spawn %i 0\n",svs.spawncount) );
281 }
282 else
283 { // need to prespawn more
284 MSG_WriteByte (&host_client->netchan.message, svc_stufftext);
285 MSG_WriteString (&host_client->netchan.message,
286 va("cmd prespawn %i %i\n", svs.spawncount, buf) );
287 }
288 }
289
290 /*
291 ==================
292 SV_Spawn_f
293 ==================
294 */
SV_Spawn_f(void)295 void SV_Spawn_f (void)
296 {
297 int i;
298 client_t *client;
299 edict_t *ent;
300 eval_t *val;
301 int n;
302
303 if (host_client->state != cs_connected)
304 {
305 Con_Printf ("Spawn not valid -- allready spawned\n");
306 return;
307 }
308
309 // handle the case of a level changing while a client was connecting
310 if ( atoi(Cmd_Argv(1)) != svs.spawncount )
311 {
312 Con_Printf ("SV_Spawn_f from different level\n");
313 SV_New_f ();
314 return;
315 }
316
317 n = atoi(Cmd_Argv(2));
318
319 // make sure n is valid
320 if ( n < 0 || n > MAX_CLIENTS )
321 {
322 Con_Printf ("SV_Spawn_f invalid client start\n");
323 SV_New_f ();
324 return;
325 }
326
327
328
329 // send all current names, colors, and frag counts
330 // FIXME: is this a good thing?
331 SZ_Clear (&host_client->netchan.message);
332
333 // send current status of all other players
334
335 // normally this could overflow, but no need to check due to backbuf
336 for (i=n, client = svs.clients + n ; i<MAX_CLIENTS ; i++, client++)
337 SV_FullClientUpdateToClient (client, host_client);
338
339 // send all current light styles
340 for (i=0 ; i<MAX_LIGHTSTYLES ; i++)
341 {
342 ClientReliableWrite_Begin (host_client, svc_lightstyle,
343 3 + (sv.lightstyles[i] ? strlen(sv.lightstyles[i]) : 1));
344 ClientReliableWrite_Byte (host_client, (char)i);
345 ClientReliableWrite_String (host_client, sv.lightstyles[i]);
346 }
347
348 // set up the edict
349 ent = host_client->edict;
350
351 memset (&ent->v, 0, progs->entityfields * 4);
352 ent->v.colormap = NUM_FOR_EDICT(ent);
353 ent->v.team = 0; // FIXME
354 ent->v.netname = PR_SetString(host_client->name);
355
356 host_client->entgravity = 1.0;
357 val = GetEdictFieldValue(ent, "gravity");
358 if (val)
359 val->_float = 1.0;
360 host_client->maxspeed = sv_maxspeed.value;
361 val = GetEdictFieldValue(ent, "maxspeed");
362 if (val)
363 val->_float = sv_maxspeed.value;
364
365 //
366 // force stats to be updated
367 //
368 memset (host_client->stats, 0, sizeof(host_client->stats));
369
370 ClientReliableWrite_Begin (host_client, svc_updatestatlong, 6);
371 ClientReliableWrite_Byte (host_client, STAT_TOTALSECRETS);
372 ClientReliableWrite_Long (host_client, pr_global_struct->total_secrets);
373
374 ClientReliableWrite_Begin (host_client, svc_updatestatlong, 6);
375 ClientReliableWrite_Byte (host_client, STAT_TOTALMONSTERS);
376 ClientReliableWrite_Long (host_client, pr_global_struct->total_monsters);
377
378 ClientReliableWrite_Begin (host_client, svc_updatestatlong, 6);
379 ClientReliableWrite_Byte (host_client, STAT_SECRETS);
380 ClientReliableWrite_Long (host_client, pr_global_struct->found_secrets);
381
382 ClientReliableWrite_Begin (host_client, svc_updatestatlong, 6);
383 ClientReliableWrite_Byte (host_client, STAT_MONSTERS);
384 ClientReliableWrite_Long (host_client, pr_global_struct->killed_monsters);
385
386 // get the client to check and download skins
387 // when that is completed, a begin command will be issued
388 ClientReliableWrite_Begin (host_client, svc_stufftext, 8);
389 ClientReliableWrite_String (host_client, "skins\n" );
390
391 }
392
393 /*
394 ==================
395 SV_SpawnSpectator
396 ==================
397 */
SV_SpawnSpectator(void)398 void SV_SpawnSpectator (void)
399 {
400 int i;
401 edict_t *e;
402
403 VectorCopy (vec3_origin, sv_player->v.origin);
404 VectorCopy (vec3_origin, sv_player->v.view_ofs);
405 sv_player->v.view_ofs[2] = 22;
406
407 // search for an info_playerstart to spawn the spectator at
408 for (i=MAX_CLIENTS-1 ; i<sv.num_edicts ; i++)
409 {
410 e = EDICT_NUM(i);
411 if (!strcmp(PR_GetString(e->v.classname), "info_player_start"))
412 {
413 VectorCopy (e->v.origin, sv_player->v.origin);
414 return;
415 }
416 }
417
418 }
419
420 /*
421 ==================
422 SV_Begin_f
423 ==================
424 */
SV_Begin_f(void)425 void SV_Begin_f (void)
426 {
427 unsigned pmodel = 0, emodel = 0;
428 int i;
429
430 if (host_client->state == cs_spawned)
431 return; // don't begin again
432
433 host_client->state = cs_spawned;
434
435 // handle the case of a level changing while a client was connecting
436 if ( atoi(Cmd_Argv(1)) != svs.spawncount )
437 {
438 Con_Printf ("SV_Begin_f from different level\n");
439 SV_New_f ();
440 return;
441 }
442
443 if (host_client->spectator)
444 {
445 SV_SpawnSpectator ();
446
447 if (SpectatorConnect) {
448 // copy spawn parms out of the client_t
449 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
450 (&pr_global_struct->parm1)[i] = host_client->spawn_parms[i];
451
452 // call the spawn function
453 pr_global_struct->time = sv.time;
454 pr_global_struct->self = EDICT_TO_PROG(sv_player);
455 PR_ExecuteProgram (SpectatorConnect);
456 }
457 }
458 else
459 {
460 // copy spawn parms out of the client_t
461 for (i=0 ; i< NUM_SPAWN_PARMS ; i++)
462 (&pr_global_struct->parm1)[i] = host_client->spawn_parms[i];
463
464 // call the spawn function
465 pr_global_struct->time = sv.time;
466 pr_global_struct->self = EDICT_TO_PROG(sv_player);
467 PR_ExecuteProgram (pr_global_struct->ClientConnect);
468
469 // actually spawn the player
470 pr_global_struct->time = sv.time;
471 pr_global_struct->self = EDICT_TO_PROG(sv_player);
472 PR_ExecuteProgram (pr_global_struct->PutClientInServer);
473 }
474
475 // clear the net statistics, because connecting gives a bogus picture
476 host_client->netchan.frame_latency = 0;
477 host_client->netchan.frame_rate = 0;
478 host_client->netchan.drop_count = 0;
479 host_client->netchan.good_count = 0;
480
481 //check he's not cheating
482
483 pmodel = atoi(Info_ValueForKey (host_client->userinfo, "pmodel"));
484 emodel = atoi(Info_ValueForKey (host_client->userinfo, "emodel"));
485
486 if (pmodel != sv.model_player_checksum ||
487 emodel != sv.eyes_player_checksum)
488 SV_BroadcastPrintf (PRINT_HIGH, "%s WARNING: non standard player/eyes model detected\n", host_client->name);
489
490 // if we are paused, tell the client
491 if (sv.paused) {
492 ClientReliableWrite_Begin (host_client, svc_setpause, 2);
493 ClientReliableWrite_Byte (host_client, sv.paused);
494 SV_ClientPrintf(host_client, PRINT_HIGH, "Server is paused.\n");
495 }
496
497 #if 0
498 //
499 // send a fixangle over the reliable channel to make sure it gets there
500 // Never send a roll angle, because savegames can catch the server
501 // in a state where it is expecting the client to correct the angle
502 // and it won't happen if the game was just loaded, so you wind up
503 // with a permanent head tilt
504 ent = EDICT_NUM( 1 + (host_client - svs.clients) );
505 MSG_WriteByte (&host_client->netchan.message, svc_setangle);
506 for (i=0 ; i < 2 ; i++)
507 MSG_WriteAngle (&host_client->netchan.message, ent->v.angles[i] );
508 MSG_WriteAngle (&host_client->netchan.message, 0 );
509 #endif
510 }
511
512 //=============================================================================
513
514 /*
515 ==================
516 SV_NextDownload_f
517 ==================
518 */
SV_NextDownload_f(void)519 void SV_NextDownload_f (void)
520 {
521 byte buffer[1024];
522 int r;
523 int percent;
524 int size;
525
526 if (!host_client->download)
527 return;
528
529 r = host_client->downloadsize - host_client->downloadcount;
530 if (r > 768)
531 r = 768;
532 r = fread (buffer, 1, r, host_client->download);
533 ClientReliableWrite_Begin (host_client, svc_download, 6+r);
534 ClientReliableWrite_Short (host_client, r);
535
536 host_client->downloadcount += r;
537 size = host_client->downloadsize;
538 if (!size)
539 size = 1;
540 percent = host_client->downloadcount*100/size;
541 ClientReliableWrite_Byte (host_client, percent);
542 ClientReliableWrite_SZ (host_client, buffer, r);
543
544 if (host_client->downloadcount != host_client->downloadsize)
545 return;
546
547 fclose (host_client->download);
548 host_client->download = NULL;
549
550 }
551
OutofBandPrintf(netadr_t where,char * fmt,...)552 void OutofBandPrintf(netadr_t where, char *fmt, ...)
553 {
554 va_list argptr;
555 char send[1024];
556
557 send[0] = 0xff;
558 send[1] = 0xff;
559 send[2] = 0xff;
560 send[3] = 0xff;
561 send[4] = A2C_PRINT;
562 va_start (argptr, fmt);
563 vsprintf (send+5, fmt, argptr);
564 va_end (argptr);
565
566 NET_SendPacket (strlen(send)+1, send, where);
567 }
568
569 /*
570 ==================
571 SV_NextUpload
572 ==================
573 */
SV_NextUpload(void)574 void SV_NextUpload (void)
575 {
576 byte buffer[1024];
577 int r;
578 int percent;
579 int size;
580 client_t *client;
581
582 if (!*host_client->uploadfn) {
583 SV_ClientPrintf(host_client, PRINT_HIGH, "Upload denied\n");
584 ClientReliableWrite_Begin (host_client, svc_stufftext, 8);
585 ClientReliableWrite_String (host_client, "stopul");
586
587 // suck out rest of packet
588 size = MSG_ReadShort (); MSG_ReadByte ();
589 msg_readcount += size;
590 return;
591 }
592
593 size = MSG_ReadShort ();
594 percent = MSG_ReadByte ();
595
596 if (!host_client->upload)
597 {
598 host_client->upload = fopen(host_client->uploadfn, "wb");
599 if (!host_client->upload) {
600 Sys_Printf("Can't create %s\n", host_client->uploadfn);
601 ClientReliableWrite_Begin (host_client, svc_stufftext, 8);
602 ClientReliableWrite_String (host_client, "stopul");
603 *host_client->uploadfn = 0;
604 return;
605 }
606 Sys_Printf("Receiving %s from %d...\n", host_client->uploadfn, host_client->userid);
607 if (host_client->remote_snap)
608 OutofBandPrintf(host_client->snap_from, "Server receiving %s from %d...\n", host_client->uploadfn, host_client->userid);
609 }
610
611 fwrite (net_message.data + msg_readcount, 1, size, host_client->upload);
612 msg_readcount += size;
613
614 Con_DPrintf ("UPLOAD: %d received\n", size);
615
616 if (percent != 100) {
617 ClientReliableWrite_Begin (host_client, svc_stufftext, 8);
618 ClientReliableWrite_String (host_client, "nextul\n");
619 } else {
620 fclose (host_client->upload);
621 host_client->upload = NULL;
622
623 Sys_Printf("%s upload completed.\n", host_client->uploadfn);
624
625 if (host_client->remote_snap) {
626 char *p;
627
628 if ((p = strchr(host_client->uploadfn, '/')) != NULL)
629 p++;
630 else
631 p = host_client->uploadfn;
632 OutofBandPrintf(host_client->snap_from, "%s upload completed.\nTo download, enter:\ndownload %s\n",
633 host_client->uploadfn, p);
634 }
635 }
636
637 }
638
639 /*
640 ==================
641 SV_BeginDownload_f
642 ==================
643 */
SV_BeginDownload_f(void)644 void SV_BeginDownload_f(void)
645 {
646 char *name;
647 extern cvar_t allow_download;
648 extern cvar_t allow_download_skins;
649 extern cvar_t allow_download_models;
650 extern cvar_t allow_download_sounds;
651 extern cvar_t allow_download_maps;
652 extern int file_from_pak; // ZOID did file come from pak?
653
654 name = Cmd_Argv(1);
655 // hacked by zoid to allow more conrol over download
656 // first off, no .. or global allow check
657 if (strstr (name, "..") || !allow_download.value
658 // leading dot is no good
659 || *name == '.'
660 // leading slash bad as well, must be in subdir
661 || *name == '/'
662 // next up, skin check
663 || (strncmp(name, "skins/", 6) == 0 && !allow_download_skins.value)
664 // now models
665 || (strncmp(name, "progs/", 6) == 0 && !allow_download_models.value)
666 // now sounds
667 || (strncmp(name, "sound/", 6) == 0 && !allow_download_sounds.value)
668 // now maps (note special case for maps, must not be in pak)
669 || (strncmp(name, "maps/", 6) == 0 && !allow_download_maps.value)
670 // MUST be in a subdirectory
671 || !strstr (name, "/") )
672 { // don't allow anything with .. path
673 ClientReliableWrite_Begin (host_client, svc_download, 4);
674 ClientReliableWrite_Short (host_client, -1);
675 ClientReliableWrite_Byte (host_client, 0);
676 return;
677 }
678
679 if (host_client->download) {
680 fclose (host_client->download);
681 host_client->download = NULL;
682 }
683
684 // lowercase name (needed for casesen file systems)
685 {
686 char *p;
687
688 for (p = name; *p; p++)
689 *p = (char)tolower(*p);
690 }
691
692
693 host_client->downloadsize = COM_FOpenFile (name, &host_client->download);
694 host_client->downloadcount = 0;
695
696 if (!host_client->download
697 // special check for maps, if it came from a pak file, don't allow
698 // download ZOID
699 || (strncmp(name, "maps/", 5) == 0 && file_from_pak))
700 {
701 if (host_client->download) {
702 fclose(host_client->download);
703 host_client->download = NULL;
704 }
705
706 Sys_Printf ("Couldn't download %s to %s\n", name, host_client->name);
707 ClientReliableWrite_Begin (host_client, svc_download, 4);
708 ClientReliableWrite_Short (host_client, -1);
709 ClientReliableWrite_Byte (host_client, 0);
710 return;
711 }
712
713 SV_NextDownload_f ();
714 Sys_Printf ("Downloading %s to %s\n", name, host_client->name);
715 }
716
717 //=============================================================================
718
719 /*
720 ==================
721 SV_Say
722 ==================
723 */
SV_Say(qboolean team)724 void SV_Say (qboolean team)
725 {
726 client_t *client;
727 int j, tmp;
728 char *p;
729 char text[2048];
730 char t1[32], *t2;
731
732 if (Cmd_Argc () < 2)
733 return;
734
735 if (team)
736 {
737 strncpy (t1, Info_ValueForKey (host_client->userinfo, "team"), 31);
738 t1[31] = 0;
739 }
740
741 if (host_client->spectator && (!sv_spectalk.value || team))
742 sprintf (text, "[SPEC] %s: ", host_client->name);
743 else if (team)
744 sprintf (text, "(%s): ", host_client->name);
745 else {
746 sprintf (text, "%s: ", host_client->name);
747 }
748
749 if (fp_messages) {
750 if (!sv.paused && realtime<host_client->lockedtill) {
751 SV_ClientPrintf(host_client, PRINT_CHAT,
752 "You can't talk for %d more seconds\n",
753 (int) (host_client->lockedtill - realtime));
754 return;
755 }
756 tmp = host_client->whensaidhead - fp_messages + 1;
757 if (tmp < 0)
758 tmp = 10+tmp;
759 if (!sv.paused &&
760 host_client->whensaid[tmp] && (realtime-host_client->whensaid[tmp] < fp_persecond)) {
761 host_client->lockedtill = realtime + fp_secondsdead;
762 if (fp_msg[0])
763 SV_ClientPrintf(host_client, PRINT_CHAT,
764 "FloodProt: %s\n", fp_msg);
765 else
766 SV_ClientPrintf(host_client, PRINT_CHAT,
767 "FloodProt: You can't talk for %d seconds.\n", fp_secondsdead);
768 return;
769 }
770 host_client->whensaidhead++;
771 if (host_client->whensaidhead > 9)
772 host_client->whensaidhead = 0;
773 host_client->whensaid[host_client->whensaidhead] = realtime;
774 }
775
776 p = Cmd_Args();
777
778 if (*p == '"')
779 {
780 p++;
781 p[Q_strlen(p)-1] = 0;
782 }
783
784 Q_strcat(text, p);
785 Q_strcat(text, "\n");
786
787 Sys_Printf ("%s", text);
788
789 for (j = 0, client = svs.clients; j < MAX_CLIENTS; j++, client++)
790 {
791 if (client->state != cs_spawned)
792 continue;
793 if (host_client->spectator && !sv_spectalk.value)
794 if (!client->spectator)
795 continue;
796
797 if (team)
798 {
799 // the spectator team
800 if (host_client->spectator) {
801 if (!client->spectator)
802 continue;
803 } else {
804 t2 = Info_ValueForKey (client->userinfo, "team");
805 if (strcmp(t1, t2) || client->spectator)
806 continue; // on different teams
807 }
808 }
809 SV_ClientPrintf(client, PRINT_CHAT, "%s", text);
810 }
811 }
812
813
814 /*
815 ==================
816 SV_Say_f
817 ==================
818 */
SV_Say_f(void)819 void SV_Say_f(void)
820 {
821 SV_Say (false);
822 }
823 /*
824 ==================
825 SV_Say_Team_f
826 ==================
827 */
SV_Say_Team_f(void)828 void SV_Say_Team_f(void)
829 {
830 SV_Say (true);
831 }
832
833
834
835 //============================================================================
836
837 /*
838 =================
839 SV_Pings_f
840
841 The client is showing the scoreboard, so send new ping times for all
842 clients
843 =================
844 */
SV_Pings_f(void)845 void SV_Pings_f (void)
846 {
847 client_t *client;
848 int j;
849
850 for (j = 0, client = svs.clients; j < MAX_CLIENTS; j++, client++)
851 {
852 if (client->state != cs_spawned)
853 continue;
854
855 ClientReliableWrite_Begin (host_client, svc_updateping, 4);
856 ClientReliableWrite_Byte (host_client, j);
857 ClientReliableWrite_Short (host_client, SV_CalcPing(client));
858 ClientReliableWrite_Begin (host_client, svc_updatepl, 4);
859 ClientReliableWrite_Byte (host_client, j);
860 ClientReliableWrite_Byte (host_client, client->lossage);
861 }
862 }
863
864
865
866 /*
867 ==================
868 SV_Kill_f
869 ==================
870 */
SV_Kill_f(void)871 void SV_Kill_f (void)
872 {
873 if (sv_player->v.health <= 0)
874 {
875 SV_ClientPrintf (host_client, PRINT_HIGH, "Can't suicide -- allready dead!\n");
876 return;
877 }
878
879 pr_global_struct->time = sv.time;
880 pr_global_struct->self = EDICT_TO_PROG(sv_player);
881 PR_ExecuteProgram (pr_global_struct->ClientKill);
882 }
883
884 /*
885 ==================
886 SV_TogglePause
887 ==================
888 */
SV_TogglePause(const char * msg)889 void SV_TogglePause (const char *msg)
890 {
891 int i;
892 client_t *cl;
893
894 sv.paused ^= 1;
895
896 if (msg)
897 SV_BroadcastPrintf (PRINT_HIGH, "%s", msg);
898
899 // send notification to all clients
900 for (i=0, cl = svs.clients ; i<MAX_CLIENTS ; i++, cl++)
901 {
902 if (!cl->state)
903 continue;
904 ClientReliableWrite_Begin (cl, svc_setpause, 2);
905 ClientReliableWrite_Byte (cl, sv.paused);
906 }
907 }
908
909
910 /*
911 ==================
912 SV_Pause_f
913 ==================
914 */
SV_Pause_f(void)915 void SV_Pause_f (void)
916 {
917 int i;
918 client_t *cl;
919 char st[sizeof(host_client->name) + 32];
920
921 if (!pausable.value) {
922 SV_ClientPrintf (host_client, PRINT_HIGH, "Pause not allowed.\n");
923 return;
924 }
925
926 if (host_client->spectator) {
927 SV_ClientPrintf (host_client, PRINT_HIGH, "Spectators can not pause.\n");
928 return;
929 }
930
931 if (sv.paused)
932 sprintf (st, "%s paused the game\n", host_client->name);
933 else
934 sprintf (st, "%s unpaused the game\n", host_client->name);
935
936 SV_TogglePause(st);
937 }
938
939
940 /*
941 =================
942 SV_Drop_f
943
944 The client is going to disconnect, so remove the connection immediately
945 =================
946 */
SV_Drop_f(void)947 void SV_Drop_f (void)
948 {
949 SV_EndRedirect ();
950 if (!host_client->spectator)
951 SV_BroadcastPrintf (PRINT_HIGH, "%s dropped\n", host_client->name);
952 SV_DropClient (host_client);
953 }
954
955 /*
956 =================
957 SV_PTrack_f
958
959 Change the bandwidth estimate for a client
960 =================
961 */
SV_PTrack_f(void)962 void SV_PTrack_f (void)
963 {
964 int i;
965 edict_t *ent, *tent;
966
967 if (!host_client->spectator)
968 return;
969
970 if (Cmd_Argc() != 2)
971 {
972 // turn off tracking
973 host_client->spec_track = 0;
974 ent = EDICT_NUM(host_client - svs.clients + 1);
975 tent = EDICT_NUM(0);
976 ent->v.goalentity = EDICT_TO_PROG(tent);
977 return;
978 }
979
980 i = atoi(Cmd_Argv(1));
981 if (i < 0 || i >= MAX_CLIENTS || svs.clients[i].state != cs_spawned ||
982 svs.clients[i].spectator) {
983 SV_ClientPrintf (host_client, PRINT_HIGH, "Invalid client to track\n");
984 host_client->spec_track = 0;
985 ent = EDICT_NUM(host_client - svs.clients + 1);
986 tent = EDICT_NUM(0);
987 ent->v.goalentity = EDICT_TO_PROG(tent);
988 return;
989 }
990 host_client->spec_track = i + 1; // now tracking
991
992 ent = EDICT_NUM(host_client - svs.clients + 1);
993 tent = EDICT_NUM(i + 1);
994 ent->v.goalentity = EDICT_TO_PROG(tent);
995 }
996
997
998 /*
999 =================
1000 SV_Rate_f
1001
1002 Change the bandwidth estimate for a client
1003 =================
1004 */
SV_Rate_f(void)1005 void SV_Rate_f (void)
1006 {
1007 int rate;
1008
1009 if (Cmd_Argc() != 2)
1010 {
1011 SV_ClientPrintf (host_client, PRINT_HIGH, "Current rate is %i\n",
1012 (int)(1.0/host_client->netchan.rate + 0.5));
1013 return;
1014 }
1015
1016 rate = atoi(Cmd_Argv(1));
1017 if (rate < 500)
1018 rate = 500;
1019 if (rate > 10000)
1020 rate = 10000;
1021
1022 SV_ClientPrintf (host_client, PRINT_HIGH, "Net rate set to %i\n", rate);
1023 host_client->netchan.rate = 1.0/rate;
1024 }
1025
1026
1027 /*
1028 =================
1029 SV_Msg_f
1030
1031 Change the message level for a client
1032 =================
1033 */
SV_Msg_f(void)1034 void SV_Msg_f (void)
1035 {
1036 if (Cmd_Argc() != 2)
1037 {
1038 SV_ClientPrintf (host_client, PRINT_HIGH, "Current msg level is %i\n",
1039 host_client->messagelevel);
1040 return;
1041 }
1042
1043 host_client->messagelevel = atoi(Cmd_Argv(1));
1044
1045 SV_ClientPrintf (host_client, PRINT_HIGH, "Msg level set to %i\n", host_client->messagelevel);
1046 }
1047
1048 /*
1049 ==================
1050 SV_SetInfo_f
1051
1052 Allow clients to change userinfo
1053 ==================
1054 */
SV_SetInfo_f(void)1055 void SV_SetInfo_f (void)
1056 {
1057 int i;
1058 char oldval[MAX_INFO_STRING];
1059
1060
1061 if (Cmd_Argc() == 1)
1062 {
1063 Con_Printf ("User info settings:\n");
1064 Info_Print (host_client->userinfo);
1065 return;
1066 }
1067
1068 if (Cmd_Argc() != 3)
1069 {
1070 Con_Printf ("usage: setinfo [ <key> <value> ]\n");
1071 return;
1072 }
1073
1074 if (Cmd_Argv(1)[0] == '*')
1075 return; // don't set priveledged values
1076
1077 strcpy(oldval, Info_ValueForKey(host_client->userinfo, Cmd_Argv(1)));
1078
1079 Info_SetValueForKey (host_client->userinfo, Cmd_Argv(1), Cmd_Argv(2), MAX_INFO_STRING);
1080 // name is extracted below in ExtractFromUserInfo
1081 // strncpy (host_client->name, Info_ValueForKey (host_client->userinfo, "name")
1082 // , sizeof(host_client->name)-1);
1083 // SV_FullClientUpdate (host_client, &sv.reliable_datagram);
1084 // host_client->sendinfo = true;
1085
1086 if (!strcmp(Info_ValueForKey(host_client->userinfo, Cmd_Argv(1)), oldval))
1087 return; // key hasn't changed
1088
1089 // process any changed values
1090 SV_ExtractFromUserinfo (host_client);
1091
1092 i = host_client - svs.clients;
1093 MSG_WriteByte (&sv.reliable_datagram, svc_setinfo);
1094 MSG_WriteByte (&sv.reliable_datagram, i);
1095 MSG_WriteString (&sv.reliable_datagram, Cmd_Argv(1));
1096 MSG_WriteString (&sv.reliable_datagram, Info_ValueForKey(host_client->userinfo, Cmd_Argv(1)));
1097 }
1098
1099 /*
1100 ==================
1101 SV_ShowServerinfo_f
1102
1103 Dumps the serverinfo info string
1104 ==================
1105 */
SV_ShowServerinfo_f(void)1106 void SV_ShowServerinfo_f (void)
1107 {
1108 Info_Print (svs.info);
1109 }
1110
SV_NoSnap_f(void)1111 void SV_NoSnap_f(void)
1112 {
1113 if (*host_client->uploadfn) {
1114 *host_client->uploadfn = 0;
1115 SV_BroadcastPrintf (PRINT_HIGH, "%s refused remote screenshot\n", host_client->name);
1116 }
1117 }
1118
1119 typedef struct
1120 {
1121 char *name;
1122 void (*func) (void);
1123 } ucmd_t;
1124
1125 ucmd_t ucmds[] =
1126 {
1127 {"new", SV_New_f},
1128 {"modellist", SV_Modellist_f},
1129 {"soundlist", SV_Soundlist_f},
1130 {"prespawn", SV_PreSpawn_f},
1131 {"spawn", SV_Spawn_f},
1132 {"begin", SV_Begin_f},
1133
1134 {"drop", SV_Drop_f},
1135 {"pings", SV_Pings_f},
1136
1137 // issued by hand at client consoles
1138 {"rate", SV_Rate_f},
1139 {"kill", SV_Kill_f},
1140 {"pause", SV_Pause_f},
1141 {"msg", SV_Msg_f},
1142
1143 {"say", SV_Say_f},
1144 {"say_team", SV_Say_Team_f},
1145
1146 {"setinfo", SV_SetInfo_f},
1147
1148 {"serverinfo", SV_ShowServerinfo_f},
1149
1150 {"download", SV_BeginDownload_f},
1151 {"nextdl", SV_NextDownload_f},
1152
1153 {"ptrack", SV_PTrack_f}, //ZOID - used with autocam
1154
1155 {"snap", SV_NoSnap_f},
1156
1157 {NULL, NULL}
1158 };
1159
1160 /*
1161 ==================
1162 SV_ExecuteUserCommand
1163 ==================
1164 */
SV_ExecuteUserCommand(char * s)1165 void SV_ExecuteUserCommand (char *s)
1166 {
1167 ucmd_t *u;
1168
1169 Cmd_TokenizeString (s);
1170 sv_player = host_client->edict;
1171
1172 SV_BeginRedirect (RD_CLIENT);
1173
1174 for (u=ucmds ; u->name ; u++)
1175 if (!strcmp (Cmd_Argv(0), u->name) )
1176 {
1177 u->func ();
1178 break;
1179 }
1180
1181 if (!u->name)
1182 Con_Printf ("Bad user command: %s\n", Cmd_Argv(0));
1183
1184 SV_EndRedirect ();
1185 }
1186
1187 /*
1188 ===========================================================================
1189
1190 USER CMD EXECUTION
1191
1192 ===========================================================================
1193 */
1194
1195 /*
1196 ===============
1197 V_CalcRoll
1198
1199 Used by view and sv_user
1200 ===============
1201 */
V_CalcRoll(vec3_t angles,vec3_t velocity)1202 float V_CalcRoll (vec3_t angles, vec3_t velocity)
1203 {
1204 vec3_t forward, right, up;
1205 float sign;
1206 float side;
1207 float value;
1208
1209 AngleVectors (angles, forward, right, up);
1210 side = DotProduct (velocity, right);
1211 sign = side < 0 ? -1 : 1;
1212 side = fabs(side);
1213
1214 value = cl_rollangle.value;
1215
1216 if (side < cl_rollspeed.value)
1217 side = side * value / cl_rollspeed.value;
1218 else
1219 side = value;
1220
1221 return side*sign;
1222
1223 }
1224
1225
1226
1227
1228 //============================================================================
1229
1230 vec3_t pmove_mins, pmove_maxs;
1231
1232 /*
1233 ====================
1234 AddLinksToPmove
1235
1236 ====================
1237 */
AddLinksToPmove(areanode_t * node)1238 void AddLinksToPmove ( areanode_t *node )
1239 {
1240 link_t *l, *next;
1241 edict_t *check;
1242 int pl;
1243 int i;
1244 physent_t *pe;
1245
1246 pl = EDICT_TO_PROG(sv_player);
1247
1248 // touch linked edicts
1249 for (l = node->solid_edicts.next ; l != &node->solid_edicts ; l = next)
1250 {
1251 next = l->next;
1252 check = EDICT_FROM_AREA(l);
1253
1254 if (check->v.owner == pl)
1255 continue; // player's own missile
1256 if (check->v.solid == SOLID_BSP
1257 || check->v.solid == SOLID_BBOX
1258 || check->v.solid == SOLID_SLIDEBOX)
1259 {
1260 if (check == sv_player)
1261 continue;
1262
1263 for (i=0 ; i<3 ; i++)
1264 if (check->v.absmin[i] > pmove_maxs[i]
1265 || check->v.absmax[i] < pmove_mins[i])
1266 break;
1267 if (i != 3)
1268 continue;
1269 if (pmove.numphysent == MAX_PHYSENTS)
1270 return;
1271 pe = &pmove.physents[pmove.numphysent];
1272 pmove.numphysent++;
1273
1274 VectorCopy (check->v.origin, pe->origin);
1275 pe->info = NUM_FOR_EDICT(check);
1276 if (check->v.solid == SOLID_BSP)
1277 pe->model = sv.models[(int)(check->v.modelindex)];
1278 else
1279 {
1280 pe->model = NULL;
1281 VectorCopy (check->v.mins, pe->mins);
1282 VectorCopy (check->v.maxs, pe->maxs);
1283 }
1284 }
1285 }
1286
1287 // recurse down both sides
1288 if (node->axis == -1)
1289 return;
1290
1291 if ( pmove_maxs[node->axis] > node->dist )
1292 AddLinksToPmove ( node->children[0] );
1293 if ( pmove_mins[node->axis] < node->dist )
1294 AddLinksToPmove ( node->children[1] );
1295 }
1296
1297
1298 /*
1299 ================
1300 AddAllEntsToPmove
1301
1302 For debugging
1303 ================
1304 */
AddAllEntsToPmove(void)1305 void AddAllEntsToPmove (void)
1306 {
1307 int e;
1308 edict_t *check;
1309 int i;
1310 physent_t *pe;
1311 int pl;
1312
1313 pl = EDICT_TO_PROG(sv_player);
1314 check = NEXT_EDICT(sv.edicts);
1315 for (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check))
1316 {
1317 if (check->free)
1318 continue;
1319 if (check->v.owner == pl)
1320 continue;
1321 if (check->v.solid == SOLID_BSP
1322 || check->v.solid == SOLID_BBOX
1323 || check->v.solid == SOLID_SLIDEBOX)
1324 {
1325 if (check == sv_player)
1326 continue;
1327
1328 for (i=0 ; i<3 ; i++)
1329 if (check->v.absmin[i] > pmove_maxs[i]
1330 || check->v.absmax[i] < pmove_mins[i])
1331 break;
1332 if (i != 3)
1333 continue;
1334 pe = &pmove.physents[pmove.numphysent];
1335
1336 VectorCopy (check->v.origin, pe->origin);
1337 pmove.physents[pmove.numphysent].info = e;
1338 if (check->v.solid == SOLID_BSP)
1339 pe->model = sv.models[(int)(check->v.modelindex)];
1340 else
1341 {
1342 pe->model = NULL;
1343 VectorCopy (check->v.mins, pe->mins);
1344 VectorCopy (check->v.maxs, pe->maxs);
1345 }
1346
1347 if (++pmove.numphysent == MAX_PHYSENTS)
1348 break;
1349 }
1350 }
1351 }
1352
1353 /*
1354 ===========
1355 SV_PreRunCmd
1356 ===========
1357 Done before running a player command. Clears the touch array
1358 */
1359 byte playertouch[(MAX_EDICTS+7)/8];
1360
SV_PreRunCmd(void)1361 void SV_PreRunCmd(void)
1362 {
1363 memset(playertouch, 0, sizeof(playertouch));
1364 }
1365
1366 /*
1367 ===========
1368 SV_RunCmd
1369 ===========
1370 */
SV_RunCmd(usercmd_t * ucmd)1371 void SV_RunCmd (usercmd_t *ucmd)
1372 {
1373 edict_t *ent;
1374 int i, n;
1375 int oldmsec;
1376
1377 cmd = *ucmd;
1378
1379 // chop up very long commands
1380 if (cmd.msec > 50)
1381 {
1382 oldmsec = ucmd->msec;
1383 cmd.msec = oldmsec/2;
1384 SV_RunCmd (&cmd);
1385 cmd.msec = oldmsec/2;
1386 cmd.impulse = 0;
1387 SV_RunCmd (&cmd);
1388 return;
1389 }
1390
1391 if (!sv_player->v.fixangle)
1392 VectorCopy (ucmd->angles, sv_player->v.v_angle);
1393
1394 sv_player->v.button0 = ucmd->buttons & 1;
1395 sv_player->v.button2 = (ucmd->buttons & 2)>>1;
1396 if (ucmd->impulse)
1397 sv_player->v.impulse = ucmd->impulse;
1398
1399 //
1400 // angles
1401 // show 1/3 the pitch angle and all the roll angle
1402 if (sv_player->v.health > 0)
1403 {
1404 if (!sv_player->v.fixangle)
1405 {
1406 sv_player->v.angles[PITCH] = -sv_player->v.v_angle[PITCH]/3;
1407 sv_player->v.angles[YAW] = sv_player->v.v_angle[YAW];
1408 }
1409 sv_player->v.angles[ROLL] =
1410 V_CalcRoll (sv_player->v.angles, sv_player->v.velocity)*4;
1411 }
1412
1413 host_frametime = ucmd->msec * 0.001;
1414 if (host_frametime > 0.1)
1415 host_frametime = 0.1;
1416
1417 if (!host_client->spectator)
1418 {
1419 pr_global_struct->frametime = host_frametime;
1420
1421 pr_global_struct->time = sv.time;
1422 pr_global_struct->self = EDICT_TO_PROG(sv_player);
1423 PR_ExecuteProgram (pr_global_struct->PlayerPreThink);
1424
1425 SV_RunThink (sv_player);
1426 }
1427
1428 for (i=0 ; i<3 ; i++)
1429 pmove.origin[i] = sv_player->v.origin[i] + (sv_player->v.mins[i] - player_mins[i]);
1430 VectorCopy (sv_player->v.velocity, pmove.velocity);
1431 VectorCopy (sv_player->v.v_angle, pmove.angles);
1432
1433 pmove.spectator = host_client->spectator;
1434 pmove.waterjumptime = sv_player->v.teleport_time;
1435 pmove.numphysent = 1;
1436 pmove.physents[0].model = sv.worldmodel;
1437 pmove.cmd = *ucmd;
1438 pmove.dead = sv_player->v.health <= 0;
1439 pmove.oldbuttons = host_client->oldbuttons;
1440
1441 movevars.entgravity = host_client->entgravity;
1442 movevars.maxspeed = host_client->maxspeed;
1443
1444 for (i=0 ; i<3 ; i++)
1445 {
1446 pmove_mins[i] = pmove.origin[i] - 256;
1447 pmove_maxs[i] = pmove.origin[i] + 256;
1448 }
1449 #if 1
1450 AddLinksToPmove ( sv_areanodes );
1451 #else
1452 AddAllEntsToPmove ();
1453 #endif
1454
1455 #if 0
1456 {
1457 int before, after;
1458
1459 before = PM_TestPlayerPosition (pmove.origin);
1460 PlayerMove ();
1461 after = PM_TestPlayerPosition (pmove.origin);
1462
1463 if (sv_player->v.health > 0 && before && !after )
1464 Con_Printf ("player %s got stuck in playermove!!!!\n", host_client->name);
1465 }
1466 #else
1467 PlayerMove ();
1468 #endif
1469
1470 host_client->oldbuttons = pmove.oldbuttons;
1471 sv_player->v.teleport_time = pmove.waterjumptime;
1472 sv_player->v.waterlevel = waterlevel;
1473 sv_player->v.watertype = watertype;
1474 if (onground != -1)
1475 {
1476 sv_player->v.flags = (int)sv_player->v.flags | FL_ONGROUND;
1477 sv_player->v.groundentity = EDICT_TO_PROG(EDICT_NUM(pmove.physents[onground].info));
1478 }
1479 else
1480 sv_player->v.flags = (int)sv_player->v.flags & ~FL_ONGROUND;
1481 for (i=0 ; i<3 ; i++)
1482 sv_player->v.origin[i] = pmove.origin[i] - (sv_player->v.mins[i] - player_mins[i]);
1483
1484 #if 0
1485 // truncate velocity the same way the net protocol will
1486 for (i=0 ; i<3 ; i++)
1487 sv_player->v.velocity[i] = (int)pmove.velocity[i];
1488 #else
1489 VectorCopy (pmove.velocity, sv_player->v.velocity);
1490 #endif
1491
1492 VectorCopy (pmove.angles, sv_player->v.v_angle);
1493
1494 if (!host_client->spectator)
1495 {
1496 // link into place and touch triggers
1497 SV_LinkEdict (sv_player, true);
1498
1499 // touch other objects
1500 for (i=0 ; i<pmove.numtouch ; i++)
1501 {
1502 n = pmove.physents[pmove.touchindex[i]].info;
1503 ent = EDICT_NUM(n);
1504 if (!ent->v.touch || (playertouch[n/8]&(1<<(n%8))))
1505 continue;
1506 pr_global_struct->self = EDICT_TO_PROG(ent);
1507 pr_global_struct->other = EDICT_TO_PROG(sv_player);
1508 PR_ExecuteProgram (ent->v.touch);
1509 playertouch[n/8] |= 1 << (n%8);
1510 }
1511 }
1512 }
1513
1514 /*
1515 ===========
1516 SV_PostRunCmd
1517 ===========
1518 Done after running a player command.
1519 */
SV_PostRunCmd(void)1520 void SV_PostRunCmd(void)
1521 {
1522 // run post-think
1523
1524 if (!host_client->spectator) {
1525 pr_global_struct->time = sv.time;
1526 pr_global_struct->self = EDICT_TO_PROG(sv_player);
1527 PR_ExecuteProgram (pr_global_struct->PlayerPostThink);
1528 SV_RunNewmis ();
1529 } else if (SpectatorThink) {
1530 pr_global_struct->time = sv.time;
1531 pr_global_struct->self = EDICT_TO_PROG(sv_player);
1532 PR_ExecuteProgram (SpectatorThink);
1533 }
1534 }
1535
1536
1537 /*
1538 ===================
1539 SV_ExecuteClientMessage
1540
1541 The current net_message is parsed for the given client
1542 ===================
1543 */
SV_ExecuteClientMessage(client_t * cl)1544 void SV_ExecuteClientMessage (client_t *cl)
1545 {
1546 int c;
1547 char *s;
1548 usercmd_t oldest, oldcmd, newcmd;
1549 client_frame_t *frame;
1550 vec3_t o;
1551 qboolean move_issued = false; //only allow one move command
1552 int checksumIndex;
1553 byte checksum, calculatedChecksum;
1554 int seq_hash;
1555
1556 // calc ping time
1557 frame = &cl->frames[cl->netchan.incoming_acknowledged & UPDATE_MASK];
1558 frame->ping_time = realtime - frame->senttime;
1559
1560 // make sure the reply sequence number matches the incoming
1561 // sequence number
1562 if (cl->netchan.incoming_sequence >= cl->netchan.outgoing_sequence)
1563 cl->netchan.outgoing_sequence = cl->netchan.incoming_sequence;
1564 else
1565 cl->send_message = false; // don't reply, sequences have slipped
1566
1567 // save time for ping calculations
1568 cl->frames[cl->netchan.outgoing_sequence & UPDATE_MASK].senttime = realtime;
1569 cl->frames[cl->netchan.outgoing_sequence & UPDATE_MASK].ping_time = -1;
1570
1571 host_client = cl;
1572 sv_player = host_client->edict;
1573
1574 // seq_hash = (cl->netchan.incoming_sequence & 0xffff) ; // ^ QW_CHECK_HASH;
1575 seq_hash = cl->netchan.incoming_sequence;
1576
1577 // mark time so clients will know how much to predict
1578 // other players
1579 cl->localtime = sv.time;
1580 cl->delta_sequence = -1; // no delta unless requested
1581 while (1)
1582 {
1583 if (msg_badread)
1584 {
1585 Con_Printf ("SV_ReadClientMessage: badread\n");
1586 SV_DropClient (cl);
1587 return;
1588 }
1589
1590 c = MSG_ReadByte ();
1591 if (c == -1)
1592 break;
1593
1594 switch (c)
1595 {
1596 default:
1597 Con_Printf ("SV_ReadClientMessage: unknown command char\n");
1598 SV_DropClient (cl);
1599 return;
1600
1601 case clc_nop:
1602 break;
1603
1604 case clc_delta:
1605 cl->delta_sequence = MSG_ReadByte ();
1606 break;
1607
1608 case clc_move:
1609 if (move_issued)
1610 return; // someone is trying to cheat...
1611
1612 move_issued = true;
1613
1614 checksumIndex = MSG_GetReadCount();
1615 checksum = (byte)MSG_ReadByte ();
1616
1617 // read loss percentage
1618 cl->lossage = MSG_ReadByte();
1619
1620 MSG_ReadDeltaUsercmd (&nullcmd, &oldest);
1621 MSG_ReadDeltaUsercmd (&oldest, &oldcmd);
1622 MSG_ReadDeltaUsercmd (&oldcmd, &newcmd);
1623
1624 if ( cl->state != cs_spawned )
1625 break;
1626
1627 // if the checksum fails, ignore the rest of the packet
1628 calculatedChecksum = COM_BlockSequenceCRCByte(
1629 net_message.data + checksumIndex + 1,
1630 MSG_GetReadCount() - checksumIndex - 1,
1631 seq_hash);
1632
1633 if (calculatedChecksum != checksum)
1634 {
1635 Con_DPrintf ("Failed command checksum for %s(%d) (%d != %d)\n",
1636 cl->name, cl->netchan.incoming_sequence, checksum, calculatedChecksum);
1637 return;
1638 }
1639
1640 if (!sv.paused) {
1641 SV_PreRunCmd();
1642
1643 if (net_drop < 20)
1644 {
1645 while (net_drop > 2)
1646 {
1647 SV_RunCmd (&cl->lastcmd);
1648 net_drop--;
1649 }
1650 if (net_drop > 1)
1651 SV_RunCmd (&oldest);
1652 if (net_drop > 0)
1653 SV_RunCmd (&oldcmd);
1654 }
1655 SV_RunCmd (&newcmd);
1656
1657 SV_PostRunCmd();
1658 }
1659
1660 cl->lastcmd = newcmd;
1661 cl->lastcmd.buttons = 0; // avoid multiple fires on lag
1662 break;
1663
1664
1665 case clc_stringcmd:
1666 s = MSG_ReadString ();
1667 SV_ExecuteUserCommand (s);
1668 break;
1669
1670 case clc_tmove:
1671 o[0] = MSG_ReadCoord();
1672 o[1] = MSG_ReadCoord();
1673 o[2] = MSG_ReadCoord();
1674 // only allowed by spectators
1675 if (host_client->spectator) {
1676 VectorCopy(o, sv_player->v.origin);
1677 SV_LinkEdict(sv_player, false);
1678 }
1679 break;
1680
1681 case clc_upload:
1682 SV_NextUpload();
1683 break;
1684
1685 }
1686 }
1687 }
1688
1689 /*
1690 ==============
1691 SV_UserInit
1692 ==============
1693 */
SV_UserInit(void)1694 void SV_UserInit (void)
1695 {
1696 Cvar_RegisterVariable (&cl_rollspeed);
1697 Cvar_RegisterVariable (&cl_rollangle);
1698 Cvar_RegisterVariable (&sv_spectalk);
1699 Cvar_RegisterVariable (&sv_mapcheck);
1700 }
1701
1702
1703