static inline void SV_PackEntity( int edictIdx, edict_t* ent, SendTable* pSendTable, EntityChange_t changeType, CFrameSnapshot *pSnapshot ) { int iSerialNum = pSnapshot->m_Entities[ edictIdx ].m_nSerialNumber; // Check to see if this entity specifies its changes. // If so, then try to early out making the fullpack bool bUsedPrev = false; if ( changeType == ENTITY_CHANGE_NONE ) { // Now this may not work if we didn't previously send a packet; // if not, then we gotta compute it bUsedPrev = framesnapshot->UsePreviouslySentPacket( pSnapshot, edictIdx, iSerialNum ); } if ( !bUsedPrev || sv_debugmanualmode.GetInt() ) { // First encode the entity's data. char packedData[MAX_PACKEDENTITY_DATA]; bf_write writeBuf( "SV_PackEntity->writeBuf", packedData, sizeof( packedData ) ); // (avoid constructor overhead). unsigned char tempData[ sizeof( CSendProxyRecipients ) * MAX_DATATABLE_PROXIES ]; CUtlMemory< CSendProxyRecipients > recip( (CSendProxyRecipients*)tempData, pSendTable->GetNumDataTableProxies() ); if( !SendTable_Encode( pSendTable, ent->m_pEnt, &writeBuf, NULL, edictIdx, &recip ) ) { Host_Error( "SV_PackEntity: SendTable_Encode returned false (ent %d).\n", edictIdx ); } SV_EnsureInstanceBaseline( edictIdx, packedData, writeBuf.GetNumBytesWritten() ); int nFlatProps = SendTable_GetNumFlatProps( pSendTable ); IChangeFrameList *pChangeFrame; // If this entity was previously in there, then it should have a valid IChangeFrameList // which we can delta against to figure out which properties have changed. // // If not, then we want to setup a new IChangeFrameList. PackedEntity *pPrevFrame = framesnapshot->GetPreviouslySentPacket( edictIdx, pSnapshot->m_Entities[ edictIdx ].m_nSerialNumber ); if ( pPrevFrame ) { // Calculate a delta. bf_read bfPrev( "SV_PackEntity->bfPrev", pPrevFrame->LockData(), pPrevFrame->GetNumBytes() ); bf_read bfNew( "SV_PackEntity->bfNew", packedData, writeBuf.GetNumBytesWritten() ); int deltaProps[MAX_DATATABLE_PROPS]; int nChanges = SendTable_CalcDelta( pSendTable, pPrevFrame->LockData(), pPrevFrame->GetNumBits(), packedData, writeBuf.GetNumBitsWritten(), deltaProps, ARRAYSIZE( deltaProps ), edictIdx ); // If it's non-manual-mode, but we detect that there are no changes here, then just // use the previous pSnapshot if it's available (as though the entity were manual mode). // It would be interesting to hook here and see how many non-manual-mode entities // are winding up with no changes. if ( nChanges == 0 ) { if ( changeType == ENTITY_CHANGE_NONE ) { for ( int iDeltaProp=0; iDeltaProp < nChanges; iDeltaProp++ ) { Msg( "Entity %d (class '%s') reported ENTITY_CHANGE_NONE but '%s' changed.\n", edictIdx, STRING( ent->classname ), pSendTable->GetProp( deltaProps[iDeltaProp] )->GetName() ); } } else { if ( pPrevFrame->CompareRecipients( recip ) ) { if ( framesnapshot->UsePreviouslySentPacket( pSnapshot, edictIdx, iSerialNum ) ) return; } } } // Ok, now snag the changeframe from the previous frame and update the 'last frame changed' // for the properties in the delta. pChangeFrame = pPrevFrame->SnagChangeFrameList(); ErrorIfNot( pChangeFrame && pChangeFrame->GetNumProps() == nFlatProps, ("SV_PackEntity: SnagChangeFrameList returned null") ); pChangeFrame->SetChangeTick( deltaProps, nChanges, pSnapshot->m_nTickNumber ); } else { // Ok, init the change frames for the first time. pChangeFrame = AllocChangeFrameList( nFlatProps, pSnapshot->m_nTickNumber ); } // Now make a PackedEntity and store the new packed data in there. PackedEntity *pCurFrame = framesnapshot->CreatePackedEntity( pSnapshot, edictIdx ); pCurFrame->SetChangeFrameList( pChangeFrame ); pCurFrame->m_nEntityIndex = edictIdx; pCurFrame->m_pSendTable = pSendTable; pCurFrame->AllocAndCopyPadded( packedData, writeBuf.GetNumBytesWritten(), &g_PackedDataAllocator ); pCurFrame->SetRecipients( recip ); } }