//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ //=============================================================================// #include "cbase.h" #include "checksum_crc.h" #include "tier1/strtools.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" #if !defined( NO_ENTITY_PREDICTION ) && defined( USE_PREDICTABLEID ) //----------------------------------------------------------------------------- // Purpose: Helper class for resetting instance numbers, etc. //----------------------------------------------------------------------------- class CPredictableIdHelper { public: CPredictableIdHelper() { memset( m_Entries, 0, sizeof( m_Entries ) ); Reset( -1 ); } void Reset( int command ) { m_nCurrentCommand = command; m_nCount = 0; } int AddEntry( int command, int hash ) { // Clear list if command number changes if ( command != m_nCurrentCommand ) { Reset( command ); } entry *e = FindOrAddEntry( hash ); if ( !e ) return 0; e->count++; return e->count-1; } private: enum { MAX_ENTRIES = 256, }; struct entry { int hash; int count; }; entry *FindOrAddEntry( int hash ) { int i; for ( i = 0; i < m_nCount; i++ ) { entry *e = &m_Entries[ i ]; if ( e->hash == hash ) return e; } if ( m_nCount >= MAX_ENTRIES ) { // assert( 0 ); return NULL; } entry *e = &m_Entries[ m_nCount++ ]; e->hash = hash; e->count = 0; return e; } int m_nCurrentCommand; int m_nCount; entry m_Entries[ MAX_ENTRIES ]; }; static CPredictableIdHelper g_Helper; //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- CPredictableId::CPredictableId( void ) { memset( &m_PredictableID, 0, sizeof( m_PredictableID ) ); } //----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CPredictableId::ResetInstanceCounters( void ) { g_Helper.Reset( -1 ); } //----------------------------------------------------------------------------- // Purpose: Is the Id being used // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool CPredictableId::IsActive( void ) const { if ( *(const int *)&m_PredictableID == 0 ) return false; return true; } //----------------------------------------------------------------------------- // Purpose: // Input : playerIndex - //----------------------------------------------------------------------------- void CPredictableId::SetPlayer( int playerIndex ) { m_PredictableID.player = (unsigned int)playerIndex; } //----------------------------------------------------------------------------- // Purpose: // Output : int //----------------------------------------------------------------------------- int CPredictableId::GetPlayer( void ) const { return (int)m_PredictableID.player; } //----------------------------------------------------------------------------- // Purpose: // Output : int //----------------------------------------------------------------------------- int CPredictableId::GetCommandNumber( void ) const { return (int)m_PredictableID.command; } //----------------------------------------------------------------------------- // Purpose: // Input : commandNumber - //----------------------------------------------------------------------------- void CPredictableId::SetCommandNumber( int commandNumber ) { m_PredictableID.command = (unsigned int)commandNumber; } /* bool CPredictableId::IsCommandNumberEqual( int testNumber ) const { if ( ( testNumber & ((1<<10) - 1) ) == m_PredictableID.command ) return true; return false; } */ //----------------------------------------------------------------------------- // Purpose: // Input : *classname - // *module - // line - // Output : static int //----------------------------------------------------------------------------- static int ClassFileLineHash( const char *classname, const char *module, int line ) { CRC32_t retval; CRC32_Init( &retval ); char tempbuffer[ 512 ]; // ACK, have to go lower case due to issues with .dsp having different cases of drive // letters, etc.!!! Q_strncpy( tempbuffer, classname, sizeof( tempbuffer ) ); Q_strlower( tempbuffer ); CRC32_ProcessBuffer( &retval, (void *)tempbuffer, Q_strlen( tempbuffer ) ); Q_strncpy( tempbuffer, module, sizeof( tempbuffer ) ); Q_strlower( tempbuffer ); CRC32_ProcessBuffer( &retval, (void *)tempbuffer, Q_strlen( tempbuffer ) ); CRC32_ProcessBuffer( &retval, (void *)&line, sizeof( int ) ); CRC32_Final( &retval ); return (int)retval; } //----------------------------------------------------------------------------- // Purpose: Create a predictable id of the specified parameter set // Input : player - // command - // *classname - // *module - // line - //----------------------------------------------------------------------------- void CPredictableId::Init( int player, int command, const char *classname, const char *module, int line ) { SetPlayer( player ); SetCommandNumber( command ); m_PredictableID.hash = ClassFileLineHash( classname, module, line ); // Use helper to determine instance number this command int instance = g_Helper.AddEntry( command, m_PredictableID.hash ); // Set appropriate instance number SetInstanceNumber( instance ); } //----------------------------------------------------------------------------- // Purpose: // Output : int //----------------------------------------------------------------------------- int CPredictableId::GetHash( void ) const { return (int)m_PredictableID.hash; } //----------------------------------------------------------------------------- // Purpose: // Input : counter - //----------------------------------------------------------------------------- void CPredictableId::SetInstanceNumber( int counter ) { m_PredictableID.instance = (unsigned int)counter; } //----------------------------------------------------------------------------- // Purpose: // Output : int //----------------------------------------------------------------------------- int CPredictableId::GetInstanceNumber( void ) const { return (int)m_PredictableID.instance; } // Client only //----------------------------------------------------------------------------- // Purpose: // Input : ack - //----------------------------------------------------------------------------- void CPredictableId::SetAcknowledged( bool ack ) { m_PredictableID.ack = ack ? 1 : 0; } //----------------------------------------------------------------------------- // Purpose: // Output : Returns true on success, false on failure. //----------------------------------------------------------------------------- bool CPredictableId::GetAcknowledged( void ) const { return m_PredictableID.ack ? true : false; } //----------------------------------------------------------------------------- // Purpose: // Output : int //----------------------------------------------------------------------------- int CPredictableId::GetRaw( void ) const { return *(int *)&m_PredictableID; } //----------------------------------------------------------------------------- // Purpose: // Input : raw - //----------------------------------------------------------------------------- void CPredictableId::SetRaw( int raw ) { *(int *)&m_PredictableID = raw; } //----------------------------------------------------------------------------- // Purpose: Determine if one id is == another, ignores Acknowledged state // Input : other - // Output : bool CPredictableId::operator //----------------------------------------------------------------------------- bool CPredictableId::operator ==( const CPredictableId& other ) const { if ( this == &other ) return true; if ( GetPlayer() != other.GetPlayer() ) return false; if ( GetCommandNumber() != other.GetCommandNumber() ) return false; if ( GetHash() != other.GetHash() ) return false; if ( GetInstanceNumber() != other.GetInstanceNumber() ) return false; return true; } bool CPredictableId::operator !=( const CPredictableId& other ) const { return !(*this == other); } //----------------------------------------------------------------------------- // Purpose: // Output : char const //----------------------------------------------------------------------------- const char *CPredictableId::Describe( void ) const { static char desc[ 128 ]; Q_snprintf( desc, sizeof( desc ), "pl(%i) cmd(%i) hash(%i) inst(%i) ack(%s)", GetPlayer(), GetCommandNumber(), GetHash(), GetInstanceNumber() , GetAcknowledged() ? "true" : "false" ); return desc; } #endif