]> de.git.xonotic.org Git - xonotic/darkplaces.git/blob - cl_parse.c
made the Sorted Edge Rasterizer (hidden surface removal) optional as the r_ser cvar...
[xonotic/darkplaces.git] / cl_parse.c
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[128] =
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_serverinfo",               // [long] version
40                                                 // [string] signon string
41                                                 // [string]..[0]model cache [string]...[0]sounds cache
42                                                 // [string]..[0]item cache
43         "svc_lightstyle",               // [byte] [string]
44         "svc_updatename",               // [byte] [string]
45         "svc_updatefrags",      // [byte] [short]
46         "svc_clientdata",               // <shortbits + data>
47         "svc_stopsound",                // <see code>
48         "svc_updatecolors",     // [byte] [byte]
49         "svc_particle",         // [vec3] <variable>
50         "svc_damage",                   // [byte] impact [byte] blood [vec3] from
51         
52         "svc_spawnstatic",
53         "OBSOLETE svc_spawnbinary",
54         "svc_spawnbaseline",
55         
56         "svc_temp_entity",              // <variable>
57         "svc_setpause",
58         "svc_signonnum",
59         "svc_centerprint",
60         "svc_killedmonster",
61         "svc_foundsecret",
62         "svc_spawnstaticsound",
63         "svc_intermission",
64         "svc_finale",                   // [string] music [string] text
65         "svc_cdtrack",                  // [byte] track [byte] looptrack
66         "svc_sellscreen",
67         "svc_cutscene",
68         "svc_showlmp",  // [string] iconlabel [string] lmpfile [short] x [short] y
69         "svc_hidelmp",  // [string] iconlabel
70         "svc_skybox", // [string] skyname
71         "", // 38
72         "", // 39
73         "", // 40
74         "", // 41
75         "", // 42
76         "", // 43
77         "", // 44
78         "", // 45
79         "", // 46
80         "", // 47
81         "", // 48
82         "", // 49
83         "", // 50
84         "svc_fog", // 51
85         "svc_effect", // [vector] org [byte] modelindex [byte] startframe [byte] framecount [byte] framerate
86         "svc_effect2", // [vector] org [short] modelindex [short] startframe [byte] framecount [byte] framerate
87 };
88
89 //=============================================================================
90
91 cvar_t demo_nehahra = {0, "demo_nehahra", "0"};
92
93 void CL_Parse_Init(void)
94 {
95         // LordHavoc: added demo_nehahra cvar
96         Cvar_RegisterVariable (&demo_nehahra);
97         if (nehahra)
98                 Cvar_SetValue("demo_nehahra", 1);
99 }
100
101 qboolean Nehahrademcompatibility; // LordHavoc: to allow playback of the early Nehahra movie segments
102 qboolean dpprotocol; // LordHavoc: whether or not the current network stream is the enhanced DarkPlaces protocol
103
104 /*
105 ===============
106 CL_EntityNum
107
108 This error checks and tracks the total number of entities
109 ===============
110 */
111 entity_t        *CL_EntityNum (int num)
112 {
113         /*
114         if (num >= cl.num_entities)
115         {
116                 if (num >= MAX_EDICTS)
117                         Host_Error ("CL_EntityNum: %i is an invalid number",num);
118                 cl.num_entities = num;
119 //              while (cl.num_entities <= num)
120 //              {
121 //                      cl_entities[cl.num_entities].colormap = -1; // no special coloring
122 //                      cl.num_entities++;
123 //              }
124         }
125         */
126         if (num >= MAX_EDICTS)
127                 Host_Error ("CL_EntityNum: %i is an invalid number",num);
128                 
129         return &cl_entities[num];
130 }
131
132
133 /*
134 ==================
135 CL_ParseStartSoundPacket
136 ==================
137 */
138 void CL_ParseStartSoundPacket(int largesoundindex)
139 {
140     vec3_t  pos;
141     int         channel, ent;
142     int         sound_num;
143     int         volume;
144     int         field_mask;
145     float       attenuation;
146         int             i;
147                    
148     field_mask = MSG_ReadByte(); 
149
150     if (field_mask & SND_VOLUME)
151                 volume = MSG_ReadByte ();
152         else
153                 volume = DEFAULT_SOUND_PACKET_VOLUME;
154         
155     if (field_mask & SND_ATTENUATION)
156                 attenuation = MSG_ReadByte () / 64.0;
157         else
158                 attenuation = DEFAULT_SOUND_PACKET_ATTENUATION;
159         
160         channel = MSG_ReadShort ();
161         if (largesoundindex)
162                 sound_num = (unsigned short) MSG_ReadShort ();
163         else
164                 sound_num = MSG_ReadByte ();
165
166         if (sound_num >= MAX_SOUNDS)
167                 Host_Error("CL_ParseStartSoundPacket: sound_num (%i) >= MAX_SOUNDS (%i)\n", sound_num, MAX_SOUNDS);
168
169         ent = channel >> 3;
170         channel &= 7;
171
172         if (ent > MAX_EDICTS)
173                 Host_Error ("CL_ParseStartSoundPacket: ent = %i", ent);
174         
175         for (i=0 ; i<3 ; i++)
176                 pos[i] = MSG_ReadCoord ();
177  
178     S_StartSound (ent, channel, cl.sound_precache[sound_num], pos, volume/255.0, attenuation);
179 }       
180
181 /*
182 ==================
183 CL_KeepaliveMessage
184
185 When the client is taking a long time to load stuff, send keepalive messages
186 so the server doesn't disconnect.
187 ==================
188 */
189 void CL_KeepaliveMessage (void)
190 {
191         float   time;
192         static float lastmsg;
193         int             ret;
194         sizebuf_t       old;
195         byte            olddata[8192];
196         
197         if (sv.active)
198                 return;         // no need if server is local
199         if (cls.demoplayback)
200                 return;
201
202 // read messages from server, should just be nops
203         old = net_message;
204         memcpy (olddata, net_message.data, net_message.cursize);
205         
206         do
207         {
208                 ret = CL_GetMessage ();
209                 switch (ret)
210                 {
211                 default:
212                         Host_Error ("CL_KeepaliveMessage: CL_GetMessage failed");               
213                 case 0:
214                         break;  // nothing waiting
215                 case 1:
216                         Host_Error ("CL_KeepaliveMessage: received a message");
217                         break;
218                 case 2:
219                         if (MSG_ReadByte() != svc_nop)
220                                 Host_Error ("CL_KeepaliveMessage: datagram wasn't a nop");
221                         break;
222                 }
223         } while (ret);
224
225         net_message = old;
226         memcpy (net_message.data, olddata, net_message.cursize);
227
228 // check time
229         time = Sys_DoubleTime ();
230         if (time - lastmsg < 5)
231                 return;
232         lastmsg = time;
233
234 // write out a nop
235         Con_Printf ("--> client to server keepalive\n");
236
237         MSG_WriteByte (&cls.message, clc_nop);
238         NET_SendMessage (cls.netcon, &cls.message);
239         SZ_Clear (&cls.message);
240 }
241
242 void CL_ParseEntityLump(char *entdata)
243 {
244         char *data;
245         char key[128], value[4096];
246         char wadname[128];
247         int i, j, k;
248         FOG_clear(); // LordHavoc: no fog until set
249         R_SetSkyBox(""); // LordHavoc: no environment mapped sky until set
250         r_farclip.value = 6144; // LordHavoc: default farclip distance
251         data = entdata;
252         if (!data)
253                 return;
254         data = COM_Parse(data);
255         if (!data)
256                 return; // valid exit
257         if (com_token[0] != '{')
258                 return; // error
259         while (1)
260         {
261                 data = COM_Parse(data);
262                 if (!data)
263                         return; // error
264                 if (com_token[0] == '}')
265                         return; // since we're just parsing the first ent (worldspawn), exit
266                 strcpy(key, com_token);
267                 while (key[strlen(key)-1] == ' ') // remove trailing spaces
268                         key[strlen(key)-1] = 0;
269                 data = COM_Parse(data);
270                 if (!data)
271                         return; // error
272                 strcpy(value, com_token);
273                 if (!strcmp("sky", key))
274                         R_SetSkyBox(value);
275                 else if (!strcmp("skyname", key)) // non-standard, introduced by QuakeForge... sigh.
276                         R_SetSkyBox(value);
277                 else if (!strcmp("qlsky", key)) // non-standard, introduced by QuakeLives (EEK)
278                         R_SetSkyBox(value);
279                 else if (!strcmp("farclip", key))
280                 {
281                         r_farclip.value = atof(value);
282                         if (r_farclip.value < 64)
283                                 r_farclip.value = 64;
284                 }
285                 else if (!strcmp("fog", key))
286                 {
287                         scanf(value, "%f %f %f %f", &fog_density, &fog_red, &fog_green, &fog_blue);
288                         j = 0;
289                 }
290                 else if (!strcmp("fog_density", key))
291                         fog_density = atof(value);
292                 else if (!strcmp("fog_red", key))
293                         fog_red = atof(value);
294                 else if (!strcmp("fog_green", key))
295                         fog_green = atof(value);
296                 else if (!strcmp("fog_blue", key))
297                         fog_blue = atof(value);
298                 else if (!strcmp("wad", key)) // for HalfLife maps
299                 {
300                         if (hlbsp)
301                         {
302                                 j = 0;
303                                 for (i = 0;i < 4096;i++)
304                                         if (value[i] != ';' && value[i] != '\\' && value[i] != '/' && value[i] != ':')
305                                                 break;
306                                 if (value[i])
307                                 {
308                                         for (;i < 4096;i++)
309                                         {
310                                                 // ignore path - the \\ check is for HalfLife... stupid windoze 'programmers'...
311                                                 if (value[i] == '\\' || value[i] == '/' || value[i] == ':')
312                                                         j = i+1;
313                                                 else if (value[i] == ';' || value[i] == 0)
314                                                 {
315                                                         k = value[i];
316                                                         value[i] = 0;
317                                                         strcpy(wadname, "textures/");
318                                                         strcat(wadname, &value[j]);
319                                                         W_LoadTextureWadFile (wadname, false);
320                                                         j = i+1;
321                                                         if (!k)
322                                                                 break;
323                                                 }
324                                         }
325                                 }
326                         }
327                 }
328         }
329 }
330
331 /*
332 ==================
333 CL_ParseServerInfo
334 ==================
335 */
336 void CL_ParseServerInfo (void)
337 {
338         char    *str;
339         int             i;
340         int             nummodels, numsounds;
341         char    model_precache[MAX_MODELS][MAX_QPATH];
342         char    sound_precache[MAX_SOUNDS][MAX_QPATH];
343         
344         Con_DPrintf ("Serverinfo packet received.\n");
345 //
346 // wipe the client_state_t struct
347 //
348         CL_ClearState ();
349
350 // parse protocol version number
351         i = MSG_ReadLong ();
352         if (i != PROTOCOL_VERSION && i != DPPROTOCOL_VERSION && i != 250)
353         {
354                 Con_Printf ("Server returned version %i, not %i or %i", i, DPPROTOCOL_VERSION, PROTOCOL_VERSION);
355                 return;
356         }
357         Nehahrademcompatibility = false;
358         if (i == 250)
359                 Nehahrademcompatibility = true;
360         if (cls.demoplayback && demo_nehahra.value)
361                 Nehahrademcompatibility = true;
362         dpprotocol = i == DPPROTOCOL_VERSION;
363
364 // parse maxclients
365         cl.maxclients = MSG_ReadByte ();
366         if (cl.maxclients < 1 || cl.maxclients > MAX_SCOREBOARD)
367         {
368                 Con_Printf("Bad maxclients (%u) from server\n", cl.maxclients);
369                 return;
370         }
371         cl.scores = Hunk_AllocName (cl.maxclients*sizeof(*cl.scores), "scores");
372
373 // parse gametype
374         cl.gametype = MSG_ReadByte ();
375
376 // parse signon message
377         str = MSG_ReadString ();
378         strncpy (cl.levelname, str, sizeof(cl.levelname)-1);
379
380 // seperate the printfs so the server message can have a color
381         if (!Nehahrademcompatibility) // no messages when playing the Nehahra movie
382         {
383                 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");
384                 Con_Printf ("%c%s\n", 2, str);
385         }
386
387 //
388 // first we go through and touch all of the precache data that still
389 // happens to be in the cache, so precaching something else doesn't
390 // needlessly purge it
391 //
392
393         Hunk_Check ();
394
395 // precache models
396         memset (cl.model_precache, 0, sizeof(cl.model_precache));
397         for (nummodels=1 ; ; nummodels++)
398         {
399                 str = MSG_ReadString ();
400                 if (!str[0])
401                         break;
402                 if (nummodels==MAX_MODELS)
403                 {
404                         Con_Printf ("Server sent too many model precaches\n");
405                         return;
406                 }
407                 if (strlen(str) >= MAX_QPATH)
408                         Host_Error ("Server sent a precache name of %i characters (max %i)", strlen(str), MAX_QPATH - 1);
409                 strcpy (model_precache[nummodels], str);
410                 Mod_TouchModel (str);
411
412 //              Hunk_Check ();
413
414         }
415
416 // precache sounds
417         memset (cl.sound_precache, 0, sizeof(cl.sound_precache));
418         for (numsounds=1 ; ; numsounds++)
419         {
420                 str = MSG_ReadString ();
421                 if (!str[0])
422                         break;
423                 if (numsounds==MAX_SOUNDS)
424                 {
425                         Con_Printf ("Server sent too many sound precaches\n");
426                         return;
427                 }
428                 if (strlen(str) >= MAX_QPATH)
429                         Host_Error ("Server sent a precache name of %i characters (max %i)", strlen(str), MAX_QPATH - 1);
430                 strcpy (sound_precache[numsounds], str);
431                 S_TouchSound (str);
432         }
433
434 //
435 // now we try to load everything else until a cache allocation fails
436 //
437
438         Hunk_Check ();
439
440         for (i=1 ; i<nummodels ; i++)
441         {
442                 isworldmodel = i == 1; // LordHavoc: first model is the world model
443                 cl.model_precache[i] = Mod_ForName (model_precache[i], false);
444
445 //              Hunk_Check ();
446
447                 if (cl.model_precache[i] == NULL)
448                 {
449                         Con_Printf("Model %s not found\n", model_precache[i]);
450                         return;
451                 }
452                 CL_KeepaliveMessage ();
453         }
454
455         Hunk_Check ();
456
457         S_BeginPrecaching ();
458         for (i=1 ; i<numsounds ; i++)
459         {
460                 cl.sound_precache[i] = S_PrecacheSound (sound_precache[i]);
461                 CL_KeepaliveMessage ();
462         }
463         S_EndPrecaching ();
464
465
466 // local state
467         cl_entities[0].render.model = cl.worldmodel = cl.model_precache[1];
468
469 //      Hunk_Check ();
470
471         R_NewMap ();
472
473         Hunk_Check ();          // make sure nothing is hurt
474
475         noclip_anglehack = false;               // noclip is turned off at start
476 }
477
478 void CL_ValidateState(entity_state_t *s)
479 {
480         model_t *model;
481
482         if (!s->active)
483                 return;
484
485         if (s->modelindex >= MAX_MODELS)
486                 Host_Error("CL_ValidateState: modelindex (%i) >= MAX_MODELS (%i)\n", s->modelindex, MAX_MODELS);
487
488         // colormap is client index + 1
489         if (s->colormap > cl.maxclients)
490                 Host_Error ("CL_ValidateState: colormap (%i) > cl.maxclients (%i)", s->colormap, cl.maxclients);
491
492         model = cl.model_precache[s->modelindex];
493         if (model && s->frame >= model->numframes)
494         {
495                 Con_DPrintf("CL_ValidateState: no such frame %i in \"%s\"\n", s->frame, model->name);
496                 s->frame = 0;
497         }
498 }
499
500 /*
501 ==================
502 CL_ParseUpdate
503
504 Parse an entity update message from the server
505 If an entities model or origin changes from frame to frame, it must be
506 relinked.  Other attributes can change without relinking.
507 ==================
508 */
509 byte entkill[MAX_EDICTS];
510 int bitprofile[32], bitprofilecount = 0;
511 void CL_ParseUpdate (int bits)
512 {
513         int i, num, deltadie;
514         entity_t *ent;
515
516         if (cls.signon == SIGNONS - 1)
517         {       // first update is the final signon stage
518                 cls.signon = SIGNONS;
519                 CL_SignonReply ();
520         }
521
522         if (bits & U_MOREBITS)
523                 bits |= (MSG_ReadByte()<<8);
524         if ((bits & U_EXTEND1) && (!Nehahrademcompatibility))
525         {
526                 bits |= MSG_ReadByte() << 16;
527                 if (bits & U_EXTEND2)
528                         bits |= MSG_ReadByte() << 24;
529         }
530
531         if (bits & U_LONGENTITY)        
532                 num = (unsigned) MSG_ReadShort ();
533         else
534                 num = (unsigned) MSG_ReadByte ();
535
536         if (num >= MAX_EDICTS)
537                 Host_Error("CL_ParseUpdate: entity number (%i) >= MAX_EDICTS (%i)\n", num, MAX_EDICTS);
538         if (num < 1)
539                 Host_Error("CL_ParseUpdate: invalid entity number (%i)\n", num);
540
541         // mark as visible (no kill)
542         entkill[num] = 0;
543
544         ent = CL_EntityNum (num);
545
546         for (i = 0;i < 32;i++)
547                 if (bits & (1 << i))
548                         bitprofile[i]++;
549         bitprofilecount++;
550
551         ent->state_previous = ent->state_current;
552         deltadie = false;
553         if (bits & U_DELTA)
554         {
555                 if (!ent->state_current.active)
556                         deltadie = true; // was not present in previous frame, leave hidden until next full update
557         }
558         else
559                 ent->state_current = ent->state_baseline;
560
561         ent->state_current.time = cl.mtime[0];
562
563         ent->state_current.flags = 0;
564         ent->state_current.active = true;
565         if (bits & U_MODEL)             ent->state_current.modelindex = (ent->state_current.modelindex & 0xFF00) | MSG_ReadByte();
566         if (bits & U_FRAME)             ent->state_current.frame = (ent->state_current.frame & 0xFF00) | MSG_ReadByte();
567         if (bits & U_COLORMAP)  ent->state_current.colormap = MSG_ReadByte();
568         if (bits & U_SKIN)              ent->state_current.skin = MSG_ReadByte();
569         if (bits & U_EFFECTS)   ent->state_current.effects = (ent->state_current.effects & 0xFF00) | MSG_ReadByte();
570         if (bits & U_ORIGIN1)   ent->state_current.origin[0] = MSG_ReadCoord();
571         if (bits & U_ANGLE1)    ent->state_current.angles[0] = MSG_ReadAngle();
572         if (bits & U_ORIGIN2)   ent->state_current.origin[1] = MSG_ReadCoord();
573         if (bits & U_ANGLE2)    ent->state_current.angles[1] = MSG_ReadAngle();
574         if (bits & U_ORIGIN3)   ent->state_current.origin[2] = MSG_ReadCoord();
575         if (bits & U_ANGLE3)    ent->state_current.angles[2] = MSG_ReadAngle();
576         if (bits & U_STEP)              ent->state_current.flags |= RENDER_STEP;
577         if (bits & U_ALPHA)             ent->state_current.alpha = MSG_ReadByte();
578         if (bits & U_SCALE)             ent->state_current.scale = MSG_ReadByte();
579         if (bits & U_EFFECTS2)  ent->state_current.effects = (ent->state_current.effects & 0x00FF) | (MSG_ReadByte() << 8);
580         if (bits & U_GLOWSIZE)  ent->state_current.glowsize = MSG_ReadByte();
581         if (bits & U_GLOWCOLOR) ent->state_current.glowcolor = MSG_ReadByte();
582         if (bits & U_GLOWTRAIL) ent->state_current.flags |= RENDER_GLOWTRAIL;
583         if (bits & U_COLORMOD)  ent->state_current.colormod = MSG_ReadByte();
584         if (bits & U_FRAME2)    ent->state_current.frame = (ent->state_current.frame & 0x00FF) | (MSG_ReadByte() << 8);
585         if (bits & U_MODEL2)    ent->state_current.modelindex = (ent->state_current.modelindex & 0x00FF) | (MSG_ReadByte() << 8);
586         if (bits & U_VIEWMODEL) ent->state_current.flags |= RENDER_VIEWMODEL;
587         if (bits & U_EXTERIORMODEL)     ent->state_current.flags |= RENDER_EXTERIORMODEL;
588
589         // LordHavoc: to allow playback of the Nehahra movie
590         if (Nehahrademcompatibility && (bits & U_EXTEND1))
591         {
592                 // LordHavoc: evil format
593                 int i = MSG_ReadFloat();
594                 int j = MSG_ReadFloat() * 255.0f;
595                 if (i == 2)
596                 {
597                         if (MSG_ReadFloat())
598                                 ent->state_current.effects |= EF_FULLBRIGHT;
599                 }
600                 if (j < 0)
601                         ent->state_current.alpha = 0;
602                 else if (j == 0 || j >= 255)
603                         ent->state_current.alpha = 255;
604                 else
605                         ent->state_current.alpha = j;
606         }
607
608         if (deltadie)
609         {
610                 // hide the entity
611                 ent->state_current.active = false;
612         }
613         else
614         {
615                 CL_ValidateState(&ent->state_current);
616
617                 /*
618                 if (!ent->state_current.active)
619                 {
620                         if (bits & U_DELTA)
621                         {
622                                 if (bits & U_MODEL)
623                                         Con_Printf("CL_ParseUpdate: delta NULL model on %i: %i %i\n", num, ent->state_previous.modelindex, ent->state_current.modelindex);
624                                 else
625                                         Con_Printf("CL_ParseUpdate: delta NULL model on %i: %i\n", num, ent->state_previous.modelindex);
626                         }
627                         else
628                         {
629                                 if (bits & U_MODEL)
630                                         Con_Printf("CL_ParseUpdate:       NULL model on %i: %i %i\n", num, ent->state_baseline.modelindex, ent->state_current.modelindex);
631                                 else
632                                         Con_Printf("CL_ParseUpdate:       NULL model on %i: %i\n", num, ent->state_baseline.modelindex);
633                         }
634                 }
635                 */
636         }
637 }
638
639 char *bitprofilenames[32] =
640 {
641         "U_MOREBITS",
642         "U_ORIGIN1",
643         "U_ORIGIN2",
644         "U_ORIGIN3",
645         "U_ANGLE2",
646         "U_STEP",
647         "U_FRAME",
648         "U_SIGNAL",
649         "U_ANGLE1",
650         "U_ANGLE3",
651         "U_MODEL",
652         "U_COLORMAP",
653         "U_SKIN",
654         "U_EFFECTS",
655         "U_LONGENTITY",
656         "U_EXTEND1",
657         "U_DELTA",
658         "U_ALPHA",
659         "U_SCALE",
660         "U_EFFECTS2",
661         "U_GLOWSIZE",
662         "U_GLOWCOLOR",
663         "U_COLORMOD",
664         "U_EXTEND2",
665         "U_GLOWTRAIL",
666         "U_VIEWMODEL",
667         "U_FRAME2",
668         "U_MODEL2",
669         "U_EXTERIORMODEL",
670         "U_UNUSED29",
671         "U_UNUSED30",
672         "U_EXTEND3",
673 };
674
675 void CL_BitProfile_f(void)
676 {
677         int i;
678         Con_Printf("bitprofile: %i updates\n");
679         if (bitprofilecount)
680                 for (i = 0;i < 32;i++)
681 //                      if (bitprofile[i])
682                                 Con_Printf("%s: %i %3.2f%%\n", bitprofilenames[i], bitprofile[i], bitprofile[i] * 100.0 / bitprofilecount);
683         Con_Printf("\n");
684         for (i = 0;i < 32;i++)
685                 bitprofile[i] = 0;
686         bitprofilecount = 0;
687 }
688
689 void CL_EntityUpdateSetup(void)
690 {
691         memset(entkill, 1, MAX_EDICTS);
692 }
693
694 void CL_EntityUpdateEnd(void)
695 {
696         int i;
697         for (i = 1;i < MAX_EDICTS;i++)
698                 if (entkill[i])
699                         cl_entities[i].state_previous.active = cl_entities[i].state_current.active = 0;
700 }
701
702 /*
703 ==================
704 CL_ParseBaseline
705 ==================
706 */
707 void CL_ParseBaseline (entity_t *ent, int large)
708 {
709         int i;
710
711         memset(&ent->state_baseline, 0, sizeof(entity_state_t));
712         ent->state_baseline.active = true;
713         if (large)
714         {
715                 ent->state_baseline.modelindex = (unsigned short) MSG_ReadShort ();
716                 ent->state_baseline.frame = (unsigned short) MSG_ReadShort ();
717         }
718         else
719         {
720                 ent->state_baseline.modelindex = MSG_ReadByte ();
721                 ent->state_baseline.frame = MSG_ReadByte ();
722         }
723         ent->state_baseline.colormap = MSG_ReadByte();
724         ent->state_baseline.skin = MSG_ReadByte();
725         for (i = 0;i < 3;i++)
726         {
727                 ent->state_baseline.origin[i] = MSG_ReadCoord ();
728                 ent->state_baseline.angles[i] = MSG_ReadAngle ();
729         }
730         ent->state_baseline.alpha = 255;
731         ent->state_baseline.scale = 16;
732         ent->state_baseline.glowsize = 0;
733         ent->state_baseline.glowcolor = 254;
734         ent->state_baseline.colormod = 255;
735         ent->state_previous = ent->state_current = ent->state_baseline;
736
737         CL_ValidateState(&ent->state_baseline);
738 }
739
740
741 /*
742 ==================
743 CL_ParseClientdata
744
745 Server information pertaining to this client only
746 ==================
747 */
748 void CL_ParseClientdata (int bits)
749 {
750         int i, j;
751
752         bits &= 0xFFFF;
753         if (bits & SU_EXTEND1)
754                 bits |= (MSG_ReadByte() << 16);
755         if (bits & SU_EXTEND2)
756                 bits |= (MSG_ReadByte() << 24);
757
758         if (bits & SU_VIEWHEIGHT)
759                 cl.viewheight = MSG_ReadChar ();
760         else
761                 cl.viewheight = DEFAULT_VIEWHEIGHT;
762
763         if (bits & SU_IDEALPITCH)
764                 cl.idealpitch = MSG_ReadChar ();
765         else
766                 cl.idealpitch = 0;
767         
768         VectorCopy (cl.mvelocity[0], cl.mvelocity[1]);
769         for (i=0 ; i<3 ; i++)
770         {
771                 if (bits & (SU_PUNCH1<<i) )
772                 {
773                         if (dpprotocol)
774                                 cl.punchangle[i] = MSG_ReadPreciseAngle();
775                         else
776                                 cl.punchangle[i] = MSG_ReadChar();
777                 }
778                 else
779                         cl.punchangle[i] = 0;
780                 if (bits & (SU_PUNCHVEC1<<i))
781                         cl.punchvector[i] = MSG_ReadFloatCoord();
782                 else
783                         cl.punchvector[i] = 0;
784                 if (bits & (SU_VELOCITY1<<i) )
785                         cl.mvelocity[0][i] = MSG_ReadChar()*16;
786                 else
787                         cl.mvelocity[0][i] = 0;
788         }
789
790         i = MSG_ReadLong ();
791         if (cl.items != i)
792         {       // set flash times
793                 for (j=0 ; j<32 ; j++)
794                         if ( (i & (1<<j)) && !(cl.items & (1<<j)))
795                                 cl.item_gettime[j] = cl.time;
796                 cl.items = i;
797         }
798                 
799         cl.onground = (bits & SU_ONGROUND) != 0;
800         cl.inwater = (bits & SU_INWATER) != 0;
801
802         cl.stats[STAT_WEAPONFRAME] = (bits & SU_WEAPONFRAME) ? MSG_ReadByte() : 0;
803         cl.stats[STAT_ARMOR] = (bits & SU_ARMOR) ? MSG_ReadByte() : 0;
804         cl.stats[STAT_WEAPON] = (bits & SU_WEAPON) ? MSG_ReadByte() : 0;
805         cl.stats[STAT_HEALTH] = MSG_ReadShort();
806         cl.stats[STAT_AMMO] = MSG_ReadByte();
807
808         cl.stats[STAT_SHELLS] = MSG_ReadByte();
809         cl.stats[STAT_NAILS] = MSG_ReadByte();
810         cl.stats[STAT_ROCKETS] = MSG_ReadByte();
811         cl.stats[STAT_CELLS] = MSG_ReadByte();
812
813         i = MSG_ReadByte ();
814
815         if (standard_quake)
816                 cl.stats[STAT_ACTIVEWEAPON] = i;
817         else
818                 cl.stats[STAT_ACTIVEWEAPON] = (1<<i);
819 }
820
821 /*
822 =====================
823 CL_ParseStatic
824 =====================
825 */
826 void CL_ParseStatic (int large)
827 {
828         entity_t *ent;
829                 
830         if (cl.num_statics >= MAX_STATIC_ENTITIES)
831                 Host_Error ("Too many static entities");
832         ent = &cl_static_entities[cl.num_statics++];
833         CL_ParseBaseline (ent, large);
834
835 // copy it to the current state
836         ent->render.model = cl.model_precache[ent->state_baseline.modelindex];
837         ent->render.frame = ent->render.frame1 = ent->render.frame2 = ent->state_baseline.frame;
838         ent->render.framelerp = 0;
839         ent->render.lerp_starttime = -1;
840         // make torchs play out of sync
841         ent->render.frame1start = ent->render.frame2start = -(rand() & 32767);
842         ent->render.colormap = -1; // no special coloring
843         ent->render.skinnum = ent->state_baseline.skin;
844         ent->render.effects = ent->state_baseline.effects;
845         ent->render.alpha = 1;
846         ent->render.scale = 1;
847         ent->render.alpha = 1;
848         ent->render.colormod[0] = ent->render.colormod[1] = ent->render.colormod[2] = 1;
849
850         VectorCopy (ent->state_baseline.origin, ent->render.origin);
851         VectorCopy (ent->state_baseline.angles, ent->render.angles);    
852 }
853
854 /*
855 ===================
856 CL_ParseStaticSound
857 ===================
858 */
859 void CL_ParseStaticSound (int large)
860 {
861         vec3_t          org;
862         int                     sound_num, vol, atten;
863
864         MSG_ReadVector(org);
865         if (large)
866                 sound_num = (unsigned short) MSG_ReadShort ();
867         else
868                 sound_num = MSG_ReadByte ();
869         vol = MSG_ReadByte ();
870         atten = MSG_ReadByte ();
871         
872         S_StaticSound (cl.sound_precache[sound_num], org, vol, atten);
873 }
874
875 void CL_ParseEffect (void)
876 {
877         vec3_t          org;
878         int                     modelindex, startframe, framecount, framerate;
879
880         MSG_ReadVector(org);
881         modelindex = MSG_ReadByte ();
882         startframe = MSG_ReadByte ();
883         framecount = MSG_ReadByte ();
884         framerate = MSG_ReadByte ();
885
886         CL_Effect(org, modelindex, startframe, framecount, framerate);
887 }
888
889 void CL_ParseEffect2 (void)
890 {
891         vec3_t          org;
892         int                     modelindex, startframe, framecount, framerate;
893
894         MSG_ReadVector(org);
895         modelindex = MSG_ReadShort ();
896         startframe = MSG_ReadShort ();
897         framecount = MSG_ReadByte ();
898         framerate = MSG_ReadByte ();
899
900         CL_Effect(org, modelindex, startframe, framecount, framerate);
901 }
902
903
904 #define SHOWNET(x) if(cl_shownet.value==2)Con_Printf ("%3i:%s\n", msg_readcount-1, x);
905
906 /*
907 =====================
908 CL_ParseServerMessage
909 =====================
910 */
911 void CL_ParseServerMessage (void)
912 {
913         int                     cmd;
914         int                     i, entitiesupdated;
915         byte            cmdlog[32];
916         char            *cmdlogname[32], *temp;
917         int                     cmdindex, cmdcount = 0;
918         
919 //
920 // if recording demos, copy the message out
921 //
922         if (cl_shownet.value == 1)
923                 Con_Printf ("%i ",net_message.cursize);
924         else if (cl_shownet.value == 2)
925                 Con_Printf ("------------------\n");
926         
927         cl.onground = false;    // unless the server says otherwise     
928 //
929 // parse the message
930 //
931         MSG_BeginReading ();
932
933         entitiesupdated = false;
934         CL_EntityUpdateSetup();
935         
936         while (1)
937         {
938                 if (msg_badread)
939                         Host_Error ("CL_ParseServerMessage: Bad server message");
940
941                 cmd = MSG_ReadByte ();
942
943                 if (cmd == -1)
944                 {
945                         SHOWNET("END OF MESSAGE");
946                         break;          // end of message
947                 }
948
949                 cmdindex = cmdcount & 31;
950                 cmdcount++;
951                 cmdlog[cmdindex] = cmd;
952
953                 // if the high bit of the command byte is set, it is a fast update
954                 if (cmd & 128)
955                 {
956                         // LordHavoc: fix for bizarre problem in MSVC that I do not understand (if I assign the string pointer directly it ends up storing a NULL pointer)
957                         temp = "entity";
958                         cmdlogname[cmdindex] = temp;
959                         SHOWNET("fast update");
960                         CL_ParseUpdate (cmd&127);
961                         continue;
962                 }
963
964                 SHOWNET(svc_strings[cmd]);
965                 cmdlogname[cmdindex] = svc_strings[cmd];
966                 if (!cmdlogname[cmdindex])
967                 {
968                         // LordHavoc: fix for bizarre problem in MSVC that I do not understand (if I assign the string pointer directly it ends up storing a NULL pointer)
969                         temp = "<unknown>";
970                         cmdlogname[cmdindex] = temp;
971                 }
972         
973                 // other commands
974                 switch (cmd)
975                 {
976                 default:
977                         {
978                                 char description[32*64], temp[64];
979                                 int count;
980                                 strcpy(description, "packet dump: ");
981                                 i = cmdcount - 32;
982                                 if (i < 0)
983                                         i = 0;
984                                 count = cmdcount - i;
985                                 i &= 31;
986                                 while(count > 0)
987                                 {
988                                         sprintf(temp, "%3i:%s ", cmdlog[i], cmdlogname[i]);
989                                         strcat(description, temp);
990                                         count--;
991                                         i++;
992                                         i &= 31;
993                                 }
994                                 description[strlen(description)-1] = '\n'; // replace the last space with a newline
995                                 Con_Printf(description);
996                                 Host_Error ("CL_ParseServerMessage: Illegible server message\n");
997                         }
998                         break;
999                         
1000                 case svc_nop:
1001 //                      Con_Printf ("svc_nop\n");
1002                         break;
1003                         
1004                 case svc_time:
1005                         // handle old protocols which do not have entity update ranges
1006                         entitiesupdated = true;
1007                         cl.mtime[1] = cl.mtime[0];
1008                         cl.mtime[0] = MSG_ReadFloat ();                 
1009                         break;
1010                         
1011                 case svc_clientdata:
1012                         i = MSG_ReadShort ();
1013                         CL_ParseClientdata (i);
1014                         break;
1015                 
1016                 case svc_version:
1017                         i = MSG_ReadLong ();
1018                         if (i != PROTOCOL_VERSION && i != DPPROTOCOL_VERSION && i != 250)
1019                                 Host_Error ("CL_ParseServerMessage: Server is protocol %i, not %i or %i", i, DPPROTOCOL_VERSION, PROTOCOL_VERSION);
1020                         Nehahrademcompatibility = false;
1021                         if (i == 250)
1022                                 Nehahrademcompatibility = true;
1023                         if (cls.demoplayback && demo_nehahra.value)
1024                                 Nehahrademcompatibility = true;
1025                         dpprotocol = i == DPPROTOCOL_VERSION;
1026                         break;
1027                         
1028                 case svc_disconnect:
1029                         Host_EndGame ("Server disconnected\n");
1030
1031                 case svc_print:
1032                         Con_Printf ("%s", MSG_ReadString ());
1033                         break;
1034                         
1035                 case svc_centerprint:
1036                         SCR_CenterPrint (MSG_ReadString ());
1037                         break;
1038                         
1039                 case svc_stufftext:
1040                         Cbuf_AddText (MSG_ReadString ());
1041                         break;
1042                         
1043                 case svc_damage:
1044                         V_ParseDamage ();
1045                         break;
1046                         
1047                 case svc_serverinfo:
1048                         CL_ParseServerInfo ();
1049                         vid.recalc_refdef = true;       // leave intermission full screen
1050                         break;
1051                         
1052                 case svc_setangle:
1053                         for (i=0 ; i<3 ; i++)
1054                                 cl.viewangles[i] = MSG_ReadAngle ();
1055                         break;
1056                         
1057                 case svc_setview:
1058                         cl.viewentity = MSG_ReadShort ();
1059                         break;
1060                                         
1061                 case svc_lightstyle:
1062                         i = MSG_ReadByte ();
1063                         if (i >= MAX_LIGHTSTYLES)
1064                                 Host_Error ("svc_lightstyle >= MAX_LIGHTSTYLES");
1065                         strncpy (cl_lightstyle[i].map,  MSG_ReadString(), MAX_STYLESTRING - 1);
1066                         cl_lightstyle[i].map[MAX_STYLESTRING - 1] = 0;
1067                         cl_lightstyle[i].length = strlen(cl_lightstyle[i].map);
1068                         break;
1069                         
1070                 case svc_sound:
1071                         CL_ParseStartSoundPacket(false);
1072                         break;
1073
1074                 case svc_sound2:
1075                         CL_ParseStartSoundPacket(true);
1076                         break;
1077
1078                 case svc_stopsound:
1079                         i = MSG_ReadShort();
1080                         S_StopSound(i>>3, i&7);
1081                         break;
1082                 
1083                 case svc_updatename:
1084                         i = MSG_ReadByte ();
1085                         if (i >= cl.maxclients)
1086                                 Host_Error ("CL_ParseServerMessage: svc_updatename >= MAX_SCOREBOARD");
1087                         strcpy (cl.scores[i].name, MSG_ReadString ());
1088                         break;
1089                         
1090                 case svc_updatefrags:
1091                         i = MSG_ReadByte ();
1092                         if (i >= cl.maxclients)
1093                                 Host_Error ("CL_ParseServerMessage: svc_updatefrags >= MAX_SCOREBOARD");
1094                         cl.scores[i].frags = MSG_ReadShort ();
1095                         break;                  
1096
1097                 case svc_updatecolors:
1098                         i = MSG_ReadByte ();
1099                         if (i >= cl.maxclients)
1100                                 Host_Error ("CL_ParseServerMessage: svc_updatecolors >= MAX_SCOREBOARD");
1101                         cl.scores[i].colors = MSG_ReadByte ();
1102                         break;
1103                         
1104                 case svc_particle:
1105                         R_ParseParticleEffect ();
1106                         break;
1107
1108                 case svc_effect:
1109                         CL_ParseEffect ();
1110                         break;
1111
1112                 case svc_effect2:
1113                         CL_ParseEffect2 ();
1114                         break;
1115
1116                 case svc_spawnbaseline:
1117                         i = MSG_ReadShort ();
1118                         // must use CL_EntityNum() to force cl.num_entities up
1119                         CL_ParseBaseline (CL_EntityNum(i), false);
1120                         break;
1121                 case svc_spawnbaseline2:
1122                         i = MSG_ReadShort ();
1123                         // must use CL_EntityNum() to force cl.num_entities up
1124                         CL_ParseBaseline (CL_EntityNum(i), true);
1125                         break;
1126                 case svc_spawnstatic:
1127                         CL_ParseStatic (false);
1128                         break;
1129                 case svc_spawnstatic2:
1130                         CL_ParseStatic (true);
1131                         break;
1132                 case svc_temp_entity:
1133                         CL_ParseTEnt ();
1134                         break;
1135
1136                 case svc_setpause:
1137                         cl.paused = MSG_ReadByte ();
1138                         if (cl.paused)
1139                                 CDAudio_Pause ();
1140                         else
1141                                 CDAudio_Resume ();
1142                         break;
1143                         
1144                 case svc_signonnum:
1145                         i = MSG_ReadByte ();
1146                         if (i <= cls.signon)
1147                                 Host_Error ("Received signon %i when at %i", i, cls.signon);
1148                         cls.signon = i;
1149                         CL_SignonReply ();
1150                         break;
1151
1152                 case svc_killedmonster:
1153                         cl.stats[STAT_MONSTERS]++;
1154                         break;
1155
1156                 case svc_foundsecret:
1157                         cl.stats[STAT_SECRETS]++;
1158                         break;
1159
1160                 case svc_updatestat:
1161                         i = MSG_ReadByte ();
1162                         if (i < 0 || i >= MAX_CL_STATS)
1163                                 Host_Error ("svc_updatestat: %i is invalid", i);
1164                         cl.stats[i] = MSG_ReadLong ();
1165                         break;
1166                         
1167                 case svc_spawnstaticsound:
1168                         CL_ParseStaticSound (false);
1169                         break;
1170
1171                 case svc_spawnstaticsound2:
1172                         CL_ParseStaticSound (true);
1173                         break;
1174
1175                 case svc_cdtrack:
1176                         cl.cdtrack = MSG_ReadByte ();
1177                         cl.looptrack = MSG_ReadByte ();
1178                         if ( (cls.demoplayback || cls.demorecording) && (cls.forcetrack != -1) )
1179                                 CDAudio_Play ((byte)cls.forcetrack, true);
1180                         else
1181                                 CDAudio_Play ((byte)cl.cdtrack, true);
1182                         break;
1183
1184                 case svc_intermission:
1185                         cl.intermission = 1;
1186                         cl.completed_time = cl.time;
1187                         vid.recalc_refdef = true;       // go to full screen
1188                         break;
1189
1190                 case svc_finale:
1191                         cl.intermission = 2;
1192                         cl.completed_time = cl.time;
1193                         vid.recalc_refdef = true;       // go to full screen
1194                         SCR_CenterPrint (MSG_ReadString ());                    
1195                         break;
1196
1197                 case svc_cutscene:
1198                         cl.intermission = 3;
1199                         cl.completed_time = cl.time;
1200                         vid.recalc_refdef = true;       // go to full screen
1201                         SCR_CenterPrint (MSG_ReadString ());                    
1202                         break;
1203
1204                 case svc_sellscreen:
1205                         Cmd_ExecuteString ("help", src_command);
1206                         break;
1207                 case svc_hidelmp:
1208                         SHOWLMP_decodehide();
1209                         break;
1210                 case svc_showlmp:
1211                         SHOWLMP_decodeshow();
1212                         break;
1213                 case svc_skybox:
1214                         R_SetSkyBox(MSG_ReadString());
1215                         break;
1216                 }
1217         }
1218
1219         if (entitiesupdated)
1220                 CL_EntityUpdateEnd();
1221 }