ngunix/WinQuake/cl_parse.c
2014-04-12 08:19:49 -04:00

1145 lines
28 KiB
C

/*
Copyright (C) 1996-1997 Id Software, Inc.
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
// cl_parse.c -- parse a message received from the server
#include "quakedef.h"
char *svc_strings[] =
{
"svc_bad",
"svc_nop",
"svc_disconnect",
"svc_updatestat",
"svc_version", // [long] server version
"svc_setview", // [short] entity number
"svc_sound", // <see code>
"svc_time", // [float] server time
"svc_print", // [string] null terminated string
"svc_stufftext", // [string] stuffed into client's console buffer
// the string should be \n terminated
"svc_setangle", // [vec3] set the view angle to this absolute value
"svc_serverinfo", // [long] version
// [string] signon string
// [string]..[0]model cache [string]...[0]sounds cache
// [string]..[0]item cache
"svc_lightstyle", // [byte] [string]
"svc_updatename", // [byte] [string]
"svc_updatefrags", // [byte] [short]
"svc_clientdata", // <shortbits + data>
"svc_stopsound", // <see code>
"svc_updatecolors", // [byte] [byte]
"svc_particle", // [vec3] <variable>
"svc_damage", // [byte] impact [byte] blood [vec3] from
"svc_spawnstatic",
"OBSOLETE svc_spawnbinary",
"svc_spawnbaseline",
"svc_temp_entity", // <variable>
"svc_setpause",
"svc_signonnum",
"svc_centerprint",
"svc_killedmonster",
"svc_foundsecret",
"svc_spawnstaticsound",
"svc_intermission",
"svc_finale", // [string] music [string] text
"svc_cdtrack", // [byte] track [byte] looptrack
"svc_sellscreen",
"svc_cutscene", // 2000-04-30 NVS HANDSHAKE SRV<->CL by Maddes
// added commata
"svc 35", "svc 36", "svc 37", "svc 38", "svc 39",
"svc 40", "svc 41", "svc 42", "svc 43", "svc 44", "svc 45", "svc 46", "svc 47", "svc 48", "svc 49",
"svc 50", "svc 51", "svc 52", "svc 53", "svc 54", "svc 55", "svc 56", "svc 57", "svc 58", "svc 59",
"svc 60", "svc 61", "svc 62", "svc 63", "svc 64", "svc 65", "svc 66", "svc 67", "svc 68", "svc 69",
"svc 70", "svc 71", "svc 72", "svc 73", "svc 74", "svc 75", "svc 76", "svc 77", "svc 78", "svc 79",
"svc 80", "svc 81", "svc 82", "svc 83", "svc 84", "svc 85", "svc 86", "svc 87", "svc 88", "svc 89",
"svc 90", "svc 91", "svc 92", "svc 93", "svc 94", "svc 95", "svc 96", "svc 97", "svc 98", "svc 99",
"svc 100", "svc 101", "svc 102", "svc 103", "svc 104", "svc 105", "svc 106", "svc 107", "svc 108", "svc 109",
"svc 110", "svc 111", "svc 112", "svc 113", "svc 114", "svc 115", "svc 116", "svc 117", "svc 118", "svc 119",
"svc 120", "svc 121", "svc 122", "svc 123", "svc 124", "svc 125",
"svc_limit", // 2001-09-20 Configurable limits by Maddes
// <variable>
"svc_extra_version", // 2000-04-30 NVS HANDSHAKE SRV<->CL by Maddes
// [float] SSVC [float] CSVC [float] CCLC
};
//=============================================================================
/*
===============
CL_EntityNum
This error checks and tracks the total number of entities
===============
*/
entity_t *CL_EntityNum (int num)
{
// 2001-09-20 Configurable entity limits by Maddes start
if (!cl_entities)
{
Cvar_Set(cl_entities_min, cl_entities_min->string); // do rangecheck
if (cl.max_edicts < cl_entities_min->value)
{
cl.max_edicts = cl_entities_min->value;
}
Con_DPrintf("Allocating memory for %i entities.\n", cl.max_edicts);
cl_entities = Hunk_AllocName (cl.max_edicts*sizeof(entity_t), "cl_edicts");
memset (cl_entities, 0, cl.max_edicts*sizeof(entity_t));
cl_entities[0].model = cl.worldmodel;
}
// 2001-09-20 Configurable entity limits by Maddes end
if (num >= cl.num_entities)
{
// 2001-09-20 Configurable entity limits by Maddes start
// if (num >= MAX_EDICTS)
if (num >= cl.max_edicts)
// 2001-09-20 Configurable entity limits by Maddes end
Host_Error ("CL_EntityNum: %i is an invalid number",num);
while (cl.num_entities<=num)
{
cl_entities[cl.num_entities].colormap = vid.colormap;
cl.num_entities++;
}
}
return &cl_entities[num];
}
/*
==================
CL_ParseStartSoundPacket
==================
*/
void CL_ParseStartSoundPacket(void)
{
vec3_t pos;
int channel, ent;
int sound_num;
int volume;
int field_mask;
float attenuation;
int i;
field_mask = MSG_ReadByte();
if (field_mask & SND_VOLUME)
volume = MSG_ReadByte ();
else
volume = DEFAULT_SOUND_PACKET_VOLUME;
if (field_mask & SND_ATTENUATION)
attenuation = MSG_ReadByte () / 64.0;
else
attenuation = DEFAULT_SOUND_PACKET_ATTENUATION;
channel = MSG_ReadShort ();
sound_num = MSG_ReadByte ();
ent = channel >> 3;
channel &= 7;
// 2001-09-20 Configurable entity limits by Maddes start
// if (ent > MAX_EDICTS)
if (ent > cl.max_edicts)
// 2001-09-20 Configurable entity limits by Maddes end
Host_Error ("CL_ParseStartSoundPacket: ent = %i", ent);
for (i=0 ; i<3 ; i++)
pos[i] = MSG_ReadCoord ();
S_StartSound (ent, channel, cl.sound_precache[sound_num], pos, volume/255.0, attenuation);
}
/*
==================
CL_KeepaliveMessage
When the client is taking a long time to load stuff, send keepalive messages
so the server doesn't disconnect.
==================
*/
void CL_KeepaliveMessage (void)
{
float time;
static float lastmsg;
int ret;
sizebuf_t old;
byte olddata[8192];
if (sv.active)
return; // no need if server is local
if (cls.demoplayback)
return;
// read messages from server, should just be nops
old = net_message;
memcpy (olddata, net_message.data, net_message.cursize);
do
{
ret = CL_GetMessage ();
switch (ret)
{
default:
Host_Error ("CL_KeepaliveMessage: CL_GetMessage failed");
case 0:
break; // nothing waiting
case 1:
Host_Error ("CL_KeepaliveMessage: received a message");
break;
case 2:
if (MSG_ReadByte() != svc_nop)
Host_Error ("CL_KeepaliveMessage: datagram wasn't a nop");
break;
}
} while (ret);
net_message = old;
memcpy (net_message.data, olddata, net_message.cursize);
// check time
time = Sys_FloatTime ();
if (time - lastmsg < 5)
return;
lastmsg = time;
// write out a nop
Con_Printf ("--> client to server keepalive\n");
MSG_WriteByte (&cls.message, clc_nop);
NET_SendMessage (cls.netcon, &cls.message);
SZ_Clear (&cls.message);
}
/*
==================
CL_ParseServerInfo
==================
*/
void CL_ParseServerInfo (void)
{
char *str;
int i;
int nummodels, numsounds;
char model_precache[MAX_MODELS][MAX_QPATH];
char sound_precache[MAX_SOUNDS][MAX_QPATH];
Con_DPrintf ("Serverinfo packet received.\n");
//
// wipe the client_state_t struct
//
CL_ClearState ();
// parse protocol version number
i = MSG_ReadLong ();
if (i != PROTOCOL_VERSION)
{
Con_Printf ("Server returned version %i, not %i\n", i, PROTOCOL_VERSION); // 2000-01-08 Missing linefeeds fix by Maddes
return;
}
// parse maxclients
cl.maxclients = MSG_ReadByte ();
if (cl.maxclients < 1 || cl.maxclients > MAX_SCOREBOARD)
{
Con_Printf("Bad maxclients (%u) from server\n", cl.maxclients);
return;
}
cl.scores = Hunk_AllocName (cl.maxclients*sizeof(*cl.scores), "scores");
// parse gametype
cl.gametype = MSG_ReadByte ();
// parse signon message
str = MSG_ReadString ();
strncpy (cl.levelname, str, sizeof(cl.levelname)-1);
// seperate the printfs so the server message can have a color
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");
Con_Printf ("%c%s\n", 2, str);
//
// first we go through and touch all of the precache data that still
// happens to be in the cache, so precaching something else doesn't
// needlessly purge it
//
// precache models
memset (cl.model_precache, 0, sizeof(cl.model_precache));
for (nummodels=1 ; ; nummodels++)
{
str = MSG_ReadString ();
if (!str[0])
break;
if (nummodels==MAX_MODELS)
{
Con_Printf ("Server sent too many model precaches\n");
return;
}
strcpy (model_precache[nummodels], str);
Mod_TouchModel (str);
}
// precache sounds
memset (cl.sound_precache, 0, sizeof(cl.sound_precache));
for (numsounds=1 ; ; numsounds++)
{
str = MSG_ReadString ();
if (!str[0])
break;
if (numsounds==MAX_SOUNDS)
{
Con_Printf ("Server sent too many sound precaches\n");
return;
}
strcpy (sound_precache[numsounds], str);
S_TouchSound (str);
}
//
// now we try to load everything else until a cache allocation fails
//
for (i=1 ; i<nummodels ; i++)
{
cl.model_precache[i] = Mod_ForName (model_precache[i], false);
if (cl.model_precache[i] == NULL)
{
Con_Printf("Model %s not found\n", model_precache[i]);
return;
}
CL_KeepaliveMessage ();
}
S_BeginPrecaching ();
for (i=1 ; i<numsounds ; i++)
{
cl.sound_precache[i] = S_PrecacheSound (sound_precache[i]);
CL_KeepaliveMessage ();
}
S_EndPrecaching ();
// local state
// 2001-09-20 Configurable entity limits by Maddes start
// cl_entities[0].model =
cl.worldmodel = cl.model_precache[1];
// 2001-09-20 Configurable entity limits by Maddes end
R_NewMap ();
Hunk_Check (); // make sure nothing is hurt
noclip_anglehack = false; // noclip is turned off at start
}
/*
==================
CL_ParseUpdate
Parse an entity update message from the server
If an entities model or origin changes from frame to frame, it must be
relinked. Other attributes can change without relinking.
==================
*/
int bitcounts[16];
void CL_ParseUpdate (int bits)
{
int i;
model_t *model;
int modnum;
qboolean forcelink;
entity_t *ent;
int num;
#ifdef GLQUAKE // 2000-07-16 General variable definition for GLQuake-only variable fix
int skin;
#endif // 2000-07-16 General variable definition for GLQuake-only variable fix
if (cls.signon == SIGNONS - 1)
{ // first update is the final signon stage
cls.signon = SIGNONS;
CL_SignonReply ();
}
if (bits & U_MOREBITS)
{
i = MSG_ReadByte ();
bits |= (i<<8);
}
if (bits & U_LONGENTITY)
num = MSG_ReadShort ();
else
num = MSG_ReadByte ();
ent = CL_EntityNum (num);
for (i=0 ; i<16 ; i++)
if (bits&(1<<i))
bitcounts[i]++;
if (ent->msgtime != cl.mtime[1])
forcelink = true; // no previous frame to lerp from
else
forcelink = false;
ent->msgtime = cl.mtime[0];
if (bits & U_MODEL)
{
modnum = MSG_ReadByte ();
if (modnum >= MAX_MODELS)
Host_Error ("CL_ParseModel: bad modnum");
}
else
modnum = ent->baseline.modelindex;
model = cl.model_precache[modnum];
if (model != ent->model)
{
ent->model = model;
// automatic animation (torches, etc) can be either all together
// or randomized
if (model)
{
if (model->synctype == ST_RAND)
ent->syncbase = (float)(rand()&0x7fff) / 0x7fff;
else
ent->syncbase = 0.0;
}
else
forcelink = true; // hack to make null model players work
#ifdef GLQUAKE
if (num > 0 && num <= cl.maxclients)
R_TranslatePlayerSkin (num - 1);
#endif
}
if (bits & U_FRAME)
ent->frame = MSG_ReadByte ();
else
ent->frame = ent->baseline.frame;
if (bits & U_COLORMAP)
i = MSG_ReadByte();
else
i = ent->baseline.colormap;
if (!i)
ent->colormap = vid.colormap;
else
{
if (i > cl.maxclients)
// 2001-12-16 Various crashes changed to host errors by Maddes start
// Sys_Error ("i >= cl.maxclients");
{
Host_Error ("CL_ParseUpdate: i > cl.maxclients: %i > %i", i, cl.maxclients);
return;
}
// 2001-12-16 Various crashes changed to host errors by Maddes end
ent->colormap = cl.scores[i-1].translations;
}
#ifdef GLQUAKE
if (bits & U_SKIN)
skin = MSG_ReadByte();
else
skin = ent->baseline.skin;
if (skin != ent->skinnum) {
ent->skinnum = skin;
if (num > 0 && num <= cl.maxclients)
R_TranslatePlayerSkin (num - 1);
}
#else
if (bits & U_SKIN)
ent->skinnum = MSG_ReadByte();
else
ent->skinnum = ent->baseline.skin;
#endif
if (bits & U_EFFECTS)
ent->effects = MSG_ReadByte();
else
ent->effects = ent->baseline.effects;
// shift the known values for interpolation
VectorCopy (ent->msg_origins[0], ent->msg_origins[1]);
VectorCopy (ent->msg_angles[0], ent->msg_angles[1]);
if (bits & U_ORIGIN1)
ent->msg_origins[0][0] = MSG_ReadCoord ();
else
ent->msg_origins[0][0] = ent->baseline.origin[0];
if (bits & U_ANGLE1)
ent->msg_angles[0][0] = MSG_ReadAngle();
else
ent->msg_angles[0][0] = ent->baseline.angles[0];
if (bits & U_ORIGIN2)
ent->msg_origins[0][1] = MSG_ReadCoord ();
else
ent->msg_origins[0][1] = ent->baseline.origin[1];
if (bits & U_ANGLE2)
ent->msg_angles[0][1] = MSG_ReadAngle();
else
ent->msg_angles[0][1] = ent->baseline.angles[1];
if (bits & U_ORIGIN3)
ent->msg_origins[0][2] = MSG_ReadCoord ();
else
ent->msg_origins[0][2] = ent->baseline.origin[2];
if (bits & U_ANGLE3)
ent->msg_angles[0][2] = MSG_ReadAngle();
else
ent->msg_angles[0][2] = ent->baseline.angles[2];
if ( bits & U_NOLERP )
ent->forcelink = true;
if ( forcelink )
{ // didn't have an update last message
VectorCopy (ent->msg_origins[0], ent->msg_origins[1]);
VectorCopy (ent->msg_origins[0], ent->origin);
VectorCopy (ent->msg_angles[0], ent->msg_angles[1]);
VectorCopy (ent->msg_angles[0], ent->angles);
ent->forcelink = true;
}
}
/*
==================
CL_ParseBaseline
==================
*/
void CL_ParseBaseline (entity_t *ent)
{
int i;
ent->baseline.modelindex = MSG_ReadByte ();
ent->baseline.frame = MSG_ReadByte ();
ent->baseline.colormap = MSG_ReadByte();
ent->baseline.skin = MSG_ReadByte();
for (i=0 ; i<3 ; i++)
{
ent->baseline.origin[i] = MSG_ReadCoord ();
ent->baseline.angles[i] = MSG_ReadAngle ();
}
}
/*
==================
CL_ParseClientdata
Server information pertaining to this client only
==================
*/
void CL_ParseClientdata (int bits)
{
int i, j;
if (bits & SU_VIEWHEIGHT)
cl.viewheight = MSG_ReadChar ();
else
cl.viewheight = DEFAULT_VIEWHEIGHT;
if (bits & SU_IDEALPITCH)
cl.idealpitch = MSG_ReadChar ();
else
cl.idealpitch = 0;
VectorCopy (cl.mvelocity[0], cl.mvelocity[1]);
for (i=0 ; i<3 ; i++)
{
if (bits & (SU_PUNCH1<<i) )
cl.punchangle[i] = MSG_ReadChar();
else
cl.punchangle[i] = 0;
if (bits & (SU_VELOCITY1<<i) )
cl.mvelocity[0][i] = MSG_ReadChar()*16;
else
cl.mvelocity[0][i] = 0;
}
// [always sent] if (bits & SU_ITEMS)
i = MSG_ReadLong ();
if (cl.items != i)
{ // set flash times
Sbar_Changed ();
for (j=0 ; j<32 ; j++)
if ( (i & (1<<j)) && !(cl.items & (1<<j)))
cl.item_gettime[j] = cl.time;
cl.items = i;
}
cl.onground = (bits & SU_ONGROUND) != 0;
cl.inwater = (bits & SU_INWATER) != 0;
if (bits & SU_WEAPONFRAME)
cl.stats[STAT_WEAPONFRAME] = MSG_ReadByte ();
else
cl.stats[STAT_WEAPONFRAME] = 0;
if (bits & SU_ARMOR)
i = MSG_ReadByte ();
else
i = 0;
if (cl.stats[STAT_ARMOR] != i)
{
cl.stats[STAT_ARMOR] = i;
Sbar_Changed ();
}
if (bits & SU_WEAPON)
i = MSG_ReadByte ();
else
i = 0;
if (cl.stats[STAT_WEAPON] != i)
{
cl.stats[STAT_WEAPON] = i;
Sbar_Changed ();
}
i = MSG_ReadShort ();
if (cl.stats[STAT_HEALTH] != i)
{
cl.stats[STAT_HEALTH] = i;
Sbar_Changed ();
}
i = MSG_ReadByte ();
if (cl.stats[STAT_AMMO] != i)
{
cl.stats[STAT_AMMO] = i;
Sbar_Changed ();
}
for (i=0 ; i<4 ; i++)
{
j = MSG_ReadByte ();
if (cl.stats[STAT_SHELLS+i] != j)
{
cl.stats[STAT_SHELLS+i] = j;
Sbar_Changed ();
}
}
i = MSG_ReadByte ();
if (standard_quake)
{
if (cl.stats[STAT_ACTIVEWEAPON] != i)
{
cl.stats[STAT_ACTIVEWEAPON] = i;
Sbar_Changed ();
}
}
else
{
if (cl.stats[STAT_ACTIVEWEAPON] != (1<<i))
{
cl.stats[STAT_ACTIVEWEAPON] = (1<<i);
Sbar_Changed ();
}
}
}
/*
=====================
CL_NewTranslation
=====================
*/
void CL_NewTranslation (int slot)
{
int i, j;
int top, bottom;
byte *dest, *source;
if (slot > cl.maxclients)
// 2001-12-16 Various crashes changed to host errors by Maddes start
// Sys_Error ("CL_NewTranslation: slot > cl.maxclients");
{
Host_Error ("CL_NewTranslation: slot > cl.maxclients: %i > %i", slot, cl.maxclients);
return;
}
// 2001-12-16 Various crashes changed to host errors by Maddes end
dest = cl.scores[slot].translations;
source = vid.colormap;
memcpy (dest, vid.colormap, sizeof(cl.scores[slot].translations));
top = cl.scores[slot].colors & 0xf0;
bottom = (cl.scores[slot].colors &15)<<4;
#ifdef GLQUAKE
R_TranslatePlayerSkin (slot);
#endif
for (i=0 ; i<VID_GRADES ; i++, dest += 256, source+=256)
{
if (top < 128) // the artists made some backwards ranges. sigh.
memcpy (dest + TOP_RANGE, source + top, 16);
else
for (j=0 ; j<16 ; j++)
dest[TOP_RANGE+j] = source[top+15-j];
if (bottom < 128)
memcpy (dest + BOTTOM_RANGE, source + bottom, 16);
else
for (j=0 ; j<16 ; j++)
dest[BOTTOM_RANGE+j] = source[bottom+15-j];
}
}
/*
=====================
CL_ParseStatic
=====================
*/
void CL_ParseStatic (void)
{
entity_t *ent;
int i;
// 2001-09-20 Configurable entity limits by Maddes start
if (!cl_static_entities)
{
Cvar_Set(cl_entities_min_static, cl_entities_min_static->string); // do rangecheck
if (cl.max_static_edicts < cl_entities_min_static->value)
{
cl.max_static_edicts = cl_entities_min_static->value;
}
Con_DPrintf("Allocating memory for %i static entities.\n", cl.max_static_edicts);
cl_static_entities = Hunk_AllocName (cl.max_static_edicts*sizeof(entity_t), "cl_ed_static");
memset (cl_static_entities, 0, cl.max_static_edicts*sizeof(entity_t));
}
// 2001-09-20 Configurable entity limits by Maddes end
i = cl.num_statics;
// 2001-09-20 Configurable entity limits by Maddes start
// if (i >= MAX_STATIC_ENTITIES)
// Host_Error ("Too many static entities");
if (i >= cl.max_static_edicts)
Host_Error ("Too many static entities, max is %i", cl.max_static_edicts);
// 2001-09-20 Configurable entity limits by Maddes end
ent = &cl_static_entities[i];
cl.num_statics++;
CL_ParseBaseline (ent);
// copy it to the current state
ent->model = cl.model_precache[ent->baseline.modelindex];
ent->frame = ent->baseline.frame;
ent->colormap = vid.colormap;
ent->skinnum = ent->baseline.skin;
ent->effects = ent->baseline.effects;
VectorCopy (ent->baseline.origin, ent->origin);
VectorCopy (ent->baseline.angles, ent->angles);
R_AddEfrags (ent);
}
/*
===================
CL_ParseStaticSound
===================
*/
void CL_ParseStaticSound (void)
{
vec3_t org;
int sound_num, vol, atten;
int i;
for (i=0 ; i<3 ; i++)
org[i] = MSG_ReadCoord ();
sound_num = MSG_ReadByte ();
vol = MSG_ReadByte ();
atten = MSG_ReadByte ();
S_StaticSound (cl.sound_precache[sound_num], org, vol, atten);
}
// 2000-04-30 NVS HANDSHAKE SRV<->CL by Maddes start
/*
=================
CL_ParseVersion
=================
*/
void CL_ParseVersion (void)
{
int type;
float f;
type = MSG_ReadByte ();
switch (type)
{
case VERSION_NVS:
// read SSVC version
f = MSG_ReadFloat ();
if (!sv.active) // not necessary on listen server
{
nvs_current_ssvc->rangecheck = NULL; //deactivate, as server can run with a much higher version
Cvar_SetValue (nvs_current_ssvc, f);
nvs_current_ssvc->rangecheck = Cvar_RangecheckFloat; //reactivate
}
// read CSVC version
f = MSG_ReadFloat ();
Cvar_SetValue (nvs_current_csvc, f);
// read CCLC version
f = MSG_ReadFloat ();
Cvar_SetValue (nvs_current_cclc, f);
break;
default:
Host_Error ("CL_ParseVersion: bad type %i", type);
break;
}
}
// 2000-04-30 NVS HANDSHAKE SRV<->CL by Maddes end
// 2001-09-20 Configurable limits by Maddes start
/*
=================
CL_ParseLimit
=================
*/
void CL_ParseLimit (void)
{
int type;
type = MSG_ReadByte ();
switch (type)
{
// 2001-09-20 Configurable entity limits by Maddes start
case LIM_ENTITIES:
cl.max_edicts = MSG_ReadShort ();
cl.max_static_edicts = MSG_ReadShort ();
cl.max_temp_edicts = MSG_ReadShort ();
Con_DPrintf("Server runs with %i normal, %i static and %i temp edicts.\n", cl.max_edicts, cl.max_static_edicts, cl.max_temp_edicts);
// check values: only the normal entities are send with their index number, the others are send without indexes
if (cl.max_edicts > MAX_EDICTS)
{
Host_Error ("CL_ParseLimit: %i entities can not be handled, max is %i", cl.max_edicts, MAX_EDICTS);
}
break;
// 2001-09-20 Configurable entity limits by Maddes end
default:
Host_Error ("CL_ParseLimit: bad type %i", type);
break;
}
}
// 2001-09-20 Configurable limits by Maddes end
#define SHOWNET(x) if(cl_shownet->value==2)Con_Printf ("%3i:%s\n", msg_readcount-1, x);
/*
=====================
CL_ParseServerMessage
=====================
*/
void CL_ParseServerMessage (void)
{
int cmd;
int i;
//
// if recording demos, copy the message out
//
if (cl_shownet->value == 1)
Con_Printf ("%i ",net_message.cursize);
else if (cl_shownet->value == 2)
Con_Printf ("------------------\n");
cl.onground = false; // unless the server says otherwise
//
// parse the message
//
MSG_BeginReading ();
while (1)
{
if (msg_badread)
Host_Error ("CL_ParseServerMessage: Bad server message");
cmd = MSG_ReadByte ();
if (cmd == -1)
{
SHOWNET("END OF MESSAGE");
return; // end of message
}
// if the high bit of the command byte is set, it is a fast update
if (cmd & 128)
{
SHOWNET("fast update");
CL_ParseUpdate (cmd&127);
continue;
}
SHOWNET(svc_strings[cmd]);
// other commands
switch (cmd)
{
default:
Host_Error ("CL_ParseServerMessage: Illegible server message");
break;
case svc_nop:
// Con_Printf ("svc_nop\n");
break;
case svc_time:
cl.mtime[1] = cl.mtime[0];
cl.mtime[0] = MSG_ReadFloat ();
break;
case svc_clientdata:
i = MSG_ReadShort ();
CL_ParseClientdata (i);
break;
case svc_version:
i = MSG_ReadLong ();
if (i != PROTOCOL_VERSION)
Host_Error ("CL_ParseServerMessage: Server is protocol %i instead of %i", i, PROTOCOL_VERSION);
break;
case svc_disconnect:
Host_EndGame ("Server disconnected\n");
case svc_print:
Con_Printf ("%s", MSG_ReadString ());
break;
case svc_centerprint:
SCR_CenterPrint (MSG_ReadString ());
break;
case svc_stufftext:
Cbuf_AddText (MSG_ReadString ());
break;
case svc_damage:
V_ParseDamage ();
break;
case svc_serverinfo:
CL_ParseServerInfo ();
vid.recalc_refdef = true; // leave intermission full screen
break;
case svc_setangle:
// 2000-05-02 NVS SVC_setangle by Maddes start
if ((nvs_current_csvc->value >= 0.50) && (cls.signon > 1))
{
for (i=0 ; i<3 ; i++)
cl.viewangles[i] = MSG_ReadFloat ();
}
else
{
// 2000-05-02 NVS SVC_setangle by Maddes end
for (i=0 ; i<3 ; i++)
cl.viewangles[i] = MSG_ReadAngle ();
} // 2000-05-02 NVS SVC_setangle by Maddes
break;
case svc_setview:
cl.viewentity = MSG_ReadShort ();
break;
case svc_lightstyle:
i = MSG_ReadByte ();
if (i >= MAX_LIGHTSTYLES)
// 2001-12-16 Various crashes changed to host errors by Maddes start
// Sys_Error ("svc_lightstyle >= MAX_LIGHTSTYLES");
{
Host_Error ("svc_lightstyle >= MAX_LIGHTSTYLES: %i >= %i", i, MAX_LIGHTSTYLES);
break;
}
// 2001-12-16 Various crashes changed to host errors by Maddes end
strcpy (cl_lightstyle[i].map, MSG_ReadString());
cl_lightstyle[i].length = strlen(cl_lightstyle[i].map);
break;
case svc_sound:
CL_ParseStartSoundPacket();
break;
case svc_stopsound:
i = MSG_ReadShort();
S_StopSound(i>>3, i&7);
break;
case svc_updatename:
Sbar_Changed ();
i = MSG_ReadByte ();
if (i >= cl.maxclients)
Host_Error ("CL_ParseServerMessage: svc_updatename > MAX_SCOREBOARD");
strcpy (cl.scores[i].name, MSG_ReadString ());
break;
case svc_updatefrags:
Sbar_Changed ();
i = MSG_ReadByte ();
if (i >= cl.maxclients)
Host_Error ("CL_ParseServerMessage: svc_updatefrags > MAX_SCOREBOARD");
cl.scores[i].frags = MSG_ReadShort ();
break;
case svc_updatecolors:
Sbar_Changed ();
i = MSG_ReadByte ();
if (i >= cl.maxclients)
Host_Error ("CL_ParseServerMessage: svc_updatecolors > MAX_SCOREBOARD");
cl.scores[i].colors = MSG_ReadByte ();
CL_NewTranslation (i);
break;
case svc_particle:
R_ParseParticleEffect ();
break;
case svc_spawnbaseline:
i = MSG_ReadShort ();
// must use CL_EntityNum() to force cl.num_entities up
CL_ParseBaseline (CL_EntityNum(i));
break;
case svc_spawnstatic:
CL_ParseStatic ();
break;
case svc_temp_entity:
CL_ParseTEnt ();
break;
case svc_setpause:
{
cl.paused = MSG_ReadByte ();
if (cl.paused)
{
CDAudio_Pause ();
#ifdef _WIN32
VID_HandlePause (true);
#endif
}
else
{
CDAudio_Resume ();
#ifdef _WIN32
VID_HandlePause (false);
#endif
}
}
break;
case svc_signonnum:
i = MSG_ReadByte ();
if (i <= cls.signon)
Host_Error ("Received signon %i when at %i", i, cls.signon);
cls.signon = i;
CL_SignonReply ();
break;
case svc_killedmonster:
cl.stats[STAT_MONSTERS]++;
break;
case svc_foundsecret:
cl.stats[STAT_SECRETS]++;
break;
case svc_updatestat:
i = MSG_ReadByte ();
if (i < 0 || i >= MAX_CL_STATS)
// 2001-12-16 Various crashes changed to host errors by Maddes start
// Sys_Error ("svc_updatestat: %i is invalid", i);
{
Host_Error ("svc_updatestat: %i is invalid (0-%i)", i, MAX_CL_STATS);
break;
}
// 2001-12-16 Various crashes changed to host errors by Maddes end
cl.stats[i] = MSG_ReadLong ();;
break;
case svc_spawnstaticsound:
CL_ParseStaticSound ();
break;
case svc_cdtrack:
cl.cdtrack = MSG_ReadByte ();
cl.looptrack = MSG_ReadByte ();
if ( (cls.demoplayback || cls.demorecording) && (cls.forcetrack != -1) )
CDAudio_Play ((byte)cls.forcetrack, true);
else
CDAudio_Play ((byte)cl.cdtrack, true);
break;
case svc_intermission:
cl.intermission = 1;
cl.completed_time = cl.time;
vid.recalc_refdef = true; // go to full screen
break;
case svc_finale:
cl.intermission = 2;
cl.completed_time = cl.time;
vid.recalc_refdef = true; // go to full screen
SCR_CenterPrint (MSG_ReadString ());
break;
case svc_cutscene:
cl.intermission = 3;
cl.completed_time = cl.time;
vid.recalc_refdef = true; // go to full screen
SCR_CenterPrint (MSG_ReadString ());
break;
case svc_sellscreen:
Cmd_ExecuteString ("help", src_command);
break;
// 2001-09-20 Configurable limits by Maddes start
case svc_limit:
CL_ParseLimit();
break;
// 2001-09-20 Configurable limits by Maddes end
// 2000-04-30 NVS HANDSHAKE SRV<->CL by Maddes start
case svc_extra_version:
CL_ParseVersion();
break;
// 2000-04-30 NVS HANDSHAKE SRV<->CL by Maddes end
}
}
}