int ProcessMessages(bf_read&msgs) { int processed = 0; while (true) { if (msgs.IsOverflowed()) { return processed; } unsigned char type = msgs.ReadUBitLong(NETMSG_TYPE_BITS); bool handled = HandleMessage(msgs, type); if (!handled) { printf("Unhandled Message: %i\n", type); return processed; } processed++; if (msgs.GetNumBitsLeft() < NETMSG_TYPE_BITS) { return processed; } } return processed; }
bool CheckJobID( bf_read &buf, int jobID[4] ) { TimeoutJobIDs(); jobID[0] = buf.ReadLong(); jobID[1] = buf.ReadLong(); jobID[2] = buf.ReadLong(); jobID[3] = buf.ReadLong(); if ( FindJobMemory( jobID ) || buf.IsOverflowed() ) { return false; } return true; }
//----------------------------------------------------------------------------- // Purpose: Called when we get a stat update for the local player //----------------------------------------------------------------------------- void CTFStatPanel::MsgFunc_PlayerStatsUpdate( bf_read &msg ) { // get the fixed-size information int iClass = msg.ReadByte(); int iMsgType = msg.ReadByte(); int iSendBits = msg.ReadLong(); bool bAlive = true; bool bSpawned = false; switch ( iMsgType ) { case STATMSG_RESET: m_RoundStatsCurrentGame.Reset(); m_RoundStatsLifeStart.Reset(); return; case STATMSG_PLAYERSPAWN: case STATMSG_PLAYERRESPAWN: bSpawned = true; break; case STATMSG_PLAYERDEATH: bAlive = false; break; case STATMSG_UPDATE: break; default: Assert( false ); } Assert( iClass >= TF_FIRST_NORMAL_CLASS && iClass <= TF_LAST_NORMAL_CLASS ); if ( iClass < TF_FIRST_NORMAL_CLASS || iClass > TF_LAST_NORMAL_CLASS ) return; m_iClassCurrentLife = iClass; C_TFPlayer *pPlayer = C_TFPlayer::GetLocalTFPlayer(); if ( pPlayer ) { m_iTeamCurrentLife = pPlayer->GetTeamNumber(); } // Msg( "Stat update: (msg %d) ", iMsgType ); // the bitfield indicates which stats are contained in the message. Set the stats appropriately. int iStat = TFSTAT_FIRST; while ( iSendBits > 0 ) { if ( iSendBits & 1 ) { int iVal = msg.ReadLong(); // Msg( "#%d=%d ", iStat, iVal ); m_RoundStatsCurrentGame.m_iStat[iStat] = iVal; } iSendBits >>= 1; iStat++; } // Msg( "\n" ); // Calculate stat values for current life. Take current game stats and subtract what the values were at the start of this life for ( iStat = TFSTAT_FIRST; iStat < TFSTAT_MAX; iStat++ ) { if ( iStat == TFSTAT_MAXSENTRYKILLS ) { // max sentry kills is special, it is a max value. Always use absolute value, do not use delta from earlier value. m_RoundStatsCurrentLife.m_iStat[TFSTAT_MAXSENTRYKILLS] = m_RoundStatsCurrentGame.m_iStat[TFSTAT_MAXSENTRYKILLS]; continue; } int iDelta = m_RoundStatsCurrentGame.m_iStat[iStat] - m_RoundStatsLifeStart.m_iStat[iStat]; Assert( iDelta >= 0 ); m_RoundStatsCurrentLife.m_iStat[iStat] = iDelta; } if ( iMsgType == STATMSG_PLAYERDEATH || iMsgType == STATMSG_PLAYERRESPAWN ) { m_RoundStatsCurrentLife.m_iStat[TFSTAT_PLAYTIME] = gpGlobals->curtime - m_flTimeCurrentLifeStart; } if ( bSpawned ) { // if the player just spawned, use current stats as baseline to calculate stats for next life m_RoundStatsLifeStart = m_RoundStatsCurrentGame; m_flTimeCurrentLifeStart = gpGlobals->curtime; } // sanity check: the message should contain exactly the # of bytes we expect based on the bit field Assert( !msg.IsOverflowed() ); Assert( 0 == msg.GetNumBytesLeft() ); // if byte count isn't correct, bail out and don't use this data, rather than risk polluting player stats with garbage if ( msg.IsOverflowed() || ( 0 != msg.GetNumBytesLeft() ) ) return; UpdateStats( iMsgType ); }