1 /*
2 Copyright (C) 1997-2001 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 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include "client.h"
27
28 char *svc_strings[256] =
29 {
30 "svc_bad",
31
32 "svc_muzzleflash",
33 "svc_muzzlflash2",
34 "svc_temp_entity",
35 "svc_layout",
36 "svc_inventory",
37
38 "svc_nop",
39 "svc_disconnect",
40 "svc_reconnect",
41 "svc_sound",
42 "svc_print",
43 "svc_stufftext",
44 "svc_serverdata",
45 "svc_configstring",
46 "svc_spawnbaseline",
47 "svc_centerprint",
48 "svc_download",
49 "svc_playerinfo",
50 "svc_packetentities",
51 "svc_deltapacketentities",
52 "svc_frame"
53 };
54
55 static size_t szr; // just for unused result warnings
56
57 /*
58 ==============
59 Q_strncpyz
60 ==============
61 */
Q_strncpyz(char * dest,const char * src,size_t size)62 void Q_strncpyz( char *dest, const char *src, size_t size )
63 {
64 #if defined HAVE_STRLCPY
65 strlcpy( dest, src, size );
66 #else
67 if( size )
68 {
69 while( --size && (*dest++ = *src++) );
70 *dest = '\0';
71 }
72 #endif
73 }
74
75 //=============================================================================
76
CL_DownloadFileName(char * dest,int destlen,char * fn)77 void CL_DownloadFileName(char *dest, int destlen, char *fn)
78 {
79 Com_sprintf (dest, destlen, "%s/%s", FS_Gamedir(), fn);
80 }
81
82 /*
83 ===============
84 CL_CheckOrDownloadFile
85
86 Returns true if the file exists, otherwise it attempts
87 to start a download from the server.
88 ===============
89 */
CL_CheckOrDownloadFile(char * filename)90 qboolean CL_CheckOrDownloadFile (char *filename)
91 {
92 FILE *fp;
93 char name[MAX_OSPATH];
94 char shortname[MAX_OSPATH];
95 char shortname2[MAX_OSPATH];
96 qboolean jpg = false;
97
98 if (strstr (filename, ".."))
99 {
100 Com_Printf ("Refusing to download a path with ..\n");
101 return true;
102 }
103
104 //if pcx, strip extension and change to .jpg, we do not use .pcx anymore
105 if(filename[strlen(filename)-1] == 'x')
106 {
107 //Filter out any potentially screwed up texture paths(meshes only reside in these folders)
108 if (strncmp(filename, "models", 6) && strncmp(filename, "vehicles", 8)
109 && strncmp(filename, "maps", 4))
110 return true;
111
112 COM_StripExtension ( filename, shortname );
113 sprintf(filename, "%s.jpg", shortname);
114 }
115
116 //if jpg, be sure to also try tga
117 if(filename[strlen(filename)-2] == 'p' && filename[strlen(filename)-1] == 'g')
118 jpg = true;
119
120 if (FS_LoadFile (filename, NULL) != -1)
121 {
122 // it exists, no need to download
123 return true;
124 }
125
126 if(jpg)
127 {
128 //didn't find .jpg skin, try for .tga skin
129 //check for presence of a local .tga(but leave filename as original extension)
130 //if we find a .tga, don't try to download anything
131 COM_StripExtension ( filename, shortname );
132 sprintf(shortname2, "%s.tga", shortname);
133 if (FS_LoadFile (shortname2, NULL) != -1)
134 {
135 // it exists, no need to download
136 return true;
137 }
138 }
139
140 strcpy (cls.downloadname, filename);
141
142 // download to a temp name, and only rename
143 // to the real name when done, so if interrupted
144 // a runt file wont be left
145 COM_StripExtension (cls.downloadname, cls.downloadtempname);
146 strcat (cls.downloadtempname, ".tmp");
147
148 // attempt an http download if available(never try to dl game model skins here)
149 if(cls.downloadurl[0] && CL_HttpDownload())
150 return false;
151
152 //ZOID
153 // check to see if we already have a tmp for this file, if so, try to resume
154 // open the file if not opened yet
155 CL_DownloadFileName(name, sizeof(name), cls.downloadtempname);
156
157 // FS_CreatePath (name);
158
159 fp = fopen (name, "r+b");
160 if (fp)
161 { // it exists
162 int len;
163
164 len = FS_filelength( fp );
165 cls.download = fp;
166
167 // give the server an offset to start the download
168 Com_Printf ("Resuming %s\n", cls.downloadname);
169 MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
170 MSG_WriteString (&cls.netchan.message,
171 va("download %s %i", cls.downloadname, len));
172 } else
173 {
174 Com_Printf ("Downloading %s\n", cls.downloadname);
175 MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
176 MSG_WriteString (&cls.netchan.message,
177 va("download %s", cls.downloadname));
178 }
179
180 cls.downloadnumber++;
181
182 send_packet_now = true;
183 return false;
184 }
185
186 /*
187 ===============
188 CL_Download_f
189
190 Request a download from the server
191 ===============
192 */
CL_Download_f(void)193 void CL_Download_f (void)
194 {
195 char filename[MAX_OSPATH];
196
197 if (Cmd_Argc() != 2)
198 {
199 Com_Printf("Usage: download <filename>\n");
200 return;
201 }
202
203 Com_sprintf(filename, sizeof(filename), "%s", Cmd_Argv(1));
204
205 if (strstr (filename, ".."))
206 {
207 Com_Printf ("Refusing to download a path with ..\n");
208 return;
209 }
210
211 if (FS_LoadFile (filename, NULL) != -1)
212 { // it exists, no need to download
213 Com_Printf("File already exists.\n");
214 return;
215 }
216
217 strcpy (cls.downloadname, filename);
218 Com_Printf ("Downloading %s\n", cls.downloadname);
219
220 // download to a temp name, and only rename
221 // to the real name when done, so if interrupted
222 // a runt file wont be left
223 COM_StripExtension (cls.downloadname, cls.downloadtempname);
224 strcat (cls.downloadtempname, ".tmp");
225
226 MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
227 MSG_WriteString (&cls.netchan.message,
228 va("download %s", cls.downloadname));
229
230 cls.downloadnumber++;
231 }
232
233 /*
234 ======================
235 CL_RegisterSounds
236 ======================
237 */
CL_RegisterSounds(void)238 void CL_RegisterSounds (void)
239 {
240 int i;
241
242 S_BeginRegistration ();
243 CL_RegisterTEntSounds ();
244 for (i=1 ; i<MAX_SOUNDS ; i++)
245 {
246 if (!cl.configstrings[CS_SOUNDS+i][0])
247 break;
248 cl.sound_precache[i] = S_RegisterSound (cl.configstrings[CS_SOUNDS+i]);
249 Sys_SendKeyEvents (); // pump message loop
250 }
251 S_EndRegistration ();
252 }
253
254
255 /*
256 =====================
257 CL_ParseDownload
258
259 A download message has been received from the server
260 =====================
261 */
CL_ParseDownload(void)262 void CL_ParseDownload (void)
263 {
264 int size, percent;
265 char name[MAX_OSPATH];
266 int r;
267
268 // read the data
269 size = MSG_ReadShort (&net_message);
270 percent = MSG_ReadByte (&net_message);
271 if (size < 0) //fix issues with bad data being dl'd
272 {
273 Com_Printf ("Server does not have file %s.\n", cls.downloadname);
274
275 //nuke the temp filename, we don't want that getting left around.
276 cls.downloadtempname[0] = 0;
277 cls.downloadname[0] = 0;
278
279 if (cls.download)
280 {
281 // if here, we tried to resume a file but the server said no
282 fclose (cls.download);
283 cls.download = NULL;
284 }
285 CL_RequestNextDownload ();
286 return;
287 }
288
289 // open the file if not opened yet
290 if (!cls.download)
291 {
292 CL_DownloadFileName(name, sizeof(name), cls.downloadtempname);
293
294 FS_CreatePath (name);
295
296 cls.download = fopen (name, "wb");
297 if (!cls.download)
298 {
299 net_message.readcount += size;
300 Com_Printf ("Failed to open %s\n", cls.downloadtempname);
301 CL_RequestNextDownload ();
302 return;
303 }
304 }
305
306 szr = fwrite (net_message.data + net_message.readcount, 1, size, cls.download);
307 net_message.readcount += size;
308
309 if (percent != 100)
310 {
311 // request next block
312 cls.downloadpercent = percent;
313
314 MSG_WriteByte (&cls.netchan.message, clc_stringcmd);
315 SZ_Print (&cls.netchan.message, "nextdl");
316 send_packet_now = true;
317 }
318 else
319 {
320 char oldn[MAX_OSPATH];
321 char newn[MAX_OSPATH];
322
323 // Com_Printf ("100%%\n");
324
325 fclose (cls.download);
326
327 // rename the temp file to it's final name
328 CL_DownloadFileName(oldn, sizeof(oldn), cls.downloadtempname);
329 CL_DownloadFileName(newn, sizeof(newn), cls.downloadname);
330 r = rename (oldn, newn);
331 if (r)
332 Com_Printf ("failed to rename.\n");
333
334 cls.download = NULL;
335 cls.downloadpercent = 0;
336
337 // get another file if needed
338
339 CL_RequestNextDownload ();
340 }
341 }
342
343
344 /*
345 =====================================================================
346
347 SERVER CONNECTING MESSAGES
348
349 =====================================================================
350 */
351
352 /*
353 ==================
354 CL_ParseServerData
355 ==================
356 */
CL_ParseServerData(void)357 void CL_ParseServerData (void)
358 {
359 extern cvar_t *fs_gamedirvar;
360 char *str;
361 int i;
362
363 Com_DPrintf ("Serverdata packet received.\n");
364 //
365 // wipe the client_state_t struct
366 //
367 CL_ClearState ();
368 cls.state = ca_connected;
369
370 // parse protocol version number
371 i = MSG_ReadLong (&net_message);
372 cls.serverProtocol = i;
373
374 // BIG HACK to let demos from release work with the 3.0x patch!!!
375 if (Com_ServerState() && PROTOCOL_VERSION == 34)
376 {
377 }
378 else if (i != PROTOCOL_VERSION)
379 Com_Error (ERR_DROP,"Server returned version %i, not %i", i, PROTOCOL_VERSION);
380
381 cl.servercount = MSG_ReadLong (&net_message);
382 cl.attractloop = MSG_ReadByte (&net_message);
383
384 // Hide console for demo playback. It interferes with timedemo results and
385 // is annoying when you just want to watch.
386 if (cl.attractloop)
387 M_ForceMenuOff ();
388
389 // game directory
390 str = MSG_ReadString (&net_message);
391 strncpy (cl.gamedir, str, sizeof(cl.gamedir)-1);
392
393 // set gamedir
394 if ((*str && (!fs_gamedirvar->string || !*fs_gamedirvar->string || strcmp(fs_gamedirvar->string, str))) || (!*str && (fs_gamedirvar->string || *fs_gamedirvar->string)))
395 Cvar_Set("game", str);
396
397 // parse player entity number
398 cl.playernum = MSG_ReadShort (&net_message);
399
400 // get the full level name
401 str = MSG_ReadString (&net_message);
402
403 // seperate the printfs so the server message can have a color
404 Com_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");
405 Com_Printf ("%c%s\n", 2, str);
406
407 // need to prep refresh at next oportunity
408 cl.refresh_prepped = false;
409 }
410
411 /*
412 ==================
413 CL_ParseBaseline
414 ==================
415 */
CL_ParseBaseline(void)416 void CL_ParseBaseline (void)
417 {
418 entity_state_t *es;
419 int bits;
420 int newnum;
421 entity_state_t nullstate;
422
423 memset (&nullstate, 0, sizeof(nullstate));
424
425 newnum = CL_ParseEntityBits ( (unsigned *)&bits );
426 es = &cl_entities[newnum].baseline;
427 CL_ParseDelta (&nullstate, es, newnum, bits);
428 }
429
430
431 /*
432 ================
433 CL_LoadClientinfo
434
435 ================
436 */
CL_LoadClientinfo(clientinfo_t * ci,char * s)437 void CL_LoadClientinfo (clientinfo_t *ci, char *s)
438 {
439 int i;
440 char *t;
441 char model_name[MAX_QPATH];
442 char skin_name[MAX_QPATH];
443 char model_filename[MAX_QPATH];
444 char skin_filename[MAX_QPATH];
445 char weapon_filename[MAX_QPATH];
446 FILE *file;
447
448 strncpy(ci->cinfo, s, sizeof(ci->cinfo));
449 ci->cinfo[sizeof(ci->cinfo)-1] = 0;
450
451 // isolate the player's name
452 strncpy(ci->name, s, sizeof(ci->name));
453 ci->name[sizeof(ci->name)-1] = 0;
454 t = strstr (s, "\\");
455 if (t)
456 {
457 ci->name[t-s] = 0;
458 s = t+1;
459 }
460
461 // isolate the model name
462 strcpy (model_name, s);
463 t = strstr(model_name, "/");
464 if (!t)
465 t = strstr(model_name, "\\");
466 if (!t)
467 t = model_name;
468 *t = 0;
469
470 ci->helmet = NULL; //we only worry about this in these cases of missing textures or models
471 ci->lod1 = NULL;
472 ci->lod2 = NULL;
473
474 if (cl_noskins->value || *s == 0)
475 {
476 Com_sprintf (model_filename, sizeof(model_filename), "players/martianenforcer/tris.md2");
477 Com_sprintf (weapon_filename, sizeof(weapon_filename), "players/martianenforcer/weapon.md2");
478 Com_sprintf (skin_filename, sizeof(skin_filename), "players/martianenforcer/default.pcx");
479 Com_sprintf (ci->iconname, sizeof(ci->iconname), "/players/martianenforcer/default_i.pcx");
480 ci->model = R_RegisterModel (model_filename);
481 ci->helmet = R_RegisterModel("players/martianenforcer/helmet.md2");
482 // weapon file
483 for (i = 0; i < num_cl_weaponmodels; i++)
484 {
485 Com_sprintf (weapon_filename, sizeof(weapon_filename), "players/martianenforcer/%s", cl_weaponmodels[i]);
486 ci->weaponmodel[i] = R_RegisterModel(weapon_filename);
487 if (!cl_vwep->value)
488 break; // only one when vwep is off
489 }
490 ci->skin = R_RegisterSkin (skin_filename);
491 ci->icon = R_RegisterPic (ci->iconname);
492 }
493 else
494 {
495 // isolate the skin name
496 strcpy (skin_name, s + strlen(model_name) + 1);
497
498 // model file
499 Com_sprintf (model_filename, sizeof(model_filename), "players/%s/tris.md2", model_name);
500 ci->model = R_RegisterModel (model_filename);
501 if (!ci->model)
502 {
503 Com_sprintf (model_filename, sizeof(model_filename), "players/martianenforcer/tris.md2");
504 ci->model = R_RegisterModel (model_filename);
505 ci->helmet = R_RegisterModel("players/martianenforcer/helmet.md2");
506 strcpy(model_name, "martianenforcer");
507 }
508
509 // skin file
510 Com_sprintf (skin_filename, sizeof(skin_filename), "players/%s/%s.pcx", model_name, skin_name);
511 ci->skin = R_RegisterSkin (skin_filename);
512
513 // if don't have a skin, it means that the model didn't have
514 // it, so default
515 if (!ci->skin)
516 {
517 strcpy(skin_name, "default");
518 Com_sprintf (skin_filename, sizeof(skin_filename), "players/%s/default.pcx", model_name);
519 ci->skin = R_RegisterSkin (skin_filename);
520 }
521
522 // weapon file
523 for (i = 0; i < num_cl_weaponmodels; i++)
524 {
525 Com_sprintf (weapon_filename, sizeof(weapon_filename), "players/%s/%s", model_name, cl_weaponmodels[i]);
526 ci->weaponmodel[i] = R_RegisterModel(weapon_filename);
527 if (!ci->weaponmodel[i] == 0) {
528 Com_sprintf (weapon_filename, sizeof(weapon_filename), "players/martianenforcer/%s", cl_weaponmodels[i]);
529 ci->weaponmodel[i] = R_RegisterModel(weapon_filename);
530 }
531 if (!cl_vwep->value)
532 break; // only one when vwep is off
533 }
534
535 // icon file
536 Com_sprintf (ci->iconname, sizeof(ci->iconname), "/players/%s/%s_i.pcx", model_name, skin_name);
537 ci->icon = R_RegisterPic (ci->iconname);
538 }
539
540 //check for level of detail models
541 if (cl_noskins->value || *s == 0)
542 strcpy(model_name, "martianenforcer");
543
544 Com_sprintf(model_filename, sizeof(model_filename), "players/%s/lod1.md2", model_name);
545 i = 0;
546 do
547 model_filename[i] = tolower(model_filename[i]);
548 while (model_filename[i++]);
549
550 FS_FOpenFile (model_filename, &file);
551 if(file)
552 {
553 //exists
554 fclose(file);
555 ci->lod1 = R_RegisterModel(model_filename);
556 }
557 else
558 ci->lod1 = NULL;
559
560 Com_sprintf(model_filename, sizeof(model_filename), "players/%s/lod2.md2", model_name);
561 i = 0;
562 do
563 model_filename[i] = tolower(model_filename[i]);
564 while (model_filename[i++]);
565
566 FS_FOpenFile (model_filename, &file);
567 if(file)
568 {
569 //exists
570 fclose(file);
571 ci->lod2 = R_RegisterModel(model_filename);
572 }
573 else
574 ci->lod2 = NULL;
575
576 // must have loaded all data types to be valid
577 if (!ci->skin || !ci->icon || !ci->model || !ci->weaponmodel[0])
578 {
579 ci->skin = NULL;
580 ci->icon = NULL;
581 ci->model = NULL;
582 ci->weaponmodel[0] = NULL;
583 return;
584 }
585
586 }
587
588 /*
589 ================
590 CL_ParseClientinfo
591
592 Load the skin, icon, and model for a client
593 ================
594 */
CL_ParseClientinfo(int player)595 void CL_ParseClientinfo (int player)
596 {
597 char *s;
598 clientinfo_t *ci;
599
600 s = cl.configstrings[player+CS_PLAYERSKINS];
601
602 ci = &cl.clientinfo[player];
603
604 CL_LoadClientinfo (ci, s);
605 }
606
CL_ParseTaunt(char * s)607 void CL_ParseTaunt( char *s)
608 {
609 int l, j;
610 char tauntsound[MAX_OSPATH];
611
612 //parse
613 strcpy( scr_playericon, COM_Parse( &s ) );
614 l = strlen(scr_playericon);
615
616 for (j=0 ; j<l ; j++)
617 scr_playericon[j] = tolower(scr_playericon[j]);
618
619 Com_sprintf(scr_playericon, sizeof(scr_playericon), "%s_i", scr_playericon);
620
621 strcpy( tauntsound, COM_Parse( &s ) );
622
623 Q_strncpyz2( scr_playername, COM_Parse( &s ), sizeof(scr_playername) );
624
625 if(cl_playtaunts->value)
626 {
627 S_StartSound (NULL, 0, 0, S_RegisterSound (tauntsound), 1, ATTN_NONE, 0);
628 scr_playericonalpha = 2.0;
629 }
630
631 }
632
633 /*
634 ================
635 CL_ParseConfigString
636 ================
637 */
CL_ParseConfigString(void)638 void CL_ParseConfigString (void)
639 {
640 int i;
641 char *s;
642 char olds[MAX_QPATH];
643 size_t length;
644
645 i = MSG_ReadShort (&net_message);
646 if (i < 0 || i >= MAX_CONFIGSTRINGS)
647 Com_Error (ERR_DROP, "configstring > MAX_CONFIGSTRINGS");
648 s = MSG_ReadString(&net_message);
649
650 strncpy (olds, cl.configstrings[i], sizeof(olds));
651 olds[sizeof(olds) - 1] = 0;
652
653 //r1: overflow may be desired by some mods in stats programs for example. who knows.
654 length = strlen(s);
655
656 if (length >= (sizeof(cl.configstrings[0]) * (MAX_CONFIGSTRINGS-i)) - 1)
657 Com_Error (ERR_DROP, "CL_ParseConfigString: configstring %d exceeds available space", i);
658
659 //r1: don't allow basic things to overflow
660 if (i != CS_NAME && i < CS_GENERAL)
661 {
662 if (i >= CS_STATUSBAR && i < CS_AIRACCEL)
663 {
664 strncpy (cl.configstrings[i], s, (sizeof(cl.configstrings[i]) * (CS_AIRACCEL - i))-1);
665 }
666 else
667 {
668 // Alien Arena client/server protocol depends on MAX_QPATH being 64
669 if (length >= MAX_QPATH)
670 Com_Printf ("WARNING: Configstring %d of length %d exceeds MAX_QPATH.\n", i, length);
671 Q_strncpyz (cl.configstrings[i], s, sizeof(cl.configstrings[i])-1);
672 }
673 }
674 else
675 {
676 strcpy (cl.configstrings[i], s);
677 }
678
679 // do something apropriate
680
681 if (i >= CS_LIGHTS && i < CS_LIGHTS+MAX_LIGHTSTYLES)
682 CL_SetLightstyle (i - CS_LIGHTS);
683 else if (i >= CS_MODELS && i < CS_MODELS+MAX_MODELS)
684 {
685 if (cl.refresh_prepped)
686 {
687 cl.model_draw[i-CS_MODELS] = R_RegisterModel (cl.configstrings[i]);
688 if (cl.configstrings[i][0] == '*')
689 cl.model_clip[i-CS_MODELS] = CM_InlineModel (cl.configstrings[i]);
690 else
691 cl.model_clip[i-CS_MODELS] = NULL;
692 }
693 }
694 else if (i >= CS_SOUNDS && i < CS_SOUNDS+MAX_MODELS)
695 {
696 if (cl.refresh_prepped)
697 cl.sound_precache[i-CS_SOUNDS] = S_RegisterSound (cl.configstrings[i]);
698 }
699 else if (i >= CS_IMAGES && i < CS_IMAGES+MAX_MODELS)
700 {
701 if (cl.refresh_prepped)
702 cl.image_precache[i-CS_IMAGES] = R_RegisterPic (cl.configstrings[i]);
703 }
704 else if (i >= CS_PLAYERSKINS && i < CS_PLAYERSKINS+MAX_CLIENTS)
705 {
706 if (cl.refresh_prepped && strcmp(olds, s))
707 CL_ParseClientinfo (i-CS_PLAYERSKINS);
708 }
709 else if ( i == CS_GENERAL)
710 CL_ParseTaunt(s);
711 }
712
713
714 /*
715 =====================================================================
716
717 ACTION MESSAGES
718
719 =====================================================================
720 */
721
722 /*
723 ==================
724 CL_ParseStartSoundPacket
725 ==================
726 */
CL_ParseStartSoundPacket(void)727 void CL_ParseStartSoundPacket(void)
728 {
729 vec3_t pos_v;
730 float *pos;
731 int channel, ent;
732 int sound_num;
733 float volume;
734 float attenuation;
735 int flags;
736 float ofs;
737
738 flags = MSG_ReadByte (&net_message);
739 sound_num = MSG_ReadByte (&net_message);
740
741 if (flags & SND_VOLUME)
742 volume = MSG_ReadByte (&net_message) / 255.0;
743 else
744 volume = DEFAULT_SOUND_PACKET_VOLUME;
745
746 if (flags & SND_ATTENUATION)
747 attenuation = MSG_ReadByte (&net_message) / 64.0;
748 else
749 attenuation = DEFAULT_SOUND_PACKET_ATTENUATION;
750
751 if (flags & SND_OFFSET)
752 ofs = MSG_ReadByte (&net_message) / 1000.0;
753 else
754 ofs = 0;
755
756 if (flags & SND_ENT)
757 { // entity reletive
758 channel = MSG_ReadShort(&net_message);
759 ent = channel>>3;
760 if (ent > MAX_EDICTS)
761 Com_Error (ERR_DROP,"CL_ParseStartSoundPacket: ent = %i", ent);
762
763 channel &= 7;
764 }
765 else
766 {
767 ent = 0;
768 channel = 0;
769 }
770
771 if (flags & SND_POS)
772 { // positioned in space
773 MSG_ReadPos (&net_message, pos_v);
774
775 pos = pos_v;
776 }
777 else // use entity number
778 pos = NULL;
779
780 if (!cl.sound_precache[sound_num])
781 return;
782
783 S_StartSound (pos, ent, channel, cl.sound_precache[sound_num], volume, attenuation, ofs);
784 }
785
786
SHOWNET(char * s)787 void SHOWNET(char *s)
788 {
789 if (cl_shownet->value>=2)
790 Com_Printf ("%3i:%s\n", net_message.readcount-1, s);
791 }
792
793 /*
794 =====================
795 CL_ParseServerMessage
796 =====================
797 */
CL_ParseServerMessage(void)798 void CL_ParseServerMessage (void)
799 {
800 int cmd;
801 char *s;
802 int i;
803
804 //
805 // if recording demos, copy the message out
806 //
807 if (cl_shownet->value == 1)
808 Com_Printf ("%i ",net_message.cursize);
809 else if (cl_shownet->value >= 2)
810 Com_Printf ("------------------\n");
811
812 //
813 // parse the message
814 //
815 while (1)
816 {
817 if (net_message.readcount > net_message.cursize)
818 {
819 Com_Error (ERR_DROP,"CL_ParseServerMessage: Bad server message");
820 break;
821 }
822
823 cmd = MSG_ReadByte (&net_message);
824
825 if (cmd == -1)
826 {
827 SHOWNET("END OF MESSAGE");
828 break;
829 }
830
831 if (cl_shownet->value>=2)
832 {
833 if (!svc_strings[cmd])
834 Com_Printf ("%3i:BAD CMD %i\n", net_message.readcount-1,cmd);
835 else
836 SHOWNET(svc_strings[cmd]);
837 }
838
839 // other commands
840 switch (cmd)
841 {
842 default:
843 Com_Error (ERR_DROP,"CL_ParseServerMessage: Illegible server message\n");
844 break;
845
846 case svc_nop:
847 // Com_Printf ("svc_nop\n");
848 break;
849
850 case svc_disconnect:
851 Com_Error (ERR_DISCONNECT,"Server disconnected\n");
852 break;
853
854 case svc_reconnect:
855 Com_Printf ("Server disconnected, reconnecting\n");
856 // stop download
857 if(cls.download)
858 {
859 if(cls.downloadhttp) // clean up http downloads
860 CL_HttpDownloadCleanup();
861 else // or just stop legacy ones
862 fclose(cls.download);
863 cls.download = NULL;
864 }
865 cls.state = ca_connecting;
866 cls.connect_time = -99999; // CL_CheckForResend() will fire immediately
867 break;
868
869 case svc_print:
870 i = MSG_ReadByte (&net_message);
871 if (i == PRINT_CHAT)
872 {
873 S_StartLocalSound ("misc/talk.wav");
874 }
875 Com_Printf ("%s", MSG_ReadString (&net_message));
876 break;
877
878 case svc_centerprint:
879 SCR_CenterPrint (MSG_ReadString (&net_message));
880 break;
881
882 case svc_stufftext:
883 s = MSG_ReadString (&net_message);
884 Com_DPrintf ("stufftext: %s\n", s);
885 Cbuf_AddText (s);
886 break;
887
888 case svc_serverdata:
889 Cbuf_Execute (); // make sure any stuffed commands are done
890 CL_ParseServerData ();
891 break;
892
893 case svc_configstring:
894 CL_ParseConfigString ();
895 break;
896
897 case svc_sound:
898 CL_ParseStartSoundPacket();
899 break;
900
901 case svc_spawnbaseline:
902 CL_ParseBaseline ();
903 break;
904
905 case svc_temp_entity:
906 CL_ParseTEnt ();
907 break;
908
909 case svc_muzzleflash:
910 CL_ParseMuzzleFlash ();
911 break;
912
913 case svc_download:
914 CL_ParseDownload ();
915 break;
916
917 case svc_frame:
918 CL_ParseFrame ();
919 break;
920
921 case svc_inventory:
922 CL_ParseInventory ();
923 break;
924
925 case svc_layout:
926 s = MSG_ReadString (&net_message);
927 strncpy (cl.layout, s, sizeof(cl.layout)-1);
928 break;
929
930 case svc_playerinfo:
931 case svc_packetentities:
932 case svc_deltapacketentities:
933 Com_Error (ERR_DROP, "Out of place frame data");
934 break;
935 }
936 }
937
938 CL_AddNetgraph ();
939
940 //
941 // we don't know if it is ok to save a demo message until
942 // after we have parsed the frame
943 //
944 if (cls.demorecording && !cls.demowaiting)
945 CL_WriteDemoMessage ();
946
947 }
948
949
950