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