|
|
1.1 root 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: */
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: */
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: */
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: */
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: */
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: */
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: */
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: */
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:
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: */
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: */
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: */
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: */
819: void SV_Say_f(void)
820: {
821: SV_Say (false);
822: }
823: /*
824: ==================
825: SV_Say_Team_f
826: ==================
827: */
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: */
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: */
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: */
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: */
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: */
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: */
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: */
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: */
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: */
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: */
1106: void SV_ShowServerinfo_f (void)
1107: {
1108: Info_Print (svs.info);
1109: }
1110:
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: */
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: */
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: */
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: */
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:
1361: void SV_PreRunCmd(void)
1362: {
1363: memset(playertouch, 0, sizeof(playertouch));
1364: }
1365:
1366: /*
1367: ===========
1368: SV_RunCmd
1369: ===========
1370: */
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: */
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: */
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: */
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:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.