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.
326 lines
8.7 KiB
326 lines
8.7 KiB
5 years ago
|
//========= 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
|