Fixed possible buffer overflow & optimized network

This commit is contained in:
Kamay Xutax 2024-08-31 00:20:04 +02:00
parent 8db1b5ec1a
commit 380f352adf
9 changed files with 233 additions and 352 deletions

View file

@ -62,10 +62,7 @@ static inline bool EncodeSpecialFloat( const SendProp *pProp, float fVal, bf_wri
// TODO_ENHANCED: // TODO_ENHANCED:
// Encoding works by sending a normalized float (from range 0.0 to 1.0) // Encoding works by sending a normalized float (from range 0.0 to 1.0)
// This works because we know the range we encode the float to // This works because we know the range we encode the float to
static inline void EncodeFloat(const SendProp* pProp, static inline void EncodeFloat( const SendProp* pProp, float fVal, bf_write* pOut, int objectID )
float fVal,
bf_write* pOut,
int objectID)
{ {
const auto WriteNormalizedFloat = [&]( double dblValue ) const auto WriteNormalizedFloat = [&]( double dblValue )
{ {
@ -102,8 +99,7 @@ static inline void EncodeFloat(const SendProp* pProp,
return; return;
} }
if ((pProp->m_fHighValue == 0.0f && pProp->m_fLowValue == 0.0f) if ( ( pProp->m_fHighValue == 0.0f && pProp->m_fLowValue == 0.0f ) || pProp->m_fHighValue == pProp->m_fLowValue )
|| pProp->m_fHighValue == pProp->m_fLowValue)
{ {
pOut->WriteBitFloat( fVal ); pOut->WriteBitFloat( fVal );
return; return;
@ -159,8 +155,7 @@ static inline void EncodeFloat(const SendProp* pProp,
pOut->WriteOneBit( sign ); pOut->WriteOneBit( sign );
WriteNormalizedFloat(dblRange > 1.0 ? (dblVal / dblRange) : WriteNormalizedFloat( dblRange > 1.0 ? ( dblVal / dblRange ) : dblVal );
dblVal);
} }
// Look for special flags like SPROP_COORD, SPROP_NOSCALE, and SPROP_NORMAL and // Look for special flags like SPROP_COORD, SPROP_NOSCALE, and SPROP_NORMAL and

View file

@ -1018,6 +1018,8 @@ if active == 1 then we are 1) not playing back demos ( where our commands are ig
void CInput::ExtraMouseSample( float frametime, bool active ) void CInput::ExtraMouseSample( float frametime, bool active )
{ {
VPROF( "CInput::ExtraMouseSample" );
CUserCmd dummy; CUserCmd dummy;
CUserCmd *cmd = &dummy; CUserCmd *cmd = &dummy;
@ -1125,13 +1127,14 @@ void CInput::ExtraMouseSample( float frametime, bool active )
void CInput::CreateMove ( int sequence_number, float input_sample_frametime, bool active ) void CInput::CreateMove ( int sequence_number, float input_sample_frametime, bool active )
{ {
VPROF( "CInput::CreateMove" );
CUserCmd *cmd = &m_pCommands[ sequence_number % MULTIPLAYER_BACKUP ]; CUserCmd *cmd = &m_pCommands[ sequence_number % MULTIPLAYER_BACKUP ];
CVerifiedUserCmd *pVerified = &m_pVerifiedCommands[ sequence_number % MULTIPLAYER_BACKUP ]; CVerifiedUserCmd *pVerified = &m_pVerifiedCommands[ sequence_number % MULTIPLAYER_BACKUP ];
cmd->Reset(); cmd->Reset();
cmd->command_number = sequence_number; cmd->command_number = sequence_number;
cmd->tick_count = gpGlobals->tickcount;
QAngle viewangles; QAngle viewangles;
engine->GetViewAngles( viewangles ); engine->GetViewAngles( viewangles );
@ -1306,8 +1309,8 @@ void CInput::CreateMove ( int sequence_number, float input_sample_frametime, boo
cmd->simulationdata[i].m_bEntityExists = false; cmd->simulationdata[i].m_bEntityExists = false;
} }
// Send interpolated simulation time for lag compensation // Send interpolated simulation time for lag compensation, let it also auto-vectorize this.
for (int i = 0; i <= ClientEntityList().GetHighestEntityIndex(); i++) for ( int i = 0; i < MAX_EDICTS; i++ )
{ {
auto pEntity = ClientEntityList().GetEnt( i ); auto pEntity = ClientEntityList().GetEnt( i );

View file

@ -863,10 +863,6 @@ bool UserCmdChanged( const CUserCmd& lhs, const CUserCmd& rhs )
return true; return true;
if ( lhs.weaponsubtype != rhs.weaponsubtype ) if ( lhs.weaponsubtype != rhs.weaponsubtype )
return true; return true;
if ( lhs.mousedx != rhs.mousedx )
return true;
if ( lhs.mousedy != rhs.mousedy )
return true;
return false; return false;
} }

View file

@ -606,14 +606,6 @@ void CCSPlayer::PlayerRunCommand( CUserCmd *ucmd, IMoveHelper *moveHelper )
if ( !sv_runcmds.GetInt() ) if ( !sv_runcmds.GetInt() )
return; return;
// don't run commands in the future
if (!IsEngineThreaded()
&& (ucmd->tick_count > (gpGlobals->tickcount + sv_max_usercmd_future_ticks.GetInt())) && !IsBot())
{
DevMsg( "Client cmd out of sync (delta: %i, client: %i != server: %i).\n", ucmd->tick_count - gpGlobals->tickcount, ucmd->tick_count, gpGlobals->tickcount);
return;
}
// If they use a negative bot_mimic value, then don't process their usercmds, but have // If they use a negative bot_mimic value, then don't process their usercmds, but have
// bots process them instead (so they can stay still and have the bot move around). // bots process them instead (so they can stay still and have the bot move around).
CUserCmd tempCmd; CUserCmd tempCmd;
@ -696,7 +688,6 @@ void CCSPlayer::RunPlayerMove( const QAngle& viewangles, float forwardmove, floa
{ {
CUserCmd lastCmd = *GetLastUserCommand(); CUserCmd lastCmd = *GetLastUserCommand();
lastCmd.command_number = cmd.command_number; lastCmd.command_number = cmd.command_number;
lastCmd.tick_count = cmd.tick_count;
SetLastUserCommand( lastCmd ); SetLastUserCommand( lastCmd );
} }
else else

View file

@ -3274,7 +3274,6 @@ void CBasePlayer::PhysicsSimulate( void )
// run the last known cmd for each dropped cmd we don't have a backup for // run the last known cmd for each dropped cmd we don't have a backup for
while ( droppedcmds > numbackup ) while ( droppedcmds > numbackup )
{ {
m_LastCmd.tick_count++;
vecAvailCommands.AddToTail( m_LastCmd ); vecAvailCommands.AddToTail( m_LastCmd );
droppedcmds--; droppedcmds--;
} }
@ -3527,13 +3526,7 @@ bool CBasePlayer::IsUserCmdDataValid( CUserCmd *pCmd )
if ( IsBot() || IsFakeClient() ) if ( IsBot() || IsFakeClient() )
return true; return true;
// Maximum difference between client's and server's tick_count bool bValid = // Prevent clients from sending invalid view angles to try to get leaf server code to crash
const int nCmdMaxTickDelta = ( 1.f / gpGlobals->interval_per_tick ) * 2.5f;
const int nMinDelta = Max( 0, gpGlobals->tickcount - nCmdMaxTickDelta );
const int nMaxDelta = gpGlobals->tickcount + nCmdMaxTickDelta;
bool bValid = ( pCmd->tick_count >= nMinDelta && pCmd->tick_count < nMaxDelta ) &&
// Prevent clients from sending invalid view angles to try to get leaf server code to crash
( pCmd->viewangles.IsValid() && IsEntityQAngleReasonable( pCmd->viewangles ) ) && ( pCmd->viewangles.IsValid() && IsEntityQAngleReasonable( pCmd->viewangles ) ) &&
// Movement ranges // Movement ranges
( IsFinite( pCmd->forwardmove ) && IsEntityCoordinateReasonable( pCmd->forwardmove ) ) && ( IsFinite( pCmd->forwardmove ) && IsEntityCoordinateReasonable( pCmd->forwardmove ) ) &&
@ -3547,8 +3540,7 @@ bool CBasePlayer::IsUserCmdDataValid( CUserCmd *pCmd )
if ( nWarningLevel == 2 ) if ( nWarningLevel == 2 )
{ {
DevMsg( " tick_count: %i\n viewangles: %5.2f %5.2f %5.2f \n forward: %5.2f \n side: \t%5.2f \n up: \t%5.2f\n", DevMsg( "viewangles: %5.2f %5.2f %5.2f \n forward: %5.2f \n side: \t%5.2f \n up: \t%5.2f\n",
pCmd->tick_count,
pCmd->viewangles.x, pCmd->viewangles.x,
pCmd->viewangles.y, pCmd->viewangles.y,
pCmd->viewangles.x, pCmd->viewangles.x,
@ -9230,13 +9222,8 @@ void CPlayerInfo::RunPlayerMove( CBotCmd *ucmd )
cmd.buttons = ucmd->buttons; cmd.buttons = ucmd->buttons;
cmd.command_number = ucmd->command_number; cmd.command_number = ucmd->command_number;
cmd.forwardmove = ucmd->forwardmove; cmd.forwardmove = ucmd->forwardmove;
cmd.hasbeenpredicted = ucmd->hasbeenpredicted;
cmd.impulse = ucmd->impulse; cmd.impulse = ucmd->impulse;
cmd.mousedx = ucmd->mousedx;
cmd.mousedy = ucmd->mousedy;
cmd.random_seed = ucmd->random_seed;
cmd.sidemove = ucmd->sidemove; cmd.sidemove = ucmd->sidemove;
cmd.tick_count = ucmd->tick_count;
cmd.upmove = ucmd->upmove; cmd.upmove = ucmd->upmove;
cmd.viewangles = ucmd->viewangles; cmd.viewangles = ucmd->viewangles;
cmd.weaponselect = ucmd->weaponselect; cmd.weaponselect = ucmd->weaponselect;
@ -9273,13 +9260,8 @@ void CPlayerInfo::SetLastUserCommand( const CBotCmd &ucmd )
cmd.buttons = ucmd.buttons; cmd.buttons = ucmd.buttons;
cmd.command_number = ucmd.command_number; cmd.command_number = ucmd.command_number;
cmd.forwardmove = ucmd.forwardmove; cmd.forwardmove = ucmd.forwardmove;
cmd.hasbeenpredicted = ucmd.hasbeenpredicted;
cmd.impulse = ucmd.impulse; cmd.impulse = ucmd.impulse;
cmd.mousedx = ucmd.mousedx;
cmd.mousedy = ucmd.mousedy;
cmd.random_seed = ucmd.random_seed;
cmd.sidemove = ucmd.sidemove; cmd.sidemove = ucmd.sidemove;
cmd.tick_count = ucmd.tick_count;
cmd.upmove = ucmd.upmove; cmd.upmove = ucmd.upmove;
cmd.viewangles = ucmd.viewangles; cmd.viewangles = ucmd.viewangles;
cmd.weaponselect = ucmd.weaponselect; cmd.weaponselect = ucmd.weaponselect;
@ -9299,13 +9281,9 @@ CBotCmd CPlayerInfo::GetLastUserCommand()
cmd.buttons = ucmd->buttons; cmd.buttons = ucmd->buttons;
cmd.command_number = ucmd->command_number; cmd.command_number = ucmd->command_number;
cmd.forwardmove = ucmd->forwardmove; cmd.forwardmove = ucmd->forwardmove;
cmd.hasbeenpredicted = ucmd->hasbeenpredicted;
cmd.impulse = ucmd->impulse; cmd.impulse = ucmd->impulse;
cmd.mousedx = ucmd->mousedx;
cmd.mousedy = ucmd->mousedy;
cmd.random_seed = ucmd->random_seed; cmd.random_seed = ucmd->random_seed;
cmd.sidemove = ucmd->sidemove; cmd.sidemove = ucmd->sidemove;
cmd.tick_count = ucmd->tick_count;
cmd.upmove = ucmd->upmove; cmd.upmove = ucmd->upmove;
cmd.viewangles = ucmd->viewangles; cmd.viewangles = ucmd->viewangles;
cmd.weaponselect = ucmd->weaponselect; cmd.weaponselect = ucmd->weaponselect;

View file

@ -450,6 +450,8 @@ void CCSPlayer::FireBullet(
float xSpread, float ySpread float xSpread, float ySpread
) )
{ {
VPROF( "CCSPlayer::FireBullet" );
float fCurrentDamage = iDamage; // damage of the bullet at it's current trajectory float fCurrentDamage = iDamage; // damage of the bullet at it's current trajectory
float flCurrentDistance = 0.0; //distance that the bullet has traveled so far float flCurrentDistance = 0.0; //distance that the bullet has traveled so far

View file

@ -45,17 +45,6 @@ void WriteUsercmd( bf_write *buf, const CUserCmd *to, const CUserCmd *from )
buf->WriteOneBit( 0 ); buf->WriteOneBit( 0 );
} }
if ( to->tick_count != ( from->tick_count + 1 ) )
{
buf->WriteOneBit( 1 );
buf->WriteUBitLong( to->tick_count, 32 );
}
else
{
buf->WriteOneBit( 0 );
}
if ( to->viewangles[ 0 ] != from->viewangles[ 0 ] ) if ( to->viewangles[ 0 ] != from->viewangles[ 0 ] )
{ {
buf->WriteOneBit( 1 ); buf->WriteOneBit( 1 );
@ -157,33 +146,12 @@ void WriteUsercmd( bf_write *buf, const CUserCmd *to, const CUserCmd *from )
buf->WriteOneBit( 0 ); buf->WriteOneBit( 0 );
} }
// TODO: Can probably get away with fewer bits.
if ( to->mousedx != from->mousedx )
{
buf->WriteOneBit( 1 );
buf->WriteShort( to->mousedx );
}
else
{
buf->WriteOneBit( 0 );
}
if ( to->mousedy != from->mousedy )
{
buf->WriteOneBit( 1 );
buf->WriteShort( to->mousedy );
}
else
{
buf->WriteOneBit( 0 );
}
#ifdef CLIENT_DLL #ifdef CLIENT_DLL
int highestEntityIndex = 0; int highestEntityIndex = 0;
if ( cl_entitylist ) if ( cl_entitylist )
{
highestEntityIndex = cl_entitylist->GetHighestEntityIndex(); highestEntityIndex = cl_entitylist->GetHighestEntityIndex();
}
#else #else
static constexpr auto highestEntityIndex = MAX_EDICTS - 1; static constexpr auto highestEntityIndex = MAX_EDICTS - 1;
#endif #endif
@ -277,16 +245,6 @@ void ReadUsercmd( bf_read *buf, CUserCmd *move, CUserCmd *from )
move->command_number = from->command_number + 1; move->command_number = from->command_number + 1;
} }
if ( buf->ReadOneBit() )
{
move->tick_count = buf->ReadUBitLong( 32 );
}
else
{
// Assume steady increment
move->tick_count = from->tick_count + 1;
}
// Read direction // Read direction
if ( buf->ReadOneBit() ) if ( buf->ReadOneBit() )
{ {
@ -332,7 +290,6 @@ void ReadUsercmd( bf_read *buf, CUserCmd *move, CUserCmd *from )
move->impulse = buf->ReadUBitLong( 8 ); move->impulse = buf->ReadUBitLong( 8 );
} }
if ( buf->ReadOneBit() ) if ( buf->ReadOneBit() )
{ {
move->weaponselect = buf->ReadUBitLong( MAX_EDICT_BITS ); move->weaponselect = buf->ReadUBitLong( MAX_EDICT_BITS );
@ -344,17 +301,9 @@ void ReadUsercmd( bf_read *buf, CUserCmd *move, CUserCmd *from )
move->random_seed = MD5_PseudoRandom( move->command_number ) & 0x7fffffff; move->random_seed = MD5_PseudoRandom( move->command_number ) & 0x7fffffff;
if ( buf->ReadOneBit() ) auto highestEntityIndex = buf->ReadUBitLong( 11 );
{
move->mousedx = buf->ReadShort();
}
if ( buf->ReadOneBit() ) highestEntityIndex = MIN(MAX_EDICTS - 1, highestEntityIndex);
{
move->mousedy = buf->ReadShort();
}
const auto highestEntityIndex = buf->ReadUBitLong(11);
for (unsigned int i = 0; i <= highestEntityIndex; i++) for (unsigned int i = 0; i <= highestEntityIndex; i++)
{ {

View file

@ -83,7 +83,6 @@ public:
void Reset() void Reset()
{ {
command_number = 0; command_number = 0;
tick_count = 0;
viewangles.Init(); viewangles.Init();
forwardmove = 0.0f; forwardmove = 0.0f;
sidemove = 0.0f; sidemove = 0.0f;
@ -116,7 +115,6 @@ public:
return *this; return *this;
command_number = src.command_number; command_number = src.command_number;
tick_count = src.tick_count;
viewangles = src.viewangles; viewangles = src.viewangles;
forwardmove = src.forwardmove; forwardmove = src.forwardmove;
sidemove = src.sidemove; sidemove = src.sidemove;
@ -155,7 +153,6 @@ public:
CRC32_Init( &crc ); CRC32_Init( &crc );
CRC32_ProcessBuffer( &crc, &command_number, sizeof( command_number ) ); CRC32_ProcessBuffer( &crc, &command_number, sizeof( command_number ) );
CRC32_ProcessBuffer( &crc, &tick_count, sizeof( tick_count ) );
CRC32_ProcessBuffer( &crc, &viewangles, sizeof( viewangles ) ); CRC32_ProcessBuffer( &crc, &viewangles, sizeof( viewangles ) );
CRC32_ProcessBuffer( &crc, &forwardmove, sizeof( forwardmove ) ); CRC32_ProcessBuffer( &crc, &forwardmove, sizeof( forwardmove ) );
CRC32_ProcessBuffer( &crc, &sidemove, sizeof( sidemove ) ); CRC32_ProcessBuffer( &crc, &sidemove, sizeof( sidemove ) );
@ -165,8 +162,6 @@ public:
CRC32_ProcessBuffer( &crc, &weaponselect, sizeof( weaponselect ) ); CRC32_ProcessBuffer( &crc, &weaponselect, sizeof( weaponselect ) );
CRC32_ProcessBuffer( &crc, &weaponsubtype, sizeof( weaponsubtype ) ); CRC32_ProcessBuffer( &crc, &weaponsubtype, sizeof( weaponsubtype ) );
CRC32_ProcessBuffer( &crc, &random_seed, sizeof( random_seed ) ); CRC32_ProcessBuffer( &crc, &random_seed, sizeof( random_seed ) );
CRC32_ProcessBuffer( &crc, &mousedx, sizeof( mousedx ) );
CRC32_ProcessBuffer(&crc, &mousedy, sizeof(mousedy));
CRC32_ProcessBuffer( &crc, simulationdata, sizeof( simulationdata ) ); CRC32_ProcessBuffer( &crc, simulationdata, sizeof( simulationdata ) );
CRC32_ProcessBuffer( &crc, &debug_hitboxes, sizeof( debug_hitboxes ) ); CRC32_ProcessBuffer( &crc, &debug_hitboxes, sizeof( debug_hitboxes ) );
CRC32_ProcessBuffer( &crc, &interpolated_amount, sizeof( interpolated_amount ) ); CRC32_ProcessBuffer( &crc, &interpolated_amount, sizeof( interpolated_amount ) );
@ -178,22 +173,12 @@ public:
// Allow command, but negate gameplay-affecting values // Allow command, but negate gameplay-affecting values
void MakeInert( void ) void MakeInert( void )
{ {
viewangles = vec3_angle; Reset();
forwardmove = 0.f;
sidemove = 0.f;
upmove = 0.f;
buttons = 0;
impulse = 0;
debug_hitboxes = DEBUG_HITBOXES_OFF;
interpolated_amount = 0.0f;
} }
// For matching server and client commands for debugging // For matching server and client commands for debugging
int command_number; int command_number;
// the tick the client created this command
int tick_count;
// Player instantaneous view angles. // Player instantaneous view angles.
QAngle viewangles; QAngle viewangles;
// Intended velocities // Intended velocities

View file

@ -25,7 +25,6 @@ public:
void Reset() void Reset()
{ {
command_number = 0; command_number = 0;
tick_count = 0;
viewangles.Init(); viewangles.Init();
forwardmove = 0.0f; forwardmove = 0.0f;
sidemove = 0.0f; sidemove = 0.0f;
@ -35,10 +34,6 @@ public:
weaponselect = 0; weaponselect = 0;
weaponsubtype = 0; weaponsubtype = 0;
random_seed = 0; random_seed = 0;
mousedx = 0;
mousedy = 0;
hasbeenpredicted = false;
} }
CBotCmd& operator =( const CBotCmd& src ) CBotCmd& operator =( const CBotCmd& src )
@ -47,7 +42,6 @@ public:
return *this; return *this;
command_number = src.command_number; command_number = src.command_number;
tick_count = src.tick_count;
viewangles = src.viewangles; viewangles = src.viewangles;
forwardmove = src.forwardmove; forwardmove = src.forwardmove;
sidemove = src.sidemove; sidemove = src.sidemove;
@ -57,18 +51,12 @@ public:
weaponselect = src.weaponselect; weaponselect = src.weaponselect;
weaponsubtype = src.weaponsubtype; weaponsubtype = src.weaponsubtype;
random_seed = src.random_seed; random_seed = src.random_seed;
mousedx = src.mousedx;
mousedy = src.mousedy;
hasbeenpredicted = src.hasbeenpredicted;
return *this; return *this;
} }
// For matching server and client commands for debugging // For matching server and client commands for debugging
int command_number; int command_number;
// the tick the client created this command
int tick_count;
// Player instantaneous view angles. // Player instantaneous view angles.
QAngle viewangles; QAngle viewangles;
// Intended velocities // Intended velocities
@ -87,12 +75,6 @@ public:
int weaponsubtype; int weaponsubtype;
int random_seed; // For shared random functions int random_seed; // For shared random functions
short mousedx; // mouse accum in x from create move
short mousedy; // mouse accum in y from create move
// Client only, tracks whether we've predicted this command at least once
bool hasbeenpredicted;
}; };