You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
325 lines
8.7 KiB
325 lines
8.7 KiB
//========= Copyright 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 ) |
|
//----------------------------------------------------------------------------- |
|
// Purpose: Helper class for resetting instance numbers, etc. |
|
//----------------------------------------------------------------------------- |
|
class CPredictableIdHelper |
|
{ |
|
public: |
|
CPredictableIdHelper() |
|
{ |
|
Reset( -1 ); |
|
} |
|
|
|
void Reset( int command ) |
|
{ |
|
m_nCurrentCommand = command; |
|
m_nCount = 0; |
|
memset( m_Entries, 0, sizeof( m_Entries ) ); |
|
} |
|
|
|
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
|
|
|