2009-02-28 14:41:18 +00:00
|
|
|
/*
|
2010-06-18 13:58:31 +00:00
|
|
|
* Copyright (C) 1997-2001 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.
|
2010-06-18 16:34:07 +00:00
|
|
|
*
|
|
|
|
* =======================================================================
|
2010-06-18 13:58:31 +00:00
|
|
|
*
|
2010-06-18 16:34:07 +00:00
|
|
|
* This file implements the entity and network protocol parsing
|
|
|
|
*
|
|
|
|
* =======================================================================
|
2010-06-18 13:58:31 +00:00
|
|
|
*/
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2009-03-03 13:43:32 +00:00
|
|
|
#include "header/client.h"
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2010-06-18 16:34:07 +00:00
|
|
|
void CL_DownloadFileName(char *dest, int destlen, char *fn);
|
|
|
|
void CL_ParseDownload (void);
|
|
|
|
|
2010-06-18 15:12:58 +00:00
|
|
|
int bitcounts[32]; /* just for protocol profiling */
|
|
|
|
|
2010-06-18 13:58:31 +00:00
|
|
|
char *svc_strings[256] = {
|
2009-02-28 14:41:18 +00:00
|
|
|
"svc_bad",
|
|
|
|
|
|
|
|
"svc_muzzleflash",
|
|
|
|
"svc_muzzlflash2",
|
|
|
|
"svc_temp_entity",
|
|
|
|
"svc_layout",
|
|
|
|
"svc_inventory",
|
|
|
|
|
|
|
|
"svc_nop",
|
|
|
|
"svc_disconnect",
|
|
|
|
"svc_reconnect",
|
|
|
|
"svc_sound",
|
|
|
|
"svc_print",
|
|
|
|
"svc_stufftext",
|
|
|
|
"svc_serverdata",
|
|
|
|
"svc_configstring",
|
2010-06-18 13:58:31 +00:00
|
|
|
"svc_spawnbaseline",
|
2009-02-28 14:41:18 +00:00
|
|
|
"svc_centerprint",
|
|
|
|
"svc_download",
|
|
|
|
"svc_playerinfo",
|
|
|
|
"svc_packetentities",
|
|
|
|
"svc_deltapacketentities",
|
|
|
|
"svc_frame"
|
|
|
|
};
|
|
|
|
|
2010-06-18 13:58:31 +00:00
|
|
|
void CL_RegisterSounds (void) {
|
2009-02-28 14:41:18 +00:00
|
|
|
int i;
|
|
|
|
|
|
|
|
S_BeginRegistration ();
|
|
|
|
CL_RegisterTEntSounds ();
|
2010-06-18 13:58:31 +00:00
|
|
|
|
|
|
|
for (i=1 ; i<MAX_SOUNDS ; i++) {
|
2009-02-28 14:41:18 +00:00
|
|
|
if (!cl.configstrings[CS_SOUNDS+i][0])
|
|
|
|
break;
|
2010-06-18 13:58:31 +00:00
|
|
|
|
2009-02-28 14:41:18 +00:00
|
|
|
cl.sound_precache[i] = S_RegisterSound (cl.configstrings[CS_SOUNDS+i]);
|
2010-06-18 13:58:31 +00:00
|
|
|
Sys_SendKeyEvents ();
|
2009-02-28 14:41:18 +00:00
|
|
|
}
|
2010-06-18 13:58:31 +00:00
|
|
|
|
2009-02-28 14:41:18 +00:00
|
|
|
S_EndRegistration ();
|
|
|
|
}
|
|
|
|
|
2010-06-18 15:12:58 +00:00
|
|
|
int CL_ParseEntityBits (unsigned *bits) {
|
|
|
|
unsigned b, total;
|
|
|
|
int i;
|
|
|
|
int number;
|
|
|
|
|
|
|
|
total = MSG_ReadByte (&net_message);
|
|
|
|
|
|
|
|
if (total & U_MOREBITS1) {
|
|
|
|
b = MSG_ReadByte (&net_message);
|
|
|
|
total |= b<<8;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (total & U_MOREBITS2) {
|
|
|
|
b = MSG_ReadByte (&net_message);
|
|
|
|
total |= b<<16;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (total & U_MOREBITS3) {
|
|
|
|
b = MSG_ReadByte (&net_message);
|
|
|
|
total |= b<<24;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* count the bits for net profiling */
|
|
|
|
for (i=0 ; i<32 ; i++)
|
|
|
|
if (total&(1<<i))
|
|
|
|
bitcounts[i]++;
|
|
|
|
|
|
|
|
if (total & U_NUMBER16)
|
|
|
|
number = MSG_ReadShort (&net_message);
|
|
|
|
|
|
|
|
else
|
|
|
|
number = MSG_ReadByte (&net_message);
|
|
|
|
|
|
|
|
*bits = total;
|
|
|
|
|
|
|
|
return number;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CL_ParseDelta (entity_state_t *from, entity_state_t *to, int number, int bits) {
|
|
|
|
/* set everything to the state we are delta'ing from */
|
|
|
|
*to = *from;
|
|
|
|
|
|
|
|
VectorCopy (from->origin, to->old_origin);
|
|
|
|
to->number = number;
|
|
|
|
|
|
|
|
if (bits & U_MODEL)
|
|
|
|
to->modelindex = MSG_ReadByte (&net_message);
|
|
|
|
|
|
|
|
if (bits & U_MODEL2)
|
|
|
|
to->modelindex2 = MSG_ReadByte (&net_message);
|
|
|
|
|
|
|
|
if (bits & U_MODEL3)
|
|
|
|
to->modelindex3 = MSG_ReadByte (&net_message);
|
|
|
|
|
|
|
|
if (bits & U_MODEL4)
|
|
|
|
to->modelindex4 = MSG_ReadByte (&net_message);
|
|
|
|
|
|
|
|
if (bits & U_FRAME8)
|
|
|
|
to->frame = MSG_ReadByte (&net_message);
|
|
|
|
|
|
|
|
if (bits & U_FRAME16)
|
|
|
|
to->frame = MSG_ReadShort (&net_message);
|
|
|
|
|
|
|
|
/* used for laser colors */
|
|
|
|
if ((bits & U_SKIN8) && (bits & U_SKIN16))
|
|
|
|
to->skinnum = MSG_ReadLong(&net_message);
|
|
|
|
|
|
|
|
else if (bits & U_SKIN8)
|
|
|
|
to->skinnum = MSG_ReadByte(&net_message);
|
|
|
|
|
|
|
|
else if (bits & U_SKIN16)
|
|
|
|
to->skinnum = MSG_ReadShort(&net_message);
|
|
|
|
|
|
|
|
if ( (bits & (U_EFFECTS8|U_EFFECTS16)) == (U_EFFECTS8|U_EFFECTS16) )
|
|
|
|
to->effects = MSG_ReadLong(&net_message);
|
|
|
|
|
|
|
|
else if (bits & U_EFFECTS8)
|
|
|
|
to->effects = MSG_ReadByte(&net_message);
|
|
|
|
|
|
|
|
else if (bits & U_EFFECTS16)
|
|
|
|
to->effects = MSG_ReadShort(&net_message);
|
|
|
|
|
|
|
|
if ( (bits & (U_RENDERFX8|U_RENDERFX16)) == (U_RENDERFX8|U_RENDERFX16) )
|
|
|
|
to->renderfx = MSG_ReadLong(&net_message);
|
|
|
|
|
|
|
|
else if (bits & U_RENDERFX8)
|
|
|
|
to->renderfx = MSG_ReadByte(&net_message);
|
|
|
|
|
|
|
|
else if (bits & U_RENDERFX16)
|
|
|
|
to->renderfx = MSG_ReadShort(&net_message);
|
|
|
|
|
|
|
|
if (bits & U_ORIGIN1)
|
|
|
|
to->origin[0] = MSG_ReadCoord (&net_message);
|
|
|
|
|
|
|
|
if (bits & U_ORIGIN2)
|
|
|
|
to->origin[1] = MSG_ReadCoord (&net_message);
|
|
|
|
|
|
|
|
if (bits & U_ORIGIN3)
|
|
|
|
to->origin[2] = MSG_ReadCoord (&net_message);
|
|
|
|
|
|
|
|
if (bits & U_ANGLE1)
|
|
|
|
to->angles[0] = MSG_ReadAngle(&net_message);
|
|
|
|
|
|
|
|
if (bits & U_ANGLE2)
|
|
|
|
to->angles[1] = MSG_ReadAngle(&net_message);
|
|
|
|
|
|
|
|
if (bits & U_ANGLE3)
|
|
|
|
to->angles[2] = MSG_ReadAngle(&net_message);
|
|
|
|
|
|
|
|
if (bits & U_OLDORIGIN)
|
|
|
|
MSG_ReadPos (&net_message, to->old_origin);
|
|
|
|
|
|
|
|
if (bits & U_SOUND)
|
|
|
|
to->sound = MSG_ReadByte (&net_message);
|
|
|
|
|
|
|
|
if (bits & U_EVENT)
|
|
|
|
to->event = MSG_ReadByte (&net_message);
|
|
|
|
|
|
|
|
else
|
|
|
|
to->event = 0;
|
|
|
|
|
|
|
|
if (bits & U_SOLID)
|
|
|
|
to->solid = MSG_ReadShort (&net_message);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Parses deltas from the given base and adds the resulting entity to
|
|
|
|
* the current frame
|
|
|
|
*/
|
|
|
|
void CL_DeltaEntity (frame_t *frame, int newnum, entity_state_t *old,
|
|
|
|
int bits) {
|
|
|
|
centity_t *ent;
|
|
|
|
entity_state_t *state;
|
|
|
|
|
|
|
|
ent = &cl_entities[newnum];
|
|
|
|
|
|
|
|
state = &cl_parse_entities[cl.parse_entities & (MAX_PARSE_ENTITIES-1)];
|
|
|
|
cl.parse_entities++;
|
|
|
|
frame->num_entities++;
|
|
|
|
|
|
|
|
CL_ParseDelta (old, state, newnum, bits);
|
|
|
|
|
|
|
|
/* some data changes will force no lerping */
|
|
|
|
if (state->modelindex != ent->current.modelindex
|
|
|
|
|| state->modelindex2 != ent->current.modelindex2
|
|
|
|
|| state->modelindex3 != ent->current.modelindex3
|
|
|
|
|| state->modelindex4 != ent->current.modelindex4
|
|
|
|
|| state->event == EV_PLAYER_TELEPORT
|
|
|
|
|| state->event == EV_OTHER_TELEPORT
|
|
|
|
|| abs((int)(state->origin[0] - ent->current.origin[0])) > 512
|
|
|
|
|| abs((int)(state->origin[1] - ent->current.origin[1])) > 512
|
|
|
|
|| abs((int)(state->origin[2] - ent->current.origin[2])) > 512
|
|
|
|
) {
|
|
|
|
ent->serverframe = -99;
|
|
|
|
}
|
|
|
|
/* wasn't in last update, so initialize some things */
|
|
|
|
if (ent->serverframe != cl.frame.serverframe - 1) {
|
|
|
|
ent->trailcount = 1024; /* for diminishing rocket / grenade trails */
|
|
|
|
|
|
|
|
/* duplicate the current state so
|
|
|
|
* lerping doesn't hurt anything */
|
|
|
|
ent->prev = *state;
|
|
|
|
|
|
|
|
if (state->event == EV_OTHER_TELEPORT) {
|
|
|
|
VectorCopy (state->origin, ent->prev.origin);
|
|
|
|
VectorCopy (state->origin, ent->lerp_origin);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
VectorCopy (state->old_origin, ent->prev.origin);
|
|
|
|
VectorCopy (state->old_origin, ent->lerp_origin);
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
/* shuffle the last state to previous */
|
|
|
|
ent->prev = ent->current;
|
|
|
|
}
|
|
|
|
|
|
|
|
ent->serverframe = cl.frame.serverframe;
|
|
|
|
ent->current = *state;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* An svc_packetentities has just been parsed, deal with the rest of the
|
|
|
|
* data stream.
|
|
|
|
*/
|
|
|
|
void CL_ParsePacketEntities (frame_t *oldframe, frame_t *newframe) {
|
|
|
|
unsigned int newnum;
|
|
|
|
unsigned bits;
|
|
|
|
entity_state_t
|
|
|
|
*oldstate = NULL;
|
|
|
|
int oldindex, oldnum;
|
|
|
|
|
|
|
|
newframe->parse_entities = cl.parse_entities;
|
|
|
|
newframe->num_entities = 0;
|
|
|
|
|
|
|
|
/* delta from the entities present in oldframe */
|
|
|
|
oldindex = 0;
|
|
|
|
|
|
|
|
if (!oldframe)
|
|
|
|
oldnum = 99999;
|
|
|
|
|
|
|
|
else {
|
|
|
|
if (oldindex >= oldframe->num_entities)
|
|
|
|
oldnum = 99999;
|
|
|
|
|
|
|
|
else {
|
|
|
|
oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)];
|
|
|
|
oldnum = oldstate->number;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
while (1) {
|
|
|
|
newnum = CL_ParseEntityBits (&bits);
|
|
|
|
|
|
|
|
if (newnum >= MAX_EDICTS)
|
|
|
|
Com_Error (ERR_DROP,"CL_ParsePacketEntities: bad number:%i", newnum);
|
|
|
|
|
|
|
|
if (net_message.readcount > net_message.cursize)
|
|
|
|
Com_Error (ERR_DROP,"CL_ParsePacketEntities: end of message");
|
|
|
|
|
|
|
|
if (!newnum)
|
|
|
|
break;
|
|
|
|
|
|
|
|
while (oldnum < newnum) {
|
|
|
|
/* one or more entities from the old packet are unchanged */
|
|
|
|
if (cl_shownet->value == 3)
|
|
|
|
Com_Printf (" unchanged: %i\n", oldnum);
|
|
|
|
|
|
|
|
CL_DeltaEntity (newframe, oldnum, oldstate, 0);
|
|
|
|
|
|
|
|
oldindex++;
|
|
|
|
|
|
|
|
if (oldindex >= oldframe->num_entities)
|
|
|
|
oldnum = 99999;
|
|
|
|
|
|
|
|
else {
|
|
|
|
oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)];
|
|
|
|
oldnum = oldstate->number;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bits & U_REMOVE) {
|
|
|
|
/* the entity present in oldframe is not in the current frame */
|
|
|
|
if (cl_shownet->value == 3)
|
|
|
|
Com_Printf (" remove: %i\n", newnum);
|
|
|
|
|
|
|
|
if (oldnum != newnum)
|
|
|
|
Com_Printf ("U_REMOVE: oldnum != newnum\n");
|
|
|
|
|
|
|
|
oldindex++;
|
|
|
|
|
|
|
|
if (oldindex >= oldframe->num_entities)
|
|
|
|
oldnum = 99999;
|
|
|
|
|
|
|
|
else {
|
|
|
|
oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)];
|
|
|
|
oldnum = oldstate->number;
|
|
|
|
}
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (oldnum == newnum) {
|
|
|
|
/* delta from previous state */
|
|
|
|
if (cl_shownet->value == 3)
|
|
|
|
Com_Printf (" delta: %i\n", newnum);
|
|
|
|
|
|
|
|
CL_DeltaEntity (newframe, newnum, oldstate, bits);
|
|
|
|
|
|
|
|
oldindex++;
|
|
|
|
|
|
|
|
if (oldindex >= oldframe->num_entities)
|
|
|
|
oldnum = 99999;
|
|
|
|
|
|
|
|
else {
|
|
|
|
oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)];
|
|
|
|
oldnum = oldstate->number;
|
|
|
|
}
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (oldnum > newnum) {
|
|
|
|
/* delta from baseline */
|
|
|
|
if (cl_shownet->value == 3)
|
|
|
|
Com_Printf (" baseline: %i\n", newnum);
|
|
|
|
|
|
|
|
CL_DeltaEntity (newframe, newnum, &cl_entities[newnum].baseline, bits);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/* any remaining entities in the old frame are copied over */
|
|
|
|
while (oldnum != 99999) {
|
|
|
|
/* one or more entities from the old packet are unchanged */
|
|
|
|
if (cl_shownet->value == 3)
|
|
|
|
Com_Printf (" unchanged: %i\n", oldnum);
|
|
|
|
|
|
|
|
CL_DeltaEntity (newframe, oldnum, oldstate, 0);
|
|
|
|
|
|
|
|
oldindex++;
|
|
|
|
|
|
|
|
if (oldindex >= oldframe->num_entities)
|
|
|
|
oldnum = 99999;
|
|
|
|
|
|
|
|
else {
|
|
|
|
oldstate = &cl_parse_entities[(oldframe->parse_entities+oldindex) & (MAX_PARSE_ENTITIES-1)];
|
|
|
|
oldnum = oldstate->number;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CL_ParsePlayerstate (frame_t *oldframe, frame_t *newframe) {
|
|
|
|
int flags;
|
|
|
|
player_state_t *state;
|
|
|
|
int i;
|
|
|
|
int statbits;
|
|
|
|
|
|
|
|
state = &newframe->playerstate;
|
|
|
|
|
|
|
|
/* clear to old value before delta parsing */
|
|
|
|
if (oldframe)
|
|
|
|
*state = oldframe->playerstate;
|
|
|
|
|
|
|
|
else
|
|
|
|
memset (state, 0, sizeof(*state));
|
|
|
|
|
|
|
|
flags = MSG_ReadShort (&net_message);
|
|
|
|
|
|
|
|
/* parse the pmove_state_t */
|
|
|
|
if (flags & PS_M_TYPE)
|
|
|
|
state->pmove.pm_type = MSG_ReadByte (&net_message);
|
|
|
|
|
|
|
|
if (flags & PS_M_ORIGIN) {
|
|
|
|
state->pmove.origin[0] = MSG_ReadShort (&net_message);
|
|
|
|
state->pmove.origin[1] = MSG_ReadShort (&net_message);
|
|
|
|
state->pmove.origin[2] = MSG_ReadShort (&net_message);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (flags & PS_M_VELOCITY) {
|
|
|
|
state->pmove.velocity[0] = MSG_ReadShort (&net_message);
|
|
|
|
state->pmove.velocity[1] = MSG_ReadShort (&net_message);
|
|
|
|
state->pmove.velocity[2] = MSG_ReadShort (&net_message);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (flags & PS_M_TIME)
|
|
|
|
state->pmove.pm_time = MSG_ReadByte (&net_message);
|
|
|
|
|
|
|
|
if (flags & PS_M_FLAGS)
|
|
|
|
state->pmove.pm_flags = MSG_ReadByte (&net_message);
|
|
|
|
|
|
|
|
if (flags & PS_M_GRAVITY)
|
|
|
|
state->pmove.gravity = MSG_ReadShort (&net_message);
|
|
|
|
|
|
|
|
if (flags & PS_M_DELTA_ANGLES) {
|
|
|
|
state->pmove.delta_angles[0] = MSG_ReadShort (&net_message);
|
|
|
|
state->pmove.delta_angles[1] = MSG_ReadShort (&net_message);
|
|
|
|
state->pmove.delta_angles[2] = MSG_ReadShort (&net_message);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cl.attractloop)
|
|
|
|
state->pmove.pm_type = PM_FREEZE; /* demo playback */
|
|
|
|
|
|
|
|
/* parse the rest of the player_state_t */
|
|
|
|
if (flags & PS_VIEWOFFSET) {
|
|
|
|
state->viewoffset[0] = MSG_ReadChar (&net_message) * 0.25f;
|
|
|
|
state->viewoffset[1] = MSG_ReadChar (&net_message) * 0.25f;
|
|
|
|
state->viewoffset[2] = MSG_ReadChar (&net_message) * 0.25f;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (flags & PS_VIEWANGLES) {
|
|
|
|
state->viewangles[0] = MSG_ReadAngle16 (&net_message);
|
|
|
|
state->viewangles[1] = MSG_ReadAngle16 (&net_message);
|
|
|
|
state->viewangles[2] = MSG_ReadAngle16 (&net_message);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (flags & PS_KICKANGLES) {
|
|
|
|
state->kick_angles[0] = MSG_ReadChar (&net_message) * 0.25f;
|
|
|
|
state->kick_angles[1] = MSG_ReadChar (&net_message) * 0.25f;
|
|
|
|
state->kick_angles[2] = MSG_ReadChar (&net_message) * 0.25f;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (flags & PS_WEAPONINDEX) {
|
|
|
|
state->gunindex = MSG_ReadByte (&net_message);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (flags & PS_WEAPONFRAME) {
|
|
|
|
state->gunframe = MSG_ReadByte (&net_message);
|
|
|
|
state->gunoffset[0] = MSG_ReadChar (&net_message)*0.25f;
|
|
|
|
state->gunoffset[1] = MSG_ReadChar (&net_message)*0.25f;
|
|
|
|
state->gunoffset[2] = MSG_ReadChar (&net_message)*0.25f;
|
|
|
|
state->gunangles[0] = MSG_ReadChar (&net_message)*0.25f;
|
|
|
|
state->gunangles[1] = MSG_ReadChar (&net_message)*0.25f;
|
|
|
|
state->gunangles[2] = MSG_ReadChar (&net_message)*0.25f;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (flags & PS_BLEND) {
|
|
|
|
state->blend[0] = MSG_ReadByte (&net_message)/255.0f;
|
|
|
|
state->blend[1] = MSG_ReadByte (&net_message)/255.0f;
|
|
|
|
state->blend[2] = MSG_ReadByte (&net_message)/255.0f;
|
|
|
|
state->blend[3] = MSG_ReadByte (&net_message)/255.0f;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (flags & PS_FOV)
|
|
|
|
state->fov = (float)MSG_ReadByte (&net_message);
|
|
|
|
|
|
|
|
if (flags & PS_RDFLAGS)
|
|
|
|
state->rdflags = MSG_ReadByte (&net_message);
|
|
|
|
|
|
|
|
/* parse stats */
|
|
|
|
statbits = MSG_ReadLong (&net_message);
|
|
|
|
|
|
|
|
for (i=0 ; i<MAX_STATS ; i++)
|
|
|
|
if (statbits & (1<<i) )
|
|
|
|
state->stats[i] = MSG_ReadShort(&net_message);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CL_FireEntityEvents (frame_t *frame) {
|
|
|
|
entity_state_t *s1;
|
|
|
|
int pnum, num;
|
|
|
|
|
|
|
|
for (pnum = 0 ; pnum<frame->num_entities ; pnum++) {
|
|
|
|
num = (frame->parse_entities + pnum)&(MAX_PARSE_ENTITIES-1);
|
|
|
|
s1 = &cl_parse_entities[num];
|
|
|
|
|
|
|
|
if (s1->event)
|
|
|
|
CL_EntityEvent (s1);
|
|
|
|
|
|
|
|
if (s1->effects & EF_TELEPORTER)
|
|
|
|
CL_TeleporterParticles (s1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CL_ParseFrame (void) {
|
|
|
|
int cmd;
|
|
|
|
int len;
|
|
|
|
frame_t *old;
|
|
|
|
|
|
|
|
memset (&cl.frame, 0, sizeof(cl.frame));
|
|
|
|
|
|
|
|
cl.frame.serverframe = MSG_ReadLong (&net_message);
|
|
|
|
cl.frame.deltaframe = MSG_ReadLong (&net_message);
|
|
|
|
cl.frame.servertime = cl.frame.serverframe*100;
|
|
|
|
|
|
|
|
/* BIG HACK to let old demos continue to work */
|
|
|
|
if (cls.serverProtocol != 26)
|
|
|
|
cl.surpressCount = MSG_ReadByte (&net_message);
|
|
|
|
|
|
|
|
if (cl_shownet->value == 3)
|
|
|
|
Com_Printf (" frame:%i delta:%i\n", cl.frame.serverframe,
|
|
|
|
cl.frame.deltaframe);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the frame is delta compressed from data that we
|
|
|
|
* no longer have available, we must suck up the rest of
|
|
|
|
* the frame, but not use it, then ask for a non-compressed
|
|
|
|
* message
|
|
|
|
*/
|
|
|
|
if (cl.frame.deltaframe <= 0) {
|
|
|
|
cl.frame.valid = true; /* uncompressed frame */
|
|
|
|
old = NULL;
|
|
|
|
cls.demowaiting = false; /* we can start recording now */
|
|
|
|
|
|
|
|
} else {
|
|
|
|
old = &cl.frames[cl.frame.deltaframe & UPDATE_MASK];
|
|
|
|
|
|
|
|
if (!old->valid) {
|
|
|
|
/* should never happen */
|
|
|
|
Com_Printf ("Delta from invalid frame (not supposed to happen!).\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (old->serverframe != cl.frame.deltaframe) {
|
|
|
|
/* The frame that the server did the delta from
|
|
|
|
* is too old, so we can't reconstruct it properly. */
|
|
|
|
Com_Printf ("Delta frame too old.\n");
|
|
|
|
|
|
|
|
} else if (cl.parse_entities - old->parse_entities > MAX_PARSE_ENTITIES-128) {
|
|
|
|
Com_Printf ("Delta parse_entities too old.\n");
|
|
|
|
|
|
|
|
} else
|
|
|
|
cl.frame.valid = true; /* valid delta parse */
|
|
|
|
}
|
|
|
|
|
|
|
|
/* clamp time */
|
|
|
|
if (cl.time > cl.frame.servertime)
|
|
|
|
cl.time = cl.frame.servertime;
|
|
|
|
|
|
|
|
else if (cl.time < cl.frame.servertime - 100)
|
|
|
|
cl.time = cl.frame.servertime - 100;
|
|
|
|
|
|
|
|
/* read areabits */
|
|
|
|
len = MSG_ReadByte (&net_message);
|
|
|
|
MSG_ReadData (&net_message, &cl.frame.areabits, len);
|
|
|
|
|
|
|
|
/* read playerinfo */
|
|
|
|
cmd = MSG_ReadByte (&net_message);
|
|
|
|
SHOWNET(svc_strings[cmd]);
|
|
|
|
|
|
|
|
if (cmd != svc_playerinfo)
|
|
|
|
Com_Error (ERR_DROP, "CL_ParseFrame: 0x%X not playerinfo", cmd);
|
|
|
|
|
|
|
|
CL_ParsePlayerstate (old, &cl.frame);
|
|
|
|
|
|
|
|
/* read packet entities */
|
|
|
|
cmd = MSG_ReadByte (&net_message);
|
|
|
|
SHOWNET(svc_strings[cmd]);
|
|
|
|
|
|
|
|
if (cmd != svc_packetentities)
|
|
|
|
Com_Error (ERR_DROP, "CL_ParseFrame: 0x%X not packetentities", cmd);
|
|
|
|
|
|
|
|
CL_ParsePacketEntities (old, &cl.frame);
|
|
|
|
|
|
|
|
/* save the frame off in the backup array for later delta comparisons */
|
|
|
|
cl.frames[cl.frame.serverframe & UPDATE_MASK] = cl.frame;
|
|
|
|
|
|
|
|
if (cl.frame.valid) {
|
|
|
|
/* getting a valid frame message ends the connection process */
|
|
|
|
if (cls.state != ca_active) {
|
|
|
|
cls.state = ca_active;
|
|
|
|
cl.force_refdef = true;
|
|
|
|
cl.predicted_origin[0] = cl.frame.playerstate.pmove.origin[0]*0.125f;
|
|
|
|
cl.predicted_origin[1] = cl.frame.playerstate.pmove.origin[1]*0.125f;
|
|
|
|
cl.predicted_origin[2] = cl.frame.playerstate.pmove.origin[2]*0.125f;
|
|
|
|
VectorCopy (cl.frame.playerstate.viewangles, cl.predicted_angles);
|
|
|
|
|
|
|
|
if (cls.disable_servercount != cl.servercount
|
|
|
|
&& cl.refresh_prepped)
|
|
|
|
SCR_EndLoadingPlaque (); /* get rid of loading plaque */
|
|
|
|
|
|
|
|
cl.sound_prepped = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* fire entity events */
|
|
|
|
CL_FireEntityEvents (&cl.frame);
|
|
|
|
|
|
|
|
if (!(!cl_predict->value || (cl.frame.playerstate.pmove.pm_flags & PMF_NO_PREDICTION)))
|
|
|
|
CL_CheckPredictionError();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-06-18 13:58:31 +00:00
|
|
|
void CL_ParseServerData (void) {
|
2009-02-28 14:41:18 +00:00
|
|
|
extern cvar_t *fs_gamedirvar;
|
|
|
|
char *str;
|
|
|
|
int i;
|
2010-06-18 13:58:31 +00:00
|
|
|
|
2009-02-28 14:41:18 +00:00
|
|
|
Com_DPrintf ("Serverdata packet received.\n");
|
2010-06-18 13:58:31 +00:00
|
|
|
|
|
|
|
/* wipe the client_state_t struct */
|
2009-02-28 14:41:18 +00:00
|
|
|
CL_ClearState ();
|
|
|
|
cls.state = ca_connected;
|
|
|
|
|
2010-06-18 13:58:31 +00:00
|
|
|
/* parse protocol version number */
|
2009-02-28 14:41:18 +00:00
|
|
|
i = MSG_ReadLong (&net_message);
|
|
|
|
cls.serverProtocol = i;
|
|
|
|
|
2010-06-18 13:58:31 +00:00
|
|
|
/* another demo hack */
|
|
|
|
if (Com_ServerState() && PROTOCOL_VERSION == 34) {
|
|
|
|
} else if (i != PROTOCOL_VERSION)
|
2009-02-28 14:41:18 +00:00
|
|
|
Com_Error (ERR_DROP,"Server returned version %i, not %i", i, PROTOCOL_VERSION);
|
|
|
|
|
|
|
|
cl.servercount = MSG_ReadLong (&net_message);
|
|
|
|
cl.attractloop = MSG_ReadByte (&net_message);
|
|
|
|
|
2010-06-18 13:58:31 +00:00
|
|
|
/* game directory */
|
2009-02-28 14:41:18 +00:00
|
|
|
str = MSG_ReadString (&net_message);
|
|
|
|
strncpy (cl.gamedir, str, sizeof(cl.gamedir)-1);
|
|
|
|
|
2010-06-18 13:58:31 +00:00
|
|
|
/* set gamedir */
|
2009-02-28 14:41:18 +00:00
|
|
|
if ((*str && (!fs_gamedirvar->string || !*fs_gamedirvar->string || strcmp(fs_gamedirvar->string, str))) || (!*str && (fs_gamedirvar->string || *fs_gamedirvar->string)))
|
|
|
|
Cvar_Set("game", str);
|
|
|
|
|
2010-06-18 13:58:31 +00:00
|
|
|
/* parse player entity number */
|
2009-02-28 14:41:18 +00:00
|
|
|
cl.playernum = MSG_ReadShort (&net_message);
|
|
|
|
|
2010-06-18 13:58:31 +00:00
|
|
|
/* get the full level name */
|
2009-02-28 14:41:18 +00:00
|
|
|
str = MSG_ReadString (&net_message);
|
|
|
|
|
2010-06-18 13:58:31 +00:00
|
|
|
if (cl.playernum == -1) {
|
|
|
|
/* playing a cinematic or showing a pic, not a level */
|
2009-02-28 14:41:18 +00:00
|
|
|
SCR_PlayCinematic (str);
|
2010-06-18 13:58:31 +00:00
|
|
|
|
|
|
|
} else {
|
|
|
|
/* seperate the printfs so the server
|
|
|
|
message can have a color */
|
2009-02-28 14:41:18 +00:00
|
|
|
Com_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");
|
|
|
|
Com_Printf ("%c%s\n", 2, str);
|
|
|
|
|
2010-06-18 13:58:31 +00:00
|
|
|
/* need to prep refresh at next oportunity */
|
2009-02-28 14:41:18 +00:00
|
|
|
cl.refresh_prepped = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-06-18 13:58:31 +00:00
|
|
|
void CL_ParseBaseline (void) {
|
2009-02-28 14:41:18 +00:00
|
|
|
entity_state_t *es;
|
|
|
|
unsigned bits;
|
|
|
|
int newnum;
|
|
|
|
entity_state_t nullstate;
|
|
|
|
|
|
|
|
memset (&nullstate, 0, sizeof(nullstate));
|
|
|
|
|
|
|
|
newnum = CL_ParseEntityBits (&bits);
|
|
|
|
es = &cl_entities[newnum].baseline;
|
|
|
|
CL_ParseDelta (&nullstate, es, newnum, bits);
|
|
|
|
}
|
|
|
|
|
2010-06-18 13:58:31 +00:00
|
|
|
void CL_LoadClientinfo (clientinfo_t *ci, char *s) {
|
2009-02-28 14:41:18 +00:00
|
|
|
int i;
|
|
|
|
char *t;
|
|
|
|
char model_name[MAX_QPATH];
|
|
|
|
char skin_name[MAX_QPATH];
|
|
|
|
char model_filename[MAX_QPATH];
|
|
|
|
char skin_filename[MAX_QPATH];
|
|
|
|
char weapon_filename[MAX_QPATH];
|
|
|
|
|
|
|
|
strncpy(ci->cinfo, s, sizeof(ci->cinfo));
|
|
|
|
ci->cinfo[sizeof(ci->cinfo)-1] = 0;
|
|
|
|
|
2010-06-18 13:58:31 +00:00
|
|
|
/* isolate the player's name */
|
2009-02-28 14:41:18 +00:00
|
|
|
strncpy(ci->name, s, sizeof(ci->name));
|
|
|
|
ci->name[sizeof(ci->name)-1] = 0;
|
|
|
|
t = strstr (s, "\\");
|
2010-06-18 13:58:31 +00:00
|
|
|
|
|
|
|
if (t) {
|
2009-02-28 14:41:18 +00:00
|
|
|
ci->name[t-s] = 0;
|
|
|
|
s = t+1;
|
|
|
|
}
|
|
|
|
|
2010-06-18 13:58:31 +00:00
|
|
|
if (cl_noskins->value || *s == 0) {
|
2009-03-02 18:42:57 +00:00
|
|
|
strcpy (model_filename, "players/male/tris.md2");
|
|
|
|
strcpy (weapon_filename, "players/male/weapon.md2");
|
|
|
|
strcpy (skin_filename, "players/male/grunt.pcx");
|
|
|
|
strcpy (ci->iconname, "/players/male/grunt_i.pcx");
|
2009-02-28 14:41:18 +00:00
|
|
|
ci->model = re.RegisterModel (model_filename);
|
|
|
|
memset(ci->weaponmodel, 0, sizeof(ci->weaponmodel));
|
|
|
|
ci->weaponmodel[0] = re.RegisterModel (weapon_filename);
|
|
|
|
ci->skin = re.RegisterSkin (skin_filename);
|
|
|
|
ci->icon = re.RegisterPic (ci->iconname);
|
2010-06-18 13:58:31 +00:00
|
|
|
|
|
|
|
} else {
|
|
|
|
/* isolate the model name */
|
2009-02-28 14:41:18 +00:00
|
|
|
strcpy (model_name, s);
|
|
|
|
t = strstr(model_name, "/");
|
2010-06-18 13:58:31 +00:00
|
|
|
|
2009-02-28 14:41:18 +00:00
|
|
|
if (!t)
|
|
|
|
t = strstr(model_name, "\\");
|
2010-06-18 13:58:31 +00:00
|
|
|
|
2009-02-28 14:41:18 +00:00
|
|
|
if (!t)
|
|
|
|
t = model_name;
|
2010-06-18 13:58:31 +00:00
|
|
|
|
2009-02-28 14:41:18 +00:00
|
|
|
*t = 0;
|
|
|
|
|
2010-06-18 13:58:31 +00:00
|
|
|
/* isolate the skin name */
|
2009-02-28 14:41:18 +00:00
|
|
|
strcpy (skin_name, s + strlen(model_name) + 1);
|
|
|
|
|
2010-06-18 13:58:31 +00:00
|
|
|
/* model file */
|
2009-02-28 14:41:18 +00:00
|
|
|
Com_sprintf (model_filename, sizeof(model_filename), "players/%s/tris.md2", model_name);
|
|
|
|
ci->model = re.RegisterModel (model_filename);
|
2010-06-18 13:58:31 +00:00
|
|
|
|
|
|
|
if (!ci->model) {
|
2009-02-28 14:41:18 +00:00
|
|
|
strcpy(model_name, "male");
|
|
|
|
Com_sprintf (model_filename, sizeof(model_filename), "players/male/tris.md2");
|
|
|
|
ci->model = re.RegisterModel (model_filename);
|
|
|
|
}
|
|
|
|
|
2010-06-18 13:58:31 +00:00
|
|
|
/* skin file */
|
2009-02-28 14:41:18 +00:00
|
|
|
Com_sprintf (skin_filename, sizeof(skin_filename), "players/%s/%s.pcx", model_name, skin_name);
|
|
|
|
ci->skin = re.RegisterSkin (skin_filename);
|
|
|
|
|
2010-06-18 13:58:31 +00:00
|
|
|
/* if we don't have the skin and the model wasn't male,
|
|
|
|
see if the male has it (this is for CTF's skins) */
|
|
|
|
if (!ci->skin && Q_stricmp(model_name, "male")) {
|
|
|
|
/* change model to male */
|
2009-02-28 14:41:18 +00:00
|
|
|
strcpy(model_name, "male");
|
|
|
|
Com_sprintf (model_filename, sizeof(model_filename), "players/male/tris.md2");
|
|
|
|
ci->model = re.RegisterModel (model_filename);
|
|
|
|
|
2010-06-18 13:58:31 +00:00
|
|
|
/* see if the skin exists for the male model */
|
2009-02-28 14:41:18 +00:00
|
|
|
Com_sprintf (skin_filename, sizeof(skin_filename), "players/%s/%s.pcx", model_name, skin_name);
|
|
|
|
ci->skin = re.RegisterSkin (skin_filename);
|
|
|
|
}
|
|
|
|
|
2010-06-18 13:58:31 +00:00
|
|
|
/* if we still don't have a skin, it means that the male model didn't have
|
|
|
|
it, so default to grunt */
|
2009-02-28 14:41:18 +00:00
|
|
|
if (!ci->skin) {
|
2010-06-18 13:58:31 +00:00
|
|
|
/* see if the skin exists for the male model */
|
2009-02-28 14:41:18 +00:00
|
|
|
Com_sprintf (skin_filename, sizeof(skin_filename), "players/%s/grunt.pcx", model_name, skin_name);
|
|
|
|
ci->skin = re.RegisterSkin (skin_filename);
|
|
|
|
}
|
|
|
|
|
2010-06-18 13:58:31 +00:00
|
|
|
/* weapon file */
|
2009-02-28 14:41:18 +00:00
|
|
|
for (i = 0; i < num_cl_weaponmodels; i++) {
|
|
|
|
Com_sprintf (weapon_filename, sizeof(weapon_filename), "players/%s/%s", model_name, cl_weaponmodels[i]);
|
|
|
|
ci->weaponmodel[i] = re.RegisterModel(weapon_filename);
|
2010-06-18 13:58:31 +00:00
|
|
|
|
2009-02-28 14:41:18 +00:00
|
|
|
if (!ci->weaponmodel[i] && strcmp(model_name, "cyborg") == 0) {
|
2010-06-18 13:58:31 +00:00
|
|
|
/* try male */
|
2009-02-28 14:41:18 +00:00
|
|
|
Com_sprintf (weapon_filename, sizeof(weapon_filename), "players/male/%s", cl_weaponmodels[i]);
|
|
|
|
ci->weaponmodel[i] = re.RegisterModel(weapon_filename);
|
|
|
|
}
|
2010-06-18 13:58:31 +00:00
|
|
|
|
2009-02-28 14:41:18 +00:00
|
|
|
if (!cl_vwep->value)
|
2010-06-18 13:58:31 +00:00
|
|
|
break; /* only one when vwep is off */
|
2009-02-28 14:41:18 +00:00
|
|
|
}
|
|
|
|
|
2010-06-18 13:58:31 +00:00
|
|
|
/* icon file */
|
2009-02-28 14:41:18 +00:00
|
|
|
Com_sprintf (ci->iconname, sizeof(ci->iconname), "/players/%s/%s_i.pcx", model_name, skin_name);
|
|
|
|
ci->icon = re.RegisterPic (ci->iconname);
|
|
|
|
}
|
|
|
|
|
2010-06-18 13:58:31 +00:00
|
|
|
/* must have loaded all data types to be valid */
|
|
|
|
if (!ci->skin || !ci->icon || !ci->model || !ci->weaponmodel[0]) {
|
2009-02-28 14:41:18 +00:00
|
|
|
ci->skin = NULL;
|
|
|
|
ci->icon = NULL;
|
|
|
|
ci->model = NULL;
|
|
|
|
ci->weaponmodel[0] = NULL;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2010-06-18 13:58:31 +00:00
|
|
|
* Load the skin, icon, and model for a client
|
|
|
|
*/
|
|
|
|
void CL_ParseClientinfo (int player) {
|
2009-02-28 14:41:18 +00:00
|
|
|
char *s;
|
|
|
|
clientinfo_t *ci;
|
|
|
|
|
|
|
|
s = cl.configstrings[player+CS_PLAYERSKINS];
|
|
|
|
|
|
|
|
ci = &cl.clientinfo[player];
|
|
|
|
|
|
|
|
CL_LoadClientinfo (ci, s);
|
|
|
|
}
|
|
|
|
|
2010-06-18 13:58:31 +00:00
|
|
|
void CL_ParseConfigString (void) {
|
2009-02-28 14:41:18 +00:00
|
|
|
int i;
|
|
|
|
char *s;
|
|
|
|
char olds[MAX_QPATH];
|
|
|
|
|
|
|
|
i = MSG_ReadShort (&net_message);
|
2010-06-18 13:58:31 +00:00
|
|
|
|
2009-02-28 14:41:18 +00:00
|
|
|
if (i < 0 || i >= MAX_CONFIGSTRINGS)
|
|
|
|
Com_Error (ERR_DROP, "configstring > MAX_CONFIGSTRINGS");
|
2010-06-18 13:58:31 +00:00
|
|
|
|
2009-02-28 14:41:18 +00:00
|
|
|
s = MSG_ReadString(&net_message);
|
|
|
|
|
|
|
|
strncpy (olds, cl.configstrings[i], sizeof(olds));
|
|
|
|
olds[sizeof(olds) - 1] = 0;
|
|
|
|
|
|
|
|
strcpy (cl.configstrings[i], s);
|
|
|
|
|
2010-06-18 13:58:31 +00:00
|
|
|
/* do something apropriate */
|
2009-02-28 14:41:18 +00:00
|
|
|
if (i >= CS_LIGHTS && i < CS_LIGHTS+MAX_LIGHTSTYLES)
|
|
|
|
CL_SetLightstyle (i - CS_LIGHTS);
|
2010-06-18 13:58:31 +00:00
|
|
|
|
|
|
|
else if (i == CS_CDTRACK) {
|
|
|
|
if (cl.refresh_prepped) {
|
2009-02-28 14:41:18 +00:00
|
|
|
CDAudio_Play (atoi(cl.configstrings[CS_CDTRACK]), true);
|
2009-10-03 16:06:45 +00:00
|
|
|
OGG_ResumeCmd();
|
|
|
|
}
|
2010-06-18 13:58:31 +00:00
|
|
|
|
|
|
|
} else if (i >= CS_MODELS && i < CS_MODELS+MAX_MODELS) {
|
|
|
|
if (cl.refresh_prepped) {
|
2009-02-28 14:41:18 +00:00
|
|
|
cl.model_draw[i-CS_MODELS] = re.RegisterModel (cl.configstrings[i]);
|
2010-06-18 13:58:31 +00:00
|
|
|
|
2009-02-28 14:41:18 +00:00
|
|
|
if (cl.configstrings[i][0] == '*')
|
|
|
|
cl.model_clip[i-CS_MODELS] = CM_InlineModel (cl.configstrings[i]);
|
2010-06-18 13:58:31 +00:00
|
|
|
|
2009-02-28 14:41:18 +00:00
|
|
|
else
|
|
|
|
cl.model_clip[i-CS_MODELS] = NULL;
|
|
|
|
}
|
2010-06-18 13:58:31 +00:00
|
|
|
|
|
|
|
} else if (i >= CS_SOUNDS && i < CS_SOUNDS+MAX_MODELS) {
|
2009-02-28 14:41:18 +00:00
|
|
|
if (cl.refresh_prepped)
|
|
|
|
cl.sound_precache[i-CS_SOUNDS] = S_RegisterSound (cl.configstrings[i]);
|
2010-06-18 13:58:31 +00:00
|
|
|
|
|
|
|
} else if (i >= CS_IMAGES && i < CS_IMAGES+MAX_MODELS) {
|
2009-02-28 14:41:18 +00:00
|
|
|
if (cl.refresh_prepped)
|
|
|
|
cl.image_precache[i-CS_IMAGES] = re.RegisterPic (cl.configstrings[i]);
|
2010-06-18 13:58:31 +00:00
|
|
|
|
|
|
|
} else if (i >= CS_PLAYERSKINS && i < CS_PLAYERSKINS+MAX_CLIENTS) {
|
2009-02-28 14:41:18 +00:00
|
|
|
if (cl.refresh_prepped && strcmp(olds, s))
|
|
|
|
CL_ParseClientinfo (i-CS_PLAYERSKINS);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-06-18 13:58:31 +00:00
|
|
|
void CL_ParseStartSoundPacket(void) {
|
|
|
|
vec3_t pos_v;
|
2009-02-28 14:41:18 +00:00
|
|
|
float *pos;
|
2010-06-18 13:58:31 +00:00
|
|
|
int channel, ent;
|
|
|
|
int sound_num;
|
|
|
|
float volume;
|
|
|
|
float attenuation;
|
2009-02-28 14:41:18 +00:00
|
|
|
int flags;
|
|
|
|
float ofs;
|
|
|
|
|
|
|
|
flags = MSG_ReadByte (&net_message);
|
|
|
|
sound_num = MSG_ReadByte (&net_message);
|
|
|
|
|
2010-06-18 13:58:31 +00:00
|
|
|
if (flags & SND_VOLUME)
|
2009-03-02 18:42:57 +00:00
|
|
|
volume = MSG_ReadByte (&net_message) / 255.0f;
|
2010-06-18 13:58:31 +00:00
|
|
|
|
2009-02-28 14:41:18 +00:00
|
|
|
else
|
|
|
|
volume = DEFAULT_SOUND_PACKET_VOLUME;
|
2010-06-18 13:58:31 +00:00
|
|
|
|
|
|
|
if (flags & SND_ATTENUATION)
|
2009-03-02 18:42:57 +00:00
|
|
|
attenuation = MSG_ReadByte (&net_message) / 64.0f;
|
2010-06-18 13:58:31 +00:00
|
|
|
|
2009-02-28 14:41:18 +00:00
|
|
|
else
|
2010-06-18 13:58:31 +00:00
|
|
|
attenuation = DEFAULT_SOUND_PACKET_ATTENUATION;
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2010-06-18 13:58:31 +00:00
|
|
|
if (flags & SND_OFFSET)
|
2009-03-02 18:42:57 +00:00
|
|
|
ofs = MSG_ReadByte (&net_message) / 1000.0f;
|
2010-06-18 13:58:31 +00:00
|
|
|
|
2009-02-28 14:41:18 +00:00
|
|
|
else
|
|
|
|
ofs = 0;
|
|
|
|
|
2010-06-18 13:58:31 +00:00
|
|
|
if (flags & SND_ENT) {
|
|
|
|
/* entity reletive */
|
|
|
|
channel = MSG_ReadShort(&net_message);
|
2009-02-28 14:41:18 +00:00
|
|
|
ent = channel>>3;
|
2010-06-18 13:58:31 +00:00
|
|
|
|
2009-02-28 14:41:18 +00:00
|
|
|
if (ent > MAX_EDICTS)
|
|
|
|
Com_Error (ERR_DROP,"CL_ParseStartSoundPacket: ent = %i", ent);
|
|
|
|
|
|
|
|
channel &= 7;
|
2010-06-18 13:58:31 +00:00
|
|
|
|
|
|
|
} else {
|
2009-02-28 14:41:18 +00:00
|
|
|
ent = 0;
|
|
|
|
channel = 0;
|
|
|
|
}
|
|
|
|
|
2010-06-18 13:58:31 +00:00
|
|
|
if (flags & SND_POS) {
|
|
|
|
/* positioned in space */
|
2009-02-28 14:41:18 +00:00
|
|
|
MSG_ReadPos (&net_message, pos_v);
|
2010-06-18 13:58:31 +00:00
|
|
|
|
2009-02-28 14:41:18 +00:00
|
|
|
pos = pos_v;
|
2010-06-18 13:58:31 +00:00
|
|
|
|
|
|
|
} else
|
|
|
|
/* use entity number */
|
2009-02-28 14:41:18 +00:00
|
|
|
pos = NULL;
|
|
|
|
|
|
|
|
if (!cl.sound_precache[sound_num])
|
|
|
|
return;
|
|
|
|
|
|
|
|
S_StartSound (pos, ent, channel, cl.sound_precache[sound_num], volume, attenuation, ofs);
|
2010-06-18 13:58:31 +00:00
|
|
|
}
|
2009-02-28 14:41:18 +00:00
|
|
|
|
2010-06-18 13:58:31 +00:00
|
|
|
void SHOWNET(char *s) {
|
2009-02-28 14:41:18 +00:00
|
|
|
if (cl_shownet->value>=2)
|
|
|
|
Com_Printf ("%3i:%s\n", net_message.readcount-1, s);
|
|
|
|
}
|
|
|
|
|
2010-06-18 13:58:31 +00:00
|
|
|
void CL_ParseServerMessage (void) {
|
|
|
|
int cmd;
|
|
|
|
char *s;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* if recording demos, copy the message out */
|
2009-02-28 14:41:18 +00:00
|
|
|
if (cl_shownet->value == 1)
|
|
|
|
Com_Printf ("%i ",net_message.cursize);
|
2010-06-18 13:58:31 +00:00
|
|
|
|
2009-02-28 14:41:18 +00:00
|
|
|
else if (cl_shownet->value >= 2)
|
|
|
|
Com_Printf ("------------------\n");
|
|
|
|
|
2010-06-18 13:58:31 +00:00
|
|
|
/* parse the message */
|
|
|
|
while (1) {
|
|
|
|
if (net_message.readcount > net_message.cursize) {
|
2009-02-28 14:41:18 +00:00
|
|
|
Com_Error (ERR_DROP,"CL_ParseServerMessage: Bad server message");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
cmd = MSG_ReadByte (&net_message);
|
|
|
|
|
2010-06-18 13:58:31 +00:00
|
|
|
if (cmd == -1) {
|
2009-02-28 14:41:18 +00:00
|
|
|
SHOWNET("END OF MESSAGE");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2010-06-18 13:58:31 +00:00
|
|
|
if (cl_shownet->value>=2) {
|
2009-02-28 14:41:18 +00:00
|
|
|
if (!svc_strings[cmd])
|
|
|
|
Com_Printf ("%3i:BAD CMD %i\n", net_message.readcount-1,cmd);
|
2010-06-18 13:58:31 +00:00
|
|
|
|
2009-02-28 14:41:18 +00:00
|
|
|
else
|
|
|
|
SHOWNET(svc_strings[cmd]);
|
|
|
|
}
|
|
|
|
|
2010-06-18 13:58:31 +00:00
|
|
|
/* other commands */
|
|
|
|
switch (cmd) {
|
|
|
|
default:
|
|
|
|
Com_Error (ERR_DROP,"CL_ParseServerMessage: Illegible server message\n");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case svc_nop:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case svc_disconnect:
|
|
|
|
Com_Error (ERR_DISCONNECT,"Server disconnected\n");
|
|
|
|
break;
|
|
|
|
|
|
|
|
case svc_reconnect:
|
|
|
|
Com_Printf ("Server disconnected, reconnecting\n");
|
|
|
|
|
|
|
|
if (cls.download) {
|
|
|
|
/* close download */
|
|
|
|
fclose (cls.download);
|
|
|
|
cls.download = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
cls.state = ca_connecting;
|
|
|
|
cls.connect_time = -99999; /* CL_CheckForResend() will fire immediately */
|
|
|
|
break;
|
|
|
|
|
|
|
|
case svc_print:
|
|
|
|
i = MSG_ReadByte (&net_message);
|
|
|
|
|
|
|
|
if (i == PRINT_CHAT) {
|
|
|
|
S_StartLocalSound ("misc/talk.wav");
|
|
|
|
con.ormask = 128;
|
|
|
|
}
|
|
|
|
|
|
|
|
Com_Printf ("%s", MSG_ReadString (&net_message));
|
|
|
|
con.ormask = 0;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case svc_centerprint:
|
|
|
|
SCR_CenterPrint (MSG_ReadString (&net_message));
|
|
|
|
break;
|
|
|
|
|
|
|
|
case svc_stufftext:
|
|
|
|
s = MSG_ReadString (&net_message);
|
|
|
|
Com_DPrintf ("stufftext: %s\n", s);
|
|
|
|
Cbuf_AddText (s);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case svc_serverdata:
|
|
|
|
Cbuf_Execute (); /* make sure any stuffed commands are done */
|
|
|
|
CL_ParseServerData ();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case svc_configstring:
|
|
|
|
CL_ParseConfigString ();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case svc_sound:
|
|
|
|
CL_ParseStartSoundPacket();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case svc_spawnbaseline:
|
|
|
|
CL_ParseBaseline ();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case svc_temp_entity:
|
|
|
|
CL_ParseTEnt ();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case svc_muzzleflash:
|
|
|
|
CL_ParseMuzzleFlash ();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case svc_muzzleflash2:
|
|
|
|
CL_ParseMuzzleFlash2 ();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case svc_download:
|
|
|
|
CL_ParseDownload ();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case svc_frame:
|
|
|
|
CL_ParseFrame ();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case svc_inventory:
|
|
|
|
CL_ParseInventory ();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case svc_layout:
|
|
|
|
s = MSG_ReadString (&net_message);
|
|
|
|
strncpy (cl.layout, s, sizeof(cl.layout)-1);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case svc_playerinfo:
|
|
|
|
case svc_packetentities:
|
|
|
|
case svc_deltapacketentities:
|
|
|
|
Com_Error (ERR_DROP, "Out of place frame data");
|
|
|
|
break;
|
2009-02-28 14:41:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CL_AddNetgraph ();
|
|
|
|
|
2010-06-18 13:58:31 +00:00
|
|
|
/* we don't know if it is ok to save a demo message until
|
|
|
|
after we have parsed the frame */
|
2009-02-28 14:41:18 +00:00
|
|
|
if (cls.demorecording && !cls.demowaiting)
|
|
|
|
CL_WriteDemoMessage ();
|
|
|
|
|
|
|
|
}
|