aboutsummaryrefslogtreecommitdiffstats
path: root/code/client/cl_parse.c
diff options
context:
space:
mode:
authorzakk <zakk@edf5b092-35ff-0310-97b2-ce42778d08ea>2005-08-26 17:39:27 +0000
committerzakk <zakk@edf5b092-35ff-0310-97b2-ce42778d08ea>2005-08-26 17:39:27 +0000
commit6bf20c78f5b69d40bcc4931df93d29198435ab67 (patch)
treee3eda937a05d7db42de725b7013bd0344b987f34 /code/client/cl_parse.c
parent872d4d7f55af706737ffb361bb76ad13e7496770 (diff)
downloadioquake3-aero-6bf20c78f5b69d40bcc4931df93d29198435ab67.tar.gz
ioquake3-aero-6bf20c78f5b69d40bcc4931df93d29198435ab67.zip
newlines fixed
git-svn-id: svn://svn.icculus.org/quake3/trunk@6 edf5b092-35ff-0310-97b2-ce42778d08ea
Diffstat (limited to 'code/client/cl_parse.c')
-rwxr-xr-xcode/client/cl_parse.c1310
1 files changed, 655 insertions, 655 deletions
diff --git a/code/client/cl_parse.c b/code/client/cl_parse.c
index 9de3588..e3dedb3 100755
--- a/code/client/cl_parse.c
+++ b/code/client/cl_parse.c
@@ -1,655 +1,655 @@
-/*
-===========================================================================
-Copyright (C) 1999-2005 Id Software, Inc.
-
-This file is part of Quake III Arena source code.
-
-Quake III Arena source code 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.
-
-Quake III Arena source code 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 Foobar; if not, write to the Free Software
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
-===========================================================================
-*/
-// cl_parse.c -- parse a message received from the server
-
-#include "client.h"
-
-char *svc_strings[256] = {
- "svc_bad",
-
- "svc_nop",
- "svc_gamestate",
- "svc_configstring",
- "svc_baseline",
- "svc_serverCommand",
- "svc_download",
- "svc_snapshot"
-};
-
-void SHOWNET( msg_t *msg, char *s) {
- if ( cl_shownet->integer >= 2) {
- Com_Printf ("%3i:%s\n", msg->readcount-1, s);
- }
-}
-
-
-/*
-=========================================================================
-
-MESSAGE PARSING
-
-=========================================================================
-*/
-
-/*
-==================
-CL_DeltaEntity
-
-Parses deltas from the given base and adds the resulting entity
-to the current frame
-==================
-*/
-void CL_DeltaEntity (msg_t *msg, clSnapshot_t *frame, int newnum, entityState_t *old,
- qboolean unchanged) {
- entityState_t *state;
-
- // save the parsed entity state into the big circular buffer so
- // it can be used as the source for a later delta
- state = &cl.parseEntities[cl.parseEntitiesNum & (MAX_PARSE_ENTITIES-1)];
-
- if ( unchanged ) {
- *state = *old;
- } else {
- MSG_ReadDeltaEntity( msg, old, state, newnum );
- }
-
- if ( state->number == (MAX_GENTITIES-1) ) {
- return; // entity was delta removed
- }
- cl.parseEntitiesNum++;
- frame->numEntities++;
-}
-
-/*
-==================
-CL_ParsePacketEntities
-
-==================
-*/
-void CL_ParsePacketEntities( msg_t *msg, clSnapshot_t *oldframe, clSnapshot_t *newframe) {
- int newnum;
- entityState_t *oldstate;
- int oldindex, oldnum;
-
- newframe->parseEntitiesNum = cl.parseEntitiesNum;
- newframe->numEntities = 0;
-
- // delta from the entities present in oldframe
- oldindex = 0;
- oldstate = NULL;
- if (!oldframe) {
- oldnum = 99999;
- } else {
- if ( oldindex >= oldframe->numEntities ) {
- oldnum = 99999;
- } else {
- oldstate = &cl.parseEntities[
- (oldframe->parseEntitiesNum + oldindex) & (MAX_PARSE_ENTITIES-1)];
- oldnum = oldstate->number;
- }
- }
-
- while ( 1 ) {
- // read the entity index number
- newnum = MSG_ReadBits( msg, GENTITYNUM_BITS );
-
- if ( newnum == (MAX_GENTITIES-1) ) {
- break;
- }
-
- if ( msg->readcount > msg->cursize ) {
- Com_Error (ERR_DROP,"CL_ParsePacketEntities: end of message");
- }
-
- while ( oldnum < newnum ) {
- // one or more entities from the old packet are unchanged
- if ( cl_shownet->integer == 3 ) {
- Com_Printf ("%3i: unchanged: %i\n", msg->readcount, oldnum);
- }
- CL_DeltaEntity( msg, newframe, oldnum, oldstate, qtrue );
-
- oldindex++;
-
- if ( oldindex >= oldframe->numEntities ) {
- oldnum = 99999;
- } else {
- oldstate = &cl.parseEntities[
- (oldframe->parseEntitiesNum + oldindex) & (MAX_PARSE_ENTITIES-1)];
- oldnum = oldstate->number;
- }
- }
- if (oldnum == newnum) {
- // delta from previous state
- if ( cl_shownet->integer == 3 ) {
- Com_Printf ("%3i: delta: %i\n", msg->readcount, newnum);
- }
- CL_DeltaEntity( msg, newframe, newnum, oldstate, qfalse );
-
- oldindex++;
-
- if ( oldindex >= oldframe->numEntities ) {
- oldnum = 99999;
- } else {
- oldstate = &cl.parseEntities[
- (oldframe->parseEntitiesNum + oldindex) & (MAX_PARSE_ENTITIES-1)];
- oldnum = oldstate->number;
- }
- continue;
- }
-
- if ( oldnum > newnum ) {
- // delta from baseline
- if ( cl_shownet->integer == 3 ) {
- Com_Printf ("%3i: baseline: %i\n", msg->readcount, newnum);
- }
- CL_DeltaEntity( msg, newframe, newnum, &cl.entityBaselines[newnum], qfalse );
- 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->integer == 3 ) {
- Com_Printf ("%3i: unchanged: %i\n", msg->readcount, oldnum);
- }
- CL_DeltaEntity( msg, newframe, oldnum, oldstate, qtrue );
-
- oldindex++;
-
- if ( oldindex >= oldframe->numEntities ) {
- oldnum = 99999;
- } else {
- oldstate = &cl.parseEntities[
- (oldframe->parseEntitiesNum + oldindex) & (MAX_PARSE_ENTITIES-1)];
- oldnum = oldstate->number;
- }
- }
-}
-
-
-/*
-================
-CL_ParseSnapshot
-
-If the snapshot is parsed properly, it will be copied to
-cl.snap and saved in cl.snapshots[]. If the snapshot is invalid
-for any reason, no changes to the state will be made at all.
-================
-*/
-void CL_ParseSnapshot( msg_t *msg ) {
- int len;
- clSnapshot_t *old;
- clSnapshot_t newSnap;
- int deltaNum;
- int oldMessageNum;
- int i, packetNum;
-
- // get the reliable sequence acknowledge number
- // NOTE: now sent with all server to client messages
- //clc.reliableAcknowledge = MSG_ReadLong( msg );
-
- // read in the new snapshot to a temporary buffer
- // we will only copy to cl.snap if it is valid
- Com_Memset (&newSnap, 0, sizeof(newSnap));
-
- // we will have read any new server commands in this
- // message before we got to svc_snapshot
- newSnap.serverCommandNum = clc.serverCommandSequence;
-
- newSnap.serverTime = MSG_ReadLong( msg );
-
- newSnap.messageNum = clc.serverMessageSequence;
-
- deltaNum = MSG_ReadByte( msg );
- if ( !deltaNum ) {
- newSnap.deltaNum = -1;
- } else {
- newSnap.deltaNum = newSnap.messageNum - deltaNum;
- }
- newSnap.snapFlags = MSG_ReadByte( msg );
-
- // 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 ( newSnap.deltaNum <= 0 ) {
- newSnap.valid = qtrue; // uncompressed frame
- old = NULL;
- clc.demowaiting = qfalse; // we can start recording now
- } else {
- old = &cl.snapshots[newSnap.deltaNum & PACKET_MASK];
- if ( !old->valid ) {
- // should never happen
- Com_Printf ("Delta from invalid frame (not supposed to happen!).\n");
- } else if ( old->messageNum != newSnap.deltaNum ) {
- // 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.parseEntitiesNum - old->parseEntitiesNum > MAX_PARSE_ENTITIES-128 ) {
- Com_Printf ("Delta parseEntitiesNum too old.\n");
- } else {
- newSnap.valid = qtrue; // valid delta parse
- }
- }
-
- // read areamask
- len = MSG_ReadByte( msg );
- MSG_ReadData( msg, &newSnap.areamask, len);
-
- // read playerinfo
- SHOWNET( msg, "playerstate" );
- if ( old ) {
- MSG_ReadDeltaPlayerstate( msg, &old->ps, &newSnap.ps );
- } else {
- MSG_ReadDeltaPlayerstate( msg, NULL, &newSnap.ps );
- }
-
- // read packet entities
- SHOWNET( msg, "packet entities" );
- CL_ParsePacketEntities( msg, old, &newSnap );
-
- // if not valid, dump the entire thing now that it has
- // been properly read
- if ( !newSnap.valid ) {
- return;
- }
-
- // clear the valid flags of any snapshots between the last
- // received and this one, so if there was a dropped packet
- // it won't look like something valid to delta from next
- // time we wrap around in the buffer
- oldMessageNum = cl.snap.messageNum + 1;
-
- if ( newSnap.messageNum - oldMessageNum >= PACKET_BACKUP ) {
- oldMessageNum = newSnap.messageNum - ( PACKET_BACKUP - 1 );
- }
- for ( ; oldMessageNum < newSnap.messageNum ; oldMessageNum++ ) {
- cl.snapshots[oldMessageNum & PACKET_MASK].valid = qfalse;
- }
-
- // copy to the current good spot
- cl.snap = newSnap;
- cl.snap.ping = 999;
- // calculate ping time
- for ( i = 0 ; i < PACKET_BACKUP ; i++ ) {
- packetNum = ( clc.netchan.outgoingSequence - 1 - i ) & PACKET_MASK;
- if ( cl.snap.ps.commandTime >= cl.outPackets[ packetNum ].p_serverTime ) {
- cl.snap.ping = cls.realtime - cl.outPackets[ packetNum ].p_realtime;
- break;
- }
- }
- // save the frame off in the backup array for later delta comparisons
- cl.snapshots[cl.snap.messageNum & PACKET_MASK] = cl.snap;
-
- if (cl_shownet->integer == 3) {
- Com_Printf( " snapshot:%i delta:%i ping:%i\n", cl.snap.messageNum,
- cl.snap.deltaNum, cl.snap.ping );
- }
-
- cl.newSnapshots = qtrue;
-}
-
-
-//=====================================================================
-
-int cl_connectedToPureServer;
-
-/*
-==================
-CL_SystemInfoChanged
-
-The systeminfo configstring has been changed, so parse
-new information out of it. This will happen at every
-gamestate, and possibly during gameplay.
-==================
-*/
-void CL_SystemInfoChanged( void ) {
- char *systemInfo;
- const char *s, *t;
- char key[BIG_INFO_KEY];
- char value[BIG_INFO_VALUE];
- qboolean gameSet;
-
- systemInfo = cl.gameState.stringData + cl.gameState.stringOffsets[ CS_SYSTEMINFO ];
- // NOTE TTimo:
- // when the serverId changes, any further messages we send to the server will use this new serverId
- // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=475
- // in some cases, outdated cp commands might get sent with this news serverId
- cl.serverId = atoi( Info_ValueForKey( systemInfo, "sv_serverid" ) );
-
- // don't set any vars when playing a demo
- if ( clc.demoplaying ) {
- return;
- }
-
- s = Info_ValueForKey( systemInfo, "sv_cheats" );
- if ( atoi(s) == 0 ) {
- Cvar_SetCheatState();
- }
-
- // check pure server string
- s = Info_ValueForKey( systemInfo, "sv_paks" );
- t = Info_ValueForKey( systemInfo, "sv_pakNames" );
- FS_PureServerSetLoadedPaks( s, t );
-
- s = Info_ValueForKey( systemInfo, "sv_referencedPaks" );
- t = Info_ValueForKey( systemInfo, "sv_referencedPakNames" );
- FS_PureServerSetReferencedPaks( s, t );
-
- gameSet = qfalse;
- // scan through all the variables in the systeminfo and locally set cvars to match
- s = systemInfo;
- while ( s ) {
- Info_NextPair( &s, key, value );
- if ( !key[0] ) {
- break;
- }
- // ehw!
- if ( !Q_stricmp( key, "fs_game" ) ) {
- gameSet = qtrue;
- }
-
- Cvar_Set( key, value );
- }
- // if game folder should not be set and it is set at the client side
- if ( !gameSet && *Cvar_VariableString("fs_game") ) {
- Cvar_Set( "fs_game", "" );
- }
- cl_connectedToPureServer = Cvar_VariableValue( "sv_pure" );
-}
-
-/*
-==================
-CL_ParseGamestate
-==================
-*/
-void CL_ParseGamestate( msg_t *msg ) {
- int i;
- entityState_t *es;
- int newnum;
- entityState_t nullstate;
- int cmd;
- char *s;
-
- Con_Close();
-
- clc.connectPacketCount = 0;
-
- // wipe local client state
- CL_ClearState();
-
- // a gamestate always marks a server command sequence
- clc.serverCommandSequence = MSG_ReadLong( msg );
-
- // parse all the configstrings and baselines
- cl.gameState.dataCount = 1; // leave a 0 at the beginning for uninitialized configstrings
- while ( 1 ) {
- cmd = MSG_ReadByte( msg );
-
- if ( cmd == svc_EOF ) {
- break;
- }
-
- if ( cmd == svc_configstring ) {
- int len;
-
- i = MSG_ReadShort( msg );
- if ( i < 0 || i >= MAX_CONFIGSTRINGS ) {
- Com_Error( ERR_DROP, "configstring > MAX_CONFIGSTRINGS" );
- }
- s = MSG_ReadBigString( msg );
- len = strlen( s );
-
- if ( len + 1 + cl.gameState.dataCount > MAX_GAMESTATE_CHARS ) {
- Com_Error( ERR_DROP, "MAX_GAMESTATE_CHARS exceeded" );
- }
-
- // append it to the gameState string buffer
- cl.gameState.stringOffsets[ i ] = cl.gameState.dataCount;
- Com_Memcpy( cl.gameState.stringData + cl.gameState.dataCount, s, len + 1 );
- cl.gameState.dataCount += len + 1;
- } else if ( cmd == svc_baseline ) {
- newnum = MSG_ReadBits( msg, GENTITYNUM_BITS );
- if ( newnum < 0 || newnum >= MAX_GENTITIES ) {
- Com_Error( ERR_DROP, "Baseline number out of range: %i", newnum );
- }
- Com_Memset (&nullstate, 0, sizeof(nullstate));
- es = &cl.entityBaselines[ newnum ];
- MSG_ReadDeltaEntity( msg, &nullstate, es, newnum );
- } else {
- Com_Error( ERR_DROP, "CL_ParseGamestate: bad command byte" );
- }
- }
-
- clc.clientNum = MSG_ReadLong(msg);
- // read the checksum feed
- clc.checksumFeed = MSG_ReadLong( msg );
-
- // parse serverId and other cvars
- CL_SystemInfoChanged();
-
- // reinitialize the filesystem if the game directory has changed
- FS_ConditionalRestart( clc.checksumFeed );
-
- // This used to call CL_StartHunkUsers, but now we enter the download state before loading the
- // cgame
- CL_InitDownloads();
-
- // make sure the game starts
- Cvar_Set( "cl_paused", "0" );
-}
-
-
-//=====================================================================
-
-/*
-=====================
-CL_ParseDownload
-
-A download message has been received from the server
-=====================
-*/
-void CL_ParseDownload ( msg_t *msg ) {
- int size;
- unsigned char data[MAX_MSGLEN];
- int block;
-
- // read the data
- block = MSG_ReadShort ( msg );
-
- if ( !block )
- {
- // block zero is special, contains file size
- clc.downloadSize = MSG_ReadLong ( msg );
-
- Cvar_SetValue( "cl_downloadSize", clc.downloadSize );
-
- if (clc.downloadSize < 0)
- {
- Com_Error(ERR_DROP, MSG_ReadString( msg ) );
- return;
- }
- }
-
- size = MSG_ReadShort ( msg );
- if (size > 0)
- MSG_ReadData( msg, data, size );
-
- if (clc.downloadBlock != block) {
- Com_DPrintf( "CL_ParseDownload: Expected block %d, got %d\n", clc.downloadBlock, block);
- return;
- }
-
- // open the file if not opened yet
- if (!clc.download)
- {
- if (!*clc.downloadTempName) {
- Com_Printf("Server sending download, but no download was requested\n");
- CL_AddReliableCommand( "stopdl" );
- return;
- }
-
- clc.download = FS_SV_FOpenFileWrite( clc.downloadTempName );
-
- if (!clc.download) {
- Com_Printf( "Could not create %s\n", clc.downloadTempName );
- CL_AddReliableCommand( "stopdl" );
- CL_NextDownload();
- return;
- }
- }
-
- if (size)
- FS_Write( data, size, clc.download );
-
- CL_AddReliableCommand( va("nextdl %d", clc.downloadBlock) );
- clc.downloadBlock++;
-
- clc.downloadCount += size;
-
- // So UI gets access to it
- Cvar_SetValue( "cl_downloadCount", clc.downloadCount );
-
- if (!size) { // A zero length block means EOF
- if (clc.download) {
- FS_FCloseFile( clc.download );
- clc.download = 0;
-
- // rename the file
- FS_SV_Rename ( clc.downloadTempName, clc.downloadName );
- }
- *clc.downloadTempName = *clc.downloadName = 0;
- Cvar_Set( "cl_downloadName", "" );
-
- // send intentions now
- // We need this because without it, we would hold the last nextdl and then start
- // loading right away. If we take a while to load, the server is happily trying
- // to send us that last block over and over.
- // Write it twice to help make sure we acknowledge the download
- CL_WritePacket();
- CL_WritePacket();
-
- // get another file if needed
- CL_NextDownload ();
- }
-}
-
-/*
-=====================
-CL_ParseCommandString
-
-Command strings are just saved off until cgame asks for them
-when it transitions a snapshot
-=====================
-*/
-void CL_ParseCommandString( msg_t *msg ) {
- char *s;
- int seq;
- int index;
-
- seq = MSG_ReadLong( msg );
- s = MSG_ReadString( msg );
-
- // see if we have already executed stored it off
- if ( clc.serverCommandSequence >= seq ) {
- return;
- }
- clc.serverCommandSequence = seq;
-
- index = seq & (MAX_RELIABLE_COMMANDS-1);
- Q_strncpyz( clc.serverCommands[ index ], s, sizeof( clc.serverCommands[ index ] ) );
-}
-
-
-/*
-=====================
-CL_ParseServerMessage
-=====================
-*/
-void CL_ParseServerMessage( msg_t *msg ) {
- int cmd;
-
- if ( cl_shownet->integer == 1 ) {
- Com_Printf ("%i ",msg->cursize);
- } else if ( cl_shownet->integer >= 2 ) {
- Com_Printf ("------------------\n");
- }
-
- MSG_Bitstream(msg);
-
- // get the reliable sequence acknowledge number
- clc.reliableAcknowledge = MSG_ReadLong( msg );
- //
- if ( clc.reliableAcknowledge < clc.reliableSequence - MAX_RELIABLE_COMMANDS ) {
- clc.reliableAcknowledge = clc.reliableSequence;
- }
-
- //
- // parse the message
- //
- while ( 1 ) {
- if ( msg->readcount > msg->cursize ) {
- Com_Error (ERR_DROP,"CL_ParseServerMessage: read past end of server message");
- break;
- }
-
- cmd = MSG_ReadByte( msg );
-
- if ( cmd == svc_EOF) {
- SHOWNET( msg, "END OF MESSAGE" );
- break;
- }
-
- if ( cl_shownet->integer >= 2 ) {
- if ( !svc_strings[cmd] ) {
- Com_Printf( "%3i:BAD CMD %i\n", msg->readcount-1, cmd );
- } else {
- SHOWNET( msg, svc_strings[cmd] );
- }
- }
-
- // other commands
- switch ( cmd ) {
- default:
- Com_Error (ERR_DROP,"CL_ParseServerMessage: Illegible server message\n");
- break;
- case svc_nop:
- break;
- case svc_serverCommand:
- CL_ParseCommandString( msg );
- break;
- case svc_gamestate:
- CL_ParseGamestate( msg );
- break;
- case svc_snapshot:
- CL_ParseSnapshot( msg );
- break;
- case svc_download:
- CL_ParseDownload( msg );
- break;
- }
- }
-}
-
-
+/*
+===========================================================================
+Copyright (C) 1999-2005 Id Software, Inc.
+
+This file is part of Quake III Arena source code.
+
+Quake III Arena source code 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.
+
+Quake III Arena source code 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 Foobar; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+===========================================================================
+*/
+// cl_parse.c -- parse a message received from the server
+
+#include "client.h"
+
+char *svc_strings[256] = {
+ "svc_bad",
+
+ "svc_nop",
+ "svc_gamestate",
+ "svc_configstring",
+ "svc_baseline",
+ "svc_serverCommand",
+ "svc_download",
+ "svc_snapshot"
+};
+
+void SHOWNET( msg_t *msg, char *s) {
+ if ( cl_shownet->integer >= 2) {
+ Com_Printf ("%3i:%s\n", msg->readcount-1, s);
+ }
+}
+
+
+/*
+=========================================================================
+
+MESSAGE PARSING
+
+=========================================================================
+*/
+
+/*
+==================
+CL_DeltaEntity
+
+Parses deltas from the given base and adds the resulting entity
+to the current frame
+==================
+*/
+void CL_DeltaEntity (msg_t *msg, clSnapshot_t *frame, int newnum, entityState_t *old,
+ qboolean unchanged) {
+ entityState_t *state;
+
+ // save the parsed entity state into the big circular buffer so
+ // it can be used as the source for a later delta
+ state = &cl.parseEntities[cl.parseEntitiesNum & (MAX_PARSE_ENTITIES-1)];
+
+ if ( unchanged ) {
+ *state = *old;
+ } else {
+ MSG_ReadDeltaEntity( msg, old, state, newnum );
+ }
+
+ if ( state->number == (MAX_GENTITIES-1) ) {
+ return; // entity was delta removed
+ }
+ cl.parseEntitiesNum++;
+ frame->numEntities++;
+}
+
+/*
+==================
+CL_ParsePacketEntities
+
+==================
+*/
+void CL_ParsePacketEntities( msg_t *msg, clSnapshot_t *oldframe, clSnapshot_t *newframe) {
+ int newnum;
+ entityState_t *oldstate;
+ int oldindex, oldnum;
+
+ newframe->parseEntitiesNum = cl.parseEntitiesNum;
+ newframe->numEntities = 0;
+
+ // delta from the entities present in oldframe
+ oldindex = 0;
+ oldstate = NULL;
+ if (!oldframe) {
+ oldnum = 99999;
+ } else {
+ if ( oldindex >= oldframe->numEntities ) {
+ oldnum = 99999;
+ } else {
+ oldstate = &cl.parseEntities[
+ (oldframe->parseEntitiesNum + oldindex) & (MAX_PARSE_ENTITIES-1)];
+ oldnum = oldstate->number;
+ }
+ }
+
+ while ( 1 ) {
+ // read the entity index number
+ newnum = MSG_ReadBits( msg, GENTITYNUM_BITS );
+
+ if ( newnum == (MAX_GENTITIES-1) ) {
+ break;
+ }
+
+ if ( msg->readcount > msg->cursize ) {
+ Com_Error (ERR_DROP,"CL_ParsePacketEntities: end of message");
+ }
+
+ while ( oldnum < newnum ) {
+ // one or more entities from the old packet are unchanged
+ if ( cl_shownet->integer == 3 ) {
+ Com_Printf ("%3i: unchanged: %i\n", msg->readcount, oldnum);
+ }
+ CL_DeltaEntity( msg, newframe, oldnum, oldstate, qtrue );
+
+ oldindex++;
+
+ if ( oldindex >= oldframe->numEntities ) {
+ oldnum = 99999;
+ } else {
+ oldstate = &cl.parseEntities[
+ (oldframe->parseEntitiesNum + oldindex) & (MAX_PARSE_ENTITIES-1)];
+ oldnum = oldstate->number;
+ }
+ }
+ if (oldnum == newnum) {
+ // delta from previous state
+ if ( cl_shownet->integer == 3 ) {
+ Com_Printf ("%3i: delta: %i\n", msg->readcount, newnum);
+ }
+ CL_DeltaEntity( msg, newframe, newnum, oldstate, qfalse );
+
+ oldindex++;
+
+ if ( oldindex >= oldframe->numEntities ) {
+ oldnum = 99999;
+ } else {
+ oldstate = &cl.parseEntities[
+ (oldframe->parseEntitiesNum + oldindex) & (MAX_PARSE_ENTITIES-1)];
+ oldnum = oldstate->number;
+ }
+ continue;
+ }
+
+ if ( oldnum > newnum ) {
+ // delta from baseline
+ if ( cl_shownet->integer == 3 ) {
+ Com_Printf ("%3i: baseline: %i\n", msg->readcount, newnum);
+ }
+ CL_DeltaEntity( msg, newframe, newnum, &cl.entityBaselines[newnum], qfalse );
+ 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->integer == 3 ) {
+ Com_Printf ("%3i: unchanged: %i\n", msg->readcount, oldnum);
+ }
+ CL_DeltaEntity( msg, newframe, oldnum, oldstate, qtrue );
+
+ oldindex++;
+
+ if ( oldindex >= oldframe->numEntities ) {
+ oldnum = 99999;
+ } else {
+ oldstate = &cl.parseEntities[
+ (oldframe->parseEntitiesNum + oldindex) & (MAX_PARSE_ENTITIES-1)];
+ oldnum = oldstate->number;
+ }
+ }
+}
+
+
+/*
+================
+CL_ParseSnapshot
+
+If the snapshot is parsed properly, it will be copied to
+cl.snap and saved in cl.snapshots[]. If the snapshot is invalid
+for any reason, no changes to the state will be made at all.
+================
+*/
+void CL_ParseSnapshot( msg_t *msg ) {
+ int len;
+ clSnapshot_t *old;
+ clSnapshot_t newSnap;
+ int deltaNum;
+ int oldMessageNum;
+ int i, packetNum;
+
+ // get the reliable sequence acknowledge number
+ // NOTE: now sent with all server to client messages
+ //clc.reliableAcknowledge = MSG_ReadLong( msg );
+
+ // read in the new snapshot to a temporary buffer
+ // we will only copy to cl.snap if it is valid
+ Com_Memset (&newSnap, 0, sizeof(newSnap));
+
+ // we will have read any new server commands in this
+ // message before we got to svc_snapshot
+ newSnap.serverCommandNum = clc.serverCommandSequence;
+
+ newSnap.serverTime = MSG_ReadLong( msg );
+
+ newSnap.messageNum = clc.serverMessageSequence;
+
+ deltaNum = MSG_ReadByte( msg );
+ if ( !deltaNum ) {
+ newSnap.deltaNum = -1;
+ } else {
+ newSnap.deltaNum = newSnap.messageNum - deltaNum;
+ }
+ newSnap.snapFlags = MSG_ReadByte( msg );
+
+ // 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 ( newSnap.deltaNum <= 0 ) {
+ newSnap.valid = qtrue; // uncompressed frame
+ old = NULL;
+ clc.demowaiting = qfalse; // we can start recording now
+ } else {
+ old = &cl.snapshots[newSnap.deltaNum & PACKET_MASK];
+ if ( !old->valid ) {
+ // should never happen
+ Com_Printf ("Delta from invalid frame (not supposed to happen!).\n");
+ } else if ( old->messageNum != newSnap.deltaNum ) {
+ // 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.parseEntitiesNum - old->parseEntitiesNum > MAX_PARSE_ENTITIES-128 ) {
+ Com_Printf ("Delta parseEntitiesNum too old.\n");
+ } else {
+ newSnap.valid = qtrue; // valid delta parse
+ }
+ }
+
+ // read areamask
+ len = MSG_ReadByte( msg );
+ MSG_ReadData( msg, &newSnap.areamask, len);
+
+ // read playerinfo
+ SHOWNET( msg, "playerstate" );
+ if ( old ) {
+ MSG_ReadDeltaPlayerstate( msg, &old->ps, &newSnap.ps );
+ } else {
+ MSG_ReadDeltaPlayerstate( msg, NULL, &newSnap.ps );
+ }
+
+ // read packet entities
+ SHOWNET( msg, "packet entities" );
+ CL_ParsePacketEntities( msg, old, &newSnap );
+
+ // if not valid, dump the entire thing now that it has
+ // been properly read
+ if ( !newSnap.valid ) {
+ return;
+ }
+
+ // clear the valid flags of any snapshots between the last
+ // received and this one, so if there was a dropped packet
+ // it won't look like something valid to delta from next
+ // time we wrap around in the buffer
+ oldMessageNum = cl.snap.messageNum + 1;
+
+ if ( newSnap.messageNum - oldMessageNum >= PACKET_BACKUP ) {
+ oldMessageNum = newSnap.messageNum - ( PACKET_BACKUP - 1 );
+ }
+ for ( ; oldMessageNum < newSnap.messageNum ; oldMessageNum++ ) {
+ cl.snapshots[oldMessageNum & PACKET_MASK].valid = qfalse;
+ }
+
+ // copy to the current good spot
+ cl.snap = newSnap;
+ cl.snap.ping = 999;
+ // calculate ping time
+ for ( i = 0 ; i < PACKET_BACKUP ; i++ ) {
+ packetNum = ( clc.netchan.outgoingSequence - 1 - i ) & PACKET_MASK;
+ if ( cl.snap.ps.commandTime >= cl.outPackets[ packetNum ].p_serverTime ) {
+ cl.snap.ping = cls.realtime - cl.outPackets[ packetNum ].p_realtime;
+ break;
+ }
+ }
+ // save the frame off in the backup array for later delta comparisons
+ cl.snapshots[cl.snap.messageNum & PACKET_MASK] = cl.snap;
+
+ if (cl_shownet->integer == 3) {
+ Com_Printf( " snapshot:%i delta:%i ping:%i\n", cl.snap.messageNum,
+ cl.snap.deltaNum, cl.snap.ping );
+ }
+
+ cl.newSnapshots = qtrue;
+}
+
+
+//=====================================================================
+
+int cl_connectedToPureServer;
+
+/*
+==================
+CL_SystemInfoChanged
+
+The systeminfo configstring has been changed, so parse
+new information out of it. This will happen at every
+gamestate, and possibly during gameplay.
+==================
+*/
+void CL_SystemInfoChanged( void ) {
+ char *systemInfo;
+ const char *s, *t;
+ char key[BIG_INFO_KEY];
+ char value[BIG_INFO_VALUE];
+ qboolean gameSet;
+
+ systemInfo = cl.gameState.stringData + cl.gameState.stringOffsets[ CS_SYSTEMINFO ];
+ // NOTE TTimo:
+ // when the serverId changes, any further messages we send to the server will use this new serverId
+ // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=475
+ // in some cases, outdated cp commands might get sent with this news serverId
+ cl.serverId = atoi( Info_ValueForKey( systemInfo, "sv_serverid" ) );
+
+ // don't set any vars when playing a demo
+ if ( clc.demoplaying ) {
+ return;
+ }
+
+ s = Info_ValueForKey( systemInfo, "sv_cheats" );
+ if ( atoi(s) == 0 ) {
+ Cvar_SetCheatState();
+ }
+
+ // check pure server string
+ s = Info_ValueForKey( systemInfo, "sv_paks" );
+ t = Info_ValueForKey( systemInfo, "sv_pakNames" );
+ FS_PureServerSetLoadedPaks( s, t );
+
+ s = Info_ValueForKey( systemInfo, "sv_referencedPaks" );
+ t = Info_ValueForKey( systemInfo, "sv_referencedPakNames" );
+ FS_PureServerSetReferencedPaks( s, t );
+
+ gameSet = qfalse;
+ // scan through all the variables in the systeminfo and locally set cvars to match
+ s = systemInfo;
+ while ( s ) {
+ Info_NextPair( &s, key, value );
+ if ( !key[0] ) {
+ break;
+ }
+ // ehw!
+ if ( !Q_stricmp( key, "fs_game" ) ) {
+ gameSet = qtrue;
+ }
+
+ Cvar_Set( key, value );
+ }
+ // if game folder should not be set and it is set at the client side
+ if ( !gameSet && *Cvar_VariableString("fs_game") ) {
+ Cvar_Set( "fs_game", "" );
+ }
+ cl_connectedToPureServer = Cvar_VariableValue( "sv_pure" );
+}
+
+/*
+==================
+CL_ParseGamestate
+==================
+*/
+void CL_ParseGamestate( msg_t *msg ) {
+ int i;
+ entityState_t *es;
+ int newnum;
+ entityState_t nullstate;
+ int cmd;
+ char *s;
+
+ Con_Close();
+
+ clc.connectPacketCount = 0;
+
+ // wipe local client state
+ CL_ClearState();
+
+ // a gamestate always marks a server command sequence
+ clc.serverCommandSequence = MSG_ReadLong( msg );
+
+ // parse all the configstrings and baselines
+ cl.gameState.dataCount = 1; // leave a 0 at the beginning for uninitialized configstrings
+ while ( 1 ) {
+ cmd = MSG_ReadByte( msg );
+
+ if ( cmd == svc_EOF ) {
+ break;
+ }
+
+ if ( cmd == svc_configstring ) {
+ int len;
+
+ i = MSG_ReadShort( msg );
+ if ( i < 0 || i >= MAX_CONFIGSTRINGS ) {
+ Com_Error( ERR_DROP, "configstring > MAX_CONFIGSTRINGS" );
+ }
+ s = MSG_ReadBigString( msg );
+ len = strlen( s );
+
+ if ( len + 1 + cl.gameState.dataCount > MAX_GAMESTATE_CHARS ) {
+ Com_Error( ERR_DROP, "MAX_GAMESTATE_CHARS exceeded" );
+ }
+
+ // append it to the gameState string buffer
+ cl.gameState.stringOffsets[ i ] = cl.gameState.dataCount;
+ Com_Memcpy( cl.gameState.stringData + cl.gameState.dataCount, s, len + 1 );
+ cl.gameState.dataCount += len + 1;
+ } else if ( cmd == svc_baseline ) {
+ newnum = MSG_ReadBits( msg, GENTITYNUM_BITS );
+ if ( newnum < 0 || newnum >= MAX_GENTITIES ) {
+ Com_Error( ERR_DROP, "Baseline number out of range: %i", newnum );
+ }
+ Com_Memset (&nullstate, 0, sizeof(nullstate));
+ es = &cl.entityBaselines[ newnum ];
+ MSG_ReadDeltaEntity( msg, &nullstate, es, newnum );
+ } else {
+ Com_Error( ERR_DROP, "CL_ParseGamestate: bad command byte" );
+ }
+ }
+
+ clc.clientNum = MSG_ReadLong(msg);
+ // read the checksum feed
+ clc.checksumFeed = MSG_ReadLong( msg );
+
+ // parse serverId and other cvars
+ CL_SystemInfoChanged();
+
+ // reinitialize the filesystem if the game directory has changed
+ FS_ConditionalRestart( clc.checksumFeed );
+
+ // This used to call CL_StartHunkUsers, but now we enter the download state before loading the
+ // cgame
+ CL_InitDownloads();
+
+ // make sure the game starts
+ Cvar_Set( "cl_paused", "0" );
+}
+
+
+//=====================================================================
+
+/*
+=====================
+CL_ParseDownload
+
+A download message has been received from the server
+=====================
+*/
+void CL_ParseDownload ( msg_t *msg ) {
+ int size;
+ unsigned char data[MAX_MSGLEN];
+ int block;
+
+ // read the data
+ block = MSG_ReadShort ( msg );
+
+ if ( !block )
+ {
+ // block zero is special, contains file size
+ clc.downloadSize = MSG_ReadLong ( msg );
+
+ Cvar_SetValue( "cl_downloadSize", clc.downloadSize );
+
+ if (clc.downloadSize < 0)
+ {
+ Com_Error(ERR_DROP, MSG_ReadString( msg ) );
+ return;
+ }
+ }
+
+ size = MSG_ReadShort ( msg );
+ if (size > 0)
+ MSG_ReadData( msg, data, size );
+
+ if (clc.downloadBlock != block) {
+ Com_DPrintf( "CL_ParseDownload: Expected block %d, got %d\n", clc.downloadBlock, block);
+ return;
+ }
+
+ // open the file if not opened yet
+ if (!clc.download)
+ {
+ if (!*clc.downloadTempName) {
+ Com_Printf("Server sending download, but no download was requested\n");
+ CL_AddReliableCommand( "stopdl" );
+ return;
+ }
+
+ clc.download = FS_SV_FOpenFileWrite( clc.downloadTempName );
+
+ if (!clc.download) {
+ Com_Printf( "Could not create %s\n", clc.downloadTempName );
+ CL_AddReliableCommand( "stopdl" );
+ CL_NextDownload();
+ return;
+ }
+ }
+
+ if (size)
+ FS_Write( data, size, clc.download );
+
+ CL_AddReliableCommand( va("nextdl %d", clc.downloadBlock) );
+ clc.downloadBlock++;
+
+ clc.downloadCount += size;
+
+ // So UI gets access to it
+ Cvar_SetValue( "cl_downloadCount", clc.downloadCount );
+
+ if (!size) { // A zero length block means EOF
+ if (clc.download) {
+ FS_FCloseFile( clc.download );
+ clc.download = 0;
+
+ // rename the file
+ FS_SV_Rename ( clc.downloadTempName, clc.downloadName );
+ }
+ *clc.downloadTempName = *clc.downloadName = 0;
+ Cvar_Set( "cl_downloadName", "" );
+
+ // send intentions now
+ // We need this because without it, we would hold the last nextdl and then start
+ // loading right away. If we take a while to load, the server is happily trying
+ // to send us that last block over and over.
+ // Write it twice to help make sure we acknowledge the download
+ CL_WritePacket();
+ CL_WritePacket();
+
+ // get another file if needed
+ CL_NextDownload ();
+ }
+}
+
+/*
+=====================
+CL_ParseCommandString
+
+Command strings are just saved off until cgame asks for them
+when it transitions a snapshot
+=====================
+*/
+void CL_ParseCommandString( msg_t *msg ) {
+ char *s;
+ int seq;
+ int index;
+
+ seq = MSG_ReadLong( msg );
+ s = MSG_ReadString( msg );
+
+ // see if we have already executed stored it off
+ if ( clc.serverCommandSequence >= seq ) {
+ return;
+ }
+ clc.serverCommandSequence = seq;
+
+ index = seq & (MAX_RELIABLE_COMMANDS-1);
+ Q_strncpyz( clc.serverCommands[ index ], s, sizeof( clc.serverCommands[ index ] ) );
+}
+
+
+/*
+=====================
+CL_ParseServerMessage
+=====================
+*/
+void CL_ParseServerMessage( msg_t *msg ) {
+ int cmd;
+
+ if ( cl_shownet->integer == 1 ) {
+ Com_Printf ("%i ",msg->cursize);
+ } else if ( cl_shownet->integer >= 2 ) {
+ Com_Printf ("------------------\n");
+ }
+
+ MSG_Bitstream(msg);
+
+ // get the reliable sequence acknowledge number
+ clc.reliableAcknowledge = MSG_ReadLong( msg );
+ //
+ if ( clc.reliableAcknowledge < clc.reliableSequence - MAX_RELIABLE_COMMANDS ) {
+ clc.reliableAcknowledge = clc.reliableSequence;
+ }
+
+ //
+ // parse the message
+ //
+ while ( 1 ) {
+ if ( msg->readcount > msg->cursize ) {
+ Com_Error (ERR_DROP,"CL_ParseServerMessage: read past end of server message");
+ break;
+ }
+
+ cmd = MSG_ReadByte( msg );
+
+ if ( cmd == svc_EOF) {
+ SHOWNET( msg, "END OF MESSAGE" );
+ break;
+ }
+
+ if ( cl_shownet->integer >= 2 ) {
+ if ( !svc_strings[cmd] ) {
+ Com_Printf( "%3i:BAD CMD %i\n", msg->readcount-1, cmd );
+ } else {
+ SHOWNET( msg, svc_strings[cmd] );
+ }
+ }
+
+ // other commands
+ switch ( cmd ) {
+ default:
+ Com_Error (ERR_DROP,"CL_ParseServerMessage: Illegible server message\n");
+ break;
+ case svc_nop:
+ break;
+ case svc_serverCommand:
+ CL_ParseCommandString( msg );
+ break;
+ case svc_gamestate:
+ CL_ParseGamestate( msg );
+ break;
+ case svc_snapshot:
+ CL_ParseSnapshot( msg );
+ break;
+ case svc_download:
+ CL_ParseDownload( msg );
+ break;
+ }
+ }
+}
+
+