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