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