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