2 Copyright (C) 1996-1997 Id Software, Inc.
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.
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.
13 See the GNU General Public License for more details.
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.
20 // cl_parse.c -- parse a message received from the server
24 char *svc_strings[128] =
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
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
53 "OBSOLETE svc_spawnbinary",
56 "svc_temp_entity", // <variable>
62 "svc_spawnstaticsound",
64 "svc_finale", // [string] music [string] text
65 "svc_cdtrack", // [byte] track [byte] looptrack
68 "svc_showlmp", // [string] iconlabel [string] lmpfile [short] x [short] y
69 "svc_hidelmp", // [string] iconlabel
70 "svc_skybox", // [string] skyname
85 "svc_effect", // [vector] org [byte] modelindex [byte] startframe [byte] framecount [byte] framerate
86 "svc_effect2", // [vector] org [short] modelindex [short] startframe [byte] framecount [byte] framerate
89 //=============================================================================
91 cvar_t demo_nehahra = {0, "demo_nehahra", "0"};
93 void CL_Parse_Init(void)
95 // LordHavoc: added demo_nehahra cvar
96 Cvar_RegisterVariable (&demo_nehahra);
97 if (gamemode == GAME_NEHAHRA)
98 Cvar_SetValue("demo_nehahra", 1);
101 qboolean Nehahrademcompatibility; // LordHavoc: to allow playback of the early Nehahra movie segments
102 qboolean dpprotocol; // LordHavoc: whether or not the current network stream is the enhanced DarkPlaces protocol
108 This error checks and tracks the total number of entities
111 entity_t *CL_EntityNum (int num)
114 if (num >= cl.num_entities)
116 if (num >= MAX_EDICTS)
117 Host_Error ("CL_EntityNum: %i is an invalid number",num);
118 cl.num_entities = num;
119 // while (cl.num_entities <= num)
121 // cl_entities[cl.num_entities].colormap = -1; // no special coloring
122 // cl.num_entities++;
126 if (num >= MAX_EDICTS)
127 Host_Error ("CL_EntityNum: %i is an invalid number",num);
129 return &cl_entities[num];
135 CL_ParseStartSoundPacket
138 void CL_ParseStartSoundPacket(int largesoundindex)
148 field_mask = MSG_ReadByte();
150 if (field_mask & SND_VOLUME)
151 volume = MSG_ReadByte ();
153 volume = DEFAULT_SOUND_PACKET_VOLUME;
155 if (field_mask & SND_ATTENUATION)
156 attenuation = MSG_ReadByte () / 64.0;
158 attenuation = DEFAULT_SOUND_PACKET_ATTENUATION;
160 channel = MSG_ReadShort ();
162 sound_num = (unsigned short) MSG_ReadShort ();
164 sound_num = MSG_ReadByte ();
166 if (sound_num >= MAX_SOUNDS)
167 Host_Error("CL_ParseStartSoundPacket: sound_num (%i) >= MAX_SOUNDS (%i)\n", sound_num, MAX_SOUNDS);
172 if (ent > MAX_EDICTS)
173 Host_Error ("CL_ParseStartSoundPacket: ent = %i", ent);
175 for (i=0 ; i<3 ; i++)
176 pos[i] = MSG_ReadCoord ();
178 S_StartSound (ent, channel, cl.sound_precache[sound_num], pos, volume/255.0, attenuation);
185 When the client is taking a long time to load stuff, send keepalive messages
186 so the server doesn't disconnect.
189 void CL_KeepaliveMessage (void)
192 static float lastmsg;
198 return; // no need if server is local
199 if (cls.demoplayback)
202 // read messages from server, should just be nops
204 memcpy (olddata, net_message.data, net_message.cursize);
208 ret = CL_GetMessage ();
212 Host_Error ("CL_KeepaliveMessage: CL_GetMessage failed");
214 break; // nothing waiting
216 Host_Error ("CL_KeepaliveMessage: received a message");
219 if (MSG_ReadByte() != svc_nop)
220 Host_Error ("CL_KeepaliveMessage: datagram wasn't a nop");
226 memcpy (net_message.data, olddata, net_message.cursize);
229 time = Sys_DoubleTime ();
230 if (time - lastmsg < 5)
235 Con_Printf ("--> client to server keepalive\n");
237 MSG_WriteByte (&cls.message, clc_nop);
238 NET_SendMessage (cls.netcon, &cls.message);
239 SZ_Clear (&cls.message);
242 //FIXME finish this code!
243 #define MAX_STATICLIGHTS 2048
245 #define LIGHTFADE_LMINUSX 0 // light, arghlite, others?
246 #define LIGHTFADE_LDIVX 1
247 #define LIGHTFADE_LDIVX2 2 // hlight
248 #define LIGHTFADE_L 3
249 #define LIGHTFADE_DEFAULT 999999 // light util not yet identified, switched later
253 int fadetype; // one of the LIGHTFADE_ values
256 vec_t radius; // the point at which lighting stops
258 vec_t cone; // if non-zero, it is a spot light
260 vec_t distancescale; // attenuation
261 vec_t lightsubtract; // biasing lighting toward black (hlight feature)
265 staticlight_t staticlight[MAX_STATICLIGHTS];
268 int r_sunlightenabled;
269 vec3_t r_sunlightdirection, r_sunlightcolor;
270 vec3_t r_light_ambientcolor;
272 void CL_ParseEntityLump(char *entdata)
275 char key[128], value[4096];
276 char targetnamebuffer[65536];
277 char *targetname[8192], *target[MAX_STATICLIGHTS], light_target[256];
278 vec3_t targetnameorigin[8192], targetnametemporigin, v;
279 int targets, targetnames, targetnamebufferpos, targetnameorigintofillin;
281 float f1, f2, f3, f4;
282 float ambientlight, ambientcolor[3], sunlight, sunlightdirection[3], sunlightcolor[3];
283 int light_fadetype, light_style, hlight, tyrlite, light_enable;
284 float light_origin[3], light_light, light_distancescale, light_lightcolor[3], light_color[3], light_direction[3], light_cone, light_lightradius;
285 FOG_clear(); // LordHavoc: no fog until set
286 R_SetSkyBox(""); // LordHavoc: no environment mapped sky until set
287 r_sunlightenabled = false;
292 data = COM_Parse(data);
295 if (com_token[0] != '{')
300 ambientcolor[0] = ambientcolor[1] = ambientcolor[2] = 1;
302 sunlightcolor[0] = sunlightcolor[1] = sunlightcolor[2] = 1;
303 sunlightdirection[0] = 0;
304 sunlightdirection[1] = 0;
305 sunlightdirection[2] = -1;
308 targetnamebufferpos = 0;
309 targetnameorigintofillin = -1;
310 targetnametemporigin[0] = 0;
311 targetnametemporigin[1] = 0;
312 targetnametemporigin[2] = 0;
315 data = COM_Parse(data);
318 if (com_token[0] == '}')
319 break; // end of worldspawn
320 if (com_token[0] == '_')
321 strcpy(key, com_token + 1);
323 strcpy(key, com_token);
324 while (key[strlen(key)-1] == ' ') // remove trailing spaces
325 key[strlen(key)-1] = 0;
326 data = COM_Parse(data);
329 strcpy(value, com_token);
330 if (!strcmp("sky", key))
332 else if (!strcmp("skyname", key)) // non-standard, introduced by QuakeForge... sigh.
334 else if (!strcmp("qlsky", key)) // non-standard, introduced by QuakeLives (EEK)
336 else if (!strcmp("fog", key))
337 scanf(value, "%f %f %f %f", &fog_density, &fog_red, &fog_green, &fog_blue);
338 else if (!strcmp("fog_density", key))
339 fog_density = atof(value);
340 else if (!strcmp("fog_red", key))
341 fog_red = atof(value);
342 else if (!strcmp("fog_green", key))
343 fog_green = atof(value);
344 else if (!strcmp("fog_blue", key))
345 fog_blue = atof(value);
346 else if (!strcmp("light", key))
347 ambientlight = atof(value);
348 else if (!strcmp("sunlight", key))
350 sunlight = atof(value);
353 else if (!strcmp("sun_color", key))
355 if (scanf(value, "%f %f %f", &v[0], &v[1], &v[2]) == 3)
356 VectorCopy(v, sunlightcolor);
359 else if (!strcmp("sun_mangle", key))
361 if (scanf(value, "%f %f %f", &v[0], &v[1], &v[2]) == 3)
362 AngleVectors(v, sunlightdirection, NULL, NULL);
365 else if (!strcmp("origin", key))
367 if (scanf(value, "%f %f %f", &v[0], &v[1], &v[2]) == 3)
369 VectorCopy(v, targetnametemporigin);
370 VectorCopy(v, light_origin);
373 else if (!strcmp("targetname", key))
375 if ((targetnames < 8192) && (strlen(value) + 1 + targetnamebufferpos <= 65536))
377 targetname[targetnames] = targetnamebuffer + targetnamebufferpos;
378 strcpy(targetnamebuffer + targetnamebufferpos, value);
379 targetnamebufferpos += strlen(value) + 1;
380 targetnameorigintofillin = targetnames++;
384 if (targetnameorigintofillin >= 0)
385 VectorCopy(targetnametemporigin, targetnameorigin[targetnameorigintofillin]);
389 r_sunlightenabled = true;
390 VectorScale(sunlightcolor, sunlight, r_sunlightcolor);
391 VectorCopy(sunlightdirection, r_sunlightdirection);
393 VectorScale(ambientcolor, ambientlight, r_light_ambientcolor);
397 data = COM_Parse(data);
400 if (com_token[0] != '{')
403 light_lightcolor[0] = light_lightcolor[1] = light_lightcolor[2] = 1.0f;
404 light_color[0] = light_color[1] = light_color[2] = 1.0f;
405 light_direction[0] = light_direction[1] = light_direction[2] = 0.0f;
406 light_cone = -cos(20*M_PI/180);
407 light_distancescale = 1.0f;
408 light_fadetype = LIGHTFADE_DEFAULT; // replaced later when light util is identified
410 light_lightradius = 0;
411 light_enable = false;
412 targetnameorigintofillin = -1;
413 targetnametemporigin[0] = 0;
414 targetnametemporigin[1] = 0;
415 targetnametemporigin[2] = 0;
418 data = COM_Parse(data);
421 if (com_token[0] == '}')
423 if (com_token[0] == '_')
424 strcpy(key, com_token + 1);
426 strcpy(key, com_token);
427 while (key[strlen(key)-1] == ' ') // remove trailing spaces
428 key[strlen(key)-1] = 0;
429 data = COM_Parse(data);
432 strcpy(value, com_token);
433 if (!strcmp("light", key))
435 n = scanf(value, "%f %f %f %f", &f1, &f2, &f3, &f4);
439 // id light, arghlite, tyrlite, others
441 light_lightcolor[0] = light_lightcolor[1] = light_lightcolor[2] = 1.0f;
444 // hlight specific (supports all 3 light formats, but this one is unique to it)
446 light_light = max(f1, max(f2, f3));
447 light_lightcolor[0] = f1 / light_light;
448 light_lightcolor[1] = f2 / light_light;
449 light_lightcolor[2] = f3 / light_light;
453 hlight = true; // unless this is a halflife map, probably hlight
455 light_lightcolor[0] = f1 * (1.0f / 255.0f);
456 light_lightcolor[1] = f1 * (1.0f / 255.0f);
457 light_lightcolor[2] = f1 * (1.0f / 255.0f);
464 else if (!strcmp("color", key))
466 n = scanf(value, "%f %f %f", &f1, &f2, &f3);
473 // n != 3 is an error
475 else if (!strcmp("wait", key))
476 light_distancescale = atof(value);
477 else if (!strcmp("delay", key))
479 light_fadetype = atoi(value);
482 else if (!strcmp("angle", key))
483 light_cone = -cos(atof(value) * M_PI / 360);
484 else if (!strcmp("mangle", key))
486 n = scanf(value, "%f %f %f", &v[0], &v[1], &v[2]);
488 AngleVectors(v, light_direction, NULL, NULL);
489 // n != 3 is an error
492 else if (!strcmp("style", key))
495 if (n >= 0 && n < MAX_LIGHTSTYLES)
498 else if (!strcmp("lightradius", key))
501 light_lightradius = atof(value);
503 else if (!strcmp("classname", key))
504 if (!strncmp(value, "light", 5))
506 else if (!strcmp("origin", key))
508 if (scanf(value, "%f %f %f", &v[0], &v[1], &v[2]) == 3)
509 VectorCopy(v, targetnametemporigin);
511 else if (!strcmp("targetname", key))
513 if ((targetnames < 8192) && (strlen(value) + 1 + targetnamebufferpos <= 65536))
515 targetname[targetnames] = targetnamebuffer + targetnamebufferpos;
516 strcpy(targetnamebuffer + targetnamebufferpos, value);
517 targetnamebufferpos += strlen(value) + 1;
518 targetnameorigintofillin = targetnames++;
521 else if (!strcmp("target", key))
522 if (strlen(value) < sizeof(light_target))
523 strcpy(light_target, value);
525 if (targetnameorigintofillin >= 0)
526 VectorCopy(targetnametemporigin, targetnameorigin[targetnameorigintofillin]);
527 if (light_enable && staticlights < MAX_STATICLIGHTS && light_light != 0)
529 VectorCopy(light_origin, staticlight[staticlights].origin);
530 staticlight[staticlights].color[0] = light_light * light_lightcolor[0] * light_color[0];
531 staticlight[staticlights].color[1] = light_light * light_lightcolor[1] * light_color[1];
532 staticlight[staticlights].color[2] = light_light * light_lightcolor[2] * light_color[2];
533 VectorCopy(light_direction, staticlight[staticlights].direction);
534 staticlight[staticlights].cone = light_cone;
535 staticlight[staticlights].distancescale = light_distancescale;
536 staticlight[staticlights].fadetype = light_fadetype;
537 staticlight[staticlights].style = light_style;
538 if (light_target && (targets < 8192) && (strlen(value) + 1 + targetnamebufferpos <= 65536))
540 target[staticlights] = targetnamebuffer + targetnamebufferpos;
541 strcpy(targetnamebuffer + targetnamebufferpos, value);
542 targetnamebufferpos += strlen(value) + 1;
545 target[staticlights] = NULL;
546 staticlight[staticlights].lightsubtract = 0;
547 if (light_lightradius)
549 staticlight[staticlights].fadetype = LIGHTFADE_LDIVX2;
550 staticlight[staticlights].lightsubtract = max(staticlight[staticlights].color[0], max(staticlight[staticlights].color[1], staticlight[staticlights].color[2])) * 0.5f / (light_lightradius * light_distancescale * light_lightradius * light_distancescale * (1.0f / 65536.0f) + 1.0f);
555 if (cl.worldmodel->ishlbsp)
556 n = LIGHTFADE_LDIVX2;
558 n = LIGHTFADE_LMINUSX;
560 n = LIGHTFADE_LDIVX2;
562 n = LIGHTFADE_LMINUSX;
563 for (i = 0;i < staticlights;i++)
565 if (staticlight[i].fadetype == LIGHTFADE_DEFAULT)
566 staticlight[i].fadetype = n;
569 for (j = 0;j < targetnames;j++)
571 if (!strcmp(target[i], targetname[j]))
573 VectorSubtract(targetnameorigin[j], staticlight[i].origin, v);
575 VectorCopy(v, staticlight[i].direction);
580 if (staticlight[i].direction[0] == 0 && staticlight[i].direction[1] == 0 && staticlight[i].direction[2] == 0)
581 staticlight[i].cone = 0;
586 =====================
589 An svc_signonnum has been received, perform a client side setup
590 =====================
592 static void CL_SignonReply (void)
596 Con_DPrintf ("CL_SignonReply: %i\n", cls.signon);
601 MSG_WriteByte (&cls.message, clc_stringcmd);
602 MSG_WriteString (&cls.message, "prespawn");
606 MSG_WriteByte (&cls.message, clc_stringcmd);
607 MSG_WriteString (&cls.message, va("name \"%s\"\n", cl_name.string));
609 MSG_WriteByte (&cls.message, clc_stringcmd);
610 MSG_WriteString (&cls.message, va("color %i %i\n", cl_color.integer >> 4, cl_color.integer & 15));
612 if (cl_pmodel.integer)
614 MSG_WriteByte (&cls.message, clc_stringcmd);
615 MSG_WriteString (&cls.message, va("pmodel %i\n", cl_pmodel.integer));
618 MSG_WriteByte (&cls.message, clc_stringcmd);
619 sprintf (str, "spawn %s", cls.spawnparms);
620 MSG_WriteString (&cls.message, str);
624 MSG_WriteByte (&cls.message, clc_stringcmd);
625 MSG_WriteString (&cls.message, "begin");
629 // SCR_EndLoadingPlaque (); // allow normal screen updates
640 void CL_ParseServerInfo (void)
644 int nummodels, numsounds;
645 char model_precache[MAX_MODELS][MAX_QPATH];
646 char sound_precache[MAX_SOUNDS][MAX_QPATH];
648 Con_DPrintf ("Serverinfo packet received.\n");
650 // wipe the client_state_t struct
654 // parse protocol version number
656 if (i != PROTOCOL_VERSION && i != DPPROTOCOL_VERSION && i != 250)
658 Con_Printf ("Server returned version %i, not %i or %i", i, DPPROTOCOL_VERSION, PROTOCOL_VERSION);
661 Nehahrademcompatibility = false;
663 Nehahrademcompatibility = true;
664 if (cls.demoplayback && demo_nehahra.integer)
665 Nehahrademcompatibility = true;
666 dpprotocol = i == DPPROTOCOL_VERSION;
669 cl.maxclients = MSG_ReadByte ();
670 if (cl.maxclients < 1 || cl.maxclients > MAX_SCOREBOARD)
672 Con_Printf("Bad maxclients (%u) from server\n", cl.maxclients);
675 cl.scores = Mem_Alloc(cl_scores_mempool, cl.maxclients*sizeof(*cl.scores));
678 cl.gametype = MSG_ReadByte ();
680 // parse signon message
681 str = MSG_ReadString ();
682 strncpy (cl.levelname, str, sizeof(cl.levelname)-1);
684 // seperate the printfs so the server message can have a color
685 if (!Nehahrademcompatibility) // no messages when playing the Nehahra movie
687 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");
688 Con_Printf ("%c%s\n", 2, str);
692 // first we go through and touch all of the precache data that still
693 // happens to be in the cache, so precaching something else doesn't
694 // needlessly purge it
697 Mem_CheckSentinelsGlobal();
701 Mem_CheckSentinelsGlobal();
704 memset (cl.model_precache, 0, sizeof(cl.model_precache));
705 for (nummodels=1 ; ; nummodels++)
707 str = MSG_ReadString ();
710 if (nummodels==MAX_MODELS)
712 Con_Printf ("Server sent too many model precaches\n");
715 if (strlen(str) >= MAX_QPATH)
716 Host_Error ("Server sent a precache name of %i characters (max %i)", strlen(str), MAX_QPATH - 1);
717 strcpy (model_precache[nummodels], str);
718 Mod_TouchModel (str);
722 memset (cl.sound_precache, 0, sizeof(cl.sound_precache));
723 for (numsounds=1 ; ; numsounds++)
725 str = MSG_ReadString ();
728 if (numsounds==MAX_SOUNDS)
730 Con_Printf ("Server sent too many sound precaches\n");
733 if (strlen(str) >= MAX_QPATH)
734 Host_Error ("Server sent a precache name of %i characters (max %i)", strlen(str), MAX_QPATH - 1);
735 strcpy (sound_precache[numsounds], str);
739 Mem_CheckSentinelsGlobal();
744 // now we try to load everything else until a cache allocation fails
747 Mem_CheckSentinelsGlobal();
749 for (i=1 ; i<nummodels ; i++)
751 // LordHavoc: i == 1 means the first model is the world model
752 cl.model_precache[i] = Mod_ForName (model_precache[i], false, true, i == 1);
754 if (cl.model_precache[i] == NULL)
756 Con_Printf("Model %s not found\n", model_precache[i]);
759 CL_KeepaliveMessage ();
762 Mem_CheckSentinelsGlobal();
764 S_BeginPrecaching ();
765 for (i=1 ; i<numsounds ; i++)
767 cl.sound_precache[i] = S_PrecacheSound (sound_precache[i]);
768 CL_KeepaliveMessage ();
773 cl_entities[0].render.model = cl.worldmodel = cl.model_precache[1];
774 cl_entities[0].render.scale = 1;
775 cl_entities[0].render.alpha = 1;
779 Mem_CheckSentinelsGlobal();
781 noclip_anglehack = false; // noclip is turned off at start
784 void CL_ValidateState(entity_state_t *s)
791 if (s->modelindex >= MAX_MODELS)
792 Host_Error("CL_ValidateState: modelindex (%i) >= MAX_MODELS (%i)\n", s->modelindex, MAX_MODELS);
794 // colormap is client index + 1
795 if (s->colormap > cl.maxclients)
796 Host_Error ("CL_ValidateState: colormap (%i) > cl.maxclients (%i)", s->colormap, cl.maxclients);
798 model = cl.model_precache[s->modelindex];
799 Mod_CheckLoaded(model);
800 if (model && s->frame >= model->numframes)
802 Con_Printf("CL_ValidateState: no such frame %i in \"%s\"\n", s->frame, model->name);
805 if (model && s->skin > 0 && s->skin >= model->numskins)
807 Con_Printf("CL_ValidateState: no such skin %i in \"%s\"\n", s->skin, model->name);
816 Parse an entity update message from the server
817 If an entities model or origin changes from frame to frame, it must be
818 relinked. Other attributes can change without relinking.
821 byte entkill[MAX_EDICTS];
822 int bitprofile[32], bitprofilecount = 0;
823 void CL_ParseUpdate (int bits)
825 int i, num, deltadie;
829 if (cls.signon == SIGNONS - 1)
830 { // first update is the final signon stage
831 cls.signon = SIGNONS;
835 if (bits & U_MOREBITS)
836 bits |= (MSG_ReadByte()<<8);
837 if ((bits & U_EXTEND1) && (!Nehahrademcompatibility))
839 bits |= MSG_ReadByte() << 16;
840 if (bits & U_EXTEND2)
841 bits |= MSG_ReadByte() << 24;
844 if (bits & U_LONGENTITY)
845 num = (unsigned) MSG_ReadShort ();
847 num = (unsigned) MSG_ReadByte ();
849 if (num >= MAX_EDICTS)
850 Host_Error("CL_ParseUpdate: entity number (%i) >= MAX_EDICTS (%i)\n", num, MAX_EDICTS);
852 Host_Error("CL_ParseUpdate: invalid entity number (%i)\n", num);
854 // mark as visible (no kill)
857 ent = CL_EntityNum (num);
859 for (i = 0;i < 32;i++)
867 new = ent->state_current;
869 deltadie = true; // was not present in previous frame, leave hidden until next full update
872 new = ent->state_baseline;
874 new.time = cl.mtime[0];
878 if (bits & U_MODEL) new.modelindex = (new.modelindex & 0xFF00) | MSG_ReadByte();
879 if (bits & U_FRAME) new.frame = (new.frame & 0xFF00) | MSG_ReadByte();
880 if (bits & U_COLORMAP) new.colormap = MSG_ReadByte();
881 if (bits & U_SKIN) new.skin = MSG_ReadByte();
882 if (bits & U_EFFECTS) new.effects = (new.effects & 0xFF00) | MSG_ReadByte();
883 if (bits & U_ORIGIN1) new.origin[0] = MSG_ReadCoord();
884 if (bits & U_ANGLE1) new.angles[0] = MSG_ReadAngle();
885 if (bits & U_ORIGIN2) new.origin[1] = MSG_ReadCoord();
886 if (bits & U_ANGLE2) new.angles[1] = MSG_ReadAngle();
887 if (bits & U_ORIGIN3) new.origin[2] = MSG_ReadCoord();
888 if (bits & U_ANGLE3) new.angles[2] = MSG_ReadAngle();
889 if (bits & U_STEP) new.flags |= RENDER_STEP;
890 if (bits & U_ALPHA) new.alpha = MSG_ReadByte();
891 if (bits & U_SCALE) new.scale = MSG_ReadByte();
892 if (bits & U_EFFECTS2) new.effects = (new.effects & 0x00FF) | (MSG_ReadByte() << 8);
893 if (bits & U_GLOWSIZE) new.glowsize = MSG_ReadByte();
894 if (bits & U_GLOWCOLOR) new.glowcolor = MSG_ReadByte();
896 if (bits & U_COLORMOD) {int i = MSG_ReadByte();float r = (((int) i >> 5) & 7) * 1.0 / 7, g = (((int) i >> 2) & 7) * 1.0 / 7, b = ((int) i & 3) * 1.0 / 3;Con_Printf("warning: U_COLORMOD %i (%1.2f %1.2f %1.2f) ignored\n", i, r, g, b);}
898 // apparently the dpcrush demo uses this (unintended, and it uses white anyway)
899 if (bits & U_COLORMOD) MSG_ReadByte();
901 if (bits & U_GLOWTRAIL) new.flags |= RENDER_GLOWTRAIL;
902 if (bits & U_FRAME2) new.frame = (new.frame & 0x00FF) | (MSG_ReadByte() << 8);
903 if (bits & U_MODEL2) new.modelindex = (new.modelindex & 0x00FF) | (MSG_ReadByte() << 8);
904 if (bits & U_VIEWMODEL) new.flags |= RENDER_VIEWMODEL;
905 if (bits & U_EXTERIORMODEL) new.flags |= RENDER_EXTERIORMODEL;
907 // LordHavoc: to allow playback of the Nehahra movie
908 if (Nehahrademcompatibility && (bits & U_EXTEND1))
910 // LordHavoc: evil format
911 int i = MSG_ReadFloat();
912 int j = MSG_ReadFloat() * 255.0f;
916 new.effects |= EF_FULLBRIGHT;
920 else if (j == 0 || j >= 255)
932 CL_ValidateState(&new);
934 if (new.flags & RENDER_STEP) // FIXME: rename this flag?
936 // make time identical for memcmp
937 new.time = ent->state_current.time;
938 if (memcmp(&new, &ent->state_current, sizeof(entity_state_t)))
941 ent->state_previous = ent->state_current;
942 ent->state_current = new;
943 // assume 10fps animation
944 ent->state_previous.time = cl.mtime[0];
945 ent->state_current.time = cl.mtime[0] + 0.1; //ent->state_previous.time + 0.1;
950 ent->state_previous = ent->state_current;
951 ent->state_current = new;
955 char *bitprofilenames[32] =
979 "obsolete U_COLORMOD",
991 void CL_BitProfile_f(void)
994 Con_Printf("bitprofile: %i updates\n");
996 for (i = 0;i < 32;i++)
997 // if (bitprofile[i])
998 Con_Printf("%s: %i %3.2f%%\n", bitprofilenames[i], bitprofile[i], bitprofile[i] * 100.0 / bitprofilecount);
1000 for (i = 0;i < 32;i++)
1002 bitprofilecount = 0;
1005 void CL_EntityUpdateSetup(void)
1007 memset(entkill, 1, MAX_EDICTS);
1010 void CL_EntityUpdateEnd(void)
1013 for (i = 1;i < MAX_EDICTS;i++)
1015 cl_entities[i].state_previous.active = cl_entities[i].state_current.active = 0;
1023 void CL_ParseBaseline (entity_t *ent, int large)
1027 memset(&ent->state_baseline, 0, sizeof(entity_state_t));
1028 ent->state_baseline.active = true;
1031 ent->state_baseline.modelindex = (unsigned short) MSG_ReadShort ();
1032 ent->state_baseline.frame = (unsigned short) MSG_ReadShort ();
1036 ent->state_baseline.modelindex = MSG_ReadByte ();
1037 ent->state_baseline.frame = MSG_ReadByte ();
1039 ent->state_baseline.colormap = MSG_ReadByte();
1040 ent->state_baseline.skin = MSG_ReadByte();
1041 for (i = 0;i < 3;i++)
1043 ent->state_baseline.origin[i] = MSG_ReadCoord ();
1044 ent->state_baseline.angles[i] = MSG_ReadAngle ();
1046 ent->state_baseline.alpha = 255;
1047 ent->state_baseline.scale = 16;
1048 ent->state_baseline.glowsize = 0;
1049 ent->state_baseline.glowcolor = 254;
1050 ent->state_previous = ent->state_current = ent->state_baseline;
1052 CL_ValidateState(&ent->state_baseline);
1060 Server information pertaining to this client only
1063 void CL_ParseClientdata (int bits)
1068 if (bits & SU_EXTEND1)
1069 bits |= (MSG_ReadByte() << 16);
1070 if (bits & SU_EXTEND2)
1071 bits |= (MSG_ReadByte() << 24);
1073 if (bits & SU_VIEWHEIGHT)
1074 cl.viewheight = MSG_ReadChar ();
1076 cl.viewheight = DEFAULT_VIEWHEIGHT;
1078 if (bits & SU_IDEALPITCH)
1079 cl.idealpitch = MSG_ReadChar ();
1083 VectorCopy (cl.mvelocity[0], cl.mvelocity[1]);
1084 for (i=0 ; i<3 ; i++)
1086 if (bits & (SU_PUNCH1<<i) )
1089 cl.punchangle[i] = MSG_ReadPreciseAngle();
1091 cl.punchangle[i] = MSG_ReadChar();
1094 cl.punchangle[i] = 0;
1095 if (bits & (SU_PUNCHVEC1<<i))
1096 cl.punchvector[i] = MSG_ReadFloatCoord();
1098 cl.punchvector[i] = 0;
1099 if (bits & (SU_VELOCITY1<<i) )
1100 cl.mvelocity[0][i] = MSG_ReadChar()*16;
1102 cl.mvelocity[0][i] = 0;
1105 i = MSG_ReadLong ();
1107 { // set flash times
1108 for (j=0 ; j<32 ; j++)
1109 if ( (i & (1<<j)) && !(cl.items & (1<<j)))
1110 cl.item_gettime[j] = cl.time;
1114 cl.onground = (bits & SU_ONGROUND) != 0;
1115 cl.inwater = (bits & SU_INWATER) != 0;
1117 cl.stats[STAT_WEAPONFRAME] = (bits & SU_WEAPONFRAME) ? MSG_ReadByte() : 0;
1118 cl.stats[STAT_ARMOR] = (bits & SU_ARMOR) ? MSG_ReadByte() : 0;
1119 cl.stats[STAT_WEAPON] = (bits & SU_WEAPON) ? MSG_ReadByte() : 0;
1120 cl.stats[STAT_HEALTH] = MSG_ReadShort();
1121 cl.stats[STAT_AMMO] = MSG_ReadByte();
1123 cl.stats[STAT_SHELLS] = MSG_ReadByte();
1124 cl.stats[STAT_NAILS] = MSG_ReadByte();
1125 cl.stats[STAT_ROCKETS] = MSG_ReadByte();
1126 cl.stats[STAT_CELLS] = MSG_ReadByte();
1128 i = MSG_ReadByte ();
1130 if (gamemode == GAME_HIPNOTIC || gamemode == GAME_ROGUE)
1131 cl.stats[STAT_ACTIVEWEAPON] = (1<<i);
1133 cl.stats[STAT_ACTIVEWEAPON] = i;
1137 =====================
1139 =====================
1141 void CL_ParseStatic (int large)
1145 if (cl.num_statics >= MAX_STATIC_ENTITIES)
1146 Host_Error ("Too many static entities");
1147 ent = &cl_static_entities[cl.num_statics++];
1148 CL_ParseBaseline (ent, large);
1150 // copy it to the current state
1151 ent->render.model = cl.model_precache[ent->state_baseline.modelindex];
1152 ent->render.frame = ent->render.frame1 = ent->render.frame2 = ent->state_baseline.frame;
1153 ent->render.framelerp = 0;
1154 // make torchs play out of sync
1155 ent->render.frame1time = ent->render.frame2time = lhrandom(-10, -1);
1156 ent->render.colormap = -1; // no special coloring
1157 ent->render.skinnum = ent->state_baseline.skin;
1158 ent->render.effects = ent->state_baseline.effects;
1159 ent->render.alpha = 1;
1160 ent->render.scale = 1;
1161 ent->render.alpha = 1;
1163 VectorCopy (ent->state_baseline.origin, ent->render.origin);
1164 VectorCopy (ent->state_baseline.angles, ent->render.angles);
1172 void CL_ParseStaticSound (int large)
1175 int sound_num, vol, atten;
1177 MSG_ReadVector(org);
1179 sound_num = (unsigned short) MSG_ReadShort ();
1181 sound_num = MSG_ReadByte ();
1182 vol = MSG_ReadByte ();
1183 atten = MSG_ReadByte ();
1185 S_StaticSound (cl.sound_precache[sound_num], org, vol, atten);
1188 void CL_ParseEffect (void)
1191 int modelindex, startframe, framecount, framerate;
1193 MSG_ReadVector(org);
1194 modelindex = MSG_ReadByte ();
1195 startframe = MSG_ReadByte ();
1196 framecount = MSG_ReadByte ();
1197 framerate = MSG_ReadByte ();
1199 CL_Effect(org, modelindex, startframe, framecount, framerate);
1202 void CL_ParseEffect2 (void)
1205 int modelindex, startframe, framecount, framerate;
1207 MSG_ReadVector(org);
1208 modelindex = MSG_ReadShort ();
1209 startframe = MSG_ReadShort ();
1210 framecount = MSG_ReadByte ();
1211 framerate = MSG_ReadByte ();
1213 CL_Effect(org, modelindex, startframe, framecount, framerate);
1217 #define SHOWNET(x) if(cl_shownet.integer==2)Con_Printf ("%3i:%s\n", msg_readcount-1, x);
1220 =====================
1221 CL_ParseServerMessage
1222 =====================
1224 void CL_ParseServerMessage (void)
1227 int i, entitiesupdated;
1229 char *cmdlogname[32], *temp;
1230 int cmdindex, cmdcount = 0;
1233 // if recording demos, copy the message out
1235 if (cl_shownet.integer == 1)
1236 Con_Printf ("%i ",net_message.cursize);
1237 else if (cl_shownet.integer == 2)
1238 Con_Printf ("------------------\n");
1240 cl.onground = false; // unless the server says otherwise
1242 // parse the message
1244 MSG_BeginReading ();
1246 entitiesupdated = false;
1247 CL_EntityUpdateSetup();
1252 Host_Error ("CL_ParseServerMessage: Bad server message");
1254 cmd = MSG_ReadByte ();
1258 SHOWNET("END OF MESSAGE");
1259 break; // end of message
1262 cmdindex = cmdcount & 31;
1264 cmdlog[cmdindex] = cmd;
1266 // if the high bit of the command byte is set, it is a fast update
1269 // 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)
1271 cmdlogname[cmdindex] = temp;
1272 SHOWNET("fast update");
1273 CL_ParseUpdate (cmd&127);
1277 SHOWNET(svc_strings[cmd]);
1278 cmdlogname[cmdindex] = svc_strings[cmd];
1279 if (!cmdlogname[cmdindex])
1281 // 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)
1283 cmdlogname[cmdindex] = temp;
1291 char description[32*64], temp[64];
1293 strcpy(description, "packet dump: ");
1297 count = cmdcount - i;
1301 sprintf(temp, "%3i:%s ", cmdlog[i], cmdlogname[i]);
1302 strcat(description, temp);
1307 description[strlen(description)-1] = '\n'; // replace the last space with a newline
1308 Con_Printf("%s", description);
1309 Host_Error ("CL_ParseServerMessage: Illegible server message\n");
1314 // Con_Printf ("svc_nop\n");
1318 // handle old protocols which do not have entity update ranges
1319 entitiesupdated = true;
1320 cl.mtime[1] = cl.mtime[0];
1321 cl.mtime[0] = MSG_ReadFloat ();
1324 case svc_clientdata:
1325 i = MSG_ReadShort ();
1326 CL_ParseClientdata (i);
1330 i = MSG_ReadLong ();
1331 if (i != PROTOCOL_VERSION && i != DPPROTOCOL_VERSION && i != 250)
1332 Host_Error ("CL_ParseServerMessage: Server is protocol %i, not %i or %i", i, DPPROTOCOL_VERSION, PROTOCOL_VERSION);
1333 Nehahrademcompatibility = false;
1335 Nehahrademcompatibility = true;
1336 if (cls.demoplayback && demo_nehahra.integer)
1337 Nehahrademcompatibility = true;
1338 dpprotocol = i == DPPROTOCOL_VERSION;
1341 case svc_disconnect:
1342 Host_EndGame ("Server disconnected\n");
1345 Con_Printf ("%s", MSG_ReadString ());
1348 case svc_centerprint:
1349 SCR_CenterPrint (MSG_ReadString ());
1353 Cbuf_AddText (MSG_ReadString ());
1360 case svc_serverinfo:
1361 CL_ParseServerInfo ();
1362 // vid.recalc_refdef = true; // leave intermission full screen
1366 for (i=0 ; i<3 ; i++)
1367 cl.viewangles[i] = MSG_ReadAngle ();
1371 cl.viewentity = MSG_ReadShort ();
1374 case svc_lightstyle:
1375 i = MSG_ReadByte ();
1376 if (i >= MAX_LIGHTSTYLES)
1377 Host_Error ("svc_lightstyle >= MAX_LIGHTSTYLES");
1378 strncpy (cl_lightstyle[i].map, MSG_ReadString(), MAX_STYLESTRING - 1);
1379 cl_lightstyle[i].map[MAX_STYLESTRING - 1] = 0;
1380 cl_lightstyle[i].length = strlen(cl_lightstyle[i].map);
1384 CL_ParseStartSoundPacket(false);
1388 CL_ParseStartSoundPacket(true);
1392 i = MSG_ReadShort();
1393 S_StopSound(i>>3, i&7);
1396 case svc_updatename:
1397 i = MSG_ReadByte ();
1398 if (i >= cl.maxclients)
1399 Host_Error ("CL_ParseServerMessage: svc_updatename >= MAX_SCOREBOARD");
1400 strcpy (cl.scores[i].name, MSG_ReadString ());
1403 case svc_updatefrags:
1404 i = MSG_ReadByte ();
1405 if (i >= cl.maxclients)
1406 Host_Error ("CL_ParseServerMessage: svc_updatefrags >= MAX_SCOREBOARD");
1407 cl.scores[i].frags = MSG_ReadShort ();
1410 case svc_updatecolors:
1411 i = MSG_ReadByte ();
1412 if (i >= cl.maxclients)
1413 Host_Error ("CL_ParseServerMessage: svc_updatecolors >= MAX_SCOREBOARD");
1414 cl.scores[i].colors = MSG_ReadByte ();
1418 CL_ParseParticleEffect ();
1429 case svc_spawnbaseline:
1430 i = MSG_ReadShort ();
1431 // must use CL_EntityNum() to force cl.num_entities up
1432 CL_ParseBaseline (CL_EntityNum(i), false);
1434 case svc_spawnbaseline2:
1435 i = MSG_ReadShort ();
1436 // must use CL_EntityNum() to force cl.num_entities up
1437 CL_ParseBaseline (CL_EntityNum(i), true);
1439 case svc_spawnstatic:
1440 CL_ParseStatic (false);
1442 case svc_spawnstatic2:
1443 CL_ParseStatic (true);
1445 case svc_temp_entity:
1450 cl.paused = MSG_ReadByte ();
1458 i = MSG_ReadByte ();
1459 if (i <= cls.signon)
1460 Host_Error ("Received signon %i when at %i", i, cls.signon);
1465 case svc_killedmonster:
1466 cl.stats[STAT_MONSTERS]++;
1469 case svc_foundsecret:
1470 cl.stats[STAT_SECRETS]++;
1473 case svc_updatestat:
1474 i = MSG_ReadByte ();
1475 if (i < 0 || i >= MAX_CL_STATS)
1476 Host_Error ("svc_updatestat: %i is invalid", i);
1477 cl.stats[i] = MSG_ReadLong ();
1480 case svc_spawnstaticsound:
1481 CL_ParseStaticSound (false);
1484 case svc_spawnstaticsound2:
1485 CL_ParseStaticSound (true);
1489 cl.cdtrack = MSG_ReadByte ();
1490 cl.looptrack = MSG_ReadByte ();
1491 if ( (cls.demoplayback || cls.demorecording) && (cls.forcetrack != -1) )
1492 CDAudio_Play ((byte)cls.forcetrack, true);
1494 CDAudio_Play ((byte)cl.cdtrack, true);
1497 case svc_intermission:
1498 cl.intermission = 1;
1499 cl.completed_time = cl.time;
1500 // vid.recalc_refdef = true; // go to full screen
1504 cl.intermission = 2;
1505 cl.completed_time = cl.time;
1506 // vid.recalc_refdef = true; // go to full screen
1507 SCR_CenterPrint (MSG_ReadString ());
1511 cl.intermission = 3;
1512 cl.completed_time = cl.time;
1513 // vid.recalc_refdef = true; // go to full screen
1514 SCR_CenterPrint (MSG_ReadString ());
1517 case svc_sellscreen:
1518 Cmd_ExecuteString ("help", src_command);
1521 SHOWLMP_decodehide();
1524 SHOWLMP_decodeshow();
1527 R_SetSkyBox(MSG_ReadString());
1532 if (entitiesupdated)
1533 CL_EntityUpdateEnd();