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 // cl_parse.c  -- parse a message received from the server
21 
22 #include "cdaudio.h"
23 #include "client.h"
24 #include "cmd.h"
25 #include "console.h"
26 #include "model.h"
27 #include "pmove.h"
28 #include "quakedef.h"
29 #include "sbar.h"
30 #include "screen.h"
31 #include "sys.h"
32 
33 #include "d_iface.h"
34 
35 static const char *svc_strings[] = {
36     "svc_bad",
37     "svc_nop",
38     "svc_disconnect",
39     "svc_updatestat",
40     "svc_version",		// [long] server version
41     "svc_setview",		// [short] entity number
42     "svc_sound",		// <see code>
43     "svc_time",			// [float] server time
44     "svc_print",		// [string] null terminated string
45     "svc_stufftext",		// [string] stuffed into clients console buffer
46 				// the string should be \n terminated
47     "svc_setangle",		// [vec3] set the view angle to this absolute
48 				// value
49 
50     "svc_serverdata",		// [long] version ...
51     "svc_lightstyle",		// [byte] [string]
52     "svc_updatename",		// [byte] [string]
53     "svc_updatefrags",		// [byte] [short]
54     "svc_clientdata",		// <shortbits + data>
55     "svc_stopsound",		// <see code>
56     "svc_updatecolors",		// [byte] [byte]
57     "svc_particle",		// [vec3] <variable>
58     "svc_damage",		// [byte] impact [byte] blood [vec3] from
59 
60     "svc_spawnstatic",
61     "OBSOLETE svc_spawnbinary",
62     "svc_spawnbaseline",
63 
64     "svc_temp_entity",		// <variable>
65     "svc_setpause",
66     "svc_signonnum",
67     "svc_centerprint",
68     "svc_killedmonster",
69     "svc_foundsecret",
70     "svc_spawnstaticsound",
71     "svc_intermission",
72     "svc_finale",
73 
74     "svc_cdtrack",
75     "svc_sellscreen",
76 
77     "svc_smallkick",
78     "svc_bigkick",
79 
80     "svc_updateping",
81     "svc_updateentertime",
82 
83     "svc_updatestatlong",
84     "svc_muzzleflash",
85     "svc_updateuserinfo",
86     "svc_download",
87     "svc_playerinfo",
88     "svc_nails",
89     "svc_choke",
90     "svc_modellist",
91     "svc_soundlist",
92     "svc_packetentities",
93     "svc_deltapacketentities",
94     "svc_maxspeed",
95     "svc_entgravity",
96 
97     "svc_setinfo",
98     "svc_serverinfo",
99     "svc_updatepl",
100     "NEW PROTOCOL",
101     "NEW PROTOCOL",
102     "NEW PROTOCOL",
103     "NEW PROTOCOL",
104     "NEW PROTOCOL",
105     "NEW PROTOCOL",
106     "NEW PROTOCOL",
107     "NEW PROTOCOL",
108     "NEW PROTOCOL",
109     "NEW PROTOCOL",
110     "NEW PROTOCOL",
111     "NEW PROTOCOL",
112     "NEW PROTOCOL"
113 };
114 
115 static int oldparsecountmod;
116 
117 int parsecountmod;
118 double parsecounttime;
119 
120 int cl_spikeindex, cl_playerindex, cl_flagindex;
121 
122 //=============================================================================
123 
124 int packet_latency[NET_TIMINGS];
125 
126 int
CL_CalcNet(void)127 CL_CalcNet(void)
128 {
129     int a, i;
130     frame_t *frame;
131     int lost;
132 
133     for (i = cls.netchan.outgoing_sequence - UPDATE_BACKUP + 1;
134 	 i <= cls.netchan.outgoing_sequence; i++) {
135 	frame = &cl.frames[i & UPDATE_MASK];
136 	if (frame->receivedtime == -1)
137 	    packet_latency[i & NET_TIMINGSMASK] = 9999;	// dropped
138 	else if (frame->receivedtime == -2)
139 	    packet_latency[i & NET_TIMINGSMASK] = 10000;	// choked
140 	else if (frame->invalid)
141 	    packet_latency[i & NET_TIMINGSMASK] = 9998;	// invalid delta
142 	else
143 	    packet_latency[i & NET_TIMINGSMASK] =
144 		(frame->receivedtime - frame->senttime) * 20;
145     }
146 
147     lost = 0;
148     for (a = 0; a < NET_TIMINGS; a++) {
149 	i = (cls.netchan.outgoing_sequence - a) & NET_TIMINGSMASK;
150 	if (packet_latency[i] == 9999)
151 	    lost++;
152     }
153     return lost * 100 / NET_TIMINGS;
154 }
155 
156 //=============================================================================
157 
158 /*
159 ===============
160 CL_CheckOrDownloadFile
161 
162 Returns true if the file exists, otherwise it attempts
163 to start a download from the server.
164 ===============
165 */
166 qboolean
CL_CheckOrDownloadFile(char * filename)167 CL_CheckOrDownloadFile(char *filename)
168 {
169     FILE *f;
170     int maxlen;
171 
172     if (strstr(filename, "..")) {
173 	Con_Printf("Refusing to download a path with ..\n");
174 	return true;
175     }
176 
177     COM_FOpenFile(filename, &f);
178     if (f) {			// it exists, no need to download
179 	fclose(f);
180 	return true;
181     }
182     /* can't download when recording */
183     if (cls.demorecording) {
184 	Con_Printf("Unable to download %s in record mode.\n",
185 		   cls.downloadname);
186 	return true;
187     }
188     /* can't download when playback */
189     if (cls.demoplayback)
190 	return true;
191 
192     snprintf(cls.downloadname, sizeof(cls.downloadname), "%s", filename);
193     Con_Printf("Downloading %s...\n", cls.downloadname);
194 
195     /*
196      * download to a temp name, and only rename to the real name when
197      * done, so if interrupted a runt file wont be left
198      */
199     strcpy(cls.downloadtempname, cls.downloadname); /* same size */
200     COM_StripExtension(cls.downloadtempname);
201 
202     /* make sure the .tmp extension fits... */
203     maxlen = sizeof(cls.downloadtempname);
204     if (strlen(cls.downloadtempname) + strlen(".tmp") > maxlen - 1) {
205 	Con_Printf("Refusing download, pathname too long\n");
206 	return true;
207     }
208     strcat(cls.downloadtempname, ".tmp");
209 
210     MSG_WriteByte(&cls.netchan.message, clc_stringcmd);
211     MSG_WriteStringf(&cls.netchan.message, "download %s", cls.downloadname);
212 
213     cls.downloadnumber++;
214 
215     return false;
216 }
217 
218 /*
219 =================
220 Model_NextDownload
221 =================
222 */
223 static void
Model_NextDownload(void)224 Model_NextDownload(void)
225 {
226     char *s;
227     int i;
228 
229     if (cls.downloadnumber == 0) {
230 	Con_Printf("Checking models...\n");
231 	cls.downloadnumber = 1;
232     }
233 
234     cls.downloadtype = dl_model;
235     for (; cl.model_name[cls.downloadnumber][0]; cls.downloadnumber++) {
236 	s = cl.model_name[cls.downloadnumber];
237 	if (s[0] == '*')
238 	    continue;		// inline brush model
239 	if (!CL_CheckOrDownloadFile(s))
240 	    return;		// started a download
241     }
242 
243     for (i = 1; i < MAX_MODELS; i++) {
244 	if (!cl.model_name[i][0])
245 	    break;
246 
247 	cl.model_precache[i] = Mod_ForName(cl.model_name[i], false);
248 
249 	if (!cl.model_precache[i]) {
250 	    Con_Printf
251 		("\nThe required model file '%s' could not be found or "
252 		 "downloaded.\n\n",
253 		 cl.model_name[i]);
254 	    Con_Printf("You may need to download or purchase a %s client "
255 		       "pack in order to play on this server.\n\n",
256 		       gamedirfile);
257 	    CL_Disconnect();
258 	    return;
259 	}
260     }
261 
262     // all done
263     cl.worldmodel = cl.model_precache[1];
264     R_NewMap();
265     Hunk_Check();		// make sure nothing is hurt
266 
267     // done with modellist, request first of static signon messages
268     MSG_WriteByte(&cls.netchan.message, clc_stringcmd);
269     MSG_WriteStringf(&cls.netchan.message, "prespawn %i 0 %i",
270 		     cl.servercount, cl.worldmodel->checksum2);
271 }
272 
273 /*
274 =================
275 Sound_NextDownload
276 =================
277 */
278 static void
Sound_NextDownload(void)279 Sound_NextDownload(void)
280 {
281     char *s;
282     int i;
283 
284     if (cls.downloadnumber == 0) {
285 	Con_Printf("Checking sounds...\n");
286 	cls.downloadnumber = 1;
287     }
288 
289     cls.downloadtype = dl_sound;
290     for (; cl.sound_name[cls.downloadnumber][0]; cls.downloadnumber++) {
291 	s = cl.sound_name[cls.downloadnumber];
292 	if (!CL_CheckOrDownloadFile(va("sound/%s", s)))
293 	    return;		// started a download
294     }
295 
296     for (i = 1; i < MAX_SOUNDS; i++) {
297 	if (!cl.sound_name[i][0])
298 	    break;
299 	cl.sound_precache[i] = S_PrecacheSound(cl.sound_name[i]);
300     }
301 
302     // done with sounds, request models now
303     memset(cl.model_precache, 0, sizeof(cl.model_precache));
304     cl_playerindex = -1;
305     cl_spikeindex = -1;
306     cl_flagindex = -1;
307     MSG_WriteByte(&cls.netchan.message, clc_stringcmd);
308     MSG_WriteStringf(&cls.netchan.message, "modellist %i 0", cl.servercount);
309 }
310 
311 
312 /*
313 ======================
314 CL_RequestNextDownload
315 ======================
316 */
317 static void
CL_RequestNextDownload(void)318 CL_RequestNextDownload(void)
319 {
320     switch (cls.downloadtype) {
321     case dl_single:
322 	break;
323     case dl_skin:
324 	Skin_NextDownload();
325 	break;
326     case dl_model:
327 	Model_NextDownload();
328 	break;
329     case dl_sound:
330 	Sound_NextDownload();
331 	break;
332     case dl_none:
333     default:
334 	Con_DPrintf("Unknown download type.\n");
335     }
336 }
337 
338 /*
339 =====================
340 CL_ParseDownload
341 
342 A download message has been received from the server
343 =====================
344 */
345 static void
CL_ParseDownload(void)346 CL_ParseDownload(void)
347 {
348     int size, percent;
349     char name[1024];
350     int r;
351 
352 
353     // read the data
354     size = MSG_ReadShort();
355     percent = MSG_ReadByte();
356 
357     if (cls.demoplayback) {
358 	if (size > 0)
359 	    msg_readcount += size;
360 	return;			// not in demo playback
361     }
362 
363     if (size == -1) {
364 	Con_Printf("File not found.\n");
365 	if (cls.download) {
366 	    Con_Printf("cls.download shouldn't have been set\n");
367 	    fclose(cls.download);
368 	    cls.download = NULL;
369 	}
370 	CL_RequestNextDownload();
371 	return;
372     }
373     // open the file if not opened yet
374     if (!cls.download) {
375 	if (strncmp(cls.downloadtempname, "skins/", 6))
376 	    sprintf(name, "%s/%s", com_gamedir, cls.downloadtempname);
377 	else
378 	    sprintf(name, "qw/%s", cls.downloadtempname);
379 
380 	COM_CreatePath(name);
381 
382 	cls.download = fopen(name, "wb");
383 	if (!cls.download) {
384 	    msg_readcount += size;
385 	    Con_Printf("Failed to open %s\n", cls.downloadtempname);
386 	    CL_RequestNextDownload();
387 	    return;
388 	}
389     }
390 
391     fwrite(net_message.data + msg_readcount, 1, size, cls.download);
392     msg_readcount += size;
393 
394     if (percent != 100) {
395 // change display routines by zoid
396 	// request next block
397 #if 0
398 	Con_Printf(".");
399 	if (10 * (percent / 10) != cls.downloadpercent) {
400 	    cls.downloadpercent = 10 * (percent / 10);
401 	    Con_Printf("%i%%", cls.downloadpercent);
402 	}
403 #endif
404 	cls.downloadpercent = percent;
405 
406 	MSG_WriteByte(&cls.netchan.message, clc_stringcmd);
407 	MSG_WriteString(&cls.netchan.message, "nextdl");
408     } else {
409 	char oldn[MAX_OSPATH];
410 	char newn[MAX_OSPATH];
411 
412 #if 0
413 	Con_Printf("100%%\n");
414 #endif
415 
416 	fclose(cls.download);
417 
418 	// rename the temp file to it's final name
419 	if (strcmp(cls.downloadtempname, cls.downloadname)) {
420 	    if (strncmp(cls.downloadtempname, "skins/", 6)) {
421 		sprintf(oldn, "%s/%s", com_gamedir, cls.downloadtempname);
422 		sprintf(newn, "%s/%s", com_gamedir, cls.downloadname);
423 	    } else {
424 		sprintf(oldn, "qw/%s", cls.downloadtempname);
425 		sprintf(newn, "qw/%s", cls.downloadname);
426 	    }
427 	    r = rename(oldn, newn);
428 	    if (r)
429 		Con_Printf("failed to rename.\n");
430 	}
431 
432 	cls.download = NULL;
433 	cls.downloadpercent = 0;
434 
435 	// get another file if needed
436 
437 	CL_RequestNextDownload();
438     }
439 }
440 
441 static byte *upload_data;
442 static int upload_pos;
443 static int upload_size;
444 
445 void
CL_NextUpload(void)446 CL_NextUpload(void)
447 {
448     byte buffer[1024];
449     int r;
450     int percent;
451     int size;
452 
453     if (!upload_data)
454 	return;
455 
456     r = upload_size - upload_pos;
457     if (r > 768)
458 	r = 768;
459     memcpy(buffer, upload_data + upload_pos, r);
460     MSG_WriteByte(&cls.netchan.message, clc_upload);
461     MSG_WriteShort(&cls.netchan.message, r);
462 
463     upload_pos += r;
464     size = upload_size;
465     if (!size)
466 	size = 1;
467     percent = upload_pos * 100 / size;
468     MSG_WriteByte(&cls.netchan.message, percent);
469     SZ_Write(&cls.netchan.message, buffer, r);
470 
471     Con_DPrintf("UPLOAD: %6d: %d written\n", upload_pos - r, r);
472 
473     if (upload_pos != upload_size)
474 	return;
475 
476     Con_Printf("Upload completed\n");
477 
478     free(upload_data);
479     upload_data = 0;
480     upload_pos = upload_size = 0;
481 }
482 
483 void
CL_StartUpload(byte * data,int size)484 CL_StartUpload(byte *data, int size)
485 {
486     if (cls.state < ca_onserver)
487 	return;			// gotta be connected
488 
489     // override
490     if (upload_data)
491 	free(upload_data);
492 
493     Con_DPrintf("Upload starting of %d...\n", size);
494 
495     upload_data = malloc(size);
496     memcpy(upload_data, data, size);
497     upload_size = size;
498     upload_pos = 0;
499 
500     CL_NextUpload();
501 }
502 
503 qboolean
CL_IsUploading(void)504 CL_IsUploading(void)
505 {
506     if (upload_data)
507 	return true;
508     return false;
509 }
510 
511 void
CL_StopUpload(void)512 CL_StopUpload(void)
513 {
514     if (upload_data)
515 	free(upload_data);
516     upload_data = NULL;
517 }
518 
519 /*
520 =====================================================================
521 
522   SERVER CONNECTING MESSAGES
523 
524 =====================================================================
525 */
526 
527 /*
528 ==================
529 CL_ParseServerData
530 ==================
531 */
532 static void
CL_ParseServerData(void)533 CL_ParseServerData(void)
534 {
535     char *str;
536     FILE *f;
537     char fn[MAX_OSPATH];
538     qboolean cflag = false;
539     int protover;
540 
541     Con_DPrintf("Serverdata packet received.\n");
542 //
543 // wipe the client_state_t struct
544 //
545     CL_ClearState();
546 
547 // parse protocol version number
548 // allow 2.2 and 2.29 demos to play
549     protover = MSG_ReadLong();
550     if (protover != PROTOCOL_VERSION &&
551 	!(cls.demoplayback
552 	  && (protover == 26 || protover == 27 || protover == 28)))
553 	Host_EndGame("Server returned version %i, not %i\n"
554 		     "You probably need to upgrade.\n"
555 		     "Check http://disenchant.net/",
556 		     protover, PROTOCOL_VERSION);
557 
558     cl.servercount = MSG_ReadLong();
559 
560     // game directory
561     str = MSG_ReadString();
562 
563     if (strcasecmp(gamedirfile, str)) {
564 	// save current config
565 	Host_WriteConfiguration();
566 	cflag = true;
567     }
568 
569     COM_Gamedir(str);
570 
571     //ZOID--run the autoexec.cfg in the gamedir
572     //if it exists
573     if (cflag) {
574 	snprintf(fn, sizeof(fn), "%s/%s", com_gamedir, "config.cfg");
575 	if ((f = fopen(fn, "r")) != NULL) {
576 	    fclose(f);
577 	    Cbuf_AddText("cl_warncmd 0\n");
578 	    Cbuf_AddText("exec config.cfg\n");
579 	    Cbuf_AddText("exec frontend.cfg\n");
580 	    Cbuf_AddText("cl_warncmd 1\n");
581 	}
582     }
583     // parse player slot, high bit means spectator
584     cl.playernum = MSG_ReadByte();
585     if (cl.playernum & 128) {
586 	cl.spectator = true;
587 	cl.playernum &= ~128;
588     }
589     // get the full level name
590     str = MSG_ReadString();
591     snprintf(cl.levelname, sizeof(cl.levelname), "%s", str);
592 
593     // get the movevars
594     movevars.gravity = MSG_ReadFloat();
595     movevars.stopspeed = MSG_ReadFloat();
596     movevars.maxspeed = MSG_ReadFloat();
597     movevars.spectatormaxspeed = MSG_ReadFloat();
598     movevars.accelerate = MSG_ReadFloat();
599     movevars.airaccelerate = MSG_ReadFloat();
600     movevars.wateraccelerate = MSG_ReadFloat();
601     movevars.friction = MSG_ReadFloat();
602     movevars.waterfriction = MSG_ReadFloat();
603     movevars.entgravity = MSG_ReadFloat();
604 
605     // seperate the printfs so the server message can have a color
606     Con_Printf("\n\n\35\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36"
607 	       "\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\36\37\n\n");
608     Con_Printf("%c%s\n", 2, str);
609 
610     // ask for the sound list next
611     memset(cl.sound_name, 0, sizeof(cl.sound_name));
612     MSG_WriteByte(&cls.netchan.message, clc_stringcmd);
613     MSG_WriteStringf(&cls.netchan.message, "soundlist %i 0", cl.servercount);
614 
615     // now waiting for downloads, etc
616     cls.state = ca_onserver;
617 }
618 
619 /*
620 ==================
621 CL_ParseSoundlist
622 ==================
623 */
624 static void
CL_ParseSoundlist(void)625 CL_ParseSoundlist(void)
626 {
627     const int NAMELEN = sizeof(cl.sound_name[0]);
628 
629     char *str, *name;
630     int numsounds;
631     int n;
632 
633 // precache sounds
634     numsounds = MSG_ReadByte();
635     for (;;) {
636 	str = MSG_ReadString();
637 	if (!str[0])
638 	    break;
639 	numsounds++;
640 	if (numsounds == MAX_SOUNDS)
641 	    Host_EndGame("Server sent too many sound_precache");
642 	name = cl.sound_name[numsounds];
643 	snprintf(name, NAMELEN, "%s", str);
644     }
645 
646     n = MSG_ReadByte();
647     if (n) {
648 	MSG_WriteByte(&cls.netchan.message, clc_stringcmd);
649 	MSG_WriteStringf(&cls.netchan.message, "soundlist %i %i",
650 			 cl.servercount, n);
651 	return;
652     }
653 
654     cls.downloadnumber = 0;
655     cls.downloadtype = dl_sound;
656     Sound_NextDownload();
657 }
658 
659 /*
660 ==================
661 CL_ParseModellist
662 ==================
663 */
664 static void
CL_ParseModellist(void)665 CL_ParseModellist(void)
666 {
667     const int NAMELEN = sizeof(cl.model_name[0]);
668     int nummodels;
669     char *str, *name;
670     int n;
671 
672 // precache models and note certain default indexes
673     nummodels = MSG_ReadByte();
674 
675     for (;;) {
676 	str = MSG_ReadString();
677 	if (!str[0])
678 	    break;
679 	nummodels++;
680 	if (nummodels == MAX_MODELS)
681 	    Host_EndGame("Server sent too many model_precache");
682 	name = cl.model_name[nummodels];
683 	snprintf(name, NAMELEN, "%s", str);
684 
685 	if (!strcmp(name, "progs/spike.mdl"))
686 	    cl_spikeindex = nummodels;
687 	if (!strcmp(name, "progs/player.mdl"))
688 	    cl_playerindex = nummodels;
689 	if (!strcmp(name, "progs/flag.mdl"))
690 	    cl_flagindex = nummodels;
691     }
692 
693     n = MSG_ReadByte();
694 
695     if (n) {
696 	MSG_WriteByte(&cls.netchan.message, clc_stringcmd);
697 	MSG_WriteStringf(&cls.netchan.message, "modellist %i %i",
698 			 cl.servercount, n);
699 	return;
700     }
701 
702     cls.downloadnumber = 0;
703     cls.downloadtype = dl_model;
704     Model_NextDownload();
705 }
706 
707 /*
708 ==================
709 CL_ParseBaseline
710 ==================
711 */
712 static void
CL_ParseBaseline(entity_state_t * es)713 CL_ParseBaseline(entity_state_t *es)
714 {
715     int i;
716 
717     es->modelindex = MSG_ReadByte();
718     es->frame = MSG_ReadByte();
719     es->colormap = MSG_ReadByte();
720     es->skinnum = MSG_ReadByte();
721     for (i = 0; i < 3; i++) {
722 	es->origin[i] = MSG_ReadCoord();
723 	es->angles[i] = MSG_ReadAngle();
724     }
725 }
726 
727 
728 
729 /*
730 =====================
731 CL_ParseStatic
732 
733 Static entities are non-interactive world objects
734 like torches
735 =====================
736 */
737 static void
CL_ParseStatic(void)738 CL_ParseStatic(void)
739 {
740     entity_t *ent;
741     int i;
742     entity_state_t es;
743 
744     CL_ParseBaseline(&es);
745 
746     i = cl.num_statics;
747     if (i >= MAX_STATIC_ENTITIES)
748 	Host_EndGame("Too many static entities");
749     ent = &cl_static_entities[i];
750     cl.num_statics++;
751 
752 // copy it to the current state
753     ent->model = cl.model_precache[es.modelindex];
754     ent->frame = es.frame;
755     ent->colormap = vid.colormap;
756     ent->skinnum = es.skinnum;
757 
758     VectorCopy(es.origin, ent->origin);
759     VectorCopy(es.angles, ent->angles);
760 
761     R_AddEfrags(ent);
762 }
763 
764 /*
765 ===================
766 CL_ParseStaticSound
767 ===================
768 */
769 static void
CL_ParseStaticSound(void)770 CL_ParseStaticSound(void)
771 {
772     vec3_t org;
773     int sound_num, vol, atten;
774     int i;
775 
776     for (i = 0; i < 3; i++)
777 	org[i] = MSG_ReadCoord();
778     sound_num = MSG_ReadByte();
779     vol = MSG_ReadByte();
780     atten = MSG_ReadByte();
781 
782     S_StaticSound(cl.sound_precache[sound_num], org, vol, atten);
783 }
784 
785 
786 
787 /*
788 =====================================================================
789 
790 ACTION MESSAGES
791 
792 =====================================================================
793 */
794 
795 /*
796 ==================
797 CL_ParseStartSoundPacket
798 ==================
799 */
800 static void
CL_ParseStartSoundPacket(void)801 CL_ParseStartSoundPacket(void)
802 {
803     vec3_t pos;
804     int channel, ent;
805     int sound_num;
806     int volume;
807     float attenuation;
808     int i;
809 
810     channel = MSG_ReadShort();
811 
812     if (channel & SND_VOLUME)
813 	volume = MSG_ReadByte();
814     else
815 	volume = DEFAULT_SOUND_PACKET_VOLUME;
816 
817     if (channel & SND_ATTENUATION)
818 	attenuation = MSG_ReadByte() / 64.0;
819     else
820 	attenuation = DEFAULT_SOUND_PACKET_ATTENUATION;
821 
822     sound_num = MSG_ReadByte();
823 
824     for (i = 0; i < 3; i++)
825 	pos[i] = MSG_ReadCoord();
826 
827     ent = (channel >> 3) & 1023;
828     channel &= 7;
829 
830     if (ent > MAX_EDICTS)
831 	Host_EndGame("%s: ent = %i", __func__, ent);
832 
833     S_StartSound(ent, channel, cl.sound_precache[sound_num], pos,
834 		 volume / 255.0, attenuation);
835 }
836 
837 
838 /*
839 ==================
840 CL_ParseClientdata
841 
842 Server information pertaining to this client only, sent every frame
843 ==================
844 */
845 static void
CL_ParseClientdata(void)846 CL_ParseClientdata(void)
847 {
848     int i;
849     float latency;
850     frame_t *frame;
851 
852 // calculate simulated time of message
853     oldparsecountmod = parsecountmod;
854 
855     i = cls.netchan.incoming_acknowledged;
856     cl.parsecount = i;
857     i &= UPDATE_MASK;
858     parsecountmod = i;
859     frame = &cl.frames[i];
860     parsecounttime = cl.frames[i].senttime;
861 
862     frame->receivedtime = realtime;
863 
864 // calculate latency
865     latency = frame->receivedtime - frame->senttime;
866 
867     if (latency < 0 || latency > 1.0) {
868 //              Con_Printf ("Odd latency: %5.2f\n", latency);
869     } else {
870 	// drift the average latency towards the observed latency
871 	if (latency < cls.latency)
872 	    cls.latency = latency;
873 	else
874 	    cls.latency += 0.001;	// drift up, so correction are needed
875     }
876 }
877 
878 /*
879 =====================
880 CL_NewTranslation
881 =====================
882 */
883 static void
CL_NewTranslation(int slot)884 CL_NewTranslation(int slot)
885 {
886    int i, j;
887    int top, bottom;
888    byte *dest, *source;
889    player_info_t *player;
890    char *skin;
891 
892    if (slot > MAX_CLIENTS)
893       Sys_Error("%s: slot > MAX_CLIENTS", __func__);
894 
895    player = &cl.players[slot];
896 
897    skin = Info_ValueForKey(player->userinfo, "skin");
898    COM_StripExtension(skin);
899 
900    if (player->skin && !strcasecmp(skin, player->skin->name))
901       player->skin = NULL;
902 
903    if (player->_topcolor != player->topcolor ||
904          player->_bottomcolor != player->bottomcolor || !player->skin) {
905       player->_topcolor = player->topcolor;
906       player->_bottomcolor = player->bottomcolor;
907 
908       dest = player->translations;
909       source = vid.colormap;
910       memcpy(dest, vid.colormap, sizeof(player->translations));
911       top = player->topcolor;
912       if (top > 13 || top < 0)
913          top = 13;
914       top *= 16;
915       bottom = player->bottomcolor;
916       if (bottom > 13 || bottom < 0)
917          bottom = 13;
918       bottom *= 16;
919 
920       for (i = 0; i < VID_GRADES; i++, dest += 256, source += 256) {
921          /* the artists made some backwards ranges.  sigh. */
922          if (top < 128)
923             memcpy(dest + TOP_RANGE, source + top, 16);
924          else
925             for (j = 0; j < 16; j++)
926                dest[TOP_RANGE + j] = source[top + 15 - j];
927 
928          if (bottom < 128)
929             memcpy(dest + BOTTOM_RANGE, source + bottom, 16);
930          else
931             for (j = 0; j < 16; j++)
932                dest[BOTTOM_RANGE + j] = source[bottom + 15 - j];
933       }
934    }
935 }
936 
937 /*
938 ==============
939 CL_ProcessUserinfo
940 ==============
941 */
942 static void
CL_ProcessUserInfo(int slot,player_info_t * player)943 CL_ProcessUserInfo(int slot, player_info_t * player)
944 {
945     char *name;
946 
947     name = Info_ValueForKey(player->userinfo, "name");
948     snprintf(player->name, sizeof(player->name), "%s", name);
949 
950     player->topcolor = atoi(Info_ValueForKey(player->userinfo, "topcolor"));
951     player->bottomcolor =
952 	atoi(Info_ValueForKey(player->userinfo, "bottomcolor"));
953     if (Info_ValueForKey(player->userinfo, "*spectator")[0])
954 	player->spectator = true;
955     else
956 	player->spectator = false;
957 
958     if (cls.state == ca_active)
959 	Skin_Find(player);
960 
961     Sbar_Changed();
962     CL_NewTranslation(slot);
963 }
964 
965 /*
966 ==============
967 CL_UpdateUserinfo
968 ==============
969 */
970 static void
CL_UpdateUserinfo(void)971 CL_UpdateUserinfo(void)
972 {
973     player_info_t *player;
974     char *info;
975     int slot;
976 
977     slot = MSG_ReadByte();
978     if (slot >= MAX_CLIENTS)
979 	Host_EndGame("%s: svc_updateuserinfo > MAX_SCOREBOARD", __func__);
980 
981     player = &cl.players[slot];
982     player->userid = MSG_ReadLong();
983 
984     info = MSG_ReadString();
985     snprintf(player->userinfo, sizeof(player->userinfo), "%s", info);
986     CL_ProcessUserInfo(slot, player);
987 }
988 
989 /*
990 ==============
991 CL_SetInfo
992 ==============
993 */
994 static void
CL_SetInfo(void)995 CL_SetInfo(void)
996 {
997     char key[MAX_MSGLEN];
998     char value[MAX_MSGLEN];
999     player_info_t *player;
1000     int slot;
1001 
1002     slot = MSG_ReadByte();
1003     if (slot >= MAX_CLIENTS)
1004 	Host_EndGame("%s: svc_setinfo > MAX_SCOREBOARD", __func__);
1005 
1006     player = &cl.players[slot];
1007     snprintf(key, sizeof(key), "%s", MSG_ReadString());
1008     snprintf(value, sizeof(value), "%s", MSG_ReadString());
1009 
1010     Con_DPrintf("SETINFO %s: %s=%s\n", player->name, key, value);
1011 
1012     Info_SetValueForKey(player->userinfo, key, value, MAX_INFO_STRING);
1013 
1014     CL_ProcessUserInfo(slot, player);
1015 }
1016 
1017 /*
1018 ==============
1019 CL_ServerInfo
1020 ==============
1021 */
1022 static void
CL_ServerInfo(void)1023 CL_ServerInfo(void)
1024 {
1025     char key[MAX_MSGLEN];
1026     char value[MAX_MSGLEN];
1027 
1028     snprintf(key, sizeof(key), "%s", MSG_ReadString());
1029     snprintf(value, sizeof(value), "%s", MSG_ReadString());
1030 
1031     Con_DPrintf("SERVERINFO: %s=%s\n", key, value);
1032 
1033     Info_SetValueForKey(cl.serverinfo, key, value, MAX_SERVERINFO_STRING);
1034 }
1035 
1036 /*
1037 =====================
1038 CL_SetStat
1039 =====================
1040 */
1041 static void
CL_SetStat(int stat,int value)1042 CL_SetStat(int stat, int value)
1043 {
1044     int j;
1045 
1046     if (stat < 0 || stat >= MAX_CL_STATS)
1047 	Sys_Error("%s: %i is invalid", __func__, stat);
1048 
1049     Sbar_Changed();
1050 
1051     if (stat == STAT_ITEMS) {	// set flash times
1052 	Sbar_Changed();
1053 	for (j = 0; j < 32; j++)
1054 	    if ((value & (1 << j)) && !(cl.stats[stat] & (1 << j)))
1055 		cl.item_gettime[j] = cl.time;
1056     }
1057 
1058     cl.stats[stat] = value;
1059 }
1060 
1061 /*
1062 ==============
1063 CL_MuzzleFlash
1064 ==============
1065 */
1066 static void
CL_MuzzleFlash(void)1067 CL_MuzzleFlash(void)
1068 {
1069    vec3_t fv, rv, uv;
1070    dlight_t *dl;
1071    int i;
1072    player_state_t *pl;
1073 
1074    i = MSG_ReadShort();
1075 
1076    if ((unsigned)(i - 1) >= MAX_CLIENTS)
1077       return;
1078 
1079    pl = &cl.frames[parsecountmod].playerstate[i - 1];
1080 
1081    dl = CL_AllocDlight(i);
1082    VectorCopy(pl->origin, dl->origin);
1083    AngleVectors(pl->viewangles, fv, rv, uv);
1084 
1085    VectorMA(dl->origin, 18, fv, dl->origin);
1086    dl->radius = 200 + (rand() & 31);
1087    dl->minlight = 32;
1088    dl->die = cl.time + 0.1;
1089    dl->color = dl_colors[DLIGHT_FLASH];
1090 }
1091 
1092 
1093 #define SHOWNET(x)							\
1094 	do {								\
1095 		if(cl_shownet.value == 2)				\
1096 			Con_Printf ("%3i:%s\n", msg_readcount - 1, x);	\
1097 	} while (0)
1098 
1099 /*
1100 =====================
1101 CL_ParseServerMessage
1102 =====================
1103 */
1104 int received_framecount;
1105 void
CL_ParseServerMessage(void)1106 CL_ParseServerMessage(void)
1107 {
1108     int cmd;
1109     char *s;
1110     int i, j;
1111 
1112     received_framecount = host_framecount;
1113     cl.last_servermessage = realtime;
1114     CL_ClearProjectiles();
1115 
1116 //
1117 // if recording demos, copy the message out
1118 //
1119     if (cl_shownet.value == 1)
1120 	Con_Printf("%i ", net_message.cursize);
1121     else if (cl_shownet.value == 2)
1122 	Con_Printf("------------------\n");
1123 
1124 
1125     CL_ParseClientdata();
1126 
1127 //
1128 // parse the message
1129 //
1130     while (1) {
1131 	if (msg_badread)
1132 	    Host_EndGame("%s: Bad server message", __func__);
1133 
1134 	cmd = MSG_ReadByte();
1135 
1136 	if (cmd == -1) {
1137 	    msg_readcount++;	// so the EOM showner has the right value
1138 	    SHOWNET("END OF MESSAGE");
1139 	    break;
1140 	}
1141 
1142 	SHOWNET(svc_strings[cmd]);
1143 
1144 	// other commands
1145 	switch (cmd) {
1146 	case svc_nop:
1147 //                      Con_Printf ("svc_nop\n");
1148 	    break;
1149 
1150 	case svc_disconnect:
1151 	    if (cls.state == ca_connected)
1152 		Host_EndGame("Server disconnected\n"
1153 			     "Server version may not be compatible");
1154 	    else
1155 		Host_EndGame("Server disconnected");
1156 	    break;
1157 
1158 	case svc_print:
1159 	    i = MSG_ReadByte();
1160 	    if (i == PRINT_CHAT) {
1161 		S_LocalSound("misc/talk.wav");
1162 		con_ormask = 128;
1163 	    }
1164 	    Con_Printf("%s", MSG_ReadString());
1165 	    con_ormask = 0;
1166 	    break;
1167 
1168 	case svc_centerprint:
1169 	    SCR_CenterPrint(MSG_ReadString());
1170 	    break;
1171 
1172 	case svc_stufftext:
1173 	    Cbuf_AddText("%s", MSG_ReadString());
1174 	    break;
1175 
1176 	case svc_damage:
1177 	    V_ParseDamage();
1178 	    break;
1179 
1180 	case svc_serverdata:
1181 	    Cbuf_Execute();	// make sure any stuffed commands are done
1182 	    CL_ParseServerData();
1183 	    vid.recalc_refdef = true;	// leave full screen intermission
1184 	    break;
1185 
1186 	case svc_setangle:
1187 	    for (i = 0; i < 3; i++)
1188 		cl.viewangles[i] = MSG_ReadAngle();
1189 //                      cl.viewangles[PITCH] = cl.viewangles[ROLL] = 0;
1190 	    break;
1191 
1192 	case svc_lightstyle:
1193 	    i = MSG_ReadByte();
1194 	    if (i >= MAX_LIGHTSTYLES)
1195 		Sys_Error("svc_lightstyle > MAX_LIGHTSTYLES");
1196 	    s = MSG_ReadString();
1197 	    snprintf(cl_lightstyle[i].map, MAX_STYLESTRING, "%s", s);
1198 	    cl_lightstyle[i].length = strlen(cl_lightstyle[i].map);
1199 	    break;
1200 
1201 	case svc_sound:
1202 	    CL_ParseStartSoundPacket();
1203 	    break;
1204 
1205 	case svc_stopsound:
1206 	    i = MSG_ReadShort();
1207 	    S_StopSound(i >> 3, i & 7);
1208 	    break;
1209 
1210 	case svc_updatefrags:
1211 	    Sbar_Changed();
1212 	    i = MSG_ReadByte();
1213 	    if (i >= MAX_CLIENTS)
1214 		Host_EndGame("%s: svc_updatefrags > MAX_SCOREBOARD", __func__);
1215 	    cl.players[i].frags = MSG_ReadShort();
1216 	    break;
1217 
1218 	case svc_updateping:
1219 	    i = MSG_ReadByte();
1220 	    if (i >= MAX_CLIENTS)
1221 		Host_EndGame("%s: svc_updateping > MAX_SCOREBOARD", __func__);
1222 	    cl.players[i].ping = MSG_ReadShort();
1223 	    break;
1224 
1225 	case svc_updatepl:
1226 	    i = MSG_ReadByte();
1227 	    if (i >= MAX_CLIENTS)
1228 		Host_EndGame("%s: svc_updatepl > MAX_SCOREBOARD", __func__);
1229 	    cl.players[i].pl = MSG_ReadByte();
1230 	    break;
1231 
1232 	case svc_updateentertime:
1233 	    // time is sent over as seconds ago
1234 	    i = MSG_ReadByte();
1235 	    if (i >= MAX_CLIENTS)
1236 		Host_EndGame("%s: svc_updateentertime > MAX_SCOREBOARD",
1237 			     __func__);
1238 	    cl.players[i].entertime = realtime - MSG_ReadFloat();
1239 	    break;
1240 
1241 	case svc_spawnbaseline:
1242 	    i = MSG_ReadShort();
1243 	    CL_ParseBaseline(&cl_baselines[i]);
1244 	    break;
1245 	case svc_spawnstatic:
1246 	    CL_ParseStatic();
1247 	    break;
1248 	case svc_temp_entity:
1249 	    CL_ParseTEnt();
1250 	    break;
1251 
1252 	case svc_killedmonster:
1253 	    cl.stats[STAT_MONSTERS]++;
1254 	    break;
1255 
1256 	case svc_foundsecret:
1257 	    cl.stats[STAT_SECRETS]++;
1258 	    break;
1259 
1260 	case svc_updatestat:
1261 	    i = MSG_ReadByte();
1262 	    j = MSG_ReadByte();
1263 	    CL_SetStat(i, j);
1264 	    break;
1265 	case svc_updatestatlong:
1266 	    i = MSG_ReadByte();
1267 	    j = MSG_ReadLong();
1268 	    CL_SetStat(i, j);
1269 	    break;
1270 
1271 	case svc_spawnstaticsound:
1272 	    CL_ParseStaticSound();
1273 	    break;
1274 
1275 	case svc_cdtrack:
1276 	    cl.cdtrack = MSG_ReadByte();
1277 	    CDAudio_Play((byte)cl.cdtrack, true);
1278 	    break;
1279 
1280 	case svc_intermission:
1281 	    cl.intermission = 1;
1282 	    cl.completed_time = realtime;
1283 	    vid.recalc_refdef = true;	// go to full screen
1284 	    for (i = 0; i < 3; i++)
1285 		cl.simorg[i] = MSG_ReadCoord();
1286 	    for (i = 0; i < 3; i++)
1287 		cl.simangles[i] = MSG_ReadAngle();
1288 	    VectorCopy(vec3_origin, cl.simvel);
1289 	    break;
1290 
1291 	case svc_finale:
1292 	    cl.intermission = 2;
1293 	    cl.completed_time = realtime;
1294 	    vid.recalc_refdef = true;	// go to full screen
1295 	    SCR_CenterPrint(MSG_ReadString());
1296 	    break;
1297 
1298 	case svc_sellscreen:
1299 	    Cmd_ExecuteString("help");
1300 	    break;
1301 
1302 	case svc_smallkick:
1303 	    cl.punchangle = -2;
1304 	    break;
1305 	case svc_bigkick:
1306 	    cl.punchangle = -4;
1307 	    break;
1308 
1309 	case svc_muzzleflash:
1310 	    CL_MuzzleFlash();
1311 	    break;
1312 
1313 	case svc_updateuserinfo:
1314 	    CL_UpdateUserinfo();
1315 	    break;
1316 
1317 	case svc_setinfo:
1318 	    CL_SetInfo();
1319 	    break;
1320 
1321 	case svc_serverinfo:
1322 	    CL_ServerInfo();
1323 	    break;
1324 
1325 	case svc_download:
1326 	    CL_ParseDownload();
1327 	    break;
1328 
1329 	case svc_playerinfo:
1330 	    CL_ParsePlayerinfo();
1331 	    break;
1332 
1333 	case svc_nails:
1334 	    CL_ParseProjectiles();
1335 	    break;
1336 
1337 	case svc_chokecount:	// some preceding packets were choked
1338 	    i = MSG_ReadByte();
1339 	    for (j = 0; j < i; j++)
1340 		cl.frames[(cls.netchan.incoming_acknowledged - 1 -
1341 			   j) & UPDATE_MASK].receivedtime = -2;
1342 	    break;
1343 
1344 	case svc_modellist:
1345 	    CL_ParseModellist();
1346 	    break;
1347 
1348 	case svc_soundlist:
1349 	    CL_ParseSoundlist();
1350 	    break;
1351 
1352 	case svc_packetentities:
1353 	    CL_ParsePacketEntities(false);
1354 	    break;
1355 
1356 	case svc_deltapacketentities:
1357 	    CL_ParsePacketEntities(true);
1358 	    break;
1359 
1360 	case svc_maxspeed:
1361 	    movevars.maxspeed = MSG_ReadFloat();
1362 	    break;
1363 
1364 	case svc_entgravity:
1365 	    movevars.entgravity = MSG_ReadFloat();
1366 	    break;
1367 
1368 	case svc_setpause:
1369 	    cl.paused = MSG_ReadByte();
1370 	    if (cl.paused)
1371 		CDAudio_Pause();
1372 	    else
1373 		CDAudio_Resume();
1374 	    break;
1375 
1376 	default:
1377 	    Host_EndGame("%s: Illegible server message", __func__);
1378 	}
1379     }
1380 
1381     CL_SetSolidEntities();
1382 }
1383