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
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
70 //=============================================================================
76 This error checks and tracks the total number of entities
79 entity_t
*CL_EntityNum (int num
)
81 if (num
>= cl
.num_entities
)
83 if (num
>= MAX_EDICTS
)
84 Host_Error ("CL_EntityNum: %i is an invalid number",num
);
85 while (cl
.num_entities
<=num
)
87 cl_entities
[cl
.num_entities
].colormap
= vid
.colormap
;
92 return &cl_entities
[num
];
98 CL_ParseStartSoundPacket
101 void CL_ParseStartSoundPacket(void)
111 field_mask
= MSG_ReadByte();
113 if (field_mask
& SND_VOLUME
)
114 volume
= MSG_ReadByte ();
116 volume
= DEFAULT_SOUND_PACKET_VOLUME
;
118 if (field_mask
& SND_ATTENUATION
)
119 attenuation
= MSG_ReadByte () / 64.0;
121 attenuation
= DEFAULT_SOUND_PACKET_ATTENUATION
;
123 channel
= MSG_ReadShort ();
124 sound_num
= MSG_ReadByte ();
129 if (ent
> MAX_EDICTS
)
130 Host_Error ("CL_ParseStartSoundPacket: ent = %i", ent
);
132 for (i
=0 ; i
<3 ; i
++)
133 pos
[i
] = MSG_ReadCoord ();
135 S_StartSound (ent
, channel
, cl
.sound_precache
[sound_num
], pos
, volume
/255.0, attenuation
);
142 When the client is taking a long time to load stuff, send keepalive messages
143 so the server doesn't disconnect.
146 void CL_KeepaliveMessage (void)
149 static float lastmsg
;
155 return; // no need if server is local
156 if (cls
.demoplayback
)
159 // read messages from server, should just be nops
161 memcpy (olddata
, net_message
.data
, net_message
.cursize
);
165 ret
= CL_GetMessage ();
169 Host_Error ("CL_KeepaliveMessage: CL_GetMessage failed");
171 break; // nothing waiting
173 Host_Error ("CL_KeepaliveMessage: received a message");
176 if (MSG_ReadByte() != svc_nop
)
177 Host_Error ("CL_KeepaliveMessage: datagram wasn't a nop");
183 memcpy (net_message
.data
, olddata
, net_message
.cursize
);
186 time
= Sys_FloatTime ();
187 if (time
- lastmsg
< 5)
192 Con_Printf ("--> client to server keepalive\n");
194 MSG_WriteByte (&cls
.message
, clc_nop
);
195 NET_SendMessage (cls
.netcon
, &cls
.message
);
196 SZ_Clear (&cls
.message
);
204 void CL_ParseServerInfo (void)
208 int nummodels
, numsounds
;
209 char model_precache
[MAX_MODELS
][MAX_QPATH
];
210 char sound_precache
[MAX_SOUNDS
][MAX_QPATH
];
212 Con_DPrintf ("Serverinfo packet received.\n");
214 // wipe the client_state_t struct
218 // parse protocol version number
220 if (i
!= PROTOCOL_VERSION
)
222 Con_Printf ("Server returned version %i, not %i", i
, PROTOCOL_VERSION
);
227 cl
.maxclients
= MSG_ReadByte ();
228 if (cl
.maxclients
< 1 || cl
.maxclients
> MAX_SCOREBOARD
)
230 Con_Printf("Bad maxclients (%u) from server\n", cl
.maxclients
);
233 cl
.scores
= Hunk_AllocName (cl
.maxclients
*sizeof(*cl
.scores
), "scores");
236 cl
.gametype
= MSG_ReadByte ();
238 // parse signon message
239 str
= MSG_ReadString ();
240 strncpy (cl
.levelname
, str
, sizeof(cl
.levelname
)-1);
242 // seperate the printfs so the server message can have a color
243 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");
244 Con_Printf ("%c%s\n", 2, str
);
247 // first we go through and touch all of the precache data that still
248 // happens to be in the cache, so precaching something else doesn't
249 // needlessly purge it
253 memset (cl
.model_precache
, 0, sizeof(cl
.model_precache
));
254 for (nummodels
=1 ; ; nummodels
++)
256 str
= MSG_ReadString ();
259 if (nummodels
==MAX_MODELS
)
261 Con_Printf ("Server sent too many model precaches\n");
264 strcpy (model_precache
[nummodels
], str
);
265 Mod_TouchModel (str
);
269 memset (cl
.sound_precache
, 0, sizeof(cl
.sound_precache
));
270 for (numsounds
=1 ; ; numsounds
++)
272 str
= MSG_ReadString ();
275 if (numsounds
==MAX_SOUNDS
)
277 Con_Printf ("Server sent too many sound precaches\n");
280 strcpy (sound_precache
[numsounds
], str
);
285 // now we try to load everything else until a cache allocation fails
288 for (i
=1 ; i
<nummodels
; i
++)
290 cl
.model_precache
[i
] = Mod_ForName (model_precache
[i
], false);
291 if (cl
.model_precache
[i
] == NULL
)
293 Con_Printf("Model %s not found\n", model_precache
[i
]);
296 CL_KeepaliveMessage ();
299 S_BeginPrecaching ();
300 for (i
=1 ; i
<numsounds
; i
++)
302 cl
.sound_precache
[i
] = S_PrecacheSound (sound_precache
[i
]);
303 CL_KeepaliveMessage ();
309 cl_entities
[0].model
= cl
.worldmodel
= cl
.model_precache
[1];
313 Hunk_Check (); // make sure nothing is hurt
315 noclip_anglehack
= false; // noclip is turned off at start
323 Parse an entity update message from the server
324 If an entities model or origin changes from frame to frame, it must be
325 relinked. Other attributes can change without relinking.
330 void CL_ParseUpdate (int bits
)
342 if (cls
.signon
== SIGNONS
- 1)
343 { // first update is the final signon stage
344 cls
.signon
= SIGNONS
;
348 if (bits
& U_MOREBITS
)
354 if (bits
& U_LONGENTITY
)
355 num
= MSG_ReadShort ();
357 num
= MSG_ReadByte ();
359 ent
= CL_EntityNum (num
);
361 for (i
=0 ; i
<16 ; i
++)
365 if (ent
->msgtime
!= cl
.mtime
[1])
366 forcelink
= true; // no previous frame to lerp from
370 ent
->msgtime
= cl
.mtime
[0];
374 modnum
= MSG_ReadByte ();
375 if (modnum
>= MAX_MODELS
)
376 Host_Error ("CL_ParseModel: bad modnum");
379 modnum
= ent
->baseline
.modelindex
;
381 model
= cl
.model_precache
[modnum
];
382 if (model
!= ent
->model
)
385 // automatic animation (torches, etc) can be either all together
389 if (model
->synctype
== ST_RAND
)
390 ent
->syncbase
= (float)(rand()&0x7fff) / 0x7fff;
395 forcelink
= true; // hack to make null model players work
397 if (num
> 0 && num
<= cl
.maxclients
)
398 R_TranslatePlayerSkin (num
- 1);
403 ent
->frame
= MSG_ReadByte ();
405 ent
->frame
= ent
->baseline
.frame
;
407 if (bits
& U_COLORMAP
)
410 i
= ent
->baseline
.colormap
;
412 ent
->colormap
= vid
.colormap
;
415 if (i
> cl
.maxclients
)
416 Sys_Error ("i >= cl.maxclients");
417 ent
->colormap
= cl
.scores
[i
-1].translations
;
422 skin
= MSG_ReadByte();
424 skin
= ent
->baseline
.skin
;
425 if (skin
!= ent
->skinnum
) {
427 if (num
> 0 && num
<= cl
.maxclients
)
428 R_TranslatePlayerSkin (num
- 1);
434 ent
->skinnum
= MSG_ReadByte();
436 ent
->skinnum
= ent
->baseline
.skin
;
439 if (bits
& U_EFFECTS
)
440 ent
->effects
= MSG_ReadByte();
442 ent
->effects
= ent
->baseline
.effects
;
444 // shift the known values for interpolation
445 VectorCopy (ent
->msg_origins
[0], ent
->msg_origins
[1]);
446 VectorCopy (ent
->msg_angles
[0], ent
->msg_angles
[1]);
448 if (bits
& U_ORIGIN1
)
449 ent
->msg_origins
[0][0] = MSG_ReadCoord ();
451 ent
->msg_origins
[0][0] = ent
->baseline
.origin
[0];
453 ent
->msg_angles
[0][0] = MSG_ReadAngle();
455 ent
->msg_angles
[0][0] = ent
->baseline
.angles
[0];
457 if (bits
& U_ORIGIN2
)
458 ent
->msg_origins
[0][1] = MSG_ReadCoord ();
460 ent
->msg_origins
[0][1] = ent
->baseline
.origin
[1];
462 ent
->msg_angles
[0][1] = MSG_ReadAngle();
464 ent
->msg_angles
[0][1] = ent
->baseline
.angles
[1];
466 if (bits
& U_ORIGIN3
)
467 ent
->msg_origins
[0][2] = MSG_ReadCoord ();
469 ent
->msg_origins
[0][2] = ent
->baseline
.origin
[2];
471 ent
->msg_angles
[0][2] = MSG_ReadAngle();
473 ent
->msg_angles
[0][2] = ent
->baseline
.angles
[2];
475 if ( bits
& U_NOLERP
)
476 ent
->forcelink
= true;
479 { // didn't have an update last message
480 VectorCopy (ent
->msg_origins
[0], ent
->msg_origins
[1]);
481 VectorCopy (ent
->msg_origins
[0], ent
->origin
);
482 VectorCopy (ent
->msg_angles
[0], ent
->msg_angles
[1]);
483 VectorCopy (ent
->msg_angles
[0], ent
->angles
);
484 ent
->forcelink
= true;
493 void CL_ParseBaseline (entity_t
*ent
)
497 ent
->baseline
.modelindex
= MSG_ReadByte ();
498 ent
->baseline
.frame
= MSG_ReadByte ();
499 ent
->baseline
.colormap
= MSG_ReadByte();
500 ent
->baseline
.skin
= MSG_ReadByte();
501 for (i
=0 ; i
<3 ; i
++)
503 ent
->baseline
.origin
[i
] = MSG_ReadCoord ();
504 ent
->baseline
.angles
[i
] = MSG_ReadAngle ();
513 Server information pertaining to this client only
516 void CL_ParseClientdata (int bits
)
520 if (bits
& SU_VIEWHEIGHT
)
521 cl
.viewheight
= MSG_ReadChar ();
523 cl
.viewheight
= DEFAULT_VIEWHEIGHT
;
525 if (bits
& SU_IDEALPITCH
)
526 cl
.idealpitch
= MSG_ReadChar ();
530 VectorCopy (cl
.mvelocity
[0], cl
.mvelocity
[1]);
531 for (i
=0 ; i
<3 ; i
++)
533 if (bits
& (SU_PUNCH1
<<i
) )
534 cl
.punchangle
[i
] = MSG_ReadChar();
536 cl
.punchangle
[i
] = 0;
537 if (bits
& (SU_VELOCITY1
<<i
) )
538 cl
.mvelocity
[0][i
] = MSG_ReadChar()*16;
540 cl
.mvelocity
[0][i
] = 0;
543 // [always sent] if (bits & SU_ITEMS)
549 for (j
=0 ; j
<32 ; j
++)
550 if ( (i
& (1<<j
)) && !(cl
.items
& (1<<j
)))
551 cl
.item_gettime
[j
] = cl
.time
;
555 cl
.onground
= (bits
& SU_ONGROUND
) != 0;
556 cl
.inwater
= (bits
& SU_INWATER
) != 0;
558 if (bits
& SU_WEAPONFRAME
)
559 cl
.stats
[STAT_WEAPONFRAME
] = MSG_ReadByte ();
561 cl
.stats
[STAT_WEAPONFRAME
] = 0;
567 if (cl
.stats
[STAT_ARMOR
] != i
)
569 cl
.stats
[STAT_ARMOR
] = i
;
573 if (bits
& SU_WEAPON
)
577 if (cl
.stats
[STAT_WEAPON
] != i
)
579 cl
.stats
[STAT_WEAPON
] = i
;
583 i
= MSG_ReadShort ();
584 if (cl
.stats
[STAT_HEALTH
] != i
)
586 cl
.stats
[STAT_HEALTH
] = i
;
591 if (cl
.stats
[STAT_AMMO
] != i
)
593 cl
.stats
[STAT_AMMO
] = i
;
597 for (i
=0 ; i
<4 ; i
++)
600 if (cl
.stats
[STAT_SHELLS
+i
] != j
)
602 cl
.stats
[STAT_SHELLS
+i
] = j
;
611 if (cl
.stats
[STAT_ACTIVEWEAPON
] != i
)
613 cl
.stats
[STAT_ACTIVEWEAPON
] = i
;
619 if (cl
.stats
[STAT_ACTIVEWEAPON
] != (1<<i
))
621 cl
.stats
[STAT_ACTIVEWEAPON
] = (1<<i
);
628 =====================
630 =====================
632 void CL_NewTranslation (int slot
)
638 if (slot
> cl
.maxclients
)
639 Sys_Error ("CL_NewTranslation: slot > cl.maxclients");
640 dest
= cl
.scores
[slot
].translations
;
641 source
= vid
.colormap
;
642 memcpy (dest
, vid
.colormap
, sizeof(cl
.scores
[slot
].translations
));
643 top
= cl
.scores
[slot
].colors
& 0xf0;
644 bottom
= (cl
.scores
[slot
].colors
&15)<<4;
646 R_TranslatePlayerSkin (slot
);
649 for (i
=0 ; i
<VID_GRADES
; i
++, dest
+= 256, source
+=256)
651 if (top
< 128) // the artists made some backwards ranges. sigh.
652 memcpy (dest
+ TOP_RANGE
, source
+ top
, 16);
654 for (j
=0 ; j
<16 ; j
++)
655 dest
[TOP_RANGE
+j
] = source
[top
+15-j
];
658 memcpy (dest
+ BOTTOM_RANGE
, source
+ bottom
, 16);
660 for (j
=0 ; j
<16 ; j
++)
661 dest
[BOTTOM_RANGE
+j
] = source
[bottom
+15-j
];
666 =====================
668 =====================
670 void CL_ParseStatic (void)
676 if (i
>= MAX_STATIC_ENTITIES
)
677 Host_Error ("Too many static entities");
678 ent
= &cl_static_entities
[i
];
680 CL_ParseBaseline (ent
);
682 // copy it to the current state
683 ent
->model
= cl
.model_precache
[ent
->baseline
.modelindex
];
684 ent
->frame
= ent
->baseline
.frame
;
685 ent
->colormap
= vid
.colormap
;
686 ent
->skinnum
= ent
->baseline
.skin
;
687 ent
->effects
= ent
->baseline
.effects
;
689 VectorCopy (ent
->baseline
.origin
, ent
->origin
);
690 VectorCopy (ent
->baseline
.angles
, ent
->angles
);
699 void CL_ParseStaticSound (void)
702 int sound_num
, vol
, atten
;
705 for (i
=0 ; i
<3 ; i
++)
706 org
[i
] = MSG_ReadCoord ();
707 sound_num
= MSG_ReadByte ();
708 vol
= MSG_ReadByte ();
709 atten
= MSG_ReadByte ();
711 S_StaticSound (cl
.sound_precache
[sound_num
], org
, vol
, atten
);
715 #define SHOWNET(x) if(cl_shownet.value==2)Con_Printf ("%3i:%s\n", msg_readcount-1, x);
718 =====================
719 CL_ParseServerMessage
720 =====================
722 void CL_ParseServerMessage (void)
728 // if recording demos, copy the message out
730 if (cl_shownet
.value
== 1)
731 Con_Printf ("%i ",net_message
.cursize
);
732 else if (cl_shownet
.value
== 2)
733 Con_Printf ("------------------\n");
735 cl
.onground
= false; // unless the server says otherwise
744 Host_Error ("CL_ParseServerMessage: Bad server message");
746 cmd
= MSG_ReadByte ();
750 SHOWNET("END OF MESSAGE");
751 return; // end of message
754 // if the high bit of the command byte is set, it is a fast update
757 SHOWNET("fast update");
758 CL_ParseUpdate (cmd
&127);
762 SHOWNET(svc_strings
[cmd
]);
768 Host_Error ("CL_ParseServerMessage: Illegible server message\n");
772 // Con_Printf ("svc_nop\n");
776 cl
.mtime
[1] = cl
.mtime
[0];
777 cl
.mtime
[0] = MSG_ReadFloat ();
781 i
= MSG_ReadShort ();
782 CL_ParseClientdata (i
);
787 if (i
!= PROTOCOL_VERSION
)
788 Host_Error ("CL_ParseServerMessage: Server is protocol %i instead of %i\n", i
, PROTOCOL_VERSION
);
792 Host_EndGame ("Server disconnected\n");
795 Con_Printf ("%s", MSG_ReadString ());
798 case svc_centerprint
:
799 SCR_CenterPrint (MSG_ReadString ());
803 Cbuf_AddText (MSG_ReadString ());
811 CL_ParseServerInfo ();
812 vid
.recalc_refdef
= true; // leave intermission full screen
816 for (i
=0 ; i
<3 ; i
++)
817 cl
.viewangles
[i
] = MSG_ReadAngle ();
821 cl
.viewentity
= MSG_ReadShort ();
826 if (i
>= MAX_LIGHTSTYLES
)
827 Sys_Error ("svc_lightstyle > MAX_LIGHTSTYLES");
828 Q_strcpy (cl_lightstyle
[i
].map
, MSG_ReadString());
829 cl_lightstyle
[i
].length
= Q_strlen(cl_lightstyle
[i
].map
);
833 CL_ParseStartSoundPacket();
838 S_StopSound(i
>>3, i
&7);
844 if (i
>= cl
.maxclients
)
845 Host_Error ("CL_ParseServerMessage: svc_updatename > MAX_SCOREBOARD");
846 strcpy (cl
.scores
[i
].name
, MSG_ReadString ());
849 case svc_updatefrags
:
852 if (i
>= cl
.maxclients
)
853 Host_Error ("CL_ParseServerMessage: svc_updatefrags > MAX_SCOREBOARD");
854 cl
.scores
[i
].frags
= MSG_ReadShort ();
857 case svc_updatecolors
:
860 if (i
>= cl
.maxclients
)
861 Host_Error ("CL_ParseServerMessage: svc_updatecolors > MAX_SCOREBOARD");
862 cl
.scores
[i
].colors
= MSG_ReadByte ();
863 CL_NewTranslation (i
);
867 R_ParseParticleEffect ();
870 case svc_spawnbaseline
:
871 i
= MSG_ReadShort ();
872 // must use CL_EntityNum() to force cl.num_entities up
873 CL_ParseBaseline (CL_EntityNum(i
));
875 case svc_spawnstatic
:
878 case svc_temp_entity
:
884 cl
.paused
= MSG_ReadByte ();
890 VID_HandlePause (true);
897 VID_HandlePause (false);
906 Host_Error ("Received signon %i when at %i", i
, cls
.signon
);
911 case svc_killedmonster
:
912 cl
.stats
[STAT_MONSTERS
]++;
915 case svc_foundsecret
:
916 cl
.stats
[STAT_SECRETS
]++;
921 if (i
< 0 || i
>= MAX_CL_STATS
)
922 Sys_Error ("svc_updatestat: %i is invalid", i
);
923 cl
.stats
[i
] = MSG_ReadLong ();;
926 case svc_spawnstaticsound
:
927 CL_ParseStaticSound ();
931 cl
.cdtrack
= MSG_ReadByte ();
932 cl
.looptrack
= MSG_ReadByte ();
933 if ( (cls
.demoplayback
|| cls
.demorecording
) && (cls
.forcetrack
!= -1) )
934 CDAudio_Play ((byte
)cls
.forcetrack
, true);
936 CDAudio_Play ((byte
)cl
.cdtrack
, true);
939 case svc_intermission
:
941 cl
.completed_time
= cl
.time
;
942 vid
.recalc_refdef
= true; // go to full screen
947 cl
.completed_time
= cl
.time
;
948 vid
.recalc_refdef
= true; // go to full screen
949 SCR_CenterPrint (MSG_ReadString ());
954 cl
.completed_time
= cl
.time
;
955 vid
.recalc_refdef
= true; // go to full screen
956 SCR_CenterPrint (MSG_ReadString ());
960 Cmd_ExecuteString ("help", src_command
);