/* ===================== 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"); } // // 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 == -1 ) { 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; } } }
/* * 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" ); } // parse the message while( 1 ) { if( msg->readcount > msg->cursize ) { Com_Error( ERR_DROP, "CL_ParseServerMessage: Bad server message" ); break; } cmd = MSG_ReadByte( msg ); if( cl_debug_serverCmd->integer & 4 ) { if( cmd == -1 ) Com_Printf( "%3i:CMD %i %s\n", msg->readcount-1, cmd, "EOF" ); else Com_Printf( "%3i:CMD %i %s\n", msg->readcount-1, cmd, !svc_strings[cmd] ? "bad" : svc_strings[cmd] ); } if( cmd == -1 ) { 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" ); break; case svc_nop: // Com_Printf( "svc_nop\n" ); break; case svc_servercmd: if( !cls.reliable ) { int cmdNum = MSG_ReadLong( msg ); if( cmdNum < 0 ) { Com_Error( ERR_DROP, "CL_ParseServerMessage: Invalid cmdNum value received: %i\n", cmdNum ); return; } if( cmdNum <= cls.lastExecutedServerCommand ) { MSG_ReadString( msg ); // read but ignore break; } cls.lastExecutedServerCommand = cmdNum; } // fall through case svc_servercs: // configstrings from demo files. they don't have acknowledge CL_ParseServerCommand( msg ); break; case svc_serverdata: if( cls.state == CA_HANDSHAKE ) { Cbuf_Execute(); // make sure any stuffed commands are done CL_ParseServerData( msg ); } else { return; // ignore rest of the packet (serverdata is always sent alone) } break; case svc_spawnbaseline: CL_ParseBaseline( msg ); break; case svc_download: CL_ParseDownload( msg ); break; case svc_clcack: if( cls.reliable ) { Com_Error( ERR_DROP, "CL_ParseServerMessage: clack message for reliable client\n" ); return; } cls.reliableAcknowledge = (unsigned)MSG_ReadLong( msg ); cls.ucmdAcknowledged = (unsigned)MSG_ReadLong( msg ); if( cl_debug_serverCmd->integer & 4 ) Com_Printf( "svc_clcack:reliable cmd ack:%i ucmdack:%i\n", cls.reliableAcknowledge, cls.ucmdAcknowledged ); break; case svc_frame: CL_ParseFrame( msg ); break; case svc_demoinfo: assert( cls.demo.playing ); { size_t meta_data_maxsize; MSG_ReadLong( msg ); MSG_ReadLong( msg ); cls.demo.meta_data_realsize = (size_t)MSG_ReadLong( msg ); meta_data_maxsize = (size_t)MSG_ReadLong( msg ); // sanity check if( cls.demo.meta_data_realsize > meta_data_maxsize ) { cls.demo.meta_data_realsize = meta_data_maxsize; } if( cls.demo.meta_data_realsize > sizeof( cls.demo.meta_data ) ) { cls.demo.meta_data_realsize = sizeof( cls.demo.meta_data ); } MSG_ReadData( msg, cls.demo.meta_data, cls.demo.meta_data_realsize ); MSG_SkipData( msg, meta_data_maxsize - cls.demo.meta_data_realsize ); } break; case svc_playerinfo: case svc_packetentities: case svc_match: Com_Error( ERR_DROP, "Out of place frame data" ); break; case svc_extension: if( 1 ) { int ext, len; ext = MSG_ReadByte( msg ); // extension id MSG_ReadByte( msg ); // version number len = MSG_ReadShort( msg ); // command length switch( ext ) { default: // unsupported MSG_SkipData( msg, len ); break; } } break; } } CL_AddNetgraph(); // // if recording demos, copy the message out // // // we don't know if it is ok to save a demo message until // after we have parsed the frame // if( cls.demo.recording && !cls.demo.waiting ) CL_WriteDemoMessage( msg ); }
/* ================ 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 ); // if we were just unpaused, we can only *now* really let the // change come into effect or the client hangs. cl_paused->modified = qfalse; 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_DPrintf ("Delta parseEntitiesNum too old.\n"); } else { newSnap.valid = qtrue; // valid delta parse } } // read areamask len = MSG_ReadByte( msg ); if((unsigned)len > sizeof(newSnap.areamask)) { Com_Error (ERR_DROP,"CL_ParseSnapshot: Invalid size %d for areamask", len); return; } MSG_ReadData( msg, &newSnap.areamask, len); // read playerinfo SHOWNET( msg, "playerstate" ); if ( old ) { MSG_ReadDeltaPlayerstate( msg, &old->ps, &newSnap.ps ); if (newSnap.ps.m_iVehicleNum) { //this means we must have written our vehicle's ps too MSG_ReadDeltaPlayerstate( msg, &old->vps, &newSnap.vps, qtrue ); } } else { MSG_ReadDeltaPlayerstate( msg, NULL, &newSnap.ps ); if (newSnap.ps.m_iVehicleNum) { //this means we must have written our vehicle's ps too MSG_ReadDeltaPlayerstate( msg, NULL, &newSnap.vps, qtrue ); } } // 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; }
/* ================ CL_ParseSnapshot If the snapshot is parsed properly, it will be copied to cl.frame and saved in cl.frames[]. 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 clc.reliableAcknowledge = MSG_ReadLong( msg ); // read in the new snapshot to a temporary buffer // we will only copy to cl.frame if it is valid memset (&newSnap, 0, sizeof(newSnap)); newSnap.serverCommandNum = clc.serverCommandSequence; newSnap.serverTime = MSG_ReadLong( msg ); newSnap.messageNum = MSG_ReadLong( msg ); deltaNum = MSG_ReadByte( msg ); if ( !deltaNum ) { newSnap.deltaNum = -1; } else { newSnap.deltaNum = newSnap.messageNum - deltaNum; } newSnap.cmdNum = MSG_ReadLong( msg ); 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; } else { old = &cl.frames[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 ) { 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 oldMessageNum = cl.frame.messageNum + 1; if ( cl.frame.messageNum - oldMessageNum >= PACKET_BACKUP ) { oldMessageNum = cl.frame.messageNum - ( PACKET_BACKUP - 1 ); } for ( ; oldMessageNum < newSnap.messageNum ; oldMessageNum++ ) { cl.frames[oldMessageNum & PACKET_MASK].valid = qfalse; } // copy to the current good spot cl.frame = newSnap; // calculate ping time for ( i = 0 ; i < PACKET_BACKUP ; i++ ) { packetNum = ( clc.netchan.outgoingSequence - 1 - i ) & PACKET_MASK; if ( cl.frame.cmdNum == cl.packetCmdNumber[ packetNum ] ) { cl.frame.ping = cls.realtime - cl.packetTime[ packetNum ]; break; } } // save the frame off in the backup array for later delta comparisons cl.frames[cl.frame.messageNum & PACKET_MASK] = cl.frame; if (cl_shownet->integer == 3) { Com_Printf (" frame:%i delta:%i\n", cl.frame.messageNum, cl.frame.deltaNum); } // actions for valid frames cl.newSnapshots = qtrue; }
void CL_ParseServerMessage (void) { int cmd; int i; // // if recording demos, copy the message out // if (cl_shownet.value == 1) Con_Printf ("%i ",net_message.cursize); else if (cl_shownet.value == 2) Con_Printf ("------------------\n"); cl.onground = false; // unless the server says otherwise // // parse the message // MSG_BeginReading (); while (1) { if (msg_badread) Host_Error ("CL_ParseServerMessage: Bad server message"); cmd = MSG_ReadByte (); if (cmd == -1) { SHOWNET("END OF MESSAGE"); return; // end of message } // if the high bit of the command byte is set, it is a fast update if (cmd & 128) { SHOWNET("fast update"); CL_ParseUpdate (cmd&127); continue; } SHOWNET(svc_strings[cmd]); // other commands switch (cmd) { default: Host_Error ("CL_ParseServerMessage: Illegible server message\n"); break; case svc_nop: // Con_Printf ("svc_nop\n"); break; case svc_time: cl.mtime[1] = cl.mtime[0]; cl.mtime[0] = MSG_ReadFloat (); break; case svc_clientdata: i = MSG_ReadShort (); CL_ParseClientdata (i); break; case svc_version: i = MSG_ReadLong (); if (i != PROTOCOL_VERSION) Host_Error ("CL_ParseServerMessage: Server is protocol %i instead of %i\n", i, PROTOCOL_VERSION); break; case svc_disconnect: Host_EndGame ("Server disconnected\n"); case svc_print: Con_Printf ("%s", MSG_ReadString ()); break; case svc_centerprint: SCR_CenterPrint (MSG_ReadString ()); break; case svc_stufftext: Cbuf_AddText (MSG_ReadString ()); break; case svc_damage: V_ParseDamage (); break; case svc_serverinfo: CL_ParseServerInfo (); vid.recalc_refdef = true; // leave intermission full screen break; case svc_setangle: for (i=0 ; i<3 ; i++) cl.viewangles[i] = MSG_ReadAngle (); break; case svc_setview: cl.viewentity = MSG_ReadShort (); break; case svc_lightstyle: i = MSG_ReadByte (); if (i >= MAX_LIGHTSTYLES) Sys_Error ("svc_lightstyle > MAX_LIGHTSTYLES"); Q_strcpy (cl_lightstyle[i].map, MSG_ReadString()); cl_lightstyle[i].length = Q_strlen(cl_lightstyle[i].map); break; case svc_sound: CL_ParseStartSoundPacket(); break; case svc_stopsound: i = MSG_ReadShort(); S_StopSound(i>>3, i&7); break; case svc_updatename: Sbar_Changed (); i = MSG_ReadByte (); if (i >= cl.maxclients) Host_Error ("CL_ParseServerMessage: svc_updatename > MAX_SCOREBOARD"); strcpy (cl.scores[i].name, MSG_ReadString ()); break; case svc_updatefrags: Sbar_Changed (); i = MSG_ReadByte (); if (i >= cl.maxclients) Host_Error ("CL_ParseServerMessage: svc_updatefrags > MAX_SCOREBOARD"); cl.scores[i].frags = MSG_ReadShort (); break; case svc_updatecolors: Sbar_Changed (); i = MSG_ReadByte (); if (i >= cl.maxclients) Host_Error ("CL_ParseServerMessage: svc_updatecolors > MAX_SCOREBOARD"); cl.scores[i].colors = MSG_ReadByte (); CL_NewTranslation (i); break; case svc_particle: R_ParseParticleEffect (); break; case svc_spawnbaseline: i = MSG_ReadShort (); // must use CL_EntityNum() to force cl.num_entities up CL_ParseBaseline (CL_EntityNum(i)); break; case svc_spawnstatic: CL_ParseStatic (); break; case svc_temp_entity: CL_ParseTEnt (); break; case svc_setpause: { cl.paused = MSG_ReadByte (); if (cl.paused) { CDAudio_Pause (); #ifdef _WIN32 VID_HandlePause (true); #endif } else { CDAudio_Resume (); #ifdef _WIN32 VID_HandlePause (false); #endif } } break; case svc_signonnum: i = MSG_ReadByte (); if (i <= cls.signon) Host_Error ("Received signon %i when at %i", i, cls.signon); cls.signon = i; CL_SignonReply (); break; case svc_killedmonster: cl.stats[STAT_MONSTERS]++; break; case svc_foundsecret: cl.stats[STAT_SECRETS]++; break; case svc_updatestat: i = MSG_ReadByte (); if (i < 0 || i >= MAX_CL_STATS) Sys_Error ("svc_updatestat: %i is invalid", i); cl.stats[i] = MSG_ReadLong ();; break; case svc_spawnstaticsound: CL_ParseStaticSound (); break; case svc_cdtrack: cl.cdtrack = MSG_ReadByte (); cl.looptrack = MSG_ReadByte (); if ( (cls.demoplayback || cls.demorecording) && (cls.forcetrack != -1) ) CDAudio_Play ((byte)cls.forcetrack, true); else CDAudio_Play ((byte)cl.cdtrack, true); break; case svc_intermission: cl.intermission = 1; cl.completed_time = (int) cl.time; vid.recalc_refdef = true; // go to full screen break; case svc_finale: cl.intermission = 2; cl.completed_time = (int) cl.time; vid.recalc_refdef = true; // go to full screen SCR_CenterPrint (MSG_ReadString ()); break; case svc_cutscene: cl.intermission = 3; cl.completed_time = (int) cl.time; vid.recalc_refdef = true; // go to full screen SCR_CenterPrint (MSG_ReadString ()); break; case svc_sellscreen: Cmd_ExecuteString2 ("help", src_command); break; } } }
/* ===================== CL_ParseServerMessage ===================== */ void CL_ParseServerMessage( msg_t *msg ) { int cmd; // msg_t msgback; // msgback = *msg; if ( cl_shownet->integer == 1 ) { Log::Notice("%i ", msg->cursize ); } else if ( cl_shownet->integer >= 2 ) { Log::Notice( "------------------\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( errorParm_t::ERR_DROP, "CL_ParseServerMessage: read past end of server message" ); } cmd = MSG_ReadByte( msg ); if ( cmd < 0 || cmd == svc_EOF ) { SHOWNET( msg, "END OF MESSAGE" ); break; } if ( cl_shownet->integer >= 2 ) { if ( !svc_strings[ cmd ] ) { Log::Notice( "%3i:BAD CMD %i\n", msg->readcount - 1, cmd ); } else { SHOWNET( msg, svc_strings[ cmd ] ); } } // other commands switch ( cmd ) { default: Com_Error( errorParm_t::ERR_DROP, "CL_ParseServerMessage: Illegible server message %d", cmd ); 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; } } }
void CLQ2_ParseFrame( QMsg& message ) { Com_Memset( &cl.q2_frame, 0, sizeof ( cl.q2_frame ) ); cl.q2_frame.serverframe = message.ReadLong(); cl.q2_frame.deltaframe = message.ReadLong(); cl.q2_frame.servertime = cl.q2_frame.serverframe * 100; // BIG HACK to let old demos continue to work if ( cls.q2_serverProtocol != 26 ) { cl.q2_surpressCount = message.ReadByte(); } if ( cl_shownet->value == 3 ) { common->Printf( " frame:%i delta:%i\n", cl.q2_frame.serverframe, cl.q2_frame.deltaframe ); } // If the frame is delta compressed from data that we // no longer have available, we must suck up the rest of // the frame, but not use it, then ask for a non-compressed // message q2frame_t* old; if ( cl.q2_frame.deltaframe <= 0 ) { cl.q2_frame.valid = true; // uncompressed frame old = NULL; cls.q2_demowaiting = false; // we can start recording now } else { old = &cl.q2_frames[ cl.q2_frame.deltaframe & UPDATE_MASK_Q2 ]; if ( !old->valid ) {// should never happen common->Printf( "Delta from invalid frame (not supposed to happen!).\n" ); } if ( old->serverframe != cl.q2_frame.deltaframe ) { // The frame that the server did the delta from // is too old, so we can't reconstruct it properly. common->Printf( "Delta frame too old.\n" ); } else if ( cl.parseEntitiesNum - old->parse_entities > MAX_PARSE_ENTITIES_Q2 - 128 ) { common->Printf( "Delta parse_entities too old.\n" ); } else { cl.q2_frame.valid = true; // valid delta parse } } // clamp time if ( cl.serverTime > cl.q2_frame.servertime ) { cl.serverTime = cl.q2_frame.servertime; } else if ( cl.serverTime < cl.q2_frame.servertime - 100 ) { cl.serverTime = cl.q2_frame.servertime - 100; } // read areabits int len = message.ReadByte(); message.ReadData( &cl.q2_frame.areabits, len ); // read playerinfo int cmd = message.ReadByte(); SHOWNET( message, svcq2_strings[ cmd ] ); if ( cmd != q2svc_playerinfo ) { common->Error( "CLQ2_ParseFrame: not playerinfo" ); } CLQ2_ParsePlayerstate( message, old, &cl.q2_frame ); // read packet entities cmd = message.ReadByte(); SHOWNET( message, svcq2_strings[ cmd ] ); if ( cmd != q2svc_packetentities ) { common->Error( "CLQ2_ParseFrame: not packetentities" ); } CLQ2_ParsePacketEntities( message, old, &cl.q2_frame ); // save the frame off in the backup array for later delta comparisons cl.q2_frames[ cl.q2_frame.serverframe & UPDATE_MASK_Q2 ] = cl.q2_frame; if ( cl.q2_frame.valid ) { // getting a valid frame message ends the connection process if ( cls.state != CA_ACTIVE ) { cls.state = CA_ACTIVE; cl.q2_predicted_origin[ 0 ] = cl.q2_frame.playerstate.pmove.origin[ 0 ] * 0.125; cl.q2_predicted_origin[ 1 ] = cl.q2_frame.playerstate.pmove.origin[ 1 ] * 0.125; cl.q2_predicted_origin[ 2 ] = cl.q2_frame.playerstate.pmove.origin[ 2 ] * 0.125; VectorCopy( cl.q2_frame.playerstate.viewangles, cl.q2_predicted_angles ); if ( cls.q2_disable_servercount != cl.servercount && cl.q2_refresh_prepped ) { SCR_EndLoadingPlaque(); // get rid of loading plaque } } cl.q2_sound_prepped = true; // can start mixing ambient sounds // fire entity events CLQ2_FireEntityEvents( &cl.q2_frame ); CLQ2_CheckPredictionError(); } }
/* ===================== CL_ParseServerMessage ===================== */ void CL_ParseServerMessage( msg_t *msg ) { int cmd; // msg_t msgback; // msgback = *msg; 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" ); } cmd = MSG_ReadByte( msg ); // See if this is an extension command after the EOF, which means we // got data that a legacy client should ignore. if ( ( cmd == svc_EOF ) && ( MSG_LookaheadByte( msg ) == svc_extension ) ) { SHOWNET( msg, "EXTENSION" ); MSG_ReadByte( msg ); // throw the svc_extension byte away. cmd = MSG_ReadByte( msg ); // something legacy clients can't do! // sometimes you get a svc_extension at end of stream...dangling // bits in the huffman decoder giving a bogus value? if ( cmd == -1 ) { cmd = svc_EOF; } } 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 %d", cmd ); 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; case svc_voip: #ifdef USE_VOIP CL_ParseVoip( msg ); #endif break; } } }
/* ===================== CL_ParseServerMessage ===================== */ void CL_ParseServerMessage (void) { int cmd; int i, j, k; int EntityCount = 0; int EntitySize = 0; int before; static double lasttime; static qboolean packet_loss = false; entity_t *ent; short RemovePlace, OrigPlace, NewPlace, AddedIndex; int sc1, sc2; byte test; float compangles[2][3]; vec3_t deltaangles; // // if recording demos, copy the message out // if (net_message.cursize > LastServerMessageSize) { LastServerMessageSize = net_message.cursize; } if (cl_shownet.integer == 1) { Con_Printf ("Time: %2.2f Pck: %i ", realtime - lasttime, net_message.cursize); lasttime = realtime; } else if (cl_shownet.integer == 2) Con_Printf ("------------------\n"); cl.onground = false; // unless the server says otherwise // // parse the message // MSG_BeginReading (); while (1) { if (msg_badread) Host_Error ("%s: Bad server message", __thisfunc__); cmd = MSG_ReadByte (); if (cmd == -1) { if (cl_shownet.integer == 1) Con_Printf ("Ent: %i (%i bytes)",EntityCount,EntitySize); SHOWNET("END OF MESSAGE"); return; // end of message } // if the high bit of the command byte is set, it is a fast update if (cmd & 128) { before = msg_readcount; SHOWNET("fast update"); if (packet_loss) CL_ParseUpdate2 (cmd&127); else CL_ParseUpdate (cmd&127); EntityCount++; EntitySize += msg_readcount - before + 1; continue; } if (cmd < NUM_SVC_STRINGS) // else, it'll hit the illegible message below { SHOWNET(svc_strings[cmd]); } // other commands switch (cmd) { default: // CL_DumpPacket (); Host_Error ("%s: Illegible server message %d", __thisfunc__, cmd); break; case svc_nop: // Con_Printf ("svc_nop\n"); break; case svc_time: cl.mtime[1] = cl.mtime[0]; cl.mtime[0] = MSG_ReadFloat (); break; case svc_clientdata: i = MSG_ReadShort (); CL_ParseClientdata (i); break; case svc_version: cl_protocol = MSG_ReadLong (); switch (cl_protocol) { case PROTOCOL_RAVEN_111: case PROTOCOL_RAVEN_112: case PROTOCOL_UQE_113: Con_Printf ("Server using protocol %i\n", cl_protocol); break; default: Host_Error ("%s: Server is protocol %i instead of %i or %i", __thisfunc__, cl_protocol, PROTOCOL_RAVEN_112, PROTOCOL_UQE_113); } break; case svc_disconnect: Host_EndGame ("Server disconnected\n"); break; case svc_print: if (intro_playing) MSG_ReadString (); else Con_Printf ("%s", MSG_ReadString ()); break; case svc_centerprint: SCR_CenterPrint (MSG_ReadString ()); break; case svc_stufftext: stufftext_frame = host_framecount; // allow full frame update // on stuff messages. Pa3PyX Cbuf_AddText (MSG_ReadString ()); break; case svc_damage: V_ParseDamage (); break; case svc_serverinfo: CL_ParseServerInfo (); vid.recalc_refdef = true; // leave intermission full screen break; case svc_setangle: for (i = 0; i < 3; i++) cl.viewangles[i] = MSG_ReadAngle (); break; case svc_setangle_interpolate: compangles[0][0] = MSG_ReadAngle(); compangles[0][1] = MSG_ReadAngle(); compangles[0][2] = MSG_ReadAngle(); for (i = 0; i < 3; i++) { compangles[1][i] = cl.viewangles[i]; for (j = 0; j < 2; j++) {//standardize both old and new angles to +-180 if (compangles[j][i] >= 360) compangles[j][i] -= 360*((int)(compangles[j][i]/360)); else if (compangles[j][i] <= 360) compangles[j][i] += 360*(1+(int)(-compangles[j][i]/360)); if (compangles[j][i] > 180) compangles[j][i] = -360 + compangles[j][i]; else if (compangles[j][i] < -180) compangles[j][i] = 360 + compangles[j][i]; } //get delta deltaangles[i] = compangles[0][i] - compangles[1][i]; //cap delta to <=180,>=-180 if (deltaangles[i] > 180) deltaangles[i] += -360; else if (deltaangles[i] < -180) deltaangles[i] += 360; //add the delta cl.viewangles[i]+=(deltaangles[i]/8);//8 step interpolation //cap newangles to +-180 if (cl.viewangles[i] >= 360) cl.viewangles[i] -= 360*((int)(cl.viewangles[i]/360)); else if (cl.viewangles[i] <= 360) cl.viewangles[i] += 360*(1+(int)(-cl.viewangles[i]/360)); if (cl.viewangles[i] > 180) cl.viewangles[i] += -360; else if (cl.viewangles[i] < -180) cl.viewangles[i] += 360; } break; case svc_setview: cl.viewentity = MSG_ReadShort (); break; case svc_lightstyle: i = MSG_ReadByte (); if (i >= MAX_LIGHTSTYLES) Sys_Error ("svc_lightstyle > MAX_LIGHTSTYLES"); q_strlcpy (cl_lightstyle[i].map, MSG_ReadString(), MAX_STYLESTRING); cl_lightstyle[i].length = strlen(cl_lightstyle[i].map); break; case svc_sound: CL_ParseStartSoundPacket(); break; case svc_sound_update_pos: {//FIXME: put a field on the entity that lists the channels //it should update when it moves- if a certain flag //is on the ent, this update_channels field could //be set automatically by each sound and stopSound //called for this ent? vec3_t pos; int channel, ent_num; channel = MSG_ReadShort (); ent_num = channel >> 3; channel &= 7; if (ent_num > MAX_EDICTS) Host_Error ("svc_sound_update_pos: ent = %i", ent_num); for (i = 0; i < 3; i++) pos[i] = MSG_ReadCoord (); S_UpdateSoundPos (ent_num, channel, pos); } break; case svc_stopsound: i = MSG_ReadShort(); S_StopSound(i>>3, i&7); break; case svc_updatename: Sbar_Changed(); i = MSG_ReadByte (); if (i >= cl.maxclients) Host_Error ("%s: svc_updatename > MAX_CLIENTS", __thisfunc__); q_strlcpy (cl.scores[i].name, MSG_ReadString(), MAX_SCOREBOARDNAME); break; case svc_updateclass: Sbar_Changed(); i = MSG_ReadByte (); if (i >= cl.maxclients) Host_Error ("%s: svc_updateclass > MAX_CLIENTS", __thisfunc__); cl.scores[i].playerclass = (float)MSG_ReadByte(); CL_NewTranslation(i); // update the color break; case svc_updatefrags: Sbar_Changed(); i = MSG_ReadByte (); if (i >= cl.maxclients) Host_Error ("%s: svc_updatefrags > MAX_CLIENTS", __thisfunc__); cl.scores[i].frags = MSG_ReadShort (); break; case svc_update_kingofhill: sv_kingofhill = MSG_ReadShort() - 1; break; case svc_updatecolors: Sbar_Changed(); i = MSG_ReadByte (); if (i >= cl.maxclients) Host_Error ("%s: svc_updatecolors > MAX_CLIENTS", __thisfunc__); cl.scores[i].colors = MSG_ReadByte (); CL_NewTranslation (i); break; case svc_particle: R_ParseParticleEffect (); break; case svc_particle2: R_ParseParticleEffect2 (); break; case svc_particle3: R_ParseParticleEffect3 (); break; case svc_particle4: R_ParseParticleEffect4 (); break; case svc_spawnbaseline: i = MSG_ReadShort (); // must use CL_EntityNum() to force cl.num_entities up CL_ParseBaseline (CL_EntityNum(i)); break; case svc_spawnstatic: CL_ParseStatic (); break; case svc_raineffect: CL_ParseRainEffect(); break; case svc_temp_entity: CL_ParseTEnt (); break; case svc_setpause: cl.paused = MSG_ReadByte (); if (cl.paused) { CDAudio_Pause (); VID_HandlePause (true); } else { CDAudio_Resume (); VID_HandlePause (false); } break; case svc_signonnum: i = MSG_ReadByte (); if (i <= cls.signon) Host_Error ("Received signon %i when at %i", i, cls.signon); cls.signon = i; CL_SignonReply (); break; case svc_killedmonster: cl.stats[STAT_MONSTERS]++; break; case svc_foundsecret: cl.stats[STAT_SECRETS]++; break; case svc_updatestat: i = MSG_ReadByte (); if (i < 0 || i >= MAX_CL_STATS) Sys_Error ("svc_updatestat: %i is invalid", i); cl.stats[i] = MSG_ReadLong (); break; case svc_spawnstaticsound: CL_ParseStaticSound (); break; case svc_cdtrack: cl.cdtrack = MSG_ReadByte (); cl.looptrack = MSG_ReadByte (); if (q_strcasecmp(bgmtype.string,"cd") == 0) { if ( (cls.demoplayback || cls.demorecording) && (cls.forcetrack != -1) ) CDAudio_Play ((byte)cls.forcetrack, true); else CDAudio_Play ((byte)cl.cdtrack, true); } else CDAudio_Stop(); break; case svc_midi_name: q_strlcpy (cl.midi_name, MSG_ReadString(), sizeof(cl.midi_name)); if (q_strcasecmp(bgmtype.string,"midi") == 0) MIDI_Play(cl.midi_name); else MIDI_Stop(); break; case svc_toggle_statbar: break; case svc_intermission: cl.intermission = MSG_ReadByte(); if (oem.integer && cl.intermission == 1) cl.intermission = 9; // skip intermissions while recording demos in single // player games, but stop recording at ending scenes. // skip intermissions when playing demos. if (cls.demorecording) { // 5: finale for the demo version // 6, 7, 8: eidolon end-1 to end-3 // 9: finale for the bundle version // 10: praevus ending if (sv.active && svs.maxclients == 1 && (cl.intermission < 5 || cl.intermission > 10)) { cl.intermission = 0; demohack = true; Cbuf_AddText("+attack\n"); // HACK !.. break; } CL_Stop_f (); } else if (cls.demoplayback) { cl.intermission = 0; break; } cl.completed_time = cl.time; vid.recalc_refdef = true; // go to full screen break; /* case svc_finale: cl.intermission = 2; cl.completed_time = cl.time; vid.recalc_refdef = true; // go to full screen SCR_CenterPrint (MSG_ReadString ()); break; case svc_cutscene: cl.intermission = 3; cl.completed_time = cl.time; vid.recalc_refdef = true; // go to full screen SCR_CenterPrint (MSG_ReadString ()); break; case svc_sellscreen: Cmd_ExecuteString ("help", src_command); break; */ case svc_set_view_flags: cl.viewent.drawflags |= MSG_ReadByte(); break; case svc_clear_view_flags: cl.viewent.drawflags &= ~MSG_ReadByte(); break; case svc_start_effect: CL_ParseEffect(); break; case svc_end_effect: CL_EndEffect(); break; case svc_plaque: CL_Plaque(); break; case svc_particle_explosion: CL_ParticleExplosion(); break; case svc_set_view_tint: i = MSG_ReadByte(); cl.viewent.colorshade = i; break; case svc_reference: packet_loss = false; cl.last_frame = cl.current_frame; cl.last_sequence = cl.current_sequence; cl.current_frame = MSG_ReadByte(); cl.current_sequence = MSG_ReadByte(); if (cl.need_build == 2) { // Con_Printf("CL: NB2 CL(%d,%d) R(%d)\n", cl.current_sequence, cl.current_frame,cl.reference_frame); cl.frames[0].count = cl.frames[1].count = cl.frames[2].count = 0; cl.need_build = 1; cl.reference_frame = cl.current_frame; } else if (cl.last_sequence != cl.current_sequence) { // Con_Printf("CL: Sequence CL(%d,%d) R(%d)\n", cl.current_sequence, cl.current_frame,cl.reference_frame); if (cl.reference_frame >= 1 && cl.reference_frame <= MAX_FRAMES) { RemovePlace = OrigPlace = NewPlace = AddedIndex = 0; for (i = 0; i < cl.num_entities; i++) { if (RemovePlace >= cl.NumToRemove || cl.RemoveList[RemovePlace] != i) { if (NewPlace < cl.frames[1].count && cl.frames[1].states[NewPlace].index == i) { cl.frames[2].states[AddedIndex] = cl.frames[1].states[NewPlace]; AddedIndex++; cl.frames[2].count++; } else if (OrigPlace < cl.frames[0].count && cl.frames[0].states[OrigPlace].index == i) { cl.frames[2].states[AddedIndex] = cl.frames[0].states[OrigPlace]; AddedIndex++; cl.frames[2].count++; } } else RemovePlace++; if (cl.frames[0].states[OrigPlace].index == i) OrigPlace++; if (cl.frames[1].states[NewPlace].index == i) NewPlace++; } cl.frames[0] = cl.frames[2]; } cl.frames[1].count = cl.frames[2].count = 0; cl.need_build = 1; cl.reference_frame = cl.current_frame; } else { // Con_Printf("CL: Normal CL(%d,%d) R(%d)\n", cl.current_sequence, cl.current_frame,cl.reference_frame); cl.need_build = 0; } for (i = 1, ent = cl_entities+1; i < cl.num_entities; i++, ent++) { ent->baseline.flags &= ~BE_ON; } for (i = 0; i < cl.frames[0].count; i++) { ent = CL_EntityNum (cl.frames[0].states[i].index); ent->model = cl.model_precache[cl.frames[0].states[i].modelindex]; ent->baseline.flags |= BE_ON; } break; case svc_clear_edicts: j = MSG_ReadByte(); if (cl.need_build) { cl.NumToRemove = j; } for (i = 0; i < j; i++) { k = MSG_ReadShort(); if (cl.need_build) cl.RemoveList[i] = k; ent = CL_EntityNum (k); ent->baseline.flags &= ~BE_ON; } break; case svc_update_inv: sc1 = sc2 = 0; test = MSG_ReadByte(); if (test & 1) sc1 |= ((int)MSG_ReadByte()); if (test & 2) sc1 |= ((int)MSG_ReadByte())<<8; if (test & 4) sc1 |= ((int)MSG_ReadByte())<<16; if (test & 8) sc1 |= ((int)MSG_ReadByte())<<24; if (test & 16) sc2 |= ((int)MSG_ReadByte()); if (test & 32) sc2 |= ((int)MSG_ReadByte())<<8; if (test & 64) sc2 |= ((int)MSG_ReadByte())<<16; if (test & 128) sc2 |= ((int)MSG_ReadByte())<<24; if (sc1 & SC1_HEALTH) cl.v.health = MSG_ReadShort(); if (sc1 & SC1_LEVEL) cl.v.level = MSG_ReadByte(); if (sc1 & SC1_INTELLIGENCE) cl.v.intelligence = MSG_ReadByte(); if (sc1 & SC1_WISDOM) cl.v.wisdom = MSG_ReadByte(); if (sc1 & SC1_STRENGTH) cl.v.strength = MSG_ReadByte(); if (sc1 & SC1_DEXTERITY) cl.v.dexterity = MSG_ReadByte(); if (sc1 & SC1_WEAPON) cl.v.weapon = MSG_ReadByte(); if (sc1 & SC1_BLUEMANA) cl.v.bluemana = MSG_ReadByte(); if (sc1 & SC1_GREENMANA) cl.v.greenmana = MSG_ReadByte(); if (sc1 & SC1_EXPERIENCE) cl.v.experience = MSG_ReadLong(); if (sc1 & SC1_CNT_TORCH) cl.v.cnt_torch = MSG_ReadByte(); if (sc1 & SC1_CNT_H_BOOST) cl.v.cnt_h_boost = MSG_ReadByte(); if (sc1 & SC1_CNT_SH_BOOST) cl.v.cnt_sh_boost = MSG_ReadByte(); if (sc1 & SC1_CNT_MANA_BOOST) cl.v.cnt_mana_boost = MSG_ReadByte(); if (sc1 & SC1_CNT_TELEPORT) cl.v.cnt_teleport = MSG_ReadByte(); if (sc1 & SC1_CNT_TOME) cl.v.cnt_tome = MSG_ReadByte(); if (sc1 & SC1_CNT_SUMMON) cl.v.cnt_summon = MSG_ReadByte(); if (sc1 & SC1_CNT_INVISIBILITY) cl.v.cnt_invisibility = MSG_ReadByte(); if (sc1 & SC1_CNT_GLYPH) cl.v.cnt_glyph = MSG_ReadByte(); if (sc1 & SC1_CNT_HASTE) cl.v.cnt_haste = MSG_ReadByte(); if (sc1 & SC1_CNT_BLAST) cl.v.cnt_blast = MSG_ReadByte(); if (sc1 & SC1_CNT_POLYMORPH) cl.v.cnt_polymorph = MSG_ReadByte(); if (sc1 & SC1_CNT_FLIGHT) cl.v.cnt_flight = MSG_ReadByte(); if (sc1 & SC1_CNT_CUBEOFFORCE) cl.v.cnt_cubeofforce = MSG_ReadByte(); if (sc1 & SC1_CNT_INVINCIBILITY) cl.v.cnt_invincibility = MSG_ReadByte(); if (sc1 & SC1_ARTIFACT_ACTIVE) cl.v.artifact_active = MSG_ReadFloat(); if (sc1 & SC1_ARTIFACT_LOW) cl.v.artifact_low = MSG_ReadFloat(); if (sc1 & SC1_MOVETYPE) cl.v.movetype = MSG_ReadByte(); if (sc1 & SC1_CAMERAMODE) cl.v.cameramode = MSG_ReadByte(); if (sc1 & SC1_HASTED) cl.v.hasted = MSG_ReadFloat(); if (sc1 & SC1_INVENTORY) cl.v.inventory = MSG_ReadByte(); if (sc1 & SC1_RINGS_ACTIVE) cl.v.rings_active = MSG_ReadFloat(); if (sc2 & SC2_RINGS_LOW) cl.v.rings_low = MSG_ReadFloat(); if (sc2 & SC2_AMULET) cl.v.armor_amulet = MSG_ReadByte(); if (sc2 & SC2_BRACER) cl.v.armor_bracer = MSG_ReadByte(); if (sc2 & SC2_BREASTPLATE) cl.v.armor_breastplate = MSG_ReadByte(); if (sc2 & SC2_HELMET) cl.v.armor_helmet = MSG_ReadByte(); if (sc2 & SC2_FLIGHT_T) cl.v.ring_flight = MSG_ReadByte(); if (sc2 & SC2_WATER_T) cl.v.ring_water = MSG_ReadByte(); if (sc2 & SC2_TURNING_T) cl.v.ring_turning = MSG_ReadByte(); if (sc2 & SC2_REGEN_T) cl.v.ring_regeneration = MSG_ReadByte(); if (sc2 & SC2_HASTE_T) cl.v.haste_time = MSG_ReadFloat(); if (sc2 & SC2_TOME_T) cl.v.tome_time = MSG_ReadFloat(); if (sc2 & SC2_PUZZLE1) q_snprintf(cl.puzzle_pieces[0], sizeof(cl.puzzle_pieces[0]), "%.9s", MSG_ReadString()); if (sc2 & SC2_PUZZLE2) q_snprintf(cl.puzzle_pieces[1], sizeof(cl.puzzle_pieces[0]), "%.9s", MSG_ReadString()); if (sc2 & SC2_PUZZLE3) q_snprintf(cl.puzzle_pieces[2], sizeof(cl.puzzle_pieces[0]), "%.9s", MSG_ReadString()); if (sc2 & SC2_PUZZLE4) q_snprintf(cl.puzzle_pieces[3], sizeof(cl.puzzle_pieces[0]), "%.9s", MSG_ReadString()); if (sc2 & SC2_PUZZLE5) q_snprintf(cl.puzzle_pieces[4], sizeof(cl.puzzle_pieces[0]), "%.9s", MSG_ReadString()); if (sc2 & SC2_PUZZLE6) q_snprintf(cl.puzzle_pieces[5], sizeof(cl.puzzle_pieces[0]), "%.9s", MSG_ReadString()); if (sc2 & SC2_PUZZLE7) q_snprintf(cl.puzzle_pieces[6], sizeof(cl.puzzle_pieces[0]), "%.9s", MSG_ReadString()); if (sc2 & SC2_PUZZLE8) q_snprintf(cl.puzzle_pieces[7], sizeof(cl.puzzle_pieces[0]), "%.9s", MSG_ReadString()); if (sc2 & SC2_MAXHEALTH) cl.v.max_health = MSG_ReadShort(); if (sc2 & SC2_MAXMANA) cl.v.max_mana = MSG_ReadByte(); if (sc2 & SC2_FLAGS) cl.v.flags = MSG_ReadFloat(); // SC2_OBJ, SC2_OBJ2: mission pack objectives // With protocol 18 (PROTOCOL_RAVEN_111), these // bits get set somehow (?!): let's avoid them. if (cl_protocol > PROTOCOL_RAVEN_111) { if (sc2 & SC2_OBJ) cl.info_mask = MSG_ReadLong(); if (sc2 & SC2_OBJ2) cl.info_mask2 = MSG_ReadLong(); } if ((sc1 & SC1_STAT_BAR) || (sc2 & SC2_STAT_BAR)) Sbar_Changed(); if ((sc1 & SC1_INV) || (sc2 & SC2_INV)) SB_InvChanged(); break; case svc_mod_name: case svc_skybox: MSG_ReadString(); Con_DPrintf ("Ignored server msg %d (%s)\n", cmd, svc_strings[cmd]); break; } } }
void CL_ParseFrame(void) { int cmd; int len; frame_t *old; memset(&cl.frame, 0, sizeof(cl.frame)); cl.frame.serverframe = MSG_ReadLong(&net_message); cl.frame.deltaframe = MSG_ReadLong(&net_message); cl.frame.servertime = cl.frame.serverframe * 100; /* BIG HACK to let old demos continue to work */ if (cls.serverProtocol != 26) { cl.surpressCount = MSG_ReadByte(&net_message); } if (cl_shownet->value == 3) { Com_Printf(" frame:%i delta:%i\n", cl.frame.serverframe, cl.frame.deltaframe); } /* If the frame is delta compressed from data that we no longer have available, we must suck up the rest of the frame, but not use it, then ask for a non-compressed message */ if (cl.frame.deltaframe <= 0) { cl.frame.valid = true; /* uncompressed frame */ old = NULL; cls.demowaiting = false; /* we can start recording now */ } else { old = &cl.frames[cl.frame.deltaframe & UPDATE_MASK]; if (!old->valid) { /* should never happen */ Com_Printf("Delta from invalid frame (not supposed to happen!).\n"); } if (old->serverframe != cl.frame.deltaframe) { /* The frame that the server did the delta from is too old, so we can't reconstruct it properly. */ Com_Printf("Delta frame too old.\n"); } else if (cl.parse_entities - old->parse_entities > MAX_PARSE_ENTITIES - 128) { Com_Printf("Delta parse_entities too old.\n"); } else { cl.frame.valid = true; /* valid delta parse */ } } /* clamp time */ if (cl.time > cl.frame.servertime) { cl.time = cl.frame.servertime; } else if (cl.time < cl.frame.servertime - 100) { cl.time = cl.frame.servertime - 100; } /* read areabits */ len = MSG_ReadByte(&net_message); MSG_ReadData(&net_message, &cl.frame.areabits, len); /* read playerinfo */ cmd = MSG_ReadByte(&net_message); SHOWNET(svc_strings[cmd]); if (cmd != svc_playerinfo) { Com_Error(ERR_DROP, "CL_ParseFrame: 0x%X not playerinfo", cmd); } CL_ParsePlayerstate(old, &cl.frame); /* read packet entities */ cmd = MSG_ReadByte(&net_message); SHOWNET(svc_strings[cmd]); if (cmd != svc_packetentities) { Com_Error(ERR_DROP, "CL_ParseFrame: 0x%X not packetentities", cmd); } CL_ParsePacketEntities(old, &cl.frame); /* save the frame off in the backup array for later delta comparisons */ cl.frames[cl.frame.serverframe & UPDATE_MASK] = cl.frame; if (cl.frame.valid) { /* getting a valid frame message ends the connection process */ if (cls.state != ca_active) { cls.state = ca_active; cl.force_refdef = true; cl.predicted_origin[0] = cl.frame.playerstate.pmove.origin[0] * 0.125f; cl.predicted_origin[1] = cl.frame.playerstate.pmove.origin[1] * 0.125f; cl.predicted_origin[2] = cl.frame.playerstate.pmove.origin[2] * 0.125f; VectorCopy(cl.frame.playerstate.viewangles, cl.predicted_angles); if ((cls.disable_servercount != cl.servercount) && cl.refresh_prepped) { SCR_EndLoadingPlaque(); /* get rid of loading plaque */ } cl.sound_prepped = true; } /* fire entity events */ CL_FireEntityEvents(&cl.frame); if (!(!cl_predict->value || (cl.frame.playerstate.pmove.pm_flags & PMF_NO_PREDICTION))) { CL_CheckPredictionError(); } } }
void CLQW_ParseServerMessage( QMsg& message ) { CLQ1_ClearProjectiles(); // // if recording demos, copy the message out // if ( cl_shownet->value == 1 ) { common->Printf( "%i ",message.cursize ); } else if ( cl_shownet->value == 2 ) { common->Printf( "------------------\n" ); } CLQW_ParseClientdata(); // // parse the message // while ( 1 ) { if ( message.badread ) { common->Error( "CLQW_ParseServerMessage: Bad server message" ); break; } int cmd = message.ReadByte(); if ( cmd == -1 ) { message.readcount++; // so the EOM showner has the right value SHOWNET( message, "END OF MESSAGE" ); break; } SHOWNET( message, svcqw_strings[ cmd ] ); // other commands switch ( cmd ) { default: common->Error( "CLQW_ParseServerMessage: Illegible server message" ); break; case q1svc_nop: break; case q1svc_disconnect: CLQW_ParseDisconnect(); break; case q1svc_print: CLQW_ParsePrint( message ); break; case q1svc_centerprint: CL_ParseCenterPrint( message ); break; case q1svc_stufftext: CL_ParseStuffText( message ); break; case q1svc_damage: VQH_ParseDamage( message ); break; case qwsvc_serverdata: CLQW_ParseServerData( message ); break; case q1svc_setangle: CLQH_ParseSetAngle( message ); break; case q1svc_lightstyle: CLQH_ParseLightStyle( message ); break; case q1svc_sound: CLQW_ParseStartSoundPacket( message ); break; case q1svc_stopsound: CLQH_ParseStopSound( message ); break; case q1svc_updatefrags: CLQW_ParseUpdateFrags( message ); break; case qwsvc_updateping: CLQW_ParseUpdatePing( message ); break; case qwsvc_updatepl: CLQW_ParseUpdatePacketLossage( message ); break; case qwsvc_updateentertime: CLQW_ParseUpdateEnterTime( message ); break; case q1svc_spawnbaseline: CLQ1_ParseSpawnBaseline( message ); break; case q1svc_spawnstatic: CLQ1_ParseSpawnStatic( message ); break; case q1svc_temp_entity: CLQW_ParseTEnt( message ); break; case q1svc_killedmonster: CLQH_ParseKilledMonster(); break; case q1svc_foundsecret: CLQH_ParseFoundSecret(); break; case q1svc_updatestat: CLQW_ParseUpdateStat( message ); break; case qwsvc_updatestatlong: CLQW_ParseUpdateStatLong( message ); break; case q1svc_spawnstaticsound: CLQH_ParseStaticSound( message ); break; case q1svc_cdtrack: CLQHW_ParseCDTrack( message ); break; case q1svc_intermission: CLQW_ParseIntermission( message ); break; case q1svc_finale: CLQHW_ParseFinale( message ); break; case q1svc_sellscreen: CLQH_ParseSellScreen(); break; case qwsvc_smallkick: CLQHW_ParseSmallKick(); break; case qwsvc_bigkick: CLQHW_ParseBigKick(); break; case qwsvc_muzzleflash: CLQW_MuzzleFlash( message ); break; case qwsvc_updateuserinfo: CLQW_ParseUpdateUserinfo( message ); break; case qwsvc_setinfo: CLQW_ParseSetInfo( message ); break; case qwsvc_serverinfo: CLQW_ParseServerInfo( message ); break; case qwsvc_download: CLQW_ParseDownload( message ); break; case qwsvc_playerinfo: CLQW_ParsePlayerinfo( message ); break; case qwsvc_nails: CLQW_ParseNails( message ); break; case qwsvc_chokecount: CLQW_ParseChokeCount( message ); break; case qwsvc_modellist: CLQW_ParseModelList( message ); break; case qwsvc_soundlist: CLQW_ParseSoundList( message ); break; case qwsvc_packetentities: CLQW_ParsePacketEntities( message ); break; case qwsvc_deltapacketentities: CLQW_ParseDeltaPacketEntities( message ); break; case qwsvc_maxspeed: CLQHW_ParseMaxSpeed( message ); break; case qwsvc_entgravity: CLQHW_ParseEntGravity( message ); break; case q1svc_setpause: CLQW_ParseSetPause( message ); break; } } CLQW_SetSolidEntities(); }
void CLQ1_ParseServerMessage( QMsg& message ) { if ( cl_shownet->value == 1 ) { common->Printf( "%i ", message.cursize ); } else if ( cl_shownet->value == 2 ) { common->Printf( "------------------\n" ); } cl.qh_onground = false; // unless the server says otherwise // // parse the message // message.BeginReadingOOB(); while ( 1 ) { if ( message.badread ) { common->Error( "CLQ1_ParseServerMessage: Bad server message" ); } int cmd = message.ReadByte(); if ( cmd == -1 ) { SHOWNET( message, "END OF MESSAGE" ); return; // end of message } // if the high bit of the command byte is set, it is a fast update if ( cmd & Q1U_SIGNAL ) { SHOWNET( message, "fast update" ); CLQ1_ParseUpdate( message, cmd & 127 ); continue; } SHOWNET( message, svcq1_strings[ cmd ] ); // other commands switch ( cmd ) { default: common->Error( "CLQ1_ParseServerMessage: Illegible server message\n" ); break; case q1svc_nop: break; case q1svc_time: CLQH_ParseTime( message ); break; case q1svc_clientdata: CLQ1_ParseClientdata( message ); break; case q1svc_version: CLQ1_ParseVersion( message ); break; case q1svc_disconnect: CLQH_ParseDisconnect(); break; case q1svc_print: CLQ1_ParsePrint( message ); break; case q1svc_centerprint: CL_ParseCenterPrint( message ); break; case q1svc_stufftext: CL_ParseStuffText( message ); break; case q1svc_damage: VQH_ParseDamage( message ); break; case q1svc_serverinfo: CLQ1_ParseServerInfo( message ); break; case q1svc_setangle: CLQH_ParseSetAngle( message ); break; case q1svc_setview: CLQH_ParseSetView( message ); break; case q1svc_lightstyle: CLQH_ParseLightStyle( message ); break; case q1svc_sound: CLQ1_ParseStartSoundPacket( message ); break; case q1svc_stopsound: CLQH_ParseStopSound( message ); break; case q1svc_updatename: CLQ1_UpdateName( message ); break; case q1svc_updatefrags: CLQ1_ParseUpdateFrags( message ); break; case q1svc_updatecolors: CLQ1_ParseUpdateColours( message ); break; case q1svc_particle: CLQ1_ParseParticleEffect( message ); break; case q1svc_spawnbaseline: CLQ1_ParseSpawnBaseline( message ); break; case q1svc_spawnstatic: CLQ1_ParseSpawnStatic( message ); break; case q1svc_temp_entity: CLQ1_ParseTEnt( message ); break; case q1svc_setpause: CLQH_ParseSetPause( message ); break; case q1svc_signonnum: CLQ1_ParseSignonNum( message ); break; case q1svc_killedmonster: CLQH_ParseKilledMonster(); break; case q1svc_foundsecret: CLQH_ParseFoundSecret(); break; case q1svc_updatestat: CLQH_ParseUpdateStat( message ); break; case q1svc_spawnstaticsound: CLQH_ParseStaticSound( message ); break; case q1svc_cdtrack: CLQ1_ParseCDTrack( message ); break; case q1svc_intermission: CLQ1_ParseIntermission(); break; case q1svc_finale: CLQ1_ParseFinale( message ); break; case q1svc_cutscene: CLQ1_ParseCutscene( message ); break; case q1svc_sellscreen: CLQH_ParseSellScreen(); break; } } }
/* ===================== 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; case svc_lua: //Make Lua VMCall Here. -Hxrmn CL_SetLuaMessage(msg); VM_Call (cgvm, CG_LUA_MSG); break; } } }
/* ===================== 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 ( (cmd < 0) || (!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"); 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; case svc_voipSpeex: #ifdef USE_VOIP CL_ParseVoip( msg, qtrue ); #endif break; case svc_voipOpus: #ifdef USE_VOIP CL_ParseVoip( msg, !clc.voipEnabled ); #endif break; } } }
/* ===================== 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 (cmd < 0 || cmd > svc_EOF) // MSG_ReadByte might return -1 and we can't access our svc_strings array ... { Com_Printf("%3i:BAD BYTE %i\n", msg->readcount - 1, cmd); // -> ERR_DROP } else { 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 %d", cmd); 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; } } CL_ParseBinaryMessage(msg); }
void CLNQ_ParseServerMessage (void) { int cmd; int i; qbool message_with_datagram; // hack to fix glitches when receiving a packet // without a datagram nq_player_teleported = false; // OMG, it's a hack! message_with_datagram = false; cl_entframecount++; if (cl_shownet.value == 1) Com_Printf ("%i ", net_message.cursize); else if (cl_shownet.value == 2) Com_Printf ("------------------\n"); cl.onground = false; // unless the server says otherwise // // parse the message // //MSG_BeginReading (); while (1) { if (msg_badread) Host_Error ("CL_ParseServerMessage: Bad server message"); cmd = MSG_ReadByte (); if (cmd == -1) { SHOWNET("END OF MESSAGE"); if (!message_with_datagram) { cl_entframecount--; } else { VectorCopy (nq_mviewangles[0], nq_mviewangles[1]); VectorCopy (nq_mviewangles_temp, nq_mviewangles[0]); } return; // end of message } // if the high bit of the command byte is set, it is a fast update if (cmd & 128) { SHOWNET("fast update"); NQD_ParseUpdate (cmd&127); continue; } if (cmd < num_svc_strings) SHOWNET(svc_strings[cmd]); // other commands switch (cmd) { default: Host_Error ("CL_ParseServerMessage: Illegible server message"); break; case svc_nop: break; case nq_svc_time: nq_mtime[1] = nq_mtime[0]; nq_mtime[0] = MSG_ReadFloat (); cl.servertime = nq_mtime[0]; message_with_datagram = true; break; case nq_svc_clientdata: i = MSG_ReadShort (); NQD_ParseClientdata (i); break; case nq_svc_version: i = MSG_ReadLong (); if (i != NQ_PROTOCOL_VERSION) Host_Error ("CL_ParseServerMessage: Server is protocol %i instead of %i\n", i, NQ_PROTOCOL_VERSION); break; case svc_disconnect: Com_Printf ("\n======== End of demo ========\n\n"); CL_NextDemo (); Host_EndGame (); Host_Abort (); break; case svc_print: NQD_ParsePrint (); break; case svc_centerprint: SCR_CenterPrint (MSG_ReadString ()); break; case svc_stufftext: NQD_ParseStufftext (); break; case svc_damage: V_ParseDamage (); break; case svc_serverdata: NQD_ParseServerData (); break; case svc_setangle: for (i=0 ; i<3 ; i++) nq_last_fixangle[i] = cl.simangles[i] = cl.viewangles[i] = MSG_ReadAngle (); break; case svc_setview: nq_viewentity = MSG_ReadShort (); if (nq_viewentity <= nq_maxclients) cl.playernum = nq_viewentity - 1; else { // just let cl.playernum stay where it was } break; case svc_lightstyle: i = MSG_ReadByte (); if (i >= MAX_LIGHTSTYLES) Sys_Error ("svc_lightstyle > MAX_LIGHTSTYLES"); strlcpy (cl_lightstyle[i].map, MSG_ReadString(), sizeof(cl_lightstyle[0].map)); cl_lightstyle[i].length = strlen(cl_lightstyle[i].map); break; case svc_sound: NQD_ParseStartSoundPacket(); break; case svc_stopsound: i = MSG_ReadShort(); S_StopSound(i>>3, i&7); break; case nq_svc_updatename: Sbar_Changed (); i = MSG_ReadByte (); if (i >= nq_maxclients) Host_Error ("CL_ParseServerMessage: svc_updatename > NQ_MAX_CLIENTS"); strlcpy (cl.players[i].name, MSG_ReadString(), sizeof(cl.players[i].name)); break; case svc_updatefrags: Sbar_Changed (); i = MSG_ReadByte (); if (i >= nq_maxclients) Host_Error ("CL_ParseServerMessage: svc_updatefrags > NQ_MAX_CLIENTS"); cl.players[i].frags = MSG_ReadShort(); break; case nq_svc_updatecolors: NQD_ParseUpdatecolors (); break; case nq_svc_particle: CL_ParseParticleEffect (); break; case svc_spawnbaseline: i = MSG_ReadShort (); if (i >= NQ_MAX_EDICTS) Host_Error ("svc_spawnbaseline: ent > MAX_EDICTS"); NQD_BumpEntityCount (i); CL_ParseBaseline (&cl_entities[i].baseline); break; case svc_spawnstatic: CL_ParseStatic (); break; case svc_temp_entity: CL_ParseTEnt (); break; case svc_setpause: if (MSG_ReadByte() != 0) cl.paused |= PAUSED_SERVER; else cl.paused &= ~PAUSED_SERVER; if (cl.paused) CDAudio_Pause (); else CDAudio_Resume (); break; case nq_svc_signonnum: i = MSG_ReadByte (); if (i <= nq_signon) Host_Error ("Received signon %i when at %i", i, nq_signon); nq_signon = i; CLNQ_SignonReply (); break; case svc_killedmonster: cl.stats[STAT_MONSTERS]++; break; case svc_foundsecret: cl.stats[STAT_SECRETS]++; break; case svc_updatestat: i = MSG_ReadByte (); if (i < 0 || i >= MAX_CL_STATS) Sys_Error ("svc_updatestat: %i is invalid", i); cl.stats[i] = MSG_ReadLong ();; break; case svc_spawnstaticsound: CL_ParseStaticSound (); break; case svc_cdtrack: cl.cdtrack = MSG_ReadByte (); MSG_ReadByte(); // loop track (unused) if (nq_forcecdtrack != -1) CDAudio_Play ((byte)nq_forcecdtrack, true); else CDAudio_Play ((byte)cl.cdtrack, true); break; case svc_intermission: cl.intermission = 1; cl.completed_time = cl.time; VectorCopy (nq_last_fixangle, cl.simangles); break; case svc_finale: cl.intermission = 2; cl.completed_time = cl.time; SCR_CenterPrint (MSG_ReadString ()); VectorCopy (nq_last_fixangle, cl.simangles); break; case nq_svc_cutscene: cl.intermission = 3; cl.completed_time = cl.time; SCR_CenterPrint (MSG_ReadString ()); VectorCopy (nq_last_fixangle, cl.simangles); break; case svc_sellscreen: break; } } }
/* ===================== CL_ParseServerMessage ===================== */ void CL_ParseServerMessage (void) { int cmd; int i; const char *str; //johnfitz int total, j, lastcmd; //johnfitz // // if recording demos, copy the message out // if (cl_shownet.value == 1) Con_Printf ("%i ",net_message.cursize); else if (cl_shownet.value == 2) Con_Printf ("------------------\n"); cl.onground = false; // unless the server says otherwise // // parse the message // MSG_BeginReading (); lastcmd = 0; while (1) { if (msg_badread) Host_Error ("CL_ParseServerMessage: Bad server message"); cmd = MSG_ReadByte (); if (cmd == -1) { SHOWNET("END OF MESSAGE"); return; // end of message } // if the high bit of the command byte is set, it is a fast update if (cmd & U_SIGNAL) //johnfitz -- was 128, changed for clarity { SHOWNET("fast update"); CL_ParseUpdate (cmd&127); continue; } SHOWNET(svc_strings[cmd]); // other commands switch (cmd) { default: Host_Error ("Illegible server message, previous was %s\n", svc_strings[lastcmd]); //johnfitz -- added svc_strings[lastcmd] break; case svc_nop: // Con_Printf ("svc_nop\n"); break; case svc_time: cl.mtime[1] = cl.mtime[0]; cl.mtime[0] = MSG_ReadFloat (); break; case svc_clientdata: CL_ParseClientdata (); //johnfitz -- removed bits parameter, we will read this inside CL_ParseClientdata() break; case svc_version: i = MSG_ReadLong (); //johnfitz -- support multiple protocols if (i != PROTOCOL_NETQUAKE && i != PROTOCOL_FITZQUAKE) Host_Error ("Server returned version %i, not %i or %i\n", i, PROTOCOL_NETQUAKE, PROTOCOL_FITZQUAKE); cl.protocol = i; //johnfitz break; case svc_disconnect: Host_EndGame ("Server disconnected\n"); case svc_print: Con_Printf ("%s", MSG_ReadString ()); break; case svc_centerprint: //johnfitz -- log centerprints to console str = MSG_ReadString (); SCR_CenterPrint (str); Con_LogCenterPrint (str); //johnfitz break; case svc_stufftext: cls.stufftext_frame = host_framecount; // allow full frame update // in demo playback -- Pa3PyX Cbuf_AddText (MSG_ReadString ()); break; case svc_damage: V_ParseDamage (); break; case svc_serverinfo: CL_ParseServerInfo (); vid.recalc_refdef = true; // leave intermission full screen break; case svc_setangle: for (i=0 ; i<3 ; i++) cl.viewangles[i] = MSG_ReadAngle (); break; case svc_setview: cl.viewentity = MSG_ReadShort (); break; case svc_lightstyle: i = MSG_ReadByte (); if (i >= MAX_LIGHTSTYLES) Sys_Error ("svc_lightstyle > MAX_LIGHTSTYLES"); q_strlcpy (cl_lightstyle[i].map, MSG_ReadString(), MAX_STYLESTRING); cl_lightstyle[i].length = Q_strlen(cl_lightstyle[i].map); //johnfitz -- save extra info if (cl_lightstyle[i].length) { total = 0; cl_lightstyle[i].peak = 'a'; for (j=0; j<cl_lightstyle[i].length; j++) { total += cl_lightstyle[i].map[j] - 'a'; cl_lightstyle[i].peak = q_max(cl_lightstyle[i].peak, cl_lightstyle[i].map[j]); } cl_lightstyle[i].average = total / cl_lightstyle[i].length + 'a'; } else cl_lightstyle[i].average = cl_lightstyle[i].peak = 'm'; //johnfitz break; case svc_sound: CL_ParseStartSoundPacket(); break; case svc_stopsound: i = MSG_ReadShort(); S_StopSound(i>>3, i&7); break; case svc_updatename: Sbar_Changed (); i = MSG_ReadByte (); if (i >= cl.maxclients) Host_Error ("CL_ParseServerMessage: svc_updatename > MAX_SCOREBOARD"); q_strlcpy (cl.scores[i].name, MSG_ReadString(), MAX_SCOREBOARDNAME); break; case svc_updatefrags: Sbar_Changed (); i = MSG_ReadByte (); if (i >= cl.maxclients) Host_Error ("CL_ParseServerMessage: svc_updatefrags > MAX_SCOREBOARD"); cl.scores[i].frags = MSG_ReadShort (); break; case svc_updatecolors: Sbar_Changed (); i = MSG_ReadByte (); if (i >= cl.maxclients) Host_Error ("CL_ParseServerMessage: svc_updatecolors > MAX_SCOREBOARD"); cl.scores[i].colors = MSG_ReadByte (); CL_NewTranslation (i); break; case svc_particle: R_ParseParticleEffect (); break; case svc_spawnbaseline: i = MSG_ReadShort (); // must use CL_EntityNum() to force cl.num_entities up CL_ParseBaseline (CL_EntityNum(i), 1); // johnfitz -- added second parameter break; case svc_spawnstatic: CL_ParseStatic (1); //johnfitz -- added parameter break; case svc_temp_entity: CL_ParseTEnt (); break; case svc_setpause: cl.paused = MSG_ReadByte (); if (cl.paused) { CDAudio_Pause (); BGM_Pause (); } else { CDAudio_Resume (); BGM_Resume (); } break; case svc_signonnum: i = MSG_ReadByte (); if (i <= cls.signon) Host_Error ("Received signon %i when at %i", i, cls.signon); cls.signon = i; //johnfitz -- if signonnum==2, signon packet has been fully parsed, so check for excessive static ents and efrags if (i == 2) { if (cl.num_statics > 128) Con_Warning ("%i static entities exceeds standard limit of 128.\n", cl.num_statics); R_CheckEfrags (); } //johnfitz CL_SignonReply (); break; case svc_killedmonster: cl.stats[STAT_MONSTERS]++; break; case svc_foundsecret: cl.stats[STAT_SECRETS]++; break; case svc_updatestat: i = MSG_ReadByte (); if (i < 0 || i >= MAX_CL_STATS) Sys_Error ("svc_updatestat: %i is invalid", i); cl.stats[i] = MSG_ReadLong ();; break; case svc_spawnstaticsound: CL_ParseStaticSound (1); //johnfitz -- added parameter break; case svc_cdtrack: cl.cdtrack = MSG_ReadByte (); cl.looptrack = MSG_ReadByte (); if ( (cls.demoplayback || cls.demorecording) && (cls.forcetrack != -1) ) BGM_PlayCDtrack ((byte)cls.forcetrack, true); else BGM_PlayCDtrack ((byte)cl.cdtrack, true); break; case svc_intermission: cl.intermission = 1; cl.completed_time = cl.time; vid.recalc_refdef = true; // go to full screen break; case svc_finale: cl.intermission = 2; cl.completed_time = cl.time; vid.recalc_refdef = true; // go to full screen //johnfitz -- log centerprints to console str = MSG_ReadString (); SCR_CenterPrint (str); Con_LogCenterPrint (str); //johnfitz break; case svc_cutscene: cl.intermission = 3; cl.completed_time = cl.time; vid.recalc_refdef = true; // go to full screen //johnfitz -- log centerprints to console str = MSG_ReadString (); SCR_CenterPrint (str); Con_LogCenterPrint (str); //johnfitz break; case svc_sellscreen: Cmd_ExecuteString ("help", src_command); break; //johnfitz -- new svc types case svc_skybox: Sky_LoadSkyBox (MSG_ReadString()); break; case svc_bf: Cmd_ExecuteString ("bf", src_command); break; case svc_fog: Fog_ParseServerMessage (); break; case svc_spawnbaseline2: //PROTOCOL_FITZQUAKE i = MSG_ReadShort (); // must use CL_EntityNum() to force cl.num_entities up CL_ParseBaseline (CL_EntityNum(i), 2); break; case svc_spawnstatic2: //PROTOCOL_FITZQUAKE CL_ParseStatic (2); break; case svc_spawnstaticsound2: //PROTOCOL_FITZQUAKE CL_ParseStaticSound (2); break; //johnfitz } lastcmd = cmd; //johnfitz } }
/* ================ 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 ); // if we were just unpaused, we can only *now* really let the // change come into effect or the client hangs. cl_paused->modified = 0; 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; if ( clc.demorecording ) { clc.demowaiting = qfalse; // we can start recording now // if(cl_autorecord->integer) { // Cvar_Set( "g_synchronousClients", "0" ); // } } else { if ( cl_autorecord->integer /*&& Cvar_VariableValue( "g_synchronousClients") */ ) { char name[ 256 ]; char mapname[ MAX_QPATH ]; char *period; qtime_t time; Com_RealTime( &time ); Q_strncpyz( mapname, cl.mapname, MAX_QPATH ); for ( period = mapname; *period; period++ ) { if ( *period == '.' ) { *period = '\0'; break; } } for ( period = mapname; *period; period++ ) { if ( *period == '/' ) { break; } } if ( *period ) { period++; } Com_sprintf( name, sizeof( name ), "demos/%s_%04i-%02i-%02i_%02i%02i%02i.dm_%d", period, 1900 + time.tm_year, time.tm_mon + 1, time.tm_mday, time.tm_hour, time.tm_min, time.tm_sec, PROTOCOL_VERSION ); CL_Record( name ); } } } 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_DPrintf( "Delta frame too old.\n" ); } else if ( cl.parseEntitiesNum - old->parseEntitiesNum > MAX_PARSE_ENTITIES - 128 ) { Com_DPrintf( "Delta parseEntitiesNum too old.\n" ); } else { newSnap.valid = qtrue; // valid delta parse } } // read areamask len = MSG_ReadByte( msg ); if ( len > sizeof( newSnap.areamask ) ) { Com_Error( ERR_DROP, "CL_ParseSnapshot: Invalid size %d for areamask.", len ); } 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; }
/* ================ CL_ParseFrame ================ */ void CL_ParseFrame (void) { int cmd; int len; frame_t *old; memset (&cl.frame, 0, sizeof(cl.frame)); cl.frame.serverframe = MSG_ReadLong(&net_message); cl.frame.deltaframe = MSG_ReadLong(&net_message); cl.frame.servertime = cl.frame.serverframe*100; // BIG HACK to let old demos continue to work if (cls.serverProtocol != 26) cl.surpressCount = MSG_ReadByte(&net_message); if (cl_shownet->value == 3) Com_Printf (" frame:%i delta:%i\n", cl.frame.serverframe, cl.frame.deltaframe); // If the frame is delta compressed from data that we // no longer have available, we must suck up the rest of // the frame, but not use it, then ask for a non-compressed // message if (cl.frame.deltaframe <= 0) { cl.frame.valid = true; // uncompressed frame old = NULL; cls.demowaiting = false; // we can start recording now } else { old = &cl.frames[cl.frame.deltaframe & UPDATE_MASK]; if (!old->valid) { // should never happen Com_Printf ("Delta from invalid frame (not supposed to happen!).\n"); } if (old->serverframe != cl.frame.deltaframe) { // The frame that the server did the delta from // is too old, so we can't reconstruct it properly. Com_Printf ("Delta frame too old.\n"); } else if (cl.parse_entities - old->parse_entities > MAX_PARSE_ENTITIES-128) { Com_Printf ("Delta parse_entities too old.\n"); } else { cl.frame.valid = true; // valid delta parse } } // clamp time if (cl.time > cl.frame.servertime) cl.time = cl.frame.servertime; else if (cl.time < cl.frame.servertime - 100) cl.time = cl.frame.servertime - 100; // read areabits len = MSG_ReadByte(&net_message); MSG_ReadData(&net_message, &cl.frame.areabits, len); // read playerinfo cmd = MSG_ReadByte(&net_message); SHOWNET(svc_strings[cmd]); if (cmd != svc_playerinfo) Com_Error(ERR_DROP, "CL_ParseFrame: not playerinfo"); CL_ParsePlayerstate(old, &cl.frame); // read packet entities cmd = MSG_ReadByte(&net_message); SHOWNET(svc_strings[cmd]); if (cmd != svc_packetentities) Com_Error(ERR_DROP, "CL_ParseFrame: not packetentities"); CL_ParsePacketEntities(old, &cl.frame); // save the frame off in the backup array for later delta comparisons cl.frames[cl.frame.serverframe & UPDATE_MASK] = cl.frame; if (cl.frame.valid) { // getting a valid frame message ends the connection process if (cls.state != ca_active) { cls.state = ca_active; //cl_scores_setinuse_all(false); // jitscores - clear scoreboard cl.force_refdef = true; cl.predicted_origin[0] = cl.frame.playerstate.pmove.origin[0]*0.125; cl.predicted_origin[1] = cl.frame.playerstate.pmove.origin[1]*0.125; cl.predicted_origin[2] = cl.frame.playerstate.pmove.origin[2]*0.125; VectorCopy(cl.frame.playerstate.viewangles, cl.predicted_angles); if (cls.disable_servercount != cl.servercount && cl.refresh_prepped) SCR_EndLoadingPlaque(); // get rid of loading plaque } cl.sound_prepped = true; // can start mixing ambient sounds // fire entity events CL_FireEntityEvents(&cl.frame); CL_CheckPredictionError(); } }
/* ===================== CL_ParseServerMessage ===================== */ void CL_ParseServerMessage(void) { unsigned int bits; int i, cmd, prevcmd; int playernum, version, stylenum, signon, statnum; int stopsound, entitynum, channel; byte colors; player_info_t *player; lightstyle_t *style; const char *stylemap, *name; // // if recording demos, copy the message out // if (cl_shownet.value == 1) Con_Printf("%i ", net_message.cursize); else if (cl_shownet.value == 2) Con_Printf("------------------\n"); cl.onground = false; // unless the server says otherwise // // parse the message // prevcmd = svc_bad; MSG_BeginReading(); while (1) { if (msg_badread) Host_Error("%s: Bad server message", __func__); cmd = MSG_ReadByte(); if (cmd == -1) { SHOWNET("END OF MESSAGE"); return; // end of message } // if the high bit of the command byte is set, it is a fast update if (cmd & 128) { SHOWNET("fast update"); CL_ParseUpdate(cmd & 127); continue; } SHOWNET(svc_strings[cmd]); // other commands switch (cmd) { case svc_nop: break; case svc_time: cl.mtime[1] = cl.mtime[0]; cl.mtime[0] = MSG_ReadFloat(); break; case svc_clientdata: CL_ParseClientdata(); break; case svc_version: version = MSG_ReadLong(); if (!Protocol_Known(version)) Host_Error("%s: Server returned unknown protocol version %i", __func__, version); cl.protocol = version; break; case svc_disconnect: Host_EndGame("Server disconnected\n"); case svc_print: Con_Printf("%s", MSG_ReadString()); break; case svc_centerprint: SCR_CenterPrint(MSG_ReadString()); break; case svc_stufftext: Cbuf_AddText("%s", MSG_ReadString()); break; case svc_damage: V_ParseDamage(); break; case svc_serverinfo: CL_ParseServerInfo(); vid.recalc_refdef = true; // leave intermission full screen break; case svc_setangle: for (i = 0; i < 3; i++) cl.viewangles[i] = MSG_ReadAngle(); break; case svc_setview: cl.viewentity = MSG_ReadShort(); break; case svc_lightstyle: stylenum = MSG_ReadByte(); if (stylenum >= MAX_LIGHTSTYLES) Sys_Error("svc_lightstyle > MAX_LIGHTSTYLES"); stylemap = MSG_ReadString(); style = cl_lightstyle + stylenum; snprintf(style->map, MAX_STYLESTRING, "%s", stylemap); style->length = strlen(style->map); break; case svc_sound: CL_ParseStartSoundPacket(); break; case svc_stopsound: stopsound = MSG_ReadShort(); /* 3-bit channel encoded in lsb */ entitynum = stopsound >> 3; channel = stopsound & 7; S_StopSound(entitynum, channel); break; case svc_updatename: Sbar_Changed(); playernum = MSG_ReadByte(); if (playernum >= cl.maxclients) Host_Error("%s: svc_updatename > MAX_SCOREBOARD", __func__); name = MSG_ReadString(); player = cl.players + playernum; snprintf(player->name, MAX_SCOREBOARDNAME, "%s", name); break; case svc_updatefrags: Sbar_Changed(); playernum = MSG_ReadByte(); if (playernum >= cl.maxclients) Host_Error("%s: svc_updatefrags > MAX_SCOREBOARD", __func__); player = cl.players + playernum; player->frags = MSG_ReadShort(); break; case svc_updatecolors: Sbar_Changed(); playernum = MSG_ReadByte(); if (playernum >= cl.maxclients) Host_Error("%s: svc_updatecolors > MAX_SCOREBOARD", __func__); colors = MSG_ReadByte(); player = cl.players + playernum; player->topcolor = (colors & 0xf0) >> 4; player->bottomcolor = colors & 0x0f; /* FIXME - is this the right check for current player? */ if (playernum == cl.viewentity) cl_color.value = colors; CL_NewTranslation(playernum); break; case svc_particle: R_ParseParticleEffect(); break; case svc_spawnbaseline: entitynum = MSG_ReadShort(); // must use CL_EntityNum() to force cl.num_entities up CL_ParseBaseline(CL_EntityNum(entitynum), 0); break; case svc_fitz_spawnbaseline2: /* FIXME - check here that protocol is FITZ? => Host_Error() */ entitynum = MSG_ReadShort(); bits = MSG_ReadByte(); // must use CL_EntityNum() to force cl.num_entities up CL_ParseBaseline(CL_EntityNum(entitynum), bits); break; case svc_spawnstatic: CL_ParseStatic(0); break; case svc_fitz_spawnstatic2: /* FIXME - check here that protocol is FITZ? => Host_Error() */ bits = MSG_ReadByte(); CL_ParseStatic(bits); break; case svc_temp_entity: CL_ParseTEnt(); break; case svc_setpause: cl.paused = MSG_ReadByte(); if (cl.paused) CDAudio_Pause(); else CDAudio_Resume(); break; case svc_signonnum: signon = MSG_ReadByte(); if (signon <= cls.signon) Host_Error("Received signon %d when at %d", signon, cls.signon); cls.signon = signon; CL_SignonReply(); break; case svc_killedmonster: cl.stats[STAT_MONSTERS]++; break; case svc_foundsecret: cl.stats[STAT_SECRETS]++; break; case svc_updatestat: statnum = MSG_ReadByte(); if (statnum < 0 || statnum >= MAX_CL_STATS) Sys_Error("svc_updatestat: %d is invalid", statnum); cl.stats[statnum] = MSG_ReadLong(); break; case svc_spawnstaticsound: CL_ParseStaticSound(); break; case svc_fitz_spawnstaticsound2: /* FIXME - check here that protocol is FITZ? => Host_Error() */ CL_ParseFitzStaticSound2(); break; case svc_cdtrack: cl.cdtrack = MSG_ReadByte(); cl.looptrack = MSG_ReadByte(); if ((cls.demoplayback || cls.demorecording) && (cls.forcetrack != -1)) CDAudio_Play((byte)cls.forcetrack, true); else CDAudio_Play((byte)cl.cdtrack, true); break; case svc_intermission: cl.intermission = 1; cl.completed_time = cl.time; vid.recalc_refdef = true; // go to full screen break; case svc_finale: cl.intermission = 2; cl.completed_time = cl.time; vid.recalc_refdef = true; // go to full screen SCR_CenterPrint(MSG_ReadString()); break; case svc_cutscene: cl.intermission = 3; cl.completed_time = cl.time; vid.recalc_refdef = true; // go to full screen SCR_CenterPrint(MSG_ReadString()); break; case svc_sellscreen: Cmd_ExecuteString("help", src_command); break; /* Various FITZ protocol messages - FIXME - !protocol => Host_Error */ case svc_fitz_skybox: MSG_ReadString(); // FIXME - TODO break; case svc_fitz_bf: Cmd_ExecuteString("bf", src_command); break; case svc_fitz_fog: /* FIXME - TODO */ MSG_ReadByte(); // density MSG_ReadByte(); // red MSG_ReadByte(); // green MSG_ReadByte(); // blue MSG_ReadShort(); // time break; default: Host_Error("%s: Illegible server message. Previous was %s", __func__, svc_strings[prevcmd]); } prevcmd = cmd; } }
/* ================ 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; sharedPlayerState_t *newPS, *oldPS; int deltaNum; int oldMessageNum; int i, packetNum; if ( !cgvm ) { Com_Error( ERR_DROP, "Received unexpected snapshot" ); } if ( !cl.cgamePlayerStateSize || !cl.cgameEntityStateSize ) { Com_Error( ERR_DROP, "cgame needs to call trap_SetNetFields" ); } // 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 ); // if we were just unpaused, we can only *now* really let the // change come into effect or the client hangs. cl_paused->modified = 0; 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 > cl.parseEntities.maxElements - MAX_SNAPSHOT_ENTITIES * CL_MAX_SPLITVIEW ) { Com_Printf ("Delta parseEntitiesNum too old.\n"); } else { newSnap.valid = qtrue; // valid delta parse } } DA_Clear( &cl.tempSnapshotPS ); // read playerinfo SHOWNET( msg, "playerstate" ); newSnap.numPSs = MSG_ReadByte( msg ); if (newSnap.numPSs > MAX_SPLITVIEW) { Com_DPrintf(S_COLOR_YELLOW "Warning: Got numPSs as %d (max=%d)\n", newSnap.numPSs, MAX_SPLITVIEW); newSnap.numPSs = MAX_SPLITVIEW; } for (i = 0; i < MAX_SPLITVIEW; i++) { newSnap.localPlayerIndex[i] = MSG_ReadByte( msg ); newSnap.playerNums[i] = MSG_ReadByte( msg ); // -1 gets converted to 255 should be set to -1 (and so should all invalid values) if ( newSnap.localPlayerIndex[i] >= newSnap.numPSs || newSnap.playerNums[i] >= MAX_CLIENTS ) { newSnap.localPlayerIndex[i] = -1; newSnap.playerNums[i] = -1; } // read areamask len = MSG_ReadByte( msg ); if(len > sizeof(newSnap.areamask[0])) { Com_Error (ERR_DROP,"CL_ParseSnapshot: Invalid size %d for areamask", len); return; } MSG_ReadData( msg, &newSnap.areamask[i], len); } for (i = 0; i < MAX_SPLITVIEW; i++) { // Read player states if (newSnap.localPlayerIndex[i] != -1) { newPS = (sharedPlayerState_t *) DA_ElementPointer( cl.tempSnapshotPS, newSnap.localPlayerIndex[i] ); if ( old && old->valid && old->localPlayerIndex[i] != -1 ) { oldPS = (sharedPlayerState_t *) DA_ElementPointer( old->playerStates, old->localPlayerIndex[i] ); MSG_ReadDeltaPlayerstate( msg, oldPS, newPS, newSnap.playerNums[i] ); } else { MSG_ReadDeltaPlayerstate( msg, NULL, newPS, newSnap.playerNums[i] ); } } // Server added or removed local player if ( old && old->playerNums[i] != newSnap.playerNums[i] ) { CL_LocalPlayerRemoved( i ); if ( newSnap.playerNums[i] != -1 ) { CL_LocalPlayerAdded( i, newSnap.playerNums[i] ); } } } // 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 player states from temp to snapshot DA_Copy( cl.tempSnapshotPS, &cl.snapshots[newSnap.messageNum & PACKET_MASK].playerStates ); newSnap.playerStates = cl.snapshots[newSnap.messageNum & PACKET_MASK].playerStates; // 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; newPS = (sharedPlayerState_t *) DA_ElementPointer( cl.snap.playerStates, 0 ); if ( newPS->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; }