This repository has been archived on 2022-06-27. You can view files and clone it, but cannot push or open issues or pull requests.
Xash3DArchive/engine/client/cl_parse.c

1927 lines
47 KiB
C
Raw Normal View History

2011-05-09 22:00:00 +02:00
/*
cl_parse.c - parse a message received from the server
Copyright (C) 2008 Uncle Mike
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 3 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.
*/
2007-06-21 22:00:00 +02:00
2008-06-09 22:00:00 +02:00
#include "common.h"
2007-06-21 22:00:00 +02:00
#include "client.h"
2010-08-04 22:00:00 +02:00
#include "net_encode.h"
2011-02-16 22:00:00 +01:00
#include "particledef.h"
2011-04-06 22:00:00 +02:00
#include "gl_local.h"
2010-11-06 22:00:00 +01:00
#include "cl_tent.h"
2010-10-31 22:00:00 +01:00
#include "shake.h"
2017-02-12 22:00:00 +01:00
#include "hltv.h"
2007-06-21 22:00:00 +02:00
2010-03-27 22:00:00 +01:00
#define MSG_COUNT 32 // last 32 messages parsed
#define MSG_MASK (MSG_COUNT - 1)
2010-04-02 22:00:00 +02:00
int CL_UPDATE_BACKUP = SINGLEPLAYER_BACKUP;
2010-08-16 22:00:00 +02:00
const char *svc_strings[256] =
2009-10-13 22:00:00 +02:00
{
"svc_bad",
"svc_nop",
"svc_disconnect",
2017-02-07 22:00:00 +01:00
"svc_event",
2010-08-16 22:00:00 +02:00
"svc_changing",
"svc_setview",
"svc_sound",
"svc_time",
"svc_print",
2009-10-13 22:00:00 +02:00
"svc_stufftext",
2010-08-16 22:00:00 +02:00
"svc_setangle",
2009-10-13 22:00:00 +02:00
"svc_serverdata",
2010-10-28 22:00:00 +02:00
"svc_lightstyle",
2010-10-17 22:00:00 +02:00
"svc_updateuserinfo",
2010-10-28 22:00:00 +02:00
"svc_deltatable",
2010-08-16 22:00:00 +02:00
"svc_clientdata",
2011-04-08 22:00:00 +02:00
"svc_stopsound",
2017-02-07 22:00:00 +01:00
"svc_pings",
2010-08-16 22:00:00 +02:00
"svc_particle",
2012-05-13 22:00:00 +02:00
"svc_restoresound",
2010-08-16 22:00:00 +02:00
"svc_spawnstatic",
2010-10-26 22:00:00 +02:00
"svc_event_reliable",
2010-08-16 22:00:00 +02:00
"svc_spawnbaseline",
"svc_temp_entity",
2009-11-10 22:00:00 +01:00
"svc_setpause",
2011-04-08 22:00:00 +02:00
"svc_signonnum",
2010-08-16 22:00:00 +02:00
"svc_centerprint",
2017-02-07 22:00:00 +01:00
"svc_modelindex",
2010-10-26 22:00:00 +02:00
"svc_soundindex",
2010-10-17 22:00:00 +02:00
"svc_ambientsound",
2010-08-16 22:00:00 +02:00
"svc_intermission",
2017-06-23 23:00:00 +02:00
"svc_finale",
2010-08-16 22:00:00 +02:00
"svc_cdtrack",
2017-02-07 22:00:00 +01:00
"svc_restore",
2017-06-23 23:00:00 +02:00
"svc_cutscene",
2010-08-16 22:00:00 +02:00
"svc_weaponanim",
"svc_bspdecal",
"svc_roomtype",
2010-10-14 22:00:00 +02:00
"svc_addangle",
2010-10-19 22:00:00 +02:00
"svc_usermessage",
2010-10-14 22:00:00 +02:00
"svc_packetentities",
"svc_deltapacketentities",
2017-03-02 22:00:00 +01:00
"svc_choke",
2011-07-07 22:00:00 +02:00
"svc_resourcelist",
2010-10-26 22:00:00 +02:00
"svc_deltamovevars",
2017-02-07 22:00:00 +01:00
"svc_resourcerequest",
2011-07-07 22:00:00 +02:00
"svc_customization",
2010-10-19 22:00:00 +02:00
"svc_crosshairangle",
"svc_soundfade",
2017-02-07 22:00:00 +01:00
"svc_filetxferfailed",
"svc_hltv",
2010-08-16 22:00:00 +02:00
"svc_director",
2011-12-24 21:00:00 +01:00
"svc_studiodecal",
2017-02-07 22:00:00 +01:00
"svc_voicedata",
2017-06-23 23:00:00 +02:00
"svc_eventindex",
2012-12-23 21:00:00 +01:00
"svc_unused55",
2017-02-07 22:00:00 +01:00
"svc_resourcelocation",
2012-12-23 21:00:00 +01:00
"svc_querycvarvalue",
"svc_querycvarvalue2",
2009-10-13 22:00:00 +02:00
};
2010-03-27 22:00:00 +01:00
typedef struct
{
int command;
int starting_offset;
int frame_number;
} oldcmd_t;
typedef struct
{
oldcmd_t oldcmd[MSG_COUNT];
int currentcmd;
2010-10-26 22:00:00 +02:00
qboolean parsing;
2010-03-27 22:00:00 +01:00
} msg_debug_t;
2011-07-07 22:00:00 +02:00
static msg_debug_t cls_message_debug;
static int starting_count;
static resourcelist_t reslist;
2010-03-27 22:00:00 +01:00
const char *CL_MsgInfo( int cmd )
{
static string sz;
2011-03-09 22:00:00 +01:00
Q_strcpy( sz, "???" );
2010-03-27 22:00:00 +01:00
2017-02-07 22:00:00 +01:00
if( cmd >= 0 && cmd <= svc_lastmsg )
2010-03-27 22:00:00 +01:00
{
// get engine message name
2011-03-09 22:00:00 +01:00
Q_strncpy( sz, svc_strings[cmd], sizeof( sz ));
2010-03-27 22:00:00 +01:00
}
2017-02-07 22:00:00 +01:00
else if( cmd > svc_lastmsg && cmd <= ( svc_lastmsg + MAX_USER_MESSAGES ))
2010-03-27 22:00:00 +01:00
{
2010-08-16 22:00:00 +02:00
int i;
for( i = 0; i < MAX_USER_MESSAGES; i++ )
{
if( clgame.msg[i].number == cmd )
{
2011-03-09 22:00:00 +01:00
Q_strncpy( sz, clgame.msg[i].name, sizeof( sz ));
2010-08-16 22:00:00 +02:00
break;
}
}
2010-03-27 22:00:00 +01:00
}
return sz;
}
/*
=====================
CL_Parse_RecordCommand
record new message params into debug buffer
=====================
*/
void CL_Parse_RecordCommand( int cmd, int startoffset )
{
int slot;
if( cmd == svc_nop ) return;
slot = ( cls_message_debug.currentcmd++ & MSG_MASK );
cls_message_debug.oldcmd[slot].command = cmd;
cls_message_debug.oldcmd[slot].starting_offset = startoffset;
cls_message_debug.oldcmd[slot].frame_number = host.framecount;
}
/*
=====================
CL_WriteErrorMessage
write net_message into buffer.dat for debugging
=====================
*/
2010-08-06 22:00:00 +02:00
void CL_WriteErrorMessage( int current_count, sizebuf_t *msg )
2010-03-27 22:00:00 +01:00
{
const char *buffer_file = "buffer.dat";
2017-01-14 22:00:00 +01:00
file_t *fp;
2011-03-08 22:00:00 +01:00
fp = FS_Open( buffer_file, "wb", false );
2010-03-27 22:00:00 +01:00
if( !fp ) return;
FS_Write( fp, &starting_count, sizeof( int ));
FS_Write( fp, &current_count, sizeof( int ));
2016-11-14 22:00:00 +01:00
FS_Write( fp, MSG_GetData( msg ), MSG_GetMaxBytes( msg ));
2010-03-27 22:00:00 +01:00
FS_Close( fp );
MsgDev( D_INFO, "Wrote erroneous message to %s\n", buffer_file );
}
/*
=====================
CL_WriteMessageHistory
list last 32 messages for debugging net troubleshooting
=====================
*/
void CL_WriteMessageHistory( void )
{
int i, thecmd;
oldcmd_t *old, *failcommand;
2010-08-06 22:00:00 +02:00
sizebuf_t *msg = &net_message;
2010-03-27 22:00:00 +01:00
if( !cls.initialized || cls.state == ca_disconnected )
return;
if( !cls_message_debug.parsing )
return;
MsgDev( D_INFO, "Last %i messages parsed.\n", MSG_COUNT );
// finish here
thecmd = cls_message_debug.currentcmd - 1;
thecmd -= ( MSG_COUNT - 1 ); // back up to here
for( i = 0; i < MSG_COUNT - 1; i++ )
{
2010-10-14 22:00:00 +02:00
thecmd &= MSG_MASK;
2010-03-27 22:00:00 +01:00
old = &cls_message_debug.oldcmd[thecmd];
2010-03-28 22:00:00 +02:00
MsgDev( D_INFO,"%i %04i %s\n", old->frame_number, old->starting_offset, CL_MsgInfo( old->command ));
2010-03-27 22:00:00 +01:00
thecmd++;
}
failcommand = &cls_message_debug.oldcmd[thecmd];
2016-11-14 22:00:00 +01:00
MsgDev( D_INFO, "BAD: %3i:%s\n", MSG_GetNumBytesRead( msg ) - 1, CL_MsgInfo( failcommand->command ));
2010-03-27 22:00:00 +01:00
if( host.developer >= 3 )
{
2016-11-14 22:00:00 +01:00
CL_WriteErrorMessage( MSG_GetNumBytesRead( msg ) - 1, msg );
2010-03-27 22:00:00 +01:00
}
cls_message_debug.parsing = false;
}
2011-01-11 22:00:00 +01:00
/*
===============
CL_UserMsgStub
Default stub for missed callbacks
===============
*/
int CL_UserMsgStub( const char *pszName, int iSize, void *pbuf )
{
return 1;
}
2017-02-21 22:00:00 +01:00
/*
==================
CL_ParseViewEntity
==================
*/
void CL_ParseViewEntity( sizebuf_t *msg )
{
cl.viewentity = MSG_ReadWord( msg );
// check entity bounds in case we want
// to use this directly in clgame.entities[] array
cl.viewentity = bound( 0, cl.viewentity, clgame.maxEntities - 1 );
}
2008-12-21 22:00:00 +01:00
/*
==================
CL_ParseSoundPacket
==================
*/
2017-02-07 22:00:00 +01:00
void CL_ParseSoundPacket( sizebuf_t *msg )
2008-12-21 22:00:00 +01:00
{
2011-04-05 22:00:00 +02:00
vec3_t pos;
2010-04-24 22:00:00 +02:00
int chan, sound;
float volume, attn;
2008-12-21 22:00:00 +01:00
int flags, pitch, entnum;
2010-08-30 22:00:00 +02:00
sound_t handle = 0;
2008-12-21 22:00:00 +01:00
2017-02-07 22:00:00 +01:00
flags = MSG_ReadUBitLong( msg, MAX_SND_FLAGS_BITS );
sound = MSG_ReadUBitLong( msg, MAX_SOUND_BITS );
chan = MSG_ReadUBitLong( msg, MAX_SND_CHAN_BITS );
2008-12-21 22:00:00 +01:00
2009-09-29 22:00:00 +02:00
if( flags & SND_VOLUME )
2016-11-14 22:00:00 +01:00
volume = (float)MSG_ReadByte( msg ) / 255.0f;
2009-09-29 22:00:00 +02:00
else volume = VOL_NORM;
2010-04-21 22:00:00 +02:00
2010-04-24 22:00:00 +02:00
if( flags & SND_ATTENUATION )
2016-11-14 22:00:00 +01:00
attn = (float)MSG_ReadByte( msg ) / 64.0f;
2010-04-24 22:00:00 +02:00
else attn = ATTN_NONE;
2010-04-21 22:00:00 +02:00
2008-12-21 22:00:00 +01:00
if( flags & SND_PITCH )
2016-11-14 22:00:00 +01:00
pitch = MSG_ReadByte( msg );
2008-12-21 22:00:00 +01:00
else pitch = PITCH_NORM;
// entity reletive
2017-02-07 22:00:00 +01:00
entnum = MSG_ReadUBitLong( msg, MAX_ENTITY_BITS );
2008-12-21 22:00:00 +01:00
2009-09-29 22:00:00 +02:00
// positioned in space
2016-11-14 22:00:00 +01:00
MSG_ReadVec3Coord( msg, pos );
2010-04-21 22:00:00 +02:00
2010-06-27 22:00:00 +02:00
if( flags & SND_SENTENCE )
{
char sentenceName[32];
2017-02-07 22:00:00 +01:00
if( flags & SND_SEQUENCE )
Q_snprintf( sentenceName, sizeof( sentenceName ), "!#%i", sound );
else Q_snprintf( sentenceName, sizeof( sentenceName ), "!%i", sound );
2010-06-27 22:00:00 +02:00
handle = S_RegisterSound( sentenceName );
}
2010-10-26 22:00:00 +02:00
else handle = cl.sound_index[sound]; // see precached sound
2010-06-27 22:00:00 +02:00
2016-08-12 23:00:00 +02:00
if( !cl.audio_prepped )
2017-02-07 22:00:00 +01:00
{
MsgDev( D_WARN, "CL_StartSoundPacket: ignore sound message: too early\n" );
2016-08-12 23:00:00 +02:00
return; // too early
2017-02-07 22:00:00 +01:00
}
2016-08-12 23:00:00 +02:00
2017-02-07 22:00:00 +01:00
if( chan == CHAN_STATIC )
2010-04-24 22:00:00 +02:00
{
2010-12-25 22:00:00 +01:00
S_AmbientSound( pos, entnum, handle, volume, attn, pitch, flags );
2010-04-24 22:00:00 +02:00
}
else
{
2010-06-27 22:00:00 +02:00
S_StartSound( pos, entnum, chan, handle, volume, attn, pitch, flags );
2010-04-24 22:00:00 +02:00
}
2008-12-21 22:00:00 +01:00
}
2012-05-13 22:00:00 +02:00
/*
==================
CL_ParseRestoreSoundPacket
==================
*/
void CL_ParseRestoreSoundPacket( sizebuf_t *msg )
{
vec3_t pos;
int chan, sound;
float volume, attn;
int flags, pitch, entnum;
double samplePos, forcedEnd;
int wordIndex;
sound_t handle = 0;
2017-02-07 22:00:00 +01:00
flags = MSG_ReadUBitLong( msg, MAX_SND_FLAGS_BITS );
sound = MSG_ReadUBitLong( msg, MAX_SOUND_BITS );
chan = MSG_ReadUBitLong( msg, MAX_SND_CHAN_BITS );
2012-05-13 22:00:00 +02:00
if( flags & SND_VOLUME )
2016-11-14 22:00:00 +01:00
volume = (float)MSG_ReadByte( msg ) / 255.0f;
2012-05-13 22:00:00 +02:00
else volume = VOL_NORM;
if( flags & SND_ATTENUATION )
2016-11-14 22:00:00 +01:00
attn = (float)MSG_ReadByte( msg ) / 64.0f;
2012-05-13 22:00:00 +02:00
else attn = ATTN_NONE;
if( flags & SND_PITCH )
2016-11-14 22:00:00 +01:00
pitch = MSG_ReadByte( msg );
2012-05-13 22:00:00 +02:00
else pitch = PITCH_NORM;
2017-02-07 22:00:00 +01:00
// entity reletive
entnum = MSG_ReadUBitLong( msg, MAX_ENTITY_BITS );
// positioned in space
MSG_ReadVec3Coord( msg, pos );
2012-05-14 22:00:00 +02:00
if( flags & SND_SENTENCE )
{
char sentenceName[32];
2017-02-07 22:00:00 +01:00
if( flags & SND_SEQUENCE )
Q_snprintf( sentenceName, sizeof( sentenceName ), "!#%i", sound );
else Q_snprintf( sentenceName, sizeof( sentenceName ), "!%i", sound );
2012-05-14 22:00:00 +02:00
handle = S_RegisterSound( sentenceName );
}
else handle = cl.sound_index[sound]; // see precached sound
2012-05-13 22:00:00 +02:00
2016-11-14 22:00:00 +01:00
wordIndex = MSG_ReadByte( msg );
2012-05-13 22:00:00 +02:00
2012-12-16 21:00:00 +01:00
// 16 bytes here
2016-11-14 22:00:00 +01:00
MSG_ReadBytes( msg, &samplePos, sizeof( samplePos ));
MSG_ReadBytes( msg, &forcedEnd, sizeof( forcedEnd ));
2012-05-13 22:00:00 +02:00
2017-02-07 22:00:00 +01:00
if( !cl.audio_prepped )
{
MsgDev( D_WARN, "CL_RestoreSoundPacket: ignore sound message: too early\n" );
return; // too early
}
2012-05-14 22:00:00 +02:00
S_RestoreSound( pos, entnum, chan, handle, volume, attn, pitch, flags, samplePos, forcedEnd, wordIndex );
2012-05-13 22:00:00 +02:00
}
2016-11-14 22:00:00 +01:00
/*
==================
CL_ParseServerTime
==================
*/
void CL_ParseServerTime( sizebuf_t *msg )
{
2017-01-21 22:00:00 +01:00
double dt;
2016-11-14 22:00:00 +01:00
cl.mtime[1] = cl.mtime[0];
cl.mtime[0] = MSG_ReadFloat( msg );
2017-01-21 22:00:00 +01:00
if( cl.maxclients == 1 )
cl.time = cl.mtime[0];
dt = cl.time - cl.mtime[0];
if( fabs( dt ) > cl_clockreset->value ) // 0.1 by default
{
cl.time = cl.mtime[0];
cl.timedelta = 0.0f;
}
else if( dt != 0.0 )
{
cl.timedelta = dt;
}
if( cl.oldtime > cl.time )
cl.oldtime = cl.time;
2016-11-14 22:00:00 +01:00
}
2017-02-13 22:00:00 +01:00
/*
==================
CL_ParseSignon
==================
*/
void CL_ParseSignon( sizebuf_t *msg )
{
int i = MSG_ReadByte( msg );
if( i <= cls.signon )
{
MsgDev( D_ERROR, "received signon %i when at %i\n", i, cls.signon );
CL_Disconnect();
return;
}
cls.signon = i;
CL_SignonReply();
}
2009-11-10 22:00:00 +01:00
/*
==================
CL_ParseMovevars
==================
*/
2010-08-06 22:00:00 +02:00
void CL_ParseMovevars( sizebuf_t *msg )
2009-11-10 22:00:00 +01:00
{
2011-04-17 22:00:00 +02:00
Delta_InitClient (); // finalize client delta's
2010-08-06 22:00:00 +02:00
MSG_ReadDeltaMovevars( msg, &clgame.oldmovevars, &clgame.movevars );
2010-08-18 22:00:00 +02:00
// update sky if changed
2011-03-09 22:00:00 +01:00
if( Q_strcmp( clgame.oldmovevars.skyName, clgame.movevars.skyName ) && cl.video_prepped )
2010-12-02 22:00:00 +01:00
R_SetupSky( clgame.movevars.skyName );
2010-08-18 22:00:00 +02:00
2016-11-17 22:00:00 +01:00
memcpy( &clgame.oldmovevars, &clgame.movevars, sizeof( movevars_t ));
2017-02-15 22:00:00 +01:00
clgame.entities->curstate.scale = clgame.movevars.waveHeight;
2012-05-21 22:00:00 +02:00
// keep features an actual!
clgame.oldmovevars.features = clgame.movevars.features = host.features;
2009-11-10 22:00:00 +01:00
}
2009-11-23 22:00:00 +01:00
/*
==================
CL_ParseParticles
==================
*/
2010-08-06 22:00:00 +02:00
void CL_ParseParticles( sizebuf_t *msg )
2009-11-23 22:00:00 +01:00
{
vec3_t org, dir;
int i, count, color;
2011-02-16 22:00:00 +01:00
float life;
2009-11-23 22:00:00 +01:00
2016-11-14 22:00:00 +01:00
MSG_ReadVec3Coord( msg, org );
2009-11-23 22:00:00 +01:00
for( i = 0; i < 3; i++ )
2017-02-05 22:00:00 +01:00
dir[i] = MSG_ReadChar( msg ) * 0.0625f;
2009-11-23 22:00:00 +01:00
2016-11-14 22:00:00 +01:00
count = MSG_ReadByte( msg );
color = MSG_ReadByte( msg );
2010-03-15 22:00:00 +01:00
if( count == 255 ) count = 1024;
2016-11-14 22:00:00 +01:00
life = MSG_ReadByte( msg ) * 0.125f;
2009-11-23 22:00:00 +01:00
2011-02-16 22:00:00 +01:00
if( life != 0.0f && count == 1 )
{
particle_t *p;
2017-02-21 22:00:00 +01:00
p = R_AllocParticle( NULL );
2011-02-16 22:00:00 +01:00
if( !p ) return;
p->die += life;
p->color = color;
p->type = pt_static;
VectorCopy( org, p->org );
VectorCopy( dir, p->vel );
}
2017-02-21 22:00:00 +01:00
else R_RunParticleEffect( org, dir, color, count );
2009-11-23 22:00:00 +01:00
}
2010-10-17 22:00:00 +02:00
/*
==================
CL_ParseStaticEntity
2012-12-23 21:00:00 +01:00
static client entity
2010-10-17 22:00:00 +02:00
==================
*/
void CL_ParseStaticEntity( sizebuf_t *msg )
{
2011-10-06 22:00:00 +02:00
entity_state_t state;
cl_entity_t *ent;
2010-10-17 22:00:00 +02:00
int i;
2016-11-17 22:00:00 +01:00
memset( &state, 0, sizeof( state ));
2010-10-17 22:00:00 +02:00
2016-11-14 22:00:00 +01:00
state.modelindex = MSG_ReadShort( msg );
state.sequence = MSG_ReadByte( msg );
state.frame = MSG_ReadByte( msg );
state.colormap = MSG_ReadWord( msg );
state.skin = MSG_ReadByte( msg );
2010-10-17 22:00:00 +02:00
for( i = 0; i < 3; i++ )
{
2016-11-14 22:00:00 +01:00
state.origin[i] = MSG_ReadCoord( msg );
state.angles[i] = MSG_ReadBitAngle( msg, 16 );
2010-10-17 22:00:00 +02:00
}
2016-11-14 22:00:00 +01:00
state.rendermode = MSG_ReadByte( msg );
2010-10-17 22:00:00 +02:00
2011-10-06 22:00:00 +02:00
if( state.rendermode != kRenderNormal )
2010-10-17 22:00:00 +02:00
{
2016-11-14 22:00:00 +01:00
state.renderamt = MSG_ReadByte( msg );
state.rendercolor.r = MSG_ReadByte( msg );
state.rendercolor.g = MSG_ReadByte( msg );
state.rendercolor.b = MSG_ReadByte( msg );
state.renderfx = MSG_ReadByte( msg );
2010-10-17 22:00:00 +02:00
}
2011-10-06 22:00:00 +02:00
i = clgame.numStatics;
if( i >= MAX_STATIC_ENTITIES )
{
MsgDev( D_ERROR, "CL_ParseStaticEntity: static entities limit exceeded!\n" );
return;
}
ent = &clgame.static_entities[i];
clgame.numStatics++;
ent->index = 0; // ???
ent->baseline = state;
ent->curstate = state;
ent->prevstate = state;
2013-10-30 21:00:00 +01:00
// statics may be respawned in game e.g. for demo recording
if( cls.state == ca_connected )
ent->trivial_accept = INVALID_HANDLE;
2011-10-06 22:00:00 +02:00
// setup the new static entity
2017-02-21 22:00:00 +01:00
VectorCopy( ent->curstate.origin, ent->origin );
VectorCopy( ent->curstate.angles, ent->angles );
ent->model = Mod_Handle( state.modelindex );
ent->curstate.framerate = 1.0f;
CL_ResetLatchedVars( ent, true );
2011-10-06 22:00:00 +02:00
2017-08-12 23:00:00 +02:00
if( ent->curstate.rendermode == kRenderNormal && ent->model != NULL )
{
// auto 'solid' faces
if( FBitSet( ent->model->flags, MODEL_TRANSPARENT ) && FBitSet( host.features, ENGINE_QUAKE_COMPATIBLE ))
{
ent->curstate.rendermode = kRenderTransAlpha;
ent->curstate.renderamt = 255;
}
}
2017-02-21 22:00:00 +01:00
R_AddEfrags( ent ); // add link
}
2011-10-06 22:00:00 +02:00
2017-02-21 22:00:00 +01:00
/*
==================
CL_WeaponAnim
Set new weapon animation
==================
*/
void CL_WeaponAnim( int iAnim, int body )
{
cl_entity_t *view = &clgame.viewent;
2017-08-14 23:00:00 +02:00
2017-03-11 22:00:00 +01:00
cl.local.weaponstarttime = 0.0f;
2017-02-21 22:00:00 +01:00
cl.local.weaponsequence = iAnim;
view->curstate.framerate = 1.0f;
view->curstate.body = body;
2017-03-06 22:00:00 +01:00
#if 0 // g-cont. for GlowShell testing
2017-02-21 22:00:00 +01:00
view->curstate.renderfx = kRenderFxGlowShell;
view->curstate.rendercolor.r = 255;
view->curstate.rendercolor.g = 128;
view->curstate.rendercolor.b = 0;
2017-03-06 22:00:00 +01:00
view->curstate.renderamt = 150;
2017-02-21 22:00:00 +01:00
#endif
2010-10-17 22:00:00 +02:00
}
2009-11-23 22:00:00 +01:00
/*
==================
CL_ParseStaticDecal
==================
*/
2010-08-06 22:00:00 +02:00
void CL_ParseStaticDecal( sizebuf_t *msg )
2009-11-23 22:00:00 +01:00
{
2013-10-23 22:00:00 +02:00
vec3_t origin;
int decalIndex, entityIndex, modelIndex;
cl_entity_t *ent = NULL;
float scale;
int flags;
2009-11-23 22:00:00 +01:00
2016-11-14 22:00:00 +01:00
MSG_ReadVec3Coord( msg, origin );
decalIndex = MSG_ReadWord( msg );
entityIndex = MSG_ReadShort( msg );
2009-11-25 22:00:00 +01:00
2010-07-02 22:00:00 +02:00
if( entityIndex > 0 )
2016-11-14 22:00:00 +01:00
modelIndex = MSG_ReadWord( msg );
2010-06-30 22:00:00 +02:00
else modelIndex = 0;
2016-11-14 22:00:00 +01:00
flags = MSG_ReadByte( msg );
scale = (float)MSG_ReadWord( msg ) / 4096.0f;
2009-11-23 22:00:00 +01:00
2014-01-01 21:00:00 +01:00
CL_FireCustomDecal( CL_DecalIndex( decalIndex ), entityIndex, modelIndex, origin, flags, scale );
2009-11-23 22:00:00 +01:00
}
2011-10-09 22:00:00 +02:00
/*
==================
CL_ParseSoundFade
==================
*/
2010-08-06 22:00:00 +02:00
void CL_ParseSoundFade( sizebuf_t *msg )
2009-11-25 22:00:00 +01:00
{
float fadePercent, fadeOutSeconds;
float holdTime, fadeInSeconds;
2016-11-14 22:00:00 +01:00
fadePercent = (float)MSG_ReadByte( msg );
holdTime = (float)MSG_ReadByte( msg );
fadeOutSeconds = (float)MSG_ReadByte( msg );
fadeInSeconds = (float)MSG_ReadByte( msg );
2009-11-25 22:00:00 +01:00
S_FadeClientVolume( fadePercent, fadeOutSeconds, holdTime, fadeInSeconds );
}
2013-01-11 21:00:00 +01:00
/*
==================
CL_ParseCustomization
==================
*/
2011-07-07 22:00:00 +02:00
void CL_ParseCustomization( sizebuf_t *msg )
{
2011-08-14 22:00:00 +02:00
// TODO: ???
2011-07-07 22:00:00 +02:00
}
2007-06-21 22:00:00 +02:00
/*
=====================================================================
SERVER CONNECTING MESSAGES
=====================================================================
*/
/*
==================
CL_ParseServerData
==================
*/
2010-08-06 22:00:00 +02:00
void CL_ParseServerData( sizebuf_t *msg )
2007-06-21 22:00:00 +02:00
{
2011-03-13 22:00:00 +01:00
string gamefolder;
2014-05-09 22:00:00 +02:00
qboolean background;
2010-03-28 22:00:00 +02:00
int i;
2007-10-19 22:00:00 +02:00
2009-09-28 22:00:00 +02:00
MsgDev( D_NOTE, "Serverdata packet received.\n" );
2010-12-13 22:00:00 +01:00
2012-03-01 21:00:00 +01:00
cls.demowaiting = false; // server is changed
clgame.load_sequence++; // now all hud sprites are invalid
2008-07-11 22:00:00 +02:00
2007-11-04 22:00:00 +01:00
// wipe the client_t struct
2012-08-29 22:00:00 +02:00
if( !cls.changelevel && !cls.changedemo )
2012-04-06 22:00:00 +02:00
CL_ClearState ();
2007-06-21 22:00:00 +02:00
cls.state = ca_connected;
2007-09-10 22:00:00 +02:00
// parse protocol version number
2016-11-14 22:00:00 +01:00
i = MSG_ReadLong( msg );
2007-06-21 22:00:00 +02:00
cls.serverProtocol = i;
2008-08-02 22:00:00 +02:00
if( i != PROTOCOL_VERSION )
2009-06-24 22:00:00 +02:00
Host_Error( "Server use invalid protocol (%i should be %i)\n", i, PROTOCOL_VERSION );
2007-06-21 22:00:00 +02:00
2016-11-14 22:00:00 +01:00
cl.servercount = MSG_ReadLong( msg );
cl.checksum = MSG_ReadLong( msg );
cl.playernum = MSG_ReadByte( msg );
cl.maxclients = MSG_ReadByte( msg );
clgame.maxEntities = MSG_ReadWord( msg );
2017-08-12 23:00:00 +02:00
clgame.maxEntities = bound( 600, clgame.maxEntities, MAX_EDICTS );
2016-11-14 22:00:00 +01:00
Q_strncpy( clgame.mapname, MSG_ReadString( msg ), MAX_STRING );
Q_strncpy( clgame.maptitle, MSG_ReadString( msg ), MAX_STRING );
background = MSG_ReadOneBit( msg );
Q_strncpy( gamefolder, MSG_ReadString( msg ), MAX_STRING );
host.features = (uint)MSG_ReadLong( msg );
2011-03-13 22:00:00 +01:00
2017-07-16 23:00:00 +02:00
if( Con_FixedFont( ))
{
// seperate the printfs so the server message can have a color
Con_Print( "\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" );
Con_Print( va( "%c%s\n\n", 2, clgame.maptitle ));
}
2017-03-08 22:00:00 +01:00
// receive the player hulls
for( i = 0; i < MAX_MAP_HULLS * 3; i++ )
{
host.player_mins[i/3][i%3] = MSG_ReadChar( msg );
host.player_maxs[i/3][i%3] = MSG_ReadChar( msg );
}
2012-02-08 21:00:00 +01:00
if( cl.maxclients > 1 && host.developer < 1 )
host.developer++;
2017-02-21 22:00:00 +01:00
// multiplayer game?
if( cl.maxclients != 1 )
{
if( r_decals->value > mp_decals.value )
Cvar_SetValue( "r_decals", mp_decals.value );
}
else Cvar_Reset( "r_decals" );
2014-05-09 22:00:00 +02:00
// set the background state
if( cls.demoplayback && ( cls.demonum != -1 ))
{
// re-init mouse
host.mouse_visible = false;
cl.background = true;
}
else cl.background = background;
if( cl.background ) // tell the game parts about background state
2017-02-12 22:00:00 +01:00
Cvar_FullSet( "cl_background", "1", FCVAR_READ_ONLY );
else Cvar_FullSet( "cl_background", "0", FCVAR_READ_ONLY );
2014-05-09 22:00:00 +02:00
2011-04-01 22:00:00 +02:00
if( !cls.changelevel )
{
// continue playing if we are changing level
S_StopBackgroundTrack ();
}
2011-04-17 22:00:00 +02:00
#if 0
// NOTE: this is not tested as well. Use with precaution
CL_ChangeGame( gamefolder, false );
#endif
2014-05-09 22:00:00 +02:00
if( !cls.changedemo )
UI_SetActiveMenu( cl.background );
2014-09-05 22:00:00 +02:00
else if( !cls.demoplayback )
Key_SetKeyDest( key_menu );
2011-02-26 22:00:00 +01:00
2017-02-15 22:00:00 +01:00
cl.viewentity = cl.playernum + 1; // always keep viewent an actual
2010-03-28 22:00:00 +02:00
2016-11-17 22:00:00 +01:00
gameui.globals->maxClients = cl.maxclients;
Q_strncpy( gameui.globals->maptitle, clgame.maptitle, sizeof( gameui.globals->maptitle ));
2010-07-18 22:00:00 +02:00
2012-08-29 22:00:00 +02:00
if( !cls.changelevel && !cls.changedemo )
CL_InitEdicts (); // re-arrange edicts
2009-11-27 22:00:00 +01:00
2008-08-02 22:00:00 +02:00
// get splash name
2014-05-09 22:00:00 +02:00
if( cls.demoplayback && ( cls.demonum != -1 ))
Cvar_Set( "cl_levelshot_name", va( "levelshots/%s_%s", cls.demoname, glState.wideScreen ? "16x9" : "4x3" ));
else Cvar_Set( "cl_levelshot_name", va( "levelshots/%s_%s", clgame.mapname, glState.wideScreen ? "16x9" : "4x3" ));
2017-02-12 22:00:00 +01:00
Cvar_SetValue( "scr_loading", 0.0f ); // reset progress bar
2009-07-27 22:00:00 +02:00
2017-02-12 22:00:00 +01:00
if(( cl_allow_levelshots->value && !cls.changelevel ) || cl.background )
2007-06-21 22:00:00 +02:00
{
2011-03-08 22:00:00 +01:00
if( !FS_FileExists( va( "%s.bmp", cl_levelshot_name->string ), true ))
2014-05-09 22:00:00 +02:00
Cvar_Set( "cl_levelshot_name", "*black" ); // render a black screen
cls.scrshot_request = scrshot_plaque; // request levelshot even if exist (check filetime)
2007-06-21 22:00:00 +02:00
}
2010-03-10 22:00:00 +01:00
2017-02-12 22:00:00 +01:00
if( scr_dark->value )
2010-10-31 22:00:00 +01:00
{
2011-01-03 22:00:00 +01:00
screenfade_t *sf = &clgame.fade;
client_textmessage_t *title;
title = CL_TextMessageGet( "GAMETITLE" );
if( title )
{
// get settings from titles.txt
sf->fadeEnd = title->holdtime + title->fadeout;
sf->fadeReset = title->fadeout;
}
2017-09-02 23:00:00 +02:00
else sf->fadeEnd = sf->fadeReset = 5.0f;
2010-10-31 22:00:00 +01:00
sf->fadeFlags = FFADE_IN;
sf->fader = sf->fadeg = sf->fadeb = 0;
sf->fadealpha = 255;
2011-01-03 22:00:00 +01:00
sf->fadeSpeed = (float)sf->fadealpha / sf->fadeReset;
2010-10-31 22:00:00 +01:00
sf->fadeReset += cl.time;
sf->fadeEnd += sf->fadeReset;
2017-02-12 22:00:00 +01:00
Cvar_SetValue( "v_dark", 0.0f );
2010-10-31 22:00:00 +01:00
}
2008-08-02 22:00:00 +02:00
// need to prep refresh at next oportunity
2008-08-03 22:00:00 +02:00
cl.video_prepped = false;
cl.audio_prepped = false;
2009-11-28 22:00:00 +01:00
2016-11-17 22:00:00 +01:00
memset( &clgame.movevars, 0, sizeof( clgame.movevars ));
memset( &clgame.oldmovevars, 0, sizeof( clgame.oldmovevars ));
2017-07-16 23:00:00 +02:00
memset( &clgame.centerPrint, 0, sizeof( clgame.centerPrint ));
2007-06-21 22:00:00 +02:00
}
2010-10-14 22:00:00 +02:00
/*
===================
CL_ParseClientData
===================
*/
void CL_ParseClientData( sizebuf_t *msg )
{
2016-03-17 22:00:00 +01:00
float parsecounttime;
2017-03-12 22:00:00 +01:00
int i, j, command_ack;
2010-10-14 22:00:00 +02:00
clientdata_t *from_cd, *to_cd;
weapon_data_t *from_wd, *to_wd;
2016-03-17 22:00:00 +01:00
weapon_data_t nullwd[64];
2010-10-14 22:00:00 +02:00
clientdata_t nullcd;
frame_t *frame;
int idx;
2016-03-17 22:00:00 +01:00
// This is the last movement that the server ack'd
command_ack = cls.netchan.incoming_acknowledged;
2010-10-14 22:00:00 +02:00
// this is the frame update that this message corresponds to
i = cls.netchan.incoming_sequence;
// did we drop some frames?
if( i > cl.last_incoming_sequence + 1 )
{
// mark as dropped
for( j = cl.last_incoming_sequence + 1; j < i; j++ )
{
if( cl.frames[j & CL_UPDATE_MASK].receivedtime >= 0.0 )
{
2017-02-05 22:00:00 +01:00
cl.frames[j & CL_UPDATE_MASK].receivedtime = -1.0f;
2011-03-28 22:00:00 +02:00
cl.frames[j & CL_UPDATE_MASK].latency = 0;
2010-10-14 22:00:00 +02:00
}
}
}
cl.parsecount = i; // ack'd incoming messages.
cl.parsecountmod = cl.parsecount & CL_UPDATE_MASK; // index into window.
frame = &cl.frames[cl.parsecountmod]; // frame at index.
frame->time = cl.mtime[0]; // mark network received time
frame->receivedtime = host.realtime; // time now that we are parsing.
2017-03-02 22:00:00 +01:00
memset( &frame->graphdata, 0, sizeof( netbandwidthgraph_t ));
2016-03-17 22:00:00 +01:00
// send time for that frame.
parsecounttime = cl.commands[command_ack & CL_UPDATE_MASK].senttime;
// current time that we got a response to the command packet.
cl.commands[command_ack & CL_UPDATE_MASK].receivedtime = host.realtime;
2015-07-08 23:00:00 +02:00
if( cl.last_command_ack != -1 )
{
2016-03-17 22:00:00 +01:00
int last_predicted;
clientdata_t *pcd, *ppcd;
entity_state_t *ps, *pps;
weapon_data_t *wd, *pwd;
2015-07-08 23:00:00 +02:00
2017-02-12 22:00:00 +01:00
if( !cls.spectator )
{
last_predicted = ( cl.last_incoming_sequence + ( command_ack - cl.last_command_ack )) & CL_UPDATE_MASK;
2015-07-08 23:00:00 +02:00
2017-02-15 22:00:00 +01:00
pps = &cl.predicted_frames[last_predicted].playerstate;
pwd = cl.predicted_frames[last_predicted].weapondata;
ppcd = &cl.predicted_frames[last_predicted].client;
2015-07-08 23:00:00 +02:00
2017-02-12 22:00:00 +01:00
ps = &frame->playerstate[cl.playernum];
wd = frame->weapondata;
2017-02-21 22:00:00 +01:00
pcd = &frame->clientdata;
2017-02-12 22:00:00 +01:00
}
else
{
ps = &cls.spectator_state.playerstate;
pps = &cls.spectator_state.playerstate;
pcd = &cls.spectator_state.client;
ppcd = &cls.spectator_state.client;
wd = cls.spectator_state.weapondata;
pwd = cls.spectator_state.weapondata;
}
2015-07-08 23:00:00 +02:00
clgame.dllFuncs.pfnTxferPredictionData( ps, pps, pcd, ppcd, wd, pwd );
}
2011-02-20 22:00:00 +01:00
// do this after all packets read for this frame?
2015-07-08 23:00:00 +02:00
cl.last_command_ack = cls.netchan.incoming_acknowledged;
2010-10-14 22:00:00 +02:00
cl.last_incoming_sequence = cls.netchan.incoming_sequence;
2012-03-24 21:00:00 +01:00
2016-03-17 22:00:00 +01:00
if( !cls.demoplayback )
{
// calculate latency of this frame.
// sent time is set when usercmd is sent to server in CL_Move
// this is the # of seconds the round trip took.
float latency = host.realtime - parsecounttime;
// fill into frame latency
frame->latency = latency;
// negative latency makes no sense. Huge latency is a problem.
if( latency >= 0.0f && latency <= 2.0f )
{
// drift the average latency towards the observed latency
// if round trip was fastest so far, just use that for latency value
// otherwise, move in 1 ms steps toward observed channel latency.
if( latency < cls.latency )
cls.latency = latency;
else cls.latency += 0.001f; // drift up, so corrections are needed
}
}
else
{
frame->latency = 0.0f;
}
2017-02-12 22:00:00 +01:00
// clientdata for spectators ends here
if( cls.spectator )
{
2017-02-15 22:00:00 +01:00
cl.local.health = 1;
2017-02-12 22:00:00 +01:00
return;
}
2017-02-21 22:00:00 +01:00
to_cd = &frame->clientdata;
2016-03-17 22:00:00 +01:00
to_wd = frame->weapondata;
2010-10-14 22:00:00 +02:00
// clear to old value before delta parsing
2016-11-14 22:00:00 +01:00
if( MSG_ReadOneBit( msg ))
2010-10-14 22:00:00 +02:00
{
2016-11-14 22:00:00 +01:00
int delta_sequence = MSG_ReadByte( msg );
2016-03-17 22:00:00 +01:00
2017-02-21 22:00:00 +01:00
from_cd = &cl.frames[delta_sequence & CL_UPDATE_MASK].clientdata;
2016-03-17 22:00:00 +01:00
from_wd = cl.frames[delta_sequence & CL_UPDATE_MASK].weapondata;
2010-10-14 22:00:00 +02:00
}
else
{
2016-03-17 22:00:00 +01:00
memset( &nullcd, 0, sizeof( nullcd ));
memset( nullwd, 0, sizeof( nullwd ));
from_cd = &nullcd;
from_wd = nullwd;
2010-10-14 22:00:00 +02:00
}
2011-04-08 22:00:00 +02:00
MSG_ReadClientData( msg, from_cd, to_cd, cl.mtime[0] );
2010-10-14 22:00:00 +02:00
2016-03-17 22:00:00 +01:00
for( i = 0; i < 64; i++ )
2010-10-14 22:00:00 +02:00
{
// check for end of weapondata (and clientdata_t message)
2016-11-14 22:00:00 +01:00
if( !MSG_ReadOneBit( msg )) break;
2010-10-14 22:00:00 +02:00
// read the weapon idx
2016-11-14 22:00:00 +01:00
idx = MSG_ReadUBitLong( msg, MAX_WEAPON_BITS );
2010-10-14 22:00:00 +02:00
2011-04-08 22:00:00 +02:00
MSG_ReadWeaponData( msg, &from_wd[idx], &to_wd[idx], cl.mtime[0] );
2010-10-14 22:00:00 +02:00
}
2017-02-12 22:00:00 +01:00
// make a local copy of physinfo
2017-03-12 22:00:00 +01:00
Q_strncpy( cls.physinfo, frame->clientdata.physinfo, sizeof( cls.physinfo ));
2017-02-12 22:00:00 +01:00
2017-02-21 22:00:00 +01:00
cl.local.maxspeed = frame->clientdata.maxspeed;
cl.local.pushmsec = frame->clientdata.pushmsec;
cl.local.weapons = frame->clientdata.weapons;
cl.local.health = frame->clientdata.health;
2010-10-14 22:00:00 +02:00
}
2007-06-21 22:00:00 +02:00
/*
==================
CL_ParseBaseline
==================
*/
2010-08-06 22:00:00 +02:00
void CL_ParseBaseline( sizebuf_t *msg )
2007-06-21 22:00:00 +02:00
{
2010-08-18 22:00:00 +02:00
int newnum;
2010-10-09 22:00:00 +02:00
float timebase;
2010-08-07 22:00:00 +02:00
cl_entity_t *ent;
Delta_InitClient (); // finalize client delta's
2007-06-21 22:00:00 +02:00
2017-02-21 22:00:00 +01:00
newnum = MSG_ReadUBitLong( msg, MAX_ENTITY_BITS );
2008-07-01 22:00:00 +02:00
2009-11-27 22:00:00 +01:00
if( newnum < 0 ) Host_Error( "CL_SpawnEdict: invalid number %i\n", newnum );
2011-04-08 22:00:00 +02:00
if( newnum >= clgame.maxEntities ) Host_Error( "CL_AllocEdict: no free edicts\n" );
2009-11-27 22:00:00 +01:00
2011-04-06 22:00:00 +02:00
ent = CL_EDICT_NUM( newnum );
2016-11-17 22:00:00 +01:00
memset( &ent->prevstate, 0, sizeof( ent->prevstate ));
2010-12-25 22:00:00 +01:00
ent->index = newnum;
2010-08-18 22:00:00 +02:00
2010-08-04 22:00:00 +02:00
if( cls.state == ca_active )
2011-04-08 22:00:00 +02:00
timebase = cl.mtime[0];
2010-10-09 22:00:00 +02:00
else timebase = 1.0f; // sv.state == ss_loading
2010-08-04 22:00:00 +02:00
2010-10-20 22:00:00 +02:00
MSG_ReadDeltaEntity( msg, &ent->prevstate, &ent->baseline, newnum, CL_IsPlayerIndex( newnum ), timebase );
2007-06-21 22:00:00 +02:00
}
2010-10-28 22:00:00 +02:00
/*
================
CL_ParseLightStyle
================
*/
void CL_ParseLightStyle( sizebuf_t *msg )
{
int style;
const char *s;
2013-09-14 22:00:00 +02:00
float f;
2010-10-28 22:00:00 +02:00
2016-11-14 22:00:00 +01:00
style = MSG_ReadByte( msg );
s = MSG_ReadString( msg );
f = MSG_ReadFloat( msg );
2010-10-28 22:00:00 +02:00
2013-09-14 22:00:00 +02:00
CL_SetLightstyle( style, s, f );
2010-10-28 22:00:00 +02:00
}
2008-11-27 22:00:00 +01:00
/*
================
CL_ParseSetAngle
set the view angle to this absolute value
================
*/
2010-08-06 22:00:00 +02:00
void CL_ParseSetAngle( sizebuf_t *msg )
2008-11-27 22:00:00 +01:00
{
2017-02-15 22:00:00 +01:00
cl.viewangles[0] = MSG_ReadBitAngle( msg, 16 );
cl.viewangles[1] = MSG_ReadBitAngle( msg, 16 );
cl.viewangles[2] = MSG_ReadBitAngle( msg, 16 );
2008-11-27 22:00:00 +01:00
}
2007-06-21 22:00:00 +02:00
2010-04-12 22:00:00 +02:00
/*
================
CL_ParseAddAngle
add the view angle yaw
================
*/
2010-08-06 22:00:00 +02:00
void CL_ParseAddAngle( sizebuf_t *msg )
2010-04-12 22:00:00 +02:00
{
2017-08-24 23:00:00 +02:00
pred_viewangle_t *a;
float delta_yaw;
2010-04-12 22:00:00 +02:00
2017-08-24 23:00:00 +02:00
delta_yaw = MSG_ReadBitAngle( msg, 16 );
if( cl.maxclients <= 1 && !FBitSet( host.features, ENGINE_FIXED_FRAMERATE ))
{
cl.viewangles[YAW] += delta_yaw;
return;
}
// update running counter
cl.addangletotal += delta_yaw;
// select entry into circular buffer
cl.angle_position = (cl.angle_position + 1) & ANGLE_MASK;
a = &cl.predicted_angle[cl.angle_position];
// record update
a->starttime = cl.mtime[0];
a->total = cl.addangletotal;
2010-04-12 22:00:00 +02:00
}
2010-10-19 22:00:00 +02:00
2009-01-23 22:00:00 +01:00
/*
================
CL_ParseCrosshairAngle
offset crosshair angles
================
*/
2010-08-06 22:00:00 +02:00
void CL_ParseCrosshairAngle( sizebuf_t *msg )
2009-01-23 22:00:00 +01:00
{
2017-02-15 22:00:00 +01:00
cl.crosshairangle[0] = MSG_ReadChar( msg ) * 0.2f;
cl.crosshairangle[1] = MSG_ReadChar( msg ) * 0.2f;
cl.crosshairangle[2] = 0.0f; // not used for screen space
2009-12-04 22:00:00 +01:00
}
2010-06-22 22:00:00 +02:00
/*
================
CL_RegisterUserMessage
register new user message or update existing
================
*/
2010-08-06 22:00:00 +02:00
void CL_RegisterUserMessage( sizebuf_t *msg )
2010-06-22 22:00:00 +02:00
{
char *pszName;
int svc_num, size;
2016-11-14 22:00:00 +01:00
svc_num = MSG_ReadByte( msg );
size = MSG_ReadByte( msg );
pszName = MSG_ReadString( msg );
2010-06-22 22:00:00 +02:00
// important stuff
if( size == 0xFF ) size = -1;
2010-08-16 22:00:00 +02:00
svc_num = bound( 0, svc_num, 255 );
2010-06-22 22:00:00 +02:00
CL_LinkUserMessage( pszName, svc_num, size );
}
2009-12-04 22:00:00 +01:00
/*
================
CL_UpdateUserinfo
collect userinfo from all players
================
*/
2010-08-06 22:00:00 +02:00
void CL_UpdateUserinfo( sizebuf_t *msg )
2009-12-04 22:00:00 +01:00
{
2017-02-05 22:00:00 +01:00
int slot, id;
2010-10-26 22:00:00 +02:00
qboolean active;
2009-12-04 22:00:00 +01:00
player_info_t *player;
2016-11-14 22:00:00 +01:00
slot = MSG_ReadUBitLong( msg, MAX_CLIENT_BITS );
2009-12-04 22:00:00 +01:00
if( slot >= MAX_CLIENTS )
2017-01-14 22:00:00 +01:00
Host_Error( "CL_ParseServerMessage: svc_updateuserinfo >= MAX_CLIENTS\n" );
2009-12-04 22:00:00 +01:00
2017-02-05 22:00:00 +01:00
id = MSG_ReadLong( msg ); // unique user ID
2009-12-04 22:00:00 +01:00
player = &cl.players[slot];
2016-11-14 22:00:00 +01:00
active = MSG_ReadOneBit( msg ) ? true : false;
2009-12-04 22:00:00 +01:00
if( active )
{
2016-11-14 22:00:00 +01:00
Q_strncpy( player->userinfo, MSG_ReadString( msg ), sizeof( player->userinfo ));
2011-03-09 22:00:00 +01:00
Q_strncpy( player->name, Info_ValueForKey( player->userinfo, "name" ), sizeof( player->name ));
Q_strncpy( player->model, Info_ValueForKey( player->userinfo, "model" ), sizeof( player->model ));
2011-07-22 22:00:00 +02:00
player->topcolor = Q_atoi( Info_ValueForKey( player->userinfo, "topcolor" ));
player->bottomcolor = Q_atoi( Info_ValueForKey( player->userinfo, "bottomcolor" ));
2017-02-12 22:00:00 +01:00
player->spectator = Q_atoi( Info_ValueForKey( player->userinfo, "*hltv" ));
2011-07-22 22:00:00 +02:00
2016-11-17 22:00:00 +01:00
if( slot == cl.playernum ) memcpy( &gameui.playerinfo, player, sizeof( player_info_t ));
2009-12-04 22:00:00 +01:00
}
2016-11-17 22:00:00 +01:00
else memset( player, 0, sizeof( *player ));
2009-01-23 22:00:00 +01:00
}
2010-10-26 22:00:00 +02:00
/*
================
CL_PrecacheModel
prceache model from server
================
*/
void CL_PrecacheModel( sizebuf_t *msg )
{
int modelIndex;
2016-11-14 22:00:00 +01:00
modelIndex = MSG_ReadUBitLong( msg, MAX_MODEL_BITS );
2010-10-26 22:00:00 +02:00
if( modelIndex < 0 || modelIndex >= MAX_MODELS )
Host_Error( "CL_PrecacheModel: bad modelindex %i\n", modelIndex );
2016-11-14 22:00:00 +01:00
Q_strncpy( cl.model_precache[modelIndex], MSG_ReadString( msg ), sizeof( cl.model_precache[0] ));
2010-10-26 22:00:00 +02:00
// when we loading map all resources is precached sequentially
if( !cl.video_prepped ) return;
2010-12-08 22:00:00 +01:00
Mod_RegisterModel( cl.model_precache[modelIndex], modelIndex );
2010-10-26 22:00:00 +02:00
}
/*
================
CL_PrecacheSound
prceache sound from server
================
*/
void CL_PrecacheSound( sizebuf_t *msg )
{
int soundIndex;
2016-11-14 22:00:00 +01:00
soundIndex = MSG_ReadUBitLong( msg, MAX_SOUND_BITS );
2010-10-26 22:00:00 +02:00
if( soundIndex < 0 || soundIndex >= MAX_SOUNDS )
Host_Error( "CL_PrecacheSound: bad soundindex %i\n", soundIndex );
2016-11-14 22:00:00 +01:00
Q_strncpy( cl.sound_precache[soundIndex], MSG_ReadString( msg ), sizeof( cl.sound_precache[0] ));
2010-10-26 22:00:00 +02:00
// when we loading map all resources is precached sequentially
if( !cl.audio_prepped ) return;
cl.sound_index[soundIndex] = S_RegisterSound( cl.sound_precache[soundIndex] );
}
2010-10-28 22:00:00 +02:00
/*
================
CL_PrecacheEvent
prceache event from server
================
*/
void CL_PrecacheEvent( sizebuf_t *msg )
{
int eventIndex;
2016-11-14 22:00:00 +01:00
eventIndex = MSG_ReadUBitLong( msg, MAX_EVENT_BITS );
2010-10-28 22:00:00 +02:00
if( eventIndex < 0 || eventIndex >= MAX_EVENTS )
Host_Error( "CL_PrecacheEvent: bad eventindex %i\n", eventIndex );
2016-11-14 22:00:00 +01:00
Q_strncpy( cl.event_precache[eventIndex], MSG_ReadString( msg ), sizeof( cl.event_precache[0] ));
2010-10-28 22:00:00 +02:00
// can be set now
CL_SetEventIndex( cl.event_precache[eventIndex], eventIndex );
}
2010-10-14 22:00:00 +02:00
/*
================
CL_UpdateUserPings
collect pings and packet lossage from clients
================
*/
void CL_UpdateUserPings( sizebuf_t *msg )
{
int i, slot;
player_info_t *player;
for( i = 0; i < MAX_CLIENTS; i++ )
{
2016-11-14 22:00:00 +01:00
if( !MSG_ReadOneBit( msg )) break; // end of message
2010-10-14 22:00:00 +02:00
2016-11-14 22:00:00 +01:00
slot = MSG_ReadUBitLong( msg, MAX_CLIENT_BITS );
2010-10-14 22:00:00 +02:00
if( slot >= MAX_CLIENTS )
2017-02-07 22:00:00 +01:00
Host_Error( "CL_ParseServerMessage: svc_pings > MAX_CLIENTS\n" );
2010-10-14 22:00:00 +02:00
player = &cl.players[slot];
2016-11-14 22:00:00 +01:00
player->ping = MSG_ReadUBitLong( msg, 12 );
player->packet_loss = MSG_ReadUBitLong( msg, 7 );
2010-10-14 22:00:00 +02:00
}
}
2011-07-07 22:00:00 +02:00
/*
==============
CL_CheckingResFile
==============
*/
void CL_CheckingResFile( char *pResFileName )
{
sizebuf_t buf;
byte data[32];
if( FS_FileExists( pResFileName, false ))
return; // already existing
cls.downloadcount++;
Msg( "Starting downloads file: %s\n", pResFileName );
if( cls.state == ca_disconnected ) return;
2016-11-14 22:00:00 +01:00
MSG_Init( &buf, "ClientPacket", data, sizeof( data ));
2017-02-05 22:00:00 +01:00
MSG_BeginClientCmd( &buf, clc_resourcelist );
2016-11-14 22:00:00 +01:00
MSG_WriteString( &buf, pResFileName );
2011-07-07 22:00:00 +02:00
if( !cls.netchan.remote_address.type ) // download in singleplayer ???
cls.netchan.remote_address.type = NA_LOOPBACK;
// make sure message will be delivered
2016-11-14 22:00:00 +01:00
Netchan_Transmit( &cls.netchan, MSG_GetNumBytesWritten( &buf ), MSG_GetData( &buf ));
2011-07-07 22:00:00 +02:00
}
/*
==============
CL_CheckingSoundResFile
==============
*/
void CL_CheckingSoundResFile( char *pResFileName )
{
string filepath;
Q_snprintf( filepath, sizeof( filepath ), "sound/%s", pResFileName );
CL_CheckingResFile( filepath );
}
/*
==============
CL_ParseResourceList
==============
*/
void CL_ParseResourceList( sizebuf_t *msg )
{
int i = 0;
2016-11-17 22:00:00 +01:00
memset( &reslist, 0, sizeof( resourcelist_t ));
2011-07-07 22:00:00 +02:00
2016-11-14 22:00:00 +01:00
reslist.rescount = MSG_ReadWord( msg ) - 1;
2011-07-07 22:00:00 +02:00
for( i = 0; i < reslist.rescount; i++ )
{
2016-11-14 22:00:00 +01:00
reslist.restype[i] = MSG_ReadWord( msg );
Q_strncpy( reslist.resnames[i], MSG_ReadString( msg ), CS_SIZE );
2011-07-07 22:00:00 +02:00
}
cls.downloadcount = 0;
for( i = 0; i < reslist.rescount; i++ )
{
if( reslist.restype[i] == t_sound )
CL_CheckingSoundResFile( reslist.resnames[i] );
else CL_CheckingResFile( reslist.resnames[i] );
}
if( !cls.downloadcount )
{
2017-02-05 22:00:00 +01:00
MSG_BeginClientCmd( &cls.netchan.message, clc_stringcmd );
2016-11-14 22:00:00 +01:00
MSG_WriteString( &cls.netchan.message, "continueloading" );
2011-07-07 22:00:00 +02:00
}
}
2010-08-16 22:00:00 +02:00
/*
==============
2017-02-12 22:00:00 +01:00
CL_ParseHLTV
2010-08-16 22:00:00 +02:00
2011-04-08 22:00:00 +02:00
spectator message (hltv)
2017-02-12 22:00:00 +01:00
sended from game.dll
==============
*/
void CL_ParseHLTV( sizebuf_t *msg )
{
switch( MSG_ReadByte( msg ))
{
case HLTV_ACTIVE:
2017-02-13 22:00:00 +01:00
cl.proxy_redirect = true;
2017-02-12 22:00:00 +01:00
cls.spectator = true;
break;
case HLTV_STATUS:
MSG_ReadLong( msg );
MSG_ReadShort( msg );
MSG_ReadWord( msg );
MSG_ReadLong( msg );
MSG_ReadLong( msg );
MSG_ReadWord( msg );
break;
case HLTV_LISTEN:
2017-02-13 22:00:00 +01:00
cls.signon = SIGNONS;
2017-02-12 22:00:00 +01:00
NET_StringToAdr( MSG_ReadString( msg ), &cls.hltv_listen_address );
// NET_JoinGroup( cls.netchan.sock, cls.hltv_listen_address );
SCR_EndLoadingPlaque();
break;
default:
MsgDev( D_ERROR, "CL_ParseHLTV: unknown HLTV command.\n" );
break;
}
}
/*
==============
CL_ParseDirector
spectator message (director)
sended from game.dll
2010-08-16 22:00:00 +02:00
==============
*/
void CL_ParseDirector( sizebuf_t *msg )
{
2016-11-14 22:00:00 +01:00
int iSize = MSG_ReadByte( msg );
2017-02-12 22:00:00 +01:00
byte pbuf[256];
2010-08-16 22:00:00 +02:00
// parse user message into buffer
2016-11-14 22:00:00 +01:00
MSG_ReadBytes( msg, pbuf, iSize );
2010-08-16 22:00:00 +02:00
clgame.dllFuncs.pfnDirectorMessage( iSize, pbuf );
}
2011-12-24 21:00:00 +01:00
/*
==============
CL_ParseStudioDecal
Studio Decal message. Used by engine in case
we need save\restore decals
==============
*/
void CL_ParseStudioDecal( sizebuf_t *msg )
{
modelstate_t state;
vec3_t start, pos;
int decalIndex, entityIndex;
int modelIndex = 0;
int flags;
2016-11-14 22:00:00 +01:00
MSG_ReadVec3Coord( msg, pos );
MSG_ReadVec3Coord( msg, start );
decalIndex = MSG_ReadWord( msg );
entityIndex = MSG_ReadWord( msg );
flags = MSG_ReadByte( msg );
state.sequence = MSG_ReadShort( msg );
state.frame = MSG_ReadShort( msg );
state.blending[0] = MSG_ReadByte( msg );
state.blending[1] = MSG_ReadByte( msg );
state.controller[0] = MSG_ReadByte( msg );
state.controller[1] = MSG_ReadByte( msg );
state.controller[2] = MSG_ReadByte( msg );
state.controller[3] = MSG_ReadByte( msg );
modelIndex = MSG_ReadWord( msg );
state.body = MSG_ReadByte( msg );
state.skin = MSG_ReadByte( msg );
2011-12-24 21:00:00 +01:00
2012-12-16 21:00:00 +01:00
if( clgame.drawFuncs.R_StudioDecalShoot != NULL )
2011-12-24 21:00:00 +01:00
{
int decalTexture = CL_DecalIndex( decalIndex );
cl_entity_t *ent = CL_GetEntityByIndex( entityIndex );
if( ent && !ent->model && modelIndex != 0 )
ent->model = Mod_Handle( modelIndex );
clgame.drawFuncs.R_StudioDecalShoot( decalTexture, ent, start, pos, flags, &state );
}
}
2010-10-31 22:00:00 +01:00
/*
==============
CL_ParseScreenShake
Set screen shake
==============
*/
void CL_ParseScreenShake( sizebuf_t *msg )
{
2016-11-14 22:00:00 +01:00
clgame.shake.amplitude = (float)(word)MSG_ReadShort( msg ) * (1.0f / (float)(1<<12));
clgame.shake.duration = (float)(word)MSG_ReadShort( msg ) * (1.0f / (float)(1<<12));
clgame.shake.frequency = (float)(word)MSG_ReadShort( msg ) * (1.0f / (float)(1<<8));
2010-10-31 22:00:00 +01:00
clgame.shake.time = cl.time + max( clgame.shake.duration, 0.01f );
2011-04-08 22:00:00 +02:00
clgame.shake.next_shake = 0.0f; // apply immediately
2010-10-31 22:00:00 +01:00
}
/*
==============
CL_ParseScreenFade
Set screen fade
==============
*/
void CL_ParseScreenFade( sizebuf_t *msg )
{
float duration, holdTime;
screenfade_t *sf = &clgame.fade;
2017-09-02 23:00:00 +02:00
float flScale;
2010-10-31 22:00:00 +01:00
2017-09-02 23:00:00 +02:00
duration = (float)MSG_ReadShort( msg );
holdTime = (float)MSG_ReadShort( msg );
2016-11-14 22:00:00 +01:00
sf->fadeFlags = MSG_ReadShort( msg );
2017-09-02 23:00:00 +02:00
flScale = ( sf->fadeFlags & FFADE_LONGFADE ) ? (1.0f / 256.0f) : (1.0f / 4096.0f);
2010-10-31 22:00:00 +01:00
2016-11-14 22:00:00 +01:00
sf->fader = MSG_ReadByte( msg );
sf->fadeg = MSG_ReadByte( msg );
sf->fadeb = MSG_ReadByte( msg );
sf->fadealpha = MSG_ReadByte( msg );
2010-10-31 22:00:00 +01:00
sf->fadeSpeed = 0.0f;
2017-09-02 23:00:00 +02:00
sf->fadeEnd = duration * flScale;
sf->fadeReset = holdTime * flScale;
2010-10-31 22:00:00 +01:00
// calc fade speed
if( duration > 0 )
{
if( sf->fadeFlags & FFADE_OUT )
{
if( sf->fadeEnd )
{
sf->fadeSpeed = -(float)sf->fadealpha / sf->fadeEnd;
}
sf->fadeEnd += cl.time;
sf->fadeReset += sf->fadeEnd;
}
else
{
if( sf->fadeEnd )
{
sf->fadeSpeed = (float)sf->fadealpha / sf->fadeEnd;
}
sf->fadeReset += cl.time;
sf->fadeEnd += sf->fadeReset;
}
}
}
2012-02-09 21:00:00 +01:00
/*
==============
CL_ParseCvarValue
Find the client cvar value
and sent it back to the server
==============
*/
void CL_ParseCvarValue( sizebuf_t *msg )
{
2016-11-14 22:00:00 +01:00
const char *cvarName = MSG_ReadString( msg );
2012-02-09 21:00:00 +01:00
convar_t *cvar = Cvar_FindVar( cvarName );
// build the answer
2017-02-05 22:00:00 +01:00
MSG_BeginClientCmd( &cls.netchan.message, clc_requestcvarvalue );
2016-11-14 22:00:00 +01:00
MSG_WriteString( &cls.netchan.message, cvar ? cvar->string : "Not Found" );
2012-02-09 21:00:00 +01:00
}
/*
==============
CL_ParseCvarValue2
Find the client cvar value
and sent it back to the server
==============
*/
void CL_ParseCvarValue2( sizebuf_t *msg )
{
2016-11-14 22:00:00 +01:00
int requestID = MSG_ReadLong( msg );
const char *cvarName = MSG_ReadString( msg );
2012-02-09 21:00:00 +01:00
convar_t *cvar = Cvar_FindVar( cvarName );
// build the answer
2017-02-05 22:00:00 +01:00
MSG_BeginClientCmd( &cls.netchan.message, clc_requestcvarvalue2 );
2016-11-14 22:00:00 +01:00
MSG_WriteLong( &cls.netchan.message, requestID );
MSG_WriteString( &cls.netchan.message, cvarName );
MSG_WriteString( &cls.netchan.message, cvar ? cvar->string : "Not Found" );
2012-02-09 21:00:00 +01:00
}
2010-11-15 22:00:00 +01:00
/*
==============
CL_DispatchUserMessage
Dispatch user message by engine request
==============
*/
qboolean CL_DispatchUserMessage( const char *pszName, int iSize, void *pbuf )
{
int i;
if( !pszName || !*pszName )
return false;
for( i = 0; i < MAX_USER_MESSAGES; i++ )
{
// search for user message
2011-03-09 22:00:00 +01:00
if( !Q_strcmp( clgame.msg[i].name, pszName ))
2010-11-15 22:00:00 +01:00
break;
}
if( i == MAX_USER_MESSAGES )
{
MsgDev( D_ERROR, "CL_DispatchUserMessage: bad message %s\n", pszName );
return false;
}
2011-01-11 22:00:00 +01:00
if( clgame.msg[i].func )
{
clgame.msg[i].func( pszName, iSize, pbuf );
}
else
{
MsgDev( D_ERROR, "CL_DispatchUserMessage: %s not hooked\n", pszName );
clgame.msg[i].func = CL_UserMsgStub; // throw warning only once
}
2010-11-15 22:00:00 +01:00
return true;
}
2010-06-22 22:00:00 +02:00
/*
==============
CL_ParseUserMessage
handles all user messages
==============
*/
2010-08-06 22:00:00 +02:00
void CL_ParseUserMessage( sizebuf_t *msg, int svc_num )
2010-06-22 22:00:00 +02:00
{
2010-08-04 22:00:00 +02:00
int i, iSize;
2010-08-16 22:00:00 +02:00
byte pbuf[256]; // message can't be larger than 255 bytes
2010-06-22 22:00:00 +02:00
2017-01-14 22:00:00 +01:00
// NOTE: any user message is really parse at engine, not in client.dll
2017-02-07 22:00:00 +01:00
if( svc_num <= svc_lastmsg || svc_num > ( MAX_USER_MESSAGES + svc_lastmsg ))
2010-06-22 22:00:00 +02:00
{
// out or range
Host_Error( "CL_ParseUserMessage: illegible server message %d\n", svc_num );
return;
}
2010-08-16 22:00:00 +02:00
for( i = 0; i < MAX_USER_MESSAGES; i++ )
2010-08-04 22:00:00 +02:00
{
2010-08-16 22:00:00 +02:00
// search for user message
if( clgame.msg[i].number == svc_num )
break;
2010-08-04 22:00:00 +02:00
}
2010-06-22 22:00:00 +02:00
2011-04-08 22:00:00 +02:00
if( i == MAX_USER_MESSAGES ) // probably unregistered
2010-08-16 22:00:00 +02:00
Host_Error( "CL_ParseUserMessage: illegible server message %d\n", svc_num );
2010-10-31 22:00:00 +01:00
// NOTE: some user messages handled into engine
2011-03-09 22:00:00 +01:00
if( !Q_strcmp( clgame.msg[i].name, "ScreenShake" ))
2010-10-31 22:00:00 +01:00
{
CL_ParseScreenShake( msg );
return;
}
2011-03-09 22:00:00 +01:00
else if( !Q_strcmp( clgame.msg[i].name, "ScreenFade" ))
2010-10-31 22:00:00 +01:00
{
CL_ParseScreenFade( msg );
return;
}
2010-08-16 22:00:00 +02:00
iSize = clgame.msg[i].size;
2010-06-22 22:00:00 +02:00
// message with variable sizes receive an actual size as first byte
2016-11-14 22:00:00 +01:00
if( iSize == -1 ) iSize = MSG_ReadByte( msg );
2010-06-22 22:00:00 +02:00
// parse user message into buffer
2016-11-14 22:00:00 +01:00
MSG_ReadBytes( msg, pbuf, iSize );
2010-06-22 22:00:00 +02:00
2011-01-11 22:00:00 +01:00
if( clgame.msg[i].func )
{
clgame.msg[i].func( clgame.msg[i].name, iSize, pbuf );
2011-04-01 22:00:00 +02:00
// HACKHACK: run final credits for Half-Life
// because hl1 doesn't have call END_SECTION
if( !Q_stricmp( clgame.msg[i].name, "HudText" ) && !Q_stricmp( GI->gamefolder, "valve" ))
{
// it's a end, so we should run credits
if( !Q_strcmp( (char *)pbuf, "END3" ))
Host_Credits();
}
2011-01-11 22:00:00 +01:00
}
else
{
MsgDev( D_ERROR, "CL_ParseUserMessage: %s not hooked\n", clgame.msg[i].name );
clgame.msg[i].func = CL_UserMsgStub; // throw warning only once
}
2010-06-22 22:00:00 +02:00
}
2017-03-02 22:00:00 +01:00
/*
=====================
CL_ResetFrame
=====================
*/
void CL_ResetFrame( frame_t *frame )
{
memset( &frame->graphdata, 0, sizeof( netbandwidthgraph_t ));
frame->receivedtime = host.realtime;
frame->valid = true;
frame->choked = false;
frame->latency = 0.0;
frame->time = cl.mtime[0];
}
2007-06-21 22:00:00 +02:00
/*
=====================================================================
ACTION MESSAGES
=====================================================================
*/
/*
=====================
CL_ParseServerMessage
=====================
*/
2017-03-02 22:00:00 +01:00
void CL_ParseServerMessage( sizebuf_t *msg, qboolean normal_message )
2007-06-21 22:00:00 +02:00
{
2008-06-30 22:00:00 +02:00
char *s;
2017-03-02 22:00:00 +01:00
int i, cmd, param1, param2;
2017-01-14 22:00:00 +01:00
size_t bufStart, playerbytes;
2007-06-21 22:00:00 +02:00
2010-08-04 22:00:00 +02:00
cls_message_debug.parsing = true; // begin parsing
2016-11-14 22:00:00 +01:00
starting_count = MSG_GetNumBytesRead( msg ); // updates each frame
2017-03-02 22:00:00 +01:00
if( normal_message )
{
// assume no entity/player update this packet
if( cls.state == ca_active )
{
cl.frames[cls.netchan.incoming_sequence & CL_UPDATE_MASK].valid = false;
cl.frames[cls.netchan.incoming_sequence & CL_UPDATE_MASK].choked = false;
}
else
{
CL_ResetFrame( &cl.frames[cls.netchan.incoming_sequence & CL_UPDATE_MASK] );
}
}
2010-03-27 22:00:00 +01:00
2007-08-17 22:00:00 +02:00
// parse the message
2008-05-20 22:00:00 +02:00
while( 1 )
2007-06-21 22:00:00 +02:00
{
2016-11-14 22:00:00 +01:00
if( MSG_CheckOverflow( msg ))
2007-06-21 22:00:00 +02:00
{
2011-04-08 22:00:00 +02:00
Host_Error( "CL_ParseServerMessage: overflow!\n" );
2009-06-24 22:00:00 +02:00
return;
2007-06-21 22:00:00 +02:00
}
2010-03-27 22:00:00 +01:00
// mark start position
2016-11-14 22:00:00 +01:00
bufStart = MSG_GetNumBytesRead( msg );
2010-08-04 22:00:00 +02:00
// end of message
2016-11-14 22:00:00 +01:00
if( MSG_GetNumBitsLeft( msg ) < 8 )
2010-08-04 22:00:00 +02:00
break;
2010-03-27 22:00:00 +01:00
2017-02-05 22:00:00 +01:00
cmd = MSG_ReadServerCmd( msg );
2008-07-15 22:00:00 +02:00
2010-03-27 22:00:00 +01:00
// record command for debugging spew on parse problem
CL_Parse_RecordCommand( cmd, bufStart );
2007-08-17 22:00:00 +02:00
// other commands
2008-06-30 22:00:00 +02:00
switch( cmd )
2007-06-21 22:00:00 +02:00
{
2010-08-16 22:00:00 +02:00
case svc_bad:
Host_Error( "svc_bad\n" );
break;
2007-06-21 22:00:00 +02:00
case svc_nop:
2011-04-08 22:00:00 +02:00
// this does nothing
2007-06-21 22:00:00 +02:00
break;
case svc_disconnect:
2007-09-10 22:00:00 +02:00
CL_Drop ();
2011-04-08 22:00:00 +02:00
Host_AbortCurrentFrame ();
2007-06-21 22:00:00 +02:00
break;
2010-03-28 22:00:00 +02:00
case svc_changing:
2016-11-14 22:00:00 +01:00
if( MSG_ReadOneBit( msg ))
2010-08-16 22:00:00 +02:00
{
cls.changelevel = true;
2017-06-23 23:00:00 +02:00
S_StopAllSounds( true );
2011-04-10 22:00:00 +02:00
if( cls.demoplayback )
2014-05-11 22:00:00 +02:00
{
2011-04-10 22:00:00 +02:00
SCR_BeginLoadingPlaque( cl.background );
2014-05-11 22:00:00 +02:00
cls.changedemo = true;
}
2010-08-16 22:00:00 +02:00
}
else MsgDev( D_INFO, "Server disconnected, reconnecting\n" );
2011-04-18 22:00:00 +02:00
CL_ClearState ();
2011-07-22 22:00:00 +02:00
CL_InitEdicts (); // re-arrange edicts
2011-04-18 22:00:00 +02:00
2012-03-01 21:00:00 +01:00
if( cls.demoplayback )
2014-05-11 22:00:00 +02:00
{
cl.background = (cls.demonum != -1) ? true : false;
2012-03-01 21:00:00 +01:00
cls.state = ca_connected;
2014-05-11 22:00:00 +02:00
}
2012-03-01 21:00:00 +01:00
else cls.state = ca_connecting;
2008-06-30 22:00:00 +02:00
cls.connect_time = MAX_HEARTBEAT; // CL_CheckForResend() will fire immediately
2007-06-21 22:00:00 +02:00
break;
2010-08-16 22:00:00 +02:00
case svc_setview:
2017-02-21 22:00:00 +01:00
CL_ParseViewEntity( msg );
2010-08-16 22:00:00 +02:00
break;
case svc_sound:
2017-02-07 22:00:00 +01:00
case svc_ambientsound:
CL_ParseSoundPacket( msg );
2016-11-14 22:00:00 +01:00
cl.frames[cl.parsecountmod].graphdata.sound += MSG_GetNumBytesRead( msg ) - bufStart;
2010-08-16 22:00:00 +02:00
break;
case svc_time:
2017-01-14 22:00:00 +01:00
CL_ParseServerTime( msg );
2010-10-14 22:00:00 +02:00
break;
2010-08-16 22:00:00 +02:00
case svc_print:
2016-11-14 22:00:00 +01:00
i = MSG_ReadByte( msg );
MsgDev( D_INFO, "^6%s", MSG_ReadString( msg ));
2014-10-31 22:00:00 +01:00
if( i == PRINT_CHAT ) S_StartLocalSound( "common/menu2.wav", VOL_NORM, false );
2010-08-16 22:00:00 +02:00
break;
2007-06-21 22:00:00 +02:00
case svc_stufftext:
2016-11-14 22:00:00 +01:00
s = MSG_ReadString( msg );
2008-06-30 22:00:00 +02:00
Cbuf_AddText( s );
2007-06-21 22:00:00 +02:00
break;
2010-10-28 22:00:00 +02:00
case svc_lightstyle:
CL_ParseLightStyle( msg );
break;
2010-08-16 22:00:00 +02:00
case svc_setangle:
CL_ParseSetAngle( msg );
break;
2007-06-21 22:00:00 +02:00
case svc_serverdata:
2008-08-02 22:00:00 +02:00
Cbuf_Execute(); // make sure any stuffed commands are done
2008-05-20 22:00:00 +02:00
CL_ParseServerData( msg );
2007-06-21 22:00:00 +02:00
break;
2010-08-16 22:00:00 +02:00
case svc_addangle:
CL_ParseAddAngle( msg );
2007-06-21 22:00:00 +02:00
break;
2010-08-16 22:00:00 +02:00
case svc_clientdata:
2010-10-14 22:00:00 +02:00
CL_ParseClientData( msg );
2016-11-14 22:00:00 +01:00
cl.frames[cl.parsecountmod].graphdata.client += MSG_GetNumBytesRead( msg ) - bufStart;
2010-08-16 22:00:00 +02:00
break;
case svc_packetentities:
2016-11-14 22:00:00 +01:00
playerbytes = CL_ParsePacketEntities( msg, false );
cl.frames[cl.parsecountmod].graphdata.players += playerbytes;
cl.frames[cl.parsecountmod].graphdata.entities += MSG_GetNumBytesRead( msg ) - bufStart - playerbytes;
2010-10-14 22:00:00 +02:00
break;
case svc_deltapacketentities:
2016-11-14 22:00:00 +01:00
playerbytes = CL_ParsePacketEntities( msg, true );
cl.frames[cl.parsecountmod].graphdata.players += playerbytes;
cl.frames[cl.parsecountmod].graphdata.entities += MSG_GetNumBytesRead( msg ) - bufStart - playerbytes;
2010-08-05 22:00:00 +02:00
break;
2017-02-07 22:00:00 +01:00
case svc_pings:
2010-10-14 22:00:00 +02:00
CL_UpdateUserPings( msg );
break;
2010-08-16 22:00:00 +02:00
case svc_usermessage:
CL_RegisterUserMessage( msg );
break;
case svc_particle:
CL_ParseParticles( msg );
2010-04-24 22:00:00 +02:00
break;
2012-05-13 22:00:00 +02:00
case svc_restoresound:
CL_ParseRestoreSoundPacket( msg );
2016-12-12 22:00:00 +01:00
cl.frames[cl.parsecountmod].graphdata.sound += MSG_GetNumBytesRead( msg ) - bufStart;
2012-05-13 22:00:00 +02:00
break;
2010-10-17 22:00:00 +02:00
case svc_spawnstatic:
CL_ParseStaticEntity( msg );
break;
2009-01-23 22:00:00 +01:00
case svc_crosshairangle:
CL_ParseCrosshairAngle( msg );
break;
2010-08-16 22:00:00 +02:00
case svc_spawnbaseline:
CL_ParseBaseline( msg );
2008-12-26 22:00:00 +01:00
break;
2010-08-16 22:00:00 +02:00
case svc_temp_entity:
CL_ParseTempEntity( msg );
2016-11-14 22:00:00 +01:00
cl.frames[cl.parsecountmod].graphdata.tentities += MSG_GetNumBytesRead( msg ) - bufStart;
2009-11-23 22:00:00 +01:00
break;
2009-11-10 22:00:00 +01:00
case svc_setpause:
2017-02-15 22:00:00 +01:00
cl.paused = ( MSG_ReadOneBit( msg ) != 0 );
2009-11-10 22:00:00 +01:00
break;
2017-02-13 22:00:00 +01:00
case svc_signonnum:
CL_ParseSignon( msg );
break;
2010-08-16 22:00:00 +02:00
case svc_deltamovevars:
2009-11-10 22:00:00 +01:00
CL_ParseMovevars( msg );
break;
2011-07-07 22:00:00 +02:00
case svc_customization:
CL_ParseCustomization( msg );
break;
2010-08-16 22:00:00 +02:00
case svc_centerprint:
2016-11-14 22:00:00 +01:00
CL_CenterPrint( MSG_ReadString( msg ), 0.25f );
2009-11-25 22:00:00 +01:00
break;
2009-12-02 22:00:00 +01:00
case svc_event:
CL_ParseEvent( msg );
2016-11-14 22:00:00 +01:00
cl.frames[cl.parsecountmod].graphdata.event += MSG_GetNumBytesRead( msg ) - bufStart;
2009-12-02 22:00:00 +01:00
break;
case svc_event_reliable:
2011-10-09 22:00:00 +02:00
CL_ParseReliableEvent( msg );
2016-11-14 22:00:00 +01:00
cl.frames[cl.parsecountmod].graphdata.event += MSG_GetNumBytesRead( msg ) - bufStart;
2009-12-02 22:00:00 +01:00
break;
2009-12-04 22:00:00 +01:00
case svc_updateuserinfo:
CL_UpdateUserinfo( msg );
break;
2010-08-16 22:00:00 +02:00
case svc_intermission:
2017-06-23 23:00:00 +02:00
cl.intermission = 1;
break;
case svc_finale:
2017-07-18 23:00:00 +02:00
CL_ParseFinaleCutscene( msg, 2 );
2017-06-23 23:00:00 +02:00
break;
case svc_cutscene:
2017-07-18 23:00:00 +02:00
CL_ParseFinaleCutscene( msg, 3 );
2010-08-16 22:00:00 +02:00
break;
2010-10-26 22:00:00 +02:00
case svc_modelindex:
CL_PrecacheModel( msg );
break;
case svc_soundindex:
CL_PrecacheSound( msg );
break;
2010-08-16 22:00:00 +02:00
case svc_soundfade:
CL_ParseSoundFade( msg );
break;
case svc_cdtrack:
2016-11-14 22:00:00 +01:00
param1 = MSG_ReadByte( msg );
2011-04-10 22:00:00 +02:00
param1 = bound( 1, param1, MAX_CDTRACKS ); // tracknum
2016-11-14 22:00:00 +01:00
param2 = MSG_ReadByte( msg );
2011-04-10 22:00:00 +02:00
param2 = bound( 1, param2, MAX_CDTRACKS ); // loopnum
2012-05-14 22:00:00 +02:00
S_StartBackgroundTrack( clgame.cdtracks[param1-1], clgame.cdtracks[param2-1], 0 );
2010-08-16 22:00:00 +02:00
break;
2010-10-28 22:00:00 +02:00
case svc_eventindex:
CL_PrecacheEvent( msg );
break;
2010-08-16 22:00:00 +02:00
case svc_deltatable:
Delta_ParseTableField( msg );
2007-06-21 22:00:00 +02:00
break;
2010-08-16 22:00:00 +02:00
case svc_weaponanim:
2016-11-14 22:00:00 +01:00
param1 = MSG_ReadByte( msg ); // iAnim
param2 = MSG_ReadByte( msg ); // body
2010-08-16 22:00:00 +02:00
CL_WeaponAnim( param1, param2 );
2008-06-30 22:00:00 +02:00
break;
2010-08-16 22:00:00 +02:00
case svc_bspdecal:
CL_ParseStaticDecal( msg );
break;
case svc_roomtype:
2016-11-14 22:00:00 +01:00
param1 = MSG_ReadShort( msg );
2017-02-12 22:00:00 +01:00
Cvar_SetValue( "room_type", param1 );
2010-08-16 22:00:00 +02:00
break;
2017-03-02 22:00:00 +01:00
case svc_choke:
cl.frames[cls.netchan.incoming_sequence & CL_UPDATE_MASK].choked = true;
2017-02-05 22:00:00 +01:00
cl.frames[cls.netchan.incoming_sequence & CL_UPDATE_MASK].receivedtime = -2.0;
2010-10-14 22:00:00 +02:00
break;
2011-07-07 22:00:00 +02:00
case svc_resourcelist:
CL_ParseResourceList( msg );
break;
2010-08-16 22:00:00 +02:00
case svc_director:
CL_ParseDirector( msg );
2007-06-21 22:00:00 +02:00
break;
2017-02-12 22:00:00 +01:00
case svc_hltv:
CL_ParseHLTV( msg );
break;
2011-12-24 21:00:00 +01:00
case svc_studiodecal:
CL_ParseStudioDecal( msg );
break;
2012-02-09 21:00:00 +01:00
case svc_querycvarvalue:
CL_ParseCvarValue( msg );
break;
case svc_querycvarvalue2:
CL_ParseCvarValue2( msg );
break;
2007-11-17 22:00:00 +01:00
default:
2008-12-25 22:00:00 +01:00
CL_ParseUserMessage( msg, cmd );
2016-11-14 22:00:00 +01:00
cl.frames[cl.parsecountmod].graphdata.usr += MSG_GetNumBytesRead( msg ) - bufStart;
2007-11-17 22:00:00 +01:00
break;
2007-06-21 22:00:00 +02:00
}
}
2010-08-19 22:00:00 +02:00
2017-02-28 22:00:00 +01:00
cl.frames[cl.parsecountmod].graphdata.msgbytes += MSG_GetNumBytesRead( msg ) - starting_count;
cls_message_debug.parsing = false; // done
2012-03-01 21:00:00 +01:00
// we don't know if it is ok to save a demo message until
// after we have parsed the frame
if( !cls.demoplayback )
{
if( cls.demorecording && !cls.demowaiting )
{
CL_WriteDemoMessage( false, starting_count, msg );
}
else if( cls.state != ca_active )
{
CL_WriteDemoMessage( true, starting_count, msg );
}
}
2008-06-30 22:00:00 +02:00
}