source-engine/game/shared/predictableid.cpp

326 lines
8.7 KiB
C++
Raw Normal View History

2020-04-22 16:56:21 +00:00
//========= 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