From 6bf20c78f5b69d40bcc4931df93d29198435ab67 Mon Sep 17 00:00:00 2001 From: zakk Date: Fri, 26 Aug 2005 17:39:27 +0000 Subject: newlines fixed git-svn-id: svn://svn.icculus.org/quake3/trunk@6 edf5b092-35ff-0310-97b2-ce42778d08ea --- code/client/cl_parse.c | 1310 ++++++++++++++++++++++++------------------------ 1 file changed, 655 insertions(+), 655 deletions(-) (limited to 'code/client/cl_parse.c') 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; + } + } +} + + -- cgit v1.2.3