monster movement interpolation now works in both protocols (shared code), this bloate...
[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 // 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
438                 if (cl.model_precache[i] == NULL)
439                 {
440                         Host_Error("Model %s not found\n", model_precache[i]);
441                         return;
442                 }
443                 CL_KeepaliveMessage ();
444         }
445
446         S_BeginPrecaching ();
447         for (i=1 ; i<numsounds ; i++)
448         {
449                 cl.sound_precache[i] = S_PrecacheSound (sound_precache[i], true);
450                 CL_KeepaliveMessage ();
451         }
452         S_EndPrecaching ();
453
454 // local state
455         ent = &cl_entities[0];
456         // entire entity array was cleared, so just fill in a few fields
457         ent->state_current.active = true;
458         ent->render.model = cl.worldmodel = cl.model_precache[1];
459         ent->render.scale = 1;
460         ent->render.alpha = 1;
461         VectorAdd(ent->render.origin, ent->render.model->normalmins, ent->render.mins);
462         VectorAdd(ent->render.origin, ent->render.model->normalmaxs, ent->render.maxs);
463         // clear entlife array
464         memset(entlife, 0, MAX_EDICTS);
465
466         cl_num_entities = 1;
467
468         R_NewMap ();
469
470         CL_CGVM_Start();
471
472         Mem_CheckSentinelsGlobal();
473
474         noclip_anglehack = false;               // noclip is turned off at start
475 }
476
477 void CL_ValidateState(entity_state_t *s)
478 {
479         model_t *model;
480
481         if (!s->active)
482                 return;
483
484         if (s->modelindex >= MAX_MODELS)
485                 Host_Error("CL_ValidateState: modelindex (%i) >= MAX_MODELS (%i)\n", s->modelindex, MAX_MODELS);
486
487         // colormap is client index + 1
488         if (s->colormap > cl.maxclients)
489                 Host_Error ("CL_ValidateState: colormap (%i) > cl.maxclients (%i)", s->colormap, cl.maxclients);
490
491         model = cl.model_precache[s->modelindex];
492         Mod_CheckLoaded(model);
493         if (model && s->frame >= model->numframes)
494         {
495                 Con_DPrintf("CL_ValidateState: no such frame %i in \"%s\"\n", s->frame, model->name);
496                 s->frame = 0;
497         }
498         if (model && s->skin > 0 && s->skin >= model->numskins)
499         {
500                 Con_DPrintf("CL_ValidateState: no such skin %i in \"%s\"\n", s->skin, model->name);
501                 s->skin = 0;
502         }
503 }
504
505 void CL_MoveLerpEntityStates(entity_t *ent)
506 {
507         float odelta[3], adelta[3];
508         VectorSubtract(ent->state_current.origin, ent->persistent.neworigin, odelta);
509         VectorSubtract(ent->state_current.angles, ent->persistent.newangles, adelta);
510         if (!ent->state_previous.active || cls.timedemo || DotProduct(odelta, odelta) > 1000*1000 || cl_nolerp.integer)
511         {
512                 // we definitely shouldn't lerp
513                 ent->persistent.lerpdeltatime = 0;
514                 ent->persistent.lerpstarttime = cl.mtime[1];
515                 VectorCopy(ent->state_current.origin, ent->persistent.oldorigin);
516                 VectorCopy(ent->state_current.angles, ent->persistent.oldangles);
517                 VectorCopy(ent->state_current.origin, ent->persistent.neworigin);
518                 VectorCopy(ent->state_current.angles, ent->persistent.newangles);
519         }
520         else// if (ent->state_current.flags & RENDER_STEP)
521         {
522                 // monster interpolation
523                 if (DotProduct(odelta, odelta) + DotProduct(adelta, adelta) > 0.01)
524                 {
525                         ent->persistent.lerpdeltatime = cl.time - ent->persistent.lerpstarttime;
526                         ent->persistent.lerpstarttime = cl.mtime[1];
527                         VectorCopy(ent->persistent.neworigin, ent->persistent.oldorigin);
528                         VectorCopy(ent->persistent.newangles, ent->persistent.oldangles);
529                         VectorCopy(ent->state_current.origin, ent->persistent.neworigin);
530                         VectorCopy(ent->state_current.angles, ent->persistent.newangles);
531                 }
532         }
533         /*
534         else
535         {
536                 // not a monster
537                 ent->persistent.lerpstarttime = cl.mtime[1];
538                 // no lerp if it's singleplayer
539                 //if (sv.active && svs.maxclients == 1 && !ent->state_current.flags & RENDER_STEP)
540                 //      ent->persistent.lerpdeltatime = 0;
541                 //else
542                         ent->persistent.lerpdeltatime = cl.mtime[0] - cl.mtime[1];
543                 VectorCopy(ent->persistent.neworigin, ent->persistent.oldorigin);
544                 VectorCopy(ent->persistent.newangles, ent->persistent.oldangles);
545                 VectorCopy(ent->state_current.origin, ent->persistent.neworigin);
546                 VectorCopy(ent->state_current.angles, ent->persistent.newangles);
547         }
548         */
549 }
550
551 /*
552 ==================
553 CL_ParseUpdate
554
555 Parse an entity update message from the server
556 If an entities model or origin changes from frame to frame, it must be
557 relinked.  Other attributes can change without relinking.
558 ==================
559 */
560 int bitprofile[32], bitprofilecount = 0;
561 void CL_ParseUpdate (int bits)
562 {
563         int i, num;
564         entity_t *ent;
565         entity_state_t new;
566
567         if (bits & U_MOREBITS)
568                 bits |= (MSG_ReadByte()<<8);
569         if ((bits & U_EXTEND1) && (!Nehahrademcompatibility))
570         {
571                 bits |= MSG_ReadByte() << 16;
572                 if (bits & U_EXTEND2)
573                         bits |= MSG_ReadByte() << 24;
574         }
575
576         if (bits & U_LONGENTITY)
577                 num = (unsigned) MSG_ReadShort ();
578         else
579                 num = (unsigned) MSG_ReadByte ();
580
581         if (num >= MAX_EDICTS)
582                 Host_Error("CL_ParseUpdate: entity number (%i) >= MAX_EDICTS (%i)\n", num, MAX_EDICTS);
583         if (num < 1)
584                 Host_Error("CL_ParseUpdate: invalid entity number (%i)\n", num);
585
586         ent = cl_entities + num;
587
588         for (i = 0;i < 32;i++)
589                 if (bits & (1 << i))
590                         bitprofile[i]++;
591         bitprofilecount++;
592
593         // note: this inherits the 'active' state of the baseline chosen
594         // (state_baseline is always active, state_current may not be active if
595         // the entity was missing in the last frame)
596         if (bits & U_DELTA)
597                 new = ent->state_current;
598         else
599         {
600                 new = ent->state_baseline;
601                 new.active = true;
602         }
603
604         new.number = num;
605         new.time = cl.mtime[0];
606         new.flags = 0;
607         if (bits & U_MODEL)             new.modelindex = (new.modelindex & 0xFF00) | MSG_ReadByte();
608         if (bits & U_FRAME)             new.frame = (new.frame & 0xFF00) | MSG_ReadByte();
609         if (bits & U_COLORMAP)  new.colormap = MSG_ReadByte();
610         if (bits & U_SKIN)              new.skin = MSG_ReadByte();
611         if (bits & U_EFFECTS)   new.effects = (new.effects & 0xFF00) | MSG_ReadByte();
612         if (bits & U_ORIGIN1)   new.origin[0] = MSG_ReadCoord();
613         if (bits & U_ANGLE1)    new.angles[0] = MSG_ReadAngle();
614         if (bits & U_ORIGIN2)   new.origin[1] = MSG_ReadCoord();
615         if (bits & U_ANGLE2)    new.angles[1] = MSG_ReadAngle();
616         if (bits & U_ORIGIN3)   new.origin[2] = MSG_ReadCoord();
617         if (bits & U_ANGLE3)    new.angles[2] = MSG_ReadAngle();
618         if (bits & U_STEP)              new.flags |= RENDER_STEP;
619         if (bits & U_ALPHA)             new.alpha = MSG_ReadByte();
620         if (bits & U_SCALE)             new.scale = MSG_ReadByte();
621         if (bits & U_EFFECTS2)  new.effects = (new.effects & 0x00FF) | (MSG_ReadByte() << 8);
622         if (bits & U_GLOWSIZE)  new.glowsize = MSG_ReadByte();
623         if (bits & U_GLOWCOLOR) new.glowcolor = MSG_ReadByte();
624         // apparently the dpcrush demo uses this (unintended, and it uses white anyway)
625         if (bits & U_COLORMOD)  MSG_ReadByte();
626         if (bits & U_GLOWTRAIL) new.flags |= RENDER_GLOWTRAIL;
627         if (bits & U_FRAME2)    new.frame = (new.frame & 0x00FF) | (MSG_ReadByte() << 8);
628         if (bits & U_MODEL2)    new.modelindex = (new.modelindex & 0x00FF) | (MSG_ReadByte() << 8);
629         if (bits & U_VIEWMODEL) new.flags |= RENDER_VIEWMODEL;
630         if (bits & U_EXTERIORMODEL)     new.flags |= RENDER_EXTERIORMODEL;
631
632         // LordHavoc: to allow playback of the Nehahra movie
633         if (Nehahrademcompatibility && (bits & U_EXTEND1))
634         {
635                 // LordHavoc: evil format
636                 int i = MSG_ReadFloat();
637                 int j = MSG_ReadFloat() * 255.0f;
638                 if (i == 2)
639                 {
640                         i = MSG_ReadFloat();
641                         if (i)
642                                 new.effects |= EF_FULLBRIGHT;
643                 }
644                 if (j < 0)
645                         new.alpha = 0;
646                 else if (j == 0 || j >= 255)
647                         new.alpha = 255;
648                 else
649                         new.alpha = j;
650         }
651
652         if (new.active)
653                 CL_ValidateState(&new);
654
655         ent->state_previous = ent->state_current;
656         ent->state_current = new;
657         if (ent->state_current.active)
658         {
659                 CL_MoveLerpEntityStates(ent);
660                 cl_entities_active[ent->state_current.number] = true;
661                 // mark as visible (no kill this frame)
662                 entlife[ent->state_current.number] = 2;
663         }
664 }
665
666 void CL_ReadEntityFrame(void)
667 {
668         entity_t *ent;
669         entity_frame_t entityframe;
670         int i;
671         EntityFrame_Read(&cl.entitydatabase);
672         EntityFrame_FetchFrame(&cl.entitydatabase, EntityFrame_MostRecentlyRecievedFrameNum(&cl.entitydatabase), &entityframe);
673         for (i = 0;i < entityframe.numentities;i++)
674         {
675                 // copy the states
676                 ent = &cl_entities[entityframe.entitydata[i].number];
677                 ent->state_previous = ent->state_current;
678                 ent->state_current = entityframe.entitydata[i];
679                 CL_MoveLerpEntityStates(ent);
680                 // the entity lives again...
681                 entlife[ent->state_current.number] = 2;
682                 cl_entities_active[ent->state_current.number] = true;
683         }
684         VectorCopy(cl.viewentoriginnew, cl.viewentoriginold);
685         VectorCopy(entityframe.eye, cl.viewentoriginnew);
686 }
687
688 char *bitprofilenames[32] =
689 {
690         "U_MOREBITS",
691         "U_ORIGIN1",
692         "U_ORIGIN2",
693         "U_ORIGIN3",
694         "U_ANGLE2",
695         "U_STEP",
696         "U_FRAME",
697         "U_SIGNAL",
698         "U_ANGLE1",
699         "U_ANGLE3",
700         "U_MODEL",
701         "U_COLORMAP",
702         "U_SKIN",
703         "U_EFFECTS",
704         "U_LONGENTITY",
705         "U_EXTEND1",
706         "U_DELTA",
707         "U_ALPHA",
708         "U_SCALE",
709         "U_EFFECTS2",
710         "U_GLOWSIZE",
711         "U_GLOWCOLOR",
712         "obsolete U_COLORMOD",
713         "U_EXTEND2",
714         "U_GLOWTRAIL",
715         "U_VIEWMODEL",
716         "U_FRAME2",
717         "U_MODEL2",
718         "U_EXTERIORMODEL",
719         "U_UNUSED29",
720         "U_UNUSED30",
721         "U_EXTEND3",
722 };
723
724 void CL_BitProfile_f(void)
725 {
726         int i;
727         Con_Printf("bitprofile: %i updates\n");
728         if (bitprofilecount)
729                 for (i = 0;i < 32;i++)
730                         Con_Printf("%s: %i %3.2f%%\n", bitprofilenames[i], bitprofile[i], bitprofile[i] * 100.0 / bitprofilecount);
731         Con_Printf("\n");
732         for (i = 0;i < 32;i++)
733                 bitprofile[i] = 0;
734         bitprofilecount = 0;
735 }
736
737 void CL_EntityUpdateSetup(void)
738 {
739 }
740
741 void CL_EntityUpdateEnd(void)
742 {
743         int i;
744         // disable entities that disappeared this frame
745         for (i = 1;i < MAX_EDICTS;i++)
746         {
747                 // clear only the entities that were active last frame but not this
748                 // frame, don't waste time clearing all entities (which would cause
749                 // cache misses)
750                 if (entlife[i])
751                 {
752                         entlife[i]--;
753                         if (!entlife[i])
754                                 cl_entities[i].state_previous.active = cl_entities[i].state_current.active = 0;
755                 }
756         }
757 }
758
759 /*
760 ==================
761 CL_ParseBaseline
762 ==================
763 */
764 void CL_ParseBaseline (entity_t *ent, int large)
765 {
766         int i;
767
768         memset(&ent->state_baseline, 0, sizeof(entity_state_t));
769         ent->state_baseline.active = true;
770         if (large)
771         {
772                 ent->state_baseline.modelindex = (unsigned short) MSG_ReadShort ();
773                 ent->state_baseline.frame = (unsigned short) MSG_ReadShort ();
774         }
775         else
776         {
777                 ent->state_baseline.modelindex = MSG_ReadByte ();
778                 ent->state_baseline.frame = MSG_ReadByte ();
779         }
780         ent->state_baseline.colormap = MSG_ReadByte();
781         ent->state_baseline.skin = MSG_ReadByte();
782         for (i = 0;i < 3;i++)
783         {
784                 ent->state_baseline.origin[i] = MSG_ReadCoord ();
785                 ent->state_baseline.angles[i] = MSG_ReadAngle ();
786         }
787         ent->state_baseline.alpha = 255;
788         ent->state_baseline.scale = 16;
789         ent->state_baseline.glowsize = 0;
790         ent->state_baseline.glowcolor = 254;
791         ent->state_previous = ent->state_current = ent->state_baseline;
792
793         CL_ValidateState(&ent->state_baseline);
794 }
795
796
797 /*
798 ==================
799 CL_ParseClientdata
800
801 Server information pertaining to this client only
802 ==================
803 */
804 void CL_ParseClientdata (int bits)
805 {
806         int i, j;
807
808         bits &= 0xFFFF;
809         if (bits & SU_EXTEND1)
810                 bits |= (MSG_ReadByte() << 16);
811         if (bits & SU_EXTEND2)
812                 bits |= (MSG_ReadByte() << 24);
813
814         if (bits & SU_VIEWHEIGHT)
815                 cl.viewheight = MSG_ReadChar ();
816         else
817                 cl.viewheight = DEFAULT_VIEWHEIGHT;
818
819         if (bits & SU_IDEALPITCH)
820                 cl.idealpitch = MSG_ReadChar ();
821         else
822                 cl.idealpitch = 0;
823
824         VectorCopy (cl.mvelocity[0], cl.mvelocity[1]);
825         for (i=0 ; i<3 ; i++)
826         {
827                 if (bits & (SU_PUNCH1<<i) )
828                 {
829                         if (dpprotocol)
830                                 cl.punchangle[i] = MSG_ReadPreciseAngle();
831                         else
832                                 cl.punchangle[i] = MSG_ReadChar();
833                 }
834                 else
835                         cl.punchangle[i] = 0;
836                 if (bits & (SU_PUNCHVEC1<<i))
837                         cl.punchvector[i] = MSG_ReadCoord();
838                 else
839                         cl.punchvector[i] = 0;
840                 if (bits & (SU_VELOCITY1<<i) )
841                         cl.mvelocity[0][i] = MSG_ReadChar()*16;
842                 else
843                         cl.mvelocity[0][i] = 0;
844         }
845
846         i = MSG_ReadLong ();
847         if (cl.items != i)
848         {       // set flash times
849                 for (j=0 ; j<32 ; j++)
850                         if ( (i & (1<<j)) && !(cl.items & (1<<j)))
851                                 cl.item_gettime[j] = cl.time;
852                 cl.items = i;
853         }
854
855         cl.onground = (bits & SU_ONGROUND) != 0;
856         cl.inwater = (bits & SU_INWATER) != 0;
857
858         cl.stats[STAT_WEAPONFRAME] = (bits & SU_WEAPONFRAME) ? MSG_ReadByte() : 0;
859         cl.stats[STAT_ARMOR] = (bits & SU_ARMOR) ? MSG_ReadByte() : 0;
860         cl.stats[STAT_WEAPON] = (bits & SU_WEAPON) ? MSG_ReadByte() : 0;
861         cl.stats[STAT_HEALTH] = MSG_ReadShort();
862         cl.stats[STAT_AMMO] = MSG_ReadByte();
863
864         cl.stats[STAT_SHELLS] = MSG_ReadByte();
865         cl.stats[STAT_NAILS] = MSG_ReadByte();
866         cl.stats[STAT_ROCKETS] = MSG_ReadByte();
867         cl.stats[STAT_CELLS] = MSG_ReadByte();
868
869         i = MSG_ReadByte ();
870
871         if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE)
872                 cl.stats[STAT_ACTIVEWEAPON] = (1<<i);
873         else
874                 cl.stats[STAT_ACTIVEWEAPON] = i;
875
876         cl.viewzoomold = cl.viewzoomnew; // for interpolation
877         if (bits & SU_VIEWZOOM)
878         {
879                 i = MSG_ReadByte();
880                 if (i < 2)
881                         i = 2;
882                 cl.viewzoomnew = (float) i * (1.0f / 255.0f);
883         }
884         else
885                 cl.viewzoomnew = 1;
886
887 }
888
889 /*
890 =====================
891 CL_ParseStatic
892 =====================
893 */
894 void CL_ParseStatic (int large)
895 {
896         entity_t *ent;
897
898         if (cl_num_static_entities >= cl_max_static_entities)
899                 Host_Error ("Too many static entities");
900         ent = &cl_static_entities[cl_num_static_entities++];
901         CL_ParseBaseline (ent, large);
902
903 // copy it to the current state
904         ent->render.model = cl.model_precache[ent->state_baseline.modelindex];
905         ent->render.frame = ent->render.frame1 = ent->render.frame2 = ent->state_baseline.frame;
906         ent->render.framelerp = 0;
907         // make torchs play out of sync
908         ent->render.frame1time = ent->render.frame2time = lhrandom(-10, -1);
909         ent->render.colormap = -1; // no special coloring
910         ent->render.skinnum = ent->state_baseline.skin;
911         ent->render.effects = ent->state_baseline.effects;
912         ent->render.alpha = 1;
913         ent->render.scale = 1;
914         ent->render.alpha = 1;
915
916         VectorCopy (ent->state_baseline.origin, ent->render.origin);
917         VectorCopy (ent->state_baseline.angles, ent->render.angles);
918
919         if (ent->render.angles[0] || ent->render.angles[2])
920         {
921                 // pitch or roll
922                 VectorAdd(ent->render.origin, ent->render.model->rotatedmins, ent->render.mins);
923                 VectorAdd(ent->render.origin, ent->render.model->rotatedmaxs, ent->render.maxs);
924         }
925         else if (ent->render.angles[1])
926         {
927                 // yaw
928                 VectorAdd(ent->render.origin, ent->render.model->yawmins, ent->render.mins);
929                 VectorAdd(ent->render.origin, ent->render.model->yawmaxs, ent->render.maxs);
930         }
931         else
932         {
933                 VectorAdd(ent->render.origin, ent->render.model->normalmins, ent->render.mins);
934                 VectorAdd(ent->render.origin, ent->render.model->normalmaxs, ent->render.maxs);
935         }
936
937         // This is definitely cheating...
938         if (ent->render.model == NULL)
939                 cl_num_static_entities--;
940 }
941
942 /*
943 ===================
944 CL_ParseStaticSound
945 ===================
946 */
947 void CL_ParseStaticSound (int large)
948 {
949         vec3_t          org;
950         int                     sound_num, vol, atten;
951
952         MSG_ReadVector(org);
953         if (large)
954                 sound_num = (unsigned short) MSG_ReadShort ();
955         else
956                 sound_num = MSG_ReadByte ();
957         vol = MSG_ReadByte ();
958         atten = MSG_ReadByte ();
959
960         S_StaticSound (cl.sound_precache[sound_num], org, vol, atten);
961 }
962
963 void CL_ParseEffect (void)
964 {
965         vec3_t          org;
966         int                     modelindex, startframe, framecount, framerate;
967
968         MSG_ReadVector(org);
969         modelindex = MSG_ReadByte ();
970         startframe = MSG_ReadByte ();
971         framecount = MSG_ReadByte ();
972         framerate = MSG_ReadByte ();
973
974         CL_Effect(org, modelindex, startframe, framecount, framerate);
975 }
976
977 void CL_ParseEffect2 (void)
978 {
979         vec3_t          org;
980         int                     modelindex, startframe, framecount, framerate;
981
982         MSG_ReadVector(org);
983         modelindex = MSG_ReadShort ();
984         startframe = MSG_ReadShort ();
985         framecount = MSG_ReadByte ();
986         framerate = MSG_ReadByte ();
987
988         CL_Effect(org, modelindex, startframe, framecount, framerate);
989 }
990
991
992 #define SHOWNET(x) if(cl_shownet.integer==2)Con_Printf ("%3i:%s\n", msg_readcount-1, x);
993
994 static qbyte cgamenetbuffer[65536];
995
996 /*
997 =====================
998 CL_ParseServerMessage
999 =====================
1000 */
1001 void CL_ParseServerMessage (void)
1002 {
1003         int                     cmd;
1004         int                     i, entitiesupdated;
1005         qbyte           cmdlog[32];
1006         char            *cmdlogname[32], *temp;
1007         int                     cmdindex, cmdcount = 0;
1008
1009 //
1010 // if recording demos, copy the message out
1011 //
1012         if (cl_shownet.integer == 1)
1013                 Con_Printf ("%i ",net_message.cursize);
1014         else if (cl_shownet.integer == 2)
1015                 Con_Printf ("------------------\n");
1016
1017         cl.onground = false;    // unless the server says otherwise
1018 //
1019 // parse the message
1020 //
1021         MSG_BeginReading ();
1022
1023         entitiesupdated = false;
1024
1025         while (1)
1026         {
1027                 if (msg_badread)
1028                         Host_Error ("CL_ParseServerMessage: Bad server message");
1029
1030                 cmd = MSG_ReadByte ();
1031
1032                 if (cmd == -1)
1033                 {
1034                         SHOWNET("END OF MESSAGE");
1035                         break;          // end of message
1036                 }
1037
1038                 cmdindex = cmdcount & 31;
1039                 cmdcount++;
1040                 cmdlog[cmdindex] = cmd;
1041
1042                 // if the high bit of the command byte is set, it is a fast update
1043                 if (cmd & 128)
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 = "entity";
1047                         cmdlogname[cmdindex] = temp;
1048                         SHOWNET("fast update");
1049                         if (cls.signon == SIGNONS - 1)
1050                         {
1051                                 // first update is the final signon stage
1052                                 cls.signon = SIGNONS;
1053                                 CL_SignonReply ();
1054                         }
1055                         CL_ParseUpdate (cmd&127);
1056                         continue;
1057                 }
1058
1059                 SHOWNET(svc_strings[cmd]);
1060                 cmdlogname[cmdindex] = svc_strings[cmd];
1061                 if (!cmdlogname[cmdindex])
1062                 {
1063                         // 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)
1064                         temp = "<unknown>";
1065                         cmdlogname[cmdindex] = temp;
1066                 }
1067
1068                 // other commands
1069                 switch (cmd)
1070                 {
1071                 default:
1072                         {
1073                                 char description[32*64], temp[64];
1074                                 int count;
1075                                 strcpy(description, "packet dump: ");
1076                                 i = cmdcount - 32;
1077                                 if (i < 0)
1078                                         i = 0;
1079                                 count = cmdcount - i;
1080                                 i &= 31;
1081                                 while(count > 0)
1082                                 {
1083                                         sprintf(temp, "%3i:%s ", cmdlog[i], cmdlogname[i]);
1084                                         strcat(description, temp);
1085                                         count--;
1086                                         i++;
1087                                         i &= 31;
1088                                 }
1089                                 description[strlen(description)-1] = '\n'; // replace the last space with a newline
1090                                 Con_Printf("%s", description);
1091                                 Host_Error ("CL_ParseServerMessage: Illegible server message\n");
1092                         }
1093                         break;
1094
1095                 case svc_nop:
1096                         break;
1097
1098                 case svc_time:
1099                         if (!entitiesupdated)
1100                         {
1101                                 // this is a new frame, we'll be seeing entities,
1102                                 // so prepare for entity updates
1103                                 CL_EntityUpdateSetup();
1104                                 entitiesupdated = true;
1105                         }
1106                         cl.mtime[1] = cl.mtime[0];
1107                         cl.mtime[0] = MSG_ReadFloat ();
1108                         break;
1109
1110                 case svc_clientdata:
1111                         i = MSG_ReadShort ();
1112                         CL_ParseClientdata (i);
1113                         break;
1114
1115                 case svc_version:
1116                         i = MSG_ReadLong ();
1117                         if (i != PROTOCOL_VERSION && i != DPPROTOCOL_VERSION1 && i != DPPROTOCOL_VERSION2 && i != DPPROTOCOL_VERSION3 && i != 250)
1118                                 Host_Error ("CL_ParseServerMessage: Server is protocol %i, not %i, %i, %i or %i", i, DPPROTOCOL_VERSION1, DPPROTOCOL_VERSION2, DPPROTOCOL_VERSION3, PROTOCOL_VERSION);
1119                         Nehahrademcompatibility = false;
1120                         if (i == 250)
1121                                 Nehahrademcompatibility = true;
1122                         if (cls.demoplayback && demo_nehahra.integer)
1123                                 Nehahrademcompatibility = true;
1124                         dpprotocol = i;
1125                         if (dpprotocol != DPPROTOCOL_VERSION1 && dpprotocol != DPPROTOCOL_VERSION2 && dpprotocol != DPPROTOCOL_VERSION3)
1126                                 dpprotocol = 0;
1127                         break;
1128
1129                 case svc_disconnect:
1130                         Host_EndGame ("Server disconnected\n");
1131
1132                 case svc_print:
1133                         Con_Printf ("%s", MSG_ReadString ());
1134                         break;
1135
1136                 case svc_centerprint:
1137                         SCR_CenterPrint (MSG_ReadString ());
1138                         break;
1139
1140                 case svc_stufftext:
1141                         Cbuf_AddText (MSG_ReadString ());
1142                         break;
1143
1144                 case svc_damage:
1145                         V_ParseDamage ();
1146                         break;
1147
1148                 case svc_serverinfo:
1149                         CL_ParseServerInfo ();
1150                         break;
1151
1152                 case svc_setangle:
1153                         for (i=0 ; i<3 ; i++)
1154                                 cl.viewangles[i] = MSG_ReadAngle ();
1155                         break;
1156
1157                 case svc_setview:
1158                         cl.viewentity = MSG_ReadShort ();
1159                         // LordHavoc: assume first setview recieved is the real player entity
1160                         if (!cl.playerentity)
1161                                 cl.playerentity = cl.viewentity;
1162                         break;
1163
1164                 case svc_lightstyle:
1165                         i = MSG_ReadByte ();
1166                         if (i >= MAX_LIGHTSTYLES)
1167                                 Host_Error ("svc_lightstyle >= MAX_LIGHTSTYLES");
1168                         strncpy (cl_lightstyle[i].map,  MSG_ReadString(), MAX_STYLESTRING - 1);
1169                         cl_lightstyle[i].map[MAX_STYLESTRING - 1] = 0;
1170                         cl_lightstyle[i].length = strlen(cl_lightstyle[i].map);
1171                         break;
1172
1173                 case svc_sound:
1174                         CL_ParseStartSoundPacket(false);
1175                         break;
1176
1177                 case svc_sound2:
1178                         CL_ParseStartSoundPacket(true);
1179                         break;
1180
1181                 case svc_stopsound:
1182                         i = MSG_ReadShort();
1183                         S_StopSound(i>>3, i&7);
1184                         break;
1185
1186                 case svc_updatename:
1187                         i = MSG_ReadByte ();
1188                         if (i >= cl.maxclients)
1189                                 Host_Error ("CL_ParseServerMessage: svc_updatename >= cl.maxclients");
1190                         strcpy (cl.scores[i].name, MSG_ReadString ());
1191                         break;
1192
1193                 case svc_updatefrags:
1194                         i = MSG_ReadByte ();
1195                         if (i >= cl.maxclients)
1196                                 Host_Error ("CL_ParseServerMessage: svc_updatefrags >= cl.maxclients");
1197                         cl.scores[i].frags = MSG_ReadShort ();
1198                         break;
1199
1200                 case svc_updatecolors:
1201                         i = MSG_ReadByte ();
1202                         if (i >= cl.maxclients)
1203                                 Host_Error ("CL_ParseServerMessage: svc_updatecolors >= cl.maxclients");
1204                         cl.scores[i].colors = MSG_ReadByte ();
1205                         // update our color cvar if our color changed
1206                         if (i == cl.playerentity - 1)
1207                                 Cvar_SetValue ("_cl_color", cl.scores[i].colors);
1208                         break;
1209
1210                 case svc_particle:
1211                         CL_ParseParticleEffect ();
1212                         break;
1213
1214                 case svc_effect:
1215                         CL_ParseEffect ();
1216                         break;
1217
1218                 case svc_effect2:
1219                         CL_ParseEffect2 ();
1220                         break;
1221
1222                 case svc_spawnbaseline:
1223                         i = MSG_ReadShort ();
1224                         if (i < 0 || i >= MAX_EDICTS)
1225                                 Host_Error ("CL_ParseServerMessage: svc_spawnbaseline: invalid entity number %i", i);
1226                         CL_ParseBaseline (cl_entities + i, false);
1227                         break;
1228                 case svc_spawnbaseline2:
1229                         i = MSG_ReadShort ();
1230                         if (i < 0 || i >= MAX_EDICTS)
1231                                 Host_Error ("CL_ParseServerMessage: svc_spawnbaseline2: invalid entity number %i", i);
1232                         CL_ParseBaseline (cl_entities + i, true);
1233                         break;
1234                 case svc_spawnstatic:
1235                         CL_ParseStatic (false);
1236                         break;
1237                 case svc_spawnstatic2:
1238                         CL_ParseStatic (true);
1239                         break;
1240                 case svc_temp_entity:
1241                         CL_ParseTEnt ();
1242                         break;
1243
1244                 case svc_setpause:
1245                         cl.paused = MSG_ReadByte ();
1246                         if (cl.paused)
1247                                 CDAudio_Pause ();
1248                         else
1249                                 CDAudio_Resume ();
1250                         break;
1251
1252                 case svc_signonnum:
1253                         i = MSG_ReadByte ();
1254                         if (i <= cls.signon)
1255                                 Host_Error ("Received signon %i when at %i", i, cls.signon);
1256                         cls.signon = i;
1257                         CL_SignonReply ();
1258                         break;
1259
1260                 case svc_killedmonster:
1261                         cl.stats[STAT_MONSTERS]++;
1262                         break;
1263
1264                 case svc_foundsecret:
1265                         cl.stats[STAT_SECRETS]++;
1266                         break;
1267
1268                 case svc_updatestat:
1269                         i = MSG_ReadByte ();
1270                         if (i < 0 || i >= MAX_CL_STATS)
1271                                 Host_Error ("svc_updatestat: %i is invalid", i);
1272                         cl.stats[i] = MSG_ReadLong ();
1273                         break;
1274
1275                 case svc_spawnstaticsound:
1276                         CL_ParseStaticSound (false);
1277                         break;
1278
1279                 case svc_spawnstaticsound2:
1280                         CL_ParseStaticSound (true);
1281                         break;
1282
1283                 case svc_cdtrack:
1284                         cl.cdtrack = MSG_ReadByte ();
1285                         cl.looptrack = MSG_ReadByte ();
1286                         if ( (cls.demoplayback || cls.demorecording) && (cls.forcetrack != -1) )
1287                                 CDAudio_Play ((qbyte)cls.forcetrack, true);
1288                         else
1289                                 CDAudio_Play ((qbyte)cl.cdtrack, true);
1290                         break;
1291
1292                 case svc_intermission:
1293                         cl.intermission = 1;
1294                         cl.completed_time = cl.time;
1295                         break;
1296
1297                 case svc_finale:
1298                         cl.intermission = 2;
1299                         cl.completed_time = cl.time;
1300                         SCR_CenterPrint (MSG_ReadString ());
1301                         break;
1302
1303                 case svc_cutscene:
1304                         cl.intermission = 3;
1305                         cl.completed_time = cl.time;
1306                         SCR_CenterPrint (MSG_ReadString ());
1307                         break;
1308
1309                 case svc_sellscreen:
1310                         Cmd_ExecuteString ("help", src_command);
1311                         break;
1312                 case svc_hidelmp:
1313                         SHOWLMP_decodehide();
1314                         break;
1315                 case svc_showlmp:
1316                         SHOWLMP_decodeshow();
1317                         break;
1318                 case svc_skybox:
1319                         R_SetSkyBox(MSG_ReadString());
1320                         break;
1321                 case svc_cgame:
1322                         {
1323                                 int length;
1324                                 length = (int) ((unsigned short) MSG_ReadShort());
1325                                 for (i = 0;i < length;i++)
1326                                         cgamenetbuffer[i] = MSG_ReadByte();
1327                                 if (!msg_badread)
1328                                         CL_CGVM_ParseNetwork(cgamenetbuffer, length);
1329                         }
1330                         break;
1331                 case svc_entities:
1332                         if (cls.signon == SIGNONS - 1)
1333                         {
1334                                 // first update is the final signon stage
1335                                 cls.signon = SIGNONS;
1336                                 CL_SignonReply ();
1337                         }
1338                         CL_ReadEntityFrame();
1339                         break;
1340                 }
1341         }
1342
1343         if (entitiesupdated)
1344                 CL_EntityUpdateEnd();
1345 }
1346