Improved lag compensation for entities

This commit is contained in:
unknown 2024-09-03 22:44:31 +02:00
parent 87337859f4
commit f696159421
20 changed files with 381 additions and 434 deletions

View file

@ -78,7 +78,7 @@ bool CLC_Move::WriteToBuffer( bf_write &buffer )
buffer.WriteUBitLong( m_nNewCommands, NUM_NEW_COMMAND_BITS ); buffer.WriteUBitLong( m_nNewCommands, NUM_NEW_COMMAND_BITS );
buffer.WriteUBitLong( m_nBackupCommands, NUM_BACKUP_COMMAND_BITS ); buffer.WriteUBitLong( m_nBackupCommands, NUM_BACKUP_COMMAND_BITS );
buffer.WriteWord( m_nLength ); buffer.WriteLong( m_nLength );
return buffer.WriteBits( m_DataOut.GetData(), m_nLength ); return buffer.WriteBits( m_DataOut.GetData(), m_nLength );
} }
@ -89,7 +89,7 @@ bool CLC_Move::ReadFromBuffer( bf_read &buffer )
m_nNewCommands = buffer.ReadUBitLong( NUM_NEW_COMMAND_BITS ); m_nNewCommands = buffer.ReadUBitLong( NUM_NEW_COMMAND_BITS );
m_nBackupCommands = buffer.ReadUBitLong( NUM_BACKUP_COMMAND_BITS ); m_nBackupCommands = buffer.ReadUBitLong( NUM_BACKUP_COMMAND_BITS );
m_nLength = buffer.ReadWord(); m_nLength = buffer.ReadLong();
m_DataIn = buffer; m_DataIn = buffer;
return buffer.SeekRelative( m_nLength ); return buffer.SeekRelative( m_nLength );
} }

View file

@ -91,7 +91,7 @@ void WriteConfig_f( ConVar *var, const char *pOldString );
// If we get more than 250 messages in the incoming buffer queue, dump any above this # // If we get more than 250 messages in the incoming buffer queue, dump any above this #
#define MAX_INCOMING_MESSAGES 250 #define MAX_INCOMING_MESSAGES 250
// Size of command send buffer // Size of command send buffer
#define MAX_CMD_BUFFER 0x10000 #define MAX_CMD_BUFFER 0x100000
CGlobalVarsBase g_ClientGlobalVariables( true ); CGlobalVarsBase g_ClientGlobalVariables( true );
IVideoRecorder *g_pVideoRecorder = NULL; IVideoRecorder *g_pVideoRecorder = NULL;

View file

@ -106,7 +106,15 @@ public:
C_BaseAnimating(); C_BaseAnimating();
~C_BaseAnimating(); ~C_BaseAnimating();
virtual C_BaseAnimating* GetBaseAnimating() { return this; } virtual C_BaseAnimating* GetBaseAnimating()
{
return this;
}
bool IsUsingClientSideAnimation()
{
return m_bClientSideAnimation;
}
bool UsesPowerOfTwoFrameBufferTexture( void ); bool UsesPowerOfTwoFrameBufferTexture( void );

View file

@ -690,7 +690,6 @@ IMPLEMENT_CLIENTCLASS_DT( C_CSPlayer, DT_CSPlayer, CCSPlayer )
RecvPropInt( RECVINFO( m_iClass ) ), RecvPropInt( RECVINFO( m_iClass ) ),
RecvPropInt( RECVINFO( m_ArmorValue ) ), RecvPropInt( RECVINFO( m_ArmorValue ) ),
RecvPropQAngles( RECVINFO( m_angEyeAngles ) ), RecvPropQAngles( RECVINFO( m_angEyeAngles ) ),
RecvPropQAngles( RECVINFO( m_angRenderAngles ) ),
RecvPropFloat( RECVINFO( m_flStamina ) ), RecvPropFloat( RECVINFO( m_flStamina ) ),
RecvPropInt( RECVINFO( m_bHasDefuser ), 0, RecvProxy_HasDefuser ), RecvPropInt( RECVINFO( m_bHasDefuser ), 0, RecvProxy_HasDefuser ),
RecvPropInt( RECVINFO( m_bNightVisionOn), 0, RecvProxy_NightVision ), RecvPropInt( RECVINFO( m_bNightVisionOn), 0, RecvProxy_NightVision ),
@ -736,10 +735,8 @@ C_CSPlayer::C_CSPlayer() :
m_iv_angRenderAngles( "C_CSPlayer::m_iv_angRenderAngles" ) m_iv_angRenderAngles( "C_CSPlayer::m_iv_angRenderAngles" )
{ {
m_angEyeAngles.Init(); m_angEyeAngles.Init();
m_angRenderAngles.Init();
AddVar( &m_angEyeAngles, &m_iv_angEyeAngles, LATCH_SIMULATION_VAR ); AddVar( &m_angEyeAngles, &m_iv_angEyeAngles, LATCH_SIMULATION_VAR );
// AddVar( &m_angRenderAngles, &m_iv_angRenderAngles, LATCH_SIMULATION_VAR );
m_iLastAddonBits = m_iAddonBits = 0; m_iLastAddonBits = m_iAddonBits = 0;
m_iLastPrimaryAddon = m_iLastSecondaryAddon = WEAPON_NONE; m_iLastPrimaryAddon = m_iLastSecondaryAddon = WEAPON_NONE;
@ -890,7 +887,7 @@ const QAngle& C_CSPlayer::GetRenderAngles()
} }
else else
{ {
return m_angRenderAngles; return BaseClass::GetRenderAngles();
} }
} }
@ -2183,7 +2180,7 @@ void C_CSPlayer::FireGameEvent( IGameEvent* event )
C_AnimationLayer backupAnimLayers[C_BaseAnimatingOverlay::MAX_OVERLAYS]; C_AnimationLayer backupAnimLayers[C_BaseAnimatingOverlay::MAX_OVERLAYS];
Vector vecBackupPosition = player->GetAbsOrigin(); Vector vecBackupPosition = player->GetAbsOrigin();
QAngle angBackupAngles = player->GetRenderAngles(); QAngle angBackupAngles = player->GetAbsAngles();
auto flOldCycle = player->GetCycle(); auto flOldCycle = player->GetCycle();
auto iOldSequence = player->GetSequence(); auto iOldSequence = player->GetSequence();
@ -2208,9 +2205,9 @@ void C_CSPlayer::FireGameEvent( IGameEvent* event )
event->GetFloat( "position_y" ), event->GetFloat( "position_y" ),
event->GetFloat( "position_z" ) ) ); event->GetFloat( "position_z" ) ) );
player->m_angRenderAngles = QAngle( event->GetFloat( "angle_x" ), player->SetAbsAngles( QAngle( event->GetFloat( "angle_x" ),
event->GetFloat( "angle_y" ), event->GetFloat( "angle_y" ),
event->GetFloat( "angle_z" ) ); event->GetFloat( "angle_z" ) ) );
const auto numposeparams = event->GetInt( "num_poseparams" ); const auto numposeparams = event->GetInt( "num_poseparams" );
Assert( numposeparams == player->GetModelPtr()->GetNumPoseParameters() ); Assert( numposeparams == player->GetModelPtr()->GetNumPoseParameters() );
@ -2314,17 +2311,19 @@ void C_CSPlayer::FireGameEvent( IGameEvent* event )
pos++; pos++;
} }
if ( pRecord->m_angRenderAngles != player->m_angRenderAngles ) auto angles = player->GetAbsAngles();
if ( pRecord->m_angAbsRotation != angles )
{ {
char buffer[256]; char buffer[256];
V_sprintf_safe( buffer, V_sprintf_safe( buffer,
"angles: %f != %f, %f != %f, %f != %f", "angles: %f != %f, %f != %f, %f != %f",
player->m_angRenderAngles.x, angles.x,
pRecord->m_angRenderAngles.x, pRecord->m_angAbsRotation.x,
player->m_angRenderAngles.y, angles.y,
pRecord->m_angRenderAngles.y, pRecord->m_angAbsRotation.y,
player->m_angRenderAngles.z, angles.z,
pRecord->m_angRenderAngles.z ); pRecord->m_angAbsRotation.z );
NDebugOverlay::EntityTextAtPosition( pRecord->m_vecAbsOrigin, pos, buffer, flDuration ); NDebugOverlay::EntityTextAtPosition( pRecord->m_vecAbsOrigin, pos, buffer, flDuration );
pos++; pos++;
@ -2441,7 +2440,7 @@ void C_CSPlayer::FireGameEvent( IGameEvent* event )
player->m_nSequence = iOldSequence; player->m_nSequence = iOldSequence;
player->m_flCycle = flOldCycle; player->m_flCycle = flOldCycle;
player->SetAbsOrigin( vecBackupPosition ); player->SetAbsOrigin( vecBackupPosition );
player->m_angRenderAngles = angBackupAngles; player->SetAbsAngles( angBackupAngles );
for ( int i = 0; i < MAXSTUDIOPOSEPARAM; i++ ) for ( int i = 0; i < MAXSTUDIOPOSEPARAM; i++ )
{ {

View file

@ -325,9 +325,7 @@ private:
bool m_bHasHelmet; bool m_bHasHelmet;
int m_iClass; int m_iClass;
int m_ArmorValue; int m_ArmorValue;
public:
QAngle m_angEyeAngles; QAngle m_angEyeAngles;
QAngle m_angRenderAngles;
private: private:
bool m_bHasDefuser; bool m_bHasDefuser;
float m_fNextThinkPushAway; float m_fNextThinkPushAway;
@ -411,7 +409,7 @@ private:
{ {
int m_nAttackerTickBase; int m_nAttackerTickBase;
Vector m_vecAbsOrigin; Vector m_vecAbsOrigin;
QAngle m_angRenderAngles; QAngle m_angAbsRotation;
float m_flSimulationTime; float m_flSimulationTime;
int m_nSequence; int m_nSequence;
float m_flCycle; float m_flCycle;

View file

@ -1306,21 +1306,33 @@ void CInput::CreateMove ( int sequence_number, float input_sample_frametime, boo
for ( int i = 0; i < MAX_EDICTS; i++ ) for ( int i = 0; i < MAX_EDICTS; i++ )
{ {
cmd->simulationdata[i].entityexists = false; cmd->simulationdata[i] = {};
} }
// Send interpolated simulation time for lag compensation, let it also auto-vectorize this. // Send interpolated simulation time for lag compensation, let it also auto-vectorize this.
for ( int i = 0; i < MAX_EDICTS; i++ ) for ( int i = 0; i < MAX_EDICTS; i++ )
{ {
auto pEntity = ClientEntityList().GetEnt( i ); const auto pEntity = ClientEntityList().GetEnt( i );
if ( !pEntity ) if ( !pEntity )
{ {
continue; continue;
} }
cmd->simulationdata[pEntity->index].sim_time = pEntity->m_flInterpolatedSimulationTime; if ( pEntity->ShouldPredict() )
cmd->simulationdata[pEntity->index].anim_time = pEntity->m_flAnimTime; {
continue;
}
cmd->simulationdata[pEntity->index].sim_time = pEntity->m_flInterpolatedSimulationTime;
auto pAnim = pEntity->GetBaseAnimating();
if ( pAnim && !pAnim->IsUsingClientSideAnimation() )
{
cmd->simulationdata[pEntity->index].anim_time = pEntity->m_flAnimTime;
}
cmd->simulationdata[pEntity->index].entityexists = true; cmd->simulationdata[pEntity->index].entityexists = true;
} }

View file

@ -480,7 +480,7 @@ void CBaseAnimatingOverlay::GetSkeleton( CStudioHdr *pStudioHdr, Vector pos[], Q
if ( m_pIk ) if ( m_pIk )
{ {
CIKContext auto_ik; CIKContext auto_ik;
auto_ik.Init( pStudioHdr, GetRenderAngles(), GetRenderOrigin(), gpGlobals->curtime, m_iIKCounter, boneMask ); auto_ik.Init( pStudioHdr, GetAbsAngles(), GetAbsOrigin(), gpGlobals->curtime, m_iIKCounter, boneMask );
boneSetup.CalcAutoplaySequences( pos, q, gpGlobals->curtime, &auto_ik ); boneSetup.CalcAutoplaySequences( pos, q, gpGlobals->curtime, &auto_ik );
} }
else else

View file

@ -1670,7 +1670,7 @@ void CBaseAnimating::CalculateIKLocks( float currentTime )
// FIXME: trace based on gravity or trace based on angles? // FIXME: trace based on gravity or trace based on angles?
Vector up; Vector up;
AngleVectors( GetRenderAngles(), NULL, NULL, &up ); AngleVectors( GetAbsAngles(), NULL, NULL, &up );
// FIXME: check number of slots? // FIXME: check number of slots?
float minHeight = FLT_MAX; float minHeight = FLT_MAX;
@ -1692,7 +1692,7 @@ void CBaseAnimating::CalculateIKLocks( float currentTime )
Vector p1, p2; Vector p1, p2;
// adjust ground to original ground position // adjust ground to original ground position
estGround = (pTarget->est.pos - GetRenderOrigin()); estGround = (pTarget->est.pos - GetAbsOrigin());
estGround = estGround - (estGround * up) * up; estGround = estGround - (estGround * up) * up;
estGround = GetAbsOrigin() + estGround + pTarget->est.floor * up; estGround = GetAbsOrigin() + estGround + pTarget->est.floor * up;
@ -1781,7 +1781,7 @@ void CBaseAnimating::CalculateIKLocks( float currentTime )
else if (trace.DidHitNonWorldEntity()) else if (trace.DidHitNonWorldEntity())
{ {
pTarget->SetPos( trace.endpos ); pTarget->SetPos( trace.endpos );
pTarget->SetAngles( GetRenderAngles() ); pTarget->SetAngles( GetAbsAngles() );
// only do this on forward tracking or commited IK ground rules // only do this on forward tracking or commited IK ground rules
if (pTarget->est.release < 0.1) if (pTarget->est.release < 0.1)
@ -1815,7 +1815,7 @@ void CBaseAnimating::CalculateIKLocks( float currentTime )
else else
{ {
pTarget->SetPos( trace.endpos ); pTarget->SetPos( trace.endpos );
pTarget->SetAngles( GetRenderAngles() ); pTarget->SetAngles( GetAbsAngles() );
pTarget->SetOnWorld( true ); pTarget->SetOnWorld( true );
} }
} }
@ -2031,7 +2031,7 @@ void CBaseAnimating::SetupBones( matrix3x4_t *pBoneToWorld, int boneMask )
// FIXME: pass this into Studio_BuildMatrices to skip transforms // FIXME: pass this into Studio_BuildMatrices to skip transforms
CBoneBitList boneComputed; CBoneBitList boneComputed;
m_iIKCounter++; m_iIKCounter++;
m_pIk->Init( pStudioHdr, GetRenderAngles(), adjOrigin, gpGlobals->curtime, m_iIKCounter, boneMask ); m_pIk->Init( pStudioHdr, GetAbsAngles(), adjOrigin, gpGlobals->curtime, m_iIKCounter, boneMask );
GetSkeleton( pStudioHdr, pos, q, boneMask ); GetSkeleton( pStudioHdr, pos, q, boneMask );
UpdateIKLocks( gpGlobals->curtime ); UpdateIKLocks( gpGlobals->curtime );
@ -2055,7 +2055,7 @@ void CBaseAnimating::SetupBones( matrix3x4_t *pBoneToWorld, int boneMask )
{ {
BuildMatricesWithBoneMerge( BuildMatricesWithBoneMerge(
pStudioHdr, pStudioHdr,
GetRenderAngles(), GetAbsAngles(),
adjOrigin, adjOrigin,
pos, pos,
q, q,
@ -2074,7 +2074,7 @@ void CBaseAnimating::SetupBones( matrix3x4_t *pBoneToWorld, int boneMask )
Studio_BuildMatrices( Studio_BuildMatrices(
pStudioHdr, pStudioHdr,
GetRenderAngles(), GetAbsAngles(),
adjOrigin, adjOrigin,
pos, pos,
q, q,
@ -3036,7 +3036,7 @@ void CBaseAnimating::GetSkeleton( CStudioHdr *pStudioHdr, Vector pos[], Quaterni
if ( m_pIk ) if ( m_pIk )
{ {
CIKContext auto_ik; CIKContext auto_ik;
auto_ik.Init( pStudioHdr, GetRenderAngles(), GetAbsOrigin(), gpGlobals->curtime, m_iIKCounter, boneMask ); auto_ik.Init( pStudioHdr, GetAbsAngles(), GetAbsOrigin(), gpGlobals->curtime, m_iIKCounter, boneMask );
boneSetup.CalcAutoplaySequences( pos, q, gpGlobals->curtime, &auto_ik ); boneSetup.CalcAutoplaySequences( pos, q, gpGlobals->curtime, &auto_ik );
} }
else else

View file

@ -426,8 +426,6 @@ public:
bool IsCurrentlyTouching( void ) const; bool IsCurrentlyTouching( void ) const;
const Vector& GetAbsOrigin( void ) const; const Vector& GetAbsOrigin( void ) const;
const QAngle& GetAbsAngles( void ) const; const QAngle& GetAbsAngles( void ) const;
virtual const Vector& GetRenderOrigin( void ) const { return GetAbsOrigin(); }
virtual const QAngle& GetRenderAngles( void ) const { return GetAbsAngles(); }
SolidType_t GetSolid() const; SolidType_t GetSolid() const;
int GetSolidFlags( void ) const; int GetSolidFlags( void ) const;

View file

@ -302,7 +302,6 @@ IMPLEMENT_SERVERCLASS_ST( CCSPlayer, DT_CSPlayer )
SendPropInt( SENDINFO( m_iClass ), Q_log2( CS_NUM_CLASSES )+1, SPROP_UNSIGNED ), SendPropInt( SENDINFO( m_iClass ), Q_log2( CS_NUM_CLASSES )+1, SPROP_UNSIGNED ),
SendPropInt( SENDINFO( m_ArmorValue ), 8 ), SendPropInt( SENDINFO( m_ArmorValue ), 8 ),
SendPropQAngles(SENDINFO(m_angEyeAngles)), SendPropQAngles(SENDINFO(m_angEyeAngles)),
SendPropQAngles(SENDINFO(m_angRenderAngles)),
SendPropBool( SENDINFO( m_bHasDefuser ) ), SendPropBool( SENDINFO( m_bHasDefuser ) ),
SendPropBool( SENDINFO( m_bNightVisionOn ) ), //send as int so we can use a RecvProxy on the client SendPropBool( SENDINFO( m_bNightVisionOn ) ), //send as int so we can use a RecvProxy on the client
SendPropBool( SENDINFO( m_bHasNightVision ) ), SendPropBool( SENDINFO( m_bHasNightVision ) ),
@ -1164,7 +1163,7 @@ void CCSPlayer::Event_Killed( const CTakeDamageInfo &info )
{ {
if ( RandomInt( 0, 100 ) < 20 ) if ( RandomInt( 0, 100 ) < 20 )
{ {
CHolidayGift::Create( WorldSpaceCenter(), GetRenderAngles(), EyeAngles(), GetAbsVelocity(), this ); CHolidayGift::Create( WorldSpaceCenter(), GetAbsAngles(), EyeAngles(), GetAbsVelocity(), this );
} }
} }
@ -1455,7 +1454,7 @@ void CCSPlayer::UpdateRadar()
WRITE_SBITLONG( pPlayer->GetAbsOrigin().x/4, COORD_INTEGER_BITS-1 ); WRITE_SBITLONG( pPlayer->GetAbsOrigin().x/4, COORD_INTEGER_BITS-1 );
WRITE_SBITLONG( pPlayer->GetAbsOrigin().y/4, COORD_INTEGER_BITS-1 ); WRITE_SBITLONG( pPlayer->GetAbsOrigin().y/4, COORD_INTEGER_BITS-1 );
WRITE_SBITLONG( pPlayer->GetAbsOrigin().z/4, COORD_INTEGER_BITS-1 ); WRITE_SBITLONG( pPlayer->GetAbsOrigin().z/4, COORD_INTEGER_BITS-1 );
WRITE_SBITLONG( AngleNormalize( pPlayer->GetRenderAngles().y ), 9 ); WRITE_SBITLONG( AngleNormalize( pPlayer->GetAbsAngles().y ), 9 );
} }
WRITE_BYTE( 0 ); // end marker WRITE_BYTE( 0 ); // end marker
@ -1584,7 +1583,8 @@ void CCSPlayer::PostThink()
m_PlayerAnimState->Update( m_angEyeAngles[YAW], m_angEyeAngles[PITCH] ); m_PlayerAnimState->Update( m_angEyeAngles[YAW], m_angEyeAngles[PITCH] );
m_angRenderAngles = m_PlayerAnimState->GetRenderAngles(); // Use the m_angRotation instead.
SetAbsAngles( m_PlayerAnimState->GetRenderAngles() );
// check if we need to apply a deafness DSP effect. // check if we need to apply a deafness DSP effect.
if ((m_applyDeafnessTime != 0.0f) && (m_applyDeafnessTime <= gpGlobals->curtime)) if ((m_applyDeafnessTime != 0.0f) && (m_applyDeafnessTime <= gpGlobals->curtime))
@ -2780,7 +2780,7 @@ void CCSPlayer::DropShield( void )
#ifdef CS_SHIELD_ENABLED #ifdef CS_SHIELD_ENABLED
//Drop an item_defuser //Drop an item_defuser
Vector vForward, vRight; Vector vForward, vRight;
AngleVectors( GetRenderAngles(), &vForward, &vRight, NULL ); AngleVectors( GetAbsAngles(), &vForward, &vRight, NULL );
RemoveShield(); RemoveShield();
@ -6719,7 +6719,7 @@ void CCSPlayer::DropWeapons( bool fromDeath, bool friendlyFire )
{ {
//Drop an item_defuser //Drop an item_defuser
Vector vForward, vRight; Vector vForward, vRight;
AngleVectors( GetRenderAngles(), &vForward, &vRight, NULL ); AngleVectors( GetAbsAngles(), &vForward, &vRight, NULL );
CBaseAnimating *pDefuser = (CBaseAnimating *)CBaseEntity::Create( "item_defuser", WorldSpaceCenter(), GetLocalAngles(), this ); CBaseAnimating *pDefuser = (CBaseAnimating *)CBaseEntity::Create( "item_defuser", WorldSpaceCenter(), GetLocalAngles(), this );
pDefuser->ApplyAbsVelocityImpulse( vForward * 200 + vRight * random->RandomFloat( -50, 50 ) ); pDefuser->ApplyAbsVelocityImpulse( vForward * 200 + vRight * random->RandomFloat( -50, 50 ) );

View file

@ -288,8 +288,6 @@ public:
virtual int GetNextObserverSearchStartPoint( bool bReverse ); virtual int GetNextObserverSearchStartPoint( bool bReverse );
virtual const QAngle& GetRenderAngles( void ) const { return m_angRenderAngles; }
// In shared code. // In shared code.
public: public:
@ -816,7 +814,6 @@ public:
// Copyed from EyeAngles() so we can send it to the client. // Copyed from EyeAngles() so we can send it to the client.
CNetworkQAngle( m_angEyeAngles ); CNetworkQAngle( m_angEyeAngles );
CNetworkQAngle( m_angRenderAngles );
bool m_bVCollisionInitted; bool m_bVCollisionInitted;

View file

@ -7,11 +7,15 @@
#ifndef ILAGCOMPENSATIONMANAGER_H #ifndef ILAGCOMPENSATIONMANAGER_H
#define ILAGCOMPENSATIONMANAGER_H #define ILAGCOMPENSATIONMANAGER_H
#ifdef _WIN32 #ifdef _WIN32
#pragma once #pragma once
#endif #endif
#include "platform.h"
class CBasePlayer; class CBasePlayer;
class CBaseEntity;
class CUserCmd; class CUserCmd;
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -19,12 +23,10 @@ class CUserCmd;
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
abstract_class ILagCompensationManager abstract_class ILagCompensationManager
{ {
public: public:
// Called during player movement to set up/restore after lag compensation // Called during player movement to set up/restore after lag compensation
virtual void StartLagCompensation( CBasePlayer *player, CUserCmd *cmd ) = 0; virtual void StartLagCompensation( CBasePlayer* player, CUserCmd* cmd ) = 0;
virtual void FinishLagCompensation(CBasePlayer *player) = 0; virtual void FinishLagCompensation( CBasePlayer* player ) = 0;
virtual void BacktrackPlayer( CBasePlayer *player, CUserCmd *cmd ) = 0;
virtual void TrackPlayerData( CBasePlayer *pPlayer ) = 0;
}; };
extern ILagCompensationManager *lagcompensation; extern ILagCompensationManager *lagcompensation;

View file

@ -746,12 +746,17 @@ static void NormalizeAngles( QAngle& angles )
} }
} }
bool CBasePlayer::WantsLagCompensationOnEntity( const CBasePlayer *pPlayer, const CUserCmd *pCmd, const CBitVec<MAX_EDICTS> *pEntityTransmitBits ) bool CBasePlayer::WantsLagCompensationOnEntity( const CBaseEntity *pEntity, const CUserCmd *pCmd, const CBitVec<MAX_EDICTS> *pEntityTransmitBits )
{ {
// Team members shouldn't be adjusted unless friendly fire is on. // Team members shouldn't be adjusted unless friendly fire is on.
if ( !friendlyfire.GetInt() && pPlayer->GetTeamNumber() == GetTeamNumber() ) if ( !friendlyfire.GetInt() && pEntity->GetTeamNumber() == GetTeamNumber() )
return false; return false;
if ( pEntity->GetOwnerEntity() == this )
{
return false;
}
// NOTE: Do not check for this, it is possible to knife from behind in CS:S // NOTE: Do not check for this, it is possible to knife from behind in CS:S
// Vector vShootPosition = Weapon_ShootPosition(); // Vector vShootPosition = Weapon_ShootPosition();
// const Vector &vHisOrigin = pPlayer->GetAbsOrigin(); // const Vector &vHisOrigin = pPlayer->GetAbsOrigin();
@ -7929,12 +7934,12 @@ void CMovementSpeedMod::InputSpeedMod(inputdata_t &data)
// If HL2_DLL is defined, then baseflex.cpp already sends these. // If HL2_DLL is defined, then baseflex.cpp already sends these.
#ifndef HL2_DLL #ifndef HL2_DLL
SendPropFloat ( SENDINFO_VECTORELEM(m_vecViewOffset, 0), -1, 0, -32.0, 32.0f), SendPropFloat ( SENDINFO_VECTORELEM(m_vecViewOffset, 0)),
SendPropFloat ( SENDINFO_VECTORELEM(m_vecViewOffset, 1), -1, 0, -32.0, 32.0f), SendPropFloat ( SENDINFO_VECTORELEM(m_vecViewOffset, 1)),
SendPropFloat ( SENDINFO_VECTORELEM(m_vecViewOffset, 2), -1, 0, 0.0f, 256.0f), SendPropFloat ( SENDINFO_VECTORELEM(m_vecViewOffset, 2)),
#endif #endif
SendPropFloat ( SENDINFO(m_flFriction), 8, SPROP_ROUNDDOWN, 0.0f, 4.0f), SendPropFloat ( SENDINFO(m_flFriction) ),
SendPropArray3 ( SENDINFO_ARRAY3(m_iAmmo), SendPropInt( SENDINFO_ARRAY(m_iAmmo), -1, SPROP_VARINT | SPROP_UNSIGNED ) ), SendPropArray3 ( SENDINFO_ARRAY3(m_iAmmo), SendPropInt( SENDINFO_ARRAY(m_iAmmo), -1, SPROP_VARINT | SPROP_UNSIGNED ) ),
@ -7956,7 +7961,7 @@ void CMovementSpeedMod::InputSpeedMod(inputdata_t &data)
SendPropVector ( SENDINFO( m_vecBaseVelocity ), -1, SPROP_NOSCALE ), SendPropVector ( SENDINFO( m_vecBaseVelocity ), -1, SPROP_NOSCALE ),
#endif #endif
SendPropEHandle ( SENDINFO( m_hConstraintEntity)), SendPropEHandle ( SENDINFO( m_hConstraintEntity )),
SendPropVector ( SENDINFO( m_vecConstraintCenter), 0, SPROP_NOSCALE ), SendPropVector ( SENDINFO( m_vecConstraintCenter), 0, SPROP_NOSCALE ),
SendPropFloat ( SENDINFO( m_flConstraintRadius ), 0, SPROP_NOSCALE ), SendPropFloat ( SENDINFO( m_flConstraintRadius ), 0, SPROP_NOSCALE ),
SendPropFloat ( SENDINFO( m_flConstraintWidth ), 0, SPROP_NOSCALE ), SendPropFloat ( SENDINFO( m_flConstraintWidth ), 0, SPROP_NOSCALE ),

View file

@ -6,6 +6,7 @@
#ifndef PLAYER_H #ifndef PLAYER_H
#define PLAYER_H #define PLAYER_H
#include "baseentity.h"
#ifdef _WIN32 #ifdef _WIN32
#pragma once #pragma once
#endif #endif
@ -282,7 +283,7 @@ public:
// Returns true if this player wants pPlayer to be moved back in time when this player runs usercmds. // Returns true if this player wants pPlayer to be moved back in time when this player runs usercmds.
// Saves a lot of overhead on the server if we can cull out entities that don't need to lag compensate // Saves a lot of overhead on the server if we can cull out entities that don't need to lag compensate
// (like team members, entities out of our PVS, etc). // (like team members, entities out of our PVS, etc).
virtual bool WantsLagCompensationOnEntity( const CBasePlayer *pPlayer, const CUserCmd *pCmd, const CBitVec<MAX_EDICTS> *pEntityTransmitBits ); virtual bool WantsLagCompensationOnEntity( const CBaseEntity *pEntity, const CUserCmd *pCmd, const CBitVec<MAX_EDICTS> *pEntityTransmitBits );
virtual void Spawn( void ); virtual void Spawn( void );
virtual void Activate( void ); virtual void Activate( void );

View file

@ -308,8 +308,12 @@ void CPlayerMove::RunPostThink( CBasePlayer *player )
{ {
VPROF( "CPlayerMove::RunPostThink" ); VPROF( "CPlayerMove::RunPostThink" );
lagcompensation->StartLagCompensation( player, player->GetCurrentCommand() );
// Run post-think // Run post-think
player->PostThink(); player->PostThink();
lagcompensation->FinishLagCompensation( player );
} }
void CommentarySystem_PePlayerRunCommand( CBasePlayer *player, CUserCmd *ucmd ); void CommentarySystem_PePlayerRunCommand( CBasePlayer *player, CUserCmd *ucmd );
@ -467,6 +471,4 @@ void CPlayerMove::RunCommand ( CBasePlayer *player, CUserCmd *ucmd, IMoveHelper
{ {
player->m_nTickBase++; player->m_nTickBase++;
} }
lagcompensation->TrackPlayerData( player );
} }

View file

@ -6,9 +6,6 @@
//=============================================================================// //=============================================================================//
#include "cbase.h" #include "cbase.h"
#ifdef CSTRIKE_DLL
#include "cs_player.h"
#endif
#include "icvar.h" #include "icvar.h"
#include "player.h" #include "player.h"
#include "shareddefs.h" #include "shareddefs.h"
@ -34,9 +31,10 @@
#define LC_ANIMATION_CHANGED ( 1 << 11 ) #define LC_ANIMATION_CHANGED ( 1 << 11 )
#define LC_POSE_PARAMS_CHANGED ( 1 << 12 ) #define LC_POSE_PARAMS_CHANGED ( 1 << 12 )
#define LC_ENCD_CONS_CHANGED ( 1 << 13 ) #define LC_ENCD_CONS_CHANGED ( 1 << 13 )
#define LC_ANIM_OVERS_CHANGED ( 1 << 14 )
// Default to 1 second max. // Default to 1 second max.
#define MAX_TICKS_SAVED 1000 #define MAX_TICKS_SAVED 1024
ConVar sv_unlag( "sv_unlag", "1", FCVAR_DEVELOPMENTONLY, "Enables player lag compensation" ); ConVar sv_unlag( "sv_unlag", "1", FCVAR_DEVELOPMENTONLY, "Enables player lag compensation" );
// Enable by default to avoid some bugs. // Enable by default to avoid some bugs.
@ -53,84 +51,11 @@ struct LayerRecord
float m_weight; float m_weight;
int m_order; int m_order;
int m_flags; int m_flags;
LayerRecord()
{
m_sequence = 0;
m_cycle = 0;
m_weight = 0;
m_order = 0;
m_flags = 0;
}
}; };
struct LagRecord struct LagRecord
{ {
public: public:
LagRecord()
{
m_fFlags = LC_NONE;
m_vecOrigin.Init();
m_vecAngles.Init();
m_vecMinsPreScaled.Init();
m_vecMaxsPreScaled.Init();
m_flSimulationTime = -1;
m_flAnimTime = -1;
m_masterSequence = 0;
m_masterCycle = 0;
for ( int layerIndex = 0; layerIndex < MAX_LAYER_RECORDS; ++layerIndex )
{
m_layerRecords[layerIndex] = {};
}
for ( int i = 0; i < MAXSTUDIOPOSEPARAM; i++ )
{
m_poseParameters[i] = 0;
}
for ( int i = 0; i < MAXSTUDIOBONECTRLS; i++ )
{
m_encodedControllers[i] = 0;
}
#ifdef CSTRIKE_DLL
m_angRenderAngles.Init();
#endif
}
LagRecord( const LagRecord& src )
{
m_fFlags = src.m_fFlags;
m_vecOrigin = src.m_vecOrigin;
m_vecAngles = src.m_vecAngles;
m_vecMinsPreScaled = src.m_vecMinsPreScaled;
m_vecMaxsPreScaled = src.m_vecMaxsPreScaled;
m_flSimulationTime = src.m_flSimulationTime;
m_flAnimTime = src.m_flAnimTime;
for ( int layerIndex = 0; layerIndex < MAX_LAYER_RECORDS; ++layerIndex )
{
m_layerRecords[layerIndex] = src.m_layerRecords[layerIndex];
}
m_masterSequence = src.m_masterSequence;
m_masterCycle = src.m_masterCycle;
for ( int i = 0; i < MAXSTUDIOPOSEPARAM; i++ )
{
m_poseParameters[i] = src.m_poseParameters[i];
}
for ( int i = 0; i < MAXSTUDIOBONECTRLS; i++ )
{
m_encodedControllers[i] = src.m_encodedControllers[i];
}
#ifdef CSTRIKE_DLL
m_angRenderAngles = src.m_angRenderAngles;
#endif
}
// Did player die this frame // Did player die this frame
int m_fFlags; int m_fFlags;
@ -149,9 +74,6 @@ struct LagRecord
float m_masterCycle; float m_masterCycle;
float m_poseParameters[MAXSTUDIOPOSEPARAM]; float m_poseParameters[MAXSTUDIOPOSEPARAM];
float m_encodedControllers[MAXSTUDIOBONECTRLS]; float m_encodedControllers[MAXSTUDIOBONECTRLS];
#ifdef CSTRIKE_DLL
QAngle m_angRenderAngles;
#endif
}; };
// //
@ -163,28 +85,28 @@ ConVar sv_unlag_debug( "sv_unlag_debug", "0" );
float g_flFractionScale = 0.95; float g_flFractionScale = 0.95;
static void RestorePlayerTo( CBasePlayer* pPlayer, const Vector& vWantedPos ) static void RestorePlayerTo( CBaseEntity* pEntity, const Vector& vWantedPos )
{ {
// Try to move to the wanted position from our current position. // Try to move to the wanted position from our current position.
trace_t tr; trace_t tr;
VPROF_BUDGET( "RestorePlayerTo", "CLagCompensationManager" ); VPROF_BUDGET( "RestorePlayerTo", "CLagCompensationManager" );
UTIL_TraceEntity( pPlayer, vWantedPos, vWantedPos, MASK_PLAYERSOLID, pPlayer, COLLISION_GROUP_PLAYER_MOVEMENT, &tr ); UTIL_TraceEntity( pEntity, vWantedPos, vWantedPos, MASK_PLAYERSOLID, pEntity->GetRefEHandle().Get(), COLLISION_GROUP_PLAYER_MOVEMENT, &tr );
if ( tr.startsolid || tr.allsolid ) if ( tr.startsolid || tr.allsolid )
{ {
if ( sv_unlag_debug.GetBool() ) if ( sv_unlag_debug.GetBool() )
{ {
DevMsg( "RestorePlayerTo() could not restore player position for client \"%s\" ( %.1f %.1f %.1f )\n", DevMsg( "RestorePlayerTo() could not restore player position for client \"%i\" ( %.1f %.1f %.1f )\n",
pPlayer->GetPlayerName(), pEntity->entindex(),
vWantedPos.x, vWantedPos.x,
vWantedPos.y, vWantedPos.y,
vWantedPos.z ); vWantedPos.z );
} }
UTIL_TraceEntity( pPlayer, UTIL_TraceEntity( pEntity,
pPlayer->GetAbsOrigin(), pEntity->GetAbsOrigin(),
vWantedPos, vWantedPos,
MASK_PLAYERSOLID, MASK_PLAYERSOLID,
pPlayer, pEntity->GetRefEHandle().Get(),
COLLISION_GROUP_PLAYER_MOVEMENT, COLLISION_GROUP_PLAYER_MOVEMENT,
&tr ); &tr );
if ( tr.startsolid || tr.allsolid ) if ( tr.startsolid || tr.allsolid )
@ -200,8 +122,8 @@ static void RestorePlayerTo( CBasePlayer* pPlayer, const Vector& vWantedPos )
{ {
// We can get to a valid place, but not all the way back to where we were. // We can get to a valid place, but not all the way back to where we were.
Vector vPos; Vector vPos;
VectorLerp( pPlayer->GetAbsOrigin(), vWantedPos, tr.fraction * g_flFractionScale, vPos ); VectorLerp( pEntity->GetAbsOrigin(), vWantedPos, tr.fraction * g_flFractionScale, vPos );
UTIL_SetOrigin( pPlayer, vPos, true ); UTIL_SetOrigin( pEntity, vPos, true );
if ( sv_unlag_debug.GetBool() ) if ( sv_unlag_debug.GetBool() )
{ {
@ -212,7 +134,7 @@ static void RestorePlayerTo( CBasePlayer* pPlayer, const Vector& vWantedPos )
else else
{ {
// Cool, the player can go back to whence he came. // Cool, the player can go back to whence he came.
UTIL_SetOrigin( pPlayer, tr.endpos, true ); UTIL_SetOrigin( pEntity, tr.endpos, true );
} }
} }
@ -228,12 +150,12 @@ class CLagCompensationManager : public CAutoGameSystemPerFrame,
} }
// IServerSystem stuff // IServerSystem stuff
virtual void Shutdown() void Shutdown() override
{ {
ClearHistory(); ClearHistory();
} }
virtual void LevelShutdownPostEntity() void LevelShutdownPostEntity() override
{ {
ClearHistory(); ClearHistory();
} }
@ -241,12 +163,10 @@ class CLagCompensationManager : public CAutoGameSystemPerFrame,
// ILagCompensationManager stuff // ILagCompensationManager stuff
// Called during player movement to set up/restore after lag compensation // Called during player movement to set up/restore after lag compensation
void StartLagCompensation( CBasePlayer* player, CUserCmd* cmd ); void StartLagCompensation( CBasePlayer* player, CUserCmd* cmd ) override;
void FinishLagCompensation( CBasePlayer* player ); void FinishLagCompensation( CBasePlayer* player ) override;
virtual void TrackPlayerData( CBasePlayer* pPlayer ); void TrackEntities( void );
inline void BacktrackEntity( CBaseEntity* pEntity, int loopIndex, CUserCmd* cmd );
private:
void BacktrackPlayer( CBasePlayer* player, CUserCmd* cmd );
void ClearHistory() void ClearHistory()
{ {
@ -256,11 +176,16 @@ class CLagCompensationManager : public CAutoGameSystemPerFrame,
} }
} }
void FrameUpdatePostEntityThink() override
{
TrackEntities();
}
// keep a list of lag records for each entities // keep a list of lag records for each entities
CUtlCircularBuffer< LagRecord, MAX_TICKS_SAVED > m_EntityTrack[MAX_EDICTS]; CUtlCircularBuffer< LagRecord, MAX_TICKS_SAVED > m_EntityTrack[MAX_EDICTS];
// Scratchpad for determining what needs to be restored // Scratchpad for determining what needs to be restored
CBitVec< MAX_EDICTS > m_RestorePlayer; CBitVec< MAX_EDICTS > m_RestoreEntity;
bool m_bNeedToRestore; bool m_bNeedToRestore;
LagRecord m_RestoreData[MAX_EDICTS]; // entities data before we moved him back LagRecord m_RestoreData[MAX_EDICTS]; // entities data before we moved him back
@ -273,92 +198,95 @@ ILagCompensationManager* lagcompensation = &g_LagCompensationManager;
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Purpose: Called once per frame after all entities have had a chance to think // Purpose: Called once per frame after all entities have had a chance to think
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void CLagCompensationManager::TrackPlayerData( CBasePlayer* pPlayer ) void CLagCompensationManager::TrackEntities()
{ {
if ( ( gpGlobals->maxClients <= 1 ) || !sv_unlag.GetBool() ) LagRecord record;
if ( !sv_unlag.GetBool() )
{ {
ClearHistory(); ClearHistory();
return; return;
} }
VPROF_BUDGET( "TrackPlayerData", "CLagCompensationManager" ); VPROF_BUDGET( "TrackEntities", "CLagCompensationManager" );
// remove all records before that time: for ( int i = 0; i < MAX_EDICTS; i++ )
auto track = &m_EntityTrack[pPlayer->entindex()];
// add new record to player track
LagRecord record;
record.m_fFlags = LC_NONE;
if ( pPlayer->IsAlive() )
{ {
record.m_fFlags |= LC_ALIVE; CBaseEntity* pEntity = UTIL_EntityByIndex( i );
}
record.m_flSimulationTime = pPlayer->GetSimulationTime(); if ( !pEntity )
record.m_flAnimTime = pPlayer->GetAnimTime();
record.m_vecAngles = pPlayer->GetAbsAngles();
record.m_vecOrigin = pPlayer->GetAbsOrigin();
record.m_vecMinsPreScaled = pPlayer->CollisionProp()->OBBMinsPreScaled();
record.m_vecMaxsPreScaled = pPlayer->CollisionProp()->OBBMaxsPreScaled();
int layerCount = pPlayer->GetNumAnimOverlays();
for ( int layerIndex = 0; layerIndex < layerCount; ++layerIndex )
{
CAnimationLayer* currentLayer = pPlayer->GetAnimOverlay( layerIndex );
if ( currentLayer )
{ {
record.m_layerRecords[layerIndex].m_cycle = currentLayer->m_flCycle; continue;
record.m_layerRecords[layerIndex].m_order = currentLayer->m_nOrder;
record.m_layerRecords[layerIndex].m_sequence = currentLayer->m_nSequence;
record.m_layerRecords[layerIndex].m_weight = currentLayer->m_flWeight;
record.m_layerRecords[layerIndex].m_flags = currentLayer->m_fFlags;
} }
}
record.m_masterSequence = pPlayer->GetSequence(); // remove all records before that time:
record.m_masterCycle = pPlayer->GetCycle(); auto track = &m_EntityTrack[i];
CStudioHdr* hdr = pPlayer->GetModelPtr(); // add new record to player track
if ( hdr ) record.m_fFlags = LC_NONE;
{ record.m_flSimulationTime = pEntity->GetSimulationTime();
for ( int paramIndex = 0; paramIndex < hdr->GetNumPoseParameters(); paramIndex++ ) record.m_flAnimTime = pEntity->GetAnimTime();
record.m_vecAngles = pEntity->GetAbsAngles();
record.m_vecOrigin = pEntity->GetAbsOrigin();
record.m_vecMinsPreScaled = pEntity->CollisionProp()->OBBMinsPreScaled();
record.m_vecMaxsPreScaled = pEntity->CollisionProp()->OBBMaxsPreScaled();
auto pAnim = dynamic_cast< CBaseAnimating* >( pEntity );
if ( pAnim )
{ {
record.m_poseParameters[paramIndex] = pPlayer->GetPoseParameterArray()[paramIndex]; record.m_masterSequence = pAnim->GetSequence();
} record.m_masterCycle = pAnim->GetCycle();
}
if ( hdr ) CStudioHdr* hdr = pAnim->GetModelPtr();
{
for ( int boneIndex = 0; boneIndex < hdr->GetNumBoneControllers(); boneIndex++ ) if ( hdr )
{
for ( int paramIndex = 0; paramIndex < hdr->GetNumPoseParameters(); paramIndex++ )
{
record.m_poseParameters[paramIndex] = pAnim->GetPoseParameterArray()[paramIndex];
}
for ( int boneIndex = 0; boneIndex < hdr->GetNumBoneControllers(); boneIndex++ )
{
record.m_encodedControllers[boneIndex] = pAnim->GetBoneControllerArray()[boneIndex];
}
}
}
auto pAnimOverlay = dynamic_cast< CBaseAnimatingOverlay* >( pEntity );
if ( pAnimOverlay )
{ {
record.m_encodedControllers[boneIndex] = pPlayer->GetBoneControllerArray()[boneIndex]; int layerCount = pAnimOverlay->GetNumAnimOverlays();
for ( int layerIndex = 0; layerIndex < layerCount; ++layerIndex )
{
CAnimationLayer* currentLayer = pAnimOverlay->GetAnimOverlay( layerIndex );
if ( currentLayer )
{
record.m_layerRecords[layerIndex].m_cycle = currentLayer->m_flCycle;
record.m_layerRecords[layerIndex].m_order = currentLayer->m_nOrder;
record.m_layerRecords[layerIndex].m_sequence = currentLayer->m_nSequence;
record.m_layerRecords[layerIndex].m_weight = currentLayer->m_flWeight;
record.m_layerRecords[layerIndex].m_flags = currentLayer->m_fFlags;
}
}
} }
track->Push( record );
} }
#ifdef CSTRIKE_DLL
const auto csPlayer = ToCSPlayer( pPlayer );
if ( csPlayer )
{
record.m_angRenderAngles = csPlayer->m_angRenderAngles;
}
#endif
track->Push( record );
} }
// Called during player movement to set up/restore after lag compensation // Called during player movement to set up/restore after lag compensation
void CLagCompensationManager::StartLagCompensation( CBasePlayer* player, CUserCmd* cmd ) void CLagCompensationManager::StartLagCompensation( CBasePlayer* player, CUserCmd* cmd )
{ {
// Assume no players need to be restored // Assume no players need to be restored
m_RestorePlayer.ClearAll(); m_RestoreEntity.ClearAll();
m_bNeedToRestore = false; m_bNeedToRestore = false;
if ( !player->m_bLagCompensation // Player not wanting lag compensation if ( !player->m_bLagCompensation // Player not wanting lag compensation
|| ( gpGlobals->maxClients <= 1 ) // no lag compensation in single player
|| !sv_unlag.GetBool() // disabled by server admin || !sv_unlag.GetBool() // disabled by server admin
|| player->IsBot() // not for bots || player->IsBot() // not for bots
|| player->IsObserver() // not for spectators || player->IsObserver() // not for spectators
@ -374,56 +302,62 @@ void CLagCompensationManager::StartLagCompensation( CBasePlayer* player, CUserCm
// Iterate all active players // Iterate all active players
const CBitVec< MAX_EDICTS >* pEntityTransmitBits = engine->GetEntityTransmitBitsForClient( player->entindex() - 1 ); const CBitVec< MAX_EDICTS >* pEntityTransmitBits = engine->GetEntityTransmitBitsForClient( player->entindex() - 1 );
for ( int i = 1; i <= gpGlobals->maxClients; i++ )
{
CBasePlayer* pPlayer = UTIL_PlayerByIndex( i );
if ( !pPlayer ) for ( int i = 0; i < MAX_EDICTS; i++ )
{
CBaseEntity* pEntity = UTIL_EntityByIndex( i );
if ( !pEntity )
{ {
continue; continue;
} }
// Don't lag compensate yourself you loser... // Don't lag compensate yourself you loser...
if ( player == pPlayer ) if ( player->entindex() == pEntity->entindex() )
{ {
continue; continue;
} }
// Custom checks for if things should lag compensate (based on things like what team the player is on). // Custom checks for if things should lag compensate (based on things like what team the player is on).
if ( !player->WantsLagCompensationOnEntity( pPlayer, cmd, pEntityTransmitBits ) ) if ( !player->WantsLagCompensationOnEntity( pEntity, cmd, pEntityTransmitBits ) )
{ {
continue; continue;
} }
// Move other player back in time // Move other player back in time
BacktrackPlayer( pPlayer, cmd ); BacktrackEntity( pEntity, i, cmd );
} }
} }
void CLagCompensationManager::BacktrackPlayer( CBasePlayer* pPlayer, CUserCmd* cmd ) inline void CLagCompensationManager::BacktrackEntity( CBaseEntity* pEntity, int loopindex, CUserCmd* cmd )
{ {
VPROF_BUDGET( "BacktrackPlayer", "CLagCompensationManager" ); VPROF_BUDGET( "BacktrackEntity", "CLagCompensationManager" );
Vector org; Vector org;
Vector minsPreScaled; Vector minsPreScaled;
Vector maxsPreScaled; Vector maxsPreScaled;
QAngle ang; QAngle ang;
#ifdef CSTRIKE_DLL
QAngle renderAngles;
#endif
LagRecord* prevRecordSim; LagRecord* prevRecordSim;
LagRecord* recordSim; LagRecord* recordSim;
LagRecord* recordAnim; LagRecord* recordAnim;
#ifdef CSTRIKE_DLL int pl_index = loopindex;
auto csPlayer = ToCSPlayer( pPlayer );
#endif
int pl_index = pPlayer->entindex();
float flTargetSimTime = cmd->simulationdata[pl_index].sim_time; float flTargetSimTime = cmd->simulationdata[pl_index].sim_time;
float flTargetAnimTime = cmd->simulationdata[pl_index].anim_time; float flTargetAnimTime = cmd->simulationdata[pl_index].anim_time;
// Somehow the client didn't care.
if (flTargetSimTime == 0)
{
if ( sv_unlag_debug.GetBool() )
{
DevMsg( "Client has refused to lag compensate this entity, probably already predicted ( %i )\n", pEntity->entindex() );
}
return;
}
// get track history of this player // get track history of this player
auto track = &m_EntityTrack[pl_index]; auto track = &m_EntityTrack[pl_index];
bool foundSim = false; bool foundSim = false;
@ -438,11 +372,6 @@ void CLagCompensationManager::BacktrackPlayer( CBasePlayer* pPlayer, CUserCmd* c
break; break;
} }
if ( !( recordSim->m_fFlags & LC_ALIVE ) )
{
break;
}
if ( flTargetSimTime == recordSim->m_flSimulationTime ) if ( flTargetSimTime == recordSim->m_flSimulationTime )
{ {
foundSim = true; foundSim = true;
@ -457,33 +386,14 @@ void CLagCompensationManager::BacktrackPlayer( CBasePlayer* pPlayer, CUserCmd* c
} }
} }
for ( int i = 0; i < MAX_TICKS_SAVED; i++ ) if ( !foundSim )
{
recordAnim = track->Get( i );
if ( !recordAnim )
{
break;
}
if ( recordAnim->m_flAnimTime == flTargetAnimTime )
{
foundAnim = true;
break;
}
}
Assert( recordAnim );
Assert( recordSim );
if ( !foundAnim || !foundSim )
{ {
if ( sv_unlag_debug.GetBool() ) if ( sv_unlag_debug.GetBool() )
{ {
DevMsg( "No valid positions in history for BacktrackPlayer client ( %s )\n", pPlayer->GetPlayerName() ); DevMsg( "No valid simulation in history for BacktrackPlayer client ( %i )\n", pEntity->entindex() );
} }
return; // that should never happen return;
} }
float fracSim = 0.0f; float fracSim = 0.0f;
@ -522,40 +432,31 @@ void CLagCompensationManager::BacktrackPlayer( CBasePlayer* pPlayer, CUserCmd* c
LagRecord* restore = &m_RestoreData[pl_index]; LagRecord* restore = &m_RestoreData[pl_index];
LagRecord* change = &m_ChangeData[pl_index]; LagRecord* change = &m_ChangeData[pl_index];
QAngle angdiff = pPlayer->GetAbsAngles() - ang; QAngle angdiff = pEntity->GetAbsAngles() - ang;
Vector orgdiff = pPlayer->GetAbsOrigin() - org; Vector orgdiff = pEntity->GetAbsOrigin() - org;
// Always remember the pristine simulation time in case we need to restore it. // Always remember the pristine simulation time in case we need to restore it.
restore->m_flSimulationTime = pPlayer->GetSimulationTime(); restore->m_flSimulationTime = pEntity->GetSimulationTime();
restore->m_flAnimTime = pPlayer->GetAnimTime(); restore->m_flAnimTime = pEntity->GetAnimTime();
#ifdef CSTRIKE_DLL
if ( csPlayer )
{
renderAngles = recordAnim->m_angRenderAngles;
restore->m_angRenderAngles = csPlayer->m_angRenderAngles;
csPlayer->m_angRenderAngles = renderAngles;
}
#endif
if ( angdiff.LengthSqr() > 0.0f ) if ( angdiff.LengthSqr() > 0.0f )
{ {
flags |= LC_ANGLES_CHANGED; flags |= LC_ANGLES_CHANGED;
restore->m_vecAngles = pPlayer->GetAbsAngles(); restore->m_vecAngles = pEntity->GetAbsAngles();
pPlayer->SetAbsAngles( ang ); pEntity->SetAbsAngles( ang );
change->m_vecAngles = ang; change->m_vecAngles = ang;
} }
// Use absolute equality here // Use absolute equality here
if ( minsPreScaled != pPlayer->CollisionProp()->OBBMinsPreScaled() if ( minsPreScaled != pEntity->CollisionProp()->OBBMinsPreScaled()
|| maxsPreScaled != pPlayer->CollisionProp()->OBBMaxsPreScaled() ) || maxsPreScaled != pEntity->CollisionProp()->OBBMaxsPreScaled() )
{ {
flags |= LC_SIZE_CHANGED; flags |= LC_SIZE_CHANGED;
restore->m_vecMinsPreScaled = pPlayer->CollisionProp()->OBBMinsPreScaled(); restore->m_vecMinsPreScaled = pEntity->CollisionProp()->OBBMinsPreScaled();
restore->m_vecMaxsPreScaled = pPlayer->CollisionProp()->OBBMaxsPreScaled(); restore->m_vecMaxsPreScaled = pEntity->CollisionProp()->OBBMaxsPreScaled();
pPlayer->SetSize( minsPreScaled, maxsPreScaled ); pEntity->SetSize( minsPreScaled, maxsPreScaled );
change->m_vecMinsPreScaled = minsPreScaled; change->m_vecMinsPreScaled = minsPreScaled;
change->m_vecMaxsPreScaled = maxsPreScaled; change->m_vecMaxsPreScaled = maxsPreScaled;
@ -565,89 +466,150 @@ void CLagCompensationManager::BacktrackPlayer( CBasePlayer* pPlayer, CUserCmd* c
if ( orgdiff.LengthSqr() > 0.0f ) if ( orgdiff.LengthSqr() > 0.0f )
{ {
flags |= LC_ORIGIN_CHANGED; flags |= LC_ORIGIN_CHANGED;
restore->m_vecOrigin = pPlayer->GetAbsOrigin(); restore->m_vecOrigin = pEntity->GetAbsOrigin();
pPlayer->SetAbsOrigin( org ); pEntity->SetAbsOrigin( org );
change->m_vecOrigin = org; change->m_vecOrigin = org;
} }
// Sorry for the loss of the optimization for the case of people auto pAnim = pEntity->GetBaseAnimating();
// standing still, but you breathe even on the server.
// This is quicker than actually comparing all bazillion floats.
flags |= LC_ANIMATION_CHANGED;
restore->m_masterSequence = pPlayer->GetSequence();
restore->m_masterCycle = pPlayer->GetCycle();
pPlayer->SetSequence( recordAnim->m_masterSequence ); auto Finish = [&]()
pPlayer->SetCycle( recordAnim->m_masterCycle );
////////////////////////
// Now do all the layers
int layerCount = pPlayer->GetNumAnimOverlays();
for ( int layerIndex = 0; layerIndex < layerCount; ++layerIndex )
{ {
CAnimationLayer* currentLayer = pPlayer->GetAnimOverlay( layerIndex ); if ( !flags )
if ( currentLayer )
{ {
restore->m_layerRecords[layerIndex].m_cycle = currentLayer->m_flCycle; return; // we didn't change anything
restore->m_layerRecords[layerIndex].m_order = currentLayer->m_nOrder; }
restore->m_layerRecords[layerIndex].m_sequence = currentLayer->m_nSequence;
restore->m_layerRecords[layerIndex].m_weight = currentLayer->m_flWeight;
restore->m_layerRecords[layerIndex].m_flags = currentLayer->m_fFlags;
currentLayer->m_flCycle = recordAnim->m_layerRecords[layerIndex].m_cycle; // Set lag compensated player's times
currentLayer->m_nOrder = recordAnim->m_layerRecords[layerIndex].m_order; pEntity->SetSimulationTime( flTargetSimTime );
currentLayer->m_nSequence = recordAnim->m_layerRecords[layerIndex].m_sequence; pEntity->SetAnimTime( flTargetAnimTime );
currentLayer->m_flWeight = recordAnim->m_layerRecords[layerIndex].m_weight;
currentLayer->m_fFlags = recordAnim->m_layerRecords[layerIndex].m_flags; if ( sv_lagflushbonecache.GetBool() )
{
if ( pAnim )
{
pAnim->InvalidateBoneCache();
}
}
m_RestoreEntity.Set( pl_index ); // remember that we changed this player
m_bNeedToRestore = true; // we changed at least one player
restore->m_fFlags = flags; // we need to restore these flags
change->m_fFlags = flags; // we have changed these flags
};
// Somehow the client didn't care.
if (flTargetAnimTime == 0)
{
if ( sv_unlag_debug.GetBool() && !pAnim )
{
DevMsg( "Client has no anim time info ( %i )\n", pEntity->entindex() );
}
Finish();
return;
}
if ( pAnim )
{
for ( int i = 0; i < MAX_TICKS_SAVED; i++ )
{
recordAnim = track->Get( i );
if ( !recordAnim )
{
break;
}
if ( recordAnim->m_flAnimTime == flTargetAnimTime )
{
foundAnim = true;
break;
}
} }
} }
flags |= LC_POSE_PARAMS_CHANGED; if ( !foundAnim )
// Now do pose parameters
CStudioHdr* hdr = pPlayer->GetModelPtr();
if ( hdr )
{ {
for ( int paramIndex = 0; paramIndex < hdr->GetNumPoseParameters(); paramIndex++ ) if ( sv_unlag_debug.GetBool() )
{ {
restore->m_poseParameters[paramIndex] = pPlayer->GetPoseParameterArray()[paramIndex]; DevMsg( "Can't lag compensate, no history for animation fpr client entity ( %i )\n", pEntity->entindex() );
float poseParameter = recordAnim->m_poseParameters[paramIndex]; }
pPlayer->SetPoseParameterRaw( paramIndex, poseParameter ); Finish();
return;
}
auto pAnimOverlay = dynamic_cast< CBaseAnimatingOverlay* >( pEntity );
if ( pAnim && foundAnim )
{
// Sorry for the loss of the optimization for the case of people
// standing still, but you breathe even on the server.
// This is quicker than actually comparing all bazillion floats.
flags |= LC_ANIMATION_CHANGED;
restore->m_masterSequence = pAnim->GetSequence();
restore->m_masterCycle = pAnim->GetCycle();
pAnim->SetSequence( recordAnim->m_masterSequence );
pAnim->SetCycle( recordAnim->m_masterCycle );
// Now do pose parameters
CStudioHdr* hdr = pAnim->GetModelPtr();
if ( hdr )
{
for ( int paramIndex = 0; paramIndex < hdr->GetNumPoseParameters(); paramIndex++ )
{
restore->m_poseParameters[paramIndex] = pAnim->GetPoseParameterArray()[paramIndex];
float poseParameter = recordAnim->m_poseParameters[paramIndex];
pAnim->SetPoseParameterRaw( paramIndex, poseParameter );
}
flags |= LC_POSE_PARAMS_CHANGED;
for ( int encIndex = 0; encIndex < hdr->GetNumBoneControllers(); encIndex++ )
{
restore->m_encodedControllers[encIndex] = pAnim->GetBoneControllerArray()[encIndex];
float encodedController = recordAnim->m_encodedControllers[encIndex];
pAnim->SetBoneControllerRaw( encIndex, encodedController );
}
flags |= LC_ENCD_CONS_CHANGED;
} }
} }
flags |= LC_ENCD_CONS_CHANGED; if ( pAnimOverlay && foundAnim )
if ( hdr )
{ {
for ( int encIndex = 0; encIndex < hdr->GetNumBoneControllers(); encIndex++ ) ////////////////////////
// Now do all the layers
int layerCount = pAnimOverlay->GetNumAnimOverlays();
for ( int layerIndex = 0; layerIndex < layerCount; ++layerIndex )
{ {
restore->m_encodedControllers[encIndex] = pPlayer->GetBoneControllerArray()[encIndex]; CAnimationLayer* currentLayer = pAnimOverlay->GetAnimOverlay( layerIndex );
float encodedController = recordAnim->m_encodedControllers[encIndex]; if ( currentLayer )
{
restore->m_layerRecords[layerIndex].m_cycle = currentLayer->m_flCycle;
restore->m_layerRecords[layerIndex].m_order = currentLayer->m_nOrder;
restore->m_layerRecords[layerIndex].m_sequence = currentLayer->m_nSequence;
restore->m_layerRecords[layerIndex].m_weight = currentLayer->m_flWeight;
restore->m_layerRecords[layerIndex].m_flags = currentLayer->m_fFlags;
pPlayer->SetBoneControllerRaw( encIndex, encodedController ); currentLayer->m_flCycle = recordAnim->m_layerRecords[layerIndex].m_cycle;
currentLayer->m_nOrder = recordAnim->m_layerRecords[layerIndex].m_order;
currentLayer->m_nSequence = recordAnim->m_layerRecords[layerIndex].m_sequence;
currentLayer->m_flWeight = recordAnim->m_layerRecords[layerIndex].m_weight;
currentLayer->m_fFlags = recordAnim->m_layerRecords[layerIndex].m_flags;
}
} }
flags |= LC_ANIM_OVERS_CHANGED;
} }
if ( !flags ) Finish();
{
return; // we didn't change anything
}
// Set lag compensated player's times
pPlayer->SetSimulationTime( flTargetSimTime );
pPlayer->SetAnimTime( flTargetAnimTime );
if ( sv_lagflushbonecache.GetBool() )
{
pPlayer->InvalidateBoneCache();
}
m_RestorePlayer.Set( pl_index ); // remember that we changed this player
m_bNeedToRestore = true; // we changed at least one player
restore->m_fFlags = flags; // we need to restore these flags
change->m_fFlags = flags; // we have changed these flags
} }
void CLagCompensationManager::FinishLagCompensation( CBasePlayer* player ) void CLagCompensationManager::FinishLagCompensation( CBasePlayer* player )
@ -662,16 +624,16 @@ void CLagCompensationManager::FinishLagCompensation( CBasePlayer* player )
} }
// Iterate all active players // Iterate all active players
for ( int i = 1; i <= gpGlobals->maxClients; i++ ) for ( int i = 0; i < MAX_EDICTS; i++ )
{ {
if ( !m_RestorePlayer.Get( i ) ) if ( !m_RestoreEntity.Get( i ) )
{ {
// player wasn't changed by lag compensation // player wasn't changed by lag compensation
continue; continue;
} }
CBasePlayer* pPlayer = UTIL_PlayerByIndex( i ); CBaseEntity* pEntity = UTIL_EntityByIndex( i );
if ( !pPlayer ) if ( !pEntity )
{ {
continue; continue;
} }
@ -679,58 +641,61 @@ void CLagCompensationManager::FinishLagCompensation( CBasePlayer* player )
LagRecord* restore = &m_RestoreData[i]; LagRecord* restore = &m_RestoreData[i];
LagRecord* change = &m_ChangeData[i]; LagRecord* change = &m_ChangeData[i];
#ifdef CSTRIKE_DLL
auto csPlayer = ToCSPlayer( pPlayer );
if ( csPlayer )
{
csPlayer->m_angRenderAngles = restore->m_angRenderAngles;
}
#endif
if ( restore->m_fFlags & LC_SIZE_CHANGED ) if ( restore->m_fFlags & LC_SIZE_CHANGED )
{ {
// see if simulation made any changes, if no, then do the restore, otherwise, pEntity->SetSize( restore->m_vecMinsPreScaled, restore->m_vecMaxsPreScaled );
// leave new values in
if ( pPlayer->CollisionProp()->OBBMinsPreScaled() == change->m_vecMinsPreScaled
&& pPlayer->CollisionProp()->OBBMaxsPreScaled() == change->m_vecMaxsPreScaled )
{
// Restore it
pPlayer->SetSize( restore->m_vecMinsPreScaled, restore->m_vecMaxsPreScaled );
}
#ifdef STAGING_ONLY
else
{
Warning( "Should we really not restore the size?\n" );
}
#endif
} }
if ( restore->m_fFlags & LC_ANGLES_CHANGED ) if ( restore->m_fFlags & LC_ANGLES_CHANGED )
{ {
if ( pPlayer->GetAbsAngles() == change->m_vecAngles ) pEntity->SetAbsAngles( restore->m_vecAngles );
{
pPlayer->SetAbsAngles( restore->m_vecAngles );
}
} }
if ( restore->m_fFlags & LC_ORIGIN_CHANGED ) if ( restore->m_fFlags & LC_ORIGIN_CHANGED )
{ {
// Okay, let's see if we can do something reasonable with the change pEntity->SetAbsOrigin( restore->m_vecOrigin );
Vector delta = pPlayer->GetAbsOrigin() - change->m_vecOrigin;
RestorePlayerTo( pPlayer, restore->m_vecOrigin + delta );
} }
if ( restore->m_fFlags & LC_ANIMATION_CHANGED ) auto pAnim = dynamic_cast< CBaseAnimating* >( pEntity );
{ auto pAnimOverlay = dynamic_cast< CBaseAnimatingOverlay* >( pEntity );
pPlayer->SetSequence( restore->m_masterSequence );
pPlayer->SetCycle( restore->m_masterCycle ); if ( pAnim )
{
if ( restore->m_fFlags & LC_ANIMATION_CHANGED )
{
pAnim->SetSequence( restore->m_masterSequence );
pAnim->SetCycle( restore->m_masterCycle );
}
CStudioHdr* hdr = pAnim->GetModelPtr();
if ( hdr )
{
if ( restore->m_fFlags & LC_POSE_PARAMS_CHANGED )
{
for ( int paramIndex = 0; paramIndex < hdr->GetNumPoseParameters(); paramIndex++ )
{
pAnim->SetPoseParameterRaw( paramIndex, restore->m_poseParameters[paramIndex] );
}
}
if ( restore->m_fFlags & LC_ENCD_CONS_CHANGED )
{
for ( int encIndex = 0; encIndex < hdr->GetNumBoneControllers(); encIndex++ )
{
pAnim->SetBoneControllerRaw( encIndex, restore->m_encodedControllers[encIndex] );
}
}
}
}
if ( restore->m_fFlags & LC_ANIM_OVERS_CHANGED && pAnimOverlay )
{
int layerCount = pAnimOverlay->GetNumAnimOverlays();
int layerCount = pPlayer->GetNumAnimOverlays();
for ( int layerIndex = 0; layerIndex < layerCount; ++layerIndex ) for ( int layerIndex = 0; layerIndex < layerCount; ++layerIndex )
{ {
CAnimationLayer* currentLayer = pPlayer->GetAnimOverlay( layerIndex ); CAnimationLayer* currentLayer = pAnimOverlay->GetAnimOverlay( layerIndex );
if ( currentLayer ) if ( currentLayer )
{ {
currentLayer->m_flCycle = restore->m_layerRecords[layerIndex].m_cycle; currentLayer->m_flCycle = restore->m_layerRecords[layerIndex].m_cycle;
@ -742,31 +707,7 @@ void CLagCompensationManager::FinishLagCompensation( CBasePlayer* player )
} }
} }
CStudioHdr* hdr = pPlayer->GetModelPtr(); pEntity->SetSimulationTime( restore->m_flSimulationTime );
pEntity->SetAnimTime( restore->m_flAnimTime );
if ( restore->m_fFlags & LC_POSE_PARAMS_CHANGED )
{
if ( hdr )
{
for ( int paramIndex = 0; paramIndex < hdr->GetNumPoseParameters(); paramIndex++ )
{
pPlayer->SetPoseParameterRaw( paramIndex, restore->m_poseParameters[paramIndex] );
}
}
}
if ( restore->m_fFlags & LC_ENCD_CONS_CHANGED )
{
if ( hdr )
{
for ( int encIndex = 0; encIndex < hdr->GetNumBoneControllers(); encIndex++ )
{
pPlayer->SetBoneControllerRaw( encIndex, restore->m_encodedControllers[encIndex] );
}
}
}
pPlayer->SetSimulationTime( restore->m_flSimulationTime );
pPlayer->SetAnimTime( restore->m_flAnimTime );
} }
} }

View file

@ -542,8 +542,8 @@ void CCSPlayer::FireBullet(
QAngle angles[MAXSTUDIOBONES]; QAngle angles[MAXSTUDIOBONES];
int indexes[MAXSTUDIOBONES]; int indexes[MAXSTUDIOBONES];
auto angle = lagPlayer->GetRenderAngles(); auto angle = lagPlayer->GetAbsAngles();
auto position = lagPlayer->GetRenderOrigin(); auto position = lagPlayer->GetAbsOrigin();
event->SetFloat( "position_x", position.x ); event->SetFloat( "position_x", position.x );
event->SetFloat( "position_y", position.y ); event->SetFloat( "position_y", position.y );

View file

@ -297,11 +297,6 @@ void FX_FireBullets(
pPlayer->StartNewBulletGroup(); pPlayer->StartNewBulletGroup();
#endif #endif
#if !defined (CLIENT_DLL)
// Move other players back to history positions based on local player's lag
lagcompensation->StartLagCompensation( pPlayer, pPlayer->GetCurrentCommand() );
#endif
RandomSeed( iSeed ); // init random system with this seed RandomSeed( iSeed ); // init random system with this seed
// Get accuracy displacement // Get accuracy displacement
@ -340,8 +335,8 @@ void FX_FireBullets(
C_CSPlayer::HitboxRecord record; C_CSPlayer::HitboxRecord record;
record.m_vecAbsOrigin = lagPlayer->GetRenderOrigin(); record.m_vecAbsOrigin = lagPlayer->GetAbsOrigin();
record.m_angRenderAngles = lagPlayer->m_angRenderAngles; record.m_angAbsRotation = lagPlayer->GetAbsAngles();
record.m_nAttackerTickBase = pPlayer->m_nTickBase; record.m_nAttackerTickBase = pPlayer->m_nTickBase;
record.m_flSimulationTime = lagPlayer->m_flInterpolatedSimulationTime; record.m_flSimulationTime = lagPlayer->m_flInterpolatedSimulationTime;
@ -393,10 +388,6 @@ void FX_FireBullets(
x0 + x1[iBullet], y0 + y1[iBullet] ); x0 + x1[iBullet], y0 + y1[iBullet] );
} }
#if !defined (CLIENT_DLL)
lagcompensation->FinishLagCompensation( pPlayer );
#endif
EndGroupingSounds(); EndGroupingSounds();
} }

View file

@ -235,14 +235,7 @@ void CKnife::SecondaryAttack()
CCSPlayer *pPlayer = GetPlayerOwner(); CCSPlayer *pPlayer = GetPlayerOwner();
if ( pPlayer && !pPlayer->m_bIsDefusing && !CSGameRules()->IsFreezePeriod() ) if ( pPlayer && !pPlayer->m_bIsDefusing && !CSGameRules()->IsFreezePeriod() )
{ {
#if !defined (CLIENT_DLL)
// Move other players back to history positions based on local player's lag
lagcompensation->StartLagCompensation( pPlayer, pPlayer->GetCurrentCommand() );
#endif
SwingOrStab( true ); SwingOrStab( true );
#if !defined (CLIENT_DLL)
lagcompensation->FinishLagCompensation( pPlayer );
#endif
} }
} }

View file

@ -547,7 +547,7 @@ def configure(conf):
'/arch:SSE' if conf.env.DEST_CPU == 'x86' else '/arch:AVX', '/arch:SSE' if conf.env.DEST_CPU == 'x86' else '/arch:AVX',
'/GF', '/GF',
'/Gy', '/Gy',
'/fp:fast', '/fp:precise',
'/Zc:forScope', '/Zc:forScope',
'/Zc:wchar_t', '/Zc:wchar_t',
'/GR', '/GR',